summaryrefslogtreecommitdiff
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/animation_track_editor.cpp17
-rw-r--r--editor/collada/collada.cpp6
-rw-r--r--editor/connections_dialog.cpp7
-rw-r--r--editor/doc/doc_data.cpp24
-rw-r--r--editor/editor_autoload_settings.cpp12
-rw-r--r--editor/editor_data.cpp21
-rw-r--r--editor/editor_data.h1
-rw-r--r--editor/editor_export.cpp2
-rw-r--r--editor/editor_file_dialog.cpp6
-rw-r--r--editor/editor_file_system.cpp3
-rw-r--r--editor/editor_help_search.cpp2
-rw-r--r--editor/editor_node.cpp77
-rw-r--r--editor/editor_node.h1
-rw-r--r--editor/editor_plugin.cpp7
-rw-r--r--editor/editor_plugin.h5
-rw-r--r--editor/editor_resource_preview.cpp6
-rw-r--r--editor/editor_settings.cpp17
-rw-r--r--editor/editor_spin_slider.cpp56
-rw-r--r--editor/editor_themes.cpp5
-rw-r--r--editor/export_template_manager.cpp6
-rw-r--r--editor/file_type_cache.cpp5
-rw-r--r--editor/filesystem_dock.cpp78
-rw-r--r--editor/filesystem_dock.h4
-rw-r--r--editor/icons/icon_editor_curve_handle.svg1
-rw-r--r--editor/icons/icon_editor_path_sharp_handle.svg1
-rw-r--r--editor/icons/icon_editor_path_smooth_handle.svg1
-rw-r--r--editor/icons/icon_timeline_indicator.svg1
-rw-r--r--editor/import/editor_import_collada.cpp24
-rw-r--r--editor/import/editor_scene_importer_gltf.cpp3
-rw-r--r--editor/import/resource_importer_csv_translation.cpp3
-rw-r--r--editor/import/resource_importer_obj.cpp6
-rw-r--r--editor/import/resource_importer_wav.cpp15
-rw-r--r--editor/node_dock.cpp7
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp3
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp11
-rw-r--r--editor/plugins/cpu_particles_2d_editor_plugin.cpp6
-rw-r--r--editor/plugins/multimesh_editor_plugin.cpp9
-rw-r--r--editor/plugins/particles_2d_editor_plugin.cpp6
-rw-r--r--editor/plugins/path_2d_editor_plugin.cpp42
-rw-r--r--editor/plugins/path_editor_plugin.cpp3
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp7
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp130
-rw-r--r--editor/plugins/theme_editor_plugin.cpp6
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp2
-rw-r--r--editor/plugins/tile_set_editor_plugin.cpp3
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp111
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h9
-rw-r--r--editor/project_manager.cpp123
-rw-r--r--editor/project_manager.h1
-rw-r--r--editor/scene_tree_dock.cpp11
-rw-r--r--editor/scene_tree_editor.cpp54
51 files changed, 564 insertions, 403 deletions
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 014bb08144..c93dc2b340 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -1748,7 +1748,11 @@ void AnimationTimelineEdit::_play_position_draw() {
if (px >= get_name_limit() && px < (play_position->get_size().width - get_buttons_width())) {
Color color = get_color("accent_color", "Editor");
- play_position->draw_line(Point2(px, 0), Point2(px, h), color, Math::round(EDSCALE));
+ play_position->draw_line(Point2(px, 0), Point2(px, h), color, Math::round(2 * EDSCALE));
+ play_position->draw_texture(
+ get_icon("TimelineIndicator", "EditorIcons"),
+ Point2(px - get_icon("TimelineIndicator", "EditorIcons")->get_width() * 0.5, 0),
+ color);
}
}
@@ -2438,7 +2442,7 @@ void AnimationTrackEdit::_play_position_draw() {
if (px >= timeline->get_name_limit() && px < (get_size().width - timeline->get_buttons_width())) {
Color color = get_color("accent_color", "Editor");
- play_position->draw_line(Point2(px, 0), Point2(px, h), color, Math::round(EDSCALE));
+ play_position->draw_line(Point2(px, 0), Point2(px, h), color, Math::round(2 * EDSCALE));
}
}
@@ -3184,7 +3188,7 @@ void AnimationTrackEditGroup::_notification(int p_what) {
if (px >= timeline->get_name_limit() && px < (get_size().width - timeline->get_buttons_width())) {
Color accent = get_color("accent_color", "Editor");
- draw_line(Point2(px, 0), Point2(px, get_size().height), accent, Math::round(EDSCALE));
+ draw_line(Point2(px, 0), Point2(px, get_size().height), accent, Math::round(2 * EDSCALE));
}
}
}
@@ -5050,10 +5054,9 @@ float AnimationTrackEditor::get_moving_selection_offset() const {
void AnimationTrackEditor::_box_selection_draw() {
- Color color = get_color("accent_color", "Editor");
- color.a = 0.2;
- Rect2 rect = Rect2(Point2(), box_selection->get_size());
- box_selection->draw_rect(rect, color);
+ const Rect2 selection_rect = Rect2(Point2(), box_selection->get_size());
+ box_selection->draw_rect(selection_rect, get_color("box_selection_fill_color", "Editor"));
+ box_selection->draw_rect(selection_rect, get_color("box_selection_stroke_color", "Editor"), false, Math::round(EDSCALE));
}
void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) {
diff --git a/editor/collada/collada.cpp b/editor/collada/collada.cpp
index edd59f3057..aea7f461f1 100644
--- a/editor/collada/collada.cpp
+++ b/editor/collada/collada.cpp
@@ -1903,8 +1903,7 @@ void Collada::_parse_animation(XMLParser &parser) {
Vector<float> &output = float_sources[output_id];
- ERR_EXPLAIN("Wrong number of keys in output");
- ERR_CONTINUE((output.size() / stride) != key_count);
+ ERR_CONTINUE_MSG((output.size() / stride) != key_count, "Wrong number of keys in output.");
for (int j = 0; j < key_count; j++) {
track.keys.write[j].data.resize(output_len);
@@ -2447,8 +2446,7 @@ void Collada::_find_morph_nodes(VisualScene *p_vscene, Node *p_node) {
state.morph_ownership_map[base] = nj->id;
break;
} else {
- ERR_EXPLAIN("Invalid scene");
- ERR_FAIL();
+ ERR_FAIL_MSG("Invalid scene.");
}
}
}
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index 48bc409b73..c5b81c4685 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -881,7 +881,6 @@ void ConnectionsDock::update_tree() {
icon = get_icon(scr->get_class(), "EditorIcons");
}
}
-
} else {
ClassDB::get_signal_list(base, &node_signals2, true);
@@ -891,6 +890,10 @@ void ConnectionsDock::update_tree() {
name = base;
}
+ if (!icon.is_valid()) {
+ icon = get_icon("Object", "EditorIcons");
+ }
+
TreeItem *pitem = NULL;
if (node_signals2.size()) {
@@ -939,7 +942,7 @@ void ConnectionsDock::update_tree() {
item->set_metadata(0, sinfo);
item->set_icon(0, get_icon("Signal", "EditorIcons"));
- // Set tooltip with the signal's documentation
+ // Set tooltip with the signal's documentation.
{
String descr;
bool found = false;
diff --git a/editor/doc/doc_data.cpp b/editor/doc/doc_data.cpp
index 5b8c8fffb8..0f99e2ba1e 100644
--- a/editor/doc/doc_data.cpp
+++ b/editor/doc/doc_data.cpp
@@ -720,8 +720,7 @@ static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> &
methods.push_back(method);
} else {
- ERR_EXPLAIN("Invalid tag in doc file: " + parser->get_node_name());
- ERR_FAIL_V(ERR_FILE_CORRUPT);
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + parser->get_node_name() + ".");
}
} else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == section)
@@ -841,8 +840,7 @@ Error DocData::_load(Ref<XMLParser> parser) {
if (parser->get_node_type() == XMLParser::NODE_TEXT)
c.tutorials.push_back(parser->get_node_data().strip_edges());
} else {
- ERR_EXPLAIN("Invalid tag in doc file: " + name3);
- ERR_FAIL_V(ERR_FILE_CORRUPT);
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + name3 + ".");
}
} else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "tutorials")
break; //end of <tutorials>
@@ -883,8 +881,7 @@ Error DocData::_load(Ref<XMLParser> parser) {
prop2.description = parser->get_node_data();
c.properties.push_back(prop2);
} else {
- ERR_EXPLAIN("Invalid tag in doc file: " + name3);
- ERR_FAIL_V(ERR_FILE_CORRUPT);
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + name3 + ".");
}
} else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "members")
@@ -912,8 +909,7 @@ Error DocData::_load(Ref<XMLParser> parser) {
prop2.description = parser->get_node_data();
c.theme_properties.push_back(prop2);
} else {
- ERR_EXPLAIN("Invalid tag in doc file: " + name3);
- ERR_FAIL_V(ERR_FILE_CORRUPT);
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + name3 + ".");
}
} else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "theme_items")
@@ -943,8 +939,7 @@ Error DocData::_load(Ref<XMLParser> parser) {
constant2.description = parser->get_node_data();
c.constants.push_back(constant2);
} else {
- ERR_EXPLAIN("Invalid tag in doc file: " + name3);
- ERR_FAIL_V(ERR_FILE_CORRUPT);
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + name3 + ".");
}
} else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "constants")
@@ -953,8 +948,7 @@ Error DocData::_load(Ref<XMLParser> parser) {
} else {
- ERR_EXPLAIN("Invalid tag in doc file: " + name2);
- ERR_FAIL_V(ERR_FILE_CORRUPT);
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + name2 + ".");
}
} else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "class")
@@ -991,10 +985,8 @@ Error DocData::save_classes(const String &p_default_path, const Map<String, Stri
Error err;
String save_file = save_path.plus_file(c.name + ".xml");
FileAccessRef f = FileAccess::open(save_file, FileAccess::WRITE, &err);
- if (err) {
- ERR_EXPLAIN("Can't write doc file: " + save_file);
- ERR_CONTINUE(err);
- }
+
+ ERR_CONTINUE_MSG(err != OK, "Can't write doc file: " + save_file + ".");
_write_string(f, 0, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp
index 7210211d90..555a7f99c8 100644
--- a/editor/editor_autoload_settings.cpp
+++ b/editor/editor_autoload_settings.cpp
@@ -315,8 +315,7 @@ void EditorAutoloadSettings::_autoload_file_callback(const String &p_path) {
Node *EditorAutoloadSettings::_create_autoload(const String &p_path) {
RES res = ResourceLoader::load(p_path);
- ERR_EXPLAIN("Can't autoload: " + p_path);
- ERR_FAIL_COND_V(res.is_null(), NULL);
+ ERR_FAIL_COND_V_MSG(res.is_null(), NULL, "Can't autoload: " + p_path + ".");
Node *n = NULL;
if (res->is_class("PackedScene")) {
Ref<PackedScene> ps = res;
@@ -325,20 +324,17 @@ Node *EditorAutoloadSettings::_create_autoload(const String &p_path) {
Ref<Script> s = res;
StringName ibt = s->get_instance_base_type();
bool valid_type = ClassDB::is_parent_class(ibt, "Node");
- ERR_EXPLAIN("Script does not inherit a Node: " + p_path);
- ERR_FAIL_COND_V(!valid_type, NULL);
+ ERR_FAIL_COND_V_MSG(!valid_type, NULL, "Script does not inherit a Node: " + p_path + ".");
Object *obj = ClassDB::instance(ibt);
- ERR_EXPLAIN("Cannot instance script for autoload, expected 'Node' inheritance, got: " + String(ibt));
- ERR_FAIL_COND_V(obj == NULL, NULL);
+ ERR_FAIL_COND_V_MSG(obj == NULL, NULL, "Cannot instance script for autoload, expected 'Node' inheritance, got: " + String(ibt) + ".");
n = Object::cast_to<Node>(obj);
n->set_script(s.get_ref_ptr());
}
- ERR_EXPLAIN("Path in autoload not a node or script: " + p_path);
- ERR_FAIL_COND_V(!n, NULL);
+ ERR_FAIL_COND_V_MSG(!n, NULL, "Path in autoload not a node or script: " + p_path + ".");
return n;
}
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index f5846c10f6..c98635d16b 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -537,6 +537,7 @@ int EditorData::add_edited_scene(int p_at_pos) {
p_at_pos = edited_scene.size();
EditedScene es;
es.root = NULL;
+ es.path = String();
es.history_current = -1;
es.version = 0;
es.live_edit_root = NodePath(String("/root"));
@@ -653,6 +654,8 @@ bool EditorData::check_and_update_scene(int p_idx) {
memdelete(edited_scene[p_idx].root);
edited_scene.write[p_idx].root = new_scene;
+ if (new_scene->get_filename() != "")
+ edited_scene.write[p_idx].path = new_scene->get_filename();
edited_scene.write[p_idx].selection = new_selection;
return true;
@@ -684,6 +687,12 @@ void EditorData::set_edited_scene_root(Node *p_root) {
ERR_FAIL_INDEX(current_edited_scene, edited_scene.size());
edited_scene.write[current_edited_scene].root = p_root;
+ if (p_root) {
+ if (p_root->get_filename() != "")
+ edited_scene.write[current_edited_scene].path = p_root->get_filename();
+ else
+ p_root->set_filename(edited_scene[current_edited_scene].path);
+ }
}
int EditorData::get_edited_scene_count() const {
@@ -773,6 +782,7 @@ String EditorData::get_scene_title(int p_idx) const {
void EditorData::set_scene_path(int p_idx, const String &p_path) {
ERR_FAIL_INDEX(p_idx, edited_scene.size());
+ edited_scene.write[p_idx].path = p_path;
if (!edited_scene[p_idx].root)
return;
@@ -783,9 +793,14 @@ String EditorData::get_scene_path(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, edited_scene.size(), String());
- if (!edited_scene[p_idx].root)
- return "";
- return edited_scene[p_idx].root->get_filename();
+ if (edited_scene[p_idx].root) {
+ if (edited_scene[p_idx].root->get_filename() == "")
+ edited_scene[p_idx].root->set_filename(edited_scene[p_idx].path);
+ else
+ return edited_scene[p_idx].root->get_filename();
+ }
+
+ return edited_scene[p_idx].path;
}
void EditorData::set_edited_scene_live_edit_root(const NodePath &p_root) {
diff --git a/editor/editor_data.h b/editor/editor_data.h
index 845878e070..df83135942 100644
--- a/editor/editor_data.h
+++ b/editor/editor_data.h
@@ -117,6 +117,7 @@ public:
struct EditedScene {
Node *root;
+ String path;
Dictionary editor_states;
List<Node *> selection;
Vector<EditorHistory::History> history_stored;
diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp
index e1f2635275..cb1754bb10 100644
--- a/editor/editor_export.cpp
+++ b/editor/editor_export.cpp
@@ -1011,7 +1011,7 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, c
if (!ftmp) {
memdelete(f);
DirAccess::remove_file_or_error(tmppath);
- ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Can't open file to read from path: " + String(tmppath));
+ ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Can't open file to read from path: " + String(tmppath) + ".");
}
const int bufsize = 16384;
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index 1f43740858..8c9aedc7b7 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -257,6 +257,7 @@ void EditorFileDialog::_post_popup() {
if (is_visible_in_tree()) {
Ref<Texture> folder = get_icon("folder", "FileDialog");
+ const Color folder_color = get_color("folder", "FileDialog");
recent->clear();
bool res = access == ACCESS_RESOURCES;
@@ -274,6 +275,7 @@ void EditorFileDialog::_post_popup() {
recent->add_item(name, folder);
recent->set_item_metadata(recent->get_item_count() - 1, recentd[i]);
+ recent->set_item_icon_modulate(recent->get_item_count() - 1, folder_color);
}
local_history.clear();
@@ -734,6 +736,7 @@ void EditorFileDialog::update_file_list() {
dir_access->list_dir_begin();
Ref<Texture> folder = get_icon("folder", "FileDialog");
+ const Color folder_color = get_color("folder", "FileDialog");
List<String> files;
List<String> dirs;
@@ -774,6 +777,7 @@ void EditorFileDialog::update_file_list() {
d["dir"] = true;
item_list->set_item_metadata(item_list->get_item_count() - 1, d);
+ item_list->set_item_icon_modulate(item_list->get_item_count() - 1, folder_color);
dirs.pop_front();
}
@@ -1200,6 +1204,7 @@ void EditorFileDialog::_update_favorites() {
String current = get_current_dir();
Ref<Texture> folder_icon = get_icon("Folder", "EditorIcons");
+ const Color folder_color = get_color("folder", "FileDialog");
favorites->clear();
favorite->set_pressed(false);
@@ -1230,6 +1235,7 @@ void EditorFileDialog::_update_favorites() {
}
favorites->set_item_metadata(favorites->get_item_count() - 1, favorited[i]);
+ favorites->set_item_icon_modulate(favorites->get_item_count() - 1, folder_color);
if (setthis) {
favorite->set_pressed(true);
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index be3df2815e..6d3377a85b 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -1930,8 +1930,7 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
Error err = da->make_dir(".import");
if (err) {
memdelete(da);
- ERR_EXPLAIN("Failed to create 'res://.import' folder.");
- ERR_FAIL();
+ ERR_FAIL_MSG("Failed to create 'res://.import' folder.");
}
}
memdelete(da);
diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp
index fbfc999dbf..af79c21f85 100644
--- a/editor/editor_help_search.cpp
+++ b/editor/editor_help_search.cpp
@@ -354,7 +354,7 @@ bool EditorHelpSearch::Runner::_phase_match_classes() {
match.constants.push_back(const_cast<DocData::ConstantDoc *>(&class_doc.constants[i]));
if (search_flags & SEARCH_PROPERTIES)
for (int i = 0; i < class_doc.properties.size(); i++)
- if (_match_string(term, class_doc.properties[i].name))
+ if (_match_string(term, class_doc.properties[i].name) || _match_string(term, class_doc.properties[i].getter) || _match_string(term, class_doc.properties[i].setter))
match.properties.push_back(const_cast<DocData::PropertyDoc *>(&class_doc.properties[i]));
if (search_flags & SEARCH_THEME_ITEMS)
for (int i = 0; i < class_doc.theme_properties.size(); i++)
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 866a90ff10..3e97dbd96c 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -1926,10 +1926,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
switch (p_option) {
case FILE_NEW_SCENE: {
- int idx = editor_data.add_edited_scene(-1);
- _scene_tab_changed(idx);
- editor_data.clear_editor_states();
- _update_scene_tabs();
+ new_scene();
} break;
case FILE_NEW_INHERITED_SCENE:
@@ -2798,8 +2795,7 @@ void EditorNode::select_editor_by_name(const String &p_name) {
}
}
- ERR_EXPLAIN("The editor name '" + p_name + "' was not found.");
- ERR_FAIL();
+ ERR_FAIL_MSG("The editor name '" + p_name + "' was not found.");
}
void EditorNode::add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed) {
@@ -2925,36 +2921,39 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled,
return;
}
- String path = cf->get_value("plugin", "script");
- path = String("res://addons").plus_file(p_addon).plus_file(path);
+ String script_path = cf->get_value("plugin", "script");
+ Ref<Script> script; // We need to save it for creating "ep" below.
- Ref<Script> script = ResourceLoader::load(path);
+ // Only try to load the script if it has a name. Else, the plugin has no init script.
+ if (script_path.length() > 0) {
+ script_path = String("res://addons").plus_file(p_addon).plus_file(script_path);
+ script = ResourceLoader::load(script_path);
- if (script.is_null()) {
- show_warning(vformat(TTR("Unable to load addon script from path: '%s'."), path));
- return;
- }
+ if (script.is_null()) {
+ show_warning(vformat(TTR("Unable to load addon script from path: '%s'."), script_path));
+ return;
+ }
- //errors in the script cause the base_type to be ""
- if (String(script->get_instance_base_type()) == "") {
- show_warning(vformat(TTR("Unable to load addon script from path: '%s' There seems to be an error in the code, please check the syntax."), path));
- return;
- }
+ // Errors in the script cause the base_type to be an empty string.
+ if (String(script->get_instance_base_type()) == "") {
+ show_warning(vformat(TTR("Unable to load addon script from path: '%s' There seems to be an error in the code, please check the syntax."), script_path));
+ return;
+ }
- //could check inheritance..
- if (String(script->get_instance_base_type()) != "EditorPlugin") {
- show_warning(vformat(TTR("Unable to load addon script from path: '%s' Base type is not EditorPlugin."), path));
- return;
- }
+ // Plugin init scripts must inherit from EditorPlugin and be tools.
+ if (String(script->get_instance_base_type()) != "EditorPlugin") {
+ show_warning(vformat(TTR("Unable to load addon script from path: '%s' Base type is not EditorPlugin."), script_path));
+ return;
+ }
- if (!script->is_tool()) {
- show_warning(vformat(TTR("Unable to load addon script from path: '%s' Script is not in tool mode."), path));
- return;
+ if (!script->is_tool()) {
+ show_warning(vformat(TTR("Unable to load addon script from path: '%s' Script is not in tool mode."), script_path));
+ return;
+ }
}
EditorPlugin *ep = memnew(EditorPlugin);
ep->set_script(script.get_ref_ptr());
- ep->set_dir_cache(p_addon);
plugin_addons[p_addon] = ep;
add_editor_plugin(ep, p_config_changed);
@@ -3162,6 +3161,14 @@ void EditorNode::fix_dependencies(const String &p_for_file) {
dependency_fixer->edit(p_for_file);
}
+int EditorNode::new_scene() {
+ int idx = editor_data.add_edited_scene(-1);
+ _scene_tab_changed(idx);
+ editor_data.clear_editor_states();
+ _update_scene_tabs();
+ return idx;
+}
+
Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, bool p_set_inherited, bool p_clear_errors, bool p_force_open_imported) {
if (!is_inside_tree()) {
@@ -3820,9 +3827,13 @@ void EditorNode::show_accept(const String &p_text, const String &p_title) {
void EditorNode::show_warning(const String &p_text, const String &p_title) {
- warning->set_text(p_text);
- warning->set_title(p_title);
- warning->popup_centered_minsize();
+ if (warning->is_inside_tree()) {
+ warning->set_text(p_text);
+ warning->set_title(p_title);
+ warning->popup_centered_minsize();
+ } else {
+ WARN_PRINTS(p_title + " " + p_text);
+ }
}
void EditorNode::_copy_warning(const String &p_str) {
@@ -4792,8 +4803,7 @@ void EditorNode::remove_control_from_dock(Control *p_control) {
}
}
- ERR_EXPLAIN("Control was not in dock");
- ERR_FAIL_COND(!dock);
+ ERR_FAIL_COND_MSG(!dock, "Control was not in dock.");
dock->remove_child(p_control);
_update_dock_slots_visibility();
@@ -5505,6 +5515,9 @@ EditorNode::EditorNode() {
}
}
+ // Define a minimum window size to prevent UI elements from overlapping or being cut off
+ OS::get_singleton()->set_min_window_size(Size2(1024, 600) * EDSCALE);
+
ResourceLoader::set_abort_on_missing_resources(false);
FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files"));
EditorFileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files"));
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 10ad2d691e..a8443549ed 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -745,6 +745,7 @@ public:
void fix_dependencies(const String &p_for_file);
void clear_scene() { _cleanup_scene(); }
+ int new_scene();
Error load_scene(const String &p_scene, bool p_ignore_broken_deps = false, bool p_set_inherited = false, bool p_clear_errors = true, bool p_force_open_imported = false);
Error load_resource(const String &p_resource, bool p_ignore_broken_deps = false);
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index 4b6afcbb86..e27f1ab9eb 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -324,13 +324,6 @@ void EditorPlugin::remove_autoload_singleton(const String &p_name) {
EditorNode::get_singleton()->get_project_settings()->get_autoload_settings()->autoload_remove(p_name);
}
-Ref<ConfigFile> EditorPlugin::get_config() {
- Ref<ConfigFile> cf = memnew(ConfigFile);
- Error err = cf->load(_dir_cache.plus_file("plugin.cfg"));
- ERR_FAIL_COND_V(err != OK, cf);
- return cf;
-}
-
ToolButton *EditorPlugin::add_control_to_bottom_panel(Control *p_control, const String &p_title) {
ERR_FAIL_NULL_V(p_control, NULL);
return EditorNode::get_singleton()->add_bottom_panel_item(p_title, p_control);
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index 7b6f55e93d..8941dfa28c 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -117,7 +117,6 @@ class EditorPlugin : public Node {
bool force_draw_over_forwarding_enabled;
String last_main_screen_name;
- String _dir_cache;
protected:
static void _bind_methods();
@@ -236,10 +235,6 @@ public:
void add_autoload_singleton(const String &p_name, const String &p_path);
void remove_autoload_singleton(const String &p_name);
- void set_dir_cache(const String &p_dir) { _dir_cache = p_dir; }
- String get_dir_cache() { return _dir_cache; }
- Ref<ConfigFile> get_config();
-
void enable_plugin();
void disable_plugin();
diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp
index 327e61cea3..4a7a9fb863 100644
--- a/editor/editor_resource_preview.cpp
+++ b/editor/editor_resource_preview.cpp
@@ -46,8 +46,7 @@ bool EditorResourcePreviewGenerator::handles(const String &p_type) const {
if (get_script_instance() && get_script_instance()->has_method("handles")) {
return get_script_instance()->call("handles", p_type);
}
- ERR_EXPLAIN("EditorResourcePreviewGenerator::handles needs to be overridden");
- ERR_FAIL_V(false);
+ ERR_FAIL_V_MSG(false, "EditorResourcePreviewGenerator::handles needs to be overridden.");
}
Ref<Texture> EditorResourcePreviewGenerator::generate(const RES &p_from, const Size2 &p_size) const {
@@ -55,8 +54,7 @@ Ref<Texture> EditorResourcePreviewGenerator::generate(const RES &p_from, const S
if (get_script_instance() && get_script_instance()->has_method("generate")) {
return get_script_instance()->call("generate", p_from, p_size);
}
- ERR_EXPLAIN("EditorResourcePreviewGenerator::generate needs to be overridden");
- ERR_FAIL_V(Ref<Texture>());
+ ERR_FAIL_V_MSG(Ref<Texture>(), "EditorResourcePreviewGenerator::generate needs to be overridden.");
}
Ref<Texture> EditorResourcePreviewGenerator::generate_from_path(const String &p_path, const Size2 &p_size) const {
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 2d2e53370d..3bd333692f 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -334,9 +334,9 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
hints["interface/editor/code_font"] = PropertyInfo(Variant::STRING, "interface/editor/code_font", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT);
_initial_set("interface/editor/dim_editor_on_dialog_popup", true);
_initial_set("interface/editor/low_processor_mode_sleep_usec", 6900); // ~144 FPS
- hints["interface/editor/low_processor_mode_sleep_usec"] = PropertyInfo(Variant::REAL, "interface/editor/low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "1,100000,1", PROPERTY_USAGE_DEFAULT);
+ hints["interface/editor/low_processor_mode_sleep_usec"] = PropertyInfo(Variant::REAL, "interface/editor/low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "1,100000,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
_initial_set("interface/editor/unfocused_low_processor_mode_sleep_usec", 50000); // 20 FPS
- hints["interface/editor/unfocused_low_processor_mode_sleep_usec"] = PropertyInfo(Variant::REAL, "interface/editor/unfocused_low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "1,100000,1", PROPERTY_USAGE_DEFAULT);
+ hints["interface/editor/unfocused_low_processor_mode_sleep_usec"] = PropertyInfo(Variant::REAL, "interface/editor/unfocused_low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "1,100000,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
_initial_set("interface/editor/separate_distraction_mode", false);
_initial_set("interface/editor/automatically_open_screenshots", true);
_initial_set("interface/editor/hide_console_window", false);
@@ -1216,7 +1216,7 @@ void EditorSettings::set_project_metadata(const String &p_section, const String
String path = get_project_settings_dir().plus_file("project_metadata.cfg");
Error err;
err = cf->load(path);
- ERR_FAIL_COND(err != OK);
+ ERR_FAIL_COND(err != OK && err != ERR_FILE_NOT_FOUND);
cf->set_value(p_section, p_key, p_data);
err = cf->save(path);
ERR_FAIL_COND(err != OK);
@@ -1451,10 +1451,7 @@ void EditorSettings::add_shortcut(const String &p_name, Ref<ShortCut> &p_shortcu
bool EditorSettings::is_shortcut(const String &p_name, const Ref<InputEvent> &p_event) const {
const Map<String, Ref<ShortCut> >::Element *E = shortcuts.find(p_name);
- if (!E) {
- ERR_EXPLAIN("Unknown Shortcut: " + p_name);
- ERR_FAIL_V(false);
- }
+ ERR_FAIL_COND_V_MSG(!E, false, "Unknown Shortcut: " + p_name + ".");
return E->get()->is_shortcut(p_event);
}
@@ -1483,10 +1480,8 @@ Ref<ShortCut> ED_GET_SHORTCUT(const String &p_path) {
}
Ref<ShortCut> sc = EditorSettings::get_singleton()->get_shortcut(p_path);
- if (!sc.is_valid()) {
- ERR_EXPLAIN("Used ED_GET_SHORTCUT with invalid shortcut: " + p_path);
- ERR_FAIL_COND_V(!sc.is_valid(), sc);
- }
+
+ ERR_FAIL_COND_V_MSG(!sc.is_valid(), sc, "Used ED_GET_SHORTCUT with invalid shortcut: " + p_path + ".");
return sc;
}
diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp
index 379b8a2980..46a30b7554 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -47,42 +47,48 @@ void EditorSpinSlider::_gui_input(const Ref<InputEvent> &p_event) {
return;
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid()) {
- if (mb->is_pressed()) {
+ if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->is_pressed()) {
- if (updown_offset != -1 && mb->get_position().x > updown_offset) {
- //there is an updown, so use it.
- if (mb->get_position().y < get_size().height / 2) {
- set_value(get_value() + get_step());
+ if (updown_offset != -1 && mb->get_position().x > updown_offset) {
+ //there is an updown, so use it.
+ if (mb->get_position().y < get_size().height / 2) {
+ set_value(get_value() + get_step());
+ } else {
+ set_value(get_value() - get_step());
+ }
+ return;
} else {
- set_value(get_value() - get_step());
+
+ grabbing_spinner_attempt = true;
+ grabbing_spinner_dist_cache = 0;
+ pre_grab_value = get_value();
+ grabbing_spinner = false;
+ grabbing_spinner_mouse_pos = Input::get_singleton()->get_mouse_position();
}
- return;
} else {
- grabbing_spinner_attempt = true;
- grabbing_spinner_dist_cache = 0;
- pre_grab_value = get_value();
- grabbing_spinner = false;
- grabbing_spinner_mouse_pos = Input::get_singleton()->get_mouse_position();
- }
- } else {
+ if (grabbing_spinner_attempt) {
- if (grabbing_spinner_attempt) {
+ if (grabbing_spinner) {
- if (grabbing_spinner) {
+ Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
+ Input::get_singleton()->warp_mouse_position(grabbing_spinner_mouse_pos);
+ update();
+ } else {
+ _focus_entered();
+ }
- Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
- Input::get_singleton()->warp_mouse_position(grabbing_spinner_mouse_pos);
- update();
- } else {
- _focus_entered();
+ grabbing_spinner = false;
+ grabbing_spinner_attempt = false;
}
-
- grabbing_spinner = false;
- grabbing_spinner_attempt = false;
}
+ } else if (mb->get_button_index() == BUTTON_WHEEL_UP || mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+
+ if (grabber->is_visible())
+ call_deferred("update");
}
}
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 97af0d08ea..d962001b38 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -351,6 +351,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("dark_color_3", "Editor", dark_color_3);
theme->set_color("contrast_color_1", "Editor", contrast_color_1);
theme->set_color("contrast_color_2", "Editor", contrast_color_2);
+ theme->set_color("box_selection_fill_color", "Editor", accent_color * Color(1, 1, 1, 0.3));
+ theme->set_color("box_selection_stroke_color", "Editor", accent_color * Color(1, 1, 1, 0.8));
theme->set_color("font_color", "Editor", font_color);
theme->set_color("highlighted_font_color", "Editor", font_color_hl);
@@ -1064,6 +1066,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// FileDialog
theme->set_icon("folder", "FileDialog", theme->get_icon("Folder", "EditorIcons"));
+ // Use a different color for folder icons to make them easier to distinguish from files.
+ // On a light theme, the icon will be dark, so we need to lighten it before blending it with the accent color.
+ theme->set_color("folder", "FileDialog", (dark_theme ? Color(1, 1, 1) : Color(5, 5, 5)).linear_interpolate(accent_color, 0.7));
theme->set_color("files_disabled", "FileDialog", font_color_disabled);
// color picker
diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp
index 72a4b43737..68e859966c 100644
--- a/editor/export_template_manager.cpp
+++ b/editor/export_template_manager.cpp
@@ -321,8 +321,7 @@ bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_
if (!f) {
ret = unzGoToNextFile(pkg);
fc++;
- ERR_EXPLAIN("Can't open file from path: " + String(to_write));
- ERR_CONTINUE(true);
+ ERR_CONTINUE_MSG(true, "Can't open file from path: " + String(to_write) + ".");
}
f->store_buffer(data.ptr(), data.size());
@@ -591,8 +590,7 @@ Error ExportTemplateManager::install_android_template() {
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
unzFile pkg = unzOpen2(source_zip.utf8().get_data(), &io);
- ERR_EXPLAIN("Android sources not in zip format");
- ERR_FAIL_COND_V(!pkg, ERR_CANT_OPEN);
+ ERR_FAIL_COND_V_MSG(!pkg, ERR_CANT_OPEN, "Android sources not in zip format.");
int ret = unzGoToFirstFile(pkg);
diff --git a/editor/file_type_cache.cpp b/editor/file_type_cache.cpp
index 1bcbc45d3b..746d38f2b5 100644
--- a/editor/file_type_cache.cpp
+++ b/editor/file_type_cache.cpp
@@ -83,11 +83,8 @@ void FileTypeCache::save() {
GLOBAL_LOCK_FUNCTION
String project = ProjectSettings::get_singleton()->get_resource_path();
FileAccess *f = FileAccess::open(project + "/file_type_cache.cch", FileAccess::WRITE);
- if (!f) {
- ERR_EXPLAIN(TTR("Can't open file_type_cache.cch for writing, not saving file type cache!"));
- ERR_FAIL();
- }
+ ERR_FAIL_COND_MSG(!f, "Can't open file_type_cache.cch for writing, not saving file type cache!");
const String *K = NULL;
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 8e332ad20e..83904800e9 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -39,6 +39,7 @@
#include "editor_node.h"
#include "editor_settings.h"
#include "scene/main/viewport.h"
+#include "scene/resources/packed_scene.h"
Ref<Texture> FileSystemDock::_get_tree_item_icon(EditorFileSystemDirectory *p_dir, int p_idx) {
Ref<Texture> file_icon;
@@ -63,6 +64,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
subdirectory_item->set_text(0, dname);
subdirectory_item->set_icon(0, get_icon("Folder", "EditorIcons"));
+ subdirectory_item->set_icon_color(0, get_color("folder", "FileDialog"));
subdirectory_item->set_selectable(0, true);
String lpath = p_dir->get_path();
subdirectory_item->set_metadata(0, lpath);
@@ -185,15 +187,19 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
continue;
Ref<Texture> folder_icon = get_icon("Folder", "EditorIcons");
+ const Color folder_color = get_color("folder", "FileDialog");
String text;
Ref<Texture> icon;
+ Color color;
if (fave == "res://") {
text = "/";
icon = folder_icon;
+ color = folder_color;
} else if (fave.ends_with("/")) {
text = fave.substr(0, fave.length() - 1).get_file();
icon = folder_icon;
+ color = folder_color;
} else {
text = fave.get_file();
int index;
@@ -203,12 +209,14 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
} else {
icon = get_icon("File", "EditorIcons");
}
+ color = Color(1, 1, 1);
}
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_icon_color(0, color);
ti->set_tooltip(0, fave);
ti->set_selectable(0, true);
ti->set_metadata(0, fave);
@@ -452,8 +460,7 @@ void FileSystemDock::_navigate_to_path(const String &p_path, bool p_select_in_fa
path = target_path + "/";
} else {
memdelete(dirAccess);
- ERR_EXPLAIN(vformat(TTR("Cannot navigate to '%s' as it has not been found in the file system!"), p_path));
- ERR_FAIL();
+ ERR_FAIL_MSG(vformat("Cannot navigate to '%s' as it has not been found in the file system!", p_path));
}
memdelete(dirAccess);
}
@@ -639,6 +646,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
}
Ref<Texture> folder_icon = (use_thumbnails) ? folder_thumbnail : get_icon("folder", "FileDialog");
+ const Color folder_color = get_color("folder", "FileDialog");
// Build the FileInfo list
List<FileInfo> filelist;
@@ -716,6 +724,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
files->set_item_metadata(files->get_item_count() - 1, bd);
files->set_item_selectable(files->get_item_count() - 1, false);
+ files->set_item_icon_modulate(files->get_item_count() - 1, folder_color);
}
for (int i = 0; i < efd->get_subdir_count(); i++) {
@@ -724,6 +733,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
files->add_item(dname, folder_icon, true);
files->set_item_metadata(files->get_item_count() - 1, directory.plus_file(dname) + "/");
+ files->set_item_icon_modulate(files->get_item_count() - 1, folder_color);
if (cselection.has(dname)) {
files->select(files->get_item_count() - 1, false);
@@ -1250,6 +1260,48 @@ void FileSystemDock::_make_dir_confirm() {
}
}
+void FileSystemDock::_make_scene_confirm() {
+ String scene_name = make_scene_dialog_text->get_text().strip_edges();
+
+ if (scene_name.length() == 0) {
+ EditorNode::get_singleton()->show_warning(TTR("No name provided."));
+ return;
+ }
+
+ String directory = path;
+ if (!directory.ends_with("/")) {
+ directory = directory.get_base_dir();
+ }
+
+ String extension = scene_name.get_extension();
+ List<String> extensions;
+ Ref<PackedScene> sd = memnew(PackedScene);
+ ResourceSaver::get_recognized_extensions(sd, &extensions);
+
+ bool extension_correct = false;
+ for (List<String>::Element *E = extensions.front(); E; E = E->next()) {
+ if (E->get() == extension) {
+ extension_correct = true;
+ break;
+ }
+ }
+ if (!extension_correct)
+ scene_name = scene_name.get_basename() + ".tscn";
+
+ scene_name = directory.plus_file(scene_name);
+
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ if (da->file_exists(scene_name)) {
+ EditorNode::get_singleton()->show_warning(TTR("A file or folder with this name already exists."));
+ memdelete(da);
+ return;
+ }
+ memdelete(da);
+
+ int idx = editor->new_scene();
+ editor->get_editor_data().set_scene_path(idx, scene_name);
+}
+
void FileSystemDock::_file_deleted(String p_file) {
emit_signal("file_deleted", p_file);
}
@@ -1698,6 +1750,13 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
make_dir_dialog_text->grab_focus();
} break;
+ case FILE_NEW_SCENE: {
+ make_scene_dialog_text->set_text("new scene");
+ make_scene_dialog_text->select_all();
+ make_scene_dialog->popup_centered_minsize(Size2(250, 80) * EDSCALE);
+ make_scene_dialog_text->grab_focus();
+ } break;
+
case FILE_NEW_SCRIPT: {
// Create a new script
String fpath = path;
@@ -2157,6 +2216,7 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str
p_popup->add_separator();
if (p_display_path_dependent_options) {
p_popup->add_item(TTR("New Folder..."), FILE_NEW_FOLDER);
+ p_popup->add_item(TTR("New Scene..."), FILE_NEW_SCENE);
p_popup->add_item(TTR("New Script..."), FILE_NEW_SCRIPT);
p_popup->add_item(TTR("New Resource..."), FILE_NEW_RESOURCE);
}
@@ -2195,6 +2255,7 @@ void FileSystemDock::_tree_rmb_empty(const Vector2 &p_pos) {
tree_popup->clear();
tree_popup->set_size(Size2(1, 1));
tree_popup->add_item(TTR("New Folder..."), FILE_NEW_FOLDER);
+ tree_popup->add_item(TTR("New Scene..."), FILE_NEW_SCENE);
tree_popup->add_item(TTR("New Script..."), FILE_NEW_SCRIPT);
tree_popup->add_item(TTR("New Resource..."), FILE_NEW_RESOURCE);
tree_popup->set_position(tree->get_global_position() + p_pos);
@@ -2237,6 +2298,7 @@ void FileSystemDock::_file_list_rmb_pressed(const Vector2 &p_pos) {
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 Scene..."), FILE_NEW_SCENE);
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);
@@ -2411,6 +2473,7 @@ void FileSystemDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_fs_changed"), &FileSystemDock::_fs_changed);
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("_make_scene_confirm"), &FileSystemDock::_make_scene_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));
ClassDB::bind_method(D_METHOD("_move_with_overwrite"), &FileSystemDock::_move_with_overwrite);
@@ -2626,6 +2689,17 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
make_dir_dialog->register_text_enter(make_dir_dialog_text);
make_dir_dialog->connect("confirmed", this, "_make_dir_confirm");
+ make_scene_dialog = memnew(ConfirmationDialog);
+ make_scene_dialog->set_title(TTR("Create Scene"));
+ VBoxContainer *make_scene_dialog_vb = memnew(VBoxContainer);
+ make_scene_dialog->add_child(make_scene_dialog_vb);
+
+ make_scene_dialog_text = memnew(LineEdit);
+ make_scene_dialog_vb->add_margin_child(TTR("Name:"), make_scene_dialog_text);
+ add_child(make_scene_dialog);
+ make_scene_dialog->register_text_enter(make_scene_dialog_text);
+ make_scene_dialog->connect("confirmed", this, "_make_scene_confirm");
+
make_script_dialog_text = memnew(ScriptCreateDialog);
make_script_dialog_text->set_title(TTR("Create Script"));
add_child(make_script_dialog_text);
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index 6de370ad29..cc5ba94b48 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -87,6 +87,7 @@ private:
FILE_INFO,
FILE_NEW_FOLDER,
FILE_NEW_SCRIPT,
+ FILE_NEW_SCENE,
FILE_SHOW_IN_EXPLORER,
FILE_COPY_PATH,
FILE_NEW_RESOURCE,
@@ -135,6 +136,8 @@ private:
LineEdit *duplicate_dialog_text;
ConfirmationDialog *make_dir_dialog;
LineEdit *make_dir_dialog_text;
+ ConfirmationDialog *make_scene_dialog;
+ LineEdit *make_scene_dialog_text;
ConfirmationDialog *overwrite_dialog;
ScriptCreateDialog *make_script_dialog_text;
CreateDialog *new_resource_dialog;
@@ -213,6 +216,7 @@ private:
void _resource_created() const;
void _make_dir_confirm();
+ void _make_scene_confirm();
void _rename_operation_confirm();
void _duplicate_operation_confirm();
void _move_with_overwrite();
diff --git a/editor/icons/icon_editor_curve_handle.svg b/editor/icons/icon_editor_curve_handle.svg
new file mode 100644
index 0000000000..c405ceab9d
--- /dev/null
+++ b/editor/icons/icon_editor_curve_handle.svg
@@ -0,0 +1 @@
+<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><circle cx="5" cy="5" fill="#fefefe" r="2.75" stroke="#000" stroke-linecap="square"/></svg> \ No newline at end of file
diff --git a/editor/icons/icon_editor_path_sharp_handle.svg b/editor/icons/icon_editor_path_sharp_handle.svg
new file mode 100644
index 0000000000..db160dfeae
--- /dev/null
+++ b/editor/icons/icon_editor_path_sharp_handle.svg
@@ -0,0 +1 @@
+<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><path d="m-3.035534-10.106602h6.071068v6.071068h-6.071068z" fill="#fefefe" stroke="#000" stroke-linecap="square" transform="matrix(-.70710678 .70710678 -.70710678 -.70710678 0 0)"/></svg> \ No newline at end of file
diff --git a/editor/icons/icon_editor_path_smooth_handle.svg b/editor/icons/icon_editor_path_smooth_handle.svg
new file mode 100644
index 0000000000..34f3d290bd
--- /dev/null
+++ b/editor/icons/icon_editor_path_smooth_handle.svg
@@ -0,0 +1 @@
+<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><path d="m1.5-8.5h7v7h-7z" fill="#fefefe" stroke="#000" stroke-linecap="square" transform="rotate(90)"/></svg> \ No newline at end of file
diff --git a/editor/icons/icon_timeline_indicator.svg b/editor/icons/icon_timeline_indicator.svg
new file mode 100644
index 0000000000..fd18192705
--- /dev/null
+++ b/editor/icons/icon_timeline_indicator.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 0h10l-4 4h-2z" fill="#fefefe"/></svg> \ No newline at end of file
diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp
index 1c4a8c43a9..449124acec 100644
--- a/editor/import/editor_import_collada.cpp
+++ b/editor/import/editor_import_collada.cpp
@@ -692,16 +692,6 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
pre_weights[w_i] = weights;
- /*
- for(Set<int>::Element *E=vertex_map[w_i].front();E;E=E->next()) {
-
- int dst = E->get();
- ERR_EXPLAIN("invalid vertex index in array");
- ERR_FAIL_INDEX_V(dst,vertex_array.size(),ERR_INVALID_DATA);
- vertex_array[dst].weights=weights;
-
- }*/
-
index_ofs += wstride * amount;
}
@@ -711,7 +701,6 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
Set<Collada::Vertex> vertex_set; //vertex set will be the vertices
List<int> indices_list; //indices will be the indices
- //Map<int,Set<int> > vertex_map; //map vertices (for setting skinning/morph)
/**************************/
/* CREATE PRIMITIVE ARRAY */
@@ -834,9 +823,6 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
vertex_set.insert(vertex);
}
- /* if (!vertex_map.has(vertex_index))
- vertex_map[vertex_index]=Set<int>();
- vertex_map[vertex_index].insert(index); //should be outside..*/
//build triangles if needed
if (j == 0)
prev2[0] = index;
@@ -1204,10 +1190,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
}
}
- if (ngsource != "") {
- ERR_EXPLAIN("Controller Instance Source '" + ngsource + "' is neither skin or morph!");
- ERR_FAIL_V(ERR_INVALID_DATA);
- }
+ ERR_FAIL_COND_V_MSG(ngsource != "", ERR_INVALID_DATA, "Controller instance source '" + ngsource + "' is neither skin or morph!");
} else {
meshid = ng2->source;
@@ -1608,7 +1591,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
}
if (xform_idx == -1) {
- WARN_PRINTS("Collada: Couldn't find matching node " + at.target + " xform for track " + at.param);
+ WARN_PRINTS("Collada: Couldn't find matching node " + at.target + " xform for track " + at.param + ".");
continue;
}
@@ -1630,8 +1613,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
} else if (data.size() == xf.data.size()) {
xf.data = data;
} else {
- ERR_EXPLAIN("Component " + at.component + " has datasize " + itos(data.size()) + ", xfdatasize " + itos(xf.data.size()));
- ERR_CONTINUE(data.size() != xf.data.size());
+ ERR_CONTINUE_MSG(data.size() != xf.data.size(), "Component " + at.component + " has datasize " + itos(data.size()) + ", xfdatasize " + itos(xf.data.size()) + ".");
}
}
diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp
index c9c5b3818f..84dd1aa866 100644
--- a/editor/import/editor_scene_importer_gltf.cpp
+++ b/editor/import/editor_scene_importer_gltf.cpp
@@ -1544,8 +1544,7 @@ Error EditorSceneImporterGLTF::_parse_cameras(GLTFState &state) {
camera.fov_size = 10;
}
} else {
- ERR_EXPLAIN("Camera should be in 'orthographic' or 'perspective'");
- ERR_FAIL_V(ERR_PARSE_ERROR);
+ ERR_FAIL_V_MSG(ERR_PARSE_ERROR, "Camera should be in 'orthographic' or 'perspective'");
}
state.cameras.push_back(camera);
diff --git a/editor/import/resource_importer_csv_translation.cpp b/editor/import/resource_importer_csv_translation.cpp
index cfcdbc8de4..301422a25a 100644
--- a/editor/import/resource_importer_csv_translation.cpp
+++ b/editor/import/resource_importer_csv_translation.cpp
@@ -101,8 +101,7 @@ Error ResourceImporterCSVTranslation::import(const String &p_source_file, const
for (int i = 1; i < line.size(); i++) {
String locale = line[i];
- ERR_EXPLAIN("Error importing CSV translation: '" + locale + "' is not a valid locale");
- ERR_FAIL_COND_V(!TranslationServer::is_locale_valid(locale), ERR_PARSE_ERROR);
+ ERR_FAIL_COND_V_MSG(!TranslationServer::is_locale_valid(locale), ERR_PARSE_ERROR, "Error importing CSV translation: '" + locale + "' is not a valid locale.");
locales.push_back(locale);
Ref<Translation> translation;
diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp
index 868f67fd77..9061c92f6e 100644
--- a/editor/import/resource_importer_obj.cpp
+++ b/editor/import/resource_importer_obj.cpp
@@ -45,8 +45,7 @@ uint32_t EditorOBJImporter::get_import_flags() const {
static Error _parse_material_library(const String &p_path, Map<String, Ref<SpatialMaterial> > &material_map, List<String> *r_missing_deps) {
FileAccessRef f = FileAccess::open(p_path, FileAccess::READ);
- ERR_EXPLAIN(vformat("Couldn't open MTL file '%s', it may not exist or not be readable.", p_path));
- ERR_FAIL_COND_V(!f, ERR_CANT_OPEN);
+ ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Couldn't open MTL file '%s', it may not exist or not be readable.", p_path));
Ref<SpatialMaterial> current;
String current_name;
@@ -207,8 +206,7 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Spati
static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p_single_mesh, bool p_generate_tangents, bool p_optimize, Vector3 p_scale_mesh, List<String> *r_missing_deps) {
FileAccessRef f = FileAccess::open(p_path, FileAccess::READ);
- ERR_EXPLAIN(vformat("Couldn't open OBJ file '%s', it may not exist or not be readable.", p_path));
- ERR_FAIL_COND_V(!f, ERR_CANT_OPEN);
+ ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Couldn't open OBJ file '%s', it may not exist or not be readable.", p_path));
Ref<ArrayMesh> mesh;
mesh.instance();
diff --git a/editor/import/resource_importer_wav.cpp b/editor/import/resource_importer_wav.cpp
index d267b29224..4fd4ab2f2e 100644
--- a/editor/import/resource_importer_wav.cpp
+++ b/editor/import/resource_importer_wav.cpp
@@ -123,8 +123,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
file->close();
memdelete(file);
- ERR_EXPLAIN("Not a WAV file (no WAVE RIFF Header)");
- ERR_FAIL_V(ERR_FILE_UNRECOGNIZED);
+ ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "Not a WAV file (no WAVE RIFF header).");
}
int format_bits = 0;
@@ -166,16 +165,14 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
if (compression_code != 1 && compression_code != 3) {
file->close();
memdelete(file);
- ERR_EXPLAIN("Format not supported for WAVE file (not PCM). Save WAVE files as uncompressed PCM instead.");
- ERR_FAIL_V(ERR_INVALID_DATA);
+ ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Format not supported for WAVE file (not PCM). Save WAVE files as uncompressed PCM instead.");
}
format_channels = file->get_16();
if (format_channels != 1 && format_channels != 2) {
file->close();
memdelete(file);
- ERR_EXPLAIN("Format not supported for WAVE file (not stereo or mono).");
- ERR_FAIL_V(ERR_INVALID_DATA);
+ ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Format not supported for WAVE file (not stereo or mono).");
}
format_freq = file->get_32(); //sampling rate
@@ -187,8 +184,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
if (format_bits % 8 || format_bits == 0) {
file->close();
memdelete(file);
- ERR_EXPLAIN("Invalid amount of bits in the sample (should be one of 8, 16, 24 or 32).");
- ERR_FAIL_V(ERR_INVALID_DATA);
+ ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Invalid amount of bits in the sample (should be one of 8, 16, 24 or 32).");
}
/* Don't need anything else, continue */
@@ -258,8 +254,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
if (file->eof_reached()) {
file->close();
memdelete(file);
- ERR_EXPLAIN("Premature end of file.");
- ERR_FAIL_V(ERR_FILE_CORRUPT);
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Premature end of file.");
}
}
diff --git a/editor/node_dock.cpp b/editor/node_dock.cpp
index 1c0151ed0a..d6df3bd369 100644
--- a/editor/node_dock.cpp
+++ b/editor/node_dock.cpp
@@ -56,10 +56,7 @@ void NodeDock::_bind_methods() {
void NodeDock::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE) {
- connections_button->set_icon(get_icon("Signals", "EditorIcons"));
- groups_button->set_icon(get_icon("Groups", "EditorIcons"));
- } else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
+ if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
connections_button->set_icon(get_icon("Signals", "EditorIcons"));
groups_button->set_icon(get_icon("Groups", "EditorIcons"));
}
@@ -131,7 +128,7 @@ NodeDock::NodeDock() {
groups->hide();
select_a_node = memnew(Label);
- select_a_node->set_text(TTR("Select a Node to edit Signals and Groups."));
+ select_a_node->set_text(TTR("Select a single node to edit its signals and groups."));
select_a_node->set_v_size_flags(SIZE_EXPAND_FILL);
select_a_node->set_valign(Label::VALIGN_CENTER);
select_a_node->set_align(Label::ALIGN_CENTER);
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index 574b47d770..7f023af848 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -571,7 +571,8 @@ void AbstractPolygon2DEditor::forward_canvas_draw_over_viewport(Control *p_overl
return;
Transform2D xform = canvas_item_editor->get_canvas_transform() * _get_node()->get_global_transform();
- const Ref<Texture> handle = get_icon("EditorHandle", "EditorIcons");
+ // All polygon points are sharp, so use the sharp handle icon
+ const Ref<Texture> handle = get_icon("EditorPathSharpHandle", "EditorIcons");
const Vertex active_point = get_active_point();
const int n_polygons = _get_polygon_count();
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 98c2f21e45..cc707dbf44 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -2918,10 +2918,15 @@ void CanvasItemEditor::_draw_selection() {
Point2 bsfrom = transform.xform(drag_from);
Point2 bsto = transform.xform(box_selecting_to);
- VisualServer::get_singleton()->canvas_item_add_rect(
- ci,
+ viewport->draw_rect(
Rect2(bsfrom, bsto - bsfrom),
- get_color("accent_color", "Editor") * Color(1, 1, 1, 0.375));
+ get_color("box_selection_fill_color", "Editor"));
+
+ viewport->draw_rect(
+ Rect2(bsfrom, bsto - bsfrom),
+ get_color("box_selection_stroke_color", "Editor"),
+ false,
+ Math::round(EDSCALE));
}
if (drag_type == DRAG_ROTATE) {
diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
index 7c2116f06b..9d625af959 100644
--- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp
+++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
@@ -87,8 +87,7 @@ void CPUParticles2DEditorPlugin::_generate_emission_mask() {
Ref<Image> img;
img.instance();
Error err = ImageLoader::load_image(source_emission_file, img);
- ERR_EXPLAIN(TTR("Error loading image:") + " " + source_emission_file);
- ERR_FAIL_COND(err != OK);
+ ERR_FAIL_COND_MSG(err != OK, "Error loading image: " + source_emission_file + ".");
if (img->is_compressed()) {
img->decompress();
@@ -196,8 +195,7 @@ void CPUParticles2DEditorPlugin::_generate_emission_mask() {
valid_normals.resize(vpc);
}
- ERR_EXPLAIN(TTR("No pixels with transparency > 128 in image..."));
- ERR_FAIL_COND(valid_positions.size() == 0);
+ ERR_FAIL_COND_MSG(valid_positions.size() == 0, "No pixels with transparency > 128 in image...");
if (capture_colors) {
PoolColorArray pca;
diff --git a/editor/plugins/multimesh_editor_plugin.cpp b/editor/plugins/multimesh_editor_plugin.cpp
index d59efe49e7..3ea014a38d 100644
--- a/editor/plugins/multimesh_editor_plugin.cpp
+++ b/editor/plugins/multimesh_editor_plugin.cpp
@@ -147,9 +147,8 @@ void MultiMeshEditor::_populate() {
w.release();
PoolVector<Face3> faces = geometry;
- ERR_EXPLAIN(TTR("Parent has no solid faces to populate."));
int facecount = faces.size();
- ERR_FAIL_COND(!facecount);
+ ERR_FAIL_COND_MSG(!facecount, "Parent has no solid faces to populate.");
PoolVector<Face3>::Read r = faces.read();
@@ -164,10 +163,8 @@ void MultiMeshEditor::_populate() {
area_accum += area;
}
- ERR_EXPLAIN(TTR("Couldn't map area."));
- ERR_FAIL_COND(triangle_area_map.size() == 0);
- ERR_EXPLAIN(TTR("Couldn't map area."));
- ERR_FAIL_COND(area_accum == 0);
+ ERR_FAIL_COND_MSG(triangle_area_map.size() == 0, "Couldn't map area.");
+ ERR_FAIL_COND_MSG(area_accum == 0, "Couldn't map area.");
Ref<MultiMesh> multimesh = memnew(MultiMesh);
multimesh->set_mesh(mesh);
diff --git a/editor/plugins/particles_2d_editor_plugin.cpp b/editor/plugins/particles_2d_editor_plugin.cpp
index e68bca55cb..8025e12885 100644
--- a/editor/plugins/particles_2d_editor_plugin.cpp
+++ b/editor/plugins/particles_2d_editor_plugin.cpp
@@ -160,8 +160,7 @@ void Particles2DEditorPlugin::_generate_emission_mask() {
Ref<Image> img;
img.instance();
Error err = ImageLoader::load_image(source_emission_file, img);
- ERR_EXPLAIN(TTR("Error loading image:") + " " + source_emission_file);
- ERR_FAIL_COND(err != OK);
+ ERR_FAIL_COND_MSG(err != OK, "Error loading image: " + source_emission_file + ".");
if (img->is_compressed()) {
img->decompress();
@@ -269,8 +268,7 @@ void Particles2DEditorPlugin::_generate_emission_mask() {
valid_normals.resize(vpc);
}
- ERR_EXPLAIN(TTR("No pixels with transparency > 128 in image..."));
- ERR_FAIL_COND(valid_positions.size() == 0);
+ ERR_FAIL_COND_MSG(valid_positions.size() == 0, "No pixels with transparency > 128 in image...");
PoolVector<uint8_t> texdata;
diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp
index b87bd29cbd..f02dc0bd6d 100644
--- a/editor/plugins/path_2d_editor_plugin.cpp
+++ b/editor/plugins/path_2d_editor_plugin.cpp
@@ -367,18 +367,18 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
void Path2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
- if (!node)
+ if (!node || !node->is_visible_in_tree() || !node->get_curve().is_valid())
return;
- if (!node->is_visible_in_tree())
- return;
+ Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
- if (!node->get_curve().is_valid())
- return;
+ const Ref<Texture> path_sharp_handle = get_icon("EditorPathSharpHandle", "EditorIcons");
+ const Ref<Texture> path_smooth_handle = get_icon("EditorPathSmoothHandle", "EditorIcons");
+ // Both handle icons must be of the same size
+ const Size2 handle_size = path_sharp_handle->get_size();
- Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
- Ref<Texture> handle = get_icon("EditorHandle", "EditorIcons");
- Size2 handle_size = handle->get_size();
+ const Ref<Texture> curve_handle = get_icon("EditorCurveHandle", "EditorIcons");
+ const Size2 curve_handle_size = curve_handle->get_size();
Ref<Curve2D> curve = node->get_curve();
@@ -387,19 +387,35 @@ void Path2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
for (int i = 0; i < len; i++) {
Vector2 point = xform.xform(curve->get_point_position(i));
- vpc->draw_texture_rect(handle, Rect2(point - handle_size * 0.5, handle_size), false, Color(1, 1, 1, 1));
+ // Determines the point icon to be used
+ bool smooth = false;
if (i < len - 1) {
Vector2 pointout = xform.xform(curve->get_point_position(i) + curve->get_point_out(i));
- vpc->draw_line(point, pointout, Color(0.5, 0.5, 1.0, 0.8), 1.0);
- vpc->draw_texture_rect(handle, Rect2(pointout - handle_size * 0.5, handle_size), false, Color(1, 0.5, 1, 0.3));
+ if (point != pointout) {
+ smooth = true;
+ // Draw the line with a dark and light color to be visible on all backgrounds
+ vpc->draw_line(point, pointout, Color(0, 0, 0, 0.5), Math::round(EDSCALE), true);
+ vpc->draw_line(point, pointout, Color(1, 1, 1, 0.5), Math::round(EDSCALE), true);
+ vpc->draw_texture_rect(curve_handle, Rect2(pointout - curve_handle_size * 0.5, curve_handle_size), false, Color(1, 1, 1, 0.75));
+ }
}
if (i > 0) {
Vector2 pointin = xform.xform(curve->get_point_position(i) + curve->get_point_in(i));
- vpc->draw_line(point, pointin, Color(0.5, 0.5, 1.0, 0.8), 1.0);
- vpc->draw_texture_rect(handle, Rect2(pointin - handle_size * 0.5, handle_size), false, Color(1, 0.5, 1, 0.3));
+ if (point != pointin) {
+ smooth = true;
+ // Draw the line with a dark and light color to be visible on all backgrounds
+ vpc->draw_line(point, pointin, Color(0, 0, 0, 0.5), Math::round(EDSCALE), true);
+ vpc->draw_line(point, pointin, Color(1, 1, 1, 0.5), Math::round(EDSCALE), true);
+ vpc->draw_texture_rect(curve_handle, Rect2(pointin - curve_handle_size * 0.5, curve_handle_size), false, Color(1, 1, 1, 0.75));
+ }
}
+
+ vpc->draw_texture_rect(
+ smooth ? path_smooth_handle : path_sharp_handle,
+ Rect2(point - handle_size * 0.5, handle_size),
+ false);
}
if (on_edge) {
diff --git a/editor/plugins/path_editor_plugin.cpp b/editor/plugins/path_editor_plugin.cpp
index 1ae5acc5ff..2493380585 100644
--- a/editor/plugins/path_editor_plugin.cpp
+++ b/editor/plugins/path_editor_plugin.cpp
@@ -652,7 +652,6 @@ PathSpatialGizmoPlugin::PathSpatialGizmoPlugin() {
Color path_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/path", Color(0.5, 0.5, 1.0, 0.8));
create_material("path_material", path_color);
- path_color.a = 0.4;
- create_material("path_thin_material", path_color);
+ create_material("path_thin_material", Color(0.5, 0.5, 0.5));
create_handle_material("handles");
}
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index 59004a08c0..bd532a6418 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -1045,8 +1045,8 @@ void Polygon2DEditor::_uv_draw() {
}
}
- Ref<Texture> handle = get_icon("EditorHandle", "EditorIcons");
- Ref<Texture> internal_handle = get_icon("EditorInternalHandle", "EditorIcons");
+ // All UV points are sharp, so use the sharp handle icon
+ Ref<Texture> handle = get_icon("EditorPathSharpHandle", "EditorIcons");
Color poly_line_color = Color(0.9, 0.5, 0.5);
if (polygons.size() || polygon_create.size()) {
@@ -1120,7 +1120,8 @@ void Polygon2DEditor::_uv_draw() {
if (i < uv_draw_max) {
uv_edit_draw->draw_texture(handle, mtx.xform(uvs[i]) - handle->get_size() * 0.5);
} else {
- uv_edit_draw->draw_texture(internal_handle, mtx.xform(uvs[i]) - internal_handle->get_size() * 0.5);
+ // Internal vertex
+ uv_edit_draw->draw_texture(handle, mtx.xform(uvs[i]) - handle->get_size() * 0.5, Color(0.6, 0.8, 1));
}
}
}
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index f2b1aad59d..2eb3ce1ec3 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/editor/plugins/spatial_editor_plugin.cpp
@@ -2373,16 +2373,22 @@ void SpatialEditorViewport::_draw() {
get_stylebox("Focus", "EditorStyles")->draw(surface->get_canvas_item(), r);
}
- RID ci = surface->get_canvas_item();
-
if (cursor.region_select) {
+ const Rect2 selection_rect = Rect2(cursor.region_begin, cursor.region_end - cursor.region_begin);
- VisualServer::get_singleton()->canvas_item_add_rect(
- ci,
- Rect2(cursor.region_begin, cursor.region_end - cursor.region_begin),
- get_color("accent_color", "Editor") * Color(1, 1, 1, 0.375));
+ surface->draw_rect(
+ selection_rect,
+ get_color("box_selection_fill_color", "Editor"));
+
+ surface->draw_rect(
+ selection_rect,
+ get_color("box_selection_stroke_color", "Editor"),
+ false,
+ Math::round(EDSCALE));
}
+ RID ci = surface->get_canvas_item();
+
if (message_time > 0) {
Ref<Font> font = get_font("font", "Label");
Point2 msgpos = Point2(5, get_size().y - 20);
@@ -5170,7 +5176,7 @@ void SpatialEditor::snap_selected_nodes_to_floor() {
// We add a bit of margin to the from position to avoid it from snapping
// when the spatial is already on a floor and there's another floor under
// it
- from = from + Vector3(0.0, 0.1, 0.0);
+ from = from + Vector3(0.0, 0.2, 0.0);
Dictionary d;
@@ -5185,31 +5191,56 @@ void SpatialEditor::snap_selected_nodes_to_floor() {
Array keys = snap_data.keys();
- if (keys.size()) {
- undo_redo->create_action(TTR("Snap Nodes To Floor"));
+ // The maximum height an object can travel to be snapped
+ const float max_snap_height = 20.0;
+
+ // Will be set to `true` if at least one node from the selection was sucessfully snapped
+ bool snapped_to_floor = false;
+ if (keys.size()) {
+ // For snapping to be performed, there must be solid geometry under at least one of the selected nodes.
+ // We need to check this before snapping to register the undo/redo action only if needed.
for (int i = 0; i < keys.size(); i++) {
Node *node = keys[i];
Spatial *sp = Object::cast_to<Spatial>(node);
-
Dictionary d = snap_data[node];
Vector3 from = d["from"];
- Vector3 position_offset = d["position_offset"];
-
- Vector3 to = from - Vector3(0.0, 10.0, 0.0);
+ Vector3 to = from - Vector3(0.0, max_snap_height, 0.0);
Set<RID> excluded = _get_physics_bodies_rid(sp);
if (ss->intersect_ray(from, to, result, excluded)) {
- Transform new_transform = sp->get_global_transform();
- new_transform.origin.y = result.position.y;
- new_transform.origin = new_transform.origin - position_offset;
-
- undo_redo->add_do_method(sp, "set_global_transform", new_transform);
- undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_transform());
+ snapped_to_floor = true;
}
}
- undo_redo->commit_action();
+ if (snapped_to_floor) {
+ undo_redo->create_action(TTR("Snap Nodes To Floor"));
+
+ // Perform snapping if at least one node can be snapped
+ for (int i = 0; i < keys.size(); i++) {
+ Node *node = keys[i];
+ Spatial *sp = Object::cast_to<Spatial>(node);
+ Dictionary d = snap_data[node];
+ Vector3 from = d["from"];
+ Vector3 to = from - Vector3(0.0, max_snap_height, 0.0);
+ Set<RID> excluded = _get_physics_bodies_rid(sp);
+
+ if (ss->intersect_ray(from, to, result, excluded)) {
+ Vector3 position_offset = d["position_offset"];
+ Transform new_transform = sp->get_global_transform();
+
+ new_transform.origin.y = result.position.y;
+ new_transform.origin = new_transform.origin - position_offset;
+
+ undo_redo->add_do_method(sp, "set_global_transform", new_transform);
+ undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_transform());
+ }
+ }
+
+ undo_redo->commit_action();
+ } else {
+ EditorNode::get_singleton()->show_warning(TTR("Couldn't find a solid floor to snap the selection to."));
+ }
}
}
@@ -5219,42 +5250,6 @@ void SpatialEditor::_unhandled_key_input(Ref<InputEvent> p_event) {
return;
snap_key_enabled = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
-
- Ref<InputEventKey> k = p_event;
-
- if (k.is_valid()) {
-
- // Note: need to check is_echo because first person movement keys might still be held
- if (!is_any_freelook_active() && !p_event->is_echo()) {
-
- if (!k->is_pressed())
- return;
-
- if (ED_IS_SHORTCUT("spatial_editor/tool_select", p_event)) {
- _menu_item_pressed(MENU_TOOL_SELECT);
- } else if (ED_IS_SHORTCUT("spatial_editor/tool_move", p_event)) {
- _menu_item_pressed(MENU_TOOL_MOVE);
- } else if (ED_IS_SHORTCUT("spatial_editor/tool_rotate", p_event)) {
- _menu_item_pressed(MENU_TOOL_ROTATE);
- } else if (ED_IS_SHORTCUT("spatial_editor/tool_scale", p_event)) {
- _menu_item_pressed(MENU_TOOL_SCALE);
- } else if (ED_IS_SHORTCUT("spatial_editor/snap_to_floor", p_event)) {
- snap_selected_nodes_to_floor();
- } else if (ED_IS_SHORTCUT("spatial_editor/local_coords", p_event)) {
- if (are_local_coords_enabled()) {
- _menu_item_toggled(false, MENU_TOOL_LOCAL_COORDS);
- } else {
- _menu_item_toggled(true, MENU_TOOL_LOCAL_COORDS);
- }
- } else if (ED_IS_SHORTCUT("spatial_editor/snap", p_event)) {
- if (is_snap_enabled()) {
- _menu_item_toggled(false, MENU_TOOL_USE_SNAP);
- } else {
- _menu_item_toggled(true, MENU_TOOL_USE_SNAP);
- }
- }
- }
- }
}
void SpatialEditor::_notification(int p_what) {
@@ -5528,7 +5523,8 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
tool_button[TOOL_MODE_SELECT]->set_pressed(true);
button_binds.write[0] = MENU_TOOL_SELECT;
tool_button[TOOL_MODE_SELECT]->connect("pressed", this, "_menu_item_pressed", button_binds);
- tool_button[TOOL_MODE_SELECT]->set_tooltip(TTR("Select Mode (Q)") + "\n" + keycode_get_string(KEY_MASK_CMD) + TTR("Drag: Rotate\nAlt+Drag: Move\nAlt+RMB: Depth list selection"));
+ tool_button[TOOL_MODE_SELECT]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_select", TTR("Select Mode"), KEY_Q));
+ tool_button[TOOL_MODE_SELECT]->set_tooltip(keycode_get_string(KEY_MASK_CMD) + TTR("Drag: Rotate\nAlt+Drag: Move\nAlt+RMB: Depth list selection"));
hbc_menu->add_child(memnew(VSeparator));
@@ -5538,7 +5534,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
tool_button[TOOL_MODE_MOVE]->set_flat(true);
button_binds.write[0] = MENU_TOOL_MOVE;
tool_button[TOOL_MODE_MOVE]->connect("pressed", this, "_menu_item_pressed", button_binds);
- tool_button[TOOL_MODE_MOVE]->set_tooltip(TTR("Move Mode (W)"));
+ tool_button[TOOL_MODE_MOVE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_move", TTR("Move Mode"), KEY_W));
tool_button[TOOL_MODE_ROTATE] = memnew(ToolButton);
hbc_menu->add_child(tool_button[TOOL_MODE_ROTATE]);
@@ -5546,7 +5542,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
tool_button[TOOL_MODE_ROTATE]->set_flat(true);
button_binds.write[0] = MENU_TOOL_ROTATE;
tool_button[TOOL_MODE_ROTATE]->connect("pressed", this, "_menu_item_pressed", button_binds);
- tool_button[TOOL_MODE_ROTATE]->set_tooltip(TTR("Rotate Mode (E)"));
+ tool_button[TOOL_MODE_ROTATE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_rotate", TTR("Rotate Mode"), KEY_E));
tool_button[TOOL_MODE_SCALE] = memnew(ToolButton);
hbc_menu->add_child(tool_button[TOOL_MODE_SCALE]);
@@ -5554,7 +5550,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
tool_button[TOOL_MODE_SCALE]->set_flat(true);
button_binds.write[0] = MENU_TOOL_SCALE;
tool_button[TOOL_MODE_SCALE]->connect("pressed", this, "_menu_item_pressed", button_binds);
- tool_button[TOOL_MODE_SCALE]->set_tooltip(TTR("Scale Mode (R)"));
+ tool_button[TOOL_MODE_SCALE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_scale", TTR("Scale Mode"), KEY_R));
hbc_menu->add_child(memnew(VSeparator));
@@ -5598,9 +5594,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_flat(true);
button_binds.write[0] = MENU_TOOL_LOCAL_COORDS;
tool_option_button[TOOL_OPT_LOCAL_COORDS]->connect("toggled", this, "_menu_item_toggled", button_binds);
- ED_SHORTCUT("spatial_editor/local_coords", TTR("Local Coords"), KEY_T);
- sct = ED_GET_SHORTCUT("spatial_editor/local_coords").ptr()->get_as_text();
- tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_tooltip(vformat(TTR("Local Space Mode (%s)"), sct));
+ tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_shortcut(ED_SHORTCUT("spatial_editor/local_coords", TTR("Use Local Space"), KEY_T));
tool_option_button[TOOL_OPT_USE_SNAP] = memnew(ToolButton);
hbc_menu->add_child(tool_option_button[TOOL_OPT_USE_SNAP]);
@@ -5608,9 +5602,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
tool_option_button[TOOL_OPT_USE_SNAP]->set_flat(true);
button_binds.write[0] = MENU_TOOL_USE_SNAP;
tool_option_button[TOOL_OPT_USE_SNAP]->connect("toggled", this, "_menu_item_toggled", button_binds);
- ED_SHORTCUT("spatial_editor/snap", TTR("Snap"), KEY_Y);
- sct = ED_GET_SHORTCUT("spatial_editor/snap").ptr()->get_as_text();
- tool_option_button[TOOL_OPT_USE_SNAP]->set_tooltip(vformat(TTR("Snap Mode (%s)"), sct));
+ tool_option_button[TOOL_OPT_USE_SNAP]->set_shortcut(ED_SHORTCUT("spatial_editor/snap", TTR("Use Snap"), KEY_Y));
hbc_menu->add_child(memnew(VSeparator));
@@ -5630,12 +5622,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
ED_SHORTCUT("spatial_editor/focus_selection", TTR("Focus Selection"), KEY_F);
ED_SHORTCUT("spatial_editor/align_transform_with_view", TTR("Align Transform with View"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_M);
ED_SHORTCUT("spatial_editor/align_rotation_with_view", TTR("Align Rotation with View"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_F);
-
- ED_SHORTCUT("spatial_editor/tool_select", TTR("Tool Select"), KEY_Q);
- ED_SHORTCUT("spatial_editor/tool_move", TTR("Tool Move"), KEY_W);
- ED_SHORTCUT("spatial_editor/tool_rotate", TTR("Tool Rotate"), KEY_E);
- ED_SHORTCUT("spatial_editor/tool_scale", TTR("Tool Scale"), KEY_R);
-
ED_SHORTCUT("spatial_editor/freelook_toggle", TTR("Toggle Freelook"), KEY_MASK_SHIFT + KEY_F);
PopupMenu *p;
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index 56357f298a..3055a9382c 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -191,11 +191,9 @@ void ThemeEditor::_save_template_cbk(String fname) {
}
FileAccess *file = FileAccess::open(filename, FileAccess::WRITE);
- if (!file) {
- ERR_EXPLAIN(TTR("Can't save theme to file:") + " " + filename);
- return;
- }
+ ERR_FAIL_COND_MSG(!file, "Can't save theme to file: " + filename + ".");
+
file->store_line("; ******************* ");
file->store_line("; Template Theme File ");
file->store_line("; ******************* ");
diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
index b2f06ca41f..b4cce9745e 100644
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ b/editor/plugins/tile_map_editor_plugin.cpp
@@ -2006,7 +2006,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
// Tools
paint_button = memnew(ToolButton);
paint_button->set_shortcut(ED_SHORTCUT("tile_map_editor/paint_tile", TTR("Paint Tile"), KEY_P));
- paint_button->set_tooltip(TTR("Shift+RMB: Line Draw\nShift+Ctrl+RMB: Rectangle Paint"));
+ paint_button->set_tooltip(TTR("Shift+LMB: Line Draw\nShift+Ctrl+LMB: Rectangle Paint"));
paint_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_NONE));
paint_button->set_toggle_mode(true);
toolbar->add_child(paint_button);
diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp
index 1a27e749e2..c1e85788f8 100644
--- a/editor/plugins/tile_set_editor_plugin.cpp
+++ b/editor/plugins/tile_set_editor_plugin.cpp
@@ -646,8 +646,7 @@ void TileSetEditor::_on_textures_added(const PoolStringArray &p_paths) {
for (int i = 0; i < p_paths.size(); i++) {
Ref<Texture> t = Ref<Texture>(ResourceLoader::load(p_paths[i]));
- ERR_EXPLAIN("'" + p_paths[i] + "' is not a valid texture.");
- ERR_CONTINUE(!t.is_valid());
+ ERR_CONTINUE_MSG(!t.is_valid(), "'" + p_paths[i] + "' is not a valid texture.");
if (texture_map.has(t->get_rid())) {
invalid_count++;
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index e193e237de..589964f620 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -69,8 +69,16 @@ void VisualShaderEditor::edit(VisualShader *p_visual_shader) {
}
}
visual_shader = Ref<VisualShader>(p_visual_shader);
+ if (!visual_shader->is_connected("changed", this, "_update_preview")) {
+ visual_shader->connect("changed", this, "_update_preview");
+ }
visual_shader->set_graph_offset(graph->get_scroll_ofs() / EDSCALE);
} else {
+ if (visual_shader.is_valid()) {
+ if (visual_shader->is_connected("changed", this, "")) {
+ visual_shader->disconnect("changed", this, "_update_preview");
+ }
+ }
visual_shader.unref();
}
@@ -81,6 +89,7 @@ void VisualShaderEditor::edit(VisualShader *p_visual_shader) {
_clear_buffer();
_update_custom_nodes();
_update_options_menu();
+ _update_preview();
}
_update_graph();
}
@@ -524,21 +533,23 @@ void VisualShaderEditor::_update_graph() {
offset->set_custom_minimum_size(Size2(0, 6 * EDSCALE));
node->add_child(offset);
- HBoxContainer *hb2 = memnew(HBoxContainer);
+ if (group_node->is_editable()) {
+ HBoxContainer *hb2 = memnew(HBoxContainer);
- Button *add_input_btn = memnew(Button);
- add_input_btn->set_text(TTR("Add input +"));
- add_input_btn->connect("pressed", this, "_add_input_port", varray(nodes[n_i], group_node->get_free_input_port_id(), VisualShaderNode::PORT_TYPE_VECTOR, "input" + itos(group_node->get_free_input_port_id())), CONNECT_DEFERRED);
- hb2->add_child(add_input_btn);
+ Button *add_input_btn = memnew(Button);
+ add_input_btn->set_text(TTR("Add input +"));
+ add_input_btn->connect("pressed", this, "_add_input_port", varray(nodes[n_i], group_node->get_free_input_port_id(), VisualShaderNode::PORT_TYPE_VECTOR, "input" + itos(group_node->get_free_input_port_id())), CONNECT_DEFERRED);
+ hb2->add_child(add_input_btn);
- hb2->add_spacer();
+ hb2->add_spacer();
- Button *add_output_btn = memnew(Button);
- add_output_btn->set_text(TTR("Add output +"));
- add_output_btn->connect("pressed", this, "_add_output_port", varray(nodes[n_i], group_node->get_free_output_port_id(), VisualShaderNode::PORT_TYPE_VECTOR, "output" + itos(group_node->get_free_output_port_id())), CONNECT_DEFERRED);
- hb2->add_child(add_output_btn);
+ Button *add_output_btn = memnew(Button);
+ add_output_btn->set_text(TTR("Add output +"));
+ add_output_btn->connect("pressed", this, "_add_output_port", varray(nodes[n_i], group_node->get_free_output_port_id(), VisualShaderNode::PORT_TYPE_VECTOR, "output" + itos(group_node->get_free_output_port_id())), CONNECT_DEFERRED);
+ hb2->add_child(add_output_btn);
- node->add_child(hb2);
+ node->add_child(hb2);
+ }
}
for (int i = 0; i < MAX(vsnode->get_input_port_count(), vsnode->get_output_port_count()); i++) {
@@ -1566,6 +1577,29 @@ void VisualShaderEditor::_notification(int p_what) {
node_filter->set_right_icon(Control::get_icon("Search", "EditorIcons"));
+ preview_shader->set_icon(Control::get_icon("Shader", "EditorIcons"));
+
+ {
+ Color background_color = EDITOR_GET("text_editor/highlighting/background_color");
+ Color text_color = EDITOR_GET("text_editor/highlighting/text_color");
+ Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color");
+ Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color");
+ Color symbol_color = EDITOR_GET("text_editor/highlighting/symbol_color");
+
+ preview_text->add_color_override("background_color", background_color);
+
+ for (List<String>::Element *E = keyword_list.front(); E; E = E->next()) {
+
+ preview_text->add_keyword_color(E->get(), keyword_color);
+ }
+
+ preview_text->add_font_override("font", get_font("expression", "EditorFonts"));
+ preview_text->add_color_override("font_color", text_color);
+ preview_text->add_color_override("symbol_color", symbol_color);
+ preview_text->add_color_region("/*", "*/", comment_color, false);
+ preview_text->add_color_region("//", "", comment_color, false);
+ }
+
tools->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Tools", "EditorIcons"));
if (p_what == NOTIFICATION_THEME_CHANGED && is_visible_in_tree())
@@ -2016,6 +2050,15 @@ void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
}
}
+void VisualShaderEditor::_show_preview_text() {
+ preview_showed = !preview_showed;
+ preview_text->set_visible(preview_showed);
+}
+
+void VisualShaderEditor::_update_preview() {
+ preview_text->set_text(visual_shader->get_code());
+}
+
void VisualShaderEditor::_bind_methods() {
ClassDB::bind_method("_rebuild", &VisualShaderEditor::_rebuild);
ClassDB::bind_method("_update_graph", &VisualShaderEditor::_update_graph);
@@ -2055,6 +2098,8 @@ void VisualShaderEditor::_bind_methods() {
ClassDB::bind_method("_node_resized", &VisualShaderEditor::_node_resized);
ClassDB::bind_method("_set_node_size", &VisualShaderEditor::_set_node_size);
ClassDB::bind_method("_clear_buffer", &VisualShaderEditor::_clear_buffer);
+ ClassDB::bind_method("_show_preview_text", &VisualShaderEditor::_show_preview_text);
+ ClassDB::bind_method("_update_preview", &VisualShaderEditor::_update_preview);
ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &VisualShaderEditor::get_drag_data_fw);
ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &VisualShaderEditor::can_drop_data_fw);
@@ -2081,13 +2126,23 @@ VisualShaderEditor::VisualShaderEditor() {
saved_node_pos = Point2(0, 0);
ShaderLanguage::get_keyword_list(&keyword_list);
+ preview_showed = false;
+
to_node = -1;
to_slot = -1;
from_node = -1;
from_slot = -1;
+ main_box = memnew(HSplitContainer);
+ main_box->set_v_size_flags(SIZE_EXPAND_FILL);
+ main_box->set_h_size_flags(SIZE_EXPAND_FILL);
+ add_child(main_box);
+
graph = memnew(GraphEdit);
- add_child(graph);
+ graph->get_zoom_hbox()->set_h_size_flags(SIZE_EXPAND_FILL);
+ graph->set_v_size_flags(SIZE_EXPAND_FILL);
+ graph->set_h_size_flags(SIZE_EXPAND_FILL);
+ main_box->add_child(graph);
graph->set_drag_forwarding(this);
graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR);
graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_BOOLEAN);
@@ -2136,6 +2191,25 @@ VisualShaderEditor::VisualShaderEditor() {
graph->get_zoom_hbox()->move_child(add_node, 0);
add_node->connect("pressed", this, "_show_members_dialog", varray(false));
+ preview_shader = memnew(ToolButton);
+ preview_shader->set_toggle_mode(true);
+ preview_shader->set_tooltip(TTR("Show resulted shader code."));
+ graph->get_zoom_hbox()->add_child(preview_shader);
+ preview_shader->connect("pressed", this, "_show_preview_text");
+
+ ///////////////////////////////////////
+ // PREVIEW PANEL
+ ///////////////////////////////////////
+
+ preview_text = memnew(TextEdit);
+ main_box->add_child(preview_text);
+ preview_text->set_h_size_flags(SIZE_EXPAND_FILL);
+ preview_text->set_v_size_flags(SIZE_EXPAND_FILL);
+ preview_text->set_visible(preview_showed);
+ preview_text->set_custom_minimum_size(Size2(400 * EDSCALE, 0));
+ preview_text->set_syntax_coloring(true);
+ preview_text->set_readonly(true);
+
///////////////////////////////////////
// SHADER NODES TREE
///////////////////////////////////////
@@ -2413,8 +2487,8 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Sin", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the sine of the parameter."), VisualShaderNodeScalarFunc::FUNC_SIN, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("SinH", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the hyperbolic sine of the parameter."), VisualShaderNodeScalarFunc::FUNC_SINH, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("Sqrt", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the square root of the parameter."), VisualShaderNodeScalarFunc::FUNC_SQRT, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("SmoothStep", "Scalar", "Functions", "VisualShaderNodeScalarSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge0' and 1.0 if x is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Step", "Scalar", "Functions", "VisualShaderNodeScalarOp", TTR("Step function( scalar(edge), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge' and otherwise 1.0."), VisualShaderNodeScalarOp::OP_STEP, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("SmoothStep", "Scalar", "Functions", "VisualShaderNodeScalarSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if x is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Step", "Scalar", "Functions", "VisualShaderNodeScalarOp", TTR("Step function( scalar(edge), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), VisualShaderNodeScalarOp::OP_STEP, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("Tan", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the tangent of the parameter."), VisualShaderNodeScalarFunc::FUNC_TAN, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("TanH", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the hyperbolic tangent of the parameter."), VisualShaderNodeScalarFunc::FUNC_TANH, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("Trunc", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Finds the truncated value of the parameter."), VisualShaderNodeScalarFunc::FUNC_TRUNC, VisualShaderNode::PORT_TYPE_SCALAR));
@@ -2507,10 +2581,10 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Sin", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the sine of the parameter."), VisualShaderNodeVectorFunc::FUNC_SIN, VisualShaderNode::PORT_TYPE_VECTOR));
add_options.push_back(AddOption("SinH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic sine of the parameter."), VisualShaderNodeVectorFunc::FUNC_SINH, VisualShaderNode::PORT_TYPE_VECTOR));
add_options.push_back(AddOption("Sqrt", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the square root of the parameter."), VisualShaderNodeVectorFunc::FUNC_SQRT, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("SmoothStep", "Vector", "Functions", "VisualShaderNodeVectorSmoothStep", TTR("SmoothStep function( vector(edge0), vector(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("SmoothStepS", "Vector", "Functions", "VisualShaderNodeVectorScalarSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Step", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Step function( vector(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge' and otherwise 1.0."), VisualShaderNodeVectorOp::OP_STEP, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("StepS", "Vector", "Functions", "VisualShaderNodeVectorScalarStep", TTR("Step function( scalar(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge' and otherwise 1.0."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("SmoothStep", "Vector", "Functions", "VisualShaderNodeVectorSmoothStep", TTR("SmoothStep function( vector(edge0), vector(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("SmoothStepS", "Vector", "Functions", "VisualShaderNodeVectorScalarSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Step", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Step function( vector(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), VisualShaderNodeVectorOp::OP_STEP, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("StepS", "Vector", "Functions", "VisualShaderNodeVectorScalarStep", TTR("Step function( scalar(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
add_options.push_back(AddOption("Tan", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the tangent of the parameter."), VisualShaderNodeVectorFunc::FUNC_TAN, VisualShaderNode::PORT_TYPE_VECTOR));
add_options.push_back(AddOption("TanH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic tangent of the parameter."), VisualShaderNodeVectorFunc::FUNC_TANH, VisualShaderNode::PORT_TYPE_VECTOR));
add_options.push_back(AddOption("Trunc", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the truncated value of the parameter."), VisualShaderNodeVectorFunc::FUNC_TRUNC, VisualShaderNode::PORT_TYPE_VECTOR));
@@ -2528,6 +2602,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Expression", "Special", "", "VisualShaderNodeExpression", TTR("Custom Godot Shader Language expression, with custom amount of input and output ports. This is a direct injection of code into the vertex/fragment/light function, do not use it to write the function declarations inside.")));
add_options.push_back(AddOption("Fresnel", "Special", "", "VisualShaderNodeFresnel", TTR("Returns falloff based on the dot product of surface normal and view direction of camera (pass associated inputs to it)."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("GlobalExpression", "Special", "", "VisualShaderNodeGlobalExpression", TTR("Custom Godot Shader Language expression, which placed on top of the resulted shader. You can place various function definitions inside and call it later in the Expressions. You can also declare varyings, uniforms and constants.")));
add_options.push_back(AddOption("ScalarDerivativeFunc", "Special", "Common", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) Scalar derivative function."), -1, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true));
add_options.push_back(AddOption("VectorDerivativeFunc", "Special", "Common", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) Vector derivative function."), -1, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true));
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index b5b00f2b5e..1556c7cd43 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -60,14 +60,18 @@ class VisualShaderEditor : public VBoxContainer {
int editing_port;
Ref<VisualShader> visual_shader;
+ HSplitContainer *main_box;
GraphEdit *graph;
ToolButton *add_node;
+ ToolButton *preview_shader;
OptionButton *edit_type;
PanelContainer *error_panel;
Label *error_label;
+ TextEdit *preview_text;
+
UndoRedo *undo_redo;
Point2 saved_node_pos;
bool saved_node_pos_dirty;
@@ -75,6 +79,8 @@ class VisualShaderEditor : public VBoxContainer {
ConfirmationDialog *members_dialog;
MenuButton *tools;
+ bool preview_showed;
+
enum ToolsMenuOptions {
EXPAND_ALL,
COLLAPSE_ALL
@@ -146,6 +152,9 @@ class VisualShaderEditor : public VBoxContainer {
void _update_custom_nodes();
void _update_options_menu();
+ void _show_preview_text();
+ void _update_preview();
+
static VisualShaderEditor *singleton;
void _node_dragged(const Vector2 &p_from, const Vector2 &p_to, int p_node);
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 0f3c4c924a..a418773131 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -997,7 +997,6 @@ public:
void load_projects();
void set_search_term(String p_search_term);
- void set_filter_option(ProjectListFilter::FilterOption p_option);
void set_order_option(ProjectListFilter::FilterOption p_option);
void sort_projects();
int get_project_count() const;
@@ -1030,7 +1029,6 @@ private:
static void load_project_data(const String &p_property_key, Item &p_item, bool p_favorite);
String _search_term;
- ProjectListFilter::FilterOption _filter_option;
ProjectListFilter::FilterOption _order_option;
Set<String> _selected_project_keys;
String _last_clicked; // Project key
@@ -1063,7 +1061,6 @@ struct ProjectListComparator {
};
ProjectList::ProjectList() {
- _filter_option = ProjectListFilter::FILTER_NAME;
_order_option = ProjectListFilter::FILTER_MODIFIED;
_scroll_children = memnew(VBoxContainer);
@@ -1303,12 +1300,6 @@ void ProjectList::set_search_term(String p_search_term) {
_search_term = p_search_term;
}
-void ProjectList::set_filter_option(ProjectListFilter::FilterOption p_option) {
- if (_filter_option != p_option) {
- _filter_option = p_option;
- }
-}
-
void ProjectList::set_order_option(ProjectListFilter::FilterOption p_option) {
if (_order_option != p_option) {
_order_option = p_option;
@@ -1328,11 +1319,18 @@ void ProjectList::sort_projects() {
bool visible = true;
if (_search_term != "") {
- if (_filter_option == ProjectListFilter::FILTER_PATH) {
- visible = item.path.findn(_search_term) != -1;
- } else if (_filter_option == ProjectListFilter::FILTER_NAME) {
- visible = item.project_name.findn(_search_term) != -1;
+
+ String search_path;
+ if (_search_term.find("/") != -1) {
+ // Search path will match the whole path
+ search_path = item.path;
+ } else {
+ // Search path will only match the last path component to make searching more strict
+ search_path = item.path.get_file();
}
+
+ // When searching, display projects whose name or path contain the search term
+ visible = item.project_name.findn(_search_term) != -1 || search_path.findn(_search_term) != -1;
}
item.control->set_visible(visible);
@@ -1694,7 +1692,6 @@ void ProjectList::_bind_methods() {
ClassDB::bind_method("_panel_input", &ProjectList::_panel_input);
ClassDB::bind_method("_favorite_pressed", &ProjectList::_favorite_pressed);
ClassDB::bind_method("_show_project", &ProjectList::_show_project);
- //ClassDB::bind_method("_unhandled_input", &ProjectList::_unhandled_input);
ADD_SIGNAL(MethodInfo(SIGNAL_SELECTION_CHANGED));
ADD_SIGNAL(MethodInfo(SIGNAL_PROJECT_ASK_OPEN));
@@ -1754,8 +1751,19 @@ void ProjectManager::_unhandled_input(const Ref<InputEvent> &p_ev) {
if (k.is_valid()) {
- if (!k->is_pressed())
+ if (!k->is_pressed()) {
return;
+ }
+
+ // Pressing Command + Q quits the Project Manager
+ // This is handled by the platform implementation on macOS,
+ // so only define the shortcut on other platforms
+#ifndef OSX_ENABLED
+ if (k->get_scancode_with_modifiers() == (KEY_MASK_CMD | KEY_Q)) {
+ _dim_window();
+ get_tree()->quit();
+ }
+#endif
if (tabs->get_current_tab() != 0)
return;
@@ -1834,7 +1842,6 @@ void ProjectManager::_unhandled_input(const Ref<InputEvent> &p_ev) {
void ProjectManager::_load_recent_projects() {
- _project_list->set_filter_option(project_filter->get_filter_option());
_project_list->set_order_option(project_order_filter->get_filter_option());
_project_list->set_search_term(project_filter->get_search_term());
_project_list->load_projects();
@@ -2198,7 +2205,6 @@ void ProjectManager::_on_order_option_changed() {
}
void ProjectManager::_on_filter_option_changed() {
- _project_list->set_filter_option(project_filter->get_filter_option());
_project_list->set_search_term(project_filter->get_search_term());
_project_list->sort_projects();
}
@@ -2270,6 +2276,9 @@ ProjectManager::ProjectManager() {
} break;
}
+ // Define a minimum window size to prevent UI elements from overlapping or being cut off
+ OS::get_singleton()->set_min_window_size(Size2(750, 420) * EDSCALE);
+
#ifndef OSX_ENABLED
// The macOS platform implementation uses its own hiDPI window resizing code
// TODO: Resize windows on hiDPI displays on Windows and Linux and remove the line below
@@ -2295,26 +2304,11 @@ ProjectManager::ProjectManager() {
VBoxContainer *vb = memnew(VBoxContainer);
panel->add_child(vb);
vb->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 8 * EDSCALE);
- vb->add_constant_override("separation", 8 * EDSCALE);
String cp;
cp += 0xA9;
OS::get_singleton()->set_window_title(VERSION_NAME + String(" - ") + TTR("Project Manager") + " - " + cp + " 2007-2019 Juan Linietsky, Ariel Manzur & Godot Contributors");
- HBoxContainer *top_hb = memnew(HBoxContainer);
- vb->add_child(top_hb);
- Label *l = memnew(Label);
- l->set_text(VERSION_NAME + String(" - ") + TTR("Project Manager"));
- top_hb->add_child(l);
- top_hb->add_spacer();
- l = memnew(Label);
- String hash = String(VERSION_HASH);
- if (hash.length() != 0)
- hash = "." + hash.left(9);
- l->set_text("v" VERSION_FULL_BUILD "" + hash);
- l->set_align(Label::ALIGN_CENTER);
- top_hb->add_child(l);
-
Control *center_box = memnew(Control);
center_box->set_v_size_flags(SIZE_EXPAND_FILL);
vb->add_child(center_box);
@@ -2322,11 +2316,12 @@ ProjectManager::ProjectManager() {
tabs = memnew(TabContainer);
center_box->add_child(tabs);
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;
- projects_hb->set_name(TTR("Project List"));
+ projects_hb->set_name(TTR("Projects"));
tabs->add_child(tree_hb);
@@ -2343,6 +2338,7 @@ ProjectManager::ProjectManager() {
sort_filter_titles.push_back("Path");
sort_filter_titles.push_back("Last Modified");
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);
@@ -2353,21 +2349,12 @@ ProjectManager::ProjectManager() {
project_order_filter->set_filter_option((ProjectListFilter::FilterOption)projects_sorting_order);
sort_filters->add_spacer(true);
- Label *search_label = memnew(Label);
- search_label->set_text(TTR("Search:"));
- sort_filters->add_child(search_label);
-
- HBoxContainer *search_filters = memnew(HBoxContainer);
- Vector<String> vec2;
- vec2.push_back("Name");
- vec2.push_back("Path");
+
project_filter = memnew(ProjectListFilter);
- project_filter->_setup_filters(vec2);
project_filter->add_search_box();
- search_filters->add_child(project_filter);
project_filter->connect("filter_changed", this, "_on_filter_option_changed");
project_filter->set_custom_minimum_size(Size2(280, 10) * EDSCALE);
- sort_filters->add_child(search_filters);
+ sort_filters->add_child(project_filter);
search_tree_vb->add_child(sort_filters);
@@ -2457,6 +2444,17 @@ ProjectManager::ProjectManager() {
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);
+ // 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);
+
language_btn = memnew(OptionButton);
language_btn->set_flat(true);
language_btn->set_focus_mode(Control::FOCUS_NONE);
@@ -2489,27 +2487,6 @@ ProjectManager::ProjectManager() {
center_box->add_child(settings_hb);
settings_hb->set_anchors_and_margins_preset(Control::PRESET_TOP_RIGHT);
- CenterContainer *cc = memnew(CenterContainer);
- Button *cancel = memnew(Button);
- cancel->set_text(TTR("Exit"));
- cancel->set_custom_minimum_size(Size2(100, 1) * EDSCALE);
-
-#ifndef OSX_ENABLED
- // Pressing Command + Q quits the Project Manager
- // This is handled by the platform implementation on macOS,
- // so only define the shortcut on other platforms
- InputEventKey *quit_key = memnew(InputEventKey);
- quit_key->set_command(true);
- quit_key->set_scancode(KEY_Q);
- ShortCut *quit_shortcut = memnew(ShortCut);
- quit_shortcut->set_shortcut(quit_key);
- cancel->set_shortcut(quit_shortcut);
-#endif
-
- cc->add_child(cancel);
- cancel->connect("pressed", this, "_exit_dialog");
- vb->add_child(cc);
-
//////////////////////////////////////////////////////////////
language_restart_ask = memnew(ConfirmationDialog);
@@ -2630,11 +2607,20 @@ 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", this, "_filter_option_selected");
+ add_child(filter_option);
+}
+
void ProjectListFilter::add_search_box() {
search_box = memnew(LineEdit);
+ search_box->set_placeholder(TTR("Search"));
search_box->connect("text_changed", this, "_search_text_changed");
search_box->set_h_size_flags(SIZE_EXPAND_FILL);
add_child(search_box);
+
has_search_box = true;
}
@@ -2645,13 +2631,6 @@ void ProjectListFilter::set_filter_size(int h_size) {
ProjectListFilter::ProjectListFilter() {
_current_filter = FILTER_NAME;
-
- filter_option = memnew(OptionButton);
- set_filter_size(80);
- filter_option->set_clip_text(true);
- filter_option->connect("item_selected", this, "_filter_option_selected");
- add_child(filter_option);
-
has_search_box = false;
}
diff --git a/editor/project_manager.h b/editor/project_manager.h
index 4ccb99d6bd..2a5fd02892 100644
--- a/editor/project_manager.h
+++ b/editor/project_manager.h
@@ -152,6 +152,7 @@ protected:
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();
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 032b3a19a6..f1eb7adbd2 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -986,9 +986,10 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
} else {
new_node = Object::cast_to<Node>(ClassDB::instance(selected_favorite_root));
}
+
if (!new_node) {
- ERR_EXPLAIN("Creating root from favorite '" + selected_favorite_root + "' failed. Creating 'Node' instead.");
new_node = memnew(Node);
+ ERR_PRINTS("Creating root from favorite '" + selected_favorite_root + "' failed. Creating 'Node' instead.");
}
} else {
switch (p_tool) {
@@ -1537,10 +1538,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
Node *validate = new_parent;
while (validate) {
- if (p_nodes.find(validate) != -1) {
- ERR_EXPLAIN("Selection changed at some point.. can't reparent");
- ERR_FAIL();
- }
+ ERR_FAIL_COND_MSG(p_nodes.find(validate) != -1, "Selection changed at some point.. can't reparent.");
validate = validate->get_parent();
}
//ok all valid
@@ -2253,8 +2251,7 @@ void SceneTreeDock::_normalize_drop(Node *&to_node, int &to_pos, int p_type) {
//drop at above selected node
if (to_node == EditorNode::get_singleton()->get_edited_scene()) {
to_node = NULL;
- ERR_EXPLAIN("Cannot perform drop above the root node!");
- ERR_FAIL();
+ ERR_FAIL_MSG("Cannot perform drop above the root node!");
}
to_pos = to_node->get_index();
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index 2d9accc3d8..43f540e688 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -270,15 +270,30 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
item->add_button(0, get_icon("NodeWarning", "EditorIcons"), BUTTON_WARNING, false, TTR("Node configuration warning:") + "\n" + p_node->get_configuration_warning());
}
- bool has_connections = p_node->has_persistent_signal_connections();
- bool has_groups = p_node->has_persistent_groups();
-
- if (has_connections && has_groups) {
- item->add_button(0, get_icon("SignalsAndGroups", "EditorIcons"), BUTTON_SIGNALS, false, TTR("Node has connection(s) and group(s).\nClick to show signals dock."));
- } else if (has_connections) {
- item->add_button(0, get_icon("Signals", "EditorIcons"), BUTTON_SIGNALS, false, TTR("Node has connections.\nClick to show signals dock."));
- } else if (has_groups) {
- item->add_button(0, get_icon("Groups", "EditorIcons"), BUTTON_GROUPS, false, TTR("Node is in group(s).\nClick to show groups dock."));
+ int num_connections = p_node->get_persistent_signal_connection_count();
+ int num_groups = p_node->get_persistent_group_count();
+
+ if (num_connections >= 1 && num_groups >= 1) {
+ item->add_button(
+ 0,
+ get_icon("SignalsAndGroups", "EditorIcons"),
+ BUTTON_SIGNALS,
+ false,
+ vformat(TTR("Node has %s connection(s) and %s group(s).\nClick to show signals dock."), num_connections, num_groups));
+ } else if (num_connections >= 1) {
+ item->add_button(
+ 0,
+ get_icon("Signals", "EditorIcons"),
+ BUTTON_SIGNALS,
+ false,
+ vformat(TTR("Node has %s connection(s).\nClick to show signals dock."), num_connections));
+ } else if (num_groups >= 1) {
+ item->add_button(
+ 0,
+ get_icon("Groups", "EditorIcons"),
+ BUTTON_GROUPS,
+ false,
+ vformat(TTR("Node is in %s group(s).\nClick to show groups dock."), num_groups));
}
}
@@ -995,6 +1010,17 @@ bool SceneTreeEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_d
return true;
}
+ if (String(d["type"]) == "script_list_element") {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(d["script_list_element"]);
+ if (se) {
+ String sp = se->get_edited_resource()->get_path();
+ if (_is_script_type(EditorFileSystem::get_singleton()->get_file_type(sp))) {
+ tree->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM);
+ return true;
+ }
+ }
+ }
+
return String(d["type"]) == "nodes";
}
void SceneTreeEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
@@ -1032,6 +1058,16 @@ void SceneTreeEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data,
emit_signal("files_dropped", files, np, section);
}
}
+
+ if (String(d["type"]) == "script_list_element") {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(d["script_list_element"]);
+ if (se) {
+ String sp = se->get_edited_resource()->get_path();
+ if (_is_script_type(EditorFileSystem::get_singleton()->get_file_type(sp))) {
+ emit_signal("script_dropped", sp, np);
+ }
+ }
+ }
}
void SceneTreeEditor::_rmb_select(const Vector2 &p_pos) {