#include #include namespace psemek::ui { namespace { struct button_impl : button { button_impl(std::string text) { set_label(std::make_shared()); label()->set_text(std::move(text)); label()->set_valign(label::valignment::center); label()->set_halign(label::halignment::center); label()->set_overflow(label::overflow_mode::drop); label()->set_multiline(label::multiline_mode::none); } button_impl(std::shared_ptr tex) { set_icon(std::make_shared()); icon()->set_image(std::move(tex)); icon()->set_downscale(false); icon()->set_upscale(false); } struct shape const & shape() const override { return shape_; } void reshape(geom::box const & bbox) override { shape_.box = bbox; auto st = merged_style(); element * c = label() ? (element *)label() : icon(); if (st && c) c->reshape(geom::shrink(bbox, 1.f * (*st->border_width + *st->inner_margin))); } void on_state_changed() override { gfx::color_rgba color{0, 0, 0, 0}; switch (state()) { case state_t::mouseover: color = {255, 255, 255, 63}; break; case state_t::mousedown: color = {0, 0, 0, 63}; break; default: break; } if (icon()) icon()->set_color(color); } void draw(painter & p) const override { auto st = merged_style(); if (!st) return; if (st->shadow_offset != geom::vector{0, 0}) p.draw_rect(shape_.box + geom::cast(*st->shadow_offset), *st->shadow_color); if (st->border_width > 0) p.draw_rect(shape_.box, *st->border_color); gfx::color_rgba color = *st->fg_color; if (state() == state_t::mouseover) color = *st->highlight_color; else if (state() == state_t::mousedown) color = *st->action_color; p.draw_rect(geom::shrink(shape_.box, 1.f * (*st->border_width)), color); } geom::box size_constraints() const override { auto sc = element::size_constraints(); element const * c = label() ? (element const *)label() : icon(); if (c) { sc = c->size_constraints(); if (auto st = merged_style()) { float extra = 2.f * (*st->border_width + *st->inner_margin); sc[0] += extra; sc[1] += extra; } } return sc; } private: box_shape shape_; }; struct frame_impl : frame { struct shape const & shape() const override { return shape_; } void reshape(geom::box const & bbox) override { shape_.box = bbox; 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))); } geom::box size_constraints() const override { geom::box r = element::size_constraints(); for (auto c : children()) if (c) r = c->size_constraints(); auto st = merged_style(); if (st) { float extra = 2.f * (*st->border_width + *st->outer_margin); r[0] += extra; r[1] += extra; } if (min_size()) { auto s = *min_size(); r[0].min = s[0]; r[1].min = s[1]; } if (max_size()) { auto s = *max_size(); r[0].max = s[0]; r[1].max = s[1]; } return r; } void draw(painter & p) const override { auto st = merged_style(); if (!st) return; if (st->shadow_offset != geom::vector{0, 0}) p.draw_rect(shape_.box + geom::cast(*st->shadow_offset), *st->shadow_color); if (st->border_width > 0) p.draw_rect(shape_.box, *st->border_color); p.draw_rect(geom::shrink(shape_.box, 1.f * (*st->border_width)), *st->bg_color); } private: box_shape shape_; }; } struct default_element_factory::impl {}; default_element_factory::default_element_factory() : pimpl_{make_impl()} {} default_element_factory::~default_element_factory() = default; std::shared_ptr