minimap_view.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
       ---
       minimap_view.rs (6284B)
       ---
            1 use std::sync::Arc;
            2 
            3 use eframe::{
            4     egui::{self, RichText},
            5     epaint::{Color32, Rect, Stroke, Vec2},
            6 };
            7 use egui::mutex::Mutex;
            8 use i18n_embed_fl::fl;
            9 use icy_engine::TextPane;
           10 use icy_engine_egui::BufferView;
           11 
           12 use crate::{AnsiEditor, Document, Message, ToolWindow};
           13 
           14 pub struct MinimapToolWindow {
           15     buffer_view: Arc<eframe::epaint::mutex::Mutex<BufferView>>,
           16     undo_size: i32,
           17     last_id: usize,
           18     palette_hash: u32,
           19     next_scroll_pos: Option<Vec2>,
           20 }
           21 
           22 impl ToolWindow for MinimapToolWindow {
           23     fn get_title(&self) -> String {
           24         fl!(crate::LANGUAGE_LOADER, "minimap_tool_title")
           25     }
           26 
           27     fn show_ui(&mut self, ui: &mut egui::Ui, active_document: Option<Arc<Mutex<Box<dyn Document>>>>) -> Option<Message> {
           28         if let Some(doc) = active_document {
           29             if let Some(editor) = doc.lock().get_ansi_editor_mut() {
           30                 return self.show_minimap(ui, editor);
           31             }
           32         }
           33         ui.vertical_centered(|ui| {
           34             ui.add_space(8.0);
           35             ui.label(RichText::new(fl!(crate::LANGUAGE_LOADER, "no_document_selected")).small());
           36         });
           37         None
           38     }
           39 }
           40 
           41 impl MinimapToolWindow {
           42     pub fn show_minimap(&mut self, ui: &mut egui::Ui, editor: &mut AnsiEditor) -> Option<Message> {
           43         let undo_stack = editor.buffer_view.lock().get_edit_state().undo_stack_len() as i32;
           44         let cur_palette_hash = editor.buffer_view.lock().get_buffer_mut().palette.get_checksum();
           45         if undo_stack != self.undo_size || self.last_id != editor.id || self.palette_hash != cur_palette_hash {
           46             self.undo_size = undo_stack;
           47             self.last_id = editor.id;
           48             let bv = editor.buffer_view.lock();
           49             let buffer = bv.get_buffer();
           50             self.buffer_view.lock().get_buffer_mut().set_size(buffer.get_size());
           51             self.buffer_view.lock().get_buffer_mut().layers = buffer.layers.clone();
           52             self.buffer_view.lock().get_buffer_mut().palette = buffer.palette.clone();
           53             self.buffer_view.lock().get_buffer_mut().set_font_table(buffer.get_font_table());
           54             self.palette_hash = cur_palette_hash;
           55             self.buffer_view.lock().redraw_font();
           56             self.buffer_view.lock().redraw_view();
           57         }
           58 
           59         self.buffer_view.lock().use_fg = editor.buffer_view.lock().use_fg;
           60         self.buffer_view.lock().use_bg = editor.buffer_view.lock().use_bg;
           61         let w = (ui.available_width() / self.buffer_view.lock().get_buffer().get_font_dimensions().width as f32).floor();
           62 
           63         let scalex = (w / self.buffer_view.lock().get_width() as f32).min(2.0);
           64         let scaley = if self.buffer_view.lock().get_buffer_mut().use_aspect_ratio() {
           65             scalex * 1.35
           66         } else {
           67             scalex
           68         };
           69 
           70         let mut opt = icy_engine_egui::TerminalOptions {
           71             filter: glow::LINEAR as i32,
           72             stick_to_bottom: false,
           73             scale: Some(Vec2::new(scalex, scaley)),
           74             use_terminal_height: false,
           75             hide_scrollbars: true,
           76 
           77             ..Default::default()
           78         };
           79 
           80         let next_scroll_pos = self.next_scroll_pos.take();
           81 
           82         if let Some(next_scroll_pos) = next_scroll_pos {
           83             opt.scroll_offset_x = Some(next_scroll_pos.x);
           84             opt.scroll_offset_y = Some(next_scroll_pos.y);
           85         }
           86 
           87         let (response, ours) = icy_engine_egui::show_terminal_area(ui, self.buffer_view.clone(), opt);
           88 
           89         let theirs = editor.buffer_view.lock().calc.clone();
           90 
           91         let their_total_size = Vec2::new(theirs.char_width, theirs.char_height) * theirs.char_size;
           92         let their_buffer_size = Vec2::new(theirs.buffer_char_width, theirs.buffer_char_height) * theirs.char_size;
           93 
           94         let our_total_size = Vec2::new(ours.char_width, ours.char_height) * ours.char_size;
           95 
           96         let tmax_y: f32 = theirs.font_height * (theirs.char_height - theirs.buffer_char_height).max(0.0);
           97         let tmax_x: f32 = theirs.font_width * (theirs.real_width as f32 - theirs.buffer_char_width).max(0.0);
           98 
           99         let size = our_total_size * their_buffer_size / their_total_size;
          100         let tx = theirs.char_scroll_position.x / tmax_x.max(1.0);
          101         let ty = theirs.char_scroll_position.y / tmax_y.max(1.0);
          102 
          103         let pos = (our_total_size - size - Vec2::new(1.0, 1.0)) * Vec2::new(tx, ty);
          104 
          105         let pos = pos - ours.char_scroll_position * ours.scale;
          106         let min = (ours.buffer_rect.min + pos).floor() + Vec2::new(0.5, 0.5);
          107 
          108         let corr = ours.buffer_rect.min.y + ours.terminal_rect.height() - (size.y + min.y);
          109         let view_size = Vec2::new(size.x, size.y + corr.min(0.0)).floor();
          110 
          111         ui.painter().rect_stroke(
          112             Rect::from_min_size(min, view_size),
          113             0.0,
          114             Stroke::new(1.0, Color32::from_rgba_premultiplied(157, 157, 157, 220)),
          115         );
          116 
          117         if pos.x < 0.0 || pos.y < 0.0 {
          118             self.next_scroll_pos = Some(ours.char_scroll_position + pos / ours.scale);
          119             ui.ctx().request_repaint();
          120         }
          121 
          122         if pos.x + size.x > ours.terminal_rect.size().x || pos.y + size.y > ours.terminal_rect.size().y {
          123             let p = pos + size - ours.terminal_rect.size();
          124             self.next_scroll_pos = Some(ours.char_scroll_position + p / ours.scale);
          125             ui.ctx().request_repaint();
          126         }
          127 
          128         if response.dragged() {
          129             if let Some(pos) = response.hover_pos() {
          130                 let pos = (pos - ours.buffer_rect.min) / ours.scale + ours.char_scroll_position;
          131                 editor.next_scroll_x_position = Some(pos.x - theirs.buffer_char_width * theirs.font_width / 2.0);
          132                 editor.next_scroll_y_position = Some(pos.y - theirs.buffer_char_height * theirs.font_height / 2.0);
          133                 ui.ctx().request_repaint();
          134             }
          135         }
          136 
          137         None
          138     }
          139 
          140     pub(crate) fn new(gl: Arc<glow::Context>) -> Self {
          141         let mut buffer_view = BufferView::new(&gl);
          142         buffer_view.interactive = false;
          143         buffer_view.get_buffer_mut().is_terminal_buffer = false;
          144         buffer_view.get_caret_mut().set_is_visible(false);
          145         Self {
          146             buffer_view: Arc::new(eframe::epaint::mutex::Mutex::new(buffer_view)),
          147             last_id: usize::MAX,
          148             undo_size: -1,
          149             palette_hash: 0,
          150             next_scroll_pos: None,
          151         }
          152     }
          153 }