267 lines
10 KiB
C++
267 lines
10 KiB
C++
#pragma once
|
|
|
|
#include "../renderable/Renderable.h"
|
|
|
|
#include <deque>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
namespace renderive {
|
|
|
|
struct Axis_Transform {
|
|
Range coordinate_range;
|
|
double pixel_origin{};
|
|
double pixel_length{};
|
|
|
|
[[nodiscard]] double coord_to_pixel(double coordinate) const noexcept {
|
|
const double span = coordinate_range.length();
|
|
if (span == 0.0)
|
|
return pixel_origin;
|
|
return pixel_origin + (coordinate - coordinate_range.origin) / span * pixel_length;
|
|
}
|
|
[[nodiscard]] double pixel_to_coord(double pixel) const noexcept {
|
|
if (pixel_length == 0.0)
|
|
return coordinate_range.origin;
|
|
return coordinate_range.origin + (pixel - pixel_origin) / pixel_length * coordinate_range.length();
|
|
}
|
|
};
|
|
|
|
class LIB_DECL Abs_Axis : public Renderable {
|
|
public:
|
|
explicit Abs_Axis(Plot_Core& plot, Orientation orientation = Orientation::Horizontal);
|
|
~Abs_Axis() override;
|
|
|
|
[[nodiscard]] int x() const;
|
|
void set_x(int value);
|
|
[[nodiscard]] int y() const;
|
|
void set_y(int value);
|
|
[[nodiscard]] Orientation orientation() const;
|
|
void set_orientation(Orientation value);
|
|
[[nodiscard]] std::size_t pixel_length() const;
|
|
void set_pixel_length(std::size_t value);
|
|
[[nodiscard]] int tick_length() const;
|
|
void set_tick_length(int value);
|
|
[[nodiscard]] int sub_tick_length() const;
|
|
void set_sub_tick_length(int value);
|
|
[[nodiscard]] Color color() const;
|
|
void set_color(Color value);
|
|
[[nodiscard]] Number_Locale locale() const;
|
|
void set_locale(Number_Locale value);
|
|
[[nodiscard]] std::string unit_text() const;
|
|
void set_unit_text(std::string value);
|
|
[[nodiscard]] Font unit_text_font() const;
|
|
void set_unit_text_font(Font value);
|
|
[[nodiscard]] Pen unit_text_pen() const;
|
|
void set_unit_text_pen(Pen value);
|
|
[[nodiscard]] Brush unit_text_background_brush() const;
|
|
void set_unit_text_background_brush(Brush value);
|
|
[[nodiscard]] int label_rotation_degrees() const;
|
|
void set_label_rotation_degrees(int value);
|
|
|
|
[[nodiscard]] virtual Range coord_range() const = 0;
|
|
[[nodiscard]] virtual double pixel_to_coord(double pixel) const;
|
|
[[nodiscard]] virtual double coord_to_pixel(double coordinate) const;
|
|
[[nodiscard]] Axis_Transform transform() const;
|
|
[[nodiscard]] double start_coord() const;
|
|
[[nodiscard]] double end_coord() const;
|
|
[[nodiscard]] int pixel_sample_count(Range range) const;
|
|
[[nodiscard]] int pixel_sample_count() const;
|
|
[[nodiscard]] virtual double tick_step(Range range) const;
|
|
[[nodiscard]] virtual int sub_tick_count(double major_step) const;
|
|
[[nodiscard]] virtual std::string tick_label(double tick) const;
|
|
|
|
protected:
|
|
struct State {
|
|
int x{};
|
|
int y{};
|
|
Orientation orientation = Orientation::Horizontal;
|
|
std::size_t pixel_length{};
|
|
int tick_length = 10;
|
|
int sub_tick_length = 5;
|
|
Color color = Color::white();
|
|
Number_Locale locale;
|
|
std::string unit_text;
|
|
Font unit_text_font;
|
|
Pen unit_text_pen{Color::white()};
|
|
Brush unit_text_background_brush{Color::black(), Brush_Style::Solid};
|
|
int label_rotation_degrees{};
|
|
};
|
|
|
|
[[nodiscard]] State axis_state() const;
|
|
void paint(detail::Painter& painter) override;
|
|
|
|
private:
|
|
mutable std::mutex axis_mutex_;
|
|
State axis_state_;
|
|
};
|
|
|
|
template <class Derived>
|
|
class Axis_Builder_Base {
|
|
public:
|
|
Derived& set_x(int value) { x_ = value; return derived(); }
|
|
Derived& set_y(int value) { y_ = value; return derived(); }
|
|
Derived& set_orientation(Orientation value) { orientation_ = value; return derived(); }
|
|
Derived& set_pixel_length(std::size_t value) { pixel_length_ = value; return derived(); }
|
|
Derived& set_tick_length(int value) { tick_length_ = value; return derived(); }
|
|
Derived& set_sub_tick_length(int value) { sub_tick_length_ = value; return derived(); }
|
|
Derived& set_color(Color value) { color_ = value; return derived(); }
|
|
Derived& set_unit_text(std::string value) { unit_text_ = std::move(value); return derived(); }
|
|
Derived& set_unit_text_font(Font value) { unit_text_font_ = value; return derived(); }
|
|
Derived& set_unit_text_pen(Pen value) { unit_text_pen_ = value; return derived(); }
|
|
Derived& set_unit_text_background_brush(Brush value) { unit_background_ = value; return derived(); }
|
|
Derived& set_label_rotation_degrees(int value) { label_rotation_ = value; return derived(); }
|
|
|
|
protected:
|
|
explicit Axis_Builder_Base(std::shared_ptr<Renderable> parent, Orientation orientation)
|
|
: parent_(std::move(parent)), orientation_(orientation) {}
|
|
|
|
void apply(Abs_Axis& axis) const {
|
|
axis.set_x(x_);
|
|
axis.set_y(y_);
|
|
axis.set_orientation(orientation_);
|
|
axis.set_pixel_length(pixel_length_);
|
|
axis.set_tick_length(tick_length_);
|
|
axis.set_sub_tick_length(sub_tick_length_);
|
|
axis.set_color(color_);
|
|
axis.set_unit_text(unit_text_);
|
|
axis.set_unit_text_font(unit_text_font_);
|
|
axis.set_unit_text_pen(unit_text_pen_);
|
|
axis.set_unit_text_background_brush(unit_background_);
|
|
axis.set_label_rotation_degrees(label_rotation_);
|
|
}
|
|
[[nodiscard]] Derived& derived() { return static_cast<Derived&>(*this); }
|
|
|
|
std::shared_ptr<Renderable> parent_;
|
|
int x_{};
|
|
int y_{};
|
|
Orientation orientation_;
|
|
std::size_t pixel_length_{};
|
|
int tick_length_ = 10;
|
|
int sub_tick_length_ = 5;
|
|
Color color_ = Color::white();
|
|
std::string unit_text_;
|
|
Font unit_text_font_;
|
|
Pen unit_text_pen_{Color::white()};
|
|
Brush unit_background_{Color::black(), Brush_Style::Solid};
|
|
int label_rotation_{};
|
|
};
|
|
|
|
class LIB_DECL Axis : public Abs_Axis, public Event_Handler {
|
|
public:
|
|
explicit Axis(Plot_Core& plot, Orientation orientation = Orientation::Horizontal);
|
|
[[nodiscard]] Range coord_range() const override;
|
|
[[nodiscard]] int label_precision() const;
|
|
void set_label_precision(int value);
|
|
[[nodiscard]] double coord_start() const;
|
|
void set_coord_start(double value);
|
|
[[nodiscard]] double coord_length() const;
|
|
void set_coord_length(double value);
|
|
void set_coord_range(Range range);
|
|
void set_use_wheel(bool value);
|
|
void set_use_drag(bool value);
|
|
[[nodiscard]] bool use_wheel() const;
|
|
[[nodiscard]] bool use_drag() const;
|
|
void handle_event(const Event& event) override;
|
|
[[nodiscard]] std::string tick_label(double tick) const override;
|
|
|
|
class Builder : public Axis_Builder_Base<Builder> {
|
|
public:
|
|
Builder(std::shared_ptr<Renderable> parent, Orientation orientation);
|
|
Builder& set_coord_range(Range value) { coordinates_ = value; return *this; }
|
|
Builder& set_label_precision(int value) { precision_ = value; return *this; }
|
|
Builder& set_use_wheel(bool value) { wheel_ = value; return *this; }
|
|
Builder& set_use_drag(bool value) { drag_ = value; return *this; }
|
|
std::shared_ptr<Axis> build();
|
|
private:
|
|
Range coordinates_{0.0, 20.0};
|
|
int precision_ = 2;
|
|
bool wheel_{};
|
|
bool drag_{};
|
|
};
|
|
|
|
private:
|
|
mutable std::mutex interaction_mutex_;
|
|
Range coordinates_{0.0, 20.0};
|
|
int precision_ = 2;
|
|
bool wheel_enabled_{};
|
|
bool drag_enabled_{};
|
|
bool dragging_{};
|
|
PointF last_pointer_{};
|
|
};
|
|
|
|
class LIB_DECL Frequency_Axis : public Axis {
|
|
public:
|
|
explicit Frequency_Axis(Plot_Core& plot, Orientation orientation = Orientation::Horizontal);
|
|
[[nodiscard]] std::string tick_label(double tick) const override;
|
|
|
|
class Builder : public Axis_Builder_Base<Builder> {
|
|
public:
|
|
Builder(std::shared_ptr<Renderable> parent, Orientation orientation);
|
|
Builder& set_coord_range(Range value) { coordinates_ = value; return *this; }
|
|
Builder& set_label_precision(int value) { precision_ = value; return *this; }
|
|
Builder& set_use_wheel(bool value) { wheel_ = value; return *this; }
|
|
Builder& set_use_drag(bool value) { drag_ = value; return *this; }
|
|
std::shared_ptr<Frequency_Axis> build();
|
|
private:
|
|
Range coordinates_{0.0, 20.0};
|
|
int precision_ = 2;
|
|
bool wheel_{};
|
|
bool drag_{};
|
|
};
|
|
};
|
|
|
|
class LIB_DECL Time_Axis : public Abs_Axis {
|
|
public:
|
|
explicit Time_Axis(Plot_Core& plot, Orientation orientation = Orientation::Horizontal);
|
|
[[nodiscard]] int visible_time_point_count() const;
|
|
void set_visible_time_point_count(int value);
|
|
[[nodiscard]] int tick_label_spacing_px() const;
|
|
void set_tick_label_spacing_px(int value);
|
|
[[nodiscard]] std::string time_format() const;
|
|
void set_time_format(std::string value);
|
|
[[nodiscard]] Font font() const;
|
|
void set_font(Font value);
|
|
[[nodiscard]] bool newest_at_axis_start() const;
|
|
void set_newest_at_axis_start(bool value);
|
|
[[nodiscard]] std::size_t time_point_count() const;
|
|
int append_time(Time_Of_Day time);
|
|
[[nodiscard]] Time_Of_Day tick_to_time(int tick) const;
|
|
[[nodiscard]] Range coord_range() const override;
|
|
[[nodiscard]] double tick_step(Range range) const override;
|
|
[[nodiscard]] std::string tick_label(double tick) const override;
|
|
|
|
class Builder : public Axis_Builder_Base<Builder> {
|
|
public:
|
|
Builder(std::shared_ptr<Renderable> parent, Orientation orientation);
|
|
Builder& set_visible_time_point_count(int value) { visible_count_ = value; return *this; }
|
|
Builder& set_tick_label_spacing_px(int value) { spacing_ = value; return *this; }
|
|
Builder& set_time_format(std::string value) { format_ = std::move(value); return *this; }
|
|
Builder& set_font(Font value) { font_ = value; return *this; }
|
|
Builder& set_newest_at_axis_start(bool value) { newest_at_start_ = value; return *this; }
|
|
std::shared_ptr<Time_Axis> build();
|
|
private:
|
|
int visible_count_ = 100;
|
|
int spacing_ = 8;
|
|
std::string format_ = "mm:ss.zzz";
|
|
Font font_;
|
|
bool newest_at_start_{};
|
|
};
|
|
|
|
private:
|
|
struct Time_State {
|
|
int visible_count = 100;
|
|
int tick_label_spacing_px = 8;
|
|
std::string format = "mm:ss.zzz";
|
|
bool newest_at_start{};
|
|
int next_tick{};
|
|
std::deque<std::pair<int, Time_Of_Day>> samples;
|
|
};
|
|
mutable std::mutex time_mutex_;
|
|
Time_State time_state_;
|
|
};
|
|
|
|
} // namespace renderive
|