Skip to content

Commit d7bebfd

Browse files
authored
Merge pull request #100 from Lynesth/patch-14
Add border styling
2 parents 761de53 + cfa7953 commit d7bebfd

File tree

6 files changed

+458
-10
lines changed

6 files changed

+458
-10
lines changed

examples/custom-styles.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
->setForegroundColour('black')
2020
->setPadding(4)
2121
->setMargin(4)
22+
->setBorder(1, 2, 'red')
2223
->setUnselectedMarker(' ')
2324
->setSelectedMarker('>')
2425
->setTitleSeparator('- ')

src/CliMenu.php

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,10 @@ protected function draw() : void
320320

321321
$frame->newLine(2);
322322

323+
if ($this->style->getBorderTopWidth() > 0) {
324+
$frame->addRows($this->style->getBorderTopRows());
325+
}
326+
323327
if ($this->title) {
324328
$frame->addRows($this->drawMenuItem(new LineBreakItem()));
325329
$frame->addRows($this->drawMenuItem(new StaticItem($this->title)));
@@ -331,6 +335,10 @@ protected function draw() : void
331335
}, $this->items, array_keys($this->items));
332336

333337
$frame->addRows($this->drawMenuItem(new LineBreakItem()));
338+
339+
if ($this->style->getBorderBottomWidth() > 0) {
340+
$frame->addRows($this->style->getBorderBottomRows());
341+
}
334342

335343
$frame->newLine(2);
336344

@@ -359,15 +367,26 @@ protected function drawMenuItem(MenuItemInterface $item, bool $selected = false)
359367
? $this->style->getInvertedColoursSetCode()
360368
: '';
361369

362-
return array_map(function ($row) use ($setColour, $invertedColour, $resetColour) {
370+
if ($this->style->getBorderLeftWidth() || $this->style->getBorderRightWidth()) {
371+
$borderColour = $this->style->getBorderColourCode();
372+
} else {
373+
$borderColour = '';
374+
}
375+
376+
return array_map(function ($row) use ($setColour, $invertedColour, $resetColour, $borderColour) {
363377
return sprintf(
364-
"%s%s%s%s%s%s%s%s\n",
378+
"%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
365379
str_repeat(' ', $this->style->getMargin()),
380+
$borderColour,
381+
str_repeat(' ', $this->style->getBorderLeftWidth()),
366382
$setColour,
367383
$invertedColour,
368384
str_repeat(' ', $this->style->getPadding()),
369385
$row,
370386
str_repeat(' ', $this->style->getRightHandPadding(mb_strlen(s::stripAnsiEscapeSequence($row)))),
387+
$this->style->getInvertedColoursUnsetCode(),
388+
$borderColour,
389+
str_repeat(' ', $this->style->getBorderRightWidth()),
371390
$resetColour,
372391
str_repeat(' ', $this->style->getMargin())
373392
);

src/CliMenuBuilder.php

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,39 @@ public function setTitleSeparator(string $separator) : self
280280
return $this;
281281
}
282282

283+
public function setBorder(
284+
int $topWidth,
285+
$rightWidth = null,
286+
$bottomWidth = null,
287+
$leftWidth = null,
288+
string $colour = null
289+
) : self {
290+
if (!is_int($rightWidth)) {
291+
$colour = $rightWidth;
292+
$rightWidth = $bottomWidth = $leftWidth = $topWidth;
293+
} elseif (!is_int($bottomWidth)) {
294+
$colour = $bottomWidth;
295+
$bottomWidth = $topWidth;
296+
$leftWidth = $rightWidth;
297+
} elseif (!is_int($leftWidth)) {
298+
$colour = $leftWidth;
299+
$leftWidth = $rightWidth;
300+
}
301+
302+
$this->style['borderTopWidth'] = $topWidth;
303+
$this->style['borderRightWidth'] = $rightWidth;
304+
$this->style['borderBottomWidth'] = $bottomWidth;
305+
$this->style['borderLeftWidth'] = $leftWidth;
306+
307+
if (is_string($colour)) {
308+
$this->style['borderColour'] = $colour;
309+
} elseif ($colour !== null) {
310+
throw new \InvalidArgumentException('Invalid colour');
311+
}
312+
313+
return $this;
314+
}
315+
283316
public function setTerminal(Terminal $terminal) : self
284317
{
285318
$this->terminal = $terminal;
@@ -344,7 +377,12 @@ private function buildStyle() : MenuStyle
344377
->setUnselectedMarker($this->style['unselectedMarker'])
345378
->setItemExtra($this->style['itemExtra'])
346379
->setDisplaysExtra($this->style['displaysExtra'])
347-
->setTitleSeparator($this->style['titleSeparator']);
380+
->setTitleSeparator($this->style['titleSeparator'])
381+
->setBorderTopWidth($this->style['borderTopWidth'])
382+
->setBorderRightWidth($this->style['borderRightWidth'])
383+
->setBorderBottomWidth($this->style['borderBottomWidth'])
384+
->setBorderLeftWidth($this->style['borderLeftWidth'])
385+
->setBorderColour($this->style['borderColour']);
348386

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

src/MenuStyle.php

Lines changed: 202 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,41 @@ class MenuStyle
9494
*/
9595
private $coloursResetCode = "\033[0m";
9696

97+
/**
98+
* @var int
99+
*/
100+
private $borderTopWidth;
101+
102+
/**
103+
* @var int
104+
*/
105+
private $borderRightWidth;
106+
107+
/**
108+
* @var int
109+
*/
110+
private $borderBottomWidth;
111+
112+
/**
113+
* @var int
114+
*/
115+
private $borderLeftWidth;
116+
117+
/**
118+
* @var string
119+
*/
120+
private $borderColour = 'white';
121+
122+
/**
123+
* @var array
124+
*/
125+
private $borderTopRows = [];
126+
127+
/**
128+
* @var array
129+
*/
130+
private $borderBottomRows = [];
131+
97132
/**
98133
* @var bool
99134
*/
@@ -115,6 +150,11 @@ class MenuStyle
115150
'itemExtra' => '',
116151
'displaysExtra' => false,
117152
'titleSeparator' => '=',
153+
'borderTopWidth' => 0,
154+
'borderRightWidth' => 0,
155+
'borderBottomWidth' => 0,
156+
'borderLeftWidth' => 0,
157+
'borderColour' => 'white',
118158
'marginAuto' => false,
119159
];
120160

@@ -185,6 +225,11 @@ public function __construct(Terminal $terminal = null)
185225
$this->setItemExtra(static::$defaultStyleValues['itemExtra']);
186226
$this->setDisplaysExtra(static::$defaultStyleValues['displaysExtra']);
187227
$this->setTitleSeparator(static::$defaultStyleValues['titleSeparator']);
228+
$this->setBorderTopWidth(static::$defaultStyleValues['borderTopWidth']);
229+
$this->setBorderRightWidth(static::$defaultStyleValues['borderRightWidth']);
230+
$this->setBorderBottomWidth(static::$defaultStyleValues['borderBottomWidth']);
231+
$this->setBorderLeftWidth(static::$defaultStyleValues['borderLeftWidth']);
232+
$this->setBorderColour(static::$defaultStyleValues['borderColour']);
188233
}
189234

190235
public function getDisabledItemText(string $text) : string
@@ -254,7 +299,9 @@ public function getColoursResetCode() : string
254299
*/
255300
protected function calculateContentWidth() : void
256301
{
257-
$this->contentWidth = $this->width - ($this->padding * 2);
302+
$this->contentWidth = $this->width
303+
- ($this->padding * 2)
304+
- ($this->borderRightWidth + $this->borderLeftWidth);
258305
}
259306

260307
public function getFg()
@@ -306,7 +353,9 @@ public function setWidth(int $width) : self
306353
if ($this->marginAuto) {
307354
$this->setMarginAuto();
308355
}
356+
309357
$this->calculateContentWidth();
358+
$this->generateBorderRows();
310359

311360
return $this;
312361
}
@@ -334,7 +383,9 @@ public function setMarginAuto() : self
334383
{
335384
$this->marginAuto = true;
336385
$this->margin = floor(($this->terminal->getWidth() - $this->width) / 2);
337-
386+
387+
$this->generateBorderRows();
388+
338389
return $this;
339390
}
340391

@@ -343,6 +394,8 @@ public function setMargin(int $margin) : self
343394
$this->marginAuto = false;
344395
$this->margin = $margin;
345396

397+
$this->generateBorderRows();
398+
346399
return $this;
347400
}
348401

@@ -426,4 +479,151 @@ public function setTitleSeparator(string $actionSeparator) : self
426479

427480
return $this;
428481
}
482+
483+
private function generateBorderRows() : void
484+
{
485+
$borderRow = sprintf(
486+
"%s%s%s%s%s\n",
487+
str_repeat(' ', $this->margin),
488+
$this->getBorderColourCode(),
489+
str_repeat(' ', $this->width),
490+
$this->coloursResetCode,
491+
str_repeat(' ', $this->margin)
492+
);
493+
494+
$this->borderTopRows = array_fill(0, $this->borderTopWidth, $borderRow);
495+
$this->borderBottomRows = array_fill(0, $this->borderBottomWidth, $borderRow);
496+
}
497+
498+
public function getBorderTopRows() : array
499+
{
500+
return $this->borderTopRows;
501+
}
502+
503+
public function getBorderBottomRows() : array
504+
{
505+
return $this->borderBottomRows;
506+
}
507+
508+
/**
509+
* Shorthand function to set all borders values at once
510+
*/
511+
public function setBorder(
512+
int $topWidth,
513+
$rightWidth = null,
514+
$bottomWidth = null,
515+
$leftWidth = null,
516+
string $colour = null
517+
) : self {
518+
if (!is_int($rightWidth)) {
519+
$colour = $rightWidth;
520+
$rightWidth = $bottomWidth = $leftWidth = $topWidth;
521+
} elseif (!is_int($bottomWidth)) {
522+
$colour = $bottomWidth;
523+
$bottomWidth = $topWidth;
524+
$leftWidth = $rightWidth;
525+
} elseif (!is_int($leftWidth)) {
526+
$colour = $leftWidth;
527+
$leftWidth = $rightWidth;
528+
}
529+
530+
$this->borderTopWidth = $topWidth;
531+
$this->borderRightWidth = $rightWidth;
532+
$this->borderBottomWidth = $bottomWidth;
533+
$this->borderLeftWidth = $leftWidth;
534+
535+
if (is_string($colour)) {
536+
$this->setBorderColour($colour);
537+
} elseif ($colour !== null) {
538+
throw new \InvalidArgumentException('Invalid colour');
539+
}
540+
541+
$this->calculateContentWidth();
542+
$this->generateBorderRows();
543+
544+
return $this;
545+
}
546+
547+
public function setBorderTopWidth(int $width) : self
548+
{
549+
$this->borderTopWidth = $width;
550+
551+
$this->generateBorderRows();
552+
553+
return $this;
554+
}
555+
556+
public function setBorderRightWidth(int $width) : self
557+
{
558+
$this->borderRightWidth = $width;
559+
$this->calculateContentWidth();
560+
561+
return $this;
562+
}
563+
564+
public function setBorderBottomWidth(int $width) : self
565+
{
566+
$this->borderBottomWidth = $width;
567+
568+
$this->generateBorderRows();
569+
570+
return $this;
571+
}
572+
573+
public function setBorderLeftWidth(int $width) : self
574+
{
575+
$this->borderLeftWidth = $width;
576+
$this->calculateContentWidth();
577+
578+
return $this;
579+
}
580+
581+
public function setBorderColour(string $colour, $fallback = null) : self
582+
{
583+
$this->borderColour = ColourUtil::validateColour(
584+
$this->terminal,
585+
$colour,
586+
$fallback
587+
);
588+
589+
$this->generateBorderRows();
590+
591+
return $this;
592+
}
593+
594+
public function getBorderTopWidth() : int
595+
{
596+
return $this->borderTopWidth;
597+
}
598+
599+
public function getBorderRightWidth() : int
600+
{
601+
return $this->borderRightWidth;
602+
}
603+
604+
public function getBorderBottomWidth() : int
605+
{
606+
return $this->borderBottomWidth;
607+
}
608+
609+
public function getBorderLeftWidth() : int
610+
{
611+
return $this->borderLeftWidth;
612+
}
613+
614+
public function getBorderColour() : string
615+
{
616+
return $this->borderColour;
617+
}
618+
619+
public function getBorderColourCode() : string
620+
{
621+
if (!ctype_digit($this->borderColour)) {
622+
$borderColourCode = self::$availableBackgroundColors[$this->borderColour];
623+
} else {
624+
$borderColourCode = sprintf("48;5;%s", $this->borderColour);
625+
}
626+
627+
return sprintf("\033[%sm", $borderColourCode);
628+
}
429629
}

0 commit comments

Comments
 (0)