fix(ui): overlay bar empty flow area must not eat map input (PR #186 review)

Hoshe's finding: the wrap fix gave the bar container the full
header-adjacent width, and with ALIGNMENT_END + the pre-existing
MOUSE_FILTER_STOP that left a ~700px dead strip (1920px screens) left
of the chips silently swallowing map clicks/drags near the top edge —
a regression the wrap change introduced by widening the rect without
revisiting the filter. Two edits: the container is now
MOUSE_FILTER_IGNORE (the legend-panel/header/empty-notice idiom; chip
Buttons STOP their own events so toggles and tooltips are unaffected),
and _is_over_ui() no longer checks the bar rect (with IGNORE, chip
events never reach the viewer — checking the wide rect would recreate
the dead strip). Regression test pins both: filter mode + an
empty-strip point not registering as UI.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-21 09:26:02 +02:00
co-authored by Claude Fable 5
parent 69123904a5
commit 872aea041f
3 changed files with 43 additions and 3 deletions
+29
View File
@@ -510,3 +510,32 @@ func test_legend_panel_shows_active_overlay_and_hides_when_toggled_off() -> void
).is_false()
v.queue_free()
## PR #186 regression: the overlay bar spans the full header-adjacent width
## so rows can wrap (ALIGNMENT_END right-aligns the chips), which leaves a
## wide EMPTY strip inside the container rect on wide screens. That strip
## must never eat map input: the container is MOUSE_FILTER_IGNORE (chip
## Buttons STOP their own events) and _is_over_ui() must not treat the bar
## rect as UI — both are pinned here because no other test exercises them.
func test_overlay_bar_empty_area_does_not_block_map_input() -> void:
var v: AtlasViewer = AtlasViewer.new()
add_child(v)
v.size = Vector2(1920.0, 1080.0)
v._position_overlay_bar()
await get_tree().process_frame
assert_int(v._overlay_bar.mouse_filter).override_failure_message(
"overlay bar container must be MOUSE_FILTER_IGNORE — STOP turns the"
+ " empty flow area into a dead strip that swallows map clicks"
).is_equal(Control.MOUSE_FILTER_IGNORE)
# A point just inside the bar's top-left is empty flow area (chips are
# right-aligned and occupy well under the full width at 1920px).
var strip_point: Vector2 = v._overlay_bar.global_position + Vector2(8.0, 8.0)
assert_bool(v._is_over_ui(strip_point)).override_failure_message(
"_is_over_ui must not claim the overlay bar's empty strip — map"
+ " pan/click near the top edge would silently die there"
).is_false()
v.queue_free()
@@ -34,7 +34,14 @@ func _init(viewer_ref = null) -> void:
func _ready() -> void:
mouse_filter = Control.MOUSE_FILTER_STOP
# IGNORE, not STOP (PR #186 review): the container spans the full
# header-adjacent width so rows can wrap, and with ALIGNMENT_END most of
# that rect is empty space left of the chips — STOP made it a dead strip
# that swallowed map clicks/drags near the top edge. The chip Buttons
# STOP their own input (Godot Button default), so toggling and tooltips
# are unaffected; empty flow area passes through to the map. Same idiom
# as the legend panel / screen header / empty notice.
mouse_filter = Control.MOUSE_FILTER_IGNORE
if _viewer == null:
return
for def: Dictionary in _viewer.get_overlay_defs():
+6 -2
View File
@@ -707,8 +707,12 @@ static func _dict_str(d: Dictionary, key: String, fallback: String) -> String:
func _is_over_ui(pos: Vector2) -> bool:
if _overlay_bar and _overlay_bar.get_global_rect().has_point(pos):
return true
# The overlay bar is deliberately NOT checked here (PR #186 review): its
# container spans the full header-adjacent width for row wrapping but is
# MOUSE_FILTER_IGNORE — chip Buttons STOP their own events (they never
# reach this viewer), and the empty flow area left of the right-aligned
# chips must stay interactive map surface. Checking the wide bar rect
# would re-create the ~700px dead strip the review caught.
if _city_panel and _city_panel.visible and _city_panel.get_global_rect().has_point(pos):
return true
return false