feat: add support for dark / light mode switching (#178)
* feat: add support for dark / light mode switching and simultaneouscustom light / dark mode themes * refactor(color-picker): optional initial color and fallback color * refactor: used FixedPortion for layout of the settings item This makes sure that the control always has at least the specified portion of the available space * refactor: make all members of the ThemeBuilder public * refactor: add and update palette colors * fix(theme): typo and derive PartialEq for ThemeBuilder * fix: update color picker usage * feat: add more variables to the theme * fix: radius on headerbar * fix: Theme CosmicConfigEntry impl * chore: specify rev of taffy * fix: theme CosmicConfigEntry missing variables * fix: apply theme type when theme mode changes * wip: add plus icon to empty color picker button * chore: fix rev and imports * refactor(color-picker): allow custom size for the icon * refactor(color_picker): make color_button public * update iced
This commit is contained in:
parent
a91deacff5
commit
7cc791a3f5
18 changed files with 542 additions and 164 deletions
|
|
@ -1,6 +1,9 @@
|
|||
// Copyright 2023 System76 <info@system76.com>
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use cosmic_config::CosmicConfigEntry;
|
||||
use cosmic_theme::ThemeMode;
|
||||
|
||||
use crate::Theme;
|
||||
|
||||
/// Status of the nav bar and its panels.
|
||||
|
|
@ -49,6 +52,9 @@ pub struct Core {
|
|||
/// Last known system theme
|
||||
pub(super) system_theme: Theme,
|
||||
|
||||
/// Theme mode
|
||||
pub(super) system_theme_mode: ThemeMode,
|
||||
|
||||
pub(super) title: String,
|
||||
|
||||
pub window: Window,
|
||||
|
|
@ -70,6 +76,16 @@ impl Default for Core {
|
|||
scale_factor: 1.0,
|
||||
title: String::new(),
|
||||
system_theme: crate::theme::active(),
|
||||
system_theme_mode: ThemeMode::config()
|
||||
.map(|c| {
|
||||
ThemeMode::get_entry(&c).unwrap_or_else(|(errors, mode)| {
|
||||
for e in errors {
|
||||
tracing::error!("{e}");
|
||||
}
|
||||
mode
|
||||
})
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
window: Window {
|
||||
context_title: String::new(),
|
||||
header_title: String::new(),
|
||||
|
|
@ -169,4 +185,15 @@ impl Core {
|
|||
self.window.width = new_width;
|
||||
self.is_condensed_update();
|
||||
}
|
||||
|
||||
/// Get the current system theme
|
||||
pub fn system_theme(&self) -> &Theme {
|
||||
&self.system_theme
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
/// Get the current system theme mode
|
||||
pub fn system_theme_mode(&self) -> ThemeMode {
|
||||
self.system_theme_mode
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use super::{command, Application, ApplicationExt, Core, Subscription};
|
|||
use crate::theme::{self, Theme, ThemeType, THEME};
|
||||
use crate::widget::nav_bar;
|
||||
use crate::{keyboard_nav, Element};
|
||||
use cosmic_theme::ThemeMode;
|
||||
#[cfg(feature = "wayland")]
|
||||
use iced::event::wayland::{self, WindowEvent};
|
||||
#[cfg(feature = "wayland")]
|
||||
|
|
@ -44,6 +45,8 @@ pub enum Message {
|
|||
ToggleNavBarCondensed,
|
||||
/// Notification of system theme changes.
|
||||
SystemThemeChange(Theme),
|
||||
/// Notification of system theme mode changes.
|
||||
SystemThemeModeChange(ThemeMode),
|
||||
/// Updates the tracked window geometry.
|
||||
WindowResize(window::Id, u32, u32),
|
||||
/// Tracks updates to window state.
|
||||
|
|
@ -152,9 +155,24 @@ where
|
|||
keyboard_nav::subscription()
|
||||
.map(Message::KeyboardNav)
|
||||
.map(super::Message::Cosmic),
|
||||
theme::subscription(0)
|
||||
theme::subscription(0, self.app.core().system_theme_mode.is_dark)
|
||||
.map(Message::SystemThemeChange)
|
||||
.map(super::Message::Cosmic),
|
||||
cosmic_config::config_subscription::<_, cosmic_theme::ThemeMode>(
|
||||
0,
|
||||
cosmic_theme::THEME_MODE_ID.into(),
|
||||
cosmic_theme::ThemeMode::version(),
|
||||
)
|
||||
.map(|(_, u)| match u {
|
||||
Ok(t) => Message::SystemThemeModeChange(t),
|
||||
Err((errors, t)) => {
|
||||
for e in errors {
|
||||
tracing::error!("{e}");
|
||||
}
|
||||
Message::SystemThemeModeChange(t)
|
||||
}
|
||||
})
|
||||
.map(super::Message::Cosmic),
|
||||
window_events.map(super::Message::Cosmic),
|
||||
])
|
||||
}
|
||||
|
|
@ -195,6 +213,7 @@ impl<T: Application> Cosmic<T> {
|
|||
iced::Command::single(Action::Window(WindowAction::Close))
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn cosmic_update(&mut self, message: Message) -> iced::Command<super::Message<T::Message>> {
|
||||
match message {
|
||||
Message::WindowResize(id, width, height) => {
|
||||
|
|
@ -295,7 +314,7 @@ impl<T: Application> Cosmic<T> {
|
|||
THEME.with(move |t| {
|
||||
let mut cosmic_theme = t.borrow_mut();
|
||||
|
||||
// Anly apply update if the theme is set to load a system theme
|
||||
// Only apply update if the theme is set to load a system theme
|
||||
if let ThemeType::System(_) = cosmic_theme.theme_type {
|
||||
cosmic_theme.set_theme(theme.theme_type);
|
||||
}
|
||||
|
|
@ -310,6 +329,21 @@ impl<T: Application> Cosmic<T> {
|
|||
self.app.on_app_exit();
|
||||
return self.close();
|
||||
}
|
||||
Message::SystemThemeModeChange(mode) => {
|
||||
let core = self.app.core_mut();
|
||||
let changed = core.system_theme_mode.is_dark != mode.is_dark;
|
||||
core.system_theme_mode = mode;
|
||||
if changed {
|
||||
THEME.with(move |t| {
|
||||
let mut cosmic_theme = t.borrow_mut();
|
||||
|
||||
// Only apply update if the theme is set to load a system theme
|
||||
if let ThemeType::System(_) = cosmic_theme.theme_type {
|
||||
cosmic_theme.set_theme(crate::theme::system_preference().theme_type);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iced::Command::none()
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@
|
|||
//! Contains the [`Theme`] type and its widget stylesheet implementations.
|
||||
|
||||
pub mod style;
|
||||
use cosmic_theme::ThemeMode;
|
||||
pub use style::*;
|
||||
|
||||
use cosmic_config::config_subscription;
|
||||
use cosmic_config::CosmicConfigEntry;
|
||||
use cosmic_theme::util::CssColor;
|
||||
use cosmic_theme::Component;
|
||||
use cosmic_theme::LayeredTheme;
|
||||
use iced_futures::Subscription;
|
||||
|
|
@ -68,10 +68,15 @@ pub fn is_high_contrast() -> bool {
|
|||
}
|
||||
|
||||
/// Watches for changes to the system's theme preference.
|
||||
pub fn subscription(id: u64) -> Subscription<crate::theme::Theme> {
|
||||
config_subscription::<u64, crate::cosmic_theme::Theme<Srgba>>(
|
||||
id,
|
||||
crate::cosmic_theme::NAME.into(),
|
||||
pub fn subscription(id: u64, is_dark: bool) -> Subscription<crate::theme::Theme> {
|
||||
config_subscription::<_, crate::cosmic_theme::Theme<Srgba>>(
|
||||
(id, is_dark),
|
||||
if is_dark {
|
||||
cosmic_theme::DARK_THEME_ID
|
||||
} else {
|
||||
cosmic_theme::LIGHT_THEME_ID
|
||||
}
|
||||
.into(),
|
||||
crate::cosmic_theme::Theme::<Srgba>::version(),
|
||||
)
|
||||
.map(|(_, res)| {
|
||||
|
|
@ -88,10 +93,21 @@ pub fn subscription(id: u64) -> Subscription<crate::theme::Theme> {
|
|||
|
||||
/// Loads the preferred system theme from `cosmic-config`.
|
||||
pub fn system_preference() -> Theme {
|
||||
let Ok(helper) = crate::cosmic_config::Config::new(
|
||||
crate::cosmic_theme::NAME,
|
||||
crate::cosmic_theme::Theme::<CssColor>::version(),
|
||||
) else {
|
||||
let Ok(mode_config) = ThemeMode::config() else {
|
||||
return Theme::dark();
|
||||
};
|
||||
|
||||
let Ok(is_dark) = ThemeMode::is_dark(&mode_config) else {
|
||||
return Theme::dark();
|
||||
};
|
||||
|
||||
let helper = if is_dark {
|
||||
crate::cosmic_theme::Theme::<Srgba>::dark_config()
|
||||
} else {
|
||||
crate::cosmic_theme::Theme::<Srgba>::light_config()
|
||||
};
|
||||
|
||||
let Ok(helper) = helper else {
|
||||
return Theme::dark();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -412,7 +412,12 @@ impl container::StyleSheet for Theme {
|
|||
.add_stop(0.0, header_top.into())
|
||||
.add_stop(1.0, header_bottom.into()),
|
||||
))),
|
||||
border_radius: BorderRadius::from([16.0, 16.0, 0.0, 0.0]),
|
||||
border_radius: BorderRadius::from([
|
||||
palette.corner_radii.radius_xs[0],
|
||||
palette.corner_radii.radius_xs[3],
|
||||
0.0,
|
||||
0.0,
|
||||
]),
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,20 +17,21 @@ use iced_core::gradient::{ColorStop, Linear};
|
|||
use iced_core::renderer::Quad;
|
||||
use iced_core::widget::{tree, Tree};
|
||||
use iced_core::{
|
||||
layout, mouse, renderer, Clipboard, Color, Layout, Length, Radians, Rectangle, Renderer, Shell,
|
||||
Vector, Widget,
|
||||
layout, mouse, renderer, Background, Clipboard, Color, Layout, Length, Radians, Rectangle,
|
||||
Renderer, Shell, Vector, Widget,
|
||||
};
|
||||
#[cfg(feature = "wayland")]
|
||||
use iced_sctk::commands::data_device::set_selection;
|
||||
use iced_style::slider::{HandleShape, RailBackground};
|
||||
use iced_widget::{canvas, column, scrollable, vertical_space, Row};
|
||||
use iced_widget::{canvas, column, horizontal_space, row, scrollable, vertical_space, Row};
|
||||
use lazy_static::lazy_static;
|
||||
use palette::{FromColor, RgbHue};
|
||||
|
||||
use super::button::StyleSheet;
|
||||
use super::divider::horizontal;
|
||||
use super::icon::from_name;
|
||||
use super::icon::{self, from_name};
|
||||
use super::segmented_button::{self, Model, SingleSelect};
|
||||
use super::{button, segmented_selection, text, text_input, tooltip};
|
||||
use super::{button, segmented_selection, text, text_input, tooltip, Icon};
|
||||
|
||||
// TODO is this going to look correct enough?
|
||||
lazy_static! {
|
||||
|
|
@ -72,9 +73,9 @@ pub struct ColorPickerModel {
|
|||
#[setters(skip)]
|
||||
input_color: String,
|
||||
#[setters(skip)]
|
||||
applied_color: Color,
|
||||
applied_color: Option<Color>,
|
||||
#[setters(skip)]
|
||||
initial_color: Color,
|
||||
fallback_color: Option<Color>,
|
||||
#[setters(skip)]
|
||||
recent_colors: Vec<Color>,
|
||||
active: bool,
|
||||
|
|
@ -91,11 +92,11 @@ impl ColorPickerModel {
|
|||
pub fn new(
|
||||
hex: impl Into<Cow<'static, str>> + Clone,
|
||||
rgb: impl Into<Cow<'static, str>> + Clone,
|
||||
fallback_color: Color,
|
||||
fallback_color: Option<Color>,
|
||||
initial_color: Option<Color>,
|
||||
) -> Self {
|
||||
let initial = initial_color.unwrap_or(fallback_color);
|
||||
let initial_srgb = palette::Srgb::from(initial);
|
||||
let initial = initial_color.or(fallback_color);
|
||||
let initial_srgb = palette::Srgb::from(initial.unwrap_or(Color::BLACK));
|
||||
let hsv = palette::Hsv::from_color(initial_srgb);
|
||||
Self {
|
||||
segmented_model: segmented_button::Model::builder()
|
||||
|
|
@ -103,10 +104,10 @@ impl ColorPickerModel {
|
|||
.insert(move |b| b.text(rgb.clone()))
|
||||
.build(),
|
||||
active_color: hsv,
|
||||
save_next: Some(initial),
|
||||
save_next: None,
|
||||
input_color: color_to_string(hsv, true),
|
||||
applied_color: fallback_color,
|
||||
initial_color: initial,
|
||||
applied_color: initial,
|
||||
fallback_color,
|
||||
recent_colors: Vec::new(), // TODO should all color pickers show the same recent colors?
|
||||
active: false,
|
||||
width: Length::Fixed(300.0),
|
||||
|
|
@ -118,13 +119,15 @@ impl ColorPickerModel {
|
|||
|
||||
/// Get a color picker button that displays the applied color
|
||||
///
|
||||
pub fn picker_button<'a, Message: 'a, T: Fn(ColorPickerUpdate) -> Message>(
|
||||
pub fn picker_button<'a, Message: 'static, T: Fn(ColorPickerUpdate) -> Message>(
|
||||
&self,
|
||||
f: T,
|
||||
icon_portion: Option<u16>,
|
||||
) -> crate::widget::Button<'a, Message, crate::Renderer> {
|
||||
color_button(
|
||||
Some(f(ColorPickerUpdate::ToggleColorPicker)),
|
||||
self.applied_color,
|
||||
Length::FillPortion(icon_portion.unwrap_or(12)),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -142,8 +145,10 @@ impl ColorPickerModel {
|
|||
}
|
||||
ColorPickerUpdate::AppliedColor => {
|
||||
let srgb = palette::Srgb::from_color(self.active_color);
|
||||
self.recent_colors.push(self.applied_color);
|
||||
self.applied_color = Color::from(srgb);
|
||||
if let Some(applied_color) = self.applied_color.take() {
|
||||
self.recent_colors.push(applied_color);
|
||||
}
|
||||
self.applied_color = Some(Color::from(srgb));
|
||||
self.active = false;
|
||||
}
|
||||
ColorPickerUpdate::ActivateSegmented(e) => {
|
||||
|
|
@ -167,10 +172,10 @@ impl ColorPickerModel {
|
|||
ColorPickerUpdate::Reset => {
|
||||
self.must_clear_cache.store(true, Ordering::SeqCst);
|
||||
|
||||
let initial_srgb = palette::Srgb::from(self.initial_color);
|
||||
let initial_srgb = palette::Srgb::from(self.fallback_color.unwrap_or(Color::BLACK));
|
||||
let hsv = palette::Hsv::from_color(initial_srgb);
|
||||
self.active_color = hsv;
|
||||
self.applied_color = self.initial_color;
|
||||
self.applied_color = self.fallback_color;
|
||||
self.copied_at = None;
|
||||
}
|
||||
ColorPickerUpdate::Cancel => {
|
||||
|
|
@ -216,7 +221,7 @@ impl ColorPickerModel {
|
|||
|
||||
/// Get the applied color of the picker
|
||||
#[must_use]
|
||||
pub fn get_applied_color(&self) -> Color {
|
||||
pub fn get_applied_color(&self) -> Option<Color> {
|
||||
self.applied_color
|
||||
}
|
||||
|
||||
|
|
@ -355,7 +360,8 @@ where
|
|||
.leading_icon(
|
||||
color_button(
|
||||
None,
|
||||
Color::from(palette::Srgb::from_color(self.active_color))
|
||||
Some(Color::from(palette::Srgb::from_color(self.active_color))),
|
||||
Length::FillPortion(12)
|
||||
)
|
||||
.into()
|
||||
)
|
||||
|
|
@ -411,7 +417,8 @@ where
|
|||
let hsv = palette::Hsv::from_color(initial_srgb);
|
||||
color_button(
|
||||
Some(on_update(ColorPickerUpdate::ActiveColor(hsv))),
|
||||
*c,
|
||||
Some(*c),
|
||||
Length::FillPortion(12),
|
||||
)
|
||||
.into()
|
||||
})
|
||||
|
|
@ -738,93 +745,122 @@ fn color_to_string(c: palette::Hsv, is_hex: bool) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
fn color_button<'a, Message: 'a>(
|
||||
pub fn color_button<'a, Message: 'static>(
|
||||
on_press: Option<Message>,
|
||||
color: Color,
|
||||
color: Option<Color>,
|
||||
icon_portion: Length,
|
||||
) -> crate::widget::Button<'a, Message, crate::Renderer> {
|
||||
let spacing = THEME.with(|t| t.borrow().cosmic().spacing);
|
||||
|
||||
button(vertical_space(Length::Fixed(f32::from(spacing.space_s))))
|
||||
.width(Length::Fixed(f32::from(spacing.space_s)))
|
||||
.height(Length::Fixed(f32::from(spacing.space_s)))
|
||||
.on_press_maybe(on_press)
|
||||
.style(crate::theme::Button::Custom {
|
||||
active: Box::new(move |focused, theme| {
|
||||
let cosmic = theme.cosmic();
|
||||
button(if color.is_some() {
|
||||
Element::from(vertical_space(Length::Fixed(f32::from(spacing.space_s))))
|
||||
} else {
|
||||
Element::from(column![
|
||||
vertical_space(Length::FillPortion(6)),
|
||||
row![
|
||||
horizontal_space(Length::FillPortion(6)),
|
||||
Icon::from(
|
||||
icon::from_name("list-add-symbolic")
|
||||
.prefer_svg(true)
|
||||
.symbolic(true)
|
||||
.size(64)
|
||||
)
|
||||
.width(icon_portion)
|
||||
.height(Length::Fill)
|
||||
.content_fit(iced_core::ContentFit::Contain),
|
||||
horizontal_space(Length::FillPortion(6)),
|
||||
]
|
||||
.height(icon_portion)
|
||||
.width(Length::Fill),
|
||||
vertical_space(Length::FillPortion(6)),
|
||||
])
|
||||
})
|
||||
.width(Length::Fixed(f32::from(spacing.space_s)))
|
||||
.height(Length::Fixed(f32::from(spacing.space_s)))
|
||||
.on_press_maybe(on_press)
|
||||
.style(crate::theme::Button::Custom {
|
||||
active: Box::new(move |focused, theme| {
|
||||
let cosmic = theme.cosmic();
|
||||
|
||||
let (outline_width, outline_color) = if focused {
|
||||
(1.0, cosmic.accent_color().into())
|
||||
} else {
|
||||
(0.0, Color::TRANSPARENT)
|
||||
};
|
||||
button::Appearance {
|
||||
shadow_offset: Vector::default(),
|
||||
background: Some(color.into()),
|
||||
border_radius: cosmic.radius_xs().into(),
|
||||
border_width: 1.0,
|
||||
border_color: cosmic.on_bg_color().into(),
|
||||
outline_width,
|
||||
outline_color,
|
||||
icon_color: None,
|
||||
text_color: None,
|
||||
}
|
||||
}),
|
||||
disabled: Box::new(move |theme| {
|
||||
let cosmic = theme.cosmic();
|
||||
let (outline_width, outline_color) = if focused {
|
||||
(1.0, cosmic.accent_color().into())
|
||||
} else {
|
||||
(0.0, Color::TRANSPARENT)
|
||||
};
|
||||
let standard = theme.active(focused, &Button::Standard);
|
||||
button::Appearance {
|
||||
shadow_offset: Vector::default(),
|
||||
background: color.map(Background::from).or(standard.background),
|
||||
border_radius: cosmic.radius_xs().into(),
|
||||
border_width: 1.0,
|
||||
border_color: cosmic.on_bg_color().into(),
|
||||
outline_width,
|
||||
outline_color,
|
||||
icon_color: None,
|
||||
text_color: None,
|
||||
}
|
||||
}),
|
||||
disabled: Box::new(move |theme| {
|
||||
let cosmic = theme.cosmic();
|
||||
|
||||
button::Appearance {
|
||||
shadow_offset: Vector::default(),
|
||||
background: Some(color.into()),
|
||||
border_radius: cosmic.radius_xs().into(),
|
||||
border_width: 1.0,
|
||||
border_color: cosmic.on_bg_color().into(),
|
||||
outline_width: 0.0,
|
||||
outline_color: Color::TRANSPARENT,
|
||||
icon_color: None,
|
||||
text_color: None,
|
||||
}
|
||||
}),
|
||||
hovered: Box::new(move |focused, theme| {
|
||||
let cosmic = theme.cosmic();
|
||||
let standard = theme.disabled(&Button::Standard);
|
||||
button::Appearance {
|
||||
shadow_offset: Vector::default(),
|
||||
background: color.map(Background::from).or(standard.background),
|
||||
border_radius: cosmic.radius_xs().into(),
|
||||
border_width: 1.0,
|
||||
border_color: cosmic.on_bg_color().into(),
|
||||
outline_width: 0.0,
|
||||
outline_color: Color::TRANSPARENT,
|
||||
icon_color: None,
|
||||
text_color: None,
|
||||
}
|
||||
}),
|
||||
hovered: Box::new(move |focused, theme| {
|
||||
let cosmic = theme.cosmic();
|
||||
|
||||
let (outline_width, outline_color) = if focused {
|
||||
(1.0, cosmic.accent_color().into())
|
||||
} else {
|
||||
(0.0, Color::TRANSPARENT)
|
||||
};
|
||||
button::Appearance {
|
||||
shadow_offset: Vector::default(),
|
||||
background: Some(color.into()),
|
||||
border_radius: cosmic.radius_xs().into(),
|
||||
border_width: 1.0,
|
||||
border_color: cosmic.on_bg_color().into(),
|
||||
outline_width,
|
||||
outline_color,
|
||||
icon_color: None,
|
||||
text_color: None,
|
||||
}
|
||||
}),
|
||||
pressed: Box::new(move |focused, theme| {
|
||||
let cosmic = theme.cosmic();
|
||||
let (outline_width, outline_color) = if focused {
|
||||
(1.0, cosmic.accent_color().into())
|
||||
} else {
|
||||
(0.0, Color::TRANSPARENT)
|
||||
};
|
||||
|
||||
let (outline_width, outline_color) = if focused {
|
||||
(1.0, cosmic.accent_color().into())
|
||||
} else {
|
||||
(0.0, Color::TRANSPARENT)
|
||||
};
|
||||
button::Appearance {
|
||||
shadow_offset: Vector::default(),
|
||||
background: Some(color.into()),
|
||||
border_radius: cosmic.radius_xs().into(),
|
||||
border_width: 1.0,
|
||||
border_color: cosmic.on_bg_color().into(),
|
||||
outline_width,
|
||||
outline_color,
|
||||
icon_color: None,
|
||||
text_color: None,
|
||||
}
|
||||
}),
|
||||
})
|
||||
let standard = theme.hovered(focused, &Button::Standard);
|
||||
button::Appearance {
|
||||
shadow_offset: Vector::default(),
|
||||
background: color.map(Background::from).or(standard.background),
|
||||
border_radius: cosmic.radius_xs().into(),
|
||||
border_width: 1.0,
|
||||
border_color: cosmic.on_bg_color().into(),
|
||||
outline_width,
|
||||
outline_color,
|
||||
icon_color: None,
|
||||
text_color: None,
|
||||
}
|
||||
}),
|
||||
pressed: Box::new(move |focused, theme| {
|
||||
let cosmic = theme.cosmic();
|
||||
|
||||
let (outline_width, outline_color) = if focused {
|
||||
(1.0, cosmic.accent_color().into())
|
||||
} else {
|
||||
(0.0, Color::TRANSPARENT)
|
||||
};
|
||||
|
||||
let standard = theme.pressed(focused, &Button::Standard);
|
||||
button::Appearance {
|
||||
shadow_offset: Vector::default(),
|
||||
background: color.map(Background::from).or(standard.background),
|
||||
border_radius: cosmic.radius_xs().into(),
|
||||
border_width: 1.0,
|
||||
border_color: cosmic.on_bg_color().into(),
|
||||
outline_width,
|
||||
outline_color,
|
||||
icon_color: None,
|
||||
text_color: None,
|
||||
}
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
impl<'a, Message> From<ColorPicker<'a, Message>> for iced::Element<'a, Message, crate::Renderer>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ use crate::{
|
|||
Element,
|
||||
};
|
||||
use derive_setters::Setters;
|
||||
use iced_core::Length;
|
||||
use iced_widget::container;
|
||||
|
||||
/// A settings item aligned in a row
|
||||
#[must_use]
|
||||
|
|
@ -70,15 +72,20 @@ impl<'a, Message: 'static> Item<'a, Message> {
|
|||
let column = column::with_capacity(2)
|
||||
.spacing(2)
|
||||
.push(text(self.title))
|
||||
.push(text(description).size(10));
|
||||
.push(text(description).size(10))
|
||||
.width(Length::FillPortion(12));
|
||||
|
||||
contents.push(column.into());
|
||||
} else {
|
||||
contents.push(text(self.title).into());
|
||||
}
|
||||
|
||||
contents.push(horizontal_space(iced::Length::Fill).into());
|
||||
contents.push(widget.into());
|
||||
contents.push(
|
||||
container(widget.into())
|
||||
.width(Length::FillPortion(4))
|
||||
.align_x(iced_core::alignment::Horizontal::Right)
|
||||
.into(),
|
||||
);
|
||||
|
||||
item_row(contents)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue