Connexion
FR
games/xencenter-xenadmin-xcp-jumphp / src / Gui / PropertySheet.php · commit fb1b7c9
<?phpnamespace App\Gui;use JumPHP\Gui\Pointer;use JumPHP\Gui\Theme;use JumPHP\Renderer\Renderer;/** * The General tab of XenCenter: sections ("General", "Memory", "CPUs", "Boot Options"...) of "key: value" lines, opened and closed * by a click on their header, scrolled. setSections([['title' => 'General', 'rows' => [['Name:', 'web-01'], ...]]]); a value may * hold "\n" (several lines), or be ['bar' => 0.6, 'text' => '…'] (a usage bar). */final class PropertySheet extends Canvas{    public const DEFAULTS = ['height' => 'fill', 'width' => 'fill', 'background' => '#ffffff', 'border' => false, 'keyWidth' => 210];    /** @var list<array{title: string, rows: list<array{0: string, 1: mixed}>}> */    private array $sections = [];    /** @var array<string, bool> closed sections */    public array $closed = [];    public function setSections(array $sections): void    {        $this->sections = $sections;    }    /** @return list<array{title: string, rows: list<array{0: string, 1: mixed}>}> */    public function sections(): array    {        return $this->sections;    }    /** The value of a line (tests): value('General', 'Name:'). */    public function value(string $section, string $key): mixed    {        foreach ($this->sections as $s) {            if ($s['title'] === $section) {                foreach ($s['rows'] as [$k, $v]) {                    if ($k === $key) {                        return $v;                    }                }            }        }        return null;    }    private function lineHeight(Theme $t): float    {        return $t->font()->lineHeight() + $t->px(9);    }    private function headerHeight(Theme $t): float    {        return $t->px(32);    }    /** @return list<string> */    private static function lines(mixed $value): array    {        return is_array($value) ? [''] : explode("\n", (string)$value);    }    protected function contentHeight(Theme $t): float    {        $h = $t->px(8);        foreach ($this->sections as $s) {            $h += $this->headerHeight($t) + $t->px(4);            if (!($this->closed[$s['title']] ?? false)) {                foreach ($s['rows'] as [, $v]) {                    $h += count(self::lines($v)) * $this->lineHeight($t);                }                $h += $t->px(10);            }        }        return $h;    }    protected function paint(Renderer $r, Theme $t): void    {        $font = $t->font();        $bold = $t->font($t->fontSize * 1.05, true);        $y = $this->y + $t->px(8) - $this->scrollY;        $lh = $this->lineHeight($t);        $keyW = $t->px((float)$this->props['keyWidth']);        $left = $this->x + $t->px(2);        $right = $this->x + $this->w - $t->px(14);        foreach ($this->sections as $s) {            $hh = $this->headerHeight($t);            $closed = $this->closed[$s['title']] ?? false;            if ($y + $hh > $this->y && $y < $this->y + $this->h) {                $t->box($r, $left, $y, $right - $left, $hh, '#eef3f9', $t->px(6));                $bold->draw($r, \JumPHP\Util\Lang::t($s['title']), $left + $t->px(28), $y + ($hh - $bold->height()) / 2, 1, '#1d3c6e');                // the open / closed chevron                $cx = $left + $t->px(11);                $cy = $y + $hh / 2;                for ($k = 0; $k < 4; $k++) {                    $closed                        ? $r->fillRect($cx + $k * $t->scale, $cy - $t->px(4) + $k * $t->scale, max(1, $t->scale), $t->px(8) - 2 * $k * $t->scale, '#1d3c6e')                        : $r->fillRect($cx - $t->px(1) + $k * $t->scale, $cy - $t->px(2) + $k * $t->scale, $t->px(9) - 2 * $k * $t->scale, max(1, $t->scale), '#1d3c6e');                }            }            $y += $hh + $t->px(4);            if ($closed) {                continue;            }            foreach ($s['rows'] as [$key, $value]) {                $lines = self::lines($value);                if ($y + count($lines) * $lh > $this->y && $y < $this->y + $this->h) {                    $ty = $y + $t->px(4);                    $r->fillRect($left + $t->px(14), $y + count($lines) * $lh - 1, $right - $left - $t->px(28), 1, '#f1f3f6');                    $font->draw($r, self::fit($font, \JumPHP\Util\Lang::t($key), $keyW - $t->px(16)), $left + $t->px(28), $ty, 1, '#6b7280');                    if (is_array($value) && isset($value['bar'])) {                        $bw = min($t->px(260), $right - $left - $keyW - $t->px(120));                        $ratio = max(0.0, min(1.0, (float)$value['bar']));                        $by = $y + $t->px(6);                        $bh = $lh - $t->px(12);                        $t->box($r, $left + $keyW, $by, $bw, $bh, '#e9edf2', $t->px(4));                        if ($ratio > 0) {                            $t->box($r, $left + $keyW, $by, max($t->px(8), $bw * $ratio), $bh, $ratio > 0.9 ? '#e5735f' : '#7cc47f', $t->px(4));                        }                        $font->draw($r, self::fit($font, (string)($value['text'] ?? ''), $right - $left - $keyW - $bw - $t->px(12)), $left + $keyW + $bw + $t->px(12), $ty, 1, '#1f2329');                    } else {                        foreach ($lines as $n => $line) {                            $font->draw($r, self::fit($font, $line, $right - $left - $keyW - $t->px(14)), $left + $keyW, $ty + $n * $lh, 1, '#1f2329');                        }                    }                }                $y += count($lines) * $lh;            }            $y += $t->px(10);        }    }    public function pointerUp(Pointer $p, bool $inside): void    {        if ($this->popupUp($p) || $this->barUp() || !$inside || $this->form === null) {            return;        }        $t = $this->form->theme;        $y = $this->y + $t->px(8) - $this->scrollY;        foreach ($this->sections as $s) {            $hh = $this->headerHeight($t);            if ($p->y >= $y && $p->y < $y + $hh) {                $this->closed[$s['title']] = !($this->closed[$s['title']] ?? false);                $this->clampScroll($t);                return;            }            $y += $hh + $t->px(4);            if (!($this->closed[$s['title']] ?? false)) {                foreach ($s['rows'] as [, $v]) {                    $y += count(self::lines($v)) * $this->lineHeight($t);                }                $y += $t->px(10);            }        }        $this->emit('click');    }}