UXGeom
UXGeom is the toolkit’s geometry: three value types and the static
operations over them. Every UXKit program uses it, because you place a view
by handing its parent a UXRect.
#use <UXKit> // or #import "UXGeometry.xc"Overview
Section titled “Overview”struct UXPoint { i16 x; i16 y; }struct UXSize { i16 w; i16 h; }struct UXRect { i16 x; i16 y; i16 w; i16 h; }These are structs: copied on assignment, never retained, never null.
A rect you hand to addSubview is a copy, so holding on to the rect you
built a view with cannot move the view later. There is no ownership to
track and nothing to free.
The coordinate system is GEM’s. The origin is top-left, y grows
downward, and units are i16 pixels. The AES stores the same values in
OBJECT.ob_x/y/w/h, and any other convention would need a conversion at
every call. If you are used to a toolkit where y grows up, this is the one
thing to re-learn.
The geometry is integer throughout, with no floats, so every backend flattens and caps a curve to identical pixels. A rounded corner on GEM and on macOS is the same shape.
Number literals bind to the parameter’s type, so
UXGeom.make(10, 10, 100, 60) needs no casts. Some toolkit sources write
(i16)10; the cast is not needed.
Topics
Section titled “Topics”make · zero · isEmpty · contains · unite · intersects · intersection · union2 · isqrt · length
static UXRect make(i16 x, i16 y, i16 w, i16 h)A rectangle from its origin and extent, in the parent’s coordinates. This is the most frequently used call in the toolkit.
content.addSubview(button, UXGeom.make(16, 48, 96, 24));static UXRect zero(void)0,0 0x0. Its main use is as the starting value for an accumulating
unite, because empty is that operation’s identity.
isEmpty
Section titled “isEmpty”static bool isEmpty(UXRect r)True when either extent is zero or negative. Negative counts as empty
so that a rect built from a backwards drag, or an
intersection with no overlap, tests as empty.
contains
Section titled “contains”static bool contains(UXRect r, i16 px, i16 py)Hit testing. The test is half-open: the left and top edges are inside, the right and bottom edges are not.
UXRect r = UXGeom.make(10, 10, 100, 60);UXGeom.contains(r, 10, 10) // true — the top-left cornerUXGeom.contains(r, 109, 69) // true — the last pixel insideUXGeom.contains(r, 110, 70) // false — the right/bottom edges are NOTThis rule lets adjacent rects tile without overlapping. Every hit-test in the toolkit follows it, so a click on the boundary between two views lands in one of them only.
static UXRect unite(UXRect a, UXRect b)The smallest rect containing both, ignoring an empty operand. That
exception makes empty the identity, so a damage region can start at
zero and union into it with no special case for the first rect.
UXRect damage = UXGeom.zero();damage = UXGeom.unite(damage, panel); // 10,10 100x60damage = UXGeom.unite(damage, button); // 10,10 130x70Without the exception, a zero rect at the origin would pull every union
back to 0,0, and every repaint would cover the whole window.
UXViewTree accumulates its dirty region
this way.
intersects
Section titled “intersects”static bool intersects(UXRect a, UXRect b)Whether two rects overlap, without building the overlap. Use this cheaper test when you only need the answer.
intersection
Section titled “intersection”static UXRect intersection(UXRect a, UXRect b)The overlapping region, or zero when there is none. You can test
the result with isEmpty instead of calling
intersects first.
UXRect panel = UXGeom.make(10, 10, 100, 60);UXRect button = UXGeom.make(80, 40, 60, 40);UXGeom.intersection(panel, button) // 80,40 30x30union2
Section titled “union2”static UXRect union2(UXRect a, UXRect b)static i32 isqrt(i32 v)Integer square root, floored, by Newton’s method from a power-of-two
seed. isqrt(50) is 7.
It lets the toolkit avoid floats. Squared distances answer most questions, but placing a line cap or an arrowhead a given distance along a stroke needs a real length.
length
Section titled “length”static i32 length(i32 dx, i32 dy)The hypotenuse of (dx, dy), floored: length(3, 4) is 5. It is built on
isqrt, and is the one place the toolkit needs a real distance.
Example
Section titled “Example”Geometry is value types and static functions, so this runs headless, with no window or driver.
#import <Stdio.xc>#import "UXGeometry.xc"
void show(u8* what, UXRect r) { Stdio.printf("%s: %d,%d %dx%d\n", what, r.x, r.y, r.w, r.h);}
void main(void) { UXRect panel = UXGeom.make(10, 10, 100, 60); UXRect button = UXGeom.make(80, 40, 60, 40);
show((u8*)"panel ", panel); // 10,10 100x60 show((u8*)"button ", button); // 80,40 60x40 show((u8*)"overlap", UXGeom.intersection(panel, button)); // 80,40 30x30 show((u8*)"both ", UXGeom.unite(panel, button)); // 10,10 130x70
// Empty is the identity, so damage needs no "first rect" case. UXRect damage = UXGeom.zero(); damage = UXGeom.unite(damage, panel); damage = UXGeom.unite(damage, button); show((u8*)"damage ", damage); // 10,10 130x70
// Half-open containment. Stdio.printf("contains(109,69) %s\n", UXGeom.contains(panel, 109, 69) ? (u8*)"yes" : (u8*)"no"); Stdio.printf("contains(110,70) %s\n", UXGeom.contains(panel, 110, 70) ? (u8*)"yes" : (u8*)"no");
Stdio.printf("length(3,4) %d isqrt(50) %d\n", UXGeom.length(3, 4), UXGeom.isqrt(50));}The comments show what it prints. The program is
website/site/examples/uxkit/geometry.xc, and the doc-examples gate
compiles it.
Conforms to
Section titled “Conforms to”- Inherits
Object
See also
Section titled “See also”UXView:frame,boundsandabsoluteFrameare allUXRect- The view tree and layout: which coordinate space a rect is in, and when the difference matters
UXViewTree: the damage regionuniteis designed for