from __future__ import annotations 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 DirtyFlags, create_map_state, get_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) 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