Add hover hints for icon commands
This commit is contained in:
@@ -186,6 +186,10 @@ const HUD_COMMAND_GRID_SIZE := Vector2(420, 46)
|
|||||||
const HUD_COMMAND_BUTTON_SIZE := Vector2(72, 42)
|
const HUD_COMMAND_BUTTON_SIZE := Vector2(72, 42)
|
||||||
const HUD_COMMAND_GRID_COLUMNS := 4
|
const HUD_COMMAND_GRID_COLUMNS := 4
|
||||||
const TOP_TOOL_BUTTON_SIZE := Vector2(46, 46)
|
const TOP_TOOL_BUTTON_SIZE := Vector2(46, 46)
|
||||||
|
const COMMAND_HINT_PANEL_SIZE := Vector2(246, 78)
|
||||||
|
const COMMAND_HINT_ICON_SIZE := Vector2(30, 30)
|
||||||
|
const COMMAND_HINT_TITLE_SIZE := Vector2(184, 22)
|
||||||
|
const COMMAND_HINT_DETAIL_SIZE := Vector2(208, 32)
|
||||||
const PREP_MENU_BUTTON_SIZE := Vector2(48, 38)
|
const PREP_MENU_BUTTON_SIZE := Vector2(48, 38)
|
||||||
const BATTLE_UNIT_LIST_PANEL_SIZE := Vector2(420, 360)
|
const BATTLE_UNIT_LIST_PANEL_SIZE := Vector2(420, 360)
|
||||||
const BATTLE_UNIT_LIST_ROW_SIZE := Vector2(372, 58)
|
const BATTLE_UNIT_LIST_ROW_SIZE := Vector2(372, 58)
|
||||||
@@ -541,6 +545,11 @@ var targeting_hint_title_label: Label
|
|||||||
var targeting_hint_detail_label: Label
|
var targeting_hint_detail_label: Label
|
||||||
var targeting_hint_back_button: Button
|
var targeting_hint_back_button: Button
|
||||||
var targeting_hint_cancel_move_button: Button
|
var targeting_hint_cancel_move_button: Button
|
||||||
|
var command_hint_panel: PanelContainer
|
||||||
|
var command_hint_icon: TextureRect
|
||||||
|
var command_hint_title_label: Label
|
||||||
|
var command_hint_detail_label: Label
|
||||||
|
var command_hint_source_button: Button
|
||||||
var threat_button: Button
|
var threat_button: Button
|
||||||
var battle_unit_list_button: Button
|
var battle_unit_list_button: Button
|
||||||
var battle_unit_list_panel: PanelContainer
|
var battle_unit_list_panel: PanelContainer
|
||||||
@@ -1150,6 +1159,7 @@ func _configure_hud_command_button(button: Button, icon_kind: String = "") -> vo
|
|||||||
button.expand_icon = true
|
button.expand_icon = true
|
||||||
button.set_meta("icon_only", true)
|
button.set_meta("icon_only", true)
|
||||||
button.set_meta("command_icon", icon_kind)
|
button.set_meta("command_icon", icon_kind)
|
||||||
|
_connect_command_hint_button(button)
|
||||||
|
|
||||||
|
|
||||||
func _configure_top_tool_button(button: Button, node_name: String, icon_kind: String, tooltip: String) -> void:
|
func _configure_top_tool_button(button: Button, node_name: String, icon_kind: String, tooltip: String) -> void:
|
||||||
@@ -1164,7 +1174,9 @@ func _configure_top_tool_button(button: Button, node_name: String, icon_kind: St
|
|||||||
button.icon = _make_toolbar_icon(icon_kind)
|
button.icon = _make_toolbar_icon(icon_kind)
|
||||||
button.expand_icon = true
|
button.expand_icon = true
|
||||||
button.set_meta("icon_only", true)
|
button.set_meta("icon_only", true)
|
||||||
|
button.set_meta("command_icon", icon_kind)
|
||||||
button.add_theme_font_size_override("font_size", 1)
|
button.add_theme_font_size_override("font_size", 1)
|
||||||
|
_connect_command_hint_button(button)
|
||||||
|
|
||||||
|
|
||||||
func _configure_title_menu_button(button: Button, node_name: String, icon_kind: String, label: String, tooltip: String, minimum_size: Vector2, important: bool = false) -> void:
|
func _configure_title_menu_button(button: Button, node_name: String, icon_kind: String, label: String, tooltip: String, minimum_size: Vector2, important: bool = false) -> void:
|
||||||
@@ -1508,6 +1520,153 @@ func _format_local_command_tooltip(label: String, hint: String) -> String:
|
|||||||
return "%s\n%s" % [normalized_label, normalized_hint]
|
return "%s\n%s" % [normalized_label, normalized_hint]
|
||||||
|
|
||||||
|
|
||||||
|
func _connect_command_hint_button(button: Button) -> void:
|
||||||
|
if button == null or bool(button.get_meta("command_hint_connected", false)):
|
||||||
|
return
|
||||||
|
button.mouse_entered.connect(_on_command_hint_button_mouse_entered.bind(button))
|
||||||
|
button.mouse_exited.connect(_on_command_hint_button_mouse_exited)
|
||||||
|
button.set_meta("command_hint_connected", true)
|
||||||
|
|
||||||
|
|
||||||
|
func _create_command_hint_panel(root: Control) -> void:
|
||||||
|
if root == null:
|
||||||
|
return
|
||||||
|
command_hint_panel = PanelContainer.new()
|
||||||
|
command_hint_panel.name = "CommandHintPanel"
|
||||||
|
command_hint_panel.visible = false
|
||||||
|
command_hint_panel.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
command_hint_panel.custom_minimum_size = COMMAND_HINT_PANEL_SIZE
|
||||||
|
command_hint_panel.size = COMMAND_HINT_PANEL_SIZE
|
||||||
|
_apply_panel_style(command_hint_panel, "target_hint")
|
||||||
|
root.add_child(command_hint_panel)
|
||||||
|
|
||||||
|
var row := HBoxContainer.new()
|
||||||
|
row.name = "CommandHintRow"
|
||||||
|
row.custom_minimum_size = Vector2(COMMAND_HINT_PANEL_SIZE.x - 22.0, COMMAND_HINT_PANEL_SIZE.y - 18.0)
|
||||||
|
row.add_theme_constant_override("separation", 8)
|
||||||
|
command_hint_panel.add_child(row)
|
||||||
|
|
||||||
|
command_hint_icon = TextureRect.new()
|
||||||
|
command_hint_icon.name = "CommandHintIcon"
|
||||||
|
command_hint_icon.custom_minimum_size = COMMAND_HINT_ICON_SIZE
|
||||||
|
command_hint_icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||||
|
command_hint_icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||||
|
row.add_child(command_hint_icon)
|
||||||
|
|
||||||
|
var text_column := VBoxContainer.new()
|
||||||
|
text_column.name = "CommandHintText"
|
||||||
|
text_column.add_theme_constant_override("separation", 2)
|
||||||
|
row.add_child(text_column)
|
||||||
|
|
||||||
|
command_hint_title_label = Label.new()
|
||||||
|
command_hint_title_label.name = "CommandHintTitle"
|
||||||
|
command_hint_title_label.custom_minimum_size = COMMAND_HINT_TITLE_SIZE
|
||||||
|
command_hint_title_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_LEFT
|
||||||
|
_apply_label_style(command_hint_title_label, UI_OLD_BRONZE, LOCAL_COMMAND_TITLE_FONT_SIZE)
|
||||||
|
text_column.add_child(command_hint_title_label)
|
||||||
|
|
||||||
|
command_hint_detail_label = Label.new()
|
||||||
|
command_hint_detail_label.name = "CommandHintDetail"
|
||||||
|
command_hint_detail_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||||
|
command_hint_detail_label.custom_minimum_size = COMMAND_HINT_DETAIL_SIZE
|
||||||
|
_apply_label_style(command_hint_detail_label, UI_PARCHMENT_TEXT, LOCAL_COMMAND_DETAIL_FONT_SIZE)
|
||||||
|
text_column.add_child(command_hint_detail_label)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_command_hint_button_mouse_entered(button: Button) -> void:
|
||||||
|
_show_command_hint_for_button(button)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_command_hint_button_mouse_exited() -> void:
|
||||||
|
_hide_command_hint()
|
||||||
|
|
||||||
|
|
||||||
|
func _show_command_hint_for_button(button: Button) -> void:
|
||||||
|
if command_hint_panel == null or button == null or not is_instance_valid(button):
|
||||||
|
return
|
||||||
|
var label := _command_hint_button_label(button)
|
||||||
|
var detail := _command_hint_button_detail(button)
|
||||||
|
if label.is_empty() and detail.is_empty():
|
||||||
|
_hide_command_hint()
|
||||||
|
return
|
||||||
|
var tooltip := _format_local_command_tooltip(label, detail)
|
||||||
|
command_hint_source_button = button
|
||||||
|
command_hint_panel.visible = true
|
||||||
|
command_hint_panel.tooltip_text = tooltip
|
||||||
|
command_hint_panel.position = _command_hint_panel_position(button)
|
||||||
|
command_hint_panel.move_to_front()
|
||||||
|
if command_hint_title_label != null:
|
||||||
|
_set_fitted_label_text(command_hint_title_label, label, LOCAL_COMMAND_TITLE_FONT_SIZE, LOCAL_COMMAND_TITLE_MIN_FONT_SIZE, COMMAND_HINT_TITLE_SIZE)
|
||||||
|
command_hint_title_label.tooltip_text = tooltip
|
||||||
|
if command_hint_detail_label != null:
|
||||||
|
_set_fitted_label_text(command_hint_detail_label, detail, LOCAL_COMMAND_DETAIL_FONT_SIZE, LOCAL_COMMAND_DETAIL_MIN_FONT_SIZE, COMMAND_HINT_DETAIL_SIZE)
|
||||||
|
command_hint_detail_label.tooltip_text = tooltip
|
||||||
|
if command_hint_icon != null:
|
||||||
|
command_hint_icon.texture = _make_toolbar_icon(str(button.get_meta("command_icon", "status")))
|
||||||
|
command_hint_icon.tooltip_text = tooltip
|
||||||
|
_set_control_tree_tooltip(command_hint_panel, tooltip)
|
||||||
|
|
||||||
|
|
||||||
|
func _hide_command_hint() -> void:
|
||||||
|
command_hint_source_button = null
|
||||||
|
if command_hint_panel != null:
|
||||||
|
command_hint_panel.visible = false
|
||||||
|
|
||||||
|
|
||||||
|
func _refresh_command_hint_if_source(button: Button) -> void:
|
||||||
|
if command_hint_panel == null or not command_hint_panel.visible:
|
||||||
|
return
|
||||||
|
if command_hint_source_button == button:
|
||||||
|
_show_command_hint_for_button(button)
|
||||||
|
|
||||||
|
|
||||||
|
func _command_hint_button_label(button: Button) -> String:
|
||||||
|
var label := str(button.get_meta("command_label", "")).strip_edges()
|
||||||
|
if not label.is_empty():
|
||||||
|
return label
|
||||||
|
var tooltip_lines := str(button.tooltip_text).split("\n", false)
|
||||||
|
if not tooltip_lines.is_empty():
|
||||||
|
return str(tooltip_lines[0]).strip_edges()
|
||||||
|
return str(button.text).strip_edges()
|
||||||
|
|
||||||
|
|
||||||
|
func _command_hint_button_detail(button: Button) -> String:
|
||||||
|
if bool(button.disabled):
|
||||||
|
var disabled_hint := str(button.get_meta("disabled_hint", "")).strip_edges()
|
||||||
|
var command_hint := str(button.get_meta("command_hint", "")).strip_edges()
|
||||||
|
if not command_hint.is_empty():
|
||||||
|
return command_hint
|
||||||
|
if not disabled_hint.is_empty():
|
||||||
|
return disabled_hint
|
||||||
|
var hint := str(button.get_meta("command_hint", "")).strip_edges()
|
||||||
|
if not hint.is_empty():
|
||||||
|
return hint
|
||||||
|
var tooltip_lines := str(button.tooltip_text).split("\n", false)
|
||||||
|
if tooltip_lines.size() > 1:
|
||||||
|
var detail_lines: Array[String] = []
|
||||||
|
for index in range(1, tooltip_lines.size()):
|
||||||
|
detail_lines.append(str(tooltip_lines[index]).strip_edges())
|
||||||
|
return _join_strings(detail_lines, "\n")
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
func _command_hint_panel_position(button: Button) -> Vector2:
|
||||||
|
var button_rect := button.get_global_rect()
|
||||||
|
var viewport_size := _viewport_size_for_layout()
|
||||||
|
var panel_size := COMMAND_HINT_PANEL_SIZE
|
||||||
|
var gap := 8.0
|
||||||
|
var x := button_rect.position.x
|
||||||
|
if button_rect.get_center().x > viewport_size.x * 0.5:
|
||||||
|
x = button_rect.end.x - panel_size.x
|
||||||
|
var y := button_rect.end.y + gap
|
||||||
|
if y + panel_size.y > viewport_size.y - 10.0:
|
||||||
|
y = button_rect.position.y - panel_size.y - gap
|
||||||
|
return Vector2(
|
||||||
|
clampf(x, 10.0, maxf(10.0, viewport_size.x - panel_size.x - 10.0)),
|
||||||
|
clampf(y, 10.0, maxf(10.0, viewport_size.y - panel_size.y - 10.0))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
func _make_top_hud_chip(node_name: String, icon_kind: String, chip_size: Vector2, variant: String) -> Dictionary:
|
func _make_top_hud_chip(node_name: String, icon_kind: String, chip_size: Vector2, variant: String) -> Dictionary:
|
||||||
var chip := PanelContainer.new()
|
var chip := PanelContainer.new()
|
||||||
chip.name = node_name
|
chip.name = node_name
|
||||||
@@ -3361,6 +3520,8 @@ func _create_hud() -> void:
|
|||||||
log_box.add_theme_stylebox_override("normal", _make_panel_style(Color(0.11, 0.07, 0.045, 0.78), UI_RICE_PAPER_DARK, 1, 6, 6, 0))
|
log_box.add_theme_stylebox_override("normal", _make_panel_style(Color(0.11, 0.07, 0.045, 0.78), UI_RICE_PAPER_DARK, 1, 6, 6, 0))
|
||||||
side_column.add_child(log_box)
|
side_column.add_child(log_box)
|
||||||
|
|
||||||
|
_create_command_hint_panel(root)
|
||||||
|
|
||||||
screen_backdrop = _make_screen_backdrop()
|
screen_backdrop = _make_screen_backdrop()
|
||||||
root.add_child(screen_backdrop)
|
root.add_child(screen_backdrop)
|
||||||
|
|
||||||
@@ -16041,6 +16202,7 @@ func _set_action_button_state(button: Button, label: String, disabled: bool, too
|
|||||||
button.text = normalized_label
|
button.text = normalized_label
|
||||||
button.tooltip_text = normalized_tooltip
|
button.tooltip_text = normalized_tooltip
|
||||||
button.disabled = disabled
|
button.disabled = disabled
|
||||||
|
_refresh_command_hint_if_source(button)
|
||||||
|
|
||||||
|
|
||||||
func _set_action_button_blocked(button: Button, base_label: String, reason_label: String, tooltip: String) -> void:
|
func _set_action_button_blocked(button: Button, base_label: String, reason_label: String, tooltip: String) -> void:
|
||||||
@@ -16051,6 +16213,7 @@ func _set_action_button_blocked(button: Button, base_label: String, reason_label
|
|||||||
_set_action_button_state(button, base_label, true, blocked_tooltip)
|
_set_action_button_state(button, base_label, true, blocked_tooltip)
|
||||||
if button != null:
|
if button != null:
|
||||||
button.set_meta("disabled_hint", reason)
|
button.set_meta("disabled_hint", reason)
|
||||||
|
_refresh_command_hint_if_source(button)
|
||||||
|
|
||||||
|
|
||||||
func _action_phase_block_reason() -> Dictionary:
|
func _action_phase_block_reason() -> Dictionary:
|
||||||
|
|||||||
@@ -4205,6 +4205,19 @@ func _check_hud_command_grid_layout(failures: Array[String]) -> void:
|
|||||||
continue
|
continue
|
||||||
if button.tooltip_text.strip_edges().is_empty():
|
if button.tooltip_text.strip_edges().is_empty():
|
||||||
failures.append("unit command icon should expose its command through tooltip: %s" % str(button.name))
|
failures.append("unit command icon should expose its command through tooltip: %s" % str(button.name))
|
||||||
|
scene._on_command_hint_button_mouse_entered(scene.wait_button)
|
||||||
|
if scene.command_hint_panel == null or not scene.command_hint_panel.visible:
|
||||||
|
failures.append("hovering a unit command icon should show the command hint panel")
|
||||||
|
else:
|
||||||
|
if scene.command_hint_title_label == null or scene.command_hint_title_label.text != "대기":
|
||||||
|
failures.append("unit command hint should show command title: %s" % ("" if scene.command_hint_title_label == null else scene.command_hint_title_label.text))
|
||||||
|
if scene.command_hint_detail_label == null or not scene.command_hint_detail_label.text.contains("부대 미지정"):
|
||||||
|
failures.append("disabled unit command hint should show the blocked reason: %s" % ("" if scene.command_hint_detail_label == null else scene.command_hint_detail_label.text))
|
||||||
|
if scene.command_hint_icon == null or scene.command_hint_icon.texture == null:
|
||||||
|
failures.append("unit command hint should show generated command icon artwork")
|
||||||
|
scene._on_command_hint_button_mouse_exited()
|
||||||
|
if scene.command_hint_panel != null and scene.command_hint_panel.visible:
|
||||||
|
failures.append("unit command hint panel should hide when leaving the icon")
|
||||||
var top_toolbar := scene.end_turn_button.get_parent() as HBoxContainer
|
var top_toolbar := scene.end_turn_button.get_parent() as HBoxContainer
|
||||||
if top_toolbar == null or top_toolbar.name != "TopToolBar":
|
if top_toolbar == null or top_toolbar.name != "TopToolBar":
|
||||||
failures.append("global battle commands should move to the top icon toolbar")
|
failures.append("global battle commands should move to the top icon toolbar")
|
||||||
@@ -4228,6 +4241,16 @@ func _check_hud_command_grid_layout(failures: Array[String]) -> void:
|
|||||||
_check_button_uses_generated_surface(failures, button, str(button.name))
|
_check_button_uses_generated_surface(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:
|
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))
|
failures.append("top tool button should reserve stable icon space: %s" % str(button.custom_minimum_size))
|
||||||
|
scene._on_command_hint_button_mouse_entered(scene.end_turn_button)
|
||||||
|
if scene.command_hint_panel == null or not scene.command_hint_panel.visible:
|
||||||
|
failures.append("hovering a top command icon should show the command hint panel")
|
||||||
|
else:
|
||||||
|
if scene.command_hint_title_label == null or scene.command_hint_title_label.text != "차례 종료":
|
||||||
|
failures.append("top command hint should show command title: %s" % ("" if scene.command_hint_title_label == null else scene.command_hint_title_label.text))
|
||||||
|
if scene.command_hint_detail_label == null or not scene.command_hint_detail_label.text.contains("적군"):
|
||||||
|
failures.append("top command hint should keep command detail: %s" % ("" if scene.command_hint_detail_label == null else scene.command_hint_detail_label.text))
|
||||||
|
if scene.command_hint_icon == null or scene.command_hint_icon.texture == null or str(scene.end_turn_button.get_meta("command_icon", "")) != "end_turn":
|
||||||
|
failures.append("top command hint should use generated top command icon artwork")
|
||||||
scene.free()
|
scene.free()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user