nomen-lang 0.0.7 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOMEN_AGENTS.md +235 -0
- package/core/System/Ansi.nm +150 -0
- package/core/System/Array.nm +358 -0
- package/core/System/BigInt.nm +887 -0
- package/core/System/Buffer.nm +526 -0
- package/core/System/Channel.nm +198 -0
- package/core/System/ClassBuffer.nm +229 -0
- package/core/System/Console.nm +211 -0
- package/core/System/Controls/Button.nm +138 -0
- package/core/System/Controls/CheckBox.nm +158 -0
- package/core/System/Controls/Container.nm +1562 -0
- package/core/System/Controls/Control.nm +28 -0
- package/core/System/Controls/Geometry.nm +101 -0
- package/core/System/Controls/Layout.nm +228 -0
- package/core/System/Controls/LayoutParams.nm +50 -0
- package/core/System/Controls/Text.nm +129 -0
- package/core/System/Controls/TextBox.nm +157 -0
- package/core/System/Controls/Window.nm +280 -0
- package/core/System/Disposable.nm +8 -0
- package/core/System/Enumerable.nm +10 -0
- package/core/System/Equatable.nm +10 -0
- package/core/System/Graph.nm +68 -0
- package/core/System/Hashable.nm +13 -0
- package/core/System/Init.nm +21 -0
- package/core/System/LinkedList.nm +64 -0
- package/core/System/List.nm +44 -0
- package/core/System/Map.nm +153 -0
- package/core/System/Math.nm +54 -0
- package/core/System/Mutex.nm +78 -0
- package/core/System/Nursery.nm +27 -0
- package/core/System/Sendable.nm +9 -0
- package/core/System/Set.nm +97 -0
- package/core/System/Stream/Directory.nm +176 -0
- package/core/System/Stream/File.nm +432 -0
- package/core/System/Stream/Http.nm +453 -0
- package/core/System/String.nm +154 -0
- package/core/System/StringBuilder.nm +249 -0
- package/core/System/Stringable.nm +8 -0
- package/core/System/Task.nm +263 -0
- package/core/System/Test.nm +241 -0
- package/core/System/Text/Json.nm +377 -0
- package/core/System/Text/JsonTree.nm +187 -0
- package/core/System/Text/Regex.nm +655 -0
- package/core/System/Time.nm +112 -0
- package/core/System/Tree.nm +70 -0
- package/core/System/Viewable.nm +27 -0
- package/core/System/bool.nm +66 -0
- package/core/System/char.nm +42 -0
- package/core/System/float.nm +43 -0
- package/core/System/int.nm +54 -0
- package/core/System/int64.nm +42 -0
- package/core/System/int8.nm +42 -0
- package/core/System/uint.nm +42 -0
- package/core/System/uint64.nm +42 -0
- package/core/System/uint8.nm +42 -0
- package/core/docs/System/Ansi.md +40 -0
- package/core/docs/System/Array.md +16 -0
- package/core/docs/System/BigInt.md +30 -0
- package/core/docs/System/Buffer.md +31 -0
- package/core/docs/System/Channel.md +10 -0
- package/core/docs/System/ClassBuffer.md +15 -0
- package/core/docs/System/Console.md +13 -0
- package/core/docs/System/Controls/Button.md +12 -0
- package/core/docs/System/Controls/CheckBox.md +15 -0
- package/core/docs/System/Controls/Container.md +82 -0
- package/core/docs/System/Controls/Control.md +5 -0
- package/core/docs/System/Controls/Geometry.md +26 -0
- package/core/docs/System/Controls/Layout.md +37 -0
- package/core/docs/System/Controls/LayoutParams.md +13 -0
- package/core/docs/System/Controls/Text.md +12 -0
- package/core/docs/System/Controls/TextBox.md +13 -0
- package/core/docs/System/Controls/Window.md +20 -0
- package/core/docs/System/Disposable.md +5 -0
- package/core/docs/System/Enumerable.md +5 -0
- package/core/docs/System/Graph.md +17 -0
- package/core/docs/System/Init.md +9 -0
- package/core/docs/System/LinkedList.md +16 -0
- package/core/docs/System/List.md +13 -0
- package/core/docs/System/Map.md +14 -0
- package/core/docs/System/Math.md +11 -0
- package/core/docs/System/Mutex.md +10 -0
- package/core/docs/System/Nursery.md +5 -0
- package/core/docs/System/Sendable.md +5 -0
- package/core/docs/System/Set.md +14 -0
- package/core/docs/System/Stream/Directory.md +12 -0
- package/core/docs/System/Stream/File.md +21 -0
- package/core/docs/System/String.md +14 -0
- package/core/docs/System/StringBuilder.md +12 -0
- package/core/docs/System/Stringable.md +5 -0
- package/core/docs/System/Task.md +15 -0
- package/core/docs/System/Text/Json.md +12 -0
- package/core/docs/System/Text/JsonTree.md +21 -0
- package/core/docs/System/Text/Regex.md +12 -0
- package/core/docs/System/Time.md +11 -0
- package/core/docs/System/Tree.md +18 -0
- package/core/docs/System/Viewable.md +5 -0
- package/core/docs/System/bool.md +9 -0
- package/core/docs/System/char.md +9 -0
- package/core/docs/System/float.md +9 -0
- package/core/docs/System/int.md +10 -0
- package/core/docs/System/int64.md +9 -0
- package/core/docs/System/int8.md +9 -0
- package/core/docs/System/uint.md +9 -0
- package/core/docs/System/uint64.md +9 -0
- package/core/docs/System/uint8.md +9 -0
- package/core/package.jsonc +4 -0
- package/dist/index.mjs +417 -5490
- package/package.json +33 -30
- package/src/args.ts +171 -0
- package/src/index.ts +53 -104
- package/src/init.ts +128 -0
- package/src/test.ts +6 -2
- package/test/fixtures/build/calc.test +0 -0
- package/test/fixtures/build/calc.test.c +0 -969
- package/test/fixtures/build/main.h +0 -170
- package/test/fixtures/calc.test.nm +0 -32
- package/tsconfig.json +0 -21
- package/vite.config.ts +0 -7
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// The `Control` trait is the polymorphic interface the layout engine uses to
|
|
2
|
+
// talk to every node in the UI tree. A control reports its desired size given a
|
|
3
|
+
// set of constraints (measure), applies a concrete rectangle (set_frame), and can
|
|
4
|
+
// report how big it would be with unbounded space (intrinsic_size).
|
|
5
|
+
//
|
|
6
|
+
// Native controls (Window, Text, …) and containers conform to it. See GUI.md
|
|
7
|
+
// ("The Control trait") for the contract. The measure/arrange math is the same
|
|
8
|
+
// regardless of storage: the handle-based `Container` applies frames directly via
|
|
9
|
+
// native `setFrame:` today, but a control that also conforms to `Control` can be
|
|
10
|
+
// driven through the trait interface (and slotted into `Array<Control>` /
|
|
11
|
+
// `ClassBuffer<Control>` once the container migrates).
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The polymorphic interface every UI node implements (measure / set_frame / intrinsic_size)
|
|
15
|
+
**/
|
|
16
|
+
pub trait Control {
|
|
17
|
+
// Given these constraints, report the size you want to be.
|
|
18
|
+
// Must satisfy min_width ≤ result.width ≤ max_width (ditto height).
|
|
19
|
+
func measure = (self, BoxConstraints constraints, out Size)
|
|
20
|
+
|
|
21
|
+
// Apply a concrete rectangle. For native controls this calls setFrame: on the
|
|
22
|
+
// platform handle. For containers this also arranges children.
|
|
23
|
+
func set_frame = (ref self, int x, int y, int width, int height)
|
|
24
|
+
|
|
25
|
+
// What size would you be with unbounded space? (Used by parents to decide
|
|
26
|
+
// wrapping, scrolling, etc. Default: call measure with infinity.)
|
|
27
|
+
func intrinsic_size = (self, out Size)
|
|
28
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// Layout geometry types for the Nomen `core/System/Controls` UI layer.
|
|
2
|
+
//
|
|
3
|
+
// These are the pure-data types that flow through the layout engine: a parent
|
|
4
|
+
// hands each child a `BoxConstraints` (min/max per axis) during the measure
|
|
5
|
+
// phase, each child reports a `Size` back, and the engine assigns each node a
|
|
6
|
+
// `Frame` (x, y, width, height) during the arrange phase. `Insets` are the
|
|
7
|
+
// padding subtracted from a container's content rect. The `LayoutLength` /
|
|
8
|
+
// `Alignment` enums describe how a child sits in its parent (see `LayoutParams`).
|
|
9
|
+
//
|
|
10
|
+
// The measure/arrange math is independent of the storage representation — these
|
|
11
|
+
// flat structs are the trait-based `Container : Control` design's data model,
|
|
12
|
+
// but the same types work with the handle-based v1 container.
|
|
13
|
+
|
|
14
|
+
const MAX_DIM = 2147483647
|
|
15
|
+
|
|
16
|
+
// ── Geometry ──
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* A 2D size (width and height)
|
|
20
|
+
**/
|
|
21
|
+
pub struct Size {
|
|
22
|
+
pub var width = 0
|
|
23
|
+
pub var height = 0
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* A rectangle (x, y, width, height) — a control's assigned position and size
|
|
28
|
+
**/
|
|
29
|
+
pub struct Frame {
|
|
30
|
+
pub var x = 0
|
|
31
|
+
pub var y = 0
|
|
32
|
+
pub var width = 0
|
|
33
|
+
pub var height = 0
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Per-edge padding (top, right, bottom, left)
|
|
38
|
+
**/
|
|
39
|
+
pub struct Insets {
|
|
40
|
+
pub var top = 0
|
|
41
|
+
pub var right = 0
|
|
42
|
+
pub var bottom = 0
|
|
43
|
+
pub var left = 0
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ── Constraints (flow DOWN) ──
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Min/max size bounds a parent passes to a child during the layout measure phase
|
|
50
|
+
**/
|
|
51
|
+
pub struct BoxConstraints {
|
|
52
|
+
pub var min_width = 0
|
|
53
|
+
pub var min_height = 0
|
|
54
|
+
pub var int max_width = MAX_DIM
|
|
55
|
+
pub var int max_height = MAX_DIM
|
|
56
|
+
|
|
57
|
+
pub func tighten_width = (self, int min, int max, out BoxConstraints) {
|
|
58
|
+
var BoxConstraints c = self
|
|
59
|
+
c.min_width = self.min_width
|
|
60
|
+
if min > c.min_width { c.min_width = min }
|
|
61
|
+
c.max_width = self.max_width
|
|
62
|
+
if max < c.max_width { c.max_width = max }
|
|
63
|
+
return c
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
pub func tighten_height = (self, int min, int max, out BoxConstraints) {
|
|
67
|
+
var BoxConstraints c = self
|
|
68
|
+
c.min_height = self.min_height
|
|
69
|
+
if min > c.min_height { c.min_height = min }
|
|
70
|
+
c.max_height = self.max_height
|
|
71
|
+
if max < c.max_height { c.max_height = max }
|
|
72
|
+
return c
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
pub func clamp_width = (self, int value, out int) {
|
|
76
|
+
if value < self.min_width { return self.min_width }
|
|
77
|
+
if value > self.max_width { return self.max_width }
|
|
78
|
+
return value
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
pub func clamp_height = (self, int value, out int) {
|
|
82
|
+
if value < self.min_height { return self.min_height }
|
|
83
|
+
if value > self.max_height { return self.max_height }
|
|
84
|
+
return value
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
pub func is_width_bounded = (self, out bool) {
|
|
88
|
+
return self.max_width < MAX_DIM
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
pub func is_height_bounded = (self, out bool) {
|
|
92
|
+
return self.max_height < MAX_DIM
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// `LayoutLength`, `Alignment`, `LayoutParams`, and `DEFAULT_PARAMS` live in
|
|
97
|
+
// `LayoutParams.nm`. They're split out so a module that only needs the
|
|
98
|
+
// per-child length model (e.g. `Container.nm`) can pull them in without also
|
|
99
|
+
// dragging `Size`/`Frame`/`Insets`/`BoxConstraints` along — `Size` and `Frame`
|
|
100
|
+
// collide with macOS `MacTypes.h` typedefs once any Cocoa-using module
|
|
101
|
+
// (Window, Controls) is in the build.
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
// All node data in flat Buffers. Buffer data pointers are shared even when
|
|
2
|
+
// the struct is copied (value semantics copy the pointer, not the data).
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A flat, buffer-backed layout tree — nodes stored in parallel arrays for the layout engine
|
|
6
|
+
**/
|
|
7
|
+
pub struct Layout {
|
|
8
|
+
var kinds = Buffer<int>() // 0=leaf, 1=vstack, 2=hstack
|
|
9
|
+
var ws = Buffer<int>() // intrinsic width (leaf) or 0
|
|
10
|
+
var hs = Buffer<int>() // intrinsic height (leaf) or 0
|
|
11
|
+
var gaps = Buffer<int>() // spacing between children (containers)
|
|
12
|
+
var par = Buffer<int>() // parent index (-1 = root)
|
|
13
|
+
var rx = Buffer<int>() // result x
|
|
14
|
+
var ry = Buffer<int>() // result y
|
|
15
|
+
var rw = Buffer<int>() // result width
|
|
16
|
+
var rh = Buffer<int>() // result height
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Initializes a Layout tree with capacity for `cap` nodes
|
|
21
|
+
**/
|
|
22
|
+
pub func init_layout = (ref Layout l, int cap) {
|
|
23
|
+
l.kinds.grow_int(cap)
|
|
24
|
+
l.ws.grow_int(cap)
|
|
25
|
+
l.hs.grow_int(cap)
|
|
26
|
+
l.gaps.grow_int(cap)
|
|
27
|
+
l.par.grow_int(cap)
|
|
28
|
+
l.rx.grow_int(cap)
|
|
29
|
+
l.ry.grow_int(cap)
|
|
30
|
+
l.rw.grow_int(cap)
|
|
31
|
+
l.rh.grow_int(cap)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Appends a leaf node (a sized control) under `parent` and returns its index
|
|
36
|
+
**/
|
|
37
|
+
pub func add_leaf = (ref Layout l, int parent, int w, int h, out int) {
|
|
38
|
+
var idx = 0
|
|
39
|
+
while l.par.load_int(idx) != 0 || idx == 0; idx += 1 {
|
|
40
|
+
if l.kinds.load_int(idx) == 0 && l.ws.load_int(idx) == 0 && l.hs.load_int(idx) == 0 && l.par.load_int(idx) == 0 {
|
|
41
|
+
break
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
l.kinds.store_int(idx, 0)
|
|
45
|
+
l.ws.store_int(idx, w)
|
|
46
|
+
l.hs.store_int(idx, h)
|
|
47
|
+
l.gaps.store_int(idx, 0)
|
|
48
|
+
l.par.store_int(idx, parent + 1)
|
|
49
|
+
return idx
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Appends a vertical stack container under `parent` and returns its index
|
|
54
|
+
**/
|
|
55
|
+
pub func add_vstack = (ref Layout l, int parent, int spacing, out int) {
|
|
56
|
+
var idx = 0
|
|
57
|
+
while true; idx += 1 {
|
|
58
|
+
if l.kinds.load_int(idx) == 0 && l.ws.load_int(idx) == 0 && l.hs.load_int(idx) == 0 && l.par.load_int(idx) == 0 {
|
|
59
|
+
break
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
l.kinds.store_int(idx, 1)
|
|
63
|
+
l.ws.store_int(idx, 0)
|
|
64
|
+
l.hs.store_int(idx, 0)
|
|
65
|
+
l.gaps.store_int(idx, spacing)
|
|
66
|
+
l.par.store_int(idx, parent + 1)
|
|
67
|
+
return idx
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Appends a horizontal stack container under `parent` and returns its index
|
|
72
|
+
**/
|
|
73
|
+
pub func add_hstack = (ref Layout l, int parent, int spacing, out int) {
|
|
74
|
+
var idx = 0
|
|
75
|
+
while true; idx += 1 {
|
|
76
|
+
if l.kinds.load_int(idx) == 0 && l.ws.load_int(idx) == 0 && l.hs.load_int(idx) == 0 && l.par.load_int(idx) == 0 {
|
|
77
|
+
break
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
l.kinds.store_int(idx, 2)
|
|
81
|
+
l.ws.store_int(idx, 0)
|
|
82
|
+
l.hs.store_int(idx, 0)
|
|
83
|
+
l.gaps.store_int(idx, spacing)
|
|
84
|
+
l.par.store_int(idx, parent + 1)
|
|
85
|
+
return idx
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
func first_child = (Layout l, int count, int parent, out int) {
|
|
89
|
+
var int p = parent + 1
|
|
90
|
+
var i = 0
|
|
91
|
+
while i < count; i += 1 {
|
|
92
|
+
if l.par.load_int(i) == p { return i }
|
|
93
|
+
}
|
|
94
|
+
return -1
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
func next_sibling = (Layout l, int count, int after, int parent, out int) {
|
|
98
|
+
var int p = parent + 1
|
|
99
|
+
var int i = after + 1
|
|
100
|
+
while i < count; i += 1 {
|
|
101
|
+
if l.par.load_int(i) == p { return i }
|
|
102
|
+
}
|
|
103
|
+
return -1
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Returns Size via two out params (workaround: single out return).
|
|
107
|
+
// Caller passes addresses; measure fills them.
|
|
108
|
+
/**
|
|
109
|
+
* Measures node widths against the given constraints (layout measure phase)
|
|
110
|
+
**/
|
|
111
|
+
pub func measure_w = (
|
|
112
|
+
Layout l,
|
|
113
|
+
int count,
|
|
114
|
+
int idx,
|
|
115
|
+
int min_w,
|
|
116
|
+
int max_w,
|
|
117
|
+
int min_h,
|
|
118
|
+
int max_h,
|
|
119
|
+
out int
|
|
120
|
+
) {
|
|
121
|
+
var int kind = l.kinds.load_int(idx)
|
|
122
|
+
if kind == 0 {
|
|
123
|
+
var int w = l.ws.load_int(idx)
|
|
124
|
+
var int h = l.hs.load_int(idx)
|
|
125
|
+
if w > max_w { w = max_w }
|
|
126
|
+
if h > max_h { h = max_h }
|
|
127
|
+
if w < min_w { w = min_w }
|
|
128
|
+
if h < min_h { h = min_h }
|
|
129
|
+
// Encode w and h: return w, store h into rh as side effect
|
|
130
|
+
l.rh.store_int(idx, h)
|
|
131
|
+
return w
|
|
132
|
+
}
|
|
133
|
+
if kind == 1 {
|
|
134
|
+
// vstack: sum heights, max widths
|
|
135
|
+
var total_h = 0
|
|
136
|
+
var max_child_w = 0
|
|
137
|
+
var n = 0
|
|
138
|
+
var int ci = first_child(l, count, idx)
|
|
139
|
+
while ci != -1 {
|
|
140
|
+
var int cw = measure_w(l, count, ci, min_w, max_w, 0, 100000)
|
|
141
|
+
var int ch = l.rh.load_int(ci)
|
|
142
|
+
total_h = total_h + ch
|
|
143
|
+
if cw > max_child_w { max_child_w = cw }
|
|
144
|
+
n += 1
|
|
145
|
+
ci = next_sibling(l, count, ci, idx)
|
|
146
|
+
}
|
|
147
|
+
if n > 1 { total_h = total_h + l.gaps.load_int(idx) * (n - 1) }
|
|
148
|
+
if max_child_w < min_w { max_child_w = min_w }
|
|
149
|
+
if max_child_w > max_w { max_child_w = max_w }
|
|
150
|
+
if total_h < min_h { total_h = min_h }
|
|
151
|
+
if total_h > max_h { total_h = max_h }
|
|
152
|
+
l.rh.store_int(idx, total_h)
|
|
153
|
+
return max_child_w
|
|
154
|
+
}
|
|
155
|
+
// hstack: sum widths, max heights
|
|
156
|
+
var total_w = 0
|
|
157
|
+
var max_child_h = 0
|
|
158
|
+
var n = 0
|
|
159
|
+
var int ci = first_child(l, count, idx)
|
|
160
|
+
while ci != -1 {
|
|
161
|
+
var int cw = measure_w(l, count, ci, 0, 100000, min_h, max_h)
|
|
162
|
+
var int ch = l.rh.load_int(ci)
|
|
163
|
+
total_w = total_w + cw
|
|
164
|
+
if ch > max_child_h { max_child_h = ch }
|
|
165
|
+
n += 1
|
|
166
|
+
ci = next_sibling(l, count, ci, idx)
|
|
167
|
+
}
|
|
168
|
+
if n > 1 { total_w = total_w + l.gaps.load_int(idx) * (n - 1) }
|
|
169
|
+
if total_w < min_w { total_w = min_w }
|
|
170
|
+
if total_w > max_w { total_w = max_w }
|
|
171
|
+
if max_child_h < min_h { max_child_h = min_h }
|
|
172
|
+
if max_child_h > max_h { max_child_h = max_h }
|
|
173
|
+
l.rh.store_int(idx, max_child_h)
|
|
174
|
+
return total_w
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Assigns concrete frames to nodes (layout arrange phase)
|
|
179
|
+
**/
|
|
180
|
+
pub func arrange = (Layout l, int count, int idx, int x, int y, int w, int h) {
|
|
181
|
+
l.rx.store_int(idx, x)
|
|
182
|
+
l.ry.store_int(idx, y)
|
|
183
|
+
l.rw.store_int(idx, w)
|
|
184
|
+
l.rh.store_int(idx, h)
|
|
185
|
+
var int kind = l.kinds.load_int(idx)
|
|
186
|
+
if kind == 0 { return }
|
|
187
|
+
|
|
188
|
+
if kind == 1 {
|
|
189
|
+
// vstack: children top to bottom, full width
|
|
190
|
+
var int running_y = y
|
|
191
|
+
var int ci = first_child(l, count, idx)
|
|
192
|
+
while ci != -1 {
|
|
193
|
+
var int child_w = measure_w(l, count, ci, w, w, 0, 100000)
|
|
194
|
+
var int child_h = l.rh.load_int(ci)
|
|
195
|
+
arrange(l, count, ci, x, running_y, w, child_h)
|
|
196
|
+
running_y = running_y + child_h + l.gaps.load_int(idx)
|
|
197
|
+
ci = next_sibling(l, count, ci, idx)
|
|
198
|
+
}
|
|
199
|
+
return
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// hstack: children left to right, full height
|
|
203
|
+
var int running_x = x
|
|
204
|
+
var int ci = first_child(l, count, idx)
|
|
205
|
+
while ci != -1 {
|
|
206
|
+
var int child_w = measure_w(l, count, ci, 0, 100000, h, h)
|
|
207
|
+
var int child_h = l.rh.load_int(ci)
|
|
208
|
+
arrange(l, count, ci, running_x, y, child_w, h)
|
|
209
|
+
running_x = running_x + child_w + l.gaps.load_int(idx)
|
|
210
|
+
ci = next_sibling(l, count, ci, idx)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Runs a full measure-then-arrange pass from `root` within the available space
|
|
216
|
+
**/
|
|
217
|
+
pub func run_layout = (ref Layout l, int count, int root, int avail_w, int avail_h) {
|
|
218
|
+
var int root_w = measure_w(l, count, root, 0, avail_w, 0, avail_h)
|
|
219
|
+
var int root_h = l.rh.load_int(root)
|
|
220
|
+
arrange(l, count, root, 0, 0, root_w, root_h)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Formats a node and its subtree as a string (for debugging)
|
|
225
|
+
**/
|
|
226
|
+
pub func fmt = (Layout l, int idx, out string) {
|
|
227
|
+
return "{" + l.rx.load_int(idx).to_string() + "," + l.ry.load_int(idx).to_string() + " " + l.rw.load_int(idx).to_string() + "x" + l.rh.load_int(idx).to_string() + "}"
|
|
228
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Per-child layout parameter types for the Nomen `core/System/Controls` UI
|
|
2
|
+
// layer. Split out of `Geometry.nm` so a module that only needs the
|
|
3
|
+
// length-model enums (e.g. `Container.nm`) can pull them in without also
|
|
4
|
+
// dragging `Size`/`Frame`/`Insets`/`BoxConstraints` along — `Size` and `Frame`
|
|
5
|
+
// collide with macOS `MacTypes.h` typedefs once any Cocoa-using module
|
|
6
|
+
// (Window, Controls) is in the build.
|
|
7
|
+
|
|
8
|
+
// ── Requested size (user-facing, on LayoutParams) ──
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* How a child dimension is sized: auto (to content), fixed, percent, or fill
|
|
12
|
+
**/
|
|
13
|
+
pub enum LayoutLength {
|
|
14
|
+
case auto // size to content (intrinsic measurement)
|
|
15
|
+
case fixed(int pixels) // exact size
|
|
16
|
+
case percent(int numerator) // numerator/100 of available space (e.g. 50 = 50%)
|
|
17
|
+
case fill // fill all available space (same as grow=1)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* How a child is positioned within available space (start / center / end / stretch)
|
|
22
|
+
**/
|
|
23
|
+
pub enum Alignment {
|
|
24
|
+
case start
|
|
25
|
+
case center
|
|
26
|
+
case end
|
|
27
|
+
case stretch
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ── Per-child layout parameters ──
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Per-child layout preferences: requested dimensions, flex grow/shrink weights, and alignment
|
|
34
|
+
**/
|
|
35
|
+
pub struct LayoutParams {
|
|
36
|
+
pub var LayoutLength width = .auto
|
|
37
|
+
pub var LayoutLength height = .auto
|
|
38
|
+
pub var grow = 0 // flex weight for distributing surplus space
|
|
39
|
+
pub var shrink = 0 // flex weight for distributing deficit
|
|
40
|
+
pub var Alignment align_self = .stretch // cross-axis alignment override
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Sensible defaults so most children just work
|
|
44
|
+
const LayoutParams DEFAULT_PARAMS = LayoutParams() + [
|
|
45
|
+
width = .auto,
|
|
46
|
+
height = .auto,
|
|
47
|
+
grow = 0,
|
|
48
|
+
shrink = 1,
|
|
49
|
+
align_self = .stretch,
|
|
50
|
+
]
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A read-only text label control
|
|
3
|
+
**/
|
|
4
|
+
pub class Text: Control {
|
|
5
|
+
var uint64 handle = 0
|
|
6
|
+
var text = ""
|
|
7
|
+
|
|
8
|
+
pub func #init = (self, Window window) {
|
|
9
|
+
```
|
|
10
|
+
#arch: c, aarch64_use_c
|
|
11
|
+
#platform: macos
|
|
12
|
+
id label = ((id(*)(id, SEL, CGRect))objc_msgSend)(
|
|
13
|
+
((id(*)(id, SEL))objc_msgSend)((id)objc_getClass("NSTextField"), sel_registerName("alloc")),
|
|
14
|
+
sel_registerName("initWithFrame:"),
|
|
15
|
+
((CGRect(*)(double, double, double, double))CGRectMake)(10, 10, 200, 30));
|
|
16
|
+
((void(*)(id, SEL, BOOL))objc_msgSend)(
|
|
17
|
+
label, sel_registerName("setEditable:"), 0);
|
|
18
|
+
((void(*)(id, SEL, BOOL))objc_msgSend)(
|
|
19
|
+
label, sel_registerName("setSelectable:"), 0);
|
|
20
|
+
((void(*)(id, SEL, BOOL))objc_msgSend)(
|
|
21
|
+
label, sel_registerName("setBordered:"), 0);
|
|
22
|
+
((void(*)(id, SEL, BOOL))objc_msgSend)(
|
|
23
|
+
label, sel_registerName("setDrawsBackground:"), 0);
|
|
24
|
+
id contentView = ((id(*)(id, SEL))objc_msgSend)(
|
|
25
|
+
(id)window->handle, sel_registerName("contentView"));
|
|
26
|
+
((void(*)(id, SEL, id))objc_msgSend)(
|
|
27
|
+
contentView, sel_registerName("addSubview:"), label);
|
|
28
|
+
self->handle = (uint64_t)label;
|
|
29
|
+
```
|
|
30
|
+
```
|
|
31
|
+
#arch: c, aarch64_use_c
|
|
32
|
+
#platform: ios
|
|
33
|
+
id label = ((id(*)(id, SEL, CGRect))objc_msgSend)(
|
|
34
|
+
((id(*)(id, SEL))objc_msgSend)(objc_getClass("UILabel"), sel_registerName("alloc")),
|
|
35
|
+
sel_registerName("initWithFrame:"),
|
|
36
|
+
((CGRect(*)(double, double, double, double))CGRectMake)(10, 10, 200, 30));
|
|
37
|
+
((void(*)(id, SEL, id))objc_msgSend)(
|
|
38
|
+
label, sel_registerName("setText:"),
|
|
39
|
+
((id(*)(id, SEL, const char*))objc_msgSend)(
|
|
40
|
+
(id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), ""));
|
|
41
|
+
((void(*)(id, SEL, BOOL))objc_msgSend)(
|
|
42
|
+
label, sel_registerName("setUserInteractionEnabled:"), 0);
|
|
43
|
+
id parentView = ((id(*)(id, SEL))objc_msgSend)(
|
|
44
|
+
((id(*)(id, SEL))objc_msgSend)(
|
|
45
|
+
(id)window->handle, sel_registerName("rootViewController")),
|
|
46
|
+
sel_registerName("view"));
|
|
47
|
+
((void(*)(id, SEL, id))objc_msgSend)(
|
|
48
|
+
parentView, sel_registerName("addSubview:"), label);
|
|
49
|
+
self->handle = (uint64_t)label;
|
|
50
|
+
```
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
pub func set_text = (ref self, string text) {
|
|
54
|
+
self.text = text
|
|
55
|
+
```
|
|
56
|
+
#arch: c, aarch64_use_c
|
|
57
|
+
#platform: macos
|
|
58
|
+
((void(*)(id, SEL, id))objc_msgSend)(
|
|
59
|
+
(id)self->handle, sel_registerName("setStringValue:"),
|
|
60
|
+
((id(*)(id, SEL, const char*))objc_msgSend)(
|
|
61
|
+
(id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), text));
|
|
62
|
+
```
|
|
63
|
+
```
|
|
64
|
+
#arch: c, aarch64_use_c
|
|
65
|
+
#platform: ios
|
|
66
|
+
((void(*)(id, SEL, id))objc_msgSend)(
|
|
67
|
+
(id)self->handle, sel_registerName("setText:"),
|
|
68
|
+
((id(*)(id, SEL, const char*))objc_msgSend)(
|
|
69
|
+
(id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), text));
|
|
70
|
+
```
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ── Control trait conformance ──
|
|
74
|
+
// A text control sizes to its content. v1 assumes an 8px monospace font, so a
|
|
75
|
+
// line is `text.length × 8` wide and 8px tall (see GUI.md "Native control
|
|
76
|
+
// refactor"). The default frame is 0,0,0,0; layout drives the real rectangle.
|
|
77
|
+
|
|
78
|
+
pub func measure = (self, BoxConstraints constraints, out Size) {
|
|
79
|
+
var s = Size()
|
|
80
|
+
s.width = self.text.length * 8
|
|
81
|
+
s.height = 8
|
|
82
|
+
return s
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
pub func intrinsic_size = (self, out Size) {
|
|
86
|
+
var s = Size()
|
|
87
|
+
s.width = self.text.length * 8
|
|
88
|
+
s.height = 8
|
|
89
|
+
return s
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
pub func set_frame = (ref self, int x, int y, int width, int height) {
|
|
93
|
+
```
|
|
94
|
+
#arch: c, aarch64_use_c
|
|
95
|
+
#platform: macos
|
|
96
|
+
((void(*)(id, SEL, CGRect))objc_msgSend)(
|
|
97
|
+
(id)self->handle, sel_registerName("setFrame:"),
|
|
98
|
+
((CGRect(*)(double, double, double, double))CGRectMake)((double)x, (double)y, (double)width, (double)height));
|
|
99
|
+
```
|
|
100
|
+
```
|
|
101
|
+
#arch: c, aarch64_use_c
|
|
102
|
+
#platform: ios
|
|
103
|
+
((void(*)(id, SEL, CGRect))objc_msgSend)(
|
|
104
|
+
(id)self->handle, sel_registerName("setFrame:"),
|
|
105
|
+
((CGRect(*)(double, double, double, double))CGRectMake)((double)x, (double)y, (double)width, (double)height));
|
|
106
|
+
```
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
func #destroy = () {
|
|
110
|
+
```
|
|
111
|
+
#arch: c, aarch64_use_c
|
|
112
|
+
#platform: macos
|
|
113
|
+
if (self->handle) {
|
|
114
|
+
((void(*)(id, SEL))objc_msgSend)((id)self->handle, sel_registerName("removeFromSuperview"));
|
|
115
|
+
((void(*)(id, SEL))objc_msgSend)((id)self->handle, sel_registerName("release"));
|
|
116
|
+
self->handle = 0;
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
```
|
|
120
|
+
#arch: c, aarch64_use_c
|
|
121
|
+
#platform: ios
|
|
122
|
+
if (self->handle) {
|
|
123
|
+
((void(*)(id, SEL))objc_msgSend)((id)self->handle, sel_registerName("removeFromSuperview"));
|
|
124
|
+
((void(*)(id, SEL))objc_msgSend)((id)self->handle, sel_registerName("release"));
|
|
125
|
+
self->handle = 0;
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An editable single-line text input control
|
|
3
|
+
**/
|
|
4
|
+
pub class TextBox : Control {
|
|
5
|
+
var uint64 handle = 0
|
|
6
|
+
|
|
7
|
+
pub func #init = (self, Window window) {
|
|
8
|
+
```
|
|
9
|
+
#arch: c, aarch64_use_c
|
|
10
|
+
#platform: macos
|
|
11
|
+
id field = ((id(*)(id, SEL, CGRect))objc_msgSend)(
|
|
12
|
+
((id(*)(id, SEL))objc_msgSend)((id)objc_getClass("NSTextField"), sel_registerName("alloc")),
|
|
13
|
+
sel_registerName("initWithFrame:"),
|
|
14
|
+
((CGRect(*)(double, double, double, double))CGRectMake)(0, 0, 200, 24));
|
|
15
|
+
((void(*)(id, SEL, BOOL))objc_msgSend)(
|
|
16
|
+
field, sel_registerName("setEditable:"), 1);
|
|
17
|
+
((void(*)(id, SEL, BOOL))objc_msgSend)(
|
|
18
|
+
field, sel_registerName("setSelectable:"), 1);
|
|
19
|
+
((void(*)(id, SEL, BOOL))objc_msgSend)(
|
|
20
|
+
field, sel_registerName("setBordered:"), 1);
|
|
21
|
+
((void(*)(id, SEL, BOOL))objc_msgSend)(
|
|
22
|
+
field, sel_registerName("setBezeled:"), 1);
|
|
23
|
+
((void(*)(id, SEL, BOOL))objc_msgSend)(
|
|
24
|
+
field, sel_registerName("setDrawsBackground:"), 1);
|
|
25
|
+
((void(*)(id, SEL, id))objc_msgSend)(
|
|
26
|
+
field, sel_registerName("setStringValue:"),
|
|
27
|
+
((id(*)(id, SEL, const char*))objc_msgSend)(
|
|
28
|
+
(id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), ""));
|
|
29
|
+
id contentView = ((id(*)(id, SEL))objc_msgSend)(
|
|
30
|
+
(id)window->handle, sel_registerName("contentView"));
|
|
31
|
+
((void(*)(id, SEL, id))objc_msgSend)(
|
|
32
|
+
contentView, sel_registerName("addSubview:"), field);
|
|
33
|
+
self->handle = (uint64_t)field;
|
|
34
|
+
```
|
|
35
|
+
```
|
|
36
|
+
#arch: c, aarch64_use_c
|
|
37
|
+
#platform: ios
|
|
38
|
+
id field = ((id(*)(id, SEL, CGRect))objc_msgSend)(
|
|
39
|
+
((id(*)(id, SEL))objc_msgSend)((id)objc_getClass("UITextField"), sel_registerName("alloc")),
|
|
40
|
+
sel_registerName("initWithFrame:"),
|
|
41
|
+
((CGRect(*)(double, double, double, double))CGRectMake)(0, 0, 200, 30));
|
|
42
|
+
((void(*)(id, SEL, BOOL))objc_msgSend)(
|
|
43
|
+
field, sel_registerName("setBorderStyle:"), 1); // UITextBorderStyleRoundedRect = 1
|
|
44
|
+
id parentView = ((id(*)(id, SEL))objc_msgSend)(
|
|
45
|
+
((id(*)(id, SEL))objc_msgSend)(
|
|
46
|
+
(id)window->handle, sel_registerName("rootViewController")),
|
|
47
|
+
sel_registerName("view"));
|
|
48
|
+
((void(*)(id, SEL, id))objc_msgSend)(
|
|
49
|
+
parentView, sel_registerName("addSubview:"), field);
|
|
50
|
+
self->handle = (uint64_t)field;
|
|
51
|
+
```
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
pub func set_frame = (ref self, int x, int y, int width, int height) {
|
|
55
|
+
```
|
|
56
|
+
#arch: c, aarch64_use_c
|
|
57
|
+
#platform: macos
|
|
58
|
+
((void(*)(id, SEL, CGRect))objc_msgSend)(
|
|
59
|
+
(id)self->handle, sel_registerName("setFrame:"),
|
|
60
|
+
((CGRect(*)(double, double, double, double))CGRectMake)((double)x, (double)y, (double)width, (double)height));
|
|
61
|
+
```
|
|
62
|
+
```
|
|
63
|
+
#arch: c, aarch64_use_c
|
|
64
|
+
#platform: ios
|
|
65
|
+
((void(*)(id, SEL, CGRect))objc_msgSend)(
|
|
66
|
+
(id)self->handle, sel_registerName("setFrame:"),
|
|
67
|
+
((CGRect(*)(double, double, double, double))CGRectMake)((double)x, (double)y, (double)width, (double)height));
|
|
68
|
+
```
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
pub func set_text = (self, string text) {
|
|
72
|
+
```
|
|
73
|
+
#arch: c, aarch64_use_c
|
|
74
|
+
#platform: macos
|
|
75
|
+
((void(*)(id, SEL, id))objc_msgSend)(
|
|
76
|
+
(id)self->handle, sel_registerName("setStringValue:"),
|
|
77
|
+
((id(*)(id, SEL, const char*))objc_msgSend)(
|
|
78
|
+
(id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), text));
|
|
79
|
+
```
|
|
80
|
+
```
|
|
81
|
+
#arch: c, aarch64_use_c
|
|
82
|
+
#platform: ios
|
|
83
|
+
((void(*)(id, SEL, id))objc_msgSend)(
|
|
84
|
+
(id)self->handle, sel_registerName("setText:"),
|
|
85
|
+
((id(*)(id, SEL, const char*))objc_msgSend)(
|
|
86
|
+
(id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), text));
|
|
87
|
+
```
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
pub func get_text = (self, out string) {
|
|
91
|
+
```
|
|
92
|
+
#arch: c, aarch64_use_c
|
|
93
|
+
#platform: macos
|
|
94
|
+
id str = ((id(*)(id, SEL))objc_msgSend)(
|
|
95
|
+
(id)self->handle, sel_registerName("stringValue"));
|
|
96
|
+
const char *cstr = ((const char*(*)(id, SEL))objc_msgSend)(
|
|
97
|
+
str, sel_registerName("UTF8String"));
|
|
98
|
+
return strdup(cstr);
|
|
99
|
+
```
|
|
100
|
+
```
|
|
101
|
+
#arch: c, aarch64_use_c
|
|
102
|
+
#platform: ios
|
|
103
|
+
id str = ((id(*)(id, SEL))objc_msgSend)(
|
|
104
|
+
(id)self->handle, sel_registerName("text"));
|
|
105
|
+
const char *cstr = ((const char*(*)(id, SEL))objc_msgSend)(
|
|
106
|
+
str, sel_registerName("UTF8String"));
|
|
107
|
+
return strdup(cstr);
|
|
108
|
+
```
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ── Control trait conformance ──
|
|
112
|
+
pub func intrinsic_size = (self, out Size) {
|
|
113
|
+
var [w, h] = native_intrinsic(self.handle)
|
|
114
|
+
var Size s = Size()
|
|
115
|
+
s.width = w
|
|
116
|
+
s.height = h
|
|
117
|
+
return s
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
pub func measure = (self, BoxConstraints constraints, out Size) {
|
|
121
|
+
var Size s = self.intrinsic_size()
|
|
122
|
+
if s.width > constraints.max_width {
|
|
123
|
+
s.width = constraints.max_width
|
|
124
|
+
}
|
|
125
|
+
if s.width < constraints.min_width {
|
|
126
|
+
s.width = constraints.min_width
|
|
127
|
+
}
|
|
128
|
+
if s.height > constraints.max_height {
|
|
129
|
+
s.height = constraints.max_height
|
|
130
|
+
}
|
|
131
|
+
if s.height < constraints.min_height {
|
|
132
|
+
s.height = constraints.min_height
|
|
133
|
+
}
|
|
134
|
+
return s
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
func #destroy = () {
|
|
138
|
+
```
|
|
139
|
+
#arch: c, aarch64_use_c
|
|
140
|
+
#platform: macos
|
|
141
|
+
if (self->handle) {
|
|
142
|
+
((void(*)(id, SEL))objc_msgSend)((id)self->handle, sel_registerName("removeFromSuperview"));
|
|
143
|
+
((void(*)(id, SEL))objc_msgSend)((id)self->handle, sel_registerName("release"));
|
|
144
|
+
self->handle = 0;
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
```
|
|
148
|
+
#arch: c, aarch64_use_c
|
|
149
|
+
#platform: ios
|
|
150
|
+
if (self->handle) {
|
|
151
|
+
((void(*)(id, SEL))objc_msgSend)((id)self->handle, sel_registerName("removeFromSuperview"));
|
|
152
|
+
((void(*)(id, SEL))objc_msgSend)((id)self->handle, sel_registerName("release"));
|
|
153
|
+
self->handle = 0;
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
}
|
|
157
|
+
}
|