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 }