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}