Widgets: Improve BoxLayout

This commit is contained in:
SirLynix
2023-05-14 18:53:56 +02:00
parent f1cd5ad048
commit 3712b641f8
10 changed files with 223 additions and 79 deletions

View File

@@ -33,20 +33,25 @@ namespace Nz
BaseWidget::Layout();
std::size_t axis;
bool reversed;
switch (m_orientation)
{
case BoxLayoutOrientation::Horizontal:
case BoxLayoutOrientation::LeftToRight:
case BoxLayoutOrientation::RightToLeft:
axis = 0; //< x
reversed = (m_orientation == BoxLayoutOrientation::RightToLeft);
break;
case BoxLayoutOrientation::Vertical:
case BoxLayoutOrientation::BottomToTop:
case BoxLayoutOrientation::TopToBottom:
axis = 1; //< y
reversed = (m_orientation == BoxLayoutOrientation::TopToBottom);
break;
}
//TODO: Keep solver state when widgets don't change
std::size_t widgetChildCount = GetWidgetChildCount();
std::size_t widgetChildCount = GetVisibleWidgetChildCount();
if (widgetChildCount == 0)
return;
@@ -58,27 +63,36 @@ namespace Nz
kiwi::Expression sizeSum;
Nz::Vector2f layoutSize = GetSize();
float availableSpace = layoutSize[axis] - m_spacing * (widgetChildCount - 1);
float perfectSpacePerWidget = availableSpace / widgetChildCount;
float maxLayoutSize = layoutSize[axis];
float availableSpace = maxLayoutSize - m_spacing * (widgetChildCount - 1);
// Handle size
ForEachWidgetChild([&](BaseWidget* child)
{
if (!child->IsVisible())
return;
float maximumSize = child->GetMaximumSize()[axis];
float minimumSize = child->GetMinimumSize()[axis];
float preferredSize = child->GetPreferredSize()[axis];
m_state->sizeVar.emplace_back();
auto& sizeVar = m_state->sizeVar.back();
m_state->solver.addConstraint({ (sizeVar >= minimumSize) | kiwi::strength::required });
if (maximumSize < std::numeric_limits<float>::infinity())
if (maximumSize < std::numeric_limits<float>::infinity() && maximumSize <= minimumSize)
m_state->solver.addConstraint({ (sizeVar <= maximumSize) | kiwi::strength::required });
m_state->solver.addConstraint({ (sizeVar >= perfectSpacePerWidget) | kiwi::strength::medium });
if (preferredSize > 0.f)
{
m_state->solver.addConstraint({ (sizeVar >= preferredSize) | kiwi::strength::medium });
m_state->solver.addConstraint({ (sizeVar >= maxLayoutSize) | kiwi::strength::weak });
}
else if (maximumSize < std::numeric_limits<float>::infinity() && maximumSize <= minimumSize)
{
m_state->solver.addConstraint({ (sizeVar >= maximumSize) | kiwi::strength::medium });
m_state->solver.addConstraint({ (sizeVar >= maxLayoutSize) | kiwi::strength::weak });
}
else
m_state->solver.addConstraint({ (sizeVar >= maxLayoutSize) | kiwi::strength::medium });
sizeSum = sizeSum + sizeVar;
});
@@ -98,11 +112,8 @@ namespace Nz
ForEachWidgetChild([&](BaseWidget* child)
{
if (!child->IsVisible())
return;
Nz::Vector2f newSize = layoutSize;
newSize[axis] = SafeCast<float>(m_state->sizeVar[varIndex].value());
newSize[axis] = static_cast<float>(m_state->sizeVar[varIndex].value());
child->Resize(newSize);
remainingSize -= newSize[axis];
@@ -113,21 +124,81 @@ namespace Nz
float spacing = m_spacing + remainingSize / (widgetChildCount - 1);
// Handle position
float cursor = 0.f;
bool first = true;
float cursor = (reversed) ? layoutSize[axis] : 0.f;
ForEachWidgetChild([&](BaseWidget* child)
{
if (first)
first = false;
else
cursor += spacing;
if (reversed)
cursor -= child->GetSize()[axis];
Nz::Vector2f position = Nz::Vector2f(0.f, 0.f);
position[axis] = cursor;
Nz::Vector2f position(0.f, 0.f);
position[axis] = cursor ;
child->SetPosition(position);
cursor += child->GetSize()[axis];
if (reversed)
cursor -= spacing;
else
cursor += child->GetSize()[axis] + spacing;
});
}
void BoxLayout::OnChildAdded(const BaseWidget* /*child*/)
{
RecomputePreferredSize();
Layout();
}
void BoxLayout::OnChildPreferredSizeUpdated(const BaseWidget* /*child*/)
{
Layout();
}
void BoxLayout::OnChildVisibilityUpdated(const BaseWidget* /*child*/)
{
RecomputePreferredSize();
Layout();
}
void BoxLayout::OnChildRemoved(const BaseWidget* /*child*/)
{
RecomputePreferredSize();
Layout();
}
void BoxLayout::RecomputePreferredSize()
{
std::size_t axis;
std::size_t otherAxis;
switch (m_orientation)
{
case BoxLayoutOrientation::LeftToRight:
case BoxLayoutOrientation::RightToLeft:
axis = 0;
otherAxis = 1;
break;
case BoxLayoutOrientation::BottomToTop:
case BoxLayoutOrientation::TopToBottom:
axis = 1;
otherAxis = 0;
break;
}
float childCount = 0.f;
Vector2f preferredSize;
ForEachWidgetChild([&](const BaseWidget* child)
{
const Vector2f& childPreferredSize = child->GetPreferredSize();
preferredSize[axis] += childPreferredSize[axis];
preferredSize[otherAxis] = std::max(preferredSize[otherAxis], childPreferredSize[otherAxis]);
childCount += 1.f;
});
if (childCount > 1.f)
preferredSize[axis] += m_spacing * (childCount - 1.f);
SetPreferredSize(preferredSize);
}
}