From efaa80fb4429e7f9bd2f8a1161be3fa66a3e9e32 Mon Sep 17 00:00:00 2001 From: Casper Storm Date: Thu, 26 Jan 2023 12:20:43 +0100 Subject: Extend pick_list::Handle --- native/src/widget/pick_list.rs | 82 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 68 insertions(+), 14 deletions(-) (limited to 'native') diff --git a/native/src/widget/pick_list.rs b/native/src/widget/pick_list.rs index c2853314..862c4157 100644 --- a/native/src/widget/pick_list.rs +++ b/native/src/widget/pick_list.rs @@ -20,6 +20,43 @@ use std::borrow::Cow; pub use iced_style::pick_list::{Appearance, StyleSheet}; +/// The content of the [`Handle`]. +#[derive(Clone)] +pub struct HandleContent +where + Renderer: text::Renderer, +{ + /// Font that will be used to display the `text`, + pub font: Renderer::Font, + /// Text that will be shown. + pub text: String, + /// Font size of the content. + pub size: Option, +} + +impl std::fmt::Debug for HandleContent +where + Renderer: text::Renderer, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("HandleIcon") + .field("text", &self.text) + .field("size", &self.size) + .finish() + } +} + +impl PartialEq for HandleContent +where + Renderer: text::Renderer, +{ + fn eq(&self, other: &Self) -> bool { + self.text.eq(&other.text) && self.size.eq(&other.size) + } +} + +impl Eq for HandleContent where Renderer: text::Renderer {} + /// The handle to the right side of the [`PickList`]. #[derive(Debug, Clone, PartialEq, Eq)] pub enum Handle @@ -33,14 +70,14 @@ where /// Font size of the content. size: Option, }, - /// A custom handle. - Custom { - /// Font that will be used to display the `text`, - font: Renderer::Font, - /// Text that will be shown. - text: String, - /// Font size of the content. - size: Option, + /// A custom static handle. + Static(HandleContent), + /// A custom dynamic handle. + Dynamic { + /// The [`HandleContent`] used when [`PickList`] is closed. + closed: HandleContent, + /// The [`HandleContent`] used when [`PickList`] is open. + open: HandleContent, }, /// No handle will be shown. None, @@ -59,16 +96,30 @@ impl Handle where Renderer: text::Renderer, { - fn content(&self) -> Option<(Renderer::Font, String, Option)> { + fn content( + &self, + is_open: bool, + ) -> Option<(Renderer::Font, String, Option)> { match self { Self::Arrow { size } => Some(( Renderer::ICON_FONT, Renderer::ARROW_DOWN_ICON.to_string(), *size, )), - Self::Custom { font, text, size } => { + Self::Static(HandleContent { font, text, size }) => { Some((font.clone(), text.clone(), *size)) } + Self::Dynamic { open, closed } => { + if is_open { + Some((open.font.clone(), open.text.clone(), open.size)) + } else { + Some(( + closed.font.clone(), + closed.text.clone(), + closed.size, + )) + } + } Self::None => None, } } @@ -258,7 +309,7 @@ where fn draw( &self, - _tree: &Tree, + tree: &Tree, renderer: &mut Renderer, theme: &Renderer::Theme, _style: &renderer::Style, @@ -278,6 +329,7 @@ where self.selected.as_ref(), &self.handle, &self.style, + || tree.state.downcast_ref::>(), ) } @@ -568,7 +620,7 @@ where } /// Draws a [`PickList`]. -pub fn draw( +pub fn draw<'a, T, Renderer>( renderer: &mut Renderer, theme: &Renderer::Theme, layout: Layout<'_>, @@ -580,11 +632,13 @@ pub fn draw( selected: Option<&T>, handle: &Handle, style: &::Style, + state: impl FnOnce() -> &'a State, ) where Renderer: text::Renderer, Renderer::Theme: StyleSheet, - T: ToString, + T: ToString + 'a, { + let state = state(); let bounds = layout.bounds(); let is_mouse_over = bounds.contains(cursor_position); let is_selected = selected.is_some(); @@ -605,7 +659,7 @@ pub fn draw( style.background, ); - if let Some((font, text, size)) = handle.content() { + if let Some((font, text, size)) = handle.content(state.is_open) { let size = f32::from(size.unwrap_or_else(|| renderer.default_size())); renderer.fill_text(Text { -- cgit From 5569e12149f9c29345fe404552ce156ef0bebf0e Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 14 Feb 2023 06:56:59 +0100 Subject: Rename `HandleContent` to `Icon` and simplify generics --- native/src/widget/pick_list.rs | 74 ++++++++++++------------------------------ 1 file changed, 20 insertions(+), 54 deletions(-) (limited to 'native') diff --git a/native/src/widget/pick_list.rs b/native/src/widget/pick_list.rs index 862c4157..17fb00d5 100644 --- a/native/src/widget/pick_list.rs +++ b/native/src/widget/pick_list.rs @@ -20,49 +20,20 @@ use std::borrow::Cow; pub use iced_style::pick_list::{Appearance, StyleSheet}; -/// The content of the [`Handle`]. -#[derive(Clone)] -pub struct HandleContent -where - Renderer: text::Renderer, -{ +/// The icon of a [`Handle`]. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Icon { /// Font that will be used to display the `text`, - pub font: Renderer::Font, + pub font: Font, /// Text that will be shown. pub text: String, /// Font size of the content. pub size: Option, } -impl std::fmt::Debug for HandleContent -where - Renderer: text::Renderer, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("HandleIcon") - .field("text", &self.text) - .field("size", &self.size) - .finish() - } -} - -impl PartialEq for HandleContent -where - Renderer: text::Renderer, -{ - fn eq(&self, other: &Self) -> bool { - self.text.eq(&other.text) && self.size.eq(&other.size) - } -} - -impl Eq for HandleContent where Renderer: text::Renderer {} - /// The handle to the right side of the [`PickList`]. #[derive(Debug, Clone, PartialEq, Eq)] -pub enum Handle -where - Renderer: text::Renderer, -{ +pub enum Handle { /// Displays an arrow icon (▼). /// /// This is the default. @@ -71,42 +42,36 @@ where size: Option, }, /// A custom static handle. - Static(HandleContent), + Static(Icon), /// A custom dynamic handle. Dynamic { - /// The [`HandleContent`] used when [`PickList`] is closed. - closed: HandleContent, - /// The [`HandleContent`] used when [`PickList`] is open. - open: HandleContent, + /// The [`Icon`] used when [`PickList`] is closed. + closed: Icon, + /// The [`Icon`] used when [`PickList`] is open. + open: Icon, }, /// No handle will be shown. None, } -impl Default for Handle -where - Renderer: text::Renderer, -{ +impl Default for Handle { fn default() -> Self { Self::Arrow { size: None } } } -impl Handle -where - Renderer: text::Renderer, -{ - fn content( +impl Handle { + fn content>( &self, is_open: bool, - ) -> Option<(Renderer::Font, String, Option)> { + ) -> Option<(Font, String, Option)> { match self { Self::Arrow { size } => Some(( Renderer::ICON_FONT, Renderer::ARROW_DOWN_ICON.to_string(), *size, )), - Self::Static(HandleContent { font, text, size }) => { + Self::Static(Icon { font, text, size }) => { Some((font.clone(), text.clone(), *size)) } Self::Dynamic { open, closed } => { @@ -141,7 +106,7 @@ where padding: Padding, text_size: Option, font: Renderer::Font, - handle: Handle, + handle: Handle, style: ::Style, } @@ -212,7 +177,7 @@ where } /// Sets the [`Handle`] of the [`PickList`]. - pub fn handle(mut self, handle: Handle) -> Self { + pub fn handle(mut self, handle: Handle) -> Self { self.handle = handle; self } @@ -630,7 +595,7 @@ pub fn draw<'a, T, Renderer>( font: &Renderer::Font, placeholder: Option<&str>, selected: Option<&T>, - handle: &Handle, + handle: &Handle, style: &::Style, state: impl FnOnce() -> &'a State, ) where @@ -659,7 +624,8 @@ pub fn draw<'a, T, Renderer>( style.background, ); - if let Some((font, text, size)) = handle.content(state.is_open) { + if let Some((font, text, size)) = handle.content::(state.is_open) + { let size = f32::from(size.unwrap_or_else(|| renderer.default_size())); renderer.fill_text(Text { -- cgit From 0272cac89e2bb3e037d0d9d5caa8b7c584386417 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 14 Feb 2023 06:59:37 +0100 Subject: Move `Handle` and `Icon` definitions in `pick_list` --- native/src/widget/pick_list.rs | 140 ++++++++++++++++++++--------------------- 1 file changed, 70 insertions(+), 70 deletions(-) (limited to 'native') diff --git a/native/src/widget/pick_list.rs b/native/src/widget/pick_list.rs index 17fb00d5..b9f6f088 100644 --- a/native/src/widget/pick_list.rs +++ b/native/src/widget/pick_list.rs @@ -20,76 +20,6 @@ use std::borrow::Cow; pub use iced_style::pick_list::{Appearance, StyleSheet}; -/// The icon of a [`Handle`]. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Icon { - /// Font that will be used to display the `text`, - pub font: Font, - /// Text that will be shown. - pub text: String, - /// Font size of the content. - pub size: Option, -} - -/// The handle to the right side of the [`PickList`]. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum Handle { - /// Displays an arrow icon (▼). - /// - /// This is the default. - Arrow { - /// Font size of the content. - size: Option, - }, - /// A custom static handle. - Static(Icon), - /// A custom dynamic handle. - Dynamic { - /// The [`Icon`] used when [`PickList`] is closed. - closed: Icon, - /// The [`Icon`] used when [`PickList`] is open. - open: Icon, - }, - /// No handle will be shown. - None, -} - -impl Default for Handle { - fn default() -> Self { - Self::Arrow { size: None } - } -} - -impl Handle { - fn content>( - &self, - is_open: bool, - ) -> Option<(Font, String, Option)> { - match self { - Self::Arrow { size } => Some(( - Renderer::ICON_FONT, - Renderer::ARROW_DOWN_ICON.to_string(), - *size, - )), - Self::Static(Icon { font, text, size }) => { - Some((font.clone(), text.clone(), *size)) - } - Self::Dynamic { open, closed } => { - if is_open { - Some((open.font.clone(), open.text.clone(), open.size)) - } else { - Some(( - closed.font.clone(), - closed.text.clone(), - closed.size, - )) - } - } - Self::None => None, - } - } -} - /// A widget for selecting a single value from a list of options. #[allow(missing_debug_implementations)] pub struct PickList<'a, T, Message, Renderer> @@ -366,6 +296,76 @@ impl Default for State { } } +/// The handle to the right side of the [`PickList`]. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Handle { + /// Displays an arrow icon (▼). + /// + /// This is the default. + Arrow { + /// Font size of the content. + size: Option, + }, + /// A custom static handle. + Static(Icon), + /// A custom dynamic handle. + Dynamic { + /// The [`Icon`] used when [`PickList`] is closed. + closed: Icon, + /// The [`Icon`] used when [`PickList`] is open. + open: Icon, + }, + /// No handle will be shown. + None, +} + +impl Default for Handle { + fn default() -> Self { + Self::Arrow { size: None } + } +} + +impl Handle { + fn content>( + &self, + is_open: bool, + ) -> Option<(Font, String, Option)> { + match self { + Self::Arrow { size } => Some(( + Renderer::ICON_FONT, + Renderer::ARROW_DOWN_ICON.to_string(), + *size, + )), + Self::Static(Icon { font, text, size }) => { + Some((font.clone(), text.clone(), *size)) + } + Self::Dynamic { open, closed } => { + if is_open { + Some((open.font.clone(), open.text.clone(), open.size)) + } else { + Some(( + closed.font.clone(), + closed.text.clone(), + closed.size, + )) + } + } + Self::None => None, + } + } +} + +/// The icon of a [`Handle`]. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Icon { + /// Font that will be used to display the `text`, + pub font: Font, + /// Text that will be shown. + pub text: String, + /// Font size of the content. + pub size: Option, +} + /// Computes the layout of a [`PickList`]. pub fn layout( renderer: &Renderer, -- cgit From bbff06b4621ae586b951564c8cc4bf95608bbb81 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 14 Feb 2023 07:02:33 +0100 Subject: Use `char` instead of `String` for `pick_list::Icon` --- native/src/widget/pick_list.rs | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) (limited to 'native') diff --git a/native/src/widget/pick_list.rs b/native/src/widget/pick_list.rs index b9f6f088..b96ffac2 100644 --- a/native/src/widget/pick_list.rs +++ b/native/src/widget/pick_list.rs @@ -329,25 +329,21 @@ impl Handle { fn content>( &self, is_open: bool, - ) -> Option<(Font, String, Option)> { + ) -> Option<(Font, char, Option)> { match self { - Self::Arrow { size } => Some(( - Renderer::ICON_FONT, - Renderer::ARROW_DOWN_ICON.to_string(), - *size, - )), - Self::Static(Icon { font, text, size }) => { - Some((font.clone(), text.clone(), *size)) + Self::Arrow { size } => { + Some((Renderer::ICON_FONT, Renderer::ARROW_DOWN_ICON, *size)) } + Self::Static(Icon { + font, + code_point, + size, + }) => Some((font.clone(), *code_point, *size)), Self::Dynamic { open, closed } => { if is_open { - Some((open.font.clone(), open.text.clone(), open.size)) + Some((open.font.clone(), open.code_point, open.size)) } else { - Some(( - closed.font.clone(), - closed.text.clone(), - closed.size, - )) + Some((closed.font.clone(), closed.code_point, closed.size)) } } Self::None => None, @@ -358,10 +354,10 @@ impl Handle { /// The icon of a [`Handle`]. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Icon { - /// Font that will be used to display the `text`, + /// Font that will be used to display the `code_point`, pub font: Font, - /// Text that will be shown. - pub text: String, + /// The unicode code point that will be used as the icon. + pub code_point: char, /// Font size of the content. pub size: Option, } @@ -624,12 +620,13 @@ pub fn draw<'a, T, Renderer>( style.background, ); - if let Some((font, text, size)) = handle.content::(state.is_open) + if let Some((font, code_point, size)) = + handle.content::(state.is_open) { let size = f32::from(size.unwrap_or_else(|| renderer.default_size())); renderer.fill_text(Text { - content: &text, + content: &code_point.to_string(), size, font, color: style.handle_color, -- cgit From fee1ab69e2bab01e5d736540be8b253ff62c3e5e Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 14 Feb 2023 07:05:18 +0100 Subject: Provide `State` reference instead of closure to `pick_list::draw` --- native/src/widget/pick_list.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'native') diff --git a/native/src/widget/pick_list.rs b/native/src/widget/pick_list.rs index b96ffac2..8189dd61 100644 --- a/native/src/widget/pick_list.rs +++ b/native/src/widget/pick_list.rs @@ -224,7 +224,7 @@ where self.selected.as_ref(), &self.handle, &self.style, - || tree.state.downcast_ref::>(), + tree.state.downcast_ref::>(), ) } @@ -593,13 +593,12 @@ pub fn draw<'a, T, Renderer>( selected: Option<&T>, handle: &Handle, style: &::Style, - state: impl FnOnce() -> &'a State, + state: &State, ) where Renderer: text::Renderer, Renderer::Theme: StyleSheet, T: ToString + 'a, { - let state = state(); let bounds = layout.bounds(); let is_mouse_over = bounds.contains(cursor_position); let is_selected = selected.is_some(); -- cgit From 7f1d58aa4591eba40dd6f3e6bc2869dcdc3e9adb Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 14 Feb 2023 07:09:24 +0100 Subject: Inline `Handle::content` for simplicity and efficiency We can avoid downcasting `state` :^) --- native/src/widget/pick_list.rs | 53 ++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 31 deletions(-) (limited to 'native') diff --git a/native/src/widget/pick_list.rs b/native/src/widget/pick_list.rs index 8189dd61..b1cdfad4 100644 --- a/native/src/widget/pick_list.rs +++ b/native/src/widget/pick_list.rs @@ -224,7 +224,7 @@ where self.selected.as_ref(), &self.handle, &self.style, - tree.state.downcast_ref::>(), + || tree.state.downcast_ref::>(), ) } @@ -325,32 +325,6 @@ impl Default for Handle { } } -impl Handle { - fn content>( - &self, - is_open: bool, - ) -> Option<(Font, char, Option)> { - match self { - Self::Arrow { size } => { - Some((Renderer::ICON_FONT, Renderer::ARROW_DOWN_ICON, *size)) - } - Self::Static(Icon { - font, - code_point, - size, - }) => Some((font.clone(), *code_point, *size)), - Self::Dynamic { open, closed } => { - if is_open { - Some((open.font.clone(), open.code_point, open.size)) - } else { - Some((closed.font.clone(), closed.code_point, closed.size)) - } - } - Self::None => None, - } - } -} - /// The icon of a [`Handle`]. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Icon { @@ -593,7 +567,7 @@ pub fn draw<'a, T, Renderer>( selected: Option<&T>, handle: &Handle, style: &::Style, - state: &State, + state: impl FnOnce() -> &'a State, ) where Renderer: text::Renderer, Renderer::Theme: StyleSheet, @@ -619,9 +593,26 @@ pub fn draw<'a, T, Renderer>( style.background, ); - if let Some((font, code_point, size)) = - handle.content::(state.is_open) - { + let handle = match handle { + Handle::Arrow { size } => { + Some((Renderer::ICON_FONT, Renderer::ARROW_DOWN_ICON, *size)) + } + Handle::Static(Icon { + font, + code_point, + size, + }) => Some((font.clone(), *code_point, *size)), + Handle::Dynamic { open, closed } => { + if state().is_open { + Some((open.font.clone(), open.code_point, open.size)) + } else { + Some((closed.font.clone(), closed.code_point, closed.size)) + } + } + Handle::None => None, + }; + + if let Some((font, code_point, size)) = handle { let size = f32::from(size.unwrap_or_else(|| renderer.default_size())); renderer.fill_text(Text { -- cgit