Initial Commit
This commit is contained in:
commit
48a5e71e00
1136 changed files with 64347 additions and 0 deletions
201
addons/script_splitter/core/Input.gd
Normal file
201
addons/script_splitter/core/Input.gd
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
@tool
|
||||
extends RefCounted
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
|
||||
const Builder = preload("./../core/builder.gd")
|
||||
const Context = preload("./../core/contex/window.gd")
|
||||
const SSPContext = preload("./../core/contex/ssp_window.gd")
|
||||
|
||||
var _plugin : EditorPlugin = null
|
||||
var _builder : Builder = null
|
||||
|
||||
signal add_row(value : Resource)
|
||||
signal add_column(value : Resource)
|
||||
signal remove_row(value : Resource)
|
||||
signal remove_column(value : Resource)
|
||||
|
||||
signal left_tab_close(value : Resource)
|
||||
signal right_tab_close(value : Resource)
|
||||
signal others_tab_close(value : Resource)
|
||||
|
||||
const ICON_ADD_COLUMN : Texture2D = preload("./../assets/split_cplus.svg")
|
||||
const ICON_ADD_ROW : Texture2D = preload("./../assets/split_rplus.svg")
|
||||
const ICON_REMOVE_COLUMN : Texture2D = preload("./../assets/split_cminus.svg")
|
||||
const ICON_REMOVE_ROW : Texture2D = preload("./../assets/split_rminus.svg")
|
||||
|
||||
const L_TAB_BAR : Texture2D = preload("./../assets/LTabBar.svg")
|
||||
const R_TAB_BAR : Texture2D = preload("./../assets/RTabBar.svg")
|
||||
const TAB_BAR: Texture2D = preload("./../assets/TabBar.svg")
|
||||
|
||||
|
||||
var _context_add_split_column : Context = null
|
||||
var _context_add_split_row : Context = null
|
||||
var _context_remove_split_column : Context = null
|
||||
var _context_remove_split_row : Context = null
|
||||
var _context_editor_split : SSPContext = null
|
||||
|
||||
var _editor_context_add_split_column : Context = null
|
||||
var _editor_context_add_split_row : Context = null
|
||||
var _editor_context_remove_split_column : Context = null
|
||||
var _editor_context_remove_split_row : Context = null
|
||||
|
||||
var _editor_context_left_tab_close : Context = null
|
||||
var _editor_context_right_tab_close : Context = null
|
||||
var _editor_context_botH_tab_close : Context = null
|
||||
|
||||
func get_honey_splitter() -> SSPContext:
|
||||
return _context_editor_split
|
||||
|
||||
# Traduction?
|
||||
func _tr(message : String) -> String:
|
||||
# ...
|
||||
return message.capitalize()
|
||||
|
||||
func init_1() -> void:
|
||||
|
||||
_context_add_split_column = Context.new(_tr("SPLIT_COLUMN"), _add_column_split, _can_split, ICON_ADD_COLUMN)
|
||||
_context_add_split_row = Context.new(_tr("SPLIT_ROW"), _add_row_split, _can_split, ICON_ADD_ROW)
|
||||
_context_remove_split_column = Context.new(_tr("MERGE_SPLITTED_COLUMN"), _remove_column_split, _can_merge_column, ICON_REMOVE_COLUMN)
|
||||
_context_remove_split_row = Context.new(_tr("MERGE_SPLITTED_ROW"), _remove_row_split, _can_merge_row, ICON_REMOVE_ROW)
|
||||
_context_editor_split = SSPContext.new()
|
||||
|
||||
_editor_context_add_split_column = Context.new(_tr("SPLIT_COLUMN"), _add_column_split, _can_split, ICON_ADD_COLUMN)
|
||||
_editor_context_add_split_row = Context.new(_tr("SPLIT_ROW"), _add_row_split, _can_split, ICON_ADD_ROW)
|
||||
_editor_context_remove_split_column = Context.new(_tr("MERGE_SPLITTED_COLUMN"), _remove_column_split, _can_merge_column, ICON_REMOVE_COLUMN)
|
||||
_editor_context_remove_split_row = Context.new(_tr("MERGE_SPLITTED_ROW"), _remove_row_split, _can_merge_row, ICON_REMOVE_ROW)
|
||||
|
||||
_editor_context_left_tab_close = Context.new(_tr("CLOSE_LEFT_TABS"), _left_tab_close, _can_left_tab_close, L_TAB_BAR)
|
||||
_editor_context_botH_tab_close = Context.new(_tr("CLOSE_OTHERS_TABS"), _others_tab_close, _can_others_tab_close, TAB_BAR)
|
||||
_editor_context_right_tab_close = Context.new(_tr("CLOSE_RIGHT_TABS"), _right_tab_close, _can_right_tab_close, R_TAB_BAR)
|
||||
|
||||
_plugin.add_context_menu_plugin(EditorContextMenuPlugin.CONTEXT_SLOT_SCRIPT_EDITOR_CODE, _context_add_split_column)
|
||||
_plugin.add_context_menu_plugin(EditorContextMenuPlugin.CONTEXT_SLOT_SCRIPT_EDITOR_CODE, _context_add_split_row)
|
||||
_plugin.add_context_menu_plugin(EditorContextMenuPlugin.CONTEXT_SLOT_SCRIPT_EDITOR_CODE, _context_remove_split_column)
|
||||
_plugin.add_context_menu_plugin(EditorContextMenuPlugin.CONTEXT_SLOT_SCRIPT_EDITOR_CODE, _context_remove_split_row)
|
||||
_plugin.add_context_menu_plugin(EditorContextMenuPlugin.CONTEXT_SLOT_SCRIPT_EDITOR_CODE, _context_editor_split)
|
||||
|
||||
_plugin.add_context_menu_plugin(EditorContextMenuPlugin.CONTEXT_SLOT_SCRIPT_EDITOR, _editor_context_add_split_column)
|
||||
_plugin.add_context_menu_plugin(EditorContextMenuPlugin.CONTEXT_SLOT_SCRIPT_EDITOR, _editor_context_add_split_row)
|
||||
_plugin.add_context_menu_plugin(EditorContextMenuPlugin.CONTEXT_SLOT_SCRIPT_EDITOR, _editor_context_remove_split_column)
|
||||
_plugin.add_context_menu_plugin(EditorContextMenuPlugin.CONTEXT_SLOT_SCRIPT_EDITOR, _editor_context_remove_split_row)
|
||||
|
||||
_plugin.add_context_menu_plugin(EditorContextMenuPlugin.CONTEXT_SLOT_SCRIPT_EDITOR, _editor_context_left_tab_close)
|
||||
_plugin.add_context_menu_plugin(EditorContextMenuPlugin.CONTEXT_SLOT_SCRIPT_EDITOR, _editor_context_right_tab_close)
|
||||
_plugin.add_context_menu_plugin(EditorContextMenuPlugin.CONTEXT_SLOT_SCRIPT_EDITOR, _editor_context_botH_tab_close)
|
||||
|
||||
|
||||
|
||||
func _get_value(value : Variant) -> PackedStringArray:
|
||||
if value is PackedStringArray:
|
||||
return value
|
||||
|
||||
elif value is Array:
|
||||
var packed : PackedStringArray = []
|
||||
for x : Variant in value:
|
||||
if x is Resource:
|
||||
packed.append(x.resource_path)
|
||||
return packed
|
||||
elif x is String:
|
||||
packed.append(x)
|
||||
return packed
|
||||
|
||||
elif value is Resource:
|
||||
var packed : PackedStringArray = [value.resource_path]
|
||||
return packed
|
||||
return []
|
||||
|
||||
func _get_resource(value : Variant) -> Variant:
|
||||
if value is Resource:
|
||||
return value
|
||||
elif value is Node:
|
||||
return value
|
||||
|
||||
var packed : PackedStringArray = []
|
||||
if value is Array:
|
||||
for x : Variant in value:
|
||||
if x is String:
|
||||
packed.append(x)
|
||||
break
|
||||
elif value is PackedStringArray:
|
||||
packed = value
|
||||
|
||||
if packed.size() == 0:
|
||||
return null
|
||||
|
||||
return packed[0]
|
||||
|
||||
func _can_split(value : Variant = null) -> bool:
|
||||
return _plugin.builder.can_split(_get_value(value))
|
||||
|
||||
func _can_merge_column(value : Variant = null) -> bool:
|
||||
return _plugin.builder.can_merge_column(_get_value(value))
|
||||
|
||||
func _can_merge_row(value : Variant = null) -> bool:
|
||||
return _plugin.builder.can_merge_row(_get_value(value))
|
||||
|
||||
func _can_left_tab_close(value : Variant = null) -> bool:
|
||||
return _plugin.builder.can_left_tab_close(_get_value(value))
|
||||
|
||||
func _can_right_tab_close(value : Variant = null) -> bool:
|
||||
return _plugin.builder.can_right_tab_close(_get_value(value))
|
||||
|
||||
func _can_others_tab_close(value : Variant = null) -> bool:
|
||||
return _plugin.builder.can_others_tab_close(_get_value(value))
|
||||
|
||||
func _left_tab_close(value : Variant = null) -> void:
|
||||
left_tab_close.emit(_get_resource(value))
|
||||
|
||||
func _right_tab_close(value : Variant = null) -> void:
|
||||
right_tab_close.emit(_get_resource(value))
|
||||
|
||||
func _others_tab_close(value : Variant = null) -> void:
|
||||
others_tab_close.emit(_get_resource(value))
|
||||
|
||||
func _add_column_split(value : Variant = null) -> void:
|
||||
add_column.emit(_get_resource(value))
|
||||
|
||||
func _add_row_split(value : Variant = null) -> void:
|
||||
add_row.emit(_get_resource(value))
|
||||
|
||||
func _remove_column_split(value : Variant = null) -> void:
|
||||
remove_column.emit(_get_resource(value))
|
||||
|
||||
func _remove_row_split(value : Variant = null) -> void:
|
||||
remove_row.emit(_get_resource(value))
|
||||
|
||||
func init_0() -> void:
|
||||
for x : Variant in [
|
||||
_context_add_split_column,
|
||||
_context_add_split_row,
|
||||
_context_remove_split_column,
|
||||
_context_remove_split_row,
|
||||
_context_editor_split,
|
||||
_editor_context_add_split_column,
|
||||
_editor_context_add_split_row,
|
||||
_editor_context_remove_split_column,
|
||||
_editor_context_remove_split_row
|
||||
]:
|
||||
if is_instance_valid(x):
|
||||
_plugin.remove_context_menu_plugin(x)
|
||||
|
||||
func _init(plugin : EditorPlugin, builder : Builder) -> void:
|
||||
_plugin = plugin
|
||||
_builder = builder
|
||||
|
||||
func event(event : InputEvent) -> bool:
|
||||
if event.is_pressed():
|
||||
if event is InputEventKey:
|
||||
if event.keycode == KEY_1 and event.ctrl_pressed:
|
||||
_plugin.builder.multi_split(2, false)
|
||||
pass
|
||||
if event.keycode == KEY_2 and event.ctrl_pressed:
|
||||
_plugin.builder.multi_split(4, false)
|
||||
pass
|
||||
return false
|
||||
1
addons/script_splitter/core/Input.gd.uid
Normal file
1
addons/script_splitter/core/Input.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dxipxeq42djlp
|
||||
205
addons/script_splitter/core/base/container.gd
Normal file
205
addons/script_splitter/core/base/container.gd
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
@tool
|
||||
extends RefCounted
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
const SplitterContainer = preload("./../../../script_splitter/core/ui/splitter/splitter_container.gd")
|
||||
const NControl = preload("./../../core/util/control.gd")
|
||||
|
||||
const IoBar = preload("./../../core/ui/splitter/io/io_bar.gd")
|
||||
|
||||
signal update()
|
||||
signal focus_by_tab(root : TabContainer, index : int)
|
||||
signal remove_by_tab(root : TabContainer, index : int)
|
||||
signal change_container(container : TabContainer)
|
||||
signal exiting()
|
||||
|
||||
@warning_ignore("unused_signal")
|
||||
signal rmb_click(index : int, TabContainer)
|
||||
|
||||
@warning_ignore("unused_signal")
|
||||
signal swap_tab(from : Container, index : int, to : Container)
|
||||
@warning_ignore("unused_signal")
|
||||
signal same_swap_tab(from : Container, index : int, type : StringName)
|
||||
|
||||
var _editor_container : TabContainer = null
|
||||
var _editor_splitter_container : SplitterContainer = null
|
||||
|
||||
var _current_container : TabContainer = null:
|
||||
set(e):
|
||||
if _current_container != e:
|
||||
change_container.emit(e)
|
||||
_current_container = e
|
||||
|
||||
var _frm : int = 0
|
||||
|
||||
var _io_bar : Node = null
|
||||
|
||||
func on_focus(root : TabContainer, index : int) -> void:
|
||||
focus_by_tab.emit(root, index)
|
||||
|
||||
func on_remove(root : TabContainer, index : int) -> void:
|
||||
remove_by_tab.emit(root, index)
|
||||
|
||||
func get_io_bar() -> IoBar:
|
||||
if !is_instance_valid(_io_bar):
|
||||
_io_bar = IoBar.new()
|
||||
return _io_bar
|
||||
|
||||
func get_container(control : Control) -> Container:
|
||||
if control is SplitterContainer.SplitterEditorContainer.Editor:
|
||||
return _editor_splitter_container.get_base_container(control)
|
||||
return null
|
||||
|
||||
func get_container_item(control : Control) -> Control:
|
||||
if control is SplitterContainer.SplitterEditorContainer.Editor:
|
||||
return _editor_splitter_container.get_base_container_item(control)
|
||||
return null
|
||||
|
||||
func _init(container : TabContainer) -> void:
|
||||
_editor_container = container
|
||||
_editor_splitter_container = SplitterContainer.new()
|
||||
_editor_splitter_container.initialize(_editor_container, self)
|
||||
_editor_splitter_container.visible = false
|
||||
|
||||
_editor_container.child_entered_tree.connect(_on_update)
|
||||
_editor_container.child_exiting_tree.connect(_on_update)
|
||||
|
||||
_editor_container.tree_exiting.connect(_on_exiting)
|
||||
|
||||
|
||||
func is_active() -> bool:
|
||||
if _frm > 0:
|
||||
_frm -= 1
|
||||
return false
|
||||
return is_instance_valid(_editor_container) and _editor_container.is_inside_tree()
|
||||
|
||||
func _on_exiting() -> void:
|
||||
_frm = 3
|
||||
exiting.emit()
|
||||
|
||||
func initialize_editor_container() -> void:
|
||||
_editor_splitter_container.initialize_editor_contianer()
|
||||
|
||||
func _on_update(__ : Node) -> void:
|
||||
update.emit()
|
||||
|
||||
func set_current_container(container : TabContainer) -> void:
|
||||
if _editor_splitter_container.set_current_editor(container):
|
||||
_current_container = container
|
||||
|
||||
func get_editor_container() -> TabContainer:
|
||||
return _editor_container
|
||||
|
||||
func get_root_container() -> SplitterContainer.SplitterRoot:
|
||||
return _editor_splitter_container.get_root()
|
||||
|
||||
func get_editor_root_container(node : Node) -> SplitterContainer.BaseContainerItem:
|
||||
if node is SplitterContainer.SplitterRoot:
|
||||
node = node.get_parent()
|
||||
return node
|
||||
return null
|
||||
|
||||
func get_editors() -> Array[Node]:
|
||||
return _editor_container.get_children()
|
||||
|
||||
func get_current_editor() -> Control:
|
||||
return _editor_splitter_container.get_current_editor()
|
||||
|
||||
func tool_created() -> void:
|
||||
_editor_container.visible = false
|
||||
_editor_splitter_container.visible = true
|
||||
|
||||
func new_column() -> Control:
|
||||
_current_container = _editor_splitter_container.create_new_column()
|
||||
return _current_container
|
||||
|
||||
func new_row() -> Control:
|
||||
_current_container = _editor_splitter_container.create_new_row()
|
||||
return _current_container
|
||||
|
||||
func update_split_container() -> void:
|
||||
for x : Node in Engine.get_main_loop().get_nodes_in_group(&"__ST_CS__"):
|
||||
if x.has_method(&"update"):
|
||||
x.call(&"update")
|
||||
|
||||
func get_all_containers() -> Array[Node]:
|
||||
if !_editor_splitter_container:
|
||||
return []
|
||||
return _editor_splitter_container.get_tree().get_nodes_in_group(&"__SP_BR__")
|
||||
|
||||
func get_current_containers() -> Array[Node]:
|
||||
if !is_instance_valid(_current_container):
|
||||
return []
|
||||
var c : Control = _editor_splitter_container.get_base_container(_current_container)
|
||||
if is_instance_valid(c):
|
||||
return c.get_children()
|
||||
return []
|
||||
|
||||
func get_all_splitters() -> Array[Node]:
|
||||
if !_editor_splitter_container:
|
||||
return []
|
||||
return _editor_splitter_container.get_tree().get_nodes_in_group(&"__SC_SPLITTER__")
|
||||
|
||||
func get_current_splitters() -> Array[Node]:
|
||||
if !is_instance_valid(_current_container):
|
||||
return []
|
||||
var c : Control = _editor_splitter_container.get_base_container_item(_current_container)
|
||||
if is_instance_valid(c):
|
||||
c = c.get_parent()
|
||||
if c:
|
||||
return c.get_children()
|
||||
return []
|
||||
|
||||
func garbage() -> void:
|
||||
var control : Node = get_current_editor()
|
||||
|
||||
var nodes : Array[Node] = get_all_splitters()
|
||||
var total : int = nodes.size()
|
||||
if total > 2:
|
||||
total = 0
|
||||
for x : Node in nodes:
|
||||
if !x.is_queued_for_deletion():
|
||||
total += 1
|
||||
|
||||
if total > 1:
|
||||
for x : Node in nodes:
|
||||
if total < 2:
|
||||
break
|
||||
if x.get_child_count() == 0:
|
||||
if control == x:
|
||||
control = null
|
||||
if !x.is_queued_for_deletion():
|
||||
x.queue_free()
|
||||
total -= 1
|
||||
|
||||
if control == null:
|
||||
for x : Node in _editor_splitter_container.get_tree().get_nodes_in_group(&"__SC_SPLITTER__"):
|
||||
if x is Control and !x.is_queued_for_deletion():
|
||||
control = x
|
||||
break
|
||||
|
||||
func reset() -> void:
|
||||
_editor_container.visible = true
|
||||
|
||||
if _editor_container.child_entered_tree.is_connected(_on_update):
|
||||
_editor_container.child_entered_tree.disconnect(_on_update)
|
||||
if _editor_container.child_exiting_tree.is_connected(_on_update):
|
||||
_editor_container.child_exiting_tree.disconnect(_on_update)
|
||||
|
||||
_editor_splitter_container.reset()
|
||||
_editor_splitter_container.queue_free()
|
||||
|
||||
func get_current_container() -> TabContainer:
|
||||
return _current_container
|
||||
|
||||
func move_container(from : int, to : int) -> bool:
|
||||
if _editor_container.get_child_count() > from and from > -1:
|
||||
_editor_container.move_child(_editor_container.get_child(from), to)
|
||||
return true
|
||||
return false
|
||||
1
addons/script_splitter/core/base/container.gd.uid
Normal file
1
addons/script_splitter/core/base/container.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://iyslc58y0lp1
|
||||
311
addons/script_splitter/core/base/list.gd
Normal file
311
addons/script_splitter/core/base/list.gd
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
@tool
|
||||
extends RefCounted
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
const SplitterList = preload("./../../core/ui/splitter/splitter_list.gd")
|
||||
|
||||
signal item_selected(item : int)
|
||||
signal move_item(from : int, to : int)
|
||||
signal updated()
|
||||
|
||||
var _editor_list : ItemList = null
|
||||
var _script_list : ItemList = null
|
||||
var _script_filesearch : LineEdit = null
|
||||
var _editor_filesearch : LineEdit = null
|
||||
var _update_list_queue : bool = false
|
||||
var _array_list : Array = []
|
||||
var _selet_queue : int = -1
|
||||
var _selecting : bool = false
|
||||
|
||||
var update_selections_callback : Callable
|
||||
|
||||
func _notification(what: int) -> void:
|
||||
if what == NOTIFICATION_PREDELETE:
|
||||
if is_instance_valid(_editor_list):
|
||||
_editor_list.visible = true
|
||||
if _editor_list.item_selected.is_connected(_item_selected):
|
||||
_editor_list.item_selected.disconnect(_item_selected)
|
||||
if _editor_list.property_list_changed.is_connected(_on_property):
|
||||
_editor_list.property_list_changed.disconnect(_on_property)
|
||||
if is_instance_valid(_editor_filesearch):
|
||||
_editor_filesearch.visible = true
|
||||
|
||||
if is_instance_valid(_script_filesearch):
|
||||
_script_filesearch.queue_free()
|
||||
|
||||
if is_instance_valid(_script_list):
|
||||
_script_list.queue_free()
|
||||
|
||||
func _on_sc_item_selected(index : int) -> void:
|
||||
if _script_list.item_count > index and index > -1:
|
||||
index = _get_script_selected(index)
|
||||
if index == -1:
|
||||
return
|
||||
select(index)
|
||||
|
||||
func _on_sc_item_activate(index : int) -> void:
|
||||
if _script_list.item_count > index:
|
||||
index = _get_script_selected(index)
|
||||
if index > -1 and index < _editor_list.item_count:
|
||||
_editor_list.item_activated.emit(index)
|
||||
|
||||
func _on_property() -> void:
|
||||
_script_list.update()
|
||||
|
||||
func _on_sc_item_clicked(index: int, at_position: Vector2, mouse_button_index: int) -> void:
|
||||
if _script_list.item_count > index:
|
||||
index = _get_script_selected(index)
|
||||
if index == -1:
|
||||
return
|
||||
_editor_list.item_clicked.emit(index, at_position, mouse_button_index)
|
||||
_script_list.update()
|
||||
|
||||
func _get_script_selected(index : int) -> int:
|
||||
if _editor_list.item_count == _script_list.item_count:
|
||||
return index
|
||||
|
||||
var tp : String = _script_list.get_item_tooltip(index)
|
||||
var cindx : int = -1
|
||||
if !tp.is_empty():
|
||||
for x : int in _editor_list.item_count:
|
||||
if tp == _editor_list.get_item_tooltip(x):
|
||||
cindx = x
|
||||
break
|
||||
else:
|
||||
tp = _script_list.get_item_text(index)
|
||||
for x : int in _editor_list.item_count:
|
||||
if tp == _editor_list.get_item_text(x):
|
||||
cindx = x
|
||||
break
|
||||
|
||||
return cindx
|
||||
|
||||
#func set_handler(manager : Object) -> void:
|
||||
#_script_list.set_handler(manager)
|
||||
#
|
||||
func _init(list : ItemList) -> void:
|
||||
_editor_list = list
|
||||
_editor_list.item_selected.connect(_item_selected)
|
||||
_editor_list.property_list_changed.connect(_on_property)
|
||||
|
||||
var parent: Node = _editor_list.get_parent()
|
||||
_script_list = list.duplicate()
|
||||
_script_list.set_script(SplitterList)
|
||||
_script_list.set_reference(_update_list)
|
||||
_script_list.set_list(_editor_list)
|
||||
_script_list.item_selected.connect(_on_sc_item_selected)
|
||||
_script_list.item_activated.connect(_on_sc_item_activate)
|
||||
_script_list.item_clicked.connect(_on_sc_item_clicked)
|
||||
|
||||
if _script_list.has_signal(&"move_item_by_index"):
|
||||
_script_list.connect(&"move_item_by_index", _on_move_item_by_index)
|
||||
#_editor_list.draw.connect(_on_update_list)
|
||||
|
||||
_script_list.add_to_group(&"__SP_LT__")
|
||||
_array_list = [_editor_list, _script_list]
|
||||
|
||||
list.visible = false
|
||||
|
||||
var filesearch : Object = parent.get_child(0)
|
||||
if filesearch is LineEdit:
|
||||
_editor_filesearch = filesearch
|
||||
var txt : String = filesearch.text
|
||||
if !txt.is_empty():
|
||||
filesearch.set(&"text", "")
|
||||
|
||||
_script_filesearch = filesearch.duplicate()
|
||||
_script_filesearch.text_changed.connect(_on_update_list_search)
|
||||
|
||||
filesearch.visible = false
|
||||
|
||||
parent.add_child(_script_list)
|
||||
parent.move_child(_script_list, 0)
|
||||
parent.add_child(_script_filesearch)
|
||||
parent.move_child(_script_filesearch, 0)
|
||||
|
||||
_script_list.update()
|
||||
|
||||
func _on_update_list() -> void:
|
||||
if _update_list_queue:
|
||||
return
|
||||
|
||||
if !is_instance_valid(_script_list) or !is_instance_valid(_editor_list):
|
||||
return
|
||||
|
||||
_update_list_queue = true
|
||||
|
||||
var filtered : bool = false
|
||||
|
||||
if is_instance_valid(_script_filesearch):
|
||||
filtered = !_script_filesearch.text.is_empty()
|
||||
|
||||
|
||||
var item_list : ItemList = _editor_list
|
||||
|
||||
_script_list.clear()
|
||||
|
||||
if filtered:
|
||||
_on_update_list_search(_script_filesearch.text)
|
||||
else:
|
||||
for x : int in item_list.item_count:
|
||||
var indx : int = _script_list.item_count
|
||||
_script_list.add_item(item_list.get_item_text(x), item_list.get_item_icon(x), true)
|
||||
_script_list.set_item_metadata(indx, item_list.get_item_metadata(x))
|
||||
_script_list.set_item_tooltip(indx, item_list.get_item_tooltip(x))
|
||||
_script_list.set_item_icon_modulate(indx, item_list.get_item_icon_modulate(x))
|
||||
_script_list.set_item_custom_fg_color(indx, item_list.get_item_custom_fg_color(x))
|
||||
|
||||
update_list_selection()
|
||||
|
||||
set_deferred(&"_update_list_queue", false)
|
||||
|
||||
func _on_update_list_search(txt : String) -> void:
|
||||
if txt.is_empty():
|
||||
_on_update_list()
|
||||
return
|
||||
|
||||
if !is_instance_valid(_script_list):
|
||||
return
|
||||
|
||||
_script_list.clear()
|
||||
|
||||
var rgx : RegEx = RegEx.create_from_string("(?i).*{0}.*".format([txt]))
|
||||
|
||||
if !is_instance_valid(rgx) or !rgx.is_valid():
|
||||
return
|
||||
|
||||
var item_list : ItemList = _editor_list
|
||||
for x : int in item_list.item_count:
|
||||
var _txt : String = item_list.get_item_text(x)
|
||||
if rgx.search(_txt) != null:
|
||||
var indx : int = _script_list.add_item(item_list.get_item_text(x), item_list.get_item_icon(x), true)
|
||||
_script_list.set_item_metadata(indx, item_list.get_item_metadata(x))
|
||||
_script_list.set_item_tooltip(indx, item_list.get_item_tooltip(x))
|
||||
_script_list.set_item_icon_modulate(indx, item_list.get_item_icon_modulate(x))
|
||||
_script_list.set_item_custom_fg_color(indx, item_list.get_item_custom_fg_color(x))
|
||||
|
||||
update_list_selection()
|
||||
|
||||
func update_list_selection() -> void:
|
||||
if update_selections_callback.is_valid():
|
||||
update_selections_callback.call(_array_list)
|
||||
|
||||
func _item_selected(i : int) -> void:
|
||||
item_selected.emit(i)
|
||||
|
||||
func _update_list() -> void:
|
||||
updated.emit()
|
||||
_on_update_list()
|
||||
|
||||
func get_editor_list() -> ItemList:
|
||||
return _editor_list
|
||||
|
||||
func get_selected_id() -> int:
|
||||
for x : int in range(_editor_list.item_count):
|
||||
if _editor_list.is_selected(x):
|
||||
return x
|
||||
return -1
|
||||
|
||||
func remove(index : int) -> void:
|
||||
if _editor_list.item_count > index and index > -1:
|
||||
_editor_list.item_clicked.emit(index, _editor_list.get_local_mouse_position(), MOUSE_BUTTON_MIDDLE)
|
||||
|
||||
func item_count() -> int:
|
||||
return _editor_list.item_count
|
||||
|
||||
func _select() -> void:
|
||||
if _selet_queue > -1 and _editor_list.item_count > _selet_queue:
|
||||
_editor_list.select(_selet_queue, true)
|
||||
_editor_list.item_selected.emit(_selet_queue)
|
||||
_update_list.call_deferred()
|
||||
_selecting = false
|
||||
|
||||
func update_list() -> void:
|
||||
_on_update_list()
|
||||
|
||||
func select(i : int) -> void:
|
||||
if i > -1 and _editor_list.item_count > i:
|
||||
_selet_queue = i
|
||||
if _selecting:
|
||||
return
|
||||
_selecting = true
|
||||
_select.call_deferred()
|
||||
|
||||
func is_selected(i : int) -> bool:
|
||||
if _editor_list.item_count > i and i > -1:
|
||||
return _editor_list.is_selected(i)
|
||||
return false
|
||||
|
||||
func get_item_tooltip(item : int) -> String:
|
||||
if _editor_list.item_count > item and item > -1:
|
||||
return _editor_list.get_item_tooltip(item)
|
||||
return ""
|
||||
|
||||
func get_item_icon(item : int) -> Texture2D:
|
||||
if _editor_list.item_count > item and item > -1:
|
||||
return _editor_list.get_item_icon(item)
|
||||
return null
|
||||
|
||||
func get_item_icon_modulate(item : int) -> Color:
|
||||
if _editor_list.item_count > item and item > -1:
|
||||
return _editor_list.get_item_icon_modulate(item)
|
||||
return Color.WHITE
|
||||
|
||||
func get_item_text(item : int) -> String:
|
||||
if _editor_list.item_count > item and item > -1:
|
||||
return _editor_list.get_item_text(item)
|
||||
return ""
|
||||
|
||||
func reset() -> void:
|
||||
if is_instance_valid(_editor_list):
|
||||
_editor_list.visible = true
|
||||
if _editor_list.draw.is_connected(_on_update_list):
|
||||
_editor_list.draw.disconnect(_on_update_list)
|
||||
if _editor_list.item_selected.is_connected(_item_selected):
|
||||
_editor_list.item_selected.disconnect(_item_selected)
|
||||
if _editor_list.property_list_changed.is_connected(_on_property):
|
||||
_editor_list.property_list_changed.disconnect(_on_property)
|
||||
|
||||
if is_instance_valid(_editor_filesearch):
|
||||
_editor_filesearch.visible = true
|
||||
|
||||
if is_instance_valid(_script_filesearch):
|
||||
_script_filesearch.queue_free()
|
||||
|
||||
if is_instance_valid(_script_list):
|
||||
_script_list.queue_free()
|
||||
|
||||
func _on_move_item_by_index(from : int, to : int) -> void:
|
||||
if from == to:
|
||||
return
|
||||
|
||||
for x : ItemList in [_script_list, _editor_list]:
|
||||
if !is_instance_valid(x):
|
||||
return
|
||||
for y : int in [from, to]:
|
||||
if x.item_count <= y or y < 0:
|
||||
return
|
||||
|
||||
var values : Array[int] = [from, to]
|
||||
|
||||
for v : int in range(0, values.size(), 1):
|
||||
if _script_list.get_item_tooltip(v) != _editor_list.get_item_tooltip(v):
|
||||
var value = -1
|
||||
var st : String = _script_list.get_item_tooltip(from)
|
||||
|
||||
for x : int in _editor_list.item_count:
|
||||
if st == _editor_list.get_item_tooltip(x):
|
||||
value = x
|
||||
break
|
||||
|
||||
if value == -1:
|
||||
return
|
||||
|
||||
values[v] = value
|
||||
|
||||
move_item.emit(values[0], values[1])
|
||||
1
addons/script_splitter/core/base/list.gd.uid
Normal file
1
addons/script_splitter/core/base/list.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://ors5ojuayup4
|
||||
249
addons/script_splitter/core/builder.gd
Normal file
249
addons/script_splitter/core/builder.gd
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
@tool
|
||||
extends RefCounted
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
const EditorManager = preload("./../core/editor/godot/manager.gd")
|
||||
const BaseContainer = preload("./../core/base/container.gd")
|
||||
const BaseList = preload("./../core/base/list.gd")
|
||||
|
||||
var _plugin : EditorPlugin = null
|
||||
var _editor_manager : EditorManager = null
|
||||
|
||||
|
||||
#region _REF_
|
||||
var _item_list : ItemList = null:
|
||||
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-Splitter] Can not find item list!")
|
||||
return _item_list
|
||||
#endregion
|
||||
|
||||
func get_editor_manager() -> EditorManager:
|
||||
return _editor_manager
|
||||
|
||||
func handle(id : StringName) -> void:
|
||||
_editor_manager.io.execute(id)
|
||||
|
||||
func refresh_warnings() -> void:
|
||||
_editor_manager.refresh_warnings.execute()
|
||||
|
||||
func can_split(values : Variant) -> bool:
|
||||
var current : Node = null
|
||||
if values is PackedStringArray and values.size() > 0:
|
||||
var root : Node = _plugin.get_tree().root
|
||||
if root.has_node(values[0]):
|
||||
current = root.get_node(values[0])
|
||||
elif values is Node:
|
||||
current = values
|
||||
return _editor_manager.get_current_totaL_editors(current) > 1
|
||||
|
||||
func can_merge_column(values : Variant) -> bool:
|
||||
var current : Node = null
|
||||
if values is PackedStringArray and values.size() > 0:
|
||||
var root : Node = _plugin.get_tree().root
|
||||
if root.has_node(values[0]):
|
||||
current = root.get_node(values[0])
|
||||
elif values is Node:
|
||||
current = values
|
||||
return _editor_manager.get_current_total_splitters(current) > 1
|
||||
|
||||
func can_merge_row(_values : Variant) -> bool:
|
||||
return _editor_manager.get_total_split_container(true) > 1
|
||||
|
||||
func can_left_tab_close(values : Variant) -> bool:
|
||||
if values is PackedStringArray and values.size() > 0:
|
||||
var root : Node = _plugin.get_tree().root
|
||||
if root.has_node(values[0]):
|
||||
values = root.get_node(values[0])
|
||||
else:
|
||||
values = values[0]
|
||||
var node : Node = _editor_manager.get_control_tool_by_current(values)
|
||||
return node and node.get_index() > 0
|
||||
|
||||
func can_right_tab_close(values : Variant) -> bool:
|
||||
if values is PackedStringArray and values.size() > 0:
|
||||
var root : Node = _plugin.get_tree().root
|
||||
if root.has_node(values[0]):
|
||||
values = root.get_node(values[0])
|
||||
else:
|
||||
values = values[0]
|
||||
var node : Node = _editor_manager.get_control_tool_by_current(values)
|
||||
return node and node.get_index() < node.get_parent().get_child_count() - 1
|
||||
|
||||
func can_others_tab_close(values : Variant) -> bool:
|
||||
return can_left_tab_close(values) and can_right_tab_close(values)
|
||||
|
||||
func update(_delta : float) -> void:
|
||||
if _editor_manager.update():
|
||||
_plugin.set_process(false)
|
||||
|
||||
func multi_split(number : int, as_row : bool) -> void:
|
||||
var total : int = _editor_manager.get_current_total_splitters(null)
|
||||
if total == number:
|
||||
return
|
||||
var container : Node = _editor_manager.get_current_root()
|
||||
if !as_row:
|
||||
if total < number:
|
||||
number = number - total
|
||||
while number > 0:
|
||||
if !can_split(container):
|
||||
return
|
||||
_editor_manager.split_column.execute(container)
|
||||
number -= 1
|
||||
else:
|
||||
number = total - number
|
||||
while number > 0:
|
||||
if !can_merge_column(container):
|
||||
return
|
||||
_editor_manager.merge_tool.execute([_editor_manager.get_current_tool(container), false])
|
||||
number -= 1
|
||||
if !as_row:
|
||||
if total < number:
|
||||
number = number - total
|
||||
while number > 0:
|
||||
if !can_split(container):
|
||||
return
|
||||
_editor_manager.split_row.execute(container)
|
||||
number -= 1
|
||||
else:
|
||||
number = total - number
|
||||
while number > 0:
|
||||
if !can_merge_column(container):
|
||||
return
|
||||
_editor_manager.merge_tool.execute([_editor_manager.get_current_tool(container), true])
|
||||
number -= 1
|
||||
|
||||
func init_0() -> void:
|
||||
if is_instance_valid(_editor_manager):
|
||||
_editor_manager.reset()
|
||||
_editor_manager = null
|
||||
|
||||
var editor : ScriptEditor = EditorInterface.get_script_editor()
|
||||
if editor:
|
||||
if editor.editor_script_changed.is_connected(_on_change):
|
||||
editor.editor_script_changed.disconnect(_on_change)
|
||||
|
||||
func _on_change(__ : Variant = null) -> void:
|
||||
_queue_update()
|
||||
|
||||
func connect_callbacks(
|
||||
on_column : Signal,
|
||||
on_row : Signal,
|
||||
out_column : Signal,
|
||||
out_row : Signal,
|
||||
left_tab_close : Signal,
|
||||
right_tab_close : Signal,
|
||||
others_tab_close : Signal,
|
||||
|
||||
do_connect : bool = true) -> void:
|
||||
for x : Array in [
|
||||
[on_column, _editor_manager.split_column.execute],
|
||||
[on_row, _editor_manager.split_row.execute],
|
||||
[out_column, _editor_manager.unsplit_column],
|
||||
[out_row, _editor_manager.unsplit_row],
|
||||
[left_tab_close, _editor_manager.left_tab_close],
|
||||
[right_tab_close, _editor_manager.right_tab_close],
|
||||
[others_tab_close, _editor_manager.others_tab_close]
|
||||
]:
|
||||
if !x[0].is_null():
|
||||
if do_connect:
|
||||
if !x[0].is_connected(x[1]):
|
||||
x[0].connect(x[1])
|
||||
else:
|
||||
if x[0].is_connected(x[1]):
|
||||
x[0].disconnect(x[1])
|
||||
func _nws() -> void:
|
||||
print("[Script Splitter] New Splitter System!\nNow use controls in toolbar for split columns and rows as you like!\nPlease provide feedback on the Github issues tab [https://github.com/CodeNameTwister/Script-Splitter]")
|
||||
|
||||
func swap_by_src(from : String, to : String, as_left : bool) -> void:
|
||||
_editor_manager.swap_tab.execute([from, to, as_left])
|
||||
|
||||
func reset_by_control(control : Node) -> void:
|
||||
if _editor_manager:
|
||||
_editor_manager.reset_by_control(control)
|
||||
|
||||
func _clean_settings() -> void:
|
||||
var e : EditorSettings = EditorInterface.get_editor_settings()
|
||||
if e.has_setting("plugin/script_spliter/rows"):
|
||||
_nws()
|
||||
e.set_setting("plugin/script_spliter/rows", null)
|
||||
e.set_setting("plugin/script_spliter/columns", null)
|
||||
e.set_setting("plugin/script_spliter/save_rows_columns_count_on_exit", null)
|
||||
e.set_setting("plugin/script_spliter/window/use_highlight_selected", null)
|
||||
e.set_setting("plugin/script_spliter/window/highlight_selected_color", null)
|
||||
e.set_setting("plugin/script_spliter/editor/split/reopen_last_closed_editor_on_add_split", null)
|
||||
e.set_setting("plugin/script_spliter/editor/split/remember_last_used_editor_buffer_size", null)
|
||||
e.set_setting("plugin/script_spliter/behavior/auto_create_split_by_config", null)
|
||||
e.set_setting("plugin/script_spliter/editor/list/colorize_actives", null)
|
||||
|
||||
for x : String in [
|
||||
"plugin/script_spliter/behaviour/refresh_warnings_on_save"
|
||||
,"plugin/script_spliter/editor/out_focus_color_value"
|
||||
,"plugin/script_spliter/editor/out_focus_color_enabled"
|
||||
,"plugin/script_spliter/editor/minimap_for_unfocus_window"
|
||||
,"plugin/script_spliter/editor/behaviour/expand_on_focus"
|
||||
,"plugin/script_spliter/editor/behaviour/can_expand_on_same_focus"
|
||||
,"plugin/script_spliter/editor/behaviour/smooth_expand"
|
||||
,"plugin/script_spliter/editor/behaviour/smooth_expand_time"
|
||||
,"plugin/script_spliter/editor/behaviour/swap_by_double_click_separator_button"
|
||||
,"plugin/script_spliter/editor/behaviour/back_and_forward/handle_back_and_forward"
|
||||
,"plugin/script_spliter/editor/behaviour/back_and_forward/history_size"
|
||||
,"plugin/script_spliter/editor/behaviour/back_and_forward/using_as_next_and_back_tab"
|
||||
,"plugin/script_spliter/editor/behaviour/back_and_forward/use_native_handler_when_there_are_no_more_tabs"
|
||||
,"plugin/script_spliter/editor/behaviour/back_and_forward/backward_key_button_input"
|
||||
,"plugin/script_spliter/editor/behaviour/back_and_forward/forward_key_button_input"
|
||||
,"plugin/script_spliter/editor/behaviour/back_and_forward/backward_mouse_button_input"
|
||||
,"plugin/script_spliter/editor/behaviour/back_and_forward/forward_mouse_button_input"
|
||||
,"plugin/script_spliter/editor/list/selected_color"
|
||||
,"plugin/script_spliter/editor/list/others_color"
|
||||
,"plugin/script_spliter/editor/tabs/use_old_behaviour"
|
||||
,"plugin/script_spliter/line/size"
|
||||
,"plugin/script_spliter/line/color"
|
||||
,"plugin/script_spliter/line/draggable"
|
||||
,"plugin/script_spliter/line/expand_by_double_click"
|
||||
,"plugin/script_spliter/line/button/size"
|
||||
,"plugin/script_spliter/line/button/modulate"
|
||||
,"plugin/script_spliter/behavior/create_all_open_editors"
|
||||
]:
|
||||
|
||||
if e.has_setting(x):
|
||||
e.set_setting(x.replace("/script_spliter/", "/script_splitter/"), e.get_setting(x))
|
||||
e.set_setting(x, null)
|
||||
|
||||
for x : int in range(1, 11, 1):
|
||||
e.set_setting(str("plugin/script_spliter/input/split_type_" , x), null)
|
||||
|
||||
#for x : int in range(1, 11, 1):
|
||||
#e.set_setting(str("plugin/script_splitter/input/split_type_" , x), null)
|
||||
|
||||
|
||||
func init_1(plugin : EditorPlugin, tab_container : TabContainer, item_list : ItemList) -> void:
|
||||
if !is_instance_valid(plugin) or !is_instance_valid(tab_container):
|
||||
printerr("Error, can`t initalize plugin, not valid references!")
|
||||
return
|
||||
|
||||
_clean_settings()
|
||||
_plugin = plugin
|
||||
_plugin.set_process(true)
|
||||
|
||||
_editor_manager = EditorManager.new(BaseContainer.new(tab_container), BaseList.new(item_list))
|
||||
_editor_manager.update_request.connect(_queue_update)
|
||||
|
||||
var editor : ScriptEditor = EditorInterface.get_script_editor()
|
||||
if editor:
|
||||
if !editor.editor_script_changed.is_connected(_on_change):
|
||||
editor.editor_script_changed.connect(_on_change)
|
||||
|
||||
func _queue_update() -> void:
|
||||
_plugin.set_process(true)
|
||||
1
addons/script_splitter/core/builder.gd.uid
Normal file
1
addons/script_splitter/core/builder.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dge4wucvh6qnb
|
||||
264
addons/script_splitter/core/contex/ssp_window.gd
Normal file
264
addons/script_splitter/core/contex/ssp_window.gd
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
@tool
|
||||
extends EditorContextMenuPlugin
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4f
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
const PLUS_SPLIT = preload("./../../assets/plus_row.svg")
|
||||
const MINUS_SPLIT = preload("./../../assets/minus_row.svg")
|
||||
const SspEditor = preload("./../../core/ui/splitter/editor/ssp_editor.gd")
|
||||
|
||||
var _vsplits : Array[VSplitContainer] = []
|
||||
|
||||
func _translate(_str : String) -> String:
|
||||
# ...
|
||||
return _str
|
||||
|
||||
func _popup_menu(_paths : PackedStringArray) -> void:
|
||||
var sc : ScriptEditor = EditorInterface.get_script_editor()
|
||||
|
||||
if !is_instance_valid(sc.get_current_script()):
|
||||
return
|
||||
|
||||
var ed : ScriptEditorBase = sc.get_current_editor()
|
||||
var be : Control = ed.get_base_editor()
|
||||
|
||||
|
||||
if be is CodeEdit:
|
||||
if !(be.get_parent() is VSplitContainer):
|
||||
add_context_menu_item(_translate("Sub-Split"), _on_sub_split, PLUS_SPLIT)
|
||||
else:
|
||||
add_context_menu_item(_translate("Remove Sub-Split"), _out_sub_split, MINUS_SPLIT)
|
||||
|
||||
func is_handled(cnt : Node) -> bool:
|
||||
return cnt is CodeEdit and cnt.get_parent() is VSplitContainer
|
||||
|
||||
|
||||
func split() -> void:
|
||||
_on_sub_split(null)
|
||||
|
||||
func merge(value : Node) -> void:
|
||||
_out_sub_split(value)
|
||||
|
||||
func _out_sub_split(value : Variant = null) -> void:
|
||||
var be : Control = null
|
||||
if value is CodeEdit:
|
||||
be = value
|
||||
else:
|
||||
var sc : ScriptEditor = EditorInterface.get_script_editor()
|
||||
var ed : ScriptEditorBase = sc.get_current_editor()
|
||||
be= ed.get_base_editor()
|
||||
|
||||
|
||||
if be is CodeEdit:
|
||||
if !is_handled(be):
|
||||
return
|
||||
|
||||
var parent : Node = be.get_parent()
|
||||
var index : int = be.get_index()
|
||||
|
||||
if !is_instance_valid(parent):
|
||||
return
|
||||
|
||||
if parent.get_child_count() > index + 1:
|
||||
var c : Node = parent.get_child(index + 1)
|
||||
if c is CodeEdit:
|
||||
_on_focus(c, be)
|
||||
|
||||
c.queue_free()
|
||||
parent.remove_child(c)
|
||||
else:
|
||||
if index > 0 and parent.get_child_count() > index:
|
||||
var c : Node = parent.get_child(index - 1)
|
||||
if c is CodeEdit:
|
||||
_on_focus(c, be)
|
||||
|
||||
c.queue_free()
|
||||
parent.remove_child(c)
|
||||
|
||||
if parent.get_child_count() == 1:
|
||||
var p : Node = parent.get_parent()
|
||||
if p:
|
||||
for y : Node in parent.get_children():
|
||||
if y.is_queued_for_deletion():
|
||||
continue
|
||||
if y.has_meta(&"RM"):
|
||||
continue
|
||||
if y is CodeEdit:
|
||||
if y.text_changed.is_connected(_on_text_change):
|
||||
y.text_changed.disconnect(_on_text_change)
|
||||
parent.remove_child(y)
|
||||
p.add_child(y)
|
||||
if p.get_child_count() > 1:
|
||||
p.move_child(y, 0)
|
||||
_vsplits.erase(parent)
|
||||
parent.queue_free()
|
||||
|
||||
for x : Node in Engine.get_main_loop().get_nodes_in_group(&"__SCRIPT_SPLITTER__"):
|
||||
if x.has_method(&"_io_call"):
|
||||
x.call(&"_io_call", &"")
|
||||
|
||||
func _on_sub_split(__ : Variant = null) -> void:
|
||||
var sc : ScriptEditor = EditorInterface.get_script_editor()
|
||||
var ed : ScriptEditorBase = sc.get_current_editor()
|
||||
var be : Control = ed.get_base_editor()
|
||||
|
||||
if be is CodeEdit:
|
||||
var parent : Node = be.get_parent()
|
||||
if is_handled(be) or !is_instance_valid(parent):
|
||||
return
|
||||
|
||||
var z : int = 0
|
||||
for x : Node in parent.get_children():
|
||||
if x is CodeEdit:
|
||||
z += 1
|
||||
if z < 2:
|
||||
var vsplit : VSplitContainer = null
|
||||
if be.get_parent() is VSplitContainer:
|
||||
vsplit = be.get_parent()
|
||||
else:
|
||||
vsplit = VSplitContainer.new()
|
||||
var p : Node = be.get_parent()
|
||||
if p:
|
||||
p.remove_child(be)
|
||||
|
||||
parent.add_child(vsplit)
|
||||
parent.move_child(vsplit, 0)
|
||||
vsplit.add_child(be)
|
||||
|
||||
vsplit.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
vsplit.size_flags_vertical= Control.SIZE_EXPAND_FILL
|
||||
|
||||
_vsplits.append(vsplit)
|
||||
|
||||
var ne : CodeEdit = be.duplicate(0)
|
||||
|
||||
ne.set_meta(&"RM", true)
|
||||
ne.set_script(SspEditor)
|
||||
ne.focus_mode = Control.FOCUS_CLICK
|
||||
ne.mouse_filter = Control.MOUSE_FILTER_PASS
|
||||
|
||||
ne.selecting_enabled = false
|
||||
var nodes : Array[Node] = be.get_parent().get_parent().get_parent().find_children("*","MenuButton",true,false)
|
||||
|
||||
for n : Node in nodes:
|
||||
if n is MenuButton:
|
||||
var mp : PopupMenu = n.get_popup()
|
||||
if mp and "%" in (n.get_popup().get_item_text(0)):
|
||||
if n.draw.is_connected(_on_update):
|
||||
n.draw.disconnect(_on_update)
|
||||
n.draw.connect(_on_update.bind(be,ne,n))
|
||||
|
||||
be.text_changed.connect(_on_text_change.bind(be, ne))
|
||||
|
||||
ne.focus_entered.connect(_on_focus.bind(ne, be))
|
||||
ne.gui_input.connect(_on_gui.bind(ne, be))
|
||||
|
||||
_on_text_change(be, ne)
|
||||
vsplit.add_child(ne)
|
||||
|
||||
for x : Node in Engine.get_main_loop().get_nodes_in_group(&"__SCRIPT_SPLITTER__"):
|
||||
if x.has_method(&"_io_call"):
|
||||
x.call(&"_io_call", &"")
|
||||
|
||||
func _on_gui(e : InputEvent, f : CodeEdit, t : CodeEdit) -> void:
|
||||
if t.has_focus():
|
||||
if e.is_pressed():
|
||||
if e is InputEventMouseButton:
|
||||
if e.button_index == MOUSE_BUTTON_LEFT:
|
||||
return
|
||||
_on_focus(f, t)
|
||||
else:
|
||||
if e.is_pressed():
|
||||
if e is InputEventMouseButton:
|
||||
if e.button_index != MOUSE_BUTTON_RIGHT:
|
||||
return
|
||||
_on_focus(f, t)
|
||||
|
||||
|
||||
func _on_update(f : Variant, t : Variant, r : Variant) -> void:
|
||||
if is_instance_valid(f) and is_instance_valid(t):
|
||||
t.set(&"theme_override_font_sizes/font_size", f.get(&"theme_override_font_sizes/font_size"))
|
||||
return
|
||||
if is_instance_valid(r):
|
||||
if r.draw.is_connected(_on_update):
|
||||
r.draw.disconnect(_on_update)
|
||||
|
||||
func _on_focus(f : CodeEdit, t : CodeEdit) -> void:
|
||||
if !is_instance_valid(f) or !is_instance_valid(t):
|
||||
return
|
||||
if f.text != t.text:
|
||||
var sv : float = f.scroll_vertical
|
||||
var sh : int = f.scroll_horizontal
|
||||
f.set(&"text", t.text)
|
||||
f.scroll_vertical = sv
|
||||
f.scroll_horizontal = sh
|
||||
var sv0 : float = f.scroll_vertical
|
||||
var sh0 : int = f.scroll_horizontal
|
||||
var sv1 : float = t.scroll_vertical
|
||||
var sh1 : int = t.scroll_horizontal
|
||||
t.scroll_vertical = sv0
|
||||
t.scroll_horizontal = sh0
|
||||
f.scroll_vertical = sv1
|
||||
f.scroll_horizontal = sh1
|
||||
var index : int = t.get_index()
|
||||
var p : Node = f.get_parent()
|
||||
p.remove_child(f)
|
||||
p.add_child(f)
|
||||
t.grab_focus()
|
||||
|
||||
if p.get_child_count() > index or index == -1:
|
||||
p.move_child(f, index)
|
||||
|
||||
func _on_text_change(ca : CodeEdit, cb : CodeEdit) -> void:
|
||||
if cb.has_method(&"set_text_reference"):
|
||||
cb.call(&"set_text_reference", ca.text)
|
||||
return
|
||||
var sv : float = cb.scroll_vertical
|
||||
var sh : int = cb.scroll_horizontal
|
||||
cb.set(&"text", ca.text)
|
||||
cb.scroll_vertical = sv
|
||||
cb.scroll_horizontal = sh
|
||||
|
||||
func _reorder(index : int, cd : CodeEdit, line : int, column : int) -> void:
|
||||
if cd.get_caret_count() <= index:
|
||||
cd.add_caret(mini(cd.get_line_count(), line), column)
|
||||
return
|
||||
cd.set_caret_line(mini(cd.get_line_count(), line), false, true, 0, index)
|
||||
cd.set_caret_column(column, false, index)
|
||||
|
||||
func _notification(what: int) -> void:
|
||||
if what == NOTIFICATION_PREDELETE:
|
||||
for x : Node in _vsplits:
|
||||
if !is_instance_valid(x):
|
||||
continue
|
||||
var p : Node = x.get_parent()
|
||||
for y : Node in x.get_children():
|
||||
if y.is_queued_for_deletion():
|
||||
continue
|
||||
if y.has_meta(&"RM"):
|
||||
continue
|
||||
if y is CodeEdit:
|
||||
for cn : Dictionary in y.text_changed.get_connections():
|
||||
var callable : Callable = cn["callable"]
|
||||
if !callable.is_valid():
|
||||
y.text_changed.disconnect(callable)
|
||||
|
||||
for n : Node in x.get_parent().get_parent().get_parent().find_children("*","MenuButton",true,false):
|
||||
if n is MenuButton:
|
||||
var mp : PopupMenu = n.get_popup()
|
||||
if mp and "%" in (n.get_popup().get_item_text(0)):
|
||||
for cn : Dictionary in n.draw.get_connections():
|
||||
var callable : Callable = cn["callable"]
|
||||
if !callable.is_valid():
|
||||
n.draw.disconnect(callable)
|
||||
x.remove_child(y)
|
||||
p.add_child(y)
|
||||
if p.get_child_count() > 1:
|
||||
p.move_child(y, 0)
|
||||
x.queue_free()
|
||||
|
||||
1
addons/script_splitter/core/contex/ssp_window.gd.uid
Normal file
1
addons/script_splitter/core/contex/ssp_window.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://cdn4c7qori2ry
|
||||
34
addons/script_splitter/core/contex/window.gd
Normal file
34
addons/script_splitter/core/contex/window.gd
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
@tool
|
||||
extends EditorContextMenuPlugin
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
var CONTEXT : String = "CUSTOM"
|
||||
var ICON : Texture = null
|
||||
var SHORTCUT : Shortcut = null
|
||||
var CALLABLE : Callable
|
||||
var VALIDATOR : Callable
|
||||
|
||||
func _init(context : String, handle : Callable, validator : Callable, icon : Texture, input_key : Array[InputEvent] = []):
|
||||
CONTEXT = context
|
||||
CALLABLE = handle
|
||||
ICON = icon
|
||||
VALIDATOR = validator
|
||||
if input_key.size() > 0:
|
||||
SHORTCUT = Shortcut.new()
|
||||
SHORTCUT.events = input_key
|
||||
add_menu_shortcut(SHORTCUT, handle)
|
||||
|
||||
func _popup_menu(paths : Variant) -> void:
|
||||
if VALIDATOR.is_valid():
|
||||
if !VALIDATOR.call(paths):
|
||||
return
|
||||
if SHORTCUT:
|
||||
add_context_menu_item_from_shortcut(CONTEXT, SHORTCUT, ICON)
|
||||
else:
|
||||
if CALLABLE.is_valid():
|
||||
add_context_menu_item(CONTEXT, CALLABLE, ICON)
|
||||
1
addons/script_splitter/core/contex/window.gd.uid
Normal file
1
addons/script_splitter/core/contex/window.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://cblflkellpdqg
|
||||
23
addons/script_splitter/core/editor/app.gd
Normal file
23
addons/script_splitter/core/editor/app.gd
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
@tool
|
||||
extends RefCounted
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
const MickeyTool = preload("./../../core/editor/tools/magic/mickey_tool.gd")
|
||||
const ToolDB = preload("./../../core/editor/database/tool_db.gd")
|
||||
const Manager = preload("./../../core/editor/godot/manager.gd")
|
||||
|
||||
var _tool_db : ToolDB = null
|
||||
var _manager : Manager = null
|
||||
|
||||
func _init(manager : Manager, tool_db : ToolDB) -> void:
|
||||
_manager = manager
|
||||
_tool_db = tool_db
|
||||
|
||||
func execute(_value : Variant = null) -> bool:
|
||||
return false
|
||||
1
addons/script_splitter/core/editor/app.gd.uid
Normal file
1
addons/script_splitter/core/editor/app.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://b5denwbu6twf4
|
||||
104
addons/script_splitter/core/editor/application/create_tool.gd
Normal file
104
addons/script_splitter/core/editor/application/create_tool.gd
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
@tool
|
||||
extends "./../../../core/editor/app.gd"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
const EditorTool = preload("./../../../core/editor/tools/editor_tool.gd")
|
||||
|
||||
const HelperEditorTool = preload("./../../../core/editor/tools/helper_editor_tool.gd")
|
||||
const ScriptEditorTool = preload("./../../../core/editor/tools/script_editor_tool.gd")
|
||||
const TextEditorTool = preload("./../../../core/editor/tools/text_editor_tool.gd")
|
||||
|
||||
var _tools : Array[EditorTool] = [
|
||||
ScriptEditorTool.new(),
|
||||
HelperEditorTool.new(),
|
||||
TextEditorTool.new()
|
||||
]
|
||||
|
||||
func execute(value : Variant = null) -> bool:
|
||||
if !is_instance_valid(value) or !(value is Control):
|
||||
return true
|
||||
|
||||
var control : Control = value
|
||||
|
||||
if !control.is_node_ready() or !control.is_inside_tree():
|
||||
return false
|
||||
|
||||
for x : MickeyTool in _tool_db.get_tools():
|
||||
if x.has(control):
|
||||
x.set_queue_free(false)
|
||||
return true
|
||||
|
||||
var index : int = control.get_index()
|
||||
if !_manager.is_valid_item_index(index):
|
||||
return false
|
||||
|
||||
var root : Node = _get_root()
|
||||
|
||||
if is_instance_valid(root):
|
||||
var mt : MickeyTool = _tools[0].build(control)
|
||||
var is_editor : bool = _is_editor(mt, control)
|
||||
|
||||
if !is_editor:
|
||||
for z : int in range(1, _tools.size(), 1):
|
||||
var x : EditorTool = _tools[z]
|
||||
mt = x.build(control)
|
||||
|
||||
if mt != null:
|
||||
break
|
||||
|
||||
if mt != null:
|
||||
mt.focus.connect(_manager.focus_tool)
|
||||
mt.new_symbol.connect(_manager.set_symbol)
|
||||
mt.clear.connect(_manager.clear_editors)
|
||||
mt.ochorus(root)
|
||||
|
||||
_tool_db.append(mt)
|
||||
|
||||
_manager.tool_created()
|
||||
_manager.update_metadata(mt)
|
||||
|
||||
mt.trigger_focus()
|
||||
return false
|
||||
|
||||
if is_editor:
|
||||
return true
|
||||
|
||||
printerr("Error!, Can not build control for ", control.name)
|
||||
return false
|
||||
|
||||
func _is_editor(mt : MickeyTool, control : Control) -> bool:
|
||||
if is_instance_valid(mt):
|
||||
return true
|
||||
|
||||
if control is ScriptEditorBase:
|
||||
var sce : ScriptEditor = EditorInterface.get_script_editor()
|
||||
if sce and control in sce.get_open_script_editors():
|
||||
if control.name.begins_with("@"):
|
||||
if !("Script" in control.name):
|
||||
return false
|
||||
return true
|
||||
return _manager.get_editor_list().get_item_tooltip(control.get_index()).is_empty()
|
||||
|
||||
return false
|
||||
|
||||
func _get_root() -> Node:
|
||||
var root : Node = _manager.get_current_root()
|
||||
if !is_instance_valid(root):
|
||||
var splitters : Array[Node] = _manager.get_base_container().get_all_splitters()
|
||||
if splitters.size() == 0:
|
||||
for x : MickeyTool in _tool_db.get_tools():
|
||||
x.reset()
|
||||
_manager.get_base_container().initialize_editor_container()
|
||||
root = _manager.get_current_root()
|
||||
else:
|
||||
for x : Node in splitters:
|
||||
if is_instance_valid(x) and !x.is_queued_for_deletion():
|
||||
root = x
|
||||
break
|
||||
return root
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://bsrituhgnfbm
|
||||
162
addons/script_splitter/core/editor/application/custom_split.gd
Normal file
162
addons/script_splitter/core/editor/application/custom_split.gd
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
@tool
|
||||
extends "./../../../core/editor/app.gd"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
const BaseContainer = preload("./../../../core/base/container.gd")
|
||||
const SpliterItem = preload("./../../../core/ui/multi_split_container/split_container_item.gd")
|
||||
|
||||
func execute(value : Variant = null) -> bool:
|
||||
if value is Array:
|
||||
if value.size() == 3:
|
||||
if value[0] is Container and value[1] is int and value[2] is StringName:
|
||||
var from : Container = value[0]
|
||||
var index : int = value[1]
|
||||
var type : StringName = value[2]
|
||||
|
||||
if from is BaseContainer.SplitterContainer.SplitterEditorContainer.Editor:
|
||||
for x : MickeyTool in _tool_db.get_tools():
|
||||
if x.is_valid():
|
||||
|
||||
if x.get_root() == from and x.get_control().get_index() == index:
|
||||
if type == &"LEFT":
|
||||
|
||||
var c : Node = _manager.get_base_container().get_container_item(x.get_root())
|
||||
var cindex : int = 0
|
||||
|
||||
if !c:
|
||||
return false
|
||||
cindex = c.get_index()
|
||||
|
||||
_manager.split_column.execute(x)
|
||||
|
||||
if !c.is_node_ready():
|
||||
await c.ready
|
||||
|
||||
c = _manager.get_base_container().get_container_item(x.get_root())
|
||||
|
||||
if is_instance_valid(c):
|
||||
if cindex > -1 and cindex < c.get_parent().get_child_count() and c.get_index() != cindex:
|
||||
c.get_parent().move_child.call_deferred(c, cindex)
|
||||
|
||||
elif type == &"RIGHT":
|
||||
var c : Node = _manager.get_base_container().get_container_item(x.get_root())
|
||||
var cindex : int = 0
|
||||
|
||||
if !c:
|
||||
return false
|
||||
|
||||
cindex = c.get_index() + 1
|
||||
|
||||
_manager.split_column.execute(x)
|
||||
|
||||
if !c.is_node_ready():
|
||||
await c.ready
|
||||
|
||||
c = _manager.get_base_container().get_container_item(x.get_root())
|
||||
|
||||
if is_instance_valid(c):
|
||||
if cindex > -1 and cindex < c.get_parent().get_child_count() and c.get_index() != cindex:
|
||||
c.get_parent().move_child.call_deferred(c, cindex)
|
||||
|
||||
elif type == &"TOP":
|
||||
var c : Node = _manager.get_base_container().get_container(x.get_root())
|
||||
var cindex : int = 0
|
||||
if !c:
|
||||
return false
|
||||
|
||||
var root : Node = c.get_parent()
|
||||
|
||||
if !root:
|
||||
return false
|
||||
|
||||
cindex = root.get_index()
|
||||
|
||||
_manager.split_row.execute(x)
|
||||
|
||||
if !c.is_node_ready():
|
||||
await c.ready
|
||||
|
||||
c = _manager.get_base_container().get_container_item(x.get_root())
|
||||
|
||||
if is_instance_valid(c):
|
||||
var row : Node = c
|
||||
for __ : int in range(0, 2, 1):
|
||||
row = c.get_parent()
|
||||
|
||||
if !is_instance_valid(row):
|
||||
break
|
||||
|
||||
if is_instance_valid(row):
|
||||
var has : bool = false
|
||||
for ___ : int in range(0, 3, 1):
|
||||
if has:
|
||||
break
|
||||
for __ : int in range(0, 3, 1):
|
||||
await Engine.get_main_loop().process_frame
|
||||
if is_instance_valid(row) and is_instance_valid(c):
|
||||
var _root : Node = c.get_parent()
|
||||
if row.has_node(_root.get_path()) :
|
||||
has = true
|
||||
break
|
||||
|
||||
if has and c and cindex > -1:
|
||||
for __ : int in range(0, 2, 1):
|
||||
c = c.get_parent()
|
||||
if !c:
|
||||
return false
|
||||
root = c.get_parent()
|
||||
if root and cindex < root.get_child_count() and c.get_index() != cindex:
|
||||
root.move_child(c, cindex)
|
||||
return true
|
||||
|
||||
elif type == &"BOTTOM":
|
||||
_manager.split_row.execute(x)
|
||||
|
||||
var c : Node = _manager.get_base_container().get_container(x.get_root())
|
||||
var cindex : int = 0
|
||||
|
||||
if !c:
|
||||
return false
|
||||
|
||||
if !c.is_node_ready():
|
||||
await c.ready
|
||||
|
||||
cindex = c.get_index() + 1
|
||||
|
||||
if c.get_index() < c.get_parent().get_child_count() - 1:
|
||||
if is_instance_valid(c):
|
||||
var row : Node = c
|
||||
for __ : int in range(0, 2, 1):
|
||||
row = c.get_parent()
|
||||
if !is_instance_valid(row):
|
||||
break
|
||||
|
||||
if is_instance_valid(row):
|
||||
var z : int = c.get_index()
|
||||
if z > 0:
|
||||
var has : bool = false
|
||||
for ___ : int in range(0, 3, 1):
|
||||
if has:
|
||||
break
|
||||
for __ : int in range(0, 3, 1):
|
||||
await Engine.get_main_loop().process_frame
|
||||
if is_instance_valid(row) and is_instance_valid(c):
|
||||
var _root : Node = c.get_parent()
|
||||
if row.has_node(_root.get_path()) and _root is SpliterItem:
|
||||
has = true
|
||||
break
|
||||
if has and c and cindex > -1:
|
||||
for __ : int in range(0, 2, 1):
|
||||
c = c.get_parent()
|
||||
if !c:
|
||||
return false
|
||||
var root : Node = c.get_parent()
|
||||
if root and cindex < root.get_child_count() and c.get_index() != cindex:
|
||||
root.move_child(c, cindex)
|
||||
return true
|
||||
return false
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://dgqwhcax1guja
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
@tool
|
||||
extends "./../../../core/editor/app.gd"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
#Override app function.
|
||||
func execute(value : Variant = null) -> bool:
|
||||
if value is Array:
|
||||
if value.size() > 1:
|
||||
if value[0] is TabContainer and value[1] is int:
|
||||
var control : TabContainer = value[0]
|
||||
var index : int = value[1]
|
||||
for x : MickeyTool in _tool_db.get_tools():
|
||||
if is_instance_valid(x):
|
||||
if x.get_root() == control:
|
||||
if x.get_control().get_index() == index:
|
||||
x.trigger_focus()
|
||||
return true
|
||||
return false
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://bipvmrq4th30m
|
||||
114
addons/script_splitter/core/editor/application/focus_tool.gd
Normal file
114
addons/script_splitter/core/editor/application/focus_tool.gd
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
@tool
|
||||
extends "./../../../core/editor/app.gd"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
const BaseList = preload("./../../../core/base/list.gd")
|
||||
|
||||
var unfocus_enabled : bool = true
|
||||
var unfocus_color : Color = Color.DARK_GRAY
|
||||
|
||||
func _init(manager : Manager, tool_db : ToolDB) -> void:
|
||||
super(manager, tool_db)
|
||||
_setup()
|
||||
|
||||
func _notification(what: int) -> void:
|
||||
if what == NOTIFICATION_PREDELETE:
|
||||
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
||||
if settings.settings_changed.is_connected(_on_change):
|
||||
settings.settings_changed.disconnect(_on_change)
|
||||
|
||||
func _on_change() -> void:
|
||||
var dt : Array = ["plugin/script_splitter/editor/out_focus_color_enabled","plugin/script_splitter/editor/out_focus_color_value"]
|
||||
|
||||
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
||||
var changes : PackedStringArray = settings.get_changed_settings()
|
||||
|
||||
for c in changes:
|
||||
if c in dt:
|
||||
_setup()
|
||||
var current : Node = _manager.get_base_container().get_current_container()
|
||||
for x : MickeyTool in _tool_db.get_tools():
|
||||
if x.is_valid():
|
||||
var root : Control = x.get_root()
|
||||
if root.modulate != Color.WHITE:
|
||||
if unfocus_enabled:
|
||||
root.modulate = unfocus_color
|
||||
else:
|
||||
root.modulate = Color.WHITE
|
||||
elif unfocus_enabled:
|
||||
if is_instance_valid(current):
|
||||
if x.get_root() != current:
|
||||
root.modulate = unfocus_color
|
||||
break
|
||||
|
||||
func _setup() -> void:
|
||||
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
||||
if !settings.settings_changed.is_connected(_on_change):
|
||||
settings.settings_changed.connect(_on_change)
|
||||
|
||||
for x : Array in [
|
||||
["unfocus_enabled", "plugin/script_splitter/editor/out_focus_color_enabled"]
|
||||
,["unfocus_color", "plugin/script_splitter/editor/out_focus_color_value"]
|
||||
]:
|
||||
if settings.has_setting(x[1]):
|
||||
set(x[0], settings.get_setting(x[1]))
|
||||
else:
|
||||
settings.set_setting(x[1], get(x[0]))
|
||||
|
||||
func execute(value : Variant = null) -> bool:
|
||||
if value is ScriptEditorBase:
|
||||
var control : Control = value.get_base_editor()
|
||||
for x : MickeyTool in _tool_db.get_tools():
|
||||
if x.has(control):
|
||||
value = x
|
||||
break
|
||||
if value is MickeyTool:
|
||||
var index : int = value.get_index()
|
||||
var editor_list : BaseList = _manager.get_editor_list()
|
||||
if editor_list.item_count() > index and index > -1:
|
||||
var control : Node = value.get_control()
|
||||
var root : Node = value.get_root()
|
||||
if root is TabContainer:
|
||||
var base : Manager.BaseContainer = _manager.get_base_container()
|
||||
var _index : int = control.get_index()
|
||||
if root.current_tab != _index and _index > -1 and _index < root.get_tab_count():
|
||||
if root.has_method(&"set_tab"):
|
||||
root.call(&"set_tab", _index)
|
||||
else:
|
||||
root.set(&"current_tab", _index)
|
||||
|
||||
var container : Control = base.get_current_container()
|
||||
if is_instance_valid(container) and unfocus_enabled:
|
||||
container.modulate = unfocus_color
|
||||
|
||||
base.set_current_container(root)
|
||||
|
||||
if is_instance_valid(root):
|
||||
root.modulate = Color.WHITE
|
||||
|
||||
var new_container : Node = base.get_container(root)
|
||||
if is_instance_valid(new_container) and new_container.has_method(&"expand_splited_container"):
|
||||
new_container.call(&"expand_splited_container", base.get_container_item(root))
|
||||
|
||||
if is_instance_valid(container):
|
||||
container = base.get_container(container)
|
||||
if is_instance_valid(container) and container != new_container and container.has_method(&"expand_splited_container"):
|
||||
container.call(&"expand_splited_container", null)
|
||||
|
||||
var grant_conainer : Node = base.get_editor_root_container(new_container)
|
||||
if is_instance_valid(grant_conainer):
|
||||
var parent : Node = grant_conainer.get_parent()
|
||||
if is_instance_valid(parent) and parent.has_method(&"expand_splited_container"):
|
||||
parent.call(&"expand_splited_container", base.get_editor_root_container(new_container))
|
||||
|
||||
if !editor_list.is_selected(index):
|
||||
editor_list.select(index)
|
||||
|
||||
_manager.io.update()
|
||||
_manager.get_editor_list().updated.emit()
|
||||
return false
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://bk4jykdijx7sj
|
||||
256
addons/script_splitter/core/editor/application/io.gd
Normal file
256
addons/script_splitter/core/editor/application/io.gd
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
@tool
|
||||
extends "./../../../core/editor/app.gd"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
const BaseList = preload("./../../../core/base/list.gd")
|
||||
const EDITOR = preload("./../../../core/ui/window/editor.tscn")
|
||||
|
||||
var expanded : bool = false
|
||||
var _updating : bool = false
|
||||
|
||||
func update() -> void:
|
||||
if _updating:
|
||||
return
|
||||
_updating = true
|
||||
_update.call_deferred()
|
||||
|
||||
func _update() -> void:
|
||||
var base : Manager.BaseContainer = _manager.get_base_container()
|
||||
var container : Node = base.get_current_container()
|
||||
if is_instance_valid(container):
|
||||
if expanded:
|
||||
var cb : Node = base.get_container_item(container)
|
||||
var ct : Array[Node] = container.get_tree().get_nodes_in_group(&"__SP_BR__")
|
||||
for x : Node in container.get_tree().get_nodes_in_group(&"__SP_IC__"):
|
||||
var v : bool = cb == x
|
||||
for y : Node in x.get_children():
|
||||
if y is Control:
|
||||
y.visible = v
|
||||
|
||||
for __ : int in range(0, 2, 1):
|
||||
for x : Node in ct:
|
||||
if x is Control:
|
||||
var v : bool = false
|
||||
for y : Node in x.get_children():
|
||||
if y is Control and y.visible:
|
||||
v = true
|
||||
break
|
||||
x.visible = v
|
||||
|
||||
var can_split : bool = _can_split(container)
|
||||
var can_merge_column : bool = _can_merge_column(base)
|
||||
var can_merge_row : bool = _can_merge_row(base)
|
||||
var can_sub_split : int = _sub()
|
||||
var can_make_float : bool = (container.get_parent() is VBoxContainer)
|
||||
|
||||
for x : Node in (Engine.get_main_loop()).get_nodes_in_group(&"__script_splitter__IO__"):
|
||||
x.enable(&"SPLIT_COLUMN",can_split)
|
||||
x.enable(&"MERGE_COLUMN",can_merge_column)
|
||||
x.enable(&"SPLIT_ROW",can_split)
|
||||
x.enable(&"MERGE_ROW",can_merge_row)
|
||||
x.enable(&"SPLIT_SUB", can_sub_split == 0)
|
||||
x.enable(&"MERGE_SPLIT_SUB", can_sub_split == 1)
|
||||
x.enable(&"MAKE_FLOATING", can_make_float)
|
||||
|
||||
_updating = false
|
||||
|
||||
func _can_split(container : Node) -> bool:
|
||||
return container != null and container.get_child_count() > 1
|
||||
|
||||
func _can_merge_column(base : Manager.BaseContainer) -> bool:
|
||||
return base != null and base.get_current_splitters().size() > 1
|
||||
|
||||
func _can_merge_row(base : Manager.BaseContainer) -> bool:
|
||||
return base != null and base.get_all_containers().size() > 1
|
||||
|
||||
func _sub() -> int:
|
||||
var sc : ScriptEditor = EditorInterface.get_script_editor()
|
||||
|
||||
if !is_instance_valid(sc.get_current_script()):
|
||||
return -1
|
||||
|
||||
var ed : ScriptEditorBase = sc.get_current_editor()
|
||||
var be : Control = ed.get_base_editor()
|
||||
|
||||
|
||||
if be is CodeEdit:
|
||||
if be.get_parent() is VSplitContainer:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
return -1
|
||||
|
||||
func _on_pin(btn : Button) -> void:
|
||||
var st : String = btn.get_meta(&"I")
|
||||
if st.is_empty():
|
||||
btn.queue_free()
|
||||
return
|
||||
|
||||
var bl : Manager.BaseList = _manager.get_editor_list()
|
||||
for x : int in bl.item_count():
|
||||
if st == bl.get_item_tooltip(x):
|
||||
bl.select(x)
|
||||
return
|
||||
|
||||
func _make_pin(tree : SceneTree, fn : String, tp : String, icn : Texture2D, mod : Color) -> void:
|
||||
if mod == Color.BLACK:
|
||||
mod = Color.WHITE
|
||||
for x : Node in tree.get_nodes_in_group(&"__SP_PIN_ROOT__"):
|
||||
var btn : Button = Button.new()
|
||||
btn.text = fn
|
||||
btn.icon = icn
|
||||
btn.set_meta(&"I", tp)
|
||||
btn.pressed.connect(_on_pin.bind(btn))
|
||||
btn.add_to_group(&"__SP_B_PIN__")
|
||||
btn.set(&"theme_override_colors/icon_normal_color", mod)
|
||||
btn.set(&"theme_override_colors/icon_focus_color", mod)
|
||||
btn.set(&"theme_override_colors/icon_pressed_color", mod)
|
||||
btn.set(&"theme_override_colors/icon_hover_color", mod)
|
||||
btn.set(&"theme_override_colors/icon_hover_pressed_color", mod)
|
||||
btn.set(&"theme_override_colors/icon_disabled_color", mod)
|
||||
btn.set(&"theme_override_font_sizes/font_size", 12.0)
|
||||
x.add_child(btn)
|
||||
|
||||
func _remove_pin(tree : SceneTree, tp : String) -> bool:
|
||||
for x : Node in tree.get_nodes_in_group(&"__SP_PIN_ROOT__"):
|
||||
if x.has_meta(&"I"):
|
||||
if x.get_meta(&"I") == tp:
|
||||
x.queue_free()
|
||||
return true
|
||||
return false
|
||||
|
||||
func execute(value : Variant = null) -> bool:
|
||||
if value == null:
|
||||
update()
|
||||
return true
|
||||
|
||||
if value is StringName:
|
||||
if value.is_empty():
|
||||
update()
|
||||
return true
|
||||
|
||||
var base : Manager.BaseContainer = _manager.get_base_container()
|
||||
var container : Node = base.get_current_container()
|
||||
|
||||
var id : StringName = value
|
||||
|
||||
match id:
|
||||
&"EXPAND":
|
||||
if is_instance_valid(container):
|
||||
var ct : Array[Node] = container.get_tree().get_nodes_in_group(&"__SP_BR__")
|
||||
if expanded:
|
||||
for x : Node in container.get_tree().get_nodes_in_group(&"__SP_IC__"):
|
||||
for y : Node in x.get_children():
|
||||
if y is Control:
|
||||
y.visible = true
|
||||
for x : Node in ct:
|
||||
if x is Control:
|
||||
x.visible = true
|
||||
else:
|
||||
var cb : Node = base.get_container_item(container)
|
||||
for x : Node in container.get_tree().get_nodes_in_group(&"__SP_IC__"):
|
||||
var v : bool = cb == x
|
||||
for y : Node in x.get_children():
|
||||
if y is Control:
|
||||
y.visible = v
|
||||
|
||||
for __ : int in range(0, 2, 1):
|
||||
for x : Node in ct:
|
||||
if x is Control:
|
||||
var v : bool = false
|
||||
for y : Node in x.get_children():
|
||||
if y is Control and y.visible:
|
||||
v = true
|
||||
break
|
||||
x.visible = v
|
||||
|
||||
expanded = !expanded
|
||||
|
||||
for x : Node in container.get_tree().get_nodes_in_group(&"__script_splitter__IO__"):
|
||||
if x.has_method(&"get_button"):
|
||||
var button : Button = x.call(&"get_button", id)
|
||||
if is_instance_valid(button):
|
||||
if expanded:
|
||||
button.modulate = Color.GREEN
|
||||
else:
|
||||
button.modulate = Color.WHITE
|
||||
|
||||
return true
|
||||
&"PIN":
|
||||
for x : MickeyTool in _tool_db.get_tools():
|
||||
if x.get_root() == container:
|
||||
if container is TabContainer:
|
||||
if container.current_tab == x.get_control().get_index():
|
||||
var list : Manager.BaseList = _manager.get_editor_list()
|
||||
var idx : int = x.get_index()
|
||||
|
||||
if list.item_count() > idx and idx > -1:
|
||||
var nm : String = list.get_item_text(idx)
|
||||
var ps : String = list.get_item_tooltip(idx)
|
||||
|
||||
if _remove_pin(container.get_tree(), ps):
|
||||
return true
|
||||
|
||||
_make_pin(container.get_tree(), nm, ps, list.get_item_icon(idx), list.get_item_icon_modulate(idx))
|
||||
&"SPLIT_COLUMN":
|
||||
if _can_split(container):
|
||||
_manager.split_column.execute()
|
||||
&"SPLIT_ROW":
|
||||
if _can_split(container):
|
||||
_manager.split_row.execute()
|
||||
&"MERGE_COLUMN":
|
||||
if _can_merge_column(base):
|
||||
_manager.merge_tool.execute([null, false])
|
||||
&"MERGE_ROW":
|
||||
if _can_merge_row(base):
|
||||
_manager.merge_tool.execute([null, true])
|
||||
&"SPLIT_SUB":
|
||||
if _sub() == 0:
|
||||
for x : Node in Engine.get_main_loop().get_nodes_in_group(&"__SCRIPT_SPLITTER__"):
|
||||
x.script_split()
|
||||
break
|
||||
&"MERGE_SPLIT_SUB":
|
||||
if _sub() == 1:
|
||||
for x : Node in Engine.get_main_loop().get_nodes_in_group(&"__SCRIPT_SPLITTER__"):
|
||||
x.script_merge()
|
||||
break
|
||||
&"MAKE_FLOATING":
|
||||
if (container.get_parent() is VBoxContainer):
|
||||
for x : ToolDB.MickeyTool in _tool_db.get_tools():
|
||||
if x.has(container):
|
||||
var y : Node = (_manager._base_container._editor_container.get_parent())
|
||||
var new_window : Window = EDITOR.instantiate()
|
||||
y.add_child(new_window)
|
||||
|
||||
var root : Node = new_window.call(&"get_root")
|
||||
root.initialize(null, _manager.get_base_container())
|
||||
root.initialize_editor_contianer()
|
||||
|
||||
var _root : Node = x.get_root()
|
||||
|
||||
x.ochorus(root.call(&"get_current_editor"))
|
||||
|
||||
if _root.get_child_count() < 1:
|
||||
var item : Node = _manager.get_base_container().get_container_item(_root)
|
||||
if item.get_child_count() == 1:
|
||||
var cont : Node = _manager.get_base_container().get_container(_root)
|
||||
if cont.get_child_count() == 1:
|
||||
cont.queue_free()
|
||||
else:
|
||||
item.queue_free()
|
||||
else:
|
||||
if _root.get_parent() is VBoxContainer:
|
||||
_root.get_parent().queue_free()
|
||||
else:
|
||||
_root.queue_free()
|
||||
|
||||
new_window.setup()
|
||||
new_window.update()
|
||||
_manager.update()
|
||||
return false
|
||||
return false
|
||||
1
addons/script_splitter/core/editor/application/io.gd.uid
Normal file
1
addons/script_splitter/core/editor/application/io.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dqgve5bbg0w1m
|
||||
91
addons/script_splitter/core/editor/application/merge_tool.gd
Normal file
91
addons/script_splitter/core/editor/application/merge_tool.gd
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
@tool
|
||||
extends "./../../../core/editor/app.gd"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
func _get_tool(value : Variant) -> MickeyTool:
|
||||
var container : MickeyTool = null
|
||||
|
||||
if value == null:
|
||||
container = _tool_db.get_by_reference(_manager.get_base_container().get_current_container())
|
||||
elif value is Node:
|
||||
container = _tool_db.get_by_reference(value)
|
||||
elif value is Resource:
|
||||
var list : ItemList = _manager.get_editor_list().get_editor_list()
|
||||
var pth : String = value.resource_path
|
||||
for x : int in list.item_count:
|
||||
if pth == list.get_item_tooltip(x):
|
||||
container = _tool_db.get_tool_id(x)
|
||||
break
|
||||
elif value is String:
|
||||
var list : ItemList = _manager.get_editor_list().get_editor_list()
|
||||
var pth : String = value
|
||||
for x : int in list.item_count:
|
||||
if pth == list.get_item_tooltip(x):
|
||||
container = _tool_db.get_tool_id(x)
|
||||
break
|
||||
|
||||
return container
|
||||
|
||||
func execute(value : Variant = null) -> bool:
|
||||
if value is Array:
|
||||
var mk : MickeyTool = _get_tool(value[0])
|
||||
|
||||
if is_instance_valid(mk) and value[1] is bool:
|
||||
if mk and mk.is_valid():
|
||||
var root : Node = mk.get_root()
|
||||
var control : Node = root
|
||||
if control.is_in_group(&"__SC_SPLITTER__"):
|
||||
var cbase : Manager.BaseContainer = _manager.get_base_container()
|
||||
if value[1]:
|
||||
control = cbase.get_container(control)
|
||||
for x : MickeyTool in _tool_db.get_tools():
|
||||
if x.is_valid():
|
||||
var node : Control = x.get_root()
|
||||
if control == cbase.get_container(node):
|
||||
x.reset()
|
||||
control.queue_free()
|
||||
else:
|
||||
for x : MickeyTool in _tool_db.get_tools():
|
||||
if x.is_valid():
|
||||
var node : Control = x.get_root()
|
||||
if node:
|
||||
if node == control:
|
||||
x.reset()
|
||||
else:
|
||||
x.reset()
|
||||
|
||||
var base : Manager.BaseContainer = _manager.get_base_container()
|
||||
|
||||
if root == base.get_current_container():
|
||||
var nodes : Array[Node] = control.get_tree().get_nodes_in_group(&"__SC_SPLITTER__")
|
||||
var container : Node = base.get_container_item(root)
|
||||
|
||||
for n : Node in nodes:
|
||||
if n == root:
|
||||
continue
|
||||
var _container : Node = base.get_container_item(n)
|
||||
if _container.get_parent() == container.get_parent():
|
||||
var i0 : int = _container.get_index()
|
||||
var i1 : int = container.get_index()
|
||||
if i0 == i1 - 1 or i0 == i1 + 1:
|
||||
base.set_current_container(n)
|
||||
return true
|
||||
|
||||
var z : int = nodes.find(root)
|
||||
if z != -1:
|
||||
if z == 0:
|
||||
if nodes.size() > 1:
|
||||
base.set_current_container(nodes[1])
|
||||
else:
|
||||
if nodes.size() > 1:
|
||||
base.set_current_container(nodes[z - 1])
|
||||
return true
|
||||
#if control.get_child_count() == 0 or root.get_child_count() == 0:
|
||||
#control.queue_free()
|
||||
return false
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://cf43swgi3ydv8
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
@tool
|
||||
extends "./../../../core/editor/app.gd"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
var _refreshing : bool = true
|
||||
|
||||
func _init(manager : Manager, tool_db : ToolDB) -> void:
|
||||
super(manager, tool_db)
|
||||
_setup()
|
||||
|
||||
func _notification(what: int) -> void:
|
||||
if what == NOTIFICATION_PREDELETE:
|
||||
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
||||
if settings.settings_changed.is_connected(_on_change):
|
||||
settings.settings_changed.disconnect(_on_change)
|
||||
|
||||
func _on_change() -> void:
|
||||
var dt : Array = ["plugin/script_splitter/behaviour/refresh_warnings_on_save"]
|
||||
|
||||
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
||||
var changes : PackedStringArray = settings.get_changed_settings()
|
||||
|
||||
for c in changes:
|
||||
if c in dt:
|
||||
_setup()
|
||||
break
|
||||
|
||||
func _setup() -> void:
|
||||
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
||||
if !settings.settings_changed.is_connected(_on_change):
|
||||
settings.settings_changed.connect(_on_change)
|
||||
|
||||
for x : Array in [
|
||||
["_refreshing", "plugin/script_splitter/behaviour/refresh_warnings_on_save"]
|
||||
]:
|
||||
if settings.has_setting(x[1]):
|
||||
set(x[0], settings.get_setting(x[1]))
|
||||
else:
|
||||
settings.set_setting(x[1], get(x[0]))
|
||||
|
||||
func execute(_value : Variant = null) -> bool:
|
||||
if !_refreshing:
|
||||
return true
|
||||
|
||||
var sp : Array[Node] = Engine.get_main_loop().get_nodes_in_group(&"__SC_SPLITTER__")
|
||||
var current : Control = _manager.get_base_container().get_current_container()
|
||||
|
||||
var ctool : MickeyTool = null
|
||||
var ltool : MickeyTool = null
|
||||
|
||||
if sp.size() < 2:
|
||||
return true
|
||||
|
||||
for x : Variant in _tool_db.get_tools():
|
||||
if is_instance_valid(x):
|
||||
if x.is_valid():
|
||||
var i : int = sp.find(x.get_root())
|
||||
var container : Node = sp[i]
|
||||
if container is TabContainer:
|
||||
var indx : int = x.get_control().get_index()
|
||||
if container.current_tab == indx:
|
||||
if container == current:
|
||||
ctool = x
|
||||
ltool = x
|
||||
_manager.select_editor_by_index(x.get_index())
|
||||
|
||||
|
||||
if is_instance_valid(ctool) and ctool != ltool:
|
||||
_manager.select_editor_by_index(ctool.get_index())
|
||||
|
||||
return true
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://c0wasvo7fwcqr
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
@tool
|
||||
extends "./../../../core/editor/app.gd"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
func execute(value : Variant = null) -> bool:
|
||||
if value is Array:
|
||||
var control : Control = value[0]
|
||||
var index : int = value[1]
|
||||
|
||||
if index < 0:
|
||||
return false
|
||||
|
||||
for x : MickeyTool in _tool_db.get_tools():
|
||||
if x.get_root() == control and x.get_control().get_index() == index:
|
||||
var _index : int = x.get_index()
|
||||
x.reset()
|
||||
_manager.get_editor_list().remove(_index)
|
||||
return true
|
||||
return false
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://bht1hix6hophq
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
@tool
|
||||
extends "./../../../core/editor/app.gd"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
func execute(value : Variant = null) -> bool:
|
||||
if value is Array:
|
||||
if value[0] is Control and value[1] is int:
|
||||
if value[1] < 0:
|
||||
return false
|
||||
for x : MickeyTool in _tool_db.get_tools():
|
||||
if x.get_index() == value[1]:
|
||||
if x.is_valid():
|
||||
x.ochorus(value[0])
|
||||
return true
|
||||
return false
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://ckvujn0hnsm11
|
||||
30
addons/script_splitter/core/editor/application/rmb_menu.gd
Normal file
30
addons/script_splitter/core/editor/application/rmb_menu.gd
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
@tool
|
||||
extends "./../../../core/editor/app.gd"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
func execute(value : Variant = null) -> bool:
|
||||
if value is Array:
|
||||
var idx : int = value[0]
|
||||
var node : Node = value[1]
|
||||
|
||||
if idx < 0:
|
||||
return false
|
||||
|
||||
for x : MickeyTool in _tool_db.get_tools():
|
||||
if x.get_root() == node:
|
||||
if x.get_control().get_index() == idx:
|
||||
var list : Manager.BaseList = _manager.get_editor_list()
|
||||
var indx : int = x.get_index()
|
||||
if list.item_count() > indx and indx > -1:
|
||||
var el : ItemList = list.get_editor_list()
|
||||
el.item_clicked.emit(indx,el.get_local_mouse_position(), MOUSE_BUTTON_RIGHT)
|
||||
|
||||
return true
|
||||
|
||||
return false
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://dj5eoum4nippb
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
@tool
|
||||
extends "./../../../core/editor/app.gd"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
func execute(value : Variant = null) -> bool:
|
||||
if value is int:
|
||||
if value < 0:
|
||||
return false
|
||||
|
||||
for x : MickeyTool in _tool_db.get_tools():
|
||||
if x.get_index() == value:
|
||||
var root : Variant = x.get_root()
|
||||
if is_instance_valid(root):
|
||||
if root is TabContainer:
|
||||
if !(root.get_window().has_focus()):
|
||||
root.get_window().grab_focus()
|
||||
var index : int = x.get_control().get_index()
|
||||
if root.current_tab != index and index > -1 and root.get_tab_count() > index:
|
||||
if root.has_method(&"set_tab"):
|
||||
root.call(&"set_tab", index)
|
||||
else:
|
||||
root.current_tab = index
|
||||
return true
|
||||
return false
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://bej35a842s2yd
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
@tool
|
||||
extends "./../../../core/editor/app.gd"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
func execute(value : Variant = null) -> bool:
|
||||
var _tool : MickeyTool = null
|
||||
if value == null:
|
||||
value = _manager.get_base_container().get_current_container()
|
||||
elif value is Resource:
|
||||
var list : ItemList = _manager.get_editor_list().get_editor_list()
|
||||
var pth : String = value.resource_path
|
||||
for x : int in list.item_count:
|
||||
if pth == list.get_item_tooltip(x):
|
||||
_tool = _tool_db.get_tool_id(x)
|
||||
break
|
||||
elif value is String:
|
||||
var list : ItemList = _manager.get_editor_list().get_editor_list()
|
||||
var pth : String = value
|
||||
for x : int in list.item_count:
|
||||
if pth == list.get_item_tooltip(x):
|
||||
_tool = _tool_db.get_tool_id(x)
|
||||
break
|
||||
elif value is MickeyTool:
|
||||
_tool = value
|
||||
|
||||
if _tool == null:
|
||||
if value is MickeyTool:
|
||||
_tool = value
|
||||
elif value is Node:
|
||||
_tool = _tool_db.get_by_reference(value)
|
||||
|
||||
if is_instance_valid(_tool) and _tool.is_valid():
|
||||
if _manager._focus_tool.unfocus_enabled:
|
||||
_tool.get_root().modulate = _manager._focus_tool.unfocus_color
|
||||
var idx : int = _tool.get_index()
|
||||
if idx > -1 and _manager.get_editor_list().item_count() > idx:
|
||||
_manager.move_tool(_manager.get_base_container().new_column(), idx)
|
||||
_manager.io.update()
|
||||
return true
|
||||
|
||||
return false
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://bomyp1t030hd
|
||||
45
addons/script_splitter/core/editor/application/split_row.gd
Normal file
45
addons/script_splitter/core/editor/application/split_row.gd
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
@tool
|
||||
extends "./../../../core/editor/app.gd"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
func execute(value : Variant = null) -> bool:
|
||||
var _tool : MickeyTool = null
|
||||
|
||||
if value == null:
|
||||
value = _manager.get_base_container().get_current_container()
|
||||
elif value is Resource:
|
||||
var list : ItemList = _manager.get_editor_list().get_editor_list()
|
||||
var pth : String = value.resource_path
|
||||
for x : int in list.item_count:
|
||||
if pth == list.get_item_tooltip(x):
|
||||
_tool = _tool_db.get_tool_id(x)
|
||||
break
|
||||
elif value is String:
|
||||
var list : ItemList = _manager.get_editor_list().get_editor_list()
|
||||
var pth : String = value
|
||||
for x : int in list.item_count:
|
||||
if pth == list.get_item_tooltip(x):
|
||||
_tool = _tool_db.get_tool_id(x)
|
||||
break
|
||||
|
||||
if _tool == null:
|
||||
if value is MickeyTool:
|
||||
_tool = value
|
||||
elif value is Node:
|
||||
_tool = _tool_db.get_by_reference(value)
|
||||
|
||||
if is_instance_valid(_tool) and _tool.is_valid():
|
||||
if _manager._focus_tool.unfocus_enabled:
|
||||
_tool.get_root().modulate = _manager._focus_tool.unfocus_color
|
||||
var idx : int = _tool.get_index()
|
||||
if idx > -1 and _manager.get_editor_list().item_count() > idx:
|
||||
_manager.move_tool(_manager.get_base_container().new_row(), idx)
|
||||
_manager.io.update()
|
||||
return true
|
||||
|
||||
return false
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://bg2573oxujrny
|
||||
79
addons/script_splitter/core/editor/application/swap_tab.gd
Normal file
79
addons/script_splitter/core/editor/application/swap_tab.gd
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
@tool
|
||||
extends "./../../../core/editor/app.gd"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
const BaseContainer = preload("./../../../core/base/container.gd")
|
||||
|
||||
var _last_tool : MickeyTool = null
|
||||
|
||||
func execute(value : Variant = null) -> bool:
|
||||
if value is Array:
|
||||
if value.size() == 3:
|
||||
if value[0] is Container and value[1] is int and value[2] is Container:
|
||||
var from : Container = value[0]
|
||||
var index : int = value[1]
|
||||
var to : Container = value[2]
|
||||
|
||||
if from == to:
|
||||
return false
|
||||
|
||||
if from is BaseContainer.SplitterContainer.SplitterEditorContainer.Editor and to is BaseContainer.SplitterContainer.SplitterEditorContainer.Editor:
|
||||
for x : MickeyTool in _tool_db.get_tools():
|
||||
if x.is_valid():
|
||||
if x.get_root() == from and x.get_control().get_index() == index:
|
||||
if _last_tool == x:
|
||||
return false
|
||||
_last_tool = x
|
||||
x.ochorus(to)
|
||||
_manager.clear_editors()
|
||||
set_deferred(&"_last_tool", null)
|
||||
return true
|
||||
else:
|
||||
if value[0] is String and value[1] is String and value[2] is bool:
|
||||
var base : Manager.BaseList = _manager.get_editor_list()
|
||||
var from : String = value[0]
|
||||
var left : bool = value[2]
|
||||
var to : String = value[1]
|
||||
var fm : MickeyTool = null
|
||||
var tm : MickeyTool = null
|
||||
if from == to:
|
||||
return false
|
||||
for x : MickeyTool in _tool_db.get_tools():
|
||||
if !x.is_valid():
|
||||
continue
|
||||
var t : String = base.get_item_tooltip(x.get_index())
|
||||
if from == t:
|
||||
fm = x
|
||||
elif to == t:
|
||||
tm = x
|
||||
if is_instance_valid(fm) and is_instance_valid(tm) and fm != tm:
|
||||
var froot : Node = fm.get_root()
|
||||
var troot : Node = tm.get_root()
|
||||
if froot == troot:
|
||||
if left:
|
||||
if froot is TabContainer:
|
||||
_manager.move_item_container(froot, fm.get_index(), maxi(tm.get_index() - 1, 0))
|
||||
froot.move_child(fm.get_control(), maxi(tm.get_control().get_index() - 1,0))
|
||||
else:
|
||||
if froot is TabContainer:
|
||||
_manager.move_item_container(froot, fm.get_index(), tm.get_index())
|
||||
froot.move_child(fm.get_control(), tm.get_control().get_index())
|
||||
else:
|
||||
if froot.get_child_count() == 1:
|
||||
|
||||
if _manager.merge_tool.execute([tm.get_control(), froot.get_parent().get_child_count() == 1]):
|
||||
fm.ochorus(troot)
|
||||
#if froot.get_parent().get_child_count() == 1:
|
||||
#froot.get_parent().queue_free()
|
||||
#else:
|
||||
#froot.queue_free()
|
||||
#_manager.get_base_container().update_split_container()
|
||||
else:
|
||||
fm.ochorus(troot)
|
||||
return true
|
||||
return false
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://cwgbj8fqlg6wm
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
@tool
|
||||
extends "./../../../core/editor/app.gd"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
var LIST_VISIBLE_SELECTED_COLOR : Color = Color.from_string("7b68ee", Color.CORNFLOWER_BLUE)
|
||||
var LIST_VISIBLE_OTHERS_COLOR : Color = Color.from_string("4835bb", Color.DARK_BLUE)
|
||||
|
||||
|
||||
var _script_list_selection : bool = false
|
||||
|
||||
func _init(manager : Manager, tool_db : ToolDB) -> void:
|
||||
super(manager, tool_db)
|
||||
_setup()
|
||||
|
||||
func _notification(what: int) -> void:
|
||||
if what == NOTIFICATION_PREDELETE:
|
||||
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
||||
if settings.settings_changed.is_connected(_on_change):
|
||||
settings.settings_changed.disconnect(_on_change)
|
||||
|
||||
func _on_change() -> void:
|
||||
var dt : Array = [
|
||||
"plugin/script_splitter/behaviour/refresh_warnings_on_saveplugin/script_splitter/editor/list/selected_color"
|
||||
,"plugin/script_splitter/behaviour/refresh_warnings_on_saveplugin/script_splitter/editor/list/others_color"
|
||||
]
|
||||
|
||||
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
||||
var changes : PackedStringArray = settings.get_changed_settings()
|
||||
|
||||
for c in changes:
|
||||
if c in dt:
|
||||
_setup()
|
||||
break
|
||||
|
||||
func _setup() -> void:
|
||||
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
||||
if !settings.settings_changed.is_connected(_on_change):
|
||||
settings.settings_changed.connect(_on_change)
|
||||
|
||||
for x : Array in [
|
||||
["LIST_VISIBLE_SELECTED_COLOR", "plugin/script_splitter/behaviour/refresh_warnings_on_saveplugin/script_splitter/editor/list/selected_color"]
|
||||
,["LIST_VISIBLE_OTHERS_COLOR", "plugin/script_splitter/behaviour/refresh_warnings_on_saveplugin/script_splitter/editor/list/others_color"]
|
||||
]:
|
||||
if settings.has_setting(x[1]):
|
||||
set(x[0], settings.get_setting(x[1]))
|
||||
else:
|
||||
settings.set_setting(x[1], get(x[0]))
|
||||
|
||||
|
||||
func execute(value : Variant = null) -> bool:
|
||||
if !value is Array or value.size() < 1:
|
||||
return false
|
||||
|
||||
if _script_list_selection:
|
||||
return true
|
||||
|
||||
_script_list_selection = true
|
||||
|
||||
|
||||
var _editor_list : ItemList = value[0]
|
||||
var _script_list : ItemList = value[1]
|
||||
|
||||
var selected : String = ""
|
||||
var others_selected : PackedStringArray = []
|
||||
|
||||
|
||||
var current : TabContainer = _manager.get_base_container().get_current_container()
|
||||
|
||||
|
||||
for x : MickeyTool in _tool_db.get_tools():
|
||||
if x.is_valid():
|
||||
var _root : Node = x.get_root()
|
||||
if _root.current_tab == x.get_control().get_index():
|
||||
var idx : int = x.get_index()
|
||||
if _editor_list.item_count > idx and idx > -1:
|
||||
if _root == current:
|
||||
selected = _editor_list.get_item_tooltip(idx)
|
||||
else:
|
||||
others_selected.append(_editor_list.get_item_tooltip(idx))
|
||||
|
||||
var color : Color = LIST_VISIBLE_SELECTED_COLOR
|
||||
var color_ctn : Color = LIST_VISIBLE_SELECTED_COLOR
|
||||
var others : Color = LIST_VISIBLE_OTHERS_COLOR
|
||||
color.a = 0.5
|
||||
others.a = 0.5
|
||||
color_ctn.a = 0.25
|
||||
|
||||
for x : int in _script_list.item_count:
|
||||
var mt : String = _script_list.get_item_tooltip(x)
|
||||
if selected == mt:
|
||||
_script_list.set_item_custom_bg_color(x, color)
|
||||
_script_list.set_item_custom_fg_color(x, Color.WHITE)
|
||||
_script_list.select(x, true)
|
||||
elif others_selected.has(mt):
|
||||
_script_list.set_item_custom_bg_color(x, others)
|
||||
else:
|
||||
_script_list.set_item_custom_bg_color(x, Color.TRANSPARENT)
|
||||
_script_list.ensure_current_is_visible()
|
||||
set_deferred(&"_script_list_selection", false)
|
||||
return false
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://d0fdvav3whi4t
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
@tool
|
||||
extends "./../../../core/editor/app.gd"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
const BaseList = preload("./../../../core/base/list.gd")
|
||||
var _buffer : Dictionary = {}
|
||||
|
||||
func execute(value : Variant = null) -> bool:
|
||||
var list : BaseList = _manager.get_editor_list()
|
||||
if is_instance_valid(value) and value is MickeyTool:
|
||||
_update(value, list)
|
||||
else:
|
||||
var arr : Array[MickeyTool] = _tool_db.get_tools()
|
||||
for x : int in range(arr.size() - 1, -1, -1):
|
||||
var _tool : Variant = arr[x]
|
||||
if !is_instance_valid(_tool):
|
||||
arr.remove_at(x)
|
||||
continue
|
||||
_update(_tool, list)
|
||||
|
||||
var dict : Dictionary = {}
|
||||
for x : ToolDB.MickeyTool in _tool_db.get_tools():
|
||||
if !x.is_valid():
|
||||
continue
|
||||
var _root : Node = x.get_root_control()
|
||||
if dict.has(_root):
|
||||
continue
|
||||
dict[_root] = true
|
||||
if _root.has_method(&"update"):
|
||||
_root.call_deferred(&"update")
|
||||
return true
|
||||
|
||||
func _update(mk : MickeyTool, list : BaseList) -> void:
|
||||
if !is_instance_valid(mk) or !mk.is_valid():
|
||||
return
|
||||
var index : int = mk.get_index()
|
||||
if index > -1 and list.item_count() > index:
|
||||
var icon : Texture2D = list.get_item_icon(index)
|
||||
var modulate : Color = list.get_item_icon_modulate(index)
|
||||
if icon and modulate != Color.WHITE and modulate != Color.BLACK:
|
||||
var root : Node = mk.get_root()
|
||||
var make : bool = true
|
||||
if root.has_method(&"set_icon_color"):
|
||||
make = root.call(&"set_icon_color", modulate)
|
||||
if make:
|
||||
if _buffer.has(icon):
|
||||
icon = _buffer[icon]
|
||||
else:
|
||||
var new_icon : Texture2D = mod_image(icon, modulate)
|
||||
_buffer[icon] = new_icon
|
||||
icon = new_icon
|
||||
|
||||
mk.update_metadata(
|
||||
list.get_item_text(index),
|
||||
list.get_item_tooltip(index),
|
||||
icon
|
||||
)
|
||||
|
||||
func mod_image(icon: Texture2D, modulate_color: Color) -> Texture2D:
|
||||
var image : Image = icon.get_image()
|
||||
if image.get_format() != Image.FORMAT_RGBA8:
|
||||
image.convert(Image.FORMAT_RGBA8)
|
||||
|
||||
var width : int = image.get_width()
|
||||
var height : int = image.get_height()
|
||||
|
||||
for x : int in range(width):
|
||||
for y : int in range(height):
|
||||
var original_color: Color = image.get_pixel(x, y)
|
||||
var modulated_color: Color = modulate_color
|
||||
if original_color.a > 0.0:
|
||||
modulated_color.a = original_color.a
|
||||
image.set_pixel(x, y, modulated_color)
|
||||
|
||||
return ImageTexture.create_from_image(image)
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://bk6hirh5yekc5
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
@tool
|
||||
extends "./../../../core/editor/app.gd"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
func execute(arr : Variant = null) -> bool:
|
||||
var value : Variant = arr[0]
|
||||
var type : int = arr[1]
|
||||
|
||||
var _tool : MickeyTool = null
|
||||
|
||||
if value == null:
|
||||
value = _manager.get_base_container().get_current_container()
|
||||
|
||||
elif value is Resource:
|
||||
var list : ItemList = _manager.get_editor_list().get_editor_list()
|
||||
var pth : String = value.resource_path
|
||||
for x : int in list.item_count:
|
||||
if pth == list.get_item_tooltip(x):
|
||||
_tool = _tool_db.get_tool_id(x)
|
||||
break
|
||||
elif value is String:
|
||||
var list : ItemList = _manager.get_editor_list().get_editor_list()
|
||||
var pth : String = value
|
||||
for x : int in list.item_count:
|
||||
if pth == list.get_item_tooltip(x):
|
||||
_tool = _tool_db.get_tool_id(x)
|
||||
break
|
||||
|
||||
if _tool == null:
|
||||
if value is MickeyTool:
|
||||
_tool = value
|
||||
elif value is Node:
|
||||
_tool = _tool_db.get_by_reference(value)
|
||||
|
||||
if is_instance_valid(_tool):
|
||||
var root : Node = _tool.get_root()
|
||||
var indx : int = _tool.get_control().get_index()
|
||||
|
||||
var index : PackedInt32Array = []
|
||||
|
||||
for x : MickeyTool in _tool_db.get_tools():
|
||||
if x.get_root() == root:
|
||||
if type < 0:
|
||||
if x.get_control().get_index() < indx:
|
||||
index.append(x.get_index())
|
||||
elif type > 0:
|
||||
if x.get_control().get_index() > indx:
|
||||
index.append(x.get_index())
|
||||
else:
|
||||
if x.get_control().get_index() != indx:
|
||||
index.append(x.get_index())
|
||||
|
||||
index.sort()
|
||||
|
||||
for z : int in range(index.size() - 1, -1, -1):
|
||||
_manager.get_editor_list().remove(index[z])
|
||||
return false
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://c8c77dtgjpvxr
|
||||
23
addons/script_splitter/core/editor/coroutine/task.gd
Normal file
23
addons/script_splitter/core/editor/coroutine/task.gd
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
@tool
|
||||
extends RefCounted
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
var _task : Array[Callable] = []
|
||||
|
||||
func has(callable : Callable) -> bool:
|
||||
return _task.has(callable)
|
||||
|
||||
func add(task : Callable) -> void:
|
||||
if task.is_valid():
|
||||
_task.append(task)
|
||||
|
||||
func update() -> void:
|
||||
for task : Callable in _task:
|
||||
if task.is_valid():
|
||||
task.call()
|
||||
_task.clear()
|
||||
1
addons/script_splitter/core/editor/coroutine/task.gd.uid
Normal file
1
addons/script_splitter/core/editor/coroutine/task.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://qbsuad1aohqy
|
||||
64
addons/script_splitter/core/editor/database/tool_db.gd
Normal file
64
addons/script_splitter/core/editor/database/tool_db.gd
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
@tool
|
||||
extends RefCounted
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
const MickeyTool = preload("./../../../core/editor/tools/magic/mickey_tool.gd")
|
||||
|
||||
var _tools : Array[MickeyTool] = []
|
||||
|
||||
func get_tools() -> Array[MickeyTool]:
|
||||
return _tools
|
||||
|
||||
func append(mk : MickeyTool) -> void:
|
||||
_tools.append(mk)
|
||||
|
||||
func garbage(val : int) -> void:
|
||||
if val == 1:
|
||||
for x : Variant in _tools:
|
||||
if is_instance_valid(x):
|
||||
(x as MickeyTool).set_queue_free(true)
|
||||
elif val == 0:
|
||||
for x : int in range(_tools.size() - 1, -1, -1):
|
||||
var variant : Variant = _tools[x]
|
||||
if !is_instance_valid(variant):
|
||||
_tools.remove_at(x)
|
||||
|
||||
if !variant.is_valid():
|
||||
if !is_instance_valid(variant.get_owner()):
|
||||
var root : Node = variant.get_root()
|
||||
if is_instance_valid(root):
|
||||
variant.get_root().queue_free()
|
||||
variant.set_queue_free(true)
|
||||
|
||||
if (variant as MickeyTool).is_queue_free():
|
||||
_tools.remove_at(x)
|
||||
|
||||
func get_tool_id(id : int) -> MickeyTool:
|
||||
for x : MickeyTool in _tools:
|
||||
if x.get_index() == id:
|
||||
return x
|
||||
return null
|
||||
|
||||
func has_tool_id(id : int) -> bool:
|
||||
for x : MickeyTool in _tools:
|
||||
if x.get_index() == id:
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
func clear() -> void:
|
||||
for x : MickeyTool in _tools:
|
||||
if is_instance_valid(x):
|
||||
x.reset()
|
||||
_tools.clear()
|
||||
|
||||
func get_by_reference(control : Node) -> MickeyTool:
|
||||
for x : MickeyTool in _tools:
|
||||
if x.has(control):
|
||||
return x
|
||||
return null
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://dv6xyd03fg7kj
|
||||
404
addons/script_splitter/core/editor/godot/manager.gd
Normal file
404
addons/script_splitter/core/editor/godot/manager.gd
Normal file
|
|
@ -0,0 +1,404 @@
|
|||
@tool
|
||||
extends RefCounted
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
const CreateTool = preload("./../../../core/editor/application/create_tool.gd")
|
||||
const UpdateMetadata = preload("./../../../core/editor/application/update_metadata.gd")
|
||||
const FocusTool = preload("./../../../core/editor/application/focus_tool.gd")
|
||||
const SelectByIndex = preload("./../../../core/editor/application/select_by_index.gd")
|
||||
const FocusByTab = preload("./../../../core/editor/application/focus_by_tab.gd")
|
||||
const ReparentTool = preload("./../../../core/editor/application/reparent_tool.gd")
|
||||
const MergeTool = preload("./../../../core/editor/application/merge_tool.gd")
|
||||
const SplitColumn = preload("./../../../core/editor/application/split_column.gd")
|
||||
const SplitRow = preload("./../../../core/editor/application/split_row.gd")
|
||||
const RemoveByTab = preload("./../../../core/editor/application/remove_by_tab.gd")
|
||||
const RefreshWarnings = preload("./../../../core/editor/application/refresh_warnings.gd")
|
||||
const UpdateListSelection = preload("./../../../core/editor/application/update_list_selection.gd")
|
||||
const SwapTab = preload("./../../../core/editor/application/swap_tab.gd")
|
||||
const RmbMenu = preload("./../../../core/editor/application/rmb_menu.gd")
|
||||
const UserTabClose = preload("./../../../core/editor/application/user_tab_close.gd")
|
||||
const Io = preload("./../../../core/editor/application/io.gd")
|
||||
const CustomSplit = preload("./../../../core/editor/application/custom_split.gd")
|
||||
|
||||
const ToolDB = preload("./../../../core/editor/database/tool_db.gd")
|
||||
const Task = preload("./../../../core/editor/coroutine/task.gd")
|
||||
|
||||
const BaseContainer = preload("./../../../core/base/container.gd")
|
||||
const BaseList = preload("./../../../core/base/list.gd")
|
||||
|
||||
|
||||
signal update_request()
|
||||
|
||||
# API
|
||||
var split_column : SplitColumn = null
|
||||
var split_row : SplitRow = null
|
||||
var refresh_warnings : RefreshWarnings = null
|
||||
var merge_tool : MergeTool = null
|
||||
|
||||
# APPLICATION
|
||||
var _create_tool : CreateTool = null
|
||||
var _focus_tool : FocusTool = null
|
||||
var _update_metadata : UpdateMetadata = null
|
||||
var _select_by_index : SelectByIndex = null
|
||||
var _focus_by_tab : FocusByTab = null
|
||||
var _remove_by_tab : RemoveByTab = null
|
||||
var _reparent_tool : ReparentTool = null
|
||||
var _update_list_selection : UpdateListSelection = null
|
||||
var _rmb_menu : RmbMenu = null
|
||||
var _user_tab_close : UserTabClose = null
|
||||
var _custom_split : CustomSplit = null
|
||||
|
||||
var io : Io = null
|
||||
var swap_tab : SwapTab = null
|
||||
|
||||
# DB
|
||||
var _tool_db : ToolDB = null
|
||||
|
||||
# REF
|
||||
var _base_container : BaseContainer = null
|
||||
var _base_list : BaseList = null
|
||||
var _task : Task = null
|
||||
|
||||
func _app_setup() -> void:
|
||||
_task = Task.new()
|
||||
_tool_db = ToolDB.new()
|
||||
|
||||
_focus_tool = FocusTool.new(self, _tool_db)
|
||||
_update_metadata = UpdateMetadata.new(self, _tool_db)
|
||||
_create_tool = CreateTool.new(self, _tool_db)
|
||||
_select_by_index = SelectByIndex.new(self, _tool_db)
|
||||
_focus_by_tab = FocusByTab .new(self, _tool_db)
|
||||
_reparent_tool = ReparentTool.new(self, _tool_db)
|
||||
merge_tool = MergeTool.new(self, _tool_db)
|
||||
_remove_by_tab = RemoveByTab.new(self, _tool_db)
|
||||
_update_list_selection = UpdateListSelection.new(self, _tool_db)
|
||||
swap_tab = SwapTab.new(self, _tool_db)
|
||||
_rmb_menu = RmbMenu.new(self, _tool_db)
|
||||
_user_tab_close = UserTabClose.new(self, _tool_db)
|
||||
_custom_split = CustomSplit.new(self, _tool_db)
|
||||
|
||||
io = Io.new(self, _tool_db)
|
||||
|
||||
split_column = SplitColumn.new(self, _tool_db)
|
||||
split_row = SplitRow.new(self, _tool_db)
|
||||
refresh_warnings = RefreshWarnings.new(self, _tool_db)
|
||||
|
||||
_base_list.update_selections_callback = _update_list_selection.execute
|
||||
|
||||
func update_list(__ : Variant) -> void:
|
||||
_base_list.update_list_selection()
|
||||
|
||||
func get_current_tool(ref : Node = null) -> ToolDB.MickeyTool:
|
||||
if ref == null:
|
||||
ref = _base_container.get_current_container()
|
||||
return _tool_db.get_by_reference(ref)
|
||||
|
||||
func _init(base_container : BaseContainer, base_list : BaseList) -> void:
|
||||
_base_container = base_container
|
||||
_base_list = base_list
|
||||
|
||||
#_base_list.set_handler(self)
|
||||
#
|
||||
_base_list.updated.connect(update_all_metadata)
|
||||
_base_list.item_selected.connect(_on_item_selected)
|
||||
_base_list.move_item.connect(_move_item_list)
|
||||
_base_container.update.connect(update_metadata)
|
||||
_base_container.focus_by_tab.connect(_on_focus_tab)
|
||||
_base_container.remove_by_tab.connect(_on_remove_tab)
|
||||
|
||||
_base_container.swap_tab.connect(_onswap_tab)
|
||||
_base_container.same_swap_tab.connect(_on_same_swap_tab)
|
||||
_base_container.change_container.connect(update_list)
|
||||
|
||||
_base_container.rmb_click.connect(_on_tab_rmb)
|
||||
|
||||
_base_container.exiting.connect(_on_exiting)
|
||||
|
||||
_app_setup()
|
||||
|
||||
func _on_exiting() -> void:
|
||||
_tool_db.clear()
|
||||
|
||||
func get_total_editors() -> int:
|
||||
var container : Control = _base_container.get_current_container()
|
||||
if is_instance_valid(container):
|
||||
return container.get_child_count()
|
||||
return 0
|
||||
|
||||
func get_current_totaL_editors(current : Node) -> int:
|
||||
var container : Control = null
|
||||
|
||||
if current == null:
|
||||
container = _base_container.get_current_container()
|
||||
elif current is Node:
|
||||
container = _tool_db.get_by_reference(current).get_root()
|
||||
|
||||
if is_instance_valid(container):
|
||||
return container.get_child_count()
|
||||
return 0
|
||||
|
||||
func get_total_split_container(by_row : bool) -> int:
|
||||
if by_row:
|
||||
var rows : Array = []
|
||||
for x : Node in _base_container.get_all_containers():
|
||||
var parent : Node = x.get_parent()
|
||||
if parent:
|
||||
if !rows.has(parent):
|
||||
rows.append(parent)
|
||||
return rows.size()
|
||||
else:
|
||||
return _base_container.get_all_containers().size()
|
||||
|
||||
func get_total_splitters() -> int:
|
||||
return _base_container.get_all_splitters().size()
|
||||
|
||||
func get_current_total_splitters(current : Node) -> int:
|
||||
if current is CodeEdit:
|
||||
var container : Control = null
|
||||
var value : ToolDB.MickeyTool = _tool_db.get_by_reference(current)
|
||||
if is_instance_valid(value) and value.is_valid():
|
||||
container = _base_container.get_container(value.get_root())
|
||||
if is_instance_valid(container):
|
||||
return container.get_child_count()
|
||||
return 0
|
||||
return _base_container.get_current_splitters().size()
|
||||
|
||||
func clear() -> void:
|
||||
_tool_db.clear()
|
||||
|
||||
func reset_by_control(control : Node) -> void:
|
||||
var tls : Array[ToolDB.MickeyTool] = []
|
||||
for x : ToolDB.MickeyTool in _tool_db.get_tools():
|
||||
if x.is_valid():
|
||||
if control.find_child(x.get_control().name, true, false):
|
||||
tls.append(x)
|
||||
|
||||
for t : ToolDB.MickeyTool in tls:
|
||||
t.reset()
|
||||
|
||||
func reset() -> void:
|
||||
_tool_db.clear()
|
||||
|
||||
_base_container.reset()
|
||||
_base_list.reset()
|
||||
|
||||
func _onswap_tab(from : Container, index : int, to : Container) -> void:
|
||||
swap_tab.execute([from, index, to])
|
||||
|
||||
func _on_same_swap_tab(from : Container, index : int, type : StringName) -> void:
|
||||
_custom_split.execute([from, index, type])
|
||||
|
||||
func _on_focus_tab(tab : TabContainer, index : int) -> void:
|
||||
_focus_by_tab.execute([tab, index])
|
||||
|
||||
func _on_remove_tab(tab : TabContainer, index : int) -> void:
|
||||
_remove_by_tab.execute([tab, index])
|
||||
|
||||
func _on_item_selected(i : int) -> void:
|
||||
_select_by_index.execute(i)
|
||||
|
||||
func is_valid_item_index(index : int) -> bool:
|
||||
return index > -1 and _base_list.item_count() > index and !_base_list.get_item_tooltip(index).is_empty() and !_base_list.get_item_text(index).is_empty()
|
||||
|
||||
func update() -> bool:
|
||||
if !_base_container.has_method(&"is_active") or !_base_container.is_active():
|
||||
return false
|
||||
|
||||
_task.update()
|
||||
_tool_db.garbage(1)
|
||||
|
||||
var update_required : bool = false
|
||||
for x : Node in _base_container.get_editors():
|
||||
update_required = !_create_tool.execute(x) || update_required
|
||||
|
||||
_tool_db.garbage(0)
|
||||
_base_container.garbage()
|
||||
|
||||
_select_by_index.execute(_base_list.get_selected_id())
|
||||
|
||||
_update_root()
|
||||
|
||||
_base_container.update_split_container()
|
||||
_base_list.update_list()
|
||||
return !update_required
|
||||
|
||||
# API
|
||||
func set_symbol(__ : String) -> void:
|
||||
var tl : ToolDB.MickeyTool = _tool_db.get_tool_id(_base_list.get_selected_id())
|
||||
if is_instance_valid(tl):
|
||||
_focus_tool.execute(tl)
|
||||
var gui : Node = tl.get_gui()
|
||||
if gui is CodeEdit:
|
||||
_center.call_deferred(gui)
|
||||
else:
|
||||
for x : Node in gui.get_children():
|
||||
if x is RichTextLabel:
|
||||
_center.call_deferred(x)
|
||||
|
||||
func _center(gui : Variant) -> void:
|
||||
if is_instance_valid(gui):
|
||||
if gui is CodeEdit:
|
||||
if gui.get_caret_count() > 0:
|
||||
gui.scroll_vertical = gui.get_scroll_pos_for_line(maxi(gui.get_caret_line(0) - 1, 0))
|
||||
gui.center_viewport_to_caret.call_deferred(0)
|
||||
|
||||
func unsplit_column(current : Variant) -> void:
|
||||
if merge_tool.execute([current, false]):
|
||||
update_request.emit()
|
||||
|
||||
func unsplit_row(current : Variant) -> void:
|
||||
if merge_tool.execute([current, true]):
|
||||
update_request.emit()
|
||||
|
||||
func move_tool(control : Control, index : int) -> bool:
|
||||
return _reparent_tool.execute([control, index])
|
||||
|
||||
func get_current_root() -> Control:
|
||||
return _base_container.get_current_editor()
|
||||
|
||||
func get_editor_list() -> BaseList:
|
||||
return _base_list
|
||||
|
||||
func get_base_container() -> BaseContainer:
|
||||
return _base_container
|
||||
|
||||
func get_editor_container() -> TabContainer:
|
||||
return _base_container.get_editor_container()
|
||||
|
||||
func select_editor_by_index(index : int) -> void:
|
||||
_base_list.select(index)
|
||||
|
||||
func focus_tool(mk : Variant) -> void:
|
||||
_focus_tool.execute(mk)
|
||||
|
||||
func tool_created() -> void:
|
||||
_base_container.tool_created()
|
||||
|
||||
func update_metadata(mk : Variant = null) -> void:
|
||||
_task.add(_update_metadata.execute.bind(mk))
|
||||
update_request.emit()
|
||||
|
||||
func update_all_metadata() -> void:
|
||||
if !_task.has(_update_metadata.execute):
|
||||
_task.add(_update_metadata.execute)
|
||||
update_request.emit()
|
||||
|
||||
func clear_editors() -> void:
|
||||
if !_task.has(_clear_editor):
|
||||
_task.add(_clear_editor)
|
||||
update_request.emit()
|
||||
|
||||
func _clear_editor() -> void:
|
||||
var spls : Array[Node] = _base_container.get_all_splitters()
|
||||
var total : int = spls.size()
|
||||
|
||||
if total > 1:
|
||||
total = 0
|
||||
for x : Node in spls:
|
||||
if is_instance_valid(x):
|
||||
if x.is_queued_for_deletion():
|
||||
continue
|
||||
total += 1
|
||||
|
||||
if total > 1:
|
||||
for x : Node in spls:
|
||||
if x.get_child_count() == 0:
|
||||
if total < 2:
|
||||
return
|
||||
|
||||
var c : Node = _base_container.get_container_item(x)
|
||||
if c and !c.is_queued_for_deletion():
|
||||
var container : Node = _base_container.get_container(x)
|
||||
if container and container.get_child_count() < 2:
|
||||
container.get_parent().queue_free()
|
||||
c.queue_free()
|
||||
total -= 1
|
||||
|
||||
func _update_root() -> void:
|
||||
var root : Control = _base_container.get_root_container()
|
||||
|
||||
if root:
|
||||
var v : bool = false
|
||||
var nodes : Array[Node] = root.get_tree().get_nodes_in_group(&"__SP_IC__")
|
||||
var total : int = nodes.size()
|
||||
for x : Node in nodes:
|
||||
if total < 2:
|
||||
break
|
||||
if x.get_child_count() == 0:
|
||||
x.queue_free()
|
||||
total -= 1
|
||||
else:
|
||||
if x.get_child(0).get_child_count() == 0:
|
||||
x.queue_free()
|
||||
total -= 1
|
||||
|
||||
for x : Node in _base_container.get_all_splitters():
|
||||
if x.get_child_count() > 0:
|
||||
v = true
|
||||
break
|
||||
root.get_parent().visible = v
|
||||
|
||||
func get_control_tool_by_current(current : Variant) -> Node:
|
||||
var root : Node = null
|
||||
if null == current or current is PackedStringArray and current.size() == 0:
|
||||
current = get_base_container().get_current_container()
|
||||
if current is TabContainer:
|
||||
var i : int = current.current_tab
|
||||
if i > -1:
|
||||
current = current.get_child(i)
|
||||
if current:
|
||||
if current is String:
|
||||
for x : int in _base_list.item_count():
|
||||
if current == _base_list.get_item_tooltip(x):
|
||||
var mk : ToolDB.MickeyTool = _tool_db.get_tool_id(x)
|
||||
if mk:
|
||||
root = mk.get_control()
|
||||
break
|
||||
elif current is Node:
|
||||
for x : ToolDB.MickeyTool in _tool_db.get_tools():
|
||||
if x.has(current):
|
||||
root = x.get_control()
|
||||
break
|
||||
return root
|
||||
|
||||
func _on_tab_rmb(index : int, tab : TabContainer) -> void:
|
||||
_rmb_menu.execute([index, tab])
|
||||
|
||||
func left_tab_close(value : Variant) -> void:
|
||||
_user_tab_close.execute([value, -1])
|
||||
|
||||
func right_tab_close(value : Variant) -> void:
|
||||
_user_tab_close.execute([value, 1])
|
||||
|
||||
func others_tab_close(value : Variant) -> void:
|
||||
_user_tab_close.execute([value, 0])
|
||||
|
||||
func _move_item_list(from : int, to : int) -> void:
|
||||
move_item_container(null, from, to)
|
||||
|
||||
func move_item_container(container : TabContainer, from : int, to : int) -> void:
|
||||
var vfrom : int = -1
|
||||
var vto : int = -1
|
||||
|
||||
if container == null:
|
||||
vfrom = from
|
||||
vto = to
|
||||
else:
|
||||
for x : ToolDB.MickeyTool in _tool_db.get_tools():
|
||||
if x.get_root() == container:
|
||||
var _idx : int = x.get_control().get_index()
|
||||
if _idx == from:
|
||||
vfrom = x.get_index()
|
||||
elif _idx == to:
|
||||
vto = x.get_index()
|
||||
|
||||
if vfrom == -1 or vto == -1:
|
||||
return
|
||||
|
||||
_base_container.move_container(vfrom, vto)
|
||||
1
addons/script_splitter/core/editor/godot/manager.gd.uid
Normal file
1
addons/script_splitter/core/editor/godot/manager.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://blq08yud6jfse
|
||||
18
addons/script_splitter/core/editor/tools/editor_tool.gd
Normal file
18
addons/script_splitter/core/editor/tools/editor_tool.gd
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
@tool
|
||||
extends RefCounted
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
const MickeyTool = preload("./../../../core/editor/tools/magic/mickey_tool.gd")
|
||||
const MickeyToolRoute = preload("./../../../core/editor/tools/magic/mickey_tool_route.gd")
|
||||
|
||||
func build(control : Node) -> MickeyTool:
|
||||
return _build_tool(control)
|
||||
|
||||
func _build_tool(_control : Node) -> MickeyTool:
|
||||
return null
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://byxd23l74ehqq
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
@tool
|
||||
extends "./../../../core/editor/tools/editor_tool.gd"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
func _build_tool(control : Node) -> MickeyTool:
|
||||
if control is ScriptEditorBase:
|
||||
return null
|
||||
if control.name.begins_with("@"):
|
||||
return null
|
||||
|
||||
var mickey : MickeyTool = null
|
||||
for x : Node in control.get_children():
|
||||
if x is RichTextLabel:
|
||||
var canvas : VBoxContainer = VBoxContainer.new()
|
||||
canvas.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
canvas.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
|
||||
var childs : Array[Node] = control.get_children()
|
||||
for n : Node in childs:
|
||||
control.remove_child(n)
|
||||
canvas.add_child(n)
|
||||
|
||||
canvas.size = control.size
|
||||
mickey = MickeyToolRoute.new(control, canvas, canvas)
|
||||
break
|
||||
return mickey
|
||||
|
||||
func _handler(control : Node) -> MickeyTool:
|
||||
var mickey : MickeyTool = null
|
||||
if control is RichTextLabel:
|
||||
var canvas : VBoxContainer = VBoxContainer.new()
|
||||
canvas.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
canvas.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
|
||||
if canvas.get_child_count() < 1:
|
||||
var childs : Array[Node] = control.get_children()
|
||||
for n : Node in childs:
|
||||
control.remove_child(n)
|
||||
canvas.add_child(n)
|
||||
|
||||
canvas.size = control.size
|
||||
mickey = MickeyToolRoute.new(control, canvas, canvas)
|
||||
return mickey
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://cnor3blarugxa
|
||||
228
addons/script_splitter/core/editor/tools/magic/mickey_tool.gd
Normal file
228
addons/script_splitter/core/editor/tools/magic/mickey_tool.gd
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
@tool
|
||||
extends RefCounted
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
const Notfy = preload("./../../../../core/util/control.gd")
|
||||
|
||||
signal focus(_tool : Object)
|
||||
signal new_symbol(symbol : String)
|
||||
signal clear()
|
||||
|
||||
var _owner : Control = null
|
||||
var _root_control : Control = null
|
||||
var _control : Control = null
|
||||
var _index : int = -1
|
||||
|
||||
var _queue_free : bool = false
|
||||
|
||||
func set_queue_free(q : bool) -> void:
|
||||
_queue_free = q
|
||||
|
||||
func is_queue_free() -> bool:
|
||||
return _queue_free
|
||||
|
||||
func is_valid() -> bool:
|
||||
for x : Variant in [_owner, _root_control, _control]:
|
||||
if !is_instance_valid(x) or (x as Node).is_queued_for_deletion() or !(x as Node).is_inside_tree():
|
||||
return false
|
||||
return _owner != get_root()
|
||||
|
||||
func update_metadata(tittle : String, tooltips : String, icon : Texture2D) -> void:
|
||||
if is_instance_valid(_control):
|
||||
var parent : Node = _root_control
|
||||
for __ : int in range(0, 4, 1):
|
||||
if parent is TabContainer or parent == null:
|
||||
break
|
||||
parent = parent.get_parent()
|
||||
|
||||
if parent is TabContainer:
|
||||
var index : int = _root_control.get_index()
|
||||
if index > -1 and parent.get_tab_count() > index:
|
||||
if !tittle.is_empty() and parent.get_tab_title(index) != tittle:
|
||||
parent.set_tab_title(index, tittle)
|
||||
_root_control.name = tittle
|
||||
if !tooltips.is_empty() and parent.get_tab_tooltip(index) != tooltips:
|
||||
parent.set_tab_tooltip(index, tooltips)
|
||||
parent.set_tab_icon(index, icon)
|
||||
|
||||
func ochorus(root : Node) -> void:
|
||||
if is_instance_valid(_root_control) and is_instance_valid(root):
|
||||
var parent : Node = _root_control.get_parent()
|
||||
if parent != root:
|
||||
|
||||
_connect_callback(false)
|
||||
|
||||
if parent:
|
||||
_root_control.reparent(root)
|
||||
else:
|
||||
root.add_child(_root_control)
|
||||
|
||||
if _owner == root:
|
||||
if _root_control.get_index() != _index:
|
||||
if _owner.get_child_count() > _index:
|
||||
_owner.move_child(_root_control, _index)
|
||||
else:
|
||||
if root is TabContainer:
|
||||
var tittle_id : int = _root_control.get_index()
|
||||
if tittle_id > -1 and tittle_id < root.get_tab_count():
|
||||
var tl : String = root.get_tab_title(tittle_id)
|
||||
if tl.is_empty() or (tl.begins_with("@") and "Text" in tl):
|
||||
root.set_tab_title(tittle_id, "Editor")
|
||||
|
||||
_connect_callback(true)
|
||||
|
||||
_root_control.visible = true
|
||||
|
||||
func trigger_focus() -> void:
|
||||
focus.emit(self)
|
||||
|
||||
func get_owner() -> Node:
|
||||
return _owner
|
||||
|
||||
func get_root() -> Node:
|
||||
if _root_control:
|
||||
return _root_control.get_parent()
|
||||
return null
|
||||
|
||||
func get_root_control() -> Node:
|
||||
if _root_control:
|
||||
var node : Node = _root_control.get_parent()
|
||||
if node:
|
||||
return node.get_parent()
|
||||
return null
|
||||
|
||||
|
||||
func get_control() -> Node:
|
||||
return _root_control
|
||||
|
||||
func get_gui() -> Node:
|
||||
return _control
|
||||
|
||||
func has(current_control : Node) -> bool:
|
||||
return _owner == current_control or _root_control == current_control or _control == current_control or get_root() == current_control
|
||||
|
||||
func _init(owner_control : Control, current_root_control : Control, current_control : Control) -> void:
|
||||
_owner = owner_control
|
||||
_root_control = current_root_control
|
||||
_control = current_control
|
||||
_index = current_root_control.get_index()
|
||||
|
||||
_owner.tree_exiting.connect(reset)
|
||||
|
||||
for x : Control in [
|
||||
_owner, _root_control, _control
|
||||
]:
|
||||
x.set_script(Notfy)
|
||||
if _owner == x:
|
||||
x.panic()
|
||||
if x.has_signal(&"notification"):
|
||||
if !x.is_connected(&"notification", _on_not):
|
||||
x.connect(&"notification", _on_not)
|
||||
|
||||
_con_focus(_control, true)
|
||||
|
||||
func _con_focus(n : Node, con : bool) -> void:
|
||||
if n is Control:
|
||||
if n.focus_mode != Control.FOCUS_NONE:
|
||||
if con:
|
||||
if !_control.gui_input.is_connected(_on_input):
|
||||
_control.gui_input.connect(_on_input)
|
||||
else:
|
||||
if _control.gui_input.is_connected(_on_input):
|
||||
_control.gui_input.disconnect(_on_input)
|
||||
for x : Node in n.get_children():
|
||||
_con_focus(x, con)
|
||||
|
||||
func _get_callables(gui : Control) -> Array:
|
||||
return [
|
||||
[gui.focus_entered, _i_like_coffe],
|
||||
#[gui.focus_exited, _i_like_candy],
|
||||
#[gui.visibility_changed, _i_like_coffe],
|
||||
]
|
||||
|
||||
func _connect_callback(con : bool) -> void:
|
||||
var gui : Control = _control
|
||||
if gui is VBoxContainer:
|
||||
gui = gui.get_child(0)
|
||||
|
||||
var arr : Array = _get_callables(gui)
|
||||
|
||||
if gui is CodeEdit:
|
||||
arr.append([gui.symbol_lookup, _on_symb])
|
||||
|
||||
if _control.focus_mode != Control.FOCUS_NONE:
|
||||
_con_focus(_control, con)
|
||||
|
||||
for x : Array in arr:
|
||||
if con:
|
||||
if !x[0].is_connected(x[1]):
|
||||
x[0].connect(x[1])
|
||||
else:
|
||||
if x[0].is_connected(x[1]):
|
||||
x[0].disconnect(x[1])
|
||||
|
||||
if con:
|
||||
if is_instance_valid(gui):
|
||||
focus.emit.call_deferred(self)
|
||||
elif is_instance_valid(_control):
|
||||
_control.modulate = Color.WHITE
|
||||
|
||||
func _on_not(what : int) -> void:
|
||||
if what == NOTIFICATION_PREDELETE:
|
||||
reset()
|
||||
|
||||
func get_index() -> int:
|
||||
if is_instance_valid(_owner) and _owner.is_inside_tree():
|
||||
return _owner.get_index()
|
||||
return -1
|
||||
|
||||
func _i_like_coffe() -> void:
|
||||
focus.emit(self)
|
||||
|
||||
func reset() -> void:
|
||||
for x : Variant in [
|
||||
_owner, _root_control, _control
|
||||
]:
|
||||
if is_instance_valid(x):
|
||||
x.set_script(null)
|
||||
|
||||
if _control is CodeEdit and !_control.is_queued_for_deletion() and _control.get_parent() is VSplitContainer:
|
||||
for x : Node in Engine.get_main_loop().get_nodes_in_group(&"__SCRIPT_SPLITTER__"):
|
||||
x.script_merge(_control)
|
||||
break
|
||||
|
||||
ochorus(_owner)
|
||||
set_queue_free(true)
|
||||
_owner = null
|
||||
_root_control = null
|
||||
_control = null
|
||||
|
||||
clear.emit()
|
||||
|
||||
func _context_update(window : Window, control : Control) -> void:
|
||||
if is_instance_valid(window) and is_instance_valid(control):
|
||||
var screen_rect: Rect2 = DisplayServer.screen_get_usable_rect(window.current_screen)
|
||||
var gvp: Vector2 = control.get_screen_position() + control.get_local_mouse_position()
|
||||
gvp.y = min(gvp.y, screen_rect.position.y + screen_rect.size.y - window.size.y + 16.0)
|
||||
gvp.x = min(gvp.x, screen_rect.position.x + screen_rect.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 == MOUSE_BUTTON_RIGHT:
|
||||
for x : Node in _owner.get_children():
|
||||
var variant : Node = x
|
||||
if variant is Window and _control is Control:
|
||||
_context_update.call_deferred(variant, _control)
|
||||
trigger_focus()
|
||||
|
||||
func _on_symb(symbol: String, _line : int, _column: int, _edit : CodeEdit = null) -> void:
|
||||
new_symbol.emit(symbol)
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://r4j0eu5er1m4
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
@tool
|
||||
extends "./../../../../core/editor/tools/magic/mickey_tool.gd"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
func has(current_control : Node) -> bool:
|
||||
if super(current_control):
|
||||
return true
|
||||
for x : Node in current_control.get_children():
|
||||
if super(x):
|
||||
return true
|
||||
return false
|
||||
|
||||
func ochorus(root : Node) -> void:
|
||||
if is_instance_valid(_root_control) and is_instance_valid(root):
|
||||
var parent : Node = _root_control.get_parent()
|
||||
if parent != root:
|
||||
|
||||
_connect_callback(false)
|
||||
|
||||
if _owner == root:
|
||||
var childs : Array[Node] = _root_control.get_children()
|
||||
for n : Node in childs:
|
||||
_root_control.remove_child(n)
|
||||
_owner.add_child(n)
|
||||
_root_control.queue_free()
|
||||
else:
|
||||
if parent:
|
||||
_root_control.reparent(root)
|
||||
else:
|
||||
root.add_child(_root_control)
|
||||
|
||||
if root is Control:
|
||||
_root_control.size = root.size
|
||||
|
||||
if root is TabContainer:
|
||||
var tittle_id : int = _root_control.get_index()
|
||||
if tittle_id > -1 and tittle_id < root.get_tab_count():
|
||||
var tl : String = root.get_tab_title(tittle_id)
|
||||
if tl.is_empty() or (tl.begins_with("@") and "Text" in tl):
|
||||
root.set_tab_title(tittle_id, "Editor")
|
||||
|
||||
_connect_callback(true)
|
||||
|
||||
_root_control.visible = true
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://pkj5o6q7sine
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
@tool
|
||||
extends "./../../../core/editor/tools/editor_tool.gd"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
func _build_tool(control : Node) -> MickeyTool:
|
||||
if control is ScriptEditorBase:
|
||||
var editor : Control = control.get_base_editor()
|
||||
var mickey_tool : MickeyTool = null
|
||||
if editor is CodeEdit:
|
||||
var rcontrol : Node = editor.get_parent()
|
||||
if is_instance_valid(rcontrol):
|
||||
for __ : int in range(5):
|
||||
if rcontrol == null:
|
||||
break
|
||||
elif rcontrol is VSplitContainer:
|
||||
mickey_tool = MickeyTool.new(rcontrol.get_parent(), rcontrol, editor)
|
||||
break
|
||||
rcontrol = rcontrol.get_parent()
|
||||
return mickey_tool
|
||||
return null
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://c5mrlc852aghg
|
||||
22
addons/script_splitter/core/editor/tools/text_editor_tool.gd
Normal file
22
addons/script_splitter/core/editor/tools/text_editor_tool.gd
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
@tool
|
||||
extends "./../../../core/editor/tools/editor_tool.gd"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
func _build_tool(control : Node) -> MickeyTool:
|
||||
if control is ScriptEditorBase:
|
||||
var editor : Control = control.get_base_editor()
|
||||
var mickey_tool : MickeyTool = null
|
||||
if editor is CodeEdit:
|
||||
var parent : Node = control.get_parent()
|
||||
if parent != null and parent.is_node_ready() and !control.get_parent() is VSplitContainer:
|
||||
mickey_tool = MickeyTool.new(control, editor, editor)
|
||||
else:
|
||||
mickey_tool = MickeyTool.new(control, editor, editor)
|
||||
return mickey_tool
|
||||
return null
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://xkgq82knloas
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="Container.svg"
|
||||
inkscape:export-filename="..\GODOT\ToShare\favoritedock\addons\script-ide\split_gui\icon\MultiSpliter.svg"
|
||||
inkscape:export-xdpi="877.71429"
|
||||
inkscape:export-ydpi="877.71429"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#eeeeee"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#505050">
|
||||
<inkscape:page
|
||||
x="0"
|
||||
y="0"
|
||||
width="16"
|
||||
height="16"
|
||||
id="page2"
|
||||
margin="0"
|
||||
bleed="0" />
|
||||
</sodipodi:namedview>
|
||||
<path
|
||||
fill="#8eef97"
|
||||
d="M 1,1 V 5 H 5 V 1 Z m 9,0 v 4 h 5 V 1 Z m -9,9 v 5 h 4 v -5 z m 9,0 v 5 h 5 V 10 Z M 8,15 7,9 1,8 H 15 L 9,7 8,1 Z"
|
||||
id="path1"
|
||||
sodipodi:nodetypes="ccccccccccccccccccccccccccc"
|
||||
inkscape:export-filename="..\GODOT\ToShare\favoritedock\addons\script-ide\split_gui\GODOT\ToShare\favoritedock\addons\script-ide\split_gui\icon\MultiSpliter.svg"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
|
|
@ -0,0 +1,43 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://c042di3o7rqml"
|
||||
path="res://.godot/imported/MultiSpliter.svg-3fac225927d0b135f9e22aa6666d3a55.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/script_splitter/core/ui/multi_split_container/icon/MultiSpliter.svg"
|
||||
dest_files=["res://.godot/imported/MultiSpliter.svg-3fac225927d0b135f9e22aa6666d3a55.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=8.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="ControlItemButton.svg"
|
||||
inkscape:export-filename="ToShare\favoritedock\addons\script-ide\split_gui\icon\MultiSpliterButton.svg"
|
||||
inkscape:export-xdpi="768"
|
||||
inkscape:export-ydpi="768"
|
||||
inkscape:version="1.4 (86a8ad7, 2024-10-11)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#eeeeee"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#505050"
|
||||
inkscape:zoom="15.999999"
|
||||
inkscape:cx="4.4375002"
|
||||
inkscape:cy="8.5937504"
|
||||
inkscape:window-width="1287"
|
||||
inkscape:window-height="745"
|
||||
inkscape:window-x="65"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1">
|
||||
<inkscape:page
|
||||
x="0"
|
||||
y="0"
|
||||
width="16"
|
||||
height="16"
|
||||
id="page2"
|
||||
margin="0"
|
||||
bleed="0" />
|
||||
</sodipodi:namedview>
|
||||
<rect
|
||||
style="fill:#bfbfbf;fill-opacity:1;stroke:#757575;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
id="rect1"
|
||||
width="12"
|
||||
height="15"
|
||||
x="2"
|
||||
y="0.45580584"
|
||||
ry="2" />
|
||||
<circle
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#bbbbbb;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
id="path1"
|
||||
cy="2.8863502"
|
||||
cx="5.3863502"
|
||||
r="1.8863502" />
|
||||
<circle
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#bbbbbb;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
id="path1-1"
|
||||
cy="7.965826"
|
||||
cx="5.3863502"
|
||||
r="1.8863502" />
|
||||
<circle
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#bbbbbb;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
id="path1-1-7"
|
||||
cy="7.965826"
|
||||
cx="10.465826"
|
||||
r="1.8863502" />
|
||||
<circle
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#bbbbbb;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
id="path1-1-7-2"
|
||||
cy="13.0453"
|
||||
cx="5.3863502"
|
||||
r="1.8863502" />
|
||||
<circle
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#bbbbbb;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
id="path1-1-7-2-7"
|
||||
cy="13.0453"
|
||||
cx="10.465826"
|
||||
r="1.8863502" />
|
||||
<circle
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#bbbbbb;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
id="path1-5"
|
||||
cy="2.8863502"
|
||||
cx="10.465826"
|
||||
r="1.8863502" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
|
|
@ -0,0 +1,43 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://d1oshw4o6jues"
|
||||
path="res://.godot/imported/MultiSpliterButton.svg-2d0a07173fe1e75a33d019b041262a7d.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/script_splitter/core/ui/multi_split_container/icon/MultiSpliterButton.svg"
|
||||
dest_files=["res://.godot/imported/MultiSpliterButton.svg-2d0a07173fe1e75a33d019b041262a7d.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=8.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="Control.svg"
|
||||
inkscape:export-filename="..\GODOT\ToShare\favoritedock\addons\script-ide\split_gui\icon\MultiSplitItem.png"
|
||||
inkscape:export-xdpi="768"
|
||||
inkscape:export-ydpi="768"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#eeeeee"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#505050">
|
||||
<inkscape:page
|
||||
x="0"
|
||||
y="0"
|
||||
width="16"
|
||||
height="16"
|
||||
id="page2"
|
||||
margin="0"
|
||||
bleed="0" />
|
||||
</sodipodi:namedview>
|
||||
<circle
|
||||
cx="8"
|
||||
cy="8"
|
||||
fill="none"
|
||||
stroke="#8eef97"
|
||||
stroke-width="2"
|
||||
id="circle1"
|
||||
r="5" />
|
||||
<circle
|
||||
style="fill:none;fill-opacity:1;stroke:#8eef97;stroke-width:0.933;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
id="path2"
|
||||
cx="7.9897118"
|
||||
cy="7.9897118"
|
||||
r="2.1256859" />
|
||||
<path
|
||||
style="fill:#8eef97;fill-opacity:1;stroke:none;stroke-width:0.933;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
d="M 1,5 5,1 H 1 M 1,5 5,1 H 1"
|
||||
id="path7"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
style="fill:#8eef97;fill-opacity:1;stroke:none;stroke-width:0.933;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
d="M 15,5 V 1 h -5"
|
||||
id="path7-8"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
style="fill:#8eef97;fill-opacity:1;stroke:none;stroke-width:0.933;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
d="m 10,15 h 5 m -5,0 h 5 v -5"
|
||||
id="path7-8-5"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="fill:#8eef97;fill-opacity:1;stroke:none;stroke-width:0.933;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
d="m 1,10 4,5 H 1 m 0,0 H 5 1"
|
||||
id="path7-8-5-1"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
|
|
@ -0,0 +1,43 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dvg5cjdqtdpd7"
|
||||
path="res://.godot/imported/MultiSpliterItem.svg-1c00cf564bbcca09a4b17a958816995f.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/script_splitter/core/ui/multi_split_container/icon/MultiSpliterItem.svg"
|
||||
dest_files=["res://.godot/imported/MultiSpliterItem.svg-1c00cf564bbcca09a4b17a958816995f.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=8.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
|
|
@ -0,0 +1,998 @@
|
|||
@tool
|
||||
@icon("icon/MultiSpliter.svg")
|
||||
extends Container
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# https://github.com/CodeNameTwister/Multi-Split-Container
|
||||
#
|
||||
# Multi-Split-Container addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
const SplitContainerItem : Script = preload("split_container_item.gd")
|
||||
const SplitButton : Texture = preload("icon/MultiSpliterButton.svg")
|
||||
|
||||
@export_category("Multi-Split Settings")
|
||||
## Max columns by rows, after added childs this is eparated by row group by columns size!
|
||||
## [br][br]
|
||||
## if this value is 0, will not create rows spliters.
|
||||
@export_range(0.0, 1000.0, 1.0) var max_columns : int = 0:
|
||||
set(e):
|
||||
max_columns = maxi(0, e)
|
||||
|
||||
if Engine.is_editor_hint():
|
||||
for x : int in range(separators_line_offsets.size()):
|
||||
separators_line_offsets[x] = 0.0
|
||||
for x : LineSep in _separators:
|
||||
x.queue_free()
|
||||
|
||||
_separators.clear()
|
||||
_first = true
|
||||
update()
|
||||
|
||||
@export_group("Line Separator", "separator_line")
|
||||
## Line separator size.
|
||||
@export var separator_line_size : float = 4.0:
|
||||
set(e):
|
||||
separator_line_size = max(e, 0.0)
|
||||
update()
|
||||
|
||||
## Separator line color.
|
||||
@export var separator_line_color : Color = Color.MAGENTA:
|
||||
set(e):
|
||||
separator_line_color = e
|
||||
if separator_line_color == Color.MAGENTA: # That color reminds me of texture not found errors.
|
||||
var root = EditorInterface.get_base_control()
|
||||
separator_line_color = root.get_theme_color("base_color", "Editor")
|
||||
update()
|
||||
|
||||
## Separator line visibility.
|
||||
@export var separator_line_visible : bool = true:
|
||||
set(e):
|
||||
separator_line_visible = e
|
||||
for l : LineSep in _separators:
|
||||
l.visible = separator_line_visible
|
||||
|
||||
@export_subgroup("Behaviour", "behaviour_")
|
||||
## Enable function for auto expand lines container on inside focus.
|
||||
@export var behaviour_expand_on_focus : bool = true
|
||||
|
||||
## Enable function for auto expand lines container on double click in the line.
|
||||
@export var behaviour_expand_on_double_click : bool = true:
|
||||
set(e):
|
||||
behaviour_expand_on_double_click = e
|
||||
for l : LineSep in _separators:
|
||||
l.double_click_handler = behaviour_expand_on_double_click
|
||||
|
||||
## Enable movement by touching line.
|
||||
@export var behaviour_can_move_by_line : bool = true:
|
||||
set(e):
|
||||
behaviour_can_move_by_line = e
|
||||
for l : LineSep in _separators:
|
||||
l.draggable = behaviour_can_move_by_line
|
||||
|
||||
## This allow expand you current focused container if you shrunk it.
|
||||
@export var behaviour_can_expand_focus_same_container : bool = false
|
||||
|
||||
## Enable smooth when expand container.
|
||||
@export var behaviour_expand_smoothed : bool = true:
|
||||
set(e):
|
||||
behaviour_expand_smoothed = e
|
||||
if !e:
|
||||
if _tween and _tween.is_running():
|
||||
_tween.kill()
|
||||
_tween = null
|
||||
|
||||
## Time speed duration for reset expand container.
|
||||
@export_range(0.01, 1000.0, 0.01) var behaviour_expand_smoothed_time : float = 0.24:
|
||||
set(e):
|
||||
behaviour_expand_smoothed_time = maxf(0.01, e)
|
||||
if _tween and _tween.is_running():
|
||||
_tween.kill()
|
||||
_tween = null
|
||||
|
||||
## Custom initial offset for separator lines. (TODO: Still Working here!)
|
||||
@export var separators_line_offsets : Array[float] :
|
||||
set(e):
|
||||
separators_line_offsets = e
|
||||
|
||||
if Engine.is_editor_hint():
|
||||
if separators_line_offsets.size() != _separators.size():
|
||||
separators_line_offsets.resize(_separators.size())
|
||||
update()
|
||||
|
||||
@export_subgroup("Drag Button", "drag_button")
|
||||
|
||||
## Set if drag button always be visible (Useful for test button size)
|
||||
@export var drag_button_always_visible : bool = false:
|
||||
set(e):
|
||||
drag_button_always_visible = e
|
||||
|
||||
var min_visible_drag_button : float = 0.0
|
||||
if drag_button_always_visible:
|
||||
min_visible_drag_button = 0.4
|
||||
|
||||
for l : LineSep in _separators:
|
||||
if l.button:
|
||||
l.button.modulate.a = 0.0
|
||||
l.button.min_no_focus_transparense = min_visible_drag_button
|
||||
|
||||
## Min size for drag button visible on split lines.
|
||||
@export_range(1.0, 200.0, 0.1) var drag_button_size : float = 24.0:
|
||||
set(e):
|
||||
drag_button_size = e
|
||||
update()
|
||||
|
||||
## Modulate color for the drag button.
|
||||
@export var drag_button_modulate : Color = Color.MAGENTA:
|
||||
set(e):
|
||||
drag_button_modulate = e
|
||||
if drag_button_modulate == Color.MAGENTA:
|
||||
if Engine.is_editor_hint():
|
||||
var root : Control = EditorInterface.get_base_control()
|
||||
drag_button_modulate = root.get_theme_color("base_color", "Editor").lightened(0.5)
|
||||
update()
|
||||
|
||||
## Change default drag button icon.
|
||||
@export var drag_button_icon : Texture = null:
|
||||
set(e):
|
||||
drag_button_icon = e
|
||||
update()
|
||||
|
||||
var _separators : Array[LineSep] = []
|
||||
var _last_container_focus : Node = null
|
||||
var _frame : int = 1
|
||||
var _first : bool = true
|
||||
var _tween : Tween = null
|
||||
|
||||
func get_separators() -> Array[LineSep]:
|
||||
return _separators
|
||||
|
||||
## Get line begin offset limit.
|
||||
func get_line_seperator_left_offset_limit(index : int) -> float:
|
||||
if index < _separators.size():
|
||||
var line_sep : LineSep = _separators[index]
|
||||
if !line_sep.is_vertical:
|
||||
if index < 1:
|
||||
return -_separators[index].initial_position.x
|
||||
var next : LineSep = _separators[index - 1]
|
||||
return (next.initial_position.x + (next.size.x/2.0)) - _separators[index].initial_position.x
|
||||
else:
|
||||
if index < 1:
|
||||
return -_separators[index].initial_position.y
|
||||
var next : LineSep = _separators[index - 1]
|
||||
return (next.initial_position.y + (next.size.y/2.0)) - _separators[index].initial_position.y
|
||||
push_warning("[PLUGIN] Not valid index for line separator!")
|
||||
return 0.0
|
||||
|
||||
## Get line end offset limit.
|
||||
func get_line_seperator_right_offset_limit(index : int) -> float:
|
||||
if index < _separators.size():
|
||||
var line_sep : LineSep = _separators[index]
|
||||
if !line_sep.is_vertical:
|
||||
if index + 1 == _separators.size():
|
||||
return (size.x/2.0) -_separators[index].initial_position.x
|
||||
var current : LineSep = _separators[index]
|
||||
return (_separators[index + 1].initial_position.x - current.initial_position.x + (current.size.x/2.0))
|
||||
else:
|
||||
if index + 1 == _separators.size():
|
||||
return size.x -_separators[index].initial_position.y
|
||||
var current : LineSep = _separators[index]
|
||||
return (_separators[index + 1].initial_position.y - current.initial_position.y + (current.size.y/2.0))
|
||||
push_warning("[PLUGIN] Not valid index for line separator!")
|
||||
return 0.0
|
||||
|
||||
# This is function is util when you want expand or constraint manualy offset.
|
||||
## Update offset of the line
|
||||
func update_line_separator_offset(index : int, offset : float) -> void:
|
||||
var line_sep : LineSep = _separators[index]
|
||||
line_sep.offset = offset
|
||||
line_sep.force_update()
|
||||
|
||||
## Get total line count.
|
||||
func get_line_separator_count() -> int:
|
||||
return _separators.size()
|
||||
|
||||
## Get Line reference by index, see get_line_separator_count()
|
||||
func get_line_separator(index : int) -> LineSep:
|
||||
return _separators[index]
|
||||
|
||||
## Get if line separator is vertical.
|
||||
func is_vertical_line_separator(index : int) -> bool:
|
||||
if index < _separators.size():
|
||||
return _separators[index].is_vertical
|
||||
push_warning("[PLUGIN] Not valid index for line separator!")
|
||||
return false
|
||||
|
||||
## Expand splited container by index container.
|
||||
func expand_splited_container(node : Node) -> void:
|
||||
var same : bool = _last_container_focus == node
|
||||
if same and !behaviour_can_expand_focus_same_container:
|
||||
return
|
||||
|
||||
_last_container_focus = node
|
||||
|
||||
if !behaviour_expand_on_focus:
|
||||
return
|
||||
|
||||
if _tween and _tween.is_running():
|
||||
if same:
|
||||
return
|
||||
_tween.kill()
|
||||
_tween = null
|
||||
|
||||
var top_lines : Array[LineSep] = []
|
||||
var bottom_lines : Array[LineSep] = []
|
||||
|
||||
var update_required : bool = false
|
||||
|
||||
for line : LineSep in _separators:
|
||||
if node in line.top_items:
|
||||
update_required = update_required or line.offset < 0.0
|
||||
top_lines.append(line)
|
||||
elif node in line.bottom_items:
|
||||
update_required = update_required or line.offset > 0.0
|
||||
bottom_lines.append(line)
|
||||
|
||||
if update_required:
|
||||
if behaviour_expand_smoothed:
|
||||
_tween = get_tree().create_tween()
|
||||
_tween.tween_method(_reset_expanded_lines.bind(top_lines, bottom_lines), 0.0, 1.0, behaviour_expand_smoothed_time)
|
||||
else:
|
||||
_reset_expanded_lines(1.0, top_lines, bottom_lines)
|
||||
|
||||
func _reset_expanded_lines(_lerp : float, top_lines : Array[LineSep], bottom_lines : Array[LineSep]) -> void:
|
||||
for iline : int in range(top_lines.size() - 1, -1, -1):
|
||||
var line : LineSep = top_lines[iline]
|
||||
if is_instance_valid(line):
|
||||
if line.offset < 0.0:
|
||||
line.offset = lerp(line.offset, 0.0, _lerp)
|
||||
else:
|
||||
top_lines.remove_at(iline)
|
||||
|
||||
for iline : int in range(bottom_lines.size() - 1, -1, -1):
|
||||
var line : LineSep = bottom_lines[iline]
|
||||
if is_instance_valid(line):
|
||||
if line.offset > 0.0:
|
||||
line.offset = lerp(line.offset, 0.0, _lerp)
|
||||
else:
|
||||
bottom_lines.remove_at(iline)
|
||||
|
||||
for line : LineSep in top_lines:
|
||||
line.force_update()
|
||||
for line : LineSep in bottom_lines:
|
||||
line.force_update()
|
||||
|
||||
## Get initial position of a separator line.
|
||||
func get_line_separator_initial_position(index : int) -> Vector2:
|
||||
if index < _separators.size():
|
||||
return _separators[index].initial_position
|
||||
push_warning("[PLUGIN] Not valid index for line separator!")
|
||||
return Vector2.ZERO
|
||||
|
||||
class DragButton extends Button:
|
||||
var _frm : float = 0.0
|
||||
var _line_sep : LineSep = null
|
||||
var _is_pressed : bool = false
|
||||
|
||||
var is_hover : bool = false
|
||||
|
||||
var _hover : Array[bool] = [false, false]
|
||||
|
||||
var min_no_focus_transparense : float = 0.0:
|
||||
set(e):
|
||||
min_no_focus_transparense = e
|
||||
modulate.a = maxf(modulate.a, min_no_focus_transparense)
|
||||
|
||||
static var DEFAULT_STYLE : StyleBox = null
|
||||
|
||||
func set_drag_icon(new_icon : Texture) -> void:
|
||||
if icon != new_icon:
|
||||
if new_icon == null:
|
||||
icon = SplitButton
|
||||
return
|
||||
icon = new_icon
|
||||
|
||||
func update_gui() -> void:
|
||||
if !_line_sep:
|
||||
return
|
||||
|
||||
if _line_sep.is_vertical:
|
||||
_line_sep.mouse_default_cursor_shape = Control.CURSOR_VSPLIT
|
||||
mouse_default_cursor_shape = Control.CURSOR_VSPLIT
|
||||
else:
|
||||
_line_sep.mouse_default_cursor_shape = Control.CURSOR_HSPLIT
|
||||
mouse_default_cursor_shape = Control.CURSOR_HSPLIT
|
||||
|
||||
func set_line(line_sep : LineSep) -> void:
|
||||
if _line_sep:
|
||||
if _line_sep.mouse_entered.is_connected(_on_enter):
|
||||
_line_sep.mouse_entered.disconnect(_on_enter)
|
||||
if _line_sep.mouse_exited.is_connected(_on_exit):
|
||||
_line_sep.mouse_exited.disconnect(_on_exit)
|
||||
if _line_sep.gui_input.is_connected(_on_input):
|
||||
_line_sep.gui_input.disconnect(_on_input)
|
||||
|
||||
_line_sep = line_sep
|
||||
|
||||
if _line_sep:
|
||||
if !_line_sep.mouse_entered.is_connected(_on_enter):
|
||||
_line_sep.mouse_entered.connect(_on_enter.bind(1))
|
||||
if !_line_sep.mouse_exited.is_connected(_on_exit):
|
||||
_line_sep.mouse_exited.connect(_on_exit.bind(1))
|
||||
if !_line_sep.gui_input.is_connected(_on_input):
|
||||
_line_sep.gui_input.connect(_on_input)
|
||||
|
||||
|
||||
func _init(line_sep : LineSep = null) -> void:
|
||||
modulate.a = 0.0
|
||||
|
||||
set_line(line_sep)
|
||||
|
||||
button_down.connect(_on_press)
|
||||
button_up.connect(_out_press)
|
||||
mouse_entered.connect(_on_enter.bind(0))
|
||||
mouse_exited.connect(_on_exit.bind(0))
|
||||
|
||||
gui_input.connect(_custom_input)
|
||||
|
||||
icon = SplitButton
|
||||
icon_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
vertical_icon_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
expand_icon = true
|
||||
|
||||
if null != icon:
|
||||
flat = true
|
||||
|
||||
if DEFAULT_STYLE == null:
|
||||
DEFAULT_STYLE = StyleBoxEmpty.new()
|
||||
|
||||
focus_mode = Control.FOCUS_CLICK
|
||||
|
||||
set(&"theme_override_styles/focus", DEFAULT_STYLE)
|
||||
set(&"theme_override_styles/disabled_mirrored", DEFAULT_STYLE)
|
||||
set(&"theme_override_styles/disabled", DEFAULT_STYLE)
|
||||
set(&"theme_override_styles/hover_pressed_mirrored", DEFAULT_STYLE)
|
||||
set(&"theme_override_styles/hover_pressed", DEFAULT_STYLE)
|
||||
set(&"theme_override_styles/hover_mirrored", DEFAULT_STYLE)
|
||||
set(&"theme_override_styles/hover", DEFAULT_STYLE)
|
||||
set(&"theme_override_styles/pressed_mirrored", DEFAULT_STYLE)
|
||||
set(&"theme_override_styles/pressed", DEFAULT_STYLE)
|
||||
set(&"theme_override_styles/normal_mirrored", DEFAULT_STYLE)
|
||||
set(&"theme_override_styles/normal", DEFAULT_STYLE)
|
||||
|
||||
z_as_relative = true
|
||||
z_index = 20
|
||||
|
||||
update_gui()
|
||||
|
||||
func _custom_input(e : InputEvent) -> void:
|
||||
if e is InputEventMouseButton:
|
||||
if e.pressed and e.double_click:
|
||||
get_tree().call_group(&"ScriptSplitter", &"swap", get_parent())
|
||||
|
||||
func _on_input(e : InputEvent) -> void:
|
||||
if e is InputEventMouseButton:
|
||||
if e.pressed and e.double_click:
|
||||
if _line_sep and _line_sep.double_click_handler:
|
||||
_line_sep.offset = 0.0
|
||||
_line_sep.offset_updated.emit()
|
||||
elif e.pressed and _line_sep.draggable and e.button_index == 1:
|
||||
button_down.emit()
|
||||
elif !e.pressed and _line_sep.draggable and e.button_index == 1:
|
||||
button_up.emit()
|
||||
|
||||
func set_line_sep_reference(ref : LineSep) -> void:
|
||||
_line_sep = ref
|
||||
|
||||
func _ready() -> void:
|
||||
set_process(false)
|
||||
|
||||
func _on_enter(x : int = 0) -> void:
|
||||
_hover[x] = true
|
||||
|
||||
_frm = 0.0
|
||||
modulate.a = 1.0
|
||||
is_hover = true
|
||||
set_process(true)
|
||||
|
||||
func _on_exit(x : int = 0) -> void:
|
||||
_hover[x] = false
|
||||
|
||||
for h : bool in _hover:
|
||||
if h != false:
|
||||
return
|
||||
|
||||
_frm = 0.0
|
||||
modulate.a = 1.0
|
||||
is_hover = false
|
||||
set_process(true)
|
||||
|
||||
func _on_press() -> void:
|
||||
_is_pressed = true
|
||||
_frm = 0.0
|
||||
modulate.a = 1.0
|
||||
set_process(true)
|
||||
|
||||
func _out_press() -> void:
|
||||
_is_pressed = false
|
||||
set_process(true)
|
||||
|
||||
func _process(delta : float) -> void:
|
||||
if !has_focus() and !is_hover:
|
||||
_frm += delta * 0.4
|
||||
if _frm >= 1.0:
|
||||
_frm = 1.0
|
||||
set_process(false)
|
||||
modulate.a = lerp(modulate.a, min_no_focus_transparense, _frm)
|
||||
if _is_pressed:
|
||||
var mpos : Vector2 = _line_sep.get_parent().get_local_mouse_position()
|
||||
if mpos != get_rect().get_center():
|
||||
_line_sep.update_offset_by_position(mpos)
|
||||
|
||||
class UndoredoSplit extends RefCounted:
|
||||
var object : SplitContainerItem = null
|
||||
var c_objects : Array[Node] = []
|
||||
|
||||
class LineSep extends ColorRect:
|
||||
signal offset_updated()
|
||||
|
||||
var top_lines : Array[LineSep] = []
|
||||
var bottom_lines : Array[LineSep] = []
|
||||
|
||||
var top_items : Array[Control] = []
|
||||
var bottom_items : Array[Control] = []
|
||||
|
||||
var is_vertical : bool = false:
|
||||
set(e):
|
||||
is_vertical = e
|
||||
|
||||
if button:
|
||||
button.update_gui()
|
||||
|
||||
var row : int = 0
|
||||
|
||||
var initial_position : Vector2 = Vector2.ZERO
|
||||
var offset : float = 0.0
|
||||
|
||||
var min_size_offset : float = 0.0
|
||||
|
||||
var prev_line : LineSep = null
|
||||
var next_line : LineSep = null
|
||||
|
||||
var button : DragButton = null
|
||||
|
||||
var double_click_handler : bool = true
|
||||
var draggable : bool = true
|
||||
|
||||
func set_next_line(next : LineSep = null) -> void:
|
||||
next_line = next
|
||||
next.prev_line = self
|
||||
|
||||
func clear() -> void:
|
||||
top_items.clear()
|
||||
bottom_items.clear()
|
||||
top_lines.clear()
|
||||
bottom_lines.clear()
|
||||
|
||||
func reset() -> void:
|
||||
position = initial_position
|
||||
update_items()
|
||||
|
||||
func update_items() -> void:
|
||||
if is_vertical:
|
||||
for item : Control in top_items:
|
||||
item.size.y = position.y - item.position.y
|
||||
if !prev_line:
|
||||
item.position.y = 0.0
|
||||
|
||||
for item : Control in bottom_items:
|
||||
item.position.y = position.y + size.y
|
||||
|
||||
if next_line:
|
||||
item.size.y = next_line.position.y - item.position.y
|
||||
else:
|
||||
item.size.y = get_parent().size.y - item.position.y
|
||||
else:
|
||||
for item : Control in top_items:
|
||||
item.size.x = position.x - item.position.x + (size.x / 2.0) - 2.0
|
||||
if !prev_line:
|
||||
item.position.x = 0.0
|
||||
|
||||
for item : Control in bottom_items:
|
||||
var diff : float = position.x + (size.x / 2.0) + 2.0
|
||||
item.position.x = diff
|
||||
|
||||
if next_line:
|
||||
item.size.x = next_line.position.x - item.position.x
|
||||
else:
|
||||
item.size.x = get_parent().size.x - item.position.x
|
||||
|
||||
func force_update() -> void:
|
||||
update_offset_by_position(initial_position + Vector2(offset * int(!is_vertical), offset * int(is_vertical)))
|
||||
|
||||
func get_current_position() -> Vector2:
|
||||
return initial_position + Vector2(offset * int(!is_vertical), offset * int(is_vertical))
|
||||
|
||||
func update_offset_by_position(vpos : Vector2) -> void:
|
||||
if is_vertical:
|
||||
min_size_offset = 0.0
|
||||
for x : Control in top_items:
|
||||
min_size_offset = maxf(min_size_offset, x.get_minimum_size().y)
|
||||
if prev_line:
|
||||
prev_line.min_size_offset = 0.0
|
||||
for x : Control in prev_line.bottom_items:
|
||||
prev_line.min_size_offset = maxf(prev_line.min_size_offset, x.get_minimum_size().y)
|
||||
|
||||
offset = vpos.y - initial_position.y
|
||||
offset = minf(offset, get_parent().size.y - (initial_position.y + size.y + min_size_offset))
|
||||
offset = maxf(offset, -(initial_position.y - min_size_offset))
|
||||
|
||||
if next_line:
|
||||
var val : float = next_line.position.y - (initial_position.y + size.y + min_size_offset)
|
||||
if offset > val:
|
||||
offset = val
|
||||
else:
|
||||
var val : float = get_parent().size.y - (initial_position.y + (size.y / 2.0) + min_size_offset)
|
||||
if offset > val:
|
||||
offset = val
|
||||
if prev_line:
|
||||
var val : float = -(initial_position.y - (prev_line.position.y + prev_line.size.y + prev_line.min_size_offset))
|
||||
|
||||
if offset < val:
|
||||
offset = val
|
||||
else:
|
||||
var top_size_offset : float = 0.0
|
||||
for x : Control in top_items:
|
||||
top_size_offset = maxf(top_size_offset, x.get_minimum_size().y)
|
||||
offset = maxf(offset, top_size_offset-initial_position.y)
|
||||
|
||||
position.y = initial_position.y + offset
|
||||
|
||||
for line : LineSep in top_lines:
|
||||
line.size.y = position.y - line.position.y
|
||||
|
||||
for line : LineSep in bottom_lines:
|
||||
line.position.y = position.y + size.y
|
||||
|
||||
if next_line:
|
||||
line.size.y = next_line.position.y - line.position.y
|
||||
else:
|
||||
line.size.y = get_parent().size.y - line.position.y
|
||||
else:
|
||||
min_size_offset = 0.0
|
||||
for x : Control in bottom_items:
|
||||
min_size_offset = maxf(min_size_offset, x.get_minimum_size().x)
|
||||
|
||||
if prev_line:
|
||||
prev_line.min_size_offset = 0.0
|
||||
for x : Control in prev_line.bottom_items:
|
||||
prev_line.min_size_offset = maxf(prev_line.min_size_offset, x.get_minimum_size().x)
|
||||
|
||||
offset = vpos.x - initial_position.x
|
||||
offset = minf(offset, get_parent().size.x - (initial_position.x + size.x + min_size_offset))
|
||||
offset = maxf(offset, -initial_position.x)
|
||||
|
||||
if next_line:
|
||||
var val : float = next_line.position.x - (initial_position.x + size.x + min_size_offset)
|
||||
if offset > val:
|
||||
offset = val
|
||||
else:
|
||||
var val : float = get_parent().size.x - (initial_position.x + (size.x/2.0) + min_size_offset)
|
||||
if offset > val:
|
||||
offset = val
|
||||
if prev_line:
|
||||
var val : float = -(initial_position.x - (prev_line.position.x + prev_line.size.x + prev_line.min_size_offset))
|
||||
|
||||
if offset < val:
|
||||
offset = val
|
||||
else:
|
||||
var top_size_offset : float = 0.0
|
||||
for x : Control in top_items:
|
||||
top_size_offset = maxf(top_size_offset, x.get_minimum_size().x)
|
||||
offset = maxf(offset, top_size_offset-initial_position.x)
|
||||
|
||||
position.x = initial_position.x + offset
|
||||
update_items()
|
||||
|
||||
func _draw() -> void:
|
||||
update()
|
||||
|
||||
func update() -> void:
|
||||
button.rotation_degrees = 90.0 * int(is_vertical)
|
||||
button.pivot_offset = button.size / 2.0
|
||||
button.position = size / 2.0 - button.pivot_offset
|
||||
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
color = Color.RED
|
||||
|
||||
func _ready() -> void:
|
||||
name = "SplitLine"
|
||||
if button == null:
|
||||
button = DragButton.new(self)
|
||||
add_child(button, false, Node.INTERNAL_MODE_BACK)
|
||||
|
||||
func _test() -> void:
|
||||
queue_redraw()
|
||||
|
||||
func _init() -> void:
|
||||
child_entered_tree.connect(_on_enter)
|
||||
child_exiting_tree.connect(_on_exiting)
|
||||
|
||||
func update() -> void:
|
||||
set_process(true)
|
||||
|
||||
func _create_separator() -> Control:
|
||||
var line_sep : LineSep = LineSep.new()
|
||||
line_sep.offset_updated.connect(update)
|
||||
return line_sep
|
||||
|
||||
func _undoredo_undo(ur : UndoredoSplit) -> void:
|
||||
if !is_instance_valid(ur):
|
||||
return
|
||||
|
||||
var split : SplitContainerItem = ur.object
|
||||
if is_instance_valid(split):
|
||||
if split.get_parent() == self:
|
||||
ur.c_objects = split.get_children()
|
||||
for x : Node in ur.c_objects:
|
||||
split.remove_child(x)
|
||||
if x is Control:
|
||||
x.visible = false
|
||||
add_child(x)
|
||||
if is_instance_valid(split) and split.get_parent() == self:
|
||||
remove_child(split)
|
||||
|
||||
func _update() -> void:
|
||||
var items : Array[Control] = []
|
||||
for x : Node in get_children():
|
||||
if is_instance_valid(x) and x is Control:
|
||||
if x.visible and !x.is_queued_for_deletion():
|
||||
if x is SplitContainerItem:
|
||||
if x.get_child_count() > 0:
|
||||
var _is_visible : bool = false
|
||||
for y : Node in x.get_children():
|
||||
if y is Control and y.visible:
|
||||
_is_visible = true
|
||||
break
|
||||
if !_is_visible:
|
||||
continue
|
||||
else:
|
||||
x.queue_free()
|
||||
continue
|
||||
elif x is DragButton or x is LineSep:
|
||||
x.queue_free()
|
||||
continue
|
||||
else:
|
||||
var container : SplitContainerItem = SplitContainerItem.new()
|
||||
|
||||
add_child(container, true)
|
||||
|
||||
x.reparent(container)
|
||||
x = container
|
||||
|
||||
|
||||
x.size_flags_horizontal = Control.SIZE_FILL
|
||||
x.size_flags_vertical = Control.SIZE_FILL
|
||||
x.clip_contents = true
|
||||
x.custom_minimum_size = Vector2.ZERO
|
||||
items.append(x)
|
||||
|
||||
var totals : int = items.size()
|
||||
var rows : int = 0
|
||||
|
||||
if max_columns > 0:
|
||||
var _totals : int = totals
|
||||
rows = 0
|
||||
while _totals > max_columns:
|
||||
_totals -= max_columns
|
||||
rows += 1
|
||||
totals -= rows
|
||||
|
||||
if totals < 1:
|
||||
for x : int in range(0, _separators.size(), 1):
|
||||
_separators[x].queue_free()
|
||||
_separators[x] = null
|
||||
_separators.clear()
|
||||
|
||||
for x : Control in items:
|
||||
x.position = Vector2.ZERO
|
||||
x.size = get_rect().size
|
||||
return
|
||||
else:
|
||||
if separator_line_size <= 0.0:
|
||||
for x : int in range(0, _separators.size(), 1):
|
||||
_separators[x].queue_free()
|
||||
_separators[x] = null
|
||||
_separators.clear()
|
||||
else:
|
||||
var sep : int = totals - 1 + rows
|
||||
for x : int in range(sep, _separators.size(), 1):
|
||||
_separators[x].queue_free()
|
||||
_separators[x] = null
|
||||
_separators.resize(sep)
|
||||
for x : int in range(0, _separators.size(), 1):
|
||||
if _separators[x] == null:
|
||||
_separators[x] = _create_separator()
|
||||
|
||||
rows += 1
|
||||
if max_columns > 1:
|
||||
if totals > max_columns:
|
||||
totals = max_columns
|
||||
|
||||
var rect_size : Vector2 = get_rect().size
|
||||
var start_position : Vector2 = Vector2.ZERO
|
||||
|
||||
var size_split : Vector2 = (rect_size / Vector2(totals, rows))
|
||||
|
||||
var size_sep : Vector2 = Vector2.ONE * separator_line_size
|
||||
|
||||
if totals > 1:
|
||||
size_sep = (size_sep / (totals - 1))
|
||||
|
||||
var item_size : Vector2 = Vector2(size_split.x, size_split.y)
|
||||
var line_size : Vector2 = Vector2(separator_line_size, item_size.y)
|
||||
|
||||
var total_items : int = items.size()
|
||||
|
||||
var vpos : Vector2 = Vector2.ZERO
|
||||
var current_row : int = 0
|
||||
|
||||
var item_index : int = 0
|
||||
|
||||
var last_vline : LineSep = null
|
||||
var last_hline : LineSep = null
|
||||
|
||||
for x : Control in items:
|
||||
x.position = Vector2.ZERO
|
||||
x.size = x.get_minimum_size()
|
||||
|
||||
for z : int in range(_separators.size()):
|
||||
var x : LineSep = _separators[z]
|
||||
|
||||
x.clear()
|
||||
|
||||
start_position.x += 1
|
||||
|
||||
if 0 < max_columns and start_position.x + 1 > max_columns:
|
||||
total_items -= max_columns
|
||||
start_position.x = 0.0
|
||||
start_position.y += 1.0
|
||||
current_row += 1
|
||||
if total_items <= max_columns and total_items > 0:
|
||||
size_split = (rect_size / Vector2(total_items, rows))
|
||||
if total_items == 1:
|
||||
size_sep = Vector2.ONE * separator_line_size
|
||||
else:
|
||||
size_sep = ((Vector2.ONE * separator_line_size) / (total_items - 1))
|
||||
item_size = Vector2(size_split.x, size_split.y)
|
||||
line_size = Vector2(separator_line_size, rect_size.y - x.position.y)
|
||||
|
||||
vpos = Vector2(0.0, start_position.y) * item_size
|
||||
x.is_vertical = true
|
||||
|
||||
if x.get_parent() == null:
|
||||
add_child(x, false, Node.INTERNAL_MODE_BACK)
|
||||
|
||||
|
||||
x.row = current_row
|
||||
|
||||
if items.size() > 0:
|
||||
var it : int = mini(item_index, items.size() - 1)
|
||||
var min_size : float = 0.0
|
||||
|
||||
var _has : bool = false
|
||||
|
||||
for y : int in range(z - 1, -1, -1):
|
||||
if it > -1:
|
||||
var item : Control = items[it]
|
||||
x.top_items.append(item)
|
||||
min_size = maxf(item.get_minimum_size().y, min_size)
|
||||
it -= 1
|
||||
|
||||
var ln : LineSep = _separators[y]
|
||||
if ln.is_vertical:
|
||||
_has = true
|
||||
break
|
||||
x.top_lines.append(ln)
|
||||
if !_has:
|
||||
for _it : int in range(it, -1, -1):
|
||||
var item : Control = items[it]
|
||||
x.top_items.append(item)
|
||||
|
||||
if item_index + 1 < items.size():
|
||||
it = item_index + 1
|
||||
_has = false
|
||||
for y : int in range(z + 1, _separators.size(), 1):
|
||||
if it < items.size():
|
||||
var item : Control = items[it]
|
||||
x.bottom_items.append(item)
|
||||
it += 1
|
||||
|
||||
var ln : LineSep = _separators[y]
|
||||
if ln.is_vertical:
|
||||
_has = true
|
||||
break
|
||||
x.bottom_lines.append(ln)
|
||||
if !_has:
|
||||
for _it : int in range(it, items.size(), 1):
|
||||
var item : Control = items[_it]
|
||||
x.bottom_items.append(item)
|
||||
|
||||
var vline_size : Vector2 = Vector2(rect_size.x, separator_line_size)
|
||||
|
||||
x.initial_position = vpos
|
||||
x.initial_position.y -= (vline_size.y) / 2.0
|
||||
x.position = x.initial_position
|
||||
|
||||
x.button.size = Vector2(drag_button_size, drag_button_size)
|
||||
|
||||
x.set(&"size", vline_size)
|
||||
x.update()
|
||||
|
||||
if last_vline:
|
||||
last_vline.set_next_line(x)
|
||||
|
||||
last_vline = x
|
||||
last_hline = null
|
||||
item_index += 1
|
||||
continue
|
||||
|
||||
vpos = start_position * item_size
|
||||
|
||||
if x.get_parent() == null:
|
||||
add_child(x, false, Node.INTERNAL_MODE_BACK)
|
||||
|
||||
|
||||
if item_index < items.size():
|
||||
var item : Control = items[item_index]
|
||||
x.top_items.append(item)
|
||||
item_index += 1
|
||||
if item_index < items.size():
|
||||
if z + 1 < _separators.size():
|
||||
if !_separators[z].is_vertical:
|
||||
x.bottom_items.append(items[item_index])
|
||||
else:
|
||||
x.bottom_items.append(items[item_index])
|
||||
|
||||
x.initial_position = vpos
|
||||
x.initial_position.x -= (line_size.x) / 2.0
|
||||
|
||||
x.button.size = Vector2(drag_button_size, drag_button_size)
|
||||
|
||||
x.row = current_row
|
||||
x.position = x.initial_position
|
||||
|
||||
x.set(&"size", line_size)
|
||||
x.update()
|
||||
|
||||
if last_hline:
|
||||
last_hline.set_next_line(x)
|
||||
last_hline = x
|
||||
|
||||
for x : Control in items:
|
||||
x.size = size
|
||||
|
||||
var min_visible_drag_button : float = 0.0
|
||||
if drag_button_always_visible:
|
||||
min_visible_drag_button = 0.4
|
||||
|
||||
if _first:
|
||||
for l : LineSep in _separators:
|
||||
l.visible = separator_line_visible
|
||||
l.color = separator_line_color
|
||||
l.double_click_handler = behaviour_expand_on_double_click
|
||||
l.button.self_modulate = drag_button_modulate
|
||||
l.button.min_no_focus_transparense = min_visible_drag_button
|
||||
l.button.set_drag_icon(drag_button_icon)
|
||||
l.draggable = behaviour_can_move_by_line
|
||||
|
||||
l.reset()
|
||||
|
||||
else:
|
||||
if separators_line_offsets.size() > 0:
|
||||
for l : int in range(0, _separators.size(), 1):
|
||||
if l < separators_line_offsets.size():
|
||||
_separators[l].offset = separators_line_offsets[l]
|
||||
continue
|
||||
break
|
||||
|
||||
for l : LineSep in _separators:
|
||||
l.visible = separator_line_visible
|
||||
l.color = separator_line_color
|
||||
l.double_click_handler = behaviour_expand_on_double_click
|
||||
l.button.self_modulate = drag_button_modulate
|
||||
l.button.min_no_focus_transparense = min_visible_drag_button
|
||||
l.button.set_drag_icon(drag_button_icon)
|
||||
l.draggable = behaviour_can_move_by_line
|
||||
|
||||
l.force_update()
|
||||
|
||||
if !Engine.is_editor_hint():
|
||||
separators_line_offsets.clear()
|
||||
else:
|
||||
for l : int in range(0, _separators.size(), 1):
|
||||
if l < separators_line_offsets.size():
|
||||
separators_line_offsets[l] = _separators[l].offset
|
||||
continue
|
||||
break
|
||||
|
||||
func _on_enter(n : Node) -> void:
|
||||
n.is_inside_tree()
|
||||
if n is SplitContainerItem or (n is Control and !Engine.is_editor_hint()):
|
||||
if !n.visibility_changed.is_connected(_on_visible):
|
||||
n.visibility_changed.connect(_on_visible)
|
||||
if is_node_ready():
|
||||
for x : int in range(separators_line_offsets.size()):
|
||||
separators_line_offsets[x] = 0.0
|
||||
update()
|
||||
|
||||
func _on_visible() -> void:
|
||||
update()
|
||||
|
||||
func _on_exiting(n : Node) -> void:
|
||||
if n is SplitContainerItem or (n is Control and !Engine.is_editor_hint()):
|
||||
if is_node_ready():
|
||||
for x : int in range(separators_line_offsets.size()):
|
||||
separators_line_offsets[x] = 0.0
|
||||
for x : LineSep in _separators:
|
||||
x.offset = 0.0
|
||||
if n.visibility_changed.is_connected(_on_visible):
|
||||
n.visibility_changed.disconnect(_on_visible)
|
||||
update()
|
||||
|
||||
func _process(__ : float) -> void:
|
||||
if is_node_ready():
|
||||
if _frame > 0:
|
||||
_frame -= 1
|
||||
return
|
||||
_update()
|
||||
if _first:
|
||||
_first = false
|
||||
else:
|
||||
set_process(false)
|
||||
|
||||
func _on_exiting_tree() -> void:
|
||||
var vp : Viewport = get_viewport()
|
||||
if vp and vp.size_changed.is_connected(update):
|
||||
vp.size_changed.disconnect(update)
|
||||
|
||||
var parent : Node = get_parent()
|
||||
if parent is Control:
|
||||
if parent.item_rect_changed.is_connected(update):
|
||||
parent.item_rect_changed.disconnect(update)
|
||||
|
||||
func _enter_tree() -> void:
|
||||
var vp : Viewport = get_viewport()
|
||||
if vp and !vp.size_changed.is_connected(update):
|
||||
vp.size_changed.connect(update)
|
||||
|
||||
var parent : Node = get_parent()
|
||||
if parent is Control:
|
||||
if !parent.item_rect_changed.is_connected(update):
|
||||
parent.item_rect_changed.connect(update)
|
||||
|
||||
if !tree_exiting.is_connected(_on_exiting_tree):
|
||||
tree_exiting.connect(_on_exiting_tree)
|
||||
|
||||
func _on_draw() -> void:
|
||||
update()
|
||||
|
||||
func _ready() -> void:
|
||||
separator_line_color = separator_line_color
|
||||
drag_button_modulate = drag_button_modulate
|
||||
|
||||
size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
size_flags_vertical =Control.SIZE_EXPAND_FILL
|
||||
|
||||
set_deferred(&"anchor_left", 0.0)
|
||||
set_deferred(&"anchor_top", 0.0)
|
||||
set_deferred(&"anchor_bottom", 1.0)
|
||||
set_deferred(&"anchor_right", 1.0)
|
||||
|
||||
if Engine.is_editor_hint():
|
||||
draw.connect(_on_draw)
|
||||
|
||||
if _first:
|
||||
update()
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://sffqwro3flkc
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
@tool
|
||||
@icon("icon/MultiSpliterItem.svg")
|
||||
extends Control
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# https://github.com/CodeNameTwister/Multi-Split-Container
|
||||
#
|
||||
# Multi-Split-Container addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
var focus_handler : bool = false
|
||||
|
||||
## Expand if tight by spliter
|
||||
func show_splited_container() -> void:
|
||||
var parent : Node = get_parent()
|
||||
if parent.has_method(&"expand_splited_container"):
|
||||
parent.call(&"expand_splited_container", self)
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
set_process(false)
|
||||
|
||||
size_flags_horizontal = Control.SIZE_FILL
|
||||
size_flags_vertical = Control.SIZE_FILL
|
||||
|
||||
set_deferred(&"anchor_left", 0.0)
|
||||
set_deferred(&"anchor_top", 0.0)
|
||||
set_deferred(&"anchor_bottom", 1.0)
|
||||
set_deferred(&"anchor_right", 1.0)
|
||||
|
||||
func _init() -> void:
|
||||
name = "SplitContainerItem"
|
||||
|
||||
child_exiting_tree.connect(_on_child_exiting_tree)
|
||||
child_entered_tree.connect(_on_child_entered_tree)
|
||||
|
||||
func _on_visible() -> void:
|
||||
var _visible : bool = false
|
||||
for x : Node in get_children():
|
||||
if x is Control:
|
||||
if x.visible:
|
||||
_visible = true
|
||||
break
|
||||
visible = _visible
|
||||
|
||||
func _on_child_entered_tree(n : Node) -> void:
|
||||
if n is Control:
|
||||
n.size = size
|
||||
n.set_anchor(SIDE_LEFT, 0.0)
|
||||
n.set_anchor(SIDE_RIGHT, 1.0)
|
||||
n.set_anchor(SIDE_TOP, 0.0)
|
||||
n.set_anchor(SIDE_BOTTOM, 1.0)
|
||||
if !n.visibility_changed.is_connected(_on_visible):
|
||||
n.visibility_changed.connect(_on_visible)
|
||||
|
||||
func _disconnect(n : Node) -> void:
|
||||
if n is Control:
|
||||
if n.visibility_changed.is_connected(_on_visible):
|
||||
n.visibility_changed.disconnect(_on_visible)
|
||||
for x : Node in n.get_children():
|
||||
_disconnect(x)
|
||||
|
||||
func _on_child_exiting_tree(n : Node) -> void:
|
||||
_disconnect(n)
|
||||
|
||||
func _enter_tree() -> void:
|
||||
var c : Node = get_parent()
|
||||
if c is Control:
|
||||
size = c.size
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://rh6vq7m1qfkr
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
@tool
|
||||
extends Label
|
||||
|
||||
func _ready() -> void:
|
||||
add_to_group(&"SP_TAB_BUTTON")
|
||||
|
||||
func _gui_input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseButton:
|
||||
if event.is_pressed() and event.button_index == MOUSE_BUTTON_LEFT:
|
||||
var btn : Node = get_parent().get_child(0)
|
||||
if btn is Button:
|
||||
btn.pressed.emit()
|
||||
|
||||
func _get_drag_data(__ : Vector2) -> Variant:
|
||||
return owner.button_main._get_drag_data(__)
|
||||
|
||||
func _drop_data(_at_position: Vector2, data: Variant) -> void:
|
||||
owner.button_main._drop_data(_at_position, data)
|
||||
|
||||
func _can_drop_data(at_position: Vector2, data: Variant) -> bool:
|
||||
return owner.button_main._can_drop_data(at_position, data)
|
||||
|
||||
func get_selected_color() -> Color:
|
||||
return owner.get_selected_color()
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://bkj4lec06udg5
|
||||
|
|
@ -0,0 +1,384 @@
|
|||
@tool
|
||||
extends PanelContainer
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
const TAB = preload("./../../../../core/ui/multi_split_container/taby/tab.tscn")
|
||||
const TIME_WAIT : float = 0.35
|
||||
|
||||
const MAX_COLLAPSED : int = 6
|
||||
|
||||
@export var container : Control = null
|
||||
var _dlt : float = 0.0
|
||||
var _try : int = 0
|
||||
|
||||
var buttons : Array[Control] = []
|
||||
var hbox : Array[HBoxContainer] = []
|
||||
var pins : PackedStringArray = []
|
||||
|
||||
var _enable_update : bool = true
|
||||
|
||||
var _reference : TabBar = null
|
||||
|
||||
var _select_color : Color = Color.CADET_BLUE:
|
||||
set = set_select_color
|
||||
|
||||
var _updating : bool = false
|
||||
|
||||
var style : StyleBox = null
|
||||
|
||||
var _behaviour_collapsed : int = MAX_COLLAPSED:
|
||||
set(e):
|
||||
_behaviour_collapsed = mini(maxi(0, e), MAX_COLLAPSED)
|
||||
|
||||
func _enter_tree() -> void:
|
||||
modulate.a = 0.0
|
||||
z_index = 10
|
||||
get_tree().create_tween().tween_property(self, "modulate:a", 1.0, 0.3)
|
||||
|
||||
_setup()
|
||||
|
||||
func _exit_tree() -> void:
|
||||
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
||||
if settings.settings_changed.is_connected(_on_change):
|
||||
settings.settings_changed.disconnect(_on_change)
|
||||
|
||||
func _on_change() -> void:
|
||||
var dt : Array = [
|
||||
"plugin/script_splitter/behaviour/refresh_warnings_on_saveplugin/script_splitter/editor/list/selected_color"
|
||||
]
|
||||
|
||||
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
||||
var changes : PackedStringArray = settings.get_changed_settings()
|
||||
|
||||
for c in changes:
|
||||
if c in dt:
|
||||
_setup()
|
||||
break
|
||||
|
||||
func _setup() -> void:
|
||||
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
||||
if !settings.settings_changed.is_connected(_on_change):
|
||||
settings.settings_changed.connect(_on_change)
|
||||
|
||||
for x : Array in [
|
||||
["_select_color", "plugin/script_splitter/behaviour/refresh_warnings_on_saveplugin/script_splitter/editor/list/selected_color"]
|
||||
]:
|
||||
if settings.has_setting(x[1]):
|
||||
set(x[0], settings.get_setting(x[1]))
|
||||
else:
|
||||
settings.set_setting(x[1], get(x[0]))
|
||||
|
||||
func _notification(what: int) -> void:
|
||||
if what == NOTIFICATION_PREDELETE:
|
||||
for x : Variant in hbox:
|
||||
if is_instance_valid(x):
|
||||
if x.get_parent() == null:
|
||||
x.queue_free()
|
||||
for x : Variant in buttons:
|
||||
if is_instance_valid(x):
|
||||
if x.get_parent() == null:
|
||||
x.queue_free()
|
||||
|
||||
func _on_pressed(btn : Button) -> void:
|
||||
if is_instance_valid(_reference):
|
||||
for x : int in _reference.tab_count:
|
||||
if _reference.get_tab_tooltip(x) == btn.tooltip_text:
|
||||
_reference.current_tab = x
|
||||
#_reference.tab_clicked.emit(x)
|
||||
_reference.tab_clicked.emit(x)
|
||||
|
||||
func _on_gui_pressed(input : InputEvent, btn : Button) -> void:
|
||||
if input.is_pressed():
|
||||
if is_instance_valid(_reference):
|
||||
for x : int in _reference.tab_count:
|
||||
if _reference.get_tab_tooltip(x) == btn.tooltip_text:
|
||||
if input is InputEventMouseButton:
|
||||
if input.button_index == MOUSE_BUTTON_RIGHT:
|
||||
_reference.tab_selected.emit(x)
|
||||
_reference.tab_rmb_clicked.emit(x)
|
||||
return
|
||||
elif input.button_index == MOUSE_BUTTON_MIDDLE:
|
||||
_reference.tab_close_pressed.emit(x)
|
||||
return
|
||||
|
||||
func remove_tab(tooltip : String) -> void:
|
||||
for x : Control in buttons:
|
||||
if x.get_src() == tooltip:
|
||||
x.queue_free()
|
||||
return
|
||||
|
||||
func rename_tab(_tab_name : String, tooltip : String, new_tab_name : String, new_tooltip : String) -> void:
|
||||
for x : Button in buttons:
|
||||
if x.get_src() == tooltip:
|
||||
x.set_src(new_tooltip)
|
||||
x.set_text(new_tab_name)
|
||||
return
|
||||
|
||||
func set_select_color(color : Color) -> void:
|
||||
_select_color = color.lightened(0.4)
|
||||
|
||||
func set_ref(tab : TabBar) -> void:
|
||||
_reference = tab
|
||||
update()
|
||||
|
||||
func set_enable(e : bool) -> void:
|
||||
_enable_update = e
|
||||
visible = e
|
||||
if e:
|
||||
_updating = false
|
||||
update()
|
||||
return
|
||||
for x : Variant in hbox:
|
||||
if is_instance_valid(x):
|
||||
x.queue_free()
|
||||
for x : Variant in buttons:
|
||||
if is_instance_valid(x):
|
||||
x.queue_free()
|
||||
buttons.clear()
|
||||
hbox.clear()
|
||||
|
||||
func _on_pin(btn : Object) -> void:
|
||||
if btn:
|
||||
if btn.has_method(&"get_src"):
|
||||
var value : Variant = btn.call(&"get_src")
|
||||
if value is String:
|
||||
if value.is_empty():
|
||||
return
|
||||
var x : int = pins.find(value)
|
||||
if x > -1:
|
||||
pins.remove_at(x)
|
||||
else:
|
||||
pins.append(value)
|
||||
|
||||
if pins.size() > 30:
|
||||
var exist : Dictionary[String, bool] = {}
|
||||
for b : Button in buttons:
|
||||
exist[b.tooltip_text] = true
|
||||
|
||||
for y : int in range(pins.size() - 1, -1, -1):
|
||||
if !exist.has(pins[y]):
|
||||
pins.remove_at(y)
|
||||
_on_rect_change()
|
||||
update()
|
||||
|
||||
func update(fllbck : bool = true) -> void:
|
||||
if !_enable_update:
|
||||
return
|
||||
if _updating:
|
||||
return
|
||||
_updating = true
|
||||
var tab : TabBar = _reference
|
||||
if !is_instance_valid(tab):
|
||||
set_deferred(&"_updating", false)
|
||||
return
|
||||
|
||||
for x : int in range(buttons.size() -1, -1, -1):
|
||||
var _container : Variant = buttons[x]
|
||||
if is_instance_valid(_container):
|
||||
continue
|
||||
buttons.remove_at(x)
|
||||
|
||||
while buttons.size() < tab.tab_count:
|
||||
var btn : Control = TAB.instantiate()
|
||||
var control : Control = btn.get_button()
|
||||
var cls : Button = btn.get_button_close()
|
||||
|
||||
if style:
|
||||
btn.set(&"theme_override_styles/panel", style)
|
||||
if !control.gui_input.is_connected(_on_gui_pressed):
|
||||
control.gui_input.connect(_on_gui_pressed.bind(control))
|
||||
if !control.pressed.is_connected(_on_pressed):
|
||||
control.pressed.connect(_on_pressed.bind(control))
|
||||
if !cls.pressed.is_connected(_on_close):
|
||||
cls.pressed.connect(_on_close.bind(control))
|
||||
if !btn.on_pin.is_connected(_on_pin):
|
||||
btn.on_pin.connect(_on_pin)
|
||||
buttons.append(btn)
|
||||
|
||||
while buttons.size() > tab.tab_count:
|
||||
var btn : Variant = buttons.pop_back()
|
||||
if is_instance_valid(btn):
|
||||
if btn is Node:
|
||||
btn.queue_free()
|
||||
else:
|
||||
btn.free()
|
||||
|
||||
if pins.size() > 0:
|
||||
var indx : int = 0
|
||||
var control : Node = tab.get_parent_control()
|
||||
if control:
|
||||
for x : int in range(control.get_child_count()):
|
||||
if x > -1 and tab.tab_count > x:
|
||||
if pins.has(tab.get_tab_tooltip(x)):
|
||||
if x != indx:
|
||||
if x < control.get_child_count():
|
||||
control.move_child(control.get_child(x), indx)
|
||||
indx += 1
|
||||
|
||||
var alpha_pin : Color = Color.WHITE
|
||||
var errors : bool = false
|
||||
alpha_pin.a = 0.25
|
||||
|
||||
for x : int in range(tab.tab_count):
|
||||
var _container : Control = buttons[x]
|
||||
var btn : Button = _container.get_button()
|
||||
var pin : Button = _container.get_button_pin()
|
||||
_container.visible = true
|
||||
btn.tooltip_text = tab.get_tab_tooltip(x)
|
||||
_container.set_text(tab.get_tab_title(x))
|
||||
btn.icon = tab.get_tab_icon(x)
|
||||
|
||||
#if fllbck and (btn.tooltip_text.is_empty() or btn.text.begins_with("@VSplitContainer") or btn.text.begins_with("@VBoxContainer")):
|
||||
#if btn.text.begins_with("@VSplitContainer") or btn.text.begins_with("@VBoxContainer"):
|
||||
#btn.text = "File"
|
||||
#errors = true
|
||||
|
||||
if pin:
|
||||
if pins.has(btn.tooltip_text):
|
||||
_container.is_pinned = true
|
||||
pin.set(&"theme_override_colors/icon_normal_color",_select_color)
|
||||
elif _container.is_pinned:
|
||||
_container.is_pinned = false
|
||||
pin.set(&"theme_override_colors/icon_normal_color", alpha_pin)
|
||||
|
||||
btn.set(&"theme_override_colors/icon_normal_color", Color.GRAY)
|
||||
_container.color_rect.visible = false
|
||||
_container.modulate.a = 0.85
|
||||
|
||||
if tab.current_tab > -1 and tab.current_tab < buttons.size():
|
||||
var _container : Control = buttons[tab.current_tab]
|
||||
var btn : Button = _container.get_button()
|
||||
|
||||
btn.set(&"theme_override_colors/icon_normal_color", _select_color)
|
||||
_container.modulate.a = 1.0
|
||||
|
||||
var c : ColorRect = _container.color_rect
|
||||
c.visible = true
|
||||
c.color = _select_color
|
||||
|
||||
|
||||
if _behaviour_collapsed < MAX_COLLAPSED:
|
||||
var iminor : int = tab.current_tab - _behaviour_collapsed
|
||||
var isup : int = tab.current_tab + _behaviour_collapsed
|
||||
for x : int in range(tab.tab_count):
|
||||
if x < iminor or x > isup:
|
||||
var _btn : Control = buttons[x]
|
||||
_btn.visible = false
|
||||
|
||||
_on_rect_change()
|
||||
|
||||
if fllbck and errors:
|
||||
Engine.get_main_loop().create_timer(3.0).timeout.connect(update.bind(false))
|
||||
|
||||
set_deferred(&"_updating", false)
|
||||
|
||||
func _on_close(btn : Button) -> void:
|
||||
if is_instance_valid(_reference):
|
||||
for x : int in range(0, _reference.tab_count, 1):
|
||||
if _reference.get_tab_tooltip(x) == btn.tooltip_text:
|
||||
_reference.tab_close_pressed.emit(x)
|
||||
break
|
||||
|
||||
func _on_gui(event : InputEvent) -> void:
|
||||
if event is InputEventMouseButton:
|
||||
if event.pressed:
|
||||
if event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
|
||||
if _behaviour_collapsed < MAX_COLLAPSED:
|
||||
_behaviour_collapsed += 1
|
||||
update()
|
||||
get_viewport().set_input_as_handled()
|
||||
elif event.button_index == MOUSE_BUTTON_WHEEL_UP:
|
||||
if _behaviour_collapsed > 0:
|
||||
_behaviour_collapsed -= 1
|
||||
update()
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
func _ready() -> void:
|
||||
size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
size_flags_vertical = Control.SIZE_FILL
|
||||
|
||||
item_rect_changed.connect(_on_rect_change)
|
||||
|
||||
if !gui_input.is_connected(_on_gui):
|
||||
gui_input.connect(_on_gui)
|
||||
|
||||
var bd : Control = EditorInterface.get_base_control()
|
||||
if bd:
|
||||
style = bd.get_theme_stylebox("panel", "")
|
||||
if is_instance_valid(style):
|
||||
style = style.duplicate()
|
||||
if style is StyleBoxFlat:
|
||||
style.border_width_top = 0.0
|
||||
style.border_width_left = 0.0
|
||||
style.border_width_right = 0.0
|
||||
style.border_width_bottom = 0.0
|
||||
style.expand_margin_left = 2.0
|
||||
style.content_margin_bottom = 0.0
|
||||
style.content_margin_top = 0.0
|
||||
style.content_margin_left = 0.0
|
||||
style.content_margin_right = 0.0
|
||||
|
||||
|
||||
func _on_rect_change() -> void:
|
||||
if !_enable_update:
|
||||
return
|
||||
_dlt = TIME_WAIT - 0.005
|
||||
_try = 0
|
||||
set_physics_process(true)
|
||||
|
||||
func get_reference() -> TabBar:
|
||||
return _reference
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
_dlt += delta
|
||||
if _dlt < TIME_WAIT:
|
||||
return
|
||||
_dlt = 0.0
|
||||
|
||||
var rsize : Vector2 = get_parent().get_parent().size
|
||||
if rsize.x > 10.0:
|
||||
for x : Node in container.get_children():
|
||||
container.remove_child(x)
|
||||
|
||||
for x : Control in buttons:
|
||||
var p : Node = x.get_parent()
|
||||
if p:
|
||||
p.remove_child(x)
|
||||
|
||||
var current : HBoxContainer = null
|
||||
|
||||
var index : int = 0
|
||||
|
||||
var min_size : float = 0.0
|
||||
var btn_size : float = 0.0
|
||||
for x : Control in buttons:
|
||||
var bsize : float = x.get_rect().size.x
|
||||
if current == null or (bsize > 0.0 and rsize.x < current.get_minimum_size().x + bsize + 12):
|
||||
if hbox.size() > index:
|
||||
current = hbox[index]
|
||||
else:
|
||||
current = HBoxContainer.new()
|
||||
current.set(&"theme_override_constants/separation", 4)
|
||||
hbox.append(current)
|
||||
index += 1
|
||||
container.add_child(current)
|
||||
current.add_child(x)
|
||||
btn_size = maxf(btn_size, x.size.y)
|
||||
if current:
|
||||
var indx : int = current.get_index() + 1
|
||||
min_size = indx * (btn_size) #+ 12.5
|
||||
|
||||
if custom_minimum_size.y != min_size:
|
||||
_try = 0
|
||||
set_physics_process(true)
|
||||
custom_minimum_size.y = min_size
|
||||
return
|
||||
|
||||
_try += 1
|
||||
if _try % 5 == 0:
|
||||
set_physics_process(false)
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://cnubduf2plac4
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
[gd_scene load_steps=2 format=3 uid="uid://c86tj28gq8d6t"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cnubduf2plac4" path="res://addons/script_splitter/core/ui/multi_split_container/taby/container.gd" id="1_fdccq"]
|
||||
|
||||
[node name="Container" type="PanelContainer" node_paths=PackedStringArray("container")]
|
||||
z_index = 10
|
||||
anchors_preset = 10
|
||||
anchor_right = 1.0
|
||||
grow_horizontal = 2
|
||||
size_flags_horizontal = 3
|
||||
script = ExtResource("1_fdccq")
|
||||
container = NodePath("Container")
|
||||
|
||||
[node name="Container" type="VBoxContainer" parent="."]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 1
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
@tool
|
||||
extends Control
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
signal on_pin(button : Object)
|
||||
|
||||
@export var color_rect : ColorRect
|
||||
@export var button_main : Button
|
||||
@export var button_close : Button
|
||||
@export var button_pin : Button
|
||||
@export var changes : Label
|
||||
|
||||
var is_pinned : bool = false
|
||||
|
||||
func _ready() -> void:
|
||||
add_to_group(&"SP_TAB_BUTTON")
|
||||
mouse_entered.connect(_on_enter)
|
||||
mouse_exited.connect(_on_exit)
|
||||
|
||||
var c : Color = Color.WHITE
|
||||
c.a = 0.25
|
||||
button_close.set(&"theme_override_colors/icon_normal_color", c)
|
||||
if !is_pinned:
|
||||
button_pin.set(&"theme_override_colors/icon_normal_color", c)
|
||||
_on_exit()
|
||||
|
||||
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
||||
|
||||
if settings:
|
||||
if !settings.settings_changed.is_connected(_on_change):
|
||||
settings.settings_changed.connect(_on_change)
|
||||
|
||||
if settings.has_setting("plugin/script_splitter/editor/tabs/close_button_visible"):
|
||||
button_close.visible = settings.get_setting("plugin/script_splitter/editor/tabs/close_button_visible")
|
||||
else:
|
||||
settings.set_setting("plugin/script_splitter/editor/tabs/close_button_visible", true)
|
||||
|
||||
if settings.has_setting("plugin/script_splitter/editor/tabs/pin_button_visible"):
|
||||
button_pin.visible = settings.get_setting("plugin/script_splitter/editor/tabs/pin_button_visible")
|
||||
else:
|
||||
settings.set_setting("plugin/script_splitter/editor/tabs/pin_button_visible", true)
|
||||
|
||||
func _on_change() -> void:
|
||||
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
||||
if settings:
|
||||
var st : PackedStringArray = settings.get_changed_settings()
|
||||
if "plugin/script_splitter/editor/tabs/close_button_visible" in st:
|
||||
button_close.visible = settings.get_setting("plugin/script_splitter/editor/tabs/close_button_visible")
|
||||
if "plugin/script_splitter/editor/tabs/pin_button_visible" in st:
|
||||
button_pin.visible = settings.get_setting("plugin/script_splitter/editor/tabs/pin_button_visible")
|
||||
|
||||
func _on_enter() -> void:
|
||||
add_to_group(&"__SPLITER_BUTTON_TAB__")
|
||||
|
||||
func _on_exit() -> void:
|
||||
remove_from_group(&"__SPLITER_BUTTON_TAB__")
|
||||
|
||||
|
||||
func get_reference() -> TabBar:
|
||||
return get_parent().get_parent().get_parent().get_reference()
|
||||
|
||||
func get_button_pin() -> Button:
|
||||
return button_pin
|
||||
|
||||
func _on_pin_pressed() -> void:
|
||||
on_pin.emit(self)
|
||||
|
||||
func set_close_visible(e : bool) -> void:
|
||||
button_close.visible = e
|
||||
|
||||
func set_src(src : String) -> void:
|
||||
button_main.tooltip_text = src
|
||||
|
||||
func get_src() -> String:
|
||||
return button_main.tooltip_text
|
||||
|
||||
func set_text(txt : String) -> void:
|
||||
if txt.ends_with("(*)"):
|
||||
button_main.text = txt.trim_suffix("(*)")
|
||||
changes.modulate.a = 1.0
|
||||
return
|
||||
button_main.text = txt
|
||||
changes.modulate.a = 0.0
|
||||
|
||||
func get_button() -> Button:
|
||||
return button_main
|
||||
|
||||
func get_button_close() -> Button:
|
||||
return button_close
|
||||
|
||||
func _get_drag_data(__ : Vector2) -> Variant:
|
||||
return button_main._get_drag_data(__)
|
||||
|
||||
func _drop_data(_at_position: Vector2, data: Variant) -> void:
|
||||
button_main._drop_data(_at_position, data)
|
||||
|
||||
func _can_drop_data(at_position: Vector2, data: Variant) -> bool:
|
||||
return button_main._can_drop_data(at_position, data)
|
||||
|
||||
func get_selected_color() -> Color:
|
||||
return color_rect.color
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://c3hg84uuly33f
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
@tool
|
||||
extends VSeparator
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
var _delta : float = 0.0
|
||||
var _ref : Control = null
|
||||
|
||||
func _ready() -> void:
|
||||
visible = false
|
||||
z_index = RenderingServer.CANVAS_ITEM_Z_MAX - 1
|
||||
z_as_relative = false
|
||||
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
set_process(_ref != null)
|
||||
|
||||
func update(ref : Control) -> void:
|
||||
_ref = ref
|
||||
_delta = 0.0
|
||||
visible = _ref != null
|
||||
set_process(visible)
|
||||
|
||||
func delete() -> void:
|
||||
_delta = 10.0
|
||||
_ref = null
|
||||
queue_free()
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
_delta += delta
|
||||
if _delta < 0.5:
|
||||
return
|
||||
if is_instance_valid(_ref) and is_inside_tree():
|
||||
if _ref.get_global_rect().has_point(get_global_mouse_position()):
|
||||
return
|
||||
|
||||
if !is_queued_for_deletion():
|
||||
queue_free()
|
||||
|
||||
func _get_drag_data(__ : Vector2) -> Variant:
|
||||
if !_ref:
|
||||
return null
|
||||
return _ref.owner.button_main._get_drag_data(__)
|
||||
|
||||
func _drop_data(_at_position: Vector2, data: Variant) -> void:
|
||||
if _ref:
|
||||
_ref.owner.button_main._drop_data(_at_position, data)
|
||||
|
||||
func _can_drop_data(at_position: Vector2, data: Variant) -> bool:
|
||||
if !_ref:
|
||||
return false
|
||||
return _ref.owner.button_main._can_drop_data(at_position, data)
|
||||
|
||||
func get_selected_color() -> Color:
|
||||
if !_ref:
|
||||
return Color.GRAY
|
||||
return _ref.owner.get_selected_color()
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://d05p8nj7f18s0
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
[gd_scene load_steps=3 format=3 uid="uid://dwe7jhlq2p40h"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://d05p8nj7f18s0" path="res://addons/script_splitter/core/ui/multi_split_container/taby/separator.gd" id="1_byjdv"]
|
||||
|
||||
[sub_resource type="StyleBoxLine" id="StyleBoxLine_ksadu"]
|
||||
color = Color(0.62352943, 0.77176476, 0.7764706, 1)
|
||||
grow_begin = 4.0
|
||||
grow_end = 4.0
|
||||
thickness = 24
|
||||
|
||||
[node name="HSeparator" type="VSeparator"]
|
||||
visible = false
|
||||
z_index = 4095
|
||||
z_as_relative = false
|
||||
offset_right = 4.0
|
||||
offset_bottom = 4.0
|
||||
mouse_filter = 2
|
||||
theme_override_styles/separator = SubResource("StyleBoxLine_ksadu")
|
||||
script = ExtResource("1_byjdv")
|
||||
226
addons/script_splitter/core/ui/multi_split_container/taby/tab.gd
Normal file
226
addons/script_splitter/core/ui/multi_split_container/taby/tab.gd
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
@tool
|
||||
extends Button
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
const SEPARATOR = preload("./../../../../core/ui/multi_split_container/taby/separator.tscn")
|
||||
const DRAG_TIME : float = 0.15
|
||||
static var line : VSeparator = null
|
||||
|
||||
|
||||
var _delta : float = 0.0
|
||||
var _last_control : Control = null
|
||||
|
||||
var is_drag : bool = false:
|
||||
set(e):
|
||||
is_drag = e
|
||||
if is_drag:
|
||||
on_drag()
|
||||
Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)
|
||||
else:
|
||||
out_drag()
|
||||
if Input.mouse_mode != Input.MOUSE_MODE_VISIBLE:
|
||||
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
|
||||
|
||||
var _fms : float = 0.0
|
||||
|
||||
func _ready() -> void:
|
||||
auto_translate_mode = Node.AUTO_TRANSLATE_MODE_DISABLED
|
||||
set_process(false)
|
||||
add_to_group(&"SP_TAB_BUTTON")
|
||||
setup()
|
||||
|
||||
func on_drag() -> void:
|
||||
var tab : TabBar = owner.get_reference()
|
||||
if tab:
|
||||
for x : Node in tab.get_tree().get_nodes_in_group(&"ScriptSplitter"):
|
||||
if x.has_method(&"dragged"):
|
||||
x.call(&"dragged", tab, true)
|
||||
|
||||
func out_drag() -> void:
|
||||
var tab : TabBar = owner.get_reference()
|
||||
if tab:
|
||||
for x : Node in tab.get_tree().get_nodes_in_group(&"ScriptSplitter"):
|
||||
if x.has_method(&"dragged"):
|
||||
x.call(&"dragged", tab, false)
|
||||
|
||||
func _get_drag_data(__ : Vector2) -> Variant:
|
||||
if !button_pressed:
|
||||
pressed.emit()
|
||||
|
||||
var c : Control = duplicate(0)
|
||||
c.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
c.z_index = RenderingServer.CANVAS_ITEM_Z_MAX - 2
|
||||
set_drag_preview(c)
|
||||
|
||||
return self
|
||||
|
||||
func _drop_data(_at_position: Vector2, data: Variant) -> void:
|
||||
if is_instance_valid(line):
|
||||
line.delete()
|
||||
if data is Node:
|
||||
if data == self:
|
||||
return
|
||||
elif data.is_in_group(&"SP_TAB_BUTTON"):
|
||||
if is_instance_valid(line):
|
||||
line.update(self)
|
||||
var node : Node = owner
|
||||
if node:
|
||||
var idx : int = node.get_index()
|
||||
if idx >= 0:
|
||||
var _node : Node = data.owner
|
||||
var lft : bool = false
|
||||
if owner.get_global_mouse_position().x <= owner.get_global_rect().get_center().x:
|
||||
lft = true
|
||||
var root : Node = _node
|
||||
for __ : int in range(3):
|
||||
root = root.get_parent()
|
||||
if !is_instance_valid(root):
|
||||
out_drag()
|
||||
return
|
||||
|
||||
for x : Node in get_tree().get_nodes_in_group(&"__SCRIPT_SPLITTER__"):
|
||||
if x.has_method(&"get_builder"):
|
||||
var o : Object = x.call(&"get_builder")
|
||||
if o.has_method(&"swap_by_src"):
|
||||
o.call(&"swap_by_src", data.tooltip_text, tooltip_text, lft)
|
||||
break
|
||||
if root:
|
||||
if root.has_method(&"update"):
|
||||
root.call(&"update")
|
||||
|
||||
out_drag()
|
||||
|
||||
func _can_drop_data(_at_position: Vector2, data: Variant) -> bool:
|
||||
if data is Node:
|
||||
if data == self:
|
||||
return false
|
||||
elif data.is_in_group(&"SP_TAB_BUTTON"):
|
||||
_last_control = data
|
||||
_delta = 0.0
|
||||
if !is_instance_valid(line):
|
||||
line = SEPARATOR.instantiate()
|
||||
var root : Node = Engine.get_main_loop().root
|
||||
if root:
|
||||
root.add_child(line)
|
||||
if line:
|
||||
var rct : Rect2 = owner.get_global_rect()
|
||||
line.update(self)
|
||||
if owner.get_global_mouse_position().x <= owner.get_global_rect().get_center().x:
|
||||
line.global_position = rct.position
|
||||
else:
|
||||
line.global_position = Vector2(rct.end.x, rct.position.y) - Vector2(line.size.x * 1.5, 0.0)
|
||||
|
||||
var style : StyleBoxLine = line.get(&"theme_override_styles/separator")
|
||||
style.set(&"thickness",size.y)
|
||||
style.set(&"color",data.get_selected_color())
|
||||
return true
|
||||
return false
|
||||
|
||||
func reset() -> void:
|
||||
if is_drag:
|
||||
set_process(false)
|
||||
is_drag = false
|
||||
if is_inside_tree():
|
||||
var parent : Node = self
|
||||
|
||||
for __ : int in range(10):
|
||||
parent = parent.get_parent()
|
||||
if parent.has_signal(&"out_dragging"):
|
||||
break
|
||||
if !is_instance_valid(parent):
|
||||
return
|
||||
if parent.has_signal(&"out_dragging"):
|
||||
for x : Node in parent.get_children():
|
||||
if x is TabContainer:
|
||||
parent.emit_signal(&"out_dragging",x.get_tab_bar())
|
||||
return
|
||||
|
||||
func _enter_tree() -> void:
|
||||
if !is_in_group(&"__SPLITER_TAB__"):
|
||||
add_to_group(&"__SPLITER_TAB__")
|
||||
if is_node_ready():
|
||||
return
|
||||
owner.modulate.a = 0.0
|
||||
get_tree().create_tween().tween_property(owner, "modulate:a", 1.0, 0.5)
|
||||
|
||||
func _exit_tree() -> void:
|
||||
if is_in_group(&"__SPLITER_TAB__"):
|
||||
remove_from_group(&"__SPLITER_TAB__")
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
_fms += delta
|
||||
if _fms > DRAG_TIME:
|
||||
if is_drag:
|
||||
if !Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT):
|
||||
set_process(false)
|
||||
is_drag = false
|
||||
var parent : Node = self
|
||||
|
||||
for __ : int in range(10):
|
||||
parent = parent.get_parent()
|
||||
if parent.has_signal(&"out_dragging"):
|
||||
break
|
||||
if !is_instance_valid(parent):
|
||||
return
|
||||
if parent.has_signal(&"out_dragging"):
|
||||
for x : Node in parent.get_children():
|
||||
if x is TabContainer:
|
||||
parent.emit_signal(&"out_dragging",x.get_tab_bar())
|
||||
return
|
||||
else:
|
||||
if !Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT):
|
||||
set_process(false)
|
||||
return
|
||||
is_drag = true
|
||||
var parent : Node = self
|
||||
for __ : int in range(10):
|
||||
parent = parent.get_parent()
|
||||
if parent.has_signal(&"on_dragging"):
|
||||
break
|
||||
if !is_instance_valid(parent):
|
||||
return
|
||||
if parent.has_signal(&"on_dragging"):
|
||||
for x : Node in parent.get_children():
|
||||
if x is TabContainer:
|
||||
parent.emit_signal(&"on_dragging",x.get_tab_bar())
|
||||
return
|
||||
|
||||
func setup() -> void:
|
||||
if !gui_input.is_connected(_on_input):
|
||||
gui_input.connect(_on_input)
|
||||
if !is_in_group(&"__SPLITER_TAB__"):
|
||||
add_to_group(&"__SPLITER_TAB__")
|
||||
|
||||
func _on_input(e : InputEvent) -> void:
|
||||
if e is InputEventMouseButton:
|
||||
if e.button_index == MOUSE_BUTTON_LEFT:
|
||||
is_drag = false
|
||||
if e.pressed:
|
||||
_fms = 0.0
|
||||
set_process(true)
|
||||
else:
|
||||
set_process(false)
|
||||
if _fms >= DRAG_TIME:
|
||||
var parent : Node = self
|
||||
for __ : int in range(10):
|
||||
parent = parent.get_parent()
|
||||
if parent.has_signal(&"out_dragging"):
|
||||
break
|
||||
if !is_instance_valid(parent):
|
||||
return
|
||||
if parent.has_signal(&"out_dragging"):
|
||||
for x : Node in parent.get_children():
|
||||
if x is TabContainer:
|
||||
parent.emit_signal(&"out_dragging",x.get_tab_bar())
|
||||
return
|
||||
#elif e.button_index == MOUSE_BUTTON_RIGHT:
|
||||
#pressed.emit()
|
||||
|
||||
func get_selected_color() -> Color:
|
||||
return owner.get_selected_color()
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://cf447gbwtnwsl
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
[gd_scene load_steps=8 format=3 uid="uid://bei2ybryufpnd"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://c3hg84uuly33f" path="res://addons/script_splitter/core/ui/multi_split_container/taby/container_button.gd" id="1_c6ml5"]
|
||||
[ext_resource type="Script" uid="uid://cf447gbwtnwsl" path="res://addons/script_splitter/core/ui/multi_split_container/taby/tab.gd" id="2_gel5x"]
|
||||
[ext_resource type="Script" uid="uid://bkj4lec06udg5" path="res://addons/script_splitter/core/ui/multi_split_container/taby/changes.gd" id="3_f5jk5"]
|
||||
[ext_resource type="Texture2D" uid="uid://7rel5pr2g7d2" path="res://addons/script_splitter/assets/pin.svg" id="3_y1lda"]
|
||||
[ext_resource type="Texture2D" uid="uid://4juherhkw8hp" path="res://addons/script_splitter/assets/Close.svg" id="4_b84sh"]
|
||||
[ext_resource type="Script" uid="uid://bi84jgnpiilbi" path="res://addons/script_splitter/core/ui/multi_split_container/taby/tab_dd.gd" id="5_4jcjw"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_hvct0"]
|
||||
|
||||
[node name="PanelContainer" type="PanelContainer" node_paths=PackedStringArray("color_rect", "button_main", "button_close", "button_pin", "changes")]
|
||||
offset_right = 49.0
|
||||
offset_bottom = 33.0
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_hvct0")
|
||||
script = ExtResource("1_c6ml5")
|
||||
color_rect = NodePath("VBoxContainer/Selected")
|
||||
button_main = NodePath("VBoxContainer/ButtonContainer/PanelContainer")
|
||||
button_close = NodePath("VBoxContainer/ButtonContainer/Close")
|
||||
button_pin = NodePath("VBoxContainer/ButtonContainer/Pin")
|
||||
changes = NodePath("VBoxContainer/ButtonContainer/Changes")
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="Selected" type="ColorRect" parent="VBoxContainer"]
|
||||
custom_minimum_size = Vector2(0, 2)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 0
|
||||
mouse_filter = 1
|
||||
color = Color(0.4904182, 0.5339965, 0.61462164, 1)
|
||||
|
||||
[node name="ButtonContainer" type="HBoxContainer" parent="VBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 0
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="PanelContainer" type="Button" parent="VBoxContainer/ButtonContainer"]
|
||||
auto_translate_mode = 2
|
||||
layout_mode = 2
|
||||
focus_mode = 0
|
||||
theme_override_colors/font_focus_color = Color(1, 1, 1, 1)
|
||||
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
|
||||
theme_override_colors/icon_normal_color = Color(1, 1, 1, 1)
|
||||
button_mask = 3
|
||||
shortcut_feedback = false
|
||||
shortcut_in_tooltip = false
|
||||
flat = true
|
||||
script = ExtResource("2_gel5x")
|
||||
|
||||
[node name="Changes" type="Label" parent="VBoxContainer/ButtonContainer"]
|
||||
layout_mode = 2
|
||||
mouse_filter = 1
|
||||
text = "*"
|
||||
script = ExtResource("3_f5jk5")
|
||||
|
||||
[node name="Pin" type="Button" parent="VBoxContainer/ButtonContainer"]
|
||||
layout_mode = 2
|
||||
focus_mode = 0
|
||||
theme_override_colors/icon_normal_color = Color(1, 1, 1, 0.25)
|
||||
shortcut_feedback = false
|
||||
shortcut_in_tooltip = false
|
||||
icon = ExtResource("3_y1lda")
|
||||
flat = true
|
||||
icon_alignment = 1
|
||||
script = ExtResource("5_4jcjw")
|
||||
|
||||
[node name="Close" type="Button" parent="VBoxContainer/ButtonContainer"]
|
||||
layout_mode = 2
|
||||
focus_mode = 0
|
||||
theme_override_colors/font_color = Color(1, 1, 1, 0.25)
|
||||
theme_override_colors/icon_normal_color = Color(1, 1, 1, 0.25)
|
||||
shortcut_feedback = false
|
||||
shortcut_in_tooltip = false
|
||||
icon = ExtResource("4_b84sh")
|
||||
flat = true
|
||||
script = ExtResource("5_4jcjw")
|
||||
|
||||
[connection signal="pressed" from="VBoxContainer/ButtonContainer/Pin" to="." method="_on_pin_pressed"]
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
@tool
|
||||
extends Control
|
||||
|
||||
func _ready() -> void:
|
||||
add_to_group(&"SP_TAB_BUTTON")
|
||||
|
||||
func _get_drag_data(__ : Vector2) -> Variant:
|
||||
return owner.button_main._get_drag_data(__)
|
||||
|
||||
func _drop_data(_at_position: Vector2, data: Variant) -> void:
|
||||
owner.button_main._drop_data(_at_position, data)
|
||||
|
||||
func _can_drop_data(at_position: Vector2, data: Variant) -> bool:
|
||||
return owner.button_main._can_drop_data(at_position, data)
|
||||
|
||||
func get_selected_color() -> Color:
|
||||
return owner.get_selected_color()
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://bi84jgnpiilbi
|
||||
41
addons/script_splitter/core/ui/splitter/editor/ssp_editor.gd
Normal file
41
addons/script_splitter/core/ui/splitter/editor/ssp_editor.gd
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
@tool
|
||||
extends CodeEdit
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4f
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
|
||||
const UPDATE_TIME : float = 0.25
|
||||
|
||||
var _dlt : float = 0.0
|
||||
var _text : String = ""
|
||||
var _dlt_update : float = UPDATE_TIME
|
||||
|
||||
func set_text_reference(txt : String) -> void:
|
||||
if _text == txt:
|
||||
return
|
||||
_text = txt
|
||||
_dlt = 0.0
|
||||
_dlt_update = UPDATE_TIME + (txt.length() * 0.00001)
|
||||
|
||||
set_process(true)
|
||||
|
||||
func _init() -> void:
|
||||
if is_node_ready():
|
||||
_ready()
|
||||
|
||||
func _ready() -> void:
|
||||
set_process(false)
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
_dlt += delta
|
||||
if _dlt > _dlt_update:
|
||||
set_process(false)
|
||||
var sv : float = scroll_vertical
|
||||
var sh : int = scroll_horizontal
|
||||
text = _text
|
||||
scroll_vertical = sv
|
||||
scroll_horizontal = sh
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://bec3qea1dh8xe
|
||||
110
addons/script_splitter/core/ui/splitter/editor_container.gd
Normal file
110
addons/script_splitter/core/ui/splitter/editor_container.gd
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
@tool
|
||||
extends TabContainer
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
const Dottab = preload("./../../../core/ui/splitter/taby/dottab.gd")
|
||||
const CLOSE = preload("./../../../assets/Close.svg")
|
||||
|
||||
const GLOBALS : PackedStringArray = ["_GlobalScope", "_GDScript"]
|
||||
|
||||
#
|
||||
signal focus(o : TabContainer, index : int)
|
||||
signal remove(o : TabContainer, index : int)
|
||||
|
||||
var _new_tab_settings : bool = false
|
||||
var _tab_queue : int = -1
|
||||
var _last_selected : int = -1
|
||||
|
||||
func _enter_tree() -> void:
|
||||
add_to_group(&"__SC_SPLITTER__")
|
||||
|
||||
func _exit_tree() -> void:
|
||||
if is_in_group(&"__SC_SPLITTER__"):
|
||||
remove_from_group(&"__SC_SPLITTER__")
|
||||
|
||||
func _ready() -> void:
|
||||
size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
|
||||
|
||||
auto_translate_mode = Node.AUTO_TRANSLATE_MODE_DISABLED
|
||||
|
||||
var tb : TabBar = get_tab_bar()
|
||||
if tb:
|
||||
tb.auto_translate_mode = auto_translate_mode
|
||||
|
||||
|
||||
drag_to_rearrange_enabled = true
|
||||
|
||||
#CONNECT
|
||||
var tab : TabBar = get_tab_bar()
|
||||
tab.set_script(Dottab)
|
||||
tab.tab_selected.connect(_on_selected)
|
||||
tab.active_tab_rearranged.connect(_on_rearranged)
|
||||
|
||||
tab.tab_close_display_policy = TabBar.CLOSE_BUTTON_SHOW_ACTIVE_ONLY
|
||||
tab.tab_close_pressed.connect(_on_remove)
|
||||
tab.select_with_rmb = true
|
||||
tab.on_start_drag.connect(on_drag)
|
||||
tab.on_stop_drag.connect(out_drag)
|
||||
|
||||
func _on_rearranged(t : int) -> void:
|
||||
if _last_selected == t or t < 0:
|
||||
return
|
||||
|
||||
for x : int in [_last_selected, t]:
|
||||
if x < 0 or x >= get_tab_count():
|
||||
return
|
||||
|
||||
var sc : SceneTree = Engine.get_main_loop()
|
||||
if sc:
|
||||
for x : Node in sc.get_nodes_in_group(&"__SCRIPT_SPLITTER__"):
|
||||
x.call(&"move_item_container", self, _last_selected, t)
|
||||
|
||||
func _set_tab() -> void:
|
||||
if current_tab != _tab_queue and _tab_queue > -1 and _tab_queue < get_tab_count():
|
||||
current_tab = _tab_queue
|
||||
_new_tab_settings = false
|
||||
|
||||
func set_tab(index : int) -> void:
|
||||
if index > -1 and index < get_tab_count():
|
||||
_tab_queue = index
|
||||
|
||||
if _new_tab_settings:
|
||||
return
|
||||
|
||||
_new_tab_settings = true
|
||||
_set_tab.call_deferred()
|
||||
|
||||
func on_drag(tab : TabBar) -> void:
|
||||
for x : Node in tab.get_tree().get_nodes_in_group(&"ScriptSplitter"):
|
||||
if x.has_method(&"dragged"):
|
||||
x.call(&"dragged", tab, true)
|
||||
|
||||
func out_drag(tab : TabBar) -> void:
|
||||
for x : Node in tab.get_tree().get_nodes_in_group(&"ScriptSplitter"):
|
||||
if x.has_method(&"dragged"):
|
||||
x.call(&"dragged", tab, false)
|
||||
|
||||
func _on_remove(index : int) -> void:
|
||||
remove.emit(self, index)
|
||||
|
||||
func _on_selected(value : int) -> void:
|
||||
_last_selected = value
|
||||
focus.emit(self, value)
|
||||
|
||||
func get_root() -> Node:
|
||||
return self
|
||||
|
||||
func set_item_tooltip(idx : int, txt : String) -> void:
|
||||
if idx > -1 and get_tab_count() > idx:
|
||||
set_tab_tooltip(idx, txt)
|
||||
|
||||
func set_item_text(idx : int, txt : String) -> void:
|
||||
if idx > -1 and get_tab_count() > idx:
|
||||
set_tab_title(idx, txt)
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://b45owls32pkxk
|
||||
122
addons/script_splitter/core/ui/splitter/io/io_bar.gd
Normal file
122
addons/script_splitter/core/ui/splitter/io/io_bar.gd
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
@tool
|
||||
extends ScrollContainer
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
const PIN = preload("./../../../../assets/pin.svg")
|
||||
const FILL_EXPAND = preload("./../../../../assets/fill_expand.svg")
|
||||
const SPLIT_CPLUS_TOOL = preload("./../../../../assets/split_cplus_tool.svg")
|
||||
const SPLIT_MINUS_TOOL = preload("./../../../../assets/split_minus_tool.svg")
|
||||
const SPLIT_PLUS_TOOL = preload("./../../../../assets/split_plus_tool.svg")
|
||||
const SPLIT_RMINUS_TOOL = preload("./../../../../assets/split_rminus_tool.svg")
|
||||
const SPLIT_RPLUS_TOOL = preload("./../../../../assets/split_rplus_tool.svg")
|
||||
const SPLIT_CMINUS_TOOL = preload("./../../../../assets/split_cminus_tool.svg")
|
||||
const ATOP = preload("./../../../../assets/atop.png")
|
||||
|
||||
|
||||
const PAD : float = 12.0
|
||||
|
||||
#CFG
|
||||
var enable_expand : bool = true
|
||||
var enable_horizontal_split : bool = true
|
||||
var enable_vertical_split : bool = true
|
||||
var enable_pop_script : bool = true
|
||||
var enable_sub_split : bool = true
|
||||
|
||||
var _root : VBoxContainer = null
|
||||
var _min_size : float = 0.0
|
||||
|
||||
@warning_ignore("unused_private_class_variable")
|
||||
var _pin_root : Control = null
|
||||
|
||||
func _ready() -> void:
|
||||
if _root == null:
|
||||
_root = VBoxContainer.new()
|
||||
_root.alignment = BoxContainer.ALIGNMENT_BEGIN
|
||||
_root.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
_root.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
add_child(_root)
|
||||
clear()
|
||||
_setup()
|
||||
|
||||
custom_minimum_size.x = _min_size + PAD
|
||||
horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
|
||||
vertical_scroll_mode = ScrollContainer.SCROLL_MODE_SHOW_NEVER
|
||||
|
||||
func get_root() -> Node:
|
||||
return _root
|
||||
|
||||
func _enter_tree() -> void:
|
||||
add_to_group(&"__script_splitter__IO__")
|
||||
|
||||
func _exit_tree() -> void:
|
||||
remove_from_group(&"__script_splitter__IO__")
|
||||
|
||||
# Traduction?
|
||||
func _tr(st : String) -> String:
|
||||
# ...
|
||||
return st.capitalize()
|
||||
|
||||
func clear() -> void:
|
||||
if _root:
|
||||
if is_inside_tree():
|
||||
for x : Node in _root.get_children():
|
||||
x.queue_free()
|
||||
else:
|
||||
for x : Node in _root.get_children():
|
||||
x.free()
|
||||
|
||||
|
||||
func setup() -> void:
|
||||
clear()
|
||||
_setup()
|
||||
|
||||
func _setup() -> void:
|
||||
if !_root:
|
||||
return
|
||||
if enable_expand:
|
||||
make_function(&"EXPAND", FILL_EXPAND, _tr("Expand/Unexpand current tab container"))
|
||||
if enable_horizontal_split:
|
||||
make_function(&"SPLIT_COLUMN", SPLIT_CPLUS_TOOL, _tr("Split to new column"))
|
||||
make_function(&"MERGE_COLUMN", SPLIT_CMINUS_TOOL, _tr("Merge current column"))
|
||||
if enable_vertical_split:
|
||||
make_function(&"SPLIT_ROW", SPLIT_RPLUS_TOOL, _tr("Split to new row"))
|
||||
make_function(&"MERGE_ROW", SPLIT_RMINUS_TOOL, _tr("Merge current row"))
|
||||
if enable_sub_split:
|
||||
make_function(&"SPLIT_SUB", SPLIT_PLUS_TOOL, _tr("Sub Split current editor"))
|
||||
make_function(&"MERGE_SPLIT_SUB", SPLIT_MINUS_TOOL, _tr("Merge sub split of current editor"))
|
||||
if enable_pop_script:
|
||||
make_function(&"MAKE_FLOATING", ATOP, _tr("Make separate window"))
|
||||
|
||||
func enable(id : StringName, e : bool) -> void:
|
||||
for x : Node in _root.get_children():
|
||||
if x.name == id:
|
||||
x.set(&"disabled", !e)
|
||||
|
||||
func get_button(id : String) -> Button:
|
||||
if _root.has_node(id):
|
||||
var node : Node = _root.get_node(id)
|
||||
if node is Button:
|
||||
return node
|
||||
return null
|
||||
|
||||
func make_function(id : StringName, icon : Texture2D = null, txt : String = "") -> void:
|
||||
var btn : Button = Button.new()
|
||||
btn.name = id
|
||||
|
||||
btn.pressed.connect(_call.bind(id))
|
||||
btn.icon = icon
|
||||
btn.alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
btn.tooltip_text = txt
|
||||
btn.flat = is_instance_valid(icon)
|
||||
_min_size = maxf(icon.get_size().x, _min_size)
|
||||
_root.add_child(btn)
|
||||
|
||||
func _call(id : StringName) -> void:
|
||||
for x : Node in get_tree().get_nodes_in_group(&"__SCRIPT_SPLITTER__"):
|
||||
if x.has_method(&"_io_call"):
|
||||
x.call(&"_io_call", id)
|
||||
1
addons/script_splitter/core/ui/splitter/io/io_bar.gd.uid
Normal file
1
addons/script_splitter/core/ui/splitter/io/io_bar.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://b817wwia7hrqd
|
||||
307
addons/script_splitter/core/ui/splitter/splitter_container.gd
Normal file
307
addons/script_splitter/core/ui/splitter/splitter_container.gd
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
@tool
|
||||
extends MarginContainer
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
const SplitterRoot = preload("./../../../core/ui/splitter/splitter_root.gd")
|
||||
const HandlerContainer = preload("./../../../core/base/container.gd")
|
||||
const BaseContainerItem = preload("splitter_item.gd")
|
||||
|
||||
const SplitterEditorContainer = preload("./../../../core/ui/splitter/splitter_editor_container.gd")
|
||||
|
||||
const Overlay = preload("./../../../core/ui/splitter/taby/overlay.gd")
|
||||
const CODE_NAME_TWISTER = preload("./../../../assets/github_CodeNameTwister.svg")
|
||||
|
||||
var _handler_container : HandlerContainer = null
|
||||
var _base_container : TabContainer = null
|
||||
|
||||
var _root : Container = null
|
||||
var _root_container : SplitterRoot = null
|
||||
|
||||
var _last_editor_container : SplitterEditorContainer.Editor = null
|
||||
|
||||
var _overlay : Overlay = null
|
||||
|
||||
var swap_by_button : bool = true
|
||||
|
||||
func get_root() -> SplitterRoot:
|
||||
return _root_container
|
||||
|
||||
func get_base_editors() -> Array[Node]:
|
||||
if is_instance_valid(_base_container):
|
||||
return _base_container.get_children()
|
||||
return []
|
||||
|
||||
func initialize(container : TabContainer, handler_container : HandlerContainer) -> void:
|
||||
_setup()
|
||||
|
||||
_handler_container = handler_container
|
||||
_base_container = container
|
||||
|
||||
_root = self
|
||||
|
||||
var credits : TextureRect = TextureRect.new()
|
||||
add_child(credits)
|
||||
|
||||
credits.texture = CODE_NAME_TWISTER
|
||||
credits.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
|
||||
credits.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||
credits.expand_mode = TextureRect.EXPAND_KEEP_SIZE
|
||||
credits.stretch_mode = TextureRect.STRETCH_KEEP_CENTERED
|
||||
credits.modulate.a = 0.25
|
||||
|
||||
if is_instance_valid(_base_container):
|
||||
var root : Node = _base_container.get_parent()
|
||||
root.add_child(_root)
|
||||
root.move_child(_root, mini(_base_container.get_index(), 0))
|
||||
|
||||
#_root.add_child(_root_container)
|
||||
|
||||
_root.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
_root.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
|
||||
var vspl : HBoxContainer = HBoxContainer.new()
|
||||
|
||||
_root.add_child(vspl)
|
||||
vspl.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
vspl.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
|
||||
var base : SplitterRoot = create_base_container(vspl, false)
|
||||
base.max_columns = 1
|
||||
_root_container = base
|
||||
|
||||
var io : Node = _handler_container.get_io_bar()
|
||||
if io.get_parent() == null:
|
||||
vspl.add_child(io)
|
||||
else:
|
||||
io = HandlerContainer.IoBar.new()
|
||||
io.enable_vertical_split = false
|
||||
vspl.add_child(io)
|
||||
|
||||
initialize_editor_contianer()
|
||||
|
||||
_overlay = Overlay.new()
|
||||
add_child(_overlay)
|
||||
|
||||
func _on_change() -> void:
|
||||
var dt : Array = ["plugin/script_splitter/editor/behaviour/swap_by_double_click_separator_button"]
|
||||
|
||||
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
||||
var changes : PackedStringArray = settings.get_changed_settings()
|
||||
|
||||
for c in changes:
|
||||
if c in dt:
|
||||
_setup()
|
||||
break
|
||||
|
||||
func _setup() -> void:
|
||||
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
||||
if !settings.settings_changed.is_connected(_on_change):
|
||||
settings.settings_changed.connect(_on_change)
|
||||
|
||||
for x : Array in [
|
||||
["swap_by_button", "plugin/script_splitter/editor/behaviour/swap_by_double_click_separator_button"]
|
||||
]:
|
||||
if settings.has_setting(x[1]):
|
||||
set(x[0], settings.get_setting(x[1]))
|
||||
else:
|
||||
settings.set_setting(x[1], get(x[0]))
|
||||
|
||||
func initialize_editor_contianer() -> void:
|
||||
if _root_container.get_child_count() > 0:
|
||||
for x : Node in _root_container.get_children():
|
||||
x.queue_free()
|
||||
_last_editor_container = create_new_editor_container(_root_container, true)
|
||||
|
||||
func swap(value : Variant) -> void:
|
||||
if !swap_by_button:
|
||||
return
|
||||
|
||||
if !is_instance_valid(value):
|
||||
return
|
||||
|
||||
elif !is_instance_valid(_root_container) or _root_container.get_child_count() == 0:
|
||||
return
|
||||
|
||||
elif !value is SplitterRoot.LineSep:
|
||||
return
|
||||
|
||||
var caller : SplitterRoot.LineSep = value
|
||||
|
||||
var _main : SplitterRoot = caller.get_parent()
|
||||
|
||||
if !is_instance_valid(_main):
|
||||
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
|
||||
var idx : int = x.get_index() - 1
|
||||
if _main.get_child_count() > idx:
|
||||
_main.move_child(x, idx)
|
||||
else:
|
||||
index += 1
|
||||
if _main.get_child_count() > index:
|
||||
var child : Node = _main.get_child(index - 1)
|
||||
_main.move_child(child, index)
|
||||
|
||||
func _enter_tree() -> void:
|
||||
add_to_group(&"ScriptSplitter")
|
||||
|
||||
func _exit_tree() -> void:
|
||||
remove_from_group(&"ScriptSplitter")
|
||||
|
||||
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
||||
if settings.settings_changed.is_connected(_on_change):
|
||||
settings.settings_changed.disconnect(_on_change)
|
||||
|
||||
|
||||
func dragged(tab : TabBar, is_drag : bool) -> void:
|
||||
if is_instance_valid(_overlay):
|
||||
if is_drag:
|
||||
_overlay.start(tab)
|
||||
else:
|
||||
if _overlay.stop(tab):
|
||||
var container : Node = _overlay.get_container()
|
||||
var from : Container = tab.get_parent()
|
||||
if is_instance_valid(container) and is_instance_valid(from):
|
||||
if from != container:
|
||||
_handler_container.swap_tab.emit(from, tab.current_tab, container)
|
||||
else:
|
||||
var type : StringName = _overlay.get_type_split()
|
||||
if !type.is_empty():
|
||||
_handler_container.same_swap_tab.emit(from, tab.current_tab, type)
|
||||
|
||||
func create_new_column() -> SplitterEditorContainer.Editor:
|
||||
var item : BaseContainerItem = get_base_container_item(_last_editor_container)
|
||||
var root : Container = get_base_container(_last_editor_container)
|
||||
var index : int = item.get_index()
|
||||
var custom_position : bool = index >= 0 and index < item.get_parent().get_child_count() - 1
|
||||
_last_editor_container = create_editor_container(create_base_container_item(root))
|
||||
if custom_position:
|
||||
root.move_child(get_base_container_item(_last_editor_container), index + 1)
|
||||
return _last_editor_container
|
||||
|
||||
func create_new_row() -> SplitterEditorContainer.Editor:
|
||||
var root : Container = get_base_container(_last_editor_container)
|
||||
var index : int = root.get_index()
|
||||
var custom_position : bool = index >= 0 and index < root.get_parent().get_child_count() - 1
|
||||
_last_editor_container = create_new_editor_container(_root_container)# create_editor_container(create_base_container_item(create_base_container(_root_container)))
|
||||
if custom_position:
|
||||
_root_container.move_child(get_base_container(_last_editor_container).get_parent(), index + 1)
|
||||
return _last_editor_container
|
||||
|
||||
|
||||
func set_current_editor(container : Node) -> bool:
|
||||
if container is SplitterEditorContainer.Editor:
|
||||
_last_editor_container = container
|
||||
return true
|
||||
return false
|
||||
|
||||
func get_base_container(editor : SplitterEditorContainer.Editor) -> Container:
|
||||
return editor.get_node("./../../../")
|
||||
|
||||
func get_base_container_item(editor : SplitterEditorContainer.Editor) -> BaseContainerItem:
|
||||
return editor.get_node("./../../")
|
||||
|
||||
func create_base_container(c_root : Node, _add_to_group : bool = true) -> Container:
|
||||
var b_root : Container = SplitterRoot.new()
|
||||
b_root.max_columns = 0
|
||||
c_root.add_child(b_root)
|
||||
b_root.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
b_root.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
|
||||
if _add_to_group:
|
||||
b_root.add_to_group(&"__SP_BR__")
|
||||
|
||||
return b_root
|
||||
|
||||
|
||||
func create_base_container_item(c_root : Container) -> BaseContainerItem:
|
||||
var b_item : BaseContainerItem = BaseContainerItem.new()
|
||||
c_root.add_child(b_item)
|
||||
|
||||
b_item.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
b_item.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
|
||||
return b_item
|
||||
|
||||
func create_editor_container(c_root : BaseContainerItem) -> SplitterEditorContainer.Editor:
|
||||
var b_editor : SplitterEditorContainer = SplitterEditorContainer.new()
|
||||
|
||||
c_root.add_child(b_editor)
|
||||
b_editor.get_editor()
|
||||
|
||||
var editor : SplitterEditorContainer.Editor = b_editor.get_editor()
|
||||
|
||||
editor.focus.connect(_handler_container.on_focus)
|
||||
editor.remove.connect(_handler_container.on_remove)
|
||||
|
||||
editor.get_tab_bar().tab_rmb_clicked.connect(_on_rmb_clicked.bind(editor))
|
||||
return editor
|
||||
|
||||
func _on_rmb_clicked(index : int, tab : Variant) -> void:
|
||||
if tab is SplitterEditorContainer.Editor:
|
||||
_handler_container.rmb_click.emit(index, tab)
|
||||
|
||||
func create_new_editor_container(c_root : Node, _add_to_group : bool = true) -> SplitterEditorContainer.Editor:
|
||||
return create_editor_container(create_base_container_item(create_base_container(c_root, _add_to_group)))
|
||||
|
||||
func get_current_editor() -> SplitterEditorContainer.Editor:
|
||||
return _last_editor_container
|
||||
|
||||
func reset() -> void:
|
||||
_root.queue_free()
|
||||
if is_instance_valid(_base_container):
|
||||
_base_container.visible = true
|
||||
|
||||
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
||||
if settings.settings_changed.is_connected(_on_change):
|
||||
settings.settings_changed.disconnect(_on_change)
|
||||
|
||||
func notify_creation() -> void:
|
||||
if is_instance_valid(_base_container) and _base_container.visible:
|
||||
_base_container.visible = false
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://dyo7c2g4uwn0g
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
@tool
|
||||
extends VBoxContainer
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
# Script Splitter
|
||||
# https://github.com/CodeNameTwister/Script-Splitter
|
||||
#
|
||||
# Script Splitter addon for godot 4
|
||||
# author: "Twister"
|
||||
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||
const Editor = preload("./../../../core/ui/splitter/editor_container.gd")
|
||||
const CONTAINER = preload("./../../../core/ui/multi_split_container/taby/container.tscn")
|
||||
|
||||
var _editor : Editor = null
|
||||
var _tab_old_behaviour : bool = false:
|
||||
set = _on_behaviour_changed
|
||||
var tab : Node = null
|
||||
|
||||
func _on_behaviour_changed(e) -> void:
|
||||
_tab_old_behaviour = e
|
||||
if is_instance_valid(tab):
|
||||
tab.set_enable(!_tab_old_behaviour)
|
||||
_editor.tabs_visible = _tab_old_behaviour
|
||||
|
||||
func _on_change() -> void:
|
||||
var dt : Array = ["plugin/script_splitter/editor/tabs/use_old_behaviour"]
|
||||
|
||||
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
||||
var changes : PackedStringArray = settings.get_changed_settings()
|
||||
|
||||
for c in changes:
|
||||
if c in dt:
|
||||
_setup()
|
||||
break
|
||||
|
||||
func _setup() -> void:
|
||||
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
||||
if !settings.settings_changed.is_connected(_on_change):
|
||||
settings.settings_changed.connect(_on_change)
|
||||
|
||||
for x : Array in [
|
||||
["_tab_old_behaviour", "plugin/script_splitter/editor/tabs/use_old_behaviour"]
|
||||
]:
|
||||
if settings.has_setting(x[1]):
|
||||
set(x[0], settings.get_setting(x[1]))
|
||||
else:
|
||||
settings.set_setting(x[1], get(x[0]))
|
||||
|
||||
func _ready() -> void:
|
||||
_editor = Editor.new()
|
||||
|
||||
var iscale : int = -8
|
||||
set(&"theme_override_constants/separation", iscale)
|
||||
|
||||
tab = CONTAINER.instantiate()
|
||||
tab.set_ref(_editor.get_tab_bar())
|
||||
tab.set_enable(!_tab_old_behaviour)
|
||||
_editor.tabs_visible = _tab_old_behaviour
|
||||
|
||||
add_child(tab)
|
||||
add_child(_editor)
|
||||
|
||||
size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
|
||||
func _enter_tree() -> void:
|
||||
add_to_group(&"__SP_EC__")
|
||||
_setup()
|
||||
|
||||
func _exit_tree() -> void:
|
||||
remove_from_group(&"__SP_EC__")
|
||||
|
||||
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
||||
if settings.settings_changed.is_connected(_on_change):
|
||||
settings.settings_changed.disconnect(_on_change)
|
||||
|
||||
func get_editor() -> Editor:
|
||||
return _editor
|
||||
|
||||
func update() -> void:
|
||||
if !is_instance_valid(tab):
|
||||
return
|
||||
tab.update()
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue