Completed
Push — master ( 5909ec...c2adaf )
by Aydin
13s
created

CliMenuBuilder::addLineBreak()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 2
1
<?php
2
3
namespace PhpSchool\CliMenu\Builder;
4
5
use PhpSchool\CliMenu\Action\ExitAction;
6
use PhpSchool\CliMenu\Action\GoBackAction;
7
use PhpSchool\CliMenu\MenuItem\AsciiArtItem;
8
use PhpSchool\CliMenu\MenuItem\LineBreakItem;
9
use PhpSchool\CliMenu\MenuItem\MenuItemInterface;
10
use PhpSchool\CliMenu\MenuItem\MenuMenuItem;
11
use PhpSchool\CliMenu\MenuItem\SelectableItem;
12
use PhpSchool\CliMenu\CliMenu;
13
use PhpSchool\CliMenu\MenuItem\StaticItem;
14
use PhpSchool\CliMenu\MenuStyle;
15
use PhpSchool\CliMenu\Terminal\TerminalFactory;
16
use PhpSchool\Terminal\Terminal;
17
18
/**
19
 * @author Michael Woodward <[email protected]>
20
 * @author Aydin Hassan <[email protected]>
21
 */
22
class CliMenuBuilder
23
{
24
    /**
25
     * @var CliMenu
26
     */
27
    private $menu;
28
29
    /**
30
     * @var string
31
     */
32
    private $goBackButtonText = 'Go Back';
33
34
    /**
35
     * @var string
36
     */
37
    private $exitButtonText = 'Exit';
38
39
    /**
40
     * @var MenuStyle
41
     */
42
    private $style;
43
44
    /**
45
     * @var Terminal
46
     */
47
    private $terminal;
48
49
    /**
50
     * @var bool
51
     */
52
    private $disableDefaultItems = false;
53
54
    /**
55
     * @var bool
56
     */
57
    private $disabled = false;
58
59
    /**
60
     * @var bool
61
     */
62
    private $subMenu = false;
63
64
    public function __construct(Terminal $terminal = null)
65
    {
66
        $this->terminal = $terminal ?? TerminalFactory::fromSystem();
67
        $this->style    = new MenuStyle($this->terminal);
68
        $this->menu     = new CliMenu(null, [], $this->terminal, $this->style);
69
    }
70
    
71
    public static function newSubMenu(Terminal $terminal) : self
72
    {
73
        $instance = new self($terminal);
74
        $instance->subMenu = true;
75
        
76
        return $instance;
77
    }
78
79
    public function setTitle(string $title) : self
80
    {
81
        $this->menu->setTitle($title);
82
83
        return $this;
84
    }
85
86
    public function addMenuItem(MenuItemInterface $item) : self
87
    {
88
        $this->menu->addItem($item);
89
90
        return $this;
91
    }
92
93
    public function addItem(
94
        string $text,
95
        callable $itemCallable,
96
        bool $showItemExtra = false,
97
        bool $disabled = false
98
    ) : self {
99
        $this->addMenuItem(new SelectableItem($text, $itemCallable, $showItemExtra, $disabled));
100
101
        return $this;
102
    }
103
104
    public function addItems(array $items) : self
105
    {
106
        foreach ($items as $item) {
107
            $this->addItem(...$item);
0 ignored issues
show
Bug introduced by Aydin Hassan
The call to addItem() misses a required argument $itemCallable.

This check looks for function calls that miss required arguments.

Loading history...
108
        }
109
110
        return $this;
111
    }
112
113
    public function addStaticItem(string $text) : self
114
    {
115
        $this->addMenuItem(new StaticItem($text));
116
117
        return $this;
118
    }
119
120
    public function addLineBreak(string $breakChar = ' ', int $lines = 1) : self
121
    {
122
        $this->addMenuItem(new LineBreakItem($breakChar, $lines));
123
124
        return $this;
125
    }
126
127
    public function addAsciiArt(string $art, string $position = AsciiArtItem::POSITION_CENTER, string $alt = '') : self
128
    {
129
        $this->addMenuItem(new AsciiArtItem($art, $position, $alt));
130
131
        return $this;
132
    }
133
134
    public function addSubMenu(string $text, \Closure $callback) : self
135
    {
136
        $builder = self::newSubMenu($this->terminal);
137
138
        $callback = $callback->bindTo($builder);
139
        $callback($builder);
140
141
        $menu = $builder->build();
142
        $menu->setParent($this->menu);
143
        
144
        //we apply the parent theme if nothing was changed
145
        //if no styles were changed in this sub-menu
146
        if (!$menu->getStyle()->hasChangedFromDefaults()) {
147
            $menu->setStyle($this->menu->getStyle());
148
        }
149
150
        $this->menu->addItem(new MenuMenuItem(
151
            $text,
152
            $menu,
153
            $builder->isMenuDisabled()
154
        ));
155
        
156
        return $this;
157
    }
158
159
    public function addSubMenuFromBuilder(string $text, CliMenuBuilder $builder) : self
160
    {
161
        $menu = $builder->build();
162
        $menu->setParent($this->menu);
163
164
        //we apply the parent theme if nothing was changed
165
        //if no styles were changed in this sub-menu
166
        if (!$menu->getStyle()->hasChangedFromDefaults()) {
167
            $menu->setStyle($this->menu->getStyle());
168
        }
169
170
        $this->menu->addItem(new MenuMenuItem(
171
            $text,
172
            $menu,
173
            $builder->isMenuDisabled()
174
        ));
175
176
        return $this;
177
    }
178
179
    public function addSplitItem(\Closure $callback) : self
180
    {
181
        $builder = new SplitItemBuilder($this->menu);
182
183
        $callback = $callback->bindTo($builder);
184
        $callback($builder);
185
        
186
        $this->menu->addItem($builder->build());
187
        
188
        return $this;
189
    }
190
191
    /**
192
     * Disable a submenu
193
     *
194
     * @throws \InvalidArgumentException
195
     */
196
    public function disableMenu() : self
197
    {
198
        if (!$this->subMenu) {
199
            throw new \InvalidArgumentException(
200
                'You can\'t disable the root menu'
201
            );
202
        }
203
204
        $this->disabled = true;
205
206
        return $this;
207
    }
208
209
    public function isMenuDisabled() : bool
210
    {
211
        return $this->disabled;
212
    }
213
214
    public function setGoBackButtonText(string $goBackButtonTest) : self
215
    {
216
        $this->goBackButtonText = $goBackButtonTest;
217
218
        return $this;
219
    }
220
221
    public function setExitButtonText(string $exitButtonText) : self
222
    {
223
        $this->exitButtonText = $exitButtonText;
224
225
        return $this;
226
    }
227
228
    public function setBackgroundColour(string $colour, string $fallback = null) : self
229
    {
230
        $this->style->setBg($colour, $fallback);
231
232
        return $this;
233
    }
234
235
    public function setForegroundColour(string $colour, string $fallback = null) : self
236
    {
237
        $this->style->setFg($colour, $fallback);
238
239
        return $this;
240
    }
241
242
    public function setWidth(int $width) : self
243
    {
244
        $this->style->setWidth($width);
245
246
        return $this;
247
    }
248
249
    public function setPadding(int $topBottom, int $leftRight = null) : self
250
    {
251
        $this->style->setPadding($topBottom, $leftRight);
252
253
        return $this;
254
    }
255
256
    public function setPaddingTopBottom(int $topBottom) : self
257
    {
258
        $this->style->setPaddingTopBottom($topBottom);
259
260
        return $this;
261
    }
262
263
    public function setPaddingLeftRight(int $leftRight) : self
264
    {
265
        $this->style->setPaddingLeftRight($leftRight);
266
267
        return $this;
268
    }
269
270
    public function setMarginAuto() : self
271
    {
272
        $this->style->setMarginAuto();
273
274
        return $this;
275
    }
276
277
    public function setMargin(int $margin) : self
278
    {
279
        $this->style->setMargin($margin);
280
281
        return $this;
282
    }
283
284
    public function setUnselectedMarker(string $marker) : self
285
    {
286
        $this->style->setUnselectedMarker($marker);
287
288
        return $this;
289
    }
290
291
    public function setSelectedMarker(string $marker) : self
292
    {
293
        $this->style->setSelectedMarker($marker);
294
295
        return $this;
296
    }
297
298
    public function setItemExtra(string $extra) : self
299
    {
300
        $this->style->setItemExtra($extra);
301
302
        return $this;
303
    }
304
305
    public function setTitleSeparator(string $separator) : self
306
    {
307
        $this->style->setTitleSeparator($separator);
308
309
        return $this;
310
    }
311
312
    public function setBorder(int $top, $right = null, $bottom = null, $left = null, string $colour = null) : self
313
    {
314
        $this->style->setBorder($top, $right, $bottom, $left, $colour);
315
316
        return $this;
317
    }
318
319
    public function setBorderTopWidth(int $width) : self
320
    {
321
        $this->style->setBorderTopWidth($width);
322
        
323
        return $this;
324
    }
325
326
    public function setBorderRightWidth(int $width) : self
327
    {
328
        $this->style->setBorderRightWidth($width);
329
330
        return $this;
331
    }
332
333
    public function setBorderBottomWidth(int $width) : self
334
    {
335
        $this->style->setBorderBottomWidth($width);
336
337
        return $this;
338
    }
339
340
    public function setBorderLeftWidth(int $width) : self
341
    {
342
        $this->style->setBorderLeftWidth($width);
343
344
        return $this;
345
    }
346
347
    public function setBorderColour(string $colour, $fallback = null) : self
348
    {
349
        $this->style->setBorderColour($colour, $fallback);
350
351
        return $this;
352
    }
353
354
    public function getTerminal() : Terminal
355
    {
356
        return $this->terminal;
357
    }
358
359
    private function getDefaultItems() : array
360
    {
361
        $actions = [];
362
        if ($this->subMenu) {
363
            $actions[] = new SelectableItem($this->goBackButtonText, new GoBackAction);
364
        }
365
366
        $actions[] = new SelectableItem($this->exitButtonText, new ExitAction);
367
        return $actions;
368
    }
369
370
    public function disableDefaultItems() : self
371
    {
372
        $this->disableDefaultItems = true;
373
374
        return $this;
375
    }
376
377
    private function itemsHaveExtra(array $items) : bool
378
    {
379
        return !empty(array_filter($items, function (MenuItemInterface $item) {
380
            return $item->showsItemExtra();
381
        }));
382
    }
383
    
384
    public function build() : CliMenu
385
    {
386
        if (!$this->disableDefaultItems) {
387
            $this->menu->addItems($this->getDefaultItems());
388
        }
389
390
        $this->style->setDisplaysExtra($this->itemsHaveExtra($this->menu->getItems()));
391
392
        return $this->menu;
393
    }
394
}
395