Skip to content

Selectable item styles #214

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 5 commits into from
Dec 20, 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
19 changes: 13 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -801,13 +801,17 @@ markers only display on *selectable* items, which are: `\PhpSchool\CliMenu\MenuI
<?php

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\Style\SelectableStyle;

$menu = (new CliMenuBuilder)
->setUnselectedMarker('❅ ')
->setSelectedMarker('✏ ')

//disable unselected marker
->setUnselectedMarker('')
->modifySelectableStyle(function (SelectableStyle $style) {
$style->setUnselectedMarker('❅ ')
->setSelectedMarker('✏ ')

// disable unselected marker
->setUnselectedMarker('')
;
})
->build();
```

Expand Down Expand Up @@ -858,9 +862,12 @@ The third parameter to `addItem` is a boolean whether to show the item extra or

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\Style\SelectableStyle;

$menu = (new CliMenuBuilder)
->setItemExtra('✔')
->modifySelectableStyle(function (SelectableStyle $style) {
$style->setItemExtra('✔');
})
->addItem('Exercise 1', function (CliMenu $menu) { echo 'I am complete!'; }, true)
->build();
```
Expand Down
7 changes: 5 additions & 2 deletions examples/custom-styles.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\Style\SelectableStyle;

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

Expand All @@ -20,9 +21,11 @@
->setPadding(4)
->setMargin(4)
->setBorder(1, 2, 'red')
->setUnselectedMarker(' ')
->setSelectedMarker('>')
->setTitleSeparator('- ')
->modifySelectableStyle(function (SelectableStyle $style) {
$style->setUnselectedMarker(' ')
->setSelectedMarker('>');
})
->build();

$menu->open();
6 changes: 4 additions & 2 deletions examples/item-extra-toggling.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\Style\SelectableStyle;

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

Expand All @@ -20,8 +21,9 @@
->addItem('First Item', $itemCallable)
->addItem('Second Item', $itemCallable)
->addItem('Third Item', $itemCallable)
->setItemExtra('[COMPLETE!]')
->displayExtra()
->modifySelectableStyle(function (SelectableStyle $style) {
$style->setItemExtra('[COMPLETE!]');
})
->addLineBreak('-')
->build();

Expand Down
44 changes: 39 additions & 5 deletions src/Builder/CliMenuBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use PhpSchool\CliMenu\MenuStyle;
use PhpSchool\CliMenu\Style\CheckboxStyle;
use PhpSchool\CliMenu\Style\RadioStyle;
use PhpSchool\CliMenu\Style\SelectableStyle;
use PhpSchool\CliMenu\Terminal\TerminalFactory;
use PhpSchool\Terminal\Terminal;

Expand Down Expand Up @@ -89,12 +90,12 @@ public function __construct(Terminal $terminal = null)
$this->style = new MenuStyle($this->terminal);
$this->menu = new CliMenu(null, [], $this->terminal, $this->style);
}

public static function newSubMenu(Terminal $terminal) : self
{
$instance = new self($terminal);
$instance->subMenu = true;

return $instance;
}

Expand Down Expand Up @@ -396,22 +397,25 @@ public function setMargin(int $margin) : self
public function setUnselectedMarker(string $marker) : self
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's just drop these methods. It's just a little BC break.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still needed for MenuMenuItem. I can completely drop in next PR for that item's style.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok great, sounds good.

{
$this->style->setUnselectedMarker($marker);
$this->menu->getSelectableStyle()->setUnselectedMarker($marker);

return $this;
}

public function setSelectedMarker(string $marker) : self
{
$this->style->setSelectedMarker($marker);
$this->menu->getSelectableStyle()->setSelectedMarker($marker);

return $this;
}

public function setItemExtra(string $extra) : self
{
$this->style->setItemExtra($extra);
$this->menu->getSelectableStyle()->setItemExtra($extra);

//if we customise item extra, it means we most likely want to display it
// if we customise item extra, it means we most likely want to display it
$this->displayExtra();

return $this;
Expand All @@ -434,7 +438,7 @@ public function setBorder(int $top, $right = null, $bottom = null, $left = null,
public function setBorderTopWidth(int $width) : self
{
$this->style->setBorderTopWidth($width);

return $this;
}

Expand Down Expand Up @@ -497,6 +501,7 @@ public function disableDefaultItems() : self
public function displayExtra() : self
{
$this->style->setDisplaysExtra(true);
$this->menu->getSelectableStyle()->setDisplaysExtra(true);

return $this;
}
Expand All @@ -507,7 +512,7 @@ private function itemsHaveExtra(array $items) : bool
return $item->showsItemExtra();
}));
}

public function build() : CliMenu
{
if (!$this->disableDefaultItems) {
Expand Down Expand Up @@ -563,6 +568,25 @@ public function modifyRadioStyle(callable $itemCallable) : self
return $this;
}

public function getSelectableStyle() : SelectableStyle
{
return $this->menu->getSelectableStyle();
}

public function setSelectableStyle(SelectableStyle $style) : self
{
$this->menu->setSelectableStyle($style);

return $this;
}

public function modifySelectableStyle(callable $itemCallable) : self
{
$itemCallable($this->menu->getSelectableStyle());

return $this;
}

/**
* Pass styles from current menu to sub-menu
* only if sub-menu style has not be customized
Expand All @@ -584,6 +608,12 @@ private function propagateStyles(CliMenu $menu, array $items = [])
$item->setStyle(clone $menu->getRadioStyle());
}

if ($item instanceof SelectableItem
&& !$item->getStyle()->hasChangedFromDefaults()
) {
$item->setStyle(clone $menu->getSelectableStyle());
}

// Apply current style to children, if they are not customized
if ($item instanceof MenuMenuItem) {
$subMenu = $item->getSubMenu();
Expand All @@ -600,6 +630,10 @@ private function propagateStyles(CliMenu $menu, array $items = [])
$subMenu->setRadioStyle(clone $menu->getRadioStyle());
}

if (!$subMenu->getSelectableStyle()->hasChangedFromDefaults()) {
$subMenu->setSelectableStyle(clone $menu->getSelectableStyle());
}

$this->propagateStyles($subMenu);
}

Expand Down
31 changes: 25 additions & 6 deletions src/CliMenu.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use PhpSchool\CliMenu\Dialogue\Flash;
use PhpSchool\CliMenu\Style\CheckboxStyle;
use PhpSchool\CliMenu\Style\RadioStyle;
use PhpSchool\CliMenu\Style\SelectableStyle;
use PhpSchool\CliMenu\Terminal\TerminalFactory;
use PhpSchool\CliMenu\Util\StringUtil as s;
use PhpSchool\Terminal\InputCharacter;
Expand Down Expand Up @@ -47,6 +48,11 @@ class CliMenu
*/
private $radioStyle;

/**
* @var SelectableStyle
*/
private $selectableStyle;

/**
* @var ?string
*/
Expand Down Expand Up @@ -102,12 +108,13 @@ public function __construct(
Terminal $terminal = null,
MenuStyle $style = null
) {
$this->title = $title;
$this->items = $items;
$this->terminal = $terminal ?: TerminalFactory::fromSystem();
$this->style = $style ?: new MenuStyle($this->terminal);
$this->checkboxStyle = new CheckboxStyle();
$this->radioStyle = new RadioStyle();
$this->title = $title;
$this->items = $items;
$this->terminal = $terminal ?: TerminalFactory::fromSystem();
$this->style = $style ?: new MenuStyle($this->terminal);
$this->checkboxStyle = new CheckboxStyle();
$this->radioStyle = new RadioStyle();
$this->selectableStyle = new SelectableStyle();

$this->selectFirstItem();
}
Expand Down Expand Up @@ -678,6 +685,18 @@ public function setRadioStyle(RadioStyle $style) : self
return $this;
}

public function getSelectableStyle() : SelectableStyle
{
return $this->selectableStyle;
}

public function setSelectableStyle(SelectableStyle $style) : self
{
$this->selectableStyle = $style;

return $this;
}

public function getCurrentFrame() : Frame
{
return $this->currentFrame;
Expand Down
98 changes: 96 additions & 2 deletions src/MenuItem/SelectableItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,31 @@

namespace PhpSchool\CliMenu\MenuItem;

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

/**
* @author Michael Woodward <[email protected]>
*/
class SelectableItem implements MenuItemInterface
{
use SelectableTrait;

/**
* @var callable
*/
private $selectAction;

private $text = '';

private $showItemExtra = false;

private $disabled = false;

/**
* @var SelectableStyle;
*/
private $style;

public function __construct(
string $text,
callable $selectAction,
Expand All @@ -24,6 +37,46 @@ public function __construct(
$this->selectAction = $selectAction;
$this->showItemExtra = $showItemExtra;
$this->disabled = $disabled;

$this->style = new SelectableStyle();
}

/**
* The output text for the item
*/
public function getRows(MenuStyle $style, bool $selected = false) : array
{
$marker = sprintf("%s", $this->style->getMarker($selected));

$length = $this->style->getDisplaysExtra()
? $style->getContentWidth() - (mb_strlen($this->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)),
$this->style->getItemExtra()
)
: $text;
}

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

/**
Expand All @@ -34,6 +87,18 @@ public function getSelectAction() : ?callable
return $this->selectAction;
}

public function getStyle() : SelectableStyle
{
return $this->style;
}

public function setStyle(SelectableStyle $style) : self
{
$this->style = $style;

return $this;
}

/**
* Return the raw string of text
*/
Expand All @@ -49,4 +114,33 @@ public function setText(string $text) : void
{
$this->text = $text;
}

/**
* Can the item be selected
*/
public function canSelect() : bool
{
return !$this->disabled;
}

public function showsItemExtra() : bool
{
return $this->showItemExtra;
}

/**
* Enable showing item extra
*/
public function showItemExtra() : void
{
$this->showItemExtra = true;
}

/**
* Disable showing item extra
*/
public function hideItemExtra() : void
{
$this->showItemExtra = false;
}
}
Loading