ES
games/xencenter-xenadmin-xcp-jumphp / src / Gui / TabStrip.php · commit fb1b7c9
<?phpnamespace App\Gui;use JumPHP\Gui\Pointer;use JumPHP\Gui\Theme;use JumPHP\Gui\Widget;use JumPHP\Renderer\Renderer;/** * The tabs over the right pane (General, Memory, Storage, Networking, Console, Performance, Snapshots...). * Events: change (int $index, string $tab). * * @property list<string> $tabs * @property int $selected */final class TabStrip extends Widget{    public const DEFAULTS = ['tabs' => [], 'selected' => 0, 'width' => 'fill'];    public static function events(): array    {        return ['change', 'click'];    }    protected function content(Theme $t, float $maxWidth, string $breakpoint): array    {        $lines = 1;        foreach ($this->boxes($t, $maxWidth, 0.0) as [, , $line]) {            $lines = max($lines, $line + 1);        }        return [$maxWidth, $t->px(40) * $lines];    }    public function value(): ?string    {        return $this->props['tabs'][(int)$this->props['selected']] ?? null;    }    /**     * x, width, line and y of each tab: the tabs that do not fit (a phone) go on more lines.     *     * @return list<array{0: float, 1: float, 2: int, 3: float}>     */    private function boxes(Theme $t, ?float $width = null, ?float $left = null): array    {        $font = $t->font();        $left ??= $this->x;        $width ??= $this->w;        $x = $left + $t->px(10);        $line = 0;        $out = [];        foreach ((array)$this->props['tabs'] as $tab) {            $w = $font->width(\JumPHP\Util\Lang::t((string)$tab)) + $t->px(28);            if ($x + $w > $left + $width - $t->px(4) && $x > $left + $t->px(10)) {                $x = $left + $t->px(10);                $line++;            }            $out[] = [$x, $w, $line, $this->y + $line * $t->px(40)];            $x += $w + $t->px(2);        }        return $out;    }    public function render(Renderer $r, Theme $t): void    {        $r->fillRect($this->x, $this->y, $this->w, $this->h, '#ffffff');        $r->fillRect($this->x, $this->y + $this->h - 1, $this->w, 1, '#e1e5eb');        $font = $t->font();        $bold = $t->font(null, true);        $lh = $t->px(40);        foreach ($this->boxes($t) as $i => [$x, $w, , $y]) {            $selected = $i === (int)$this->props['selected'];            $hover = $this->hovered && $this->hoverTab === $i;            if ($hover && !$selected) {                $t->box($r, $x, $y + $t->px(6), $w, $lh - $t->px(12), '#f0f3f8', $t->px(6));            }            if ($selected) {                $t->box($r, $x + $t->px(6), $y + $lh - $t->px(3), $w - $t->px(12), $t->px(3), '#2f6fd6', $t->px(1.5));            }            $f = $selected ? $bold : $font;            $f->draw($r, \JumPHP\Util\Lang::t((string)$this->props['tabs'][$i]), $x + $w / 2, $y + ($lh - $f->height()) / 2, 1,                $selected ? '#1d3c6e' : '#57606a', 'center');        }    }    private int $hoverTab = -1;    public function update(float $dt): void    {        $engine = $this->form?->engineOrNull();        if ($engine === null || !$this->hovered || $this->form === null) {            $this->hoverTab = -1;            return;        }        $mx = $engine->input->getMouse()->x;        $my = $engine->input->getMouse()->y;        $this->hoverTab = -1;        $lh = $this->form->theme->px(40);        foreach ($this->boxes($this->form->theme) as $i => [$x, $w, , $y]) {            if ($mx >= $x && $mx < $x + $w && $my >= $y && $my < $y + $lh) {                $this->hoverTab = $i;            }        }    }    public function select(int $index): void    {        $tabs = (array)$this->props['tabs'];        if (!isset($tabs[$index])) {            return;        }        if ($index !== (int)$this->props['selected']) {            $this->selected = $index;            $this->emit('change', $index, (string)$tabs[$index]);        }    }    public function selectTab(string $tab): void    {        $index = array_search($tab, (array)$this->props['tabs'], true);        if ($index !== false) {            $this->select((int)$index);        }    }    public function pointerUp(Pointer $p, bool $inside): void    {        if (!$inside || $this->form === null) {            return;        }        $lh = $this->form->theme->px(40);        foreach ($this->boxes($this->form->theme) as $i => [$x, $w, , $y]) {            if ($p->x >= $x && $p->x < $x + $w && $p->y >= $y && $p->y < $y + $lh) {                $this->select($i);            }        }        $this->emit('click');    }}