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

@ -48,8 +48,8 @@ namespace Nz
void EnableBackground(bool enable); void EnableBackground(bool enable);
template<typename F> void ForEachWidgetChild(F iterator); template<typename F> void ForEachWidgetChild(F&& iterator, bool onlyVisible = true);
template<typename F> void ForEachWidgetChild(F iterator) const; template<typename F> void ForEachWidgetChild(F&& iterator, bool onlyVisible = true) const;
//virtual BaseWidget* Clone() const = 0; //virtual BaseWidget* Clone() const = 0;
@ -74,6 +74,7 @@ namespace Nz
inline Vector2f GetSize() const; inline Vector2f GetSize() const;
const std::shared_ptr<WidgetTheme>& GetTheme() const; const std::shared_ptr<WidgetTheme>& GetTheme() const;
inline std::size_t GetVisibleWidgetChildCount() const;
inline float GetWidth() const; inline float GetWidth() const;
inline std::size_t GetWidgetChildCount() const; inline std::size_t GetWidgetChildCount() const;
@ -108,6 +109,8 @@ namespace Nz
BaseWidget& operator=(const BaseWidget&) = delete; BaseWidget& operator=(const BaseWidget&) = delete;
BaseWidget& operator=(BaseWidget&&) = delete; BaseWidget& operator=(BaseWidget&&) = delete;
NazaraSignal(OnWidgetResized, const BaseWidget* /*widget*/, const Vector2f& /*size*/);
protected: protected:
virtual void Layout(); virtual void Layout();
@ -125,6 +128,10 @@ namespace Nz
virtual bool IsFocusable() const; virtual bool IsFocusable() const;
inline bool IsInside(float x, float y) const; inline bool IsInside(float x, float y) const;
virtual void OnChildAdded(const BaseWidget* child);
virtual void OnChildPreferredSizeUpdated(const BaseWidget* child);
virtual void OnChildVisibilityUpdated(const BaseWidget* child);
virtual void OnChildRemoved(const BaseWidget* child);
virtual void OnFocusLost(); virtual void OnFocusLost();
virtual void OnFocusReceived(); virtual void OnFocusReceived();
virtual bool OnKeyPressed(const WindowEvent::KeyEvent& key); virtual bool OnKeyPressed(const WindowEvent::KeyEvent& key);
@ -135,8 +142,8 @@ namespace Nz
virtual bool OnMouseButtonPress(int x, int y, Mouse::Button button); virtual bool OnMouseButtonPress(int x, int y, Mouse::Button button);
virtual bool OnMouseButtonRelease(int x, int y, Mouse::Button button); virtual bool OnMouseButtonRelease(int x, int y, Mouse::Button button);
virtual bool OnMouseButtonTriplePress(int x, int y, Mouse::Button button); virtual bool OnMouseButtonTriplePress(int x, int y, Mouse::Button button);
virtual bool OnMouseWheelMoved(int x, int y, float delta);
virtual void OnMouseExit(); virtual void OnMouseExit();
virtual bool OnMouseWheelMoved(int x, int y, float delta);
virtual void OnRenderLayerUpdated(int baseRenderLayer); virtual void OnRenderLayerUpdated(int baseRenderLayer);
virtual void OnParentResized(const Vector2f& newSize); virtual void OnParentResized(const Vector2f& newSize);
virtual bool OnTextEntered(char32_t character, bool repeated); virtual bool OnTextEntered(char32_t character, bool repeated);
@ -173,7 +180,7 @@ namespace Nz
std::shared_ptr<Sprite> m_backgroundSprite; std::shared_ptr<Sprite> m_backgroundSprite;
std::shared_ptr<WidgetTheme> m_theme; std::shared_ptr<WidgetTheme> m_theme;
std::vector<WidgetEntity> m_entities; std::vector<WidgetEntity> m_entities;
std::vector<std::unique_ptr<BaseWidget>> m_children; std::vector<std::unique_ptr<BaseWidget>> m_widgetChilds;
entt::registry* m_registry; entt::registry* m_registry;
Canvas* m_canvas; Canvas* m_canvas;
Color m_backgroundColor; Color m_backgroundColor;
@ -183,7 +190,7 @@ namespace Nz
Vector2f m_minimumSize; Vector2f m_minimumSize;
Vector2f m_preferredSize; Vector2f m_preferredSize;
Vector2f m_size; Vector2f m_size;
BaseWidget* m_widgetParent; BaseWidget* m_parentWidget;
bool m_visible; bool m_visible;
int m_baseRenderLayer; int m_baseRenderLayer;
int m_renderLayerCount; int m_renderLayerCount;

View File

@ -21,7 +21,7 @@ namespace Nz
m_minimumSize(0.f), m_minimumSize(0.f),
m_preferredSize(-1), m_preferredSize(-1),
m_size(50.f, 50.f), m_size(50.f, 50.f),
m_widgetParent(nullptr), m_parentWidget(nullptr),
m_visible(true), m_visible(true),
m_baseRenderLayer(0), m_baseRenderLayer(0),
m_renderLayerCount(1) m_renderLayerCount(1)
@ -44,32 +44,33 @@ namespace Nz
widget->SetBaseRenderLayer(m_baseRenderLayer + m_renderLayerCount); widget->SetBaseRenderLayer(m_baseRenderLayer + m_renderLayerCount);
widget->Show(widget->IsVisible() && m_visible); widget->Show(widget->IsVisible() && m_visible);
m_children.emplace_back(std::move(widget)); m_widgetChilds.emplace_back(std::move(widget));
OnChildAdded(m_widgetChilds.back().get());
} }
inline void BaseWidget::Center() inline void BaseWidget::Center()
{ {
NazaraAssert(m_widgetParent, "Widget has no parent"); NazaraAssert(m_parentWidget, "Widget has no parent");
Vector2f parentSize = m_widgetParent->GetSize(); Vector2f parentSize = m_parentWidget->GetSize();
Vector2f mySize = GetSize(); Vector2f mySize = GetSize();
SetPosition((parentSize.x - mySize.x) / 2.f, (parentSize.y - mySize.y) / 2.f); SetPosition((parentSize.x - mySize.x) / 2.f, (parentSize.y - mySize.y) / 2.f);
} }
inline void BaseWidget::CenterHorizontal() inline void BaseWidget::CenterHorizontal()
{ {
NazaraAssert(m_widgetParent, "Widget has no parent"); NazaraAssert(m_parentWidget, "Widget has no parent");
Vector2f parentSize = m_widgetParent->GetSize(); Vector2f parentSize = m_parentWidget->GetSize();
Vector2f mySize = GetSize(); Vector2f mySize = GetSize();
SetPosition((parentSize.x - mySize.x) / 2.f, GetPosition(CoordSys::Local).y); SetPosition((parentSize.x - mySize.x) / 2.f, GetPosition(CoordSys::Local).y);
} }
inline void BaseWidget::CenterVertical() inline void BaseWidget::CenterVertical()
{ {
NazaraAssert(m_widgetParent, "Widget has no parent"); NazaraAssert(m_parentWidget, "Widget has no parent");
Vector2f parentSize = m_widgetParent->GetSize(); Vector2f parentSize = m_parentWidget->GetSize();
Vector2f mySize = GetSize(); Vector2f mySize = GetSize();
SetPosition(GetPosition(CoordSys::Local).x, (parentSize.y - mySize.y) / 2.f); SetPosition(GetPosition(CoordSys::Local).x, (parentSize.y - mySize.y) / 2.f);
} }
@ -80,17 +81,27 @@ namespace Nz
} }
template<typename F> template<typename F>
inline void BaseWidget::ForEachWidgetChild(F iterator) void BaseWidget::ForEachWidgetChild(F&& iterator, bool onlyVisible)
{ {
for (const auto& child : m_children) for (const auto& child : m_widgetChilds)
{
if (onlyVisible && !child->IsVisible())
continue;
iterator(child.get()); iterator(child.get());
}
} }
template<typename F> template<typename F>
inline void BaseWidget::ForEachWidgetChild(F iterator) const void BaseWidget::ForEachWidgetChild(F&& iterator, bool onlyVisible) const
{ {
for (const auto& child : m_children) for (const auto& child : m_widgetChilds)
iterator(static_cast<const BaseWidget*>(child.get())); {
if (onlyVisible && !child->IsVisible())
continue;
iterator(child.get());
}
} }
inline const Color& BaseWidget::GetBackgroundColor() const inline const Color& BaseWidget::GetBackgroundColor() const
@ -173,6 +184,15 @@ namespace Nz
return m_theme; return m_theme;
} }
inline std::size_t BaseWidget::GetVisibleWidgetChildCount() const
{
std::size_t visibleChild = 0;
for (const auto& child : m_widgetChilds)
visibleChild += (child->IsVisible()) ? 1 : 0;
return visibleChild;
}
inline float BaseWidget::GetWidth() const inline float BaseWidget::GetWidth() const
{ {
return m_size.x; return m_size.x;
@ -180,7 +200,7 @@ namespace Nz
inline std::size_t BaseWidget::GetWidgetChildCount() const inline std::size_t BaseWidget::GetWidgetChildCount() const
{ {
return m_children.size(); return m_widgetChilds.size();
} }
inline void BaseWidget::Hide() inline void BaseWidget::Hide()
@ -227,7 +247,8 @@ namespace Nz
inline void BaseWidget::SetMaximumSize(const Vector2f& maximumSize) inline void BaseWidget::SetMaximumSize(const Vector2f& maximumSize)
{ {
m_maximumSize = maximumSize; m_maximumSize.x = std::max(m_minimumSize.x, maximumSize.x);
m_maximumSize.y = std::max(m_minimumSize.y, maximumSize.y);
Vector2f size = GetSize(); Vector2f size = GetSize();
if (size.x > m_maximumSize.x || size.y > m_maximumSize.y) if (size.x > m_maximumSize.x || size.y > m_maximumSize.y)
@ -252,7 +273,8 @@ namespace Nz
inline void BaseWidget::SetMinimumSize(const Vector2f& minimumSize) inline void BaseWidget::SetMinimumSize(const Vector2f& minimumSize)
{ {
m_minimumSize = minimumSize; m_minimumSize.x = std::min(minimumSize.x, m_maximumSize.x);
m_minimumSize.y = std::min(minimumSize.y, m_maximumSize.y);
Vector2f size = GetSize(); Vector2f size = GetSize();
if (size.x < m_minimumSize.x || size.y < m_minimumSize.y) if (size.x < m_minimumSize.x || size.y < m_minimumSize.y)
@ -294,16 +316,20 @@ namespace Nz
OnRenderLayerUpdated(GetBaseRenderLayer()); OnRenderLayerUpdated(GetBaseRenderLayer());
for (const auto& widgetPtr : m_children) for (const auto& widgetPtr : m_widgetChilds)
widgetPtr->SetBaseRenderLayer(m_baseRenderLayer + m_renderLayerCount); widgetPtr->SetBaseRenderLayer(m_baseRenderLayer + m_renderLayerCount);
} }
} }
inline void BaseWidget::SetPreferredSize(const Vector2f& preferredSize) inline void BaseWidget::SetPreferredSize(const Vector2f& preferredSize)
{ {
m_preferredSize = preferredSize; if (m_preferredSize != preferredSize)
{
m_preferredSize = preferredSize;
//Resize(m_preferredSize); if (m_parentWidget)
m_parentWidget->OnChildPreferredSizeUpdated(this);
}
} }
inline void BaseWidget::SetRenderLayerCount(int renderLayerCount) inline void BaseWidget::SetRenderLayerCount(int renderLayerCount)
@ -311,7 +337,7 @@ namespace Nz
if (m_renderLayerCount != renderLayerCount) if (m_renderLayerCount != renderLayerCount)
{ {
m_renderLayerCount = renderLayerCount; m_renderLayerCount = renderLayerCount;
for (const auto& widgetPtr : m_children) for (const auto& widgetPtr : m_widgetChilds)
widgetPtr->SetBaseRenderLayer(m_baseRenderLayer + m_renderLayerCount); widgetPtr->SetBaseRenderLayer(m_baseRenderLayer + m_renderLayerCount);
} }
} }
@ -323,7 +349,7 @@ namespace Nz
inline void BaseWidget::NotifyParentResized(const Vector2f& newSize) inline void BaseWidget::NotifyParentResized(const Vector2f& newSize)
{ {
for (const auto& widgetPtr : m_children) for (const auto& widgetPtr : m_widgetChilds)
widgetPtr->OnParentResized(newSize); widgetPtr->OnParentResized(newSize);
} }
@ -334,3 +360,4 @@ namespace Nz
} }
#include <Nazara/Widgets/DebugOff.hpp> #include <Nazara/Widgets/DebugOff.hpp>

View File

@ -27,6 +27,13 @@ namespace Nz
BoxLayout& operator=(BoxLayout&&) = delete; BoxLayout& operator=(BoxLayout&&) = delete;
private: private:
void OnChildAdded(const BaseWidget* child) override;
void OnChildPreferredSizeUpdated(const BaseWidget* child) override;
void OnChildVisibilityUpdated(const BaseWidget* child) override;
void OnChildRemoved(const BaseWidget* child) override;
void RecomputePreferredSize();
struct State; struct State;
std::unique_ptr<State> m_state; std::unique_ptr<State> m_state;

View File

@ -11,8 +11,10 @@ namespace Nz
{ {
enum class BoxLayoutOrientation enum class BoxLayoutOrientation
{ {
Horizontal, BottomToTop,
Vertical LeftToRight,
RightToLeft,
TopToBottom
}; };
enum class CheckboxState enum class CheckboxState

View File

@ -134,9 +134,9 @@ namespace Nz
AbstractTextDrawer& textDrawer = GetTextDrawer(); AbstractTextDrawer& textDrawer = GetTextDrawer();
textDrawer.SetMaxLineWidth(GetWidth()); textDrawer.SetMaxLineWidth(GetWidth());
UpdateTextSprite();
} }
UpdateTextSprite();
RefreshCursor(); RefreshCursor();
} }
@ -630,9 +630,17 @@ namespace Nz
void AbstractTextAreaWidget::UpdateTextSprite() 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()); Vector2f textSize = Vector2f(m_textSprite->GetAABB().GetLengths());
SetPreferredSize(textSize);
auto& textNode = GetRegistry().get<NodeComponent>(m_textEntity); auto& textNode = GetRegistry().get<NodeComponent>(m_textEntity);
textNode.SetPosition(s_textAreaPaddingWidth, GetHeight() - s_textAreaPaddingHeight - textSize.y); textNode.SetPosition(s_textAreaPaddingWidth, GetHeight() - s_textAreaPaddingHeight - textSize.y);

View File

@ -34,7 +34,7 @@ namespace Nz
NazaraAssert(parent->GetCanvas(), "Parent has no canvas"); NazaraAssert(parent->GetCanvas(), "Parent has no canvas");
m_canvas = parent->GetCanvas(); m_canvas = parent->GetCanvas();
m_widgetParent = parent; m_parentWidget = parent;
m_registry = &m_canvas->GetRegistry(); m_registry = &m_canvas->GetRegistry();
RegisterToCanvas(); RegisterToCanvas();
@ -75,7 +75,7 @@ namespace Nz
{ {
NazaraAssert(this != m_canvas, "Canvas cannot be destroyed by calling Destroy()"); 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()); OnRenderLayerUpdated(GetBaseRenderLayer());
for (const auto& widgetPtr : m_children) for (const auto& widgetPtr : m_widgetChilds)
widgetPtr->SetBaseRenderLayer(m_baseRenderLayer + m_renderLayerCount); widgetPtr->SetBaseRenderLayer(m_baseRenderLayer + m_renderLayerCount);
} }
@ -128,14 +128,15 @@ namespace Nz
std::unique_ptr<BaseWidget> BaseWidget::ReleaseFromParent() std::unique_ptr<BaseWidget> BaseWidget::ReleaseFromParent()
{ {
if (!m_widgetParent) if (!m_parentWidget)
return {}; 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; }); 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_widgetParent->m_children.end()); assert(it != m_parentWidget->m_widgetChilds.end());
std::unique_ptr<BaseWidget> ownerPtr = std::move(*it); 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; return ownerPtr;
} }
@ -151,6 +152,8 @@ namespace Nz
m_size = newSize; m_size = newSize;
Layout(); Layout();
OnWidgetResized(this, newSize);
} }
void BaseWidget::SetBackgroundColor(const Color& color) void BaseWidget::SetBackgroundColor(const Color& color)
@ -183,7 +186,7 @@ namespace Nz
m_renderingRect = renderingRect; m_renderingRect = renderingRect;
UpdatePositionAndSize(); UpdatePositionAndSize();
for (const auto& widgetPtr : m_children) for (const auto& widgetPtr : m_widgetChilds)
widgetPtr->UpdatePositionAndSize(); widgetPtr->UpdatePositionAndSize();
} }
@ -206,6 +209,9 @@ namespace Nz
} }
ShowChildren(show); ShowChildren(show);
if (m_parentWidget)
m_parentWidget->OnChildVisibilityUpdated(this);
} }
} }
@ -262,6 +268,22 @@ namespace Nz
return false; 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() void BaseWidget::OnFocusLost()
{ {
} }
@ -309,15 +331,15 @@ namespace Nz
return OnMouseButtonPress(x, y, button); return OnMouseButtonPress(x, y, button);
} }
void BaseWidget::OnMouseExit()
{
}
bool BaseWidget::OnMouseWheelMoved(int /*x*/, int /*y*/, float /*delta*/) bool BaseWidget::OnMouseWheelMoved(int /*x*/, int /*y*/, float /*delta*/)
{ {
return false; return false;
} }
void BaseWidget::OnMouseExit()
{
}
void BaseWidget::OnRenderLayerUpdated(int /*firstRenderLayer*/) void BaseWidget::OnRenderLayerUpdated(int /*firstRenderLayer*/)
{ {
} }
@ -338,25 +360,25 @@ namespace Nz
void BaseWidget::ShowChildren(bool show) void BaseWidget::ShowChildren(bool show)
{ {
for (const auto& widgetPtr : m_children) for (const auto& widgetPtr : m_widgetChilds)
widgetPtr->Show(show); widgetPtr->Show(show);
} }
void BaseWidget::DestroyChild(BaseWidget* widget) 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; 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() void BaseWidget::DestroyChildren()
{ {
m_children.clear(); m_widgetChilds.clear();
} }
void BaseWidget::RegisterToCanvas() void BaseWidget::RegisterToCanvas()
@ -375,7 +397,7 @@ namespace Nz
NazaraAssert(oldCanvas == newCanvas, "Transferring a widget between canvas is not yet supported"); NazaraAssert(oldCanvas == newCanvas, "Transferring a widget between canvas is not yet supported");
Node::SetParent(widget); Node::SetParent(widget);
m_widgetParent = widget; m_parentWidget = widget;
Layout(); Layout();
} }
@ -396,9 +418,9 @@ namespace Nz
Rectf scissorRect = GetScissorRect(); Rectf scissorRect = GetScissorRect();
if (m_widgetParent) if (m_parentWidget)
{ {
Rectf parentScissorRect = m_widgetParent->GetScissorRect(); Rectf parentScissorRect = m_parentWidget->GetScissorRect();
if (!scissorRect.Intersect(parentScissorRect, &scissorRect)) if (!scissorRect.Intersect(parentScissorRect, &scissorRect))
scissorRect = parentScissorRect; scissorRect = parentScissorRect;

View File

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

View File

@ -23,7 +23,7 @@ namespace Nz
Vector2f size(drawer.GetBounds().GetLengths()); Vector2f size(drawer.GetBounds().GetLengths());
SetMinimumSize(size); SetMinimumSize(size);
SetPreferredSize(size + Vector2f(20.f, 10.f)); SetPreferredSize(size + Vector2f(20.f, 10.f)); //< corner size (TODO: Retrieve them from theme)
Layout(); Layout();
} }

View File

@ -20,7 +20,7 @@ namespace Nz
{ {
m_canvas = this; m_canvas = this;
BaseWidget::m_registry = &m_registry; BaseWidget::m_registry = &m_registry;
m_widgetParent = nullptr; m_parentWidget = nullptr;
SetBaseRenderLayer(initialRenderLayer); SetBaseRenderLayer(initialRenderLayer);
@ -99,10 +99,10 @@ namespace Nz
if (functor(targetWidget)) if (functor(targetWidget))
return; return;
if (!targetWidget.widget->m_widgetParent) if (!targetWidget.widget->m_parentWidget)
return; return;
widgetIndex = targetWidget.widget->m_widgetParent->m_canvasIndex; widgetIndex = targetWidget.widget->m_parentWidget->m_canvasIndex;
} }
} }

View File

@ -27,7 +27,7 @@ namespace Nz
Vector2f size(drawer.GetBounds().GetLengths()); Vector2f size(drawer.GetBounds().GetLengths());
SetMinimumSize(size); SetMinimumSize(size);
SetPreferredSize(size + Vector2f(20.f, 10.f)); SetPreferredSize(size);
Layout(); Layout();
} }