summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/classes/@GDScript.xml4
-rw-r--r--doc/classes/EditorFileSystem.xml4
-rw-r--r--doc/classes/EditorInterface.xml12
-rw-r--r--doc/classes/EditorPlugin.xml58
-rw-r--r--doc/classes/EditorResourcePreviewGenerator.xml16
-rw-r--r--doc/classes/EditorSettings.xml8
-rw-r--r--doc/classes/ProjectSettings.xml3
-rwxr-xr-xdoc/tools/makerst.py17
-rw-r--r--drivers/gles3/shaders/canvas.glsl10
-rw-r--r--editor/dependency_editor.cpp28
-rw-r--r--editor/editor_file_dialog.cpp20
-rw-r--r--editor/editor_file_dialog.h4
-rw-r--r--editor/editor_node.cpp248
-rw-r--r--editor/editor_node.h17
-rw-r--r--editor/editor_plugin.cpp30
-rw-r--r--editor/editor_plugin.h8
-rw-r--r--editor/editor_resource_preview.cpp109
-rw-r--r--editor/editor_resource_preview.h11
-rw-r--r--editor/editor_settings.cpp31
-rw-r--r--editor/editor_settings.h6
-rw-r--r--editor/filesystem_dock.cpp1470
-rw-r--r--editor/filesystem_dock.h90
-rw-r--r--editor/import/resource_importer_obj.cpp21
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp12
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.h4
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp2
-rw-r--r--editor/plugins/animation_player_editor_plugin.h4
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp243
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h2
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.h4
-rw-r--r--editor/plugins/editor_preview_plugins.cpp151
-rw-r--r--editor/plugins/editor_preview_plugins.h26
-rw-r--r--editor/plugins/light_occluder_2d_editor_plugin.cpp8
-rw-r--r--editor/plugins/light_occluder_2d_editor_plugin.h4
-rw-r--r--editor/plugins/path_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/path_2d_editor_plugin.h4
-rw-r--r--editor/plugins/shader_editor_plugin.cpp4
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp6
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp40
-rw-r--r--editor/plugins/tile_map_editor_plugin.h8
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp11
-rw-r--r--main/main.cpp164
-rw-r--r--main/main.h9
-rw-r--r--modules/opensimplex/doc_classes/SimplexNoise.xml6
-rw-r--r--scene/2d/navigation2d.cpp28
-rw-r--r--scene/3d/navigation.cpp40
-rw-r--r--scene/3d/navigation.h1
-rw-r--r--scene/resources/font.cpp1
-rw-r--r--scene/resources/shader.cpp11
-rw-r--r--scene/resources/shader.h2
-rw-r--r--scene/resources/visual_shader.cpp4
-rw-r--r--scene/resources/visual_shader.h2
53 files changed, 1810 insertions, 1220 deletions
diff --git a/doc/classes/@GDScript.xml b/doc/classes/@GDScript.xml
index 3e46dc4e92..7bd332a3e4 100644
--- a/doc/classes/@GDScript.xml
+++ b/doc/classes/@GDScript.xml
@@ -120,9 +120,9 @@
<method name="atan2">
<return type="float">
</return>
- <argument index="0" name="x" type="float">
+ <argument index="0" name="y" type="float">
</argument>
- <argument index="1" name="y" type="float">
+ <argument index="1" name="x" type="float">
</argument>
<description>
Returns the arc tangent of [code]y/x[/code] in radians. Use to get the angle of tangent [code]y/x[/code]. To compute the value, the method takes into account the sign of both arguments in order to determine the quadrant.
diff --git a/doc/classes/EditorFileSystem.xml b/doc/classes/EditorFileSystem.xml
index ade6d2034d..5a8b506f9e 100644
--- a/doc/classes/EditorFileSystem.xml
+++ b/doc/classes/EditorFileSystem.xml
@@ -93,10 +93,6 @@
Remitted if a resource is reimported.
</description>
</signal>
- <signal name="script_classes_updated">
- <description>
- </description>
- </signal>
<signal name="sources_changed">
<argument index="0" name="exist" type="bool">
</argument>
diff --git a/doc/classes/EditorInterface.xml b/doc/classes/EditorInterface.xml
index d85d021a68..f073c5e40b 100644
--- a/doc/classes/EditorInterface.xml
+++ b/doc/classes/EditorInterface.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="EditorInterface" inherits="Node" category="Core" version="3.1">
<brief_description>
- Editor interface and main components.
+ Godot editor's interface.
</brief_description>
<description>
- Editor interface. Allows saving and (re-)loading scenes, rendering mesh previews, inspecting and editing resources and objects and provides access to [EditorSettings], [EditorFileSystem], [EditorResourcePreview], [ScriptEditor], the editor viewport, as well as information about scenes. Also see [EditorPlugin] and [EditorScript].
+ EditorInterface gives you control over Godot editor's window. It allows customizing the window, saving and (re-)loading scenes, rendering mesh previews, inspecting and editing resources and objects, and provides access to [EditorSettings], [EditorFileSystem], [EditorResourcePreview], [ScriptEditor], the editor viewport, and information about scenes.
</description>
<tutorials>
</tutorials>
@@ -24,14 +24,14 @@
<return type="Control">
</return>
<description>
- Returns the main container of Godot's editor window. You can use it, for example, to retrieve the size of the container and place your controls accordingly.
+ Returns the main container of Godot editor's window. You can use it, for example, to retrieve the size of the container and place your controls accordingly.
</description>
</method>
<method name="get_edited_scene_root">
<return type="Node">
</return>
<description>
- Returns the edited scene's root [Node].
+ Returns the edited (current) scene's root [Node].
</description>
</method>
<method name="get_editor_settings">
@@ -52,7 +52,7 @@
<return type="Array">
</return>
<description>
- Returns an [Array] of the currently opened scenes.
+ Returns an [Array] with the file paths of the currently opened scenes.
</description>
</method>
<method name="get_resource_filesystem">
@@ -66,7 +66,7 @@
<return type="EditorResourcePreview">
</return>
<description>
- Returns the [EditorResourcePreview]\ er.
+ Returns the [EditorResourcePreview].
</description>
</method>
<method name="get_script_editor">
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index 208780547e..ac139f18c9 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -4,7 +4,7 @@
Used by the editor to extend its functionality.
</brief_description>
<description>
- Plugins are used by the editor to extend functionality. The most common types of plugins are those which edit a given node or resource type, import plugins and export plugins.
+ Plugins are used by the editor to extend functionality. The most common types of plugins are those which edit a given node or resource type, import plugins and export plugins. Also see [EditorScript] to add functions to the editor.
</description>
<tutorials>
<link>http://docs.godotengine.org/en/3.0/development/plugins/index.html</link>
@@ -31,7 +31,7 @@
<argument index="1" name="title" type="String">
</argument>
<description>
- Add a control to the bottom panel (together with Output, Debug, Animation, etc). Returns a reference to the button added. It's up to you to hide/show the button when needed. If your plugin is being removed, also make sure to remove your control by calling [method remove_control_from_bottom_panel].
+ Add a control to the bottom panel (together with Output, Debug, Animation, etc). Returns a reference to the button added. It's up to you to hide/show the button when needed. When your plugin is deactivated, make sure to remove your custom control with [method remove_control_from_bottom_panel] and free it with [code]queue_free()[/code].
</description>
</method>
<method name="add_control_to_container">
@@ -44,7 +44,7 @@
<description>
Add a custom control to a container (see CONTAINER_* enum). There are many locations where custom controls can be added in the editor UI.
Please remember that you have to manage the visibility of your custom controls yourself (and likely hide it after adding it).
- If your plugin is being removed, also make sure to remove your custom controls too.
+ When your plugin is deactivated, make sure to remove your custom control with [method remove_control_from_container] and free it with [code]queue_free()[/code].
</description>
</method>
<method name="add_control_to_dock">
@@ -57,7 +57,7 @@
<description>
Add the control to a specific dock slot (see DOCK_* enum for options).
If the dock is repositioned and as long as the plugin is active, the editor will save the dock position on further sessions.
- If your plugin is being removed, also make sure to remove your control by calling [method remove_control_from_docks].
+ When your plugin is deactivated, make sure to remove your custom control with [method remove_control_from_docks] and free it with [code]queue_free()[/code].
</description>
</method>
<method name="add_custom_type">
@@ -74,7 +74,7 @@
<description>
Add a custom type, which will appear in the list of nodes or resources. An icon can be optionally passed.
When given node or resource is selected, the base type will be instanced (ie, "Spatial", "Control", "Resource"), then the script will be loaded and set to this object.
- You can use the [method EditorPlugin.handles] to check if your custom object is being edited by checking the script or using 'is' keyword.
+ You can use the virtual method [method handles] to check if your custom object is being edited by checking the script or using 'is' keyword.
During run-time, this will be a simple object with a script so this function does not need to be called then.
</description>
</method>
@@ -122,7 +122,7 @@
<argument index="3" name="ud" type="Variant" default="null">
</argument>
<description>
- Adds a custom menu to 'Project &gt; Tools' as [code]name[/code] that calls [code]callback[/code] on an instance of [code]handler[/code] with a parameter [code]ud[/code] when user activates it.
+ Add a custom menu to 'Project &gt; Tools' as [code]name[/code] that calls [code]callback[/code] on an instance of [code]handler[/code] with a parameter [code]ud[/code] when user activates it.
</description>
</method>
<method name="add_tool_submenu_item">
@@ -133,6 +133,7 @@
<argument index="1" name="submenu" type="Object">
</argument>
<description>
+ Like [method add_tool_menu_item] but adds the [code]submenu[/code] item inside the [code]name[/code] menu.
</description>
</method>
<method name="apply_changes" qualifiers="virtual">
@@ -165,15 +166,21 @@
This function is used for plugins that edit specific object types (nodes or resources). It requests the editor to edit the given object.
</description>
</method>
- <method name="forward_canvas_gui_input" qualifiers="virtual">
- <return type="bool">
+ <method name="forward_canvas_draw_over_viewport" qualifiers="virtual">
+ <return type="void">
</return>
- <argument index="0" name="event" type="InputEvent">
+ <argument index="0" name="overlay" type="Control">
</argument>
<description>
+ This method is called when there is an input event in the 2D viewport, e.g. the user clicks with the mouse in the 2D space (canvas GUI). Keep in mind that for this method to be called you have to first declare the virtual method [method handles] so the editor knows that you want to work with the workspace:
+ [codeblock]
+ func handles(object):
+ return true
+ [/codeblock]
+ Also note that the edited scene must have a root node.
</description>
</method>
- <method name="forward_draw_over_viewport" qualifiers="virtual">
+ <method name="forward_canvas_force_draw_over_viewport" qualifiers="virtual">
<return type="void">
</return>
<argument index="0" name="overlay" type="Control">
@@ -181,10 +188,10 @@
<description>
</description>
</method>
- <method name="forward_force_draw_over_viewport" qualifiers="virtual">
- <return type="void">
+ <method name="forward_canvas_gui_input" qualifiers="virtual">
+ <return type="bool">
</return>
- <argument index="0" name="overlay" type="Control">
+ <argument index="0" name="event" type="InputEvent">
</argument>
<description>
</description>
@@ -197,8 +204,12 @@
<argument index="1" name="event" type="InputEvent">
</argument>
<description>
- Implement this function if you are interested in 3D view screen input events. It will be called only if currently selected node is handled by your plugin.
- If you would like to always gets those input events then additionally use [method set_input_forwarding_always_enabled].
+ This method is called when there is an input event in the 3D viewport, e.g. the user clicks with the mouse in the 3D space (spatial GUI). Keep in mind that for this method to be called you have to first declare the virtual method [method handles] so the editor knows that you want to work with the workspace:
+ [codeblock]
+ func handles(object):
+ return true
+ [/codeblock]
+ Also note that the edited scene must have a root node.
</description>
</method>
<method name="get_breakpoints" qualifiers="virtual">
@@ -212,6 +223,7 @@
<return type="EditorInterface">
</return>
<description>
+ Return the [EditorInterface] object that gives you control over Godot editor's window and its functionalities.
</description>
</method>
<method name="get_plugin_icon" qualifiers="virtual">
@@ -253,7 +265,7 @@
<argument index="0" name="layout" type="ConfigFile">
</argument>
<description>
- Get the GUI layout of the plugin. This is used to save the project's editor layout when the [method EditorPlugin.queue_save_layout] is called or the editor layout was changed(For example changing the position of a dock).
+ Get the GUI layout of the plugin. This is used to save the project's editor layout when [method queue_save_layout] is called or the editor layout was changed(For example changing the position of a dock).
</description>
</method>
<method name="handles" qualifiers="virtual">
@@ -262,14 +274,14 @@
<argument index="0" name="object" type="Object">
</argument>
<description>
- Implement this function if your plugin edits a specific type of object (Resource or Node). If you return true, then you will get the functions [method EditorPlugin.edit] and [method EditorPlugin.make_visible] called when the editor requests them.
+ Implement this function if your plugin edits a specific type of object (Resource or Node). If you return true, then you will get the functions [method EditorPlugin.edit] and [method EditorPlugin.make_visible] called when the editor requests them. If you have declared the methods [method forward_canvas_gui_input] and [method forward_spatial_gui_input] these will be called too.
</description>
</method>
<method name="has_main_screen" qualifiers="virtual">
<return type="bool">
</return>
<description>
- Return true if this is a main screen editor plugin (it goes in the main screen selector together with 2D, 3D, Script).
+ Return true if this is a main screen editor plugin (it goes in the workspaces selector together with '2D', '3D', and 'Script').
</description>
</method>
<method name="hide_bottom_panel">
@@ -318,7 +330,7 @@
<argument index="0" name="control" type="Control">
</argument>
<description>
- Remove the control from the bottom panel. Don't forget to call this if you added one, so the editor can remove it cleanly.
+ Remove the control from the bottom panel. You have to manually [code]queue_free()[/code] the control.
</description>
</method>
<method name="remove_control_from_container">
@@ -329,7 +341,7 @@
<argument index="1" name="control" type="Control">
</argument>
<description>
- Remove the control from the specified container. Use it when cleaning up after adding a control with [method add_control_to_container]. Note that you can simply free the control if you won't use it anymore.
+ Remove the control from the specified container. You have to manually [code]queue_free()[/code] the control.
</description>
</method>
<method name="remove_control_from_docks">
@@ -338,7 +350,7 @@
<argument index="0" name="control" type="Control">
</argument>
<description>
- Remove the control from the dock. Don't forget to call this if you added one, so the editor can save the layout and remove it cleanly.
+ Remove the control from the dock. You have to manually [code]queue_free()[/code] the control.
</description>
</method>
<method name="remove_custom_type">
@@ -347,7 +359,7 @@
<argument index="0" name="type" type="String">
</argument>
<description>
- Remove a custom type added by [method EditorPlugin.add_custom_type]
+ Remove a custom type added by [method add_custom_type]
</description>
</method>
<method name="remove_export_plugin">
@@ -441,7 +453,7 @@
<argument index="0" name="screen_name" type="String">
</argument>
<description>
- Emitted when user change main screen view (2D, 3D, Script, AssetLib). Works also with screens which are defined by plugins.
+ Emitted when user change the workspace (2D, 3D, Script, AssetLib). Also works with custom screens defined by plugins.
</description>
</signal>
<signal name="resource_saved">
diff --git a/doc/classes/EditorResourcePreviewGenerator.xml b/doc/classes/EditorResourcePreviewGenerator.xml
index fb9af47b1f..c4dcbbbc82 100644
--- a/doc/classes/EditorResourcePreviewGenerator.xml
+++ b/doc/classes/EditorResourcePreviewGenerator.xml
@@ -16,10 +16,12 @@
</return>
<argument index="0" name="from" type="Resource">
</argument>
+ <argument index="1" name="size" type="Vector2">
+ </argument>
<description>
- Generate a preview from a given resource. This must be always implemented.
- Returning an empty texture is an OK way to fail and let another generator take care.
- Care must be taken because this function is always called from a thread (not the main thread).
+ Generate a preview from a given resource with the specified size. This must always be implemented.
+ Returning an empty texture is an OK way to fail and let another generator take care.
+ Care must be taken because this function is always called from a thread (not the main thread).
</description>
</method>
<method name="generate_from_path" qualifiers="virtual">
@@ -27,10 +29,12 @@
</return>
<argument index="0" name="path" type="String">
</argument>
+ <argument index="1" name="size" type="Vector2">
+ </argument>
<description>
- Generate a preview directly from a path, implementing this is optional, as default code will load and call generate()
- Returning an empty texture is an OK way to fail and let another generator take care.
- Care must be taken because this function is always called from a thread (not the main thread).
+ Generate a preview directly from a path with the specified size. Implementing this is optional, as default code will load and call [method generate].
+ Returning an empty texture is an OK way to fail and let another generator take care.
+ Care must be taken because this function is always called from a thread (not the main thread).
</description>
</method>
<method name="handles" qualifiers="virtual">
diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index bd85075b7e..9d48669a6b 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -48,11 +48,11 @@
Erase a given setting (pass full property path).
</description>
</method>
- <method name="get_favorite_dirs" qualifiers="const">
+ <method name="get_favorites" qualifiers="const">
<return type="PoolStringArray">
</return>
<description>
- Get the list of favorite directories for this project.
+ Get the list of favorite files and directories for this project.
</description>
</method>
<method name="get_project_metadata" qualifiers="const">
@@ -122,13 +122,13 @@
<description>
</description>
</method>
- <method name="set_favorite_dirs">
+ <method name="set_favorites">
<return type="void">
</return>
<argument index="0" name="dirs" type="PoolStringArray">
</argument>
<description>
- Set the list of favorite directories for this project.
+ Set the list of favorite files and directories for this project.
</description>
</method>
<method name="set_initial_value">
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 548d60fe35..c05d6bc849 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -609,9 +609,6 @@
<member name="network/remote_fs/page_size" type="int" setter="" getter="">
Page size used by remote filesystem.
</member>
- <member name="network/ssl/certificates" type="String" setter="" getter="">
- If your game or application uses HTTPS, a certificates file is needed. It must be set here.
- </member>
<member name="node/name_casing" type="int" setter="" getter="">
When creating nodes names automatically, set the type of casing in this project. This is mostly an editor setting.
</member>
diff --git a/doc/tools/makerst.py b/doc/tools/makerst.py
index ad6601b18b..63a5c8cbbf 100755
--- a/doc/tools/makerst.py
+++ b/doc/tools/makerst.py
@@ -573,7 +573,7 @@ def make_rst_class(node):
if events != None and len(list(events)) > 0:
f.write(make_heading('Signals', '-'))
for m in list(events):
- f.write(" .. _class_" + name + "_" + m.attrib['name'] + ":\n\n")
+ f.write(".. _class_" + name + "_" + m.attrib['name'] + ":\n\n")
make_method(f, name, m, True, True)
f.write('\n')
d = m.find('description')
@@ -599,7 +599,7 @@ def make_rst_class(node):
if len(enum_names) > 0:
f.write(make_heading('Enumerations', '-'))
for e in enum_names:
- f.write(" .. _enum_" + name + "_" + e + ":\n\n")
+ f.write(".. _enum_" + name + "_" + e + ":\n\n")
f.write("enum **" + e + "**:\n\n")
for c in enums:
if c.attrib['enum'] != e:
@@ -624,6 +624,7 @@ def make_rst_class(node):
if c.text.strip() != '':
s += ' --- ' + rstize_text(c.text.strip(), name)
f.write(s + '\n')
+ f.write('\n')
# Class description
descr = node.find('description')
@@ -644,25 +645,25 @@ def make_rst_class(node):
if match.lastindex == 2:
# Doc reference with fragment identifier: emit direct link to section with reference to page, for example:
# `#calling-javascript-from-script in Exporting For Web`
- f.write("- `" + groups[1] + " <../" + groups[0] + ".html" + groups[1] + ">`_ in :doc:`../" + groups[0] + "`\n")
+ f.write("- `" + groups[1] + " <../" + groups[0] + ".html" + groups[1] + ">`_ in :doc:`../" + groups[0] + "`\n\n")
# Commented out alternative: Instead just emit:
# `Subsection in Exporting For Web`
- # f.write("- `Subsection <../" + groups[0] + ".html" + groups[1] + ">`_ in :doc:`../" + groups[0] + "`\n")
+ # f.write("- `Subsection <../" + groups[0] + ".html" + groups[1] + ">`_ in :doc:`../" + groups[0] + "`\n\n")
elif match.lastindex == 1:
# Doc reference, for example:
# `Math`
- f.write("- :doc:`../" + groups[0] + "`\n")
+ f.write("- :doc:`../" + groups[0] + "`\n\n")
else:
# External link, for example:
# `http://enet.bespin.org/usergroup0.html`
- f.write("- `" + link + " <" + link + ">`_\n")
+ f.write("- `" + link + " <" + link + ">`_\n\n")
# Property descriptions
members = node.find('members')
if members != None and len(list(members)) > 0:
f.write(make_heading('Property Descriptions', '-'))
for m in list(members):
- f.write(" .. _class_" + name + "_" + m.attrib['name'] + ":\n\n")
+ f.write(".. _class_" + name + "_" + m.attrib['name'] + ":\n\n")
make_properties(f, name, m, True)
if m.text.strip() != '':
f.write(rstize_text(m.text.strip(), name))
@@ -673,7 +674,7 @@ def make_rst_class(node):
if methods != None and len(list(methods)) > 0:
f.write(make_heading('Method Descriptions', '-'))
for m in list(methods):
- f.write(" .. _class_" + name + "_" + m.attrib['name'] + ":\n\n")
+ f.write(".. _class_" + name + "_" + m.attrib['name'] + ":\n\n")
make_method(f, name, m, True)
f.write('\n')
d = m.find('description')
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index 53f563303a..5203f53fa2 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -120,12 +120,12 @@ void main() {
vec4 color = color_attrib;
#ifdef USE_INSTANCING
- mat4 extra_matrix2 = extra_matrix * transpose(mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0)));
+ mat4 extra_matrix_instance = extra_matrix * transpose(mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0)));
color *= instance_color;
vec4 instance_custom = instance_custom_data;
#else
- mat4 extra_matrix2 = extra_matrix;
+ mat4 extra_matrix_instance = extra_matrix;
vec4 instance_custom = vec4(0.0);
#endif
@@ -157,7 +157,7 @@ void main() {
#endif
-#define extra_matrix extra_matrix2
+#define extra_matrix extra_matrix_instance
{
/* clang-format off */
@@ -246,8 +246,8 @@ VERTEX_SHADER_CODE
pos = outvec.xy;
#endif
- local_rot.xy = normalize((modelview_matrix * (extra_matrix * vec4(1.0, 0.0, 0.0, 0.0))).xy);
- local_rot.zw = normalize((modelview_matrix * (extra_matrix * vec4(0.0, 1.0, 0.0, 0.0))).xy);
+ local_rot.xy = normalize((modelview_matrix * (extra_matrix_instance * vec4(1.0, 0.0, 0.0, 0.0))).xy);
+ local_rot.zw = normalize((modelview_matrix * (extra_matrix_instance * vec4(0.0, 1.0, 0.0, 0.0))).xy);
#ifdef USE_TEXTURE_RECT
local_rot.xy *= sign(src_rect.z);
local_rot.zw *= sign(src_rect.w);
diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp
index 037543f45c..d64b02a605 100644
--- a/editor/dependency_editor.cpp
+++ b/editor/dependency_editor.cpp
@@ -504,7 +504,7 @@ void DependencyRemoveDialog::ok_pressed() {
}
if (dirs_to_delete.size() == 0) {
- //If we only deleted files we should only need to tell the file system about the files we touched.
+ // If we only deleted files we should only need to tell the file system about the files we touched.
for (int i = 0; i < files_to_delete.size(); ++i)
EditorFileSystem::get_singleton()->update_file(files_to_delete[i]);
} else {
@@ -518,21 +518,25 @@ void DependencyRemoveDialog::ok_pressed() {
}
}
- // if some dirs would be deleted, favorite dirs need to be updated
- Vector<String> previous_favorite_dirs = EditorSettings::get_singleton()->get_favorite_dirs();
- Vector<String> new_favorite_dirs;
+ EditorFileSystem::get_singleton()->scan_changes();
+ }
- for (int i = 0; i < previous_favorite_dirs.size(); ++i) {
- if (dirs_to_delete.find(previous_favorite_dirs[i] + "/") < 0) {
- new_favorite_dirs.push_back(previous_favorite_dirs[i]);
- }
- }
+ // If some files/dirs would be deleted, favorite dirs need to be updated
+ Vector<String> previous_favorites = EditorSettings::get_singleton()->get_favorites();
+ Vector<String> new_favorites;
- if (new_favorite_dirs.size() < previous_favorite_dirs.size()) {
- EditorSettings::get_singleton()->set_favorite_dirs(new_favorite_dirs);
+ for (int i = 0; i < previous_favorites.size(); ++i) {
+ if (previous_favorites[i].ends_with("/")) {
+ if (dirs_to_delete.find(previous_favorites[i]) < 0)
+ new_favorites.push_back(previous_favorites[i]);
+ } else {
+ if (files_to_delete.find(previous_favorites[i]) < 0)
+ new_favorites.push_back(previous_favorites[i]);
}
+ }
- EditorFileSystem::get_singleton()->scan_changes();
+ if (new_favorites.size() < previous_favorites.size()) {
+ EditorSettings::get_singleton()->set_favorites(new_favorites);
}
}
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index 3659a06bb7..f11a30bb86 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -269,7 +269,7 @@ void EditorFileDialog::_post_popup() {
set_process_unhandled_input(true);
}
-void EditorFileDialog::_thumbnail_result(const String &p_path, const Ref<Texture> &p_preview, const Variant &p_udata) {
+void EditorFileDialog::_thumbnail_result(const String &p_path, const Ref<Texture> &p_preview, const Ref<Texture> &p_small_preview, const Variant &p_udata) {
if (display_mode == DISPLAY_LIST || p_preview.is_null())
return;
@@ -284,7 +284,7 @@ void EditorFileDialog::_thumbnail_result(const String &p_path, const Ref<Texture
}
}
-void EditorFileDialog::_thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Variant &p_udata) {
+void EditorFileDialog::_thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Ref<Texture> &p_small_preview, const Variant &p_udata) {
set_process(false);
preview_waiting = false;
@@ -1115,7 +1115,7 @@ void EditorFileDialog::_update_drives() {
void EditorFileDialog::_favorite_selected(int p_idx) {
- Vector<String> favorited = EditorSettings::get_singleton()->get_favorite_dirs();
+ Vector<String> favorited = EditorSettings::get_singleton()->get_favorites();
ERR_FAIL_INDEX(p_idx, favorited.size());
dir_access->change_dir(favorited[p_idx]);
@@ -1130,7 +1130,7 @@ void EditorFileDialog::_favorite_move_up() {
int current = favorites->get_current();
if (current > 0 && current < favorites->get_item_count()) {
- Vector<String> favorited = EditorSettings::get_singleton()->get_favorite_dirs();
+ Vector<String> favorited = EditorSettings::get_singleton()->get_favorites();
int a_idx = favorited.find(String(favorites->get_item_metadata(current - 1)));
int b_idx = favorited.find(String(favorites->get_item_metadata(current)));
@@ -1139,7 +1139,7 @@ void EditorFileDialog::_favorite_move_up() {
return;
SWAP(favorited.write[a_idx], favorited.write[b_idx]);
- EditorSettings::get_singleton()->set_favorite_dirs(favorited);
+ EditorSettings::get_singleton()->set_favorites(favorited);
_update_favorites();
update_file_list();
@@ -1150,7 +1150,7 @@ void EditorFileDialog::_favorite_move_down() {
int current = favorites->get_current();
if (current >= 0 && current < favorites->get_item_count() - 1) {
- Vector<String> favorited = EditorSettings::get_singleton()->get_favorite_dirs();
+ Vector<String> favorited = EditorSettings::get_singleton()->get_favorites();
int a_idx = favorited.find(String(favorites->get_item_metadata(current + 1)));
int b_idx = favorited.find(String(favorites->get_item_metadata(current)));
@@ -1159,7 +1159,7 @@ void EditorFileDialog::_favorite_move_down() {
return;
SWAP(favorited.write[a_idx], favorited.write[b_idx]);
- EditorSettings::get_singleton()->set_favorite_dirs(favorited);
+ EditorSettings::get_singleton()->set_favorites(favorited);
_update_favorites();
update_file_list();
@@ -1176,7 +1176,7 @@ void EditorFileDialog::_update_favorites() {
favorite->set_pressed(false);
- Vector<String> favorited = EditorSettings::get_singleton()->get_favorite_dirs();
+ Vector<String> favorited = EditorSettings::get_singleton()->get_favorites();
for (int i = 0; i < favorited.size(); i++) {
bool cres = favorited[i].begins_with("res://");
if (cres != res)
@@ -1206,7 +1206,7 @@ void EditorFileDialog::_favorite_toggled(bool p_toggle) {
String cd = get_current_dir();
- Vector<String> favorited = EditorSettings::get_singleton()->get_favorite_dirs();
+ Vector<String> favorited = EditorSettings::get_singleton()->get_favorites();
bool found = false;
for (int i = 0; i < favorited.size(); i++) {
@@ -1228,7 +1228,7 @@ void EditorFileDialog::_favorite_toggled(bool p_toggle) {
favorite->set_pressed(true);
}
- EditorSettings::get_singleton()->set_favorite_dirs(favorited);
+ EditorSettings::get_singleton()->set_favorites(favorited);
_update_favorites();
}
diff --git a/editor/editor_file_dialog.h b/editor/editor_file_dialog.h
index 61eeff9162..56cefb9a47 100644
--- a/editor/editor_file_dialog.h
+++ b/editor/editor_file_dialog.h
@@ -190,8 +190,8 @@ private:
void _save_to_recent();
//callback function is callback(String p_path,Ref<Texture> preview,Variant udata) preview null if could not load
- void _thumbnail_result(const String &p_path, const Ref<Texture> &p_preview, const Variant &p_udata);
- void _thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Variant &p_udata);
+ void _thumbnail_result(const String &p_path, const Ref<Texture> &p_preview, const Ref<Texture> &p_small_preview, const Variant &p_udata);
+ void _thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Ref<Texture> &p_small_preview, const Variant &p_udata);
void _request_single_thumbnail(const String &p_path);
void _unhandled_input(const Ref<InputEvent> &p_event);
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 0ba1ef3b18..03746fb8b7 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -2039,6 +2039,14 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
emit_signal("stop_pressed");
} break;
+
+ case FILE_SHOW_IN_FILESYSTEM: {
+ String path = editor_data.get_scene_path(editor_data.get_edited_scene());
+ if (path != String()) {
+ filesystem_dock->navigate_to_path(path);
+ }
+ } break;
+
case RUN_PLAY_SCENE: {
_save_default_environment();
@@ -3357,19 +3365,12 @@ void EditorNode::_dock_select_input(const Ref<InputEvent> &p_input) {
dock_slot[nrect]->show();
dock_select->update();
- VSplitContainer *splits[DOCK_SLOT_MAX / 2] = {
- left_l_vsplit,
- left_r_vsplit,
- right_l_vsplit,
- right_r_vsplit,
- };
-
- for (int i = 0; i < 4; i++) {
+ for (int i = 0; i < vsplits.size(); i++) {
bool in_use = dock_slot[i * 2 + 0]->get_tab_count() || dock_slot[i * 2 + 1]->get_tab_count();
if (in_use)
- splits[i]->show();
+ vsplits[i]->show();
else
- splits[i]->hide();
+ vsplits[i]->hide();
}
if (right_l_vsplit->is_visible() || right_r_vsplit->is_visible())
@@ -3541,30 +3542,16 @@ void EditorNode::_save_docks_to_config(Ref<ConfigFile> p_layout, const String &p
p_layout->set_value(p_section, "dock_filesystem_split", filesystem_dock->get_split_offset());
- VSplitContainer *splits[DOCK_SLOT_MAX / 2] = {
- left_l_vsplit,
- left_r_vsplit,
- right_l_vsplit,
- right_r_vsplit,
- };
-
- for (int i = 0; i < DOCK_SLOT_MAX / 2; i++) {
+ for (int i = 0; i < vsplits.size(); i++) {
- if (splits[i]->is_visible_in_tree()) {
- p_layout->set_value(p_section, "dock_split_" + itos(i + 1), splits[i]->get_split_offset());
+ if (vsplits[i]->is_visible_in_tree()) {
+ p_layout->set_value(p_section, "dock_split_" + itos(i + 1), vsplits[i]->get_split_offset());
}
}
- HSplitContainer *h_splits[4] = {
- left_l_hsplit,
- left_r_hsplit,
- main_hsplit,
- right_hsplit,
- };
+ for (int i = 0; i < hsplits.size(); i++) {
- for (int i = 0; i < 4; i++) {
-
- p_layout->set_value(p_section, "dock_hsplit_" + itos(i + 1), h_splits[i]->get_split_offset());
+ p_layout->set_value(p_section, "dock_hsplit_" + itos(i + 1), hsplits[i]->get_split_offset());
}
}
@@ -3610,21 +3597,14 @@ void EditorNode::_load_docks() {
void EditorNode::_update_dock_slots_visibility() {
- VSplitContainer *splits[DOCK_SLOT_MAX / 2] = {
- left_l_vsplit,
- left_r_vsplit,
- right_l_vsplit,
- right_r_vsplit,
- };
-
if (!docks_visible) {
for (int i = 0; i < DOCK_SLOT_MAX; i++) {
dock_slot[i]->hide();
}
- for (int i = 0; i < DOCK_SLOT_MAX / 2; i++) {
- splits[i]->hide();
+ for (int i = 0; i < vsplits.size(); i++) {
+ vsplits[i]->hide();
}
right_hsplit->hide();
@@ -3638,12 +3618,12 @@ void EditorNode::_update_dock_slots_visibility() {
dock_slot[i]->hide();
}
- for (int i = 0; i < DOCK_SLOT_MAX / 2; i++) {
+ for (int i = 0; i < vsplits.size(); i++) {
bool in_use = dock_slot[i * 2 + 0]->get_tab_count() || dock_slot[i * 2 + 1]->get_tab_count();
if (in_use)
- splits[i]->show();
+ vsplits[i]->show();
else
- splits[i]->hide();
+ vsplits[i]->hide();
}
for (int i = 0; i < DOCK_SLOT_MAX; i++) {
@@ -3664,12 +3644,6 @@ void EditorNode::_update_dock_slots_visibility() {
void EditorNode::_dock_tab_changed(int p_tab) {
// update visibility but don't set current tab
- VSplitContainer *splits[DOCK_SLOT_MAX / 2] = {
- left_l_vsplit,
- left_r_vsplit,
- right_l_vsplit,
- right_r_vsplit,
- };
if (!docks_visible) {
@@ -3677,8 +3651,8 @@ void EditorNode::_dock_tab_changed(int p_tab) {
dock_slot[i]->hide();
}
- for (int i = 0; i < DOCK_SLOT_MAX / 2; i++) {
- splits[i]->hide();
+ for (int i = 0; i < vsplits.size(); i++) {
+ vsplits[i]->hide();
}
right_hsplit->hide();
@@ -3692,12 +3666,12 @@ void EditorNode::_dock_tab_changed(int p_tab) {
dock_slot[i]->hide();
}
- for (int i = 0; i < DOCK_SLOT_MAX / 2; i++) {
+ for (int i = 0; i < vsplits.size(); i++) {
bool in_use = dock_slot[i * 2 + 0]->get_tab_count() || dock_slot[i * 2 + 1]->get_tab_count();
if (in_use)
- splits[i]->show();
+ vsplits[i]->show();
else
- splits[i]->hide();
+ vsplits[i]->hide();
}
bottom_panel->show();
@@ -3756,42 +3730,28 @@ void EditorNode::_load_docks_from_config(Ref<ConfigFile> p_layout, const String
}
filesystem_dock->set_split_offset(fs_split_ofs);
- VSplitContainer *splits[DOCK_SLOT_MAX / 2] = {
- left_l_vsplit,
- left_r_vsplit,
- right_l_vsplit,
- right_r_vsplit,
- };
-
- for (int i = 0; i < DOCK_SLOT_MAX / 2; i++) {
+ for (int i = 0; i < vsplits.size(); i++) {
if (!p_layout->has_section_key(p_section, "dock_split_" + itos(i + 1)))
continue;
int ofs = p_layout->get_value(p_section, "dock_split_" + itos(i + 1));
- splits[i]->set_split_offset(ofs);
+ vsplits[i]->set_split_offset(ofs);
}
- HSplitContainer *h_splits[4] = {
- left_l_hsplit,
- left_r_hsplit,
- main_hsplit,
- right_hsplit,
- };
-
- for (int i = 0; i < 4; i++) {
+ for (int i = 0; i < hsplits.size(); i++) {
if (!p_layout->has_section_key(p_section, "dock_hsplit_" + itos(i + 1)))
continue;
int ofs = p_layout->get_value(p_section, "dock_hsplit_" + itos(i + 1));
- h_splits[i]->set_split_offset(ofs);
+ hsplits[i]->set_split_offset(ofs);
}
- for (int i = 0; i < DOCK_SLOT_MAX / 2; i++) {
+ for (int i = 0; i < vsplits.size(); i++) {
bool in_use = dock_slot[i * 2 + 0]->get_tab_count() || dock_slot[i * 2 + 1]->get_tab_count();
if (in_use)
- splits[i]->show();
+ vsplits[i]->show();
else
- splits[i]->hide();
+ vsplits[i]->hide();
}
if (right_l_vsplit->is_visible() || right_r_vsplit->is_visible())
@@ -3975,6 +3935,7 @@ void EditorNode::_scene_tab_input(const Ref<InputEvent> &p_input) {
scene_tabs_context_menu->add_shortcut(ED_GET_SHORTCUT("editor/save_all_scenes"), FILE_SAVE_ALL_SCENES);
if (scene_tabs->get_hovered_tab() >= 0) {
scene_tabs_context_menu->add_separator();
+ scene_tabs_context_menu->add_item(TTR("Show in filesystem"), FILE_SHOW_IN_FILESYSTEM);
scene_tabs_context_menu->add_item(TTR("Play This Scene"), RUN_PLAY_SCENE);
scene_tabs_context_menu->add_item(TTR("Close Tab"), FILE_CLOSE);
}
@@ -3989,7 +3950,7 @@ void EditorNode::_reposition_active_tab(int idx_to) {
_update_scene_tabs();
}
-void EditorNode::_thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Variant &p_udata) {
+void EditorNode::_thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Ref<Texture> &p_small_preview, const Variant &p_udata) {
int p_tab = p_udata.operator signed int();
if (p_preview.is_valid()) {
Rect2 rect = scene_tabs->get_tab_rect(p_tab);
@@ -4925,9 +4886,6 @@ EditorNode::EditorNode() {
left_l_vsplit->add_child(dock_slot[DOCK_SLOT_LEFT_UL]);
dock_slot[DOCK_SLOT_LEFT_BL] = memnew(TabContainer);
left_l_vsplit->add_child(dock_slot[DOCK_SLOT_LEFT_BL]);
- left_l_vsplit->hide();
- dock_slot[DOCK_SLOT_LEFT_UL]->hide();
- dock_slot[DOCK_SLOT_LEFT_BL]->hide();
left_r_hsplit = memnew(HSplitContainer);
left_l_hsplit->add_child(left_r_hsplit);
@@ -4965,19 +4923,22 @@ EditorNode::EditorNode() {
right_r_vsplit->add_child(dock_slot[DOCK_SLOT_RIGHT_UR]);
dock_slot[DOCK_SLOT_RIGHT_BR] = memnew(TabContainer);
right_r_vsplit->add_child(dock_slot[DOCK_SLOT_RIGHT_BR]);
- right_r_vsplit->hide();
- dock_slot[DOCK_SLOT_RIGHT_UR]->hide();
- dock_slot[DOCK_SLOT_RIGHT_BR]->hide();
- left_l_vsplit->connect("dragged", this, "_dock_split_dragged");
- left_r_vsplit->connect("dragged", this, "_dock_split_dragged");
- right_l_vsplit->connect("dragged", this, "_dock_split_dragged");
- right_r_vsplit->connect("dragged", this, "_dock_split_dragged");
+ // Store them for easier access
+ vsplits.push_back(left_l_vsplit);
+ vsplits.push_back(left_r_vsplit);
+ vsplits.push_back(right_l_vsplit);
+ vsplits.push_back(right_r_vsplit);
- left_l_hsplit->connect("dragged", this, "_dock_split_dragged");
- left_r_hsplit->connect("dragged", this, "_dock_split_dragged");
- main_hsplit->connect("dragged", this, "_dock_split_dragged");
- right_hsplit->connect("dragged", this, "_dock_split_dragged");
+ hsplits.push_back(left_l_hsplit);
+ hsplits.push_back(left_r_hsplit);
+ hsplits.push_back(main_hsplit);
+ hsplits.push_back(right_hsplit);
+
+ for (int i = 0; i < vsplits.size(); i++) {
+ vsplits[i]->connect("dragged", this, "_dock_split_dragged");
+ hsplits[i]->connect("dragged", this, "_dock_split_dragged");
+ }
dock_select_popup = memnew(PopupPanel);
gui_base->add_child(dock_select_popup);
@@ -5487,63 +5448,72 @@ EditorNode::EditorNode() {
_menu_option(SETTINGS_UPDATE_SPINNER_HIDE);
}
- scene_tree_dock = memnew(SceneTreeDock(this, scene_root, editor_selection, editor_data));
- dock_slot[DOCK_SLOT_RIGHT_UL]->add_child(scene_tree_dock);
- dock_slot[DOCK_SLOT_RIGHT_UL]->set_tab_title(scene_tree_dock->get_index(), TTR("Scene"));
- dock_slot[DOCK_SLOT_LEFT_BR]->hide();
+ // Instantiate and place editor docks
+ scene_tree_dock = memnew(SceneTreeDock(this, scene_root, editor_selection, editor_data));
inspector_dock = memnew(InspectorDock(this, editor_data));
- dock_slot[DOCK_SLOT_RIGHT_BL]->add_child(inspector_dock);
- dock_slot[DOCK_SLOT_RIGHT_BL]->set_tab_title(inspector_dock->get_index(), TTR("Inspector"));
-
- Button *property_editable_warning;
-
import_dock = memnew(ImportDock);
- dock_slot[DOCK_SLOT_RIGHT_UL]->add_child(import_dock);
- dock_slot[DOCK_SLOT_RIGHT_UL]->set_tab_title(import_dock->get_index(), TTR("Import"));
-
- bool use_single_dock_column = (OS::get_singleton()->get_screen_size(OS::get_singleton()->get_current_screen()).x < 1200);
-
node_dock = memnew(NodeDock);
- if (use_single_dock_column) {
- dock_slot[DOCK_SLOT_RIGHT_UL]->add_child(node_dock);
- dock_slot[DOCK_SLOT_RIGHT_UL]->set_tab_title(node_dock->get_index(), TTR("Node"));
- } else {
- dock_slot[DOCK_SLOT_RIGHT_BL]->add_child(node_dock);
- dock_slot[DOCK_SLOT_RIGHT_BL]->set_tab_title(node_dock->get_index(), TTR("Node"));
- }
filesystem_dock = memnew(FileSystemDock(this));
- filesystem_dock->set_file_list_display_mode(int(EditorSettings::get_singleton()->get("docks/filesystem/display_mode")));
-
- if (use_single_dock_column) {
- dock_slot[DOCK_SLOT_RIGHT_BL]->add_child(filesystem_dock);
- dock_slot[DOCK_SLOT_RIGHT_BL]->set_tab_title(filesystem_dock->get_index(), TTR("FileSystem"));
- left_r_vsplit->hide();
- dock_slot[DOCK_SLOT_LEFT_UR]->hide();
- dock_slot[DOCK_SLOT_LEFT_BR]->hide();
- } else {
- dock_slot[DOCK_SLOT_LEFT_UR]->add_child(filesystem_dock);
- dock_slot[DOCK_SLOT_LEFT_UR]->set_tab_title(filesystem_dock->get_index(), TTR("FileSystem"));
- }
+ filesystem_dock->set_file_list_display_mode(int(EditorSettings::get_singleton()->get("docks/filesystem/files_display_mode")));
filesystem_dock->connect("open", this, "open_request");
filesystem_dock->connect("instance", this, "_instance_request");
- const String docks_section = "docks";
+ // Scene: Top left
+ dock_slot[DOCK_SLOT_LEFT_UR]->add_child(scene_tree_dock);
+ dock_slot[DOCK_SLOT_LEFT_UR]->set_tab_title(scene_tree_dock->get_index(), TTR("Scene"));
+
+ // Import: Top left, behind Scene
+ dock_slot[DOCK_SLOT_LEFT_UR]->add_child(import_dock);
+ dock_slot[DOCK_SLOT_LEFT_UR]->set_tab_title(import_dock->get_index(), TTR("Import"));
+
+ // FileSystem: Bottom left
+ dock_slot[DOCK_SLOT_LEFT_BR]->add_child(filesystem_dock);
+ dock_slot[DOCK_SLOT_LEFT_BR]->set_tab_title(filesystem_dock->get_index(), TTR("FileSystem"));
+
+ // Inspector: Full height right
+ dock_slot[DOCK_SLOT_RIGHT_UL]->add_child(inspector_dock);
+ dock_slot[DOCK_SLOT_RIGHT_UL]->set_tab_title(inspector_dock->get_index(), TTR("Inspector"));
+
+ // Node: Full height right, behind Inspector
+ dock_slot[DOCK_SLOT_RIGHT_UL]->add_child(node_dock);
+ dock_slot[DOCK_SLOT_RIGHT_UL]->set_tab_title(node_dock->get_index(), TTR("Node"));
+
+ // Hide unused dock slots and vsplits
+ dock_slot[DOCK_SLOT_LEFT_UL]->hide();
+ dock_slot[DOCK_SLOT_LEFT_BL]->hide();
+ dock_slot[DOCK_SLOT_RIGHT_BL]->hide();
+ dock_slot[DOCK_SLOT_RIGHT_UR]->hide();
+ dock_slot[DOCK_SLOT_RIGHT_BR]->hide();
+ left_l_vsplit->hide();
+ right_r_vsplit->hide();
+
+ // Add some offsets to left_r and main hsplits to make LEFT_R and RIGHT_L docks wider than minsize
+ left_r_hsplit->set_split_offset(40 * EDSCALE);
+ main_hsplit->set_split_offset(-40 * EDSCALE);
+ // Define corresponding default layout
+
+ const String docks_section = "docks";
overridden_default_layout = -1;
default_layout.instance();
- default_layout->set_value(docks_section, "dock_3", "FileSystem");
- default_layout->set_value(docks_section, "dock_5", "Scene,Import");
- default_layout->set_value(docks_section, "dock_6", "Inspector,Node");
+ // Dock numbers are based on DockSlot enum value + 1
+ default_layout->set_value(docks_section, "dock_3", "Scene,Import");
+ default_layout->set_value(docks_section, "dock_4", "FileSystem");
+ default_layout->set_value(docks_section, "dock_5", "Inspector,Node");
- for (int i = 0; i < DOCK_SLOT_MAX / 2; i++)
- default_layout->set_value(docks_section, "dock_hsplit_" + itos(i + 1), 0);
- for (int i = 0; i < DOCK_SLOT_MAX / 2; i++)
+ for (int i = 0; i < vsplits.size(); i++)
default_layout->set_value(docks_section, "dock_split_" + itos(i + 1), 0);
+ default_layout->set_value(docks_section, "dock_hsplit_1", 0);
+ default_layout->set_value(docks_section, "dock_hsplit_2", 40 * EDSCALE);
+ default_layout->set_value(docks_section, "dock_hsplit_3", -40 * EDSCALE);
+ default_layout->set_value(docks_section, "dock_hsplit_4", 0);
_update_layouts_menu();
+ // Bottom panels
+
bottom_panel = memnew(PanelContainer);
bottom_panel->add_style_override("panel", gui_base->get_stylebox("panel", "TabContainer"));
center_split->add_child(bottom_panel);
@@ -5928,17 +5898,31 @@ bool EditorPluginList::forward_spatial_gui_input(Camera *p_camera, const Ref<Inp
return discard;
}
-void EditorPluginList::forward_draw_over_viewport(Control *p_overlay) {
+void EditorPluginList::forward_canvas_draw_over_viewport(Control *p_overlay) {
+
+ for (int i = 0; i < plugins_list.size(); i++) {
+ plugins_list[i]->forward_canvas_draw_over_viewport(p_overlay);
+ }
+}
+
+void EditorPluginList::forward_canvas_force_draw_over_viewport(Control *p_overlay) {
+
+ for (int i = 0; i < plugins_list.size(); i++) {
+ plugins_list[i]->forward_canvas_force_draw_over_viewport(p_overlay);
+ }
+}
+
+void EditorPluginList::forward_spatial_draw_over_viewport(Control *p_overlay) {
for (int i = 0; i < plugins_list.size(); i++) {
- plugins_list[i]->forward_draw_over_viewport(p_overlay);
+ plugins_list[i]->forward_spatial_draw_over_viewport(p_overlay);
}
}
-void EditorPluginList::forward_force_draw_over_viewport(Control *p_overlay) {
+void EditorPluginList::forward_spatial_force_draw_over_viewport(Control *p_overlay) {
for (int i = 0; i < plugins_list.size(); i++) {
- plugins_list[i]->forward_force_draw_over_viewport(p_overlay);
+ plugins_list[i]->forward_spatial_force_draw_over_viewport(p_overlay);
}
}
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 7409c64a64..bdbe0a245b 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -125,6 +125,7 @@ private:
FILE_SAVE_ALL_SCENES,
FILE_SAVE_BEFORE_RUN,
FILE_SAVE_AND_RUN,
+ FILE_SHOW_IN_FILESYSTEM,
FILE_IMPORT_SUBSCENE,
FILE_EXPORT_PROJECT,
FILE_EXPORT_MESH_LIBRARY,
@@ -208,7 +209,7 @@ private:
String video_driver_request;
void _video_driver_selected(int);
- //split
+ // Split containers
HSplitContainer *left_l_hsplit;
VSplitContainer *left_l_vsplit;
@@ -221,7 +222,11 @@ private:
VSplitContainer *center_split;
- //main tabs
+ // To access those easily by index
+ Vector<VSplitContainer *> vsplits;
+ Vector<HSplitContainer *> hsplits;
+
+ // Main tabs
Tabs *scene_tabs;
PopupMenu *scene_tabs_context_menu;
@@ -535,7 +540,7 @@ private:
void _scene_tab_exit();
void _scene_tab_input(const Ref<InputEvent> &p_input);
void _reposition_active_tab(int idx_to);
- void _thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Variant &p_udata);
+ void _thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Ref<Texture> &p_small_preview, const Variant &p_udata);
void _scene_tab_script_edited(int p_tab);
Dictionary _get_main_scene_state();
@@ -812,9 +817,11 @@ public:
void make_visible(bool p_visible);
void edit(Object *p_object);
bool forward_gui_input(const Ref<InputEvent> &p_event);
+ void forward_canvas_draw_over_viewport(Control *p_overlay);
+ void forward_canvas_force_draw_over_viewport(Control *p_overlay);
bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event, bool serve_when_force_input_enabled);
- void forward_draw_over_viewport(Control *p_overlay);
- void forward_force_draw_over_viewport(Control *p_overlay);
+ void forward_spatial_draw_over_viewport(Control *p_overlay);
+ void forward_spatial_force_draw_over_viewport(Control *p_overlay);
void add_plugin(EditorPlugin *p_plugin);
void clear();
bool empty();
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index 1f2e73654c..1ad23963a9 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -503,17 +503,17 @@ bool EditorPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
return false;
}
-void EditorPlugin::forward_draw_over_viewport(Control *p_overlay) {
+void EditorPlugin::forward_canvas_draw_over_viewport(Control *p_overlay) {
- if (get_script_instance() && get_script_instance()->has_method("forward_draw_over_viewport")) {
- get_script_instance()->call("forward_draw_over_viewport", p_overlay);
+ if (get_script_instance() && get_script_instance()->has_method("forward_canvas_draw_over_viewport")) {
+ get_script_instance()->call("forward_canvas_draw_over_viewport", p_overlay);
}
}
-void EditorPlugin::forward_force_draw_over_viewport(Control *p_overlay) {
+void EditorPlugin::forward_canvas_force_draw_over_viewport(Control *p_overlay) {
- if (get_script_instance() && get_script_instance()->has_method("forward_force_draw_over_viewport")) {
- get_script_instance()->call("forward_force_draw_over_viewport", p_overlay);
+ if (get_script_instance() && get_script_instance()->has_method("forward_canvas_force_draw_over_viewport")) {
+ get_script_instance()->call("forward_canvas_force_draw_over_viewport", p_overlay);
}
}
@@ -545,6 +545,20 @@ bool EditorPlugin::forward_spatial_gui_input(Camera *p_camera, const Ref<InputEv
return false;
}
+
+void EditorPlugin::forward_spatial_draw_over_viewport(Control *p_overlay) {
+
+ if (get_script_instance() && get_script_instance()->has_method("forward_spatial_draw_over_viewport")) {
+ get_script_instance()->call("forward_spatial_draw_over_viewport", p_overlay);
+ }
+}
+
+void EditorPlugin::forward_spatial_force_draw_over_viewport(Control *p_overlay) {
+
+ if (get_script_instance() && get_script_instance()->has_method("forward_spatial_force_draw_over_viewport")) {
+ get_script_instance()->call("forward_spatial_force_draw_over_viewport", p_overlay);
+ }
+}
String EditorPlugin::get_name() const {
if (get_script_instance() && get_script_instance()->has_method("get_plugin_name")) {
@@ -769,8 +783,8 @@ void EditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_script_create_dialog"), &EditorPlugin::get_script_create_dialog);
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "forward_canvas_gui_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_force_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_canvas_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_canvas_force_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "forward_spatial_gui_input", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_plugin_name"));
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::OBJECT, "get_plugin_icon"));
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index 6c385abf9b..e03aeb5d30 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -174,9 +174,13 @@ public:
void notify_resource_saved(const Ref<Resource> &p_resource);
virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event);
- virtual void forward_draw_over_viewport(Control *p_overlay);
- virtual void forward_force_draw_over_viewport(Control *p_overlay);
+ virtual void forward_canvas_draw_over_viewport(Control *p_overlay);
+ virtual void forward_canvas_force_draw_over_viewport(Control *p_overlay);
+
virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event);
+ virtual void forward_spatial_draw_over_viewport(Control *p_overlay);
+ virtual void forward_spatial_force_draw_over_viewport(Control *p_overlay);
+
virtual String get_name() const;
virtual const Ref<Texture> get_icon() const;
virtual bool has_main_screen() const;
diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp
index edfee595ea..310c3b3a52 100644
--- a/editor/editor_resource_preview.cpp
+++ b/editor/editor_resource_preview.cpp
@@ -30,11 +30,14 @@
#include "editor_resource_preview.h"
+#include "core/method_bind_ext.gen.inc"
+
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/message_queue.h"
#include "core/os/file_access.h"
#include "core/project_settings.h"
+#include "editor_node.h"
#include "editor_scale.h"
#include "editor_settings.h"
@@ -46,32 +49,37 @@ bool EditorResourcePreviewGenerator::handles(const String &p_type) const {
ERR_EXPLAIN("EditorResourcePreviewGenerator::handles needs to be overridden");
ERR_FAIL_V(false);
}
-Ref<Texture> EditorResourcePreviewGenerator::generate(const RES &p_from) const {
+
+Ref<Texture> EditorResourcePreviewGenerator::generate(const RES &p_from, const Size2 p_size) const {
if (get_script_instance() && get_script_instance()->has_method("generate")) {
- return get_script_instance()->call("generate", p_from);
+ return get_script_instance()->call("generate", p_from, p_size);
}
ERR_EXPLAIN("EditorResourcePreviewGenerator::generate needs to be overridden");
ERR_FAIL_V(Ref<Texture>());
}
-Ref<Texture> EditorResourcePreviewGenerator::generate_from_path(const String &p_path) const {
+Ref<Texture> EditorResourcePreviewGenerator::generate_from_path(const String &p_path, const Size2 p_size) const {
if (get_script_instance() && get_script_instance()->has_method("generate_from_path")) {
- return get_script_instance()->call("generate_from_path", p_path);
+ return get_script_instance()->call("generate_from_path", p_path, p_size);
}
RES res = ResourceLoader::load(p_path);
if (!res.is_valid())
return res;
- return generate(res);
+ return generate(res, p_size);
+}
+
+bool EditorResourcePreviewGenerator::should_generate_small_preview() const {
+ return false;
}
void EditorResourcePreviewGenerator::_bind_methods() {
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "handles", PropertyInfo(Variant::STRING, "type")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(CLASS_INFO(Texture), "generate", PropertyInfo(Variant::OBJECT, "from", PROPERTY_HINT_RESOURCE_TYPE, "Resource")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(CLASS_INFO(Texture), "generate_from_path", PropertyInfo(Variant::STRING, "path", PROPERTY_HINT_FILE)));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo(CLASS_INFO(Texture), "generate", PropertyInfo(Variant::OBJECT, "from", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), PropertyInfo(Variant::VECTOR2, "size")));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo(CLASS_INFO(Texture), "generate_from_path", PropertyInfo(Variant::STRING, "path", PROPERTY_HINT_FILE), PropertyInfo(Variant::VECTOR2, "size")));
}
EditorResourcePreviewGenerator::EditorResourcePreviewGenerator() {
@@ -85,7 +93,7 @@ void EditorResourcePreview::_thread_func(void *ud) {
erp->_thread();
}
-void EditorResourcePreview::_preview_ready(const String &p_str, const Ref<Texture> &p_texture, ObjectID id, const StringName &p_func, const Variant &p_ud) {
+void EditorResourcePreview::_preview_ready(const String &p_str, const Ref<Texture> &p_texture, const Ref<Texture> &p_small_texture, ObjectID id, const StringName &p_func, const Variant &p_ud) {
preview_mutex->lock();
@@ -103,6 +111,7 @@ void EditorResourcePreview::_preview_ready(const String &p_str, const Ref<Textur
Item item;
item.order = order++;
item.preview = p_texture;
+ item.small_preview = p_small_texture;
item.last_hash = hash;
item.modified_time = modified_time;
@@ -110,11 +119,10 @@ void EditorResourcePreview::_preview_ready(const String &p_str, const Ref<Textur
preview_mutex->unlock();
- MessageQueue::get_singleton()->push_call(id, p_func, path, p_texture, p_ud);
+ MessageQueue::get_singleton()->push_call(id, p_func, path, p_texture, p_small_texture, p_ud);
}
-Ref<Texture> EditorResourcePreview::_generate_preview(const QueueItem &p_item, const String &cache_base) {
-
+void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref<ImageTexture> &r_small_texture, const QueueItem &p_item, const String &cache_base) {
String type;
if (p_item.resource.is_valid())
@@ -122,40 +130,59 @@ Ref<Texture> EditorResourcePreview::_generate_preview(const QueueItem &p_item, c
else
type = ResourceLoader::get_resource_type(p_item.path);
- if (type == "")
- return Ref<Texture>(); //could not guess type
+ if (type == "") {
+ r_texture = Ref<ImageTexture>();
+ r_small_texture = Ref<ImageTexture>();
+ return; //could not guess type
+ }
- Ref<Texture> generated;
+ int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
+ thumbnail_size *= EDSCALE;
- for (int i = 0; i < preview_generators.size(); i++) {
+ r_texture = Ref<ImageTexture>();
+ r_small_texture = Ref<ImageTexture>();
+ for (int i = 0; i < preview_generators.size(); i++) {
if (!preview_generators[i]->handles(type))
continue;
+
+ Ref<Texture> generated;
if (p_item.resource.is_valid()) {
- generated = preview_generators[i]->generate(p_item.resource);
+ generated = preview_generators[i]->generate(p_item.resource, Vector2(thumbnail_size, thumbnail_size));
} else {
- generated = preview_generators[i]->generate_from_path(p_item.path);
+ generated = preview_generators[i]->generate_from_path(p_item.path, Vector2(thumbnail_size, thumbnail_size));
}
+ r_texture = generated;
+ if (r_texture.is_valid() && preview_generators[i]->should_generate_small_preview()) {
+ int small_thumbnail_size = EditorNode::get_singleton()->get_theme_base()->get_icon("Object", "EditorIcons")->get_width(); // Kind of a workaround to retreive the default icon size
+ small_thumbnail_size *= EDSCALE;
+
+ Ref<Image> small_image = r_texture->get_data();
+ small_image->resize(small_thumbnail_size, small_thumbnail_size, Image::INTERPOLATE_CUBIC);
+ r_small_texture.instance();
+ r_small_texture->create_from_image(small_image);
+ }
break;
}
if (!p_item.resource.is_valid()) {
// cache the preview in case it's a resource on disk
- if (generated.is_valid()) {
- int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
- thumbnail_size *= EDSCALE;
+ if (r_texture.is_valid()) {
//wow it generated a preview... save cache
- ResourceSaver::save(cache_base + ".png", generated);
+ bool has_small_texture = r_small_texture.is_valid();
+ ResourceSaver::save(cache_base + ".png", r_texture);
+ if (has_small_texture) {
+ ResourceSaver::save(cache_base + "_small.png", r_small_texture);
+ }
FileAccess *f = FileAccess::open(cache_base + ".txt", FileAccess::WRITE);
f->store_line(itos(thumbnail_size));
+ f->store_line(itos(has_small_texture));
f->store_line(itos(FileAccess::get_modified_time(p_item.path)));
f->store_line(FileAccess::get_md5(p_item.path));
memdelete(f);
}
}
-
- return generated;
}
void EditorResourcePreview::_thread() {
@@ -177,7 +204,7 @@ void EditorResourcePreview::_thread() {
path += ":" + itos(cache[item.path].last_hash); //keep last hash (see description of what this is in condition below)
}
- _preview_ready(path, cache[item.path].preview, item.id, item.function, item.userdata);
+ _preview_ready(path, cache[item.path].preview, cache[item.path].small_preview, item.id, item.function, item.userdata);
preview_mutex->unlock();
} else {
@@ -185,15 +212,17 @@ void EditorResourcePreview::_thread() {
preview_mutex->unlock();
Ref<ImageTexture> texture;
+ Ref<ImageTexture> small_texture;
int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
thumbnail_size *= EDSCALE;
if (item.resource.is_valid()) {
- texture = _generate_preview(item, String());
+ _generate_preview(texture, small_texture, item, String());
+
//adding hash to the end of path (should be ID:<objid>:<hash>) because of 5 argument limit to call_deferred
- _preview_ready(item.path + ":" + itos(item.resource->hash_edited_version()), texture, item.id, item.function, item.userdata);
+ _preview_ready(item.path + ":" + itos(item.resource->hash_edited_version()), texture, small_texture, item.id, item.function, item.userdata);
} else {
@@ -207,12 +236,13 @@ void EditorResourcePreview::_thread() {
FileAccess *f = FileAccess::open(file, FileAccess::READ);
if (!f) {
- //generate
- texture = _generate_preview(item, cache_base);
+ // No cache found, generate
+ _generate_preview(texture, small_texture, item, cache_base);
} else {
uint64_t modtime = FileAccess::get_modified_time(item.path);
int tsize = f->get_line().to_int64();
+ bool has_small_texture = f->get_line().to_int();
uint64_t last_modtime = f->get_line().to_int64();
bool cache_valid = true;
@@ -236,6 +266,7 @@ void EditorResourcePreview::_thread() {
f = FileAccess::open(file, FileAccess::WRITE);
f->store_line(itos(modtime));
+ f->store_line(itos(has_small_texture));
f->store_line(md5);
memdelete(f);
}
@@ -243,12 +274,12 @@ void EditorResourcePreview::_thread() {
memdelete(f);
}
- //cache_valid = false;
-
if (cache_valid) {
Ref<Image> img;
img.instance();
+ Ref<Image> small_img;
+ small_img.instance();
if (img->load(cache_base + ".png") != OK) {
cache_valid = false;
@@ -256,16 +287,24 @@ void EditorResourcePreview::_thread() {
texture.instance();
texture->create_from_image(img, Texture::FLAG_FILTER);
+
+ if (has_small_texture) {
+ if (small_img->load(cache_base + "_small.png") != OK) {
+ cache_valid = false;
+ } else {
+ small_texture.instance();
+ small_texture->create_from_image(small_img, Texture::FLAG_FILTER);
+ }
+ }
}
}
if (!cache_valid) {
- texture = _generate_preview(item, cache_base);
+ _generate_preview(texture, small_texture, item, cache_base);
}
}
-
- _preview_ready(item.path, texture, item.id, item.function, item.userdata);
+ _preview_ready(item.path, texture, small_texture, item.id, item.function, item.userdata);
}
}
@@ -287,7 +326,7 @@ void EditorResourcePreview::queue_edited_resource_preview(const Ref<Resource> &p
if (cache.has(path_id) && cache[path_id].last_hash == p_res->hash_edited_version()) {
cache[path_id].order = order++;
- p_receiver->call_deferred(p_receiver_func, path_id, cache[path_id].preview, p_userdata);
+ p_receiver->call_deferred(p_receiver_func, path_id, cache[path_id].preview, cache[path_id].small_preview, p_userdata);
preview_mutex->unlock();
return;
}
@@ -312,7 +351,7 @@ void EditorResourcePreview::queue_resource_preview(const String &p_path, Object
preview_mutex->lock();
if (cache.has(p_path)) {
cache[p_path].order = order++;
- p_receiver->call_deferred(p_receiver_func, p_path, cache[p_path].preview, p_userdata);
+ p_receiver->call_deferred(p_receiver_func, p_path, cache[p_path].preview, cache[p_path].small_preview, p_userdata);
preview_mutex->unlock();
return;
}
diff --git a/editor/editor_resource_preview.h b/editor/editor_resource_preview.h
index 434b26e901..a3417cdf60 100644
--- a/editor/editor_resource_preview.h
+++ b/editor/editor_resource_preview.h
@@ -63,8 +63,10 @@ protected:
public:
virtual bool handles(const String &p_type) const;
- virtual Ref<Texture> generate(const RES &p_from) const;
- virtual Ref<Texture> generate_from_path(const String &p_path) const;
+ virtual Ref<Texture> generate(const RES &p_from, const Size2 p_size) const;
+ virtual Ref<Texture> generate_from_path(const String &p_path, const Size2 p_size) const;
+
+ virtual bool should_generate_small_preview() const;
EditorResourcePreviewGenerator();
};
@@ -92,6 +94,7 @@ class EditorResourcePreview : public Node {
struct Item {
Ref<Texture> preview;
+ Ref<Texture> small_preview;
int order;
uint32_t last_hash;
uint64_t modified_time;
@@ -101,8 +104,8 @@ class EditorResourcePreview : public Node {
Map<String, Item> cache;
- void _preview_ready(const String &p_str, const Ref<Texture> &p_texture, ObjectID id, const StringName &p_func, const Variant &p_ud);
- Ref<Texture> _generate_preview(const QueueItem &p_item, const String &cache_base);
+ void _preview_ready(const String &p_str, const Ref<Texture> &p_texture, const Ref<Texture> &p_small_texture, ObjectID id, const StringName &p_func, const Variant &p_ud);
+ void _generate_preview(Ref<ImageTexture> &r_texture, Ref<ImageTexture> &r_small_texture, const QueueItem &p_item, const String &cache_base);
static void _thread_func(void *ud);
void _thread();
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 3e959731fc..3f49edf88d 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -511,17 +511,16 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("filesystem/file_dialog/show_hidden_files", false);
_initial_set("filesystem/file_dialog/display_mode", 0);
hints["filesystem/file_dialog/display_mode"] = PropertyInfo(Variant::INT, "filesystem/file_dialog/display_mode", PROPERTY_HINT_ENUM, "Thumbnails,List");
+
_initial_set("filesystem/file_dialog/thumbnail_size", 64);
hints["filesystem/file_dialog/thumbnail_size"] = PropertyInfo(Variant::INT, "filesystem/file_dialog/thumbnail_size", PROPERTY_HINT_RANGE, "32,128,16");
- _initial_set("docks/filesystem/disable_split", false);
- _initial_set("docks/filesystem/split_mode_minimum_height", 600);
_initial_set("docks/filesystem/display_mode", 0);
- hints["docks/filesystem/display_mode"] = PropertyInfo(Variant::INT, "docks/filesystem/display_mode", PROPERTY_HINT_ENUM, "Thumbnails,List");
+ hints["docks/filesystem/display_mode"] = PropertyInfo(Variant::INT, "docks/filesystem/display_mode", PROPERTY_HINT_ENUM, "Tree only, Split");
_initial_set("docks/filesystem/thumbnail_size", 64);
hints["docks/filesystem/thumbnail_size"] = PropertyInfo(Variant::INT, "docks/filesystem/thumbnail_size", PROPERTY_HINT_RANGE, "32,128,16");
- _initial_set("docks/filesystem/display_mode", 0);
- hints["docks/filesystem/display_mode"] = PropertyInfo(Variant::INT, "docks/filesystem/display_mode", PROPERTY_HINT_ENUM, "Thumbnails,List");
+ _initial_set("docks/filesystem/files_display_mode", 0);
+ hints["docks/filesystem/files_display_mode"] = PropertyInfo(Variant::INT, "docks/filesystem/files_display_mode", PROPERTY_HINT_ENUM, "Thumbnails,List");
_initial_set("docks/filesystem/always_show_folders", true);
_initial_set("editors/animation/autorename_animation_tracks", true);
@@ -1152,20 +1151,20 @@ Variant EditorSettings::get_project_metadata(const String &p_section, const Stri
return cf->get_value(p_section, p_key, p_default);
}
-void EditorSettings::set_favorite_dirs(const Vector<String> &p_favorites_dirs) {
+void EditorSettings::set_favorites(const Vector<String> &p_favorites) {
- favorite_dirs = p_favorites_dirs;
- FileAccess *f = FileAccess::open(get_project_settings_dir().plus_file("favorite_dirs"), FileAccess::WRITE);
+ favorites = p_favorites;
+ FileAccess *f = FileAccess::open(get_project_settings_dir().plus_file("favorites"), FileAccess::WRITE);
if (f) {
- for (int i = 0; i < favorite_dirs.size(); i++)
- f->store_line(favorite_dirs[i]);
+ for (int i = 0; i < favorites.size(); i++)
+ f->store_line(favorites[i]);
memdelete(f);
}
}
-Vector<String> EditorSettings::get_favorite_dirs() const {
+Vector<String> EditorSettings::get_favorites() const {
- return favorite_dirs;
+ return favorites;
}
void EditorSettings::set_recent_dirs(const Vector<String> &p_recent_dirs) {
@@ -1186,11 +1185,11 @@ Vector<String> EditorSettings::get_recent_dirs() const {
void EditorSettings::load_favorites() {
- FileAccess *f = FileAccess::open(get_project_settings_dir().plus_file("favorite_dirs"), FileAccess::READ);
+ FileAccess *f = FileAccess::open(get_project_settings_dir().plus_file("favorites"), FileAccess::READ);
if (f) {
String line = f->get_line().strip_edges();
while (line != "") {
- favorite_dirs.push_back(line);
+ favorites.push_back(line);
line = f->get_line().strip_edges();
}
memdelete(f);
@@ -1471,8 +1470,8 @@ void EditorSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_project_metadata", "section", "key", "data"), &EditorSettings::set_project_metadata);
ClassDB::bind_method(D_METHOD("get_project_metadata", "section", "key", "default"), &EditorSettings::get_project_metadata, DEFVAL(Variant()));
- ClassDB::bind_method(D_METHOD("set_favorite_dirs", "dirs"), &EditorSettings::set_favorite_dirs);
- ClassDB::bind_method(D_METHOD("get_favorite_dirs"), &EditorSettings::get_favorite_dirs);
+ ClassDB::bind_method(D_METHOD("set_favorites", "dirs"), &EditorSettings::set_favorites);
+ ClassDB::bind_method(D_METHOD("get_favorites"), &EditorSettings::get_favorites);
ClassDB::bind_method(D_METHOD("set_recent_dirs", "dirs"), &EditorSettings::set_recent_dirs);
ClassDB::bind_method(D_METHOD("get_recent_dirs"), &EditorSettings::get_recent_dirs);
diff --git a/editor/editor_settings.h b/editor/editor_settings.h
index 8165c36e67..7b0de9617c 100644
--- a/editor/editor_settings.h
+++ b/editor/editor_settings.h
@@ -107,7 +107,7 @@ private:
String config_file_path;
String project_config_dir;
- Vector<String> favorite_dirs;
+ Vector<String> favorites;
Vector<String> recent_dirs;
bool save_changed_setting;
@@ -173,8 +173,8 @@ public:
void set_project_metadata(const String &p_section, const String &p_key, Variant p_data);
Variant get_project_metadata(const String &p_section, const String &p_key, Variant p_default) const;
- void set_favorite_dirs(const Vector<String> &p_favorites_dirs);
- Vector<String> get_favorite_dirs() const;
+ void set_favorites(const Vector<String> &p_favorites);
+ Vector<String> get_favorites() const;
void set_recent_dirs(const Vector<String> &p_recent_dirs);
Vector<String> get_recent_dirs() const;
void load_favorites();
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 3a55966e7b..46f89439c0 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -40,27 +40,38 @@
#include "editor_settings.h"
#include "scene/main/viewport.h"
+Ref<Texture> FileSystemDock::_get_tree_item_icon(EditorFileSystemDirectory *p_dir, int p_idx) {
+ Ref<Texture> file_icon;
+ if (!p_dir->get_file_import_is_valid(p_idx)) {
+ file_icon = get_icon("ImportFail", "EditorIcons");
+ } else {
+ String file_type = p_dir->get_file_type(p_idx);
+ file_icon = (has_icon(file_type, "EditorIcons")) ? get_icon(file_type, "EditorIcons") : get_icon("File", "EditorIcons");
+ }
+ return file_icon;
+}
+
bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector<String> &uncollapsed_paths) {
- TreeItem *item = tree->create_item(p_parent);
+ bool parent_should_expand = false;
+
+ // Create a tree item for the subdirectory
+ TreeItem *subdirectory_item = tree->create_item(p_parent);
String dname = p_dir->get_name();
if (dname == "")
dname = "res://";
- item->set_text(0, dname);
- item->set_icon(0, get_icon("Folder", "EditorIcons"));
- item->set_selectable(0, true);
+ subdirectory_item->set_text(0, dname);
+ subdirectory_item->set_icon(0, get_icon("Folder", "EditorIcons"));
+ subdirectory_item->set_selectable(0, true);
String lpath = p_dir->get_path();
- if (lpath != "res://" && lpath.ends_with("/")) {
- lpath = lpath.substr(0, lpath.length() - 1);
- }
- item->set_metadata(0, lpath);
- if (lpath == path) {
- item->select(0);
+ subdirectory_item->set_metadata(0, lpath);
+ if (path == lpath || ((display_mode_setting == DISPLAY_MODE_SETTING_SPLIT) && path.get_base_dir() == lpath)) {
+ subdirectory_item->select(0);
}
if ((path.begins_with(lpath) && path != lpath)) {
- item->set_collapsed(false);
+ subdirectory_item->set_collapsed(false);
} else {
bool is_collapsed = true;
for (int i = 0; i < uncollapsed_paths.size(); i++) {
@@ -69,23 +80,65 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
break;
}
}
- item->set_collapsed(is_collapsed);
+ subdirectory_item->set_collapsed(is_collapsed);
+ }
+ if (searched_string.length() > 0 && dname.to_lower().find(searched_string) >= 0) {
+ parent_should_expand = true;
}
+ // Create items for all subdirectories
for (int i = 0; i < p_dir->get_subdir_count(); i++)
- _create_tree(item, p_dir->get_subdir(i), uncollapsed_paths);
+ parent_should_expand = (_create_tree(subdirectory_item, p_dir->get_subdir(i), uncollapsed_paths) || parent_should_expand);
- return true;
-}
+ // Create all items for the files in the subdirectory
+ if (display_mode_setting == DISPLAY_MODE_SETTING_TREE_ONLY) {
+ for (int i = 0; i < p_dir->get_file_count(); i++) {
+ String file_name = p_dir->get_file(i);
+
+ if (searched_string.length() > 0) {
+ if (file_name.to_lower().find(searched_string) < 0) {
+ // The seached string is not in the file name, we skip it
+ continue;
+ } else {
+ // We expand all parents
+ parent_should_expand = true;
+ }
+ }
-void FileSystemDock::_update_tree(bool keep_collapse_state, bool p_uncollapse_root) {
+ TreeItem *file_item = tree->create_item(subdirectory_item);
+ file_item->set_text(0, file_name);
+ file_item->set_icon(0, _get_tree_item_icon(p_dir, i));
+ String file_metadata = lpath.plus_file(file_name);
+ file_item->set_metadata(0, file_metadata);
+ if (path == file_metadata) {
+ file_item->select(0);
+ file_item->set_as_cursor(0);
+ }
+ Array udata;
+ udata.push_back(tree_update_id);
+ udata.push_back(file_item);
+ EditorResourcePreview::get_singleton()->queue_resource_preview(file_metadata, this, "_tree_thumbnail_done", udata);
+ }
+ }
- Vector<String> uncollapsed_paths;
- if (keep_collapse_state) {
- TreeItem *root = tree->get_root();
- if (root) {
- TreeItem *resTree = root->get_children()->get_next();
+ if (searched_string.length() > 0) {
+ if (parent_should_expand) {
+ subdirectory_item->set_collapsed(false);
+ } else if (dname != "res://") {
+ subdirectory_item->get_parent()->remove_child(subdirectory_item);
+ }
+ }
+
+ return parent_should_expand;
+}
+Vector<String> FileSystemDock::_compute_uncollapsed_paths() {
+ // Register currently collapsed paths
+ Vector<String> uncollapsed_paths;
+ TreeItem *root = tree->get_root();
+ if (root) {
+ TreeItem *resTree = root->get_children()->get_next();
+ if (resTree) {
Vector<TreeItem *> needs_check;
needs_check.push_back(resTree);
@@ -102,84 +155,121 @@ void FileSystemDock::_update_tree(bool keep_collapse_state, bool p_uncollapse_ro
}
}
}
+ return uncollapsed_paths;
+}
+
+void FileSystemDock::_update_tree(const Vector<String> p_uncollapsed_paths, bool p_uncollapse_root) {
+ // Recreate the tree
tree->clear();
+ tree_update_id++;
updating_tree = true;
-
TreeItem *root = tree->create_item();
+
+ // Handles the favorites
TreeItem *favorites = tree->create_item(root);
favorites->set_icon(0, get_icon("Favorites", "EditorIcons"));
favorites->set_text(0, TTR("Favorites:"));
favorites->set_selectable(0, false);
- Vector<String> favorite_paths = EditorSettings::get_singleton()->get_favorite_dirs();
- String res_path = "res://";
- Ref<Texture> folder_icon = get_icon("Folder", "EditorIcons");
+ Vector<String> favorite_paths = EditorSettings::get_singleton()->get_favorites();
for (int i = 0; i < favorite_paths.size(); i++) {
String fave = favorite_paths[i];
- if (!fave.begins_with(res_path))
+ if (!fave.begins_with("res://"))
+ continue;
+ if (display_mode_setting == DISPLAY_MODE_SETTING_SPLIT && !fave.ends_with("/"))
continue;
- TreeItem *ti = tree->create_item(favorites);
- if (fave == res_path)
- ti->set_text(0, "/");
- else
- ti->set_text(0, fave.get_file());
- ti->set_icon(0, folder_icon);
- ti->set_selectable(0, true);
- ti->set_metadata(0, fave);
+ Ref<Texture> folder_icon = get_icon("Folder", "EditorIcons");
+
+ String text;
+ Ref<Texture> icon;
+ if (fave == "res://") {
+ text = "/";
+ icon = folder_icon;
+ } else if (fave.ends_with("/")) {
+ text = fave.substr(0, fave.length() - 1).get_file();
+ icon = folder_icon;
+ } else {
+ text = fave.get_file();
+ int index;
+ EditorFileSystemDirectory *dir = EditorFileSystem::get_singleton()->find_file(fave, &index);
+ if (dir) {
+ icon = _get_tree_item_icon(dir, index);
+ } else {
+ icon = get_icon("File", "EditorIcons");
+ }
+ }
+
+ if (searched_string.length() == 0 || text.to_lower().find(searched_string) >= 0) {
+ TreeItem *ti = tree->create_item(favorites);
+ ti->set_text(0, text);
+ ti->set_icon(0, icon);
+ ti->set_tooltip(0, fave);
+ ti->set_selectable(0, true);
+ ti->set_metadata(0, fave);
+ }
}
+ Vector<String> uncollapsed_paths = p_uncollapsed_paths;
if (p_uncollapse_root) {
uncollapsed_paths.push_back("res://");
}
+ // Create the remaining of the tree
_create_tree(root, EditorFileSystem::get_singleton()->get_filesystem(), uncollapsed_paths);
tree->ensure_cursor_is_visible();
updating_tree = false;
}
void FileSystemDock::_update_display_mode() {
-
- bool disable_split = bool(EditorSettings::get_singleton()->get("docks/filesystem/disable_split"));
- bool compact_mode = get_size().height < int(EditorSettings::get_singleton()->get("docks/filesystem/split_mode_minimum_height"));
- DisplayMode new_mode;
- if (disable_split || compact_mode) {
- new_mode = file_list_view ? DISPLAY_FILE_LIST_ONLY : DISPLAY_TREE_ONLY;
+ // Compute the new display mode
+ DisplayMode new_display_mode;
+ if (display_mode_setting == DISPLAY_MODE_SETTING_TREE_ONLY) {
+ new_display_mode = file_list_view ? DISPLAY_MODE_FILE_LIST_ONLY : DISPLAY_MODE_TREE_ONLY;
} else {
- new_mode = DISPLAY_SPLIT;
+ new_display_mode = DISPLAY_MODE_SPLIT;
}
- if (new_mode != display_mode) {
- switch (new_mode) {
- case DISPLAY_TREE_ONLY:
+ if (new_display_mode != display_mode || old_display_mode_setting != display_mode_setting) {
+ display_mode = new_display_mode;
+ old_display_mode_setting = display_mode_setting;
+ button_toggle_display_mode->set_pressed(display_mode_setting == DISPLAY_MODE_SETTING_SPLIT ? true : false);
+ switch (display_mode) {
+ case DISPLAY_MODE_TREE_ONLY:
tree->show();
tree->set_v_size_flags(SIZE_EXPAND_FILL);
- _update_tree(true);
+ if (display_mode_setting == DISPLAY_MODE_SETTING_TREE_ONLY) {
+ tree_search_box->show();
+ } else {
+ tree_search_box->hide();
+ }
+ _update_tree(_compute_uncollapsed_paths());
file_list_vb->hide();
break;
- case DISPLAY_FILE_LIST_ONLY:
+ case DISPLAY_MODE_FILE_LIST_ONLY:
tree->hide();
+ tree_search_box->hide();
button_tree->show();
file_list_vb->show();
_update_files(true);
break;
- case DISPLAY_SPLIT:
+ case DISPLAY_MODE_SPLIT:
tree->show();
tree->set_v_size_flags(SIZE_EXPAND_FILL);
button_tree->hide();
tree->ensure_cursor_is_visible();
- _update_tree(true);
+ tree_search_box->hide();
+ _update_tree(_compute_uncollapsed_paths());
file_list_vb->show();
_update_files(true);
break;
}
- display_mode = new_mode;
}
}
@@ -201,34 +291,36 @@ void FileSystemDock::_notification(int p_what) {
String ei = "EditorIcons";
button_reload->set_icon(get_icon("Reload", ei));
- button_favorite->set_icon(get_icon("Favorites", ei));
- //button_instance->set_icon(get_icon("Add", ei));
- //button_open->set_icon(get_icon("Folder", ei));
+ button_toggle_display_mode->set_icon(get_icon("Panels2", ei));
button_tree->set_icon(get_icon("Filesystem", ei));
_update_file_list_display_mode_button();
button_file_list_display_mode->connect("pressed", this, "_change_file_display");
- //file_options->set_icon( get_icon("Tools","ei"));
- files->connect("item_activated", this, "_select_file");
+
+ files->connect("item_activated", this, "_file_list_activate_file");
button_hist_next->connect("pressed", this, "_fw_history");
button_hist_prev->connect("pressed", this, "_bw_history");
- search_box->set_right_icon(get_icon("Search", ei));
- search_box->set_clear_button_enabled(true);
+ tree_search_box->set_right_icon(get_icon("Search", ei));
+ tree_search_box->set_clear_button_enabled(true);
+ file_list_search_box->set_right_icon(get_icon("Search", ei));
+ file_list_search_box->set_clear_button_enabled(true);
button_hist_next->set_icon(get_icon("Forward", ei));
button_hist_prev->set_icon(get_icon("Back", ei));
- button_show->set_icon(get_icon("GuiVisibilityVisible", "EditorIcons"));
- file_options->connect("id_pressed", this, "_file_option");
- folder_options->connect("id_pressed", this, "_folder_option");
+ file_list_popup->connect("id_pressed", this, "_file_list_rmb_option");
+ tree_popup->connect("id_pressed", this, "_tree_rmb_option");
button_tree->connect("pressed", this, "_go_to_tree", varray(), CONNECT_DEFERRED);
current_path->connect("text_entered", this, "navigate_to_path");
+ display_mode_setting = DisplayModeSetting(int(EditorSettings::get_singleton()->get("docks/filesystem/display_mode")));
+ always_show_folders = bool(EditorSettings::get_singleton()->get("docks/filesystem/always_show_folders"));
+
_update_display_mode();
if (EditorFileSystem::get_singleton()->is_scanning()) {
_set_scanning_mode();
} else {
- _update_tree(false, true);
+ _update_tree(Vector<String>(), true);
}
} break;
@@ -245,7 +337,7 @@ void FileSystemDock::_notification(int p_what) {
Dictionary dd = get_viewport()->gui_get_drag_data();
if (tree->is_visible_in_tree() && dd.has("type")) {
if ((String(dd["type"]) == "files") || (String(dd["type"]) == "files_and_dirs") || (String(dd["type"]) == "resource")) {
- tree->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM);
+ tree->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM | Tree::DROP_MODE_INBETWEEN);
} else if ((String(dd["type"]) == "favorite")) {
tree->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN);
}
@@ -261,20 +353,37 @@ void FileSystemDock::_notification(int p_what) {
// Update icons
String ei = "EditorIcons";
button_reload->set_icon(get_icon("Reload", ei));
- button_favorite->set_icon(get_icon("Favorites", ei));
+ button_toggle_display_mode->set_icon(get_icon("Panels2", ei));
button_tree->set_icon(get_icon("Filesystem", ei));
button_hist_next->set_icon(get_icon("Forward", ei));
button_hist_prev->set_icon(get_icon("Back", ei));
- search_box->set_right_icon(get_icon("Search", ei));
- search_box->set_clear_button_enabled(true);
+ tree_search_box->set_right_icon(get_icon("Search", ei));
+ tree_search_box->set_clear_button_enabled(true);
+ file_list_search_box->set_right_icon(get_icon("Search", ei));
+ file_list_search_box->set_clear_button_enabled(true);
+
+ bool should_update_files = false;
- // Change size mode
- int new_file_list_mode = int(EditorSettings::get_singleton()->get("docks/filesystem/display_mode"));
+ // Update file list display mode
+ int new_file_list_mode = int(EditorSettings::get_singleton()->get("docks/filesystem/files_display_mode"));
if (new_file_list_mode != file_list_display_mode) {
set_file_list_display_mode(new_file_list_mode);
- } else {
_update_file_list_display_mode_button();
+ should_update_files = true;
+ }
+
+ // Update display of files in tree
+ display_mode_setting = DisplayModeSetting(int(EditorSettings::get_singleton()->get("docks/filesystem/display_mode")));
+
+ // Update allways showfolders
+ bool new_always_show_folders = bool(EditorSettings::get_singleton()->get("docks/filesystem/always_show_folders"));
+ if (new_always_show_folders != always_show_folders) {
+ always_show_folders = new_always_show_folders;
+ should_update_files = true;
+ }
+
+ if (should_update_files) {
_update_files(true);
}
@@ -285,74 +394,33 @@ void FileSystemDock::_notification(int p_what) {
}
}
-void FileSystemDock::_dir_selected() {
+void FileSystemDock::_tree_multi_selected(Object *p_item, int p_column, bool p_selected) {
+ // Return if we don't select something new
+ if (!p_selected)
+ return;
+
+ // Tree item selected
TreeItem *sel = tree->get_selected();
if (!sel)
return;
path = sel->get_metadata(0);
- bool found = false;
- Vector<String> favorites = EditorSettings::get_singleton()->get_favorite_dirs();
- for (int i = 0; i < favorites.size(); i++) {
-
- if (favorites[i] == path) {
- found = true;
- break;
- }
- }
-
- button_favorite->set_pressed(found);
+ // Set the current path
current_path->set_text(path);
_push_to_history();
- if (display_mode == DISPLAY_SPLIT) {
+ // Update the file list
+ if (!updating_tree && display_mode == DISPLAY_MODE_SPLIT) {
_update_files(false);
}
}
-void FileSystemDock::_favorites_pressed() {
-
- TreeItem *sel = tree->get_selected();
- if (!sel)
- return;
- path = sel->get_metadata(0);
-
- int idx = -1;
- Vector<String> favorites = EditorSettings::get_singleton()->get_favorite_dirs();
- for (int i = 0; i < favorites.size(); i++) {
-
- if (favorites[i] == path) {
- idx = i;
- break;
- }
- }
-
- if (idx == -1) {
- favorites.push_back(path);
- } else {
- favorites.remove(idx);
- }
- EditorSettings::get_singleton()->set_favorite_dirs(favorites);
- _update_tree(true);
-}
-
-void FileSystemDock::_show_current_scene_file() {
-
- int index = EditorNode::get_editor_data().get_edited_scene();
- String path = EditorNode::get_editor_data().get_scene_path(index);
- if (path != String()) {
- navigate_to_path(path);
- }
-}
-
String FileSystemDock::get_selected_path() const {
-
- TreeItem *sel = tree->get_selected();
- if (!sel)
- return "";
-
- return sel->get_metadata(0);
+ if (path.ends_with("/"))
+ return path;
+ else
+ return path.get_base_dir();
}
String FileSystemDock::get_current_path() const {
@@ -361,14 +429,17 @@ String FileSystemDock::get_current_path() const {
}
void FileSystemDock::navigate_to_path(const String &p_path) {
+
+ String target_path = p_path;
// If the path is a file, do not only go to the directory in the tree, also select the file in the file list.
- String file_name = "";
+ if (target_path.ends_with("/")) {
+ target_path = target_path.substr(0, target_path.length() - 1);
+ }
DirAccess *dirAccess = DirAccess::open("res://");
if (dirAccess->file_exists(p_path)) {
- path = p_path.get_base_dir();
- file_name = p_path.get_file();
+ path = target_path;
} else if (dirAccess->dir_exists(p_path)) {
- path = p_path;
+ path = target_path + "/";
} else {
ERR_EXPLAIN(vformat(TTR("Cannot navigate to '%s' as it has not been found in the file system!"), p_path));
ERR_FAIL();
@@ -377,13 +448,20 @@ void FileSystemDock::navigate_to_path(const String &p_path) {
current_path->set_text(path);
_push_to_history();
- if (display_mode == DISPLAY_SPLIT) {
- _update_tree(true);
+ if (display_mode == DISPLAY_MODE_SPLIT) {
+ _update_tree(_compute_uncollapsed_paths());
_update_files(false);
- } else {
- _go_to_file_list();
+ } else if (display_mode == DISPLAY_MODE_TREE_ONLY) {
+ if (path.ends_with("/")) {
+ _go_to_file_list();
+ } else {
+ _update_tree(_compute_uncollapsed_paths());
+ }
+ } else { // DISPLAY_MODE_FILE_LIST_ONLY
+ _update_files(true);
}
+ String file_name = p_path.get_file();
if (!file_name.empty()) {
for (int i = 0; i < files->get_item_count(); i++) {
if (files->get_item_text(i) == file_name) {
@@ -395,10 +473,9 @@ void FileSystemDock::navigate_to_path(const String &p_path) {
}
}
-void FileSystemDock::_thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Variant &p_udata) {
+void FileSystemDock::_file_list_thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Ref<Texture> &p_small_preview, const Variant &p_udata) {
if ((file_list_vb->is_visible_in_tree() || path == p_path.get_base_dir()) && p_preview.is_valid()) {
-
Array uarr = p_udata;
int idx = uarr[0];
String file = uarr[1];
@@ -407,6 +484,27 @@ void FileSystemDock::_thumbnail_done(const String &p_path, const Ref<Texture> &p
}
}
+void FileSystemDock::_tree_thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Ref<Texture> &p_small_preview, const Variant &p_udata) {
+ if (p_small_preview.is_valid()) {
+ Array uarr = p_udata;
+ if (tree_update_id == (int)uarr[0]) {
+ TreeItem *file_item = Object::cast_to<TreeItem>(uarr[1]);
+ if (file_item) {
+ file_item->set_icon(0, p_small_preview);
+
+ // Update the favorite icon if needed
+ TreeItem *favorite = tree->get_root()->get_children()->get_children();
+ while (favorite) {
+ if (favorite->get_metadata(0) == file_item->get_metadata(0)) {
+ favorite->set_icon(0, p_small_preview);
+ }
+ favorite = favorite->get_next();
+ }
+ }
+ }
+ }
+}
+
void FileSystemDock::_update_file_list_display_mode_button() {
if (button_file_list_display_mode->is_pressed()) {
@@ -424,7 +522,7 @@ void FileSystemDock::_change_file_display() {
_update_file_list_display_mode_button();
- EditorSettings::get_singleton()->set("docks/filesystem/display_mode", file_list_display_mode);
+ EditorSettings::get_singleton()->set("docks/filesystem/files_display_mode", file_list_display_mode);
_update_files(true);
}
@@ -438,12 +536,10 @@ void FileSystemDock::_search(EditorFileSystemDirectory *p_path, List<FileInfo> *
_search(p_path->get_subdir(i), matches, p_max_items);
}
- String match = search_box->get_text().to_lower();
-
for (int i = 0; i < p_path->get_file_count(); i++) {
String file = p_path->get_file(i);
- if (file.to_lower().find(match) != -1) {
+ if (file.to_lower().find(searched_string) != -1) {
FileInfo fi;
fi.name = file;
@@ -461,12 +557,10 @@ void FileSystemDock::_search(EditorFileSystemDirectory *p_path, List<FileInfo> *
void FileSystemDock::_update_files(bool p_keep_selection) {
+ // Register the previously selected items
Set<String> cselection;
-
if (p_keep_selection) {
-
for (int i = 0; i < files->get_item_count(); i++) {
-
if (files->is_selected(i))
cselection.insert(files->get_item_text(i));
}
@@ -476,7 +570,17 @@ void FileSystemDock::_update_files(bool p_keep_selection) {
current_path->set_text(path);
- EditorFileSystemDirectory *efd = EditorFileSystem::get_singleton()->get_filesystem_path(path);
+ String directory = path;
+ if (directory.ends_with("/") && directory != "res://") {
+ directory = directory.substr(0, directory.length() - 1);
+ }
+ String file = "";
+ EditorFileSystemDirectory *efd = EditorFileSystem::get_singleton()->get_filesystem_path(directory);
+ if (!efd) {
+ directory = path.get_base_dir();
+ file = path.get_file();
+ efd = EditorFileSystem::get_singleton()->get_filesystem_path(directory);
+ }
if (!efd)
return;
@@ -487,10 +591,8 @@ void FileSystemDock::_update_files(bool p_keep_selection) {
Ref<Texture> file_thumbnail;
Ref<Texture> file_thumbnail_broken;
- bool always_show_folders = EditorSettings::get_singleton()->get("docks/filesystem/always_show_folders");
-
bool use_thumbnails = (file_list_display_mode == FILE_LIST_DISPLAY_THUMBNAILS);
- bool use_folders = search_box->get_text().length() == 0 && ((display_mode == DISPLAY_FILE_LIST_ONLY || display_mode == DISPLAY_TREE_ONLY) || always_show_folders);
+ bool use_folders = searched_string.length() == 0 && ((display_mode == DISPLAY_MODE_FILE_LIST_ONLY || display_mode == DISPLAY_MODE_TREE_ONLY) || always_show_folders);
if (use_thumbnails) {
@@ -521,14 +623,15 @@ void FileSystemDock::_update_files(bool p_keep_selection) {
if (use_folders) {
Ref<Texture> folderIcon = (use_thumbnails) ? folder_thumbnail : get_icon("folder", "FileDialog");
- if (path != "res://") {
+ if (directory != "res://") {
files->add_item("..", folderIcon, true);
- String bd = path.get_base_dir();
+ String bd = directory.get_base_dir();
if (bd != "res://" && !bd.ends_with("/"))
bd += "/";
files->set_item_metadata(files->get_item_count() - 1, bd);
+ files->set_item_selectable(files->get_item_count() - 1, false);
}
for (int i = 0; i < efd->get_subdir_count(); i++) {
@@ -536,16 +639,17 @@ void FileSystemDock::_update_files(bool p_keep_selection) {
String dname = efd->get_subdir(i)->get_name();
files->add_item(dname, folderIcon, true);
- files->set_item_metadata(files->get_item_count() - 1, path.plus_file(dname) + "/");
+ files->set_item_metadata(files->get_item_count() - 1, directory.plus_file(dname) + "/");
- if (cselection.has(dname))
+ if (cselection.has(dname)) {
files->select(files->get_item_count() - 1, false);
+ }
}
}
List<FileInfo> filelist;
- if (search_box->get_text().length() > 0) {
+ if (searched_string.length() > 0) {
_search(EditorFileSystem::get_singleton()->get_filesystem(), &filelist, 128);
filelist.sort();
@@ -555,7 +659,7 @@ void FileSystemDock::_update_files(bool p_keep_selection) {
FileInfo fi;
fi.name = efd->get_file(i);
- fi.path = path.plus_file(fi.name);
+ fi.path = directory.plus_file(fi.name);
fi.type = efd->get_file_type(i);
fi.import_broken = !efd->get_file_import_is_valid(i);
fi.import_status = 0;
@@ -598,7 +702,7 @@ void FileSystemDock::_update_files(bool p_keep_selection) {
udata.resize(2);
udata[0] = item_index;
udata[1] = fname;
- EditorResourcePreview::get_singleton()->queue_resource_preview(fpath, this, "_thumbnail_done", udata);
+ EditorResourcePreview::get_singleton()->queue_resource_preview(fpath, this, "_file_list_thumbnail_done", udata);
}
} else {
files->add_item(fname, type_icon, true);
@@ -609,6 +713,11 @@ void FileSystemDock::_update_files(bool p_keep_selection) {
if (cselection.has(fname))
files->select(item_index, false);
+ if (!p_keep_selection && file != "" && fname == file) {
+ files->select(item_index, true);
+ files->ensure_current_is_visible();
+ }
+
if (finfo->sources.size()) {
for (int j = 0; j < finfo->sources.size(); j++) {
tooltip += "\nSource: " + finfo->sources[j];
@@ -618,8 +727,8 @@ void FileSystemDock::_update_files(bool p_keep_selection) {
}
}
-void FileSystemDock::_select_file(int p_idx) {
- String fpath = files->get_item_metadata(p_idx);
+void FileSystemDock::_select_file(const String p_path) {
+ String fpath = p_path;
if (fpath.ends_with("/")) {
if (fpath != "res://") {
fpath = fpath.substr(0, fpath.length() - 1);
@@ -634,9 +743,21 @@ void FileSystemDock::_select_file(int p_idx) {
}
}
+void FileSystemDock::_tree_activate_file() {
+ TreeItem *selected = tree->get_selected();
+ if (selected) {
+ call_deferred("_select_file", selected->get_metadata(0));
+ }
+}
+
+void FileSystemDock::_file_list_activate_file(int p_idx) {
+ _select_file(files->get_item_metadata(p_idx));
+}
+
void FileSystemDock::_go_to_file_list() {
- if (display_mode == DISPLAY_TREE_ONLY) {
+ if (display_mode == DISPLAY_MODE_TREE_ONLY) {
+
file_list_view = true;
_update_display_mode();
} else {
@@ -645,6 +766,7 @@ void FileSystemDock::_go_to_file_list() {
_update_files(false);
}
}
+
void FileSystemDock::_go_to_tree() {
file_list_view = false;
@@ -655,7 +777,7 @@ void FileSystemDock::_go_to_tree() {
void FileSystemDock::_preview_invalidated(const String &p_path) {
- if (file_list_display_mode == FILE_LIST_DISPLAY_THUMBNAILS && p_path.get_base_dir() == path && search_box->get_text() == String() && file_list_vb->is_visible_in_tree()) {
+ if (file_list_display_mode == FILE_LIST_DISPLAY_THUMBNAILS && p_path.get_base_dir() == path && searched_string.length() == 0 && file_list_vb->is_visible_in_tree()) {
for (int i = 0; i < files->get_item_count(); i++) {
@@ -665,7 +787,7 @@ void FileSystemDock::_preview_invalidated(const String &p_path) {
udata.resize(2);
udata[0] = i;
udata[1] = files->get_item_text(i);
- EditorResourcePreview::get_singleton()->queue_resource_preview(p_path, this, "_thumbnail_done", udata);
+ EditorResourcePreview::get_singleton()->queue_resource_preview(p_path, this, "_file_list_thumbnail_done", udata);
break;
}
}
@@ -680,7 +802,7 @@ void FileSystemDock::_fs_changed() {
split_box->show();
if (tree->is_visible()) {
- _update_tree(true);
+ _update_tree(_compute_uncollapsed_paths());
}
if (file_list_vb->is_visible()) {
@@ -724,7 +846,7 @@ void FileSystemDock::_update_history() {
current_path->set_text(path);
if (tree->is_visible()) {
- _update_tree(true);
+ _update_tree(_compute_uncollapsed_paths());
tree->grab_focus();
tree->ensure_cursor_is_visible();
}
@@ -968,23 +1090,23 @@ void FileSystemDock::_update_project_settings_after_move(const Map<String, Strin
ProjectSettings::get_singleton()->save();
}
-void FileSystemDock::_update_favorite_dirs_list_after_move(const Map<String, String> &p_renames) const {
-
- Vector<String> favorite_dirs = EditorSettings::get_singleton()->get_favorite_dirs();
- Vector<String> new_favorite_dirs;
+void FileSystemDock::_update_favorites_list_after_move(const Map<String, String> &p_files_renames, const Map<String, String> &p_folders_renames) const {
- for (int i = 0; i < favorite_dirs.size(); i++) {
- String old_path = favorite_dirs[i] + "/";
+ Vector<String> favorites = EditorSettings::get_singleton()->get_favorites();
+ Vector<String> new_favorites;
- if (p_renames.has(old_path)) {
- String new_path = p_renames[old_path];
- new_favorite_dirs.push_back(new_path.substr(0, new_path.length() - 1));
+ for (int i = 0; i < favorites.size(); i++) {
+ String old_path = favorites[i];
+ if (p_folders_renames.has(old_path)) {
+ new_favorites.push_back(p_folders_renames[old_path]);
+ } else if (p_files_renames.has(old_path)) {
+ new_favorites.push_back(p_files_renames[old_path]);
} else {
- new_favorite_dirs.push_back(favorite_dirs[i]);
+ new_favorites.push_back(old_path);
}
}
- EditorSettings::get_singleton()->set_favorite_dirs(new_favorite_dirs);
+ EditorSettings::get_singleton()->set_favorites(new_favorites);
}
void FileSystemDock::_make_dir_confirm() {
@@ -998,9 +1120,13 @@ void FileSystemDock::_make_dir_confirm() {
return;
}
- print_verbose("Making folder " + dir_name + " in " + path);
+ String directory = path;
+ if (!directory.ends_with("/")) {
+ directory = directory.get_base_dir();
+ }
+ print_verbose("Making folder " + dir_name + " in " + directory);
DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
- Error err = da->change_dir(path);
+ Error err = da->change_dir(directory);
if (err == OK) {
err = da->make_dir(dir_name);
}
@@ -1051,7 +1177,7 @@ void FileSystemDock::_rename_operation_confirm() {
_update_dependencies_after_move(file_renames);
_update_resource_paths_after_move(file_renames);
_update_project_settings_after_move(file_renames);
- _update_favorite_dirs_list_after_move(folder_renames);
+ _update_favorites_list_after_move(file_renames, folder_renames);
//Rescan everything
print_verbose("FileSystem: calling rescan.");
@@ -1144,111 +1270,209 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool overw
_update_dependencies_after_move(file_renames);
_update_resource_paths_after_move(file_renames);
_update_project_settings_after_move(file_renames);
- _update_favorite_dirs_list_after_move(folder_renames);
+ _update_favorites_list_after_move(file_renames, folder_renames);
print_verbose("FileSystem: calling rescan.");
_rescan();
}
}
-void FileSystemDock::_file_option(int p_option) {
+Vector<String> FileSystemDock::_tree_get_selected(bool remove_self_inclusion) {
+ // Build a list of selected items with the active one at the first position
+ Vector<String> selected_strings;
+
+ TreeItem *active_selected = tree->get_selected();
+ if (active_selected) {
+ selected_strings.push_back(active_selected->get_metadata(0));
+ }
+
+ TreeItem *selected = tree->get_root();
+ selected = tree->get_next_selected(selected);
+ while (selected) {
+ if (selected != active_selected) {
+ selected_strings.push_back(selected->get_metadata(0));
+ }
+ selected = tree->get_next_selected(selected);
+ }
+
+ // Remove paths or files that are included into another
+ if (remove_self_inclusion && selected_strings.size() > 1) {
+ selected_strings.sort_custom<NaturalNoCaseComparator>();
+ String last_path = "";
+ for (int i = 0; i < selected_strings.size(); i++) {
+ if (last_path != "" && selected_strings[i].begins_with(last_path)) {
+ selected_strings.remove(i);
+ i--;
+ }
+ if (selected_strings[i].ends_with("/")) {
+ last_path = selected_strings[i];
+ }
+ }
+ }
+ return selected_strings;
+}
+
+void FileSystemDock::_tree_rmb_option(int p_option) {
+
+ Vector<String> selected_strings = _tree_get_selected();
+
+ // Execute the current option
switch (p_option) {
- case FILE_SHOW_IN_EXPLORER: {
+ case FOLDER_EXPAND_ALL:
+ case FOLDER_COLLAPSE_ALL: {
+ // Expand or collapse the folder
+ if (selected_strings.size() == 1) {
+ bool is_collapsed = (p_option == FOLDER_COLLAPSE_ALL);
+
+ Vector<TreeItem *> needs_check;
+ needs_check.push_back(tree->get_selected());
- String path = this->path;
+ while (needs_check.size()) {
+ needs_check[0]->set_collapsed(is_collapsed);
- // first try to grab directory from selected file, so that it works for searched files
- int idx = files->get_current();
+ TreeItem *child = needs_check[0]->get_children();
+ while (child) {
+ needs_check.push_back(child);
+ child = child->get_next();
+ }
- if (idx >= 0 && idx < files->get_item_count()) {
- path = files->get_item_metadata(idx);
- path = path.get_base_dir();
+ needs_check.remove(0);
+ }
}
+ } break;
+ default: {
+ _file_option(p_option, selected_strings);
+ } break;
+ }
+}
+
+void FileSystemDock::_file_list_rmb_option(int p_option) {
+ Vector<int> selected_id = files->get_selected_items();
+ Vector<String> selected;
+ for (int i = 0; i < selected_id.size(); i++) {
+ selected.push_back(files->get_item_metadata(selected_id[i]));
+ }
+ _file_option(p_option, selected);
+}
- path = ProjectSettings::get_singleton()->globalize_path(path);
- OS::get_singleton()->shell_open(String("file://") + path);
+void FileSystemDock::_file_option(int p_option, const Vector<String> p_selected) {
+ // The first one should be the active item
+
+ switch (p_option) {
+ case FILE_SHOW_IN_EXPLORER: {
+ // Show the file / folder in the OS explorer
+ String fpath = path;
+ if (!fpath.ends_with("/")) {
+ fpath = fpath.get_base_dir();
+ }
+ String dir = ProjectSettings::get_singleton()->globalize_path(fpath);
+ OS::get_singleton()->shell_open(String("file://") + dir);
} break;
+
case FILE_OPEN: {
- for (int i = 0; i < files->get_item_count(); i++) {
- if (files->is_selected(i)) {
- _select_file(i);
- }
+ // Open the file
+ for (int i = 0; i < p_selected.size(); i++) {
+ _select_file(p_selected[i]);
}
} break;
- case FILE_INSTANCE: {
+ case FILE_INSTANCE: {
+ // Instance all selected scenes
Vector<String> paths;
-
- for (int i = 0; i < files->get_item_count(); i++) {
- if (!files->is_selected(i))
- continue;
- String fpath = files->get_item_metadata(i);
+ for (int i = 0; i < p_selected.size(); i++) {
+ String fpath = p_selected[i];
if (EditorFileSystem::get_singleton()->get_file_type(fpath) == "PackedScene") {
paths.push_back(fpath);
}
}
-
if (!paths.empty()) {
emit_signal("instance", paths);
}
} break;
- case FILE_DEPENDENCIES: {
- int idx = files->get_current();
- if (idx < 0 || idx >= files->get_item_count())
- break;
- String fpath = files->get_item_metadata(idx);
- deps_editor->edit(fpath);
+ case FILE_ADD_FAVORITE: {
+ // Add the files from favorites
+ Vector<String> favorites = EditorSettings::get_singleton()->get_favorites();
+ for (int i = 0; i < p_selected.size(); i++) {
+ if (favorites.find(p_selected[i]) == -1) {
+ favorites.push_back(p_selected[i]);
+ }
+ }
+ EditorSettings::get_singleton()->set_favorites(favorites);
+ _update_tree(_compute_uncollapsed_paths());
} break;
- case FILE_OWNERS: {
- int idx = files->get_current();
- if (idx < 0 || idx >= files->get_item_count())
- break;
- String fpath = files->get_item_metadata(idx);
- owners_editor->show(fpath);
+ case FILE_REMOVE_FAVORITE: {
+ // Remove the files from favorites
+ Vector<String> favorites = EditorSettings::get_singleton()->get_favorites();
+ for (int i = 0; i < p_selected.size(); i++) {
+ favorites.erase(p_selected[i]);
+ }
+ EditorSettings::get_singleton()->set_favorites(favorites);
+ _update_tree(_compute_uncollapsed_paths());
+ } break;
+
+ case FILE_DEPENDENCIES: {
+ // Checkout the file dependencies
+ if (!p_selected.empty()) {
+ String fpath = p_selected[0];
+ deps_editor->edit(fpath);
+ }
} break;
+
+ case FILE_OWNERS: {
+ // Checkout the file owners
+ if (!p_selected.empty()) {
+ String fpath = p_selected[0];
+ owners_editor->show(fpath);
+ }
+ } break;
+
case FILE_MOVE: {
+ // Move the files to a given location
to_move.clear();
- for (int i = 0; i < files->get_item_count(); i++) {
- if (!files->is_selected(i))
- continue;
-
- String fpath = files->get_item_metadata(i);
- to_move.push_back(FileOrFolder(fpath, !fpath.ends_with("/")));
+ for (int i = 0; i < p_selected.size(); i++) {
+ String fpath = p_selected[i];
+ if (fpath != "res://") {
+ to_move.push_back(FileOrFolder(fpath, !fpath.ends_with("/")));
+ }
}
if (to_move.size() > 0) {
move_dialog->popup_centered_ratio();
}
} break;
- case FILE_RENAME: {
- int idx = files->get_current();
- if (idx < 0 || idx >= files->get_item_count())
- break;
- to_rename.path = files->get_item_metadata(idx);
- to_rename.is_file = !to_rename.path.ends_with("/");
- if (to_rename.is_file) {
- String name = to_rename.path.get_file();
- rename_dialog->set_title(TTR("Renaming file:") + " " + name);
- rename_dialog_text->set_text(name);
- rename_dialog_text->select(0, name.find_last("."));
- } else {
- String name = to_rename.path.substr(0, to_rename.path.length() - 1).get_file();
- rename_dialog->set_title(TTR("Renaming folder:") + " " + name);
- rename_dialog_text->set_text(name);
- rename_dialog_text->select(0, name.length());
+ case FILE_RENAME: {
+ // Rename the active file
+ if (!p_selected.empty()) {
+ to_rename.path = p_selected[0];
+ if (to_rename.path != "res://") {
+ to_rename.is_file = !to_rename.path.ends_with("/");
+ if (to_rename.is_file) {
+ String name = to_rename.path.get_file();
+ rename_dialog->set_title(TTR("Renaming file:") + " " + name);
+ rename_dialog_text->set_text(name);
+ rename_dialog_text->select(0, name.find_last("."));
+ } else {
+ String name = to_rename.path.substr(0, to_rename.path.length() - 1).get_file();
+ rename_dialog->set_title(TTR("Renaming folder:") + " " + name);
+ rename_dialog_text->set_text(name);
+ rename_dialog_text->select(0, name.length());
+ }
+ rename_dialog->popup_centered_minsize(Size2(250, 80) * EDSCALE);
+ rename_dialog_text->grab_focus();
+ }
}
- rename_dialog->popup_centered_minsize(Size2(250, 80) * EDSCALE);
- rename_dialog_text->grab_focus();
} break;
+
case FILE_REMOVE: {
+ // Remove the selected files
Vector<String> remove_files;
Vector<String> remove_folders;
- for (int i = 0; i < files->get_item_count(); i++) {
- String fpath = files->get_item_metadata(i);
- if (files->is_selected(i) && fpath != "res://") {
+ for (int i = 0; i < p_selected.size(); i++) {
+ String fpath = p_selected[i];
+ if (fpath != "res://") {
if (fpath.ends_with("/")) {
remove_folders.push_back(fpath);
} else {
@@ -1259,166 +1483,77 @@ void FileSystemDock::_file_option(int p_option) {
if (remove_files.size() + remove_folders.size() > 0) {
remove_dialog->show(remove_folders, remove_files);
- //1) find if used
- //2) warn
}
} break;
- case FILE_DUPLICATE: {
- int idx = files->get_current();
- if (idx < 0 || idx >= files->get_item_count())
- break;
- to_duplicate.path = files->get_item_metadata(idx);
- to_duplicate.is_file = !to_duplicate.path.ends_with("/");
- if (to_duplicate.is_file) {
- String name = to_duplicate.path.get_file();
- duplicate_dialog->set_title(TTR("Duplicating file:") + " " + name);
- duplicate_dialog_text->set_text(name);
- duplicate_dialog_text->select(0, name.find_last("."));
- } else {
- String name = to_duplicate.path.substr(0, to_duplicate.path.length() - 1).get_file();
- duplicate_dialog->set_title(TTR("Duplicating folder:") + " " + name);
- duplicate_dialog_text->set_text(name);
- duplicate_dialog_text->select(0, name.length());
+ case FILE_DUPLICATE: {
+ // Duplicate the selected files
+ for (int i = 0; i < p_selected.size(); i++) {
+ to_duplicate.path = p_selected[i];
+ to_duplicate.is_file = !to_duplicate.path.ends_with("/");
+ if (to_duplicate.is_file) {
+ String name = to_duplicate.path.get_file();
+ duplicate_dialog->set_title(TTR("Duplicating file:") + " " + name);
+ duplicate_dialog_text->set_text(name);
+ duplicate_dialog_text->select(0, name.find_last("."));
+ } else {
+ String name = to_duplicate.path.substr(0, to_duplicate.path.length() - 1).get_file();
+ duplicate_dialog->set_title(TTR("Duplicating folder:") + " " + name);
+ duplicate_dialog_text->set_text(name);
+ duplicate_dialog_text->select(0, name.length());
+ }
+ duplicate_dialog->popup_centered_minsize(Size2(250, 80) * EDSCALE);
+ duplicate_dialog_text->grab_focus();
}
- duplicate_dialog->popup_centered_minsize(Size2(250, 80) * EDSCALE);
- duplicate_dialog_text->grab_focus();
} break;
+
case FILE_INFO: {
} break;
- case FILE_REIMPORT: {
+ case FILE_REIMPORT: {
+ // Reimport all selected files
Vector<String> reimport;
- for (int i = 0; i < files->get_item_count(); i++) {
-
- if (!files->is_selected(i))
- continue;
-
- String fpath = files->get_item_metadata(i);
- reimport.push_back(fpath);
+ for (int i = 0; i < p_selected.size(); i++) {
+ reimport.push_back(p_selected[i]);
}
ERR_FAIL_COND(reimport.size() == 0);
- /*
- Ref<ResourceImportMetadata> rimd = ResourceLoader::load_import_metadata(reimport[0]);
- ERR_FAIL_COND(!rimd.is_valid());
- String editor=rimd->get_editor();
-
- if (editor.begins_with("texture_")) { //compatibility fix for old texture format
- editor="texture";
- }
-
- Ref<EditorImportPlugin> rimp = EditorImportExport::get_singleton()->get_import_plugin_by_name(editor);
- ERR_FAIL_COND(!rimp.is_valid());
-
- if (reimport.size()==1) {
- rimp->import_dialog(reimport[0]);
- } else {
- rimp->reimport_multiple_files(reimport);
-
- }
- */
} break;
+
case FILE_NEW_FOLDER: {
+ // Create a new folder
make_dir_dialog_text->set_text("new folder");
make_dir_dialog_text->select_all();
make_dir_dialog->popup_centered_minsize(Size2(250, 80) * EDSCALE);
make_dir_dialog_text->grab_focus();
} break;
+
case FILE_NEW_SCRIPT: {
- String tarDir = path;
- if (tarDir != "res://" && !tarDir.ends_with("/")) {
- tarDir += "/";
+ // Create a new script
+ String fpath = path;
+ if (!fpath.ends_with("/")) {
+ fpath = fpath.get_base_dir();
}
-
- make_script_dialog_text->config("Node", tarDir + "new_script.gd");
+ make_script_dialog_text->config("Node", fpath + "new_script.gd");
make_script_dialog_text->popup_centered(Size2(300, 300) * EDSCALE);
} break;
+
case FILE_COPY_PATH: {
- int idx = files->get_current();
- if (idx < 0 || idx >= files->get_item_count())
- break;
- String fpath = files->get_item_metadata(idx);
- OS::get_singleton()->set_clipboard(fpath);
+ // Copy the file path
+ if (!p_selected.empty()) {
+ String fpath = p_selected[0];
+ OS::get_singleton()->set_clipboard(fpath);
+ }
} break;
+
case FILE_NEW_RESOURCE: {
+ // Create a new resource
new_resource_dialog->popup_create(true);
} break;
}
}
-void FileSystemDock::_folder_option(int p_option) {
-
- TreeItem *selected = tree->get_selected();
-
- switch (p_option) {
- case FOLDER_EXPAND_ALL:
- case FOLDER_COLLAPSE_ALL: {
- bool is_collapsed = (p_option == FOLDER_COLLAPSE_ALL);
- Vector<TreeItem *> needs_check;
- needs_check.push_back(selected);
-
- while (needs_check.size()) {
- needs_check[0]->set_collapsed(is_collapsed);
-
- TreeItem *child = needs_check[0]->get_children();
- while (child) {
- needs_check.push_back(child);
- child = child->get_next();
- }
-
- needs_check.remove(0);
- }
- } break;
- case FOLDER_MOVE: {
- to_move.clear();
- String fpath = selected->get_metadata(tree->get_selected_column());
- if (fpath != "res://") {
- fpath = fpath.ends_with("/") ? fpath.substr(0, fpath.length() - 1) : fpath;
- to_move.push_back(FileOrFolder(fpath, false));
- move_dialog->popup_centered_ratio();
- }
- } break;
- case FOLDER_RENAME: {
- to_rename.path = selected->get_metadata(tree->get_selected_column());
- to_rename.is_file = false;
- if (to_rename.path != "res://") {
- String name = to_rename.path.ends_with("/") ? to_rename.path.substr(0, to_rename.path.length() - 1).get_file() : to_rename.path.get_file();
- rename_dialog->set_title(TTR("Renaming folder:") + " " + name);
- rename_dialog_text->set_text(name);
- rename_dialog_text->select(0, name.length());
- rename_dialog->popup_centered_minsize(Size2(250, 80) * EDSCALE);
- rename_dialog_text->grab_focus();
- }
- } break;
- case FOLDER_REMOVE: {
- Vector<String> remove_folders;
- Vector<String> remove_files;
- String fpath = selected->get_metadata(tree->get_selected_column());
- if (fpath != "res://") {
- remove_folders.push_back(fpath);
- remove_dialog->show(remove_folders, remove_files);
- }
- } break;
- case FOLDER_NEW_FOLDER: {
- make_dir_dialog_text->set_text("new folder");
- make_dir_dialog_text->select_all();
- make_dir_dialog->popup_centered_minsize(Size2(250, 80) * EDSCALE);
- make_dir_dialog_text->grab_focus();
- } break;
- case FOLDER_COPY_PATH: {
- String fpath = selected->get_metadata(tree->get_selected_column());
- OS::get_singleton()->set_clipboard(fpath);
- } break;
- case FOLDER_SHOW_IN_EXPLORER: {
- String fpath = selected->get_metadata(tree->get_selected_column());
- String dir = ProjectSettings::get_singleton()->globalize_path(fpath);
- OS::get_singleton()->shell_open(String("file://") + dir);
- } break;
- }
-}
-
void FileSystemDock::_resource_created() const {
Object *c = new_resource_dialog->instance_selected();
@@ -1431,38 +1566,39 @@ void FileSystemDock::_resource_created() const {
RES current_res = RES(r);
- editor->save_resource_as(current_res, path);
-}
-
-void FileSystemDock::_dir_rmb_pressed(const Vector2 &p_pos) {
- folder_options->clear();
- folder_options->set_size(Size2(1, 1));
+ String fpath = path;
+ if (!fpath.ends_with("/")) {
+ fpath = fpath.get_base_dir();
+ }
- folder_options->add_item(TTR("Expand all"), FOLDER_EXPAND_ALL);
- folder_options->add_item(TTR("Collapse all"), FOLDER_COLLAPSE_ALL);
+ editor->save_resource_as(current_res, fpath);
+}
- TreeItem *item = tree->get_selected();
- if (item) {
- String fpath = item->get_metadata(tree->get_selected_column());
- folder_options->add_separator();
- folder_options->add_item(TTR("Copy Path"), FOLDER_COPY_PATH);
- if (fpath != "res://") {
- folder_options->add_item(TTR("Rename..."), FOLDER_RENAME);
- folder_options->add_item(TTR("Move To..."), FOLDER_MOVE);
- folder_options->add_item(TTR("Delete"), FOLDER_REMOVE);
- }
- folder_options->add_separator();
- folder_options->add_item(TTR("New Folder..."), FOLDER_NEW_FOLDER);
- folder_options->add_item(TTR("Open In File Manager"), FOLDER_SHOW_IN_EXPLORER);
+void FileSystemDock::_search_changed(const String &p_text, const Control *p_from) {
+ if (searched_string.length() == 0 && p_text.length() > 0) {
+ // Register the uncollapsed paths before they change
+ uncollapsed_paths_before_search = _compute_uncollapsed_paths();
}
- folder_options->set_position(tree->get_global_position() + p_pos);
- folder_options->popup();
-}
-void FileSystemDock::_search_changed(const String &p_text) {
+ searched_string = p_text.to_lower();
- if (file_list_vb->is_visible())
- _update_files(false);
+ if (p_from == tree_search_box)
+ file_list_search_box->set_text(searched_string);
+ else // file_list_search_box
+ tree_search_box->set_text(searched_string);
+
+ switch (display_mode) {
+ case DISPLAY_MODE_FILE_LIST_ONLY: {
+ _update_files(false);
+ } break;
+ case DISPLAY_MODE_TREE_ONLY: {
+ _update_tree(searched_string.length() == 0 ? uncollapsed_paths_before_search : Vector<String>());
+ } break;
+ case DISPLAY_MODE_SPLIT: {
+ _update_files(false);
+ _update_tree(searched_string.length() == 0 ? uncollapsed_paths_before_search : Vector<String>());
+ } break;
+ }
}
void FileSystemDock::_rescan() {
@@ -1471,20 +1607,25 @@ void FileSystemDock::_rescan() {
EditorFileSystem::get_singleton()->scan();
}
+void FileSystemDock::_toggle_split_mode(bool p_active) {
+ display_mode_setting = p_active ? DISPLAY_MODE_SETTING_SPLIT : DISPLAY_MODE_SETTING_TREE_ONLY;
+ EditorSettings::get_singleton()->set("docks/filesystem/display_mode", int(display_mode_setting));
+ _update_display_mode();
+}
+
void FileSystemDock::fix_dependencies(const String &p_for_file) {
deps_editor->edit(p_for_file);
}
void FileSystemDock::focus_on_filter() {
- if (display_mode == DISPLAY_FILE_LIST_ONLY && tree->is_visible()) {
+ if (display_mode == DISPLAY_MODE_FILE_LIST_ONLY && tree->is_visible()) {
// Tree mode, switch to files list with search box
tree->hide();
file_list_vb->show();
- button_favorite->hide();
}
- search_box->grab_focus();
+ file_list_search_box->grab_focus();
}
void FileSystemDock::set_file_list_display_mode(int p_mode) {
@@ -1497,33 +1638,43 @@ void FileSystemDock::set_file_list_display_mode(int p_mode) {
}
Variant FileSystemDock::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
- bool is_favorite = false;
+ bool all_favorites = true;
+ bool all_not_favorites = true;
+
Vector<String> paths;
if (p_from == tree) {
- TreeItem *selected = tree->get_selected();
- if (!selected)
- return Variant();
-
- String folder = selected->get_metadata(0);
- if (folder == String())
- return Variant();
-
- paths.push_back(folder.ends_with("/") ? folder : (folder + "/"));
- is_favorite = selected->get_parent() != NULL && tree->get_root()->get_children() == selected->get_parent();
+ // Check if the first selected is in favorite
+ TreeItem *selected = tree->get_next_selected(tree->get_root());
+ while (selected) {
+ bool is_favorite = selected->get_parent() != NULL && tree->get_root()->get_children() == selected->get_parent();
+ all_favorites &= is_favorite;
+ all_not_favorites &= !is_favorite;
+ selected = tree->get_next_selected(selected);
+ }
+ if (all_favorites) {
+ paths = _tree_get_selected(false);
+ } else {
+ paths = _tree_get_selected();
+ }
} else if (p_from == files) {
for (int i = 0; i < files->get_item_count(); i++) {
if (files->is_selected(i)) {
paths.push_back(files->get_item_metadata(i));
}
}
+ all_favorites = false;
+ all_not_favorites = true;
}
if (paths.empty())
return Variant();
+ if (!all_favorites && !all_not_favorites)
+ return Variant();
+
Dictionary drag_data = EditorNode::get_singleton()->drag_files_and_dirs(paths, p_from);
- if (is_favorite) {
+ if (all_favorites) {
drag_data["type"] = "favorite";
}
return drag_data;
@@ -1535,34 +1686,46 @@ bool FileSystemDock::can_drop_data_fw(const Point2 &p_point, const Variant &p_da
if (drag_data.has("type") && String(drag_data["type"]) == "favorite") {
- //moving favorite around
+ // Moving favorite around
TreeItem *ti = tree->get_item_at_position(p_point);
if (!ti)
return false;
- int what = tree->get_drop_section_at_position(p_point);
+ int drop_section = tree->get_drop_section_at_position(p_point);
+ TreeItem *favorites_item = tree->get_root()->get_children();
+
+ TreeItem *resources_item = favorites_item->get_next();
- if (ti == tree->get_root()->get_children()) {
- return (what == 1); //the parent, first fav
+ if (ti == favorites_item) {
+ return (drop_section == 1); // The parent, first fav
}
- if (ti->get_parent() && tree->get_root()->get_children() == ti->get_parent()) {
- return true; // a favorite
+ if (ti->get_parent() && favorites_item == ti->get_parent()) {
+ return true; // A favorite
}
-
- if (ti == tree->get_root()->get_children()->get_next()) {
- return (what == -1); //the tree, last fav
+ if (ti == resources_item) {
+ return (drop_section == -1); // The tree, last fav
}
return false;
}
if (drag_data.has("type") && String(drag_data["type"]) == "resource") {
- String to_dir = _get_drag_target_folder(p_point, p_from);
+ // Move resources
+ String to_dir;
+ bool favorite;
+ _get_drag_target_folder(to_dir, favorite, p_point, p_from);
return !to_dir.empty();
}
if (drag_data.has("type") && (String(drag_data["type"]) == "files" || String(drag_data["type"]) == "files_and_dirs")) {
- String to_dir = _get_drag_target_folder(p_point, p_from);
+ // Move files or dir
+ String to_dir;
+ bool favorite;
+ _get_drag_target_folder(to_dir, favorite, p_point, p_from);
+
+ if (favorite)
+ return true;
+
if (to_dir.empty())
return false;
@@ -1587,71 +1750,67 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
return;
Dictionary drag_data = p_data;
- if (drag_data.has("type") && String(drag_data["type"]) == "favorite") {
+ Vector<String> dirs = EditorSettings::get_singleton()->get_favorites();
- //moving favorite around
+ if (drag_data.has("type") && String(drag_data["type"]) == "favorite") {
+ // Moving favorite around
TreeItem *ti = tree->get_item_at_position(p_point);
if (!ti)
return;
+ int drop_section = tree->get_drop_section_at_position(p_point);
+ int drop_position;
Vector<String> files = drag_data["files"];
-
- ERR_FAIL_COND(files.size() != 1);
-
- String swap = files[0];
- if (swap != "res://" && swap.ends_with("/")) {
- swap = swap.substr(0, swap.length() - 1);
- }
-
- int what = tree->get_drop_section_at_position(p_point);
-
- TreeItem *swap_item = NULL;
-
- if (ti == tree->get_root()->get_children()) {
- swap_item = tree->get_root()->get_children()->get_children();
-
- } else if (ti->get_parent() && tree->get_root()->get_children() == ti->get_parent()) {
- if (what == -1) {
- swap_item = ti;
- } else {
- swap_item = ti->get_next();
+ TreeItem *favorites_item = tree->get_root()->get_children();
+ TreeItem *resources_item = favorites_item->get_next();
+
+ if (ti == favorites_item) {
+ // Drop on the favorite folder
+ drop_position = 0;
+ } else if (ti == resources_item) {
+ // Drop on the resouce item
+ drop_position = dirs.size();
+ } else {
+ // Drop in the list
+ drop_position = dirs.find(ti->get_metadata(0));
+ if (drop_section == 1) {
+ drop_position++;
}
}
- String swap_with;
-
- if (swap_item) {
- swap_with = swap_item->get_metadata(0);
- if (swap_with != "res://" && swap_with.ends_with("/")) {
- swap_with = swap_with.substr(0, swap_with.length() - 1);
+ // Remove dragged favorites
+ Vector<int> to_remove;
+ int offset = 0;
+ for (int i = 0; i < files.size(); i++) {
+ int to_remove_pos = dirs.find(files[i]);
+ to_remove.push_back(to_remove_pos);
+ if (to_remove_pos < drop_position) {
+ offset++;
}
}
+ drop_position -= offset;
+ to_remove.sort();
+ for (int i = 0; i < to_remove.size(); i++) {
+ dirs.remove(to_remove[i] - i);
+ }
- if (swap == swap_with)
- return;
-
- Vector<String> dirs = EditorSettings::get_singleton()->get_favorite_dirs();
-
- ERR_FAIL_COND(dirs.find(swap) == -1);
- ERR_FAIL_COND(swap_with != String() && dirs.find(swap_with) == -1);
-
- dirs.erase(swap);
-
- if (swap_with == String()) {
- dirs.push_back(swap);
- } else {
- int idx = dirs.find(swap_with);
- dirs.insert(idx, swap);
+ // Re-add them at the right position
+ for (int i = 0; i < files.size(); i++) {
+ dirs.insert(drop_position, files[i]);
+ drop_position++;
}
- EditorSettings::get_singleton()->set_favorite_dirs(dirs);
- _update_tree(true);
+ EditorSettings::get_singleton()->set_favorites(dirs);
+ _update_tree(_compute_uncollapsed_paths());
return;
}
if (drag_data.has("type") && String(drag_data["type"]) == "resource") {
+ // Moving resource
Ref<Resource> res = drag_data["resource"];
- String to_dir = _get_drag_target_folder(p_point, p_from);
+ String to_dir;
+ bool favorite;
+ _get_drag_target_folder(to_dir, favorite, p_point, p_from);
if (res.is_valid() && !to_dir.empty()) {
EditorNode::get_singleton()->push_item(res.ptr());
EditorNode::get_singleton()->save_resource_as(res, to_dir);
@@ -1659,7 +1818,10 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
}
if (drag_data.has("type") && (String(drag_data["type"]) == "files" || String(drag_data["type"]) == "files_and_dirs")) {
- String to_dir = _get_drag_target_folder(p_point, p_from);
+ // Move files or add to favorites
+ String to_dir;
+ bool favorite;
+ _get_drag_target_folder(to_dir, favorite, p_point, p_from);
if (!to_dir.empty()) {
Vector<String> fnames = drag_data["files"];
to_move.clear();
@@ -1667,50 +1829,93 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
to_move.push_back(FileOrFolder(fnames[i], !fnames[i].ends_with("/")));
}
_move_operation_confirm(to_dir);
+ } else if (favorite) {
+ // Add the files from favorites
+ Vector<String> fnames = drag_data["files"];
+ Vector<String> favorites = EditorSettings::get_singleton()->get_favorites();
+ for (int i = 0; i < fnames.size(); i++) {
+ if (favorites.find(fnames[i]) == -1) {
+ favorites.push_back(fnames[i]);
+ }
+ }
+ EditorSettings::get_singleton()->set_favorites(favorites);
+ _update_tree(_compute_uncollapsed_paths());
}
}
}
-String FileSystemDock::_get_drag_target_folder(const Point2 &p_point, Control *p_from) const {
+void FileSystemDock::_get_drag_target_folder(String &target, bool &target_favorites, const Point2 &p_point, Control *p_from) const {
+ target = String();
+ target_favorites = false;
+
+ // In the file list
if (p_from == files) {
int pos = files->get_item_at_position(p_point, true);
- if (pos == -1)
- return path;
+ if (pos == -1) {
+ return;
+ }
- String target = files->get_item_metadata(pos);
- return target.ends_with("/") ? target : path;
+ String ltarget = files->get_item_metadata(pos);
+ target = ltarget.ends_with("/") ? target : path;
+ return;
}
+ // In the tree
if (p_from == tree) {
TreeItem *ti = tree->get_item_at_position(p_point);
- if (ti && ti != tree->get_root()->get_children())
- return ti->get_metadata(0);
+ int section = tree->get_drop_section_at_position(p_point);
+ if (ti) {
+ // Check the favorites first
+ if (ti == tree->get_root()->get_children() && section >= 0) {
+ target_favorites = true;
+ return;
+ } else if (ti->get_parent() == tree->get_root()->get_children()) {
+ target_favorites = true;
+ return;
+ } else {
+ String fpath = ti->get_metadata(0);
+ if (section == 0) {
+ if (fpath.ends_with("/")) {
+ // We drop on a folder
+ target = fpath;
+ return;
+ }
+ } else {
+ if (ti->get_parent() != tree->get_root()->get_children()) {
+ // Not in the favorite section
+ if (fpath != "res://") {
+ // We drop between two files
+ if (fpath.ends_with("/")) {
+ fpath = fpath.substr(0, fpath.length() - 1);
+ }
+ target = fpath.get_base_dir();
+ return;
+ }
+ }
+ }
+ }
+ }
}
- return String();
+ return;
}
-void FileSystemDock::_files_list_rmb_select(int p_item, const Vector2 &p_pos) {
-
- //Right clicking ".." should clear current selection
- if (files->get_item_text(p_item) == "..") {
- for (int i = 0; i < files->get_item_count(); i++) {
- files->unselect(i);
- }
- }
+void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<String> p_paths) {
+ // Add options for files and folders
+ ERR_FAIL_COND(p_paths.empty())
Vector<String> filenames;
Vector<String> foldernames;
+ Vector<String> favorites = EditorSettings::get_singleton()->get_favorites();
+
bool all_files = true;
bool all_files_scenes = true;
bool all_folders = true;
- for (int i = 0; i < files->get_item_count(); i++) {
- if (!files->is_selected(i)) {
- continue;
- }
-
- String fpath = files->get_item_metadata(i);
+ bool all_favorites = true;
+ bool all_not_favorites = true;
+ for (int i = 0; i < p_paths.size(); i++) {
+ String fpath = p_paths[i];
if (fpath.ends_with("/")) {
foldernames.push_back(fpath);
all_files = false;
@@ -1719,68 +1924,135 @@ void FileSystemDock::_files_list_rmb_select(int p_item, const Vector2 &p_pos) {
all_folders = false;
all_files_scenes &= (EditorFileSystem::get_singleton()->get_file_type(fpath) == "PackedScene");
}
+
+ // Check if in favorites
+ bool found = false;
+ for (int j = 0; j < favorites.size(); j++) {
+ if (favorites[j] == fpath) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ all_not_favorites = false;
+ } else {
+ all_favorites = false;
+ }
}
- file_options->clear();
- file_options->set_size(Size2(1, 1));
if (all_files) {
if (all_files_scenes && filenames.size() >= 1) {
- file_options->add_item(TTR("Open Scene(s)"), FILE_OPEN);
- file_options->add_item(TTR("Instance"), FILE_INSTANCE);
- file_options->add_separator();
+ p_popup->add_item(TTR("Open Scene(s)"), FILE_OPEN);
+ p_popup->add_item(TTR("Instance"), FILE_INSTANCE);
+ p_popup->add_separator();
}
if (!all_files_scenes && filenames.size() == 1) {
- file_options->add_item(TTR("Open"), FILE_OPEN);
- file_options->add_separator();
+ p_popup->add_item(TTR("Open"), FILE_OPEN);
+ p_popup->add_separator();
+ }
+ }
+
+ if (p_paths.size() >= 1) {
+ if (!all_favorites) {
+ p_popup->add_item(TTR("Add to favorites"), FILE_ADD_FAVORITE);
+ }
+ if (!all_not_favorites) {
+ p_popup->add_item(TTR("Remove from favorites"), FILE_REMOVE_FAVORITE);
}
+ p_popup->add_separator();
+ }
+ if (all_files) {
if (filenames.size() == 1) {
- file_options->add_item(TTR("Edit Dependencies..."), FILE_DEPENDENCIES);
- file_options->add_item(TTR("View Owners..."), FILE_OWNERS);
- file_options->add_separator();
+ p_popup->add_item(TTR("Edit Dependencies..."), FILE_DEPENDENCIES);
+ p_popup->add_item(TTR("View Owners..."), FILE_OWNERS);
+ p_popup->add_separator();
}
} else if (all_folders && foldernames.size() > 0) {
- file_options->add_item(TTR("Open"), FILE_OPEN);
- file_options->add_separator();
+ p_popup->add_item(TTR("Open"), FILE_OPEN);
+ p_popup->add_separator();
}
- int num_items = filenames.size() + foldernames.size();
- if (num_items >= 1) {
- if (num_items == 1) {
- file_options->add_item(TTR("Copy Path"), FILE_COPY_PATH);
- file_options->add_item(TTR("Rename..."), FILE_RENAME);
- file_options->add_item(TTR("Duplicate..."), FILE_DUPLICATE);
- }
- file_options->add_item(TTR("Move To..."), FILE_MOVE);
- file_options->add_item(TTR("Delete"), FILE_REMOVE);
- file_options->add_separator();
+ if (p_paths.size() == 1) {
+ p_popup->add_item(TTR("Copy Path"), FILE_COPY_PATH);
+ p_popup->add_item(TTR("Rename..."), FILE_RENAME);
+ p_popup->add_item(TTR("Duplicate..."), FILE_DUPLICATE);
}
- file_options->add_item(TTR("New Folder..."), FILE_NEW_FOLDER);
- file_options->add_item(TTR("New Script..."), FILE_NEW_SCRIPT);
- file_options->add_item(TTR("New Resource..."), FILE_NEW_RESOURCE);
+ p_popup->add_item(TTR("Move To..."), FILE_MOVE);
+ p_popup->add_item(TTR("Delete"), FILE_REMOVE);
- String fpath = files->get_item_metadata(p_item);
- String item_text = fpath.ends_with("/") ? TTR("Open In File Manager") : TTR("Show In File Manager");
- file_options->add_item(item_text, FILE_SHOW_IN_EXPLORER);
+ if (p_paths.size() == 1) {
+ p_popup->add_separator();
+ p_popup->add_item(TTR("New Folder..."), FILE_NEW_FOLDER);
+ p_popup->add_item(TTR("New Script..."), FILE_NEW_SCRIPT);
+ p_popup->add_item(TTR("New Resource..."), FILE_NEW_RESOURCE);
- file_options->set_position(files->get_global_position() + p_pos);
- file_options->popup();
+ String fpath = p_paths[0];
+ String item_text = fpath.ends_with("/") ? TTR("Open In File Manager") : TTR("Show In File Manager");
+ p_popup->add_item(item_text, FILE_SHOW_IN_EXPLORER);
+ }
+}
+
+void FileSystemDock::_tree_rmb_select(const Vector2 &p_pos) {
+ // Right click is pressed in the tree
+ Vector<String> paths = _tree_get_selected();
+
+ if (paths.size() == 1) {
+ if (paths[0].ends_with("/")) {
+ tree_popup->add_item(TTR("Expand all"), FOLDER_EXPAND_ALL);
+ tree_popup->add_item(TTR("Collapse all"), FOLDER_COLLAPSE_ALL);
+ tree_popup->add_separator();
+ }
+ }
+
+ // Popup
+ if (!paths.empty()) {
+ tree_popup->clear();
+ tree_popup->set_size(Size2(1, 1));
+ _file_and_folders_fill_popup(tree_popup, paths);
+ tree_popup->set_position(tree->get_global_position() + p_pos);
+ tree_popup->popup();
+ }
}
-void FileSystemDock::_rmb_pressed(const Vector2 &p_pos) {
- file_options->clear();
- file_options->set_size(Size2(1, 1));
+void FileSystemDock::_file_list_rmb_select(int p_item, const Vector2 &p_pos) {
+ // Right click is pressed in the file list
+ Vector<String> paths;
+ for (int i = 0; i < files->get_item_count(); i++) {
+ if (!files->is_selected(i))
+ continue;
+ if (files->get_item_text(p_item) == "..") {
+ files->unselect(i);
+ continue;
+ }
+ paths.push_back(files->get_item_metadata(i));
+ }
+
+ // Popup
+ if (!paths.empty()) {
+ file_list_popup->clear();
+ file_list_popup->set_size(Size2(1, 1));
+ _file_and_folders_fill_popup(file_list_popup, paths);
+ file_list_popup->set_position(files->get_global_position() + p_pos);
+ file_list_popup->popup();
+ }
+}
- file_options->add_item(TTR("New Folder..."), FILE_NEW_FOLDER);
- file_options->add_item(TTR("New Script..."), FILE_NEW_SCRIPT);
- file_options->add_item(TTR("New Resource..."), FILE_NEW_RESOURCE);
- file_options->add_item(TTR("Show In File Manager"), FILE_SHOW_IN_EXPLORER);
- file_options->set_position(files->get_global_position() + p_pos);
- file_options->popup();
+void FileSystemDock::_file_list_rmb_pressed(const Vector2 &p_pos) {
+ // Right click on empty space for file list
+ file_list_popup->clear();
+ file_list_popup->set_size(Size2(1, 1));
+
+ file_list_popup->add_item(TTR("New Folder..."), FILE_NEW_FOLDER);
+ file_list_popup->add_item(TTR("New Script..."), FILE_NEW_SCRIPT);
+ file_list_popup->add_item(TTR("New Resource..."), FILE_NEW_RESOURCE);
+ file_list_popup->add_item(TTR("Show In File Manager"), FILE_SHOW_IN_EXPLORER);
+ file_list_popup->set_position(files->get_global_position() + p_pos);
+ file_list_popup->popup();
}
void FileSystemDock::select_file(const String &p_file) {
@@ -1790,11 +2062,24 @@ void FileSystemDock::select_file(const String &p_file) {
void FileSystemDock::_file_multi_selected(int p_index, bool p_selected) {
+ // Set the path to the current focussed item
+ int current = files->get_current();
+ if (current == p_index) {
+ String fpath = files->get_item_metadata(current);
+ if (!fpath.ends_with("/")) {
+ path = fpath;
+ if (display_mode == DISPLAY_MODE_SPLIT) {
+ _update_tree(_compute_uncollapsed_paths());
+ }
+ }
+ }
+
+ // Update the import dock
import_dock_needs_update = true;
call_deferred("_update_import_dock");
}
-void FileSystemDock::_files_gui_input(Ref<InputEvent> p_event) {
+void FileSystemDock::_tree_gui_input(Ref<InputEvent> p_event) {
if (get_viewport()->get_modal_stack_top())
return; //ignore because of modal window
@@ -1802,21 +2087,34 @@ void FileSystemDock::_files_gui_input(Ref<InputEvent> p_event) {
Ref<InputEventKey> key = p_event;
if (key.is_valid() && key->is_pressed() && !key->is_echo()) {
if (ED_IS_SHORTCUT("filesystem_dock/duplicate", p_event)) {
- _file_option(FILE_DUPLICATE);
+ _tree_rmb_option(FILE_DUPLICATE);
} else if (ED_IS_SHORTCUT("filesystem_dock/copy_path", p_event)) {
- _file_option(FILE_COPY_PATH);
+ _tree_rmb_option(FILE_COPY_PATH);
} else if (ED_IS_SHORTCUT("filesystem_dock/delete", p_event)) {
- _file_option(FILE_REMOVE);
+ _tree_rmb_option(FILE_REMOVE);
} else if (ED_IS_SHORTCUT("filesystem_dock/rename", p_event)) {
- _file_option(FILE_RENAME);
+ _tree_rmb_option(FILE_RENAME);
}
}
}
-void FileSystemDock::_file_selected() {
+void FileSystemDock::_file_list_gui_input(Ref<InputEvent> p_event) {
- import_dock_needs_update = true;
- _update_import_dock();
+ if (get_viewport()->get_modal_stack_top())
+ return; //ignore because of modal window
+
+ Ref<InputEventKey> key = p_event;
+ if (key.is_valid() && key->is_pressed() && !key->is_echo()) {
+ if (ED_IS_SHORTCUT("filesystem_dock/duplicate", p_event)) {
+ _file_list_rmb_option(FILE_DUPLICATE);
+ } else if (ED_IS_SHORTCUT("filesystem_dock/copy_path", p_event)) {
+ _file_list_rmb_option(FILE_COPY_PATH);
+ } else if (ED_IS_SHORTCUT("filesystem_dock/delete", p_event)) {
+ _file_list_rmb_option(FILE_REMOVE);
+ } else if (ED_IS_SHORTCUT("filesystem_dock/rename", p_event)) {
+ _file_list_rmb_option(FILE_RENAME);
+ }
+ }
}
void FileSystemDock::_update_import_dock() {
@@ -1869,16 +2167,25 @@ void FileSystemDock::_update_import_dock() {
void FileSystemDock::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_files_gui_input"), &FileSystemDock::_files_gui_input);
+ ClassDB::bind_method(D_METHOD("_file_list_gui_input"), &FileSystemDock::_file_list_gui_input);
+ ClassDB::bind_method(D_METHOD("_tree_gui_input"), &FileSystemDock::_tree_gui_input);
+
ClassDB::bind_method(D_METHOD("_update_tree"), &FileSystemDock::_update_tree);
ClassDB::bind_method(D_METHOD("_rescan"), &FileSystemDock::_rescan);
- ClassDB::bind_method(D_METHOD("_favorites_pressed"), &FileSystemDock::_favorites_pressed);
- ClassDB::bind_method(D_METHOD("_show_current_scene_file"), &FileSystemDock::_show_current_scene_file);
- //ClassDB::bind_method(D_METHOD("_instance_pressed"),&ScenesDock::_instance_pressed);
- ClassDB::bind_method(D_METHOD("_go_to_file_list"), &FileSystemDock::_go_to_file_list);
- ClassDB::bind_method(D_METHOD("_dir_rmb_pressed"), &FileSystemDock::_dir_rmb_pressed);
- ClassDB::bind_method(D_METHOD("_thumbnail_done"), &FileSystemDock::_thumbnail_done);
+ ClassDB::bind_method(D_METHOD("_toggle_split_mode"), &FileSystemDock::_toggle_split_mode);
+
+ ClassDB::bind_method(D_METHOD("_tree_rmb_option", "option"), &FileSystemDock::_tree_rmb_option);
+ ClassDB::bind_method(D_METHOD("_file_list_rmb_option", "option"), &FileSystemDock::_file_list_rmb_option);
+
+ ClassDB::bind_method(D_METHOD("_tree_rmb_select"), &FileSystemDock::_tree_rmb_select);
+ ClassDB::bind_method(D_METHOD("_file_list_rmb_select"), &FileSystemDock::_file_list_rmb_select);
+ ClassDB::bind_method(D_METHOD("_file_list_rmb_pressed"), &FileSystemDock::_file_list_rmb_pressed);
+
+ ClassDB::bind_method(D_METHOD("_file_list_thumbnail_done"), &FileSystemDock::_file_list_thumbnail_done);
+ ClassDB::bind_method(D_METHOD("_tree_thumbnail_done"), &FileSystemDock::_tree_thumbnail_done);
+ ClassDB::bind_method(D_METHOD("_file_list_activate_file"), &FileSystemDock::_file_list_activate_file);
+ ClassDB::bind_method(D_METHOD("_tree_activate_file"), &FileSystemDock::_tree_activate_file);
ClassDB::bind_method(D_METHOD("_select_file"), &FileSystemDock::_select_file);
ClassDB::bind_method(D_METHOD("_go_to_tree"), &FileSystemDock::_go_to_tree);
ClassDB::bind_method(D_METHOD("navigate_to_path"), &FileSystemDock::navigate_to_path);
@@ -1886,9 +2193,7 @@ void FileSystemDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_fw_history"), &FileSystemDock::_fw_history);
ClassDB::bind_method(D_METHOD("_bw_history"), &FileSystemDock::_bw_history);
ClassDB::bind_method(D_METHOD("_fs_changed"), &FileSystemDock::_fs_changed);
- ClassDB::bind_method(D_METHOD("_dir_selected"), &FileSystemDock::_dir_selected);
- ClassDB::bind_method(D_METHOD("_file_option"), &FileSystemDock::_file_option);
- ClassDB::bind_method(D_METHOD("_folder_option"), &FileSystemDock::_folder_option);
+ ClassDB::bind_method(D_METHOD("_tree_multi_selected"), &FileSystemDock::_tree_multi_selected);
ClassDB::bind_method(D_METHOD("_make_dir_confirm"), &FileSystemDock::_make_dir_confirm);
ClassDB::bind_method(D_METHOD("_resource_created"), &FileSystemDock::_resource_created);
ClassDB::bind_method(D_METHOD("_move_operation_confirm", "to_path", "overwrite"), &FileSystemDock::_move_operation_confirm, DEFVAL(false));
@@ -1901,13 +2206,10 @@ void FileSystemDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &FileSystemDock::get_drag_data_fw);
ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &FileSystemDock::can_drop_data_fw);
ClassDB::bind_method(D_METHOD("drop_data_fw"), &FileSystemDock::drop_data_fw);
- ClassDB::bind_method(D_METHOD("_files_list_rmb_select"), &FileSystemDock::_files_list_rmb_select);
ClassDB::bind_method(D_METHOD("_preview_invalidated"), &FileSystemDock::_preview_invalidated);
- ClassDB::bind_method(D_METHOD("_file_selected"), &FileSystemDock::_file_selected);
ClassDB::bind_method(D_METHOD("_file_multi_selected"), &FileSystemDock::_file_multi_selected);
ClassDB::bind_method(D_METHOD("_update_import_dock"), &FileSystemDock::_update_import_dock);
- ClassDB::bind_method(D_METHOD("_rmb_pressed"), &FileSystemDock::_rmb_pressed);
ADD_SIGNAL(MethodInfo("instance", PropertyInfo(Variant::POOL_STRING_ARRAY, "files")));
ADD_SIGNAL(MethodInfo("open"));
@@ -1924,9 +2226,12 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
ED_SHORTCUT("filesystem_dock/delete", TTR("Delete"), KEY_DELETE);
ED_SHORTCUT("filesystem_dock/rename", TTR("Rename"));
+ VBoxContainer *top_vbc = memnew(VBoxContainer);
+ add_child(top_vbc);
+
HBoxContainer *toolbar_hbc = memnew(HBoxContainer);
toolbar_hbc->add_constant_override("separation", 0);
- add_child(toolbar_hbc);
+ top_vbc->add_child(toolbar_hbc);
button_hist_prev = memnew(ToolButton);
button_hist_prev->set_disabled(true);
@@ -1942,6 +2247,7 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
current_path = memnew(LineEdit);
current_path->set_h_size_flags(SIZE_EXPAND_FILL);
+ current_path->set_text(path);
toolbar_hbc->add_child(current_path);
button_reload = memnew(Button);
@@ -1952,22 +2258,25 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
button_reload->hide();
toolbar_hbc->add_child(button_reload);
- //toolbar_hbc->add_spacer();
+ button_toggle_display_mode = memnew(Button);
+ button_toggle_display_mode->set_flat(true);
+ button_toggle_display_mode->set_toggle_mode(true);
+ button_toggle_display_mode->connect("toggled", this, "_toggle_split_mode");
+ button_toggle_display_mode->set_focus_mode(FOCUS_NONE);
+ button_toggle_display_mode->set_tooltip(TTR("Toggle split mode"));
+ toolbar_hbc->add_child(button_toggle_display_mode);
- button_favorite = memnew(Button);
- button_favorite->set_flat(true);
- button_favorite->set_toggle_mode(true);
- button_favorite->connect("pressed", this, "_favorites_pressed");
- button_favorite->set_tooltip(TTR("Toggle folder status as Favorite."));
- button_favorite->set_focus_mode(FOCUS_NONE);
- toolbar_hbc->add_child(button_favorite);
-
- button_show = memnew(Button);
- button_show->set_flat(true);
- button_show->connect("pressed", this, "_show_current_scene_file");
- toolbar_hbc->add_child(button_show);
- button_show->set_focus_mode(FOCUS_NONE);
- button_show->set_tooltip(TTR("Show current scene file."));
+ HBoxContainer *toolbar2_hbc = memnew(HBoxContainer);
+ toolbar2_hbc->add_constant_override("separation", 0);
+ top_vbc->add_child(toolbar2_hbc);
+
+ tree_search_box = memnew(LineEdit);
+ tree_search_box->set_h_size_flags(SIZE_EXPAND_FILL);
+ tree_search_box->set_placeholder(TTR("Search files"));
+ tree_search_box->connect("text_changed", this, "_search_changed", varray(tree_search_box));
+ toolbar2_hbc->add_child(tree_search_box);
+
+ //toolbar_hbc->add_spacer();
//Control *spacer = memnew( Control);
@@ -1990,13 +2299,13 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
button_instance->set_tooltip(TTR("Instance the selected scene(s) as child of the selected node."));
*/
- file_options = memnew(PopupMenu);
- file_options->set_hide_on_window_lose_focus(true);
- add_child(file_options);
+ file_list_popup = memnew(PopupMenu);
+ file_list_popup->set_hide_on_window_lose_focus(true);
+ add_child(file_list_popup);
- folder_options = memnew(PopupMenu);
- folder_options->set_hide_on_window_lose_focus(true);
- add_child(folder_options);
+ tree_popup = memnew(PopupMenu);
+ tree_popup->set_hide_on_window_lose_focus(true);
+ add_child(tree_popup);
split_box = memnew(VSplitContainer);
split_box->set_v_size_flags(SIZE_EXPAND_FILL);
@@ -2007,13 +2316,15 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
tree->set_hide_root(true);
tree->set_drag_forwarding(this);
tree->set_allow_rmb_select(true);
+ tree->set_select_mode(Tree::SELECT_MULTI);
tree->set_custom_minimum_size(Size2(0, 200 * EDSCALE));
split_box->add_child(tree);
tree->connect("item_edited", this, "_favorite_toggled");
- tree->connect("item_activated", this, "_go_to_file_list");
- tree->connect("cell_selected", this, "_dir_selected");
- tree->connect("item_rmb_selected", this, "_dir_rmb_pressed");
+ tree->connect("item_activated", this, "_tree_activate_file");
+ tree->connect("multi_selected", this, "_tree_multi_selected");
+ tree->connect("item_rmb_selected", this, "_tree_rmb_select");
+ tree->connect("gui_input", this, "_tree_gui_input");
file_list_vb = memnew(VBoxContainer);
file_list_vb->set_v_size_flags(SIZE_EXPAND_FILL);
@@ -2027,11 +2338,11 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
button_tree->hide();
path_hb->add_child(button_tree);
- search_box = memnew(LineEdit);
- search_box->set_h_size_flags(SIZE_EXPAND_FILL);
- search_box->set_placeholder(TTR("Search files"));
- search_box->connect("text_changed", this, "_search_changed");
- path_hb->add_child(search_box);
+ file_list_search_box = memnew(LineEdit);
+ file_list_search_box->set_h_size_flags(SIZE_EXPAND_FILL);
+ file_list_search_box->set_placeholder(TTR("Search files"));
+ file_list_search_box->connect("text_changed", this, "_search_changed", varray(file_list_search_box));
+ path_hb->add_child(file_list_search_box);
button_file_list_display_mode = memnew(ToolButton);
button_file_list_display_mode->set_toggle_mode(true);
@@ -2041,11 +2352,10 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
files->set_v_size_flags(SIZE_EXPAND_FILL);
files->set_select_mode(ItemList::SELECT_MULTI);
files->set_drag_forwarding(this);
- files->connect("item_rmb_selected", this, "_files_list_rmb_select");
- files->connect("gui_input", this, "_files_gui_input");
- files->connect("item_selected", this, "_file_selected");
+ files->connect("item_rmb_selected", this, "_file_list_rmb_select");
+ files->connect("gui_input", this, "_file_list_gui_input");
files->connect("multi_selected", this, "_file_multi_selected");
- files->connect("rmb_clicked", this, "_rmb_pressed");
+ files->connect("rmb_clicked", this, "_file_list_rmb_pressed");
files->set_allow_rmb_select(true);
file_list_vb->add_child(files);
@@ -2123,7 +2433,11 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
new_resource_dialog->set_base_type("Resource");
new_resource_dialog->connect("create", this, "_resource_created");
+ searched_string = String();
+ uncollapsed_paths_before_search = Vector<String>();
+
updating_tree = false;
+ tree_update_id = 0;
initialized = false;
import_dock_needs_update = false;
@@ -2131,8 +2445,12 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
history_max_size = 20;
history.push_back("res://");
- display_mode = DISPLAY_SPLIT;
+ display_mode = DISPLAY_MODE_SPLIT;
file_list_display_mode = FILE_LIST_DISPLAY_THUMBNAILS;
+
+ display_mode_setting = DISPLAY_MODE_SETTING_TREE_ONLY;
+ old_display_mode_setting = DISPLAY_MODE_SETTING_TREE_ONLY;
+ always_show_folders = false;
}
FileSystemDock::~FileSystemDock() {
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index 40be645bf7..51c8791b25 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -66,15 +66,22 @@ public:
};
private:
+ enum DisplayModeSetting {
+ DISPLAY_MODE_SETTING_TREE_ONLY,
+ DISPLAY_MODE_SETTING_SPLIT,
+ };
+
enum DisplayMode {
- DISPLAY_TREE_ONLY,
- DISPLAY_FILE_LIST_ONLY,
- DISPLAY_SPLIT,
+ DISPLAY_MODE_TREE_ONLY,
+ DISPLAY_MODE_FILE_LIST_ONLY,
+ DISPLAY_MODE_SPLIT,
};
enum FileMenu {
FILE_OPEN,
FILE_INSTANCE,
+ FILE_ADD_FAVORITE,
+ FILE_REMOVE_FAVORITE,
FILE_DEPENDENCIES,
FILE_OWNERS,
FILE_MOVE,
@@ -87,18 +94,9 @@ private:
FILE_NEW_SCRIPT,
FILE_SHOW_IN_EXPLORER,
FILE_COPY_PATH,
- FILE_NEW_RESOURCE
- };
-
- enum FolderMenu {
+ FILE_NEW_RESOURCE,
FOLDER_EXPAND_ALL,
FOLDER_COLLAPSE_ALL,
- FOLDER_MOVE,
- FOLDER_RENAME,
- FOLDER_REMOVE,
- FOLDER_NEW_FOLDER,
- FOLDER_SHOW_IN_EXPLORER,
- FOLDER_COPY_PATH
};
VBoxContainer *scanning_vb;
@@ -109,24 +107,30 @@ private:
EditorNode *editor;
Set<String> favorites;
+ Button *button_toggle_display_mode;
Button *button_reload;
- Button *button_favorite;
Button *button_tree;
Button *button_file_list_display_mode;
Button *button_hist_next;
Button *button_hist_prev;
- Button *button_show;
LineEdit *current_path;
- LineEdit *search_box;
+ LineEdit *tree_search_box;
+ LineEdit *file_list_search_box;
+
+ String searched_string;
+ Vector<String> uncollapsed_paths_before_search;
+
TextureRect *search_icon;
HBoxContainer *path_hb;
FileListDisplayMode file_list_display_mode;
DisplayMode display_mode;
+ DisplayModeSetting display_mode_setting;
+ DisplayModeSetting old_display_mode_setting;
bool file_list_view;
- PopupMenu *file_options;
- PopupMenu *folder_options;
+ PopupMenu *file_list_popup;
+ PopupMenu *tree_popup;
DependencyEditor *deps_editor;
DependencyEditorOwners *owners_editor;
@@ -143,6 +147,8 @@ private:
ScriptCreateDialog *make_script_dialog_text;
CreateDialog *new_resource_dialog;
+ bool always_show_folders;
+
class FileOrFolder {
public:
String path;
@@ -169,14 +175,18 @@ private:
bool initialized;
bool updating_tree;
+ int tree_update_id;
Tree *tree; //directories
ItemList *files;
bool import_dock_needs_update;
+ Ref<Texture> _get_tree_item_icon(EditorFileSystemDirectory *p_dir, int p_idx);
bool _create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector<String> &uncollapsed_paths);
- void _update_tree(bool keep_collapse_state, bool p_uncollapse_root = false);
+ Vector<String> _compute_uncollapsed_paths();
+ void _update_tree(const Vector<String> p_uncollapsed_paths = Vector<String>(), bool p_uncollapse_root = false);
- void _files_gui_input(Ref<InputEvent> p_event);
+ void _file_list_gui_input(Ref<InputEvent> p_event);
+ void _tree_gui_input(Ref<InputEvent> p_event);
void _update_files(bool p_keep_selection);
void _update_file_list_display_mode_button();
@@ -186,12 +196,13 @@ private:
void _go_to_tree();
void _go_to_file_list();
- void _select_file(int p_idx);
+ void _select_file(const String p_path);
+ void _tree_activate_file();
+ void _file_list_activate_file(int p_idx);
void _file_multi_selected(int p_index, bool p_selected);
- void _update_import_dock();
+ void _tree_multi_selected(Object *p_item, int p_column, bool p_selected);
- void _file_selected();
- void _dir_selected();
+ void _update_import_dock();
void _get_all_items_in_dir(EditorFileSystemDirectory *efsd, Vector<String> &files, Vector<String> &folders) const;
void _find_remaps(EditorFileSystemDirectory *efsd, const Map<String, String> &renames, Vector<String> &to_remaps) const;
@@ -199,8 +210,8 @@ private:
void _try_duplicate_item(const FileOrFolder &p_item, const String &p_new_path) const;
void _update_dependencies_after_move(const Map<String, String> &p_renames) const;
void _update_resource_paths_after_move(const Map<String, String> &p_renames) const;
- void _update_favorite_dirs_list_after_move(const Map<String, String> &p_renames) const;
- void _update_project_settings_after_move(const Map<String, String> &p_renames) const;
+ void _update_favorites_list_after_move(const Map<String, String> &p_files_renames, const Map<String, String> &p_folders_renames) const;
+ void _update_project_settings_after_move(const Map<String, String> &p_folders_renames) const;
void _resource_created() const;
void _make_dir_confirm();
@@ -210,8 +221,9 @@ private:
bool _check_existing();
void _move_operation_confirm(const String &p_to_path, bool overwrite = false);
- void _file_option(int p_option);
- void _folder_option(int p_option);
+ void _tree_rmb_option(int p_option);
+ void _file_list_rmb_option(int p_option);
+ void _file_option(int p_option, const Vector<String> p_selected);
void _fw_history();
void _bw_history();
@@ -221,13 +233,14 @@ private:
void _set_scanning_mode();
void _rescan();
- void _favorites_pressed();
- void _show_current_scene_file();
- void _search_changed(const String &p_text);
+ void _toggle_split_mode(bool p_active);
- void _dir_rmb_pressed(const Vector2 &p_pos);
- void _files_list_rmb_select(int p_item, const Vector2 &p_pos);
- void _rmb_pressed(const Vector2 &p_pos);
+ void _search_changed(const String &p_text, const Control *p_from);
+
+ void _file_and_folders_fill_popup(PopupMenu *p_popup, Vector<String> p_paths);
+ void _tree_rmb_select(const Vector2 &p_pos);
+ void _file_list_rmb_select(int p_item, const Vector2 &p_pos);
+ void _file_list_rmb_pressed(const Vector2 &p_pos);
struct FileInfo {
String name;
@@ -238,7 +251,7 @@ private:
bool import_broken;
bool operator<(const FileInfo &fi) const {
- return name < fi.name;
+ return NaturalNoCaseComparator()(name, fi.name);
}
};
@@ -247,13 +260,16 @@ private:
Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
- String _get_drag_target_folder(const Point2 &p_point, Control *p_from) const;
+ void _get_drag_target_folder(String &target, bool &target_favorites, const Point2 &p_point, Control *p_from) const;
void _preview_invalidated(const String &p_path);
- void _thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Variant &p_udata);
+ void _file_list_thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Ref<Texture> &p_small_preview, const Variant &p_udata);
+ void _tree_thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Ref<Texture> &p_small_preview, const Variant &p_udata);
void _update_display_mode();
+ Vector<String> _tree_get_selected(bool remove_self_inclusion = true);
+
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp
index b18bbc8ce9..c237d2e854 100644
--- a/editor/import/resource_importer_obj.cpp
+++ b/editor/import/resource_importer_obj.cpp
@@ -126,7 +126,12 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Spati
ERR_FAIL_COND_V(current.is_null(), ERR_FILE_CORRUPT);
String p = l.replace("map_Kd", "").replace("\\", "/").strip_edges();
- String path = base_path.plus_file(p);
+ String path;
+ if (p.is_abs_path()) {
+ path = p;
+ } else {
+ path = base_path.plus_file(p);
+ }
Ref<Texture> texture = ResourceLoader::load(path);
@@ -141,7 +146,12 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Spati
ERR_FAIL_COND_V(current.is_null(), ERR_FILE_CORRUPT);
String p = l.replace("map_Ks", "").replace("\\", "/").strip_edges();
- String path = base_path.plus_file(p);
+ String path;
+ if (p.is_abs_path()) {
+ path = p;
+ } else {
+ path = base_path.plus_file(p);
+ }
Ref<Texture> texture = ResourceLoader::load(path);
@@ -156,7 +166,12 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Spati
ERR_FAIL_COND_V(current.is_null(), ERR_FILE_CORRUPT);
String p = l.replace("map_Ns", "").replace("\\", "/").strip_edges();
- String path = base_path.plus_file(p);
+ String path;
+ if (p.is_abs_path()) {
+ path = p;
+ } else {
+ path = base_path.plus_file(p);
+ }
Ref<Texture> texture = ResourceLoader::load(path);
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index b51ff8b320..f7e59e2beb 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -516,12 +516,10 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
return false;
}
-void AbstractPolygon2DEditor::forward_draw_over_viewport(Control *p_overlay) {
+void AbstractPolygon2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
if (!_get_node())
return;
- Control *vpc = canvas_item_editor->get_viewport_control();
-
Transform2D xform = canvas_item_editor->get_canvas_transform() * _get_node()->get_global_transform();
const Ref<Texture> handle = get_icon("EditorHandle", "EditorIcons");
@@ -562,7 +560,7 @@ void AbstractPolygon2DEditor::forward_draw_over_viewport(Control *p_overlay) {
Vector2 point = xform.xform(p);
Vector2 next_point = xform.xform(p2);
- vpc->draw_line(point, next_point, col, 2 * EDSCALE);
+ p_overlay->draw_line(point, next_point, col, 2 * EDSCALE);
}
}
@@ -586,7 +584,7 @@ void AbstractPolygon2DEditor::forward_draw_over_viewport(Control *p_overlay) {
p2 = points[(i + 1) % n_points] + offset;
const Vector2 next_point = xform.xform(p2);
- vpc->draw_line(point, next_point, col, 2 * EDSCALE);
+ p_overlay->draw_line(point, next_point, col, 2 * EDSCALE);
}
}
@@ -598,14 +596,14 @@ void AbstractPolygon2DEditor::forward_draw_over_viewport(Control *p_overlay) {
const Vector2 point = xform.xform(p);
const Color modulate = vertex == active_point ? Color(0.5, 1, 2) : Color(1, 1, 1);
- vpc->draw_texture(handle, point - handle->get_size() * 0.5, modulate);
+ p_overlay->draw_texture(handle, point - handle->get_size() * 0.5, modulate);
}
}
if (edge_point.valid()) {
Ref<Texture> add_handle = get_icon("EditorHandleAdd", "EditorIcons");
- vpc->draw_texture(add_handle, edge_point.pos - add_handle->get_size() * 0.5);
+ p_overlay->draw_texture(add_handle, edge_point.pos - add_handle->get_size() * 0.5);
}
}
diff --git a/editor/plugins/abstract_polygon_2d_editor.h b/editor/plugins/abstract_polygon_2d_editor.h
index 9ba03bcdf6..00634ba5b8 100644
--- a/editor/plugins/abstract_polygon_2d_editor.h
+++ b/editor/plugins/abstract_polygon_2d_editor.h
@@ -137,7 +137,7 @@ protected:
public:
bool forward_gui_input(const Ref<InputEvent> &p_event);
- void forward_draw_over_viewport(Control *p_overlay);
+ void forward_canvas_draw_over_viewport(Control *p_overlay);
void edit(Node *p_polygon);
AbstractPolygon2DEditor(EditorNode *p_editor, bool p_wip_destructive = true);
@@ -153,7 +153,7 @@ class AbstractPolygon2DEditorPlugin : public EditorPlugin {
public:
virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return polygon_editor->forward_gui_input(p_event); }
- virtual void forward_draw_over_viewport(Control *p_overlay) { polygon_editor->forward_draw_over_viewport(p_overlay); }
+ virtual void forward_canvas_draw_over_viewport(Control *p_overlay) { polygon_editor->forward_canvas_draw_over_viewport(p_overlay); }
bool has_main_screen() const { return false; }
virtual String get_name() const { return klass; }
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index bf7603bd86..445664f8dd 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -908,7 +908,7 @@ void AnimationPlayerEditor::edit(AnimationPlayer *p_player) {
}
}
-void AnimationPlayerEditor::forward_force_draw_over_viewport(Control *p_overlay) {
+void AnimationPlayerEditor::forward_canvas_force_draw_over_viewport(Control *p_overlay) {
if (!onion.can_overlay)
return;
diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h
index 5ac7b99903..55f082aadb 100644
--- a/editor/plugins/animation_player_editor_plugin.h
+++ b/editor/plugins/animation_player_editor_plugin.h
@@ -246,7 +246,7 @@ public:
void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; }
void edit(AnimationPlayer *p_player);
- void forward_force_draw_over_viewport(Control *p_overlay);
+ void forward_canvas_force_draw_over_viewport(Control *p_overlay);
AnimationPlayerEditor(EditorNode *p_editor, AnimationPlayerEditorPlugin *p_plugin);
};
@@ -271,7 +271,7 @@ public:
virtual bool handles(Object *p_object) const;
virtual void make_visible(bool p_visible);
- virtual void forward_force_draw_over_viewport(Control *p_overlay) { anim_editor->forward_force_draw_over_viewport(p_overlay); }
+ virtual void forward_canvas_force_draw_over_viewport(Control *p_overlay) { anim_editor->forward_canvas_force_draw_over_viewport(p_overlay); }
AnimationPlayerEditorPlugin(EditorNode *p_node);
~AnimationPlayerEditorPlugin();
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 61433bbeec..2ea17fda1c 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -715,6 +715,46 @@ Vector2 CanvasItemEditor::_position_to_anchor(const Control *p_control, Vector2
return (p_control->get_transform().xform(position) - parent_rect.position) / parent_rect.size;
}
+void CanvasItemEditor::_save_canvas_item_ik_chain(const CanvasItem *p_canvas_item, List<float> *p_bones_length, List<Dictionary> *p_bones_state) {
+ if (p_bones_length)
+ *p_bones_length = List<float>();
+ if (p_bones_state)
+ *p_bones_state = List<Dictionary>();
+
+ const Node2D *bone = Object::cast_to<Node2D>(p_canvas_item);
+ if (bone && bone->has_meta("_edit_bone_")) {
+ // Check if we have an IK chain
+ List<const Node2D *> bone_ik_list;
+ bool ik_found = false;
+ bone = Object::cast_to<Node2D>(bone->get_parent());
+ while (bone) {
+ bone_ik_list.push_back(bone);
+ if (bone->has_meta("_edit_ik_")) {
+ ik_found = true;
+ break;
+ } else if (!bone->has_meta("_edit_bone_")) {
+ break;
+ }
+ bone = Object::cast_to<Node2D>(bone->get_parent());
+ }
+
+ //Save the bone state and length if we have an IK chain
+ if (ik_found) {
+ bone = Object::cast_to<Node2D>(p_canvas_item);
+ Transform2D bone_xform = bone->get_global_transform();
+ for (List<const Node2D *>::Element *bone_E = bone_ik_list.front(); bone_E; bone_E = bone_E->next()) {
+ bone_xform = bone_xform * bone->get_transform().affine_inverse();
+ const Node2D *parent_bone = bone_E->get();
+ if (p_bones_length)
+ p_bones_length->push_back(parent_bone->get_global_transform().get_origin().distance_to(bone->get_global_position()));
+ if (p_bones_state)
+ p_bones_state->push_back(parent_bone->_edit_get_state());
+ bone = parent_bone;
+ }
+ }
+ }
+}
+
void CanvasItemEditor::_save_canvas_item_state(List<CanvasItem *> p_canvas_items, bool save_bones) {
for (List<CanvasItem *>::Element *E = p_canvas_items.front(); E; E = E->next()) {
CanvasItem *canvas_item = E->get();
@@ -727,54 +767,28 @@ void CanvasItemEditor::_save_canvas_item_state(List<CanvasItem *> p_canvas_items
} else {
se->pre_drag_rect = Rect2();
}
- se->pre_drag_bones_length = List<float>();
- se->pre_drag_bones_undo_state = List<Dictionary>();
// If we have a bone, save the state of all nodes in the IK chain
- Node2D *bone = Object::cast_to<Node2D>(canvas_item);
- if (bone && bone->has_meta("_edit_bone_")) {
- // Check if we have an IK chain
- List<Node2D *> bone_ik_list;
- bool ik_found = false;
- bone = Object::cast_to<Node2D>(bone->get_parent());
- while (bone) {
- bone_ik_list.push_back(bone);
- if (bone->has_meta("_edit_ik_")) {
- ik_found = true;
- break;
- } else if (!bone->has_meta("_edit_bone_")) {
- break;
- }
- bone = Object::cast_to<Node2D>(bone->get_parent());
- }
-
- //Save the bone state and length if we have an IK chain
- if (ik_found) {
- bone = Object::cast_to<Node2D>(canvas_item);
- Transform2D bone_xform = bone->get_global_transform();
- for (List<Node2D *>::Element *bone_E = bone_ik_list.front(); bone_E; bone_E = bone_E->next()) {
- bone_xform = bone_xform * bone->get_transform().affine_inverse();
- Node2D *parent_bone = bone_E->get();
- se->pre_drag_bones_length.push_back(parent_bone->get_global_transform().get_origin().distance_to(bone->get_global_position()));
- se->pre_drag_bones_undo_state.push_back(parent_bone->_edit_get_state());
- bone = parent_bone;
- }
- }
- }
+ _save_canvas_item_ik_chain(canvas_item, &(se->pre_drag_bones_length), &(se->pre_drag_bones_undo_state));
}
}
}
+void CanvasItemEditor::_restore_canvas_item_ik_chain(CanvasItem *p_canvas_item, const List<Dictionary> *p_bones_state) {
+ CanvasItem *canvas_item = p_canvas_item;
+ for (const List<Dictionary>::Element *E = p_bones_state->front(); E; E = E->next()) {
+ canvas_item = Object::cast_to<CanvasItem>(canvas_item->get_parent());
+ canvas_item->_edit_set_state(E->get());
+ }
+}
+
void CanvasItemEditor::_restore_canvas_item_state(List<CanvasItem *> p_canvas_items, bool restore_bones) {
for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
CanvasItem *canvas_item = E->get();
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
canvas_item->_edit_set_state(se->undo_state);
if (restore_bones) {
- for (List<Dictionary>::Element *E = se->pre_drag_bones_undo_state.front(); E; E = E->next()) {
- canvas_item = Object::cast_to<CanvasItem>(canvas_item->get_parent());
- canvas_item->_edit_set_state(E->get());
- }
+ _restore_canvas_item_ik_chain(canvas_item, &(se->pre_drag_bones_undo_state));
}
}
}
@@ -1199,73 +1213,72 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) {
void CanvasItemEditor::_solve_IK(Node2D *leaf_node, Point2 target_position) {
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(leaf_node);
- if (se && !se->pre_drag_bones_undo_state.empty()) {
-
- // Build the node list
- Point2 leaf_pos = target_position;
-
- List<Node2D *> joints_list;
- List<Point2> joints_pos;
- Node2D *joint = leaf_node;
- Transform2D joint_transform = leaf_node->get_global_transform_with_canvas();
- for (int i = 0; i < se->pre_drag_bones_undo_state.size() + 1; i++) {
- joints_list.push_back(joint);
- joints_pos.push_back(joint_transform.get_origin());
- joint_transform = joint_transform * joint->get_transform().affine_inverse();
- joint = Object::cast_to<Node2D>(joint->get_parent());
- }
- Point2 root_pos = joints_list.back()->get()->get_global_transform_with_canvas().get_origin();
-
- // Restraints the node to a maximum distance is necessary
- float total_len = 0;
- for (List<float>::Element *E = se->pre_drag_bones_length.front(); E; E = E->next()) {
- total_len += E->get();
- }
- if ((root_pos.distance_to(leaf_pos)) > total_len) {
- Vector2 rel = leaf_pos - root_pos;
- rel = rel.normalized() * total_len;
- leaf_pos = root_pos + rel;
- }
- joints_pos[0] = leaf_pos;
-
- // Run the solver
- int solver_iterations = 64;
- float solver_k = 0.3;
-
- // Build the position list
- for (int i = 0; i < solver_iterations; i++) {
- // Handle the leaf joint
- int node_id = 0;
+ if (se) {
+ int nb_bones = se->pre_drag_bones_undo_state.size();
+ if (nb_bones > 0) {
+
+ // Build the node list
+ Point2 leaf_pos = target_position;
+
+ List<Node2D *> joints_list;
+ List<Point2> joints_pos;
+ Node2D *joint = leaf_node;
+ Transform2D joint_transform = leaf_node->get_global_transform_with_canvas();
+ for (int i = 0; i < nb_bones + 1; i++) {
+ joints_list.push_back(joint);
+ joints_pos.push_back(joint_transform.get_origin());
+ joint_transform = joint_transform * joint->get_transform().affine_inverse();
+ joint = Object::cast_to<Node2D>(joint->get_parent());
+ }
+ Point2 root_pos = joints_list.back()->get()->get_global_transform_with_canvas().get_origin();
+
+ // Restraints the node to a maximum distance is necessary
+ float total_len = 0;
for (List<float>::Element *E = se->pre_drag_bones_length.front(); E; E = E->next()) {
- Vector2 direction = (joints_pos[node_id + 1] - joints_pos[node_id]).normalized();
- int len = E->get();
- if (E == se->pre_drag_bones_length.front()) {
- joints_pos[1] = joints_pos[1].linear_interpolate(joints_pos[0] + len * direction, solver_k);
- } else if (E == se->pre_drag_bones_length.back()) {
- joints_pos[node_id] = joints_pos[node_id].linear_interpolate(joints_pos[node_id + 1] - len * direction, solver_k);
- } else {
- Vector2 center = (joints_pos[node_id + 1] + joints_pos[node_id]) / 2.0;
- joints_pos[node_id] = joints_pos[node_id].linear_interpolate(center - (direction * len) / 2.0, solver_k);
- joints_pos[node_id + 1] = joints_pos[node_id + 1].linear_interpolate(center + (direction * len) / 2.0, solver_k);
+ total_len += E->get();
+ }
+ if ((root_pos.distance_to(leaf_pos)) > total_len) {
+ Vector2 rel = leaf_pos - root_pos;
+ rel = rel.normalized() * total_len;
+ leaf_pos = root_pos + rel;
+ }
+ joints_pos[0] = leaf_pos;
+
+ // Run the solver
+ int solver_iterations = 64;
+ float solver_k = 0.3;
+
+ // Build the position list
+ for (int i = 0; i < solver_iterations; i++) {
+ // Handle the leaf joint
+ int node_id = 0;
+ for (List<float>::Element *E = se->pre_drag_bones_length.front(); E; E = E->next()) {
+ Vector2 direction = (joints_pos[node_id + 1] - joints_pos[node_id]).normalized();
+ int len = E->get();
+ if (E == se->pre_drag_bones_length.front()) {
+ joints_pos[1] = joints_pos[1].linear_interpolate(joints_pos[0] + len * direction, solver_k);
+ } else if (E == se->pre_drag_bones_length.back()) {
+ joints_pos[node_id] = joints_pos[node_id].linear_interpolate(joints_pos[node_id + 1] - len * direction, solver_k);
+ } else {
+ Vector2 center = (joints_pos[node_id + 1] + joints_pos[node_id]) / 2.0;
+ joints_pos[node_id] = joints_pos[node_id].linear_interpolate(center - (direction * len) / 2.0, solver_k);
+ joints_pos[node_id + 1] = joints_pos[node_id + 1].linear_interpolate(center + (direction * len) / 2.0, solver_k);
+ }
+ node_id++;
}
- node_id++;
}
- }
- // Set the position
- float total_rot = 0.0f;
- for (int node_id = joints_list.size() - 1; node_id > 0; node_id--) {
- Point2 current = (joints_list[node_id - 1]->get_global_position() - joints_list[node_id]->get_global_position()).normalized();
- Point2 target = (joints_pos[node_id - 1] - joints_list[node_id]->get_global_position()).normalized();
- float rot = current.angle_to(target);
- if (joints_list[node_id]->get_global_transform().basis_determinant() < 0) {
- rot = -rot;
+ // Set the position
+ for (int node_id = joints_list.size() - 1; node_id > 0; node_id--) {
+ Point2 current = (joints_list[node_id - 1]->get_global_position() - joints_list[node_id]->get_global_position()).normalized();
+ Point2 target = (joints_pos[node_id - 1] - joints_list[node_id]->get_global_position()).normalized();
+ float rot = current.angle_to(target);
+ if (joints_list[node_id]->get_global_transform().basis_determinant() < 0) {
+ rot = -rot;
+ }
+ joints_list[node_id]->rotate(rot);
}
- joints_list[node_id]->rotate(rot);
- total_rot += rot;
}
-
- joints_list[0]->rotate(-total_rot);
}
}
@@ -1664,7 +1677,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
if (drag_type == DRAG_SCALE_X || drag_type == DRAG_SCALE_Y) {
// Resize the node
if (m.is_valid()) {
- _restore_canvas_item_state(drag_selection, true);
+ _restore_canvas_item_state(drag_selection);
CanvasItem *canvas_item = drag_selection[0];
drag_to = transform.affine_inverse().xform(m->get_position());
@@ -1730,6 +1743,15 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
if (drag_type == DRAG_MOVE) {
// Move the nodes
if (m.is_valid()) {
+
+ // Save the ik chain for reapplying before IK solve
+ Vector<List<Dictionary> > all_bones_ik_states;
+ for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
+ List<Dictionary> bones_ik_states;
+ _save_canvas_item_ik_chain(E->get(), NULL, &bones_ik_states);
+ all_bones_ik_states.push_back(bones_ik_states);
+ }
+
_restore_canvas_item_state(drag_selection, true);
drag_to = transform.affine_inverse().xform(m->get_position());
@@ -1751,6 +1773,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
}
bool force_no_IK = m->get_alt();
+ int index = 0;
for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
CanvasItem *canvas_item = E->get();
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
@@ -1758,10 +1781,15 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
Node2D *node2d = Object::cast_to<Node2D>(canvas_item);
if (node2d && se->pre_drag_bones_undo_state.size() > 0 && !force_no_IK) {
+ real_t initial_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation();
+ _restore_canvas_item_ik_chain(node2d, &(all_bones_ik_states[index]));
+ real_t final_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation();
+ node2d->rotate(initial_leaf_node_rotation - final_leaf_node_rotation);
_solve_IK(node2d, new_pos);
} else {
canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos));
}
+ index++;
}
return true;
}
@@ -1800,6 +1828,14 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
if (drag_selection.size() > 0) {
+ // Save the ik chain for reapplying before IK solve
+ Vector<List<Dictionary> > all_bones_ik_states;
+ for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
+ List<Dictionary> bones_ik_states;
+ _save_canvas_item_ik_chain(E->get(), NULL, &bones_ik_states);
+ all_bones_ik_states.push_back(bones_ik_states);
+ }
+
_restore_canvas_item_state(drag_selection, true);
bool move_local_base = k->get_alt();
@@ -1845,6 +1881,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
new_pos = previous_pos + (drag_to - drag_from);
}
+ int index = 0;
for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
CanvasItem *canvas_item = E->get();
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
@@ -1852,10 +1889,15 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
Node2D *node2d = Object::cast_to<Node2D>(canvas_item);
if (node2d && se->pre_drag_bones_undo_state.size() > 0) {
+ real_t initial_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation();
+ _restore_canvas_item_ik_chain(node2d, &(all_bones_ik_states[index]));
+ real_t final_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation();
+ node2d->rotate(initial_leaf_node_rotation - final_leaf_node_rotation);
_solve_IK(node2d, new_pos);
} else {
canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos));
}
+ index++;
}
}
return true;
@@ -3026,6 +3068,7 @@ bool CanvasItemEditor::_build_bones_list(Node *p_node) {
}
void CanvasItemEditor::_draw_viewport() {
+
// Update the transform
transform = Transform2D();
transform.scale_basis(Size2(zoom, zoom));
@@ -3074,11 +3117,11 @@ void CanvasItemEditor::_draw_viewport() {
EditorPluginList *over_plugin_list = editor->get_editor_plugins_over();
if (!over_plugin_list->empty()) {
- over_plugin_list->forward_draw_over_viewport(viewport);
+ over_plugin_list->forward_canvas_draw_over_viewport(viewport);
}
EditorPluginList *force_over_plugin_list = editor->get_editor_plugins_force_over();
if (!force_over_plugin_list->empty()) {
- force_over_plugin_list->forward_force_draw_over_viewport(viewport);
+ force_over_plugin_list->forward_canvas_force_draw_over_viewport(viewport);
}
_draw_bones();
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 61631dee7d..2d539d6727 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -377,7 +377,9 @@ private:
void _add_canvas_item(CanvasItem *p_canvas_item);
+ void _save_canvas_item_ik_chain(const CanvasItem *p_canvas_item, List<float> *p_bones_length, List<Dictionary> *p_bones_state);
void _save_canvas_item_state(List<CanvasItem *> p_canvas_items, bool save_bones = false);
+ void _restore_canvas_item_ik_chain(CanvasItem *p_canvas_item, const List<Dictionary> *p_bones_state);
void _restore_canvas_item_state(List<CanvasItem *> p_canvas_items, bool restore_bones = false);
void _commit_canvas_item_state(List<CanvasItem *> p_canvas_items, String action_name, bool commit_bones = false);
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp
index 9e052bb027..e3f364790a 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.cpp
+++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp
@@ -415,7 +415,7 @@ void CollisionShape2DEditor::_get_current_shape_type() {
canvas_item_editor->get_viewport_control()->update();
}
-void CollisionShape2DEditor::forward_draw_over_viewport(Control *p_overlay) {
+void CollisionShape2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
if (!node) {
return;
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.h b/editor/plugins/collision_shape_2d_editor_plugin.h
index 10784f1129..fb7b2acb0f 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.h
+++ b/editor/plugins/collision_shape_2d_editor_plugin.h
@@ -75,7 +75,7 @@ protected:
public:
bool forward_canvas_gui_input(const Ref<InputEvent> &p_event);
- void forward_draw_over_viewport(Control *p_overlay);
+ void forward_canvas_draw_over_viewport(Control *p_overlay);
void edit(Node *p_node);
CollisionShape2DEditor(EditorNode *p_editor);
@@ -89,7 +89,7 @@ class CollisionShape2DEditorPlugin : public EditorPlugin {
public:
virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return collision_shape_2d_editor->forward_canvas_gui_input(p_event); }
- virtual void forward_draw_over_viewport(Control *p_overlay) { return collision_shape_2d_editor->forward_draw_over_viewport(p_overlay); }
+ virtual void forward_canvas_draw_over_viewport(Control *p_overlay) { return collision_shape_2d_editor->forward_canvas_draw_over_viewport(p_overlay); }
virtual String get_name() const { return "CollisionShape2D"; }
bool has_main_screen() const { return false; }
diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp
index 72a746e95b..7f83865777 100644
--- a/editor/plugins/editor_preview_plugins.cpp
+++ b/editor/plugins/editor_preview_plugins.cpp
@@ -78,7 +78,11 @@ bool EditorTexturePreviewPlugin::handles(const String &p_type) const {
return ClassDB::is_parent_class(p_type, "Texture");
}
-Ref<Texture> EditorTexturePreviewPlugin::generate(const RES &p_from) const {
+bool EditorTexturePreviewPlugin::should_generate_small_preview() const {
+ return true;
+}
+
+Ref<Texture> EditorTexturePreviewPlugin::generate(const RES &p_from, const Size2 p_size) const {
Ref<Image> img;
Ref<AtlasTexture> atex = p_from;
@@ -100,8 +104,6 @@ Ref<Texture> EditorTexturePreviewPlugin::generate(const RES &p_from) const {
img = img->duplicate();
img->clear_mipmaps();
- int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
- thumbnail_size *= EDSCALE;
if (img->is_compressed()) {
if (img->decompress() != OK)
return Ref<Texture>();
@@ -109,22 +111,15 @@ Ref<Texture> EditorTexturePreviewPlugin::generate(const RES &p_from) const {
img->convert(Image::FORMAT_RGBA8);
}
- int width, height;
- if (img->get_width() > thumbnail_size && img->get_width() >= img->get_height()) {
-
- width = thumbnail_size;
- height = img->get_height() * thumbnail_size / img->get_width();
- } else if (img->get_height() > thumbnail_size && img->get_height() >= img->get_width()) {
-
- height = thumbnail_size;
- width = img->get_width() * thumbnail_size / img->get_height();
- } else {
-
- width = img->get_width();
- height = img->get_height();
+ Vector2 new_size = img->get_size();
+ if (new_size.x > p_size.x) {
+ new_size = Vector2(p_size.x, new_size.y * p_size.x / new_size.x);
}
+ if (new_size.y > p_size.y) {
+ new_size = Vector2(new_size.x * p_size.y / new_size.y, p_size.y);
+ }
+ img->resize(new_size.x, new_size.y, Image::INTERPOLATE_CUBIC);
- img->resize(width, height);
post_process_preview(img);
Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture));
@@ -143,7 +138,7 @@ bool EditorImagePreviewPlugin::handles(const String &p_type) const {
return p_type == "Image";
}
-Ref<Texture> EditorImagePreviewPlugin::generate(const RES &p_from) const {
+Ref<Texture> EditorImagePreviewPlugin::generate(const RES &p_from, const Size2 p_size) const {
Ref<Image> img = p_from;
@@ -153,8 +148,6 @@ Ref<Texture> EditorImagePreviewPlugin::generate(const RES &p_from) const {
img = img->duplicate();
img->clear_mipmaps();
- int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
- thumbnail_size *= EDSCALE;
if (img->is_compressed()) {
if (img->decompress() != OK)
return Ref<Image>();
@@ -162,22 +155,15 @@ Ref<Texture> EditorImagePreviewPlugin::generate(const RES &p_from) const {
img->convert(Image::FORMAT_RGBA8);
}
- int width, height;
- if (img->get_width() > thumbnail_size && img->get_width() >= img->get_height()) {
-
- width = thumbnail_size;
- height = img->get_height() * thumbnail_size / img->get_width();
- } else if (img->get_height() > thumbnail_size && img->get_height() >= img->get_width()) {
-
- height = thumbnail_size;
- width = img->get_width() * thumbnail_size / img->get_height();
- } else {
-
- width = img->get_width();
- height = img->get_height();
+ Vector2 new_size = img->get_size();
+ if (new_size.x > p_size.x) {
+ new_size = Vector2(p_size.x, new_size.y * p_size.x / new_size.x);
+ }
+ if (new_size.y > p_size.y) {
+ new_size = Vector2(new_size.x * p_size.y / new_size.y, p_size.y);
}
+ img->resize(new_size.x, new_size.y, Image::INTERPOLATE_CUBIC);
- img->resize(width, height);
post_process_preview(img);
Ref<ImageTexture> ptex;
@@ -190,6 +176,9 @@ Ref<Texture> EditorImagePreviewPlugin::generate(const RES &p_from) const {
EditorImagePreviewPlugin::EditorImagePreviewPlugin() {
}
+bool EditorImagePreviewPlugin::should_generate_small_preview() const {
+ return true;
+}
////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////
bool EditorBitmapPreviewPlugin::handles(const String &p_type) const {
@@ -197,7 +186,7 @@ bool EditorBitmapPreviewPlugin::handles(const String &p_type) const {
return ClassDB::is_parent_class(p_type, "BitMap");
}
-Ref<Texture> EditorBitmapPreviewPlugin::generate(const RES &p_from) const {
+Ref<Texture> EditorBitmapPreviewPlugin::generate(const RES &p_from, const Size2 p_size) const {
Ref<BitMap> bm = p_from;
@@ -227,8 +216,6 @@ Ref<Texture> EditorBitmapPreviewPlugin::generate(const RES &p_from) const {
img.instance();
img->create(bm->get_size().width, bm->get_size().height, 0, Image::FORMAT_L8, data);
- int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
- thumbnail_size *= EDSCALE;
if (img->is_compressed()) {
if (img->decompress() != OK)
return Ref<Texture>();
@@ -236,22 +223,15 @@ Ref<Texture> EditorBitmapPreviewPlugin::generate(const RES &p_from) const {
img->convert(Image::FORMAT_RGBA8);
}
- int width, height;
- if (img->get_width() > thumbnail_size && img->get_width() >= img->get_height()) {
-
- width = thumbnail_size;
- height = img->get_height() * thumbnail_size / img->get_width();
- } else if (img->get_height() > thumbnail_size && img->get_height() >= img->get_width()) {
-
- height = thumbnail_size;
- width = img->get_width() * thumbnail_size / img->get_height();
- } else {
-
- width = img->get_width();
- height = img->get_height();
+ Vector2 new_size = img->get_size();
+ if (new_size.x > p_size.x) {
+ new_size = Vector2(p_size.x, new_size.y * p_size.x / new_size.x);
+ }
+ if (new_size.y > p_size.y) {
+ new_size = Vector2(new_size.x * p_size.y / new_size.y, p_size.y);
}
+ img->resize(new_size.x, new_size.y, Image::INTERPOLATE_CUBIC);
- img->resize(width, height);
post_process_preview(img);
Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture));
@@ -260,6 +240,10 @@ Ref<Texture> EditorBitmapPreviewPlugin::generate(const RES &p_from) const {
return ptex;
}
+bool EditorBitmapPreviewPlugin::should_generate_small_preview() const {
+ return true;
+}
+
EditorBitmapPreviewPlugin::EditorBitmapPreviewPlugin() {
}
@@ -269,12 +253,12 @@ bool EditorPackedScenePreviewPlugin::handles(const String &p_type) const {
return ClassDB::is_parent_class(p_type, "PackedScene");
}
-Ref<Texture> EditorPackedScenePreviewPlugin::generate(const RES &p_from) const {
+Ref<Texture> EditorPackedScenePreviewPlugin::generate(const RES &p_from, const Size2 p_size) const {
- return generate_from_path(p_from->get_path());
+ return generate_from_path(p_from->get_path(), p_size);
}
-Ref<Texture> EditorPackedScenePreviewPlugin::generate_from_path(const String &p_path) const {
+Ref<Texture> EditorPackedScenePreviewPlugin::generate_from_path(const String &p_path, const Size2 p_size) const {
String temp_path = EditorSettings::get_singleton()->get_cache_dir();
String cache_base = ProjectSettings::get_singleton()->globalize_path(p_path).md5_text();
@@ -323,7 +307,11 @@ bool EditorMaterialPreviewPlugin::handles(const String &p_type) const {
return ClassDB::is_parent_class(p_type, "Material"); //any material
}
-Ref<Texture> EditorMaterialPreviewPlugin::generate(const RES &p_from) const {
+bool EditorMaterialPreviewPlugin::should_generate_small_preview() const {
+ return true;
+}
+
+Ref<Texture> EditorMaterialPreviewPlugin::generate(const RES &p_from, const Size2 p_size) const {
Ref<Material> material = p_from;
ERR_FAIL_COND_V(material.is_null(), Ref<Texture>());
@@ -346,10 +334,9 @@ Ref<Texture> EditorMaterialPreviewPlugin::generate(const RES &p_from) const {
ERR_FAIL_COND_V(!img.is_valid(), Ref<ImageTexture>());
- int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
- thumbnail_size *= EDSCALE;
img->convert(Image::FORMAT_RGBA8);
- img->resize(thumbnail_size, thumbnail_size);
+ int thumbnail_size = MAX(p_size.x, p_size.y);
+ img->resize(thumbnail_size, thumbnail_size, Image::INTERPOLATE_CUBIC);
post_process_preview(img);
Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture));
ptex->create_from_image(img, 0);
@@ -490,7 +477,7 @@ bool EditorScriptPreviewPlugin::handles(const String &p_type) const {
return ClassDB::is_parent_class(p_type, "Script");
}
-Ref<Texture> EditorScriptPreviewPlugin::generate(const RES &p_from) const {
+Ref<Texture> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size2 p_size) const {
Ref<Script> scr = p_from;
if (scr.is_null())
@@ -512,10 +499,9 @@ Ref<Texture> EditorScriptPreviewPlugin::generate(const RES &p_from) const {
int line = 0;
int col = 0;
- int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
- thumbnail_size *= EDSCALE;
Ref<Image> img;
img.instance();
+ int thumbnail_size = MAX(p_size.x, p_size.y);
img->create(thumbnail_size, thumbnail_size, 0, Image::FORMAT_RGBA8);
Color bg_color = EditorSettings::get_singleton()->get("text_editor/highlighting/background_color");
@@ -613,16 +599,15 @@ bool EditorAudioStreamPreviewPlugin::handles(const String &p_type) const {
return ClassDB::is_parent_class(p_type, "AudioStream");
}
-Ref<Texture> EditorAudioStreamPreviewPlugin::generate(const RES &p_from) const {
+Ref<Texture> EditorAudioStreamPreviewPlugin::generate(const RES &p_from, const Size2 p_size) const {
Ref<AudioStream> stream = p_from;
ERR_FAIL_COND_V(stream.is_null(), Ref<Texture>());
- int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
- thumbnail_size *= EDSCALE;
PoolVector<uint8_t> img;
- int w = thumbnail_size;
- int h = thumbnail_size;
+
+ int w = p_size.x;
+ int h = p_size.y;
img.resize(w * h * 3);
PoolVector<uint8_t>::Write imgdata = img.write();
@@ -711,7 +696,7 @@ bool EditorMeshPreviewPlugin::handles(const String &p_type) const {
return ClassDB::is_parent_class(p_type, "Mesh"); //any Mesh
}
-Ref<Texture> EditorMeshPreviewPlugin::generate(const RES &p_from) const {
+Ref<Texture> EditorMeshPreviewPlugin::generate(const RES &p_from, const Size2 p_size) const {
Ref<Mesh> mesh = p_from;
ERR_FAIL_COND_V(mesh.is_null(), Ref<Texture>());
@@ -749,10 +734,17 @@ Ref<Texture> EditorMeshPreviewPlugin::generate(const RES &p_from) const {
VS::get_singleton()->instance_set_base(mesh_instance, RID());
- int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
- thumbnail_size *= EDSCALE;
img->convert(Image::FORMAT_RGBA8);
- img->resize(thumbnail_size, thumbnail_size);
+
+ Vector2 new_size = img->get_size();
+ if (new_size.x > p_size.x) {
+ new_size = Vector2(p_size.x, new_size.y * p_size.x / new_size.x);
+ }
+ if (new_size.y > p_size.y) {
+ new_size = Vector2(new_size.x * p_size.y / new_size.y, p_size.y);
+ }
+ img->resize(new_size.x, new_size.y, Image::INTERPOLATE_CUBIC);
+
post_process_preview(img);
Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture));
@@ -825,15 +817,12 @@ bool EditorFontPreviewPlugin::handles(const String &p_type) const {
return ClassDB::is_parent_class(p_type, "DynamicFontData");
}
-Ref<Texture> EditorFontPreviewPlugin::generate_from_path(const String &p_path) const {
+Ref<Texture> EditorFontPreviewPlugin::generate_from_path(const String &p_path, const Size2 p_size) const {
Ref<DynamicFontData> SampledFont;
SampledFont.instance();
SampledFont->set_font_path(p_path);
- int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
- thumbnail_size *= EDSCALE;
-
Ref<DynamicFont> sampled_font;
sampled_font.instance();
sampled_font->set_size(50);
@@ -864,7 +853,15 @@ Ref<Texture> EditorFontPreviewPlugin::generate_from_path(const String &p_path) c
ERR_FAIL_COND_V(img.is_null(), Ref<ImageTexture>());
img->convert(Image::FORMAT_RGBA8);
- img->resize(thumbnail_size, thumbnail_size);
+
+ Vector2 new_size = img->get_size();
+ if (new_size.x > p_size.x) {
+ new_size = Vector2(p_size.x, new_size.y * p_size.x / new_size.x);
+ }
+ if (new_size.y > p_size.y) {
+ new_size = Vector2(new_size.x * p_size.y / new_size.y, p_size.y);
+ }
+ img->resize(new_size.x, new_size.y, Image::INTERPOLATE_CUBIC);
post_process_preview(img);
@@ -874,9 +871,9 @@ Ref<Texture> EditorFontPreviewPlugin::generate_from_path(const String &p_path) c
return ptex;
}
-Ref<Texture> EditorFontPreviewPlugin::generate(const RES &p_from) const {
+Ref<Texture> EditorFontPreviewPlugin::generate(const RES &p_from, const Size2 p_size) const {
- return generate_from_path(p_from->get_path());
+ return generate_from_path(p_from->get_path(), p_size);
}
EditorFontPreviewPlugin::EditorFontPreviewPlugin() {
diff --git a/editor/plugins/editor_preview_plugins.h b/editor/plugins/editor_preview_plugins.h
index 8bd7943383..ed5d2a3ecd 100644
--- a/editor/plugins/editor_preview_plugins.h
+++ b/editor/plugins/editor_preview_plugins.h
@@ -39,7 +39,8 @@ class EditorTexturePreviewPlugin : public EditorResourcePreviewGenerator {
GDCLASS(EditorTexturePreviewPlugin, EditorResourcePreviewGenerator)
public:
virtual bool handles(const String &p_type) const;
- virtual Ref<Texture> generate(const RES &p_from) const;
+ virtual bool should_generate_small_preview() const;
+ virtual Ref<Texture> generate(const RES &p_from, const Size2 p_size) const;
EditorTexturePreviewPlugin();
};
@@ -48,7 +49,8 @@ class EditorImagePreviewPlugin : public EditorResourcePreviewGenerator {
GDCLASS(EditorImagePreviewPlugin, EditorResourcePreviewGenerator)
public:
virtual bool handles(const String &p_type) const;
- virtual Ref<Texture> generate(const RES &p_from) const;
+ virtual bool should_generate_small_preview() const;
+ virtual Ref<Texture> generate(const RES &p_from, const Size2 p_size) const;
EditorImagePreviewPlugin();
};
@@ -57,7 +59,8 @@ class EditorBitmapPreviewPlugin : public EditorResourcePreviewGenerator {
GDCLASS(EditorBitmapPreviewPlugin, EditorResourcePreviewGenerator)
public:
virtual bool handles(const String &p_type) const;
- virtual Ref<Texture> generate(const RES &p_from) const;
+ virtual bool should_generate_small_preview() const;
+ virtual Ref<Texture> generate(const RES &p_from, const Size2 p_size) const;
EditorBitmapPreviewPlugin();
};
@@ -66,8 +69,8 @@ class EditorPackedScenePreviewPlugin : public EditorResourcePreviewGenerator {
public:
virtual bool handles(const String &p_type) const;
- virtual Ref<Texture> generate(const RES &p_from) const;
- virtual Ref<Texture> generate_from_path(const String &p_path) const;
+ virtual Ref<Texture> generate(const RES &p_from, const Size2 p_size) const;
+ virtual Ref<Texture> generate_from_path(const String &p_path, const Size2 p_size) const;
EditorPackedScenePreviewPlugin();
};
@@ -95,7 +98,8 @@ protected:
public:
virtual bool handles(const String &p_type) const;
- virtual Ref<Texture> generate(const RES &p_from) const;
+ virtual bool should_generate_small_preview() const;
+ virtual Ref<Texture> generate(const RES &p_from, const Size2 p_size) const;
EditorMaterialPreviewPlugin();
~EditorMaterialPreviewPlugin();
@@ -104,7 +108,7 @@ public:
class EditorScriptPreviewPlugin : public EditorResourcePreviewGenerator {
public:
virtual bool handles(const String &p_type) const;
- virtual Ref<Texture> generate(const RES &p_from) const;
+ virtual Ref<Texture> generate(const RES &p_from, const Size2 p_size) const;
EditorScriptPreviewPlugin();
};
@@ -112,7 +116,7 @@ public:
class EditorAudioStreamPreviewPlugin : public EditorResourcePreviewGenerator {
public:
virtual bool handles(const String &p_type) const;
- virtual Ref<Texture> generate(const RES &p_from) const;
+ virtual Ref<Texture> generate(const RES &p_from, const Size2 p_size) const;
EditorAudioStreamPreviewPlugin();
};
@@ -139,7 +143,7 @@ protected:
public:
virtual bool handles(const String &p_type) const;
- virtual Ref<Texture> generate(const RES &p_from) const;
+ virtual Ref<Texture> generate(const RES &p_from, const Size2 p_size) const;
EditorMeshPreviewPlugin();
~EditorMeshPreviewPlugin();
@@ -162,8 +166,8 @@ protected:
public:
virtual bool handles(const String &p_type) const;
- virtual Ref<Texture> generate(const RES &p_from) const;
- virtual Ref<Texture> generate_from_path(const String &p_path) const;
+ virtual Ref<Texture> generate(const RES &p_from, const Size2 p_size) const;
+ virtual Ref<Texture> generate_from_path(const String &p_path, const Size2 p_size) const;
EditorFontPreviewPlugin();
~EditorFontPreviewPlugin();
diff --git a/editor/plugins/light_occluder_2d_editor_plugin.cpp b/editor/plugins/light_occluder_2d_editor_plugin.cpp
index 4f8a307cc1..2f2e1dae81 100644
--- a/editor/plugins/light_occluder_2d_editor_plugin.cpp
+++ b/editor/plugins/light_occluder_2d_editor_plugin.cpp
@@ -319,13 +319,11 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
return false;
}
-void LightOccluder2DEditor::forward_draw_over_viewport(Control *p_overlay) {
+void LightOccluder2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
if (!node || !node->get_occluder_polygon().is_valid())
return;
- Control *vpc = canvas_item_editor->get_viewport_control();
-
Vector<Vector2> poly;
if (wip_active)
@@ -353,9 +351,9 @@ void LightOccluder2DEditor::forward_draw_over_viewport(Control *p_overlay) {
if (i == poly.size() - 1 && (!node->get_occluder_polygon()->is_closed() || wip_active)) {
} else {
- vpc->draw_line(point, next_point, col, 2);
+ p_overlay->draw_line(point, next_point, col, 2);
}
- vpc->draw_texture(handle, point - handle->get_size() * 0.5);
+ p_overlay->draw_texture(handle, point - handle->get_size() * 0.5);
}
}
diff --git a/editor/plugins/light_occluder_2d_editor_plugin.h b/editor/plugins/light_occluder_2d_editor_plugin.h
index 39de8b1020..a1962892ee 100644
--- a/editor/plugins/light_occluder_2d_editor_plugin.h
+++ b/editor/plugins/light_occluder_2d_editor_plugin.h
@@ -83,7 +83,7 @@ protected:
public:
Vector2 snap_point(const Vector2 &p_point) const;
- void forward_draw_over_viewport(Control *p_overlay);
+ void forward_canvas_draw_over_viewport(Control *p_overlay);
bool forward_gui_input(const Ref<InputEvent> &p_event);
void edit(Node *p_collision_polygon);
LightOccluder2DEditor(EditorNode *p_editor);
@@ -98,7 +98,7 @@ class LightOccluder2DEditorPlugin : public EditorPlugin {
public:
virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return light_occluder_editor->forward_gui_input(p_event); }
- virtual void forward_draw_over_viewport(Control *p_overlay) { return light_occluder_editor->forward_draw_over_viewport(p_overlay); }
+ virtual void forward_canvas_draw_over_viewport(Control *p_overlay) { return light_occluder_editor->forward_canvas_draw_over_viewport(p_overlay); }
virtual String get_name() const { return "LightOccluder2D"; }
bool has_main_screen() const { return false; }
diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp
index 96c1ad2f2b..88b3194490 100644
--- a/editor/plugins/path_2d_editor_plugin.cpp
+++ b/editor/plugins/path_2d_editor_plugin.cpp
@@ -288,7 +288,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
return false;
}
-void Path2DEditor::forward_draw_over_viewport(Control *p_overlay) {
+void Path2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
if (!node)
return;
diff --git a/editor/plugins/path_2d_editor_plugin.h b/editor/plugins/path_2d_editor_plugin.h
index 1e3955f84f..3a78657746 100644
--- a/editor/plugins/path_2d_editor_plugin.h
+++ b/editor/plugins/path_2d_editor_plugin.h
@@ -107,7 +107,7 @@ protected:
public:
bool forward_gui_input(const Ref<InputEvent> &p_event);
- void forward_draw_over_viewport(Control *p_overlay);
+ void forward_canvas_draw_over_viewport(Control *p_overlay);
void edit(Node *p_path2d);
Path2DEditor(EditorNode *p_editor);
};
@@ -121,7 +121,7 @@ class Path2DEditorPlugin : public EditorPlugin {
public:
virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return path2d_editor->forward_gui_input(p_event); }
- virtual void forward_draw_over_viewport(Control *p_overlay) { return path2d_editor->forward_draw_over_viewport(p_overlay); }
+ virtual void forward_canvas_draw_over_viewport(Control *p_overlay) { return path2d_editor->forward_canvas_draw_over_viewport(p_overlay); }
virtual String get_name() const { return "Path2D"; }
bool has_main_screen() const { return false; }
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index 51e58b712e..361271af89 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -426,7 +426,7 @@ void ShaderEditor::ensure_select_current() {
void ShaderEditor::edit(const Ref<Shader> &p_shader) {
- if (p_shader.is_null())
+ if (p_shader.is_null() || !p_shader->is_text_shader())
return;
shader = p_shader;
@@ -606,7 +606,7 @@ void ShaderEditorPlugin::edit(Object *p_object) {
bool ShaderEditorPlugin::handles(Object *p_object) const {
Shader *shader = Object::cast_to<Shader>(p_object);
- return shader != NULL;
+ return shader != NULL && shader->is_text_shader();
}
void ShaderEditorPlugin::make_visible(bool p_visible) {
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index fed4362405..3e6a0ae81a 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/editor/plugins/spatial_editor_plugin.cpp
@@ -2312,12 +2312,12 @@ void SpatialEditorViewport::_draw() {
EditorPluginList *over_plugin_list = EditorNode::get_singleton()->get_editor_plugins_over();
if (!over_plugin_list->empty()) {
- over_plugin_list->forward_draw_over_viewport(surface);
+ over_plugin_list->forward_spatial_draw_over_viewport(surface);
}
EditorPluginList *force_over_plugin_list = editor->get_editor_plugins_force_over();
if (!force_over_plugin_list->empty()) {
- force_over_plugin_list->forward_force_draw_over_viewport(surface);
+ force_over_plugin_list->forward_spatial_force_draw_over_viewport(surface);
}
if (surface->has_focus()) {
@@ -2346,7 +2346,6 @@ void SpatialEditorViewport::_draw() {
Point2 center = _point_to_screen(_edit.center);
VisualServer::get_singleton()->canvas_item_add_line(ci, _edit.mouse_pos, center, Color(0.4, 0.7, 1.0, 0.8));
}
-
if (previewing) {
Size2 ss = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height"));
@@ -5584,7 +5583,6 @@ void SpatialEditorPlugin::make_visible(bool p_visible) {
spatial_editor->show();
spatial_editor->set_process(true);
- spatial_editor->grab_focus();
} else {
diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
index a0adbfccff..aa4338d775 100644
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ b/editor/plugins/tile_map_editor_plugin.cpp
@@ -686,7 +686,7 @@ void TileMapEditor::_erase_selection() {
}
}
-void TileMapEditor::_draw_cell(int p_cell, const Point2i &p_point, bool p_flip_h, bool p_flip_v, bool p_transpose, const Transform2D &p_xform) {
+void TileMapEditor::_draw_cell(Control *p_viewport, int p_cell, const Point2i &p_point, bool p_flip_h, bool p_flip_v, bool p_transpose, const Transform2D &p_xform) {
Ref<Texture> t = node->get_tileset()->tile_get_texture(p_cell);
@@ -783,19 +783,19 @@ void TileMapEditor::_draw_cell(int p_cell, const Point2i &p_point, bool p_flip_h
modulate.a = 0.5;
if (r.has_no_area())
- canvas_item_editor->draw_texture_rect(t, rect, false, modulate, p_transpose);
+ p_viewport->draw_texture_rect(t, rect, false, modulate, p_transpose);
else
- canvas_item_editor->draw_texture_rect_region(t, rect, r, modulate, p_transpose);
+ p_viewport->draw_texture_rect_region(t, rect, r, modulate, p_transpose);
}
-void TileMapEditor::_draw_fill_preview(int p_cell, const Point2i &p_point, bool p_flip_h, bool p_flip_v, bool p_transpose, const Transform2D &p_xform) {
+void TileMapEditor::_draw_fill_preview(Control *p_viewport, int p_cell, const Point2i &p_point, bool p_flip_h, bool p_flip_v, bool p_transpose, const Transform2D &p_xform) {
PoolVector<Vector2> points = _bucket_fill(p_point, false, true);
PoolVector<Vector2>::Read pr = points.read();
int len = points.size();
for (int i = 0; i < len; ++i) {
- _draw_cell(p_cell, pr[i], p_flip_h, p_flip_v, p_transpose, p_xform);
+ _draw_cell(p_viewport, p_cell, pr[i], p_flip_h, p_flip_v, p_transpose, p_xform);
}
}
@@ -1390,17 +1390,17 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
return false;
}
-void TileMapEditor::forward_draw_over_viewport(Control *p_overlay) {
+void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
if (!node)
return;
Transform2D cell_xf = node->get_cell_transform();
- Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * node->get_global_transform();
+ Transform2D xform = p_overlay->get_canvas_transform() * node->get_global_transform();
Transform2D xform_inv = xform.affine_inverse();
- Size2 screen_size = canvas_item_editor->get_size();
+ Size2 screen_size = p_overlay->get_size();
{
Rect2 aabb;
aabb.position = node->world_to_map(xform_inv.xform(Vector2()));
@@ -1419,7 +1419,7 @@ void TileMapEditor::forward_draw_over_viewport(Control *p_overlay) {
Vector2 to = xform.xform(node->map_to_world(Vector2(i, si.position.y + si.size.y + 1)));
Color col = i == 0 ? Color(1, 0.8, 0.2, 0.5) : Color(1, 0.3, 0.1, 0.2);
- canvas_item_editor->draw_line(from, to, col, 1);
+ p_overlay->draw_line(from, to, col, 1);
if (max_lines-- == 0)
break;
}
@@ -1439,7 +1439,7 @@ void TileMapEditor::forward_draw_over_viewport(Control *p_overlay) {
Vector2 from = xform.xform(node->map_to_world(Vector2(i, j), true) + ofs);
Vector2 to = xform.xform(node->map_to_world(Vector2(i, j + 1), true) + ofs);
Color col = i == 0 ? Color(1, 0.8, 0.2, 0.5) : Color(1, 0.3, 0.1, 0.2);
- canvas_item_editor->draw_line(from, to, col, 1);
+ p_overlay->draw_line(from, to, col, 1);
if (max_lines-- == 0)
break;
@@ -1457,7 +1457,7 @@ void TileMapEditor::forward_draw_over_viewport(Control *p_overlay) {
Vector2 to = xform.xform(node->map_to_world(Vector2(si.position.x + si.size.x + 1, i)));
Color col = i == 0 ? Color(1, 0.8, 0.2, 0.5) : Color(1, 0.3, 0.1, 0.2);
- canvas_item_editor->draw_line(from, to, col, 1);
+ p_overlay->draw_line(from, to, col, 1);
if (max_lines-- == 0)
break;
@@ -1476,7 +1476,7 @@ void TileMapEditor::forward_draw_over_viewport(Control *p_overlay) {
Vector2 from = xform.xform(node->map_to_world(Vector2(j, i), true) + ofs);
Vector2 to = xform.xform(node->map_to_world(Vector2(j + 1, i), true) + ofs);
Color col = i == 0 ? Color(1, 0.8, 0.2, 0.5) : Color(1, 0.3, 0.1, 0.2);
- canvas_item_editor->draw_line(from, to, col, 1);
+ p_overlay->draw_line(from, to, col, 1);
if (max_lines-- == 0)
break;
@@ -1493,7 +1493,7 @@ void TileMapEditor::forward_draw_over_viewport(Control *p_overlay) {
points.push_back(xform.xform(node->map_to_world((rectangle.position + Point2(rectangle.size.x + 1, rectangle.size.y + 1)))));
points.push_back(xform.xform(node->map_to_world((rectangle.position + Point2(0, rectangle.size.y + 1)))));
- canvas_item_editor->draw_colored_polygon(points, Color(0.2, 0.8, 1, 0.4));
+ p_overlay->draw_colored_polygon(points, Color(0.2, 0.8, 1, 0.4));
}
if (mouse_over) {
@@ -1519,7 +1519,7 @@ void TileMapEditor::forward_draw_over_viewport(Control *p_overlay) {
col = Color(1.0, 0.4, 0.2, 0.8);
for (int i = 0; i < 4; i++)
- canvas_item_editor->draw_line(endpoints[i], endpoints[(i + 1) % 4], col, 2);
+ p_overlay->draw_line(endpoints[i], endpoints[(i + 1) % 4], col, 2);
bool bucket_preview = EditorSettings::get_singleton()->get("editors/tile_map/bucket_fill_preview");
if (tool == TOOL_SELECTING || tool == TOOL_PICKING || !bucket_preview) {
@@ -1538,7 +1538,7 @@ void TileMapEditor::forward_draw_over_viewport(Control *p_overlay) {
for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) {
- _draw_cell(ids[0], E->key(), flip_h, flip_v, transpose, xform);
+ _draw_cell(p_overlay, ids[0], E->key(), flip_h, flip_v, transpose, xform);
}
} else if (tool == TOOL_RECTANGLE_PAINT) {
@@ -1551,7 +1551,7 @@ void TileMapEditor::forward_draw_over_viewport(Control *p_overlay) {
for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) {
for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) {
- _draw_cell(ids[0], Point2i(j, i), flip_h, flip_v, transpose, xform);
+ _draw_cell(p_overlay, ids[0], Point2i(j, i), flip_h, flip_v, transpose, xform);
}
}
} else if (tool == TOOL_PASTING) {
@@ -1573,7 +1573,7 @@ void TileMapEditor::forward_draw_over_viewport(Control *p_overlay) {
TileData tcd = E->get();
- _draw_cell(tcd.cell, tcd.pos + ofs, tcd.flip_h, tcd.flip_v, tcd.transpose, xform);
+ _draw_cell(p_overlay, tcd.cell, tcd.pos + ofs, tcd.flip_h, tcd.flip_v, tcd.transpose, xform);
}
Rect2i duplicate = rectangle;
@@ -1585,12 +1585,12 @@ void TileMapEditor::forward_draw_over_viewport(Control *p_overlay) {
points.push_back(xform.xform(node->map_to_world((duplicate.position + Point2(duplicate.size.x + 1, duplicate.size.y + 1)))));
points.push_back(xform.xform(node->map_to_world((duplicate.position + Point2(0, duplicate.size.y + 1)))));
- canvas_item_editor->draw_colored_polygon(points, Color(0.2, 1.0, 0.8, 0.2));
+ p_overlay->draw_colored_polygon(points, Color(0.2, 1.0, 0.8, 0.2));
} else if (tool == TOOL_BUCKET) {
Vector<int> tiles = get_selected_tiles();
- _draw_fill_preview(tiles[0], over_tile, flip_h, flip_v, transpose, xform);
+ _draw_fill_preview(p_overlay, tiles[0], over_tile, flip_h, flip_v, transpose, xform);
} else {
@@ -1599,7 +1599,7 @@ void TileMapEditor::forward_draw_over_viewport(Control *p_overlay) {
if (st.size() == 1 && st[0] == TileMap::INVALID_CELL)
return;
- _draw_cell(st[0], over_tile, flip_h, flip_v, transpose, xform);
+ _draw_cell(p_overlay, st[0], over_tile, flip_h, flip_v, transpose, xform);
}
}
}
diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h
index c824824d56..74aece6f47 100644
--- a/editor/plugins/tile_map_editor_plugin.h
+++ b/editor/plugins/tile_map_editor_plugin.h
@@ -168,8 +168,8 @@ class TileMapEditor : public VBoxContainer {
void _select(const Point2i &p_from, const Point2i &p_to);
void _erase_selection();
- void _draw_cell(int p_cell, const Point2i &p_point, bool p_flip_h, bool p_flip_v, bool p_transpose, const Transform2D &p_xform);
- void _draw_fill_preview(int p_cell, const Point2i &p_point, bool p_flip_h, bool p_flip_v, bool p_transpose, const Transform2D &p_xform);
+ void _draw_cell(Control *p_viewport, int p_cell, const Point2i &p_point, bool p_flip_h, bool p_flip_v, bool p_transpose, const Transform2D &p_xform);
+ void _draw_fill_preview(Control *p_viewport, int p_cell, const Point2i &p_point, bool p_flip_h, bool p_flip_v, bool p_transpose, const Transform2D &p_xform);
void _clear_bucket_cache();
void _update_copydata();
@@ -206,7 +206,7 @@ public:
HBoxContainer *get_toolbar() const { return toolbar; }
bool forward_gui_input(const Ref<InputEvent> &p_event);
- void forward_draw_over_viewport(Control *p_overlay);
+ void forward_canvas_draw_over_viewport(Control *p_overlay);
void edit(Node *p_tile_map);
@@ -225,7 +225,7 @@ protected:
public:
virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return tile_map_editor->forward_gui_input(p_event); }
- virtual void forward_draw_over_viewport(Control *p_overlay) { tile_map_editor->forward_draw_over_viewport(p_overlay); }
+ virtual void forward_canvas_draw_over_viewport(Control *p_overlay) { tile_map_editor->forward_canvas_draw_over_viewport(p_overlay); }
virtual String get_name() const { return "TileMap"; }
bool has_main_screen() const { return false; }
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 207078d90f..39e50ec7f8 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -510,6 +510,17 @@ void VisualShaderEditor::_connection_request(const String &p_from, int p_from_in
}
undo_redo->create_action("Nodes Connected");
+
+ List<VisualShader::Connection> conns;
+ visual_shader->get_node_connections(type, &conns);
+
+ for (List<VisualShader::Connection>::Element *E = conns.front(); E; E = E->next()) {
+ if (E->get().to_node == to && E->get().to_port == p_to_index) {
+ undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
+ undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
+ }
+ }
+
undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from, p_from_index, to, p_to_index);
undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index);
undo_redo->add_do_method(this, "_update_graph");
diff --git a/main/main.cpp b/main/main.cpp
index db82ff8f6e..dac646ba70 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -77,63 +77,95 @@
#include "editor/project_manager.h"
#endif
-static ProjectSettings *globals = NULL;
+/* Static members */
+
+// Singletons
+
+// Initialized in setup()
static Engine *engine = NULL;
+static ProjectSettings *globals = NULL;
static InputMap *input_map = NULL;
-static bool _start_success = false;
-static ScriptDebugger *script_debugger = NULL;
-AudioServer *audio_server = NULL;
-ARVRServer *arvr_server = NULL;
-PhysicsServer *physics_server = NULL;
-Physics2DServer *physics_2d_server = NULL;
-
-static MessageQueue *message_queue = NULL;
+static TranslationServer *translation_server = NULL;
static Performance *performance = NULL;
-
static PackedData *packed_data = NULL;
#ifdef MINIZIP_ENABLED
static ZipArchive *zip_packed_data = NULL;
#endif
static FileAccessNetworkClient *file_access_network_client = NULL;
-static TranslationServer *translation_server = NULL;
+static ScriptDebugger *script_debugger = NULL;
+static MessageQueue *message_queue = NULL;
+
+// Initialized in setup2()
+static AudioServer *audio_server = NULL;
+static ARVRServer *arvr_server = NULL;
+static PhysicsServer *physics_server = NULL;
+static Physics2DServer *physics_2d_server = NULL;
+// We error out if setup2() doesn't turn this true
+static bool _start_success = false;
+
+// Drivers
+
+static int video_driver_idx = -1;
+static int audio_driver_idx = -1;
+
+// Engine config/tools
+
+static bool editor = false;
+static bool project_manager = false;
+static String locale;
+static bool show_help = false;
+static bool auto_build_solutions = false;
+static bool auto_quit = false;
+static OS::ProcessID allow_focus_steal_pid = 0;
+
+// Display
static OS::VideoMode video_mode;
+static int init_screen = -1;
+static bool init_fullscreen = false;
static bool init_maximized = false;
static bool init_windowed = false;
-static bool init_fullscreen = false;
static bool init_always_on_top = false;
static bool init_use_custom_pos = false;
+static Vector2 init_custom_pos;
+static bool force_lowdpi = false;
+static bool use_vsync = true;
+
+// Debug
+
+static bool use_debug_profiler = false;
#ifdef DEBUG_ENABLED
static bool debug_collisions = false;
static bool debug_navigation = false;
#endif
static int frame_delay = 0;
-static Vector2 init_custom_pos;
-static int video_driver_idx = -1;
-static int audio_driver_idx = -1;
-static String locale;
-static bool use_debug_profiler = false;
-static bool force_lowdpi = false;
-static int init_screen = -1;
-static bool use_vsync = true;
-static bool editor = false;
-static bool show_help = false;
static bool disable_render_loop = false;
static int fixed_fps = -1;
-static bool auto_build_solutions = false;
-static bool auto_quit = false;
static bool print_fps = false;
-static OS::ProcessID allow_focus_steal_pid = 0;
-
-static bool project_manager = false;
+/* Helper methods */
+// Used by Mono module, should likely be registered in Engine singleton instead
+// FIXME: This is also not 100% accurate, `project_manager` is only true when it was requested,
+// but not if e.g. we fail to load and project and fallback to the manager.
bool Main::is_project_manager() {
return project_manager;
}
-void initialize_physics() {
+static String unescape_cmdline(const String &p_str) {
+ return p_str.replace("%20", " ");
+}
+static String get_full_version_string() {
+ String hash = String(VERSION_HASH);
+ if (hash.length() != 0)
+ hash = "." + hash.left(7);
+ return String(VERSION_FULL_BUILD) + hash;
+}
+
+// FIXME: Could maybe be moved to PhysicsServerManager and Physics2DServerManager directly
+// to have less code in main.cpp.
+void initialize_physics() {
/// 3D Physics Server
physics_server = PhysicsServerManager::new_server(ProjectSettings::get_singleton()->get(PhysicsServerManager::setting_property_name));
if (!physics_server) {
@@ -161,19 +193,6 @@ void finalize_physics() {
memdelete(physics_2d_server);
}
-static String unescape_cmdline(const String &p_str) {
-
- return p_str.replace("%20", " ");
-}
-
-static String get_full_version_string() {
-
- String hash = String(VERSION_HASH);
- if (hash.length() != 0)
- hash = "." + hash.left(7);
- return String(VERSION_FULL_BUILD) + hash;
-}
-
//#define DEBUG_INIT
#ifdef DEBUG_INIT
#define MAIN_PRINT(m_txt) print_line(m_txt)
@@ -278,6 +297,32 @@ void Main::print_help(const char *p_binary) {
#endif
}
+/* Engine initialization
+ *
+ * Consists of several methods that are called by each platform's specific main(argc, argv).
+ * To fully understand engine init, one should therefore start from the platform's main and
+ * see how it calls into the Main class' methods.
+ *
+ * The initialization is typically done in 3 steps (with the setup2 step triggered either
+ * automatically by setup, or manually in the platform's main).
+ *
+ * - setup(execpath, argc, argv, p_second_phase) is the main entry point for all platforms,
+ * responsible for the initialization of all low level singletons and core types, and parsing
+ * command line arguments to configure things accordingly.
+ * If p_second_phase is true, it will chain into setup2() (default behaviour). This is
+ * disabled on some platforms (Android, iOS, UWP) which trigger the second step in their
+ * own time.
+ *
+ * - setup2(p_main_tid_override) registers high level servers and singletons, displays the
+ * boot splash, then registers higher level types (scene, editor, etc.).
+ *
+ * - start() is the last step and that's where command line tools can run, or the main loop
+ * can be created eventually and the project settings put into action. That's also where
+ * the editor node is created, if relevant.
+ * start() does it own argument parsing for a subset of the command line arguments described
+ * in help, it's a bit messy and should be globalized with the setup() parsing somehow.
+ */
+
Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_phase) {
RID_OwnerBase::init_rid();
@@ -1003,15 +1048,6 @@ error:
if (file_access_network_client)
memdelete(file_access_network_client);
- // Note 1: *zip_packed_data live into *packed_data
- // Note 2: PackedData::~PackedData destroy this.
- /*
-#ifdef MINIZIP_ENABLED
- if (zip_packed_data)
- memdelete( zip_packed_data );
-#endif
-*/
-
unregister_core_driver_types();
unregister_core_types();
@@ -1210,7 +1246,6 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
}
// everything the main loop needs to know about frame timings
-
static MainTimerSync main_timer_sync;
bool Main::start() {
@@ -1713,13 +1748,23 @@ bool Main::start() {
return true;
}
+/* Main iteration
+ *
+ * This is the iteration of the engine's game loop, advancing the state of physics,
+ * rendering and audio.
+ * It's called directly by the platform's OS::run method, where the loop is created
+ * and monitored.
+ *
+ * The OS implementation can impact its draw step with the Main::force_redraw() method.
+ */
+
uint64_t Main::last_ticks = 0;
uint64_t Main::target_ticks = 0;
uint32_t Main::frames = 0;
uint32_t Main::frame = 0;
bool Main::force_redraw_requested = false;
-//for performance metrics
+// For performance metrics
static uint64_t physics_process_max = 0;
static uint64_t idle_process_max = 0;
@@ -1743,11 +1788,6 @@ bool Main::iteration() {
Engine::get_singleton()->_frame_step = step;
- /*
- if (time_accum+step < frame_slice)
- return false;
- */
-
uint64_t physics_process_ticks = 0;
uint64_t idle_process_ticks = 0;
@@ -1891,9 +1931,15 @@ bool Main::iteration() {
}
void Main::force_redraw() {
-
force_redraw_requested = true;
-};
+}
+
+/* Engine deinitialization
+ *
+ * Responsible for freeing all the memory allocated by previous setup steps,
+ * so that the engine closes cleanly without leaking memory or crashing.
+ * The order matters as some of those steps are linked with each other.
+ */
void Main::cleanup() {
diff --git a/main/main.h b/main/main.h
index bd56e21d94..23a19dddec 100644
--- a/main/main.h
+++ b/main/main.h
@@ -49,13 +49,16 @@ class Main {
static bool force_redraw_requested;
public:
+ static bool is_project_manager();
+
static Error setup(const char *execpath, int argc, char *argv[], bool p_second_phase = true);
static Error setup2(Thread::ID p_main_tid_override = 0);
static bool start();
+
static bool iteration();
- static void cleanup();
static void force_redraw();
- static bool is_project_manager();
+
+ static void cleanup();
};
-#endif
+#endif // MAIN_H
diff --git a/modules/opensimplex/doc_classes/SimplexNoise.xml b/modules/opensimplex/doc_classes/SimplexNoise.xml
index de29ff874c..5b3af1cd67 100644
--- a/modules/opensimplex/doc_classes/SimplexNoise.xml
+++ b/modules/opensimplex/doc_classes/SimplexNoise.xml
@@ -14,7 +14,7 @@
noise.seed = randi()
noise.octaves = 4
noise.period = 20.0
- noise.persistance = 0.8
+ noise.persistence = 0.8
# Sample
print("Values:")
@@ -118,9 +118,9 @@
Period of the base octave.
A lower period results in a higher-frequency noise (more value changes across the same distance).
</member>
- <member name="persistance" type="float" setter="set_persistance" getter="get_persistance">
+ <member name="persistence" type="float" setter="set_persistence" getter="get_persistence">
Contribution factor of the different octaves.
- A [code]persistance[/code] value of 1 means all the octaves have the same contribution, a value of 0.5 means each octave contributes half as much as the previous one.
+ A [code]persistence[/code] value of 1 means all the octaves have the same contribution, a value of 0.5 means each octave contributes half as much as the previous one.
</member>
<member name="seed" type="int" setter="set_seed" getter="get_seed">
Seed used to generate random values, different seeds will generate different noise maps.
diff --git a/scene/2d/navigation2d.cpp b/scene/2d/navigation2d.cpp
index 9eec8e6cc3..1b789bab9d 100644
--- a/scene/2d/navigation2d.cpp
+++ b/scene/2d/navigation2d.cpp
@@ -388,10 +388,34 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
Polygon *p = E->get();
float cost = p->distance;
- cost += p->center.distance_to(end_point);
- if (cost < least_cost) {
+#ifdef USE_ENTRY_POINT
+ int es = p->edges.size();
+ float shortest_distance = 1e30;
+
+ for (int i = 0; i < es; i++) {
+ Polygon::Edge &e = p->edges.write[i];
+
+ if (!e.C)
+ continue;
+
+ Vector2 edge[2] = {
+ _get_vertex(p->edges[i].point),
+ _get_vertex(p->edges[(i + 1) % es].point)
+ };
+
+ Vector2 edge_point = Geometry::get_closest_point_to_segment_2d(p->entry, edge);
+ float dist = p->entry.distance_to(edge_point);
+ if (dist < shortest_distance)
+ shortest_distance = dist;
+ }
+
+ cost += shortest_distance;
+#else
+ cost += p->center.distance_to(end_point);
+#endif
+ if (cost < least_cost) {
least_cost_poly = E;
least_cost = cost;
}
diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp
index 8d84d2408c..54f74c2df3 100644
--- a/scene/3d/navigation.cpp
+++ b/scene/3d/navigation.cpp
@@ -30,6 +30,8 @@
#include "navigation.h"
+#define USE_ENTRY_POINT
+
void Navigation::_navmesh_link(int p_id) {
ERR_FAIL_COND(!navmesh_map.has(p_id));
@@ -331,7 +333,18 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector
if (begin_poly->edges[i].C) {
begin_poly->edges[i].C->prev_edge = begin_poly->edges[i].C_edge;
+#ifdef USE_ENTRY_POINT
+ Vector3 edge[2] = {
+ _get_vertex(begin_poly->edges[i].point),
+ _get_vertex(begin_poly->edges[(i + 1) % begin_poly->edges.size()].point)
+ };
+
+ Vector3 entry = Geometry::get_closest_point_to_segment(begin_poly->entry, edge);
+ begin_poly->edges[i].C->distance = begin_poly->entry.distance_to(entry);
+ begin_poly->edges[i].C->entry = entry;
+#else
begin_poly->edges[i].C->distance = begin_poly->center.distance_to(begin_poly->edges[i].C->center);
+#endif
open_list.push_back(begin_poly->edges[i].C);
if (begin_poly->edges[i].C == end_poly) {
@@ -356,10 +369,33 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector
Polygon *p = E->get();
float cost = p->distance;
- cost += p->center.distance_to(end_point);
+#ifdef USE_ENTRY_POINT
+ int es = p->edges.size();
- if (cost < least_cost) {
+ float shortest_distance = 1e30;
+
+ for (int i = 0; i < es; i++) {
+ Polygon::Edge &e = p->edges.write[i];
+
+ if (!e.C)
+ continue;
+ Vector3 edge[2] = {
+ _get_vertex(p->edges[i].point),
+ _get_vertex(p->edges[(i + 1) % es].point)
+ };
+
+ Vector3 edge_point = Geometry::get_closest_point_to_segment(p->entry, edge);
+ float dist = p->entry.distance_to(edge_point);
+ if (dist < shortest_distance)
+ shortest_distance = dist;
+ }
+
+ cost += shortest_distance;
+#else
+ cost += p->center.distance_to(end_point);
+#endif
+ if (cost < least_cost) {
least_cost_poly = E;
least_cost = cost;
}
diff --git a/scene/3d/navigation.h b/scene/3d/navigation.h
index 5a501039c8..8f200997cd 100644
--- a/scene/3d/navigation.h
+++ b/scene/3d/navigation.h
@@ -94,6 +94,7 @@ class Navigation : public Spatial {
Vector<Edge> edges;
Vector3 center;
+ Vector3 entry;
float distance;
int prev_edge;
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 50bf8f38f7..b78b3a6ffb 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -178,6 +178,7 @@ PoolVector<int> BitmapFont::_get_kernings() const {
void BitmapFont::_set_textures(const Vector<Variant> &p_textures) {
+ textures.clear();
for (int i = 0; i < p_textures.size(); i++) {
Ref<Texture> tex = p_textures[i];
ERR_CONTINUE(!tex.is_valid());
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index 1bfc41bd92..66bf3b4991 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -126,6 +126,11 @@ void Shader::get_default_texture_param_list(List<StringName> *r_textures) const
r_textures->push_back(E->key());
}
}
+
+bool Shader::is_text_shader() const {
+ return true;
+}
+
bool Shader::has_param(const StringName &p_param) const {
return params_cache.has(p_param);
@@ -235,8 +240,10 @@ Error ResourceFormatSaverShader::save(const String &p_path, const RES &p_resourc
void ResourceFormatSaverShader::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
- if (Object::cast_to<Shader>(*p_resource)) {
- p_extensions->push_back("shader");
+ if (const Shader *shader = Object::cast_to<Shader>(*p_resource)) {
+ if (shader->is_text_shader()) {
+ p_extensions->push_back("shader");
+ }
}
}
bool ResourceFormatSaverShader::recognize(const RES &p_resource) const {
diff --git a/scene/resources/shader.h b/scene/resources/shader.h
index 6c91205c0c..c2c205237f 100644
--- a/scene/resources/shader.h
+++ b/scene/resources/shader.h
@@ -79,6 +79,8 @@ public:
Ref<Texture> get_default_texture_param(const StringName &p_param) const;
void get_default_texture_param_list(List<StringName> *r_textures) const;
+ virtual bool is_text_shader() const;
+
_FORCE_INLINE_ StringName remap_param(const StringName &p_param) const {
if (params_cache_dirty)
get_param_list(NULL);
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 6bfb6ec5bf..f12ea8f2bb 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -414,6 +414,10 @@ Shader::Mode VisualShader::get_mode() const {
return shader_mode;
}
+bool VisualShader::is_text_shader() const {
+ return false;
+}
+
String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port, Vector<DefaultTextureParam> &default_tex_params) const {
Ref<VisualShaderNode> node = get_node(p_type, p_node);
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index 70d2425304..2867daac3a 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -141,6 +141,8 @@ public:
void set_mode(Mode p_mode);
virtual Mode get_mode() const;
+ virtual bool is_text_shader() const;
+
void set_graph_offset(const Vector2 &p_offset);
Vector2 get_graph_offset() const;