Add reusable UI components for Phase 7 UI Polish

- Introduced `EmojiQuickGrid`, `FontPresetPicker`, and `PresetSizeToggle` classes for emoji selection, font presets, and size toggles respectively.
- Implemented configuration methods for each component to handle dynamic content and theming.
- Created tests for the new components to ensure functionality and integration with the existing UI.
- Added a comprehensive architecture specification for Phase 7 UI Polish detailing scope, implementation, and validation strategies.
- Updated existing theme handling to support new UI elements and ensure consistent styling across the application.
This commit is contained in:
2026-09-18 09:42:48 -04:00
parent baa19a9341
commit 1a2a43c805
35 changed files with 1791 additions and 205 deletions
+9 -8
View File
@@ -67,6 +67,10 @@ func _initialize() -> void:
func _run() -> void:
# SandboxStage opens a recovery dialog when a prior interactive run left an
# autosave. That native child window survives briefly across this suite's
# short-lived stage fixtures and contaminates camera/navigation assertions.
DirAccess.remove_absolute("user://sandbox_autosave.scene")
print("")
print("========================================================")
print(" PHASE 4b.1 FIX REGRESSION TEST (headless)")
@@ -439,18 +443,15 @@ func _test_bug5_ghost_lifecycle() -> void:
_check(ghost.get_parent() == holder, "ghost is parented to the ghost holder, not World")
_check(world.get_children().has(ghost) == false, "ghost is not a selectable World child")
_check(is_equal_approx(ghost.modulate.a, 0.5), "ghost is translucent (alpha 0.5)")
# Block-unit snapped ghost positioning (strides, not the 16-px grid/cursor).
# Single-placement preview follows the configured snap grid; footprint stride
# remains exclusively for drag painting.
stage._snap_enabled = true
var raw_pos: Vector2 = stage._camera.get_global_mouse_position() \
+ stage._spawner.get_spawn_offset("ground")
var expected_cell: Vector2i = stage._world_to_terrain_cell(raw_pos)
var expected_pos: Vector2 = stage._terrain_cell_center(expected_cell)
var expected_pos: Vector2 = stage._snap_to_grid(raw_pos)
stage._update_ghost_position()
_check(ghost.position.distance_to(expected_pos) <= 0.01,
"ghost positioned at the block-unit cell center (got %s, expected %s)" % [ghost.position, expected_pos])
_check(is_equal_approx(fmod(absf(ghost.position.x), GROUND_STRIDE_X), 0.0),
"ghost x is a multiple of the %dpx stride (got %.1f)" % [GROUND_STRIDE_X, ghost.position.x])
_check(is_equal_approx(fmod(absf(ghost.position.y), GROUND_STRIDE_Y), 0.0),
"ghost y is a multiple of the 32px stride (got %.1f)" % ghost.position.y)
"ghost positioned at the configured snap-grid point (got %s, expected %s)" % [ghost.position, expected_pos])
# Drag begin frees the single cursor ghost and builds per-cell ghosts.
stage._begin_terrain_drag(stage._terrain_cell_center(Vector2i(30, 0)))