Add in-window menus for Linux and Windows.

This commit is contained in:
2026-08-07 15:23:12 +02:00
parent 3b1a65359c
commit 358648378e
4 changed files with 767 additions and 69 deletions

View File

@@ -15,6 +15,7 @@ pub struct Popover<'a, Message, Theme = iced::Theme, Renderer = iced::Renderer>
is_open: bool,
on_dismiss: Message,
gap: f32,
align_right: bool,
}
impl<'a, Message, Theme, Renderer> Popover<'a, Message, Theme, Renderer> {
@@ -30,13 +31,31 @@ impl<'a, Message, Theme, Renderer> Popover<'a, Message, Theme, Renderer> {
is_open,
on_dismiss,
gap: 8.0,
align_right: true,
}
}
/// Anchor the popup to the trigger's left edge.
pub fn align_left(mut self) -> Self {
self.align_right = false;
self
}
}
fn popup_position(anchor: Rectangle, popup: Size, viewport: Size, gap: f32) -> Point {
fn popup_position(
anchor: Rectangle,
popup: Size,
viewport: Size,
gap: f32,
align_right: bool,
) -> Point {
let max_x = (viewport.width - popup.width).max(0.0);
let x = (anchor.x + anchor.width - popup.width).clamp(0.0, max_x);
let x = if align_right {
anchor.x + anchor.width - popup.width
} else {
anchor.x
}
.clamp(0.0, max_x);
let below = anchor.y + anchor.height + gap;
let y = if below + popup.height <= viewport.height {
below
@@ -169,6 +188,7 @@ where
state: &mut popup_tree[0],
on_dismiss: self.on_dismiss.clone(),
gap: self.gap,
align_right: self.align_right,
}))
});
@@ -203,6 +223,7 @@ struct PopupOverlay<'a, 'b, Message, Theme, Renderer> {
state: &'b mut Tree,
on_dismiss: Message,
gap: f32,
align_right: bool,
}
impl<Message, Theme, Renderer> overlay::Overlay<Message, Theme, Renderer>
@@ -217,7 +238,13 @@ where
renderer,
&layout::Limits::new(Size::ZERO, bounds),
);
let position = popup_position(self.anchor, popup.size(), bounds, self.gap);
let position = popup_position(
self.anchor,
popup.size(),
bounds,
self.gap,
self.align_right,
);
layout::Node::with_children(popup.size(), vec![popup])
.translate(Vector::new(position.x, position.y))
}
@@ -345,6 +372,7 @@ mod tests {
Size::new(220.0, 180.0),
Size::new(800.0, 600.0),
8.0,
true,
),
Point::new(280.0, 58.0)
);
@@ -358,8 +386,23 @@ mod tests {
Size::new(220.0, 180.0),
Size::new(800.0, 600.0),
8.0,
true,
),
Point::new(0.0, 382.0)
);
}
#[test]
fn popup_can_be_left_aligned_to_its_trigger() {
assert_eq!(
popup_position(
Rectangle::new(Point::new(120.0, 20.0), Size::new(80.0, 30.0)),
Size::new(220.0, 180.0),
Size::new(800.0, 600.0),
8.0,
false,
),
Point::new(120.0, 58.0)
);
}
}