44
55use PhpSchool \CliMenu \Terminal \TerminalFactory ;
66use PhpSchool \CliMenu \Util \ColourUtil ;
7+ use PhpSchool \CliMenu \Util \StringUtil as s ;
78use PhpSchool \Terminal \Terminal ;
89use Assert \Assertion ;
910
@@ -30,23 +31,31 @@ class MenuStyle
3031 protected $ bg ;
3132
3233 /**
34+ * The width of the menu. Including borders and padding.
35+ * Does not include margin.
36+ *
37+ * May not be the value that was requested in the
38+ * circumstance that the terminal is smaller then the
39+ * requested width.
40+ *
3341 * @var int
3442 */
3543 protected $ width ;
3644
3745 /**
38- * In case the menu is wider than the terminal
39- * The value that we originally shrunk it to
40- * (the width of the terminal)
46+ * In case the requested width is wider than the terminal
47+ * then we shrink the width to fit the terminal. We keep
48+ * the requested size in case the margins are changed and
49+ * we need to recalculate the width.
4150 *
42- * @var bool
51+ * @var int
4352 */
44- private $ widthShrunkTo ;
53+ private $ requestedWidth ;
4554
4655 /**
4756 * @var int
4857 */
49- protected $ margin ;
58+ protected $ margin = 0 ;
5059
5160 /**
5261 * @var int
@@ -143,6 +152,11 @@ class MenuStyle
143152 */
144153 private $ marginAuto = false ;
145154
155+ /**
156+ * @var bool
157+ */
158+ private $ debugMode = false ;
159+
146160 /**
147161 * Default Values
148162 *
@@ -255,10 +269,10 @@ public function hasChangedFromDefaults() : bool
255269 ];
256270
257271 $ defaultStyleValues = self ::$ defaultStyleValues ;
258- if ($ this ->widthShrunkTo ) {
259- $ defaultStyleValues ['width ' ] = $ this ->widthShrunkTo ;
272+ if ($ this ->width !== $ this -> requestedWidth ) {
273+ $ defaultStyleValues ['width ' ] = $ this ->width ;
260274 }
261-
275+
262276 return $ currentValues !== array_values ($ defaultStyleValues );
263277 }
264278
@@ -326,13 +340,14 @@ public function getColoursResetCode() : string
326340
327341 /**
328342 * Calculate the contents width
343+ *
344+ * The content width is menu width minus borders and padding.
329345 */
330346 protected function calculateContentWidth () : void
331347 {
332348 $ this ->contentWidth = $ this ->width
333349 - ($ this ->paddingLeftRight * 2 )
334- - ($ this ->borderRightWidth + $ this ->borderLeftWidth )
335- - $ this ->margin ;
350+ - ($ this ->borderRightWidth + $ this ->borderLeftWidth );
336351
337352 if ($ this ->contentWidth < 0 ) {
338353 $ this ->contentWidth = 0 ;
@@ -384,14 +399,12 @@ public function setWidth(int $width) : self
384399 {
385400 Assertion::greaterOrEqualThan ($ width , 0 );
386401
387- if ($ width >= $ this ->terminal ->getWidth ()) {
388- $ width = $ this ->terminal ->getWidth ();
389- $ this ->widthShrunkTo = $ width ;
390- }
402+ $ this ->requestedWidth = $ width ;
403+ $ width = $ this ->maybeShrinkWidth ($ this ->margin , $ width );
391404
392405 $ this ->width = $ width ;
393406 if ($ this ->marginAuto ) {
394- $ this ->setMarginAuto ( );
407+ $ this ->calculateMarginAuto ( $ width );
395408 }
396409
397410 $ this ->calculateContentWidth ();
@@ -401,6 +414,15 @@ public function setWidth(int $width) : self
401414 return $ this ;
402415 }
403416
417+ private function maybeShrinkWidth (int $ margin , int $ width ) : int
418+ {
419+ if ($ width + $ margin >= $ this ->terminal ->getWidth ()) {
420+ $ width = $ this ->terminal ->getWidth () - $ margin ;
421+ }
422+
423+ return $ width ;
424+ }
425+
404426 public function getPaddingTopBottom () : int
405427 {
406428 return $ this ->paddingTopBottom ;
@@ -421,7 +443,7 @@ private function generatePaddingTopBottomRows() : void
421443
422444 $ paddingRow = sprintf (
423445 "%s%s%s%s%s%s%s%s%s%s \n" ,
424- str_repeat (' ' , $ this ->margin ),
446+ $ this -> debugMode ? $ this -> getDebugString ( $ this -> margin ) : str_repeat (' ' , $ this ->margin ),
425447 $ borderColour ,
426448 str_repeat (' ' , $ this ->borderLeftWidth ),
427449 $ this ->getColoursSetCode (),
@@ -433,6 +455,15 @@ private function generatePaddingTopBottomRows() : void
433455 $ this ->coloursResetCode
434456 );
435457
458+
459+ if ($ this ->debugMode && s::length ($ paddingRow ) <= $ this ->terminal ->getWidth ()) {
460+ $ paddingRow = substr_replace (
461+ $ paddingRow ,
462+ sprintf ("%s \n" , $ this ->getDebugString ($ this ->terminal ->getWidth () - (s::length ($ paddingRow ) - 1 ))),
463+ -1
464+ );
465+ }
466+
436467 $ this ->paddingTopBottomRows = array_fill (0 , $ this ->paddingTopBottom , $ paddingRow );
437468 }
438469
@@ -485,24 +516,28 @@ public function getMargin() : int
485516 public function setMarginAuto () : self
486517 {
487518 $ this ->marginAuto = true ;
488- $ this ->margin = ( int ) floor (( $ this -> terminal -> getWidth () - $ this -> width ) / 2 ) ;
519+ $ this ->margin = 0 ;
489520
490- $ this ->generateBorderRows ();
491- $ this ->generatePaddingTopBottomRows ();
521+ $ this ->setWidth ($ this ->requestedWidth );
492522
493523 return $ this ;
494524 }
495525
526+ private function calculateMarginAuto (int $ width ) : void
527+ {
528+ $ this ->margin = (int ) floor (($ this ->terminal ->getWidth () - ($ width )) / 2 );
529+ }
530+
496531 public function setMargin (int $ margin ) : self
497532 {
498533 Assertion::greaterOrEqualThan ($ margin , 0 );
499534
500535 $ this ->marginAuto = false ;
501536 $ this ->margin = $ margin ;
502537
503- $ this -> calculateContentWidth ();
504- $ this -> generateBorderRows ();
505- $ this ->generatePaddingTopBottomRows ( );
538+ //margin + width may now exceed terminal size
539+ //so set width again to trigger width check + maybe resize
540+ $ this ->setWidth ( $ this -> requestedWidth );
506541
507542 return $ this ;
508543 }
@@ -566,12 +601,20 @@ private function generateBorderRows() : void
566601 {
567602 $ borderRow = sprintf (
568603 "%s%s%s%s \n" ,
569- str_repeat (' ' , $ this ->margin ),
604+ $ this -> debugMode ? $ this -> getDebugString ( $ this -> margin ) : str_repeat (' ' , $ this ->margin ),
570605 $ this ->getBorderColourCode (),
571- str_repeat (' ' , $ this ->width - $ this -> margin ),
572- $ this ->coloursResetCode
606+ str_repeat (' ' , $ this ->width ),
607+ $ this ->getColoursResetCode ()
573608 );
574609
610+ if ($ this ->debugMode && s::length ($ borderRow ) <= $ this ->terminal ->getWidth ()) {
611+ $ borderRow = substr_replace (
612+ $ borderRow ,
613+ sprintf ("%s \n" , $ this ->getDebugString ($ this ->terminal ->getWidth () - (s::length ($ borderRow ) - 1 ))),
614+ -1
615+ );
616+ }
617+
575618 $ this ->borderTopRows = array_fill (0 , $ this ->borderTopWidth , $ borderRow );
576619 $ this ->borderBottomRows = array_fill (0 , $ this ->borderBottomWidth , $ borderRow );
577620 }
@@ -713,4 +756,22 @@ public function getBorderColourCode() : string
713756
714757 return sprintf ("\033[%sm " , $ borderColourCode );
715758 }
759+
760+ /**
761+ * Get a string of given length consisting of 0-9
762+ * eg $length = 15 : 012345678901234
763+ */
764+ private function getDebugString (int $ length ) : string
765+ {
766+ $ nums = [];
767+ for ($ i = 0 , $ j = 0 ; $ i < $ length ; $ i ++, $ j ++) {
768+ if ($ j === 10 ) {
769+ $ j = 0 ;
770+ }
771+
772+ $ nums [] = $ j ;
773+ }
774+
775+ return implode ('' , $ nums );
776+ }
716777}
0 commit comments