Skip to content

Commit

Permalink
Misc improvements to Bounds in gpui geometry
Browse files Browse the repository at this point in the history
* Makes `dilate` and `inset` return.

* Implements `Add<Point<T>>` and `Sub<Point<T>>`.

* Makes some trait constraints more precise.
  • Loading branch information
mgsloan committed Dec 17, 2024
1 parent a062c0f commit ebf6804
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 66 deletions.
183 changes: 120 additions & 63 deletions crates/gpui/src/geometry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::{
cmp::{self, PartialOrd},
fmt,
hash::Hash,
ops::{Add, Div, Mul, MulAssign, Sub},
ops::{Add, Div, Mul, MulAssign, Neg, Sub},
};

use crate::{AppContext, DisplayId};
Expand Down Expand Up @@ -753,6 +753,25 @@ impl Bounds<Pixels> {
}
}

impl<T> Bounds<T>
where
T: Clone + Debug + Default,
{
/// Creates a new `Bounds` with the specified origin and size.
///
/// # Arguments
///
/// * `origin` - A `Point<T>` representing the origin of the bounds.
/// * `size` - A `Size<T>` representing the size of the bounds.
///
/// # Returns
///
/// Returns a `Bounds<T>` that has the given origin and size.
pub fn new(origin: Point<T>, size: Size<T>) -> Self {
Bounds { origin, size }
}
}

impl<T> Bounds<T>
where
T: Clone + Debug + Sub<Output = T> + Default,
Expand Down Expand Up @@ -823,25 +842,25 @@ where

Bounds { origin, size }
}
}

/// Creates a new `Bounds` with the specified origin and size.
///
/// # Arguments
///
/// * `origin` - A `Point<T>` representing the origin of the bounds.
/// * `size` - A `Size<T>` representing the size of the bounds.
///
/// # Returns
///
/// Returns a `Bounds<T>` that has the given origin and size.
pub fn new(origin: Point<T>, size: Size<T>) -> Self {
Bounds { origin, size }
impl<T> Bounds<T>
where
T: Clone + Debug + Sub<T, Output = T> + Default + Half,
{
/// Creates a new bounds centered at the given point.
pub fn centered_at(center: Point<T>, size: Size<T>) -> Self {
let origin = Point {
x: center.x - size.width.half(),
y: center.y - size.height.half(),
};
Self::new(origin, size)
}
}

impl<T> Bounds<T>
where
T: Clone + Debug + PartialOrd + Add<T, Output = T> + Sub<Output = T> + Default + Half,
T: Clone + Debug + PartialOrd + Add<T, Output = T> + Default,
{
/// Checks if this `Bounds` intersects with another `Bounds`.
///
Expand Down Expand Up @@ -885,49 +904,12 @@ where
&& self.origin.y < their_lower_right.y
&& my_lower_right.y > other.origin.y
}
}

/// Dilates the bounds by a specified amount in all directions.
///
/// This method expands the bounds by the given `amount`, increasing the size
/// and adjusting the origin so that the bounds grow outwards equally in all directions.
/// The resulting bounds will have its width and height increased by twice the `amount`
/// (since it grows in both directions), and the origin will be moved by `-amount`
/// in both the x and y directions.
///
/// # Arguments
///
/// * `amount` - The amount by which to dilate the bounds.
///
/// # Examples
///
/// ```
/// # use gpui::{Bounds, Point, Size};
/// let mut bounds = Bounds {
/// origin: Point { x: 10, y: 10 },
/// size: Size { width: 10, height: 10 },
/// };
/// bounds.dilate(5);
/// assert_eq!(bounds, Bounds {
/// origin: Point { x: 5, y: 5 },
/// size: Size { width: 20, height: 20 },
/// });
/// ```
pub fn dilate(&mut self, amount: T) {
self.origin.x = self.origin.x.clone() - amount.clone();
self.origin.y = self.origin.y.clone() - amount.clone();
let double_amount = amount.clone() + amount;
self.size.width = self.size.width.clone() + double_amount.clone();
self.size.height = self.size.height.clone() + double_amount;
}

/// inset the bounds by a specified amount
/// Note that this may panic if T does not support negative values
pub fn inset(&self, amount: T) -> Self {
let mut result = self.clone();
result.dilate(T::default() - amount);
result
}

impl<T> Bounds<T>
where
T: Clone + Debug + Add<T, Output = T> + Default + Half,
{
/// Returns the center point of the bounds.
///
/// Calculates the center by taking the origin's x and y coordinates and adding half the width and height
Expand Down Expand Up @@ -955,7 +937,12 @@ where
y: self.origin.y.clone() + self.size.height.clone().half(),
}
}
}

impl<T> Bounds<T>
where
T: Clone + Debug + Add<T, Output = T> + Default,
{
/// Calculates the half perimeter of a rectangle defined by the bounds.
///
/// The half perimeter is calculated as the sum of the width and the height of the rectangle.
Expand All @@ -977,14 +964,56 @@ where
pub fn half_perimeter(&self) -> T {
self.size.width.clone() + self.size.height.clone()
}
}

/// centered_at creates a new bounds centered at the given point.
pub fn centered_at(center: Point<T>, size: Size<T>) -> Self {
let origin = Point {
x: center.x - size.width.half(),
y: center.y - size.height.half(),
};
Self::new(origin, size)
impl<T> Bounds<T>
where
T: Clone + Debug + Add<T, Output = T> + Sub<Output = T> + Default,
{
/// Dilates the bounds by a specified amount in all directions.
///
/// This method expands the bounds by the given `amount`, increasing the size
/// and adjusting the origin so that the bounds grow outwards equally in all directions.
/// The resulting bounds will have its width and height increased by twice the `amount`
/// (since it grows in both directions), and the origin will be moved by `-amount`
/// in both the x and y directions.
///
/// # Arguments
///
/// * `amount` - The amount by which to dilate the bounds.
///
/// # Examples
///
/// ```
/// # use gpui::{Bounds, Point, Size};
/// let mut bounds = Bounds {
/// origin: Point { x: 10, y: 10 },
/// size: Size { width: 10, height: 10 },
/// };
/// bounds.dilate(5);
/// assert_eq!(bounds, Bounds {
/// origin: Point { x: 5, y: 5 },
/// size: Size { width: 20, height: 20 },
/// });
/// ```
pub fn dilate(&self, amount: T) -> Bounds<T> {
let double_amount = amount.clone() + amount.clone();
Bounds {
origin: self.origin.clone() - point(amount.clone(), amount),
size: self.size.clone() + size(double_amount.clone(), double_amount),
}
}
}

impl<T> Bounds<T>
where
T: Clone + Debug + Add<T, Output = T> + Sub<T, Output = T> + Neg<Output = T> + Default,
{
/// Inset the bounds by a specified amount. Equivalent to `dilate` with the amount negated.
///
/// Note that this may panic if T does not support negative values.
pub fn inset(&self, amount: T) -> Self {
self.dilate(-amount)
}
}

Expand Down Expand Up @@ -1111,6 +1140,34 @@ where
}
}

impl<T> Add<Point<T>> for Bounds<T>
where
T: Add<T, Output = T> + Default + Clone + Debug,
{
type Output = Self;

fn add(self, rhs: Point<T>) -> Self {
Self {
origin: self.origin + rhs,
size: self.size,
}
}
}

impl<T> Sub<Point<T>> for Bounds<T>
where
T: Sub<T, Output = T> + Default + Clone + Debug,
{
type Output = Self;

fn sub(self, rhs: Point<T>) -> Self {
Self {
origin: self.origin - rhs,
size: self.size,
}
}
}

impl<T> Bounds<T>
where
T: Add<T, Output = T> + Clone + Default + Debug,
Expand Down
4 changes: 1 addition & 3 deletions crates/gpui/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2281,9 +2281,7 @@ impl<'a> WindowContext<'a> {
let content_mask = self.content_mask();
let opacity = self.element_opacity();
for shadow in shadows {
let mut shadow_bounds = bounds;
shadow_bounds.origin += shadow.offset;
shadow_bounds.dilate(shadow.spread_radius);
let shadow_bounds = (bounds + shadow.offset).dilate(shadow.spread_radius);
self.window.next_frame.scene.insert_primitive(Shadow {
order: 0,
blur_radius: shadow.blur_radius.scale(scale_factor),
Expand Down

0 comments on commit ebf6804

Please sign in to comment.