* Layout WIP

* Widgets/BoxLayout: Fix layout algorithm

* Widgets/BoxLayout: Fix box layout algorithm for good

* SDK/Widgets: Remove padding

* Sdk/Widgets: Make use of minimum/preferred size

* Sdk/TextAreaWidget: Add Minimum/PreferredSize to TextArea

* Sdk/Widgets: Add height/width variants of get/set fixed, maximum, minimum and preferred size methods

* Sdk/BoxLayout: Remove useless code

* Sdk/TextAreaWidget: Fix compilation

* Widgets/TextAreaWidget: Fix cursor position
This commit is contained in:
Jérôme Leclercq 2018-09-11 21:03:44 +02:00 committed by GitHub
parent d99ae411c6
commit 53aa9ea170
29 changed files with 470 additions and 162 deletions

View File

@ -46,44 +46,61 @@ namespace Ndk
void EnableBackground(bool enable);
template<typename F> void ForEachWidgetChild(F iterator);
template<typename F> void ForEachWidgetChild(F iterator) const;
//virtual BaseWidget* Clone() const = 0;
inline const Nz::Color& GetBackgroundColor() const;
inline Canvas* GetCanvas();
inline Nz::SystemCursor GetCursor() const;
inline const Padding& GetPadding() const;
inline Nz::Vector2f GetContentOrigin() const;
inline const Nz::Vector2f& GetContentSize() const;
inline float GetHeight() const;
inline float GetMaximumHeight() const;
inline Nz::Vector2f GetMaximumSize() const;
inline float GetMaximumWidth() const;
inline float GetMinimumHeight() const;
inline Nz::Vector2f GetMinimumSize() const;
inline float GetMinimumWidth() const;
inline float GetPreferredHeight() const;
inline Nz::Vector2f GetPreferredSize() const;
inline float GetPreferredWidth() const;
inline Nz::Vector2f GetSize() const;
inline float GetWidth() const;
inline std::size_t GetWidgetChildCount() const;
bool HasFocus() const;
inline bool IsVisible() const;
virtual void ResizeToContent() = 0;
void Resize(const Nz::Vector2f& size);
void SetBackgroundColor(const Nz::Color& color);
void SetCursor(Nz::SystemCursor systemCursor);
inline void SetContentSize(const Nz::Vector2f& size);
void SetFocus();
inline void SetPadding(float left, float top, float right, float bottom);
void SetSize(const Nz::Vector2f& size);
inline void SetFixedHeight(float fixedHeight);
inline void SetFixedSize(const Nz::Vector2f& fixedSize);
inline void SetFixedWidth(float fixedWidth);
inline void SetMaximumHeight(float maximumHeight);
inline void SetMaximumSize(const Nz::Vector2f& maximumSize);
inline void SetMaximumWidth(float maximumWidth);
inline void SetMinimumHeight(float minimumHeight);
inline void SetMinimumSize(const Nz::Vector2f& minimumSize);
inline void SetMinimumWidth(float minimumWidth);
void Show(bool show = true);
BaseWidget& operator=(const BaseWidget&) = delete;
BaseWidget& operator=(BaseWidget&&) = delete;
struct Padding
{
float left;
float top;
float right;
float bottom;
};
protected:
const EntityHandle& CreateEntity(bool isContentEntity);
const EntityHandle& CreateEntity();
void DestroyEntity(Entity* entity);
virtual void Layout();
@ -102,10 +119,12 @@ namespace Ndk
virtual void OnParentResized(const Nz::Vector2f& newSize);
virtual void OnTextEntered(char32_t character, bool repeated);
inline void SetPreferredSize(const Nz::Vector2f& preferredSize);
private:
inline BaseWidget();
inline void DestroyChild(BaseWidget* widget);
void DestroyChild(BaseWidget* widget);
void DestroyChildren();
inline bool IsRegisteredToCanvas() const;
inline void NotifyParentResized(const Nz::Vector2f& newSize);
@ -117,7 +136,6 @@ namespace Ndk
struct WidgetEntity
{
EntityOwner handle;
bool isContent;
};
static constexpr std::size_t InvalidCanvasIndex = std::numeric_limits<std::size_t>::max();
@ -127,12 +145,14 @@ namespace Ndk
std::vector<std::unique_ptr<BaseWidget>> m_children;
Canvas* m_canvas;
EntityOwner m_backgroundEntity;
Padding m_padding;
WorldHandle m_world;
Nz::Color m_backgroundColor;
Nz::SpriteRef m_backgroundSprite;
Nz::SystemCursor m_cursor;
Nz::Vector2f m_contentSize;
Nz::Vector2f m_maximumSize;
Nz::Vector2f m_minimumSize;
Nz::Vector2f m_preferredSize;
Nz::Vector2f m_size;
BaseWidget* m_widgetParent;
bool m_visible;
};

View File

@ -13,11 +13,13 @@ namespace Ndk
m_canvas(nullptr),
m_backgroundColor(Nz::Color(230, 230, 230, 255)),
m_cursor(Nz::SystemCursor_Default),
m_contentSize(50.f, 50.f),
m_size(50.f, 50.f),
m_maximumSize(std::numeric_limits<float>::infinity()),
m_minimumSize(0.f),
m_preferredSize(-1),
m_widgetParent(nullptr),
m_visible(true)
{
SetPadding(5.f, 5.f, 5.f, 5.f);
}
template<typename T, typename... Args>
@ -64,6 +66,20 @@ namespace Ndk
SetPosition(GetPosition(Nz::CoordSys_Local).x, (parentSize.y - mySize.y) / 2.f);
}
template<typename F>
inline void BaseWidget::ForEachWidgetChild(F iterator)
{
for (const auto& child : m_children)
iterator(child.get());
}
template<typename F>
inline void BaseWidget::ForEachWidgetChild(F iterator) const
{
for (const auto& child : m_children)
iterator(static_cast<const BaseWidget*>(child.get()));
}
inline const Nz::Color& BaseWidget::GetBackgroundColor() const
{
return m_backgroundColor;
@ -79,24 +95,69 @@ namespace Ndk
return m_cursor;
}
inline const BaseWidget::Padding& BaseWidget::GetPadding() const
inline float BaseWidget::GetHeight() const
{
return m_padding;
return m_size.y;
}
inline Nz::Vector2f BaseWidget::GetContentOrigin() const
inline float BaseWidget::GetMaximumHeight() const
{
return { m_padding.left, m_padding.top };
return m_maximumSize.y;
}
inline const Nz::Vector2f& BaseWidget::GetContentSize() const
inline Nz::Vector2f BaseWidget::GetMaximumSize() const
{
return m_contentSize;
return m_maximumSize;
}
inline float BaseWidget::GetMaximumWidth() const
{
return m_maximumSize.x;
}
inline float BaseWidget::GetMinimumHeight() const
{
return m_minimumSize.y;
}
inline Nz::Vector2f BaseWidget::GetMinimumSize() const
{
return m_minimumSize;
}
inline float BaseWidget::GetMinimumWidth() const
{
return m_minimumSize.x;
}
inline float BaseWidget::GetPreferredHeight() const
{
return m_preferredSize.y;
}
inline Nz::Vector2f BaseWidget::GetPreferredSize() const
{
return m_preferredSize;
}
inline float BaseWidget::GetPreferredWidth() const
{
return m_preferredSize.x;
}
inline Nz::Vector2f BaseWidget::GetSize() const
{
return Nz::Vector2f(m_contentSize.x + m_padding.left + m_padding.right, m_contentSize.y + m_padding.top + m_padding.bottom);
return Nz::Vector2f(GetWidth(), GetHeight());
}
inline float BaseWidget::GetWidth() const
{
return m_size.x;
}
inline std::size_t BaseWidget::GetWidgetChildCount() const
{
return m_children.size();
}
inline bool BaseWidget::IsVisible() const
@ -104,22 +165,79 @@ namespace Ndk
return m_visible;
}
inline void BaseWidget::SetContentSize(const Nz::Vector2f& size)
inline void BaseWidget::SetFixedHeight(float fixedHeight)
{
NotifyParentResized(size);
m_contentSize = size;
Layout();
SetMaximumHeight(fixedHeight);
SetMinimumHeight(fixedHeight);
}
inline void BaseWidget::SetPadding(float left, float top, float right, float bottom)
inline void BaseWidget::SetFixedSize(const Nz::Vector2f& fixedSize)
{
m_padding.left = left;
m_padding.top = top;
m_padding.bottom = bottom;
m_padding.right = right;
SetMaximumSize(fixedSize);
SetMinimumSize(fixedSize);
}
Layout();
inline void BaseWidget::SetFixedWidth(float fixedWidth)
{
SetMaximumWidth(fixedWidth);
SetMinimumWidth(fixedWidth);
}
inline void BaseWidget::SetMaximumHeight(float maximumHeight)
{
Nz::Vector2f maximumSize = GetMaximumSize();
maximumSize.y = maximumHeight;
SetMaximumSize(maximumSize);
}
inline void BaseWidget::SetMaximumSize(const Nz::Vector2f& maximumSize)
{
m_maximumSize = maximumSize;
Nz::Vector2f size = GetSize();
if (size.x > m_maximumSize.x || size.y > m_maximumSize.y)
Resize(size); //< Will clamp automatically
}
inline void BaseWidget::SetMaximumWidth(float maximumWidth)
{
Nz::Vector2f maximumSize = GetMaximumSize();
maximumSize.x = maximumWidth;
SetMaximumSize(maximumSize);
}
inline void BaseWidget::SetMinimumHeight(float minimumHeight)
{
Nz::Vector2f minimumSize = GetMinimumSize();
minimumSize.y = minimumHeight;
SetMinimumSize(minimumSize);
}
inline void BaseWidget::SetMinimumSize(const Nz::Vector2f& minimumSize)
{
m_minimumSize = minimumSize;
Nz::Vector2f size = GetSize();
if (size.x < m_minimumSize.x || size.y < m_minimumSize.y)
Resize(size); //< Will clamp automatically
}
inline void BaseWidget::SetMinimumWidth(float minimumWidth)
{
Nz::Vector2f minimumSize = GetMinimumSize();
minimumSize.x = minimumWidth;
SetMinimumSize(minimumSize);
}
inline void BaseWidget::SetPreferredSize(const Nz::Vector2f& preferredSize)
{
m_preferredSize = preferredSize;
Resize(m_preferredSize);
}
inline bool BaseWidget::IsRegisteredToCanvas() const

View File

@ -28,8 +28,6 @@ namespace Ndk
inline const WorldHandle& GetWorld() const;
void ResizeToContent() override;
Canvas& operator=(const Canvas&) = delete;
Canvas& operator=(Canvas&&) = delete;

View File

@ -27,9 +27,6 @@ namespace Ndk
m_mouseMovedSlot.Connect(eventHandler.OnMouseMoved, this, &Canvas::OnEventMouseMoved);
m_mouseLeftSlot.Connect(eventHandler.OnMouseLeft, this, &Canvas::OnEventMouseLeft);
m_textEnteredSlot.Connect(eventHandler.OnTextEntered, this, &Canvas::OnEventTextEntered);
// Disable padding by default
SetPadding(0.f, 0.f, 0.f, 0.f);
}
inline Canvas::~Canvas()

View File

@ -0,0 +1,48 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
#pragma once
#ifndef NDK_WIDGETS_BOXLAYOUT_HPP
#define NDK_WIDGETS_BOXLAYOUT_HPP
#include <NDK/Prerequisites.hpp>
#include <NDK/BaseWidget.hpp>
#include <NDK/Widgets/Enums.hpp>
#include <vector>
namespace Ndk
{
class NDK_API BoxLayout : public BaseWidget
{
public:
inline BoxLayout(BaseWidget* parent, BoxLayoutOrientation orientation);
BoxLayout(const BoxLayout&) = delete;
BoxLayout(BoxLayout&&) = default;
~BoxLayout() = default;
void Layout() override;
BoxLayout& operator=(const BoxLayout&) = delete;
BoxLayout& operator=(BoxLayout&&) = default;
private:
struct ChildInfo
{
BaseWidget* widget;
bool isConstrained;
float maximumSize;
float minimumSize;
float size;
};
std::vector<ChildInfo> m_childInfos;
BoxLayoutOrientation m_orientation;
float m_spacing;
};
}
#include <NDK/Widgets/BoxLayout.inl>
#endif // NDK_WIDGETS_BOXLAYOUT_HPP

View File

@ -0,0 +1,15 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
#include <NDK/Widgets/BoxLayout.hpp>
namespace Ndk
{
BoxLayout::BoxLayout(BaseWidget* parent, BoxLayoutOrientation orientation) :
BaseWidget(parent),
m_orientation(orientation),
m_spacing(5.f)
{
}
}

View File

@ -28,10 +28,6 @@ namespace Ndk
ButtonWidget(ButtonWidget&&) = default;
~ButtonWidget() = default;
//virtual ButtonWidget* Clone() const = 0;
void ResizeToContent() override;
inline const Nz::Color& GetColor() const;
inline const Nz::Color& GetCornerColor() const;
inline const Nz::Color& GetHoverColor() const;

View File

@ -93,6 +93,10 @@ namespace Ndk
{
m_textSprite->Update(drawer);
Nz::Vector2f textSize = Nz::Vector2f(m_textSprite->GetBoundingVolume().obb.localBox.GetLengths());
SetMinimumSize(textSize);
SetPreferredSize(textSize + Nz::Vector2f(20.f, 10.f));
Layout();
}
}

View File

@ -53,7 +53,6 @@ namespace Ndk
void SetState(CheckboxState state);
inline void SetTextMargin(float margin);
void ResizeToContent() override;
inline void UpdateText(const Nz::AbstractTextDrawer& drawer);
@ -68,6 +67,7 @@ namespace Ndk
void Layout() override;
void UpdateCheckbox();
void UpdateSize();
void OnMouseButtonRelease(int x, int y, Nz::Mouse::Button button) override;
inline bool ContainsCheckbox(int x, int y) const;

View File

@ -65,6 +65,7 @@ namespace Ndk
m_checkboxBackgroundSprite->SetSize(size - GetCheckboxBorderSize() * 2.f);
m_checkboxContentSprite->SetSize(GetCheckboxSize() - GetCheckboxBorderSize() * 2.f - Nz::Vector2f { 4.f, 4.f });
UpdateSize();
Layout();
}
@ -77,6 +78,8 @@ namespace Ndk
inline void CheckboxWidget::UpdateText(const Nz::AbstractTextDrawer& drawer)
{
m_textSprite->Update(drawer);
UpdateSize();
Layout();
}

View File

@ -9,6 +9,12 @@
namespace Ndk
{
enum BoxLayoutOrientation
{
BoxLayoutOrientation_Horizontal,
BoxLayoutOrientation_Vertical
};
enum CheckboxState
{
CheckboxState_Checked,

View File

@ -26,14 +26,14 @@ namespace Ndk
//virtual ImageWidget* Clone() const = 0;
void ResizeToContent() override;
void ResizeToContent();
inline const Nz::Color& GetColor() const;
inline const Nz::TextureRef& GetTexture() const;
inline const Nz::Rectf& GetTextureCoords() const;
inline void SetColor(const Nz::Color& color);
inline void SetTexture(const Nz::TextureRef& texture, bool resizeToContent = true);
inline void SetTexture(const Nz::TextureRef& texture);
inline void SetTextureCoords(const Nz::Rectf& coords);
inline void SetTextureRect(const Nz::Rectui& rect);

View File

@ -26,12 +26,13 @@ namespace Ndk
m_sprite->SetColor(color);
}
inline void ImageWidget::SetTexture(const Nz::TextureRef& texture, bool resizeToContent)
inline void ImageWidget::SetTexture(const Nz::TextureRef& texture)
{
m_sprite->SetTexture(texture, false);
if (resizeToContent)
ResizeToContent();
Nz::Vector2f textureSize = Nz::Vector2f(Nz::Vector2ui(m_sprite->GetMaterial()->GetDiffuseMap()->GetSize()));
SetMinimumSize(textureSize);
SetPreferredSize(textureSize);
}
inline void ImageWidget::SetTextureCoords(const Nz::Rectf& coords)

View File

@ -26,10 +26,6 @@ namespace Ndk
LabelWidget(LabelWidget&&) = default;
~LabelWidget() = default;
//virtual LabelWidget* Clone() const = 0;
void ResizeToContent() override;
inline void UpdateText(const Nz::AbstractTextDrawer& drawer);
LabelWidget& operator=(const LabelWidget&) = delete;

View File

@ -9,5 +9,8 @@ namespace Ndk
inline void LabelWidget::UpdateText(const Nz::AbstractTextDrawer& drawer)
{
m_textSprite->Update(drawer);
SetMinimumSize(Nz::Vector2f(m_textSprite->GetBoundingVolume().obb.localBox.GetLengths()));
SetPreferredSize(Nz::Vector2f(m_textSprite->GetBoundingVolume().obb.localBox.GetLengths()));
}
}

View File

@ -67,8 +67,6 @@ namespace Ndk
inline void SetTextMargin(float margin);
inline void SetTextColor(const Nz::Color& color);
inline void ResizeToContent() override {}
NazaraSignal(OnValueChanged, const ProgressBarWidget* /*progressBar*/);
private:

View File

@ -1,4 +1,4 @@
// Copyright (C) 2017 Samy Bensaid
// Copyright (C) 2017 Samy Bensaid
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
@ -148,9 +148,8 @@ namespace Ndk
{
if (IsTextEnabled())
{
Nz::Vector2f size = GetContentSize();
m_textSprite->Update(Nz::SimpleTextDrawer::Draw(Nz::String::Number(m_value).Append('%'),
static_cast<unsigned>(std::min(size.x, size.y) / 2.f), 0u, m_textColor));
Nz::Vector2f size = GetSize();
m_textSprite->Update(Nz::SimpleTextDrawer::Draw(Nz::String::Number(m_value).Append('%'), static_cast<unsigned int>(std::min(size.x, size.y) / 2.f), 0u, m_textColor));
}
}
}

View File

@ -11,8 +11,8 @@
#include <Nazara/Utility/SimpleTextDrawer.hpp>
#include <NDK/BaseWidget.hpp>
#include <NDK/Widgets/Enums.hpp>
#include <vector>
#include <functional>
#include <vector>
namespace Ndk
{
@ -40,7 +40,7 @@ namespace Ndk
void Erase(std::size_t firstGlyph, std::size_t lastGlyph);
void EraseSelection();
inline CharacterFilter GetCharacterFilter() const;
inline const CharacterFilter& GetCharacterFilter() const;
inline unsigned int GetCharacterSize() const;
inline const Nz::Vector2ui& GetCursorPosition() const;
inline Nz::Vector2ui GetCursorPosition(std::size_t glyphIndex) const;
@ -61,10 +61,8 @@ namespace Ndk
inline void MoveCursor(int offset);
inline void MoveCursor(const Nz::Vector2i& offset);
void ResizeToContent() override;
inline void SetCharacterFilter(CharacterFilter filter);
inline void SetCharacterSize(unsigned int characterSize);
void SetCharacterSize(unsigned int characterSize);
inline void SetCursorPosition(std::size_t glyphIndex);
inline void SetCursorPosition(Nz::Vector2ui cursorPosition);
inline void SetEchoMode(EchoMode echoMode);
@ -108,7 +106,7 @@ namespace Ndk
void RefreshCursor();
void UpdateDisplayText();
std::function<bool(char32_t)> m_characterFilter;
CharacterFilter m_characterFilter;
EchoMode m_echoMode;
EntityHandle m_cursorEntity;
EntityHandle m_textEntity;

View File

@ -33,7 +33,7 @@ namespace Ndk
Erase(glyphPosition, glyphPosition + 1U);
}
inline TextAreaWidget::CharacterFilter TextAreaWidget::GetCharacterFilter() const
inline const TextAreaWidget::CharacterFilter& TextAreaWidget::GetCharacterFilter() const
{
return m_characterFilter;
}
@ -162,12 +162,7 @@ namespace Ndk
inline void TextAreaWidget::SetCharacterFilter(CharacterFilter filter)
{
m_characterFilter = filter;
}
inline void TextAreaWidget::SetCharacterSize(unsigned int characterSize)
{
m_drawer.SetCharacterSize(characterSize);
m_characterFilter = std::move(filter);
}
inline void TextAreaWidget::SetCursorPosition(std::size_t glyphIndex)

View File

@ -81,7 +81,7 @@ namespace Ndk
m_backgroundSprite->SetColor(m_backgroundColor);
m_backgroundSprite->SetMaterial(Nz::Material::New((m_backgroundColor.IsOpaque()) ? "Basic2D" : "Translucent2D")); //< TODO: Use a shared material instead of creating one everytime
m_backgroundEntity = CreateEntity(false);
m_backgroundEntity = CreateEntity();
m_backgroundEntity->AddComponent<GraphicsComponent>().Attach(m_backgroundSprite, -1);
m_backgroundEntity->AddComponent<NodeComponent>().SetParent(this);
@ -89,14 +89,14 @@ namespace Ndk
}
else
{
m_backgroundEntity->Kill();
m_backgroundEntity.Reset();
m_backgroundSprite.Reset();
}
}
/*!
* \brief Checks if this widget has keyboard focus
* \return true if widget has keyboard focus, false otherwhise
* \return true if widget has keyboard focus, false otherwise
*/
bool BaseWidget::HasFocus() const
{
@ -106,6 +106,19 @@ namespace Ndk
return m_canvas->IsKeyboardOwner(m_canvasIndex);
}
void BaseWidget::Resize(const Nz::Vector2f& size)
{
// Adjust new size
Nz::Vector2f newSize = size;
newSize.Maximize(m_minimumSize);
newSize.Minimize(m_maximumSize);
NotifyParentResized(newSize);
m_size = newSize;
Layout();
}
void BaseWidget::SetBackgroundColor(const Nz::Color& color)
{
m_backgroundColor = color;
@ -131,11 +144,6 @@ namespace Ndk
m_canvas->SetKeyboardOwner(m_canvasIndex);
}
void BaseWidget::SetSize(const Nz::Vector2f& size)
{
SetContentSize({std::max(size.x - m_padding.left - m_padding.right, 0.f), std::max(size.y - m_padding.top - m_padding.bottom, 0.f)});
}
void BaseWidget::Show(bool show)
{
if (m_visible != show)
@ -155,7 +163,7 @@ namespace Ndk
}
}
const Ndk::EntityHandle& BaseWidget::CreateEntity(bool isContentEntity)
const Ndk::EntityHandle& BaseWidget::CreateEntity()
{
const EntityHandle& newEntity = m_world->CreateEntity();
newEntity->Enable(m_visible);
@ -163,7 +171,6 @@ namespace Ndk
m_entities.emplace_back();
WidgetEntity& widgetEntity = m_entities.back();
widgetEntity.handle = newEntity;
widgetEntity.isContent = isContentEntity;
return newEntity;
}
@ -179,7 +186,7 @@ namespace Ndk
void BaseWidget::Layout()
{
if (m_backgroundEntity)
m_backgroundSprite->SetSize(m_contentSize.x + m_padding.left + m_padding.right, m_contentSize.y + m_padding.top + m_padding.bottom);
m_backgroundSprite->SetSize(m_size.x, m_size.y);
UpdatePositionAndSize();
}
@ -282,16 +289,12 @@ namespace Ndk
Nz::Vector2f widgetPos = Nz::Vector2f(GetPosition());
Nz::Vector2f widgetSize = GetSize();
Nz::Vector2f contentPos = widgetPos + GetContentOrigin();
Nz::Vector2f contentSize = GetContentSize();
Nz::Recti fullBounds(Nz::Rectf(widgetPos.x, widgetPos.y, widgetSize.x, widgetSize.y));
Nz::Recti contentBounds(Nz::Rectf(contentPos.x, contentPos.y, contentSize.x, contentSize.y));
for (WidgetEntity& widgetEntity : m_entities)
{
const Ndk::EntityHandle& entity = widgetEntity.handle;
if (entity->HasComponent<GraphicsComponent>())
entity->GetComponent<GraphicsComponent>().SetScissorRect((widgetEntity.isContent) ? contentBounds : fullBounds);
entity->GetComponent<GraphicsComponent>().SetScissorRect(fullBounds);
}
}
}

View File

@ -7,10 +7,6 @@
namespace Ndk
{
void Canvas::ResizeToContent()
{
}
std::size_t Canvas::RegisterWidget(BaseWidget* widget)
{
WidgetEntry box;

View File

@ -0,0 +1,122 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
#include <NDK/Widgets/BoxLayout.hpp>
#include <Nazara/Core/Log.hpp>
#include <Nazara/Core/MemoryHelper.hpp>
#include <cassert>
namespace Ndk
{
void BoxLayout::Layout()
{
std::size_t axis1, axis2;
switch (m_orientation)
{
case BoxLayoutOrientation_Horizontal:
axis1 = 0; //< x
axis2 = 1; //< y
break;
case BoxLayoutOrientation_Vertical:
axis1 = 1; //< y
axis2 = 0; //< x
break;
default:
assert(false);
break;
}
m_childInfos.clear();
// Handle size
ForEachWidgetChild([&](BaseWidget* child)
{
if (!child->IsVisible())
return;
m_childInfos.emplace_back();
auto& info = m_childInfos.back();
info.isConstrained = false;
info.maximumSize = child->GetMaximumSize()[axis1];
info.minimumSize = child->GetMinimumSize()[axis1];
info.size = info.minimumSize;
info.widget = child;
});
Nz::Vector2f layoutSize = GetSize();
float availableSpace = layoutSize[axis1] - m_spacing * (m_childInfos.size() - 1);
float remainingSize = availableSpace;
for (auto& info : m_childInfos)
remainingSize -= info.minimumSize;
// Okay this algorithm is FAR from perfect but I couldn't figure a way other than this one
std::size_t unconstrainedChildCount = m_childInfos.size();
bool hasUnconstrainedChilds = false;
for (std::size_t i = 0; i < m_childInfos.size(); ++i)
{
if (remainingSize <= 0.0001f)
break;
float evenSize = remainingSize / unconstrainedChildCount;
for (auto& info : m_childInfos)
{
if (info.isConstrained)
continue;
float previousSize = info.size;
info.size += evenSize;
if (info.size > info.maximumSize)
{
unconstrainedChildCount--;
evenSize += (info.size - info.maximumSize) / unconstrainedChildCount;
info.isConstrained = true;
info.size = info.maximumSize;
}
else
hasUnconstrainedChilds = true;
remainingSize -= info.size - previousSize;
}
if (!hasUnconstrainedChilds)
break;
}
float spacing = m_spacing + remainingSize / (m_childInfos.size() - 1);
for (auto& info : m_childInfos)
{
Nz::Vector2f newSize = info.widget->GetSize();
newSize[axis1] = info.size;
info.widget->Resize(newSize);
}
// Handle position
float cursor = 0.f;
bool first = true;
for (auto& info : m_childInfos)
{
if (first)
first = false;
else
cursor += spacing;
Nz::Vector2f position = Nz::Vector2f(0.f, 0.f);
position[axis1] = cursor;
info.widget->SetPosition(position);
cursor += info.size;
};
}
}

View File

@ -30,13 +30,13 @@ namespace Ndk
m_gradientSprite->SetCornerColor(Nz::RectCorner_RightBottom, m_cornerColor);
m_gradientSprite->SetMaterial(Nz::Material::New("Basic2D"));
m_gradientEntity = CreateEntity(false);
m_gradientEntity = CreateEntity();
m_gradientEntity->AddComponent<NodeComponent>().SetParent(this);
m_gradientEntity->AddComponent<GraphicsComponent>().Attach(m_gradientSprite);
m_textSprite = Nz::TextSprite::New();
m_textEntity = CreateEntity(true);
m_textEntity = CreateEntity();
m_textEntity->AddComponent<NodeComponent>().SetParent(this);
m_textEntity->AddComponent<GraphicsComponent>().Attach(m_textSprite, 1);
@ -73,22 +73,15 @@ namespace Ndk
return s_pressCornerColor;
}
void ButtonWidget::ResizeToContent()
{
SetContentSize(Nz::Vector2f(m_textSprite->GetBoundingVolume().obb.localBox.GetLengths()));
}
void ButtonWidget::Layout()
{
BaseWidget::Layout();
m_gradientSprite->SetSize(GetSize());
Nz::Vector2f origin = GetContentOrigin();
const Nz::Vector2f& contentSize = GetContentSize();
Nz::Vector2f size = GetSize();
m_gradientSprite->SetSize(size);
Nz::Boxf textBox = m_textEntity->GetComponent<GraphicsComponent>().GetAABB();
m_textEntity->GetComponent<NodeComponent>().SetPosition(origin.x + contentSize.x / 2 - textBox.width / 2, origin.y + contentSize.y / 2 - textBox.height / 2);
m_textEntity->GetComponent<NodeComponent>().SetPosition(size.x / 2.f - textBox.width / 2.f, size.y / 2.f - textBox.height / 2.f);
}
void ButtonWidget::OnMouseButtonPress(int /*x*/, int /*y*/, Nz::Mouse::Button button)

View File

@ -28,19 +28,19 @@ namespace Ndk
m_checkboxContentSprite = Nz::Sprite::New(Nz::Material::New("Translucent2D"));
m_textSprite = Nz::TextSprite::New();
m_checkboxBorderEntity = CreateEntity(false);
m_checkboxBorderEntity = CreateEntity();
m_checkboxBorderEntity->AddComponent<NodeComponent>().SetParent(this);
m_checkboxBorderEntity->AddComponent<GraphicsComponent>().Attach(m_checkboxBorderSprite);
m_checkboxBackgroundEntity = CreateEntity(false);
m_checkboxBackgroundEntity = CreateEntity();
m_checkboxBackgroundEntity->AddComponent<NodeComponent>().SetParent(this);
m_checkboxBackgroundEntity->AddComponent<GraphicsComponent>().Attach(m_checkboxBackgroundSprite, 1);
m_checkboxContentEntity = CreateEntity(true);
m_checkboxContentEntity = CreateEntity();
m_checkboxContentEntity->AddComponent<NodeComponent>().SetParent(this);
m_checkboxContentEntity->AddComponent<GraphicsComponent>().Attach(m_checkboxContentSprite, 2);
m_textEntity = CreateEntity(true);
m_textEntity = CreateEntity();
m_textEntity->AddComponent<NodeComponent>().SetParent(this);
m_textEntity->AddComponent<GraphicsComponent>().Attach(m_textSprite);
@ -108,20 +108,11 @@ namespace Ndk
return m_state;
}
void CheckboxWidget::ResizeToContent()
{
Nz::Vector3f textSize = m_textSprite->GetBoundingVolume().obb.localBox.GetLengths();
Nz::Vector2f checkboxSize = GetCheckboxSize();
Nz::Vector2f finalSize { checkboxSize.x + (m_adaptativeMargin ? checkboxSize.x / 2.f : m_textMargin) + textSize.x, std::max(textSize.y, checkboxSize.y) };
SetContentSize(finalSize);
}
void CheckboxWidget::Layout()
{
BaseWidget::Layout();
Nz::Vector2f origin = GetContentOrigin();
Nz::Vector2f origin = Nz::Vector2f(0.f);
Nz::Vector2f checkboxSize = GetCheckboxSize();
Nz::Vector2f borderSize = GetCheckboxBorderSize();
@ -178,4 +169,14 @@ namespace Ndk
m_checkboxContentSprite->SetTexture(Nz::TextureRef {});
}
}
void CheckboxWidget::UpdateSize()
{
Nz::Vector3f textSize = m_textSprite->GetBoundingVolume().obb.localBox.GetLengths();
Nz::Vector2f checkboxSize = GetCheckboxSize();
Nz::Vector2f finalSize{ checkboxSize.x + (m_adaptativeMargin ? checkboxSize.x / 2.f : m_textMargin) + textSize.x, std::max(textSize.y, checkboxSize.y) };
SetMinimumSize(finalSize);
SetPreferredSize(finalSize);
}
}

View File

@ -11,7 +11,7 @@ namespace Ndk
ImageWidget::ImageWidget(BaseWidget* parent) :
BaseWidget(parent)
{
m_entity = CreateEntity(true);
m_entity = CreateEntity();
m_entity->AddComponent<NodeComponent>();
auto& gfx = m_entity->AddComponent<GraphicsComponent>();
@ -19,19 +19,10 @@ namespace Ndk
gfx.Attach(m_sprite);
}
void ImageWidget::ResizeToContent()
{
Nz::Vector3ui textureSize = m_sprite->GetMaterial()->GetDiffuseMap()->GetSize();
SetSize({ static_cast<float>(textureSize.x), static_cast<float>(textureSize.y) });
}
void ImageWidget::Layout()
{
BaseWidget::Layout();
Nz::Vector2f origin = GetContentOrigin();
Nz::Vector2f contentSize = GetContentSize();
m_entity->GetComponent<NodeComponent>().SetPosition(origin);
m_sprite->SetSize(contentSize);
m_sprite->SetSize(GetSize());
}
}

View File

@ -13,7 +13,7 @@ namespace Ndk
{
m_textSprite = Nz::TextSprite::New();
m_textEntity = CreateEntity(true);
m_textEntity = CreateEntity();
m_textEntity->AddComponent<GraphicsComponent>().Attach(m_textSprite);
m_textEntity->AddComponent<NodeComponent>().SetParent(this);
@ -23,12 +23,5 @@ namespace Ndk
void LabelWidget::Layout()
{
BaseWidget::Layout();
m_textEntity->GetComponent<NodeComponent>().SetPosition(GetContentOrigin());
}
void LabelWidget::ResizeToContent()
{
SetContentSize(Nz::Vector2f(m_textSprite->GetBoundingVolume().obb.localBox.GetLengths()));
}
}

View File

@ -30,11 +30,11 @@ namespace Ndk
SetBarColor(s_barColor, s_barCornerColor);
m_borderEntity = CreateEntity(false);
m_borderEntity = CreateEntity();
m_borderEntity->AddComponent<NodeComponent>().SetParent(this);
m_borderEntity->AddComponent<GraphicsComponent>().Attach(m_borderSprite);
m_barEntity = CreateEntity(true);
m_barEntity = CreateEntity();
m_barEntity->AddComponent<NodeComponent>().SetParent(this);
GraphicsComponent& graphics = m_barEntity->AddComponent<GraphicsComponent>();
@ -43,7 +43,7 @@ namespace Ndk
m_textSprite = Nz::TextSprite::New();
m_textEntity = CreateEntity(true);
m_textEntity = CreateEntity();
m_textEntity->AddComponent<NodeComponent>().SetParent(this);
m_textEntity->AddComponent<GraphicsComponent>().Attach(m_textSprite);
@ -76,8 +76,8 @@ namespace Ndk
void ProgressBarWidget::Layout()
{
Nz::Vector2f origin = GetContentOrigin();
Nz::Vector2f size = GetContentSize();
Nz::Vector2f origin = Nz::Vector2f(0.f);
Nz::Vector2f size = GetSize();
Nz::Vector2f progressBarSize = size;
if (IsTextEnabled())

View File

@ -4,6 +4,7 @@
#include <NDK/Widgets/TextAreaWidget.hpp>
#include <Nazara/Core/Unicode.hpp>
#include <Nazara/Utility/Font.hpp>
#include <NDK/Components/GraphicsComponent.hpp>
#include <NDK/Components/NodeComponent.hpp>
@ -20,19 +21,23 @@ namespace Ndk
m_readOnly(false),
m_tabEnabled(false)
{
m_cursorEntity = CreateEntity(true);
m_cursorEntity = CreateEntity();
m_cursorEntity->AddComponent<GraphicsComponent>();
m_cursorEntity->AddComponent<NodeComponent>().SetParent(this);
m_cursorEntity->GetComponent<NodeComponent>().SetPosition(5.f, 3.f);
m_cursorEntity->Enable(false);
m_textSprite = Nz::TextSprite::New();
m_textEntity = CreateEntity(true);
m_textEntity = CreateEntity();
m_textEntity->AddComponent<GraphicsComponent>().Attach(m_textSprite);
m_textEntity->AddComponent<NodeComponent>().SetParent(this);
m_textEntity->GetComponent<NodeComponent>().SetPosition(5.f, 3.f);
SetCursor(Nz::SystemCursor_Text);
SetCharacterSize(GetCharacterSize()); //< Actualize minimum / preferred size
EnableBackground(true);
Layout();
}
@ -140,9 +145,25 @@ namespace Ndk
return Nz::Vector2ui::Zero();
}
void TextAreaWidget::ResizeToContent()
void TextAreaWidget::SetCharacterSize(unsigned int characterSize)
{
SetContentSize(Nz::Vector2f(m_textSprite->GetBoundingVolume().obb.localBox.GetLengths()));
m_drawer.SetCharacterSize(characterSize);
std::size_t fontCount = m_drawer.GetFontCount();
unsigned int lineHeight = 0;
int spaceAdvance = 0;
for (std::size_t i = 0; i < fontCount; ++i)
{
Nz::Font* font = m_drawer.GetFont(i);
const Nz::Font::SizeInfo& sizeInfo = font->GetSizeInfo(characterSize);
lineHeight = std::max(lineHeight, sizeInfo.lineHeight);
spaceAdvance = std::max(spaceAdvance, sizeInfo.spaceAdvance);
}
Nz::Vector2f size = { float(spaceAdvance), float(lineHeight) + 5.f };
SetMinimumSize(size);
SetPreferredSize({ size.x * 6.f, size.y });
}
void TextAreaWidget::Write(const Nz::String& text, std::size_t glyphPosition)
@ -165,8 +186,6 @@ namespace Ndk
{
BaseWidget::Layout();
m_textEntity->GetComponent<NodeComponent>().SetPosition(GetContentOrigin());
RefreshCursor();
}
@ -403,8 +422,7 @@ namespace Ndk
{
SetFocus();
const Padding& padding = GetPadding();
Nz::Vector2ui hoveredGlyph = GetHoveredGlyph(float(x - padding.left), float(y - padding.top));
Nz::Vector2ui hoveredGlyph = GetHoveredGlyph(float(x) - 5.f, float(y) - 5.f);
// Shift extends selection
if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::LShift) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::RShift))
@ -434,10 +452,7 @@ namespace Ndk
void TextAreaWidget::OnMouseMoved(int x, int y, int deltaX, int deltaY)
{
if (m_isMouseButtonDown)
{
const Padding& padding = GetPadding();
SetSelection(m_selectionCursor, GetHoveredGlyph(float(x - padding.left), float(y - padding.top)));
}
SetSelection(m_selectionCursor, GetHoveredGlyph(float(x) - 5.f, float(y) - 3.f));
}
void TextAreaWidget::OnTextEntered(char32_t character, bool /*repeated*/)
@ -514,8 +529,6 @@ namespace Ndk
if (m_readOnly)
return;
m_cursorEntity->GetComponent<NodeComponent>().SetPosition(GetContentOrigin());
std::size_t selectionLineCount = m_cursorPositionEnd.y - m_cursorPositionBegin.y + 1;
std::size_t oldSpriteCount = m_cursorSprites.size();
if (m_cursorSprites.size() != selectionLineCount)

View File

@ -36,6 +36,7 @@ TOOL.FilesExcluded = {
"../SDK/**/Particle*Component.*",
"../SDK/**/ParticleSystem.*",
"../SDK/**/RenderSystem.*",
"../SDK/**/*Layout*.*",
"../SDK/**/*Widget*.*",
"../SDK/**/LuaBinding_Audio.*",
"../SDK/**/LuaBinding_Graphics.*",