#include #include #include #include #include #include namespace psemek::ui { namespace { struct root_proxy : element { children_range children() const override { return children_range{&root_raw, &root_raw + 1}; } struct shape const & shape() const override { return shape_; } using element::reshape; void reshape(geom::box const & bbox) override { shape_.box = bbox; if (root) root->reshape(bbox); if (on_reshape) post(on_reshape); } geom::box size_constraints() const override { return root->size_constraints(); } void draw(painter &) const override {} std::shared_ptr root; element * root_raw = nullptr; box_shape shape_; std::function on_reshape; }; } struct controller::impl { async::event_loop * loop; painter_impl painter; std::shared_ptr root; std::optional> mouse; impl(async::event_loop * loop); template bool event(E const & e); void update(float dt); }; controller::impl::impl(async::event_loop * loop) : loop(loop) , root{std::make_shared()} { root->set_loop(loop); root->on_reshape = [this]{ if (mouse) event(mouse_move{*mouse}); }; } template bool controller::impl::event(E const & e) { auto visitor = util::recursive([&](auto && self, element * elem) -> bool { if (elem->hidden()) return false; auto cs = elem->children(); for (auto it = cs.rbegin(); it != cs.rend(); ++it) if (*it && self(*it)) return true; if (elem->enabled() && elem->on_event(e)) return true; return false; }); if (root) return visitor(root.get()); return false; } void controller::impl::update(float dt) { auto visitor = util::recursive([dt](auto && self, element * elem) -> void { if (elem->enabled()) elem->update(dt); for (auto c : elem->children()) if (c) self(c); }); if (root) visitor(root.get()); } controller::controller(async::event_loop * loop) : pimpl_{make_impl(loop)} {} async::event_loop * controller::loop() const { return impl().loop; } controller::~controller() = default; std::shared_ptr controller::set_root(std::shared_ptr r) { auto old = std::move(impl().root->root); if (old) old->set_parent(nullptr); impl().root->root = std::move(r); impl().root->root_raw = impl().root->root.get(); if (impl().root->root) impl().root->root->set_parent(impl().root.get()); impl().root->reshape(); return old; } element * controller::root() { return impl().root->root.get(); } void controller::reshape(geom::box const & shape) { impl().root->reshape(shape); } bool controller::event(mouse_move const & e) { impl().mouse = e.position; return impl().event(e); } bool controller::event(mouse_click const & e) { return impl().event(e); } bool controller::event(mouse_wheel const & e) { return impl().event(e); } bool controller::event(key_press const & e) { return impl().event(e); } void controller::update(float dt) { impl().update(dt); } void controller::render(gfx::render_target const & rt) { impl().painter.start_frame(geom::cast(rt.viewport)); auto visitor = util::recursive([&](auto && self, element * elem) -> void { if (elem->hidden()) return; bool const visible = !(impl().painter.current_bbox() & elem->shape().bbox()).empty(); if (visible) elem->draw(impl().painter); for (auto c : elem->children()) if (c) self(c); if (visible) elem->post_draw(impl().painter); }); visitor(impl().root.get()); rt.bind(); gl::Enable(gl::DEPTH_TEST); gl::DepthFunc(gl::LEQUAL); gl::Enable(gl::BLEND); gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); gl::Disable(gl::CULL_FACE); impl().painter.render(geom::window_camera{rt.viewport[0].length(), rt.viewport[1].length()}.transform()); } }