137 lines
5.8 KiB
C++
137 lines
5.8 KiB
C++
#include "Marker.h"
|
|
#include <algorithm>
|
|
#include "../Axis/Abs_Axis_p.h"
|
|
#include "../base/Memory.h"
|
|
#include "../render/Canvas.h"
|
|
namespace renderive {
|
|
struct Marker_Render_State : Render_State, Marker_Prop {};
|
|
struct Marker_Input_Data : Latest_Input_Data {
|
|
std::pmr::vector<Marker_Item> items{memory_resource(Memory_Domain::Other)};
|
|
void push(std::span<const Marker_Item> value) {
|
|
items.assign(value.begin(), value.end());
|
|
mark_latest_pushed();
|
|
}
|
|
void push(std::pmr::vector<Marker_Item>&& value) {
|
|
items = std::move(value);
|
|
mark_latest_pushed();
|
|
}
|
|
void clear() override {
|
|
items.clear();
|
|
clear_latest();
|
|
}
|
|
};
|
|
struct Marker_Private : Typed_Render_Data<Marker, Marker_Render_State, Marker_Input_Data> {
|
|
std::pmr::vector<Marker_Item> prepared_items{memory_resource(Memory_Domain::Other)};
|
|
bool use_prepared_items = false;
|
|
void draw_item(Canvas& canvas, const Marker_Item& item, const Axis_Mapping_2D& mapping) {
|
|
PointF point = mapping.map(item.position);
|
|
PointF domain_start = mapping.map(item.position.x, mapping.value.coord_range.origin);
|
|
PointF domain_end = mapping.map(item.position.x, mapping.value.coord_range.target);
|
|
PointF value_start = mapping.map(mapping.domain.coord_range.origin, item.position.y);
|
|
PointF value_end = mapping.map(mapping.domain.coord_range.target, item.position.y);
|
|
canvas.set_pen(item.pen);
|
|
canvas.set_brush(item.brush);
|
|
if (item.mode == Marker_Mode::Point) {
|
|
canvas.draw_ellipse(point, item.radius, item.radius);
|
|
}
|
|
else if (item.mode == Marker_Mode::Domain_Line) {
|
|
canvas.draw_line(domain_start, domain_end);
|
|
}
|
|
else if (item.mode == Marker_Mode::Value_Line) {
|
|
canvas.draw_line(value_start, value_end);
|
|
}
|
|
else {
|
|
canvas.draw_line(domain_start, domain_end);
|
|
canvas.draw_line(value_start, value_end);
|
|
}
|
|
}
|
|
void prepare_data(const Render_Frame_Snapshot&, const Renderable_Frame_View& frame_view) override {
|
|
Marker_Input_Data* input = render_input_data(frame_view);
|
|
if (!input)
|
|
return;
|
|
if (!input->pending)
|
|
return;
|
|
prepared_items.swap(input->items);
|
|
use_prepared_items = true;
|
|
frame_view.consume_input();
|
|
}
|
|
void draw(Canvas& canvas, const Render_Frame_Snapshot& snapshot, const Renderable_Frame_View& frame_view) override {
|
|
Marker_Render_State* s = render_state(frame_view);
|
|
if (!s)
|
|
return;
|
|
auto domain_axis = s->domain_axis.lock();
|
|
auto value_axis = s->value_axis.lock();
|
|
if (!domain_axis || !value_axis)
|
|
return;
|
|
Axis_Mapping_2D mapping = Axis_Render_Access::mapping(domain_axis.get(), value_axis.get(), snapshot);
|
|
canvas.save();
|
|
if (use_prepared_items) {
|
|
for (const Marker_Item& item : prepared_items)
|
|
draw_item(canvas, item, mapping);
|
|
}
|
|
else {
|
|
Marker_Item item;
|
|
item.position = s->position;
|
|
item.radius = s->radius;
|
|
item.pen = s->pen;
|
|
item.brush = s->brush;
|
|
item.mode = s->mode;
|
|
draw_item(canvas, item, mapping);
|
|
}
|
|
canvas.restore();
|
|
}
|
|
};
|
|
RENDERIVE_DEFINE_RENDERABLE_BINDING(Marker, Marker_Private, Marker_Render_State, Marker_Input_Data, "Marker")
|
|
void Marker::update_items(std::span<const Marker_Item> items) {
|
|
if (!ok())
|
|
return;
|
|
Render_Input_Lease<Marker_Private, Marker_Input_Data> input(d());
|
|
input->push(items);
|
|
}
|
|
void Marker::update_items(std::pmr::vector<Marker_Item>&& items) {
|
|
if (!ok())
|
|
return;
|
|
Render_Input_Lease<Marker_Private, Marker_Input_Data> input(d());
|
|
input->push(std::move(items));
|
|
}
|
|
RENDERIVE_DEFINE_WEAK_STATE_PROP(Marker, Marker_Render_State, Abs_Axis, domain_axis)
|
|
RENDERIVE_DEFINE_WEAK_STATE_PROP(Marker, Marker_Render_State, Abs_Axis, value_axis)
|
|
RENDERIVE_DEFINE_STATE_PROP(Marker, Marker_Render_State, PointF, position)
|
|
double Marker::radius() {
|
|
return d()->edit_state_value(&Marker_Render_State::radius);
|
|
}
|
|
void Marker::set_radius(double value) {
|
|
d()->set_state_value(&Marker_Render_State::radius, std::max(0.0, value));
|
|
}
|
|
RENDERIVE_DEFINE_STATE_PROP(Marker, Marker_Render_State, Pen, pen)
|
|
RENDERIVE_DEFINE_STATE_PROP(Marker, Marker_Render_State, Brush, brush)
|
|
RENDERIVE_DEFINE_STATE_PROP(Marker, Marker_Render_State, Marker_Mode, mode)
|
|
Marker::Builder::Builder(std::shared_ptr<Renderable> parent, std::shared_ptr<Abs_Axis> domain_axis, std::shared_ptr<Abs_Axis> value_axis) {
|
|
ASSERT(parent, "Marker build error! parent == nullptr");
|
|
ASSERT(domain_axis && value_axis, "Marker build error! axis == nullptr");
|
|
ASSERT(domain_axis->attached_to_plot(), "Marker build error! domain_axis->plot == nullptr");
|
|
ASSERT(domain_axis->shares_plot_with(*value_axis), "Marker build error! domain_axis->plot != value_axis->plot");
|
|
ASSERT(parent->shares_plot_with(*domain_axis), "Marker build error! parent->plot != axis->plot");
|
|
ASSERT(domain_axis->orientation() != value_axis->orientation(), "Marker build error! axes must be orthogonal");
|
|
this->parent = parent;
|
|
this->domain_axis = domain_axis;
|
|
this->value_axis = value_axis;
|
|
}
|
|
std::shared_ptr<Marker> Marker::Builder::build() {
|
|
auto ret = renderive::make_shared<Marker>();
|
|
ret->init(parent);
|
|
Marker_Private* pd = ret->d();
|
|
Render_Edit_Lease<Marker_Private, Marker_Render_State> edit(pd);
|
|
Marker_Render_State* sc = edit.operator->();
|
|
PROP_R(std::weak_ptr<Abs_Axis>, domain_axis)
|
|
PROP_R(std::weak_ptr<Abs_Axis>, value_axis)
|
|
PROP_R(PointF, position)
|
|
PROP_R(double, radius)
|
|
PROP_R(Pen, pen)
|
|
PROP_R(Brush, brush)
|
|
PROP_R(Marker_Mode, mode)
|
|
sc->radius = std::max(0.0, sc->radius);
|
|
return ret;
|
|
}
|
|
} // namespace renderive
|