1use fltk::{
2 enums::Shortcut,
3 menu::{MenuButton, MenuFlag},
4 prelude::{MenuExt, WidgetExt},
5};
6use rutle::structured_document::BlockType;
7
8pub struct MenuActions {
10 pub has_selection: bool,
11 pub current_block: BlockType,
13
14 pub set_paragraph: Box<dyn FnMut()>,
16 pub set_heading1: Box<dyn FnMut()>,
17 pub set_heading2: Box<dyn FnMut()>,
18 pub set_heading3: Box<dyn FnMut()>,
19 pub toggle_quote: Box<dyn FnMut()>,
20 pub toggle_code_block: Box<dyn FnMut()>,
21 pub toggle_list: Box<dyn FnMut()>,
22 pub toggle_checklist: Box<dyn FnMut()>,
23 pub toggle_ordered_list: Box<dyn FnMut()>,
24
25 pub toggle_bold: Box<dyn FnMut()>,
27 pub toggle_italic: Box<dyn FnMut()>,
28 pub toggle_code: Box<dyn FnMut()>,
29 pub toggle_strike: Box<dyn FnMut()>,
30 pub toggle_underline: Box<dyn FnMut()>,
31 pub toggle_highlight: Box<dyn FnMut()>,
32 pub clear_formatting: Box<dyn FnMut()>,
33
34 pub cut: Box<dyn FnMut()>,
36 pub copy: Box<dyn FnMut()>,
37 pub paste: Box<dyn FnMut()>,
38
39 pub edit_link: Box<dyn FnMut()>,
41}
42
43pub fn show_context_menu(x: i32, y: i32, mut actions: MenuActions) {
45 let mut menu = MenuButton::default();
46 menu.set_pos(x, y);
47
48 #[cfg(target_os = "macos")]
50 let para_shortcut = Shortcut::Command | Shortcut::Alt | '0';
51 #[cfg(not(target_os = "macos"))]
52 let para_shortcut = Shortcut::Ctrl | Shortcut::Alt | '0';
53
54 #[cfg(target_os = "macos")]
55 let h1_shortcut = Shortcut::Command | Shortcut::Alt | '1';
56 #[cfg(not(target_os = "macos"))]
57 let h1_shortcut = Shortcut::Ctrl | Shortcut::Alt | '1';
58
59 #[cfg(target_os = "macos")]
60 let h2_shortcut = Shortcut::Command | Shortcut::Alt | '2';
61 #[cfg(not(target_os = "macos"))]
62 let h2_shortcut = Shortcut::Ctrl | Shortcut::Alt | '2';
63
64 #[cfg(target_os = "macos")]
65 let h3_shortcut = Shortcut::Command | Shortcut::Alt | '3';
66 #[cfg(not(target_os = "macos"))]
67 let h3_shortcut = Shortcut::Ctrl | Shortcut::Alt | '3';
68
69 #[cfg(target_os = "macos")]
70 let list_shortcut = Shortcut::Command | Shortcut::Shift | '8';
71 #[cfg(not(target_os = "macos"))]
72 let list_shortcut = Shortcut::Ctrl | Shortcut::Shift | '8';
73
74 #[cfg(target_os = "macos")]
76 let ordered_list_shortcut = Shortcut::Command | Shortcut::Shift | '7';
77 #[cfg(not(target_os = "macos"))]
78 let ordered_list_shortcut = Shortcut::Ctrl | Shortcut::Shift | '7';
79
80 #[cfg(target_os = "macos")]
82 let code_block_shortcut = Shortcut::Command | Shortcut::Shift | '6';
83 #[cfg(not(target_os = "macos"))]
84 let code_block_shortcut = Shortcut::Ctrl | Shortcut::Shift | '6';
85
86 #[cfg(target_os = "macos")]
88 let quote_shortcut = Shortcut::Command | Shortcut::Shift | '5';
89 #[cfg(not(target_os = "macos"))]
90 let quote_shortcut = Shortcut::Ctrl | Shortcut::Shift | '5';
91
92 #[cfg(target_os = "macos")]
93 let checklist_shortcut = Shortcut::Command | Shortcut::Shift | '9';
94 #[cfg(not(target_os = "macos"))]
95 let checklist_shortcut = Shortcut::Ctrl | Shortcut::Shift | '9';
96
97 menu.add(
99 "Paragraph Style/Paragraph\t",
100 para_shortcut,
101 MenuFlag::Radio,
102 move |_| (actions.set_paragraph)(),
103 );
104 menu.add(
105 "Paragraph Style/Heading 1\t",
106 h1_shortcut,
107 MenuFlag::Radio,
108 move |_| (actions.set_heading1)(),
109 );
110 menu.add(
111 "Paragraph Style/Heading 2\t",
112 h2_shortcut,
113 MenuFlag::Radio,
114 move |_| (actions.set_heading2)(),
115 );
116 menu.add(
117 "Paragraph Style/Heading 3\t",
118 h3_shortcut,
119 MenuFlag::Radio,
120 move |_| (actions.set_heading3)(),
121 );
122 menu.add(
123 "Paragraph Style/Quote\t",
124 quote_shortcut,
125 MenuFlag::Radio,
126 move |_| (actions.toggle_quote)(),
127 );
128 menu.add(
129 "Paragraph Style/Code\t",
130 code_block_shortcut,
131 MenuFlag::Radio,
132 move |_| (actions.toggle_code_block)(),
133 );
134 menu.add(
135 "Paragraph Style/Numbered List\t",
136 ordered_list_shortcut,
137 MenuFlag::Radio,
138 move |_| (actions.toggle_ordered_list)(),
139 );
140 menu.add(
141 "Paragraph Style/List Item\t",
142 list_shortcut,
143 MenuFlag::Radio,
144 move |_| (actions.toggle_list)(),
145 );
146 menu.add(
147 "Paragraph Style/Checklist Item\t",
148 checklist_shortcut,
149 MenuFlag::Radio,
150 move |_| (actions.toggle_checklist)(),
151 );
152
153 let labels = [
155 "Paragraph Style/Paragraph\t",
156 "Paragraph Style/Heading 1\t",
157 "Paragraph Style/Heading 2\t",
158 "Paragraph Style/Heading 3\t",
159 "Paragraph Style/Quote\t",
160 "Paragraph Style/Code\t",
161 "Paragraph Style/Numbered List\t",
162 "Paragraph Style/List Item\t",
163 "Paragraph Style/Checklist Item\t",
164 ];
165 for &label in &labels {
167 let idx = menu.find_index(label);
168 if idx >= 0 {
169 menu.set_mode(idx, MenuFlag::Radio);
170 }
171 }
172 if let Some(lbl) = match actions.current_block {
174 BlockType::Paragraph => Some("Paragraph Style/Paragraph\t"),
175 BlockType::Heading { level } => match level {
176 1 => Some("Paragraph Style/Heading 1\t"),
177 2 => Some("Paragraph Style/Heading 2\t"),
178 3 => Some("Paragraph Style/Heading 3\t"),
179 _ => None,
180 },
181 BlockType::CodeBlock { .. } => Some("Paragraph Style/Code\t"),
182 BlockType::BlockQuote => Some("Paragraph Style/Quote\t"),
183 BlockType::ListItem {
184 ordered, checkbox, ..
185 } => Some(if ordered {
186 "Paragraph Style/Numbered List\t"
187 } else if checkbox.is_some() {
188 "Paragraph Style/Checklist Item\t"
189 } else {
190 "Paragraph Style/List Item\t"
191 }),
192 BlockType::Table { .. } => None,
194 } && let Some(mut item) = menu.find_item(lbl)
195 {
196 item.set();
197 }
198
199 #[cfg(target_os = "macos")]
201 let bold_shortcut = Shortcut::Command | 'b';
202 #[cfg(not(target_os = "macos"))]
203 let bold_shortcut = Shortcut::Ctrl | 'b';
204
205 #[cfg(target_os = "macos")]
206 let italic_shortcut = Shortcut::Command | 'i';
207 #[cfg(not(target_os = "macos"))]
208 let italic_shortcut = Shortcut::Ctrl | 'i';
209
210 #[cfg(target_os = "macos")]
211 let code_shortcut = Shortcut::Command | Shortcut::Shift | 'c';
212 #[cfg(not(target_os = "macos"))]
213 let code_shortcut = Shortcut::Ctrl | Shortcut::Shift | 'c';
214
215 #[cfg(target_os = "macos")]
216 let strike_shortcut = Shortcut::Command | Shortcut::Shift | 'x';
217 #[cfg(not(target_os = "macos"))]
218 let strike_shortcut = Shortcut::Ctrl | Shortcut::Shift | 'x';
219
220 #[cfg(target_os = "macos")]
221 let underline_shortcut = Shortcut::Command | 'u';
222 #[cfg(not(target_os = "macos"))]
223 let underline_shortcut = Shortcut::Ctrl | 'u';
224
225 #[cfg(target_os = "macos")]
226 let highlight_shortcut = Shortcut::Command | Shortcut::Shift | 'h';
227 #[cfg(not(target_os = "macos"))]
228 let highlight_shortcut = Shortcut::Ctrl | Shortcut::Shift | 'h';
229
230 #[cfg(target_os = "macos")]
231 let clear_shortcut = Shortcut::Command | '\\';
232 #[cfg(not(target_os = "macos"))]
233 let clear_shortcut = Shortcut::Ctrl | '\\';
234
235 menu.add(
236 "Toggle Bold\t",
237 bold_shortcut,
238 MenuFlag::Normal,
239 move |_| (actions.toggle_bold)(),
240 );
241 menu.add(
242 "Toggle Italic\t",
243 italic_shortcut,
244 MenuFlag::Normal,
245 move |_| (actions.toggle_italic)(),
246 );
247 menu.add(
248 "Toggle Underline\t",
249 underline_shortcut,
250 MenuFlag::Normal,
251 move |_| (actions.toggle_underline)(),
252 );
253 menu.add(
254 "Toggle Code\t",
255 code_shortcut,
256 MenuFlag::Normal,
257 move |_| (actions.toggle_code)(),
258 );
259 menu.add(
260 "Toggle Highlight\t",
261 highlight_shortcut,
262 MenuFlag::Normal,
263 move |_| (actions.toggle_highlight)(),
264 );
265 menu.add(
266 "Toggle Strikethrough\t",
267 strike_shortcut,
268 MenuFlag::Normal,
269 move |_| (actions.toggle_strike)(),
270 );
271 #[cfg(target_os = "macos")]
273 let edit_link_shortcut = Shortcut::Command | 'k';
274 #[cfg(not(target_os = "macos"))]
275 let edit_link_shortcut = Shortcut::Ctrl | 'k';
276 menu.add(
277 "Edit Linkā¦\t",
278 edit_link_shortcut,
279 MenuFlag::Normal,
280 move |_| (actions.edit_link)(),
281 );
282
283 menu.add(
284 "_Clear Formatting\t",
285 clear_shortcut,
286 MenuFlag::Normal,
287 move |_| (actions.clear_formatting)(),
288 );
289
290 #[cfg(target_os = "macos")]
292 let cut_shortcut = Shortcut::Command | 'x';
293 #[cfg(not(target_os = "macos"))]
294 let cut_shortcut = Shortcut::Ctrl | 'x';
295 menu.add("Cut\t", cut_shortcut, MenuFlag::Normal, move |_| {
296 (actions.cut)()
297 });
298
299 #[cfg(target_os = "macos")]
300 let copy_shortcut = Shortcut::Command | 'c';
301 #[cfg(not(target_os = "macos"))]
302 let copy_shortcut = Shortcut::Ctrl | 'c';
303 menu.add("Copy\t", copy_shortcut, MenuFlag::Normal, move |_| {
304 (actions.copy)()
305 });
306
307 #[cfg(target_os = "macos")]
308 let paste_shortcut = Shortcut::Command | 'v';
309 #[cfg(not(target_os = "macos"))]
310 let paste_shortcut = Shortcut::Ctrl | 'v';
311 menu.add(
312 "Paste\t",
313 paste_shortcut,
314 MenuFlag::Normal,
315 move |_m: &mut MenuButton| (actions.paste)(),
316 );
317
318 if !actions.has_selection {
320 for label in ["Cut\t", "Copy\t"] {
321 let idx = menu.find_index(label);
322 if idx >= 0 {
323 menu.set_mode(idx, MenuFlag::Inactive);
324 }
325 }
326 }
327
328 menu.popup();
329}