459 lines
16 KiB
GDScript
459 lines
16 KiB
GDScript
@tool
|
|
extends EditorPlugin
|
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
|
# Script Spliter
|
|
# https://github.com/CodeNameTwister/Script-Spliter
|
|
#
|
|
# Script Spliter addon for godot 4
|
|
# author: "Twister"
|
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
|
|
|
const BUILDER : Script = preload("res://addons/script_spliter/core/builder.gd")
|
|
const CONTEXT : Script = preload("res://addons/script_spliter/context/context_window.gd")
|
|
|
|
const CMD_MENU_TOOL : String = "Script Spliter"
|
|
|
|
#CONTEXT
|
|
const ICON_ADD_COLUMN : Texture = preload("res://addons/script_spliter/context/icons/split_cplus.svg")
|
|
const ICON_REMOVE_COLUMN : Texture = preload("res://addons/script_spliter/context/icons/split_cminus.svg")
|
|
const ICON_ADD_ROW : Texture = preload("res://addons/script_spliter/context/icons/split_rplus.svg")
|
|
const ICON_REMOVE_ROW : Texture = preload("res://addons/script_spliter/context/icons/split_rminus.svg")
|
|
const ICON_FLOATING : Texture = preload("res://addons/script_spliter/context/icons/atop.png")
|
|
const ICON_TAB : Texture = preload("res://addons/script_spliter/assets/tab_icon.svg")
|
|
|
|
var _rmb_editor_add_split : EditorContextMenuPlugin = null
|
|
var _rmb_editor_remove_split: EditorContextMenuPlugin = null
|
|
var _rmb_editor_code_add_split : EditorContextMenuPlugin = null
|
|
var _rmb_editor_code_remove_split : EditorContextMenuPlugin = null
|
|
var _rmb_editor_pop_script : EditorContextMenuPlugin = null
|
|
var _rmb_editor_code_pop_script : EditorContextMenuPlugin = null
|
|
|
|
var _rmb_close_all_tab_in_split : EditorContextMenuPlugin = null
|
|
var _rmb_close_all_tab_in_split_right : EditorContextMenuPlugin = null
|
|
var _rmb_close_all_tab_in_split_left : EditorContextMenuPlugin = null
|
|
|
|
var _menu_split_selector : Window = null
|
|
var _builder : Object = null
|
|
|
|
var _daemon_chaser : Node = null
|
|
|
|
#region _REF_
|
|
var _tab_container : Node = null:
|
|
get:
|
|
if !is_instance_valid(_tab_container):
|
|
var script_editor: ScriptEditor = EditorInterface.get_script_editor()
|
|
_tab_container = find(script_editor, "*", "TabContainer")
|
|
return _tab_container
|
|
|
|
var _item_list : Node = null:
|
|
get:
|
|
if !is_instance_valid(_item_list):
|
|
var script_editor: ScriptEditor = EditorInterface.get_script_editor()
|
|
_item_list = find(script_editor, "*", "ItemList")
|
|
return _item_list
|
|
#endregion
|
|
|
|
#region _USER_BUFFER_
|
|
var _rows : int = 0:
|
|
set(e):
|
|
_rows = maxi(e, 0)
|
|
var _columns : int = 0:
|
|
set(e):
|
|
_columns = maxi(e, 0)
|
|
var _refresh_warnings_on_save : bool = true
|
|
#endregion
|
|
|
|
var _frm : int = 0
|
|
var _d_chase : bool = false
|
|
|
|
func get_builder() -> Object:
|
|
return _builder
|
|
|
|
func find(root : Node, pattern : String, type : String) -> Node:
|
|
var e : Array[Node] = root.find_children(pattern, type, true, false)
|
|
if e.size() > 0:
|
|
return e[0]
|
|
return null
|
|
|
|
func get_split_rows() -> int:
|
|
return _rows
|
|
|
|
func get_split_columns() -> int:
|
|
return _columns
|
|
|
|
func _on_save(res : Resource) -> void:
|
|
if res is Script:
|
|
_save_external_data()
|
|
|
|
func _save_external_data() -> void:
|
|
if _d_chase == true:
|
|
return
|
|
_d_chase = true
|
|
if _refresh_warnings_on_save and is_instance_valid(_builder):
|
|
if _daemon_chaser == null:
|
|
_daemon_chaser = ResourceLoader.load("res://addons/script_spliter/core/DaemonChaser.gd").new()
|
|
add_child(_daemon_chaser)
|
|
_daemon_chaser.set_current_index(_builder.get_current_focus_index())
|
|
_daemon_chaser.buffer = _builder.get_focus_config()
|
|
_builder.enable_focus_highlight(false)
|
|
_daemon_chaser.run(_builder.focus_by_index, _builder.set_focus_config)
|
|
set_deferred(&"_d_chase", false)
|
|
|
|
func _process(__: float) -> void:
|
|
if _frm < 2:
|
|
_frm += 1
|
|
return
|
|
_frm = 0
|
|
set_process(false)
|
|
if is_instance_valid(_builder):
|
|
_builder.update()
|
|
|
|
func _on_change_settings() -> void:
|
|
if is_instance_valid(_builder):
|
|
_builder.update_config()
|
|
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
|
var changes : PackedStringArray = settings.get_changed_settings()
|
|
|
|
if &"plugin/script_spliter/behaviour/refresh_warnings_on_save" in changes:
|
|
_refresh_warnings_on_save = settings.get_setting(&"plugin/script_spliter/behaviour/refresh_warnings_on_save")
|
|
|
|
func _init() -> void:
|
|
var o : Object = _tab_container
|
|
if o == null:
|
|
#push_warning("[Script-Spliter] 0x000A")
|
|
return
|
|
o = _item_list
|
|
if o == null:
|
|
#push_warning("[Script-Spliter] 0x000B")
|
|
return
|
|
|
|
func _run() -> void:
|
|
if is_instance_valid(_builder):
|
|
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
|
var scripts_tab_container : Node = _tab_container
|
|
|
|
if !scripts_tab_container:
|
|
push_warning("[Script-Spliter] 0x000A Error can not find editor reference!")
|
|
return
|
|
|
|
var il : Node = _item_list
|
|
if null != il:
|
|
_builder.set_item_list(il)
|
|
else:
|
|
push_warning("[Script-Spliter] 0x000B Error can not find editor reference!")
|
|
return
|
|
|
|
if !scripts_tab_container.is_node_ready():
|
|
await scripts_tab_container.ready
|
|
if !is_instance_valid(scripts_tab_container):
|
|
push_error("Unspected error reference be replace or free it, can not run plugin!")
|
|
return
|
|
|
|
settings.settings_changed.connect(_on_change_settings)
|
|
|
|
_builder.init_1()
|
|
_builder.build(scripts_tab_container, _columns, _rows)
|
|
set_process_input(true)
|
|
|
|
func set_type_split(columns : int, rows : int) -> void:
|
|
_columns = columns
|
|
_rows = rows
|
|
|
|
var str_columns : String = str(maxi(_columns, 1))
|
|
var str_rows : String = str(maxi(rows, 1))
|
|
|
|
print("[{0}] {1} {2}: > {3} {5} - {4} {6}".format(
|
|
[
|
|
_get_translated_text("INFO"),
|
|
_get_translated_text("Setting"),
|
|
_get_translated_text("To"),
|
|
_get_translated_text("Columns"),
|
|
_get_translated_text("Rows"),
|
|
str_columns,
|
|
str_rows
|
|
]) )
|
|
|
|
if is_instance_valid(_builder):
|
|
_builder.update_build(columns, rows)
|
|
|
|
func _exit_tree() -> void:
|
|
remove_tool_menu_item(CMD_MENU_TOOL)
|
|
_setup(0)
|
|
|
|
if is_instance_valid(_builder):
|
|
_builder.init_0()
|
|
_builder.free.call_deferred()
|
|
|
|
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
|
if settings.settings_changed.is_connected(_on_change_settings):
|
|
settings.settings_changed.disconnect(_on_change_settings)
|
|
|
|
if is_instance_valid(_daemon_chaser) and !_daemon_chaser.is_queued_for_deletion():
|
|
_daemon_chaser.queue_free()
|
|
|
|
func _get_translated_text(text : String) -> String:
|
|
# TODO: Translation
|
|
return text
|
|
|
|
func swap(caller : Object) -> void:
|
|
if is_instance_valid(_builder):
|
|
_builder.swap(caller)
|
|
|
|
func _setup(input : int) -> void:
|
|
var settings : EditorSettings = EditorInterface.get_editor_settings()
|
|
|
|
if input != 0:
|
|
add_to_group(&"ScriptSpliter")
|
|
|
|
main_screen_changed.connect(_on_change)
|
|
resource_saved.connect(_on_save)
|
|
|
|
var ctx_add_column : String = _get_translated_text("ADD_SPLIT").capitalize()
|
|
var ctx_remove_split : String = _get_translated_text("REMOVE_SPLIT").capitalize()
|
|
var ctx_pop_script : String = _get_translated_text("MAKE_FLOATING_SCRIPT").capitalize()
|
|
var ctx_close_tabs : String = _get_translated_text("CLOSE_OTHERS_TABS_IN_SPLIT").capitalize()
|
|
var ctx_close_tabs_right : String = _get_translated_text("CLOSE_RIGHT_TABS_IN_SPLIT").capitalize()
|
|
var ctx_close_tabs_left : String = _get_translated_text("CLOSE_LEFT_TABS_IN_SPLIT").capitalize()
|
|
|
|
#SETUP
|
|
_rmb_editor_add_split = CONTEXT.new(ctx_add_column, _add_window_split, _can_add_split, ICON_ADD_COLUMN)
|
|
_rmb_editor_remove_split = CONTEXT.new(ctx_remove_split, _remove_window_split, _can_remove_split, ICON_REMOVE_COLUMN)
|
|
|
|
_rmb_editor_code_add_split = CONTEXT.new(ctx_add_column, _add_window_split, _can_add_split, ICON_ADD_COLUMN)
|
|
_rmb_editor_code_remove_split = CONTEXT.new(ctx_remove_split, _remove_window_split, _can_remove_split, ICON_REMOVE_COLUMN)
|
|
|
|
_rmb_editor_pop_script = CONTEXT.new(ctx_pop_script, _make_pop_script, _can_make_pop_script, ICON_FLOATING)
|
|
_rmb_editor_code_pop_script = CONTEXT.new(ctx_pop_script, _make_pop_script, _can_make_pop_script, ICON_FLOATING)
|
|
|
|
_rmb_close_all_tab_in_split = CONTEXT.new(ctx_close_tabs, _close_all_tabs_in_split, _can_close_tab_in_split, ICON_TAB)
|
|
_rmb_close_all_tab_in_split_left = CONTEXT.new(ctx_close_tabs_left, _close_all_tabs_in_split_left, _can_close_left_tab_in_split, ICON_TAB)
|
|
_rmb_close_all_tab_in_split_right = CONTEXT.new(ctx_close_tabs_right, _close_all_tabs_in_split_right, _can_close_right_tab_in_split, ICON_TAB)
|
|
|
|
add_context_menu_plugin(EditorContextMenuPlugin.CONTEXT_SLOT_SCRIPT_EDITOR, _rmb_close_all_tab_in_split)
|
|
add_context_menu_plugin(EditorContextMenuPlugin.CONTEXT_SLOT_SCRIPT_EDITOR, _rmb_close_all_tab_in_split_left)
|
|
add_context_menu_plugin(EditorContextMenuPlugin.CONTEXT_SLOT_SCRIPT_EDITOR, _rmb_close_all_tab_in_split_right)
|
|
|
|
|
|
add_context_menu_plugin(EditorContextMenuPlugin.CONTEXT_SLOT_SCRIPT_EDITOR, _rmb_editor_add_split)
|
|
add_context_menu_plugin(EditorContextMenuPlugin.CONTEXT_SLOT_SCRIPT_EDITOR, _rmb_editor_remove_split)
|
|
|
|
add_context_menu_plugin(EditorContextMenuPlugin.CONTEXT_SLOT_SCRIPT_EDITOR_CODE, _rmb_editor_code_add_split)
|
|
add_context_menu_plugin(EditorContextMenuPlugin.CONTEXT_SLOT_SCRIPT_EDITOR_CODE, _rmb_editor_code_remove_split)
|
|
|
|
add_context_menu_plugin(EditorContextMenuPlugin.CONTEXT_SLOT_SCRIPT_EDITOR, _rmb_editor_pop_script)
|
|
add_context_menu_plugin(EditorContextMenuPlugin.CONTEXT_SLOT_SCRIPT_EDITOR_CODE, _rmb_editor_code_pop_script)
|
|
|
|
if !settings.has_setting(&"plugin/script_spliter/rows"):
|
|
settings.set_setting(&"plugin/script_spliter/rows", _rows)
|
|
else:
|
|
_rows = settings.get_setting(&"plugin/script_spliter/rows")
|
|
if !settings.has_setting(&"plugin/script_spliter/columns"):
|
|
settings.set_setting(&"plugin/script_spliter/columns", _columns)
|
|
else:
|
|
_columns = settings.get_setting(&"plugin/script_spliter/columns")
|
|
if !settings.has_setting(&"plugin/script_spliter/save_rows_columns_count_on_exit"):
|
|
settings.set_setting(&"plugin/script_spliter/save_rows_columns_count_on_exit", false)
|
|
if !settings.has_setting(&"plugin/script_spliter/behaviour/refresh_warnings_on_save"):
|
|
settings.set_setting(&"plugin/script_spliter/behaviour/refresh_warnings_on_save", _refresh_warnings_on_save)
|
|
else:
|
|
_refresh_warnings_on_save = settings.get_setting(&"plugin/script_spliter/behaviour/refresh_warnings_on_save")
|
|
else:
|
|
if is_in_group(&"ScriptSpliter"):
|
|
remove_from_group(&"ScriptSpliter")
|
|
|
|
main_screen_changed.disconnect(_on_change)
|
|
resource_saved.disconnect(_on_save)
|
|
|
|
if is_instance_valid(_rmb_close_all_tab_in_split):
|
|
remove_context_menu_plugin(_rmb_close_all_tab_in_split)
|
|
if is_instance_valid(_rmb_close_all_tab_in_split_right):
|
|
remove_context_menu_plugin(_rmb_close_all_tab_in_split_right)
|
|
if is_instance_valid(_rmb_close_all_tab_in_split_left):
|
|
remove_context_menu_plugin(_rmb_close_all_tab_in_split_left)
|
|
|
|
if is_instance_valid(_rmb_editor_add_split):
|
|
remove_context_menu_plugin(_rmb_editor_add_split)
|
|
if is_instance_valid(_rmb_editor_remove_split):
|
|
remove_context_menu_plugin(_rmb_editor_remove_split)
|
|
if is_instance_valid(_rmb_editor_code_add_split):
|
|
remove_context_menu_plugin(_rmb_editor_code_add_split)
|
|
if is_instance_valid(_rmb_editor_code_remove_split):
|
|
remove_context_menu_plugin(_rmb_editor_code_remove_split)
|
|
if is_instance_valid(_rmb_editor_pop_script):
|
|
remove_context_menu_plugin(_rmb_editor_pop_script)
|
|
if is_instance_valid(_rmb_editor_code_pop_script):
|
|
remove_context_menu_plugin(_rmb_editor_code_pop_script)
|
|
|
|
|
|
if settings.has_setting(&"plugin/script_spliter/save_rows_columns_count_on_exit"):
|
|
if settings.get_setting(&"plugin/script_spliter/save_rows_columns_count_on_exit") == true:
|
|
settings.set_setting(&"plugin/script_spliter/rows", _rows)
|
|
settings.set_setting(&"plugin/script_spliter/columns", _columns)
|
|
|
|
func _can_close_tab_in_split(path : PackedStringArray) -> bool:
|
|
return _builder.has_other_tabs()
|
|
|
|
func _can_close_right_tab_in_split(path : PackedStringArray) -> bool:
|
|
return _builder.has_right_tabs()
|
|
|
|
func _can_close_left_tab_in_split(path : PackedStringArray) -> bool:
|
|
return _builder.has_left_tabs()
|
|
|
|
func _close_all_tabs_in_split(__ : Variant) -> void:
|
|
_builder.close_other_tabs()
|
|
|
|
func _close_all_tabs_in_split_right(__ : Variant) -> void:
|
|
_builder.close_right_tabs()
|
|
|
|
func _close_all_tabs_in_split_left(__ : Variant) -> void:
|
|
_builder.close_left_tabs()
|
|
|
|
func _can_add_split(path : PackedStringArray) -> bool:
|
|
if !is_instance_valid(_builder):
|
|
return false
|
|
if path.size() == 0:
|
|
return _builder.can_add_split(null)
|
|
else:
|
|
for x : String in path:
|
|
if x.begins_with("res://"):
|
|
var sc : ScriptEditor = EditorInterface.get_script_editor()
|
|
return _builder.can_add_split(sc.get_current_editor().get_base_editor())
|
|
else:
|
|
var node : Node = get_node_or_null(x)
|
|
if node:
|
|
return _builder.can_add_split(node)
|
|
else:
|
|
var sc : ScriptEditor = EditorInterface.get_script_editor()
|
|
return _builder.can_add_split(sc.get_current_editor().get_base_editor())
|
|
return false
|
|
|
|
func _can_remove_split(path : PackedStringArray) -> bool:
|
|
if !is_instance_valid(_builder):
|
|
return false
|
|
if path.size() == 0:
|
|
return _builder.can_remove_split(null)
|
|
else:
|
|
for x : String in path:
|
|
if x.begins_with("res://"):
|
|
var sc : ScriptEditor = EditorInterface.get_script_editor()
|
|
return _builder.can_remove_split(sc.get_current_editor().get_base_editor())
|
|
else:
|
|
var node : Node = get_node_or_null(x)
|
|
if node:
|
|
return _builder.can_remove_split(node)
|
|
else:
|
|
var sc : ScriptEditor = EditorInterface.get_script_editor()
|
|
return _builder.can_remove_split(sc.get_current_editor().get_base_editor())
|
|
return false
|
|
|
|
func _add_window_split(variant : Variant) -> void:
|
|
var control : Control = null
|
|
if variant is Script:
|
|
var sc : ScriptEditor = EditorInterface.get_script_editor()
|
|
if variant == sc.get_current_script():
|
|
control = sc.get_current_editor().get_base_editor()
|
|
else:
|
|
var c : ScriptEditorBase = sc.get_current_editor()
|
|
if c:
|
|
control = c.get_base_editor()
|
|
elif variant is CodeEdit:
|
|
control = variant
|
|
if is_instance_valid(control):
|
|
_builder.add_split(control)
|
|
|
|
func _remove_window_split(variant : Variant) -> void:
|
|
var control : Control = null
|
|
if variant is Script:
|
|
var sc : ScriptEditor = EditorInterface.get_script_editor()
|
|
if variant == sc.get_current_script():
|
|
control = sc.get_current_editor().get_base_editor()
|
|
else:
|
|
var c : ScriptEditorBase = sc.get_current_editor()
|
|
if c:
|
|
control = c.get_base_editor()
|
|
elif variant is CodeEdit:
|
|
control = variant
|
|
if is_instance_valid(control):
|
|
_builder.remove_split(control)
|
|
|
|
func _make_pop_script(variant : Variant) -> void:
|
|
var control : Control = null
|
|
if variant is Script:
|
|
var sc : ScriptEditor = EditorInterface.get_script_editor()
|
|
var arr : Array[ScriptEditorBase] = sc.get_open_script_editors()
|
|
var scs : Array[Script] = sc.get_open_scripts()
|
|
if arr.size() == scs.size():
|
|
for y : int in range(0, scs.size(), 1):
|
|
if scs[y] == variant:
|
|
control = arr[y].get_base_editor()
|
|
break
|
|
if variant is CodeEdit:
|
|
control = variant
|
|
if is_instance_valid(control):
|
|
_builder.make_pop_script(control)
|
|
|
|
func _can_make_pop_script(path : PackedStringArray) -> bool:
|
|
if !is_instance_valid(_builder):
|
|
return false
|
|
for x : String in path:
|
|
var node : Node = get_node_or_null(x)
|
|
if node:
|
|
return !_builder.is_pop_script(node)
|
|
return false
|
|
|
|
func _on_change(screen_name : String) -> void:
|
|
if screen_name == "Script":
|
|
if is_instance_valid(_builder):
|
|
_builder.update_rect.call_deferred()
|
|
|
|
|
|
func _enter_tree() -> void:
|
|
_setup(1)
|
|
if !is_instance_valid(_builder):
|
|
_builder = BUILDER.new(self)
|
|
add_tool_menu_item(CMD_MENU_TOOL, _on_tool_command)
|
|
|
|
func _on_tool_command() -> void:
|
|
if is_instance_valid(_builder):
|
|
var data : Array[int] = _builder.get_current_columns_and_rows()
|
|
_columns = data[0]
|
|
_rows = data[1]
|
|
|
|
if !is_instance_valid(_menu_split_selector):
|
|
_menu_split_selector = (ResourceLoader.load("res://addons/script_spliter/context/menu_tool.tscn") as PackedScene).instantiate()
|
|
_menu_split_selector.set_plugin(self)
|
|
_menu_split_selector.visible = false
|
|
add_child(_menu_split_selector)
|
|
_menu_split_selector.popup_centered.call_deferred()
|
|
|
|
func _ready() -> void:
|
|
set_process(false)
|
|
set_process_input(false)
|
|
if !get_tree().root.is_node_ready():
|
|
await get_tree().root.ready
|
|
for __ : int in range(2):
|
|
await get_tree().process_frame
|
|
_run()
|
|
|
|
func _notification(what: int) -> void:
|
|
if what == NOTIFICATION_PREDELETE:
|
|
if is_instance_valid(_builder) and !_builder.is_queued_for_deletion():
|
|
_builder.init_0()
|
|
_builder.free()
|
|
|
|
func _input(event: InputEvent) -> void:
|
|
if event is InputEventKey:
|
|
if event.pressed and event.ctrl_pressed:
|
|
if event.keycode == 49:
|
|
set_type_split(0, 0)
|
|
elif event.keycode == 50:
|
|
set_type_split(2, 1)
|
|
elif event.keycode == 51:
|
|
set_type_split(1, 2)
|
|
elif event.keycode == 52:
|
|
set_type_split(3, 1)
|
|
elif event.keycode == 53:
|
|
set_type_split(1, 3)
|
|
elif event.keycode == 54:
|
|
set_type_split(2, 2)
|