Files
plotter/include/plot/plot/cursor.hpp
T

72 lines
3.6 KiB
C++

#pragma once
#include <string>
#include <plot/core/color.hpp>
#include <plot/core/types.hpp>
namespace plot {
/// Where a cursor sits relative to the data grid.
enum class SnapMode {
Free, ///< the cursor stays exactly where the caller put it.
NearestSample, ///< the cursor is pulled onto the nearest sample of the trace's x grid.
};
/// Which of a cursor's two coordinates is live, and how it reads: the instrument
/// the plot has always had, and the same one turned a quarter turn (spec §14).
///
/// `Vertical` is a marker at a data `x` spanning the axes' *height*; `Horizontal` is
/// a ruler at a data `y` spanning their *width*. One type rather than two, because
/// the two differ in exactly one thing -- which coordinate a drag writes -- and every
/// other part of the machinery (the hit radius, the drag, the hover highlight, the
/// label path) is then one path instead of two that would have to be kept in step.
///
/// The orientation is what says which fields of `Cursor` mean anything:
///
/// | orientation | live coordinate | live snap | dead fields |
/// |--------------|-------------------|------------------------------|-------------------------|
/// | `Vertical` | `x`, on `axis_x` | `snap` (`SnapMode`) | `y`, `h_snap`, `axis_y` |
/// | `Horizontal` | `y`, on `axis_y` | `h_snap` (`HRulerSnap`) | `x`, `snap`, `axis_x` |
///
/// A dead field is *ignored*, not honoured: `Plot::set_cursor_y()` on a vertical
/// cursor and `Plot::set_cursor_x()` on a horizontal ruler change nothing, and neither
/// does the other orientation's snap setter (see `Plot::set_cursor_h_snap()`). A dead
/// field that could be written would leave the struct holding two coordinates that
/// could disagree about where the cursor is, and the two snaps free to drift into
/// meaning each other's job -- `SnapMode::NearestSample` is a sample of an *x* grid,
/// while `HRulerSnap::NearestTick` is a tick of a *y* axis.
enum class CursorOrientation {
Vertical, ///< a marker at a data x, spanning the axes' height.
Horizontal, ///< a ruler at a data y, spanning the axes' width.
};
/// How a horizontal ruler's `y` relates to its y axis' tick set.
///
/// Deliberately not a `SnapMode`: a vertical cursor snaps onto a *sample* of the
/// trace's x grid, and a series is sampled in x, so "the nearest y sample" is not a
/// thing that exists. What a y ruler has to land on is a *tick* -- one of the values
/// the y axis is labelled with.
enum class HRulerSnap {
Free, ///< the ruler stays exactly where the caller or the drag put it.
NearestTick, ///< the ruler is pulled onto the nearest tick of its y axis' tick set.
};
/// A marker at a data coordinate. Which coordinate -- and which snap -- is live, and
/// which fields are dead, is `orientation`'s to say (see CursorOrientation); `label`
/// is an optional caption drawn beside the marker, and a horizontal ruler
/// additionally draws its own value, written in its y axis' own tick format.
struct Cursor {
CursorOrientation orientation = CursorOrientation::Vertical;
f64 x = 0.0; ///< the data x. Live for `Vertical`, dead for `Horizontal`.
f64 y = 0.0; ///< the data y. Live for `Horizontal`, dead for `Vertical`.
SnapMode snap = SnapMode::Free; ///< the vertical snap. Dead for `Horizontal`.
HRulerSnap h_snap = HRulerSnap::Free; ///< the horizontal snap. Dead for `Vertical`.
Color color = Color::hex(0xFFB020);
std::string label;
u32 axis_x = 0; ///< the x axis `x` is in. Dead for `Horizontal`.
u32 axis_y = 0; ///< the y axis `y` is in. Dead for `Vertical`.
bool visible = true;
};
} // namespace plot