Files
game/ui/types.sx
2026-02-24 19:22:05 +02:00

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;
}
}