Skip to content

Checkbox + Radio item-level styling #205

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

Closed
wants to merge 10 commits into from
Closed

Checkbox + Radio item-level styling #205

wants to merge 10 commits into from

Conversation

AydinHassan
Copy link
Member

@AydinHassan AydinHassan commented Dec 19, 2019

#204 without checkbox rename

Related to #203 and #200

  • Renames CheckableItem to CheckboxItem
  • Adds item-level styling (markers, item extra and display extra)
  • Item styles are passed down from parent menu, or use default values

This does not fix the nested-style issue from #201

@codecov-io
Copy link

codecov-io commented Dec 19, 2019

Codecov Report

Merging #205 into master will decrease coverage by 1.43%.
The diff coverage is 82.72%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master     #205      +/-   ##
============================================
- Coverage     93.91%   92.48%   -1.44%     
- Complexity      516      559      +43     
============================================
  Files            29       30       +1     
  Lines          1561     1689     +128     
============================================
+ Hits           1466     1562      +96     
- Misses           95      127      +32
Impacted Files Coverage Δ Complexity Δ
src/MenuStyle.php 96.99% <ø> (-0.29%) 70 <0> (-8)
src/MenuItem/RadioItem.php 100% <100%> (ø) 21 <11> (+11) ⬆️
src/CliMenu.php 95.25% <100%> (+0.2%) 113 <4> (+4) ⬆️
src/MenuItem/SplitItem.php 100% <100%> (ø) 45 <0> (-2) ⬇️
src/Builder/CliMenuBuilder.php 78.76% <50%> (-2.97%) 76 <6> (+6)
src/Builder/SplitItemBuilder.php 70.31% <61.53%> (-7.19%) 20 <6> (+8)
src/MenuItem/CheckboxItem.php 92.72% <87.87%> (-7.28%) 20 <11> (+11)
src/Style/CheckboxStyle.php 88.57% <88.57%> (ø) 12 <12> (?)
src/Style/RadioStyle.php 88.57% <88.57%> (ø) 12 <12> (?)
... and 1 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c72b588...4ea4242. Read the comment docs.

@jtreminio jtreminio mentioned this pull request Dec 19, 2019

public function __construct()
{
$this->setMarkerOn(self::DEFAULT_STYLES['markerOn']);
Copy link
Member Author

Choose a reason for hiding this comment

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

Doesn't this automatically set it as custom?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, but then it has $this->custom = false;

Comment on lines 136 to 138
$menu->radioStyle(function (RadioStyle $style) {
$style->fromArray($this->menu->getRadioStyle()->toArray());
});
Copy link
Member Author

Choose a reason for hiding this comment

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

Same as above


public function radioStyle(callable $itemCallable) : self
{
$this->menu->radioStyle($itemCallable);
Copy link
Member Author

Choose a reason for hiding this comment

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

$itemCallable($this->menu->getRadioStyle())

@@ -139,4 +168,18 @@ public function build() : SplitItem
{
return $this->splitItem;
}

public function checkboxStyle(callable $itemCallable) : self
Copy link
Member Author

Choose a reason for hiding this comment

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

I don't quite understand this - Isn't this modifying the parent menu checkbox style?

Copy link
Contributor

Choose a reason for hiding this comment

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

It's for changing the style for items defined within an addSplitItem() call:

$menu = (new CliMenuBuilder)
    ->setWidth(150)
    ->addSplitItem(function (SplitItemBuilder $b) use ($itemCallable) {
        $b->addSubMenu('Sub Menu on a split item', function (CliMenuBuilder $b) {
            $b->setTitle('Behold the awesomeness')
                ->addItem('This is awesome', function() { print 'Yes!'; })
                ->addSplitItem(function (SplitItemBuilder $b) {
                    $b
                        ->checkboxStyle(function (CheckboxStyle $style) {
                            $style->setMarkerOn('[x]');
                        })
                        ->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', function (CliMenuBuilder $b) {
                            $b->addItem('One', function() { print 'One!'; })
                                ->addItem('Two', function() { print 'Two!'; })
                                ->addItem('Three', function() { print 'Three!'; });
                        });
                });
        })
        ->addItem('Item 2', $itemCallable)
        ->addStaticItem('Item 3 - Static')
        ->addItem('Item 4', $itemCallable);
    })
    ->build();

CliMenuBuilder::addSplitItem()'s style objects are separate from SplitItemBuilder's

Copy link
Member Author

Choose a reason for hiding this comment

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

hmm, it doesn't seem to work for me

Copy link
Contributor

Choose a reason for hiding this comment

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

<?php

use PhpSchool\CliMenu\Builder\SplitItemBuilder;
use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\Style\CheckboxStyle;

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

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

$menu = (new CliMenuBuilder)
    ->setWidth(150)
    ->addSplitItem(function (SplitItemBuilder $b) use ($itemCallable) {
        $b->addSubMenu('Sub Menu on a split item', function (CliMenuBuilder $b) {
            $b->setTitle('Behold the awesomeness')
                ->addItem('This is awesome', function() { print 'Yes!'; })
                ->addSplitItem(function (SplitItemBuilder $b) {
                    $b
                        ->modifyCheckboxStyle(function (CheckboxStyle $style) {
                            $style->setMarkerOn('[x] ');
                        })
                        ->addCheckboxItem('Rust', function() { print 'Item 1!'; })
                        ->addCheckboxItem('C++', function() { print 'Item 1!'; })
                        ->addCheckboxItem('Go', function() { print 'Item 1!'; })
                        ->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', function (CliMenuBuilder $b) {
                            $b->addItem('One', function() { print 'One!'; })
                                ->addItem('Two', function() { print 'Two!'; })
                                ->addItem('Three', function() { print 'Three!'; });
                        });
                });
        })
        ->addItem('Item 2', $itemCallable)
        ->addStaticItem('Item 3 - Static')
        ->addItem('Item 4', $itemCallable);
    })
    ->build();

$menu->open();

Updates README radioStyle -> modifyRadioStyle
Comment on lines +235 to +241
if (!$menu->getCheckboxStyle()->hasChangedFromDefaults()) {
$menu->setCheckboxStyle(clone $this->menu->getCheckboxStyle());
}

if (!$menu->getRadioStyle()->hasChangedFromDefaults()) {
$menu->setRadioStyle(clone $this->menu->getRadioStyle());
}
Copy link
Member Author

Choose a reason for hiding this comment

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

We could extract this to a private method, since we do it below as well. But we can do that later.

Copy link
Member Author

Choose a reason for hiding this comment

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

Above even.

public function __construct(CliMenu $menu)
{
$this->menu = $menu;
$this->splitItem = new SplitItem();

$this->checkboxStyle = new CheckboxStyle();
Copy link
Member Author

Choose a reason for hiding this comment

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

So this seems to be inconsistent with the way CliMenu and CliMenuBuilder work. CliMenu holds the style instances, not the builder. The builder proxies to them. But here the SplitItemBuilder contains the style instances. Can we make it similar to the CliMenuBuilder works?

return $this;
}

public function modifyCheckboxStyle(callable $itemCallable) : self
Copy link
Member Author

@AydinHassan AydinHassan Dec 19, 2019

Choose a reason for hiding this comment

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

I actually think we should drop this. It's took me a while but I think I get what you are doing. If you change the styles in a splititem builder, they persist back to the parent menu. I think it makes the code very confusing. I would rather we just not allow to modify the styles in the SplitItem. Or rather if you modify the styles, it only applies to the split item and not the parent menu.

Copy link
Contributor

Choose a reason for hiding this comment

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

Style is always limited only to the current scope and any children:

<?php

use PhpSchool\CliMenu\Builder\SplitItemBuilder;
use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\Style\CheckboxStyle;

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

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

$menu = (new CliMenuBuilder)
    ->setTitle('Select a Language')
    ->addCheckboxItem('Rust', $itemCallable)
    ->addCheckboxItem('C++', $itemCallable)
    ->addCheckboxItem('Go', $itemCallable)
    ->addCheckboxItem('Java', $itemCallable)
    ->addCheckboxItem('C', $itemCallable)
    ->addSplitItem(function (SplitItemBuilder $b) use ($itemCallable) {
        $b->setGutter(5)
            ->modifyCheckboxStyle(function (CheckboxStyle $style) {
                $style->setMarkerOff('ooo')
                    ->setMarkerOn('xxx');
            })
            ->addCheckboxItem('Rust', $itemCallable)
            ->addCheckboxItem('C++', $itemCallable)
            ->addCheckboxItem('Go', $itemCallable)
            ->addCheckboxItem('Java', $itemCallable)
            ->addCheckboxItem('C', $itemCallable)
        ;
    })
    ->build();

$menu->open();

The parent should never be affected from the modify*Style() methods:

Peek 2019-12-19 16-26

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually you're right, there's a bug where changing in a child updates the parent:

<?php

use PhpSchool\CliMenu\Builder\SplitItemBuilder;
use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\Style\CheckboxStyle;

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

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

$menu = (new CliMenuBuilder)
    ->setTitle('Select a Language')
    ->addCheckboxItem('1-A', $itemCallable)
    ->addCheckboxItem('1-B', $itemCallable)
    ->addSplitItem(function (SplitItemBuilder $b) use ($itemCallable) {
        $b->setGutter(5)
            ->addCheckboxItem('2-A', $itemCallable)
            ->modifyCheckboxStyle(function (CheckboxStyle $style) {
                $style->setMarkerOff('o ')
                    ->setMarkerOn('x ');
            })
            ->addCheckboxItem('2-B', $itemCallable)
            ->addSubMenu('Options', function (CliMenuBuilder $b) use ($itemCallable) {
                $b->setTitle('CLI Menu > Options')
                    ->addCheckboxItem('Rust', $itemCallable)
                    ->addCheckboxItem('C++', $itemCallable)
                    ->addCheckboxItem('Go', $itemCallable)
                    ->addCheckboxItem('Java', $itemCallable)
                    ->addCheckboxItem('C', $itemCallable)
                    ->addLineBreak('-');
            })
            ->addCheckboxItem('2-C', $itemCallable)
            ->addCheckboxItem('2-D', $itemCallable)
            ->addCheckboxItem('2-E', $itemCallable)
        ;
    })
    ->addCheckboxItem('1-C', $itemCallable)
    ->addCheckboxItem('1-D', $itemCallable)
    ->addCheckboxItem('1-E', $itemCallable)
    ->build();

$menu->open();

I'll fix and add a test.

Copy link
Member Author

Choose a reason for hiding this comment

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

Phew 😅 Thought I was going crazy

Copy link
Contributor

Choose a reason for hiding this comment

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

Right, I see, because SplitMenuBuilder::$menu is the exact same instance as CliMenuBuilder::$menu.

This is why SplitMenuBuilder had its own style instances (removed in #208).

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually, I think the problem is that I had a fundamental misunderstanding on the SplitItem.

I was thinking this was a separate menu ala submenu, but it's simply a horizontal partitioner of the current menu.

You're completely right, SplitItemBuilder shouldn't have any of the radio/checkbox style methods, and should not have its own style instance(s).

SplitItemBuilder should reference menu styles
@jtreminio
Copy link
Contributor

jtreminio commented Dec 20, 2019

Please review and merge #210 before this PR.

It is going to be required for this process to work properly, and since there have been a ton of changes and I messed up on the SplitItem styling (#205 (comment)) it's probably best if I create a new PR without all the changes.

@AydinHassan
Copy link
Member Author

@jtreminio #210 is merged now. Thank you. I think these changes should be a lot simpler now.

@jtreminio
Copy link
Contributor

Competing PR at #211

@AydinHassan AydinHassan deleted the item-style branch December 20, 2019 07:28
@AydinHassan AydinHassan restored the item-style branch February 15, 2020 12:08
@AydinHassan AydinHassan deleted the item-style branch February 15, 2020 19:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants