From 78c81508e000c7065948e5afdde02fc8080ad501 Mon Sep 17 00:00:00 2001 From: Juan Treminio Date: Wed, 18 Dec 2019 15:29:10 -0600 Subject: [PATCH 1/8] Item-level style example; fixes disappearing styles for nested --- examples/checkable-item.php | 7 +- examples/radio-item.php | 11 +- src/Builder/CliMenuBuilder.php | 190 ++++++++++++++++++--------- src/Builder/SplitItemBuilder.php | 106 ++++++++++++++- src/CliMenu.php | 65 ++++++++- src/MenuItem/CheckableInterface.php | 7 + src/MenuItem/CheckableItem.php | 82 +++--------- src/MenuItem/ItemStyleInterface.php | 12 ++ src/MenuItem/MenuMenuItem.php | 12 +- src/MenuItem/RadioInterface.php | 7 + src/MenuItem/RadioItem.php | 88 ++++--------- src/MenuItem/SelectableInterface.php | 9 ++ src/MenuItem/SelectableItem.php | 2 +- src/MenuItem/SelectableTrait.php | 39 ++++-- src/MenuItem/SplitItem.php | 14 +- src/MenuItem/ToggableTrait.php | 72 ++++++++-- src/MenuStyle.php | 141 ++------------------ src/Style/CheckableStyle.php | 61 +++++++++ src/Style/Colour.php | 36 +++++ src/Style/ItemStyleInterface.php | 36 +++++ src/Style/ItemStyleTrait.php | 184 ++++++++++++++++++++++++++ src/Style/RadioStyle.php | 61 +++++++++ src/Style/SelectableStyle.php | 61 +++++++++ 23 files changed, 932 insertions(+), 371 deletions(-) create mode 100644 src/MenuItem/CheckableInterface.php create mode 100644 src/MenuItem/ItemStyleInterface.php create mode 100644 src/MenuItem/RadioInterface.php create mode 100644 src/MenuItem/SelectableInterface.php create mode 100644 src/Style/CheckableStyle.php create mode 100644 src/Style/Colour.php create mode 100644 src/Style/ItemStyleInterface.php create mode 100644 src/Style/ItemStyleTrait.php create mode 100644 src/Style/RadioStyle.php create mode 100644 src/Style/SelectableStyle.php diff --git a/examples/checkable-item.php b/examples/checkable-item.php index 663cdd33..b9603155 100644 --- a/examples/checkable-item.php +++ b/examples/checkable-item.php @@ -2,6 +2,7 @@ use PhpSchool\CliMenu\CliMenu; use PhpSchool\CliMenu\Builder\CliMenuBuilder; +use PhpSchool\CliMenu\Style\CheckableStyle; require_once(__DIR__ . '/../vendor/autoload.php'); @@ -22,8 +23,10 @@ }) ->addSubMenu('Interpreted', function (CliMenuBuilder $b) use ($itemCallable) { $b->setTitle('Interpreted Languages') - ->setUncheckedMarker('[○] ') - ->setCheckedMarker('[●] ') + ->setCheckableStyle(function (CheckableStyle $style) { + $style->setMarkerOff('[○] ') + ->setMarkerOn('[●] '); + }) ->addCheckableItem('PHP', $itemCallable) ->addCheckableItem('Javascript', $itemCallable) ->addCheckableItem('Ruby', $itemCallable) diff --git a/examples/radio-item.php b/examples/radio-item.php index d3b7f0c9..b0add65c 100644 --- a/examples/radio-item.php +++ b/examples/radio-item.php @@ -2,9 +2,14 @@ use PhpSchool\CliMenu\CliMenu; use PhpSchool\CliMenu\Builder\CliMenuBuilder; +use PhpSchool\CliMenu\Style\RadioStyle; require_once(__DIR__ . '/../vendor/autoload.php'); +ini_set('display_errors', 1); +ini_set('display_startup_errors', 1); +error_reporting(E_ALL); + $itemCallable = function (CliMenu $menu) { echo $menu->getSelectedItem()->getText(); }; @@ -22,8 +27,10 @@ }) ->addSubMenu('Interpreted', function (CliMenuBuilder $b) use ($itemCallable) { $b->setTitle('Interpreted Languages') - ->setUnradioMarker('[ ] ') - ->setRadioMarker('[✔] ') + ->setRadioStyle(function (RadioStyle $style) { + $style->setMarkerOff('[ ] ') + ->setMarkerOn('[✔] '); + }) ->addRadioItem('PHP', $itemCallable) ->addRadioItem('Javascript', $itemCallable) ->addRadioItem('Ruby', $itemCallable) diff --git a/src/Builder/CliMenuBuilder.php b/src/Builder/CliMenuBuilder.php index fd856698..ce3419de 100644 --- a/src/Builder/CliMenuBuilder.php +++ b/src/Builder/CliMenuBuilder.php @@ -2,6 +2,7 @@ namespace PhpSchool\CliMenu\Builder; +use Closure; use PhpSchool\CliMenu\Action\ExitAction; use PhpSchool\CliMenu\Action\GoBackAction; use PhpSchool\CliMenu\Exception\InvalidShortcutException; @@ -11,11 +12,15 @@ use PhpSchool\CliMenu\MenuItem\MenuItemInterface; use PhpSchool\CliMenu\MenuItem\MenuMenuItem; use PhpSchool\CliMenu\MenuItem\RadioItem; +use PhpSchool\CliMenu\MenuItem\SelectableInterface; use PhpSchool\CliMenu\MenuItem\SelectableItem; use PhpSchool\CliMenu\CliMenu; use PhpSchool\CliMenu\MenuItem\SplitItem; use PhpSchool\CliMenu\MenuItem\StaticItem; use PhpSchool\CliMenu\MenuStyle; +use PhpSchool\CliMenu\Style\CheckableStyle; +use PhpSchool\CliMenu\Style\RadioStyle; +use PhpSchool\CliMenu\Style\SelectableStyle; use PhpSchool\CliMenu\Terminal\TerminalFactory; use PhpSchool\Terminal\Terminal; @@ -118,7 +123,10 @@ public function addItem( bool $showItemExtra = false, bool $disabled = false ) : self { - $this->addMenuItem(new SelectableItem($text, $itemCallable, $showItemExtra, $disabled)); + $item = (new SelectableItem($text, $itemCallable, $showItemExtra, $disabled)) + ->setStyle($this->menu->getSelectableStyle()); + + $this->addMenuItem($item); return $this; } @@ -138,7 +146,10 @@ public function addCheckableItem( bool $showItemExtra = false, bool $disabled = false ) : self { - $this->addMenuItem(new CheckableItem($text, $itemCallable, $showItemExtra, $disabled)); + $item = (new CheckableItem($text, $itemCallable, $showItemExtra, $disabled)) + ->setStyle($this->menu->getCheckableStyle()); + + $this->addMenuItem($item); return $this; } @@ -149,7 +160,10 @@ public function addRadioItem( bool $showItemExtra = false, bool $disabled = false ) : self { - $this->addMenuItem(new RadioItem($text, $itemCallable, $showItemExtra, $disabled)); + $item = (new RadioItem($text, $itemCallable, $showItemExtra, $disabled)) + ->setStyle($this->menu->getRadioStyle()); + + $this->addMenuItem($item); return $this; } @@ -175,7 +189,7 @@ public function addAsciiArt(string $art, string $position = AsciiArtItem::POSITI return $this; } - public function addSubMenu(string $text, \Closure $callback) : self + public function addSubMenu(string $text, Closure $callback) : self { $builder = self::newSubMenu($this->terminal); @@ -186,20 +200,12 @@ public function addSubMenu(string $text, \Closure $callback) : self $callback = $callback->bindTo($builder); $callback($builder); - $menu = $builder->build(); - $menu->setParent($this->menu); - - //we apply the parent theme if nothing was changed - //if no styles were changed in this sub-menu - if (!$menu->getStyle()->hasChangedFromDefaults()) { - $menu->setStyle($this->menu->getStyle()); - } + $menu = $this->createMenuClosure($builder, $this->menu); + + $item = (new MenuMenuItem($text, $menu, $builder->isMenuDisabled())) + ->setStyle($this->menu->getSelectableStyle()); - $this->menu->addItem($item = new MenuMenuItem( - $text, - $menu, - $builder->isMenuDisabled() - )); + $this->menu->addItem($item); $this->processItemShortcut($item); @@ -208,26 +214,73 @@ public function addSubMenu(string $text, \Closure $callback) : self public function addSubMenuFromBuilder(string $text, CliMenuBuilder $builder) : self { - $menu = $builder->build(); - $menu->setParent($this->menu); + $menu = $this->createMenuClosure($builder, $this->menu); - //we apply the parent theme if nothing was changed - //if no styles were changed in this sub-menu - if (!$menu->getStyle()->hasChangedFromDefaults()) { - $menu->setStyle($this->menu->getStyle()); - } + $item = (new MenuMenuItem($text, $menu, $builder->isMenuDisabled())) + ->setStyle($this->menu->getSelectableStyle()); - $this->menu->addItem($item = new MenuMenuItem( - $text, - $menu, - $builder->isMenuDisabled() - )); + $this->menu->addItem($item); $this->processItemShortcut($item); return $this; } + /** + * Create the submenu as a closure which is then unpacked in MenuMenuItem::showSubMenu + * This allows us to wait until all user-provided styles are parsed and apply them to nested items + * + * @param CliMenuBuilder|SplitItemBuilder $builder + * @param CliMenu $parent + * @return Closure + */ + protected function createMenuClosure($builder, CliMenu $parent = null) : Closure + { + return function () use ($builder, $parent) { + $menu = $builder->build(); + + if ($parent) { + $menu->setParent($parent); + } + + // we apply the parent theme if nothing was changed + // if no styles were changed in this sub-menu + if (!$menu->getStyle()->hasChangedFromDefaults()) { + $menu->setStyle($this->menu->getStyle()); + } + + // If user changed this style, persist to the menu so children CheckableItems may use it + if ($this->menu->getCheckableStyle()->getIsCustom()) { + $menu->setCheckableStyle(function (CheckableStyle $style) { + $style->fromArray($this->menu->getCheckableStyle()->toArray()); + }); + } + + // If user changed this style, persist to the menu so children RadioItems may use it + if ($this->menu->getRadioStyle()->getIsCustom()) { + $menu->setRadioStyle(function (RadioStyle $style) { + $style->fromArray($this->menu->getRadioStyle()->toArray()); + }); + } + + // If user changed this style, persist to the menu so children SelectableItems may use it + if ($this->menu->getSelectableStyle()->getIsCustom()) { + $menu->setSelectableStyle(function (SelectableStyle $style) { + $style->fromArray($this->menu->getSelectableStyle()->toArray()); + }); + } + + // This will be filled with user-provided items + foreach ($menu->getItems() as $item) { + if ($item instanceof SelectableInterface && !$item->getStyle()->getIsCustom()) { + $item->setStyle(clone $menu->getSelectableStyle()); + } + } + + return $menu; + }; + } + public function enableAutoShortcuts(string $regex = null) : self { $this->autoShortcuts = true; @@ -294,7 +347,7 @@ private function processIndividualShortcut(MenuItemInterface $item, callable $ca } } - public function addSplitItem(\Closure $callback) : self + public function addSplitItem(Closure $callback) : self { $builder = new SplitItemBuilder($this->menu); @@ -302,6 +355,27 @@ public function addSplitItem(\Closure $callback) : self $builder->enableAutoShortcuts($this->autoShortcutsRegex); } + // If user changed this style, persist to the menu so children CheckableItems may use it + if ($this->menu->getCheckableStyle()->getIsCustom()) { + $builder->setCheckableStyle(function (CheckableStyle $style) { + $style->fromArray($this->menu->getCheckableStyle()->toArray()); + }); + } + + // If user changed this style, persist to the menu so children RadioItems may use it + if ($this->menu->getRadioStyle()->getIsCustom()) { + $builder->setRadioStyle(function (RadioStyle $style) { + $style->fromArray($this->menu->getRadioStyle()->toArray()); + }); + } + + // If user changed this style, persist to the menu so children SelectableItems may use it + if ($this->menu->getSelectableStyle()->getIsCustom()) { + $builder->setSelectableStyle(function (SelectableStyle $style) { + $style->fromArray($this->menu->getSelectableStyle()->toArray()); + }); + } + $callback($builder); $this->menu->addItem($splitItem = $builder->build()); @@ -418,34 +492,6 @@ public function setSelectedMarker(string $marker) : self return $this; } - public function setUncheckedMarker(string $marker) : self - { - $this->style->setUncheckedMarker($marker); - - return $this; - } - - public function setCheckedMarker(string $marker) : self - { - $this->style->setCheckedMarker($marker); - - return $this; - } - - public function setUnradioMarker(string $marker) : self - { - $this->style->setUnradioMarker($marker); - - return $this; - } - - public function setRadioMarker(string $marker) : self - { - $this->style->setRadioMarker($marker); - - return $this; - } - public function setItemExtra(string $extra) : self { $this->style->setItemExtra($extra); @@ -519,10 +565,13 @@ private function getDefaultItems() : array { $actions = []; if ($this->subMenu) { - $actions[] = new SelectableItem($this->goBackButtonText, new GoBackAction); + $actions[] = (new SelectableItem($this->goBackButtonText, new GoBackAction)) + ->setStyle($this->menu->getSelectableStyle()); } - $actions[] = new SelectableItem($this->exitButtonText, new ExitAction); + $actions[] = (new SelectableItem($this->exitButtonText, new ExitAction)) + ->setStyle($this->menu->getSelectableStyle()); + return $actions; } @@ -559,4 +608,25 @@ public function build() : CliMenu return $this->menu; } + + public function setCheckableStyle(callable $itemCallable) : self + { + $this->menu->setCheckableStyle($itemCallable); + + return $this; + } + + public function setRadioStyle(callable $itemCallable) : self + { + $this->menu->setRadioStyle($itemCallable); + + return $this; + } + + public function setSelectableStyle(callable $itemCallable) : self + { + $this->menu->setSelectableStyle($itemCallable); + + return $this; + } } diff --git a/src/Builder/SplitItemBuilder.php b/src/Builder/SplitItemBuilder.php index 1ece321d..f3428209 100644 --- a/src/Builder/SplitItemBuilder.php +++ b/src/Builder/SplitItemBuilder.php @@ -2,14 +2,19 @@ namespace PhpSchool\CliMenu\Builder; +use Closure; use PhpSchool\CliMenu\CliMenu; use PhpSchool\CliMenu\MenuItem\CheckableItem; use PhpSchool\CliMenu\MenuItem\LineBreakItem; use PhpSchool\CliMenu\MenuItem\MenuMenuItem; use PhpSchool\CliMenu\MenuItem\RadioItem; +use PhpSchool\CliMenu\MenuItem\SelectableInterface; use PhpSchool\CliMenu\MenuItem\SelectableItem; use PhpSchool\CliMenu\MenuItem\SplitItem; use PhpSchool\CliMenu\MenuItem\StaticItem; +use PhpSchool\CliMenu\Style\CheckableStyle; +use PhpSchool\CliMenu\Style\RadioStyle; +use PhpSchool\CliMenu\Style\SelectableStyle; /** * @author Aydin Hassan @@ -42,10 +47,29 @@ class SplitItemBuilder */ private $autoShortcutsRegex = '/\[(.)\]/'; + /** + * @var CheckableStyle + */ + private $checkableStyle; + + /** + * @var RadioStyle + */ + private $radioStyle; + + /** + * @var SelectableStyle + */ + private $selectableStyle; + public function __construct(CliMenu $menu) { $this->menu = $menu; $this->splitItem = new SplitItem(); + + $this->checkableStyle = new CheckableStyle($menu->getTerminal()); + $this->radioStyle = new RadioStyle($menu->getTerminal()); + $this->selectableStyle = new SelectableStyle($menu->getTerminal()); } public function addItem( @@ -54,7 +78,10 @@ public function addItem( bool $showItemExtra = false, bool $disabled = false ) : self { - $this->splitItem->addItem(new SelectableItem($text, $itemCallable, $showItemExtra, $disabled)); + $item = (new SelectableItem($text, $itemCallable, $showItemExtra, $disabled)) + ->setStyle($this->menu->getSelectableStyle()); + + $this->splitItem->addItem($item); return $this; } @@ -65,7 +92,10 @@ public function addCheckableItem( bool $showItemExtra = false, bool $disabled = false ) : self { - $this->splitItem->addItem(new CheckableItem($text, $itemCallable, $showItemExtra, $disabled)); + $item = (new CheckableItem($text, $itemCallable, $showItemExtra, $disabled)) + ->setStyle($this->menu->getCheckableStyle()); + + $this->splitItem->addItem($item); return $this; } @@ -76,7 +106,10 @@ public function addRadioItem( bool $showItemExtra = false, bool $disabled = false ) : self { - $this->splitItem->addItem(new RadioItem($text, $itemCallable, $showItemExtra, $disabled)); + $item = (new RadioItem($text, $itemCallable, $showItemExtra, $disabled)) + ->setStyle($this->menu->getRadioStyle()); + + $this->splitItem->addItem($item); return $this; } @@ -105,8 +138,7 @@ public function addSubMenu(string $text, \Closure $callback) : self $callback($builder); - $menu = $builder->build(); - $menu->setParent($this->menu); + $menu = $this->createMenuClosure($builder); $this->splitItem->addItem(new MenuMenuItem( $text, @@ -139,4 +171,68 @@ public function build() : SplitItem { return $this->splitItem; } + + public function setCheckableStyle(callable $itemCallable) : self + { + $this->menu->setCheckableStyle($itemCallable); + + return $this; + } + + public function setRadioStyle(callable $itemCallable) : self + { + $this->menu->setRadioStyle($itemCallable); + + return $this; + } + + public function setSelectableStyle(callable $itemCallable) : self + { + $this->menu->setSelectableStyle($itemCallable); + + return $this; + } + + /** + * Create the submenu as a closure which is then unpacked in MenuMenuItem::showSubMenu + * This allows us to wait until all user-provided styles are parsed and apply them to nested items + * + * @param CliMenuBuilder $builder + * @return Closure + */ + protected function createMenuClosure(CliMenuBuilder $builder) : Closure + { + return function () use ($builder) { + $menu = $builder->build(); + + $menu->setParent($this->menu); + + $menu->setCheckableStyle(function (CheckableStyle $style) { + $style->fromArray($this->menu->getCheckableStyle()->toArray()); + }); + + // If user changed this style, persist to the menu so children RadioItems may use it + if ($this->menu->getRadioStyle()->getIsCustom()) { + $menu->setRadioStyle(function (RadioStyle $style) { + $style->fromArray($this->menu->getRadioStyle()->toArray()); + }); + } + + // If user changed this style, persist to the menu so children SelectableItems may use it + if ($this->menu->getSelectableStyle()->getIsCustom()) { + $menu->setSelectableStyle(function (SelectableStyle $style) { + $style->fromArray($this->menu->getSelectableStyle()->toArray()); + }); + } + + // This will be filled with user-provided items + foreach ($menu->getItems() as $item) { + if ($item instanceof SelectableInterface && !$item->getStyle()->getIsCustom()) { + $item->setStyle(clone $menu->getSelectableStyle()); + } + } + + return $menu; + }; + } } diff --git a/src/CliMenu.php b/src/CliMenu.php index 56174747..d1e58fbb 100644 --- a/src/CliMenu.php +++ b/src/CliMenu.php @@ -14,6 +14,9 @@ use PhpSchool\CliMenu\MenuItem\StaticItem; use PhpSchool\CliMenu\Dialogue\Confirm; use PhpSchool\CliMenu\Dialogue\Flash; +use PhpSchool\CliMenu\Style\CheckableStyle; +use PhpSchool\CliMenu\Style\RadioStyle; +use PhpSchool\CliMenu\Style\SelectableStyle; use PhpSchool\CliMenu\Terminal\TerminalFactory; use PhpSchool\CliMenu\Util\StringUtil as s; use PhpSchool\Terminal\InputCharacter; @@ -35,6 +38,21 @@ class CliMenu */ protected $style; + /** + * @var CheckableStyle + */ + private $checkableStyle; + + /** + * @var RadioStyle + */ + private $radioStyle; + + /** + * @var SelectableStyle + */ + private $selectableStyle; + /** * @var ?string */ @@ -90,10 +108,13 @@ public function __construct( Terminal $terminal = null, MenuStyle $style = null ) { - $this->title = $title; - $this->items = $items; - $this->terminal = $terminal ?: TerminalFactory::fromSystem(); - $this->style = $style ?: new MenuStyle($this->terminal); + $this->title = $title; + $this->items = $items; + $this->terminal = $terminal ?: TerminalFactory::fromSystem(); + $this->style = $style ?: new MenuStyle($this->terminal); + $this->checkableStyle = new CheckableStyle($this->terminal); + $this->radioStyle = new RadioStyle($this->terminal); + $this->selectableStyle = new SelectableStyle($this->terminal); $this->selectFirstItem(); } @@ -638,6 +659,42 @@ public function setStyle(MenuStyle $style) : void $this->style = $style; } + public function getCheckableStyle() : CheckableStyle + { + return $this->checkableStyle; + } + + public function setCheckableStyle(callable $itemCallable) : self + { + $itemCallable($this->checkableStyle); + + return $this; + } + + public function getRadioStyle() : RadioStyle + { + return $this->radioStyle; + } + + public function setRadioStyle(callable $itemCallable) : self + { + $itemCallable($this->radioStyle); + + return $this; + } + + public function getSelectableStyle() : SelectableStyle + { + return $this->selectableStyle; + } + + public function setSelectableStyle(callable $itemCallable) : self + { + $itemCallable($this->selectableStyle); + + return $this; + } + public function getCurrentFrame() : Frame { return $this->currentFrame; diff --git a/src/MenuItem/CheckableInterface.php b/src/MenuItem/CheckableInterface.php new file mode 100644 index 00000000..c8657415 --- /dev/null +++ b/src/MenuItem/CheckableInterface.php @@ -0,0 +1,7 @@ +disabled = $disabled; } - /** - * Execute the items callable if required - */ - public function getSelectAction() : ?callable - { - return function (CliMenu $cliMenu) { - $this->toggle(); - $cliMenu->redraw(); - - return ($this->selectAction)($cliMenu); - }; - } - - /** - * Return the raw string of text - */ - public function getText() : string + public function getStyle() : Style\ItemStyleInterface { - return $this->text; - } + if (!$this->style) { + $this->style = new Style\CheckableStyle(); + } - /** - * Set the raw string of text - */ - public function setText(string $text) : void - { - $this->text = $text; + return $this->style; } /** - * Can the item be selected + * @param Style\CheckableStyle|Style\ItemStyleInterface $style + * @return $this */ - public function canSelect() : bool + public function setStyle(Style\ItemStyleInterface $style) : self { - return !$this->disabled; - } + $this->style = $style; - public function showsItemExtra() : bool - { - return $this->showItemExtra; + return $this; } /** - * Enable showing item extra + * Execute the items callable if required */ - public function showItemExtra() : void + public function getSelectAction() : ?callable { - $this->showItemExtra = true; - } + return function (CliMenu $cliMenu) { + $this->toggle(); + $cliMenu->redraw(); - /** - * Disable showing item extra - */ - public function hideItemExtra() : void - { - $this->showItemExtra = false; + return ($this->selectAction)($cliMenu); + }; } } diff --git a/src/MenuItem/ItemStyleInterface.php b/src/MenuItem/ItemStyleInterface.php new file mode 100644 index 00000000..db98f82c --- /dev/null +++ b/src/MenuItem/ItemStyleInterface.php @@ -0,0 +1,12 @@ + */ -class MenuMenuItem implements MenuItemInterface +class MenuMenuItem implements MenuItemInterface, SelectableInterface { use SelectableTrait; /** - * @var CliMenu + * @var CliMenu|\Closure */ private $subMenu; - public function __construct(string $text, CliMenu $subMenu, bool $disabled = false) + public function __construct(string $text, $subMenu, bool $disabled = false) { $this->text = $text; $this->subMenu = $subMenu; @@ -64,6 +63,11 @@ public function getSubMenu() : CliMenu public function showSubMenu(CliMenu $parentMenu) : void { $parentMenu->closeThis(); + + if ($this->subMenu instanceof \Closure) { + $this->subMenu = ($this->subMenu)(); + } + $this->subMenu->open(); } } diff --git a/src/MenuItem/RadioInterface.php b/src/MenuItem/RadioInterface.php new file mode 100644 index 00000000..f9e6dc46 --- /dev/null +++ b/src/MenuItem/RadioInterface.php @@ -0,0 +1,7 @@ +disabled = $disabled; } + public function getStyle() : Style\ItemStyleInterface + { + if (!$this->style) { + $this->style = new Style\RadioStyle(); + } + + return $this->style; + } + + /** + * @param Style\RadioStyle|Style\ItemStyleInterface $style + * @return $this + */ + public function setStyle(Style\ItemStyleInterface $style) : self + { + $this->style = $style; + + return $this; + } + /** * Execute the items callable if required */ @@ -72,49 +73,4 @@ function (RadioItem $checkableItem) { return ($this->selectAction)($cliMenu); }; } - - /** - * Return the raw string of text - */ - public function getText() : string - { - return $this->text; - } - - /** - * Set the raw string of text - */ - public function setText(string $text) : void - { - $this->text = $text; - } - - /** - * Can the item be selected - */ - public function canSelect() : bool - { - return !$this->disabled; - } - - public function showsItemExtra() : bool - { - return $this->showItemExtra; - } - - /** - * Enable showing item extra - */ - public function showItemExtra() : void - { - $this->showItemExtra = true; - } - - /** - * Disable showing item extra - */ - public function hideItemExtra() : void - { - $this->showItemExtra = false; - } } diff --git a/src/MenuItem/SelectableInterface.php b/src/MenuItem/SelectableInterface.php new file mode 100644 index 00000000..f1dc0c1a --- /dev/null +++ b/src/MenuItem/SelectableInterface.php @@ -0,0 +1,9 @@ + */ -class SelectableItem implements MenuItemInterface +class SelectableItem implements MenuItemInterface, SelectableInterface { use SelectableTrait; diff --git a/src/MenuItem/SelectableTrait.php b/src/MenuItem/SelectableTrait.php index c162493a..bdae1359 100644 --- a/src/MenuItem/SelectableTrait.php +++ b/src/MenuItem/SelectableTrait.php @@ -3,6 +3,7 @@ namespace PhpSchool\CliMenu\MenuItem; use PhpSchool\CliMenu\MenuStyle; +use PhpSchool\CliMenu\Style; use PhpSchool\CliMenu\Util\StringUtil; /** @@ -10,30 +11,46 @@ */ trait SelectableTrait { - /** - * @var string - */ private $text = ''; + private $showItemExtra = false; + + private $disabled = false; + /** - * @var bool + * @var Style\ItemStyleInterface; */ - private $showItemExtra = false; + private $style; + + public function getStyle() : Style\ItemStyleInterface + { + if (!$this->style) { + $this->style = new Style\SelectableStyle(); + } + + return $this->style; + } /** - * @var bool + * @param Style\ItemStyleInterface|Style\SelectableStyle $style + * @return $this */ - private $disabled = false; + public function setStyle(Style\ItemStyleInterface $style) : self + { + $this->style = $style; + + return $this; + } /** * The output text for the item */ public function getRows(MenuStyle $style, bool $selected = false) : array { - $marker = sprintf("%s", $style->getMarker($selected)); + $marker = sprintf("%s", $this->style->getMarker($selected)); - $length = $style->getDisplaysExtra() - ? $style->getContentWidth() - (mb_strlen($style->getItemExtra()) + 2) + $length = $this->style->getDisplaysExtra() + ? $style->getContentWidth() - (mb_strlen($this->style->getItemExtra()) + 2) : $style->getContentWidth(); $rows = explode( @@ -50,7 +67,7 @@ public function getRows(MenuStyle $style, bool $selected = false) : array if ($key === 0) { return $this->showItemExtra - ? sprintf('%s%s %s', $text, str_repeat(' ', $length - mb_strlen($row)), $style->getItemExtra()) + ? sprintf('%s%s %s', $text, str_repeat(' ', $length - mb_strlen($row)), $this->style->getItemExtra()) : $text; } diff --git a/src/MenuItem/SplitItem.php b/src/MenuItem/SplitItem.php index 2808b333..4e5e0553 100644 --- a/src/MenuItem/SplitItem.php +++ b/src/MenuItem/SplitItem.php @@ -130,16 +130,12 @@ public function getRows(MenuStyle $style, bool $selected = false) : array array_map(function ($index, $item) use ($selected, $length, $style) { $isSelected = $selected && $index === $this->selectedItemIndex; - if ($item instanceof CheckableItem) { - $markerType = $item->getChecked() - ? $style->getCheckedMarker() - : $style->getUncheckedMarker(); - } elseif ($item instanceof RadioItem) { - $markerType = $item->getChecked() - ? $style->getRadioMarker() - : $style->getUnradioMarker(); + $itemStyle = $item->getStyle(); + + if ($item instanceof ToggableItemInterface) { + $markerType = $itemStyle->getMarker($item->getChecked()); } else { - $markerType = $style->getMarker($isSelected); + $markerType = $itemStyle->getMarker($isSelected); } $marker = $item->canSelect() diff --git a/src/MenuItem/ToggableTrait.php b/src/MenuItem/ToggableTrait.php index 6982d6b5..d11c538d 100644 --- a/src/MenuItem/ToggableTrait.php +++ b/src/MenuItem/ToggableTrait.php @@ -3,30 +3,35 @@ namespace PhpSchool\CliMenu\MenuItem; use PhpSchool\CliMenu\MenuStyle; +use PhpSchool\CliMenu\Style\ItemStyleInterface; use PhpSchool\CliMenu\Util\StringUtil; trait ToggableTrait { /** - * @var bool + * @var callable */ + private $selectAction; + + private $text = ''; + + private $showItemExtra = false; + + private $disabled = false; + private $checked = false; + /** + * @var ItemStyleInterface; + */ + private $style; + /** * The output text for the item */ public function getRows(MenuStyle $style, bool $selected = false) : array { - $markerTypes = [ - true => $this instanceof CheckableItem - ? $style->getCheckedMarker() - : $style->getRadioMarker(), - false => $this instanceof CheckableItem - ? $style->getUncheckedMarker() - : $style->getUnradioMarker(), - ]; - - $marker = sprintf("%s", $markerTypes[$this->checked]); + $marker = sprintf("%s", $this->style->getMarker($this->checked)); $length = $style->getDisplaysExtra() ? $style->getContentWidth() - (mb_strlen($style->getItemExtra()) + 2) @@ -85,4 +90,49 @@ public function getChecked() : bool { return $this->checked; } + + /** + * Return the raw string of text + */ + public function getText() : string + { + return $this->text; + } + + /** + * Set the raw string of text + */ + public function setText(string $text) : void + { + $this->text = $text; + } + + /** + * Can the item be selected + */ + public function canSelect() : bool + { + return !$this->disabled; + } + + public function showsItemExtra() : bool + { + return $this->showItemExtra; + } + + /** + * Enable showing item extra + */ + public function showItemExtra() : void + { + $this->showItemExtra = true; + } + + /** + * Disable showing item extra + */ + public function hideItemExtra() : void + { + $this->showItemExtra = false; + } } diff --git a/src/MenuStyle.php b/src/MenuStyle.php index f2139bca..5b0f8600 100644 --- a/src/MenuStyle.php +++ b/src/MenuStyle.php @@ -69,26 +69,6 @@ class MenuStyle */ private $unselectedMarker; - /** - * @var string - */ - private $checkedMarker; - - /** - * @var string - */ - private $uncheckedMarker; - - /** - * @var string - */ - private $radioMarker; - - /** - * @var string - */ - private $unradioMarker; - /** * @var string */ @@ -109,21 +89,6 @@ class MenuStyle */ private $coloursSetCode; - /** - * @var string - */ - private $invertedColoursSetCode = "\033[7m"; - - /** - * @var string - */ - private $invertedColoursUnsetCode = "\033[27m"; - - /** - * @var string - */ - private $coloursResetCode = "\033[0m"; - /** * @var int */ @@ -178,10 +143,6 @@ class MenuStyle 'margin' => 2, 'selectedMarker' => '● ', 'unselectedMarker' => '○ ', - 'checkedMarker' => '[✔] ', - 'uncheckedMarker' => '[ ] ', - 'radioMarker' => '[●] ', - 'unradioMarker' => '[○] ', 'itemExtra' => '✔', 'displaysExtra' => false, 'titleSeparator' => '=', @@ -193,36 +154,6 @@ class MenuStyle 'marginAuto' => false, ]; - /** - * @var array - */ - private static $availableForegroundColors = [ - 'black' => 30, - 'red' => 31, - 'green' => 32, - 'yellow' => 33, - 'blue' => 34, - 'magenta' => 35, - 'cyan' => 36, - 'white' => 37, - 'default' => 39, - ]; - - /** - * @var array - */ - private static $availableBackgroundColors = [ - 'black' => 40, - 'red' => 41, - 'green' => 42, - 'yellow' => 43, - 'blue' => 44, - 'magenta' => 45, - 'cyan' => 46, - 'white' => 47, - 'default' => 49, - ]; - /** * @var array */ @@ -253,10 +184,6 @@ public function __construct(Terminal $terminal = null) $this->setMargin(self::$defaultStyleValues['margin']); $this->setSelectedMarker(self::$defaultStyleValues['selectedMarker']); $this->setUnselectedMarker(self::$defaultStyleValues['unselectedMarker']); - $this->setCheckedMarker(self::$defaultStyleValues['checkedMarker']); - $this->setUncheckedMarker(self::$defaultStyleValues['uncheckedMarker']); - $this->setRadioMarker(self::$defaultStyleValues['radioMarker']); - $this->setUnradioMarker(self::$defaultStyleValues['unradioMarker']); $this->setItemExtra(self::$defaultStyleValues['itemExtra']); $this->setDisplaysExtra(self::$defaultStyleValues['displaysExtra']); $this->setTitleSeparator(self::$defaultStyleValues['titleSeparator']); @@ -278,10 +205,6 @@ public function hasChangedFromDefaults() : bool $this->margin, $this->selectedMarker, $this->unselectedMarker, - $this->checkedMarker, - $this->uncheckedMarker, - $this->radioMarker, - $this->unradioMarker, $this->itemExtra, $this->displaysExtra, $this->titleSeparator, @@ -312,13 +235,13 @@ public function getDisabledItemText(string $text) : string private function generateColoursSetCode() : void { if (!ctype_digit($this->fg)) { - $fgCode = self::$availableForegroundColors[$this->fg]; + $fgCode = Style\Colour::AVAILABLE_FOREGROUND_COLOURS[$this->fg]; } else { $fgCode = sprintf("38;5;%s", $this->fg); } if (!ctype_digit($this->bg)) { - $bgCode = self::$availableBackgroundColors[$this->bg]; + $bgCode = Style\Colour::AVAILABLE_BACKGROUND_COLOURS[$this->bg]; } else { $bgCode = sprintf("48;5;%s", $this->bg); } @@ -339,7 +262,7 @@ public function getColoursSetCode() : string */ public function getInvertedColoursSetCode() : string { - return $this->invertedColoursSetCode; + return Style\Colour::INVERTED_SET_CODE; } /** @@ -347,7 +270,7 @@ public function getInvertedColoursSetCode() : string */ public function getInvertedColoursUnsetCode() : string { - return $this->invertedColoursUnsetCode; + return Style\Colour::INVERTED_UNSET_CODE; } /** @@ -355,7 +278,7 @@ public function getInvertedColoursUnsetCode() : string */ public function getColoursResetCode() : string { - return $this->coloursResetCode; + return Style\Colour::RESET_CODE; } /** @@ -462,7 +385,7 @@ private function generatePaddingTopBottomRows() : void str_repeat(' ', $this->paddingLeftRight), $borderColour, str_repeat(' ', $this->borderRightWidth), - $this->coloursResetCode + Style\Colour::RESET_CODE ); $this->paddingTopBottomRows = array_fill(0, $this->paddingTopBottom, $paddingRow); @@ -589,54 +512,6 @@ public function getMarker(bool $selected) : string return $selected ? $this->selectedMarker : $this->unselectedMarker; } - public function getCheckedMarker() : string - { - return $this->checkedMarker; - } - - public function setCheckedMarker(string $marker) : self - { - $this->checkedMarker = $marker; - - return $this; - } - - public function getUncheckedMarker() : string - { - return $this->uncheckedMarker; - } - - public function setUncheckedMarker(string $marker) : self - { - $this->uncheckedMarker = $marker; - - return $this; - } - - public function getRadioMarker() : string - { - return $this->radioMarker; - } - - public function setRadioMarker(string $marker) : self - { - $this->radioMarker = $marker; - - return $this; - } - - public function getUnradioMarker() : string - { - return $this->unradioMarker; - } - - public function setUnradioMarker(string $marker) : self - { - $this->unradioMarker = $marker; - - return $this; - } - public function setItemExtra(string $itemExtra) : self { $this->itemExtra = $itemExtra; @@ -680,7 +555,7 @@ private function generateBorderRows() : void str_repeat(' ', $this->margin), $this->getBorderColourCode(), str_repeat(' ', $this->width), - $this->coloursResetCode + Style\Colour::RESET_CODE ); $this->borderTopRows = array_fill(0, $this->borderTopWidth, $borderRow); @@ -817,7 +692,7 @@ public function getBorderColour() : string public function getBorderColourCode() : string { if (!ctype_digit($this->borderColour)) { - $borderColourCode = self::$availableBackgroundColors[$this->borderColour]; + $borderColourCode = Style\Colour::AVAILABLE_BACKGROUND_COLOURS[$this->borderColour]; } else { $borderColourCode = sprintf("48;5;%s", $this->borderColour); } diff --git a/src/Style/CheckableStyle.php b/src/Style/CheckableStyle.php new file mode 100644 index 00000000..30dae979 --- /dev/null +++ b/src/Style/CheckableStyle.php @@ -0,0 +1,61 @@ + 'white', + 'bg' => 'blue', + 'markerOn' => '[✔] ', + 'markerOff' => '[ ] ', + 'itemExtra' => '✔', + 'displaysExtra' => false, + ]; + + public function __construct(Terminal $terminal = null) + { + $this->terminal = $terminal ?: TerminalFactory::fromSystem(); + + $this->fg = self::DEFAULT_STYLES['fg']; + $this->bg = self::DEFAULT_STYLES['bg']; + + $this->generateColoursSetCode(); + + $this->setMarkerOn(self::DEFAULT_STYLES['markerOn']); + $this->setMarkerOff(self::DEFAULT_STYLES['markerOff']); + $this->setItemExtra(self::DEFAULT_STYLES['itemExtra']); + $this->setDisplaysExtra(self::DEFAULT_STYLES['displaysExtra']); + + $this->custom = false; + } + + public function toArray(): array + { + return [ + 'fg' => $this->fg, + 'bg' => $this->bg, + 'markerOn' => $this->markerOn, + 'markerOff' => $this->markerOff, + 'itemExtra' => $this->itemExtra, + 'displaysExtra' => $this->displaysExtra, + ]; + } + + public function fromArray(array $style) : self + { + $this->fg = $style['fg'] ?? $this->fg; + $this->bg = $style['bg'] ?? $this->bg; + $this->markerOn = $style['markerOn'] ?? $this->markerOn; + $this->markerOff = $style['markerOff'] ?? $this->markerOff; + $this->itemExtra = $style['itemExtra'] ?? $this->itemExtra; + $this->displaysExtra = $style['displaysExtra'] ?? $this->displaysExtra; + + return $this; + } +} diff --git a/src/Style/Colour.php b/src/Style/Colour.php new file mode 100644 index 00000000..e21ed533 --- /dev/null +++ b/src/Style/Colour.php @@ -0,0 +1,36 @@ + 30, + 'red' => 31, + 'green' => 32, + 'yellow' => 33, + 'blue' => 34, + 'magenta' => 35, + 'cyan' => 36, + 'white' => 37, + 'default' => 39, + ]; + + public const AVAILABLE_BACKGROUND_COLOURS = [ + 'black' => 40, + 'red' => 41, + 'green' => 42, + 'yellow' => 43, + 'blue' => 44, + 'magenta' => 45, + 'cyan' => 46, + 'white' => 47, + 'default' => 49, + ]; + + public const INVERTED_SET_CODE = "\033[7m"; + + public const INVERTED_UNSET_CODE = "\033[27m"; + + public const RESET_CODE = "\033[0m"; +} diff --git a/src/Style/ItemStyleInterface.php b/src/Style/ItemStyleInterface.php new file mode 100644 index 00000000..00043149 --- /dev/null +++ b/src/Style/ItemStyleInterface.php @@ -0,0 +1,36 @@ +custom; + } + + /** + * Get the colour code for Bg and Fg + */ + public function getColoursSetCode() : string + { + return $this->coloursSetCode; + } + + public function getFg() + { + return $this->fg; + } + + public function setFg(string $fg, string $fallback = null) : self + { + $this->custom = true; + + $this->fg = ColourUtil::validateColour( + $this->terminal, + $fg, + $fallback + ); + $this->generateColoursSetCode(); + + return $this; + } + + public function getBg() + { + return $this->bg; + } + + public function setBg(string $bg, string $fallback = null) : self + { + $this->custom = true; + + $this->bg = ColourUtil::validateColour( + $this->terminal, + $bg, + $fallback + ); + + $this->generateColoursSetCode(); + + return $this; + } + + public function getMarker(bool $selected) : string + { + return $selected ? $this->markerOn : $this->markerOff; + } + + public function getMarkerOn() : string + { + return $this->markerOn; + } + + public function setMarkerOn(string $marker) : self + { + $this->custom = true; + + $this->markerOn = $marker; + + return $this; + } + + public function getMarkerOff() : string + { + return $this->markerOff; + } + + public function setMarkerOff(string $marker) : self + { + $this->custom = true; + + $this->markerOff = $marker; + + return $this; + } + + public function getItemExtra() : string + { + return $this->itemExtra; + } + + public function setItemExtra(string $itemExtra) : self + { + $this->custom = true; + + $this->itemExtra = $itemExtra; + + return $this; + } + + public function getDisplaysExtra() : bool + { + return $this->displaysExtra; + } + + public function setDisplaysExtra(bool $displaysExtra) : self + { + $this->custom = true; + + $this->displaysExtra = $displaysExtra; + + return $this; + } + + /** + * Generates the ansi escape sequence to set the colours + */ + private function generateColoursSetCode() : void + { + if (!ctype_digit($this->fg)) { + $fgCode = Colour::AVAILABLE_FOREGROUND_COLOURS[$this->fg]; + } else { + $fgCode = sprintf("38;5;%s", $this->fg); + } + + if (!ctype_digit($this->bg)) { + $bgCode = Colour::AVAILABLE_BACKGROUND_COLOURS[$this->bg]; + } else { + $bgCode = sprintf("48;5;%s", $this->bg); + } + + $this->coloursSetCode = sprintf("\033[%s;%sm", $fgCode, $bgCode); + } +} diff --git a/src/Style/RadioStyle.php b/src/Style/RadioStyle.php new file mode 100644 index 00000000..d95f86b0 --- /dev/null +++ b/src/Style/RadioStyle.php @@ -0,0 +1,61 @@ + 'white', + 'bg' => 'blue', + 'markerOn' => '[●] ', + 'markerOff' => '[○] ', + 'itemExtra' => '✔', + 'displaysExtra' => false, + ]; + + public function __construct(Terminal $terminal = null) + { + $this->terminal = $terminal ?: TerminalFactory::fromSystem(); + + $this->fg = self::DEFAULT_STYLES['fg']; + $this->bg = self::DEFAULT_STYLES['bg']; + + $this->generateColoursSetCode(); + + $this->setMarkerOn(self::DEFAULT_STYLES['markerOn']); + $this->setMarkerOff(self::DEFAULT_STYLES['markerOff']); + $this->setItemExtra(self::DEFAULT_STYLES['itemExtra']); + $this->setDisplaysExtra(self::DEFAULT_STYLES['displaysExtra']); + + $this->custom = false; + } + + public function toArray(): array + { + return [ + 'fg' => $this->fg, + 'bg' => $this->bg, + 'markerOn' => $this->markerOn, + 'markerOff' => $this->markerOff, + 'itemExtra' => $this->itemExtra, + 'displaysExtra' => $this->displaysExtra, + ]; + } + + public function fromArray(array $style) : self + { + $this->fg = $style['fg'] ?? $this->fg; + $this->bg = $style['bg'] ?? $this->bg; + $this->markerOn = $style['markerOn'] ?? $this->markerOn; + $this->markerOff = $style['markerOff'] ?? $this->markerOff; + $this->itemExtra = $style['itemExtra'] ?? $this->itemExtra; + $this->displaysExtra = $style['displaysExtra'] ?? $this->displaysExtra; + + return $this; + } +} diff --git a/src/Style/SelectableStyle.php b/src/Style/SelectableStyle.php new file mode 100644 index 00000000..0ccf690e --- /dev/null +++ b/src/Style/SelectableStyle.php @@ -0,0 +1,61 @@ + 'white', + 'bg' => 'blue', + 'markerOn' => '● ', + 'markerOff' => '○ ', + 'itemExtra' => '✔', + 'displaysExtra' => false, + ]; + + public function __construct(Terminal $terminal = null) + { + $this->terminal = $terminal ?: TerminalFactory::fromSystem(); + + $this->fg = self::DEFAULT_STYLES['fg']; + $this->bg = self::DEFAULT_STYLES['bg']; + + $this->generateColoursSetCode(); + + $this->setMarkerOn(self::DEFAULT_STYLES['markerOn']); + $this->setMarkerOff(self::DEFAULT_STYLES['markerOff']); + $this->setItemExtra(self::DEFAULT_STYLES['itemExtra']); + $this->setDisplaysExtra(self::DEFAULT_STYLES['displaysExtra']); + + $this->custom = false; + } + + public function toArray(): array + { + return [ + 'fg' => $this->fg, + 'bg' => $this->bg, + 'markerOn' => $this->markerOn, + 'markerOff' => $this->markerOff, + 'itemExtra' => $this->itemExtra, + 'displaysExtra' => $this->displaysExtra, + ]; + } + + public function fromArray(array $style) : self + { + $this->fg = $style['fg'] ?? $this->fg; + $this->bg = $style['bg'] ?? $this->bg; + $this->markerOn = $style['markerOn'] ?? $this->markerOn; + $this->markerOff = $style['markerOff'] ?? $this->markerOff; + $this->itemExtra = $style['itemExtra'] ?? $this->itemExtra; + $this->displaysExtra = $style['displaysExtra'] ?? $this->displaysExtra; + + return $this; + } +} From cf5816ce9becbb6ee473a6a4585460c228df01a2 Mon Sep 17 00:00:00 2001 From: Juan Treminio Date: Wed, 18 Dec 2019 15:44:17 -0600 Subject: [PATCH 2/8] Code cleanup --- src/Builder/CliMenuBuilder.php | 13 +++++-------- src/Builder/SplitItemBuilder.php | 9 ++++++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Builder/CliMenuBuilder.php b/src/Builder/CliMenuBuilder.php index ce3419de..596b2f9f 100644 --- a/src/Builder/CliMenuBuilder.php +++ b/src/Builder/CliMenuBuilder.php @@ -200,7 +200,7 @@ public function addSubMenu(string $text, Closure $callback) : self $callback = $callback->bindTo($builder); $callback($builder); - $menu = $this->createMenuClosure($builder, $this->menu); + $menu = $this->createMenuClosure($builder); $item = (new MenuMenuItem($text, $menu, $builder->isMenuDisabled())) ->setStyle($this->menu->getSelectableStyle()); @@ -214,7 +214,7 @@ public function addSubMenu(string $text, Closure $callback) : self public function addSubMenuFromBuilder(string $text, CliMenuBuilder $builder) : self { - $menu = $this->createMenuClosure($builder, $this->menu); + $menu = $this->createMenuClosure($builder); $item = (new MenuMenuItem($text, $menu, $builder->isMenuDisabled())) ->setStyle($this->menu->getSelectableStyle()); @@ -231,17 +231,14 @@ public function addSubMenuFromBuilder(string $text, CliMenuBuilder $builder) : s * This allows us to wait until all user-provided styles are parsed and apply them to nested items * * @param CliMenuBuilder|SplitItemBuilder $builder - * @param CliMenu $parent * @return Closure */ - protected function createMenuClosure($builder, CliMenu $parent = null) : Closure + protected function createMenuClosure($builder) : Closure { - return function () use ($builder, $parent) { + return function () use ($builder) { $menu = $builder->build(); - if ($parent) { - $menu->setParent($parent); - } + $menu->setParent($this->menu); // we apply the parent theme if nothing was changed // if no styles were changed in this sub-menu diff --git a/src/Builder/SplitItemBuilder.php b/src/Builder/SplitItemBuilder.php index f3428209..3572bc81 100644 --- a/src/Builder/SplitItemBuilder.php +++ b/src/Builder/SplitItemBuilder.php @@ -207,9 +207,12 @@ protected function createMenuClosure(CliMenuBuilder $builder) : Closure $menu->setParent($this->menu); - $menu->setCheckableStyle(function (CheckableStyle $style) { - $style->fromArray($this->menu->getCheckableStyle()->toArray()); - }); + // If user changed this style, persist to the menu so children CheckableItems may use it + if ($this->menu->getCheckableStyle()->getIsCustom()) { + $menu->setCheckableStyle(function (CheckableStyle $style) { + $style->fromArray($this->menu->getCheckableStyle()->toArray()); + }); + } // If user changed this style, persist to the menu so children RadioItems may use it if ($this->menu->getRadioStyle()->getIsCustom()) { From cc0b96855397f9adbc9013760fe95ff5827a0c5a Mon Sep 17 00:00:00 2001 From: Juan Treminio Date: Wed, 18 Dec 2019 20:07:30 -0600 Subject: [PATCH 3/8] Updates tests to use Item Style classes --- src/MenuItem/CheckableItem.php | 6 +- src/MenuItem/MenuMenuItem.php | 7 ++ src/MenuItem/RadioItem.php | 6 +- src/MenuItem/SelectableInterface.php | 2 - src/MenuItem/SelectableItem.php | 4 + src/MenuItem/SelectableTrait.php | 4 - src/MenuItem/SplitItem.php | 22 +++-- test/Builder/CliMenuBuilderTest.php | 4 - test/MenuItem/MenuMenuItemTest.php | 17 ++-- test/MenuItem/SelectableItemTest.php | 30 +++--- test/MenuItem/SplitItemTest.php | 141 +++++++++++++++------------ test/MenuStyleTest.php | 8 -- 12 files changed, 126 insertions(+), 125 deletions(-) diff --git a/src/MenuItem/CheckableItem.php b/src/MenuItem/CheckableItem.php index 3d1bbcda..99883d48 100644 --- a/src/MenuItem/CheckableItem.php +++ b/src/MenuItem/CheckableItem.php @@ -19,14 +19,12 @@ public function __construct( $this->selectAction = $selectAction; $this->showItemExtra = $showItemExtra; $this->disabled = $disabled; + + $this->style = new Style\CheckableStyle(); } public function getStyle() : Style\ItemStyleInterface { - if (!$this->style) { - $this->style = new Style\CheckableStyle(); - } - return $this->style; } diff --git a/src/MenuItem/MenuMenuItem.php b/src/MenuItem/MenuMenuItem.php index 7db6e8ee..31fabacb 100644 --- a/src/MenuItem/MenuMenuItem.php +++ b/src/MenuItem/MenuMenuItem.php @@ -3,6 +3,7 @@ namespace PhpSchool\CliMenu\MenuItem; use PhpSchool\CliMenu\CliMenu; +use PhpSchool\CliMenu\Style; /** * @author Michael Woodward @@ -21,6 +22,8 @@ public function __construct(string $text, $subMenu, bool $disabled = false) $this->text = $text; $this->subMenu = $subMenu; $this->disabled = $disabled; + + $this->style = new Style\SelectableStyle(); } /** @@ -54,6 +57,10 @@ public function setText(string $text) : void */ public function getSubMenu() : CliMenu { + if ($this->subMenu instanceof \Closure) { + $this->subMenu = ($this->subMenu)(); + } + return $this->subMenu; } diff --git a/src/MenuItem/RadioItem.php b/src/MenuItem/RadioItem.php index 9568f6b7..d974173e 100644 --- a/src/MenuItem/RadioItem.php +++ b/src/MenuItem/RadioItem.php @@ -19,14 +19,12 @@ public function __construct( $this->selectAction = $selectAction; $this->showItemExtra = $showItemExtra; $this->disabled = $disabled; + + $this->style = new Style\RadioStyle(); } public function getStyle() : Style\ItemStyleInterface { - if (!$this->style) { - $this->style = new Style\RadioStyle(); - } - return $this->style; } diff --git a/src/MenuItem/SelectableInterface.php b/src/MenuItem/SelectableInterface.php index f1dc0c1a..7b5ced8f 100644 --- a/src/MenuItem/SelectableInterface.php +++ b/src/MenuItem/SelectableInterface.php @@ -2,8 +2,6 @@ namespace PhpSchool\CliMenu\MenuItem; -use PhpSchool\CliMenu\Style; - interface SelectableInterface extends ItemStyleInterface { } diff --git a/src/MenuItem/SelectableItem.php b/src/MenuItem/SelectableItem.php index 738cfe6e..e7327337 100644 --- a/src/MenuItem/SelectableItem.php +++ b/src/MenuItem/SelectableItem.php @@ -2,6 +2,8 @@ namespace PhpSchool\CliMenu\MenuItem; +use PhpSchool\CliMenu\Style; + /** * @author Michael Woodward */ @@ -24,6 +26,8 @@ public function __construct( $this->selectAction = $selectAction; $this->showItemExtra = $showItemExtra; $this->disabled = $disabled; + + $this->style = new Style\SelectableStyle(); } /** diff --git a/src/MenuItem/SelectableTrait.php b/src/MenuItem/SelectableTrait.php index bdae1359..80a71aae 100644 --- a/src/MenuItem/SelectableTrait.php +++ b/src/MenuItem/SelectableTrait.php @@ -24,10 +24,6 @@ trait SelectableTrait public function getStyle() : Style\ItemStyleInterface { - if (!$this->style) { - $this->style = new Style\SelectableStyle(); - } - return $this->style; } diff --git a/src/MenuItem/SplitItem.php b/src/MenuItem/SplitItem.php index 4e5e0553..1b366487 100644 --- a/src/MenuItem/SplitItem.php +++ b/src/MenuItem/SplitItem.php @@ -130,12 +130,20 @@ public function getRows(MenuStyle $style, bool $selected = false) : array array_map(function ($index, $item) use ($selected, $length, $style) { $isSelected = $selected && $index === $this->selectedItemIndex; - $itemStyle = $item->getStyle(); + if ($item instanceof ItemStyleInterface) { + $itemStyle = $item->getStyle(); - if ($item instanceof ToggableItemInterface) { - $markerType = $itemStyle->getMarker($item->getChecked()); + $getMarkerType = $item instanceof ToggableItemInterface + ? $item->getChecked() + : $isSelected; + + $markerType = $itemStyle->getMarker($getMarkerType); + $displaysExtraType = $itemStyle->getDisplaysExtra(); + $itemExtraType = $itemStyle->getItemExtra(); } else { - $markerType = $itemStyle->getMarker($isSelected); + $markerType = $style->getMarker($isSelected); + $displaysExtraType = $style->getDisplaysExtra(); + $itemExtraType = $style->getItemExtra(); } $marker = $item->canSelect() @@ -143,10 +151,10 @@ public function getRows(MenuStyle $style, bool $selected = false) : array : ''; $itemExtra = ''; - if ($style->getDisplaysExtra()) { + if ($displaysExtraType) { $itemExtra = $item->showsItemExtra() - ? sprintf(' %s', $style->getItemExtra()) - : sprintf(' %s', str_repeat(' ', mb_strlen($style->getItemExtra()))); + ? sprintf(' %s', $itemExtraType) + : sprintf(' %s', str_repeat(' ', mb_strlen($itemExtraType))); } return $this->buildCell( diff --git a/test/Builder/CliMenuBuilderTest.php b/test/Builder/CliMenuBuilderTest.php index 60a6b77f..e634a525 100644 --- a/test/Builder/CliMenuBuilderTest.php +++ b/test/Builder/CliMenuBuilderTest.php @@ -67,8 +67,6 @@ public function testModifyStyles() : void $builder->setMargin(4); $builder->setUnselectedMarker('>'); $builder->setSelectedMarker('x'); - $builder->setUncheckedMarker('-'); - $builder->setCheckedMarker('+'); $builder->setItemExtra('*'); $builder->setTitleSeparator('-'); @@ -83,8 +81,6 @@ public function testModifyStyles() : void self::assertEquals(4, $style->getMargin()); self::assertEquals('>', $style->getUnselectedMarker()); self::assertEquals('x', $style->getSelectedMarker()); - self::assertEquals('-', $style->getUncheckedMarker()); - self::assertEquals('+', $style->getCheckedMarker()); self::assertEquals('*', $style->getItemExtra()); self::assertEquals('-', $style->getTitleSeparator()); } diff --git a/test/MenuItem/MenuMenuItemTest.php b/test/MenuItem/MenuMenuItemTest.php index 16c03bd8..2199ab0d 100644 --- a/test/MenuItem/MenuMenuItemTest.php +++ b/test/MenuItem/MenuMenuItemTest.php @@ -55,11 +55,12 @@ public function testGetRows() : void $menuStyle = new MenuStyle($terminal); $menuStyle->setPaddingLeftRight(0); $menuStyle->setWidth(10); - $menuStyle->setUnselectedMarker('* '); $subMenu = $this->createMock(CliMenu::class); $item = new MenuMenuItem('Item', $subMenu); + $item->getStyle() + ->setMarkerOff('* '); $this->assertEquals(['* Item'], $item->getRows($menuStyle)); } @@ -71,11 +72,12 @@ public function testGetRowsWithUnSelectedMarker() : void $menuStyle = new MenuStyle($terminal); $menuStyle->setPaddingLeftRight(0); $menuStyle->setWidth(10); - $menuStyle->setUnselectedMarker('* '); $subMenu = $this->createMock(CliMenu::class); $item = new MenuMenuItem('Item', $subMenu); + $item->getStyle() + ->setMarkerOff('* '); $this->assertEquals(['* Item'], $item->getRows($menuStyle)); $this->assertEquals(['* Item'], $item->getRows($menuStyle, false)); } @@ -89,17 +91,13 @@ public function testGetRowsWithSelectedMarker() : void ->method('getContentWidth') ->will($this->returnValue(10)); - $menuStyle - ->expects($this->once()) - ->method('getMarker') - ->with(true) - ->will($this->returnValue('= ')); - $subMenu = $this->getMockBuilder(CliMenu::class) ->disableOriginalConstructor() ->getMock(); $item = new MenuMenuItem('Item', $subMenu); + $item->getStyle() + ->setMarkerOn('= '); $this->assertEquals(['= Item'], $item->getRows($menuStyle, true)); } @@ -112,11 +110,12 @@ public function testGetRowsWithMultipleLines() : void $menuStyle = new MenuStyle($terminal); $menuStyle->setPaddingLeftRight(0); $menuStyle->setWidth(10); - $menuStyle->setUnselectedMarker('* '); $subMenu = $this->createMock(CliMenu::class); $item = new MenuMenuItem('LONG ITEM LINE', $subMenu); + $item->getStyle() + ->setMarkerOff('* '); $this->assertEquals( [ "* LONG", diff --git a/test/MenuItem/SelectableItemTest.php b/test/MenuItem/SelectableItemTest.php index c78e9fec..5b9c09af 100644 --- a/test/MenuItem/SelectableItemTest.php +++ b/test/MenuItem/SelectableItemTest.php @@ -87,14 +87,10 @@ public function testGetRowsWithUnSelectedMarker() : void ->method('getContentWidth') ->will($this->returnValue(10)); - $menuStyle - ->expects($this->exactly(2)) - ->method('getMarker') - ->with(false) - ->will($this->returnValue('* ')); - $item = new SelectableItem('Item', function () { }); + $item->getStyle() + ->setMarkerOff('* '); $this->assertEquals(['* Item'], $item->getRows($menuStyle)); $this->assertEquals(['* Item'], $item->getRows($menuStyle, false)); } @@ -108,14 +104,10 @@ public function testGetRowsWithSelectedMarker() : void ->method('getContentWidth') ->will($this->returnValue(10)); - $menuStyle - ->expects($this->once()) - ->method('getMarker') - ->with(true) - ->will($this->returnValue('= ')); - $item = new SelectableItem('Item', function () { }); + $item->getStyle() + ->setMarkerOn('= '); $this->assertEquals(['= Item'], $item->getRows($menuStyle, true)); } @@ -127,12 +119,13 @@ public function testGetRowsWithItemExtra() : void $menuStyle = new MenuStyle($terminal); $menuStyle->setPaddingLeftRight(0); $menuStyle->setWidth(20); - $menuStyle->setItemExtra('[EXTRA]'); - $menuStyle->setDisplaysExtra(true); - $menuStyle->setUnselectedMarker('* '); $item = new SelectableItem('Item', function () { }, true); + $item->getStyle() + ->setItemExtra('[EXTRA]') + ->setDisplaysExtra(true) + ->setMarkerOff('* '); $this->assertEquals(['* Item [EXTRA]'], $item->getRows($menuStyle)); } @@ -144,12 +137,13 @@ public function testGetRowsWithMultipleLinesWithItemExtra() : void $menuStyle = new MenuStyle($terminal); $menuStyle->setPaddingLeftRight(0); $menuStyle->setWidth(20); - $menuStyle->setItemExtra('[EXTRA]'); - $menuStyle->setDisplaysExtra(true); - $menuStyle->setUnselectedMarker('* '); $item = new SelectableItem('LONG ITEM LINE', function () { }, true); + $item->getStyle() + ->setItemExtra('[EXTRA]') + ->setDisplaysExtra(true) + ->setMarkerOff('* '); $this->assertEquals( [ "* LONG ITEM [EXTRA]", diff --git a/test/MenuItem/SplitItemTest.php b/test/MenuItem/SplitItemTest.php index d97b1b1f..0487b10a 100644 --- a/test/MenuItem/SplitItemTest.php +++ b/test/MenuItem/SplitItemTest.php @@ -12,6 +12,9 @@ use PhpSchool\CliMenu\MenuItem\SplitItem; use PhpSchool\CliMenu\MenuItem\StaticItem; use PhpSchool\CliMenu\MenuStyle; +use PhpSchool\CliMenu\Style\CheckableStyle; +use PhpSchool\CliMenu\Style\RadioStyle; +use PhpSchool\CliMenu\Style\SelectableStyle; use PhpSchool\Terminal\Terminal; use PHPUnit\Framework\TestCase; @@ -193,17 +196,16 @@ public function testGetRowsWithOneItemSelected() : void ->method('getContentWidth') ->will($this->returnValue(30)); - $menuStyle - ->expects($this->any()) - ->method('getMarker') - ->willReturnMap([[true, '= '], [false, '* ']]); + $selectableStyle = new SelectableStyle(); + $selectableStyle->setMarkerOn('= ') + ->setMarkerOff('* '); $item = new SplitItem( [ - new SelectableItem('Item One', function () { - }), - new SelectableItem('Item Two', function () { - }) + (new SelectableItem('Item One', function () { + }))->setStyle($selectableStyle), + (new SelectableItem('Item Two', function () { + }))->setStyle($selectableStyle), ] ); @@ -241,18 +243,15 @@ public function testGetRowsWithMultipleLinesWithUnSelectedMarker() : void ->method('getContentWidth') ->will($this->returnValue(30)); - $menuStyle - ->expects($this->any()) - ->method('getMarker') - ->with(false) - ->will($this->returnValue('* ')); + $selectableStyle = new SelectableStyle(); + $selectableStyle->setMarkerOff('* '); $item = new SplitItem( [ - new SelectableItem("Item\nOne", function () { - }), - new SelectableItem("Item\nTwo", function () { - }) + (new SelectableItem("Item\nOne", function () { + }))->setStyle($selectableStyle), + (new SelectableItem("Item\nTwo", function () { + }))->setStyle($selectableStyle), ] ); @@ -274,17 +273,16 @@ public function testGetRowsWithMultipleLinesWithOneItemSelected() : void ->method('getContentWidth') ->will($this->returnValue(30)); - $menuStyle - ->expects($this->any()) - ->method('getMarker') - ->willReturnMap([[true, '= '], [false, '* ']]); + $selectableStyle = new SelectableStyle(); + $selectableStyle->setMarkerOn('= ') + ->setMarkerOff('* '); $item = new SplitItem( [ - new SelectableItem("Item\nOne", function () { - }), - new SelectableItem("Item\nTwo", function () { - }) + (new SelectableItem("Item\nOne", function () { + }))->setStyle($selectableStyle), + (new SelectableItem("Item\nTwo", function () { + }))->setStyle($selectableStyle), ] ); @@ -299,6 +297,9 @@ public function testGetRowsWithMultipleLinesWithOneItemSelected() : void ); } + /** + * @todo Refactor this to use SelectableStyle() exclusively + */ public function testGetRowsWithItemExtra() : void { $terminal = $this->createMock(Terminal::class); @@ -311,18 +312,26 @@ public function testGetRowsWithItemExtra() : void $menuStyle->setDisplaysExtra(true); $menuStyle->setUnselectedMarker('* '); + $selectableStyle = new SelectableStyle(); + $selectableStyle->setItemExtra('[EXTRA]') + ->setDisplaysExtra(true) + ->setMarkerOff('* '); + $item = new SplitItem( [ - new SelectableItem('Item 1', function () { - }, true), - new SelectableItem('Item 2', function () { - }, true) + (new SelectableItem('Item 1', function () { + }, true))->setStyle($selectableStyle), + (new SelectableItem('Item 2', function () { + }, true))->setStyle($selectableStyle), ] ); self::assertEquals(['* Item 1 [EXTRA] * Item 2 [EXTRA] '], $item->getRows($menuStyle)); } + /** + * @todo Refactor this to use SelectableStyle() exclusively + */ public function testGetRowsWithMultipleLinesWithItemExtra() : void { $terminal = $this->createMock(Terminal::class); @@ -335,12 +344,17 @@ public function testGetRowsWithMultipleLinesWithItemExtra() : void $menuStyle->setDisplaysExtra(true); $menuStyle->setUnselectedMarker('* '); + $selectableStyle = new SelectableStyle(); + $selectableStyle->setItemExtra(' [EXTRA]') + ->setDisplaysExtra(true) + ->setMarkerOff('* '); + $item = new SplitItem( [ - new SelectableItem("Item 1\nItem 1", function () { - }, true), - new SelectableItem("Item 2\nItem 2", function () { - }, true) + (new SelectableItem("Item 1\nItem 1", function () { + }, true))->setStyle($selectableStyle), + (new SelectableItem("Item 2\nItem 2", function () { + }, true))->setStyle($selectableStyle), ] ); @@ -365,12 +379,17 @@ public function testGetRowsWithMultipleLinesWithItemExtraOnOne() : void $menuStyle->setDisplaysExtra(true); $menuStyle->setUnselectedMarker('* '); + $selectableStyle = new SelectableStyle(); + $selectableStyle->setItemExtra(' [EXTRA] ') + ->setDisplaysExtra(true) + ->setMarkerOff('* '); + $item = new SplitItem( [ - new SelectableItem("Item 1\nItem 1", function () { - }), - new SelectableItem("Item 2\nItem 2", function () { - }, true) + (new SelectableItem("Item 1\nItem 1", function () { + }))->setStyle($selectableStyle), + (new SelectableItem("Item 2\nItem 2", function () { + }, true))->setStyle($selectableStyle), ] ); @@ -479,21 +498,17 @@ public function testCheckableItem() : void ->method('getContentWidth') ->will($this->returnValue(30)); - $menuStyle - ->expects($this->any()) - ->method('getCheckedMarker') - ->willReturn('[✔] '); - - $menuStyle - ->expects($this->any()) - ->method('getUncheckedMarker') - ->willReturn('[ ] '); - $checkableItem1 = new CheckableItem('Item One', function () { }); + $checkableItem1->getStyle() + ->setMarkerOff('[ ] ') + ->setMarkerOn('[✔] '); $checkableItem2 = new CheckableItem('Item Two', function () { }); + $checkableItem2->getStyle() + ->setMarkerOff('[ ] ') + ->setMarkerOn('[✔] '); $item = new SplitItem( [ @@ -520,26 +535,22 @@ public function testRadioItem() : void ->method('getContentWidth') ->will($this->returnValue(30)); - $menuStyle - ->expects($this->any()) - ->method('getRadioMarker') - ->willReturn('[●] '); - - $menuStyle - ->expects($this->any()) - ->method('getUnradioMarker') - ->willReturn('[○] '); + $radioStyle = new RadioStyle(); + $radioStyle->setMarkerOn('[+] ') + ->setMarkerOff('[-] '); - $checkableItem1 = new RadioItem('Item One', function () { + $radioItem1 = new RadioItem('Item One', function () { }); + $radioItem1->setStyle($radioStyle); - $checkableItem2 = new RadioItem('Item Two', function () { + $radioItem2 = new RadioItem('Item Two', function () { }); + $radioItem2->setStyle($radioStyle); $item = new SplitItem( [ - $checkableItem1, - $checkableItem2, + $radioItem1, + $radioItem2, ] ); @@ -561,14 +572,14 @@ public function testRadioItem() : void $item->setSelectedItemIndex(0); - self::assertEquals(['[○] Item One [○] Item Two '], $item->getRows($menuStyle, true)); + self::assertEquals(['[-] Item One [-] Item Two '], $item->getRows($menuStyle, true)); - $checkableItem1->getSelectAction()($cliMenu); + $radioItem1->getSelectAction()($cliMenu); - self::assertEquals(['[●] Item One [○] Item Two '], $item->getRows($menuStyle, true)); + self::assertEquals(['[+] Item One [-] Item Two '], $item->getRows($menuStyle, true)); - $checkableItem2->getSelectAction()($cliMenu); + $radioItem2->getSelectAction()($cliMenu); - self::assertEquals(['[○] Item One [●] Item Two '], $item->getRows($menuStyle, true)); + self::assertEquals(['[-] Item One [+] Item Two '], $item->getRows($menuStyle, true)); } } diff --git a/test/MenuStyleTest.php b/test/MenuStyleTest.php index 6294f351..1c954cc3 100644 --- a/test/MenuStyleTest.php +++ b/test/MenuStyleTest.php @@ -100,10 +100,6 @@ public function testGetterAndSetters() : void $style->setFg('yellow'); $style->setUnselectedMarker('-'); $style->setSelectedMarker('>'); - $style->setUncheckedMarker('/'); - $style->setCheckedMarker('+'); - $style->setUnradioMarker('O'); - $style->setRadioMarker('X'); $style->setItemExtra('EXTRA!'); $style->setDisplaysExtra(true); $style->setTitleSeparator('+'); @@ -121,10 +117,6 @@ public function testGetterAndSetters() : void self::assertSame('yellow', $style->getFg()); self::assertSame('-', $style->getUnselectedMarker()); self::assertSame('>', $style->getSelectedMarker()); - self::assertEquals('/', $style->getUncheckedMarker()); - self::assertEquals('+', $style->getCheckedMarker()); - self::assertEquals('O', $style->getUnradioMarker()); - self::assertEquals('X', $style->getRadioMarker()); self::assertSame('EXTRA!', $style->getItemExtra()); self::assertTrue($style->getDisplaysExtra()); self::assertSame('+', $style->getTitleSeparator()); From f1683dce6056ba70bb7d738d52d09b9025602500 Mon Sep 17 00:00:00 2001 From: Juan Treminio Date: Wed, 18 Dec 2019 20:34:27 -0600 Subject: [PATCH 4/8] Inject CliMenu-level style into items --- src/Builder/CliMenuBuilder.php | 75 +++++++++++++++++----------------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/src/Builder/CliMenuBuilder.php b/src/Builder/CliMenuBuilder.php index 596b2f9f..8b40214d 100644 --- a/src/Builder/CliMenuBuilder.php +++ b/src/Builder/CliMenuBuilder.php @@ -8,6 +8,7 @@ use PhpSchool\CliMenu\Exception\InvalidShortcutException; use PhpSchool\CliMenu\MenuItem\AsciiArtItem; use PhpSchool\CliMenu\MenuItem\CheckableItem; +use PhpSchool\CliMenu\MenuItem\ItemStyleInterface; use PhpSchool\CliMenu\MenuItem\LineBreakItem; use PhpSchool\CliMenu\MenuItem\MenuItemInterface; use PhpSchool\CliMenu\MenuItem\MenuMenuItem; @@ -246,30 +247,39 @@ protected function createMenuClosure($builder) : Closure $menu->setStyle($this->menu->getStyle()); } - // If user changed this style, persist to the menu so children CheckableItems may use it - if ($this->menu->getCheckableStyle()->getIsCustom()) { - $menu->setCheckableStyle(function (CheckableStyle $style) { - $style->fromArray($this->menu->getCheckableStyle()->toArray()); - }); - } + $menu->setCheckableStyle(function (CheckableStyle $style) { + $style->fromArray($this->menu->getCheckableStyle()->toArray()); + }); - // If user changed this style, persist to the menu so children RadioItems may use it - if ($this->menu->getRadioStyle()->getIsCustom()) { - $menu->setRadioStyle(function (RadioStyle $style) { - $style->fromArray($this->menu->getRadioStyle()->toArray()); - }); - } + $menu->setRadioStyle(function (RadioStyle $style) { + $style->fromArray($this->menu->getRadioStyle()->toArray()); + }); - // If user changed this style, persist to the menu so children SelectableItems may use it - if ($this->menu->getSelectableStyle()->getIsCustom()) { - $menu->setSelectableStyle(function (SelectableStyle $style) { - $style->fromArray($this->menu->getSelectableStyle()->toArray()); - }); - } + $menu->setSelectableStyle(function (SelectableStyle $style) { + $style->fromArray($this->menu->getSelectableStyle()->toArray()); + }); // This will be filled with user-provided items foreach ($menu->getItems() as $item) { - if ($item instanceof SelectableInterface && !$item->getStyle()->getIsCustom()) { + // Only set style for compatible items + if (!$item instanceof ItemStyleInterface) { + continue; + } + + // If item has a custom style, skip overriding + if ($item->getStyle()->getIsCustom()) { + continue; + } + + if ($item instanceof CheckableStyle) { + $item->setStyle(clone $menu->getCheckableStyle()); + } + + if ($item instanceof RadioStyle) { + $item->setStyle(clone $menu->getRadioStyle()); + } + + if ($item instanceof SelectableInterface) { $item->setStyle(clone $menu->getSelectableStyle()); } } @@ -352,26 +362,17 @@ public function addSplitItem(Closure $callback) : self $builder->enableAutoShortcuts($this->autoShortcutsRegex); } - // If user changed this style, persist to the menu so children CheckableItems may use it - if ($this->menu->getCheckableStyle()->getIsCustom()) { - $builder->setCheckableStyle(function (CheckableStyle $style) { - $style->fromArray($this->menu->getCheckableStyle()->toArray()); - }); - } + $builder->setCheckableStyle(function (CheckableStyle $style) { + $style->fromArray($this->menu->getCheckableStyle()->toArray()); + }); - // If user changed this style, persist to the menu so children RadioItems may use it - if ($this->menu->getRadioStyle()->getIsCustom()) { - $builder->setRadioStyle(function (RadioStyle $style) { - $style->fromArray($this->menu->getRadioStyle()->toArray()); - }); - } + $builder->setRadioStyle(function (RadioStyle $style) { + $style->fromArray($this->menu->getRadioStyle()->toArray()); + }); - // If user changed this style, persist to the menu so children SelectableItems may use it - if ($this->menu->getSelectableStyle()->getIsCustom()) { - $builder->setSelectableStyle(function (SelectableStyle $style) { - $style->fromArray($this->menu->getSelectableStyle()->toArray()); - }); - } + $builder->setSelectableStyle(function (SelectableStyle $style) { + $style->fromArray($this->menu->getSelectableStyle()->toArray()); + }); $callback($builder); From 036b1e9fd9ba61b3cbaf6a84a5b676807e66a682 Mon Sep 17 00:00:00 2001 From: Juan Treminio Date: Wed, 18 Dec 2019 20:35:04 -0600 Subject: [PATCH 5/8] Do not handle fg/bg at item-level just yet --- src/Style/CheckableStyle.php | 26 ++------- src/Style/ItemStyleInterface.php | 10 ---- src/Style/ItemStyleTrait.php | 90 -------------------------------- src/Style/RadioStyle.php | 24 ++------- src/Style/SelectableStyle.php | 24 ++------- 5 files changed, 13 insertions(+), 161 deletions(-) diff --git a/src/Style/CheckableStyle.php b/src/Style/CheckableStyle.php index 30dae979..9a62925c 100644 --- a/src/Style/CheckableStyle.php +++ b/src/Style/CheckableStyle.php @@ -2,31 +2,19 @@ namespace PhpSchool\CliMenu\Style; -use PhpSchool\CliMenu\Terminal\TerminalFactory; -use PhpSchool\Terminal\Terminal; - class CheckableStyle implements ItemStyleInterface { use ItemStyleTrait; protected const DEFAULT_STYLES = [ - 'fg' => 'white', - 'bg' => 'blue', 'markerOn' => '[✔] ', 'markerOff' => '[ ] ', 'itemExtra' => '✔', 'displaysExtra' => false, ]; - public function __construct(Terminal $terminal = null) + public function __construct() { - $this->terminal = $terminal ?: TerminalFactory::fromSystem(); - - $this->fg = self::DEFAULT_STYLES['fg']; - $this->bg = self::DEFAULT_STYLES['bg']; - - $this->generateColoursSetCode(); - $this->setMarkerOn(self::DEFAULT_STYLES['markerOn']); $this->setMarkerOff(self::DEFAULT_STYLES['markerOff']); $this->setItemExtra(self::DEFAULT_STYLES['itemExtra']); @@ -35,11 +23,9 @@ public function __construct(Terminal $terminal = null) $this->custom = false; } - public function toArray(): array + public function toArray() : array { return [ - 'fg' => $this->fg, - 'bg' => $this->bg, 'markerOn' => $this->markerOn, 'markerOff' => $this->markerOff, 'itemExtra' => $this->itemExtra, @@ -49,11 +35,9 @@ public function toArray(): array public function fromArray(array $style) : self { - $this->fg = $style['fg'] ?? $this->fg; - $this->bg = $style['bg'] ?? $this->bg; - $this->markerOn = $style['markerOn'] ?? $this->markerOn; - $this->markerOff = $style['markerOff'] ?? $this->markerOff; - $this->itemExtra = $style['itemExtra'] ?? $this->itemExtra; + $this->markerOn = $style['markerOn'] ?? $this->markerOn; + $this->markerOff = $style['markerOff'] ?? $this->markerOff; + $this->itemExtra = $style['itemExtra'] ?? $this->itemExtra; $this->displaysExtra = $style['displaysExtra'] ?? $this->displaysExtra; return $this; diff --git a/src/Style/ItemStyleInterface.php b/src/Style/ItemStyleInterface.php index 00043149..e1bacdeb 100644 --- a/src/Style/ItemStyleInterface.php +++ b/src/Style/ItemStyleInterface.php @@ -6,16 +6,6 @@ interface ItemStyleInterface { public function getIsCustom() : bool; - public function getColoursSetCode() : string; - - public function getFg(); - - public function setFg(string $fg, string $fallback = null) : self; - - public function getBg(); - - public function setBg(string $bg, string $fallback = null) : self; - public function getMarker(bool $selected) : string; public function getMarkerOn() : string; diff --git a/src/Style/ItemStyleTrait.php b/src/Style/ItemStyleTrait.php index aeca1140..7b7a1fd2 100644 --- a/src/Style/ItemStyleTrait.php +++ b/src/Style/ItemStyleTrait.php @@ -2,26 +2,8 @@ namespace PhpSchool\CliMenu\Style; -use PhpSchool\CliMenu\Util\ColourUtil; -use PhpSchool\Terminal\Terminal; - trait ItemStyleTrait { - /** - * @var Terminal - */ - protected $terminal; - - /** - * @var string - */ - protected $fg; - - /** - * @var string - */ - protected $bg; - /** * @var string */ @@ -42,11 +24,6 @@ trait ItemStyleTrait */ protected $displaysExtra; - /** - * @var string - */ - protected $coloursSetCode; - protected $custom = false; public function getIsCustom() : bool @@ -54,53 +31,6 @@ public function getIsCustom() : bool return $this->custom; } - /** - * Get the colour code for Bg and Fg - */ - public function getColoursSetCode() : string - { - return $this->coloursSetCode; - } - - public function getFg() - { - return $this->fg; - } - - public function setFg(string $fg, string $fallback = null) : self - { - $this->custom = true; - - $this->fg = ColourUtil::validateColour( - $this->terminal, - $fg, - $fallback - ); - $this->generateColoursSetCode(); - - return $this; - } - - public function getBg() - { - return $this->bg; - } - - public function setBg(string $bg, string $fallback = null) : self - { - $this->custom = true; - - $this->bg = ColourUtil::validateColour( - $this->terminal, - $bg, - $fallback - ); - - $this->generateColoursSetCode(); - - return $this; - } - public function getMarker(bool $selected) : string { return $selected ? $this->markerOn : $this->markerOff; @@ -161,24 +91,4 @@ public function setDisplaysExtra(bool $displaysExtra) : self return $this; } - - /** - * Generates the ansi escape sequence to set the colours - */ - private function generateColoursSetCode() : void - { - if (!ctype_digit($this->fg)) { - $fgCode = Colour::AVAILABLE_FOREGROUND_COLOURS[$this->fg]; - } else { - $fgCode = sprintf("38;5;%s", $this->fg); - } - - if (!ctype_digit($this->bg)) { - $bgCode = Colour::AVAILABLE_BACKGROUND_COLOURS[$this->bg]; - } else { - $bgCode = sprintf("48;5;%s", $this->bg); - } - - $this->coloursSetCode = sprintf("\033[%s;%sm", $fgCode, $bgCode); - } } diff --git a/src/Style/RadioStyle.php b/src/Style/RadioStyle.php index d95f86b0..1b877345 100644 --- a/src/Style/RadioStyle.php +++ b/src/Style/RadioStyle.php @@ -2,31 +2,19 @@ namespace PhpSchool\CliMenu\Style; -use PhpSchool\CliMenu\Terminal\TerminalFactory; -use PhpSchool\Terminal\Terminal; - class RadioStyle implements ItemStyleInterface { use ItemStyleTrait; protected const DEFAULT_STYLES = [ - 'fg' => 'white', - 'bg' => 'blue', 'markerOn' => '[●] ', 'markerOff' => '[○] ', 'itemExtra' => '✔', 'displaysExtra' => false, ]; - public function __construct(Terminal $terminal = null) + public function __construct() { - $this->terminal = $terminal ?: TerminalFactory::fromSystem(); - - $this->fg = self::DEFAULT_STYLES['fg']; - $this->bg = self::DEFAULT_STYLES['bg']; - - $this->generateColoursSetCode(); - $this->setMarkerOn(self::DEFAULT_STYLES['markerOn']); $this->setMarkerOff(self::DEFAULT_STYLES['markerOff']); $this->setItemExtra(self::DEFAULT_STYLES['itemExtra']); @@ -38,8 +26,6 @@ public function __construct(Terminal $terminal = null) public function toArray(): array { return [ - 'fg' => $this->fg, - 'bg' => $this->bg, 'markerOn' => $this->markerOn, 'markerOff' => $this->markerOff, 'itemExtra' => $this->itemExtra, @@ -49,11 +35,9 @@ public function toArray(): array public function fromArray(array $style) : self { - $this->fg = $style['fg'] ?? $this->fg; - $this->bg = $style['bg'] ?? $this->bg; - $this->markerOn = $style['markerOn'] ?? $this->markerOn; - $this->markerOff = $style['markerOff'] ?? $this->markerOff; - $this->itemExtra = $style['itemExtra'] ?? $this->itemExtra; + $this->markerOn = $style['markerOn'] ?? $this->markerOn; + $this->markerOff = $style['markerOff'] ?? $this->markerOff; + $this->itemExtra = $style['itemExtra'] ?? $this->itemExtra; $this->displaysExtra = $style['displaysExtra'] ?? $this->displaysExtra; return $this; diff --git a/src/Style/SelectableStyle.php b/src/Style/SelectableStyle.php index 0ccf690e..388c3823 100644 --- a/src/Style/SelectableStyle.php +++ b/src/Style/SelectableStyle.php @@ -2,31 +2,19 @@ namespace PhpSchool\CliMenu\Style; -use PhpSchool\CliMenu\Terminal\TerminalFactory; -use PhpSchool\Terminal\Terminal; - class SelectableStyle implements ItemStyleInterface { use ItemStyleTrait; protected const DEFAULT_STYLES = [ - 'fg' => 'white', - 'bg' => 'blue', 'markerOn' => '● ', 'markerOff' => '○ ', 'itemExtra' => '✔', 'displaysExtra' => false, ]; - public function __construct(Terminal $terminal = null) + public function __construct() { - $this->terminal = $terminal ?: TerminalFactory::fromSystem(); - - $this->fg = self::DEFAULT_STYLES['fg']; - $this->bg = self::DEFAULT_STYLES['bg']; - - $this->generateColoursSetCode(); - $this->setMarkerOn(self::DEFAULT_STYLES['markerOn']); $this->setMarkerOff(self::DEFAULT_STYLES['markerOff']); $this->setItemExtra(self::DEFAULT_STYLES['itemExtra']); @@ -38,8 +26,6 @@ public function __construct(Terminal $terminal = null) public function toArray(): array { return [ - 'fg' => $this->fg, - 'bg' => $this->bg, 'markerOn' => $this->markerOn, 'markerOff' => $this->markerOff, 'itemExtra' => $this->itemExtra, @@ -49,11 +35,9 @@ public function toArray(): array public function fromArray(array $style) : self { - $this->fg = $style['fg'] ?? $this->fg; - $this->bg = $style['bg'] ?? $this->bg; - $this->markerOn = $style['markerOn'] ?? $this->markerOn; - $this->markerOff = $style['markerOff'] ?? $this->markerOff; - $this->itemExtra = $style['itemExtra'] ?? $this->itemExtra; + $this->markerOn = $style['markerOn'] ?? $this->markerOn; + $this->markerOff = $style['markerOff'] ?? $this->markerOff; + $this->itemExtra = $style['itemExtra'] ?? $this->itemExtra; $this->displaysExtra = $style['displaysExtra'] ?? $this->displaysExtra; return $this; From bbe7ad8d50854af3b7b5af52e8182a1c2bb783e2 Mon Sep 17 00:00:00 2001 From: Juan Treminio Date: Wed, 18 Dec 2019 22:10:47 -0600 Subject: [PATCH 6/8] All tests green --- src/Builder/CliMenuBuilder.php | 64 +++++++++++++++++---- src/MenuItem/SplitItem.php | 59 ++++++++++++------- src/MenuItem/StaticItem.php | 25 +++++++- src/MenuItem/ToggableTrait.php | 10 ++-- src/MenuStyle.php | 88 ----------------------------- src/Style/ItemStyleInterface.php | 20 +++++-- src/Style/ItemStyleTrait.php | 3 + src/Style/SplitStyle.php | 67 ++++++++++++++++++++++ src/Style/StaticStyle.php | 60 ++++++++++++++++++++ test/Builder/CliMenuBuilderTest.php | 17 +++--- test/MenuItem/CheckableItemTest.php | 10 ++-- test/MenuItem/RadioItemTest.php | 10 ++-- test/MenuItem/SplitItemTest.php | 25 ++++---- test/MenuStyleTest.php | 23 -------- 14 files changed, 302 insertions(+), 179 deletions(-) create mode 100644 src/Style/SplitStyle.php create mode 100644 src/Style/StaticStyle.php diff --git a/src/Builder/CliMenuBuilder.php b/src/Builder/CliMenuBuilder.php index 8b40214d..263791b9 100644 --- a/src/Builder/CliMenuBuilder.php +++ b/src/Builder/CliMenuBuilder.php @@ -22,6 +22,7 @@ use PhpSchool\CliMenu\Style\CheckableStyle; use PhpSchool\CliMenu\Style\RadioStyle; use PhpSchool\CliMenu\Style\SelectableStyle; +use PhpSchool\CliMenu\Style\SplitStyle; use PhpSchool\CliMenu\Terminal\TerminalFactory; use PhpSchool\Terminal\Terminal; @@ -198,7 +199,6 @@ public function addSubMenu(string $text, Closure $callback) : self $builder->enableAutoShortcuts($this->autoShortcutsRegex); } - $callback = $callback->bindTo($builder); $callback($builder); $menu = $this->createMenuClosure($builder); @@ -375,8 +375,13 @@ public function addSplitItem(Closure $callback) : self }); $callback($builder); - - $this->menu->addItem($splitItem = $builder->build()); + + $splitItem = $builder->build(); + $splitItem->setStyleCallback(function (SplitStyle $style) { + $style->fromArray($this->menu->getSelectableStyle()->toArray()); + }); + + $this->menu->addItem($splitItem); $this->processSplitItemShortcuts($splitItem); @@ -478,23 +483,47 @@ public function setMargin(int $margin) : self public function setUnselectedMarker(string $marker) : self { - $this->style->setUnselectedMarker($marker); + array_map(function (SelectableInterface $item) use ($marker) { + $item->getStyle() + ->setMarkerOff($marker); + }, array_filter($this->menu->getItems(), function (MenuItemInterface $item) { + return $item instanceof SelectableInterface; + })); + + $this->menu->getSelectableStyle() + ->setMarkerOff($marker); return $this; } public function setSelectedMarker(string $marker) : self { - $this->style->setSelectedMarker($marker); + array_map(function (SelectableInterface $item) use ($marker) { + $item->getStyle() + ->setMarkerOn($marker); + }, array_filter($this->menu->getItems(), function (MenuItemInterface $item) { + return $item instanceof SelectableInterface; + })); + + $this->menu->getSelectableStyle() + ->setMarkerOn($marker); return $this; } public function setItemExtra(string $extra) : self { - $this->style->setItemExtra($extra); + array_map(function (SelectableInterface $item) use ($extra) { + $item->getStyle() + ->setItemExtra($extra); + }, array_filter($this->menu->getItems(), function (MenuItemInterface $item) { + return $item instanceof SelectableInterface; + })); + + $this->menu->getSelectableStyle() + ->setItemExtra($extra); - //if we customise item extra, it means we most likely want to display it + // if we customise item extra, it means we most likely want to display it $this->displayExtra(); return $this; @@ -582,7 +611,15 @@ public function disableDefaultItems() : self public function displayExtra() : self { - $this->style->setDisplaysExtra(true); + array_map(function (SelectableInterface $item) { + $item->getStyle() + ->setDisplaysExtra(true); + }, array_filter($this->menu->getItems(), function (MenuItemInterface $item) { + return $item instanceof SelectableInterface; + })); + + $this->menu->getSelectableStyle() + ->setDisplaysExtra(true); return $this; } @@ -600,8 +637,15 @@ public function build() : CliMenu $this->menu->addItems($this->getDefaultItems()); } - if (!$this->style->getDisplaysExtra()) { - $this->style->setDisplaysExtra($this->itemsHaveExtra($this->menu->getItems())); + if (!$this->menu->getSelectableStyle()->getDisplaysExtra()) { + $displaysExtra = $this->itemsHaveExtra($this->menu->getItems()); + + array_map(function (SelectableInterface $item) use ($displaysExtra) { + $item->getStyle() + ->setDisplaysExtra($displaysExtra); + }, array_filter($this->menu->getItems(), function (MenuItemInterface $item) { + return $item instanceof SelectableInterface; + })); } return $this->menu; diff --git a/src/MenuItem/SplitItem.php b/src/MenuItem/SplitItem.php index 1b366487..c5074a3e 100644 --- a/src/MenuItem/SplitItem.php +++ b/src/MenuItem/SplitItem.php @@ -4,6 +4,7 @@ use Assert\Assertion; use PhpSchool\CliMenu\MenuStyle; +use PhpSchool\CliMenu\Style\SplitStyle; use PhpSchool\CliMenu\Util\StringUtil; /** @@ -31,6 +32,16 @@ class SplitItem implements MenuItemInterface */ private $gutter = 2; + /** + * @var SplitStyle + */ + private $style; + + /** + * @var \Callable + */ + private $styleCallback = null; + /** * @var array */ @@ -44,6 +55,13 @@ public function __construct(array $items = []) { $this->addItems($items); $this->setDefaultSelectedItem(); + + $this->style = new SplitStyle(); + } + + public function setStyleCallback(Callable $callable) + { + $this->styleCallback = $callable; } public function setGutter(int $gutter) : void @@ -107,6 +125,13 @@ private function setDefaultSelectedItem() : void */ public function getRows(MenuStyle $style, bool $selected = false) : array { + // Set local style with parent style + if ($this->styleCallback) { + ($this->styleCallback)($this->style); + + $this->styleCallback = null; + } + $numberOfItems = count($this->items); if ($numberOfItems === 0) { @@ -117,8 +142,8 @@ public function getRows(MenuStyle $style, bool $selected = false) : array $this->setDefaultSelectedItem(); } - $length = $style->getDisplaysExtra() - ? floor($style->getContentWidth() / $numberOfItems) - (mb_strlen($style->getItemExtra()) + 2) + $length = $this->style->getDisplaysExtra() + ? floor($style->getContentWidth() / $numberOfItems) - (mb_strlen($this->style->getItemExtra()) + 2) : floor($style->getContentWidth() / $numberOfItems); $length -= $this->gutter; @@ -128,33 +153,25 @@ public function getRows(MenuStyle $style, bool $selected = false) : array return $this->buildRows( array_map(function ($index, $item) use ($selected, $length, $style) { + /** @var ItemStyleInterface|MenuItemInterface $item */ $isSelected = $selected && $index === $this->selectedItemIndex; - if ($item instanceof ItemStyleInterface) { - $itemStyle = $item->getStyle(); - - $getMarkerType = $item instanceof ToggableItemInterface - ? $item->getChecked() - : $isSelected; + $itemStyle = $item->getStyle(); - $markerType = $itemStyle->getMarker($getMarkerType); - $displaysExtraType = $itemStyle->getDisplaysExtra(); - $itemExtraType = $itemStyle->getItemExtra(); - } else { - $markerType = $style->getMarker($isSelected); - $displaysExtraType = $style->getDisplaysExtra(); - $itemExtraType = $style->getItemExtra(); - } + $getMarkerType = $item instanceof ToggableItemInterface + ? $item->getChecked() + : $isSelected; $marker = $item->canSelect() - ? sprintf('%s', $markerType) + ? sprintf('%s', $itemStyle->getMarker($getMarkerType)) : ''; $itemExtra = ''; - if ($displaysExtraType) { + if ($itemStyle->getDisplaysExtra()) { + $itemExtraString = $itemStyle->getItemExtra(); $itemExtra = $item->showsItemExtra() - ? sprintf(' %s', $itemExtraType) - : sprintf(' %s', str_repeat(' ', mb_strlen($itemExtraType))); + ? sprintf(' %s', $itemExtraString) + : sprintf(' %s', str_repeat(' ', mb_strlen($itemExtraString))); } return $this->buildCell( @@ -180,7 +197,7 @@ public function getRows(MenuStyle $style, bool $selected = false) : array private function buildRows(array $cells, MenuStyle $style, int $missingLength, int $length) : array { - $extraPadLength = $style->getDisplaysExtra() ? 2 + mb_strlen($style->getItemExtra()) : 0; + $extraPadLength = $this->style->getDisplaysExtra() ? 2 + mb_strlen($this->style->getItemExtra()) : 0; return array_map( function ($i) use ($cells, $length, $missingLength, $extraPadLength) { diff --git a/src/MenuItem/StaticItem.php b/src/MenuItem/StaticItem.php index fc532a0f..3601baa8 100644 --- a/src/MenuItem/StaticItem.php +++ b/src/MenuItem/StaticItem.php @@ -1,8 +1,8 @@ text = $text; + + $this->style = new Style\StaticStyle(); + } + + public function getStyle() : Style\ItemStyleInterface + { + return $this->style; + } + + /** + * @param Style\ItemStyleInterface|Style\SelectableStyle $style + * @return $this + */ + public function setStyle(Style\ItemStyleInterface $style) : self + { + $this->style = $style; + + return $this; } /** diff --git a/src/MenuItem/ToggableTrait.php b/src/MenuItem/ToggableTrait.php index d11c538d..504988e7 100644 --- a/src/MenuItem/ToggableTrait.php +++ b/src/MenuItem/ToggableTrait.php @@ -33,8 +33,10 @@ public function getRows(MenuStyle $style, bool $selected = false) : array { $marker = sprintf("%s", $this->style->getMarker($this->checked)); - $length = $style->getDisplaysExtra() - ? $style->getContentWidth() - (mb_strlen($style->getItemExtra()) + 2) + $itemExtra = $this->style->getItemExtra(); + + $length = $this->style->getDisplaysExtra() + ? $style->getContentWidth() - (mb_strlen($itemExtra) + 2) : $style->getContentWidth(); $rows = explode( @@ -46,12 +48,12 @@ public function getRows(MenuStyle $style, bool $selected = false) : array ) ); - return array_map(function ($row, $key) use ($style, $length) { + return array_map(function ($row, $key) use ($style, $length, $itemExtra) { $text = $this->disabled ? $style->getDisabledItemText($row) : $row; if ($key === 0) { return $this->showItemExtra - ? sprintf('%s%s %s', $text, str_repeat(' ', $length - mb_strlen($row)), $style->getItemExtra()) + ? sprintf('%s%s %s', $text, str_repeat(' ', $length - mb_strlen($row)), $itemExtra) : $text; } diff --git a/src/MenuStyle.php b/src/MenuStyle.php index 5b0f8600..00690fa9 100644 --- a/src/MenuStyle.php +++ b/src/MenuStyle.php @@ -59,26 +59,6 @@ class MenuStyle */ protected $contentWidth; - /** - * @var string - */ - private $selectedMarker; - - /** - * @var string - */ - private $unselectedMarker; - - /** - * @var string - */ - private $itemExtra; - - /** - * @var bool - */ - private $displaysExtra; - /** * @var string */ @@ -141,10 +121,6 @@ class MenuStyle 'paddingTopBottom' => 1, 'paddingLeftRight' => 2, 'margin' => 2, - 'selectedMarker' => '● ', - 'unselectedMarker' => '○ ', - 'itemExtra' => '✔', - 'displaysExtra' => false, 'titleSeparator' => '=', 'borderTopWidth' => 0, 'borderRightWidth' => 0, @@ -182,10 +158,6 @@ public function __construct(Terminal $terminal = null) $this->setPaddingTopBottom(self::$defaultStyleValues['paddingTopBottom']); $this->setPaddingLeftRight(self::$defaultStyleValues['paddingLeftRight']); $this->setMargin(self::$defaultStyleValues['margin']); - $this->setSelectedMarker(self::$defaultStyleValues['selectedMarker']); - $this->setUnselectedMarker(self::$defaultStyleValues['unselectedMarker']); - $this->setItemExtra(self::$defaultStyleValues['itemExtra']); - $this->setDisplaysExtra(self::$defaultStyleValues['displaysExtra']); $this->setTitleSeparator(self::$defaultStyleValues['titleSeparator']); $this->setBorderTopWidth(self::$defaultStyleValues['borderTopWidth']); $this->setBorderRightWidth(self::$defaultStyleValues['borderRightWidth']); @@ -203,10 +175,6 @@ public function hasChangedFromDefaults() : bool $this->paddingTopBottom, $this->paddingLeftRight, $this->margin, - $this->selectedMarker, - $this->unselectedMarker, - $this->itemExtra, - $this->displaysExtra, $this->titleSeparator, $this->borderTopWidth, $this->borderRightWidth, @@ -480,62 +448,6 @@ public function getRightHandPadding(int $contentLength) : int return $rightPadding; } - public function getSelectedMarker() : string - { - return $this->selectedMarker; - } - - public function setSelectedMarker(string $marker) : self - { - $this->selectedMarker = $marker; - - return $this; - } - - public function getUnselectedMarker() : string - { - return $this->unselectedMarker; - } - - public function setUnselectedMarker(string $marker) : self - { - $this->unselectedMarker = $marker; - - return $this; - } - - /** - * Get the correct marker for the item - */ - public function getMarker(bool $selected) : string - { - return $selected ? $this->selectedMarker : $this->unselectedMarker; - } - - public function setItemExtra(string $itemExtra) : self - { - $this->itemExtra = $itemExtra; - - return $this; - } - - public function getItemExtra() : string - { - return $this->itemExtra; - } - - public function getDisplaysExtra() : bool - { - return $this->displaysExtra; - } - - public function setDisplaysExtra(bool $displaysExtra) : self - { - $this->displaysExtra = $displaysExtra; - - return $this; - } - public function getTitleSeparator() : string { return $this->titleSeparator; diff --git a/src/Style/ItemStyleInterface.php b/src/Style/ItemStyleInterface.php index e1bacdeb..d3b6fa79 100644 --- a/src/Style/ItemStyleInterface.php +++ b/src/Style/ItemStyleInterface.php @@ -10,17 +10,29 @@ public function getMarker(bool $selected) : string; public function getMarkerOn() : string; - public function setMarkerOn(string $marker) : self; + /** + * @return $this + */ + public function setMarkerOn(string $marker); public function getMarkerOff() : string; - public function setMarkerOff(string $marker) : self; + /** + * @return $this + */ + public function setMarkerOff(string $marker); public function getItemExtra() : string; - public function setItemExtra(string $itemExtra) : self; + /** + * @return $this + */ + public function setItemExtra(string $itemExtra); public function getDisplaysExtra() : bool; - public function setDisplaysExtra(bool $displaysExtra) : self; + /** + * @return $this + */ + public function setDisplaysExtra(bool $displaysExtra); } diff --git a/src/Style/ItemStyleTrait.php b/src/Style/ItemStyleTrait.php index 7b7a1fd2..80299403 100644 --- a/src/Style/ItemStyleTrait.php +++ b/src/Style/ItemStyleTrait.php @@ -75,6 +75,9 @@ public function setItemExtra(string $itemExtra) : self $this->itemExtra = $itemExtra; + // if we customise item extra, it means we most likely want to display it + $this->setDisplaysExtra(true); + return $this; } diff --git a/src/Style/SplitStyle.php b/src/Style/SplitStyle.php new file mode 100644 index 00000000..56573df1 --- /dev/null +++ b/src/Style/SplitStyle.php @@ -0,0 +1,67 @@ + '', + 'displaysExtra' => false, + ]; + + public function __construct() + { + $this->setItemExtra(self::DEFAULT_STYLES['itemExtra']); + $this->setDisplaysExtra(self::DEFAULT_STYLES['displaysExtra']); + } + + public function getItemExtra() : string + { + return $this->itemExtra; + } + + public function setItemExtra(string $itemExtra) : self + { + $this->itemExtra = $itemExtra; + + return $this; + } + + public function getDisplaysExtra() : bool + { + return $this->displaysExtra; + } + + public function setDisplaysExtra(bool $displaysExtra) : self + { + $this->displaysExtra = $displaysExtra; + + return $this; + } + + public function toArray() : array + { + return [ + 'itemExtra' => $this->itemExtra, + 'displaysExtra' => $this->displaysExtra, + ]; + } + + public function fromArray(array $style) : self + { + $this->itemExtra = $style['itemExtra'] ?? $this->itemExtra; + $this->displaysExtra = $style['displaysExtra'] ?? $this->displaysExtra; + + return $this; + } +} diff --git a/src/Style/StaticStyle.php b/src/Style/StaticStyle.php new file mode 100644 index 00000000..8a1df7cd --- /dev/null +++ b/src/Style/StaticStyle.php @@ -0,0 +1,60 @@ + '', + 'markerOff' => '', + 'itemExtra' => '', + 'displaysExtra' => false, + ]; + + public function __construct() + { + $this->fromArray([]); + } + + public function setMarkerOn(string $marker) : self + { + return $this; + } + + public function setMarkerOff(string $marker) : self + { + return $this; + } + + public function setItemExtra(string $itemExtra) : self + { + return $this; + } + + public function setDisplaysExtra(bool $displaysExtra) : self + { + return $this; + } + + public function toArray(): array + { + return [ + 'markerOn' => $this->markerOn, + 'markerOff' => $this->markerOff, + 'itemExtra' => $this->itemExtra, + 'displaysExtra' => $this->displaysExtra, + ]; + } + + public function fromArray(array $style) : self + { + $this->markerOn = self::DEFAULT_STYLES['markerOn']; + $this->markerOff = self::DEFAULT_STYLES['markerOff']; + $this->itemExtra = self::DEFAULT_STYLES['itemExtra']; + $this->displaysExtra = self::DEFAULT_STYLES['displaysExtra']; + + return $this; + } +} diff --git a/test/Builder/CliMenuBuilderTest.php b/test/Builder/CliMenuBuilderTest.php index e634a525..d7404b60 100644 --- a/test/Builder/CliMenuBuilderTest.php +++ b/test/Builder/CliMenuBuilderTest.php @@ -79,10 +79,11 @@ public function testModifyStyles() : void self::assertEquals(4, $style->getPaddingTopBottom()); self::assertEquals(1, $style->getPaddingLeftRight()); self::assertEquals(4, $style->getMargin()); - self::assertEquals('>', $style->getUnselectedMarker()); - self::assertEquals('x', $style->getSelectedMarker()); - self::assertEquals('*', $style->getItemExtra()); self::assertEquals('-', $style->getTitleSeparator()); + + self::assertEquals('>', $menu->getSelectableStyle()->getMarkerOff()); + self::assertEquals('x', $menu->getSelectableStyle()->getMarkerOn()); + self::assertEquals('*', $menu->getSelectableStyle()->getItemExtra()); } public function testSetBorderShorthandFunction() : void @@ -804,9 +805,9 @@ public function testAddSubMenuWithClosureBinding() : void { $builder = new CliMenuBuilder; $builder->disableDefaultItems(); - $builder->addSubMenu('My SubMenu', function () { - $this->disableDefaultItems(); - $this->addItem('My Item', function () { + $builder->addSubMenu('My SubMenu', function (CliMenuBuilder $b) { + $b->disableDefaultItems(); + $b->addItem('My Item', function () { }); }); @@ -854,7 +855,7 @@ public function testDisplayExtraForcesExtraToBeDisplayedWhenNoItemsDisplayExtra( $menu = $builder->build(); - self::assertTrue($menu->getStyle()->getDisplaysExtra()); + self::assertTrue($menu->getSelectableStyle()->getDisplaysExtra()); } public function testModifyingItemExtraForcesExtraToBeDisplayedWhenNoItemsDisplayExtra() : void @@ -868,7 +869,7 @@ public function testModifyingItemExtraForcesExtraToBeDisplayedWhenNoItemsDisplay $menu = $builder->build(); - self::assertTrue($menu->getStyle()->getDisplaysExtra()); + self::assertTrue($menu->getSelectableStyle()->getDisplaysExtra()); } diff --git a/test/MenuItem/CheckableItemTest.php b/test/MenuItem/CheckableItemTest.php index 9d28a0f1..5ab00ee9 100644 --- a/test/MenuItem/CheckableItemTest.php +++ b/test/MenuItem/CheckableItemTest.php @@ -141,11 +141,12 @@ public function testGetRowsWithItemExtra() : void $menuStyle = new MenuStyle($terminal); $menuStyle->setPaddingLeftRight(0); $menuStyle->setWidth(20); - $menuStyle->setItemExtra('[EXTRA]'); - $menuStyle->setDisplaysExtra(true); $item = new CheckableItem('Item', function () { }, true); + $item->getStyle() + ->setItemExtra('[EXTRA]') + ->setDisplaysExtra(true); $this->assertEquals(['[ ] Item [EXTRA]'], $item->getRows($menuStyle)); } @@ -157,11 +158,12 @@ public function testGetRowsWithMultipleLinesWithItemExtra() : void $menuStyle = new MenuStyle($terminal); $menuStyle->setPaddingLeftRight(0); $menuStyle->setWidth(20); - $menuStyle->setItemExtra('[EXTRA]'); - $menuStyle->setDisplaysExtra(true); $item = new CheckableItem('LONG ITEM LINE', function () { }, true); + $item->getStyle() + ->setItemExtra('[EXTRA]') + ->setDisplaysExtra(true); $this->assertEquals( [ "[ ] LONG [EXTRA]", diff --git a/test/MenuItem/RadioItemTest.php b/test/MenuItem/RadioItemTest.php index 00f667df..92475352 100644 --- a/test/MenuItem/RadioItemTest.php +++ b/test/MenuItem/RadioItemTest.php @@ -175,11 +175,12 @@ public function testGetRowsWithItemExtra() : void $menuStyle = new MenuStyle($terminal); $menuStyle->setPaddingLeftRight(0); $menuStyle->setWidth(20); - $menuStyle->setItemExtra('[EXTRA]'); - $menuStyle->setDisplaysExtra(true); $item = new RadioItem('Item', function () { }, true); + $item->getStyle() + ->setItemExtra('[EXTRA]') + ->setDisplaysExtra(true); $this->assertEquals(['[○] Item [EXTRA]'], $item->getRows($menuStyle)); } @@ -191,11 +192,12 @@ public function testGetRowsWithMultipleLinesWithItemExtra() : void $menuStyle = new MenuStyle($terminal); $menuStyle->setPaddingLeftRight(0); $menuStyle->setWidth(20); - $menuStyle->setItemExtra('[EXTRA]'); - $menuStyle->setDisplaysExtra(true); $item = new RadioItem('LONG ITEM LINE', function () { }, true); + $item->getStyle() + ->setItemExtra('[EXTRA]') + ->setDisplaysExtra(true); $this->assertEquals( [ "[○] LONG [EXTRA]", diff --git a/test/MenuItem/SplitItemTest.php b/test/MenuItem/SplitItemTest.php index 0487b10a..4debcf15 100644 --- a/test/MenuItem/SplitItemTest.php +++ b/test/MenuItem/SplitItemTest.php @@ -15,6 +15,7 @@ use PhpSchool\CliMenu\Style\CheckableStyle; use PhpSchool\CliMenu\Style\RadioStyle; use PhpSchool\CliMenu\Style\SelectableStyle; +use PhpSchool\CliMenu\Style\SplitStyle; use PhpSchool\Terminal\Terminal; use PHPUnit\Framework\TestCase; @@ -308,9 +309,6 @@ public function testGetRowsWithItemExtra() : void $menuStyle = new MenuStyle($terminal); $menuStyle->setPaddingLeftRight(0); $menuStyle->setWidth(50); - $menuStyle->setItemExtra('[EXTRA]'); - $menuStyle->setDisplaysExtra(true); - $menuStyle->setUnselectedMarker('* '); $selectableStyle = new SelectableStyle(); $selectableStyle->setItemExtra('[EXTRA]') @@ -325,13 +323,14 @@ public function testGetRowsWithItemExtra() : void }, true))->setStyle($selectableStyle), ] ); + $item->setStyleCallback(function (SplitStyle $style) { + $style->setItemExtra('[EXTRA]') + ->setDisplaysExtra(true); + }); self::assertEquals(['* Item 1 [EXTRA] * Item 2 [EXTRA] '], $item->getRows($menuStyle)); } - /** - * @todo Refactor this to use SelectableStyle() exclusively - */ public function testGetRowsWithMultipleLinesWithItemExtra() : void { $terminal = $this->createMock(Terminal::class); @@ -340,9 +339,6 @@ public function testGetRowsWithMultipleLinesWithItemExtra() : void $menuStyle = new MenuStyle($terminal); $menuStyle->setPaddingLeftRight(0); $menuStyle->setWidth(50); - $menuStyle->setItemExtra(' [EXTRA]'); - $menuStyle->setDisplaysExtra(true); - $menuStyle->setUnselectedMarker('* '); $selectableStyle = new SelectableStyle(); $selectableStyle->setItemExtra(' [EXTRA]') @@ -357,6 +353,10 @@ public function testGetRowsWithMultipleLinesWithItemExtra() : void }, true))->setStyle($selectableStyle), ] ); + $item->setStyleCallback(function (SplitStyle $style) { + $style->setItemExtra(' [EXTRA]') + ->setDisplaysExtra(true); + }); self::assertEquals( [ @@ -375,9 +375,6 @@ public function testGetRowsWithMultipleLinesWithItemExtraOnOne() : void $menuStyle = new MenuStyle($terminal); $menuStyle->setPaddingLeftRight(0); $menuStyle->setWidth(50); - $menuStyle->setItemExtra(' [EXTRA] '); - $menuStyle->setDisplaysExtra(true); - $menuStyle->setUnselectedMarker('* '); $selectableStyle = new SelectableStyle(); $selectableStyle->setItemExtra(' [EXTRA] ') @@ -392,6 +389,10 @@ public function testGetRowsWithMultipleLinesWithItemExtraOnOne() : void }, true))->setStyle($selectableStyle), ] ); + $item->setStyleCallback(function (SplitStyle $style) { + $style->setItemExtra(' [EXTRA] ') + ->setDisplaysExtra(true); + }); self::assertEquals( [ diff --git a/test/MenuStyleTest.php b/test/MenuStyleTest.php index 1c954cc3..7a664140 100644 --- a/test/MenuStyleTest.php +++ b/test/MenuStyleTest.php @@ -81,10 +81,6 @@ public function testGetterAndSetters() : void self::assertSame('blue', $style->getBg()); self::assertSame('white', $style->getFg()); - self::assertSame('○ ', $style->getUnselectedMarker()); - self::assertSame('● ', $style->getSelectedMarker()); - self::assertSame('✔', $style->getItemExtra()); - self::assertFalse($style->getDisplaysExtra()); self::assertSame('=', $style->getTitleSeparator()); self::assertSame(100, $style->getWidth()); self::assertSame(2, $style->getMargin()); @@ -98,10 +94,6 @@ public function testGetterAndSetters() : void $style->setBg('red'); $style->setFg('yellow'); - $style->setUnselectedMarker('-'); - $style->setSelectedMarker('>'); - $style->setItemExtra('EXTRA!'); - $style->setDisplaysExtra(true); $style->setTitleSeparator('+'); $style->setWidth(200); $style->setMargin(10); @@ -115,10 +107,6 @@ public function testGetterAndSetters() : void self::assertSame('red', $style->getBg()); self::assertSame('yellow', $style->getFg()); - self::assertSame('-', $style->getUnselectedMarker()); - self::assertSame('>', $style->getSelectedMarker()); - self::assertSame('EXTRA!', $style->getItemExtra()); - self::assertTrue($style->getDisplaysExtra()); self::assertSame('+', $style->getTitleSeparator()); self::assertSame(200, $style->getWidth()); self::assertSame(10, $style->getMargin()); @@ -233,17 +221,6 @@ public function testSetBgThrowsExceptionWhenColourCodeIsNotInRange() : void $style->setBg(257, 'white'); } - public function testGetMarkerReturnsTheCorrectMarkers() : void - { - $style = $this->getMenuStyle(); - - $style->setSelectedMarker('>'); - $style->setUnselectedMarker('x'); - - static::assertSame('>', $style->getMarker(true)); - static::assertSame('x', $style->getMarker(false)); - } - public function testWidthCalculation() : void { $style = $this->getMenuStyle(); From 08e197db50609478e495e51e15db0c83081887b9 Mon Sep 17 00:00:00 2001 From: Juan Treminio Date: Thu, 19 Dec 2019 10:23:46 -0600 Subject: [PATCH 7/8] Changes name for style callback methods --- src/Builder/CliMenuBuilder.php | 54 +++++++++++++++++++++++++------- src/Builder/SplitItemBuilder.php | 54 +++++++++++++++++++++++++------- src/CliMenu.php | 42 +++++++++++++++++++++---- 3 files changed, 120 insertions(+), 30 deletions(-) diff --git a/src/Builder/CliMenuBuilder.php b/src/Builder/CliMenuBuilder.php index 263791b9..7f511021 100644 --- a/src/Builder/CliMenuBuilder.php +++ b/src/Builder/CliMenuBuilder.php @@ -247,15 +247,15 @@ protected function createMenuClosure($builder) : Closure $menu->setStyle($this->menu->getStyle()); } - $menu->setCheckableStyle(function (CheckableStyle $style) { + $menu->checkableStyle(function (CheckableStyle $style) { $style->fromArray($this->menu->getCheckableStyle()->toArray()); }); - $menu->setRadioStyle(function (RadioStyle $style) { + $menu->radioStyle(function (RadioStyle $style) { $style->fromArray($this->menu->getRadioStyle()->toArray()); }); - $menu->setSelectableStyle(function (SelectableStyle $style) { + $menu->selectableStyle(function (SelectableStyle $style) { $style->fromArray($this->menu->getSelectableStyle()->toArray()); }); @@ -362,15 +362,15 @@ public function addSplitItem(Closure $callback) : self $builder->enableAutoShortcuts($this->autoShortcutsRegex); } - $builder->setCheckableStyle(function (CheckableStyle $style) { + $builder->checkableStyle(function (CheckableStyle $style) { $style->fromArray($this->menu->getCheckableStyle()->toArray()); }); - $builder->setRadioStyle(function (RadioStyle $style) { + $builder->radioStyle(function (RadioStyle $style) { $style->fromArray($this->menu->getRadioStyle()->toArray()); }); - $builder->setSelectableStyle(function (SelectableStyle $style) { + $builder->selectableStyle(function (SelectableStyle $style) { $style->fromArray($this->menu->getSelectableStyle()->toArray()); }); @@ -651,23 +651,53 @@ public function build() : CliMenu return $this->menu; } - public function setCheckableStyle(callable $itemCallable) : self + /** + * Use as + * + ->checkableStyle(function (CheckableStyle $style) { + $style->setMarkerOff('- '); + }) + * + * @param callable $itemCallable + * @return $this + */ + public function checkableStyle(callable $itemCallable) : self { - $this->menu->setCheckableStyle($itemCallable); + $this->menu->checkableStyle($itemCallable); return $this; } - public function setRadioStyle(callable $itemCallable) : self + /** + * Use as + * + ->radioStyle(function (RadioStyle $style) { + $style->setMarkerOff('- '); + }) + * + * @param callable $itemCallable + * @return $this + */ + public function radioStyle(callable $itemCallable) : self { - $this->menu->setRadioStyle($itemCallable); + $this->menu->radioStyle($itemCallable); return $this; } - public function setSelectableStyle(callable $itemCallable) : self + /** + * Use as + * + ->selectableStyle(function (SelectableStyle $style) { + $style->setMarkerOff('- '); + }) + * + * @param callable $itemCallable + * @return $this + */ + public function selectableStyle(callable $itemCallable) : self { - $this->menu->setSelectableStyle($itemCallable); + $this->menu->selectableStyle($itemCallable); return $this; } diff --git a/src/Builder/SplitItemBuilder.php b/src/Builder/SplitItemBuilder.php index 3572bc81..0166863b 100644 --- a/src/Builder/SplitItemBuilder.php +++ b/src/Builder/SplitItemBuilder.php @@ -67,9 +67,9 @@ public function __construct(CliMenu $menu) $this->menu = $menu; $this->splitItem = new SplitItem(); - $this->checkableStyle = new CheckableStyle($menu->getTerminal()); - $this->radioStyle = new RadioStyle($menu->getTerminal()); - $this->selectableStyle = new SelectableStyle($menu->getTerminal()); + $this->checkableStyle = new CheckableStyle(); + $this->radioStyle = new RadioStyle(); + $this->selectableStyle = new SelectableStyle(); } public function addItem( @@ -172,23 +172,53 @@ public function build() : SplitItem return $this->splitItem; } - public function setCheckableStyle(callable $itemCallable) : self + /** + * Use as + * + ->checkableStyle(function (CheckableStyle $style) { + $style->setMarkerOff('- '); + }) + * + * @param callable $itemCallable + * @return $this + */ + public function checkableStyle(callable $itemCallable) : self { - $this->menu->setCheckableStyle($itemCallable); + $this->menu->checkableStyle($itemCallable); return $this; } - public function setRadioStyle(callable $itemCallable) : self + /** + * Use as + * + ->radioStyle(function (RadioStyle $style) { + $style->setMarkerOff('- '); + }) + * + * @param callable $itemCallable + * @return $this + */ + public function radioStyle(callable $itemCallable) : self { - $this->menu->setRadioStyle($itemCallable); + $this->menu->radioStyle($itemCallable); return $this; } - public function setSelectableStyle(callable $itemCallable) : self + /** + * Use as + * + ->selectableStyle(function (SelectableStyle $style) { + $style->setMarkerOff('- '); + }) + * + * @param callable $itemCallable + * @return $this + */ + public function selectableStyle(callable $itemCallable) : self { - $this->menu->setSelectableStyle($itemCallable); + $this->menu->selectableStyle($itemCallable); return $this; } @@ -209,21 +239,21 @@ protected function createMenuClosure(CliMenuBuilder $builder) : Closure // If user changed this style, persist to the menu so children CheckableItems may use it if ($this->menu->getCheckableStyle()->getIsCustom()) { - $menu->setCheckableStyle(function (CheckableStyle $style) { + $menu->checkableStyle(function (CheckableStyle $style) { $style->fromArray($this->menu->getCheckableStyle()->toArray()); }); } // If user changed this style, persist to the menu so children RadioItems may use it if ($this->menu->getRadioStyle()->getIsCustom()) { - $menu->setRadioStyle(function (RadioStyle $style) { + $menu->radioStyle(function (RadioStyle $style) { $style->fromArray($this->menu->getRadioStyle()->toArray()); }); } // If user changed this style, persist to the menu so children SelectableItems may use it if ($this->menu->getSelectableStyle()->getIsCustom()) { - $menu->setSelectableStyle(function (SelectableStyle $style) { + $menu->selectableStyle(function (SelectableStyle $style) { $style->fromArray($this->menu->getSelectableStyle()->toArray()); }); } diff --git a/src/CliMenu.php b/src/CliMenu.php index d1e58fbb..0a989872 100644 --- a/src/CliMenu.php +++ b/src/CliMenu.php @@ -112,9 +112,9 @@ public function __construct( $this->items = $items; $this->terminal = $terminal ?: TerminalFactory::fromSystem(); $this->style = $style ?: new MenuStyle($this->terminal); - $this->checkableStyle = new CheckableStyle($this->terminal); - $this->radioStyle = new RadioStyle($this->terminal); - $this->selectableStyle = new SelectableStyle($this->terminal); + $this->checkableStyle = new CheckableStyle(); + $this->radioStyle = new RadioStyle(); + $this->selectableStyle = new SelectableStyle(); $this->selectFirstItem(); } @@ -664,7 +664,17 @@ public function getCheckableStyle() : CheckableStyle return $this->checkableStyle; } - public function setCheckableStyle(callable $itemCallable) : self + /** + * Use as + * + ->checkableStyle(function (CheckableStyle $style) { + $style->setMarkerOff('- '); + }) + * + * @param callable $itemCallable + * @return $this + */ + public function checkableStyle(callable $itemCallable) : self { $itemCallable($this->checkableStyle); @@ -676,7 +686,17 @@ public function getRadioStyle() : RadioStyle return $this->radioStyle; } - public function setRadioStyle(callable $itemCallable) : self + /** + * Use as + * + ->radioStyle(function (RadioStyle $style) { + $style->setMarkerOff('- '); + }) + * + * @param callable $itemCallable + * @return $this + */ + public function radioStyle(callable $itemCallable) : self { $itemCallable($this->radioStyle); @@ -688,7 +708,17 @@ public function getSelectableStyle() : SelectableStyle return $this->selectableStyle; } - public function setSelectableStyle(callable $itemCallable) : self + /** + * Use as + * + ->selectableStyle(function (SelectableStyle $style) { + $style->setMarkerOff('- '); + }) + * + * @param callable $itemCallable + * @return $this + */ + public function selectableStyle(callable $itemCallable) : self { $itemCallable($this->selectableStyle); From b08a081e8b4f3ec717c1605b9ab0a6f660eb1656 Mon Sep 17 00:00:00 2001 From: Juan Treminio Date: Thu, 19 Dec 2019 11:07:05 -0600 Subject: [PATCH 8/8] Removes Style\Color --- src/MenuStyle.php | 61 ++++++++++++++++++++++++++++++++++++++------ src/Style/Colour.php | 36 -------------------------- 2 files changed, 53 insertions(+), 44 deletions(-) delete mode 100644 src/Style/Colour.php diff --git a/src/MenuStyle.php b/src/MenuStyle.php index 00690fa9..98064782 100644 --- a/src/MenuStyle.php +++ b/src/MenuStyle.php @@ -69,6 +69,21 @@ class MenuStyle */ private $coloursSetCode; + /** + * @var string + */ + private $invertedColoursSetCode = "\033[7m"; + + /** + * @var string + */ + private $invertedColoursUnsetCode = "\033[27m"; + + /** + * @var string + */ + private $coloursResetCode = "\033[0m"; + /** * @var int */ @@ -130,6 +145,36 @@ class MenuStyle 'marginAuto' => false, ]; + /** + * @var array + */ + private static $availableForegroundColors = [ + 'black' => 30, + 'red' => 31, + 'green' => 32, + 'yellow' => 33, + 'blue' => 34, + 'magenta' => 35, + 'cyan' => 36, + 'white' => 37, + 'default' => 39, + ]; + + /** + * @var array + */ + private static $availableBackgroundColors = [ + 'black' => 40, + 'red' => 41, + 'green' => 42, + 'yellow' => 43, + 'blue' => 44, + 'magenta' => 45, + 'cyan' => 46, + 'white' => 47, + 'default' => 49, + ]; + /** * @var array */ @@ -203,13 +248,13 @@ public function getDisabledItemText(string $text) : string private function generateColoursSetCode() : void { if (!ctype_digit($this->fg)) { - $fgCode = Style\Colour::AVAILABLE_FOREGROUND_COLOURS[$this->fg]; + $fgCode = self::$availableForegroundColors[$this->fg]; } else { $fgCode = sprintf("38;5;%s", $this->fg); } if (!ctype_digit($this->bg)) { - $bgCode = Style\Colour::AVAILABLE_BACKGROUND_COLOURS[$this->bg]; + $bgCode = self::$availableBackgroundColors[$this->bg]; } else { $bgCode = sprintf("48;5;%s", $this->bg); } @@ -230,7 +275,7 @@ public function getColoursSetCode() : string */ public function getInvertedColoursSetCode() : string { - return Style\Colour::INVERTED_SET_CODE; + return $this->invertedColoursSetCode; } /** @@ -238,7 +283,7 @@ public function getInvertedColoursSetCode() : string */ public function getInvertedColoursUnsetCode() : string { - return Style\Colour::INVERTED_UNSET_CODE; + return $this->invertedColoursUnsetCode; } /** @@ -246,7 +291,7 @@ public function getInvertedColoursUnsetCode() : string */ public function getColoursResetCode() : string { - return Style\Colour::RESET_CODE; + return $this->coloursResetCode; } /** @@ -353,7 +398,7 @@ private function generatePaddingTopBottomRows() : void str_repeat(' ', $this->paddingLeftRight), $borderColour, str_repeat(' ', $this->borderRightWidth), - Style\Colour::RESET_CODE + $this->coloursResetCode ); $this->paddingTopBottomRows = array_fill(0, $this->paddingTopBottom, $paddingRow); @@ -467,7 +512,7 @@ private function generateBorderRows() : void str_repeat(' ', $this->margin), $this->getBorderColourCode(), str_repeat(' ', $this->width), - Style\Colour::RESET_CODE + $this->coloursResetCode ); $this->borderTopRows = array_fill(0, $this->borderTopWidth, $borderRow); @@ -604,7 +649,7 @@ public function getBorderColour() : string public function getBorderColourCode() : string { if (!ctype_digit($this->borderColour)) { - $borderColourCode = Style\Colour::AVAILABLE_BACKGROUND_COLOURS[$this->borderColour]; + $borderColourCode = self::$availableBackgroundColors[$this->borderColour]; } else { $borderColourCode = sprintf("48;5;%s", $this->borderColour); } diff --git a/src/Style/Colour.php b/src/Style/Colour.php deleted file mode 100644 index e21ed533..00000000 --- a/src/Style/Colour.php +++ /dev/null @@ -1,36 +0,0 @@ - 30, - 'red' => 31, - 'green' => 32, - 'yellow' => 33, - 'blue' => 34, - 'magenta' => 35, - 'cyan' => 36, - 'white' => 37, - 'default' => 39, - ]; - - public const AVAILABLE_BACKGROUND_COLOURS = [ - 'black' => 40, - 'red' => 41, - 'green' => 42, - 'yellow' => 43, - 'blue' => 44, - 'magenta' => 45, - 'cyan' => 46, - 'white' => 47, - 'default' => 49, - ]; - - public const INVERTED_SET_CODE = "\033[7m"; - - public const INVERTED_UNSET_CODE = "\033[27m"; - - public const RESET_CODE = "\033[0m"; -}