lib/arrange/src/axis.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const types = @import("types.zig");
2
3 const FlexDirection = types.FlexDirection;
4 const Insets = types.Insets;
5 const Node = types.Node;
6 const Rect = types.Rect;
7 const Size = types.Size;
8
9 pub const Axis = enum {
10 horizontal,
11 vertical,
12 };
13
14 pub const AxisLimits = struct {
15 min: f32 = 0,
16 max: ?f32 = null,
17 };
18
19 pub const ResolvedInsets = struct {
20 top: f32 = 0,
21 left: f32 = 0,
22 right: f32 = 0,
23 bottom: f32 = 0,
24 };
25
26 pub fn constrainSize(node: *const Node, size: Size) Size {
27 return .{
28 .width = clampSize(node, .horizontal, size.width),
29 .height = clampSize(node, .vertical, size.height),
30 };
31 }
32
33 pub fn clampSize(node: *const Node, axis: Axis, value: f32) f32 {
34 const limits = axisLimits(node, axis);
35 var result = @max(nonNegative(value), limits.min);
36 if (limits.max) |max_value| result = @min(result, max_value);
37 return result;
38 }
39
40 pub fn axisLimits(node: *const Node, axis: Axis) AxisLimits {
41 const constraints = node.style.constraints;
42 const raw_min = switch (axis) {
43 .horizontal => constraints.min_width,
44 .vertical => constraints.min_height,
45 };
46 const raw_max = switch (axis) {
47 .horizontal => constraints.max_width,
48 .vertical => constraints.max_height,
49 };
50 const min = if (raw_min) |value| nonNegative(value) else 0;
51 const max = if (raw_max) |value| @max(nonNegative(value), min) else null;
52 return .{ .min = min, .max = max };
53 }
54
55 pub fn mainAxis(direction: FlexDirection) Axis {
56 return switch (direction) {
57 .row => .horizontal,
58 .column => .vertical,
59 };
60 }
61
62 pub fn crossAxis(direction: FlexDirection) Axis {
63 return switch (direction) {
64 .row => .vertical,
65 .column => .horizontal,
66 };
67 }
68
69 pub fn rectFromAxes(container: Rect, direction: FlexDirection, main_offset: f32, cross_offset: f32, main_size: f32, cross_size: f32) Rect {
70 return switch (direction) {
71 .row => .{
72 .x = container.x + main_offset,
73 .y = container.y + cross_offset,
74 .width = main_size,
75 .height = cross_size,
76 },
77 .column => .{
78 .x = container.x + cross_offset,
79 .y = container.y + main_offset,
80 .width = cross_size,
81 .height = main_size,
82 },
83 };
84 }
85
86 pub fn contentRect(rect: Rect, padding: Insets) Rect {
87 const resolved = resolvedInsets(padding);
88 return .{
89 .x = rect.x + resolved.left,
90 .y = rect.y + resolved.top,
91 .width = @max(rect.width - resolved.left - resolved.right, 0),
92 .height = @max(rect.height - resolved.top - resolved.bottom, 0),
93 };
94 }
95
96 pub fn resolvedInsets(insets: Insets) ResolvedInsets {
97 return .{
98 .top = if (insets.top) |value| nonNegative(value) else 0,
99 .left = if (insets.left) |value| nonNegative(value) else 0,
100 .right = if (insets.right) |value| nonNegative(value) else 0,
101 .bottom = if (insets.bottom) |value| nonNegative(value) else 0,
102 };
103 }
104
105 pub fn mainSize(rect: Rect, direction: FlexDirection) f32 {
106 return switch (direction) {
107 .row => rect.width,
108 .column => rect.height,
109 };
110 }
111
112 pub fn crossSize(rect: Rect, direction: FlexDirection) f32 {
113 return switch (direction) {
114 .row => rect.height,
115 .column => rect.width,
116 };
117 }
118
119 pub fn nonNegative(value: f32) f32 {
120 return @max(value, 0);
121 }