Files
Renderive/render_2D/axis/Numeric_Axis.cpp
T
2026-08-11 23:17:03 +08:00

158 lines
5.0 KiB
C++

#include "Numeric_Axis.h"
#include "Axis_Format.h"
#include <algorithm>
#include <cmath>
namespace renderive::detail {
namespace {
bool valid_range(Range range) {
return std::isfinite(range.origin) && std::isfinite(range.target) && range.size() > 0.0;
}
Numeric_Axis_State numeric_state_from(const Axis_Properties& properties) {
return {
properties.coordinates,
std::clamp(properties.precision, 0, 12),
properties.wheel,
properties.drag
};
}
} // namespace
Axis_Control::Axis_Control(Plot_Core& plot, const Axis_Properties& properties)
: Abs_Axis(plot, properties), numeric_(numeric_state_from(properties)) {}
Range Axis_Control::coord_range() const {
return numeric_.get<&Numeric_Axis_State::coordinates>();
}
int Axis_Control::label_precision() const {
return numeric_.get<&Numeric_Axis_State::precision>();
}
void Axis_Control::set_label_precision(int value) {
numeric_.set<&Numeric_Axis_State::precision>(std::clamp(value, 0, 12));
changed();
}
double Axis_Control::coord_start() const { return coord_range().origin; }
void Axis_Control::set_coord_start(double value) {
auto range = coord_range();
set_coord_range({value, value + range.length()});
}
double Axis_Control::coord_length() const { return coord_range().length(); }
void Axis_Control::set_coord_length(double value) {
auto range = coord_range();
set_coord_range({range.origin, range.origin + value});
}
void Axis_Control::set_coord_range(Range range) {
if (!valid_range(range))
return;
numeric_.set<&Numeric_Axis_State::coordinates>(range);
changed();
}
void Axis_Control::set_use_wheel(bool value) {
numeric_.set<&Numeric_Axis_State::wheel>(value);
changed();
}
void Axis_Control::set_use_drag(bool value) {
numeric_.set<&Numeric_Axis_State::drag>(value);
changed();
}
bool Axis_Control::use_wheel() const {
return numeric_.get<&Numeric_Axis_State::wheel>();
}
bool Axis_Control::use_drag() const {
return numeric_.get<&Numeric_Axis_State::drag>();
}
void Axis_Control::handle_event(const Event& event) {
if (event.type == Event_Type::Wheel && use_wheel()) {
const auto& wheel = static_cast<const Wheel_Event&>(event);
Range range = coord_range();
const double anchor_pixel = orientation() == Orientation::Horizontal ? wheel.position.x : wheel.position.y;
const double anchor = pixel_to_coord(anchor_pixel);
const double factor = wheel.angle_delta_y >= 0.0 ? 0.9 : 1.1;
set_coord_range({anchor + (range.origin - anchor) * factor,
anchor + (range.target - anchor) * factor});
event.accept();
return;
}
if (!use_drag())
return;
if (event.type == Event_Type::Pointer_Press) {
const auto& pointer = static_cast<const Pointer_Event&>(event);
if (pointer.button == Mouse_Button::Left) {
interaction_.update([&](Axis_Interaction_State& interaction) {
interaction.dragging = true;
interaction.last_pointer = pointer.position;
});
event.accept();
}
} else if (event.type == Event_Type::Pointer_Move) {
const auto& pointer = static_cast<const Pointer_Event&>(event);
PointF previous;
bool dragging{};
interaction_.update([&](Axis_Interaction_State& interaction) {
dragging = interaction.dragging;
if (!dragging)
return;
previous = interaction.last_pointer;
interaction.last_pointer = pointer.position;
});
if (!dragging)
return;
const double delta = orientation() == Orientation::Horizontal
? pointer.position.x - previous.x
: pointer.position.y - previous.y;
Range range = coord_range();
const double shift = pixel_length() == 0 ? 0.0 : -delta * range.length() / pixel_length();
set_coord_range({range.origin + shift, range.target + shift});
event.accept();
} else if (event.type == Event_Type::Pointer_Release) {
bool accepted{};
interaction_.update([&](Axis_Interaction_State& interaction) {
accepted = interaction.dragging;
interaction.dragging = false;
});
if (accepted)
event.accept();
}
}
std::string Axis_Control::tick_label(double tick) const {
return localized_axis_number(tick, label_precision(), locale());
}
void Axis_Control::publish() {
Abs_Axis::publish();
numeric_.publish();
interaction_.publish();
}
std::uint64_t Axis_Control::state_revision() const {
return Abs_Axis::state_revision() + numeric_.state_revision() + interaction_.state_revision();
}
Numeric_Axis_State Axis_Control::numeric_state() const {
return numeric_.read([](const Numeric_Axis_State& value) { return value; });
}
Numeric_Axis_State Axis_Control::render_numeric_state() const {
return numeric_.render_use_state();
}
} // namespace renderive::detail