URI: 
       Font manager is now safe to use. - 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
       ---
   DIR commit f57013ff5c782c14681c78d5b942ca4748c9f256
   DIR parent 5fadfe581516cd6559cf2b02f38356aebdb35785
  HTML Author: Mike Krüger <mkrueger@posteo.de>
       Date:   Wed, 27 Sep 2023 15:59:32 +0200
       
       Font manager is now safe to use.
       
       But still doesn't look good - but font story should now be functional.
       
       Diffstat:
         M i18n/de/icy_draw.ftl                |      10 ++++++++++
         M i18n/en/icy_draw.ftl                |       8 ++++++++
         M src/ui/dialogs/export_file_dialog/… |       3 ++-
         M src/ui/dialogs/font_manager.rs      |     403 ++++++++++++++++---------------
         M src/ui/editor/animation/mod.rs      |       6 ++++--
       
       5 files changed, 235 insertions(+), 195 deletions(-)
       ---
   DIR diff --git a/i18n/de/icy_draw.ftl b/i18n/de/icy_draw.ftl
       @@ -397,6 +397,16 @@ new-file-template-thedraw-ui-label=
        
            Eine große Font-Sammlung kann hier heruntergeladen werden:
        
       +manage-font-dialog-title=Bufferfonts bearbeiten
       +manage-font-used_font_label=Verwendete Fonts
       +manage-font-copy_font_button=Kopieren
       +manage-font-copy_font_button-tooltip=Kopiert den Font als CTerm ANSI Sequenz ins Clipboard. (Für BBS)
       +manage-font-remove_font_button=Entfernen
       +manage-font-used_label=verwendet
       +manage-font-not_used_label=nicht verwendet
       +manage-font-replace_label=Ersetze Font mit:
       +manage-font-replace_font_button=Ersetzen
       +
        palette_selector-dos_default_palette=VGA 16 Farben
        palette_selector-dos_default_low_palette=VGA 8 Farben
        palette_selector-c64_default_palette=C64 Farben
   DIR diff --git a/i18n/en/icy_draw.ftl b/i18n/en/icy_draw.ftl
       @@ -392,6 +392,14 @@ new-file-template-thedraw-ui-label=
            A big font archive can be downloaded from:
        
        manage-font-dialog-title=Manage Fonts
       +manage-font-used_font_label=Used Fonts
       +manage-font-copy_font_button=Copy Font
       +manage-font-copy_font_button-tooltip=Copies font as CTerm ANSI sequence to clipboard. (for BBS use)
       +manage-font-remove_font_button=Remove
       +manage-font-used_label=used
       +manage-font-not_used_label=not used
       +manage-font-replace_label=Replace usage with slot
       +manage-font-replace_font_button=Replace
        
        palette_selector-dos_default_palette=VGA 16 colors
        palette_selector-dos_default_low_palette=VGA 8 colors
   DIR diff --git a/src/ui/dialogs/export_file_dialog/mod.rs b/src/ui/dialogs/export_file_dialog/mod.rs
       @@ -183,7 +183,7 @@ impl ModalDialog for ExportFileDialog {
        
        type CreateSettingsFunction = fn(&mut Ui, &mut SaveOptions);
        
       -const TYPE_DESCRIPTIONS: [(&str, CreateSettingsFunction, &str); 10] = [
       +const TYPE_DESCRIPTIONS: [(&str, CreateSettingsFunction, &str); 11] = [
            ("Ansi (.ans)", ansi::create_settings_page, "ans"),
            ("Avatar (.avt)", avatar::create_settings_page, "avt"),
            ("PCBoard (.pcb)", pcboard::create_settings_page, "pcb"),
       @@ -197,5 +197,6 @@ const TYPE_DESCRIPTIONS: [(&str, CreateSettingsFunction, &str); 10] = [
            ),
            ("Bin (.bin)", bin::create_settings_page, "bin"),
            ("XBin (.xb)", xbin::create_settings_page, "xb"),
       +    ("CtrlA (.msg)", pcboard::create_settings_page, "msg"),
            ("PNG (.png)", png::create_settings_page, "png"),
        ];
   DIR diff --git a/src/ui/dialogs/font_manager.rs b/src/ui/dialogs/font_manager.rs
       @@ -1,34 +1,37 @@
       -use std::{path::Path, sync::Arc};
       +use std::sync::Arc;
        
       +use crate::{AnsiEditor, Message, TerminalResult};
        use eframe::{
       -    egui::{self, Button, Sense, SidePanel, TextStyle, WidgetText},
       +    egui::{self, Button, Sense, TextStyle, TopBottomPanel, WidgetText},
            epaint::{FontFamily, FontId, Rounding},
        };
        use egui_modal::Modal;
        use i18n_embed_fl::fl;
       -use icy_engine::{BitFont, TextPane};
       -use icy_engine_egui::BufferView;
       -
       -use crate::{AnsiEditor, Message, TerminalResult};
        
        pub struct FontManager {
            selected: usize,
            replace_with: usize,
            do_select: bool,
       -    replace_font_path: String,
            buffer_view: Arc<eframe::epaint::mutex::Mutex<icy_engine_egui::BufferView>>,
       +    used_fonts: Vec<usize>,
        }
        
        impl FontManager {
            pub fn new(editor: &AnsiEditor) -> Self {
       +        let used_fonts = icy_engine::analyze_font_usage(editor.buffer_view.lock().get_buffer());
                Self {
                    selected: 0,
                    do_select: false,
                    replace_with: 0,
       -            replace_font_path: String::new(),
                    buffer_view: editor.buffer_view.clone(),
       +            used_fonts,
                }
            }
       +
       +    fn update_used_fonts(&mut self) {
       +        let lock = &self.buffer_view.lock();
       +        self.used_fonts = icy_engine::analyze_font_usage(lock.get_buffer());
       +    }
        }
        
        impl crate::ModalDialog for FontManager {
       @@ -36,185 +39,184 @@ impl crate::ModalDialog for FontManager {
                let mut result = false;
                let modal = Modal::new(ctx, "manage_font_dialog");
                modal.show(|ui| {
       -            ui.set_height(420.);
       -            ui.set_width(800.);
       +            ui.set_height(320.);
       +            ui.set_width(600.);
        
                    modal.title(ui, fl!(crate::LANGUAGE_LOADER, "manage-font-dialog-title"));
                    modal.frame(ui, |ui| {
       -                SidePanel::left("new_file_side_panel")
       -                    .exact_width(280.0)
       -                    .resizable(false)
       -                    .show_inside(ui, |ui| {
       -                        let row_height = 24.0;
       -                        ui.label("Used fonts");
       -                        egui::ScrollArea::vertical()
       -                            .id_source("bitfont_scroll_area")
       -                            .show(ui, |ui| {
       -                                for (i, font) in self.buffer_view.lock().get_buffer().font_iter() {
       -                                    let is_selected = *i == self.selected;
       -
       -                                    let (id, rect) = ui
       -                                        .allocate_space([ui.available_width(), row_height].into());
       -                                    let response = ui.interact(rect, id, Sense::click());
       -                                    if response.hovered() {
       -                                        ui.painter().rect_filled(
       -                                            rect.expand(1.0),
       -                                            Rounding::same(4.0),
       -                                            ui.style().visuals.widgets.active.bg_fill,
       -                                        );
       -                                    } else if is_selected {
       -                                        ui.painter().rect_filled(
       -                                            rect.expand(1.0),
       -                                            Rounding::same(4.0),
       -                                            ui.style().visuals.extreme_bg_color,
       -                                        );
       -                                    }
       +                egui::CentralPanel::default().show_inside(ui, |ui| {
       +                    let row_height = 24.0;
       +                    ui.label(fl!(crate::LANGUAGE_LOADER, "manage-font-used_font_label"));
       +                    egui::ScrollArea::vertical()
       +                        .id_source("bitfont_scroll_area")
       +                        .show(ui, |ui| {
       +                            for (i, font) in self.buffer_view.lock().get_buffer().font_iter() {
       +                                let is_selected = *i == self.selected;
        
       -                                    let font_id = FontId::new(12.0, FontFamily::Monospace);
       -                                    let text: WidgetText = format!("{i:-3}.").into();
       -                                    let galley = text.into_galley(
       -                                        ui,
       -                                        Some(false),
       -                                        f32::INFINITY,
       -                                        font_id.clone(),
       +                                let (id, rect) =
       +                                    ui.allocate_space([ui.available_width(), row_height].into());
       +                                let response = ui.interact(rect, id, Sense::click());
       +                                if response.hovered() {
       +                                    ui.painter().rect_filled(
       +                                        rect.expand(1.0),
       +                                        Rounding::same(4.0),
       +                                        ui.style().visuals.widgets.active.bg_fill,
                                            );
       -                                    let size = galley.size();
       -                                    let mut title_rect = rect;
       -                                    title_rect.set_left(title_rect.left() + 4.0);
       -                                    title_rect.set_top(title_rect.bottom() - size.y - 8.0);
       -                                    let text_color = if is_selected {
       -                                        ui.style().visuals.strong_text_color()
       -                                    } else {
       -                                        ui.style().visuals.text_color()
       -                                    };
       -                                    ui.painter().galley_with_color(
       -                                        egui::Align2::LEFT_TOP
       -                                            .align_size_within_rect(
       -                                                galley.size(),
       -                                                title_rect.shrink(4.0),
       -                                            )
       -                                            .min,
       -                                        galley.galley,
       -                                        text_color,
       +                                } else if is_selected {
       +                                    ui.painter().rect_filled(
       +                                        rect.expand(1.0),
       +                                        Rounding::same(4.0),
       +                                        ui.style().visuals.extreme_bg_color,
                                            );
       +                                }
        
       -                                    let font_id = TextStyle::Button.resolve(ui.style());
       -                                    let text: WidgetText = font.name.clone().into();
       -                                    let galley =
       -                                        text.into_galley(ui, Some(false), f32::INFINITY, font_id);
       -                                    let mut title_rect = rect;
       -                                    title_rect.set_left(title_rect.left() + 4.0 + size.x + 4.0);
       -                                    ui.painter().galley_with_color(
       -                                        egui::Align2::LEFT_TOP
       -                                            .align_size_within_rect(
       -                                                galley.size(),
       -                                                title_rect.shrink(4.0),
       -                                            )
       -                                            .min,
       -                                        galley.galley,
       -                                        text_color,
       -                                    );
       +                                let font_id = FontId::new(12.0, FontFamily::Monospace);
       +                                let text: WidgetText = format!("{i:-3}.").into();
       +                                let galley = text.into_galley(
       +                                    ui,
       +                                    Some(false),
       +                                    f32::INFINITY,
       +                                    font_id.clone(),
       +                                );
       +                                let size = galley.size();
       +                                let mut title_rect = rect;
       +                                title_rect.set_left(title_rect.left() + 4.0);
       +                                title_rect.set_top(title_rect.bottom() - size.y - 8.0);
       +                                let text_color = if is_selected {
       +                                    ui.style().visuals.strong_text_color()
       +                                } else {
       +                                    ui.style().visuals.text_color()
       +                                };
       +                                ui.painter().galley_with_color(
       +                                    egui::Align2::LEFT_TOP
       +                                        .align_size_within_rect(
       +                                            galley.size(),
       +                                            title_rect.shrink(4.0),
       +                                        )
       +                                        .min,
       +                                    galley.galley,
       +                                    text_color,
       +                                );
       +
       +                                let font_id = TextStyle::Button.resolve(ui.style());
       +                                let text: WidgetText = font.name.clone().into();
       +                                let galley =
       +                                    text.into_galley(ui, Some(false), f32::INFINITY, font_id);
       +                                let mut title_rect = rect;
       +                                title_rect.set_left(title_rect.left() + 4.0 + size.x + 4.0);
       +                                ui.painter().galley_with_color(
       +                                    egui::Align2::LEFT_TOP
       +                                        .align_size_within_rect(
       +                                            galley.size(),
       +                                            title_rect.shrink(4.0),
       +                                        )
       +                                        .min,
       +                                    galley.galley,
       +                                    text_color,
       +                                );
       +
       +                                let font_id = TextStyle::Button.resolve(ui.style());
       +                                let text: WidgetText =
       +                                    format!("{}x{}", font.size.width, font.size.height).into();
       +                                let galley =
       +                                    text.into_galley(ui, Some(false), f32::INFINITY, font_id);
       +                                let mut title_rect = rect;
       +                                title_rect.set_left(title_rect.left() + 399.0);
       +                                ui.painter().galley_with_color(
       +                                    egui::Align2::LEFT_TOP
       +                                        .align_size_within_rect(
       +                                            galley.size(),
       +                                            title_rect.shrink(4.0),
       +                                        )
       +                                        .min,
       +                                    galley.galley,
       +                                    text_color,
       +                                );
        
       -                                    if response.clicked() {
       -                                        self.selected = *i;
       -                                    }
       +                                let font_id = TextStyle::Button.resolve(ui.style());
       +                                let text: WidgetText = if self.used_fonts.contains(i) {
       +                                    fl!(crate::LANGUAGE_LOADER, "manage-font-used_label")
       +                                } else {
       +                                    fl!(crate::LANGUAGE_LOADER, "manage-font-not_used_label")
                                        }
       -                            });
       -                    });
       +                                .into();
       +                                let galley =
       +                                    text.into_galley(ui, Some(false), f32::INFINITY, font_id);
       +                                let mut title_rect = rect;
       +                                title_rect.set_left(title_rect.left() + 480.0);
       +                                ui.painter().galley_with_color(
       +                                    egui::Align2::LEFT_TOP
       +                                        .align_size_within_rect(
       +                                            galley.size(),
       +                                            title_rect.shrink(4.0),
       +                                        )
       +                                        .min,
       +                                    galley.galley,
       +                                    text_color,
       +                                );
        
       -                egui::CentralPanel::default().show_inside(ui, |ui| {
       -                    {
       -                        let lock = &self.buffer_view.lock();
       -                        if let Some(font) = lock.get_buffer().get_font(self.selected) {
       -                            ui.label(format!("Using slot {}", self.selected));
       -                            ui.label(format!("Size {}x{}", font.size.width, font.size.height));
       -                            let fonts = icy_engine::analyze_font_usage(lock.get_buffer());
       -                            if fonts.contains(&self.selected) {
       -                                ui.label("Font used.");
       -                            } else {
       -                                ui.label("No font usage.");
       +                                if response.clicked() {
       +                                    self.selected = *i;
       +                                }
                                    }
       -                        }
       -                    }
       -                    ui.horizontal(|ui| {
       -                        ui.label("Replace usage with slot:");
       -                        let mut tmp_str = self.replace_with.to_string();
       -                        ui.add(
       -                            egui::TextEdit::singleline(&mut tmp_str)
       -                                .desired_width(80.0)
       -                                .char_limit(4),
       -                        );
       -                        if let Ok(new_width) = tmp_str.parse::<usize>() {
       -                            self.replace_with = new_width;
       -                        } else {
       -                            self.replace_with = 0;
       -                        }
       -                        let enabled = self
       -                            .buffer_view
       -                            .lock()
       -                            .get_buffer()
       -                            .get_font(self.replace_with)
       -                            .is_some();
       -                        if ui.add_enabled(enabled, Button::new("Replace")).clicked() {
       -                            replace_font_usage(
       -                                &mut self.buffer_view.lock(),
       -                                self.selected,
       -                                self.replace_with,
       -                            );
       -                            self.selected = 0;
       -                            self.replace_with = 0;
       -                            self.do_select = true;
       -                        }
       -                    });
       +                        });
       +                });
       +                TopBottomPanel::bottom("font_manager_bottom_panel")
       +                    .exact_height(24.0)
       +                    .resizable(false)
       +                    .show_inside(ui, |ui| {
       +                        ui.add_space(8.0);
        
       -                    ui.horizontal(|ui| {
       -                        ui.label("Load new font file for slot:");
       -                        ui.add(
       -                            egui::TextEdit::singleline(&mut self.replace_font_path)
       -                                .desired_width(200.0),
       -                        );
       -                        let enabled = Path::new(&self.replace_font_path).exists();
       -                        if ui.add_enabled(enabled, Button::new("Load")).clicked() {
       -                            match BitFont::load(Path::new(&self.replace_font_path)) {
       -                                Ok(font) => {
       -                                    self.buffer_view
       -                                        .lock()
       -                                        .get_buffer_mut()
       -                                        .set_font(self.selected, font);
       -                                }
       -                                Err(err) => {
       -                                    log::error!("{err}");
       +                        ui.horizontal(|ui| {
       +                            ui.label(fl!(crate::LANGUAGE_LOADER, "manage-font-replace_label"));
       +                            let mut tmp_str = self.replace_with.to_string();
       +                            ui.add(
       +                                egui::TextEdit::singleline(&mut tmp_str)
       +                                    .desired_width(80.0)
       +                                    .char_limit(4),
       +                            );
       +                            if let Ok(new_width) = tmp_str.parse::<usize>() {
       +                                self.replace_with = new_width;
       +                            } else {
       +                                self.replace_with = 0;
       +                            }
       +                            let enabled = self
       +                                .buffer_view
       +                                .lock()
       +                                .get_buffer()
       +                                .get_font(self.replace_with)
       +                                .is_some();
       +                            if ui
       +                                .add_enabled(
       +                                    enabled,
       +                                    Button::new(fl!(
       +                                        crate::LANGUAGE_LOADER,
       +                                        "manage-font-replace_font_button"
       +                                    )),
       +                                )
       +                                .clicked()
       +                            {
       +                                if let Err(err) = self
       +                                    .buffer_view
       +                                    .lock()
       +                                    .get_edit_state_mut()
       +                                    .replace_font_usage(self.selected, self.replace_with)
       +                                {
       +                                    log::error!(
       +                                        "Error replacing font {}->{}: {err}",
       +                                        self.selected,
       +                                        self.replace_with
       +                                    );
                                        }
       +                                self.update_used_fonts();
       +                                self.selected = 0;
       +                                self.replace_with = 0;
       +                                self.do_select = true;
                                    }
       -                        }
       +                        });
                            });
       -
       -                    if ui
       -                        .add_enabled(self.selected > 0, Button::new("Remove"))
       -                        .clicked()
       -                    {
       -                        replace_font_usage(&mut self.buffer_view.lock(), self.selected, 0);
       -                        self.buffer_view
       -                            .lock()
       -                            .get_buffer_mut()
       -                            .remove_font(self.selected);
       -                        self.selected = 0;
       -                        self.replace_with = 0;
       -                        self.do_select = true;
       -                    }
       -
       -                    if ui
       -                        .add_enabled(self.selected > 0, Button::new("Copy Font as Ansi"))
       -                        .clicked()
       -                    {
       -                        let lock = &self.buffer_view.lock();
       -                        if let Some(font) = lock.get_buffer().get_font(self.selected) {
       -                            ui.output_mut(|o| o.copied_text = font.encode_as_ansi(self.selected));
       -                        }
       -                    }
       -                });
                    });
       -
       +            ui.add_space(8.0);
                    modal.buttons(ui, |ui| {
                        if ui
                            .button(fl!(crate::LANGUAGE_LOADER, "new-file-ok"))
       @@ -222,6 +224,44 @@ impl crate::ModalDialog for FontManager {
                        {
                            result = true;
                        }
       +
       +                let copy_font_button = ui.add(Button::new(fl!(
       +                    crate::LANGUAGE_LOADER,
       +                    "manage-font-copy_font_button"
       +                )));
       +                let copy_font_button = copy_font_button.on_hover_ui(|ui| {
       +                    ui.label(fl!(
       +                        crate::LANGUAGE_LOADER,
       +                        "manage-font-copy_font_button-tooltip"
       +                    ));
       +                });
       +
       +                if copy_font_button.clicked() {
       +                    let lock = &self.buffer_view.lock();
       +                    if let Some(font) = lock.get_buffer().get_font(self.selected) {
       +                        ui.output_mut(|o| o.copied_text = font.encode_as_ansi(self.selected));
       +                    }
       +                }
       +                let remove_font_button = &ui.add_enabled(
       +                    self.selected > 0,
       +                    Button::new(fl!(
       +                        crate::LANGUAGE_LOADER,
       +                        "manage-font-remove_font_button"
       +                    )),
       +                );
       +                if remove_font_button.clicked() {
       +                    if let Err(err) = self
       +                        .buffer_view
       +                        .lock()
       +                        .get_edit_state_mut()
       +                        .remove_font(self.selected)
       +                    {
       +                        log::error!("Error removing font {}: {err}", self.selected);
       +                    }
       +                    self.update_used_fonts();
       +                    self.replace_with = 0;
       +                    self.do_select = true;
       +                }
                    });
                });
                modal.open();
       @@ -236,24 +276,3 @@ impl crate::ModalDialog for FontManager {
                Ok(None)
            }
        }
       -
       -fn replace_font_usage(buffer_view: &mut BufferView, from: usize, to: usize) {
       -    if buffer_view.get_caret().get_font_page() == from {
       -        buffer_view.get_caret_mut().set_font_page(to);
       -    }
       -    for layer in &mut buffer_view.get_buffer_mut().layers {
       -        if layer.default_font_page == from {
       -            layer.default_font_page = to;
       -        }
       -        for y in 0..layer.get_height() {
       -            for x in 0..layer.get_width() {
       -                let mut ch = layer.get_char((x, y));
       -                if ch.attribute.get_font_page() == from {
       -                    ch.attribute.set_font_page(to);
       -                    layer.set_char((x, y), ch);
       -                    assert!(layer.get_char((x, y)).get_font_page() == to);
       -                }
       -            }
       -        }
       -    }
       -}
   DIR diff --git a/src/ui/editor/animation/mod.rs b/src/ui/editor/animation/mod.rs
       @@ -425,9 +425,11 @@ impl Document for AnimationEditor {
                                        let frames = animator.lock().unwrap().frames.len();
                                        if cur_frame < frames {
                                            animator.lock().unwrap().set_cur_frame(cur_frame);
       -                                } 
       +                                }
                                        self.animator = Some(animator);
       -                                self.animator.as_ref().unwrap()
       +                                self.animator
       +                                    .as_ref()
       +                                    .unwrap()
                                            .lock()
                                            .unwrap()
                                            .display_frame(self.buffer_view.clone());