Skip to content

Split item with builder #127

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 44 commits into from
May 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
9ee226c
Add Split Item
Lynesth May 1, 2018
1ebbfcf
Add Split Item
Lynesth May 1, 2018
2d6f516
Create SplitItem.php
Lynesth May 1, 2018
b661374
Fix PSR2 + non-nullable int
Lynesth May 1, 2018
44b7c84
Merge branch 'master' into patch-4
Lynesth May 1, 2018
45e17ac
Merge branch 'patch-4' of https://github.com/Lynesth/cli-menu into Ly…
May 11, 2018
fc48628
Integration with CliMenuBuilder
May 11, 2018
31f134f
cs
May 11, 2018
0483240
Add submenus to split items
Lynesth May 11, 2018
92af28f
Merge branch 'patch-4' of https://github.com/Lynesth/cli-menu
AydinHassan May 11, 2018
b00bb94
Refactor split item to separate builder
AydinHassan May 11, 2018
2f08464
CS
AydinHassan May 11, 2018
32acc24
Fix typehint again
AydinHassan May 11, 2018
fe1a12d
Update SplitItem.php
Lynesth May 13, 2018
035910e
Split moveSelection in 2 functions
May 13, 2018
bc21c15
Refactoring
Lynesth May 13, 2018
009cf60
Add comment and exception
Lynesth May 13, 2018
ccea967
Merge pull request #128 from Lynesth/patch-22
AydinHassan May 13, 2018
c4c0d51
Remove unused method
AydinHassan May 13, 2018
bb9b06d
Tests + minor fixes
AydinHassan May 13, 2018
c7ef4d0
Refactor SplitItem
AydinHassan May 13, 2018
59df011
CS
AydinHassan May 13, 2018
cd817b2
CS
AydinHassan May 13, 2018
7fe55f0
Consistent method names
AydinHassan May 13, 2018
15b0c6d
Use __CLASS__ constant
AydinHassan May 13, 2018
f931cb6
Tests for add/set items
AydinHassan May 13, 2018
e058166
Throw an exception in getRows if no items were added
AydinHassan May 13, 2018
a6fadcf
CS
AydinHassan May 13, 2018
54cf6a0
Fix display bug
AydinHassan May 13, 2018
de67bcf
tests for canSelect
AydinHassan May 13, 2018
b7c1eca
Selected item tests
AydinHassan May 13, 2018
39d5df7
Remove boundary check
AydinHassan May 13, 2018
525486e
Merge pull request #132 from php-school/split-item-menu-tests
AydinHassan May 13, 2018
c5ffe6c
Fix wordwrap
AydinHassan May 13, 2018
1dc8b08
CS
AydinHassan May 13, 2018
ff94083
Merge pull request #134 from php-school/word-wrap-fix
AydinHassan May 13, 2018
f711cd3
New wordwrap method
AydinHassan May 13, 2018
1bf30f8
Merge pull request #135 from php-school/wordwrap-again
AydinHassan May 13, 2018
327c85f
Split Item - Item Extra
AydinHassan May 13, 2018
b3b5927
Merge pull request #136 from php-school/split-item-item-extra
AydinHassan May 13, 2018
c5741fe
Refactor split item item selection and CliMenu can select checks. Add
AydinHassan May 13, 2018
ecb429d
Fix doc
AydinHassan May 13, 2018
d293834
CS
AydinHassan May 13, 2018
61c6940
Merge pull request #138 from php-school/split-item-select-refactor
AydinHassan May 14, 2018
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
35 changes: 35 additions & 0 deletions examples/split-item.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?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)
->setWidth(150)
->addSplitItem()
->addSubMenu('Sub Menu on a split item')
->setTitle('Behold the awesomeness')
->addItem('This is awesome', function() { print 'Yes!'; })
->addSplitItem()
->addItem('Split Item 1', function() { print 'Item 1!'; })
->addItem('Split Item 2', function() { print 'Item 2!'; })
->addItem('Split Item 3', function() { print 'Item 3!'; })
->addSubMenu('Split Item Nested Sub Menu')
->addItem('One', function() { print 'One!'; })
->addItem('Two', function() { print 'Two!'; })
->addItem('Three', function() { print 'Three!'; })
->end()
->end()
->end()
->addItem('Item 2', $itemCallable)
->addStaticItem('Item 3 - Static')
->addItem('Item 4', $itemCallable)
->end()
->build();

$menu->open();
17 changes: 17 additions & 0 deletions src/Builder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace PhpSchool\CliMenu;

use PhpSchool\Terminal\Terminal;

/**
* @author Aydin Hassan <aydin@hotmail.co.uk>
*/
interface Builder
{
public function getTerminal() : Terminal;

public function end() : ?Builder;

public function getMenuStyle() : MenuStyle;
}
109 changes: 109 additions & 0 deletions src/BuilderUtils.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php

namespace PhpSchool\CliMenu;

use PhpSchool\CliMenu\MenuItem\LineBreakItem;
use PhpSchool\CliMenu\MenuItem\MenuMenuItem;
use PhpSchool\CliMenu\MenuItem\SelectableItem;
use PhpSchool\CliMenu\MenuItem\StaticItem;
use RuntimeException;

/**
* @author Aydin Hassan <aydin@hotmail.co.uk>
*/
trait BuilderUtils
{
/**
* @var null|Builder
*/
private $parent;

/**
* @var self[]
*/
private $subMenuBuilders = [];

/**
* @var CliMenu[]
*/
private $subMenus = [];

/**
* @var array
*/
private $menuItems = [];

public function addItem(
string $text,
callable $itemCallable,
bool $showItemExtra = false,
bool $disabled = false
) : self {
$this->menuItems[] = new SelectableItem($text, $itemCallable, $showItemExtra, $disabled);

return $this;
}

public function addStaticItem(string $text) : self
{
$this->menuItems[] = new StaticItem($text);

return $this;
}

public function addLineBreak(string $breakChar = ' ', int $lines = 1) : self
{
$this->menuItems[] = new LineBreakItem($breakChar, $lines);

return $this;
}

/**
* Add a submenu with a name. The name will be displayed as the item text
* in the parent menu.
*/
public function addSubMenu(string $name, CliMenuBuilder $subMenuBuilder = null) : Builder
{
$this->menuItems[] = $id = 'submenu-placeholder-' . $name;

if (null === $subMenuBuilder) {
$this->subMenuBuilders[$id] = new CliMenuBuilder($this);
return $this->subMenuBuilders[$id];
}

$this->subMenuBuilders[$id] = $subMenuBuilder;
return $this;
}

private function buildSubMenus(array $items) : array
{
return array_map(function ($item) {
if (!is_string($item) || 0 !== strpos($item, 'submenu-placeholder-')) {
return $item;
}

$menuBuilder = $this->subMenuBuilders[$item];
$this->subMenus[$item] = $menuBuilder->build();

return new MenuMenuItem(
substr($item, \strlen('submenu-placeholder-')),
$this->subMenus[$item],
$menuBuilder->isMenuDisabled()
);
}, $items);
}

/**
* Return to parent builder
*
* @throws RuntimeException
*/
public function end() : ?Builder
{
if (null === $this->parent) {
throw new RuntimeException('No parent builder to return to');
}

return $this->parent;
}
}
76 changes: 68 additions & 8 deletions src/CliMenu.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use PhpSchool\CliMenu\Input\Text;
use PhpSchool\CliMenu\MenuItem\LineBreakItem;
use PhpSchool\CliMenu\MenuItem\MenuItemInterface;
use PhpSchool\CliMenu\MenuItem\SplitItem;
use PhpSchool\CliMenu\MenuItem\StaticItem;
use PhpSchool\CliMenu\Dialogue\Confirm;
use PhpSchool\CliMenu\Dialogue\Flash;
Expand Down Expand Up @@ -256,7 +257,12 @@ private function display() : void
switch ($char->getControl()) {
case InputCharacter::UP:
case InputCharacter::DOWN:
$this->moveSelection($char->getControl());
$this->moveSelectionVertically($char->getControl());
$this->draw();
break;
case InputCharacter::LEFT:
case InputCharacter::RIGHT:
$this->moveSelectionHorizontally($char->getControl());
$this->draw();
break;
case InputCharacter::ENTER:
Expand All @@ -269,11 +275,11 @@ private function display() : void
/**
* Move the selection in a given direction, up / down
*/
protected function moveSelection(string $direction) : void
protected function moveSelectionVertically(string $direction) : void
{
do {
$itemKeys = array_keys($this->items);
$itemKeys = array_keys($this->items);

do {
$direction === 'UP'
? $this->selectedItem--
: $this->selectedItem++;
Expand All @@ -282,15 +288,65 @@ protected function moveSelection(string $direction) : void
$this->selectedItem = $direction === 'UP'
? end($itemKeys)
: reset($itemKeys);
} elseif ($this->getSelectedItem()->canSelect()) {
return;
}
} while (!$this->getSelectedItem()->canSelect());
} while (!$this->canSelect());
}

/**
* Move the selection in a given direction, left / right
*/
protected function moveSelectionHorizontally(string $direction) : void
{
if (!$this->items[$this->selectedItem] instanceof SplitItem) {
return;
}

/** @var SplitItem $item */
$item = $this->items[$this->selectedItem];
$itemKeys = array_keys($item->getItems());
$selectedItemIndex = $item->getSelectedItemIndex();

do {
$direction === 'LEFT'
? $selectedItemIndex--
: $selectedItemIndex++;

if (!array_key_exists($selectedItemIndex, $item->getItems())) {
$selectedItemIndex = $direction === 'LEFT'
? end($itemKeys)
: reset($itemKeys);
}
} while (!$item->canSelectIndex($selectedItemIndex));

$item->setSelectedItemIndex($selectedItemIndex);
}

/**
* Can the currently selected item actually be selected?
*
* For example:
* selectable item -> yes
* static item -> no
* split item with only static items -> no
* split item with at least one selectable item -> yes
*
* @return bool
*/
private function canSelect() : bool
{
return $this->items[$this->selectedItem]->canSelect();
}

/**
* Retrieve the item the user actually selected
*
*/
public function getSelectedItem() : MenuItemInterface
{
return $this->items[$this->selectedItem];
$item = $this->items[$this->selectedItem];
return $item instanceof SplitItem
? $item->getSelectedItem()
: $item;
}

/**
Expand Down Expand Up @@ -385,6 +441,10 @@ protected function draw() : void
protected function drawMenuItem(MenuItemInterface $item, bool $selected = false) : array
{
$rows = $item->getRows($this->style, $selected);

if ($item instanceof SplitItem) {
$selected = false;
}

$invertedColoursSetCode = $selected
? $this->style->getInvertedColoursSetCode()
Expand Down
Loading