D5/UI/ui_base.gd

155 lines
6.3 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ui_base.gd
class_name UIPage
extends Control
# --- Signals ---
signal navigate_requested(target_page_node: Control)
signal workflow_end_requested(is_confirm_and_trigger_action: bool)
# --- Exported Variables for Inspector ---
## The page to navigate to when a "next" or "confirm" action is triggered.
@export var next_ui_node_path: NodePath
## The page to navigate to when a "back" or "cancel" action is triggered.
@export var back_ui_node_path: NodePath
## For sub-pages, this is their direct parent page (e.g., A is parent of A_1).
## Used if back_ui_node_path is not set for a sub-page, to return to its parent.
@export var parent_page_node_path: NodePath
## If true (default), this page will be hidden when go_next() is called and
## a next_ui_node_path is successfully navigated to.
## If false, this page will remain visible.
@export var hide_on_next: bool = true
# --- Internal Variables ---
var main_controller # Will hold reference to Main.gd
func _ready():
# Attempt to find the Main controller. Assumes Main is the owner or a known path.
if owner and owner.has_method("get_shared_data"): # Simple check if owner is Main
main_controller = owner
# --- Godot Input Handling ---
func _input(event):
# Only process input if the page is currently visible and the feature is enabled
if not visible:
return
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_RIGHT and event.is_pressed():
print("UIPage '", name, "' detected right-click. Attempting to go back.")
go_back()
get_viewport().set_input_as_handled() # Consume the event so other nodes don't process it
# --- Public Methods ---
func show_page():
# 仅当页面之前是不可见状态时,才设置 visible = true。
# 或者更简单地,总是设置 visible = true因为重复设置 true 没有副作用。
if not visible:
visible = true
func hide_page():
# Only call _on_page_deactivated if the page was previously visible.
if visible:
_on_page_deactivated() # Call the overridable method before hiding
visible = false
# else:
# print("UIPage " + name + " already hidden. Not re-deactivating.")
func _on_page_activated():
# Base implementation can be empty or log
print("UIPage activated: " + name)
pass
func _on_page_deactivated():
# Base implementation can be empty or log
print("UIPage deactivated: " + name)
pass
# --- Navigation Methods (to be called by buttons on this page) ---
func go_next():
if not next_ui_node_path.is_empty():
var target_node = get_node_or_null(next_ui_node_path)
if target_node and target_node is Control: # Ensure target_node is a Control, ideally a UIPage
emit_signal("navigate_requested", target_node)
else:
printerr("Next UI node not found or not a Control: ", next_ui_node_path, " from page ", name)
emit_signal("workflow_end_requested", true) # Or some error state
else:
# next_ui_node is null, meaning workflow ends with confirmation
emit_signal("workflow_end_requested", true)
func go_back():
var target_path_to_try = back_ui_node_path
if target_path_to_try.is_empty() and not parent_page_node_path.is_empty():
target_path_to_try = parent_page_node_path
if not target_path_to_try.is_empty():
var target_node = get_node_or_null(target_path_to_try)
if target_node and target_node is Control: # Ensure target_node is a Control, ideally a UIPage
emit_signal("navigate_requested", target_node)
else:
printerr("Back/Parent UI node not found or not a Control: ", target_path_to_try, " from page ", name)
emit_signal("workflow_end_requested", false) # Or some error state
else:
emit_signal("workflow_end_requested", false)
# --- Data Access Methods (Examples) ---
func get_main_data(key: String, default = null):
if main_controller:
return main_controller.get_shared_data(key, default)
else: # <--- 修改点: 将警告移入 else 分支
push_warning("Cannot get_main_data, Main controller not found from page '", name, "'")
return default
func set_main_data(key: String, value):
if main_controller:
main_controller.set_shared_data(key, value)
else: # <--- 修改点: 将警告移入 else 分支
push_warning("Cannot set_main_data, Main controller not found from page '", name, "'. Data not set.")
# --- Helper function to check if potential_ancestor is an ancestor of node_to_check ---
func _is_ancestor_of(potential_ancestor: Node, node_to_check: Node) -> bool:
if not potential_ancestor or not node_to_check:
return false
# Ensure both nodes are in the scene tree to safely use get_parent()
if not node_to_check.is_inside_tree() or not potential_ancestor.is_inside_tree():
return false
var current_parent = node_to_check.get_parent()
while current_parent:
if current_parent == potential_ancestor:
return true
current_parent = current_parent.get_parent() # Move up the tree
return false
# --- Helper for navigating to a specific child page (MODIFIED) ---
func go_to_child_page(child_page_node: Control):
# Check if a child_page_node was provided
if not child_page_node:
printerr("Error in '", name, ".go_to_child_page': Target child_page_node is null.")
return
# This check prevents navigating to an ancestor using this function.
# If child_page_node is an ancestor of self, it's considered an invalid target for "go_to_child_page".
# Original problematic line: if child_page_node and child_page_node.is_a_parent_of(self):
if _is_ancestor_of(child_page_node, self):
printerr("Error in '", name, ".go_to_child_page': Navigation target '", child_page_node.name,
"' cannot be an ancestor of the current page '", self.name,
"'. 'go_to_child_page' is intended for pages that are descendants or unrelated in the scene tree hierarchy.")
return
# Optional: If 'go_to_child_page' strictly means a *direct child* in the scene tree,
# you might want to add a check like this:
# if child_page_node.get_parent() != self:
# printerr("Error in '", name, ".go_to_child_page': Target '", child_page_node.name,
# "' is not a direct child of this page '", self.name, "'.")
# return
# Ensure child_page_node is a Control (already type-hinted, but good for safety)
if child_page_node is Control:
emit_signal("navigate_requested", child_page_node)
#self._on_page_deactivated()
else:
# This case might occur if something other than a Control node is passed,
# despite the type hint.
printerr("Error in '", name, ".go_to_child_page': Invalid target '", child_page_node,
"'. It is not a Control node.")