egui_charts/ui/drawing_toolbar/utilities/
magnet.rs1use crate::icons::icons;
13use crate::localization as l10n;
14use crate::theme::ThemeExt;
15use crate::tokens::DESIGN_TOKENS;
16use crate::ui::drawing_toolbar::DrawingToolbarAction;
17use crate::ui::drawing_toolbar::components::icon_button::draw_latched_button;
18use crate::ui::drawing_toolbar::state::MagnetType;
19use crate::ui::drawing_toolbar::submenu_builder::SubmenuBuilder;
20use egui::{Align, Align2, Id, Layout, Rect, Response, RichText, Ui, Vec2};
21
22const HINT_TEXT_WIDTH: f32 = 236.0;
24
25pub struct MagnetButton;
27
28impl MagnetButton {
29 pub fn show(ui: &mut Ui, is_active: bool) -> Response {
32 draw_latched_button(ui, &icons::DRAWING_MAGNET, "Magnet mode", is_active)
33 }
34
35 pub fn show_submenu(
38 ui: &mut Ui,
39 magnet_on: bool,
40 magnet_type: MagnetType,
41 snap_to_indicators: bool,
42 ) -> Option<DrawingToolbarAction> {
43 let is_current = |kind| magnet_on && magnet_type == kind;
44 SubmenuBuilder::new(ui)
45 .add_text_item_with_action("Off", "Turn magnetic snapping off", || {
46 Some(DrawingToolbarAction::ToggleMagnet)
47 })
48 .icon(&icons::CLOSE)
49 .checked(!magnet_on)
50 .add_text_item_with_action("Weak magnet", "Snap only near chart values", || {
51 Some(DrawingToolbarAction::SetMagnetType(MagnetType::Weak))
52 })
53 .icon(&icons::MAGNET)
54 .checked(is_current(MagnetType::Weak))
55 .add_text_item_with_action(
56 "Strong magnet",
57 "Snap to the nearest bar OHLC value",
58 || Some(DrawingToolbarAction::SetMagnetType(MagnetType::Strong)),
59 )
60 .icon(&icons::DRAWING_MAGNET)
61 .checked(is_current(MagnetType::Strong))
62 .add_text_item_with_action(
63 "Snap to indicators",
64 "Include visible study values",
65 move || {
66 Some(DrawingToolbarAction::SetSnapToIndicators(
67 !snap_to_indicators,
68 ))
69 },
70 )
71 .checked(snap_to_indicators)
72 .show()
73 }
74
75 pub(crate) fn show_hint(ui: &Ui, anchor: Rect) -> bool {
79 let theme = ui.active_theme();
80 let ctx = ui.ctx();
81 egui::Area::new(Id::NULL.with("drawing_toolbar_magnet_hint"))
82 .order(egui::Order::Foreground)
83 .enabled(ui.is_enabled())
84 .pivot(Align2::LEFT_CENTER)
85 .fixed_pos(anchor.right_center() + Vec2::new(theme.spacing.sm, 0.0))
86 .show(ctx, |ui| {
87 egui::Frame::new()
88 .fill(theme.ui.accent)
89 .corner_radius(theme.radius.md)
90 .inner_margin(theme.spacing.xxl + theme.spacing.sm)
91 .shadow(ui.visuals().popup_shadow)
92 .show(ui, |ui| {
93 ui.set_width(HINT_TEXT_WIDTH);
94 ui.spacing_mut().item_spacing.y = theme.spacing.xl;
95 let text = [
97 "Drawing points snap to the open, high, low or close of the nearest bar.",
98 "Click the magnet again to turn it off.",
99 ]
100 .map(|text| l10n::text(ctx, text))
101 .join(" ");
102 ui.label(RichText::new(text).color(theme.ui.accent_text));
103 ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
104 ui.spacing_mut().button_padding.x = theme.spacing.xl + theme.spacing.xs;
106 let response = ui.add(
107 egui::Button::new(
108 RichText::new(l10n::text(ctx, "Got it")).color(theme.ui.accent),
109 )
110 .fill(theme.ui.accent_text)
111 .min_size(Vec2::new(
113 DESIGN_TOKENS.sizing.target_min,
114 DESIGN_TOKENS.sizing.settings_dialog.button_height,
115 ))
116 .corner_radius(theme.radius.md),
117 );
118 crate::styles::focus::draw_focus_ring(ui, &response, theme.radius.md);
119 response.clicked()
120 })
121 .inner
122 })
123 .inner
124 })
125 .inner
126 }
127}