]> git.localhorst.tv Git - blobs.git/blobdiff - src/ui/widgets.cpp
fix layout
[blobs.git] / src / ui / widgets.cpp
index b0d44e20969fa23a55bbfe589e76d4b0fa3332be..554a6854876f22f0f5bd9425046342a1251318d4 100644 (file)
@@ -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,70 +28,15 @@ Label::~Label() {
 
 Label *Label::Text(const std::string &t) {
        if (text != t) {
-               dirty = true;
+               BreakLayout();
        }
        text = t;
        return this;
 }
 
-Label *Label::Decimal(double n, int prec) {
-       std::stringstream s;
-       s << std::fixed << std::setprecision(prec) << n;
-       return Text(s.str());
-}
-
-Label *Label::Length(double m) {
-       std::stringstream s;
-       s << std::fixed << std::setprecision(3);
-       if (m > 1500.0) {
-               s << (m * 0.001) << "km";
-       } else if (m < 0.1) {
-               s << (m * 1000.0) << "mm";
-       } else {
-               s << m << "m";
-       }
-       return Text(s.str());
-}
-
-Label *Label::Mass(double kg) {
-       std::stringstream s;
-       s << std::fixed << std::setprecision(3);
-       if (kg > 1500.0) {
-               s << (kg * 0.001) << "t";
-       } else if (kg < 0.1) {
-               s << (kg * 1000.0) << "g";
-       } else if (kg < 0.0001) {
-               s << (kg * 1.0e6) << "mg";
-       } else {
-               s << kg << "kg";
-       }
-       return Text(s.str());
-}
-
-Label *Label::Percentage(double n) {
-       std::stringstream s;
-       s << std::fixed << std::setprecision(1) << (n * 100.0) << '%';
-       return Text(s.str());
-}
-
-Label *Label::Time(double s) {
-       int is = int(s);
-       std::stringstream ss;
-       if (is >= 3600) {
-               ss << (is / 3600) << "h ";
-               is %= 3600;
-       }
-       if (is >= 60) {
-               ss << (is / 60) << "m ";
-               is %= 60;
-       }
-       ss << is << 's';
-       return Text(ss.str());
-}
-
 Label *Label::Font(const graphics::Font &f) {
        if (font != &f) {
-               dirty = true;
+               BreakLayout();
        }
        font = &f;
        return this;
@@ -112,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();
@@ -130,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;
 }
 
 
@@ -192,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;
 }
 
@@ -218,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;
 }
 
@@ -238,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) {
@@ -256,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());
@@ -275,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;
+       }
+}
+
 }
 }