diff --git a/examples/cosmic-sctk/src/main.rs b/examples/cosmic-sctk/src/main.rs index 343a4b0..16c9af7 100644 --- a/examples/cosmic-sctk/src/main.rs +++ b/examples/cosmic-sctk/src/main.rs @@ -7,6 +7,7 @@ mod window; pub use window::Window; pub fn main() -> cosmic::iced::Result { + settings::set_default_icon_theme("Pop"); let mut settings = settings(); settings.initial_surface = InitialSurface::XdgWindow(Default::default()); Window::run(settings) diff --git a/examples/cosmic/src/main.rs b/examples/cosmic/src/main.rs index d289e54..1d1f2bf 100644 --- a/examples/cosmic/src/main.rs +++ b/examples/cosmic/src/main.rs @@ -7,9 +7,8 @@ mod window; pub use window::*; pub fn main() -> cosmic::iced::Result { + settings::set_default_icon_theme("Pop"); let mut settings = settings(); settings.window.min_size = Some((600, 300)); - // TODO: Window resize handles not functioning yet - settings.window.decorations = false; Window::run(settings) } diff --git a/examples/cosmic/src/window.rs b/examples/cosmic/src/window.rs index 8fb61da..39ffef6 100644 --- a/examples/cosmic/src/window.rs +++ b/examples/cosmic/src/window.rs @@ -19,7 +19,7 @@ mod bluetooth; mod demo; -use self::{demo::DemoView, desktop::DesktopPage}; +use self::desktop::DesktopPage; mod desktop; use self::input_devices::InputDevicesPage; @@ -272,28 +272,8 @@ impl Application for Window { .sidebar_toggled(true) .show_maximize(true) .show_minimize(true); - window.demo.slider_value = 50.0; - // window.theme = Theme::Light; - window.demo.pick_list_selected = Some("Option 1"); + window.title = String::from("COSMIC Design System - Iced"); - window.demo.spin_button.min = -10; - window.demo.spin_button.max = 10; - - // Configures the demo view switcher. - let key = window.demo.view_switcher.insert("Controls", DemoView::TabA); - window.demo.view_switcher.activate(key); - window - .demo - .view_switcher - .insert("Segmented Button", DemoView::TabB); - window.demo.view_switcher.insert("Tab C", DemoView::TabC); - - // Configures the demo selection button. - let key = window.demo.selection.insert("Choice A", ()); - window.demo.selection.activate(key); - window.demo.selection.insert("Choice B", ()); - window.demo.selection.insert("Choice C", ()); - (window, Command::none()) } diff --git a/examples/cosmic/src/window/demo.rs b/examples/cosmic/src/window/demo.rs index f111719..a5f96fc 100644 --- a/examples/cosmic/src/window/demo.rs +++ b/examples/cosmic/src/window/demo.rs @@ -30,6 +30,7 @@ pub enum Message { ButtonPressed, CheckboxToggled(bool), Debug(bool), + IconTheme(segmented_button::Key), PickListSelected(&'static str), RowSelected(usize), Selection(segmented_button::Key), @@ -45,9 +46,9 @@ pub enum Output { ThemeChanged(Theme), } -#[derive(Default)] pub struct State { pub checkbox_value: bool, + pub icon_theme: segmented_button::State<&'static str>, pub pick_list_selected: Option<&'static str>, pub selection: segmented_button::State<()>, pub slider_value: f32, @@ -56,6 +57,41 @@ pub struct State { pub view_switcher: segmented_button::State, } +impl Default for State { + fn default() -> State { + State { + checkbox_value: false, + pick_list_selected: Some("Option 1"), + slider_value: 50.0, + spin_button: SpinButtonModel::default().min(-10).max(10), + toggler_value: false, + icon_theme: { + let mut icon_theme = segmented_button::State::default(); + let key = icon_theme.insert("Pop", "Pop"); + icon_theme.activate(key); + icon_theme.insert("Adwaita", "Adwaita"); + icon_theme + }, + selection: { + let mut selection = segmented_button::State::default(); + let key = selection.insert("Choice A", ()); + selection.activate(key); + selection.insert("Choice B", ()); + selection.insert("Choice C", ()); + selection + }, + view_switcher: { + let mut view_switcher = segmented_button::State::default(); + let key = view_switcher.insert("Controls", DemoView::TabA); + view_switcher.activate(key); + view_switcher.insert("Segmented Button", DemoView::TabB); + view_switcher.insert("Tab C", DemoView::TabC); + view_switcher + }, + } + } +} + impl State { pub(super) fn update(&mut self, message: Message) -> Option { match message { @@ -70,6 +106,12 @@ impl State { Message::ThemeChanged(theme) => return Some(Output::ThemeChanged(theme)), Message::TogglerToggled(value) => self.toggler_value = value, Message::ViewSwitcher(key) => self.view_switcher.activate(key), + Message::IconTheme(key) => { + self.icon_theme.activate(key); + if let Some(theme) = self.icon_theme.data(key) { + cosmic::settings::set_default_icon_theme(*theme); + } + } } None @@ -88,6 +130,9 @@ impl State { }, ); + let choose_icon_theme = + horizontal_segmented_selection(&self.icon_theme).on_activate(Message::IconTheme); + settings::view_column(vec![ window.page_title(Page::Demo), horizontal_view_switcher(&self.view_switcher) @@ -98,6 +143,7 @@ impl State { Some(DemoView::TabA) => settings::view_column(vec![ settings::view_section("Debug") .add(settings::item("Debug theme", choose_theme)) + .add(settings::item("Debug icon theme", choose_icon_theme)) .add(settings::item( "Debug layout", toggler(None, window.debug, Message::Debug), diff --git a/src/lib.rs b/src/lib.rs index 53fbfe5..35242e7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,21 +16,12 @@ pub mod font; pub mod theme; pub mod widget; +pub mod settings; +pub use settings::settings; + mod ext; pub use ext::ElementExt; pub use theme::Theme; pub type Renderer = iced::Renderer; pub type Element<'a, Message> = iced::Element<'a, Message, Renderer>; - -#[must_use] -pub fn settings() -> iced::Settings { - iced::Settings { - default_font: match font::FONT { - iced::Font::Default => None, - iced::Font::External { bytes, .. } => Some(bytes), - }, - default_text_size: 18, - ..iced::Settings::default() - } -} diff --git a/src/settings.rs b/src/settings.rs new file mode 100644 index 0000000..b33c517 --- /dev/null +++ b/src/settings.rs @@ -0,0 +1,31 @@ +use crate::font; +use std::cell::RefCell; + +thread_local! { + /// The fallback icon theme to search if no icon theme was specified. + pub(crate) static DEFAULT_ICON_THEME: RefCell = RefCell::new(String::from("Pop")); +} + +/// The fallback icon theme to search if no icon theme was specified. +#[must_use] +pub fn default_icon_theme() -> String { + DEFAULT_ICON_THEME.with(|f| f.borrow().clone()) +} + +/// Set the fallback icon theme to search when loading system icons. +pub fn set_default_icon_theme(name: impl Into) { + DEFAULT_ICON_THEME.with(|f| *f.borrow_mut() = name.into()); +} + +/// Default iced settings for COSMIC applications. +#[must_use] +pub fn settings() -> iced::Settings { + iced::Settings { + default_font: match font::FONT { + iced::Font::Default => None, + iced::Font::External { bytes, .. } => Some(bytes), + }, + default_text_size: 18, + ..iced::Settings::default() + } +} diff --git a/src/widget/icon.rs b/src/widget/icon.rs index 9ed41f4..22f8061 100644 --- a/src/widget/icon.rs +++ b/src/widget/icon.rs @@ -10,9 +10,9 @@ use iced::{ ContentFit, Length, }; use std::{ - borrow::Cow, collections::hash_map::DefaultHasher, ffi::OsStr, hash::Hasher, path::Path, + borrow::Cow, collections::hash_map::DefaultHasher, ffi::OsStr, hash::Hash, hash::Hasher, + path::Path, path::PathBuf, }; -use std::{hash::Hash, path::PathBuf}; #[derive(Debug, Hash)] pub enum IconSource<'a> { @@ -112,18 +112,25 @@ impl<'a> Icon<'a> { let mut hasher = DefaultHasher::new(); self.hash(&mut hasher); - iced_lazy::lazy(hasher.finish(), move || -> Element { + if self.theme.is_none() { + crate::settings::DEFAULT_ICON_THEME.with(|f| f.borrow().hash(&mut hasher)); + } + + let hash = hasher.finish(); + + iced_lazy::lazy(hash, move || -> Element { let name_path_buffer: Option; let icon: Option<&Path> = match &self.name { IconSource::Path(path) => Some(path), IconSource::Name(name) => { - let mut builder = freedesktop_icons::lookup(name).with_size(self.size); - - if let Some(theme) = self.theme.as_deref() { - builder = builder.with_theme(theme); - } - - let icon = builder.with_cache().find(); + let icon = crate::settings::DEFAULT_ICON_THEME.with(|default_theme| { + let default_theme: &str = &default_theme.borrow(); + freedesktop_icons::lookup(name) + .with_size(self.size) + .with_theme(self.theme.as_deref().unwrap_or(default_theme)) + .with_cache() + .find() + }); name_path_buffer = if icon.is_none() { freedesktop_icons::lookup(name) diff --git a/src/widget/spin_button/mod.rs b/src/widget/spin_button/mod.rs index a15196c..ac85bad 100644 --- a/src/widget/spin_button/mod.rs +++ b/src/widget/spin_button/mod.rs @@ -45,7 +45,7 @@ impl SpinButton Element<'static, SpinMessage> { container( row![