Skip to content

Geometry

The four value types layout and drawing share: a position, a size, a rectangle and an inset. All coordinates are i32 logical screen pixels in the current orientation, the same space the host draws in, with the origin at the top-left corner and y growing downwards.

Never assume a panel size or shape. The panels this runs on are portrait and landscape, from 296x128 to 800x480; ask Renderer::screen_size, or better, lay out from Theme::content_area. Writing a widget uses all four.

PointA position on screen.
SizeA width and height, clamped at zero by every constructor.
RectA positioned, sized region.
InsetsSpace inset equally or individually on each edge.

A rect's right and bottom edges are outside it. A rect at x with width w covers the columns x to x + w - 1; Rect::right is x + w, the first column outside. contains and intersects agree on this, so two rects that merely touch do not overlap, and rects laid edge to edge tile without a shared pixel.

A size never goes below zero. Size::new, Size::shrink and everything built on them clamp each dimension at zero, so a layout that over-subtracts gives an empty rectangle rather than an inverted one. A position is not clamped, and neither is an inset.

All four types are Copy, Default (all zeros), Debug and Eq.

A position on screen.

pub struct Point
Field or constantAbstract
Point::xPixels from the left edge.
Point::yPixels from the top edge.
Point::ORIGINThe top-left corner of the screen.

A point may be negative or beyond the panel: a view scrolled up past the top of its viewport renders at a negative y.

Example — moving a point

Rust
use xpui::Point;
let origin = Point::new(16, 60);
assert_eq!(origin.offset(4, -8), Point::new(20, 52));
assert_eq!(Point::default(), Point::ORIGIN);

A point at x, y.

pub const fn new(x: i32, y: i32) -> Self

This point moved by dx/dy.

pub const fn offset(self, dx: i32, dy: i32) -> Self

Either may be negative. A widget uses it to place a child inside its own padding: origin.offset(pad, pad).

See also: Rect, Rect::contains

A width and height, clamped at zero by every constructor.

pub struct Size
Field or constantAbstract
Size::widthPixels across.
Size::heightPixels down.
Size::ZERONothing at all.

A size is what a view's measure receives and what its size answers. It has no position: a Rect pairs one with an origin.

Example — clamping at zero

Rust
use xpui::Size;
assert_eq!(Size::new(-10, 20), Size::new(0, 20));
assert_eq!(Size::new(0, 0), Size::ZERO);
assert!(Size::new(-10, 20).is_empty());

A size of width by height, each clamped at zero.

pub fn new(width: i32, height: i32) -> Self

This size shrunk by dw/dh, clamped at zero.

pub fn shrink(self, dw: i32, dh: i32) -> Self

It saturates at zero rather than going negative. A negative dw or dh grows the size instead.

Example — shrinking past zero

Rust
use xpui::Size;
let available = Size::new(100, 40);
assert_eq!(available.shrink(32, 8), Size::new(68, 32));
// Over-subtracting saturates, one dimension at a time.
assert_eq!(available.shrink(120, 0), Size::new(0, 40));
// A negative amount grows it.
assert_eq!(available.shrink(-10, -10), Size::new(110, 50));

Whether either dimension is zero, so nothing could be drawn in it.

pub fn is_empty(self) -> bool

Example — a row with no height is empty

Rust
use xpui::Size;
assert!(Size::new(200, 0).is_empty());
assert!(Size::ZERO.is_empty());
assert!(!Size::new(1, 1).is_empty());

See also: Rect, Insets

A positioned, sized region.

pub struct Rect
FieldAbstract
Rect::originThe top-left corner.
Rect::sizeThe width and height.

The origin may be anywhere, negative included; the size is clamped at zero by Rect::new and Rect::inset. Its right and bottom edges are outside it: see Edges and clamping. A view builds one from what render receives, Rect { origin, size: self.size }.

Example — edges

Rust
use xpui::{Point, Rect, Size};
let card = Rect::new(10, 20, 200, 80);
assert_eq!((card.x(), card.y()), (10, 20));
assert_eq!((card.width(), card.height()), (200, 80));
assert_eq!((card.right(), card.bottom()), (210, 100));
assert_eq!(card.origin, Point::new(10, 20));
assert_eq!(card.size, Size::new(200, 80));
// A negative size is clamped; a negative origin is not.
assert_eq!(Rect::new(-5, 0, -1, 10).size, Size::new(0, 10));
assert_eq!(Rect::new(-5, 0, -1, 10).x(), -5);

Example — hit-testing a tap

Rust
use xpui::{Point, Rect};
let button = Rect::new(0, 0, 200, 80);
assert!(button.contains(Point::new(0, 0))); // the top-left corner is inside
assert!(button.contains(Point::new(199, 79))); // the last pixel is inside
assert!(!button.contains(Point::new(200, 10))); // the right edge is outside
assert!(!button.contains(Point::new(10, 80))); // the bottom edge is outside

A rect with its top-left corner at x, y.

pub fn new(x: i32, y: i32, width: i32, height: i32) -> Self

width and height are clamped at zero, as by Size::new.

The left edge.

pub const fn x(&self) -> i32

The top edge.

pub const fn y(&self) -> i32

Pixels across.

pub const fn width(&self) -> i32

Pixels down.

pub const fn height(&self) -> i32

The first column outside the rect.

pub const fn right(&self) -> i32

x() + width(). The last column inside is one less.

The first row outside the rect.

pub const fn bottom(&self) -> i32

y() + height(). The next row of a stack starts here, with no gap and no overlap.

Example — stacking rows edge to edge

Rust
use xpui::Rect;
let first = Rect::new(16, 60, 448, 40);
let second = Rect::new(16, first.bottom(), 448, 40);
assert_eq!(second.y(), 100);
assert!(!first.intersects(second));

This rect pulled inward on every edge by insets.

pub fn inset(&self, insets: Insets) -> Self

The origin moves by left and top, and the size shrinks by horizontal and vertical, clamped at zero. Negative insets push the rect outward.

Example — padding, too much padding, and an outset

Rust
use xpui::{Insets, Rect, Size};
let card = Rect::new(0, 0, 200, 80);
assert_eq!(card.inset(Insets::all(8)), Rect::new(8, 8, 184, 64));
// More inset than there is room: the size stops at zero.
let crushed = card.inset(Insets::symmetric(120, 0));
assert_eq!(crushed.size, Size::new(0, 80));
assert!(crushed.size.is_empty());
// Negative insets grow it, as a touch target larger than its glyph does.
assert_eq!(card.inset(Insets::all(-4)), Rect::new(-4, -4, 208, 88));

Whether point is inside; the right and bottom edges are outside.

pub fn contains(&self, point: Point) -> bool

An empty rect contains nothing.

Whether the two overlap at all.

pub fn intersects(&self, other: Rect) -> bool

Touching edges do not count, matching contains, which treats the right and bottom edges as outside.

Example — overlap

Rust
use xpui::{Point, Rect};
let a = Rect::new(0, 0, 100, 100);
assert!(a.intersects(Rect::new(99, 99, 10, 10))); // one pixel shared
assert!(!a.intersects(Rect::new(100, 0, 10, 10))); // touching the right edge
assert!(!a.intersects(Rect::new(0, 100, 10, 10))); // touching the bottom edge
assert!(a.intersects(Rect::new(-10, -10, 200, 200))); // around it
assert!(a.intersects(Rect::new(50, 50, 0, 0))); // empty, but inside
assert!(!Rect::new(50, 50, 0, 0).contains(Point::new(50, 50)));

See also: Point, Size, Insets, Renderer::clip

Space inset equally or individually on each edge.

pub struct Insets
Field or constantAbstract
Insets::topPixels taken from the top edge.
Insets::rightPixels taken from the right edge.
Insets::bottomPixels taken from the bottom edge.
Insets::leftPixels taken from the left edge.
Insets::ZERONo inset on any edge.

Insets are not clamped: a negative one grows a rect under Rect::inset. Padding takes one.

Example — building insets

Rust
use xpui::Insets;
let even = Insets::all(8);
assert_eq!((even.top, even.right, even.bottom, even.left), (8, 8, 8, 8));
let wide = Insets::symmetric(16, 4);
assert_eq!((wide.top, wide.right, wide.bottom, wide.left), (4, 16, 4, 16));
let header = Insets { top: 40, ..Insets::ZERO };
assert_eq!(header.vertical(), 40);
assert_eq!(Insets::default(), Insets::ZERO);

The same inset on all four edges.

pub const fn all(value: i32) -> Self

Independent horizontal and vertical insets.

pub const fn symmetric(horizontal: i32, vertical: i32) -> Self
ParameterMeaning
horizontalTaken from the left and from the right, each.
verticalTaken from the top and from the bottom, each.

Left and right together: the width an inset rect loses.

pub const fn horizontal(&self) -> i32

Top and bottom together: the height an inset rect loses.

pub const fn vertical(&self) -> i32

Example — the size inside the insets

Rust
use xpui::{Insets, Size};
let insets = Insets::symmetric(16, 4);
assert_eq!((insets.horizontal(), insets.vertical()), (32, 8));
let inner = Size::new(480, 40).shrink(insets.horizontal(), insets.vertical());
assert_eq!(inner, Size::new(448, 32));

See also: Rect::inset, Padding