Skip to content
25 changes: 25 additions & 0 deletions examples/basic-centered.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

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

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

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

$menu = (new CliMenuBuilder)
->setTitle('Basic CLI Menu')
->addItem('First Item', $itemCallable)
->addItem('Make menu wider', function (CliMenu $menu) {
$menu->getStyle()->setWidth($menu->getStyle()->getWidth() + 10);
$menu->redraw();
})
->addItem('Third Item', $itemCallable)
->addLineBreak('-')
->setWidth(70)
->setMarginAuto()
->build();

$menu->open();
17 changes: 15 additions & 2 deletions src/CliMenuBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,18 @@ public function setPadding(int $padding) : self
return $this;
}

public function setMarginAuto() : self
{
$this->style['marginAuto'] = true;

return $this;
}

public function setMargin(int $margin) : self
{
Assertion::greaterOrEqualThan($margin, 0);

$this->style['marginAuto'] = false;
$this->style['margin'] = $margin;

return $this;
Expand Down Expand Up @@ -320,17 +330,20 @@ private function getMenuStyle() : MenuStyle

private function buildStyle() : MenuStyle
{
return (new MenuStyle($this->terminal))
$style = (new MenuStyle($this->terminal))
->setFg($this->style['fg'])
->setBg($this->style['bg'])
->setWidth($this->style['width'])
->setPadding($this->style['padding'])
->setMargin($this->style['margin'])
->setSelectedMarker($this->style['selectedMarker'])
->setUnselectedMarker($this->style['unselectedMarker'])
->setItemExtra($this->style['itemExtra'])
->setDisplaysExtra($this->style['displaysExtra'])
->setTitleSeparator($this->style['titleSeparator']);

$this->style['marginAuto'] ? $style->setMarginAuto() : $style->setMargin($this->style['margin']);

return $style;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Dialogue/Dialogue.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ protected function calculateCoordinates() : void
//x
$parentStyle = $this->parentMenu->getStyle();
$dialogueHalfLength = (mb_strlen($this->text) + ($this->style->getPadding() * 2)) / 2;
$widthHalfLength = ceil($parentStyle->getWidth() / 2);
$widthHalfLength = ceil($parentStyle->getWidth() / 2 + $parentStyle->getMargin());
$this->x = $widthHalfLength - $dialogueHalfLength;
}

Expand Down
2 changes: 1 addition & 1 deletion src/Input/InputIO.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ private function calculateXPosition(Input $input, string $userInput) : int

$parentStyle = $this->parentMenu->getStyle();
$halfWidth = ($width + ($input->getStyle()->getPadding() * 2)) / 2;
$parentHalfWidth = ceil($parentStyle->getWidth() / 2);
$parentHalfWidth = ceil($parentStyle->getWidth() / 2 + $parentStyle->getMargin());

return $parentHalfWidth - $halfWidth;
}
Expand Down
28 changes: 21 additions & 7 deletions src/MenuStyle.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ class MenuStyle
*/
private $titleSeparator;

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

/**
* Default Values
*
Expand All @@ -89,6 +94,7 @@ class MenuStyle
'itemExtra' => '✔',
'displaysExtra' => false,
'titleSeparator' => '=',
'marginAuto' => false,
];

public static function getDefaultStyleValues() : array
Expand Down Expand Up @@ -233,7 +239,7 @@ public function getUnselectedUnsetCode() : string
*/
protected function calculateContentWidth() : void
{
$this->contentWidth = $this->width - ($this->padding*2) - ($this->margin*2);
$this->contentWidth = $this->width - ($this->padding * 2);
}

public function getFg() : string
Expand Down Expand Up @@ -267,13 +273,14 @@ public function getWidth() : int

public function setWidth(int $width) : self
{
$availableWidth = $this->terminal->getWidth() - ($this->margin * 2) - ($this->padding * 2);

if ($width >= $availableWidth) {
$width = $availableWidth;
if ($width >= $this->terminal->getWidth()) {
$width = $this->terminal->getWidth();
}

$this->width = $width;
if ($this->marginAuto) {
$this->setMarginAuto();
}
$this->calculateContentWidth();

return $this;
Expand All @@ -298,12 +305,19 @@ public function getMargin() : int
return $this->margin;
}

public function setMarginAuto() : self
{
$this->marginAuto = true;
$this->margin = floor(($this->terminal->getWidth() - $this->width) / 2);

return $this;
}

public function setMargin(int $margin) : self
{
$this->marginAuto = false;
$this->margin = $margin;

$this->calculateContentWidth();

return $this;
}

Expand Down
87 changes: 87 additions & 0 deletions test/CliMenuBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,93 @@ public function testThrowsExceptionWhenDisablingRootMenu() : void

(new CliMenuBuilder)->disableMenu();
}

/**
* @dataProvider marginBelowZeroProvider
*/
public function testSetMarginThrowsExceptionIfValueIsNotZeroOrAbove(int $value) : void
{
self::expectException(\Assert\InvalidArgumentException::class);


(new CliMenuBuilder)->setMargin($value);
}

public function marginBelowZeroProvider() : array
{
return [[-1], [-2], [-10]];
}

/**
* @dataProvider marginAboveZeroProvider
*/
public function testSetMarginAcceptsZeroAndPositiveIntegers(int $value) : void
{
$menu = (new CliMenuBuilder)->setMargin($value)->build();

self::assertSame($value, $menu->getStyle()->getMargin());
}

public function marginAboveZeroProvider() : array
{
return [[0], [1], [10], [50]];
}

public function testSetMarginAutoAutomaticallyCalculatesMarginToCenter() : void
{
$terminal = self::createMock(Terminal::class);
$terminal
->expects($this->any())
->method('getWidth')
->will($this->returnValue(200));

$builder = new CliMenuBuilder;
$menu = $builder
->setTerminal($terminal)
->setMarginAuto()
->setWidth(100)
->build();

self::assertSame(50, $menu->getStyle()->getMargin());
}

public function testSetMarginAutoOverwritesSetMargin() : void
{
$terminal = self::createMock(Terminal::class);
$terminal
->expects($this->any())
->method('getWidth')
->will($this->returnValue(200));

$builder = new CliMenuBuilder;
$menu = $builder
->setTerminal($terminal)
->setMargin(10)
->setMarginAuto()
->setWidth(100)
->build();

self::assertSame(50, $menu->getStyle()->getMargin());
}

public function testSetMarginManuallyOverwritesSetMarginAuto() : void
{
$terminal = self::createMock(Terminal::class);
$terminal
->expects($this->any())
->method('getWidth')
->will($this->returnValue(200));

$builder = new CliMenuBuilder;
$menu = $builder
->setTerminal($terminal)
->setMarginAuto()
->setMargin(10)
->setWidth(100)
->build();

self::assertSame(10, $menu->getStyle()->getMargin());
}

private function checkItems(CliMenu $menu, array $expected) : void
{
Expand Down
2 changes: 1 addition & 1 deletion test/CliMenuTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public function setUp()

$this->terminal->expects($this->any())
->method('getWidth')
->willReturn(50);
->willReturn(46);

$this->terminal->expects($this->any())
->method('write')
Expand Down
2 changes: 1 addition & 1 deletion test/Dialogue/ConfirmTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public function setUp()

$this->terminal->expects($this->any())
->method('getWidth')
->willReturn(50);
->willReturn(46);

$this->terminal->expects($this->any())
->method('write')
Expand Down
2 changes: 1 addition & 1 deletion test/Dialogue/FlashTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public function setUp()

$this->terminal->expects($this->any())
->method('getWidth')
->willReturn(50);
->willReturn(46);

$this->terminal->expects($this->any())
->method('write')
Expand Down
44 changes: 42 additions & 2 deletions test/MenuStyleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ public function testWidthCalculation() : void
$style->setPadding(5);
$style->setMargin(5);

static::assertSame(280, $style->getContentWidth());
static::assertSame(290, $style->getContentWidth());
}

public function testRightHandPaddingCalculation() : void
Expand All @@ -171,6 +171,46 @@ public function testRightHandPaddingCalculation() : void
$style->setPadding(5);
$style->setMargin(5);

static::assertSame(235, $style->getRightHandPadding(50));
static::assertSame(245, $style->getRightHandPadding(50));
}

public function testMargin() : void
{
$style = $this->getMenuStyle();

$style->setWidth(300);
$style->setPadding(5);
$style->setMargin(5);

self::assertSame(5, $style->getMargin());
}

public function testMarginAutoCenters() : void
{
$style = $this->getMenuStyle();

$style->setWidth(300);
$style->setPadding(5);
$style->setMarginAuto();

self::assertSame(100, $style->getMargin());
self::assertSame(290, $style->getContentWidth());
}

public function testModifyWithWhenMarginAutoIsEnabledRecalculatesMargin() : void
{
$style = $this->getMenuStyle();

$style->setWidth(300);
$style->setPadding(5);
$style->setMarginAuto();

self::assertSame(100, $style->getMargin());
self::assertSame(290, $style->getContentWidth());

$style->setWidth(400);

self::assertSame(50, $style->getMargin());
self::assertSame(390, $style->getContentWidth());
}
}