#include "Numeric_Axis.h" #include "Axis_Format.h" #include #include 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(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(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(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