Add Corner to geometry and make names of corner methods consistent (#22119)

Michael Sloan created

Release Notes:

- N/A

Change summary

crates/activity_indicator/src/activity_indicator.rs             |   2 
crates/assistant/src/inline_assistant.rs                        |   2 
crates/assistant/src/slash_command_picker.rs                    |   4 
crates/assistant2/src/context_strip.rs                          |   4 
crates/assistant2/src/inline_assistant.rs                       |   2 
crates/collab_ui/src/collab_panel.rs                            |   2 
crates/collab_ui/src/collab_panel/channel_modal.rs              |   2 
crates/collab_ui/src/collab_ui.rs                               |   2 
crates/editor/src/element.rs                                    |  30 
crates/editor/src/hunk_diff.rs                                  |   5 
crates/file_finder/src/file_finder.rs                           |   4 
crates/gpui/examples/gradient.rs                                |   8 
crates/gpui/examples/painting.rs                                |  10 
crates/gpui/examples/window_positioning.rs                      |   6 
crates/gpui/src/elements/anchored.rs                            | 107 -
crates/gpui/src/elements/div.rs                                 |   4 
crates/gpui/src/elements/uniform_list.rs                        |   4 
crates/gpui/src/geometry.rs                                     | 201 ++
crates/gpui/src/style.rs                                        |  18 
crates/inline_completion_button/src/inline_completion_button.rs |   6 
crates/language_model_selector/src/language_model_selector.rs   |   2 
crates/language_tools/src/lsp_log.rs                            |  10 
crates/outline_panel/src/outline_panel.rs                       |   2 
crates/project_panel/src/project_panel.rs                       |   2 
crates/repl/src/components/kernel_options.rs                    |   2 
crates/terminal/src/terminal.rs                                 |   2 
crates/terminal_view/src/terminal_panel.rs                      |   6 
crates/terminal_view/src/terminal_view.rs                       |   2 
crates/title_bar/src/collab.rs                                  |  10 
crates/title_bar/src/title_bar.rs                               |   2 
crates/ui/src/components/dropdown_menu.rs                       |   4 
crates/ui/src/components/popover_menu.rs                        |  34 
crates/ui/src/components/right_click_menu.rs                    |  17 
crates/ui/src/components/scrollbar.rs                           |   4 
crates/ui/src/components/stories/context_menu.rs                |  12 
crates/workspace/src/dock.rs                                    |  14 
crates/workspace/src/pane.rs                                    |  15 
crates/workspace/src/pane_group.rs                              |  10 
crates/zed/src/zed/quick_action_bar.rs                          |   6 
39 files changed, 325 insertions(+), 254 deletions(-)

Detailed changes

crates/assistant/src/inline_assistant.rs πŸ”—

@@ -1556,7 +1556,7 @@ impl Render for PromptEditor {
                                             anchored()
                                                 .position_mode(gpui::AnchoredPositionMode::Local)
                                                 .position(point(px(0.), px(24.)))
-                                                .anchor(gpui::AnchorCorner::TopLeft)
+                                                .anchor(gpui::Corner::TopLeft)
                                                 .child(self.render_rate_limit_notice(cx)),
                                         )
                                     })),

crates/assistant/src/slash_command_picker.rs πŸ”—

@@ -316,8 +316,8 @@ impl<T: PopoverTrigger> RenderOnce for SlashCommandSelector<T> {
         PopoverMenu::new("model-switcher")
             .menu(move |_cx| Some(picker_view.clone()))
             .trigger(self.trigger)
-            .attach(gpui::AnchorCorner::TopLeft)
-            .anchor(gpui::AnchorCorner::BottomLeft)
+            .attach(gpui::Corner::TopLeft)
+            .anchor(gpui::Corner::BottomLeft)
             .offset(gpui::Point {
                 x: px(0.0),
                 y: px(-16.0),

crates/assistant2/src/context_strip.rs πŸ”—

@@ -67,8 +67,8 @@ impl Render for ContextStrip {
                                 )
                             }),
                     )
-                    .attach(gpui::AnchorCorner::TopLeft)
-                    .anchor(gpui::AnchorCorner::BottomLeft)
+                    .attach(gpui::Corner::TopLeft)
+                    .anchor(gpui::Corner::BottomLeft)
                     .offset(gpui::Point {
                         x: px(0.0),
                         y: px(-16.0),

crates/assistant2/src/inline_assistant.rs πŸ”—

@@ -1673,7 +1673,7 @@ impl Render for PromptEditor {
                                                             gpui::AnchoredPositionMode::Local,
                                                         )
                                                         .position(point(px(0.), px(24.)))
-                                                        .anchor(gpui::AnchorCorner::TopLeft)
+                                                        .anchor(gpui::Corner::TopLeft)
                                                         .child(self.render_rate_limit_notice(cx)),
                                                 )
                                             })),

crates/collab_ui/src/collab_panel.rs πŸ”—

@@ -2708,7 +2708,7 @@ impl Render for CollabPanel {
                 deferred(
                     anchored()
                         .position(*position)
-                        .anchor(gpui::AnchorCorner::TopLeft)
+                        .anchor(gpui::Corner::TopLeft)
                         .child(menu.clone()),
                 )
                 .with_priority(1)

crates/collab_ui/src/collab_ui.rs πŸ”—

@@ -44,7 +44,7 @@ fn notification_window_options(
     let notification_margin_height = px(-48.);
 
     let bounds = gpui::Bounds::<Pixels> {
-        origin: screen.bounds().upper_right()
+        origin: screen.bounds().top_right()
             - point(
                 size.width + notification_margin_width,
                 notification_margin_height,

crates/editor/src/element.rs πŸ”—

@@ -31,13 +31,13 @@ use file_icons::FileIcons;
 use git::{blame::BlameEntry, diff::DiffHunkStatus, Oid};
 use gpui::{
     anchored, deferred, div, fill, outline, point, px, quad, relative, size, svg,
-    transparent_black, Action, AnchorCorner, AnyElement, AvailableSpace, Bounds, ClickEvent,
-    ClipboardItem, ContentMask, Corners, CursorStyle, DispatchPhase, Edges, Element,
-    ElementInputHandler, Entity, FontId, GlobalElementId, HighlightStyle, Hitbox, Hsla,
-    InteractiveElement, IntoElement, Length, ModifiersChangedEvent, MouseButton, MouseDownEvent,
-    MouseMoveEvent, MouseUpEvent, PaintQuad, ParentElement, Pixels, ScrollDelta, ScrollWheelEvent,
-    ShapedLine, SharedString, Size, StatefulInteractiveElement, Style, Styled, Subscription,
-    TextRun, TextStyleRefinement, View, ViewContext, WeakView, WindowContext,
+    transparent_black, Action, AnyElement, AvailableSpace, Bounds, ClickEvent, ClipboardItem,
+    ContentMask, Corner, Corners, CursorStyle, DispatchPhase, Edges, Element, ElementInputHandler,
+    Entity, FontId, GlobalElementId, HighlightStyle, Hitbox, Hsla, InteractiveElement, IntoElement,
+    Length, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent,
+    PaintQuad, ParentElement, Pixels, ScrollDelta, ScrollWheelEvent, ShapedLine, SharedString,
+    Size, StatefulInteractiveElement, Style, Styled, Subscription, TextRun, TextStyleRefinement,
+    View, ViewContext, WeakView, WindowContext,
 };
 use itertools::Itertools;
 use language::{
@@ -706,7 +706,7 @@ impl EditorElement {
         let mut scroll_delta = gpui::Point::<f32>::default();
         let vertical_margin = position_map.line_height.min(text_bounds.size.height / 3.0);
         let top = text_bounds.origin.y + vertical_margin;
-        let bottom = text_bounds.lower_left().y - vertical_margin;
+        let bottom = text_bounds.bottom_left().y - vertical_margin;
         if event.position.y < top {
             scroll_delta.y = -scale_vertical_mouse_autoscroll_delta(top - event.position.y);
         }
@@ -716,7 +716,7 @@ impl EditorElement {
 
         let horizontal_margin = position_map.line_height.min(text_bounds.size.width / 3.0);
         let left = text_bounds.origin.x + horizontal_margin;
-        let right = text_bounds.upper_right().x - horizontal_margin;
+        let right = text_bounds.top_right().x - horizontal_margin;
         if event.position.x < left {
             scroll_delta.x = -scale_horizontal_mouse_autoscroll_delta(left - event.position.x);
         }
@@ -1213,7 +1213,7 @@ impl EditorElement {
 
         let track_bounds = Bounds::from_corners(
             point(self.scrollbar_left(&bounds), bounds.origin.y),
-            point(bounds.lower_right().x, bounds.lower_left().y),
+            point(bounds.bottom_right().x, bounds.bottom_left().y),
         );
 
         let settings = EditorSettings::get_global(cx);
@@ -2824,7 +2824,7 @@ impl EditorElement {
             list_origin.x = (cx.viewport_size().width - list_width).max(Pixels::ZERO);
         }
 
-        if list_origin.y + list_height > text_hitbox.lower_right().y {
+        if list_origin.y + list_height > text_hitbox.bottom_right().y {
             list_origin.y -= line_height + list_height;
         }
 
@@ -3067,7 +3067,7 @@ impl EditorElement {
                     anchored()
                         .position(position)
                         .child(context_menu)
-                        .anchor(AnchorCorner::TopLeft)
+                        .anchor(Corner::TopLeft)
                         .snap_to_window_with_margin(px(8.)),
                 )
                 .with_priority(1)
@@ -3132,7 +3132,7 @@ impl EditorElement {
         for mut hover_popover in hover_popovers {
             let size = hover_popover.layout_as_root(AvailableSpace::min_size(), cx);
             let horizontal_offset =
-                (text_hitbox.upper_right().x - (hovered_point.x + size.width)).min(Pixels::ZERO);
+                (text_hitbox.top_right().x - (hovered_point.x + size.width)).min(Pixels::ZERO);
 
             overall_height += HOVER_POPOVER_GAP + size.height;
 
@@ -4407,7 +4407,7 @@ impl EditorElement {
     }
 
     fn scrollbar_left(&self, bounds: &Bounds<Pixels>) -> Pixels {
-        bounds.upper_right().x - self.style.scrollbar_width
+        bounds.top_right().x - self.style.scrollbar_width
     }
 
     fn column_pixels(&self, column: usize, cx: &WindowContext) -> Pixels {
@@ -5488,7 +5488,7 @@ impl Element for EditorElement {
                         cx.insert_hitbox(gutter_bounds(bounds, gutter_dimensions), false);
                     let text_hitbox = cx.insert_hitbox(
                         Bounds {
-                            origin: gutter_hitbox.upper_right(),
+                            origin: gutter_hitbox.top_right(),
                             size: size(text_width, bounds.size.height),
                         },
                         false,

crates/editor/src/hunk_diff.rs πŸ”—

@@ -1,8 +1,7 @@
 use collections::{HashMap, HashSet};
 use git::diff::DiffHunkStatus;
 use gpui::{
-    Action, AnchorCorner, AppContext, CursorStyle, Hsla, Model, MouseButton, Subscription, Task,
-    View,
+    Action, AppContext, Corner, CursorStyle, Hsla, Model, MouseButton, Subscription, Task, View,
 };
 use language::{Buffer, BufferId, Point};
 use multi_buffer::{
@@ -743,7 +742,7 @@ impl Editor {
                                                                 },
                                                             ),
                                                         )
-                                                        .anchor(AnchorCorner::TopRight)
+                                                        .anchor(Corner::TopRight)
                                                         .with_handle(hunk_controls_menu_handle)
                                                         .menu(move |cx| {
                                                             let focus = focus.clone();

crates/file_finder/src/file_finder.rs πŸ”—

@@ -1261,8 +1261,8 @@ impl PickerDelegate for FileFinderDelegate {
                 .child(
                     PopoverMenu::new("menu-popover")
                         .with_handle(self.popover_menu_handle.clone())
-                        .attach(gpui::AnchorCorner::TopRight)
-                        .anchor(gpui::AnchorCorner::BottomRight)
+                        .attach(gpui::Corner::TopRight)
+                        .anchor(gpui::Corner::BottomRight)
                         .trigger(
                             Button::new("actions-trigger", "Split Options")
                                 .selected_label_color(Color::Accent)

crates/gpui/examples/gradient.rs πŸ”—

@@ -218,13 +218,13 @@ impl Render for GradientViewer {
                     let height = square_bounds.size.height;
                     let horizontal_offset = height;
                     let vertical_offset = px(30.);
-                    let mut path = gpui::Path::new(square_bounds.lower_left());
+                    let mut path = gpui::Path::new(square_bounds.bottom_left());
                     path.line_to(square_bounds.origin + point(horizontal_offset, vertical_offset));
                     path.line_to(
-                        square_bounds.upper_right() + point(-horizontal_offset, vertical_offset),
+                        square_bounds.top_right() + point(-horizontal_offset, vertical_offset),
                     );
-                    path.line_to(square_bounds.lower_right());
-                    path.line_to(square_bounds.lower_left());
+                    path.line_to(square_bounds.bottom_right());
+                    path.line_to(square_bounds.bottom_left());
                     cx.paint_path(
                         path,
                         linear_gradient(

crates/gpui/examples/painting.rs πŸ”—

@@ -49,17 +49,17 @@ impl PaintingViewer {
         let height = square_bounds.size.height;
         let horizontal_offset = height;
         let vertical_offset = px(30.);
-        let mut path = Path::new(square_bounds.lower_left());
+        let mut path = Path::new(square_bounds.bottom_left());
         path.curve_to(
             square_bounds.origin + point(horizontal_offset, vertical_offset),
             square_bounds.origin + point(px(0.0), vertical_offset),
         );
-        path.line_to(square_bounds.upper_right() + point(-horizontal_offset, vertical_offset));
+        path.line_to(square_bounds.top_right() + point(-horizontal_offset, vertical_offset));
         path.curve_to(
-            square_bounds.lower_right(),
-            square_bounds.upper_right() + point(px(0.0), vertical_offset),
+            square_bounds.bottom_right(),
+            square_bounds.top_right() + point(px(0.0), vertical_offset),
         );
-        path.line_to(square_bounds.lower_left());
+        path.line_to(square_bounds.bottom_left());
         lines.push(path);
 
         Self {

crates/gpui/examples/window_positioning.rs πŸ”—

@@ -86,7 +86,7 @@ fn main() {
             .unwrap();
 
             let bounds = Bounds {
-                origin: screen.bounds().upper_right()
+                origin: screen.bounds().top_right()
                     - point(size.width + margin_offset, -margin_offset),
                 size,
             };
@@ -101,7 +101,7 @@ fn main() {
             .unwrap();
 
             let bounds = Bounds {
-                origin: screen.bounds().lower_left()
+                origin: screen.bounds().bottom_left()
                     - point(-margin_offset, size.height + margin_offset),
                 size,
             };
@@ -116,7 +116,7 @@ fn main() {
             .unwrap();
 
             let bounds = Bounds {
-                origin: screen.bounds().lower_right()
+                origin: screen.bounds().bottom_right()
                     - point(size.width + margin_offset, size.height + margin_offset),
                 size,
             };

crates/gpui/src/elements/anchored.rs πŸ”—

@@ -2,8 +2,8 @@ use smallvec::SmallVec;
 use taffy::style::{Display, Position};
 
 use crate::{
-    point, AnyElement, Bounds, Edges, Element, GlobalElementId, IntoElement, LayoutId,
-    ParentElement, Pixels, Point, Size, Style, WindowContext,
+    point, AnyElement, Axis, Bounds, Corner, Edges, Element, GlobalElementId, IntoElement,
+    LayoutId, ParentElement, Pixels, Point, Size, Style, WindowContext,
 };
 
 /// The state that the anchored element element uses to track its children.
@@ -15,7 +15,7 @@ pub struct AnchoredState {
 /// will avoid overflowing the window bounds.
 pub struct Anchored {
     children: SmallVec<[AnyElement; 2]>,
-    anchor_corner: AnchorCorner,
+    anchor_corner: Corner,
     fit_mode: AnchoredFitMode,
     anchor_position: Option<Point<Pixels>>,
     position_mode: AnchoredPositionMode,
@@ -26,7 +26,7 @@ pub struct Anchored {
 pub fn anchored() -> Anchored {
     Anchored {
         children: SmallVec::new(),
-        anchor_corner: AnchorCorner::TopLeft,
+        anchor_corner: Corner::TopLeft,
         fit_mode: AnchoredFitMode::SwitchAnchor,
         anchor_position: None,
         position_mode: AnchoredPositionMode::Window,
@@ -35,7 +35,7 @@ pub fn anchored() -> Anchored {
 
 impl Anchored {
     /// Sets which corner of the anchored element should be anchored to the current position.
-    pub fn anchor(mut self, anchor: AnchorCorner) -> Self {
+    pub fn anchor(mut self, anchor: Corner) -> Self {
         self.anchor_corner = anchor;
         self
     }
@@ -120,7 +120,7 @@ impl Element for Anchored {
         for child_layout_id in &request_layout.child_layout_ids {
             let child_bounds = cx.layout_bounds(*child_layout_id);
             child_min = child_min.min(&child_bounds.origin);
-            child_max = child_max.max(&child_bounds.lower_right());
+            child_max = child_max.max(&child_bounds.bottom_right());
         }
         let size: Size<Pixels> = (child_max - child_min).into();
 
@@ -140,19 +140,23 @@ impl Element for Anchored {
             let mut anchor_corner = self.anchor_corner;
 
             if desired.left() < limits.left() || desired.right() > limits.right() {
-                let switched = anchor_corner
-                    .switch_axis(Axis::Horizontal)
-                    .get_bounds(origin, size);
+                let switched = Bounds::from_corner_and_size(
+                    anchor_corner.other_side_corner_along(Axis::Horizontal),
+                    origin,
+                    size,
+                );
                 if !(switched.left() < limits.left() || switched.right() > limits.right()) {
-                    anchor_corner = anchor_corner.switch_axis(Axis::Horizontal);
+                    anchor_corner = anchor_corner.other_side_corner_along(Axis::Horizontal);
                     desired = switched
                 }
             }
 
             if desired.top() < limits.top() || desired.bottom() > limits.bottom() {
-                let switched = anchor_corner
-                    .switch_axis(Axis::Vertical)
-                    .get_bounds(origin, size);
+                let switched = Bounds::from_corner_and_size(
+                    anchor_corner.other_side_corner_along(Axis::Vertical),
+                    origin,
+                    size,
+                );
                 if !(switched.top() < limits.top() || switched.bottom() > limits.bottom()) {
                     desired = switched;
                 }
@@ -214,11 +218,6 @@ impl IntoElement for Anchored {
     }
 }
 
-enum Axis {
-    Horizontal,
-    Vertical,
-}
-
 /// Which algorithm to use when fitting the anchored element to be inside the window.
 #[derive(Copy, Clone, PartialEq)]
 pub enum AnchoredFitMode {
@@ -243,83 +242,25 @@ impl AnchoredPositionMode {
     fn get_position_and_bounds(
         &self,
         anchor_position: Option<Point<Pixels>>,
-        anchor_corner: AnchorCorner,
+        anchor_corner: Corner,
         size: Size<Pixels>,
         bounds: Bounds<Pixels>,
     ) -> (Point<Pixels>, Bounds<Pixels>) {
         match self {
             AnchoredPositionMode::Window => {
                 let anchor_position = anchor_position.unwrap_or(bounds.origin);
-                let bounds = anchor_corner.get_bounds(anchor_position, size);
+                let bounds = Bounds::from_corner_and_size(anchor_corner, anchor_position, size);
                 (anchor_position, bounds)
             }
             AnchoredPositionMode::Local => {
                 let anchor_position = anchor_position.unwrap_or_default();
-                let bounds = anchor_corner.get_bounds(bounds.origin + anchor_position, size);
+                let bounds = Bounds::from_corner_and_size(
+                    anchor_corner,
+                    bounds.origin + anchor_position,
+                    size,
+                );
                 (anchor_position, bounds)
             }
         }
     }
 }
-
-/// Which corner of the anchored element should be considered the anchor.
-#[derive(Clone, Copy, PartialEq, Eq)]
-pub enum AnchorCorner {
-    /// The top left corner
-    TopLeft,
-    /// The top right corner
-    TopRight,
-    /// The bottom left corner
-    BottomLeft,
-    /// The bottom right corner
-    BottomRight,
-}
-
-impl AnchorCorner {
-    fn get_bounds(&self, origin: Point<Pixels>, size: Size<Pixels>) -> Bounds<Pixels> {
-        let origin = match self {
-            Self::TopLeft => origin,
-            Self::TopRight => Point {
-                x: origin.x - size.width,
-                y: origin.y,
-            },
-            Self::BottomLeft => Point {
-                x: origin.x,
-                y: origin.y - size.height,
-            },
-            Self::BottomRight => Point {
-                x: origin.x - size.width,
-                y: origin.y - size.height,
-            },
-        };
-
-        Bounds { origin, size }
-    }
-
-    /// Get the point corresponding to this anchor corner in `bounds`.
-    pub fn corner(&self, bounds: Bounds<Pixels>) -> Point<Pixels> {
-        match self {
-            Self::TopLeft => bounds.origin,
-            Self::TopRight => bounds.upper_right(),
-            Self::BottomLeft => bounds.lower_left(),
-            Self::BottomRight => bounds.lower_right(),
-        }
-    }
-
-    fn switch_axis(self, axis: Axis) -> Self {
-        match axis {
-            Axis::Vertical => match self {
-                AnchorCorner::TopLeft => AnchorCorner::BottomLeft,
-                AnchorCorner::TopRight => AnchorCorner::BottomRight,
-                AnchorCorner::BottomLeft => AnchorCorner::TopLeft,
-                AnchorCorner::BottomRight => AnchorCorner::TopRight,
-            },
-            Axis::Horizontal => match self {
-                AnchorCorner::TopLeft => AnchorCorner::TopRight,
-                AnchorCorner::TopRight => AnchorCorner::TopLeft,
-                AnchorCorner::BottomLeft => AnchorCorner::BottomRight,
-                AnchorCorner::BottomRight => AnchorCorner::BottomLeft,
-            },
-        }
-    }
-}

crates/gpui/src/elements/div.rs πŸ”—

@@ -1193,7 +1193,7 @@ impl Element for Div {
             for (ix, child_layout_id) in request_layout.child_layout_ids.iter().enumerate() {
                 let child_bounds = cx.layout_bounds(*child_layout_id);
                 child_min = child_min.min(&child_bounds.origin);
-                child_max = child_max.max(&child_bounds.lower_right());
+                child_max = child_max.max(&child_bounds.bottom_right());
                 state.child_bounds.push(child_bounds);
 
                 if let Some(requested) = requested.as_ref() {
@@ -1208,7 +1208,7 @@ impl Element for Div {
             for child_layout_id in &request_layout.child_layout_ids {
                 let child_bounds = cx.layout_bounds(*child_layout_id);
                 child_min = child_min.min(&child_bounds.origin);
-                child_max = child_max.max(&child_bounds.lower_right());
+                child_max = child_max.max(&child_bounds.bottom_right());
             }
             (child_max - child_min).into()
         };

crates/gpui/src/elements/uniform_list.rs πŸ”—

@@ -219,7 +219,7 @@ impl Element for UniformList {
 
         let padded_bounds = Bounds::from_corners(
             bounds.origin + point(border.left + padding.left, border.top + padding.top),
-            bounds.lower_right()
+            bounds.bottom_right()
                 - point(border.right + padding.right, border.bottom + padding.bottom),
         );
 
@@ -261,7 +261,7 @@ impl Element for UniformList {
 
                 let padded_bounds = Bounds::from_corners(
                     bounds.origin + point(border.left + padding.left, border.top),
-                    bounds.lower_right() - point(border.right + padding.right, border.bottom),
+                    bounds.bottom_right() - point(border.right + padding.right, border.bottom),
                 );
 
                 if let Some(handle) = self.scroll_handle.as_mut() {

crates/gpui/src/geometry.rs πŸ”—

@@ -694,7 +694,7 @@ impl Size<Length> {
 /// Represents a rectangular area in a 2D space with an origin point and a size.
 ///
 /// The `Bounds` struct is generic over a type `T` which represents the type of the coordinate system.
-/// The origin is represented as a `Point<T>` which defines the upper-left corner of the rectangle,
+/// The origin is represented as a `Point<T>` which defines the top left corner of the rectangle,
 /// and the size is represented as a `Size<T>` which defines the width and height of the rectangle.
 ///
 /// # Examples
@@ -757,16 +757,16 @@ impl<T> Bounds<T>
 where
     T: Clone + Debug + Sub<Output = T> + Default,
 {
-    /// Constructs a `Bounds` from two corner points: the upper-left and lower-right corners.
+    /// Constructs a `Bounds` from two corner points: the top left and bottom right corners.
     ///
     /// This function calculates the origin and size of the `Bounds` based on the provided corner points.
-    /// The origin is set to the upper-left corner, and the size is determined by the difference between
-    /// the x and y coordinates of the lower-right and upper-left points.
+    /// The origin is set to the top left corner, and the size is determined by the difference between
+    /// the x and y coordinates of the bottom right and top left points.
     ///
     /// # Arguments
     ///
-    /// * `upper_left` - A `Point<T>` representing the upper-left corner of the rectangle.
-    /// * `lower_right` - A `Point<T>` representing the lower-right corner of the rectangle.
+    /// * `upper_left` - A `Point<T>` representing the top left corner of the rectangle.
+    /// * `bottom_right` - A `Point<T>` representing the bottom right corner of the rectangle.
     ///
     /// # Returns
     ///
@@ -777,25 +777,53 @@ where
     /// ```
     /// # use gpui::{Bounds, Point};
     /// let upper_left = Point { x: 0, y: 0 };
-    /// let lower_right = Point { x: 10, y: 10 };
-    /// let bounds = Bounds::from_corners(upper_left, lower_right);
+    /// let bottom_right = Point { x: 10, y: 10 };
+    /// let bounds = Bounds::from_corners(upper_left, bottom_right);
     ///
     /// assert_eq!(bounds.origin, upper_left);
     /// assert_eq!(bounds.size.width, 10);
     /// assert_eq!(bounds.size.height, 10);
     /// ```
-    pub fn from_corners(upper_left: Point<T>, lower_right: Point<T>) -> Self {
+    pub fn from_corners(upper_left: Point<T>, bottom_right: Point<T>) -> Self {
         let origin = Point {
             x: upper_left.x.clone(),
             y: upper_left.y.clone(),
         };
         let size = Size {
-            width: lower_right.x - upper_left.x,
-            height: lower_right.y - upper_left.y,
+            width: bottom_right.x - upper_left.x,
+            height: bottom_right.y - upper_left.y,
         };
         Bounds { origin, size }
     }
 
+    /// Constructs a `Bounds` from a corner point and size.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use zed::{Bounds, Corner, Point};
+    /// todo!
+    /// ```
+    pub fn from_corner_and_size(corner: Corner, origin: Point<T>, size: Size<T>) -> Bounds<T> {
+        let origin = match corner {
+            Corner::TopLeft => origin,
+            Corner::TopRight => Point {
+                x: origin.x - size.width.clone(),
+                y: origin.y,
+            },
+            Corner::BottomLeft => Point {
+                x: origin.x,
+                y: origin.y - size.height.clone(),
+            },
+            Corner::BottomRight => Point {
+                x: origin.x - size.width.clone(),
+                y: origin.y - size.height.clone(),
+            },
+        };
+
+        Bounds { origin, size }
+    }
+
     /// Creates a new `Bounds` with the specified origin and size.
     ///
     /// # Arguments
@@ -849,8 +877,8 @@ where
     /// assert_eq!(bounds1.intersects(&bounds3), false); // Non-overlapping bounds
     /// ```
     pub fn intersects(&self, other: &Bounds<T>) -> bool {
-        let my_lower_right = self.lower_right();
-        let their_lower_right = other.lower_right();
+        let my_lower_right = self.bottom_right();
+        let their_lower_right = other.bottom_right();
 
         self.origin.x < their_lower_right.x
             && my_lower_right.x > other.origin.x
@@ -996,8 +1024,8 @@ impl<T: Clone + Default + Debug + PartialOrd + Add<T, Output = T> + Sub<Output =
     /// ```
     pub fn intersect(&self, other: &Self) -> Self {
         let upper_left = self.origin.max(&other.origin);
-        let lower_right = self.lower_right().min(&other.lower_right());
-        Self::from_corners(upper_left, lower_right)
+        let bottom_right = self.bottom_right().min(&other.bottom_right());
+        Self::from_corners(upper_left, bottom_right)
     }
 
     /// Computes the union of two `Bounds`.
@@ -1035,7 +1063,7 @@ impl<T: Clone + Default + Debug + PartialOrd + Add<T, Output = T> + Sub<Output =
     /// ```
     pub fn union(&self, other: &Self) -> Self {
         let top_left = self.origin.min(&other.origin);
-        let bottom_right = self.lower_right().max(&other.lower_right());
+        let bottom_right = self.bottom_right().max(&other.bottom_right());
         Bounds::from_corners(top_left, bottom_right)
     }
 }
@@ -1123,11 +1151,11 @@ where
         self.origin.x.clone() + self.size.width.clone()
     }
 
-    /// Returns the upper-right corner point of the bounds.
+    /// Returns the top right corner point of the bounds.
     ///
     /// # Returns
     ///
-    /// A `Point<T>` representing the upper-right corner of the bounds.
+    /// A `Point<T>` representing the top right corner of the bounds.
     ///
     /// # Examples
     ///
@@ -1137,21 +1165,21 @@ where
     ///     origin: Point { x: 0, y: 0 },
     ///     size: Size { width: 10, height: 20 },
     /// };
-    /// let upper_right = bounds.upper_right();
-    /// assert_eq!(upper_right, Point { x: 10, y: 0 });
+    /// let top_right = bounds.top_right();
+    /// assert_eq!(top_right, Point { x: 10, y: 0 });
     /// ```
-    pub fn upper_right(&self) -> Point<T> {
+    pub fn top_right(&self) -> Point<T> {
         Point {
             x: self.origin.x.clone() + self.size.width.clone(),
             y: self.origin.y.clone(),
         }
     }
 
-    /// Returns the lower-right corner point of the bounds.
+    /// Returns the bottom right corner point of the bounds.
     ///
     /// # Returns
     ///
-    /// A `Point<T>` representing the lower-right corner of the bounds.
+    /// A `Point<T>` representing the bottom right corner of the bounds.
     ///
     /// # Examples
     ///
@@ -1161,21 +1189,21 @@ where
     ///     origin: Point { x: 0, y: 0 },
     ///     size: Size { width: 10, height: 20 },
     /// };
-    /// let lower_right = bounds.lower_right();
-    /// assert_eq!(lower_right, Point { x: 10, y: 20 });
+    /// let bottom_right = bounds.bottom_right();
+    /// assert_eq!(bottom_right, Point { x: 10, y: 20 });
     /// ```
-    pub fn lower_right(&self) -> Point<T> {
+    pub fn bottom_right(&self) -> Point<T> {
         Point {
             x: self.origin.x.clone() + self.size.width.clone(),
             y: self.origin.y.clone() + self.size.height.clone(),
         }
     }
 
-    /// Returns the lower-left corner point of the bounds.
+    /// Returns the bottom left corner point of the bounds.
     ///
     /// # Returns
     ///
-    /// A `Point<T>` representing the lower-left corner of the bounds.
+    /// A `Point<T>` representing the bottom left corner of the bounds.
     ///
     /// # Examples
     ///
@@ -1185,15 +1213,41 @@ where
     ///     origin: Point { x: 0, y: 0 },
     ///     size: Size { width: 10, height: 20 },
     /// };
-    /// let lower_left = bounds.lower_left();
-    /// assert_eq!(lower_left, Point { x: 0, y: 20 });
+    /// let bottom_left = bounds.bottom_left();
+    /// assert_eq!(bottom_left, Point { x: 0, y: 20 });
     /// ```
-    pub fn lower_left(&self) -> Point<T> {
+    pub fn bottom_left(&self) -> Point<T> {
         Point {
             x: self.origin.x.clone(),
             y: self.origin.y.clone() + self.size.height.clone(),
         }
     }
+
+    /// Returns the requested corner point of the bounds.
+    ///
+    /// # Returns
+    ///
+    /// A `Point<T>` representing the corner of the bounds requested by the parameter.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use zed::{Bounds, Corner, Point, Size};
+    /// let bounds = Bounds {
+    ///     origin: Point { x: 0, y: 0 },
+    ///     size: Size { width: 10, height: 20 },
+    /// };
+    /// let bottom_left = bounds.corner(Corner::BottomLeft);
+    /// assert_eq!(bottom_left, Point { x: 0, y: 20 });
+    /// ```
+    pub fn corner(&self, corner: Corner) -> Point<T> {
+        match corner {
+            Corner::TopLeft => self.origin.clone(),
+            Corner::TopRight => self.top_right(),
+            Corner::BottomLeft => self.bottom_left(),
+            Corner::BottomRight => self.bottom_right(),
+        }
+    }
 }
 
 impl<T> Bounds<T>
@@ -1861,6 +1915,64 @@ impl From<Pixels> for Edges<Pixels> {
     }
 }
 
+/// Identifies a corner of a 2d box.
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub enum Corner {
+    /// The top left corner
+    TopLeft,
+    /// The top right corner
+    TopRight,
+    /// The bottom left corner
+    BottomLeft,
+    /// The bottom right corner
+    BottomRight,
+}
+
+impl Corner {
+    /// Returns the directly opposite corner.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use zed::Corner;
+    /// assert_eq!(Corner::TopLeft.opposite_corner(), Corner::BottomRight);
+    /// ```
+    pub fn opposite_corner(self) -> Self {
+        match self {
+            Corner::TopLeft => Corner::BottomRight,
+            Corner::TopRight => Corner::BottomLeft,
+            Corner::BottomLeft => Corner::TopRight,
+            Corner::BottomRight => Corner::TopLeft,
+        }
+    }
+
+    /// Returns the corner across from this corner, moving along the specified axis.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use zed::Corner;
+    /// let result = Corner::TopLeft.other_side_corner_along(Axis::Horizontal);
+    /// assert_eq!(result, Corner::TopRight);
+    /// ```
+    pub fn other_side_corner_along(self, axis: Axis) -> Self {
+        match axis {
+            Axis::Vertical => match self {
+                Corner::TopLeft => Corner::BottomLeft,
+                Corner::TopRight => Corner::BottomRight,
+                Corner::BottomLeft => Corner::TopLeft,
+                Corner::BottomRight => Corner::TopRight,
+            },
+            Axis::Horizontal => match self {
+                Corner::TopLeft => Corner::TopRight,
+                Corner::TopRight => Corner::TopLeft,
+                Corner::BottomLeft => Corner::BottomRight,
+                Corner::BottomRight => Corner::BottomLeft,
+            },
+        }
+    }
+}
+
 /// Represents the corners of a box in a 2D space, such as border radius.
 ///
 /// Each field represents the size of the corner on one side of the box: `top_left`, `top_right`, `bottom_right`, and `bottom_left`.
@@ -1914,6 +2026,33 @@ where
             bottom_left: value,
         }
     }
+
+    /// Returns the requested corner.
+    ///
+    /// # Returns
+    ///
+    /// A `Point<T>` representing the corner requested by the parameter.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use zed::{Corner, Corners};
+    /// let corners = Corners {
+    ///     top_left: 1,
+    ///     top_right: 2,
+    ///     bottom_left: 3,
+    ///     bottom_right: 4
+    /// };
+    /// assert_eq!(corners.corner(Corner::BottomLeft), 3);
+    /// ```
+    pub fn corner(&self, corner: Corner) -> T {
+        match corner {
+            Corner::TopLeft => self.top_left.clone(),
+            Corner::TopRight => self.top_right.clone(),
+            Corner::BottomLeft => self.bottom_left.clone(),
+            Corner::BottomRight => self.bottom_right.clone(),
+        }
+    }
 }
 
 impl Corners<AbsoluteLength> {

crates/gpui/src/style.rs πŸ”—

@@ -509,7 +509,7 @@ impl Style {
             } => None,
             _ => {
                 let mut min = bounds.origin;
-                let mut max = bounds.lower_right();
+                let mut max = bounds.bottom_right();
 
                 if self
                     .border_color
@@ -530,12 +530,12 @@ impl Style {
                     // x visible, y hidden
                     (true, false) => Bounds::from_corners(
                         point(min.x, bounds.origin.y),
-                        point(max.x, bounds.lower_right().y),
+                        point(max.x, bounds.bottom_right().y),
                     ),
                     // x hidden, y visible
                     (false, true) => Bounds::from_corners(
                         point(bounds.origin.x, min.y),
-                        point(bounds.lower_right().x, max.y),
+                        point(bounds.bottom_right().x, max.y),
                     ),
                     // both hidden
                     (false, false) => Bounds::from_corners(min, max),
@@ -604,19 +604,19 @@ impl Style {
 
             let top_bounds = Bounds::from_corners(
                 bounds.origin,
-                bounds.upper_right() + point(Pixels::ZERO, max_border_width.max(max_corner_radius)),
+                bounds.top_right() + point(Pixels::ZERO, max_border_width.max(max_corner_radius)),
             );
             let bottom_bounds = Bounds::from_corners(
-                bounds.lower_left() - point(Pixels::ZERO, max_border_width.max(max_corner_radius)),
-                bounds.lower_right(),
+                bounds.bottom_left() - point(Pixels::ZERO, max_border_width.max(max_corner_radius)),
+                bounds.bottom_right(),
             );
             let left_bounds = Bounds::from_corners(
-                top_bounds.lower_left(),
+                top_bounds.bottom_left(),
                 bottom_bounds.origin + point(max_border_width, Pixels::ZERO),
             );
             let right_bounds = Bounds::from_corners(
-                top_bounds.lower_right() - point(max_border_width, Pixels::ZERO),
-                bottom_bounds.upper_right(),
+                top_bounds.bottom_right() - point(max_border_width, Pixels::ZERO),
+                bottom_bounds.top_right(),
             );
 
             let mut background = self.border_color.unwrap_or_default();

crates/inline_completion_button/src/inline_completion_button.rs πŸ”—

@@ -4,7 +4,7 @@ use editor::{scroll::Autoscroll, Editor};
 use feature_flags::{FeatureFlagAppExt, ZetaFeatureFlag};
 use fs::Fs;
 use gpui::{
-    actions, div, Action, AnchorCorner, AppContext, AsyncWindowContext, Entity, IntoElement,
+    actions, div, Action, AppContext, AsyncWindowContext, Corner, Entity, IntoElement,
     ParentElement, Render, Subscription, View, ViewContext, WeakView, WindowContext,
 };
 use language::{
@@ -123,7 +123,7 @@ impl Render for InlineCompletionButton {
                                 _ => this.update(cx, |this, cx| this.build_copilot_start_menu(cx)),
                             })
                         })
-                        .anchor(AnchorCorner::BottomRight)
+                        .anchor(Corner::BottomRight)
                         .trigger(
                             IconButton::new("copilot-icon", icon)
                                 .tooltip(|cx| Tooltip::text("GitHub Copilot", cx)),
@@ -191,7 +191,7 @@ impl Render for InlineCompletionButton {
                             ),
                             _ => None,
                         })
-                        .anchor(AnchorCorner::BottomRight)
+                        .anchor(Corner::BottomRight)
                         .trigger(
                             IconButton::new("supermaven-icon", icon)
                                 .tooltip(move |cx| Tooltip::text(tooltip_text.clone(), cx)),

crates/language_model_selector/src/language_model_selector.rs πŸ”—

@@ -107,7 +107,7 @@ impl<T: PopoverTrigger> RenderOnce for LanguageModelSelectorPopoverMenu<T> {
         PopoverMenu::new("model-switcher")
             .menu(move |_cx| Some(language_model_selector.clone()))
             .trigger(self.trigger)
-            .attach(gpui::AnchorCorner::BottomLeft)
+            .attach(gpui::Corner::BottomLeft)
             .when_some(self.handle.clone(), |menu, handle| menu.with_handle(handle))
     }
 }

crates/language_tools/src/lsp_log.rs πŸ”—

@@ -3,7 +3,7 @@ use copilot::Copilot;
 use editor::{actions::MoveToEnd, Editor, EditorEvent};
 use futures::{channel::mpsc, StreamExt};
 use gpui::{
-    actions, div, AnchorCorner, AppContext, Context, EventEmitter, FocusHandle, FocusableView,
+    actions, div, AppContext, Context, Corner, EventEmitter, FocusHandle, FocusableView,
     IntoElement, Model, ModelContext, ParentElement, Render, Styled, Subscription, View,
     ViewContext, VisualContext, WeakModel, WindowContext,
 };
@@ -1158,7 +1158,7 @@ impl Render for LspLogToolbarItemView {
             .collect();
         let log_toolbar_view = cx.view().clone();
         let lsp_menu = PopoverMenu::new("LspLogView")
-            .anchor(AnchorCorner::TopLeft)
+            .anchor(Corner::TopLeft)
             .trigger(Button::new(
                 "language_server_menu_header",
                 current_server
@@ -1214,7 +1214,7 @@ impl Render for LspLogToolbarItemView {
             let rpc_trace_enabled = server.rpc_trace_enabled;
             let log_view = log_view.clone();
             PopoverMenu::new("LspViewSelector")
-                .anchor(AnchorCorner::TopLeft)
+                .anchor(Corner::TopLeft)
                 .trigger(Button::new(
                     "language_server_menu_header",
                     server.selected_entry.label(),
@@ -1301,7 +1301,7 @@ impl Render for LspLogToolbarItemView {
                             let log_view = log_view.clone();
                             div().child(
                                 PopoverMenu::new("lsp-trace-level-menu")
-                                    .anchor(AnchorCorner::TopLeft)
+                                    .anchor(Corner::TopLeft)
                                     .trigger(Button::new(
                                         "language_server_trace_level_selector",
                                         "Trace level",
@@ -1359,7 +1359,7 @@ impl Render for LspLogToolbarItemView {
                             let log_view = log_view.clone();
                             div().child(
                                 PopoverMenu::new("lsp-log-level-menu")
-                                    .anchor(AnchorCorner::TopLeft)
+                                    .anchor(Corner::TopLeft)
                                     .trigger(Button::new(
                                         "language_server_log_level_selector",
                                         "Log level",

crates/outline_panel/src/outline_panel.rs πŸ”—

@@ -4257,7 +4257,7 @@ impl OutlinePanel {
             deferred(
                 anchored()
                     .position(*position)
-                    .anchor(gpui::AnchorCorner::TopLeft)
+                    .anchor(gpui::Corner::TopLeft)
                     .child(menu.clone()),
             )
             .with_priority(1)

crates/project_panel/src/project_panel.rs πŸ”—

@@ -4102,7 +4102,7 @@ impl Render for ProjectPanel {
                     deferred(
                         anchored()
                             .position(*position)
-                            .anchor(gpui::AnchorCorner::TopLeft)
+                            .anchor(gpui::Corner::TopLeft)
                             .child(menu.clone()),
                     )
                     .with_priority(1)

crates/repl/src/components/kernel_options.rs πŸ”—

@@ -253,7 +253,7 @@ impl<T: PopoverTrigger> RenderOnce for KernelSelector<T> {
         PopoverMenu::new("kernel-switcher")
             .menu(move |_cx| Some(picker_view.clone()))
             .trigger(self.trigger)
-            .attach(gpui::AnchorCorner::BottomLeft)
+            .attach(gpui::Corner::BottomLeft)
             .when_some(self.handle, |menu, handle| menu.with_handle(handle))
     }
 }

crates/terminal/src/terminal.rs πŸ”—

@@ -1461,7 +1461,7 @@ impl Terminal {
     fn drag_line_delta(&self, e: &MouseMoveEvent, region: Bounds<Pixels>) -> Option<Pixels> {
         //TODO: Why do these need to be doubled? Probably the same problem that the IME has
         let top = region.origin.y + (self.last_content.size.line_height * 2.);
-        let bottom = region.lower_left().y - (self.last_content.size.line_height * 2.);
+        let bottom = region.bottom_left().y - (self.last_content.size.line_height * 2.);
         let scroll_delta = if e.position.y < top {
             (top - e.position.y).pow(1.1)
         } else if e.position.y > bottom {

crates/terminal_view/src/terminal_panel.rs πŸ”—

@@ -12,7 +12,7 @@ use collections::HashMap;
 use db::kvp::KEY_VALUE_STORE;
 use futures::future::join_all;
 use gpui::{
-    actions, Action, AnchorCorner, AnyView, AppContext, AsyncWindowContext, Entity, EventEmitter,
+    actions, Action, AnyView, AppContext, AsyncWindowContext, Corner, Entity, EventEmitter,
     ExternalPaths, FocusHandle, FocusableView, IntoElement, Model, ParentElement, Pixels, Render,
     Styled, Task, View, ViewContext, VisualContext, WeakView, WindowContext,
 };
@@ -141,7 +141,7 @@ impl TerminalPanel {
                                     .icon_size(IconSize::Small)
                                     .tooltip(|cx| Tooltip::text("New…", cx)),
                             )
-                            .anchor(AnchorCorner::TopRight)
+                            .anchor(Corner::TopRight)
                             .with_handle(pane.new_item_context_menu_handle.clone())
                             .menu(move |cx| {
                                 let focus_handle = focus_handle.clone();
@@ -171,7 +171,7 @@ impl TerminalPanel {
                                     .icon_size(IconSize::Small)
                                     .tooltip(|cx| Tooltip::text("Split Pane", cx)),
                             )
-                            .anchor(AnchorCorner::TopRight)
+                            .anchor(Corner::TopRight)
                             .with_handle(pane.split_item_context_menu_handle.clone())
                             .menu({
                                 let split_context = split_context.clone();

crates/terminal_view/src/terminal_view.rs πŸ”—

@@ -987,7 +987,7 @@ impl Render for TerminalView {
                 deferred(
                     anchored()
                         .position(*position)
-                        .anchor(gpui::AnchorCorner::TopLeft)
+                        .anchor(gpui::Corner::TopLeft)
                         .child(menu.clone()),
                 )
                 .with_priority(1)

crates/title_bar/src/collab.rs πŸ”—

@@ -73,17 +73,17 @@ fn render_color_ribbon(color: Hsla) -> impl Element {
             let height = bounds.size.height;
             let horizontal_offset = height;
             let vertical_offset = px(height.0 / 2.0);
-            let mut path = Path::new(bounds.lower_left());
+            let mut path = Path::new(bounds.bottom_left());
             path.curve_to(
                 bounds.origin + point(horizontal_offset, vertical_offset),
                 bounds.origin + point(px(0.0), vertical_offset),
             );
-            path.line_to(bounds.upper_right() + point(-horizontal_offset, vertical_offset));
+            path.line_to(bounds.top_right() + point(-horizontal_offset, vertical_offset));
             path.curve_to(
-                bounds.lower_right(),
-                bounds.upper_right() + point(px(0.0), vertical_offset),
+                bounds.bottom_right(),
+                bounds.top_right() + point(px(0.0), vertical_offset),
             );
-            path.line_to(bounds.lower_left());
+            path.line_to(bounds.bottom_left());
             cx.paint_path(path, color);
         },
     )

crates/title_bar/src/title_bar.rs πŸ”—

@@ -615,7 +615,7 @@ impl TitleBar {
                         .style(ButtonStyle::Subtle)
                         .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)),
                 )
-                .anchor(gpui::AnchorCorner::TopRight)
+                .anchor(gpui::Corner::TopRight)
         } else {
             PopoverMenu::new("user-menu")
                 .menu(|cx| {

crates/ui/src/components/dropdown_menu.rs πŸ”—

@@ -1,5 +1,5 @@
 #![allow(missing_docs)]
-use gpui::{AnchorCorner, ClickEvent, CursorStyle, MouseButton, View};
+use gpui::{ClickEvent, Corner, CursorStyle, MouseButton, View};
 
 use crate::{prelude::*, ContextMenu, PopoverMenu};
 
@@ -46,7 +46,7 @@ impl RenderOnce for DropdownMenu {
             .full_width(self.full_width)
             .menu(move |_cx| Some(self.menu.clone()))
             .trigger(DropdownMenuTrigger::new(self.label).full_width(self.full_width))
-            .attach(AnchorCorner::BottomLeft)
+            .attach(Corner::BottomLeft)
     }
 }
 

crates/ui/src/components/popover_menu.rs πŸ”—

@@ -3,10 +3,10 @@
 use std::{cell::RefCell, rc::Rc};
 
 use gpui::{
-    anchored, deferred, div, point, prelude::FluentBuilder, px, size, AnchorCorner, AnyElement,
-    Bounds, DismissEvent, DispatchPhase, Element, ElementId, GlobalElementId, HitboxId,
-    InteractiveElement, IntoElement, LayoutId, Length, ManagedView, MouseDownEvent, ParentElement,
-    Pixels, Point, Style, View, VisualContext, WindowContext,
+    anchored, deferred, div, point, prelude::FluentBuilder, px, size, AnyElement, Bounds, Corner,
+    DismissEvent, DispatchPhase, Element, ElementId, GlobalElementId, HitboxId, InteractiveElement,
+    IntoElement, LayoutId, Length, ManagedView, MouseDownEvent, ParentElement, Pixels, Point,
+    Style, View, VisualContext, WindowContext,
 };
 
 use crate::prelude::*;
@@ -89,8 +89,8 @@ pub struct PopoverMenu<M: ManagedView> {
         >,
     >,
     menu_builder: Option<Rc<dyn Fn(&mut WindowContext) -> Option<View<M>> + 'static>>,
-    anchor: AnchorCorner,
-    attach: Option<AnchorCorner>,
+    anchor: Corner,
+    attach: Option<Corner>,
     offset: Option<Point<Pixels>>,
     trigger_handle: Option<PopoverMenuHandle<M>>,
     full_width: bool,
@@ -103,7 +103,7 @@ impl<M: ManagedView> PopoverMenu<M> {
             id: id.into(),
             child_builder: None,
             menu_builder: None,
-            anchor: AnchorCorner::TopLeft,
+            anchor: Corner::TopLeft,
             attach: None,
             offset: None,
             trigger_handle: None,
@@ -140,13 +140,13 @@ impl<M: ManagedView> PopoverMenu<M> {
 
     /// anchor defines which corner of the menu to anchor to the attachment point
     /// (by default the cursor position, but see attach)
-    pub fn anchor(mut self, anchor: AnchorCorner) -> Self {
+    pub fn anchor(mut self, anchor: Corner) -> Self {
         self.anchor = anchor;
         self
     }
 
     /// attach defines which corner of the handle to attach the menu's anchor to
-    pub fn attach(mut self, attach: AnchorCorner) -> Self {
+    pub fn attach(mut self, attach: Corner) -> Self {
         self.attach = Some(attach);
         self
     }
@@ -157,12 +157,12 @@ impl<M: ManagedView> PopoverMenu<M> {
         self
     }
 
-    fn resolved_attach(&self) -> AnchorCorner {
+    fn resolved_attach(&self) -> Corner {
         self.attach.unwrap_or(match self.anchor {
-            AnchorCorner::TopLeft => AnchorCorner::BottomLeft,
-            AnchorCorner::TopRight => AnchorCorner::BottomRight,
-            AnchorCorner::BottomLeft => AnchorCorner::TopLeft,
-            AnchorCorner::BottomRight => AnchorCorner::TopRight,
+            Corner::TopLeft => Corner::BottomLeft,
+            Corner::TopRight => Corner::BottomRight,
+            Corner::BottomLeft => Corner::TopLeft,
+            Corner::BottomRight => Corner::TopRight,
         })
     }
 
@@ -171,8 +171,8 @@ impl<M: ManagedView> PopoverMenu<M> {
             // Default offset = 4px padding + 1px border
             let offset = rems_from_px(5.) * cx.rem_size();
             match self.anchor {
-                AnchorCorner::TopRight | AnchorCorner::BottomRight => point(offset, px(0.)),
-                AnchorCorner::TopLeft | AnchorCorner::BottomLeft => point(-offset, px(0.)),
+                Corner::TopRight | Corner::BottomRight => point(offset, px(0.)),
+                Corner::TopLeft | Corner::BottomLeft => point(-offset, px(0.)),
             }
         })
     }
@@ -259,7 +259,7 @@ impl<M: ManagedView> Element for PopoverMenu<M> {
                         .anchor(self.anchor);
                     if let Some(child_bounds) = element_state.child_bounds {
                         anchored = anchored.position(
-                            self.resolved_attach().corner(child_bounds) + self.resolved_offset(cx),
+                            child_bounds.corner(self.resolved_attach()) + self.resolved_offset(cx),
                         );
                     }
                     let mut element = deferred(anchored.child(div().occlude().child(menu.clone())))

crates/ui/src/components/right_click_menu.rs πŸ”—

@@ -3,18 +3,17 @@
 use std::{cell::RefCell, rc::Rc};
 
 use gpui::{
-    anchored, deferred, div, px, AnchorCorner, AnyElement, Bounds, DismissEvent, DispatchPhase,
-    Element, ElementId, GlobalElementId, Hitbox, InteractiveElement, IntoElement, LayoutId,
-    ManagedView, MouseButton, MouseDownEvent, ParentElement, Pixels, Point, View, VisualContext,
-    WindowContext,
+    anchored, deferred, div, px, AnyElement, Bounds, Corner, DismissEvent, DispatchPhase, Element,
+    ElementId, GlobalElementId, Hitbox, InteractiveElement, IntoElement, LayoutId, ManagedView,
+    MouseButton, MouseDownEvent, ParentElement, Pixels, Point, View, VisualContext, WindowContext,
 };
 
 pub struct RightClickMenu<M: ManagedView> {
     id: ElementId,
     child_builder: Option<Box<dyn FnOnce(bool) -> AnyElement + 'static>>,
     menu_builder: Option<Rc<dyn Fn(&mut WindowContext) -> View<M> + 'static>>,
-    anchor: Option<AnchorCorner>,
-    attach: Option<AnchorCorner>,
+    anchor: Option<Corner>,
+    attach: Option<Corner>,
 }
 
 impl<M: ManagedView> RightClickMenu<M> {
@@ -30,13 +29,13 @@ impl<M: ManagedView> RightClickMenu<M> {
 
     /// anchor defines which corner of the menu to anchor to the attachment point
     /// (by default the cursor position, but see attach)
-    pub fn anchor(mut self, anchor: AnchorCorner) -> Self {
+    pub fn anchor(mut self, anchor: Corner) -> Self {
         self.anchor = Some(anchor);
         self
     }
 
     /// attach defines which corner of the handle to attach the menu's anchor to
-    pub fn attach(mut self, attach: AnchorCorner) -> Self {
+    pub fn attach(mut self, attach: Corner) -> Self {
         self.attach = Some(attach);
         self
     }
@@ -238,7 +237,7 @@ impl<M: ManagedView> Element for RightClickMenu<M> {
                     *menu.borrow_mut() = Some(new_menu);
                     *position.borrow_mut() = if let Some(child_bounds) = child_bounds {
                         if let Some(attach) = attach {
-                            attach.corner(child_bounds)
+                            child_bounds.corner(attach)
                         } else {
                             cx.mouse_position()
                         }

crates/ui/src/components/scrollbar.rs πŸ”—

@@ -236,12 +236,12 @@ impl Element for Scrollbar {
             let padded_bounds = if is_vertical {
                 Bounds::from_corners(
                     bounds.origin + point(Pixels::ZERO, extra_padding),
-                    bounds.lower_right() - point(Pixels::ZERO, extra_padding * 3),
+                    bounds.bottom_right() - point(Pixels::ZERO, extra_padding * 3),
                 )
             } else {
                 Bounds::from_corners(
                     bounds.origin + point(extra_padding, Pixels::ZERO),
-                    bounds.lower_right() - point(extra_padding * 3, Pixels::ZERO),
+                    bounds.bottom_right() - point(extra_padding * 3, Pixels::ZERO),
                 )
             };
 

crates/ui/src/components/stories/context_menu.rs πŸ”—

@@ -1,4 +1,4 @@
-use gpui::{actions, AnchorCorner, Render, View};
+use gpui::{actions, Corner, Render, View};
 use story::Story;
 
 use crate::prelude::*;
@@ -47,8 +47,8 @@ impl Render for ContextMenuStory {
                     .child(
                         right_click_menu("test1")
                             .trigger(Label::new("BOTTOM LEFT"))
-                            .anchor(AnchorCorner::BottomLeft)
-                            .attach(AnchorCorner::TopLeft)
+                            .anchor(Corner::BottomLeft)
+                            .attach(Corner::TopLeft)
                             .menu(move |cx| build_menu(cx, "bottom left")),
                     ),
             )
@@ -60,14 +60,14 @@ impl Render for ContextMenuStory {
                     .child(
                         right_click_menu("test3")
                             .trigger(Label::new("TOP RIGHT"))
-                            .anchor(AnchorCorner::TopRight)
+                            .anchor(Corner::TopRight)
                             .menu(move |cx| build_menu(cx, "top right")),
                     )
                     .child(
                         right_click_menu("test4")
                             .trigger(Label::new("BOTTOM RIGHT"))
-                            .anchor(AnchorCorner::BottomRight)
-                            .attach(AnchorCorner::TopRight)
+                            .anchor(Corner::BottomRight)
+                            .attach(Corner::TopRight)
                             .menu(move |cx| build_menu(cx, "bottom right")),
                     ),
             )

crates/workspace/src/dock.rs πŸ”—

@@ -3,10 +3,10 @@ use crate::{status_bar::StatusItemView, Workspace};
 use crate::{DraggedDock, Event, Pane};
 use client::proto;
 use gpui::{
-    deferred, div, px, Action, AnchorCorner, AnyView, AppContext, Axis, Entity, EntityId,
-    EventEmitter, FocusHandle, FocusableView, IntoElement, KeyContext, MouseButton, MouseDownEvent,
-    MouseUpEvent, ParentElement, Render, SharedString, StyleRefinement, Styled, Subscription, View,
-    ViewContext, VisualContext, WeakView, WindowContext,
+    deferred, div, px, Action, AnyView, AppContext, Axis, Corner, Entity, EntityId, EventEmitter,
+    FocusHandle, FocusableView, IntoElement, KeyContext, MouseButton, MouseDownEvent, MouseUpEvent,
+    ParentElement, Render, SharedString, StyleRefinement, Styled, Subscription, View, ViewContext,
+    VisualContext, WeakView, WindowContext,
 };
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
@@ -719,10 +719,8 @@ impl Render for PanelButtons {
         let dock_position = dock.position;
 
         let (menu_anchor, menu_attach) = match dock.position {
-            DockPosition::Left => (AnchorCorner::BottomLeft, AnchorCorner::TopLeft),
-            DockPosition::Bottom | DockPosition::Right => {
-                (AnchorCorner::BottomRight, AnchorCorner::TopRight)
-            }
+            DockPosition::Left => (Corner::BottomLeft, Corner::TopLeft),
+            DockPosition::Bottom | DockPosition::Right => (Corner::BottomRight, Corner::TopRight),
         };
 
         let buttons = dock

crates/workspace/src/pane.rs πŸ”—

@@ -14,8 +14,8 @@ use anyhow::Result;
 use collections::{BTreeSet, HashMap, HashSet, VecDeque};
 use futures::{stream::FuturesUnordered, StreamExt};
 use gpui::{
-    actions, anchored, deferred, impl_actions, prelude::*, Action, AnchorCorner, AnyElement,
-    AppContext, AsyncWindowContext, ClickEvent, ClipboardItem, Div, DragMoveEvent, EntityId,
+    actions, anchored, deferred, impl_actions, prelude::*, Action, AnyElement, AppContext,
+    AsyncWindowContext, ClickEvent, ClipboardItem, Corner, Div, DragMoveEvent, EntityId,
     EventEmitter, ExternalPaths, FocusHandle, FocusOutEvent, FocusableView, KeyContext, Model,
     MouseButton, MouseDownEvent, NavigationDirection, Pixels, Point, PromptLevel, Render,
     ScrollHandle, Subscription, Task, View, ViewContext, VisualContext, WeakFocusHandle, WeakView,
@@ -432,7 +432,7 @@ impl Pane {
                                     .icon_size(IconSize::Small)
                                     .tooltip(|cx| Tooltip::text("New...", cx)),
                             )
-                            .anchor(AnchorCorner::TopRight)
+                            .anchor(Corner::TopRight)
                             .with_handle(pane.new_item_context_menu_handle.clone())
                             .menu(move |cx| {
                                 Some(ContextMenu::build(cx, |menu, _| {
@@ -465,7 +465,7 @@ impl Pane {
                                     .icon_size(IconSize::Small)
                                     .tooltip(|cx| Tooltip::text("Split Pane", cx)),
                             )
-                            .anchor(AnchorCorner::TopRight)
+                            .anchor(Corner::TopRight)
                             .with_handle(pane.split_item_context_menu_handle.clone())
                             .menu(move |cx| {
                                 ContextMenu::build(cx, |menu, _| {
@@ -2506,12 +2506,7 @@ impl Pane {
 
     pub fn render_menu_overlay(menu: &View<ContextMenu>) -> Div {
         div().absolute().bottom_0().right_0().size_0().child(
-            deferred(
-                anchored()
-                    .anchor(AnchorCorner::TopRight)
-                    .child(menu.clone()),
-            )
-            .with_priority(1),
+            deferred(anchored().anchor(Corner::TopRight).child(menu.clone())).with_priority(1),
         )
     }
 

crates/workspace/src/pane_group.rs πŸ”—

@@ -758,9 +758,9 @@ impl SplitDirection {
     pub fn edge(&self, rect: Bounds<Pixels>) -> Pixels {
         match self {
             Self::Up => rect.origin.y,
-            Self::Down => rect.lower_left().y,
-            Self::Left => rect.lower_left().x,
-            Self::Right => rect.lower_right().x,
+            Self::Down => rect.bottom_left().y,
+            Self::Left => rect.bottom_left().x,
+            Self::Right => rect.bottom_right().x,
         }
     }
 
@@ -771,7 +771,7 @@ impl SplitDirection {
                 size: size(bounds.size.width, length),
             },
             Self::Down => Bounds {
-                origin: point(bounds.lower_left().x, bounds.lower_left().y - length),
+                origin: point(bounds.bottom_left().x, bounds.bottom_left().y - length),
                 size: size(bounds.size.width, length),
             },
             Self::Left => Bounds {
@@ -779,7 +779,7 @@ impl SplitDirection {
                 size: size(length, bounds.size.height),
             },
             Self::Right => Bounds {
-                origin: point(bounds.lower_right().x - length, bounds.lower_left().y),
+                origin: point(bounds.bottom_right().x - length, bounds.bottom_left().y),
                 size: size(length, bounds.size.height),
             },
         }

crates/zed/src/zed/quick_action_bar.rs πŸ”—

@@ -10,7 +10,7 @@ use editor::actions::{
 };
 use editor::{Editor, EditorSettings};
 use gpui::{
-    Action, AnchorCorner, ClickEvent, ElementId, EventEmitter, FocusHandle, FocusableView,
+    Action, ClickEvent, Corner, ElementId, EventEmitter, FocusHandle, FocusableView,
     InteractiveElement, ParentElement, Render, Styled, Subscription, View, ViewContext, WeakView,
 };
 use search::{buffer_search, BufferSearchBar};
@@ -168,7 +168,7 @@ impl Render for QuickActionBar {
                         }),
                 )
                 .with_handle(self.toggle_selections_handle.clone())
-                .anchor(AnchorCorner::TopRight)
+                .anchor(Corner::TopRight)
                 .menu(move |cx| {
                     let focus = focus.clone();
                     let menu = ContextMenu::build(cx, move |menu, _| {
@@ -217,7 +217,7 @@ impl Render for QuickActionBar {
                             this.tooltip(|cx| Tooltip::text("Editor Controls", cx))
                         }),
                 )
-                .anchor(AnchorCorner::TopRight)
+                .anchor(Corner::TopRight)
                 .with_handle(self.toggle_settings_handle.clone())
                 .menu(move |cx| {
                     let menu = ContextMenu::build(cx, |mut menu, _| {