Skip to main content

openlogi_core/binding/action_ring/
icon.rs

1use serde::{Deserialize, Serialize};
2
3use super::super::Action;
4
5/// Presentation icon for an Actions Ring slot.
6///
7/// Variant names are persisted in TOML and declaration order is part of the
8/// agent IPC wire format, so variants are append-only.
9#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
10pub enum ActionRingIcon {
11    /// Pointer click glyph.
12    Pointer,
13    /// Physical mouse glyph.
14    Mouse,
15    /// Copy glyph.
16    Copy,
17    /// Clipboard/paste glyph.
18    Paste,
19    /// Scissors/cut glyph.
20    Cut,
21    /// Search glyph.
22    Search,
23    /// Save glyph.
24    Save,
25    /// Keyboard glyph.
26    Keyboard,
27    /// Application grid glyph.
28    Applications,
29    /// Actions grid glyph.
30    Grid,
31    /// Layer stack glyph.
32    Layers,
33    /// Display glyph.
34    Monitor,
35    /// Lock glyph.
36    Lock,
37    /// Camera glyph.
38    Camera,
39    /// Playback glyph.
40    Play,
41    /// Audio glyph.
42    Volume,
43    /// Gauge glyph.
44    Gauge,
45    /// Refresh glyph.
46    Refresh,
47    /// Up arrow glyph.
48    ArrowUp,
49    /// Down arrow glyph.
50    ArrowDown,
51    /// Left arrow glyph.
52    ArrowLeft,
53    /// Right arrow glyph.
54    ArrowRight,
55    /// Undo glyph.
56    Undo,
57    /// Redo glyph.
58    Redo,
59    /// Selection checklist glyph.
60    SelectAll,
61    /// Circular back glyph.
62    MouseBack,
63    /// Circular forward glyph.
64    MouseForward,
65    /// New-tab glyph.
66    NewTab,
67    /// Close-tab glyph.
68    CloseTab,
69    /// Reopen-tab glyph.
70    ReopenTab,
71    /// Next-tab glyph.
72    NextTab,
73    /// Previous-tab glyph.
74    PreviousTab,
75    /// Reload glyph.
76    Reload,
77    /// Previous-desktop glyph.
78    PreviousDesktop,
79    /// Next-desktop glyph.
80    NextDesktop,
81    /// Previous-track glyph.
82    PreviousTrack,
83    /// Next-track glyph.
84    NextTrack,
85    /// Lower-volume glyph.
86    VolumeDown,
87    /// Muted-volume glyph.
88    Mute,
89    /// Horizontal scroll-left glyph.
90    ScrollLeft,
91    /// Horizontal scroll-right glyph.
92    ScrollRight,
93    /// Folder glyph.
94    Folder,
95    /// File glyph.
96    File,
97    /// Globe glyph.
98    Globe,
99    /// Terminal glyph.
100    Terminal,
101    /// Settings glyph.
102    Settings,
103    /// Star glyph.
104    Star,
105    /// Heart glyph.
106    Heart,
107    /// Calendar glyph.
108    Calendar,
109    /// Notification bell glyph.
110    Bell,
111    /// User glyph.
112    User,
113    /// Color palette glyph.
114    Palette,
115    /// Open book glyph.
116    Book,
117    /// Prohibited action glyph.
118    Ban,
119}
120
121impl ActionRingIcon {
122    /// Path of this glyph's embedded SVG, as the GPUI frontends' asset source
123    /// serves it. The catalogue of shipped glyphs is a property of the icon
124    /// set, so it lives with the variants rather than in either frontend —
125    /// `openlogi-ui` owns the bytes and tests that every variant resolves.
126    #[must_use]
127    pub const fn asset_path(self) -> &'static str {
128        match self {
129            Self::Pointer => "action-icons/mouse-pointer-click.svg",
130            Self::Mouse => "action-icons/mouse.svg",
131            Self::Copy => "action-icons/copy.svg",
132            Self::Paste => "action-icons/clipboard-paste.svg",
133            Self::Cut => "action-icons/scissors.svg",
134            Self::Search => "action-icons/search.svg",
135            Self::Save => "action-icons/save.svg",
136            Self::Keyboard => "action-icons/keyboard.svg",
137            Self::Applications => "action-icons/grid-3x3.svg",
138            Self::Grid => "action-icons/layout-grid.svg",
139            Self::Layers => "action-icons/layers.svg",
140            Self::Monitor => "action-icons/monitor.svg",
141            Self::Lock => "action-icons/lock.svg",
142            Self::Camera => "action-icons/camera.svg",
143            Self::Play => "action-icons/play.svg",
144            Self::Volume => "action-icons/volume-2.svg",
145            Self::Gauge => "action-icons/gauge.svg",
146            Self::Refresh => "action-icons/refresh-cw.svg",
147            Self::ArrowUp => "action-icons/chevrons-up.svg",
148            Self::ArrowDown => "action-icons/chevrons-down.svg",
149            Self::ArrowLeft => "action-icons/arrow-left.svg",
150            Self::ArrowRight => "action-icons/arrow-right.svg",
151            Self::Undo => "action-icons/undo-2.svg",
152            Self::Redo => "action-icons/redo-2.svg",
153            Self::SelectAll => "action-icons/list-checks.svg",
154            Self::MouseBack => "action-icons/circle-arrow-left.svg",
155            Self::MouseForward => "action-icons/circle-arrow-right.svg",
156            Self::NewTab => "action-icons/square-plus.svg",
157            Self::CloseTab => "action-icons/square-x.svg",
158            Self::ReopenTab => "action-icons/rotate-ccw.svg",
159            Self::NextTab => "action-icons/chevron-right.svg",
160            Self::PreviousTab => "action-icons/chevron-left.svg",
161            Self::Reload => "action-icons/rotate-cw.svg",
162            Self::PreviousDesktop => "action-icons/square-arrow-left.svg",
163            Self::NextDesktop => "action-icons/square-arrow-right.svg",
164            Self::PreviousTrack => "action-icons/skip-back.svg",
165            Self::NextTrack => "action-icons/skip-forward.svg",
166            Self::VolumeDown => "action-icons/volume-1.svg",
167            Self::Mute => "action-icons/volume-x.svg",
168            Self::ScrollLeft => "action-icons/chevrons-left.svg",
169            Self::ScrollRight => "action-icons/chevrons-right.svg",
170            Self::Folder => "action-icons/folder.svg",
171            Self::File => "action-icons/file.svg",
172            Self::Globe => "action-icons/globe.svg",
173            Self::Terminal => "action-icons/square-terminal.svg",
174            Self::Settings => "action-icons/settings.svg",
175            Self::Star => "action-icons/star.svg",
176            Self::Heart => "action-icons/heart.svg",
177            Self::Calendar => "action-icons/calendar.svg",
178            Self::Bell => "action-icons/bell.svg",
179            Self::User => "action-icons/user.svg",
180            Self::Palette => "action-icons/palette.svg",
181            Self::Book => "action-icons/book-open.svg",
182            Self::Ban => "action-icons/ban.svg",
183        }
184    }
185
186    /// Every icon offered by the Actions Ring editor.
187    pub const ALL: [Self; 54] = [
188        Self::Pointer,
189        Self::Mouse,
190        Self::Copy,
191        Self::Paste,
192        Self::Cut,
193        Self::Search,
194        Self::Save,
195        Self::Keyboard,
196        Self::Applications,
197        Self::Grid,
198        Self::Layers,
199        Self::Monitor,
200        Self::Lock,
201        Self::Camera,
202        Self::Play,
203        Self::Volume,
204        Self::Gauge,
205        Self::Refresh,
206        Self::ArrowUp,
207        Self::ArrowDown,
208        Self::ArrowLeft,
209        Self::ArrowRight,
210        Self::Undo,
211        Self::Redo,
212        Self::SelectAll,
213        Self::MouseBack,
214        Self::MouseForward,
215        Self::NewTab,
216        Self::CloseTab,
217        Self::ReopenTab,
218        Self::NextTab,
219        Self::PreviousTab,
220        Self::Reload,
221        Self::PreviousDesktop,
222        Self::NextDesktop,
223        Self::PreviousTrack,
224        Self::NextTrack,
225        Self::VolumeDown,
226        Self::Mute,
227        Self::ScrollLeft,
228        Self::ScrollRight,
229        Self::Folder,
230        Self::File,
231        Self::Globe,
232        Self::Terminal,
233        Self::Settings,
234        Self::Star,
235        Self::Heart,
236        Self::Calendar,
237        Self::Bell,
238        Self::User,
239        Self::Palette,
240        Self::Book,
241        Self::Ban,
242    ];
243
244    /// Existing localization key used as this icon's accessible label.
245    #[must_use]
246    pub fn label(self) -> &'static str {
247        match self {
248            Self::Pointer => "Left Click",
249            Self::Mouse => "Middle Click",
250            Self::Copy => "Copy",
251            Self::Paste => "Paste",
252            Self::Cut => "Cut",
253            Self::Search => "Find",
254            Self::Save => "Save",
255            Self::Keyboard => "Custom shortcut",
256            Self::Applications => "Open application or folder",
257            Self::Grid => "Actions Ring",
258            Self::Layers => "App Exposé",
259            Self::Monitor => "Show Desktop",
260            Self::Lock => "Lock Screen",
261            Self::Camera => "Screenshot",
262            Self::Play => "Play / Pause",
263            Self::Volume => "Volume Up",
264            Self::Gauge => "Cycle DPI Presets",
265            Self::Refresh => "Toggle SmartShift",
266            Self::ArrowUp => "Scroll Up",
267            Self::ArrowDown => "Scroll Down",
268            Self::ArrowLeft | Self::ScrollLeft => "Scroll Left",
269            Self::ArrowRight | Self::ScrollRight => "Scroll Right",
270            Self::Undo => "Undo",
271            Self::Redo => "Redo",
272            Self::SelectAll => "Select All",
273            Self::MouseBack => "Back (Button 4)",
274            Self::MouseForward => "Forward (Button 5)",
275            Self::NewTab => "New Tab",
276            Self::CloseTab => "Close Tab",
277            Self::ReopenTab => "Reopen Tab",
278            Self::NextTab => "Next Tab",
279            Self::PreviousTab => "Previous Tab",
280            Self::Reload => "Reload Page",
281            Self::PreviousDesktop => "Previous Desktop",
282            Self::NextDesktop => "Next Desktop",
283            Self::PreviousTrack => "Previous Track",
284            Self::NextTrack => "Next Track",
285            Self::VolumeDown => "Volume Down",
286            Self::Mute => "Mute",
287            Self::Folder => "Folder",
288            Self::File => "File",
289            Self::Globe => "Globe",
290            Self::Terminal => "Terminal",
291            Self::Settings => "Settings",
292            Self::Star => "Star",
293            Self::Heart => "Heart",
294            Self::Calendar => "Calendar",
295            Self::Bell => "Bell",
296            Self::User => "User",
297            Self::Palette => "Palette",
298            Self::Book => "Book",
299            Self::Ban => "Do Nothing",
300        }
301    }
302}
303
304/// Builds [`ActionRingIcon::for_action`] from
305/// [`for_each_unit_action!`](super::super::action::for_each_unit_action)'s
306/// rows, splicing in the hand-written arms for payload-carrying variants so
307/// the generated `match` still covers every [`Action`] variant exhaustively.
308macro_rules! derive_action_icon {
309    ( $( $variant:ident $label:literal $category:ident $icon:ident $( $tag:ident )? ),* $(,)? ) => {
310        impl ActionRingIcon {
311            /// Default icon for an executable action.
312            #[must_use]
313            pub fn for_action(action: &Action) -> Self {
314                match action {
315                    $( Action::$variant => Self::$icon, )*
316                    Action::SetDpiPreset(_) => Self::Gauge,
317                    Action::CustomShortcut(_) | Action::TypeText(_) | Action::Workflow(_) => {
318                        Self::Keyboard
319                    }
320                    Action::RunAppleScript(_) | Action::RunShellCommand(_) => Self::Terminal,
321                    Action::OpenApplication(_) => Self::Applications,
322                }
323            }
324        }
325    };
326}
327
328super::super::action::for_each_unit_action!(derive_action_icon);