@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
