Widgets: Improve BoxLayout
This commit is contained in:
@@ -134,9 +134,9 @@ namespace Nz
|
||||
AbstractTextDrawer& textDrawer = GetTextDrawer();
|
||||
|
||||
textDrawer.SetMaxLineWidth(GetWidth());
|
||||
UpdateTextSprite();
|
||||
}
|
||||
|
||||
UpdateTextSprite();
|
||||
RefreshCursor();
|
||||
}
|
||||
|
||||
@@ -630,9 +630,17 @@ namespace Nz
|
||||
|
||||
void AbstractTextAreaWidget::UpdateTextSprite()
|
||||
{
|
||||
m_textSprite->Update(GetTextDrawer());
|
||||
const AbstractTextDrawer& textDrawer = GetTextDrawer();
|
||||
m_textSprite->Update(textDrawer);
|
||||
|
||||
float preferredHeight = 0.f;
|
||||
std::size_t lineCount = textDrawer.GetLineCount();
|
||||
for (std::size_t i = 0; i < lineCount; ++i)
|
||||
preferredHeight += textDrawer.GetLine(i).bounds.height;
|
||||
|
||||
SetPreferredSize({ -1.f, preferredHeight + s_textAreaPaddingHeight * 2.f });
|
||||
|
||||
Vector2f textSize = Vector2f(m_textSprite->GetAABB().GetLengths());
|
||||
SetPreferredSize(textSize);
|
||||
|
||||
auto& textNode = GetRegistry().get<NodeComponent>(m_textEntity);
|
||||
textNode.SetPosition(s_textAreaPaddingWidth, GetHeight() - s_textAreaPaddingHeight - textSize.y);
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Nz
|
||||
NazaraAssert(parent->GetCanvas(), "Parent has no canvas");
|
||||
|
||||
m_canvas = parent->GetCanvas();
|
||||
m_widgetParent = parent;
|
||||
m_parentWidget = parent;
|
||||
m_registry = &m_canvas->GetRegistry();
|
||||
|
||||
RegisterToCanvas();
|
||||
@@ -75,7 +75,7 @@ namespace Nz
|
||||
{
|
||||
NazaraAssert(this != m_canvas, "Canvas cannot be destroyed by calling Destroy()");
|
||||
|
||||
m_widgetParent->DestroyChild(this); //< This does delete us
|
||||
m_parentWidget->DestroyChild(this); //< This does delete us
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -110,7 +110,7 @@ namespace Nz
|
||||
|
||||
OnRenderLayerUpdated(GetBaseRenderLayer());
|
||||
|
||||
for (const auto& widgetPtr : m_children)
|
||||
for (const auto& widgetPtr : m_widgetChilds)
|
||||
widgetPtr->SetBaseRenderLayer(m_baseRenderLayer + m_renderLayerCount);
|
||||
}
|
||||
|
||||
@@ -128,14 +128,15 @@ namespace Nz
|
||||
|
||||
std::unique_ptr<BaseWidget> BaseWidget::ReleaseFromParent()
|
||||
{
|
||||
if (!m_widgetParent)
|
||||
if (!m_parentWidget)
|
||||
return {};
|
||||
|
||||
auto it = std::find_if(m_widgetParent->m_children.begin(), m_widgetParent->m_children.end(), [&](const std::unique_ptr<BaseWidget>& widgetPtr) { return widgetPtr.get() == this; });
|
||||
assert(it != m_widgetParent->m_children.end());
|
||||
auto it = std::find_if(m_parentWidget->m_widgetChilds.begin(), m_parentWidget->m_widgetChilds.end(), [&](const std::unique_ptr<BaseWidget>& widgetPtr) { return widgetPtr.get() == this; });
|
||||
assert(it != m_parentWidget->m_widgetChilds.end());
|
||||
|
||||
std::unique_ptr<BaseWidget> ownerPtr = std::move(*it);
|
||||
m_widgetParent->m_children.erase(it);
|
||||
m_parentWidget->m_widgetChilds.erase(it);
|
||||
m_parentWidget->OnChildRemoved(this);
|
||||
|
||||
return ownerPtr;
|
||||
}
|
||||
@@ -151,6 +152,8 @@ namespace Nz
|
||||
m_size = newSize;
|
||||
|
||||
Layout();
|
||||
|
||||
OnWidgetResized(this, newSize);
|
||||
}
|
||||
|
||||
void BaseWidget::SetBackgroundColor(const Color& color)
|
||||
@@ -183,7 +186,7 @@ namespace Nz
|
||||
m_renderingRect = renderingRect;
|
||||
|
||||
UpdatePositionAndSize();
|
||||
for (const auto& widgetPtr : m_children)
|
||||
for (const auto& widgetPtr : m_widgetChilds)
|
||||
widgetPtr->UpdatePositionAndSize();
|
||||
}
|
||||
|
||||
@@ -206,6 +209,9 @@ namespace Nz
|
||||
}
|
||||
|
||||
ShowChildren(show);
|
||||
|
||||
if (m_parentWidget)
|
||||
m_parentWidget->OnChildVisibilityUpdated(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,6 +268,22 @@ namespace Nz
|
||||
return false;
|
||||
}
|
||||
|
||||
void BaseWidget::OnChildAdded(const BaseWidget* /*child*/)
|
||||
{
|
||||
}
|
||||
|
||||
void BaseWidget::OnChildPreferredSizeUpdated(const BaseWidget* /*child*/)
|
||||
{
|
||||
}
|
||||
|
||||
void BaseWidget::OnChildVisibilityUpdated(const BaseWidget* /*child*/)
|
||||
{
|
||||
}
|
||||
|
||||
void BaseWidget::OnChildRemoved(const BaseWidget* /*child*/)
|
||||
{
|
||||
}
|
||||
|
||||
void BaseWidget::OnFocusLost()
|
||||
{
|
||||
}
|
||||
@@ -309,15 +331,15 @@ namespace Nz
|
||||
return OnMouseButtonPress(x, y, button);
|
||||
}
|
||||
|
||||
void BaseWidget::OnMouseExit()
|
||||
{
|
||||
}
|
||||
|
||||
bool BaseWidget::OnMouseWheelMoved(int /*x*/, int /*y*/, float /*delta*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void BaseWidget::OnMouseExit()
|
||||
{
|
||||
}
|
||||
|
||||
void BaseWidget::OnRenderLayerUpdated(int /*firstRenderLayer*/)
|
||||
{
|
||||
}
|
||||
@@ -338,25 +360,25 @@ namespace Nz
|
||||
|
||||
void BaseWidget::ShowChildren(bool show)
|
||||
{
|
||||
for (const auto& widgetPtr : m_children)
|
||||
for (const auto& widgetPtr : m_widgetChilds)
|
||||
widgetPtr->Show(show);
|
||||
}
|
||||
|
||||
void BaseWidget::DestroyChild(BaseWidget* widget)
|
||||
{
|
||||
auto it = std::find_if(m_children.begin(), m_children.end(), [widget] (const std::unique_ptr<BaseWidget>& widgetPtr) -> bool
|
||||
auto it = std::find_if(m_widgetChilds.begin(), m_widgetChilds.end(), [widget] (const std::unique_ptr<BaseWidget>& widgetPtr) -> bool
|
||||
{
|
||||
return widgetPtr.get() == widget;
|
||||
});
|
||||
|
||||
NazaraAssert(it != m_children.end(), "Child widget not found in parent");
|
||||
NazaraAssert(it != m_widgetChilds.end(), "Child widget not found in parent");
|
||||
|
||||
m_children.erase(it);
|
||||
m_widgetChilds.erase(it);
|
||||
}
|
||||
|
||||
void BaseWidget::DestroyChildren()
|
||||
{
|
||||
m_children.clear();
|
||||
m_widgetChilds.clear();
|
||||
}
|
||||
|
||||
void BaseWidget::RegisterToCanvas()
|
||||
@@ -375,7 +397,7 @@ namespace Nz
|
||||
NazaraAssert(oldCanvas == newCanvas, "Transferring a widget between canvas is not yet supported");
|
||||
|
||||
Node::SetParent(widget);
|
||||
m_widgetParent = widget;
|
||||
m_parentWidget = widget;
|
||||
|
||||
Layout();
|
||||
}
|
||||
@@ -396,9 +418,9 @@ namespace Nz
|
||||
|
||||
Rectf scissorRect = GetScissorRect();
|
||||
|
||||
if (m_widgetParent)
|
||||
if (m_parentWidget)
|
||||
{
|
||||
Rectf parentScissorRect = m_widgetParent->GetScissorRect();
|
||||
Rectf parentScissorRect = m_parentWidget->GetScissorRect();
|
||||
|
||||
if (!scissorRect.Intersect(parentScissorRect, &scissorRect))
|
||||
scissorRect = parentScissorRect;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Nz
|
||||
|
||||
Vector2f size(drawer.GetBounds().GetLengths());
|
||||
SetMinimumSize(size);
|
||||
SetPreferredSize(size + Vector2f(20.f, 10.f));
|
||||
SetPreferredSize(size + Vector2f(20.f, 10.f)); //< corner size (TODO: Retrieve them from theme)
|
||||
|
||||
Layout();
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Nz
|
||||
{
|
||||
m_canvas = this;
|
||||
BaseWidget::m_registry = &m_registry;
|
||||
m_widgetParent = nullptr;
|
||||
m_parentWidget = nullptr;
|
||||
|
||||
SetBaseRenderLayer(initialRenderLayer);
|
||||
|
||||
@@ -99,10 +99,10 @@ namespace Nz
|
||||
if (functor(targetWidget))
|
||||
return;
|
||||
|
||||
if (!targetWidget.widget->m_widgetParent)
|
||||
if (!targetWidget.widget->m_parentWidget)
|
||||
return;
|
||||
|
||||
widgetIndex = targetWidget.widget->m_widgetParent->m_canvasIndex;
|
||||
widgetIndex = targetWidget.widget->m_parentWidget->m_canvasIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Nz
|
||||
|
||||
Vector2f size(drawer.GetBounds().GetLengths());
|
||||
SetMinimumSize(size);
|
||||
SetPreferredSize(size + Vector2f(20.f, 10.f));
|
||||
SetPreferredSize(size);
|
||||
|
||||
Layout();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user