summaryrefslogtreecommitdiff
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/debugger/editor_debugger_node.cpp27
-rw-r--r--editor/debugger/editor_debugger_node.h5
-rw-r--r--editor/debugger/script_editor_debugger.cpp63
-rw-r--r--editor/debugger/script_editor_debugger.h15
-rw-r--r--editor/editor_feature_profile.cpp17
-rw-r--r--editor/editor_feature_profile.h2
-rw-r--r--editor/editor_node.cpp10
-rw-r--r--editor/editor_plugin.cpp10
-rw-r--r--editor/editor_plugin.h4
-rw-r--r--editor/plugins/editor_debugger_plugin.cpp124
-rw-r--r--editor/plugins/editor_debugger_plugin.h64
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp2
-rw-r--r--editor/plugins/theme_editor_plugin.cpp6
-rw-r--r--editor/project_manager.cpp572
-rw-r--r--editor/project_manager.h78
-rw-r--r--editor/project_settings_editor.cpp1
-rw-r--r--editor/script_create_dialog.cpp10
-rw-r--r--editor/settings_config_dialog.cpp2
18 files changed, 614 insertions, 398 deletions
diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp
index a9c18138d8..b461ac4f35 100644
--- a/editor/debugger/editor_debugger_node.cpp
+++ b/editor/debugger/editor_debugger_node.cpp
@@ -34,6 +34,7 @@
#include "editor/debugger/script_editor_debugger.h"
#include "editor/editor_log.h"
#include "editor/editor_node.h"
+#include "editor/plugins/editor_debugger_plugin.h"
#include "editor/plugins/script_editor_plugin.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/tab_container.h"
@@ -114,6 +115,12 @@ ScriptEditorDebugger *EditorDebuggerNode::_add_debugger() {
tabs->add_theme_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox("DebuggerPanel", "EditorStyles"));
}
+ if (!debugger_plugins.empty()) {
+ for (Set<Ref<Script>>::Element *i = debugger_plugins.front(); i; i = i->next()) {
+ node->add_debugger_plugin(i->get());
+ }
+ }
+
return node;
}
@@ -618,3 +625,23 @@ void EditorDebuggerNode::live_debug_reparent_node(const NodePath &p_at, const No
dbg->live_debug_reparent_node(p_at, p_new_place, p_new_name, p_at_pos);
});
}
+
+void EditorDebuggerNode::add_debugger_plugin(const Ref<Script> &p_script) {
+ ERR_FAIL_COND_MSG(debugger_plugins.has(p_script), "Debugger plugin already exists.");
+ ERR_FAIL_COND_MSG(p_script.is_null(), "Debugger plugin script is null");
+ ERR_FAIL_COND_MSG(String(p_script->get_instance_base_type()) == "", "Debugger plugin script has error.");
+ ERR_FAIL_COND_MSG(String(p_script->get_instance_base_type()) != "EditorDebuggerPlugin", "Base type of debugger plugin is not 'EditorDebuggerPlugin'.");
+ ERR_FAIL_COND_MSG(!p_script->is_tool(), "Debugger plugin script is not in tool mode.");
+ debugger_plugins.insert(p_script);
+ for (int i = 0; get_debugger(i); i++) {
+ get_debugger(i)->add_debugger_plugin(p_script);
+ }
+}
+
+void EditorDebuggerNode::remove_debugger_plugin(const Ref<Script> &p_script) {
+ ERR_FAIL_COND_MSG(!debugger_plugins.has(p_script), "Debugger plugin doesn't exists.");
+ debugger_plugins.erase(p_script);
+ for (int i = 0; get_debugger(i); i++) {
+ get_debugger(i)->remove_debugger_plugin(p_script);
+ }
+}
diff --git a/editor/debugger/editor_debugger_node.h b/editor/debugger/editor_debugger_node.h
index ff9601c026..8d70a7f961 100644
--- a/editor/debugger/editor_debugger_node.h
+++ b/editor/debugger/editor_debugger_node.h
@@ -103,6 +103,8 @@ private:
CameraOverride camera_override = OVERRIDE_NONE;
Map<Breakpoint, bool> breakpoints;
+ Set<Ref<Script>> debugger_plugins;
+
ScriptEditorDebugger *_add_debugger();
EditorDebuggerRemoteObject *get_inspected_remote_object();
@@ -186,5 +188,8 @@ public:
Error start(const String &p_protocol = "tcp://");
void stop();
+
+ void add_debugger_plugin(const Ref<Script> &p_script);
+ void remove_debugger_plugin(const Ref<Script> &p_script);
};
#endif // EDITOR_DEBUGGER_NODE_H
diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp
index 49bf068be7..1fca95b6da 100644
--- a/editor/debugger/script_editor_debugger.cpp
+++ b/editor/debugger/script_editor_debugger.cpp
@@ -44,6 +44,7 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
+#include "editor/plugins/editor_debugger_plugin.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "editor/property_editor.h"
#include "main/performance.h"
@@ -701,7 +702,28 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
performance_profiler->update_monitors(monitors);
} else {
- WARN_PRINT("unknown message " + p_msg);
+ int colon_index = p_msg.find_char(':');
+ ERR_FAIL_COND_MSG(colon_index < 1, "Invalid message received");
+
+ bool parsed = false;
+ const String cap = p_msg.substr(0, colon_index);
+ Map<StringName, Callable>::Element *element = captures.find(cap);
+ if (element) {
+ Callable &c = element->value();
+ ERR_FAIL_COND_MSG(c.is_null(), "Invalid callable registered: " + cap);
+ Variant cmd = p_msg.substr(colon_index + 1), data = p_data;
+ const Variant *args[2] = { &cmd, &data };
+ Variant retval;
+ Callable::CallError err;
+ c.call(args, 2, retval, err);
+ ERR_FAIL_COND_MSG(err.error != Callable::CallError::CALL_OK, "Error calling 'capture' to callable: " + Variant::get_callable_error_text(c, args, 2, err));
+ ERR_FAIL_COND_MSG(retval.get_type() != Variant::BOOL, "Error calling 'capture' to callable: " + String(c) + ". Return type is not bool.");
+ parsed = retval;
+ }
+
+ if (!parsed) {
+ WARN_PRINT("unknown message " + p_msg);
+ }
}
}
@@ -847,6 +869,7 @@ void ScriptEditorDebugger::start(Ref<RemoteDebuggerPeer> p_peer) {
tabs->set_current_tab(0);
_set_reason_text(TTR("Debug session started."), MESSAGE_SUCCESS);
_update_buttons_state();
+ emit_signal("started");
}
void ScriptEditorDebugger::_update_buttons_state() {
@@ -1395,6 +1418,7 @@ void ScriptEditorDebugger::_bind_methods() {
ClassDB::bind_method(D_METHOD("request_remote_object", "id"), &ScriptEditorDebugger::request_remote_object);
ClassDB::bind_method(D_METHOD("update_remote_object", "id", "property", "value"), &ScriptEditorDebugger::update_remote_object);
+ ADD_SIGNAL(MethodInfo("started"));
ADD_SIGNAL(MethodInfo("stopped"));
ADD_SIGNAL(MethodInfo("stop_requested"));
ADD_SIGNAL(MethodInfo("stack_frame_selected", PropertyInfo(Variant::INT, "frame")));
@@ -1408,6 +1432,43 @@ void ScriptEditorDebugger::_bind_methods() {
ADD_SIGNAL(MethodInfo("remote_tree_updated"));
}
+void ScriptEditorDebugger::add_debugger_plugin(const Ref<Script> &p_script) {
+ if (!debugger_plugins.has(p_script)) {
+ EditorDebuggerPlugin *plugin = memnew(EditorDebuggerPlugin());
+ plugin->attach_debugger(this);
+ plugin->set_script(p_script);
+ tabs->add_child(plugin);
+ debugger_plugins.insert(p_script, plugin);
+ }
+}
+
+void ScriptEditorDebugger::remove_debugger_plugin(const Ref<Script> &p_script) {
+ if (debugger_plugins.has(p_script)) {
+ tabs->remove_child(debugger_plugins[p_script]);
+ debugger_plugins[p_script]->detach_debugger(false);
+ memdelete(debugger_plugins[p_script]);
+ debugger_plugins.erase(p_script);
+ }
+}
+
+void ScriptEditorDebugger::send_message(const String &p_message, const Array &p_args) {
+ _put_msg(p_message, p_args);
+}
+
+void ScriptEditorDebugger::register_message_capture(const StringName &p_name, const Callable &p_callable) {
+ ERR_FAIL_COND_MSG(has_capture(p_name), "Capture already registered: " + p_name);
+ captures.insert(p_name, p_callable);
+}
+
+void ScriptEditorDebugger::unregister_message_capture(const StringName &p_name) {
+ ERR_FAIL_COND_MSG(!has_capture(p_name), "Capture not registered: " + p_name);
+ captures.erase(p_name);
+}
+
+bool ScriptEditorDebugger::has_capture(const StringName &p_name) {
+ return captures.has(p_name);
+}
+
ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) {
editor = p_editor;
diff --git a/editor/debugger/script_editor_debugger.h b/editor/debugger/script_editor_debugger.h
index 6e5699e929..56b34e8e8c 100644
--- a/editor/debugger/script_editor_debugger.h
+++ b/editor/debugger/script_editor_debugger.h
@@ -54,6 +54,7 @@ class EditorVisualProfiler;
class EditorNetworkProfiler;
class EditorPerformanceProfiler;
class SceneDebuggerTree;
+class EditorDebuggerPlugin;
class ScriptEditorDebugger : public MarginContainer {
GDCLASS(ScriptEditorDebugger, MarginContainer);
@@ -146,6 +147,10 @@ private:
EditorDebuggerNode::CameraOverride camera_override;
+ Map<Ref<Script>, EditorDebuggerPlugin *> debugger_plugins;
+
+ Map<StringName, Callable> captures;
+
void _stack_dump_frame_selected();
void _file_selected(const String &p_file);
@@ -253,6 +258,16 @@ public:
bool is_skip_breakpoints();
virtual Size2 get_minimum_size() const override;
+
+ void add_debugger_plugin(const Ref<Script> &p_script);
+ void remove_debugger_plugin(const Ref<Script> &p_script);
+
+ void send_message(const String &p_message, const Array &p_args);
+
+ void register_message_capture(const StringName &p_name, const Callable &p_callable);
+ void unregister_message_capture(const StringName &p_name);
+ bool has_capture(const StringName &p_name);
+
ScriptEditorDebugger(EditorNode *p_editor = nullptr);
~ScriptEditorDebugger();
};
diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp
index f68cc3b323..418370a7c3 100644
--- a/editor/editor_feature_profile.cpp
+++ b/editor/editor_feature_profile.cpp
@@ -41,9 +41,9 @@ const char *EditorFeatureProfile::feature_names[FEATURE_MAX] = {
TTRC("Script Editor"),
TTRC("Asset Library"),
TTRC("Scene Tree Editing"),
- TTRC("Import Dock"),
TTRC("Node Dock"),
- TTRC("FileSystem and Import Docks")
+ TTRC("FileSystem Dock"),
+ TTRC("Import Dock"),
};
const char *EditorFeatureProfile::feature_identifiers[FEATURE_MAX] = {
@@ -51,9 +51,9 @@ const char *EditorFeatureProfile::feature_identifiers[FEATURE_MAX] = {
"script",
"asset_lib",
"scene_tree",
- "import_dock",
"node_dock",
- "filesystem_dock"
+ "filesystem_dock",
+ "import_dock",
};
void EditorFeatureProfile::set_disable_class(const StringName &p_class, bool p_disabled) {
@@ -678,9 +678,16 @@ void EditorFeatureProfileManager::_update_selected_profile() {
TreeItem *root = class_list->create_item();
TreeItem *features = class_list->create_item(root);
+ TreeItem *last_feature;
features->set_text(0, TTR("Enabled Features:"));
for (int i = 0; i < EditorFeatureProfile::FEATURE_MAX; i++) {
- TreeItem *feature = class_list->create_item(features);
+ TreeItem *feature;
+ if (i == EditorFeatureProfile::FEATURE_IMPORT_DOCK) {
+ feature = class_list->create_item(last_feature);
+ } else {
+ feature = class_list->create_item(features);
+ last_feature = feature;
+ }
feature->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
feature->set_text(0, TTRGET(EditorFeatureProfile::get_feature_name(EditorFeatureProfile::Feature(i))));
feature->set_selectable(0, true);
diff --git a/editor/editor_feature_profile.h b/editor/editor_feature_profile.h
index 38413e35a2..d0d08c61f4 100644
--- a/editor/editor_feature_profile.h
+++ b/editor/editor_feature_profile.h
@@ -49,9 +49,9 @@ public:
FEATURE_SCRIPT,
FEATURE_ASSET_LIB,
FEATURE_SCENE_TREE,
- FEATURE_IMPORT_DOCK,
FEATURE_NODE_DOCK,
FEATURE_FILESYSTEM_DOCK,
+ FEATURE_IMPORT_DOCK,
FEATURE_MAX
};
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 381ff88890..26281a232b 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -123,6 +123,7 @@
#include "editor/plugins/cpu_particles_3d_editor_plugin.h"
#include "editor/plugins/curve_editor_plugin.h"
#include "editor/plugins/debugger_editor_plugin.h"
+#include "editor/plugins/editor_debugger_plugin.h"
#include "editor/plugins/editor_preview_plugins.h"
#include "editor/plugins/gi_probe_editor_plugin.h"
#include "editor/plugins/gpu_particles_2d_editor_plugin.h"
@@ -456,8 +457,6 @@ void EditorNode::_notification(int p_what) {
editor_selection->update();
- //scene_root->set_size_override(true, Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height")));
-
{ //TODO should only happen on settings changed
int current_filter = GLOBAL_GET("rendering/canvas_textures/default_texture_filter");
if (current_filter != scene_root->get_default_canvas_item_texture_filter()) {
@@ -3622,6 +3621,7 @@ void EditorNode::register_editor_types() {
// FIXME: Is this stuff obsolete, or should it be ported to new APIs?
ClassDB::register_class<EditorScenePostImport>();
//ClassDB::register_type<EditorImportExport>();
+ ClassDB::register_class<EditorDebuggerPlugin>();
}
void EditorNode::unregister_editor_types() {
@@ -5344,9 +5344,11 @@ void EditorNode::_feature_profile_changed() {
TabContainer *node_tabs = cast_to<TabContainer>(node_dock->get_parent());
TabContainer *fs_tabs = cast_to<TabContainer>(filesystem_dock->get_parent());
if (profile.is_valid()) {
- import_tabs->set_tab_hidden(import_dock->get_index(), profile->is_feature_disabled(EditorFeatureProfile::FEATURE_IMPORT_DOCK));
node_tabs->set_tab_hidden(node_dock->get_index(), profile->is_feature_disabled(EditorFeatureProfile::FEATURE_NODE_DOCK));
- fs_tabs->set_tab_hidden(filesystem_dock->get_index(), profile->is_feature_disabled(EditorFeatureProfile::FEATURE_FILESYSTEM_DOCK));
+ // The Import dock is useless without the FileSystem dock. Ensure the configuration is valid.
+ bool fs_dock_disabled = profile->is_feature_disabled(EditorFeatureProfile::FEATURE_FILESYSTEM_DOCK);
+ fs_tabs->set_tab_hidden(filesystem_dock->get_index(), fs_dock_disabled);
+ import_tabs->set_tab_hidden(import_dock->get_index(), fs_dock_disabled || profile->is_feature_disabled(EditorFeatureProfile::FEATURE_IMPORT_DOCK));
main_editor_buttons[EDITOR_3D]->set_visible(!profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D));
main_editor_buttons[EDITOR_SCRIPT]->set_visible(!profile->is_feature_disabled(EditorFeatureProfile::FEATURE_SCRIPT));
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index da0a0827d2..bce46b719a 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -811,6 +811,14 @@ ScriptCreateDialog *EditorPlugin::get_script_create_dialog() {
return EditorNode::get_singleton()->get_script_create_dialog();
}
+void EditorPlugin::add_debugger_plugin(const Ref<Script> &p_script) {
+ EditorDebuggerNode::get_singleton()->add_debugger_plugin(p_script);
+}
+
+void EditorPlugin::remove_debugger_plugin(const Ref<Script> &p_script) {
+ EditorDebuggerNode::get_singleton()->remove_debugger_plugin(p_script);
+}
+
void EditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_control_to_container", "container", "control"), &EditorPlugin::add_control_to_container);
ClassDB::bind_method(D_METHOD("add_control_to_bottom_panel", "control", "title"), &EditorPlugin::add_control_to_bottom_panel);
@@ -851,6 +859,8 @@ void EditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_editor_interface"), &EditorPlugin::get_editor_interface);
ClassDB::bind_method(D_METHOD("get_script_create_dialog"), &EditorPlugin::get_script_create_dialog);
+ ClassDB::bind_method(D_METHOD("add_debugger_plugin", "script"), &EditorPlugin::add_debugger_plugin);
+ ClassDB::bind_method(D_METHOD("remove_debugger_plugin", "script"), &EditorPlugin::remove_debugger_plugin);
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_canvas_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index 685f69bf3f..c7803f73c9 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -33,6 +33,7 @@
#include "core/io/config_file.h"
#include "core/undo_redo.h"
+#include "editor/debugger/editor_debugger_node.h"
#include "editor/editor_inspector.h"
#include "editor/editor_translation_parser.h"
#include "editor/import/editor_import_plugin.h"
@@ -249,6 +250,9 @@ public:
void add_autoload_singleton(const String &p_name, const String &p_path);
void remove_autoload_singleton(const String &p_name);
+ void add_debugger_plugin(const Ref<Script> &p_script);
+ void remove_debugger_plugin(const Ref<Script> &p_script);
+
void enable_plugin();
void disable_plugin();
diff --git a/editor/plugins/editor_debugger_plugin.cpp b/editor/plugins/editor_debugger_plugin.cpp
new file mode 100644
index 0000000000..b775e871e2
--- /dev/null
+++ b/editor/plugins/editor_debugger_plugin.cpp
@@ -0,0 +1,124 @@
+/*************************************************************************/
+/* editor_debugger_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "editor_debugger_plugin.h"
+
+#include "editor/debugger/script_editor_debugger.h"
+
+void EditorDebuggerPlugin::_breaked(bool p_really_did, bool p_can_debug) {
+ if (p_really_did) {
+ emit_signal("breaked", p_can_debug);
+ } else {
+ emit_signal("continued");
+ }
+}
+
+void EditorDebuggerPlugin::_started() {
+ emit_signal("started");
+}
+
+void EditorDebuggerPlugin::_stopped() {
+ emit_signal("stopped");
+}
+
+void EditorDebuggerPlugin::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("send_message", "message", "data"), &EditorDebuggerPlugin::send_message);
+ ClassDB::bind_method(D_METHOD("register_message_capture", "name", "callable"), &EditorDebuggerPlugin::register_message_capture);
+ ClassDB::bind_method(D_METHOD("unregister_message_capture", "name"), &EditorDebuggerPlugin::unregister_message_capture);
+ ClassDB::bind_method(D_METHOD("has_capture", "name"), &EditorDebuggerPlugin::has_capture);
+ ClassDB::bind_method(D_METHOD("is_breaked"), &EditorDebuggerPlugin::is_breaked);
+ ClassDB::bind_method(D_METHOD("is_debuggable"), &EditorDebuggerPlugin::is_debuggable);
+ ClassDB::bind_method(D_METHOD("is_session_active"), &EditorDebuggerPlugin::is_session_active);
+
+ ADD_SIGNAL(MethodInfo("started"));
+ ADD_SIGNAL(MethodInfo("stopped"));
+ ADD_SIGNAL(MethodInfo("breaked", PropertyInfo(Variant::BOOL, "can_debug")));
+ ADD_SIGNAL(MethodInfo("continued"));
+}
+
+void EditorDebuggerPlugin::attach_debugger(ScriptEditorDebugger *p_debugger) {
+ debugger = p_debugger;
+ if (debugger) {
+ debugger->connect("started", callable_mp(this, &EditorDebuggerPlugin::_started));
+ debugger->connect("stopped", callable_mp(this, &EditorDebuggerPlugin::_stopped));
+ debugger->connect("breaked", callable_mp(this, &EditorDebuggerPlugin::_breaked));
+ }
+}
+
+void EditorDebuggerPlugin::detach_debugger(bool p_call_debugger) {
+ if (debugger) {
+ debugger->disconnect("started", callable_mp(this, &EditorDebuggerPlugin::_started));
+ debugger->disconnect("stopped", callable_mp(this, &EditorDebuggerPlugin::_stopped));
+ debugger->disconnect("breaked", callable_mp(this, &EditorDebuggerPlugin::_breaked));
+ if (p_call_debugger && get_script_instance()) {
+ debugger->remove_debugger_plugin(get_script_instance()->get_script());
+ }
+ debugger = nullptr;
+ }
+}
+
+void EditorDebuggerPlugin::send_message(const String &p_message, const Array &p_args) {
+ ERR_FAIL_COND_MSG(!debugger, "Plugin is not attached to debugger");
+ debugger->send_message(p_message, p_args);
+}
+
+void EditorDebuggerPlugin::register_message_capture(const StringName &p_name, const Callable &p_callable) {
+ ERR_FAIL_COND_MSG(!debugger, "Plugin is not attached to debugger");
+ debugger->register_message_capture(p_name, p_callable);
+}
+
+void EditorDebuggerPlugin::unregister_message_capture(const StringName &p_name) {
+ ERR_FAIL_COND_MSG(!debugger, "Plugin is not attached to debugger");
+ debugger->unregister_message_capture(p_name);
+}
+
+bool EditorDebuggerPlugin::has_capture(const StringName &p_name) {
+ ERR_FAIL_COND_V_MSG(!debugger, false, "Plugin is not attached to debugger");
+ return debugger->has_capture(p_name);
+}
+
+bool EditorDebuggerPlugin::is_breaked() {
+ ERR_FAIL_COND_V_MSG(!debugger, false, "Plugin is not attached to debugger");
+ return debugger->is_breaked();
+}
+
+bool EditorDebuggerPlugin::is_debuggable() {
+ ERR_FAIL_COND_V_MSG(!debugger, false, "Plugin is not attached to debugger");
+ return debugger->is_debuggable();
+}
+
+bool EditorDebuggerPlugin::is_session_active() {
+ ERR_FAIL_COND_V_MSG(!debugger, false, "Plugin is not attached to debugger");
+ return debugger->is_session_active();
+}
+
+EditorDebuggerPlugin::~EditorDebuggerPlugin() {
+ detach_debugger(true);
+}
diff --git a/editor/plugins/editor_debugger_plugin.h b/editor/plugins/editor_debugger_plugin.h
new file mode 100644
index 0000000000..10fd1151de
--- /dev/null
+++ b/editor/plugins/editor_debugger_plugin.h
@@ -0,0 +1,64 @@
+/*************************************************************************/
+/* editor_debugger_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef EDITOR_DEBUGGER_PLUGIN_H
+#define EDITOR_DEBUGGER_PLUGIN_H
+
+#include "scene/gui/control.h"
+
+class ScriptEditorDebugger;
+
+class EditorDebuggerPlugin : public Control {
+ GDCLASS(EditorDebuggerPlugin, Control);
+
+private:
+ ScriptEditorDebugger *debugger = nullptr;
+
+ void _breaked(bool p_really_did, bool p_can_debug);
+ void _started();
+ void _stopped();
+
+protected:
+ static void _bind_methods();
+
+public:
+ void attach_debugger(ScriptEditorDebugger *p_debugger);
+ void detach_debugger(bool p_call_debugger);
+ void send_message(const String &p_message, const Array &p_args);
+ void register_message_capture(const StringName &p_name, const Callable &p_callable);
+ void unregister_message_capture(const StringName &p_name);
+ bool has_capture(const StringName &p_name);
+ bool is_breaked();
+ bool is_debuggable();
+ bool is_session_active();
+ ~EditorDebuggerPlugin();
+};
+
+#endif // EDITOR_DEBUGGER_PLUGIN_H
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 762f42abeb..6e722607f7 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -875,7 +875,7 @@ void TextureRegionEditor::_changed_callback(Object *p_changed, const char *p_pro
if (!is_visible()) {
return;
}
- if (p_prop == StringName("atlas") || p_prop == StringName("texture")) {
+ if (p_prop == StringName("atlas") || p_prop == StringName("texture") || p_prop == StringName("region")) {
_edit_region();
}
}
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index 18a107ff75..932ded6938 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -206,8 +206,8 @@ void ThemeEditor::_save_template_cbk(String fname) {
file->store_line("; [value] examples:");
file->store_line("; ");
file->store_line("; Type.item = 6 ; numeric constant. ");
- file->store_line("; Type.item = #FF00FF ; HTML color ");
- file->store_line("; Type.item = #55FF00FF ; HTML color with alpha 55.");
+ file->store_line("; Type.item = #FF00FF ; HTML color (magenta).");
+ file->store_line("; Type.item = #FF00FF55 ; HTML color (magenta with alpha 0x55).");
file->store_line("; Type.item = icon(image.png) ; icon in a png file (relative to theme file).");
file->store_line("; Type.item = font(font.xres) ; font in a resource (relative to theme file).");
file->store_line("; Type.item = sbox(stylebox.xres) ; stylebox in a resource (relative to theme file).");
@@ -629,7 +629,7 @@ ThemeEditor::ThemeEditor() {
ScrollContainer *scroll = memnew(ScrollContainer);
add_child(scroll);
scroll->set_enable_v_scroll(true);
- scroll->set_enable_h_scroll(false);
+ scroll->set_enable_h_scroll(true);
scroll->set_v_size_flags(SIZE_EXPAND_FILL);
MarginContainer *root_container = memnew(MarginContainer);
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 35311b32eb..a316756808 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -330,6 +330,7 @@ private:
return;
}
}
+
String sp = p.simplify_path();
project_path->set_text(sp);
_path_text_changed(sp);
@@ -1012,7 +1013,7 @@ public:
void update_dock_menu();
void load_projects();
void set_search_term(String p_search_term);
- void set_order_option(ProjectListFilter::FilterOption p_option);
+ void set_order_option(int p_option);
void sort_projects();
int get_project_count() const;
void select_project(int p_index);
@@ -1045,7 +1046,7 @@ private:
static void load_project_data(const String &p_property_key, Item &p_item, bool p_favorite);
String _search_term;
- ProjectListFilter::FilterOption _order_option;
+ FilterOption _order_option;
Set<String> _selected_project_keys;
String _last_clicked; // Project key
VBoxContainer *_scroll_children;
@@ -1055,7 +1056,7 @@ private:
};
struct ProjectListComparator {
- ProjectListFilter::FilterOption order_option;
+ FilterOption order_option;
// operator<
_FORCE_INLINE_ bool operator()(const ProjectList::Item &a, const ProjectList::Item &b) const {
@@ -1066,9 +1067,9 @@ struct ProjectListComparator {
return false;
}
switch (order_option) {
- case ProjectListFilter::FILTER_PATH:
+ case PATH:
return a.project_key < b.project_key;
- case ProjectListFilter::FILTER_EDIT_DATE:
+ case EDIT_DATE:
return a.last_edited > b.last_edited;
default:
return a.project_name < b.project_name;
@@ -1077,8 +1078,7 @@ struct ProjectListComparator {
};
ProjectList::ProjectList() {
- _order_option = ProjectListFilter::FILTER_EDIT_DATE;
-
+ _order_option = FilterOption::NAME;
_scroll_children = memnew(VBoxContainer);
_scroll_children->set_h_size_flags(Control::SIZE_EXPAND_FILL);
add_child(_scroll_children);
@@ -1238,8 +1238,6 @@ void ProjectList::load_projects() {
create_project_item_control(i);
}
- sort_projects();
-
set_v_scroll(0);
update_icons_async();
@@ -1391,12 +1389,13 @@ void ProjectList::set_search_term(String p_search_term) {
_search_term = p_search_term;
}
-void ProjectList::set_order_option(ProjectListFilter::FilterOption p_option) {
- if (_order_option != p_option) {
- _order_option = p_option;
- EditorSettings::get_singleton()->set("project_manager/sorting_order", (int)_order_option);
- EditorSettings::get_singleton()->save();
- }
+void ProjectList::set_order_option(int p_option) {
+ FilterOption selected = (FilterOption)p_option;
+ EditorSettings::get_singleton()->set("project_manager/sorting_order", p_option);
+ EditorSettings::get_singleton()->save();
+ _order_option = selected;
+
+ sort_projects();
}
void ProjectList::sort_projects() {
@@ -1798,6 +1797,9 @@ void ProjectList::_bind_methods() {
void ProjectManager::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
+ search_box->set_right_icon(get_theme_icon("Search", "EditorIcons"));
+ search_box->set_clear_button_enabled(true);
+
Engine::get_singleton()->set_editor_hint(false);
} break;
case NOTIFICATION_RESIZED: {
@@ -1806,6 +1808,10 @@ void ProjectManager::_notification(int p_what) {
}
} break;
case NOTIFICATION_READY: {
+ int default_sorting = (int)EditorSettings::get_singleton()->get("project_manager/sorting_order");
+ filter_option->select(default_sorting);
+ _project_list->set_order_option(default_sorting);
+
if (_project_list->get_project_count() == 0 && StreamPeerSSL::is_available()) {
open_templates->popup_centered();
}
@@ -1813,7 +1819,7 @@ void ProjectManager::_notification(int p_what) {
if (_project_list->get_project_count() >= 1) {
// Focus on the search box immediately to allow the user
// to search without having to reach for their mouse
- project_filter->search_box->grab_focus();
+ search_box->grab_focus();
}
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -1833,7 +1839,7 @@ void ProjectManager::_dim_window() {
// No transition is applied, as the effect needs to be visible immediately
float c = 0.5f;
Color dim_color = Color(c, c, c);
- gui_base->set_modulate(dim_color);
+ set_modulate(dim_color);
}
void ProjectManager::_update_project_buttons() {
@@ -1853,7 +1859,7 @@ void ProjectManager::_update_project_buttons() {
rename_btn->set_disabled(empty_selection || is_missing_project_selected);
run_btn->set_disabled(empty_selection || is_missing_project_selected);
- erase_missing_btn->set_visible(_project_list->is_any_project_missing());
+ erase_missing_btn->set_disabled(!_project_list->is_any_project_missing());
}
void ProjectManager::_unhandled_input(const Ref<InputEvent> &p_ev) {
@@ -1930,7 +1936,7 @@ void ProjectManager::_unhandled_input(const Ref<InputEvent> &p_ev) {
} break;
case KEY_F: {
if (k->get_command()) {
- this->project_filter->search_box->grab_focus();
+ this->search_box->grab_focus();
} else {
keycode_handled = false;
}
@@ -1947,8 +1953,7 @@ void ProjectManager::_unhandled_input(const Ref<InputEvent> &p_ev) {
}
void ProjectManager::_load_recent_projects() {
- _project_list->set_order_option(project_order_filter->get_filter_option());
- _project_list->set_search_term(project_filter->get_search_term());
+ _project_list->set_search_term(search_box->get_text().strip_edges());
_project_list->load_projects();
_update_project_buttons();
@@ -1970,7 +1975,7 @@ void ProjectManager::_on_projects_updated() {
}
void ProjectManager::_on_project_created(const String &dir) {
- project_filter->clear();
+ search_box->clear();
int i = _project_list->refresh_project(dir);
_project_list->select_project(i);
_project_list->ensure_project_visible(i);
@@ -2113,7 +2118,6 @@ void ProjectManager::_run_project_confirm() {
}
}
-// When you press the "Run" button
void ProjectManager::_run_project() {
const Set<String> &selected_list = _project_list->get_selected_project_keys();
@@ -2226,8 +2230,6 @@ void ProjectManager::_erase_missing_projects() {
void ProjectManager::_language_selected(int p_id) {
String lang = language_btn->get_item_metadata(p_id);
EditorSettings::get_singleton()->set("interface/editor/editor_language", lang);
- language_btn->set_text(lang);
- language_btn->set_icon(get_theme_icon("Environment", "EditorIcons"));
language_restart_ask->set_text(TTR("Language changed.\nThe interface will update after restarting the editor or project manager."));
language_restart_ask->popup_centered();
@@ -2304,13 +2306,14 @@ void ProjectManager::_scan_multiple_folders(PackedStringArray p_files) {
}
}
-void ProjectManager::_on_order_option_changed() {
- _project_list->set_order_option(project_order_filter->get_filter_option());
- _project_list->sort_projects();
+void ProjectManager::_on_order_option_changed(int p_idx) {
+ if (is_inside_tree()) {
+ _project_list->set_order_option(p_idx);
+ }
}
-void ProjectManager::_on_filter_option_changed() {
- _project_list->set_search_term(project_filter->get_search_term());
+void ProjectManager::_on_search_term_changed(const String &p_term) {
+ _project_list->set_search_term(p_term);
_project_list->sort_projects();
// Select the first visible project in the list.
@@ -2341,7 +2344,6 @@ ProjectManager::ProjectManager() {
{
int display_scale = EditorSettings::get_singleton()->get("interface/editor/display_scale");
- float custom_display_scale = EditorSettings::get_singleton()->get("interface/editor/custom_display_scale");
switch (display_scale) {
case 0: {
@@ -2372,9 +2374,8 @@ ProjectManager::ProjectManager() {
case 6:
editor_set_scale(2.0);
break;
-
default: {
- editor_set_scale(custom_display_scale);
+ editor_set_scale(EditorSettings::get_singleton()->get("interface/editor/custom_display_scale"));
} break;
}
@@ -2385,28 +2386,26 @@ ProjectManager::ProjectManager() {
DisplayServer::get_singleton()->window_set_size(DisplayServer::get_singleton()->window_get_size() * MAX(1, EDSCALE));
}
+ String cp;
+ cp += 0xA9;
+ DisplayServer::get_singleton()->window_set_title(VERSION_NAME + String(" - ") + TTR("Project Manager") + " - " + cp + " 2007-2020 Juan Linietsky, Ariel Manzur & Godot Contributors");
+
FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files"));
set_anchors_and_margins_preset(Control::PRESET_WIDE);
set_theme(create_custom_theme());
- gui_base = memnew(Control);
- add_child(gui_base);
- gui_base->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+ set_anchors_and_margins_preset(Control::PRESET_WIDE);
Panel *panel = memnew(Panel);
- gui_base->add_child(panel);
+ add_child(panel);
panel->set_anchors_and_margins_preset(Control::PRESET_WIDE);
- panel->add_theme_style_override("panel", gui_base->get_theme_stylebox("Background", "EditorStyles"));
+ panel->add_theme_style_override("panel", get_theme_stylebox("Background", "EditorStyles"));
VBoxContainer *vb = memnew(VBoxContainer);
panel->add_child(vb);
vb->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 8 * EDSCALE);
- String cp;
- cp += 0xA9;
- DisplayServer::get_singleton()->window_set_title(VERSION_NAME + String(" - ") + TTR("Project Manager") + " - " + cp + " 2007-2020 Juan Linietsky, Ariel Manzur & Godot Contributors");
-
Control *center_box = memnew(Control);
center_box->set_v_size_flags(Control::SIZE_EXPAND_FILL);
vb->add_child(center_box);
@@ -2416,218 +2415,231 @@ ProjectManager::ProjectManager() {
tabs->set_anchors_and_margins_preset(Control::PRESET_WIDE);
tabs->set_tab_align(TabContainer::ALIGN_LEFT);
- HBoxContainer *tree_hb = memnew(HBoxContainer);
- projects_hb = tree_hb;
-
+ HBoxContainer *projects_hb = memnew(HBoxContainer);
projects_hb->set_name(TTR("Projects"));
+ tabs->add_child(projects_hb);
- tabs->add_child(tree_hb);
-
- VBoxContainer *search_tree_vb = memnew(VBoxContainer);
- tree_hb->add_child(search_tree_vb);
- search_tree_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
-
- HBoxContainer *sort_filters = memnew(HBoxContainer);
- Label *sort_label = memnew(Label);
- sort_label->set_text(TTR("Sort:"));
- sort_filters->add_child(sort_label);
- Vector<String> sort_filter_titles;
- sort_filter_titles.push_back(TTR("Name"));
- sort_filter_titles.push_back(TTR("Path"));
- sort_filter_titles.push_back(TTR("Last Edited"));
- project_order_filter = memnew(ProjectListFilter);
- project_order_filter->add_filter_option();
- project_order_filter->_setup_filters(sort_filter_titles);
- project_order_filter->set_filter_size(150);
- sort_filters->add_child(project_order_filter);
- project_order_filter->connect("filter_changed", callable_mp(this, &ProjectManager::_on_order_option_changed));
- project_order_filter->set_custom_minimum_size(Size2(180, 10) * EDSCALE);
-
- int projects_sorting_order = (int)EditorSettings::get_singleton()->get("project_manager/sorting_order");
- project_order_filter->set_filter_option((ProjectListFilter::FilterOption)projects_sorting_order);
-
- sort_filters->add_spacer(true);
-
- project_filter = memnew(ProjectListFilter);
- project_filter->add_search_box();
- project_filter->connect("filter_changed", callable_mp(this, &ProjectManager::_on_filter_option_changed));
- project_filter->set_custom_minimum_size(Size2(280, 10) * EDSCALE);
- sort_filters->add_child(project_filter);
-
- search_tree_vb->add_child(sort_filters);
-
- PanelContainer *pc = memnew(PanelContainer);
- pc->add_theme_style_override("panel", gui_base->get_theme_stylebox("bg", "Tree"));
- search_tree_vb->add_child(pc);
- pc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
-
- _project_list = memnew(ProjectList);
- _project_list->connect(ProjectList::SIGNAL_SELECTION_CHANGED, callable_mp(this, &ProjectManager::_update_project_buttons));
- _project_list->connect(ProjectList::SIGNAL_PROJECT_ASK_OPEN, callable_mp(this, &ProjectManager::_open_selected_projects_ask));
- pc->add_child(_project_list);
- _project_list->set_enable_h_scroll(false);
-
- VBoxContainer *tree_vb = memnew(VBoxContainer);
- tree_hb->add_child(tree_vb);
-
- Button *open = memnew(Button);
- open->set_text(TTR("Edit"));
- tree_vb->add_child(open);
- open->connect("pressed", callable_mp(this, &ProjectManager::_open_selected_projects_ask));
- open_btn = open;
-
- Button *run = memnew(Button);
- run->set_text(TTR("Run"));
- tree_vb->add_child(run);
- run->connect("pressed", callable_mp(this, &ProjectManager::_run_project));
- run_btn = run;
-
- tree_vb->add_child(memnew(HSeparator));
-
- Button *scan = memnew(Button);
- scan->set_text(TTR("Scan"));
- tree_vb->add_child(scan);
- scan->connect("pressed", callable_mp(this, &ProjectManager::_scan_projects));
-
- tree_vb->add_child(memnew(HSeparator));
-
- scan_dir = memnew(FileDialog);
- scan_dir->set_access(FileDialog::ACCESS_FILESYSTEM);
- scan_dir->set_file_mode(FileDialog::FILE_MODE_OPEN_DIR);
- scan_dir->set_title(TTR("Select a Folder to Scan")); // must be after mode or it's overridden
- scan_dir->set_current_dir(EditorSettings::get_singleton()->get("filesystem/directories/default_project_path"));
- gui_base->add_child(scan_dir);
- scan_dir->connect("dir_selected", callable_mp(this, &ProjectManager::_scan_begin));
-
- Button *create = memnew(Button);
- create->set_text(TTR("New Project"));
- tree_vb->add_child(create);
- create->connect("pressed", callable_mp(this, &ProjectManager::_new_project));
-
- Button *import = memnew(Button);
- import->set_text(TTR("Import"));
- tree_vb->add_child(import);
- import->connect("pressed", callable_mp(this, &ProjectManager::_import_project));
-
- Button *rename = memnew(Button);
- rename->set_text(TTR("Rename"));
- tree_vb->add_child(rename);
- rename->connect("pressed", callable_mp(this, &ProjectManager::_rename_project));
- rename_btn = rename;
-
- Button *erase = memnew(Button);
- erase->set_text(TTR("Remove"));
- tree_vb->add_child(erase);
- erase->connect("pressed", callable_mp(this, &ProjectManager::_erase_project));
- erase_btn = erase;
-
- Button *erase_missing = memnew(Button);
- erase_missing->set_text(TTR("Remove Missing"));
- tree_vb->add_child(erase_missing);
- erase_missing->connect("pressed", callable_mp(this, &ProjectManager::_erase_missing_projects));
- erase_missing_btn = erase_missing;
-
- tree_vb->add_spacer();
+ {
+ // Projects + search bar
+ VBoxContainer *search_tree_vb = memnew(VBoxContainer);
+ projects_hb->add_child(search_tree_vb);
+ search_tree_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- if (StreamPeerSSL::is_available()) {
- asset_library = memnew(EditorAssetLibrary(true));
- asset_library->set_name(TTR("Templates"));
- tabs->add_child(asset_library);
- asset_library->connect("install_asset", callable_mp(this, &ProjectManager::_install_project));
- } else {
- WARN_PRINT("Asset Library not available, as it requires SSL to work.");
- }
+ HBoxContainer *hb = memnew(HBoxContainer);
+ hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ search_tree_vb->add_child(hb);
- HBoxContainer *settings_hb = memnew(HBoxContainer);
- settings_hb->set_alignment(BoxContainer::ALIGN_END);
- settings_hb->set_h_grow_direction(Control::GROW_DIRECTION_BEGIN);
+ search_box = memnew(LineEdit);
+ search_box->set_placeholder(TTR("Search"));
+ search_box->set_tooltip(TTR("The search box filters projects by name and last path component.\nTo filter projects by name and full path, the query must contain at least one `/` character."));
+ search_box->connect("text_changed", callable_mp(this, &ProjectManager::_on_search_term_changed));
+ search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ hb->add_child(search_box);
- Label *version_label = memnew(Label);
- String hash = String(VERSION_HASH);
- if (hash.length() != 0) {
- hash = "." + hash.left(9);
- }
- version_label->set_text("v" VERSION_FULL_BUILD "" + hash);
- // Fade out the version label to be less prominent, but still readable
- version_label->set_self_modulate(Color(1, 1, 1, 0.6));
- version_label->set_align(Label::ALIGN_CENTER);
- settings_hb->add_child(version_label);
+ hb->add_spacer();
- language_btn = memnew(OptionButton);
- language_btn->set_flat(true);
- language_btn->set_focus_mode(Control::FOCUS_NONE);
+ Label *sort_label = memnew(Label);
+ sort_label->set_text(TTR("Sort:"));
+ hb->add_child(sort_label);
- Vector<String> editor_languages;
- List<PropertyInfo> editor_settings_properties;
- EditorSettings::get_singleton()->get_property_list(&editor_settings_properties);
- for (List<PropertyInfo>::Element *E = editor_settings_properties.front(); E; E = E->next()) {
- PropertyInfo &pi = E->get();
- if (pi.name == "interface/editor/editor_language") {
- editor_languages = pi.hint_string.split(",");
- }
- }
- String current_lang = EditorSettings::get_singleton()->get("interface/editor/editor_language");
- for (int i = 0; i < editor_languages.size(); i++) {
- String lang = editor_languages[i];
- String lang_name = TranslationServer::get_singleton()->get_locale_name(lang);
- language_btn->add_item(lang_name + " [" + lang + "]", i);
- language_btn->set_item_metadata(i, lang);
- if (current_lang == lang) {
- language_btn->select(i);
- language_btn->set_text(lang);
- }
- }
- language_btn->set_icon(get_theme_icon("Environment", "EditorIcons"));
+ filter_option = memnew(OptionButton);
+ filter_option->set_clip_text(true);
+ filter_option->set_custom_minimum_size(Size2(150 * EDSCALE, 10 * EDSCALE));
+ filter_option->connect("item_selected", callable_mp(this, &ProjectManager::_on_order_option_changed));
+ hb->add_child(filter_option);
- settings_hb->add_child(language_btn);
- language_btn->connect("item_selected", callable_mp(this, &ProjectManager::_language_selected));
+ Vector<String> sort_filter_titles;
+ sort_filter_titles.push_back(TTR("Name"));
+ sort_filter_titles.push_back(TTR("Path"));
+ sort_filter_titles.push_back(TTR("Last Edited"));
- center_box->add_child(settings_hb);
- settings_hb->set_anchors_and_margins_preset(Control::PRESET_TOP_RIGHT);
+ for (int i = 0; i < sort_filter_titles.size(); i++) {
+ filter_option->add_item(sort_filter_titles[i]);
+ }
- //////////////////////////////////////////////////////////////
+ PanelContainer *pc = memnew(PanelContainer);
+ pc->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree"));
+ pc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ search_tree_vb->add_child(pc);
- language_restart_ask = memnew(ConfirmationDialog);
- language_restart_ask->get_ok()->set_text(TTR("Restart Now"));
- language_restart_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_restart_confirm));
- language_restart_ask->get_cancel()->set_text(TTR("Continue"));
- gui_base->add_child(language_restart_ask);
+ _project_list = memnew(ProjectList);
+ _project_list->connect(ProjectList::SIGNAL_SELECTION_CHANGED, callable_mp(this, &ProjectManager::_update_project_buttons));
+ _project_list->connect(ProjectList::SIGNAL_PROJECT_ASK_OPEN, callable_mp(this, &ProjectManager::_open_selected_projects_ask));
+ _project_list->set_enable_h_scroll(false);
+ pc->add_child(_project_list);
+ }
- erase_missing_ask = memnew(ConfirmationDialog);
- erase_missing_ask->get_ok()->set_text(TTR("Remove All"));
- erase_missing_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_erase_missing_projects_confirm));
- gui_base->add_child(erase_missing_ask);
+ {
+ // Project tab side bar
+ VBoxContainer *tree_vb = memnew(VBoxContainer);
+ tree_vb->set_custom_minimum_size(Size2(120, 120));
+ projects_hb->add_child(tree_vb);
+
+ Button *create = memnew(Button);
+ create->set_text(TTR("New Project"));
+ create->connect("pressed", callable_mp(this, &ProjectManager::_new_project));
+ tree_vb->add_child(create);
+
+ Button *import = memnew(Button);
+ import->set_text(TTR("Import"));
+ import->connect("pressed", callable_mp(this, &ProjectManager::_import_project));
+ tree_vb->add_child(import);
+
+ Button *scan = memnew(Button);
+ scan->set_text(TTR("Scan"));
+ scan->connect("pressed", callable_mp(this, &ProjectManager::_scan_projects));
+ tree_vb->add_child(scan);
+
+ tree_vb->add_child(memnew(HSeparator));
+
+ open_btn = memnew(Button);
+ open_btn->set_text(TTR("Edit"));
+ open_btn->connect("pressed", callable_mp(this, &ProjectManager::_open_selected_projects_ask));
+ tree_vb->add_child(open_btn);
+
+ run_btn = memnew(Button);
+ run_btn->set_text(TTR("Run"));
+ run_btn->connect("pressed", callable_mp(this, &ProjectManager::_run_project));
+ tree_vb->add_child(run_btn);
+
+ rename_btn = memnew(Button);
+ rename_btn->set_text(TTR("Rename"));
+ rename_btn->connect("pressed", callable_mp(this, &ProjectManager::_rename_project));
+ tree_vb->add_child(rename_btn);
+
+ erase_btn = memnew(Button);
+ erase_btn->set_text(TTR("Remove"));
+ erase_btn->connect("pressed", callable_mp(this, &ProjectManager::_erase_project));
+ tree_vb->add_child(erase_btn);
+
+ erase_missing_btn = memnew(Button);
+ erase_missing_btn->set_text(TTR("Remove Missing"));
+ erase_missing_btn->connect("pressed", callable_mp(this, &ProjectManager::_erase_missing_projects));
+ tree_vb->add_child(erase_missing_btn);
+ }
- erase_ask = memnew(ConfirmationDialog);
- erase_ask->get_ok()->set_text(TTR("Remove"));
- erase_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_erase_project_confirm));
- gui_base->add_child(erase_ask);
+ {
+ // Version info and language options
+ HBoxContainer *settings_hb = memnew(HBoxContainer);
+ settings_hb->set_alignment(BoxContainer::ALIGN_END);
+ settings_hb->set_h_grow_direction(Control::GROW_DIRECTION_BEGIN);
+
+ Label *version_label = memnew(Label);
+ String hash = String(VERSION_HASH);
+ if (hash.length() != 0) {
+ hash = "." + hash.left(9);
+ }
+ version_label->set_text("v" VERSION_FULL_BUILD "" + hash);
+ version_label->set_self_modulate(Color(1, 1, 1, 0.6));
+ version_label->set_align(Label::ALIGN_CENTER);
+ settings_hb->add_child(version_label);
+
+ language_btn = memnew(OptionButton);
+ language_btn->set_flat(true);
+ language_btn->set_icon(get_theme_icon("Environment", "EditorIcons"));
+ language_btn->set_focus_mode(Control::FOCUS_NONE);
+ language_btn->connect("item_selected", callable_mp(this, &ProjectManager::_language_selected));
+
+ Vector<String> editor_languages;
+ List<PropertyInfo> editor_settings_properties;
+ EditorSettings::get_singleton()->get_property_list(&editor_settings_properties);
+ for (List<PropertyInfo>::Element *E = editor_settings_properties.front(); E; E = E->next()) {
+ PropertyInfo &pi = E->get();
+ if (pi.name == "interface/editor/editor_language") {
+ editor_languages = pi.hint_string.split(",");
+ break;
+ }
+ }
- multi_open_ask = memnew(ConfirmationDialog);
- multi_open_ask->get_ok()->set_text(TTR("Edit"));
- multi_open_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_open_selected_projects));
- gui_base->add_child(multi_open_ask);
+ String current_lang = EditorSettings::get_singleton()->get("interface/editor/editor_language");
+ language_btn->set_text(current_lang);
- multi_run_ask = memnew(ConfirmationDialog);
- multi_run_ask->get_ok()->set_text(TTR("Run"));
- multi_run_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_run_project_confirm));
- gui_base->add_child(multi_run_ask);
+ for (int i = 0; i < editor_languages.size(); i++) {
+ String lang = editor_languages[i];
+ String lang_name = TranslationServer::get_singleton()->get_locale_name(lang);
+ language_btn->add_item(lang_name + " [" + lang + "]", i);
+ language_btn->set_item_metadata(i, lang);
+ if (current_lang == lang) {
+ language_btn->select(i);
+ }
+ }
- multi_scan_ask = memnew(ConfirmationDialog);
- multi_scan_ask->get_ok()->set_text(TTR("Scan"));
- gui_base->add_child(multi_scan_ask);
+ settings_hb->add_child(language_btn);
+ center_box->add_child(settings_hb);
+ settings_hb->set_anchors_and_margins_preset(Control::PRESET_TOP_RIGHT);
+ }
- ask_update_settings = memnew(ConfirmationDialog);
- ask_update_settings->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_confirm_update_settings));
- gui_base->add_child(ask_update_settings);
+ if (StreamPeerSSL::is_available()) {
+ asset_library = memnew(EditorAssetLibrary(true));
+ asset_library->set_name(TTR("Templates"));
+ tabs->add_child(asset_library);
+ asset_library->connect("install_asset", callable_mp(this, &ProjectManager::_install_project));
+ } else {
+ WARN_PRINT("Asset Library not available, as it requires SSL to work.");
+ }
- OS::get_singleton()->set_low_processor_usage_mode(true);
+ {
+ // Dialogs
+ language_restart_ask = memnew(ConfirmationDialog);
+ language_restart_ask->get_ok()->set_text(TTR("Restart Now"));
+ language_restart_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_restart_confirm));
+ language_restart_ask->get_cancel()->set_text(TTR("Continue"));
+ add_child(language_restart_ask);
+
+ scan_dir = memnew(FileDialog);
+ scan_dir->set_access(FileDialog::ACCESS_FILESYSTEM);
+ scan_dir->set_file_mode(FileDialog::FILE_MODE_OPEN_DIR);
+ scan_dir->set_title(TTR("Select a Folder to Scan")); // must be after mode or it's overridden
+ scan_dir->set_current_dir(EditorSettings::get_singleton()->get("filesystem/directories/default_project_path"));
+ add_child(scan_dir);
+ scan_dir->connect("dir_selected", callable_mp(this, &ProjectManager::_scan_begin));
+
+ erase_missing_ask = memnew(ConfirmationDialog);
+ erase_missing_ask->get_ok()->set_text(TTR("Remove All"));
+ erase_missing_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_erase_missing_projects_confirm));
+ add_child(erase_missing_ask);
+
+ erase_ask = memnew(ConfirmationDialog);
+ erase_ask->get_ok()->set_text(TTR("Remove"));
+ erase_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_erase_project_confirm));
+ add_child(erase_ask);
+
+ multi_open_ask = memnew(ConfirmationDialog);
+ multi_open_ask->get_ok()->set_text(TTR("Edit"));
+ multi_open_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_open_selected_projects));
+ add_child(multi_open_ask);
+
+ multi_run_ask = memnew(ConfirmationDialog);
+ multi_run_ask->get_ok()->set_text(TTR("Run"));
+ multi_run_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_run_project_confirm));
+ add_child(multi_run_ask);
+
+ multi_scan_ask = memnew(ConfirmationDialog);
+ multi_scan_ask->get_ok()->set_text(TTR("Scan"));
+ add_child(multi_scan_ask);
+
+ ask_update_settings = memnew(ConfirmationDialog);
+ ask_update_settings->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_confirm_update_settings));
+ add_child(ask_update_settings);
+
+ npdialog = memnew(ProjectDialog);
+ npdialog->connect("projects_updated", callable_mp(this, &ProjectManager::_on_projects_updated));
+ npdialog->connect("project_created", callable_mp(this, &ProjectManager::_on_project_created));
+ add_child(npdialog);
+
+ run_error_diag = memnew(AcceptDialog);
+ run_error_diag->set_title(TTR("Can't run project"));
+ add_child(run_error_diag);
- npdialog = memnew(ProjectDialog);
- gui_base->add_child(npdialog);
+ dialog_error = memnew(AcceptDialog);
+ add_child(dialog_error);
- npdialog->connect("projects_updated", callable_mp(this, &ProjectManager::_on_projects_updated));
- npdialog->connect("project_created", callable_mp(this, &ProjectManager::_on_project_created));
+ open_templates = memnew(ConfirmationDialog);
+ open_templates->set_text(TTR("You currently don't have any projects.\nWould you like to explore official example projects in the Asset Library?"));
+ open_templates->get_ok()->set_text(TTR("Open Asset Library"));
+ open_templates->connect("confirmed", callable_mp(this, &ProjectManager::_open_asset_library));
+ add_child(open_templates);
+ }
_load_recent_projects();
@@ -2637,18 +2649,7 @@ ProjectManager::ProjectManager() {
SceneTree::get_singleton()->get_root()->connect("files_dropped", callable_mp(this, &ProjectManager::_files_dropped));
- run_error_diag = memnew(AcceptDialog);
- gui_base->add_child(run_error_diag);
- run_error_diag->set_title(TTR("Can't run project"));
-
- dialog_error = memnew(AcceptDialog);
- gui_base->add_child(dialog_error);
-
- open_templates = memnew(ConfirmationDialog);
- open_templates->set_text(TTR("You currently don't have any projects.\nWould you like to explore official example projects in the Asset Library?"));
- open_templates->get_ok()->set_text(TTR("Open Asset Library"));
- open_templates->connect("confirmed", callable_mp(this, &ProjectManager::_open_asset_library));
- add_child(open_templates);
+ OS::get_singleton()->set_low_processor_usage_mode(true);
}
ProjectManager::~ProjectManager() {
@@ -2656,82 +2657,3 @@ ProjectManager::~ProjectManager() {
EditorSettings::destroy();
}
}
-
-void ProjectListFilter::_setup_filters(Vector<String> options) {
- filter_option->clear();
- for (int i = 0; i < options.size(); i++) {
- filter_option->add_item(options[i]);
- }
-}
-
-void ProjectListFilter::_search_text_changed(const String &p_newtext) {
- emit_signal("filter_changed");
-}
-
-String ProjectListFilter::get_search_term() {
- return search_box->get_text().strip_edges();
-}
-
-ProjectListFilter::FilterOption ProjectListFilter::get_filter_option() {
- return _current_filter;
-}
-
-void ProjectListFilter::set_filter_option(FilterOption option) {
- filter_option->select((int)option);
- _filter_option_selected(0);
-}
-
-void ProjectListFilter::_filter_option_selected(int p_idx) {
- FilterOption selected = (FilterOption)(filter_option->get_selected());
- if (_current_filter != selected) {
- _current_filter = selected;
- if (is_inside_tree()) {
- emit_signal("filter_changed");
- }
- }
-}
-
-void ProjectListFilter::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE && has_search_box) {
- search_box->set_right_icon(get_theme_icon("Search", "EditorIcons"));
- search_box->set_clear_button_enabled(true);
- }
-}
-
-void ProjectListFilter::_bind_methods() {
- ADD_SIGNAL(MethodInfo("filter_changed"));
-}
-
-void ProjectListFilter::add_filter_option() {
- filter_option = memnew(OptionButton);
- filter_option->set_clip_text(true);
- filter_option->connect("item_selected", callable_mp(this, &ProjectListFilter::_filter_option_selected));
- add_child(filter_option);
-}
-
-void ProjectListFilter::add_search_box() {
- search_box = memnew(LineEdit);
- search_box->set_placeholder(TTR("Search"));
- search_box->set_tooltip(
- TTR("The search box filters projects by name and last path component.\nTo filter projects by name and full path, the query must contain at least one `/` character."));
- search_box->connect("text_changed", callable_mp(this, &ProjectListFilter::_search_text_changed));
- search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- add_child(search_box);
-
- has_search_box = true;
-}
-
-void ProjectListFilter::set_filter_size(int h_size) {
- filter_option->set_custom_minimum_size(Size2(h_size * EDSCALE, 10 * EDSCALE));
-}
-
-ProjectListFilter::ProjectListFilter() {
- _current_filter = FILTER_NAME;
- has_search_box = false;
-}
-
-void ProjectListFilter::clear() {
- if (has_search_box) {
- search_box->clear();
- }
-}
diff --git a/editor/project_manager.h b/editor/project_manager.h
index 66b38d0746..407dba0c94 100644
--- a/editor/project_manager.h
+++ b/editor/project_manager.h
@@ -39,22 +39,31 @@
class ProjectDialog;
class ProjectList;
-class ProjectListFilter;
+
+enum FilterOption {
+ NAME,
+ PATH,
+ EDIT_DATE,
+};
class ProjectManager : public Control {
GDCLASS(ProjectManager, Control);
- Button *erase_btn;
- Button *erase_missing_btn;
+ TabContainer *tabs;
+
+ ProjectList *_project_list;
+
+ LineEdit *search_box;
+ OptionButton *filter_option;
+
+ Button *run_btn;
Button *open_btn;
Button *rename_btn;
- Button *run_btn;
+ Button *erase_btn;
+ Button *erase_missing_btn;
EditorAssetLibrary *asset_library;
- ProjectListFilter *project_filter;
- ProjectListFilter *project_order_filter;
-
FileDialog *scan_dir;
ConfirmationDialog *language_restart_ask;
ConfirmationDialog *erase_ask;
@@ -64,18 +73,12 @@ class ProjectManager : public Control {
ConfirmationDialog *multi_scan_ask;
ConfirmationDialog *ask_update_settings;
ConfirmationDialog *open_templates;
+
AcceptDialog *run_error_diag;
AcceptDialog *dialog_error;
ProjectDialog *npdialog;
- HBoxContainer *projects_hb;
- TabContainer *tabs;
- ProjectList *_project_list;
-
OptionButton *language_btn;
- Control *gui_base;
-
- bool importing;
void _open_asset_library();
void _scan_projects();
@@ -94,14 +97,13 @@ class ProjectManager : public Control {
void _language_selected(int p_id);
void _restart_confirm();
void _exit_dialog();
- void _scan_begin(const String &p_base);
-
void _confirm_update_settings();
void _load_recent_projects();
void _on_project_created(const String &dir);
void _on_projects_updated();
- void _update_scroll_position(const String &dir);
+ void _scan_multiple_folders(PackedStringArray p_files);
+ void _scan_begin(const String &p_base);
void _scan_dir(const String &path, List<String> *r_projects);
void _install_project(const String &p_zip_path, const String &p_title);
@@ -109,10 +111,9 @@ class ProjectManager : public Control {
void _dim_window();
void _unhandled_input(const Ref<InputEvent> &p_ev);
void _files_dropped(PackedStringArray p_files, int p_screen);
- void _scan_multiple_folders(PackedStringArray p_files);
- void _on_order_option_changed();
- void _on_filter_option_changed();
+ void _on_order_option_changed(int p_idx);
+ void _on_search_term_changed(const String &p_term);
protected:
void _notification(int p_what);
@@ -123,41 +124,4 @@ public:
~ProjectManager();
};
-class ProjectListFilter : public HBoxContainer {
- GDCLASS(ProjectListFilter, HBoxContainer);
-
-public:
- enum FilterOption {
- FILTER_NAME,
- FILTER_PATH,
- FILTER_EDIT_DATE,
- };
-
-private:
- friend class ProjectManager;
-
- OptionButton *filter_option;
- LineEdit *search_box;
- bool has_search_box;
- FilterOption _current_filter;
-
- void _search_text_changed(const String &p_newtext);
- void _filter_option_selected(int p_idx);
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- void _setup_filters(Vector<String> options);
- void add_filter_option();
- void add_search_box();
- void set_filter_size(int h_size);
- String get_search_term();
- FilterOption get_filter_option();
- void set_filter_option(FilterOption);
- ProjectListFilter();
- void clear();
-};
-
#endif // PROJECT_MANAGER_H
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index 82ac225ddb..b6621d0d1e 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -333,6 +333,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
header->add_child(search_bar);
search_box = memnew(LineEdit);
+ search_box->set_placeholder(TTR("Search"));
search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
search_bar->add_child(search_box);
diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp
index 628475bbc0..90efb11b7d 100644
--- a/editor/script_create_dialog.cpp
+++ b/editor/script_create_dialog.cpp
@@ -722,6 +722,15 @@ void ScriptCreateDialog::_update_dialog() {
}
get_ok()->set_disabled(!script_ok);
+
+ Callable entered_call = callable_mp(this, &ScriptCreateDialog::_path_entered);
+ if (script_ok) {
+ if (!file_path->is_connected("text_entered", entered_call)) {
+ file_path->connect("text_entered", entered_call);
+ }
+ } else if (file_path->is_connected("text_entered", entered_call)) {
+ file_path->disconnect("text_entered", entered_call);
+ }
}
void ScriptCreateDialog::_bind_methods() {
@@ -849,7 +858,6 @@ ScriptCreateDialog::ScriptCreateDialog() {
hb->connect("sort_children", callable_mp(this, &ScriptCreateDialog::_path_hbox_sorted));
file_path = memnew(LineEdit);
file_path->connect("text_changed", callable_mp(this, &ScriptCreateDialog::_path_changed));
- file_path->connect("text_entered", callable_mp(this, &ScriptCreateDialog::_path_entered));
file_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);
hb->add_child(file_path);
path_button = memnew(Button);
diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp
index 9f286bd8f6..35610ef71b 100644
--- a/editor/settings_config_dialog.cpp
+++ b/editor/settings_config_dialog.cpp
@@ -405,6 +405,7 @@ EditorSettingsDialog::EditorSettingsDialog() {
tab_general->add_child(hbc);
search_box = memnew(LineEdit);
+ search_box->set_placeholder(TTR("Search"));
search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
hbc->add_child(search_box);
@@ -449,6 +450,7 @@ EditorSettingsDialog::EditorSettingsDialog() {
tab_shortcuts->add_child(hbc);
shortcut_search_box = memnew(LineEdit);
+ shortcut_search_box->set_placeholder(TTR("Search"));
shortcut_search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
hbc->add_child(shortcut_search_box);
shortcut_search_box->connect("text_changed", callable_mp(this, &EditorSettingsDialog::_filter_shortcuts));