step 5: add stable pan zoom and view commands

This commit is contained in:
2026-05-23 10:19:13 +02:00
parent 563ddd962b
commit 2d6242bd3f
9 changed files with 362 additions and 18 deletions

View File

@@ -1,8 +1,19 @@
from __future__ import annotations
from dpg_map.interaction import calculate_hit_rect
import pytest
import dpg_map as dpgm
from dpg_map.commands import CommandKind
from dpg_map.interaction import (
calculate_hit_rect,
handle_mouse_down,
handle_mouse_drag,
handle_mouse_release,
handle_mouse_wheel,
pan_state_by_pixels,
)
from dpg_map.sizing import SizeMeasurement, apply_size_measurement
from dpg_map.state import create_map_state
from dpg_map.state import DirtyFlags, create_map_state, get_map_state
def test_hit_rect_uses_effective_map_size() -> None:
@@ -17,3 +28,68 @@ def test_hit_rect_uses_effective_map_size() -> None:
assert rect.height == 250
assert rect.contains(410.0, 270.0)
assert not rect.contains(411.0, 270.0)
def test_pan_updates_center_and_queues_view_command() -> None:
state = create_map_state(tag="pan", center=(0.0, 0.0), zoom=3)
apply_size_measurement(state, SizeMeasurement(width=400, height=300, visible=True))
old_center = state.center
pan_state_by_pixels(state, 40.0, 0.0)
assert state.center != old_center
assert state.center[1] < old_center[1]
assert state.dirty & DirtyFlags.VIEW
drained = state.command_queue.drain()
assert drained[-1].kind is CommandKind.SET_VIEW
assert drained[-1].payload["center"] == state.center
def test_mouse_drag_uses_active_drag_state() -> None:
state = create_map_state(tag="drag", center=(0.0, 0.0), zoom=3)
apply_size_measurement(state, SizeMeasurement(width=400, height=300, visible=True))
rect = calculate_hit_rect(state, (10.0, 20.0))
handle_mouse_down(state, (20.0, 30.0), rect)
assert state.interaction.active_drag is True
handle_mouse_drag(state, (45.0, 30.0))
handle_mouse_release(state)
assert state.interaction.active_drag is False
assert state.interaction.last_mouse_position is None
assert state.center[1] < 0.0
def test_wheel_zoom_keeps_cursor_latlon_stable() -> None:
state = create_map_state(tag="wheel", center=(47.9029, 1.9093), zoom=8)
apply_size_measurement(state, SizeMeasurement(width=800, height=600, visible=True))
rect = calculate_hit_rect(state, (100.0, 50.0))
before = dpgm.screen_to_latlon(300.0, 200.0, map_tag="wheel")
handle_mouse_wheel(state, mouse_pos=(400.0, 250.0), wheel_delta=1.0, hit_rect=rect)
after = dpgm.screen_to_latlon(300.0, 200.0, map_tag="wheel")
assert state.zoom == 9
assert after == pytest.approx(before, abs=1e-7)
def test_view_coordinate_helpers_roundtrip() -> None:
create_map_state(tag="view-roundtrip", center=(47.9029, 1.9093), zoom=12)
state = get_map_state("view-roundtrip")
apply_size_measurement(state, SizeMeasurement(width=800, height=600, visible=True))
screen = dpgm.latlon_to_screen(47.91, 1.92, map_tag="view-roundtrip")
latlon = dpgm.screen_to_latlon(*screen, map_tag="view-roundtrip")
assert latlon == pytest.approx((47.91, 1.92), abs=1e-7)
def test_fit_bounds_sets_center_and_zoom() -> None:
create_map_state(tag="fit", center=(0.0, 0.0), zoom=2)
state = get_map_state("fit")
apply_size_measurement(state, SizeMeasurement(width=800, height=600, visible=True))
dpgm.fit_bounds(((47.8, 1.8), (48.0, 2.0)), map_tag="fit")
assert dpgm.get_center(map_tag="fit") == pytest.approx((47.9, 1.9))
assert dpgm.get_zoom(map_tag="fit") > 2