generated from mstar/godot-template
158 lines
4.5 KiB
GDScript3
158 lines
4.5 KiB
GDScript3
|
@tool
|
||
|
extends Control
|
||
|
const FlowChartNode = preload("res://addons/imjp94.yafsm/scenes/flowchart/FlowChartNode.gd")
|
||
|
|
||
|
var content_lines = Control.new() # Node that hold all flowchart lines
|
||
|
var content_nodes = Control.new() # Node that hold all flowchart nodes
|
||
|
|
||
|
var _connections = {}
|
||
|
|
||
|
func _init():
|
||
|
|
||
|
name = "FlowChartLayer"
|
||
|
mouse_filter = MOUSE_FILTER_IGNORE
|
||
|
|
||
|
content_lines.name = "content_lines"
|
||
|
content_lines.mouse_filter = MOUSE_FILTER_IGNORE
|
||
|
add_child(content_lines)
|
||
|
move_child(content_lines, 0) # Make sure content_lines always behind nodes
|
||
|
|
||
|
content_nodes.name = "content_nodes"
|
||
|
content_nodes.mouse_filter = MOUSE_FILTER_IGNORE
|
||
|
add_child(content_nodes)
|
||
|
|
||
|
func hide_content():
|
||
|
content_nodes.hide()
|
||
|
content_lines.hide()
|
||
|
|
||
|
func show_content():
|
||
|
content_nodes.show()
|
||
|
content_lines.show()
|
||
|
|
||
|
# Get required scroll rect base on content
|
||
|
func get_scroll_rect(scroll_margin=0):
|
||
|
var rect = Rect2()
|
||
|
for child in content_nodes.get_children():
|
||
|
# Every child is a state/statemachine node
|
||
|
var child_rect = child.get_rect()
|
||
|
rect = rect.merge(child_rect)
|
||
|
return rect.grow(scroll_margin)
|
||
|
|
||
|
# Add node
|
||
|
func add_node(node):
|
||
|
content_nodes.add_child(node)
|
||
|
|
||
|
# Remove node
|
||
|
func remove_node(node):
|
||
|
if node:
|
||
|
content_nodes.remove_child(node)
|
||
|
|
||
|
# Called after connection established
|
||
|
func _connect_node(connection):
|
||
|
content_lines.add_child(connection.line)
|
||
|
connection.join()
|
||
|
|
||
|
# Called after connection broken
|
||
|
func _disconnect_node(connection):
|
||
|
content_lines.remove_child(connection.line)
|
||
|
return connection.line
|
||
|
|
||
|
# Rename node
|
||
|
func rename_node(old, new):
|
||
|
for from in _connections.keys():
|
||
|
if from == old: # Connection from
|
||
|
var from_connections = _connections[from]
|
||
|
_connections.erase(old)
|
||
|
_connections[new] = from_connections
|
||
|
else: # Connection to
|
||
|
for to in _connections[from].keys():
|
||
|
if to == old:
|
||
|
var from_connection = _connections[from]
|
||
|
var value = from_connection[old]
|
||
|
from_connection.erase(old)
|
||
|
from_connection[new] = value
|
||
|
|
||
|
# Connect two nodes with a line
|
||
|
func connect_node(line, from, to, interconnection_offset=0):
|
||
|
if from == to:
|
||
|
return # Connect to self
|
||
|
var connections_from = _connections.get(from)
|
||
|
if connections_from:
|
||
|
if to in connections_from:
|
||
|
return # Connection existed
|
||
|
var connection = Connection.new(line, content_nodes.get_node(NodePath(from)), content_nodes.get_node(NodePath(to)))
|
||
|
if connections_from == null:
|
||
|
connections_from = {}
|
||
|
_connections[from] = connections_from
|
||
|
connections_from[to] = connection
|
||
|
_connect_node(connection)
|
||
|
|
||
|
# Check if connection in both ways
|
||
|
connections_from = _connections.get(to)
|
||
|
if connections_from:
|
||
|
var inv_connection = connections_from.get(from)
|
||
|
if inv_connection:
|
||
|
connection.offset = interconnection_offset
|
||
|
inv_connection.offset = interconnection_offset
|
||
|
connection.join()
|
||
|
inv_connection.join()
|
||
|
|
||
|
# Break a connection between two node
|
||
|
func disconnect_node(from, to):
|
||
|
var connections_from = _connections.get(from)
|
||
|
var connection = connections_from.get(to)
|
||
|
if connection == null:
|
||
|
return
|
||
|
|
||
|
_disconnect_node(connection)
|
||
|
if connections_from.size() == 1:
|
||
|
_connections.erase(from)
|
||
|
else:
|
||
|
connections_from.erase(to)
|
||
|
|
||
|
connections_from = _connections.get(to)
|
||
|
if connections_from:
|
||
|
var inv_connection = connections_from.get(from)
|
||
|
if inv_connection:
|
||
|
inv_connection.offset = 0
|
||
|
inv_connection.join()
|
||
|
return connection.line
|
||
|
|
||
|
# Clear all selection
|
||
|
func clear_connections():
|
||
|
for connections_from in _connections.values():
|
||
|
for connection in connections_from.values():
|
||
|
connection.line.queue_free()
|
||
|
_connections.clear()
|
||
|
|
||
|
# Return array of dictionary of connection as such [{"from1": "to1"}, {"from2": "to2"}]
|
||
|
func get_connection_list():
|
||
|
var connection_list = []
|
||
|
for connections_from in _connections.values():
|
||
|
for connection in connections_from.values():
|
||
|
connection_list.append({"from": connection.from_node.name, "to": connection.to_node.name})
|
||
|
return connection_list
|
||
|
|
||
|
class Connection:
|
||
|
var line # Control node that draw line
|
||
|
var from_node
|
||
|
var to_node
|
||
|
var offset = 0 # line's y offset to make space for two interconnecting lines
|
||
|
|
||
|
func _init(p_line, p_from_node, p_to_node):
|
||
|
line = p_line
|
||
|
from_node = p_from_node
|
||
|
to_node = p_to_node
|
||
|
|
||
|
# Update line position
|
||
|
func join():
|
||
|
line.join(get_from_pos(), get_to_pos(), offset, [from_node.get_rect() if from_node else Rect2(), to_node.get_rect() if to_node else Rect2()])
|
||
|
|
||
|
# Return start position of line
|
||
|
func get_from_pos():
|
||
|
return from_node.position + from_node.size / 2
|
||
|
|
||
|
# Return destination position of line
|
||
|
func get_to_pos():
|
||
|
return to_node.position + to_node.size / 2 if to_node else line.position
|