|
| 1 | +module gui |
| 2 | + |
| 3 | +import gg |
| 4 | + |
| 5 | +// Helpers |
| 6 | +fn make_window() Window { |
| 7 | + // Minimal window; we do not touch window.ui in these tests |
| 8 | + mut w := Window{} |
| 9 | + // ensure clean renderers |
| 10 | + w.renderers = [] |
| 11 | + return w |
| 12 | +} |
| 13 | + |
| 14 | +fn make_clip(x f32, y f32, w f32, h f32) DrawClip { |
| 15 | + return gg.Rect{ |
| 16 | + x: x |
| 17 | + y: y |
| 18 | + width: w |
| 19 | + height: h |
| 20 | + } |
| 21 | +} |
| 22 | + |
| 23 | +// ----------------------------- |
| 24 | +// rects_overlap basic behavior |
| 25 | +// ----------------------------- |
| 26 | +fn test_rects_overlap() { |
| 27 | + a := make_clip(0, 0, 10, 10) |
| 28 | + b := make_clip(5, 5, 10, 10) |
| 29 | + c := make_clip(10, 0, 5, 5) // touches edge at x=10 |
| 30 | + |
| 31 | + assert rects_overlap(a, b) |
| 32 | + assert !rects_overlap(a, c) // touching edge is not overlapping (strict <) |
| 33 | +} |
| 34 | + |
| 35 | +// ----------------------------- |
| 36 | +// dim_alpha halves the alpha |
| 37 | +// ----------------------------- |
| 38 | +fn test_dim_alpha() { |
| 39 | + c := rgba(10, 20, 30, 201) |
| 40 | + d := dim_alpha(c) |
| 41 | + assert d.r == c.r |
| 42 | + assert d.g == c.g |
| 43 | + assert d.b == c.b |
| 44 | + // Integer division by 2 |
| 45 | + assert d.a == u8(201 / 2) |
| 46 | +} |
| 47 | + |
| 48 | +// -------------------------------------------- |
| 49 | +// render_rectangle emits a single DrawRect |
| 50 | +// -------------------------------------------- |
| 51 | +fn test_render_rectangle_inside_clip() { |
| 52 | + mut w := make_window() |
| 53 | + mut s := Shape{ |
| 54 | + shape_type: .rectangle |
| 55 | + x: 10 |
| 56 | + y: 20 |
| 57 | + width: 30 |
| 58 | + height: 40 |
| 59 | + color: rgb(100, 150, 200) |
| 60 | + fill: true |
| 61 | + radius: 5 |
| 62 | + } |
| 63 | + clip := make_clip(0, 0, 200, 200) |
| 64 | + |
| 65 | + render_rectangle(mut s, clip, mut w) |
| 66 | + |
| 67 | + assert w.renderers.len == 1 |
| 68 | + r := w.renderers[0] |
| 69 | + match r { |
| 70 | + DrawRect { |
| 71 | + assert r.x == s.x |
| 72 | + assert r.y == s.y |
| 73 | + assert r.w == s.width |
| 74 | + assert r.h == s.height |
| 75 | + assert r.style == .fill |
| 76 | + assert r.is_rounded |
| 77 | + assert r.radius == s.radius |
| 78 | + assert r.color == s.color.to_gx_color() |
| 79 | + } |
| 80 | + else { |
| 81 | + assert false, 'expected DrawRect' |
| 82 | + } |
| 83 | + } |
| 84 | +} |
| 85 | + |
| 86 | +fn test_render_rectangle_outside_clip_disables_shape() { |
| 87 | + mut w := make_window() |
| 88 | + mut s := Shape{ |
| 89 | + shape_type: .rectangle |
| 90 | + x: 100 |
| 91 | + y: 100 |
| 92 | + width: 20 |
| 93 | + height: 20 |
| 94 | + color: rgb(10, 10, 10) |
| 95 | + fill: false |
| 96 | + } |
| 97 | + clip := make_clip(0, 0, 50, 50) |
| 98 | + |
| 99 | + render_rectangle(mut s, clip, mut w) |
| 100 | + |
| 101 | + assert w.renderers.len == 0 |
| 102 | + assert s.disabled |
| 103 | +} |
| 104 | + |
| 105 | +// ---------------------------------------- |
| 106 | +// render_circle emits a single DrawCircle |
| 107 | +// ---------------------------------------- |
| 108 | +fn test_render_circle_inside_clip() { |
| 109 | + mut w := make_window() |
| 110 | + mut s := Shape{ |
| 111 | + shape_type: .circle |
| 112 | + x: 0 |
| 113 | + y: 0 |
| 114 | + width: 40 |
| 115 | + height: 20 |
| 116 | + color: rgb(1, 2, 3) |
| 117 | + fill: false |
| 118 | + } |
| 119 | + clip := make_clip(-10, -10, 100, 100) |
| 120 | + |
| 121 | + render_circle(mut s, clip, mut w) |
| 122 | + |
| 123 | + assert w.renderers.len == 1 |
| 124 | + c := w.renderers[0] |
| 125 | + match c { |
| 126 | + DrawCircle { |
| 127 | + // Center should be at (x + w/2, y + h/2) |
| 128 | + assert f32_are_close(c.x, s.x + s.width / 2) |
| 129 | + assert f32_are_close(c.y, s.y + s.height / 2) |
| 130 | + // Radius is half of the shortest side |
| 131 | + assert f32_are_close(c.radius, f32_min(s.width, s.height) / 2) |
| 132 | + assert c.fill == s.fill |
| 133 | + assert c.color == s.color.to_gx_color() |
| 134 | + } |
| 135 | + else { |
| 136 | + assert false, 'expected DrawCircle' |
| 137 | + } |
| 138 | + } |
| 139 | +} |
| 140 | + |
| 141 | +// -------------------------------------------------------- |
| 142 | +// render_layout: clip push before children, pop after |
| 143 | +// -------------------------------------------------------- |
| 144 | +fn test_render_layout_clip_push_pop() { |
| 145 | + mut w := make_window() |
| 146 | + mut root := Layout{ |
| 147 | + shape: &Shape{ |
| 148 | + // Keep it invisible as a container to avoid text/container drawing |
| 149 | + color: color_transparent |
| 150 | + clip: true |
| 151 | + padding: Padding{ |
| 152 | + left: 2 |
| 153 | + right: 3 |
| 154 | + top: 4 |
| 155 | + bottom: 5 |
| 156 | + } |
| 157 | + shape_clip: make_clip(10, 20, 100, 50) |
| 158 | + } |
| 159 | + children: [] |
| 160 | + } |
| 161 | + |
| 162 | + initial_clip := make_clip(0, 0, 400, 400) |
| 163 | + bg := rgb(0, 0, 0) |
| 164 | + |
| 165 | + render_layout(mut root, bg, initial_clip, mut w) |
| 166 | + |
| 167 | + // Expect two clips: computed shape_clip (with padding applied), then pop back to initial |
| 168 | + assert w.renderers.len == 2 |
| 169 | + sc_push := w.renderers[0] |
| 170 | + sc_pop := w.renderers[1] |
| 171 | + |
| 172 | + match sc_push { |
| 173 | + DrawClip { |
| 174 | + assert f32_are_close(sc_push.x, 10 + 2) |
| 175 | + assert f32_are_close(sc_push.y, 20 + 4) |
| 176 | + assert f32_are_close(sc_push.width, 100 - (2 + 3)) |
| 177 | + assert f32_are_close(sc_push.height, 50 - (4 + 5)) |
| 178 | + } |
| 179 | + else { |
| 180 | + assert false, 'expected first renderer to be DrawClip (push)' |
| 181 | + } |
| 182 | + } |
| 183 | + match sc_pop { |
| 184 | + DrawClip { |
| 185 | + assert f32_are_close(sc_pop.x, initial_clip.x) |
| 186 | + assert f32_are_close(sc_pop.y, initial_clip.y) |
| 187 | + assert f32_are_close(sc_pop.width, initial_clip.width) |
| 188 | + assert f32_are_close(sc_pop.height, initial_clip.height) |
| 189 | + } |
| 190 | + else { |
| 191 | + assert false, 'expected second renderer to be DrawClip (pop)' |
| 192 | + } |
| 193 | + } |
| 194 | +} |
0 commit comments