Replace stateful widgets with new iced_pure API

This commit is contained in:
Héctor Ramón Jiménez 2022-07-27 06:49:20 +02:00
parent c44267b85f
commit ff2519b1d4
No known key found for this signature in database
GPG key ID: 140CC052C94F138E
142 changed files with 3631 additions and 14494 deletions

View file

@ -9,8 +9,7 @@ use crate::overlay::menu::{self, Menu};
use crate::renderer;
use crate::text::{self, Text};
use crate::touch;
use crate::widget::container;
use crate::widget::scrollable;
use crate::widget::tree::{self, Tree};
use crate::{
Clipboard, Element, Layout, Length, Padding, Point, Rectangle, Shell, Size,
Widget,
@ -27,8 +26,7 @@ where
Renderer: text::Renderer,
Renderer::Theme: StyleSheet,
{
state: &'a mut State<T>,
on_selected: Box<dyn Fn(T) -> Message>,
on_selected: Box<dyn Fn(T) -> Message + 'a>,
options: Cow<'a, [T]>,
placeholder: Option<String>,
selected: Option<T>,
@ -39,35 +37,6 @@ where
style: <Renderer::Theme as StyleSheet>::Style,
}
/// The local state of a [`PickList`].
#[derive(Debug, Clone)]
pub struct State<T> {
menu: menu::State,
keyboard_modifiers: keyboard::Modifiers,
is_open: bool,
hovered_option: Option<usize>,
last_selection: Option<T>,
}
impl<T> State<T> {
/// Creates a new [`State`] for a [`PickList`].
pub fn new() -> Self {
Self {
menu: menu::State::default(),
keyboard_modifiers: keyboard::Modifiers::default(),
is_open: bool::default(),
hovered_option: Option::default(),
last_selection: Option::default(),
}
}
}
impl<T> Default for State<T> {
fn default() -> Self {
Self::new()
}
}
impl<'a, T: 'a, Message, Renderer> PickList<'a, T, Message, Renderer>
where
T: ToString + Eq,
@ -78,17 +47,14 @@ where
/// The default padding of a [`PickList`].
pub const DEFAULT_PADDING: Padding = Padding::new(5);
/// Creates a new [`PickList`] with the given [`State`], a list of options,
/// the current selected value, and the message to produce when an option is
/// selected.
/// Creates a new [`PickList`] with the given list of options, the current
/// selected value, and the message to produce when an option is selected.
pub fn new(
state: &'a mut State<T>,
options: impl Into<Cow<'a, [T]>>,
selected: Option<T>,
on_selected: impl Fn(T) -> Message + 'static,
on_selected: impl Fn(T) -> Message + 'a,
) -> Self {
Self {
state,
on_selected: Box::new(on_selected),
options: options.into(),
placeholder: None,
@ -141,6 +107,168 @@ where
}
}
impl<'a, T: 'a, Message, Renderer> Widget<Message, Renderer>
for PickList<'a, T, Message, Renderer>
where
T: Clone + ToString + Eq + 'static,
[T]: ToOwned<Owned = Vec<T>>,
Message: 'a,
Renderer: text::Renderer + 'a,
Renderer::Theme: StyleSheet,
{
fn tag(&self) -> tree::Tag {
tree::Tag::of::<State<T>>()
}
fn state(&self) -> tree::State {
tree::State::new(State::<T>::new())
}
fn width(&self) -> Length {
self.width
}
fn height(&self) -> Length {
Length::Shrink
}
fn layout(
&self,
renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
layout(
renderer,
limits,
self.width,
self.padding,
self.text_size,
&self.font,
self.placeholder.as_deref(),
&self.options,
)
}
fn on_event(
&mut self,
tree: &mut Tree,
event: Event,
layout: Layout<'_>,
cursor_position: Point,
_renderer: &Renderer,
_clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
) -> event::Status {
update(
event,
layout,
cursor_position,
shell,
self.on_selected.as_ref(),
self.selected.as_ref(),
&self.options,
|| tree.state.downcast_mut::<State<T>>(),
)
}
fn mouse_interaction(
&self,
_tree: &Tree,
layout: Layout<'_>,
cursor_position: Point,
_viewport: &Rectangle,
_renderer: &Renderer,
) -> mouse::Interaction {
mouse_interaction(layout, cursor_position)
}
fn draw(
&self,
_tree: &Tree,
renderer: &mut Renderer,
theme: &Renderer::Theme,
_style: &renderer::Style,
layout: Layout<'_>,
cursor_position: Point,
_viewport: &Rectangle,
) {
draw(
renderer,
theme,
layout,
cursor_position,
self.padding,
self.text_size,
&self.font,
self.placeholder.as_deref(),
self.selected.as_ref(),
self.style,
)
}
fn overlay<'b>(
&'b self,
tree: &'b mut Tree,
layout: Layout<'_>,
_renderer: &Renderer,
) -> Option<overlay::Element<'b, Message, Renderer>> {
let state = tree.state.downcast_mut::<State<T>>();
overlay(
layout,
state,
self.padding,
self.text_size,
self.font.clone(),
&self.options,
self.style,
)
}
}
impl<'a, T: 'a, Message, Renderer> From<PickList<'a, T, Message, Renderer>>
for Element<'a, Message, Renderer>
where
T: Clone + ToString + Eq + 'static,
[T]: ToOwned<Owned = Vec<T>>,
Message: 'a,
Renderer: text::Renderer + 'a,
Renderer::Theme: StyleSheet,
{
fn from(pick_list: PickList<'a, T, Message, Renderer>) -> Self {
Self::new(pick_list)
}
}
/// The local state of a [`PickList`].
#[derive(Debug)]
pub struct State<T> {
menu: menu::State,
keyboard_modifiers: keyboard::Modifiers,
is_open: bool,
hovered_option: Option<usize>,
last_selection: Option<T>,
}
impl<T> State<T> {
/// Creates a new [`State`] for a [`PickList`].
pub fn new() -> Self {
Self {
menu: menu::State::default(),
keyboard_modifiers: keyboard::Modifiers::default(),
is_open: bool::default(),
hovered_option: Option::default(),
last_selection: Option::default(),
}
}
}
impl<T> Default for State<T> {
fn default() -> Self {
Self::new()
}
}
/// Computes the layout of a [`PickList`].
pub fn layout<Renderer, T>(
renderer: &Renderer,
@ -429,127 +557,3 @@ pub fn draw<T, Renderer>(
});
}
}
impl<'a, T: 'a, Message, Renderer> Widget<Message, Renderer>
for PickList<'a, T, Message, Renderer>
where
T: Clone + ToString + Eq,
[T]: ToOwned<Owned = Vec<T>>,
Message: 'static,
Renderer: text::Renderer + 'a,
Renderer::Theme: StyleSheet,
{
fn width(&self) -> Length {
self.width
}
fn height(&self) -> Length {
Length::Shrink
}
fn layout(
&self,
renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
layout(
renderer,
limits,
self.width,
self.padding,
self.text_size,
&self.font,
self.placeholder.as_deref(),
&self.options,
)
}
fn on_event(
&mut self,
event: Event,
layout: Layout<'_>,
cursor_position: Point,
_renderer: &Renderer,
_clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
) -> event::Status {
update(
event,
layout,
cursor_position,
shell,
self.on_selected.as_ref(),
self.selected.as_ref(),
&self.options,
|| &mut self.state,
)
}
fn mouse_interaction(
&self,
layout: Layout<'_>,
cursor_position: Point,
_viewport: &Rectangle,
_renderer: &Renderer,
) -> mouse::Interaction {
mouse_interaction(layout, cursor_position)
}
fn draw(
&self,
renderer: &mut Renderer,
theme: &Renderer::Theme,
_style: &renderer::Style,
layout: Layout<'_>,
cursor_position: Point,
_viewport: &Rectangle,
) {
draw(
renderer,
theme,
layout,
cursor_position,
self.padding,
self.text_size,
&self.font,
self.placeholder.as_deref(),
self.selected.as_ref(),
self.style,
)
}
fn overlay(
&mut self,
layout: Layout<'_>,
_renderer: &Renderer,
) -> Option<overlay::Element<'_, Message, Renderer>> {
overlay(
layout,
self.state,
self.padding,
self.text_size,
self.font.clone(),
&self.options,
self.style,
)
}
}
impl<'a, T: 'a, Message, Renderer> From<PickList<'a, T, Message, Renderer>>
for Element<'a, Message, Renderer>
where
T: Clone + ToString + Eq,
[T]: ToOwned<Owned = Vec<T>>,
Message: 'static,
Renderer: text::Renderer + 'a,
Renderer::Theme: StyleSheet
+ container::StyleSheet
+ scrollable::StyleSheet
+ menu::StyleSheet,
<Renderer::Theme as StyleSheet>::Style:
Into<<Renderer::Theme as menu::StyleSheet>::Style>,
{
fn from(pick_list: PickList<'a, T, Message, Renderer>) -> Self {
Element::new(pick_list)
}
}