erase_imp.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
---
erase_imp.rs (6396B)
---
1 use eframe::egui;
2 use i18n_embed_fl::fl;
3 use icy_engine::{editor::AtomicUndoGuard, AttributedChar, TextAttribute};
4 use icy_engine_egui::TerminalCalc;
5
6 use crate::{AnsiEditor, Event, Message};
7
8 use super::{Position, Tool};
9
10 #[derive(PartialEq, Eq)]
11 pub enum EraseType {
12 Shade,
13 Solid,
14 }
15
16 pub struct EraseTool {
17 size: i32,
18 brush_type: EraseType,
19 undo_op: Option<AtomicUndoGuard>,
20 cur_pos: Position,
21 }
22
23 impl Default for EraseTool {
24 fn default() -> Self {
25 Self {
26 size: 3,
27 brush_type: crate::model::erase_imp::EraseType::Solid,
28 undo_op: None,
29 cur_pos: Position::default(),
30 }
31 }
32 }
33
34 impl EraseTool {
35 fn eraser(&self, editor: &mut AnsiEditor, pos: Position) {
36 let mid = Position::new(-(self.size / 2), -(self.size / 2));
37
38 let center = pos + mid;
39 let gradient = ['\u{00DB}', '\u{00B2}', '\u{00B1}', '\u{00B0}', ' '];
40 let use_selection = editor.buffer_view.lock().get_edit_state().is_something_selected();
41 let offset = if let Some(layer) = editor.buffer_view.lock().get_edit_state().get_cur_layer() {
42 layer.get_offset()
43 } else {
44 Position::default()
45 };
46 editor.buffer_view.lock().get_edit_state_mut().set_is_buffer_dirty();
47 for y in 0..self.size {
48 for x in 0..self.size {
49 let pos = center + Position::new(x, y);
50 if use_selection && !editor.buffer_view.lock().get_edit_state().get_is_selected(pos + offset) {
51 continue;
52 }
53 match self.brush_type {
54 EraseType::Shade => {
55 let ch = editor.get_char_from_cur_layer(pos);
56
57 let mut attribute = ch.attribute;
58
59 let mut char_code = gradient[0];
60 let mut found = false;
61 if ch.ch == gradient[gradient.len() - 1] {
62 char_code = gradient[gradient.len() - 1];
63 attribute = TextAttribute::default();
64 found = true;
65 } else {
66 for i in 0..gradient.len() - 1 {
67 if ch.ch == gradient[i] {
68 char_code = gradient[i + 1];
69 found = true;
70 break;
71 }
72 }
73 }
74
75 if found {
76 editor.set_char(pos, AttributedChar::new(char_code, attribute));
77 }
78 }
79 EraseType::Solid => {
80 editor.set_char(pos, AttributedChar::invisible());
81 }
82 }
83 }
84 }
85 }
86 }
87
88 impl Tool for EraseTool {
89 fn get_icon(&self) -> &egui::Image<'static> {
90 &super::icons::ERASER_SVG
91 }
92 fn tool_name(&self) -> String {
93 fl!(crate::LANGUAGE_LOADER, "tool-eraser_name")
94 }
95
96 fn tooltip(&self) -> String {
97 fl!(crate::LANGUAGE_LOADER, "tool-eraser_tooltip")
98 }
99
100 fn use_caret(&self, _editor: &AnsiEditor) -> bool {
101 false
102 }
103
104 fn show_ui(&mut self, _ctx: &egui::Context, ui: &mut egui::Ui, _editor_opt: Option<&mut AnsiEditor>) -> Option<Message> {
105 ui.horizontal(|ui| {
106 ui.label(fl!(crate::LANGUAGE_LOADER, "tool-size-label"));
107 ui.add(egui::DragValue::new(&mut self.size).clamp_range(1..=20).speed(1));
108 });
109 ui.radio_value(&mut self.brush_type, EraseType::Solid, fl!(crate::LANGUAGE_LOADER, "tool-solid"));
110 ui.radio_value(&mut self.brush_type, EraseType::Shade, fl!(crate::LANGUAGE_LOADER, "tool-shade"));
111 None
112 }
113
114 fn handle_no_hover(&mut self, editor: &mut AnsiEditor) {
115 let lock: &mut eframe::epaint::mutex::MutexGuard<'_, icy_engine_egui::BufferView> = &mut editor.buffer_view.lock();
116 let get_edit_state_mut = lock.get_edit_state_mut();
117 if get_edit_state_mut.get_tool_overlay_mask_mut().is_empty() {
118 return;
119 }
120 get_edit_state_mut.get_tool_overlay_mask_mut().clear();
121 get_edit_state_mut.set_is_buffer_dirty();
122 }
123
124 fn handle_hover(&mut self, _ui: &egui::Ui, response: egui::Response, editor: &mut AnsiEditor, cur: Position, cur_abs: Position) -> egui::Response {
125 let mid: Position = Position::new(-(self.size / 2), -(self.size / 2));
126 if self.cur_pos != cur + mid {
127 self.cur_pos = cur + mid;
128 let lock = &mut editor.buffer_view.lock();
129 let get_tool_overlay_mask_mut = lock.get_edit_state_mut().get_tool_overlay_mask_mut();
130 get_tool_overlay_mask_mut.clear();
131 for y in 0..self.size {
132 for x in 0..self.size {
133 let pos = cur_abs + Position::new(x, y) + mid;
134 get_tool_overlay_mask_mut.set_is_selected(pos, true);
135 }
136 }
137 lock.get_edit_state_mut().set_is_buffer_dirty();
138 }
139 response.on_hover_cursor(egui::CursorIcon::Crosshair)
140 }
141
142 fn handle_click(&mut self, editor: &mut AnsiEditor, button: i32, pos: Position, _pos_abs: Position, _response: &egui::Response) -> Option<Message> {
143 if button == 1 {
144 let _undo = editor.begin_atomic_undo(fl!(crate::LANGUAGE_LOADER, "undo-eraser"));
145 self.eraser(editor, pos);
146 }
147 None
148 }
149
150 fn handle_drag(&mut self, _ui: &egui::Ui, response: egui::Response, editor: &mut AnsiEditor, _calc: &TerminalCalc) -> egui::Response {
151 self.eraser(editor, editor.drag_pos.cur);
152 response
153 }
154
155 fn handle_drag_begin(&mut self, editor: &mut AnsiEditor, _response: &egui::Response) -> Event {
156 self.undo_op = Some(editor.begin_atomic_undo(fl!(crate::LANGUAGE_LOADER, "undo-eraser")));
157 self.eraser(editor, editor.drag_pos.cur);
158 Event::None
159 }
160
161 fn handle_drag_end(&mut self, _editor: &mut AnsiEditor) -> Option<Message> {
162 self.undo_op = None;
163 None
164 }
165
166 fn get_toolbar_location_text(&self, _editor: &AnsiEditor) -> String {
167 let pos = self.cur_pos;
168 fl!(crate::LANGUAGE_LOADER, "toolbar-position", line = (pos.y + 1), column = (pos.x + 1))
169 }
170 }