Implement cached style merging
This commit is contained in:
parent
d0a117adf4
commit
b37d2d25c7
8 changed files with 85 additions and 29 deletions
|
|
@ -39,7 +39,7 @@ struct ui_example
|
||||||
: app("UI example", 1)
|
: app("UI example", 1)
|
||||||
, ui_controller(&loop)
|
, ui_controller(&loop)
|
||||||
{
|
{
|
||||||
auto style = std::make_shared<ui::style>(ui::default_style());
|
auto style = std::make_shared<ui::style>();
|
||||||
style->font = ui::make_default_9x12_font();
|
style->font = ui::make_default_9x12_font();
|
||||||
style->text_scale = 2;
|
style->text_scale = 2;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,9 @@ namespace psemek::ui
|
||||||
virtual void enable() { set_enabled(true); }
|
virtual void enable() { set_enabled(true); }
|
||||||
virtual void disable() { set_enabled(false); }
|
virtual void disable() { set_enabled(false); }
|
||||||
|
|
||||||
virtual std::shared_ptr<struct style const> style() const;
|
virtual std::shared_ptr<struct style const> style() const { return style_; }
|
||||||
virtual std::shared_ptr<struct style const> set_style(std::shared_ptr<struct style const> st);
|
virtual std::shared_ptr<struct style const> set_style(std::shared_ptr<struct style const> st);
|
||||||
|
virtual std::shared_ptr<struct style const> merged_style() const;
|
||||||
|
|
||||||
virtual void draw(painter & p) const = 0;
|
virtual void draw(painter & p) const = 0;
|
||||||
|
|
||||||
|
|
@ -59,6 +60,7 @@ namespace psemek::ui
|
||||||
async::executor * loop_ = nullptr;
|
async::executor * loop_ = nullptr;
|
||||||
bool enabled_ = true;
|
bool enabled_ = true;
|
||||||
std::shared_ptr<struct style const> style_;
|
std::shared_ptr<struct style const> style_;
|
||||||
|
mutable std::shared_ptr<struct style const> merged_style_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,8 @@ namespace psemek::ui
|
||||||
std::shared_ptr<struct font> font;
|
std::shared_ptr<struct font> font;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void merge(style & dst, style const & src);
|
||||||
|
|
||||||
style default_style();
|
style default_style();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,9 +37,9 @@ namespace psemek::ui
|
||||||
void reshape(geom::box<float, 2> const & bbox) override
|
void reshape(geom::box<float, 2> const & bbox) override
|
||||||
{
|
{
|
||||||
shape_.box = bbox;
|
shape_.box = bbox;
|
||||||
auto s = style();
|
auto st = merged_style();
|
||||||
element * c = label() ? (element *)label() : icon();
|
element * c = label() ? (element *)label() : icon();
|
||||||
if (s && c) c->reshape(geom::shrink(bbox, 1.f * (*s->border_width + *s->inner_margin)));
|
if (st && c) c->reshape(geom::shrink(bbox, 1.f * (*st->border_width + *st->inner_margin)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_state_changed() override
|
void on_state_changed() override
|
||||||
|
|
@ -63,21 +63,21 @@ namespace psemek::ui
|
||||||
|
|
||||||
void draw(painter & p) const override
|
void draw(painter & p) const override
|
||||||
{
|
{
|
||||||
auto s = style();
|
auto st = merged_style();
|
||||||
if (!s) return;
|
if (!st) return;
|
||||||
|
|
||||||
if (s->shadow_offset != geom::vector{0, 0})
|
if (st->shadow_offset != geom::vector{0, 0})
|
||||||
p.draw_rect(shape_.box + geom::cast<float>(*s->shadow_offset), *s->shadow_color);
|
p.draw_rect(shape_.box + geom::cast<float>(*st->shadow_offset), *st->shadow_color);
|
||||||
|
|
||||||
if (s->border_width > 0)
|
if (st->border_width > 0)
|
||||||
p.draw_rect(shape_.box, *s->border_color);
|
p.draw_rect(shape_.box, *st->border_color);
|
||||||
|
|
||||||
gfx::color_rgba color = *s->fg_color;
|
gfx::color_rgba color = *st->fg_color;
|
||||||
if (state() == state_t::mouseover)
|
if (state() == state_t::mouseover)
|
||||||
color = *s->highlight_color;
|
color = *st->highlight_color;
|
||||||
else if (state() == state_t::mousedown)
|
else if (state() == state_t::mousedown)
|
||||||
color = *s->action_color;
|
color = *st->action_color;
|
||||||
p.draw_rect(geom::shrink(shape_.box, 1.f * (*s->border_width)), color);
|
p.draw_rect(geom::shrink(shape_.box, 1.f * (*st->border_width)), color);
|
||||||
}
|
}
|
||||||
|
|
||||||
geom::box<float, 2> size_constraints() const override
|
geom::box<float, 2> size_constraints() const override
|
||||||
|
|
@ -90,7 +90,7 @@ namespace psemek::ui
|
||||||
{
|
{
|
||||||
sc = c->size_constraints();
|
sc = c->size_constraints();
|
||||||
|
|
||||||
if (auto st = style())
|
if (auto st = merged_style())
|
||||||
{
|
{
|
||||||
float extra = 2.f * (*st->border_width + *st->inner_margin);
|
float extra = 2.f * (*st->border_width + *st->inner_margin);
|
||||||
sc[0] += extra;
|
sc[0] += extra;
|
||||||
|
|
@ -113,7 +113,7 @@ namespace psemek::ui
|
||||||
void reshape(geom::box<float, 2> const & bbox) override
|
void reshape(geom::box<float, 2> const & bbox) override
|
||||||
{
|
{
|
||||||
shape_.box = bbox;
|
shape_.box = bbox;
|
||||||
auto st = style();
|
auto st = merged_style();
|
||||||
if (!st) return;
|
if (!st) return;
|
||||||
for (auto c : children())
|
for (auto c : children())
|
||||||
if (c) c->reshape(geom::shrink(bbox, 1.f * (*st->border_width + *st->outer_margin)));
|
if (c) c->reshape(geom::shrink(bbox, 1.f * (*st->border_width + *st->outer_margin)));
|
||||||
|
|
@ -127,7 +127,7 @@ namespace psemek::ui
|
||||||
if (c)
|
if (c)
|
||||||
r = c->size_constraints();
|
r = c->size_constraints();
|
||||||
|
|
||||||
auto st = style();
|
auto st = merged_style();
|
||||||
if (st)
|
if (st)
|
||||||
{
|
{
|
||||||
float extra = 2.f * (*st->border_width + *st->outer_margin);
|
float extra = 2.f * (*st->border_width + *st->outer_margin);
|
||||||
|
|
@ -154,7 +154,7 @@ namespace psemek::ui
|
||||||
|
|
||||||
void draw(painter & p) const override
|
void draw(painter & p) const override
|
||||||
{
|
{
|
||||||
auto st = style();
|
auto st = merged_style();
|
||||||
if (!st) return;
|
if (!st) return;
|
||||||
|
|
||||||
if (st->shadow_offset != geom::vector{0, 0})
|
if (st->shadow_offset != geom::vector{0, 0})
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
#include <psemek/ui/element.hpp>
|
#include <psemek/ui/element.hpp>
|
||||||
|
|
||||||
|
#include <psemek/util/recursive.hpp>
|
||||||
|
|
||||||
#include <psemek/log/log.hpp>
|
#include <psemek/log/log.hpp>
|
||||||
|
|
||||||
namespace psemek::ui
|
namespace psemek::ui
|
||||||
|
|
@ -37,19 +39,46 @@ namespace psemek::ui
|
||||||
return {{{0.f, inf}, {0.f, inf}}};
|
return {{{0.f, inf}, {0.f, inf}}};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<struct style const> element::style() const
|
|
||||||
{
|
|
||||||
element const * e = this;
|
|
||||||
while (!e->style_ && e->parent()) e = e->parent();
|
|
||||||
return e->style_;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<style const> element::set_style(std::shared_ptr<struct style const> st)
|
std::shared_ptr<style const> element::set_style(std::shared_ptr<struct style const> st)
|
||||||
{
|
{
|
||||||
std::swap(st, style_);
|
std::swap(st, style_);
|
||||||
|
|
||||||
|
auto visitor = util::recursive([](auto && self, element * e) -> void {
|
||||||
|
e->merged_style_ = nullptr;
|
||||||
|
for (auto c : e->children())
|
||||||
|
if (c) self(c);
|
||||||
|
});
|
||||||
|
visitor(this);
|
||||||
|
|
||||||
return st;
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<struct style const> element::merged_style() const
|
||||||
|
{
|
||||||
|
if (!merged_style_)
|
||||||
|
{
|
||||||
|
if (!style_)
|
||||||
|
{
|
||||||
|
if (parent())
|
||||||
|
merged_style_ = parent()->merged_style();
|
||||||
|
else
|
||||||
|
merged_style_ = std::make_shared<struct style>(default_style());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto merged_style = std::make_shared<struct style>(*style_);
|
||||||
|
if (parent())
|
||||||
|
merge(*merged_style, *parent()->merged_style());
|
||||||
|
else
|
||||||
|
merge(*merged_style, default_style());
|
||||||
|
|
||||||
|
merged_style_ = merged_style;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return merged_style_;
|
||||||
|
}
|
||||||
|
|
||||||
void element::post(std::function<void()> f)
|
void element::post(std::function<void()> f)
|
||||||
{
|
{
|
||||||
auto l = loop();
|
auto l = loop();
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ namespace psemek::ui
|
||||||
|
|
||||||
geom::box<float, 2> grid_layout::size_constraints() const
|
geom::box<float, 2> grid_layout::size_constraints() const
|
||||||
{
|
{
|
||||||
auto st = style();
|
auto st = merged_style();
|
||||||
if (!st) return element::size_constraints();
|
if (!st) return element::size_constraints();
|
||||||
|
|
||||||
static float const inf = std::numeric_limits<float>::infinity();
|
static float const inf = std::numeric_limits<float>::infinity();
|
||||||
|
|
@ -163,7 +163,7 @@ namespace psemek::ui
|
||||||
|
|
||||||
void grid_layout::reshape(geom::box<float, 2> const & bbox)
|
void grid_layout::reshape(geom::box<float, 2> const & bbox)
|
||||||
{
|
{
|
||||||
auto st = style();
|
auto st = merged_style();
|
||||||
if (!st) return;
|
if (!st) return;
|
||||||
|
|
||||||
float const margin = *st->outer_margin;
|
float const margin = *st->outer_margin;
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ namespace psemek::ui
|
||||||
|
|
||||||
if (!cached_state_->font) return;
|
if (!cached_state_->font) return;
|
||||||
|
|
||||||
auto st = style();
|
auto st = merged_style();
|
||||||
if (!st) return;
|
if (!st) return;
|
||||||
|
|
||||||
if (st->text_shadow_offset != geom::vector{0, 0})
|
if (st->text_shadow_offset != geom::vector{0, 0})
|
||||||
|
|
@ -91,7 +91,7 @@ namespace psemek::ui
|
||||||
|
|
||||||
if (text_.empty()) return state;
|
if (text_.empty()) return state;
|
||||||
|
|
||||||
auto st = style();
|
auto st = merged_style();
|
||||||
if (!st) return state;
|
if (!st) return state;
|
||||||
if (!st->font) return state;
|
if (!st->font) return state;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,29 @@
|
||||||
namespace psemek::ui
|
namespace psemek::ui
|
||||||
{
|
{
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void merge(std::optional<T> & dst, std::optional<T> const & src)
|
||||||
|
{
|
||||||
|
if (!dst) dst = src;
|
||||||
|
}
|
||||||
|
|
||||||
|
void merge(style & dst, style const & src)
|
||||||
|
{
|
||||||
|
merge(dst.bg_color, src.bg_color);
|
||||||
|
merge(dst.fg_color, src.fg_color);
|
||||||
|
merge(dst.highlight_color, src.highlight_color);
|
||||||
|
merge(dst.action_color, src.action_color);
|
||||||
|
merge(dst.border_color, src.border_color);
|
||||||
|
merge(dst.border_width, src.border_width);
|
||||||
|
merge(dst.shadow_offset, src.shadow_offset);
|
||||||
|
merge(dst.shadow_color, src.shadow_color);
|
||||||
|
merge(dst.inner_margin, src.inner_margin);
|
||||||
|
merge(dst.outer_margin, src.outer_margin);
|
||||||
|
merge(dst.text_color, src.text_color);
|
||||||
|
merge(dst.text_scale, src.text_scale);
|
||||||
|
merge(dst.text_shadow_offset, src.text_shadow_offset);
|
||||||
|
}
|
||||||
|
|
||||||
style default_style()
|
style default_style()
|
||||||
{
|
{
|
||||||
style s;
|
style s;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue