toddy_core/message.rs
1//! Internal message enum and serialization helpers.
2//!
3//! [`Message`] is the iced `Message` type used by the renderer. Every
4//! widget interaction (click, input, slide, toggle, etc.) and every
5//! runtime event (keyboard, mouse, window lifecycle) maps to a variant.
6//! The renderer's `update()` method dispatches on these variants to
7//! emit outgoing events over the wire protocol.
8//!
9//! The serialization helpers convert iced types (keys, modifiers, mouse
10//! buttons, scroll deltas) into the wire-format strings expected by the
11//! host.
12
13use iced::widget::markdown;
14use iced::widget::text_editor;
15use iced::{Point, window};
16use serde_json::Value;
17
18use crate::protocol::KeyModifiers;
19
20// ---------------------------------------------------------------------------
21// Event data structs
22// ---------------------------------------------------------------------------
23
24/// Scrollable viewport state, emitted on scroll position changes.
25#[derive(Debug, Clone, Copy)]
26pub struct ScrollViewport {
27 /// Absolute scroll offset on the x axis (pixels from left).
28 pub absolute_x: f32,
29 /// Absolute scroll offset on the y axis (pixels from top).
30 pub absolute_y: f32,
31 /// Relative scroll position on the x axis (0.0 = start, 1.0 = end).
32 pub relative_x: f32,
33 /// Relative scroll position on the y axis (0.0 = top, 1.0 = bottom).
34 pub relative_y: f32,
35 /// Total content width (may exceed viewport).
36 pub content_width: f32,
37 /// Total content height (may exceed viewport).
38 pub content_height: f32,
39 /// Visible viewport width.
40 pub viewport_width: f32,
41 /// Visible viewport height.
42 pub viewport_height: f32,
43}
44
45/// All fields from an iced keyboard event, packed for Message transport.
46#[derive(Debug, Clone)]
47pub struct KeyEventData {
48 pub key: iced::keyboard::Key,
49 pub modified_key: iced::keyboard::Key,
50 pub physical_key: iced::keyboard::key::Physical,
51 pub location: iced::keyboard::Location,
52 pub modifiers: iced::keyboard::Modifiers,
53 pub text: Option<String>,
54 pub repeat: bool,
55 /// Whether iced reported this event as `Captured` (consumed by a widget).
56 pub captured: bool,
57}
58
59// ---------------------------------------------------------------------------
60// Message
61// ---------------------------------------------------------------------------
62
63#[derive(Debug, Clone)]
64pub enum Message {
65 /// A user clicked a button with the given node ID.
66 Click(String),
67 /// A text input value changed (id, new_value).
68 Input(String, String),
69 /// A text input was submitted (id, current_value).
70 Submit(String, String),
71 /// A checkbox or toggler was toggled (id, checked).
72 Toggle(String, bool),
73 /// A slider value changed (id, value).
74 Slide(String, f64),
75 /// A slider was released (id).
76 SlideRelease(String),
77 /// A pick_list/combo_box/radio selection (id, value).
78 Select(String, String),
79 /// A text editor action (id, action).
80 TextEditorAction(String, text_editor::Action),
81 /// A markdown link was clicked.
82 MarkdownUrl(markdown::Uri),
83 /// A message arrived from the stdin reader (or stdin closed).
84 Stdin(StdinEvent),
85 /// No-op: used as return value for fire-and-forget tasks (font loads, etc.)
86 NoOp,
87 /// A keyboard key was pressed (full event data).
88 KeyPressed(KeyEventData),
89 /// A keyboard key was released (full event data).
90 KeyReleased(KeyEventData),
91 /// Keyboard modifiers changed (modifiers, captured).
92 ModifiersChanged(iced::keyboard::Modifiers, bool),
93 // -- IME events --
94 /// IME session opened (captured).
95 ImeOpened(bool),
96 /// IME preedit text updated (composing text, optional cursor range, captured).
97 ImePreedit(String, Option<std::ops::Range<usize>>, bool),
98 /// IME committed final text (text, captured).
99 ImeCommit(String, bool),
100 /// IME session closed (captured).
101 ImeClosed(bool),
102 /// A window close was requested by the user (WM close button).
103 WindowCloseRequested(window::Id),
104 /// A window was actually closed by iced.
105 WindowClosed(window::Id),
106 /// A new window was opened (iced_id, toddy_id).
107 WindowOpened(window::Id, String),
108 // -- Mouse events --
109 /// Cursor moved to (x, y) in a window (position, window_id, captured).
110 CursorMoved(Point, window::Id, bool),
111 /// Cursor entered a window (window_id, captured).
112 CursorEntered(window::Id, bool),
113 /// Cursor left a window (window_id, captured).
114 CursorLeft(window::Id, bool),
115 /// Mouse button pressed (button, window_id, captured).
116 MouseButtonPressed(iced::mouse::Button, window::Id, bool),
117 /// Mouse button released (button, window_id, captured).
118 MouseButtonReleased(iced::mouse::Button, window::Id, bool),
119 /// Mouse wheel scrolled (delta, window_id, captured).
120 WheelScrolled(iced::mouse::ScrollDelta, window::Id, bool),
121 // -- Touch events --
122 /// Touch finger pressed (finger, position, window_id, captured).
123 FingerPressed(iced::touch::Finger, Point, window::Id, bool),
124 /// Touch finger moved (finger, position, window_id, captured).
125 FingerMoved(iced::touch::Finger, Point, window::Id, bool),
126 /// Touch finger lifted (finger, position, window_id, captured).
127 FingerLifted(iced::touch::Finger, Point, window::Id, bool),
128 /// Touch finger lost (finger, position, window_id, captured).
129 FingerLost(iced::touch::Finger, Point, window::Id, bool),
130 // -- Window lifecycle events --
131 /// A window event from iced (window_id, event).
132 WindowEvent(window::Id, window::Event),
133 // -- System / animation events --
134 /// Animation frame with timestamp.
135 AnimationFrame(iced::time::Instant),
136 /// System theme mode changed.
137 ThemeChanged(iced::theme::Mode),
138 /// Sensor widget resize event (id, width, height).
139 SensorResize(String, f32, f32),
140 /// Canvas interaction event (press, release, move).
141 CanvasEvent {
142 id: String,
143 kind: String,
144 x: f32,
145 y: f32,
146 extra: String,
147 },
148 /// Canvas scroll event.
149 CanvasScroll {
150 id: String,
151 cursor_x: f32,
152 cursor_y: f32,
153 delta_x: f32,
154 delta_y: f32,
155 },
156 /// PaneGrid pane was resized (grid_id, resize_event).
157 PaneResized(String, iced::widget::pane_grid::ResizeEvent),
158 /// PaneGrid pane was dragged (grid_id, drag_event).
159 PaneDragged(String, iced::widget::pane_grid::DragEvent),
160 /// PaneGrid pane was clicked (grid_id, pane).
161 PaneClicked(String, iced::widget::pane_grid::Pane),
162 /// PaneGrid focus cycle via F6 (grid_id, target_pane).
163 PaneFocusCycle(String, iced::widget::pane_grid::Pane),
164 /// Scrollable viewport changed.
165 ScrollEvent(String, ScrollViewport),
166 /// Text was pasted into a text_input (id, pasted_text).
167 Paste(String, String),
168 /// ComboBox option was hovered (combo_id, option_value).
169 OptionHovered(String, String),
170 /// MouseArea simple event (id, kind). Kind is one of: right_press,
171 /// right_release, middle_release, double_click, enter, exit.
172 MouseAreaEvent(String, String),
173 /// MouseArea cursor move event (id, x, y).
174 MouseAreaMove(String, f32, f32),
175 /// MouseArea scroll event (id, delta_x, delta_y).
176 MouseAreaScroll(String, f32, f32),
177 /// Generic widget event. Used for on_open, on_close, sort, and
178 /// other events that carry a family string and optional data.
179 Event {
180 id: String,
181 data: Value,
182 family: String,
183 },
184}
185
186/// What the stdin reader thread sends back.
187#[derive(Debug, Clone)]
188pub enum StdinEvent {
189 Message(crate::protocol::IncomingMessage),
190 Closed,
191 Warning(String),
192}
193
194// ---------------------------------------------------------------------------
195// Key serialization helpers
196// ---------------------------------------------------------------------------
197
198pub fn serialize_key(key: &iced::keyboard::Key) -> String {
199 match key {
200 iced::keyboard::Key::Named(named) => format!("{named:?}"),
201 iced::keyboard::Key::Character(c) => c.to_string(),
202 iced::keyboard::Key::Unidentified => "Unidentified".to_string(),
203 }
204}
205
206pub fn serialize_modifiers(mods: iced::keyboard::Modifiers) -> KeyModifiers {
207 KeyModifiers {
208 shift: mods.shift(),
209 ctrl: mods.control(),
210 alt: mods.alt(),
211 logo: mods.logo(),
212 command: mods.command(),
213 }
214}
215
216pub fn serialize_physical_key(physical: &iced::keyboard::key::Physical) -> String {
217 match physical {
218 iced::keyboard::key::Physical::Code(code) => format!("{code:?}"),
219 iced::keyboard::key::Physical::Unidentified(code) => {
220 format!("Unidentified({code:?})")
221 }
222 }
223}
224
225pub fn serialize_location(location: &iced::keyboard::Location) -> &'static str {
226 match location {
227 iced::keyboard::Location::Standard => "standard",
228 iced::keyboard::Location::Left => "left",
229 iced::keyboard::Location::Right => "right",
230 iced::keyboard::Location::Numpad => "numpad",
231 }
232}
233
234// ---------------------------------------------------------------------------
235// Mouse serialization helpers
236// ---------------------------------------------------------------------------
237
238pub fn serialize_mouse_button(button: &iced::mouse::Button) -> String {
239 match button {
240 iced::mouse::Button::Left => "left".to_string(),
241 iced::mouse::Button::Right => "right".to_string(),
242 iced::mouse::Button::Middle => "middle".to_string(),
243 iced::mouse::Button::Back => "back".to_string(),
244 iced::mouse::Button::Forward => "forward".to_string(),
245 iced::mouse::Button::Other(n) => format!("other_{n}"),
246 }
247}
248
249pub fn serialize_scroll_delta(delta: &iced::mouse::ScrollDelta) -> (f32, f32, &'static str) {
250 match delta {
251 iced::mouse::ScrollDelta::Lines { x, y } => (*x, *y, "lines"),
252 iced::mouse::ScrollDelta::Pixels { x, y } => (*x, *y, "pixels"),
253 }
254}