settings_dialog.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
       ---
       settings_dialog.rs (18866B)
       ---
            1 use std::sync::Arc;
            2 
            3 use eframe::{
            4     egui::{self, color_picker, Layout, Modifiers, RichText},
            5     epaint::{mutex::Mutex, Color32, Vec2},
            6 };
            7 use egui::Context;
            8 use i18n_embed_fl::fl;
            9 use icy_engine::{AttributedChar, BitFont, Buffer, Color, Position, Size, TextAttribute};
           10 use icy_engine_egui::{show_monitor_settings, show_terminal_area, BufferView, MarkerSettings, MonitorSettings};
           11 
           12 use crate::{CharSetMapping, CharTableToolWindow, Commands, FontSelector, ModalDialog, SelectOutlineDialog, Settings, CHARACTER_SETS, KEYBINDINGS, SETTINGS};
           13 pub struct SettingsDialog {
           14     settings_category: usize,
           15     select_outline_dialog: SelectOutlineDialog,
           16     is_dark_mode: Option<bool>,
           17     monitor_settings: MonitorSettings,
           18     marker_settings: MarkerSettings,
           19     key_filter: String,
           20     key_bindings: Vec<(String, eframe::egui::Key, Modifiers)>,
           21 
           22     font_cache: Vec<BitFont>,
           23     font_selector: Option<FontSelector>,
           24     cur_char_set: usize,
           25     char_sets: Vec<CharSetMapping>,
           26     views: Vec<Arc<Mutex<BufferView>>>,
           27     selected_view: usize,
           28     char_view: CharTableToolWindow,
           29 }
           30 const MONITOR_CAT: usize = 0;
           31 const MARKER_CAT: usize = 1;
           32 const OUTLINE_CAT: usize = 2;
           33 const CHAR_SET_CAT: usize = 3;
           34 const KEYBIND_CAT: usize = 4;
           35 
           36 impl SettingsDialog {
           37     pub fn new(ctx: &Context, gl: &Arc<glow::Context>) -> Self {
           38         let mut views = Vec::new();
           39 
           40         for _ in 0..15 {
           41             let mut buffer = Buffer::new(Size::new(10, 1));
           42             buffer.is_terminal_buffer = false;
           43             let mut buffer_view = BufferView::from_buffer(gl, buffer);
           44             buffer_view.interactive = true;
           45             views.push(Arc::new(Mutex::new(buffer_view)));
           46         }
           47         let char_view = CharTableToolWindow::new(ctx, 32);
           48 
           49         let mut font_cache = if let Ok(font_dir) = Settings::get_font_diretory() {
           50             FontSelector::load_fonts(font_dir.as_path())
           51         } else {
           52             Vec::new()
           53         };
           54 
           55         for f in icy_engine::SAUCE_FONT_NAMES {
           56             font_cache.push(BitFont::from_sauce_name(f).unwrap());
           57         }
           58         for slot in 0..icy_engine::ANSI_FONTS {
           59             let ansi_font = BitFont::from_ansi_font_page(slot).unwrap();
           60             font_cache.push(ansi_font);
           61         }
           62         font_cache.dedup_by(|x, y| x.get_checksum() == y.get_checksum());
           63         let font = BitFont::default();
           64         font_cache.retain(|x| x.get_checksum() != font.get_checksum());
           65         font_cache.insert(0, font);
           66 
           67         Self {
           68             settings_category: MONITOR_CAT,
           69             select_outline_dialog: SelectOutlineDialog::default(),
           70             monitor_settings: Default::default(),
           71             marker_settings: Default::default(),
           72             key_filter: String::new(),
           73             key_bindings: Commands::default_keybindings(),
           74             char_sets: Default::default(),
           75             font_cache,
           76             cur_char_set: 0,
           77             selected_view: 0,
           78             views,
           79             char_view,
           80             font_selector: None,
           81             is_dark_mode: unsafe { SETTINGS.is_dark_mode },
           82         }
           83     }
           84 
           85     pub(crate) fn init(&mut self) {
           86         self.monitor_settings = unsafe { SETTINGS.monitor_settings.clone() };
           87         self.marker_settings = unsafe { SETTINGS.marker_settings.clone() };
           88         self.key_bindings = unsafe { KEYBINDINGS.key_bindings.clone() };
           89         self.char_sets = unsafe { CHARACTER_SETS.character_sets.clone() };
           90     }
           91 
           92     pub fn show(&mut self, ctx: &egui::Context) -> bool {
           93         let mut open = true;
           94         let mut dialog_open = true;
           95         let title = RichText::new(fl!(crate::LANGUAGE_LOADER, "settings-heading"));
           96         if ctx.input(|i| i.key_down(egui::Key::Escape)) {
           97             open = false;
           98         }
           99 
          100         if let Some(selector) = &mut self.font_selector {
          101             if selector.show(ctx) {
          102                 if selector.should_commit() {
          103                     let font = selector.selected_font().get_checksum();
          104                     let mut new_set = self.char_sets[0].clone();
          105                     new_set.font_checksum = font;
          106                     self.char_sets.push(new_set);
          107                 }
          108                 self.font_selector = None;
          109             }
          110             return open;
          111         }
          112 
          113         egui::Window::new(title)
          114             .open(&mut open)
          115             .collapsible(false)
          116             .fixed_size(Vec2::new(400., 300.))
          117             .resizable(false)
          118             .frame(egui::Frame::window(&ctx.style()))
          119             .show(ctx, |ui| {
          120                 ui.horizontal(|ui| {
          121                     egui::widgets::global_dark_light_mode_switch(ui);
          122                     self.is_dark_mode = Some(ui.visuals().dark_mode);
          123 
          124                     let settings_category = self.settings_category;
          125 
          126                     if ui
          127                         .selectable_label(settings_category == MONITOR_CAT, fl!(crate::LANGUAGE_LOADER, "settings-monitor-category"))
          128                         .clicked()
          129                     {
          130                         self.settings_category = MONITOR_CAT;
          131                     }
          132 
          133                     if ui
          134                         .selectable_label(settings_category == MARKER_CAT, fl!(crate::LANGUAGE_LOADER, "settings-markers-guides-category"))
          135                         .clicked()
          136                     {
          137                         self.settings_category = MARKER_CAT;
          138                     }
          139 
          140                     if ui
          141                         .selectable_label(settings_category == OUTLINE_CAT, fl!(crate::LANGUAGE_LOADER, "settings-font-outline-category"))
          142                         .clicked()
          143                     {
          144                         self.settings_category = OUTLINE_CAT;
          145                     }
          146                     if ui
          147                         .selectable_label(settings_category == CHAR_SET_CAT, fl!(crate::LANGUAGE_LOADER, "settings-char-set-category"))
          148                         .clicked()
          149                     {
          150                         self.settings_category = CHAR_SET_CAT;
          151                     }
          152 
          153                     if ui
          154                         .selectable_label(settings_category == KEYBIND_CAT, fl!(crate::LANGUAGE_LOADER, "settings-keybindings-category"))
          155                         .clicked()
          156                     {
          157                         self.settings_category = KEYBIND_CAT;
          158                     }
          159                 });
          160                 ui.separator();
          161                 match self.settings_category {
          162                     MONITOR_CAT => unsafe {
          163                         if let Some(new_settings) = show_monitor_settings(ui, &SETTINGS.monitor_settings) {
          164                             SETTINGS.monitor_settings = new_settings;
          165                         }
          166                     },
          167                     MARKER_CAT => {
          168                         ui.add_space(8.0);
          169                         unsafe {
          170                             if let Some(new_settings) = show_marker_settings(ui, &SETTINGS.marker_settings) {
          171                                 SETTINGS.marker_settings = new_settings;
          172                             }
          173                         }
          174                     }
          175 
          176                     CHAR_SET_CAT => {
          177                         ui.add_space(8.0);
          178                         self.show_charset_editor(ui);
          179                     }
          180 
          181                     OUTLINE_CAT => {
          182                         ui.add_space(8.0);
          183                         self.select_outline_dialog.show_outline_ui(ui, 4, Vec2::new(8.0, 8.0));
          184                     }
          185 
          186                     KEYBIND_CAT => {
          187                         let mut map = std::collections::HashMap::new();
          188                         for (s, key, modifier) in &self.key_bindings {
          189                             map.insert(s.clone(), (*key, *modifier));
          190                         }
          191                         crate::Commands::show_keybinds_settings(ui, &mut self.key_filter, &mut map);
          192                         self.key_bindings.clear();
          193                         for (s, (key, modifier)) in map {
          194                             self.key_bindings.push((s, key, modifier));
          195                         }
          196                     }
          197                     _ => {}
          198                 }
          199 
          200                 ui.separator();
          201                 ui.add_space(4.0);
          202                 ui.with_layout(Layout::right_to_left(egui::Align::TOP), |ui| {
          203                     if ui.button(fl!(crate::LANGUAGE_LOADER, "new-file-ok")).clicked() {
          204                         unsafe {
          205                             if KEYBINDINGS.key_bindings != self.key_bindings {
          206                                 KEYBINDINGS.key_bindings = self.key_bindings.clone();
          207                                 if let Err(err) = KEYBINDINGS.save() {
          208                                     log::error!("Error saving keybindings: {}", err);
          209                                 }
          210                             }
          211                             if CHARACTER_SETS.character_sets != self.char_sets {
          212                                 CHARACTER_SETS.character_sets = self.char_sets.clone();
          213                                 if let Err(err) = CHARACTER_SETS.save() {
          214                                     log::error!("Error saving character sets: {}", err);
          215                                 }
          216                             }
          217                             SETTINGS.is_dark_mode = self.is_dark_mode;
          218                             if let Err(err) = Settings::save() {
          219                                 log::error!("Error saving settings: {err}");
          220                             }
          221                         }
          222                         dialog_open = false;
          223                     }
          224 
          225                     if ui.button(fl!(crate::LANGUAGE_LOADER, "new-file-cancel")).clicked() {
          226                         unsafe {
          227                             SETTINGS.monitor_settings = self.monitor_settings.clone();
          228                             SETTINGS.marker_settings = self.marker_settings.clone();
          229                             if let Some(dark_mode) = SETTINGS.is_dark_mode {
          230                                 ui.visuals_mut().dark_mode = dark_mode;
          231                             }
          232                         }
          233                         dialog_open = false;
          234                     }
          235 
          236                     if (self.settings_category == MONITOR_CAT
          237                         || self.settings_category == MARKER_CAT
          238                         || self.settings_category == CHAR_SET_CAT
          239                         || self.settings_category == KEYBIND_CAT)
          240                         && ui.button(fl!(crate::LANGUAGE_LOADER, "settings-reset_button")).clicked()
          241                     {
          242                         unsafe {
          243                             match self.settings_category {
          244                                 MONITOR_CAT => SETTINGS.monitor_settings = Default::default(),
          245                                 MARKER_CAT => SETTINGS.marker_settings = Default::default(),
          246                                 CHAR_SET_CAT => self.char_sets = Default::default(),
          247                                 KEYBIND_CAT => {
          248                                     self.key_bindings = Commands::default_keybindings();
          249                                 }
          250                                 _ => {}
          251                             }
          252                         }
          253                     }
          254                 });
          255             });
          256 
          257         open && dialog_open
          258     }
          259 
          260     pub fn show_charset_editor(&mut self, ui: &mut egui::Ui) {
          261         ui.set_height(580.);
          262         let mut id = 0;
          263         ui.add_space(48.0);
          264 
          265         let mut cur_font = &self.font_cache[0];
          266         for font in &self.font_cache {
          267             if font.checksum == self.char_sets[self.cur_char_set].font_checksum {
          268                 cur_font = font;
          269                 break;
          270             }
          271         }
          272 
          273         ui.horizontal(|ui| {
          274             ui.vertical(|ui| {
          275                 ui.label(fl!(crate::LANGUAGE_LOADER, "settings-char_set_list_label"));
          276                 egui::ScrollArea::vertical().max_height(240.0).show(ui, |ui| {
          277                     ui.vertical(|ui| {
          278                         for (i, char_set) in self.char_sets.iter().enumerate() {
          279                             let label = if char_set.font_checksum == 0 {
          280                                 "Default".to_string()
          281                             } else {
          282                                 let mut result = "Unknown".to_string();
          283                                 for font in &self.font_cache {
          284                                     if font.checksum == char_set.font_checksum {
          285                                         result = font.name.to_string();
          286                                         break;
          287                                     }
          288                                 }
          289                                 result
          290                             };
          291                             if ui.selectable_label(self.cur_char_set == i, label).clicked() {
          292                                 self.cur_char_set = i;
          293                             }
          294                         }
          295                     });
          296                 });
          297             });
          298             ui.separator();
          299             if ui.add(egui::Button::new(fl!(crate::LANGUAGE_LOADER, "add-font-dialog-select"))).clicked() {
          300                 self.font_selector = Some(FontSelector::font_library());
          301             }
          302 
          303             if ui
          304                 .add_enabled(
          305                     self.cur_char_set > 0,
          306                     egui::Button::new(fl!(crate::LANGUAGE_LOADER, "manage-font-remove_font_button")),
          307                 )
          308                 .clicked()
          309             {
          310                 self.char_sets.remove(self.cur_char_set);
          311                 self.cur_char_set = 0;
          312             }
          313             if ui
          314                 .add_enabled(self.cur_char_set == 0, egui::Button::new(fl!(crate::LANGUAGE_LOADER, "settings-reset_button")))
          315                 .clicked()
          316             {
          317                 self.char_sets[0] = CharSetMapping::default();
          318                 for view in self.views.iter() {
          319                     view.lock().get_edit_state_mut().set_is_buffer_dirty();
          320                 }
          321             }
          322         });
          323         ui.separator();
          324         egui::Grid::new("paste_mode_grid").num_columns(6).spacing([8.0, 8.0]).show(ui, |ui| {
          325             for (i, view) in self.views.iter().enumerate() {
          326                 let font_dims = view.lock().get_buffer_mut().get_font_dimensions();
          327 
          328                 let opt = icy_engine_egui::TerminalOptions {
          329                     stick_to_bottom: false,
          330                     scale: Some(Vec2::new(2.0, 2.0)),
          331                     id: Some(egui::Id::new(200 + id)),
          332                     terminal_size: Some(Vec2::new(font_dims.width as f32 * 10. * 2.0, font_dims.height as f32 * 2.0)),
          333                     force_focus: self.selected_view == i,
          334                     ..Default::default()
          335                 };
          336 
          337                 for x in 0..10 {
          338                     let ch = self.char_sets[self.cur_char_set].table[id][x];
          339                     view.lock().get_buffer_mut().layers[0].set_char((x, 0), AttributedChar::new(ch, TextAttribute::default()));
          340                 }
          341                 if id % 3 == 0 {
          342                     ui.end_row();
          343                 }
          344                 id += 1;
          345 
          346                 ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
          347                     if i == self.selected_view {
          348                         ui.strong(fl!(crate::LANGUAGE_LOADER, "settings-set-label", set = id));
          349                     } else {
          350                         ui.label(fl!(crate::LANGUAGE_LOADER, "settings-set-label", set = id));
          351                     }
          352                 });
          353                 let (response, calc) = show_terminal_area(ui, view.clone(), opt);
          354                 if response.has_focus() {
          355                     self.selected_view = i;
          356                 }
          357                 if response.clicked() {
          358                     if let Some(click_pos) = response.hover_pos() {
          359                         let pos = calc.calc_click_pos(click_pos);
          360                         let pos = Position::new(pos.x as i32, pos.y as i32);
          361                         view.lock().get_caret_mut().set_position(pos);
          362                     }
          363                 }
          364             }
          365         });
          366         if self.char_view.get_font().get_checksum() != cur_font.checksum {
          367             self.char_view.set_font(ui.ctx(), cur_font.clone());
          368             for view in &self.views {
          369                 view.lock().get_buffer_mut().set_font(0, cur_font.clone())
          370             }
          371         }
          372         if let Some(ch) = self.char_view.show_plain_char_table(ui) {
          373             let mut pos = self.views[self.selected_view].lock().get_caret().get_position();
          374             self.char_sets[self.cur_char_set].table[self.selected_view][pos.x as usize] = ch;
          375             pos.x = (pos.x + 1).min(9);
          376             self.views[self.selected_view].lock().get_caret_mut().set_position(pos);
          377 
          378             for x in 0..10 {
          379                 let ch = self.char_sets[self.cur_char_set].table[self.selected_view][x];
          380                 self.views[self.selected_view].lock().get_buffer_mut().layers[0].set_char((x, 0), AttributedChar::new(ch, TextAttribute::default()));
          381             }
          382 
          383             self.views[self.selected_view].lock().get_edit_state_mut().set_is_buffer_dirty();
          384         }
          385 
          386         if ui.input(|i| i.key_pressed(egui::Key::ArrowLeft)) {
          387             let mut pos = self.views[self.selected_view].lock().get_caret().get_position();
          388             pos.x = (pos.x - 1).max(0);
          389             self.views[self.selected_view].lock().get_caret_mut().set_position(pos);
          390         }
          391 
          392         if ui.input(|i| i.key_pressed(egui::Key::ArrowRight)) {
          393             let mut pos = self.views[self.selected_view].lock().get_caret().get_position();
          394             pos.x = (pos.x + 1).min(9);
          395             self.views[self.selected_view].lock().get_caret_mut().set_position(pos);
          396         }
          397     }
          398 }
          399 
          400 pub fn show_marker_settings(ui: &mut egui::Ui, old_settings: &MarkerSettings) -> Option<MarkerSettings> {
          401     let mut result = None;
          402 
          403     let mut marker_settings = old_settings.clone();
          404 
          405     ui.add(egui::Slider::new(&mut marker_settings.reference_image_alpha, 0.1..=0.9).text(fl!(crate::LANGUAGE_LOADER, "settings-reference-alpha")));
          406 
          407     ui.horizontal(|ui| {
          408         ui.label(fl!(crate::LANGUAGE_LOADER, "settings-raster-label"));
          409         let (r, g, b) = marker_settings.raster_color.get_rgb();
          410         let mut color = Color32::from_rgb(r, g, b);
          411 
          412         color_picker::color_edit_button_srgba(ui, &mut color, color_picker::Alpha::Opaque);
          413         marker_settings.raster_color = Color::new(color.r(), color.g(), color.b());
          414         ui.add(egui::Slider::new(&mut marker_settings.raster_alpha, 0.1..=0.9).text(fl!(crate::LANGUAGE_LOADER, "settings-alpha")));
          415     });
          416 
          417     ui.horizontal(|ui| {
          418         ui.label(fl!(crate::LANGUAGE_LOADER, "settings-guide-label"));
          419         let (r, g, b) = marker_settings.guide_color.get_rgb();
          420         let mut color = Color32::from_rgb(r, g, b);
          421 
          422         color_picker::color_edit_button_srgba(ui, &mut color, color_picker::Alpha::Opaque);
          423         marker_settings.guide_color = Color::new(color.r(), color.g(), color.b());
          424 
          425         ui.add(egui::Slider::new(&mut marker_settings.guide_alpha, 0.1..=0.9).text(fl!(crate::LANGUAGE_LOADER, "settings-alpha")));
          426     });
          427 
          428     if marker_settings != *old_settings {
          429         result = Some(marker_settings);
          430     }
          431 
          432     result
          433 }