diff --git a/README.md b/README.md index 0cea2d90..0ec66fd4 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ * [Remove Exit Button](#remove-exit-button) * [Items](#appearance) * [Selectable Item](#selectable-item) + * [Checkable Item](#checkable-item) * [Line Break Item](#line-break-item) * [Static Item](#static-item) * [Ascii Art Item](#ascii-art-item) @@ -499,6 +500,7 @@ $menu = (new CliMenuBuilder) There a few different types of items you can add to your menu * Selectable Item - This is the type of item you need for something to be selectable (you can hit enter and it will invoke your callable) +* Checkable Item - This is a checkbox type of item that keeps track of its toggled state to show a different marker. * Line Break Item - This is used to break up areas, it can span multiple lines and will be the width of Menu. Whatever string is passed will be repeated. * Static Item - This will print whatever text is passed, useful for headings. * Ascii Art Item - Special item which allows usage of Ascii art. It takes care of padding and alignment. @@ -544,6 +546,27 @@ $menu = (new CliMenuBuilder) Note: You can add as many items as you want and they can all have a different action. The action is the second parameter and must be a valid PHP `callable`. Try using an `Invokable` class to keep your actions easily testable. +### Checkable Item + +```php +getSelectedItem(); + $item->toggle(); + $menu->redraw(); +}; + +$menu = (new CliMenuBuilder) + ->addCheckableItem('Item 1', $callable) + ->addCheckableItem('Item 2', $callable) + ->addCheckableItem('Item 3', $callable) + ->build(); +``` + ### Line Break Item ```php @@ -674,7 +697,7 @@ Split Items allows you to add multiple items on the same row. The full width of You can set the number of spaces separating items using `->setGutter()` (defaults to 2). -Only Selectable, Static and SubMenu items are currently allowed inside a Split Item. +Only Selectable, Checkable, Static and SubMenu items are currently allowed inside a Split Item. ```php open(); There are a few things to note about the syntax and builder process here: 1. The first parameter to `addSplitItem` is a closure, which will be invoked with a new instance of `SplitItemBuilder` which you can use to add items to the split item. -2. You can call `addItem`, `addSubMenu` and `addStaticItem` on the `SplitItemBuilder`. +2. You can call `addItem`, `addCheckableItem`, `addSubMenu` and `addStaticItem` on the `SplitItemBuilder`. 3. `SplitItemBuilder` has a fluent interface so you can chain method calls. Note: The closure used to build the split item is also binded with the `SplitItemBuilder` instance so you can add items and such using `$this->addItem()` rather than using the function @@ -769,6 +792,19 @@ $menu = (new CliMenuBuilder) ->build(); ``` +You may also change the marker for `\PhpSchool\CliMenu\MenuItem\CheckableItem`: + +```php +setUncheckedMarker('[○] ') + ->setCheckedMarker('[●] ') + ->build(); +``` + ### Item Extra You can optionally display some arbitrary text on the right hand side of an item. You can customise this text and @@ -904,7 +940,7 @@ $exit = function(CliMenu $menu) { }; $menu = (new CliMenuBuilder) - ->addItem('Item 1') + ->addItem('Item 1', function(CliMenu $menu) {}) ->build(); $menu->addCustomControlMapping("x", $exit); diff --git a/examples/split-checkable-item.php b/examples/split-checkable-item.php new file mode 100644 index 00000000..862c4beb --- /dev/null +++ b/examples/split-checkable-item.php @@ -0,0 +1,32 @@ +getSelectedItem(); + + $item->toggle(); + + $menu->redraw(); +}; + +$menu = (new CliMenuBuilder) + ->setTitle('Select a Language') + ->addSplitItem(function (SplitItemBuilder $b) use ($itemCallable) { + $b->setGutter(5) + ->addCheckableItem('Rust', $itemCallable) + ->addCheckableItem('C++', $itemCallable) + ->addCheckableItem('Go', $itemCallable) + ->addCheckableItem('Java', $itemCallable) + ->addCheckableItem('C', $itemCallable) + ; + }) + ->build(); + +$menu->open(); diff --git a/src/Builder/SplitItemBuilder.php b/src/Builder/SplitItemBuilder.php index 61fac5de..99014b61 100644 --- a/src/Builder/SplitItemBuilder.php +++ b/src/Builder/SplitItemBuilder.php @@ -3,6 +3,7 @@ namespace PhpSchool\CliMenu\Builder; use PhpSchool\CliMenu\CliMenu; +use PhpSchool\CliMenu\MenuItem\CheckableItem; use PhpSchool\CliMenu\MenuItem\LineBreakItem; use PhpSchool\CliMenu\MenuItem\MenuMenuItem; use PhpSchool\CliMenu\MenuItem\SelectableItem; @@ -57,6 +58,17 @@ public function addItem( return $this; } + public function addCheckableItem( + string $text, + callable $itemCallable, + bool $showItemExtra = false, + bool $disabled = false + ) : self { + $this->splitItem->addItem(new CheckableItem($text, $itemCallable, $showItemExtra, $disabled)); + + return $this; + } + public function addStaticItem(string $text) : self { $this->splitItem->addItem(new StaticItem($text)); diff --git a/src/MenuItem/CheckableItem.php b/src/MenuItem/CheckableItem.php index 93f021d7..e8fded5d 100644 --- a/src/MenuItem/CheckableItem.php +++ b/src/MenuItem/CheckableItem.php @@ -2,11 +2,10 @@ namespace PhpSchool\CliMenu\MenuItem; -use PhpSchool\CliMenu\MenuItem; use PhpSchool\CliMenu\MenuStyle; use PhpSchool\CliMenu\Util\StringUtil; -class CheckableItem implements MenuItem\MenuItemInterface +class CheckableItem implements MenuItemInterface { /** * @var callable diff --git a/src/MenuItem/SplitItem.php b/src/MenuItem/SplitItem.php index bc5d27fe..ea362cda 100644 --- a/src/MenuItem/SplitItem.php +++ b/src/MenuItem/SplitItem.php @@ -129,8 +129,17 @@ public function getRows(MenuStyle $style, bool $selected = false) : array return $this->buildRows( 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(); + } else { + $markerType = $style->getMarker($isSelected); + } + $marker = $item->canSelect() - ? sprintf('%s', $style->getMarker($isSelected)) + ? sprintf('%s', $markerType) : ''; $itemExtra = ''; diff --git a/test/Builder/SplitItemBuilderTest.php b/test/Builder/SplitItemBuilderTest.php index 6d2d10fe..3450c35f 100644 --- a/test/Builder/SplitItemBuilderTest.php +++ b/test/Builder/SplitItemBuilderTest.php @@ -4,6 +4,7 @@ use PhpSchool\CliMenu\Builder\SplitItemBuilder; use PhpSchool\CliMenu\CliMenu; +use PhpSchool\CliMenu\MenuItem\CheckableItem; use PhpSchool\CliMenu\MenuItem\MenuMenuItem; use PhpSchool\CliMenu\MenuItem\SelectableItem; use PhpSchool\CliMenu\MenuItem\SplitItem; @@ -37,6 +38,31 @@ public function testAddItem() : void $this->checkItemItems($item, $expected); } + public function testAddCheckableItem() : void + { + $callable = function () { + }; + + $menu = new CliMenu(null, []); + $builder = new SplitItemBuilder($menu); + $builder->addCheckableItem('Item 1', $callable); + $builder->addCheckableItem('Item 2', $callable); + $item = $builder->build(); + + $expected = [ + [ + 'class' => CheckableItem::class, + 'text' => 'Item 1', + ], + [ + 'class' => CheckableItem::class, + 'text' => 'Item 2', + ], + ]; + + $this->checkItemItems($item, $expected); + } + public function testAddStaticItem() : void {