FifeGUI 0.3.0
A C++ GUI library designed for games.
container.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later OR BSD-3-Clause
2// SPDX-FileCopyrightText: 2004 - 2008 Olof Naessén and Per Larsson
3// SPDX-FileCopyrightText: 2013 - 2026 Fifengine contributors
4
5// Corresponding header include
6#include "fifechan/widgets/container.hpp"
7
8// Standard library includes
9#include <algorithm>
10#include <list>
11#include <string>
12#include <vector>
13
14// Project headers (subdirs before local)
15#include "fifechan/exception.hpp"
16#include "fifechan/graphics.hpp"
17#include "fifechan/math.hpp"
18
19namespace fcn
20{
21 Container::Container() = default;
22
23 Container::~Container() = default;
24
25 void Container::draw(Graphics* graphics)
26 {
27 bool const active = isFocused();
28 // Compute per-side border offsets so widgets using side-only borders
29 // (e.g., bottom-only) don't get inset on all sides.
30 int const leftBorder = (getBorderSides() & Widget::BORDER_LEFT) != 0U ? static_cast<int>(getBorderSize()) : 0;
31 int const topBorder = (getBorderSides() & Widget::BORDER_TOP) != 0U ? static_cast<int>(getBorderSize()) : 0;
32 int const rightBorder = (getBorderSides() & Widget::BORDER_RIGHT) != 0U ? static_cast<int>(getBorderSize()) : 0;
33 int const bottomBorder =
34 (getBorderSides() & Widget::BORDER_BOTTOM) != 0U ? static_cast<int>(getBorderSize()) : 0;
35
36 if (isOpaque()) {
37 if (active &&
38 ((getSelectionMode() & Widget::SelectionMode::Background) == Widget::SelectionMode::Background)) {
39 graphics->setColor(getSelectionColor());
40 } else {
41 graphics->setColor(getBaseColor());
42 }
43
44 graphics->fillRectangle(
45 leftBorder,
46 topBorder,
47 getWidth() - (leftBorder + rightBorder),
48 getHeight() - (topBorder + bottomBorder));
49 }
50 if (mBackgroundWidget != nullptr) {
51 Rectangle const rec(
52 leftBorder,
53 topBorder,
54 getWidth() - (leftBorder + rightBorder),
55 getHeight() - (topBorder + bottomBorder));
56 mBackgroundWidget->setDimension(rec);
57 mBackgroundWidget->_draw(graphics);
58 }
59 if (getBorderSize() > 0) {
60 if (active && (getSelectionMode() & Widget::SelectionMode::Border) == Widget::SelectionMode::Border) {
61 drawSelectionFrame(graphics);
62 } else {
63 drawBorder(graphics);
64 }
65 }
66
67 // Children are drawn by Widget::_draw after `draw()` returns.
68 // Avoid drawing them here to prevent double-rendering.
69 }
70
71 // TODO opacity with 0.0 = fully transparent, 1.0 = fully visible
72 void Container::setOpacity(float opacity)
73 {
74 mOpacity = std::clamp(opacity, 0.0F, 1.0F);
75
76 if (mOpacity < 1.0F) {
77 setOpaque(false);
78 } else {
79 setOpaque(true);
80 }
81 }
82
83 void Container::setOpaque(bool opaque)
84 {
85 mOpaque = opaque;
86 }
87
89 {
90 return mOpaque;
91 }
92
93 void Container::add(Widget* widget)
94 {
95 Widget::add(widget);
97 }
98
99 void Container::addWidget(std::unique_ptr<Widget> widget)
100 {
101 if (widget == nullptr) {
102 return;
103 }
104
105 Widget* rawWidget = widget.release();
106 add(rawWidget);
107 }
108
109 void Container::add(Widget* widget, int x, int y)
110 {
111 widget->setPosition(x, y);
112 Widget::add(widget);
114 }
115
116 void Container::addWidget(std::unique_ptr<Widget> widget, int x, int y)
117 {
118 if (widget == nullptr) {
119 return;
120 }
121
122 Widget* rawWidget = widget.release();
123 add(rawWidget, x, y);
124 }
125
127 {
128 Widget::remove(widget);
130 }
131
136
137 Widget* Container::findWidgetById(std::string const & id)
138 {
139 return Widget::findWidgetById(id);
140 }
141
143 {
144 mContainerListeners.push_back(containerListener);
145 }
146
147 // cppcheck-suppress constParameterPointer
149 {
150 mContainerListeners.remove(containerListener);
151 }
152
154 {
156
157 for (iter = mContainerListeners.begin(); iter != mContainerListeners.end(); ++iter) {
158 ContainerEvent const event(source, this);
159 (*iter)->widgetAdded(event);
160 }
161 }
162
164 {
166
167 for (iter = mContainerListeners.begin(); iter != mContainerListeners.end(); ++iter) {
168 ContainerEvent const event(source, this);
169 (*iter)->widgetRemoved(event);
170 }
171 }
172
173 Widget* Container::getChild(unsigned int index) const
174 {
175 if (index >= getChildrenCount()) {
176 return nullptr;
177 }
178
179 auto const & children = getChildren();
180 auto iter = std::next(children.begin(), index);
181
182 return *iter;
183 }
184
185 void Container::resizeToContent(bool recursion)
186 {
187 if (mLayout == LayoutPolicy::Absolute) {
188 if (recursion) {
189 std::list<Widget*>::const_iterator currChild(mChildren.begin());
190 std::list<Widget*>::const_iterator const endChildren(mChildren.end());
191 for (; currChild != endChildren; ++currChild) {
192 if (!(*currChild)->isVisible()) {
193 continue;
194 }
195 (*currChild)->resizeToContent(recursion);
196 }
197 }
198 return;
199 }
200
201 int childMaxW = 0;
202 int childMaxH = 0;
203 int layoutMaxW = 0;
204 int layoutMaxH = 0;
205 int totalW = 0;
206 int totalH = 0;
207 int visibleChilds = 0;
208
209 std::list<Widget*>::const_iterator currChild(mChildren.begin());
210 std::list<Widget*>::const_iterator endChildren(mChildren.end());
211 for (; currChild != endChildren; ++currChild) {
212 if (!(*currChild)->isVisible()) {
213 continue;
214 }
215 if (recursion) {
216 (*currChild)->resizeToContent(recursion);
217 }
218 Rectangle const & rec = (*currChild)->getDimension();
219 childMaxW = std::max(childMaxW, rec.width);
220 childMaxH = std::max(childMaxH, rec.height);
221 layoutMaxW =
222 std::max(layoutMaxW, rec.width + (*currChild)->getMarginLeft() + (*currChild)->getMarginRight());
223 layoutMaxH =
224 std::max(layoutMaxH, rec.height + (*currChild)->getMarginTop() + (*currChild)->getMarginBottom());
225 ++visibleChilds;
226 }
227
228 // diff means border, padding, ...
229 int const diffW = getDimension().width - getChildrenArea().width;
230 int const diffH = getDimension().height - getChildrenArea().height;
231 Rectangle dimensions(0, 0, childMaxW, childMaxH);
232
233 if (mLayout == LayoutPolicy::AutoSize && visibleChilds > 0) {
234 currChild = mChildren.begin();
235 endChildren = mChildren.end();
236 for (; currChild != endChildren; ++currChild) {
237 if (!(*currChild)->isVisible()) {
238 continue;
239 }
240 Rectangle const & rec = (*currChild)->getDimension();
241 int const childW = rec.x + rec.width + (*currChild)->getMarginLeft() + (*currChild)->getMarginRight();
242 int const childH = rec.y + rec.height + (*currChild)->getMarginTop() + (*currChild)->getMarginBottom();
243 totalW = std::max(totalW, childW);
244 totalH = std::max(totalH, childH);
245 }
246 totalW += diffW;
247 totalH += diffH;
248 } else if (mLayout == LayoutPolicy::Vertical && visibleChilds > 0) {
258 currChild = mChildren.begin();
259 endChildren = mChildren.end();
260 for (; currChild != endChildren; ++currChild) {
261 if (!(*currChild)->isVisible()) {
262 continue;
263 }
264 dimensions.x = (*currChild)->getMarginLeft();
265 dimensions.y += (*currChild)->getMarginTop();
266 int const layoutW = (*currChild)->getWidth() + (*currChild)->getMarginLeft() +
267 ((*currChild)->getMarginRight() > 0 ? (*currChild)->getMarginRight() : 0);
268 dimensions.width = (*currChild)->getWidth() + (layoutMaxW - layoutW); // may expand
269 dimensions.height = (*currChild)->getHeight();
270 (*currChild)->setDimension(dimensions);
271 dimensions.y += (*currChild)->getHeight() + (*currChild)->getMarginBottom() + getVerticalSpacing();
272 }
273 // remove last spacing
274 dimensions.y -= getVerticalSpacing();
275 totalW = std::max(layoutMaxW, childMaxW) + diffW;
276 totalH = dimensions.y + diffH;
277 } else if (mLayout == LayoutPolicy::Horizontal && visibleChilds > 0) {
287 currChild = mChildren.begin();
288 endChildren = mChildren.end();
289 for (; currChild != endChildren; ++currChild) {
290 if (!(*currChild)->isVisible()) {
291 continue;
292 }
293 dimensions.x += (*currChild)->getMarginLeft();
294 dimensions.y = (*currChild)->getMarginTop();
295 dimensions.width = (*currChild)->getWidth();
296 int const layoutH = (*currChild)->getHeight() + (*currChild)->getMarginTop() +
297 ((*currChild)->getMarginBottom() > 0 ? (*currChild)->getMarginBottom() : 0);
298 dimensions.height = (*currChild)->getHeight() + (layoutMaxH - layoutH); // may expand
299 (*currChild)->setDimension(dimensions);
300 dimensions.x += (*currChild)->getWidth() + (*currChild)->getMarginRight() + getHorizontalSpacing();
301 }
302 // remove last spacing
303 dimensions.x -= getHorizontalSpacing();
304 totalW = dimensions.x + diffW;
305 totalH = std::max(layoutMaxH, childMaxH) + diffH;
306 } else if (mLayout == LayoutPolicy::Circular && visibleChilds > 0) {
307 float const angle = 360.0F / visibleChilds;
308 auto const xRadius = static_cast<float>((childMaxW * 2) + getHorizontalSpacing());
309 auto const yRadius = static_cast<float>((childMaxH * 2) + getVerticalSpacing());
310 currChild = mChildren.begin();
311 endChildren = mChildren.end();
312 int w = 0;
313 int h = 0;
314 int i = 0;
315 int minW = 50000;
316 int minH = 50000;
317 int maxW = -50000;
318 int maxH = -50000;
319 for (; currChild != endChildren; ++currChild) {
320 if (!(*currChild)->isVisible()) {
321 continue;
322 }
323 float const tmpAngle =
324 static_cast<float>(static_cast<int>((angle * i) + 270) % 360) / (180.0F / Mathf::pi());
325 int const x = static_cast<int>(
326 (xRadius * std::cos(tmpAngle)) - (static_cast<float>((*currChild)->getWidth()) / 2.0F));
327 int const y = static_cast<int>(
328 (yRadius * std::sin(tmpAngle)) - (static_cast<float>((*currChild)->getHeight()) / 2.0F));
329 minW = std::min(minW, x);
330 maxW = std::max(maxW, x + (*currChild)->getWidth());
331 minH = std::min(minH, y);
332 maxH = std::max(maxH, y + (*currChild)->getHeight());
333
334 (*currChild)->setPosition(x, y);
335 ++i;
336 }
337
338 w = std::abs(minW) + std::abs(maxW);
339 h = std::abs(minH) + std::abs(maxH);
340
341 int const centerX = w / 2;
342 int const centerY = h / 2;
343
344 currChild = mChildren.begin();
345 endChildren = mChildren.end();
346 for (; currChild != endChildren; ++currChild) {
347 if (!(*currChild)->isVisible()) {
348 continue;
349 }
350 int const x = (*currChild)->getX() + centerX;
351 int const y = (*currChild)->getY() + centerY;
352
353 (*currChild)->setPosition(x, y);
354 }
355
356 totalW = w + diffW;
357 totalH = h + diffH;
358 }
359
360 setSize(totalW, totalH);
361 }
362
364 {
366 int const w = getWidth() + (2 * getBorderSize()) + getPaddingLeft() + getPaddingRight();
367 int const h = getHeight() + (2 * getBorderSize()) + getPaddingTop() + getPaddingBottom();
368 setSize(w, h);
369 }
370
371 // TODO(jakoch): This is a very complex method. It should be refactored.
372 void Container::expandContent(bool recursion)
373 {
374 if (mLayout == LayoutPolicy::Absolute) {
375 if (recursion) {
376 std::list<Widget*>::const_iterator currChild(mChildren.begin());
377 std::list<Widget*>::const_iterator const endChildren(mChildren.end());
378 for (; currChild != endChildren; ++currChild) {
379 if (!(*currChild)->isVisible()) {
380 continue;
381 }
382 (*currChild)->expandContent(recursion);
383 }
384 }
385 return;
386 }
387
388 if (mLayout == LayoutPolicy::AutoSize) {
389 return;
390 }
391
392 Rectangle const childrenArea = getChildrenArea();
393 int const spaceW = childrenArea.width;
394 int const spaceH = childrenArea.height;
395 int neededSpaceW = 0;
396 int neededSpaceH = 0;
397 int maxMinW = 0;
398 int maxMinH = 0;
399 int minMaxW = 50000;
400 int minMaxH = 50000;
401 int maxHExpander = 0;
402 int maxVExpander = 0;
403 int expanderNeededSpaceW = 0;
404 int expanderNeededSpaceH = 0;
405 unsigned int visibleChilds = 0;
406 std::list<Widget*> hExpander;
407 std::list<Widget*> vExpander;
408
409 std::list<Widget*>::const_iterator currChild(mChildren.begin());
410 std::list<Widget*>::const_iterator endChildren(mChildren.end());
411 for (; currChild != endChildren; ++currChild) {
412 if (!(*currChild)->isVisible()) {
413 continue;
414 }
415 ++visibleChilds;
416 // get needed space
417 neededSpaceW += (*currChild)->getWidth() + (*currChild)->getMarginLeft() + (*currChild)->getMarginRight() +
419 neededSpaceH += (*currChild)->getHeight() + (*currChild)->getMarginTop() + (*currChild)->getMarginBottom() +
421 // get expander and expander max/min size
422 if ((*currChild)->isVerticalExpand()) {
423 maxVExpander = std::max(maxVExpander, (*currChild)->getHeight());
424 maxMinH = std::max(maxMinH, (*currChild)->getMinSize().getHeight());
425 minMaxH = std::min(minMaxH, (*currChild)->getMaxSize().getHeight());
426 expanderNeededSpaceH += (*currChild)->getHeight() + getVerticalSpacing();
427 vExpander.push_back((*currChild));
428 }
429 if ((*currChild)->isHorizontalExpand()) {
430 maxHExpander = std::max(maxHExpander, (*currChild)->getWidth());
431 maxMinW = std::max(maxMinW, (*currChild)->getMinSize().getWidth());
432 minMaxW = std::min(minMaxW, (*currChild)->getMaxSize().getWidth());
433 expanderNeededSpaceW += (*currChild)->getWidth() + getHorizontalSpacing();
434 hExpander.push_back((*currChild));
435 }
436 }
437
438 if (mLayout == LayoutPolicy::Vertical && visibleChilds > 0) {
439 bool const hexpand = isHorizontalExpand() && (getParent() == nullptr);
440 neededSpaceH -= getVerticalSpacing();
441 int freeSpace = spaceH - neededSpaceH;
442 if (freeSpace > 0) {
443 if (!vExpander.empty()) {
444 expanderNeededSpaceH -= getVerticalSpacing();
445 }
446 if (mUniform) {
447 // check against the smallest maximal height
448 maxVExpander = std::min(minMaxH, maxVExpander);
449 // check against the largest minimal height
450 maxVExpander = std::max(maxMinH, maxVExpander);
451 int h = 0;
452 // calculate maximal height if all expanders get this max height
453 int const maxNeeded =
454 ((maxVExpander + getVerticalSpacing()) * vExpander.size()) - getVerticalSpacing();
455 int const tmpSpace = (freeSpace + expanderNeededSpaceH) - maxNeeded;
456 if (tmpSpace > 0) {
457 h = maxVExpander;
458 freeSpace = tmpSpace;
459 }
460 // distribute space
461 if (freeSpace > 0 || h > 0) {
462
463 auto it = vExpander.begin();
464
465 int expanders = vExpander.size();
466
467 for (; it != vExpander.end(); ++it) {
468 int const layoutH = (*it)->getHeight() + (*it)->getMarginTop() +
469 ((*it)->getMarginBottom() > 0 ? (*it)->getMarginBottom() : 0);
470 // divide the space so that all expanders get the same size
471 int const diff = h > 0 ? 0 : (*it)->getHeight() + (maxVExpander - layoutH);
472 int delta = ((freeSpace - diff) / expanders) + diff;
473 if (delta == 0) {
474 delta = 1;
475 }
476 delta = std::min(delta, freeSpace);
477 int const oldH = h > 0 ? h : (*it)->getHeight();
478 int tmpH = oldH + delta;
479 (*it)->setHeight(tmpH);
480 tmpH = (*it)->getHeight();
481 delta = tmpH - oldH;
482 freeSpace -= delta;
483 --expanders;
484 }
485 }
486
487 } else {
488 if (!vExpander.empty()) {
489 // simply add one to each expander until free space is empty
490 // or all expanders reached the max height
491 std::vector<Widget*> maxExpanders;
492 while ((freeSpace != 0) && maxExpanders.size() < vExpander.size()) {
493 auto it = vExpander.begin();
494 for (; it != vExpander.end(); ++it) {
495 int const h = (*it)->getHeight();
496 (*it)->setHeight(h + 1);
497 if (h != (*it)->getHeight()) {
498 --freeSpace;
499 if (freeSpace == 0) {
500 break;
501 }
502 } else {
503 if (std::ranges::find(maxExpanders, *it) == maxExpanders.end()) {
504 maxExpanders.push_back(*it);
505 }
506 }
507 }
508 }
509 }
510 }
511 }
512 // adapt position
513 if (!hExpander.empty() || !vExpander.empty() || hexpand) {
514 Rectangle rec(0, 0, spaceW, 0);
515 currChild = mChildren.begin();
516 endChildren = mChildren.end();
517 for (; currChild != endChildren; ++currChild) {
518 if (!(*currChild)->isVisible()) {
519 continue;
520 }
521 if (hexpand || (*currChild)->isHorizontalExpand()) {
522 int const layoutW = (*currChild)->getMarginLeft() +
523 ((*currChild)->getMarginRight() > 0 ? (*currChild)->getMarginRight() : 0);
524
525 rec.width = spaceW - layoutW;
526 } else {
527 rec.width = (*currChild)->getWidth();
528 }
529 rec.x = (*currChild)->getMarginLeft();
530 rec.y += (*currChild)->getMarginTop();
531 rec.height = (*currChild)->getHeight();
532 (*currChild)->setDimension(rec);
533 rec.y += rec.height + (*currChild)->getMarginBottom() + getVerticalSpacing();
534 }
535 }
536 } else if (mLayout == LayoutPolicy::Horizontal && visibleChilds > 0) {
537 bool const vexpand = isVerticalExpand() || (getParent() == nullptr);
538 neededSpaceW -= getHorizontalSpacing();
539 int freeSpace = spaceW - neededSpaceW;
540 if (freeSpace > 0) {
541 if (mUniform) {
542 if (!hExpander.empty()) {
543 expanderNeededSpaceW -= getHorizontalSpacing();
544 }
545 // check against the smallest maximal width
546 maxHExpander = std::min(minMaxW, maxHExpander);
547 // check against the largest minimal width
548 maxHExpander = std::max(maxMinW, maxHExpander);
549 int w = 0;
550 // calculate maximal width if all expanders get this max width
551 int const maxNeeded =
552 ((maxHExpander + getHorizontalSpacing()) * hExpander.size()) - getHorizontalSpacing();
553 int const tmpSpace = (freeSpace + expanderNeededSpaceW) - maxNeeded;
554 if (tmpSpace > 0) {
555 w = maxHExpander;
556 freeSpace = tmpSpace;
557 }
558 // distribute space
559 if (freeSpace > 0 || w > 0) {
560 auto it = hExpander.begin();
561 int expanders = hExpander.size();
562 for (; it != hExpander.end(); ++it) {
563 // divide the space so that all expanders get the same size
564 int const layoutW = (*it)->getWidth() + (*it)->getMarginLeft() +
565 ((*it)->getMarginRight() > 0 ? (*it)->getMarginRight() : 0);
566
567 int const diff = w > 0 ? 0 : (*it)->getWidth() + (maxHExpander - layoutW);
568 int delta = ((freeSpace - diff) / expanders) + diff;
569 if (delta == 0) {
570 delta = 1;
571 }
572 delta = std::min(delta, freeSpace);
573 int const oldW = w > 0 ? w : (*it)->getWidth();
574 int tmpW = oldW + delta;
575 (*it)->setWidth(tmpW);
576 tmpW = (*it)->getWidth();
577 delta = tmpW - oldW;
578 freeSpace -= delta;
579 --expanders;
580 }
581 }
582 } else {
583 if (!hExpander.empty()) {
584 // simply add one to each expander until free space is empty
585 // or all expanders reached the max width
586 std::vector<Widget*> maxExpanders;
587 while ((freeSpace != 0) && maxExpanders.size() < hExpander.size()) {
588 auto it = hExpander.begin();
589 for (; it != hExpander.end(); ++it) {
590 int const w = (*it)->getWidth();
591 (*it)->setWidth(w + 1);
592 if (w != (*it)->getWidth()) {
593 --freeSpace;
594 if (freeSpace == 0) {
595 break;
596 }
597 } else {
598 if (std::ranges::find(maxExpanders, *it) == maxExpanders.end()) {
599 maxExpanders.push_back(*it);
600 }
601 }
602 }
603 }
604 }
605 }
606 }
607 // adapt position
608 if (!hExpander.empty() || !vExpander.empty() || vexpand) {
609 Rectangle rec(0, 0, 0, spaceH);
610 currChild = mChildren.begin();
611 endChildren = mChildren.end();
612 for (; currChild != endChildren; ++currChild) {
613 if (!(*currChild)->isVisible()) {
614 continue;
615 }
616 if (vexpand || (*currChild)->isVerticalExpand()) {
617 int const layoutH = (*currChild)->getMarginTop() +
618 ((*currChild)->getMarginBottom() > 0 ? (*currChild)->getMarginBottom() : 0);
619
620 rec.height = spaceH - layoutH;
621 } else {
622 rec.height = (*currChild)->getHeight();
623 }
624 rec.x += (*currChild)->getMarginLeft();
625 rec.y = (*currChild)->getMarginTop();
626 rec.width = (*currChild)->getWidth();
627 (*currChild)->setDimension(rec);
628 rec.x += rec.width + (*currChild)->getMarginRight() + getHorizontalSpacing();
629 }
630 }
631 } else if (mLayout == LayoutPolicy::Circular && visibleChilds > 0) {
632 float const angle = 360.0F / visibleChilds;
633 int childMaxW = 0;
634 int childMaxH = 0;
635 currChild = mChildren.begin();
636 endChildren = mChildren.end();
637 for (; currChild != endChildren; ++currChild) {
638 if (!(*currChild)->isVisible()) {
639 continue;
640 }
641 childMaxW = std::max(childMaxW, (*currChild)->getWidth());
642 childMaxH = std::max(childMaxH, (*currChild)->getHeight());
643 }
644 // childMaxW += getHorizontalSpacing();
645 // childMaxH += getVerticalSpacing();
646 float xRadius = (spaceW - childMaxW) / 2.0F;
647 float yRadius = (spaceH - childMaxH) / 2.0F;
648 float const centerX = spaceW / 2.0F;
649 float const centerY = spaceH / 2.0F;
650 if (xRadius < 1) {
651 xRadius = static_cast<float>(childMaxW);
652 }
653 if (yRadius < 1) {
654 yRadius = static_cast<float>(childMaxH);
655 }
656 // this forces a uniform circle
657 // xRadius = std::max(xRadius, yRadius);
658 // yRadius = xRadius;
659 int i = 0;
660 currChild = mChildren.begin();
661 endChildren = mChildren.end();
662 for (; currChild != endChildren; ++currChild) {
663 if (!(*currChild)->isVisible()) {
664 continue;
665 }
666 float const tmpAngle =
667 static_cast<float>(static_cast<int>((angle * i) + 270) % 360) / (180.0F / Mathf::pi());
668 int x = static_cast<int>(centerX + (xRadius * std::cos(tmpAngle)));
669 int y = static_cast<int>(centerY + (yRadius * std::sin(tmpAngle)));
670 x -= (*currChild)->getWidth() / 2;
671 y -= (*currChild)->getHeight() / 2;
672
673 (*currChild)->setPosition(x, y);
674 ++i;
675 }
676 }
677
678 if (recursion) {
679 currChild = mChildren.begin();
680 endChildren = mChildren.end();
681 for (; currChild != endChildren; ++currChild) {
682 if (!(*currChild)->isVisible()) {
683 continue;
684 }
685 (*currChild)->expandContent(recursion);
686 }
687 }
688 }
689
691 {
692 mLayout = policy;
693 }
694
696 {
697 return mLayout;
698 }
699
700 void Container::setUniformSize(bool uniform)
701 {
702 mUniform = uniform;
703 }
704
706 {
707 return mUniform;
708 }
709
711 {
712 // Set per-side border offsets.
713 // Widgets using side-only borders (e.g. border-bottom only) don't get inset on all sides.
714 int const leftBorder = (getBorderSides() & Widget::BORDER_LEFT) != 0U ? static_cast<int>(getBorderSize()) : 0;
715 int const topBorder = (getBorderSides() & Widget::BORDER_TOP) != 0U ? static_cast<int>(getBorderSize()) : 0;
716 int const rightBorder = (getBorderSides() & Widget::BORDER_RIGHT) != 0U ? static_cast<int>(getBorderSize()) : 0;
717 int const bottomBorder =
718 (getBorderSides() & Widget::BORDER_BOTTOM) != 0U ? static_cast<int>(getBorderSize()) : 0;
719
720 int const horizontalBorders = leftBorder + rightBorder;
721 int const verticalBorders = topBorder + bottomBorder;
722
723 Rectangle rec;
724 rec.x = leftBorder + getPaddingLeft();
725 rec.y = topBorder + getPaddingTop();
726 rec.width = getWidth() - horizontalBorders - getPaddingLeft() - getPaddingRight();
727 rec.height = getHeight() - verticalBorders - getPaddingTop() - getPaddingBottom();
728 return rec;
729 }
730
731 void Container::setVerticalSpacing(unsigned int spacing)
732 {
733 mVerticalSpacing = spacing;
734 }
735
736 unsigned int Container::getVerticalSpacing() const
737 {
738 return mVerticalSpacing;
739 }
740
741 void Container::setHorizontalSpacing(unsigned int spacing)
742 {
743 mHorizontalSpacing = spacing;
744 }
745
747 {
748 return mHorizontalSpacing;
749 }
750
752 {
753 if (mBackgroundWidget == widget) {
754 return;
755 }
756
757 mBackgroundWidget = widget;
758 }
759
764} // namespace fcn
Represents changes within a container (e.g., widget added/removed).
Interface for listening to container modification events.
virtual bool isUniformSize() const
True if the container tries to expand the childs to a uniform size.
void remove(Widget *widget) override
Removes a widget from the Container.
void draw(Graphics *graphics) override
Draws the widget.
Definition container.cpp:25
bool mOpaque
True if the container is opaque, false otherwise.
virtual void setLayout(LayoutPolicy policy)
Sets the layout of the container.
virtual void setHorizontalSpacing(unsigned int spacing)
Set the horizontal spacing between columns.
void addContainerListener(ContainerListener *containerListener)
Adds a container listener to the container.
Container()
Constructor.
unsigned int mVerticalSpacing
VerticalSpacing.
void distributeWidgetAddedEvent(Widget *source)
Distributes a widget added container event to all container listeners of the container.
LayoutPolicy mLayout
Layout.
unsigned int mHorizontalSpacing
HorizontalSpacing.
Widget * mBackgroundWidget
Optional widget that is rendered behind other children as the container background.
void expandContent()
Expands the child widgets to the size of this widget, calls recursively all childs.
Definition widget.hpp:1597
virtual void setOpacity(float opacity)
Sets the opacity of the container.
Definition container.cpp:72
Widget * findWidgetById(std::string const &id) override
Finds a widget given an id.
void resizeToContent(bool recursion=true) override
Resize this container to fit its children.
virtual bool isOpaque() const
Checks if the container is opaque or not.
Definition container.cpp:88
void distributeWidgetRemovedEvent(Widget *source)
Distributes a widget removed container event to all container listeners of the container.
float mOpacity
Opacity of the container, between 0.0 (fully transparent) and 1.0 (fully opaque).
void setBackgroundWidget(Widget *widget)
Set a widget that will be rendered behind other children as the background.
virtual void add(Widget *widget)
Adds a widget to the container.
Definition container.cpp:93
LayoutPolicy
The layout policy of the container.
Definition container.hpp:50
ContainerListenerList::iterator ContainerListenerIterator
Iterator for ContainerListenerList.
void removeAllChildren() override
Removes all widgets from the the container.
Rectangle getChildrenArea() override
Gets the area of the widget occupied by the widget's children.
virtual void setVerticalSpacing(unsigned int spacing)
Set the vertical spacing between rows.
virtual void addWidget(std::unique_ptr< Widget > widget)
Adds a widget to the container, transferring ownership.
Definition container.cpp:99
bool mUniform
Indicates if the childs should be expanded to a uniform size.
Widget * getBackgroundWidget()
Get the background widget if one is set.
virtual void setUniformSize(bool uniform)
If enabled, the free space is distributed in a way that the size of the childrens will be equal (if p...
virtual LayoutPolicy getLayout() const
Gets the layout of the container.
void removeContainerListener(ContainerListener *containerListener)
Removes a container listener from the container.
virtual unsigned int getHorizontalSpacing() const
Get the horizontal spacing between rows.
void adjustSize() override
Adjust the size of the container after layout computations.
Widget * getChild(unsigned int index) const
Gets child by index.
ContainerListenerList mContainerListeners
The container listeners of the container.
virtual void setOpaque(bool opaque)
Sets the container to be opaque or not.
Definition container.cpp:83
virtual unsigned int getVerticalSpacing() const
Get the vertical spacing between rows.
Abstract interface providing primitive drawing functions (lines, rectangles, etc.).
Definition graphics.hpp:58
virtual void setColor(Color const &color)=0
Sets the color to use when drawing.
virtual void fillRectangle(Rectangle const &rectangle)=0
Draws a filled rectangle.
static num_type pi()
Definition math.hpp:267
Represents a rectangular area (X, Y, Width, Height).
Definition rectangle.hpp:22
int width
Holds the width of the rectangle.
int y
Holds the x coordinate of the rectangle.
int x
Holds the x coordinate of the rectangle.
int height
Holds the height of the rectangle.
Color const & getBaseColor() const
Gets the base color.
Definition widget.cpp:742
std::list< Widget * > const & getChildren() const
Gets the children of the widget.
Definition widget.cpp:1589
bool isHorizontalExpand() const
Gets if widget is horizontal expandable.
Definition widget.cpp:440
unsigned int getChildrenCount() const
Gets how many childs the widget have.
Definition widget.cpp:339
int getWidth() const
Gets the width of the widget.
Definition widget.cpp:252
virtual Widget * getParent() const
Gets the widget's parent container.
Definition widget.cpp:239
void add(Widget *widget)
Adds a child to the widget.
Definition widget.cpp:1446
void resizeToChildren()
Resizes the widget to fit it's children exactly.
Definition widget.cpp:1344
virtual Widget * findWidgetById(std::string const &id)
Finds a widget by id.
Definition widget.cpp:1358
virtual void remove(Widget *widget)
Removes a specific child from the widget.
Definition widget.cpp:1422
virtual bool isFocused() const
Checks if the widget is focused.
Definition widget.cpp:624
virtual void removeAllChildren()
Remvoes all children from the widget.
Definition widget.cpp:1402
unsigned int getPaddingLeft() const
Gets the left padding.
Definition widget.cpp:604
Widget()
Constructor.
Definition widget.cpp:52
virtual void setSize(int width, int height)
Sets the size of the widget.
Definition widget.cpp:1065
void setPosition(int x, int y)
Sets position of the widget.
Definition widget.cpp:306
Rectangle const & getDimension() const
Gets the dimension of the widget.
Definition widget.cpp:609
virtual void drawBorder(Graphics *graphics)
Called when a widget have a border.
Definition widget.cpp:156
unsigned int getPaddingTop() const
Gets the top padding.
Definition widget.cpp:574
unsigned int getBorderSize() const
Gets the size of the widget's border.
Definition widget.cpp:474
virtual void drawSelectionFrame(Graphics *graphics)
Called when a widget is "active" and the selection mode is Frame or FrameWithBackground.
Definition widget.cpp:217
std::list< Widget * > mChildren
Holds all children of the widget.
Definition widget.hpp:2099
unsigned int getPaddingBottom() const
Gets the bottom padding.
Definition widget.cpp:594
SelectionMode getSelectionMode() const
Gets the selection mode.
Definition widget.cpp:802
int getHeight() const
Gets the height of the widget.
Definition widget.cpp:265
unsigned int getPaddingRight() const
Gets the right padding.
Definition widget.cpp:584
Color const & getSelectionColor() const
Gets the selection color.
Definition widget.cpp:772
bool isVerticalExpand() const
Gets if widget is vertical expandable.
Definition widget.cpp:430
unsigned int getBorderSides() const
Get the currently selected border sides.
Definition widget.cpp:484
Used replacement tokens by configure_file():