182 lines
5.5 KiB
Plaintext
182 lines
5.5 KiB
Plaintext
#import "modules/std.sx";
|
|
#import "modules/math";
|
|
|
|
Point :: struct {
|
|
x, y: f32;
|
|
|
|
zero :: () -> Point { Point.{ x = 0.0, y = 0.0 }; }
|
|
|
|
add :: (self: Point, b: Point) -> Point {
|
|
Point.{ x = self.x + b.x, y = self.y + b.y };
|
|
}
|
|
|
|
sub :: (self: Point, b: Point) -> Point {
|
|
Point.{ x = self.x - b.x, y = self.y - b.y };
|
|
}
|
|
|
|
scale :: (self: Point, s: f32) -> Point {
|
|
Point.{ x = self.x * s, y = self.y * s };
|
|
}
|
|
|
|
distance :: (self: Point, b: Point) -> f32 {
|
|
dx := self.x - b.x;
|
|
dy := self.y - b.y;
|
|
sqrt(dx * dx + dy * dy);
|
|
}
|
|
}
|
|
|
|
Size :: struct {
|
|
width, height: f32;
|
|
|
|
zero :: () -> Size { Size.{ width = 0.0, height = 0.0 }; }
|
|
|
|
contains :: (self: Size, point: Point) -> bool {
|
|
point.x >= 0.0 and point.x <= self.width and point.y >= 0.0 and point.y <= self.height;
|
|
}
|
|
}
|
|
|
|
Frame :: struct {
|
|
origin: Point;
|
|
size: Size;
|
|
|
|
zero :: () -> Frame { Frame.{ origin = Point.zero(), size = Size.zero() }; }
|
|
|
|
make :: (x: f32, y: f32, w: f32, h: f32) -> Frame {
|
|
Frame.{ origin = Point.{ x = x, y = y }, size = Size.{ width = w, height = h } };
|
|
}
|
|
|
|
max_x :: (self: Frame) -> f32 { self.origin.x + self.size.width; }
|
|
max_y :: (self: Frame) -> f32 { self.origin.y + self.size.height; }
|
|
|
|
contains :: (self: Frame, point: Point) -> bool {
|
|
point.x >= self.origin.x and point.x <= self.max_x()
|
|
and point.y >= self.origin.y and point.y <= self.max_y();
|
|
}
|
|
|
|
intersection :: (self: Frame, other: Frame) -> Frame {
|
|
x1 := max(self.origin.x, other.origin.x);
|
|
y1 := max(self.origin.y, other.origin.y);
|
|
x2 := min(self.max_x(), other.max_x());
|
|
y2 := min(self.max_y(), other.max_y());
|
|
if x2 <= x1 or y2 <= y1 then Frame.zero()
|
|
else Frame.make(x1, y1, x2 - x1, y2 - y1);
|
|
}
|
|
|
|
inset :: (self: Frame, insets: EdgeInsets) -> Frame {
|
|
Frame.make(
|
|
self.origin.x + insets.left,
|
|
self.origin.y + insets.top,
|
|
self.size.width - insets.left - insets.right,
|
|
self.size.height - insets.top - insets.bottom
|
|
);
|
|
}
|
|
}
|
|
|
|
EdgeInsets :: struct {
|
|
top, left, bottom, right: f32;
|
|
|
|
zero :: () -> EdgeInsets { EdgeInsets.{ top = 0.0, left = 0.0, bottom = 0.0, right = 0.0 }; }
|
|
|
|
all :: (v: f32) -> EdgeInsets {
|
|
EdgeInsets.{ top = v, left = v, bottom = v, right = v };
|
|
}
|
|
|
|
symmetric :: (h: f32, v: f32) -> EdgeInsets {
|
|
EdgeInsets.{ top = v, left = h, bottom = v, right = h };
|
|
}
|
|
|
|
horizontal :: (self: EdgeInsets) -> f32 { self.left + self.right; }
|
|
vertical :: (self: EdgeInsets) -> f32 { self.top + self.bottom; }
|
|
}
|
|
|
|
Color :: struct {
|
|
r, g, b, a: u8;
|
|
|
|
rgba :: (r: u8, g: u8, b: u8, a: u8) -> Color {
|
|
Color.{ r = r, g = g, b = b, a = a };
|
|
}
|
|
|
|
rgb :: (r: u8, g: u8, b: u8) -> Color {
|
|
Color.{ r = r, g = g, b = b, a = 255 };
|
|
}
|
|
|
|
rf :: (self: Color) -> f32 { xx self.r / 255.0; }
|
|
gf :: (self: Color) -> f32 { xx self.g / 255.0; }
|
|
bf :: (self: Color) -> f32 { xx self.b / 255.0; }
|
|
af :: (self: Color) -> f32 { xx self.a / 255.0; }
|
|
|
|
with_alpha :: (self: Color, a: u8) -> Color {
|
|
Color.{ r = self.r, g = self.g, b = self.b, a = a };
|
|
}
|
|
}
|
|
|
|
// Named color constants
|
|
COLOR_WHITE :: Color.{ r = 255, g = 255, b = 255, a = 255 };
|
|
COLOR_BLACK :: Color.{ r = 0, g = 0, b = 0, a = 255 };
|
|
COLOR_RED :: Color.{ r = 255, g = 59, b = 48, a = 255 };
|
|
COLOR_GREEN :: Color.{ r = 52, g = 199, b = 89, a = 255 };
|
|
COLOR_BLUE :: Color.{ r = 0, g = 122, b = 255, a = 255 };
|
|
COLOR_YELLOW :: Color.{ r = 255, g = 204, b = 0, a = 255 };
|
|
COLOR_ORANGE :: Color.{ r = 255, g = 149, b = 0, a = 255 };
|
|
COLOR_GRAY :: Color.{ r = 142, g = 142, b = 147, a = 255 };
|
|
COLOR_DARK_GRAY :: Color.{ r = 44, g = 44, b = 46, a = 255 };
|
|
COLOR_LIGHT_GRAY :: Color.{ r = 209, g = 209, b = 214, a = 255 };
|
|
COLOR_TRANSPARENT :: Color.{ r = 0, g = 0, b = 0, a = 0 };
|
|
|
|
// Size proposal — optional dimensions (null = flexible)
|
|
ProposedSize :: struct {
|
|
width: ?f32;
|
|
height: ?f32;
|
|
|
|
fixed :: (w: f32, h: f32) -> ProposedSize {
|
|
ProposedSize.{ width = w, height = h };
|
|
}
|
|
|
|
flexible :: () -> ProposedSize {
|
|
ProposedSize.{ width = null, height = null };
|
|
}
|
|
}
|
|
|
|
HAlignment :: enum {
|
|
leading;
|
|
center;
|
|
trailing;
|
|
}
|
|
|
|
VAlignment :: enum {
|
|
top;
|
|
center;
|
|
bottom;
|
|
}
|
|
|
|
Alignment :: struct {
|
|
h: HAlignment;
|
|
v: VAlignment;
|
|
}
|
|
|
|
ALIGN_CENTER :: Alignment.{ h = .center, v = .center };
|
|
ALIGN_TOP_LEADING :: Alignment.{ h = .leading, v = .top };
|
|
ALIGN_TOP :: Alignment.{ h = .center, v = .top };
|
|
ALIGN_TOP_TRAILING :: Alignment.{ h = .trailing, v = .top };
|
|
ALIGN_LEADING :: Alignment.{ h = .leading, v = .center };
|
|
ALIGN_TRAILING :: Alignment.{ h = .trailing, v = .center };
|
|
ALIGN_BOTTOM :: Alignment.{ h = .center, v = .bottom };
|
|
|
|
// Compute x offset for a child of child_width inside container_width
|
|
align_h :: (alignment: HAlignment, child_width: f32, container_width: f32) -> f32 {
|
|
if alignment == {
|
|
case .leading: 0.0;
|
|
case .center: { (container_width - child_width) * 0.5; }
|
|
case .trailing: container_width - child_width;
|
|
}
|
|
}
|
|
|
|
// Compute y offset for a child of child_height inside container_height
|
|
align_v :: (alignment: VAlignment, child_height: f32, container_height: f32) -> f32 {
|
|
if alignment == {
|
|
case .top: 0.0;
|
|
case .center: { (container_height - child_height) * 0.5; }
|
|
case .bottom: container_height - child_height;
|
|
}
|
|
}
|