Skip to content

Refactors for ItemStyles #230

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 13 commits into from
Feb 15, 2020
4 changes: 0 additions & 4 deletions phpstan.neon
Original file line number Diff line number Diff line change
@@ -1,6 +1,2 @@
parameters:
checkMissingIterableValueType: false
ignoreErrors:
-
message: '#Function PhpSchool\\\\CliMenu\\\\Util\\\\mapWithKeys should return array but returns array|false#'
path: src/Util/ArrayUtils.php
118 changes: 43 additions & 75 deletions src/Builder/CliMenuBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use PhpSchool\CliMenu\MenuItem\StaticItem;
use PhpSchool\CliMenu\MenuStyle;
use PhpSchool\CliMenu\Style\CheckboxStyle;
use PhpSchool\CliMenu\Style\DefaultStyle;
use PhpSchool\CliMenu\Style\RadioStyle;
use PhpSchool\CliMenu\Style\SelectableStyle;
use PhpSchool\CliMenu\Terminal\TerminalFactory;
Expand Down Expand Up @@ -397,7 +398,7 @@ public function setMargin(int $margin) : self
public function setItemExtra(string $extra) : self
{
$this->style->setItemExtra($extra);
$this->menu->getSelectableStyle()->setItemExtra($extra);
$this->getSelectableStyle()->setItemExtra($extra);

// if we customise item extra, it means we most likely want to display it
$this->displayExtra();
Expand Down Expand Up @@ -490,7 +491,7 @@ public function disableDefaultItems() : self
public function displayExtra() : self
{
$this->style->setDisplaysExtra(true);
$this->menu->getSelectableStyle()->setDisplaysExtra(true);
$this->getSelectableStyle()->setDisplaysExtra(true);

return $this;
}
Expand All @@ -513,126 +514,93 @@ public function build() : CliMenu
}

if (!$this->subMenu) {
$this->propagateStyles($this->menu);
$this->menu->propagateStyles();
}

return $this->menu;
}

public function getCheckboxStyle() : CheckboxStyle
public function getDefaultStyle() : DefaultStyle
{
return $this->menu->getCheckboxStyle();
$style = $this->menu->getItemStyle(DefaultStyle::class);
assert($style instanceof DefaultStyle);
return $style;
}

public function setCheckboxStyle(CheckboxStyle $style) : self
public function setDefaultStyle(DefaultStyle $style) : self
{
$this->menu->setCheckboxStyle($style);
$this->menu->setItemStyle($style, DefaultStyle::class);

return $this;
}

public function modifyCheckboxStyle(callable $itemCallable) : self
public function modifyDefaultStyle(callable $itemCallable) : self
{
$itemCallable($this->menu->getCheckboxStyle());
$itemCallable($this->getDefaultStyle());

return $this;
}

public function getRadioStyle() : RadioStyle
public function getSelectableStyle() : SelectableStyle
{
return $this->menu->getRadioStyle();
$style = $this->menu->getItemStyle(SelectableStyle::class);
assert($style instanceof SelectableStyle);
return $style;
}

public function setRadioStyle(RadioStyle $style) : self
public function setSelectableStyle(SelectableStyle $style) : self
{
$this->menu->setRadioStyle($style);
$this->menu->setItemStyle($style, SelectableStyle::class);

return $this;
}

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

return $this;
}

public function getSelectableStyle() : SelectableStyle
public function getCheckboxStyle() : CheckboxStyle
{
return $this->menu->getSelectableStyle();
$style = $this->menu->getItemStyle(CheckboxStyle::class);
assert($style instanceof CheckboxStyle);
return $style;
}

public function setSelectableStyle(SelectableStyle $style) : self
public function setCheckboxStyle(CheckboxStyle $style) : self
{
$this->menu->setSelectableStyle($style);
$this->menu->setItemStyle($style, CheckboxStyle::class);

return $this;
}

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

return $this;
}

/**
* Pass styles from current menu to sub-menu
* only if sub-menu style has not be customized
*/
private function propagateStyles(CliMenu $menu, array $items = []) : void
{
$currentItems = !empty($items) ? $items : $menu->getItems();

foreach ($currentItems as $item) {
if ($item instanceof CheckboxItem
&& !$item->getStyle()->hasChangedFromDefaults()
) {
$item->setStyle(clone $menu->getCheckboxStyle());
}

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

if (($item instanceof MenuMenuItem
|| $item instanceof SelectableItem
|| $item instanceof StaticItem
)
&& !$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();

if (!$subMenu->getStyle()->hasChangedFromDefaults()) {
$subMenu->setStyle(clone $menu->getStyle());
}

if (!$subMenu->getCheckboxStyle()->hasChangedFromDefaults()) {
$subMenu->setCheckboxStyle(clone $menu->getCheckboxStyle());
}
public function getRadioStyle() : RadioStyle
{
$style = $this->menu->getItemStyle(RadioStyle::class);
assert($style instanceof RadioStyle);
return $style;
}

if (!$subMenu->getRadioStyle()->hasChangedFromDefaults()) {
$subMenu->setRadioStyle(clone $menu->getRadioStyle());
}
public function setRadioStyle(RadioStyle $style) : self
{
$this->menu->setItemStyle($style, RadioItem::class);

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

$this->propagateStyles($subMenu);
}
public function modifyRadioStyle(callable $itemCallable) : self
{
$itemCallable($this->getRadioStyle());

// Apply styles to SplitItem children using current $menu
if ($item instanceof SplitItem) {
$this->propagateStyles($menu, $item->getItems());
}
}
return $this;
}
}
81 changes: 40 additions & 41 deletions src/CliMenu.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,19 @@
use PhpSchool\CliMenu\Input\Text;
use PhpSchool\CliMenu\MenuItem\LineBreakItem;
use PhpSchool\CliMenu\MenuItem\MenuItemInterface;
use PhpSchool\CliMenu\MenuItem\PropagatesStyles;
use PhpSchool\CliMenu\MenuItem\SplitItem;
use PhpSchool\CliMenu\MenuItem\StaticItem;
use PhpSchool\CliMenu\Dialogue\Confirm;
use PhpSchool\CliMenu\Dialogue\Flash;
use PhpSchool\CliMenu\Style\CheckboxStyle;
use PhpSchool\CliMenu\Style\RadioStyle;
use PhpSchool\CliMenu\Style\SelectableStyle;
use PhpSchool\CliMenu\Style\ItemStyle;
use PhpSchool\CliMenu\Style\Locator;
use PhpSchool\CliMenu\Terminal\TerminalFactory;
use PhpSchool\CliMenu\Util\StringUtil as s;
use PhpSchool\Terminal\InputCharacter;
use PhpSchool\Terminal\NonCanonicalReader;
use PhpSchool\Terminal\Terminal;
use function PhpSchool\CliMenu\Util\each;

/**
* @author Michael Woodward <[email protected]>
Expand All @@ -39,19 +40,9 @@ class CliMenu
protected $style;

/**
* @var CheckboxStyle
* @var Locator
*/
private $checkboxStyle;

/**
* @var RadioStyle
*/
private $radioStyle;

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

/**
* @var ?string
Expand Down Expand Up @@ -112,9 +103,8 @@ public function __construct(
$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->itemStyleLocator = new Locator();

$this->selectFirstItem();
}
Expand Down Expand Up @@ -661,40 +651,28 @@ public function setStyle(MenuStyle $style) : void
$this->style = $style;
}

public function getCheckboxStyle() : CheckboxStyle
public function setItemStyle(ItemStyle $style, string $styleClass) : void
{
return $this->checkboxStyle;
$this->itemStyleLocator->setStyle($style, $styleClass);
}

public function setCheckboxStyle(CheckboxStyle $style) : self
public function getItemStyle(string $styleClass) : ItemStyle
{
$this->checkboxStyle = $style;

return $this;
return $this->itemStyleLocator->getStyle($styleClass);
}

public function getRadioStyle() : RadioStyle
public function getItemStyleForItem(MenuItemInterface $item) : ItemStyle
{
return $this->radioStyle;
return $this->itemStyleLocator->getStyleForMenuItem($item);
}

public function setRadioStyle(RadioStyle $style) : self
public function importStyles(CliMenu $menu) : void
{
$this->radioStyle = $style;

return $this;
}

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

public function setSelectableStyle(SelectableStyle $style) : self
{
$this->selectableStyle = $style;
if (!$this->style->hasChangedFromDefaults()) {
$this->style = $menu->style;
}

return $this;
$this->itemStyleLocator->importFrom($menu->itemStyleLocator);
}

public function getCurrentFrame() : Frame
Expand Down Expand Up @@ -763,4 +741,25 @@ private function guardSingleLine(string $text) : void
throw new \InvalidArgumentException;
}
}

public function propagateStyles() : void
{
each(
array_filter($this->items, function (MenuItemInterface $item) {
return !$item->getStyle()->hasChangedFromDefaults();
}),
function (int $index, $item) {
$item->setStyle(clone $this->getItemStyleForItem($item));
}
);

each(
array_filter($this->items, function (MenuItemInterface $item) {
return $item instanceof PropagatesStyles;
}),
function (int $index, PropagatesStyles $item) {
$item->propagateStyles($this);
}
);
}
}
22 changes: 22 additions & 0 deletions src/MenuItem/AsciiArtItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use Assert\Assertion;
use PhpSchool\CliMenu\MenuStyle;
use PhpSchool\CliMenu\Style\DefaultStyle;
use PhpSchool\CliMenu\Style\ItemStyle;

/**
* @author Michael Woodward <[email protected]>
Expand Down Expand Up @@ -37,13 +39,20 @@ class AsciiArtItem implements MenuItemInterface
*/
private $artLength;

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

public function __construct(string $text, string $position = self::POSITION_CENTER, string $alt = '')
{
Assertion::inArray($position, [self::POSITION_CENTER, self::POSITION_RIGHT, self::POSITION_LEFT]);

$this->setText($text);
$this->position = $position;
$this->alternateText = $alt;

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

/**
Expand Down Expand Up @@ -161,4 +170,17 @@ public function hideItemExtra() : void
{
//noop
}

/**
* @return DefaultStyle
*/
public function getStyle() : ItemStyle
{
return $this->style;
}

public function setStyle(DefaultStyle $style) : void
{
$this->style = $style;
}
}
Loading