| 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 | } |