diff --git a/addons/btree/Editor/create.gd b/addons/btree/Editor/create.gd index f047ada..66c1aee 100644 --- a/addons/btree/Editor/create.gd +++ b/addons/btree/Editor/create.gd @@ -2,6 +2,7 @@ tool extends MenuButton var pop = null +var undo_redo:UndoRedo = null const Runtime = preload("res://addons/btree/Runtime/runtime.gd") const error_no_task = "No function start with \"task_*(task)\" please create one !" @@ -13,13 +14,46 @@ var wait_scene = preload("res://addons/btree/Editor/wait_node/wait_node.tscn") var general_fcall_scene = preload("res://addons/btree/Editor/general_fcall/general_fcall.tscn") var general_decorator_scene = preload("res://addons/btree/Editor/general_decorator/general_decorator.tscn") var inverter = preload("res://addons/btree/Editor/inverter/inverter.tscn") +var general_decorator_script = preload("res://addons/btree/Editor/general_decorator/general_decorator.gd") var pop_pos = Vector2.ZERO export(NodePath) var graph_path:NodePath export(NodePath) var hint_path:NodePath +var drop_offset = Vector2.ZERO func id_pressed(id): var graph = get_node(graph_path) var zoom = graph.zoom + var test_node = create_node(id) + graph.add_child(test_node) + var generated_name = test_node.name + graph.remove_child(test_node) + test_node.queue_free() + undo_redo.create_action("add_node") + undo_redo.add_do_method(self, "add_node", id, generated_name, drop_offset) + undo_redo.add_undo_method(self, "del_node", generated_name) + undo_redo.commit_action() + return + +func add_node(id, name, offset): + var graph = get_node(graph_path) + var node = create_node(id) + node.name = name + node.offset = offset + (node as GraphNode).connect("dragged", graph, "node_dragged", [node]) + (node as GraphNode).connect("resize_request", graph, "resize_request", [node]) + if node is general_decorator_script: + node.undo_redo = undo_redo + graph.add_child(node) + return + +func del_node(gname): + var graph = get_node(graph_path) + var node = graph.get_node_or_null(gname) + node.queue_free() + return + +func create_node(id): + var graph = get_node(graph_path) var inst = null match id: Runtime.TNodeTypes.TASK: @@ -68,9 +102,7 @@ func id_pressed(id): inst.as_random_sequence() Runtime.TNodeTypes.INVERTER: inst = inverter.instance() - inst.offset = (graph.scroll_offset / zoom) + (graph.get_local_mouse_position() / zoom) - graph.add_child(inst) - return + return inst func _ready(): pop = get_popup() @@ -87,7 +119,7 @@ func _ready(): pop.add_item("While Node", Runtime.TNodeTypes.WHILE) pop.add_item("Wait Node", Runtime.TNodeTypes.WAIT) pop.add_item("Race Node", Runtime.TNodeTypes.RACE) - pop.add_item("Random Selector", Runtime.TNodeTypes.SELECTOR) - pop.add_item("Random Sequence", Runtime.TNodeTypes.SEQUENCE) + pop.add_item("Random Selector", Runtime.TNodeTypes.RANDOM_SELECTOR) + pop.add_item("Random Sequence", Runtime.TNodeTypes.RANDOM_SEQUENCE) pop.add_item("Inverter", Runtime.TNodeTypes.INVERTER) return diff --git a/addons/btree/Editor/editor.tscn b/addons/btree/Editor/editor.tscn index adb4dda..bdad2b2 100644 --- a/addons/btree/Editor/editor.tscn +++ b/addons/btree/Editor/editor.tscn @@ -21,7 +21,7 @@ margin_left = 119.0 margin_right = 172.0 margin_bottom = 20.0 text = "Create" -items = [ "Task", null, 0, false, false, 1, 0, null, "", false, "Selector", null, 0, false, false, 3, 0, null, "", false, "Sequence", null, 0, false, false, 2, 0, null, "", false, "Priority Selector", null, 0, false, false, 4, 0, null, "", false, "Priority Condition", null, 0, false, false, 5, 0, null, "", false, "Paralel", null, 0, false, false, 6, 0, null, "", false, "Mute", null, 0, false, false, 7, 0, null, "", false, "Repeat", null, 0, false, false, 8, 0, null, "", false, "While Node", null, 0, false, false, 9, 0, null, "", false, "Wait Node", null, 0, false, false, 10, 0, null, "", false, "Race Node", null, 0, false, false, 11, 0, null, "", false, "Random Selector", null, 0, false, false, 3, 0, null, "", false, "Random Sequence", null, 0, false, false, 2, 0, null, "", false, "Inverter", null, 0, false, false, 14, 0, null, "", false ] +items = [ "Task", null, 0, false, false, 1, 0, null, "", false, "Selector", null, 0, false, false, 3, 0, null, "", false, "Sequence", null, 0, false, false, 2, 0, null, "", false, "Priority Selector", null, 0, false, false, 4, 0, null, "", false, "Priority Condition", null, 0, false, false, 5, 0, null, "", false, "Paralel", null, 0, false, false, 6, 0, null, "", false, "Mute", null, 0, false, false, 7, 0, null, "", false, "Repeat", null, 0, false, false, 8, 0, null, "", false, "While Node", null, 0, false, false, 9, 0, null, "", false, "Wait Node", null, 0, false, false, 10, 0, null, "", false, "Race Node", null, 0, false, false, 11, 0, null, "", false, "Random Selector", null, 0, false, false, 12, 0, null, "", false, "Random Sequence", null, 0, false, false, 13, 0, null, "", false, "Inverter", null, 0, false, false, 14, 0, null, "", false ] script = ExtResource( 1 ) graph_path = NodePath("../../graph") hint_path = NodePath("../../footer/hint") diff --git a/addons/btree/Editor/general_decorator/general_decorator.gd b/addons/btree/Editor/general_decorator/general_decorator.gd index 6d5f5ce..fc87ced 100644 --- a/addons/btree/Editor/general_decorator/general_decorator.gd +++ b/addons/btree/Editor/general_decorator/general_decorator.gd @@ -2,14 +2,13 @@ tool extends GraphNode const Runtime = preload("res://addons/btree/Runtime/runtime.gd") - var type = -1 +var undo_redo:UndoRedo func _ready(): $slot0/Add.connect("pressed", self, "add_pressed") $slot0/Del.connect("pressed", self, "del_pressed") connect("close_request", self, "close_request") - connect("resize_request", self, "resize_request") return func _enter_tree(): @@ -53,15 +52,11 @@ func label(): return l func add_pressed(): - add_child(label()) - set_slot(get_child_count() - 1, false, 0, Color.blue, true, 0, Color.blue, null, null) + get_parent().gd_add_slot(name) return func del_pressed(): - if get_child_count() > 1: - get_parent().slot_removed(name, get_connection_output_count() - 1) - clear_slot(get_child_count() - 1) - remove_child(get_child(get_child_count()-1)) + get_parent().gd_del_slot(name) return func get_data(): @@ -89,7 +84,3 @@ func set_data(data): func close_request(): get_parent().child_delete(self) return - -func resize_request(new_minsize): - rect_size = new_minsize - return diff --git a/addons/btree/Editor/general_decorator/general_decorator.tscn b/addons/btree/Editor/general_decorator/general_decorator.tscn index c910d25..4b619ba 100644 --- a/addons/btree/Editor/general_decorator/general_decorator.tscn +++ b/addons/btree/Editor/general_decorator/general_decorator.tscn @@ -15,6 +15,9 @@ slot/0/right_enabled = false slot/0/right_type = 0 slot/0/right_color = Color( 1, 1, 1, 1 ) script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} [node name="slot0" type="HBoxContainer" parent="."] margin_left = 16.0 diff --git a/addons/btree/Editor/general_fcall/general_fcall.gd b/addons/btree/Editor/general_fcall/general_fcall.gd index c8f5dac..d004f8d 100644 --- a/addons/btree/Editor/general_fcall/general_fcall.gd +++ b/addons/btree/Editor/general_fcall/general_fcall.gd @@ -2,16 +2,13 @@ tool extends GraphNode const Runtime = preload("res://addons/btree/Runtime/runtime.gd") - var type = Runtime.TNodeTypes.TASK var load_function = "" var params = [] var param_scene = preload("res://addons/btree/Editor/task/param.tscn") - func _ready(): connect("close_request", self, "self_close") - connect("resize_request", self, "self_resize") $Input/Add.connect("pressed", self, "add_pressed") return @@ -34,10 +31,10 @@ func _enter_tree(): opt.selected = 0 for i in params: var input = param_scene.instance() - input.set_id($Params.get_child_count()) input.connect("remove_me", self, "remove_param") input.call_deferred("set_value", i) $Params.add_child(input) + input.update_label() return func as_task(): @@ -57,10 +54,6 @@ func as_while(): set_slot(0, true, 0, Color.blue, true, 0, Color.blue) return -func self_resize(new_minsize): - rect_size = new_minsize - return - func update(): if not get_parent(): return @@ -129,14 +122,9 @@ func get_data(): return ret_data func add_pressed(): - var input = param_scene.instance() - input.set_id($Params.get_child_count()) - input.connect("remove_me", self, "remove_param") - $Params.add_child(input) + get_parent().add_param(name) return func remove_param(param): - $Params.remove_child(param) - for i in range($Params.get_child_count()): - $Params.get_child(i).set_id(i) + get_parent().del_param(name, param.get_index()) return diff --git a/addons/btree/Editor/general_fcall/general_fcall.tscn b/addons/btree/Editor/general_fcall/general_fcall.tscn index 74586b7..2e8a52c 100644 --- a/addons/btree/Editor/general_fcall/general_fcall.tscn +++ b/addons/btree/Editor/general_fcall/general_fcall.tscn @@ -55,6 +55,7 @@ text = "Function Name : " margin_left = 113.0 margin_right = 142.0 margin_bottom = 20.0 +size_flags_horizontal = 3 [node name="Input" type="HBoxContainer" parent="."] margin_left = 16.0 diff --git a/addons/btree/Editor/graph.gd b/addons/btree/Editor/graph.gd index 083f3e5..cfe0735 100644 --- a/addons/btree/Editor/graph.gd +++ b/addons/btree/Editor/graph.gd @@ -83,6 +83,7 @@ var repeat_scene = preload("res://addons/btree/Editor/repeat/repeat.tscn") var wait_scene = preload("res://addons/btree/Editor/wait_node/wait_node.tscn") var general_fcall_scene = preload("res://addons/btree/Editor/general_fcall/general_fcall.tscn") var general_decorator_scene = preload("res://addons/btree/Editor/general_decorator/general_decorator.tscn") +var general_decorator_script = preload("res://addons/btree/Editor/general_decorator/general_decorator.gd") var general_fcall_class = preload("res://addons/btree/Editor/general_fcall/general_fcall.gd") var minim_scene = preload("res://addons/btree/Editor/minim_node/minim_node.tscn") var inverter_scene = preload("res://addons/btree/Editor/inverter/inverter.tscn") @@ -100,110 +101,170 @@ func build_tree_from_data(): return func create_node(n): + var node if n.type == Runtime.TNodeTypes.TASK: - var task = general_fcall_scene.instance() - task.as_task() - task.name = n.name - task.set_data(n.data) - return task + node = general_fcall_scene.instance() + node.as_task() + node.name = n.name + node.set_data(n.data) elif n.type == Runtime.TNodeTypes.SEQUENCE: - var seq = general_decorator_scene.instance() - seq.as_sequence() - seq.name = n.name - seq.set_data(n.data) - return seq + node = general_decorator_scene.instance() + node.as_sequence() + node.name = n.name + node.set_data(n.data) elif n.type == Runtime.TNodeTypes.SELECTOR: - var sel = general_decorator_scene.instance() - sel.as_selector() - sel.name = n.name - sel.set_data(n.data) - return sel + node = general_decorator_scene.instance() + node.as_selector() + node.name = n.name + node.set_data(n.data) elif n.type == Runtime.TNodeTypes.PRIORITY_SELECTOR: - var pse = pselector_scene.instance() - pse.name = n.name - pse.set_data(n.data) - return pse + node = pselector_scene.instance() + node.name = n.name + node.set_data(n.data) elif n.type == Runtime.TNodeTypes.PRIORITY_CONDITION: - var inst = general_fcall_scene.instance() - inst.as_priority_condition() - inst.name = n.name - inst.set_data(n.data) - return inst + node = general_fcall_scene.instance() + node.as_priority_condition() + node.name = n.name + node.set_data(n.data) elif n.type == Runtime.TNodeTypes.PARALEL: - var par = general_decorator_scene.instance() - par.as_paralel() - par.name = n.name - par.set_data(n.data) - return par + node = general_decorator_scene.instance() + node.as_paralel() + node.name = n.name + node.set_data(n.data) elif n.type == Runtime.TNodeTypes.MUTE: - var mute = mute_scene.instance() - mute.name = n.name - mute.set_data(n.data) - return mute + node = mute_scene.instance() + node.name = n.name + node.set_data(n.data) elif n.type == Runtime.TNodeTypes.REPEAT: - var rep = repeat_scene.instance() - rep.name = n.name - rep.set_data(n.data) - return rep + node = repeat_scene.instance() + node.name = n.name + node.set_data(n.data) elif n.type == Runtime.TNodeTypes.WHILE: - var whi = general_fcall_scene.instance() - whi.as_while() - whi.name = n.name - whi.set_data(n.data) - return whi + node = general_fcall_scene.instance() + node.as_while() + node.name = n.name + node.set_data(n.data) elif n.type == Runtime.TNodeTypes.WAIT: - var w = wait_scene.instance() - w.name = n.name - w.set_data(n.data) - return w + node = wait_scene.instance() + node.name = n.name + node.set_data(n.data) elif n.type == Runtime.TNodeTypes.RACE: - var r = general_decorator_scene.instance() - r.as_race() - r.name = n.name - r.set_data(n.data) - return r + node = general_decorator_scene.instance() + node.as_race() + node.name = n.name + node.set_data(n.data) elif n.type == Runtime.TNodeTypes.RANDOM_SELECTOR: - var r = general_decorator_scene.instance() - r.as_random_selector() - r.name = n.name - r.set_data(n.data) - return r + node = general_decorator_scene.instance() + node.as_random_selector() + node.name = n.name + node.set_data(n.data) elif n.type == Runtime.TNodeTypes.RANDOM_SEQUENCE: - var r = general_decorator_scene.instance() - r.as_random_sequence() - r.name = n.name - r.set_data(n.data) - return r + node = general_decorator_scene.instance() + node.as_random_sequence() + node.name = n.name + node.set_data(n.data) elif n.type == Runtime.TNodeTypes.INVERTER: - var r = inverter_scene.instance() - r.name = n.name - r.set_data(n.data) - return r + node = inverter_scene.instance() + node.name = n.name + node.set_data(n.data) elif n.type == Runtime.TNodeTypes.MINIM: - var m = minim_scene.instance() - m.name = n.name - m.set_data(n.data) - return m - return null + node = minim_scene.instance() + node.name = n.name + node.set_data(n.data) + (node as GraphNode).connect("dragged", self, "node_dragged", [node]) + (node as GraphNode).connect("resize_request", self, "resize_request", [node]) + if node is general_decorator_script: + node.undo_redo = undo_redo + return node + +func snapc_vec(size): + size.x /= snap_distance + size.y /= snap_distance + size.x = ceil(size.x) + size.y = ceil(size.y) + size *= snap_distance + return size + +func resize_request(nsize:Vector2, node:GraphNode): + var size = snapc_vec(nsize) + var snap = snapc_vec(node.rect_size) + var fit = true + var temp = node.rect_size + node.rect_size = size + fit = node.rect_size.is_equal_approx(size) + node.rect_size = temp + if not fit: + node.rect_size = Vector2.ZERO + size = snapc_vec(node.rect_size) + node.rect_size = temp + if not size.is_equal_approx(snap): + undo_redo.create_action("node resize") + undo_redo.add_do_method(self, "update_node_rect_size", node.name, size) + undo_redo.add_undo_method(self, "update_node_rect_size", node.name, node.rect_size) + undo_redo.commit_action() + return + +func update_node_rect_size(node_name, size): + var node:GraphNode = get_node_or_null(node_name) + if node: + node.rect_size = size + if not node.rect_size.is_equal_approx(size): + node.rect_size = snapc_vec(node.rect_size) + return func connection_request(from, from_slot, to, to_slot): if from == to: return + var dc = [] for i in get_connection_list(): if from == i.from and from_slot == i.from_port: - disconnect_node(i.from, i.from_port, i.to, i.to_port) + dc.append([i.from, i.from_port, i.to, i.to_port]) if to == i.to and to_slot == i.to_port: - disconnect_node(i.from, i.from_port, i.to, i.to_port) - connect_node(from, from_slot, to, to_slot) + dc.append([i.from, i.from_port, i.to, i.to_port]) + undo_redo.create_action("connect_node") +# redo + for i in dc: + undo_redo.add_do_method(self, "disconnect_node", i[0], i[1], i[2], i[3]) + undo_redo.add_do_method(self, "connect_node", from, from_slot, to, to_slot) +# undo + undo_redo.add_undo_method(self, "disconnect_node", from, from_slot, to, to_slot) + for i in dc: + undo_redo.add_undo_method(self, "connect_node", i[0], i[1], i[2], i[3]) + undo_redo.commit_action() return func child_delete(node): + var cp = [] for i in get_connection_list(): - if node.name == i.from: - disconnect_node(i.from, i.from_port, i.to, i.to_port) - if node.name == i.to: - disconnect_node(i.from, i.from_port, i.to, i.to_port) - node.queue_free() + if node.name == i.from or node.name == i.to: + cp.append([i.from, i.from_port, i.to, i.to_port]) + + var data = {} + data["name"] = node.name + data["type"] = node.type + data["data"] = node.get_data() + + undo_redo.create_action("delete node") + undo_redo.add_do_method(self, "remove_node", node.name, cp) + undo_redo.add_undo_method(self, "re_create_node", data, cp) + undo_redo.commit_action() + return + +func re_create_node(data, cp): + var node = create_node(data) + add_child(node) + for i in cp: + connect_node(i[0], i[1], i[2], i[3]) + return + +func remove_node(node_name, cp): + for i in cp: + disconnect_node(i[0], i[1], i[2], i[3]) + var node = get_node_or_null(node_name) + if node: + node.queue_free() + else: + print("NOT FOUND : ",node_name) return func _on_save_pressed(): @@ -267,9 +328,94 @@ func find(name, nodes): return null func disconnection_request(from, from_slot, to, to_slot): - disconnect_node(from, from_slot, to, to_slot) + undo_redo.create_action("disconnect_node") + undo_redo.add_do_method(self, "disconnect_node", from, from_slot, to, to_slot) + undo_redo.add_undo_method(self, "connect_node", from, from_slot, to, to_slot) + undo_redo.commit_action() + return + +func ps_add_slot(name): + undo_redo.create_action("add_slot") + undo_redo.add_do_method(self, "add_slot1", name) + undo_redo.add_undo_method(self, "del_slot", name) + undo_redo.commit_action() + return + +func ps_del_slot(name): + var node = get_node(name) + if node.get_child_count() <= 1: + return + var port = node.get_connection_output_count() - 1 + var con + for i in get_connection_list(): + if i.from == name and i.from_port == port: + con = i + break + undo_redo.create_action("remove_slot") + if con: + undo_redo.add_do_method(self, "disconnect_node", con.from, con.from_port, con.to, con.to_port) + undo_redo.add_do_method(self, "del_slot", name) + undo_redo.add_undo_method(self, "add_slot1", name) + if con: + undo_redo.add_undo_method(self, "connect_node", con.from, con.from_port, con.to, con.to_port) + undo_redo.commit_action() + return + + +func gd_add_slot(name): + undo_redo.create_action("add_slot") + undo_redo.add_do_method(self, "add_slot", name) + undo_redo.add_undo_method(self, "del_slot", name) + undo_redo.commit_action() + return + +func gd_del_slot(name): + var node = get_node(name) + if node.get_child_count() <= 1: + return + var port = node.get_connection_output_count() - 1 + var con + for i in get_connection_list(): + if i.from == name and i.from_port == port: + con = i + break + undo_redo.create_action("remove_slot") + if con: + undo_redo.add_do_method(self, "disconnect_node", con.from, con.from_port, con.to, con.to_port) + undo_redo.add_do_method(self, "del_slot", name) + undo_redo.add_undo_method(self, "add_slot", name) + if con: + undo_redo.add_undo_method(self, "connect_node", con.from, con.from_port, con.to, con.to_port) + undo_redo.commit_action() return +func add_slot1(name): + var node:GraphNode = get_node(name) + node.add_child(label(name)) + node.set_slot(node.get_child_count() - 1, false, 0, Color.blue, true, 1, Color.yellow, null, null) + return + +func add_slot(name): + var node:GraphNode = get_node(name) + node.add_child(label(name)) + node.set_slot(node.get_child_count() - 1, false, 0, Color.blue, true, 0, Color.blue, null, null) + return + +func del_slot(name): + var node:GraphNode = get_node(name) + if get_child_count() > 1: + node.clear_slot(node.get_child_count() - 1) + node.remove_child(node.get_child(node.get_child_count() - 1)) + node.rect_size = Vector2.ZERO + return + +func label(name): + var node = get_node(name) + var l = Label.new() + l.align = Label.ALIGN_RIGHT + l.text = str(node.get_child_count()) + return l + func slot_removed(name, slot): for i in get_connection_list(): if i.from == name and i.from_port == slot: @@ -353,7 +499,8 @@ func copy_node(): return var root_offset = (scroll_offset / zoom) + (get_local_mouse_position() / zoom) - + root_offset = snapc_vec(root_offset) + var nodes = [] for i in get_children(): if i is GraphNode: @@ -363,37 +510,55 @@ func copy_node(): "data":i.get_data() } nodes.append(node) + var cp = find(selected.name, nodes) - build_tree(cp, get_connection_list(), nodes) nodes.clear() rec_populate(cp, nodes) - - var inst_node = [] - var mapping = {} + + var nmap = {} for i in nodes: - var inst = create_node(i) - var ori_name = inst.name - add_child(inst) - inst_node.append(inst) - var mapping_name = inst.name - mapping[ori_name] = mapping_name - - var rinst = null - for i in inst_node: - if i.name == mapping[cp.name]: - rinst = i - break + var tnode = create_node(i) + add_child(tnode) + nmap[i.name] = tnode.name + + for i in nmap.values(): + var rm = get_node(i) + remove_child(rm) + rm.free() + + var con_pair = [] + for n in nodes: + for j in get_connection_list(): + if n.name == j.from: + con_pair.append([nmap[j.from], j.from_port, nmap[j.to], j.to_port]) + + for i in nodes: + i.name = nmap[i.name] + var shifted = root_offset - selected.offset + undo_redo.create_action("recursive_copy") + undo_redo.add_do_method(self, "create_graph", nodes, con_pair, shifted) + undo_redo.add_undo_method(self, "delete_graph", nodes, con_pair) + undo_redo.commit_action() + return - if rinst: - var shifted = root_offset - rinst.offset - for i in inst_node: - i.offset += shifted +func delete_graph(nodes, con_pair): + for c in con_pair: + disconnect_node(c[0], c[1], c[2], c[3]) + for n in nodes: + if has_node(n.name): + var i = get_node(n.name) + remove_child(i) + i.free() + return - for i in nodes: - for j in get_connection_list(): - if i.name == j.from: - connect_node(mapping[j.from], j.from_port, mapping[j.to], j.to_port) +func create_graph(nodes, con_pair, shifted): + for n in nodes: + var inst = create_node(n) + inst.offset += shifted + add_child(inst) + for c in con_pair: + connect_node(c[0], c[1], c[2], c[3]) return var minim_class = preload("res://addons/btree/Editor/minim_node/minim_node.gd") @@ -411,9 +576,26 @@ func minimize_node(): if selected.name == "root": hint("Cannot Minimize \"root\" Node !") return - var soffset = selected.offset + var tnode = minim_scene.instance() + add_child(tnode) + var target_name = tnode.name + remove_child(tnode) + tnode.free() + undo_redo.create_action("minim_node") + undo_redo.add_do_method(self, "do_minim", selected.name, target_name) + undo_redo.add_undo_method(self, "do_maxim", target_name) + undo_redo.commit_action() + return + +func do_minim(node_name, minim_name): + var mnode = get_node_or_null(node_name) + if not mnode: + return + var soffset = mnode.offset var m_inst = minim_scene.instance() + m_inst.connect("dragged", self, "node_dragged", [m_inst]) m_inst.offset = soffset + m_inst.name = minim_name add_child(m_inst) var nodes = [] @@ -426,7 +608,7 @@ func minimize_node(): } nodes.append(node) - var cp = find(selected.name, nodes) + var cp = find(mnode.name, nodes) build_tree(cp, get_connection_list(), nodes) nodes.clear() rec_populate(cp, nodes) @@ -457,12 +639,12 @@ func minimize_node(): } nodes.append(node) - var mroot = find(selected.name, nodes) + var mroot = find(mnode.name, nodes) build_tree(mroot, get_connection_list(), nodes) m_inst.data["root"] = mroot for i in get_connection_list(): - if i.to == selected.name: + if i.to == mnode.name: disconnect_node(i.from, i.from_port, i.to, i.to_port) if current_connection: @@ -480,12 +662,23 @@ func minimize_node(): return func maximize_node(minim): - var data = minim.data + undo_redo.create_action("expand_minim") + undo_redo.add_do_method(self, "do_maxim", minim.name) + undo_redo.add_undo_method(self, "do_minim", minim.data.root.name, minim.name) + undo_redo.commit_action() + return +func do_maxim(node_name): + var minim = get_node_or_null(node_name) + if not minim: + return + + remove_child(minim) + var data = minim.data var connection = data.connection var nodes = data.nodes var root = data.root - + var inst_node = [] var mapping = {} for i in nodes: @@ -495,28 +688,28 @@ func maximize_node(minim): inst_node.append(inst) var mapping_name = inst.name mapping[ori_name] = mapping_name - + var rinst = null for i in inst_node: if i.name == mapping[root.name]: rinst = i break - + if rinst: var shifted = minim.offset - rinst.offset for i in inst_node: i.offset += shifted - + for i in nodes: for j in connection: if i.name == j.from or i.name == j.to: connect_node(mapping[j.from], j.from_port, mapping[j.to], j.to_port) - + for i in get_connection_list(): if i.to == minim.name: disconnect_node(i.from, i.from_port, i.to, i.to_port) connect_node(i.from, i.from_port, rinst.name, 0) - + minim.queue_free() selected = rinst set_selected(rinst) @@ -547,28 +740,61 @@ func rdelete_node(): build_tree(cp, get_connection_list(), nodes) nodes.clear() rec_populate(cp, nodes) - + + var dcon = [] + for i in nodes: for j in get_connection_list(): if i.name == j.from or i.name == j.to: - disconnect_node(j.from, j.from_port, j.to, j.to_port) - + dcon.append([j.from, j.from_port, j.to, j.to_port]) + + var dnam = [] for i in nodes: if has_node(i.name): - var n = get_node(i.name) - n.free() + var node = get_node(i.name) + var data = {} + data["name"] = node.name + data["type"] = node.type + data["data"] = node.get_data() + dnam.append(data) selected = null + + undo_redo.create_action("recursive_delete") + for i in dcon: + undo_redo.add_do_method(self, "disconnect_node", i[0], i[1], i[2], i[3]) + for i in dnam: + undo_redo.add_do_method(self, "fnode", i) + + for i in dnam: + undo_redo.add_undo_method(self, "cnode", i) + for i in dcon: + undo_redo.add_undo_method(self, "connect_node", i[0], i[1], i[2], i[3]) + undo_redo.commit_action() + return + +func cnode(ndata:Dictionary): + var node = create_node(ndata) + add_child(node) + return + +func fnode(ndata:Dictionary): + var node = get_node(ndata.name) + remove_child(node) + node.free() return func rmove_node(): var root_offset = (scroll_offset / zoom) + (get_local_mouse_position() / zoom) + root_offset = snapc_vec(root_offset) if not selected: hint("No Node Selected") return if not selected.selected: hint("No Node Selected") return - + if (selected as GraphNode).offset.is_equal_approx(root_offset): + return + var nodes = [] for i in get_children(): if i is GraphNode: @@ -578,22 +804,33 @@ func rmove_node(): "data":i.get_data() } nodes.append(node) - + var cp = find(selected.name, nodes) build_tree(cp, get_connection_list(), nodes) nodes.clear() rec_populate(cp, nodes) - + if not has_node(cp.name): return - + var rn = get_node(cp.name) var shifted = root_offset - rn.offset - + + var shifted_name = [] for i in nodes: if has_node(i.name): - var n = get_node(i.name) - n.offset += shifted + shifted_name.append(i.name) + undo_redo.create_action("recursive_move") + undo_redo.add_do_method(self, "shift_nodes", shifted_name, shifted) + undo_redo.add_undo_method(self, "shift_nodes", shifted_name, -shifted) + undo_redo.commit_action() + return + +func shift_nodes(names, shifted): + for i in names: + if has_node(i): + var node:GraphNode = get_node(i) + node.offset += shifted return func rec_populate(root, nodes:Array): @@ -637,7 +874,10 @@ func _on_search_bar_text_changed(new_text): export(NodePath) var create_path func popup_request(position): - get_node(create_path).get_popup().popup(Rect2(position, Vector2(1, 1))) + var create = get_node(create_path) + create.drop_offset = (scroll_offset / zoom) + (get_local_mouse_position() / zoom) + create.undo_redo = undo_redo + create.get_popup().popup(Rect2(position, Vector2(1, 1))) return func _on_debug_pressed(): @@ -648,6 +888,33 @@ func _on_help_pressed(): get_parent().get_parent().help() return +func _process(delta): + if not dragged_nodes.empty(): + var redo = [] + var undo = [] + for i in dragged_nodes: + undo.append([i[2], i[0]]) + redo.append([i[2], i[1]]) + undo_redo.create_action("node_drag") + undo_redo.add_do_method(self, "update_node_offset", redo) + undo_redo.add_undo_method(self, "update_node_offset", undo) + undo_redo.commit_action() + dragged_nodes.clear() + return + +func update_node_offset(node_offset): + for i in node_offset: + var n:GraphNode = get_node_or_null(i[0]) + if n: + n.offset = (i[1] / snap_distance) * snap_distance + return + +var dragged_nodes = [] +func node_dragged(start, end, node): + var event = [start, end, node.name] + dragged_nodes.append(event) + return + func create_snapshot(): var info = {} info.nodes = [] @@ -677,8 +944,94 @@ func load_from(data): var node = get_node("root") node.set_data(n.data) else: - var node = create_node(n) + var node:GraphNode = create_node(n) add_child(node) for c in data.connection: connect_node(c.from, c.from_port, c.to, c.to_port) return + +var param_scene = preload("res://addons/btree/Editor/task/param.tscn") + +func add_param(name): + undo_redo.create_action("add_param") + undo_redo.add_do_method(self, "add_last", name) + undo_redo.add_do_method(self, "sync_data_and_node", name) + undo_redo.add_undo_method(self, "del_last", name) + undo_redo.add_undo_method(self, "sync_data_and_node", name) + undo_redo.commit_action() + return + +func add_last(name): + var node = get_node(name) + node.params.clear() + var np = node.get_node("Params") + for i in np.get_children(): + node.params.append(i.get_value()) + node.params.append(["", 1]) + return + +func del_last(name): + var node = get_node(name) + node.params.clear() + var np = node.get_node("Params") + for i in np.get_children(): + node.params.append(i.get_value()) + node.params.pop_back() + return + +func sync_data_and_node(name): + var node = get_node(name) + var params:Array = node.params + var target = node.get_node("Params") + while params.size() > target.get_child_count(): + var inst = param_scene.instance() + inst.connect("remove_me", node, "remove_param") + target.add_child(inst) + while params.size() < target.get_child_count(): + var del = target.get_child(0) + target.remove_child(del) + del.queue_free() + for i in range(params.size()): + var sel = target.get_child(i) + sel.set_value(params[i]) + sel.update_label() + node.rect_size = Vector2.ZERO + return + +func del_param(name, index): + var node = get_node(name) + var np = node.get_node("Params") + var params:Array = node.params + params.clear() + for i in np.get_children(): + params.append(i.get_value()) + + var old_value = params[index] + + undo_redo.create_action("remove_param") + undo_redo.add_do_method(self, "cls_index", name, index) + undo_redo.add_do_method(self, "sync_data_and_node", name) + undo_redo.add_undo_method(self, "ins_index", name, index, old_value) + undo_redo.add_undo_method(self, "sync_data_and_node", name) + undo_redo.commit_action() + return + +func cls_index(name, index): + var node = get_node(name) + var np = node.get_node("Params") + var params:Array = node.params + params.clear() + for i in np.get_children(): + params.append(i.get_value()) + params.remove(index) + return + +func ins_index(name, index, value): + var node = get_node(name) + var np = node.get_node("Params") + var params:Array = node.params + params.clear() + for i in np.get_children(): + params.append(i.get_value()) + params.insert(index, value) + return diff --git a/addons/btree/Editor/inverter/inverter.gd b/addons/btree/Editor/inverter/inverter.gd index 6631bb3..d837b95 100644 --- a/addons/btree/Editor/inverter/inverter.gd +++ b/addons/btree/Editor/inverter/inverter.gd @@ -2,9 +2,12 @@ tool extends GraphNode const Runtime = preload("res://addons/btree/Runtime/runtime.gd") - const type = Runtime.TNodeTypes.INVERTER +func _ready(): + connect("close_request", self, "close_request") + return + func _enter_tree(): title = name return @@ -20,10 +23,6 @@ func set_data(data): offset = data.offset return -func _on_inverter_close_request(): +func close_request(): get_parent().child_delete(self) return - -func _on_inverter_resize_request(new_minsize): - rect_size = new_minsize - return diff --git a/addons/btree/Editor/inverter/inverter.tscn b/addons/btree/Editor/inverter/inverter.tscn index 56895b7..54c4269 100644 --- a/addons/btree/Editor/inverter/inverter.tscn +++ b/addons/btree/Editor/inverter/inverter.tscn @@ -21,9 +21,7 @@ __meta__ = { } [node name="slot0" type="Label" parent="."] -margin_left = 32.0 -margin_top = 48.0 -margin_right = 144.0 -margin_bottom = 73.0 -[connection signal="close_request" from="." to="." method="_on_inverter_close_request"] -[connection signal="resize_request" from="." to="." method="_on_inverter_resize_request"] +margin_left = 16.0 +margin_top = 24.0 +margin_right = 79.0 +margin_bottom = 38.0 diff --git a/addons/btree/Editor/minim_node/minim_node.gd b/addons/btree/Editor/minim_node/minim_node.gd index c78c397..8a09fce 100644 --- a/addons/btree/Editor/minim_node/minim_node.gd +++ b/addons/btree/Editor/minim_node/minim_node.gd @@ -8,7 +8,6 @@ var data func _ready(): connect("close_request", self, "close_request") - connect("resize_request", self, "resize_request") $expand.connect("pressed", self, "pressed") return @@ -45,7 +44,3 @@ func pressed(): func close_request(): get_parent().child_delete(self) return - -func resize_request(min_size): - rect_size = min_size - return diff --git a/addons/btree/Editor/minim_node/minim_node.tscn b/addons/btree/Editor/minim_node/minim_node.tscn index e2e9aa6..102045c 100644 --- a/addons/btree/Editor/minim_node/minim_node.tscn +++ b/addons/btree/Editor/minim_node/minim_node.tscn @@ -49,13 +49,13 @@ size_flags_horizontal = 3 [node name="separator" type="HSeparator" parent="."] margin_left = 16.0 -margin_top = 52.0 +margin_top = 53.0 margin_right = 220.0 -margin_bottom = 56.0 +margin_bottom = 57.0 [node name="expand" type="Button" parent="."] margin_left = 16.0 -margin_top = 57.0 +margin_top = 58.0 margin_right = 220.0 -margin_bottom = 77.0 +margin_bottom = 78.0 text = "Expand" diff --git a/addons/btree/Editor/mute/mute.gd b/addons/btree/Editor/mute/mute.gd index a570937..791e4b7 100644 --- a/addons/btree/Editor/mute/mute.gd +++ b/addons/btree/Editor/mute/mute.gd @@ -5,6 +5,10 @@ const Runtime = preload("res://addons/btree/Runtime/runtime.gd") const type = Runtime.TNodeTypes.MUTE +func _ready(): + connect("close_request", self, "close_request") + return + func _enter_tree(): title = name return @@ -20,10 +24,6 @@ func set_data(data): offset = data.offset return -func _on_mute_close_request(): +func close_request(): get_parent().child_delete(self) return - -func _on_mute_resize_request(new_minsize): - rect_size = new_minsize - return diff --git a/addons/btree/Editor/mute/mute.tscn b/addons/btree/Editor/mute/mute.tscn index 404a6a3..efd1dfc 100644 --- a/addons/btree/Editor/mute/mute.tscn +++ b/addons/btree/Editor/mute/mute.tscn @@ -21,9 +21,7 @@ __meta__ = { } [node name="slot0" type="Label" parent="."] -margin_left = 32.0 -margin_top = 48.0 -margin_right = 115.0 -margin_bottom = 73.0 -[connection signal="close_request" from="." to="." method="_on_mute_close_request"] -[connection signal="resize_request" from="." to="." method="_on_mute_resize_request"] +margin_left = 16.0 +margin_top = 24.0 +margin_right = 76.0 +margin_bottom = 38.0 diff --git a/addons/btree/Editor/pselector/pselector.gd b/addons/btree/Editor/pselector/pselector.gd index 1323891..acbf4e2 100644 --- a/addons/btree/Editor/pselector/pselector.gd +++ b/addons/btree/Editor/pselector/pselector.gd @@ -5,9 +5,12 @@ const Runtime = preload("res://addons/btree/Runtime/runtime.gd") const type = Runtime.TNodeTypes.PRIORITY_SELECTOR +func _ready(): + connect("close_request", self, "close_request") + return + func _on_Add_pressed(): - add_child(label()) - set_slot(get_child_count() - 1, false, 0, Color.blue, true, 1, Color.yellow, null, null) + get_parent().ps_add_slot(name) return func label(): @@ -17,10 +20,7 @@ func label(): return l func _on_Del_pressed(): - if get_child_count() > 1: - get_parent().slot_removed(name, get_connection_output_count() - 1) - clear_slot(get_child_count() - 1) - remove_child(get_child(get_child_count()-1)) + get_parent().ps_del_slot(name) return func _enter_tree(): @@ -49,10 +49,6 @@ func set_data(data): set_slot(get_child_count() - 1, false, 0, Color.blue, true, 1, Color.yellow, null, null) return -func _on_priority_selector_resize_request(new_minsize): - rect_size = new_minsize - return - -func _on_priority_selector_close_request(): +func close_request(): get_parent().child_delete(self) return diff --git a/addons/btree/Editor/pselector/pselector.tscn b/addons/btree/Editor/pselector/pselector.tscn index 1f9ca8f..0465892 100644 --- a/addons/btree/Editor/pselector/pselector.tscn +++ b/addons/btree/Editor/pselector/pselector.tscn @@ -35,7 +35,5 @@ margin_left = 100.0 margin_right = 117.0 margin_bottom = 20.0 text = "-" -[connection signal="close_request" from="." to="." method="_on_priority_selector_close_request"] -[connection signal="resize_request" from="." to="." method="_on_priority_selector_resize_request"] [connection signal="pressed" from="Control/Add" to="." method="_on_Add_pressed"] [connection signal="pressed" from="Control/Del" to="." method="_on_Del_pressed"] diff --git a/addons/btree/Editor/repeat/repeat.gd b/addons/btree/Editor/repeat/repeat.gd index e432bb8..97f31e5 100644 --- a/addons/btree/Editor/repeat/repeat.gd +++ b/addons/btree/Editor/repeat/repeat.gd @@ -6,6 +6,7 @@ const Runtime = preload("res://addons/btree/Runtime/runtime.gd") const type = Runtime.TNodeTypes.REPEAT func _ready(): + connect("close_request", self, "close_request") $slot0/count.value = 0 return @@ -13,11 +14,7 @@ func _enter_tree(): title = name return -func _on_repeat_resize_request(new_minsize): - rect_size = new_minsize - return - -func _on_repeat_close_request(): +func close_request(): get_parent().child_delete(self) return @@ -33,4 +30,3 @@ func set_data(data): offset = data.offset $slot0/count.call_deferred("set_value", data.count) return - diff --git a/addons/btree/Editor/repeat/repeat.tscn b/addons/btree/Editor/repeat/repeat.tscn index 0675142..879f933 100644 --- a/addons/btree/Editor/repeat/repeat.tscn +++ b/addons/btree/Editor/repeat/repeat.tscn @@ -19,6 +19,9 @@ slot/0/right_enabled = true slot/0/right_type = 0 slot/0/right_color = Color( 0, 0.0862745, 1, 1 ) script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} [node name="slot0" type="HBoxContainer" parent="."] margin_left = 16.0 @@ -36,7 +39,6 @@ text = "Count : " margin_left = 53.0 margin_right = 127.0 margin_bottom = 24.0 +size_flags_horizontal = 3 allow_greater = true script = ExtResource( 2 ) -[connection signal="close_request" from="." to="." method="_on_repeat_close_request"] -[connection signal="resize_request" from="." to="." method="_on_repeat_resize_request"] diff --git a/addons/btree/Editor/task/param.gd b/addons/btree/Editor/task/param.gd index b5c45cd..7d84abd 100644 --- a/addons/btree/Editor/task/param.gd +++ b/addons/btree/Editor/task/param.gd @@ -2,25 +2,45 @@ tool extends HBoxContainer signal remove_me(me) - -var id = 0 +var float_regex:RegEx = RegEx.new() func _ready(): + float_regex.compile("^[-+]?\\d*\\.?\\d*$") $OptionButton.clear() $OptionButton.add_item("Number") $OptionButton.add_item("Text") $OptionButton.selected = 1 + _on_OptionButton_item_selected(1) + $text_value.connect("text_changed", self, "validate") + $text_value.connect("focus_exited", self, "fe_validate") return -func set_id(value:int): - id = value +func fe_validate(): + var value = $text_value.text + if $OptionButton.selected == 0: + var r = float_regex.search(value) + if r: + $text_value.text = r.get_string() + else: + $text_value.text = "0" return -func _process(delta): - $Label.text = str(id, " : ") +func validate(value:String): + if $OptionButton.selected == 0: + if value.length() == 0: + return + var r = float_regex.search(value) + if r: + var pc = $text_value.caret_position + $text_value.text = r.get_string() + $text_value.caret_position = pc + else: + $text_value.text = "0" + $text_value.caret_position = 1 return -func _on_TextEdit_gui_input(event): +func update_label(): + $Label.text = str(get_index(), " : ") return func _on_Button_pressed(): @@ -28,39 +48,24 @@ func _on_Button_pressed(): return func get_value(): - var val = $TextEdit.text + var val if $OptionButton.selected == 0: - if val.is_valid_integer(): - val = int(val) - elif val.is_valid_float(): - val = float(val) + var text:String = $text_value.text + if text.is_valid_integer(): + val = text.to_int() else: - val = 0 + val = text.to_float() + else: + val = $text_value.text return [val, $OptionButton.selected] func set_value(values): - $TextEdit.text = str(values[0]) $OptionButton.selected = values[1] + _on_OptionButton_item_selected(values[1]) + $text_value.text = str(values[0]) return -func _on_TextEdit_focus_exited(): - if not valid(): - $TextEdit.text = "0" - return - -func valid()->bool: - var val = $TextEdit.text - if $OptionButton.selected == 0: - if val.is_valid_integer(): - return true - elif val.is_valid_float(): - return true - else: - return false - else: - return true - func _on_OptionButton_item_selected(ID): - if not valid(): - $TextEdit.text = "0" + if ID == 0: + validate($text_value.text) return diff --git a/addons/btree/Editor/task/param.tscn b/addons/btree/Editor/task/param.tscn index f849b7a..949437e 100644 --- a/addons/btree/Editor/task/param.tscn +++ b/addons/btree/Editor/task/param.tscn @@ -18,18 +18,15 @@ margin_bottom = 14.0 size_flags_vertical = 0 text = "0 : " -[node name="TextEdit" type="TextEdit" parent="."] +[node name="text_value" type="LineEdit" parent="."] margin_left = 24.0 -margin_right = 124.0 -margin_bottom = 40.0 -rect_min_size = Vector2( 100, 40 ) +margin_right = 122.0 +margin_bottom = 24.0 size_flags_horizontal = 3 -size_flags_vertical = 3 -wrap_enabled = true [node name="OptionButton" type="OptionButton" parent="."] -margin_left = 128.0 -margin_right = 184.0 +margin_left = 126.0 +margin_right = 182.0 margin_bottom = 20.0 size_flags_horizontal = 0 size_flags_vertical = 0 @@ -38,12 +35,11 @@ items = [ "Number", null, false, 0, null, "Text", null, false, 1, null ] selected = 1 [node name="Button" type="Button" parent="."] -margin_left = 188.0 -margin_right = 208.0 +margin_left = 186.0 +margin_right = 206.0 margin_bottom = 20.0 size_flags_horizontal = 0 size_flags_vertical = 0 text = "X" -[connection signal="focus_exited" from="TextEdit" to="." method="_on_TextEdit_focus_exited"] [connection signal="item_selected" from="OptionButton" to="." method="_on_OptionButton_item_selected"] [connection signal="pressed" from="Button" to="." method="_on_Button_pressed"] diff --git a/addons/btree/Editor/tree_root/root.gd b/addons/btree/Editor/tree_root/root.gd index 96aa768..5c5a203 100644 --- a/addons/btree/Editor/tree_root/root.gd +++ b/addons/btree/Editor/tree_root/root.gd @@ -2,9 +2,12 @@ tool extends GraphNode const Runtime = preload("res://addons/btree/Runtime/runtime.gd") - const type = Runtime.TNodeTypes.ROOT +func _ready(): + connect("dragged", get_parent(), "node_dragged", [self]) + return + func get_data(): return { "offset" : offset, diff --git a/addons/btree/Editor/wait_node/wait_node.gd b/addons/btree/Editor/wait_node/wait_node.gd index fd85089..2c98c31 100644 --- a/addons/btree/Editor/wait_node/wait_node.gd +++ b/addons/btree/Editor/wait_node/wait_node.gd @@ -2,10 +2,10 @@ tool extends GraphNode const Runtime = preload("res://addons/btree/Runtime/runtime.gd") - const type = Runtime.TNodeTypes.WAIT func _ready(): + connect("close_request", self, "close_request") $slot0/count.value = 0 return @@ -13,11 +13,7 @@ func _enter_tree(): title = name return -func _on_wait_node_resize_request(new_minsize): - rect_size = new_minsize - return - -func _on_wait_node_close_request(): +func close_request(): get_parent().child_delete(self) return diff --git a/addons/btree/Editor/wait_node/wait_node.tscn b/addons/btree/Editor/wait_node/wait_node.tscn index 07dee39..93d1d29 100644 --- a/addons/btree/Editor/wait_node/wait_node.tscn +++ b/addons/btree/Editor/wait_node/wait_node.tscn @@ -16,6 +16,9 @@ slot/0/right_enabled = false slot/0/right_type = 0 slot/0/right_color = Color( 1, 1, 1, 1 ) script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} [node name="slot0" type="HBoxContainer" parent="."] margin_left = 16.0 @@ -33,7 +36,6 @@ text = "Count : " margin_left = 53.0 margin_right = 127.0 margin_bottom = 24.0 +size_flags_horizontal = 3 allow_greater = true script = ExtResource( 2 ) -[connection signal="close_request" from="." to="." method="_on_wait_node_close_request"] -[connection signal="resize_request" from="." to="." method="_on_wait_node_resize_request"]