#pragma once #include #include #include #include #include #include #include #include #include #include #include namespace psemek::ui { struct element : std::enable_shared_from_this { virtual element * parent() const { return parent_; } virtual void set_parent(element * parent); using children_range = util::span; virtual children_range children() const { return {}; } virtual element * root(); virtual element const * root() const; virtual async::event_loop * loop() const; virtual void set_loop(async::event_loop * loop); virtual geom::box events_bbox() const; virtual bool on_event(mouse_move const &) { return false; } virtual bool on_event(mouse_click const &) { return false; } virtual bool on_event(mouse_wheel const &) { return false; } virtual bool on_event(key_press const &) { return false; } virtual bool on_event(text_input const &) { return false; } virtual bool focused() const { return false; } virtual struct shape const & shape() const = 0; virtual void reshape(geom::box const & bbox) = 0; virtual void reshape(); // Constraints on the element's width & height, assuming unlimited available space virtual geom::box size_constraints() const; // Constraints on the element's width, assuming fixed height virtual geom::interval width_constraints(float height) const; // Constraints on the element's height, assuming fixed width virtual geom::interval height_constraints(float width) const; virtual bool enabled() const { return enabled_; } virtual void set_enabled(bool value) { enabled_ = value; } virtual void enable() { set_enabled(true); } virtual void disable() { set_enabled(false); } virtual bool hidden() const { return hidden_; } virtual void set_hidden(bool value) { hidden_ = value; } virtual void hide() { set_hidden(true); } virtual void show() { set_hidden(false); } virtual bool transparent() const { return false; } virtual std::shared_ptr style() const { return style_; } virtual std::shared_ptr own_style() const { return own_style_; } virtual std::shared_ptr set_style(std::shared_ptr st); virtual std::shared_ptr set_own_style(std::shared_ptr st); virtual void style_updated() const; virtual void own_style_updated() const; virtual std::optional const & id() const { return id_; } virtual std::optional set_id(std::optional id); virtual std::optional const & hint() const { return hint_; } virtual std::optional set_hint(std::optional hint); virtual std::any const & data() const { return data_; } virtual std::any & data() { return data_; } virtual void update(float /* dt */) {} virtual void draw(painter & p) const = 0; virtual void post_draw(painter & /* p */) const {} virtual ~element(); virtual void post(util::function f) const; virtual void post_reshape(); protected: virtual void release_children(); virtual std::shared_ptr merged_style() const; virtual std::shared_ptr merged_own_style() const; static bool in_text_input(); static void start_text_input(); static void stop_text_input(); private: element * parent_ = nullptr; async::event_loop * loop_ = nullptr; std::shared_ptr style_; std::shared_ptr own_style_; mutable std::shared_ptr merged_style_; mutable std::shared_ptr merged_own_style_; bool reshape_posted_ = false; bool enabled_ = true; bool hidden_ = false; mutable std::vector> delayed_callbacks_; std::optional id_; std::optional hint_; std::any data_; void post_delayed_callbacks() const; }; template Type * find_first_parent_of_type(element * e) { while (true) { if (!e) return nullptr; if (auto p = dynamic_cast(e)) return p; e = e->parent(); } } template Type * find_last_parent_of_type(element * e) { Type * r = nullptr; while (true) { if (auto p = find_first_parent_of_type(e)) { r = p; e = p->parent(); } else return r; } } element * find_element_by_id(element * root, std::string_view id); void send_fake_mouse_move_event(element * e, bool mouseover); }