Completed
Pull Request — master (#161)
by De Cramer
02:59
created

layoutLine::getX()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace eXpansion\Framework\Gui\Layouts;
4
5
use FML\Controls\Control;
6
use FML\Controls\Frame;
7
use FML\Elements\Format;
8
use FML\Script\Features\ScriptFeature;
9
use FML\Types\Container;
10
use FML\Types\Renderable;
11
use FML\Types\ScriptFeatureable;
12
13
class layoutLine implements Renderable, ScriptFeatureable, Container
14
{
15
    protected $frameClasses = [];
16
17
    protected $frameId = null;
18
19
    /** @var float */
20
    protected $width = 0.;
21
22
    /** @var float */
23
    protected $height = 0.;
24
25
    /** @var Control[] */
26
    protected $elements = [];
27
28
    /** @var float */
29
    private $margin = 2.;
30
    /**
31
     * @var float
32
     */
33
    protected $startX = 0.;
34
    /**
35
     * @var float
36
     */
37
    protected $startY = 0.;
38
39
    /** @var string */
40
    protected $hAlign = "left";
41
42
    /** @var string */
43
    protected $vAlign = "top";
44
45
    /**
46
     * layoutLine constructor.
47
     * @param float $startX
48
     * @param float $startY
49
     * @param object[] $elements
50
     * @param float $margin
51
     * @throws \Exception
52
     */
53
    public function __construct($startX, $startY, $elements = [], $margin = 0.)
54
    {
55
        if (!is_array($elements)) {
56
            throw new \Exception('not an array');
57
        }
58
        $this->margin = $margin;
59
        $this->elements = $elements;
60
        $this->startX = $startX;
61
        $this->startY = $startY;
62
        $sizeY = 0;
63
        foreach ($this->elements as $idx => $element) {
64
            $this->width += $element->getWidth() + $this->margin;
65
            if ($element->getY() + $element->getHeight() > $sizeY) {
66
                $this->setHeight($element->getHeight());
67
            }
68
        }
69
70
    }
71
72
    /**
73
     * Render the XML element
74
     *
75
     * @param \DOMDocument $domDocument DOMDocument for which the XML element should be rendered
76
     * @return \DOMElement
77
     */
78
    public function render(\DOMDocument $domDocument)
79
    {
80
        $frame = new Frame();
81
        $frame->setId($this->frameId);
82
        $frame->setAlign($this->hAlign, $this->vAlign);
83
        $frame->setPosition($this->startX, $this->startY);
84
        $frame->addClasses($this->frameClasses);
85
86
        $start = 0;
87
        $sizeY = 0;
88
89
        foreach ($this->elements as $idx => $element) {
90
91
            $element->setX($start + $this->getRelativeStartPosition($element));
92
            $start += $element->getWidth() + $this->margin;
93
94
            if ($element->getY() + $element->getHeight() > $sizeY) {
95
                $this->setHeight($element->getHeight());
96
            }
97
            $frame->addChild($element);
98
        }
99
100
        return $frame->render($domDocument);
101
    }
102
103
    /**
104
     * @param Control $element
105
     * @return float|int
106
     */
107
    private function getRelativeStartPosition($element)
108
    {
109
        if ($element->getHorizontalAlign() == "center") {
110
            return ($element->getWidth() / 2);
111
        }
112
113
        return 0;
114
    }
115
116
    /**
117
     * Get the Script Features
118
     *
119
     * @return ScriptFeature[]
120
     */
121 View Code Duplication
    public function getScriptFeatures()
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...
122
    {
123
        $features = [];
124
        foreach ($this->elements as $element) {
125
            if ($element instanceof ScriptFeatureable) {
126
                $features[] = $element->getScriptFeatures();
127
            }
128
        }
129
130
        return ScriptFeature::collect($features);
131
    }
132
133
    /**
134
     * @param mixed $startX
135
     * @return layoutLine
136
     */
137
    public function setX($startX)
138
    {
139
        $this->startX = $startX;
140
141
        return $this;
142
    }
143
144
    /**
145
     * @param mixed $startY
146
     * @return layoutLine
147
     */
148
    public function setY($startY)
149
    {
150
        $this->startY = $startY;
151
152
        return $this;
153
    }
154
155
    /**
156
     * @return float
157
     */
158
    public function getX()
159
    {
160
        return $this->startX;
161
    }
162
163
    /**
164
     * @return mixed
165
     */
166
    public function getY()
167
    {
168
        return $this->startY;
169
    }
170
171
    /**
172
     * @return float
173
     */
174
    public function getWidth()
175
    {
176
        return $this->width;
177
    }
178
179
    /**
180
     * @param float $width
181
     */
182
    public function setWidth($width)
183
    {
184
        $this->width = $width;
185
    }
186
187
    /**
188
     * @return float
189
     */
190
    public function getHeight()
191
    {
192
        return $this->height;
193
    }
194
195
    /**
196
     * @param float $height
197
     */
198
    public function setHeight($height)
199
    {
200
        $this->height = $height;
201
    }
202
203
    /**
204
     * @param object $element
205
     */
206
    public function addChild(Renderable $element)
207
    {
208
        $this->elements[] = $element;
209
        $this->width += $element->getWidth() + $this->margin;
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface FML\Types\Renderable as the method getWidth() does only exist in the following implementations of said interface: ControlStub, FML\Controls\Audio, FML\Controls\Control, FML\Controls\Entry, FML\Controls\FileEntry, FML\Controls\Frame, FML\Controls\Frame3d, FML\Controls\FrameInstance, FML\Controls\Gauge, FML\Controls\Graph, FML\Controls\Label, FML\Controls\Labels\Label_Button, FML\Controls\Labels\Label_Text, FML\Controls\Quad, FML\Controls\Quads\Quad_321Go, FML\Controls\Quads\Quad_BgRaceScore2, FML\Controls\Quads\Quad_Bgs1, FML\Controls\Quads\Quad_Bgs1InRace, FML\Controls\Quads\Quad_BgsButtons, FML\Controls\Quads\Quad_BgsChallengeMedals, FML\Controls\Quads\Quad_BgsPlayerCard, FML\Controls\Quads\Quad_Copilot, FML\Controls\Quads\Quad_Emblems, FML\Controls\Quads\Quad_EnergyBar, FML\Controls\Quads\Quad_Hud3dEchelons, FML\Controls\Quads\Quad_Hud3dIcons, FML\Controls\Quads\Quad_Icons128x128_1, FML\Controls\Quads\Quad_Icons128x128_Blink, FML\Controls\Quads\Quad_Icons128x32_1, FML\Controls\Quads\Quad_Icons64x64_1, FML\Controls\Quads\Quad_Icons64x64_2, FML\Controls\Quads\Quad_ManiaPlanetLogos, FML\Controls\Quads\Quad_ManiaPlanetMainMenu, FML\Controls\Quads\Quad_ManiaplanetSystem, FML\Controls\Quads\Quad_MedalsBig, FML\Controls\Quads\Quad_TitleLogos, FML\Controls\Quads\Quad_...structionBullet_Buttons, FML\Controls\Quads\Quad_UIConstruction_Buttons, FML\Controls\Quads\Quad_UIConstruction_Buttons2, FML\Controls\Quads\Quad_UiSMSpectatorScoreBig, FML\Controls\TextEdit, FML\Controls\Video, eXpansion\Framework\Gui\Builders\WidgetBackground, eXpansion\Framework\Gui\...nents\abstractUiElement, eXpansion\Framework\Gui\Components\uiAnimation, eXpansion\Framework\Gui\Components\uiButton, eXpansion\Framework\Gui\Components\uiCheckbox, eXpansion\Framework\Gui\Components\uiDropdown, eXpansion\Framework\Gui\Components\uiInput, eXpansion\Framework\Gui\Components\uiInputMasked, eXpansion\Framework\Gui\Components\uiLabel, eXpansion\Framework\Gui\Components\uiLine, eXpansion\Framework\Gui\Components\uiScrollbar, eXpansion\Framework\Gui\Components\uiTextbox, eXpansion\Framework\Gui\Components\uiTooltip, eXpansion\Framework\Gui\Layouts\layoutLine, eXpansion\Framework\Gui\Layouts\layoutRow, eXpansion\Framework\Gui\Layouts\layoutScrollable.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
210
        $this->height += $element->getHeight();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface FML\Types\Renderable as the method getHeight() does only exist in the following implementations of said interface: ControlStub, FML\Controls\Audio, FML\Controls\Control, FML\Controls\Entry, FML\Controls\FileEntry, FML\Controls\Frame, FML\Controls\Frame3d, FML\Controls\FrameInstance, FML\Controls\Gauge, FML\Controls\Graph, FML\Controls\Label, FML\Controls\Labels\Label_Button, FML\Controls\Labels\Label_Text, FML\Controls\Quad, FML\Controls\Quads\Quad_321Go, FML\Controls\Quads\Quad_BgRaceScore2, FML\Controls\Quads\Quad_Bgs1, FML\Controls\Quads\Quad_Bgs1InRace, FML\Controls\Quads\Quad_BgsButtons, FML\Controls\Quads\Quad_BgsChallengeMedals, FML\Controls\Quads\Quad_BgsPlayerCard, FML\Controls\Quads\Quad_Copilot, FML\Controls\Quads\Quad_Emblems, FML\Controls\Quads\Quad_EnergyBar, FML\Controls\Quads\Quad_Hud3dEchelons, FML\Controls\Quads\Quad_Hud3dIcons, FML\Controls\Quads\Quad_Icons128x128_1, FML\Controls\Quads\Quad_Icons128x128_Blink, FML\Controls\Quads\Quad_Icons128x32_1, FML\Controls\Quads\Quad_Icons64x64_1, FML\Controls\Quads\Quad_Icons64x64_2, FML\Controls\Quads\Quad_ManiaPlanetLogos, FML\Controls\Quads\Quad_ManiaPlanetMainMenu, FML\Controls\Quads\Quad_ManiaplanetSystem, FML\Controls\Quads\Quad_MedalsBig, FML\Controls\Quads\Quad_TitleLogos, FML\Controls\Quads\Quad_...structionBullet_Buttons, FML\Controls\Quads\Quad_UIConstruction_Buttons, FML\Controls\Quads\Quad_UIConstruction_Buttons2, FML\Controls\Quads\Quad_UiSMSpectatorScoreBig, FML\Controls\TextEdit, FML\Controls\Video, eXpansion\Framework\Gui\Builders\WidgetBackground, eXpansion\Framework\Gui\...nents\abstractUiElement, eXpansion\Framework\Gui\Components\uiAnimation, eXpansion\Framework\Gui\Components\uiButton, eXpansion\Framework\Gui\Components\uiCheckbox, eXpansion\Framework\Gui\Components\uiDropdown, eXpansion\Framework\Gui\Components\uiInput, eXpansion\Framework\Gui\Components\uiInputMasked, eXpansion\Framework\Gui\Components\uiLabel, eXpansion\Framework\Gui\Components\uiLine, eXpansion\Framework\Gui\Components\uiScrollbar, eXpansion\Framework\Gui\Components\uiTextbox, eXpansion\Framework\Gui\Components\uiTooltip, eXpansion\Framework\Gui\Layouts\layoutLine, eXpansion\Framework\Gui\Layouts\layoutRow, eXpansion\Framework\Gui\Layouts\layoutScrollable.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
211
    }
212
213
    public function getChildren()
214
    {
215
        return $this->elements;
216
    }
217
218
219
    public function addClass($class)
220
    {
221
        $this->frameClasses [] = $class;
222
    }
223
224
    /**
225
     * Add a new child
226
     *
227
     * @api
228
     * @param Renderable $child Child Control to add
229
     * @return static
230
     * @deprecated Use addChild()
231
     * @see        Container::addChild()
232
     */
233
    public function add(Renderable $child)
234
    {
235
        // TODO: Implement add() method.
236
    }
237
238
    /**
239
     * Add new children
240
     *
241
     * @api
242
     * @param Renderable[] $children Child Controls to add
243
     * @return static
244
     */
245
    public function addChildren(array $children)
246
    {
247
        foreach ($children as $child) {
248
            $this->addChild($child);
249
        }
250
    }
251
252
    /**
253
     * Remove all children
254
     *
255
     * @api
256
     * @return static
257
     */
258
    public function removeAllChildren()
259
    {
260
        $this->width = 0;
0 ignored issues
show
Documentation Bug introduced by
The property $width was declared of type double, but 0 is of type integer. 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...
261
        $this->height = 0;
0 ignored issues
show
Documentation Bug introduced by
The property $height was declared of type double, but 0 is of type integer. 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...
262
        $this->elements = [];
263
264
        return $this;
265
    }
266
267
    /**
268
     * Remove all children
269
     *
270
     * @api
271
     * @return static
272
     * @deprecated Use removeAllChildren()
273
     * @see        Container::removeAllChildren()
274
     */
275
    public function removeChildren()
276
    {
277
        // TODO: Implement removeChildren() method.
278
    }
279
280
    /**
281
     * Get the Format
282
     *
283
     * @api
284
     * @param bool $createIfEmpty If the format should be created if it doesn't exist yet
285
     * @return Format
286
     * @deprecated Use Style
287
     * @see        Style
288
     */
289
    public function getFormat($createIfEmpty = true)
290
    {
291
292
    }
293
294
    /**
295
     * Set the Format
296
     *
297
     * @api
298
     * @param Format $format New Format
299
     * @return void
300
     * @deprecated Use Style
301
     * @see        Style
302
     */
303
    public function setFormat(Format $format = null)
304
    {
305
306
    }
307
308
    public function setAlign($hAling = "left", $vAlign = "top")
309
    {
310
        $this->halign = $hAling;
0 ignored issues
show
Bug introduced by
The property halign does not seem to exist. Did you mean hAlign?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
311
        $this->valign = $vAlign;
0 ignored issues
show
Bug introduced by
The property valign does not seem to exist. Did you mean vAlign?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
312
313
        return $this;
314
    }
315
316
317
    public function setPosition($x, $y)
318
    {
319
        $this->setX($x);
320
        $this->setY($y);
321
322
        return $this;
323
    }
324
325
    /**
326
     * @return null|string
327
     */
328
    public function getId()
329
    {
330
        return $this->frameId;
331
    }
332
333
    /**
334
     * @param null|string $frameId
335
     */
336
    public function setId($frameId)
337
    {
338
        $this->frameId = $frameId;
339
340
        return $this;
341
    }
342
343
    /**
344
     * @return string
345
     */
346
    public function getHorizontalAlign(): string
347
    {
348
        return $this->hAlign;
349
    }
350
351
    /**
352
     * @param string $hAlign
353
     */
354
    public function setHorizontalAlign(string $hAlign)
355
    {
356
        $this->hAlign = $hAlign;
357
358
        return $this;
359
    }
360
361
}
362