Implement theme styling for Radio

This commit is contained in:
Héctor Ramón Jiménez 2022-05-27 01:26:57 +02:00
parent d988d813d7
commit 28d09bfff1
No known key found for this signature in database
GPG key ID: 140CC052C94F138E
10 changed files with 86 additions and 157 deletions

View file

@ -69,15 +69,12 @@ impl Sandbox for ScrollableDemo {
let choose_theme = style::Theme::ALL.iter().fold( let choose_theme = style::Theme::ALL.iter().fold(
Column::new().spacing(10).push(Text::new("Choose a theme:")), Column::new().spacing(10).push(Text::new("Choose a theme:")),
|column, option| { |column, option| {
column.push( column.push(Radio::new(
Radio::new(
*option, *option,
format!("{:?}", option), format!("{:?}", option),
Some(*theme), Some(*theme),
Message::ThemeChanged, Message::ThemeChanged,
) ))
.style(*theme),
)
}, },
); );

View file

@ -1,4 +1,4 @@
use iced::{container, radio, rule, scrollable}; use iced::{container, rule, scrollable};
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Theme { pub enum Theme {
@ -25,15 +25,6 @@ impl<'a> From<Theme> for Box<dyn container::StyleSheet + 'a> {
} }
} }
impl<'a> From<Theme> for Box<dyn radio::StyleSheet + 'a> {
fn from(theme: Theme) -> Self {
match theme {
Theme::Light => Default::default(),
Theme::Dark => dark::Radio.into(),
}
}
}
impl<'a> From<Theme> for Box<dyn scrollable::StyleSheet + 'a> { impl<'a> From<Theme> for Box<dyn scrollable::StyleSheet + 'a> {
fn from(theme: Theme) -> Self { fn from(theme: Theme) -> Self {
match theme { match theme {
@ -53,7 +44,7 @@ impl From<Theme> for Box<dyn rule::StyleSheet> {
} }
mod dark { mod dark {
use iced::{container, radio, rule, scrollable, Color}; use iced::{container, rule, scrollable, Color};
const BACKGROUND: Color = Color::from_rgb( const BACKGROUND: Color = Color::from_rgb(
0x36 as f32 / 255.0, 0x36 as f32 / 255.0,
@ -73,12 +64,6 @@ mod dark {
0xE9 as f32 / 255.0, 0xE9 as f32 / 255.0,
); );
const ACTIVE: Color = Color::from_rgb(
0x72 as f32 / 255.0,
0x89 as f32 / 255.0,
0xDA as f32 / 255.0,
);
const SCROLLBAR: Color = Color::from_rgb( const SCROLLBAR: Color = Color::from_rgb(
0x2E as f32 / 255.0, 0x2E as f32 / 255.0,
0x33 as f32 / 255.0, 0x33 as f32 / 255.0,
@ -107,27 +92,6 @@ mod dark {
} }
} }
pub struct Radio;
impl radio::StyleSheet for Radio {
fn active(&self) -> radio::Style {
radio::Style {
background: SURFACE.into(),
dot_color: ACTIVE,
border_width: 1.0,
border_color: ACTIVE,
text_color: None,
}
}
fn hovered(&self) -> radio::Style {
radio::Style {
background: Color { a: 0.5, ..SURFACE }.into(),
..self.active()
}
}
}
pub struct Scrollable; pub struct Scrollable;
impl scrollable::StyleSheet for Scrollable { impl scrollable::StyleSheet for Scrollable {

View file

@ -61,15 +61,12 @@ impl Sandbox for Styling {
let choose_theme = style::Theme::ALL.iter().fold( let choose_theme = style::Theme::ALL.iter().fold(
Column::new().spacing(10).push(Text::new("Choose a theme:")), Column::new().spacing(10).push(Text::new("Choose a theme:")),
|column, theme| { |column, theme| {
column.push( column.push(Radio::new(
Radio::new(
*theme, *theme,
format!("{:?}", theme), format!("{:?}", theme),
Some(self.theme), Some(self.theme),
Message::ThemeChanged, Message::ThemeChanged,
) ))
.style(self.theme),
)
}, },
); );
@ -158,7 +155,7 @@ impl Sandbox for Styling {
mod style { mod style {
use iced::{ use iced::{
checkbox, container, progress_bar, radio, rule, scrollable, text_input, checkbox, container, progress_bar, rule, scrollable, text_input,
toggler, toggler,
}; };
@ -187,15 +184,6 @@ mod style {
} }
} }
impl<'a> From<Theme> for Box<dyn radio::StyleSheet + 'a> {
fn from(theme: Theme) -> Self {
match theme {
Theme::Light => Default::default(),
Theme::Dark => dark::Radio.into(),
}
}
}
impl<'a> From<Theme> for Box<dyn text_input::StyleSheet + 'a> { impl<'a> From<Theme> for Box<dyn text_input::StyleSheet + 'a> {
fn from(theme: Theme) -> Self { fn from(theme: Theme) -> Self {
match theme { match theme {
@ -252,8 +240,8 @@ mod style {
mod dark { mod dark {
use iced::{ use iced::{
checkbox, container, progress_bar, radio, rule, scrollable, checkbox, container, progress_bar, rule, scrollable, text_input,
text_input, toggler, Color, toggler, Color,
}; };
const SURFACE: Color = Color::from_rgb( const SURFACE: Color = Color::from_rgb(
@ -292,27 +280,6 @@ mod style {
} }
} }
pub struct Radio;
impl radio::StyleSheet for Radio {
fn active(&self) -> radio::Style {
radio::Style {
background: SURFACE.into(),
dot_color: ACTIVE,
border_width: 1.0,
border_color: ACTIVE,
text_color: None,
}
}
fn hovered(&self) -> radio::Style {
radio::Style {
background: Color { a: 0.5, ..SURFACE }.into(),
..self.active()
}
}
}
pub struct TextInput; pub struct TextInput;
impl text_input::StyleSheet for TextInput { impl text_input::StyleSheet for TextInput {

View file

@ -12,14 +12,14 @@ use crate::{
Shell, Widget, Shell, Widget,
}; };
pub use iced_style::radio::{Style, StyleSheet}; pub use iced_style::radio::{Appearance, StyleSheet};
/// A circular button representing a choice. /// A circular button representing a choice.
/// ///
/// # Example /// # Example
/// ``` /// ```
/// # type Radio<'a, Message> = /// # type Radio<Message> =
/// # iced_native::widget::Radio<'a, Message, iced_native::renderer::Null>; /// # iced_native::widget::Radio<Message, iced_native::renderer::Null>;
/// # /// #
/// #[derive(Debug, Clone, Copy, PartialEq, Eq)] /// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
/// pub enum Choice { /// pub enum Choice {
@ -41,7 +41,11 @@ pub use iced_style::radio::{Style, StyleSheet};
/// ///
/// ![Radio buttons drawn by `iced_wgpu`](https://github.com/iced-rs/iced/blob/7760618fb112074bc40b148944521f312152012a/docs/images/radio.png?raw=true) /// ![Radio buttons drawn by `iced_wgpu`](https://github.com/iced-rs/iced/blob/7760618fb112074bc40b148944521f312152012a/docs/images/radio.png?raw=true)
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
pub struct Radio<'a, Message, Renderer: text::Renderer> { pub struct Radio<Message, Renderer>
where
Renderer: text::Renderer,
Renderer::Theme: StyleSheet,
{
is_selected: bool, is_selected: bool,
on_click: Message, on_click: Message,
label: String, label: String,
@ -50,12 +54,14 @@ pub struct Radio<'a, Message, Renderer: text::Renderer> {
spacing: u16, spacing: u16,
text_size: Option<u16>, text_size: Option<u16>,
font: Renderer::Font, font: Renderer::Font,
style_sheet: Box<dyn StyleSheet + 'a>, style: <Renderer::Theme as StyleSheet>::Style,
} }
impl<'a, Message, Renderer: text::Renderer> Radio<'a, Message, Renderer> impl<Message, Renderer> Radio<Message, Renderer>
where where
Message: Clone, Message: Clone,
Renderer: text::Renderer,
Renderer::Theme: StyleSheet,
{ {
/// The default size of a [`Radio`] button. /// The default size of a [`Radio`] button.
pub const DEFAULT_SIZE: u16 = 28; pub const DEFAULT_SIZE: u16 = 28;
@ -90,7 +96,7 @@ where
spacing: Self::DEFAULT_SPACING, //15 spacing: Self::DEFAULT_SPACING, //15
text_size: None, text_size: None,
font: Default::default(), font: Default::default(),
style_sheet: Default::default(), style: Default::default(),
} }
} }
@ -127,18 +133,18 @@ where
/// Sets the style of the [`Radio`] button. /// Sets the style of the [`Radio`] button.
pub fn style( pub fn style(
mut self, mut self,
style_sheet: impl Into<Box<dyn StyleSheet + 'a>>, style: impl Into<<Renderer::Theme as StyleSheet>::Style>,
) -> Self { ) -> Self {
self.style_sheet = style_sheet.into(); self.style = style.into();
self self
} }
} }
impl<'a, Message, Renderer> Widget<Message, Renderer> impl<Message, Renderer> Widget<Message, Renderer> for Radio<Message, Renderer>
for Radio<'a, Message, Renderer>
where where
Message: Clone, Message: Clone,
Renderer: text::Renderer, Renderer: text::Renderer,
Renderer::Theme: StyleSheet,
{ {
fn width(&self) -> Length { fn width(&self) -> Length {
self.width self.width
@ -223,9 +229,9 @@ where
let mut children = layout.children(); let mut children = layout.children();
let custom_style = if is_mouse_over { let custom_style = if is_mouse_over {
self.style_sheet.hovered() theme.hovered(self.style)
} else { } else {
self.style_sheet.active() theme.active(self.style)
}; };
{ {
@ -281,15 +287,14 @@ where
} }
} }
impl<'a, Message, Renderer> From<Radio<'a, Message, Renderer>> impl<'a, Message, Renderer> From<Radio<Message, Renderer>>
for Element<'a, Message, Renderer> for Element<'a, Message, Renderer>
where where
Message: 'a + Clone, Message: 'a + Clone,
Renderer: 'a + text::Renderer, Renderer: 'a + text::Renderer,
Renderer::Theme: StyleSheet,
{ {
fn from( fn from(radio: Radio<Message, Renderer>) -> Element<'a, Message, Renderer> {
radio: Radio<'a, Message, Renderer>,
) -> Element<'a, Message, Renderer> {
Element::new(radio) Element::new(radio)
} }
} }

View file

@ -100,15 +100,16 @@ where
/// Creates a new [`Radio`]. /// Creates a new [`Radio`].
/// ///
/// [`Radio`]: widget::Radio /// [`Radio`]: widget::Radio
pub fn radio<'a, Message, Renderer, V>( pub fn radio<Message, Renderer, V>(
label: impl Into<String>, label: impl Into<String>,
value: V, value: V,
selected: Option<V>, selected: Option<V>,
on_click: impl FnOnce(V) -> Message, on_click: impl FnOnce(V) -> Message,
) -> widget::Radio<'a, Message, Renderer> ) -> widget::Radio<Message, Renderer>
where where
Message: Clone, Message: Clone,
Renderer: iced_native::text::Renderer, Renderer: iced_native::text::Renderer,
Renderer::Theme: widget::radio::StyleSheet,
V: Copy + Eq, V: Copy + Eq,
{ {
widget::Radio::new(value, label, selected, on_click) widget::Radio::new(value, label, selected, on_click)

View file

@ -9,13 +9,13 @@ use iced_native::renderer;
use iced_native::text; use iced_native::text;
use iced_native::{Clipboard, Length, Point, Rectangle, Shell}; use iced_native::{Clipboard, Length, Point, Rectangle, Shell};
pub use iced_native::widget::radio::{Radio, Style, StyleSheet}; pub use iced_native::widget::radio::{Appearance, Radio, StyleSheet};
impl<'a, Message, Renderer> Widget<Message, Renderer> impl<Message, Renderer> Widget<Message, Renderer> for Radio<Message, Renderer>
for Radio<'a, Message, Renderer>
where where
Message: Clone, Message: Clone,
Renderer: text::Renderer, Renderer: text::Renderer,
Renderer::Theme: StyleSheet,
{ {
fn width(&self) -> Length { fn width(&self) -> Length {
<Self as iced_native::Widget<Message, Renderer>>::width(self) <Self as iced_native::Widget<Message, Renderer>>::width(self)
@ -96,10 +96,11 @@ where
} }
impl<'a, Message, Renderer> Into<Element<'a, Message, Renderer>> impl<'a, Message, Renderer> Into<Element<'a, Message, Renderer>>
for Radio<'a, Message, Renderer> for Radio<Message, Renderer>
where where
Message: 'a + Clone, Message: 'a + Clone,
Renderer: text::Renderer + 'a, Renderer: text::Renderer + 'a,
Renderer::Theme: StyleSheet,
{ {
fn into(self) -> Element<'a, Message, Renderer> { fn into(self) -> Element<'a, Message, Renderer> {
Element::new(self) Element::new(self)

View file

@ -90,11 +90,11 @@ pub mod pick_list {
pub mod radio { pub mod radio {
//! Create choices using radio buttons. //! Create choices using radio buttons.
pub use iced_pure::widget::radio::{Style, StyleSheet}; pub use iced_pure::widget::radio::{Appearance, StyleSheet};
/// A circular button representing a choice. /// A circular button representing a choice.
pub type Radio<'a, Message, Theme> = pub type Radio<Message, Theme> =
iced_pure::widget::Radio<'a, Message, crate::Renderer<Theme>>; iced_pure::widget::Radio<Message, crate::Renderer<Theme>>;
} }
pub mod scrollable { pub mod scrollable {

View file

@ -106,11 +106,11 @@ pub mod pick_list {
pub mod radio { pub mod radio {
//! Create choices using radio buttons. //! Create choices using radio buttons.
pub use iced_native::widget::radio::{Style, StyleSheet}; pub use iced_native::widget::radio::{Appearance, StyleSheet};
/// A circular button representing a choice. /// A circular button representing a choice.
pub type Radio<'a, Message, Theme> = pub type Radio<Message, Theme> =
iced_native::widget::Radio<'a, Message, crate::Renderer<Theme>>; iced_native::widget::Radio<Message, crate::Renderer<Theme>>;
} }
pub mod scrollable { pub mod scrollable {

View file

@ -3,7 +3,7 @@ use iced_core::{Background, Color};
/// The appearance of a radio button. /// The appearance of a radio button.
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Style { pub struct Appearance {
pub background: Background, pub background: Background,
pub dot_color: Color, pub dot_color: Color,
pub border_width: f32, pub border_width: f32,
@ -13,43 +13,9 @@ pub struct Style {
/// A set of rules that dictate the style of a radio button. /// A set of rules that dictate the style of a radio button.
pub trait StyleSheet { pub trait StyleSheet {
fn active(&self) -> Style; type Style: Default + Copy;
fn hovered(&self) -> Style; fn active(&self, style: Self::Style) -> Appearance;
}
struct Default; fn hovered(&self, style: Self::Style) -> Appearance;
impl StyleSheet for Default {
fn active(&self) -> Style {
Style {
background: Background::Color(Color::from_rgb(0.95, 0.95, 0.95)),
dot_color: Color::from_rgb(0.3, 0.3, 0.3),
border_width: 1.0,
border_color: Color::from_rgb(0.6, 0.6, 0.6),
text_color: None,
}
}
fn hovered(&self) -> Style {
Style {
background: Background::Color(Color::from_rgb(0.90, 0.90, 0.90)),
..self.active()
}
}
}
impl<'a> std::default::Default for Box<dyn StyleSheet + 'a> {
fn default() -> Self {
Box::new(Default)
}
}
impl<'a, T> From<T> for Box<dyn StyleSheet + 'a>
where
T: StyleSheet + 'a,
{
fn from(style_sheet: T) -> Self {
Box::new(style_sheet)
}
} }

View file

@ -4,6 +4,7 @@ pub use self::palette::Palette;
use crate::application; use crate::application;
use crate::button; use crate::button;
use crate::radio;
use crate::slider; use crate::slider;
use iced_core::{Background, Color}; use iced_core::{Background, Color};
@ -165,3 +166,30 @@ impl slider::StyleSheet for Theme {
} }
} }
} }
impl radio::StyleSheet for Theme {
type Style = ();
fn active(&self, _style: Self::Style) -> radio::Appearance {
let palette = self.extended_palette();
radio::Appearance {
background: Color::TRANSPARENT.into(),
dot_color: palette.primary.strong.color.into(),
border_width: 1.0,
border_color: palette.primary.strong.color,
text_color: None,
}
}
fn hovered(&self, style: Self::Style) -> radio::Appearance {
let active = self.active(style);
let palette = self.extended_palette();
radio::Appearance {
dot_color: palette.primary.weak.text.into(),
background: palette.primary.weak.color.into(),
..active
}
}
}