#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace psemek::ui { namespace { struct button_impl : button { struct shape const & shape() const override { return shape_; } void reshape(math::box const & bbox) override { shape_.box = bbox; auto st = merged_own_style(); math::vector offset{0.f, 0.f}; if (state() == state_t::mousedown) offset = math::cast(*st->action_offset); auto c = child_.get(); if (c) c->reshape(math::shrink(bbox, math::vector{*st->border_width + (*st->inner_margin)[0], *st->border_width + (*st->inner_margin)[1]}) + offset); } void on_state_changed(state_t old) override { button::on_state_changed(old); 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_own_style(); if (!st) return; if (st->shadow_offset != math::vector{0, 0}) p.draw_rect(shape_.box + math::cast(*st->shadow_offset), *st->shadow_color); auto offset = math::vector{0.f, 0.f}; if (state() == state_t::mousedown) offset = math::cast(*st->action_offset); if (st->border_width > 0) p.draw_rect(shape_.box + offset, *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(math::shrink(shape_.box, 1.f * (*st->border_width)) + offset, color); } math::box size_constraints() const override { auto sc = element::size_constraints(); if (child_) { auto csc = child_->size_constraints(); sc[0].min = csc[0].min; sc[1].min = csc[1].min; } if (auto st = merged_own_style()) { sc[0] += 2.f * (*st->border_width); sc[1] += 2.f * (*st->border_width); sc += 2.f * math::cast(*st->inner_margin); } return sc; } math::interval width_constraints(float height) const override { auto wc = element::width_constraints(height); auto st = merged_own_style(); float extra = 2.f * (*st->border_width) + 2.f * math::cast(*st->inner_margin)[0]; if (child_) { auto cwc = child_->width_constraints(height - extra); wc.min = cwc.min; } wc += extra; return wc; } math::interval height_constraints(float width) const override { auto hc = element::height_constraints(width); auto st = merged_own_style(); float extra = 2.f * (*st->border_width) + 2.f * math::cast(*st->inner_margin)[1]; if (child_) { auto chc = child_->height_constraints(width - extra); hc.min = chc.min; } hc += extra; return hc; } private: box_shape shape_; }; struct frame_impl : frame { struct shape const & shape() const override { return shape_; } void reshape(math::box const & bbox) override { shape_.box = bbox; auto st = merged_own_style(); if (!st) return; for (auto c : children()) if (c) c->reshape(math::shrink(bbox, 1.f * (*st->border_width + *st->bevel_width + *st->outer_margin))); } math::box size_constraints() const override { math::box sc = frame::size_constraints(); auto st = merged_own_style(); if (st) { float extra = 2.f * (*st->border_width + *st->bevel_width + *st->outer_margin); sc[0] += extra; sc[1] += extra; } return sc; } math::interval width_constraints(float height) const override { auto wc = frame::width_constraints(height); auto st = merged_own_style(); if (st) { float extra = 2.f * (*st->border_width + *st->bevel_width + *st->outer_margin); wc += extra; } return wc; } math::interval height_constraints(float width) const override { auto hc = frame::height_constraints(width); auto st = merged_own_style(); if (st) { float extra = 2.f * (*st->border_width + *st->bevel_width + *st->outer_margin); hc += extra; } return hc; } void draw(painter & p) const override { auto st = merged_own_style(); if (!st) return; if (st->shadow_offset != math::vector{0, 0}) p.draw_rect(shape_.box + math::cast(*st->shadow_offset), *st->shadow_color); if (st->border_width > 0) p.draw_rect(shape_.box, *st->border_color); if (st->bevel_width > 0) { math::point corners[4]; math::point corners_in[4]; auto box = math::shrink(shape_.box, *st->border_width); corners[0] = box.corner(0, 0); corners[1] = box.corner(1, 0); corners[2] = box.corner(1, 1); corners[3] = box.corner(0, 1); auto box_in = math::shrink(box, *st->bevel_width); corners_in[0] = box_in.corner(0, 0); corners_in[1] = box_in.corner(1, 0); corners_in[2] = box_in.corner(1, 1); corners_in[3] = box_in.corner(0, 1); auto c1 = *st->bevel_light_color; auto c2 = *st->bevel_dark_color; if (*st->bevel_type == bevel_type::down) std::swap(c1, c2); p.draw_triangle({corners[0], corners_in[0], corners[1]}, c1); p.draw_triangle({corners[1], corners_in[0], corners_in[1]}, c1); p.draw_triangle({corners[1], corners_in[1], corners[2]}, c1); p.draw_triangle({corners[2], corners_in[1], corners_in[2]}, c1); p.draw_triangle({corners[2], corners_in[2], corners[3]}, c2); p.draw_triangle({corners[3], corners_in[2], corners_in[3]}, c2); p.draw_triangle({corners[3], corners_in[3], corners[0]}, c2); p.draw_triangle({corners[0], corners_in[3], corners_in[0]}, c2); } p.draw_rect(math::shrink(shape_.box, 1.f * (*st->border_width + *st->bevel_width)), *st->bg_color); } private: box_shape shape_; }; struct window_impl : window { window_impl(std::shared_ptr close_icon) : close_texture_(std::move(close_icon)) , caption_(std::make_shared