URI: 
       settings_dialog.rs - icy_draw - [fork] icy_draw is the successor to mystic draw.
  HTML git clone https://git.drkhsh.at/icy_draw.git
   DIR Log
   DIR Files
   DIR Refs
   DIR README
       ---
       settings_dialog.rs (16942B)
       ---
            1 use eframe::egui::{self, RichText};
            2 use egui::{Layout, TextEdit, Vec2};
            3 use i18n_embed_fl::fl;
            4 use icy_engine_gui::show_monitor_settings;
            5 use icy_net::serial::{CharSize, Parity, StopBits};
            6 
            7 use crate::{
            8     ui::{MainWindowMode, MainWindowState},
            9     KeyBindings, Modem,
           10 };
           11 
           12 #[derive(Default)]
           13 pub struct DialogState {
           14     pub settings_category: usize,
           15 }
           16 
           17 #[derive(Clone, Debug)]
           18 pub(crate) enum Message {
           19     SwitchSettingsCategory(usize),
           20     CloseDialog,
           21     OpenSettingsFolder,
           22     ResetMonitorSettings,
           23     ResetKeybindSettings,
           24     UpdateIEMSI(crate::IEMSISettings),
           25     UpdateModem(Modem),
           26     UpdateMonitorSettings(icy_engine_gui::MonitorSettings),
           27     // ChangeOpenglScaling(Scaling),
           28     UpdateKeybinds(KeyBindings),
           29     ChangeConsoleBeep(bool),
           30 }
           31 
           32 type ShowSettingsCallback = fn(&MainWindowState, ui: &mut egui::Ui) -> Option<Message>;
           33 type ResetMessage = Option<Message>;
           34 
           35 lazy_static::lazy_static! {
           36     static ref SETTING_CATEGORIES: [(String, ShowSettingsCallback, ResetMessage); 5] = [
           37         (
           38             fl!(crate::LANGUAGE_LOADER, "settings-monitor-category"),
           39             show_monitor_settings2,
           40             Some(Message::ResetMonitorSettings)
           41         ),
           42         (
           43             fl!(crate::LANGUAGE_LOADER, "settings-iemsi-category"),
           44             show_iemsi_settings,
           45             None
           46         ),
           47         (
           48             fl!(crate::LANGUAGE_LOADER, "settings-terminal-category"),
           49             show_terminal_settings,
           50             None
           51         ),
           52         (
           53             fl!(crate::LANGUAGE_LOADER, "settings-keybinds-category"),
           54             crate::show_keybinds_settings,
           55             Some(Message::ResetKeybindSettings)
           56         ),
           57         (
           58             fl!(crate::LANGUAGE_LOADER, "settings-modem-category"),
           59             show_modem_settings,
           60             None
           61         ),
           62     ];
           63 }
           64 
           65 impl MainWindowState {
           66     pub fn show_settings(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
           67         let mut result = None;
           68 
           69         let mut open = true;
           70         let title = RichText::new(fl!(crate::LANGUAGE_LOADER, "settings-heading"));
           71         if ctx.input(|i| i.key_down(egui::Key::Escape)) {
           72             open = false;
           73         }
           74 
           75         egui::Window::new(title)
           76             .open(&mut open)
           77             .collapsible(false)
           78             .fixed_size(Vec2::new(400., 300.))
           79             .resizable(false)
           80             .frame(egui::Frame::window(&ctx.style()))
           81             .show(ctx, |ui| {
           82                 ui.horizontal(|ui| {
           83                     let old_dark = self.options.is_dark_mode;
           84                     egui::widgets::global_dark_light_mode_switch(ui);
           85                     self.options.is_dark_mode = Some(ui.visuals().dark_mode);
           86                     if self.options.is_dark_mode != old_dark {
           87                         self.store_options();
           88                     }
           89                     let settings_category = self.settings_dialog.settings_category;
           90                     for i in 0..SETTING_CATEGORIES.len() {
           91                         if ui.selectable_label(settings_category == i, &SETTING_CATEGORIES[i].0).clicked() {
           92                             result = Some(Message::SwitchSettingsCategory(i));
           93                         }
           94                     }
           95                 });
           96                 ui.separator();
           97                 let settings_category = self.settings_dialog.settings_category;
           98                 if let Some(cat) = SETTING_CATEGORIES.get(settings_category) {
           99                     if let Some(cmd) = cat.1(self, ui) {
          100                         result = Some(cmd);
          101                     }
          102                 } else {
          103                     ui.colored_label(ui.style().visuals.error_fg_color, "Invalid settings category");
          104                 }
          105 
          106                 ui.separator();
          107                 ui.add_space(4.0);
          108                 ui.with_layout(Layout::right_to_left(egui::Align::TOP), |ui| {
          109                     if ui.button(fl!(crate::LANGUAGE_LOADER, "dialing_directory-ok-button")).clicked() {
          110                         result = Some(Message::CloseDialog);
          111                     }
          112 
          113                     let settings_category = self.settings_dialog.settings_category;
          114                     if let Some(cat) = SETTING_CATEGORIES.get(settings_category) {
          115                         if let Some(reset_cmd) = &cat.2 {
          116                             if ui.button(fl!(crate::LANGUAGE_LOADER, "settings-reset-button")).clicked() {
          117                                 result = Some(reset_cmd.clone());
          118                             }
          119                         }
          120                     }
          121                 });
          122             });
          123 
          124         if !open {
          125             result = Some(Message::CloseDialog);
          126         }
          127 
          128         update_state(self, result);
          129     }
          130 }
          131 
          132 fn show_iemsi_settings(state: &MainWindowState, ui: &mut egui::Ui) -> Option<Message> {
          133     let mut iemsi = state.options.iemsi.clone();
          134     ui.checkbox(&mut iemsi.autologin, fl!(crate::LANGUAGE_LOADER, "settings-iemsi-autologin-checkbox"));
          135 
          136     egui::Grid::new("some_unique_id")
          137         .num_columns(2)
          138         .spacing([4.0, 8.0])
          139         .min_row_height(24.)
          140         .show(ui, |ui| {
          141             ui.with_layout(Layout::right_to_left(egui::Align::Center), |ui| {
          142                 ui.label(RichText::new(fl!(crate::LANGUAGE_LOADER, "settings-iemsi-alias")));
          143             });
          144             ui.add(TextEdit::singleline(&mut iemsi.alias));
          145             ui.end_row();
          146 
          147             ui.with_layout(Layout::right_to_left(egui::Align::Center), |ui| {
          148                 ui.label(RichText::new(fl!(crate::LANGUAGE_LOADER, "settings-iemsi-location")));
          149             });
          150             ui.add(TextEdit::singleline(&mut iemsi.location));
          151             ui.end_row();
          152 
          153             ui.with_layout(Layout::right_to_left(egui::Align::Center), |ui| {
          154                 ui.label(RichText::new(fl!(crate::LANGUAGE_LOADER, "settings-iemsi-data-phone")));
          155             });
          156             ui.add(TextEdit::singleline(&mut iemsi.data_phone));
          157             ui.end_row();
          158 
          159             ui.with_layout(Layout::right_to_left(egui::Align::Center), |ui| {
          160                 ui.label(RichText::new(fl!(crate::LANGUAGE_LOADER, "settings-iemsi-voice-phone")));
          161             });
          162             ui.add(TextEdit::singleline(&mut iemsi.voice_phone));
          163             ui.end_row();
          164 
          165             ui.with_layout(Layout::right_to_left(egui::Align::Center), |ui| {
          166                 ui.label(RichText::new(fl!(crate::LANGUAGE_LOADER, "settings-iemsi-birth-date")));
          167             });
          168             ui.add(TextEdit::singleline(&mut iemsi.birth_date));
          169             ui.end_row();
          170         });
          171 
          172     if iemsi == state.options.iemsi {
          173         None
          174     } else {
          175         Some(Message::UpdateIEMSI(iemsi))
          176     }
          177 }
          178 
          179 fn show_terminal_settings(state: &MainWindowState, ui: &mut egui::Ui) -> Option<Message> {
          180     let mut result = None;
          181     let mut beep = state.options.console_beep;
          182 
          183     if ui
          184         .checkbox(&mut beep, fl!(crate::LANGUAGE_LOADER, "settings-terminal-console-beep-checkbox"))
          185         .changed()
          186     {
          187         result = Some(Message::ChangeConsoleBeep(beep));
          188     }
          189 
          190     ui.add_space(16.0);
          191     if ui.button(fl!(crate::LANGUAGE_LOADER, "settings-terminal-open-settings-dir-button")).clicked() {
          192         result = Some(Message::OpenSettingsFolder);
          193     }
          194     ui.add_space(8.0);
          195 
          196     result
          197 }
          198 
          199 fn show_monitor_settings2(state: &MainWindowState, ui: &mut egui::Ui) -> Option<Message> {
          200     let mut result = None;
          201 
          202     let monitor_settings = state.options.monitor_settings.clone();
          203     if let Some(settings) = show_monitor_settings(ui, &monitor_settings) {
          204         result = Some(Message::UpdateMonitorSettings(settings));
          205     }
          206 
          207     result
          208 }
          209 
          210 fn update_state(state: &mut MainWindowState, message_opt: Option<Message>) {
          211     match message_opt {
          212         Some(Message::CloseDialog) => {
          213             state.mode = MainWindowMode::ShowTerminal;
          214         }
          215         Some(Message::SwitchSettingsCategory(category)) => {
          216             state.settings_dialog.settings_category = category;
          217         }
          218         Some(Message::ResetMonitorSettings) => {
          219             state.options.reset_monitor_settings();
          220             state.store_options();
          221         }
          222         Some(Message::ResetKeybindSettings) => {
          223             state.options.reset_keybindings();
          224             state.store_options();
          225         }
          226         Some(Message::OpenSettingsFolder) => {
          227             if let Some(proj_dirs) = directories::ProjectDirs::from("com", "GitHub", "icy_term") {
          228                 open::that(proj_dirs.config_dir()).unwrap();
          229             }
          230         }
          231         Some(Message::UpdateIEMSI(iemsi)) => {
          232             state.options.iemsi = iemsi;
          233             state.store_options();
          234         }
          235         Some(Message::UpdateModem(modem)) => {
          236             state.options.modem = modem;
          237             state.store_options();
          238         }
          239         Some(Message::UpdateMonitorSettings(monitor_settings)) => {
          240             state.options.monitor_settings = monitor_settings;
          241             state.store_options();
          242         } /*
          243         Some(Message::ChangeOpenglScaling(scaling)) => {
          244         state.options.scaling = scaling;
          245         state.store_options();
          246         }*/
          247         Some(Message::UpdateKeybinds(keybinds)) => {
          248             state.options.bind = keybinds;
          249             state.store_options();
          250         }
          251         Some(Message::ChangeConsoleBeep(beep)) => {
          252             state.options.console_beep = beep;
          253             state.store_options();
          254         }
          255         _ => {}
          256     }
          257 }
          258 
          259 fn show_modem_settings(state: &MainWindowState, ui: &mut egui::Ui) -> Option<Message> {
          260     let mut modem = state.options.modem.clone();
          261 
          262     egui::Grid::new("some_unique_id")
          263         .num_columns(2)
          264         .spacing([4.0, 8.0])
          265         .min_row_height(24.)
          266         .show(ui, |ui| {
          267             ui.with_layout(Layout::right_to_left(egui::Align::Center), |ui| {
          268                 ui.label(RichText::new(fl!(crate::LANGUAGE_LOADER, "settings-modem-device")));
          269             });
          270             ui.add(TextEdit::singleline(&mut modem.device));
          271             ui.end_row();
          272 
          273             ui.with_layout(Layout::right_to_left(egui::Align::Center), |ui| {
          274                 ui.label(RichText::new(fl!(crate::LANGUAGE_LOADER, "settings-modem-baud_rate")));
          275             });
          276             let mut baud = modem.baud_rate.to_string();
          277             ui.add(TextEdit::singleline(&mut baud));
          278             if let Ok(baud) = baud.parse() {
          279                 modem.baud_rate = baud;
          280             }
          281             ui.end_row();
          282 
          283             ui.with_layout(Layout::right_to_left(egui::Align::Center), |ui: &mut egui::Ui| {
          284                 ui.label(RichText::new(fl!(crate::LANGUAGE_LOADER, "settings-modem-data_bits")));
          285             });
          286 
          287             ui.horizontal(|ui| {
          288                 let txt = match modem.char_size {
          289                     CharSize::Bits5 => "5",
          290                     CharSize::Bits6 => "6",
          291                     CharSize::Bits7 => "7",
          292                     CharSize::Bits8 => "8",
          293                 };
          294                 egui::ComboBox::from_id_source("combobox1").selected_text(RichText::new(txt)).show_ui(ui, |ui| {
          295                     ui.selectable_value(&mut modem.char_size, CharSize::Bits5, "5");
          296                     ui.selectable_value(&mut modem.char_size, CharSize::Bits6, "6");
          297                     ui.selectable_value(&mut modem.char_size, CharSize::Bits7, "7");
          298                     ui.selectable_value(&mut modem.char_size, CharSize::Bits8, "8");
          299                 });
          300 
          301                 let txt = match modem.stop_bits {
          302                     StopBits::One => "1",
          303                     StopBits::Two => "2",
          304                 };
          305                 egui::ComboBox::from_id_source("combobox2").selected_text(RichText::new(txt)).show_ui(ui, |ui| {
          306                     ui.selectable_value(&mut modem.stop_bits, StopBits::One, "1");
          307                     ui.selectable_value(&mut modem.stop_bits, StopBits::Two, "2");
          308                 });
          309                 let txt = match modem.parity {
          310                     Parity::None => "None",
          311                     Parity::Odd => "Odd",
          312                     Parity::Even => "Even",
          313                 };
          314                 egui::ComboBox::from_id_source("combobox3").selected_text(RichText::new(txt)).show_ui(ui, |ui| {
          315                     ui.selectable_value(&mut modem.parity, Parity::None, "None");
          316                     ui.selectable_value(&mut modem.parity, Parity::Odd, "Odd");
          317                     ui.selectable_value(&mut modem.parity, Parity::Even, "Even");
          318                 });
          319             });
          320             ui.end_row();
          321 
          322             ui.with_layout(Layout::right_to_left(egui::Align::Center), |ui| {
          323                 ui.label(RichText::new(fl!(crate::LANGUAGE_LOADER, "settings-modem-init_string")));
          324             });
          325             ui.add(TextEdit::singleline(&mut modem.init_string));
          326             ui.end_row();
          327 
          328             ui.with_layout(Layout::right_to_left(egui::Align::Center), |ui| {
          329                 ui.label(RichText::new(fl!(crate::LANGUAGE_LOADER, "settings-modem_dial_string")));
          330             });
          331             ui.add(TextEdit::singleline(&mut modem.dial_string));
          332             ui.end_row();
          333         });
          334 
          335     if modem == state.options.modem {
          336         None
          337     } else {
          338         Some(Message::UpdateModem(modem))
          339     }
          340 }
          341 
          342 #[cfg(test)]
          343 mod tests {
          344     #![allow(clippy::field_reassign_with_default)]
          345     use icy_engine_gui::MonitorSettings;
          346 
          347     use crate::{
          348         ui::{
          349             dialogs::settings_dialog::{update_state, SETTING_CATEGORIES},
          350             MainWindowState,
          351         },
          352         IEMSISettings, KeyBindings, Options, Scaling,
          353     };
          354 
          355     #[test]
          356     fn test_close_dialog() {
          357         let mut state: MainWindowState = MainWindowState::default();
          358         state.mode = super::MainWindowMode::ShowSettings;
          359         update_state(&mut state, Some(super::Message::CloseDialog));
          360         assert!(matches!(state.mode, super::MainWindowMode::ShowTerminal));
          361         assert!(!state.options_written);
          362     }
          363 
          364     #[test]
          365     fn test_switch_category_dialog() {
          366         let mut state: MainWindowState = MainWindowState::default();
          367         for i in 0..SETTING_CATEGORIES.len() {
          368             update_state(&mut state, Some(super::Message::SwitchSettingsCategory(i)));
          369             assert_eq!(i, state.settings_dialog.settings_category);
          370         }
          371         assert!(!state.options_written);
          372     }
          373 
          374     #[test]
          375     fn test_reset_monitor_settings() {
          376         let mut state: MainWindowState = MainWindowState::default();
          377         let mut opt: Options = Options::default();
          378         opt.scaling = Scaling::Linear;
          379         opt.monitor_settings.blur = 0.0;
          380         opt.monitor_settings.brightness = 1.0;
          381         state.options = opt;
          382 
          383         assert_ne!(Options::default().scaling, state.options.scaling);
          384         assert_ne!(Options::default().monitor_settings, state.options.monitor_settings);
          385         update_state(&mut state, Some(super::Message::ResetMonitorSettings));
          386         assert_eq!(Options::default().scaling, state.options.scaling);
          387         assert_eq!(Options::default().monitor_settings, state.options.monitor_settings);
          388         assert!(state.options_written);
          389     }
          390 
          391     #[test]
          392     fn test_reset_keybindings() {
          393         let mut state: MainWindowState = MainWindowState::default();
          394         let mut opt = Options::default();
          395         opt.bind.download = None;
          396         opt.bind.full_screen = None;
          397         state.options = opt;
          398 
          399         assert_ne!(Options::default().bind, state.options.bind);
          400         update_state(&mut state, Some(super::Message::ResetKeybindSettings));
          401         assert_eq!(Options::default().bind, state.options.bind);
          402         assert!(state.options_written);
          403     }
          404 
          405     #[test]
          406     fn test_change_console_beep() {
          407         let mut state: MainWindowState = MainWindowState::default();
          408         update_state(&mut state, Some(super::Message::ChangeConsoleBeep(false)));
          409         assert_ne!(Options::default().console_beep, state.options.console_beep);
          410         assert!(state.options_written);
          411     }
          412 
          413     #[test]
          414     fn test_set_keybindings() {
          415         let mut state: MainWindowState = MainWindowState::default();
          416         let mut bind = KeyBindings::default();
          417         bind.download = None;
          418         bind.full_screen = None;
          419         update_state(&mut state, Some(super::Message::UpdateKeybinds(bind)));
          420         assert_ne!(KeyBindings::default(), state.options.bind);
          421         assert!(state.options_written);
          422     }
          423 
          424     #[test]
          425     fn test_set_monitor_settings() {
          426         let mut state: MainWindowState = MainWindowState::default();
          427         let mut settings = MonitorSettings::default();
          428         settings.blur = 0.0;
          429         settings.brightness = 1.0;
          430         update_state(&mut state, Some(super::Message::UpdateMonitorSettings(settings)));
          431         assert_ne!(MonitorSettings::default(), state.options.monitor_settings);
          432         assert!(state.options_written);
          433     }
          434 
          435     #[test]
          436     fn test_set_iemsi_settings() {
          437         let mut state: MainWindowState = MainWindowState::default();
          438         let mut settings = IEMSISettings::default();
          439         settings.alias = "foo".to_string();
          440         settings.voice_phone = "42".to_string();
          441         update_state(&mut state, Some(super::Message::UpdateIEMSI(settings)));
          442         assert_ne!(IEMSISettings::default(), state.options.iemsi);
          443         assert!(state.options_written);
          444     }
          445 }