1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
3 | #include "GUI/BsGUILayoutUtility.h" |
4 | #include "GUI/BsGUIElementBase.h" |
5 | #include "GUI/BsGUILayout.h" |
6 | |
7 | namespace bs |
8 | { |
9 | Vector2I GUILayoutUtility::calcOptimalSize(const GUIElementBase* elem) |
10 | { |
11 | return elem->_calculateLayoutSizeRange().optimal; |
12 | } |
13 | |
14 | Vector2I GUILayoutUtility::calcActualSize(UINT32 width, UINT32 height, GUILayout* layout, bool updateOptimalSizes) |
15 | { |
16 | if (updateOptimalSizes) |
17 | layout->_updateOptimalLayoutSizes(); |
18 | |
19 | return calcActualSizeInternal(width, height, layout); |
20 | } |
21 | |
22 | Vector2I GUILayoutUtility::calcActualSizeInternal(UINT32 width, UINT32 height, GUILayout* layout) |
23 | { |
24 | UINT32 numElements = (UINT32)layout->_getNumChildren(); |
25 | Rect2I* elementAreas = nullptr; |
26 | |
27 | if (numElements > 0) |
28 | elementAreas = bs_stack_new<Rect2I>(numElements); |
29 | |
30 | Rect2I parentArea; |
31 | parentArea.width = width; |
32 | parentArea.height = height; |
33 | |
34 | layout->_getElementAreas(parentArea, elementAreas, numElements, layout->_getCachedChildSizeRanges(), layout->_getCachedSizeRange()); |
35 | |
36 | Rect2I* actualAreas = elementAreas; // We re-use the same array |
37 | for (UINT32 i = 0; i < numElements; i++) |
38 | { |
39 | GUIElementBase* child = layout->_getChild(i); |
40 | Rect2I childArea = elementAreas[i]; |
41 | |
42 | if (child->_getType() == GUIElementBase::Type::Layout || child->_getType() == GUIElementBase::Type::Panel) |
43 | { |
44 | Vector2I childActualSize = calcActualSizeInternal(childArea.width, childArea.height, static_cast<GUILayout*>(child)); |
45 | actualAreas[i].width = (UINT32)childActualSize.x; |
46 | actualAreas[i].height = (UINT32)childActualSize.y; |
47 | } |
48 | else if (child->_getType() == GUIElementBase::Type::Element) |
49 | { |
50 | RectOffset padding = child->_getPadding(); |
51 | |
52 | actualAreas[i].width = elementAreas[i].width + padding.left + padding.right; |
53 | actualAreas[i].height = elementAreas[i].height + padding.top + padding.bottom; |
54 | } |
55 | else |
56 | { |
57 | actualAreas[i].width = elementAreas[i].width; |
58 | actualAreas[i].height = elementAreas[i].height; |
59 | } |
60 | } |
61 | |
62 | Vector2I min; |
63 | Vector2I max; |
64 | |
65 | if (numElements > 0) |
66 | { |
67 | Rect2I childArea = actualAreas[0]; |
68 | |
69 | min = Vector2I(childArea.x, childArea.y); |
70 | max = Vector2I(childArea.x + childArea.width, childArea.y + childArea.height); |
71 | } |
72 | |
73 | for (UINT32 i = 1; i < numElements; i++) |
74 | { |
75 | Rect2I childArea = actualAreas[i]; |
76 | |
77 | min.x = std::min(min.x, childArea.x); |
78 | min.y = std::min(min.y, childArea.y); |
79 | |
80 | max.x = std::max(max.x, childArea.x + (INT32)childArea.width); |
81 | max.y = std::max(max.y, childArea.y + (INT32)childArea.height); |
82 | } |
83 | |
84 | Vector2I actualSize = max - min; |
85 | |
86 | if (elementAreas != nullptr) |
87 | bs_stack_free(elementAreas); |
88 | |
89 | return actualSize; |
90 | } |
91 | } |