step 3: add widget shell sizing and frame pump

This commit is contained in:
2026-05-22 18:33:45 +02:00
parent 13b6a1e65b
commit 743a82f796
14 changed files with 568 additions and 12 deletions

19
tests/test_interaction.py Normal file
View File

@@ -0,0 +1,19 @@
from __future__ import annotations
from dpg_map.interaction import calculate_hit_rect
from dpg_map.sizing import SizeMeasurement, apply_size_measurement
from dpg_map.state import create_map_state
def test_hit_rect_uses_effective_map_size() -> None:
state = create_map_state(tag="hit-rect")
apply_size_measurement(state, SizeMeasurement(width=400, height=250, visible=True))
rect = calculate_hit_rect(state, (10.0, 20.0))
assert rect.x == 10.0
assert rect.y == 20.0
assert rect.width == 400
assert rect.height == 250
assert rect.contains(410.0, 270.0)
assert not rect.contains(411.0, 270.0)

30
tests/test_renderer.py Normal file
View File

@@ -0,0 +1,30 @@
from __future__ import annotations
from dpg_map.commands import CommandKind, MapCommand
from dpg_map.renderer import drain_renderer_commands
from dpg_map.state import DirtyFlags, create_map_state
def test_renderer_command_drain_preserves_structural_order_and_coalesces() -> None:
state = create_map_state(tag="renderer-drain")
state.dirty = DirtyFlags.NONE
state.command_queue.put(MapCommand(CommandKind.ADD_OVERLAY, state.tag, {"tag": "a"}))
state.command_queue.put(MapCommand(CommandKind.SET_VIEW, state.tag, {"zoom": 3}))
state.command_queue.put(MapCommand(CommandKind.SET_VIEW, state.tag, {"zoom": 4}))
state.command_queue.put(MapCommand(CommandKind.UPDATE_OVERLAY, state.tag, {"tag": "a", "v": 1}))
state.command_queue.put(MapCommand(CommandKind.UPDATE_OVERLAY, state.tag, {"tag": "a", "v": 2}))
state.command_queue.put(MapCommand(CommandKind.DELETE_OVERLAY, state.tag, {"tag": "a"}))
commands = drain_renderer_commands(state)
assert [command.kind for command in commands] == [
CommandKind.ADD_OVERLAY,
CommandKind.SET_VIEW,
CommandKind.UPDATE_OVERLAY,
CommandKind.DELETE_OVERLAY,
]
assert commands[1].payload == {"zoom": 4}
assert commands[2].payload == {"tag": "a", "v": 2}
assert state.dirty & DirtyFlags.VIEW
assert state.dirty & DirtyFlags.OVERLAYS

44
tests/test_sizing.py Normal file
View File

@@ -0,0 +1,44 @@
from __future__ import annotations
from dpg_map.sizing import SizeMeasurement, apply_size_measurement, effective_draw_size
from dpg_map.state import DirtyFlags, create_map_state
def test_size_measurement_tracks_last_nonzero_size() -> None:
state = create_map_state(tag="size-last-nonzero")
first = apply_size_measurement(state, SizeMeasurement(width=640, height=360, visible=True))
hidden = apply_size_measurement(state, SizeMeasurement(width=0, height=0, visible=False))
assert first.changed is True
assert state.measured_width == 0
assert state.measured_height == 0
assert state.last_nonzero_width == 640
assert state.last_nonzero_height == 360
assert hidden.became_hidden is True
assert effective_draw_size(state) == (640, 360)
def test_zero_size_does_not_permanently_collapse_map() -> None:
state = create_map_state(tag="size-reappears")
apply_size_measurement(state, SizeMeasurement(width=500, height=300, visible=True))
apply_size_measurement(state, SizeMeasurement(width=0, height=0, visible=False))
update = apply_size_measurement(state, SizeMeasurement(width=700, height=450, visible=True))
assert update.became_visible is True
assert update.effective_width == 700
assert update.effective_height == 450
assert state.last_nonzero_width == 700
assert state.last_nonzero_height == 450
def test_resize_marks_size_dirty() -> None:
state = create_map_state(tag="size-dirty")
state.dirty = DirtyFlags.NONE
apply_size_measurement(state, SizeMeasurement(width=320, height=240, visible=True))
assert state.dirty & DirtyFlags.SIZE
assert state.dirty & DirtyFlags.TILES
assert state.dirty & DirtyFlags.OVERLAYS