gpui/geometry.rs
1//! Value types for positions, sizes, bounds, lengths and pixel units.
2//!
3//! The public items are re-exported from the crate root. [`Point`] explains the coordinate
4//! system, and [`Pixels`] explains the difference between logical and device pixels.
5
6use anyhow::{Context as _, anyhow};
7use core::fmt::Debug;
8use derive_more::{Add, AddAssign, Div, DivAssign, Mul, Neg, Sub, SubAssign};
9use refineable::Refineable;
10use schemars::{JsonSchema, json_schema};
11use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
12use std::borrow::Cow;
13use std::ops::{AddAssign, Range};
14use std::{
15 cmp::{self, PartialOrd},
16 f32::consts::GOLDEN_RATIO,
17 fmt::{self, Display},
18 hash::Hash,
19 ops::{Add, Div, Mul, MulAssign, Neg, Sub},
20};
21use taffy::prelude::{TaffyGridLine, TaffyGridSpan};
22
23use crate::{App, DisplayId};
24
25/// An axis of two-dimensional space.
26///
27/// Use an axis with [`Along`] to read or update a [`Point`] or [`Size`] along one direction,
28/// without choosing between `x` and `width` by hand.
29///
30/// # Examples
31///
32/// ```
33/// use gpui::{Along, Axis, px, size};
34///
35/// let size = size(px(100.), px(40.));
36/// assert_eq!(size.along(Axis::Horizontal), px(100.));
37/// assert_eq!(size.along(Axis::Vertical), px(40.));
38/// ```
39#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
40pub enum Axis {
41 /// The vertical axis, running up and down. `y` and `height` belong to it.
42 Vertical,
43 /// The horizontal axis, running left and right. `x` and `width` belong to it.
44 Horizontal,
45}
46
47impl Axis {
48 /// Returns the other axis.
49 ///
50 /// # Examples
51 ///
52 /// ```
53 /// # use gpui::Axis;
54 /// assert_eq!(Axis::Vertical.invert(), Axis::Horizontal);
55 /// assert_eq!(Axis::Horizontal.invert(), Axis::Vertical);
56 /// ```
57 pub fn invert(self) -> Self {
58 match self {
59 Axis::Vertical => Axis::Horizontal,
60 Axis::Horizontal => Axis::Vertical,
61 }
62 }
63}
64
65/// Reads and updates the value along one [`Axis`].
66///
67/// [`Point`] and [`Size`] implement this trait. The horizontal axis is `x` for a point and
68/// `width` for a size. The vertical axis is `y` and `height`.
69///
70/// # Examples
71///
72/// ```
73/// use gpui::{Along, Axis, point, px};
74///
75/// let mut position = point(px(10.), px(20.));
76/// position = position.apply_along(Axis::Vertical, |y| y + px(5.));
77/// assert_eq!(position.along(Axis::Vertical), px(25.));
78/// ```
79pub trait Along {
80 /// The type of the value along each axis.
81 type Unit;
82
83 /// Returns the value along `axis`.
84 fn along(&self, axis: Axis) -> Self::Unit;
85
86 /// Returns a copy with `f` applied to the value along `axis`. The other axis is unchanged.
87 fn apply_along(&self, axis: Axis, f: impl FnOnce(Self::Unit) -> Self::Unit) -> Self;
88}
89
90/// A position or offset in two-dimensional space.
91///
92/// GPUI's coordinate system has its origin at the top left corner of the window. The `x` axis
93/// increases to the right and the `y` axis increases downward, so a larger `y` is lower on the
94/// screen. Coordinates are in logical pixels: `px(1.)` is one logical pixel, which the platform
95/// scales to device pixels for the display. Use [`Pixels`] for positions that the UI lays out.
96///
97/// `Point<T>` works with any `T` that is `Clone`, `Debug`, `Default` and `PartialEq`. The
98/// arithmetic and ordering methods also need `T` to support the matching operators.
99///
100/// [`Bounds`] uses points for its origin. For how positions map onto the layout tree, see
101/// [layout and style](crate::_documentation::concepts::layout_and_style).
102///
103/// # Examples
104///
105/// ```
106/// use gpui::{Point, point, px};
107///
108/// let card = point(px(20.), px(30.));
109/// let offset = point(px(5.), px(-10.));
110/// assert_eq!(card + offset, point(px(25.), px(20.)));
111/// ```
112#[derive(
113 Refineable,
114 Default,
115 Add,
116 AddAssign,
117 Sub,
118 SubAssign,
119 Copy,
120 Debug,
121 PartialEq,
122 Eq,
123 Serialize,
124 Deserialize,
125 JsonSchema,
126 Hash,
127 Neg,
128)]
129#[refineable(Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
130#[repr(C)]
131pub struct Point<T: Clone + Debug + Default + PartialEq> {
132 /// The horizontal coordinate, increasing to the right.
133 pub x: T,
134 /// The vertical coordinate, increasing downward.
135 pub y: T,
136}
137
138/// Creates a [`Point`] from its `x` and `y` coordinates.
139///
140/// Same as [`Point::new`].
141///
142/// # Examples
143///
144/// ```
145/// use gpui::point;
146///
147/// let p = point(10, 20);
148/// assert_eq!(p.x, 10);
149/// assert_eq!(p.y, 20);
150/// ```
151pub const fn point<T: Clone + Debug + Default + PartialEq>(x: T, y: T) -> Point<T> {
152 Point { x, y }
153}
154
155impl<T: Clone + Debug + Default + PartialEq> Point<T> {
156 /// Creates a point from its `x` and `y` coordinates. Same as [`point`].
157 ///
158 /// # Examples
159 ///
160 /// ```
161 /// use gpui::Point;
162 ///
163 /// let p = Point::new(10, 20);
164 /// assert_eq!(p.x, 10);
165 /// assert_eq!(p.y, 20);
166 /// ```
167 pub const fn new(x: T, y: T) -> Self {
168 Self { x, y }
169 }
170
171 /// Returns a new point with `f` applied to both coordinates.
172 ///
173 /// # Examples
174 ///
175 /// ```
176 /// # use gpui::Point;
177 /// let p = Point { x: 3, y: 4 };
178 /// let p_float = p.map(|coord| coord as f32);
179 /// assert_eq!(p_float, Point { x: 3.0, y: 4.0 });
180 /// ```
181 #[must_use]
182 pub fn map<U: Clone + Debug + Default + PartialEq>(&self, f: impl Fn(T) -> U) -> Point<U> {
183 Point {
184 x: f(self.x.clone()),
185 y: f(self.y.clone()),
186 }
187 }
188}
189
190impl<T: Clone + Debug + Default + PartialEq> Along for Point<T> {
191 type Unit = T;
192
193 fn along(&self, axis: Axis) -> T {
194 match axis {
195 Axis::Horizontal => self.x.clone(),
196 Axis::Vertical => self.y.clone(),
197 }
198 }
199
200 fn apply_along(&self, axis: Axis, f: impl FnOnce(T) -> T) -> Point<T> {
201 match axis {
202 Axis::Horizontal => Point {
203 x: f(self.x.clone()),
204 y: self.y.clone(),
205 },
206 Axis::Vertical => Point {
207 x: self.x.clone(),
208 y: f(self.y.clone()),
209 },
210 }
211 }
212}
213
214impl Point<Pixels> {
215 /// Multiplies both coordinates by `factor`, producing [`ScaledPixels`].
216 ///
217 /// Pass the display's scale factor, such as `2.0` on a Retina display, to convert a logical
218 /// position into the scaled space that GPUI draws in.
219 ///
220 /// # Examples
221 ///
222 /// ```
223 /// # use gpui::{Point, Pixels, ScaledPixels};
224 /// let p = Point { x: Pixels::from(10.0), y: Pixels::from(20.0) };
225 /// let scaled_p = p.scale(1.5);
226 /// assert_eq!(scaled_p, Point { x: ScaledPixels::from(15.0), y: ScaledPixels::from(30.0) });
227 /// ```
228 pub fn scale(&self, factor: f32) -> Point<ScaledPixels> {
229 Point {
230 x: self.x.scale(factor),
231 y: self.y.scale(factor),
232 }
233 }
234
235 /// Returns the distance from `(0, 0)` to this point.
236 ///
237 /// The result is an `f64`, not [`Pixels`].
238 ///
239 /// # Examples
240 ///
241 /// ```
242 /// # use gpui::{Pixels, Point};
243 /// let p = Point { x: Pixels::from(3.0), y: Pixels::from(4.0) };
244 /// assert_eq!(p.magnitude(), 5.0);
245 /// ```
246 pub fn magnitude(&self) -> f64 {
247 ((self.x.0.powi(2) + self.y.0.powi(2)) as f64).sqrt()
248 }
249
250 /// Returns `true` if both coordinates differ from `other` by less than `epsilon`.
251 ///
252 /// Use this to compare positions computed with floating point arithmetic. The comparison is
253 /// strict: a difference of exactly `epsilon` returns `false`.
254 ///
255 /// # Examples
256 ///
257 /// ```
258 /// # use gpui::{Pixels, Point};
259 /// let p1 = Point { x: Pixels::from(1.0), y: Pixels::from(1.0) };
260 /// let p2 = Point { x: Pixels::from(3.0), y: Pixels::from(-2.0) };
261 /// assert_eq!(p1.is_nearly_eq(&p2, Pixels::from(4.0)), true);
262 /// ```
263 pub fn is_nearly_eq(&self, other: &Self, epsilon: Pixels) -> bool {
264 let diff = *self - *other;
265 diff.x.abs() < epsilon && diff.y.abs() < epsilon
266 }
267}
268
269impl<T> Point<T>
270where
271 T: Sub<T, Output = T> + Clone + Debug + Default + PartialEq,
272{
273 /// Returns this point's position relative to `origin`.
274 ///
275 /// Subtracts `origin` from both coordinates. [`Bounds::localize`] uses it to convert a point in
276 /// window coordinates into a bounds rectangle's local coordinates.
277 ///
278 /// # Examples
279 ///
280 /// ```
281 /// # use gpui::{Point, point, px};
282 /// let pointer = point(px(150.), px(90.));
283 /// let element_origin = point(px(100.), px(80.));
284 /// assert_eq!(pointer.relative_to(&element_origin), point(px(50.), px(10.)));
285 /// ```
286 pub fn relative_to(&self, origin: &Point<T>) -> Point<T> {
287 point(
288 self.x.clone() - origin.x.clone(),
289 self.y.clone() - origin.y.clone(),
290 )
291 }
292}
293
294impl<T, Rhs> Mul<Rhs> for Point<T>
295where
296 T: Mul<Rhs, Output = T> + Clone + Debug + Default + PartialEq,
297 Rhs: Clone + Debug,
298{
299 type Output = Point<T>;
300
301 fn mul(self, rhs: Rhs) -> Self::Output {
302 Point {
303 x: self.x * rhs.clone(),
304 y: self.y * rhs,
305 }
306 }
307}
308
309impl<T, S> MulAssign<S> for Point<T>
310where
311 T: Mul<S, Output = T> + Clone + Debug + Default + PartialEq,
312 S: Clone,
313{
314 fn mul_assign(&mut self, rhs: S) {
315 self.x = self.x.clone() * rhs.clone();
316 self.y = self.y.clone() * rhs;
317 }
318}
319
320impl<T, S> Div<S> for Point<T>
321where
322 T: Div<S, Output = T> + Clone + Debug + Default + PartialEq,
323 S: Clone,
324{
325 type Output = Self;
326
327 fn div(self, rhs: S) -> Self::Output {
328 Self {
329 x: self.x / rhs.clone(),
330 y: self.y / rhs,
331 }
332 }
333}
334
335impl<T> Point<T>
336where
337 T: PartialOrd + Clone + Debug + Default + PartialEq,
338{
339 /// Returns a point with the larger `x` and the larger `y` of `self` and `other`.
340 ///
341 /// # Examples
342 ///
343 /// ```
344 /// # use gpui::Point;
345 /// let p1 = Point { x: 3, y: 7 };
346 /// let p2 = Point { x: 5, y: 2 };
347 /// assert_eq!(p1.max(&p2), Point { x: 5, y: 7 });
348 /// ```
349 pub fn max(&self, other: &Self) -> Self {
350 Point {
351 x: if self.x > other.x {
352 self.x.clone()
353 } else {
354 other.x.clone()
355 },
356 y: if self.y > other.y {
357 self.y.clone()
358 } else {
359 other.y.clone()
360 },
361 }
362 }
363
364 /// Returns a point with the smaller `x` and the smaller `y` of `self` and `other`.
365 ///
366 /// # Examples
367 ///
368 /// ```
369 /// # use gpui::Point;
370 /// let p1 = Point { x: 3, y: 7 };
371 /// let p2 = Point { x: 5, y: 2 };
372 /// assert_eq!(p1.min(&p2), Point { x: 3, y: 2 });
373 /// ```
374 pub fn min(&self, other: &Self) -> Self {
375 Point {
376 x: if self.x <= other.x {
377 self.x.clone()
378 } else {
379 other.x.clone()
380 },
381 y: if self.y <= other.y {
382 self.y.clone()
383 } else {
384 other.y.clone()
385 },
386 }
387 }
388
389 /// Limits each coordinate to the range from `min` to `max`.
390 ///
391 /// A coordinate below `min` becomes `min`, and a coordinate above `max` becomes `max`. If `min`
392 /// is greater than `max` in a coordinate, that coordinate becomes `max`.
393 ///
394 /// # Examples
395 ///
396 /// ```
397 /// # use gpui::Point;
398 /// let p = Point { x: 10, y: 20 };
399 /// let min = Point { x: 0, y: 5 };
400 /// let max = Point { x: 15, y: 25 };
401 /// assert_eq!(p.clamp(&min, &max), Point { x: 10, y: 20 });
402 ///
403 /// let p_out_of_bounds = Point { x: -5, y: 30 };
404 /// assert_eq!(p_out_of_bounds.clamp(&min, &max), Point { x: 0, y: 25 });
405 /// ```
406 pub fn clamp(&self, min: &Self, max: &Self) -> Self {
407 self.max(min).min(max)
408 }
409}
410
411impl<T: Clone + Debug + Default + PartialEq> Clone for Point<T> {
412 fn clone(&self) -> Self {
413 Self {
414 x: self.x.clone(),
415 y: self.y.clone(),
416 }
417 }
418}
419
420impl<T: Clone + Debug + Default + PartialEq + Display> Display for Point<T> {
421 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
422 write!(f, "({}, {})", self.x, self.y)
423 }
424}
425
426/// A width and height, such as the size of a window or an element.
427///
428/// `Size<Pixels>` holds layout sizes in logical pixels. `Size<Length>` holds style values, which
429/// can also be `auto` or a fraction of the parent. `Size<DevicePixels>` holds whole physical
430/// pixels, such as the size of an image. Construct a size with [`size`].
431///
432/// # Examples
433///
434/// ```
435/// use gpui::{px, size};
436///
437/// let window = size(px(800.), px(600.));
438/// assert_eq!(window.width, px(800.));
439/// assert_eq!(window.height, px(600.));
440/// ```
441#[derive(
442 Add, Clone, Copy, Default, Deserialize, Div, Hash, Neg, PartialEq, Refineable, Serialize, Sub,
443)]
444#[refineable(Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
445#[repr(C)]
446pub struct Size<T: Clone + Debug + Default + PartialEq> {
447 /// The width, along the horizontal axis.
448 pub width: T,
449 /// The height, along the vertical axis.
450 pub height: T,
451}
452
453impl<T: Clone + Debug + Default + PartialEq> Size<T> {
454 /// Creates a size from its width and height. Same as [`size`].
455 ///
456 /// # Examples
457 ///
458 /// ```
459 /// use gpui::Size;
460 ///
461 /// let s = Size::new(10, 20);
462 /// assert_eq!(s.width, 10);
463 /// assert_eq!(s.height, 20);
464 /// ```
465 pub fn new(width: T, height: T) -> Self {
466 size(width, height)
467 }
468}
469
470/// Creates a [`Size`] from its width and height.
471///
472/// Same as [`Size::new`].
473///
474/// # Examples
475///
476/// ```
477/// use gpui::size;
478///
479/// let my_size = size(10, 20);
480/// assert_eq!(my_size.width, 10);
481/// assert_eq!(my_size.height, 20);
482/// ```
483pub const fn size<T>(width: T, height: T) -> Size<T>
484where
485 T: Clone + Debug + Default + PartialEq,
486{
487 Size { width, height }
488}
489
490impl<T> Size<T>
491where
492 T: Clone + Debug + Default + PartialEq,
493{
494 /// Returns a new size with `f` applied to the width and the height.
495 ///
496 /// # Examples
497 ///
498 /// ```
499 /// # use gpui::Size;
500 /// let my_size = Size { width: 10, height: 20 };
501 /// let my_new_size = my_size.map(|dimension| dimension as f32 * 1.5);
502 /// assert_eq!(my_new_size, Size { width: 15.0, height: 30.0 });
503 /// ```
504 pub fn map<U>(&self, f: impl Fn(T) -> U) -> Size<U>
505 where
506 U: Clone + Debug + Default + PartialEq,
507 {
508 Size {
509 width: f(self.width.clone()),
510 height: f(self.height.clone()),
511 }
512 }
513}
514
515impl<T> Size<T>
516where
517 T: Clone + Debug + Default + PartialEq + Half,
518{
519 /// Returns the point at the center of a box of this size, measured from `(0, 0)`.
520 ///
521 /// # Examples
522 ///
523 /// ```
524 /// # use gpui::{point, px, size};
525 /// assert_eq!(size(px(100.), px(40.)).center(), point(px(50.), px(20.)));
526 /// ```
527 pub fn center(&self) -> Point<T> {
528 Point {
529 x: self.width.half(),
530 y: self.height.half(),
531 }
532 }
533
534 /// Returns the point at `anchor` on the edge or corner of a box of this size.
535 ///
536 /// The box's top left corner is `(0, 0)`, so `Anchor::BottomRight` returns the size itself.
537 ///
538 /// # Examples
539 ///
540 /// ```
541 /// # use gpui::{Anchor, point, px, size};
542 /// let s = size(px(100.), px(40.));
543 /// assert_eq!(s.at_anchor(Anchor::BottomCenter), point(px(50.), px(40.)));
544 /// assert_eq!(s.at_anchor(Anchor::BottomRight), point(px(100.), px(40.)));
545 /// ```
546 pub fn at_anchor(&self, anchor: Anchor) -> Point<T> {
547 match anchor {
548 Anchor::TopLeft => Point::new(T::default(), T::default()),
549 Anchor::TopRight => Point::new(self.width.clone(), T::default()),
550 Anchor::BottomLeft => Point::new(T::default(), self.height.clone()),
551 Anchor::BottomRight => Point::new(self.width.clone(), self.height.clone()),
552 Anchor::TopCenter => Point::new(self.width.half(), T::default()),
553 Anchor::BottomCenter => Point::new(self.width.half(), self.height.clone()),
554 Anchor::LeftCenter => Point::new(T::default(), self.height.half()),
555 Anchor::RightCenter => Point::new(self.width.clone(), self.height.half()),
556 }
557 }
558}
559
560impl Size<Pixels> {
561 /// Multiplies the width and height by `factor`, producing [`ScaledPixels`].
562 ///
563 /// # Examples
564 ///
565 /// ```
566 /// # use gpui::{Size, Pixels, ScaledPixels};
567 /// let size = Size { width: Pixels::from(100.0), height: Pixels::from(50.0) };
568 /// let scaled_size = size.scale(2.0);
569 /// assert_eq!(scaled_size, Size { width: ScaledPixels::from(200.0), height: ScaledPixels::from(100.0) });
570 /// ```
571 pub fn scale(&self, factor: f32) -> Size<ScaledPixels> {
572 Size {
573 width: self.width.scale(factor),
574 height: self.height.scale(factor),
575 }
576 }
577}
578
579impl<T> Along for Size<T>
580where
581 T: Clone + Debug + Default + PartialEq,
582{
583 type Unit = T;
584
585 fn along(&self, axis: Axis) -> T {
586 match axis {
587 Axis::Horizontal => self.width.clone(),
588 Axis::Vertical => self.height.clone(),
589 }
590 }
591
592 fn apply_along(&self, axis: Axis, f: impl FnOnce(T) -> T) -> Self {
593 match axis {
594 Axis::Horizontal => Size {
595 width: f(self.width.clone()),
596 height: self.height.clone(),
597 },
598 Axis::Vertical => Size {
599 width: self.width.clone(),
600 height: f(self.height.clone()),
601 },
602 }
603 }
604}
605
606impl<T> Size<T>
607where
608 T: PartialOrd + Clone + Debug + Default + PartialEq,
609{
610 /// Returns a size with the larger width and the larger height of `self` and `other`.
611 ///
612 /// # Examples
613 ///
614 /// ```
615 /// # use gpui::Size;
616 /// let size1 = Size { width: 30, height: 40 };
617 /// let size2 = Size { width: 50, height: 20 };
618 /// assert_eq!(size1.max(&size2), Size { width: 50, height: 40 });
619 /// ```
620 pub fn max(&self, other: &Self) -> Self {
621 Size {
622 width: if self.width >= other.width {
623 self.width.clone()
624 } else {
625 other.width.clone()
626 },
627 height: if self.height >= other.height {
628 self.height.clone()
629 } else {
630 other.height.clone()
631 },
632 }
633 }
634
635 /// Returns a size with the smaller width and the smaller height of `self` and `other`.
636 ///
637 /// # Examples
638 ///
639 /// ```
640 /// # use gpui::Size;
641 /// let size1 = Size { width: 30, height: 40 };
642 /// let size2 = Size { width: 50, height: 20 };
643 /// assert_eq!(size1.min(&size2), Size { width: 30, height: 20 });
644 /// ```
645 pub fn min(&self, other: &Self) -> Self {
646 Size {
647 width: if self.width >= other.width {
648 other.width.clone()
649 } else {
650 self.width.clone()
651 },
652 height: if self.height >= other.height {
653 other.height.clone()
654 } else {
655 self.height.clone()
656 },
657 }
658 }
659}
660
661impl<T, Rhs> Mul<Rhs> for Size<T>
662where
663 T: Mul<Rhs, Output = Rhs> + Clone + Debug + Default + PartialEq,
664 Rhs: Clone + Debug + Default + PartialEq,
665{
666 type Output = Size<Rhs>;
667
668 fn mul(self, rhs: Rhs) -> Self::Output {
669 Size {
670 width: self.width * rhs.clone(),
671 height: self.height * rhs,
672 }
673 }
674}
675
676impl<T, S> MulAssign<S> for Size<T>
677where
678 T: Mul<S, Output = T> + Clone + Debug + Default + PartialEq,
679 S: Clone,
680{
681 fn mul_assign(&mut self, rhs: S) {
682 self.width = self.width.clone() * rhs.clone();
683 self.height = self.height.clone() * rhs;
684 }
685}
686
687impl<T> Eq for Size<T> where T: Eq + Clone + Debug + Default + PartialEq {}
688
689impl<T> Debug for Size<T>
690where
691 T: Clone + Debug + Default + PartialEq,
692{
693 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
694 write!(f, "Size {{ {:?} × {:?} }}", self.width, self.height)
695 }
696}
697
698impl<T: Clone + Debug + Default + PartialEq + Display> Display for Size<T> {
699 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
700 write!(f, "{} × {}", self.width, self.height)
701 }
702}
703
704impl<T: Clone + Debug + Default + PartialEq> From<Point<T>> for Size<T> {
705 fn from(point: Point<T>) -> Self {
706 Self {
707 width: point.x,
708 height: point.y,
709 }
710 }
711}
712
713impl From<Size<Pixels>> for Size<DefiniteLength> {
714 fn from(size: Size<Pixels>) -> Self {
715 Size {
716 width: size.width.into(),
717 height: size.height.into(),
718 }
719 }
720}
721
722impl From<Size<Pixels>> for Size<AbsoluteLength> {
723 fn from(size: Size<Pixels>) -> Self {
724 Size {
725 width: size.width.into(),
726 height: size.height.into(),
727 }
728 }
729}
730
731impl Size<Length> {
732 /// Returns a size whose width and height are both `relative(1.)`, filling the parent.
733 ///
734 /// # Examples
735 ///
736 /// ```
737 /// # use gpui::{DefiniteLength, Length, Size, relative};
738 /// let full = Size::<Length>::full();
739 /// assert_eq!(full.width, Length::Definite(DefiniteLength::from(relative(1.))));
740 /// assert_eq!(full.height, Length::Definite(DefiniteLength::from(relative(1.))));
741 /// ```
742 pub fn full() -> Self {
743 Self {
744 width: relative(1.).into(),
745 height: relative(1.).into(),
746 }
747 }
748}
749
750impl Size<Length> {
751 /// Returns a size whose width and height are both [`Length::Auto`].
752 ///
753 /// With `auto` in both dimensions, layout sizes the element from its content.
754 ///
755 /// # Examples
756 ///
757 /// ```
758 /// # use gpui::{Length, Size};
759 /// let auto = Size::<Length>::auto();
760 /// assert_eq!(auto.width, Length::Auto);
761 /// assert_eq!(auto.height, Length::Auto);
762 /// ```
763 pub fn auto() -> Self {
764 Self {
765 width: Length::Auto,
766 height: Length::Auto,
767 }
768 }
769}
770
771/// A rectangle, defined by its top left corner and its size.
772///
773/// The rectangle covers the area from [`origin`](Bounds::origin) to the bottom right corner.
774/// [`Bounds::contains`] treats the left and top edges as inside and the right and bottom edges
775/// as outside, so adjacent bounds don't overlap. Elements receive their bounds in logical pixels
776/// when they are laid out and painted. See [layout and style](crate::_documentation::concepts::layout_and_style).
777///
778/// # Examples
779///
780/// ```
781/// use gpui::{Bounds, Point, Size};
782///
783/// let bounds = Bounds::new(Point { x: 10, y: 20 }, Size { width: 30, height: 40 });
784/// assert_eq!(bounds.right(), 40);
785/// assert_eq!(bounds.bottom(), 60);
786/// ```
787#[derive(Refineable, Copy, Clone, Default, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
788#[refineable(Debug)]
789#[repr(C)]
790pub struct Bounds<T: Clone + Debug + Default + PartialEq> {
791 /// The top left corner of the rectangle.
792 pub origin: Point<T>,
793 /// The width and height of the rectangle.
794 pub size: Size<T>,
795}
796
797/// Creates [`Bounds`] from an origin and a size.
798///
799/// Same as [`Bounds::new`].
800///
801/// # Examples
802///
803/// ```
804/// use gpui::{bounds, point, px, size};
805///
806/// let b = bounds(point(px(10.), px(10.)), size(px(100.), px(50.)));
807/// assert_eq!(b.right(), px(110.));
808/// assert_eq!(b.bottom(), px(60.));
809/// ```
810pub fn bounds<T: Clone + Debug + Default + PartialEq>(
811 origin: Point<T>,
812 size: Size<T>,
813) -> Bounds<T> {
814 Bounds { origin, size }
815}
816
817impl Bounds<Pixels> {
818 /// Returns bounds of `size` centered on a display.
819 ///
820 /// Uses the display with `display_id`, or the primary display if `display_id` is `None` or
821 /// doesn't match a connected display. If there is no display at all, the bounds start at
822 /// `(0, 0)`.
823 ///
824 /// # Examples
825 ///
826 /// ```
827 /// # use gpui::{Bounds, TestApp, bounds, point, px, size};
828 /// # let app = TestApp::new();
829 /// app.read(|cx| {
830 /// // The test platform has one 1920 by 1080 display.
831 /// let window = Bounds::centered(None, size(px(800.), px(600.)), cx);
832 /// assert_eq!(window, bounds(point(px(560.), px(240.)), size(px(800.), px(600.))));
833 /// });
834 /// ```
835 pub fn centered(display_id: Option<DisplayId>, size: Size<Pixels>, cx: &App) -> Self {
836 let display = display_id
837 .and_then(|id| cx.find_display(id))
838 .or_else(|| cx.primary_display());
839
840 display
841 .map(|display| {
842 let visible_bounds = display.visible_bounds();
843 Bounds::centered_at(visible_bounds.center(), size.min(&visible_bounds.size))
844 })
845 .unwrap_or_else(|| Bounds {
846 origin: point(px(0.), px(0.)),
847 size,
848 })
849 }
850
851 /// Returns bounds that cover a display.
852 ///
853 /// Uses the display with `display_id`, or the primary display if `display_id` is `None` or
854 /// doesn't match a connected display. If there is no display at all, returns 1024 by 768
855 /// pixels at `(0, 0)`.
856 ///
857 /// # Examples
858 ///
859 /// ```
860 /// # use gpui::{Bounds, TestApp, bounds, point, px, size};
861 /// # let app = TestApp::new();
862 /// app.read(|cx| {
863 /// // The test platform has one 1920 by 1080 display.
864 /// let screen = Bounds::maximized(None, cx);
865 /// assert_eq!(screen, bounds(point(px(0.), px(0.)), size(px(1920.), px(1080.))));
866 /// });
867 /// ```
868 pub fn maximized(display_id: Option<DisplayId>, cx: &App) -> Self {
869 let display = display_id
870 .and_then(|id| cx.find_display(id))
871 .or_else(|| cx.primary_display());
872
873 display
874 .map(|display| display.bounds())
875 .unwrap_or_else(|| Bounds {
876 origin: point(px(0.), px(0.)),
877 size: size(px(1024.), px(768.)),
878 })
879 }
880}
881
882impl<T> Bounds<T>
883where
884 T: Clone + Debug + Default + PartialEq,
885{
886 /// Creates bounds from an origin and a size. Same as [`bounds`].
887 ///
888 /// # Examples
889 ///
890 /// ```
891 /// # use gpui::{Bounds, Point, Size};
892 /// let b = Bounds::new(Point { x: 0, y: 0 }, Size { width: 10, height: 20 });
893 /// assert_eq!(b.size.height, 20);
894 /// ```
895 pub fn new(origin: Point<T>, size: Size<T>) -> Self {
896 Bounds { origin, size }
897 }
898}
899
900impl<T> Bounds<T>
901where
902 T: Sub<Output = T> + Clone + Debug + Default + PartialEq,
903{
904 /// Creates bounds from its top left and bottom right corners.
905 ///
906 /// The size is `bottom_right - top_left` and is not clamped. A `bottom_right` above or to the
907 /// left of `top_left` gives a negative width or height, which [`Bounds::is_empty`] reports as
908 /// empty.
909 ///
910 /// # Examples
911 ///
912 /// ```
913 /// # use gpui::{Bounds, Point};
914 /// let top_left = Point { x: 0, y: 0 };
915 /// let bottom_right = Point { x: 10, y: 10 };
916 /// let bounds = Bounds::from_corners(top_left, bottom_right);
917 ///
918 /// assert_eq!(bounds.origin, top_left);
919 /// assert_eq!(bounds.size.width, 10);
920 /// assert_eq!(bounds.size.height, 10);
921 /// ```
922 pub fn from_corners(top_left: Point<T>, bottom_right: Point<T>) -> Self {
923 let origin = Point {
924 x: top_left.x.clone(),
925 y: top_left.y.clone(),
926 };
927 let size = Size {
928 width: bottom_right.x - top_left.x,
929 height: bottom_right.y - top_left.y,
930 };
931 Bounds { origin, size }
932 }
933}
934
935impl<T> Bounds<T>
936where
937 T: Sub<Output = T> + Half + Clone + Debug + Default + PartialEq,
938{
939 /// Creates bounds of `size` whose `corner` sits at `origin`.
940 ///
941 /// Use this to place a box by one of its corners or edge centers: the box's top left corner is
942 /// `origin` minus the offset of `corner` within the size.
943 ///
944 /// # Examples
945 ///
946 /// ```
947 /// # use gpui::{Anchor, Bounds, point, px, size};
948 /// let b = Bounds::from_anchor_and_size(
949 /// Anchor::BottomRight,
950 /// point(px(10.), px(10.)),
951 /// size(px(4.), px(2.)),
952 /// );
953 /// assert_eq!(b.origin, point(px(6.), px(8.)));
954 /// assert_eq!(b.bottom_right(), point(px(10.), px(10.)));
955 /// ```
956 pub fn from_anchor_and_size(corner: Anchor, origin: Point<T>, size: Size<T>) -> Bounds<T> {
957 let origin = origin - size.at_anchor(corner);
958 Bounds { origin, size }
959 }
960}
961
962impl<T> Bounds<T>
963where
964 T: Sub<T, Output = T> + Half + Clone + Debug + Default + PartialEq,
965{
966 /// Creates bounds of `size` centered on `center`.
967 ///
968 /// # Examples
969 ///
970 /// ```
971 /// # use gpui::{Bounds, point, px, size};
972 /// let b = Bounds::centered_at(point(px(50.), px(50.)), size(px(20.), px(10.)));
973 /// assert_eq!(b.origin, point(px(40.), px(45.)));
974 /// assert_eq!(b.center(), point(px(50.), px(50.)));
975 /// ```
976 pub fn centered_at(center: Point<T>, size: Size<T>) -> Self {
977 let origin = Point {
978 x: center.x - size.width.half(),
979 y: center.y - size.height.half(),
980 };
981 Self::new(origin, size)
982 }
983}
984
985impl<T> Bounds<T>
986where
987 T: Add<T, Output = T> + Half + Clone + Debug + Default + PartialEq,
988{
989 /// Returns the midpoint of the top edge.
990 ///
991 /// # Examples
992 ///
993 /// ```
994 /// # use gpui::{Bounds, Point, Size};
995 /// let bounds = Bounds {
996 /// origin: Point { x: 0, y: 0 },
997 /// size: Size { width: 10, height: 20 },
998 /// };
999 /// assert_eq!(bounds.top_center(), Point { x: 5, y: 0 });
1000 /// ```
1001 pub fn top_center(&self) -> Point<T> {
1002 Point {
1003 x: self.origin.x.clone() + self.size.width.half(),
1004 y: self.origin.y.clone(),
1005 }
1006 }
1007
1008 /// Returns the midpoint of the bottom edge.
1009 ///
1010 /// # Examples
1011 ///
1012 /// ```
1013 /// # use gpui::{Bounds, Point, Size};
1014 /// let bounds = Bounds {
1015 /// origin: Point { x: 0, y: 0 },
1016 /// size: Size { width: 10, height: 20 },
1017 /// };
1018 /// assert_eq!(bounds.bottom_center(), Point { x: 5, y: 20 });
1019 /// ```
1020 pub fn bottom_center(&self) -> Point<T> {
1021 Point {
1022 x: self.origin.x.clone() + self.size.width.half(),
1023 y: self.origin.y.clone() + self.size.height.clone(),
1024 }
1025 }
1026
1027 /// Returns the midpoint of the left edge.
1028 ///
1029 /// # Examples
1030 ///
1031 /// ```
1032 /// # use gpui::{Bounds, Point, Size};
1033 /// let bounds = Bounds {
1034 /// origin: Point { x: 0, y: 0 },
1035 /// size: Size { width: 10, height: 20 },
1036 /// };
1037 /// assert_eq!(bounds.left_center(), Point { x: 0, y: 10 });
1038 /// ```
1039 pub fn left_center(&self) -> Point<T> {
1040 Point {
1041 x: self.origin.x.clone(),
1042 y: self.origin.y.clone() + self.size.height.half(),
1043 }
1044 }
1045
1046 /// Returns the midpoint of the right edge.
1047 ///
1048 /// # Examples
1049 ///
1050 /// ```
1051 /// # use gpui::{Bounds, Point, Size};
1052 /// let bounds = Bounds {
1053 /// origin: Point { x: 0, y: 0 },
1054 /// size: Size { width: 10, height: 20 },
1055 /// };
1056 /// assert_eq!(bounds.right_center(), Point { x: 10, y: 10 });
1057 /// ```
1058 pub fn right_center(&self) -> Point<T> {
1059 Point {
1060 x: self.origin.x.clone() + self.size.width.clone(),
1061 y: self.origin.y.clone() + self.size.height.half(),
1062 }
1063 }
1064}
1065
1066impl<T> Bounds<T>
1067where
1068 T: PartialOrd + Add<T, Output = T> + Clone + Debug + Default + PartialEq,
1069{
1070 /// Returns `true` if this rectangle and `other` share some area.
1071 ///
1072 /// Bounds that only touch along an edge don't intersect.
1073 ///
1074 /// # Examples
1075 ///
1076 /// ```
1077 /// # use gpui::{Bounds, Point, Size};
1078 /// let bounds1 = Bounds {
1079 /// origin: Point { x: 0, y: 0 },
1080 /// size: Size { width: 10, height: 10 },
1081 /// };
1082 /// let bounds2 = Bounds {
1083 /// origin: Point { x: 5, y: 5 },
1084 /// size: Size { width: 10, height: 10 },
1085 /// };
1086 /// let bounds3 = Bounds {
1087 /// origin: Point { x: 20, y: 20 },
1088 /// size: Size { width: 10, height: 10 },
1089 /// };
1090 ///
1091 /// assert_eq!(bounds1.intersects(&bounds2), true);
1092 /// assert_eq!(bounds1.intersects(&bounds3), false);
1093 /// ```
1094 pub fn intersects(&self, other: &Bounds<T>) -> bool {
1095 let my_lower_right = self.bottom_right();
1096 let their_lower_right = other.bottom_right();
1097
1098 self.origin.x < their_lower_right.x
1099 && my_lower_right.x > other.origin.x
1100 && self.origin.y < their_lower_right.y
1101 && my_lower_right.y > other.origin.y
1102 }
1103}
1104
1105impl<T> Bounds<T>
1106where
1107 T: Add<T, Output = T> + Half + Clone + Debug + Default + PartialEq,
1108{
1109 /// Returns the center point of the bounds.
1110 ///
1111 /// # Examples
1112 ///
1113 /// ```
1114 /// # use gpui::{Bounds, Point, Size};
1115 /// let bounds = Bounds {
1116 /// origin: Point { x: 0, y: 0 },
1117 /// size: Size { width: 10, height: 20 },
1118 /// };
1119 /// assert_eq!(bounds.center(), Point { x: 5, y: 10 });
1120 /// ```
1121 pub fn center(&self) -> Point<T> {
1122 Point {
1123 x: self.origin.x.clone() + self.size.width.clone().half(),
1124 y: self.origin.y.clone() + self.size.height.clone().half(),
1125 }
1126 }
1127}
1128
1129impl<T> Bounds<T>
1130where
1131 T: Add<T, Output = T> + Clone + Debug + Default + PartialEq,
1132{
1133 /// Returns the width plus the height.
1134 ///
1135 /// The perimeter of the bounds is twice this value.
1136 ///
1137 /// # Examples
1138 ///
1139 /// ```
1140 /// # use gpui::{Bounds, Point, Size};
1141 /// let bounds = Bounds {
1142 /// origin: Point { x: 0, y: 0 },
1143 /// size: Size { width: 10, height: 20 },
1144 /// };
1145 /// assert_eq!(bounds.half_perimeter(), 30);
1146 /// ```
1147 pub fn half_perimeter(&self) -> T {
1148 self.size.width.clone() + self.size.height.clone()
1149 }
1150}
1151
1152impl<T> Bounds<T>
1153where
1154 T: Add<T, Output = T> + Sub<Output = T> + Clone + Debug + Default + PartialEq,
1155{
1156 /// Returns the bounds grown by `amount` on every side.
1157 ///
1158 /// The origin moves by `-amount` and the width and height grow by twice `amount`, so the
1159 /// center stays in place. A negative `amount` shrinks the bounds. Use [`Bounds::inset`] to
1160 /// shrink by a positive amount.
1161 ///
1162 /// # Examples
1163 ///
1164 /// ```
1165 /// # use gpui::{Bounds, Point, Size};
1166 /// let bounds = Bounds {
1167 /// origin: Point { x: 10, y: 10 },
1168 /// size: Size { width: 10, height: 10 },
1169 /// };
1170 /// assert_eq!(bounds.dilate(5), Bounds {
1171 /// origin: Point { x: 5, y: 5 },
1172 /// size: Size { width: 20, height: 20 },
1173 /// });
1174 /// ```
1175 #[must_use]
1176 pub fn dilate(&self, amount: T) -> Bounds<T> {
1177 let double_amount = amount.clone() + amount.clone();
1178 Bounds {
1179 origin: self.origin.clone() - point(amount.clone(), amount),
1180 size: self.size.clone() + size(double_amount.clone(), double_amount),
1181 }
1182 }
1183
1184 /// Returns the bounds grown by a different amount on each side.
1185 ///
1186 /// Each side of `amount` moves the matching edge outward: `top` grows upward, `right` grows to
1187 /// the right, and so on.
1188 ///
1189 /// # Examples
1190 ///
1191 /// ```
1192 /// # use gpui::{Bounds, Edges, Point, Size};
1193 /// let bounds = Bounds {
1194 /// origin: Point { x: 10, y: 10 },
1195 /// size: Size { width: 10, height: 10 },
1196 /// };
1197 /// let amount = Edges { top: 1, right: 2, bottom: 3, left: 4 };
1198 /// assert_eq!(bounds.extend(amount), Bounds {
1199 /// origin: Point { x: 6, y: 9 },
1200 /// size: Size { width: 16, height: 14 },
1201 /// });
1202 /// ```
1203 #[must_use]
1204 pub fn extend(&self, amount: Edges<T>) -> Bounds<T> {
1205 Bounds {
1206 origin: self.origin.clone() - point(amount.left.clone(), amount.top.clone()),
1207 size: self.size.clone()
1208 + size(
1209 amount.left.clone() + amount.right.clone(),
1210 amount.top.clone() + amount.bottom,
1211 ),
1212 }
1213 }
1214}
1215
1216impl<T> Bounds<T>
1217where
1218 T: Add<T, Output = T>
1219 + Sub<T, Output = T>
1220 + Neg<Output = T>
1221 + Clone
1222 + Debug
1223 + Default
1224 + PartialEq,
1225{
1226 /// Returns the bounds shrunk by `amount` on every side.
1227 ///
1228 /// Same as [`Bounds::dilate`] with `amount` negated.
1229 ///
1230 /// # Examples
1231 ///
1232 /// ```
1233 /// # use gpui::{Bounds, Point, Size};
1234 /// let bounds = Bounds {
1235 /// origin: Point { x: 0.0, y: 0.0 },
1236 /// size: Size { width: 10.0, height: 10.0 },
1237 /// };
1238 /// assert_eq!(bounds.inset(2.0), Bounds {
1239 /// origin: Point { x: 2.0, y: 2.0 },
1240 /// size: Size { width: 6.0, height: 6.0 },
1241 /// });
1242 /// ```
1243 pub fn inset(&self, amount: T) -> Self {
1244 self.dilate(-amount)
1245 }
1246}
1247
1248impl<T: PartialOrd + Add<T, Output = T> + Sub<Output = T> + Clone + Debug + Default + PartialEq>
1249 Bounds<T>
1250{
1251 /// Returns the area that this rectangle and `other` share.
1252 ///
1253 /// If the bounds don't overlap, the result has zero width or zero height. Its origin is then
1254 /// the larger of the two origins in each coordinate, which may lie outside both bounds.
1255 ///
1256 /// # Examples
1257 ///
1258 /// ```
1259 /// # use gpui::{Bounds, Point, Size};
1260 /// let bounds1 = Bounds {
1261 /// origin: Point { x: 0, y: 0 },
1262 /// size: Size { width: 10, height: 10 },
1263 /// };
1264 /// let bounds2 = Bounds {
1265 /// origin: Point { x: 5, y: 5 },
1266 /// size: Size { width: 10, height: 10 },
1267 /// };
1268 /// assert_eq!(bounds1.intersect(&bounds2), Bounds {
1269 /// origin: Point { x: 5, y: 5 },
1270 /// size: Size { width: 5, height: 5 },
1271 /// });
1272 /// ```
1273 pub fn intersect(&self, other: &Self) -> Self {
1274 let upper_left = self.origin.max(&other.origin);
1275 let bottom_right = self
1276 .bottom_right()
1277 .min(&other.bottom_right())
1278 .max(&upper_left);
1279 Self::from_corners(upper_left, bottom_right)
1280 }
1281
1282 /// Returns the smallest bounds that contain both rectangles.
1283 ///
1284 /// # Examples
1285 ///
1286 /// ```
1287 /// # use gpui::{Bounds, Point, Size};
1288 /// let bounds1 = Bounds {
1289 /// origin: Point { x: 0, y: 0 },
1290 /// size: Size { width: 10, height: 10 },
1291 /// };
1292 /// let bounds2 = Bounds {
1293 /// origin: Point { x: 5, y: 5 },
1294 /// size: Size { width: 15, height: 15 },
1295 /// };
1296 /// assert_eq!(bounds1.union(&bounds2), Bounds {
1297 /// origin: Point { x: 0, y: 0 },
1298 /// size: Size { width: 20, height: 20 },
1299 /// });
1300 /// ```
1301 pub fn union(&self, other: &Self) -> Self {
1302 let top_left = self.origin.min(&other.origin);
1303 let bottom_right = self.bottom_right().max(&other.bottom_right());
1304 Bounds::from_corners(top_left, bottom_right)
1305 }
1306}
1307
1308impl<T> Bounds<T>
1309where
1310 T: Add<T, Output = T> + Sub<T, Output = T> + Clone + Debug + Default + PartialEq,
1311{
1312 /// Returns the distance from each edge of this rectangle to the matching edge of `outer`.
1313 ///
1314 /// A positive value means this rectangle lies inside `outer` on that side. A negative value means
1315 /// it extends past `outer`.
1316 ///
1317 /// # Examples
1318 ///
1319 /// ```
1320 /// # use gpui::{Bounds, Edges, Point, Size};
1321 /// let outer = Bounds {
1322 /// origin: Point { x: 0, y: 0 },
1323 /// size: Size { width: 100, height: 100 },
1324 /// };
1325 /// let inner = Bounds {
1326 /// origin: Point { x: 10, y: 20 },
1327 /// size: Size { width: 30, height: 40 },
1328 /// };
1329 /// assert_eq!(inner.space_within(&outer), Edges { top: 20, right: 60, bottom: 40, left: 10 });
1330 /// ```
1331 pub fn space_within(&self, outer: &Self) -> Edges<T> {
1332 Edges {
1333 top: self.top() - outer.top(),
1334 right: outer.right() - self.right(),
1335 bottom: outer.bottom() - self.bottom(),
1336 left: self.left() - outer.left(),
1337 }
1338 }
1339}
1340
1341impl<T, Rhs> Mul<Rhs> for Bounds<T>
1342where
1343 T: Mul<Rhs, Output = Rhs> + Clone + Debug + Default + PartialEq,
1344 Point<T>: Mul<Rhs, Output = Point<Rhs>>,
1345 Rhs: Clone + Debug + Default + PartialEq,
1346{
1347 type Output = Bounds<Rhs>;
1348
1349 fn mul(self, rhs: Rhs) -> Self::Output {
1350 Bounds {
1351 origin: self.origin * rhs.clone(),
1352 size: self.size * rhs,
1353 }
1354 }
1355}
1356
1357impl<T, S> MulAssign<S> for Bounds<T>
1358where
1359 T: Mul<S, Output = T> + Clone + Debug + Default + PartialEq,
1360 S: Clone,
1361{
1362 fn mul_assign(&mut self, rhs: S) {
1363 self.origin *= rhs.clone();
1364 self.size *= rhs;
1365 }
1366}
1367
1368impl<T, S> Div<S> for Bounds<T>
1369where
1370 Size<T>: Div<S, Output = Size<T>>,
1371 T: Div<S, Output = T> + Clone + Debug + Default + PartialEq,
1372 S: Clone,
1373{
1374 type Output = Self;
1375
1376 fn div(self, rhs: S) -> Self {
1377 Self {
1378 origin: self.origin / rhs.clone(),
1379 size: self.size / rhs,
1380 }
1381 }
1382}
1383
1384impl<T> Add<Point<T>> for Bounds<T>
1385where
1386 T: Add<T, Output = T> + Clone + Debug + Default + PartialEq,
1387{
1388 type Output = Self;
1389
1390 fn add(self, rhs: Point<T>) -> Self {
1391 Self {
1392 origin: self.origin + rhs,
1393 size: self.size,
1394 }
1395 }
1396}
1397
1398impl<T> Sub<Point<T>> for Bounds<T>
1399where
1400 T: Sub<T, Output = T> + Clone + Debug + Default + PartialEq,
1401{
1402 type Output = Self;
1403
1404 fn sub(self, rhs: Point<T>) -> Self {
1405 Self {
1406 origin: self.origin - rhs,
1407 size: self.size,
1408 }
1409 }
1410}
1411
1412impl<T: Clone + Debug + Default + PartialEq> From<Size<T>> for Point<T> {
1413 fn from(size: Size<T>) -> Self {
1414 Self {
1415 x: size.width,
1416 y: size.height,
1417 }
1418 }
1419}
1420
1421impl<T> Bounds<T>
1422where
1423 T: Add<T, Output = T> + Clone + Debug + Default + PartialEq,
1424{
1425 /// Returns the y coordinate of the top edge.
1426 pub fn top(&self) -> T {
1427 self.origin.y.clone()
1428 }
1429
1430 /// Returns the y coordinate of the bottom edge, which is outside the bounds.
1431 pub fn bottom(&self) -> T {
1432 self.origin.y.clone() + self.size.height.clone()
1433 }
1434
1435 /// Returns the x coordinate of the left edge.
1436 pub fn left(&self) -> T {
1437 self.origin.x.clone()
1438 }
1439
1440 /// Returns the x coordinate of the right edge, which is outside the bounds.
1441 pub fn right(&self) -> T {
1442 self.origin.x.clone() + self.size.width.clone()
1443 }
1444
1445 /// Returns the top right corner point of the bounds.
1446 ///
1447 /// # Examples
1448 ///
1449 /// ```
1450 /// # use gpui::{Bounds, Point, Size};
1451 /// let bounds = Bounds {
1452 /// origin: Point { x: 0, y: 0 },
1453 /// size: Size { width: 10, height: 20 },
1454 /// };
1455 /// assert_eq!(bounds.top_right(), Point { x: 10, y: 0 });
1456 /// ```
1457 pub fn top_right(&self) -> Point<T> {
1458 Point {
1459 x: self.origin.x.clone() + self.size.width.clone(),
1460 y: self.origin.y.clone(),
1461 }
1462 }
1463
1464 /// Returns the bottom right corner point of the bounds.
1465 ///
1466 /// This point is outside the bounds: [`Bounds::contains`] returns `false` for it.
1467 ///
1468 /// # Examples
1469 ///
1470 /// ```
1471 /// # use gpui::{Bounds, Point, Size};
1472 /// let bounds = Bounds {
1473 /// origin: Point { x: 0, y: 0 },
1474 /// size: Size { width: 10, height: 20 },
1475 /// };
1476 /// assert_eq!(bounds.bottom_right(), Point { x: 10, y: 20 });
1477 /// ```
1478 pub fn bottom_right(&self) -> Point<T> {
1479 Point {
1480 x: self.origin.x.clone() + self.size.width.clone(),
1481 y: self.origin.y.clone() + self.size.height.clone(),
1482 }
1483 }
1484
1485 /// Returns the bottom left corner point of the bounds.
1486 ///
1487 /// # Examples
1488 ///
1489 /// ```
1490 /// # use gpui::{Bounds, Point, Size};
1491 /// let bounds = Bounds {
1492 /// origin: Point { x: 0, y: 0 },
1493 /// size: Size { width: 10, height: 20 },
1494 /// };
1495 /// assert_eq!(bounds.bottom_left(), Point { x: 0, y: 20 });
1496 /// ```
1497 pub fn bottom_left(&self) -> Point<T> {
1498 Point {
1499 x: self.origin.x.clone(),
1500 y: self.origin.y.clone() + self.size.height.clone(),
1501 }
1502 }
1503}
1504
1505impl<T> Bounds<T>
1506where
1507 T: Add<T, Output = T> + Half + Clone + Debug + Default + PartialEq,
1508{
1509 /// Returns the point at `corner` on this rectangle.
1510 ///
1511 /// Accepts the four corners and the four edge midpoints.
1512 ///
1513 /// # Examples
1514 ///
1515 /// ```
1516 /// use gpui::{Anchor, Bounds, Point, Size};
1517 /// let bounds = Bounds {
1518 /// origin: Point { x: 0, y: 0 },
1519 /// size: Size { width: 10, height: 20 },
1520 /// };
1521 /// assert_eq!(bounds.corner(Anchor::BottomLeft), Point { x: 0, y: 20 });
1522 /// ```
1523 pub fn corner(&self, corner: Anchor) -> Point<T> {
1524 match corner {
1525 Anchor::TopLeft => self.origin.clone(),
1526 Anchor::TopRight => self.top_right(),
1527 Anchor::BottomLeft => self.bottom_left(),
1528 Anchor::BottomRight => self.bottom_right(),
1529 Anchor::TopCenter => self.top_center(),
1530 Anchor::BottomCenter => self.bottom_center(),
1531 Anchor::LeftCenter => self.left_center(),
1532 Anchor::RightCenter => self.right_center(),
1533 }
1534 }
1535}
1536
1537impl<T> Bounds<T>
1538where
1539 T: Add<T, Output = T> + PartialOrd + Clone + Debug + Default + PartialEq,
1540{
1541 /// Returns `true` if `point` lies inside the bounds.
1542 ///
1543 /// The left and top edges are inside, and the right and bottom edges are outside. A point at
1544 /// `(right, y)` or `(x, bottom)` returns `false`. With integer coordinates, a rectangle of
1545 /// width 10 at `x = 0` contains `x = 0` through `x = 9` only.
1546 ///
1547 /// # Examples
1548 ///
1549 /// ```
1550 /// # use gpui::{Bounds, Point, Size};
1551 /// let bounds = Bounds {
1552 /// origin: Point { x: 0, y: 0 },
1553 /// size: Size { width: 10, height: 10 },
1554 /// };
1555 /// assert!(bounds.contains(&Point { x: 5, y: 5 }));
1556 /// assert!(bounds.contains(&Point { x: 0, y: 0 }));
1557 /// assert!(!bounds.contains(&Point { x: 10, y: 5 }));
1558 /// assert!(!bounds.contains(&Point { x: 15, y: 15 }));
1559 /// ```
1560 pub fn contains(&self, point: &Point<T>) -> bool {
1561 point.x >= self.origin.x
1562 && point.x < self.origin.x.clone() + self.size.width.clone()
1563 && point.y >= self.origin.y
1564 && point.y < self.origin.y.clone() + self.size.height.clone()
1565 }
1566
1567 /// Returns `true` if this rectangle lies entirely inside `other`.
1568 ///
1569 /// Checks that the top left and bottom right corners of this rectangle are inside `other`, using
1570 /// the rules of [`Bounds::contains`].
1571 ///
1572 /// # Examples
1573 ///
1574 /// ```
1575 /// # use gpui::{Bounds, Point, Size};
1576 /// let outer = Bounds {
1577 /// origin: Point { x: 0, y: 0 },
1578 /// size: Size { width: 20, height: 20 },
1579 /// };
1580 /// let inner = Bounds {
1581 /// origin: Point { x: 5, y: 5 },
1582 /// size: Size { width: 10, height: 10 },
1583 /// };
1584 /// let overlapping = Bounds {
1585 /// origin: Point { x: 15, y: 15 },
1586 /// size: Size { width: 10, height: 10 },
1587 /// };
1588 ///
1589 /// assert!(inner.is_contained_within(&outer));
1590 /// assert!(!overlapping.is_contained_within(&outer));
1591 /// ```
1592 pub fn is_contained_within(&self, other: &Self) -> bool {
1593 other.contains(&self.origin) && other.contains(&self.bottom_right())
1594 }
1595
1596 /// Returns bounds with `f` applied to the origin and the size, converting `T` to `U`.
1597 ///
1598 /// # Examples
1599 ///
1600 /// ```
1601 /// # use gpui::{Bounds, Point, Size};
1602 /// let bounds = Bounds {
1603 /// origin: Point { x: 10.0, y: 10.0 },
1604 /// size: Size { width: 10.0, height: 20.0 },
1605 /// };
1606 /// let new_bounds = bounds.map(|value| value as f64 * 1.5);
1607 ///
1608 /// assert_eq!(new_bounds, Bounds {
1609 /// origin: Point { x: 15.0, y: 15.0 },
1610 /// size: Size { width: 15.0, height: 30.0 },
1611 /// });
1612 /// ```
1613 pub fn map<U>(&self, f: impl Fn(T) -> U) -> Bounds<U>
1614 where
1615 U: Clone + Debug + Default + PartialEq,
1616 {
1617 Bounds {
1618 origin: self.origin.map(&f),
1619 size: self.size.map(f),
1620 }
1621 }
1622
1623 /// Returns bounds with `f` applied to each coordinate of the origin. The size is unchanged.
1624 ///
1625 /// # Examples
1626 ///
1627 /// ```
1628 /// # use gpui::{Bounds, Point, Size};
1629 /// let bounds = Bounds {
1630 /// origin: Point { x: 10.0, y: 10.0 },
1631 /// size: Size { width: 10.0, height: 20.0 },
1632 /// };
1633 /// let new_bounds = bounds.map_origin(|value| value * 1.5);
1634 ///
1635 /// assert_eq!(new_bounds, Bounds {
1636 /// origin: Point { x: 15.0, y: 15.0 },
1637 /// size: Size { width: 10.0, height: 20.0 },
1638 /// });
1639 /// ```
1640 pub fn map_origin(self, f: impl Fn(T) -> T) -> Bounds<T> {
1641 Bounds {
1642 origin: self.origin.map(f),
1643 size: self.size,
1644 }
1645 }
1646
1647 /// Returns bounds with `f` applied to the width and the height. The origin is unchanged.
1648 ///
1649 /// # Examples
1650 ///
1651 /// ```
1652 /// # use gpui::{Bounds, Point, Size};
1653 /// let bounds = Bounds {
1654 /// origin: Point { x: 10.0, y: 10.0 },
1655 /// size: Size { width: 10.0, height: 20.0 },
1656 /// };
1657 /// let new_bounds = bounds.map_size(|value| value * 1.5);
1658 ///
1659 /// assert_eq!(new_bounds, Bounds {
1660 /// origin: Point { x: 10.0, y: 10.0 },
1661 /// size: Size { width: 15.0, height: 30.0 },
1662 /// });
1663 /// ```
1664 pub fn map_size(self, f: impl Fn(T) -> T) -> Bounds<T> {
1665 Bounds {
1666 origin: self.origin,
1667 size: self.size.map(f),
1668 }
1669 }
1670}
1671
1672impl<T> Bounds<T>
1673where
1674 T: Add<T, Output = T> + Sub<T, Output = T> + PartialOrd + Clone + Debug + Default + PartialEq,
1675{
1676 /// Returns `point` relative to the origin of this rectangle, or `None` if `point` is outside.
1677 ///
1678 /// Use it to turn a window position into a position inside an element. The result follows
1679 /// the rules of [`Bounds::contains`].
1680 ///
1681 /// # Examples
1682 ///
1683 /// ```
1684 /// # use gpui::{Bounds, Point, Size, bounds, point, px, size};
1685 /// let panel = bounds(point(px(100.), px(50.)), size(px(200.), px(100.)));
1686 /// assert_eq!(panel.localize(&point(px(110.), px(60.))), Some(point(px(10.), px(10.))));
1687 /// assert_eq!(panel.localize(&point(px(10.), px(10.))), None);
1688 /// ```
1689 pub fn localize(&self, point: &Point<T>) -> Option<Point<T>> {
1690 self.contains(point)
1691 .then(|| point.relative_to(&self.origin))
1692 }
1693}
1694
1695impl<T: PartialOrd + Clone + Debug + Default + PartialEq> Bounds<T> {
1696 /// Returns `true` if the width or the height is zero or less.
1697 ///
1698 /// # Examples
1699 ///
1700 /// ```
1701 /// # use gpui::{Bounds, Point, Size};
1702 /// let empty = Bounds {
1703 /// origin: Point { x: 0, y: 0 },
1704 /// size: Size { width: 10, height: 0 },
1705 /// };
1706 /// assert!(empty.is_empty());
1707 /// ```
1708 #[must_use]
1709 pub fn is_empty(&self) -> bool {
1710 self.size.width <= T::default() || self.size.height <= T::default()
1711 }
1712}
1713
1714impl<T: Clone + Debug + Default + PartialEq + Display + Add<T, Output = T>> Display for Bounds<T> {
1715 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1716 write!(
1717 f,
1718 "{} - {} (size {})",
1719 self.origin,
1720 self.bottom_right(),
1721 self.size
1722 )
1723 }
1724}
1725
1726impl Size<DevicePixels> {
1727 /// Converts this size from device pixels to logical pixels by dividing by `scale_factor`.
1728 ///
1729 /// # Examples
1730 ///
1731 /// ```
1732 /// # use gpui::{DevicePixels, Size, px, size};
1733 /// let device = size(DevicePixels(200), DevicePixels(100));
1734 /// assert_eq!(device.to_pixels(2.), size(px(100.), px(50.)));
1735 /// ```
1736 pub fn to_pixels(self, scale_factor: f32) -> Size<Pixels> {
1737 size(
1738 px(self.width.0 as f32 / scale_factor),
1739 px(self.height.0 as f32 / scale_factor),
1740 )
1741 }
1742}
1743
1744impl Size<Pixels> {
1745 /// Converts this size from logical pixels to device pixels.
1746 ///
1747 /// Multiplies each side by `scale_factor` and rounds it to the nearest whole device pixel.
1748 ///
1749 /// # Examples
1750 ///
1751 /// ```
1752 /// # use gpui::{DevicePixels, px, size};
1753 /// let logical = size(px(100.), px(50.3));
1754 /// assert_eq!(logical.to_device_pixels(2.), size(DevicePixels(200), DevicePixels(101)));
1755 /// ```
1756 pub fn to_device_pixels(self, scale_factor: f32) -> Size<DevicePixels> {
1757 size(
1758 DevicePixels((self.width.0 * scale_factor).round() as i32),
1759 DevicePixels((self.height.0 * scale_factor).round() as i32),
1760 )
1761 }
1762}
1763
1764impl Bounds<Pixels> {
1765 /// Multiplies the origin and the size by `factor`, producing [`ScaledPixels`].
1766 ///
1767 /// Pass the display's scale factor to convert logical bounds into the scaled space. The values
1768 /// aren't rounded: use [`Bounds::to_device_pixels`] to get whole device pixels.
1769 ///
1770 /// # Examples
1771 ///
1772 /// ```
1773 /// # use gpui::{Bounds, Point, Size, Pixels, ScaledPixels};
1774 /// let bounds = Bounds {
1775 /// origin: Point { x: Pixels::from(10.0), y: Pixels::from(20.0) },
1776 /// size: Size { width: Pixels::from(30.0), height: Pixels::from(40.0) },
1777 /// };
1778 /// let scaled_bounds = bounds.scale(2.0);
1779 /// assert_eq!(scaled_bounds, Bounds {
1780 /// origin: Point {
1781 /// x: ScaledPixels::from(20.0),
1782 /// y: ScaledPixels::from(40.0),
1783 /// },
1784 /// size: Size {
1785 /// width: ScaledPixels::from(60.0),
1786 /// height: ScaledPixels::from(80.0)
1787 /// },
1788 /// });
1789 /// ```
1790 pub fn scale(&self, factor: f32) -> Bounds<ScaledPixels> {
1791 Bounds {
1792 origin: self.origin.scale(factor),
1793 size: self.size.scale(factor),
1794 }
1795 }
1796
1797 /// Converts these logical bounds to device pixels.
1798 ///
1799 /// Multiplies each coordinate and size by `factor`, rounding each to the nearest whole device
1800 /// pixel. The origin and the size are rounded separately, so the bottom right corner can differ
1801 /// by one pixel from rounding the corner directly.
1802 ///
1803 /// # Examples
1804 ///
1805 /// ```
1806 /// # use gpui::{Bounds, DevicePixels, bounds, point, px, size};
1807 /// let logical = bounds(point(px(10.), px(20.)), size(px(30.), px(40.)));
1808 /// assert_eq!(
1809 /// logical.to_device_pixels(1.5),
1810 /// bounds(point(DevicePixels(15), DevicePixels(30)), size(DevicePixels(45), DevicePixels(60))),
1811 /// );
1812 /// ```
1813 pub fn to_device_pixels(self, factor: f32) -> Bounds<DevicePixels> {
1814 Bounds {
1815 origin: point(
1816 DevicePixels((self.origin.x.0 * factor).round() as i32),
1817 DevicePixels((self.origin.y.0 * factor).round() as i32),
1818 ),
1819 size: self.size.to_device_pixels(factor),
1820 }
1821 }
1822}
1823
1824impl Bounds<DevicePixels> {
1825 /// Converts these device pixel bounds to logical pixels by dividing by `scale_factor`.
1826 ///
1827 /// # Examples
1828 ///
1829 /// ```
1830 /// # use gpui::{Bounds, DevicePixels, bounds, point, px, size};
1831 /// let device = bounds(point(DevicePixels(200), DevicePixels(100)), size(DevicePixels(400), DevicePixels(300)));
1832 /// assert_eq!(device.to_pixels(2.), bounds(point(px(100.), px(50.)), size(px(200.), px(150.))));
1833 /// ```
1834 pub fn to_pixels(self, scale_factor: f32) -> Bounds<Pixels> {
1835 Bounds {
1836 origin: point(
1837 px(self.origin.x.0 as f32 / scale_factor),
1838 px(self.origin.y.0 as f32 / scale_factor),
1839 ),
1840 size: self.size.to_pixels(scale_factor),
1841 }
1842 }
1843}
1844
1845/// The sizes of the four sides of a box, such as its padding or margin.
1846///
1847/// Each field holds the size of one side. The value is measured inward from that side: `top`
1848/// is the space along the top edge, and so on. `Edges<Pixels>` implements `From<f32>` and
1849/// `From<Pixels>` for the same value on all four sides.
1850///
1851/// # Examples
1852///
1853/// ```
1854/// # use gpui::Edges;
1855/// let edges = Edges {
1856/// top: 10.0,
1857/// right: 20.0,
1858/// bottom: 30.0,
1859/// left: 40.0,
1860/// };
1861///
1862/// assert_eq!(edges.top, 10.0);
1863/// assert_eq!(edges.right, 20.0);
1864/// assert_eq!(edges.bottom, 30.0);
1865/// assert_eq!(edges.left, 40.0);
1866/// ```
1867#[derive(Refineable, Clone, Default, Debug, Eq, PartialEq)]
1868#[refineable(Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
1869#[repr(C)]
1870pub struct Edges<T: Clone + Debug + Default + PartialEq> {
1871 /// The size of the top side.
1872 pub top: T,
1873 /// The size of the right side.
1874 pub right: T,
1875 /// The size of the bottom side.
1876 pub bottom: T,
1877 /// The size of the left side.
1878 pub left: T,
1879}
1880
1881impl<T> Mul for Edges<T>
1882where
1883 T: Mul<Output = T> + Clone + Debug + Default + PartialEq,
1884{
1885 type Output = Self;
1886
1887 fn mul(self, rhs: Self) -> Self::Output {
1888 Self {
1889 top: self.top.clone() * rhs.top,
1890 right: self.right.clone() * rhs.right,
1891 bottom: self.bottom.clone() * rhs.bottom,
1892 left: self.left * rhs.left,
1893 }
1894 }
1895}
1896
1897impl<T, S> MulAssign<S> for Edges<T>
1898where
1899 T: Mul<S, Output = T> + Clone + Debug + Default + PartialEq,
1900 S: Clone,
1901{
1902 fn mul_assign(&mut self, rhs: S) {
1903 self.top = self.top.clone() * rhs.clone();
1904 self.right = self.right.clone() * rhs.clone();
1905 self.bottom = self.bottom.clone() * rhs.clone();
1906 self.left = self.left.clone() * rhs;
1907 }
1908}
1909
1910impl<T: Clone + Debug + Default + PartialEq + Copy> Copy for Edges<T> {}
1911
1912impl<T: Clone + Debug + Default + PartialEq> Edges<T> {
1913 /// Returns edges with `value` on all four sides.
1914 ///
1915 /// # Examples
1916 ///
1917 /// ```
1918 /// # use gpui::Edges;
1919 /// let uniform_edges = Edges::all(10.0);
1920 /// assert_eq!(uniform_edges.top, 10.0);
1921 /// assert_eq!(uniform_edges.right, 10.0);
1922 /// assert_eq!(uniform_edges.bottom, 10.0);
1923 /// assert_eq!(uniform_edges.left, 10.0);
1924 /// ```
1925 pub fn all(value: T) -> Self {
1926 Self {
1927 top: value.clone(),
1928 right: value.clone(),
1929 bottom: value.clone(),
1930 left: value,
1931 }
1932 }
1933
1934 /// Returns edges with `value` on the left and right sides, and the default on the top and bottom.
1935 ///
1936 /// # Examples
1937 ///
1938 /// ```
1939 /// # use gpui::Edges;
1940 /// let edges = Edges::horizontal(10.0);
1941 /// assert_eq!(edges.top, 0.0);
1942 /// assert_eq!(edges.right, 10.0);
1943 /// assert_eq!(edges.bottom, 0.0);
1944 /// assert_eq!(edges.left, 10.0);
1945 /// ```
1946 pub fn horizontal(value: T) -> Self {
1947 Self {
1948 top: T::default(),
1949 right: value.clone(),
1950 bottom: T::default(),
1951 left: value,
1952 }
1953 }
1954
1955 /// Returns edges with `value` on the top and bottom sides, and the default on the left and right.
1956 ///
1957 /// # Examples
1958 ///
1959 /// ```
1960 /// # use gpui::Edges;
1961 /// let edges = Edges::vertical(10.0);
1962 /// assert_eq!(edges.top, 10.0);
1963 /// assert_eq!(edges.right, 0.0);
1964 /// assert_eq!(edges.bottom, 10.0);
1965 /// assert_eq!(edges.left, 0.0);
1966 /// ```
1967 pub fn vertical(value: T) -> Self {
1968 Self {
1969 top: value.clone(),
1970 right: T::default(),
1971 bottom: value,
1972 left: T::default(),
1973 }
1974 }
1975
1976 /// Returns edges with `f` applied to each side.
1977 ///
1978 /// # Examples
1979 ///
1980 /// ```
1981 /// # use gpui::Edges;
1982 /// let edges = Edges { top: 10, right: 20, bottom: 30, left: 40 };
1983 /// let edges_float = edges.map(|&value| value as f32 * 1.1);
1984 /// assert_eq!(edges_float, Edges { top: 11.0, right: 22.0, bottom: 33.0, left: 44.0 });
1985 /// ```
1986 pub fn map<U>(&self, f: impl Fn(&T) -> U) -> Edges<U>
1987 where
1988 U: Clone + Debug + Default + PartialEq,
1989 {
1990 Edges {
1991 top: f(&self.top),
1992 right: f(&self.right),
1993 bottom: f(&self.bottom),
1994 left: f(&self.left),
1995 }
1996 }
1997
1998 /// Returns `true` if `predicate` is `true` for at least one side.
1999 ///
2000 /// # Examples
2001 ///
2002 /// ```
2003 /// # use gpui::Edges;
2004 /// let edges = Edges {
2005 /// top: 10,
2006 /// right: 0,
2007 /// bottom: 5,
2008 /// left: 0,
2009 /// };
2010 ///
2011 /// assert!(edges.any(|value| *value == 0));
2012 /// assert!(edges.any(|value| *value > 0));
2013 /// assert!(!edges.any(|value| *value > 10));
2014 /// ```
2015 pub fn any<F: Fn(&T) -> bool>(&self, predicate: F) -> bool {
2016 predicate(&self.top)
2017 || predicate(&self.right)
2018 || predicate(&self.bottom)
2019 || predicate(&self.left)
2020 }
2021}
2022
2023impl Edges<Length> {
2024 /// Returns edges with [`Length::Auto`] on all four sides.
2025 ///
2026 /// # Examples
2027 ///
2028 /// ```
2029 /// # use gpui::{Edges, Length};
2030 /// let auto_edges = Edges::auto();
2031 /// assert_eq!(auto_edges.top, Length::Auto);
2032 /// assert_eq!(auto_edges.right, Length::Auto);
2033 /// assert_eq!(auto_edges.bottom, Length::Auto);
2034 /// assert_eq!(auto_edges.left, Length::Auto);
2035 /// ```
2036 pub fn auto() -> Self {
2037 Self {
2038 top: Length::Auto,
2039 right: Length::Auto,
2040 bottom: Length::Auto,
2041 left: Length::Auto,
2042 }
2043 }
2044
2045 /// Returns edges of zero pixels on all four sides.
2046 ///
2047 /// # Examples
2048 ///
2049 /// ```
2050 /// # use gpui::{DefiniteLength, Edges, Length, Pixels};
2051 /// let no_edges = Edges::<Length>::zero();
2052 /// assert_eq!(no_edges.top, Length::Definite(DefiniteLength::from(Pixels::ZERO)));
2053 /// assert_eq!(no_edges.right, Length::Definite(DefiniteLength::from(Pixels::ZERO)));
2054 /// assert_eq!(no_edges.bottom, Length::Definite(DefiniteLength::from(Pixels::ZERO)));
2055 /// assert_eq!(no_edges.left, Length::Definite(DefiniteLength::from(Pixels::ZERO)));
2056 /// ```
2057 pub fn zero() -> Self {
2058 Self {
2059 top: px(0.).into(),
2060 right: px(0.).into(),
2061 bottom: px(0.).into(),
2062 left: px(0.).into(),
2063 }
2064 }
2065}
2066
2067impl Edges<DefiniteLength> {
2068 /// Returns edges of zero on all four sides.
2069 ///
2070 /// # Examples
2071 ///
2072 /// ```
2073 /// # use gpui::{px, DefiniteLength, Edges};
2074 /// let no_edges = Edges::<DefiniteLength>::zero();
2075 /// assert_eq!(no_edges.top, DefiniteLength::from(px(0.)));
2076 /// assert_eq!(no_edges.right, DefiniteLength::from(px(0.)));
2077 /// assert_eq!(no_edges.bottom, DefiniteLength::from(px(0.)));
2078 /// assert_eq!(no_edges.left, DefiniteLength::from(px(0.)));
2079 /// ```
2080 pub fn zero() -> Self {
2081 Self {
2082 top: px(0.).into(),
2083 right: px(0.).into(),
2084 bottom: px(0.).into(),
2085 left: px(0.).into(),
2086 }
2087 }
2088
2089 /// Resolves each side to pixels.
2090 ///
2091 /// `top` and `bottom` are fractions of `parent_size.height`, and `left` and `right` are fractions
2092 /// of `parent_size.width`. Rems are multiplied by `rem_size`.
2093 ///
2094 /// # Examples
2095 ///
2096 /// ```
2097 /// # use gpui::{Edges, DefiniteLength, px, relative, AbsoluteLength, rems, Size};
2098 /// let edges = Edges {
2099 /// top: DefiniteLength::Absolute(AbsoluteLength::Pixels(px(10.0))),
2100 /// right: relative(0.5).into(),
2101 /// bottom: DefiniteLength::Absolute(AbsoluteLength::Rems(rems(2.0))),
2102 /// left: relative(0.25).into(),
2103 /// };
2104 /// let parent_size = Size {
2105 /// width: AbsoluteLength::Pixels(px(200.0)),
2106 /// height: AbsoluteLength::Pixels(px(100.0)),
2107 /// };
2108 /// let rem_size = px(16.0);
2109 /// let edges_in_pixels = edges.to_pixels(parent_size, rem_size);
2110 ///
2111 /// assert_eq!(edges_in_pixels.top, px(10.0));
2112 /// assert_eq!(edges_in_pixels.right, px(100.0));
2113 /// assert_eq!(edges_in_pixels.bottom, px(32.0));
2114 /// assert_eq!(edges_in_pixels.left, px(50.0));
2115 /// ```
2116 pub fn to_pixels(self, parent_size: Size<AbsoluteLength>, rem_size: Pixels) -> Edges<Pixels> {
2117 Edges {
2118 top: self.top.to_pixels(parent_size.height, rem_size),
2119 right: self.right.to_pixels(parent_size.width, rem_size),
2120 bottom: self.bottom.to_pixels(parent_size.height, rem_size),
2121 left: self.left.to_pixels(parent_size.width, rem_size),
2122 }
2123 }
2124}
2125
2126impl Edges<AbsoluteLength> {
2127 /// Sets the edges of the `Edges` struct to zero, which means no size or thickness.
2128 ///
2129 /// This is typically used when you want to specify that a box (like a padding or margin area)
2130 /// should have no edges, effectively making it non-existent or invisible in layout calculations.
2131 ///
2132 /// # Returns
2133 ///
2134 /// Returns an `Edges<AbsoluteLength>` with all edges set to zero length.
2135 ///
2136 /// # Examples
2137 ///
2138 /// ```
2139 /// # use gpui::{AbsoluteLength, Edges, Pixels};
2140 /// let no_edges = Edges::<AbsoluteLength>::zero();
2141 /// assert_eq!(no_edges.top, AbsoluteLength::Pixels(Pixels::ZERO));
2142 /// assert_eq!(no_edges.right, AbsoluteLength::Pixels(Pixels::ZERO));
2143 /// assert_eq!(no_edges.bottom, AbsoluteLength::Pixels(Pixels::ZERO));
2144 /// assert_eq!(no_edges.left, AbsoluteLength::Pixels(Pixels::ZERO));
2145 /// ```
2146 pub fn zero() -> Self {
2147 Self {
2148 top: px(0.).into(),
2149 right: px(0.).into(),
2150 bottom: px(0.).into(),
2151 left: px(0.).into(),
2152 }
2153 }
2154
2155 /// Resolves each side to pixels. Rems are multiplied by `rem_size`.
2156 ///
2157 /// # Examples
2158 ///
2159 /// ```
2160 /// # use gpui::{Edges, AbsoluteLength, Pixels, px, rems};
2161 /// let edges = Edges {
2162 /// top: AbsoluteLength::Pixels(px(10.0)),
2163 /// right: AbsoluteLength::Rems(rems(1.0)),
2164 /// bottom: AbsoluteLength::Pixels(px(20.0)),
2165 /// left: AbsoluteLength::Rems(rems(2.0)),
2166 /// };
2167 /// let rem_size = px(16.0);
2168 /// let edges_in_pixels = edges.to_pixels(rem_size);
2169 ///
2170 /// assert_eq!(edges_in_pixels.top, px(10.0));
2171 /// assert_eq!(edges_in_pixels.right, px(16.0));
2172 /// assert_eq!(edges_in_pixels.bottom, px(20.0));
2173 /// assert_eq!(edges_in_pixels.left, px(32.0));
2174 /// ```
2175 pub fn to_pixels(self, rem_size: Pixels) -> Edges<Pixels> {
2176 Edges {
2177 top: self.top.to_pixels(rem_size),
2178 right: self.right.to_pixels(rem_size),
2179 bottom: self.bottom.to_pixels(rem_size),
2180 left: self.left.to_pixels(rem_size),
2181 }
2182 }
2183}
2184
2185impl Edges<Pixels> {
2186 /// Multiplies each side by `factor`, producing [`ScaledPixels`].
2187 ///
2188 /// # Examples
2189 ///
2190 /// ```
2191 /// # use gpui::{Edges, Pixels, ScaledPixels};
2192 /// let edges = Edges {
2193 /// top: Pixels::from(10.0),
2194 /// right: Pixels::from(20.0),
2195 /// bottom: Pixels::from(30.0),
2196 /// left: Pixels::from(40.0),
2197 /// };
2198 /// let scaled_edges = edges.scale(2.0);
2199 /// assert_eq!(scaled_edges.top, ScaledPixels::from(20.0));
2200 /// assert_eq!(scaled_edges.right, ScaledPixels::from(40.0));
2201 /// assert_eq!(scaled_edges.bottom, ScaledPixels::from(60.0));
2202 /// assert_eq!(scaled_edges.left, ScaledPixels::from(80.0));
2203 /// ```
2204 pub fn scale(&self, factor: f32) -> Edges<ScaledPixels> {
2205 Edges {
2206 top: self.top.scale(factor),
2207 right: self.right.scale(factor),
2208 bottom: self.bottom.scale(factor),
2209 left: self.left.scale(factor),
2210 }
2211 }
2212
2213 /// Returns the largest of the four sides.
2214 ///
2215 /// # Examples
2216 ///
2217 /// ```
2218 /// # use gpui::{Edges, Pixels, px};
2219 /// let edges = Edges { top: px(4.), right: px(9.), bottom: px(2.), left: px(1.) };
2220 /// assert_eq!(edges.max(), px(9.));
2221 /// ```
2222 pub fn max(&self) -> Pixels {
2223 self.top.max(self.right).max(self.bottom).max(self.left)
2224 }
2225}
2226
2227impl From<f32> for Edges<Pixels> {
2228 fn from(val: f32) -> Self {
2229 let val: Pixels = val.into();
2230 val.into()
2231 }
2232}
2233
2234impl From<Pixels> for Edges<Pixels> {
2235 fn from(val: Pixels) -> Self {
2236 Edges {
2237 top: val,
2238 right: val,
2239 bottom: val,
2240 left: val,
2241 }
2242 }
2243}
2244
2245/// A point on the edge or corner of a box, used to align a position to that box.
2246///
2247/// [`Size::at_anchor`], [`Bounds::corner`] and [`Bounds::from_anchor_and_size`] take an anchor.
2248/// Anchors don't carry a size, so they name a location on any box.
2249///
2250/// # Examples
2251///
2252/// ```
2253/// use gpui::{Anchor, Bounds, Point, Size};
2254/// let bounds = Bounds {
2255/// origin: Point { x: 0, y: 0 },
2256/// size: Size { width: 10, height: 20 },
2257/// };
2258/// assert_eq!(bounds.corner(Anchor::TopRight), Point { x: 10, y: 0 });
2259/// ```
2260#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2261pub enum Anchor {
2262 /// The top left corner.
2263 TopLeft,
2264 /// The top right corner.
2265 TopRight,
2266 /// The bottom left corner.
2267 BottomLeft,
2268 /// The bottom right corner.
2269 BottomRight,
2270 /// The midpoint of the top edge.
2271 TopCenter,
2272 /// The midpoint of the bottom edge.
2273 BottomCenter,
2274 /// The midpoint of the left edge.
2275 LeftCenter,
2276 /// The midpoint of the right edge.
2277 RightCenter,
2278}
2279
2280impl Anchor {
2281 /// Returns the anchor on the opposite side of the box.
2282 ///
2283 /// Corners map to the diagonally opposite corner, and each edge midpoint maps to the midpoint of
2284 /// the opposite edge.
2285 ///
2286 /// # Examples
2287 ///
2288 /// ```
2289 /// # use gpui::Anchor;
2290 /// assert_eq!(Anchor::TopLeft.opposite(), Anchor::BottomRight);
2291 /// assert_eq!(Anchor::TopCenter.opposite(), Anchor::BottomCenter);
2292 /// ```
2293 #[must_use]
2294 pub fn opposite(self) -> Self {
2295 match self {
2296 Anchor::TopLeft => Anchor::BottomRight,
2297 Anchor::TopRight => Anchor::BottomLeft,
2298 Anchor::BottomLeft => Anchor::TopRight,
2299 Anchor::BottomRight => Anchor::TopLeft,
2300 Anchor::TopCenter => Anchor::BottomCenter,
2301 Anchor::BottomCenter => Anchor::TopCenter,
2302 Anchor::LeftCenter => Anchor::RightCenter,
2303 Anchor::RightCenter => Anchor::LeftCenter,
2304 }
2305 }
2306
2307 /// Reflects this anchor across the center of the box along `axis`.
2308 ///
2309 /// [`Axis::Vertical`] swaps the top and bottom sides, and [`Axis::Horizontal`] swaps the left and
2310 /// right sides. An anchor on the center line of that axis stays where it is.
2311 ///
2312 /// # Examples
2313 ///
2314 /// ```
2315 /// # use gpui::{Anchor, Axis};
2316 /// assert_eq!(Anchor::TopLeft.other_side_along(Axis::Horizontal), Anchor::TopRight);
2317 /// assert_eq!(Anchor::TopLeft.other_side_along(Axis::Vertical), Anchor::BottomLeft);
2318 /// assert_eq!(Anchor::TopCenter.other_side_along(Axis::Horizontal), Anchor::TopCenter);
2319 /// ```
2320 #[must_use]
2321 pub fn other_side_along(self, axis: Axis) -> Self {
2322 match axis {
2323 Axis::Vertical => match self {
2324 Anchor::TopLeft => Anchor::BottomLeft,
2325 Anchor::TopRight => Anchor::BottomRight,
2326 Anchor::BottomLeft => Anchor::TopLeft,
2327 Anchor::BottomRight => Anchor::TopRight,
2328 Anchor::TopCenter => Anchor::BottomCenter,
2329 Anchor::BottomCenter => Anchor::TopCenter,
2330 Anchor::LeftCenter => Anchor::LeftCenter,
2331 Anchor::RightCenter => Anchor::RightCenter,
2332 },
2333 Axis::Horizontal => match self {
2334 Anchor::TopLeft => Anchor::TopRight,
2335 Anchor::TopRight => Anchor::TopLeft,
2336 Anchor::BottomLeft => Anchor::BottomRight,
2337 Anchor::BottomRight => Anchor::BottomLeft,
2338 Anchor::TopCenter => Anchor::TopCenter,
2339 Anchor::BottomCenter => Anchor::BottomCenter,
2340 Anchor::LeftCenter => Anchor::RightCenter,
2341 Anchor::RightCenter => Anchor::LeftCenter,
2342 },
2343 }
2344 }
2345
2346 /// Returns `true` for the midpoint of an edge, and `false` for a corner.
2347 ///
2348 /// # Examples
2349 ///
2350 /// ```
2351 /// # use gpui::Anchor;
2352 /// assert!(Anchor::LeftCenter.is_center());
2353 /// assert!(!Anchor::BottomRight.is_center());
2354 /// ```
2355 #[inline]
2356 pub fn is_center(&self) -> bool {
2357 matches!(
2358 self,
2359 Self::TopCenter | Self::BottomCenter | Self::LeftCenter | Self::RightCenter
2360 )
2361 }
2362
2363 /// Returns whether the anchor is bottom-positioned.
2364 #[inline]
2365 pub fn is_bottom(&self) -> bool {
2366 matches!(
2367 self,
2368 Self::BottomCenter | Self::BottomLeft | Self::BottomRight
2369 )
2370 }
2371}
2372
2373/// The values at the four corners of a box, such as a border radius.
2374///
2375/// Use `Corners<Pixels>` for radii. `Corners<Pixels>` implements `From<f32>` and `From<Pixels>`
2376/// for the same value at every corner.
2377///
2378/// # Examples
2379///
2380/// ```
2381/// # use gpui::{Corners, Pixels, px};
2382/// let radii = Corners::all(px(8.));
2383/// assert_eq!(radii.top_left, Pixels::from(8.));
2384/// assert_eq!(radii.bottom_right, Pixels::from(8.));
2385/// ```
2386#[derive(Refineable, Clone, Default, Debug, Eq, PartialEq)]
2387#[refineable(Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
2388#[repr(C)]
2389pub struct Corners<T: Clone + Debug + Default + PartialEq> {
2390 /// The value at the top left corner.
2391 pub top_left: T,
2392 /// The value at the top right corner.
2393 pub top_right: T,
2394 /// The value at the bottom right corner.
2395 pub bottom_right: T,
2396 /// The value at the bottom left corner.
2397 pub bottom_left: T,
2398}
2399
2400impl<T> Corners<T>
2401where
2402 T: Add<T, Output = T> + Half + Clone + Debug + Default + PartialEq,
2403{
2404 /// Returns corners with `value` at every corner.
2405 ///
2406 /// # Examples
2407 ///
2408 /// ```
2409 /// # use gpui::Corners;
2410 /// let uniform_corners = Corners::all(5.0);
2411 /// assert_eq!(uniform_corners.top_left, 5.0);
2412 /// assert_eq!(uniform_corners.top_right, 5.0);
2413 /// assert_eq!(uniform_corners.bottom_right, 5.0);
2414 /// assert_eq!(uniform_corners.bottom_left, 5.0);
2415 /// ```
2416 pub fn all(value: T) -> Self {
2417 Self {
2418 top_left: value.clone(),
2419 top_right: value.clone(),
2420 bottom_right: value.clone(),
2421 bottom_left: value,
2422 }
2423 }
2424
2425 /// Returns the value at `corner`.
2426 ///
2427 /// The four corner anchors return their field. An edge midpoint returns the average of the two
2428 /// corners on that edge, computed with [`Half`]. For example, `Anchor::TopCenter` averages
2429 /// `top_left` and `top_right`.
2430 ///
2431 /// # Examples
2432 ///
2433 /// Corner positions:
2434 ///
2435 /// ```
2436 /// # use gpui::{Anchor, Corners};
2437 /// let corners = Corners {
2438 /// top_left: 10,
2439 /// top_right: 20,
2440 /// bottom_left: 30,
2441 /// bottom_right: 40
2442 /// };
2443 /// assert_eq!(corners.corner(Anchor::TopLeft), 10);
2444 /// assert_eq!(corners.corner(Anchor::BottomRight), 40);
2445 /// ```
2446 ///
2447 /// Edge midpoints, calculated as the average of the adjacent corners:
2448 ///
2449 /// ```
2450 /// # use gpui::{Anchor, Corners};
2451 /// let corners = Corners {
2452 /// top_left: 10,
2453 /// top_right: 20,
2454 /// bottom_left: 30,
2455 /// bottom_right: 40
2456 /// };
2457 /// assert_eq!(corners.corner(Anchor::TopCenter), 15);
2458 /// assert_eq!(corners.corner(Anchor::BottomCenter), 35);
2459 /// assert_eq!(corners.corner(Anchor::LeftCenter), 20);
2460 /// assert_eq!(corners.corner(Anchor::RightCenter), 30);
2461 /// ```
2462 #[must_use]
2463 pub fn corner(&self, corner: Anchor) -> T {
2464 match corner {
2465 Anchor::TopLeft => self.top_left.clone(),
2466 Anchor::TopRight => self.top_right.clone(),
2467 Anchor::BottomLeft => self.bottom_left.clone(),
2468 Anchor::BottomRight => self.bottom_right.clone(),
2469 Anchor::TopCenter => (self.top_left.clone() + self.top_right.clone()).half(),
2470 Anchor::BottomCenter => (self.bottom_left.clone() + self.bottom_right.clone()).half(),
2471 Anchor::LeftCenter => (self.top_left.clone() + self.bottom_left.clone()).half(),
2472 Anchor::RightCenter => (self.top_right.clone() + self.bottom_right.clone()).half(),
2473 }
2474 }
2475}
2476
2477impl Corners<AbsoluteLength> {
2478 /// Resolves each corner to pixels. Rems are multiplied by `rem_size`.
2479 ///
2480 /// # Examples
2481 ///
2482 /// ```
2483 /// # use gpui::{Corners, AbsoluteLength, Pixels, Rems};
2484 /// let corners = Corners {
2485 /// top_left: AbsoluteLength::Pixels(Pixels::from(15.0)),
2486 /// top_right: AbsoluteLength::Rems(Rems(1.0)),
2487 /// bottom_right: AbsoluteLength::Pixels(Pixels::from(30.0)),
2488 /// bottom_left: AbsoluteLength::Rems(Rems(2.0)),
2489 /// };
2490 /// let rem_size = Pixels::from(16.0);
2491 /// let corners_in_pixels = corners.to_pixels(rem_size);
2492 ///
2493 /// assert_eq!(corners_in_pixels.top_left, Pixels::from(15.0));
2494 /// assert_eq!(corners_in_pixels.top_right, Pixels::from(16.0));
2495 /// assert_eq!(corners_in_pixels.bottom_right, Pixels::from(30.0));
2496 /// assert_eq!(corners_in_pixels.bottom_left, Pixels::from(32.0));
2497 /// ```
2498 pub fn to_pixels(self, rem_size: Pixels) -> Corners<Pixels> {
2499 Corners {
2500 top_left: self.top_left.to_pixels(rem_size),
2501 top_right: self.top_right.to_pixels(rem_size),
2502 bottom_right: self.bottom_right.to_pixels(rem_size),
2503 bottom_left: self.bottom_left.to_pixels(rem_size),
2504 }
2505 }
2506}
2507
2508impl Corners<Pixels> {
2509 /// Multiplies each corner by `factor`, producing [`ScaledPixels`].
2510 ///
2511 /// # Examples
2512 ///
2513 /// ```
2514 /// # use gpui::{Corners, Pixels, ScaledPixels};
2515 /// let corners = Corners {
2516 /// top_left: Pixels::from(10.0),
2517 /// top_right: Pixels::from(20.0),
2518 /// bottom_right: Pixels::from(30.0),
2519 /// bottom_left: Pixels::from(40.0),
2520 /// };
2521 /// let scaled_corners = corners.scale(2.0);
2522 /// assert_eq!(scaled_corners.top_left, ScaledPixels::from(20.0));
2523 /// assert_eq!(scaled_corners.top_right, ScaledPixels::from(40.0));
2524 /// assert_eq!(scaled_corners.bottom_right, ScaledPixels::from(60.0));
2525 /// assert_eq!(scaled_corners.bottom_left, ScaledPixels::from(80.0));
2526 /// ```
2527 #[must_use]
2528 pub fn scale(&self, factor: f32) -> Corners<ScaledPixels> {
2529 Corners {
2530 top_left: self.top_left.scale(factor),
2531 top_right: self.top_right.scale(factor),
2532 bottom_right: self.bottom_right.scale(factor),
2533 bottom_left: self.bottom_left.scale(factor),
2534 }
2535 }
2536
2537 /// Returns the largest corner value.
2538 ///
2539 /// # Examples
2540 ///
2541 /// ```
2542 /// # use gpui::{Corners, Pixels, px};
2543 /// let corners = Corners {
2544 /// top_left: px(1.),
2545 /// top_right: px(4.),
2546 /// bottom_right: px(2.),
2547 /// bottom_left: px(3.),
2548 /// };
2549 /// assert_eq!(corners.max(), px(4.));
2550 /// ```
2551 #[must_use]
2552 pub fn max(&self) -> Pixels {
2553 self.top_left
2554 .max(self.top_right)
2555 .max(self.bottom_right)
2556 .max(self.bottom_left)
2557 }
2558}
2559
2560impl<T: Div<f32, Output = T> + Ord + Clone + Debug + Default + PartialEq> Corners<T> {
2561 /// Limits each corner radius to half of the shorter side of `size`.
2562 ///
2563 /// Radii larger than that would overlap, so each one is replaced by the limit. Radii below the
2564 /// limit are unchanged.
2565 ///
2566 /// # Examples
2567 ///
2568 /// ```
2569 /// # use gpui::{Corners, px, size};
2570 /// let radii = Corners::all(px(30.)).clamp_radii_for_quad_size(size(px(40.), px(100.)));
2571 /// assert_eq!(radii, Corners::all(px(20.)));
2572 ///
2573 /// let small = Corners::all(px(5.)).clamp_radii_for_quad_size(size(px(40.), px(100.)));
2574 /// assert_eq!(small, Corners::all(px(5.)));
2575 /// ```
2576 #[must_use]
2577 pub fn clamp_radii_for_quad_size(self, size: Size<T>) -> Corners<T> {
2578 let max = cmp::min(size.width, size.height) / 2.;
2579 Corners {
2580 top_left: cmp::min(self.top_left, max.clone()),
2581 top_right: cmp::min(self.top_right, max.clone()),
2582 bottom_right: cmp::min(self.bottom_right, max.clone()),
2583 bottom_left: cmp::min(self.bottom_left, max),
2584 }
2585 }
2586}
2587
2588impl<T: Clone + Debug + Default + PartialEq> Corners<T> {
2589 /// Returns corners with `f` applied to each corner.
2590 ///
2591 /// # Examples
2592 ///
2593 /// ```
2594 /// # use gpui::{Corners, Pixels, Rems};
2595 /// let corners = Corners {
2596 /// top_left: Pixels::from(10.0),
2597 /// top_right: Pixels::from(20.0),
2598 /// bottom_right: Pixels::from(30.0),
2599 /// bottom_left: Pixels::from(40.0),
2600 /// };
2601 /// let corners_in_rems = corners.map(|&px| Rems(f32::from(px) / 16.0));
2602 /// assert_eq!(corners_in_rems, Corners {
2603 /// top_left: Rems(0.625),
2604 /// top_right: Rems(1.25),
2605 /// bottom_right: Rems(1.875),
2606 /// bottom_left: Rems(2.5),
2607 /// });
2608 /// ```
2609 #[must_use]
2610 pub fn map<U>(&self, f: impl Fn(&T) -> U) -> Corners<U>
2611 where
2612 U: Clone + Debug + Default + PartialEq,
2613 {
2614 Corners {
2615 top_left: f(&self.top_left),
2616 top_right: f(&self.top_right),
2617 bottom_right: f(&self.bottom_right),
2618 bottom_left: f(&self.bottom_left),
2619 }
2620 }
2621}
2622
2623impl<T> Mul for Corners<T>
2624where
2625 T: Mul<Output = T> + Clone + Debug + Default + PartialEq,
2626{
2627 type Output = Self;
2628
2629 fn mul(self, rhs: Self) -> Self::Output {
2630 Self {
2631 top_left: self.top_left.clone() * rhs.top_left,
2632 top_right: self.top_right.clone() * rhs.top_right,
2633 bottom_right: self.bottom_right.clone() * rhs.bottom_right,
2634 bottom_left: self.bottom_left * rhs.bottom_left,
2635 }
2636 }
2637}
2638
2639impl<T, S> MulAssign<S> for Corners<T>
2640where
2641 T: Mul<S, Output = T> + Clone + Debug + Default + PartialEq,
2642 S: Clone,
2643{
2644 fn mul_assign(&mut self, rhs: S) {
2645 self.top_left = self.top_left.clone() * rhs.clone();
2646 self.top_right = self.top_right.clone() * rhs.clone();
2647 self.bottom_right = self.bottom_right.clone() * rhs.clone();
2648 self.bottom_left = self.bottom_left.clone() * rhs;
2649 }
2650}
2651
2652impl<T> Copy for Corners<T> where T: Copy + Clone + Debug + Default + PartialEq {}
2653
2654impl From<f32> for Corners<Pixels> {
2655 fn from(val: f32) -> Self {
2656 Corners {
2657 top_left: val.into(),
2658 top_right: val.into(),
2659 bottom_right: val.into(),
2660 bottom_left: val.into(),
2661 }
2662 }
2663}
2664
2665impl From<Pixels> for Corners<Pixels> {
2666 fn from(val: Pixels) -> Self {
2667 Corners {
2668 top_left: val,
2669 top_right: val,
2670 bottom_right: val,
2671 bottom_left: val,
2672 }
2673 }
2674}
2675
2676/// An angle in radians.
2677///
2678/// Use [`radians`] to create one, or convert a [`Percentage`] of a full turn with `From`.
2679///
2680/// # Examples
2681///
2682/// ```
2683/// use gpui::{Radians, percentage, radians};
2684/// let half_turn = radians(std::f32::consts::PI);
2685/// let quarter_turn = Radians::from(percentage(0.25));
2686/// assert!((quarter_turn.0 - std::f32::consts::FRAC_PI_2).abs() < 1e-6);
2687/// assert!((half_turn.0 - std::f32::consts::PI).abs() < 1e-6);
2688/// ```
2689#[derive(
2690 Clone,
2691 Copy,
2692 Default,
2693 Add,
2694 AddAssign,
2695 Sub,
2696 SubAssign,
2697 Neg,
2698 Div,
2699 DivAssign,
2700 PartialEq,
2701 Serialize,
2702 Deserialize,
2703 Debug,
2704)]
2705#[repr(transparent)]
2706pub struct Radians(pub f32);
2707
2708/// Creates a [`Radians`] angle from a value in radians.
2709///
2710/// # Examples
2711///
2712/// ```
2713/// use gpui::radians;
2714/// assert_eq!(radians(1.5).0, 1.5);
2715/// ```
2716pub fn radians(value: f32) -> Radians {
2717 Radians(value)
2718}
2719
2720/// A fraction of a full turn, from `0.0` to `1.0`.
2721///
2722/// Create one with [`percentage`]. Convert it to [`Radians`] with `From`.
2723#[derive(
2724 Clone,
2725 Copy,
2726 Default,
2727 Add,
2728 AddAssign,
2729 Sub,
2730 SubAssign,
2731 Neg,
2732 Div,
2733 DivAssign,
2734 PartialEq,
2735 Serialize,
2736 Deserialize,
2737 Debug,
2738)]
2739#[repr(transparent)]
2740pub struct Percentage(pub f32);
2741
2742/// Creates a [`Percentage`] of a full turn.
2743///
2744/// # Panics
2745///
2746/// Panics in debug builds if `value` is outside `0.0..=1.0`. Release builds don't check the
2747/// range.
2748///
2749/// # Examples
2750///
2751/// ```
2752/// use gpui::{Radians, percentage};
2753/// let turn = Radians::from(percentage(1.0));
2754/// assert!((turn.0 - std::f32::consts::TAU).abs() < 1e-6);
2755/// ```
2756pub fn percentage(value: f32) -> Percentage {
2757 debug_assert!(
2758 (0.0..=1.0).contains(&value),
2759 "Percentage must be between 0 and 1"
2760 );
2761 Percentage(value)
2762}
2763
2764impl From<Percentage> for Radians {
2765 fn from(value: Percentage) -> Self {
2766 radians(value.0 * std::f32::consts::PI * 2.0)
2767 }
2768}
2769
2770/// A length in logical pixels, GPUI's unit for layout, painting and input.
2771///
2772/// The platform converts logical pixels to device pixels using the display's scale factor. Thus
2773/// `px(10.)` becomes 20 device pixels at scale factor 2. Styles, element bounds, [`Point`] and
2774/// [`Size`] values in the UI use `Pixels`.
2775///
2776/// GPUI has three pixel types, and they differ in what the number counts:
2777///
2778/// * `Pixels` is a logical length. Its value is an `f32`, so fractions are kept.
2779/// * [`ScaledPixels`] is a logical length multiplied by the scale factor, from [`Pixels::scale`].
2780/// It is still an `f32` and isn't rounded. Paint primitives in the scene are in scaled pixels.
2781/// * [`DevicePixels`] is a whole number of physical pixels on the display. Convert to it with
2782/// [`Size::to_device_pixels`] or [`Bounds::to_device_pixels`], which round each component to the
2783/// nearest pixel.
2784///
2785/// Create a `Pixels` with [`px`] or `Pixels::from`. It supports addition and subtraction with
2786/// other `Pixels`, multiplication and division by an `f32`, and division by another `Pixels`,
2787/// which gives a plain `f32` ratio.
2788///
2789/// # Examples
2790///
2791/// ```
2792/// use gpui::{Pixels, ScaledPixels, px};
2793///
2794/// let length = Pixels::from(10.0);
2795/// let scaled_length = length.scale(2.0);
2796/// assert_eq!(scaled_length, ScaledPixels::from(20.0));
2797/// assert_eq!(px(10.) / px(4.), 2.5);
2798/// ```
2799#[derive(
2800 Clone,
2801 Copy,
2802 Default,
2803 Add,
2804 AddAssign,
2805 Sub,
2806 SubAssign,
2807 Neg,
2808 Div,
2809 DivAssign,
2810 PartialEq,
2811 Serialize,
2812 Deserialize,
2813 JsonSchema,
2814)]
2815#[repr(transparent)]
2816pub struct Pixels(pub(crate) f32);
2817
2818impl Div for Pixels {
2819 type Output = f32;
2820
2821 fn div(self, rhs: Self) -> Self::Output {
2822 self.0 / rhs.0
2823 }
2824}
2825
2826impl std::ops::DivAssign for Pixels {
2827 fn div_assign(&mut self, rhs: Self) {
2828 *self = Self(self.0 / rhs.0);
2829 }
2830}
2831
2832impl std::ops::RemAssign for Pixels {
2833 fn rem_assign(&mut self, rhs: Self) {
2834 self.0 %= rhs.0;
2835 }
2836}
2837
2838impl std::ops::Rem for Pixels {
2839 type Output = Self;
2840
2841 fn rem(self, rhs: Self) -> Self {
2842 Self(self.0 % rhs.0)
2843 }
2844}
2845
2846impl Mul<f32> for Pixels {
2847 type Output = Self;
2848
2849 fn mul(self, rhs: f32) -> Self {
2850 Self(self.0 * rhs)
2851 }
2852}
2853
2854impl Mul<Pixels> for f32 {
2855 type Output = Pixels;
2856
2857 fn mul(self, rhs: Pixels) -> Self::Output {
2858 rhs * self
2859 }
2860}
2861
2862impl Mul<usize> for Pixels {
2863 type Output = Self;
2864
2865 fn mul(self, rhs: usize) -> Self {
2866 self * (rhs as f32)
2867 }
2868}
2869
2870impl Mul<Pixels> for usize {
2871 type Output = Pixels;
2872
2873 fn mul(self, rhs: Pixels) -> Pixels {
2874 rhs * self
2875 }
2876}
2877
2878impl MulAssign<f32> for Pixels {
2879 fn mul_assign(&mut self, rhs: f32) {
2880 self.0 *= rhs;
2881 }
2882}
2883
2884impl Display for Pixels {
2885 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2886 write!(f, "{}px", self.0)
2887 }
2888}
2889
2890impl Debug for Pixels {
2891 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2892 Display::fmt(self, f)
2893 }
2894}
2895
2896impl std::iter::Sum for Pixels {
2897 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
2898 iter.fold(Self::ZERO, |a, b| a + b)
2899 }
2900}
2901
2902impl<'a> std::iter::Sum<&'a Pixels> for Pixels {
2903 fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
2904 iter.fold(Self::ZERO, |a, b| a + *b)
2905 }
2906}
2907
2908impl TryFrom<&'_ str> for Pixels {
2909 type Error = anyhow::Error;
2910
2911 fn try_from(value: &'_ str) -> Result<Self, Self::Error> {
2912 value
2913 .strip_suffix("px")
2914 .context("expected 'px' suffix")
2915 .and_then(|number| Ok(number.parse()?))
2916 .map(Self)
2917 }
2918}
2919
2920impl Pixels {
2921 /// A length of zero pixels.
2922 pub const ZERO: Pixels = Pixels(0.0);
2923 /// The largest finite value that `Pixels` can hold.
2924 pub const MAX: Pixels = Pixels(f32::MAX);
2925 /// The smallest finite value that `Pixels` can hold.
2926 pub const MIN: Pixels = Pixels(f32::MIN);
2927
2928 /// Returns the raw `f32` value.
2929 pub fn as_f32(self) -> f32 {
2930 self.0
2931 }
2932
2933 /// Returns the largest whole number of pixels that is less than or equal to this value.
2934 ///
2935 /// # Examples
2936 ///
2937 /// ```
2938 /// # use gpui::px;
2939 /// assert_eq!(px(2.7).floor(), px(2.));
2940 /// assert_eq!(px(-2.3).floor(), px(-3.));
2941 /// ```
2942 pub fn floor(&self) -> Self {
2943 Self(self.0.floor())
2944 }
2945
2946 /// Returns this value rounded to the nearest whole pixel. Halfway values round away from zero.
2947 ///
2948 /// # Examples
2949 ///
2950 /// ```
2951 /// # use gpui::px;
2952 /// assert_eq!(px(2.4).round(), px(2.));
2953 /// assert_eq!(px(2.5).round(), px(3.));
2954 /// ```
2955 pub fn round(&self) -> Self {
2956 Self(self.0.round())
2957 }
2958
2959 /// Returns the smallest whole number of pixels that is greater than or equal to this value.
2960 ///
2961 /// # Examples
2962 ///
2963 /// ```
2964 /// # use gpui::px;
2965 /// assert_eq!(px(2.1).ceil(), px(3.));
2966 /// assert_eq!(px(-2.7).ceil(), px(-2.));
2967 /// ```
2968 pub fn ceil(&self) -> Self {
2969 Self(self.0.ceil())
2970 }
2971
2972 /// Multiplies this value by `factor`, producing [`ScaledPixels`].
2973 ///
2974 /// Pass the display's scale factor, such as `2.0` on a Retina display. The result isn't rounded.
2975 ///
2976 /// # Examples
2977 ///
2978 /// ```
2979 /// # use gpui::{px, ScaledPixels};
2980 /// assert_eq!(px(10.).scale(1.5), ScaledPixels::from(15.));
2981 /// ```
2982 #[must_use]
2983 pub fn scale(&self, factor: f32) -> ScaledPixels {
2984 ScaledPixels(self.0 * factor)
2985 }
2986
2987 /// Raises this value to the power `exponent`.
2988 ///
2989 /// # Examples
2990 ///
2991 /// ```
2992 /// # use gpui::px;
2993 /// assert_eq!(px(3.).pow(2.), px(9.));
2994 /// ```
2995 pub fn pow(&self, exponent: f32) -> Self {
2996 Self(self.0.powf(exponent))
2997 }
2998
2999 /// Returns the absolute value.
3000 ///
3001 /// # Examples
3002 ///
3003 /// ```
3004 /// # use gpui::px;
3005 /// assert_eq!(px(-3.).abs(), px(3.));
3006 /// ```
3007 pub fn abs(&self) -> Self {
3008 Self(self.0.abs())
3009 }
3010
3011 /// Returns `1.0` for positive values and `+0.0`, and `-1.0` for negative values and `-0.0`.
3012 ///
3013 /// The sign is a plain `f32`, not [`Pixels`].
3014 ///
3015 /// # Examples
3016 ///
3017 /// ```
3018 /// # use gpui::px;
3019 /// assert_eq!(px(-3.).signum(), -1.0);
3020 /// assert_eq!(px(3.).signum(), 1.0);
3021 /// ```
3022 pub fn signum(&self) -> f32 {
3023 self.0.signum()
3024 }
3025
3026 /// Returns the value as an `f64`.
3027 ///
3028 /// # Examples
3029 ///
3030 /// ```
3031 /// # use gpui::px;
3032 /// assert_eq!(px(1.5).to_f64(), 1.5);
3033 /// ```
3034 pub fn to_f64(self) -> f64 {
3035 self.0 as f64
3036 }
3037}
3038
3039impl Eq for Pixels {}
3040
3041impl PartialOrd for Pixels {
3042 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
3043 Some(self.cmp(other))
3044 }
3045}
3046
3047impl Ord for Pixels {
3048 fn cmp(&self, other: &Self) -> cmp::Ordering {
3049 self.0.total_cmp(&other.0)
3050 }
3051}
3052
3053impl std::hash::Hash for Pixels {
3054 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
3055 self.0.to_bits().hash(state);
3056 }
3057}
3058
3059impl From<f64> for Pixels {
3060 fn from(pixels: f64) -> Self {
3061 Pixels(pixels as f32)
3062 }
3063}
3064
3065impl From<f32> for Pixels {
3066 fn from(pixels: f32) -> Self {
3067 Pixels(pixels)
3068 }
3069}
3070
3071impl From<Pixels> for f32 {
3072 fn from(pixels: Pixels) -> Self {
3073 pixels.0
3074 }
3075}
3076
3077impl From<&Pixels> for f32 {
3078 fn from(pixels: &Pixels) -> Self {
3079 pixels.0
3080 }
3081}
3082
3083impl From<Pixels> for f64 {
3084 fn from(pixels: Pixels) -> Self {
3085 pixels.0 as f64
3086 }
3087}
3088
3089impl From<Pixels> for u32 {
3090 fn from(pixels: Pixels) -> Self {
3091 pixels.0 as u32
3092 }
3093}
3094
3095impl From<&Pixels> for u32 {
3096 fn from(pixels: &Pixels) -> Self {
3097 pixels.0 as u32
3098 }
3099}
3100
3101impl From<u32> for Pixels {
3102 fn from(pixels: u32) -> Self {
3103 Pixels(pixels as f32)
3104 }
3105}
3106
3107impl From<Pixels> for usize {
3108 fn from(pixels: Pixels) -> Self {
3109 pixels.0 as usize
3110 }
3111}
3112
3113impl From<usize> for Pixels {
3114 fn from(pixels: usize) -> Self {
3115 Pixels(pixels as f32)
3116 }
3117}
3118
3119/// A whole number of physical pixels on the display.
3120///
3121/// Device pixels are the pixels the hardware draws. Use them for sizes that are measured in
3122/// pixels of the output, such as the size of a rendered image or a window's drawable area.
3123/// Layout and painting use [`Pixels`]. Convert between the two with [`Size::to_device_pixels`]
3124/// and [`Size::to_pixels`], which apply the scale factor.
3125///
3126/// `DevicePixels` implements `Debug` as `"<n> px (device)"`.
3127///
3128/// # Examples
3129///
3130/// ```
3131/// use gpui::DevicePixels;
3132///
3133/// let pixels = DevicePixels(10);
3134/// assert_eq!(pixels.0, 10);
3135/// assert_eq!(DevicePixels::from(640_u32), DevicePixels(640));
3136/// ```
3137#[derive(
3138 Add,
3139 AddAssign,
3140 Clone,
3141 Copy,
3142 Default,
3143 Div,
3144 Eq,
3145 Hash,
3146 Ord,
3147 PartialEq,
3148 PartialOrd,
3149 Sub,
3150 SubAssign,
3151 Serialize,
3152 Deserialize,
3153)]
3154#[repr(transparent)]
3155pub struct DevicePixels(pub i32);
3156
3157impl DevicePixels {
3158 /// Returns the number of bytes needed for this many pixels.
3159 ///
3160 /// Multiply by the number of bytes each pixel takes, such as 4 for RGBA. Only use this on
3161 /// non-negative values: a negative count is cast to `u32` before multiplying, which gives a
3162 /// meaningless result.
3163 ///
3164 /// # Examples
3165 ///
3166 /// ```
3167 /// # use gpui::DevicePixels;
3168 /// let pixels = DevicePixels(10);
3169 /// let bytes_per_pixel = 4;
3170 /// let total_bytes = pixels.to_bytes(bytes_per_pixel);
3171 /// assert_eq!(total_bytes, 40);
3172 /// ```
3173 pub fn to_bytes(self, bytes_per_pixel: u8) -> u32 {
3174 self.0 as u32 * bytes_per_pixel as u32
3175 }
3176}
3177
3178impl fmt::Debug for DevicePixels {
3179 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3180 write!(f, "{} px (device)", self.0)
3181 }
3182}
3183
3184impl From<DevicePixels> for i32 {
3185 fn from(device_pixels: DevicePixels) -> Self {
3186 device_pixels.0
3187 }
3188}
3189
3190impl From<i32> for DevicePixels {
3191 fn from(device_pixels: i32) -> Self {
3192 DevicePixels(device_pixels)
3193 }
3194}
3195
3196impl From<u32> for DevicePixels {
3197 fn from(device_pixels: u32) -> Self {
3198 DevicePixels(device_pixels as i32)
3199 }
3200}
3201
3202impl From<DevicePixels> for u32 {
3203 fn from(device_pixels: DevicePixels) -> Self {
3204 device_pixels.0 as u32
3205 }
3206}
3207
3208impl From<DevicePixels> for u64 {
3209 fn from(device_pixels: DevicePixels) -> Self {
3210 device_pixels.0 as u64
3211 }
3212}
3213
3214impl From<u64> for DevicePixels {
3215 fn from(device_pixels: u64) -> Self {
3216 DevicePixels(device_pixels as i32)
3217 }
3218}
3219
3220impl From<DevicePixels> for usize {
3221 fn from(device_pixels: DevicePixels) -> Self {
3222 device_pixels.0 as usize
3223 }
3224}
3225
3226impl From<usize> for DevicePixels {
3227 fn from(device_pixels: usize) -> Self {
3228 DevicePixels(device_pixels as i32)
3229 }
3230}
3231
3232/// A logical length multiplied by the display's scale factor.
3233///
3234/// `ScaledPixels` is the result of [`Pixels::scale`]. It is a fraction-capable `f32` in the
3235/// space of physical pixels, so it can keep sub-pixel positions. Paint primitives in the scene
3236/// use this type. To get whole device pixels, round with [`ScaledPixels::round`] or convert with
3237/// `From<ScaledPixels> for DevicePixels`. Note that the conversion rounds up, unlike
3238/// [`Size::to_device_pixels`], which rounds to the nearest pixel.
3239///
3240/// # Examples
3241///
3242/// ```
3243/// use gpui::{DevicePixels, ScaledPixels, px};
3244///
3245/// let scaled: ScaledPixels = px(10.5).scale(2.);
3246/// assert_eq!(scaled, ScaledPixels::from(21.));
3247/// assert_eq!(scaled.round(), ScaledPixels::from(21.));
3248/// assert_eq!(DevicePixels::from(ScaledPixels(10.2)), DevicePixels(11));
3249/// ```
3250#[derive(Clone, Copy, Default, Add, AddAssign, Sub, SubAssign, Div, DivAssign, PartialEq)]
3251#[repr(transparent)]
3252pub struct ScaledPixels(pub f32);
3253
3254impl ScaledPixels {
3255 /// Returns the raw `f32` value.
3256 pub fn as_f32(self) -> f32 {
3257 self.0
3258 }
3259
3260 /// Returns the largest whole number that is less than or equal to this value.
3261 pub fn floor(&self) -> Self {
3262 Self(self.0.floor())
3263 }
3264
3265 /// Returns this value rounded to the nearest whole number. Halfway values round away from zero.
3266 ///
3267 /// # Examples
3268 ///
3269 /// ```
3270 /// # use gpui::ScaledPixels;
3271 /// assert_eq!(ScaledPixels(2.4).round(), ScaledPixels(2.));
3272 /// ```
3273 pub fn round(&self) -> Self {
3274 Self(self.0.round())
3275 }
3276
3277 /// Returns the smallest whole number that is greater than or equal to this value.
3278 pub fn ceil(&self) -> Self {
3279 Self(self.0.ceil())
3280 }
3281}
3282
3283impl Eq for ScaledPixels {}
3284
3285impl PartialOrd for ScaledPixels {
3286 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
3287 Some(self.cmp(other))
3288 }
3289}
3290
3291impl Ord for ScaledPixels {
3292 fn cmp(&self, other: &Self) -> cmp::Ordering {
3293 self.0.total_cmp(&other.0)
3294 }
3295}
3296
3297impl Debug for ScaledPixels {
3298 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3299 write!(f, "{}px (scaled)", self.0)
3300 }
3301}
3302
3303impl From<ScaledPixels> for DevicePixels {
3304 fn from(scaled: ScaledPixels) -> Self {
3305 DevicePixels(scaled.0.ceil() as i32)
3306 }
3307}
3308
3309impl From<DevicePixels> for ScaledPixels {
3310 fn from(device: DevicePixels) -> Self {
3311 ScaledPixels(device.0 as f32)
3312 }
3313}
3314
3315impl From<ScaledPixels> for f64 {
3316 fn from(scaled_pixels: ScaledPixels) -> Self {
3317 scaled_pixels.0 as f64
3318 }
3319}
3320
3321impl From<ScaledPixels> for u32 {
3322 fn from(pixels: ScaledPixels) -> Self {
3323 pixels.0 as u32
3324 }
3325}
3326
3327impl From<f32> for ScaledPixels {
3328 fn from(pixels: f32) -> Self {
3329 Self(pixels)
3330 }
3331}
3332
3333impl Div for ScaledPixels {
3334 type Output = f32;
3335
3336 fn div(self, rhs: Self) -> Self::Output {
3337 self.0 / rhs.0
3338 }
3339}
3340
3341impl std::ops::DivAssign for ScaledPixels {
3342 fn div_assign(&mut self, rhs: Self) {
3343 *self = Self(self.0 / rhs.0);
3344 }
3345}
3346
3347impl std::ops::RemAssign for ScaledPixels {
3348 fn rem_assign(&mut self, rhs: Self) {
3349 self.0 %= rhs.0;
3350 }
3351}
3352
3353impl std::ops::Rem for ScaledPixels {
3354 type Output = Self;
3355
3356 fn rem(self, rhs: Self) -> Self {
3357 Self(self.0 % rhs.0)
3358 }
3359}
3360
3361impl Mul<f32> for ScaledPixels {
3362 type Output = Self;
3363
3364 fn mul(self, rhs: f32) -> Self {
3365 Self(self.0 * rhs)
3366 }
3367}
3368
3369impl Mul<ScaledPixels> for f32 {
3370 type Output = ScaledPixels;
3371
3372 fn mul(self, rhs: ScaledPixels) -> Self::Output {
3373 rhs * self
3374 }
3375}
3376
3377impl Mul<usize> for ScaledPixels {
3378 type Output = Self;
3379
3380 fn mul(self, rhs: usize) -> Self {
3381 self * (rhs as f32)
3382 }
3383}
3384
3385impl Mul<ScaledPixels> for usize {
3386 type Output = ScaledPixels;
3387
3388 fn mul(self, rhs: ScaledPixels) -> ScaledPixels {
3389 rhs * self
3390 }
3391}
3392
3393impl MulAssign<f32> for ScaledPixels {
3394 fn mul_assign(&mut self, rhs: f32) {
3395 self.0 *= rhs;
3396 }
3397}
3398
3399/// A length in rems, a unit based on the font size of the window.
3400///
3401/// One rem is the window's root font size, 16 pixels by default. Change it with
3402/// [`crate::Window::set_rem_size`]. Lengths in rems scale with the user's text size, so prefer them for
3403/// spacing and text. [`rems`] creates a `Rems` value.
3404///
3405/// # Examples
3406///
3407/// ```
3408/// use gpui::{Pixels, Rems, px, rems};
3409///
3410/// let two_rems = rems(2.0);
3411/// assert_eq!(two_rems, Rems(2.0));
3412/// assert_eq!(two_rems.to_pixels(px(16.)), Pixels::from(32.));
3413/// ```
3414#[derive(Clone, Copy, Default, Add, Sub, Mul, Div, Neg, PartialEq)]
3415pub struct Rems(pub f32);
3416
3417impl Rems {
3418 /// A length of zero rems.
3419 pub const ZERO: Self = Self(0.0);
3420 /// Converts this length to pixels, given the size of one rem.
3421 ///
3422 /// # Examples
3423 ///
3424 /// ```
3425 /// # use gpui::{px, rems};
3426 /// assert_eq!(rems(0.25).to_pixels(px(16.)), px(4.));
3427 /// ```
3428 pub fn to_pixels(self, rem_size: Pixels) -> Pixels {
3429 self * rem_size
3430 }
3431 /// Converts `length` to rems, using the window's current rem size.
3432 ///
3433 /// # Examples
3434 ///
3435 /// ```
3436 /// # use gpui::{Context, IntoElement, Render, Rems, TestApp, Window, div, px};
3437 /// # struct Empty;
3438 /// # impl Render for Empty {
3439 /// # fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement { div() }
3440 /// # }
3441 /// # let mut app = TestApp::new();
3442 /// # let mut window = app.open_window(|_, _| Empty);
3443 /// window.update(|_, window, _| {
3444 /// // The default rem size is 16 pixels.
3445 /// assert_eq!(Rems::from_pixels(px(32.), window), Rems(2.0));
3446 /// });
3447 /// ```
3448 pub fn from_pixels(length: Pixels, window: &gpui::Window) -> Self {
3449 Self(length / window.rem_size())
3450 }
3451}
3452
3453impl Mul<Pixels> for Rems {
3454 type Output = Pixels;
3455
3456 fn mul(self, other: Pixels) -> Pixels {
3457 Pixels(self.0 * other.0)
3458 }
3459}
3460
3461impl AddAssign<Rems> for Rems {
3462 fn add_assign(&mut self, rhs: Rems) {
3463 self.0 += rhs.0
3464 }
3465}
3466
3467impl Display for Rems {
3468 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3469 write!(f, "{}rem", self.0)
3470 }
3471}
3472
3473impl Debug for Rems {
3474 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3475 Display::fmt(self, f)
3476 }
3477}
3478
3479impl TryFrom<&'_ str> for Rems {
3480 type Error = anyhow::Error;
3481
3482 fn try_from(value: &'_ str) -> Result<Self, Self::Error> {
3483 value
3484 .strip_suffix("rem")
3485 .context("expected 'rem' suffix")
3486 .and_then(|number| Ok(number.parse()?))
3487 .map(Self)
3488 }
3489}
3490
3491/// A length given as a fraction of a reference length.
3492///
3493/// `1.0` is the full reference length and `0.5` is half of it. Fractions can be negative or
3494/// greater than `1.0`. Create one with [`relative`]. The reference length is supplied when the
3495/// value is resolved, for example by [`Relative::to_pixels`]. [`Relative`] displays as a
3496/// percentage, so `relative(0.5)` shows as `50%`.
3497///
3498/// # Examples
3499///
3500/// ```
3501/// use gpui::{AbsoluteLength, Relative, px, rems};
3502///
3503/// let half = Relative::from(0.5);
3504/// assert_eq!(half.to_pixels(AbsoluteLength::Rems(rems(2.)), px(16.)), px(16.));
3505/// let base_size = AbsoluteLength::Pixels(px(200.0));
3506///
3507/// assert_eq!(half.to_pixels(base_size, px(16.0)), px(100.0));
3508/// assert_eq!(half.to_string(), "50%");
3509/// ```
3510#[derive(Clone, Copy, Default, Add, Sub, Mul, Div, Neg, PartialEq)]
3511#[repr(transparent)]
3512pub struct Relative(pub(crate) f32);
3513
3514impl Relative {
3515 /// A fraction of zero.
3516 pub const ZERO: Self = Self(0.0);
3517
3518 /// Returns the raw fraction.
3519 pub fn as_f32(self) -> f32 {
3520 self.0
3521 }
3522
3523 /// Resolves this fraction of `base_size` to pixels.
3524 ///
3525 /// When `base_size` is in rems, `rem_size` gives the pixel size of one rem.
3526 ///
3527 /// # Examples
3528 ///
3529 /// ```
3530 /// # use gpui::{AbsoluteLength, px, relative, rems};
3531 /// let base = AbsoluteLength::Rems(rems(2.));
3532 /// assert_eq!(relative(0.5).to_pixels(base, px(16.)), px(16.));
3533 /// ```
3534 pub fn to_pixels(self, base_size: AbsoluteLength, rem_size: Pixels) -> Pixels {
3535 match base_size {
3536 AbsoluteLength::Pixels(pixels) => pixels * self.0,
3537 AbsoluteLength::Rems(rems) => rems * rem_size * self.0,
3538 }
3539 }
3540}
3541
3542impl From<f32> for Relative {
3543 fn from(fraction: f32) -> Self {
3544 Self(fraction)
3545 }
3546}
3547
3548impl AddAssign<Relative> for Relative {
3549 fn add_assign(&mut self, rhs: Relative) {
3550 self.0 += rhs.0;
3551 }
3552}
3553
3554impl Display for Relative {
3555 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3556 write!(f, "{}%", self.0 * 100.0)
3557 }
3558}
3559
3560impl Debug for Relative {
3561 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3562 Display::fmt(self, f)
3563 }
3564}
3565
3566impl TryFrom<&'_ str> for Relative {
3567 type Error = anyhow::Error;
3568
3569 fn try_from(value: &'_ str) -> Result<Self, Self::Error> {
3570 value
3571 .strip_suffix('%')
3572 .context("expected '%' suffix")
3573 .and_then(|number| Ok(number.parse::<f32>()?))
3574 .map(|percentage| Self(percentage / 100.0))
3575 }
3576}
3577
3578/// A length that doesn't depend on the parent: pixels or rems.
3579///
3580/// Pixels are fixed on screen. Rems depend on the window's rem size, so they track the user's
3581/// text size. Use [`AbsoluteLength::to_pixels`] to resolve a value for layout.
3582///
3583/// # Examples
3584///
3585/// ```
3586/// use gpui::{AbsoluteLength, Pixels, Rems, px, rems};
3587///
3588/// let fixed = AbsoluteLength::from(px(12.));
3589/// let scaled = AbsoluteLength::from(rems(0.75));
3590/// assert_eq!(fixed.to_pixels(px(16.)), Pixels::from(12.));
3591/// assert_eq!(scaled.to_pixels(px(16.)), Pixels::from(12.));
3592/// ```
3593#[derive(Clone, Copy, Neg, PartialEq)]
3594pub enum AbsoluteLength {
3595 /// A length in logical pixels.
3596 Pixels(Pixels),
3597 /// A length in rems.
3598 Rems(Rems),
3599}
3600
3601impl AbsoluteLength {
3602 /// Returns `true` if the length is zero, whether in pixels or rems.
3603 ///
3604 /// # Examples
3605 ///
3606 /// ```
3607 /// use gpui::{AbsoluteLength, px, rems};
3608 /// assert!(AbsoluteLength::from(px(0.)).is_zero());
3609 /// assert!(!AbsoluteLength::from(rems(0.5)).is_zero());
3610 /// ```
3611 pub fn is_zero(&self) -> bool {
3612 match self {
3613 AbsoluteLength::Pixels(px) => px.0 == 0.0,
3614 AbsoluteLength::Rems(rems) => rems.0 == 0.0,
3615 }
3616 }
3617}
3618
3619impl From<Pixels> for AbsoluteLength {
3620 fn from(pixels: Pixels) -> Self {
3621 AbsoluteLength::Pixels(pixels)
3622 }
3623}
3624
3625impl From<Rems> for AbsoluteLength {
3626 fn from(rems: Rems) -> Self {
3627 AbsoluteLength::Rems(rems)
3628 }
3629}
3630
3631impl AbsoluteLength {
3632 /// Converts this length to pixels. Rems are multiplied by `rem_size`.
3633 ///
3634 /// # Examples
3635 ///
3636 /// ```
3637 /// # use gpui::{AbsoluteLength, Pixels, Rems};
3638 /// let length_in_pixels = AbsoluteLength::Pixels(Pixels::from(42.0));
3639 /// let length_in_rems = AbsoluteLength::Rems(Rems(2.0));
3640 /// let rem_size = Pixels::from(16.0);
3641 ///
3642 /// assert_eq!(length_in_pixels.to_pixels(rem_size), Pixels::from(42.0));
3643 /// assert_eq!(length_in_rems.to_pixels(rem_size), Pixels::from(32.0));
3644 /// ```
3645 pub fn to_pixels(self, rem_size: Pixels) -> Pixels {
3646 match self {
3647 AbsoluteLength::Pixels(pixels) => pixels,
3648 AbsoluteLength::Rems(rems) => rems.to_pixels(rem_size),
3649 }
3650 }
3651
3652 /// Converts this length to rems. Pixels are divided by `rem_size`.
3653 ///
3654 /// # Examples
3655 ///
3656 /// ```
3657 /// # use gpui::{AbsoluteLength, Pixels, Rems};
3658 /// let length = AbsoluteLength::Pixels(Pixels::from(32.0));
3659 /// assert_eq!(length.to_rems(Pixels::from(16.0)), Rems(2.0));
3660 /// ```
3661 pub fn to_rems(self, rem_size: Pixels) -> Rems {
3662 match self {
3663 AbsoluteLength::Pixels(pixels) => Rems(pixels.0 / rem_size.0),
3664 AbsoluteLength::Rems(rems) => rems,
3665 }
3666 }
3667}
3668
3669impl Default for AbsoluteLength {
3670 fn default() -> Self {
3671 px(0.).into()
3672 }
3673}
3674
3675impl Display for AbsoluteLength {
3676 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3677 match self {
3678 Self::Pixels(pixels) => write!(f, "{pixels}"),
3679 Self::Rems(rems) => write!(f, "{rems}"),
3680 }
3681 }
3682}
3683
3684impl Debug for AbsoluteLength {
3685 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3686 Display::fmt(self, f)
3687 }
3688}
3689
3690const EXPECTED_ABSOLUTE_LENGTH: &str = "number with 'px' or 'rem' suffix";
3691
3692impl TryFrom<&'_ str> for AbsoluteLength {
3693 type Error = anyhow::Error;
3694
3695 fn try_from(value: &'_ str) -> Result<Self, Self::Error> {
3696 if let Ok(pixels) = value.try_into() {
3697 Ok(Self::Pixels(pixels))
3698 } else if let Ok(rems) = value.try_into() {
3699 Ok(Self::Rems(rems))
3700 } else {
3701 Err(anyhow!(
3702 "invalid AbsoluteLength '{value}', expected {EXPECTED_ABSOLUTE_LENGTH}"
3703 ))
3704 }
3705 }
3706}
3707
3708impl JsonSchema for AbsoluteLength {
3709 fn schema_name() -> Cow<'static, str> {
3710 "AbsoluteLength".into()
3711 }
3712
3713 fn json_schema(_generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
3714 json_schema!({
3715 "type": "string",
3716 "pattern": r"^-?\d+(\.\d+)?(px|rem)$"
3717 })
3718 }
3719}
3720
3721impl<'de> Deserialize<'de> for AbsoluteLength {
3722 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
3723 struct StringVisitor;
3724
3725 impl de::Visitor<'_> for StringVisitor {
3726 type Value = AbsoluteLength;
3727
3728 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
3729 write!(f, "{EXPECTED_ABSOLUTE_LENGTH}")
3730 }
3731
3732 fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
3733 AbsoluteLength::try_from(value).map_err(E::custom)
3734 }
3735 }
3736
3737 deserializer.deserialize_str(StringVisitor)
3738 }
3739}
3740
3741impl Serialize for AbsoluteLength {
3742 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
3743 where
3744 S: Serializer,
3745 {
3746 serializer.serialize_str(&format!("{self}"))
3747 }
3748}
3749
3750/// A length with a value: an absolute length, or a fraction of the parent.
3751///
3752/// Unlike [`Length`], it can't be `auto`. Layout resolves a fraction against the parent's size
3753/// with [`DefiniteLength::to_pixels`].
3754///
3755/// # Examples
3756///
3757/// ```
3758/// use gpui::{DefiniteLength, Pixels, px, relative};
3759///
3760/// let half_of_parent = DefiniteLength::from(relative(0.5));
3761/// let fixed = DefiniteLength::from(px(10.));
3762/// assert_eq!(fixed, DefiniteLength::from(Pixels::from(10.)));
3763/// assert_ne!(half_of_parent, fixed);
3764/// ```
3765#[derive(Clone, Copy, Neg, PartialEq)]
3766pub enum DefiniteLength {
3767 /// A fixed length in pixels or rems.
3768 Absolute(AbsoluteLength),
3769 /// A fraction of the parent's size.
3770 Relative(Relative),
3771}
3772
3773impl DefiniteLength {
3774 /// Converts this length to pixels.
3775 ///
3776 /// An absolute length converts directly. A fraction is multiplied by `base_size`, which is the
3777 /// parent's size along the axis this length applies to. `rem_size` is the pixel size of one rem.
3778 ///
3779 /// # Examples
3780 ///
3781 /// ```
3782 /// # use gpui::{DefiniteLength, AbsoluteLength, Pixels, px, relative, rems};
3783 /// let length_in_pixels = DefiniteLength::Absolute(AbsoluteLength::Pixels(px(42.0)));
3784 /// let length_in_rems = DefiniteLength::Absolute(AbsoluteLength::Rems(rems(2.0)));
3785 /// let length_as_fraction = DefiniteLength::from(relative(0.5));
3786 /// let base_size = AbsoluteLength::Pixels(px(100.0));
3787 /// let rem_size = px(16.0);
3788 ///
3789 /// assert_eq!(length_in_pixels.to_pixels(base_size, rem_size), Pixels::from(42.0));
3790 /// assert_eq!(length_in_rems.to_pixels(base_size, rem_size), Pixels::from(32.0));
3791 /// assert_eq!(length_as_fraction.to_pixels(base_size, rem_size), Pixels::from(50.0));
3792 /// ```
3793 pub fn to_pixels(self, base_size: AbsoluteLength, rem_size: Pixels) -> Pixels {
3794 match self {
3795 DefiniteLength::Absolute(size) => size.to_pixels(rem_size),
3796 DefiniteLength::Relative(relative) => relative.to_pixels(base_size, rem_size),
3797 }
3798 }
3799}
3800
3801impl Debug for DefiniteLength {
3802 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3803 Display::fmt(self, f)
3804 }
3805}
3806
3807impl Display for DefiniteLength {
3808 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3809 match self {
3810 DefiniteLength::Absolute(length) => write!(f, "{length}"),
3811 DefiniteLength::Relative(relative) => write!(f, "{relative}"),
3812 }
3813 }
3814}
3815
3816const EXPECTED_DEFINITE_LENGTH: &str = "expected number with 'px', 'rem', or '%' suffix";
3817
3818impl TryFrom<&'_ str> for DefiniteLength {
3819 type Error = anyhow::Error;
3820
3821 fn try_from(value: &'_ str) -> Result<Self, Self::Error> {
3822 if value.ends_with('%') {
3823 let relative = Relative::try_from(value).with_context(|| {
3824 format!("invalid DefiniteLength '{value}', expected {EXPECTED_DEFINITE_LENGTH}")
3825 })?;
3826 Ok(DefiniteLength::Relative(relative))
3827 } else if let Ok(absolute_length) = value.try_into() {
3828 Ok(DefiniteLength::Absolute(absolute_length))
3829 } else {
3830 Err(anyhow!(
3831 "invalid DefiniteLength '{value}', expected {EXPECTED_DEFINITE_LENGTH}"
3832 ))
3833 }
3834 }
3835}
3836
3837impl JsonSchema for DefiniteLength {
3838 fn schema_name() -> Cow<'static, str> {
3839 "DefiniteLength".into()
3840 }
3841
3842 fn json_schema(_generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
3843 json_schema!({
3844 "type": "string",
3845 "pattern": r"^-?\d+(\.\d+)?(px|rem|%)$"
3846 })
3847 }
3848}
3849
3850impl<'de> Deserialize<'de> for DefiniteLength {
3851 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
3852 struct StringVisitor;
3853
3854 impl de::Visitor<'_> for StringVisitor {
3855 type Value = DefiniteLength;
3856
3857 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
3858 write!(f, "{EXPECTED_DEFINITE_LENGTH}")
3859 }
3860
3861 fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
3862 DefiniteLength::try_from(value).map_err(E::custom)
3863 }
3864 }
3865
3866 deserializer.deserialize_str(StringVisitor)
3867 }
3868}
3869
3870impl Serialize for DefiniteLength {
3871 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
3872 where
3873 S: Serializer,
3874 {
3875 serializer.serialize_str(&format!("{self}"))
3876 }
3877}
3878
3879impl From<Pixels> for DefiniteLength {
3880 fn from(pixels: Pixels) -> Self {
3881 Self::Absolute(pixels.into())
3882 }
3883}
3884
3885impl From<Rems> for DefiniteLength {
3886 fn from(rems: Rems) -> Self {
3887 Self::Absolute(rems.into())
3888 }
3889}
3890
3891impl From<Relative> for DefiniteLength {
3892 fn from(relative: Relative) -> Self {
3893 Self::Relative(relative)
3894 }
3895}
3896
3897impl From<AbsoluteLength> for DefiniteLength {
3898 fn from(length: AbsoluteLength) -> Self {
3899 Self::Absolute(length)
3900 }
3901}
3902
3903impl Default for DefiniteLength {
3904 fn default() -> Self {
3905 Self::Absolute(AbsoluteLength::default())
3906 }
3907}
3908
3909/// A length that can be a definite value or `auto`.
3910///
3911/// `auto` lets layout size the element from its content or its container. Style methods that
3912/// accept a size take a `Length`, so they accept `px`, `rems`, `relative` and `auto` values.
3913///
3914/// # Examples
3915///
3916/// ```
3917/// use gpui::{Length, auto, px, relative};
3918///
3919/// let fixed: Length = px(120.).into();
3920/// let fill: Length = relative(1.).into();
3921/// assert_eq!(auto(), Length::Auto);
3922/// assert_ne!(fixed, fill);
3923/// ```
3924#[derive(Clone, Copy, PartialEq)]
3925pub enum Length {
3926 /// A length with a value, in pixels, rems or a fraction of the parent.
3927 Definite(DefiniteLength),
3928 /// The size is chosen by the layout algorithm.
3929 Auto,
3930}
3931
3932impl Debug for Length {
3933 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3934 Display::fmt(self, f)
3935 }
3936}
3937
3938impl Display for Length {
3939 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3940 match self {
3941 Length::Definite(definite_length) => write!(f, "{}", definite_length),
3942 Length::Auto => write!(f, "auto"),
3943 }
3944 }
3945}
3946
3947const EXPECTED_LENGTH: &str = "expected 'auto' or number with 'px', 'rem', or '%' suffix";
3948
3949impl TryFrom<&'_ str> for Length {
3950 type Error = anyhow::Error;
3951
3952 fn try_from(value: &'_ str) -> Result<Self, Self::Error> {
3953 if value == "auto" {
3954 Ok(Length::Auto)
3955 } else if let Ok(definite_length) = value.try_into() {
3956 Ok(Length::Definite(definite_length))
3957 } else {
3958 Err(anyhow!(
3959 "invalid Length '{value}', expected {EXPECTED_LENGTH}"
3960 ))
3961 }
3962 }
3963}
3964
3965impl JsonSchema for Length {
3966 fn schema_name() -> Cow<'static, str> {
3967 "Length".into()
3968 }
3969
3970 fn json_schema(_generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
3971 json_schema!({
3972 "type": "string",
3973 "pattern": r"^(auto|-?\d+(\.\d+)?(px|rem|%))$"
3974 })
3975 }
3976}
3977
3978impl<'de> Deserialize<'de> for Length {
3979 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
3980 struct StringVisitor;
3981
3982 impl de::Visitor<'_> for StringVisitor {
3983 type Value = Length;
3984
3985 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
3986 write!(f, "{EXPECTED_LENGTH}")
3987 }
3988
3989 fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
3990 Length::try_from(value).map_err(E::custom)
3991 }
3992 }
3993
3994 deserializer.deserialize_str(StringVisitor)
3995 }
3996}
3997
3998impl Serialize for Length {
3999 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
4000 where
4001 S: Serializer,
4002 {
4003 serializer.serialize_str(&format!("{self}"))
4004 }
4005}
4006
4007/// Creates a [`Relative`] length, a fraction of the reference length.
4008///
4009/// A fraction of `1.0` is the full reference length. Values outside `0.0` to `1.0` give lengths
4010/// below zero or above the full reference length.
4011///
4012/// # Examples
4013///
4014/// ```
4015/// use gpui::{AbsoluteLength, px, relative};
4016///
4017/// let full = relative(1.);
4018/// assert_eq!(full.as_f32(), 1.0);
4019/// assert_eq!(full.to_pixels(AbsoluteLength::Pixels(px(200.)), px(16.)), px(200.));
4020/// ```
4021pub const fn relative(fraction: f32) -> Relative {
4022 Relative(fraction)
4023}
4024
4025/// Returns the golden ratio, about `1.618`, as a [`Relative`] length.
4026///
4027/// # Examples
4028///
4029/// ```
4030/// use gpui::phi;
4031/// let expected = (1.0 + 5f32.sqrt()) / 2.0;
4032/// assert!((phi().as_f32() - expected).abs() < 1e-6);
4033/// ```
4034pub const fn phi() -> Relative {
4035 relative(GOLDEN_RATIO)
4036}
4037
4038/// Creates a [`Rems`] length.
4039///
4040/// # Examples
4041///
4042/// ```
4043/// use gpui::{Rems, rems};
4044/// assert_eq!(rems(1.5), Rems(1.5));
4045/// ```
4046pub const fn rems(rems: f32) -> Rems {
4047 Rems(rems)
4048}
4049
4050/// Creates a [`Pixels`] length, the usual way to write a fixed size in logical pixels.
4051///
4052/// # Examples
4053///
4054/// ```
4055/// use gpui::{Pixels, px};
4056/// assert_eq!(px(12.), Pixels::from(12.));
4057/// ```
4058pub const fn px(pixels: f32) -> Pixels {
4059 Pixels(pixels)
4060}
4061
4062/// Returns [`Length::Auto`], which lets layout choose the size from the context.
4063///
4064/// # Examples
4065///
4066/// ```
4067/// use gpui::{Length, auto};
4068/// assert_eq!(auto(), Length::Auto);
4069/// ```
4070pub const fn auto() -> Length {
4071 Length::Auto
4072}
4073
4074impl From<Pixels> for Length {
4075 fn from(pixels: Pixels) -> Self {
4076 Self::Definite(pixels.into())
4077 }
4078}
4079
4080impl From<Rems> for Length {
4081 fn from(rems: Rems) -> Self {
4082 Self::Definite(rems.into())
4083 }
4084}
4085
4086impl From<Relative> for Length {
4087 fn from(relative: Relative) -> Self {
4088 Self::Definite(relative.into())
4089 }
4090}
4091
4092impl From<DefiniteLength> for Length {
4093 fn from(length: DefiniteLength) -> Self {
4094 Self::Definite(length)
4095 }
4096}
4097
4098impl From<AbsoluteLength> for Length {
4099 fn from(length: AbsoluteLength) -> Self {
4100 Self::Definite(length.into())
4101 }
4102}
4103
4104impl Default for Length {
4105 fn default() -> Self {
4106 Self::Definite(DefiniteLength::default())
4107 }
4108}
4109
4110impl From<()> for Length {
4111 fn from(_: ()) -> Self {
4112 Self::Definite(DefiniteLength::default())
4113 }
4114}
4115
4116/// The rows and columns that a grid item occupies.
4117///
4118/// Set this on a grid item to place it. Each range runs from its start placement to its end
4119/// placement, as in CSS `grid-row` and `grid-column`.
4120///
4121/// # Examples
4122///
4123/// ```
4124/// use gpui::{GridLocation, GridPlacement};
4125///
4126/// let location = GridLocation {
4127/// row: GridPlacement::Line(1)..GridPlacement::Span(2),
4128/// column: GridPlacement::Auto..GridPlacement::Auto,
4129/// };
4130/// assert_eq!(location.row.start, GridPlacement::Line(1));
4131/// ```
4132#[derive(Clone, PartialEq, Debug, Serialize, Deserialize, JsonSchema, Default)]
4133pub struct GridLocation {
4134 /// The rows this item uses within the grid.
4135 pub row: Range<GridPlacement>,
4136 /// The columns this item uses within the grid.
4137 pub column: Range<GridPlacement>,
4138}
4139
4140/// Where a grid item starts or ends along one axis of a grid.
4141///
4142/// # Examples
4143///
4144/// ```
4145/// use gpui::GridPlacement;
4146///
4147/// assert_eq!(GridPlacement::default(), GridPlacement::Auto);
4148/// assert_eq!(GridPlacement::Span(3), GridPlacement::Span(3));
4149/// ```
4150#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize, JsonSchema, Default)]
4151pub enum GridPlacement {
4152 /// The grid line with this index, numbered as in CSS grid line placement.
4153 Line(i16),
4154 /// The number of grid tracks to span, measured from the other end of the range.
4155 Span(u16),
4156 /// Lets the layout algorithm pick the grid line.
4157 #[default]
4158 Auto,
4159}
4160
4161impl From<GridPlacement> for taffy::GridPlacement {
4162 fn from(placement: GridPlacement) -> Self {
4163 match placement {
4164 GridPlacement::Line(index) => taffy::GridPlacement::from_line_index(index),
4165 GridPlacement::Span(span) => taffy::GridPlacement::from_span(span),
4166 GridPlacement::Auto => taffy::GridPlacement::Auto,
4167 }
4168 }
4169}
4170
4171/// Returns half of a value, for centering and midpoints.
4172///
4173/// Geometry code uses this trait to find midpoints and centers for each unit. For integers, the
4174/// result truncates toward zero, so `half` of `7` is `3`.
4175///
4176/// # Examples
4177///
4178/// ```
4179/// use gpui::{Half, px};
4180///
4181/// assert_eq!(7_i32.half(), 3);
4182/// assert_eq!(px(7.).half(), px(3.5));
4183/// ```
4184pub trait Half {
4185 /// Returns half of this value.
4186 fn half(&self) -> Self;
4187}
4188
4189impl Half for i32 {
4190 fn half(&self) -> Self {
4191 self / 2
4192 }
4193}
4194
4195impl Half for f32 {
4196 fn half(&self) -> Self {
4197 self / 2.
4198 }
4199}
4200
4201impl Half for DevicePixels {
4202 fn half(&self) -> Self {
4203 Self(self.0 / 2)
4204 }
4205}
4206
4207impl Half for ScaledPixels {
4208 fn half(&self) -> Self {
4209 Self(self.0 / 2.)
4210 }
4211}
4212
4213impl Half for Pixels {
4214 fn half(&self) -> Self {
4215 Self(self.0 / 2.)
4216 }
4217}
4218
4219impl Half for Rems {
4220 fn half(&self) -> Self {
4221 Self(self.0 / 2.)
4222 }
4223}
4224
4225impl Half for Relative {
4226 fn half(&self) -> Self {
4227 Self(self.0 / 2.)
4228 }
4229}
4230
4231/// Checks whether a length or geometry value is zero.
4232///
4233/// Implemented for the length types and for [`Point`], [`Size`], [`Bounds`] and [`Corners`].
4234/// For a [`Size`], the check is `true` when either side is zero, because the area is then zero.
4235/// For a [`Point`], both coordinates must be zero. For [`Corners`], all four corners must be zero.
4236///
4237/// # Examples
4238///
4239/// ```
4240/// use gpui::{IsZero, px, size};
4241///
4242/// assert!(px(0.).is_zero());
4243/// assert!(size(px(10.), px(0.)).is_zero());
4244/// assert!(!size(px(10.), px(5.)).is_zero());
4245/// ```
4246pub trait IsZero {
4247 /// Returns `true` if this value is zero.
4248 fn is_zero(&self) -> bool;
4249}
4250
4251impl IsZero for DevicePixels {
4252 fn is_zero(&self) -> bool {
4253 self.0 == 0
4254 }
4255}
4256
4257impl IsZero for ScaledPixels {
4258 fn is_zero(&self) -> bool {
4259 self.0 == 0.
4260 }
4261}
4262
4263impl IsZero for Pixels {
4264 fn is_zero(&self) -> bool {
4265 self.0 == 0.
4266 }
4267}
4268
4269impl IsZero for Rems {
4270 fn is_zero(&self) -> bool {
4271 self.0 == 0.
4272 }
4273}
4274
4275impl IsZero for Relative {
4276 fn is_zero(&self) -> bool {
4277 self.0 == 0.
4278 }
4279}
4280
4281impl IsZero for AbsoluteLength {
4282 fn is_zero(&self) -> bool {
4283 match self {
4284 AbsoluteLength::Pixels(pixels) => pixels.is_zero(),
4285 AbsoluteLength::Rems(rems) => rems.is_zero(),
4286 }
4287 }
4288}
4289
4290impl IsZero for DefiniteLength {
4291 fn is_zero(&self) -> bool {
4292 match self {
4293 DefiniteLength::Absolute(length) => length.is_zero(),
4294 DefiniteLength::Relative(relative) => relative.is_zero(),
4295 }
4296 }
4297}
4298
4299impl IsZero for Length {
4300 fn is_zero(&self) -> bool {
4301 match self {
4302 Length::Definite(length) => length.is_zero(),
4303 Length::Auto => false,
4304 }
4305 }
4306}
4307
4308impl<T: IsZero + Clone + Debug + Default + PartialEq> IsZero for Point<T> {
4309 fn is_zero(&self) -> bool {
4310 self.x.is_zero() && self.y.is_zero()
4311 }
4312}
4313
4314impl<T> IsZero for Size<T>
4315where
4316 T: IsZero + Clone + Debug + Default + PartialEq,
4317{
4318 fn is_zero(&self) -> bool {
4319 self.width.is_zero() || self.height.is_zero()
4320 }
4321}
4322
4323impl<T: IsZero + Clone + Debug + Default + PartialEq> IsZero for Bounds<T> {
4324 fn is_zero(&self) -> bool {
4325 self.size.is_zero()
4326 }
4327}
4328
4329impl<T> IsZero for Corners<T>
4330where
4331 T: IsZero + Clone + Debug + Default + PartialEq,
4332{
4333 fn is_zero(&self) -> bool {
4334 self.top_left.is_zero()
4335 && self.top_right.is_zero()
4336 && self.bottom_right.is_zero()
4337 && self.bottom_left.is_zero()
4338 }
4339}
4340
4341#[cfg(test)]
4342mod tests {
4343 use super::*;
4344
4345 #[test]
4346 fn test_bounds_intersects() {
4347 let bounds1 = Bounds {
4348 origin: Point { x: 0.0, y: 0.0 },
4349 size: Size {
4350 width: 5.0,
4351 height: 5.0,
4352 },
4353 };
4354 let bounds2 = Bounds {
4355 origin: Point { x: 4.0, y: 4.0 },
4356 size: Size {
4357 width: 5.0,
4358 height: 5.0,
4359 },
4360 };
4361 let bounds3 = Bounds {
4362 origin: Point { x: 10.0, y: 10.0 },
4363 size: Size {
4364 width: 5.0,
4365 height: 5.0,
4366 },
4367 };
4368
4369 // Test Case 1: Intersecting bounds
4370 assert!(bounds1.intersects(&bounds2));
4371
4372 // Test Case 2: Non-Intersecting bounds
4373 assert!(!bounds1.intersects(&bounds3));
4374
4375 // Test Case 3: Bounds intersecting with themselves
4376 assert!(bounds1.intersects(&bounds1));
4377 }
4378}