Improve popup menu to leave some margin with window edges (#17159)
Release Notes: - Improved popup menu to leave some margin with window edges. ## Updates in GPUI - gpui: Add `snap_to_window_with_margin` method to `anchored` to support leave margin to window edges. ## Before <img width="609" alt="before-snap-to-window 2024-08-30 222506" src="https://github.com/user-attachments/assets/62bb6791-7c89-4558-9484-5c7b31f5e91e"> ## After <img width="698" alt="snap-to-window1 2024-08-30 222506" src="https://github.com/user-attachments/assets/51634e79-2a95-42fe-8362-a3c7003648eb"> <img width="622" alt="snap-to-window 2024-08-30 222506" src="https://github.com/user-attachments/assets/43a865d6-d238-4fdc-ae9d-8160b9ba7953">
This commit is contained in:
parent
b401f6951b
commit
47aec5e64d
5 changed files with 40 additions and 18 deletions
|
@ -2732,7 +2732,7 @@ impl EditorElement {
|
||||||
.position(position)
|
.position(position)
|
||||||
.child(context_menu)
|
.child(context_menu)
|
||||||
.anchor(AnchorCorner::TopLeft)
|
.anchor(AnchorCorner::TopLeft)
|
||||||
.snap_to_window(),
|
.snap_to_window_with_margin(px(8.)),
|
||||||
)
|
)
|
||||||
.with_priority(1)
|
.with_priority(1)
|
||||||
.into_any(),
|
.into_any(),
|
||||||
|
|
|
@ -2,8 +2,8 @@ use smallvec::SmallVec;
|
||||||
use taffy::style::{Display, Position};
|
use taffy::style::{Display, Position};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
point, AnyElement, Bounds, Element, GlobalElementId, IntoElement, LayoutId, ParentElement,
|
point, AnyElement, Bounds, Edges, Element, GlobalElementId, IntoElement, LayoutId,
|
||||||
Pixels, Point, Size, Style, WindowContext,
|
ParentElement, Pixels, Point, Size, Style, WindowContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The state that the anchored element element uses to track its children.
|
/// The state that the anchored element element uses to track its children.
|
||||||
|
@ -60,6 +60,12 @@ impl Anchored {
|
||||||
self.fit_mode = AnchoredFitMode::SnapToWindow;
|
self.fit_mode = AnchoredFitMode::SnapToWindow;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Snap to window edge and leave some margins.
|
||||||
|
pub fn snap_to_window_with_margin(mut self, edges: impl Into<Edges<Pixels>>) -> Self {
|
||||||
|
self.fit_mode = AnchoredFitMode::SnapToWindowWithMargin(edges.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParentElement for Anchored {
|
impl ParentElement for Anchored {
|
||||||
|
@ -153,22 +159,27 @@ impl Element for Anchored {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let edges = match self.fit_mode {
|
||||||
|
AnchoredFitMode::SnapToWindowWithMargin(edges) => edges,
|
||||||
|
_ => Edges::default(),
|
||||||
|
};
|
||||||
|
|
||||||
// Snap the horizontal edges of the anchored element to the horizontal edges of the window if
|
// Snap the horizontal edges of the anchored element to the horizontal edges of the window if
|
||||||
// its horizontal bounds overflow, aligning to the left if it is wider than the limits.
|
// its horizontal bounds overflow, aligning to the left if it is wider than the limits.
|
||||||
if desired.right() > limits.right() {
|
if desired.right() > limits.right() {
|
||||||
desired.origin.x -= desired.right() - limits.right();
|
desired.origin.x -= desired.right() - limits.right() + edges.right;
|
||||||
}
|
}
|
||||||
if desired.left() < limits.left() {
|
if desired.left() < limits.left() {
|
||||||
desired.origin.x = limits.origin.x;
|
desired.origin.x = limits.origin.x + edges.left;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Snap the vertical edges of the anchored element to the vertical edges of the window if
|
// Snap the vertical edges of the anchored element to the vertical edges of the window if
|
||||||
// its vertical bounds overflow, aligning to the top if it is taller than the limits.
|
// its vertical bounds overflow, aligning to the top if it is taller than the limits.
|
||||||
if desired.bottom() > limits.bottom() {
|
if desired.bottom() > limits.bottom() {
|
||||||
desired.origin.y -= desired.bottom() - limits.bottom();
|
desired.origin.y -= desired.bottom() - limits.bottom() + edges.bottom;
|
||||||
}
|
}
|
||||||
if desired.top() < limits.top() {
|
if desired.top() < limits.top() {
|
||||||
desired.origin.y = limits.origin.y;
|
desired.origin.y = limits.origin.y + edges.top;
|
||||||
}
|
}
|
||||||
|
|
||||||
let offset = desired.origin - bounds.origin;
|
let offset = desired.origin - bounds.origin;
|
||||||
|
@ -211,18 +222,20 @@ enum Axis {
|
||||||
/// Which algorithm to use when fitting the anchored element to be inside the window.
|
/// Which algorithm to use when fitting the anchored element to be inside the window.
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub enum AnchoredFitMode {
|
pub enum AnchoredFitMode {
|
||||||
/// Snap the anchored element to the window edge
|
/// Snap the anchored element to the window edge.
|
||||||
SnapToWindow,
|
SnapToWindow,
|
||||||
/// Switch which corner anchor this anchored element is attached to
|
/// Snap to window edge and leave some margins.
|
||||||
|
SnapToWindowWithMargin(Edges<Pixels>),
|
||||||
|
/// Switch which corner anchor this anchored element is attached to.
|
||||||
SwitchAnchor,
|
SwitchAnchor,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Which algorithm to use when positioning the anchored element.
|
/// Which algorithm to use when positioning the anchored element.
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub enum AnchoredPositionMode {
|
pub enum AnchoredPositionMode {
|
||||||
/// Position the anchored element relative to the window
|
/// Position the anchored element relative to the window.
|
||||||
Window,
|
Window,
|
||||||
/// Position the anchored element relative to its parent
|
/// Position the anchored element relative to its parent.
|
||||||
Local,
|
Local,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1836,11 +1836,18 @@ impl Edges<Pixels> {
|
||||||
|
|
||||||
impl From<f32> for Edges<Pixels> {
|
impl From<f32> for Edges<Pixels> {
|
||||||
fn from(val: f32) -> Self {
|
fn from(val: f32) -> Self {
|
||||||
|
let val: Pixels = val.into();
|
||||||
|
val.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Pixels> for Edges<Pixels> {
|
||||||
|
fn from(val: Pixels) -> Self {
|
||||||
Edges {
|
Edges {
|
||||||
top: val.into(),
|
top: val,
|
||||||
right: val.into(),
|
right: val,
|
||||||
bottom: val.into(),
|
bottom: val,
|
||||||
left: val.into(),
|
left: val,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -252,7 +252,9 @@ impl<M: ManagedView> Element for PopoverMenu<M> {
|
||||||
let mut menu_layout_id = None;
|
let mut menu_layout_id = None;
|
||||||
|
|
||||||
let menu_element = element_state.menu.borrow_mut().as_mut().map(|menu| {
|
let menu_element = element_state.menu.borrow_mut().as_mut().map(|menu| {
|
||||||
let mut anchored = anchored().snap_to_window().anchor(self.anchor);
|
let mut anchored = anchored()
|
||||||
|
.snap_to_window_with_margin(px(8.))
|
||||||
|
.anchor(self.anchor);
|
||||||
if let Some(child_bounds) = element_state.child_bounds {
|
if let Some(child_bounds) = element_state.child_bounds {
|
||||||
anchored = anchored.position(
|
anchored = anchored.position(
|
||||||
self.resolved_attach().corner(child_bounds) + self.resolved_offset(cx),
|
self.resolved_attach().corner(child_bounds) + self.resolved_offset(cx),
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{cell::RefCell, rc::Rc};
|
use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
anchored, deferred, div, AnchorCorner, AnyElement, Bounds, DismissEvent, DispatchPhase,
|
anchored, deferred, div, px, AnchorCorner, AnyElement, Bounds, DismissEvent, DispatchPhase,
|
||||||
Element, ElementId, GlobalElementId, Hitbox, InteractiveElement, IntoElement, LayoutId,
|
Element, ElementId, GlobalElementId, Hitbox, InteractiveElement, IntoElement, LayoutId,
|
||||||
ManagedView, MouseButton, MouseDownEvent, ParentElement, Pixels, Point, View, VisualContext,
|
ManagedView, MouseButton, MouseDownEvent, ParentElement, Pixels, Point, View, VisualContext,
|
||||||
WindowContext,
|
WindowContext,
|
||||||
|
@ -118,7 +118,7 @@ impl<M: ManagedView> Element for RightClickMenu<M> {
|
||||||
let mut menu_layout_id = None;
|
let mut menu_layout_id = None;
|
||||||
|
|
||||||
let menu_element = element_state.menu.borrow_mut().as_mut().map(|menu| {
|
let menu_element = element_state.menu.borrow_mut().as_mut().map(|menu| {
|
||||||
let mut anchored = anchored().snap_to_window();
|
let mut anchored = anchored().snap_to_window_with_margin(px(8.));
|
||||||
if let Some(anchor) = this.anchor {
|
if let Some(anchor) = this.anchor {
|
||||||
anchored = anchored.anchor(anchor);
|
anchored = anchored.anchor(anchor);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue