Added more file templates. - 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
       ---
 (DIR) commit e4e1ef3699f34b4c4859e97124ff45b3f9f08107
 (DIR) parent b8dd4eecf3a4e022b9466d2162ce2fc5bb8f0aad
 (HTM) Author: Mike Krüger <mkrueger@posteo.de>
       Date:   Thu, 21 Sep 2023 08:45:10 +0200
       
       Added more file templates.
       
       Charset view now shows the current font.
       
       Diffstat:
         M i18n/de/icy_draw.ftl                |      19 +++++++++++++++----
         M i18n/en/icy_draw.ftl                |      20 ++++++++++++++++----
         M src/ui/dialogs/font_selector.rs     |      26 ++++++++++++--------------
         M src/ui/dialogs/new_file_dialog.rs   |     285 ++++++++++++++++++++++++++-----
         M src/ui/document_docking.rs          |       9 +++++++++
         M src/ui/editor/charfont/mod.rs       |       2 +-
         M src/ui/main_window.rs               |      36 ++++++++++++++++++++++++++-----
         M src/ui/palette_editor.rs            |      11 +++++++----
         M src/ui/top_bar.rs                   |     203 +++++++++++++++++++++++--------
       
       9 files changed, 483 insertions(+), 128 deletions(-)
       ---
 (DIR) diff --git a/i18n/de/icy_draw.ftl b/i18n/de/icy_draw.ftl
       @@ -65,10 +65,16 @@ menu-select_nothing=Nichts
        menu-inverse_selection=Invertieren
        
        menu-colors=Farben
       -menu-color-mode=Farbmodus
       -menu-color-mode-unrestricted=Unbegrenzt
       -menu-color-mode-dos=16 Farben, blink
       -menu-color-mode-ice=16 Farben, ice
       +menu-ice-mode=Ice-Modus
       +menu-ice-mode-unrestricted=Unbegrenzt
       +menu-ice-mode-blink=Blinken
       +menu-ice-mode-ice=Ice
       +menu-palette-mode=Palette
       +menu-palette-mode-unrestricted=Unbegrenzt
       +menu-palette-mode-dos=Dos 16
       +menu-palette-mode-free=Frei 16
       +menu-palette-mode-free8=Frei 8
       +
        menu-color-mode-ext-colors=256 Farben
        menu-color-mode-ext-font=16 Farben, ext font, blink
        menu-color-mode-ext-font-ice=16 Farben, ext font, ice
       @@ -100,6 +106,11 @@ menu-default_color=Standardfarbe
        menu-toggle_color=Farbe umschalten
        
        menu-fonts=Fonts
       +menu-font-mode=Font Modus
       +menu-font-mode-unrestricted=Unbegrenzt
       +menu-font-mode-sauce=Sauce
       +menu-font-mode-single=Einer
       +menu-font-mode-dual=Zwei
        menu-open_font_selector=Schriften…
        menu-open_font_manager=Bufferfonts bearbeiten…
        menu-open_font_directoy=Fontverzeichnis öffnen…
 (DIR) diff --git a/i18n/en/icy_draw.ftl b/i18n/en/icy_draw.ftl
       @@ -65,10 +65,16 @@ menu-select_nothing=Deselect
        menu-inverse_selection=Inverse
        
        menu-colors=Colors
       -menu-color-mode=Color Mode
       -menu-color-mode-unrestricted=Unrestricted
       -menu-color-mode-dos=16 Colors, blink
       -menu-color-mode-ice=16 Colors, ice
       +menu-ice-mode=Ice Mode
       +menu-ice-mode-unrestricted=Unrestricted
       +menu-ice-mode-blink=Blink
       +menu-ice-mode-ice=Ice
       +menu-palette-mode=Palette Mode
       +menu-palette-mode-unrestricted=Unrestricted
       +menu-palette-mode-dos=Dos 16
       +menu-palette-mode-free=Free 16
       +menu-palette-mode-free8=Free 8
       +
        menu-select_palette=Select Palette
        menu-next_fg_color=Next Foreground Color
        menu-next_bg_color=Next Background Color
       @@ -95,6 +101,12 @@ menu-pick_attribute_under_caret=Pick up Attribute
        menu-default_color=Default Color
        menu-toggle_color=Switch Foreground/Background
        menu-fonts=Fonts
       +menu-font-mode=Font Mode
       +menu-font-mode-unrestricted=Unrestricted
       +menu-font-mode-sauce=Sauce
       +menu-font-mode-single=Single
       +menu-font-mode-dual=Dual
       +
        menu-open_font_selector=Fonts…
        menu-open_font_manager=Edit Buffer Fonts…
        menu-open_font_directoy=Open Font Directory…
 (DIR) diff --git a/src/ui/dialogs/font_selector.rs b/src/ui/dialogs/font_selector.rs
       @@ -10,7 +10,9 @@ use i18n_embed_fl::fl;
        use icy_engine::{AttributedChar, BitFont, Buffer, TextAttribute, ANSI_FONTS};
        use walkdir::WalkDir;
        
       -use crate::{create_retained_image, AnsiEditor, Message, Settings, TerminalResult};
       +use crate::{
       +    create_retained_image, is_font_extensions, AnsiEditor, Message, Settings, TerminalResult,
       +};
        
        enum BitfontSource {
            BuiltIn(usize),
       @@ -106,9 +108,9 @@ impl FontSelector {
                    if extension.is_none() {
                        continue;
                    }
       -            let ext = extension.unwrap().to_lowercase();
       +            let ext = extension.unwrap().to_lowercase().to_string();
        
       -            if "psf" == ext || "f16" == ext || "f14" == ext || "f8" == ext || "fon" == ext {
       +            if is_font_extensions(&ext) {
                        if let Ok(font) = BitFont::load(path) {
                            fonts.push(font);
                        }
       @@ -138,20 +140,16 @@ impl FontSelector {
                        for i in 0..archive.len() {
                            match archive.by_index(i) {
                                Ok(mut file) => {
       -                            if let Some(name) = file.enclosed_name() {
       -                                let name = name.to_string_lossy().to_ascii_lowercase();
       -                                if name.ends_with(".psf")
       -                                    || name.ends_with(".f16")
       -                                    || name.ends_with(".f14")
       -                                    || name.ends_with(".f8")
       -                                    || name.ends_with(".fon")
       -                                {
       +                            if let Some(path) = file.enclosed_name() {
       +                                let file_name = path.to_string_lossy().to_string();
       +                                let ext = path.extension().unwrap().to_str().unwrap();
       +                                if is_font_extensions(&ext.to_ascii_lowercase()) {
                                            let mut data = Vec::new();
                                            file.read_to_end(&mut data).unwrap_or_default();
       -                                    if let Ok(font) = BitFont::from_bytes(name, &data) {
       -                                        fonts.push(font);
       +                                    if let Ok(font) = BitFont::from_bytes(file_name, &data) {
       +                                        fonts.push(font)
                                            }
       -                                } else if name.ends_with(".zip") {
       +                                } else if ext == "zip" {
                                            let mut data = Vec::new();
                                            file.read_to_end(&mut data).unwrap_or_default();
                                            FontSelector::read_zip_archive(data, fonts);
 (DIR) diff --git a/src/ui/dialogs/new_file_dialog.rs b/src/ui/dialogs/new_file_dialog.rs
       @@ -29,11 +29,157 @@ pub struct NewFileDialog {
            templates: Vec<Box<dyn Template>>,
        }
        
       -struct AnsiTemplate {
       +struct Dos16Template {
            pub width: i32,
            pub height: i32,
       +}
       +
       +impl Template for Dos16Template {
       +    fn image(&self) -> &RetainedImage {
       +        &crate::ANSI_TEMPLATE_IMG
       +    }
       +
       +    fn title(&self) -> String {
       +        fl!(crate::LANGUAGE_LOADER, "new-file-template-cp437-title")
       +    }
       +
       +    fn description(&self) -> String {
       +        fl!(
       +            crate::LANGUAGE_LOADER,
       +            "new-file-template-cp437-description"
       +        )
       +    }
       +
       +    fn show_ui(&mut self, ui: &mut Ui) {
       +        show_file_ui(ui, &mut self.width, &mut self.height);
       +    }
       +
       +    fn create_file(&self, window: &mut MainWindow) -> crate::TerminalResult<Option<Message>> {
       +        let mut buf = Buffer::create((self.width, self.height));
       +        buf.ice_mode = icy_engine::IceMode::Blink;
       +        buf.palette_mode = icy_engine::PaletteMode::Fixed16;
       +        buf.font_mode = icy_engine::FontMode::Sauce;
       +
       +        let id = window.create_id();
       +        let editor = AnsiEditor::new(&window.gl, id, buf);
       +        add_child(&mut window.document_tree, None, Box::new(editor));
       +        Ok(None)
       +    }
       +}
        
       -    pub file_id: bool,
       +struct Ice16Template {
       +    pub width: i32,
       +    pub height: i32,
       +}
       +
       +impl Template for Ice16Template {
       +    fn image(&self) -> &RetainedImage {
       +        &crate::ANSI_TEMPLATE_IMG
       +    }
       +
       +    fn title(&self) -> String {
       +        fl!(crate::LANGUAGE_LOADER, "new-file-template-ice-title")
       +    }
       +
       +    fn description(&self) -> String {
       +        fl!(crate::LANGUAGE_LOADER, "new-file-template-ice-description")
       +    }
       +
       +    fn show_ui(&mut self, ui: &mut Ui) {
       +        show_file_ui(ui, &mut self.width, &mut self.height);
       +    }
       +
       +    fn create_file(&self, window: &mut MainWindow) -> crate::TerminalResult<Option<Message>> {
       +        let mut buf = Buffer::create((self.width, self.height));
       +        buf.ice_mode = icy_engine::IceMode::Ice;
       +        buf.palette_mode = icy_engine::PaletteMode::Fixed16;
       +        buf.font_mode = icy_engine::FontMode::Sauce;
       +
       +        let id = window.create_id();
       +        let editor = AnsiEditor::new(&window.gl, id, buf);
       +        add_child(&mut window.document_tree, None, Box::new(editor));
       +        Ok(None)
       +    }
       +}
       +
       +struct XB16Template {
       +    pub width: i32,
       +    pub height: i32,
       +}
       +
       +impl Template for XB16Template {
       +    fn image(&self) -> &RetainedImage {
       +        &crate::ANSI_TEMPLATE_IMG
       +    }
       +
       +    fn title(&self) -> String {
       +        fl!(crate::LANGUAGE_LOADER, "new-file-template-xb-title")
       +    }
       +
       +    fn description(&self) -> String {
       +        fl!(crate::LANGUAGE_LOADER, "new-file-template-xb-description")
       +    }
       +
       +    fn show_ui(&mut self, ui: &mut Ui) {
       +        show_file_ui(ui, &mut self.width, &mut self.height);
       +    }
       +
       +    fn create_file(&self, window: &mut MainWindow) -> crate::TerminalResult<Option<Message>> {
       +        let mut buf = Buffer::create((self.width, self.height));
       +        buf.ice_mode = icy_engine::IceMode::Ice;
       +        buf.palette_mode = icy_engine::PaletteMode::Free16;
       +        buf.font_mode = icy_engine::FontMode::Single;
       +
       +        let id = window.create_id();
       +        let editor = AnsiEditor::new(&window.gl, id, buf);
       +        add_child(&mut window.document_tree, None, Box::new(editor));
       +        Ok(None)
       +    }
       +}
       +
       +struct XBExtTemplate {
       +    pub width: i32,
       +    pub height: i32,
       +}
       +
       +impl Template for XBExtTemplate {
       +    fn image(&self) -> &RetainedImage {
       +        &crate::ANSI_TEMPLATE_IMG
       +    }
       +
       +    fn title(&self) -> String {
       +        fl!(crate::LANGUAGE_LOADER, "new-file-template-xb-ext-title")
       +    }
       +
       +    fn description(&self) -> String {
       +        fl!(
       +            crate::LANGUAGE_LOADER,
       +            "new-file-template-xb-ext-description"
       +        )
       +    }
       +
       +    fn show_ui(&mut self, ui: &mut Ui) {
       +        show_file_ui(ui, &mut self.width, &mut self.height);
       +    }
       +
       +    fn create_file(&self, window: &mut MainWindow) -> crate::TerminalResult<Option<Message>> {
       +        let mut buf = Buffer::create((self.width, self.height));
       +        buf.palette =
       +            icy_engine::Palette::from_colors(icy_engine::DOS_DEFAULT_PALETTE[0..8].to_vec());
       +        buf.ice_mode = icy_engine::IceMode::Ice;
       +        buf.palette_mode = icy_engine::PaletteMode::Free8;
       +        buf.font_mode = icy_engine::FontMode::Dual;
       +
       +        let id = window.create_id();
       +        let editor = AnsiEditor::new(&window.gl, id, buf);
       +        add_child(&mut window.document_tree, None, Box::new(editor));
       +        Ok(None)
       +    }
       +}
       +
       +struct AnsiTemplate {
       +    pub width: i32,
       +    pub height: i32,
        }
        
        impl Template for AnsiTemplate {
       @@ -42,53 +188,60 @@ impl Template for AnsiTemplate {
            }
        
            fn title(&self) -> String {
       -        if self.file_id {
       -            fl!(crate::LANGUAGE_LOADER, "new-file-template-file_id-title")
       -        } else {
       -            fl!(crate::LANGUAGE_LOADER, "new-file-template-ansi-title")
       -        }
       +        fl!(crate::LANGUAGE_LOADER, "new-file-template-ansi-title")
            }
        
            fn description(&self) -> String {
       -        if self.file_id {
       -            fl!(
       -                crate::LANGUAGE_LOADER,
       -                "new-file-template-file_id-description"
       -            )
       -        } else {
       -            fl!(crate::LANGUAGE_LOADER, "new-file-template-ansi-description")
       -        }
       +        fl!(crate::LANGUAGE_LOADER, "new-file-template-ansi-description")
            }
        
            fn show_ui(&mut self, ui: &mut Ui) {
       -        egui::Grid::new("some_unique_id")
       -            .num_columns(2)
       -            .spacing([4.0, 8.0])
       -            .show(ui, |ui| {
       -                ui.with_layout(Layout::right_to_left(egui::Align::Center), |ui| {
       -                    ui.label(fl!(crate::LANGUAGE_LOADER, "new-file-width"));
       -                });
       -                let mut tmp_str = self.width.to_string();
       -                ui.add(egui::TextEdit::singleline(&mut tmp_str).char_limit(35));
       -                if let Ok(new_width) = tmp_str.parse::<i32>() {
       -                    self.width = new_width;
       -                }
       -                ui.end_row();
       +        show_file_ui(ui, &mut self.width, &mut self.height);
       +    }
        
       -                ui.with_layout(Layout::right_to_left(egui::Align::Center), |ui| {
       -                    ui.label(fl!(crate::LANGUAGE_LOADER, "new-file-height"));
       -                });
       -                let mut tmp_str = self.height.to_string();
       -                ui.add(egui::TextEdit::singleline(&mut tmp_str).char_limit(35));
       -                if let Ok(new_height) = tmp_str.parse::<i32>() {
       -                    self.height = new_height;
       -                }
       -                ui.end_row();
       -            });
       +    fn create_file(&self, window: &mut MainWindow) -> crate::TerminalResult<Option<Message>> {
       +        let mut buf = Buffer::create((self.width, self.height));
       +        buf.ice_mode = icy_engine::IceMode::Unlimited;
       +        buf.palette_mode = icy_engine::PaletteMode::RGB;
       +        buf.font_mode = icy_engine::FontMode::Unlimited;
       +
       +        let id = window.create_id();
       +        let editor = AnsiEditor::new(&window.gl, id, buf);
       +        add_child(&mut window.document_tree, None, Box::new(editor));
       +        Ok(None)
       +    }
       +}
       +
       +struct FileIdTemplate {
       +    pub width: i32,
       +    pub height: i32,
       +}
       +
       +impl Template for FileIdTemplate {
       +    fn image(&self) -> &RetainedImage {
       +        &crate::ANSI_TEMPLATE_IMG
       +    }
       +
       +    fn title(&self) -> String {
       +        fl!(crate::LANGUAGE_LOADER, "new-file-template-file_id-title")
       +    }
       +
       +    fn description(&self) -> String {
       +        fl!(
       +            crate::LANGUAGE_LOADER,
       +            "new-file-template-file_id-description"
       +        )
       +    }
       +
       +    fn show_ui(&mut self, ui: &mut Ui) {
       +        show_file_ui(ui, &mut self.width, &mut self.height);
            }
        
            fn create_file(&self, window: &mut MainWindow) -> crate::TerminalResult<Option<Message>> {
       -        let buf = Buffer::create((self.width, self.height));
       +        let mut buf = Buffer::create((self.width, self.height));
       +        buf.ice_mode = icy_engine::IceMode::Blink;
       +        buf.palette_mode = icy_engine::PaletteMode::Fixed16;
       +        buf.font_mode = icy_engine::FontMode::Sauce;
                let id = window.create_id();
                let editor = AnsiEditor::new(&window.gl, id, buf);
                add_child(&mut window.document_tree, None, Box::new(editor));
       @@ -96,6 +249,33 @@ impl Template for AnsiTemplate {
            }
        }
        
       +fn show_file_ui(ui: &mut Ui, width: &mut i32, height: &mut i32) {
       +    egui::Grid::new("some_unique_id")
       +        .num_columns(2)
       +        .spacing([4.0, 8.0])
       +        .show(ui, |ui| {
       +            ui.with_layout(Layout::right_to_left(egui::Align::Center), |ui| {
       +                ui.label(fl!(crate::LANGUAGE_LOADER, "new-file-width"));
       +            });
       +            let mut tmp_str = width.to_string();
       +            ui.add(egui::TextEdit::singleline(&mut tmp_str).char_limit(35));
       +            if let Ok(new_width) = tmp_str.parse::<i32>() {
       +                *width = new_width;
       +            }
       +            ui.end_row();
       +
       +            ui.with_layout(Layout::right_to_left(egui::Align::Center), |ui| {
       +                ui.label(fl!(crate::LANGUAGE_LOADER, "new-file-height"));
       +            });
       +            let mut tmp_str = height.to_string();
       +            ui.add(egui::TextEdit::singleline(&mut tmp_str).char_limit(35));
       +            if let Ok(new_height) = tmp_str.parse::<i32>() {
       +                *height = new_height;
       +            }
       +            ui.end_row();
       +        });
       +}
       +
        struct AnsiMationTemplate {}
        
        impl Template for AnsiMationTemplate {
       @@ -235,12 +415,26 @@ impl Default for NewFileDialog {
                    Box::new(AnsiTemplate {
                        width: 80,
                        height: 25,
       -                file_id: false,
                    }),
       -            Box::new(AnsiTemplate {
       +            Box::new(XB16Template {
       +                width: 80,
       +                height: 25,
       +            }),
       +            Box::new(Dos16Template {
       +                width: 80,
       +                height: 25,
       +            }),
       +            Box::new(Ice16Template {
       +                width: 80,
       +                height: 25,
       +            }),
       +            Box::new(XBExtTemplate {
       +                width: 80,
       +                height: 25,
       +            }),
       +            Box::new(FileIdTemplate {
                        width: 44,
                        height: 25,
       -                file_id: true,
                    }),
                    Box::new(AnsiMationTemplate {}),
                    Box::new(BitFontTemplate {}),
       @@ -342,7 +536,12 @@ impl crate::ModalDialog for NewFileDialog {
        
                                            let font_id =
                                                FontId::new(14.0, eframe::epaint::FontFamily::Proportional);
       -                                    let text: WidgetText = template.description().into();
       +                                    let text: WidgetText = template
       +                                        .description()
       +                                        .lines()
       +                                        .next()
       +                                        .unwrap_or_default()
       +                                        .into();
                                            let galley =
                                                text.into_galley(ui, Some(false), f32::INFINITY, font_id);
                                            let mut descr_rect = rect;
 (DIR) diff --git a/src/ui/document_docking.rs b/src/ui/document_docking.rs
       @@ -312,6 +312,13 @@ impl egui_tiles::Behavior<DocumentTab> for DocumentBehavior {
                            if let Some(editor) = doc.get_ansi_editor() {
                                ui.add_space(4.0);
                                let mut buffer = Buffer::new((48, 1));
       +                        let font_page = editor.buffer_view.lock().get_caret().get_font_page();
       +                        if let Some(font) =
       +                            editor.buffer_view.lock().get_buffer().get_font(font_page)
       +                        {
       +                            buffer.set_font(1, font.clone());
       +                        }
       +
                                let char_set = Settings::get_character_set();
                                if self.cur_char_set != char_set
                                    || self.dark_mode != ui.style().visuals.dark_mode
       @@ -355,10 +362,12 @@ impl egui_tiles::Behavior<DocumentTab> for DocumentBehavior {
                                            i += 1;
                                        }
                                        attr.set_foreground(15);
       +                                attr.set_font_page(1);
                                        buffer.layers[0].set_char(
                                            (i, 0),
                                            AttributedChar::new(editor.get_char_set_key(j), attr),
                                        );
       +                                attr.set_font_page(0);
                                        i += 1;
                                    }
        
 (DIR) diff --git a/src/ui/editor/charfont/mod.rs b/src/ui/editor/charfont/mod.rs
       @@ -647,7 +647,7 @@ impl CharFontEditor {
                                    for x in 0..lw {
                                        let ch = buf.get_char((x, y));
                                        data.push(ch.ch as u8);
       -                                data.push(ch.attribute.as_u8(icy_engine::BufferType::LegacyIce));
       +                                data.push(ch.attribute.as_u8());
                                    }
                                    w = w.max(lw);
                                    h = y;
 (DIR) diff --git a/src/ui/main_window.rs b/src/ui/main_window.rs
       @@ -227,7 +227,7 @@ impl MainWindow {
                Settings::add_recent_file(path);
                if let Some(ext) = path.extension() {
                    let ext = ext.to_str().unwrap().to_ascii_lowercase();
       -            if "psf" == ext || "f16" == ext || "f14" == ext || "f8" == ext || "fon" == ext {
       +            if is_font_extensions(&ext) {
                        let file_name = path.file_name();
                        if file_name.is_none() {
                            return;
       @@ -546,6 +546,30 @@ impl MainWindow {
            }
        }
        
       +pub fn is_font_extensions(ext: &str) -> bool {
       +    "psf" == ext
       +        || "f19" == ext
       +        || "f18" == ext
       +        || "f17" == ext
       +        || "f16" == ext
       +        || "f15" == ext
       +        || "f14" == ext
       +        || "f13" == ext
       +        || "f12" == ext
       +        || "f11" == ext
       +        || "f10" == ext
       +        || "f09" == ext
       +        || "f08" == ext
       +        || "f07" == ext
       +        || "f06" == ext
       +        || "f05" == ext
       +        || "f04" == ext
       +        || "f03" == ext
       +        || "f02" == ext
       +        || "f01" == ext
       +        || "fon" == ext
       +}
       +
        pub fn button_with_shortcut(
            ui: &mut Ui,
            enabled: bool,
       @@ -607,13 +631,15 @@ impl eframe::App for MainWindow {
        
                        let mut caret_attr = TextAttribute::default();
                        let mut palette = Palette::default();
       -                let mut buffer_type = icy_engine::BufferType::NoLimits;
       +                let mut ice_mode = icy_engine::IceMode::Unlimited;
       +                let mut font_mode = icy_engine::FontMode::Unlimited;
        
                        if let Some(doc) = self.get_active_document() {
                            if let Some(editor) = doc.lock().unwrap().get_ansi_editor() {
                                caret_attr = editor.buffer_view.lock().get_caret().get_attribute();
                                palette = editor.buffer_view.lock().get_buffer().palette.clone();
       -                        buffer_type = editor.buffer_view.lock().get_buffer().buffer_type;
       +                        ice_mode = editor.buffer_view.lock().get_buffer().ice_mode;
       +                        font_mode = editor.buffer_view.lock().get_buffer().font_mode;
                            }
                        }
        
       @@ -626,12 +652,12 @@ impl eframe::App for MainWindow {
                        });
        
                        ui.separator();
       -                let msg2 = crate::palette_editor_16(ui, &caret_attr, &palette, buffer_type);
       +                let msg2 = crate::palette_editor_16(ui, &caret_attr, &palette, ice_mode, font_mode);
                        if msg.is_none() {
                            msg = msg2;
                        }
        
       -                if buffer_type.has_blink()
       +                if ice_mode.has_blink()
                            && ui
                                .selectable_label(
                                    caret_attr.is_blinking(),
 (DIR) diff --git a/src/ui/palette_editor.rs b/src/ui/palette_editor.rs
       @@ -1,7 +1,7 @@
        use crate::{Message, SWAP_SVG};
        use eframe::egui::{self, Sense};
        use eframe::epaint::{Color32, Pos2, Rect, Rounding, Stroke, Vec2};
       -use icy_engine::{BufferType, Palette, TextAttribute};
       +use icy_engine::{Palette, TextAttribute};
        use std::cmp::min;
        
        pub fn palette_switcher(
       @@ -152,7 +152,8 @@ pub fn palette_editor_16(
            ui: &mut egui::Ui,
            caret_attr: &TextAttribute,
            palette: &Palette,
       -    buffer_type: BufferType,
       +    ice_mode: icy_engine::IceMode,
       +    font_mode: icy_engine::FontMode,
        ) -> Option<Message> {
            let mut result = None;
        
       @@ -255,11 +256,13 @@ pub fn palette_editor_16(
                        pos.x as u32 + pos.y as u32 * items_per_row as u32,
                    );
                    if response.clicked() {
       -                result = Some(Message::SetForeground(color));
       +                if color < 8 || font_mode.has_high_fg_colors() || palette.len() > 16 {
       +                    result = Some(Message::SetForeground(color));
       +                }
                        response.mark_changed();
                    }
                    if response.secondary_clicked() {
       -                if color < 8 || buffer_type.has_high_bg_colors() || palette.len() > 16 {
       +                if color < 8 || ice_mode.has_high_bg_colors() || palette.len() > 16 {
                            result = Some(Message::SetBackground(color));
                        }
                        response.mark_changed();
 (DIR) diff --git a/src/ui/top_bar.rs b/src/ui/top_bar.rs
       @@ -8,7 +8,7 @@ use egui_extras::RetainedImage;
        use i18n_embed_fl::fl;
        use icy_engine::{
            util::{pop_data, BUFFER_DATA},
       -    BufferType,
       +    FontMode, IceMode, PaletteMode,
        };
        
        use crate::{button_with_shortcut, MainWindow, Message, Settings, PLUGINS, SETTINGS};
       @@ -262,58 +262,100 @@ impl MainWindow {
                                if let Ok(doc) = &mut pane.doc.lock() {
                                    let editor = doc.get_ansi_editor_mut().unwrap();
                                    let lock = &mut editor.buffer_view.lock();
       -                            if !matches!(lock.get_buffer().buffer_type, BufferType::Unicode) {
       -                                ui.menu_button(
       -                                    fl!(crate::LANGUAGE_LOADER, "menu-color-mode"),
       -                                    |ui| {
       -                                        ui.style_mut().wrap = Some(false);
       -                                        ui.set_min_width(240.0);
       -
       -                                        if ui
       -                                            .selectable_label(
       -                                                lock.get_buffer().buffer_type
       -                                                    == BufferType::NoLimits,
       -                                                fl!(
       -                                                    crate::LANGUAGE_LOADER,
       -                                                    "menu-color-mode-unrestricted"
       -                                                ),
       -                                            )
       -                                            .clicked()
       -                                        {
       -                                            lock.get_buffer_mut().buffer_type =
       -                                                BufferType::NoLimits;
       -                                            ui.close_menu();
       -                                        }
       -
       -                                        if ui
       -                                            .selectable_label(
       -                                                lock.get_buffer().buffer_type
       -                                                    == BufferType::LegacyDos,
       -                                                fl!(crate::LANGUAGE_LOADER, "menu-color-mode-dos"),
       -                                            )
       -                                            .clicked()
       -                                        {
       -                                            lock.get_buffer_mut().buffer_type =
       -                                                BufferType::LegacyDos;
       -                                            ui.close_menu();
       -                                        }
       -
       -                                        if ui
       -                                            .selectable_label(
       -                                                lock.get_buffer().buffer_type
       -                                                    == BufferType::LegacyIce,
       -                                                fl!(crate::LANGUAGE_LOADER, "menu-color-mode-ice"),
       -                                            )
       -                                            .clicked()
       -                                        {
       -                                            lock.get_buffer_mut().buffer_type =
       -                                                BufferType::LegacyIce;
       -                                            ui.close_menu();
       -                                        }
       -                                    },
       -                                );
       -                                ui.separator();
       -                            }
       +                            ui.menu_button(fl!(crate::LANGUAGE_LOADER, "menu-ice-mode"), |ui| {
       +                                ui.style_mut().wrap = Some(false);
       +                                ui.set_min_width(240.0);
       +
       +                                if ui
       +                                    .selectable_label(
       +                                        lock.get_buffer().ice_mode == IceMode::Unlimited,
       +                                        fl!(crate::LANGUAGE_LOADER, "menu-ice-mode-unrestricted"),
       +                                    )
       +                                    .clicked()
       +                                {
       +                                    lock.get_buffer_mut().ice_mode = IceMode::Unlimited;
       +                                    ui.close_menu();
       +                                }
       +
       +                                if ui
       +                                    .selectable_label(
       +                                        lock.get_buffer().ice_mode == IceMode::Blink,
       +                                        fl!(crate::LANGUAGE_LOADER, "menu-ice-mode-blink"),
       +                                    )
       +                                    .clicked()
       +                                {
       +                                    lock.get_buffer_mut().ice_mode = IceMode::Blink;
       +                                    ui.close_menu();
       +                                }
       +
       +                                if ui
       +                                    .selectable_label(
       +                                        lock.get_buffer().ice_mode == IceMode::Ice,
       +                                        fl!(crate::LANGUAGE_LOADER, "menu-ice-mode-ice"),
       +                                    )
       +                                    .clicked()
       +                                {
       +                                    lock.get_buffer_mut().ice_mode = IceMode::Ice;
       +                                    ui.close_menu();
       +                                }
       +                            });
       +
       +                            ui.menu_button(
       +                                fl!(crate::LANGUAGE_LOADER, "menu-palette-mode"),
       +                                |ui| {
       +                                    ui.style_mut().wrap = Some(false);
       +                                    ui.set_min_width(240.0);
       +
       +                                    if ui
       +                                        .selectable_label(
       +                                            lock.get_buffer().palette_mode == PaletteMode::RGB,
       +                                            fl!(
       +                                                crate::LANGUAGE_LOADER,
       +                                                "menu-palette-mode-unrestricted"
       +                                            ),
       +                                        )
       +                                        .clicked()
       +                                    {
       +                                        lock.get_buffer_mut().palette_mode = PaletteMode::RGB;
       +                                        ui.close_menu();
       +                                    }
       +
       +                                    if ui
       +                                        .selectable_label(
       +                                            lock.get_buffer().palette_mode == PaletteMode::Fixed16,
       +                                            fl!(crate::LANGUAGE_LOADER, "menu-palette-mode-dos"),
       +                                        )
       +                                        .clicked()
       +                                    {
       +                                        lock.get_buffer_mut().palette_mode = PaletteMode::Fixed16;
       +                                        ui.close_menu();
       +                                    }
       +
       +                                    if ui
       +                                        .selectable_label(
       +                                            lock.get_buffer().palette_mode == PaletteMode::Free16,
       +                                            fl!(crate::LANGUAGE_LOADER, "menu-palette-mode-free"),
       +                                        )
       +                                        .clicked()
       +                                    {
       +                                        lock.get_buffer_mut().palette_mode = PaletteMode::Free16;
       +                                        ui.close_menu();
       +                                    }
       +
       +                                    if ui
       +                                        .selectable_label(
       +                                            lock.get_buffer().palette_mode == PaletteMode::Free8,
       +                                            fl!(crate::LANGUAGE_LOADER, "menu-palette-mode-free8"),
       +                                        )
       +                                        .clicked()
       +                                    {
       +                                        lock.get_buffer_mut().palette_mode = PaletteMode::Free8;
       +                                        ui.close_menu();
       +                                    }
       +                                },
       +                            );
       +
       +                            ui.separator();
                                }
                            }
                        }
       @@ -338,6 +380,61 @@ impl MainWindow {
                    ui.menu_button(fl!(crate::LANGUAGE_LOADER, "menu-fonts"), |ui| {
                        ui.style_mut().wrap = Some(false);
                        ui.set_min_width(220.0);
       +                if let Some(pane) = self.get_active_pane_mut() {
       +                    if let Ok(doc) = &mut pane.doc.lock() {
       +                        ui.menu_button(fl!(crate::LANGUAGE_LOADER, "menu-font-mode"), |ui| {
       +                            ui.style_mut().wrap = Some(false);
       +                            ui.set_min_width(240.0);
       +                            let editor = doc.get_ansi_editor_mut().unwrap();
       +
       +                            let lock = &mut editor.buffer_view.lock();
       +
       +                            if ui
       +                                .selectable_label(
       +                                    lock.get_buffer().font_mode == FontMode::Unlimited,
       +                                    fl!(crate::LANGUAGE_LOADER, "menu-font-mode-unrestricted"),
       +                                )
       +                                .clicked()
       +                            {
       +                                lock.get_buffer_mut().font_mode = FontMode::Unlimited;
       +                                ui.close_menu();
       +                            }
       +
       +                            if ui
       +                                .selectable_label(
       +                                    lock.get_buffer().font_mode == FontMode::Single,
       +                                    fl!(crate::LANGUAGE_LOADER, "menu-font-mode-single"),
       +                                )
       +                                .clicked()
       +                            {
       +                                lock.get_buffer_mut().font_mode = FontMode::Single;
       +                                ui.close_menu();
       +                            }
       +
       +                            if ui
       +                                .selectable_label(
       +                                    lock.get_buffer().font_mode == FontMode::Sauce,
       +                                    fl!(crate::LANGUAGE_LOADER, "menu-font-mode-sauce"),
       +                                )
       +                                .clicked()
       +                            {
       +                                lock.get_buffer_mut().font_mode = FontMode::Sauce;
       +                                ui.close_menu();
       +                            }
       +
       +                            if ui
       +                                .selectable_label(
       +                                    lock.get_buffer().font_mode == FontMode::Dual,
       +                                    fl!(crate::LANGUAGE_LOADER, "menu-font-mode-dual"),
       +                                )
       +                                .clicked()
       +                            {
       +                                lock.get_buffer_mut().font_mode = FontMode::Dual;
       +                                ui.close_menu();
       +                            }
       +                        });
       +                    }
       +                }
                        self.commands[0].open_font_selector.ui(ui, &mut result);
                        self.commands[0].open_font_manager.ui(ui, &mut result);
                        ui.separator();