diff --git a/src/dialog.rs b/src/dialog.rs index c476acc..6950fda 100644 --- a/src/dialog.rs +++ b/src/dialog.rs @@ -14,7 +14,7 @@ use cosmic::{ keyboard::{Event as KeyEvent, Modifiers}, subscription::{self, Subscription}, widget::scrollable, - window, Event, Length, Size, + window, Alignment, Event, Length, Size, }, theme, widget::{self, menu::KeyBind, segmented_button}, @@ -69,6 +69,13 @@ impl DialogKind { } } + pub fn accept_label(&self) -> String { + match self { + Self::SaveFile { .. } => fl!("save"), + _ => fl!("open"), + } + } + pub fn is_dir(&self) -> bool { matches!(self, Self::OpenFolder | Self::OpenMultipleFolders) } @@ -82,6 +89,31 @@ impl DialogKind { } } +pub struct DialogChoiceOption { + pub id: String, + pub label: String, +} + +impl AsRef for DialogChoiceOption { + fn as_ref(&self) -> &str { + &self.label + } +} + +pub enum DialogChoice { + CheckBox { + id: String, + label: String, + value: bool, + }, + ComboBox { + id: String, + label: String, + options: Vec, + selected: Option, + }, +} + pub struct Dialog { cosmic: Cosmic, mapper: fn(DialogMessage) -> M, @@ -142,6 +174,28 @@ impl Dialog { ) } + pub fn set_title(&mut self, title: impl Into) -> Command { + let mapper = self.mapper; + self.cosmic.app.title = title.into(); + self.cosmic + .app + .update_title() + .map(DialogMessage) + .map(move |message| app::Message::App(mapper(message))) + } + + pub fn set_accept_label(&mut self, accept_label: impl Into) { + self.cosmic.app.accept_label = accept_label.into(); + } + + pub fn choices(&self) -> &[DialogChoice] { + &self.cosmic.app.choices + } + + pub fn set_choices(&mut self, choices: impl Into>) { + self.cosmic.app.choices = choices.into(); + } + pub fn subscription(&self) -> Subscription { self.cosmic .subscription() @@ -186,6 +240,7 @@ struct Flags { #[derive(Clone, Debug)] enum Message { Cancel, + Choice(usize, usize), Filename(String), Modifiers(Modifiers), NotifyEvents(Vec), @@ -222,6 +277,9 @@ impl PartialEq for WatcherWrapper { struct App { core: Core, flags: Flags, + title: String, + accept_label: String, + choices: Vec, filename_id: widget::Id, modifiers: Modifiers, nav_model: segmented_button::SingleSelectModel, @@ -251,9 +309,8 @@ impl App { } fn update_title(&mut self) -> Command { - let title = self.flags.kind.title(); - self.set_header_title(title.clone()); - self.set_window_title(title, self.main_window_id()) + self.set_header_title(self.title.clone()); + self.set_window_title(self.title.clone(), self.main_window_id()) } fn update_watcher(&mut self) -> Command { @@ -332,6 +389,9 @@ impl Application for App { //TODO: make set_nav_bar_toggle_condensed pub core.nav_bar_toggle_condensed(); + let title = flags.kind.title(); + let accept_label = flags.kind.accept_label(); + let mut nav_model = segmented_button::ModelBuilder::default(); if let Some(dir) = dirs::home_dir() { nav_model = nav_model.insert(move |b| { @@ -374,6 +434,9 @@ impl Application for App { let mut app = App { core, flags, + title, + accept_label, + choices: Vec::new(), filename_id: widget::Id::unique(), modifiers: Modifiers::empty(), nav_model: nav_model.build(), @@ -448,6 +511,22 @@ impl Application for App { return window::close(self.main_window_id()); } } + Message::Choice(choice_i, option_i) => { + if let Some(choice) = self.choices.get_mut(choice_i) { + match choice { + DialogChoice::CheckBox { value, .. } => *value = option_i > 0, + DialogChoice::ComboBox { + options, selected, .. + } => { + if option_i < options.len() { + *selected = Some(option_i); + } else { + *selected = None; + } + } + } + } + } Message::Filename(new_filename) => { // Select based on filename self.tab.select_name(&new_filename); @@ -693,30 +772,49 @@ impl Application for App { .map(move |message| Message::TabMessage(message)), ); - tab_column = tab_column.push( - widget::row::with_children(vec![ - if let DialogKind::SaveFile { filename } = &self.flags.kind { - widget::text_input("", filename) - .id(self.filename_id.clone()) - .on_input(Message::Filename) - .on_submit(Message::Save(false)) - .into() - } else { - widget::horizontal_space(Length::Fill).into() - }, - widget::button::standard(fl!("cancel")) - .on_press(Message::Cancel) - .into(), - if self.flags.kind.save() { - widget::button::suggested(fl!("save")).on_press(Message::Save(false)) - } else { - widget::button::suggested(fl!("open")).on_press(Message::Open) - } - .into(), - ]) + let mut row = widget::row::with_capacity(self.choices.len() * 2 + 3) + .align_items(Alignment::Center) .padding(space_xxs) - .spacing(space_xxs), - ); + .spacing(space_xxs); + if let DialogKind::SaveFile { filename } = &self.flags.kind { + row = row.push( + widget::text_input("", filename) + .id(self.filename_id.clone()) + .on_input(Message::Filename) + .on_submit(Message::Save(false)), + ); + } else { + row = row.push(widget::horizontal_space(Length::Fill)); + } + for (choice_i, choice) in self.choices.iter().enumerate() { + match choice { + DialogChoice::CheckBox { label, value, .. } => { + row = row.push(widget::text::body(label)); + row = row.push(widget::checkbox("", *value, move |checked| { + Message::Choice(choice_i, if checked { 1 } else { 0 }) + })); + } + DialogChoice::ComboBox { + label, + options, + selected, + .. + } => { + row = row.push(widget::text::body(label)); + row = row.push(widget::dropdown(options, *selected, move |option_i| { + Message::Choice(choice_i, option_i) + })); + } + } + } + row = row.push(widget::button::standard(fl!("cancel")).on_press(Message::Cancel)); + row = row.push(if self.flags.kind.save() { + widget::button::suggested(&self.accept_label).on_press(Message::Save(false)) + } else { + widget::button::suggested(&self.accept_label).on_press(Message::Open) + }); + + tab_column = tab_column.push(row); let content: Element<_> = tab_column.into();