char_table.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
       ---
       char_table.rs (9417B)
       ---
            1 use std::sync::Arc;
            2 
            3 use eframe::{
            4     egui::{self, RichText, Sense},
            5     epaint::{Color32, FontId, Pos2, Rect, Vec2},
            6 };
            7 use egui::{load::SizedTexture, mutex::Mutex, Context, Image, TextureHandle};
            8 use i18n_embed_fl::fl;
            9 use icy_engine::{AttributedChar, BitFont, Buffer, TextAttribute};
           10 
           11 use crate::{create_image, AnsiEditor, Document, Message, ToolWindow};
           12 
           13 pub struct CharTableToolWindow {
           14     font: BitFont,
           15     hover_char: Option<char>,
           16     hover_char_image: TextureHandle,
           17     char_table: TextureHandle,
           18     buffer_width: usize,
           19 }
           20 
           21 impl CharTableToolWindow {
           22     pub fn new(ctx: &Context, buffer_width: usize) -> Self {
           23         let font = BitFont::default();
           24         let char_table = create_font_image(ctx, &font, buffer_width, TextAttribute::default(), TextAttribute::default(), 0);
           25         let hover_char_image = create_hover_image(ctx, &font, ' ', 14);
           26         Self {
           27             font,
           28             char_table,
           29             hover_char: None,
           30             hover_char_image,
           31             buffer_width,
           32         }
           33     }
           34 
           35     pub fn get_font(&self) -> &BitFont {
           36         &self.font
           37     }
           38 
           39     pub fn set_font(&mut self, ctx: &Context, font: BitFont) {
           40         self.font = font;
           41         self.char_table = create_font_image(ctx, &self.font, self.buffer_width, TextAttribute::default(), TextAttribute::default(), 0);
           42         self.hover_char = None;
           43     }
           44 
           45     pub fn show_plain_char_table(&mut self, ui: &mut egui::Ui) -> Option<char> {
           46         let mut something_hovered = false;
           47         let mut result = None;
           48         egui::ScrollArea::vertical().id_source("char_table_scroll_area").show(ui, |ui| {
           49             ui.add_space(4.0);
           50             ui.horizontal(|ui| {
           51                 let scale = 2.0;
           52                 let sized_texture: SizedTexture = (&self.char_table).into();
           53                 let width = sized_texture.size.x * scale;
           54                 let height = sized_texture.size.y * scale;
           55                 ui.add_space((ui.available_width() - width) / 2.0);
           56 
           57                 let (id, rect) = ui.allocate_space([width, height].into());
           58                 let response = ui.interact(rect, id, Sense::click());
           59                 let r = Rect::from_min_size(Pos2::new(rect.left(), rect.top()), Vec2::new(width, height));
           60                 let image = Image::from_texture(sized_texture);
           61 
           62                 image.paint_at(ui, r);
           63 
           64                 let fw = scale * self.font.size.width as f32;
           65                 let fh = scale * self.font.size.height as f32;
           66                 if response.clicked() {
           67                     result = self.hover_char;
           68                 }
           69                 if response.hovered() {
           70                     if let Some(pos) = response.hover_pos() {
           71                         something_hovered = true;
           72                         let pos = pos - response.rect.min;
           73                         let ch = (pos.x / fw) as usize + self.buffer_width * (pos.y / fh) as usize;
           74                         let ch = unsafe { char::from_u32_unchecked(ch as u32) };
           75                         let hover_char = Some(ch);
           76                         if self.hover_char != hover_char {
           77                             self.hover_char = hover_char;
           78                             self.hover_char_image = create_hover_image(ui.ctx(), &self.font, ch, 14);
           79                         }
           80 
           81                         let x = (ch as usize) % self.buffer_width;
           82                         let y = (ch as usize) / self.buffer_width;
           83 
           84                         let rect = Rect::from_min_size(rect.min + Vec2::new(x as f32 * fw, y as f32 * fh), Vec2::new(fw, fh));
           85                         let sized_texture: SizedTexture = (&self.hover_char_image).into();
           86                         let image = Image::from_texture(sized_texture);
           87                         image.paint_at(ui, rect.expand(2.0));
           88                     }
           89                 }
           90             });
           91         });
           92         ui.horizontal(|ui| {
           93             ui.add_space(4.0);
           94             ui.label(RichText::new(fl!(crate::LANGUAGE_LOADER, "font-view-font_label")).small());
           95             ui.label(RichText::new(self.font.name.to_string()).small().color(Color32::WHITE));
           96         });
           97 
           98         if let Some(ch) = self.hover_char {
           99             ui.horizontal(|ui| {
          100                 ui.add_space(4.0);
          101                 ui.label(RichText::new(fl!(crate::LANGUAGE_LOADER, "font-view-char_label")).small());
          102                 ui.label(RichText::new(format!("{0}/0x{0:02X}", ch as u32)).small().color(Color32::WHITE));
          103             });
          104         } else {
          105             ui.horizontal(|ui| {
          106                 ui.label("   ");
          107             });
          108             ui.horizontal(|ui| {
          109                 ui.label("   ");
          110             });
          111         }
          112         if !something_hovered {
          113             self.hover_char = None;
          114         }
          115         result
          116     }
          117 
          118     pub fn show_char_table(&mut self, ui: &mut egui::Ui, editor: &AnsiEditor) -> Option<Message> {
          119         let mut result = None;
          120 
          121         let font_page = editor.buffer_view.lock().get_caret().get_font_page();
          122         let font_count = editor.buffer_view.lock().get_buffer().font_count();
          123         if let Some(cur_font) = editor.buffer_view.lock().get_buffer().get_font(font_page) {
          124             if cur_font.name != self.font.name {
          125                 self.font = cur_font.clone();
          126                 self.char_table = create_font_image(ui.ctx(), &self.font, self.buffer_width, TextAttribute::default(), TextAttribute::default(), 0);
          127                 self.hover_char = None;
          128             }
          129         }
          130 
          131         if font_count > 1 {
          132             ui.add_space(8.0);
          133 
          134             ui.horizontal(|ui| {
          135                 ui.add_space(12.0);
          136 
          137                 ui.label(fl!(crate::LANGUAGE_LOADER, "font-view-font_page_label"));
          138                 if ui.selectable_label(false, RichText::new("◀").font(FontId::proportional(14.))).clicked() {
          139                     let mut prev = font_page;
          140                     let mut last = 0;
          141                     for (page, _) in editor.buffer_view.lock().get_buffer().font_iter() {
          142                         last = last.max(*page);
          143                         if *page < font_page {
          144                             if prev == font_page {
          145                                 prev = *page;
          146                             } else {
          147                                 prev = prev.max(*page);
          148                             }
          149                         }
          150                     }
          151                     if prev == font_page {
          152                         result = Some(Message::SetFontPage(last));
          153                     } else {
          154                         result = Some(Message::SetFontPage(prev));
          155                     }
          156                 }
          157                 ui.label(RichText::new(font_page.to_string()));
          158 
          159                 if ui.selectable_label(false, RichText::new("▶").font(FontId::proportional(14.))).clicked() {
          160                     let mut next = font_page;
          161                     let mut first = usize::MAX;
          162                     for (page, _) in editor.buffer_view.lock().get_buffer().font_iter() {
          163                         first = first.min(*page);
          164                         if *page > font_page {
          165                             if next == font_page {
          166                                 next = *page;
          167                             } else {
          168                                 next = next.min(*page);
          169                             }
          170                         }
          171                     }
          172                     if next == font_page {
          173                         result = Some(Message::SetFontPage(first));
          174                     } else {
          175                         result = Some(Message::SetFontPage(next));
          176                     }
          177                 }
          178             });
          179         }
          180 
          181         let response = self.show_plain_char_table(ui);
          182 
          183         if let Some(ch) = response {
          184             result = Some(Message::CharTable(ch));
          185         }
          186 
          187         result
          188     }
          189 }
          190 
          191 pub fn create_font_image(
          192     ctx: &Context,
          193     font: &BitFont,
          194     buffer_width: usize,
          195     attribute: TextAttribute,
          196     selected_attribute: TextAttribute,
          197     selected: usize,
          198 ) -> TextureHandle {
          199     let mut buffer = Buffer::new((buffer_width, (font.length as usize) / buffer_width));
          200     buffer.set_font(0, font.clone());
          201     for ch in 0..font.length as usize {
          202         buffer.layers[0].set_char(
          203             (ch % buffer_width, ch / buffer_width),
          204             AttributedChar::new(
          205                 unsafe { char::from_u32_unchecked(ch as u32) },
          206                 if ch == selected { selected_attribute } else { attribute },
          207             ),
          208         );
          209     }
          210     create_image(ctx, &buffer)
          211 }
          212 
          213 pub fn create_hover_image(ctx: &Context, font: &BitFont, ch: char, color: u32) -> TextureHandle {
          214     let mut buffer = Buffer::new((1, 1));
          215     buffer.set_font(0, font.clone());
          216     let mut attr = TextAttribute::default();
          217     attr.set_foreground(color);
          218 
          219     buffer.layers[0].set_char((0, 0), AttributedChar::new(unsafe { char::from_u32_unchecked(ch as u32) }, attr));
          220     create_image(ctx, &buffer)
          221 }
          222 
          223 impl ToolWindow for CharTableToolWindow {
          224     fn get_title(&self) -> String {
          225         fl!(crate::LANGUAGE_LOADER, "char_table_tool_title")
          226     }
          227 
          228     fn show_ui(&mut self, ui: &mut egui::Ui, active_document: Option<Arc<Mutex<Box<dyn Document>>>>) -> Option<Message> {
          229         if let Some(doc) = active_document {
          230             if let Some(editor) = doc.lock().get_ansi_editor() {
          231                 return self.show_char_table(ui, editor);
          232             }
          233         }
          234         ui.vertical_centered(|ui| {
          235             ui.add_space(8.0);
          236             ui.label(RichText::new(fl!(crate::LANGUAGE_LOADER, "no_document_selected")).small());
          237         });
          238         None
          239     }
          240 }