Add in-window menus for Linux and Windows.
This commit is contained in:
@@ -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)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user