Use generated toolbar icons

This commit is contained in:
2026-06-20 02:47:48 +09:00
parent 45a563b738
commit fa40a0f2b0
27 changed files with 102 additions and 3 deletions

View File

@@ -91,6 +91,7 @@ const SCENARIO_BACKGROUNDS := [
func _init() -> void:
var failures: Array[String] = []
_check_battle_visual_data(failures)
_check_generated_toolbar_icons(failures)
_check_scene_texture_loading(failures)
_check_hud_focus_text(failures)
_check_ancient_ui_theme(failures)
@@ -2944,6 +2945,37 @@ func _check_scenario_backgrounds_data(failures: Array[String]) -> void:
_check_image_path(failures, background_path, label)
func _check_generated_toolbar_icons(failures: Array[String]) -> void:
var icon_kinds := [
"attack",
"tactic",
"item",
"wait",
"end_turn",
"threat",
"unit_list",
"save",
"load",
"settings",
"campaign",
"shop",
"talk",
"equip",
"roster",
"formation",
"status",
"objective",
"terrain",
"forecast",
"move",
"cancel",
"restart",
"new"
]
for icon_kind in icon_kinds:
_check_toolbar_icon_path(failures, "res://art/ui/icons/toolbar_%s.png" % icon_kind, "toolbar icon %s" % icon_kind)
func _check_scene_texture_loading(failures: Array[String]) -> void:
var scene = BattleSceneScript.new()
if not scene.state.load_battle("res://data/scenarios/001_yellow_turbans.json"):
@@ -3715,6 +3747,13 @@ func _has_descendant_texture(root: Node) -> bool:
return false
func _check_button_uses_generated_toolbar_icon(failures: Array[String], button: Button, context: String) -> void:
if button == null or button.icon == null:
return
if button.icon.get_width() < 128 or button.icon.get_height() < 128:
failures.append("%s should use generated high-resolution toolbar art, got %dx%d" % [context, button.icon.get_width(), button.icon.get_height()])
func _check_local_command_icon_button(failures: Array[String], button: Button, expected_label: String, expected_icon: String) -> void:
if button == null:
failures.append("local command button missing: %s" % expected_label)
@@ -3723,6 +3762,7 @@ func _check_local_command_icon_button(failures: Array[String], button: Button, e
failures.append("local command should be icon-first without visible text: %s text=%s" % [expected_label, button.text])
if button.icon == null or str(button.get_meta("command_icon", "")) != expected_icon:
failures.append("local command should carry an immediate visual icon: %s icon=%s meta=%s" % [expected_label, str(button.icon), str(button.get_meta("command_icon", ""))])
_check_button_uses_generated_toolbar_icon(failures, button, expected_label)
if str(button.get_meta("command_label", "")) != expected_label:
failures.append("local command should keep old wording in hover metadata: %s meta=%s" % [expected_label, str(button.get_meta("command_label", ""))])
if str(button.tooltip_text).strip_edges().is_empty() or not str(button.tooltip_text).contains(expected_label):
@@ -3759,6 +3799,7 @@ func _check_hud_command_grid_layout(failures: Array[String]) -> void:
failures.append("unit command button should reserve fixed icon space: %s" % str(button.custom_minimum_size))
if button.icon == null or str(button.get_meta("command_icon", "")) != str(expectation["icon"]):
failures.append("unit command button should carry an immediate visual icon: %s icon=%s meta=%s" % [button.text, str(button.icon), str(button.get_meta("command_icon", ""))])
_check_button_uses_generated_toolbar_icon(failures, button, str(expectation["icon"]))
if not bool(button.get_meta("icon_only", false)) or button.text != "":
failures.append("unit command button should be icon-first without visible text: %s text=%s" % [str(button.name), button.text])
if not scene.state.load_battle("res://data/scenarios/001_yellow_turbans.json"):
@@ -3793,6 +3834,7 @@ func _check_hud_command_grid_layout(failures: Array[String]) -> void:
failures.append("top tool button should share the top toolbar: %s" % str(button.name))
if not bool(button.get_meta("icon_only", false)) or button.text != "" or button.icon == null:
failures.append("top tool button should be icon-only with tooltip detail: %s text=%s icon=%s" % [str(button.name), button.text, str(button.icon)])
_check_button_uses_generated_toolbar_icon(failures, button, str(button.name))
if button.custom_minimum_size.x < BattleSceneScript.TOP_TOOL_BUTTON_SIZE.x or button.custom_minimum_size.y < BattleSceneScript.TOP_TOOL_BUTTON_SIZE.y:
failures.append("top tool button should reserve stable icon space: %s" % str(button.custom_minimum_size))
scene.free()
@@ -3901,6 +3943,7 @@ func _check_prep_menu_icon_button(failures: Array[String], button: Button, expec
failures.append("pre-battle prep button should be icon-first without visible text: %s text=%s" % [expected_label, button.text])
if button.icon == null or str(button.get_meta("command_icon", "")) != expected_icon:
failures.append("pre-battle prep button should carry a distinct icon: %s icon=%s meta=%s" % [expected_label, str(button.icon), str(button.get_meta("command_icon", ""))])
_check_button_uses_generated_toolbar_icon(failures, button, expected_label)
if str(button.get_meta("command_label", "")) != expected_label:
failures.append("pre-battle prep button should preserve Korean label in metadata: %s meta=%s" % [expected_label, str(button.get_meta("command_label", ""))])
if str(button.tooltip_text).strip_edges().is_empty() or not str(button.tooltip_text).contains(expected_label):
@@ -4738,6 +4781,50 @@ func _check_alpha_cutout_path(failures: Array[String], path: String, context: St
failures.append("%s should have substantial transparent background: %s (%d/%d sampled pixels)" % [context, path, transparent_samples, total_samples])
func _check_toolbar_icon_path(failures: Array[String], path: String, context: String) -> void:
if path.is_empty():
failures.append("%s has an empty icon path" % context)
return
if not path.begins_with("res://"):
failures.append("%s must use a res:// path: %s" % [context, path])
return
if not FileAccess.file_exists(path):
failures.append("%s references missing icon: %s" % [context, path])
return
var image := Image.new()
var err := image.load(path)
if err != OK:
failures.append("%s references unreadable icon: %s" % [context, path])
return
if image.get_width() < 128 or image.get_height() < 128:
failures.append("%s icon should keep high-resolution source pixels: %s (%dx%d)" % [context, path, image.get_width(), image.get_height()])
return
for corner in [Vector2i(0, 0), Vector2i(image.get_width() - 1, 0), Vector2i(0, image.get_height() - 1), Vector2i(image.get_width() - 1, image.get_height() - 1)]:
if image.get_pixelv(corner).a > 0.01:
failures.append("%s icon should have transparent corners: %s" % [context, path])
return
var opaque_samples := 0
var transparent_samples := 0
var green_fringe_samples := 0
var total_samples := 0
for y in range(0, image.get_height(), 4):
for x in range(0, image.get_width(), 4):
total_samples += 1
var pixel := image.get_pixel(x, y)
if pixel.a <= 0.01:
transparent_samples += 1
elif pixel.a >= 0.80:
opaque_samples += 1
if pixel.g > 0.88 and pixel.r < 0.20 and pixel.b < 0.20:
green_fringe_samples += 1
if transparent_samples < int(total_samples * 0.12):
failures.append("%s icon should retain transparent UI padding: %s (%d/%d sampled pixels)" % [context, path, transparent_samples, total_samples])
if opaque_samples < int(total_samples * 0.18):
failures.append("%s icon should contain substantial artwork: %s (%d/%d sampled pixels)" % [context, path, opaque_samples, total_samples])
if green_fringe_samples > 0:
failures.append("%s icon should not keep chroma-key green pixels: %s (%d sampled)" % [context, path, green_fringe_samples])
func _check_image_path(failures: Array[String], path: String, context: String) -> void:
if path.is_empty():
failures.append("%s has an empty image path" % context)