forked from joey/godottest
216 lines
6.1 KiB
GDScript
216 lines
6.1 KiB
GDScript
@tool
|
||
class_name BeehaveDebuggerTab
|
||
extends PanelContainer
|
||
|
||
const Utils = preload("res://addons/beehave/utils/utils.gd")
|
||
const TREE_ICON = preload("../icons/tree.svg")
|
||
const OldGraph = preload("old_graph_edit.gd")
|
||
const NewGraph = preload("new_graph_edit.gd")
|
||
const Blackboard = preload("new_node_blackboard.gd")
|
||
|
||
signal make_floating
|
||
|
||
var session: EditorDebuggerSession
|
||
var first_run = true
|
||
var active_trees = {}
|
||
var active_tree_id = -1
|
||
|
||
# UI nodes
|
||
var container: HSplitContainer
|
||
var item_list: ItemList
|
||
var graph_container: HSplitContainer
|
||
var graph
|
||
var blackboard_vbox: VBoxContainer
|
||
var message: Label
|
||
|
||
func _ready() -> void:
|
||
_build_ui()
|
||
_init_graph()
|
||
stop()
|
||
|
||
visibility_changed.connect(_on_visibility_changed)
|
||
if visible and is_visible_in_tree():
|
||
get_tree().create_timer(0.5).timeout.connect(_on_visibility_changed)
|
||
|
||
|
||
func _build_ui() -> void:
|
||
# Main split fills entire panel
|
||
container = HSplitContainer.new()
|
||
container.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||
add_child(container)
|
||
|
||
# Left: behavior‐tree list
|
||
item_list = ItemList.new()
|
||
item_list.custom_minimum_size = Vector2(300, 0)
|
||
item_list.item_selected.connect(_on_item_selected)
|
||
container.add_child(item_list)
|
||
|
||
# Right: graph + (optional) blackboard
|
||
graph_container = HSplitContainer.new()
|
||
graph_container.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||
container.add_child(graph_container)
|
||
|
||
# Blackboard pane: narrow, hidden until needed
|
||
blackboard_vbox = VBoxContainer.new()
|
||
blackboard_vbox.custom_minimum_size = Vector2(500, 0)
|
||
blackboard_vbox.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||
blackboard_vbox.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||
blackboard_vbox.hide()
|
||
graph_container.add_child(blackboard_vbox)
|
||
|
||
# "Run Project for debugging" overlay
|
||
message = Label.new()
|
||
message.text = "Run Project for debugging"
|
||
message.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||
message.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||
message.set_anchors_preset(Control.PRESET_CENTER)
|
||
add_child(message)
|
||
|
||
|
||
func _init_graph() -> void:
|
||
var frames = Utils.get_frames()
|
||
if Engine.get_version_info().minor >= 2:
|
||
graph = NewGraph.new(frames)
|
||
else:
|
||
graph = OldGraph.new(frames)
|
||
|
||
# Graph on the left, blackboard (index 1) on the right
|
||
graph.node_selected.connect(_on_graph_node_selected)
|
||
graph.node_deselected.connect(_on_graph_node_deselected)
|
||
graph.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||
graph_container.add_child(graph)
|
||
graph_container.move_child(graph, 0)
|
||
|
||
# "Make Floating" button
|
||
var float_btn = Button.new()
|
||
float_btn.name = "MakeFloatingButton"
|
||
float_btn.flat = true
|
||
float_btn.focus_mode = Control.FOCUS_NONE
|
||
float_btn.icon = get_theme_icon("ExternalLink", "EditorIcons")
|
||
float_btn.pressed.connect(func():
|
||
emit_signal("make_floating")
|
||
)
|
||
graph.get_menu_container().add_child(float_btn)
|
||
|
||
# "Toggle Panel" button
|
||
var toggle_btn = Button.new()
|
||
toggle_btn.name = "TogglePanelButton"
|
||
toggle_btn.flat = true
|
||
toggle_btn.focus_mode = Control.FOCUS_NONE
|
||
toggle_btn.icon = get_theme_icon("Back", "EditorIcons")
|
||
toggle_btn.pressed.connect(func():
|
||
item_list.visible = not item_list.visible
|
||
var icon_name = "Back" if item_list.visible else "Forward"
|
||
toggle_btn.icon = get_theme_icon(icon_name, "EditorIcons")
|
||
)
|
||
graph.get_menu_container().add_child(toggle_btn)
|
||
graph.get_menu_container().move_child(toggle_btn, 0)
|
||
|
||
|
||
func start() -> void:
|
||
container.visible = true
|
||
message.visible = false
|
||
|
||
if first_run:
|
||
first_run = false
|
||
for delay in [0.0, 0.1, 0.5]:
|
||
get_tree().create_timer(delay).timeout.connect(_notify_state)
|
||
else:
|
||
_notify_state()
|
||
|
||
# Auto-detach if enabled in project settings - check every time
|
||
if ProjectSettings.get_setting("beehave/debugger/start_detached", false):
|
||
emit_signal("make_floating")
|
||
|
||
|
||
func _notify_state() -> void:
|
||
if not session or not visible or not is_visible_in_tree():
|
||
return
|
||
session.send_message("beehave:visibility_changed", [true])
|
||
if active_tree_id != -1:
|
||
session.send_message("beehave:activate_tree", [active_tree_id])
|
||
|
||
|
||
func stop() -> void:
|
||
container.visible = false
|
||
message.visible = true
|
||
active_trees.clear()
|
||
item_list.clear()
|
||
graph.beehave_tree = {}
|
||
blackboard_vbox.hide()
|
||
|
||
|
||
func register_tree(data: Dictionary) -> void:
|
||
var id_str = str(data.id)
|
||
if not active_trees.has(id_str):
|
||
var idx = item_list.add_item(data.name, TREE_ICON)
|
||
item_list.set_item_tooltip(idx, data.path)
|
||
item_list.set_item_metadata(idx, data.id)
|
||
active_trees[id_str] = data
|
||
|
||
if data.id.to_int() == active_tree_id:
|
||
_notify_state()
|
||
|
||
if item_list.get_selected_items().is_empty():
|
||
_select_item_by_id(id_str)
|
||
|
||
|
||
func unregister_tree(instance_id: int) -> void:
|
||
var id_str = str(instance_id)
|
||
for i in range(item_list.get_item_count()):
|
||
if item_list.get_item_metadata(i) == id_str:
|
||
item_list.remove_item(i)
|
||
break
|
||
active_trees.erase(id_str)
|
||
if graph.beehave_tree.get("id", "") == id_str:
|
||
graph.beehave_tree = {}
|
||
blackboard_vbox.hide()
|
||
|
||
|
||
func _select_item_by_id(id_str: String) -> void:
|
||
for i in range(item_list.get_item_count()):
|
||
if item_list.get_item_metadata(i) == id_str:
|
||
item_list.select(i)
|
||
break
|
||
get_tree().create_timer(0.2).timeout.connect(func():
|
||
if item_list.is_inside_tree() and not item_list.get_selected_items().is_empty():
|
||
_on_item_selected(item_list.get_selected_items()[0])
|
||
)
|
||
|
||
|
||
func _on_item_selected(idx: int) -> void:
|
||
if idx < 0 or idx >= item_list.get_item_count():
|
||
return
|
||
|
||
# Immediately hide & clear the blackboard when switching trees
|
||
blackboard_vbox.hide()
|
||
for child in blackboard_vbox.get_children():
|
||
child.free()
|
||
|
||
var id = item_list.get_item_metadata(idx)
|
||
var tree_data = active_trees.get(str(id), {})
|
||
if tree_data.is_empty():
|
||
return
|
||
|
||
graph.beehave_tree = tree_data
|
||
active_tree_id = id.to_int()
|
||
_notify_state()
|
||
get_tree().create_timer(0.1).timeout.connect(_notify_state)
|
||
|
||
|
||
func _on_graph_node_selected(node: GraphNode) -> void:
|
||
blackboard_vbox.show()
|
||
blackboard_vbox.add_child(Blackboard.new(Utils.get_frames(), node))
|
||
|
||
|
||
func _on_graph_node_deselected(node: GraphNode) -> void:
|
||
for child in blackboard_vbox.get_children():
|
||
if child.name == node.name:
|
||
child.free()
|
||
if blackboard_vbox.get_child_count() == 0:
|
||
blackboard_vbox.hide()
|
||
|
||
|
||
func _on_visibility_changed() -> void:
|
||
_notify_state()
|