Skip to content

Adds RadioItem and ToggableTrait #194

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Dec 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 39 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
* [Items](#appearance)
* [Selectable Item](#selectable-item)
* [Checkable Item](#checkable-item)
* [Radio Item](#radio-item)
* [Line Break Item](#line-break-item)
* [Static Item](#static-item)
* [Ascii Art Item](#ascii-art-item)
Expand Down Expand Up @@ -501,6 +502,7 @@ 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.
* 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.
* 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.
Expand Down Expand Up @@ -568,6 +570,28 @@ $menu = (new CliMenuBuilder)
When selecting an item, it will be toggled. Notice at first each item is unchecked. After selecting one it will become
checked.

### Radio Item

```php
<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;

$callable = function (CliMenu $menu) {
echo $menu->getSelectedItem()->getText();
};

$menu = (new CliMenuBuilder)
->addRadioItem('Item 1', $callable)
->addRadioItem('Item 2', $callable)
->addRadioItem('Item 3', $callable)
->build();
```

When selecting an item, it will be toggled. Notice at first each item is unchecked. After selecting one it will become
checked and all other `RadioItem` within the same level will be unchecked.

### Line Break Item

```php
Expand Down Expand Up @@ -698,7 +722,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, Checkable, Static and SubMenu items are currently allowed inside a Split Item.
Only Selectable, Checkable, Radio, Static and SubMenu items are currently allowed inside a Split Item.

```php
<?php
Expand Down Expand Up @@ -731,7 +755,7 @@ $menu->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`, `addCheckableItem`, `addSubMenu` and `addStaticItem` on the `SplitItemBuilder`.
2. You can call `addItem`, `addCheckableItem`, `addRadioItem`, `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
Expand Down Expand Up @@ -806,6 +830,19 @@ $menu = (new CliMenuBuilder)
->build();
```

and for `\PhpSchool\CliMenu\MenuItem\RadioItem`:

```php
<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;

$menu = (new CliMenuBuilder)
->setUnradioMarker('[ ] ')
->setRadioMarker('[✔] ')
->build();
```

### Item Extra

You can optionally display some arbitrary text on the right hand side of an item. You can customise this text and
Expand Down
35 changes: 35 additions & 0 deletions examples/radio-item.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\Builder\CliMenuBuilder;

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

$itemCallable = function (CliMenu $menu) {
echo $menu->getSelectedItem()->getText();
};

$menu = (new CliMenuBuilder)
->setTitle('Select a Language')
->addSubMenu('Compiled', function (CliMenuBuilder $b) use ($itemCallable) {
$b->setTitle('Compiled Languages')
->addRadioItem('Rust', $itemCallable)
->addRadioItem('C++', $itemCallable)
->addRadioItem('Go', $itemCallable)
->addRadioItem('Java', $itemCallable)
->addRadioItem('C', $itemCallable)
;
})
->addSubMenu('Interpreted', function (CliMenuBuilder $b) use ($itemCallable) {
$b->setTitle('Interpreted Languages')
->setUnradioMarker('[ ] ')
->setRadioMarker('[✔] ')
->addRadioItem('PHP', $itemCallable)
->addRadioItem('Javascript', $itemCallable)
->addRadioItem('Ruby', $itemCallable)
->addRadioItem('Python', $itemCallable)
;
})
->build();

$menu->open();
8 changes: 1 addition & 7 deletions examples/split-checkable-item.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,11 @@
use PhpSchool\CliMenu\Builder\SplitItemBuilder;
use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\MenuItem\CheckableItem;

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

$itemCallable = function (CliMenu $menu) {
/** @var CheckableItem $item */
$item = $menu->getSelectedItem();

$item->toggle();

$menu->redraw();
echo $menu->getSelectedItem()->getText();
};

$menu = (new CliMenuBuilder)
Expand Down
26 changes: 26 additions & 0 deletions examples/split-radio-item.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

use PhpSchool\CliMenu\Builder\SplitItemBuilder;
use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\Builder\CliMenuBuilder;

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

$itemCallable = function (CliMenu $menu) {
echo $menu->getSelectedItem()->getText();
};

$menu = (new CliMenuBuilder)
->setTitle('Select a Language')
->addSplitItem(function (SplitItemBuilder $b) use ($itemCallable) {
$b->setGutter(5)
->addRadioItem('Rust', $itemCallable)
->addRadioItem('C++', $itemCallable)
->addRadioItem('Go', $itemCallable)
->addRadioItem('Java', $itemCallable)
->addRadioItem('C', $itemCallable)
;
})
->build();

$menu->open();
26 changes: 26 additions & 0 deletions src/Builder/CliMenuBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use PhpSchool\CliMenu\MenuItem\LineBreakItem;
use PhpSchool\CliMenu\MenuItem\MenuItemInterface;
use PhpSchool\CliMenu\MenuItem\MenuMenuItem;
use PhpSchool\CliMenu\MenuItem\RadioItem;
use PhpSchool\CliMenu\MenuItem\SelectableItem;
use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\MenuItem\SplitItem;
Expand Down Expand Up @@ -142,6 +143,17 @@ public function addCheckableItem(
return $this;
}

public function addRadioItem(
string $text,
callable $itemCallable,
bool $showItemExtra = false,
bool $disabled = false
) : self {
$this->addMenuItem(new RadioItem($text, $itemCallable, $showItemExtra, $disabled));

return $this;
}

public function addStaticItem(string $text) : self
{
$this->addMenuItem(new StaticItem($text));
Expand Down Expand Up @@ -421,6 +433,20 @@ public function setCheckedMarker(string $marker) : self
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);
Expand Down
12 changes: 12 additions & 0 deletions src/Builder/SplitItemBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use PhpSchool\CliMenu\MenuItem\CheckableItem;
use PhpSchool\CliMenu\MenuItem\LineBreakItem;
use PhpSchool\CliMenu\MenuItem\MenuMenuItem;
use PhpSchool\CliMenu\MenuItem\RadioItem;
use PhpSchool\CliMenu\MenuItem\SelectableItem;
use PhpSchool\CliMenu\MenuItem\SplitItem;
use PhpSchool\CliMenu\MenuItem\StaticItem;
Expand Down Expand Up @@ -69,6 +70,17 @@ public function addCheckableItem(
return $this;
}

public function addRadioItem(
string $text,
callable $itemCallable,
bool $showItemExtra = false,
bool $disabled = false
) : self {
$this->splitItem->addItem(new RadioItem($text, $itemCallable, $showItemExtra, $disabled));

return $this;
}

public function addStaticItem(string $text) : self
{
$this->splitItem->addItem(new StaticItem($text));
Expand Down
18 changes: 18 additions & 0 deletions src/CliMenu.php
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,24 @@ public function setSelectedItem(MenuItemInterface $item) : void
$this->selectedItem = $key;
}

public function getSelectedItemIndex() : int
{
if (null === $this->selectedItem) {
throw new \RuntimeException('No selected item');
}

return $this->selectedItem;
}

public function getItemByIndex(int $index) : MenuItemInterface
{
if (!isset($this->items[$index])) {
throw new \RuntimeException('Item with index does not exist');
}

return $this->items[$index];
}

public function executeAsSelected(MenuItemInterface $item) : void
{
$current = $this->items[$this->selectedItem];
Expand Down
77 changes: 3 additions & 74 deletions src/MenuItem/CheckableItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
namespace PhpSchool\CliMenu\MenuItem;

use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\MenuStyle;
use PhpSchool\CliMenu\Util\StringUtil;

class CheckableItem implements MenuItemInterface
class CheckableItem implements MenuItemInterface, ToggableItemInterface
{
use ToggableTrait;

/**
* @var callable
*/
Expand All @@ -28,11 +28,6 @@ class CheckableItem implements MenuItemInterface
*/
private $disabled = false;

/**
* @var bool
*/
private $checked = false;

public function __construct(
string $text,
callable $selectAction,
Expand Down Expand Up @@ -74,43 +69,6 @@ public function setText(string $text) : void
$this->text = $text;
}

/**
* The output text for the item
*
* @param MenuStyle $style
* @param bool $selected Currently unused in this class
* @return array
*/
public function getRows(MenuStyle $style, bool $selected = false) : array
{
$marker = sprintf("%s", $this->checked ? $style->getCheckedMarker() : $style->getUncheckedMarker());

$length = $style->getDisplaysExtra()
? $style->getContentWidth() - (mb_strlen($style->getItemExtra()) + 2)
: $style->getContentWidth();

$rows = explode(
"\n",
StringUtil::wordwrap(
sprintf('%s%s', $marker, $this->text),
$length,
sprintf("\n%s", str_repeat(' ', mb_strlen($marker)))
)
);

return array_map(function ($row, $key) use ($style, $length) {
$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())
: $text;
}

return $text;
}, $rows, array_keys($rows));
}

/**
* Can the item be selected
*/
Expand Down Expand Up @@ -139,33 +97,4 @@ public function hideItemExtra() : void
{
$this->showItemExtra = false;
}

/**
* Toggles checked state
*/
public function toggle()
{
$this->checked = !$this->checked;
}

/**
* Sets checked state to true
*/
public function setChecked()
{
$this->checked = true;
}

/**
* Sets checked state to false
*/
public function setUnchecked()
{
$this->checked = false;
}

public function getChecked(): bool
{
return $this->checked;
}
}
Loading