use iced::advanced::layout::{self, Layout};
use iced::advanced::widget::{self, Widget};
use iced::advanced::{mouse, renderer};
use iced::{Element, Event, Length, Rectangle, Size};
pub(crate) const MEASURE_CAP: f32 = 2_000.0;
#[derive(Debug, Default)]
struct State {
measured: Option<f32>,
published_for: Option<u64>,
}
#[allow(missing_debug_implementations)]
pub struct Measure<'a, Message, Theme, Renderer> {
children: Vec<Element<'a, Message, Theme, Renderer>>,
epoch: u64,
on_measured: Box<dyn Fn(f32) -> Message + 'a>,
}
impl<'a, Message, Theme, Renderer> Measure<'a, Message, Theme, Renderer> {
pub fn new(
children: Vec<Element<'a, Message, Theme, Renderer>>,
epoch: u64,
on_measured: impl Fn(f32) -> Message + 'a,
) -> Self {
Self {
children,
epoch,
on_measured: Box::new(on_measured),
}
}
}
impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>
for Measure<'_, Message, Theme, Renderer>
where
Renderer: renderer::Renderer,
{
fn tag(&self) -> widget::tree::Tag {
widget::tree::Tag::of::<State>()
}
fn state(&self) -> widget::tree::State {
widget::tree::State::new(State::default())
}
fn children(&self) -> Vec<widget::Tree> {
self.children.iter().map(widget::Tree::new).collect()
}
fn diff(&self, tree: &mut widget::Tree) {
tree.diff_children(&self.children);
}
fn size(&self) -> Size<Length> {
Size::new(Length::Shrink, Length::Shrink)
}
fn layout(
&mut self,
tree: &mut widget::Tree,
renderer: &Renderer,
_limits: &layout::Limits,
) -> layout::Node {
let state = tree.state.downcast_mut::<State>();
if self.children.is_empty() {
state.measured = None;
} else {
let unbounded =
layout::Limits::new(Size::ZERO, Size::new(MEASURE_CAP, f32::INFINITY));
let mut max = 0.0f32;
for (element, tree) in self.children.iter_mut().zip(&mut tree.children) {
let node = element.as_widget_mut().layout(tree, renderer, &unbounded);
max = max.max(node.size().width);
}
state.measured = Some(max);
}
layout::Node::new(Size::ZERO)
}
fn update(
&mut self,
tree: &mut widget::Tree,
_event: &Event,
_layout: Layout<'_>,
_cursor: mouse::Cursor,
_renderer: &Renderer,
_clipboard: &mut dyn iced::advanced::Clipboard,
shell: &mut iced::advanced::Shell<'_, Message>,
_viewport: &Rectangle,
) {
let state = tree.state.downcast_mut::<State>();
if let Some(width) = state.measured {
if state.published_for != Some(self.epoch) {
state.published_for = Some(self.epoch);
shell.publish((self.on_measured)(width));
}
}
}
fn draw(
&self,
_tree: &widget::Tree,
_renderer: &mut Renderer,
_theme: &Theme,
_style: &renderer::Style,
_layout: Layout<'_>,
_cursor: mouse::Cursor,
_viewport: &Rectangle,
) {
}
}
impl<'a, Message, Theme, Renderer> From<Measure<'a, Message, Theme, Renderer>>
for Element<'a, Message, Theme, Renderer>
where
Message: 'a,
Theme: 'a,
Renderer: renderer::Renderer + 'a,
{
fn from(measure: Measure<'a, Message, Theme, Renderer>) -> Self {
Element::new(measure)
}
}