From: Daniel Karbach <daniel.karbach@localhorst.tv>
Date: Mon, 4 Dec 2017 15:01:47 +0000 (+0100)
Subject: fix layout
X-Git-Url: https://git.localhorst.tv/?a=commitdiff_plain;h=bf25780e00b719b0e5fa5d0191087bca2d99462b;p=blobs.git

fix layout
---

diff --git a/src/ui/Label.hpp b/src/ui/Label.hpp
index 1bc7e86..7ba884b 100644
--- a/src/ui/Label.hpp
+++ b/src/ui/Label.hpp
@@ -30,7 +30,7 @@ public:
 	void Draw(app::Assets &, graphics::Viewport &) noexcept override;
 
 private:
-	void Update();
+	void FixLayout() override;
 
 private:
 	const graphics::Font *font;
@@ -38,7 +38,6 @@ private:
 	graphics::Texture tex;
 	glm::vec4 fg_color;
 	glm::vec4 bg_color;
-	bool dirty;
 
 };
 
diff --git a/src/ui/Meter.hpp b/src/ui/Meter.hpp
index 9f2db65..7223726 100644
--- a/src/ui/Meter.hpp
+++ b/src/ui/Meter.hpp
@@ -15,9 +15,9 @@ public:
 	~Meter() override;
 
 public:
-	Meter *Size(const glm::vec2 &s) noexcept { size = s; return this; }
-	Meter *Padding(const glm::vec2 &p) noexcept { padding = p; return this; }
-	Meter *Border(float b) noexcept { border = b; return this; }
+	Meter *Size(const glm::vec2 &s) noexcept { size = s; BreakParentLayout(); return this; }
+	Meter *Padding(const glm::vec2 &p) noexcept { padding = p; BreakParentLayout(); return this; }
+	Meter *Border(float b) noexcept { border = b; BreakParentLayout(); return this; }
 
 	Meter *FillColor(const glm::vec4 &c) noexcept { fill_color = c; return this; }
 	Meter *BorderColor(const glm::vec4 &c) noexcept { border_color = c; return this; }
diff --git a/src/ui/Panel.hpp b/src/ui/Panel.hpp
index d49dbf4..cf72e72 100644
--- a/src/ui/Panel.hpp
+++ b/src/ui/Panel.hpp
@@ -37,7 +37,7 @@ public:
 	Panel *Direction(Dir);
 
 	glm::vec2 Size() override;
-	void Layout();
+	void FixLayout();
 	void Draw(app::Assets &, graphics::Viewport &) noexcept override;
 
 private:
diff --git a/src/ui/Widget.hpp b/src/ui/Widget.hpp
index a69defb..84570a3 100644
--- a/src/ui/Widget.hpp
+++ b/src/ui/Widget.hpp
@@ -26,18 +26,33 @@ public:
 	Widget &operator =(Widget &&) = delete;
 
 public:
+	void SetParent(Widget &) noexcept;
+	bool HasParent() const noexcept { return parent; }
+	Widget &GetParent() noexcept { return *parent; }
+	const Widget &GetParent() const noexcept { return *parent; }
+
 	Widget *Position(const glm::vec2 &p) noexcept { pos = p; return this; }
 	const glm::vec2 &Position() const noexcept { return pos; }
 
 	Widget *ZIndex(float z) noexcept { z_index = z; return this; }
 	float ZIndex() const noexcept { return z_index; }
 
+	bool DirtyLayout() const noexcept { return dirty_layout; }
+	void BreakLayout() noexcept;
+	void BreakParentLayout() noexcept;
+	void Layout();
+
 	virtual glm::vec2 Size() = 0;
 	virtual void Draw(app::Assets &, graphics::Viewport &) noexcept = 0;
 
 private:
+	virtual void FixLayout() { }
+
+private:
+	Widget *parent;
 	glm::vec2 pos;
 	float z_index;
+	bool dirty_layout;
 
 };
 
diff --git a/src/ui/ui.cpp b/src/ui/ui.cpp
index 88d1288..c4d35e3 100644
--- a/src/ui/ui.cpp
+++ b/src/ui/ui.cpp
@@ -91,6 +91,8 @@ CreaturePanel::CreaturePanel(app::Assets &assets)
 		->Spacing(2)
 		->Direction(Panel::VERTICAL);
 	Panel *stat_meter_panel = new Panel;
+	stat_label[0]->Layout();
+	stats[0]->Layout();
 	stat_meter_panel
 		->Spacing(stat_label[0]->Size().y - stats[0]->Size().y + 2)
 		->Direction(Panel::VERTICAL);
@@ -241,6 +243,7 @@ void CreaturePanel::Draw(graphics::Viewport &viewport) noexcept {
 
 	const glm::vec2 margin(20.0f);
 	panel.Position(glm::vec2(viewport.Width() - margin.x - panel.Size().x, margin.y));
+	panel.Layout();
 	panel.Draw(assets, viewport);
 }
 
@@ -339,6 +342,7 @@ void RecordsPanel::Draw(graphics::Viewport &viewport) noexcept {
 
 	const glm::vec2 margin(20.0f);
 	panel.Position(glm::vec2(margin.x, margin.y));
+	panel.Layout();
 	panel.Draw(sim.Assets(), viewport);
 }
 
@@ -388,6 +392,7 @@ void TimePanel::Draw(graphics::Viewport &viewport) noexcept {
 
 	const glm::vec2 margin(20.0f);
 	panel.Position(glm::vec2(margin.x, viewport.Height() - margin.y - panel.Size().y));
+	panel.Layout();
 	panel.Draw(sim.Assets(), viewport);
 }
 
diff --git a/src/ui/widgets.cpp b/src/ui/widgets.cpp
index a81defc..554a685 100644
--- a/src/ui/widgets.cpp
+++ b/src/ui/widgets.cpp
@@ -20,8 +20,7 @@ Label::Label(const graphics::Font &f)
 , text()
 , tex()
 , fg_color(0.0f, 0.0f, 0.0f, 1.0f)
-, bg_color(0.0f, 0.0f, 0.0f, 0.0f)
-, dirty(true) {
+, bg_color(0.0f, 0.0f, 0.0f, 0.0f) {
 }
 
 Label::~Label() {
@@ -29,7 +28,7 @@ Label::~Label() {
 
 Label *Label::Text(const std::string &t) {
 	if (text != t) {
-		dirty = true;
+		BreakLayout();
 	}
 	text = t;
 	return this;
@@ -37,7 +36,7 @@ Label *Label::Text(const std::string &t) {
 
 Label *Label::Font(const graphics::Font &f) {
 	if (font != &f) {
-		dirty = true;
+		BreakLayout();
 	}
 	font = &f;
 	return this;
@@ -57,13 +56,11 @@ glm::vec2 Label::Size() {
 	if (text.empty()) {
 		return glm::vec2(0.0f);
 	}
-	Update();
 	return tex.Size();
 }
 
 void Label::Draw(app::Assets &assets, graphics::Viewport &viewport) noexcept {
 	if (text.empty()) return;
-	Update();
 	glm::vec2 size = Size();
 
 	assets.shaders.alpha_sprite.Activate();
@@ -75,10 +72,9 @@ void Label::Draw(app::Assets &assets, graphics::Viewport &viewport) noexcept {
 	assets.shaders.alpha_sprite.DrawRect();
 }
 
-void Label::Update() {
-	if (!dirty || text.empty()) return;
+void Label::FixLayout() {
+	if (text.empty()) return;
 	font->Render(text, tex);
-	dirty = false;
 }
 
 
@@ -137,22 +133,15 @@ Panel::~Panel() {
 }
 
 Panel *Panel::Add(Widget *w) {
-	std::unique_ptr<Widget> widget(w);
-	glm::vec2 wsize = widget->Size();
-	if (dir == HORIZONTAL) {
-		size.x += wsize.x;
-		size.y = std::max(size.y, wsize.y);
-	} else {
-		size.x = std::max(size.x, wsize.x);
-		size.y += wsize.y;
-	}
-	widgets.emplace_back(std::move(widget));
+	w->SetParent(*this);
+	widgets.emplace_back(std::unique_ptr<Widget>(w));
+	BreakLayout();
 	return this;
 }
 
 Panel *Panel::Clear() {
 	widgets.clear();
-	size = glm::vec2(0.0f);
+	BreakLayout();
 	return this;
 }
 
@@ -163,17 +152,19 @@ Panel *Panel::Background(const glm::vec4 &c) {
 
 Panel *Panel::Padding(const glm::vec2 &p) {
 	padding = p;
+	BreakParentLayout();
 	return this;
 }
 
 Panel *Panel::Spacing(float s) {
 	spacing = s;
+	BreakParentLayout();
 	return this;
 }
 
 Panel *Panel::Direction(Dir d) {
 	dir = d;
-	Layout();
+	BreakLayout();
 	return this;
 }
 
@@ -183,7 +174,10 @@ glm::vec2 Panel::Size() {
 	return (2.0f * padding) + space + size;
 }
 
-void Panel::Layout() {
+void Panel::FixLayout() {
+	for (auto &w : widgets) {
+		w->Layout();
+	}
 	size = glm::vec2(0.0f);
 	if (dir == HORIZONTAL) {
 		for (auto &w : widgets) {
@@ -201,8 +195,6 @@ void Panel::Layout() {
 }
 
 void Panel::Draw(app::Assets &assets, graphics::Viewport &viewport) noexcept {
-	// TODO: separate draw and layout, it's inefficient and the wrong tree order anyway
-	Layout();
 	if (bg_color.a > 0.0f) {
 		assets.shaders.canvas.Activate();
 		assets.shaders.canvas.ZIndex(ZIndex());
@@ -220,12 +212,37 @@ void Panel::Draw(app::Assets &assets, graphics::Viewport &viewport) noexcept {
 
 
 Widget::Widget()
-: pos(0.0f)
-, z_index(1.0f)  {
+: parent(nullptr)
+, pos(0.0f)
+, z_index(1.0f)
+, dirty_layout(false) {
 }
 
 Widget::~Widget() {
 }
 
+void Widget::SetParent(Widget &p) noexcept {
+	parent = &p;
+}
+
+void Widget::BreakLayout() noexcept {
+	if (dirty_layout) return;
+	dirty_layout = true;
+	BreakParentLayout();
+}
+
+void Widget::BreakParentLayout() noexcept {
+	if (HasParent()) {
+		GetParent().BreakLayout();
+	}
+}
+
+void Widget::Layout() {
+	if (dirty_layout) {
+		FixLayout();
+		dirty_layout = false;
+	}
+}
+
 }
 }