2356 lines
71 KiB
GDScript
2356 lines
71 KiB
GDScript
@tool
|
|
extends Object
|
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
|
# Script Spliter
|
|
# https://github.com/CodeNameTwister/Script-Spliter
|
|
#
|
|
# Script Spliter addon for godot 4
|
|
# author: "Twister"
|
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
|
|
|
const EditorContainer : Script = preload("res://addons/script_spliter/core/EditorContainer.gd")
|
|
const DD : Script = preload("res://addons/script_spliter/core/DDContainer.gd")
|
|
const DDO : PackedScene = preload("res://addons/script_spliter/core/ui/dd.tscn")
|
|
const DDITEM : Script = preload("res://addons/script_spliter/core/DDItem.gd")
|
|
|
|
#region POPSC
|
|
const FLYING_SCRIPT : PackedScene = preload("res://addons/script_spliter/context/flying_script.tscn")
|
|
const _POP_SCRIPT_PLACEHOLDER : String = "_POPGDScript_"
|
|
var _pop_scripts : Array[Window] = []
|
|
var _pop_script_placeholder : bool = false
|
|
#endregion
|
|
|
|
const GLOBALS : PackedStringArray = ["_GlobalScope", "_GDScript"]
|
|
|
|
var _plugin : Node = null
|
|
|
|
var _root : Node = null
|
|
var _main : EditorContainer = null
|
|
var _container : Root = null
|
|
var _editor : TabContainer = null
|
|
|
|
var _code_editors : Array[Mickeytools] = []
|
|
|
|
var _last_local_tool : Mickeytools = null
|
|
var _last_tool : Mickeytools = null:
|
|
set(e):
|
|
_last_tool = e
|
|
if is_instance_valid(_last_tool):
|
|
if !_last_tool.is_floating():
|
|
_last_local_tool = _last_tool
|
|
|
|
var _tweener : ReTweener = null
|
|
var _item_list : ItemList = null:
|
|
set(e):
|
|
|
|
if e == null and is_instance_valid(_item_list):
|
|
if _item_list.has_signal(&"on_start_drag") and _item_list.is_connected(&"on_start_drag", _on_drag):
|
|
_item_list.disconnect(&"on_start_drag", _on_drag)
|
|
if _item_list.has_signal(&"on_stop_drag") and _item_list.is_connected(&"on_stop_drag", _out_drag):
|
|
_item_list.disconnect(&"on_stop_drag", _out_drag)
|
|
|
|
if _item_list.get_script() == DDITEM:
|
|
_item_list.set_script(null)
|
|
_item_list = null
|
|
else:
|
|
_item_list = e
|
|
if is_instance_valid(_item_list) and _item_list.get_script() != DDITEM:
|
|
_item_list.set_script(DDITEM)
|
|
|
|
if _item_list.has_signal(&"on_start_drag") and !_item_list.is_connected(&"on_start_drag", _on_drag):
|
|
_item_list.connect(&"on_start_drag", _on_drag)
|
|
if _item_list.has_signal(&"on_stop_drag") and !_item_list.is_connected(&"on_stop_drag", _out_drag):
|
|
_item_list.connect(&"on_stop_drag", _out_drag)
|
|
|
|
|
|
get:
|
|
if !is_instance_valid(_item_list):
|
|
var script_editor: ScriptEditor = EditorInterface.get_script_editor()
|
|
var items : Array[Node] = script_editor.find_children("*", "ItemList", true, false)
|
|
if items.size() > 0:
|
|
_item_list = items[0]
|
|
else:
|
|
push_warning("[Script-Spliter] Can not find item list!")
|
|
return _item_list
|
|
|
|
#region __CONFIG__
|
|
var _SPLIT_USE_HIGHLIGHT_SELECTED : bool = true
|
|
var _MINIMAP_4_UNFOCUS_WINDOW : bool = false
|
|
|
|
var _SPLIT_HIGHLIGHT_COLOR : Color = Color.MEDIUM_SLATE_BLUE
|
|
|
|
var _SEPARATOR_LINE_SIZE : int = 8
|
|
var _SEPARATOR_LINE_COLOR : Color = Color.MAGENTA
|
|
var _SEPARATOR_BUTTON_SIZE : int = 19
|
|
var _SEPARATOR_BUTTON_MODULATE : Color = Color.WHITE
|
|
var _SEPARATOR_BUTTON_ICON : String = "res://addons/script_spliter/context/icons/expand.svg"
|
|
|
|
var _SEPARATOR_LINE_MOVEMENT : bool = true
|
|
var _SEPARATOR_LINE_DOUBLE_CLICK : bool = true
|
|
|
|
var _BEHAVIOUR_CAN_EXPAND_ON_FOCUS : bool = true
|
|
var _BEHAVIOUR_CAN_EXPAND_SAME_ON_FOCUS : bool = false
|
|
|
|
var _SEPARATOR_SMOOTH_EXPAND : bool = true
|
|
var _SEPARATOR_SMOOTH_EXPAND_TIME : float = 0.24
|
|
|
|
var _OUT_FOCUS_COLORED : bool = true
|
|
var _UNFOCUS_COLOR : Color = Color.GRAY
|
|
|
|
var _SWAP_BY_BUTTON : bool = true
|
|
|
|
#region _9_
|
|
var HANDLE_BACK_FORWARD_BUTTONS : bool = true
|
|
var HANDLE_BACKWARD_FORWARD_AS_NEXT_BACK_TAB : bool = false
|
|
var HANDLE_BACK_FORWARD_BUFFER : int = 20
|
|
var USE_NATIVE_ON_NOT_TABS : bool = true
|
|
var _HANDLE_BACKWARD_KEY_PATH : String = "res://addons/script_spliter/io/backward_key_button.tres"
|
|
var _HANDLE_FORWARD_KEY_PATH : String = "res://addons/script_spliter/io/forward_key_button.tres"
|
|
var _HANDLE_BACKWARD_MOUSE_BUTTON_PATH : String = "res://addons/script_spliter/io/backward_mouse_button.tres"
|
|
var _HANDLE_FORWARD_MOUSE_BUTTON_PATH : String = "res://addons/script_spliter/io/forward_mouse_button.tres"
|
|
#endregion
|
|
|
|
# CURRENT CONFIG
|
|
var current_columns : int = 1
|
|
var current_rows : int = 1
|
|
|
|
# FLAG
|
|
var _chaser_enabled : bool = false
|
|
var _focus_queue : bool = false
|
|
|
|
# REF
|
|
var _wm : Window = null
|
|
|
|
var is_dd_handled : bool = false
|
|
var _last_dd_root : Control = null
|
|
var _ddo : Control = null
|
|
|
|
signal tool_added(tool : Mickeytools)
|
|
|
|
func _get_data_cfg() -> Array[Array]:
|
|
const CFG : Array[Array] = [
|
|
[&"plugin/script_spliter/window/use_highlight_selected", &"_SPLIT_USE_HIGHLIGHT_SELECTED"]
|
|
,[&"plugin/script_spliter/window/highlight_selected_color",&"_SPLIT_HIGHLIGHT_COLOR"]
|
|
|
|
,[&"plugin/script_spliter/editor/minimap_for_unfocus_window", &"_MINIMAP_4_UNFOCUS_WINDOW"]
|
|
,[&"plugin/script_spliter/editor/out_focus_color_enabled", &"_OUT_FOCUS_COLORED"]
|
|
,[&"plugin/script_spliter/editor/out_focus_color_value", &"_UNFOCUS_COLOR"]
|
|
,[&"plugin/script_spliter/editor/split/reopen_last_closed_editor_on_add_split", &"_SHOULD_OPEN_CLOSED_EDITOR_SCRIPT"]
|
|
,[&"plugin/script_spliter/editor/split/remember_last_used_editor_buffer_size", &"_LAST_USED_EDITOR_SIZE"]
|
|
|
|
,[&"plugin/script_spliter/line/size", &"_SEPARATOR_LINE_SIZE"]
|
|
,[&"plugin/script_spliter/line/color", &"_SEPARATOR_LINE_COLOR"]
|
|
,[&"plugin/script_spliter/line/draggable", &"_SEPARATOR_LINE_MOVEMENT"]
|
|
,[&"plugin/script_spliter/line/expand_by_double_click", &"_SEPARATOR_LINE_DOUBLE_CLICK"]
|
|
|
|
,[&"plugin/script_spliter/line/button/size", &"_SEPARATOR_BUTTON_SIZE"]
|
|
,[&"plugin/script_spliter/line/button/modulate", &"_SEPARATOR_BUTTON_MODULATE"]
|
|
,[&"plugin/script_spliter/line/button/icon_path", &"_SEPARATOR_BUTTON_ICON"]
|
|
|
|
,[&"plugin/script_spliter/editor/behaviour/expand_on_focus", &"_BEHAVIOUR_CAN_EXPAND_ON_FOCUS"]
|
|
,[&"plugin/script_spliter/editor/behaviour/can_expand_on_same_focus", &"_BEHAVIOUR_CAN_EXPAND_SAME_ON_FOCUS"]
|
|
,[&"plugin/script_spliter/editor/behaviour/smooth_expand", &"_SEPARATOR_SMOOTH_EXPAND"]
|
|
,[&"plugin/script_spliter/editor/behaviour/smooth_expand_time", &"_SEPARATOR_SMOOTH_EXPAND_TIME"]
|
|
,[&"plugin/script_spliter/editor/behaviour/swap_by_double_click_separator_button", &"_SWAP_BY_BUTTON"]
|
|
,[&"plugin/script_spliter/editor/behaviour/back_and_forward/handle_back_and_forward", &"HANDLE_BACK_FORWARD_BUTTONS"]
|
|
,[&"plugin/script_spliter/editor/behaviour/back_and_forward/history_size", &"HANDLE_BACK_FORWARD_BUFFER"]
|
|
,[&"plugin/script_spliter/editor/behaviour/back_and_forward/using_as_next_and_back_tab", &"HANDLE_BACKWARD_FORWARD_AS_NEXT_BACK_TAB"]
|
|
,[&"plugin/script_spliter/editor/behaviour/back_and_forward/backward_key_button_path", &"_HANDLE_BACKWARD_KEY_PATH"]
|
|
,[&"plugin/script_spliter/editor/behaviour/back_and_forward/forward_key_button_path", &"_HANDLE_FORWARD_KEY_PATH"]
|
|
,[&"plugin/script_spliter/editor/behaviour/back_and_forward/backward_mouse_button_path", &"_HANDLE_BACKWARD_MOUSE_BUTTON_PATH"]
|
|
,[&"plugin/script_spliter/editor/behaviour/back_and_forward/forward_mouse_button_path", &"_HANDLE_FORWARD_MOUSE_BUTTON_PATH"]
|
|
,[&"plugin/script_spliter/editor/behaviour/back_and_forward/use_native_handler_when_there_are_no_more_tabs", &"USE_NATIVE_ON_NOT_TABS"]
|
|
]
|
|
return CFG
|
|
|
|
func _on_wm_foucs() -> void:
|
|
if !is_instance_valid(_last_tool) or _last_tool.is_floating():
|
|
if is_instance_valid(_last_local_tool):
|
|
_last_local_tool.focus.emit(_last_local_tool)
|
|
else:
|
|
for x : Mickeytools in _code_editors:
|
|
if !x.is_floating():
|
|
x.focus.emit(x)
|
|
return
|
|
|
|
func _out_wm_focus() -> void:
|
|
return
|
|
|
|
func show_dd(root : Control) -> void:
|
|
var dd : Control = null
|
|
for xx : Node in _main.get_children():
|
|
if xx is Control and !xx.visible:
|
|
continue
|
|
for x : Node in xx.get_children():
|
|
if x is Control and x.visible:
|
|
var mp : Vector2i = x.get_global_mouse_position()
|
|
if x.get_global_rect().has_point(mp):
|
|
dd = xx
|
|
break
|
|
if dd == null or _last_dd_root == dd:
|
|
return
|
|
_last_dd_root = dd
|
|
|
|
var node : Node = _last_tool.get_root()
|
|
|
|
if node == root:
|
|
return
|
|
if node:
|
|
if dd.find_child(node.name, true, false) != null:
|
|
if is_instance_valid(_ddo):
|
|
var p : Node = _ddo.get_parent()
|
|
if p:
|
|
p.remove_child(_ddo)
|
|
return
|
|
if !is_instance_valid(_ddo):
|
|
_ddo = DDO.instantiate()
|
|
else:
|
|
var p : Node = _ddo.get_parent()
|
|
if p:
|
|
p.remove_child(_ddo)
|
|
dd.add_child(_ddo)
|
|
_ddo.visible = true
|
|
|
|
func set_item_list(o : ItemList) -> void:
|
|
_item_list = o
|
|
|
|
func init_1() -> void:
|
|
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
|
var vp : Viewport = _plugin.get_viewport()
|
|
if vp:
|
|
_wm = vp.get_window()
|
|
|
|
if !_wm.focus_entered.is_connected(_on_wm_foucs):
|
|
_wm.focus_entered.connect(_on_wm_foucs)
|
|
if !_wm.focus_exited.is_connected(_out_wm_focus):
|
|
_wm.focus_exited.connect(_out_wm_focus)
|
|
|
|
|
|
for x : Array in _get_data_cfg():
|
|
if !settings.has_setting(x[0]):
|
|
settings.set_setting(x[0], get(x[1]))
|
|
else:
|
|
set(x[1], settings.get_setting(x[0]))
|
|
|
|
settings.add_property_info({
|
|
"name": &"plugin/script_spliter/window/highlight_selected_color",
|
|
"type": TYPE_COLOR
|
|
})
|
|
settings.add_property_info({
|
|
"name": &"plugin/script_spliter/line/button/modulate",
|
|
"type": TYPE_COLOR
|
|
})
|
|
#endregion
|
|
|
|
#region _FEATURE#5_
|
|
var _SHOULD_OPEN_CLOSED_EDITOR_SCRIPT : bool = false
|
|
var _LAST_USED_EDITOR_SIZE : int = 4
|
|
|
|
var _lifo_src : PackedStringArray = []
|
|
|
|
func add_last_script_used(src : String) -> void:
|
|
if _LAST_USED_EDITOR_SIZE > 0:
|
|
if src.is_empty():
|
|
return
|
|
|
|
var x : int = _lifo_src.find(src)
|
|
if x > -1:
|
|
_lifo_src.remove_at(x)
|
|
|
|
_lifo_src.append(src)
|
|
var total : int = maxi(_LAST_USED_EDITOR_SIZE, 0)
|
|
while _lifo_src.size() > total:
|
|
_lifo_src.remove_at(0)
|
|
|
|
func get_last_script_used() -> String:
|
|
var size : int = _lifo_src.size()
|
|
var result : String = ""
|
|
if size > 0:
|
|
size -= 1
|
|
result = _lifo_src[size]
|
|
_lifo_src.remove_at(size)
|
|
return result
|
|
#region
|
|
|
|
func update_config() -> void:
|
|
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
|
var changes : PackedStringArray = settings.get_changed_settings()
|
|
|
|
var _dirty_colored : bool = _OUT_FOCUS_COLORED
|
|
|
|
for x : Array in _get_data_cfg():
|
|
if x[0] in changes:
|
|
set(x[1], settings.get_setting(x[0]))
|
|
|
|
_update_container()
|
|
|
|
if _dirty_colored and !_OUT_FOCUS_COLORED:
|
|
for x : Mickeytools in _code_editors:
|
|
var gui : Node = x.get_control()
|
|
if is_instance_valid(gui) and gui is Control:
|
|
gui.modulate = Color.WHITE
|
|
|
|
for x : String in changes:
|
|
if "button_path" in x:
|
|
if !InputMap.has_action(&"ui_script_spliter_forward"):
|
|
InputMap.add_action(&"ui_script_spliter_forward")
|
|
else:
|
|
InputMap.action_erase_events(&"ui_script_spliter_forward")
|
|
|
|
var key_0 : InputEventKey = ResourceLoader.load(_HANDLE_FORWARD_KEY_PATH)
|
|
var key_1 : InputEventMouseButton = ResourceLoader.load(_HANDLE_FORWARD_MOUSE_BUTTON_PATH)
|
|
InputMap.action_add_event(&"ui_script_spliter_forward", key_0)
|
|
InputMap.action_add_event(&"ui_script_spliter_forward", key_1)
|
|
|
|
if !InputMap.has_action(&"ui_script_spliter_backward"):
|
|
InputMap.add_action(&"ui_script_spliter_backward")
|
|
else:
|
|
InputMap.action_erase_events(&"ui_script_spliter_backward")
|
|
|
|
key_0 = ResourceLoader.load(_HANDLE_BACKWARD_KEY_PATH)
|
|
key_1 = ResourceLoader.load(_HANDLE_BACKWARD_MOUSE_BUTTON_PATH)
|
|
InputMap.action_add_event(&"ui_script_spliter_backward", key_0)
|
|
InputMap.action_add_event(&"ui_script_spliter_backward", key_1)
|
|
break
|
|
|
|
func _update_container() -> void:
|
|
if !is_instance_valid(_main):
|
|
return
|
|
_main.separator_line_size = _SEPARATOR_LINE_SIZE
|
|
_main.separator_line_color = _SEPARATOR_LINE_COLOR
|
|
_main.drag_button_size = _SEPARATOR_BUTTON_SIZE
|
|
_main.drag_button_modulate = _SEPARATOR_BUTTON_MODULATE
|
|
_main.behaviour_expand_smoothed = _SEPARATOR_SMOOTH_EXPAND
|
|
_main.behaviour_expand_smoothed_time = _SEPARATOR_SMOOTH_EXPAND_TIME
|
|
_main.behaviour_expand_on_focus = _BEHAVIOUR_CAN_EXPAND_ON_FOCUS
|
|
_main.behaviour_can_expand_focus_same_container = _BEHAVIOUR_CAN_EXPAND_SAME_ON_FOCUS
|
|
_main.behaviour_expand_on_double_click = _SEPARATOR_LINE_DOUBLE_CLICK
|
|
_main.behaviour_can_move_by_line = _SEPARATOR_LINE_MOVEMENT
|
|
|
|
if !_SEPARATOR_BUTTON_ICON.is_empty():
|
|
if FileAccess.file_exists(_SEPARATOR_BUTTON_ICON):
|
|
var text : Variant = ResourceLoader.load(_SEPARATOR_BUTTON_ICON)
|
|
if text is Texture:
|
|
_main.drag_button_icon = text
|
|
else:
|
|
push_warning("[Script-Spliter] The resource is not a texture imported ", _SEPARATOR_BUTTON_ICON)
|
|
else:
|
|
push_warning("[Script-Spliter] Can not find the resource ", _SEPARATOR_BUTTON_ICON)
|
|
|
|
func _init(plugin : Object) -> void:
|
|
_plugin = plugin
|
|
|
|
func init_0() -> void:
|
|
if is_instance_valid(_tweener):
|
|
_tweener.clear()
|
|
_tweener = null
|
|
|
|
if is_instance_valid(_ddo):
|
|
if !_ddo.is_queued_for_deletion():
|
|
_ddo.queue_free()
|
|
|
|
if is_instance_valid(_wm):
|
|
if _wm.focus_entered.is_connected(_on_wm_foucs):
|
|
_wm.focus_entered.disconnect(_on_wm_foucs)
|
|
if _wm.focus_exited.is_connected(_out_wm_focus):
|
|
_wm.focus_exited.disconnect(_out_wm_focus)
|
|
|
|
if is_instance_valid(_editor):
|
|
if _editor.tree_exiting.is_connected(_on_container_exit):
|
|
_editor.tree_exiting.disconnect(_on_container_exit)
|
|
if _editor.tree_entered.is_connected(_on_container_entered):
|
|
_editor.tree_entered.disconnect(_on_container_entered)
|
|
|
|
|
|
if is_instance_valid(_root) and _root is Control:
|
|
if _root.item_rect_changed.is_connected(update_rect):
|
|
_root.item_rect_changed.disconnect(update_rect)
|
|
|
|
for x : Mickeytools in _code_editors:
|
|
x.reset(false)
|
|
x.free()
|
|
_code_editors.clear()
|
|
|
|
if is_instance_valid(_container):
|
|
var parent : Node = _container.get_parent()
|
|
_container.visible = false
|
|
if is_instance_valid(parent):
|
|
parent.remove_child(_container)
|
|
_container.queue_free()
|
|
|
|
if is_instance_valid(_editor):
|
|
_setup(_editor, false)
|
|
_editor.visible = true
|
|
|
|
_item_list = null
|
|
|
|
for x : Window in _pop_scripts:
|
|
if is_instance_valid(x) and !x.is_queued_for_deletion():
|
|
x.queue_free()
|
|
_pop_scripts.clear()
|
|
|
|
|
|
func _clear() -> void:
|
|
for z : int in range(_code_editors.size() - 1, -1 , -1):
|
|
var x : Mickeytools = _code_editors[z]
|
|
var dirty : bool = false
|
|
for e : Node in _editor.get_children():
|
|
if x.is_equal(e):
|
|
dirty = true
|
|
break
|
|
if !dirty:
|
|
_code_editors[z].reset()
|
|
_code_editors.remove_at(z)
|
|
|
|
for x : Window in _pop_scripts:
|
|
var node : Node = x.get_base_control()
|
|
for y : Node in node.get_children():
|
|
var dirty : bool = false
|
|
for t : Mickeytools in _code_editors:
|
|
if t.get_control() == y:
|
|
dirty = true
|
|
if !dirty:
|
|
for zx : Node in _editor.get_children():
|
|
if y == zx:
|
|
dirty = true
|
|
break
|
|
if dirty:
|
|
y.queue_free.call_deferred()
|
|
if node.get_child_count() < 1:
|
|
_pop_scripts.erase(x)
|
|
x.queue_free()
|
|
|
|
for x : Node in _main.get_children():
|
|
if x is TabContainer:continue
|
|
for y : Node in x.get_children():
|
|
for z : Node in y.get_children():
|
|
var dirty : bool = false
|
|
for t : Mickeytools in _code_editors:
|
|
if t.get_control() == z:
|
|
dirty = true
|
|
if !dirty:
|
|
for zx : Node in _editor.get_children():
|
|
if z == zx:
|
|
dirty = true
|
|
break
|
|
if dirty:
|
|
z.queue_free.call_deferred()
|
|
else:
|
|
y.remove_child(z)
|
|
|
|
func get_editors() -> Array[Mickeytools]:
|
|
return _code_editors
|
|
|
|
func _get_editor_root() -> Node:
|
|
var aviable : Node = get_aviable()
|
|
if is_instance_valid(aviable):
|
|
return aviable
|
|
if is_instance_valid(_last_tool):
|
|
return _last_tool.get_root()
|
|
return null
|
|
|
|
func get_last_tool() -> Mickeytools:
|
|
return _last_tool
|
|
|
|
func update_info(root : TabContainer, index : int , src : String) -> void:
|
|
if !is_instance_valid(root):
|
|
return
|
|
var item_list : Control = _item_list
|
|
if !src.is_empty():
|
|
if is_instance_valid(item_list):
|
|
var indx : int = -1
|
|
for x : int in item_list.item_count:
|
|
if item_list.get_item_tooltip(x) == src:
|
|
indx = x
|
|
break
|
|
if indx > -1:
|
|
var text : String = _item_list.get_item_text(indx)
|
|
if text.is_empty() or text.begins_with("@"):
|
|
text = item_list.get_item_tooltip(index).get_file()
|
|
text = text.trim_suffix("(*)")
|
|
root.set_tab_title(index, text)
|
|
root.set_tab_icon(index, item_list.get_item_icon(indx))
|
|
|
|
|
|
|
|
class Root extends MarginContainer:
|
|
var _helper : Object = null
|
|
|
|
func _init(helper : Object) -> void:
|
|
_helper = helper
|
|
|
|
func _get_index(x : Mickeytools) -> int:
|
|
var gui : Control = x.get_gui()
|
|
if is_instance_valid(gui):
|
|
var root : Control = x.get_root()
|
|
if root:
|
|
root = root.get_parent()
|
|
if is_instance_valid(root):
|
|
return root.get_index()
|
|
return -1
|
|
|
|
func _fwrd() -> bool:
|
|
if _helper._chaser_enabled:
|
|
return true
|
|
|
|
var tool : Mickeytools = _helper.get_last_tool()
|
|
if !is_instance_valid(tool):
|
|
return false
|
|
|
|
var root : Variant = tool.get_root()
|
|
if !is_instance_valid(root):
|
|
return false
|
|
|
|
if !_helper.HANDLE_BACKWARD_FORWARD_AS_NEXT_BACK_TAB:
|
|
for __ : int in range(0, 2):
|
|
if root == null:
|
|
return false
|
|
elif root.has_method(&"forward_editor"):
|
|
var o : Object = root.call(&"forward_editor")
|
|
if o and o.has_signal(&"focus"):
|
|
o.emit_signal(&"focus", o, false)
|
|
return true
|
|
return false
|
|
root = root.get_parent()
|
|
else:
|
|
var control : TabContainer = root
|
|
var count : int = control.get_tab_count()
|
|
if count > 1:
|
|
var current : int = wrapi(control.current_tab + 1, 0, count)
|
|
if current > -1 and current < control.get_child_count():
|
|
var gui : Node = control.get_child(current)
|
|
for x : Mickeytools in _helper.get_editors():
|
|
var ctrl : Control = x.get_control()
|
|
if gui == ctrl or gui.find_child(ctrl.name):
|
|
x.focus.emit.call_deferred(x)
|
|
return true
|
|
return false
|
|
|
|
func _bkt() -> bool:
|
|
if _helper._chaser_enabled:
|
|
return false
|
|
var tool : Mickeytools = _helper.get_last_tool()
|
|
if !is_instance_valid(tool):
|
|
return false
|
|
|
|
var root : Variant = tool.get_root()
|
|
if !is_instance_valid(root):
|
|
return false
|
|
|
|
if !_helper.HANDLE_BACKWARD_FORWARD_AS_NEXT_BACK_TAB:
|
|
for __ : int in range(0, 2):
|
|
if root == null:
|
|
return false
|
|
elif root.has_method(&"backward_editor"):
|
|
var o : Object = root.call(&"backward_editor")
|
|
if o and o.has_signal(&"focus"):
|
|
o.emit_signal(&"focus", o, false)
|
|
return true
|
|
return false
|
|
root = root.get_parent()
|
|
else:
|
|
var control : TabContainer = root
|
|
var count : int = control.get_tab_count()
|
|
if count > 1:
|
|
var current : int = wrapi(control.current_tab - 1, 0, count)
|
|
if current > -1 and current < control.get_child_count():
|
|
var gui : Node = control.get_child(current)
|
|
for x : Mickeytools in _helper.get_editors():
|
|
var ctrl : Control = x.get_control()
|
|
if gui == ctrl or gui.find_child(ctrl.name):
|
|
x.focus.emit.call_deferred(x)
|
|
return true
|
|
return false
|
|
|
|
func _input(event: InputEvent) -> void:
|
|
if _helper.HANDLE_BACK_FORWARD_BUTTONS:
|
|
if event.is_action_pressed(&"ui_script_spliter_backward"):
|
|
if _bkt() or !_helper.USE_NATIVE_ON_NOT_TABS:
|
|
event.alt_pressed = false
|
|
get_viewport().set_input_as_handled()
|
|
return
|
|
elif event.is_action_pressed(&"ui_script_spliter_forward"):
|
|
if _fwrd() or !_helper.USE_NATIVE_ON_NOT_TABS:
|
|
event.alt_pressed = false
|
|
get_viewport().set_input_as_handled()
|
|
if _helper.is_dd_handled:
|
|
_helper.show_dd(self)
|
|
|
|
class Mickeytools extends Object:
|
|
signal focus(_self : Mickeytools)
|
|
signal tool_updated()
|
|
|
|
var _helper : Object = null
|
|
|
|
var _root : Node = null
|
|
var _parent : Node = null
|
|
var _reference : Node = null
|
|
var _control : Node = null
|
|
var _gui : Node = null
|
|
var _index : int = 0
|
|
var _src : String = ""
|
|
|
|
func set_src(src : String) -> void:
|
|
_src = src
|
|
|
|
func get_src() -> String:
|
|
return _src
|
|
|
|
func get_title_name() -> String:
|
|
if is_instance_valid(_reference):
|
|
if _reference.get_parent() != null:
|
|
return _helper.get_item_text(_src)
|
|
return ""
|
|
|
|
func has_focus() -> bool:
|
|
if is_instance_valid(_reference):
|
|
if _reference.get_parent() != null:
|
|
return _helper.get_selected_item() == _reference.get_index()
|
|
return false
|
|
|
|
func get_gui() -> Node:
|
|
return _gui
|
|
|
|
func is_floating() -> bool:
|
|
return _root and _root.get_parent().owner is Window
|
|
|
|
func grab_focus(should_grab_focus : bool) -> void:
|
|
var root : TabContainer = _root
|
|
if is_instance_valid(root) and is_instance_valid(_control):
|
|
if _control.get_parent() == null:
|
|
return
|
|
var index : int = _control.get_index()
|
|
if !_helper._chaser_enabled:
|
|
for x : Node in root.get_children():
|
|
if x == _control:
|
|
if index > -1 and index < root.get_child_count():
|
|
root.current_tab = index
|
|
break
|
|
|
|
if should_grab_focus:
|
|
if is_instance_valid(_gui) and _gui.is_inside_tree():
|
|
var control : Control = _gui
|
|
if control.focus_mode != Control.FOCUS_NONE:
|
|
control.grab_focus.call_deferred()
|
|
elif _control.focus_mode != Control.FOCUS_NONE:
|
|
_control.grab_focus.call_deferred()
|
|
|
|
if is_instance_valid(_gui):
|
|
var vp : Viewport = _gui.get_viewport()
|
|
if is_instance_valid(vp):
|
|
var wm : Window = vp.get_window()
|
|
if wm and !wm.has_focus():
|
|
wm.grab_focus()
|
|
|
|
func get_origin() -> Node:
|
|
return _parent
|
|
|
|
func get_control() -> Node:
|
|
return _control
|
|
|
|
func get_root() -> Node:
|
|
return _root
|
|
|
|
func get_reference() -> Node:
|
|
return _reference
|
|
|
|
func is_equal(reference : Node) -> bool:
|
|
return _reference == reference
|
|
|
|
func __hey_listen(c : Control, out : Array[CodeEdit]) -> bool:
|
|
if c is CodeEdit and out.size() > 0:
|
|
out[0] = c
|
|
return true
|
|
for x : Node in c.get_children():
|
|
if __hey_listen(x, out):
|
|
return true
|
|
return false
|
|
|
|
func _i_like_coffe() -> void:
|
|
focus.emit(self)
|
|
var tab : TabContainer = _root
|
|
|
|
var parent : Node = tab.get_parent()
|
|
if parent and parent.has_method(&"show_splited_container"):
|
|
parent.call(&"show_splited_container")
|
|
|
|
update()
|
|
_helper.update_queue()
|
|
|
|
func _init(helper : Object, root : Node, control : Control) -> void:
|
|
_helper = helper
|
|
set_root(root)
|
|
set_reference(control)
|
|
|
|
func set_root(root : Node) -> void:
|
|
if root != _root:
|
|
if is_instance_valid(_root):
|
|
if _root.has_method(&"remove_editor"):
|
|
_root.call(&"remove_editor", self)
|
|
_root = root
|
|
|
|
func _context_update(window : Window, control : Control) -> void:
|
|
if is_instance_valid(window) and is_instance_valid(control) and is_instance_valid(_root):
|
|
var root : Viewport= _root.get_viewport()
|
|
var gvp : Vector2 = control.get_global_mouse_position()
|
|
gvp.x += (window.size.x/ 4.0)
|
|
gvp.y = min(gvp.y, root.size.y-window.size.y + 16.0)
|
|
gvp.x = min(gvp.x, root.size.x-window.size.x + 16.0)
|
|
|
|
window.set_deferred(&"position", gvp)
|
|
|
|
|
|
|
|
func _on_input(input : InputEvent) -> void:
|
|
if input is InputEventMouseMotion:
|
|
return
|
|
|
|
if input is InputEventMouseButton:
|
|
if input.pressed and input.button_index == 2:
|
|
if _reference.get_child_count() > 1:
|
|
var variant : Node = _reference.get_child(1)
|
|
if variant is Window and _gui is Control:
|
|
_context_update.call_deferred(variant, _gui)
|
|
|
|
if _helper.can_expand_same_focus():
|
|
var tab : TabContainer = _root
|
|
|
|
var parent : Node = tab.get_parent()
|
|
if parent and parent.has_method(&"show_splited_container"):
|
|
parent.call(&"show_splited_container")
|
|
|
|
func _on_symb(symbol: String, line : int, column: int, edit : CodeEdit = null) -> void:
|
|
const BREAKERS : PackedStringArray = [" ", "\n", "\t"]
|
|
if edit:
|
|
var txt : String = edit.get_text_for_symbol_lookup()
|
|
if !txt.is_empty():
|
|
var pck : PackedStringArray = txt.split('\n')
|
|
if column > -1 and line > -1 and pck.size() > line:
|
|
var cline : String = pck[line]
|
|
while column > -1:
|
|
var _char : String = cline[column]
|
|
if _char in BREAKERS:
|
|
break
|
|
if _char == "@":
|
|
symbol = str("@", symbol)
|
|
break
|
|
column -= 1
|
|
_helper.set_search_symbol(symbol)
|
|
|
|
func set_reference(control : Node) -> void:
|
|
if !is_instance_valid(control):
|
|
return
|
|
if _reference == control:
|
|
return
|
|
elif is_instance_valid(_reference):
|
|
reset()
|
|
|
|
if is_instance_valid(_gui) and _gui.gui_input.is_connected(_on_input):
|
|
_gui.gui_input.disconnect(_on_input)
|
|
|
|
_reference = control
|
|
_control = null
|
|
_gui = null
|
|
|
|
if control is ScriptEditorBase:
|
|
_gui = control.get_base_editor()
|
|
|
|
if _gui is CodeEdit:
|
|
var carets : PackedInt32Array = _gui.get_sorted_carets()
|
|
if carets.size() > 0:
|
|
var sc : ScriptEditor = EditorInterface.get_script_editor()
|
|
if is_instance_valid(sc):
|
|
var line : int = _gui.get_caret_line(0)
|
|
if line > _gui.get_line_count():
|
|
line = _gui.get_line_count() - 1
|
|
if line > -1:
|
|
sc.goto_line(line)
|
|
if !_gui.symbol_lookup.is_connected(_on_symb):
|
|
_gui.symbol_lookup.connect(_on_symb.bind(_gui))
|
|
_control = _gui.get_parent()
|
|
var __parent : Node = _control.get_parent()
|
|
if __parent is VSplitContainer:
|
|
_index = _control.get_index()
|
|
_control = VSplitContainer.new()
|
|
_parent = __parent
|
|
|
|
var childs : Array[Node] = __parent.get_children()
|
|
if __parent.is_inside_tree() and _control.is_inside_tree():
|
|
for x : Node in childs:
|
|
x.reparent(_control)
|
|
else:
|
|
for x : Node in childs:
|
|
_parent.remove_child(x)
|
|
_control.add_child(x)
|
|
else:
|
|
for x : Node in control.get_children():
|
|
if x is RichTextLabel:
|
|
if _reference is CanvasItem:
|
|
var canvas : VBoxContainer = VBoxContainer.new()
|
|
canvas.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
|
canvas.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
|
_root.add_child(canvas)
|
|
canvas.size = _root.size
|
|
|
|
|
|
if canvas.get_child_count() < 1:
|
|
var childs : Array[Node] = _reference.get_children()
|
|
if _reference.is_inside_tree() and canvas.is_inside_tree():
|
|
for n : Node in childs:
|
|
n.reparent(canvas)
|
|
else:
|
|
for n : Node in childs:
|
|
_reference.remove_child(n)
|
|
canvas.add_child(n)
|
|
|
|
x.size = canvas.size
|
|
_gui = canvas
|
|
_control = canvas
|
|
_helper.search_by_symbol(control)
|
|
else:
|
|
_gui = x
|
|
_control = x
|
|
break
|
|
|
|
if _control == null:
|
|
_gui = control
|
|
if control.get_child_count() > 0:
|
|
_gui = control.get_child(0)
|
|
_control = _gui
|
|
|
|
var parent : Node = _control.get_parent()
|
|
if null != parent:
|
|
_parent = parent
|
|
|
|
|
|
if parent != _root:
|
|
if parent != null:
|
|
if !parent.is_inside_tree() or !_root.is_inside_tree():
|
|
parent.remove_child(_control)
|
|
_root.add_child(_control)
|
|
else:
|
|
_control.reparent(_root)
|
|
else:
|
|
_root.add_child(_control)
|
|
if _gui:
|
|
var gui : Control = _gui
|
|
|
|
if gui.focus_mode != Control.FOCUS_NONE:
|
|
if !gui.gui_input.is_connected(_on_input):
|
|
gui.gui_input.connect(_on_input)
|
|
|
|
if gui is VBoxContainer:
|
|
gui = gui.get_child(0)
|
|
if !gui.focus_entered.is_connected(_i_like_coffe):
|
|
gui.focus_entered.connect(_i_like_coffe)
|
|
if !gui.is_node_ready():
|
|
await gui.ready
|
|
if is_instance_valid(gui):
|
|
focus.emit(self)
|
|
tool_updated.emit()
|
|
|
|
func update() -> void:
|
|
if is_instance_valid(_control) and is_instance_valid(_reference):
|
|
var root : TabContainer = _root
|
|
if is_instance_valid(root):
|
|
if _control.get_parent() == root and _reference.get_parent() != null:
|
|
_helper.update_info.call_deferred(root, _control.get_index(), _src)
|
|
|
|
func kill() -> void:
|
|
for x : Node in [_gui, _reference]:
|
|
if is_instance_valid(x) and x.is_queued_for_deletion():
|
|
x.queue_free()
|
|
|
|
func reset(disconnect_signals : bool = true) -> void:
|
|
if is_instance_valid(_gui):
|
|
if disconnect_signals and _gui.is_inside_tree():
|
|
var gui : Control = _gui
|
|
if gui is VBoxContainer:
|
|
gui = gui.get_child(0)
|
|
if gui.focus_entered.is_connected(_i_like_coffe):
|
|
gui.focus_entered.disconnect(_i_like_coffe)
|
|
if gui.gui_input.is_connected(_on_input):
|
|
gui.gui_input.disconnect(_on_input)
|
|
if gui is CodeEdit:
|
|
if gui.symbol_lookup.is_connected(_on_symb):
|
|
gui.symbol_lookup.disconnect(_on_symb)
|
|
_gui.modulate = Color.WHITE
|
|
|
|
if _gui is VBoxContainer:
|
|
if _gui.is_inside_tree() and _reference.is_inside_tree():
|
|
for x : Node in _gui.get_children():
|
|
x.reparent(_reference)
|
|
else:
|
|
var childs : Array[Node] = _gui.get_children()
|
|
for x : Node in childs:
|
|
_gui.remove_child(x)
|
|
_reference.add_child(x)
|
|
if _gui != _control:
|
|
_gui.queue_free()
|
|
_gui = null
|
|
_control.queue_free()
|
|
_control = null
|
|
|
|
if is_instance_valid(_control):
|
|
if is_instance_valid(_parent):
|
|
var parent : Node = _control.get_parent()
|
|
if parent != _parent:
|
|
if _control is VSplitContainer:
|
|
if !_control.is_inside_tree() or !_parent.is_inside_tree():
|
|
var childs : Array[Node] = _control.get_children()
|
|
for c : Node in childs:
|
|
_control.remove_child(c)
|
|
_parent.add_child(c)
|
|
else:
|
|
for c : Node in _control.get_children():
|
|
c.reparent(_parent)
|
|
_control.queue_free()
|
|
else:
|
|
_helper.control_reparent.call_deferred(_index, _control, parent, _parent)
|
|
_gui = null
|
|
_parent = null
|
|
_control = null
|
|
_reference = null
|
|
_index = 0
|
|
|
|
if is_instance_valid(_helper) and !_helper.is_queued_for_deletion():
|
|
if _helper.add_last_script_used.is_valid():
|
|
_helper.add_last_script_used(_src)
|
|
|
|
func control_reparent(_index : int, _control : Object, parent : Object, _parent : Object) -> void:
|
|
if !is_instance_valid(_control):
|
|
return
|
|
|
|
if !is_instance_valid(_parent):
|
|
return
|
|
|
|
if _parent != _control.get_parent():
|
|
if is_instance_valid(parent):
|
|
if _control.is_inside_tree() and _parent.is_inside_tree():
|
|
_control.reparent(_parent)
|
|
else:
|
|
parent.remove_child(_control)
|
|
_parent.add_child(_control)
|
|
else:
|
|
_parent.add_child(_control)
|
|
if _parent.is_inside_tree():
|
|
if _index > -1 and _index < _parent.get_child_count():
|
|
_parent.move_child(_control, _index)
|
|
|
|
class ReTweener extends RefCounted:
|
|
var _tween : Tween = null
|
|
var _ref : Control = null
|
|
var color : Color = Color.MEDIUM_SLATE_BLUE
|
|
|
|
func create_tween(control : Control) -> void:
|
|
if !is_instance_valid(control) or control.is_queued_for_deletion() or !control.is_inside_tree():
|
|
return
|
|
|
|
if _ref == control:
|
|
return
|
|
clear()
|
|
_tween = control.get_tree().create_tween()
|
|
_ref = control
|
|
_tween.tween_method(_callback, color, Color.WHITE, 0.35)
|
|
|
|
func _callback(c : Color) -> void:
|
|
if is_instance_valid(_ref) and _ref.is_inside_tree():
|
|
_ref.modulate = c
|
|
return
|
|
clear()
|
|
|
|
func secure_clear(ref : Object) -> void:
|
|
if !is_instance_valid(_ref) or _ref == ref:
|
|
clear()
|
|
|
|
func clear() -> void:
|
|
if _tween:
|
|
if _tween.is_valid():
|
|
_tween.kill()
|
|
_tween = null
|
|
if is_instance_valid(_ref):
|
|
_ref.modulate = Color.WHITE
|
|
|
|
func _set_focus(tool : Mickeytools, txt : String = "", items : PackedStringArray = [], refresh_history : bool = true) -> void:
|
|
if !is_instance_valid(tool):
|
|
return
|
|
|
|
_last_tool = tool
|
|
if !_chaser_enabled:
|
|
var ctrl : Variant = tool.get_control()
|
|
if is_instance_valid(ctrl) and ctrl.is_inside_tree():
|
|
var root : Control = tool.get_root()
|
|
if root is TabContainer and ctrl.get_parent() == root:
|
|
var indx : int = ctrl.get_index()
|
|
if root.current_tab != indx:
|
|
root.current_tab = indx
|
|
if refresh_history:
|
|
var current : Node = root
|
|
for __ : int in range(0, 2):
|
|
if current == null:
|
|
break
|
|
elif current.has_method(&"add_editor"):
|
|
current.call(&"add_editor", tool, HANDLE_BACK_FORWARD_BUFFER)
|
|
break
|
|
current = current.get_parent()
|
|
|
|
var ref : Node = _last_tool.get_reference()
|
|
if ref.get_parent() == null:
|
|
return
|
|
|
|
var index : int = ref.get_index()
|
|
if index < 0:
|
|
return
|
|
|
|
for x : Node in _editor.get_children():
|
|
if x == ref:
|
|
if index > -1 and is_instance_valid(_item_list):
|
|
if _item_list.item_count > index:
|
|
_item_list.item_selected.emit(index)
|
|
break
|
|
|
|
if _SPLIT_USE_HIGHLIGHT_SELECTED and _code_editors.size() > 1:
|
|
var control : Node = _last_tool.get_gui()
|
|
if is_instance_valid(control) and control.is_inside_tree():
|
|
if _tweener == null:
|
|
_tweener = ReTweener.new()
|
|
_tweener.color = _SPLIT_HIGHLIGHT_COLOR
|
|
_tweener.create_tween(control)
|
|
|
|
var gui : Node = _last_tool.get_gui()
|
|
if is_instance_valid(gui) and should_grab_focus():
|
|
if !_MINIMAP_4_UNFOCUS_WINDOW and _OUT_FOCUS_COLORED:
|
|
for x : Mickeytools in _code_editors:
|
|
if is_instance_valid(x):
|
|
var _gui : Variant = x.get_gui()
|
|
if is_instance_valid(_gui) and _gui is CodeEdit:
|
|
_gui.modulate = _UNFOCUS_COLOR
|
|
_gui.minimap_draw = false
|
|
|
|
if gui is CodeEdit:
|
|
gui.modulate = Color.WHITE
|
|
gui.minimap_draw = true
|
|
|
|
elif !_MINIMAP_4_UNFOCUS_WINDOW:
|
|
for x : Mickeytools in _code_editors:
|
|
if is_instance_valid(x):
|
|
var _gui : Variant = x.get_gui()
|
|
if is_instance_valid(_gui) and _gui is CodeEdit:
|
|
_gui.minimap_draw = false
|
|
if gui is CodeEdit:
|
|
gui.minimap_draw = true
|
|
|
|
elif _OUT_FOCUS_COLORED:
|
|
for x : Mickeytools in _code_editors:
|
|
if is_instance_valid(x):
|
|
var _gui : Variant = x.get_gui()
|
|
if is_instance_valid(gui) and gui is CodeEdit:
|
|
_gui.modulate = _UNFOCUS_COLOR
|
|
if gui is CodeEdit:
|
|
gui.modulate = Color.WHITE
|
|
|
|
var vp : Viewport = gui.get_viewport()
|
|
if is_instance_valid(vp):
|
|
var wm : Window = vp.get_window()
|
|
if wm and !wm.has_focus():
|
|
wm.grab_focus()
|
|
if is_instance_valid(gui) and !gui.has_focus():
|
|
if gui is VBoxContainer:
|
|
gui = gui.get_child(0)
|
|
gui.grab_focus.call_deferred()
|
|
|
|
var item_list : ItemList = _item_list
|
|
if is_instance_valid(item_list):
|
|
_update_path()
|
|
|
|
if txt.length() > 0:
|
|
for x : int in range(item_list.item_count - 1, -1, -1):
|
|
var _txt : String = item_list.get_item_text(x)
|
|
if _txt.is_empty() or _txt.begins_with("@"):
|
|
_txt = item_list.get_item_tooltip(x).get_file()
|
|
if !(_txt in items):
|
|
item_list.remove_item(x)
|
|
item_list.get_parent().get_child(0).set(&"text", txt)
|
|
item_list.queue_redraw()
|
|
|
|
set_deferred(&"_focus_queue", false)
|
|
|
|
func _update_path() -> void:
|
|
if _item_list.item_count == _editor.get_child_count():
|
|
for x : Mickeytools in _code_editors:
|
|
var ref : Control = x.get_reference()
|
|
if is_instance_valid(ref):
|
|
var index : int = ref.get_index()
|
|
if index > -1 and _item_list.item_count > index:
|
|
x.set_src(_item_list.get_item_tooltip(index))
|
|
|
|
func _on_focus(tool : Mickeytools, refresh_history : bool = true) -> void:
|
|
if _focus_queue:
|
|
return
|
|
_focus_queue = true
|
|
|
|
var filesearch : Object = _item_list.get_parent().get_child(0)
|
|
if filesearch is LineEdit:
|
|
var txt : String = filesearch.text
|
|
if !txt.is_empty():
|
|
var items : PackedStringArray = []
|
|
for x : int in _item_list.item_count:
|
|
items.append(_item_list.get_item_text(x))
|
|
filesearch.set(&"text", "")
|
|
_set_focus.call_deferred(tool, txt, items, refresh_history)
|
|
return
|
|
_set_focus(tool, "", [], refresh_history)
|
|
|
|
func _out_it(node : Node, with_signals : bool = false) -> void:
|
|
var has_tween : bool = is_instance_valid(_tweener)
|
|
if has_tween and _code_editors.size() == 0:
|
|
_tweener.clear()
|
|
|
|
for x : int in range(_code_editors.size() - 1, -1 , -1):
|
|
var tool : Mickeytools = _code_editors[x]
|
|
if is_instance_valid(tool):
|
|
if tool.is_equal(node):
|
|
if has_tween:
|
|
_tweener.secure_clear(tool.get_control())
|
|
tool.reset(with_signals)
|
|
tool.free()
|
|
else:
|
|
continue
|
|
_code_editors.remove_at(x)
|
|
|
|
func _grab_focus_by_tab(tb : int) -> void:
|
|
if tb > -1 and tb < _editor.get_child_count():
|
|
var ctrl : Control = _editor.get_child(tb)
|
|
for pop : Window in _pop_scripts:
|
|
var control : Control = pop.get_base_control()
|
|
for m : Mickeytools in _code_editors:
|
|
var gui : Control = m.get_gui()
|
|
if m.get_reference() == ctrl and (control == gui or gui.get_parent()):
|
|
m.focus.emit(m)
|
|
|
|
func _on_tab_change(tb : int = 0) -> void:
|
|
if !_chaser_enabled:
|
|
_grab_focus_by_tab(tb)
|
|
|
|
|
|
process_update_queue(tb)
|
|
|
|
func _setup(editor : TabContainer, setup : bool) -> void:
|
|
const INIT_2 : Array[StringName] = [&"connect", &"disconnect"]
|
|
const INIT_3 : Array[Array] = [[&"tab_changed", &"_on_tab_change"],[&"child_entered_tree", &"_on_it"], [&"child_exiting_tree", &"_out_it"]]
|
|
var _2 : StringName = INIT_2[int(!setup)]
|
|
for _3 : Array in INIT_3:
|
|
var _0 : StringName = _3[0]
|
|
if editor.has_signal(_0):
|
|
var _1 : Callable = Callable.create(self, _3[1])
|
|
if editor.is_connected(_0, _1) != setup:
|
|
editor.call(_2, _0, _1)
|
|
|
|
if setup:
|
|
if !FileAccess.file_exists("res://addons/script_spliter/io/backward_key_button.tres"):
|
|
if DirAccess.dir_exists_absolute("res://addons/script_spliter/io"):
|
|
var input : InputEventKey = InputEventKey.new()
|
|
input.keycode = KEY_LEFT
|
|
input.alt_pressed = true
|
|
input.pressed = true
|
|
ResourceSaver.save(input, "res://addons/script_spliter/io/backward_key_button.tres")
|
|
input = null
|
|
if !FileAccess.file_exists("res://addons/script_spliter/io/forward_key_button.tres"):
|
|
if DirAccess.dir_exists_absolute("res://addons/script_spliter/io"):
|
|
var input : InputEventKey = InputEventKey.new()
|
|
input.keycode = KEY_RIGHT
|
|
input.alt_pressed = true
|
|
input.pressed = true
|
|
ResourceSaver.save(input, "res://addons/script_spliter/io/forward_key_button.tres")
|
|
input = null
|
|
if !FileAccess.file_exists("res://addons/script_spliter/io/backward_mouse_button.tres"):
|
|
if DirAccess.dir_exists_absolute("res://addons/script_spliter/io"):
|
|
var input : InputEventMouseButton = InputEventMouseButton.new()
|
|
input.button_index = MOUSE_BUTTON_XBUTTON1
|
|
input.pressed = true
|
|
ResourceSaver.save(input, "res://addons/script_spliter/io/backward_mouse_button.tres")
|
|
input = null
|
|
if !FileAccess.file_exists("res://addons/script_spliter/io/forward_mouse_button.tres"):
|
|
if DirAccess.dir_exists_absolute("res://addons/script_spliter/io"):
|
|
var input : InputEventMouseButton = InputEventMouseButton.new()
|
|
input.button_index = MOUSE_BUTTON_XBUTTON2
|
|
input.pressed = true
|
|
ResourceSaver.save(input, "res://addons/script_spliter/io/forward_mouse_button.tres")
|
|
input = null
|
|
|
|
if !InputMap.has_action(&"ui_script_spliter_forward"):
|
|
InputMap.add_action(&"ui_script_spliter_forward")
|
|
else:
|
|
InputMap.action_erase_events(&"ui_script_spliter_forward")
|
|
|
|
if FileAccess.file_exists(_HANDLE_FORWARD_KEY_PATH):
|
|
var key_0 : InputEventKey = ResourceLoader.load(_HANDLE_FORWARD_KEY_PATH)
|
|
if key_0 is InputEvent:
|
|
InputMap.action_add_event(&"ui_script_spliter_forward", key_0)
|
|
else:
|
|
printerr("Not type InputEvent: ", key_0)
|
|
else:
|
|
printerr("Not exist file", _HANDLE_FORWARD_KEY_PATH)
|
|
|
|
if FileAccess.file_exists(_HANDLE_FORWARD_MOUSE_BUTTON_PATH):
|
|
var key_1 : Variant = ResourceLoader.load(_HANDLE_FORWARD_MOUSE_BUTTON_PATH)
|
|
if key_1 is InputEvent:
|
|
InputMap.action_add_event(&"ui_script_spliter_forward", key_1)
|
|
else:
|
|
printerr("Not type InputEvent: ", key_1)
|
|
else:
|
|
printerr("Not exist file", _HANDLE_FORWARD_MOUSE_BUTTON_PATH)
|
|
|
|
if !InputMap.has_action(&"ui_script_spliter_backward"):
|
|
InputMap.add_action(&"ui_script_spliter_backward")
|
|
else:
|
|
InputMap.action_erase_events(&"ui_script_spliter_backward")
|
|
|
|
if FileAccess.file_exists(_HANDLE_BACKWARD_KEY_PATH):
|
|
var key_0 : Variant = ResourceLoader.load(_HANDLE_BACKWARD_KEY_PATH)
|
|
if key_0 is InputEvent:
|
|
InputMap.action_add_event(&"ui_script_spliter_backward", key_0)
|
|
else:
|
|
printerr("Not type InputEvent: ", key_0)
|
|
else:
|
|
printerr("Not exist file", _HANDLE_BACKWARD_KEY_PATH)
|
|
|
|
if FileAccess.file_exists(_HANDLE_BACKWARD_MOUSE_BUTTON_PATH):
|
|
var key_1 : InputEventMouseButton = ResourceLoader.load(_HANDLE_BACKWARD_MOUSE_BUTTON_PATH)
|
|
if key_1 is InputEvent:
|
|
InputMap.action_add_event(&"ui_script_spliter_backward", key_1)
|
|
else:
|
|
printerr("Not type InputEvent: ", key_1)
|
|
else:
|
|
printerr("Not exist file", _HANDLE_BACKWARD_MOUSE_BUTTON_PATH)
|
|
|
|
func _on_sub_change(__ : int, tab : TabContainer) -> void:
|
|
if _chaser_enabled:
|
|
return
|
|
var _tab : int = tab.current_tab
|
|
if _tab > -1 and _tab < tab.get_child_count():
|
|
var control : Control = tab.get_child(_tab)
|
|
|
|
for x : Mickeytools in _code_editors:
|
|
if is_instance_valid(x):
|
|
var ctrl : Variant = x.get_control()
|
|
if is_instance_valid(ctrl):
|
|
if ctrl == control:
|
|
x.focus.emit(x)
|
|
return
|
|
|
|
func _on_tab_rmb(itab : int, tab : TabContainer) -> void:
|
|
if tab.get_child_count() > itab and itab > -1:
|
|
if is_instance_valid(_item_list):
|
|
var ref : Node = tab.get_child(itab)
|
|
for x : Mickeytools in _code_editors:
|
|
if x.get_control() == ref:
|
|
for e : Node in _editor.get_children():
|
|
if e == x.get_reference() and e.get_parent() != null:
|
|
var i : int = e.get_index()
|
|
if i > -1 and i < _item_list.item_count:
|
|
_item_list.item_clicked.emit(i, _item_list.get_local_mouse_position(), MOUSE_BUTTON_RIGHT)
|
|
return
|
|
break
|
|
|
|
func _on_close(itab : int, tab : TabContainer) -> void:
|
|
if tab.get_child_count() > itab and itab > -1:
|
|
if is_instance_valid(_item_list):
|
|
var ref : Node = tab.get_child(itab)
|
|
for x : Mickeytools in _code_editors:
|
|
if x.get_control() == ref:
|
|
for e : Node in _editor.get_children():
|
|
if e == x.get_reference():
|
|
remove_tool(x)
|
|
var i : int = e.get_index()
|
|
if i > -1 and i < _item_list.item_count:
|
|
_item_list.item_clicked.emit(i, _item_list.get_local_mouse_position(), MOUSE_BUTTON_MIDDLE)
|
|
return
|
|
break
|
|
|
|
func _on_enter(n : Node, tab : TabContainer) -> void:
|
|
var root : Node = n.get_parent()
|
|
for x : Mickeytools in _code_editors:
|
|
if x.get_root() == root:
|
|
x.update.call_deferred()
|
|
break
|
|
var _v : bool = tab.get_child_count() > 0
|
|
if tab.visible != _v:
|
|
tab.visible = _v
|
|
|
|
func _on_exit(n : Node, tab : TabContainer) -> void:
|
|
var _v : bool = tab.get_child_count() > 1 or (tab.get_child_count() > 0 and tab.get_child(0) != n)
|
|
if tab.visible != _v:
|
|
tab.visible = _v
|
|
if !is_queued_for_deletion():
|
|
process_update_queue()
|
|
|
|
func _get_root() -> Control:
|
|
var margin : Root = Root.new(self)
|
|
margin.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
margin.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
|
|
|
var texture : TextureRect = TextureRect.new()
|
|
texture.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
texture.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
|
texture.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
|
texture.stretch_mode = TextureRect.STRETCH_KEEP_CENTERED
|
|
texture.texture = preload("res://addons/script_spliter/assets/github_CodeNameTwister.png")
|
|
texture.self_modulate.a = 0.25
|
|
|
|
margin.add_child(texture)
|
|
return margin
|
|
|
|
func _get_container() -> Control:
|
|
var editor : EditorContainer = EditorContainer.new()
|
|
editor.separator_line_size = 4.0
|
|
editor.drag_button_size = 12.0
|
|
editor.behaviour_can_expand_focus_same_container = true
|
|
return editor
|
|
|
|
func _out_drag(e : Control) -> void:
|
|
var current : Control = null
|
|
|
|
is_dd_handled = false
|
|
_last_dd_root = null
|
|
if is_instance_valid(_ddo):
|
|
_ddo.visible = false
|
|
var np : Node = _ddo.get_parent()
|
|
if is_instance_valid(np):
|
|
current = np
|
|
np.remove_child(_ddo)
|
|
if is_instance_valid(current):
|
|
if current.get_global_rect().has_point(current.get_global_mouse_position()):
|
|
if e is TabBar:
|
|
var ct : int = e.current_tab
|
|
var p : Node = e.get_parent()
|
|
if p and ct < p.get_child_count():
|
|
var gui : Node = p.get_child(ct)
|
|
|
|
var root : Node = null
|
|
for x : Mickeytools in _code_editors:
|
|
var __root : Node = x.get_root()
|
|
if is_instance_valid(_root) and __root.get_parent() == current:
|
|
root = __root
|
|
break
|
|
|
|
if is_instance_valid(root):
|
|
for x : Mickeytools in _code_editors:
|
|
if x.get_control() == gui or x.get_gui() == gui:
|
|
if root != x.get_root():
|
|
queue_swap(x, root)
|
|
return
|
|
elif e is ItemList:
|
|
var it : PackedInt32Array = e.get_selected_items()
|
|
if it.size() > 0:
|
|
var src : String = e.get_item_tooltip(it[0])
|
|
var root : Node = null
|
|
for x : Mickeytools in _code_editors:
|
|
var __root : Node = x.get_root()
|
|
if is_instance_valid(_root) and __root.get_parent() == current:
|
|
root = __root
|
|
break
|
|
|
|
if is_instance_valid(root):
|
|
for x : Mickeytools in _code_editors:
|
|
if x.get_src() == src:
|
|
if root != x.get_root():
|
|
queue_swap(x, root)
|
|
return
|
|
|
|
|
|
func queue_swap(x : Mickeytools, root : Node) -> void:
|
|
if is_instance_valid(x):
|
|
var ref : Node = x.get_reference()
|
|
if is_instance_valid(ref) and is_instance_valid(root):
|
|
remove_tool(x)
|
|
create_code_editor.call_deferred(root, ref)
|
|
_new_tools.call_deferred(_code_editors.duplicate(false))
|
|
|
|
|
|
func _new_tools(tools : Array[Mickeytools]) -> void:
|
|
var tool : Mickeytools = null
|
|
for x in _code_editors:
|
|
if x in tools:
|
|
continue
|
|
tool = x
|
|
break
|
|
if tool:
|
|
tool.focus.emit.call_deferred(tool)
|
|
await Engine.get_main_loop().process_frame
|
|
if is_instance_valid(tool):
|
|
tool.update()
|
|
|
|
func _on_drag(e : Control) -> void:
|
|
is_dd_handled = is_instance_valid(e)
|
|
if !is_dd_handled:
|
|
_last_dd_root = null
|
|
if is_instance_valid(_ddo):
|
|
_ddo.visible = false
|
|
var np : Node = _ddo.get_parent()
|
|
if np:
|
|
np.remove_child(_ddo)
|
|
|
|
func _get_container_edit() -> Control:
|
|
var rtab : DD = DD.new()
|
|
|
|
rtab.get_tab_bar().tab_close_display_policy = TabBar.CLOSE_BUTTON_SHOW_ALWAYS
|
|
|
|
rtab.drag_to_rearrange_enabled = true
|
|
|
|
|
|
rtab.child_entered_tree.connect(_on_enter.bind(rtab))
|
|
rtab.child_exiting_tree.connect(_on_exit.bind(rtab))
|
|
|
|
rtab.visible = false
|
|
|
|
var rcall : Callable = _on_sub_change.bind(rtab)
|
|
|
|
rtab.tab_changed.connect(rcall)
|
|
rtab.tab_clicked.connect(rcall)
|
|
rtab.get_tab_bar().tab_close_pressed.connect(_on_close.bind(rtab))
|
|
rtab.get_tab_bar().select_with_rmb = true
|
|
rtab.get_tab_bar().tab_rmb_clicked.connect(_on_tab_rmb.bind(rtab))
|
|
|
|
rtab.on_dragging.connect(_on_drag)
|
|
rtab.out_dragging.connect(_out_drag)
|
|
|
|
rtab.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
rtab.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
|
|
|
return rtab
|
|
|
|
func _create_by_last_used() -> void:
|
|
if _lifo_src.size() > 0:
|
|
var item_list : ItemList = _item_list
|
|
if is_instance_valid(item_list):
|
|
var unused : Array[Node] = []
|
|
if _item_list.item_count == _editor.get_child_count():
|
|
for x : Node in _main.get_children():
|
|
if is_instance_valid(x):
|
|
if x is TabContainer and x.get_child_count() == 0:
|
|
unused.append(x)
|
|
else:
|
|
for y : Node in x.get_children():
|
|
if y is TabContainer and y.get_child_count() == 0:
|
|
unused.append(y)
|
|
for u : Node in unused:
|
|
var sc : String = get_last_script_used()
|
|
var dirty : bool = false
|
|
if sc.is_empty():
|
|
continue
|
|
|
|
for x : int in _item_list.item_count:
|
|
if _item_list.get_item_tooltip(x) == sc:
|
|
create_code_editor(u, _editor.get_child(x))
|
|
dirty = true
|
|
break
|
|
if !dirty and sc.begins_with("res://") and FileAccess.file_exists(sc):
|
|
if _SHOULD_OPEN_CLOSED_EDITOR_SCRIPT:
|
|
var res : Variant = ResourceLoader.load(sc)
|
|
if res is Script:
|
|
EditorInterface.edit_script.call_deferred(res)
|
|
|
|
func update() -> void:
|
|
if is_queued_for_deletion() or !_plugin.is_inside_tree():
|
|
return
|
|
|
|
_clear()
|
|
if _editor.get_child_count() > 0:
|
|
var root : Node = _get_editor_root()
|
|
if null != root and _editor.current_tab > -1:
|
|
create_code_editor(root, _editor.get_current_tab_control())
|
|
|
|
_create_by_last_used()
|
|
|
|
for x : Node in _main.get_children():
|
|
if is_instance_valid(x):
|
|
if x is TabContainer and x.get_child_count() == 0:
|
|
for z : Node in _editor.get_children():
|
|
if null != create_code_editor(x, z):
|
|
break
|
|
else:
|
|
for y : Node in x.get_children():
|
|
if y is TabContainer and y.get_child_count() == 0:
|
|
for z : Node in _editor.get_children():
|
|
if null != create_code_editor(y, z):
|
|
break
|
|
|
|
if !is_instance_valid(_last_tool) or _last_tool.is_queued_for_deletion():
|
|
for i : int in range(_code_editors.size() - 1, -1, -1):
|
|
if is_instance_valid(_code_editors[i]):
|
|
_last_tool = _code_editors[i]
|
|
_last_tool.focus.emit.call_deferred(_last_tool)
|
|
break
|
|
_code_editors.remove_at(i)
|
|
|
|
if _pop_scripts.size() > 0:
|
|
for p : Window in _pop_scripts:
|
|
if !p.visible:
|
|
p.show()
|
|
|
|
if _pop_script_placeholder:
|
|
for x : Mickeytools in _code_editors:
|
|
if !x.is_floating():
|
|
var ref : Node = x.get_reference()
|
|
if ref.get_parent() != null:
|
|
if get_item_text(x.get_src()).begins_with(_POP_SCRIPT_PLACEHOLDER):
|
|
continue
|
|
_clear_placeholder()
|
|
else:
|
|
_clear_placeholder()
|
|
|
|
func _clear_placeholder() -> void:
|
|
if _pop_script_placeholder:
|
|
for x : int in range(_item_list.item_count):
|
|
var txt : String = _item_list.get_item_text(x)
|
|
if txt.is_empty() or txt.begins_with("@"):
|
|
txt = _item_list.get_item_tooltip(x).get_file()
|
|
if txt.begins_with(_POP_SCRIPT_PLACEHOLDER):
|
|
_item_list.item_clicked.emit(x, _item_list.get_local_mouse_position(), MOUSE_BUTTON_MIDDLE)
|
|
break
|
|
_pop_script_placeholder = false
|
|
|
|
|
|
|
|
func is_visible_minimap_required() -> bool:
|
|
return _MINIMAP_4_UNFOCUS_WINDOW
|
|
|
|
func get_item_text(src : String) -> String:
|
|
var item_list : Control = _item_list
|
|
var text : String = ""
|
|
if !src.is_empty():
|
|
if is_instance_valid(item_list):
|
|
var indx : int = -1
|
|
for x : int in item_list.item_count:
|
|
if item_list.get_item_tooltip(x) == src:
|
|
indx = x
|
|
break
|
|
if indx > -1:
|
|
text = item_list.get_item_text(indx)
|
|
if text.is_empty() or text.begins_with("@"):
|
|
text = item_list.get_item_tooltip(indx).get_file()
|
|
text = text.trim_suffix("(*)")
|
|
return text
|
|
|
|
func get_aviable() -> Node:
|
|
for x : Node in _main.get_children():
|
|
if x is TabContainer and x.get_child_count() == 0:
|
|
return x
|
|
for y : Node in x.get_children():
|
|
if y is TabContainer and y.get_child_count() == 0:
|
|
return y
|
|
return null
|
|
|
|
func is_node_valid(root : Node) -> bool:
|
|
return is_instance_valid(root) and root.is_inside_tree()
|
|
|
|
func is_valid_code_editor(root : Node, editor : Node, fallback : bool = true) -> bool:
|
|
if !is_node_valid(root) or !is_node_valid(editor):
|
|
return false
|
|
|
|
if !editor.is_node_ready():
|
|
return false
|
|
|
|
if editor.get_child_count() == 0:
|
|
if fallback and editor.is_inside_tree():
|
|
var index : int = editor.get_index()
|
|
if index > -1 and _item_list.item_count > index:
|
|
_item_list.item_selected.emit(index)
|
|
return is_valid_code_editor(root, editor, false)
|
|
return false
|
|
|
|
return true
|
|
|
|
|
|
func is_valid_doc(editor : Control) -> bool:
|
|
if !editor is ScriptEditorBase:
|
|
for x : Node in editor.get_children():
|
|
if x is RichTextLabel:
|
|
return true
|
|
return false
|
|
|
|
func add_tool(tool : Mickeytools) -> void:
|
|
_code_editors.append(tool)
|
|
tool_added.emit(tool)
|
|
|
|
func remove_tool(x : Mickeytools, with_signals : bool = true) -> void:
|
|
x.reset(with_signals)
|
|
_code_editors.erase(x)
|
|
x.free()
|
|
|
|
func create_code_editor(root : Node, editor : Node) -> Mickeytools:
|
|
if !is_valid_code_editor(root, editor):
|
|
return null
|
|
|
|
var tool : Mickeytools = null
|
|
|
|
if root.get_child_count() > 0:
|
|
var childs : Array[Node] = root.get_children()
|
|
for m : Mickeytools in _code_editors:
|
|
if m.get_reference() == editor:
|
|
var o : Node = m.get_control()
|
|
if o in childs or m.get_gui() in childs:
|
|
return null
|
|
else:
|
|
for m : Mickeytools in _code_editors:
|
|
if m.get_reference() == editor:
|
|
var o : Node = m.get_control()
|
|
var __root : Control = m.get_root()
|
|
if is_instance_valid(__root) and __root.get_child_count() > 1:
|
|
if __root and __root.current_tab != o.get_index():
|
|
tool = m
|
|
break
|
|
|
|
if is_valid_doc(editor):
|
|
if editor.name.begins_with("@"):
|
|
return
|
|
|
|
if null == tool:
|
|
for x : Mickeytools in _code_editors:
|
|
if x.is_equal(editor):
|
|
return null
|
|
tool = Mickeytools.new(self, root, editor)
|
|
tool.focus.connect(_on_focus)
|
|
add_tool(tool)
|
|
|
|
tool.focus.emit(tool)
|
|
else:
|
|
tool.reset()
|
|
tool.set_root(root)
|
|
tool.set_reference(editor)
|
|
|
|
if _last_tool == null:
|
|
_last_tool = tool
|
|
tool.focus.emit(tool)
|
|
tool.update.call_deferred()
|
|
return tool
|
|
|
|
func update_queue(__ : int = 0) -> void:
|
|
if _plugin:
|
|
_plugin.set_process(true)
|
|
if _main and _container:
|
|
update_rect()
|
|
_main.update()
|
|
|
|
#region callback
|
|
func _on_it(editor : Node) -> void:
|
|
if is_valid_doc(editor):
|
|
if editor.name.begins_with("@"):
|
|
editor.queue_free()
|
|
return
|
|
update_queue(0)
|
|
update()
|
|
|
|
func _on_container_entered() -> void:
|
|
update_queue()
|
|
|
|
func _on_container_exit() -> void:
|
|
for x : Mickeytools in _code_editors:
|
|
x.reset()
|
|
if !is_queued_for_deletion():
|
|
process_update_queue()
|
|
#endregion
|
|
|
|
func remove_split(node : Node) -> void:
|
|
if _code_editors.size() > 1:
|
|
if node is CodeEdit:
|
|
for it : int in range(_code_editors.size() - 1, -1, -1):
|
|
var x : Mickeytools = _code_editors[it]
|
|
if x.get_gui() == node:
|
|
_remove_split_by_control(x.get_control())
|
|
|
|
remove_tool(x)
|
|
|
|
process_update_queue()
|
|
break
|
|
|
|
func _remove_split_by_control(c : Control) -> void:
|
|
for x : Node in _main.get_children():
|
|
if x is TabContainer:continue
|
|
if x.get_child_count() > 0:
|
|
for y : Node in x.get_children():
|
|
for z : Node in y.get_children():
|
|
if z == c:
|
|
_main.remove_child(x)
|
|
return
|
|
|
|
func _get_unused_editor_control() -> Array[Node]:
|
|
var out : Array[Node] = []
|
|
for x : Node in _editor.get_children():
|
|
var exist : bool = false
|
|
for m : Mickeytools in _code_editors:
|
|
if !is_instance_valid(m):
|
|
_code_editors.erase(m)
|
|
continue
|
|
if m.is_equal(x):
|
|
exist = true
|
|
break
|
|
if !exist:
|
|
out.append(x)
|
|
return out
|
|
|
|
func _free_editor_container(control : Control) -> bool:
|
|
if control.get_parent() == _main:
|
|
for x : int in range(_code_editors.size() - 1, -1 , -1):
|
|
var c : Mickeytools = _code_editors[x]
|
|
var cc : Variant = c.get_control()
|
|
if is_instance_valid(cc):
|
|
var _a : Node = cc.get_parent()
|
|
var _b : Node = control
|
|
if _a == _b or _a.get_parent() == _b:
|
|
remove_tool(c)
|
|
else:
|
|
remove_tool(c)
|
|
_main.remove_child(control)
|
|
control.queue_free()
|
|
return true
|
|
return false
|
|
|
|
func build(editor : TabContainer, columns : int = 0, rows : int = 0) -> void:
|
|
_setup(editor, true)
|
|
|
|
var root : Node = editor.get_parent()
|
|
if is_instance_valid(root) and !(root is Root):
|
|
_root = root
|
|
|
|
if is_instance_valid(_editor) and _editor != editor:
|
|
if _editor.tree_entered.is_connected(_on_container_entered):
|
|
_editor.tree_entered.disconnect(_on_container_entered)
|
|
|
|
if _editor.tree_exiting.is_connected(_on_container_exit):
|
|
_editor.tree_exiting.disconnect(_on_container_exit)
|
|
|
|
_editor = editor
|
|
|
|
if !_editor.tree_entered.is_connected(_on_container_entered):
|
|
_editor.tree_entered.connect(_on_container_entered)
|
|
|
|
if !_editor.tree_exiting.is_connected(_on_container_exit):
|
|
_editor.tree_exiting.connect(_on_container_exit)
|
|
|
|
if !is_instance_valid(_container):
|
|
_container = _get_root()
|
|
|
|
if !is_instance_valid(_main):
|
|
_main = _get_container()
|
|
|
|
root = _container.get_parent()
|
|
|
|
if root != _root:
|
|
if is_instance_valid(root):
|
|
root.remove_child(_container)
|
|
var index : int = _editor.get_index()
|
|
_root.add_child(_container)
|
|
_root.move_child(_container, index)
|
|
|
|
root = _main.get_parent()
|
|
if root != _container:
|
|
if is_instance_valid(root):
|
|
root.remove_child(_main)
|
|
_container.add_child(_main)
|
|
|
|
_container.size = _container.get_parent().size
|
|
_container.anchor_left = 0.0
|
|
_container.anchor_top = 0.0
|
|
_container.anchor_right = 1.0
|
|
_container.anchor_bottom = 1.0
|
|
|
|
_main.behaviour_expand_on_focus = true
|
|
_main.behaviour_expand_on_double_click = true
|
|
|
|
|
|
_editor.visible = false
|
|
_main.visible = true
|
|
|
|
update_config()
|
|
|
|
update_build(columns, rows)
|
|
|
|
if (_root is Control):
|
|
if !_root.item_rect_changed.is_connected(update_rect):
|
|
_root.item_rect_changed.connect(update_rect)
|
|
update_rect.call_deferred()
|
|
|
|
func update_rect() -> void:
|
|
var _size : Vector2 = _container.size
|
|
_size.x = maxf(_container.size.x, 1.0)
|
|
_size.y = maxf(_container.size.y, 1.0)
|
|
_main.size = _size
|
|
for x : Node in _main.get_children():
|
|
if x is Control:
|
|
if x is TabContainer:
|
|
continue
|
|
for y : Node in x.get_children():
|
|
if y is Control:
|
|
y.set_deferred(&"size", x.size)
|
|
_main.update()
|
|
|
|
func find_editor(node : Node) -> Control:
|
|
for x : Node in _main.get_children():
|
|
for y : Node in x.get_children():
|
|
if y == node:
|
|
return x
|
|
return null
|
|
|
|
func can_remove_split(node : Node) -> bool:
|
|
if !is_instance_valid(_main):
|
|
return false
|
|
|
|
if node == null:
|
|
return _code_editors.size() > 1
|
|
|
|
if _code_editors.size() > 1:
|
|
if node is CodeEdit:
|
|
var main : bool = false
|
|
for x : Mickeytools in _code_editors:
|
|
if x.is_floating():
|
|
continue
|
|
var item_list : Node = _item_list
|
|
if item_list:
|
|
var reference : Node = x.get_reference()
|
|
if reference.get_parent() != null:
|
|
if get_control_item_name(reference.get_index()).begins_with(_POP_SCRIPT_PLACEHOLDER):
|
|
continue
|
|
if main:
|
|
return true
|
|
main = true
|
|
return false
|
|
|
|
func get_control_item_name(index : int) -> String:
|
|
var item_list : Node = _item_list
|
|
if item_list:
|
|
if index > -1 and index < item_list.item_count:
|
|
var text : String = item_list.get_item_text(index)
|
|
if text.is_empty() or text.begins_with("@"):
|
|
text = item_list.get_item_tooltip(index).get_file()
|
|
return text
|
|
return ""
|
|
|
|
|
|
func get_editor_item_text(c : int) -> String:
|
|
var item_list : Control = _item_list
|
|
var text : String = ""
|
|
if c > -1:
|
|
if is_instance_valid(item_list):
|
|
if null != item_list and c < _editor.get_child_count() and item_list.item_count > c:
|
|
text = item_list.get_item_text(c)
|
|
if text.is_empty() or text.begins_with("@"):
|
|
text = item_list.get_item_tooltip(c).get_file()
|
|
text = text.trim_suffix("(*)")
|
|
return text
|
|
|
|
func can_add_split(_node : Node) -> bool:
|
|
if !is_instance_valid(_main):
|
|
return false
|
|
|
|
if _node == null:
|
|
return _code_editors.size() < _editor.get_child_count()
|
|
|
|
for o : int in _editor.get_child_count():
|
|
if get_editor_item_text(o).begins_with(_POP_SCRIPT_PLACEHOLDER):
|
|
continue
|
|
var x : Node = _editor.get_child(o)
|
|
var created : bool = false
|
|
if x.has_method(&"get_base_editor"):
|
|
x = x.call(&"get_base_editor")
|
|
for m : Mickeytools in _code_editors:
|
|
if m.get_gui() == x:
|
|
created = true
|
|
break
|
|
else:
|
|
if x.get_child_count() > 0:
|
|
var child : Node = x.get_child(0)
|
|
for m : Mickeytools in _code_editors:
|
|
var gui : Node = m.get_gui()
|
|
if gui == x or child == gui:
|
|
created = true
|
|
break
|
|
else:
|
|
for m : Mickeytools in _code_editors:
|
|
var gui : Node = m.get_gui()
|
|
if gui == x :
|
|
created = true
|
|
break
|
|
if !created:
|
|
return true
|
|
return false
|
|
|
|
func add_split(control : Node) -> void:
|
|
var unused : Array[Node] = _get_unused_editor_control()
|
|
if unused.size() == 0:
|
|
print("[INFO] Not aviable split!")
|
|
return
|
|
|
|
var current_unused : Node = control
|
|
|
|
for x : Mickeytools in _code_editors:
|
|
if x.is_equal(control) or x.get_gui() == control:
|
|
current_unused = null
|
|
break
|
|
|
|
var root : Control = get_aviable()
|
|
if root == null:
|
|
var broot : Node = _main.make_split_container_item()
|
|
root = _get_container_edit()
|
|
broot.add_child(root)
|
|
_main.add_child(broot)
|
|
|
|
if null == current_unused:
|
|
current_unused = unused[0]
|
|
|
|
_create_by_last_used()
|
|
if root.get_child_count() == 0:
|
|
create_code_editor(root, current_unused)
|
|
|
|
process_update_queue()
|
|
|
|
func get_current_columns_and_rows() -> Array[int]:
|
|
var out : Array[int] = [0, 0]
|
|
if is_instance_valid(_main):
|
|
var columns : int = _main.max_columns
|
|
var container : int = _main.get_child_count()
|
|
if container > 0 and columns > 0:
|
|
@warning_ignore("integer_division")
|
|
container = int(container / columns)
|
|
out[0] = columns
|
|
out[1] = container
|
|
return out
|
|
|
|
func update_build(columns : int, rows : int) -> void:
|
|
for x : Node in _main.get_children():
|
|
if x is EditorContainer:
|
|
for y in x.get_children():
|
|
if y.has_method(&"reset"):
|
|
y.call(&"reset")
|
|
_out_drag(null)
|
|
|
|
current_columns = maxi(columns, 0)
|
|
current_rows = maxi(rows, 0)
|
|
|
|
var totals : int = maxi(current_columns * current_rows, 1)
|
|
_main.max_columns = current_columns
|
|
|
|
while _main.get_child_count() > totals:
|
|
if !_free_editor_container(_main.get_child(_main.get_child_count() - 1)):
|
|
break
|
|
|
|
while _main.get_child_count() < totals:
|
|
var broot : Node = _main.make_split_container_item()
|
|
var root : Node = _get_container_edit()
|
|
broot.add_child(root)
|
|
_main.add_child(broot)
|
|
|
|
var aviable : Node = get_aviable()
|
|
if aviable:
|
|
if _lifo_src.size() > 0:
|
|
_create_by_last_used()
|
|
aviable = get_aviable()
|
|
while aviable != null:
|
|
var unused : Array[Node] = _get_unused_editor_control()
|
|
if unused.size() == 0:
|
|
break
|
|
if null == create_code_editor(aviable, unused[0]):
|
|
break
|
|
aviable = get_aviable()
|
|
|
|
process_update_queue()
|
|
|
|
|
|
#region _CHASER_
|
|
func get_current_focus_index() -> int:
|
|
var arr : PackedInt32Array = _item_list.get_selected_items()
|
|
if arr.size() > 0:
|
|
return arr[0]
|
|
return 0
|
|
|
|
func focus_by_index(index : int, check_is_visible : bool = true) -> int:
|
|
if _code_editors.size() > index:
|
|
if check_is_visible:
|
|
while _code_editors.size() > index:
|
|
var cd : Mickeytools = _code_editors[index]
|
|
if cd != _last_tool:
|
|
var variant : Variant = cd.get_control()
|
|
if is_instance_valid(variant):
|
|
if variant is Control:
|
|
var parent : Node = variant.get_parent()
|
|
if parent is TabContainer:
|
|
if parent.get_current_tab_control() == variant:
|
|
_on_focus(cd)
|
|
return index
|
|
index += 1
|
|
else:
|
|
var cd : Mickeytools = _code_editors[index]
|
|
var variant : Variant = cd.get_control()
|
|
if is_instance_valid(variant):
|
|
if variant is Control:
|
|
var parent : Node = variant.get_parent()
|
|
if parent is TabContainer:
|
|
if parent.get_current_tab_control() == variant:
|
|
_on_focus(cd)
|
|
return index
|
|
return -1
|
|
|
|
func get_focus_config() -> Dictionary:
|
|
return {
|
|
"highlight_selected" : _SPLIT_USE_HIGHLIGHT_SELECTED
|
|
,"behaviour_expand_on_focus" : _main.behaviour_expand_on_focus
|
|
,"last_tool" : _last_tool
|
|
}
|
|
|
|
func set_focus_config(d : Dictionary) -> void:
|
|
_chaser_enabled = false
|
|
_SPLIT_USE_HIGHLIGHT_SELECTED = d["highlight_selected"]
|
|
_main.behaviour_expand_on_focus = d["behaviour_expand_on_focus"]
|
|
|
|
var _last : Variant = d["last_tool"]
|
|
if is_instance_valid(_last):
|
|
if _last != _last_local_tool:
|
|
_last.focus.emit(_last)
|
|
|
|
func enable_focus_highlight(enable : bool) -> void:
|
|
_chaser_enabled = !enable
|
|
_SPLIT_USE_HIGHLIGHT_SELECTED = enable
|
|
_main.behaviour_expand_on_focus = enable
|
|
|
|
func should_grab_focus() -> bool:
|
|
return !_chaser_enabled
|
|
#endregion
|
|
|
|
#region _POP_SCRIPT_
|
|
func _on_pop_input(event : InputEvent) -> void:
|
|
(_editor.get_parent() as Control).gui_input.emit(event)
|
|
|
|
func is_pop_script(ctrl : Node) -> bool:
|
|
for pop : Node in _pop_scripts:
|
|
var control : Control = pop.get_base_control()
|
|
if ctrl is CodeEdit:
|
|
for __ : int in range(2):
|
|
ctrl = ctrl.get_parent()
|
|
if ctrl == null:
|
|
return false
|
|
for x : Node in control.get_children():
|
|
if x == ctrl:
|
|
return true
|
|
return false
|
|
|
|
func _on_pop_script_close(pop : Window) -> void:
|
|
if !is_instance_valid(pop) or pop.is_queued_for_deletion():
|
|
return
|
|
var container : Node = pop.get_base_control()
|
|
for x : Mickeytools in _code_editors:
|
|
var gui : Node = x.get_gui()
|
|
var control : Node = x.get_control()
|
|
if control.get_parent() == container or gui.get_parent() == container:
|
|
remove_tool(x, true)
|
|
|
|
if container.get_child_count() < 1:
|
|
_pop_scripts.erase(pop)
|
|
if !pop.is_queued_for_deletion():
|
|
pop.queue_free()
|
|
update_queue()
|
|
return
|
|
push_warning("Can not free popscript!")
|
|
|
|
func make_pop_script(control : Node) -> Window:
|
|
if control is CodeEdit:
|
|
for __ : int in range(2):
|
|
control = control.get_parent()
|
|
if control == null:
|
|
return null
|
|
var m : Mickeytools = null
|
|
for x : Mickeytools in _code_editors:
|
|
if x.get_control() == control:
|
|
m = x
|
|
break
|
|
|
|
if m == null:
|
|
return null
|
|
|
|
var node : Node = FLYING_SCRIPT.instantiate()
|
|
node.set_base_control(_get_container_edit())
|
|
|
|
var editor : Control = m.get_reference()
|
|
remove_tool(m)
|
|
|
|
_plugin.add_child(node)
|
|
|
|
var tool : Mickeytools = create_code_editor(node.get_base_control(), editor)
|
|
if null == tool:
|
|
if !node.is_inside_tree():
|
|
node.free()
|
|
else:
|
|
node.queue_free()
|
|
return null
|
|
|
|
node.proxy = editor
|
|
node.controller = tool
|
|
|
|
node.on_close.connect(_on_pop_script_close)
|
|
|
|
_pop_scripts.append(node)
|
|
|
|
_check_pop()
|
|
return node
|
|
|
|
func _check_pop() -> void:
|
|
if !_pop_script_placeholder:
|
|
var placeholder : bool = true
|
|
var total_floatings : int = 0
|
|
for x : Mickeytools in _code_editors:
|
|
if !x.is_floating():
|
|
placeholder = false
|
|
break
|
|
total_floatings += 1
|
|
if placeholder and _editor.get_child_count() <= total_floatings:
|
|
_pop_script_placeholder = true
|
|
var PLACEHOLDER : String = str("res://addons/script_spliter/context/",_POP_SCRIPT_PLACEHOLDER, ".gd")
|
|
if FileAccess.file_exists(PLACEHOLDER):
|
|
var script : Script = ResourceLoader.load(PLACEHOLDER)
|
|
if null != script:
|
|
_editor.child_entered_tree.connect(_on_placeholder, CONNECT_ONE_SHOT)
|
|
EditorInterface.edit_script(script)
|
|
|
|
func _placeholder_queue() -> void:
|
|
for x : int in _editor.get_child_count():
|
|
var txt : String = get_editor_item_text(x)
|
|
if txt.begins_with(_POP_SCRIPT_PLACEHOLDER):
|
|
var n : Node = _editor.get_child(x)
|
|
var c : Control = n.call(&"get_base_editor")
|
|
if c != null:
|
|
if c is CodeEdit:
|
|
c.editable = false
|
|
c.minimap_draw = false
|
|
|
|
func _on_placeholder(__ : Node) -> void:
|
|
_placeholder_queue.call_deferred()
|
|
#endregion
|
|
|
|
func process_update_queue(__ : int = 0) -> void:
|
|
update_queue(__)
|
|
update_queue.call_deferred(__)
|
|
|
|
func get_selected_item() -> int:
|
|
var item_list : ItemList = _item_list
|
|
if is_instance_valid(item_list):
|
|
for x : int in item_list.item_count:
|
|
if item_list.is_selected(x):
|
|
return x
|
|
return -1
|
|
|
|
func can_expand_same_focus() -> bool:
|
|
return _BEHAVIOUR_CAN_EXPAND_SAME_ON_FOCUS
|
|
|
|
#region _8_
|
|
func swap(caller : Object) -> void:
|
|
if !_SWAP_BY_BUTTON:
|
|
return
|
|
|
|
if !is_instance_valid(_main) or _main.get_child_count() == 0:
|
|
return
|
|
|
|
var separators : Array = _main.get_separators()
|
|
if separators.size() == 0:
|
|
return
|
|
|
|
var index : int = 0
|
|
var linesep : Object = null
|
|
for x : Object in separators:
|
|
if x == caller:
|
|
linesep =x
|
|
break
|
|
index += 1
|
|
|
|
if linesep:
|
|
if linesep.is_vertical:
|
|
var atotal : int = 1
|
|
var btotal : int = 1
|
|
var nodes : Array[Node] = []
|
|
|
|
for x : int in range(index + 1, separators.size(), 1):
|
|
var clinesep : Object = separators[x]
|
|
if clinesep.is_vertical:
|
|
break
|
|
atotal += 1
|
|
for x : int in range(index - 1, -1, -1):
|
|
var clinesep : Object = separators[x]
|
|
if clinesep.is_vertical:
|
|
break
|
|
btotal += 1
|
|
|
|
var cindex : int = index
|
|
while atotal > 0:
|
|
cindex += 1
|
|
atotal -= 1
|
|
if cindex < _main.get_child_count():
|
|
nodes.append(_main.get_child(cindex))
|
|
continue
|
|
break
|
|
|
|
for x : Node in nodes:
|
|
cindex = btotal
|
|
while cindex > 0:
|
|
cindex -= 1
|
|
_main.move_child(x, x.get_index() - 1)
|
|
else:
|
|
index += 1
|
|
if _main.get_child_count() > index:
|
|
var child : Node = _main.get_child(index - 1)
|
|
_main.move_child(child, index)
|
|
#endregion
|
|
#region _7_
|
|
var _search_symbol : String = ""
|
|
|
|
func set_search_symbol(symbol: String) -> void:
|
|
_search_symbol = symbol
|
|
|
|
func reset_symbol() -> void:
|
|
_search_symbol = ""
|
|
|
|
func search_by_symbol(reference : Node) -> void:
|
|
if _search_symbol.is_empty():
|
|
return
|
|
var symbol : String = _search_symbol
|
|
var class_nm : StringName = reference.name.strip_edges()
|
|
|
|
reset_symbol()
|
|
|
|
if symbol == class_nm:
|
|
return
|
|
|
|
if class_nm.is_empty():
|
|
return
|
|
|
|
if class_nm.begins_with("_"):
|
|
if class_nm in GLOBALS:
|
|
return
|
|
|
|
if ClassDB.class_exists(class_nm):
|
|
var prefx : String = ""
|
|
if class_nm == "GraphNode":
|
|
prefx = "class_theme_item"
|
|
if symbol.begins_with("@"):
|
|
prefx = "class_annotation"
|
|
elif ClassDB.class_has_signal(class_nm, symbol):
|
|
prefx = "class_signal"
|
|
elif ClassDB.class_has_enum(class_nm, symbol, true):
|
|
prefx = "class_constant"
|
|
else:
|
|
var list : Array[Dictionary] = ClassDB.class_get_property_list(class_nm, true)
|
|
for x : Dictionary in list:
|
|
if x.name == symbol:
|
|
prefx = "class_property"
|
|
break
|
|
if prefx.is_empty():
|
|
list = ClassDB.class_get_method_list(class_nm, true)
|
|
for x : Dictionary in list:
|
|
if x.name == symbol:
|
|
prefx = "class_method"
|
|
break
|
|
if !prefx.is_empty():
|
|
var path : String = "{0}:{1}:{2}".format([prefx, class_nm, symbol])
|
|
EditorInterface.get_script_editor().goto_help(path)
|
|
#endregion
|
|
|
|
#region 0.3.6
|
|
var last_hover_tab : TabBar = null
|
|
|
|
func get_hover_tab(tabs : Array[TabBar] = []) -> TabBar:
|
|
var nodes : Array[TabBar] = tabs
|
|
if tabs.size() == 0:
|
|
nodes = get_tabs()
|
|
for n : TabBar in nodes:
|
|
if n.get_global_rect().has_point(n.get_global_mouse_position()):
|
|
return n
|
|
return null
|
|
|
|
func has_other_tabs() -> bool:
|
|
var tabs : Array[TabBar] = get_tabs()
|
|
var hover : TabBar = get_hover_tab(tabs)
|
|
last_hover_tab = hover
|
|
if is_instance_valid(hover):
|
|
var container : TabContainer = hover.get_parent()
|
|
if container.get_tab_count() > 1:
|
|
var index :int = container.current_tab
|
|
if index > 0 and index < container.get_tab_count() - 1:
|
|
return true
|
|
return false
|
|
|
|
func has_right_tabs() -> bool:
|
|
var tabs : Array[TabBar] = get_tabs()
|
|
var hover : TabBar = get_hover_tab(tabs)
|
|
last_hover_tab = hover
|
|
if is_instance_valid(hover):
|
|
var container : TabContainer = hover.get_parent()
|
|
var index : int = container.current_tab
|
|
return index > -1 and index < container.get_tab_count() - 1
|
|
return false
|
|
|
|
func has_left_tabs() -> bool:
|
|
var tabs : Array[TabBar] = get_tabs()
|
|
var hover : TabBar = get_hover_tab(tabs)
|
|
last_hover_tab = hover
|
|
if is_instance_valid(hover):
|
|
var container : TabContainer = hover.get_parent()
|
|
var index : int = container.current_tab
|
|
return index > 0
|
|
return false
|
|
|
|
func get_tabs() -> Array[TabBar]:
|
|
var tabs : Array[TabBar] = []
|
|
var nodes : Array[Node] = _plugin.get_tree().get_nodes_in_group(&"__SPLITER_TAB__")
|
|
for x : Node in nodes:
|
|
if x is TabBar:
|
|
tabs.append(x)
|
|
return tabs
|
|
|
|
func close_right_tabs() -> void:
|
|
var hover : TabBar = last_hover_tab
|
|
if is_instance_valid(hover):
|
|
var container : TabContainer = hover.get_parent()
|
|
var index : int = container.current_tab
|
|
if index > -1 and container.get_child_count() > index:
|
|
var childs : Array[Node] = container.get_children()
|
|
var out : Array[Node] = []
|
|
var _tools : Array[Mickeytools] = []
|
|
for c : int in range(index + 1, childs.size(), 1):
|
|
out.append(childs[c])
|
|
for x : Mickeytools in _code_editors:
|
|
if x.get_control() in out:
|
|
_tools.append(x)
|
|
for t : Mickeytools in _tools:
|
|
t.reset(true)
|
|
|
|
func close_left_tabs() -> void:
|
|
var hover : TabBar = last_hover_tab
|
|
if is_instance_valid(hover):
|
|
var container : TabContainer = hover.get_parent()
|
|
var index : int = container.current_tab
|
|
if index > -1 and container.get_child_count() > index:
|
|
var childs : Array[Node] = container.get_children()
|
|
var out : Array[Node] = []
|
|
var _tools : Array[Mickeytools] = []
|
|
for c : int in range(index - 1, -1, -1):
|
|
out.append(childs[c])
|
|
for x : Mickeytools in _code_editors:
|
|
if x.get_control() in out:
|
|
_tools.append(x)
|
|
for t : Mickeytools in _tools:
|
|
t.reset(true)
|
|
|
|
func close_other_tabs() -> void:
|
|
var hover : TabBar = last_hover_tab
|
|
if is_instance_valid(hover):
|
|
var container : TabContainer = hover.get_parent()
|
|
var index : int = container.current_tab
|
|
if index > -1 and container.get_child_count() > index:
|
|
var out : Array[Node] = container.get_children()
|
|
var _tools : Array[Mickeytools] = []
|
|
out.erase(container.get_child(index))
|
|
for x : Mickeytools in _code_editors:
|
|
if x.get_control() in out:
|
|
_tools.append(x)
|
|
for t : Mickeytools in _tools:
|
|
t.reset(true)
|
|
#endregion
|