Skip to main content

egui_charts/config/
crosshair.rs

1//! Crosshair options for the chart cursor overlay.
2//!
3//! Controls the crosshair mode (free, or snapping to values), visual style
4//! (Full / Dot / Arrow / Hidden), the style of each line, and colors.
5
6use crate::model::LineStyle;
7use crate::theme::ThemeExt;
8use egui::Color32;
9
10/// Crosshair mode
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
12pub enum CrosshairMode {
13    /// Normal crosshair (snaps x to the bar center and follows the pointer value)
14    #[default]
15    Normal,
16    /// Magnet crosshair (snaps to the nearest visible OHLC, study or comparison value)
17    Magnet,
18    /// Snaps the price pane to the nearest visible main or added-series close on its own
19    /// scale. Equal screen distances prefer the main series, then added series in draw
20    /// order. Volume and study panes snap to their values as with `Magnet`.
21    MagnetClose,
22}
23
24impl CrosshairMode {
25    /// Whether the crosshair snaps to values instead of following the pointer.
26    pub(crate) fn snaps(self) -> bool {
27        matches!(self, Self::Magnet | Self::MagnetClose)
28    }
29}
30
31/// Crosshair visual style
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
33pub enum CrosshairStyle {
34    /// Full crosshair with vertical and horizontal lines (default)
35    #[default]
36    Full,
37    /// Only a dot at the intersection point
38    Dot,
39    /// Standard arrow cursor and axis readouts, without crosshair lines
40    Arrow,
41    /// A fading pointer trail for presentations, with axis readouts.
42    Demonstration,
43    /// A trail that follows the pointer while the primary button is held and fades after it is
44    /// released, with axis readouts. It creates no drawings.
45    Magic,
46    /// No crosshair lines or axis labels. Legends, the data window and tooltips still follow
47    /// the pointer.
48    Hidden,
49}
50
51/// Crosshair options
52#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
53#[non_exhaustive]
54#[serde(default)]
55pub struct CrosshairOptions {
56    /// Crosshair mode
57    pub mode: CrosshairMode,
58
59    /// Crosshair visual style (Full/Dot/Arrow/Hidden)
60    pub style: CrosshairStyle,
61
62    /// Vertical line style
63    pub vert_line_style: LineStyle,
64
65    /// Horizontal line style
66    pub horz_line_style: LineStyle,
67
68    /// Show vertical line
69    pub vert_line_visible: bool,
70
71    /// Show horizontal line
72    pub horz_line_visible: bool,
73
74    /// Vertical line color (`Color32::PLACEHOLDER`: active theme)
75    pub vert_line_color: Color32,
76
77    /// Horizontal line color (`Color32::PLACEHOLDER`: active theme)
78    pub horz_line_color: Color32,
79
80    /// Vertical line width
81    pub vert_line_width: f32,
82
83    /// Horizontal line width
84    pub horz_line_width: f32,
85
86    /// Show axis labels, subject to each label's visibility switch.
87    pub label_visible: bool,
88
89    /// Show the time-axis label, independently of the vertical line. Needs `label_visible`.
90    pub vert_label_visible: bool,
91
92    /// Show the price-axis label, independently of the horizontal line. Needs `label_visible`.
93    /// Also applies to volume and study values.
94    pub horz_label_visible: bool,
95
96    /// Background of the vertical line's label on the time axis (`Color32::PLACEHOLDER`:
97    /// active theme)
98    pub vert_label_background_color: Color32,
99
100    /// Background of the horizontal line's label on the price axis (`Color32::PLACEHOLDER`:
101    /// active theme)
102    pub horz_label_background_color: Color32,
103
104    /// Label text color (`Color32::PLACEHOLDER`: active theme)
105    pub label_text_color: Color32,
106}
107
108impl Default for CrosshairOptions {
109    fn default() -> Self {
110        Self {
111            mode: CrosshairMode::Normal,
112            style: CrosshairStyle::Full,
113            vert_line_style: LineStyle::Dashed,
114            horz_line_style: LineStyle::Dashed,
115            vert_line_visible: true,
116            horz_line_visible: true,
117            vert_line_color: Color32::PLACEHOLDER,
118            horz_line_color: Color32::PLACEHOLDER,
119            vert_line_width: 1.0,
120            horz_line_width: 1.0,
121            label_visible: true,
122            vert_label_visible: true,
123            horz_label_visible: true,
124            vert_label_background_color: Color32::PLACEHOLDER,
125            horz_label_background_color: Color32::PLACEHOLDER,
126            label_text_color: Color32::PLACEHOLDER,
127        }
128    }
129}
130
131impl CrosshairOptions {
132    /// These options with `Color32::PLACEHOLDER` colours taken from the theme applied to `ctx`.
133    pub(crate) fn resolved(&self, ctx: &egui::Context) -> Self {
134        let chart = ctx.active_theme().chart;
135        let or = |color: Color32, themed: Color32| {
136            if color == Color32::PLACEHOLDER {
137                themed
138            } else {
139                color
140            }
141        };
142        Self {
143            vert_line_color: or(self.vert_line_color, chart.crosshair_line),
144            horz_line_color: or(self.horz_line_color, chart.crosshair_line),
145            vert_label_background_color: or(
146                self.vert_label_background_color,
147                chart.crosshair_label_bg,
148            ),
149            horz_label_background_color: or(
150                self.horz_label_background_color,
151                chart.crosshair_label_bg,
152            ),
153            label_text_color: or(self.label_text_color, chart.crosshair_label_text),
154            ..*self
155        }
156    }
157}