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)
|
||||
, 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->text_scale = 2;
|
||||
|
||||
|
|
|
|||
|
|
@ -44,8 +44,9 @@ namespace psemek::ui
|
|||
virtual void enable() { set_enabled(true); }
|
||||
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> merged_style() const;
|
||||
|
||||
virtual void draw(painter & p) const = 0;
|
||||
|
||||
|
|
@ -59,6 +60,7 @@ namespace psemek::ui
|
|||
async::executor * loop_ = nullptr;
|
||||
bool enabled_ = true;
|
||||
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;
|
||||
};
|
||||
|
||||
void merge(style & dst, style const & src);
|
||||
|
||||
style default_style();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,9 +37,9 @@ namespace psemek::ui
|
|||
void reshape(geom::box<float, 2> const & bbox) override
|
||||
{
|
||||
shape_.box = bbox;
|
||||
auto s = style();
|
||||
auto st = merged_style();
|
||||
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
|
||||
|
|
@ -63,21 +63,21 @@ namespace psemek::ui
|
|||
|
||||
void draw(painter & p) const override
|
||||
{
|
||||
auto s = style();
|
||||
if (!s) return;
|
||||
auto st = merged_style();
|
||||
if (!st) return;
|
||||
|
||||
if (s->shadow_offset != geom::vector{0, 0})
|
||||
p.draw_rect(shape_.box + geom::cast<float>(*s->shadow_offset), *s->shadow_color);
|
||||
if (st->shadow_offset != geom::vector{0, 0})
|
||||
p.draw_rect(shape_.box + geom::cast<float>(*st->shadow_offset), *st->shadow_color);
|
||||
|
||||
if (s->border_width > 0)
|
||||
p.draw_rect(shape_.box, *s->border_color);
|
||||
if (st->border_width > 0)
|
||||
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)
|
||||
color = *s->highlight_color;
|
||||
color = *st->highlight_color;
|
||||
else if (state() == state_t::mousedown)
|
||||
color = *s->action_color;
|
||||
p.draw_rect(geom::shrink(shape_.box, 1.f * (*s->border_width)), color);
|
||||
color = *st->action_color;
|
||||
p.draw_rect(geom::shrink(shape_.box, 1.f * (*st->border_width)), color);
|
||||
}
|
||||
|
||||
geom::box<float, 2> size_constraints() const override
|
||||
|
|
@ -90,7 +90,7 @@ namespace psemek::ui
|
|||
{
|
||||
sc = c->size_constraints();
|
||||
|
||||
if (auto st = style())
|
||||
if (auto st = merged_style())
|
||||
{
|
||||
float extra = 2.f * (*st->border_width + *st->inner_margin);
|
||||
sc[0] += extra;
|
||||
|
|
@ -113,7 +113,7 @@ namespace psemek::ui
|
|||
void reshape(geom::box<float, 2> const & bbox) override
|
||||
{
|
||||
shape_.box = bbox;
|
||||
auto st = style();
|
||||
auto st = merged_style();
|
||||
if (!st) return;
|
||||
for (auto c : children())
|
||||
if (c) c->reshape(geom::shrink(bbox, 1.f * (*st->border_width + *st->outer_margin)));
|
||||
|
|
@ -127,7 +127,7 @@ namespace psemek::ui
|
|||
if (c)
|
||||
r = c->size_constraints();
|
||||
|
||||
auto st = style();
|
||||
auto st = merged_style();
|
||||
if (st)
|
||||
{
|
||||
float extra = 2.f * (*st->border_width + *st->outer_margin);
|
||||
|
|
@ -154,7 +154,7 @@ namespace psemek::ui
|
|||
|
||||
void draw(painter & p) const override
|
||||
{
|
||||
auto st = style();
|
||||
auto st = merged_style();
|
||||
if (!st) return;
|
||||
|
||||
if (st->shadow_offset != geom::vector{0, 0})
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include <psemek/ui/element.hpp>
|
||||
|
||||
#include <psemek/util/recursive.hpp>
|
||||
|
||||
#include <psemek/log/log.hpp>
|
||||
|
||||
namespace psemek::ui
|
||||
|
|
@ -37,19 +39,46 @@ namespace psemek::ui
|
|||
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::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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
auto l = loop();
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ namespace psemek::ui
|
|||
|
||||
geom::box<float, 2> grid_layout::size_constraints() const
|
||||
{
|
||||
auto st = style();
|
||||
auto st = merged_style();
|
||||
if (!st) return element::size_constraints();
|
||||
|
||||
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)
|
||||
{
|
||||
auto st = style();
|
||||
auto st = merged_style();
|
||||
if (!st) return;
|
||||
|
||||
float const margin = *st->outer_margin;
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ namespace psemek::ui
|
|||
|
||||
if (!cached_state_->font) return;
|
||||
|
||||
auto st = style();
|
||||
auto st = merged_style();
|
||||
if (!st) return;
|
||||
|
||||
if (st->text_shadow_offset != geom::vector{0, 0})
|
||||
|
|
@ -91,7 +91,7 @@ namespace psemek::ui
|
|||
|
||||
if (text_.empty()) return state;
|
||||
|
||||
auto st = style();
|
||||
auto st = merged_style();
|
||||
if (!st) return state;
|
||||
if (!st->font) return state;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,29 @@
|
|||
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 s;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue