Files
Renderive/Core/plottable/Hover_Tooltip.h
T
2026-08-02 03:43:39 +08:00

167 lines
6.0 KiB
C++

#pragma once
#include <functional>
#include <string>
#include <utility>
#include <vector>
#include "../Axis/export.h"
#include "../base/Color.h"
#include "../base/Geometry.h"
#include "../base/Style.h"
#include "../base/Text.h"
#include "../render/Canvas.h"
namespace renderive {
struct Hover_Tooltip_State;
struct Hover_Tooltip_Provider;
struct LIB_DECL Hover_Tooltip_State {
virtual ~Hover_Tooltip_State() = default;
Hover_Tooltip_State() {
tooltip_background_brush = Brush{Color::white(), Brush_Style::Solid};
tooltip_text_pen = Pen{Color::black()};
}
int hover_info_left = 4;
int hover_info_top = 4;
int hover_info_right = 4;
int hover_info_bottom = 4;
Brush tooltip_background_brush;
Font hover_info_font;
Pen tooltip_text_pen;
bool use_hover_tooltip = true;
bool hover_info_active = false;
Point hover_position;
void draw_hover_tooltip(Canvas* canvas, Abs_Axis* domain_axis, Abs_Axis* value_axis, Hover_Tooltip_Provider* renderable);
bool can_show_hover(Renderable* able) const;
};
struct LIB_DECL Hover_Tooltip_Provider {
struct Hover_State_Edit {
Hover_State_Edit() = default;
Hover_State_Edit(Hover_Tooltip_Provider* owner, Hover_Tooltip_State* state, std::function<void()> on_finish)
: owner(owner), state(state), on_finish(std::move(on_finish)) {}
Hover_State_Edit(const Hover_State_Edit&) = delete;
Hover_State_Edit& operator=(const Hover_State_Edit&) = delete;
Hover_State_Edit(Hover_State_Edit&& other) noexcept
: owner(std::exchange(other.owner, nullptr)),
state(std::exchange(other.state, nullptr)),
on_finish(std::move(other.on_finish)) {}
Hover_State_Edit& operator=(Hover_State_Edit&& other) noexcept {
if (this == &other)
return *this;
finish();
owner = std::exchange(other.owner, nullptr);
state = std::exchange(other.state, nullptr);
on_finish = std::move(other.on_finish);
return *this;
}
~Hover_State_Edit() {
finish();
}
Hover_Tooltip_State* operator->() const {
return state;
}
private:
void finish() {
if (!owner)
return;
if (on_finish)
on_finish();
on_finish = {};
owner = nullptr;
state = nullptr;
}
Hover_Tooltip_Provider* owner{};
Hover_Tooltip_State* state{};
std::function<void()> on_finish{};
};
virtual std::vector<std::string> build_hover_lines(Abs_Axis* h, Abs_Axis* v, Point pos);
virtual ~Hover_Tooltip_Provider() = default;
virtual void draw_hover_tooltip(Canvas* canvas, Abs_Axis* h, Abs_Axis* v) {
return hover_render_state()->draw_hover_tooltip(canvas, h, v, this);
}
virtual bool hover_ok(Renderable* able) {
return hover_render_state()->can_show_hover(able);
}
virtual bool hit_test_hover(Point pos) {
(void)pos;
return true;
}
bool hover_tooltip_enabled() {
return hover_edit_state()->use_hover_tooltip;
}
void set_use_hover_info(bool use) {
auto edit = begin_hover_edit();
edit->use_hover_tooltip = use;
}
void set_hover_tooltip_font(const Font& font) {
auto edit = begin_hover_edit();
edit->hover_info_font = font;
}
Font hover_tooltip_font() {
return hover_edit_state()->hover_info_font;
}
Brush hover_info_background_brush() {
return hover_edit_state()->tooltip_background_brush;
}
void set_hover_tooltip_background_brush(const Brush& brush) {
auto edit = begin_hover_edit();
edit->tooltip_background_brush = brush.color.a != 0 ? brush : Brush{};
}
Pen tooltip_text_pen() {
return hover_edit_state()->tooltip_text_pen;
}
void set_tooltip_text_pen(const Pen& pen) {
auto edit = begin_hover_edit();
edit->tooltip_text_pen = pen.color.a != 0 ? pen : Pen{.style = Line_Style::None};
}
void get_hover_tooltip_contents_margins(int& left, int& top, int& right, int& bottom) {
auto s = hover_edit_state();
left = s->hover_info_left;
top = s->hover_info_top;
right = s->hover_info_right;
bottom = s->hover_info_bottom;
}
void set_hover_tooltip_contents_margins(int left, int top, int right, int bottom) {
auto edit = begin_hover_edit();
edit->hover_info_left = left;
edit->hover_info_top = top;
edit->hover_info_right = right;
edit->hover_info_bottom = bottom;
}
Hover_State_Edit begin_hover_edit() {
return begin_hover_edit_impl();
}
private:
virtual Hover_Tooltip_State* hover_edit_state() = 0;
virtual Hover_Tooltip_State* hover_render_state() = 0;
virtual Hover_State_Edit begin_hover_edit_impl() = 0;
};
template <typename That>
struct LIB_DECL Hover_Info_Renderable : Hover_Tooltip_Provider {
private:
That* that() {
return static_cast<That*>(this);
}
Hover_Tooltip_State* hover_edit_state() override {
auto t = that();
return dynamic_cast<Hover_Tooltip_State*>(t->d_ptr->state(State_Edit));
}
Hover_Tooltip_State* hover_render_state() override {
auto t = that();
return dynamic_cast<Hover_Tooltip_State*>(t->d_ptr->state(State_Render));
}
Hover_State_Edit begin_hover_edit_impl() override {
auto t = that();
auto record = t->d_ptr->state_control.try_acquire_role(State_Edit);
if (record.result != Triple_Buffer_Result::Success)
return {};
auto lease = record.lease;
auto* data = t->d_ptr;
auto* state = dynamic_cast<Hover_Tooltip_State*>(data->state_by_index(lease.index));
return Hover_State_Edit(this, state, [data, lease]() mutable {
++data->state_by_index(lease.index)->version;
if (data->q_ptr)
data->q_ptr->mark_render_dirty();
data->state_control.unmark_use(lease);
});
}
};
} // namespace renderive