Skip to content

Commit

Permalink
Merge pull request #40 from php-school/feature/disable-items
Browse files Browse the repository at this point in the history
Add disabled item functionality
  • Loading branch information
mikeymike committed Oct 3, 2016
2 parents a6989b8 + a02ca7f commit c7bdb1b
Show file tree
Hide file tree
Showing 10 changed files with 153 additions and 16 deletions.
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ Check out the [examples](examples) directory and run them to check out what is p
<img width="600" alt="submenu" src="https://cloud.githubusercontent.com/assets/2817002/11442401/e6f03ef2-950c-11e5-897a-6d55496a4105.png">
<img width="600" alt="submenu-options" src="https://cloud.githubusercontent.com/assets/2817002/11442403/eaf4782e-950c-11e5-82c5-ab57f84cd6bc.png">

##### Disabled Items & Submenus
<img width="600" alt="submenu" src="https://cloud.githubusercontent.com/assets/2174476/19047849/868fa8c0-899b-11e6-9004-811c8da6d435.png">

### API

Expand Down Expand Up @@ -329,7 +331,38 @@ $subMenu = $mainMenuBuilder->getSubMenu('Super Sub Menu');

You can only do this after the main menu has been built, this is because the main menu builder takes care of building all sub menus.

#### Disabling Items & Sub Menus

In this example we are disabling certain items and a submenu but still having them shown in the output.

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

$menu = (new CliMenuBuilder)
->setTitle('Basic CLI Menu Disabled Items')
->addItem('First Item', $itemCallable)
->addItem('Second Item', $itemCallable, false, true)
->addItem('Third Item', $itemCallable, false, true)
->addSubMenu('Submenu')
->setTitle('Basic CLI Menu Disabled Items > Submenu')
->addItem('You can go in here!', $itemCallable)
->end()
->addSubMenu('Disabled Submenu')
->setTitle('Basic CLI Menu Disabled Items > Disabled Submenu')
->addItem('Nope can\'t see this!', $itemCallable)
->disableMenu()
->end()
->addLineBreak('-')
->build();
```

The third param on the `->addItem` call is what disables an item while the `->disableMenu()` call disables the relevent menu.

The outcome is a full menu with dimmed rows to denote them being disabled. When a user navigates these items are jumped over to the next available selectable item.

---

Once you get going you might just end up with something that looks a little like this...

Expand Down
29 changes: 29 additions & 0 deletions examples/disabled-items.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

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

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

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

$menu = (new CliMenuBuilder)
->setTitle('Basic CLI Menu Disabled Items')
->addItem('First Item', $itemCallable)
->addItem('Second Item', $itemCallable, false, true)
->addItem('Third Item', $itemCallable, false, true)
->addSubMenu('Submenu')
->setTitle('Basic CLI Menu Disabled Items > Submenu')
->addItem('You can go in here!', $itemCallable)
->end()
->addSubMenu('Disabled Submenu')
->setTitle('Basic CLI Menu Disabled Items > Disabled Submenu')
->addItem('Nope can\'t see this!', $itemCallable)
->disableMenu()
->end()
->addLineBreak('-')
->build();

$menu->open();
6 changes: 3 additions & 3 deletions src/CliMenu.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
use PhpSchool\CliMenu\Exception\InvalidInstantiationException;
use PhpSchool\CliMenu\Exception\InvalidTerminalException;
use PhpSchool\CliMenu\MenuItem\LineBreakItem;
use PhpSchool\CliMenu\MenuItem\MenuItem;
use PhpSchool\CliMenu\MenuItem\MenuItemInterface;
use PhpSchool\CliMenu\MenuItem\StaticItem;
use PhpSchool\CliMenu\Terminal\TerminalFactory;
use \PhpSchool\CliMenu\Terminal\TerminalInterface;
use PhpSchool\CliMenu\Terminal\TerminalInterface;
use PhpSchool\CliMenu\Util\StringUtil as s;

/**
* Class CliMenu
Expand Down Expand Up @@ -295,7 +295,7 @@ protected function drawMenuItem(MenuItemInterface $item, $selected = false)
$setColour,
str_repeat(' ', $this->style->getPadding()),
$row,
str_repeat(' ', $this->style->getRightHandPadding(mb_strlen($row))),
str_repeat(' ', $this->style->getRightHandPadding(mb_strlen(s::stripAnsiEscapeSequence($row)))),
$unsetColour,
str_repeat(' ', $this->style->getMargin())
);
Expand Down
38 changes: 35 additions & 3 deletions src/CliMenuBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ class CliMenuBuilder
*/
private $disableDefaultItems = false;

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

/**
* @param CliMenuBuilder|null $parent
*/
Expand Down Expand Up @@ -130,13 +135,14 @@ public function addMenuItem(MenuItemInterface $item)
* @param string $text
* @param callable $itemCallable
* @param bool $showItemExtra
* @param bool $disabled
* @return $this
*/
public function addItem($text, callable $itemCallable, $showItemExtra = false)
public function addItem($text, callable $itemCallable, $showItemExtra = false, $disabled = false)
{
Assertion::string($text);

$this->addMenuItem(new SelectableItem($text, $itemCallable, $showItemExtra));
$this->addMenuItem(new SelectableItem($text, $itemCallable, $showItemExtra, $disabled));

return $this;
}
Expand Down Expand Up @@ -211,6 +217,32 @@ public function addSubMenu($id)
return $this->subMenus[$id];
}

/**
* Disable a submenu
* @throws \InvalidArgumentException
* @return $this
*/
public function disableMenu()
{
if (!$this->parent) {
throw new \InvalidArgumentException(
'You can\'t disable the root menu'
);
}

$this->disabled = true;

return $this;
}

/**
* @return bool
*/
public function isMenuDisabled()
{
return $this->disabled;
}

/**
* @param string $goBackButtonTest
* @return $this
Expand Down Expand Up @@ -462,7 +494,7 @@ private function buildSubMenus(array $items)
$menuBuilder = $this->subMenus[$item];
$this->subMenus[$item] = $menuBuilder->build();

return new MenuMenuItem($item, $this->subMenus[$item]);
return new MenuMenuItem($item, $this->subMenus[$item], $menuBuilder->isMenuDisabled());
}, $items);
}

Expand Down
8 changes: 5 additions & 3 deletions src/MenuItem/MenuMenuItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@ class MenuMenuItem implements MenuItemInterface
/**
* @param string $text
* @param CliMenu $subMenu
* @param bool $disabled
*/
public function __construct($text, CliMenu $subMenu)
public function __construct($text, CliMenu $subMenu, $disabled = false)
{
Assertion::string($text);

$this->text = $text;
$this->subMenu = $subMenu;
$this->text = $text;
$this->subMenu = $subMenu;
$this->disabled = $disabled;
}

/**
Expand Down
4 changes: 3 additions & 1 deletion src/MenuItem/SelectableItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,16 @@ class SelectableItem implements MenuItemInterface
* @param string $text
* @param callable $selectAction
* @param bool $showItemExtra
* @param bool $disabled
*/
public function __construct($text, callable $selectAction, $showItemExtra = false)
public function __construct($text, callable $selectAction, $showItemExtra = false, $disabled = false)
{
Assertion::string($text);

$this->text = $text;
$this->selectAction = $selectAction;
$this->showItemExtra = (bool) $showItemExtra;
$this->disabled = $disabled;
}

/**
Expand Down
17 changes: 12 additions & 5 deletions src/MenuItem/SelectableTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,18 @@ trait SelectableTrait
/**
* @var string
*/
private $text;
private $text = '';

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

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

/**
* The output text for the item
*
Expand All @@ -48,13 +53,15 @@ public function getRows(MenuStyle $style, $selected = false)
);

return array_map(function ($row, $key) use ($style, $marker, $length) {
$text = $this->disabled ? $style->getDisabledItemText($row) : $row;

if ($key === 0) {
return $this->showItemExtra
? sprintf('%s%s %s', $row, str_repeat(' ', $length - mb_strlen($row)), $style->getItemExtra())
: $row;
? sprintf('%s%s %s', $text, str_repeat(' ', $length - mb_strlen($row)), $style->getItemExtra())
: $text;
}

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

Expand All @@ -65,7 +72,7 @@ public function getRows(MenuStyle $style, $selected = false)
*/
public function canSelect()
{
return true;
return !$this->disabled;
}

/**
Expand Down
17 changes: 16 additions & 1 deletion src/MenuStyle.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,11 @@ class MenuStyle
*/
private static $availableOptions = array(
'bold' => array('set' => 1, 'unset' => 22),
'dim' => array('set' => 2, 'unset' => 22),
'underscore' => array('set' => 4, 'unset' => 24),
'blink' => array('set' => 5, 'unset' => 25),
'reverse' => array('set' => 7, 'unset' => 27),
'conceal' => array('set' => 8, 'unset' => 28),
'conceal' => array('set' => 8, 'unset' => 28)
);

/**
Expand Down Expand Up @@ -180,6 +181,20 @@ public static function getAvailableColours()
{
return array_keys(self::$availableBackgroundColors);
}

/**
* @param string $text
* @return string
*/
public function getDisabledItemText($text)
{
return sprintf(
"\033[%sm%s\033[%sm",
self::$availableOptions['dim']['set'],
$text,
self::$availableOptions['dim']['unset']
);
}

/**
* Get the colour code set for Bg and Fg
Expand Down
9 changes: 9 additions & 0 deletions src/Util/StringUtil.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,13 @@ public static function wordwrap($str, $width, $break = "\n")
return $word;
}, explode(" ", $str)));
}

/**
* @param string $str
* @return string
*/
public static function stripAnsiEscapeSequence($str)
{
return preg_replace('/\x1b[^m]*m/', '', $str);
}
}
8 changes: 8 additions & 0 deletions test/CliMenuBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,14 @@ public function testDisableDefaultItemsDisablesExitAndGoBackOnSubMenu()

$this->checkVariable($subMenu, 'items', []);
}

public function testThrowsExceptionWhenDisablingRootMenu()
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('You can\'t disable the root menu');

(new CliMenuBuilder)->disableMenu();
}

/**
* @param CliMenu $menu
Expand Down

0 comments on commit c7bdb1b

Please sign in to comment.