diff --git a/src/main.rs b/src/main.rs index 80a769e..6f6b1d3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,17 +6,16 @@ use std::{env, path::PathBuf, process}; use gtk::prelude::*; use mcdu::McduModel; use relm4::prelude::*; -use sheet_listing::SheetListingModel; +use sheet_listing::{SheetListingInput, SheetListingModel}; struct AppModel { - text: String, mcdu: Controller, sheet_listing: Controller, } #[derive(Debug)] enum AppInput { - McduInput(char), + SearchStarted(String), SheetPressed(PathBuf), } @@ -44,17 +43,7 @@ impl SimpleComponent for AppModel { // set_hscrollbar_policy: PolicyType::Never, }, }, - gtk::Box { - set_orientation: gtk::Orientation::Vertical, - set_valign: gtk::Align::Center, - model.mcdu.widget(), - #[name = "label"] - gtk::Label { - #[watch] - set_label: &model.text, - set_margin_all: 5, - } - }, + model.mcdu.widget(), } } } @@ -69,7 +58,7 @@ impl SimpleComponent for AppModel { let mcdu = McduModel::builder() .launch(()) .forward(sender.input_sender(), |response| match response { - mcdu::McduOutput::ButtonPress(c) => AppInput::McduInput(c), + mcdu::McduOutput::SearchStarted(query) => AppInput::SearchStarted(query), }); let sheet_listing = @@ -82,7 +71,6 @@ impl SimpleComponent for AppModel { }); let model = AppModel { - text: String::from("Text: "), mcdu, sheet_listing, }; @@ -94,8 +82,8 @@ impl SimpleComponent for AppModel { fn update(&mut self, message: Self::Input, _sender: ComponentSender) { match message { - AppInput::McduInput(c) => self.text.push(c), AppInput::SheetPressed(sheet) => opener::open(sheet).unwrap(), + AppInput::SearchStarted(query) => self.sheet_listing.emit(SheetListingInput { query }), } } } diff --git a/src/mcdu.rs b/src/mcdu.rs index 0611947..a18646b 100644 --- a/src/mcdu.rs +++ b/src/mcdu.rs @@ -1,24 +1,57 @@ use relm4::gtk::{glib, prelude::*}; use relm4::{gtk, ComponentParts, ComponentSender, SimpleComponent}; -pub struct McduModel; +pub struct McduModel { + query: String, + query_changed_by_mcdu_keys: bool, +} + +impl McduModel { + fn new() -> Self { + McduModel { + query: String::new(), + query_changed_by_mcdu_keys: false, + } + } +} #[derive(Debug)] pub enum McduOutput { + SearchStarted(String), +} + +#[derive(Debug)] +pub enum KeyboardEvent { ButtonPress(char), + SearchStarted(String), + QueryChanged(String), } #[relm4::component(pub)] impl SimpleComponent for McduModel { type Init = (); - type Input = (); + type Input = KeyboardEvent; type Output = McduOutput; view! { #[root] - gtk::Grid { - set_column_spacing: 5, - set_row_spacing: 5, + gtk::Box { + set_orientation: gtk::Orientation::Vertical, + set_valign: gtk::Align::Center, + gtk::SearchEntry { + set_margin_bottom: 10, + + #[block_signal(change_handler, search_handler)] + #[track = "model.query_changed_by_mcdu_keys"] + set_text: &model.query, + connect_changed[sender] => move |search_entry| sender.input(KeyboardEvent::QueryChanged(search_entry.text().to_string())) @change_handler, + connect_search_changed[sender] => move |search_entry| sender.input(KeyboardEvent::SearchStarted(search_entry.text().to_string())) @search_handler, + }, + #[name = "keyboard"] + gtk::Grid { + set_column_spacing: 5, + set_row_spacing: 5, + } } } @@ -27,6 +60,9 @@ impl SimpleComponent for McduModel { root: &Self::Root, sender: ComponentSender, ) -> ComponentParts { + let model = McduModel::new(); + let widgets = view_output!(); + let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; let mcdu_width = 6; @@ -34,17 +70,33 @@ impl SimpleComponent for McduModel { let button = gtk::Button::default(); button.set_label(&c.to_string()); button.connect_clicked(glib::clone!(@strong sender => move |_| { - sender.output(McduOutput::ButtonPress(c)).unwrap(); + sender.input(KeyboardEvent::ButtonPress(c)); })); let column = i % mcdu_width; let row = (i - column) / mcdu_width; - root.attach(&button, column as i32, row as i32, 1, 1); + widgets + .keyboard + .attach(&button, column as i32, row as i32, 1, 1); } - let model = McduModel; - let widgets = view_output!(); ComponentParts { model, widgets } } + + fn update(&mut self, message: Self::Input, sender: ComponentSender) { + self.query_changed_by_mcdu_keys = false; + match message { + KeyboardEvent::ButtonPress(c) => { + // println!("Button press: {}", c); + self.query_changed_by_mcdu_keys = true; + self.query.push(c); + } + KeyboardEvent::SearchStarted(s) => { + // println!("Started search: {}", s); + sender.output(McduOutput::SearchStarted(s)).unwrap(); + } + KeyboardEvent::QueryChanged(query) => self.query = query, + } + } } diff --git a/src/sheet_listing.rs b/src/sheet_listing.rs index fb0d56d..162023d 100644 --- a/src/sheet_listing.rs +++ b/src/sheet_listing.rs @@ -9,11 +9,13 @@ use walkdir::WalkDir; pub struct SheetModel { path: PathBuf, + visible: bool, } #[derive(Debug)] pub enum SheetModelInput { OnClicked, + SearchChanged(String), } #[derive(Debug)] @@ -30,6 +32,8 @@ impl SimpleComponent for SheetModel { view! { #[root] gtk::Box { + #[watch] + set_visible: model.visible, set_orientation: gtk::Orientation::Vertical, append = >k::Button { set_label: &format!("{}", model.path.file_name().unwrap().to_string_lossy()), @@ -45,7 +49,10 @@ impl SimpleComponent for SheetModel { root: &Self::Root, sender: ComponentSender, ) -> ComponentParts { - let model = SheetModel { path }; + let model = SheetModel { + path, + visible: true, + }; let widgets = view_output!(); ComponentParts { model, widgets } } @@ -55,18 +62,33 @@ impl SimpleComponent for SheetModel { SheetModelInput::OnClicked => sender .output(SheetPressedMessage::SheetPressed(self.path.clone())) .unwrap(), + SheetModelInput::SearchChanged(query) => { + self.visible = self + .path + .file_name() + .unwrap() + .to_string_lossy() + .to_lowercase() + .contains(&query.to_lowercase()); + } } } } pub struct SheetListingModel { - _sheet_models: Vec>, + query: String, + sheet_models: Vec>, +} + +#[derive(Debug)] +pub struct SheetListingInput { + pub query: String, } #[relm4::component(pub)] impl SimpleComponent for SheetListingModel { type Init = PathBuf; - type Input = (); + type Input = SheetListingInput; type Output = SheetPressedMessage; view! { @@ -102,9 +124,17 @@ impl SimpleComponent for SheetListingModel { } let model = SheetListingModel { - _sheet_models: sheet_models, + query: String::new(), + sheet_models: sheet_models, }; let widgets = view_output!(); ComponentParts { model, widgets } } + + fn update(&mut self, message: Self::Input, sender: ComponentSender) { + self.query = message.query; + for model in self.sheet_models.iter() { + model.emit(SheetModelInput::SearchChanged(self.query.clone())); + } + } }