diff --git a/Cargo.lock b/Cargo.lock index 7c9959ea..2aef3ad0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3293,6 +3293,7 @@ version = "0.4.0" dependencies = [ "camino", "egui", + "fuzzy-matcher", "luminol-audio", "luminol-components", "luminol-core", diff --git a/crates/core/src/modal.rs b/crates/core/src/modal.rs index 0cad1f8f..ea6c325a 100644 --- a/crates/core/src/modal.rs +++ b/crates/core/src/modal.rs @@ -39,4 +39,6 @@ pub trait Modal: Sized { data: &'m mut Self::Data, update_state: &'m mut crate::UpdateState<'_>, ) -> impl egui::Widget + 'm; + + fn reset(&mut self); } diff --git a/crates/modals/Cargo.toml b/crates/modals/Cargo.toml index 3187888b..52424d58 100644 --- a/crates/modals/Cargo.toml +++ b/crates/modals/Cargo.toml @@ -27,3 +27,5 @@ luminol-data.workspace = true luminol-components.workspace = true luminol-filesystem.workspace = true luminol-graphics.workspace = true + +fuzzy-matcher = "0.3.7" diff --git a/crates/modals/src/event_graphic_picker.rs b/crates/modals/src/event_graphic_picker.rs index 2d87cadf..6ded9d07 100644 --- a/crates/modals/src/event_graphic_picker.rs +++ b/crates/modals/src/event_graphic_picker.rs @@ -124,6 +124,10 @@ impl luminol_core::Modal for Modal { button_response } } + + fn reset(&mut self) { + todo!() + } } impl Modal { diff --git a/crates/modals/src/graphic_picker.rs b/crates/modals/src/graphic_picker.rs index 6671bb77..4c7102f6 100644 --- a/crates/modals/src/graphic_picker.rs +++ b/crates/modals/src/graphic_picker.rs @@ -86,6 +86,10 @@ impl luminol_core::Modal for Modal { button_response } } + + fn reset(&mut self) { + todo!() + } } impl Modal { diff --git a/crates/modals/src/sound_picker.rs b/crates/modals/src/sound_picker.rs index 1d19de30..32c19d49 100644 --- a/crates/modals/src/sound_picker.rs +++ b/crates/modals/src/sound_picker.rs @@ -65,6 +65,11 @@ impl luminol_core::Modal for Modal { button_response } } + + fn reset(&mut self) { + self.tab.audio_file.name = None; + self.open = false; + } } impl Modal { diff --git a/crates/modals/src/switch.rs b/crates/modals/src/switch.rs index b806ed9b..b0c2c0aa 100644 --- a/crates/modals/src/switch.rs +++ b/crates/modals/src/switch.rs @@ -22,11 +22,14 @@ // terms of the Steamworks API by Valve Corporation, the licensors of this // Program grant you additional permission to convey the resulting work. +use luminol_components::UiExt; + +#[derive(Default)] /// The switch picker modal. pub enum Modal { + #[default] Closed, Open { - switch_id_range: std::ops::Range, search_text: String, switch_id: usize, }, @@ -44,7 +47,7 @@ impl luminol_core::Modal for Modal { let button_text = if ui.is_enabled() { let system = update_state.data.system(); *data = system.switches.len().min(*data); - format!("{data:0>3}: {}", system.switches[*data]) + format!("{:0>3}: {}", *data + 1, system.switches[*data]) } else { "...".to_string() }; @@ -52,7 +55,6 @@ impl luminol_core::Modal for Modal { if button_response.clicked() { *self = Self::Open { - switch_id_range: *data..*data, search_text: String::new(), switch_id: *data, }; @@ -64,6 +66,10 @@ impl luminol_core::Modal for Modal { button_response } } + + fn reset(&mut self) { + *self = Self::Closed; + } } impl Modal { @@ -78,7 +84,6 @@ impl Modal { let mut needs_save = false; let Self::Open { - switch_id_range, search_text, switch_id, } = self @@ -92,37 +97,26 @@ impl Modal { .show(ctx, |ui| { let system = update_state.data.system(); + let matcher = fuzzy_matcher::skim::SkimMatcherV2::default(); + ui.group(|ui| { egui::ScrollArea::vertical() .auto_shrink([false, false]) .max_height(384.) .show(ui, |ui| { - for (id, name) in - system.switches.iter().enumerate().filter(|(id, s)| { - (id + 1).to_string().contains(search_text.as_str()) - || s.contains(search_text.as_str()) - }) - { - let id = id + 1; - let mut text = egui::RichText::new(format!("{id}: {name}")); - - if switch_id_range.start == id { - text = text.color(egui::Color32::YELLOW); + for (id, name) in system.switches.iter().enumerate() { + let text = format!("{:0>3}: {name}", id + 1); + if matcher.fuzzy(&text, search_text, false).is_none() { + continue; } - let response = ui.selectable_value(switch_id, id, text); - - if switch_id_range.end == id { - switch_id_range.end = usize::MAX; - switch_id_range.start = id; - - response.scroll_to_me(None); - } - - if response.double_clicked() { - keep_open = false; - needs_save = true; - } + ui.with_stripe(id % 2 == 0, |ui| { + let response = ui.selectable_value(switch_id, id, text); + if response.double_clicked() { + keep_open = false; + needs_save = true; + } + }); } }) }); @@ -130,15 +124,6 @@ impl Modal { ui.horizontal(|ui| { luminol_components::close_options_ui(ui, &mut keep_open, &mut needs_save); - if ui - .add( - egui::DragValue::new(&mut switch_id_range.start) - .clamp_range(0..=system.switches.len()), - ) - .changed() - { - switch_id_range.end = switch_id_range.start; - }; egui::TextEdit::singleline(search_text) .hint_text("Search 🔎") .show(ui); diff --git a/crates/modals/src/variable.rs b/crates/modals/src/variable.rs index b7a8f5f8..3b6b84db 100644 --- a/crates/modals/src/variable.rs +++ b/crates/modals/src/variable.rs @@ -22,11 +22,14 @@ // terms of the Steamworks API by Valve Corporation, the licensors of this // Program grant you additional permission to convey the resulting work. +use luminol_components::UiExt; + +#[derive(Default)] /// The variable picker modal. pub enum Modal { + #[default] Closed, Open { - variable_id_range: std::ops::Range, search_text: String, variable_id: usize, }, @@ -44,7 +47,7 @@ impl luminol_core::Modal for Modal { let button_text = if ui.is_enabled() { let system = update_state.data.system(); *data = system.variables.len().min(*data); - format!("{data:0>3}: {}", system.variables[*data]) + format!("{:0>3}: {}", *data + 1, system.variables[*data]) } else { "...".to_string() }; @@ -52,7 +55,6 @@ impl luminol_core::Modal for Modal { if button_response.clicked() { *self = Self::Open { - variable_id_range: *data..*data, search_text: String::new(), variable_id: *data, }; @@ -64,6 +66,10 @@ impl luminol_core::Modal for Modal { button_response } } + + fn reset(&mut self) { + *self = Self::Closed; + } } impl Modal { @@ -78,7 +84,6 @@ impl Modal { let mut needs_save = false; let Self::Open { - variable_id_range, search_text, variable_id, } = self @@ -92,37 +97,26 @@ impl Modal { .show(ctx, |ui| { let system = update_state.data.system(); + let matcher = fuzzy_matcher::skim::SkimMatcherV2::default(); + ui.group(|ui| { egui::ScrollArea::vertical() .auto_shrink([false, false]) .max_height(384.) .show(ui, |ui| { - for (id, name) in - system.variables.iter().enumerate().filter(|(id, s)| { - (id + 1).to_string().contains(search_text.as_str()) - || s.contains(search_text.as_str()) - }) - { - let id = id + 1; - let mut text = egui::RichText::new(format!("{id}: {name}")); - - if variable_id_range.start == id { - text = text.color(egui::Color32::YELLOW); + for (id, name) in system.variables.iter().enumerate() { + let text = format!("{:0>3}: {name}", id + 1); + if matcher.fuzzy(&text, search_text, false).is_none() { + continue; } - let response = ui.selectable_value(variable_id, id, text); - - if variable_id_range.end == id { - variable_id_range.end = usize::MAX; - variable_id_range.start = id; - - response.scroll_to_me(None); - } - - if response.double_clicked() { - keep_open = false; - needs_save = true; - } + ui.with_stripe(id % 2 == 0, |ui| { + let response = ui.selectable_value(variable_id, id, text); + if response.double_clicked() { + keep_open = false; + needs_save = true; + } + }); } }) }); @@ -130,15 +124,6 @@ impl Modal { ui.horizontal(|ui| { luminol_components::close_options_ui(ui, &mut keep_open, &mut needs_save); - if ui - .add( - egui::DragValue::new(&mut variable_id_range.start) - .clamp_range(0..=system.variables.len()), - ) - .changed() - { - variable_id_range.end = variable_id_range.start; - }; egui::TextEdit::singleline(search_text) .hint_text("Search 🔎") .show(ui); diff --git a/crates/ui/src/windows/event_edit.rs b/crates/ui/src/windows/event_edit.rs index b1612c62..08a96c8c 100644 --- a/crates/ui/src/windows/event_edit.rs +++ b/crates/ui/src/windows/event_edit.rs @@ -34,21 +34,43 @@ pub struct Window { tab: Tab, event: rpg::Event, - switch_1_modal: switch::Modal, - switch_2_modal: switch::Modal, - variable_modal: variable::Modal, - graphic_picker: event_graphic_picker::Modal, page_graphic: EventGraphic, + graphic_picker: event_graphic_picker::Modal, } -#[derive(strum::Display, strum::EnumIter, PartialEq)] +#[derive(strum::Display, strum::EnumIter)] enum Tab { - Configuration, + Configuration { + switch_1_modal: switch::Modal, + switch_2_modal: switch::Modal, + variable_modal: variable::Modal, + }, Movement, Commands, Graphic, } +impl PartialEq for Tab { + fn eq(&self, other: &Tab) -> bool { + std::mem::discriminant(self) == std::mem::discriminant(other) + } +} + +impl Tab { + fn reset(&mut self) { + if let Tab::Configuration { + switch_1_modal, + switch_2_modal, + variable_modal, + } = self + { + switch_1_modal.reset(); + switch_2_modal.reset(); + variable_modal.reset(); + } + } +} + enum EventGraphic { Unloaded, NonePresent, @@ -73,9 +95,6 @@ impl Window { tab: Tab::Commands, event, - switch_1_modal: switch::Modal::Closed, - switch_2_modal: switch::Modal::Closed, - variable_modal: variable::Modal::Closed, page_graphic: EventGraphic::Unloaded, graphic_picker, } @@ -129,10 +148,15 @@ impl luminol_core::Window for Window { ui.horizontal(|ui| { for page in 0..self.event.pages.len() { if ui - .selectable_value(&mut self.selected_page, page, format!("Page {page}")) + .selectable_value( + &mut self.selected_page, + page, + format!("Page {}", page + 1), + ) .changed() { self.page_graphic = EventGraphic::Unloaded; + self.tab.reset(); } } }); @@ -167,14 +191,18 @@ impl luminol_core::Window for Window { } } - match self.tab { - Tab::Configuration => { + match &mut self.tab { + Tab::Configuration { + switch_1_modal, + switch_2_modal, + variable_modal, + } => { ui.columns(2, |columns| { columns[0].horizontal(|ui| { ui.checkbox(&mut page.condition.switch1_valid, "Switch"); ui.add_enabled( page.condition.switch1_valid, - self.switch_1_modal + switch_1_modal .button(&mut page.condition.switch1_id, update_state), ); ui.label("is ON"); @@ -183,7 +211,7 @@ impl luminol_core::Window for Window { ui.checkbox(&mut page.condition.switch2_valid, "Switch"); ui.add_enabled( page.condition.switch2_valid, - self.switch_2_modal + switch_2_modal .button(&mut page.condition.switch2_id, update_state), ); ui.label("is ON"); @@ -192,7 +220,7 @@ impl luminol_core::Window for Window { ui.checkbox(&mut page.condition.variable_valid, "Variable"); ui.add_enabled( page.condition.variable_valid, - self.variable_modal + variable_modal .button(&mut page.condition.variable_id, update_state), ); ui.label("is");