Skip to content

Dialogue feature #49

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
Oct 27, 2016
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
62 changes: 62 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ Check out the [examples](examples) directory and run them to check out what is p
##### Disabled Items & Submenus
<img width="600" alt="submenu" src="https://cloud.githubusercontent.com/assets/2174476/19047849/868fa8c0-899b-11e6-9004-811c8da6d435.png">

##### Flash Dialogue
<img width="600" alt="submenu" src="https://cloud.githubusercontent.com/assets/2817002/19781788/f271c09c-9c82-11e6-87c3-167fd191c705.png">

##### Confirm Dialogue
<img width="600" alt="submenu" src="https://cloud.githubusercontent.com/assets/2817002/19781794/fb8b58c8-9c82-11e6-97ac-8e2eb21e9f7c.png">

### API

The `CliMenu` object is constructed via the Builder class
Expand Down Expand Up @@ -412,6 +418,62 @@ $menu = (new CliMenuBuilder)
$menu->open();
```

#### Dialogues

##### Flash

Show a one line message over the top of the menu. It has a separate style object which is colored by default different
to the menu. It can be modified to suit your own style. The dialogue is dismissed with any key press. In the example
below we change the background color on the flash to green.

```php
use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\CliMenuBuilder;

$itemCallable = function (CliMenu $menu) {
$flash = $menu->flash("PHP School FTW!!");
$flash->getStyle()->setBg('green');
$flash->display();
};

$menu = (new CliMenuBuilder)
->setTitle('Basic CLI Menu')
->addItem('First Item', $itemCallable)
->addItem('Second Item', $itemCallable)
->addItem('Third Item', $itemCallable)
->addLineBreak('-')
->build();

$menu->open();
```

##### Confirm

Prompts are very similar to flashes except that a button is shown which has to be selected to dismiss them. The button
text can be customised.

```php
use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\CliMenuBuilder;

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

$itemCallable = function (CliMenu $menu) {
$menu->confirm('PHP School FTW!')
->display('OK!');
};

$menu = (new CliMenuBuilder)
->setTitle('Basic CLI Menu')
->addItem('First Item', $itemCallable)
->addItem('Second Item', $itemCallable)
->addItem('Third Item', $itemCallable)
->addLineBreak('-')
->build();

$menu->open();
```

---

Once you get going you might just end up with something that looks a little like this...
Expand Down
21 changes: 21 additions & 0 deletions examples/confirm.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\CliMenuBuilder;

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

$itemCallable = function (CliMenu $menu) {
$menu->confirm('PHP School FTW!')
->display('OK');
};

$menu = (new CliMenuBuilder)
->setTitle('Basic CLI Menu')
->addItem('First Item', $itemCallable)
->addItem('Second Item', $itemCallable)
->addItem('Third Item', $itemCallable)
->addLineBreak('-')
->build();

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

use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\CliMenuBuilder;

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

$itemCallable = function (CliMenu $menu) {
$flash = $menu->flash("PHP School FTW!!");
$flash->getStyle()->setBg('green');
$flash->display();
};

$menu = (new CliMenuBuilder)
->setTitle('Basic CLI Menu')
->addItem('First Item', $itemCallable)
->addItem('Second Item', $itemCallable)
->addItem('Third Item', $itemCallable)
->addLineBreak('-')
->build();

$menu->open();
81 changes: 67 additions & 14 deletions src/CliMenu.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
use PhpSchool\CliMenu\MenuItem\LineBreakItem;
use PhpSchool\CliMenu\MenuItem\MenuItemInterface;
use PhpSchool\CliMenu\MenuItem\StaticItem;
use PhpSchool\CliMenu\Dialogue\Confirm;
use PhpSchool\CliMenu\Dialogue\Flash;
use PhpSchool\CliMenu\Terminal\TerminalFactory;
use PhpSchool\CliMenu\Terminal\TerminalInterface;
use PhpSchool\CliMenu\Util\StringUtil as s;
Expand Down Expand Up @@ -55,6 +57,11 @@ class CliMenu
*/
protected $parent;

/**
* @var Frame|null
*/
private $currentFrame;

/**
* @param string $title
* @param array $items
Expand Down Expand Up @@ -258,28 +265,37 @@ protected function draw()
$this->terminal->clean();
$this->terminal->moveCursorToTop();

echo "\n\n";
$frame = new Frame;

$frame->newLine(2);

if (is_string($this->title)) {
$this->drawMenuItem(new LineBreakItem());
$this->drawMenuItem(new StaticItem($this->title));
$this->drawMenuItem(new LineBreakItem($this->style->getTitleSeparator()));
$frame->addRows($this->drawMenuItem(new LineBreakItem()));
$frame->addRows($this->drawMenuItem(new StaticItem($this->title)));
$frame->addRows($this->drawMenuItem(new LineBreakItem($this->style->getTitleSeparator())));
}

array_map(function ($item, $index) {
$this->drawMenuItem($item, $index === $this->selectedItem);
array_map(function ($item, $index) use ($frame) {
$frame->addRows($this->drawMenuItem($item, $index === $this->selectedItem));
}, $this->items, array_keys($this->items));

$this->drawMenuItem(new LineBreakItem());
$frame->addRows($this->drawMenuItem(new LineBreakItem()));

$frame->newLine(2);

foreach ($frame->getRows() as $row) {
echo $row;
}

echo "\n\n";
$this->currentFrame = $frame;
}

/**
* Draw a menu item
*
* @param MenuItemInterface $item
* @param bool|false $selected
* @return array
*/
protected function drawMenuItem(MenuItemInterface $item, $selected = false)
{
Expand All @@ -293,9 +309,9 @@ protected function drawMenuItem(MenuItemInterface $item, $selected = false)
? $this->style->getSelectedUnsetCode()
: $this->style->getUnselectedUnsetCode();

foreach ($rows as $row) {
echo sprintf(
"%s%s%s%s%s%s%s",
return array_map(function ($row) use ($setColour, $unsetColour) {
return sprintf(
"%s%s%s%s%s%s%s\n\r",
str_repeat(' ', $this->style->getMargin()),
$setColour,
str_repeat(' ', $this->style->getPadding()),
Expand All @@ -304,9 +320,7 @@ protected function drawMenuItem(MenuItemInterface $item, $selected = false)
$unsetColour,
str_repeat(' ', $this->style->getMargin())
);

echo "\n\r";
}
}, $rows);
}

/**
Expand Down Expand Up @@ -379,4 +393,43 @@ public function getStyle()
{
return $this->style;
}

public function getCurrentFrame()
{
return $this->currentFrame;
}

/**
* @param string $text
* @return Flash
*/
public function flash($text)
{
if (strpos($text, "\n") !== false) {
throw new \InvalidArgumentException;
}

$style = (new MenuStyle($this->terminal))
->setBg('yellow')
Copy link
Member

Choose a reason for hiding this comment

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

We should probably make this customizable (one for a minor release later though imo, unless it would be a BC break)

Copy link
Member Author

Choose a reason for hiding this comment

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

You can grab the style from the Flash object and change it before you call display :). Checkout the example 😄

Copy link
Member

Choose a reason for hiding this comment

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

of course ... that didn't click .. nice!

->setFg('red');

return new Flash($this, $style, $this->terminal, $text);
}

/**
* @param string $text
* @return Confirm
*/
public function confirm($text)
{
if (strpos($text, "\n") !== false) {
throw new \InvalidArgumentException;
}

$style = (new MenuStyle($this->terminal))
->setBg('yellow')
->setFg('red');

return new Confirm($this, $style, $this->terminal, $text);
}
}
81 changes: 81 additions & 0 deletions src/Dialogue/Confirm.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php

namespace PhpSchool\CliMenu\Dialogue;

/**
* @author Aydin Hassan <[email protected]>
*/
class Confirm extends Dialogue
{

/**
* Display confirmation with a button with the given text
*
* @param string $confirmText
*/
public function display($confirmText = 'OK')
{
$this->assertMenuOpen();

$this->terminal->moveCursorToRow($this->y);

$promptWidth = mb_strlen($this->text) + 4;

$this->emptyRow();

$this->write(sprintf(
"%s %s %s\n",
$this->style->getUnselectedSetCode(),
$this->text,
$this->style->getUnselectedUnsetCode()
));

$this->emptyRow();

$confirmText = sprintf(' < %s > ', $confirmText);
$leftFill = ($promptWidth / 2) - (mb_strlen($confirmText) / 2);

$this->write(sprintf(
'%s%s%s',
$this->style->getUnselectedSetCode(),
str_repeat(' ', $leftFill),
$this->style->getUnselectedSetCode()
));

$this->write(
Copy link
Member

Choose a reason for hiding this comment

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

Should we be handling long messages, e.g. wrap over multiple lines like we do with the menu items?

Copy link
Member Author

Choose a reason for hiding this comment

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

ATM - we only allow one line message and long message won't wrap - it was a bit hard for the calculating logic as I was rushing. We can add this in the future with a bit more time without breaking BC.

Copy link
Member

Choose a reason for hiding this comment

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

yeah no worries sounds good to me. it would complicate centering height etc too so a nice little challenge in the future

sprintf(
'%s%s%s',
$this->style->getSelectedSetCode(),
$confirmText,
$this->style->getSelectedUnsetCode()
),
-1
);

$this->write(
sprintf(
"%s%s%s\n",
$this->style->getUnselectedSetCode(),
str_repeat(' ', ceil($promptWidth - $leftFill - mb_strlen($confirmText))),
$this->style->getSelectedUnsetCode()
),
-1
);

$this->write(sprintf(
"%s %s %s\n",
$this->style->getUnselectedSetCode(),
str_repeat(' ', mb_strlen($this->text)),
$this->style->getUnselectedUnsetCode()
));

$this->terminal->moveCursorToTop();
$input = $this->terminal->getKeyedInput();

while ($input !== 'enter') {
$input = $this->terminal->getKeyedInput();
}

$this->parentMenu->redraw();
}
}
Loading