13 BoxContainer::BoxContainer(Direction direction)
14 : m_Direction(direction) {}
16 BoxContainer::Direction BoxContainer::getDirection()
const {
return m_Direction; }
17 void BoxContainer::setDirection(Direction direction) { m_Direction = direction; }
19 bool BoxContainer::getFillAcross()
const {
return m_FillAcross; }
20 void BoxContainer::setFillAcross(
bool fillAcross) { m_FillAcross = fillAcross; }
22 int32_t BoxContainer::getSpacing()
const {
return m_Spacing; }
23 void BoxContainer::setSpacing(int32_t spacing) { m_Spacing = spacing; }
25 void BoxContainer::setGrowPriority(Component* component, GrowPriority priority)
27 m_GrowPriorities[component] = priority;
30 BoxContainer::GrowPriority BoxContainer::getGrowPriority(Component* component)
const
32 auto priority = m_GrowPriorities.find(component);
33 return priority == m_GrowPriorities.end() ? GrowPriority::NEVER : (*priority).second;
36 void BoxContainer::pushBackSpacer(uint32_t weight)
38 Component* prevComponent = m_Children.empty() ? nullptr : m_Children.back();
39 m_Spacers.emplace_back(prevComponent, weight);
41 mergeSpacers(prevComponent);
44 void BoxContainer::pushFrontSpacer(uint32_t weight)
46 m_Spacers.emplace_back(
nullptr, weight);
48 mergeSpacers(
nullptr);
51 void BoxContainer::layoutChildren()
53 Sml::Rectangle<int32_t> contentArea = getContentArea();
55 size_t countSpacers = m_Spacers.size();
56 size_t countGrowingComponents = computeGrowingComponentsCount(GrowPriority::ALWAYS);
57 uint32_t totalSpacersWeight = computeTotalSpacersWeight();
59 if (m_Direction == Direction::LEFT_TO_RIGHT)
61 int32_t freeWidth = getLayoutWidth() - computeCustomPrefWidth();
62 int32_t widthForSpacers = (countGrowingComponents == 0) ? freeWidth : 0;
63 int32_t widthForGrowingComponents = freeWidth - widthForSpacers;
64 int32_t widthForGrowingComponent = widthForGrowingComponents / countGrowingComponents;
66 int32_t curX = contentArea.pos.x + computeSpacerSize(
nullptr, totalSpacersWeight,
68 int32_t centerY = contentArea.pos.y + contentArea.height / 2;
70 for (Component* child : m_Children)
72 child->setLayoutX(curX);
73 child->setLayoutWidth(child->computePrefWidth());
75 if (getGrowPriority(child) == GrowPriority::ALWAYS)
77 child->setLayoutWidth(child->getLayoutWidth() + widthForGrowingComponent);
80 curX += child->getLayoutWidth() + getSpacing() +
81 computeSpacerSize(child, totalSpacersWeight, widthForSpacers);
83 child->setLayoutHeight(m_FillAcross ? contentArea.height : child->computePrefHeight());
84 child->setLayoutY(centerY - child->getLayoutHeight() / 2);
87 else if (m_Direction == Direction::TOP_TO_BOTTOM)
89 int32_t freeHeight = getLayoutHeight() - computeCustomPrefHeight();
90 int32_t heightForSpacers = (countGrowingComponents == 0) ? freeHeight : 0;
91 int32_t heightForGrowingComponents = freeHeight - heightForSpacers;
92 int32_t heightForGrowingComponent = heightForGrowingComponents / countGrowingComponents;
94 int32_t curY = contentArea.pos.y + computeSpacerSize(
nullptr, totalSpacersWeight,
97 for (Component* child : m_Children)
99 child->setLayoutX(contentArea.pos.x);
100 child->setLayoutWidth(m_FillAcross ? contentArea.width : child->computePrefWidth());
102 child->setLayoutY(curY);
103 child->setLayoutHeight(child->computePrefHeight());
105 if (getGrowPriority(child) == GrowPriority::ALWAYS)
107 child->setLayoutHeight(child->getLayoutHeight() + heightForGrowingComponent);
110 curY += child->getLayoutHeight() + getSpacing() +
111 computeSpacerSize(child, totalSpacersWeight, heightForSpacers);
116 int32_t BoxContainer::computeTotalPrefSizeWithSpacing(SizeDimension sizeDimension)
const
118 int32_t totalPrefSize = getSpacing() * (m_Children.size() - 1);
120 for (Component* child : m_Children)
122 if (sizeDimension == SizeDimension::WIDTH)
124 totalPrefSize += child->computePrefWidth();
128 totalPrefSize += child->computePrefHeight();
132 return totalPrefSize;
135 int32_t BoxContainer::computeMaximumPrefSize(SizeDimension sizeDimension)
const
137 int32_t maxPrefSize = 0;
139 for (Component* child : m_Children)
141 int32_t prefSize = 0;
143 if (sizeDimension == SizeDimension::WIDTH)
145 prefSize = child->computePrefWidth();
149 prefSize = child->computePrefHeight();
152 if (prefSize > maxPrefSize)
154 maxPrefSize = prefSize;
161 int32_t BoxContainer::computeCustomPrefWidth(int32_t height)
const
163 int32_t prefWidth = getInsets().left + getInsets().right;
165 if (m_Children.empty())
170 if (m_Direction == Direction::LEFT_TO_RIGHT)
172 prefWidth += computeTotalPrefSizeWithSpacing(SizeDimension::WIDTH);
174 else if (m_Direction == Direction::TOP_TO_BOTTOM)
176 prefWidth += computeMaximumPrefSize(SizeDimension::WIDTH);
182 int32_t BoxContainer::computeCustomPrefHeight(int32_t width)
const
184 int32_t prefHeight = getInsets().top + getInsets().bottom;
186 if (m_Children.empty())
191 if (m_Direction == Direction::LEFT_TO_RIGHT)
193 prefHeight += computeMaximumPrefSize(SizeDimension::HEIGHT);
195 else if (m_Direction == Direction::TOP_TO_BOTTOM)
197 prefHeight += computeTotalPrefSizeWithSpacing(SizeDimension::HEIGHT);
204 int32_t BoxContainer::computeCustomMinWidth(int32_t height)
const
210 int32_t BoxContainer::computeCustomMinHeight(int32_t width)
const
215 uint32_t BoxContainer::computeTotalSpacersWeight()
const
217 uint32_t totalWeight = 0;
218 for (
const Spacer& spacer : m_Spacers)
220 totalWeight += spacer.weight;
226 int32_t BoxContainer::computeSpacerSize(Component* prev, uint32_t totalWeight,
227 int32_t totalSpacersSize)
const
229 if (totalWeight == 0) {
return 0; }
231 for (
const Spacer& spacer : m_Spacers)
233 if (spacer.prevComponent == prev)
235 return totalSpacersSize * (
static_cast<float>(spacer.weight) /
236 static_cast<float>(totalWeight));
243 void BoxContainer::mergeSpacers(Component* prev)
245 static std::vector<std::list<Spacer>::iterator> spacersToErase;
246 spacersToErase.clear();
248 Spacer newSpacer{prev, 0};
249 for (
auto it = m_Spacers.begin(); it != m_Spacers.end(); ++it)
251 if (it->prevComponent == prev)
253 newSpacer.weight += it->weight;
254 spacersToErase.push_back(it);
258 for (
auto spacerToErase : spacersToErase)
260 m_Spacers.erase(spacerToErase);
263 if (newSpacer.weight > 0)
265 m_Spacers.push_back(newSpacer);
269 size_t BoxContainer::computeGrowingComponentsCount(GrowPriority priority)
const
273 for (
auto pair : m_GrowPriorities)
275 if (pair.second == priority)
284 HBox::HBox() : BoxContainer(BoxContainer::Direction::LEFT_TO_RIGHT) {}
286 VBox::VBox() : BoxContainer(BoxContainer::Direction::TOP_TO_BOTTOM) {}