URI: 
       brush_imp.rs - icy_draw - icy_draw is the successor to mystic draw. fork / mirror
  HTML git clone https://git.drkhsh.at/icy_draw.git
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       brush_imp.rs (10132B)
       ---
            1 use eframe::egui::Response;
            2 use egui::{load::SizedTexture, Image, TextureHandle, Widget};
            3 use i18n_embed_fl::fl;
            4 use icy_engine::{editor::AtomicUndoGuard, AttributedChar, Layer, TextPane};
            5 use icy_engine_egui::TerminalCalc;
            6 use std::{cell::RefCell, rc::Rc};
            7 
            8 use crate::{
            9     create_image,
           10     paint::{BrushMode, ColorMode},
           11     AnsiEditor, Event, Message,
           12 };
           13 
           14 use super::{Position, Tool};
           15 
           16 pub static mut CUSTOM_BRUSH: Option<Layer> = None;
           17 
           18 pub struct BrushTool {
           19     color_mode: ColorMode,
           20     size: i32,
           21     char_code: Rc<RefCell<char>>,
           22 
           23     undo_op: Option<AtomicUndoGuard>,
           24     cur_pos: Position,
           25     custom_brush: Option<Layer>,
           26     image: Option<TextureHandle>,
           27     brush_mode: BrushMode,
           28 }
           29 
           30 impl Default for BrushTool {
           31     fn default() -> Self {
           32         Self {
           33             size: 3,
           34             color_mode: ColorMode::Both,
           35             undo_op: None,
           36             custom_brush: None,
           37             image: None,
           38             brush_mode: BrushMode::Shade,
           39             char_code: Rc::new(RefCell::new('\u{00B0}')),
           40             cur_pos: Position::default(),
           41         }
           42     }
           43 }
           44 impl BrushTool {
           45     fn paint_brush(&self, editor: &mut AnsiEditor, pos: Position) {
           46         let mid = Position::new(-(self.size / 2), -(self.size / 2));
           47 
           48         let center = pos + mid;
           49         let gradient = ['\u{00B0}', '\u{00B1}', '\u{00B2}', '\u{00DB}'];
           50         let caret_attr = editor.buffer_view.lock().get_caret().get_attribute();
           51         if matches!(self.brush_mode, BrushMode::Custom) {
           52             editor.join_overlay("brush");
           53             return;
           54         }
           55 
           56         let use_selection = editor.buffer_view.lock().get_edit_state().is_something_selected();
           57         editor.buffer_view.lock().get_edit_state_mut().set_is_buffer_dirty();
           58 
           59         let offset = if let Some(layer) = editor.buffer_view.lock().get_edit_state().get_cur_layer() {
           60             layer.get_offset()
           61         } else {
           62             Position::default()
           63         };
           64 
           65         for y in 0..self.size {
           66             for x in 0..self.size {
           67                 let pos = center + Position::new(x, y);
           68                 if use_selection && !editor.buffer_view.lock().get_edit_state().get_is_selected(pos + offset) {
           69                     continue;
           70                 }
           71                 let ch = editor.get_char_from_cur_layer(pos);
           72                 let mut attribute = ch.attribute;
           73                 attribute.attr &= !icy_engine::attribute::INVISIBLE;
           74 
           75                 if self.color_mode.use_fore() {
           76                     attribute.set_foreground(caret_attr.get_foreground());
           77                 }
           78                 if self.color_mode.use_back() {
           79                     attribute.set_background(caret_attr.get_background());
           80                 }
           81 
           82                 match &self.brush_mode {
           83                     BrushMode::Shade => {
           84                         let mut char_code = gradient[0];
           85                         if ch.ch == gradient[gradient.len() - 1] {
           86                             char_code = gradient[gradient.len() - 1];
           87                         } else {
           88                             for i in 0..gradient.len() - 1 {
           89                                 if ch.ch == gradient[i] {
           90                                     char_code = gradient[i + 1];
           91                                     break;
           92                                 }
           93                             }
           94                         }
           95                         editor.set_char(pos, AttributedChar::new(char_code, attribute));
           96                     }
           97                     BrushMode::Char(ch) => {
           98                         attribute.set_font_page(caret_attr.get_font_page());
           99                         editor.set_char(center + Position::new(x, y), AttributedChar::new(*ch.borrow(), attribute));
          100                     }
          101                     BrushMode::Colorize => {
          102                         editor.set_char(pos, AttributedChar::new(ch.ch, attribute));
          103                     }
          104                     _ => {}
          105                 }
          106             }
          107         }
          108     }
          109 }
          110 
          111 impl Tool for BrushTool {
          112     fn get_icon(&self) -> &egui::Image<'static> {
          113         &super::icons::BRUSH_SVG
          114     }
          115 
          116     fn tool_name(&self) -> String {
          117         fl!(crate::LANGUAGE_LOADER, "tool-paint_brush_name")
          118     }
          119 
          120     fn tooltip(&self) -> String {
          121         fl!(crate::LANGUAGE_LOADER, "tool-paint_brush_tooltip")
          122     }
          123 
          124     fn use_caret(&self, _editor: &AnsiEditor) -> bool {
          125         false
          126     }
          127 
          128     fn show_ui(&mut self, ctx: &egui::Context, ui: &mut egui::Ui, editor_opt: Option<&mut AnsiEditor>) -> Option<Message> {
          129         self.color_mode.show_ui(ui);
          130 
          131         ui.horizontal(|ui| {
          132             ui.label(fl!(crate::LANGUAGE_LOADER, "tool-size-label"));
          133             ui.add(egui::DragValue::new(&mut self.size).clamp_range(1..=20).speed(1));
          134         });
          135         /*
          136                 ui.radio_value(&mut self.brush_type, BrushType::Shade, fl!(crate::LANGUAGE_LOADER, "tool-shade"));
          137                 ui.horizontal(|ui| {
          138                     ui.radio_value(&mut self.brush_type, BrushType::Solid, fl!(crate::LANGUAGE_LOADER, "tool-character"));
          139                     if let Some(buffer_opt) = buffer_opt {
          140                         result = draw_glyph(ui, buffer_opt, &self.char_code);
          141                     }
          142                 });
          143                 ui.radio_value(&mut self.brush_type, BrushType::Color, fl!(crate::LANGUAGE_LOADER, "tool-colorize"));
          144         */
          145         let result = self.brush_mode.show_ui(ui, editor_opt, self.char_code.clone(), crate::paint::BrushUi::Brush);
          146 
          147         unsafe {
          148             if CUSTOM_BRUSH.is_some() {
          149                 self.custom_brush = CUSTOM_BRUSH.take();
          150             }
          151         }
          152 
          153         if let Some(custom_brush) = &self.custom_brush {
          154             let mut layer = custom_brush.clone();
          155             layer.set_offset((0, 0));
          156             layer.role = icy_engine::Role::Normal;
          157             let mut buf = icy_engine::Buffer::new(layer.get_size());
          158             layer.set_title(buf.layers[0].get_title());
          159             buf.layers.clear();
          160             buf.layers.push(layer);
          161             self.image = Some(create_image(ctx, &buf));
          162 
          163             ui.radio_value(&mut self.brush_mode, BrushMode::Custom, fl!(crate::LANGUAGE_LOADER, "tool-custom-brush"));
          164             if let Some(image) = &self.image {
          165                 let sized_texture: SizedTexture = image.into();
          166                 let w = ui.available_width() - 16.0;
          167                 let scale = w / sized_texture.size.x;
          168                 let image = Image::from_texture(sized_texture).fit_to_original_size(scale);
          169                 image.ui(ui);
          170             }
          171         }
          172         result
          173     }
          174 
          175     fn handle_no_hover(&mut self, editor: &mut AnsiEditor) {
          176         if matches!(self.brush_mode, BrushMode::Custom) {
          177             editor.clear_overlay_layer();
          178         }
          179         let lock = &mut editor.buffer_view.lock();
          180         let get_edit_state_mut = lock.get_edit_state_mut();
          181         if get_edit_state_mut.get_tool_overlay_mask_mut().is_empty() {
          182             return;
          183         }
          184         get_edit_state_mut.get_tool_overlay_mask_mut().clear();
          185         get_edit_state_mut.set_is_buffer_dirty();
          186     }
          187 
          188     fn handle_hover(&mut self, _ui: &egui::Ui, response: egui::Response, editor: &mut AnsiEditor, cur: Position, cur_abs: Position) -> egui::Response {
          189         if matches!(self.brush_mode, BrushMode::Custom) {
          190             editor.clear_overlay_layer();
          191             let lock = &mut editor.buffer_view.lock();
          192             if let Some(layer) = lock.get_edit_state_mut().get_overlay_layer() {
          193                 if let Some(brush) = &self.custom_brush {
          194                     let mid = Position::new(-(brush.get_width() / 2), -(brush.get_height() / 2));
          195                     self.cur_pos = cur + mid;
          196                     for y in 0..brush.get_height() {
          197                         for x in 0..brush.get_width() {
          198                             let pos = Position::new(x, y);
          199                             let ch = brush.get_char(pos);
          200                             layer.set_char(cur + pos + mid, AttributedChar::new(ch.ch, ch.attribute));
          201                         }
          202                     }
          203                     lock.get_edit_state_mut().set_is_buffer_dirty();
          204                 }
          205             }
          206         } else {
          207             let mid = Position::new(-(self.size / 2), -(self.size / 2));
          208 
          209             if self.cur_pos != cur + mid {
          210                 self.cur_pos = cur + mid;
          211                 let lock = &mut editor.buffer_view.lock();
          212                 let get_tool_overlay_mask_mut = lock.get_edit_state_mut().get_tool_overlay_mask_mut();
          213                 get_tool_overlay_mask_mut.clear();
          214                 for y in 0..self.size {
          215                     for x in 0..self.size {
          216                         let pos = cur_abs + Position::new(x, y) + mid;
          217                         get_tool_overlay_mask_mut.set_is_selected(pos, true);
          218                     }
          219                 }
          220                 lock.get_edit_state_mut().set_is_buffer_dirty();
          221             }
          222             editor.buffer_view.lock().get_buffer_mut().remove_overlay();
          223         }
          224         response.on_hover_cursor(egui::CursorIcon::Crosshair)
          225     }
          226 
          227     fn handle_click(&mut self, editor: &mut AnsiEditor, button: i32, pos: Position, _pos_abs: Position, _response: &Response) -> Option<Message> {
          228         if button == 1 {
          229             let _op: AtomicUndoGuard = editor.begin_atomic_undo(fl!(crate::LANGUAGE_LOADER, "undo-paint-brush"));
          230 
          231             self.paint_brush(editor, pos);
          232         }
          233         None
          234     }
          235 
          236     fn handle_drag(&mut self, _ui: &egui::Ui, response: egui::Response, editor: &mut AnsiEditor, _calc: &TerminalCalc) -> egui::Response {
          237         self.paint_brush(editor, editor.drag_pos.cur);
          238         response
          239     }
          240 
          241     fn handle_drag_begin(&mut self, editor: &mut AnsiEditor, _response: &egui::Response) -> Event {
          242         self.undo_op = Some(editor.begin_atomic_undo(fl!(crate::LANGUAGE_LOADER, "undo-paint-brush")));
          243         self.paint_brush(editor, editor.drag_pos.cur);
          244         Event::None
          245     }
          246 
          247     fn handle_drag_end(&mut self, _editor: &mut AnsiEditor) -> Option<Message> {
          248         self.undo_op = None;
          249         None
          250     }
          251 
          252     fn get_toolbar_location_text(&self, _editor: &AnsiEditor) -> String {
          253         let pos = self.cur_pos;
          254         fl!(crate::LANGUAGE_LOADER, "toolbar-position", line = (pos.y + 1), column = (pos.x + 1))
          255     }
          256 }