diff --git a/Cargo.lock b/Cargo.lock index a2e4e4f..a3626bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1210,7 +1210,7 @@ dependencies = [ [[package]] name = "cosmic-config" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#e29ce0d4c1a3ff09913e4f0d3bfd5553fe5a770b" +source = "git+https://github.com/pop-os/libcosmic.git#91eae67dd59c70283590253d5a98688093017ebe" dependencies = [ "atomicwrites", "cosmic-config-derive", @@ -1232,7 +1232,7 @@ dependencies = [ [[package]] name = "cosmic-config-derive" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#e29ce0d4c1a3ff09913e4f0d3bfd5553fe5a770b" +source = "git+https://github.com/pop-os/libcosmic.git#91eae67dd59c70283590253d5a98688093017ebe" dependencies = [ "quote", "syn 1.0.109", @@ -1373,7 +1373,7 @@ dependencies = [ [[package]] name = "cosmic-theme" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#e29ce0d4c1a3ff09913e4f0d3bfd5553fe5a770b" +source = "git+https://github.com/pop-os/libcosmic.git#91eae67dd59c70283590253d5a98688093017ebe" dependencies = [ "almost", "cosmic-config", @@ -2164,9 +2164,9 @@ dependencies = [ [[package]] name = "freedesktop-desktop-entry" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6a4cdc5571033a6a329b9e8a8430594d1e3b60f42bb79e79686cadef34740ea" +checksum = "7e5e2bd2e383df08a8439c2e096be16d5355aa00f976b295cf8e077ea5953d5d" dependencies = [ "cached", "gettext-rs", @@ -2786,7 +2786,7 @@ dependencies = [ [[package]] name = "iced" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#e29ce0d4c1a3ff09913e4f0d3bfd5553fe5a770b" +source = "git+https://github.com/pop-os/libcosmic.git#91eae67dd59c70283590253d5a98688093017ebe" dependencies = [ "dnd", "iced_accessibility", @@ -2804,7 +2804,7 @@ dependencies = [ [[package]] name = "iced_accessibility" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#e29ce0d4c1a3ff09913e4f0d3bfd5553fe5a770b" +source = "git+https://github.com/pop-os/libcosmic.git#91eae67dd59c70283590253d5a98688093017ebe" dependencies = [ "accesskit", "accesskit_winit", @@ -2813,7 +2813,7 @@ dependencies = [ [[package]] name = "iced_core" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#e29ce0d4c1a3ff09913e4f0d3bfd5553fe5a770b" +source = "git+https://github.com/pop-os/libcosmic.git#91eae67dd59c70283590253d5a98688093017ebe" dependencies = [ "bitflags 2.9.0", "bytes", @@ -2837,7 +2837,7 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#e29ce0d4c1a3ff09913e4f0d3bfd5553fe5a770b" +source = "git+https://github.com/pop-os/libcosmic.git#91eae67dd59c70283590253d5a98688093017ebe" dependencies = [ "futures", "iced_core", @@ -2863,7 +2863,7 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#e29ce0d4c1a3ff09913e4f0d3bfd5553fe5a770b" +source = "git+https://github.com/pop-os/libcosmic.git#91eae67dd59c70283590253d5a98688093017ebe" dependencies = [ "bitflags 2.9.0", "bytemuck", @@ -2885,7 +2885,7 @@ dependencies = [ [[package]] name = "iced_renderer" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#e29ce0d4c1a3ff09913e4f0d3bfd5553fe5a770b" +source = "git+https://github.com/pop-os/libcosmic.git#91eae67dd59c70283590253d5a98688093017ebe" dependencies = [ "iced_graphics", "iced_tiny_skia", @@ -2897,7 +2897,7 @@ dependencies = [ [[package]] name = "iced_runtime" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#e29ce0d4c1a3ff09913e4f0d3bfd5553fe5a770b" +source = "git+https://github.com/pop-os/libcosmic.git#91eae67dd59c70283590253d5a98688093017ebe" dependencies = [ "bytes", "cosmic-client-toolkit", @@ -2912,7 +2912,7 @@ dependencies = [ [[package]] name = "iced_tiny_skia" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#e29ce0d4c1a3ff09913e4f0d3bfd5553fe5a770b" +source = "git+https://github.com/pop-os/libcosmic.git#91eae67dd59c70283590253d5a98688093017ebe" dependencies = [ "bytemuck", "cosmic-text", @@ -2928,7 +2928,7 @@ dependencies = [ [[package]] name = "iced_wgpu" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#e29ce0d4c1a3ff09913e4f0d3bfd5553fe5a770b" +source = "git+https://github.com/pop-os/libcosmic.git#91eae67dd59c70283590253d5a98688093017ebe" dependencies = [ "as-raw-xcb-connection", "bitflags 2.9.0", @@ -2959,7 +2959,7 @@ dependencies = [ [[package]] name = "iced_widget" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#e29ce0d4c1a3ff09913e4f0d3bfd5553fe5a770b" +source = "git+https://github.com/pop-os/libcosmic.git#91eae67dd59c70283590253d5a98688093017ebe" dependencies = [ "cosmic-client-toolkit", "dnd", @@ -2977,7 +2977,7 @@ dependencies = [ [[package]] name = "iced_winit" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#e29ce0d4c1a3ff09913e4f0d3bfd5553fe5a770b" +source = "git+https://github.com/pop-os/libcosmic.git#91eae67dd59c70283590253d5a98688093017ebe" dependencies = [ "cosmic-client-toolkit", "dnd", @@ -3557,7 +3557,7 @@ checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" [[package]] name = "libcosmic" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#e29ce0d4c1a3ff09913e4f0d3bfd5553fe5a770b" +source = "git+https://github.com/pop-os/libcosmic.git#91eae67dd59c70283590253d5a98688093017ebe" dependencies = [ "apply", "ashpd 0.9.2", diff --git a/src/dialog.rs b/src/dialog.rs index e506b9d..b780505 100644 --- a/src/dialog.rs +++ b/src/dialog.rs @@ -13,7 +13,7 @@ use cosmic::{ theme, widget::{ self, - menu::{Action as MenuAction, KeyBind}, + menu::{key_bind::Modifier, Action as MenuAction, KeyBind}, segmented_button, }, Application, ApplicationExt, Element, @@ -139,6 +139,71 @@ impl AsRef for DialogFilter { } } +#[derive(Clone, Debug)] +pub struct DialogLabelSpan { + pub text: String, + pub underline: bool, +} + +#[derive(Clone, Debug)] +pub struct DialogLabel { + pub spans: Vec, + pub key_bind_opt: Option, +} + +impl> From for DialogLabel { + fn from(text: T) -> Self { + let mut spans = Vec::::new(); + let mut key_bind_opt = None; + let mut next_underline = false; + for c in text.as_ref().chars() { + let underline = next_underline; + next_underline = false; + + if c == '_' { + if !underline { + next_underline = true; + continue; + } + } + + if underline && key_bind_opt.is_none() { + key_bind_opt = Some(KeyBind { + modifiers: vec![Modifier::Alt], + key: Key::Character(c.to_lowercase().to_string().into()), + }); + } + + if let Some(span) = spans.last_mut() { + if underline == span.underline { + span.text.push(c); + continue; + } + } + + spans.push(DialogLabelSpan { + text: String::from(c), + underline, + }); + } + + dbg!(Self { + spans, + key_bind_opt + }) + } +} + +impl<'a, M: Clone + 'static> From<&'a DialogLabel> for Element<'a, M> { + fn from(label: &'a DialogLabel) -> Self { + let mut iced_spans = Vec::with_capacity(label.spans.len()); + for span in label.spans.iter() { + iced_spans.push(cosmic::iced::widget::span(&span.text).underline(span.underline)); + } + cosmic::iced::widget::rich_text(iced_spans).into() + } +} + pub struct Dialog { cosmic: Cosmic, mapper: fn(DialogMessage) -> M, @@ -218,8 +283,8 @@ impl Dialog { .map(move |message| cosmic::action::app(mapper(message))) } - pub fn set_accept_label(&mut self, accept_label: impl Into) { - self.cosmic.app.accept_label = accept_label.into(); + pub fn set_accept_label(&mut self, accept_label: impl AsRef) { + self.cosmic.app.accept_label = DialogLabel::from(accept_label); } pub fn choices(&self) -> &[DialogChoice] { @@ -388,7 +453,7 @@ struct App { core: Core, flags: Flags, title: String, - accept_label: String, + accept_label: DialogLabel, choices: Vec, context_page: ContextPage, dialog_pages: VecDeque, @@ -409,8 +474,11 @@ struct App { impl App { fn button_view(&self) -> Element { let cosmic_theme::Spacing { + space_xxxs, space_xxs, space_xs, + space_s, + space_l, .. } = theme::active().cosmic().spacing; @@ -458,11 +526,37 @@ impl App { } row = row.push(widget::horizontal_space()); 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) - }); + + let mut has_selected = false; + if let Some(items) = self.tab.items_opt() { + for item in items.iter() { + if item.selected { + has_selected = true; + break; + } + } + } + row = row.push( + //TODO: easier way to create buttons with rich text + widget::button::custom( + widget::row::with_children(vec![Element::from(&self.accept_label)]) + .padding([0, space_s]) + .width(Length::Shrink) + .height(space_l) + .spacing(space_xxxs) + .align_y(Alignment::Center) + ) + .padding(0) + .on_press_maybe(if self.flags.kind.save() { + Some(Message::Save(false)) + } else if has_selected { + Some(Message::Open) + } else { + None + }) + .class(widget::button::ButtonClass::Suggested) + /*TODO: a11y feature: .label(&self.accept_label.text)*/ + ); col = col.push(row); @@ -786,7 +880,7 @@ impl Application for App { core, flags, title, - accept_label, + accept_label: DialogLabel::from(accept_label), choices: Vec::new(), context_page: ContextPage::Preview(None, PreviewKind::Selected), dialog_pages: VecDeque::new(), @@ -1174,6 +1268,15 @@ impl Application for App { return self.update(Message::from(action.message())); } } + if let Some(key_bind) = &self.accept_label.key_bind_opt { + if key_bind.matches(modifiers, &key) { + return self.update(if self.flags.kind.save() { + Message::Save(false) + } else { + Message::Open + }); + } + } } Message::Modifiers(modifiers) => { self.modifiers = modifiers;