Skip to content

Initial checkable item support #186

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 16, 2019
Merged
Show file tree
Hide file tree
Changes from 3 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: 41 additions & 0 deletions examples/checkable-item.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

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->check();

$menu->redraw();
};

$menu = (new CliMenuBuilder)
->setTitle('Select a Language')
->addSubMenu('Compiled', function (CliMenuBuilder $b) use ($itemCallable) {
$b->setTitle('Compiled Languages')
->addCheckableItem('Rust', $itemCallable)
->addCheckableItem('C++', $itemCallable)
->addCheckableItem('Go', $itemCallable)
->addCheckableItem('Java', $itemCallable)
->addCheckableItem('C', $itemCallable)
;
})
->addSubMenu('Interpreted', function (CliMenuBuilder $b) use ($itemCallable) {
$b->setTitle('Interpreted Languages')
->setUncheckedMarker('[○] ')
->setCheckedMarker('[●] ')
->addCheckableItem('PHP', $itemCallable)
->addCheckableItem('Javascript', $itemCallable)
->addCheckableItem('Ruby', $itemCallable)
->addCheckableItem('Python', $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 @@ -6,6 +6,7 @@
use PhpSchool\CliMenu\Action\GoBackAction;
use PhpSchool\CliMenu\Exception\InvalidShortcutException;
use PhpSchool\CliMenu\MenuItem\AsciiArtItem;
use PhpSchool\CliMenu\MenuItem\CheckableItem;
use PhpSchool\CliMenu\MenuItem\LineBreakItem;
use PhpSchool\CliMenu\MenuItem\MenuItemInterface;
use PhpSchool\CliMenu\MenuItem\MenuMenuItem;
Expand Down Expand Up @@ -130,6 +131,17 @@ public function addItems(array $items) : self
return $this;
}

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

return $this;
}

public function addStaticItem(string $text) : self
{
$this->addMenuItem(new StaticItem($text));
Expand Down Expand Up @@ -395,6 +407,20 @@ public function setSelectedMarker(string $marker) : self
return $this;
}

public function setUncheckedMarker(string $marker) : self
{
$this->style->setUncheckedMarker($marker);

return $this;
}

public function setCheckedMarker(string $marker) : self
{
$this->style->setCheckedMarker($marker);

return $this;
}

public function setItemExtra(string $extra) : self
{
$this->style->setItemExtra($extra);
Expand Down
166 changes: 166 additions & 0 deletions src/MenuItem/CheckableItem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
<?php

namespace PhpSchool\CliMenu\MenuItem;

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

class CheckableItem implements MenuItem\MenuItemInterface
{
/**
* @var callable
*/
private $selectAction;

/**
* @var string
*/
private $text = '';

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

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

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

public function __construct(
string $text,
callable $selectAction,
bool $showItemExtra = false,
bool $disabled = false
) {
$this->text = $text;
$this->selectAction = $selectAction;
$this->showItemExtra = $showItemExtra;
$this->disabled = $disabled;
}

/**
* Execute the items callable if required
*/
public function getSelectAction() : ?callable
{
return $this->selectAction;
}

/**
* Return the raw string of text
*/
public function getText() : string
{
return $this->text;
}

/**
* Set the raw string of text
*/
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
*/
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;
}

/**
* Toggles checked state
*/
public function check()
{
$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;
}
}
40 changes: 40 additions & 0 deletions src/MenuStyle.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,16 @@ class MenuStyle
*/
private $unselectedMarker;

/**
* @var string
*/
private $checkedMarker;

/**
* @var string
*/
private $uncheckedMarker;

/**
* @var string
*/
Expand Down Expand Up @@ -158,6 +168,8 @@ class MenuStyle
'margin' => 2,
'selectedMarker' => '● ',
'unselectedMarker' => '○ ',
'checkedMarker' => '[✔] ',
'uncheckedMarker' => '[ ] ',
'itemExtra' => '✔',
'displaysExtra' => false,
'titleSeparator' => '=',
Expand Down Expand Up @@ -229,6 +241,8 @@ public function __construct(Terminal $terminal = null)
$this->setMargin(self::$defaultStyleValues['margin']);
$this->setSelectedMarker(self::$defaultStyleValues['selectedMarker']);
$this->setUnselectedMarker(self::$defaultStyleValues['unselectedMarker']);
$this->setCheckedMarker(self::$defaultStyleValues['checkedMarker']);
$this->setUncheckedMarker(self::$defaultStyleValues['uncheckedMarker']);
$this->setItemExtra(self::$defaultStyleValues['itemExtra']);
$this->setDisplaysExtra(self::$defaultStyleValues['displaysExtra']);
$this->setTitleSeparator(self::$defaultStyleValues['titleSeparator']);
Expand All @@ -250,6 +264,8 @@ public function hasChangedFromDefaults() : bool
$this->margin,
$this->selectedMarker,
$this->unselectedMarker,
$this->checkedMarker,
$this->uncheckedMarker,
$this->itemExtra,
$this->displaysExtra,
$this->titleSeparator,
Expand Down Expand Up @@ -557,6 +573,30 @@ public function getMarker(bool $selected) : string
return $selected ? $this->selectedMarker : $this->unselectedMarker;
}

public function getCheckedMarker() : string
{
return $this->checkedMarker;
}

public function setCheckedMarker(string $marker) : self
{
$this->checkedMarker = $marker;

return $this;
}

public function getUncheckedMarker() : string
{
return $this->uncheckedMarker;
}

public function setUncheckedMarker(string $marker) : self
{
$this->uncheckedMarker = $marker;

return $this;
}

public function setItemExtra(string $itemExtra) : self
{
$this->itemExtra = $itemExtra;
Expand Down