@@ -4,6 +4,8 @@ namespace LuaUi
44{
55 void LuaFlex::updateProperties ()
66 {
7+ mGap = propertyValue (" gap" , 0 );
8+ mWrap = propertyValue (" wrap" , false );
79 mHorizontal = propertyValue (" horizontal" , false );
810 mAutoSized = propertyValue (" autoSize" , true );
911 mAlign = propertyValue (" align" , Alignment::Start);
@@ -15,22 +17,16 @@ namespace LuaUi
1517 {
1618 int alignSize (int container, int content, Alignment alignment)
1719 {
18- int alignedPosition = 0 ;
20+ switch (alignment)
1921 {
20- switch (alignment)
21- {
22- case Alignment::Start:
23- alignedPosition = 0 ;
24- break ;
25- case Alignment::Center:
26- alignedPosition = (container - content) / 2 ;
27- break ;
28- case Alignment::End:
29- alignedPosition = container - content;
30- break ;
31- }
22+ case Alignment::Start:
23+ return 0 ;
24+ case Alignment::Center:
25+ return (container - content) / 2 ;
26+ case Alignment::End:
27+ return container - content;
3228 }
33- return alignedPosition ;
29+ return 0 ;
3430 }
3531
3632 float getGrow (WidgetExtension* w)
@@ -41,41 +37,109 @@ namespace LuaUi
4137
4238 void LuaFlex::updateChildren ()
4339 {
44- float totalGrow = 0 ;
40+ const auto & flexChildren = children ();
41+
4542 MyGUI::IntSize childrenSize;
46- for ( auto * w : children () )
43+ if ( mAutoSized )
4744 {
48- w->clearForced ();
49- MyGUI::IntSize size = w->calculateSize ();
50- primary (childrenSize) += primary (size);
51- secondary (childrenSize) = std::max (secondary (childrenSize), secondary (size));
52- totalGrow += getGrow (w);
45+ int measuredPrimary = 0 ;
46+ int measuredSecondary = 0 ;
47+ bool isFirst = true ;
48+ for (auto * w : flexChildren)
49+ {
50+ w->clearForced ();
51+ const MyGUI::IntSize size = w->calculateSize ();
52+ measuredPrimary += primary (size) + (isFirst ? 0 : mGap );
53+ measuredSecondary = std::max (measuredSecondary, secondary (size));
54+ isFirst = false ;
55+ }
56+ primary (childrenSize) = measuredPrimary;
57+ secondary (childrenSize) = measuredSecondary;
58+ mChildrenSize = childrenSize;
5359 }
54- mChildrenSize = childrenSize;
5560
5661 MyGUI::IntSize flexSize = calculateSize ();
57- int growSize = 0 ;
58- float growFactor = 0 ;
59- if (totalGrow > 0 )
60- {
61- growSize = primary (flexSize) - primary (childrenSize);
62- growFactor = growSize / totalGrow;
63- }
6462
65- MyGUI::IntPoint childPosition;
66- primary (childPosition) = alignSize (primary (flexSize) - growSize, primary (childrenSize), mAlign );
67- for (auto * w : children ())
63+ int currentSecondaryAxisPosition = 0 ;
64+ size_t widgetIndex = 0 ;
65+
66+ while (widgetIndex < flexChildren.size ())
6867 {
69- MyGUI::IntSize size = w->calculateSize ();
70- primary (size) += static_cast <int >(growFactor * getGrow (w));
71- float stretch = std::clamp (w->externalValue (" stretch" , 0 .0f ), 0 .0f , 1 .0f );
72- secondary (size) = std::max (secondary (size), static_cast <int >(stretch * secondary (flexSize)));
73- secondary (childPosition) = alignSize (secondary (flexSize), secondary (size), mArrange );
74- w->forcePosition (childPosition);
75- w->forceSize (size);
76- w->updateCoord ();
77- primary (childPosition) += primary (size);
68+ const size_t trackStart = widgetIndex;
69+ int primaryAxisSize = 0 ;
70+ int primaryAxisSizeRemaining = primary (flexSize);
71+ int secondaryAxisSize = 0 ;
72+ float totalPrimaryGrow = 0 ;
73+
74+ while (widgetIndex < flexChildren.size ())
75+ {
76+ auto * w = flexChildren[widgetIndex];
77+ w->clearForced ();
78+
79+ const MyGUI::IntSize size = w->calculateSize ();
80+ const int childPrimary = primary (size);
81+ const int childSecondary = secondary (size);
82+ const bool notFirstOnTrack = (widgetIndex > trackStart);
83+ const int primaryToAdd = childPrimary + (notFirstOnTrack ? mGap : 0 );
84+
85+ if (!mAutoSized && mWrap && notFirstOnTrack && primaryAxisSizeRemaining < primaryToAdd)
86+ break ;
87+
88+ primaryAxisSize += primaryToAdd;
89+ primaryAxisSizeRemaining -= primaryToAdd;
90+ secondaryAxisSize = std::max (childSecondary, secondaryAxisSize);
91+ totalPrimaryGrow += getGrow (w);
92+ widgetIndex++;
93+ }
94+ primaryAxisSizeRemaining = std::max (0 , primaryAxisSizeRemaining);
95+
96+ // Keeping a constant total here ensures widgets that use grow don't use the
97+ // changing 'primaryAxisSizeRemaining' (which shrinks as we take off grown amounts).
98+ const int totalPrimaryAxisSizeRemaining = primaryAxisSizeRemaining;
99+ const int trackPrimarySizeAfterGrow
100+ = primaryAxisSize + (totalPrimaryGrow > 0 ? totalPrimaryAxisSizeRemaining : 0 );
101+ const int primaryAxisChildrenShift = alignSize (primary (flexSize), trackPrimarySizeAfterGrow, mAlign );
102+ int currentPrimaryAxisPosition = primaryAxisChildrenShift;
103+
104+ for (size_t j = trackStart; j < widgetIndex; ++j)
105+ {
106+ auto * w = flexChildren[j];
107+ MyGUI::IntPoint widgetPosition;
108+ MyGUI::IntSize widgetSize = w->calculateSize ();
109+
110+ // Note: Grow is on the primary axis and stretch is "grow" on the cross/secondary axis
111+ const float widgetGrowFactor = getGrow (w);
112+ const float stretch = std::clamp (w->externalValue (" stretch" , 0 .0f ), 0 .0f , 1 .0f );
113+ if (widgetGrowFactor > 0 )
114+ {
115+ const int pixelsToExpandBy = std::clamp (
116+ static_cast <int >(
117+ std::round ((widgetGrowFactor / totalPrimaryGrow) * totalPrimaryAxisSizeRemaining)),
118+ 0 , primaryAxisSizeRemaining);
119+ primary (widgetSize) += pixelsToExpandBy;
120+ primaryAxisSizeRemaining -= pixelsToExpandBy;
121+ }
122+
123+ const int stretchTargetSecondary = mWrap ? secondaryAxisSize : secondary (flexSize);
124+ secondary (widgetSize) = std::max (secondary (widgetSize),
125+ std::clamp (
126+ static_cast <int >(std::round (stretch * stretchTargetSecondary)), 0 , stretchTargetSecondary));
127+
128+ primary (widgetPosition) = currentPrimaryAxisPosition;
129+ currentPrimaryAxisPosition += primary (widgetSize) + mGap ;
130+ const int arrangeTargetSecondary = mWrap ? secondaryAxisSize : secondary (flexSize);
131+ secondary (widgetPosition)
132+ = currentSecondaryAxisPosition + alignSize (arrangeTargetSecondary, secondary (widgetSize), mArrange );
133+
134+ w->forceSize (widgetSize);
135+ w->forcePosition (widgetPosition);
136+ w->updateCoord ();
137+ }
138+
139+ currentSecondaryAxisPosition += secondaryAxisSize + mGap ;
78140 }
141+
142+ mChildrenSize = childrenSize;
79143 WidgetExtension::updateChildren ();
80144 }
81145
@@ -108,7 +172,7 @@ namespace LuaUi
108172 const std::vector<std::string_view>& LuaFlex::allUsedProperties () const
109173 {
110174 static std::vector<std::string_view> usedProps = std::invoke ([this ] {
111- std::vector<std::string_view> props = { " horizontal" , " autoSize" , " arrange" , " align" };
175+ std::vector<std::string_view> props = { " horizontal" , " autoSize" , " arrange" , " align" , " gap " , " wrap " };
112176 auto baseProps = WidgetExtension::allUsedProperties ();
113177 props.insert (props.end (), baseProps.begin (), baseProps.end ());
114178 return props;
0 commit comments