ui: basic map scroller

This commit is contained in:
Ilia Denisov
2026-03-06 23:29:06 +02:00
committed by GitHub
parent 29d188969b
commit 1de621c743
68 changed files with 9861 additions and 118 deletions
@@ -0,0 +1,171 @@
package world
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestWorldDeltaFixedToCanvasPx_RemainderAccumulatesPositive(t *testing.T) {
t.Parallel()
// zoom=1: px = (deltaWorldFp * 1000) / 1e6
// For deltaWorldFp=1, each step contributes 0 px with remainder,
// and after 1000 steps it must become 1 px total.
zoomFp := SCALE
var rem int64
sum := 0
for i := 0; i < 1000; i++ {
sum += worldDeltaFixedToCanvasPx(1, zoomFp, &rem)
}
require.Equal(t, 1, sum)
}
func TestWorldDeltaFixedToCanvasPx_RemainderAccumulatesNegative(t *testing.T) {
t.Parallel()
zoomFp := SCALE
var rem int64
sum := 0
for i := 0; i < 1000; i++ {
sum += worldDeltaFixedToCanvasPx(-1, zoomFp, &rem)
}
require.Equal(t, -1, sum)
}
func TestComputePanShiftPx_FirstCallRequiresFullRedraw(t *testing.T) {
t.Parallel()
w := NewWorld(10, 10)
params := RenderParams{
ViewportWidthPx: 100,
ViewportHeightPx: 80,
MarginXPx: 25,
MarginYPx: 20,
CameraXWorldFp: 5 * SCALE,
CameraYWorldFp: 5 * SCALE,
CameraZoom: 1.0,
}
_, _, err := w.ComputePanShiftPx(params)
require.ErrorIs(t, err, errIncrementalStateNotReady)
}
func TestComputePanShiftPx_ZoomOrViewportChangeForcesFullRedraw(t *testing.T) {
t.Parallel()
w := NewWorld(10, 10)
base := RenderParams{
ViewportWidthPx: 100,
ViewportHeightPx: 80,
MarginXPx: 25,
MarginYPx: 20,
CameraXWorldFp: 5 * SCALE,
CameraYWorldFp: 5 * SCALE,
CameraZoom: 1.0,
}
require.NoError(t, w.CommitFullRedrawState(base))
changed := base
changed.CameraZoom = 2.0
_, _, err := w.ComputePanShiftPx(changed)
require.ErrorIs(t, err, errIncrementalZoomMismatch)
changed2 := base
changed2.ViewportWidthPx = 101
_, _, err = w.ComputePanShiftPx(changed2)
require.ErrorIs(t, err, errIncrementalZoomMismatch)
}
func TestComputePanShiftPx_PanRightShiftsImageLeft(t *testing.T) {
t.Parallel()
w := NewWorld(10, 10)
params := RenderParams{
ViewportWidthPx: 100,
ViewportHeightPx: 80,
MarginXPx: 25,
MarginYPx: 20,
CameraXWorldFp: 5 * SCALE,
CameraYWorldFp: 5 * SCALE,
CameraZoom: 1.0,
}
require.NoError(t, w.CommitFullRedrawState(params))
// Move camera right by 1 world unit => world rect minX increases by 1 unit,
// so content moves left by 1px at zoom=1 => image shift should be -1.
params2 := params
params2.CameraXWorldFp += 1 * SCALE
dx, dy, err := w.ComputePanShiftPx(params2)
require.NoError(t, err)
require.Equal(t, -1, dx)
require.Equal(t, 0, dy)
}
func TestComputePanShiftPx_PanUpShiftsImageDown(t *testing.T) {
t.Parallel()
w := NewWorld(10, 10)
params := RenderParams{
ViewportWidthPx: 100,
ViewportHeightPx: 80,
MarginXPx: 25,
MarginYPx: 20,
CameraXWorldFp: 5 * SCALE,
CameraYWorldFp: 5 * SCALE,
CameraZoom: 1.0,
}
require.NoError(t, w.CommitFullRedrawState(params))
// Move camera up by 1 world unit => world rect minY decreases by 1 unit,
// so content moves down by 1px => image shift should be +1 in dy.
params2 := params
params2.CameraYWorldFp -= 1 * SCALE
dx, dy, err := w.ComputePanShiftPx(params2)
require.NoError(t, err)
require.Equal(t, 0, dx)
require.Equal(t, 1, dy)
}
func TestComputePanShiftPx_SubPixelPanAccumulatesToOnePixel(t *testing.T) {
t.Parallel()
w := NewWorld(10, 10)
params := RenderParams{
ViewportWidthPx: 100,
ViewportHeightPx: 80,
MarginXPx: 25,
MarginYPx: 20,
CameraXWorldFp: 5 * SCALE,
CameraYWorldFp: 5 * SCALE,
CameraZoom: 1.0,
}
require.NoError(t, w.CommitFullRedrawState(params))
// Pan camera right by 0.001 world units (1 fixed-point) 1000 times.
// At zoom=1 this should accumulate to a 1px content shift left, hence image shift -1.
totalDx := 0
p := params
for i := 0; i < 1000; i++ {
p.CameraXWorldFp += 1
dx, dy, err := w.ComputePanShiftPx(p)
require.NoError(t, err)
require.Equal(t, 0, dy)
totalDx += dx
}
require.Equal(t, -1, totalDx)
}