feat(settings): global setting for icon theme
This commit is contained in:
parent
043485c68d
commit
7d018a2139
8 changed files with 103 additions and 48 deletions
|
|
@ -7,6 +7,7 @@ mod window;
|
||||||
pub use window::Window;
|
pub use window::Window;
|
||||||
|
|
||||||
pub fn main() -> cosmic::iced::Result {
|
pub fn main() -> cosmic::iced::Result {
|
||||||
|
settings::set_default_icon_theme("Pop");
|
||||||
let mut settings = settings();
|
let mut settings = settings();
|
||||||
settings.initial_surface = InitialSurface::XdgWindow(Default::default());
|
settings.initial_surface = InitialSurface::XdgWindow(Default::default());
|
||||||
Window::run(settings)
|
Window::run(settings)
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,8 @@ mod window;
|
||||||
pub use window::*;
|
pub use window::*;
|
||||||
|
|
||||||
pub fn main() -> cosmic::iced::Result {
|
pub fn main() -> cosmic::iced::Result {
|
||||||
|
settings::set_default_icon_theme("Pop");
|
||||||
let mut settings = settings();
|
let mut settings = settings();
|
||||||
settings.window.min_size = Some((600, 300));
|
settings.window.min_size = Some((600, 300));
|
||||||
// TODO: Window resize handles not functioning yet
|
|
||||||
settings.window.decorations = false;
|
|
||||||
Window::run(settings)
|
Window::run(settings)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ mod bluetooth;
|
||||||
|
|
||||||
mod demo;
|
mod demo;
|
||||||
|
|
||||||
use self::{demo::DemoView, desktop::DesktopPage};
|
use self::desktop::DesktopPage;
|
||||||
mod desktop;
|
mod desktop;
|
||||||
|
|
||||||
use self::input_devices::InputDevicesPage;
|
use self::input_devices::InputDevicesPage;
|
||||||
|
|
@ -272,28 +272,8 @@ impl Application for Window {
|
||||||
.sidebar_toggled(true)
|
.sidebar_toggled(true)
|
||||||
.show_maximize(true)
|
.show_maximize(true)
|
||||||
.show_minimize(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.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())
|
(window, Command::none())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ pub enum Message {
|
||||||
ButtonPressed,
|
ButtonPressed,
|
||||||
CheckboxToggled(bool),
|
CheckboxToggled(bool),
|
||||||
Debug(bool),
|
Debug(bool),
|
||||||
|
IconTheme(segmented_button::Key),
|
||||||
PickListSelected(&'static str),
|
PickListSelected(&'static str),
|
||||||
RowSelected(usize),
|
RowSelected(usize),
|
||||||
Selection(segmented_button::Key),
|
Selection(segmented_button::Key),
|
||||||
|
|
@ -45,9 +46,9 @@ pub enum Output {
|
||||||
ThemeChanged(Theme),
|
ThemeChanged(Theme),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct State {
|
pub struct State {
|
||||||
pub checkbox_value: bool,
|
pub checkbox_value: bool,
|
||||||
|
pub icon_theme: segmented_button::State<&'static str>,
|
||||||
pub pick_list_selected: Option<&'static str>,
|
pub pick_list_selected: Option<&'static str>,
|
||||||
pub selection: segmented_button::State<()>,
|
pub selection: segmented_button::State<()>,
|
||||||
pub slider_value: f32,
|
pub slider_value: f32,
|
||||||
|
|
@ -56,6 +57,41 @@ pub struct State {
|
||||||
pub view_switcher: segmented_button::State<DemoView>,
|
pub view_switcher: segmented_button::State<DemoView>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
impl State {
|
||||||
pub(super) fn update(&mut self, message: Message) -> Option<Output> {
|
pub(super) fn update(&mut self, message: Message) -> Option<Output> {
|
||||||
match message {
|
match message {
|
||||||
|
|
@ -70,6 +106,12 @@ impl State {
|
||||||
Message::ThemeChanged(theme) => return Some(Output::ThemeChanged(theme)),
|
Message::ThemeChanged(theme) => return Some(Output::ThemeChanged(theme)),
|
||||||
Message::TogglerToggled(value) => self.toggler_value = value,
|
Message::TogglerToggled(value) => self.toggler_value = value,
|
||||||
Message::ViewSwitcher(key) => self.view_switcher.activate(key),
|
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
|
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![
|
settings::view_column(vec![
|
||||||
window.page_title(Page::Demo),
|
window.page_title(Page::Demo),
|
||||||
horizontal_view_switcher(&self.view_switcher)
|
horizontal_view_switcher(&self.view_switcher)
|
||||||
|
|
@ -98,6 +143,7 @@ impl State {
|
||||||
Some(DemoView::TabA) => settings::view_column(vec![
|
Some(DemoView::TabA) => settings::view_column(vec![
|
||||||
settings::view_section("Debug")
|
settings::view_section("Debug")
|
||||||
.add(settings::item("Debug theme", choose_theme))
|
.add(settings::item("Debug theme", choose_theme))
|
||||||
|
.add(settings::item("Debug icon theme", choose_icon_theme))
|
||||||
.add(settings::item(
|
.add(settings::item(
|
||||||
"Debug layout",
|
"Debug layout",
|
||||||
toggler(None, window.debug, Message::Debug),
|
toggler(None, window.debug, Message::Debug),
|
||||||
|
|
|
||||||
15
src/lib.rs
15
src/lib.rs
|
|
@ -16,21 +16,12 @@ pub mod font;
|
||||||
pub mod theme;
|
pub mod theme;
|
||||||
pub mod widget;
|
pub mod widget;
|
||||||
|
|
||||||
|
pub mod settings;
|
||||||
|
pub use settings::settings;
|
||||||
|
|
||||||
mod ext;
|
mod ext;
|
||||||
pub use ext::ElementExt;
|
pub use ext::ElementExt;
|
||||||
|
|
||||||
pub use theme::Theme;
|
pub use theme::Theme;
|
||||||
pub type Renderer = iced::Renderer<Theme>;
|
pub type Renderer = iced::Renderer<Theme>;
|
||||||
pub type Element<'a, Message> = iced::Element<'a, Message, Renderer>;
|
pub type Element<'a, Message> = iced::Element<'a, Message, Renderer>;
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn settings<Flags: Default>() -> iced::Settings<Flags> {
|
|
||||||
iced::Settings {
|
|
||||||
default_font: match font::FONT {
|
|
||||||
iced::Font::Default => None,
|
|
||||||
iced::Font::External { bytes, .. } => Some(bytes),
|
|
||||||
},
|
|
||||||
default_text_size: 18,
|
|
||||||
..iced::Settings::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
31
src/settings.rs
Normal file
31
src/settings.rs
Normal file
|
|
@ -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<String> = 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<String>) {
|
||||||
|
DEFAULT_ICON_THEME.with(|f| *f.borrow_mut() = name.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Default iced settings for COSMIC applications.
|
||||||
|
#[must_use]
|
||||||
|
pub fn settings<Flags: Default>() -> iced::Settings<Flags> {
|
||||||
|
iced::Settings {
|
||||||
|
default_font: match font::FONT {
|
||||||
|
iced::Font::Default => None,
|
||||||
|
iced::Font::External { bytes, .. } => Some(bytes),
|
||||||
|
},
|
||||||
|
default_text_size: 18,
|
||||||
|
..iced::Settings::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,9 +10,9 @@ use iced::{
|
||||||
ContentFit, Length,
|
ContentFit, Length,
|
||||||
};
|
};
|
||||||
use std::{
|
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)]
|
#[derive(Debug, Hash)]
|
||||||
pub enum IconSource<'a> {
|
pub enum IconSource<'a> {
|
||||||
|
|
@ -112,18 +112,25 @@ impl<'a> Icon<'a> {
|
||||||
let mut hasher = DefaultHasher::new();
|
let mut hasher = DefaultHasher::new();
|
||||||
self.hash(&mut hasher);
|
self.hash(&mut hasher);
|
||||||
|
|
||||||
iced_lazy::lazy(hasher.finish(), move || -> Element<Message> {
|
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<Message> {
|
||||||
let name_path_buffer: Option<PathBuf>;
|
let name_path_buffer: Option<PathBuf>;
|
||||||
let icon: Option<&Path> = match &self.name {
|
let icon: Option<&Path> = match &self.name {
|
||||||
IconSource::Path(path) => Some(path),
|
IconSource::Path(path) => Some(path),
|
||||||
IconSource::Name(name) => {
|
IconSource::Name(name) => {
|
||||||
let mut builder = freedesktop_icons::lookup(name).with_size(self.size);
|
let icon = crate::settings::DEFAULT_ICON_THEME.with(|default_theme| {
|
||||||
|
let default_theme: &str = &default_theme.borrow();
|
||||||
if let Some(theme) = self.theme.as_deref() {
|
freedesktop_icons::lookup(name)
|
||||||
builder = builder.with_theme(theme);
|
.with_size(self.size)
|
||||||
}
|
.with_theme(self.theme.as_deref().unwrap_or(default_theme))
|
||||||
|
.with_cache()
|
||||||
let icon = builder.with_cache().find();
|
.find()
|
||||||
|
});
|
||||||
|
|
||||||
name_path_buffer = if icon.is_none() {
|
name_path_buffer = if icon.is_none() {
|
||||||
freedesktop_icons::lookup(name)
|
freedesktop_icons::lookup(name)
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ impl<T: 'static + Copy + Hash + ToString, Message: 'static> SpinButton<T, Messag
|
||||||
let Self { on_change, value } = self;
|
let Self { on_change, value } = self;
|
||||||
|
|
||||||
Element::from(iced_lazy::lazy(
|
Element::from(iced_lazy::lazy(
|
||||||
value,
|
(value, crate::settings::default_icon_theme()),
|
||||||
move || -> Element<'static, SpinMessage> {
|
move || -> Element<'static, SpinMessage> {
|
||||||
container(
|
container(
|
||||||
row![
|
row![
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue