messages.rs - icy_draw - icy_draw is the successor to mystic draw. fork / mirror
(HTM) git clone https://git.drkhsh.at/icy_draw.git
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
messages.rs (45073B)
---
1 use std::{cell::RefCell, path::PathBuf, rc::Rc, sync::Arc};
2
3 use directories::UserDirs;
4 use eframe::{
5 egui::{self},
6 epaint::Vec2,
7 };
8 use egui::mutex::Mutex;
9 use icy_engine::{util::pop_data, BitFont, EngineResult, IceMode, Layer, PaletteMode, SauceData, Size, TextPane, TheDrawFont};
10
11 use crate::{
12 util::autosave::{self},
13 AnsiEditor, MainWindow, NewFileDialog, SaveFileDialog, SelectCharacterDialog, SelectOutlineDialog, Settings, MRU_FILES, PLUGINS, SETTINGS,
14 };
15
16 #[derive(Clone)]
17 pub enum Message {
18 NewFileDialog,
19 OpenFileDialog,
20 SaveFile,
21 SaveFileAs,
22 ExportFile,
23 ShowOutlineDialog,
24 CloseWindow,
25
26 AddNewLayer(usize),
27 EditLayer(usize),
28 RemoveLayer(usize),
29 RaiseLayer(usize),
30 LowerLayer(usize),
31 ToggleLayerVisibility(usize),
32 SelectLayer(usize),
33 DuplicateLayer(usize),
34 MergeLayerDown(usize),
35
36 Undo,
37 Redo,
38 EditSauce,
39 SetCanvasSize,
40 SelectAll,
41 SelectNothing,
42 DeleteSelection,
43
44 ShowAboutDialog,
45 ShowCharacterSelectionDialog(Rc<RefCell<char>>),
46 SelectFontDialog(Arc<Mutex<Vec<TheDrawFont>>>, Arc<Mutex<i32>>),
47 ShowError(String),
48 SetFontPage(usize),
49 CharTable(char),
50 ResizeLayer(usize),
51 SelectTool(usize),
52 AnchorLayer,
53 AddFloatingLayer,
54 JustifyLeft,
55 JustifyRight,
56 Center,
57 FlipX,
58 FlipY,
59 Crop,
60 Paste,
61 ResizeBuffer(bool, i32, i32),
62 PasteAsNewImage,
63 PasteAsBrush,
64 Copy,
65 Cut,
66 RemoveFloatingLayer,
67 SelectOutline(usize),
68
69 CenterLine,
70 JustifyLineLeft,
71 JustifyLineRight,
72
73 InsertRow,
74 DeleteRow,
75 InsertColumn,
76 DeleteColumn,
77
78 EraseRow,
79 EraseRowToStart,
80 EraseRowToEnd,
81
82 EraseColumn,
83 EraseColumnToStart,
84 EraseColumnToEnd,
85
86 ScrollAreaUp,
87 ScrollAreaDown,
88 ScrollAreaLeft,
89 ScrollAreaRight,
90
91 SetReferenceImage,
92 ToggleReferenceImage,
93 ClearReferenceImage,
94
95 PickAttributeUnderCaret,
96 SwitchToDefaultColor,
97 ToggleColor,
98
99 StampLayerDown,
100 RotateLayer,
101 MakeLayerTransparent,
102
103 ToggleFullScreen,
104
105 ZoomReset,
106 ZoomIn,
107 ZoomOut,
108
109 OpenFontSelector,
110 OpenAddFonts,
111 OpenFontManager,
112 OpenFontDirectory,
113 OpenTdfDirectory,
114 OpenPalettesDirectory,
115 ToggleMirrorMode,
116 ClearRecentOpenFiles,
117 SetGuide(i32, i32),
118 SetRaster(i32, i32),
119 LoadFile(PathBuf, bool),
120 TryLoadFile(PathBuf),
121 ClearLayer(usize),
122 InverseSelection,
123
124 SetForeground(u32),
125 SetForegroundRgb(u8, u8, u8),
126
127 SetBackground(u32),
128 SetBackgroundRgb(u8, u8, u8),
129 ClearSelection,
130 UpdateFont(Box<(BitFont, BitFont)>),
131
132 SelectPalette,
133 ToggleLayerBorders,
134 ToggleLineNumbers,
135 RunPlugin(usize),
136 OpenPluginDirectory,
137 SelectPreviousTool,
138 NextFgColor,
139 PreviousFgColor,
140 NextBgColor,
141 PreviousBgColor,
142 ShowSettings,
143 ToggleLGAFont,
144 ToggleAspectRatio,
145 SwitchToFontPage(usize),
146 SetAnsiFont(usize),
147 SetFont(Box<BitFont>),
148 SwitchPaletteMode(PaletteMode),
149 SwitchIceMode(IceMode),
150 AddFont(Box<BitFont>),
151 AddAnsiFont(usize),
152 SetSauceFont(String),
153 ToggleGrid,
154 KeySwitchForeground(usize),
155 KeySwitchBackground(usize),
156 }
157
158 pub const CTRL_SHIFT: egui::Modifiers = egui::Modifiers {
159 alt: false,
160 ctrl: true,
161 shift: true,
162 mac_cmd: false,
163 command: false,
164 };
165
166 impl<'a> MainWindow<'a> {
167 pub fn handle_message(&mut self, msg_opt: Option<Message>) {
168 let Some(msg) = msg_opt else {
169 return;
170 };
171 match msg {
172 Message::NewFileDialog => {
173 self.open_dialog(NewFileDialog::default());
174 }
175 Message::OpenFileDialog => {
176 let mut initial_directory = if let Some(d) = self.get_active_pane_mut() { d.get_path() } else { None };
177 set_default_initial_directory_opt(&mut initial_directory);
178 if let Some(mut path) = initial_directory {
179 while path.parent().is_some() && !path.is_dir() {
180 path = path.parent().unwrap().to_path_buf();
181 }
182
183 self.open_file_window.file_view.set_path(path);
184 }
185 self.open_file_window.reset();
186 self.in_open_file_mode = true;
187 }
188
189 Message::TryLoadFile(path) => {
190 let auto_save = autosave::get_autosave_file(&path);
191 if auto_save.exists() {
192 self.open_dialog(crate::AutoSaveDialog::new(path));
193 return;
194 }
195
196 self.open_file(&path, false);
197 }
198 Message::LoadFile(path, load_autosave) => {
199 self.open_file(&path, load_autosave);
200 }
201
202 Message::SaveFile => {
203 let msg = if let Some(pane) = self.get_active_pane_mut() {
204 if pane.is_untitled() || pane.doc.lock().get_ansi_editor().is_some() && !is_icy_file(pane.get_path()) {
205 Some(Message::SaveFileAs)
206 } else {
207 pane.save()
208 }
209 } else {
210 None
211 };
212
213 self.handle_message(msg);
214 }
215 Message::SaveFileAs => {
216 if let Some((_, tab)) = self.get_active_pane() {
217 let path = tab.get_path();
218 self.open_dialog(SaveFileDialog::new(path));
219 }
220 }
221 Message::ExportFile => {
222 self.run_editor_command(0, |window, editor, _| {
223 let view = editor.buffer_view.clone();
224 window.open_dialog(crate::ExportFileDialog::new(view.lock().get_buffer()));
225 None
226 });
227 if let Some(doc) = self.get_active_document() {
228 if let Some(editor) = doc.lock().get_ansi_editor() {
229 let view = editor.buffer_view.clone();
230 self.open_dialog(crate::ExportFileDialog::new(view.lock().get_buffer()));
231 }
232 }
233 }
234 Message::ShowOutlineDialog => {
235 self.open_dialog(SelectOutlineDialog::default());
236 }
237 Message::Undo => {
238 let mut msg = None;
239 if let Some(editor) = self.get_active_document() {
240 msg = self.handle_result(editor.lock().undo()).unwrap_or(None);
241 }
242 self.handle_message(msg);
243 }
244 Message::Redo => {
245 let mut msg = None;
246 if let Some(editor) = self.get_active_document() {
247 msg = self.handle_result(editor.lock().redo()).unwrap_or(None);
248 }
249 self.handle_message(msg);
250 }
251
252 Message::SelectAll => {
253 self.run_editor_command(0, |_, editor, _| {
254 let buf = &mut editor.buffer_view.lock();
255 let w = buf.get_buffer().get_width();
256 let h = buf.get_buffer().get_height();
257
258 buf.set_selection(icy_engine::Rectangle::from(0, 0, w, h));
259 None
260 });
261 }
262 Message::SelectNothing => {
263 self.run_editor_command(0, |_, editor, _| to_message(editor.buffer_view.lock().get_edit_state_mut().clear_selection()));
264 }
265 Message::DeleteSelection => {
266 self.run_editor_command(0, |_, editor: &mut AnsiEditor, _| {
267 to_message(editor.buffer_view.lock().get_edit_state_mut().erase_selection())
268 });
269 }
270 Message::ShowCharacterSelectionDialog(ch) => {
271 self.run_editor_command(ch, |window, editor: &mut AnsiEditor, ch| {
272 let buf = editor.buffer_view.clone();
273 window.open_dialog(SelectCharacterDialog::new(buf, ch));
274 None
275 });
276 }
277 Message::SelectFontDialog(fonts, selected_font) => {
278 self.open_dialog(crate::SelectFontDialog::new(fonts, selected_font));
279 }
280 Message::EditSauce => {
281 if let Some(doc) = self.get_active_document() {
282 if let Some(editor) = doc.lock().get_ansi_editor() {
283 let view = editor.buffer_view.clone();
284 self.open_dialog(crate::EditSauceDialog::new(view.lock().get_buffer()));
285 }
286 }
287 }
288
289 Message::SetCanvasSize => {
290 if let Some(doc) = self.get_active_document() {
291 if let Some(editor) = doc.lock().get_ansi_editor() {
292 let view = editor.buffer_view.clone();
293 self.open_dialog(crate::SetCanvasSizeDialog::new(view.lock().get_buffer()));
294 }
295 }
296 }
297
298 Message::EditLayer(i) => {
299 if let Some(doc) = self.get_active_document() {
300 if let Some(editor) = doc.lock().get_ansi_editor() {
301 let view = editor.buffer_view.clone();
302 self.open_dialog(crate::EditLayerDialog::new(view.lock().get_buffer(), i));
303 }
304 }
305 }
306 Message::ResizeLayer(i) => {
307 if let Some(doc) = self.get_active_document() {
308 if let Some(editor) = doc.lock().get_ansi_editor_mut() {
309 let view = editor.buffer_view.clone();
310 self.open_dialog(crate::ResizeLayerDialog::new(view.lock().get_buffer(), i));
311 }
312 }
313 }
314 Message::AddNewLayer(cur_layer) => {
315 self.run_editor_command(cur_layer, |_, editor, cur_layer| {
316 let mut lock = editor.buffer_view.lock();
317 to_message(lock.get_edit_state_mut().add_new_layer(cur_layer))
318 });
319 }
320 Message::RaiseLayer(cur_layer) => {
321 self.run_editor_command(cur_layer, |_, editor, cur_layer| {
322 let mut lock = editor.buffer_view.lock();
323 to_message(lock.get_edit_state_mut().raise_layer(cur_layer))
324 });
325 }
326 Message::LowerLayer(cur_layer) => {
327 self.run_editor_command(cur_layer, |_, editor, cur_layer| {
328 let mut lock = editor.buffer_view.lock();
329 to_message(lock.get_edit_state_mut().lower_layer(cur_layer))
330 });
331 }
332 Message::RemoveLayer(cur_layer) => {
333 self.run_editor_command(cur_layer, |_, editor: &mut crate::AnsiEditor, cur_layer| {
334 let mut lock = editor.buffer_view.lock();
335 to_message(lock.get_edit_state_mut().remove_layer(cur_layer))
336 });
337
338 self.run_editor_command(0, |_, editor: &mut crate::AnsiEditor, _| {
339 let mut lock = editor.buffer_view.lock();
340
341 if lock.get_buffer().layers.is_empty() {
342 to_message(lock.get_edit_state_mut().add_new_layer(0))
343 } else {
344 None
345 }
346 });
347 }
348 Message::ClearLayer(cur_layer) => {
349 self.run_editor_command(cur_layer, |_, editor, cur_layer| {
350 let mut lock = editor.buffer_view.lock();
351 to_message(lock.get_edit_state_mut().clear_layer(cur_layer))
352 });
353 }
354 Message::RemoveFloatingLayer => {
355 self.run_editor_command(0, |_, editor: &mut crate::AnsiEditor, _| {
356 let mut lock = editor.buffer_view.lock();
357 if let Ok(layer) = lock.get_edit_state().get_current_layer() {
358 to_message(lock.get_edit_state_mut().remove_layer(layer))
359 } else {
360 Some(Message::ShowError("No floating layer to remove".to_string()))
361 }
362 });
363 }
364 Message::ClearSelection => {
365 self.run_editor_command(0, |_, editor: &mut crate::AnsiEditor, _| {
366 let mut lock = editor.buffer_view.lock();
367 to_message(lock.get_edit_state_mut().clear_selection())
368 });
369 }
370 Message::DuplicateLayer(cur_layer) => {
371 self.run_editor_command(cur_layer, |_, editor: &mut crate::AnsiEditor, cur_layer| {
372 let mut lock = editor.buffer_view.lock();
373 to_message(lock.get_edit_state_mut().duplicate_layer(cur_layer))
374 });
375 }
376 Message::MergeLayerDown(cur_layer) => {
377 self.run_editor_command(cur_layer, |_, editor: &mut crate::AnsiEditor, cur_layer| {
378 let mut lock = editor.buffer_view.lock();
379 to_message(lock.get_edit_state_mut().merge_layer_down(cur_layer))
380 });
381 }
382
383 Message::ToggleLayerVisibility(cur_layer) => {
384 self.run_editor_command(cur_layer, |_, editor: &mut crate::AnsiEditor, cur_layer| {
385 let mut lock = editor.buffer_view.lock();
386 to_message(lock.get_edit_state_mut().toggle_layer_visibility(cur_layer))
387 });
388 }
389
390 Message::SelectLayer(cur_layer) => {
391 self.run_editor_command(cur_layer, |_, editor, cur_layer| {
392 editor.set_cur_layer_index(cur_layer);
393 None
394 });
395 }
396
397 Message::AnchorLayer => {
398 self.run_editor_command(0, |_, editor: &mut crate::AnsiEditor, _| {
399 to_message(editor.buffer_view.lock().get_edit_state_mut().anchor_layer())
400 });
401 }
402
403 Message::AddFloatingLayer => {
404 self.run_editor_command(0, |_, editor: &mut crate::AnsiEditor, _| {
405 to_message(editor.buffer_view.lock().get_edit_state_mut().add_floating_layer())
406 });
407 }
408
409 Message::SetFontPage(page) => {
410 self.run_editor_command(page, |_, editor, page| {
411 editor.buffer_view.lock().get_caret_mut().set_font_page(page);
412
413 let lock = &mut editor.buffer_view.lock();
414 let buf = &mut lock.get_buffer_mut();
415 if buf.get_font(page).is_none() {
416 match BitFont::from_ansi_font_page(page) {
417 Ok(font) => {
418 buf.set_font(page, font);
419 }
420 Err(err) => {
421 log::error!("Failed to load font: {err}");
422 }
423 }
424 }
425 None
426 });
427 }
428
429 Message::CharTable(ch) => {
430 self.run_editor_command(ch, |_, editor, ch| {
431 editor.type_key(ch);
432 None
433 });
434 }
435
436 Message::SelectTool(tool) => {
437 self.document_behavior.set_selected_tool(tool);
438 }
439
440 Message::SelectPreviousTool => {
441 self.document_behavior.select_prev_tool();
442 }
443
444 Message::ShowAboutDialog => {
445 self.open_dialog(crate::AboutDialog::default());
446 }
447
448 Message::ShowError(msg) => {
449 log::error!("{msg}");
450 self.toasts.error(msg);
451 }
452
453 Message::Paste => {
454 if let Some(doc) = self.get_active_document() {
455 self.handle_result(doc.lock().paste());
456 }
457 }
458
459 Message::Cut => {
460 if let Some(doc) = self.get_active_document() {
461 self.handle_result(doc.lock().cut());
462 }
463 }
464 Message::Copy => {
465 if let Some(doc) = self.get_active_document() {
466 self.handle_result(doc.lock().copy());
467 }
468 }
469
470 Message::JustifyLeft => {
471 self.run_editor_command(0, |_, editor, _| {
472 let mut lock = editor.buffer_view.lock();
473 to_message(lock.get_edit_state_mut().justify_left())
474 });
475 }
476
477 Message::JustifyRight => {
478 self.run_editor_command(0, |_, editor, _| {
479 let mut lock = editor.buffer_view.lock();
480 to_message(lock.get_edit_state_mut().justify_right())
481 });
482 }
483
484 Message::Center => {
485 self.run_editor_command(0, |_, editor, _| {
486 let mut lock = editor.buffer_view.lock();
487 to_message(lock.get_edit_state_mut().center())
488 });
489 }
490
491 Message::FlipX => {
492 self.run_editor_command(0, |_, editor, _| {
493 let mut lock = editor.buffer_view.lock();
494 to_message(lock.get_edit_state_mut().flip_x())
495 });
496 }
497
498 Message::FlipY => {
499 self.run_editor_command(0, |_, editor, _| {
500 let mut lock = editor.buffer_view.lock();
501 to_message(lock.get_edit_state_mut().flip_y())
502 });
503 }
504
505 Message::Crop => {
506 self.run_editor_command(0, |_, editor, _| {
507 let mut lock = editor.buffer_view.lock();
508 to_message(lock.get_edit_state_mut().crop())
509 });
510 }
511 Message::ResizeBuffer(resize_layer, w, h) => {
512 self.run_editor_command((resize_layer, w, h), |_, editor, (resize_layer, w, h)| {
513 let mut lock = editor.buffer_view.lock();
514 to_message(lock.get_edit_state_mut().resize_buffer(resize_layer, Size::new(w, h)))
515 });
516 }
517
518 Message::PasteAsNewImage => {
519 if let Some(data) = pop_data(icy_engine::util::BUFFER_DATA) {
520 if let Some(mut layer) = Layer::from_clipboard_data(&data) {
521 layer.set_offset((0, 0));
522 layer.role = icy_engine::Role::Normal;
523 let mut buf = icy_engine::Buffer::new(layer.get_size());
524 layer.set_title(buf.layers[0].get_title());
525 buf.layers.clear();
526 buf.layers.push(layer);
527 let id = self.create_id();
528 buf.is_terminal_buffer = false;
529 buf.set_height(buf.get_line_count());
530 let editor = AnsiEditor::new(&self.gl, id, buf);
531 crate::add_child(&mut self.document_tree, None, Box::new(editor));
532 }
533 }
534 }
535
536 Message::PasteAsBrush => {
537 if let Some(data) = pop_data(icy_engine::util::BUFFER_DATA) {
538 if let Some(layer) = Layer::from_clipboard_data(&data) {
539 unsafe {
540 crate::model::brush_imp::CUSTOM_BRUSH = Some(layer);
541 self.document_behavior.set_selected_tool(crate::BRUSH_TOOL);
542 }
543 }
544 }
545 }
546 Message::CloseWindow => {
547 self.is_closed = true;
548 }
549 Message::CenterLine => {
550 self.run_editor_command(0, |_, editor, _| {
551 let mut lock = editor.buffer_view.lock();
552 to_message(lock.get_edit_state_mut().center_line())
553 });
554 }
555 Message::JustifyLineLeft => {
556 self.run_editor_command(0, |_, editor, _| {
557 let mut lock = editor.buffer_view.lock();
558 to_message(lock.get_edit_state_mut().justify_line_left())
559 });
560 }
561 Message::JustifyLineRight => {
562 self.run_editor_command(0, |_, editor, _| {
563 let mut lock = editor.buffer_view.lock();
564 to_message(lock.get_edit_state_mut().justify_line_right())
565 });
566 }
567 Message::InsertRow => {
568 self.run_editor_command(0, |_, editor, _| {
569 let mut lock = editor.buffer_view.lock();
570 to_message(lock.get_edit_state_mut().insert_row())
571 });
572 }
573 Message::DeleteRow => {
574 self.run_editor_command(0, |_, editor, _| {
575 let mut lock = editor.buffer_view.lock();
576 to_message(lock.get_edit_state_mut().delete_row())
577 });
578 }
579 Message::InsertColumn => {
580 self.run_editor_command(0, |_, editor, _| {
581 let mut lock = editor.buffer_view.lock();
582 to_message(lock.get_edit_state_mut().insert_column())
583 });
584 }
585 Message::DeleteColumn => {
586 self.run_editor_command(0, |_, editor, _| {
587 let mut lock = editor.buffer_view.lock();
588 to_message(lock.get_edit_state_mut().delete_column())
589 });
590 }
591 Message::EraseRow => {
592 self.run_editor_command(0, |_, editor, _| {
593 let mut lock = editor.buffer_view.lock();
594 to_message(lock.get_edit_state_mut().erase_row())
595 });
596 }
597 Message::EraseRowToStart => {
598 self.run_editor_command(0, |_, editor, _| {
599 let mut lock = editor.buffer_view.lock();
600 to_message(lock.get_edit_state_mut().erase_row_to_start())
601 });
602 }
603 Message::EraseRowToEnd => {
604 self.run_editor_command(0, |_, editor, _| {
605 let mut lock = editor.buffer_view.lock();
606 to_message(lock.get_edit_state_mut().erase_row_to_end())
607 });
608 }
609 Message::EraseColumn => {
610 self.run_editor_command(0, |_, editor, _| {
611 let mut lock = editor.buffer_view.lock();
612 to_message(lock.get_edit_state_mut().erase_column())
613 });
614 }
615 Message::EraseColumnToStart => {
616 self.run_editor_command(0, |_, editor, _| {
617 let mut lock = editor.buffer_view.lock();
618 to_message(lock.get_edit_state_mut().erase_column_to_start())
619 });
620 }
621 Message::EraseColumnToEnd => {
622 self.run_editor_command(0, |_, editor, _| {
623 let mut lock = editor.buffer_view.lock();
624 to_message(lock.get_edit_state_mut().erase_column_to_end())
625 });
626 }
627 Message::ScrollAreaUp => {
628 self.run_editor_command(0, |_, editor, _| {
629 let mut lock = editor.buffer_view.lock();
630 to_message(lock.get_edit_state_mut().scroll_area_up())
631 });
632 }
633 Message::ScrollAreaDown => {
634 self.run_editor_command(0, |_, editor, _| {
635 let mut lock = editor.buffer_view.lock();
636 to_message(lock.get_edit_state_mut().scroll_area_down())
637 });
638 }
639 Message::ScrollAreaLeft => {
640 self.run_editor_command(0, |_, editor, _| {
641 let mut lock = editor.buffer_view.lock();
642 to_message(lock.get_edit_state_mut().scroll_area_left())
643 });
644 }
645 Message::ScrollAreaRight => {
646 self.run_editor_command(0, |_, editor, _| {
647 let mut lock = editor.buffer_view.lock();
648 to_message(lock.get_edit_state_mut().scroll_area_right())
649 });
650 }
651
652 Message::StampLayerDown => {
653 self.run_editor_command(0, |_, editor, _| {
654 let mut lock = editor.buffer_view.lock();
655 to_message(lock.get_edit_state_mut().stamp_layer_down())
656 });
657 }
658
659 Message::RotateLayer => {
660 self.run_editor_command(0, |_, editor, _| {
661 let mut lock = editor.buffer_view.lock();
662 to_message(lock.get_edit_state_mut().rotate_layer())
663 });
664 }
665
666 Message::MakeLayerTransparent => {
667 self.run_editor_command(0, |_, editor, _| {
668 let mut lock = editor.buffer_view.lock();
669 to_message(lock.get_edit_state_mut().make_layer_transparent())
670 });
671 }
672
673 Message::SetReferenceImage => {
674 self.run_editor_command(0, |window, editor, _| {
675 let mut initial_directory = if let Some(d) = editor.buffer_view.lock().get_reference_image_path() {
676 d.parent().map(|p| p.to_path_buf())
677 } else {
678 None
679 };
680 set_default_initial_directory_opt(&mut initial_directory);
681
682 window.open_dialog(crate::OpenReferenceImageDialog::new(initial_directory));
683 None
684 });
685 }
686 Message::ToggleReferenceImage => {
687 self.run_editor_command(0, |_, editor, _| {
688 let mut lock = editor.buffer_view.lock();
689 lock.toggle_reference_image();
690 None
691 });
692 }
693 Message::ClearReferenceImage => {
694 self.run_editor_command(0, |_, editor, _| {
695 let mut lock: eframe::epaint::mutex::MutexGuard<'_, icy_engine_egui::BufferView> = editor.buffer_view.lock();
696 lock.clear_reference_image();
697 None
698 });
699 }
700
701 Message::PickAttributeUnderCaret => {
702 self.run_editor_command(0, |_, editor, _| {
703 let bv = &mut editor.buffer_view.lock();
704 let pos = bv.get_caret().get_position();
705
706 let attr = if let Some(layer) = bv.get_edit_state().get_cur_layer() {
707 bv.get_buffer().get_char(pos + layer.get_offset()).attribute
708 } else {
709 bv.get_buffer().get_char(pos).attribute
710 };
711
712 let fg = attr.get_foreground();
713 let bg = attr.get_background();
714 let caret = bv.get_caret_mut();
715 caret.set_foreground(fg);
716 caret.set_background(bg);
717 None
718 });
719 }
720
721 Message::SwitchToDefaultColor => {
722 self.run_editor_command(0, |_, editor, _| {
723 let bv = &mut editor.buffer_view.lock();
724 let caret = bv.get_caret_mut();
725 caret.set_foreground(7);
726 caret.set_background(0);
727 None
728 });
729 }
730
731 Message::ToggleColor => {
732 self.run_editor_command(0, |_, editor, _| {
733 let mut attr = editor.buffer_view.lock().get_caret().get_attribute();
734 let fg = attr.get_foreground();
735 let bg = attr.get_background();
736 attr.set_foreground(bg);
737 attr.set_background(fg);
738 editor.buffer_view.lock().get_caret_mut().set_attr(attr);
739 None
740 });
741 }
742
743 Message::SelectOutline(outline) => {
744 Settings::set_character_set(outline);
745 }
746
747 Message::ToggleFullScreen => {
748 self.is_fullscreen = !self.is_fullscreen;
749 }
750
751 Message::ZoomReset => unsafe {
752 SETTINGS.set_scale(Vec2::splat(2.0));
753 },
754
755 Message::ZoomIn => unsafe {
756 SETTINGS.set_scale(SETTINGS.get_scale() + Vec2::splat(0.5));
757 },
758
759 Message::ZoomOut => unsafe {
760 SETTINGS.set_scale(SETTINGS.get_scale() - Vec2::splat(0.5));
761 },
762
763 Message::OpenFontDirectory => match Settings::get_font_diretory() {
764 Ok(dir) => {
765 if let Err(err) = open::that(dir) {
766 self.handle_message(Some(Message::ShowError(format!("Can't open font directory: {err}"))));
767 }
768 }
769 Err(err) => {
770 self.handle_message(Some(Message::ShowError(format!("{err}"))));
771 }
772 },
773
774 Message::OpenTdfDirectory => match Settings::get_tdf_diretory() {
775 Ok(dir) => {
776 if let Err(err) = open::that(dir) {
777 self.handle_message(Some(Message::ShowError(format!("Can't open font directory: {err}"))));
778 }
779 }
780 Err(err) => {
781 self.handle_message(Some(Message::ShowError(format!("{err}"))));
782 }
783 },
784
785 Message::OpenPalettesDirectory => match Settings::get_palettes_diretory() {
786 Ok(dir) => {
787 if let Err(err) = open::that(dir) {
788 self.handle_message(Some(Message::ShowError(format!("Can't open font directory: {err}"))));
789 }
790 }
791 Err(err) => {
792 self.handle_message(Some(Message::ShowError(format!("{err}"))));
793 }
794 },
795 Message::OpenFontSelector => {
796 self.run_editor_command(0, |window, editor, _| {
797 window.open_dialog(crate::FontSelector::new(editor, false));
798 None
799 });
800 }
801
802 Message::OpenAddFonts => {
803 self.run_editor_command(0, |window, editor, _| {
804 window.open_dialog(crate::FontSelector::new(editor, true));
805 None
806 });
807 }
808
809 Message::OpenFontManager => {
810 self.run_editor_command(0, |window, editor, _| {
811 window.open_dialog(crate::FontManager::new(editor));
812 None
813 });
814 }
815 Message::SetGuide(x, y) => {
816 self.run_editor_command((x, y), |_, editor, (x, y)| {
817 if x <= 0 && y <= 0 {
818 editor.guide = None;
819 } else {
820 editor.guide = Some(Vec2::new(x as f32, y as f32));
821 editor.buffer_view.lock().set_show_guide(true);
822 }
823 None
824 });
825 }
826 Message::SetRaster(x, y) => {
827 self.run_editor_command((x, y), |_, editor, (x, y)| {
828 if x <= 0 && y <= 0 {
829 editor.raster = None;
830 } else {
831 editor.raster = Some(Vec2::new(x as f32, y as f32));
832 editor.buffer_view.lock().set_show_raster(true);
833 }
834 None
835 });
836 }
837
838 Message::ToggleMirrorMode => {
839 self.run_editor_command(0, |_, editor, _| {
840 let mode = editor.buffer_view.lock().get_edit_state_mut().get_mirror_mode();
841 editor.buffer_view.lock().get_edit_state_mut().set_mirror_mode(!mode);
842 None
843 });
844 }
845
846 Message::ClearRecentOpenFiles => {
847 unsafe { MRU_FILES.clear_recent_files() };
848 }
849
850 Message::InverseSelection => {
851 self.run_editor_command(0, |_, editor, _| to_message(editor.buffer_view.lock().get_edit_state_mut().inverse_selection()));
852 }
853
854 Message::SetForeground(color) => {
855 self.run_editor_command(color, |_, editor, color| {
856 editor.buffer_view.lock().get_caret_mut().set_foreground(color);
857 None
858 });
859 }
860 Message::SetForegroundRgb(r, g, b) => {
861 self.run_editor_command((r, g, b), |_, editor, (r, g, b)| {
862 let color = editor.buffer_view.lock().get_buffer_mut().palette.insert_color_rgb(r, g, b);
863 editor.buffer_view.lock().get_caret_mut().set_foreground(color);
864 None
865 });
866 }
867
868 Message::SetBackground(color) => {
869 self.run_editor_command(color, |_, editor, color| {
870 editor.buffer_view.lock().get_caret_mut().set_background(color);
871 None
872 });
873 }
874 Message::SetBackgroundRgb(r, g, b) => {
875 self.run_editor_command((r, g, b), |_, editor, (r, g, b)| {
876 let color = editor.buffer_view.lock().get_buffer_mut().palette.insert_color_rgb(r, g, b);
877 editor.buffer_view.lock().get_caret_mut().set_background(color);
878 None
879 });
880 }
881
882 Message::UpdateFont(font_box) => {
883 let (old, new) = font_box.as_ref();
884 self.enumerate_documents(|_, pane| {
885 if let Some(editor) = pane.doc.lock().get_ansi_editor() {
886 editor.buffer_view.lock().get_buffer_mut().font_iter_mut().for_each(|(_, font)| {
887 if font.glyphs == old.glyphs {
888 *font = new.clone();
889 }
890 });
891 editor.buffer_view.lock().redraw_font();
892 }
893 });
894 }
895
896 Message::SelectPalette => {
897 self.run_editor_command(0, |window, editor, _| {
898 let mut msg = None;
899
900 match crate::SelectPaletteDialog::new(editor) {
901 Ok(dialog) => {
902 window.open_dialog(dialog);
903 }
904 Err(err) => {
905 log::error!("Failed to open palette dialog: {err}");
906 msg = Some(Message::ShowError(format!("{err}")));
907 }
908 }
909 msg
910 });
911 }
912
913 Message::ToggleLayerBorders => unsafe {
914 SETTINGS.show_layer_borders = !SETTINGS.show_layer_borders;
915 },
916 Message::ToggleLineNumbers => unsafe {
917 SETTINGS.show_line_numbers = !SETTINGS.show_line_numbers;
918 },
919 Message::RunPlugin(i) => {
920 self.run_editor_command(i, |window, editor, i| {
921 let mut msg = None;
922 unsafe {
923 if let Err(err) = PLUGINS[i].run_plugin(window, editor) {
924 msg = Some(Message::ShowError(format!("Error running plugin: {err}")));
925 }
926 }
927 msg
928 });
929 }
930 Message::OpenPluginDirectory => match Settings::get_plugin_directory() {
931 Ok(dir) => {
932 if let Err(err) = open::that(dir) {
933 self.handle_message(Some(Message::ShowError(format!("Can't open font directory: {err}"))));
934 }
935 }
936 Err(err) => {
937 self.handle_message(Some(Message::ShowError(format!("{err}"))));
938 }
939 },
940
941 Message::KeySwitchForeground(k) => {
942 self.run_editor_command(k, |_, editor, k| {
943 let palette_len = editor.buffer_view.lock().get_buffer_mut().palette.len() as u32;
944 let mut fg = editor.buffer_view.lock().get_caret_mut().get_attribute().get_foreground();
945 if fg % 8 == k as u32 {
946 fg += 8;
947 } else {
948 fg = k as u32;
949 }
950 fg %= palette_len;
951 if fg < 8 || editor.buffer_view.lock().get_buffer().font_mode.has_high_fg_colors() || palette_len > 16 {
952 editor.buffer_view.lock().get_caret_mut().set_foreground(fg);
953 }
954 None
955 });
956 }
957
958 Message::KeySwitchBackground(k) => {
959 self.run_editor_command(k, |_, editor, k| {
960 let palette_len = editor.buffer_view.lock().get_buffer_mut().palette.len() as u32;
961 let mut bg = editor.buffer_view.lock().get_caret_mut().get_attribute().get_background();
962 if bg % 8 == k as u32 {
963 bg += 8;
964 } else {
965 bg = k as u32;
966 }
967 bg %= palette_len;
968 if bg < 8 || editor.buffer_view.lock().get_buffer().ice_mode.has_high_bg_colors() || palette_len > 16 {
969 editor.buffer_view.lock().get_caret_mut().set_background(bg);
970 }
971 None
972 });
973 }
974
975 Message::NextFgColor => {
976 self.run_editor_command(0, |_, editor, _| {
977 let palette_len = editor.buffer_view.lock().get_buffer_mut().palette.len() as u32;
978 let fg = editor.buffer_view.lock().get_caret_mut().get_attribute().get_foreground();
979
980 editor.buffer_view.lock().get_caret_mut().set_foreground((fg + 1) % palette_len);
981 None
982 });
983 }
984 Message::PreviousFgColor => {
985 self.run_editor_command(0, |_, editor, _| {
986 let palette_len = editor.buffer_view.lock().get_buffer_mut().palette.len() as u32;
987 let fg = editor.buffer_view.lock().get_caret_mut().get_attribute().get_foreground();
988
989 editor.buffer_view.lock().get_caret_mut().set_foreground((fg + palette_len - 1) % palette_len);
990 None
991 });
992 }
993 Message::NextBgColor => {
994 self.run_editor_command(0, |_, editor, _| {
995 let palette_len = editor.buffer_view.lock().get_buffer_mut().palette.len() as u32;
996 let bg = editor.buffer_view.lock().get_caret_mut().get_attribute().get_background();
997
998 editor.buffer_view.lock().get_caret_mut().set_background((bg + 1) % palette_len);
999 None
1000 });
1001 }
1002 Message::PreviousBgColor => {
1003 self.run_editor_command(0, |_, editor, _| {
1004 let palette_len = editor.buffer_view.lock().get_buffer_mut().palette.len() as u32;
1005 let bg = editor.buffer_view.lock().get_caret_mut().get_attribute().get_background();
1006
1007 editor.buffer_view.lock().get_caret_mut().set_background((bg + palette_len - 1) % palette_len);
1008 None
1009 });
1010 }
1011 Message::ShowSettings => {
1012 self.show_settings = true;
1013 self.settings_dialog.init();
1014 }
1015
1016 Message::ToggleLGAFont => {
1017 self.run_editor_command(0, |_, editor, _| {
1018 let use_lga = editor.buffer_view.lock().get_buffer_mut().use_letter_spacing();
1019 let mut sauce_data = if let Some(data) = &editor.buffer_view.lock().get_buffer_mut().get_sauce() {
1020 data.clone()
1021 } else {
1022 SauceData::default()
1023 };
1024 sauce_data.use_letter_spacing = !use_lga;
1025
1026 to_message(editor.buffer_view.lock().get_edit_state_mut().update_sauce_data(Some(sauce_data)))
1027 });
1028 }
1029
1030 Message::ToggleAspectRatio => {
1031 self.run_editor_command(0, |_, editor, _| {
1032 let use_ar = editor.buffer_view.lock().get_buffer_mut().use_aspect_ratio();
1033 let mut sauce_data = if let Some(data) = &editor.buffer_view.lock().get_buffer_mut().get_sauce() {
1034 data.clone()
1035 } else {
1036 SauceData::default()
1037 };
1038 sauce_data.use_aspect_ratio = !use_ar;
1039
1040 to_message(editor.buffer_view.lock().get_edit_state_mut().update_sauce_data(Some(sauce_data)))
1041 });
1042 }
1043
1044 Message::SwitchToFontPage(page) => {
1045 self.run_editor_command(page, |_, editor, page| {
1046 to_message(editor.buffer_view.lock().get_edit_state_mut().switch_to_font_page(page))
1047 });
1048 }
1049 Message::SetAnsiFont(page) => {
1050 self.run_editor_command(page, |_, editor, page| {
1051 to_message(editor.buffer_view.lock().get_edit_state_mut().set_ansi_font(page))
1052 });
1053 }
1054
1055 Message::SetSauceFont(name) => {
1056 self.run_editor_command(name, |_, editor, name| {
1057 to_message(editor.buffer_view.lock().get_edit_state_mut().set_sauce_font(&name))
1058 });
1059 }
1060
1061 Message::SetFont(fnt) => {
1062 self.run_editor_command(fnt, |_, editor, fnt| to_message(editor.buffer_view.lock().get_edit_state_mut().set_font(*fnt)));
1063 }
1064 Message::AddAnsiFont(page) => {
1065 self.run_editor_command(page, |_, editor, page| {
1066 to_message(editor.buffer_view.lock().get_edit_state_mut().add_ansi_font(page))
1067 });
1068 }
1069 Message::AddFont(fnt) => {
1070 self.run_editor_command(fnt, |_, editor, fnt| to_message(editor.buffer_view.lock().get_edit_state_mut().add_font(*fnt)));
1071 }
1072
1073 Message::SwitchPaletteMode(mode) => {
1074 self.run_editor_command(mode, |_, editor, mode| {
1075 to_message(editor.buffer_view.lock().get_edit_state_mut().set_palette_mode(mode))
1076 });
1077 }
1078
1079 Message::SwitchIceMode(mode) => {
1080 self.run_editor_command(mode, |_, editor, mode| {
1081 to_message(editor.buffer_view.lock().get_edit_state_mut().set_ice_mode(mode))
1082 });
1083 }
1084
1085 Message::ToggleGrid => {
1086 self.run_editor_command(0, |_, editor, _| {
1087 let lock = &mut editor.buffer_view.lock();
1088 let show_raster = lock.get_show_raster();
1089 let show_guide = lock.get_show_guide();
1090
1091 if editor.raster.is_some() && editor.guide.is_some() {
1092 if show_raster && show_guide {
1093 lock.set_show_raster(false);
1094 lock.set_show_guide(false);
1095 } else if show_raster {
1096 lock.set_show_guide(true);
1097 } else {
1098 lock.set_show_raster(true);
1099 }
1100 } else if editor.raster.is_some() {
1101 lock.set_show_raster(!show_raster);
1102 } else if editor.guide.is_some() {
1103 lock.set_show_guide(!show_guide);
1104 }
1105 None
1106 });
1107 }
1108 }
1109 }
1110 }
1111
1112 fn is_icy_file(get_path: Option<PathBuf>) -> bool {
1113 let Some(path) = get_path else {
1114 return false;
1115 };
1116 let Some(ext) = path.extension() else {
1117 return false;
1118 };
1119 ext == "icy"
1120 }
1121
1122 pub fn set_default_initial_directory_opt(initial_directory: &mut Option<PathBuf>) {
1123 if initial_directory.is_some() {
1124 return;
1125 }
1126 *initial_directory = if let Some(user) = UserDirs::new() {
1127 Some(user.home_dir().to_path_buf())
1128 } else if let Ok(cur) = std::env::current_dir() {
1129 Some(cur)
1130 } else {
1131 return;
1132 };
1133 }
1134
1135 pub fn to_message<T>(result: EngineResult<T>) -> Option<Message> {
1136 if let Err(result) = result {
1137 Some(Message::ShowError(format!("{result}")))
1138 } else {
1139 None
1140 }
1141 }