Skip to content

Commit 1b78207

Browse files
authored
Merge pull request #194 from jtreminio/feature/radio-item
Adds RadioItem and ToggableTrait
2 parents 867de8a + ca2712d commit 1b78207

18 files changed

+821
-83
lines changed

README.md

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
* [Items](#appearance)
4343
* [Selectable Item](#selectable-item)
4444
* [Checkable Item](#checkable-item)
45+
* [Radio Item](#radio-item)
4546
* [Line Break Item](#line-break-item)
4647
* [Static Item](#static-item)
4748
* [Ascii Art Item](#ascii-art-item)
@@ -501,6 +502,7 @@ There a few different types of items you can add to your menu
501502

502503
* 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)
503504
* Checkable Item - This is a checkbox type of item that keeps track of its toggled state to show a different marker.
505+
* Radio Item - This is a radio type of item that keeps track of its toggled state to show a different marker. Disables all other radios within its `CliMenu` level.
504506
* 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.
505507
* Static Item - This will print whatever text is passed, useful for headings.
506508
* Ascii Art Item - Special item which allows usage of Ascii art. It takes care of padding and alignment.
@@ -568,6 +570,28 @@ $menu = (new CliMenuBuilder)
568570
When selecting an item, it will be toggled. Notice at first each item is unchecked. After selecting one it will become
569571
checked.
570572

573+
### Radio Item
574+
575+
```php
576+
<?php
577+
578+
use PhpSchool\CliMenu\Builder\CliMenuBuilder;
579+
use PhpSchool\CliMenu\CliMenu;
580+
581+
$callable = function (CliMenu $menu) {
582+
echo $menu->getSelectedItem()->getText();
583+
};
584+
585+
$menu = (new CliMenuBuilder)
586+
->addRadioItem('Item 1', $callable)
587+
->addRadioItem('Item 2', $callable)
588+
->addRadioItem('Item 3', $callable)
589+
->build();
590+
```
591+
592+
When selecting an item, it will be toggled. Notice at first each item is unchecked. After selecting one it will become
593+
checked and all other `RadioItem` within the same level will be unchecked.
594+
571595
### Line Break Item
572596

573597
```php
@@ -698,7 +722,7 @@ Split Items allows you to add multiple items on the same row. The full width of
698722

699723
You can set the number of spaces separating items using `->setGutter()` (defaults to 2).
700724

701-
Only Selectable, Checkable, Static and SubMenu items are currently allowed inside a Split Item.
725+
Only Selectable, Checkable, Radio, Static and SubMenu items are currently allowed inside a Split Item.
702726

703727
```php
704728
<?php
@@ -731,7 +755,7 @@ $menu->open();
731755
There are a few things to note about the syntax and builder process here:
732756

733757
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.
734-
2. You can call `addItem`, `addCheckableItem`, `addSubMenu` and `addStaticItem` on the `SplitItemBuilder`.
758+
2. You can call `addItem`, `addCheckableItem`, `addRadioItem`, `addSubMenu` and `addStaticItem` on the `SplitItemBuilder`.
735759
3. `SplitItemBuilder` has a fluent interface so you can chain method calls.
736760

737761
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
@@ -806,6 +830,19 @@ $menu = (new CliMenuBuilder)
806830
->build();
807831
```
808832

833+
and for `\PhpSchool\CliMenu\MenuItem\RadioItem`:
834+
835+
```php
836+
<?php
837+
838+
use PhpSchool\CliMenu\Builder\CliMenuBuilder;
839+
840+
$menu = (new CliMenuBuilder)
841+
->setUnradioMarker('[ ] ')
842+
->setRadioMarker('[✔] ')
843+
->build();
844+
```
845+
809846
### Item Extra
810847

811848
You can optionally display some arbitrary text on the right hand side of an item. You can customise this text and

examples/radio-item.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
use PhpSchool\CliMenu\CliMenu;
4+
use PhpSchool\CliMenu\Builder\CliMenuBuilder;
5+
6+
require_once(__DIR__ . '/../vendor/autoload.php');
7+
8+
$itemCallable = function (CliMenu $menu) {
9+
echo $menu->getSelectedItem()->getText();
10+
};
11+
12+
$menu = (new CliMenuBuilder)
13+
->setTitle('Select a Language')
14+
->addSubMenu('Compiled', function (CliMenuBuilder $b) use ($itemCallable) {
15+
$b->setTitle('Compiled Languages')
16+
->addRadioItem('Rust', $itemCallable)
17+
->addRadioItem('C++', $itemCallable)
18+
->addRadioItem('Go', $itemCallable)
19+
->addRadioItem('Java', $itemCallable)
20+
->addRadioItem('C', $itemCallable)
21+
;
22+
})
23+
->addSubMenu('Interpreted', function (CliMenuBuilder $b) use ($itemCallable) {
24+
$b->setTitle('Interpreted Languages')
25+
->setUnradioMarker('[ ] ')
26+
->setRadioMarker('[✔] ')
27+
->addRadioItem('PHP', $itemCallable)
28+
->addRadioItem('Javascript', $itemCallable)
29+
->addRadioItem('Ruby', $itemCallable)
30+
->addRadioItem('Python', $itemCallable)
31+
;
32+
})
33+
->build();
34+
35+
$menu->open();

examples/split-checkable-item.php

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,11 @@
33
use PhpSchool\CliMenu\Builder\SplitItemBuilder;
44
use PhpSchool\CliMenu\CliMenu;
55
use PhpSchool\CliMenu\Builder\CliMenuBuilder;
6-
use PhpSchool\CliMenu\MenuItem\CheckableItem;
76

87
require_once(__DIR__ . '/../vendor/autoload.php');
98

109
$itemCallable = function (CliMenu $menu) {
11-
/** @var CheckableItem $item */
12-
$item = $menu->getSelectedItem();
13-
14-
$item->toggle();
15-
16-
$menu->redraw();
10+
echo $menu->getSelectedItem()->getText();
1711
};
1812

1913
$menu = (new CliMenuBuilder)

examples/split-radio-item.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
use PhpSchool\CliMenu\Builder\SplitItemBuilder;
4+
use PhpSchool\CliMenu\CliMenu;
5+
use PhpSchool\CliMenu\Builder\CliMenuBuilder;
6+
7+
require_once(__DIR__ . '/../vendor/autoload.php');
8+
9+
$itemCallable = function (CliMenu $menu) {
10+
echo $menu->getSelectedItem()->getText();
11+
};
12+
13+
$menu = (new CliMenuBuilder)
14+
->setTitle('Select a Language')
15+
->addSplitItem(function (SplitItemBuilder $b) use ($itemCallable) {
16+
$b->setGutter(5)
17+
->addRadioItem('Rust', $itemCallable)
18+
->addRadioItem('C++', $itemCallable)
19+
->addRadioItem('Go', $itemCallable)
20+
->addRadioItem('Java', $itemCallable)
21+
->addRadioItem('C', $itemCallable)
22+
;
23+
})
24+
->build();
25+
26+
$menu->open();

src/Builder/CliMenuBuilder.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use PhpSchool\CliMenu\MenuItem\LineBreakItem;
1111
use PhpSchool\CliMenu\MenuItem\MenuItemInterface;
1212
use PhpSchool\CliMenu\MenuItem\MenuMenuItem;
13+
use PhpSchool\CliMenu\MenuItem\RadioItem;
1314
use PhpSchool\CliMenu\MenuItem\SelectableItem;
1415
use PhpSchool\CliMenu\CliMenu;
1516
use PhpSchool\CliMenu\MenuItem\SplitItem;
@@ -142,6 +143,17 @@ public function addCheckableItem(
142143
return $this;
143144
}
144145

146+
public function addRadioItem(
147+
string $text,
148+
callable $itemCallable,
149+
bool $showItemExtra = false,
150+
bool $disabled = false
151+
) : self {
152+
$this->addMenuItem(new RadioItem($text, $itemCallable, $showItemExtra, $disabled));
153+
154+
return $this;
155+
}
156+
145157
public function addStaticItem(string $text) : self
146158
{
147159
$this->addMenuItem(new StaticItem($text));
@@ -421,6 +433,20 @@ public function setCheckedMarker(string $marker) : self
421433
return $this;
422434
}
423435

436+
public function setUnradioMarker(string $marker) : self
437+
{
438+
$this->style->setUnradioMarker($marker);
439+
440+
return $this;
441+
}
442+
443+
public function setRadioMarker(string $marker) : self
444+
{
445+
$this->style->setRadioMarker($marker);
446+
447+
return $this;
448+
}
449+
424450
public function setItemExtra(string $extra) : self
425451
{
426452
$this->style->setItemExtra($extra);

src/Builder/SplitItemBuilder.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use PhpSchool\CliMenu\MenuItem\CheckableItem;
77
use PhpSchool\CliMenu\MenuItem\LineBreakItem;
88
use PhpSchool\CliMenu\MenuItem\MenuMenuItem;
9+
use PhpSchool\CliMenu\MenuItem\RadioItem;
910
use PhpSchool\CliMenu\MenuItem\SelectableItem;
1011
use PhpSchool\CliMenu\MenuItem\SplitItem;
1112
use PhpSchool\CliMenu\MenuItem\StaticItem;
@@ -69,6 +70,17 @@ public function addCheckableItem(
6970
return $this;
7071
}
7172

73+
public function addRadioItem(
74+
string $text,
75+
callable $itemCallable,
76+
bool $showItemExtra = false,
77+
bool $disabled = false
78+
) : self {
79+
$this->splitItem->addItem(new RadioItem($text, $itemCallable, $showItemExtra, $disabled));
80+
81+
return $this;
82+
}
83+
7284
public function addStaticItem(string $text) : self
7385
{
7486
$this->splitItem->addItem(new StaticItem($text));

src/CliMenu.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,24 @@ public function setSelectedItem(MenuItemInterface $item) : void
404404
$this->selectedItem = $key;
405405
}
406406

407+
public function getSelectedItemIndex() : int
408+
{
409+
if (null === $this->selectedItem) {
410+
throw new \RuntimeException('No selected item');
411+
}
412+
413+
return $this->selectedItem;
414+
}
415+
416+
public function getItemByIndex(int $index) : MenuItemInterface
417+
{
418+
if (!isset($this->items[$index])) {
419+
throw new \RuntimeException('Item with index does not exist');
420+
}
421+
422+
return $this->items[$index];
423+
}
424+
407425
public function executeAsSelected(MenuItemInterface $item) : void
408426
{
409427
$current = $this->items[$this->selectedItem];

src/MenuItem/CheckableItem.php

Lines changed: 3 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
namespace PhpSchool\CliMenu\MenuItem;
44

55
use PhpSchool\CliMenu\CliMenu;
6-
use PhpSchool\CliMenu\MenuStyle;
7-
use PhpSchool\CliMenu\Util\StringUtil;
86

9-
class CheckableItem implements MenuItemInterface
7+
class CheckableItem implements MenuItemInterface, ToggableItemInterface
108
{
9+
use ToggableTrait;
10+
1111
/**
1212
* @var callable
1313
*/
@@ -28,11 +28,6 @@ class CheckableItem implements MenuItemInterface
2828
*/
2929
private $disabled = false;
3030

31-
/**
32-
* @var bool
33-
*/
34-
private $checked = false;
35-
3631
public function __construct(
3732
string $text,
3833
callable $selectAction,
@@ -74,43 +69,6 @@ public function setText(string $text) : void
7469
$this->text = $text;
7570
}
7671

77-
/**
78-
* The output text for the item
79-
*
80-
* @param MenuStyle $style
81-
* @param bool $selected Currently unused in this class
82-
* @return array
83-
*/
84-
public function getRows(MenuStyle $style, bool $selected = false) : array
85-
{
86-
$marker = sprintf("%s", $this->checked ? $style->getCheckedMarker() : $style->getUncheckedMarker());
87-
88-
$length = $style->getDisplaysExtra()
89-
? $style->getContentWidth() - (mb_strlen($style->getItemExtra()) + 2)
90-
: $style->getContentWidth();
91-
92-
$rows = explode(
93-
"\n",
94-
StringUtil::wordwrap(
95-
sprintf('%s%s', $marker, $this->text),
96-
$length,
97-
sprintf("\n%s", str_repeat(' ', mb_strlen($marker)))
98-
)
99-
);
100-
101-
return array_map(function ($row, $key) use ($style, $length) {
102-
$text = $this->disabled ? $style->getDisabledItemText($row) : $row;
103-
104-
if ($key === 0) {
105-
return $this->showItemExtra
106-
? sprintf('%s%s %s', $text, str_repeat(' ', $length - mb_strlen($row)), $style->getItemExtra())
107-
: $text;
108-
}
109-
110-
return $text;
111-
}, $rows, array_keys($rows));
112-
}
113-
11472
/**
11573
* Can the item be selected
11674
*/
@@ -139,33 +97,4 @@ public function hideItemExtra() : void
13997
{
14098
$this->showItemExtra = false;
14199
}
142-
143-
/**
144-
* Toggles checked state
145-
*/
146-
public function toggle()
147-
{
148-
$this->checked = !$this->checked;
149-
}
150-
151-
/**
152-
* Sets checked state to true
153-
*/
154-
public function setChecked()
155-
{
156-
$this->checked = true;
157-
}
158-
159-
/**
160-
* Sets checked state to false
161-
*/
162-
public function setUnchecked()
163-
{
164-
$this->checked = false;
165-
}
166-
167-
public function getChecked(): bool
168-
{
169-
return $this->checked;
170-
}
171100
}

0 commit comments

Comments
 (0)