diff --git a/.godot_ide/.gdignore b/.godot_ide/.gdignore new file mode 100644 index 0000000..a0d111a --- /dev/null +++ b/.godot_ide/.gdignore @@ -0,0 +1 @@ +IDE CONFIG \ No newline at end of file diff --git a/.godot_ide/config.ini b/.godot_ide/config.ini new file mode 100644 index 0000000..c230836 --- /dev/null +++ b/.godot_ide/config.ini @@ -0,0 +1,12 @@ +[config] + +plugin={ +"res://addons/_Godot-IDE_/plugins/fancy_filters_script/plugin.gd": true, +"res://addons/_Godot-IDE_/plugins/fancy_search_class/plugin.gd": true, +"res://addons/_Godot-IDE_/plugins/fancy_search_files/plugin.gd": true, +"res://addons/_Godot-IDE_/plugins/gd_override_functions/plugin.gd": true, +"res://addons/_Godot-IDE_/plugins/macro-n/plugin.gd": true, +"res://addons/_Godot-IDE_/plugins/quick_folds/plugin.gd": true, +"res://addons/_Godot-IDE_/plugins/script_splitter/plugin.gd": true, +"res://addons/_Godot-IDE_/plugins/symbol_navigator/plugin.gd": true +} diff --git a/addons/_Godot-IDE_/IDE.gd b/addons/_Godot-IDE_/IDE.gd new file mode 100644 index 0000000..565c7ba --- /dev/null +++ b/addons/_Godot-IDE_/IDE.gd @@ -0,0 +1,683 @@ +@tool +class_name IDE extends EditorPlugin +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# ./plugins: Folder for extensions. +# ./shared_resources: Free use for any purposes. +# ============================================================================= + +const EDITOR_CONFIG_PATH : String = "plugin/godot_ide/" +const PATH_CONFIG : String = "res://.ide/" + +static var _ref : Dictionary[String, Object] = {} +static var _safe_ref : Dictionary[String, Node] = {} + +static var debug : bool = true + +static var PRIVATE_METHODS : String = "__" +static var VIRTUAL_METHODS : String = "_" + +static var _menu : MenuButton = null + +#region DEV_API +## Get current editor container for edit/view scripts. +static func get_script_editor_container() -> TabContainer: + var script_editor: ScriptEditor = EditorInterface.get_script_editor() + var out : Variant = _get_reference("script_editor_container", script_editor, "*", "TabContainer", 0) + if out is TabContainer: + return out + return null + +## Get current script/documents opened list. +static func get_script_list() -> ItemList: + var script_editor: ScriptEditor = EditorInterface.get_script_editor() + var out : Variant = _get_reference("script_list", script_editor, "*", "ItemList", 0) + if out is ItemList: + return out + return null + +## Get search bar native of script list. +static func get_script_list_search_bar() -> LineEdit: + var script_editor: ScriptEditor = EditorInterface.get_script_editor() + var out : Variant = _get_reference("script_list_search_bar", script_editor, "*", "LineEdit", 0) + if out is LineEdit: + return out + return null + +## Get label of the script list +static func get_script_list_current_label() -> Label: + var script_editor: ScriptEditor = EditorInterface.get_script_editor() + var out : Variant = _get_reference("script_list_current_label", script_editor, "*", "Label", 2) + if out is Label: + return out + return null + +## Get the bottom panel of filter side by script list. +static func get_filter_methods() -> ItemList: + var script_editor: ScriptEditor = EditorInterface.get_script_editor() + var out : Variant = _get_reference("filter_methods", script_editor, "*", "ItemList", 1) + if out is ItemList: + return out + return null + +## Get the search bar of the filters method panel. +static func get_filter_methods_search_bar() -> LineEdit: + var script_editor: ScriptEditor = EditorInterface.get_script_editor() + var out : Variant = _get_reference("filter_methods_search_bar", script_editor, "*", "LineEdit", 1) + if out is LineEdit: + return out + return null + +## Get the file on top menu bar. +static func get_file_menu_button() -> MenuButton: + var script_editor: ScriptEditor = EditorInterface.get_script_editor() + var out : Variant = _get_reference("file_menu_button", script_editor, "*", "MenuButton", 0) + if out is MenuButton: + return out + return null + +## Get the edit on top menu bar. +static func get_edit_menu_button() -> MenuButton: + var script_editor: ScriptEditor = EditorInterface.get_script_editor() + var out : Variant = _get_reference("edit_menu_button", script_editor, "*", "MenuButton", 1) + if out is MenuButton: + return out + return null + +## Get the search on top menu bar. +static func get_search_menu_button() -> MenuButton: + var script_editor: ScriptEditor = EditorInterface.get_script_editor() + var out : Variant = _get_reference("search_menu_button", script_editor, "*", "MenuButton", 2) + if out is MenuButton: + return out + return null + +## Get the got to menu on top menu bar. +static func get_go_to_menu_button() -> MenuButton: + var script_editor: ScriptEditor = EditorInterface.get_script_editor() + var out : Variant = _get_reference("get_go_to_menu_button", script_editor, "*", "MenuButton", 3) + if out is MenuButton: + return out + return null + +## Get the debug on top menu bar. +static func get_debug_menu_button() -> MenuButton: + var script_editor: ScriptEditor = EditorInterface.get_script_editor() + var out : Variant = _get_reference("debug_menu_button", script_editor, "*", "MenuButton", 17) + if out is MenuButton: + return out + return null + +## Get the container of scripts list. +static func get_script_list_container() -> VSplitContainer: + var script_editor: ScriptEditor = EditorInterface.get_script_editor() + var out : Variant = _get_reference("script_list_container", script_editor, "*", "VSplitContainer", 0) + if out is VSplitContainer: + return out + return null + +## Get the container of the editor. +static func get_editor_container() -> HSplitContainer: + var script_editor: ScriptEditor = EditorInterface.get_script_editor() + var out : Variant = _get_reference("editor_container", script_editor, "*", "HSplitContainer", 0) + if out is HSplitContainer: + return out + return null + +## Get native screen size. Raito must be 0.1 - 1.0 +static func get_screen_size(ratio : float = 1.0) -> Vector2: + var screen : Vector2 = DisplayServer.screen_get_size() + return screen * ratio + +## Clamp native screen size. +static func clamp_screen_size(current_size : Vector2, min_ratio : float = 0.0, max_ratio : float = 1.0) -> Vector2: + var screen : Vector2 = DisplayServer.screen_get_size() + var max_screen : Vector2 = screen * max_ratio + var min_screen : Vector2 = screen * min_ratio + return Vector2(max(min(current_size.x, max_screen.x), min_screen.x), max(min(current_size.y, max_screen.y), min_screen.y)) + +## Get full properties headers of a script. +static func get_script_properties_list(script : Script, full : bool = true, check_is_native : bool = true) -> Dictionary: + if script == null: + return {} + var nname : String = get_name_script(script) + if check_is_native and ClassDB.class_exists(nname): + return _generate_native(nname) + if full: + var data : Dictionary = _generate(script) + return _generate_native(script.get_instance_base_type(), data, data.size()-1) + else: + return _generate(script) + +## Get editor menu of godot-ide-extension from editor container. +static func get_menu_button() -> MenuButton: + return _menu +#endregion + + +# ============================================================================= +#region DEV_CONFIG +static func set_config(plugin_name : String, config_name : String, value : Variant) -> void: + var editor : EditorSettings = EditorInterface.get_editor_settings() + if editor: + if config_name.is_empty(): + printerr("Config name can not be empty!") + return + if plugin_name.is_empty(): + printerr("Plugin name can not be empty") + return + editor.set_setting(EDITOR_CONFIG_PATH.path_join(plugin_name).path_join(config_name), value) + +static func add_property_config_info(plugin_name : String, config_name : String, type : Variant.Type, hint : int, hint_string : String): + var editor : EditorSettings = EditorInterface.get_editor_settings() + if editor: + if config_name.is_empty(): + printerr("Config name can not be empty!") + return + if plugin_name.is_empty(): + printerr("Plugin name can not be empty") + return + editor.add_property_info({ + "name": EDITOR_CONFIG_PATH.path_join(plugin_name).path_join(config_name), + "type": type, + "hint": hint, + "hint_string": hint_string + }) + +static func get_config(addon_name : String, config_name : String) -> Variant: + var editor : EditorSettings = EditorInterface.get_editor_settings() + if editor: + var setting : String = EDITOR_CONFIG_PATH.path_join(addon_name).path_join(config_name) + if editor.has_setting(setting): + return editor.get_setting(setting) + return null + +static func set_file_config_value(section : String, key : String, value : Variant) -> int: + if !DirAccess.dir_exists_absolute(PATH_CONFIG): + if OK != DirAccess.make_dir_recursive_absolute(PATH_CONFIG): + push_warning("Can not creates config dir!") + return 1 + if FileAccess.file_exists(PATH_CONFIG.path_join(".gdignore")): + var file : FileAccess = FileAccess.open(PATH_CONFIG.path_join(".gdignore"), FileAccess.WRITE) + file.store_string("FOLDER Godot-IDE CONFIG") + file.close() + + var cfg_path : String = PATH_CONFIG.path_join("config.ini") + var cfg : ConfigFile = ConfigFile.new() + if FileAccess.file_exists(cfg_path): + cfg.load(cfg_path) + cfg.set_value(section, key, value) + return cfg.save(cfg_path) + +static func get_file_config_value(section : String, key : String) -> Variant: + var cfg_path : String = PATH_CONFIG.path_join("config.ini") + if !FileAccess.file_exists(cfg_path): + return null + var cfg : ConfigFile = ConfigFile.new() + var err : int = cfg.load(cfg_path) + if OK != err: + return null + return cfg.get_value(section, key, "") + +#endregion + +#region utils + + +static func get_type(_typeof : int) -> String: + var txt : String = "" + match _typeof: + TYPE_BOOL : txt = "bool" + TYPE_INT : txt = "int" + TYPE_FLOAT: txt = "float" + TYPE_STRING : txt = "String" + TYPE_VECTOR2 : txt = "Vector2" + TYPE_VECTOR2I : txt = "Vector2i" + TYPE_RECT2 : txt = "Rect2" + TYPE_RECT2I : txt = "Rect2i" + TYPE_VECTOR3 : txt = "Vector3" + TYPE_VECTOR3I : txt = "Vector3i" + TYPE_TRANSFORM2D : txt = "Tranform2D" + TYPE_VECTOR4 : txt = "Vector4" + TYPE_VECTOR4I : txt = "Vector4i" + TYPE_PLANE : txt = "Plane" + TYPE_QUATERNION : txt = "Quaternion" + TYPE_AABB : txt = "AABB" + TYPE_BASIS : txt = "Basis" + TYPE_TRANSFORM3D : txt = "Transform3D" + TYPE_PROJECTION : txt = "Projection" + TYPE_COLOR : txt = "Color" + TYPE_STRING_NAME : txt = "StringName" + TYPE_NODE_PATH : txt = "NodePath" + TYPE_RID : txt = "RID" + TYPE_OBJECT : txt = "Object" + TYPE_CALLABLE : txt = "Callable" + TYPE_SIGNAL : txt = "Signal" + TYPE_DICTIONARY : txt = "Dictionary" + TYPE_ARRAY : txt = "Array" + TYPE_PACKED_BYTE_ARRAY : txt = "PackedByteArray" + TYPE_PACKED_INT32_ARRAY : txt = "PackedInt32Array" + TYPE_PACKED_INT64_ARRAY : txt = "PackedInt64Array" + TYPE_PACKED_FLOAT32_ARRAY : txt = "PackedFloat32Array" + TYPE_PACKED_FLOAT64_ARRAY : txt = "PackedFloat64Array" + TYPE_PACKED_STRING_ARRAY : txt = "PackedStringArray" + TYPE_PACKED_VECTOR2_ARRAY : txt = "PackedVector2Array" + TYPE_PACKED_VECTOR3_ARRAY : txt = "PackedVector3Array" + TYPE_PACKED_COLOR_ARRAY : txt = "PackedColorArray" + TYPE_PACKED_VECTOR4_ARRAY : txt = "PackedVector4Array" + _: + txt = "Variant" + return txt + +static func _generate(script : Script, data : Dictionary = {}, index : int = -1) -> Dictionary: + if script == null: + return data + var funcs : Dictionary = {} + var props : Dictionary = {} + var signals : Dictionary = {} + var constants : Dictionary = {} + var base : Dictionary = { + "name" : &"GDScript" + ,"functions" : funcs + ,"properties" : props + ,"signals" : signals + ,"constants" : constants + ,"type": 1 + ,"custom": false + ,"path" : script.resource_path + ,"tool" : script.is_tool() + ,"abstract" : script.is_abstract() + ,"built_in" : script.is_built_in() + } + + var base_name : String = get_name_script(script, base) + base["name"] = base_name + index += 1 + data[index] = base + + for dict: Dictionary in script.get_script_method_list(): + var func_name: StringName = dict.name + if func_name.begins_with("@"):continue + funcs[func_name] =_get_header_virtual(dict) + if dict.has("flags"): + if dict["flags"] & METHOD_FLAG_STATIC: + funcs[func_name] += "||static" + elif dict["flags"] & METHOD_FLAG_CONST: + funcs[func_name] += "||const" + + for dict : Dictionary in script.get_script_property_list(): + var pro_name: StringName = dict.name + var as_exporrt : bool = false + if !pro_name.get_extension().is_empty(): + continue + if dict.has("usage"): + var usage : int = dict["usage"] + if !(usage & PROPERTY_USAGE_SCRIPT_VARIABLE): + continue + for x : int in [PROPERTY_USAGE_STORAGE, PROPERTY_USAGE_EDITOR, PROPERTY_USAGE_CHECKABLE, PROPERTY_USAGE_CHECKED, PROPERTY_USAGE_GROUP]: + if usage & x: + as_exporrt = true + break + props[pro_name] =_get_header_virtual(dict) + if as_exporrt: + props[pro_name] += "||export" + else: + if dict.has("flags"): + if dict["flags"] & METHOD_FLAG_STATIC: + props[pro_name] += "||static" + elif dict["flags"] & METHOD_FLAG_CONST: + props[pro_name] += "||const" + + for dict : Dictionary in script.get_property_list(): + var pro_name: StringName = dict.name + if !pro_name.get_extension().is_empty(): + continue + if dict.has("usage"): + var usage : int = dict["usage"] + if !(usage & PROPERTY_USAGE_SCRIPT_VARIABLE): + continue + props[pro_name] =_get_header_virtual(dict) + props[pro_name] += "||static" + + for dict : Dictionary in script.get_script_signal_list(): + var pro_name: StringName = dict.name + signals[pro_name] =_get_header_virtual(dict) + + for dict : Variant in script.get_script_constant_map(): + if dict is StringName: + var variant : Variant = script.get(dict) + constants[dict] = "{0}||{1}".format([dict, get_type(typeof(variant))]) + elif dict is Dictionary: + var pro_name: StringName = dict.name + constants[pro_name] =_get_header_virtual(dict) + + if data.size() > 0: + var start : int = 0 + while !data.has(start) and start < index: + start += 1 + for x : int in range(start, index, 1): + var clazz : Dictionary = data[x]["functions"] + for k : Variant in funcs.keys(): + if clazz.has(k): + if !"||overrided" in clazz[k]: + clazz[k] += "||overrided" + for x : int in range(start, index, 1): + var clazz : Dictionary = data[x]["properties"] + for k : Variant in props.keys(): + if clazz.has(k): + if !"||overrided" in clazz[k]: + clazz[k] += "||overrided" + for x : int in range(start, index, 1): + var clazz : Dictionary = data[x]["signals"] + for k : Variant in signals.keys(): + if clazz.has(k): + if !"||overrided" in clazz[k]: + clazz[k] += "||overrided" + for x : int in range(start, index, 1): + var clazz : Dictionary = data[x]["constants"] + for k : Variant in constants.keys(): + if clazz.has(k): + if !"||overrided" in clazz[k]: + clazz[k] += "||overrided" + else: + clazz[k] = constants[k] + "||overrided" + return _generate(script.get_base_script(), data, index) + + +static func _generate_native(native : StringName, data : Dictionary = {}, index : int = 0) -> Dictionary: + if native.is_empty() or !ClassDB.class_exists(native): + return data + var funcs : Dictionary = {} + var props : Dictionary = {} + var signals : Dictionary = {} + var constants : Dictionary = {} + + var api_type : int = ClassDB.class_get_api_type(native) + + var base : Dictionary = { + "name" : native + ,"functions" : funcs + ,"properties" : props + ,"signals" : signals + ,"constants" : constants + ,"type" : 0 + ,"custom": false + ,"path" : "NativeScript" + ,"tool" : api_type == ClassDB.APIType.API_EDITOR or api_type == ClassDB.APIType.API_EDITOR_EXTENSION + ,"abstract" : false #! + ,"built_in" : false + } + index += 1 + data[index] = base + + + for dict: Dictionary in ClassDB.class_get_method_list(native, true): + funcs[dict.name] =_get_header_virtual(dict) + + for dict : Dictionary in ClassDB.class_get_property_list(native, true): + var pro_name: StringName = dict.name + if !pro_name.get_extension().is_empty(): + continue + props[pro_name] =_get_header_virtual(dict) + + for dict : Dictionary in ClassDB.class_get_signal_list(native, true): + var pro_name: StringName = dict.name + signals[pro_name] =_get_header_virtual(dict) + + for dict : String in ClassDB.class_get_enum_list(native, true): + var pro_name: StringName = dict + constants[pro_name] = "{0}||enum||void".format([dict]) + + for dict : String in ClassDB.class_get_integer_constant_list(native, true): + var pro_name: StringName = dict + constants[pro_name] = "{0}||int||void".format([dict]) + + if data.size() > 0: + var start : int = 0 + while !data.has(start) and start < index: + start += 1 + for x : int in range(start, index, 1): + var clazz : Dictionary = data[x]["functions"] + for k : Variant in funcs.keys(): + if clazz.has(k): + if !"||overrided" in clazz[k]: + clazz[k] += "||overrided" + for x : int in range(start, index, 1): + var clazz : Dictionary = data[x]["properties"] + for k : Variant in props.keys(): + if clazz.has(k): + if !"||overrided" in clazz[k]: + clazz[k] += "||overrided" + for x : int in range(start, index, 1): + var clazz : Dictionary = data[x]["signals"] + for k : Variant in signals.keys(): + if clazz.has(k): + if !"||overrided" in clazz[k]: + clazz[k] += "||overrided" + for x : int in range(start, index, 1): + var clazz : Dictionary = data[x]["constants"] + for k : Variant in constants.keys(): + if clazz.has(k): + if !"||overrided" in clazz[k]: + clazz[k] += "||overrided" + + return _generate_native(ClassDB.get_parent_class(native), data, index) + +static func clamp_rect_to_screen(to_clamp_rect: Rect2, max_aviable_rect : Rect2) -> Rect2: + + if to_clamp_rect.position.x < max_aviable_rect.position.x: + to_clamp_rect.position.x = max_aviable_rect.position.x + elif to_clamp_rect.position.x + to_clamp_rect.size.x > max_aviable_rect.position.x + max_aviable_rect.size.x: + to_clamp_rect.position.x = max_aviable_rect.position.x + max_aviable_rect.size.x - to_clamp_rect.size.x + + if to_clamp_rect.position.y < max_aviable_rect.position.y: + to_clamp_rect.position.y = max_aviable_rect.position.y + elif to_clamp_rect.position.y + to_clamp_rect.size.y > max_aviable_rect.position.y + max_aviable_rect.size.y: + to_clamp_rect.position.y = max_aviable_rect.position.y + max_aviable_rect.size.y - to_clamp_rect.size.y + + if to_clamp_rect.size.x > max_aviable_rect.size.x: + to_clamp_rect.position.x = max_aviable_rect.position.x + (max_aviable_rect.size.x - to_clamp_rect.size.x) / 2 + if to_clamp_rect.size.y > max_aviable_rect.size.y: + to_clamp_rect.position.y = max_aviable_rect.position.y + (max_aviable_rect.size.y - to_clamp_rect.size.y) / 2 + + return to_clamp_rect + + +static func get_header_function(dict : Dictionary) -> String: + var params : String = "" + var args : Array = dict["args"] + var separator : String = "" + var default_args : Array = dict["default_args"] + var _default_index : int = default_args.size() + + for y : int in range(args.size() - 1, -1, -1): + var arg : Dictionary = args[y] + var txt : String = arg["name"] + if !(arg["class_name"]).is_empty(): + txt += str(" : ", arg["class_name"] as String) + else: + var _typeof : int = arg["type"] + txt += str(" : ", IDE.get_type(_typeof)) + if _default_index > 0: + _default_index -= 1 + var def : Variant = default_args[_default_index] + var _type : int = typeof(def) + if def == null or _type < 1: + txt += str(' = null') + elif _type < 5: + if def is String: + txt += str(' = "', def, '"') + elif def is StringName: + txt += str(' = &"', def, '"') + else: + txt += str(" = ", def) + else: + txt += str(" = ", IDE.get_type(typeof(def)), def) + params = str(txt, separator, params) + separator = ", " + + var return_dic : Dictionary = dict["return"] + var return_type : String = "void" + var return_value : String = "pass" + if !return_dic["class_name"].is_empty(): + return_type = (return_dic["class_name"] as String) + return_value = "return null" + else: + var _type : int = return_dic["type"] + if _type < 1: + var func_name : String = str(dict["name"]).to_lower() + if func_name == "get" or __is_variant(func_name): + return_type = "Variant" + return_value = "return null" + else: + return_type = "void" + else: + return_type = IDE.get_type(return_dic["type"]) + if _type == TYPE_INT: + return_value = "return 0" + elif _type == TYPE_BOOL: + return_value = "return false" + elif _type == TYPE_FLOAT: + return_value = "return 0.0" + elif _type == TYPE_STRING: + return_value = 'return ""' + elif _type == TYPE_ARRAY: + return_value = "return []" + else: + return_value = str("return ", return_type,"()") + return "func {0}({1}) -> {2}:\n\t#TODO: code here :)\n\t{3}".format([dict["name"], params, return_type, return_value]) + + + +static func _get_header_virtual(dict : Dictionary, include_paremeters : bool = true) -> String: + var params : String = "" + var separator : String = "" + if dict.has("args"): + var args : Array = dict["args"] + var default_args : Array = dict["default_args"] + var _default_index : int = default_args.size() + + for y : int in range(args.size() - 1, -1, -1): + var arg : Dictionary = args[y] + var txt : String = "" #arg["name"] + if !(arg["class_name"]).is_empty(): + txt += str(arg["class_name"] as String) + else: + var _typeof : int = arg["type"] + txt += str(IDE.get_type(_typeof)) + if include_paremeters and _default_index > 0: + _default_index -= 1 + var def : Variant = default_args[_default_index] + var _type : int = typeof(def) + if def == null or _type < 1: + txt += str(' = null') + elif _type < 5: + if def is String: + txt += str(' = "', def, '"') + elif def is StringName: + txt += str(' = &"', def, '"') + else: + txt += str(" = ", def) + else: + txt += str(" = ",IDE.get_type(typeof(def)), def) + params = str(txt, separator, params) + separator = ", " + + if dict.has("return"): + var return_dic : Dictionary = dict["return"] + var return_type : String = "void" + + if !return_dic["class_name"].is_empty(): + return_type = (return_dic["class_name"] as String) + else: + var _type : int = return_dic["type"] + if _type < 1: + var func_name : String = str(dict["name"]).to_lower() + if func_name == "get" or __is_variant(func_name): + return_type = "Variant" + else: + return_type = "void" + else: + return_type = get_type(return_dic["type"]) + + #if params.is_empty(): + #params = "-" + return "{0}||{1}||{2}".format([dict["name"], params, return_type]) #Replace x more space. + elif dict.has("class_name"): + var classname : String = dict["class_name"] + if classname.is_empty() and dict.has("type"): + classname = get_type(dict["type"]) + params = classname + return "{0}||{1}||void".format([dict["name"], params]) + +static func __is_variant(func_name : String) -> bool: + const FUNC_GET : Array[String] = ["get_", "_get"] + for x : String in FUNC_GET: + if func_name.begins_with(x) or func_name.ends_with(x): + return true + return func_name.contains("_get_") + +static func get_name_script(script : Script, ref_data : Dictionary = {}) -> StringName: + var base_name : StringName = script.get_global_name() + if base_name.is_empty(): + var path : String = script.resource_name + if path.is_empty(): + path = script.resource_path + if !path.is_empty(): + var _name : String = path.get_file() + _name = _name.trim_suffix("." + _name.get_extension()) + base_name = _name + else: + base_name = &"CustomScript" + ref_data["custom"] = true + else: + base_name = path + return base_name + +static func _reset() -> void: + for x : String in _ref.keys(): + var object : Variant = _ref[x] + if is_instance_valid(object) and object is Node: + if _safe_ref.has(x): + var parent : Node = _safe_ref[x] + if is_instance_valid(parent) and !parent.is_queued_for_deletion(): + var current : Node = object.get_parent() + if current != parent: + if is_instance_valid(current): + object.reparent(parent) + else: + parent.add_child(object) + +static func _get_reference(container_name : String, root_container : Node, pattern : String, type : String, index : int) -> Variant: + if !is_instance_valid(root_container): + if debug: + # If you recieved this message, try reset the engine with this addon enabled. + # | If the problem persist, make a issue on "https://github.com/CodeNameTwister/godot_ide" + push_warning("Caution!, not root reference setted!!") + return null + elif _ref.has(container_name): + var object : Variant = _ref[container_name] + if is_instance_valid(object): + if object is Node: + if !_safe_ref.has(container_name): + _safe_ref[container_name] = object.get_parent() + return object + var new_object : Variant = _find(root_container, pattern, type, index) + if is_instance_valid(new_object): + _ref[container_name] = new_object + return new_object + if debug: + # If you recieved this message, try reset the engine with this addon enabled. + # | If the problem persist, make a issue on "https://github.com/CodeNameTwister/godot_ide" + push_warning("Caution!, can not found: {0}!!".format([container_name])) + return null + +static func _find(root : Node, pattern : String, type : String, index : int = 0) -> Node: + var e : Array[Node] = root.find_children(pattern, type, true, false) + if e.size() > index: + return e[index] + return null + +#endregion diff --git a/addons/_Godot-IDE_/IDE.gd.uid b/addons/_Godot-IDE_/IDE.gd.uid new file mode 100644 index 0000000..0cf2c73 --- /dev/null +++ b/addons/_Godot-IDE_/IDE.gd.uid @@ -0,0 +1 @@ +uid://d270rwyekls6t diff --git a/addons/_Godot-IDE_/icon.svg b/addons/_Godot-IDE_/icon.svg new file mode 100644 index 0000000..5e672c5 --- /dev/null +++ b/addons/_Godot-IDE_/icon.svg @@ -0,0 +1,128 @@ + + + + + + + + + + + diff --git a/addons/_Godot-IDE_/icon.svg.import b/addons/_Godot-IDE_/icon.svg.import new file mode 100644 index 0000000..33b9eb0 --- /dev/null +++ b/addons/_Godot-IDE_/icon.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://brfrp6r0fiwl2" +path="res://.godot/imported/icon.svg-b579c8a7bc6a03fedff183ec85fa8cc5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/icon.svg" +dest_files=["res://.godot/imported/icon.svg-b579c8a7bc6a03fedff183ec85fa8cc5.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/plugin.cfg b/addons/_Godot-IDE_/plugin.cfg new file mode 100644 index 0000000..a6cc127 --- /dev/null +++ b/addons/_Godot-IDE_/plugin.cfg @@ -0,0 +1,8 @@ +[plugin] + +name="Godot-IDE" +description="GODOT-IDE" +author="Twister" +version="0.5.5" +script="plugin.gd" +github="https://github.com/CodeNameTwister/Godot-IDE" diff --git a/addons/_Godot-IDE_/plugin.gd b/addons/_Godot-IDE_/plugin.gd new file mode 100644 index 0000000..bf2e347 --- /dev/null +++ b/addons/_Godot-IDE_/plugin.gd @@ -0,0 +1,299 @@ +@tool +extends IDE +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# ./plugins: Folder for extensions. +# ./shared_resources: Free use for any purposes. +# ============================================================================= + +var _plugins : Array[EditorPlugin] = [] +var _enable_plugins : Dictionary = {} + +func _ready() -> void: + debug = false + + main_screen_changed.connect(_on_main_screen_changed) + resource_saved.connect(_on_resource_saved) + scene_closed.connect(_on_scene_closed) + scene_changed.connect(_on_scene_changed) + scene_saved.connect(_on_scene_saved) + + _initialize() + +func _on_resource_saved(resource : Resource) -> void: + for x : EditorPlugin in _plugins: + x.resource_saved.emit(resource) + +func _on_scene_closed(filepath: String) -> void: + for x : EditorPlugin in _plugins: + x.scene_closed.emit(filepath) + +func _on_scene_changed(scene_root: Node) -> void: + for x : EditorPlugin in _plugins: + x.scene_changed.emit(scene_root) + +func _on_scene_saved(filepath: String) -> void: + for x : EditorPlugin in _plugins: + x.scene_saved.emit(filepath) + +func _on_main_screen_changed(screen_name : String) -> void: + for x : EditorPlugin in _plugins: + x.main_screen_changed.emit(screen_name) + +func _enter_tree() -> void: + set_process(true) + +func _process(_delta: float) -> void: + var editor : EditorFileSystem = EditorInterface.get_resource_filesystem() + if !editor: + return + if editor.is_scanning(): + return + set_process(false) + + #Self-Secure All Loaded + _initialize() + + var base : String = get_script().resource_path.get_base_dir() + var path : String = base.path_join("plugins") + + _init_config(1) + _load_plugins(path) + + _sugar_godot(path) + _sugar_godot(base.path_join("shared_resources"), "teal") + +func _init_config(init : int) -> void: + const PATH : String = "res://.godot_ide/" + var cfg_path : String = PATH.path_join("config.ini") + if !DirAccess.dir_exists_absolute(PATH): + DirAccess.make_dir_absolute(PATH) + var file : FileAccess = FileAccess.open(PATH.path_join(".gdignore"), FileAccess.WRITE) + if file: + file.store_string("IDE CONFIG") + file.close() + + if init == 1: + if FileAccess.file_exists(cfg_path): + var cfg : ConfigFile = ConfigFile.new() + if cfg.load(cfg_path) == OK: + var value : Variant = cfg.get_value("config", "plugin", {}) + if value is Dictionary: + _enable_plugins = value + else: + var cfg : ConfigFile = ConfigFile.new() + cfg.set_value("config", "plugin", _enable_plugins) + if cfg.save(cfg_path) != OK: + push_warning("Can not save plugin changes!") + + #if Engine.get_version_info().minor > 4: + #_enable_plugins["res://addons/_Godot-IDE_/plugins/script_spliter/plugin.gd"] = false + +#region __PRX__ +func _apply_changes() -> void: + _callback(&"_apply_changes") + +func _set_window_layout(configuration: ConfigFile) -> void: + for plugin : EditorPlugin in _plugins: + if plugin.has_method(&"_set_window_layout"): + plugin.call(&"_set_window_layout", configuration) + +func _build() -> bool: + for plugin : EditorPlugin in _plugins: + if plugin.has_method(&"_build"): + if !plugin.call(&"_build"): + return false + return true + +func _clear() -> void: + _callback(&"_build") + +func _disable_plugin() -> void: + _callback(&"_disable_plugin") + +func _edit(object: Object) -> void: + for plugin : EditorPlugin in _plugins: + if plugin.has_method(&"_edit"): + plugin.call(&"_edit", object) + +func _forward_3d_draw_over_viewport(viewport_control: Control) -> void: + for plugin : EditorPlugin in _plugins: + if plugin.has_method(&"_forward_3d_draw_over_viewport"): + plugin.call(&"_forward_3d_draw_over_viewport", viewport_control) + +func _forward_3d_force_draw_over_viewport(viewport_control: Control) -> void: + for plugin : EditorPlugin in _plugins: + if plugin.has_method(&"_forward_3d_force_draw_over_viewport"): + plugin.call(&"_forward_3d_force_draw_over_viewport", viewport_control) + +func _forward_canvas_draw_over_viewport(viewport_control: Control) -> void: + for plugin : EditorPlugin in _plugins: + if plugin.has_method(&"_forward_canvas_draw_over_viewport"): + plugin.call(&"_forward_canvas_draw_over_viewport", viewport_control) + +func _forward_canvas_force_draw_over_viewport(viewport_control: Control) -> void: + for plugin : EditorPlugin in _plugins: + if plugin.has_method(&"_forward_canvas_force_draw_over_viewport"): + plugin.call(&"_forward_canvas_force_draw_over_viewport", viewport_control) + +func _forward_canvas_gui_input(event: InputEvent) -> bool: + var out : bool = false + for plugin : EditorPlugin in _plugins: + if plugin.has_method(&"_forward_canvas_gui_input"): + out = plugin.call(&"_forward_canvas_gui_input", event) or out + return out +#endregion + +func _callback(method : StringName) -> void: + for plugin : EditorPlugin in _plugins: + if plugin.has_method(method): + plugin.call(method) + +func _exit_tree() -> void: + for x : Node in _plugins: + if is_instance_valid(x): + if !x.is_queued_for_deletion(): + x.queue_free() + + _plugins.clear() + _init_config(0) + + var editor : EditorSettings = EditorInterface.get_editor_settings() + if editor: + if editor.settings_changed.is_connected(_on_changes): + editor.settings_changed.disconnect(_on_changes) + + if is_instance_valid(IDE._menu): + IDE._menu.queue_free() + IDE._menu = null + +func _load_plugins(path : String) -> void: + if !is_instance_valid(IDE._menu): + var file : MenuButton = get_file_menu_button() + if is_instance_valid(file): + var root : Node = file.get_parent() + IDE._menu = MenuButton.new() + IDE._menu.text = "Godot-IDE" + root.add_child(_menu) + root.move_child(_menu, mini(1, root.get_child_count() - 1)) + + if !DirAccess.dir_exists_absolute(path): + path = path.get_base_dir().get_file() + if EditorInterface.is_plugin_enabled(path): + EditorInterface.set_plugin_enabled(path, false) + printerr("{0}: Error, can not find 'plugins' folder! [0x00000003]".format([path.capitalize().to_upper()])) + return + + var dir :DirAccess = DirAccess.open(path) + var plugins_dir : Array = [] + var plugins_file : Array = [] + var authors : PackedStringArray = [] + + if dir: + dir.list_dir_begin() + var file_name : String = dir.get_next() + while !file_name.is_empty(): + if dir.current_is_dir(): + plugins_dir.append(path.path_join(file_name)) + file_name = dir.get_next() + dir.list_dir_end() + else: + printerr("{0}:error, can not open 'plugins' folder! [0x00000005]".format([path.get_base_dir().get_file().capitalize().to_upper()])) + + while plugins_dir.size() > 0: + var current_path : String = plugins_dir.pop_back() + var plugin_path : String = current_path.path_join("plugin.gd") + var plugin_cfg : String = current_path.path_join("plugin.cfg") + + if FileAccess.file_exists(plugin_cfg): + var cfg : ConfigFile = ConfigFile.new() + if cfg.load(plugin_cfg) == OK: + if cfg.has_section_key("plugin", "script"): + plugin_path = current_path.path_join(str(cfg.get_value("plugin", "script"))) + if cfg.has_section_key("plugin", "author"): + var value : String = str(cfg.get_value("plugin", "author")) + if !value.is_empty() and !authors.has(value): + authors.append(value) + + if !FileAccess.file_exists(plugin_path): + plugin_path = current_path.path_join(current_path.get_file()) + if !FileAccess.file_exists(plugin_path): + printerr("{0}:error, can not open 'plugin/{1}' folder! [0x00000005]".format([path.get_base_dir().get_file().capitalize().to_upper(), current_path.get_file()])) + continue + plugins_file.append(plugin_path) + + var current_plugins : Dictionary = {} + for plugin : String in plugins_file: + if _enable_plugins.has(plugin): + if _enable_plugins[plugin] == false: + continue + var variant : Variant = ResourceLoader.load(plugin) + if variant is Script: + if variant.can_instantiate(): + if !variant.is_tool(): + push_warning("Plugin script is not tool: {0}".format([plugin])) + variant = variant.new() + if variant is EditorPlugin: + _plugins.append(variant) + current_plugins[plugin] = true + + _enable_plugins = current_plugins + + for plugin : EditorPlugin in _plugins: + get_parent().add_child(plugin) + if plugin.has_method(&"_enable_plugin"): + plugin.call(&"_enable_plugin") + + print("[Godot-IDE Extension]") + if authors.size() > 0: + print("> Plugin Contributors: {0}".format([", ".join(authors)])) + + +func _sugar_godot(dir : String, col : String = "blue") -> void: + if !ProjectSettings.has_setting("file_customization/folder_colors"): + ProjectSettings.set_setting("file_customization/folder_colors", {dir: col}) + else: + if !dir.ends_with("/"): + dir += "/" + var data : Dictionary = ProjectSettings.get_setting("file_customization/folder_colors", {}) + if !data.has(dir): + data[dir] = col + ProjectSettings.set_setting("file_customization/folder_colors", data) + else: + return + var editor : EditorFileSystem = EditorInterface.get_resource_filesystem() + if editor: + editor.scan.call_deferred() + +func _on_changes() -> void: + var editor : EditorSettings = EditorInterface.get_editor_settings() + if editor: + var changes : PackedStringArray = editor.get_changed_settings() + if "plugin/gd_override_functions/inheritance/virtual_functions_begins_with" in changes: + IDE.VIRTUAL_METHODS = editor.get_setting("plugin/gd_override_functions/inheritance/virtual_functions_begins_with") + if "plugin/gd_override_functions/inheritance/private_functions_begins_with" in changes: + IDE.PRIVATE_METHODS = editor.get_setting("plugin/gd_override_functions/inheritance/private_functions_begins_with") + +func _initialize() -> void: + var dirt : Dictionary = {} + var dat : Array[Dictionary] = (get_script() as Script).get_script_method_list() + for dct : Dictionary in dat: + var key : String = dct["name"] + if dirt.has(key): + continue + dirt[key] = true + if has_method(key): + if key.begins_with("get_"): + if !dct.has("args") or dct["args"].size() == 0: + call(key) + + var editor : EditorSettings = EditorInterface.get_editor_settings() + if editor: + if editor.has_setting("plugin/gd_override_functions/inheritance/virtual_functions_begins_with"): + IDE.VIRTUAL_METHODS = editor.get_setting("plugin/gd_override_functions/inheritance/virtual_functions_begins_with") + if editor.has_setting("plugin/gd_override_functions/inheritance/private_functions_begins_with"): + IDE.PRIVATE_METHODS = editor.get_setting("plugin/gd_override_functions/inheritance/private_functions_begins_with") + if !editor.settings_changed.is_connected(_on_changes): + editor.settings_changed.connect(_on_changes) diff --git a/addons/_Godot-IDE_/plugin.gd.uid b/addons/_Godot-IDE_/plugin.gd.uid new file mode 100644 index 0000000..e12e430 --- /dev/null +++ b/addons/_Godot-IDE_/plugin.gd.uid @@ -0,0 +1 @@ +uid://bqmc0vi754ifc diff --git a/addons/_Godot-IDE_/plugins/fancy_filters_script/assets/flatbox.tres b/addons/_Godot-IDE_/plugins/fancy_filters_script/assets/flatbox.tres new file mode 100644 index 0000000..50fd0c6 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_filters_script/assets/flatbox.tres @@ -0,0 +1,5 @@ +[gd_resource type="StyleBoxEmpty" format=3 uid="uid://dwpkbhgi7dk8"] + +[resource] +content_margin_left = 8.0 +content_margin_right = 8.0 diff --git a/addons/_Godot-IDE_/plugins/fancy_filters_script/button.gd b/addons/_Godot-IDE_/plugins/fancy_filters_script/button.gd new file mode 100644 index 0000000..93e90a8 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_filters_script/button.gd @@ -0,0 +1,14 @@ +@tool +extends Button +# ============================================================================= +# Author: Twister +# Fancy Filter Script +# +# Addon for Godot +# ============================================================================= + + +func _pressed() -> void: + if owner: + if owner.has_method(name): + owner.call(name) diff --git a/addons/_Godot-IDE_/plugins/fancy_filters_script/button.gd.uid b/addons/_Godot-IDE_/plugins/fancy_filters_script/button.gd.uid new file mode 100644 index 0000000..e66c99b --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_filters_script/button.gd.uid @@ -0,0 +1 @@ +uid://b1v225muollg5 diff --git a/addons/_Godot-IDE_/plugins/fancy_filters_script/button_filter.gd b/addons/_Godot-IDE_/plugins/fancy_filters_script/button_filter.gd new file mode 100644 index 0000000..2b1b0ae --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_filters_script/button_filter.gd @@ -0,0 +1,35 @@ +@tool +extends Button +# ============================================================================= +# Author: Twister +# Fancy Filter Script +# +# Addon for Godot +# ============================================================================= + +func update_settings() -> void: + var variant : Variant = owner.get(name) + if variant is bool: + button_pressed = variant + + visual() + + +func _ready() -> void: + update_settings() + +func _pressed() -> void: + if owner.has_method(&"enable_filter"): + owner.call(&"enable_filter", name, button_pressed) + visual() + +func visual() -> void: + if button_pressed: + var value : Variant = owner.get(str(name, "_color")) + if value is Color: + modulate = value + else: + modulate = Color.WHITE + else: + modulate = Color.DARK_GRAY + modulate.a = 0.7 diff --git a/addons/_Godot-IDE_/plugins/fancy_filters_script/button_filter.gd.uid b/addons/_Godot-IDE_/plugins/fancy_filters_script/button_filter.gd.uid new file mode 100644 index 0000000..61dcdff --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_filters_script/button_filter.gd.uid @@ -0,0 +1 @@ +uid://gct2x12uf8jj diff --git a/addons/_Godot-IDE_/plugins/fancy_filters_script/components/order_settings.gd b/addons/_Godot-IDE_/plugins/fancy_filters_script/components/order_settings.gd new file mode 100644 index 0000000..4c79341 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_filters_script/components/order_settings.gd @@ -0,0 +1,36 @@ +@tool +extends Control +# ============================================================================= +# Author: Twister +# Fancy Filter Script +# +# Addon for Godot +# ============================================================================= + +@export var container : Control = null + +func _ready() -> void: + var p : Node = get_parent() + if !p.child_entered_tree.is_connected(_on_child): + p.child_entered_tree.connect(_on_child) + + visibility_changed.connect(_on_visible) + +func _on_child(n : Node) -> void: + var p : Node = get_parent() + if is_instance_valid(p) and !p.is_queued_for_deletion(): + if p.get_child_count() > 0: + p.move_child.call_deferred(self, p.get_child_count() - 1) + +func _on_visible() -> void: + if visible: + var packed : PackedScene = ResourceLoader.load("res://addons/_Godot-IDE_/plugins/fancy_filters_script/components/settings.tscn") + if packed: + var c : Control = packed.instantiate() + container.add_child(c) + c.size_flags_horizontal = Control.SIZE_EXPAND_FILL + c.size_flags_vertical = Control.SIZE_EXPAND_FILL + + else: + for x : Node in container.get_children(): + x.queue_free() diff --git a/addons/_Godot-IDE_/plugins/fancy_filters_script/components/order_settings.gd.uid b/addons/_Godot-IDE_/plugins/fancy_filters_script/components/order_settings.gd.uid new file mode 100644 index 0000000..928d051 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_filters_script/components/order_settings.gd.uid @@ -0,0 +1 @@ +uid://cbvs583dwh5o diff --git a/addons/_Godot-IDE_/plugins/fancy_filters_script/components/settings.gd b/addons/_Godot-IDE_/plugins/fancy_filters_script/components/settings.gd new file mode 100644 index 0000000..671a9c5 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_filters_script/components/settings.gd @@ -0,0 +1,142 @@ +@tool +extends Control +# ============================================================================= +# Author: Twister +# Fancy Filter Script +# +# Addon for Godot +# ============================================================================= +@export var _type_members : TabContainer +@export var _accessibility : TabContainer + +@export var sorty_name_enabled : CheckBox + +@export var order_name_check : CheckBox +@export var order_name_button : Button + +@export var background_color : Button +@export var use_dots : Button +@export var flat_mode_button : Button +@export var separate_script_list_button : Button + +const NORMAL_ICON : Texture2D = preload("res://addons/_Godot-IDE_/shared_resources/up.svg") +const INVERT_ICON : Texture2D = preload("res://addons/_Godot-IDE_/shared_resources/down.svg") + +signal on_update_order(data : Dictionary) + +enum TYPE_ORDER{ + NONE = 0, + NORMAL = 1, + INVERT = 2 +} + +var name_order : TYPE_ORDER = TYPE_ORDER.NORMAL + +func use_background_color_in_script_info() -> void: + IDE.set_config("fancy_filters_script", "use_background_color_in_script_info", background_color.button_pressed) + +func use_dots_as_item_icons() -> void: + IDE.set_config("fancy_filters_script", "use_dots_as_item_icons", use_dots.button_pressed) + +func flat_mode() -> void: + IDE.set_config("fancy_filters_script", "flat_mode", flat_mode_button.button_pressed) + +func separate_script_list() -> void: + IDE.set_config("fancy_filters_script", "separate_container_list", separate_script_list_button.button_pressed) + +func update_settings() -> void: + var order : Variant = IDE.get_config("fancy_filters_script", "members_order_by") + var name_type : Variant = IDE.get_config("fancy_filters_script", "name_order_by") + var background_pressed : Variant = IDE.get_config("fancy_filters_script", "use_background_color_in_script_info") + var use_dots_pressed: Variant = IDE.get_config("fancy_filters_script", "use_dots_as_item_icons") + var flat_mode_pressed : Variant = IDE.get_config("fancy_filters_script", "flat_mode") + var separate_script_list_pressed : Variant = IDE.get_config("fancy_filters_script", "separate_container_list") + + if !(separate_script_list_pressed is bool): + separate_script_list_pressed = false + if !(order is Array): + order = [] + if !(name_type is int): + name_type = 0 + if !(background_pressed is bool): + background_pressed = false + if !(use_dots_pressed is bool): + use_dots_pressed = false + if !(flat_mode_pressed is bool): + flat_mode_pressed = false + + use_dots.button_pressed = use_dots_pressed + background_color.button_pressed = background_pressed + flat_mode_button.button_pressed = flat_mode_pressed + separate_script_list_button.button_pressed = separate_script_list_pressed + + name_order = name_type + + order_name_check.button_pressed = name_order != 0 + + if name_order == TYPE_ORDER.INVERT: + order_name_button.icon = INVERT_ICON + else: + order_name_button.icon = NORMAL_ICON + + for x : Node in _type_members.get_children(): + match x.name: + &"Properties": + for z : int in range(order.size()): + if order[z] == 0: + _type_members.move_child(x, z) + &"Methods": + for z : int in range(order.size()): + if order[z] == 1: + _type_members.move_child(x, z) + &"Signals": + for z : int in range(order.size()): + if order[z] == 2: + _type_members.move_child(x, z) + &"Constant": + for z : int in range(order.size()): + if order[z] == 3: + _type_members.move_child(x, z) + order_name_button.disabled = !order_name_check.button_pressed + +func _ready() -> void: + update_settings() + +func order_name_check_button() -> void: + order_name_button.disabled = !order_name_check.button_pressed + if order_name_check.button_pressed == false: + IDE.set_config("fancy_filters_script", "name_order_by", 0) + else: + if order_name_button.icon == INVERT_ICON: + name_order = TYPE_ORDER.INVERT + else: + name_order = TYPE_ORDER.NORMAL + IDE.set_config("fancy_filters_script", "name_order_by", name_order) + +func order_name() -> void: + if name_order == TYPE_ORDER.NORMAL: + name_order = TYPE_ORDER.INVERT + order_name_button.icon = INVERT_ICON + else: + name_order = TYPE_ORDER.NORMAL + order_name_button.icon = NORMAL_ICON + if order_name_check.button_pressed == false: + IDE.set_config("fancy_filters_script", "name_order_by", 0) + else: + IDE.set_config("fancy_filters_script", "name_order_by", name_order) + +func set_settings() -> void: + var new_order : Array[int] = [] + + for x : Node in _type_members.get_children(): + match x.name: + &"Properties": + new_order.append(0) + &"Methods": + new_order.append(1) + &"Signals": + new_order.append(2) + &"Constant": + new_order.append(3) + + IDE.set_config("fancy_filters_script", "members_order_by", new_order) diff --git a/addons/_Godot-IDE_/plugins/fancy_filters_script/components/settings.gd.uid b/addons/_Godot-IDE_/plugins/fancy_filters_script/components/settings.gd.uid new file mode 100644 index 0000000..d69ce3c --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_filters_script/components/settings.gd.uid @@ -0,0 +1 @@ +uid://blc70goak5ixm diff --git a/addons/_Godot-IDE_/plugins/fancy_filters_script/components/settings.tscn b/addons/_Godot-IDE_/plugins/fancy_filters_script/components/settings.tscn new file mode 100644 index 0000000..2928b54 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_filters_script/components/settings.tscn @@ -0,0 +1,158 @@ +[gd_scene load_steps=6 format=3 uid="uid://bhrieo2dhroxj"] + +[ext_resource type="Script" uid="uid://blc70goak5ixm" path="res://addons/_Godot-IDE_/plugins/fancy_filters_script/components/settings.gd" id="1_8gu0h"] +[ext_resource type="StyleBox" uid="uid://dwpkbhgi7dk8" path="res://addons/_Godot-IDE_/plugins/fancy_filters_script/assets/flatbox.tres" id="1_e4fgx"] +[ext_resource type="Texture2D" uid="uid://bgjo43cuidob1" path="res://addons/_Godot-IDE_/shared_resources/up.svg" id="3_f6f5j"] +[ext_resource type="Script" uid="uid://drngb2pss3dtj" path="res://addons/_Godot-IDE_/plugins/fancy_filters_script/components/tab_container.gd" id="3_g0drt"] +[ext_resource type="Script" uid="uid://b1v225muollg5" path="res://addons/_Godot-IDE_/plugins/fancy_filters_script/button.gd" id="4_f6f5j"] + +[node name="Settings" type="VBoxContainer" node_paths=PackedStringArray("_type_members", "_accessibility", "sorty_name_enabled", "order_name_check", "order_name_button", "background_color", "use_dots", "flat_mode_button", "separate_script_list_button")] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_8gu0h") +_type_members = NodePath("Type") +_accessibility = NodePath("Accessibility") +sorty_name_enabled = NodePath("order_name_check_button") +order_name_check = NodePath("order_name_check_button") +order_name_button = NodePath("order_name") +background_color = NodePath("use_background_color_in_script_info") +use_dots = NodePath("use_dots_as_item_icons") +flat_mode_button = NodePath("flat_mode") +separate_script_list_button = NodePath("separate_script_list") + +[node name="order_name_check_button" type="CheckBox" parent="."] +layout_mode = 2 +size_flags_horizontal = 0 +button_pressed = true +text = "Enable Order By Name" +script = ExtResource("4_f6f5j") + +[node name="order_name" type="Button" parent="."] +custom_minimum_size = Vector2(200, 0) +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "Make sorty by using the name member." +text = "Sort Name" +icon = ExtResource("3_f6f5j") +icon_alignment = 2 +script = ExtResource("4_f6f5j") + +[node name="Sep3" type="HSeparator" parent="."] +layout_mode = 2 + +[node name="Label6" type="Label" parent="."] +layout_mode = 2 +size_flags_horizontal = 0 +text = "Order By Members (Drag and Drop)" + +[node name="Type" type="TabContainer" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "Change order by drag values." +theme_override_styles/panel = ExtResource("1_e4fgx") +theme_override_styles/tabbar_background = ExtResource("1_e4fgx") +theme_override_styles/tab_unselected = ExtResource("1_e4fgx") +theme_override_styles/tab_hovered = ExtResource("1_e4fgx") +theme_override_styles/tab_selected = ExtResource("1_e4fgx") +theme_override_styles/tab_disabled = ExtResource("1_e4fgx") +theme_override_styles/tab_focus = ExtResource("1_e4fgx") +current_tab = 0 +drag_to_rearrange_enabled = true +script = ExtResource("3_g0drt") + +[node name="Properties" type="Control" parent="Type"] +layout_mode = 2 +metadata/_tab_index = 0 + +[node name="Methods" type="Control" parent="Type"] +visible = false +layout_mode = 2 +metadata/_tab_index = 1 + +[node name="Signals" type="Control" parent="Type"] +visible = false +layout_mode = 2 +metadata/_tab_index = 2 + +[node name="Constant" type="Control" parent="Type"] +visible = false +layout_mode = 2 +metadata/_tab_index = 3 + +[node name="Sep" type="HSeparator" parent="."] +visible = false +layout_mode = 2 + +[node name="accessibility2" type="Label" parent="."] +visible = false +layout_mode = 2 +text = "Order By Accesibility (Drag and Drop)" + +[node name="Accessibility" type="TabContainer" parent="."] +visible = false +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_styles/panel = ExtResource("1_e4fgx") +theme_override_styles/tabbar_background = ExtResource("1_e4fgx") +theme_override_styles/tab_unselected = ExtResource("1_e4fgx") +theme_override_styles/tab_hovered = ExtResource("1_e4fgx") +theme_override_styles/tab_selected = ExtResource("1_e4fgx") +theme_override_styles/tab_disabled = ExtResource("1_e4fgx") +theme_override_styles/tab_focus = ExtResource("1_e4fgx") +current_tab = 0 +drag_to_rearrange_enabled = true +script = ExtResource("3_g0drt") + +[node name="Export" type="Control" parent="Accessibility"] +layout_mode = 2 +metadata/_tab_index = 0 + +[node name="Static" type="Control" parent="Accessibility"] +visible = false +layout_mode = 2 +metadata/_tab_index = 1 + +[node name="Public" type="Control" parent="Accessibility"] +visible = false +layout_mode = 2 +metadata/_tab_index = 2 + +[node name="Virtual" type="Control" parent="Accessibility"] +visible = false +layout_mode = 2 +metadata/_tab_index = 3 + +[node name="Private" type="Control" parent="Accessibility"] +visible = false +layout_mode = 2 +metadata/_tab_index = 4 + +[node name="Sep2" type="HSeparator" parent="."] +layout_mode = 2 + +[node name="use_dots_as_item_icons" type="CheckBox" parent="."] +layout_mode = 2 +size_flags_horizontal = 0 +text = "Use Dots As Script Info Items Icons" +script = ExtResource("4_f6f5j") + +[node name="use_background_color_in_script_info" type="CheckBox" parent="."] +layout_mode = 2 +size_flags_horizontal = 0 +text = "Use Background Colors in Script Info Items" +script = ExtResource("4_f6f5j") + +[node name="flat_mode" type="CheckBox" parent="."] +layout_mode = 2 +size_flags_horizontal = 0 +text = "Flat Mode" +script = ExtResource("4_f6f5j") + +[node name="separate_script_list" type="CheckBox" parent="."] +layout_mode = 2 +size_flags_horizontal = 0 +text = "Separate Script List" +script = ExtResource("4_f6f5j") diff --git a/addons/_Godot-IDE_/plugins/fancy_filters_script/components/tab_container.gd b/addons/_Godot-IDE_/plugins/fancy_filters_script/components/tab_container.gd new file mode 100644 index 0000000..dbaae6b --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_filters_script/components/tab_container.gd @@ -0,0 +1,13 @@ +@tool +extends TabContainer +# ============================================================================= +# Author: Twister +# Fancy Filter Script +# +# Addon for Godot +# ============================================================================= + +func _notification(what: int) -> void: + if what == NOTIFICATION_DRAG_END: + if owner.has_method(&"set_settings"): + owner.call(&"set_settings") diff --git a/addons/_Godot-IDE_/plugins/fancy_filters_script/components/tab_container.gd.uid b/addons/_Godot-IDE_/plugins/fancy_filters_script/components/tab_container.gd.uid new file mode 100644 index 0000000..7b8db2c --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_filters_script/components/tab_container.gd.uid @@ -0,0 +1 @@ +uid://drngb2pss3dtj diff --git a/addons/_Godot-IDE_/plugins/fancy_filters_script/filter_scene.tscn b/addons/_Godot-IDE_/plugins/fancy_filters_script/filter_scene.tscn new file mode 100644 index 0000000..ec049ab --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_filters_script/filter_scene.tscn @@ -0,0 +1,179 @@ +[gd_scene load_steps=14 format=3 uid="uid://dhlxe0qj82e8y"] + +[ext_resource type="Script" uid="uid://bwtq1pkujrb1d" path="res://addons/_Godot-IDE_/plugins/fancy_filters_script/script_info.gd" id="1_5gq01"] +[ext_resource type="Script" uid="uid://gct2x12uf8jj" path="res://addons/_Godot-IDE_/plugins/fancy_filters_script/button_filter.gd" id="2_djmkv"] +[ext_resource type="Script" uid="uid://dpkvcqsih4i8w" path="res://addons/_Godot-IDE_/plugins/fancy_filters_script/filters_container.gd" id="2_u1yuj"] +[ext_resource type="Texture2D" uid="uid://cjpyaeqxjujsy" path="res://addons/_Godot-IDE_/shared_resources/MethodOverride.svg" id="3_7xcf1"] +[ext_resource type="Texture2D" uid="uid://dqfn3tghaer0y" path="res://addons/_Godot-IDE_/shared_resources/ScriptExtend.svg" id="3_nynvq"] +[ext_resource type="Texture2D" uid="uid://ouml4wypk5bq" path="res://addons/_Godot-IDE_/shared_resources/MemberConstant.svg" id="4_7xcf1"] +[ext_resource type="Texture2D" uid="uid://bu2y52as0gijo" path="res://addons/_Godot-IDE_/shared_resources/MemberSignal.svg" id="5_2xgjc"] +[ext_resource type="Texture2D" uid="uid://cec6jsyssk4ys" path="res://addons/_Godot-IDE_/shared_resources/MemberProperty.svg" id="5_nynvq"] +[ext_resource type="Texture2D" uid="uid://cgdceyfng83st" path="res://addons/_Godot-IDE_/shared_resources/MemberMethod.svg" id="6_ndpn6"] +[ext_resource type="Texture2D" uid="uid://bjmtfc58y1sbs" path="res://addons/_Godot-IDE_/shared_resources/InterfaceScript.svg" id="8_goajo"] +[ext_resource type="Texture2D" uid="uid://816fejewtbfj" path="res://addons/_Godot-IDE_/shared_resources/search.svg" id="10_2xgjc"] +[ext_resource type="Script" uid="uid://bbbdyhh8lhw4a" path="res://addons/_Godot-IDE_/plugins/fancy_filters_script/line_edit.gd" id="11_1yamo"] +[ext_resource type="Script" uid="uid://cbvs583dwh5o" path="res://addons/_Godot-IDE_/plugins/fancy_filters_script/components/order_settings.gd" id="12_u1yuj"] + +[node name="Container" type="TabContainer" node_paths=PackedStringArray("button_container", "tree_container")] +custom_minimum_size = Vector2(64, 64) +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +current_tab = 0 +script = ExtResource("1_5gq01") +button_container = NodePath("Script Info/VContainer/SContainer/SHContainer") +tree_container = NodePath("Script Info/SContainer/Tree") + +[node name="Script Info" type="VBoxContainer" parent="."] +layout_mode = 2 +metadata/_tab_index = 0 + +[node name="VContainer" type="VBoxContainer" parent="Script Info"] +layout_mode = 2 + +[node name="SContainer" type="ScrollContainer" parent="Script Info/VContainer"] +custom_minimum_size = Vector2(0, 38) +layout_mode = 2 +size_flags_vertical = 3 +horizontal_scroll_mode = 3 +vertical_scroll_mode = 3 +script = ExtResource("2_u1yuj") + +[node name="SHContainer" type="HBoxContainer" parent="Script Info/VContainer/SContainer"] +custom_minimum_size = Vector2(0, 32) +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="show_all" type="Button" parent="Script Info/VContainer/SContainer/SHContainer"] +custom_minimum_size = Vector2(32, 0) +layout_mode = 2 +toggle_mode = true +button_pressed = true +text = "All" +icon_alignment = 1 +script = ExtResource("2_djmkv") + +[node name="show_inheritance" type="Button" parent="Script Info/VContainer/SContainer/SHContainer"] +modulate = Color(0.960784, 0.960784, 0.960784, 1) +custom_minimum_size = Vector2(32, 0) +layout_mode = 2 +tooltip_text = "Show inheritance" +toggle_mode = true +icon = ExtResource("3_7xcf1") +icon_alignment = 1 +script = ExtResource("2_djmkv") + +[node name="show_functions" type="Button" parent="Script Info/VContainer/SContainer/SHContainer"] +custom_minimum_size = Vector2(32, 0) +layout_mode = 2 +tooltip_text = "Show Properties" +toggle_mode = true +button_pressed = true +icon = ExtResource("6_ndpn6") +icon_alignment = 1 +script = ExtResource("2_djmkv") + +[node name="show_properties" type="Button" parent="Script Info/VContainer/SContainer/SHContainer"] +modulate = Color(0.7372549, 0.8784314, 1, 1) +custom_minimum_size = Vector2(32, 0) +layout_mode = 2 +tooltip_text = "Show Properties" +toggle_mode = true +button_pressed = true +icon = ExtResource("5_nynvq") +icon_alignment = 1 +script = ExtResource("2_djmkv") + +[node name="show_signals" type="Button" parent="Script Info/VContainer/SContainer/SHContainer"] +modulate = Color(0.89998645, 0.817927, 1, 1) +custom_minimum_size = Vector2(32, 0) +layout_mode = 2 +tooltip_text = "Show Signals" +toggle_mode = true +button_pressed = true +icon = ExtResource("5_2xgjc") +icon_alignment = 1 +script = ExtResource("2_djmkv") + +[node name="show_constants" type="Button" parent="Script Info/VContainer/SContainer/SHContainer"] +modulate = Color(0, 1, 1, 1) +custom_minimum_size = Vector2(32, 0) +layout_mode = 2 +tooltip_text = "Show Constants" +toggle_mode = true +button_pressed = true +icon = ExtResource("4_7xcf1") +icon_alignment = 1 +script = ExtResource("2_djmkv") + +[node name="show_parent_class" type="Button" parent="Script Info/VContainer/SContainer/SHContainer"] +modulate = Color(0.4627451, 0.8117647, 0.70980394, 1) +custom_minimum_size = Vector2(32, 0) +layout_mode = 2 +tooltip_text = "Show parent classes" +toggle_mode = true +button_pressed = true +icon = ExtResource("3_nynvq") +icon_alignment = 1 +script = ExtResource("2_djmkv") + +[node name="show_native_class" type="Button" parent="Script Info/VContainer/SContainer/SHContainer"] +modulate = Color(0.4627451, 0.8117647, 0.70980394, 1) +custom_minimum_size = Vector2(32, 0) +layout_mode = 2 +tooltip_text = "Show native classes" +toggle_mode = true +icon = ExtResource("8_goajo") +icon_alignment = 1 +script = ExtResource("2_djmkv") + +[node name="LineEdit" type="LineEdit" parent="Script Info/VContainer" node_paths=PackedStringArray("tree")] +layout_mode = 2 +placeholder_text = "Search Bar" +clear_button_enabled = true +right_icon = ExtResource("10_2xgjc") +script = ExtResource("11_1yamo") +tree = NodePath("../../SContainer/Tree") + +[node name="SContainer" type="ScrollContainer" parent="Script Info"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="Tree" type="Tree" parent="Script Info/SContainer"] +auto_translate_mode = 2 +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +theme_override_constants/h_separation = 0 +theme_override_constants/item_margin = 6 +columns = 2 +allow_rmb_select = true + +[node name="Settings" type="VBoxContainer" parent="." node_paths=PackedStringArray("container")] +visible = false +layout_mode = 2 +script = ExtResource("12_u1yuj") +container = NodePath("VBoxContainer/MarginContainer") +metadata/_tab_index = 1 + +[node name="VBoxContainer" type="VBoxContainer" parent="Settings"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="Label" type="Label" parent="Settings/VBoxContainer"] +layout_mode = 2 +text = "Filter Settings" +horizontal_alignment = 1 + +[node name="HSeparator" type="HSeparator" parent="Settings/VBoxContainer"] +layout_mode = 2 + +[node name="MarginContainer" type="ScrollContainer" parent="Settings/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 diff --git a/addons/_Godot-IDE_/plugins/fancy_filters_script/filters_container.gd b/addons/_Godot-IDE_/plugins/fancy_filters_script/filters_container.gd new file mode 100644 index 0000000..73c1608 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_filters_script/filters_container.gd @@ -0,0 +1,22 @@ +@tool +extends ScrollContainer + +func _ready() -> void: + mouse_entered.connect(_on_mouse) + _out_mouse() + +func _process(_delta: float) -> void: + if is_inside_tree(): + if get_global_rect().has_point(get_global_mouse_position()): + return + _out_mouse() + +func _on_mouse() -> void: + horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_AUTO + vertical_scroll_mode = ScrollContainer.SCROLL_MODE_AUTO + set_process(true) + +func _out_mouse() -> void: + horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_SHOW_NEVER + vertical_scroll_mode = ScrollContainer.SCROLL_MODE_SHOW_NEVER + set_process(false) diff --git a/addons/_Godot-IDE_/plugins/fancy_filters_script/filters_container.gd.uid b/addons/_Godot-IDE_/plugins/fancy_filters_script/filters_container.gd.uid new file mode 100644 index 0000000..c325a65 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_filters_script/filters_container.gd.uid @@ -0,0 +1 @@ +uid://dpkvcqsih4i8w diff --git a/addons/_Godot-IDE_/plugins/fancy_filters_script/line_edit.gd b/addons/_Godot-IDE_/plugins/fancy_filters_script/line_edit.gd new file mode 100644 index 0000000..3786f22 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_filters_script/line_edit.gd @@ -0,0 +1,85 @@ +@tool +extends LineEdit +# ============================================================================= +# Author: Twister +# Fancy Filter Script +# +# Addon for Godot +# ============================================================================= + + +@export var tree : Tree = null + + +func _enter_tree() -> void: + if !is_in_group(&"UPDATE_ON_SAVE"): + add_to_group(&"UPDATE_ON_SAVE") + +func _exit_tree() -> void: + if is_in_group(&"UPDATE_ON_SAVE"): + remove_from_group(&"UPDATE_ON_SAVE") + +func _process(_delta: float) -> void: + set_process(false) + if text.is_empty(): + return + sxrch.call_deferred(text) + +func update() -> void: + set_process(true) + +func _ready() -> void: + set_process(false) + text_changed.connect(sxrch) + +func reset() -> void: + if tree: + var root : TreeItem = tree.get_root() + if !root: + return + _reset(root) + +func _reset(root : TreeItem) -> void: + root.visible = true + for c : TreeItem in root.get_children(): + _reset(c) + +func sxrch(txt : String) -> void: + reset() + if txt.is_empty(): + return + if tree: + var root : TreeItem = tree.get_root() + if !root: + return + var rgx0 : RegEx = RegEx.create_from_string("(?i)\\b{0}\\b".format([txt])) + var rgx1 : RegEx = RegEx.create_from_string("(?i).*{0}.*".format([txt])) + var d0 : Array[TreeItem] = [] + var d1 : Array[TreeItem] = [] + + for x : RegEx in [rgx0, rgx1]: + if !is_instance_valid(x) or !x.is_valid(): + return + + _sxrch(root, rgx0, rgx1, d0, d1) + root.visible = true + + for t : TreeItem in d0: + _visible(t) + for t : TreeItem in d1: + _visible(t) + +func _visible(root : TreeItem) -> void: + if root: + root.visible = true + _visible(root.get_parent()) + +func _sxrch(root : TreeItem, rgx0 : RegEx, rgx1 : RegEx, d0 : Array[TreeItem], d1 : Array[TreeItem]) -> void: + var txt : String = root.get_text(0) + root.visible = false + if rgx0.search(txt) != null: + d0.append(root) + elif d0.size() == 0 and rgx1.search(txt) != null: + d1.append(root) + for x : TreeItem in root.get_children(): + _sxrch(x, rgx0, rgx1, d0, d1) diff --git a/addons/_Godot-IDE_/plugins/fancy_filters_script/line_edit.gd.uid b/addons/_Godot-IDE_/plugins/fancy_filters_script/line_edit.gd.uid new file mode 100644 index 0000000..1b2b21f --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_filters_script/line_edit.gd.uid @@ -0,0 +1 @@ +uid://bbbdyhh8lhw4a diff --git a/addons/_Godot-IDE_/plugins/fancy_filters_script/plugin.cfg b/addons/_Godot-IDE_/plugins/fancy_filters_script/plugin.cfg new file mode 100644 index 0000000..5982422 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_filters_script/plugin.cfg @@ -0,0 +1,8 @@ +[plugin] + +name="Fance Editor Filters" +description="Tool Addon for godot 4." +author="Twister" +version="1.1.5" +github="https://github.com/CodeNameTwister" +script="plugin.gd" diff --git a/addons/_Godot-IDE_/plugins/fancy_filters_script/plugin.gd b/addons/_Godot-IDE_/plugins/fancy_filters_script/plugin.gd new file mode 100644 index 0000000..6c7e8ee --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_filters_script/plugin.gd @@ -0,0 +1,272 @@ +@tool +extends EditorPlugin +# ============================================================================= +# Author: Twister +# Fancy Filter Script +# +# Addon for Godot +# ============================================================================= + +var TAB : PackedScene = preload("res://addons/_Godot-IDE_/plugins/fancy_filters_script/filter_scene.tscn") + +var _parent : Control = null +var _container : Control = null +var _script_info : Control = null +var _placeholder : Control = null + +var _id_show_hide_tool : int = -1 +var _id_toggle_position_tool : int = -1 +var _id_switch_panels : int = -1 + +var _c_input_show_hide : InputEventKey = null +var _c_input_switch_panels : InputEventKey = null + +var _as_separate_container : bool = false + +var _input_defined : bool = false + +func _on_changes() -> void: + var settings : EditorSettings = EditorInterface.get_editor_settings() + if settings: + for x : String in settings.get_changed_settings(): + if "separate_container_list" in x: + var value : Variant = IDE.get_config("fancy_filters_script", "separate_container_list") + if value is bool and value != _as_separate_container: + _as_separate_container = value + _exit_tree() + _enter_tree() + break + +func _init() -> void: + var input0 : Variant = IDE.get_config("fancy_filters_script", "show_hide") + var input1 : Variant = IDE.get_config("fancy_filters_script", "switch_panels") + var as_separate_container : Variant = IDE.get_config("fancy_filters_script", "separate_container_list") + + var settings : EditorSettings = EditorInterface.get_editor_settings() + if settings: + # 0.5.1 + if settings.has_setting("plugin/godot_ide/fancy_filter_script/script_list_and_filter_to_right"): + settings.set_setting("plugin/godot_ide/fancy_filters_script/script_list_and_filter_to_right", settings.get_setting("plugin/godot_ide/fancy_filter_script/script_list_and_filter_to_right")) + settings.set_setting("plugin/godot_ide/fancy_filter_script/script_list_and_filter_to_right", null) + + if !settings.settings_changed.is_connected(_on_changes): + settings.settings_changed.connect(_on_changes) + + if as_separate_container is bool: + _as_separate_container = _as_separate_container + else: + IDE.set_config("fancy_filters_script", "separate_container_list", _as_separate_container) + + if input0 is InputEventKey: + _c_input_show_hide = input0 + else: + _c_input_show_hide = InputEventKey.new() + _c_input_show_hide.pressed = true + _c_input_show_hide.ctrl_pressed = true + _c_input_show_hide.keycode = KEY_T + IDE.set_config("fancy_filters_script", "show_hide", _c_input_show_hide) + + + if input1 is InputEventKey: + _c_input_switch_panels = input1 + else: + _c_input_switch_panels = InputEventKey.new() + _c_input_switch_panels.pressed = true + _c_input_switch_panels.ctrl_pressed = true + _c_input_switch_panels.keycode = KEY_G + IDE.set_config("fancy_filters_script", "switch_panels", _c_input_switch_panels) + +func _get_traduce(msg : String) -> String: + return msg + +func _on_pop_pressed(index : int) -> void: + if index > -1: + if index == _id_show_hide_tool: + _container.visible = !_container.visible + elif index == _id_toggle_position_tool: + toggle_position() + elif index == _id_switch_panels: + if !_script_info.visible: + var tab : Variant = _script_info.get_parent() + if tab is TabContainer: + tab.current_tab = _script_info.get_index() + else: + var script_list : Control = IDE.get_script_list_container() + if is_instance_valid(script_list):# + var tab : Variant = script_list.get_parent() + if tab is TabContainer: + tab.current_tab = script_list.get_index() + +func _apply_changes() -> void: + if _container: + if _container.has_method(&"force_update"): + _container.call_deferred(&"force_update") + get_tree().call_group(&"UPDATE_ON_SAVE", &"update") + +func _enter_tree() -> void: + var container : VSplitContainer = IDE.get_script_list_container() + if container: + var variant : Variant = IDE.get_config("fancy_filters_script", "script_list_and_filter_to_right") + var expected_index : int = 0 + if variant is bool: + if variant == true: + expected_index = 1 + + container.name = "Script List" + _container = TAB.instantiate() + + if _container.get_child_count() > 0: + _script_info = _container.get_child(0) + + var parent : Control = container.get_parent() + _parent = parent + if !_as_separate_container: + var x : int = container.get_child_count() + if x > 1: + var cntl : Node = container.get_child(x - 1) + if cntl is Control: + if _placeholder == null: + _placeholder = Control.new() + _placeholder.visible = false + cntl.reparent(_placeholder) + + container.add_child(_container) + container.move_child(_container, 0) + container.split_offset = 100 + container.clamp_split_offset() + else: + container.add_child(_container) + else: + parent.add_child(_container) + container.reparent(_container) + + toggle_position() + + var cnt : Control = _container + if !_as_separate_container: + cnt = _container.get_parent() + + if cnt.get_index() != expected_index: + toggle_position() + + var menu : MenuButton = IDE.get_menu_button() + if is_instance_valid(menu): + if _input_defined: + return + + _input_defined = true + + var pop : PopupMenu = menu.get_popup() + var total : int = pop.item_count + var msg : String = _get_traduce("Show/Hide Scripts and Filters Panel") + + if !pop.index_pressed.is_connected(_on_pop_pressed): + pop.index_pressed.connect(_on_pop_pressed) + + _add_input(pop, msg, _c_input_show_hide) + _id_show_hide_tool = total + + total = pop.item_count + msg = _get_traduce("Toggle Script Info/Script List Panel (Only if the separated option enabled)") + _add_input(pop, msg, _c_input_switch_panels) + _id_switch_panels = total + + total = pop.item_count + msg = _get_traduce("Toggle Position Script and Filters Panel") + pop.add_item(msg, -1) #, KEY_MASK_CTRL | KEY_NOT_DEFINED_YET + _id_toggle_position_tool =total + +func _add_input(pop : PopupMenu, msg : String, input : InputEventKey) -> void: + if null != input: + if input.ctrl_pressed and input.alt_pressed: + pop.add_item(msg, -1, KEY_MASK_CTRL | KEY_MASK_ALT | input.keycode) + elif input.ctrl_pressed: + pop.add_item(msg, -1, KEY_MASK_CTRL | input.keycode) + elif input.alt_pressed: + pop.add_item(msg, -1, KEY_MASK_ALT | input.keycode) + else: + pop.add_item(msg, -1, input.keycode) + else: + pop.add_item(msg, -1, input.keycode) #, KEY_MASK_CTRL | KEY_NOT_DEFINED_YET) #, KEY_MASK_CTRL | KEY_NOT_DEFINED_YET + +func _ready() -> void: + if !Engine.get_main_loop().root.is_node_ready(): + await Engine.get_main_loop().root.ready + for __ : int in range(30): + var scene : SceneTree = get_tree() + if !is_instance_valid(scene): + return + await scene.process_frame + +func _input(event: InputEvent) -> void: + if event.is_pressed() and event.is_match(_c_input_switch_panels): + _on_pop_pressed(_id_switch_panels) + +func toggle_position() -> void: + var container : Control = _container + if container: + if !_as_separate_container: + container = container.get_parent() + + if null == container: + return + + var parent : Control = container.get_parent() + + if parent is HSplitContainer and parent.get_child_count() > 1: + if container.get_index() != 0: + var size : float = (parent.get_child(0) as Control).size.x + parent.move_child(container, 0) + parent.split_offset = -size + parent.clamp_split_offset.call_deferred() + + var settings : EditorSettings = EditorInterface.get_editor_settings() + if is_instance_valid(settings): + settings.set_setting("plugin/godot_ide/fancy_filters_script/script_list_and_filter_to_right", false) + else: + var size : float = (parent.get_child(1) as Control).size.x + parent.move_child(container, parent.get_child_count() - 1) + parent.split_offset = size + parent.clamp_split_offset.call_deferred() + + var settings : EditorSettings = EditorInterface.get_editor_settings() + if is_instance_valid(settings): + settings.set_setting("plugin/godot_ide/fancy_filters_script/script_list_and_filter_to_right", true) + +func _exit_tree() -> void: + var container : VSplitContainer = IDE.get_script_list_container() + + if is_instance_valid(_container) and _container.is_inside_tree(): + IDE.set_config("fancy_filters_script", "script_list_and_filter_to_right", _container.get_index() > 0) + + if container: + var current_parent : Node = container.get_parent() + + if _placeholder: + for x : Node in _placeholder.get_children(): + x.reparent(container) + _placeholder.queue_free() + _placeholder = null + + if current_parent != _parent: + if current_parent == null: + _parent.add_child(container) + else: + container.reparent(_parent) + for x : Node in container.get_children(): + if x is Control: + x.visible = true + if is_instance_valid(_container): + _container.queue_free() + _container = null + container.visible = true + + var parent : Control = container.get_parent() + if parent is HSplitContainer: + if container.get_index() != 0: + var size : float = (parent.get_child(1) as Control).size.x + parent.move_child(container, 0) + parent.split_offset = -size + parent.clamp_split_offset.call_deferred() + + #TODO: Remove new menu buttons diff --git a/addons/_Godot-IDE_/plugins/fancy_filters_script/plugin.gd.uid b/addons/_Godot-IDE_/plugins/fancy_filters_script/plugin.gd.uid new file mode 100644 index 0000000..69a7f23 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_filters_script/plugin.gd.uid @@ -0,0 +1 @@ +uid://bh2804ipay0ks diff --git a/addons/_Godot-IDE_/plugins/fancy_filters_script/pop_tree.gd b/addons/_Godot-IDE_/plugins/fancy_filters_script/pop_tree.gd new file mode 100644 index 0000000..594580c --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_filters_script/pop_tree.gd @@ -0,0 +1,49 @@ +@tool +extends Popup +# ============================================================================= +# Author: Twister +# Fancy Filter Script +# +# Addon for Godot +# ============================================================================= + + +@export var override_copy_button : Button + +var callback : Callable + +func _ready() -> void: + var control : Control = EditorInterface.get_base_control() + if !control: + return + get_child(0). add_theme_stylebox_override(&"panel", control.get_theme_stylebox(&"panel", &"")) + + +func enable_copy_override(e : bool) -> void: + override_copy_button.disabled = !e + +func override_copy() -> void: + if callback.is_valid(): + callback.call(&"override_copy") + close() + +func copy() -> void: + if callback.is_valid(): + callback.call(&"copy") + close() + +func close() -> void: + hide() + queue_free() + +func goto() -> void: + if callback.is_valid(): + callback.call(&"goto") + + +func _on_popup_hide() -> void: + close() + + +func _on_close_requested() -> void: + close() diff --git a/addons/_Godot-IDE_/plugins/fancy_filters_script/pop_tree.gd.uid b/addons/_Godot-IDE_/plugins/fancy_filters_script/pop_tree.gd.uid new file mode 100644 index 0000000..4602b5b --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_filters_script/pop_tree.gd.uid @@ -0,0 +1 @@ +uid://cmcd05m1t5hwr diff --git a/addons/_Godot-IDE_/plugins/fancy_filters_script/pop_tree.tscn b/addons/_Godot-IDE_/plugins/fancy_filters_script/pop_tree.tscn new file mode 100644 index 0000000..42d4266 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_filters_script/pop_tree.tscn @@ -0,0 +1,76 @@ +[gd_scene load_steps=4 format=3 uid="uid://d1v4xxafti6nw"] + +[ext_resource type="Script" uid="uid://cmcd05m1t5hwr" path="res://addons/_Godot-IDE_/plugins/fancy_filters_script/pop_tree.gd" id="1_x40uf"] +[ext_resource type="Script" uid="uid://b1v225muollg5" path="res://addons/_Godot-IDE_/plugins/fancy_filters_script/button.gd" id="2_l7727"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_l7727"] +content_margin_left = 5.0 +content_margin_top = 5.0 +content_margin_right = 5.0 +content_margin_bottom = 5.0 +bg_color = Color(0.115499996, 0.132, 0.15949999, 1) +corner_detail = 1 +anti_aliasing = false + +[node name="PopTree" type="Popup" node_paths=PackedStringArray("override_copy_button")] +oversampling_override = 1.0 +title = "Member Selected" +position = Vector2i(496, 231) +size = Vector2i(161, 189) +visible = true +content_scale_aspect = 4 +script = ExtResource("1_x40uf") +override_copy_button = NodePath("PanelContainer/MarginContainer/VBoxContainer/override_copy") + +[node name="PanelContainer" type="PanelContainer" parent="."] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_l7727") + +[node name="MarginContainer" type="MarginContainer" parent="PanelContainer"] +layout_mode = 2 +theme_override_constants/margin_left = 4 +theme_override_constants/margin_top = 4 +theme_override_constants/margin_right = 4 +theme_override_constants/margin_bottom = 4 + +[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/MarginContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +text = "Select Option" +horizontal_alignment = 1 + +[node name="HSeparator" type="HSeparator" parent="PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 + +[node name="copy" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 8 +text = "Copy" +script = ExtResource("2_l7727") + +[node name="override_copy" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 8 +text = "Copy for override" +script = ExtResource("2_l7727") + +[node name="goto" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 8 +text = "Go to member" +script = ExtResource("2_l7727") + +[node name="close" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 10 +text = "Close" +script = ExtResource("2_l7727") + +[connection signal="close_requested" from="." to="." method="_on_close_requested"] +[connection signal="popup_hide" from="." to="." method="_on_popup_hide"] diff --git a/addons/_Godot-IDE_/plugins/fancy_filters_script/script_info.gd b/addons/_Godot-IDE_/plugins/fancy_filters_script/script_info.gd new file mode 100644 index 0000000..1ff9e93 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_filters_script/script_info.gd @@ -0,0 +1,1149 @@ +@tool +extends Control +# ============================================================================= +# Author: Twister +# Fancy Filter Script +# +# Addon for Godot +# ============================================================================= + +const PUBLIC_ICON : Texture2D = preload("res://addons/_Godot-IDE_/shared_resources/func_public.svg") +const PRIVATE_ICON : Texture2D = preload("res://addons/_Godot-IDE_/shared_resources/func_private.svg") +const PROTECTED_ICON : Texture2D = preload("res://addons/_Godot-IDE_/shared_resources/func_virtual.svg") +const STATIC_ICON : Texture2D = preload("res://addons/_Godot-IDE_/shared_resources/static.svg") +const CONST_ICON : Texture2D = preload("res://addons/_Godot-IDE_/shared_resources/static.svg") +const EXPORT_ICON : Texture2D = preload("res://addons/_Godot-IDE_/shared_resources/MemberAnnotation.svg") +const OVERRIDED_ICON : Texture2D = preload("res://addons/_Godot-IDE_/shared_resources/MethodOverride.svg") +const CHECKED_ICON : Texture2D = preload("res://addons/_Godot-IDE_/shared_resources/check.svg") + +const SCRIPT_TOOL_ICON : Texture2D = preload("res://addons/_Godot-IDE_/shared_resources/Tools.svg") +const SCRIPT_ICON : Texture2D = preload("res://addons/_Godot-IDE_/shared_resources/Script.svg") +const SCRIPT_EXTEND_ICON : Texture2D = preload("res://addons/_Godot-IDE_/shared_resources/ScriptExtend.svg") +const SCRIPT_ABSTRACT_ICON : Texture2D = SCRIPT_ICON +const SCRIPT_NATIVE_ICON : Texture2D = preload("res://addons/_Godot-IDE_/shared_resources/InterfaceScript.svg") + +const MEMBER_ANNOTATION_ICON : Texture2D = preload("res://addons/_Godot-IDE_/shared_resources/MemberAnnotation.svg") +const MEMBER_CONSTANT_ICON : Texture2D = preload("res://addons/_Godot-IDE_/shared_resources/MemberConstant.svg") +#const MEMBER_CONSTRUCTOR_ICON : Texture2D = preload("res://addons/_Godot-IDE_/shared_resources/MemberConstructor.svg") +const MEMBER_METHOD_ICON : Texture2D = preload("res://addons/_Godot-IDE_/shared_resources/MemberMethod.svg") +#const MEMBER_OPERATOR_ICON : Texture2D = preload("res://addons/_Godot-IDE_/shared_resources/MemberOperator.svg") +const MEMBER_PROPERTY_ICON : Texture2D = preload("res://addons/_Godot-IDE_/shared_resources/MemberProperty.svg") +const MEMBER_SIGNAL_ICON : Texture2D = preload("res://addons/_Godot-IDE_/shared_resources/MemberSignal.svg") +const MEMBER_OVERRIDE_ICON : Texture2D = preload("res://addons/_Godot-IDE_/shared_resources/MethodOverride.svg") + +enum SORT_NAME_TYPE{ + NONE = 0, + ORDER_NAME_NORMAL = 1, + ORDER_NAME_INVERT = 2#, + #ORDER_ACCESSIBILITY_NORMAL, + #ORDER_ACCESSIBILITY_INVERT +} + +@export var button_container : Control = null +@export var tree_container : Tree = null + +var DOTS_ICON : Texture2D = null + +#region CONFIG +var use_colors_in_tittles : bool = false +var use_dots_as_item_icons : bool = false +var use_background_color_in_script_info : bool = false + +var show_properties : bool = true +var show_signals : bool = true +var show_constants : bool = true +var show_parent_class : bool = true +var show_native_class : bool = false +var show_functions : bool = true +var show_inheritance : bool = true + +var flat_mode : bool = false + +var show_properties_color : Color = Color("bce0ff") +var show_signals_color : Color = Color("e5d1ff") +var show_constants_color : Color = Color("00ffff") +var show_parent_class_color : Color = Color("76cfb5") +var show_native_class_color : Color = Color("76cfb5") +var show_function_color : Color = Color("66e6ff") + +var properties_color_item : Color = Color("bce0ff") +var signals_color_item : Color = Color("e5d1ff") +var constants_color_item : Color = Color("64ffff") +#var parent_class_color_item : Color = show_native_class_color +#var native_class_color_item : Color = show_native_class_color +var function_color_item : Color = Color("66e6ff") +var inheritance_color_item : Color = Color("76cfb5") + + +#var accessibility_order_by : Array[int] = [0,1,2,3,4,5] +var members_order_by : Array[int] = [0,1,2,3] +var name_order_by : SORT_NAME_TYPE = SORT_NAME_TYPE.NONE +#endregion + +var _pop : Popup = null + +var _buffer : Dictionary = {} +var _last : Variant = null + +#var accessibility : AccesibilityOrder = null + +#func _init() -> void: + #accessibility = AccesibilityOrder.new(accessibility_order_by.size()) + +func _is_in_change(plugin : String, item : String, array : PackedStringArray) -> bool: + item = plugin.path_join(item) + for x : String in array: + if x.ends_with(item): + return true + return false + +func _setup(changes : PackedStringArray = []) -> void: + var PLUGIN : String = "fancy_filters_script" + var dirty : bool = false + + for x : String in [ + "show_properties" + ,"show_signals" + ,"show_constants" + ,"show_parent_class" + ,"show_native_class" + ,"show_functions" + ,"show_inheritance" + ,"use_colors_in_tittles" + ,"use_dots_as_item_icons" + , "use_background_color_in_script_info" + ,"show_properties_color" + ,"show_signals_color" + ,"show_constants_color" + #,"show_parent_class_color" + #,"show_native_class_color" + ,"show_function_color" + ,"properties_color_item" + ,"signals_color_item" + ,"constants_color_item" + #,"parent_class_color_item" + #,"native_class_color_item" + ,"function_color_item" + ,"inheritance_color_item" + #,"accessibility_order_by" + ,"members_order_by" + ,"name_order_by" + ,"flat_mode" + ]: + if changes.size() == 0 or _is_in_change(PLUGIN, x, changes): + var value : Variant = get(x) + if value != null: + var current : Variant = IDE.get_config(PLUGIN, x) + if typeof(current) == typeof(value): + set(x, current) + dirty = true + else: + IDE.set_config(PLUGIN, x, value) + else: + push_warning("Its broke! > ", x) + + if use_dots_as_item_icons: + if DOTS_ICON == null: + DOTS_ICON = ResourceLoader.load("res://addons/_Godot-IDE_/shared_resources/dot.svg") + else: + DOTS_ICON = null + + if changes.size() > 0 and dirty: + propagate_call(&"update_settings") + force_update() + +func _on_settings_changed() -> void: + var settings : EditorSettings = EditorInterface.get_editor_settings() + if settings: + var changes : PackedStringArray = settings.get_changed_settings() + _setup(changes) + +func _enter_tree() -> void: + _setup() + + var editor : ScriptEditor = EditorInterface.get_script_editor() + if editor: + if !editor.editor_script_changed.is_connected(_on_change_script): + editor.editor_script_changed.connect(_on_change_script) + + var settings : EditorSettings = EditorInterface.get_editor_settings() + if settings: + if !settings.settings_changed.is_connected(_on_settings_changed): + settings.settings_changed.connect(_on_settings_changed) + + +func _exit_tree() -> void: + var editor : ScriptEditor = EditorInterface.get_script_editor() + if editor: + if editor.editor_script_changed.is_connected(_on_change_script): + editor.editor_script_changed.disconnect(_on_change_script) + + var settings : EditorSettings = EditorInterface.get_editor_settings() + if settings: + if settings.settings_changed.is_connected(_on_settings_changed): + settings.settings_changed.disconnect(_on_settings_changed) + +func enable_filter(filter_name : StringName, value : bool) -> void: + if filter_name == &"show_all": + var buttons : Array[Node] = button_container.get_children() + if buttons[0] is Button: + var val : bool = buttons[0].button_pressed + for node : Node in buttons: + if node is Button: + node.button_pressed = val + if get(node.name) != null: + set(node.name, value) + if node.has_method(&"visual"): + node.call(&"visual") + else: + if get(filter_name) != null: + set(filter_name, value) + var buttons : Array[Node] = button_container.get_children() + var all : Button = buttons[0] + all.button_pressed = true + for node : Node in buttons: + if node is Button: + if node.button_pressed == false and node != all: + all.button_pressed = false + break + if all.has_method(&"visual"): + all.call(&"visual") + force_update() + +func _on_collapsed(item : TreeItem) -> void: + var meta : Variant = item.get_metadata(0) + if meta is String: + _buffer[meta] = item.collapsed + +func _process(_delta: float) -> void: + set_process(false) + + var editor : ScriptEditor = EditorInterface.get_script_editor() + var sc : Script = _last + _last = null + if editor: + var nsc : Script = editor.get_current_script() + if nsc: + sc = nsc + _on_change_script(sc) + +func force_update() -> void: + set_process(true) + +func _on_activate() -> void: + if tree_container: + if is_instance_valid(_last): + var current : Script = _last + var item : TreeItem = tree_container.get_selected() + if !item: + return + var symbol_name : String = item.get_text(1).strip_edges().split(" ", false, 1)[0] + while true: + var st : String = current.resource_path + if !FileAccess.file_exists(st): + return + + var script_content : String = FileAccess.get_file_as_string(st) + var lines : PackedStringArray = script_content.split("\n", true) + var line_number : int = -1 + + var pattern : RegEx = RegEx.create_from_string("[\\s]*var[\\n\\t\\s]+\\b" + symbol_name + "\\b.*|\\s*const[\\n\\t\\s]+\\b" + symbol_name + "\\b.*|\\s*func[\\n\\t\\s]+\\b" + symbol_name + "|\\s*signal[\\n\\t\\s]+\\b" + symbol_name) + if is_instance_valid(pattern) and pattern.is_valid(): + for x : int in range(lines.size()): + var line : String = lines[x] + if pattern.search(line): + line_number = x + break + + if line_number > -1: + var sce: ScriptEditor = EditorInterface.get_script_editor() + if !sce: + return + if sce.get_current_script() != current: + EditorInterface.edit_script(current, line_number, 0, true) + sce.goto_line(line_number) + return + var base : Script = current.get_base_script() + if base != null: + current = base + continue + break + var type : StringName = current.get_instance_base_type() + while !type.is_empty(): + if ClassDB.class_exists(type): + var symbol : String = item.get_tooltip_text(0) + var prefx : String = "" + if symbol.is_empty(): + symbol = item.get_tooltip_text(1) + if type == "GraphNode": + prefx = "class_theme_item" + if symbol.begins_with("@"): + prefx = "class_annotation" + elif ClassDB.class_has_signal(type, symbol_name): + prefx = "class_signal" + elif ClassDB.class_has_enum(type, symbol_name, true): + prefx = "class_constant" + elif ClassDB.class_has_integer_constant(type, symbol_name): + prefx = "class_constant" + else: + var list : Array[Dictionary] = ClassDB.class_get_property_list(type, true) + for x : Dictionary in list: + if x.name == symbol_name: + prefx = "class_property" + break + if prefx.is_empty(): + list = ClassDB.class_get_method_list(type, true) + for x : Dictionary in list: + if x.name == symbol_name: + prefx = "class_method" + break + if !prefx.is_empty(): + var path : String = "{0}:{1}:{2}".format([prefx, type, symbol_name]) + EditorInterface.get_script_editor().goto_help(path) + return + type = ClassDB.get_parent_class(type) + continue + break + +func _copy(fnc : String,data : String, type : int) -> void: + if type == 1: + data = (data.trim_prefix("func ").split(")", false, 1)[0] + ")").replace(" : ", "_") + elif type == 2: + var packed : PackedStringArray = data.trim_prefix("func ").split("(", false, 1) + data = packed[0] + ".emit(" + data += (packed[1].split(")", true, 1)[0] + ")").replace(" : ", "_") + elif type == 3: + data = fnc + else: + var packed : PackedStringArray = data.split("\n", false, 0) + if packed.size() > 1: + data = str(packed[0], " ", packed[packed.size() - 1].strip_edges()) + DisplayServer.clipboard_set(data) + print("Copied in clipboard: [", fnc, "] use ctrl + v for paste!") + +func _on_pop_selection(option : StringName, item : TreeItem) -> void: + if is_instance_valid(item): + var parent : TreeItem = item.get_parent() + if parent: + if option == &"goto": + tree_container.item_activated.emit() + elif option == &"copy" or option == &"override_copy": + var icon : Texture2D = parent.get_icon(0) + if icon == null: + icon = item.get_icon(0) + if !is_instance_valid(icon): + return + var itype : int = 3 + if icon == MEMBER_METHOD_ICON: + if option == &"override_copy": + itype = 0 + else: + itype = 1 + elif icon == MEMBER_SIGNAL_ICON: + itype = 2 + var editor : ScriptEditor = EditorInterface.get_script_editor() + if editor: + var sc : Script = editor.get_current_script() + if sc: + var func_ : StringName = item.get_text(1).strip_edges().get_slice(" ", 0) + if itype == 3: + _copy(func_, func_, itype) + return + if itype != 2: + var base : Script = sc + while base != null: + for d : Dictionary in base.get_script_method_list(): + if d.name == func_: + _copy(func_, IDE.get_header_function(d),itype) + return + for d : Dictionary in base.get_method_list(): + if d.name == func_: + _copy(func_, IDE.get_header_function(d),itype) + return + var nbase : Script = base.get_base_script() + if nbase != null: + base = nbase + break + if base != null: + var type : StringName = base.get_instance_base_type() + if ClassDB.class_exists(type): + for d : Dictionary in ClassDB.class_get_method_list(type, false): + if d.name == func_: + _copy(func_, IDE.get_header_function(d),itype) + return + else: + var base : Script = sc + while base != null: + for d : Dictionary in base.get_script_signal_list(): + if d.name == func_: + _copy(func_, IDE.get_header_function(d),itype) + return + for d : Dictionary in base.get_signal_list(): + if d.name == func_: + _copy(func_, IDE.get_header_function(d),itype) + return + var nbase : Script = base.get_base_script() + if nbase != null: + base = nbase + break + if base != null: + var type : StringName = base.get_instance_base_type() + if ClassDB.class_exists(type): + for d : Dictionary in ClassDB.class_get_signal_list(type, false): + if d.name == func_: + _copy(func_, IDE.get_header_function(d),itype) + return + + +func _on_mouse(_mouse_position: Vector2, mouse_button_index: int) -> void: + if mouse_button_index == MOUSE_BUTTON_RIGHT: + var editor : ScriptEditor = EditorInterface.get_script_editor() + if editor: + var sc : Script = editor.get_current_script() + if !is_instance_valid(sc): + print("[INFO] The current editor does not have script focus!") + return + + var item : TreeItem = tree_container.get_selected() + if item: + var parent : TreeItem = item.get_parent() + if parent: + var icon : Texture2D = parent.get_icon(0) + if icon == null: + icon = item.get_icon(0) + if !is_instance_valid(icon): + return + for x : Texture2D in [ + MEMBER_CONSTANT_ICON, + MEMBER_METHOD_ICON, + MEMBER_SIGNAL_ICON, + MEMBER_PROPERTY_ICON + ]: + if icon == x: + var is_first : bool = true + parent = parent.get_parent() + if parent and parent.get_index() > 0: + is_first = false + if !is_instance_valid(_pop): + var res : PackedScene = ResourceLoader.load("res://addons/_Godot-IDE_/plugins/fancy_filters_script/pop_tree.tscn") + _pop = res.instantiate() + add_child(_pop) + _pop.callback = _on_pop_selection.bind(item) + _pop.enable_copy_override(MEMBER_METHOD_ICON == icon and (!is_first or flat_mode)) + + var os_name : String = OS.get_name() + match os_name: + "macOS": + var mouse_global : Vector2 = get_global_mouse_position() + var offset : Vector2 = Vector2(10.0, 10.0) #HINT: dot scale: interface/editor/display_scale ## I leave this here, maybe use for a future testing and update. + var popup_rect : Rect2 = Rect2(mouse_global + offset, Vector2.ZERO) + _pop.popup_on_parent(popup_rect) + "iOS": + _pop.popup_centered() + _: + # Others platforms. + _pop.position = get_global_mouse_position() + _pop.popup() + return + + +func _custom_order(s1 : String, s2 : String) -> bool: + for x : int in mini(s1.length(), s2.length()): + var c1 : String = s1[x].to_lower() + var c2 : String = s2[x].to_lower() + if c1 == c2: + continue + return c1 < c2 + return false + +func _order_name(keys : Array) -> Array: + if name_order_by != SORT_NAME_TYPE.NONE: + if name_order_by == SORT_NAME_TYPE.ORDER_NAME_NORMAL: + keys.sort_custom(_custom_order) + elif name_order_by == SORT_NAME_TYPE.ORDER_NAME_INVERT: + keys.sort_custom(_custom_order) + keys.reverse() + return keys + +func _on_change_script(script : Script) -> void: + if _last == script: + return + _last = script + tree_container.clear() + if script == null: + return + var data : Dictionary = IDE.get_script_properties_list(script) + var root : TreeItem = tree_container.create_item() + tree_container.columns = 1#3 + var path : String = script.resource_path + if !path.is_empty(): + root.set_text(0, "[{0}]".format([path.get_file()])) + root.set_tooltip_text(0, path) + else: + root.set_text(0, "Info") + + if _buffer.size() > 40: + _buffer.clear() + + if !tree_container.item_collapsed.is_connected(_on_collapsed): + tree_container.item_collapsed.connect(_on_collapsed) + + if !tree_container.item_activated.is_connected(_on_activate): + tree_container.item_activated.connect(_on_activate) + + if !tree_container.item_mouse_selected.is_connected(_on_mouse): + tree_container.allow_rmb_select = true + tree_container.item_mouse_selected.connect(_on_mouse) + + + var private_methods : String = IDE.PRIVATE_METHODS + var protected_methods : String = IDE.VIRTUAL_METHODS + tree_container.columns = 2 + tree_container.set_column_expand(0, true) + tree_container.set_column_expand(1, true) + tree_container.set_column_custom_minimum_width(0, 0) + tree_container.set_column_clip_content(0, false) + tree_container.set_column_expand_ratio(0, 0) + tree_container.set_column_custom_minimum_width(1, 200) + root.set_expand_right(0, true) + root.set_selectable(0, false) + root.set_expand_right(1, true) + root.set_selectable(1, false) + root.disable_folding = true + + var BASE_COLOR : Color = root.get_custom_color(0) + if BASE_COLOR == Color.BLACK: + BASE_COLOR = Color.WHITE + + var PRIMARY_COLOR : Color = BASE_COLOR.darkened(0.2) + var SECONDARY_COLOR : Color = BASE_COLOR.darkened(0.4) + + var public_icon : Texture2D = PUBLIC_ICON + var private_icon : Texture2D = PRIVATE_ICON + var virtual_icon : Texture2D = PROTECTED_ICON + var public_icon_modulate: Color = Color.WHITE + var private_icon_modulate: Color = Color.WHITE + var virtual_icon_modulate: Color = Color.WHITE + + if use_dots_as_item_icons and null != DOTS_ICON: + public_icon = DOTS_ICON + private_icon = DOTS_ICON + virtual_icon = DOTS_ICON + public_icon_modulate = Color.GREEN + private_icon_modulate = Color.YELLOW + virtual_icon_modulate = Color.REBECCA_PURPLE + + var index : int = -1 + var src : String = script.source_code + var track_override : Dictionary[StringName, bool] = {} + + if flat_mode: + var values : Dictionary = {} + for sc : Dictionary in data.values(): + index += 1 + if index > 0: + var native : bool = sc["path"] == "NativeScript" + if native and !show_native_class: + continue + elif !native and !show_parent_class: + continue + + + var sc_data : Dictionary = {} + for order : int in members_order_by: + if order == 0 and show_properties: + if !values.has(order): + values[order] = [] + sc_data = sc["properties"] + if sc_data.size() > 0: + values[order].append(sc_data) + + + elif order == 1 and show_functions: + sc_data = sc["functions"] + if sc_data.size() > 0: + if !values.has(order): + values[order] = [] + values[order].append(sc_data) + + elif order == 2 and show_signals: + sc_data = sc["signals"] + if sc_data.size() > 0: + if !values.has(order): + values[order] = [] + values[order].append(sc_data) + + + elif order == 3 and show_constants: + sc_data = sc["constants"] + if sc_data.size() > 0: + if !values.has(order): + values[order] = [] + values[order].append(sc_data) + + + for order : int in values.keys(): + var tree_item : TreeItem = null + var meta : String = "" + tree_item = root + for sc_data : Dictionary in values[order]: + if order == 0: + var mthds : TreeItem = null + var item_color : Color = SECONDARY_COLOR + var override_item_color : Color = inheritance_color_item + + if properties_color_item != Color.WHITE: + item_color = properties_color_item + + mthds = tree_item + var TRANSPARENT : Color = show_properties_color + + for fnc : StringName in _order_name(sc_data.keys()): + var packed : PackedStringArray = sc_data[fnc].split("||") + var override : bool = false + if "overrided" in packed: + if !show_inheritance: + continue + override = true + var _item : TreeItem = mthds.create_child() + var text : String = " {0} : {1}".format([packed[0], packed[1]]) + _item.set_text(1, text) + _item.set_icon(0, MEMBER_PROPERTY_ICON) + _item.set_icon_modulate(0, TRANSPARENT) + _item.set_selectable(0, false) + + if "export" in packed: + _item.set_icon(1, EXPORT_ICON) + _item.set_tooltip_text(1, str("@export var ", text)) + #accessibility.add(0, fnc) + elif "static" in packed: + _item.set_icon(1, STATIC_ICON) + _item.set_tooltip_text(1, str("static var ", text)) + #accessibility.add(1, fnc) + elif "const" in packed: + _item.set_icon(1, CONST_ICON) + _item.set_tooltip_text(1, str("const ", text)) + #accessibility.add(2, fnc) + elif fnc.begins_with(private_methods): + _item.set_icon(1, private_icon) + _item.set_icon_modulate(1, private_icon_modulate) + #accessibility.add(3, fnc) + elif fnc.begins_with(protected_methods): + _item.set_icon(1, virtual_icon) + _item.set_icon_modulate(1, virtual_icon_modulate) + #accessibility.add(4, fnc) + else: + _item.set_icon(1, public_icon) + _item.set_icon_modulate(1, public_icon_modulate) + #accessibility.add(5, fnc) + if override: + #accessibility.add_overrided(fnc) + _item.set_icon_overlay(1, OVERRIDED_ICON) + _item.set_custom_color(1, override_item_color) + else: + _item.set_custom_color(1, item_color) + if use_background_color_in_script_info: + var c : Color = show_properties_color + c.a = 0.05 + _item.set_custom_bg_color(0, c) + _item.set_custom_bg_color(1, c) + + elif order == 1: + var mthds : TreeItem = null + var item_color : Color = SECONDARY_COLOR + var override_item_color : Color = inheritance_color_item + + if function_color_item != Color.WHITE: + item_color = function_color_item + + mthds = tree_item + + var TRANSPARENT : Color = show_function_color + + for fnc : StringName in _order_name(sc_data.keys()): + var packed : PackedStringArray = sc_data[fnc].split("||") + var override : bool = false + if "overrided" in packed: + if index > 0: + if !show_inheritance: + continue + else: + if !show_inheritance: + var rgx : RegEx = RegEx.create_from_string("func[\\s\\t\\n]*\\b{0}[\\s\\t\\n]*\\(".format([fnc])) + if is_instance_valid(rgx) and rgx.is_valid(): + if null == rgx.search(src): + continue + track_override[fnc] = true + override = show_inheritance + + var _item : TreeItem = mthds.create_child() + var text : String = " {0} ( {1} ) -> {2}".format([packed[0], packed[1], packed[2]]) + + _item.set_icon(0, MEMBER_METHOD_ICON) + _item.set_icon_modulate(0, TRANSPARENT) + _item.set_selectable(0, false) + + if "static" in packed: + _item.set_icon(1, STATIC_ICON) + _item.set_tooltip_text(1, str("static var ", text)) + elif "const" in packed: + _item.set_icon(1, CONST_ICON) + _item.set_tooltip_text(1, str("const ", text)) + elif fnc.begins_with(private_methods): + _item.set_icon(1, private_icon) + _item.set_icon_modulate(1, private_icon_modulate) + elif fnc.begins_with(protected_methods): + _item.set_icon(1, virtual_icon) + _item.set_icon_modulate(1, virtual_icon_modulate) + else: + _item.set_icon(1, public_icon) + _item.set_icon_modulate(1, public_icon_modulate) + if override: + _item.set_icon_overlay(1, OVERRIDED_ICON) + _item.set_custom_color(1, override_item_color) + else: + _item.set_custom_color(1, item_color) + if index > 0: + if track_override.has(fnc): + _item.set_icon_overlay(1, CHECKED_ICON) + _item.set_text(1, text) + if use_background_color_in_script_info: + var c : Color = show_function_color + c.a = 0.05 + _item.set_custom_bg_color(0, c) + _item.set_custom_bg_color(1, c) + + elif order == 2: + var mthds : TreeItem = null + var item_color : Color = SECONDARY_COLOR + var override_item_color : Color = inheritance_color_item + + if signals_color_item != Color.WHITE: + item_color = signals_color_item + + mthds = tree_item + + + var TRANSPARENT : Color = show_signals_color + + for fnc : StringName in _order_name(sc_data.keys()): + var packed : PackedStringArray = sc_data[fnc].split("||") + var override : bool = false + if "overrided" in packed: + if !show_inheritance: + continue + override = true + var _item : TreeItem = mthds.create_child() + _item.set_text(1, " {0} ( {1} ) -> {2}".format([packed[0], packed[1], packed[2]])) + + _item.set_icon(0, MEMBER_SIGNAL_ICON) + _item.set_icon_modulate(0, TRANSPARENT) + _item.set_selectable(0, false) + + if override: + _item.set_icon_overlay(1, OVERRIDED_ICON) + _item.set_custom_color(1, override_item_color) + else: + _item.set_custom_color(1, item_color) + if use_background_color_in_script_info: + var c : Color = show_signals_color + c.a = 0.05 + _item.set_custom_bg_color(0, c) + _item.set_custom_bg_color(1, c) + + elif order == 3: + var mthds : TreeItem = null + var item_color : Color = SECONDARY_COLOR + var override_item_color : Color = inheritance_color_item + + if constants_color_item != Color.WHITE: + item_color = constants_color_item + + mthds = tree_item + + var TRANSPARENT : Color = show_constants_color + + for fnc : StringName in _order_name(sc_data.keys()): + var packed : PackedStringArray = sc_data[fnc].split("||") + var override : bool = false + if "overrided" in packed: + if !show_inheritance: + continue + override = true + var _item : TreeItem = mthds.create_child() + _item.set_text(1, " {0} : {1}".format([packed[0], packed[1]])) + + _item.set_icon(0, MEMBER_CONSTANT_ICON) + _item.set_icon_modulate(0, TRANSPARENT) + _item.set_selectable(0, false) + + if override: + _item.set_icon_overlay(1, OVERRIDED_ICON) + _item.set_custom_color(1, override_item_color) + else: + _item.set_custom_color(1, item_color) + if use_background_color_in_script_info: + var c : Color = show_constants_color + c.a = 0.05 + _item.set_custom_bg_color(0, c) + _item.set_custom_bg_color(1, c) + else: + for sc : Dictionary in data.values(): + index += 1 + if index > 0: + var native : bool = sc["path"] == "NativeScript" + if native and !show_native_class: + continue + elif !native and !show_parent_class: + continue + + var tree_item : TreeItem = null + var meta : String = "" + + + tree_item = root.create_child() + meta = str("C", index) + tree_item.set_text(0, str(" ",sc["name"])) + tree_item.set_tooltip_text(1, sc["path"]) + tree_item.set_metadata(0, meta) + tree_item.set_custom_color(0, BASE_COLOR) + tree_item.set_icon_modulate(0, Color.WHITE) + tree_item.set_expand_right(0, true) + #tree_item.set_text_alignment(0, HORIZONTAL_ALIGNMENT_CENTER) + if _buffer.has(meta): + tree_item.collapsed = _buffer[meta] + if sc["tool"]: + tree_item.set_icon(0, SCRIPT_TOOL_ICON) + tree_item.set_icon_modulate(0, Color.DEEP_SKY_BLUE) + if index > 0: + tree_item.set_icon_overlay(0, OVERRIDED_ICON) + elif sc["abstract"]: + tree_item.set_icon(0, SCRIPT_ABSTRACT_ICON) + if index > 0: + tree_item.set_icon_overlay(0, OVERRIDED_ICON) + elif sc["path"] == "NativeScript": + tree_item.set_icon(0, SCRIPT_NATIVE_ICON) + else: + if index > 0: + tree_item.set_icon(0, SCRIPT_EXTEND_ICON) + else: + tree_item.set_icon(0, SCRIPT_ICON) + tree_item.set_selectable(0, false) + tree_item.set_selectable(1, false) + + var sc_data : Dictionary = {} + for order : int in members_order_by: + if order == 0 and show_properties: + sc_data = sc["properties"] + if sc_data.size() > 0: + var mthds : TreeItem = null + var item_color : Color = SECONDARY_COLOR + var override_item_color : Color = inheritance_color_item + + if properties_color_item != Color.WHITE: + item_color = properties_color_item + + mthds = tree_item.create_child() + + mthds.set_text(0, " Properties") + mthds.set_selectable(0, false) + mthds.set_selectable(1, false) + mthds.set_expand_right(0, true) + mthds.set_icon(0, MEMBER_PROPERTY_ICON) + + if use_background_color_in_script_info: + var c : Color = show_properties_color + c.a = 0.15 + mthds.set_custom_bg_color(0, c) + mthds.set_custom_bg_color(1, c) + if use_colors_in_tittles: + mthds.set_custom_color(0, show_properties_color) + else: + mthds.set_custom_color(0, PRIMARY_COLOR) + meta = str("P", index) + mthds.set_metadata(0, meta) + mthds.set_icon_modulate(0, show_properties_color) + if _buffer.has(meta): + mthds.collapsed = _buffer[meta] + else: + mthds.collapsed = true + + var TRANSPARENT : Color = show_properties_color + TRANSPARENT.a = 0.4 + + for fnc : StringName in _order_name(sc_data.keys()): + var packed : PackedStringArray = sc_data[fnc].split("||") + var override : bool = false + if "overrided" in packed: + if !show_inheritance: + continue + override = true + var _item : TreeItem = mthds.create_child() + var text : String = " {0} : {1}".format([packed[0], packed[1]]) + _item.set_text(1, text) + _item.set_icon(0, MEMBER_PROPERTY_ICON) + _item.set_icon_modulate(0, TRANSPARENT) + _item.set_selectable(0, false) + + if "export" in packed: + _item.set_icon(1, EXPORT_ICON) + _item.set_tooltip_text(1, str("@export var ", text)) + #accessibility.add(0, fnc) + elif "static" in packed: + _item.set_icon(1, STATIC_ICON) + _item.set_tooltip_text(1, str("static var ", text)) + #accessibility.add(1, fnc) + elif "const" in packed: + _item.set_icon(1, CONST_ICON) + _item.set_tooltip_text(1, str("const ", text)) + #accessibility.add(2, fnc) + elif fnc.begins_with(private_methods): + _item.set_icon(1, private_icon) + _item.set_icon_modulate(1, private_icon_modulate) + #accessibility.add(3, fnc) + elif fnc.begins_with(protected_methods): + _item.set_icon(1, virtual_icon) + _item.set_icon_modulate(1, virtual_icon_modulate) + #accessibility.add(4, fnc) + else: + _item.set_icon(1, public_icon) + _item.set_icon_modulate(1, public_icon_modulate) + #accessibility.add(5, fnc) + if override: + #accessibility.add_overrided(fnc) + _item.set_icon_overlay(1, OVERRIDED_ICON) + _item.set_custom_color(1, override_item_color) + else: + _item.set_custom_color(1, item_color) + if use_background_color_in_script_info: + var c : Color = show_properties_color + c.a = 0.05 + _item.set_custom_bg_color(0, c) + _item.set_custom_bg_color(1, c) + + elif order == 1 and show_functions: + sc_data = sc["functions"] + if sc_data.size() > 0: + var mthds : TreeItem = null + var item_color : Color = SECONDARY_COLOR + var override_item_color : Color = inheritance_color_item + + if function_color_item != Color.WHITE: + item_color = function_color_item + + mthds = tree_item.create_child() + + mthds.set_text(0, " Methods") + mthds.set_selectable(0, false) + mthds.set_selectable(1, false) + mthds.set_expand_right(0, true) + mthds.set_icon(0, MEMBER_METHOD_ICON) + if use_background_color_in_script_info: + var c : Color = show_function_color + c.a = 0.15 + mthds.set_custom_bg_color(0, c) + mthds.set_custom_bg_color(1, c) + if use_colors_in_tittles: + mthds.set_custom_color(0, show_function_color) + else: + mthds.set_custom_color(0, PRIMARY_COLOR) + meta = str("F", index) + mthds.set_metadata(0, meta) + mthds.set_icon_modulate(0, show_function_color) + if _buffer.has(meta): + mthds.collapsed = _buffer[meta] + else: + mthds.collapsed = true + + var TRANSPARENT : Color = show_function_color + TRANSPARENT.a = 0.4 + + for fnc : StringName in _order_name(sc_data.keys()): + var packed : PackedStringArray = sc_data[fnc].split("||") + var override : bool = false + if "overrided" in packed: + if index > 0: + if !show_inheritance: + continue + else: + if !show_inheritance: + var rgx : RegEx = RegEx.create_from_string("func[\\s\\t\\n]*\\b{0}[\\s\\t\\n]*\\(".format([fnc])) + if is_instance_valid(rgx) and rgx.is_valid(): + if null == rgx.search(src): + continue + track_override[fnc] = true + override = show_inheritance + + var _item : TreeItem = mthds.create_child() + var text : String = " {0} ( {1} ) -> {2}".format([packed[0], packed[1], packed[2]]) + + _item.set_icon(0, MEMBER_METHOD_ICON) + _item.set_icon_modulate(0, TRANSPARENT) + _item.set_selectable(0, false) + + if "static" in packed: + _item.set_icon(1, STATIC_ICON) + _item.set_tooltip_text(1, str("static var ", text)) + elif "const" in packed: + _item.set_icon(1, CONST_ICON) + _item.set_tooltip_text(1, str("const ", text)) + elif fnc.begins_with(private_methods): + _item.set_icon(1, private_icon) + _item.set_icon_modulate(1, private_icon_modulate) + elif fnc.begins_with(protected_methods): + _item.set_icon(1, virtual_icon) + _item.set_icon_modulate(1, virtual_icon_modulate) + else: + _item.set_icon(1, public_icon) + _item.set_icon_modulate(1, public_icon_modulate) + if override: + _item.set_icon_overlay(1, OVERRIDED_ICON) + _item.set_custom_color(1, override_item_color) + else: + _item.set_custom_color(1, item_color) + if index > 0: + if track_override.has(fnc): + _item.set_icon_overlay(1, CHECKED_ICON) + _item.set_text(1, text) + if use_background_color_in_script_info: + var c : Color = show_function_color + c.a = 0.05 + _item.set_custom_bg_color(0, c) + _item.set_custom_bg_color(1, c) + + elif order == 2 and show_signals: + sc_data = sc["signals"] + if sc_data.size() > 0: + var mthds : TreeItem = null + var item_color : Color = SECONDARY_COLOR + var override_item_color : Color = inheritance_color_item + + if signals_color_item != Color.WHITE: + item_color = signals_color_item + + mthds = tree_item.create_child() + + mthds.set_text(0, " Signals") + mthds.set_selectable(0, false) + mthds.set_selectable(1, false) + mthds.set_expand_right(0, true) + mthds.set_icon(0, MEMBER_SIGNAL_ICON) + if use_background_color_in_script_info: + var c : Color = show_signals_color + c.a = 0.15 + mthds.set_custom_bg_color(0, c) + mthds.set_custom_bg_color(1, c) + if use_colors_in_tittles: + mthds.set_custom_color(0, show_signals_color) + else: + mthds.set_custom_color(0, PRIMARY_COLOR) + meta = str("S", index) + mthds.set_metadata(0, meta) + mthds.set_icon_modulate(0, show_signals_color) + if _buffer.has(meta): + mthds.collapsed = _buffer[meta] + else: + mthds.collapsed = true + + var TRANSPARENT : Color = show_signals_color + TRANSPARENT.a = 0.4 + + for fnc : StringName in _order_name(sc_data.keys()): + var packed : PackedStringArray = sc_data[fnc].split("||") + var override : bool = false + if "overrided" in packed: + if !show_inheritance: + continue + override = true + var _item : TreeItem = mthds.create_child() + _item.set_text(1, " {0} ( {1} ) -> {2}".format([packed[0], packed[1], packed[2]])) + + _item.set_icon(0, MEMBER_SIGNAL_ICON) + _item.set_icon_modulate(0, TRANSPARENT) + _item.set_selectable(0, false) + + if override: + _item.set_icon_overlay(1, OVERRIDED_ICON) + _item.set_custom_color(1, override_item_color) + else: + _item.set_custom_color(1, item_color) + if use_background_color_in_script_info: + var c : Color = show_signals_color + c.a = 0.05 + _item.set_custom_bg_color(0, c) + _item.set_custom_bg_color(1, c) + + elif order == 3 and show_constants: + sc_data = sc["constants"] + if sc_data.size() > 0: + var mthds : TreeItem = null + var item_color : Color = SECONDARY_COLOR + var override_item_color : Color = inheritance_color_item + + if constants_color_item != Color.WHITE: + item_color = constants_color_item + + + mthds = tree_item.create_child() + + mthds.set_text(0, " Constant") + mthds.set_selectable(0, false) + mthds.set_selectable(1, false) + mthds.set_expand_right(0, true) + mthds.set_icon(0, MEMBER_CONSTANT_ICON) + if use_background_color_in_script_info: + var c : Color = show_constants_color + c.a = 0.15 + mthds.set_custom_bg_color(0, c) + mthds.set_custom_bg_color(1, c) + if use_colors_in_tittles: + mthds.set_custom_color(0, show_constants_color) + else: + mthds.set_custom_color(0, PRIMARY_COLOR) + meta = str("I", index) + mthds.set_metadata(0, meta) + mthds.set_icon_modulate(0, show_constants_color) + if _buffer.has(meta): + mthds.collapsed = _buffer[meta] + else: + + mthds.collapsed = true + + var TRANSPARENT : Color = show_constants_color + TRANSPARENT.a = 0.4 + + for fnc : StringName in _order_name(sc_data.keys()): + var packed : PackedStringArray = sc_data[fnc].split("||") + var override : bool = false + if "overrided" in packed: + if !show_inheritance: + continue + override = true + var _item : TreeItem = mthds.create_child() + _item.set_text(1, " {0} : {1}".format([packed[0], packed[1]])) + + _item.set_icon(0, MEMBER_CONSTANT_ICON) + _item.set_icon_modulate(0, TRANSPARENT) + _item.set_selectable(0, false) + + if override: + _item.set_icon_overlay(1, OVERRIDED_ICON) + _item.set_custom_color(1, override_item_color) + else: + _item.set_custom_color(1, item_color) + if use_background_color_in_script_info: + var c : Color = show_constants_color + c.a = 0.05 + _item.set_custom_bg_color(0, c) + _item.set_custom_bg_color(1, c) + + +func _ready() -> void: + var editor : ScriptEditor = EditorInterface.get_script_editor() + if editor: + var sc : Script = editor.get_current_script() + if sc: + set_process(false) + _on_change_script(sc) + return + set_process(true) diff --git a/addons/_Godot-IDE_/plugins/fancy_filters_script/script_info.gd.uid b/addons/_Godot-IDE_/plugins/fancy_filters_script/script_info.gd.uid new file mode 100644 index 0000000..2a5fb12 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_filters_script/script_info.gd.uid @@ -0,0 +1 @@ +uid://bwtq1pkujrb1d diff --git a/addons/_Godot-IDE_/plugins/fancy_search_class/gui/button.gd b/addons/_Godot-IDE_/plugins/fancy_search_class/gui/button.gd new file mode 100644 index 0000000..62a2c96 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_search_class/gui/button.gd @@ -0,0 +1,13 @@ +@tool +extends Button +# ============================================================================= +# Author: Twister +# Fancy Search Class +# +# Addon for Godot +# ============================================================================= + + +func _pressed() -> void: + if owner.has_method(name): + owner.call(name) diff --git a/addons/_Godot-IDE_/plugins/fancy_search_class/gui/button.gd.uid b/addons/_Godot-IDE_/plugins/fancy_search_class/gui/button.gd.uid new file mode 100644 index 0000000..60fd8f1 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_search_class/gui/button.gd.uid @@ -0,0 +1 @@ +uid://c6pfvkgkabvt6 diff --git a/addons/_Godot-IDE_/plugins/fancy_search_class/gui/line_edit.gd b/addons/_Godot-IDE_/plugins/fancy_search_class/gui/line_edit.gd new file mode 100644 index 0000000..eaff23b --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_search_class/gui/line_edit.gd @@ -0,0 +1,66 @@ +@tool +extends LineEdit +# ============================================================================= +# Author: Twister +# Fancy Search Class +# +# Addon for Godot +# ============================================================================= + + +@export var tree : Tree = null + +func _ready() -> void: + text_changed.connect(sxrch) + +func reset() -> void: + if tree: + var root : TreeItem = tree.get_root() + if !root: + return + _reset(root) + +func _reset(root : TreeItem) -> void: + root.visible = true + for c : TreeItem in root.get_children(): + _reset(c) + +func sxrch(txt : String) -> void: + reset() + if txt.is_empty(): + return + if tree: + var root : TreeItem = tree.get_root() + if !root: + return + var rgx0 : RegEx = RegEx.create_from_string("(?i)\\b{0}\\b".format([txt])) + var rgx1 : RegEx = RegEx.create_from_string("(?i).*{0}.*".format([txt])) + var d0 : Array[TreeItem] = [] + var d1 : Array[TreeItem] = [] + + for x : RegEx in [rgx0, rgx1]: + if !is_instance_valid(x) or !x.is_valid(): + return + + _sxrch(root, rgx0, rgx1, d0, d1) + root.visible = true + + for t : TreeItem in d0: + _visible(t) + for t : TreeItem in d1: + _visible(t) + +func _visible(root : TreeItem) -> void: + if root: + root.visible = true + _visible(root.get_parent()) + +func _sxrch(root : TreeItem, rgx0 : RegEx, rgx1 : RegEx, d0 : Array[TreeItem], d1 : Array[TreeItem]) -> void: + var txt : String = root.get_text(0) + root.visible = false + if rgx0.search(txt) != null: + d0.append(root) + elif d0.size() == 0 and rgx1.search(txt) != null: + d1.append(root) + for x : TreeItem in root.get_children(): + _sxrch(x, rgx0, rgx1, d0, d1) diff --git a/addons/_Godot-IDE_/plugins/fancy_search_class/gui/line_edit.gd.uid b/addons/_Godot-IDE_/plugins/fancy_search_class/gui/line_edit.gd.uid new file mode 100644 index 0000000..88d8b5e --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_search_class/gui/line_edit.gd.uid @@ -0,0 +1 @@ +uid://blmveofp20cm1 diff --git a/addons/_Godot-IDE_/plugins/fancy_search_class/gui/main.gd b/addons/_Godot-IDE_/plugins/fancy_search_class/gui/main.gd new file mode 100644 index 0000000..f00ac91 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_search_class/gui/main.gd @@ -0,0 +1,383 @@ +@tool +extends Window +# ============================================================================= +# Author: Twister +# Fancy Search Class +# +# Addon for Godot +# ============================================================================= + + +@export var _container : TabContainer = null +@export var _tree : Tree = null +@export var _tree_recents : Tree = null + +#var files : Dictionary[StringName, Dictionary] = {} + +const CUTE_ICON : Texture2D = preload("res://addons/_Godot-IDE_/shared_resources/Script.svg") + +var _first_time : bool = false + +var _recents : PackedStringArray = [] + +var _default_tx : Texture2D = null + +var _collapsed : bool = false + +func _enter_tree() -> void: + _first_time = true + + var screen : Vector2 = DisplayServer.screen_get_size() + var value : Variant = IDE.get_config("fancy_search_class", "size") + if value is Vector2 or value is Vector2i: + screen = value + else: + screen = screen * 0.6 + + IDE.clamp_screen_size(screen, 0.3, 1.0) + + size = screen + +func _ready() -> void: + update() + for x : int in range(1, _container.get_child_count(), 1): + _container.get_child(x).queue_free() + visibility_changed.connect(_on_visible) + _container.tab_changed.connect(_on_change) + _tree.item_activated.connect(_on_activate.bind(_tree)) + _tree_recents.item_activated.connect(_on_activate.bind(_tree_recents)) + + var result : Variant = IDE.get_file_config_value("fancy_search_class", "recents") + if result is PackedStringArray: + _recents = result + + var control : Control = EditorInterface.get_base_control() + if !control: + return + get_child(0). add_theme_stylebox_override(&"panel", control.get_theme_stylebox(&"panel", &"")) + +func _save() -> void: + IDE.set_file_config_value("fancy_search_class", "recents", _recents) + +func _on_visible() -> void: + if visible: + update() + else: + _save() + queue_free() + +func clear() -> void: + _recents.clear() + _tree_recents.clear() + +func _on_activate(tree : Tree) -> void: + if !tree: + return + + var item : TreeItem = tree.get_selected() + + if !item: + return + + var value : Variant = item.get_metadata(0) + if value is String: + if FileAccess.file_exists(value): + EditorInterface.select_file(value) + if ResourceLoader.exists(value): + var res : Resource = ResourceLoader.load(value) + if !(value in _recents): + while _recents.size() > 30: + _recents.remove_at(0) + _recents.append(value) + if res is Resource: + if res is PackedScene: + EditorInterface.open_scene_from_path(value) + elif res is Script: + EditorInterface.edit_script(res) + else: + EditorInterface.edit_resource(res) + hide() + +func _on_change(_tab_changed : int) -> void: + var control : Control = _container.get_current_tab_control() + if control: + _update_tree(control.name) + +func _exit_tree() -> void: + if is_instance_valid(_tree): + _tree.clear() + IDE.set_config("fancy_search_class", "size", size) + +func close() -> void: + hide() + +func get_icon(type : String) -> Texture2D: + var control : Control = EditorInterface.get_base_control() + if !control: + return null + return control.get_theme_icon(type, "EditorIcons") + +func _make_tree(root : TreeItem, key : StringName, dat : Dictionary, buff : Dictionary) -> void: + if buff.has(key): + return + var tree : TreeItem = root.create_child() + buff[key] = tree + tree.set_text(0, key) + for k : StringName in dat.keys(): + var packed : PackedStringArray = dat["class"] + for p : String in packed: + var t : TreeItem = tree.create_child() + t.set_text(0, p) + buff[p] = t + +var pumpking : Pumpking = null + +class Pumpking extends RefCounted: + var cute_name : StringName = "" + var next : Array[Pumpking] = [] + var back : Pumpking = null + + var witchies : PackedStringArray = [] + + func born_pumpking() -> Pumpking: + var borned_pumpking : Pumpking = Pumpking.new() + next.append(borned_pumpking) + return borned_pumpking + + func merge_pumpking(pumpking : Pumpking) -> void: + if !(next in next) and back != pumpking: + if pumpking in next: + return + next.append(pumpking) + + func get_pumpking(check_cute_name : StringName) -> Pumpking: + if check_cute_name == cute_name: + return self + + for x : Pumpking in next: + var y : Pumpking = x.get_pumpking(check_cute_name) + if y: + return y + + return null + +func _update_tree(filter : StringName) -> void: + _tree.clear() + if pumpking: + if filter == &"All": + _collapsed = true + var root : TreeItem = _tree.create_item() + root.set_text(0, pumpking.cute_name) + for x : Pumpking in pumpking.next: + _fill_tree(root, x) + else: + _collapsed = false + var current : Pumpking = pumpking.get_pumpking(filter) + if current != pumpking: + var root : TreeItem = _tree.create_item() + root.set_text(0, current.cute_name) + _fill_tree(root, current) + else: + _update_tree(&"All") + +func _process(_delta: float) -> void: + var fs : EditorFileSystem = EditorInterface.get_resource_filesystem() + if !fs: + return + if fs.is_scanning(): + return + set_process(false) + _update() + +func update() -> void: + set_process(true) + +func _update() -> void: + var fs : EditorFileSystem = EditorInterface.get_resource_filesystem() + if fs: + var fd : EditorFileSystemDirectory = fs.get_filesystem() + if fd: + for x : int in range(1, _container.get_child_count(), 1): + var node : Node = _container.get_child(x) + node.name = node.name + "_queue" + node.queue_free() + + pumpking = Pumpking.new() + search(fd) + + if _default_tx == null: + _default_tx = get_icon("DEFAULT_NOT_FOUND") + + for p : Pumpking in pumpking.next: + _fill_tab(p) + + if _first_time: + _first_time = false + _update_tree.call_deferred(&"All") + _update_recents() + +func _fill_tab(pump : Pumpking) -> void: + var control : Control = Control.new() + var index : int = -1 + var nname : StringName = pump.cute_name + control.set_deferred(&"name", nname) + _container.add_child(control) + index = control.get_index() + if _container.get_tab_count() > index: + var icon : Texture2D = get_icon(nname) + if icon == _default_tx: + icon = CUTE_ICON + _container.set_tab_icon(index, icon) + for p : Pumpking in pump.next: + _fill_tab(p) + +func _fill_tree(root : TreeItem, pump : Pumpking) -> void: + var tree : TreeItem = root.create_child() + var nname : StringName = pump.cute_name + tree.set_text(0, nname) + var icon : Texture2D = get_icon(nname) + if icon == _default_tx: + icon = CUTE_ICON + tree.set_icon(0, icon) + tree.set_selectable(0, false) + tree.collapsed = _collapsed + + for w : String in pump.witchies: + var witch : TreeItem = tree.create_child() + + var text : String = w + var slice : int = w.get_slice_count("/") + if slice > 6: + text = w.get_file() + for x : int in range(slice - 1, slice - 4, -1): + text = w.get_slice("/", x).path_join(text) + text = "...".path_join(text) + + witch.set_text(0, text) + witch.set_icon(0, icon) + witch.set_custom_color(0, Color.DARK_GRAY) + witch.set_icon_modulate(0, Color.DARK_GRAY) + witch.set_metadata(0, w) + witch.set_tooltip_text(0, w) + + for x : Pumpking in pump.next: + _fill_tree(tree, x) + +func _update_recents() -> void: + _tree_recents.clear() + var fs : EditorFileSystem = EditorInterface.get_resource_filesystem() + if fs: + var data : Dictionary[String, PackedStringArray] = {} + var exist : PackedStringArray = [] + for x : String in _recents: + if FileAccess.file_exists(x): + var type : StringName = "File" + var fe : EditorFileSystemDirectory = fs.get_filesystem_path(x.get_base_dir()) + if fe: + for f : int in fe.get_file_count(): + if fe.get_file_path(f) == x: + type = fe.get_file_script_class_name(f) + if type.is_empty(): + type = fe.get_file_script_class_extends(f) + break + if type.is_empty(): + type = fs.get_file_type(x) + if !data.has(type): + var packed : PackedStringArray = [] + data[type] = packed + data[type].append(x) + exist.append(x) + _recents = exist + + + var root : TreeItem = _tree_recents.create_item() + root.set_text(0, "Recents Files") + root.set_selectable(0, false) + root.set_custom_color(0, Color.WHITE) + + for k : String in data.keys(): + var item : TreeItem = root.create_child() + var icon : Texture2D = get_icon(k) + + item.set_text(0, k) + item.set_selectable(0, false) + item.set_custom_color(0, Color.GRAY) + item.set_icon_modulate(0, Color.GRAY) + + if icon == _default_tx: + icon = CUTE_ICON + item.set_icon(0, icon) + for y : String in data[k]: + var fitem : TreeItem = item.create_child() + fitem.set_text(0, y.get_file()) + fitem.set_icon(0, icon) + fitem.set_tooltip_text(0, y) + fitem.set_custom_color(0, Color.DARK_GRAY) + fitem.set_icon_modulate(0, Color.DARK_GRAY) + fitem.set_metadata(0, y) + +func search(fd : EditorFileSystemDirectory) -> void: + if pumpking == null: + pumpking = Pumpking.new() + pumpking.cute_name = "Found Files" + for f : int in fd.get_file_count(): + var extension : StringName = fd.get_file_script_class_extends(f) + var type : StringName = fd.get_file_script_class_name(f) + var ee : bool = extension.is_empty() + var te : bool = type.is_empty() + if ee and te: + continue + var path : String = fd.get_file_path(f) + + if !ee: + var grand_pumpking : Pumpking = pumpking.get_pumpking(extension) + if grand_pumpking == null: + grand_pumpking = pumpking.born_pumpking() + grand_pumpking.cute_name = extension + if !te: + var newer_pumpking : Pumpking = grand_pumpking.get_pumpking(type) + if newer_pumpking == null: + newer_pumpking = grand_pumpking.born_pumpking() + newer_pumpking.cute_name = type + newer_pumpking.witchies.append(path) + else: + grand_pumpking.witchies.append(path) + elif !te: + var new_pumpking : Pumpking = pumpking.get_pumpking(type) + if new_pumpking == null: + new_pumpking = pumpking.born_pumpking() + new_pumpking.cute_name = type + new_pumpking.witchies.append(path) + + #if !ee: + #if !files.has(extension): + #var current_files : PackedStringArray = [] + #var classes : PackedStringArray = [] + #files[extension] = { + #"files" : current_files, + #"class" : classes, + #"parent" : "" + #} + #var data : Dictionary = files[extension] + #var packed : PackedStringArray = data["files"] + # + #if te: + #if !(path in packed): + #packed.append(path) + # + #if !te: + #if !files.has(type): + #var current_files : PackedStringArray = [] + #var classes : PackedStringArray = [] + #files[type] = { + #"files" : current_files, + #"class" : classes, + #"parent" : extension + #} + #var data : Dictionary = files[type] + #var packed : PackedStringArray = data["files"] + #if !(path in packed): + #packed.append(path) + + for x : int in fd.get_subdir_count(): + search(fd.get_subdir(x)) diff --git a/addons/_Godot-IDE_/plugins/fancy_search_class/gui/main.gd.uid b/addons/_Godot-IDE_/plugins/fancy_search_class/gui/main.gd.uid new file mode 100644 index 0000000..c01869e --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_search_class/gui/main.gd.uid @@ -0,0 +1 @@ +uid://dalllwmyh2v5m diff --git a/addons/_Godot-IDE_/plugins/fancy_search_class/gui/main.tscn b/addons/_Godot-IDE_/plugins/fancy_search_class/gui/main.tscn new file mode 100644 index 0000000..62279c4 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_search_class/gui/main.tscn @@ -0,0 +1,126 @@ +[gd_scene load_steps=6 format=3 uid="uid://cfwi81ii6ww5b"] + +[ext_resource type="Script" uid="uid://dalllwmyh2v5m" path="res://addons/_Godot-IDE_/plugins/fancy_search_class/gui/main.gd" id="1_v5iyo"] +[ext_resource type="Script" uid="uid://c6pfvkgkabvt6" path="res://addons/_Godot-IDE_/plugins/fancy_search_class/gui/button.gd" id="2_bnpnb"] +[ext_resource type="Texture2D" uid="uid://816fejewtbfj" path="res://addons/_Godot-IDE_/shared_resources/search.svg" id="2_nf02n"] +[ext_resource type="Script" uid="uid://blmveofp20cm1" path="res://addons/_Godot-IDE_/plugins/fancy_search_class/gui/line_edit.gd" id="3_m1yal"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_nf02n"] +content_margin_left = 5.0 +content_margin_top = 5.0 +content_margin_right = 5.0 +content_margin_bottom = 5.0 +bg_color = Color(0.1155, 0.132, 0.1595, 1) +corner_detail = 1 +anti_aliasing = false + +[node name="Window" type="Popup" node_paths=PackedStringArray("_container", "_tree", "_tree_recents")] +title = "Fancy Search Class" +initial_position = 4 +size = Vector2i(816, 500) +visible = true +script = ExtResource("1_v5iyo") +_container = NodePath("Main/MainContainer/HBoxContainer/BoxContainer/Container") +_tree = NodePath("Main/MainContainer/HBoxContainer/BoxContainer/Resource/Tree") +_tree_recents = NodePath("Main/MainContainer/HBoxContainer/RecentsContainer/SCroll/Recents") + +[node name="Main" type="PanelContainer" parent="."] +custom_minimum_size = Vector2(200, 500) +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_nf02n") + +[node name="MainContainer" type="MarginContainer" parent="Main"] +layout_mode = 2 +theme_override_constants/margin_left = 4 +theme_override_constants/margin_top = 4 +theme_override_constants/margin_right = 4 +theme_override_constants/margin_bottom = 4 + +[node name="HBoxContainer" type="HBoxContainer" parent="Main/MainContainer"] +layout_mode = 2 + +[node name="BoxContainer" type="VBoxContainer" parent="Main/MainContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Tittle" type="Label" parent="Main/MainContainer/HBoxContainer/BoxContainer"] +layout_mode = 2 +text = "Search Files By Class" +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="Separator" type="HSeparator" parent="Main/MainContainer/HBoxContainer/BoxContainer"] +layout_mode = 2 + +[node name="Container" type="TabContainer" parent="Main/MainContainer/HBoxContainer/BoxContainer"] +layout_mode = 2 +current_tab = 0 + +[node name="All" type="Control" parent="Main/MainContainer/HBoxContainer/BoxContainer/Container"] +layout_mode = 2 +metadata/_tab_index = 0 + +[node name="LineEdit" type="LineEdit" parent="Main/MainContainer/HBoxContainer/BoxContainer" node_paths=PackedStringArray("tree")] +layout_mode = 2 +placeholder_text = "File Search" +alignment = 1 +clear_button_enabled = true +right_icon = ExtResource("2_nf02n") +script = ExtResource("3_m1yal") +tree = NodePath("../Resource/Tree") + +[node name="Resource" type="ScrollContainer" parent="Main/MainContainer/HBoxContainer/BoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="Tree" type="Tree" parent="Main/MainContainer/HBoxContainer/BoxContainer/Resource"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="Bottom" type="HSeparator" parent="Main/MainContainer/HBoxContainer/BoxContainer"] +layout_mode = 2 + +[node name="close" type="Button" parent="Main/MainContainer/HBoxContainer/BoxContainer"] +layout_mode = 2 +text = "Close" +script = ExtResource("2_bnpnb") + +[node name="RecentsContainer" type="VBoxContainer" parent="Main/MainContainer/HBoxContainer"] +custom_minimum_size = Vector2(120, 0) +layout_mode = 2 + +[node name="Tittle" type="Label" parent="Main/MainContainer/HBoxContainer/RecentsContainer"] +layout_mode = 2 +text = "Recents" +horizontal_alignment = 1 + +[node name="Sep" type="HSeparator" parent="Main/MainContainer/HBoxContainer/RecentsContainer"] +layout_mode = 2 + +[node name="LineEdit2" type="LineEdit" parent="Main/MainContainer/HBoxContainer/RecentsContainer" node_paths=PackedStringArray("tree")] +layout_mode = 2 +placeholder_text = "Recent Search" +alignment = 1 +clear_button_enabled = true +right_icon = ExtResource("2_nf02n") +script = ExtResource("3_m1yal") +tree = NodePath("../SCroll/Recents") + +[node name="SCroll" type="ScrollContainer" parent="Main/MainContainer/HBoxContainer/RecentsContainer"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="Recents" type="Tree" parent="Main/MainContainer/HBoxContainer/RecentsContainer/SCroll"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="clear" type="Button" parent="Main/MainContainer/HBoxContainer/RecentsContainer"] +layout_mode = 2 +text = "Clear" +script = ExtResource("2_bnpnb") diff --git a/addons/_Godot-IDE_/plugins/fancy_search_class/plugin.cfg b/addons/_Godot-IDE_/plugins/fancy_search_class/plugin.cfg new file mode 100644 index 0000000..ff87303 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_search_class/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="Fancy Search Class" +description="Allow easy search class files" +author="Twister" +version="" +script="plugin.gd" diff --git a/addons/_Godot-IDE_/plugins/fancy_search_class/plugin.gd b/addons/_Godot-IDE_/plugins/fancy_search_class/plugin.gd new file mode 100644 index 0000000..400c066 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_search_class/plugin.gd @@ -0,0 +1,33 @@ +@tool +extends EditorPlugin +# ============================================================================= +# Author: Twister +# Fancy Search Class +# +# Addon for Godot +# ============================================================================= + + +const FANCY_SEARCH : PackedScene = preload("res://addons/_Godot-IDE_/plugins/fancy_search_class/gui/main.tscn") + +var pop : Window = null +var _c_input : InputEvent = null + +func _init() -> void: + var input : Variant = IDE.get_config("fancy_search_class", "invoke_input") + if input is InputEvent: + _c_input = input + else: + _c_input = InputEventKey.new() + _c_input.pressed = true + _c_input.alt_pressed = true + _c_input.keycode = KEY_DELETE + IDE.set_config("fancy_search_class", "invoke_input", _c_input) + + +func _input(event: InputEvent) -> void: + if event.is_pressed() and event.is_match(_c_input): + if !is_instance_valid(pop): + pop = FANCY_SEARCH.instantiate() + add_child(pop) + pop.popup_centered() diff --git a/addons/_Godot-IDE_/plugins/fancy_search_class/plugin.gd.uid b/addons/_Godot-IDE_/plugins/fancy_search_class/plugin.gd.uid new file mode 100644 index 0000000..a9c3fa5 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_search_class/plugin.gd.uid @@ -0,0 +1 @@ +uid://dhvs8xuxenk2y diff --git a/addons/_Godot-IDE_/plugins/fancy_search_files/gui/button.gd b/addons/_Godot-IDE_/plugins/fancy_search_files/gui/button.gd new file mode 100644 index 0000000..d428dd3 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_search_files/gui/button.gd @@ -0,0 +1,13 @@ +@tool +extends Button +# ============================================================================= +# Author: Twister +# Fancy Search Files +# +# Addon for Godot +# ============================================================================= + + +func _pressed() -> void: + if owner.has_method(name): + owner.call(name) diff --git a/addons/_Godot-IDE_/plugins/fancy_search_files/gui/button.gd.uid b/addons/_Godot-IDE_/plugins/fancy_search_files/gui/button.gd.uid new file mode 100644 index 0000000..aeb4b02 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_search_files/gui/button.gd.uid @@ -0,0 +1 @@ +uid://cpdqmdfvgpxmv diff --git a/addons/_Godot-IDE_/plugins/fancy_search_files/gui/line_edit.gd b/addons/_Godot-IDE_/plugins/fancy_search_files/gui/line_edit.gd new file mode 100644 index 0000000..6e91f1d --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_search_files/gui/line_edit.gd @@ -0,0 +1,66 @@ +@tool +extends LineEdit +# ============================================================================= +# Author: Twister +# Fancy Search Files +# +# Addon for Godot +# ============================================================================= + + +@export var tree : Tree = null + +func _ready() -> void: + text_changed.connect(sxrch) + +func reset() -> void: + if tree: + var root : TreeItem = tree.get_root() + if !root: + return + _reset(root) + +func _reset(root : TreeItem) -> void: + root.visible = true + for c : TreeItem in root.get_children(): + _reset(c) + +func sxrch(txt : String) -> void: + reset() + if txt.is_empty(): + return + if tree: + var root : TreeItem = tree.get_root() + if !root: + return + var rgx0 : RegEx = RegEx.create_from_string("(?i)\\b{0}\\b".format([txt])) + var rgx1 : RegEx = RegEx.create_from_string("(?i).*{0}.*".format([txt])) + var d0 : Array[TreeItem] = [] + var d1 : Array[TreeItem] = [] + + for x : RegEx in [rgx0, rgx1]: + if !is_instance_valid(x) or !x.is_valid(): + return + + _sxrch(root, rgx0, rgx1, d0, d1) + root.visible = false + + for t : TreeItem in d0: + _visible(t) + for t : TreeItem in d1: + _visible(t) + +func _visible(root : TreeItem) -> void: + if root: + root.visible = true + _visible(root.get_parent()) + +func _sxrch(root : TreeItem, rgx0 : RegEx, rgx1 : RegEx, d0 : Array[TreeItem], d1 : Array[TreeItem]) -> void: + var txt : String = root.get_text(0) + root.visible = false + if rgx0.search(txt) != null: + d0.append(root) + elif d0.size() == 0 and rgx1.search(txt) != null: + d1.append(root) + for x : TreeItem in root.get_children(): + _sxrch(x, rgx0, rgx1, d0, d1) diff --git a/addons/_Godot-IDE_/plugins/fancy_search_files/gui/line_edit.gd.uid b/addons/_Godot-IDE_/plugins/fancy_search_files/gui/line_edit.gd.uid new file mode 100644 index 0000000..ecbaf5e --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_search_files/gui/line_edit.gd.uid @@ -0,0 +1 @@ +uid://bx6ivdaldbcf8 diff --git a/addons/_Godot-IDE_/plugins/fancy_search_files/gui/main.gd b/addons/_Godot-IDE_/plugins/fancy_search_files/gui/main.gd new file mode 100644 index 0000000..00f0ce9 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_search_files/gui/main.gd @@ -0,0 +1,253 @@ +@tool +extends Window +# ============================================================================= +# Author: Twister +# Fancy Search Files +# +# Addon for Godot +# ============================================================================= + + +@export var _container : TabContainer = null +@export var _tree : Tree = null +@export var _tree_recents : Tree = null + +var files : Dictionary[StringName, PackedStringArray] = {} + +var _first_time : bool = false + +var _recents : PackedStringArray = [] + +var _default_tx : Texture2D = null + +func _enter_tree() -> void: + _first_time = true + + var screen : Vector2 = DisplayServer.screen_get_size() + var value : Variant = IDE.get_config("fancy_search_files", "size") + if value is Vector2 or value is Vector2i: + screen = value + else: + screen = screen * 0.6 + IDE.clamp_screen_size(screen, 0.3, 1.0) + size = screen + +func _ready() -> void: + update() + for x : int in range(1, _container.get_child_count(), 1): + _container.get_child(x).queue_free() + visibility_changed.connect(_on_visible) + _container.tab_changed.connect(_on_change) + _tree.item_activated.connect(_on_activate.bind(_tree)) + _tree_recents.item_activated.connect(_on_activate.bind(_tree_recents)) + + var result : Variant = IDE.get_file_config_value("fancy_search_files", "recents") + if result is PackedStringArray: + _recents = result + + var control : Control = EditorInterface.get_base_control() + if !control: + return + get_child(0). add_theme_stylebox_override(&"panel", control.get_theme_stylebox(&"panel", &"")) + +func _save() -> void: + IDE.set_file_config_value("fancy_search_files", "recents", _recents) + +func _on_visible() -> void: + if visible: + update() + else: + _save() + queue_free() + +func clear() -> void: + _recents.clear() + _tree_recents.clear() + +func _on_activate(tree : Tree) -> void: + if !tree: + return + + var item : TreeItem = tree.get_selected() + + if !item: + return + + var value : Variant = item.get_metadata(0) + if value is String: + if FileAccess.file_exists(value): + EditorInterface.select_file(value) + if ResourceLoader.exists(value): + var res : Resource = ResourceLoader.load(value) + if !(value in _recents): + while _recents.size() > 30: + _recents.remove_at(0) + _recents.append(value) + if res is Resource: + if res is PackedScene: + EditorInterface.open_scene_from_path(value) + elif res is Script: + EditorInterface.edit_script(res) + else: + EditorInterface.edit_resource(res) + hide() + +func _on_change(_tab_changed : int) -> void: + var control : Control = _container.get_current_tab_control() + if control: + _update_tree(control.name) + +func _exit_tree() -> void: + if is_instance_valid(_tree): + _tree.clear() + IDE.set_config("fancy_search_files", "size", size) + +func close() -> void: + hide() + +func get_icon(type : String) -> Texture2D: + var control : Control = EditorInterface.get_base_control() + if !control: + return null + var icon : Texture2D = control.get_theme_icon(type, "EditorIcons") + + if icon == _default_tx: + icon = control.get_theme_icon("File", "EditorIcons") + return icon + +func _update_tree(filter : StringName) -> void: + _tree.clear() + if files.size() == 0: + return + + if filter == &"All": + var root : TreeItem = _tree.create_item() + root.set_selectable(0, false) + for k : StringName in files.keys(): + var item : TreeItem = root.create_child() + var icon : Texture2D = get_icon(k) + item.set_text(0, k) + item.set_icon_modulate(0, Color.WHITE) + item.set_selectable(0, false) + item.collapsed = true + item.set_icon(0, icon) + for f : String in files[k]: + var fitem : TreeItem = item.create_child() + var slice : int = f.get_slice_count("/") + if slice > 5: + var txt : String = "" + for x : int in range(slice - 1, 3, -1): + txt = f.get_slice("/", x).path_join(txt) + txt = "...".path_join(txt) + fitem.set_text(0, txt) + else: + fitem.set_text(0, f) + fitem.set_icon(0, icon) + fitem.set_metadata(0, f) + fitem.set_icon_modulate(0, Color.GRAY) + fitem.set_custom_color(0, Color.GRAY) + fitem.set_tooltip_text(0, f) + elif files.has(filter): + var root : TreeItem = _tree.create_item() + var item : TreeItem = root.create_child() + var icon : Texture2D = get_icon(filter) + item.set_text(0, filter) + item.set_icon_modulate(0, Color.WHITE) + item.set_selectable(0, false) + item.collapsed = false + item.set_icon(0, icon) + for f : String in files[filter]: + var fitem : TreeItem = item.create_child() + fitem.set_text(0, f.get_file()) + fitem.set_icon(0, icon) + fitem.set_metadata(0, f) + fitem.set_icon_modulate(0, Color.GRAY) + fitem.set_custom_color(0, Color.GRAY) + fitem.set_tooltip_text(0, f) + else: + push_warning("Not valid type!") + +func _process(_delta: float) -> void: + var fs : EditorFileSystem = EditorInterface.get_resource_filesystem() + if !fs: + return + if fs.is_scanning(): + return + set_process(false) + _update() + +func update() -> void: + set_process(true) + +func _update() -> void: + var fs : EditorFileSystem = EditorInterface.get_resource_filesystem() + if fs: + var fd : EditorFileSystemDirectory = fs.get_filesystem() + if fd: + for x : int in range(1, _container.get_child_count(), 1): + var node : Node = _container.get_child(x) + node.name = node.name + "_queue" + node.queue_free() + files.clear() + search(fd) + + if _default_tx == null: + _default_tx = get_icon("DEFAULT_NOT_FOUND") + + for x : StringName in files.keys(): + var control : Control = Control.new() + var index : int = -1 + control.set_deferred(&"name", x) + _container.add_child(control) + index = control.get_index() + if _container.get_tab_count() > index: + _container.set_tab_icon(index, get_icon(x)) + if _first_time: + _first_time = false + _update_tree.call_deferred(&"All") + _update_recents() + +func _update_recents() -> void: + _tree_recents.clear() + var fs : EditorFileSystem = EditorInterface.get_resource_filesystem() + if fs: + var data : Dictionary[String, PackedStringArray] = {} + for x : String in _recents: + if FileAccess.file_exists(x): + var type : String = fs.get_file_type(x) + if !data.has(type): + var packed : PackedStringArray = [] + data[type] = packed + data[type].append(x) + + var root : TreeItem = _tree_recents.create_item() + root.set_text(0, "Recents Files") + root.set_selectable(0, false) + root.set_custom_color(0, Color.WHITE) + for k : String in data.keys(): + var item : TreeItem = root.create_child() + var icon : Texture2D = get_icon(k) + item.set_text(0, k) + item.set_icon(0, icon) + item.set_selectable(0, false) + item.set_custom_color(0, Color.GRAY) + item.set_icon_modulate(0, Color.GRAY) + for y : String in data[k]: + var fitem : TreeItem = item.create_child() + fitem.set_text(0, y.get_file()) + fitem.set_icon(0, icon) + fitem.set_tooltip_text(0, y) + fitem.set_custom_color(0, Color.DARK_GRAY) + fitem.set_icon_modulate(0, Color.DARK_GRAY) + fitem.set_metadata(0, y) + +func search(fd : EditorFileSystemDirectory) -> void: + for f : int in fd.get_file_count(): + var type : StringName = fd.get_file_type(f) + if !files.has(type): + var _packed : PackedStringArray = [] + files[type] = _packed + files[type].append(fd.get_file_path(f)) + + for x : int in fd.get_subdir_count(): + search(fd.get_subdir(x)) diff --git a/addons/_Godot-IDE_/plugins/fancy_search_files/gui/main.gd.uid b/addons/_Godot-IDE_/plugins/fancy_search_files/gui/main.gd.uid new file mode 100644 index 0000000..f4aae77 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_search_files/gui/main.gd.uid @@ -0,0 +1 @@ +uid://dvsbvurbdecex diff --git a/addons/_Godot-IDE_/plugins/fancy_search_files/gui/main.tscn b/addons/_Godot-IDE_/plugins/fancy_search_files/gui/main.tscn new file mode 100644 index 0000000..2bd06f4 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_search_files/gui/main.tscn @@ -0,0 +1,126 @@ +[gd_scene load_steps=6 format=3 uid="uid://cddiai7iiut3l"] + +[ext_resource type="Script" uid="uid://dvsbvurbdecex" path="res://addons/_Godot-IDE_/plugins/fancy_search_files/gui/main.gd" id="1_0f0lw"] +[ext_resource type="Texture2D" uid="uid://816fejewtbfj" path="res://addons/_Godot-IDE_/shared_resources/search.svg" id="2_fowvl"] +[ext_resource type="Script" uid="uid://cpdqmdfvgpxmv" path="res://addons/_Godot-IDE_/plugins/fancy_search_files/gui/button.gd" id="2_ydlx0"] +[ext_resource type="Script" uid="uid://bx6ivdaldbcf8" path="res://addons/_Godot-IDE_/plugins/fancy_search_files/gui/line_edit.gd" id="3_5ntm4"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_fowvl"] +content_margin_left = 3.0 +content_margin_top = 3.0 +content_margin_right = 3.0 +content_margin_bottom = 3.0 +bg_color = Color(0.1155, 0.132, 0.1595, 1) +corner_detail = 1 +anti_aliasing = false + +[node name="Window" type="Popup" node_paths=PackedStringArray("_container", "_tree", "_tree_recents")] +title = "Fancy Search Files" +initial_position = 4 +size = Vector2i(816, 500) +visible = true +script = ExtResource("1_0f0lw") +_container = NodePath("Main/MainContainer/HBoxContainer/BoxContainer/Container") +_tree = NodePath("Main/MainContainer/HBoxContainer/BoxContainer/Resource/Tree") +_tree_recents = NodePath("Main/MainContainer/HBoxContainer/RecentsContainer/SCroll/Recents") + +[node name="Main" type="PanelContainer" parent="."] +custom_minimum_size = Vector2(200, 500) +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_fowvl") + +[node name="MainContainer" type="MarginContainer" parent="Main"] +layout_mode = 2 +theme_override_constants/margin_left = 4 +theme_override_constants/margin_top = 4 +theme_override_constants/margin_right = 4 +theme_override_constants/margin_bottom = 4 + +[node name="HBoxContainer" type="HBoxContainer" parent="Main/MainContainer"] +layout_mode = 2 + +[node name="BoxContainer" type="VBoxContainer" parent="Main/MainContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Tittle" type="Label" parent="Main/MainContainer/HBoxContainer/BoxContainer"] +layout_mode = 2 +text = "Search Files By Type" +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="Separator" type="HSeparator" parent="Main/MainContainer/HBoxContainer/BoxContainer"] +layout_mode = 2 + +[node name="Container" type="TabContainer" parent="Main/MainContainer/HBoxContainer/BoxContainer"] +layout_mode = 2 +current_tab = 0 + +[node name="All" type="Control" parent="Main/MainContainer/HBoxContainer/BoxContainer/Container"] +layout_mode = 2 +metadata/_tab_index = 0 + +[node name="LineEdit" type="LineEdit" parent="Main/MainContainer/HBoxContainer/BoxContainer" node_paths=PackedStringArray("tree")] +layout_mode = 2 +placeholder_text = "File Search" +alignment = 1 +clear_button_enabled = true +right_icon = ExtResource("2_fowvl") +script = ExtResource("3_5ntm4") +tree = NodePath("../Resource/Tree") + +[node name="Resource" type="ScrollContainer" parent="Main/MainContainer/HBoxContainer/BoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="Tree" type="Tree" parent="Main/MainContainer/HBoxContainer/BoxContainer/Resource"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="Bottom" type="HSeparator" parent="Main/MainContainer/HBoxContainer/BoxContainer"] +layout_mode = 2 + +[node name="close" type="Button" parent="Main/MainContainer/HBoxContainer/BoxContainer"] +layout_mode = 2 +text = "Close" +script = ExtResource("2_ydlx0") + +[node name="RecentsContainer" type="VBoxContainer" parent="Main/MainContainer/HBoxContainer"] +custom_minimum_size = Vector2(120, 0) +layout_mode = 2 + +[node name="Tittle" type="Label" parent="Main/MainContainer/HBoxContainer/RecentsContainer"] +layout_mode = 2 +text = "Recents" +horizontal_alignment = 1 + +[node name="Sep" type="HSeparator" parent="Main/MainContainer/HBoxContainer/RecentsContainer"] +layout_mode = 2 + +[node name="LineEdit2" type="LineEdit" parent="Main/MainContainer/HBoxContainer/RecentsContainer" node_paths=PackedStringArray("tree")] +layout_mode = 2 +placeholder_text = "Recent Search" +alignment = 1 +clear_button_enabled = true +right_icon = ExtResource("2_fowvl") +script = ExtResource("3_5ntm4") +tree = NodePath("../SCroll/Recents") + +[node name="SCroll" type="ScrollContainer" parent="Main/MainContainer/HBoxContainer/RecentsContainer"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="Recents" type="Tree" parent="Main/MainContainer/HBoxContainer/RecentsContainer/SCroll"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="clear" type="Button" parent="Main/MainContainer/HBoxContainer/RecentsContainer"] +layout_mode = 2 +text = "Clear" +script = ExtResource("2_ydlx0") diff --git a/addons/_Godot-IDE_/plugins/fancy_search_files/plugin.cfg b/addons/_Godot-IDE_/plugins/fancy_search_files/plugin.cfg new file mode 100644 index 0000000..4bc7638 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_search_files/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="Fancy Search Files" +description="Allow easy search files by type" +author="Twister" +version="" +script="plugin.gd" diff --git a/addons/_Godot-IDE_/plugins/fancy_search_files/plugin.gd b/addons/_Godot-IDE_/plugins/fancy_search_files/plugin.gd new file mode 100644 index 0000000..bb35d1a --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_search_files/plugin.gd @@ -0,0 +1,33 @@ +@tool +extends EditorPlugin +# ============================================================================= +# Author: Twister +# Fancy Search Files +# +# Addon for Godot +# ============================================================================= + +const FANCY_SEARCH : PackedScene = preload("res://addons/_Godot-IDE_/plugins/fancy_search_files/gui/main.tscn") + +var pop : Window = null + +var _c_input : InputEvent = null + +func _init() -> void: + var input : Variant = IDE.get_config("fancy_search_files", "invoke_input") + if input is InputEvent: + _c_input = input + else: + _c_input = InputEventKey.new() + _c_input.pressed = true + _c_input.ctrl_pressed = true + _c_input.alt_pressed = true + _c_input.keycode = KEY_SPACE + IDE.set_config("fancy_search_files", "invoke_input", _c_input) + +func _input(event: InputEvent) -> void: + if event.is_pressed() and event.is_match(_c_input): + if !is_instance_valid(pop): + pop = FANCY_SEARCH.instantiate() + add_child(pop) + pop.popup_centered() diff --git a/addons/_Godot-IDE_/plugins/fancy_search_files/plugin.gd.uid b/addons/_Godot-IDE_/plugins/fancy_search_files/plugin.gd.uid new file mode 100644 index 0000000..a779cfc --- /dev/null +++ b/addons/_Godot-IDE_/plugins/fancy_search_files/plugin.gd.uid @@ -0,0 +1 @@ +uid://8e7vxkrhsi2j diff --git a/addons/_Godot-IDE_/plugins/gd_override_functions/plugin.cfg b/addons/_Godot-IDE_/plugins/gd_override_functions/plugin.cfg new file mode 100644 index 0000000..dfbbe21 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/gd_override_functions/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="GDOverrideFunctions" +description="Allow select virtual functions for override/implement." +author="Twister" +version="0.3" +script="plugin.gd" diff --git a/addons/_Godot-IDE_/plugins/gd_override_functions/plugin.gd b/addons/_Godot-IDE_/plugins/gd_override_functions/plugin.gd new file mode 100644 index 0000000..b33d2ec --- /dev/null +++ b/addons/_Godot-IDE_/plugins/gd_override_functions/plugin.gd @@ -0,0 +1,54 @@ +@tool +extends EditorPlugin +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# GD Override Functions +# +# Virtual Popups override functions. godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + +var RES : Script = preload("res://addons/_Godot-IDE_/plugins/gd_override_functions/popup/virtuals_popup_context.gd") + +#region extension_features +var popup_virtual_functions : RefCounted = null +var popup_virtual_functions_code : RefCounted = null +#endregion + +var _c_input : InputEvent = null + +func _init() -> void: + var editor : EditorSettings = EditorInterface.get_editor_settings() + if editor: + var input : Variant = editor.get_setting("plugin/gd_override_functions/invoke_input") + if input is InputEvent: + _c_input = input + else: + _c_input = InputEventKey.new() + _c_input.pressed = true + _c_input.alt_pressed = true + _c_input.keycode = KEY_INSERT + editor.set_setting("plugin/gd_override_functions/invoke_input", _c_input) + + +func _enter_tree() -> void: + popup_virtual_functions = RES.new() + popup_virtual_functions_code = RES.new() + add_context_menu_plugin(EditorContextMenuPlugin.CONTEXT_SLOT_SCRIPT_EDITOR, popup_virtual_functions) + add_context_menu_plugin(EditorContextMenuPlugin.CONTEXT_SLOT_SCRIPT_EDITOR_CODE, popup_virtual_functions_code) + +func _exit_tree() -> void: + remove_context_menu_plugin(popup_virtual_functions) + remove_context_menu_plugin(popup_virtual_functions_code) + + popup_virtual_functions = null + popup_virtual_functions_code = null + +#Input because the dev can be change buttons ( >.>) +func _input(event: InputEvent) -> void: + if event.is_pressed() and event.is_match(_c_input, true): + var editor : ScriptEditor = EditorInterface.get_script_editor() + if editor: + var sc : Script = editor.get_current_script() + if sc: + if popup_virtual_functions and popup_virtual_functions.has_method(&"callback"): + popup_virtual_functions_code.call(&"callback", sc) diff --git a/addons/_Godot-IDE_/plugins/gd_override_functions/plugin.gd.uid b/addons/_Godot-IDE_/plugins/gd_override_functions/plugin.gd.uid new file mode 100644 index 0000000..f485967 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/gd_override_functions/plugin.gd.uid @@ -0,0 +1 @@ +uid://bo3i5csexlcoe diff --git a/addons/_Godot-IDE_/plugins/gd_override_functions/popup/button/pressed.tres b/addons/_Godot-IDE_/plugins/gd_override_functions/popup/button/pressed.tres new file mode 100644 index 0000000..5d2a3d4 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/gd_override_functions/popup/button/pressed.tres @@ -0,0 +1,14 @@ +[gd_resource type="StyleBoxFlat" format=3 uid="uid://daq1bri8pp6lp"] + +[resource] +bg_color = Color(0.352941, 0.12549, 0.352941, 0.25098) +border_width_left = 4 +border_width_top = 4 +border_width_right = 4 +border_width_bottom = 4 +border_color = Color(0.631373, 0.270588, 0.631373, 1) +border_blend = true +corner_radius_top_left = 4 +corner_radius_top_right = 4 +corner_radius_bottom_right = 4 +corner_radius_bottom_left = 4 diff --git a/addons/_Godot-IDE_/plugins/gd_override_functions/popup/icon/Attribute.txt b/addons/_Godot-IDE_/plugins/gd_override_functions/popup/icon/Attribute.txt new file mode 100644 index 0000000..7c791f7 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/gd_override_functions/popup/icon/Attribute.txt @@ -0,0 +1,2 @@ +ICONS +https://www.flaticon.com/free-icons \ No newline at end of file diff --git a/addons/_Godot-IDE_/plugins/gd_override_functions/popup/virtuals_popup.gd b/addons/_Godot-IDE_/plugins/gd_override_functions/popup/virtuals_popup.gd new file mode 100644 index 0000000..86d8db8 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/gd_override_functions/popup/virtuals_popup.gd @@ -0,0 +1,1203 @@ +@tool +extends Popup +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# script-ide: Virtual Popups +# +# Virtual Popups for script-ide addon.godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + +const BUILT_IN_SCRIPT: String = "::GDScript" + +const ICON_PUBLIC : Texture = preload("res://addons/_Godot-IDE_/shared_resources/func_public.svg") +const ICON_VIRTUALS : Texture = preload("res://addons/_Godot-IDE_/shared_resources/func_virtual.svg") +const ICON_PRIVATE : Texture = preload("res://addons/_Godot-IDE_/shared_resources/func_private.svg") +const ICON_CHECKED : Texture = preload("res://addons/_Godot-IDE_/shared_resources/check.svg") +#const ICON_WARNING : Texture = preload("res://addons/gd_override_functions/popup/icon/warning.png") + +const ICON_NATIVE_CLASS : Texture = preload("res://addons/_Godot-IDE_/shared_resources/Script.svg") +const ICON_CUSTOM_CLASS : Texture = preload("res://addons/_Godot-IDE_/shared_resources/ScriptExtend.svg") +const ICON_CUSTOM_SCRIPT : Texture = preload("res://addons/_Godot-IDE_/shared_resources/PluginScript.svg") +const ICON_INTERFACE_SCRIPT : Texture = preload("res://addons/_Godot-IDE_/shared_resources/InterfaceScript.svg") + +const ICON_ORDER_DEFAULT : Texture = preload("res://addons/_Godot-IDE_/shared_resources/up.svg") +const ICON_ORDER_INVERT : Texture = preload("res://addons/_Godot-IDE_/shared_resources/down.svg") + +var COLOR_CLASS : Color = Color.DARK_SLATE_BLUE +var COLOR_NATIVE_CLASS : Color = Color.BLACK +var COLOR_PARAMETERS : Color = Color.BLACK +var COLOR_INTERFACE : Color = Color.BLACK + +var include_paremeters : bool = false + +# FILTERS +var _private_begin_equal_protected : bool = false +var _public_filter : bool = false +var _private_filter : bool = false +var _protected_filter : bool = true +var _interface_filter : bool = true + +enum FILTER_TYPE{ + DEFAULT, + REVERSE, + DEFAUL_TREE, + REVERSE_TREE +} + +@export_tool_button("Test") +var test_button: Callable = _testing + +@export var tree : Tree +@export var accept_button : Button +@export var cancel_button : Button + +@export var check_generate_at_line : CheckBox + +# GENERATORS +@export var interface_generate_button : Button +@export var virtual_generate_button : Button + +#region order +@export var order_button : Button +#endregion + +#region filter_handler +@export var public_button : Button +@export var protected_button : Button +@export var private_button : Button +@export var interface_button : Button + +var _last_script : Script = null +var _last_filter : FILTER_TYPE = FILTER_TYPE.REVERSE +#endregion + +var _buffer_data : Dictionary = {} +var _created_funcs : Dictionary = {} + +var _generate_at_end_line : bool = true + +#region _USER_CONFIG_ +## Class name chars in the begin for identify a class as interface +var _interface_begins_with : String = "I" +## Class name chars in the end for identify a class as interface. +var _interface_end_with : String = "Interface" +## Ignore Upper/Lower case of class name. +var _interface_ignore_case : bool = true +## Function name in the begin for identify function as virtual. +var _char_virtual_function : String = "_" +## Function name in the end for identify function as virtual. +var _char_private_function : String = "__" +## Include native class like IMyClass, MyClassInterface. +var _include_native_class_for_check_interfaces : bool = false +#endregion + +func _update_settings() -> void: + var editor : EditorSettings = EditorInterface.get_editor_settings() + if null == editor: + return + + if editor.has_setting("plugin/gd_override_functions/interface/class_as_interface_if_begins_with"): + _interface_begins_with = editor.get_setting("plugin/gd_override_functions/interface/class_as_interface_if_begins_with") + if editor.has_setting("plugin/gd_override_functions/interface/class_as_interface_if_end_with"): + _interface_end_with = editor.get_setting("plugin/gd_override_functions/interface/class_as_interface_if_end_with") + if editor.has_setting("plugin/gd_override_functions/interface/class_interface_name_ignore_case"): + _interface_ignore_case = editor.get_setting("plugin/gd_override_functions/interface/class_interface_name_ignore_case") + if editor.has_setting("plugin/gd_override_functions/inheritance/virtual_functions_begins_with"): + _char_virtual_function = editor.get_setting("plugin/gd_override_functions/inheritance/virtual_functions_begins_with") + if editor.has_setting("plugin/gd_override_functions/inheritance/private_functions_begins_with"): + _char_private_function = editor.get_setting("plugin/gd_override_functions/inheritance/private_functions_begins_with") + if editor.has_setting("plugin/gd_override_functions/inheritance/include_native_class_for_check_interfaces"): + _include_native_class_for_check_interfaces = editor.get_setting("plugin/gd_override_functions/inheritance/include_native_class_for_check_interfaces") + if _interface_ignore_case: + _interface_end_with = _interface_end_with.to_lower() + _interface_begins_with = _interface_begins_with.to_lower() + +func make_tree(input_script : Script, filter_type : FILTER_TYPE = _last_filter) -> void: + _buffer_data = {} + _created_funcs = {} + if tree == null: + push_error("Not defined tree!") + return + + tree.clear() + + _update_settings() + + _last_script = input_script + _last_filter = filter_type + + var callback : Callable = _on_accept_button + if accept_button: + if accept_button.pressed.is_connected(_on_accept_button): + accept_button.pressed.disconnect(_on_accept_button) + accept_button.pressed.connect(callback) + if tree.item_activated.is_connected(_on_accept_button): + tree.item_activated.disconnect(_on_accept_button) + tree.item_activated.connect(callback) + + # script-ide: Check if built-in script. In this case we need to duplicate it for whatever reason. + if (input_script.get_path().contains(BUILT_IN_SCRIPT)): + input_script = input_script.duplicate() + + var output : Array = generate_data(input_script) + var base : Dictionary = output[0] + var base_count : int = output[1] + + #MAKE TREE + var start : int = 0 + var end : int = base_count + 1 + var step : int = 1 + if filter_type == FILTER_TYPE.DEFAULT or filter_type == FILTER_TYPE.DEFAUL_TREE: + start = base_count + end = -1 + step = -1 + + tree.set_column_custom_minimum_width(0, 25) + + tree.set_column_title_alignment(0, HORIZONTAL_ALIGNMENT_CENTER) + tree.set_column_title_alignment(1, HORIZONTAL_ALIGNMENT_CENTER) + tree.set_column_title_alignment(2, HORIZONTAL_ALIGNMENT_CENTER) + + tree.set_column_title(0, "Class/Functions") + tree.set_column_title(1, "Params") + tree.set_column_title(2, "Return") + tree.column_titles_visible = true + + var root : TreeItem = tree.create_item() + root.set_text(0, "Classes") + + _created_funcs = _clear_funcs(input_script) + + _buffer_data = base + + if filter_type == FILTER_TYPE.DEFAUL_TREE or filter_type == FILTER_TYPE.REVERSE_TREE: + var last : TreeItem = root + for x : int in range(start, end, step): + var dict : Dictionary = base[x] + var funcs : Dictionary = dict["funcs"] + + if funcs.size() == 0:continue + + var item : TreeItem = tree.create_item(last, -1) + + item.set_text(0, dict["name"]) + last = item + + if dict["type"] == 0: + item.set_custom_bg_color(0, COLOR_NATIVE_CLASS) + item.set_custom_bg_color(1, COLOR_NATIVE_CLASS) + item.set_custom_bg_color(2, COLOR_NATIVE_CLASS) + item.collapsed = true + item.set_icon(0, ICON_NATIVE_CLASS) + elif dict["type"] == 1: + item.set_custom_bg_color(0, COLOR_CLASS) + item.set_custom_bg_color(1, COLOR_CLASS) + item.set_custom_bg_color(2, COLOR_CLASS) + if dict["custom"] == true: + item.set_icon(0, ICON_CUSTOM_SCRIPT) + else: + item.set_icon(0, ICON_CUSTOM_CLASS) + elif dict["type"] == 3: + item.set_custom_bg_color(0, COLOR_NATIVE_CLASS) + item.set_custom_bg_color(1, COLOR_NATIVE_CLASS) + item.set_custom_bg_color(2, COLOR_NATIVE_CLASS) + item.collapsed = true + item.set_icon(0, ICON_INTERFACE_SCRIPT) + else: + item.set_custom_bg_color(0, COLOR_INTERFACE) + item.set_custom_bg_color(1, COLOR_INTERFACE) + item.set_custom_bg_color(2, COLOR_INTERFACE) + if dict["custom"] == true: + item.set_icon(0, ICON_INTERFACE_SCRIPT) + else: + item.set_icon(0, ICON_INTERFACE_SCRIPT) #NOTNATIVE4NOW + item.set_selectable(0, false) + item.set_selectable(1, false) + item.set_selectable(2, false) + for key : Variant in funcs.keys(): + var sub_item : TreeItem = tree.create_item(item, -1) + var func_name : PackedStringArray = (funcs[key] as String).split('||', false, 2) + for fx : int in range(0, func_name.size(), 1): + sub_item.set_text(fx, func_name[fx]) + sub_item.set_text_alignment(1,HORIZONTAL_ALIGNMENT_CENTER) + sub_item.set_text_alignment(2,HORIZONTAL_ALIGNMENT_CENTER) + sub_item.set_selectable(1, false) + sub_item.set_selectable(2, false) + sub_item.set_custom_color(1, COLOR_PARAMETERS) + sub_item.set_custom_color(2, COLOR_PARAMETERS) + if _created_funcs.has(key): + sub_item.set_icon_overlay(0, ICON_CHECKED) + sub_item.set_selectable(0, false) + else: + #if dict["type"] == 2 and !override.has(key): + #sub_item.set_icon_overlay(0, ICON_WARNING) + #else: + sub_item.set_icon_overlay(0, null) + sub_item.set_selectable(0, true) + if (key as String).begins_with(_char_private_function): + sub_item.set_icon(0, ICON_PRIVATE) + elif (key as String).begins_with(_char_virtual_function): + sub_item.set_icon(0, ICON_VIRTUALS) + else: + sub_item.set_icon(0, ICON_PUBLIC) + else: + for x : int in range(start, end, step): + var dict : Dictionary = base[x] + var funcs : Dictionary = dict["funcs"] + + if funcs.size() == 0:continue + + var item : TreeItem = tree.create_item(null, -1) + + item.set_text(0, dict["name"]) + if dict["type"] == 0: + item.set_custom_bg_color(0, COLOR_NATIVE_CLASS) + item.set_custom_bg_color(1, COLOR_NATIVE_CLASS) + item.set_custom_bg_color(2, COLOR_NATIVE_CLASS) + item.collapsed = true + item.set_icon(0, ICON_NATIVE_CLASS) + elif dict["type"] == 1: + item.set_custom_bg_color(0, COLOR_CLASS) + item.set_custom_bg_color(1, COLOR_CLASS) + item.set_custom_bg_color(2, COLOR_CLASS) + if dict["custom"] == true: + item.set_icon(0, ICON_CUSTOM_SCRIPT) + else: + item.set_icon(0, ICON_CUSTOM_CLASS) + elif dict["type"] == 3: + item.set_custom_bg_color(0, COLOR_NATIVE_CLASS) + item.set_custom_bg_color(1, COLOR_NATIVE_CLASS) + item.set_custom_bg_color(2, COLOR_NATIVE_CLASS) + item.collapsed = true + item.set_icon(0, ICON_INTERFACE_SCRIPT) + else: + item.set_custom_bg_color(0, COLOR_INTERFACE) + item.set_custom_bg_color(1, COLOR_INTERFACE) + item.set_custom_bg_color(2, COLOR_INTERFACE) + if dict["custom"] == true: + item.set_icon(0, ICON_INTERFACE_SCRIPT) + else: + item.set_icon(0, ICON_INTERFACE_SCRIPT) #NOTNATIVE4NOW + item.set_selectable(0, false) + item.set_selectable(1, false) + item.set_selectable(2, false) + for key : Variant in funcs.keys(): + var sub_item : TreeItem = tree.create_item(item, -1) + var func_name : PackedStringArray = (funcs[key] as String).split('||', false, 2) + for fx : int in range(0, func_name.size(), 1): + sub_item.set_text(fx, func_name[fx]) + sub_item.set_text_alignment(1,HORIZONTAL_ALIGNMENT_CENTER) + sub_item.set_text_alignment(2,HORIZONTAL_ALIGNMENT_CENTER) + sub_item.set_selectable(1, false) + sub_item.set_selectable(2, false) + sub_item.set_custom_color(1, COLOR_PARAMETERS) + sub_item.set_custom_color(2, COLOR_PARAMETERS) + if _created_funcs.has(key): + sub_item.set_icon_overlay(0, ICON_CHECKED) + sub_item.set_selectable(0, false) + else: + #if dict["type"] == 2 and !override.has(key): + #sub_item.set_icon_overlay(0, ICON_WARNING) + #else: + sub_item.set_icon_overlay(0, null) + sub_item.set_selectable(0, true) + if (key as String).begins_with(_char_private_function): + sub_item.set_icon(0, ICON_PRIVATE) + elif (key as String).begins_with(_char_virtual_function): + sub_item.set_icon(0, ICON_VIRTUALS) + else: + sub_item.set_icon(0, ICON_PUBLIC) + + if root.get_child_count() == 0: + root.set_text(0, "No functions aviables!") + tree.hide_root = false + + _update_gui() + +## Generate tree data, @output Array(base class data, total bases inherited class]) +func generate_data(script : Script) -> Array: + var data_base : Dictionary = {} + var base_count : int = _generate_native(script.get_instance_base_type(), data_base, _generate(script.get_base_script(), data_base)) + return [data_base, base_count] + +func _on_settings_change() -> void: + var editor : EditorSettings = EditorInterface.get_editor_settings() + var changes : PackedStringArray = editor.get_changed_settings() + if "plugin/gd_override_functions/generate_at_end_line" in changes: + _generate_at_end_line = editor.get_setting("plugin/gd_override_functions/generate_at_end_line") + if "plugin/gd_override_functions/order_inverted" in changes: + var inverted : bool = editor.get_setting("plugin/gd_override_functions/order_inverted") + if inverted: + _last_filter = FILTER_TYPE.REVERSE + else: + _last_filter = FILTER_TYPE.DEFAULT + + if "plugin/gd_override_functions/initial_size" in changes: + var _size : Variant = editor.get_setting("plugin/gd_override_functions/initial_size") + if _size is Vector2 or _size is Vector2i: + size = _size + size.x = maxf(size.x, 512.0) + size.y = maxf(size.y, 512.0) + +#region init +func _ready() -> void: + var w_size : Vector2 = DisplayServer.window_get_size() + if w_size != Vector2.ZERO: + size = w_size * 0.6 + + config_update(false) + + if !Engine.is_editor_hint(): + #Component created for be used in editor mode, so testing is invoke in non editor mode. + _testing() + + +func _testing() -> void: + await get_tree().process_frame + + #Also work with class_name + var input_script : Script = ResourceLoader.load("res://addons/gd_override_functions/popup/testing/child.gd") + + #Show popup + call_deferred(&"show") + make_tree(input_script, _last_filter) + +func _on_change_order_pressed() -> void: + match _last_filter: + #FILTER_TYPE.REVERSE: + #_last_filter = FILTER_TYPE.DEFAULT + #FILTER_TYPE.DEFAULT: + #_last_filter = FILTER_TYPE.REVERSE_TREE + #FILTER_TYPE.REVERSE_TREE: + ##_last_filter = FILTER_TYPE.DEFAUL_TREE + #FILTER_TYPE.DEFAUL_TREE: + #_last_filter = FILTER_TYPE.REVERSE + FILTER_TYPE.REVERSE: + _last_filter = FILTER_TYPE.DEFAULT + FILTER_TYPE.DEFAULT: + _last_filter = FILTER_TYPE.REVERSE + _: + _last_filter = FILTER_TYPE.REVERSE + var root : TreeItem = tree.get_root() + var collapsed : Dictionary = {} + + if root: + var tree_item : TreeItem = root.get_first_child() + while null != tree_item: + collapsed[tree_item.get_text(0)] = tree_item.collapsed + tree_item = tree_item.get_next() + + make_tree(_last_script, _last_filter) + root = tree.get_root() + + if root: + var tree_item : TreeItem = root.get_first_child() + while null != tree_item: + var txt : String = str(tree_item.get_text(0)) + if collapsed.has(txt): + tree_item.collapsed = collapsed[txt] + tree_item = tree_item.get_next() + + +func _on_public_filter_pressed() -> void: + var root : TreeItem = tree.get_root() + var collapsed : Dictionary = {} + + if root: + var tree_item : TreeItem = root.get_first_child() + while null != tree_item: + collapsed[tree_item.get_text(0)] = tree_item.collapsed + tree_item = tree_item.get_next() + + _public_filter = !_public_filter + make_tree(_last_script, _last_filter) + + root = tree.get_root() + if root: + var tree_item : TreeItem = root.get_first_child() + while null != tree_item: + var txt : String = str(tree_item.get_text(0)) + if collapsed.has(txt): + tree_item.collapsed = collapsed[txt] + tree_item = tree_item.get_next() + +func _on_protected_filter_pressed() -> void: + var root : TreeItem = tree.get_root() + var collapsed : Dictionary = {} + + if root: + var tree_item : TreeItem = root.get_first_child() + while null != tree_item: + collapsed[tree_item.get_text(0)] = tree_item.collapsed + tree_item = tree_item.get_next() + + _protected_filter = !_protected_filter + make_tree(_last_script, _last_filter) + + root = tree.get_root() + if root: + var tree_item : TreeItem = root.get_first_child() + while null != tree_item: + var txt : String = str(tree_item.get_text(0)) + if collapsed.has(txt): + tree_item.collapsed = collapsed[txt] + tree_item = tree_item.get_next() + +func _on_private_filter_pressed() -> void: + var root : TreeItem = tree.get_root() + var collapsed : Dictionary = {} + + if root: + var tree_item : TreeItem = root.get_first_child() + while null != tree_item: + collapsed[tree_item.get_text(0)] = tree_item.collapsed + tree_item = tree_item.get_next() + + _private_filter = !_private_filter + make_tree(_last_script, _last_filter) + + root = tree.get_root() + if root: + var tree_item : TreeItem = root.get_first_child() + while null != tree_item: + var txt : String = str(tree_item.get_text(0)) + if collapsed.has(txt): + tree_item.collapsed = collapsed[txt] + tree_item = tree_item.get_next() + +func _on_interface_filter_pressed() -> void: + var root : TreeItem = tree.get_root() + var collapsed : Dictionary = {} + + if root: + var tree_item : TreeItem = root.get_first_child() + while null != tree_item: + collapsed[tree_item.get_text(0)] = tree_item.collapsed + tree_item = tree_item.get_next() + + _interface_filter = !_interface_filter + make_tree(_last_script, _last_filter) + + root = tree.get_root() + if root: + var tree_item : TreeItem = root.get_first_child() + while null != tree_item: + var txt : String = str(tree_item.get_text(0)) + if collapsed.has(txt): + tree_item.collapsed = collapsed[txt] + tree_item = tree_item.get_next() + + +func _on_generate_virtual_pressed() -> void: + if _buffer_data.size() == 0: + print("Not class aviables!") + return + var funcs : Dictionary = {} + for x : Variant in _buffer_data.keys(): + if _buffer_data[x]["type"] > 0: + var _class_data : Dictionary = _buffer_data[x] + var _funcs : Dictionary = _class_data["funcs"] + for _func : Variant in _funcs.keys(): + var func_name : String = str(_func) + if !func_name.begins_with(_char_private_function) and func_name.begins_with(_char_virtual_function): + if _created_funcs.has(_func): + continue + funcs[_func] = { + "type" : _class_data["type"] + ,"class" :_class_data["name"] + ,"name" : str(_func) + } + if funcs.size() == 0: + print("Not has virtual methods for override/implement!") + return + _make(funcs) + +func _on_generate_interface_pressed() -> void: + if _buffer_data.size() == 0: + print("Not class aviables!") + return + var funcs : Dictionary = {} + for x : Variant in _buffer_data.keys(): + if _buffer_data[x]["type"] == 2: + var _class_data : Dictionary = _buffer_data[x] + var _funcs : Dictionary = _class_data["funcs"] + for _func : Variant in _funcs.keys(): + if _created_funcs.has(_func): + continue + funcs[_func] = { + "type" : _class_data["type"] + ,"class" :_class_data["name"] + ,"name" : str(_func) + } + continue + if funcs.size() == 0: + print("Not has interfaces methods for override/implement!") + return + _make(funcs) + +func _on_check_generate_at_line(toggled : bool) -> void: + _generate_at_end_line = toggled + +func config_update(save : bool = false) -> void: + const SETTING : String = "plugin/gd_override_functions/initial_size" + const SETTING_CHECK : String = "plugin/gd_override_functions/save_size_on_exit" + var editor : EditorSettings = EditorInterface.get_editor_settings() + + size.x = maxf(size.x, 512) + size.y = maxf(size.y, 512) + + if editor: + if !editor.has_setting(SETTING_CHECK): + editor.set_setting(SETTING_CHECK, true) + + if !editor.has_setting(SETTING): + editor.set_setting(SETTING, (size as Vector2i)) + return + + if save: + if editor.get_setting(SETTING_CHECK) == true: + editor.set_setting(SETTING, (size as Vector2i)) + else: + size = editor.get_setting(SETTING) + +func _init() -> void: + _private_begin_equal_protected = _char_private_function.begins_with(_char_virtual_function) + if !is_node_ready(): + await ready + assert(tree and accept_button and cancel_button) + + tree.select_mode = Tree.SELECT_MULTI + tree.multi_selected.connect(_on_tree_multi_selected) + cancel_button.pressed.connect(_on_cancel_button) + + if public_button: + public_button.pressed.connect(_on_public_filter_pressed) + if protected_button: + protected_button.pressed.connect(_on_protected_filter_pressed) + if private_button: + private_button.pressed.connect(_on_private_filter_pressed) + if interface_button: + interface_button.pressed.connect(_on_interface_filter_pressed) + if interface_generate_button: + interface_generate_button.pressed.connect(_on_generate_interface_pressed) + if virtual_generate_button: + virtual_generate_button.pressed.connect(_on_generate_virtual_pressed) + + if order_button: + order_button.pressed.connect(_on_change_order_pressed) + + if check_generate_at_line: + check_generate_at_line.toggled.connect(_on_check_generate_at_line) + + COLOR_CLASS = COLOR_CLASS.darkened(0.4) + COLOR_NATIVE_CLASS = COLOR_CLASS.darkened(0.4) + COLOR_PARAMETERS = COLOR_CLASS.lightened(0.3) + COLOR_INTERFACE = COLOR_CLASS.lightened(0.2) + + visibility_changed.connect(_on_change_visibility) + + + var editor : EditorSettings = EditorInterface.get_editor_settings() + if !editor.has_setting("plugin/gd_override_functions/generate_at_end_line"): + editor.set_setting("plugin/gd_override_functions/generate_at_end_line", _generate_at_end_line) + editor.add_property_info({ + "name": "plugin/gd_override_functions/generate_at_end_line", + "type" : TYPE_BOOL + }) + else: + _generate_at_end_line = editor.get_setting("plugin/gd_override_functions/generate_at_end_line") + + if !editor.has_setting("plugin/gd_override_functions/order_inverted"): + editor.set_setting("plugin/gd_override_functions/order_inverted", _last_filter == FILTER_TYPE.REVERSE) + editor.add_property_info({ + "name": "plugin/gd_override_functions/order_inverted", + "type" : TYPE_BOOL + }) + else: + var inverted : bool = editor.get_setting("plugin/gd_override_functions/order_inverted") + if inverted: + _last_filter = FILTER_TYPE.REVERSE + else: + _last_filter = FILTER_TYPE.DEFAULT + + if !editor.has_setting("plugin/gd_override_functions/inheritance/virtual_functions_begins_with"): + editor.set_setting("plugin/gd_override_functions/inheritance/virtual_functions_begins_with", _char_virtual_function) + if !editor.has_setting("plugin/gd_override_functions/inheritance/private_functions_begins_with"): + editor.set_setting("plugin/gd_override_functions/inheritance/private_functions_begins_with", _char_private_function) + + if !editor.has_setting("plugin/gd_override_functions/interface/class_as_interface_if_begins_with"): + editor.set_setting("plugin/gd_override_functions/interface/class_as_interface_if_begins_with", _interface_begins_with) + if !editor.has_setting("plugin/gd_override_functions/interface/class_as_interface_if_end_with"): + editor.set_setting("plugin/gd_override_functions/interface/class_as_interface_if_end_with", _interface_end_with) + if !editor.has_setting("plugin/gd_override_functions/interface/class_interface_name_ignore_case"): + editor.set_setting("plugin/gd_override_functions/interface/class_interface_name_ignore_case", false) + if !editor.has_setting("plugin/gd_override_functions/inheritance/include_native_class_for_check_interfaces"): + editor.set_setting("plugin/gd_override_functions/inheritance/include_native_class_for_check_interfaces", _include_native_class_for_check_interfaces) + + editor.settings_changed.connect(_on_settings_change) + + _update_gui() +#endregion + +func _on_change_visibility() -> void: + if !visible: + _created_funcs.clear() + _buffer_data.clear() + + var editor : EditorSettings = EditorInterface.get_editor_settings() + editor.set_setting("plugin/gd_override_functions/generate_at_end_line", _generate_at_end_line) + editor.set_setting("plugin/gd_override_functions/order_inverted", _last_filter == FILTER_TYPE.REVERSE) + + return + +func _update_gui() -> void: + if accept_button: + accept_button.disabled = tree.get_selected() == null + + if public_button: + public_button.button_pressed = _public_filter + + if protected_button: + protected_button.button_pressed = _protected_filter + + if private_button: + private_button.button_pressed = _private_filter + + if interface_button: + interface_button.button_pressed = _interface_filter + + if order_button: + if _last_filter == FILTER_TYPE.DEFAULT or _last_filter == FILTER_TYPE.DEFAUL_TREE: + order_button.icon = ICON_ORDER_INVERT + else: + order_button.icon = ICON_ORDER_DEFAULT + + if check_generate_at_line: + check_generate_at_line.button_pressed = _generate_at_end_line + + #UPDATE INTERFACE + if virtual_generate_button: + virtual_generate_button.disabled = true + if _buffer_data.size() > 0: + for x : Variant in _buffer_data.keys(): + if _buffer_data[x]["type"] > 0: + var _class_data : Dictionary = _buffer_data[x] + var _funcs : Dictionary = _class_data["funcs"] + for _func : Variant in _funcs.keys(): + var func_name : String = str(_func) + if !func_name.begins_with(_char_private_function) and func_name.begins_with(_char_virtual_function): + if !_created_funcs.has(_func): + virtual_generate_button.disabled = false + break + if !virtual_generate_button.disabled: + break + + #UPDATE INTERFACE + if interface_generate_button: + interface_generate_button.disabled = true + if _buffer_data.size() == 0: + return + for x : Variant in _buffer_data.keys(): + if _buffer_data[x]["type"] > 1: + var _class_data : Dictionary = _buffer_data[x] + var _funcs : Dictionary = _class_data["funcs"] + for _func : Variant in _funcs.keys(): + if !_created_funcs.has(_func): + interface_generate_button.disabled = false + return + +func _write_lines(_class_name : String, func_name : String, input_script : Script, data : String, is_interface : bool = false) -> bool: + #ONLY EDITOR MODE + if !Engine.is_editor_hint(): + print(data) + return false + + var comment : String = "Override {0} {1}." + var type : String = "function" + + if is_interface: + comment = "Implement {0} {1}." + + if func_name.begins_with(_char_private_function): + type = "private function" + elif func_name.begins_with(_char_virtual_function): + type = "virtual function" + + var script_editor: ScriptEditor = EditorInterface.get_script_editor() + var scripts : Array[Script] = script_editor.get_open_scripts() + var scripts_editor : Array[ScriptEditorBase] = script_editor.get_open_script_editors() + var edit : CodeEdit = null + var iscript : int = -1 + + for x : int in range(scripts.size()): + if scripts[x] == input_script: + iscript = x + break + + if iscript == -1 or iscript >= scripts_editor.size(): + push_error("Error, can`t get editor!") + return false + + edit = scripts_editor[iscript].get_base_editor() + + var new_line : String = str("#", comment.format([_class_name,type]),"\n", data) + if !_generate_at_end_line and edit.get_caret_count() > 0: + var line : int = -1 + for x : int in edit.get_caret_count(): + line = edit.get_caret_line(x) + break + if line > -1: + var line_to : int = -1 + while line < edit.get_line_count(): + var ctxline : String = edit.get_line(line) + if ctxline.length() > 0: + if ctxline.begins_with(" ") or ctxline.begins_with("\t"): + if !ctxline.strip_edges().is_empty(): + line_to = -1 + else: + line_to = line + else: + if line_to == -1: + line_to = line + break + else: + if line_to == -1: + line_to = line + line += 1 + if line_to > -1 and line_to != edit.get_line_count() - 1: + if line_to > 1: + if !(edit.get_line(line_to - 1).strip_edges().is_empty()): + new_line = str('\n', new_line) + if line_to < edit.get_line_count() - 1: + if !(edit.get_line(line_to + 1).strip_edges().is_empty()): + new_line = str(new_line, '\n') + var ctx : String = edit.get_line(line_to) + if !ctx.strip_edges().is_empty(): + edit.set_line(line_to, new_line+'\n'+edit.get_line(line_to)) + else: + edit.set_line(line_to, new_line) + _goto_line(script_editor, line_to) + return true + + if edit.text.ends_with("\n"): + edit.text += str("\n", new_line) + else: + edit.text += str("\n\n", new_line) + _goto_line(script_editor, edit.get_line_count() - 1) + return true + +# goto_line script-ide +func _goto_line(script_editor : ScriptEditor, index : int): + script_editor.goto_line(index) + + var code_edit: CodeEdit = script_editor.get_current_editor().get_base_editor() + code_edit.set_caret_line(index) + code_edit.set_v_scroll(index) + code_edit.set_caret_column(code_edit.get_line(index).length()) + code_edit.set_h_scroll(0) + + code_edit.grab_focus() + +func __iterate_metada(buffer : PackedStringArray, input_script : Script, funcs : Dictionary, metadata : Array[Dictionary], totals : int = 0) -> int: + if totals < funcs.size(): + for key : Variant in funcs.keys(): + var data : Dictionary = funcs[key] + var class_type : int = data["type"] + var _class_name : String = data["class"] + var _func : String = data["name"] + + var is_interface : bool = class_type == 2 + + for meta : Dictionary in metadata: + if meta.name == _func: + if _func in buffer: + continue + buffer.append(_func) + if _write_lines(_class_name, _func, input_script, _get_full_header_virtual(meta), is_interface): + if is_interface: + print('[INFO] Created "{0}.{1}" interface function'.format([_class_name, _func])) + else: + print('[INFO] Created "{0}.{1}" function'.format([_class_name, _func])) + else: + if Engine.is_editor_hint(): + if is_interface: + print('[INFO] Error on create "{0}.{1}" interface function!'.format([_class_name, _func])) + else: + print('[INFO] Error on create "{0}.{1}" function!'.format([_class_name, _func])) + totals += 1 + if totals == funcs.size(): + break + return totals + +#region UI_CALLBACK +func _on_accept_button() -> void: + var item : TreeItem = tree.get_next_selected(null) + var funcs : Dictionary = {} + + while item != null: + var parent : String = item.get_parent().get_text(0) + var fname : String = item.get_text(0) + + for x : Variant in _buffer_data.keys(): + if _buffer_data[x]["name"] == parent: + var _class_data : Dictionary = _buffer_data[x] + var _funcs : Dictionary = _class_data["funcs"] + if _funcs.has(fname): + funcs[fname] = { + "type" : _class_data["type"] + ,"class" :_class_data["name"] + ,"name" : fname + } + item = tree.get_next_selected(item) + + _make(funcs) + +func _make(funcs : Dictionary) -> void: + var type_base : StringName = _last_script.get_instance_base_type() + var buffer : PackedStringArray = [] + if ClassDB.class_exists(type_base): + __iterate_metada(buffer, _last_script, funcs, ClassDB.class_get_method_list(type_base), __iterate_metada(buffer, _last_script, funcs, _last_script.get_script_method_list(), 0),) + else: + __iterate_metada(buffer, _last_script, funcs, _last_script.get_script_method_list(), 0) + _on_cancel_button() + + + +func _on_cancel_button() -> void: + hide() + config_update(true) + +func _on_tree_multi_selected(_item: TreeItem, _column: int, _selected: bool) -> void: + _update_gui() +#endregion + +func _get_name(script : Script, ref_data : Dictionary) -> StringName: + var base_name : StringName = script.get_global_name() + if base_name.is_empty(): + var path : String = script.resource_name + if path.is_empty(): + path = script.resource_path + if !path.is_empty(): + var _name : String = path.get_file() + _name = _name.trim_suffix("." + _name.get_extension()) + base_name = _name + else: + base_name = &"CustomScript" + ref_data["custom"] = true + else: + base_name = path + return base_name + +func _clear_funcs(script : Script) -> Dictionary: + var out : Dictionary = {} + if Engine.is_editor_hint(): + var rgx : RegEx = RegEx.create_from_string("(?m)^func\\s+(\\w*)\\s*\\(") + var source : String = script.source_code + var script_editor: ScriptEditor = EditorInterface.get_script_editor() + var scripts_editors : Array[ScriptEditorBase] = script_editor.get_open_script_editors() + var scripts : Array[Script] = script_editor.get_open_scripts() + var iscript : int = -1 + + for x : int in range(scripts.size()): + if scripts[x] == script: + iscript = x + break + if iscript > -1 and scripts_editors.size() > iscript: + source = scripts_editors[iscript].get_base_editor().text + for rs : RegExMatch in rgx.search_all(source): + if rs.strings.size() > 1: + var fname : String = rs.strings[1] + out[fname] = fname + else: + for methods : Dictionary in script.get_script_method_list(): + out[methods.name] = methods.name + return out + +func _generate_native(native : StringName, data : Dictionary, index : int = 0) -> int: + if native.is_empty() or !ClassDB.class_exists(native): + return index + var funcs : Dictionary = {} + var base : Dictionary = { + "name" : native + ,"funcs" : funcs + ,"type" : 0 + ,"custom": false + } + index += 1 + data[index] = base + + if _include_native_class_for_check_interfaces: + var base_name : String = native + if _interface_ignore_case: + base_name = base_name.to_lower() + if (!_interface_begins_with.is_empty() and base_name.begins_with(_interface_begins_with)) or \ + (!_interface_end_with.is_empty() and base_name.ends_with(_interface_end_with)): + base["type"] = 3 + + if _interface_filter and base["type"] == 3: + #SHOW ALL + for dict: Dictionary in ClassDB.class_get_method_list(native): + funcs[dict.name] = _get_header_virtual(dict) + else: + for dict: Dictionary in ClassDB.class_get_method_list(native): + #region conditional + if _protected_filter: + if dict.flags & METHOD_FLAG_VIRTUAL > 0: + funcs[dict.name] =_get_header_virtual(dict) + continue + if _public_filter: + var method : StringName = dict.name + if _private_begin_equal_protected: + if !method.begins_with(_char_virtual_function): + funcs[method] = _get_header_virtual(dict) + continue + else: + if !method.begins_with(_char_private_function) and !method.begins_with(_char_virtual_function): + funcs[method] =_get_header_virtual(dict) + continue + if _private_filter: + var method : StringName = dict.name + if _private_begin_equal_protected: + if method.begins_with(_char_private_function): + funcs[method] =_get_header_virtual(dict) + else: + if method.begins_with(_char_private_function) and !method.begins_with(_char_virtual_function): + funcs[method] =_get_header_virtual(dict) + #endregion + + for x : int in range(0, index, 1): + var clazz : Dictionary = data[x]["funcs"] + for k : Variant in funcs.keys(): + if clazz.has(k): + clazz.erase(k) + + return _generate_native(ClassDB.get_parent_class(native), data, index) + +func _generate(script : Script, data : Dictionary, index : int = -1) -> int: + if script == null: + return index + var funcs : Dictionary = {} + var base : Dictionary = { + "name" : &"GDScript" + ,"funcs" : funcs + ,"type": 1 + ,"custom": false + } + var base_name : String = _get_name(script, base) + base["name"] = base_name + index += 1 + data[index] = base + + if _interface_ignore_case: + base_name = base_name.to_lower() + + if (!_interface_begins_with.is_empty() and base_name.begins_with(_interface_begins_with)) or \ + (!_interface_end_with.is_empty() and base_name.ends_with(_interface_end_with)): + base["type"] = 2 + + if _interface_filter and base["type"] == 2: + #SHOW ALL + for dict: Dictionary in script.get_script_method_list(): + if dict.name.begins_with("@"):continue + funcs[dict.name] = _get_header_virtual(dict) + else: + for dict: Dictionary in script.get_script_method_list(): + var func_name: StringName = dict.name + if func_name.begins_with("@"):continue + #region conditional + if _protected_filter: + if (func_name.begins_with(_char_virtual_function) and !func_name.begins_with(_char_private_function)) or dict.flags & METHOD_FLAG_VIRTUAL > 0: + funcs[func_name] = _get_header_virtual(dict) + if _public_filter: + if _private_begin_equal_protected: + if !func_name.begins_with(_char_virtual_function): + funcs[func_name] =_get_header_virtual(dict) + continue + else: + if !func_name.begins_with(_char_private_function) and !func_name.begins_with(_char_virtual_function): + funcs[func_name] =_get_header_virtual(dict) + continue + if _private_filter: + if _private_begin_equal_protected: + if func_name.begins_with(_char_private_function): + funcs[func_name] =_get_header_virtual(dict) + else: + if func_name.begins_with(_char_private_function) and !func_name.begins_with(_char_virtual_function): + funcs[func_name] =_get_header_virtual(dict) + #endregion + + for x : int in range(0, index, 1): + var clazz : Dictionary = data[x]["funcs"] + for k : Variant in funcs.keys(): + if clazz.has(k): + clazz.erase(k) + return _generate(script.get_base_script(), data, index) + +func __is_variant(func_name : String) -> bool: + const FUNC_GET : Array[String] = ["get_", "_get"] + for x : String in FUNC_GET: + if func_name.begins_with(x) or func_name.ends_with(x): + return true + return func_name.contains("_get_") + +func _get_header_virtual(dict : Dictionary) -> String: + var params : String = "" + var args : Array = dict["args"] + var separator : String = "" + var default_args : Array = dict["default_args"] + var _default_index : int = default_args.size() + + for y : int in range(args.size() - 1, -1, -1): + var arg : Dictionary = args[y] + var txt : String = "" #arg["name"] + if !(arg["class_name"]).is_empty(): + txt += str(arg["class_name"] as String) + else: + var _typeof : int = arg["type"] + txt += str(_get_type(_typeof)) + if include_paremeters and _default_index > 0: + _default_index -= 1 + var def : Variant = default_args[_default_index] + var _type : int = typeof(def) + if def == null or _type < 1: + txt += str(' = null') + elif _type < 5: + if def is String: + txt += str(' = "', def, '"') + elif def is StringName: + txt += str(' = &"', def, '"') + else: + txt += str(" = ", def) + else: + txt += str(" = ",_get_type(typeof(def)), def) + params = str(txt, separator, params) + separator = ", " + + var return_dic : Dictionary = dict["return"] + var return_type : String = "void" + + if !return_dic["class_name"].is_empty(): + return_type = (return_dic["class_name"] as String) + else: + var _type : int = return_dic["type"] + if _type < 1: + var func_name : String = str(dict["name"]).to_lower() + if func_name == "get" or __is_variant(func_name): + return_type = "Variant" + else: + return_type = "void" + else: + return_type = _get_type(return_dic["type"]) + + if params.is_empty(): + params = "-" + return "{0}||{1}||{2}".format([dict["name"], params, return_type]).replace(" ", "") #Replace x more space. + +func _get_full_header_virtual(dict : Dictionary) -> String: + var params : String = "" + var args : Array = dict["args"] + var separator : String = "" + var default_args : Array = dict["default_args"] + var _default_index : int = default_args.size() + + for y : int in range(args.size() - 1, -1, -1): + var arg : Dictionary = args[y] + var txt : String = arg["name"] + if !(arg["class_name"]).is_empty(): + txt += str(" : ", arg["class_name"] as String) + else: + var _typeof : int = arg["type"] + txt += str(" : ", _get_type(_typeof)) + if _default_index > 0: + _default_index -= 1 + var def : Variant = default_args[_default_index] + var _type : int = typeof(def) + if def == null or _type < 1: + txt += str(' = null') + elif _type < 5: + if def is String: + txt += str(' = "', def, '"') + elif def is StringName: + txt += str(' = &"', def, '"') + else: + txt += str(" = ", def) + else: + txt += str(" = ",_get_type(typeof(def)), def) + params = str(txt, separator, params) + separator = ", " + + var return_dic : Dictionary = dict["return"] + var return_type : String = "void" + var return_value : String = "pass" + if !return_dic["class_name"].is_empty(): + return_type = (return_dic["class_name"] as String) + return_value = "return null" + else: + var _type : int = return_dic["type"] + if _type < 1: + var func_name : String = str(dict["name"]).to_lower() + if func_name == "get" or __is_variant(func_name): + return_type = "Variant" + return_value = "return null" + else: + return_type = "void" + else: + return_type = _get_type(return_dic["type"]) + if _type == TYPE_INT: + return_value = "return 0" + elif _type == TYPE_BOOL: + return_value = "return false" + elif _type == TYPE_FLOAT: + return_value = "return 0.0" + elif _type == TYPE_STRING: + return_value = 'return ""' + elif _type == TYPE_ARRAY: + return_value = "return []" + else: + return_value = str("return ", return_type,"()") + return "func {0}({1}) -> {2}:\n\t#TODO: code here :)\n\t{3}".format([dict["name"], params, return_type, return_value]) + +func _get_type(_typeof : int) -> String: + var txt : String = "" + match _typeof: + TYPE_BOOL : txt = "bool" + TYPE_INT : txt = "int" + TYPE_FLOAT: txt = "float" + TYPE_STRING : txt = "String" + TYPE_VECTOR2 : txt = "Vector2" + TYPE_VECTOR2I : txt = "Vector2i" + TYPE_RECT2 : txt = "Rect2" + TYPE_RECT2I : txt = "Rect2i" + TYPE_VECTOR3 : txt = "Vector3" + TYPE_VECTOR3I : txt = "Vector3i" + TYPE_TRANSFORM2D : txt = "Tranform2D" + TYPE_VECTOR4 : txt = "Vector4" + TYPE_VECTOR4I : txt = "Vector4i" + TYPE_PLANE : txt = "Plane" + TYPE_QUATERNION : txt = "Quaternion" + TYPE_AABB : txt = "AABB" + TYPE_BASIS : txt = "Basis" + TYPE_TRANSFORM3D : txt = "Transform3D" + TYPE_PROJECTION : txt = "Projection" + TYPE_COLOR : txt = "Color" + TYPE_STRING_NAME : txt = "StringName" + TYPE_NODE_PATH : txt = "NodePath" + TYPE_RID : txt = "RID" + TYPE_OBJECT : txt = "Object" + TYPE_CALLABLE : txt = "Callable" + TYPE_SIGNAL : txt = "Signal" + TYPE_DICTIONARY : txt = "Dictionary" + TYPE_ARRAY : txt = "Array" + TYPE_PACKED_BYTE_ARRAY : txt = "PackedByteArray" + TYPE_PACKED_INT32_ARRAY : txt = "PackedInt32Array" + TYPE_PACKED_INT64_ARRAY : txt = "PackedInt64Array" + TYPE_PACKED_FLOAT32_ARRAY : txt = "PackedFloat32Array" + TYPE_PACKED_FLOAT64_ARRAY : txt = "PackedFloat64Array" + TYPE_PACKED_STRING_ARRAY : txt = "PackedStringArray" + TYPE_PACKED_VECTOR2_ARRAY : txt = "PackedVector2Array" + TYPE_PACKED_VECTOR3_ARRAY : txt = "PackedVector3Array" + TYPE_PACKED_COLOR_ARRAY : txt = "PackedColorArray" + TYPE_PACKED_VECTOR4_ARRAY : txt = "PackedVector4Array" + _: + txt = "Variant" + return txt diff --git a/addons/_Godot-IDE_/plugins/gd_override_functions/popup/virtuals_popup.gd.uid b/addons/_Godot-IDE_/plugins/gd_override_functions/popup/virtuals_popup.gd.uid new file mode 100644 index 0000000..530ff15 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/gd_override_functions/popup/virtuals_popup.gd.uid @@ -0,0 +1 @@ +uid://bnbi70ajc0nbg diff --git a/addons/_Godot-IDE_/plugins/gd_override_functions/popup/virtuals_popup.tscn b/addons/_Godot-IDE_/plugins/gd_override_functions/popup/virtuals_popup.tscn new file mode 100644 index 0000000..e05b3c6 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/gd_override_functions/popup/virtuals_popup.tscn @@ -0,0 +1,196 @@ +[gd_scene load_steps=10 format=3 uid="uid://hxjjupcjoat8"] + +[ext_resource type="Script" uid="uid://bnbi70ajc0nbg" path="res://addons/_Godot-IDE_/plugins/gd_override_functions/popup/virtuals_popup.gd" id="1_afp4m"] +[ext_resource type="Texture2D" uid="uid://bgjo43cuidob1" path="res://addons/_Godot-IDE_/shared_resources/up.svg" id="2_v42ap"] +[ext_resource type="Texture2D" uid="uid://dg7rdmg80x4jv" path="res://addons/_Godot-IDE_/shared_resources/func_virtual.svg" id="3_t5ujg"] +[ext_resource type="Texture2D" uid="uid://bjmtfc58y1sbs" path="res://addons/_Godot-IDE_/shared_resources/InterfaceScript.svg" id="4_yees5"] +[ext_resource type="StyleBox" uid="uid://daq1bri8pp6lp" path="res://addons/_Godot-IDE_/plugins/gd_override_functions/popup/button/pressed.tres" id="5_obeej"] +[ext_resource type="Texture2D" uid="uid://ckc3yk6f8y3ob" path="res://addons/_Godot-IDE_/shared_resources/func_public.svg" id="6_kuyjr"] +[ext_resource type="Texture2D" uid="uid://do4gmovks0mn6" path="res://addons/_Godot-IDE_/shared_resources/func_private.svg" id="7_edrjb"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_iq5ej"] +bg_color = Color(0.352765, 0.124129, 0.353458, 1) +border_width_left = 4 +border_width_top = 4 +border_width_right = 4 +border_color = Color(0.631373, 0.270588, 0.631373, 1) +corner_radius_top_left = 2 +corner_radius_top_right = 2 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_knkse"] +bg_color = Color(0.196078, 0.392157, 0.588235, 1) + +[node name="Virtuals" type="PopupPanel" node_paths=PackedStringArray("tree", "accept_button", "cancel_button", "check_generate_at_line", "interface_generate_button", "virtual_generate_button", "order_button", "public_button", "protected_button", "private_button", "interface_button")] +title = "GD Override Functions" +initial_position = 4 +size = Vector2i(1024, 512) +visible = true +transient_to_focused = true +unresizable = false +borderless = false +script = ExtResource("1_afp4m") +tree = NodePath("Container/Tree") +accept_button = NodePath("Container/FooterContainer/OkButton") +cancel_button = NodePath("Container/FooterContainer/CancelButton") +check_generate_at_line = NodePath("Container/CheckConfig0") +interface_generate_button = NodePath("Container/HBoxContainer/interface_generate_btn") +virtual_generate_button = NodePath("Container/HBoxContainer/virtual_generate_btn") +order_button = NodePath("Container/HBoxContainer/order") +public_button = NodePath("Container/HBoxContainer/public_btn") +protected_button = NodePath("Container/HBoxContainer/protected_btn") +private_button = NodePath("Container/HBoxContainer/private_btn") +interface_button = NodePath("Container/HBoxContainer/interface_btn") + +[node name="Container" type="VBoxContainer" parent="."] +offset_left = 4.0 +offset_top = 4.0 +offset_right = 1020.0 +offset_bottom = 508.0 + +[node name="TittleContainer" type="PanelContainer" parent="Container"] +custom_minimum_size = Vector2(24, 24) +layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_iq5ej") + +[node name="Tittle" type="Label" parent="Container/TittleContainer"] +layout_mode = 2 +size_flags_horizontal = 6 +text = "Select Methods to Override/Implement" +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="TextureRect" type="TextureRect" parent="Container/TittleContainer"] +custom_minimum_size = Vector2(16, 16) +layout_mode = 2 +size_flags_horizontal = 8 +expand_mode = 1 +stretch_mode = 3 + +[node name="HBoxContainer" type="HBoxContainer" parent="Container"] +layout_mode = 2 + +[node name="order" type="Button" parent="Container/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Order by class inherited." +text = "Order" +icon = ExtResource("2_v42ap") + +[node name="virtual_generate_btn" type="Button" parent="Container/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Implement all custom virtual methods. +(Only custom virtuals methods!)" +disabled = true +text = "Generate" +icon = ExtResource("3_t5ujg") + +[node name="interface_generate_btn" type="Button" parent="Container/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Implement all interface methods." +disabled = true +text = "Generate" +icon = ExtResource("4_yees5") + +[node name="Label" type="Label" parent="Container/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 10 +text = "Filters Methods" + +[node name="public_btn" type="Button" parent="Container/HBoxContainer"] +custom_minimum_size = Vector2(16, 16) +layout_mode = 2 +tooltip_text = "Public methods. + +Example: +func public_method() +func my_method() +func foo()" +theme_override_font_sizes/font_size = 16 +theme_override_styles/pressed = ExtResource("5_obeej") +toggle_mode = true +icon = ExtResource("6_kuyjr") +icon_alignment = 1 + +[node name="protected_btn" type="Button" parent="Container/HBoxContainer"] +custom_minimum_size = Vector2(16, 16) +layout_mode = 2 +tooltip_text = "Protected/Virtual Methods. + +Example: +func _virtual_method() +func _my_virtual_method() +func _ready()" +theme_override_styles/pressed = ExtResource("5_obeej") +toggle_mode = true +button_pressed = true +icon = ExtResource("3_t5ujg") +icon_alignment = 1 + +[node name="private_btn" type="Button" parent="Container/HBoxContainer"] +custom_minimum_size = Vector2(16, 16) +layout_mode = 2 +tooltip_text = "Private Methods. + +Example: +func __private_method() +func __my_private_method +func __foo()" +theme_override_styles/pressed = ExtResource("5_obeej") +toggle_mode = true +icon = ExtResource("7_edrjb") +icon_alignment = 1 + +[node name="interface_btn" type="Button" parent="Container/HBoxContainer"] +custom_minimum_size = Vector2(16, 16) +layout_mode = 2 +tooltip_text = "Interfaces. +This include all interface methods. + +Interfaces are the \"custom classes\" begin with \"I\" character. + +Example: +class_name IMyClass +class_name IDummy_Class +class_name Ifoo_class + +Files without class_name but begin with \"I\" also work! + +Example: +IMyInterface.gd +IDummy_Script.gd +Ifoo_script.gd" +theme_override_styles/pressed = ExtResource("5_obeej") +toggle_mode = true +button_pressed = true +icon = ExtResource("4_yees5") +icon_alignment = 1 + +[node name="Tree" type="Tree" parent="Container"] +custom_minimum_size = Vector2(128, 256) +layout_mode = 2 +size_flags_vertical = 3 +columns = 3 +column_titles_visible = true +hide_root = true +select_mode = 2 + +[node name="CheckConfig0" type="CheckBox" parent="Container"] +layout_mode = 2 +button_pressed = true +text = "Generate at end of line" + +[node name="FooterContainer" type="HBoxContainer" parent="Container"] +layout_mode = 2 + +[node name="OkButton" type="Button" parent="Container/FooterContainer"] +custom_minimum_size = Vector2(64, 0) +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_styles/normal = SubResource("StyleBoxFlat_knkse") +disabled = true +text = "Create" + +[node name="CancelButton" type="Button" parent="Container/FooterContainer"] +custom_minimum_size = Vector2(64, 0) +layout_mode = 2 +size_flags_horizontal = 3 +text = "Cancel" diff --git a/addons/_Godot-IDE_/plugins/gd_override_functions/popup/virtuals_popup_context.gd b/addons/_Godot-IDE_/plugins/gd_override_functions/popup/virtuals_popup_context.gd new file mode 100644 index 0000000..2d99f66 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/gd_override_functions/popup/virtuals_popup_context.gd @@ -0,0 +1,52 @@ +@tool +extends EditorContextMenuPlugin +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# script-ide: Virtual Popups +# +# Virtual Popups for script-ide addon.godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +const SCENE : PackedScene = preload("res://addons/_Godot-IDE_/plugins/gd_override_functions/popup/virtuals_popup.tscn") +const ICON : Texture = preload("res://addons/_Godot-IDE_/shared_resources/func_virtual.svg") + +func _notification(what: int) -> void: + if what == NOTIFICATION_PREDELETE: + var root : Node = Engine.get_main_loop().root + var virtual_popup : Popup = root.get_node_or_null("_VPOPUP_") + if is_instance_valid(virtual_popup) and !virtual_popup.is_queued_for_deletion(): + virtual_popup.config_update(true) + virtual_popup.queue_free() + +func callback(input : Object) -> void: + var input_script : Script = null + + if input is Script: + input_script = input + elif input is CodeEdit: + var script_editor: ScriptEditor = EditorInterface.get_script_editor() + var scripts_editors : Array[ScriptEditorBase] = script_editor.get_open_script_editors() + var scripts : Array[Script] = script_editor.get_open_scripts() + var iscript : int = -1 + + for x : int in range(scripts_editors.size()): + if scripts_editors[x].get_base_editor() == input: + iscript = x + pass + if iscript > -1 and iscript < scripts.size(): + input_script = scripts[iscript] + + if null == input_script: + push_error("[PLUGIN] Error, can`t get current script - not valid!") + return + + var root : Node = Engine.get_main_loop().root + var virtual_popup : Popup = root.get_node_or_null("_VPOPUP_") + if virtual_popup == null: + virtual_popup = SCENE.instantiate() + virtual_popup.set(&"name", &"_VPOPUP_") + root.add_child(virtual_popup) + virtual_popup.make_tree(input_script) + virtual_popup.popup_centered.call_deferred() + +func _popup_menu(_paths : PackedStringArray) -> void: + add_context_menu_item("Override Virtual Functions", callback, ICON) diff --git a/addons/_Godot-IDE_/plugins/gd_override_functions/popup/virtuals_popup_context.gd.uid b/addons/_Godot-IDE_/plugins/gd_override_functions/popup/virtuals_popup_context.gd.uid new file mode 100644 index 0000000..219eddf --- /dev/null +++ b/addons/_Godot-IDE_/plugins/gd_override_functions/popup/virtuals_popup_context.gd.uid @@ -0,0 +1 @@ +uid://bcfsicur2au8j diff --git a/addons/_Godot-IDE_/plugins/macro-n/context.gd b/addons/_Godot-IDE_/plugins/macro-n/context.gd new file mode 100644 index 0000000..1a989ef --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/context.gd @@ -0,0 +1,65 @@ +extends EditorContextMenuPlugin +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# Macro-N +# ============================================================================= +const INTERFACE_SCRIPT = preload("res://addons/_Godot-IDE_/shared_resources/InterfaceScript.svg") +var _helper : Object = null +var _fragments : Window = null + +var controller : Object = null + + +func _init(helper : Object) -> void: + _helper = helper + +#Override EditorContextMenuPlugin virtual function. +func _popup_menu(_paths : PackedStringArray) -> void: + if controller == null: + controller = ResourceLoader.load("res://addons/_Godot-IDE_/plugins/macro-n/src/gui/controller/ShowTextController.gd").new() + var txt : String = controller.execute() + if txt.is_empty(): + return + add_context_menu_item("Macro-N", _on_save.bind(txt), INTERFACE_SCRIPT) + +func _on_save(_variant : Variant, text : String) -> void: + _helper.call(&"half_life", text, -1) + +func show_macros() -> void: + if !is_instance_valid(_fragments): + var fragment : PackedScene = ResourceLoader.load("res://addons/_Godot-IDE_/plugins/macro-n/src/gui/Fragments/Fragments.tscn") + _fragments = fragment.instantiate() + _helper.add_child(_fragments) + var db : Object = ResourceLoader.load("res://addons/_Godot-IDE_/plugins/macro-n/src/repo/configurator.gd").new() + _fragments.set_dependencies( + [ + ResourceLoader.load("res://addons/_Godot-IDE_/plugins/macro-n/src/app/remove_fragment.gd").new(db), + ResourceLoader.load("res://addons/_Godot-IDE_/plugins/macro-n/src/app/get_all_fragments.gd").new(db), + ResourceLoader.load("res://addons/_Godot-IDE_/plugins/macro-n/src/app/save_fragment.gd").new(db) + ] + ) + + _fragments.on_create.connect(_helper.create_new) + + _fragments.popup_centered() + + +func invoke_macron_bypass() -> void: + if controller == null: + controller = ResourceLoader.load("res://addons/_Godot-IDE_/plugins/macro-n/src/gui/controller/ShowTextController.gd").new() + var txt : String = controller.execute() + txt = txt.strip_edges() + if txt.is_empty(): + return + _helper.call(&"half_life", txt, 1) + +func invoke_macron() -> void: + if controller == null: + controller = ResourceLoader.load("res://addons/_Godot-IDE_/plugins/macro-n/src/gui/controller/ShowTextController.gd").new() + var txt : String = controller.execute() + txt = txt.strip_edges() + if txt.is_empty(): + return + _helper.call(&"half_life", txt, 0) diff --git a/addons/_Godot-IDE_/plugins/macro-n/context.gd.uid b/addons/_Godot-IDE_/plugins/macro-n/context.gd.uid new file mode 100644 index 0000000..0d63db0 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/context.gd.uid @@ -0,0 +1 @@ +uid://cstqqmdlwkth diff --git a/addons/_Godot-IDE_/plugins/macro-n/macro-n.gd b/addons/_Godot-IDE_/plugins/macro-n/macro-n.gd new file mode 100644 index 0000000..dd4b90f --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/macro-n.gd @@ -0,0 +1,112 @@ +extends RefCounted +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# Macro-N +# ============================================================================= + + +var user_path : String = "" +var templates_path : String = "" + +var _pop_warn : ConfirmationDialog + +var _helper : Node = null + +func _init(helper : Node) -> void: + assert(helper != null) + _helper = helper + +func _get_pop() -> Object: + var packed : PackedScene = ResourceLoader.load("res://addons/_Godot-IDE_/plugins/macro-n/context/Macro-N.tscn") + return packed.instantiate() + +func feed() -> void: + var edit : ScriptEditor = EditorInterface.get_script_editor() + + if edit: + var base : ScriptEditorBase = edit.get_current_editor() + if base: + var be : Control = base.get_base_editor() + if be is CodeEdit: + pipe_pop_in(be.text) + + #NO SYTNAX + return + +func pipe_pop_in(txt : String) -> void: + txt = parse_text(txt) + if txt.is_empty(): + print("[Macro-N] Error!, empty syntax!") + return + + var pop : Node = _get_pop() + if !pop.is_inside_tree(): + _helper.add_child(pop) + pop.callback = pipe_save + pop.call(&"show_feed", txt) + +func pipe_save(path : String, txt : String) -> void: + if !DirAccess.dir_exists_absolute(path): + print("[Macro-N]: Can not find dir save path!") + return + + path = path.strip_edges() + if path.is_empty(): + path = "My Macro File" + + txt = parse_text(txt) + + var end : String = user_path.path_join(path + ".mn") + if !FileAccess.file_exists(end): + if !_save(end, txt): + print("[Macro-N] Can not save syntax! ", end) + else: + print("[Macron-N] Saved syntax: ", end) + return + _save_warn(end, txt) + +func _save(end : String, txt : String) -> bool: + var file : FileAccess = FileAccess.open(end, FileAccess.WRITE) + if !file: + return false + return file.store_string(txt) + +func _save_warn(end : String, txt : String) -> void: + if !is_instance_valid(_pop_warn): + _pop_warn = ConfirmationDialog.new() + _pop_warn.title = "Already Exist File, Ovewrite?" + _pop_warn.canceled.connect(func():_pop_warn.queue_free()) + _pop_warn.confirmed.connect( + func(): + _save(end, txt) + _pop_warn.queue_free() + ) + _helper.add_child(_pop_warn) + _pop_warn.popup_centered() + +func parse_text(txt : String) -> String: + var split : PackedStringArray = txt.split("\n", true, 0) + var maxt : Array[int] = [0, 0] + + while split.size() > 0 and split[0].strip_edges().length() == 0: + split.remove_at(0) + + if split.size() == 0: + return "" + + for xline : int in range(split.size()): + var line : String = split[xline] + var indx : int = 0 + var cline : int = mini(xline, 1) + while line.length() > indx and (line[indx] == '\t' or line[indx] == ' '): + indx += 1 + maxt[cline] = maxi(maxt[cline], indx) + + if maxt[0] < maxt[1]: + var st : int = maxt[0] + for xline : int in range(split.size()): + split[xline] = split[xline].substr(st, -1) + + return "\n".join(split) diff --git a/addons/_Godot-IDE_/plugins/macro-n/macro-n.gd.uid b/addons/_Godot-IDE_/plugins/macro-n/macro-n.gd.uid new file mode 100644 index 0000000..86a18bb --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/macro-n.gd.uid @@ -0,0 +1 @@ +uid://burhkdjv1q8bu diff --git a/addons/_Godot-IDE_/plugins/macro-n/plugin.cfg b/addons/_Godot-IDE_/plugins/macro-n/plugin.cfg new file mode 100644 index 0000000..ad31b74 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="Macro-N" +description="Allow generate code by shortcut" +author="Twister" +version="Alpha-1.0" +script="plugin.gd" diff --git a/addons/_Godot-IDE_/plugins/macro-n/plugin.gd b/addons/_Godot-IDE_/plugins/macro-n/plugin.gd new file mode 100644 index 0000000..bd0c34d --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/plugin.gd @@ -0,0 +1,77 @@ +@tool +extends EditorPlugin +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# Macro-N +# ============================================================================= + +const CONTEXT := preload("res://addons/_Godot-IDE_/plugins/macro-n/context.gd") + +var ctx_macron_n : EditorContextMenuPlugin = null +var macron_n : RefCounted = null + +var _c_input : InputEvent = null +var _g_input : InputEvent = null +var _cb_input : InputEvent = null + + +func _enter_tree() -> void: + ctx_macron_n = CONTEXT.new(self) + add_context_menu_plugin(EditorContextMenuPlugin.CONTEXT_SLOT_SCRIPT_EDITOR_CODE, ctx_macron_n) + +func _exit_tree() -> void: + macron_n = null + remove_context_menu_plugin(ctx_macron_n) + +func half_life(txt : String, type : int) -> void: + if !is_instance_valid(macron_n): + macron_n = ResourceLoader.load("res://addons/_Godot-IDE_/plugins/macro-n/src/main.gd").new(self) + macron_n.execute(txt, type) + +func create_new() -> void: + if !is_instance_valid(macron_n): + macron_n = ResourceLoader.load("res://addons/_Godot-IDE_/plugins/macro-n/src/main.gd").new(self) + macron_n.execute("# CODE HERE", 2) + +func _init() -> void: + var input : Variant = IDE.get_config("macro_n", "invoke_input") + if input is InputEvent: + _c_input = input + else: + _c_input = InputEventKey.new() + _c_input.pressed = true + _c_input.ctrl_pressed = true + _c_input.keycode = KEY_E + IDE.set_config("macro_n", "invoke_macro", _c_input) + + input = IDE.get_config("macro_n", "invoke_macro_by_pass") + if input is InputEvent: + _cb_input = input + else: + _cb_input = InputEventKey.new() + _cb_input.pressed = true + _cb_input.ctrl_pressed = true + _cb_input.shift_pressed = true + _cb_input.keycode = KEY_E + IDE.set_config("macro_n", "invoke_macro_by_pass", input) + + input = IDE.get_config("macro_n", "show_all_macro") + if input is InputEvent: + _g_input = input + else: + _g_input = InputEventKey.new() + _g_input.pressed = true + _g_input.alt_pressed = true + _g_input.keycode = KEY_END + IDE.set_config("macro_n", "show_all_macro", _g_input) + +func _input(event: InputEvent) -> void: + if event.is_pressed(): + if event.is_match(_c_input): + ctx_macron_n.invoke_macron() + elif event.is_match(_cb_input): + ctx_macron_n.invoke_macron_bypass() + elif event.is_match(_g_input): + ctx_macron_n.show_macros() diff --git a/addons/_Godot-IDE_/plugins/macro-n/plugin.gd.uid b/addons/_Godot-IDE_/plugins/macro-n/plugin.gd.uid new file mode 100644 index 0000000..775f6c9 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/plugin.gd.uid @@ -0,0 +1 @@ +uid://dx71kxr16b0k5 diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/app/get_all_fragments.gd b/addons/_Godot-IDE_/plugins/macro-n/src/app/get_all_fragments.gd new file mode 100644 index 0000000..65a5865 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/app/get_all_fragments.gd @@ -0,0 +1,23 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/macro-n/src/app/in/IGetAllFragments.gd" +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# Macro-N +# ============================================================================= + +const IFragmentDB := preload("res://addons/_Godot-IDE_/plugins/macro-n/src/app/out/IFragmentDB.gd") + +var _fragment_db : IFragmentDB = null + +func _init(fragment_db : IFragmentDB) -> void: + _fragment_db = fragment_db + +#Implement IGetAllFragments function. +func execute() -> Array[Dictionary]: + return _fragment_db.get_all_fragments() + +#Implement IGetAllFragments function. +func get_keys() -> PackedStringArray: + return _fragment_db.get_data_keys() diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/app/get_all_fragments.gd.uid b/addons/_Godot-IDE_/plugins/macro-n/src/app/get_all_fragments.gd.uid new file mode 100644 index 0000000..0c98a37 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/app/get_all_fragments.gd.uid @@ -0,0 +1 @@ +uid://ccqfm0nk400vq diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/app/get_fragment.gd b/addons/_Godot-IDE_/plugins/macro-n/src/app/get_fragment.gd new file mode 100644 index 0000000..5366c2c --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/app/get_fragment.gd @@ -0,0 +1,21 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/macro-n/src/app/in/IGetFragment.gd" +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# Macro-N +# ============================================================================= + + +const IFragmentDB := preload("res://addons/_Godot-IDE_/plugins/macro-n/src/app/out/IFragmentDB.gd") + +var _fragment_db : IFragmentDB = null + +func _init(fragment_db : IFragmentDB) -> void: + _fragment_db = fragment_db + + +#Implement IGetFragment function. +func execute(shortcut : String) -> Dictionary: + return _fragment_db.get_fragment(shortcut) diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/app/get_fragment.gd.uid b/addons/_Godot-IDE_/plugins/macro-n/src/app/get_fragment.gd.uid new file mode 100644 index 0000000..4ddf3c8 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/app/get_fragment.gd.uid @@ -0,0 +1 @@ +uid://cpk8peml78tct diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/app/in/IGetAllFragments.gd b/addons/_Godot-IDE_/plugins/macro-n/src/app/in/IGetAllFragments.gd new file mode 100644 index 0000000..4aa060b --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/app/in/IGetAllFragments.gd @@ -0,0 +1,17 @@ +@tool +extends RefCounted +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# Macro-N +# ============================================================================= + + +func get_keys() -> PackedStringArray: + push_error("Not supported!") + return [] + +func execute() -> Array[Dictionary]: + push_error("Not supported!") + return [] diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/app/in/IGetAllFragments.gd.uid b/addons/_Godot-IDE_/plugins/macro-n/src/app/in/IGetAllFragments.gd.uid new file mode 100644 index 0000000..143ad9e --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/app/in/IGetAllFragments.gd.uid @@ -0,0 +1 @@ +uid://b00jdghts8a6b diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/app/in/IGetFragment.gd b/addons/_Godot-IDE_/plugins/macro-n/src/app/in/IGetFragment.gd new file mode 100644 index 0000000..90d09b0 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/app/in/IGetFragment.gd @@ -0,0 +1,13 @@ +@tool +extends RefCounted +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# Macro-N +# ============================================================================= + + +func execute(shortcut : String) -> Dictionary: + push_error("Not supported!") + return {} diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/app/in/IGetFragment.gd.uid b/addons/_Godot-IDE_/plugins/macro-n/src/app/in/IGetFragment.gd.uid new file mode 100644 index 0000000..3421f41 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/app/in/IGetFragment.gd.uid @@ -0,0 +1 @@ +uid://br4bwcq3fxweb diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/app/in/IMacro.gd b/addons/_Godot-IDE_/plugins/macro-n/src/app/in/IMacro.gd new file mode 100644 index 0000000..a2af172 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/app/in/IMacro.gd @@ -0,0 +1,13 @@ +@tool +extends RefCounted +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# Macro-N +# ============================================================================= + + +func execute(txt : String) -> String: + push_error("Not supported!") + return "" diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/app/in/IMacro.gd.uid b/addons/_Godot-IDE_/plugins/macro-n/src/app/in/IMacro.gd.uid new file mode 100644 index 0000000..2bc7cbc --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/app/in/IMacro.gd.uid @@ -0,0 +1 @@ +uid://d4dlryhpw7hev diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/app/in/IRemoveFragment.gd b/addons/_Godot-IDE_/plugins/macro-n/src/app/in/IRemoveFragment.gd new file mode 100644 index 0000000..d3bc44c --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/app/in/IRemoveFragment.gd @@ -0,0 +1,13 @@ +@tool +extends RefCounted +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# Macro-N +# ============================================================================= + + +func execute(txt : String) -> int: + push_error("Not supported!") + return -1 diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/app/in/IRemoveFragment.gd.uid b/addons/_Godot-IDE_/plugins/macro-n/src/app/in/IRemoveFragment.gd.uid new file mode 100644 index 0000000..092da65 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/app/in/IRemoveFragment.gd.uid @@ -0,0 +1 @@ +uid://rtemrp027x42 diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/app/in/ISerializerFragments.gd b/addons/_Godot-IDE_/plugins/macro-n/src/app/in/ISerializerFragments.gd new file mode 100644 index 0000000..a330d75 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/app/in/ISerializerFragments.gd @@ -0,0 +1,13 @@ +@tool +extends RefCounted +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# Macro-N +# ============================================================================= + + +func execute(shortcut : String, description : String, content : String) -> int: + push_error("Not supported!") + return -1 diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/app/in/ISerializerFragments.gd.uid b/addons/_Godot-IDE_/plugins/macro-n/src/app/in/ISerializerFragments.gd.uid new file mode 100644 index 0000000..3b4f509 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/app/in/ISerializerFragments.gd.uid @@ -0,0 +1 @@ +uid://dwci52n45a278 diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/app/invoke_macro.gd b/addons/_Godot-IDE_/plugins/macro-n/src/app/invoke_macro.gd new file mode 100644 index 0000000..f219511 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/app/invoke_macro.gd @@ -0,0 +1,54 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/macro-n/src/app/in/IMacro.gd" +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# Macro-N +# ============================================================================= + + +const IFragmentDB = preload("res://addons/_Godot-IDE_/plugins/macro-n/src/app/out/IFragmentDB.gd") +var _db : IFragmentDB + +func _init(db : IFragmentDB) -> void: + _db = db + +#Implement IMacro function. +func execute(txt : String) -> String: + var values : Array[Dictionary] = _db.get_all_fragments() + if values.size() == 0: + return "" + + var rgx : RegEx = RegEx.create_from_string("\\barg(\\d+)\\b") + + for v : Dictionary in values: + var val : String = v["shortcut"] + var _rgx : RegEx = null + _rgx = RegEx.create_from_string(str("(?m)^",rgx.sub(val, "(.*?)", true, 0, -1),"$")) + + if !is_instance_valid(_rgx) or !_rgx.is_valid(): + continue + + if null != _rgx.search(txt): + var input : Array = [] + var out : Dictionary = {} + for x : RegExMatch in rgx.search_all(val, 0, -1): + if x.strings.size() > 1: + out[x.strings[0]] = x.strings[0] + input.append(x.strings[0]) + + var indx : int = 0 + for x : RegExMatch in _rgx.search_all(txt, 0, -1): + for y : int in range(1, x.strings.size(), 1): + var ctnt : String = x.strings[y] + while indx >= input.size(): + input.append(ctnt) + out[input[indx]] = ctnt + indx += 1 + + var nrgx : RegEx = RegEx.create_from_string("\\barg(\\d+)\\b") + var defnrgx : RegEx = RegEx.create_from_string("\\{(\\barg\\d+\\b)\\}") + var content : String = nrgx.sub(v["content"], "{$0}", true) + return defnrgx.sub(content.format(out), "$1", true) + return "" diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/app/invoke_macro.gd.uid b/addons/_Godot-IDE_/plugins/macro-n/src/app/invoke_macro.gd.uid new file mode 100644 index 0000000..ec6a55f --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/app/invoke_macro.gd.uid @@ -0,0 +1 @@ +uid://b7jauusersf4r diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/app/invoke_macro_bypass.gd b/addons/_Godot-IDE_/plugins/macro-n/src/app/invoke_macro_bypass.gd new file mode 100644 index 0000000..94f69f9 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/app/invoke_macro_bypass.gd @@ -0,0 +1,66 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/macro-n/src/app/in/IMacro.gd" +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# Macro-N +# ============================================================================= + +const LIMIT : int = 100 + +const IFragmentDB = preload("res://addons/_Godot-IDE_/plugins/macro-n/src/app/out/IFragmentDB.gd") +var _db : IFragmentDB + +func _init(db : IFragmentDB) -> void: + _db = db + +#Implement IMacro function. +func execute(txt : String) -> String: + var values : Array[Dictionary] = _db.get_all_fragments() + if values.size() == 0: + return "" + + var rgx : RegEx = RegEx.create_from_string("\\barg(\\d+)\\b") + for v : Dictionary in values: + var val : String = v["shortcut"] + var _rgx : RegEx = null + _rgx = RegEx.create_from_string(str("\\s*",rgx.sub(val, "(.*?)", true, 0, -1),"\\s*")) + + if !is_instance_valid(_rgx) or !_rgx.is_valid(): + continue + + if null != _rgx.search(txt): + var input : Array = [] + var out : Dictionary = {} + for x : RegExMatch in rgx.search_all(val, 0, -1): + if x.strings.size() > 1: + out[x.strings[0]] = x.strings[0] + input.append(x.strings[0]) + + var indx : int = 0 + for x : RegExMatch in _rgx.search_all(txt, 0, -1): + for y : int in range(1, x.strings.size(), 1): + var ctnt : String = x.strings[y] + while indx >= input.size(): + input.append(ctnt) + out[input[indx]] = ctnt + indx += 1 + + var nrgx : RegEx = RegEx.create_from_string("\\barg(\\d+)\\b") + var defnrgx : RegEx = RegEx.create_from_string("\\{(\\barg\\d+\\b)\\}") + var content : String = nrgx.sub(v["content"], "{$0}", true) + + var result : String = _rgx.sub(txt, defnrgx.sub(content.format(out), "$1", true), true) + var new_result : String = execute(result) + var _out : int = LIMIT + + while !new_result.is_empty() and result != new_result and _out > 0: + result = new_result + new_result = execute(new_result) + _out -= 1 + + if _out == 0: + printerr("Macro overflow error!") + return result + return "" diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/app/invoke_macro_bypass.gd.uid b/addons/_Godot-IDE_/plugins/macro-n/src/app/invoke_macro_bypass.gd.uid new file mode 100644 index 0000000..285d0ef --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/app/invoke_macro_bypass.gd.uid @@ -0,0 +1 @@ +uid://curvq1o31f5cx diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/app/out/IFragmentDB.gd b/addons/_Godot-IDE_/plugins/macro-n/src/app/out/IFragmentDB.gd new file mode 100644 index 0000000..20d4947 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/app/out/IFragmentDB.gd @@ -0,0 +1,28 @@ +@tool +extends RefCounted +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# Macro-N +# ============================================================================= + +func save_fragment(shortcut : String, description : String, full_text : String) -> int: + push_error("Not supported!") + return -1 + +func get_fragment(shortcut : String) -> Dictionary: + push_error("Not supported!") + return {} + +func get_all_fragments() -> Array[Dictionary]: + push_error("Not supported!") + return [] + +func get_data_keys() -> PackedStringArray: + push_error("Not supported!") + return [] + +func remove(shortcut : String) -> int: + push_error("Not supported!") + return -1 diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/app/out/IFragmentDB.gd.uid b/addons/_Godot-IDE_/plugins/macro-n/src/app/out/IFragmentDB.gd.uid new file mode 100644 index 0000000..74e5b24 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/app/out/IFragmentDB.gd.uid @@ -0,0 +1 @@ +uid://bqt2ahh581vvv diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/app/remove_fragment.gd b/addons/_Godot-IDE_/plugins/macro-n/src/app/remove_fragment.gd new file mode 100644 index 0000000..e38bfae --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/app/remove_fragment.gd @@ -0,0 +1,19 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/macro-n/src/app/in/IRemoveFragment.gd" +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# Macro-N +# ============================================================================= + +const IFragmentDB := preload("res://addons/_Godot-IDE_/plugins/macro-n/src/app/out/IFragmentDB.gd") + +var _fragment_db : IFragmentDB = null + +func _init(fragment_db : IFragmentDB) -> void: + _fragment_db = fragment_db + +#Implement IRemoveFragment function. +func execute(txt : String) -> int: + return _fragment_db.remove(txt) diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/app/remove_fragment.gd.uid b/addons/_Godot-IDE_/plugins/macro-n/src/app/remove_fragment.gd.uid new file mode 100644 index 0000000..2f32e93 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/app/remove_fragment.gd.uid @@ -0,0 +1 @@ +uid://cts7bspkw8xjg diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/app/save_fragment.gd b/addons/_Godot-IDE_/plugins/macro-n/src/app/save_fragment.gd new file mode 100644 index 0000000..3a4aa8a --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/app/save_fragment.gd @@ -0,0 +1,27 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/macro-n/src/app/in/ISerializerFragments.gd" +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# Macro-N +# ============================================================================= + +const IFragmentDB := preload("res://addons/_Godot-IDE_/plugins/macro-n/src/app/out/IFragmentDB.gd") + +var _fragment_db : IFragmentDB = null + +func _init(fragment_db : IFragmentDB) -> void: + _fragment_db = fragment_db + + + +#Implement ISerializerFragments function. +func execute(shortcut : String, description : String, content : String) -> int: + description = description.strip_edges() + shortcut = shortcut.strip_edges() + + var result : int = _fragment_db.save_fragment(shortcut, description, content) + if OK != result: + push_error("On error on try save macro fragment!") + return result diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/app/save_fragment.gd.uid b/addons/_Godot-IDE_/plugins/macro-n/src/app/save_fragment.gd.uid new file mode 100644 index 0000000..816b3ba --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/app/save_fragment.gd.uid @@ -0,0 +1 @@ +uid://duou0e0hh4e7t diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/core/fragment.gd b/addons/_Godot-IDE_/plugins/macro-n/src/core/fragment.gd new file mode 100644 index 0000000..3224847 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/core/fragment.gd @@ -0,0 +1,13 @@ +@tool +extends RefCounted +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# Macro-N +# ============================================================================= + +var shortcut : String +var tittle : String +var description : String +var text : String diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/core/fragment.gd.uid b/addons/_Godot-IDE_/plugins/macro-n/src/core/fragment.gd.uid new file mode 100644 index 0000000..81bf762 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/core/fragment.gd.uid @@ -0,0 +1 @@ +uid://dwmbc85wlymty diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/gui/Fragments/Fragments.tscn b/addons/_Godot-IDE_/plugins/macro-n/src/gui/Fragments/Fragments.tscn new file mode 100644 index 0000000..fd1e9eb --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/gui/Fragments/Fragments.tscn @@ -0,0 +1,81 @@ +[gd_scene load_steps=5 format=3 uid="uid://ckn2qdpg5fs5y"] + +[ext_resource type="Script" uid="uid://bio4l72bwqcsi" path="res://addons/_Godot-IDE_/plugins/macro-n/src/gui/Fragments/fragments.gd" id="1_4jc8e"] +[ext_resource type="Script" uid="uid://b4ypyfc1c0ybj" path="res://addons/_Godot-IDE_/plugins/macro-n/src/gui/util/Button.gd" id="2_k3ugs"] +[ext_resource type="Texture2D" uid="uid://ckc3yk6f8y3ob" path="res://addons/_Godot-IDE_/shared_resources/func_public.svg" id="2_r7fa2"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_r7fa2"] +content_margin_left = 5.0 +content_margin_top = 5.0 +content_margin_right = 5.0 +content_margin_bottom = 5.0 +bg_color = Color(0.1155, 0.132, 0.1595, 1) +corner_detail = 1 +anti_aliasing = false + +[node name="Fragments" type="Window" node_paths=PackedStringArray("container")] +title = "Show All Macros" +initial_position = 4 +size = Vector2i(1536, 864) +wrap_controls = true +transient = true +transient_to_focused = true +exclusive = true +script = ExtResource("1_4jc8e") +container = NodePath("PanelContainer/MarginContainer/VBoxContainer/ScrollContainer/GridContainer") + +[node name="PanelContainer" type="PanelContainer" parent="."] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_r7fa2") + +[node name="MarginContainer" type="MarginContainer" parent="PanelContainer"] +layout_mode = 2 +theme_override_constants/margin_left = 8 +theme_override_constants/margin_top = 8 +theme_override_constants/margin_right = 8 +theme_override_constants/margin_bottom = 8 + +[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/MarginContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +text = "All Shortucts" +horizontal_alignment = 1 +uppercase = true + +[node name="HSeparator2" type="HSeparator" parent="PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 + +[node name="ScrollContainer" type="ScrollContainer" parent="PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="GridContainer" type="GridContainer" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +columns = 7 + +[node name="HSeparator" type="HSeparator" parent="PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 16 + +[node name="create" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Create New" +icon = ExtResource("2_r7fa2") +script = ExtResource("2_k3ugs") + +[node name="close" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Close" +script = ExtResource("2_k3ugs") diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/gui/Fragments/component/Edit.tscn b/addons/_Godot-IDE_/plugins/macro-n/src/gui/Fragments/component/Edit.tscn new file mode 100644 index 0000000..3133bcc --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/gui/Fragments/component/Edit.tscn @@ -0,0 +1,83 @@ +[gd_scene load_steps=5 format=3 uid="uid://dt1pjig5ml6we"] + +[ext_resource type="Script" uid="uid://ctoxe1fxxiuc1" path="res://addons/_Godot-IDE_/plugins/macro-n/src/gui/Fragments/component/edit.gd" id="1_0vdlq"] +[ext_resource type="Script" uid="uid://b4ypyfc1c0ybj" path="res://addons/_Godot-IDE_/plugins/macro-n/src/gui/util/Button.gd" id="2_h73ec"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_leugs"] +content_margin_left = 5.0 +content_margin_top = 5.0 +content_margin_right = 5.0 +content_margin_bottom = 5.0 +bg_color = Color(0.1155, 0.132, 0.1595, 1) +corner_detail = 1 +anti_aliasing = false + +[sub_resource type="GDScriptSyntaxHighlighter" id="GDScriptSyntaxHighlighter_h73ec"] + +[node name="Edit" type="Window" node_paths=PackedStringArray("update_btn", "base_edit", "container")] +position = Vector2i(0, 36) +size = Vector2i(500, 500) +transient = true +transient_to_focused = true +exclusive = true +script = ExtResource("1_0vdlq") +update_btn = NodePath("MarginContainer/MarginContainer/VBoxContainer/HBoxContainer/update") +base_edit = NodePath("MarginContainer/MarginContainer/CodeEdit") +container = NodePath("MarginContainer/MarginContainer/VBoxContainer/ScrollContainer") + +[node name="MarginContainer" type="PanelContainer" parent="."] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_leugs") + +[node name="MarginContainer" type="MarginContainer" parent="MarginContainer"] +layout_mode = 2 +theme_override_constants/margin_left = 4 +theme_override_constants/margin_top = 4 +theme_override_constants/margin_right = 4 +theme_override_constants/margin_bottom = 4 + +[node name="CodeEdit" type="CodeEdit" parent="MarginContainer/MarginContainer"] +visible = false +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +syntax_highlighter = SubResource("GDScriptSyntaxHighlighter_h73ec") + +[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/MarginContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="MarginContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +text = "Edit Content" +horizontal_alignment = 1 + +[node name="HSeparator" type="HSeparator" parent="MarginContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 + +[node name="ScrollContainer" type="ScrollContainer" parent="MarginContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="HSeparator2" type="HSeparator" parent="MarginContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 8 + +[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 12 + +[node name="close" type="Button" parent="MarginContainer/MarginContainer/VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Close" +script = ExtResource("2_h73ec") + +[node name="update" type="Button" parent="MarginContainer/MarginContainer/VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Update" +script = ExtResource("2_h73ec") diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/gui/Fragments/component/edit.gd b/addons/_Godot-IDE_/plugins/macro-n/src/gui/Fragments/component/edit.gd new file mode 100644 index 0000000..3789061 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/gui/Fragments/component/edit.gd @@ -0,0 +1,100 @@ +@tool +extends Window +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# Macro-N +# ============================================================================= + + +@export var update_btn : Button +@export var base_edit : CodeEdit +@export var code_edit : CodeEdit +@export var container : Control + +var _origin : Object = null + +var _code : String = "" + +func _get_edit() -> CodeEdit: + var editor : ScriptEditor = EditorInterface.get_script_editor() + if editor: + var _editor : Control = editor.get_current_editor().get_base_editor() + if _editor is CodeEdit: + return _editor.duplicate(0) + + return CodeEdit.new() + +func _on_change_txt() -> void: + base_edit.text = code_edit.text + +func _ready() -> void: + close_requested.connect(close) + + var res : CodeHighlighter = ResourceLoader.load("uid://cyenwroye7tue").new() + + res.set_base(base_edit.syntax_highlighter) + res.set_rgx(RegEx.create_from_string("\\barg\\d+\\b")) + + if code_edit == null: + code_edit = _get_edit() + container.add_child(code_edit) + code_edit.size_flags_horizontal = Control.SIZE_EXPAND_FILL + code_edit.size_flags_vertical = Control.SIZE_EXPAND_FILL + + + code_edit.syntax_highlighter = res + code_edit.text_changed.connect(_on_change_txt) + + var control : Control = EditorInterface.get_base_control() + if !control: + return + get_child(0). add_theme_stylebox_override(&"panel", control.get_theme_stylebox(&"panel", &"")) + +func set_origin(o : Object) -> void: + _origin = o + +func close() -> void: + queue_free() + +func update() -> void: + var pop : ConfirmationDialog = ConfirmationDialog.new() + pop.title = "Macro-N" + pop.size.x = 350 + + pop.dialog_text = "Are you sure update?" + + for x : Node in pop.get_children(true): + if x is Label: + x.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + + pop.confirmed.connect(_on_confirm) + EditorInterface.popup_dialog_centered(pop) + +func _on_confirm() -> void: + _origin.set_meta(&"content", code_edit.text) + + var pop : AcceptDialog = AcceptDialog.new() + pop.title = "Macro-N" + pop.size.x = 350 + pop.dialog_text = "Macro content update!\nRemember press 'UPDATE' button for save!" + + for x : Node in pop.get_children(true): + if x is Label: + x.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + + pop.close_requested.connect(close) + pop.confirmed.connect(close) + EditorInterface.popup_dialog_centered(pop) + +func _on_change() -> void: + update_btn.disabled = _code == code_edit.text + +func set_code(code : String) -> void: + _code = code + base_edit.text = _code + code_edit.text = _code + + code_edit.text_changed.connect(_on_change) + update_btn.disabled = true diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/gui/Fragments/component/edit.gd.uid b/addons/_Godot-IDE_/plugins/macro-n/src/gui/Fragments/component/edit.gd.uid new file mode 100644 index 0000000..1d21ac5 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/gui/Fragments/component/edit.gd.uid @@ -0,0 +1 @@ +uid://ctoxe1fxxiuc1 diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/gui/Fragments/fragments.gd b/addons/_Godot-IDE_/plugins/macro-n/src/gui/Fragments/fragments.gd new file mode 100644 index 0000000..c31ab8b --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/gui/Fragments/fragments.gd @@ -0,0 +1,382 @@ +@tool +extends Window +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# Macro-N +# ============================================================================= + + +const IGetAllFragments = preload("res://addons/_Godot-IDE_/plugins/macro-n/src/app/in/IGetAllFragments.gd") +const IRemoveFragment = preload("res://addons/_Godot-IDE_/plugins/macro-n/src/app/in/IRemoveFragment.gd") +const ISerializerFragments = preload("res://addons/_Godot-IDE_/plugins/macro-n/src/app/in/ISerializerFragments.gd") + +const SCRIPT = preload("res://addons/_Godot-IDE_/shared_resources/Script.svg") +const METHOD_OVERRIDE = preload("res://addons/_Godot-IDE_/shared_resources/MethodOverride.svg") +const DOT = preload("res://addons/_Godot-IDE_/shared_resources/dot.svg") + +const EDIT = preload("res://addons/_Godot-IDE_/plugins/macro-n/src/gui/Fragments/component/Edit.tscn") + +signal on_create() + +@export var container : Node = null + +var _GetAllFragments : IGetAllFragments = null +var _RemoveFragment : IRemoveFragment = null +var _SerializerFragments : ISerializerFragments = null + +func _ready() -> void: + set_process(false) + size = IDE.get_screen_size(0.8) + size.x = maxi(size.x, 300) + size.y = maxi(size.y, 300) + about_to_popup.connect(_about_to_popup) + close_requested.connect(close) + + var control : Control = EditorInterface.get_base_control() + if !control: + return + get_child(0). add_theme_stylebox_override(&"panel", control.get_theme_stylebox(&"panel", &"")) + + + +func close() -> void: + queue_free() + +func _about_to_popup() -> void: + set_process(false) + _make_components(container) + +func set_dependencies(res : Array[Variant]) -> void: + for o : Variant in res: + if o is IGetAllFragments: + _GetAllFragments = o + elif o is IRemoveFragment: + _RemoveFragment = o + elif o is ISerializerFragments: + _SerializerFragments = o + if !is_instance_valid(_RemoveFragment) or !is_instance_valid(_GetAllFragments) or !is_instance_valid(_SerializerFragments): + push_warning("Not defined all dependencies!") + +func _make_component(root : Node, data : Dictionary) -> void: + var shortcut : LineEdit = LineEdit.new() + var copy_shortcut : Button = Button.new() + + + var description : LineEdit = LineEdit.new() + var copy_clipboard : Button = Button.new() + var show_content : Button = Button.new() + var update_show_content : Button = Button.new() + var erase_show_content : Button = Button.new() + + + shortcut.text = data["shortcut"] + description.text = data["description"] + show_content.text = "" + update_show_content.text = "" + erase_show_content.text = "" + copy_shortcut.text = "" + copy_clipboard.text = "" + + copy_shortcut.disabled = shortcut.text.length() < 1 + copy_shortcut.tooltip_text = "Copy Macro Shorcut Button" + copy_clipboard.tooltip_text = "Copy Macro Content Button" + + show_content.alignment = HORIZONTAL_ALIGNMENT_CENTER + update_show_content.alignment = HORIZONTAL_ALIGNMENT_CENTER + erase_show_content.alignment = HORIZONTAL_ALIGNMENT_CENTER + + shortcut.set_meta(&"origin", shortcut.text) + description.set_meta(&"origin", description.text) + show_content.set_meta(&"origin", data["content"]) + show_content.set_meta(&"content", data["content"]) + + shortcut.tooltip_text = shortcut.text + description.tooltip_text = description.text + show_content.tooltip_text = show_content.text + + shortcut.text_changed.connect(_on_text.bind(shortcut)) + description.text_changed.connect(_on_text.bind(description)) + + show_content.icon = SCRIPT + update_show_content.icon = METHOD_OVERRIDE + erase_show_content.icon = DOT + copy_clipboard.icon = DOT + copy_shortcut.icon = DOT + + copy_clipboard.icon_alignment = HORIZONTAL_ALIGNMENT_CENTER + copy_shortcut.icon_alignment = HORIZONTAL_ALIGNMENT_CENTER + erase_show_content.icon_alignment = HORIZONTAL_ALIGNMENT_CENTER + update_show_content.icon_alignment = HORIZONTAL_ALIGNMENT_CENTER + show_content.icon_alignment = HORIZONTAL_ALIGNMENT_CENTER + + copy_shortcut.modulate = Color.GREEN + copy_clipboard.modulate = Color.SKY_BLUE + erase_show_content.modulate = Color.RED + + copy_shortcut.pressed.connect(_copy.bind(shortcut)) + copy_clipboard.pressed.connect(_copy.bind(show_content)) + show_content.pressed.connect(_on_content.bind(show_content)) + update_show_content.pressed.connect(_on_update.bind(shortcut, description, show_content)) + erase_show_content.pressed.connect(_on_erase.bind(shortcut)) + + root.add_child(shortcut) + root.add_child(copy_shortcut) + root.add_child(description) + root.add_child(copy_clipboard) + root.add_child(show_content) + root.add_child(update_show_content) + root.add_child(erase_show_content) + + shortcut.custom_minimum_size.x = 350.0 + description.size_flags_horizontal = Control.SIZE_EXPAND_FILL + +func _copy(content : Node) -> void: + var txt_content : String = "" + var type : String = "" + if content is Button: + if !content.has_meta(&"content"): + printerr("Not has content!") + return + + type = "Content" + + txt_content = content.get_meta(&"content") + + elif content is LineEdit: + + if content.text.length() == 0: + printerr("Not has shortcut content!") + return + + type = "Shortcut" + txt_content = content.text + + var copy : bool = false + var txt : String = "" + + if txt_content.length() > 0: + DisplayServer.clipboard_set(txt_content) + txt = ("Macro {0} copied to clipboard!".format([type])) + else: + txt = ("Error, Macro {0} not copied to clipboard!".format([type])) + + var pop : AcceptDialog = AcceptDialog.new() + + pop.title = "Macro-N" + pop.dialog_text = txt.capitalize() + + for x : Node in pop.get_children(true): + if x is Label: + x.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + + EditorInterface.popup_dialog_centered(pop) + +var _edit : Window + +func _on_content(content : Node) -> void: + if content.has_meta(&"content"): + var txt : String = content.get_meta(&"content") + + if !is_instance_valid(_edit): + _edit = EDIT.instantiate() + add_child(_edit) + _edit.set_origin(content) + _edit.set_code(txt) + _edit.popup_centered() + else: + printerr("Not defined content!! {0}".format([content])) + +func _on_update(shortcut : LineEdit, description : LineEdit, show_content : Node) -> void: + for x : Node in [shortcut, description, show_content]: + if !x.has_meta(&"origin"): + printerr("Not defined origin content! {0}".format([x])) + return + + var changes : PackedStringArray = [] + + if shortcut.text != shortcut.get_meta(&"origin"): + changes.append("shortcut".capitalize()) + if description.text != description.get_meta(&"origin"): + changes.append("description".capitalize()) + if show_content.get_meta(&"content") != show_content.get_meta(&"origin"): + changes.append("macro_content".capitalize()) + + + var pop : AcceptDialog = null + + if changes.size() == 0: + pop = AcceptDialog.new() + else: + pop = ConfirmationDialog.new() + pop.confirmed.connect(_on_confirm_update.bind(shortcut, description, show_content)) + + pop.title = "Macro-N" + + pop.dialog_text = "None changes for be update!" + + if changes.size() > 0 : + pop.dialog_text = "Changes to update:\n{0}".format([", ".join(changes)]) + + for x : Node in pop.get_children(true): + if x is Label: + x.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + + EditorInterface.popup_dialog_centered(pop) + + +func _on_confirm_update(shortcut : LineEdit, description : LineEdit, show_content : Control) -> void: + var done : bool = false + var origin : String = shortcut.get_meta(&"origin") + if shortcut.text != origin: + if OK == _RemoveFragment.execute(origin): + if OK == _SerializerFragments.execute(shortcut.text, description.text, show_content.get_meta(&"content")): + shortcut.set_meta(&"origin", shortcut.text) + description.set_meta(&"origin", description.text) + done = true + else: + printerr("Error, can not save!") + else: + if OK == _SerializerFragments.execute(shortcut.text, description.text, show_content.get_meta(&"content")): + shortcut.set_meta(&"origin", shortcut.text) + description.set_meta(&"origin", description.text) + done = true + else: + printerr("Error, can not save!") + + var pop : AcceptDialog = AcceptDialog.new() + pop.title = "Macro-N" + + if done: + pop.dialog_text = "Macro updated success!" + else: + pop.dialog_text = "Error on trying update Macro!" + + for x : Node in pop.get_children(true): + if x is Label: + x.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + + EditorInterface.popup_dialog_centered(pop) + + _update() + +func _update() -> void: + set_process(true) + +func _process(delta: float) -> void: + set_process(false) + _make_components(container) + +func _on_erase(item : LineEdit) -> void: + var id : String = "" + if item.has_meta(&"origin"): + id = item.get_meta(&"origin") + + var pop : ConfirmationDialog = ConfirmationDialog.new() + pop.title = "Macro-N" + + if id.is_empty(): + pop.dialog_text = "Are you sure to remove?" + else: + pop.dialog_text = "Are you sure to remove?\n[{0}]".format([id]) + + for x : Node in pop.get_children(true): + if x is Label: + x.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + + pop.confirmed.connect(_on_confirm_erase.bind(item)) + + EditorInterface.popup_dialog_centered(pop) + +func _on_confirm_erase(item : LineEdit) -> void: + var id : String = "" + if item.has_meta(&"origin"): + id = item.get_meta(&"origin") + else: + id = item.text + if _RemoveFragment.execute(id) == OK: + var pop : AcceptDialog = AcceptDialog.new() + pop.title = "Macro-N" + + pop.dialog_text = "Removed Macro Success!" + + for x : Node in pop.get_children(true): + if x is Label: + x.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + + EditorInterface.popup_dialog_centered(pop) + + _update() + else: + var pop : AcceptDialog = AcceptDialog.new() + pop.title = "Macro-N" + + if id.is_empty(): + pop.dialog_text = "Error on trying find Macro for be remove!" + else: + pop.dialog_text = "Error on trying remove Macro:\n{0}".format([id]) + + for x : Node in pop.get_children(true): + if x is Label: + x.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + + EditorInterface.popup_dialog_centered(pop) + + +func _make_tittle_component(root : Node) -> void: + var shortcut : Label = Label.new() + var copy_shortcut : Label = Label.new() + var description : Label = Label.new() + var show_content : Label = Label.new() + var copy_content : Label = Label.new() + var update_show_content : Label = Label.new() + var erase_show_content : Label = Label.new() + + copy_shortcut.text = "Copy Shorcut" + shortcut.text = "Shortcut" + description.text = "Description" + show_content.text = "Show Content" + update_show_content.text = "Update" + erase_show_content.text = "Erase" + copy_content.text = "Copy Content" + + for x : Label in [shortcut, copy_shortcut, description, copy_content, show_content, update_show_content, erase_show_content]: + x.vertical_alignment = VERTICAL_ALIGNMENT_CENTER + x.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + + root.add_child(x) + +func _on_text(txt : String, item : Control) -> void: + item.set(&"tooltip_text", txt) + +func _make_components(root : Node) -> void: + + if !is_instance_valid(root): + printerr("Not define container!") + return + + for x : Node in root.get_children(): + x.queue_free() + + var objects : Array[Dictionary] = _GetAllFragments.execute() + if objects.size() < 1: + var label : Label = Label.new() + label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + label.size_flags_horizontal = Control.SIZE_EXPAND_FILL + label.size_flags_vertical = Control.SIZE_EXPAND_FILL + label.text = "You don't have any macros saved yet!" + root.add_child(label) + return + + _make_tittle_component(root) + + for o : Dictionary in objects: + var val : String = o["shortcut"] + if val.is_empty(): + continue + _make_component(root, o) + +func create() -> void: + on_create.emit() + close() diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/gui/Fragments/fragments.gd.uid b/addons/_Godot-IDE_/plugins/macro-n/src/gui/Fragments/fragments.gd.uid new file mode 100644 index 0000000..e135c0d --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/gui/Fragments/fragments.gd.uid @@ -0,0 +1 @@ +uid://bio4l72bwqcsi diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/gui/SweetOne/SweetOne.gd b/addons/_Godot-IDE_/plugins/macro-n/src/gui/SweetOne/SweetOne.gd new file mode 100644 index 0000000..0ebf27f --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/gui/SweetOne/SweetOne.gd @@ -0,0 +1,230 @@ +@tool +extends Window +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# Macro-N +# ============================================================================= + + +const IGetAllFragments := preload("res://addons/_Godot-IDE_/plugins/macro-n/src/app/in/IGetAllFragments.gd") +const IGetFragment := preload("res://addons/_Godot-IDE_/plugins/macro-n/src/app/in/IGetFragment.gd") +const ISerializerFragment := preload("res://addons/_Godot-IDE_/plugins/macro-n/src/app/in/ISerializerFragments.gd") + +const EDITOR_KEY : String = "content" +const ID_KEY : String = "shortcut" + +@export var fragment_data_container : Control = null +@export var base_editor : CodeEdit = null + +var _GetAllFragments : IGetAllFragments = null +var _GetFragment : IGetFragment = null +var _SerializerFragment : ISerializerFragment = null + + +var _content_container : CodeEdit = null +var _id_container : LineEdit = null + +func _ready() -> void: + close_requested.connect(close) + + var control : Control = EditorInterface.get_base_control() + if !control: + return + get_child(0). add_theme_stylebox_override(&"panel", control.get_theme_stylebox(&"panel", &"")) + + +func close() -> void: + queue_free() + +func set_dependencies(dependencies : Array) -> void: + for dp : Variant in dependencies: + if dp is IGetAllFragments: + _GetAllFragments = dp + elif dp is IGetFragment: + _GetFragment = dp + elif dp is ISerializerFragment: + _SerializerFragment = dp + for x : Object in [_GetAllFragments, _GetFragment, _SerializerFragment]: + if !is_instance_valid(x): + push_error("[Macro-N] Error on get dependencies!") + return + _setup() + +func accept() -> void: + var pray2god : bool = false + var errors : PackedStringArray = [] + + if !is_instance_valid(_id_container) or !is_instance_valid(_content_container): + pray2god = true + else: + _id_container.text = _id_container.text.strip_edges() + for x : Node in fragment_data_container.get_children(): + if x is LineEdit or x is CodeEdit: + if x.text.is_empty(): + pray2god = true + errors.append(x.name) + + if pray2god: + var pop : AcceptDialog = AcceptDialog.new() + pop.title = "🔥 This is fine..." + pop.size.x = 500 + + if errors.size() > 0: + pop.dialog_text = "Check that the values are set correctly:\n{0}".format([", ".join(errors)]) + else: + pop.dialog_text = "An error occurred during processing!" #Get me out, Latom. + + for x : Node in pop.get_children(true): + if x is Label: + x.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + + EditorInterface.popup_dialog_centered(pop) + return + + var shortcut : String = _id_container.text + + var text : String = "Create new Marcro? \n'{0}'".format([shortcut]) + + var window : ConfirmationDialog = ConfirmationDialog.new() + window.title = "Hey, Listen!" + + window.get_ok_button().self_modulate = Color.GREEN + window.get_cancel_button().self_modulate = Color.RED + + if !_GetFragment.execute(shortcut)["shortcut"].is_empty(): + text = "The Macro '{0}' already exists!\nyou want to overwrite?".format([shortcut]) + window.get_ok_button().self_modulate = Color.ORANGE + window.ok_button_text = "Overwrite" + + window.dialog_text = text + + for x : Node in window.get_children(true): + if x is Label: + x.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + + + window.confirmed.connect(_save) + EditorInterface.popup_dialog_centered(window) + +func _save() -> void: + if !is_instance_valid(_id_container) or !is_instance_valid(_content_container): + return + + var data : Dictionary[String, String] = {} + for x : Node in fragment_data_container.get_children(): + if x is LineEdit or x is CodeEdit: + data[x.name] = x.text + + var keys : PackedStringArray = _GetAllFragments.get_keys() + if data.has_all(_GetAllFragments.get_keys()): + var text : String = "The Macro {0} is saved!".format([data[keys[0]]]) + var result : int = _SerializerFragment.execute( + data[keys[0]], + data[keys[1]], + data[keys[2]] + ) + if OK != result: + text = "An error on try save Macro: {0}".format([data[keys[0]]]) + else: + close.call_deferred() + + var window : AcceptDialog = AcceptDialog.new() + window.title = "Message Result" + window.dialog_text = text + + for x : Node in window.get_children(true): + if x is Label: + x.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + EditorInterface.popup_dialog_centered(window) + else: + push_error("[Macro-N] Error, not valid keys!") + close() + +func set_content(txt : String) -> void: + if is_instance_valid(_content_container): + base_editor.text = parse_text(txt) + _content_container.text = base_editor.text + else: + push_warning("Can not found editor container!") + +func parse_text(txt : String) -> String: + var split : PackedStringArray = txt.split("\n", true, 0) + var maxt : Array[int] = [0, 0] + + while split.size() > 0 and split[0].strip_edges().length() == 0: + split.remove_at(0) + + if split.size() == 0: + return "" + + for xline : int in range(split.size()): + var line : String = split[xline] + var indx : int = 0 + var cline : int = mini(xline, 1) + while line.length() > indx and (line[indx] == '\t' or line[indx] == ' '): + indx += 1 + maxt[cline] = maxi(maxt[cline], indx) + + if maxt[0] < maxt[1]: + var st : int = maxt[0] + for xline : int in range(split.size()): + split[xline] = split[xline].substr(st, -1) + + return "\n".join(split) + +func _on_change_txt() -> void: + base_editor.text = _content_container.text + +func _get_edit() -> CodeEdit: + var editor : ScriptEditor = EditorInterface.get_script_editor() + if editor: + var _editor : Control = editor.get_current_editor().get_base_editor() + if _editor is CodeEdit: + return _editor.duplicate(0) + + return CodeEdit.new() + +func _setup() -> void: + var keys : PackedStringArray = _GetAllFragments.get_keys() + for x : Node in fragment_data_container.get_children(): + x.name = "_" + x.name + x.queue_free() + + for k : String in keys: + if k == EDITOR_KEY: + var control : CodeEdit = _get_edit() + var res : CodeHighlighter = ResourceLoader.load("uid://cyenwroye7tue").new() + + res.set_base(base_editor.syntax_highlighter) + res.set_rgx(RegEx.create_from_string("\\barg\\d+\\b")) + + fragment_data_container.add_child(control) + control.syntax_highlighter = res + control.text_changed.connect(_on_change_txt) + + control.name = k + + control.size_flags_horizontal = Control.SIZE_EXPAND_FILL + control.size_flags_vertical = Control.SIZE_EXPAND_FILL + _content_container = control + continue + + var tittle: Label = Label.new() + var edit : LineEdit = LineEdit.new() + tittle.text = k.capitalize() + edit.placeholder_text = "Please set {0} value".format([tittle.text]) + + edit.name = k + + fragment_data_container.add_child(tittle) + fragment_data_container.add_child(edit) + + tittle.size_flags_horizontal = Control.SIZE_EXPAND_FILL + edit.size_flags_horizontal = Control.SIZE_EXPAND_FILL + + if k == ID_KEY: + _id_container = edit + + size = IDE.get_screen_size(0.75) diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/gui/SweetOne/SweetOne.gd.uid b/addons/_Godot-IDE_/plugins/macro-n/src/gui/SweetOne/SweetOne.gd.uid new file mode 100644 index 0000000..55dbd70 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/gui/SweetOne/SweetOne.gd.uid @@ -0,0 +1 @@ +uid://bnkrnw0nf5fhm diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/gui/SweetOne/SweetOne.tscn b/addons/_Godot-IDE_/plugins/macro-n/src/gui/SweetOne/SweetOne.tscn new file mode 100644 index 0000000..bc2ed83 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/gui/SweetOne/SweetOne.tscn @@ -0,0 +1,82 @@ +[gd_scene load_steps=5 format=3 uid="uid://b25j4mq6e1fso"] + +[ext_resource type="Script" uid="uid://bnkrnw0nf5fhm" path="res://addons/_Godot-IDE_/plugins/macro-n/src/gui/SweetOne/SweetOne.gd" id="1_axr5e"] +[ext_resource type="Script" uid="uid://b4ypyfc1c0ybj" path="res://addons/_Godot-IDE_/plugins/macro-n/src/gui/util/Button.gd" id="2_x0cqq"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_3tb81"] +content_margin_left = 6.0 +content_margin_top = 6.0 +content_margin_right = 6.0 +content_margin_bottom = 6.0 +bg_color = Color(0.1155, 0.132, 0.1595, 1) +corner_detail = 1 +anti_aliasing = false + +[sub_resource type="GDScriptSyntaxHighlighter" id="GDScriptSyntaxHighlighter_x0cqq"] + +[node name="SweetOne" type="Window" node_paths=PackedStringArray("fragment_data_container", "base_editor")] +title = "Plugin Macro-N" +initial_position = 4 +size = Vector2i(500, 500) +exclusive = true +script = ExtResource("1_axr5e") +fragment_data_container = NodePath("PanelContainer/MarginContainer/VBoxContainer/VBoxContainer") +base_editor = NodePath("PanelContainer/MarginContainer/CodeEdit") + +[node name="PanelContainer" type="PanelContainer" parent="."] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_3tb81") + +[node name="MarginContainer" type="MarginContainer" parent="PanelContainer"] +layout_mode = 2 +theme_override_constants/margin_left = 4 +theme_override_constants/margin_top = 4 +theme_override_constants/margin_right = 4 +theme_override_constants/margin_bottom = 4 + +[node name="CodeEdit" type="CodeEdit" parent="PanelContainer/MarginContainer"] +visible = false +layout_mode = 2 +syntax_highlighter = SubResource("GDScriptSyntaxHighlighter_x0cqq") + +[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/MarginContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +text = "Macro-N" +horizontal_alignment = 1 + +[node name="HSeparator" type="HSeparator" parent="PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="HSeparator2" type="HSeparator" parent="PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 8 + +[node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 16 + +[node name="close" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/HBoxContainer"] +modulate = Color(1, 0.392157, 1, 1) +layout_mode = 2 +size_flags_horizontal = 3 +text = "Close" +script = ExtResource("2_x0cqq") + +[node name="accept" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/HBoxContainer"] +modulate = Color(0.392157, 1, 1, 1) +layout_mode = 2 +size_flags_horizontal = 3 +text = "Accept" +script = ExtResource("2_x0cqq") diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/gui/controller/ShowTextController.gd b/addons/_Godot-IDE_/plugins/macro-n/src/gui/controller/ShowTextController.gd new file mode 100644 index 0000000..276416a --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/gui/controller/ShowTextController.gd @@ -0,0 +1,44 @@ +@tool +extends RefCounted +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# Macro-N +# ============================================================================= + + +func execute() -> String: + var text : String = "" + var editor : ScriptEditor = EditorInterface.get_script_editor() + if editor: + var sc : Script = editor.get_current_script() + if sc: + var base : ScriptEditorBase = editor.get_current_editor() + var control : Control = base.get_base_editor() + if control is CodeEdit: + var last_line : int = -1 + for x : int in control.get_caret_count(): + var current : String = control.get_selected_text(x) + if current.is_empty(): + continue + var from : int = control.get_selection_from_column(x) + var line : int = control.get_caret_line(x) + if from > 0: + var txt : String = control.get_line(line) + if txt.length() > from: + while from > -1: + var chars : String = txt[from] + if chars == '\t': + current = '\t' + current + elif chars == ' ': + current = ' ' + current + from -= 1 + if last_line == -1: + text += current + elif last_line < line: + text = str(text ,'\n', current) + else: + text = str(current ,'\n', text) + last_line = line + return text diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/gui/controller/ShowTextController.gd.uid b/addons/_Godot-IDE_/plugins/macro-n/src/gui/controller/ShowTextController.gd.uid new file mode 100644 index 0000000..a539339 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/gui/controller/ShowTextController.gd.uid @@ -0,0 +1 @@ +uid://ctahuhicmqk8i diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/gui/util/Button.gd b/addons/_Godot-IDE_/plugins/macro-n/src/gui/util/Button.gd new file mode 100644 index 0000000..8fb12ad --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/gui/util/Button.gd @@ -0,0 +1,13 @@ +@tool +extends Button +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# Macro-N +# ============================================================================= + + +func _pressed() -> void: + if owner and owner.has_method(name): + owner.call(name) diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/gui/util/Button.gd.uid b/addons/_Godot-IDE_/plugins/macro-n/src/gui/util/Button.gd.uid new file mode 100644 index 0000000..ad32350 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/gui/util/Button.gd.uid @@ -0,0 +1 @@ +uid://b4ypyfc1c0ybj diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/gui/util/syntax.gd b/addons/_Godot-IDE_/plugins/macro-n/src/gui/util/syntax.gd new file mode 100644 index 0000000..6f86d6b --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/gui/util/syntax.gd @@ -0,0 +1,37 @@ +extends CodeHighlighter +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# Macro-N +# ============================================================================= + +var _enabled : bool = false +var rgx : RegEx = null + +var _base : SyntaxHighlighter = null + +func set_base(b : SyntaxHighlighter) -> void: + _base = b + _enabled = is_instance_valid(_base) and is_instance_valid(rgx) + +func set_rgx(r : RegEx) -> void: + rgx = r + _enabled = is_instance_valid(_base) and is_instance_valid(rgx) + +func _get_line_syntax_highlighting(line : int) -> Dictionary: + var out : Dictionary = {} + if _enabled: + out = _base.get_line_syntax_highlighting(line) + + var line_text: String = get_text_edit().get_line(line) + for x : RegExMatch in rgx.search_all(line_text): + var start : int = x.get_start() + var end : int = x.get_end() + _add_color_region(out, start, end, Color.GOLD) + + return out + +func _add_color_region(data: Dictionary, start_col: int, end_col: int, color: Color): + for x : int in range(start_col, end_col, 1): + data[x] = {"color": color} diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/gui/util/syntax.gd.uid b/addons/_Godot-IDE_/plugins/macro-n/src/gui/util/syntax.gd.uid new file mode 100644 index 0000000..862c2c5 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/gui/util/syntax.gd.uid @@ -0,0 +1 @@ +uid://cyenwroye7tue diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/main.gd b/addons/_Godot-IDE_/plugins/macro-n/src/main.gd new file mode 100644 index 0000000..691c499 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/main.gd @@ -0,0 +1,80 @@ +extends RefCounted +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# Macro-N +# ============================================================================= + +const IFragmentDB := preload("res://addons/_Godot-IDE_/plugins/macro-n/src/app/out/IFragmentDB.gd") +const IGetAllFragments := preload("res://addons/_Godot-IDE_/plugins/macro-n/src/app/in/IGetAllFragments.gd") +const IGetFragment := preload("res://addons/_Godot-IDE_/plugins/macro-n/src/app/in/IGetFragment.gd") +const ISerializerFragment := preload("res://addons/_Godot-IDE_/plugins/macro-n/src/app/in/ISerializerFragments.gd") +const IMacro = preload("res://addons/_Godot-IDE_/plugins/macro-n/src/app/in/IMacro.gd") + +var _root : Node = null +var _node : Window = null + +func _init(root : Node) -> void: + _root = root + +func _cut() -> void: + var ip : InputEventKey = InputEventKey.new() + ip.ctrl_pressed = true + ip.pressed = true + ip.keycode = KEY_X + Engine.get_main_loop().root.push_input(ip) + +func _paste(txt : String) -> void: + DisplayServer.clipboard_set(txt) + + var cip : InputEventKey = InputEventKey.new() + cip.ctrl_pressed = true + cip.pressed = true + cip.keycode = KEY_V + Engine.get_main_loop().root.push_input(cip) + +func execute(txt : String, type : int) -> void: + if type == 0 or type == 1: + var FragmentDB : IFragmentDB = ResourceLoader.load("res://addons/_Godot-IDE_/plugins/macro-n/src/repo/configurator.gd").new() + var macro : IMacro = null + if type == 0: + macro = ResourceLoader.load("res://addons/_Godot-IDE_/plugins/macro-n/src/app/invoke_macro.gd").new(FragmentDB) + else: + macro = ResourceLoader.load("res://addons/_Godot-IDE_/plugins/macro-n/src/app/invoke_macro_bypass.gd").new(FragmentDB) + var content : String = macro.execute(txt) + if content.length() == 0: + return + + var sc : ScriptEditor = EditorInterface.get_script_editor() + var node : Node = sc.get_current_editor() + if node: + node = node.get_base_editor() + if node is CodeEdit: + if node.get_caret_count() > 0: + _cut() + _paste(content) + else: + if is_instance_valid(_node): + _node.popup_centered() + return + + var GUI : PackedScene = ResourceLoader.load("res://addons/_Godot-IDE_/plugins/macro-n/src/gui/SweetOne/SweetOne.tscn") + + var FragmentDB : IFragmentDB = ResourceLoader.load("res://addons/_Godot-IDE_/plugins/macro-n/src/repo/configurator.gd").new() + var GetAllFragments : IGetAllFragments = ResourceLoader.load("res://addons/_Godot-IDE_/plugins/macro-n/src/app/get_all_fragments.gd").new(FragmentDB) + var GetFragment : IGetFragment = ResourceLoader.load("res://addons/_Godot-IDE_/plugins/macro-n/src/app/get_fragment.gd").new(FragmentDB) + var SerializerFragment : ISerializerFragment = ResourceLoader.load("res://addons/_Godot-IDE_/plugins/macro-n/src/app/save_fragment.gd").new(FragmentDB) + + _node = GUI.instantiate() + _root.add_child(_node) + + _node.set_dependencies([ + GetAllFragments, + GetFragment, + SerializerFragment + ]) + + _node.set_content(txt) + + _node.popup_centered() diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/main.gd.uid b/addons/_Godot-IDE_/plugins/macro-n/src/main.gd.uid new file mode 100644 index 0000000..f6cdcca --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/main.gd.uid @@ -0,0 +1 @@ +uid://ddggr4djfu4ft diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/repo/configurator.gd b/addons/_Godot-IDE_/plugins/macro-n/src/repo/configurator.gd new file mode 100644 index 0000000..2657781 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/repo/configurator.gd @@ -0,0 +1,93 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/macro-n/src/app/out/IFragmentDB.gd" +# ============================================================================= +# Author: Twister +# Godot-IDE Extension +# +# Macro-N +# ============================================================================= + +const URI : String = "res://addons/_Godot-IDE_/plugins/macro-n/save/user_data.dat" + +func _setup() -> void: + var dir : String = URI.get_base_dir() + if !DirAccess.dir_exists_absolute(dir): + DirAccess.make_dir_absolute(dir) + +func _get_dto() -> Dictionary: + return { + "shortcut" : "", + "description" : "", + "content" : "" + } + +func _get_database() -> ConfigFile: + _setup() + + var cfg : ConfigFile = ConfigFile.new() + + if FileAccess.file_exists(URI) and cfg.load(URI) != OK: + push_error("[Macro-N] Can not restore user data saved!") + var dir : String = URI.get_base_dir() + var file : String = URI.get_file() + var index : int = 0 + var uri : String = dir.path_join(str(file, "_back", index)) + while FileAccess.file_exists(uri): + uri = dir.path_join(str(file, "_back", index)) + index += 1 + var io : FileAccess = FileAccess.open(uri, FileAccess.WRITE) + if io: + io.store_string(FileAccess.get_file_as_string(URI)) + io.close() + + return cfg + +#Implement IFragmentDB function. +func save_fragment(shortcut : String, description : String, full_text : String) -> int: + var cfg : ConfigFile = _get_database() + cfg.set_value(shortcut, "description", description) + cfg.set_value(shortcut, "content", full_text) + return cfg.save(URI) + +#Implement IFragmentDB function. +func get_fragment(shortcut : String) -> Dictionary: + var cfg : ConfigFile = _get_database() + + var data : Dictionary = _get_dto() + + if cfg.has_section(shortcut): + data["shortcut"] = shortcut + for k : String in data.keys(): + if cfg.has_section_key(shortcut, k): + data[k] = cfg.get_value(shortcut, k, "") + + return data + +#Implement IFragmentDB function. +func get_all_fragments() -> Array[Dictionary]: + var cfg : ConfigFile = _get_database() + var out : Array[Dictionary] = [] + + for shortcut : String in cfg.get_sections(): + var data : Dictionary = _get_dto() + for k : String in data.keys(): + if cfg.has_section_key(shortcut, k): + data[k] = cfg.get_value(shortcut, k, "") + + data["shortcut"] = shortcut + + out.append(data) + + return out + +#Implement IFragmentDB function. +func remove(shortcut : String) -> int: + var db : ConfigFile = _get_database() + if db.has_section(shortcut): + db.erase_section(shortcut) + return db.save(URI) + return -1 + +#Implement IFragmentDB function. +func get_data_keys() -> PackedStringArray: + return PackedStringArray(_get_dto().keys()) diff --git a/addons/_Godot-IDE_/plugins/macro-n/src/repo/configurator.gd.uid b/addons/_Godot-IDE_/plugins/macro-n/src/repo/configurator.gd.uid new file mode 100644 index 0000000..701232b --- /dev/null +++ b/addons/_Godot-IDE_/plugins/macro-n/src/repo/configurator.gd.uid @@ -0,0 +1 @@ +uid://c6pujcw1hjxo4 diff --git a/addons/_Godot-IDE_/plugins/quick_folds/plugin.cfg b/addons/_Godot-IDE_/plugins/quick_folds/plugin.cfg new file mode 100644 index 0000000..1989eb9 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/quick_folds/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="QuickFolds" +description="Quick Folds Addon for Godot" +author="Twister" +version="1.0" +script="plugin.gd" diff --git a/addons/_Godot-IDE_/plugins/quick_folds/plugin.gd b/addons/_Godot-IDE_/plugins/quick_folds/plugin.gd new file mode 100644 index 0000000..47166ff --- /dev/null +++ b/addons/_Godot-IDE_/plugins/quick_folds/plugin.gd @@ -0,0 +1,115 @@ +@tool +extends EditorPlugin +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Quick Folds +# https://github.com/CodeNameTwister/Quick-Folds +# +# Script Spliter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + +const KEYS : PackedInt32Array = [ + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_0 + ] + +var _inputs : Array[InputEvent] = [] +var _inverted_inputs : Array[InputEvent] = [] + +func _init() -> void: + var editor : EditorSettings = EditorInterface.get_editor_settings() + if editor: + var key1 : String = "plugin/quick_folds/input/fold_type_" + var key2 : String = "plugin/quick_folds/input/inverted_fold_type_" + for z : Array in [[key1, _inputs, false], [key2, _inverted_inputs, true]]: + for x : int in range(0, KEYS.size(), 1): + var key_token : String = str(z[0], x + 1) + var _input : InputEvent = null + if editor.has_setting(key_token): + var variant : Variant = editor.get_setting(key_token) + if variant is InputEvent: + _input = variant + z[1].append(_input) + continue + _input = InputEventKey.new() + _input.pressed = true + _input.alt_pressed = true + _input.shift_pressed = z[2] + _input.keycode = KEYS[x] + editor.set_setting(key_token, _input) + z[1].append(_input) + + set_process_unhandled_input(_inputs.size() > 0 or _inverted_inputs.size() > 0) + +func _unhandled_input(event: InputEvent) -> void: + if event.is_pressed(): + for x : InputEvent in _inputs: + if event.is_match(x): + var index : int = _inputs.find(x) + if index > -1: + folding(index, false) + return + for x : InputEvent in _inverted_inputs: + if event.is_match(x): + var index : int = _inverted_inputs.find(x) + if index > -1: + folding(index, true) + return + +func _show_error(msg : String = 'Error, on try fold editor!') -> void: + push_warning(msg) + +func folding(level: int, from_back : bool) -> void: + var script_editor : ScriptEditor = null + var editor : ScriptEditorBase = null + + script_editor = EditorInterface.get_script_editor() + + if !is_instance_valid(script_editor): + _show_error() + return + + editor = script_editor.get_current_editor() + + if !is_instance_valid(editor): + _show_error() + return + + var control : Control = script_editor.get_current_editor().get_base_editor() + + if control is CodeEdit: + control.unfold_all_lines() + + if from_back: + var max_indent : int = 0 + for line_idx : int in range(control.get_line_count()): + max_indent = maxi(max_indent, control.get_indent_level(line_idx)) + + level = maxi(max_indent - maxi(level * control.indent_size, 0), -1) + + for line : int in range(control.get_line_count()): + var indent: int = control.get_indent_level(line) + if control.can_fold_line(line): + if level < indent: + control.fold_line(line) + else: + control.unfold_line(line) + + else: + level = maxi((level - 1) * control.indent_size, -1) + + for line : int in range(control.get_line_count()): + var indent: int = control.get_indent_level(line) + if control.can_fold_line(line): + if level < indent: + control.fold_line(line) + else: + control.unfold_line(line) diff --git a/addons/_Godot-IDE_/plugins/quick_folds/plugin.gd.uid b/addons/_Godot-IDE_/plugins/quick_folds/plugin.gd.uid new file mode 100644 index 0000000..4751dd5 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/quick_folds/plugin.gd.uid @@ -0,0 +1 @@ +uid://bvjx2bstjy2sl diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/Close.svg b/addons/_Godot-IDE_/plugins/script_splitter/assets/Close.svg new file mode 100644 index 0000000..be1c1dc --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/Close.svg @@ -0,0 +1 @@ + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/Close.svg.import b/addons/_Godot-IDE_/plugins/script_splitter/assets/Close.svg.import new file mode 100644 index 0000000..b54c2b6 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/Close.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://4juherhkw8hp" +path="res://.godot/imported/Close.svg-f44a86eac1bc9e4998cafdc9b4738a96.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/plugins/script_splitter/assets/Close.svg" +dest_files=["res://.godot/imported/Close.svg-f44a86eac1bc9e4998cafdc9b4738a96.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/LTabBar.svg b/addons/_Godot-IDE_/plugins/script_splitter/assets/LTabBar.svg new file mode 100644 index 0000000..09a66e1 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/LTabBar.svg @@ -0,0 +1,39 @@ + + + + + + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/LTabBar.svg.import b/addons/_Godot-IDE_/plugins/script_splitter/assets/LTabBar.svg.import new file mode 100644 index 0000000..977d269 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/LTabBar.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cod0nie30hnjp" +path="res://.godot/imported/LTabBar.svg-c5ab80cb44d42fa40c9701bd78e5d30a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/plugins/script_splitter/assets/LTabBar.svg" +dest_files=["res://.godot/imported/LTabBar.svg-c5ab80cb44d42fa40c9701bd78e5d30a.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/RTabBar.svg b/addons/_Godot-IDE_/plugins/script_splitter/assets/RTabBar.svg new file mode 100644 index 0000000..9f28e6a --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/RTabBar.svg @@ -0,0 +1,39 @@ + + + + + + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/RTabBar.svg.import b/addons/_Godot-IDE_/plugins/script_splitter/assets/RTabBar.svg.import new file mode 100644 index 0000000..6480f71 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/RTabBar.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://di3qxejijgp0e" +path="res://.godot/imported/RTabBar.svg-9a0f50b61d7ac6a2c158eb70fd4d9a6f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/plugins/script_splitter/assets/RTabBar.svg" +dest_files=["res://.godot/imported/RTabBar.svg-9a0f50b61d7ac6a2c158eb70fd4d9a6f.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/TabBar.svg b/addons/_Godot-IDE_/plugins/script_splitter/assets/TabBar.svg new file mode 100644 index 0000000..b2af581 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/TabBar.svg @@ -0,0 +1,39 @@ + + + + + + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/TabBar.svg.import b/addons/_Godot-IDE_/plugins/script_splitter/assets/TabBar.svg.import new file mode 100644 index 0000000..6053390 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/TabBar.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dceedsu8mfraw" +path="res://.godot/imported/TabBar.svg-3dd1b971b123a90fb519f5c4f78d81b1.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/plugins/script_splitter/assets/TabBar.svg" +dest_files=["res://.godot/imported/TabBar.svg-3dd1b971b123a90fb519f5c4f78d81b1.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/atop.png b/addons/_Godot-IDE_/plugins/script_splitter/assets/atop.png new file mode 100644 index 0000000..4ed361e --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/atop.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:372e1e40caadb7b6fe6ed6a5fc66024dcf43269ac459b6adca0678220354a5cc +size 345 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/atop.png.import b/addons/_Godot-IDE_/plugins/script_splitter/assets/atop.png.import new file mode 100644 index 0000000..3d8a815 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/atop.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://r6u1jtnbr4eg" +path="res://.godot/imported/atop.png-e7eeb8db1372f6d12e66a684718d9524.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/plugins/script_splitter/assets/atop.png" +dest_files=["res://.godot/imported/atop.png-e7eeb8db1372f6d12e66a684718d9524.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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/expand.svg b/addons/_Godot-IDE_/plugins/script_splitter/assets/expand.svg new file mode 100644 index 0000000..c642cd7 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/expand.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/expand.svg.import b/addons/_Godot-IDE_/plugins/script_splitter/assets/expand.svg.import new file mode 100644 index 0000000..8fec137 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/expand.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cractge21enk" +path="res://.godot/imported/expand.svg-5bf3a72499998da54d96db747a1f30d1.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/plugins/script_splitter/assets/expand.svg" +dest_files=["res://.godot/imported/expand.svg-5bf3a72499998da54d96db747a1f30d1.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/file_in.png b/addons/_Godot-IDE_/plugins/script_splitter/assets/file_in.png new file mode 100644 index 0000000..f5af979 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/file_in.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:df9b95a4dceffc3419d614adf51aa908828431cef14281dd66a9c35b581a13f9 +size 2625 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/file_in.png.import b/addons/_Godot-IDE_/plugins/script_splitter/assets/file_in.png.import new file mode 100644 index 0000000..b0f2652 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/file_in.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cxds5tr6aq5v3" +path="res://.godot/imported/file_in.png-af9f02cc8f82ddae25e5704ad234b217.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/plugins/script_splitter/assets/file_in.png" +dest_files=["res://.godot/imported/file_in.png-af9f02cc8f82ddae25e5704ad234b217.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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/fill_expand.svg b/addons/_Godot-IDE_/plugins/script_splitter/assets/fill_expand.svg new file mode 100644 index 0000000..2bd0014 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/fill_expand.svg @@ -0,0 +1,55 @@ + + + + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/fill_expand.svg.import b/addons/_Godot-IDE_/plugins/script_splitter/assets/fill_expand.svg.import new file mode 100644 index 0000000..5a7a082 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/fill_expand.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cejhhnje48450" +path="res://.godot/imported/fill_expand.svg-68507395421cbcd27a7b7775f7347f96.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/plugins/script_splitter/assets/fill_expand.svg" +dest_files=["res://.godot/imported/fill_expand.svg-68507395421cbcd27a7b7775f7347f96.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/github_CodeNameTwister.svg b/addons/_Godot-IDE_/plugins/script_splitter/assets/github_CodeNameTwister.svg new file mode 100644 index 0000000..8d15944 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/github_CodeNameTwister.svg @@ -0,0 +1,199 @@ + + + + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/github_CodeNameTwister.svg.import b/addons/_Godot-IDE_/plugins/script_splitter/assets/github_CodeNameTwister.svg.import new file mode 100644 index 0000000..3fc6384 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/github_CodeNameTwister.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b0vjxv8swip1d" +path="res://.godot/imported/github_CodeNameTwister.svg-413c2dedf30616fd5aa27dc054f1ff13.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/plugins/script_splitter/assets/github_CodeNameTwister.svg" +dest_files=["res://.godot/imported/github_CodeNameTwister.svg-413c2dedf30616fd5aa27dc054f1ff13.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/minus_row.svg b/addons/_Godot-IDE_/plugins/script_splitter/assets/minus_row.svg new file mode 100644 index 0000000..b072808 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/minus_row.svg @@ -0,0 +1,47 @@ + + + + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/minus_row.svg.import b/addons/_Godot-IDE_/plugins/script_splitter/assets/minus_row.svg.import new file mode 100644 index 0000000..7f93825 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/minus_row.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cy5kd5rqu50mo" +path="res://.godot/imported/minus_row.svg-41677dd9d6292f7f66ac69259f155706.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/plugins/script_splitter/assets/minus_row.svg" +dest_files=["res://.godot/imported/minus_row.svg-41677dd9d6292f7f66ac69259f155706.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/pin.svg b/addons/_Godot-IDE_/plugins/script_splitter/assets/pin.svg new file mode 100644 index 0000000..010cf26 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/pin.svg @@ -0,0 +1,51 @@ + + + + + + + + + + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/pin.svg.import b/addons/_Godot-IDE_/plugins/script_splitter/assets/pin.svg.import new file mode 100644 index 0000000..3fddf5e --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/pin.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://7rel5pr2g7d2" +path="res://.godot/imported/pin.svg-178508cb55a2e5067fd62293946886b7.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/plugins/script_splitter/assets/pin.svg" +dest_files=["res://.godot/imported/pin.svg-178508cb55a2e5067fd62293946886b7.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/plus_row.svg b/addons/_Godot-IDE_/plugins/script_splitter/assets/plus_row.svg new file mode 100644 index 0000000..c5e6934 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/plus_row.svg @@ -0,0 +1,41 @@ + + + + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/plus_row.svg.import b/addons/_Godot-IDE_/plugins/script_splitter/assets/plus_row.svg.import new file mode 100644 index 0000000..469ffad --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/plus_row.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cj6sg45m64fiv" +path="res://.godot/imported/plus_row.svg-947a3d1b90cc7713424371beaa7e9f65.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/plugins/script_splitter/assets/plus_row.svg" +dest_files=["res://.godot/imported/plus_row.svg-947a3d1b90cc7713424371beaa7e9f65.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/split_cminus.svg b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_cminus.svg new file mode 100644 index 0000000..8981386 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_cminus.svg @@ -0,0 +1,80 @@ + + + + + + + + + + + split-screen + + + + + + split-screen + + + + + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/split_cminus.svg.import b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_cminus.svg.import new file mode 100644 index 0000000..dff45a7 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_cminus.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c1b7aoplxr0x7" +path="res://.godot/imported/split_cminus.svg-e2809c97c9a0d3913d3b9355b3d51b1d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/plugins/script_splitter/assets/split_cminus.svg" +dest_files=["res://.godot/imported/split_cminus.svg-e2809c97c9a0d3913d3b9355b3d51b1d.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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/split_cminus_tool.svg b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_cminus_tool.svg new file mode 100644 index 0000000..9c7b077 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_cminus_tool.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + split-screen + + + + + split-screen + + + + + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/split_cminus_tool.svg.import b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_cminus_tool.svg.import new file mode 100644 index 0000000..75426e7 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_cminus_tool.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d3s0q8570ppjv" +path="res://.godot/imported/split_cminus_tool.svg-ef687c17cf4f3e2eb6c96350a9b11a99.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/plugins/script_splitter/assets/split_cminus_tool.svg" +dest_files=["res://.godot/imported/split_cminus_tool.svg-ef687c17cf4f3e2eb6c96350a9b11a99.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/split_cplus.svg b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_cplus.svg new file mode 100644 index 0000000..2cc4a56 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_cplus.svg @@ -0,0 +1,93 @@ + + + + + + + + + + + split-screen + + + + + + + + split-screen + + + + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/split_cplus.svg.import b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_cplus.svg.import new file mode 100644 index 0000000..ea56119 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_cplus.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bvyjqo1dus1xu" +path="res://.godot/imported/split_cplus.svg-9fdcb19f5d8e4547181323a8dddac482.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/plugins/script_splitter/assets/split_cplus.svg" +dest_files=["res://.godot/imported/split_cplus.svg-9fdcb19f5d8e4547181323a8dddac482.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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/split_cplus_tool.svg b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_cplus_tool.svg new file mode 100644 index 0000000..4e76e51 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_cplus_tool.svg @@ -0,0 +1,90 @@ + + + + + + + + + + + split-screen + + + + + + split-screen + + + + + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/split_cplus_tool.svg.import b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_cplus_tool.svg.import new file mode 100644 index 0000000..7e6bd01 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_cplus_tool.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://6pq6vesk5ycg" +path="res://.godot/imported/split_cplus_tool.svg-4d052e790c616fae56d146b3e9b403a7.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/plugins/script_splitter/assets/split_cplus_tool.svg" +dest_files=["res://.godot/imported/split_cplus_tool.svg-4d052e790c616fae56d146b3e9b403a7.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/split_minus_tool.svg b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_minus_tool.svg new file mode 100644 index 0000000..68ee0b2 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_minus_tool.svg @@ -0,0 +1,68 @@ + + + + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/split_minus_tool.svg.import b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_minus_tool.svg.import new file mode 100644 index 0000000..4a84207 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_minus_tool.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://btm5y6ifmbles" +path="res://.godot/imported/split_minus_tool.svg-69be4b426393a3ce9ec2cf8029858538.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/plugins/script_splitter/assets/split_minus_tool.svg" +dest_files=["res://.godot/imported/split_minus_tool.svg-69be4b426393a3ce9ec2cf8029858538.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/split_plus_tool.svg b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_plus_tool.svg new file mode 100644 index 0000000..82ae148 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_plus_tool.svg @@ -0,0 +1,56 @@ + + + + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/split_plus_tool.svg.import b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_plus_tool.svg.import new file mode 100644 index 0000000..a08dd34 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_plus_tool.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bg17j5ifvqsi8" +path="res://.godot/imported/split_plus_tool.svg-70364f620a127c87706f04c3c5713c37.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/plugins/script_splitter/assets/split_plus_tool.svg" +dest_files=["res://.godot/imported/split_plus_tool.svg-70364f620a127c87706f04c3c5713c37.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/split_rminus.svg b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_rminus.svg new file mode 100644 index 0000000..50fa1a2 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_rminus.svg @@ -0,0 +1,79 @@ + + + + + + + + + + + split-screen + + + + + + split-screen + + + + + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/split_rminus.svg.import b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_rminus.svg.import new file mode 100644 index 0000000..c451c54 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_rminus.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bvjk4po8w2m2j" +path="res://.godot/imported/split_rminus.svg-1ef0b3f2a9114007898d1e4c47d28a4f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/plugins/script_splitter/assets/split_rminus.svg" +dest_files=["res://.godot/imported/split_rminus.svg-1ef0b3f2a9114007898d1e4c47d28a4f.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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/split_rminus_tool.svg b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_rminus_tool.svg new file mode 100644 index 0000000..471eb43 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_rminus_tool.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + split-screen + + + + + split-screen + + + + + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/split_rminus_tool.svg.import b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_rminus_tool.svg.import new file mode 100644 index 0000000..262a417 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_rminus_tool.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d1yp7jd6hvabl" +path="res://.godot/imported/split_rminus_tool.svg-7e3379363d3a251c15b40f135e3f5132.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/plugins/script_splitter/assets/split_rminus_tool.svg" +dest_files=["res://.godot/imported/split_rminus_tool.svg-7e3379363d3a251c15b40f135e3f5132.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/split_rplus.svg b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_rplus.svg new file mode 100644 index 0000000..81e2b3a --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_rplus.svg @@ -0,0 +1,92 @@ + + + + + + + + + + + split-screen + + + + + + split-screen + + + + + + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/split_rplus.svg.import b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_rplus.svg.import new file mode 100644 index 0000000..c7eabd8 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_rplus.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://1sqajw0mikdj" +path="res://.godot/imported/split_rplus.svg-a38a9e7660a8f7d4f7e55dc2aa40dce2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/plugins/script_splitter/assets/split_rplus.svg" +dest_files=["res://.godot/imported/split_rplus.svg-a38a9e7660a8f7d4f7e55dc2aa40dce2.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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/split_rplus_tool.svg b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_rplus_tool.svg new file mode 100644 index 0000000..7e7967d --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_rplus_tool.svg @@ -0,0 +1,90 @@ + + + + + + + + + + + split-screen + + + + + + split-screen + + + + + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/assets/split_rplus_tool.svg.import b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_rplus_tool.svg.import new file mode 100644 index 0000000..93f5647 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/assets/split_rplus_tool.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://den018oksgm5m" +path="res://.godot/imported/split_rplus_tool.svg-a22d42ef806d4f5441bc1950a87a36c6.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/plugins/script_splitter/assets/split_rplus_tool.svg" +dest_files=["res://.godot/imported/split_rplus_tool.svg-a22d42ef806d4f5441bc1950a87a36c6.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/Input.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/Input.gd new file mode 100644 index 0000000..2bc9efa --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/Input.gd @@ -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("res://addons/_Godot-IDE_/plugins/script_splitter/core/builder.gd") +const Context = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/contex/window.gd") +const SSPContext = preload("res://addons/_Godot-IDE_/plugins/script_splitter/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("res://addons/_Godot-IDE_/plugins/script_splitter/assets/split_cplus.svg") +const ICON_ADD_ROW : Texture2D = preload("res://addons/_Godot-IDE_/plugins/script_splitter/assets/split_rplus.svg") +const ICON_REMOVE_COLUMN : Texture2D = preload("res://addons/_Godot-IDE_/plugins/script_splitter/assets/split_cminus.svg") +const ICON_REMOVE_ROW : Texture2D = preload("res://addons/_Godot-IDE_/plugins/script_splitter/assets/split_rminus.svg") + +const L_TAB_BAR : Texture2D = preload("res://addons/_Godot-IDE_/plugins/script_splitter/assets/LTabBar.svg") +const R_TAB_BAR : Texture2D = preload("res://addons/_Godot-IDE_/plugins/script_splitter/assets/RTabBar.svg") +const TAB_BAR: Texture2D = preload("res://addons/_Godot-IDE_/plugins/script_splitter/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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/Input.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/Input.gd.uid new file mode 100644 index 0000000..b39dcb4 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/Input.gd.uid @@ -0,0 +1 @@ +uid://dxipxeq42djlp diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/base/container.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/base/container.gd new file mode 100644 index 0000000..f9116f6 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/base/container.gd @@ -0,0 +1,197 @@ +@tool +extends RefCounted +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Script Splitter +# https://github.com/CodeNameTwister/Script-Splitter +# +# Script Splitter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + +const SplitterContainer = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_container.gd") +const NControl = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/util/control.gd") + +const IoBar = preload("res://addons/_Godot-IDE_/plugins/script_splitter/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) + +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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/base/container.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/base/container.gd.uid new file mode 100644 index 0000000..a26a995 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/base/container.gd.uid @@ -0,0 +1 @@ +uid://iyslc58y0lp1 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/base/list.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/base/list.gd new file mode 100644 index 0000000..0b4cfa8 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/base/list.gd @@ -0,0 +1,277 @@ +@tool +extends RefCounted +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Script Splitter +# https://github.com/CodeNameTwister/Script-Splitter +# +# Script Splitter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +const SplitterList = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_list.gd") + +signal item_selected(item : 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) + #_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() diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/base/list.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/base/list.gd.uid new file mode 100644 index 0000000..2ffa5c2 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/base/list.gd.uid @@ -0,0 +1 @@ +uid://ors5ojuayup4 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/builder.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/builder.gd new file mode 100644 index 0000000..8d14728 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/builder.gd @@ -0,0 +1,242 @@ +@tool +extends RefCounted +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Script Splitter +# https://github.com/CodeNameTwister/Script-Splitter +# +# Script Splitter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + +const EditorManager = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/godot/manager.gd") +const BaseContainer = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/base/container.gd") +const BaseList = preload("res://addons/_Godot-IDE_/plugins/script_splitter/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 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 _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) diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/builder.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/builder.gd.uid new file mode 100644 index 0000000..303723d --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/builder.gd.uid @@ -0,0 +1 @@ +uid://dge4wucvh6qnb diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/contex/ssp_window.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/contex/ssp_window.gd new file mode 100644 index 0000000..0ed6eef --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/contex/ssp_window.gd @@ -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("res://addons/_Godot-IDE_/plugins/script_splitter/assets/plus_row.svg") +const MINUS_SPLIT = preload("res://addons/_Godot-IDE_/plugins/script_splitter/assets/minus_row.svg") +const SspEditor = preload("res://addons/_Godot-IDE_/plugins/script_splitter/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() + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/contex/ssp_window.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/contex/ssp_window.gd.uid new file mode 100644 index 0000000..c5f4f98 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/contex/ssp_window.gd.uid @@ -0,0 +1 @@ +uid://cdn4c7qori2ry diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/contex/window.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/contex/window.gd new file mode 100644 index 0000000..3a78f54 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/contex/window.gd @@ -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) diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/contex/window.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/contex/window.gd.uid new file mode 100644 index 0000000..47bcb74 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/contex/window.gd.uid @@ -0,0 +1 @@ +uid://cblflkellpdqg diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/app.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/app.gd new file mode 100644 index 0000000..ccbf44a --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/app.gd @@ -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("res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/magic/mickey_tool.gd") +const ToolDB = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/database/tool_db.gd") +const Manager = preload("res://addons/_Godot-IDE_/plugins/script_splitter/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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/app.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/app.gd.uid new file mode 100644 index 0000000..198c806 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/app.gd.uid @@ -0,0 +1 @@ +uid://b5denwbu6twf4 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/create_tool.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/create_tool.gd new file mode 100644 index 0000000..5809d99 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/create_tool.gd @@ -0,0 +1,104 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/app.gd" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Script Splitter +# https://github.com/CodeNameTwister/Script-Splitter +# +# Script Splitter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + +const EditorTool = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/editor_tool.gd") + +const HelperEditorTool = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/helper_editor_tool.gd") +const ScriptEditorTool = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/script_editor_tool.gd") +const TextEditorTool = preload("res://addons/_Godot-IDE_/plugins/script_splitter/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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/create_tool.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/create_tool.gd.uid new file mode 100644 index 0000000..d875493 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/create_tool.gd.uid @@ -0,0 +1 @@ +uid://bsrituhgnfbm diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/focus_by_tab.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/focus_by_tab.gd new file mode 100644 index 0000000..27fff67 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/focus_by_tab.gd @@ -0,0 +1,24 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/script_splitter/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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/focus_by_tab.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/focus_by_tab.gd.uid new file mode 100644 index 0000000..2ee4c31 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/focus_by_tab.gd.uid @@ -0,0 +1 @@ +uid://bipvmrq4th30m diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/focus_tool.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/focus_tool.gd new file mode 100644 index 0000000..16e48c2 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/focus_tool.gd @@ -0,0 +1,115 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/app.gd" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Script Splitter +# https://github.com/CodeNameTwister/Script-Splitter +# +# Script Splitter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +const BaseList = preload("res://addons/_Godot-IDE_/plugins/script_splitter/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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/focus_tool.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/focus_tool.gd.uid new file mode 100644 index 0000000..7a564f9 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/focus_tool.gd.uid @@ -0,0 +1 @@ +uid://bk4jykdijx7sj diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/io.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/io.gd new file mode 100644 index 0000000..5eb629c --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/io.gd @@ -0,0 +1,219 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/app.gd" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Script Splitter +# https://github.com/CodeNameTwister/Script-Splitter +# +# Script Splitter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +const BaseList = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/base/list.gd") + +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() + + 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) + + _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 + return false diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/io.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/io.gd.uid new file mode 100644 index 0000000..ae5b166 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/io.gd.uid @@ -0,0 +1 @@ +uid://dqgve5bbg0w1m diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/merge_tool.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/merge_tool.gd new file mode 100644 index 0000000..dd88524 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/merge_tool.gd @@ -0,0 +1,91 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/script_splitter/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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/merge_tool.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/merge_tool.gd.uid new file mode 100644 index 0000000..35ca41e --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/merge_tool.gd.uid @@ -0,0 +1 @@ +uid://cf43swgi3ydv8 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/refresh_warnings.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/refresh_warnings.gd new file mode 100644 index 0000000..42debe0 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/refresh_warnings.gd @@ -0,0 +1,77 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/script_splitter/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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/refresh_warnings.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/refresh_warnings.gd.uid new file mode 100644 index 0000000..b23bd46 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/refresh_warnings.gd.uid @@ -0,0 +1 @@ +uid://c0wasvo7fwcqr diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/remove_by_tab.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/remove_by_tab.gd new file mode 100644 index 0000000..3f48d89 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/remove_by_tab.gd @@ -0,0 +1,26 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/script_splitter/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 + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/remove_by_tab.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/remove_by_tab.gd.uid new file mode 100644 index 0000000..631d782 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/remove_by_tab.gd.uid @@ -0,0 +1 @@ +uid://bht1hix6hophq diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/reparent_tool.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/reparent_tool.gd new file mode 100644 index 0000000..146dac3 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/reparent_tool.gd @@ -0,0 +1,21 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/script_splitter/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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/reparent_tool.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/reparent_tool.gd.uid new file mode 100644 index 0000000..1c1e1cf --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/reparent_tool.gd.uid @@ -0,0 +1 @@ +uid://ckvujn0hnsm11 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/rmb_menu.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/rmb_menu.gd new file mode 100644 index 0000000..81db7e4 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/rmb_menu.gd @@ -0,0 +1,30 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/script_splitter/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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/rmb_menu.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/rmb_menu.gd.uid new file mode 100644 index 0000000..2b6a7a5 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/rmb_menu.gd.uid @@ -0,0 +1 @@ +uid://dj5eoum4nippb diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/select_by_index.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/select_by_index.gd new file mode 100644 index 0000000..1ea0aee --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/select_by_index.gd @@ -0,0 +1,28 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/script_splitter/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: + 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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/select_by_index.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/select_by_index.gd.uid new file mode 100644 index 0000000..240bcfa --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/select_by_index.gd.uid @@ -0,0 +1 @@ +uid://bej35a842s2yd diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/split_column.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/split_column.gd new file mode 100644 index 0000000..d883f68 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/split_column.gd @@ -0,0 +1,44 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/script_splitter/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_column(), idx) + _manager.io.update() + return true + + return false diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/split_column.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/split_column.gd.uid new file mode 100644 index 0000000..9e0a782 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/split_column.gd.uid @@ -0,0 +1 @@ +uid://bomyp1t030hd diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/split_row.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/split_row.gd new file mode 100644 index 0000000..706d604 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/split_row.gd @@ -0,0 +1,45 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/script_splitter/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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/split_row.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/split_row.gd.uid new file mode 100644 index 0000000..bf4ce13 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/split_row.gd.uid @@ -0,0 +1 @@ +uid://bg2573oxujrny diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/swap_tab.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/swap_tab.gd new file mode 100644 index 0000000..057cccf --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/swap_tab.gd @@ -0,0 +1,71 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/app.gd" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Script Splitter +# https://github.com/CodeNameTwister/Script-Splitter +# +# Script Splitter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +const BaseContainer = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/base/container.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 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: + x.ochorus(to) + _manager.clear_editors() + 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: + var tidx : int = tm.get_control().get_index() + if left: + froot.move_child(fm.get_control(), maxi(tidx - 1,0)) + else: + froot.move_child(fm.get_control(), tidx) + 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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/swap_tab.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/swap_tab.gd.uid new file mode 100644 index 0000000..ff85dd1 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/swap_tab.gd.uid @@ -0,0 +1 @@ +uid://cwgbj8fqlg6wm diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/update_list_selection.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/update_list_selection.gd new file mode 100644 index 0000000..8d20f2f --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/update_list_selection.gd @@ -0,0 +1,105 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/script_splitter/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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/update_list_selection.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/update_list_selection.gd.uid new file mode 100644 index 0000000..6b1f8d0 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/update_list_selection.gd.uid @@ -0,0 +1 @@ +uid://d0fdvav3whi4t diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/update_metadata.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/update_metadata.gd new file mode 100644 index 0000000..d5607a1 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/update_metadata.gd @@ -0,0 +1,80 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/app.gd" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Script Splitter +# https://github.com/CodeNameTwister/Script-Splitter +# +# Script Splitter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +const BaseList = preload("res://addons/_Godot-IDE_/plugins/script_splitter/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) diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/update_metadata.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/update_metadata.gd.uid new file mode 100644 index 0000000..a51432c --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/update_metadata.gd.uid @@ -0,0 +1 @@ +uid://bk6hirh5yekc5 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/user_tab_close.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/user_tab_close.gd new file mode 100644 index 0000000..6ec3022 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/user_tab_close.gd @@ -0,0 +1,63 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/script_splitter/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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/user_tab_close.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/user_tab_close.gd.uid new file mode 100644 index 0000000..d26c457 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/user_tab_close.gd.uid @@ -0,0 +1 @@ +uid://c8c77dtgjpvxr diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/coroutine/task.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/coroutine/task.gd new file mode 100644 index 0000000..d6a22c4 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/coroutine/task.gd @@ -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() diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/coroutine/task.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/coroutine/task.gd.uid new file mode 100644 index 0000000..0f41e24 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/coroutine/task.gd.uid @@ -0,0 +1 @@ +uid://qbsuad1aohqy diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/database/tool_db.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/database/tool_db.gd new file mode 100644 index 0000000..40cb9da --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/database/tool_db.gd @@ -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("res://addons/_Godot-IDE_/plugins/script_splitter/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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/database/tool_db.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/database/tool_db.gd.uid new file mode 100644 index 0000000..24e16c3 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/database/tool_db.gd.uid @@ -0,0 +1 @@ +uid://dv6xyd03fg7kj diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/godot/manager.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/godot/manager.gd new file mode 100644 index 0000000..47fd948 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/godot/manager.gd @@ -0,0 +1,361 @@ +@tool +extends RefCounted +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Script Splitter +# https://github.com/CodeNameTwister/Script-Splitter +# +# Script Splitter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + +const CreateTool = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/create_tool.gd") +const UpdateMetadata = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/update_metadata.gd") +const FocusTool = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/focus_tool.gd") +const SelectByIndex = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/select_by_index.gd") +const FocusByTab = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/focus_by_tab.gd") +const ReparentTool = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/reparent_tool.gd") +const MergeTool = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/merge_tool.gd") +const SplitColumn = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/split_column.gd") +const SplitRow = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/split_row.gd") +const RemoveByTab = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/remove_by_tab.gd") +const RefreshWarnings = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/refresh_warnings.gd") +const UpdateListSelection = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/update_list_selection.gd") +const SwapTab = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/swap_tab.gd") +const RmbMenu = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/rmb_menu.gd") +const UserTabClose = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/user_tab_close.gd") +const Io = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/application/io.gd") + +const ToolDB = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/database/tool_db.gd") +const Task = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/coroutine/task.gd") + +const BaseContainer = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/base/container.gd") +const BaseList = preload("res://addons/_Godot-IDE_/plugins/script_splitter/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 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) + 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_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.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() -> 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_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.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]) diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/godot/manager.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/godot/manager.gd.uid new file mode 100644 index 0000000..eccf3d0 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/godot/manager.gd.uid @@ -0,0 +1 @@ +uid://blq08yud6jfse diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/editor_tool.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/editor_tool.gd new file mode 100644 index 0000000..e33d364 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/editor_tool.gd @@ -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("res://addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/magic/mickey_tool.gd") +const MickeyToolRoute = preload("res://addons/_Godot-IDE_/plugins/script_splitter/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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/editor_tool.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/editor_tool.gd.uid new file mode 100644 index 0000000..135f612 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/editor_tool.gd.uid @@ -0,0 +1 @@ +uid://byxd23l74ehqq diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/helper_editor_tool.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/helper_editor_tool.gd new file mode 100644 index 0000000..4c82973 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/helper_editor_tool.gd @@ -0,0 +1,49 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/script_splitter/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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/helper_editor_tool.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/helper_editor_tool.gd.uid new file mode 100644 index 0000000..78266ad --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/helper_editor_tool.gd.uid @@ -0,0 +1 @@ +uid://cnor3blarugxa diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/magic/mickey_tool.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/magic/mickey_tool.gd new file mode 100644 index 0000000..f26e31c --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/magic/mickey_tool.gd @@ -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("res://addons/_Godot-IDE_/plugins/script_splitter/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) diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/magic/mickey_tool.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/magic/mickey_tool.gd.uid new file mode 100644 index 0000000..0966307 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/magic/mickey_tool.gd.uid @@ -0,0 +1 @@ +uid://r4j0eu5er1m4 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/magic/mickey_tool_route.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/magic/mickey_tool_route.gd new file mode 100644 index 0000000..2e48e32 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/magic/mickey_tool_route.gd @@ -0,0 +1,50 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/script_splitter/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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/magic/mickey_tool_route.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/magic/mickey_tool_route.gd.uid new file mode 100644 index 0000000..fae7083 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/magic/mickey_tool_route.gd.uid @@ -0,0 +1 @@ +uid://pkj5o6q7sine diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/script_editor_tool.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/script_editor_tool.gd new file mode 100644 index 0000000..8302789 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/script_editor_tool.gd @@ -0,0 +1,26 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/script_splitter/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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/script_editor_tool.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/script_editor_tool.gd.uid new file mode 100644 index 0000000..c2a9cc9 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/script_editor_tool.gd.uid @@ -0,0 +1 @@ +uid://c5mrlc852aghg diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/text_editor_tool.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/text_editor_tool.gd new file mode 100644 index 0000000..d3201c5 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/text_editor_tool.gd @@ -0,0 +1,22 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/script_splitter/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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/text_editor_tool.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/text_editor_tool.gd.uid new file mode 100644 index 0000000..fd57ac1 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/editor/tools/text_editor_tool.gd.uid @@ -0,0 +1 @@ +uid://xkgq82knloas diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/icon/MultiSpliter.svg b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/icon/MultiSpliter.svg new file mode 100644 index 0000000..4e3a514 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/icon/MultiSpliter.svg @@ -0,0 +1,43 @@ + + + + + + + + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/icon/MultiSpliter.svg.import b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/icon/MultiSpliter.svg.import new file mode 100644 index 0000000..72f8fc9 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/icon/MultiSpliter.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c042di3o7rqml" +path="res://.godot/imported/MultiSpliter.svg-6817b55c935448e01c4c56c2cdea2496.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/icon/MultiSpliter.svg" +dest_files=["res://.godot/imported/MultiSpliter.svg-6817b55c935448e01c4c56c2cdea2496.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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/icon/MultiSpliterButton.svg b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/icon/MultiSpliterButton.svg new file mode 100644 index 0000000..28877b8 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/icon/MultiSpliterButton.svg @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/icon/MultiSpliterButton.svg.import b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/icon/MultiSpliterButton.svg.import new file mode 100644 index 0000000..7afcb63 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/icon/MultiSpliterButton.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d1oshw4o6jues" +path="res://.godot/imported/MultiSpliterButton.svg-c4f3205a91f571beaa6eaa4d00d0c837.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/icon/MultiSpliterButton.svg" +dest_files=["res://.godot/imported/MultiSpliterButton.svg-c4f3205a91f571beaa6eaa4d00d0c837.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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/icon/MultiSpliterItem.svg b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/icon/MultiSpliterItem.svg new file mode 100644 index 0000000..09251a4 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/icon/MultiSpliterItem.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/icon/MultiSpliterItem.svg.import b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/icon/MultiSpliterItem.svg.import new file mode 100644 index 0000000..c43a2d3 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/icon/MultiSpliterItem.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dvg5cjdqtdpd7" +path="res://.godot/imported/MultiSpliterItem.svg-d4de4583cb5a7de8e2fcdbebea722e6d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/icon/MultiSpliterItem.svg" +dest_files=["res://.godot/imported/MultiSpliterItem.svg-d4de4583cb5a7de8e2fcdbebea722e6d.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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/multi_split_container.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/multi_split_container.gd new file mode 100644 index 0000000..fb1af1a --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/multi_split_container.gd @@ -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() diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/multi_split_container.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/multi_split_container.gd.uid new file mode 100644 index 0000000..0b4003b --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/multi_split_container.gd.uid @@ -0,0 +1 @@ +uid://sffqwro3flkc diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/split_container_item.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/split_container_item.gd new file mode 100644 index 0000000..223b613 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/split_container_item.gd @@ -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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/split_container_item.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/split_container_item.gd.uid new file mode 100644 index 0000000..0596a8d --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/split_container_item.gd.uid @@ -0,0 +1 @@ +uid://rh6vq7m1qfkr diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/changes.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/changes.gd new file mode 100644 index 0000000..9a77ef2 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/changes.gd @@ -0,0 +1,9 @@ +@tool +extends Label + +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() diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/changes.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/changes.gd.uid new file mode 100644 index 0000000..7022c81 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/changes.gd.uid @@ -0,0 +1 @@ +uid://bkj4lec06udg5 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/container.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/container.gd new file mode 100644 index 0000000..e0c061e --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/container.gd @@ -0,0 +1,353 @@ +@tool +extends PanelContainer +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Script Splitter +# https://github.com/CodeNameTwister/Script-Splitter +# +# Script Splitter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + +const TAB = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/tab.tscn") + +@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 + +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() + 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 + + _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 _ready() -> void: + size_flags_horizontal = Control.SIZE_EXPAND_FILL + size_flags_vertical = Control.SIZE_FILL + + item_rect_changed.connect(_on_rect_change) + + + 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 = 0.0 + _try = 0 + set_physics_process(true) + +func get_reference() -> TabBar: + return _reference + +func _physics_process(delta: float) -> void: + _dlt += delta + if _dlt < 0.005: + return + _dlt = 0.0 + _try += 1 + if _try % 2 == 0: + return + set_physics_process(_try < 30) + 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 + + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/container.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/container.gd.uid new file mode 100644 index 0000000..151c97a --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/container.gd.uid @@ -0,0 +1 @@ +uid://cnubduf2plac4 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/container.tscn b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/container.tscn new file mode 100644 index 0000000..74d4420 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/container.tscn @@ -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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/container_button.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/container_button.gd new file mode 100644 index 0000000..5ff7325 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/container_button.gd @@ -0,0 +1,69 @@ +@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: + 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() + +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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/container_button.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/container_button.gd.uid new file mode 100644 index 0000000..7b8e1de --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/container_button.gd.uid @@ -0,0 +1 @@ +uid://c3hg84uuly33f diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/separator.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/separator.gd new file mode 100644 index 0000000..2949c3f --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/separator.gd @@ -0,0 +1,39 @@ +@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 + 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() diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/separator.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/separator.gd.uid new file mode 100644 index 0000000..b0e41f3 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/separator.gd.uid @@ -0,0 +1 @@ +uid://d05p8nj7f18s0 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/separator.tscn b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/separator.tscn new file mode 100644 index 0000000..6b58fc3 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/separator.tscn @@ -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.4, 0.4, 1, 1) +grow_begin = 4.0 +grow_end = 4.0 +thickness = 38 + +[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") diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/tab.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/tab.gd new file mode 100644 index 0000000..941291f --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/tab.gd @@ -0,0 +1,222 @@ +@tool +extends Button +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Script Splitter +# https://github.com/CodeNameTwister/Script-Splitter +# +# Script Splitter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + +const SEPARATOR = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/separator.tscn") +static var line : VSeparator = null + + +var _delta : float = 0.0 + +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: + var c : Control = duplicate(0) + c.z_index = RenderingServer.CANVAS_ITEM_Z_MAX - 2 + set_drag_preview(c) + pressed.emit() + 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"): + 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 get_global_mouse_position().x <= 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"): + _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 at_position.x <= size.x * 0.5: + line.global_position = rct.position + else: + line.global_position = Vector2(rct.end.x, rct.position.y) + + var style : StyleBoxLine = line.get(&"theme_override_styles/separator") + style.set(&"thickness",size.y) + style.set(&"color",owner.color_rect.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 _init() -> void: + if is_node_ready(): + _ready() + +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 > 0.24: + 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 >= 0.24: + 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() diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/tab.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/tab.gd.uid new file mode 100644 index 0000000..b7e4df5 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/tab.gd.uid @@ -0,0 +1 @@ +uid://cf447gbwtnwsl diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/tab.tscn b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/tab.tscn new file mode 100644 index 0000000..ac36500 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/taby/tab.tscn @@ -0,0 +1,79 @@ +[gd_scene load_steps=7 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"] + +[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 + +[node name="ButtonContainer" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 0 + +[node name="PanelContainer" type="Button" parent="VBoxContainer/ButtonContainer"] +auto_translate_mode = 2 +layout_mode = 2 +focus_mode = 0 +mouse_filter = 1 +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 +mouse_filter = 1 +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 + +[node name="Close" type="Button" parent="VBoxContainer/ButtonContainer"] +layout_mode = 2 +focus_mode = 0 +mouse_filter = 1 +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 + +[connection signal="pressed" from="VBoxContainer/ButtonContainer/Pin" to="." method="_on_pin_pressed"] diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/pin/Pin.tscn b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/pin/Pin.tscn new file mode 100644 index 0000000..cbd9174 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/pin/Pin.tscn @@ -0,0 +1,33 @@ +[gd_scene load_steps=4 format=3 uid="uid://cnbyjwmktxipx"] + +[ext_resource type="Script" uid="uid://w8t1dg3mooti" path="res://addons/script_spliter/core/ui/pin/control.gd" id="1_2gb5h"] +[ext_resource type="Script" uid="uid://cl3i4qjav3ikw" path="res://addons/script_spliter/core/ui/pin/root.gd" id="1_e0xng"] +[ext_resource type="Script" uid="uid://c34ix3uq8fdae" path="res://addons/script_spliter/core/ui/pin/pin.gd" id="1_ulj15"] + +[node name="Control" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_e0xng") + +[node name="Control" type="ScrollContainer" parent="."] +custom_minimum_size = Vector2(0, 16) +layout_mode = 1 +anchors_preset = 10 +anchor_right = 1.0 +offset_right = -1152.0 +offset_bottom = 36.0 +grow_horizontal = 2 +rotation = 1.5707964 +pivot_offset = Vector2(12.06, 12.42) +size_flags_horizontal = 0 +size_flags_vertical = 0 +vertical_scroll_mode = 0 +script = ExtResource("1_2gb5h") + +[node name="HBoxContainer" type="HBoxContainer" parent="Control"] +layout_mode = 2 +script = ExtResource("1_ulj15") diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/pin/control.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/pin/control.gd new file mode 100644 index 0000000..2e9f4ff --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/pin/control.gd @@ -0,0 +1,14 @@ +@tool +extends Control +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Script Splitter +# https://github.com/CodeNameTwister/Script-Splitter +# +# Script Splitter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + +func _draw() -> void: + pivot_offset.x = size.y * 0.335 + pivot_offset.y = size.y * 0.345 + size.x = get_child(0).size.x diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/pin/control.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/pin/control.gd.uid new file mode 100644 index 0000000..ce599d2 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/pin/control.gd.uid @@ -0,0 +1 @@ +uid://w8t1dg3mooti diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/pin/pin.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/pin/pin.gd new file mode 100644 index 0000000..746e507 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/pin/pin.gd @@ -0,0 +1,15 @@ +@tool +extends HBoxContainer +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Script Splitter +# https://github.com/CodeNameTwister/Script-Splitter +# +# Script Splitter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + +func _enter_tree() -> void: + add_to_group(&"__SP_PIN_ROOT__") + +func _exit_tree() -> void: + remove_from_group(&"__SP_PIN_ROOT__") diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/pin/pin.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/pin/pin.gd.uid new file mode 100644 index 0000000..e8cf252 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/pin/pin.gd.uid @@ -0,0 +1 @@ +uid://c34ix3uq8fdae diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/pin/root.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/pin/root.gd new file mode 100644 index 0000000..9c21e06 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/pin/root.gd @@ -0,0 +1,10 @@ +extends Control +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Script Splitter +# https://github.com/CodeNameTwister/Script-Splitter +# +# Script Splitter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +func get_root() -> Node: + return get_node("./../../") diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/pin/root.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/pin/root.gd.uid new file mode 100644 index 0000000..8a4982a --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/pin/root.gd.uid @@ -0,0 +1 @@ +uid://cl3i4qjav3ikw diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/editor/ssp_editor.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/editor/ssp_editor.gd new file mode 100644 index 0000000..23f8130 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/editor/ssp_editor.gd @@ -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 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/editor/ssp_editor.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/editor/ssp_editor.gd.uid new file mode 100644 index 0000000..3e84528 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/editor/ssp_editor.gd.uid @@ -0,0 +1 @@ +uid://bec3qea1dh8xe diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/editor_container.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/editor_container.gd new file mode 100644 index 0000000..24c8919 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/editor_container.gd @@ -0,0 +1,94 @@ +@tool +extends TabContainer +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Script Splitter +# https://github.com/CodeNameTwister/Script-Splitter +# +# Script Splitter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +const Dottab = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/taby/dottab.gd") +const CLOSE = preload("res://addons/_Godot-IDE_/plugins/script_splitter/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 + +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.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 _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: + 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) diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/editor_container.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/editor_container.gd.uid new file mode 100644 index 0000000..047e001 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/editor_container.gd.uid @@ -0,0 +1 @@ +uid://b45owls32pkxk diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/io/io_bar.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/io/io_bar.gd new file mode 100644 index 0000000..8fad1e4 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/io/io_bar.gd @@ -0,0 +1,89 @@ +@tool +extends ScrollContainer +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Script Splitter +# https://github.com/CodeNameTwister/Script-Splitter +# +# Script Splitter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +const PIN = preload("res://addons/_Godot-IDE_/plugins/script_splitter/assets/pin.svg") +const FILL_EXPAND = preload("res://addons/_Godot-IDE_/plugins/script_splitter/assets/fill_expand.svg") +const SPLIT_CPLUS_TOOL = preload("res://addons/_Godot-IDE_/plugins/script_splitter/assets/split_cplus_tool.svg") +const SPLIT_MINUS_TOOL = preload("res://addons/_Godot-IDE_/plugins/script_splitter/assets/split_minus_tool.svg") +const SPLIT_PLUS_TOOL = preload("res://addons/_Godot-IDE_/plugins/script_splitter/assets/split_plus_tool.svg") +const SPLIT_RMINUS_TOOL = preload("res://addons/_Godot-IDE_/plugins/script_splitter/assets/split_rminus_tool.svg") +const SPLIT_RPLUS_TOOL = preload("res://addons/_Godot-IDE_/plugins/script_splitter/assets/split_rplus_tool.svg") +const SPLIT_CMINUS_TOOL = preload("res://addons/_Godot-IDE_/plugins/script_splitter/assets/split_cminus_tool.svg") + +const PAD : float = 12.0 + +var _root : VBoxContainer = null +var _min_size : float = 0.0 + +@warning_ignore("unused_private_class_variable") +var _pin_root : Control = null + +func _ready() -> void: + _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) + _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 _setup() -> void: + make_function(&"EXPAND", FILL_EXPAND, _tr("Expand/Unexpand current tab container")) + make_function(&"SPLIT_COLUMN", SPLIT_CPLUS_TOOL, _tr("Split to new column")) + make_function(&"MERGE_COLUMN", SPLIT_CMINUS_TOOL, _tr("Merge current column")) + make_function(&"SPLIT_ROW", SPLIT_RPLUS_TOOL, _tr("Split to new row")) + make_function(&"MERGE_ROW", SPLIT_RMINUS_TOOL, _tr("Merge current row")) + 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")) + +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) diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/io/io_bar.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/io/io_bar.gd.uid new file mode 100644 index 0000000..3d47ef5 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/io/io_bar.gd.uid @@ -0,0 +1 @@ +uid://b817wwia7hrqd diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_container.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_container.gd new file mode 100644 index 0000000..e5b4222 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_container.gd @@ -0,0 +1,292 @@ +@tool +extends MarginContainer +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Script Splitter +# https://github.com/CodeNameTwister/Script-Splitter +# +# Script Splitter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +const SplitterRoot = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_root.gd") +const HandlerContainer = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/base/container.gd") +const BaseContainerItem = preload("splitter_item.gd") + +const SplitterEditorContainer = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_editor_container.gd") + +const Overlay = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/taby/overlay.gd") +const CODE_NAME_TWISTER = preload("res://addons/_Godot-IDE_/plugins/script_splitter/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]: + return _base_container.get_children() + +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 + + 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 + + + vspl.add_child(_handler_container.get_io_bar()) + 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_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) + +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() + _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 _base_container.visible: + _base_container.visible = false diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_container.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_container.gd.uid new file mode 100644 index 0000000..377bda5 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_container.gd.uid @@ -0,0 +1 @@ +uid://dyo7c2g4uwn0g diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_editor_container.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_editor_container.gd new file mode 100644 index 0000000..b2ef7ba --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_editor_container.gd @@ -0,0 +1,80 @@ +extends VBoxContainer +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Script Splitter +# https://github.com/CodeNameTwister/Script-Splitter +# +# Script Splitter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +const Editor = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/editor_container.gd") +const CONTAINER = preload("res://addons/_Godot-IDE_/plugins/script_splitter/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() + + set(&"theme_override_constants/separation", -12) + + 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() diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_editor_container.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_editor_container.gd.uid new file mode 100644 index 0000000..f094d34 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_editor_container.gd.uid @@ -0,0 +1 @@ +uid://dlqgddtcsov1m diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_item.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_item.gd new file mode 100644 index 0000000..f5296c7 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_item.gd @@ -0,0 +1,67 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/split_container_item.gd" + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Script Splitter +# https://github.com/CodeNameTwister/Script-Splitter +# +# Script Splitter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + +var _fms : float = 0.0 + +func _ready() -> void: + super() + modulate = Color.DARK_GRAY + set_physics_process(modulate != Color.WHITE) + +func _physics_process(delta: float) -> void: + _fms += delta * 0.24 + if _fms >= 1.0: + _fms = 1.0 + set_physics_process(false) + modulate = lerp(modulate, Color.WHITE, _fms) + +func _enter_tree() -> void: + super() + + add_to_group(&"__SP_IC__") + var parent : Node = get_parent() + if parent.has_method(&"expand_splited_container"): + _on_child(self) + +func _exit_tree() -> void: + add_to_group(&"__SP_IC__") + +func _on_child(n : Node) -> void: + if n is Control: + var parent : Node = get_parent() + if !n.child_entered_tree.is_connected(_on_child): + n.child_entered_tree.connect(_on_child) + + if !n.child_exiting_tree.is_connected(_out_child): + n.child_exiting_tree.connect(_out_child) + + if n.focus_mode != Control.FOCUS_NONE: + if !n.focus_entered.is_connected(parent.expand_splited_container): + n.focus_entered.connect(parent.expand_splited_container.bind(self)) + + for x : Node in n.get_children(): + _on_child(x) + +func _out_child(n : Node) -> void: + if n is Control: + var parent : Node = get_parent() + if n.child_entered_tree.is_connected(_on_child): + n.child_entered_tree.disconnect(_on_child) + + if n.child_exiting_tree.is_connected(_out_child): + n.child_exiting_tree.disconnect(_out_child) + + if n.focus_mode != Control.FOCUS_NONE: + if n.focus_entered.is_connected(parent.expand_splited_container): + n.focus_entered.disconnect(parent.expand_splited_container) + for x : Node in n.get_children(): + _out_child(x) + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_item.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_item.gd.uid new file mode 100644 index 0000000..f9aa33b --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_item.gd.uid @@ -0,0 +1 @@ +uid://b2kiv55ed0aj diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_list.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_list.gd new file mode 100644 index 0000000..34471c1 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_list.gd @@ -0,0 +1,87 @@ +@tool +extends ItemList +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Script Splitter +# https://github.com/CodeNameTwister/Script-Splitter +# +# Script Splitter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + +var _ss: Callable +var _delta : int = 0 +var _list : ItemList = null + +func _ready() -> void: + set_physics_process(false) + +func update() -> void: + _delta = 0 + set_physics_process(true) + +func set_list(item : ItemList) -> void: + _list = item + +func set_reference(scall : Callable) -> void: + _ss = scall + +func changes(list : ItemList) -> bool: + if list.item_count != item_count: + return true + + for x : int in list.item_count: + if is_selected(x) != is_selected(x) or \ + get_item_text(x) != list.get_item_text(x) or\ + get_item_icon(x) != list.get_item_icon(x) or \ + get_item_icon_modulate(x) != list.get_item_icon_modulate(x) or \ + get_item_tooltip(x) != list.get_item_tooltip(x): + return true + + return false + +func _physics_process(__ : float) -> void: + _delta += 1 + if _delta < 10: + return + set_physics_process(false) + if !_ss.is_valid(): + return + if !changes(_list): + return + _ss.call() + +# +#var dragged_item_index: int = -1 +# +#func _get_drag_data(at_position: Vector2) -> Variant: + #var item_index = get_item_at_position(at_position) +# + #if item_index != -1: + #dragged_item_index = item_index + # + #var drag_preview : Label = Label.new() + #drag_preview.text = get_item_text(item_index) + #set_drag_preview(drag_preview) + # + #return item_index + #return null +# +#func _can_drop_data(at_position: Vector2, data: Variant) -> bool: + #if typeof(data) == TYPE_INT: + #var drop_index : int = get_item_at_position(at_position) + # + #return drop_index != -1 and drop_index != data + # + #return false +# +#func _drop_data(at_position: Vector2, data: Variant) -> void: + #if !(data is int): + #return + #var from_index : int = data as int + # + #var to_index : int = get_item_at_position(at_position) + # + #if from_index != -1 and to_index != -1: + #_list.move_item(from_index, to_index) + # + #dragged_item_index = -1 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_list.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_list.gd.uid new file mode 100644 index 0000000..b4b29c9 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_list.gd.uid @@ -0,0 +1 @@ +uid://c12gyjf2qmasp diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_root.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_root.gd new file mode 100644 index 0000000..a1f6182 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_root.gd @@ -0,0 +1,108 @@ +@tool +extends "res://addons/_Godot-IDE_/plugins/script_splitter/core/ui/multi_split_container/multi_split_container.gd" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Script Splitter +# https://github.com/CodeNameTwister/Script-Splitter +# +# Script Splitter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +const EXPAND = preload("res://addons/_Godot-IDE_/plugins/script_splitter/assets/expand.svg") + +var __setup : bool = false +var _delta : float = 0.0 + +func _init() -> void: + super() + + drag_button_icon = EXPAND + drag_button_size = 24.0 + behaviour_expand_on_focus = true + behaviour_can_expand_focus_same_container = false + behaviour_expand_smoothed = true + drag_button_always_visible = false + drag_button_modulate = Color.WHITE + behaviour_expand_on_double_click = true + behaviour_can_move_by_line = true + + _setup() + +func _ready() -> void: + super() + modulate.a = 0.0 + set_physics_process(true) + +func _physics_process(delta : float) -> void: + _delta += delta * 2.0 + if _delta >= 1.0: + _delta = 1.0 + set_physics_process(false) + modulate.a = _delta + + +func _on_change() -> void: + var dt : Array = ["plugin/script_splitter/editor/behaviour/expand_on_focus" + ,"plugin/script_splitter/editor/behaviour/can_expand_on_same_focus" + ,"plugin/script_splitter/editor/behaviour/smooth_expand" + ,"plugin/script_splitter/editor/behaviour/smooth_expand_time" + ,"plugin/script_splitter/line/size" + ,"plugin/script_splitter/line/color" + ,"plugin/script_splitter/line/draggable" + ,"plugin/script_splitter/line/expand_by_double_click" + ,"plugin/script_splitter/line/button/size" + ,"plugin/script_splitter/line/button/modulate" + ,"plugin/script_splitter/line/button/always_visible" + ] + + var settings : EditorSettings = EditorInterface.get_editor_settings() + var changes : PackedStringArray = settings.get_changed_settings() + + for c in changes: + if c in dt: + _setup() + update() + 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 [ + ["behaviour_expand_on_focus", "plugin/script_splitter/editor/behaviour/expand_on_focus"] + ,["behaviour_can_expand_focus_same_container", "plugin/script_splitter/editor/behaviour/can_expand_on_same_focus"] + ,["behaviour_expand_smoothed", "plugin/script_splitter/editor/behaviour/smooth_expand"] + ,["drag_button_size", "plugin/script_splitter/editor/behaviour/smooth_expand_time"] + ,["separator_line_size", "plugin/script_splitter/line/size"] + ,["separator_line_color", "plugin/script_splitter/line/color"] + ,["behaviour_can_move_by_line", "plugin/script_splitter/line/draggable"] + ,["behaviour_expand_on_double_click", "plugin/script_splitter/line/expand_by_double_click"] + ,["drag_button_size", "plugin/script_splitter/line/button/size"] + ,["drag_button_modulate", "plugin/script_splitter/line/button/modulate"] + ,["drag_button_always_visible", "plugin/script_splitter/line/button/always_visible"] + ]: + if settings.has_setting(x[1]): + set(x[0], settings.get_setting(x[1])) + else: + settings.set_setting(x[1], get(x[0])) + + +func _enter_tree() -> void: + add_to_group(&"__ST_CS__") + super() + + if __setup: + return + + __setup = true + + _setup() + +func _exit_tree() -> void: + remove_from_group(&"__ST_CS__") + + var settings : EditorSettings = EditorInterface.get_editor_settings() + if settings.settings_changed.is_connected(_on_change): + settings.settings_changed.disconnect(_on_change) + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_root.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_root.gd.uid new file mode 100644 index 0000000..532e88c --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/splitter_root.gd.uid @@ -0,0 +1 @@ +uid://cl2dnbvuovoro diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/taby/dottab.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/taby/dottab.gd new file mode 100644 index 0000000..cb473d1 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/taby/dottab.gd @@ -0,0 +1,78 @@ +@tool +extends TabBar +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Script Splitter +# https://github.com/CodeNameTwister/Script-Splitter +# +# Script Splitter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + + +signal on_start_drag(t : TabBar) +signal on_stop_drag(t : TabBar) + +var is_drag : bool = false: + set(e): + is_drag = e + if is_drag: + Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN) + else: + Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) + +var _fms : float = 0.0 + +func reset() -> void: + if is_drag: + set_process(false) + is_drag = false + if is_inside_tree(): + on_stop_drag.emit(null) + +func _init() -> void: + if is_node_ready(): + _ready() + +func _ready() -> void: + set_process(false) + setup() + + select_with_rmb = true + +func _enter_tree() -> void: + if !is_in_group(&"__SPLITER_TAB__"): + add_to_group(&"__SPLITER_TAB__") + +func _exit_tree() -> void: + if is_in_group(&"__SPLITER_TAB__"): + remove_from_group(&"__SPLITER_TAB__") + +func _process(delta: float) -> void: + _fms += delta + if _fms > 0.24: + if is_drag: + if !Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): + set_process(false) + is_drag = false + on_stop_drag.emit(self) + else: + on_start_drag.emit(self) + is_drag = true + +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 >= 0.24: + on_stop_drag.emit(self) diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/taby/dottab.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/taby/dottab.gd.uid new file mode 100644 index 0000000..e2af954 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/taby/dottab.gd.uid @@ -0,0 +1 @@ +uid://bbwrffwhmepvw diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/taby/overlay.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/taby/overlay.gd new file mode 100644 index 0000000..17a2bbf --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/taby/overlay.gd @@ -0,0 +1,120 @@ +@tool +extends ColorRect +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Script Splitter +# https://github.com/CodeNameTwister/Script-Splitter +# +# Script Splitter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +const FILE_IN = preload("res://addons/_Godot-IDE_/plugins/script_splitter/assets/file_in.png") + + +const NORMAL : float = 0.0 +const FILL : float = 0.65 + +var _dt : float = 0.0 +var _fc : float = 0.0 +var _ec : float = 1.0 + +var _ref : TabBar = null +var _container : Control = null + +var txt : TextureRect = null + +func _init() -> void: + visible = false + mouse_filter = Control.MOUSE_FILTER_IGNORE + z_as_relative = false + z_index = RenderingServer.CANVAS_ITEM_Z_MAX - 1 + +func start(ref : TabBar) -> void: + _fc = NORMAL + _ec = FILL + _dt = 0.0 + _ref = ref + modulate.a = _fc + + if is_instance_valid(ref): + _container = ref.get_parent() + else: + _container = null + + _update() + set_process(true) + +func stop(tab : TabBar = null) -> bool: + set_process(false) + visible = false + if is_instance_valid(tab) and tab == _ref: + var container : Node = _ref.get_parent() + if is_instance_valid(_container) and _container == container: + return get_global_rect().has_point(get_global_mouse_position()) + return false + +func get_container() -> Node: + for x : Node in get_tree().get_nodes_in_group(&"__SC_SPLITTER__"): + if x == _container: + continue + var root : Node = x.get_parent() + if root is Control: + var rect : Rect2 = root.get_global_rect() + if rect.has_point(get_global_mouse_position()): + return x + return null + +func _ready() -> void: + color = Color.DARK_GREEN + + set_process(false) + visible = false + + txt = TextureRect.new() + + add_child(txt) + + txt.texture = FILE_IN + txt.expand_mode = TextureRect.EXPAND_KEEP_SIZE + txt.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED + +func _update() -> void: + if is_instance_valid(_container): + for x : Node in get_tree().get_nodes_in_group(&"__SC_SPLITTER__"): + if x == _container: + continue + var root : Node = x.get_parent() + if root is Control: + var rect : Rect2 = root.get_global_rect() + if rect.has_point(get_global_mouse_position()): + size = root.size + global_position = root.global_position + txt.global_position = get_global_rect().get_center() - (txt.texture.get_size() * 0.5) + if !visible: + visible = true + return + + _fc = NORMAL + _ec = FILL + _dt = 0.0 + modulate.a = _fc + visible = false + +func _process(delta: float) -> void: + _update() + + if !visible: + return + + _dt += delta * 2.0 + if _dt >= 1.0: + modulate.a = _ec + if _ec == FILL: + _ec = NORMAL + _fc = FILL + else: + _ec = FILL + _fc = NORMAL + _dt = 0.0 + return + modulate.a = lerpf(_fc, _ec, _dt) + diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/taby/overlay.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/taby/overlay.gd.uid new file mode 100644 index 0000000..d3fafe3 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/ui/splitter/taby/overlay.gd.uid @@ -0,0 +1 @@ +uid://lo116b5bry0t diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/util/control.gd b/addons/_Godot-IDE_/plugins/script_splitter/core/util/control.gd new file mode 100644 index 0000000..3d2dfdc --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/util/control.gd @@ -0,0 +1,22 @@ +@tool +extends Node +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Script Splitter +# https://github.com/CodeNameTwister/Script-Splitter +# +# Script Splitter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + + +signal notification(what : int) + +func _notification(what: int) -> void: + notification.emit(what) + +func panic() -> void: + if !tree_exiting.is_connected(_on_exiting): + tree_exiting.connect(_on_exiting) + +func _on_exiting() -> void: + notification.emit(NOTIFICATION_PREDELETE) diff --git a/addons/_Godot-IDE_/plugins/script_splitter/core/util/control.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/core/util/control.gd.uid new file mode 100644 index 0000000..07902e0 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/core/util/control.gd.uid @@ -0,0 +1 @@ +uid://d3whf030xddd3 diff --git a/addons/_Godot-IDE_/plugins/script_splitter/plugin.cfg b/addons/_Godot-IDE_/plugins/script_splitter/plugin.cfg new file mode 100644 index 0000000..a5e5ffb --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/plugin.cfg @@ -0,0 +1,9 @@ +[plugin] + +name="Script Splitter" +description="Tool Addon for godot 4 +Allow split script window." +author="Twister" +version="0.5-DEV-2.2" +github="https://github.com/CodeNameTwister/Script-Splitter" +script="plugin.gd" diff --git a/addons/_Godot-IDE_/plugins/script_splitter/plugin.gd b/addons/_Godot-IDE_/plugins/script_splitter/plugin.gd new file mode 100644 index 0000000..4b6a839 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/plugin.gd @@ -0,0 +1,85 @@ +@tool +extends EditorPlugin +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Script Splitter +# https://github.com/CodeNameTwister/Script-Splitter +# +# Script Splitter addon for godot 4 +# author: "Twister" +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + + +const InputTool = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/Input.gd") +const TWISTER_script_splitter = preload("res://addons/_Godot-IDE_/plugins/script_splitter/core/builder.gd") +var builder : TWISTER_script_splitter = null +var handler : InputTool = null + +var tab_container : Node = null: + get: + if !is_instance_valid(tab_container): + tab_container = IDE.get_script_editor_container() + return tab_container +var item_list : Node = null: + get: + if !is_instance_valid(item_list): + item_list = IDE.get_script_list() + return item_list + +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 _enter_tree() -> void: + add_to_group(&"__SCRIPT_SPLITTER__") + builder = TWISTER_script_splitter.new() + handler = InputTool.new(self, builder) + +func script_split() -> void: + handler.get_honey_splitter().split() + +func script_merge(value : Node = null) -> void: + handler.get_honey_splitter().merge(value) + +func _ready() -> void: + set_process(false) + set_process_input(false) + for __ : int in range(5): + await Engine.get_main_loop().process_frame + if is_instance_valid(builder): + builder.init_1(self, tab_container, item_list) + if is_instance_valid(handler): + handler.init_1() + + builder.connect_callbacks( + handler.add_column, + handler.add_row, + handler.remove_column, + handler.remove_row, + handler.left_tab_close, + handler.right_tab_close, + handler.others_tab_close + ) + +func _save_external_data() -> void: + builder.refresh_warnings() + +func _exit_tree() -> void: + remove_from_group(&"__SCRIPT_SPLITTER__") + for x : Variant in [handler, builder]: + if is_instance_valid(x) and x is Object: + x.call(&"init_0") + +func get_builder() -> Object: + return builder + +func _process(delta: float) -> void: + builder.update(delta) + +func _input(event: InputEvent) -> void: + if handler.event(event): + get_viewport().set_input_as_handled() + +func _io_call(id : StringName) -> void: + builder.handle(id) diff --git a/addons/_Godot-IDE_/plugins/script_splitter/plugin.gd.uid b/addons/_Godot-IDE_/plugins/script_splitter/plugin.gd.uid new file mode 100644 index 0000000..8dc92c7 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/script_splitter/plugin.gd.uid @@ -0,0 +1 @@ +uid://dxveb5g4kxu45 diff --git a/addons/_Godot-IDE_/plugins/symbol_navigator/gui/exclude_dirs_dialog.gd b/addons/_Godot-IDE_/plugins/symbol_navigator/gui/exclude_dirs_dialog.gd new file mode 100644 index 0000000..7132bf1 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/symbol_navigator/gui/exclude_dirs_dialog.gd @@ -0,0 +1,345 @@ +@tool +extends Window + +# ============================================================================= +# Symbol Navigator - Exclude Directories Dialog +# Author: kyros +# Configure directories to exclude from symbol search +# ============================================================================= + +# UI components +@export var header_label : Label = null +@export var directories_edit : TextEdit = null +@export var preset_container : VBoxContainer = null +@export var save_button : Button = null +@export var cancel_button : Button = null +@export var validation_label : Label = null + +# Preset buttons +var godot_button : Button = null +var git_button : Button = null +var import_button : Button = null +var exports_button : Button = null +var mono_button : Button = null + +# Signal emitted when directories are saved +signal directories_saved(directories: Array[String]) + +# Data +var _current_directories : Array[String] = [] +var _preset_directories = { + ".godot": "Godot 4+ engine cache and settings", + ".git": "Git version control files", + ".import": "Godot 3.x import cache files", + "exports": "Export output directory", + ".mono": "C# Mono build files and cache", + "__pycache__": "Python cache files", + ".vs": "Visual Studio files", + ".vscode": "VS Code settings", + "bin": "Binary output files", + "obj": "Object files from compilation" +} + +func _ready() -> void: + # Initialize UI components + _find_ui_components() + _validate_ui_components() + _connect_signals() + + # Initialize validation label + if validation_label: + validation_label.text = "" + validation_label.modulate = Color.WHITE + + # Setup dialog display + _setup_dialog_display() + +func _find_ui_components() -> void: + """Find and assign UI components""" + header_label = find_child("HeaderLabel") as Label + directories_edit = find_child("DirectoriesEdit") as TextEdit + preset_container = find_child("PresetContainer") as VBoxContainer + save_button = find_child("SaveButton") as Button + cancel_button = find_child("CancelButton") as Button + validation_label = find_child("ValidationLabel") as Label + + # Find preset buttons + godot_button = find_child("GodotButton") as Button + git_button = find_child("GitButton") as Button + import_button = find_child("ImportButton") as Button + exports_button = find_child("ExportsButton") as Button + mono_button = find_child("MonoButton") as Button + +func _validate_ui_components() -> void: + """Validate that all UI components were found""" + var missing_components = [] + + if not header_label: + missing_components.append("HeaderLabel") + if not directories_edit: + missing_components.append("DirectoriesEdit") + if not save_button: + missing_components.append("SaveButton") + if not cancel_button: + missing_components.append("CancelButton") + + if not missing_components.is_empty(): + push_warning("[Exclude Dirs Dialog] Missing UI components: " + str(missing_components)) + +func _connect_signals() -> void: + """Connect button signals""" + if save_button: + save_button.pressed.connect(_on_save_pressed) + if cancel_button: + cancel_button.pressed.connect(_on_cancel_pressed) + if directories_edit: + directories_edit.text_changed.connect(_on_text_changed) + + # Connect preset buttons + if godot_button: + godot_button.pressed.connect(_on_preset_pressed.bind(".godot")) + if git_button: + git_button.pressed.connect(_on_preset_pressed.bind(".git")) + if import_button: + import_button.pressed.connect(_on_preset_pressed.bind(".import")) + if exports_button: + exports_button.pressed.connect(_on_preset_pressed.bind("exports")) + if mono_button: + mono_button.pressed.connect(_on_preset_pressed.bind(".mono")) + +func set_excluded_directories(directories: Array[String]) -> void: + """Set the current excluded directories""" + _current_directories = directories.duplicate() + + if directories_edit: + directories_edit.text = "\n".join(directories) + + _validate_directories() + +func get_excluded_directories() -> Array[String]: + """Get the currently configured directories""" + if not directories_edit: + return _current_directories + + var directories: Array[String] = [] + var lines = directories_edit.text.split("\n") + + for line in lines: + var trimmed = line.strip_edges() + if not trimmed.is_empty(): + directories.append(trimmed) + + return directories + +func _on_save_pressed() -> void: + """Handle save button press""" + var directories = get_excluded_directories() + + # Validate directories before saving + if not _validate_directories(): + return + + # Emit signal with the directories + directories_saved.emit(directories) + + # Close dialog + hide() + queue_free() + +func _on_cancel_pressed() -> void: + """Handle cancel button press""" + hide() + queue_free() + +func _on_close_requested() -> void: + """Handle window close request""" + _on_cancel_pressed() + +func _on_text_changed() -> void: + """Handle text changes in directories edit""" + _validate_directories() + +func _on_preset_pressed(preset_dir: String) -> void: + """Handle preset button press""" + if not directories_edit: + return + + var current_text = directories_edit.text.strip_edges() + var lines = current_text.split("\n") if not current_text.is_empty() else [] + + # Check if directory is already in the list + var already_exists = false + for line in lines: + if line.strip_edges() == preset_dir: + already_exists = true + break + + if not already_exists: + # Add the preset directory + if not current_text.is_empty() and not current_text.ends_with("\n"): + directories_edit.text += "\n" + directories_edit.text += preset_dir + + # Show feedback + _show_validation_message("Added: " + preset_dir, "success") + else: + # Show feedback that it already exists + _show_validation_message("Already exists: " + preset_dir, "warning") + + # Trigger validation + _validate_directories() + +func _validate_directories() -> bool: + """Validate the directory entries""" + if not directories_edit: + return true + + var directories = get_excluded_directories() + var issues = [] + var warnings = [] + + # Check for empty entries (already filtered out in get_excluded_directories()) + + # Check for duplicates + var seen_dirs = [] + for dir in directories: + if dir in seen_dirs: + issues.append("Duplicate: " + dir) + else: + seen_dirs.append(dir) + + # Check for invalid directory names + for dir in directories: + if not _is_valid_directory_name(dir): + issues.append("Invalid name: " + dir) + elif _is_system_directory(dir): + warnings.append("System directory: " + dir) + + # Update validation display + if not issues.is_empty(): + _show_validation_message("Issues: " + ", ".join(issues), "error") + if save_button: + save_button.disabled = true + return false + elif not warnings.is_empty(): + _show_validation_message("Warnings: " + ", ".join(warnings), "warning") + if save_button: + save_button.disabled = false + return true + else: + var count = directories.size() + _show_validation_message("✓ %d directories configured" % count, "success") + if save_button: + save_button.disabled = false + return true + +func _is_valid_directory_name(dir_name: String) -> bool: + """Check if a directory name is valid""" + if dir_name.is_empty(): + return false + + # Check for invalid characters (basic check) + var invalid_chars = ["<", ">", ":", "\"", "|", "?", "*"] + for char in invalid_chars: + if char in dir_name: + return false + + # Check for reserved names (Windows) + var reserved_names = ["CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"] + if dir_name.to_upper() in reserved_names: + return false + + return true + +func _is_system_directory(dir_name: String) -> bool: + """Check if directory is a system directory (warning, not error)""" + var system_dirs = ["System", "Windows", "Program Files", "Users", "etc", "usr", "var", "tmp"] + return dir_name in system_dirs + +func _show_validation_message(message: String, type: String = "info") -> void: + """Show validation message with appropriate color""" + if not validation_label: + return + + validation_label.text = message + + match type: + "success": + validation_label.modulate = Color(0.2, 0.8, 0.2, 1.0) # Green + "warning": + validation_label.modulate = Color(1.0, 0.8, 0.2, 1.0) # Orange + "error": + validation_label.modulate = Color(0.9, 0.2, 0.2, 1.0) # Red + _: + validation_label.modulate = Color.WHITE + +func _input(event: InputEvent) -> void: + """Handle keyboard shortcuts""" + if not visible: + return + + if event is InputEventKey and event.pressed: + match event.keycode: + KEY_ENTER: + # Ctrl+Enter saves + if event.ctrl_pressed: + if save_button and not save_button.disabled: + _on_save_pressed() + get_viewport().set_input_as_handled() + KEY_ESCAPE: + # Escape key cancels + _on_cancel_pressed() + get_viewport().set_input_as_handled() + +func _setup_dialog_display() -> void: + """Setup dialog size and position for proper display""" + # Get optimal size for dialog + var optimal_size = _get_optimal_dialog_size() + size = optimal_size + + # Center the dialog manually + _center_dialog() + +func _get_optimal_dialog_size() -> Vector2i: + """Calculate optimal dialog size based on content and DPI""" + # Base size for exclude dirs dialog + var base_size = Vector2i(600, 450) + + # Get screen info for DPI awareness + var screen = DisplayServer.screen_get_size() + var dpi_scale = DisplayServer.screen_get_scale() + + # Apply DPI scaling if needed + if dpi_scale > 1.0: + base_size = Vector2i( + int(base_size.x * min(dpi_scale, 1.5)), + int(base_size.y * min(dpi_scale, 1.5)) + ) + + # Ensure minimum size + base_size.x = max(base_size.x, 500) + base_size.y = max(base_size.y, 400) + + # Ensure it fits on screen (leave 100px margin) + base_size.x = min(base_size.x, screen.x - 100) + base_size.y = min(base_size.y, screen.y - 100) + + return base_size + +func _center_dialog() -> void: + """Manually center the dialog on screen""" + var screen_size = DisplayServer.screen_get_size() + var dialog_size = size + + # Calculate centered position + var centered_pos = Vector2i( + (screen_size.x - dialog_size.x) / 2, + (screen_size.y - dialog_size.y) / 2 + ) + + # Ensure dialog stays on screen + centered_pos.x = max(0, centered_pos.x) + centered_pos.y = max(0, centered_pos.y) + + # Set position + position = centered_pos diff --git a/addons/_Godot-IDE_/plugins/symbol_navigator/gui/exclude_dirs_dialog.gd.uid b/addons/_Godot-IDE_/plugins/symbol_navigator/gui/exclude_dirs_dialog.gd.uid new file mode 100644 index 0000000..061e421 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/symbol_navigator/gui/exclude_dirs_dialog.gd.uid @@ -0,0 +1 @@ +uid://cpsjg2ybiew8s diff --git a/addons/_Godot-IDE_/plugins/symbol_navigator/gui/exclude_dirs_dialog.tscn b/addons/_Godot-IDE_/plugins/symbol_navigator/gui/exclude_dirs_dialog.tscn new file mode 100644 index 0000000..f2e68ee --- /dev/null +++ b/addons/_Godot-IDE_/plugins/symbol_navigator/gui/exclude_dirs_dialog.tscn @@ -0,0 +1,100 @@ +[gd_scene load_steps=2 format=3 uid="uid://drnd7lnoqdl7n"] + +[ext_resource type="Script" uid="uid://cpsjg2ybiew8s" path="res://addons/_Godot-IDE_/plugins/symbol_navigator/gui/exclude_dirs_dialog.gd" id="1_exclude_script"] + +[node name="ExcludeDirsDialog" type="Window" node_paths=PackedStringArray("header_label", "directories_edit", "preset_container", "save_button", "cancel_button", "validation_label")] +title = "Configure Excluded Directories" +position = Vector2i(1470, 742) +size = Vector2i(900, 675) +exclusive = true +script = ExtResource("1_exclude_script") +header_label = NodePath("MarginContainer/MainContainer/HeaderLabel") +directories_edit = NodePath("MarginContainer/MainContainer/DirectoriesEdit") +preset_container = NodePath("MarginContainer/MainContainer/PresetContainer") +save_button = NodePath("MarginContainer/MainContainer/ButtonContainer/SaveButton") +cancel_button = NodePath("MarginContainer/MainContainer/ButtonContainer/CancelButton") +validation_label = NodePath("MarginContainer/MainContainer/ValidationLabel") + +[node name="MarginContainer" type="MarginContainer" parent="."] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/margin_left = 10 +theme_override_constants/margin_top = 10 +theme_override_constants/margin_right = 10 +theme_override_constants/margin_bottom = 10 + +[node name="MainContainer" type="VBoxContainer" parent="MarginContainer"] +layout_mode = 2 +theme_override_constants/separation = 10 + +[node name="HeaderLabel" type="Label" parent="MarginContainer/MainContainer"] +layout_mode = 2 +text = "Enter directory names to exclude from search (one per line):" +autowrap_mode = 3 + +[node name="DirectoriesEdit" type="TextEdit" parent="MarginContainer/MainContainer"] +layout_mode = 2 +size_flags_vertical = 3 +placeholder_text = "Example: +.godot +.git +.import +exports +.mono" +wrap_mode = 1 + +[node name="ValidationLabel" type="Label" parent="MarginContainer/MainContainer"] +layout_mode = 2 +vertical_alignment = 1 +autowrap_mode = 3 + +[node name="PresetContainer" type="VBoxContainer" parent="MarginContainer/MainContainer"] +layout_mode = 2 +size_flags_vertical = 4 + +[node name="PresetLabel" type="Label" parent="MarginContainer/MainContainer/PresetContainer"] +layout_mode = 2 +text = "Quick Add Common Directories:" + +[node name="PresetButtonsContainer" type="HBoxContainer" parent="MarginContainer/MainContainer/PresetContainer"] +layout_mode = 2 +theme_override_constants/separation = 5 + +[node name="GodotButton" type="Button" parent="MarginContainer/MainContainer/PresetContainer/PresetButtonsContainer"] +layout_mode = 2 +text = ".godot" + +[node name="GitButton" type="Button" parent="MarginContainer/MainContainer/PresetContainer/PresetButtonsContainer"] +layout_mode = 2 +text = ".git" + +[node name="ImportButton" type="Button" parent="MarginContainer/MainContainer/PresetContainer/PresetButtonsContainer"] +layout_mode = 2 +text = ".import" + +[node name="ExportsButton" type="Button" parent="MarginContainer/MainContainer/PresetContainer/PresetButtonsContainer"] +layout_mode = 2 +text = "exports" + +[node name="MonoButton" type="Button" parent="MarginContainer/MainContainer/PresetContainer/PresetButtonsContainer"] +layout_mode = 2 +text = ".mono" + +[node name="ButtonContainer" type="HBoxContainer" parent="MarginContainer/MainContainer"] +layout_mode = 2 +size_flags_vertical = 4 +theme_override_constants/separation = 10 +alignment = 2 + +[node name="SaveButton" type="Button" parent="MarginContainer/MainContainer/ButtonContainer"] +layout_mode = 2 +text = "Save" + +[node name="CancelButton" type="Button" parent="MarginContainer/MainContainer/ButtonContainer"] +layout_mode = 2 +text = "Cancel" + +[connection signal="close_requested" from="." to="." method="_on_close_requested"] diff --git a/addons/_Godot-IDE_/plugins/symbol_navigator/gui/find_references.tscn b/addons/_Godot-IDE_/plugins/symbol_navigator/gui/find_references.tscn new file mode 100644 index 0000000..134c5ab --- /dev/null +++ b/addons/_Godot-IDE_/plugins/symbol_navigator/gui/find_references.tscn @@ -0,0 +1,378 @@ +[gd_scene load_steps=2 format=3 uid="uid://b76nmixqh7tom"] + +[sub_resource type="GDScript" id="GDScript_ly0sj"] +script/source = "@tool +extends Window +# ============================================================================= +# Author: GodotIDE Team +# Symbol Navigator - Find References Window +# +# UI for displaying symbol references across the project +# ============================================================================= + +@export var search_bar : LineEdit = null +@export var results_tree : Tree = null +@export var status_label : Label = null +@export var search_button : Button = null +@export var close_button : Button = null + +var _current_symbol : String = \"\" +var _search_results : Array[Dictionary] = [] + +func _ready() -> void: + # Set up window + title = \"Find References\" + size = Vector2(800, 600) + + # Apply editor theme + var control : Control = EditorInterface.get_base_control() + if control: + get_child(0).add_theme_stylebox_override(&\"panel\", control.get_theme_stylebox(&\"panel\", &\"\")) + + # Connect window close signal + close_requested.connect(_on_close_pressed) + + # Connect signals + if search_button: + search_button.pressed.connect(_on_search_pressed) + if close_button: + close_button.pressed.connect(_on_close_pressed) + if search_bar: + search_bar.text_submitted.connect(_on_search_submitted) + if results_tree: + results_tree.item_activated.connect(_on_item_activated) + + # Set up tree + if results_tree: + results_tree.set_column_titles_visible(true) + results_tree.set_column_title(0, \"File\") + results_tree.set_column_title(1, \"Line\") + results_tree.set_column_title(2, \"Context\") + results_tree.columns = 3 + +func search_symbol(symbol: String) -> void: + _current_symbol = symbol + if search_bar: + search_bar.text = symbol + _perform_search() + +func _on_search_pressed() -> void: + if search_bar: + _current_symbol = search_bar.text + _perform_search() + +func _on_search_submitted(text: String) -> void: + _current_symbol = text + _perform_search() + +func _on_close_pressed() -> void: + hide() + +func _perform_search() -> void: + if _current_symbol.is_empty(): + _update_status(\"Please enter a symbol to search\") + return + + _update_status(\"Searching for references...\") + _clear_results() + + # Perform the actual search + _search_in_project() + + # Update UI + _display_results() + _update_status(\"Found %d references\" % _search_results.size()) + +func _clear_results() -> void: + _search_results.clear() + if results_tree: + results_tree.clear() + +func _search_in_project() -> void: + var fs : EditorFileSystem = EditorInterface.get_resource_filesystem() + if not fs: + return + + var root_dir = fs.get_filesystem() + if root_dir: + _search_in_directory(root_dir) + +func _search_in_directory(dir: EditorFileSystemDirectory) -> void: + # Search in files + for i in range(dir.get_file_count()): + var file_path = dir.get_file_path(i) + var file_type = dir.get_file_type(i) + + # Only search in script files + if file_type == \"GDScript\" or file_path.ends_with(\".gd\"): + _search_in_file(file_path) + + # Search in subdirectories + for i in range(dir.get_subdir_count()): + _search_in_directory(dir.get_subdir(i)) + +func _search_in_file(file_path: String) -> void: + var file = FileAccess.open(file_path, FileAccess.READ) + if not file: + return + + var line_number = 1 + while not file.eof_reached(): + var line = file.get_line() + var matches = _find_symbol_in_line(line, _current_symbol) + + for match_pos in matches: + var result = { + \"file_path\": file_path, + \"line_number\": line_number, + \"line_content\": line.strip_edges(), + \"column\": match_pos + } + _search_results.append(result) + + line_number += 1 + + file.close() + +func _find_symbol_in_line(line: String, symbol: String) -> Array[int]: + var matches: Array[int] = [] + + # Skip lines that are likely false positives + var trimmed_line = line.strip_edges() + + # Skip comments (but allow commented code for reference) + if trimmed_line.begins_with(\"#\") and not trimmed_line.contains(\"func \"): + return matches + + # Skip string literals (basic detection) + if _is_in_string_literal(line, symbol): + return matches + + # Create regex pattern for word boundary matching + var regex = RegEx.new() + var pattern = \"\\\\b\" + _escape_regex_string(symbol) + \"\\\\b\" + regex.compile(pattern) + + var results = regex.search_all(line) + for result in results: + var match_pos = result.get_start() + + # Additional context-aware filtering + if _is_valid_symbol_context(line, match_pos, symbol): + matches.append(match_pos) + + return matches + +# Check if symbol is inside a string literal +func _is_in_string_literal(line: String, symbol: String) -> bool: + var in_string = false + var in_triple_string = false + var quote_char = \"\" + + # Simple string detection (not perfect but catches most cases) + for i in range(line.length()): + var char = line[i] + + # Handle triple quotes + if i < line.length() - 2: + var triple = line.substr(i, 3) + if triple == '\"\"\"' or triple == \"'''\": + if not in_string: + in_triple_string = not in_triple_string + quote_char = triple[0] + continue + + # Handle single/double quotes + if char == '\"' or char == \"'\": + if not in_triple_string: + if not in_string: + in_string = true + quote_char = char + elif char == quote_char: + in_string = false + quote_char = \"\" + + # If we find the symbol and we're currently in a string, it's probably a false positive + return (in_string or in_triple_string) and symbol in line + +# Check if the symbol appears in a valid context +func _is_valid_symbol_context(line: String, position: int, symbol: String) -> bool: + # Get context around the symbol + var start = max(0, position - 10) + var end = min(line.length(), position + symbol.length() + 10) + var context = line.substr(start, end - start) + + # Skip if it's part of a longer identifier (additional safety) + if position > 0: + var prev_char = line[position - 1] + if _is_identifier_char(prev_char): + return false + + if position + symbol.length() < line.length(): + var next_char = line[position + symbol.length()] + if _is_identifier_char(next_char): + return false + + return true + +func _is_identifier_char(char: String) -> bool: + return char.is_valid_identifier() or char == \"_\" + +# Escape special regex characters since Godot 4 doesn't have RegEx.escape() +func _escape_regex_string(text: String) -> String: + var escaped = text + # Order matters - escape backslash first + escaped = escaped.replace(\"\\\\\", \"\\\\\\\\\") + escaped = escaped.replace(\".\", \"\\\\.\") + escaped = escaped.replace(\"^\", \"\\\\^\") + escaped = escaped.replace(\"$\", \"\\\\$\") + escaped = escaped.replace(\"*\", \"\\\\*\") + escaped = escaped.replace(\"+\", \"\\\\+\") + escaped = escaped.replace(\"?\", \"\\\\?\") + escaped = escaped.replace(\"(\", \"\\\\(\") + escaped = escaped.replace(\")\", \"\\\\)\") + escaped = escaped.replace(\"[\", \"\\\\[\") + escaped = escaped.replace(\"]\", \"\\\\]\") + escaped = escaped.replace(\"{\", \"\\\\{\") + escaped = escaped.replace(\"}\", \"\\\\}\") + escaped = escaped.replace(\"|\", \"\\\\|\") + return escaped + +func _display_results() -> void: + if not results_tree: + return + + results_tree.clear() + var root = results_tree.create_item() + root.set_text(0, \"References (%d)\" % _search_results.size()) + + var file_groups = {} + + # Group results by file + for result in _search_results: + var file_path = result[\"file_path\"] + if not file_groups.has(file_path): + file_groups[file_path] = [] + file_groups[file_path].append(result) + + # Create tree structure + for file_path in file_groups.keys(): + var file_item = root.create_child() + var file_name = file_path.get_file() + var relative_path = file_path.replace(\"res://\", \"\") + + file_item.set_text(0, file_name) + file_item.set_text(1, \"\") + file_item.set_text(2, relative_path) + file_item.set_metadata(0, {\"type\": \"file\", \"path\": file_path}) + + # Add individual references + for result in file_groups[file_path]: + var ref_item = file_item.create_child() + ref_item.set_text(0, \"\") + ref_item.set_text(1, str(result[\"line_number\"])) + ref_item.set_text(2, result[\"line_content\"]) + ref_item.set_metadata(0, result) + +func _on_item_activated() -> void: + var selected = results_tree.get_selected() + if not selected: + return + + var metadata = selected.get_metadata(0) + if not metadata: + return + + # Navigate to the reference + if metadata.has(\"file_path\") and metadata.has(\"line_number\"): + _navigate_to_reference(metadata[\"file_path\"], metadata[\"line_number\"], metadata.get(\"column\", 0)) + +func _navigate_to_reference(file_path: String, line_number: int, column: int) -> void: + # Open the file in the script editor + var script = ResourceLoader.load(file_path) + if script and script is Script: + EditorInterface.edit_script(script) + + # Navigate to specific line + var script_editor = EditorInterface.get_script_editor() + if script_editor: + script_editor.goto_line(line_number - 1) + + # Focus on the specific column if possible + var current_editor = script_editor.get_current_editor() + if current_editor: + var code_edit : CodeEdit = current_editor.get_base_editor() + if code_edit: + code_edit.set_caret_line(line_number - 1) + code_edit.set_caret_column(column) + +func _update_status(message: String) -> void: + if status_label: + status_label.text = message + + +func _on_close_requested() -> void: + _on_close_pressed() + + +func _on_focus_exited() -> void: + _on_close_pressed() +" + +[node name="Window" type="Window" node_paths=PackedStringArray("search_bar", "results_tree", "status_label", "search_button", "close_button")] +title = "Find References" +position = Vector2i(0, 36) +size = Vector2i(800, 600) +exclusive = true +script = SubResource("GDScript_ly0sj") +search_bar = NodePath("VBoxContainer/SearchBar/SearchBar") +results_tree = NodePath("VBoxContainer/MainContent/Tree") +status_label = NodePath("VBoxContainer/Status/Label") +search_button = NodePath("VBoxContainer/SearchBar/Button") +close_button = NodePath("VBoxContainer/Status/Button") + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 + +[node name="SearchBar" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="VBoxContainer/SearchBar"] +layout_mode = 2 +text = "Search for:" + +[node name="SearchBar" type="LineEdit" parent="VBoxContainer/SearchBar"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Button" type="Button" parent="VBoxContainer/SearchBar"] +layout_mode = 2 +text = "Search" + +[node name="MainContent" type="HSplitContainer" parent="VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="Tree" type="Tree" parent="VBoxContainer/MainContent"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 0.0 +columns = 3 +column_titles_visible = true + +[node name="Status" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 4 + +[node name="Label" type="Label" parent="VBoxContainer/Status"] +layout_mode = 2 +text = "Ready" + +[node name="Button" type="Button" parent="VBoxContainer/Status"] +layout_mode = 2 +text = "Close" + +[connection signal="close_requested" from="." to="." method="_on_close_requested"] +[connection signal="focus_exited" from="." to="." method="_on_focus_exited"] diff --git a/addons/_Godot-IDE_/plugins/symbol_navigator/gui/find_references_panel.gd b/addons/_Godot-IDE_/plugins/symbol_navigator/gui/find_references_panel.gd new file mode 100644 index 0000000..bf03cf6 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/symbol_navigator/gui/find_references_panel.gd @@ -0,0 +1,1123 @@ +@tool +extends Control +# ============================================================================= +# Symbol Navigator - Find References Panel +# Author: kyros +# Bottom panel UI for displaying symbol references with navigation and code preview +# ============================================================================= + +@export var search_bar : LineEdit = null +@export var results_tree : Tree = null +@export var status_label : Label = null +@export var search_button : Button = null +@export var clear_button : Button = null +@export var code_header : Label = null +@export var code_display : RichTextLabel = null +@export var case_sensitive_check : CheckBox = null +@export var match_mode_option : OptionButton = null +@export var exclude_dirs_button : Button = null +@export var highlight_style_option : OptionButton = null + +enum MatchMode { + WORD_BOUNDARY, # Word boundary matching (default) + EXACT, # Hole line exact match + STARTS_WITH, # Start matching + CONTAINS, # Include match + ENDS_WITH # end match +} + +var _current_symbol : String = "" +var _search_results : Array[Dictionary] = [] +var _case_sensitive : bool = false +var _match_mode : MatchMode = MatchMode.WORD_BOUNDARY +var _excluded_directories : Array[String] = [] +var _highlight_style : String = "dots" +var _highlight_prefix : String = "·" +var _highlight_suffix : String = "·" + +func _ready() -> void: + # Initialize components and connections + _ensure_components_initialized() + + # Apply editor theme for integration + var editor_control : Control = EditorInterface.get_base_control() + if editor_control: + var theme = editor_control.get_theme() + if theme: + set_theme(theme) + + # Connect UI signals + if search_button: + search_button.pressed.connect(_on_search_pressed) + if clear_button: + clear_button.pressed.connect(_on_clear_pressed) + if search_bar: + search_bar.text_submitted.connect(_on_search_submitted) + search_bar.text_changed.connect(_on_search_text_changed) + if results_tree: + results_tree.item_activated.connect(_on_item_activated) + results_tree.item_selected.connect(_on_item_selected) + if case_sensitive_check: + case_sensitive_check.toggled.connect(_on_case_sensitive_toggled) + if match_mode_option: + match_mode_option.item_selected.connect(_on_match_mode_changed) + _setup_match_mode_options() + if exclude_dirs_button: + exclude_dirs_button.pressed.connect(_on_exclude_dirs_pressed) + if highlight_style_option: + highlight_style_option.item_selected.connect(_on_highlight_style_changed) + _setup_highlight_style_options() + + # Configure tree columns + if results_tree: + results_tree.set_column_titles_visible(true) + results_tree.set_column_title(0, "File / Reference") + results_tree.set_column_title(1, "Line") + results_tree.columns = 2 + results_tree.set_column_expand_ratio(0, 3.0) + results_tree.set_column_expand_ratio(1, 1.0) + + # Initialize UI state + _update_results_info("Enter a symbol to search") + _clear_code_display() + + # Load saved configuration + _load_configuration() + +func _load_configuration() -> void: + """Load saved configuration settings""" + # Load case sensitivity setting + var saved_case_sensitive = IDE.get_config("symbol_navigator", "case_sensitive") #if not exist config, return a null + if saved_case_sensitive is bool: + _case_sensitive = saved_case_sensitive + if case_sensitive_check: + case_sensitive_check.set_pressed_no_signal(_case_sensitive) + + # Load match mode setting + var saved_match_mode = IDE.get_config("symbol_navigator", "match_mode") + if null != saved_match_mode: + _match_mode = saved_match_mode as MatchMode + if match_mode_option: + match_mode_option.select(saved_match_mode) + + # Load excluded directories + var saved_excluded_dirs = IDE.get_config("symbol_navigator", "excluded_directories") + if null != saved_excluded_dirs: + _excluded_directories = saved_excluded_dirs + + # Load highlight style setting + var saved_highlight_style = IDE.get_config("symbol_navigator", "highlight_style") + _highlight_style = saved_highlight_style if saved_highlight_style else "dots" + _update_highlight_markers() + if highlight_style_option: + highlight_style_option.select(_get_style_index(_highlight_style)) + +func _ensure_components_initialized() -> void: + """Ensure all exported components are properly initialized""" + if not search_bar: + search_bar = _find_component_robust("SearchBar", LineEdit) + if not results_tree: + results_tree = _find_component_robust("ResultsTree", Tree) + if not status_label: + status_label = _find_component_robust("StatusLabel", Label) + if not search_button: + search_button = _find_component_robust("SearchButton", Button) + if not clear_button: + clear_button = _find_component_robust("ClearButton", Button) + if not code_header: + code_header = _find_component_robust("CodeHeader", Label) + if not code_display: + code_display = _find_component_robust("CodeDisplay", TextEdit) + if not case_sensitive_check: + case_sensitive_check = _find_component_robust("CaseSensitiveCheck", CheckBox) + if not match_mode_option: + match_mode_option = _find_component_robust("MatchModeOption", OptionButton) + if not exclude_dirs_button: + exclude_dirs_button = _find_component_robust("ExcludeDirsButton", Button) + if not highlight_style_option: + highlight_style_option = _find_component_robust("HighlightStyleOption", OptionButton) + + # Only log if critical components are missing + var missing_components = [] + if not search_bar: missing_components.append("search_bar") + if not results_tree: missing_components.append("results_tree") + if not status_label: missing_components.append("status_label") + + if not missing_components.is_empty(): + print("Error: Missing critical components: %s" % ", ".join(missing_components)) + + +func _find_component_robust(component_name: String, component_type) -> Node: + """Robust component finder using multiple strategies""" + var found_component: Node = null + + # Strategy 1: Direct NodePath lookup + var expected_paths = _get_expected_paths(component_name) + for path in expected_paths: + found_component = get_node_or_null(path) + if found_component and _is_correct_type(found_component, component_type): + return found_component + + # Strategy 2: find_child() search + found_component = find_child(component_name, true, false) + if found_component and _is_correct_type(found_component, component_type): + return found_component + + # Strategy 3: Recursive search by type and name + found_component = _recursive_find_by_type_and_name(self, component_type, component_name) + if found_component: + return found_component + + # Strategy 4: Recursive search by type only (first match) + found_component = _recursive_find_by_type(self, component_type) + if found_component: + return found_component + + # Strategy 5: Partial name matching + found_component = _recursive_find_by_partial_name(self, component_name.to_lower()) + if found_component and _is_correct_type(found_component, component_type): + return found_component + + return null + +func _is_correct_type(node: Node, expected_type) -> bool: + """Check if a node is of the expected type""" + # Use multiple type checking methods for robustness + if expected_type == LineEdit: + return node is LineEdit + elif expected_type == Tree: + return node is Tree + elif expected_type == Label: + return node is Label + elif expected_type == Button: + return node is Button + elif expected_type == TextEdit: + return node is TextEdit + elif expected_type == CheckBox: + return node is CheckBox + elif expected_type == OptionButton: + return node is OptionButton + elif expected_type == RichTextLabel: + return node is RichTextLabel + else: + # Fallback to class name comparison + return node.get_class() == str(expected_type).get_slice(":", 0) + +func _get_expected_paths(component_name: String) -> Array[String]: + """Get all possible paths for a component""" + var paths: Array[String] = [] + + # Add the standard expected paths + match component_name: + "SearchBar": + paths.append("MainContainer/SearchSection/SearchBar") + "ResultsTree": + paths.append("MainContainer/MainContent/LeftPanel/ResultsTree") + "StatusLabel": + paths.append("MainContainer/StatusSection/StatusLabel") + "SearchButton": + paths.append("MainContainer/SearchSection/SearchButton") + "ClearButton": + paths.append("MainContainer/StatusSection/ClearButton") + "CodeHeader": + paths.append("MainContainer/MainContent/RightPanel/CodeHeader") + "CodeDisplay": + paths.append("MainContainer/MainContent/RightPanel/CodeDisplay") + "CaseSensitiveCheck": + paths.append("MainContainer/SearchSection/CaseSensitiveCheck") + "MatchModeOption": + paths.append("MainContainer/SearchSection/MatchModeOption") + "ExcludeDirsButton": + paths.append("MainContainer/SearchSection/ExcludeDirsButton") + "HighlightStyleOption": + paths.append("MainContainer/SearchSection/HighlightStyleOption") + + return paths + +func _recursive_find_by_type_and_name(node: Node, target_type, target_name: String) -> Node: + """Recursively search for a node of the specified type and name""" + if _is_correct_type(node, target_type) and target_name.to_lower() in node.name.to_lower(): + return node + + for child in node.get_children(): + var result = _recursive_find_by_type_and_name(child, target_type, target_name) + if result: + return result + + return null + +func _recursive_find_by_type(node: Node, target_type) -> Node: + """Recursively search for a node of the specified type""" + if _is_correct_type(node, target_type): + return node + + for child in node.get_children(): + var result = _recursive_find_by_type(child, target_type) + if result: + return result + + return null + +func _recursive_find_by_partial_name(node: Node, partial_name: String) -> Node: + """Recursively search for a node with a name containing the partial string""" + if partial_name in node.name.to_lower(): + return node + + for child in node.get_children(): + var result = _recursive_find_by_partial_name(child, partial_name) + if result: + return result + + return null + +func search_symbol(symbol: String) -> void: + """Start a search for the given symbol and display results""" + _current_symbol = symbol + if search_bar: + search_bar.text = symbol + + # Ensure components are ready before search + _ensure_components_initialized() + + _perform_search() + +func _on_search_pressed() -> void: + if search_bar: + _current_symbol = search_bar.text.strip_edges() + _perform_search() + +func _on_search_submitted(text: String) -> void: + _current_symbol = text.strip_edges() + _perform_search() + +func _on_search_text_changed(text: String) -> void: + # Enable/disable search button based on input + if search_button: + search_button.disabled = text.strip_edges().is_empty() + +func _on_clear_pressed() -> void: + _clear_results() + if search_bar: + search_bar.clear() + search_bar.grab_focus() + _update_status("Cleared") + _update_results_info("Enter a symbol to search") + +func _on_case_sensitive_toggled(pressed: bool) -> void: + _case_sensitive = pressed + # Save setting + IDE.set_config("symbol_navigator", "case_sensitive", _case_sensitive) + # Automatically re-search if we have a current symbol + if not _current_symbol.is_empty(): + _perform_search() + +func _on_match_mode_changed(index: int) -> void: + _match_mode = index as MatchMode + # Save setting + IDE.set_config("symbol_navigator", "match_mode", _match_mode) + # Automatically re-search if we have a current symbol + if not _current_symbol.is_empty(): + _perform_search() + +func _on_highlight_style_changed(index: int) -> void: + """Handle highlight style option change""" + var style_names = ["dots", "brackets", "arrows", "quotes", "squares", "circles"] + _highlight_style = style_names[index] + _update_highlight_markers() + # Save setting + IDE.set_config("symbol_navigator", "highlight_style", _highlight_style) + # Automatically re-search if we have a current symbol + if not _current_symbol.is_empty(): + _perform_search() + +func _update_highlight_markers() -> void: + """Update highlight prefix and suffix based on current style""" + match _highlight_style: + "dots": + _highlight_prefix = "·" + _highlight_suffix = "·" + "brackets": + _highlight_prefix = "(" + _highlight_suffix = ")" + "arrows": + _highlight_prefix = "→" + _highlight_suffix = "←" + "quotes": + _highlight_prefix = "「" + _highlight_suffix = "」" + "squares": + _highlight_prefix = "▪" + _highlight_suffix = "▪" + "circles": + _highlight_prefix = "○" + _highlight_suffix = "○" + _: + _highlight_prefix = "·" + _highlight_suffix = "·" + +func _get_style_index(style_name: String) -> int: + """Get the index of a style name in the options""" + var style_names = ["dots", "brackets", "arrows", "quotes", "squares", "circles"] + var index = style_names.find(style_name) + return index if index != -1 else 0 + +func _setup_match_mode_options() -> void: + if not match_mode_option: + return + + match_mode_option.clear() + match_mode_option.add_item("Word Boundary") + match_mode_option.add_item("Exact Match") + match_mode_option.add_item("Starts With") + match_mode_option.add_item("Contains") + match_mode_option.add_item("Ends With") + match_mode_option.selected = _match_mode + +func _setup_highlight_style_options() -> void: + """Setup the highlight style option button with available styles""" + if not highlight_style_option: + return + + highlight_style_option.clear() + highlight_style_option.add_item("Dots (·symbol·)") + highlight_style_option.add_item("Brackets ((symbol))") + highlight_style_option.add_item("Arrows (→symbol←)") + highlight_style_option.add_item("Quotes (「symbol」)") + highlight_style_option.add_item("Squares (▪symbol▪)") + highlight_style_option.add_item("Circles (○symbol○)") + highlight_style_option.selected = _get_style_index(_highlight_style) + +func _on_exclude_dirs_pressed() -> void: + """Show dialog to configure excluded directories""" + _show_exclude_dirs_dialog() + +func _show_exclude_dirs_dialog() -> void: + """Show dialog to configure excluded directories using dedicated scene""" + # Load the exclude directories dialog scene + var dialog_scene = load("res://addons/_Godot-IDE_/plugins/symbol_navigator/gui/exclude_dirs_dialog.tscn") + if not dialog_scene: + print("Error: Cannot load exclude_dirs_dialog.tscn") + _show_exclude_dirs_dialog_fallback() + return + + # Instantiate the dialog + var dialog = dialog_scene.instantiate() + if not dialog: + print("Error: Cannot instantiate exclude_dirs_dialog") + _show_exclude_dirs_dialog_fallback() + return + + # Set current excluded directories + dialog.set_excluded_directories(_excluded_directories) + + # Connect the save signal + dialog.directories_saved.connect(_on_directories_saved) + + # Add to editor interface (better than current_scene for editor plugins) + var editor_control = EditorInterface.get_base_control() + if editor_control: + editor_control.add_child(dialog) + else: + # Fallback to current scene + get_tree().current_scene.add_child(dialog) + + # Show the dialog + dialog.popup_centered() + +func _on_directories_saved(directories: Array[String]) -> void: + """Handle directories saved from the exclude dialog""" + _excluded_directories = directories.duplicate() + + # Save to configuration + IDE.set_config("symbol_navigator", "excluded_directories", _excluded_directories) + + # Update status + var count = _excluded_directories.size() + _update_status("Updated excluded directories (%d configured)" % count) + + # Re-search if we have a current symbol + if not _current_symbol.is_empty(): + _perform_search() + +func _show_exclude_dirs_dialog_fallback() -> void: + """Fallback dialog implementation for when scene loading fails""" + var dialog = AcceptDialog.new() + dialog.title = "Configure Excluded Directories" + dialog.size = Vector2i(400, 300) + + var vbox = VBoxContainer.new() + dialog.add_child(vbox) + + var info_label = Label.new() + info_label.text = "Enter directory names to exclude from search (one per line):" + vbox.add_child(info_label) + + var text_edit = TextEdit.new() + text_edit.text = "\n".join(_excluded_directories) + text_edit.custom_minimum_size = Vector2(380, 200) + vbox.add_child(text_edit) + + var button_container = HBoxContainer.new() + vbox.add_child(button_container) + + var save_button = Button.new() + save_button.text = "Save" + button_container.add_child(save_button) + + var cancel_button = Button.new() + cancel_button.text = "Cancel" + button_container.add_child(cancel_button) + + # Add to editor interface (improved for editor plugins) + var editor_control = EditorInterface.get_base_control() + if editor_control: + editor_control.add_child(dialog) + else: + get_tree().current_scene.add_child(dialog) + + # Connect signals + save_button.pressed.connect(func(): + _save_excluded_directories_from_fallback(text_edit.text) + dialog.queue_free() + ) + cancel_button.pressed.connect(func(): + dialog.queue_free() + ) + + dialog.popup_centered() + +func _save_excluded_directories_from_fallback(text: String) -> void: + """Save excluded directories from fallback dialog""" + var directories: Array[String] = [] + var lines = text.split("\n") + for line in lines: + var trimmed = line.strip_edges() + if not trimmed.is_empty(): + directories.append(trimmed) + + # Use the same handler as the main dialog + _on_directories_saved(directories) + +func _perform_search() -> void: + if _current_symbol.is_empty(): + _update_status("Please enter a symbol to search") + return + + _update_status("Searching for references...") + _clear_results() + + # Perform the actual search + _search_in_project() + + # Update UI and show results + _display_results() + var result_count = _search_results.size() + if result_count > 0: + # Log successful search + print("Found %d references to '%s'" % [result_count, _current_symbol]) + _update_status("Found %d references to '%s'" % [result_count, _current_symbol]) + else: + _update_status("No references found for '%s'" % _current_symbol) + +func _clear_results() -> void: + _search_results.clear() + if results_tree: + results_tree.clear() + _clear_code_display() + _update_results_info("0 references found") + +func _search_in_project() -> void: + var fs : EditorFileSystem = EditorInterface.get_resource_filesystem() + if not fs: + return + + var root_dir = fs.get_filesystem() + if root_dir: + _search_in_directory(root_dir) + +func _search_in_directory(dir: EditorFileSystemDirectory) -> void: + # Check if this directory should be excluded + var dir_name = dir.get_name() + if _should_exclude_directory(dir_name): + return + + # Search in files + for i in range(dir.get_file_count()): + var file_path = dir.get_file_path(i) + var file_type = dir.get_file_type(i) + + # Only search in script files + if file_type == "GDScript" or file_path.ends_with(".gd"): + _search_in_file(file_path) + + # Search in subdirectories + for i in range(dir.get_subdir_count()): + _search_in_directory(dir.get_subdir(i)) + +func _should_exclude_directory(dir_name: String) -> bool: + """Check if a directory should be excluded from search""" + for excluded_dir in _excluded_directories: + if dir_name == excluded_dir or dir_name.begins_with(excluded_dir + "/"): + return true + return false + +func _search_in_file(file_path: String) -> void: + var file = FileAccess.open(file_path, FileAccess.READ) + if not file: + print("Error: Cannot access file %s" % file_path.get_file()) + return + + var line_number = 1 + while not file.eof_reached(): + var line = file.get_line() + var matches = _find_symbol_in_line(line, _current_symbol) + + for match_pos in matches: + var result = { + "file_path": file_path, + "line_number": line_number, + "line_content": line.strip_edges(), + "column": match_pos + } + _search_results.append(result) + + line_number += 1 + + file.close() + +func _find_symbol_in_line(line: String, symbol: String) -> Array[int]: + var matches: Array[int] = [] + + # Skip lines that are likely false positives + var trimmed_line = line.strip_edges() + + # Skip comments (but allow commented code for reference) + if trimmed_line.begins_with("#") and not trimmed_line.contains("func "): + return matches + + # Skip string literals (basic detection) - only for word boundary mode + if _match_mode == MatchMode.WORD_BOUNDARY and _is_in_string_literal(line, symbol): + return matches + + # Apply case sensitivity + var search_line = line if _case_sensitive else line.to_lower() + var search_symbol = symbol if _case_sensitive else symbol.to_lower() + + # Create regex pattern based on match mode + var regex = RegEx.new() + var pattern = _get_match_pattern(search_symbol) + if regex.compile(pattern) != OK: + return matches + + var results = regex.search_all(search_line) + for result in results: + var match_pos = result.get_start() + + # Additional context-aware filtering (only for word boundary mode) + if _match_mode == MatchMode.WORD_BOUNDARY: + if _is_valid_symbol_context(line, match_pos, symbol): + matches.append(match_pos) + else: + matches.append(match_pos) + + return matches + +func _get_match_pattern(symbol: String) -> String: + var escaped_symbol = _escape_regex_string(symbol) + + match _match_mode: + MatchMode.WORD_BOUNDARY: + return "\\b" + escaped_symbol + "\\b" + MatchMode.EXACT: + return "^" + escaped_symbol + "$" + MatchMode.STARTS_WITH: + return "^" + escaped_symbol + MatchMode.CONTAINS: + return escaped_symbol + MatchMode.ENDS_WITH: + return escaped_symbol + "$" + _: + return "\\b" + escaped_symbol + "\\b" + +# Check if symbol is inside a string literal +func _is_in_string_literal(line: String, symbol: String) -> bool: + var in_string = false + var in_triple_string = false + var quote_char = "" + + # Simple string detection (not perfect but catches most cases) + for i in range(line.length()): + var char = line[i] + + # Handle triple quotes + if i < line.length() - 2: + var triple = line.substr(i, 3) + if triple == '"""' or triple == "'''": + if not in_string: + in_triple_string = not in_triple_string + quote_char = triple[0] + continue + + # Handle single/double quotes + if char == '"' or char == "'": + if not in_triple_string: + if not in_string: + in_string = true + quote_char = char + elif char == quote_char: + in_string = false + quote_char = "" + + # If we find the symbol and we're currently in a string, it's probably a false positive + return (in_string or in_triple_string) and symbol in line + +# Check if the symbol appears in a valid context +func _is_valid_symbol_context(line: String, position: int, symbol: String) -> bool: + # Get context around the symbol + var start = max(0, position - 10) + var end = min(line.length(), position + symbol.length() + 10) + var context = line.substr(start, end - start) + + # Skip if it's part of a longer identifier (additional safety) + if position > 0: + var prev_char = line[position - 1] + if _is_identifier_char(prev_char): + return false + + if position + symbol.length() < line.length(): + var next_char = line[position + symbol.length()] + if _is_identifier_char(next_char): + return false + + return true + +func _is_identifier_char(char: String) -> bool: + return char.is_valid_identifier() or char == "_" + +# Escape special regex characters since Godot 4 doesn't have RegEx.escape() +func _escape_regex_string(text: String) -> String: + var escaped = text + # Order matters - escape backslash first + escaped = escaped.replace("\\", "\\\\") + escaped = escaped.replace(".", "\\.") + escaped = escaped.replace("^", "\\^") + escaped = escaped.replace("$", "\\$") + escaped = escaped.replace("*", "\\*") + escaped = escaped.replace("+", "\\+") + escaped = escaped.replace("?", "\\?") + escaped = escaped.replace("(", "\\(") + escaped = escaped.replace(")", "\\)") + escaped = escaped.replace("[", "\\[") + escaped = escaped.replace("]", "\\]") + escaped = escaped.replace("{", "\\{") + escaped = escaped.replace("}", "\\}") + escaped = escaped.replace("|", "\\|") + return escaped + +func _display_results() -> void: + # Ensure components are initialized + if not results_tree: + _ensure_components_initialized() + + if not results_tree: + print("Error: results_tree component not found") + _display_results_fallback() + return + + # Clear the tree and code display + results_tree.clear() + _clear_code_display() + + if _search_results.is_empty(): + _update_results_info("No references found") + return + + # Create root item (hidden) + var root = results_tree.create_item() + var file_groups = {} + + # Group results by file + for result in _search_results: + var file_path = result["file_path"] + if not file_groups.has(file_path): + file_groups[file_path] = [] + file_groups[file_path].append(result) + + # Update results info + var total_files = file_groups.size() + var total_refs = _search_results.size() + _update_results_info("%d references in %d files" % [total_refs, total_files]) + + # Create tree structure for navigation + for file_path in file_groups.keys(): + var file_item = root.create_child() + var file_name = file_path.get_file() + var reference_count = file_groups[file_path].size() + + # File header in navigation tree + file_item.set_text(0, "📁 %s (%d)" % [file_name, reference_count]) + file_item.set_text(1, "") + file_item.set_metadata(0, {"type": "file", "path": file_path}) + + # File item styling + file_item.set_selectable(0, false) + file_item.set_custom_color(0, Color(0.8, 0.9, 1.0)) + file_item.set_collapsed(false) + + # Add individual references + for result in file_groups[file_path]: + var ref_item = file_item.create_child() + var line_content = result.get("line_content", "") + var truncated_content = _truncate_line_content(line_content, 80) + # Apply symbol highlighting to the tree item text using simple text markers + var highlighted_content = _highlight_symbol_with_text_markers(truncated_content, _current_symbol) + ref_item.set_text(0, " → Line %d: %s" % [result["line_number"], highlighted_content]) + ref_item.set_text(1, str(result["line_number"])) + ref_item.set_metadata(0, result) + + # Reference item styling + ref_item.set_custom_color(0, Color(0.9, 0.9, 0.9)) + ref_item.set_custom_color(1, Color(0.8, 0.8, 0.6)) + + # Force tree update + results_tree.queue_redraw() + +func _clear_code_display() -> void: + """Clear the code display area""" + if code_header: + code_header.text = "Select a reference to view code" + if code_display: + code_display.text = "" + #Change to set if property placeholder_text not exist Godot 4.4.1 + code_display.set(&"placeholder_text", "Code content will appear here...") + +func _update_results_info(info_text: String) -> void: + """Update the results info label in the left panel""" + # Ensure components are initialized first + if not results_tree: + _ensure_components_initialized() + + # Method 1: Try using the direct NodePath first + var results_info_label = get_node_or_null("MainContainer/MainContent/LeftPanel/ResultsInfo") + if results_info_label and results_info_label is Label: + results_info_label.text = info_text + return + + # Method 2: Try using parent-child relationship + if results_tree and results_tree.get_parent(): + var left_panel = results_tree.get_parent() + + # Try to find ResultsInfo by searching through children + for i in range(left_panel.get_child_count()): + var child = left_panel.get_child(i) + if child.name == "ResultsInfo" and child is Label: + child.text = info_text + return + + # Log error only if all methods fail + print("Error: ResultsInfo label not found in UI structure") + +func _update_code_display(result: Dictionary) -> void: + """Update the right panel with code content for the selected reference""" + if not result.has("file_path") or not result.has("line_number"): + return + + var file_path = result["file_path"] + var line_number = result["line_number"] + var column = result.get("column", 0) + var file_name = file_path.get_file() + + # Update header + if code_header: + code_header.text = "%s:%d" % [file_name, line_number] + + # Load and display file content with color highlighting + if code_display: + var file_content = _load_file_content(file_path) + if not file_content.is_empty(): + # Show context around the line with BBCode highlighting + var context_content = _get_context_content_with_highlighting(file_content, line_number, column, 5) + code_display.text = context_content + + # Enable BBCode parsing for color highlighting + code_display.bbcode_enabled = true + +func _load_file_content(file_path: String) -> String: + """Load the content of a file""" + var file = FileAccess.open(file_path, FileAccess.READ) + if not file: + print("Error: Cannot load file content for %s" % file_path.get_file()) + return "" + var content = file.get_as_text() + file.close() + return content + +func _get_context_content_with_highlighting(file_content: String, target_line: int, target_column: int, context_lines: int) -> String: + """Get file content with context around the target line, with BBCode color highlighting""" + var lines = file_content.split("\n") + var start_line = max(0, target_line - context_lines - 1) + var end_line = min(lines.size() - 1, target_line + context_lines - 1) + + var context_lines_array = [] + for i in range(start_line, end_line + 1): + var line_content = lines[i] + var line_num = i + 1 + + # Add line number prefix + var prefix = "%3d: " % line_num + var formatted_line = prefix + line_content + + # Apply syntax highlighting to the target line + if line_num == target_line: + formatted_line = prefix + _highlight_symbol_with_bbcode(line_content, _current_symbol) + # Use different background color for target line + formatted_line = "[bgcolor=#2d2d30]" + formatted_line + "[/bgcolor]" + + context_lines_array.append(formatted_line) + + return "\n".join(context_lines_array) + +# Keep the old function for backward compatibility (if needed elsewhere) +func _get_context_content(file_content: String, target_line: int, context_lines: int) -> String: + """Get file content with context around the target line, with highlighting""" + var lines = file_content.split("\n") + var start_line = max(0, target_line - context_lines - 1) + var end_line = min(lines.size() - 1, target_line + context_lines - 1) + + var context_lines_array = [] + for i in range(start_line, end_line + 1): + var line_content = lines[i] + var line_num = i + 1 + + # Add line number prefix and highlight target line + var prefix = "%3d: " % line_num + if line_num == target_line: + # Highlight the target line and symbol + line_content = _highlight_symbol_in_line(line_content, _current_symbol) + prefix = "►%3d: " % line_num + else: + prefix = " %3d: " % line_num + + context_lines_array.append(prefix + line_content) + + return "\n".join(context_lines_array) + +func _truncate_line_content(line: String, max_length: int) -> String: + """Truncate line content if it's too long, preserving meaningful code""" + if line.length() <= max_length: + return line + + # Try to show the beginning and add ellipsis + var truncated = line.substr(0, max_length - 3) + return truncated + "..." + +func _highlight_symbol_with_text_markers(line: String, symbol: String) -> String: + """Highlight symbol in a line of code using simple text markers for Tree display""" + if symbol.is_empty(): + return line + + # Apply case sensitivity for the display + var search_line = line if _case_sensitive else line.to_lower() + var search_symbol = symbol if _case_sensitive else symbol.to_lower() + + # Create regex pattern based on match mode + var regex = RegEx.new() + var pattern = _get_match_pattern(search_symbol) + if regex.compile(pattern) != OK: + return line + + # Apply highlighting using simple text markers + var highlighted = line + var results = regex.search_all(search_line) + + # Apply highlights from right to left to preserve positions + results.reverse() + for result in results: + var start_pos = result.get_start() + var end_pos = result.get_end() + var match_text = line.substr(start_pos, end_pos - start_pos) + + # Create highlighted version with configurable text markers + var highlight = "%s%s%s" % [_highlight_prefix, match_text, _highlight_suffix] + + highlighted = highlighted.substr(0, start_pos) + highlight + highlighted.substr(end_pos) + + return highlighted + +func _highlight_symbol_with_bbcode(line: String, symbol: String) -> String: + """Highlight symbol in a line of code using BBCode formatting""" + if symbol.is_empty(): + return line + + # Apply case sensitivity for the display + var search_line = line if _case_sensitive else line.to_lower() + var search_symbol = symbol if _case_sensitive else symbol.to_lower() + + # Create regex pattern based on match mode + var regex = RegEx.new() + var pattern = _get_match_pattern(search_symbol) + if regex.compile(pattern) != OK: + return line + + # Apply highlighting using BBCode + var highlighted = line + var results = regex.search_all(search_line) + + # Apply highlights from right to left to preserve positions + results.reverse() + for result in results: + var start_pos = result.get_start() + var end_pos = result.get_end() + var match_text = line.substr(start_pos, end_pos - start_pos) + + # Create highlighted version with yellow background and bold text + var highlight = "[bgcolor=yellow][color=black][b]%s[/b][/color][/bgcolor]" % match_text + + highlighted = highlighted.substr(0, start_pos) + highlight + highlighted.substr(end_pos) + + return highlighted + +func _highlight_symbol_in_line(line: String, symbol: String) -> String: + """Highlight symbol in a line of code (legacy version with symbols)""" + if symbol.is_empty(): + return line + + # Use word boundary matching for better accuracy + var regex = RegEx.new() + var pattern = "\\b" + _escape_regex_string(symbol) + "\\b" + if regex.compile(pattern) != OK: + return "" + + var highlighted = regex.sub(line, "%s%s%s" % [_highlight_prefix, symbol, _highlight_suffix], true) + return highlighted + +func _on_item_activated() -> void: + var selected = results_tree.get_selected() + if not selected: + return + + var metadata = selected.get_metadata(0) + if not metadata or not metadata.has("file_path"): + return + + # Navigate to the reference + if metadata.has("line_number"): + _navigate_to_reference(metadata["file_path"], metadata["line_number"], metadata.get("column", 0)) + +func _on_item_selected() -> void: + var selected = results_tree.get_selected() + if not selected: + return + + var metadata = selected.get_metadata(0) + if metadata: + if metadata.has("type") and metadata["type"] == "file": + # File item selected - show file info, clear code display + var file_path = metadata["path"] + var relative_path = file_path.replace("res://", "") + _update_status("📁 %s" % relative_path) + _clear_code_display() + elif metadata.has("file_path") and metadata.has("line_number"): + # Reference item selected - show code content and update status + _update_code_display(metadata) + var file_name = metadata["file_path"].get_file() + var line_num = metadata["line_number"] + var relative_path = metadata["file_path"].replace("res://", "") + _update_status("📍 Line %d in %s (%s)" % [line_num, file_name, relative_path]) + +func _navigate_to_reference(file_path: String, line_number: int, column: int) -> void: + # Open the file in the script editor + var script = ResourceLoader.load(file_path) + if script and script is Script: + EditorInterface.edit_script(script) + + # Navigate to specific line + var script_editor = EditorInterface.get_script_editor() + if script_editor: + script_editor.goto_line(line_number - 1) + + # Focus on the specific column if possible + var current_editor = script_editor.get_current_editor() + if current_editor: + var code_edit : CodeEdit = current_editor.get_base_editor() + if code_edit: + code_edit.set_caret_line(line_number - 1) + code_edit.set_caret_column(column) + code_edit.grab_focus() + else: + print("Error: Cannot navigate to %s:%d" % [file_path.get_file(), line_number]) + +func _display_results_fallback() -> void: + """Fallback method to display results when Tree component is not available""" + var total_refs = _search_results.size() + if total_refs > 0: + var file_groups = {} + for result in _search_results: + var file_path = result["file_path"] + if not file_groups.has(file_path): + file_groups[file_path] = [] + file_groups[file_path].append(result) + + var total_files = file_groups.size() + _update_results_info("%d references in %d files" % [total_refs, total_files]) + + # Try to create a simple Tree component dynamically + _create_fallback_tree() + else: + _update_results_info("No references found") + +func _create_fallback_tree() -> void: + """Create a Tree component dynamically when the scene component is missing""" + # Find the left panel where the tree should be + var left_panel = get_node_or_null("MainContainer/MainContent/LeftPanel") + if not left_panel: + print("Error: Cannot find LeftPanel for tree creation") + return + + # Check if there's already a Tree somewhere + var existing_tree = _recursive_find_by_type(left_panel, Tree) + if existing_tree: + results_tree = existing_tree + _display_results() + return + + # Create a new Tree component + var new_tree = Tree.new() + new_tree.name = "FallbackResultsTree" + new_tree.columns = 2 + new_tree.column_titles_visible = true + new_tree.hide_root = true + new_tree.select_mode = Tree.SELECT_SINGLE + new_tree.set_column_title(0, "File / Reference") + new_tree.set_column_title(1, "Line") + new_tree.set_column_expand_ratio(0, 3.0) + new_tree.set_column_expand_ratio(1, 1.0) + + # Connect signals + new_tree.item_activated.connect(_on_item_activated) + new_tree.item_selected.connect(_on_item_selected) + + # Add to the left panel + var insert_position = 1 + if left_panel.get_child_count() > insert_position: + left_panel.add_child(new_tree) + left_panel.move_child(new_tree, insert_position) + else: + left_panel.add_child(new_tree) + + # Set size flags to expand + new_tree.size_flags_vertical = Control.SIZE_EXPAND_FILL + + # Update our reference and try again + results_tree = new_tree + _display_results() + +func _update_status(message: String) -> void: + if status_label: + status_label.text = message + +# Public method to show this panel in the bottom dock +func show_and_focus() -> void: + show() + if search_bar: + search_bar.grab_focus() diff --git a/addons/_Godot-IDE_/plugins/symbol_navigator/gui/find_references_panel.gd.uid b/addons/_Godot-IDE_/plugins/symbol_navigator/gui/find_references_panel.gd.uid new file mode 100644 index 0000000..b8e0a10 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/symbol_navigator/gui/find_references_panel.gd.uid @@ -0,0 +1 @@ +uid://ccdxcm5e4uuaw diff --git a/addons/_Godot-IDE_/plugins/symbol_navigator/gui/find_references_panel.tscn b/addons/_Godot-IDE_/plugins/symbol_navigator/gui/find_references_panel.tscn new file mode 100644 index 0000000..a8925a1 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/symbol_navigator/gui/find_references_panel.tscn @@ -0,0 +1,165 @@ +[gd_scene load_steps=2 format=3 uid="uid://hsyqdgwk3rr0"] + +[ext_resource type="Script" uid="uid://ccdxcm5e4uuaw" path="res://addons/_Godot-IDE_/plugins/symbol_navigator/gui/find_references_panel.gd" id="1_panel_script"] + +[node name="FindReferencesPanel" type="Control" node_paths=PackedStringArray("search_bar", "results_tree", "status_label", "search_button", "clear_button", "code_header", "code_display", "case_sensitive_check", "match_mode_option", "exclude_dirs_button", "highlight_style_option")] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_panel_script") +search_bar = NodePath("MainContainer/SearchSection/SearchBar") +results_tree = NodePath("MainContainer/MainContent/LeftPanel/ResultsTree") +status_label = NodePath("MainContainer/StatusSection/StatusLabel") +search_button = NodePath("MainContainer/SearchSection/SearchButton") +clear_button = NodePath("MainContainer/StatusSection/ClearButton") +code_header = NodePath("MainContainer/MainContent/RightPanel/CodeHeader") +code_display = NodePath("MainContainer/MainContent/RightPanel/CodeDisplay") +case_sensitive_check = NodePath("MainContainer/SearchSection/CaseSensitiveCheck") +match_mode_option = NodePath("MainContainer/SearchSection/MatchModeOption") +exclude_dirs_button = NodePath("MainContainer/SearchSection/ExcludeDirsButton") +highlight_style_option = NodePath("MainContainer/SearchSection/HighlightStyleOption") + +[node name="MainContainer" type="VBoxContainer" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 4.0 +offset_top = 4.0 +offset_right = -4.0 +offset_bottom = -4.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="SearchSection" type="HBoxContainer" parent="MainContainer"] +custom_minimum_size = Vector2(0, 36) +layout_mode = 2 + +[node name="SearchLabel" type="Label" parent="MainContainer/SearchSection"] +layout_mode = 2 +text = "Search:" +vertical_alignment = 1 + +[node name="SearchBar" type="LineEdit" parent="MainContainer/SearchSection"] +layout_mode = 2 +size_flags_horizontal = 3 +placeholder_text = "Enter symbol to find references..." +select_all_on_focus = true + +[node name="SearchButton" type="Button" parent="MainContainer/SearchSection"] +custom_minimum_size = Vector2(80, 0) +layout_mode = 2 +text = "Find" + +[node name="ExcludeDirsButton" type="Button" parent="MainContainer/SearchSection"] +custom_minimum_size = Vector2(80, 0) +layout_mode = 2 +text = "Exclude Dirs" + +[node name="CaseSensitiveCheck" type="CheckBox" parent="MainContainer/SearchSection"] +layout_mode = 2 +button_pressed = true +text = "Case Sensitive" + +[node name="MatchModeOption" type="OptionButton" parent="MainContainer/SearchSection"] +custom_minimum_size = Vector2(120, 0) +layout_mode = 2 +selected = 0 +item_count = 5 +popup/item_0/text = "Word Boundary" +popup/item_0/id = 0 +popup/item_1/text = "Exact Match" +popup/item_1/id = 1 +popup/item_2/text = "Starts With" +popup/item_2/id = 2 +popup/item_3/text = "Contains" +popup/item_3/id = 3 +popup/item_4/text = "Ends With" +popup/item_4/id = 4 + +[node name="HighlightLabel" type="Label" parent="MainContainer/SearchSection"] +layout_mode = 2 +text = "Highlight:" +vertical_alignment = 1 + +[node name="HighlightStyleOption" type="OptionButton" parent="MainContainer/SearchSection"] +custom_minimum_size = Vector2(140, 0) +layout_mode = 2 +selected = 3 +item_count = 6 +popup/item_0/text = "Dots (·symbol·)" +popup/item_0/id = 0 +popup/item_1/text = "Brackets ((symbol))" +popup/item_1/id = 1 +popup/item_2/text = "Arrows (→symbol←)" +popup/item_2/id = 2 +popup/item_3/text = "Quotes (「symbol」)" +popup/item_3/id = 3 +popup/item_4/text = "Squares (▪symbol▪)" +popup/item_4/id = 4 +popup/item_5/text = "Circles (○symbol○)" +popup/item_5/id = 5 + +[node name="Separator1" type="HSeparator" parent="MainContainer"] +custom_minimum_size = Vector2(0, 8) +layout_mode = 2 + +[node name="MainContent" type="HSplitContainer" parent="MainContainer"] +layout_mode = 2 +size_flags_vertical = 3 +split_offset = 300 + +[node name="LeftPanel" type="VBoxContainer" parent="MainContainer/MainContent"] +custom_minimum_size = Vector2(250, 0) +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="ResultsInfo" type="Label" parent="MainContainer/MainContent/LeftPanel"] +layout_mode = 2 +text = "Enter a symbol to search" + +[node name="ResultsTree" type="Tree" parent="MainContainer/MainContent/LeftPanel"] +layout_mode = 2 +size_flags_vertical = 3 +columns = 2 +column_titles_visible = true +hide_root = true + +[node name="RightPanel" type="VBoxContainer" parent="MainContainer/MainContent"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="CodeHeader" type="Label" parent="MainContainer/MainContent/RightPanel"] +layout_mode = 2 +text = "Select a reference to view code" + +[node name="CodeSeparator" type="HSeparator" parent="MainContainer/MainContent/RightPanel"] +layout_mode = 2 + +[node name="CodeDisplay" type="RichTextLabel" parent="MainContainer/MainContent/RightPanel"] +layout_mode = 2 +size_flags_vertical = 3 +focus_mode = 2 +selection_enabled = true + +[node name="Separator2" type="HSeparator" parent="MainContainer"] +custom_minimum_size = Vector2(0, 4) +layout_mode = 2 + +[node name="StatusSection" type="HBoxContainer" parent="MainContainer"] +custom_minimum_size = Vector2(0, 24) +layout_mode = 2 + +[node name="StatusLabel" type="Label" parent="MainContainer/StatusSection"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Ready" +vertical_alignment = 1 + +[node name="ClearButton" type="Button" parent="MainContainer/StatusSection"] +custom_minimum_size = Vector2(60, 0) +layout_mode = 2 +text = "Clear" diff --git a/addons/_Godot-IDE_/plugins/symbol_navigator/gui/rename_dialog.gd b/addons/_Godot-IDE_/plugins/symbol_navigator/gui/rename_dialog.gd new file mode 100644 index 0000000..fc8d687 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/symbol_navigator/gui/rename_dialog.gd @@ -0,0 +1,1027 @@ +@tool +extends Window + +# ============================================================================= +# Symbol Navigator - Rename Dialog +# Author: kyros +# Rename symbols (variables, functions, classes) across the entire project +# +# Technical Features: +# - Direct source replacement: Instantly update content in open editors +# - Smart symbol matching: Precise word boundary matching with regex +# - State preservation: Maintain user's cursor position and scroll state +# - Quality assurance: Automatic file content verification after batch changes +# +# User Workflow: +# 1. Select symbol → Press F2 (auto-preview) +# 2. Enter new name → Press Enter or click Rename +# 3. Files modified and editor updates in real-time ✨ +# ============================================================================= + +# UI components +@export var new_name_edit : LineEdit = null +@export var scope_option : OptionButton = null +@export var preview_tree : Tree = null +@export var rename_button : Button = null +@export var cancel_button : Button = null +@export var select_all_button : Button = null +@export var unselect_all_button : Button = null +@export var selection_status : Label = null + +# Data +var _current_symbol : String = "" +var _rename_results : Array = [] +var _selected_items : Array = [] # Tracks which items are selected for rename +var _file_groups : Dictionary = {} # Maps file_path to array of result indices +var _file_selections : Dictionary = {} # Maps file_path to selection state +var _scope_project_wide : bool = true + + +func _ready() -> void: + # Find UI components + _find_ui_components() + + # Validate UI components were found + _validate_ui_components() + + # Connect signals + _connect_signals() + + # Setup tree + _setup_preview_tree() + + # Setup dialog display + _setup_dialog_display() + +func _find_ui_components() -> void: + """Find and assign UI components""" + new_name_edit = find_child("NewNameEdit") as LineEdit + scope_option = find_child("ScopeOption") as OptionButton + preview_tree = find_child("PreviewTree") as Tree + rename_button = find_child("RenameButton") as Button + cancel_button = find_child("CancelButton") as Button + select_all_button = find_child("SelectAllButton") as Button + unselect_all_button = find_child("UnselectAllButton") as Button + selection_status = find_child("SelectionStatus") as Label + +func _validate_ui_components() -> void: + """Validate that all UI components were found and report missing ones""" + var missing_components = [] + + if not new_name_edit: + missing_components.append("NewNameEdit") + if not scope_option: + missing_components.append("ScopeOption") + if not preview_tree: + missing_components.append("PreviewTree") + if not rename_button: + missing_components.append("RenameButton") + if not cancel_button: + missing_components.append("CancelButton") + if not select_all_button: + missing_components.append("SelectAllButton") + if not unselect_all_button: + missing_components.append("UnselectAllButton") + if not selection_status: + missing_components.append("SelectionStatus") + + if missing_components.size() > 0: + push_warning("[Rename Dialog] Missing UI components: " + str(missing_components)) + +func _connect_signals() -> void: + """Connect button signals""" + var connected_count = 0 + + if rename_button: + rename_button.pressed.connect(_on_rename_pressed) + connected_count += 1 + if cancel_button: + cancel_button.pressed.connect(_on_cancel_pressed) + connected_count += 1 + if scope_option: + scope_option.item_selected.connect(_on_scope_changed) + connected_count += 1 + if new_name_edit: + new_name_edit.text_changed.connect(_on_text_changed) + connected_count += 1 + if select_all_button: + select_all_button.pressed.connect(_on_select_all_pressed) + connected_count += 1 + if unselect_all_button: + unselect_all_button.pressed.connect(_on_unselect_all_pressed) + connected_count += 1 + if preview_tree: + preview_tree.item_edited.connect(_on_tree_item_edited) + connected_count += 1 + + if connected_count == 0: + push_warning("[Rename Dialog] No signals connected - UI components may not be properly initialized") + + + +func _setup_preview_tree() -> void: + """Setup the preview tree columns""" + if not preview_tree: + return + + preview_tree.columns = 3 + preview_tree.set_column_title(0, "✓") + preview_tree.set_column_title(1, "File / Location") + preview_tree.set_column_title(2, "Line") + preview_tree.set_column_expand_ratio(0, 0.3) # Checkbox column (narrow) + preview_tree.set_column_expand_ratio(1, 3.0) # File/Location column (wide) + preview_tree.set_column_expand_ratio(2, 0.7) # Line number column (narrow) + preview_tree.hide_root = true + +func set_symbol(symbol: String) -> void: + """Set the symbol to be renamed""" + _current_symbol = symbol + + # Check if UI components are ready + if not _are_ui_components_ready(): + # Defer the call until the next frame when components should be ready + call_deferred("_deferred_set_symbol", symbol) + return + + _apply_symbol_to_ui(symbol) + +func _are_ui_components_ready() -> bool: + """Check if all required UI components are available""" + return (new_name_edit != null and + scope_option != null and + preview_tree != null and + rename_button != null and + cancel_button != null) + +func _deferred_set_symbol(symbol: String) -> void: + """Deferred version of set_symbol, called when UI is ready""" + if not _are_ui_components_ready(): + print("[Rename Dialog] ERROR: UI components still not ready after deferral") + print("[Rename Dialog] new_name_edit: ", new_name_edit) + print("[Rename Dialog] scope_option: ", scope_option) + print("[Rename Dialog] preview_tree: ", preview_tree) + print("[Rename Dialog] rename_button: ", rename_button) + print("[Rename Dialog] cancel_button: ", cancel_button) + return + + _apply_symbol_to_ui(symbol) + +func _apply_symbol_to_ui(symbol: String) -> void: + """Apply the symbol to the UI components""" + # Update UI + if new_name_edit: + new_name_edit.text = symbol + new_name_edit.select_all() + new_name_edit.grab_focus() + + title = "Rename Symbol: " + symbol + + # Automatically trigger preview when symbol is set + call_deferred("_auto_preview") + +func _auto_preview() -> void: + """Automatically trigger preview without changing the current name""" + # Verify UI components are still available + if not _are_ui_components_ready(): + print("[Rename Symbol] ERROR: UI components not ready during auto-preview") + return + + # Clear previous results + _rename_results.clear() + + # Search for all occurrences + _search_symbol_occurrences() + + # Display results in tree + _display_preview_results() + + # Update status + if _rename_results.size() == 0: + print("[Rename Symbol] No occurrences found for symbol: '%s'" % _current_symbol) + + +func _on_rename_pressed() -> void: + """Perform the actual rename operation""" + # Comprehensive pre-flight checks + if _rename_results.is_empty(): + _show_error("No preview results. Please click Preview first.") + return + + if not new_name_edit or not is_instance_valid(new_name_edit): + _show_error("Name input field not available") + return + + var new_name = new_name_edit.text.strip_edges() + if new_name.is_empty(): + _show_error("New name cannot be empty") + return + + if new_name == _current_symbol: + _show_error("New name is the same as current symbol") + return + + if _selected_items.is_empty(): + _show_error("No items selected for rename") + return + + # Disable the rename button to prevent double-clicks + if rename_button: + rename_button.disabled = true + + # Perform batch rename with error handling + var success = _perform_batch_rename(new_name) + if not success: + _show_error("Rename operation failed") + if rename_button: + rename_button.disabled = false + return + + if success: + # Force Godot to refresh the file system + _refresh_file_system() + + # Verify the modifications actually took effect + var verification_success = _verify_modifications(new_name) + + if verification_success: + # Success - no log needed for normal operation + var message = "Successfully renamed '%s' to '%s' in %d locations" % [_current_symbol, new_name, _selected_items.size()] + _show_success(message) + else: + # Partial failure - files may be modified but verification failed + var warning = "Rename completed but verification failed. Please check files manually." + _show_error(warning) + + hide() + else: + # Complete operation failure + _show_error("Rename operation failed. Some files may have been modified.") + + # Re-enable the rename button + if rename_button: + rename_button.disabled = false + +func _on_cancel_pressed() -> void: + """Cancel the rename operation""" + hide() + +func _on_scope_changed(index: int) -> void: + """Handle scope selection change""" + _scope_project_wide = (index == 1) # Assuming index 1 is "Entire Project" + + # Re-trigger preview when scope changes + if not _current_symbol.is_empty(): + call_deferred("_auto_preview") + +func _on_text_changed(new_text: String) -> void: + """Handle text changes in the name input""" + # Check for special characters and validate name + var trimmed_text = new_text.strip_edges() + var is_valid = _validate_symbol_name(trimmed_text) + + # Enable/disable rename button based on text validity + if rename_button: + rename_button.disabled = not is_valid + + # Special Character Compatibility Check + if not trimmed_text.is_empty() and not _is_name_compatible(trimmed_text): + pass # Silently validate compatibility + +func _input(event: InputEvent) -> void: + """Handle keyboard shortcuts""" + if not visible: + return + + if event is InputEventKey and event.pressed: + match event.keycode: + KEY_ENTER: + # Enter key triggers rename if valid + if rename_button and not rename_button.disabled: + _on_rename_pressed() + get_viewport().set_input_as_handled() + KEY_ESCAPE: + # Escape key cancels + _on_cancel_pressed() + get_viewport().set_input_as_handled() + KEY_A: + # Ctrl+A for select all + if event.ctrl_pressed: + _on_select_all_pressed() + get_viewport().set_input_as_handled() + +func _on_select_all_pressed() -> void: + """Select all items for renaming""" + if not preview_tree: + return + + _selected_items.clear() + + # Add all valid indices to selected items + for i in range(_rename_results.size()): + _selected_items.append(i) + + # Update file selections + for file_path in _file_groups.keys(): + _file_selections[file_path] = true + + # Update checkboxes in tree + _update_tree_checkboxes(true) + _update_selection_status() + +func _on_unselect_all_pressed() -> void: + """Unselect all items""" + if not preview_tree: + return + + _selected_items.clear() + + # Update file selections + for file_path in _file_groups.keys(): + _file_selections[file_path] = false + + # Update checkboxes in tree + _update_tree_checkboxes(false) + _update_selection_status() + +func _on_tree_item_edited() -> void: + """Handle checkbox clicks in tree (both file-level and item-level)""" + var edited_item = preview_tree.get_edited() + if not edited_item: + return + + var metadata = edited_item.get_metadata(0) + if metadata == null: + return + + var is_checked = edited_item.is_checked(0) + + if metadata.has("type"): + if metadata["type"] == "file": + # Handle file-level checkbox + _on_file_checkbox_changed(metadata["path"], is_checked) + elif metadata["type"] == "item": + # Handle item-level checkbox + _on_item_checkbox_changed(metadata["index"], is_checked) + + _update_selection_status() + +func _on_file_checkbox_changed(file_path: String, is_checked: bool) -> void: + """Handle file-level checkbox changes""" + if not _file_groups.has(file_path): + return + + # Update file selection state + _file_selections[file_path] = is_checked + + # Update all items in this file + for item_data in _file_groups[file_path]: + var index = item_data["index"] + + if is_checked: + # Add to selected items if not already there + if index not in _selected_items: + _selected_items.append(index) + else: + # Remove from selected items + if index in _selected_items: + _selected_items.erase(index) + + # Update the visual state of child checkboxes + _update_child_checkboxes(file_path, is_checked) + +func _on_item_checkbox_changed(index: int, is_checked: bool) -> void: + """Handle individual item checkbox changes""" + if is_checked and index not in _selected_items: + _selected_items.append(index) + elif not is_checked and index in _selected_items: + _selected_items.erase(index) + + # Update the parent file's checkbox state based on children + var file_path = _rename_results[index]["file_path"] + _update_file_checkbox_state(file_path) + +func _update_tree_checkboxes(checked: bool) -> void: + """Update all checkboxes in the tree (both files and items)""" + if not preview_tree: + return + + var root = preview_tree.get_root() + if not root: + return + + _iterate_tree_items(root, func(item): + var metadata = item.get_metadata(0) + if metadata != null and metadata.has("type"): + # Update both file and item checkboxes + item.set_checked(0, checked) + ) + +func _iterate_tree_items(item: TreeItem, callback: Callable) -> void: + """Recursively iterate through tree items""" + if item: + callback.call(item) + var child = item.get_first_child() + while child: + _iterate_tree_items(child, callback) + child = child.get_next() + +func _update_child_checkboxes(file_path: String, checked: bool) -> void: + """Update all child checkboxes for a file""" + if not preview_tree: + return + + var root = preview_tree.get_root() + if not root: + return + + # Find the file item and update its children + _iterate_tree_items(root, func(item): + var metadata = item.get_metadata(0) + if metadata != null and metadata.has("type"): + if metadata["type"] == "file" and metadata["path"] == file_path: + # Found the file item, update its children + var child = item.get_first_child() + while child: + child.set_checked(0, checked) + child = child.get_next() + ) + +func _update_file_checkbox_state(file_path: String) -> void: + """Update file checkbox based on children selection state (tri-state logic)""" + if not _file_groups.has(file_path): + return + + # Count selected items in this file + var selected_count = 0 + var total_count = _file_groups[file_path].size() + + for item_data in _file_groups[file_path]: + var index = item_data["index"] + if index in _selected_items: + selected_count += 1 + + # Update file checkbox state and visual appearance + var root = preview_tree.get_root() + if root: + _iterate_tree_items(root, func(item): + var metadata = item.get_metadata(0) + if metadata != null and metadata.has("type"): + if metadata["type"] == "file" and metadata["path"] == file_path: + if selected_count == 0: + # None selected + item.set_checked(0, false) + _file_selections[file_path] = false + elif selected_count == total_count: + # All selected + item.set_checked(0, true) + _file_selections[file_path] = true + else: + # Partial selection - show as checked but different visual state + item.set_checked(0, true) + _file_selections[file_path] = true + # In Godot, we can't easily show tri-state, but we track it logically + ) + +func _update_selection_status() -> void: + """Update the selection status label""" + if not selection_status: + return + + var total_items = _rename_results.size() + var selected_items = _selected_items.size() + var total_files = _file_groups.size() + var selected_files = 0 + + # Count how many files have at least one selected item + for file_path in _file_groups.keys(): + var has_selected = false + for item_data in _file_groups[file_path]: + if item_data["index"] in _selected_items: + has_selected = true + break + if has_selected: + selected_files += 1 + + selection_status.text = "%d files, %d of %d items selected" % [selected_files, selected_items, total_items] + +func _search_symbol_occurrences() -> void: + """Search for all occurrences of the symbol""" + var fs : EditorFileSystem = EditorInterface.get_resource_filesystem() + if not fs: + return + + var root_dir = fs.get_filesystem() + if not root_dir: + return + + + if _scope_project_wide: + _search_in_directory(root_dir) + else: + # Current file only + var current_script = _get_current_script_path() + if not current_script.is_empty(): + _search_in_file(current_script) + +func _search_in_directory(dir: EditorFileSystemDirectory) -> void: + """Recursively search in directory""" + # Search files in current directory + for i in range(dir.get_file_count()): + var file_path = dir.get_file_path(i) + if _is_script_file(file_path): + _search_in_file(file_path) + + # Search subdirectories + for i in range(dir.get_subdir_count()): + var subdir = dir.get_subdir(i) + _search_in_directory(subdir) + +func _search_in_file(file_path: String) -> void: + """Search for symbol occurrences in a single file""" + var file = FileAccess.open(file_path, FileAccess.READ) + if not file: + push_warning("[Rename Dialog] Cannot open file: %s" % file_path) + return + + # Safety check for file size to prevent memory issues + var file_size = file.get_length() + if file_size > 10 * 1024 * 1024: # 10MB limit + push_warning("[Rename Dialog] Skipping large file: %s (%d bytes)" % [file_path, file_size]) + file.close() + return + + var line_number = 1 + var max_lines = 10000 # Prevent infinite loops + while not file.eof_reached() and line_number <= max_lines: + var line = file.get_line() + var occurrences = _find_symbol_in_line(line, _current_symbol) + + for occurrence in occurrences: + var result = { + "file_path": file_path, + "line_number": line_number, + "line_content": line.strip_edges(), + "column": occurrence["column"], + "match_start": occurrence["start"], + "match_end": occurrence["end"] + } + _rename_results.append(result) + + line_number += 1 + + file.close() + + if line_number > max_lines: + push_warning("[Rename Dialog] File too long, search truncated: %s" % file_path) + +func _find_symbol_in_line(line: String, symbol: String) -> Array: + """Find all occurrences of symbol in a line, ensuring word boundaries""" + var occurrences = [] + + var regex = RegEx.new() + var pattern = "\\b" + _escape_regex_string(symbol) + "\\b" + if regex.compile(pattern) != OK: + return occurrences + + var search_from = 0 + while true: + var result = regex.search(line, search_from) + if not result: + break + + occurrences.append({ + "column": result.get_start(), + "start": result.get_start(), + "end": result.get_end(), + "match": result.get_string() + }) + + search_from = result.get_end() + + return occurrences + +func _escape_regex_string(text: String) -> String: + """Escape special regex characters""" + var special_chars = ["\\", ".", "^", "$", "*", "+", "?", "(", ")", "[", "]", "{", "}", "|"] + var escaped = text + for char in special_chars: + escaped = escaped.replace(char, "\\" + char) + return escaped + +func _display_preview_results() -> void: + """Display the preview results in the tree""" + if not preview_tree: + return + + preview_tree.clear() + _selected_items.clear() + _file_groups.clear() + _file_selections.clear() + + if _rename_results.is_empty(): + var root = preview_tree.create_item() + var no_results = root.create_child() + no_results.set_text(1, "No occurrences found") # Column 1 (File/Location) + no_results.set_text(2, "") # Column 2 (Line) + _update_selection_status() + return + + var root = preview_tree.create_item() + + # Group by file and store in class variables + for i in range(_rename_results.size()): + var result = _rename_results[i] + var file_path = result["file_path"] + if not _file_groups.has(file_path): + _file_groups[file_path] = [] + _file_groups[file_path].append({"index": i, "result": result}) + + # Initialize file selections (all selected by default) + for file_path in _file_groups.keys(): + _file_selections[file_path] = true + + # Display grouped results + for file_path in _file_groups.keys(): + var file_item = root.create_child() + var file_name = file_path.get_file() + + # Column 0: File-level checkbox (selected by default) + file_item.set_cell_mode(0, TreeItem.CELL_MODE_CHECK) + file_item.set_checked(0, true) # Default to selected + file_item.set_editable(0, true) + + # Column 1: File name and count + file_item.set_text(1, "%s (%d occurrences)" % [file_name, _file_groups[file_path].size()]) + + # Column 2: Empty for file headers + file_item.set_text(2, "") + file_item.set_custom_color(1, Color(0.8, 0.9, 1.0)) + + # Store file path as metadata for file-level checkbox handling + file_item.set_metadata(0, {"type": "file", "path": file_path}) + + # Add occurrences with checkboxes + for item_data in _file_groups[file_path]: + var result = item_data["result"] + var index = item_data["index"] + + var ref_item = file_item.create_child() + + # Column 0: Checkbox (selected by default) + ref_item.set_cell_mode(0, TreeItem.CELL_MODE_CHECK) + ref_item.set_checked(0, true) # Default to selected + ref_item.set_editable(0, true) + + # Column 1: File/Location info + var line_content = result["line_content"] + if line_content.length() > 60: + line_content = line_content.substr(0, 57) + "..." + ref_item.set_text(1, " → Line %d: %s" % [result["line_number"], line_content]) + + # Column 2: Line number + ref_item.set_text(2, str(result["line_number"])) + + # Store the index as metadata for tracking + ref_item.set_metadata(0, {"type": "item", "index": index}) + + # Add to selected items (all selected by default) + _selected_items.append(index) + + _update_selection_status() + +func _perform_batch_rename(new_name: String) -> bool: + """Execute batch rename operation - core functionality""" + var files_to_modify = {} + + # Group modifications by file (only selected items) + for i in _selected_items: + if i >= 0 and i < _rename_results.size(): + var result = _rename_results[i] + var file_path = result["file_path"] + if not files_to_modify.has(file_path): + files_to_modify[file_path] = [] + files_to_modify[file_path].append(result) + + var success_count = 0 + var total_files = files_to_modify.size() + + # Process each file + for file_path in files_to_modify.keys(): + var modifications = files_to_modify[file_path] + + if _modify_file(file_path, modifications, new_name): + success_count += 1 + else: + # Only log errors + print("Error: Failed to modify %s" % file_path.get_file()) + + # Only log if there were failures + if success_count != total_files: + print("Warning: Only %d/%d files modified successfully" % [success_count, total_files]) + + return success_count == total_files + +func _modify_file(file_path: String, modifications: Array, new_name: String) -> bool: + """Modify all symbol occurrences in a single file""" + # Read file content + var file = FileAccess.open(file_path, FileAccess.READ) + if not file: + return false + + var lines = [] + while not file.eof_reached(): + lines.append(file.get_line()) + file.close() + + # Sort by line and column (reverse order for safe replacement) + modifications.sort_custom(func(a, b): return a["line_number"] > b["line_number"] or (a["line_number"] == b["line_number"] and a["column"] > b["column"])) + + # Apply all modifications + for mod in modifications: + var line_idx = mod["line_number"] - 1 + if line_idx >= 0 and line_idx < lines.size(): + var old_line = lines[line_idx] + var start_pos = mod["match_start"] + var end_pos = mod["match_end"] + + # Execute symbol replacement + var new_line = old_line.substr(0, start_pos) + new_name + old_line.substr(end_pos) + lines[line_idx] = new_line + + # Write back to file + file = FileAccess.open(file_path, FileAccess.WRITE) + if not file: + return false + + for line in lines: + file.store_line(line) + file.close() + + return true + +func _get_current_script_path() -> String: + """Get the path of the currently open script""" + var script_editor : ScriptEditor = EditorInterface.get_script_editor() + if not script_editor: + return "" + + # Method 1: Try to get current script directly + var current_script = script_editor.get_current_script() + if current_script and current_script.resource_path != "": + return current_script.resource_path + + # Method 2: Try through current editor + var current_editor = script_editor.get_current_editor() + if current_editor: + if current_editor is ScriptEditorBase: + var base_editor = current_editor.get_base_editor() + if base_editor and base_editor is CodeEdit: + # Try to get script from the editor + var script = current_editor.get_edited_resource() + if script and script.resource_path != "": + return script.resource_path + + # Method 3: Try through editor selection + var editor_selection = EditorInterface.get_selection() + if editor_selection: + var selected = editor_selection.get_selected_nodes() + if selected.size() > 0: + var node = selected[0] + var script = node.get_script() + if script and script.resource_path != "": + return script.resource_path + + return "" + +func _is_script_file(file_path: String) -> bool: + """Check if file is a script file we should search in""" + var extension = file_path.get_extension().to_lower() + return extension in ["gd", "cs", "cpp", "h", "hpp", "c", "py", "js", "ts"] + +func _show_error(message: String) -> void: + """Show error message""" + print("[Rename Symbol] Error: %s" % message) + # Could also show a popup or status message + +func _validate_symbol_name(name: String) -> bool: + """Validate that the symbol name is valid for renaming""" + if name.is_empty(): + return false + + if name == _current_symbol: + return false + + # Check for basic identifier rules (letters, numbers, underscore) + var regex = RegEx.new() + if regex.compile("^[a-zA-Z_][a-zA-Z0-9_]*$") != OK: + return true # Fallback to allowing anything if regex fails + + return regex.search(name) != null + +func _is_name_compatible(name: String) -> bool: + """Check if the name contains only standard ASCII characters""" + for i in range(name.length()): + var char_code = name.unicode_at(i) + # Allow only standard ASCII printable characters (32-126) + # Plus common programming characters + if char_code < 32 or char_code > 126: + return false + return true + +func _show_success(message: String) -> void: + """Show success message""" + print("[Rename Symbol] ✅ SUCCESS: %s" % message) + +func _refresh_file_system() -> void: + """Direct source replacement for immediate synchronization - core functionality""" + # Collect all modified file paths (only selected items) + var modified_files : PackedStringArray = PackedStringArray() + for i in _selected_items: + if i >= 0 and i < _rename_results.size(): + var result = _rename_results[i] + if result.has("file_path"): + var file_path = result["file_path"] + if file_path not in modified_files: + modified_files.append(file_path) + + # Limit the number of files to prevent system overload + if modified_files.size() > 100: + push_warning("[Rename Dialog] Large number of files to refresh: %d" % modified_files.size()) + + # Force reload with direct source replacement + _force_reload(modified_files) + +func _replace_src(path: String, new_text: String) -> void: + """Replace source code in open editors - prevents user from losing work state""" + var item_list: ItemList = IDE.get_script_list() + var editor_container: TabContainer = IDE.get_script_editor_container() + + # Check API availability + if not is_instance_valid(item_list) or not is_instance_valid(editor_container): + push_warning("[Rename Dialog] IDE components not available for source replacement") + return + + if item_list.item_count != editor_container.get_tab_count(): + push_warning("[Rename Dialog] Script list and editor container count mismatch") + return + + # Find and update open file editors + for x: int in item_list.item_count: + if path == item_list.get_item_tooltip(x): + var control: Control = editor_container.get_tab_control(x) + if control is ScriptEditorBase: + var editor: Control = control.get_base_editor() + if editor is CodeEdit: + # Save user's current view state + var scroll_h: int = editor.scroll_horizontal + var scroll_v: int = editor.scroll_vertical + var caret_line: int = editor.get_caret_line() + var caret_column: int = editor.get_caret_column() + + # Replace source content + editor.text = new_text + + # Restore user's view state (scroll position, cursor position) + editor.scroll_horizontal = scroll_h + editor.scroll_vertical = scroll_v + editor.set_caret_line(caret_line) + editor.set_caret_column(caret_column) + return + +func _force_reload(files: PackedStringArray, type_hint: String = "") -> void: + """Force reload files, bypassing cache and updating open editors""" + for file: String in files: + if not ResourceLoader.exists(file): + continue + + if ResourceLoader.has_cached(file): + # Bypass cache to load fresh content + var resource: Resource = ResourceLoader.load(file, type_hint, ResourceLoader.CACHE_MODE_IGNORE) + if resource is Script: + # Directly replace source in open editors + _replace_src(resource.resource_path, resource.source_code) + + + + + + +func _verify_modifications(new_name: String) -> bool: + """Verify that modifications were successfully applied to the file - Quality Assurance Mechanism""" + var files_to_check = {} + for i in _selected_items: + if i >= 0 and i < _rename_results.size(): + var result = _rename_results[i] + var file_path = result["file_path"] + if not files_to_check.has(file_path): + files_to_check[file_path] = [] + files_to_check[file_path].append(result) + + var verified_files = 0 + var total_files = files_to_check.size() + + # Validate modification results file by file + for file_path in files_to_check.keys(): + if _verify_file_modifications(file_path, files_to_check[file_path], new_name): + verified_files += 1 + # Show details only on failures + else: + print(" ❌ Verification failed: %s" % file_path.get_file()) + + var success = verified_files == total_files + if not success: + print(" ⚠️ Verification: %d/%d files verified" % [verified_files, total_files]) + + return success + +func _verify_file_modifications(file_path: String, modifications: Array, new_name: String) -> bool: + """Verify that modifications in a single file were successful""" + var file = FileAccess.open(file_path, FileAccess.READ) + if not file: + return false + + var lines = [] + while not file.eof_reached(): + lines.append(file.get_line()) + file.close() + + # Check each modification + for mod in modifications: + var line_idx = mod["line_number"] - 1 + if line_idx >= 0 and line_idx < lines.size(): + var line = lines[line_idx] + # Check if the new name exists + if not new_name in line: + return false + else: + return false + + return true + + + +func _show_sync_warning() -> void: + """Show warning about synchronization issues""" + print("[Rename Symbol] ⚠️ Files were modified but verification had issues") + + +func _on_close_requested() -> void: + _on_cancel_pressed() + + +func _on_focus_exited() -> void: + _on_cancel_pressed() + + +func _setup_dialog_display() -> void: + """Setup dialog size and position for proper display""" + # Get optimal size for dialog + var optimal_size = _get_optimal_dialog_size() + size = optimal_size + + # Center the dialog manually + _center_dialog() + +func _get_optimal_dialog_size() -> Vector2i: + """Calculate optimal dialog size based on content and DPI""" + # Base size for rename dialog + var base_size = Vector2i(800, 600) + + # Get screen info for DPI awareness + var screen = DisplayServer.screen_get_size() + var dpi_scale = DisplayServer.screen_get_scale() + + # Apply DPI scaling if needed + if dpi_scale > 1.0: + base_size = Vector2i( + int(base_size.x * min(dpi_scale, 1.5)), + int(base_size.y * min(dpi_scale, 1.5)) + ) + + # Ensure minimum size for rename dialog with code preview + base_size.x = max(base_size.x, 700) + base_size.y = max(base_size.y, 500) + + # Ensure it fits on screen (leave 100px margin) + base_size.x = min(base_size.x, screen.x - 100) + base_size.y = min(base_size.y, screen.y - 100) + + return base_size + +func _center_dialog() -> void: + """Manually center the dialog on screen""" + var screen_size = DisplayServer.screen_get_size() + var dialog_size = size + + # Calculate centered position + var centered_pos = Vector2i( + (screen_size.x - dialog_size.x) / 2, + (screen_size.y - dialog_size.y) / 2 + ) + + # Ensure dialog stays on screen + centered_pos.x = max(0, centered_pos.x) + centered_pos.y = max(0, centered_pos.y) + + # Set position + position = centered_pos diff --git a/addons/_Godot-IDE_/plugins/symbol_navigator/gui/rename_dialog.gd.uid b/addons/_Godot-IDE_/plugins/symbol_navigator/gui/rename_dialog.gd.uid new file mode 100644 index 0000000..802fd41 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/symbol_navigator/gui/rename_dialog.gd.uid @@ -0,0 +1 @@ +uid://b26eh3hs86gi4 diff --git a/addons/_Godot-IDE_/plugins/symbol_navigator/gui/rename_dialog.tscn b/addons/_Godot-IDE_/plugins/symbol_navigator/gui/rename_dialog.tscn new file mode 100644 index 0000000..ab5c30a --- /dev/null +++ b/addons/_Godot-IDE_/plugins/symbol_navigator/gui/rename_dialog.tscn @@ -0,0 +1,107 @@ +[gd_scene load_steps=2 format=3 uid="uid://byndwttsl5vau"] + +[ext_resource type="Script" uid="uid://b26eh3hs86gi4" path="res://addons/_Godot-IDE_/plugins/symbol_navigator/gui/rename_dialog.gd" id="1_rqbkt"] + +[node name="Window" type="Window" node_paths=PackedStringArray("new_name_edit", "scope_option", "preview_tree", "rename_button", "cancel_button", "select_all_button", "unselect_all_button", "selection_status")] +title = "Rename Symbol" +position = Vector2i(0, 36) +size = Vector2i(800, 600) +exclusive = true +script = ExtResource("1_rqbkt") +new_name_edit = NodePath("MarginContainer/MainContainer/HeaderContainer/NewNameEdit") +scope_option = NodePath("MarginContainer/MainContainer/HeaderContainer/ScopeOption") +preview_tree = NodePath("MarginContainer/MainContainer/PreviewContainer/PreviewTree") +rename_button = NodePath("MarginContainer/MainContainer/HBoxContainer/RenameButton") +cancel_button = NodePath("MarginContainer/MainContainer/HBoxContainer/CancelButton") +select_all_button = NodePath("MarginContainer/MainContainer/SelectionControls/SelectAllButton") +unselect_all_button = NodePath("MarginContainer/MainContainer/SelectionControls/UnselectAllButton") +selection_status = NodePath("MarginContainer/MainContainer/SelectionControls/SelectionStatus") + +[node name="MarginContainer" type="MarginContainer" parent="."] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/margin_left = 10 +theme_override_constants/margin_top = 10 +theme_override_constants/margin_right = 10 +theme_override_constants/margin_bottom = 10 + +[node name="MainContainer" type="VBoxContainer" parent="MarginContainer"] +layout_mode = 2 +theme_override_constants/separation = 10 + +[node name="HeaderContainer" type="VBoxContainer" parent="MarginContainer/MainContainer"] +layout_mode = 2 +size_flags_vertical = 4 +theme_override_constants/separation = 5 + +[node name="SymbolLabel" type="Label" parent="MarginContainer/MainContainer/HeaderContainer"] +layout_mode = 2 +text = "Rename symbol to:" +autowrap_mode = 3 + +[node name="NewNameEdit" type="LineEdit" parent="MarginContainer/MainContainer/HeaderContainer"] +layout_mode = 2 +placeholder_text = "Enter new name..." +select_all_on_focus = true + +[node name="ScopeOption" type="OptionButton" parent="MarginContainer/MainContainer/HeaderContainer"] +layout_mode = 2 +selected = 1 +item_count = 2 +popup/item_0/text = "Current File Only" +popup/item_0/id = 0 +popup/item_1/text = "Entire Project" +popup/item_1/id = 1 + +[node name="SelectionControls" type="HBoxContainer" parent="MarginContainer/MainContainer"] +layout_direction = 2 +layout_mode = 2 +size_flags_vertical = 4 +theme_override_constants/separation = 10 + +[node name="SelectionStatus" type="Label" parent="MarginContainer/MainContainer/SelectionControls"] +layout_direction = 2 +layout_mode = 2 +text = "0 of 0 selected" +horizontal_alignment = 2 + +[node name="SelectAllButton" type="Button" parent="MarginContainer/MainContainer/SelectionControls"] +layout_mode = 2 +text = "Select All" +alignment = 2 + +[node name="UnselectAllButton" type="Button" parent="MarginContainer/MainContainer/SelectionControls"] +layout_mode = 2 +text = "Unselect All" +alignment = 2 + +[node name="PreviewContainer" type="HSplitContainer" parent="MarginContainer/MainContainer"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="PreviewTree" type="Tree" parent="MarginContainer/MainContainer/PreviewContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +columns = 3 +column_titles_visible = true +hide_root = true + +[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/MainContainer"] +layout_mode = 2 +size_flags_vertical = 4 +theme_override_constants/separation = 10 +alignment = 2 + +[node name="RenameButton" type="Button" parent="MarginContainer/MainContainer/HBoxContainer"] +layout_mode = 2 +text = "Rename" + +[node name="CancelButton" type="Button" parent="MarginContainer/MainContainer/HBoxContainer"] +layout_mode = 2 +text = "Cancel" + +[connection signal="close_requested" from="." to="." method="_on_close_requested"] +[connection signal="focus_exited" from="." to="." method="_on_focus_exited"] diff --git a/addons/_Godot-IDE_/plugins/symbol_navigator/plugin.cfg b/addons/_Godot-IDE_/plugins/symbol_navigator/plugin.cfg new file mode 100644 index 0000000..825ea0d --- /dev/null +++ b/addons/_Godot-IDE_/plugins/symbol_navigator/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="Symbol Navigator" +description="Find references and rename symbols across the project" +author="kyros" +version="3.0" +script="plugin.gd" diff --git a/addons/_Godot-IDE_/plugins/symbol_navigator/plugin.gd b/addons/_Godot-IDE_/plugins/symbol_navigator/plugin.gd new file mode 100644 index 0000000..cb9b88a --- /dev/null +++ b/addons/_Godot-IDE_/plugins/symbol_navigator/plugin.gd @@ -0,0 +1,203 @@ +@tool +extends EditorPlugin +# ============================================================================= +# Author: GodotIDE Team +# Symbol Navigator +# +# Find references and rename symbols across the project +# ============================================================================= + +const FIND_REFERENCES_PANEL_UI = preload("res://addons/_Godot-IDE_/plugins/symbol_navigator/gui/find_references_panel.tscn") +const RENAME_SYMBOL_UI = preload("res://addons/_Godot-IDE_/plugins/symbol_navigator/gui/rename_dialog.tscn") + +var _find_references_panel : Control = null +var _find_references_panel_button : Button = null +var _rename_dialog : Window = null + +# Input shortcuts +var _find_references_input : InputEventKey = null +var _rename_symbol_input : InputEventKey = null + +# Menu items +var _context_menu_plugin : EditorPlugin = null + +func _init() -> void: + # Initialize shortcuts + _setup_shortcuts() + +func _setup_shortcuts() -> void: + # Find references shortcut (Shift+F12) + var find_input : Variant = IDE.get_config("symbol_navigator", "find_references_input") + if find_input is InputEventKey: + _find_references_input = find_input + else: + _find_references_input = InputEventKey.new() + _find_references_input.pressed = true + _find_references_input.shift_pressed = true + _find_references_input.keycode = KEY_F12 + IDE.set_config("symbol_navigator", "find_references_input", _find_references_input) + + # Rename symbol shortcut (F2) + var rename_input : Variant = IDE.get_config("symbol_navigator", "rename_symbol_input") + if rename_input is InputEventKey: + _rename_symbol_input = rename_input + else: + _rename_symbol_input = InputEventKey.new() + _rename_symbol_input.pressed = true + _rename_symbol_input.keycode = KEY_F2 + IDE.set_config("symbol_navigator", "rename_symbol_input", _rename_symbol_input) + +func _enter_tree() -> void: + # Plugin is activated + if IDE.debug: + print("[Symbol Navigator] Plugin activated") + + # Set up bottom panel for find references + _setup_bottom_panel() + +func _exit_tree() -> void: + # Clean up bottom panel + if is_instance_valid(_find_references_panel): + remove_control_from_bottom_panel(_find_references_panel) + _find_references_panel.queue_free() + _find_references_panel = null + _find_references_panel_button = null + + # Clean up rename dialog + if is_instance_valid(_rename_dialog): + _rename_dialog.queue_free() + _rename_dialog = null + + if IDE.debug: + print("[Symbol Navigator] Plugin deactivated") + +func _input(event: InputEvent) -> void: + if not event.is_pressed(): + return + + # Handle find references shortcut + if event.is_match(_find_references_input): + _open_find_references() + + # Handle rename symbol shortcut + elif event.is_match(_rename_symbol_input): + _open_rename_dialog() + +func _open_find_references() -> void: + var current_symbol = _get_symbol_at_cursor() + if current_symbol.is_empty(): + push_warning("[Symbol Navigator] No symbol found at cursor") + return + + # Ensure the bottom panel is set up + if not is_instance_valid(_find_references_panel): + _setup_bottom_panel() + + if is_instance_valid(_find_references_panel): + # Make the bottom panel visible first + make_bottom_panel_item_visible(_find_references_panel) + + # Try to call search_symbol with error handling + if _find_references_panel.has_method("search_symbol"): + _find_references_panel.search_symbol(current_symbol) + if _find_references_panel.has_method("show_and_focus"): + _find_references_panel.show_and_focus() + else: + push_warning("[Symbol Navigator] Panel search_symbol method not available, using fallback...") + # Just show the panel even if we can't search + if _find_references_panel.has_method("show_and_focus"): + _find_references_panel.show_and_focus() + else: + push_error("[Symbol Navigator] Failed to create or access find references panel") + +func _open_rename_dialog() -> void: + var current_symbol = _get_symbol_at_cursor() + if current_symbol.is_empty(): + push_warning("[Symbol Navigator] No symbol found at cursor") + return + + print("[Symbol Navigator] Opening rename dialog for symbol: ", current_symbol) + + if not is_instance_valid(_rename_dialog): + print("[Symbol Navigator] Creating new rename dialog instance") + _rename_dialog = RENAME_SYMBOL_UI.instantiate() + add_child(_rename_dialog) + + # Wait for the dialog to be ready before calling methods on it + if not _rename_dialog.is_node_ready(): + print("[Symbol Navigator] Dialog not ready, waiting for ready signal") + await _rename_dialog.ready + + print("[Symbol Navigator] Dialog ready, setting symbol") + + _rename_dialog.set_symbol(current_symbol) + _rename_dialog.popup_centered() + +# Get symbol at current cursor position +func _get_symbol_at_cursor() -> String: + var script_editor : ScriptEditor = EditorInterface.get_script_editor() + if not script_editor: + return "" + + var current_editor = script_editor.get_current_editor() + if not current_editor: + return "" + + var code_edit : CodeEdit = current_editor.get_base_editor() + if not code_edit: + return "" + + var caret_line = code_edit.get_caret_line() + var caret_column = code_edit.get_caret_column() + var line_text = code_edit.get_line(caret_line) + + # Extract word at cursor position + return _extract_word_at_position(line_text, caret_column) + +# Extract word at specific column position in text +func _extract_word_at_position(text: String, column: int) -> String: + if text.is_empty() or column < 0 or column >= text.length(): + return "" + + # Word boundary characters + var word_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_" + + # Find start of word + var start = column + while start > 0 and word_chars.contains(text[start - 1]): + start -= 1 + + # Find end of word + var end = column + while end < text.length() and word_chars.contains(text[end]): + end += 1 + + if start == end: + return "" + + return text.substr(start, end - start) + +func _setup_bottom_panel() -> void: + """Set up the find references bottom panel""" + if is_instance_valid(_find_references_panel): + return # Already set up + + # Create the panel instance + _find_references_panel = FIND_REFERENCES_PANEL_UI.instantiate() + + if not _find_references_panel: + push_error("[Symbol Navigator] Failed to instantiate find references panel") + return + + # Simple validation - just check if it's a Control + if not _find_references_panel is Control: + push_error("[Symbol Navigator] Panel is not a Control node") + _find_references_panel.queue_free() + _find_references_panel = null + return + + # Add it to the bottom panel with a tab + _find_references_panel_button = add_control_to_bottom_panel(_find_references_panel, "Find References") + + if IDE.debug: + print("[Symbol Navigator] Bottom panel 'Find References' added successfully") diff --git a/addons/_Godot-IDE_/plugins/symbol_navigator/plugin.gd.uid b/addons/_Godot-IDE_/plugins/symbol_navigator/plugin.gd.uid new file mode 100644 index 0000000..2652d29 --- /dev/null +++ b/addons/_Godot-IDE_/plugins/symbol_navigator/plugin.gd.uid @@ -0,0 +1 @@ +uid://hckp1nfwdm5l diff --git a/addons/_Godot-IDE_/shared_resources/CREDITS.txt b/addons/_Godot-IDE_/shared_resources/CREDITS.txt new file mode 100644 index 0000000..ce04a3b --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/CREDITS.txt @@ -0,0 +1,10 @@ +CREDITS + +Icons may vary from those: + * Downloaded from godot repository. + * Created by CodeNameTwister. + * Created by Community. + +URL: + github: https://github.com/godotengine/godot + github: https://github.com/CodeNameTwister diff --git a/addons/_Godot-IDE_/shared_resources/InterfaceScript.svg b/addons/_Godot-IDE_/shared_resources/InterfaceScript.svg new file mode 100644 index 0000000..0ddcb11 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/InterfaceScript.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + diff --git a/addons/_Godot-IDE_/shared_resources/InterfaceScript.svg.import b/addons/_Godot-IDE_/shared_resources/InterfaceScript.svg.import new file mode 100644 index 0000000..47de66b --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/InterfaceScript.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bjmtfc58y1sbs" +path="res://.godot/imported/InterfaceScript.svg-978d78f5291d69d37e8f5c5fbdda303f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/shared_resources/InterfaceScript.svg" +dest_files=["res://.godot/imported/InterfaceScript.svg-978d78f5291d69d37e8f5c5fbdda303f.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/shared_resources/MemberAnnotation.svg b/addons/_Godot-IDE_/shared_resources/MemberAnnotation.svg new file mode 100644 index 0000000..b2b486e --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/MemberAnnotation.svg @@ -0,0 +1 @@ + diff --git a/addons/_Godot-IDE_/shared_resources/MemberAnnotation.svg.import b/addons/_Godot-IDE_/shared_resources/MemberAnnotation.svg.import new file mode 100644 index 0000000..0243c23 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/MemberAnnotation.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dl6qns43xyjnv" +path="res://.godot/imported/MemberAnnotation.svg-66dc87598be9e506c35ad9c58ce00471.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/shared_resources/MemberAnnotation.svg" +dest_files=["res://.godot/imported/MemberAnnotation.svg-66dc87598be9e506c35ad9c58ce00471.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/shared_resources/MemberConstant.svg b/addons/_Godot-IDE_/shared_resources/MemberConstant.svg new file mode 100644 index 0000000..d4622ce --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/MemberConstant.svg @@ -0,0 +1 @@ + diff --git a/addons/_Godot-IDE_/shared_resources/MemberConstant.svg.import b/addons/_Godot-IDE_/shared_resources/MemberConstant.svg.import new file mode 100644 index 0000000..327285c --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/MemberConstant.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ouml4wypk5bq" +path="res://.godot/imported/MemberConstant.svg-4dc55bf9072736db9c3b22d3a1c92bb2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/shared_resources/MemberConstant.svg" +dest_files=["res://.godot/imported/MemberConstant.svg-4dc55bf9072736db9c3b22d3a1c92bb2.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/shared_resources/MemberConstructor.svg b/addons/_Godot-IDE_/shared_resources/MemberConstructor.svg new file mode 100644 index 0000000..0298086 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/MemberConstructor.svg @@ -0,0 +1 @@ + diff --git a/addons/_Godot-IDE_/shared_resources/MemberConstructor.svg.import b/addons/_Godot-IDE_/shared_resources/MemberConstructor.svg.import new file mode 100644 index 0000000..af27211 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/MemberConstructor.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d4jeah6wyiv8r" +path="res://.godot/imported/MemberConstructor.svg-ed9f2c87bf749cf455de04099172a17e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/shared_resources/MemberConstructor.svg" +dest_files=["res://.godot/imported/MemberConstructor.svg-ed9f2c87bf749cf455de04099172a17e.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/shared_resources/MemberMethod.svg b/addons/_Godot-IDE_/shared_resources/MemberMethod.svg new file mode 100644 index 0000000..9183525 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/MemberMethod.svg @@ -0,0 +1 @@ + diff --git a/addons/_Godot-IDE_/shared_resources/MemberMethod.svg.import b/addons/_Godot-IDE_/shared_resources/MemberMethod.svg.import new file mode 100644 index 0000000..a3b0f01 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/MemberMethod.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cgdceyfng83st" +path="res://.godot/imported/MemberMethod.svg-e10674ee5ab6973a2b54597a1c256593.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/shared_resources/MemberMethod.svg" +dest_files=["res://.godot/imported/MemberMethod.svg-e10674ee5ab6973a2b54597a1c256593.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/shared_resources/MemberOperator.svg b/addons/_Godot-IDE_/shared_resources/MemberOperator.svg new file mode 100644 index 0000000..1de44e1 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/MemberOperator.svg @@ -0,0 +1 @@ + diff --git a/addons/_Godot-IDE_/shared_resources/MemberOperator.svg.import b/addons/_Godot-IDE_/shared_resources/MemberOperator.svg.import new file mode 100644 index 0000000..4e5ef4f --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/MemberOperator.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://qjgp3e2bfkdt" +path="res://.godot/imported/MemberOperator.svg-c5b91d60b0472f74f035d73b4040fe2b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/shared_resources/MemberOperator.svg" +dest_files=["res://.godot/imported/MemberOperator.svg-c5b91d60b0472f74f035d73b4040fe2b.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/shared_resources/MemberProperty.svg b/addons/_Godot-IDE_/shared_resources/MemberProperty.svg new file mode 100644 index 0000000..52c1ce6 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/MemberProperty.svg @@ -0,0 +1 @@ + diff --git a/addons/_Godot-IDE_/shared_resources/MemberProperty.svg.import b/addons/_Godot-IDE_/shared_resources/MemberProperty.svg.import new file mode 100644 index 0000000..cc9196b --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/MemberProperty.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cec6jsyssk4ys" +path="res://.godot/imported/MemberProperty.svg-1ddceeee17fe7a22098a69e182e66fca.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/shared_resources/MemberProperty.svg" +dest_files=["res://.godot/imported/MemberProperty.svg-1ddceeee17fe7a22098a69e182e66fca.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/shared_resources/MemberSignal.svg b/addons/_Godot-IDE_/shared_resources/MemberSignal.svg new file mode 100644 index 0000000..f36ffa1 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/MemberSignal.svg @@ -0,0 +1 @@ + diff --git a/addons/_Godot-IDE_/shared_resources/MemberSignal.svg.import b/addons/_Godot-IDE_/shared_resources/MemberSignal.svg.import new file mode 100644 index 0000000..31e7077 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/MemberSignal.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bu2y52as0gijo" +path="res://.godot/imported/MemberSignal.svg-8254fad67fe0c20a2c2884abbd96d40f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/shared_resources/MemberSignal.svg" +dest_files=["res://.godot/imported/MemberSignal.svg-8254fad67fe0c20a2c2884abbd96d40f.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/shared_resources/MethodOverride.svg b/addons/_Godot-IDE_/shared_resources/MethodOverride.svg new file mode 100644 index 0000000..6210f0e --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/MethodOverride.svg @@ -0,0 +1 @@ + diff --git a/addons/_Godot-IDE_/shared_resources/MethodOverride.svg.import b/addons/_Godot-IDE_/shared_resources/MethodOverride.svg.import new file mode 100644 index 0000000..329b093 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/MethodOverride.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cjpyaeqxjujsy" +path="res://.godot/imported/MethodOverride.svg-77874f3b27ae11b68bc31d64d64b0ff7.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/shared_resources/MethodOverride.svg" +dest_files=["res://.godot/imported/MethodOverride.svg-77874f3b27ae11b68bc31d64d64b0ff7.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/shared_resources/MiniObject.svg b/addons/_Godot-IDE_/shared_resources/MiniObject.svg new file mode 100644 index 0000000..359c132 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/MiniObject.svg @@ -0,0 +1 @@ + diff --git a/addons/_Godot-IDE_/shared_resources/MiniObject.svg.import b/addons/_Godot-IDE_/shared_resources/MiniObject.svg.import new file mode 100644 index 0000000..0a54183 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/MiniObject.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://qlqlwh2m5g2g" +path="res://.godot/imported/MiniObject.svg-89475cde474fae096b341c01ac17ea07.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/shared_resources/MiniObject.svg" +dest_files=["res://.godot/imported/MiniObject.svg-89475cde474fae096b341c01ac17ea07.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/shared_resources/PluginScript.svg b/addons/_Godot-IDE_/shared_resources/PluginScript.svg new file mode 100644 index 0000000..910efc3 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/PluginScript.svg @@ -0,0 +1 @@ + diff --git a/addons/_Godot-IDE_/shared_resources/PluginScript.svg.import b/addons/_Godot-IDE_/shared_resources/PluginScript.svg.import new file mode 100644 index 0000000..bc80fa7 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/PluginScript.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://byubjxffpi1m0" +path="res://.godot/imported/PluginScript.svg-d9d886078c7444d411aced8d4bd81c3c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/shared_resources/PluginScript.svg" +dest_files=["res://.godot/imported/PluginScript.svg-d9d886078c7444d411aced8d4bd81c3c.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/shared_resources/Script.svg b/addons/_Godot-IDE_/shared_resources/Script.svg new file mode 100644 index 0000000..4e418ab --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/Script.svg @@ -0,0 +1 @@ + diff --git a/addons/_Godot-IDE_/shared_resources/Script.svg.import b/addons/_Godot-IDE_/shared_resources/Script.svg.import new file mode 100644 index 0000000..5b669d6 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/Script.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://mv5pf1qwmqho" +path="res://.godot/imported/Script.svg-d05847253586d81271dfb434935b6178.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/shared_resources/Script.svg" +dest_files=["res://.godot/imported/Script.svg-d05847253586d81271dfb434935b6178.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/shared_resources/ScriptExtend.svg b/addons/_Godot-IDE_/shared_resources/ScriptExtend.svg new file mode 100644 index 0000000..0b57798 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/ScriptExtend.svg @@ -0,0 +1 @@ + diff --git a/addons/_Godot-IDE_/shared_resources/ScriptExtend.svg.import b/addons/_Godot-IDE_/shared_resources/ScriptExtend.svg.import new file mode 100644 index 0000000..2ba6e41 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/ScriptExtend.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dqfn3tghaer0y" +path="res://.godot/imported/ScriptExtend.svg-07de63a340541258754fef7b071c3168.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/shared_resources/ScriptExtend.svg" +dest_files=["res://.godot/imported/ScriptExtend.svg-07de63a340541258754fef7b071c3168.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/shared_resources/Tools.svg b/addons/_Godot-IDE_/shared_resources/Tools.svg new file mode 100644 index 0000000..2ba2fc4 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/Tools.svg @@ -0,0 +1 @@ + diff --git a/addons/_Godot-IDE_/shared_resources/Tools.svg.import b/addons/_Godot-IDE_/shared_resources/Tools.svg.import new file mode 100644 index 0000000..58b1238 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/Tools.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bayjudew7j16p" +path="res://.godot/imported/Tools.svg-019ff87dc535ddd3db11c2c200d22113.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/shared_resources/Tools.svg" +dest_files=["res://.godot/imported/Tools.svg-019ff87dc535ddd3db11c2c200d22113.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/shared_resources/check.svg b/addons/_Godot-IDE_/shared_resources/check.svg new file mode 100644 index 0000000..921112b --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/check.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/addons/_Godot-IDE_/shared_resources/check.svg.import b/addons/_Godot-IDE_/shared_resources/check.svg.import new file mode 100644 index 0000000..ff84953 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/check.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://csrtms7lvdx8w" +path="res://.godot/imported/check.svg-b87e99db7758119a786b0c553010930b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/shared_resources/check.svg" +dest_files=["res://.godot/imported/check.svg-b87e99db7758119a786b0c553010930b.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/shared_resources/dot.svg b/addons/_Godot-IDE_/shared_resources/dot.svg new file mode 100644 index 0000000..1d5927f --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/dot.svg @@ -0,0 +1,41 @@ + + + + + + + + diff --git a/addons/_Godot-IDE_/shared_resources/dot.svg.import b/addons/_Godot-IDE_/shared_resources/dot.svg.import new file mode 100644 index 0000000..6533349 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/dot.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://lp3f3g1amkc7" +path="res://.godot/imported/dot.svg-63df02addb58f3150f7ea8b487e79315.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/shared_resources/dot.svg" +dest_files=["res://.godot/imported/dot.svg-63df02addb58f3150f7ea8b487e79315.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/shared_resources/down.svg b/addons/_Godot-IDE_/shared_resources/down.svg new file mode 100644 index 0000000..cbe103f --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/down.svg @@ -0,0 +1,56 @@ + + + + + + + up + + + + + up + + + + diff --git a/addons/_Godot-IDE_/shared_resources/down.svg.import b/addons/_Godot-IDE_/shared_resources/down.svg.import new file mode 100644 index 0000000..17500c9 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/down.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c2oodbi52ec3m" +path="res://.godot/imported/down.svg-84b9ebb55f51b2dc7e4d105afecfa4c0.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/shared_resources/down.svg" +dest_files=["res://.godot/imported/down.svg-84b9ebb55f51b2dc7e4d105afecfa4c0.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/shared_resources/func_private.svg b/addons/_Godot-IDE_/shared_resources/func_private.svg new file mode 100644 index 0000000..9957f77 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/func_private.svg @@ -0,0 +1,47 @@ + + + + + + + + diff --git a/addons/_Godot-IDE_/shared_resources/func_private.svg.import b/addons/_Godot-IDE_/shared_resources/func_private.svg.import new file mode 100644 index 0000000..bf9761c --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/func_private.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://do4gmovks0mn6" +path="res://.godot/imported/func_private.svg-95314f7c2fb9613d1b172db455694da5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/shared_resources/func_private.svg" +dest_files=["res://.godot/imported/func_private.svg-95314f7c2fb9613d1b172db455694da5.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/shared_resources/func_public.svg b/addons/_Godot-IDE_/shared_resources/func_public.svg new file mode 100644 index 0000000..7d40eec --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/func_public.svg @@ -0,0 +1,55 @@ + + + + + + + + + + + + diff --git a/addons/_Godot-IDE_/shared_resources/func_public.svg.import b/addons/_Godot-IDE_/shared_resources/func_public.svg.import new file mode 100644 index 0000000..2084100 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/func_public.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ckc3yk6f8y3ob" +path="res://.godot/imported/func_public.svg-e84d2a0b8a76de4cc140c8ac1fc5fa19.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/shared_resources/func_public.svg" +dest_files=["res://.godot/imported/func_public.svg-e84d2a0b8a76de4cc140c8ac1fc5fa19.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/shared_resources/func_virtual.svg b/addons/_Godot-IDE_/shared_resources/func_virtual.svg new file mode 100644 index 0000000..cfedb37 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/func_virtual.svg @@ -0,0 +1,40 @@ + + + + + + diff --git a/addons/_Godot-IDE_/shared_resources/func_virtual.svg.import b/addons/_Godot-IDE_/shared_resources/func_virtual.svg.import new file mode 100644 index 0000000..6573de7 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/func_virtual.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dg7rdmg80x4jv" +path="res://.godot/imported/func_virtual.svg-80710816056a85c8137e952bcaa38480.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/shared_resources/func_virtual.svg" +dest_files=["res://.godot/imported/func_virtual.svg-80710816056a85c8137e952bcaa38480.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/shared_resources/search.svg b/addons/_Godot-IDE_/shared_resources/search.svg new file mode 100644 index 0000000..b4582cc --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/search.svg @@ -0,0 +1,55 @@ + + + + diff --git a/addons/_Godot-IDE_/shared_resources/search.svg.import b/addons/_Godot-IDE_/shared_resources/search.svg.import new file mode 100644 index 0000000..c3ab77b --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/search.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://816fejewtbfj" +path="res://.godot/imported/search.svg-eb5038c2ffb72bd3926a7614da05a411.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/shared_resources/search.svg" +dest_files=["res://.godot/imported/search.svg-eb5038c2ffb72bd3926a7614da05a411.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/shared_resources/static.svg b/addons/_Godot-IDE_/shared_resources/static.svg new file mode 100644 index 0000000..af9ae2d --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/static.svg @@ -0,0 +1,58 @@ + + + + diff --git a/addons/_Godot-IDE_/shared_resources/static.svg.import b/addons/_Godot-IDE_/shared_resources/static.svg.import new file mode 100644 index 0000000..225fdbc --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/static.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ds6tdwn7834jk" +path="res://.godot/imported/static.svg-2d7e8777fe546366b9cbd2e7140c27b2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/shared_resources/static.svg" +dest_files=["res://.godot/imported/static.svg-2d7e8777fe546366b9cbd2e7140c27b2.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/shared_resources/up.svg b/addons/_Godot-IDE_/shared_resources/up.svg new file mode 100644 index 0000000..939c201 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/up.svg @@ -0,0 +1,56 @@ + + + + + + + up + + + + + up + + + + diff --git a/addons/_Godot-IDE_/shared_resources/up.svg.import b/addons/_Godot-IDE_/shared_resources/up.svg.import new file mode 100644 index 0000000..5a4131c --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/up.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bgjo43cuidob1" +path="res://.godot/imported/up.svg-5eba3501c749f279a18720dc3ddb6226.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/shared_resources/up.svg" +dest_files=["res://.godot/imported/up.svg-5eba3501c749f279a18720dc3ddb6226.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=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/_Godot-IDE_/shared_resources/warning.png b/addons/_Godot-IDE_/shared_resources/warning.png new file mode 100644 index 0000000..3627ca0 --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/warning.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:44906c3c38edec5fd2281617b09b07c9121e72f0a01b6f663d1b9bd1c6d3f734 +size 238 diff --git a/addons/_Godot-IDE_/shared_resources/warning.png.import b/addons/_Godot-IDE_/shared_resources/warning.png.import new file mode 100644 index 0000000..21e586c --- /dev/null +++ b/addons/_Godot-IDE_/shared_resources/warning.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://x8xl24etv1nb" +path="res://.godot/imported/warning.png-7a2d105cf05eee357eaf1264447091e5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/_Godot-IDE_/shared_resources/warning.png" +dest_files=["res://.godot/imported/warning.png-7a2d105cf05eee357eaf1264447091e5.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 diff --git a/project.godot b/project.godot index 1ef97d2..0413754 100644 --- a/project.godot +++ b/project.godot @@ -8,11 +8,15 @@ config_version=5 +[animation] + +compatibility/default_parent_skeleton_in_mesh_instance_3d=true + [application] config/name="TheFlipSide" run/main_scene="res://Scenes/main.tscn" -config/features=PackedStringArray("4.5", "Forward Plus") +config/features=PackedStringArray("4.6", "Forward Plus") [autoload] @@ -22,6 +26,17 @@ al_globals="*res://Scripts/al_globals.gd" project/assembly_name="TheFlipSide" +[editor_plugins] + +enabled=PackedStringArray("res://addons/_Godot-IDE_/plugin.cfg") + +[file_customization] + +folder_colors={ +"res://addons/_Godot-IDE_/plugins": "blue", +"res://addons/_Godot-IDE_/shared_resources/": "teal" +} + [input] flip={