From 3a0d34c0240f4421737a6a08761f99d6f8140d02 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 4 Mar 2023 05:37:11 +0100 Subject: Create `iced_widget` subcrate and re-organize the whole codebase --- widget/src/pick_list.rs | 658 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 658 insertions(+) create mode 100644 widget/src/pick_list.rs (limited to 'widget/src/pick_list.rs') diff --git a/widget/src/pick_list.rs b/widget/src/pick_list.rs new file mode 100644 index 00000000..cd23cdd2 --- /dev/null +++ b/widget/src/pick_list.rs @@ -0,0 +1,658 @@ +//! Display a dropdown list of selectable values. +use crate::container; +use crate::core::alignment; +use crate::core::event::{self, Event}; +use crate::core::keyboard; +use crate::core::layout; +use crate::core::mouse; +use crate::core::overlay; +use crate::core::renderer; +use crate::core::text::{self, Text}; +use crate::core::touch; +use crate::core::widget::tree::{self, Tree}; +use crate::core::{ + Clipboard, Element, Layout, Length, Padding, Pixels, Point, Rectangle, + Shell, Size, Widget, +}; +use crate::overlay::menu::{self, Menu}; +use crate::scrollable; + +use std::borrow::Cow; + +pub use crate::style::pick_list::{Appearance, StyleSheet}; + +/// A widget for selecting a single value from a list of options. +#[allow(missing_debug_implementations)] +pub struct PickList<'a, T, Message, Renderer = crate::Renderer> +where + [T]: ToOwned>, + Renderer: text::Renderer, + Renderer::Theme: StyleSheet, +{ + on_selected: Box Message + 'a>, + options: Cow<'a, [T]>, + placeholder: Option, + selected: Option, + width: Length, + padding: Padding, + text_size: Option, + font: Option, + handle: Handle, + style: ::Style, +} + +impl<'a, T: 'a, Message, Renderer> PickList<'a, T, Message, Renderer> +where + T: ToString + Eq, + [T]: ToOwned>, + Renderer: text::Renderer, + Renderer::Theme: StyleSheet + + scrollable::StyleSheet + + menu::StyleSheet + + container::StyleSheet, + ::Style: + From<::Style>, +{ + /// The default padding of a [`PickList`]. + pub const DEFAULT_PADDING: Padding = Padding::new(5.0); + + /// 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( + options: impl Into>, + selected: Option, + on_selected: impl Fn(T) -> Message + 'a, + ) -> Self { + Self { + on_selected: Box::new(on_selected), + options: options.into(), + placeholder: None, + selected, + width: Length::Shrink, + padding: Self::DEFAULT_PADDING, + text_size: None, + font: None, + handle: Default::default(), + style: Default::default(), + } + } + + /// Sets the placeholder of the [`PickList`]. + pub fn placeholder(mut self, placeholder: impl Into) -> Self { + self.placeholder = Some(placeholder.into()); + self + } + + /// Sets the width of the [`PickList`]. + pub fn width(mut self, width: impl Into) -> Self { + self.width = width.into(); + self + } + + /// Sets the [`Padding`] of the [`PickList`]. + pub fn padding>(mut self, padding: P) -> Self { + self.padding = padding.into(); + self + } + + /// Sets the text size of the [`PickList`]. + pub fn text_size(mut self, size: impl Into) -> Self { + self.text_size = Some(size.into().0); + self + } + + /// Sets the font of the [`PickList`]. + pub fn font(mut self, font: impl Into) -> Self { + self.font = Some(font.into()); + self + } + + /// Sets the [`Handle`] of the [`PickList`]. + pub fn handle(mut self, handle: Handle) -> Self { + self.handle = handle; + self + } + + /// Sets the style of the [`PickList`]. + pub fn style( + mut self, + style: impl Into<::Style>, + ) -> Self { + self.style = style.into(); + self + } +} + +impl<'a, T: 'a, Message, Renderer> Widget + for PickList<'a, T, Message, Renderer> +where + T: Clone + ToString + Eq + 'static, + [T]: ToOwned>, + Message: 'a, + Renderer: text::Renderer + 'a, + Renderer::Theme: StyleSheet + + scrollable::StyleSheet + + menu::StyleSheet + + container::StyleSheet, + ::Style: + From<::Style>, +{ + fn tag(&self) -> tree::Tag { + tree::Tag::of::>() + } + + fn state(&self) -> tree::State { + tree::State::new(State::::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::>(), + ) + } + + 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, + ) { + let font = self.font.unwrap_or_else(|| renderer.default_font()); + draw( + renderer, + theme, + layout, + cursor_position, + self.padding, + self.text_size, + font, + self.placeholder.as_deref(), + self.selected.as_ref(), + &self.handle, + &self.style, + || tree.state.downcast_ref::>(), + ) + } + + fn overlay<'b>( + &'b mut self, + tree: &'b mut Tree, + layout: Layout<'_>, + renderer: &Renderer, + ) -> Option> { + let state = tree.state.downcast_mut::>(); + + overlay( + layout, + state, + self.padding, + self.text_size, + self.font.unwrap_or_else(|| renderer.default_font()), + &self.options, + self.style.clone(), + ) + } +} + +impl<'a, T: 'a, Message, Renderer> From> + for Element<'a, Message, Renderer> +where + T: Clone + ToString + Eq + 'static, + [T]: ToOwned>, + Message: 'a, + Renderer: text::Renderer + 'a, + Renderer::Theme: StyleSheet + + scrollable::StyleSheet + + menu::StyleSheet + + container::StyleSheet, + ::Style: + From<::Style>, +{ + 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 { + menu: menu::State, + keyboard_modifiers: keyboard::Modifiers, + is_open: bool, + hovered_option: Option, + last_selection: Option, +} + +impl State { + /// 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 Default for State { + fn default() -> Self { + Self::new() + } +} + +/// The handle to the right side of the [`PickList`]. +#[derive(Debug, Clone, PartialEq)] +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 } + } +} + +/// The icon of a [`Handle`]. +#[derive(Debug, Clone, PartialEq)] +pub struct Icon { + /// Font that will be used to display the `code_point`, + pub font: Font, + /// The unicode code point that will be used as the icon. + pub code_point: char, + /// Font size of the content. + pub size: Option, +} + +/// Computes the layout of a [`PickList`]. +pub fn layout( + renderer: &Renderer, + limits: &layout::Limits, + width: Length, + padding: Padding, + text_size: Option, + font: Option, + placeholder: Option<&str>, + options: &[T], +) -> layout::Node +where + Renderer: text::Renderer, + T: ToString, +{ + use std::f32; + + let limits = limits.width(width).height(Length::Shrink).pad(padding); + let text_size = text_size.unwrap_or_else(|| renderer.default_size()); + + let max_width = match width { + Length::Shrink => { + let measure = |label: &str| -> f32 { + let (width, _) = renderer.measure( + label, + text_size, + font.unwrap_or_else(|| renderer.default_font()), + Size::new(f32::INFINITY, f32::INFINITY), + ); + + width.round() + }; + + let labels = options.iter().map(ToString::to_string); + + let labels_width = labels + .map(|label| measure(&label)) + .fold(100.0, |candidate, current| current.max(candidate)); + + let placeholder_width = placeholder.map(measure).unwrap_or(100.0); + + labels_width.max(placeholder_width) + } + _ => 0.0, + }; + + let size = { + let intrinsic = + Size::new(max_width + text_size + padding.left, text_size * 1.2); + + limits.resolve(intrinsic).pad(padding) + }; + + layout::Node::new(size) +} + +/// Processes an [`Event`] and updates the [`State`] of a [`PickList`] +/// accordingly. +pub fn update<'a, T, Message>( + event: Event, + layout: Layout<'_>, + cursor_position: Point, + shell: &mut Shell<'_, Message>, + on_selected: &dyn Fn(T) -> Message, + selected: Option<&T>, + options: &[T], + state: impl FnOnce() -> &'a mut State, +) -> event::Status +where + T: PartialEq + Clone + 'a, +{ + match event { + Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) + | Event::Touch(touch::Event::FingerPressed { .. }) => { + let state = state(); + + let event_status = if state.is_open { + // Event wasn't processed by overlay, so cursor was clicked either outside it's + // bounds or on the drop-down, either way we close the overlay. + state.is_open = false; + + event::Status::Captured + } else if layout.bounds().contains(cursor_position) { + state.is_open = true; + state.hovered_option = + options.iter().position(|option| Some(option) == selected); + + event::Status::Captured + } else { + event::Status::Ignored + }; + + if let Some(last_selection) = state.last_selection.take() { + shell.publish((on_selected)(last_selection)); + + state.is_open = false; + + event::Status::Captured + } else { + event_status + } + } + Event::Mouse(mouse::Event::WheelScrolled { + delta: mouse::ScrollDelta::Lines { y, .. }, + }) => { + let state = state(); + + if state.keyboard_modifiers.command() + && layout.bounds().contains(cursor_position) + && !state.is_open + { + fn find_next<'a, T: PartialEq>( + selected: &'a T, + mut options: impl Iterator, + ) -> Option<&'a T> { + let _ = options.find(|&option| option == selected); + + options.next() + } + + let next_option = if y < 0.0 { + if let Some(selected) = selected { + find_next(selected, options.iter()) + } else { + options.first() + } + } else if y > 0.0 { + if let Some(selected) = selected { + find_next(selected, options.iter().rev()) + } else { + options.last() + } + } else { + None + }; + + if let Some(next_option) = next_option { + shell.publish((on_selected)(next_option.clone())); + } + + event::Status::Captured + } else { + event::Status::Ignored + } + } + Event::Keyboard(keyboard::Event::ModifiersChanged(modifiers)) => { + let state = state(); + + state.keyboard_modifiers = modifiers; + + event::Status::Ignored + } + _ => event::Status::Ignored, + } +} + +/// Returns the current [`mouse::Interaction`] of a [`PickList`]. +pub fn mouse_interaction( + layout: Layout<'_>, + cursor_position: Point, +) -> mouse::Interaction { + let bounds = layout.bounds(); + let is_mouse_over = bounds.contains(cursor_position); + + if is_mouse_over { + mouse::Interaction::Pointer + } else { + mouse::Interaction::default() + } +} + +/// Returns the current overlay of a [`PickList`]. +pub fn overlay<'a, T, Message, Renderer>( + layout: Layout<'_>, + state: &'a mut State, + padding: Padding, + text_size: Option, + font: Renderer::Font, + options: &'a [T], + style: ::Style, +) -> Option> +where + T: Clone + ToString, + Message: 'a, + Renderer: text::Renderer + 'a, + Renderer::Theme: StyleSheet + + scrollable::StyleSheet + + menu::StyleSheet + + container::StyleSheet, + ::Style: + From<::Style>, +{ + if state.is_open { + let bounds = layout.bounds(); + + let mut menu = Menu::new( + &mut state.menu, + options, + &mut state.hovered_option, + &mut state.last_selection, + ) + .width(bounds.width) + .padding(padding) + .font(font) + .style(style); + + if let Some(text_size) = text_size { + menu = menu.text_size(text_size); + } + + Some(menu.overlay(layout.position(), bounds.height)) + } else { + None + } +} + +/// Draws a [`PickList`]. +pub fn draw<'a, T, Renderer>( + renderer: &mut Renderer, + theme: &Renderer::Theme, + layout: Layout<'_>, + cursor_position: Point, + padding: Padding, + text_size: Option, + font: Renderer::Font, + placeholder: Option<&str>, + selected: Option<&T>, + handle: &Handle, + style: &::Style, + state: impl FnOnce() -> &'a State, +) where + Renderer: text::Renderer, + Renderer::Theme: StyleSheet, + T: ToString + 'a, +{ + let bounds = layout.bounds(); + let is_mouse_over = bounds.contains(cursor_position); + let is_selected = selected.is_some(); + + let style = if is_mouse_over { + theme.hovered(style) + } else { + theme.active(style) + }; + + renderer.fill_quad( + renderer::Quad { + bounds, + border_color: style.border_color, + border_width: style.border_width, + border_radius: style.border_radius.into(), + }, + style.background, + ); + + 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, *code_point, *size)), + Handle::Dynamic { open, closed } => { + if state().is_open { + Some((open.font, open.code_point, open.size)) + } else { + Some((closed.font, closed.code_point, closed.size)) + } + } + Handle::None => None, + }; + + if let Some((font, code_point, size)) = handle { + let size = size.unwrap_or_else(|| renderer.default_size()); + + renderer.fill_text(Text { + content: &code_point.to_string(), + size, + font, + color: style.handle_color, + bounds: Rectangle { + x: bounds.x + bounds.width - padding.horizontal(), + y: bounds.center_y(), + height: size * 1.2, + ..bounds + }, + horizontal_alignment: alignment::Horizontal::Right, + vertical_alignment: alignment::Vertical::Center, + }); + } + + let label = selected.map(ToString::to_string); + + if let Some(label) = label.as_deref().or(placeholder) { + let text_size = text_size.unwrap_or_else(|| renderer.default_size()); + + renderer.fill_text(Text { + content: label, + size: text_size, + font, + color: if is_selected { + style.text_color + } else { + style.placeholder_color + }, + bounds: Rectangle { + x: bounds.x + padding.left, + y: bounds.center_y(), + width: bounds.width - padding.horizontal(), + height: text_size * 1.2, + }, + horizontal_alignment: alignment::Horizontal::Left, + vertical_alignment: alignment::Vertical::Center, + }); + } +} -- cgit From 33b5a900197e2798a393d6d9a0834039666eddbb Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 19 Apr 2023 01:19:56 +0200 Subject: Make basic text shaping the default shaping strategy --- widget/src/pick_list.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'widget/src/pick_list.rs') diff --git a/widget/src/pick_list.rs b/widget/src/pick_list.rs index cd23cdd2..d44f4cae 100644 --- a/widget/src/pick_list.rs +++ b/widget/src/pick_list.rs @@ -366,6 +366,7 @@ where text_size, font.unwrap_or_else(|| renderer.default_font()), Size::new(f32::INFINITY, f32::INFINITY), + false, ); width.round() @@ -628,6 +629,7 @@ pub fn draw<'a, T, Renderer>( }, horizontal_alignment: alignment::Horizontal::Right, vertical_alignment: alignment::Vertical::Center, + advanced_shape: false, }); } @@ -653,6 +655,7 @@ pub fn draw<'a, T, Renderer>( }, horizontal_alignment: alignment::Horizontal::Left, vertical_alignment: alignment::Vertical::Center, + advanced_shape: false, }); } } -- cgit From 4bd290afe7d81d9aaf7467b3ce91491f6600261a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 19 Apr 2023 02:00:45 +0200 Subject: Introduce `text::Shaping` enum and replace magic boolean --- widget/src/pick_list.rs | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) (limited to 'widget/src/pick_list.rs') diff --git a/widget/src/pick_list.rs b/widget/src/pick_list.rs index d44f4cae..c0cb2946 100644 --- a/widget/src/pick_list.rs +++ b/widget/src/pick_list.rs @@ -36,6 +36,7 @@ where width: Length, padding: Padding, text_size: Option, + text_shaping: text::Shaping, font: Option, handle: Handle, style: ::Style, @@ -71,6 +72,7 @@ where width: Length::Shrink, padding: Self::DEFAULT_PADDING, text_size: None, + text_shaping: text::Shaping::Basic, font: None, handle: Default::default(), style: Default::default(), @@ -101,6 +103,12 @@ where self } + /// Sets the [`text::Shaping`] strategy of the [`PickList`]. + pub fn text_shaping(mut self, shaping: text::Shaping) -> Self { + self.text_shaping = shaping; + self + } + /// Sets the font of the [`PickList`]. pub fn font(mut self, font: impl Into) -> Self { self.font = Some(font.into()); @@ -164,6 +172,7 @@ where self.width, self.padding, self.text_size, + self.text_shaping, self.font, self.placeholder.as_deref(), &self.options, @@ -221,6 +230,7 @@ where cursor_position, self.padding, self.text_size, + self.text_shaping, font, self.placeholder.as_deref(), self.selected.as_ref(), @@ -243,6 +253,7 @@ where state, self.padding, self.text_size, + self.text_shaping, self.font.unwrap_or_else(|| renderer.default_font()), &self.options, self.style.clone(), @@ -336,6 +347,8 @@ pub struct Icon { pub code_point: char, /// Font size of the content. pub size: Option, + /// The shaping strategy of the icon. + pub shaping: text::Shaping, } /// Computes the layout of a [`PickList`]. @@ -345,6 +358,7 @@ pub fn layout( width: Length, padding: Padding, text_size: Option, + text_shaping: text::Shaping, font: Option, placeholder: Option<&str>, options: &[T], @@ -366,7 +380,7 @@ where text_size, font.unwrap_or_else(|| renderer.default_font()), Size::new(f32::INFINITY, f32::INFINITY), - false, + text_shaping, ); width.round() @@ -516,6 +530,7 @@ pub fn overlay<'a, T, Message, Renderer>( state: &'a mut State, padding: Padding, text_size: Option, + text_shaping: text::Shaping, font: Renderer::Font, options: &'a [T], style: ::Style, @@ -543,6 +558,7 @@ where .width(bounds.width) .padding(padding) .font(font) + .text_shaping(text_shaping) .style(style); if let Some(text_size) = text_size { @@ -563,6 +579,7 @@ pub fn draw<'a, T, Renderer>( cursor_position: Point, padding: Padding, text_size: Option, + text_shaping: text::Shaping, font: Renderer::Font, placeholder: Option<&str>, selected: Option<&T>, @@ -595,25 +612,34 @@ pub fn draw<'a, T, Renderer>( ); let handle = match handle { - Handle::Arrow { size } => { - Some((Renderer::ICON_FONT, Renderer::ARROW_DOWN_ICON, *size)) - } + Handle::Arrow { size } => Some(( + Renderer::ICON_FONT, + Renderer::ARROW_DOWN_ICON, + *size, + text::Shaping::Basic, + )), Handle::Static(Icon { font, code_point, size, - }) => Some((*font, *code_point, *size)), + shaping, + }) => Some((*font, *code_point, *size, *shaping)), Handle::Dynamic { open, closed } => { if state().is_open { - Some((open.font, open.code_point, open.size)) + Some((open.font, open.code_point, open.size, open.shaping)) } else { - Some((closed.font, closed.code_point, closed.size)) + Some(( + closed.font, + closed.code_point, + closed.size, + closed.shaping, + )) } } Handle::None => None, }; - if let Some((font, code_point, size)) = handle { + if let Some((font, code_point, size, shaping)) = handle { let size = size.unwrap_or_else(|| renderer.default_size()); renderer.fill_text(Text { @@ -629,7 +655,7 @@ pub fn draw<'a, T, Renderer>( }, horizontal_alignment: alignment::Horizontal::Right, vertical_alignment: alignment::Vertical::Center, - advanced_shape: false, + shaping, }); } @@ -655,7 +681,7 @@ pub fn draw<'a, T, Renderer>( }, horizontal_alignment: alignment::Horizontal::Left, vertical_alignment: alignment::Vertical::Center, - advanced_shape: false, + shaping: text_shaping, }); } } -- cgit From 9499a8f9e6f9971dedfae563cb133232aa3cebc2 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 4 May 2023 13:00:16 +0200 Subject: Support configurable `LineHeight` in text widgets --- widget/src/pick_list.rs | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'widget/src/pick_list.rs') diff --git a/widget/src/pick_list.rs b/widget/src/pick_list.rs index c0cb2946..bc2c9066 100644 --- a/widget/src/pick_list.rs +++ b/widget/src/pick_list.rs @@ -36,6 +36,7 @@ where width: Length, padding: Padding, text_size: Option, + text_line_height: text::LineHeight, text_shaping: text::Shaping, font: Option, handle: Handle, @@ -72,6 +73,7 @@ where width: Length::Shrink, padding: Self::DEFAULT_PADDING, text_size: None, + text_line_height: text::LineHeight::default(), text_shaping: text::Shaping::Basic, font: None, handle: Default::default(), @@ -103,6 +105,15 @@ where self } + /// Sets the text [`LineHeight`] of the [`PickList`]. + pub fn text_line_height( + mut self, + line_height: impl Into, + ) -> Self { + self.text_line_height = line_height.into(); + self + } + /// Sets the [`text::Shaping`] strategy of the [`PickList`]. pub fn text_shaping(mut self, shaping: text::Shaping) -> Self { self.text_shaping = shaping; @@ -172,6 +183,7 @@ where self.width, self.padding, self.text_size, + self.text_line_height, self.text_shaping, self.font, self.placeholder.as_deref(), @@ -230,6 +242,7 @@ where cursor_position, self.padding, self.text_size, + self.text_line_height, self.text_shaping, font, self.placeholder.as_deref(), @@ -358,6 +371,7 @@ pub fn layout( width: Length, padding: Padding, text_size: Option, + text_line_height: text::LineHeight, text_shaping: text::Shaping, font: Option, placeholder: Option<&str>, @@ -375,11 +389,10 @@ where let max_width = match width { Length::Shrink => { let measure = |label: &str| -> f32 { - let (width, _) = renderer.measure( + let width = renderer.measure_width( label, text_size, font.unwrap_or_else(|| renderer.default_font()), - Size::new(f32::INFINITY, f32::INFINITY), text_shaping, ); @@ -400,8 +413,10 @@ where }; let size = { - let intrinsic = - Size::new(max_width + text_size + padding.left, text_size * 1.2); + let intrinsic = Size::new( + max_width + text_size + padding.left, + f32::from(text_line_height.to_absolute(Pixels(text_size))), + ); limits.resolve(intrinsic).pad(padding) }; @@ -579,6 +594,7 @@ pub fn draw<'a, T, Renderer>( cursor_position: Point, padding: Padding, text_size: Option, + text_line_height: text::LineHeight, text_shaping: text::Shaping, font: Renderer::Font, placeholder: Option<&str>, @@ -645,6 +661,7 @@ pub fn draw<'a, T, Renderer>( renderer.fill_text(Text { content: &code_point.to_string(), size, + line_height: text::LineHeight::default(), font, color: style.handle_color, bounds: Rectangle { @@ -667,6 +684,7 @@ pub fn draw<'a, T, Renderer>( renderer.fill_text(Text { content: label, size: text_size, + line_height: text_line_height, font, color: if is_selected { style.text_color -- cgit From f0c87375d53d620b5939d87e1bc54288f9c184ac Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 10 May 2023 00:02:34 +0200 Subject: Add `line_height` to `pick_list::Icon` --- widget/src/pick_list.rs | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'widget/src/pick_list.rs') diff --git a/widget/src/pick_list.rs b/widget/src/pick_list.rs index bc2c9066..50b47417 100644 --- a/widget/src/pick_list.rs +++ b/widget/src/pick_list.rs @@ -360,6 +360,8 @@ pub struct Icon { pub code_point: char, /// Font size of the content. pub size: Option, + /// Line height of the content. + pub line_height: text::LineHeight, /// The shaping strategy of the icon. pub shaping: text::Shaping, } @@ -632,22 +634,31 @@ pub fn draw<'a, T, Renderer>( Renderer::ICON_FONT, Renderer::ARROW_DOWN_ICON, *size, + text::LineHeight::default(), text::Shaping::Basic, )), Handle::Static(Icon { font, code_point, size, + line_height, shaping, - }) => Some((*font, *code_point, *size, *shaping)), + }) => Some((*font, *code_point, *size, *line_height, *shaping)), Handle::Dynamic { open, closed } => { if state().is_open { - Some((open.font, open.code_point, open.size, open.shaping)) + Some(( + open.font, + open.code_point, + open.size, + open.line_height, + open.shaping, + )) } else { Some(( closed.font, closed.code_point, closed.size, + closed.line_height, closed.shaping, )) } @@ -655,19 +666,19 @@ pub fn draw<'a, T, Renderer>( Handle::None => None, }; - if let Some((font, code_point, size, shaping)) = handle { + if let Some((font, code_point, size, line_height, shaping)) = handle { let size = size.unwrap_or_else(|| renderer.default_size()); renderer.fill_text(Text { content: &code_point.to_string(), size, - line_height: text::LineHeight::default(), + line_height, font, color: style.handle_color, bounds: Rectangle { x: bounds.x + bounds.width - padding.horizontal(), y: bounds.center_y(), - height: size * 1.2, + height: f32::from(line_height.to_absolute(Pixels(size))), ..bounds }, horizontal_alignment: alignment::Horizontal::Right, -- cgit From 1400b5187d6fa30f5fa4f83684939f6dc87cb55f Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 10 May 2023 00:37:08 +0200 Subject: Fix bounds of `PickList` text label --- widget/src/pick_list.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'widget/src/pick_list.rs') diff --git a/widget/src/pick_list.rs b/widget/src/pick_list.rs index 50b47417..8c445dda 100644 --- a/widget/src/pick_list.rs +++ b/widget/src/pick_list.rs @@ -706,7 +706,9 @@ pub fn draw<'a, T, Renderer>( x: bounds.x + padding.left, y: bounds.center_y(), width: bounds.width - padding.horizontal(), - height: text_size * 1.2, + height: f32::from( + text_line_height.to_absolute(Pixels(text_size)), + ), }, horizontal_alignment: alignment::Horizontal::Left, vertical_alignment: alignment::Vertical::Center, -- cgit