Passed
Push — main ( 56908f...4059b3 )
by ANDREY
02:30
created

Glyph::setParent()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
namespace VPA\Console\Glyphs;
4
5
use VPA\Console\Color;
6
use VPA\Console\FrameConfigInterface;
7
use VPA\Console\FrameSymbol;
8
use VPA\Console\Nodes;
9
use VPA\Console\Symbol;
10
use VPA\Console\SymbolMode;
11
use VPA\DI\Injectable;
12
13
#[Injectable]
14
abstract class Glyph
15
{
16
    use Nodes;
17
18
    protected array $children = [];
19
    protected array $config = [];
20
    protected ?Glyph $parent = null;
21
    protected int $documentWidth = 80;
22
    protected int $width = 0;
23
    protected int $height = 0;
24
    protected ?bool $isFirstSibling = null;
25
    protected ?bool $isLastSibling = null;
26
    protected bool $isRendered = false;
27
    protected array $renderMap = [];
28
    protected array $cachedRenderMap = [];
29
    protected int $X = 0;
30
    protected int $Y = 0;
31
    protected int $offsetX = 0;
32
    protected int $offsetY = 0;
33
    protected bool $renderedWidth = false;
34
    protected bool $renderedHeight = false;
35
    protected int $contentWidth = 0;
36
    protected int $contentHeight = 0;
37
    protected array $symbolConfig = [];
38
39
40 54
    public function __construct(protected FrameConfigInterface $globalConfig)
41
    {
42 54
        $this->config = [
43
            'overflowX' => 'none',
44
            'overflowY' => 'none',
45
            'paddingLeft' => 0,
46
            'paddingRight' => 0,
47
            'paddingTop' => 0,
48
            'paddingBottom' => 0,
49
            'width' => 'auto',
50
            'maxWidth' => 100,
51
            'color' => Color::WHITE,
52
        ];
53
    }
54
55 39
    public function __isset(string $name): bool
56
    {
57 39
        return array_key_exists($name, $this->config);
58
    }
59
60 38
    public function __set(string $name, mixed $value): void
61
    {
62 38
        if ($this->__isset($name)) {
63 37
            $this->config[$name] = $value;
64 37
            return;
65
        }
66 1
        throw new \Exception(
67 1
            sprintf(
68
                "The property %s not exists for the %s element.",
69
                $name,
70 1
                get_class($this)
71
            )
72
        );
73
    }
74
75 51
    public function __get(string $name): mixed
76
    {
77 51
        return $this->config[$name] ?? null;
78
    }
79
80 37
    public function setConfig(array $config): Glyph
81
    {
82 37
        $this->config = array_merge($this->config, $config);
83 37
        return $this;
84
    }
85
86 46
    public function getConfig(): array
87
    {
88 46
        return $this->config;
89
    }
90
91 28
    public function addChild(Glyph $child): Glyph
92
    {
93 28
        $this->children[] = $child;
94 28
        $child->setParent($this);
95 28
        return $child;
96
    }
97
98 26
    public function getChildren(): array
99
    {
100 26
        return $this->children;
101
    }
102
103 14
    public function assign(): array
104
    {
105 14
        if ($this->isRendered) {
106 1
            return $this->renderMap;
107
        }
108 14
        $this->isRendered = true;
109 14
        $this->render();
110 14
        return $this->renderMap;
111
    }
112
113 3
    public function display(): void
114
    {
115 3
        $this->assign();
116 3
        $this->printMap();
117
    }
118
119 14
    public function render(): Glyph
120
    {
121 14
        $width = $this->getWidth();
122 14
        $height = $this->getHeight();
123 14
        $this->symbolConfig = [
124
            'mode' => SymbolMode::DEFAULT,
125 14
            'color' => $this->__get('borderColor'),
126 14
            'backgroundColor' => $this->__get('backgroundColor'),
127
        ];
128 14
        for ($i = 0; $i < $height; $i++) {
129 14
            $this->renderMap[$i] = array_fill(0, $width, clone $this->gc('space'));
130
        }
131 14
        foreach ($this->children as $child) {
132 13
            $this->mergeMaps($child->render());
133
        }
134 14
        return $this;
135
    }
136
137 1
    public function isFirstSibling(Glyph $child): bool
138
    {
139 1
        $first = reset($this->children);
140 1
        return $first !== false && $first === $child;
141
    }
142
143 1
    public function isLastSibling(Glyph $child): bool
144
    {
145 1
        $last = end($this->children);
146 1
        return $last !== false && $last === $child;
147
    }
148
149 2
    public function ifFirstSibling(array $config): Glyph
150
    {
151 2
        if (!$this->parent) {
152 1
            return $this;
153
        }
154 1
        $first = $this->parent->isFirstSibling($this);
155 1
        if ($first) {
156 1
            foreach ($config as $property => $value) {
157 1
                $this->__set($property, $value);
158
            }
159
        }
160 1
        return $this;
161
    }
162
163 2
    public function ifLastSibling(array $config): Glyph
164
    {
165 2
        if (!$this->parent) {
166 1
            return $this;
167
        }
168 1
        $last = $this->parent->isLastSibling($this);
169 1
        if ($last) {
170 1
            foreach ($config as $property => $value) {
171 1
                $this->__set($property, $value);
172
            }
173
        }
174 1
        return $this;
175
    }
176
177 2
    public function getDocumentWidth(): int
178
    {
179 2
        if (is_null($this->parent)) {
180 1
            return $this->documentWidth;
181
        } else {
182 1
            return $this->parent->getDocumentWidth();
183
        }
184
    }
185
186 3
    protected function printMap(): void
187
    {
188 3
        foreach ($this->renderMap as $y => $list) {
189 3
            echo implode("", $list) . "\n";
190
        }
191
    }
192
193 17
    public function getWidthByContent(int $endOfPreviousSibling = 0): int
194
    {
195 17
        $this->X = $endOfPreviousSibling;
196 17
        foreach ($this->children as $child) {
197
            $this->width = $child->getWidthByContent(0);
198
        }
199 17
        return $this->width;
200
    }
201
202 23
    public function getHeightByContent(int $endOfPreviousSibling = 0): int
203
    {
204 23
        $this->Y = $endOfPreviousSibling;
205 23
        foreach ($this->children as $child) {
206
            $this->height = $child->getHeightByContent();
207
        }
208 23
        return $this->height;
209
    }
210
211 24
    protected function gc(string $name): object
212
    {
213 24
        $property = $this->globalConfig->__get($name);
214 24
        if ($property instanceof Symbol) {
215 14
            return $property->setConfig($this->symbolConfig);
216
        }
217 16
        return $property;
218
    }
219
220
221 34
    public function getWidth(): int
222
    {
223 34
        return $this->width;
224
    }
225
226 18
    public function setX(int $x): void
227
    {
228 18
        $this->X = $x;
229
    }
230
231 23
    public function setY(int $y): void
232
    {
233 23
        $this->Y = $y;
234
    }
235
236 13
    public function setWidth(int $width): Glyph
237
    {
238 13
        $configWidth = $this->__get('width');
239 13
        if ($configWidth == 'auto') {
240 12
            $this->width = $width;
241
        } else {
242 1
            $this->width = intval($configWidth);
243
        }
244 13
        foreach ($this->getChildren() as $child) {
245 9
            $child->__set('maxWidth', $width);
246
        }
247 13
        $this->renderedWidth = true;
248 13
        return $this;
249
    }
250
251 17
    public function getHeight(): int
252
    {
253 17
        return $this->height;
254
    }
255
256 10
    public function setHeight(int $height): Glyph
257
    {
258 10
        $this->height = $height;
259 10
        $this->renderedHeight = true;
260 10
        return $this;
261
    }
262
263 28
    public function setParent(Glyph $parent): void
264
    {
265 28
        $this->parent = $parent;
266
    }
267
268 31
    public function getParent(): Glyph|null
269
    {
270 31
        return $this->parent;
271
    }
272
273 13
    private function mergeMaps(Glyph $render): void
274
    {
275 13
        $offsetX = $render->X + $this->offsetX;
276 13
        $offsetY = $render->Y + $this->offsetY;
277 13
        foreach ($render->renderMap as $y => $line) {
278 13
            foreach ($line as $x => $item) {
279 13
                $coordX = $offsetX + $x;
280 13
                $coordY = $offsetY + intval($y);
281 13
                $this->renderMap[$coordY][$coordX] = $item;
282
            }
283
        }
284
    }
285
}
286