Simplify theming for PickList, ComboBox, and Menu widgets
This commit is contained in:
parent
9b2fd64167
commit
597a41cea7
13 changed files with 420 additions and 471 deletions
|
|
@ -10,12 +10,12 @@ use crate::core::text::{self, Text};
|
|||
use crate::core::touch;
|
||||
use crate::core::widget::Tree;
|
||||
use crate::core::{
|
||||
Border, Clipboard, Length, Padding, Pixels, Point, Rectangle, Size, Vector,
|
||||
Background, Border, Clipboard, Color, Length, Padding, Pixels, Point,
|
||||
Rectangle, Size, Vector,
|
||||
};
|
||||
use crate::core::{Element, Shell, Widget};
|
||||
use crate::scrollable::{self, Scrollable};
|
||||
|
||||
pub use iced_style::menu::{Appearance, StyleSheet};
|
||||
use crate::style::Theme;
|
||||
|
||||
/// A list of selectable options.
|
||||
#[allow(missing_debug_implementations)]
|
||||
|
|
@ -26,7 +26,6 @@ pub struct Menu<
|
|||
Theme = crate::Theme,
|
||||
Renderer = crate::Renderer,
|
||||
> where
|
||||
Theme: StyleSheet,
|
||||
Renderer: text::Renderer,
|
||||
{
|
||||
state: &'a mut State,
|
||||
|
|
@ -40,14 +39,14 @@ pub struct Menu<
|
|||
text_line_height: text::LineHeight,
|
||||
text_shaping: text::Shaping,
|
||||
font: Option<Renderer::Font>,
|
||||
style: Theme::Style,
|
||||
style: Style<Theme>,
|
||||
}
|
||||
|
||||
impl<'a, T, Message, Theme, Renderer> Menu<'a, T, Message, Theme, Renderer>
|
||||
where
|
||||
T: ToString + Clone,
|
||||
Message: 'a,
|
||||
Theme: StyleSheet + container::Style + scrollable::Style + 'a,
|
||||
Theme: container::Style + scrollable::Style + 'a,
|
||||
Renderer: text::Renderer + 'a,
|
||||
{
|
||||
/// Creates a new [`Menu`] with the given [`State`], a list of options, and
|
||||
|
|
@ -58,6 +57,29 @@ where
|
|||
hovered_option: &'a mut Option<usize>,
|
||||
on_selected: impl FnMut(T) -> Message + 'a,
|
||||
on_option_hovered: Option<&'a dyn Fn(T) -> Message>,
|
||||
) -> Self
|
||||
where
|
||||
Style<Theme>: Default,
|
||||
{
|
||||
Self::with_style(
|
||||
state,
|
||||
options,
|
||||
hovered_option,
|
||||
on_selected,
|
||||
on_option_hovered,
|
||||
Style::default(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a new [`Menu`] with the given [`State`], a list of options,
|
||||
/// the message to produced when an option is selected, and its [`Style`].
|
||||
pub fn with_style(
|
||||
state: &'a mut State,
|
||||
options: &'a [T],
|
||||
hovered_option: &'a mut Option<usize>,
|
||||
on_selected: impl FnMut(T) -> Message + 'a,
|
||||
on_option_hovered: Option<&'a dyn Fn(T) -> Message>,
|
||||
style: Style<Theme>,
|
||||
) -> Self {
|
||||
Menu {
|
||||
state,
|
||||
|
|
@ -71,7 +93,7 @@ where
|
|||
text_line_height: text::LineHeight::default(),
|
||||
text_shaping: text::Shaping::Basic,
|
||||
font: None,
|
||||
style: Default::default(),
|
||||
style,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -115,10 +137,7 @@ where
|
|||
}
|
||||
|
||||
/// Sets the style of the [`Menu`].
|
||||
pub fn style(
|
||||
mut self,
|
||||
style: impl Into<<Theme as StyleSheet>::Style>,
|
||||
) -> Self {
|
||||
pub fn style(mut self, style: impl Into<Style<Theme>>) -> Self {
|
||||
self.style = style.into();
|
||||
self
|
||||
}
|
||||
|
|
@ -165,7 +184,6 @@ impl Default for State {
|
|||
|
||||
struct Overlay<'a, Message, Theme, Renderer>
|
||||
where
|
||||
Theme: StyleSheet + container::Style,
|
||||
Renderer: crate::core::Renderer,
|
||||
{
|
||||
position: Point,
|
||||
|
|
@ -173,13 +191,13 @@ where
|
|||
container: Container<'a, Message, Theme, Renderer>,
|
||||
width: f32,
|
||||
target_height: f32,
|
||||
style: <Theme as StyleSheet>::Style,
|
||||
style: Style<Theme>,
|
||||
}
|
||||
|
||||
impl<'a, Message, Theme, Renderer> Overlay<'a, Message, Theme, Renderer>
|
||||
where
|
||||
Message: 'a,
|
||||
Theme: StyleSheet + container::Style + scrollable::Style + 'a,
|
||||
Theme: container::Style + scrollable::Style + 'a,
|
||||
Renderer: text::Renderer + 'a,
|
||||
{
|
||||
pub fn new<T>(
|
||||
|
|
@ -205,18 +223,21 @@ where
|
|||
style,
|
||||
} = menu;
|
||||
|
||||
let container = Container::new(Scrollable::new(List {
|
||||
options,
|
||||
hovered_option,
|
||||
on_selected,
|
||||
on_option_hovered,
|
||||
font,
|
||||
text_size,
|
||||
text_line_height,
|
||||
text_shaping,
|
||||
padding,
|
||||
style: style.clone(),
|
||||
}));
|
||||
let container = Container::new(
|
||||
Scrollable::new(List {
|
||||
options,
|
||||
hovered_option,
|
||||
on_selected,
|
||||
on_option_hovered,
|
||||
font,
|
||||
text_size,
|
||||
text_line_height,
|
||||
text_shaping,
|
||||
padding,
|
||||
style: style.menu,
|
||||
})
|
||||
.style(style.scrollable),
|
||||
);
|
||||
|
||||
state.tree.diff(&container as &dyn Widget<_, _, _>);
|
||||
|
||||
|
|
@ -235,7 +256,6 @@ impl<'a, Message, Theme, Renderer>
|
|||
crate::core::Overlay<Message, Theme, Renderer>
|
||||
for Overlay<'a, Message, Theme, Renderer>
|
||||
where
|
||||
Theme: StyleSheet + container::Style,
|
||||
Renderer: text::Renderer,
|
||||
{
|
||||
fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node {
|
||||
|
|
@ -302,9 +322,10 @@ where
|
|||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
) {
|
||||
let appearance = StyleSheet::appearance(theme, &self.style);
|
||||
let bounds = layout.bounds();
|
||||
|
||||
let appearance = (self.style.menu)(theme);
|
||||
|
||||
renderer.fill_quad(
|
||||
renderer::Quad {
|
||||
bounds,
|
||||
|
|
@ -321,7 +342,6 @@ where
|
|||
|
||||
struct List<'a, T, Message, Theme, Renderer>
|
||||
where
|
||||
Theme: StyleSheet,
|
||||
Renderer: text::Renderer,
|
||||
{
|
||||
options: &'a [T],
|
||||
|
|
@ -333,14 +353,13 @@ where
|
|||
text_line_height: text::LineHeight,
|
||||
text_shaping: text::Shaping,
|
||||
font: Option<Renderer::Font>,
|
||||
style: Theme::Style,
|
||||
style: fn(&Theme) -> Appearance,
|
||||
}
|
||||
|
||||
impl<'a, T, Message, Theme, Renderer> Widget<Message, Theme, Renderer>
|
||||
for List<'a, T, Message, Theme, Renderer>
|
||||
where
|
||||
T: Clone + ToString,
|
||||
Theme: StyleSheet,
|
||||
Renderer: text::Renderer,
|
||||
{
|
||||
fn size(&self) -> Size<Length> {
|
||||
|
|
@ -483,7 +502,7 @@ where
|
|||
_cursor: mouse::Cursor,
|
||||
viewport: &Rectangle,
|
||||
) {
|
||||
let appearance = theme.appearance(&self.style);
|
||||
let appearance = (self.style)(theme);
|
||||
let bounds = layout.bounds();
|
||||
|
||||
let text_size =
|
||||
|
|
@ -553,10 +572,68 @@ impl<'a, T, Message, Theme, Renderer>
|
|||
where
|
||||
T: ToString + Clone,
|
||||
Message: 'a,
|
||||
Theme: StyleSheet + 'a,
|
||||
Theme: 'a,
|
||||
Renderer: 'a + text::Renderer,
|
||||
{
|
||||
fn from(list: List<'a, T, Message, Theme, Renderer>) -> Self {
|
||||
Element::new(list)
|
||||
}
|
||||
}
|
||||
|
||||
/// The appearance of a [`Menu`].
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Appearance {
|
||||
/// The [`Background`] of the menu.
|
||||
pub background: Background,
|
||||
/// The [`Border`] of the menu.
|
||||
pub border: Border,
|
||||
/// The text [`Color`] of the menu.
|
||||
pub text_color: Color,
|
||||
/// The text [`Color`] of a selected option in the menu.
|
||||
pub selected_text_color: Color,
|
||||
/// The background [`Color`] of a selected option in the menu.
|
||||
pub selected_background: Background,
|
||||
}
|
||||
|
||||
/// The definiton of the default style of a [`Menu`].
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct Style<Theme> {
|
||||
/// The style of the [`Menu`].
|
||||
menu: fn(&Theme) -> Appearance,
|
||||
/// The style of the [`Scrollable`] of the [`Menu`].
|
||||
scrollable: fn(&Theme, scrollable::Status) -> scrollable::Appearance,
|
||||
}
|
||||
|
||||
impl<Theme> Clone for Style<Theme> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<Theme> Copy for Style<Theme> {}
|
||||
|
||||
impl Default for Style<Theme> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
menu: default,
|
||||
scrollable: scrollable::default,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The default style of a [`Menu`].
|
||||
pub fn default(theme: &Theme) -> Appearance {
|
||||
let palette = theme.extended_palette();
|
||||
|
||||
Appearance {
|
||||
background: palette.background.weak.color.into(),
|
||||
border: Border {
|
||||
width: 1.0,
|
||||
radius: 0.0.into(),
|
||||
color: palette.background.strong.color,
|
||||
},
|
||||
text_color: palette.background.weak.text,
|
||||
selected_text_color: palette.primary.strong.text,
|
||||
selected_background: palette.primary.strong.color.into(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue