test: v0.4.0 focus/drag/resize assertions
Adds 46 new W.3 assertions covering: focus(id) reorders within open_order; focus(hud) no-op; raise alias; lower(id) to bottom; get_focused tier priority + nil-when-empty; click-to-focus auto-routing; drag updates bounds_override; drag screen-clamp on all four edges; resize updates bounds_override; min_size + max_size clamps; dispatch-time drag-start + resize-start consume the click; chromeless drag-start excluded; bounds_override survives drag-end and is respected by point_in_any_panel. Bumps panel-test 0.3.0 -> 0.4.0 + panel-dep 0.4.0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
39
README.md
39
README.md
@@ -1,18 +1,23 @@
|
|||||||
# lib-core.panel-test
|
# lib-core.panel-test
|
||||||
|
|
||||||
Test-module for `lib-core.panel`. v0.3.0 expands to 79 assertions:
|
Test-module for `lib-core.panel`. v0.4.0 expands to 128 assertions:
|
||||||
- v0.1.x: registry lifecycle, theme validation, error handling,
|
- v0.1.x: registry lifecycle, theme validation, error handling,
|
||||||
pause-gate, context-menu dispatch.
|
pause-gate, context-menu dispatch.
|
||||||
- v0.2.0 (W.0): multi-active model, 11 layout-slots, custom-fn layout,
|
- v0.2.0 (W.0): multi-active model, 11 layout-slots, custom-fn layout,
|
||||||
hit-test reverse-open-order, bw-compat shim.
|
hit-test reverse-open-order, bw-compat shim.
|
||||||
- v0.3.0 (W.2): z-tiers (hud/normal/top), persistent windows,
|
- v0.3.0 (W.2): z-tiers (hud/normal/top), persistent windows,
|
||||||
input_block routing (none/self/all), default-input_block per tier,
|
input_block routing (none/self/all), default-input_block per tier,
|
||||||
panel.point_in_any_panel public API.
|
panel.point_in_any_panel public API, chromeless guards, top-tier
|
||||||
|
modal swallow.
|
||||||
|
- v0.4.0 (W.3): focus API (focus/raise/lower/get_focused),
|
||||||
|
click-to-focus auto-routing, drag-by-title-bar with 32px
|
||||||
|
screen-clamp, resize-by-SE-corner with min/max_size clamps,
|
||||||
|
bounds_override pattern persistence, chromeless drag guard.
|
||||||
|
|
||||||
**Version:** 0.3.0
|
**Version:** 0.4.0
|
||||||
**Lib-ID:** lib-core.panel-test
|
**Lib-ID:** lib-core.panel-test
|
||||||
**Requires:** lib-core.panel v0.3.0
|
**Requires:** lib-core.panel v0.4.0
|
||||||
**Tags:** test, panel, ui, window-manager
|
**Tags:** test, panel, ui, window-manager, focus, drag, resize
|
||||||
|
|
||||||
## Running
|
## Running
|
||||||
|
|
||||||
@@ -23,9 +28,9 @@ SPOREL_LIBS_DIR=~/Projects/Sporel/sporel-libs SPOREL_CI=1 SPOREL_LOG_STDERR=1 \
|
|||||||
./build/Sporel.exe --test-libs=lib-core.panel-test 2>&1 | tail -15
|
./build/Sporel.exe --test-libs=lib-core.panel-test 2>&1 | tail -15
|
||||||
```
|
```
|
||||||
|
|
||||||
Expected: `pass=79 fail=0`.
|
Expected: `pass=128 fail=0`.
|
||||||
|
|
||||||
## Assertion Summary (v0.3.0)
|
## Assertion Summary (v0.4.0)
|
||||||
|
|
||||||
**v0.1.x baseline (10 assertions):**
|
**v0.1.x baseline (10 assertions):**
|
||||||
1. register + open / close round-trip
|
1. register + open / close round-trip
|
||||||
@@ -45,7 +50,7 @@ layout-slot resolution (left-half, right-half, center, custom fn),
|
|||||||
loud-error on unknown slot, hit-test reverse-open-order, is_pausing
|
loud-error on unknown slot, hit-test reverse-open-order, is_pausing
|
||||||
across all open windows.
|
across all open windows.
|
||||||
|
|
||||||
**v0.3.0 W.2 z-tiers + persistent + input-block (25 assertions):**
|
**v0.3.0 W.2 z-tiers + persistent + input-block (28 assertions):**
|
||||||
- persistent flag auto-opens at register-time + is in open_order
|
- persistent flag auto-opens at register-time + is in open_order
|
||||||
- z_tier render-order is hud → normal → top
|
- z_tier render-order is hud → normal → top
|
||||||
- within z_tier, open-order preserved
|
- within z_tier, open-order preserved
|
||||||
@@ -58,3 +63,21 @@ across all open windows.
|
|||||||
- Loud-Error on unknown input_block
|
- Loud-Error on unknown input_block
|
||||||
- default input_block per tier (hud=none, normal=self, top=all)
|
- default input_block per tier (hud=none, normal=self, top=all)
|
||||||
- point_in_any_panel public API (inside / outside / none open)
|
- point_in_any_panel public API (inside / outside / none open)
|
||||||
|
- chromeless suppresses phantom close-button hit-test
|
||||||
|
- top-tier modal swallows outside-clicks before lower tiers can claim
|
||||||
|
|
||||||
|
**v0.4.0 W.3 focus + drag + resize (46 assertions):**
|
||||||
|
- focus(id) reorders within open_order; focus(hud) is no-op
|
||||||
|
- raise alias = focus
|
||||||
|
- lower(id) moves to bottom of open_order
|
||||||
|
- get_focused() prioritizes top-tier over normal; nil when nothing open
|
||||||
|
- click on window auto-focuses (non-hud only)
|
||||||
|
- drag updates bounds_override (simulate-backdoor)
|
||||||
|
- drag screen-clamp keeps 32px of title-bar visible on all edges
|
||||||
|
- resize updates bounds_override (SE-corner; simulate-backdoor)
|
||||||
|
- resize min_size + max_size constraints clamp correctly
|
||||||
|
- dispatch-time drag-start fires on real title-bar click
|
||||||
|
- dispatch-time resize-start fires on real SE-corner click
|
||||||
|
- chromeless widget does NOT drag-start on top-area click
|
||||||
|
- bounds_override survives drag-end (persists in window record)
|
||||||
|
- point_in_any_panel respects bounds_override
|
||||||
|
|||||||
367
init.lua
367
init.lua
@@ -1,11 +1,16 @@
|
|||||||
-- lib-core.panel-test v0.3.0 — Panel test suite
|
-- lib-core.panel-test v0.4.0 — Panel test suite
|
||||||
-- Exercises: registry lifecycle, theme, errors, pause-gate, context-menu
|
-- Exercises: registry lifecycle, theme, errors, pause-gate, context-menu
|
||||||
-- dispatch, multi-active model, layout-slots, hit-test reverse-order,
|
-- dispatch, multi-active model, layout-slots, hit-test reverse-order,
|
||||||
-- z_tiers, persistent windows, input_block routing,
|
-- z_tiers, persistent windows, input_block routing,
|
||||||
-- panel.point_in_any_panel.
|
-- panel.point_in_any_panel, focus/raise/lower API, click-to-focus,
|
||||||
|
-- drag-by-title-bar (with screen-clamp), resize-by-SE-corner (with min/max
|
||||||
|
-- size constraints).
|
||||||
-- Render paths are NOT tested here: engine.render.* is blocked in test-mode
|
-- Render paths are NOT tested here: engine.render.* is blocked in test-mode
|
||||||
-- (assert_in_render_phase guard in engine_lua_render.c). Input dispatch is
|
-- (assert_in_render_phase guard in engine_lua_render.c). Input dispatch is
|
||||||
-- exercised via panel._dispatch_event_for_test(event).
|
-- exercised via panel._dispatch_event_for_test(event). Drag/resize state
|
||||||
|
-- is exercised via panel._test_simulate_drag_{start,move,end} and
|
||||||
|
-- panel._test_simulate_resize_{start,move,end} backdoors (engine.input
|
||||||
|
-- is not poll-able from a test-lib context).
|
||||||
|
|
||||||
local panel = require("lib-core.panel")
|
local panel = require("lib-core.panel")
|
||||||
local T = engine.test
|
local T = engine.test
|
||||||
@@ -602,6 +607,362 @@ function M.run_tests(_ctx)
|
|||||||
T.assert(not normal_clicked_m,
|
T.assert(not normal_clicked_m,
|
||||||
"modal swallow: normal-tier widget does NOT receive click while top-tier all-modal is open")
|
"modal swallow: normal-tier widget does NOT receive click while top-tier all-modal is open")
|
||||||
panel._test_reset_all()
|
panel._test_reset_all()
|
||||||
|
|
||||||
|
-- ==================================================================
|
||||||
|
-- W.3 v0.4.0 — Focus + Drag + Resize
|
||||||
|
-- ==================================================================
|
||||||
|
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
-- W.3 #1: focus(id) reorders within open_order
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
panel.register("w_fA", make_widget({ title = "A" }))
|
||||||
|
panel.register("w_fB", make_widget({ title = "B" }))
|
||||||
|
panel.open("w_fA")
|
||||||
|
panel.open("w_fB")
|
||||||
|
T.equals(panel._test_get_focused_id(), "w_fB",
|
||||||
|
"W.3 B focused initially (last-opened)")
|
||||||
|
panel.focus("w_fA")
|
||||||
|
T.equals(panel._test_get_focused_id(), "w_fA",
|
||||||
|
"W.3 focus(A) reorders so A is now focused")
|
||||||
|
local fo = panel._test_get_open_ids()
|
||||||
|
T.equals(fo[#fo], "w_fA",
|
||||||
|
"W.3 focus moves widget to end of open_order")
|
||||||
|
panel._test_reset_all()
|
||||||
|
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
-- W.3 #2: focus on hud-tier widget is a no-op
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
panel.register("w_hud_f", make_widget({ title = "Hud" }),
|
||||||
|
{ z_tier = "hud", layout = "top" })
|
||||||
|
panel.register("w_norm_f", make_widget({ title = "Norm" }),
|
||||||
|
{ z_tier = "normal", layout = "bottom" })
|
||||||
|
panel.open("w_hud_f")
|
||||||
|
panel.open("w_norm_f")
|
||||||
|
-- normal-tier opened last → focused
|
||||||
|
T.equals(panel._test_get_focused_id(), "w_norm_f",
|
||||||
|
"W.3 normal-tier focused after open")
|
||||||
|
panel.focus("w_hud_f") -- should be no-op
|
||||||
|
T.equals(panel._test_get_focused_id(), "w_norm_f",
|
||||||
|
"W.3 focus(hud-tier widget) is a no-op (hud never focusable)")
|
||||||
|
panel._test_reset_all()
|
||||||
|
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
-- W.3 #3: raise alias = focus
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
panel.register("w_rA", make_widget({ title = "A" }))
|
||||||
|
panel.register("w_rB", make_widget({ title = "B" }))
|
||||||
|
panel.open("w_rA")
|
||||||
|
panel.open("w_rB")
|
||||||
|
panel.raise("w_rA")
|
||||||
|
T.equals(panel._test_get_focused_id(), "w_rA",
|
||||||
|
"W.3 raise(id) is alias for focus(id)")
|
||||||
|
panel._test_reset_all()
|
||||||
|
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
-- W.3 #4: lower(id) moves to bottom of open_order
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
panel.register("w_lA", make_widget({ title = "A" }))
|
||||||
|
panel.register("w_lB", make_widget({ title = "B" }))
|
||||||
|
panel.open("w_lA")
|
||||||
|
panel.open("w_lB")
|
||||||
|
panel.lower("w_lB") -- B was focused; lower → bottom
|
||||||
|
local lo = panel._test_get_open_ids()
|
||||||
|
T.equals(lo[1], "w_lB",
|
||||||
|
"W.3 lower(B) moves B to bottom of open_order")
|
||||||
|
T.equals(panel._test_get_focused_id(), "w_lA",
|
||||||
|
"W.3 after lower(B), A is focused (last in order)")
|
||||||
|
panel._test_reset_all()
|
||||||
|
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
-- W.3 #5: get_focused() prioritizes top-tier over normal
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
panel.register("w_gn", make_widget({ title = "N" }),
|
||||||
|
{ z_tier = "normal", layout = "left" })
|
||||||
|
panel.register("w_gt", make_widget({ title = "T" }),
|
||||||
|
{ z_tier = "top", layout = "center" })
|
||||||
|
panel.open("w_gt")
|
||||||
|
panel.open("w_gn")
|
||||||
|
-- gn opened last; but top-tier gt should win for get_focused
|
||||||
|
T.equals(panel.get_focused(), "w_gt",
|
||||||
|
"W.3 get_focused() returns top-tier widget even when normal-tier is last-opened")
|
||||||
|
panel._test_reset_all()
|
||||||
|
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
-- W.3 #6: get_focused() returns last-opened when no top-tier
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
panel.register("w_g1", make_widget({ title = "1" }))
|
||||||
|
panel.register("w_g2", make_widget({ title = "2" }))
|
||||||
|
panel.open("w_g1")
|
||||||
|
panel.open("w_g2")
|
||||||
|
T.equals(panel.get_focused(), "w_g2",
|
||||||
|
"W.3 get_focused() returns last-opened when no top-tier window")
|
||||||
|
panel._test_reset_all()
|
||||||
|
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
-- W.3 #7: get_focused() returns nil when nothing open
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
T.assert(panel.get_focused() == nil,
|
||||||
|
"W.3 get_focused() returns nil when no windows open")
|
||||||
|
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
-- W.3 #8: click on window auto-focuses
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
panel.register("w_acA", make_widget({ title = "A" }), { layout = "left-half" })
|
||||||
|
panel.register("w_acB", make_widget({ title = "B" }), { layout = "right-half" })
|
||||||
|
panel.open("w_acA")
|
||||||
|
panel.open("w_acB")
|
||||||
|
T.equals(panel._test_get_focused_id(), "w_acB",
|
||||||
|
"W.3 B initial-focused")
|
||||||
|
-- Click in A's left-half → auto-focus A
|
||||||
|
local sw_ac, sh_ac = panel._test_get_screen_size()
|
||||||
|
panel._dispatch_event_for_test({
|
||||||
|
kind = "click", button = "left",
|
||||||
|
x = sw_ac * 0.25, y = sh_ac * 0.5,
|
||||||
|
})
|
||||||
|
T.equals(panel._test_get_focused_id(), "w_acA",
|
||||||
|
"W.3 click on A auto-focuses A")
|
||||||
|
panel._test_reset_all()
|
||||||
|
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
-- W.3 #9: focus(hud-tier) does NOT promote hud above normal-tier
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
-- focus() is the modder-facing API for "bring to top within tier".
|
||||||
|
-- The contract is: hud-tier widgets are NEVER promoted via focus()
|
||||||
|
-- (they are cosmetic overlays). Verify by opening normal, then hud
|
||||||
|
-- (hud is naturally last-opened by virtue of open ordering), then
|
||||||
|
-- explicitly call focus on each and verify the open_order tail.
|
||||||
|
panel.register("w_hf_norm", make_widget({ title = "N" }),
|
||||||
|
{ z_tier = "normal", layout = "right-half" })
|
||||||
|
panel.register("w_hf_hud", make_widget({ title = "H" }),
|
||||||
|
{ z_tier = "hud", input_block = "self", layout = "left-half" })
|
||||||
|
panel.open("w_hf_hud") -- opens first
|
||||||
|
panel.open("w_hf_norm") -- opens last → last in open_order
|
||||||
|
T.equals(panel._test_get_focused_id(), "w_hf_norm",
|
||||||
|
"W.3 normal opened last → last in open_order")
|
||||||
|
-- focus(hud-tier) is a no-op: order is preserved.
|
||||||
|
panel.focus("w_hf_hud")
|
||||||
|
T.equals(panel._test_get_focused_id(), "w_hf_norm",
|
||||||
|
"W.3 focus(hud-tier widget) is a no-op (order unchanged)")
|
||||||
|
-- Click on hud-tier should also be a no-op for focus (auto-focus
|
||||||
|
-- internally calls M.focus, which is no-op for hud).
|
||||||
|
local sw_hf, sh_hf = panel._test_get_screen_size()
|
||||||
|
panel._dispatch_event_for_test({
|
||||||
|
kind = "click", button = "left",
|
||||||
|
x = sw_hf * 0.25, y = sh_hf * 0.5,
|
||||||
|
})
|
||||||
|
T.equals(panel._test_get_focused_id(), "w_hf_norm",
|
||||||
|
"W.3 click on hud-tier does NOT change focus (auto-focus no-op for hud)")
|
||||||
|
panel._test_reset_all()
|
||||||
|
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
-- W.3 #10: drag updates bounds_override
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
panel.register("w_d", make_widget({ title = "D" }), {
|
||||||
|
draggable = true,
|
||||||
|
layout = function(_sw, _sh) return {x=100, y=100, w=200, h=150} end,
|
||||||
|
})
|
||||||
|
panel.open("w_d")
|
||||||
|
-- Start drag at title-bar click point (110, 105) — 10px inside top-left
|
||||||
|
panel._test_simulate_drag_start("w_d", 110, 105)
|
||||||
|
T.equals(panel._test_get_dragging_id(), "w_d",
|
||||||
|
"W.3 drag-start sets dragging_id")
|
||||||
|
-- Move mouse +50 +30 → window moves from (100,100) to (150,130)
|
||||||
|
panel._test_simulate_drag_move(160, 135)
|
||||||
|
local bd = panel._test_get_window_bounds("w_d")
|
||||||
|
T.equals(bd.x, 150, "W.3 drag updates x (+50)")
|
||||||
|
T.equals(bd.y, 130, "W.3 drag updates y (+30)")
|
||||||
|
T.equals(bd.w, 200, "W.3 drag preserves w")
|
||||||
|
T.equals(bd.h, 150, "W.3 drag preserves h")
|
||||||
|
panel._test_simulate_drag_end()
|
||||||
|
T.assert(panel._test_get_dragging_id() == nil,
|
||||||
|
"W.3 drag-end clears dragging_id")
|
||||||
|
panel._test_reset_all()
|
||||||
|
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
-- W.3 #11: drag screen-clamp keeps title-bar visible (32px minimum)
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
panel.register("w_dc", make_widget({ title = "DC" }), {
|
||||||
|
draggable = true,
|
||||||
|
layout = function(_sw, _sh) return {x=100, y=100, w=200, h=150} end,
|
||||||
|
})
|
||||||
|
panel.open("w_dc")
|
||||||
|
panel._test_simulate_drag_start("w_dc", 110, 110)
|
||||||
|
-- Try to drag way off-screen left + up
|
||||||
|
panel._test_simulate_drag_move(-5000, -5000)
|
||||||
|
local bdc = panel._test_get_window_bounds("w_dc")
|
||||||
|
local sw_dc, sh_dc = panel._test_get_screen_size()
|
||||||
|
-- x clamp: at most (-w + 32) = -200 + 32 = -168
|
||||||
|
T.assert(bdc.x >= -200 + 32 - 0.01,
|
||||||
|
"W.3 drag x-clamp keeps 32px visible on right edge when pushed left")
|
||||||
|
-- y clamp: at most 0 (title-bar top must stay on-screen)
|
||||||
|
T.assert(bdc.y >= 0 - 0.01,
|
||||||
|
"W.3 drag y-clamp prevents title-bar from leaving top of screen")
|
||||||
|
-- Try drag way off-screen right + down
|
||||||
|
panel._test_simulate_drag_move(99999, 99999)
|
||||||
|
bdc = panel._test_get_window_bounds("w_dc")
|
||||||
|
-- x clamp: at most (sw - 32)
|
||||||
|
T.assert(bdc.x <= sw_dc - 32 + 0.01,
|
||||||
|
"W.3 drag x-clamp keeps 32px visible on left edge when pushed right")
|
||||||
|
T.assert(bdc.y <= sh_dc - 32 + 0.01,
|
||||||
|
"W.3 drag y-clamp keeps title-bar reachable when pushed down")
|
||||||
|
panel._test_simulate_drag_end()
|
||||||
|
panel._test_reset_all()
|
||||||
|
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
-- W.3 #12: resize updates bounds (SE-corner)
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
panel.register("w_r", make_widget({ title = "R" }), {
|
||||||
|
resizable = true,
|
||||||
|
layout = function(_sw, _sh) return {x=100, y=100, w=200, h=150} end,
|
||||||
|
})
|
||||||
|
panel.open("w_r")
|
||||||
|
-- Start resize at SE-corner (~ 300, 250); use the actual coords
|
||||||
|
panel._test_simulate_resize_start("w_r", 300, 250)
|
||||||
|
T.equals(panel._test_get_resizing_id(), "w_r",
|
||||||
|
"W.3 resize-start sets resizing_id")
|
||||||
|
-- Drag SE-corner +50 +40 → w becomes 250, h becomes 190
|
||||||
|
panel._test_simulate_resize_move(350, 290)
|
||||||
|
local br = panel._test_get_window_bounds("w_r")
|
||||||
|
T.equals(br.w, 250, "W.3 resize updates w (+50)")
|
||||||
|
T.equals(br.h, 190, "W.3 resize updates h (+40)")
|
||||||
|
T.equals(br.x, 100, "W.3 resize preserves x")
|
||||||
|
T.equals(br.y, 100, "W.3 resize preserves y")
|
||||||
|
panel._test_simulate_resize_end()
|
||||||
|
T.assert(panel._test_get_resizing_id() == nil,
|
||||||
|
"W.3 resize-end clears resizing_id")
|
||||||
|
panel._test_reset_all()
|
||||||
|
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
-- W.3 #13: resize respects min_size constraint
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
panel.register("w_rmin", make_widget({ title = "Rmin" }), {
|
||||||
|
resizable = true,
|
||||||
|
min_size = { w = 180, h = 120 },
|
||||||
|
layout = function(_sw, _sh) return {x=100, y=100, w=200, h=150} end,
|
||||||
|
})
|
||||||
|
panel.open("w_rmin")
|
||||||
|
panel._test_simulate_resize_start("w_rmin", 300, 250)
|
||||||
|
-- Try to shrink way past min — should clamp to min_size
|
||||||
|
panel._test_simulate_resize_move(0, 0)
|
||||||
|
local brmin = panel._test_get_window_bounds("w_rmin")
|
||||||
|
T.equals(brmin.w, 180, "W.3 resize clamps to min_size.w")
|
||||||
|
T.equals(brmin.h, 120, "W.3 resize clamps to min_size.h")
|
||||||
|
panel._test_simulate_resize_end()
|
||||||
|
panel._test_reset_all()
|
||||||
|
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
-- W.3 #14: resize respects max_size constraint
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
panel.register("w_rmax", make_widget({ title = "Rmax" }), {
|
||||||
|
resizable = true,
|
||||||
|
max_size = { w = 250, h = 180 },
|
||||||
|
layout = function(_sw, _sh) return {x=100, y=100, w=200, h=150} end,
|
||||||
|
})
|
||||||
|
panel.open("w_rmax")
|
||||||
|
panel._test_simulate_resize_start("w_rmax", 300, 250)
|
||||||
|
-- Try to grow way past max — should clamp
|
||||||
|
panel._test_simulate_resize_move(99999, 99999)
|
||||||
|
local brmax = panel._test_get_window_bounds("w_rmax")
|
||||||
|
T.equals(brmax.w, 250, "W.3 resize clamps to max_size.w")
|
||||||
|
T.equals(brmax.h, 180, "W.3 resize clamps to max_size.h")
|
||||||
|
panel._test_simulate_resize_end()
|
||||||
|
panel._test_reset_all()
|
||||||
|
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
-- W.3 #15: drag-start via _dispatch_event on title-bar click
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
-- This exercises the real dispatch-time drag-start detection rather
|
||||||
|
-- than the simulate-backdoor.
|
||||||
|
local handler_fired_d = false
|
||||||
|
panel.register("w_dd", make_widget({
|
||||||
|
title = "DD",
|
||||||
|
handle_input = function(_ctx, _ev) handler_fired_d = true end,
|
||||||
|
}), {
|
||||||
|
draggable = true,
|
||||||
|
layout = function(_sw, _sh) return {x=100, y=100, w=200, h=150} end,
|
||||||
|
})
|
||||||
|
panel.open("w_dd")
|
||||||
|
-- Click in the title-bar area (top of window) → drag-start, handler NOT invoked
|
||||||
|
panel._dispatch_event_for_test({
|
||||||
|
kind = "click", button = "left",
|
||||||
|
x = 150, y = 108, -- well inside title-bar (font_size_title=18 + padding=8*2 = 34 px)
|
||||||
|
})
|
||||||
|
T.equals(panel._test_get_dragging_id(), "w_dd",
|
||||||
|
"W.3 dispatch-time drag-start sets dragging_id")
|
||||||
|
T.assert(not handler_fired_d,
|
||||||
|
"W.3 dispatch-time drag-start consumes the click (handler NOT invoked)")
|
||||||
|
panel._test_simulate_drag_end()
|
||||||
|
panel._test_reset_all()
|
||||||
|
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
-- W.3 #16: resize-start via _dispatch_event on SE-corner click
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
local handler_fired_r = false
|
||||||
|
panel.register("w_rr", make_widget({
|
||||||
|
title = "RR",
|
||||||
|
handle_input = function(_ctx, _ev) handler_fired_r = true end,
|
||||||
|
}), {
|
||||||
|
resizable = true,
|
||||||
|
layout = function(_sw, _sh) return {x=100, y=100, w=200, h=150} end,
|
||||||
|
})
|
||||||
|
panel.open("w_rr")
|
||||||
|
-- Click in SE-corner (12x12 zone at right-bottom)
|
||||||
|
panel._dispatch_event_for_test({
|
||||||
|
kind = "click", button = "left",
|
||||||
|
x = 295, y = 245, -- inside 12px SE handle (bottom-right = 300, 250)
|
||||||
|
})
|
||||||
|
T.equals(panel._test_get_resizing_id(), "w_rr",
|
||||||
|
"W.3 dispatch-time resize-start sets resizing_id")
|
||||||
|
T.assert(not handler_fired_r,
|
||||||
|
"W.3 dispatch-time resize-start consumes the click (handler NOT invoked)")
|
||||||
|
panel._test_simulate_resize_end()
|
||||||
|
panel._test_reset_all()
|
||||||
|
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
-- W.3 #17: chromeless widget does NOT drag-start on top-area click
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
-- chromeless has no defined title-bar. Drag must NOT engage.
|
||||||
|
local hf_chrome_d = false
|
||||||
|
panel.register("w_chrome_d", make_widget({
|
||||||
|
title = "CD",
|
||||||
|
handle_input = function(_ctx, _ev) hf_chrome_d = true end,
|
||||||
|
}), {
|
||||||
|
chromeless = true,
|
||||||
|
draggable = true, -- modder set both; chromeless takes precedence
|
||||||
|
layout = function(_sw, _sh) return {x=100, y=100, w=200, h=150} end,
|
||||||
|
})
|
||||||
|
panel.open("w_chrome_d")
|
||||||
|
-- Click in what WOULD be the title-bar area on a chromed widget
|
||||||
|
panel._dispatch_event_for_test({
|
||||||
|
kind = "click", button = "left", x = 150, y = 108,
|
||||||
|
})
|
||||||
|
T.assert(panel._test_get_dragging_id() == nil,
|
||||||
|
"W.3 chromeless widget does NOT drag-start (no title-bar)")
|
||||||
|
T.assert(hf_chrome_d,
|
||||||
|
"W.3 chromeless widget's handler receives the click (no drag intercept)")
|
||||||
|
panel._test_reset_all()
|
||||||
|
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
-- W.3 #18: bounds_override survives the layout-fn (drag persists)
|
||||||
|
-- ------------------------------------------------------------------
|
||||||
|
-- Once bounds_override is set, the layout-fn no longer drives bounds.
|
||||||
|
panel.register("w_bo", make_widget({ title = "BO" }), {
|
||||||
|
draggable = true,
|
||||||
|
layout = function(_sw, _sh) return {x=100, y=100, w=200, h=150} end,
|
||||||
|
})
|
||||||
|
panel.open("w_bo")
|
||||||
|
panel._test_simulate_drag_start("w_bo", 110, 110)
|
||||||
|
panel._test_simulate_drag_move(310, 310)
|
||||||
|
panel._test_simulate_drag_end()
|
||||||
|
local bbo = panel._test_get_window_bounds("w_bo")
|
||||||
|
T.equals(bbo.x, 300, "W.3 bounds_override survives after drag-end (x)")
|
||||||
|
T.equals(bbo.y, 300, "W.3 bounds_override survives after drag-end (y)")
|
||||||
|
-- Verify point_in_any_panel uses override too
|
||||||
|
T.assert(panel.point_in_any_panel(350, 350),
|
||||||
|
"W.3 point_in_any_panel respects bounds_override")
|
||||||
|
T.assert(not panel.point_in_any_panel(150, 150),
|
||||||
|
"W.3 point_in_any_panel does NOT report old layout-fn position")
|
||||||
|
panel._test_reset_all()
|
||||||
end
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"id": "lib-core.panel-test",
|
"id": "lib-core.panel-test",
|
||||||
"role": "test",
|
"role": "test",
|
||||||
"version": "0.3.0",
|
"version": "0.4.0",
|
||||||
"api_min": "0.1",
|
"api_min": "0.1",
|
||||||
"deps": [
|
"deps": [
|
||||||
{"id": "lib-core.panel", "version": "0.3.0"}
|
{"id": "lib-core.panel", "version": "0.4.0"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user