wip rebase updates

This commit is contained in:
Ashley Wulber 2026-02-10 15:37:41 -05:00
parent 86dcf8af6c
commit e10459fb37
68 changed files with 1776 additions and 1544 deletions

View file

@ -57,11 +57,11 @@ pub fn resolve<'a, E, Message, Renderer>(
padding: Padding,
spacing: f32,
align_items: Alignment,
items: &[E],
items: &mut [E],
tree: &mut [&mut Tree],
) -> Node
where
E: std::borrow::Borrow<Element<'a, Message, crate::Theme, Renderer>>,
E: std::borrow::BorrowMut<Element<'a, Message, crate::Theme, Renderer>>,
Renderer: renderer::Renderer,
{
let limits = limits.shrink(padding);
@ -69,7 +69,7 @@ where
let max_cross = axis.cross(limits.max());
let mut fill_sum = 0;
let mut cross = axis.cross(limits.min()).max(axis.cross(Size::INFINITY));
let mut cross = axis.cross(limits.min()).max(axis.cross(Size::INFINITE));
let mut available = axis.main(limits.max()) - total_spacing;
let mut nodes: Vec<Node> = Vec::with_capacity(items.len());
@ -78,8 +78,8 @@ where
if align_items == Alignment::Center {
let mut fill_cross = axis.cross(limits.min());
for (child, tree) in items.iter().zip(tree.iter_mut()) {
let child = child.borrow();
for (child, tree) in items.iter_mut().zip(tree.iter_mut()) {
let child = child.borrow_mut();
let c_size = child.as_widget().size();
let cross_fill_factor = match axis {
Axis::Horizontal => c_size.height,
@ -92,7 +92,7 @@ where
let child_limits = Limits::new(Size::ZERO, Size::new(max_width, max_height));
let layout = child.as_widget().layout(tree, renderer, &child_limits);
let layout = child.as_widget_mut().layout(tree, renderer, &child_limits);
let size = layout.size();
fill_cross = fill_cross.max(axis.cross(size));
@ -102,8 +102,8 @@ where
cross = fill_cross;
}
for (i, (child, tree)) in items.iter().zip(tree.iter_mut()).enumerate() {
let child = child.borrow();
for (i, (child, tree)) in items.iter_mut().zip(tree.iter_mut()).enumerate() {
let child = child.borrow_mut();
let c_size = child.as_widget().size();
let fill_factor = match axis {
Axis::Horizontal => c_size.width,
@ -129,7 +129,7 @@ where
Size::new(max_width, max_height),
);
let layout = child.as_widget().layout(tree, renderer, &child_limits);
let layout = child.as_widget_mut().layout(tree, renderer, &child_limits);
let size = layout.size();
available -= axis.main(size);
@ -146,8 +146,8 @@ where
let remaining = available.max(0.0);
for (i, (child, tree)) in items.iter().zip(tree.iter_mut()).enumerate() {
let child = child.borrow();
for (i, (child, tree)) in items.iter_mut().zip(tree.iter_mut()).enumerate() {
let child = child.borrow_mut();
let c_size = child.as_widget().size();
let fill_factor = match axis {
Axis::Horizontal => c_size.width,
@ -180,7 +180,7 @@ where
Size::new(max_width, max_height),
);
let layout = child.as_widget().layout(tree, renderer, &child_limits);
let layout = child.as_widget_mut().layout(tree, renderer, &child_limits);
if align_items != Alignment::Center {
cross = cross.max(axis.cross(layout.size()));
@ -231,7 +231,7 @@ pub fn resolve_wrapper<'a, Message>(
padding: Padding,
spacing: f32,
align_items: Alignment,
items: &[&RcElementWrapper<Message>],
items: &mut [&mut RcElementWrapper<Message>],
tree: &mut [&mut Tree],
) -> Node {
let limits = limits.shrink(padding);
@ -239,7 +239,7 @@ pub fn resolve_wrapper<'a, Message>(
let max_cross = axis.cross(limits.max());
let mut fill_sum = 0;
let mut cross = axis.cross(limits.min()).max(axis.cross(Size::INFINITY));
let mut cross = axis.cross(limits.min()).max(axis.cross(Size::INFINITE));
let mut available = axis.main(limits.max()) - total_spacing;
let mut nodes: Vec<Node> = Vec::with_capacity(items.len());
@ -248,7 +248,7 @@ pub fn resolve_wrapper<'a, Message>(
if align_items == Alignment::Center {
let mut fill_cross = axis.cross(limits.min());
for (child, tree) in items.iter().zip(tree.iter_mut()) {
for (child, tree) in items.into_iter().zip(tree.iter_mut()) {
let c_size = child.size();
let cross_fill_factor = match axis {
Axis::Horizontal => c_size.height,
@ -271,7 +271,7 @@ pub fn resolve_wrapper<'a, Message>(
cross = fill_cross;
}
for (i, (child, tree)) in items.iter().zip(tree.iter_mut()).enumerate() {
for (i, (child, tree)) in items.into_iter().zip(tree.iter_mut()).enumerate() {
let c_size = child.size();
let fill_factor = match axis {
Axis::Horizontal => c_size.width,
@ -314,7 +314,7 @@ pub fn resolve_wrapper<'a, Message>(
let remaining = available.max(0.0);
for (i, (child, tree)) in items.iter().zip(tree.iter_mut()).enumerate() {
for (i, (child, tree)) in items.into_iter().zip(tree.iter_mut()).enumerate() {
let c_size = child.size();
let fill_factor = match axis {
Axis::Horizontal => c_size.width,

View file

@ -26,7 +26,7 @@ use crate::{
},
};
use iced::{Point, Shadow, Vector, window};
use iced::{Point, Shadow, Vector, event::Status, window};
use iced_core::Border;
use iced_widget::core::{
Alignment, Clipboard, Element, Layout, Length, Padding, Rectangle, Shell, Widget, event,
@ -533,14 +533,14 @@ where
menu_roots_children(&self.menu_roots)
}
fn layout(&self, tree: &mut Tree, renderer: &Renderer, limits: &Limits) -> Node {
fn layout(&mut self, tree: &mut Tree, renderer: &Renderer, limits: &Limits) -> Node {
use super::flex;
let limits = limits.width(self.width).height(self.height);
let children = self
let mut children = self
.menu_roots
.iter()
.map(|root| &root.item)
.iter_mut()
.map(|root| &mut root.item)
.collect::<Vec<_>>();
// the first children of the tree are the menu roots items
let mut tree_children = tree
@ -555,28 +555,28 @@ where
self.padding,
self.spacing,
Alignment::Center,
&children,
&mut children,
&mut tree_children,
)
}
#[allow(clippy::too_many_lines)]
fn on_event(
fn update(
&mut self,
tree: &mut Tree,
event: event::Event,
event: &event::Event,
layout: Layout<'_>,
view_cursor: Cursor,
renderer: &Renderer,
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
viewport: &Rectangle,
) -> event::Status {
) {
use event::Event::{Mouse, Touch};
use mouse::{Button::Left, Event::ButtonReleased};
use touch::Event::{FingerLifted, FingerLost};
let root_status = process_root_events(
process_root_events(
&mut self.menu_roots,
view_cursor,
tree,
@ -638,7 +638,7 @@ where
});
if !create_popup {
return event::Status::Ignored;
return;
}
#[cfg(all(
feature = "multi-window",
@ -665,8 +665,6 @@ where
}
_ => (),
}
root_status
}
fn draw(
@ -704,6 +702,7 @@ where
..Default::default()
},
shadow: Shadow::default(),
snap: true,
};
renderer.fill_quad(path_quad, styling.path);
@ -731,8 +730,9 @@ where
fn overlay<'b>(
&'b mut self,
tree: &'b mut Tree,
layout: Layout<'_>,
layout: Layout<'b>,
_renderer: &Renderer,
viewport: &Rectangle,
translation: Vector,
) -> Option<overlay::Element<'b, Message, crate::Theme, Renderer>> {
#[cfg(all(
@ -799,18 +799,16 @@ fn process_root_events<Message>(
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
viewport: &Rectangle,
) -> event::Status
where
{
) {
menu_roots
.iter_mut()
.zip(&mut tree.children)
.zip(layout.children())
.map(|((root, t), lo)| {
// assert!(t.tag == tree::Tag::stateless());
root.item.on_event(
root.item.update(
&mut t.children[root.index],
event.clone(),
event,
lo,
view_cursor,
renderer,
@ -818,6 +816,5 @@ where
shell,
viewport,
)
})
.fold(event::Status::Ignored, event::Status::merge)
});
}

View file

@ -310,7 +310,7 @@ pub(crate) struct MenuState {
}
impl MenuState {
pub(super) fn layout<Message>(
&self,
&mut self,
overlay_offset: Vector,
slice: MenuSlice,
renderer: &crate::Renderer,
@ -329,8 +329,8 @@ impl MenuState {
// viewport space children bounds
let children_bounds = self.menu_bounds.children_bounds + overlay_offset;
let child_nodes = self.menu_bounds.child_positions[start_index..=end_index]
.iter()
.zip(self.menu_bounds.child_sizes[start_index..=end_index].iter())
.iter_mut()
.zip(self.menu_bounds.child_sizes[start_index..=end_index].iter_mut())
.zip(menu_tree[start_index..=end_index].iter())
.map(|((cp, size), mt)| {
let mut position = *cp;
@ -347,7 +347,11 @@ impl MenuState {
let limits = Limits::new(size, size);
mt.item
.layout(&mut tree[mt.index], renderer, &limits)
.element
.with_data_mut(|e| {
e.as_widget_mut()
.layout(&mut tree[mt.index], renderer, &limits)
})
.move_to(Point::new(0.0, position + self.scroll_offset))
})
.collect::<Vec<_>>();
@ -360,7 +364,7 @@ impl MenuState {
overlay_offset: Vector,
index: usize,
renderer: &crate::Renderer,
menu_tree: &MenuTree<Message>,
menu_tree: &mut MenuTree<Message>,
tree: &mut Tree,
) -> Node {
// viewport space children bounds
@ -499,7 +503,7 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
} else {
self.depth
}]
.iter()
.iter_mut()
.enumerate()
.filter(|ms| self.is_overlay || ms.0 < 1)
.fold(
@ -545,15 +549,15 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
}
#[allow(clippy::too_many_lines)]
fn on_event(
fn update(
&mut self,
event: event::Event,
event: &event::Event,
layout: Layout<'_>,
view_cursor: Cursor,
renderer: &crate::Renderer,
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
) -> (Option<(usize, MenuState)>, event::Status) {
) -> Option<(usize, MenuState)> {
use event::{
Event::{Mouse, Touch},
Status::{Captured, Ignored},
@ -569,7 +573,7 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
.inner
.with_data(|data| data.open || data.active_root.len() <= self.depth)
{
return (None, Ignored);
return None;
}
let viewport = layout.bounds();
@ -583,7 +587,7 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
};
let menu_status = process_menu_events(
self,
event.clone(),
&event,
view_cursor,
renderer,
clipboard,
@ -602,25 +606,28 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
self.main_offset as f32,
);
let ret = match event {
Mouse(WheelScrolled { delta }) => {
process_scroll_events(self, delta, overlay_cursor, viewport_size, overlay_offset)
.merge(menu_status)
}
match event {
Mouse(WheelScrolled { delta }) => process_scroll_events(
self,
shell,
*delta,
overlay_cursor,
viewport_size,
overlay_offset,
),
Mouse(ButtonPressed(Left)) | Touch(FingerPressed { .. }) => {
self.tree.inner.with_data_mut(|data| {
data.pressed = true;
data.view_cursor = view_cursor;
});
Captured
}
Mouse(CursorMoved { position }) | Touch(FingerMoved { position, .. }) => {
let view_cursor = Cursor::Available(position);
let view_cursor = Cursor::Available(*position);
let overlay_cursor = view_cursor.position().unwrap_or_default() - overlay_offset;
if !self.is_overlay && !view_cursor.is_over(viewport) {
return (None, menu_status);
return None;
}
let (new_root, status) = process_overlay_events(
@ -634,7 +641,7 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
shell,
);
return (new_root, status.merge(menu_status));
return new_root;
}
Mouse(ButtonReleased(_)) | Touch(FingerLifted { .. }) => {
@ -694,23 +701,19 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
}
state.reset();
return Captured;
}
}
// close all menus when clicking inside the menu bar
if self.bar_bounds.contains(overlay_cursor) {
state.reset();
Captured
} else {
menu_status
}
})
}
_ => menu_status,
_ => {}
};
(None, ret)
None
}
#[allow(unused_results, clippy::too_many_lines)]
@ -734,7 +737,7 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
let render_bounds = if self.is_overlay {
Rectangle::new(Point::ORIGIN, viewport.size())
} else {
Rectangle::new(Point::ORIGIN, Size::INFINITY)
Rectangle::new(Point::ORIGIN, Size::INFINITE)
};
let styling = theme.appearance(&self.style);
@ -796,6 +799,7 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
color: styling.border_color,
},
shadow: Shadow::default(),
snap: true,
};
let menu_color = styling.background;
r.fill_quad(menu_quad, menu_color);
@ -815,6 +819,7 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
..Default::default()
},
shadow: Shadow::default(),
snap: true,
};
r.fill_quad(path_quad, styling.path);
@ -867,17 +872,16 @@ impl<Message: Clone + 'static> overlay::Overlay<Message, crate::Theme, crate::Re
)
}
fn on_event(
fn update(
&mut self,
event: iced::Event,
event: &iced::Event,
layout: Layout<'_>,
cursor: mouse::Cursor,
renderer: &crate::Renderer,
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
) -> event::Status {
self.on_event(event, layout, cursor, renderer, clipboard, shell)
.1
) {
self.update(event, layout, cursor, renderer, clipboard, shell);
}
fn draw(
@ -903,7 +907,7 @@ impl<Message: std::clone::Clone + 'static> Widget<Message, crate::Theme, crate::
}
fn layout(
&self,
&mut self,
_tree: &mut Tree,
renderer: &crate::Renderer,
limits: &iced_core::layout::Limits,
@ -925,18 +929,18 @@ impl<Message: std::clone::Clone + 'static> Widget<Message, crate::Theme, crate::
}
#[allow(clippy::too_many_lines)]
fn on_event(
fn update(
&mut self,
tree: &mut Tree,
event: iced::Event,
event: &iced::Event,
layout: Layout<'_>,
cursor: mouse::Cursor,
renderer: &crate::Renderer,
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
viewport: &Rectangle,
) -> event::Status {
let (new_root, status) = self.on_event(event, layout, cursor, renderer, clipboard, shell);
) {
let new_root = self.update(event, layout, cursor, renderer, clipboard, shell);
#[cfg(all(
feature = "multi-window",
@ -997,7 +1001,7 @@ impl<Message: std::clone::Clone + 'static> Widget<Message, crate::Theme, crate::
Some((popup_menu, popup_id))
}) else {
return status;
return;
};
// XXX we push a new active root manually instead
init_root_popup_menu(
@ -1040,7 +1044,7 @@ impl<Message: std::clone::Clone + 'static> Widget<Message, crate::Theme, crate::
});
let menu_node = Widget::layout(
&menu,
&mut menu,
&mut Tree::empty(),
renderer,
&Limits::NONE.min_width(1.).min_height(1.),
@ -1082,10 +1086,9 @@ impl<Message: std::clone::Clone + 'static> Widget<Message, crate::Theme, crate::
),
));
return status;
return;
}
}
status
}
}
@ -1103,8 +1106,8 @@ fn pad_rectangle(rect: Rectangle, padding: Padding) -> Rectangle {
Rectangle {
x: rect.x - padding.left,
y: rect.y - padding.top,
width: rect.width + padding.horizontal(),
height: rect.height + padding.vertical(),
width: rect.width + padding.x(),
height: rect.height + padding.y(),
}
}
@ -1274,15 +1277,13 @@ pub(super) fn init_root_popup_menu<Message>(
#[allow(clippy::too_many_arguments)]
fn process_menu_events<Message: std::clone::Clone>(
menu: &mut Menu<Message>,
event: event::Event,
event: &event::Event,
view_cursor: Cursor,
renderer: &crate::Renderer,
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
overlay_offset: Vector,
) -> event::Status {
use event::Status;
) {
let my_state = &mut menu.tree;
let menu_roots = match &mut menu.menu_roots {
Cow::Borrowed(_) => panic!(),
@ -1290,15 +1291,15 @@ fn process_menu_events<Message: std::clone::Clone>(
};
my_state.inner.with_data_mut(|state| {
if state.active_root.len() <= menu.depth {
return event::Status::Ignored;
return;
}
let Some(hover) = state.menu_states.last_mut() else {
return Status::Ignored;
return;
};
let Some(hover_index) = hover.index else {
return Status::Ignored;
return;
};
let mt = state.active_root.iter().skip(1).fold(
@ -1321,7 +1322,7 @@ fn process_menu_events<Message: std::clone::Clone>(
let child_layout = Layout::new(&child_node);
// process only the last widget
mt.item.on_event(
mt.item.update(
tree,
event,
child_layout,
@ -1330,7 +1331,7 @@ fn process_menu_events<Message: std::clone::Clone>(
clipboard,
shell,
&Rectangle::default(),
)
);
})
}
@ -1561,12 +1562,12 @@ where
fn process_scroll_events<Message>(
menu: &mut Menu<'_, Message>,
shell: &mut Shell<'_, Message>,
delta: mouse::ScrollDelta,
overlay_cursor: Point,
viewport_size: Size,
overlay_offset: Vector,
) -> event::Status
where
) where
Message: Clone,
{
use event::Status::{Captured, Ignored};
@ -1590,12 +1591,12 @@ where
// update
if state.menu_states.is_empty() {
return Ignored;
return;
} else if state.menu_states.len() == 1 {
let last_ms = &mut state.menu_states[0];
if last_ms.index.is_none() {
return Captured;
return;
}
let (max_offset, min_offset) = calc_offset_bounds(last_ms, viewport_size);
@ -1616,7 +1617,8 @@ where
.children_bounds
.contains(overlay_cursor)
{
return Captured;
shell.capture_event();
return;
}
// scroll the second last one
@ -1632,8 +1634,8 @@ where
last_two[1].menu_bounds.check_bounds.y += clamped_delta_y;
}
}
Captured
})
shell.capture_event();
});
}
#[allow(clippy::pedantic)]
@ -1666,11 +1668,11 @@ fn get_children_layout<Message>(
.map(|mt| {
mt.item
.element
.with_data(|w| match w.as_widget().size().height {
.with_data_mut(|w| match w.as_widget_mut().size().height {
Length::Fixed(f) => Size::new(width, f),
Length::Shrink => {
let l_height = w
.as_widget()
.as_widget_mut()
.layout(
&mut tree[mt.index],
renderer,

View file

@ -253,13 +253,16 @@ pub fn menu_items<
let key = find_key(&action, key_binds);
let mut items = vec![
widget::text(l).into(),
widget::horizontal_space().into(),
widget::space::horizontal().into(),
widget::text(key).class(key_class).into(),
];
if let Some(icon) = icon {
items.insert(0, widget::icon::icon(icon).size(14).into());
items.insert(1, widget::Space::with_width(spacing.space_xxs).into());
items.insert(
1,
widget::space::horizontal().width(spacing.space_xxs).into(),
);
}
let menu_button = menu_button(items).on_press(action.message());
@ -273,13 +276,16 @@ pub fn menu_items<
let mut items = vec![
widget::text(l).into(),
widget::horizontal_space().into(),
widget::space::horizontal().into(),
widget::text(key).class(key_class).into(),
];
if let Some(icon) = icon {
items.insert(0, widget::icon::icon(icon).size(14).into());
items.insert(1, widget::Space::with_width(spacing.space_xxs).into());
items.insert(
1,
widget::space::horizontal().width(spacing.space_xxs).into(),
);
}
let menu_button = menu_button(items);
@ -301,16 +307,21 @@ pub fn menu_items<
.width(Length::Fixed(16.0))
.into()
} else {
widget::Space::with_width(Length::Fixed(16.0)).into()
widget::space::horizontal()
.width(Length::Fixed(16.0))
.into()
},
widget::Space::with_width(spacing.space_xxs).into(),
widget::space::horizontal().width(spacing.space_xxs).into(),
widget::text(label).align_x(iced::Alignment::Start).into(),
widget::horizontal_space().into(),
widget::space::horizontal().into(),
widget::text(key).class(key_class).into(),
];
if let Some(icon) = icon {
items.insert(1, widget::Space::with_width(spacing.space_xxs).into());
items.insert(
1,
widget::space::horizontal().width(spacing.space_xxs).into(),
);
items.insert(2, widget::icon::icon(icon).size(14).into());
}
@ -325,7 +336,7 @@ pub fn menu_items<
RcElementWrapper::new(crate::Element::from(
menu_button::<'static, _>(vec![
widget::text(l.clone()).into(),
widget::horizontal_space().into(),
widget::space::horizontal().into(),
widget::icon::from_name("pan-end-symbolic")
.size(16)
.icon()