diff --git a/iced b/iced index 14ef12f4..d67f1a1c 160000 --- a/iced +++ b/iced @@ -1 +1 @@ -Subproject commit 14ef12f429078be78c45cd3348162b5f8459e993 +Subproject commit d67f1a1c79cf3dcb378520ef7e4e9ab653f75bea diff --git a/src/widget/dropdown/multi/menu.rs b/src/widget/dropdown/multi/menu.rs index cd510ddc..aac00107 100644 --- a/src/widget/dropdown/multi/menu.rs +++ b/src/widget/dropdown/multi/menu.rs @@ -190,7 +190,12 @@ impl<'a, Message: 'a> Overlay<'a, Message> { } impl<'a, Message> iced_core::Overlay for Overlay<'a, Message> { - fn layout(&self, renderer: &crate::Renderer, bounds: Size, position: Point) -> layout::Node { + fn layout( + &mut self, + renderer: &crate::Renderer, + bounds: Size, + position: Point, + ) -> layout::Node { let space_below = bounds.height - (position.y + self.target_height); let space_above = position.y; @@ -207,7 +212,9 @@ impl<'a, Message> iced_core::Overlay for Overlay<'a, M ) .width(self.width); - let mut node = self.container.layout(renderer, &limits); + let mut node = self + .container + .layout(&mut self.state.children[0], renderer, &limits); node.move_to(if space_below > space_above { position + Vector::new(0.0, self.target_height) @@ -296,13 +303,18 @@ where Length::Shrink } - fn layout(&self, renderer: &crate::Renderer, limits: &layout::Limits) -> layout::Node { + fn layout( + &self, + _tree: &mut Tree, + renderer: &crate::Renderer, + limits: &layout::Limits, + ) -> layout::Node { use std::f32; let limits = limits.width(Length::Fill).height(Length::Shrink); let text_size = self .text_size - .unwrap_or_else(|| text::Renderer::default_size(renderer)); + .unwrap_or_else(|| text::Renderer::default_size(renderer).0); let text_line_height = self.text_line_height.to_absolute(Pixels(text_size)); @@ -359,7 +371,7 @@ where if let Some(cursor_position) = cursor.position_in(bounds) { let text_size = self .text_size - .unwrap_or_else(|| text::Renderer::default_size(renderer)); + .unwrap_or_else(|| text::Renderer::default_size(renderer).0); let text_line_height = f32::from(self.text_line_height.to_absolute(Pixels(text_size))); @@ -406,7 +418,7 @@ where if let Some(cursor_position) = cursor.position_in(bounds) { let text_size = self .text_size - .unwrap_or_else(|| text::Renderer::default_size(renderer)); + .unwrap_or_else(|| text::Renderer::default_size(renderer).0); let text_line_height = f32::from(self.text_line_height.to_absolute(Pixels(text_size))); @@ -488,7 +500,7 @@ where let text_size = self .text_size - .unwrap_or_else(|| text::Renderer::default_size(renderer)); + .unwrap_or_else(|| text::Renderer::default_size(renderer).0); let offset = viewport.y - bounds.y; @@ -571,24 +583,26 @@ where (appearance.text_color, crate::font::FONT) }; + let bounds = Rectangle { + x: bounds.x + self.padding.left, + y: bounds.y + self.padding.top, + width: bounds.width, + height: bounds.height, + }; text::Renderer::fill_text( renderer, Text { content: option.as_ref(), - bounds: Rectangle { - x: bounds.x + self.padding.left, - y: bounds.center_y(), - width: bounds.width, - ..bounds - }, - size: text_size, + bounds: bounds.size(), + size: iced::Pixels(text_size), line_height: self.text_line_height, font, - color, horizontal_alignment: alignment::Horizontal::Left, vertical_alignment: alignment::Vertical::Center, shaping: text::Shaping::Advanced, }, + bounds.position(), + color, ); } @@ -618,23 +632,25 @@ where } OptionElement::Description(description) => { + let bounds = Rectangle { + x: bounds.center_x(), + y: bounds.center_y(), + ..bounds + }; text::Renderer::fill_text( renderer, Text { content: description.as_ref(), - bounds: Rectangle { - x: bounds.center_x(), - y: bounds.center_y(), - ..bounds - }, - size: text_size, + bounds: bounds.size(), + size: iced::Pixels(text_size), line_height: text::LineHeight::Absolute(Pixels(text_line_height + 4.0)), font: crate::font::FONT, - color: appearance.description_color, horizontal_alignment: alignment::Horizontal::Center, vertical_alignment: alignment::Vertical::Center, shaping: text::Shaping::Advanced, }, + bounds.position(), + appearance.description_color, ); } } diff --git a/src/widget/dropdown/multi/widget.rs b/src/widget/dropdown/multi/widget.rs index df5d618b..3f59fcc2 100644 --- a/src/widget/dropdown/multi/widget.rs +++ b/src/widget/dropdown/multi/widget.rs @@ -6,7 +6,7 @@ use super::menu::{self, Menu}; use crate::widget::icon; use derive_setters::Setters; use iced_core::event::{self, Event}; -use iced_core::text::{self, Text}; +use iced_core::text::{self, Paragraph, Text}; use iced_core::widget::tree::{self, Tree}; use iced_core::{alignment, keyboard, layout, mouse, overlay, renderer, svg, touch}; use iced_core::{Clipboard, Layout, Length, Padding, Pixels, Rectangle, Shell, Size, Widget}; @@ -78,7 +78,12 @@ impl<'a, S: AsRef, Message: 'a, Item: Clone + PartialEq + 'static> Length::Shrink } - fn layout(&self, renderer: &crate::Renderer, limits: &layout::Limits) -> layout::Node { + fn layout( + &self, + tree: &mut Tree, + renderer: &crate::Renderer, + limits: &layout::Limits, + ) -> layout::Node { layout( renderer, limits, @@ -88,11 +93,16 @@ impl<'a, S: AsRef, Message: 'a, Item: Clone + PartialEq + 'static> self.text_size.unwrap_or(14.0), self.text_line_height, self.font, - self.selections - .selected - .as_ref() - .and_then(|id| self.selections.get(id)) - .map(AsRef::as_ref), + self.selections.selected.as_ref().and_then(|id| { + self.selections.get(id).map(AsRef::as_ref).zip( + tree.state + .downcast_mut::>() + .selections + .iter_mut() + .find(|(i, _)| i == id) + .map(|(_, p)| p), + ) + }), ) } @@ -177,6 +187,7 @@ impl<'a, S: AsRef, Message: 'a, Item: Clone + PartialEq + 'static> self.padding, self.text_size.unwrap_or(14.0), self.font, + self.text_line_height, self.selections, &self.on_selected, ) @@ -199,6 +210,8 @@ pub struct State { keyboard_modifiers: keyboard::Modifiers, is_open: bool, hovered_option: Option, + selections: Vec<(Item, crate::Paragraph)>, + descriptions: Vec, } impl State { @@ -217,6 +230,8 @@ impl State { keyboard_modifiers: keyboard::Modifiers::default(), is_open: false, hovered_option: None, + selections: Vec::new(), + descriptions: Vec::new(), } } } @@ -238,7 +253,7 @@ pub fn layout( text_size: f32, text_line_height: text::LineHeight, font: Option, - selection: Option<&str>, + selection: Option<(&str, &mut crate::Paragraph)>, ) -> layout::Node { use std::f32; @@ -246,16 +261,18 @@ pub fn layout( let max_width = match width { Length::Shrink => { - let measure = |label: &str| -> f32 { - let width = text::Renderer::measure_width( - renderer, - label, - text_size, - font.unwrap_or_else(|| text::Renderer::default_font(renderer)), - text::Shaping::Advanced, - ); - - width.round() + let measure = move |(label, paragraph): (_, &mut crate::Paragraph)| -> f32 { + paragraph.update(Text { + content: label, + bounds: Size::new(f32::MAX, f32::MAX), + size: iced::Pixels(text_size), + line_height: text_line_height, + font: font.unwrap_or_else(|| text::Renderer::default_font(renderer)), + horizontal_alignment: alignment::Horizontal::Left, + vertical_alignment: alignment::Vertical::Top, + shaping: text::Shaping::Advanced, + }); + paragraph.min_width().round() }; selection.map(measure).unwrap_or_default() @@ -359,6 +376,7 @@ pub fn overlay<'a, S: AsRef, Message: 'a, Item: Clone + PartialEq + 'static padding: Padding, text_size: f32, font: Option, + text_line_height: text::LineHeight, selections: &'a super::Model, on_selected: &'a dyn Fn(Item) -> Message, ) -> Option> { @@ -378,38 +396,62 @@ pub fn overlay<'a, S: AsRef, Message: 'a, Item: Clone + PartialEq + 'static None, ) .width({ - let measure = |label: &str| -> f32 { - let width = text::Renderer::measure_width( - renderer, - label, - text_size, - crate::font::FONT, - text::Shaping::Advanced, - ); - - width.round() + let measure = |label: &str, paragraph: &mut crate::Paragraph| { + paragraph.update(Text { + content: label, + bounds: Size::new(f32::MAX, f32::MAX), + size: iced::Pixels(text_size), + line_height: text_line_height, + font: font.unwrap_or_else(|| text::Renderer::default_font(renderer)), + horizontal_alignment: alignment::Horizontal::Left, + vertical_alignment: alignment::Vertical::Top, + shaping: text::Shaping::Advanced, + }); + paragraph.min_width().round() }; - let measure_description = |label: &str| -> f32 { - let width = text::Renderer::measure_width( - renderer, - label, - text_size + 4.0, - crate::font::FONT, - text::Shaping::Advanced, - ); - - width.round() + let measure_description = |label: &str, paragraph: &mut crate::Paragraph| { + paragraph.update(Text { + content: label, + bounds: Size::new(f32::MAX, f32::MAX), + size: iced::Pixels(text_size + 4.0), + line_height: text_line_height, + font: font.unwrap_or_else(|| text::Renderer::default_font(renderer)), + horizontal_alignment: alignment::Horizontal::Left, + vertical_alignment: alignment::Vertical::Top, + shaping: text::Shaping::Advanced, + }); + paragraph.min_width().round() }; + let mut desc_count = 0; selections .elements() .map(|element| match element { super::menu::OptionElement::Description(desc) => { - measure_description(desc.as_ref()) + let paragraph = if state.descriptions.len() > desc_count { + &mut state.descriptions[desc_count] + } else { + state.descriptions.push(crate::Paragraph::new()); + state.descriptions.last_mut().unwrap() + }; + desc_count += 1; + measure_description(desc.as_ref(), paragraph) } - super::menu::OptionElement::Option((option, _item)) => measure(option.as_ref()), + super::menu::OptionElement::Option((option, item)) => { + let paragraph = if let Some(index) = + state.selections.iter().position(|(i, _)| i == item) + { + &mut state.selections[index].1 + } else { + state + .selections + .push((item.clone(), crate::Paragraph::new())); + &mut state.selections.last_mut().unwrap().1 + }; + measure(option.as_ref(), paragraph) + } super::menu::OptionElement::Separator => 1.0, }) @@ -482,26 +524,29 @@ pub fn draw<'a, S, Item: Clone + PartialEq + 'static>( } if let Some(content) = selected.map(AsRef::as_ref) { - let text_size = text_size.unwrap_or_else(|| text::Renderer::default_size(renderer)); + let text_size = text_size.unwrap_or_else(|| text::Renderer::default_size(renderer).0); + + let bounds = Rectangle { + x: bounds.x + padding.left, + y: bounds.center_y(), + width: bounds.width - padding.horizontal(), + height: f32::from(text_line_height.to_absolute(Pixels(text_size))), + }; text::Renderer::fill_text( renderer, Text { content, - size: text_size, + size: iced::Pixels(text_size), line_height: text_line_height, font, - color: style.text_color, - bounds: Rectangle { - x: bounds.x + padding.left, - y: bounds.center_y(), - width: bounds.width - padding.horizontal(), - height: f32::from(text_line_height.to_absolute(Pixels(text_size))), - }, + bounds: bounds.size(), horizontal_alignment: alignment::Horizontal::Left, vertical_alignment: alignment::Vertical::Center, shaping: text::Shaping::Advanced, }, + bounds.position(), + style.text_color, ); } }