psemek/libs/ui_legacy/include/psemek/ui/element.hpp

165 lines
4.6 KiB
C++

#pragma once
#include <psemek/ui/shape.hpp>
#include <psemek/ui/event.hpp>
#include <psemek/ui/painter.hpp>
#include <psemek/ui/style.hpp>
#include <psemek/async/event_loop.hpp>
#include <psemek/util/span.hpp>
#include <psemek/util/function.hpp>
#include <memory>
#include <optional>
#include <string>
#include <any>
namespace psemek::ui
{
struct element
: std::enable_shared_from_this<element>
{
virtual element * parent() const { return parent_; }
virtual void set_parent(element * parent);
using children_range = util::span<element * const>;
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<float, 2> 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<float, 2> const & bbox) = 0;
virtual void reshape();
// Constraints on the element's width & height, assuming unlimited available space
virtual geom::box<float, 2> size_constraints() const;
// Constraints on the element's width, assuming fixed height
virtual geom::interval<float> width_constraints(float height) const;
// Constraints on the element's height, assuming fixed width
virtual geom::interval<float> 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<struct style> style() const { return style_; }
virtual std::shared_ptr<struct style> own_style() const { return own_style_; }
virtual std::shared_ptr<struct style> set_style(std::shared_ptr<struct style> st);
virtual std::shared_ptr<struct style> set_own_style(std::shared_ptr<struct style> st);
virtual void style_updated() const;
virtual void own_style_updated() const;
virtual std::optional<std::string> const & id() const { return id_; }
virtual std::optional<std::string> set_id(std::optional<std::string> id);
virtual std::optional<std::string> const & hint() const { return hint_; }
virtual std::optional<std::string> set_hint(std::optional<std::string> 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<void()> f) const;
virtual void post_reshape();
protected:
virtual void release_children();
virtual std::shared_ptr<struct style> merged_style() const;
virtual std::shared_ptr<struct style> 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<struct style> style_;
std::shared_ptr<struct style> own_style_;
mutable std::shared_ptr<struct style> merged_style_;
mutable std::shared_ptr<struct style> merged_own_style_;
bool reshape_posted_ = false;
bool enabled_ = true;
bool hidden_ = false;
mutable std::vector<util::function<void()>> delayed_callbacks_;
std::optional<std::string> id_;
std::optional<std::string> hint_;
std::any data_;
void post_delayed_callbacks() const;
};
template <typename Type>
Type * find_first_parent_of_type(element * e)
{
while (true)
{
if (!e)
return nullptr;
if (auto p = dynamic_cast<Type *>(e))
return p;
e = e->parent();
}
}
template <typename Type>
Type * find_last_parent_of_type(element * e)
{
Type * r = nullptr;
while (true)
{
if (auto p = find_first_parent_of_type<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);
}