Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ set(GUI_LIB_SOURCES
src/gui/gui2_progressbar.cpp
src/gui/gui2_progressslider.cpp
src/gui/gui2_scrolltext.cpp
src/gui/gui2_scrollcontainer.cpp
src/gui/gui2_advancedscrolltext.cpp
src/gui/gui2_button.cpp
src/gui/gui2_resizabledialog.cpp
Expand Down Expand Up @@ -196,6 +197,7 @@ set(GUI_LIB_SOURCES
src/gui/gui2_resizabledialog.h
src/gui/gui2_rotationdial.h
src/gui/gui2_scrollbar.h
src/gui/gui2_scrollcontainer.h
src/gui/gui2_scrolltext.h
src/gui/gui2_selector.h
src/gui/gui2_slider.h
Expand Down
89 changes: 56 additions & 33 deletions src/gui/gui2_container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

GuiContainer::~GuiContainer()
{
for(GuiElement* element : children)
for (GuiElement* element : children)
{
element->owner = nullptr;
delete element;
Expand All @@ -13,23 +13,24 @@ GuiContainer::~GuiContainer()

void GuiContainer::drawElements(glm::vec2 mouse_position, sp::Rect parent_rect, sp::RenderTarget& renderer)
{
for(auto it = children.begin(); it != children.end(); )
for (auto it = children.begin(); it != children.end(); )
{
GuiElement* element = *it;
if (element->destroyed)
{
//Find the owning cancas, as we need to remove ourselves if we are the focus or click element.
GuiCanvas* canvas = dynamic_cast<GuiCanvas*>(element->getTopLevelContainer());
if (canvas)
canvas->unfocusElementTree(element);
if (canvas) canvas->unfocusElementTree(element);

//Delete it from our list.
it = children.erase(it);

// Free up the memory used by the element.
element->owner = nullptr;
delete element;
}else{
}
else
{
element->hover = element->rect.contains(mouse_position);

if (element->visible)
Expand Down Expand Up @@ -61,57 +62,54 @@ void GuiContainer::drawDebugElements(sp::Rect parent_rect, sp::RenderTarget& ren

GuiElement* GuiContainer::getClickElement(sp::io::Pointer::Button button, glm::vec2 position, sp::io::Pointer::ID id)
{
for(auto it = children.rbegin(); it != children.rend(); it++)
for (auto it = children.rbegin(); it != children.rend(); it++)
{
GuiElement* element = *it;

if (element->visible && element->enabled && element->rect.contains(position))
{
GuiElement* clicked = element->getClickElement(button, position, id);
if (clicked)
return clicked;
if (element->onMouseDown(button, position, id))
{
return element;
}
if (clicked) return clicked;
if (element->onMouseDown(button, position, id)) return element;
}
}

return nullptr;
}

GuiElement* GuiContainer::executeScrollOnElement(glm::vec2 position, float value)
{
for(auto it = children.rbegin(); it != children.rend(); it++)
for (auto it = children.rbegin(); it != children.rend(); it++)
{
GuiElement* element = *it;

if (element->visible && element->enabled && element->rect.contains(position))
{
GuiElement* scrolled = element->executeScrollOnElement(position, value);
if (scrolled)
return scrolled;
if (element->onMouseWheelScroll(position, value))
return element;
if (scrolled) return scrolled;
if (element->onMouseWheelScroll(position, value)) return element;
}
}

return nullptr;
}

void GuiContainer::updateLayout(const sp::Rect& rect)
{
this->rect = rect;

if (layout_manager || !children.empty())
{
if (!layout_manager)
layout_manager = std::make_unique<GuiLayout>();
if (!layout_manager) layout_manager = std::make_unique<GuiLayout>();

glm::vec2 padding_size(layout.padding.left + layout.padding.right, layout.padding.top + layout.padding.bottom);
layout_manager->updateLoop(*this, sp::Rect(rect.position + glm::vec2{layout.padding.left, layout.padding.top}, rect.size - padding_size));
if (layout.match_content_size)
{
glm::vec2 content_size_min(std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
glm::vec2 content_size_max(std::numeric_limits<float>::min(), std::numeric_limits<float>::min());
for(auto w : children)

for (auto w : children)
{
if (w && w->isVisible())
{
Expand All @@ -123,6 +121,7 @@ void GuiContainer::updateLayout(const sp::Rect& rect)
content_size_max.y = std::max(content_size_max.y, p1.y + w->layout.margin.bottom);
}
}

if (content_size_max.x != std::numeric_limits<float>::min())
{
this->rect.size = (content_size_max - content_size_min) + padding_size;
Expand All @@ -132,6 +131,36 @@ void GuiContainer::updateLayout(const sp::Rect& rect)
}
}

void GuiContainer::clearElementOwner(GuiElement* element)
{
element->owner = nullptr;
}

void GuiContainer::setElementHover(GuiElement* element, bool has_hover)
{
element->hover = has_hover;
}

void GuiContainer::setElementFocus(GuiElement* element, bool has_focus)
{
element->focus = has_focus;
}

void GuiContainer::callDrawElements(GuiContainer* container, glm::vec2 mouse_pos, sp::Rect rect, sp::RenderTarget& render_target)
{
container->drawElements(mouse_pos, rect, render_target);
}

GuiElement* GuiContainer::callGetClickElement(GuiContainer* container, sp::io::Pointer::Button button, glm::vec2 pos, sp::io::Pointer::ID id)
{
return container->getClickElement(button, pos, id);
}

GuiElement* GuiContainer::callExecuteScrollOnElement(GuiContainer* container, glm::vec2 pos, float value)
{
return container->executeScrollOnElement(pos, value);
}

void GuiContainer::setAttribute(const string& key, const string& value)
{
if (key == "size")
Expand Down Expand Up @@ -187,9 +216,7 @@ void GuiContainer::setAttribute(const string& key, const string& value)
{
auto values = value.split(",", 3);
if (values.size() == 1)
{
layout.padding.top = layout.padding.bottom = layout.padding.left = layout.padding.right = values[0].strip().toFloat();
}
layout.padding.top = layout.padding.bottom = layout.padding.left = layout.padding.right = values[0].strip().toFloat();
else if (values.size() == 2)
{
layout.padding.left = layout.padding.right = values[0].strip().toFloat();
Expand Down Expand Up @@ -232,24 +259,22 @@ void GuiContainer::setAttribute(const string& key, const string& value)
else if (key == "layout")
{
GuiLayoutClassRegistry* reg;
for(reg = GuiLayoutClassRegistry::first; reg != nullptr; reg = reg->next)
{
if (value == reg->name)
break;
}

for (reg = GuiLayoutClassRegistry::first; reg != nullptr; reg = reg->next)
if (value == reg->name) break;

if (reg)
{
layout_manager = reg->creation_function();
}else{
else
LOG(Error, "Failed to find layout type:", value);
}
}
else if (key == "stretch")
{
if (value == "aspect")
layout.fill_height = layout.fill_width = layout.lock_aspect_ratio = true;
else
layout.fill_height = layout.fill_width = value.toBool();

layout.match_content_size = false;
}
else if (key == "fill_height")
Expand All @@ -263,7 +288,5 @@ void GuiContainer::setAttribute(const string& key, const string& value)
layout.match_content_size = false;
}
else
{
LOG(Warning, "Tried to set unknown widget attribute:", key, "to", value);
}
}
57 changes: 33 additions & 24 deletions src/gui/gui2_container.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#ifndef GUI2_CONTAINER_H
#define GUI2_CONTAINER_H
#pragma once

#include <list>
#include <memory>
Expand All @@ -17,25 +16,26 @@ namespace sp {
class GuiElement;
class GuiLayout;
class GuiTheme;

class GuiContainer : sp::NonCopyable
{
public:
public:
// Nested type to capture layout attributes
class LayoutInfo
{
public:
class Sides
{
public:
float left = 0;
float right = 0;
float top = 0;
float bottom = 0;
float left = 0.0f;
float right = 0.0f;
float top = 0.0f;
float bottom = 0.0f;
};

glm::vec2 position{0, 0};
glm::vec2 position{0.0f, 0.0f};
sp::Alignment alignment = sp::Alignment::TopLeft;
glm::vec2 size{1, 1};
glm::vec2 size{1.0f, 1.0f};
glm::ivec2 span{1, 1};
Sides margin;
Sides padding;
Expand All @@ -45,30 +45,39 @@ class GuiContainer : sp::NonCopyable
bool match_content_size = true;
};

LayoutInfo layout;
std::list<GuiElement*> children;
protected:
GuiTheme* theme;
public:
GuiContainer() = default;
virtual ~GuiContainer();

// Public data
LayoutInfo layout;
std::list<GuiElement*> children;

// Public interfaces
template<typename T> void setLayout() { layout_manager = std::make_unique<T>(); }
void updateLayout(const sp::Rect& rect);
virtual void updateLayout(const sp::Rect& rect);
virtual void setAttribute(const string& key, const string& value);
const sp::Rect& getRect() const { return rect; }

virtual void setAttribute(const string& key, const string& value);
protected:
GuiTheme* theme;

// Protected data
sp::Rect rect{0,0,0,0};
std::unique_ptr<GuiLayout> layout_manager = nullptr;

// Protected interfaces
virtual void drawElements(glm::vec2 mouse_position, sp::Rect parent_rect, sp::RenderTarget& window);
virtual void drawDebugElements(sp::Rect parent_rect, sp::RenderTarget& window);
GuiElement* getClickElement(sp::io::Pointer::Button button, glm::vec2 position, sp::io::Pointer::ID id);
GuiElement* executeScrollOnElement(glm::vec2 position, float value);
virtual GuiElement* getClickElement(sp::io::Pointer::Button button, glm::vec2 position, sp::io::Pointer::ID id);
virtual GuiElement* executeScrollOnElement(glm::vec2 position, float value);

friend class GuiElement;
// Static helpers for subclass access to protected members.
static void clearElementOwner(GuiElement* element);
static void setElementHover(GuiElement* element, bool has_hover);
static void setElementFocus(GuiElement* element, bool has_focus);
static void callDrawElements(GuiContainer* container, glm::vec2 mouse_pos, sp::Rect rect, sp::RenderTarget& render_target);
static GuiElement* callGetClickElement(GuiContainer* container, sp::io::Pointer::Button button, glm::vec2 pos, sp::io::Pointer::ID id);
static GuiElement* callExecuteScrollOnElement(GuiContainer* container, glm::vec2 pos, float value);

sp::Rect rect{0,0,0,0};
private:
std::unique_ptr<GuiLayout> layout_manager = nullptr;
friend class GuiElement;
};

#endif//GUI2_CONTAINER_H
Loading
Loading