Simplify theming for Text widget

This commit is contained in:
Héctor Ramón Jiménez 2024-03-04 19:31:26 +01:00
parent ce309db37b
commit 4130ae4be9
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
12 changed files with 116 additions and 122 deletions

View file

@ -29,7 +29,7 @@ where
vertical_alignment: alignment::Vertical, vertical_alignment: alignment::Vertical,
font: Option<Renderer::Font>, font: Option<Renderer::Font>,
shaping: Shaping, shaping: Shaping,
style: Theme::Style, style: Style<Theme>,
} }
impl<'a, Theme, Renderer> Text<'a, Theme, Renderer> impl<'a, Theme, Renderer> Text<'a, Theme, Renderer>
@ -49,7 +49,7 @@ where
horizontal_alignment: alignment::Horizontal::Left, horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Top, vertical_alignment: alignment::Vertical::Top,
shaping: Shaping::Basic, shaping: Shaping::Basic,
style: Default::default(), style: Style::Themed(Theme::default()),
} }
} }
@ -74,8 +74,20 @@ where
} }
/// Sets the style of the [`Text`]. /// Sets the style of the [`Text`].
pub fn style(mut self, style: impl Into<Theme::Style>) -> Self { pub fn style(mut self, style: fn(&Theme) -> Appearance) -> Self {
self.style = style.into(); self.style = Style::Themed(style);
self
}
/// Sets the [`Color`] of the [`Text`].
pub fn color(mut self, color: impl Into<Color>) -> Self {
self.style = Style::Colored(Some(color.into()));
self
}
/// Sets the [`Color`] of the [`Text`].
pub fn color_maybe(mut self, color: Option<impl Into<Color>>) -> Self {
self.style = Style::Colored(color.map(Into::into));
self self
} }
@ -175,14 +187,12 @@ where
) { ) {
let state = tree.state.downcast_ref::<State<Renderer::Paragraph>>(); let state = tree.state.downcast_ref::<State<Renderer::Paragraph>>();
draw( let appearance = match self.style {
renderer, Style::Themed(f) => f(theme),
style, Style::Colored(color) => Appearance { color },
layout, };
state,
theme.appearance(self.style.clone()), draw(renderer, style, layout, state, appearance, viewport);
viewport,
);
} }
} }
@ -298,7 +308,7 @@ where
horizontal_alignment: self.horizontal_alignment, horizontal_alignment: self.horizontal_alignment,
vertical_alignment: self.vertical_alignment, vertical_alignment: self.vertical_alignment,
font: self.font, font: self.font,
style: self.style.clone(), style: self.style,
shaping: self.shaping, shaping: self.shaping,
} }
} }
@ -327,11 +337,18 @@ where
/// The style sheet of some text. /// The style sheet of some text.
pub trait StyleSheet { pub trait StyleSheet {
/// The supported style of the [`StyleSheet`]. /// Returns the default styling strategy for [`Text`].
type Style: Default + Clone; fn default() -> fn(&Self) -> Appearance {
|_| Appearance::default()
}
}
/// Produces the [`Appearance`] of some text. impl StyleSheet for Color {
fn appearance(&self, style: Self::Style) -> Appearance; fn default() -> fn(&Self) -> Appearance {
|color| Appearance {
color: Some(*color),
}
}
} }
/// The apperance of some text. /// The apperance of some text.
@ -342,3 +359,17 @@ pub struct Appearance {
/// The default, `None`, means using the inherited color. /// The default, `None`, means using the inherited color.
pub color: Option<Color>, pub color: Option<Color>,
} }
#[derive(Debug)]
enum Style<Theme> {
Themed(fn(&Theme) -> Appearance),
Colored(Option<Color>),
}
impl<Theme> Clone for Style<Theme> {
fn clone(&self) -> Self {
*self
}
}
impl<Theme> Copy for Style<Theme> {}

View file

@ -1,25 +1,26 @@
use iced_wgpu::Renderer; use iced_wgpu::Renderer;
use iced_widget::{slider, text_input, Column, Row, Text}; use iced_widget::{column, container, row, slider, text, text_input};
use iced_winit::core::{Alignment, Color, Element, Length}; use iced_winit::core::alignment;
use iced_winit::core::{Color, Element, Length};
use iced_winit::runtime::{Command, Program}; use iced_winit::runtime::{Command, Program};
use iced_winit::style::Theme; use iced_winit::style::Theme;
pub struct Controls { pub struct Controls {
background_color: Color, background_color: Color,
text: String, input: String,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Message { pub enum Message {
BackgroundColorChanged(Color), BackgroundColorChanged(Color),
TextChanged(String), InputChanged(String),
} }
impl Controls { impl Controls {
pub fn new() -> Controls { pub fn new() -> Controls {
Controls { Controls {
background_color: Color::BLACK, background_color: Color::BLACK,
text: String::default(), input: String::default(),
} }
} }
@ -38,8 +39,8 @@ impl Program for Controls {
Message::BackgroundColorChanged(color) => { Message::BackgroundColorChanged(color) => {
self.background_color = color; self.background_color = color;
} }
Message::TextChanged(text) => { Message::InputChanged(input) => {
self.text = text; self.input = input;
} }
} }
@ -48,60 +49,48 @@ impl Program for Controls {
fn view(&self) -> Element<Message, Theme, Renderer> { fn view(&self) -> Element<Message, Theme, Renderer> {
let background_color = self.background_color; let background_color = self.background_color;
let text = &self.text;
let sliders = Row::new() let sliders = row![
.width(500) slider(0.0..=1.0, background_color.r, move |r| {
.spacing(20) Message::BackgroundColorChanged(Color {
.push( r,
slider(0.0..=1.0, background_color.r, move |r| { ..background_color
Message::BackgroundColorChanged(Color {
r,
..background_color
})
}) })
.step(0.01), })
) .step(0.01),
.push( slider(0.0..=1.0, background_color.g, move |g| {
slider(0.0..=1.0, background_color.g, move |g| { Message::BackgroundColorChanged(Color {
Message::BackgroundColorChanged(Color { g,
g, ..background_color
..background_color
})
}) })
.step(0.01), })
) .step(0.01),
.push( slider(0.0..=1.0, background_color.b, move |b| {
slider(0.0..=1.0, background_color.b, move |b| { Message::BackgroundColorChanged(Color {
Message::BackgroundColorChanged(Color { b,
b, ..background_color
..background_color
})
}) })
.step(0.01), })
); .step(0.01),
]
.width(500)
.spacing(20);
Row::new() container(
.height(Length::Fill) column![
.align_items(Alignment::End) text("Background color").color(Color::WHITE),
.push( text(format!("{background_color:?}"))
Column::new().align_items(Alignment::End).push( .size(14)
Column::new() .color(Color::WHITE),
.padding(10) text_input("Placeholder", &self.input)
.spacing(10) .on_input(Message::InputChanged),
.push(Text::new("Background color").style(Color::WHITE)) sliders,
.push(sliders) ]
.push( .spacing(10),
Text::new(format!("{background_color:?}")) )
.size(14) .padding(10)
.style(Color::WHITE), .height(Length::Fill)
) .align_y(alignment::Vertical::Bottom)
.push( .into()
text_input("Placeholder", text)
.on_input(Message::TextChanged),
),
),
)
.into()
} }
} }

View file

@ -184,8 +184,7 @@ impl Sandbox for App {
.style(theme::Button::Destructive); .style(theme::Button::Destructive);
row![ row![
text(&item.name) text(&item.name).color(item.color),
.style(theme::Text::Color(item.color.into())),
horizontal_space(), horizontal_space(),
pick_list(Color::ALL, Some(item.color), move |color| { pick_list(Color::ALL, Some(item.color), move |color| {
Message::ItemColorChanged(item.clone(), color) Message::ItemColorChanged(item.clone(), color)

View file

@ -162,7 +162,7 @@ impl Application for Example {
let title = row![ let title = row![
pin_button, pin_button,
"Pane", "Pane",
text(pane.id.to_string()).style(if is_focused { text(pane.id.to_string()).color(if is_focused {
PANE_ID_COLOR_FOCUSED PANE_ID_COLOR_FOCUSED
} else { } else {
PANE_ID_COLOR_UNFOCUSED PANE_ID_COLOR_UNFOCUSED

View file

@ -1,8 +1,6 @@
use iced::futures; use iced::futures;
use iced::widget::{self, column, container, image, row, text}; use iced::widget::{self, column, container, image, row, text};
use iced::{ use iced::{Alignment, Application, Command, Element, Length, Settings, Theme};
Alignment, Application, Color, Command, Element, Length, Settings, Theme,
};
pub fn main() -> iced::Result { pub fn main() -> iced::Result {
Pokedex::run(Settings::default()) Pokedex::run(Settings::default())
@ -116,7 +114,7 @@ impl Pokemon {
text(&self.name).size(30).width(Length::Fill), text(&self.name).size(30).width(Length::Fill),
text(format!("#{}", self.number)) text(format!("#{}", self.number))
.size(20) .size(20)
.style(Color::from([0.5, 0.5, 0.5])), .color([0.5, 0.5, 0.5]),
] ]
.align_items(Alignment::Center) .align_items(Alignment::Center)
.spacing(20), .spacing(20),

View file

@ -8,7 +8,7 @@ use iced::widget::{
}; };
use iced::window; use iced::window;
use iced::{Application, Element}; use iced::{Application, Element};
use iced::{Color, Command, Length, Settings, Size, Subscription}; use iced::{Command, Length, Settings, Size, Subscription};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -209,7 +209,7 @@ impl Application for Todos {
let title = text("todos") let title = text("todos")
.width(Length::Fill) .width(Length::Fill)
.size(100) .size(100)
.style(Color::from([0.5, 0.5, 0.5])) .color([0.5, 0.5, 0.5])
.horizontal_alignment(alignment::Horizontal::Center); .horizontal_alignment(alignment::Horizontal::Center);
let input = text_input("What needs to be done?", input_value) let input = text_input("What needs to be done?", input_value)
@ -467,7 +467,7 @@ fn empty_message(message: &str) -> Element<'_, Message> {
.width(Length::Fill) .width(Length::Fill)
.size(25) .size(25)
.horizontal_alignment(alignment::Horizontal::Center) .horizontal_alignment(alignment::Horizontal::Center)
.style(Color::from([0.7, 0.7, 0.7])), .color([0.7, 0.7, 0.7]),
) )
.height(200) .height(200)
.center_y() .center_y()

View file

@ -474,7 +474,7 @@ impl<'a> Step {
let color_section = column![ let color_section = column![
"And its color:", "And its color:",
text(format!("{color:?}")).style(color), text(format!("{color:?}")).color(color),
color_sliders, color_sliders,
] ]
.padding(20) .padding(20)

View file

@ -82,7 +82,10 @@ impl Application for Example {
row![ row![
text(label), text(label),
horizontal_space(), horizontal_space(),
text(value).font(Font::MONOSPACE).size(14).style(color), text(value)
.font(Font::MONOSPACE)
.size(14)
.color_maybe(color),
] ]
.height(40) .height(40)
.align_items(Alignment::Center) .align_items(Alignment::Center)
@ -102,13 +105,12 @@ impl Application for Example {
}) })
.unwrap_or_default() .unwrap_or_default()
{ {
Color { Some(Color {
g: 1.0, g: 1.0,
..Color::BLACK ..Color::BLACK
} })
.into()
} else { } else {
theme::Text::Default None
}, },
) )
}; };
@ -120,7 +122,7 @@ impl Application for Example {
Some(Point { x, y }) => format!("({x}, {y})"), Some(Point { x, y }) => format!("({x}, {y})"),
None => "unknown".to_string(), None => "unknown".to_string(),
}, },
theme::Text::Default, None,
), ),
view_bounds("Outer container", self.outer_bounds), view_bounds("Outer container", self.outer_bounds),
view_bounds("Inner container", self.inner_bounds), view_bounds("Inner container", self.inner_bounds),

View file

@ -6,7 +6,7 @@ use iced::widget::{
button, column, container, row, scrollable, text, text_input, button, column, container, row, scrollable, text, text_input,
}; };
use iced::{ use iced::{
Application, Color, Command, Element, Length, Settings, Subscription, Theme, color, Application, Command, Element, Length, Settings, Subscription, Theme,
}; };
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
@ -99,7 +99,7 @@ impl Application for WebSocket {
let message_log: Element<_> = if self.messages.is_empty() { let message_log: Element<_> = if self.messages.is_empty() {
container( container(
text("Your messages will appear here...") text("Your messages will appear here...")
.style(Color::from_rgb8(0x88, 0x88, 0x88)), .color(color!(0x888888)),
) )
.width(Length::Fill) .width(Length::Fill)
.height(Length::Fill) .height(Length::Fill)

View file

@ -1203,32 +1203,7 @@ impl scrollable::StyleSheet for Theme {
} }
} }
/// The style of text. impl text::StyleSheet for Theme {}
#[derive(Clone, Copy, Default)]
pub enum Text {
/// The default style.
#[default]
Default,
/// Colored text.
Color(Color),
}
impl From<Color> for Text {
fn from(color: Color) -> Self {
Text::Color(color)
}
}
impl text::StyleSheet for Theme {
type Style = Text;
fn appearance(&self, style: Self::Style) -> text::Appearance {
match style {
Text::Default => text::Appearance::default(),
Text::Color(c) => text::Appearance { color: Some(c) },
}
}
}
/// The style of a text input. /// The style of a text input.
#[derive(Default)] #[derive(Default)]

View file

@ -39,7 +39,7 @@ pub struct Checkbox<
Theme = crate::Theme, Theme = crate::Theme,
Renderer = crate::Renderer, Renderer = crate::Renderer,
> where > where
Theme: StyleSheet + crate::text::StyleSheet, Theme: StyleSheet,
Renderer: text::Renderer, Renderer: text::Renderer,
{ {
is_checked: bool, is_checked: bool,

View file

@ -20,7 +20,7 @@ pub struct Tooltip<
Theme = crate::Theme, Theme = crate::Theme,
Renderer = crate::Renderer, Renderer = crate::Renderer,
> where > where
Theme: container::StyleSheet + crate::text::StyleSheet, Theme: container::StyleSheet,
Renderer: text::Renderer, Renderer: text::Renderer,
{ {
content: Element<'a, Message, Theme, Renderer>, content: Element<'a, Message, Theme, Renderer>,
@ -34,7 +34,7 @@ pub struct Tooltip<
impl<'a, Message, Theme, Renderer> Tooltip<'a, Message, Theme, Renderer> impl<'a, Message, Theme, Renderer> Tooltip<'a, Message, Theme, Renderer>
where where
Theme: container::StyleSheet + crate::text::StyleSheet, Theme: container::StyleSheet,
Renderer: text::Renderer, Renderer: text::Renderer,
{ {
/// The default padding of a [`Tooltip`] drawn by this renderer. /// The default padding of a [`Tooltip`] drawn by this renderer.