Add popup menus for actions

This commit is contained in:
2024-10-01 22:31:51 +02:00
parent 3caca13e5c
commit 88abeaa896
4 changed files with 163 additions and 28 deletions
+94
View File
@@ -0,0 +1,94 @@
<?php
namespace NoccyLabs\JEdit\Editor;
use NoccyLabs\JEdit\Terminal\Terminal;
class Menu
{
const U_CORNER_TOPLEFT = "\u{250c}";
const U_CORNER_TOPRIGHT = "\u{2510}";
const U_CORNER_BOTTOMLEFT = "\u{2514}";
const U_CORNER_BOTTOMRIGHT = "\u{2518}";
const U_CORNER_ROUNDED_TOPLEFT = "\u{256d}";
const U_CORNER_ROUNDED_TOPRIGHT = "\u{256e}";
const U_CORNER_ROUNDED_BOTTOMLEFT = "\u{2570}";
const U_CORNER_ROUNDED_BOTTOMRIGHT = "\u{256f}";
const U_EDGE_HORIZONTAL = "\u{2500}";
const U_EDGE_VERTICAL = "\u{2502}";
const U_EDGE_VERTICAL_SCROLL = "\u{250a}";
const U_EDGE_VERTICAL_THUMB = "\u{2503}";
const U_EDGE_VERTICAL_LEFT = "\u{2524}";
const U_EDGE_VERTICAL_RIGHT = "\u{251c}";
private int $index = 0;
public function __construct(private Terminal $terminal, private array $items, private string $title = 'Menu')
{
}
public function display(int $left, int $top, int $width, int $height = 0, string|int|null $value): mixed
{
if ($height == 0) $height = count($this->items) + 4;
$this->redraw($left, $top, $width, $height);
$showing = true;
while ($showing) {
while (null === ($ch = $this->terminal->readKey())) {
usleep(10000);
}
if (mb_strlen($ch) == 1) {
if ($ch == "\x03") {
$showing = false;
}
if ($ch == "\r") {
return array_keys($this->items)[$this->index];
}
} else {
if ($ch == "k{UP}") {
$this->index--;
if ($this->index < 0) $this->index = count($this->items) - 1;
$this->redraw($left, $top, $width, $height);
} elseif ($ch == "k{DOWN}") {
$this->index++;
if ($this->index >= count($this->items)) $this->index = 0;
$this->redraw($left, $top, $width, $height);
}
}
}
return null;
}
private function redraw(int $left, int $top, int $width, int $height) {
$visibleItems = $height - 4;
// draw head
echo "\e[40;37m";
$this->terminal
->writeAt($left, $top + 0, self::U_CORNER_ROUNDED_TOPLEFT.str_repeat(self::U_EDGE_HORIZONTAL,$width - 2).self::U_CORNER_ROUNDED_TOPRIGHT)
->writeAt($left, $top + 1, self::U_EDGE_VERTICAL.str_repeat(" ",$width - 2).self::U_EDGE_VERTICAL)
->writeAt($left + 2, $top + 1, "\e[1m" . $this->title . "\e[22m")
->writeAt($left, $top + 2, self::U_EDGE_VERTICAL_RIGHT.str_repeat(self::U_EDGE_HORIZONTAL,$width - 2).self::U_EDGE_VERTICAL_LEFT)
->writeAt($left, $top + $height - 1, self::U_CORNER_BOTTOMLEFT.str_repeat(self::U_EDGE_HORIZONTAL,$width - 2).self::U_CORNER_BOTTOMRIGHT)
;
$keys = array_keys($this->items);
for ($n = 0; $n < $visibleItems; $n++) {
$key = $keys[$n]??null;
$item = " " . ($key ? ($this->items[$key]) : null);
$item = $item . str_repeat(" ", $width - 2 - mb_strlen($item)) . "\e[40;37m";
$item = (($n == $this->index)?"\e[37;44m":"\e[40;37m") . $item;
$this->terminal
->writeAt($left, $top + 3 + $n, self::U_EDGE_VERTICAL.$item.self::U_EDGE_VERTICAL_SCROLL);
}
echo "\e[0m";
}
}