diff --git a/src/CliMenu.php b/src/CliMenu.php index 914851f6..b2b1432e 100644 --- a/src/CliMenu.php +++ b/src/CliMenu.php @@ -257,9 +257,12 @@ private function display() : void switch ($char->getControl()) { case InputCharacter::UP: case InputCharacter::DOWN: + $this->moveSelectionVertically($char->getControl()); + $this->draw(); + break; case InputCharacter::LEFT: case InputCharacter::RIGHT: - $this->moveSelection($char->getControl()); + $this->moveSelectionHorizontally($char->getControl()); $this->draw(); break; case InputCharacter::ENTER: @@ -272,60 +275,57 @@ private function display() : void /** * Move the selection in a given direction, up / down */ - protected function moveSelection(string $direction) : void + protected function moveSelectionVertically(string $direction) : void { - do { - if ($direction === 'UP' || $direction === 'DOWN') { - $itemKeys = array_keys($this->items); - - $direction === 'UP' - ? $this->selectedItem-- - : $this->selectedItem++; - - if (!array_key_exists($this->selectedItem, $this->items)) { - $this->selectedItem = $direction === 'UP' - ? end($itemKeys) - : reset($itemKeys); - } elseif ($this->getSelectedItem()->canSelect()) { - return; - } - } else { - $item = $this->getSelectedItem(true); - if (!$item instanceof SplitItem) { - return; - } + $itemKeys = array_keys($this->items); - $itemKeys = array_keys($item->getItems()); - $selectedItemIndex = $item->getSelectedItemIndex(); - $direction === 'LEFT' - ? $selectedItemIndex-- - : $selectedItemIndex++; - $item->setSelectedItemIndex($selectedItemIndex); - - if (!array_key_exists($selectedItemIndex, $item->getItems())) { - $selectedItemIndex = $direction === 'LEFT' - ? end($itemKeys) - : reset($itemKeys); - $item->setSelectedItemIndex($selectedItemIndex); - } elseif ($item->getItems()[$item->getSelectedItemIndex()]->canSelect()) { - return; - } + do { + $direction === 'UP' + ? $this->selectedItem-- + : $this->selectedItem++; + + if (!array_key_exists($this->selectedItem, $this->items)) { + $this->selectedItem = $direction === 'UP' + ? end($itemKeys) + : reset($itemKeys); } } while (!$this->getSelectedItem()->canSelect()); } - public function getSelectedItem(bool $oneLevelDeep = false) : MenuItemInterface + /** + * Move the selection in a given direction, left / right + */ + protected function moveSelectionHorizontally(string $direction) : void { - if ($oneLevelDeep) { - return $this->items[$this->selectedItem]; - } else { - $item = $this->items[$this->selectedItem]; - if ($item instanceof SplitItem) { - $item = $item->getItems()[$item->getSelectedItemIndex()]; + if (!$this->items[$this->selectedItem] instanceof SplitItem) { + return; + } + + $item = $this->items[$this->selectedItem]; + $itemKeys = array_keys($item->getItems()); + $selectedItemIndex = $item->getSelectedItemIndex(); + + do { + $direction === 'LEFT' + ? $selectedItemIndex-- + : $selectedItemIndex++; + $item->setSelectedItemIndex($selectedItemIndex); + + if (!array_key_exists($selectedItemIndex, $item->getItems())) { + $selectedItemIndex = $direction === 'LEFT' + ? end($itemKeys) + : reset($itemKeys); + $item->setSelectedItemIndex($selectedItemIndex); } + } while (!$item->getSelectedItem()->canSelect()); + } - return $item; - } + public function getSelectedItem() : MenuItemInterface + { + $item = $this->items[$this->selectedItem]; + return $item instanceof SplitItem + ? $item->getSelectedItem() + : $item; } /** diff --git a/src/MenuItem/SplitItem.php b/src/MenuItem/SplitItem.php index 2f1d6c8c..fa2c66f1 100644 --- a/src/MenuItem/SplitItem.php +++ b/src/MenuItem/SplitItem.php @@ -19,7 +19,7 @@ class SplitItem implements MenuItemInterface private $items; /** - * @var int + * @var int|null */ private $selectedItemIndex; @@ -112,16 +112,16 @@ public function getRows(MenuStyle $style, bool $selected = false) : array $missingLength = $style->getContentWidth() % $numberOfItems; - $lines = 0; - $cells = []; - foreach ($this->items as $index => $item) { + $cells = array_map(function ($index, $item) use ($selected, $length, $style) { $isSelected = $selected && $index === $this->selectedItemIndex; - $marker = sprintf("%s ", $style->getMarker($isSelected)); + $marker = $item->canSelect() + ? sprintf("%s ", $style->getMarker($isSelected)) + : sprintf("%s ", str_repeat(' ', mb_strlen($style->getMarker(false)))); $content = StringUtil::wordwrap( sprintf('%s%s', $marker, $item->getText()), $length ); - $cell = array_map(function ($row) use ($length, $style, $isSelected) { + return array_map(function ($row) use ($length, $style, $isSelected) { $invertedColoursSetCode = $isSelected ? $style->getInvertedColoursSetCode() : ''; @@ -138,12 +138,9 @@ public function getRows(MenuStyle $style, bool $selected = false) : array str_repeat(' ', $this->margin) ); }, explode("\n", $content)); - $lineCount = count($cell); - if ($lineCount > $lines) { - $lines = $lineCount; - } - $cells[] = $cell; - } + }, array_keys($this->items), $this->items); + + $lines = max(array_map('count', $cells)); $rows = []; for ($i = 0; $i < $lines; $i++) { @@ -172,17 +169,16 @@ public function setSelectedItemIndex(int $index) : void $this->selectedItemIndex = $index; } - public function getSelectedItemIndex() : int + public function getSelectedItemIndex() : ?int { - if ($this->selectedItemIndex === null) { - return 0; - } return $this->selectedItemIndex; } public function getSelectedItem() : MenuItemInterface { - return $this->items[$this->selectedItemIndex]; + return $this->selectedItemIndex !== null + ? $this->items[$this->selectedItemIndex] + : $this; } public function getItems() : array @@ -192,7 +188,7 @@ public function getItems() : array /** * Can the item be selected - * Not really in this case but that's the trick + * In this case, it indicates if at least 1 item inside the SplitItem can be selected */ public function canSelect() : bool { @@ -232,14 +228,10 @@ public function hideItemExtra() : void } /** - * Return the raw string of text + * Nothing to return with SplitItem */ public function getText() : string { - $text = []; - foreach ($this->items as $item) { - $text[] = $item->getText(); - } - return explode(' - ', $text); + throw new \BadMethodCallException(sprintf('Not supported on: %s', SplitItem::class)); } }