Completed
Push — master ( 06534f...3f2ab1 )
by Aydin
11s
created

MenuStyle::generateColoursSetCode()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 10
nc 4
nop 0
1
<?php
2
3
namespace PhpSchool\CliMenu;
4
5
use PhpSchool\CliMenu\Exception\InvalidInstantiationException;
6
use PhpSchool\CliMenu\Terminal\TerminalFactory;
7
use PhpSchool\CliMenu\Util\ColourUtil;
8
use PhpSchool\Terminal\Terminal;
9
10
//TODO: B/W fallback
11
12
/**
13
 * @author Michael Woodward <[email protected]>
14
 */
15
class MenuStyle
16
{
17
    /**
18
     * @var Terminal
19
     */
20
    protected $terminal;
21
22
    /**
23
     * @var int|string
24
     */
25
    protected $fg;
26
27
    /**
28
     * @var int|string
29
     */
30
    protected $bg;
31
32
    /**
33
     * @var int
34
     */
35
    protected $width;
36
37
    /**
38
     * @var int
39
     */
40
    protected $padding;
41
42
    /**
43
     * @var int
44
     */
45
    protected $margin;
46
47
    /**
48
     * @var int
49
     */
50
    protected $contentWidth;
51
52
    /**
53
     * @var string
54
     */
55
    private $selectedMarker;
56
57
    /**
58
     * @var string
59
     */
60
    private $unselectedMarker;
61
62
    /**
63
     * @var string
64
     */
65
    private $itemExtra;
66
67
    /**
68
     * @var bool
69
     */
70
    private $displaysExtra;
71
72
    /**
73
     * @var string
74
     */
75
    private $titleSeparator;
76
77
    /**
78
     * @var string
79
     */
80
    private $coloursSetCode;
81
82
    /**
83
     * @var string
84
     */
85
    private $invertedColoursSetCode = "\033[7m";
86
87
    /**
88
     * @var string
89
     */
90
    private $invertedColoursUnsetCode = "\033[27m";
91
92
    /**
93
     * @var string
94
     */
95
    private $coloursResetCode = "\033[0m";
96
97
    /**
98
     * @var bool
99
     */
100
    private $marginAuto = false;
101
102
    /**
103
     * Default Values
104
     *
105
     * @var array
106
     */
107
    private static $defaultStyleValues = [
108
        'fg' => 'white',
109
        'bg' => 'blue',
110
        'width' => 100,
111
        'padding' => 2,
112
        'margin' => 2,
113
        'selectedMarker' => '●',
114
        'unselectedMarker' => '○',
115
        'itemExtra' => '✔',
116
        'displaysExtra' => false,
117
        'titleSeparator' => '=',
118
        'marginAuto' => false,
119
    ];
120
121
    public static function getDefaultStyleValues() : array
122
    {
123
        return static::$defaultStyleValues;
0 ignored issues
show
Bug introduced by
Since $defaultStyleValues is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $defaultStyleValues to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
124
    }
125
126
    /**
127
     * @var array
128
     */
129
    private static $availableForegroundColors = array(
130
        'black'   => 30,
131
        'red'     => 31,
132
        'green'   => 32,
133
        'yellow'  => 33,
134
        'blue'    => 34,
135
        'magenta' => 35,
136
        'cyan'    => 36,
137
        'white'   => 37,
138
        'default' => 39,
139
    );
140
141
    /**
142
     * @var array
143
     */
144
    private static $availableBackgroundColors = array(
145
        'black'   => 40,
146
        'red'     => 41,
147
        'green'   => 42,
148
        'yellow'  => 43,
149
        'blue'    => 44,
150
        'magenta' => 45,
151
        'cyan'    => 46,
152
        'white'   => 47,
153
        'default' => 49,
154
    );
155
156
    /**
157
     * @var array
158
     */
159
    private static $availableOptions = array(
160
        'bold'       => array('set' => 1, 'unset' => 22),
161
        'dim'        => array('set' => 2, 'unset' => 22),
162
        'underscore' => array('set' => 4, 'unset' => 24),
163
        'blink'      => array('set' => 5, 'unset' => 25),
164
        'reverse'    => array('set' => 7, 'unset' => 27),
165
        'conceal'    => array('set' => 8, 'unset' => 28)
166
    );
167
168
    /**
169
     * Initialise style
170
     */
171
    public function __construct(Terminal $terminal = null)
172
    {
173
        $this->terminal = $terminal ?: TerminalFactory::fromSystem();
174
175
        $this->setFg(static::$defaultStyleValues['fg']);
0 ignored issues
show
Bug introduced by
Since $defaultStyleValues is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $defaultStyleValues to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
176
        $this->setBg(static::$defaultStyleValues['bg']);
0 ignored issues
show
Bug introduced by
Since $defaultStyleValues is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $defaultStyleValues to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
177
        $this->setWidth(static::$defaultStyleValues['width']);
0 ignored issues
show
Bug introduced by
Since $defaultStyleValues is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $defaultStyleValues to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
178
        $this->setPadding(static::$defaultStyleValues['padding']);
0 ignored issues
show
Bug introduced by
Since $defaultStyleValues is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $defaultStyleValues to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
179
        $this->setMargin(static::$defaultStyleValues['margin']);
0 ignored issues
show
Bug introduced by
Since $defaultStyleValues is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $defaultStyleValues to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
180
        $this->setSelectedMarker(static::$defaultStyleValues['selectedMarker']);
0 ignored issues
show
Bug introduced by
Since $defaultStyleValues is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $defaultStyleValues to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
181
        $this->setUnselectedMarker(static::$defaultStyleValues['unselectedMarker']);
0 ignored issues
show
Bug introduced by
Since $defaultStyleValues is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $defaultStyleValues to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
182
        $this->setItemExtra(static::$defaultStyleValues['itemExtra']);
0 ignored issues
show
Bug introduced by
Since $defaultStyleValues is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $defaultStyleValues to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
183
        $this->setDisplaysExtra(static::$defaultStyleValues['displaysExtra']);
0 ignored issues
show
Bug introduced by
Since $defaultStyleValues is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $defaultStyleValues to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
184
        $this->setTitleSeparator(static::$defaultStyleValues['titleSeparator']);
0 ignored issues
show
Bug introduced by
Since $defaultStyleValues is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $defaultStyleValues to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
185
    }
186
187
    public function getDisabledItemText(string $text) : string
188
    {
189
        return sprintf(
190
            "\033[%sm%s\033[%sm",
191
            self::$availableOptions['dim']['set'],
192
            $text,
193
            self::$availableOptions['dim']['unset']
194
        );
195
    }
196
197
    /**
198
     * Generates the ansi escape sequence to set the colours
199
     */
200
    private function generateColoursSetCode() : void
201
    {
202
        if (is_string($this->fg)) {
203
            $fgCode = self::$availableForegroundColors[$this->fg];
204
        } else {
205
            $fgCode = sprintf("38;5;%s", $this->fg);
206
        }
207
208
        if (is_string($this->bg)) {
209
            $bgCode = self::$availableBackgroundColors[$this->bg];
210
        } else {
211
            $bgCode = sprintf("48;5;%s", $this->bg);
212
        }
213
214
        $this->coloursSetCode = sprintf("\033[%s;%sm", $fgCode, $bgCode);
215
    }
216
217
    /**
218
     * Get the colour code for Bg and Fg
219
     */
220
    public function getColoursSetCode() : string
221
    {
222
        return $this->coloursSetCode;
223
    }
224
225
    /**
226
     * Get the inverted escape sequence (used for selected elements)
227
     */
228
    public function getInvertedColoursSetCode() : string
229
    {
230
        return $this->invertedColoursSetCode;
231
    }
232
233
    /**
234
     * Get the inverted escape sequence (used for selected elements)
235
     */
236
    public function getInvertedColoursUnsetCode() : string
237
    {
238
        return $this->invertedColoursUnsetCode;
239
    }
240
241
    /**
242
     * Get the escape sequence used to reset colours to default
243
     */
244
    public function getColoursResetCode() : string
245
    {
246
        return $this->coloursResetCode;
247
    }
248
249
    /**
250
     * Calculate the contents width
251
     */
252
    protected function calculateContentWidth() : void
253
    {
254
        $this->contentWidth = $this->width - ($this->padding * 2);
255
    }
256
257
    public function getFg()
258
    {
259
        return $this->fg;
260
    }
261
262 View Code Duplication
    public function setFg($fg, string $fallback = null) : self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
263
    {
264
        $this->fg = ColourUtil::validateColour(
265
            $this->terminal,
266
            $fg,
267
            $fallback
268
        );
269
        $this->generateColoursSetCode();
270
271
        return $this;
272
    }
273
274
    public function getBg()
275
    {
276
        return $this->bg;
277
    }
278
279 View Code Duplication
    public function setBg($bg, string $fallback = null) : self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
280
    {
281
        $this->bg = ColourUtil::validateColour(
282
            $this->terminal,
283
            $bg,
284
            $fallback
285
        );
286
        $this->generateColoursSetCode();
287
288
        return $this;
289
    }
290
291
    public function getWidth() : int
292
    {
293
        return $this->width;
294
    }
295
296
    public function setWidth(int $width) : self
297
    {
298
        if ($width >= $this->terminal->getWidth()) {
299
            $width = $this->terminal->getWidth();
300
        }
301
302
        $this->width = $width;
303
        if ($this->marginAuto) {
304
            $this->setMarginAuto();
305
        }
306
        $this->calculateContentWidth();
307
308
        return $this;
309
    }
310
311
    public function getPadding() : int
312
    {
313
        return $this->padding;
314
    }
315
316
    public function setPadding(int $padding) : self
317
    {
318
        $this->padding = $padding;
319
320
        $this->calculateContentWidth();
321
322
        return $this;
323
    }
324
325
    public function getMargin() : int
326
    {
327
        return $this->margin;
328
    }
329
330
    public function setMarginAuto() : self
331
    {
332
        $this->marginAuto = true;
333
        $this->margin = floor(($this->terminal->getWidth() - $this->width) / 2);
0 ignored issues
show
Documentation Bug introduced by
The property $margin was declared of type integer, but floor(($this->terminal->...() - $this->width) / 2) is of type double. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
334
        
335
        return $this;
336
    }
337
338
    public function setMargin(int $margin) : self
339
    {
340
        $this->marginAuto = false;
341
        $this->margin = $margin;
342
343
        return $this;
344
    }
345
346
    public function getContentWidth() : int
347
    {
348
        return $this->contentWidth;
349
    }
350
351
    /**
352
     * Get padding for right had side of content
353
     */
354
    public function getRightHandPadding(int $contentLength) : int
355
    {
356
        return $this->getContentWidth() - $contentLength + $this->getPadding();
357
    }
358
359
    public function getSelectedMarker() : string
360
    {
361
        return $this->selectedMarker;
362
    }
363
364
    public function setSelectedMarker(string $marker) : self
365
    {
366
        $this->selectedMarker = mb_substr($marker, 0, 1);
367
368
        return $this;
369
    }
370
371
    public function getUnselectedMarker() : string
372
    {
373
        return $this->unselectedMarker;
374
    }
375
376
    public function setUnselectedMarker(string $marker) : self
377
    {
378
        $this->unselectedMarker = mb_substr($marker, 0, 1);
379
380
        return $this;
381
    }
382
383
    /**
384
     * Get the correct marker for the item
385
     */
386
    public function getMarker(bool $selected) : string
387
    {
388
        return $selected ? $this->selectedMarker : $this->unselectedMarker;
389
    }
390
391
    public function setItemExtra(string $itemExtra) : self
392
    {
393
        $this->itemExtra = $itemExtra;
394
395
        return $this;
396
    }
397
398
    public function getItemExtra() : string
399
    {
400
        return $this->itemExtra;
401
    }
402
403
    public function getDisplaysExtra() : bool
404
    {
405
        return $this->displaysExtra;
406
    }
407
408
    public function setDisplaysExtra(bool $displaysExtra) : self
409
    {
410
        $this->displaysExtra = $displaysExtra;
411
412
        return $this;
413
    }
414
415
    public function getTitleSeparator() : string
416
    {
417
        return $this->titleSeparator;
418
    }
419
420
    public function setTitleSeparator(string $actionSeparator) : self
421
    {
422
        $this->titleSeparator = $actionSeparator;
423
424
        return $this;
425
    }
426
}
427