summaryrefslogtreecommitdiff
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/code_editor.cpp37
-rw-r--r--editor/code_editor.h3
-rw-r--r--editor/dependency_editor.cpp4
-rw-r--r--editor/doc_tools.cpp12
-rw-r--r--editor/editor_audio_buses.cpp41
-rw-r--r--editor/editor_feature_profile.cpp12
-rw-r--r--editor/editor_inspector.cpp131
-rw-r--r--editor/editor_inspector.h4
-rw-r--r--editor/editor_node.cpp6
-rw-r--r--editor/editor_plugin_settings.cpp10
-rw-r--r--editor/editor_properties.cpp292
-rw-r--r--editor/editor_resource_picker.cpp8
-rw-r--r--editor/editor_run.cpp1
-rw-r--r--editor/editor_spin_slider.cpp10
-rw-r--r--editor/editor_themes.cpp9
-rw-r--r--editor/find_in_files.cpp5
-rw-r--r--editor/icons/TileMapHighlightSelected.svg1
-rw-r--r--editor/import/editor_importer_bake_reset.cpp223
-rw-r--r--editor/import/editor_importer_bake_reset.h54
-rw-r--r--editor/import/resource_importer_scene.cpp7
-rw-r--r--editor/inspector_dock.cpp5
-rw-r--r--editor/localization_editor.cpp9
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp2
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp3
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp206
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h69
-rw-r--r--editor/plugins/editor_preview_plugins.cpp2
-rw-r--r--editor/plugins/node_3d_editor_gizmos.cpp2
-rw-r--r--editor/plugins/node_3d_editor_gizmos.h2
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp204
-rw-r--r--editor/plugins/node_3d_editor_plugin.h32
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp30
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.h12
-rw-r--r--editor/plugins/script_text_editor.cpp29
-rw-r--r--editor/plugins/shader_editor_plugin.cpp6
-rw-r--r--editor/plugins/theme_editor_plugin.cpp4
-rw-r--r--editor/plugins/tiles/atlas_merging_dialog.cpp2
-rw-r--r--editor/plugins/tiles/tile_atlas_view.cpp5
-rw-r--r--editor/plugins/tiles/tile_data_editors.h2
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp691
-rw-r--r--editor/plugins/tiles/tile_map_editor.h35
-rw-r--r--editor/plugins/tiles/tile_proxies_manager_dialog.cpp12
-rw-r--r--editor/plugins/tiles/tile_proxies_manager_dialog.h2
-rw-r--r--editor/plugins/version_control_editor_plugin.cpp26
-rw-r--r--editor/plugins/version_control_editor_plugin.h1
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp88
-rw-r--r--editor/project_export.cpp4
-rw-r--r--editor/project_manager.cpp37
-rw-r--r--editor/script_create_dialog.cpp4
49 files changed, 1628 insertions, 768 deletions
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index 03695419cb..eeb99b3677 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -31,6 +31,7 @@
#include "code_editor.h"
#include "core/input/input.h"
+#include "core/object/message_queue.h"
#include "core/os/keyboard.h"
#include "core/string/string_builder.h"
#include "editor/editor_scale.h"
@@ -950,14 +951,20 @@ void CodeTextEditor::update_editor_settings() {
text_editor->set_line_folding_enabled(EditorSettings::get_singleton()->get("text_editor/appearance/code_folding"));
text_editor->set_draw_fold_gutter(EditorSettings::get_singleton()->get("text_editor/appearance/code_folding"));
text_editor->set_wrap_enabled(EditorSettings::get_singleton()->get("text_editor/appearance/word_wrap"));
- text_editor->set_show_line_length_guidelines(EditorSettings::get_singleton()->get("text_editor/appearance/show_line_length_guidelines"));
- text_editor->set_line_length_guideline_soft_column(EditorSettings::get_singleton()->get("text_editor/appearance/line_length_guideline_soft_column"));
- text_editor->set_line_length_guideline_hard_column(EditorSettings::get_singleton()->get("text_editor/appearance/line_length_guideline_hard_column"));
text_editor->set_scroll_pass_end_of_file(EditorSettings::get_singleton()->get("text_editor/cursor/scroll_past_end_of_file"));
text_editor->cursor_set_block_mode(EditorSettings::get_singleton()->get("text_editor/cursor/block_caret"));
text_editor->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/cursor/caret_blink"));
text_editor->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/cursor/caret_blink_speed"));
- text_editor->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/completion/auto_brace_complete"));
+ text_editor->set_auto_brace_completion_enabled(EditorSettings::get_singleton()->get("text_editor/completion/auto_brace_complete"));
+
+ if (EditorSettings::get_singleton()->get("text_editor/appearance/show_line_length_guidelines")) {
+ TypedArray<int> guideline_cols;
+ guideline_cols.append(EditorSettings::get_singleton()->get("text_editor/appearance/line_length_guideline_hard_column"));
+ if (EditorSettings::get_singleton()->get("text_editor/appearance/line_length_guideline_soft_column") != guideline_cols[0]) {
+ guideline_cols.append(EditorSettings::get_singleton()->get("text_editor/appearance/line_length_guideline_soft_column"));
+ }
+ text_editor->set_line_length_guidelines(guideline_cols);
+ }
}
void CodeTextEditor::set_find_replace_bar(FindReplaceBar *p_bar) {
@@ -1567,6 +1574,17 @@ void CodeTextEditor::_update_font() {
}
void CodeTextEditor::_on_settings_change() {
+ if (settings_changed) {
+ return;
+ }
+
+ settings_changed = true;
+ MessageQueue::get_singleton()->push_callable(callable_mp(this, &CodeTextEditor::_apply_settings_change));
+}
+
+void CodeTextEditor::_apply_settings_change() {
+ settings_changed = false;
+
_update_text_editor_theme();
_update_font();
@@ -1597,16 +1615,9 @@ void CodeTextEditor::_on_settings_change() {
} break;
}
- // Auto brace completion.
- text_editor->set_auto_brace_completion(
- EDITOR_GET("text_editor/completion/auto_brace_complete"));
-
- code_complete_timer->set_wait_time(
- EDITOR_GET("text_editor/completion/code_complete_delay"));
-
- // Call hint settings.
text_editor->set_code_hint_draw_below(EDITOR_GET("text_editor/completion/put_callhint_tooltip_below_current_line"));
+ code_complete_timer->set_wait_time(EDITOR_GET("text_editor/completion/code_complete_delay"));
idle->set_wait_time(EDITOR_GET("text_editor/completion/idle_parse_delay"));
}
@@ -1820,7 +1831,7 @@ CodeTextEditor::CodeTextEditor() {
}
text_editor->set_draw_line_numbers(true);
- text_editor->set_brace_matching(true);
+ text_editor->set_highlight_matching_braces_enabled(true);
text_editor->set_auto_indent_enabled(true);
status_bar = memnew(HBoxContainer);
diff --git a/editor/code_editor.h b/editor/code_editor.h
index 0e5a84b3d5..4cd4880df0 100644
--- a/editor/code_editor.h
+++ b/editor/code_editor.h
@@ -162,7 +162,10 @@ class CodeTextEditor : public VBoxContainer {
int error_line;
int error_column;
+ bool settings_changed = false;
+
void _on_settings_change();
+ void _apply_settings_change();
void _update_text_editor_theme();
void _update_font();
diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp
index 069ae2c7f2..a9d8cb219c 100644
--- a/editor/dependency_editor.cpp
+++ b/editor/dependency_editor.cpp
@@ -463,13 +463,13 @@ void DependencyRemoveDialog::show(const Vector<String> &p_folders, const Vector<
removed_deps.sort();
if (removed_deps.is_empty()) {
owners->hide();
- text->set_text(TTR("Remove selected files from the project? (no undo)\nYou can find the removed files in the system trash to restore them."));
+ text->set_text(TTR("Remove the selected files from the project? (Cannot be undone.)\nDepending on your filesystem configuration, the files will either be moved to the system trash or deleted permanently."));
set_size(Size2());
popup_centered();
} else {
_build_removed_dependency_tree(removed_deps);
owners->show();
- text->set_text(TTR("The files being removed are required by other resources in order for them to work.\nRemove them anyway? (no undo)\nYou can find the removed files in the system trash to restore them."));
+ text->set_text(TTR("The files being removed are required by other resources in order for them to work.\nRemove them anyway? (Cannot be undone.)\nDepending on your filesystem configuration, the files will either be moved to the system trash or deleted permanently."));
popup_centered(Size2(500, 350));
}
EditorFileSystem::get_singleton()->scan_changes();
diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp
index cbd4a1b916..c752d0d4fd 100644
--- a/editor/doc_tools.cpp
+++ b/editor/doc_tools.cpp
@@ -1208,8 +1208,7 @@ Error DocTools::save_classes(const String &p_default_path, const Map<String, Str
if (m.return_enum != String()) {
enum_text = " enum=\"" + m.return_enum + "\"";
}
- _write_string(f, 3, "<return type=\"" + m.return_type + "\"" + enum_text + ">");
- _write_string(f, 3, "</return>");
+ _write_string(f, 3, "<return type=\"" + m.return_type + "\"" + enum_text + " />");
}
for (int j = 0; j < m.arguments.size(); j++) {
@@ -1221,12 +1220,10 @@ Error DocTools::save_classes(const String &p_default_path, const Map<String, Str
}
if (a.default_value != "") {
- _write_string(f, 3, "<argument index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\"" + enum_text + " default=\"" + a.default_value.xml_escape(true) + "\">");
+ _write_string(f, 3, "<argument index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\"" + enum_text + " default=\"" + a.default_value.xml_escape(true) + "\" />");
} else {
- _write_string(f, 3, "<argument index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\"" + enum_text + ">");
+ _write_string(f, 3, "<argument index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\"" + enum_text + " />");
}
-
- _write_string(f, 3, "</argument>");
}
_write_string(f, 3, "<description>");
@@ -1274,8 +1271,7 @@ Error DocTools::save_classes(const String &p_default_path, const Map<String, Str
_write_string(f, 2, "<signal name=\"" + m.name + "\">");
for (int j = 0; j < m.arguments.size(); j++) {
const DocData::ArgumentDoc &a = m.arguments[j];
- _write_string(f, 3, "<argument index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\">");
- _write_string(f, 3, "</argument>");
+ _write_string(f, 3, "<argument index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\" />");
}
_write_string(f, 3, "<description>");
diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp
index 4a19f007d4..5209ee06c6 100644
--- a/editor/editor_audio_buses.cpp
+++ b/editor/editor_audio_buses.cpp
@@ -62,7 +62,8 @@ void EditorAudioBus::_update_visible_channels() {
void EditorAudioBus::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_READY: {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
for (int i = 0; i < CHANNELS_MAX; i++) {
channel[i].vu_l->set_under_texture(get_theme_icon(SNAME("BusVuEmpty"), SNAME("EditorIcons")));
channel[i].vu_l->set_progress_texture(get_theme_icon(SNAME("BusVuFull"), SNAME("EditorIcons")));
@@ -86,6 +87,12 @@ void EditorAudioBus::_notification(int p_what) {
bus_options->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
+ audio_value_preview_label->add_theme_color_override("font_color", get_theme_color(SNAME("font_color"), SNAME("TooltipLabel")));
+ audio_value_preview_label->add_theme_color_override("font_shadow_color", get_theme_color(SNAME("font_shadow_color"), SNAME("TooltipLabel")));
+ audio_value_preview_box->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TooltipPanel")));
+ } break;
+
+ case NOTIFICATION_READY: {
update_bus();
set_process(true);
} break;
@@ -157,26 +164,7 @@ void EditorAudioBus::_notification(int p_what) {
set_process(is_visible_in_tree());
} break;
- case NOTIFICATION_THEME_CHANGED: {
- for (int i = 0; i < CHANNELS_MAX; i++) {
- channel[i].vu_l->set_under_texture(get_theme_icon(SNAME("BusVuEmpty"), SNAME("EditorIcons")));
- channel[i].vu_l->set_progress_texture(get_theme_icon(SNAME("BusVuFull"), SNAME("EditorIcons")));
- channel[i].vu_r->set_under_texture(get_theme_icon(SNAME("BusVuEmpty"), SNAME("EditorIcons")));
- channel[i].vu_r->set_progress_texture(get_theme_icon(SNAME("BusVuFull"), SNAME("EditorIcons")));
- channel[i].prev_active = true;
- }
-
- disabled_vu = get_theme_icon(SNAME("BusVuFrozen"), SNAME("EditorIcons"));
-
- solo->set_icon(get_theme_icon(SNAME("AudioBusSolo"), SNAME("EditorIcons")));
- mute->set_icon(get_theme_icon(SNAME("AudioBusMute"), SNAME("EditorIcons")));
- bypass->set_icon(get_theme_icon(SNAME("AudioBusBypass"), SNAME("EditorIcons")));
-
- bus_options->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
- audio_value_preview_box->add_theme_color_override("font_color", get_theme_color(SNAME("font_color"), SNAME("TooltipLabel")));
- audio_value_preview_box->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TooltipPanel")));
- } break;
case NOTIFICATION_MOUSE_EXIT:
case NOTIFICATION_DRAG_END: {
if (hovering_drop) {
@@ -833,6 +821,11 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
slider->set_clip_contents(false);
audio_value_preview_box = memnew(Panel);
+ slider->add_child(audio_value_preview_box);
+ audio_value_preview_box->set_as_top_level(true);
+ audio_value_preview_box->set_mouse_filter(MOUSE_FILTER_PASS);
+ audio_value_preview_box->hide();
+
HBoxContainer *audioprev_hbc = memnew(HBoxContainer);
audioprev_hbc->set_v_size_flags(SIZE_EXPAND_FILL);
audioprev_hbc->set_h_size_flags(SIZE_EXPAND_FILL);
@@ -842,16 +835,8 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
audio_value_preview_label->set_v_size_flags(SIZE_EXPAND_FILL);
audio_value_preview_label->set_h_size_flags(SIZE_EXPAND_FILL);
audio_value_preview_label->set_mouse_filter(MOUSE_FILTER_PASS);
- audio_value_preview_box->add_theme_color_override("font_color", get_theme_color(SNAME("font_color"), SNAME("TooltipLabel")));
-
audioprev_hbc->add_child(audio_value_preview_label);
- slider->add_child(audio_value_preview_box);
- audio_value_preview_box->set_as_top_level(true);
- audio_value_preview_box->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TooltipPanel")));
- audio_value_preview_box->set_mouse_filter(MOUSE_FILTER_PASS);
- audio_value_preview_box->hide();
-
preview_timer = memnew(Timer);
preview_timer->set_wait_time(0.8f);
preview_timer->set_one_shot(true);
diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp
index 22f44a54bb..72a0c353e8 100644
--- a/editor/editor_feature_profile.cpp
+++ b/editor/editor_feature_profile.cpp
@@ -740,7 +740,7 @@ void EditorFeatureProfileManager::_update_selected_profile() {
TreeItem *features = class_list->create_item(root);
TreeItem *last_feature;
- features->set_text(0, TTR("Main Features") + ":");
+ features->set_text(0, TTR("Main Features:"));
for (int i = 0; i < EditorFeatureProfile::FEATURE_MAX; i++) {
TreeItem *feature;
if (i == EditorFeatureProfile::FEATURE_IMPORT_DOCK) {
@@ -764,7 +764,7 @@ void EditorFeatureProfileManager::_update_selected_profile() {
}
TreeItem *classes = class_list->create_item(root);
- classes->set_text(0, TTR("Nodes and Classes") + ":");
+ classes->set_text(0, TTR("Nodes and Classes:"));
_fill_classes_from(classes, "Node", class_selected);
_fill_classes_from(classes, "Resource", class_selected);
@@ -917,7 +917,7 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() {
class_list_vbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
class_list = memnew(Tree);
- class_list_vbc->add_margin_child(TTR("Configure Selected Profile") + ":", class_list, true);
+ class_list_vbc->add_margin_child(TTR("Configure Selected Profile:"), class_list, true);
class_list->set_hide_root(true);
class_list->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true);
class_list->connect("cell_selected", callable_mp(this, &EditorFeatureProfileManager::_class_list_item_selected));
@@ -931,11 +931,11 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() {
property_list_vbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
description_bit = memnew(EditorHelpBit);
- property_list_vbc->add_margin_child(TTR("Description") + ":", description_bit, false);
+ property_list_vbc->add_margin_child(TTR("Description:"), description_bit, false);
description_bit->set_custom_minimum_size(Size2(0, 80) * EDSCALE);
property_list = memnew(Tree);
- property_list_vbc->add_margin_child(TTR("Extra Options") + ":", property_list, true);
+ property_list_vbc->add_margin_child(TTR("Extra Options:"), property_list, true);
property_list->set_hide_root(true);
property_list->set_hide_folding(true);
property_list->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true);
@@ -957,7 +957,7 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() {
VBoxContainer *new_profile_vb = memnew(VBoxContainer);
new_profile_dialog->add_child(new_profile_vb);
Label *new_profile_label = memnew(Label);
- new_profile_label->set_text(TTR("New profile name") + ":");
+ new_profile_label->set_text(TTR("New profile name:"));
new_profile_vb->add_child(new_profile_label);
new_profile_name = memnew(LineEdit);
new_profile_vb->add_child(new_profile_name);
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 3db03c0276..d7b7e8e52d 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -417,7 +417,7 @@ bool EditorPropertyRevert::may_node_be_in_instance(Node *p_node) {
return might_be; // or might not be
}
-bool EditorPropertyRevert::get_instantiated_node_original_property(Node *p_node, const StringName &p_prop, Variant &value) {
+bool EditorPropertyRevert::get_instantiated_node_original_property(Node *p_node, const StringName &p_prop, Variant &value, bool p_check_class_default) {
Node *node = p_node;
Node *orig = node;
@@ -455,7 +455,7 @@ bool EditorPropertyRevert::get_instantiated_node_original_property(Node *p_node,
node = node->get_owner();
}
- if (!found && p_node) {
+ if (p_check_class_default && !found && p_node) {
//if not found, try default class value
Variant attempt = ClassDB::class_get_default_property_value(p_node->get_class_name(), p_prop);
if (attempt.get_type() != Variant::NIL) {
@@ -493,6 +493,7 @@ bool EditorPropertyRevert::is_node_property_different(Node *p_node, const Varian
if (ss.is_valid()) {
found_state = true;
+ break;
}
if (node == edited_scene) {
//just in case
@@ -506,59 +507,71 @@ bool EditorPropertyRevert::is_node_property_different(Node *p_node, const Varian
}
}
- if (p_current.get_type() == Variant::FLOAT && p_orig.get_type() == Variant::FLOAT) {
- float a = p_current;
- float b = p_orig;
+ return is_property_value_different(p_current, p_orig);
+}
- return !Math::is_equal_approx(a, b); //this must be done because, as some scenes save as text, there might be a tiny difference in floats due to numerical error
+bool EditorPropertyRevert::is_property_value_different(const Variant &p_a, const Variant &p_b) {
+ if (p_a.get_type() == Variant::FLOAT && p_b.get_type() == Variant::FLOAT) {
+ //this must be done because, as some scenes save as text, there might be a tiny difference in floats due to numerical error
+ return !Math::is_equal_approx((float)p_a, (float)p_b);
+ } else {
+ return p_a != p_b;
}
-
- return bool(Variant::evaluate(Variant::OP_NOT_EQUAL, p_current, p_orig));
}
-bool EditorPropertyRevert::can_property_revert(Object *p_object, const StringName &p_property) {
- bool has_revert = false;
+Variant EditorPropertyRevert::get_property_revert_value(Object *p_object, const StringName &p_property) {
+ // If the object implements property_can_revert, rely on that completely
+ // (i.e. don't then try to revert to default value - the property_get_revert implementation
+ // can do that if so desired)
+ if (p_object->has_method("property_can_revert") && p_object->call("property_can_revert", p_property)) {
+ return p_object->call("property_get_revert", p_property);
+ }
+ Ref<Script> scr = p_object->get_script();
Node *node = Object::cast_to<Node>(p_object);
-
if (node && EditorPropertyRevert::may_node_be_in_instance(node)) {
- //check for difference including instantiation
- Variant vorig;
- if (EditorPropertyRevert::get_instantiated_node_original_property(node, p_property, vorig)) {
- Variant v = p_object->get(p_property);
-
- if (EditorPropertyRevert::is_node_property_different(node, v, vorig)) {
- has_revert = true;
+ //if this node is an instance or inherits, but it has a script attached which is unrelated
+ //to the one set for the parent and also has a default value for the property, consider that
+ //has precedence over the value from the parent, because that is an explicit source of defaults
+ //closer in the tree to the current node
+ bool ignore_parent = false;
+ if (scr.is_valid()) {
+ Variant sorig;
+ if (EditorPropertyRevert::get_instantiated_node_original_property(node, "script", sorig) && !scr->inherits_script(sorig)) {
+ Variant dummy;
+ if (scr->get_property_default_value(p_property, dummy)) {
+ ignore_parent = true;
+ }
}
}
- } else {
- //check for difference against default class value instead
- Variant default_value = ClassDB::class_get_default_property_value(p_object->get_class_name(), p_property);
- if (default_value != Variant() && default_value != p_object->get(p_property)) {
- has_revert = true;
+
+ if (!ignore_parent) {
+ //check for difference including instantiation
+ Variant vorig;
+ if (EditorPropertyRevert::get_instantiated_node_original_property(node, p_property, vorig, false)) {
+ return vorig;
+ }
}
}
- // If the object implements property_can_revert, rely on that completely
- // (i.e. don't then try to revert to default value - the property_get_revert implementation
- // can do that if so desired)
- if (p_object->has_method("property_can_revert")) {
- has_revert = p_object->call("property_can_revert", p_property).operator bool();
- } else {
- if (!has_revert && !p_object->get_script().is_null()) {
- Ref<Script> scr = p_object->get_script();
- if (scr.is_valid()) {
- Variant orig_value;
- if (scr->get_property_default_value(p_property, orig_value)) {
- if (orig_value != p_object->get(p_property)) {
- has_revert = true;
- }
- }
- }
+ if (scr.is_valid()) {
+ Variant orig_value;
+ if (scr->get_property_default_value(p_property, orig_value)) {
+ return orig_value;
}
}
- return has_revert;
+ //report default class value instead
+ return ClassDB::class_get_default_property_value(p_object->get_class_name(), p_property);
+}
+
+bool EditorPropertyRevert::can_property_revert(Object *p_object, const StringName &p_property) {
+ Variant revert_value = EditorPropertyRevert::get_property_revert_value(p_object, p_property);
+ if (revert_value.get_type() == Variant::NIL) {
+ return false;
+ }
+ Variant current_value = p_object->get(p_property);
+ return EditorPropertyRevert::is_property_value_different(current_value, revert_value);
}
void EditorProperty::update_reload_status() {
@@ -761,41 +774,11 @@ void EditorProperty::_gui_input(const Ref<InputEvent> &p_event) {
}
if (revert_rect.has_point(mpos)) {
- Variant vorig;
-
- Node *node = Object::cast_to<Node>(object);
- if (node && EditorPropertyRevert::may_node_be_in_instance(node) && EditorPropertyRevert::get_instantiated_node_original_property(node, property, vorig)) {
- emit_changed(property, vorig.duplicate(true));
- update_property();
- return;
- }
-
- if (object->call("property_can_revert", property).operator bool()) {
- Variant rev = object->call("property_get_revert", property);
- emit_changed(property, rev);
- update_property();
- return;
- }
-
- if (!object->get_script().is_null()) {
- Ref<Script> scr = object->get_script();
- if (scr.is_valid()) {
- Variant orig_value;
- if (scr->get_property_default_value(property, orig_value)) {
- emit_changed(property, orig_value);
- update_property();
- return;
- }
- }
- }
-
- Variant default_value = ClassDB::class_get_default_property_value(object->get_class_name(), property);
- if (default_value != Variant()) {
- emit_changed(property, default_value);
- update_property();
- return;
- }
+ Variant revert_value = EditorPropertyRevert::get_property_revert_value(object, property);
+ emit_changed(property, revert_value);
+ update_property();
}
+
if (check_rect.has_point(mpos)) {
checked = !checked;
update();
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index ee70bd4397..3c9ba9f39d 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -40,8 +40,10 @@ class UndoRedo;
class EditorPropertyRevert {
public:
static bool may_node_be_in_instance(Node *p_node);
- static bool get_instantiated_node_original_property(Node *p_node, const StringName &p_prop, Variant &value);
+ static bool get_instantiated_node_original_property(Node *p_node, const StringName &p_prop, Variant &value, bool p_check_class_default = true);
static bool is_node_property_different(Node *p_node, const Variant &p_current, const Variant &p_orig);
+ static bool is_property_value_different(const Variant &p_a, const Variant &p_b);
+ static Variant get_property_revert_value(Object *p_object, const StringName &p_property);
static bool can_property_revert(Object *p_object, const StringName &p_property);
};
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 46d76a946f..2dfad8f05a 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -1168,7 +1168,8 @@ void EditorNode::save_resource_as(const Ref<Resource> &p_resource, const String
file->set_current_file(p_resource->get_path().get_file());
} else {
if (extensions.size()) {
- file->set_current_file("new_" + p_resource->get_class().to_lower() + "." + preferred.front()->get().to_lower());
+ String resource_name_snake_case = p_resource->get_class().camelcase_to_underscore();
+ file->set_current_file("new_" + resource_name_snake_case + "." + preferred.front()->get().to_lower());
} else {
file->set_current_file(String());
}
@@ -1184,7 +1185,8 @@ void EditorNode::save_resource_as(const Ref<Resource> &p_resource, const String
} else if (preferred.size()) {
String existing;
if (extensions.size()) {
- existing = "new_" + p_resource->get_class().to_lower() + "." + preferred.front()->get().to_lower();
+ String resource_name_snake_case = p_resource->get_class().camelcase_to_underscore();
+ existing = "new_" + resource_name_snake_case + "." + preferred.front()->get().to_lower();
}
file->set_current_path(existing);
}
diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp
index a8b08dc9ed..aa313f0c50 100644
--- a/editor/editor_plugin_settings.cpp
+++ b/editor/editor_plugin_settings.cpp
@@ -208,11 +208,11 @@ EditorPluginSettings::EditorPluginSettings() {
plugin_list->set_v_size_flags(SIZE_EXPAND_FILL);
plugin_list->set_columns(5);
plugin_list->set_column_titles_visible(true);
- plugin_list->set_column_title(0, TTR("Name:"));
- plugin_list->set_column_title(1, TTR("Version:"));
- plugin_list->set_column_title(2, TTR("Author:"));
- plugin_list->set_column_title(3, TTR("Status:"));
- plugin_list->set_column_title(4, TTR("Edit:"));
+ plugin_list->set_column_title(0, TTR("Name"));
+ plugin_list->set_column_title(1, TTR("Version"));
+ plugin_list->set_column_title(2, TTR("Author"));
+ plugin_list->set_column_title(3, TTR("Status"));
+ plugin_list->set_column_title(4, TTR("Edit"));
plugin_list->set_column_expand(0, true);
plugin_list->set_column_clip_content(0, true);
plugin_list->set_column_expand(1, false);
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index df763d5bf0..fa03d281f2 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -691,17 +691,39 @@ EditorPropertyFlags::EditorPropertyFlags() {
class EditorPropertyLayersGrid : public Control {
GDCLASS(EditorPropertyLayersGrid, Control);
-public:
- uint32_t value;
+private:
Vector<Rect2> flag_rects;
+ Rect2 expand_rect;
+ bool expand_hovered = false;
+ bool expanded = false;
+ int expansion_rows = 0;
+ int hovered_index = -1;
+
+ Size2 get_grid_size() const {
+ Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label"));
+ int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label"));
+ return Vector2(0, font->get_height(font_size) * 3);
+ }
+
+public:
+ uint32_t value = 0;
+ int layer_group_size = 0;
+ int layer_count = 0;
Vector<String> names;
Vector<String> tooltips;
- int hovered_index;
virtual Size2 get_minimum_size() const override {
- Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label"));
- int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label"));
- return Vector2(0, font->get_height(font_size) * 2);
+ Size2 min_size = get_grid_size();
+
+ // Add extra rows when expanded.
+ if (expanded) {
+ const int bsize = (min_size.height * 80 / 100) / 2;
+ for (int i = 0; i < expansion_rows; ++i) {
+ min_size.y += 2 * (bsize + 1) + 3;
+ }
+ }
+
+ return min_size;
}
virtual String get_tooltip(const Point2 &p_pos) const override {
@@ -712,80 +734,192 @@ public:
}
return String();
}
+
void _gui_input(const Ref<InputEvent> &p_ev) {
const Ref<InputEventMouseMotion> mm = p_ev;
-
if (mm.is_valid()) {
- for (int i = 0; i < flag_rects.size(); i++) {
- if (flag_rects[i].has_point(mm->get_position())) {
- // Used to highlight the hovered flag in the layers grid.
- hovered_index = i;
- update();
- break;
+ bool expand_was_hovered = expand_hovered;
+ expand_hovered = expand_rect.has_point(mm->get_position());
+ if (expand_hovered != expand_was_hovered) {
+ update();
+ }
+
+ if (!expand_hovered) {
+ for (int i = 0; i < flag_rects.size(); i++) {
+ if (flag_rects[i].has_point(mm->get_position())) {
+ // Used to highlight the hovered flag in the layers grid.
+ hovered_index = i;
+ update();
+ return;
+ }
}
}
+
+ // Remove highlight when no square is hovered.
+ if (hovered_index != -1) {
+ hovered_index = -1;
+ update();
+ }
+
+ return;
}
const Ref<InputEventMouseButton> mb = p_ev;
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_pressed()) {
+ if (hovered_index >= 0) {
+ // Toggle the flag.
+ // We base our choice on the hovered flag, so that it always matches the hovered flag.
+ if (value & (1 << hovered_index)) {
+ value &= ~(1 << hovered_index);
+ } else {
+ value |= (1 << hovered_index);
+ }
- if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_pressed() && hovered_index >= 0) {
- // Toggle the flag.
- // We base our choice on the hovered flag, so that it always matches the hovered flag.
- if (value & (1 << hovered_index)) {
- value &= ~(1 << hovered_index);
- } else {
- value |= (1 << hovered_index);
+ emit_signal(SNAME("flag_changed"), value);
+ update();
+ } else if (expand_hovered) {
+ expanded = !expanded;
+ minimum_size_changed();
+ update();
}
-
- emit_signal(SNAME("flag_changed"), value);
- update();
}
}
void _notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
- Rect2 rect;
- rect.size = get_size();
+ Size2 grid_size = get_grid_size();
+ grid_size.x = get_size().x;
+
flag_rects.clear();
- const int bsize = (rect.size.height * 80 / 100) / 2;
+ int prev_expansion_rows = expansion_rows;
+ expansion_rows = 0;
+
+ const int bsize = (grid_size.height * 80 / 100) / 2;
const int h = bsize * 2 + 1;
- const int vofs = (rect.size.height - h) / 2;
Color color = get_theme_color(SNAME("highlight_color"), SNAME("Editor"));
- for (int i = 0; i < 2; i++) {
- Point2 ofs(4, vofs);
- if (i == 1) {
+
+ Color text_color = get_theme_color(SNAME("font_color"), SNAME("Editor"));
+ text_color.a *= 0.5;
+
+ Color text_color_on = get_theme_color(SNAME("font_hover_color"), SNAME("Editor"));
+ text_color_on.a *= 0.7;
+
+ const int vofs = (grid_size.height - h) / 2;
+
+ int layer_index = 0;
+ int block_index = 0;
+
+ Point2 arrow_pos;
+
+ Point2 block_ofs(4, vofs);
+
+ while (true) {
+ Point2 ofs = block_ofs;
+
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < layer_group_size; j++) {
+ const bool on = value & (1 << layer_index);
+ Rect2 rect2 = Rect2(ofs, Size2(bsize, bsize));
+
+ color.a = on ? 0.6 : 0.2;
+ if (layer_index == hovered_index) {
+ // Add visual feedback when hovering a flag.
+ color.a += 0.15;
+ }
+
+ draw_rect(rect2, color);
+ flag_rects.push_back(rect2);
+
+ Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label"));
+ Vector2 offset;
+ offset.y = rect2.size.y * 0.75;
+
+ draw_string(font, rect2.position + offset, itos(layer_index), HALIGN_CENTER, rect2.size.x, -1, on ? text_color_on : text_color);
+
+ ofs.x += bsize + 1;
+
+ ++layer_index;
+ }
+
+ ofs.x = block_ofs.x;
ofs.y += bsize + 1;
}
- ofs += rect.position;
- for (int j = 0; j < 10; j++) {
- Point2 o = ofs + Point2(j * (bsize + 1), 0);
- if (j >= 5) {
- o.x += 1;
+ if (layer_index >= layer_count) {
+ if (!flag_rects.is_empty() && (expansion_rows == 0)) {
+ const Rect2 &last_rect = flag_rects[flag_rects.size() - 1];
+ arrow_pos = last_rect.position + last_rect.size;
}
+ break;
+ }
- const int idx = i * 10 + j;
- const bool on = value & (1 << idx);
- Rect2 rect2 = Rect2(o, Size2(bsize, bsize));
+ int block_size_x = layer_group_size * (bsize + 1);
+ block_ofs.x += block_size_x + 3;
- color.a = on ? 0.6 : 0.2;
- if (idx == hovered_index) {
- // Add visual feedback when hovering a flag.
- color.a += 0.15;
+ if (block_ofs.x + block_size_x + 12 > grid_size.width) {
+ // Keep last valid cell position for the expansion icon.
+ if (!flag_rects.is_empty() && (expansion_rows == 0)) {
+ const Rect2 &last_rect = flag_rects[flag_rects.size() - 1];
+ arrow_pos = last_rect.position + last_rect.size;
+ }
+ ++expansion_rows;
+
+ if (expanded) {
+ // Expand grid to next line.
+ block_ofs.x = 4;
+ block_ofs.y += 2 * (bsize + 1) + 3;
+ } else {
+ // Skip remaining blocks.
+ break;
}
-
- draw_rect(rect2, color);
- flag_rects.push_back(rect2);
}
+
+ ++block_index;
}
+
+ if ((expansion_rows != prev_expansion_rows) && expanded) {
+ minimum_size_changed();
+ }
+
+ if ((expansion_rows == 0) && (layer_index == layer_count)) {
+ // Whole grid was drawn, no need for expansion icon.
+ break;
+ }
+
+ Ref<Texture2D> arrow = get_theme_icon(SNAME("arrow"), SNAME("Tree"));
+ ERR_FAIL_COND(arrow.is_null());
+
+ Color arrow_color = get_theme_color(SNAME("highlight_color"), SNAME("Editor"));
+ arrow_color.a = expand_hovered ? 1.0 : 0.6;
+
+ arrow_pos.x += 2.0;
+ arrow_pos.y -= arrow->get_height();
+
+ Rect2 arrow_draw_rect(arrow_pos, arrow->get_size());
+ expand_rect = arrow_draw_rect;
+ if (expanded) {
+ arrow_draw_rect.size.y *= -1.0; // Flip arrow vertically when expanded.
+ }
+
+ RID ci = get_canvas_item();
+ arrow->draw_rect(ci, arrow_draw_rect, false, arrow_color);
+
} break;
+
case NOTIFICATION_MOUSE_EXIT: {
- hovered_index = -1;
- update();
+ if (expand_hovered) {
+ expand_hovered = false;
+ update();
+ }
+ if (hovered_index != -1) {
+ hovered_index = -1;
+ update();
+ }
} break;
+
default:
break;
}
@@ -800,12 +934,8 @@ public:
ClassDB::bind_method(D_METHOD("_gui_input"), &EditorPropertyLayersGrid::_gui_input);
ADD_SIGNAL(MethodInfo("flag_changed", PropertyInfo(Variant::INT, "flag")));
}
-
- EditorPropertyLayersGrid() {
- value = 0;
- hovered_index = -1; // Nothing is hovered.
- }
};
+
void EditorPropertyLayers::_grid_changed(uint32_t p_grid) {
emit_changed(get_edited_property(), p_grid);
}
@@ -818,30 +948,49 @@ void EditorPropertyLayers::update_property() {
void EditorPropertyLayers::setup(LayerType p_layer_type) {
String basename;
+ int layer_group_size = 0;
+ int layer_count = 0;
switch (p_layer_type) {
- case LAYER_RENDER_2D:
+ case LAYER_RENDER_2D: {
basename = "layer_names/2d_render";
- break;
- case LAYER_PHYSICS_2D:
+ layer_group_size = 5;
+ layer_count = 20;
+ } break;
+
+ case LAYER_PHYSICS_2D: {
basename = "layer_names/2d_physics";
- break;
- case LAYER_NAVIGATION_2D:
+ layer_group_size = 4;
+ layer_count = 32;
+ } break;
+
+ case LAYER_NAVIGATION_2D: {
basename = "layer_names/2d_navigation";
- break;
- case LAYER_RENDER_3D:
+ layer_group_size = 4;
+ layer_count = 32;
+ } break;
+
+ case LAYER_RENDER_3D: {
basename = "layer_names/3d_render";
- break;
- case LAYER_PHYSICS_3D:
+ layer_group_size = 5;
+ layer_count = 20;
+ } break;
+
+ case LAYER_PHYSICS_3D: {
basename = "layer_names/3d_physics";
- break;
- case LAYER_NAVIGATION_3D:
+ layer_group_size = 4;
+ layer_count = 32;
+ } break;
+
+ case LAYER_NAVIGATION_3D: {
basename = "layer_names/3d_navigation";
- break;
+ layer_group_size = 4;
+ layer_count = 32;
+ } break;
}
Vector<String> names;
Vector<String> tooltips;
- for (int i = 0; i < 20; i++) {
+ for (int i = 0; i < layer_count; i++) {
String name;
if (ProjectSettings::get_singleton()->has_setting(basename + vformat("/layer_%d", i))) {
@@ -858,12 +1007,17 @@ void EditorPropertyLayers::setup(LayerType p_layer_type) {
grid->names = names;
grid->tooltips = tooltips;
+ grid->layer_group_size = layer_group_size;
+ grid->layer_count = layer_count;
}
void EditorPropertyLayers::_button_pressed() {
+ int layer_count = grid->layer_count;
+ int layer_group_size = grid->layer_group_size;
+
layers->clear();
- for (int i = 0; i < 20; i++) {
- if (i == 5 || i == 10 || i == 15) {
+ for (int i = 0; i < layer_count; i++) {
+ if ((i != 0) && ((i % layer_group_size) == 0)) {
layers->add_separator();
}
layers->add_check_item(grid->names[i], i);
@@ -894,17 +1048,21 @@ void EditorPropertyLayers::_bind_methods() {
EditorPropertyLayers::EditorPropertyLayers() {
HBoxContainer *hb = memnew(HBoxContainer);
+ hb->set_clip_contents(true);
add_child(hb);
grid = memnew(EditorPropertyLayersGrid);
grid->connect("flag_changed", callable_mp(this, &EditorPropertyLayers::_grid_changed));
grid->set_h_size_flags(SIZE_EXPAND_FILL);
hb->add_child(grid);
+
button = memnew(Button);
button->set_toggle_mode(true);
button->set_text("...");
button->connect("pressed", callable_mp(this, &EditorPropertyLayers::_button_pressed));
hb->add_child(button);
+
set_bottom_editor(hb);
+
layers = memnew(PopupMenu);
add_child(layers);
layers->set_hide_on_checkable_item_selection(false);
diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp
index 7d809ea656..9977f5f42c 100644
--- a/editor/editor_resource_picker.cpp
+++ b/editor/editor_resource_picker.cpp
@@ -505,7 +505,9 @@ bool EditorResourcePicker::_is_drop_valid(const Dictionary &p_drag_data) const {
Ref<Resource> res;
if (drag_data.has("type") && String(drag_data["type"]) == "script_list_element") {
ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(drag_data["script_list_element"]);
- res = se->get_edited_resource();
+ if (se) {
+ res = se->get_edited_resource();
+ }
} else if (drag_data.has("type") && String(drag_data["type"]) == "resource") {
res = drag_data["resource"];
}
@@ -571,7 +573,9 @@ void EditorResourcePicker::drop_data_fw(const Point2 &p_point, const Variant &p_
Ref<Resource> dropped_resource;
if (drag_data.has("type") && String(drag_data["type"]) == "script_list_element") {
ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(drag_data["script_list_element"]);
- dropped_resource = se->get_edited_resource();
+ if (se) {
+ dropped_resource = se->get_edited_resource();
+ }
} else if (drag_data.has("type") && String(drag_data["type"]) == "resource") {
dropped_resource = drag_data["resource"];
}
diff --git a/editor/editor_run.cpp b/editor/editor_run.cpp
index 4fadbf5922..8a7ec9aa82 100644
--- a/editor/editor_run.cpp
+++ b/editor/editor_run.cpp
@@ -270,6 +270,7 @@ void EditorRun::stop() {
for (const OS::ProcessID &E : pids) {
OS::get_singleton()->kill(E);
}
+ pids.clear();
}
status = STATUS_STOP;
diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp
index 58ab7d3cef..a802afda0f 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -32,12 +32,18 @@
#include "core/input/input.h"
#include "core/math/expression.h"
+#include "core/os/keyboard.h"
#include "editor_node.h"
#include "editor_scale.h"
String EditorSpinSlider::get_tooltip(const Point2 &p_pos) const {
if (grabber->is_visible()) {
- return TS->format_number(rtos(get_value())) + "\n\n" + TTR("Hold Ctrl to round to integers. Hold Shift for more precise changes.");
+#ifdef OSX_ENABLED
+ const int key = KEY_META;
+#else
+ const int key = KEY_CTRL;
+#endif
+ return TS->format_number(rtos(get_value())) + "\n\n" + vformat(TTR("Hold %s to round to integers. Hold Shift for more precise changes."), find_keycode_name(key));
}
return TS->format_number(rtos(get_value()));
}
@@ -116,7 +122,7 @@ void EditorSpinSlider::_gui_input(const Ref<InputEvent> &p_event) {
pre_grab_value = get_max();
}
- if (mm->is_ctrl_pressed()) {
+ if (mm->is_command_pressed()) {
// If control was just pressed, don't make the value do a huge jump in magnitude.
if (grabbing_spinner_dist_cache != 0) {
pre_grab_value += grabbing_spinner_dist_cache * get_step();
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index b3b43348d0..f0cc1530ab 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -380,6 +380,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const Color font_color = mono_color.lerp(base_color, 0.25);
const Color font_hover_color = mono_color.lerp(base_color, 0.125);
const Color font_disabled_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.3);
+ const Color font_readonly_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.65);
const Color selection_color = accent_color * Color(1, 1, 1, 0.4);
const Color disabled_color = mono_color.inverted().lerp(base_color, 0.7);
const Color disabled_bg_color = mono_color.inverted().lerp(base_color, 0.9);
@@ -582,6 +583,10 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// Focus
theme->set_stylebox("Focus", "EditorStyles", style_widget_focus);
+ // Use a less opaque color to be less distracting for the 2D and 3D editor viewports.
+ Ref<StyleBoxFlat> style_widget_focus_viewport = style_widget_focus->duplicate();
+ style_widget_focus_viewport->set_border_color(accent_color * Color(1, 1, 1, 0.5));
+ theme->set_stylebox("FocusViewport", "EditorStyles", style_widget_focus_viewport);
// Menu
Ref<StyleBoxFlat> style_menu = style_widget->duplicate();
@@ -1024,9 +1029,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("read_only", "LineEdit", style_line_edit_disabled);
theme->set_icon("clear", "LineEdit", theme->get_icon("GuiClose", "EditorIcons"));
theme->set_color("read_only", "LineEdit", font_disabled_color);
- theme->set_color("font_uneditable_color", "LineEdit", font_disabled_color);
theme->set_color("font_color", "LineEdit", font_color);
theme->set_color("font_selected_color", "LineEdit", mono_color);
+ theme->set_color("font_uneditable_color", "LineEdit", font_readonly_color);
theme->set_color("caret_color", "LineEdit", font_color);
theme->set_color("selection_color", "LineEdit", selection_color);
theme->set_color("clear_button_color", "LineEdit", font_color);
@@ -1192,7 +1197,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_tooltip->set_default_margin(SIDE_TOP, default_margin_size * EDSCALE * 0.5);
style_tooltip->set_default_margin(SIDE_RIGHT, default_margin_size * EDSCALE);
style_tooltip->set_default_margin(SIDE_BOTTOM, default_margin_size * EDSCALE * 0.5);
- style_tooltip->set_bg_color(mono_color.inverted());
+ style_tooltip->set_bg_color(mono_color.inverted() * Color(1, 1, 1, 0.9));
style_tooltip->set_border_width_all(0);
theme->set_color("font_color", "TooltipLabel", font_hover_color);
theme->set_color("font_color_shadow", "TooltipLabel", Color(0, 0, 0, 0));
diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp
index 87277e79f3..9444706fd2 100644
--- a/editor/find_in_files.cpp
+++ b/editor/find_in_files.cpp
@@ -228,6 +228,11 @@ void FindInFiles::_scan_dir(String path, PackedStringArray &out_folders) {
break;
}
+ // If there is a .gdignore file in the directory, don't bother searching it
+ if (file == ".gdignore") {
+ break;
+ }
+
// Ignore special dirs (such as .git and .import)
if (file == "." || file == ".." || file.begins_with(".")) {
continue;
diff --git a/editor/icons/TileMapHighlightSelected.svg b/editor/icons/TileMapHighlightSelected.svg
new file mode 100644
index 0000000000..de8a291b8e
--- /dev/null
+++ b/editor/icons/TileMapHighlightSelected.svg
@@ -0,0 +1 @@
+<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" fill-rule="nonzero"><path d="m4.5 5.2011663h10.5v2.005h-10.5z" stroke-width="1.14115"/><g stroke-width=".862635"><path d="m2 4.2340105v-1h1l1 2z"/><path d="m2 8.2340105v1h1l1-2z"/><path d="m1.3786796 5.5269037-.70710677.7071068.70710677.7071068 2.1213204-.7071068z"/></g><path d="m4.5 1.7061663h10.5v2.005h-10.5z" stroke-width="1.14117"/><g stroke-width="1.14116"><path d="m4.5 8.7011663h10.5v2.0049997h-10.5z"/><path d="m4.5 12.206166h10.5v2.005h-10.5z"/></g></g></svg>
diff --git a/editor/import/editor_importer_bake_reset.cpp b/editor/import/editor_importer_bake_reset.cpp
new file mode 100644
index 0000000000..939c47faa4
--- /dev/null
+++ b/editor/import/editor_importer_bake_reset.cpp
@@ -0,0 +1,223 @@
+/*************************************************************************/
+/* editor_importer_bake_reset.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "editor/import/editor_importer_bake_reset.h"
+
+#include "core/error/error_macros.h"
+#include "core/math/transform_3d.h"
+#include "editor/import/scene_importer_mesh_node_3d.h"
+#include "resource_importer_scene.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/3d/node_3d.h"
+#include "scene/3d/skeleton_3d.h"
+#include "scene/animation/animation_player.h"
+
+// Given that an engineering team has made a reference character, one wants ten animators to create animations.
+// Currently, a tech artist needs to combine the ten files into one exported gltf2 to import into Godot Engine.
+// We bake the RESET animation and then set it to identity,
+// so that rigs with corresponding RESET animation can have their animations transferred with ease.
+//
+// The original algorithm for the code was used to change skeleton bone rolls to be parent to child.
+//
+// Reference https://github.com/godotengine/godot-proposals/issues/2961
+void BakeReset::_bake_animation_pose(Node *scene, const String &p_bake_anim) {
+ Map<StringName, BakeResetRestBone> r_rest_bones;
+ Vector<Node3D *> r_meshes;
+ List<Node *> queue;
+ queue.push_back(scene);
+ while (!queue.is_empty()) {
+ List<Node *>::Element *E = queue.front();
+ Node *node = E->get();
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(node);
+ // Step 1: import scene with animations into the rest bones data structure.
+ _fetch_reset_animation(ap, r_rest_bones, p_bake_anim);
+
+ int child_count = node->get_child_count();
+ for (int i = 0; i < child_count; i++) {
+ queue.push_back(node->get_child(i));
+ }
+ queue.pop_front();
+ }
+
+ queue.push_back(scene);
+ while (!queue.is_empty()) {
+ List<Node *>::Element *E = queue.front();
+ Node *node = E->get();
+ EditorSceneImporterMeshNode3D *editor_mesh_3d = scene->cast_to<EditorSceneImporterMeshNode3D>(node);
+ MeshInstance3D *mesh_3d = scene->cast_to<MeshInstance3D>(node);
+ if (scene->cast_to<Skeleton3D>(node)) {
+ Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node);
+
+ // Step 2: Bake the RESET animation from the RestBone to the skeleton.
+ _fix_skeleton(skeleton, r_rest_bones);
+ }
+ if (editor_mesh_3d) {
+ NodePath path = editor_mesh_3d->get_skeleton_path();
+ if (!path.is_empty() && editor_mesh_3d->get_node_or_null(path) && Object::cast_to<Skeleton3D>(editor_mesh_3d->get_node_or_null(path))) {
+ r_meshes.push_back(editor_mesh_3d);
+ }
+ } else if (mesh_3d) {
+ NodePath path = mesh_3d->get_skeleton_path();
+ if (!path.is_empty() && mesh_3d->get_node_or_null(path) && Object::cast_to<Skeleton3D>(mesh_3d->get_node_or_null(path))) {
+ r_meshes.push_back(mesh_3d);
+ }
+ }
+ int child_count = node->get_child_count();
+ for (int i = 0; i < child_count; i++) {
+ queue.push_back(node->get_child(i));
+ }
+ queue.pop_front();
+ }
+
+ queue.push_back(scene);
+ while (!queue.is_empty()) {
+ List<Node *>::Element *E = queue.front();
+ Node *node = E->get();
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(node);
+ if (ap) {
+ // Step 3: Key all RESET animation frames to identity.
+ _align_animations(ap, r_rest_bones);
+ }
+
+ int child_count = node->get_child_count();
+ for (int i = 0; i < child_count; i++) {
+ queue.push_back(node->get_child(i));
+ }
+ queue.pop_front();
+ }
+}
+
+void BakeReset::_align_animations(AnimationPlayer *p_ap, const Map<StringName, BakeResetRestBone> &r_rest_bones) {
+ ERR_FAIL_NULL(p_ap);
+ List<StringName> anim_names;
+ p_ap->get_animation_list(&anim_names);
+ for (List<StringName>::Element *anim_i = anim_names.front(); anim_i; anim_i = anim_i->next()) {
+ Ref<Animation> a = p_ap->get_animation(anim_i->get());
+ ERR_CONTINUE(a.is_null());
+ for (Map<StringName, BakeResetRestBone>::Element *rest_bone_i = r_rest_bones.front(); rest_bone_i; rest_bone_i = rest_bone_i->next()) {
+ int track = a->find_track(NodePath(rest_bone_i->key()));
+ if (track == -1) {
+ continue;
+ }
+ int new_track = a->add_track(Animation::TYPE_TRANSFORM3D);
+ NodePath new_path = NodePath(rest_bone_i->key());
+ BakeResetRestBone rest_bone = rest_bone_i->get();
+ a->track_set_path(new_track, new_path);
+ for (int key_i = 0; key_i < a->track_get_key_count(track); key_i++) {
+ Vector3 loc;
+ Quaternion rot;
+ Vector3 scale;
+ Error err = a->transform_track_get_key(track, key_i, &loc, &rot, &scale);
+ ERR_CONTINUE(err);
+ real_t time = a->track_get_key_time(track, key_i);
+ rot.normalize();
+ loc = loc - rest_bone.loc;
+ rot = rest_bone.rest_delta.get_rotation_quaternion().inverse() * rot;
+ rot.normalize();
+ scale = Vector3(1, 1, 1) - (rest_bone.rest_delta.get_scale() - scale);
+ // Apply the reverse of the rest changes to make the key be close to identity transform.
+ a->transform_track_insert_key(new_track, time, loc, rot, scale);
+ }
+ a->remove_track(track);
+ }
+ }
+}
+
+void BakeReset::_fetch_reset_animation(AnimationPlayer *p_ap, Map<StringName, BakeResetRestBone> &r_rest_bones, const String &p_bake_anim) {
+ ERR_FAIL_NULL(p_ap);
+ List<StringName> anim_names;
+ p_ap->get_animation_list(&anim_names);
+ Node *root = p_ap->get_owner();
+ ERR_FAIL_NULL(root);
+ Ref<Animation> a = p_ap->get_animation(p_bake_anim);
+ ERR_FAIL_NULL(a);
+ for (int32_t track = 0; track < a->get_track_count(); track++) {
+ NodePath path = a->track_get_path(track);
+ String string_path = path;
+ Skeleton3D *skeleton = root->cast_to<Skeleton3D>(root->get_node(string_path.get_slice(":", 0)));
+ if (!skeleton) {
+ continue;
+ }
+ String bone_name = string_path.get_slice(":", 1);
+ for (int key_i = 0; key_i < a->track_get_key_count(track); key_i++) {
+ Vector3 loc;
+ Quaternion rot;
+ Vector3 scale;
+ Error err = a->transform_track_get_key(track, key_i, &loc, &rot, &scale);
+ ERR_CONTINUE(err);
+ rot.normalize();
+ Basis rot_basis = Basis(rot, scale);
+ BakeResetRestBone rest_bone;
+ rest_bone.rest_delta = rot_basis;
+ rest_bone.loc = loc;
+ // Store the animation into the RestBone.
+ r_rest_bones[StringName(String(skeleton->get_owner()->get_path_to(skeleton)) + ":" + bone_name)] = rest_bone;
+ break;
+ }
+ }
+}
+
+void BakeReset::_fix_skeleton(Skeleton3D *p_skeleton, Map<StringName, BakeReset::BakeResetRestBone> &r_rest_bones) {
+ int bone_count = p_skeleton->get_bone_count();
+
+ // First iterate through all the bones and update the RestBone.
+ for (int j = 0; j < bone_count; j++) {
+ StringName final_path = String(p_skeleton->get_owner()->get_path_to(p_skeleton)) + String(":") + p_skeleton->get_bone_name(j);
+ BakeResetRestBone &rest_bone = r_rest_bones[final_path];
+ rest_bone.rest_local = p_skeleton->get_bone_rest(j);
+ }
+ for (int i = 0; i < bone_count; i++) {
+ int parent_bone = p_skeleton->get_bone_parent(i);
+ String path = p_skeleton->get_owner()->get_path_to(p_skeleton);
+ StringName final_path = String(path) + String(":") + p_skeleton->get_bone_name(parent_bone);
+ if (parent_bone >= 0) {
+ r_rest_bones[path].children.push_back(i);
+ }
+ }
+
+ // When we apply transform to a bone, we also have to move all of its children in the opposite direction.
+ for (int i = 0; i < bone_count; i++) {
+ StringName final_path = String(p_skeleton->get_owner()->get_path_to(p_skeleton)) + String(":") + p_skeleton->get_bone_name(i);
+ r_rest_bones[final_path].rest_local = r_rest_bones[final_path].rest_local * Transform3D(r_rest_bones[final_path].rest_delta, r_rest_bones[final_path].loc);
+ // Iterate through the children and move in the opposite direction.
+ for (int j = 0; j < r_rest_bones[final_path].children.size(); j++) {
+ int child_index = r_rest_bones[final_path].children[j];
+ StringName children_path = String(p_skeleton->get_name()) + String(":") + p_skeleton->get_bone_name(child_index);
+ r_rest_bones[children_path].rest_local = Transform3D(r_rest_bones[final_path].rest_delta, r_rest_bones[final_path].loc).affine_inverse() * r_rest_bones[children_path].rest_local;
+ }
+ }
+
+ for (int i = 0; i < bone_count; i++) {
+ StringName final_path = String(p_skeleton->get_owner()->get_path_to(p_skeleton)) + String(":") + p_skeleton->get_bone_name(i);
+ ERR_CONTINUE(!r_rest_bones.has(final_path));
+ Transform3D rest_transform = r_rest_bones[final_path].rest_local;
+ p_skeleton->set_bone_rest(i, rest_transform);
+ }
+}
diff --git a/editor/import/editor_importer_bake_reset.h b/editor/import/editor_importer_bake_reset.h
new file mode 100644
index 0000000000..e36ae86181
--- /dev/null
+++ b/editor/import/editor_importer_bake_reset.h
@@ -0,0 +1,54 @@
+/*************************************************************************/
+/* editor_importer_bake_reset.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef RESOURCE_IMPORTER_BAKE_RESET_H
+#define RESOURCE_IMPORTER_BAKE_RESET_H
+
+#include "scene/main/node.h"
+
+class Skeleton3D;
+class AnimationPlayer;
+class BakeReset {
+ struct BakeResetRestBone {
+ Transform3D rest_local;
+ Basis rest_delta;
+ Vector3 loc;
+ Vector<int> children;
+ };
+
+public:
+ void _bake_animation_pose(Node *scene, const String &p_bake_anim);
+
+private:
+ void _fix_skeleton(Skeleton3D *p_skeleton, Map<StringName, BakeReset::BakeResetRestBone> &r_rest_bones);
+ void _align_animations(AnimationPlayer *p_ap, const Map<StringName, BakeResetRestBone> &r_rest_bones);
+ void _fetch_reset_animation(AnimationPlayer *p_ap, Map<StringName, BakeResetRestBone> &r_rest_bones, const String &p_bake_anim);
+};
+#endif
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index e9160f0414..1e642462dc 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -32,6 +32,7 @@
#include "core/io/resource_saver.h"
#include "editor/editor_node.h"
+#include "editor/import/editor_importer_bake_reset.h"
#include "editor/import/scene_import_settings.h"
#include "editor/import/scene_importer_mesh_node_3d.h"
#include "scene/3d/area_3d.h"
@@ -1060,6 +1061,7 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "meshes/lightmap_texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.1));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "skins/use_named_skins"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import"), true));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/bake_reset_animation"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 15));
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "import_script/path", PROPERTY_HINT_FILE, script_ext_hint), ""));
@@ -1410,6 +1412,11 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
_pre_fix_node(scene, scene, collision_map);
_post_fix_node(scene, scene, collision_map, scanned_meshes, node_data, material_data, animation_data, fps);
+ bool use_bake_reset_animation = p_options["animation/bake_reset_animation"];
+ if (use_bake_reset_animation) {
+ BakeReset bake_reset;
+ bake_reset._bake_animation_pose(scene, "RESET");
+ }
String root_type = p_options["nodes/root_type"];
root_type = root_type.split(" ")[0]; // full root_type is "ClassName (filename.gd)" for a script global class.
diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp
index 1973494a2a..a566afb597 100644
--- a/editor/inspector_dock.cpp
+++ b/editor/inspector_dock.cpp
@@ -409,6 +409,7 @@ void InspectorDock::update(Object *p_object) {
current = p_object;
if (!p_object) {
+ open_docs_button->set_disabled(true);
object_menu->set_disabled(true);
warning->hide();
search->set_editable(false);
@@ -424,7 +425,7 @@ void InspectorDock::update(Object *p_object) {
editor_path->enable_path();
resource_save_button->set_disabled(!is_resource);
- open_docs_button->set_visible(is_resource || is_node);
+ open_docs_button->set_disabled(!is_resource && !is_node);
PopupMenu *resource_extra_popup = resource_extra_button->get_popup();
resource_extra_popup->set_item_disabled(resource_extra_popup->get_item_index(RESOURCE_COPY), !is_resource);
@@ -575,7 +576,7 @@ InspectorDock::InspectorDock(EditorNode *p_editor, EditorData &p_editor_data) {
open_docs_button = memnew(Button);
open_docs_button->set_flat(true);
- open_docs_button->set_visible(false);
+ open_docs_button->set_disabled(true);
open_docs_button->set_tooltip(TTR("Open documentation for this object."));
open_docs_button->set_icon(get_theme_icon(SNAME("HelpSearch"), SNAME("EditorIcons")));
open_docs_button->set_shortcut(ED_SHORTCUT("property_editor/open_help", TTR("Open Documentation")));
diff --git a/editor/localization_editor.cpp b/editor/localization_editor.cpp
index b32ea67d4d..3fe1aa557d 100644
--- a/editor/localization_editor.cpp
+++ b/editor/localization_editor.cpp
@@ -371,15 +371,10 @@ void LocalizationEditor::_translation_filter_mode_changed(int p_mode) {
void LocalizationEditor::_pot_add(const PackedStringArray &p_paths) {
PackedStringArray pot_translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations_pot_files");
-
for (int i = 0; i < p_paths.size(); i++) {
- for (int j = 0; j < pot_translations.size(); j++) {
- if (pot_translations[j] == p_paths[i]) {
- continue; //exists
- }
+ if (!pot_translations.has(p_paths[i])) {
+ pot_translations.push_back(p_paths[i]);
}
-
- pot_translations.push_back(p_paths[i]);
}
undo_redo->create_action(vformat(TTR("Add %d file(s) for POT generation"), p_paths.size()));
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index c94014944c..69206daea8 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -89,7 +89,7 @@ Size2 AnimationNodeBlendTreeEditor::get_minimum_size() const {
void AnimationNodeBlendTreeEditor::_property_changed(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing) {
AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_tree();
updating = true;
- undo_redo->create_action(TTR("Parameter Changed") + ": " + String(p_property), UndoRedo::MERGE_ENDS);
+ undo_redo->create_action(TTR("Parameter Changed:") + " " + String(p_property), UndoRedo::MERGE_ENDS);
undo_redo->add_do_property(tree, p_property, p_value);
undo_redo->add_undo_property(tree, p_property, tree->get(p_property));
undo_redo->add_do_method(this, "_update_graph");
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index 4ba9147955..681c3e7195 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -408,7 +408,8 @@ void AnimationPlayerEditor::_animation_save_as(const Ref<Resource> &p_resource)
if (p_resource->get_name() != "") {
path = p_resource->get_name() + "." + extensions.front()->get().to_lower();
} else {
- path = "new_" + p_resource->get_class().to_lower() + "." + extensions.front()->get().to_lower();
+ String resource_name_snake_case = p_resource->get_class().camelcase_to_underscore();
+ path = "new_" + resource_name_snake_case + "." + extensions.front()->get().to_lower();
}
}
}
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 02b6dd654e..16e224b105 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -81,8 +81,8 @@ public:
SnapDialog() {
const int SPIN_BOX_GRID_RANGE = 16384;
const int SPIN_BOX_ROTATION_RANGE = 360;
- const float SPIN_BOX_SCALE_MIN = 0.01f;
- const float SPIN_BOX_SCALE_MAX = 100;
+ const real_t SPIN_BOX_SCALE_MIN = 0.01;
+ const real_t SPIN_BOX_SCALE_MAX = 100;
Label *label;
VBoxContainer *container;
@@ -210,7 +210,7 @@ public:
child_container->add_child(scale_step);
}
- void set_fields(const Point2 p_grid_offset, const Point2 p_grid_step, const int p_primary_grid_steps, const float p_rotation_offset, const float p_rotation_step, const float p_scale_step) {
+ void set_fields(const Point2 p_grid_offset, const Point2 p_grid_step, const int p_primary_grid_steps, const real_t p_rotation_offset, const real_t p_rotation_step, const real_t p_scale_step) {
grid_offset_x->set_value(p_grid_offset.x);
grid_offset_y->set_value(p_grid_offset.y);
grid_step_x->set_value(p_grid_step.x);
@@ -221,7 +221,7 @@ public:
scale_step->set_value(p_scale_step);
}
- void get_fields(Point2 &p_grid_offset, Point2 &p_grid_step, int &p_primary_grid_steps, float &p_rotation_offset, float &p_rotation_step, float &p_scale_step) {
+ void get_fields(Point2 &p_grid_offset, Point2 &p_grid_step, int &p_primary_grid_steps, real_t &p_rotation_offset, real_t &p_rotation_step, real_t &p_scale_step) {
p_grid_offset = Point2(grid_offset_x->get_value(), grid_offset_y->get_value());
p_grid_step = Point2(grid_step_x->get_value(), grid_step_y->get_value());
p_primary_grid_steps = int(primary_grid_steps->get_value());
@@ -249,12 +249,12 @@ bool CanvasItemEditor::_is_node_movable(const Node *p_node, bool p_popup_warning
}
void CanvasItemEditor::_snap_if_closer_float(
- float p_value,
- float &r_current_snap, SnapTarget &r_current_snap_target,
- float p_target_value, SnapTarget p_snap_target,
- float p_radius) {
- float radius = p_radius / zoom;
- float dist = Math::abs(p_value - p_target_value);
+ const real_t p_value,
+ real_t &r_current_snap, SnapTarget &r_current_snap_target,
+ const real_t p_target_value, const SnapTarget p_snap_target,
+ const real_t p_radius) {
+ const real_t radius = p_radius / zoom;
+ const real_t dist = Math::abs(p_value - p_target_value);
if ((p_radius < 0 || dist < radius) && (r_current_snap_target == SNAP_TARGET_NONE || dist < Math::abs(r_current_snap - p_value))) {
r_current_snap = p_target_value;
r_current_snap_target = p_snap_target;
@@ -264,9 +264,9 @@ void CanvasItemEditor::_snap_if_closer_float(
void CanvasItemEditor::_snap_if_closer_point(
Point2 p_value,
Point2 &r_current_snap, SnapTarget (&r_current_snap_target)[2],
- Point2 p_target_value, SnapTarget p_snap_target,
- real_t rotation,
- float p_radius) {
+ Point2 p_target_value, const SnapTarget p_snap_target,
+ const real_t rotation,
+ const real_t p_radius) {
Transform2D rot_trans = Transform2D(rotation, Point2());
p_value = rot_trans.inverse().xform(p_value);
p_target_value = rot_trans.inverse().xform(p_target_value);
@@ -459,7 +459,7 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, unsig
return output;
}
-float CanvasItemEditor::snap_angle(float p_target, float p_start) const {
+real_t CanvasItemEditor::snap_angle(real_t p_target, real_t p_start) const {
if (((smart_snap_active || snap_rotation) ^ Input::get_singleton()->is_key_pressed(KEY_CTRL)) && snap_rotation_step != 0) {
if (snap_relative) {
return Math::snapped(p_target - snap_rotation_offset, snap_rotation_step) + snap_rotation_offset + (p_start - (int)(p_start / snap_rotation_step) * snap_rotation_step);
@@ -923,7 +923,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
}
// Hover over guides
- float minimum = 1e20;
+ real_t minimum = 1e20;
is_hovering_h_guide = false;
is_hovering_v_guide = false;
@@ -1264,7 +1264,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
if (pan_gesture.is_valid() && !p_already_accepted) {
// If ctrl key pressed, then zoom instead of pan.
if (pan_gesture->is_ctrl_pressed()) {
- const float factor = pan_gesture->get_delta().y;
+ const real_t factor = pan_gesture->get_delta().y;
zoom_widget->set_zoom_by_increments(1);
if (factor != 1.f) {
@@ -1490,9 +1490,9 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) {
anchor_pos[i] = (transform * control->get_global_transform_with_canvas()).xform(_anchor_to_position(control, anchor_pos[i]));
anchor_rects[i] = Rect2(anchor_pos[i], anchor_handle->get_size());
if (control->is_layout_rtl()) {
- anchor_rects[i].position -= anchor_handle->get_size() * Vector2(float(i == 1 || i == 2), float(i <= 1));
+ anchor_rects[i].position -= anchor_handle->get_size() * Vector2(real_t(i == 1 || i == 2), real_t(i <= 1));
} else {
- anchor_rects[i].position -= anchor_handle->get_size() * Vector2(float(i == 0 || i == 3), float(i <= 1));
+ anchor_rects[i].position -= anchor_handle->get_size() * Vector2(real_t(i == 0 || i == 3), real_t(i <= 1));
}
}
@@ -1646,7 +1646,7 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {
};
DragType resize_drag = DRAG_NONE;
- float radius = (select_handle->get_size().width / 2) * 1.5;
+ real_t radius = (select_handle->get_size().width / 2) * 1.5;
for (int i = 0; i < 4; i++) {
int prev = (i + 3) % 4;
@@ -1692,7 +1692,7 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {
bool symmetric = m->is_alt_pressed();
Rect2 local_rect = canvas_item->_edit_get_rect();
- float aspect = local_rect.get_size().y / local_rect.get_size().x;
+ real_t aspect = local_rect.get_size().y / local_rect.get_size().x;
Point2 current_begin = local_rect.get_position();
Point2 current_end = local_rect.get_position() + local_rect.get_size();
Point2 max_begin = (symmetric) ? (current_begin + current_end - canvas_item->_edit_get_minimum_size()) / 2.0 : current_end - canvas_item->_edit_get_minimum_size();
@@ -1883,7 +1883,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
Size2 scale = canvas_item->call("get_scale");
Size2 original_scale = scale;
- float ratio = scale.y / scale.x;
+ real_t ratio = scale.y / scale.x;
if (drag_type == DRAG_SCALE_BOTH) {
Size2 scale_factor = drag_to_local / drag_from_local;
if (uniform) {
@@ -2012,11 +2012,13 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
drag_to = transform.affine_inverse().xform(m->get_position());
Point2 previous_pos;
- if (drag_selection.size() == 1) {
- Transform2D xform = drag_selection[0]->get_global_transform_with_canvas() * drag_selection[0]->get_transform().affine_inverse();
- previous_pos = xform.xform(drag_selection[0]->_edit_get_position());
- } else {
- previous_pos = _get_encompassing_rect_from_list(drag_selection).position;
+ if (!drag_selection.is_empty()) {
+ if (drag_selection.size() == 1) {
+ Transform2D xform = drag_selection[0]->get_global_transform_with_canvas() * drag_selection[0]->get_transform().affine_inverse();
+ previous_pos = xform.xform(drag_selection[0]->_edit_get_position());
+ } else {
+ previous_pos = _get_encompassing_rect_from_list(drag_selection).position;
+ }
}
Point2 new_pos = snap_point(previous_pos + (drag_to - drag_from), SNAP_GRID | SNAP_GUIDES | SNAP_PIXEL | SNAP_NODE_PARENT | SNAP_NODE_ANCHORS | SNAP_OTHER_NODES, 0, nullptr, drag_selection);
@@ -2539,7 +2541,7 @@ void CanvasItemEditor::_update_cursor() {
List<CanvasItem *> selection = _get_edited_canvas_items();
if (selection.size() == 1) {
- float angle = Math::fposmod((double)selection[0]->get_global_transform_with_canvas().get_rotation(), Math_PI);
+ const double angle = Math::fposmod((double)selection[0]->get_global_transform_with_canvas().get_rotation(), Math_PI);
if (angle > Math_PI * 7.0 / 8.0) {
rotation_array_index = 0;
} else if (angle > Math_PI * 5.0 / 8.0) {
@@ -2645,7 +2647,7 @@ void CanvasItemEditor::_draw_margin_at_position(int p_value, Point2 p_position,
}
}
-void CanvasItemEditor::_draw_percentage_at_position(float p_value, Point2 p_position, Side p_side) {
+void CanvasItemEditor::_draw_percentage_at_position(real_t p_value, Point2 p_position, Side p_side) {
String str = TS->format_number(vformat("%.1f ", p_value * 100.0)) + TS->percent_sign();
if (p_value != 0) {
_draw_text_at_position(p_position, str, p_side);
@@ -2655,7 +2657,7 @@ void CanvasItemEditor::_draw_percentage_at_position(float p_value, Point2 p_posi
void CanvasItemEditor::_draw_focus() {
// Draw the focus around the base viewport
if (viewport->has_focus()) {
- get_theme_stylebox(SNAME("Focus"), SNAME("EditorStyles"))->draw(viewport->get_canvas_item(), Rect2(Point2(), viewport->get_size()));
+ get_theme_stylebox(SNAME("FocusViewport"), SNAME("EditorStyles"))->draw(viewport->get_canvas_item(), Rect2(Point2(), viewport->get_size()));
}
}
@@ -2670,7 +2672,7 @@ void CanvasItemEditor::_draw_guides() {
if (drag_type == DRAG_V_GUIDE && i == dragged_guide_index) {
continue;
}
- float x = xform.xform(Point2(vguides[i], 0)).x;
+ real_t x = xform.xform(Point2(vguides[i], 0)).x;
viewport->draw_line(Point2(x, 0), Point2(x, viewport->get_size().y), guide_color, Math::round(EDSCALE));
}
}
@@ -2681,7 +2683,7 @@ void CanvasItemEditor::_draw_guides() {
if (drag_type == DRAG_H_GUIDE && i == dragged_guide_index) {
continue;
}
- float y = xform.xform(Point2(0, hguides[i])).y;
+ real_t y = xform.xform(Point2(0, hguides[i])).y;
viewport->draw_line(Point2(0, y), Point2(viewport->get_size().x, y), guide_color, Math::round(EDSCALE));
}
}
@@ -2745,7 +2747,7 @@ void CanvasItemEditor::_draw_rulers() {
ruler_transform.scale_basis(Point2(2, 2));
}
} else {
- float basic_rule = 100;
+ real_t basic_rule = 100;
for (int i = 0; basic_rule * zoom > 100; i++) {
basic_rule /= (i % 2) ? 5.0 : 2.0;
}
@@ -2774,7 +2776,7 @@ void CanvasItemEditor::_draw_rulers() {
Point2 position = (transform * ruler_transform * major_subdivide * minor_subdivide).xform(Point2(i, 0)).round();
if (i % (major_subdivision * minor_subdivision) == 0) {
viewport->draw_line(Point2(position.x, 0), Point2(position.x, RULER_WIDTH), graduation_color, Math::round(EDSCALE));
- float val = (ruler_transform * major_subdivide * minor_subdivide).xform(Point2(i, 0)).x;
+ real_t val = (ruler_transform * major_subdivide * minor_subdivide).xform(Point2(i, 0)).x;
viewport->draw_string(font, Point2(position.x + 2, font->get_height(font_size)), TS->format_number(vformat(((int)val == val) ? "%d" : "%.1f", val)), HALIGN_LEFT, -1, font_size, font_color);
} else {
if (i % minor_subdivision == 0) {
@@ -2791,7 +2793,7 @@ void CanvasItemEditor::_draw_rulers() {
Point2 position = (transform * ruler_transform * major_subdivide * minor_subdivide).xform(Point2(0, i)).round();
if (i % (major_subdivision * minor_subdivision) == 0) {
viewport->draw_line(Point2(0, position.y), Point2(RULER_WIDTH, position.y), graduation_color, Math::round(EDSCALE));
- float val = (ruler_transform * major_subdivide * minor_subdivide).xform(Point2(0, i)).y;
+ real_t val = (ruler_transform * major_subdivide * minor_subdivide).xform(Point2(0, i)).y;
Transform2D text_xform = Transform2D(-Math_PI / 2.0, Point2(font->get_height(font_size), position.y - 2));
viewport->draw_set_transform_matrix(viewport->get_transform() * text_xform);
@@ -2924,8 +2926,8 @@ void CanvasItemEditor::_draw_ruler_tool() {
viewport->draw_string(font, text_pos, TS->format_number(vformat("%.1f px", length_vector.length())), HALIGN_LEFT, -1, font_size, font_color, outline_size, outline_color);
if (draw_secondary_lines) {
- const float horizontal_angle_rad = atan2(length_vector.y, length_vector.x);
- const float vertical_angle_rad = Math_PI / 2.0 - horizontal_angle_rad;
+ const real_t horizontal_angle_rad = atan2(length_vector.y, length_vector.x);
+ const real_t vertical_angle_rad = Math_PI / 2.0 - horizontal_angle_rad;
const int horizontal_angle = round(180 * horizontal_angle_rad / Math_PI);
const int vertical_angle = round(180 * vertical_angle_rad / Math_PI);
@@ -2961,28 +2963,28 @@ void CanvasItemEditor::_draw_ruler_tool() {
// Angle arcs
int arc_point_count = 8;
- float arc_radius_max_length_percent = 0.1;
- float ruler_length = length_vector.length() * zoom;
- float arc_max_radius = 50.0;
- float arc_line_width = 2.0;
+ real_t arc_radius_max_length_percent = 0.1;
+ real_t ruler_length = length_vector.length() * zoom;
+ real_t arc_max_radius = 50.0;
+ real_t arc_line_width = 2.0;
const Vector2 end_to_begin = (end - begin);
- float arc_1_start_angle =
+ real_t arc_1_start_angle =
end_to_begin.x < 0 ?
(end_to_begin.y < 0 ? 3.0 * Math_PI / 2.0 - vertical_angle_rad : Math_PI / 2.0) :
(end_to_begin.y < 0 ? 3.0 * Math_PI / 2.0 : Math_PI / 2.0 - vertical_angle_rad);
- float arc_1_end_angle = arc_1_start_angle + vertical_angle_rad;
+ real_t arc_1_end_angle = arc_1_start_angle + vertical_angle_rad;
// Constrain arc to triangle height & max size
- float arc_1_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.y)), arc_max_radius);
+ real_t arc_1_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.y)), arc_max_radius);
- float arc_2_start_angle =
+ real_t arc_2_start_angle =
end_to_begin.x < 0 ?
(end_to_begin.y < 0 ? 0.0 : -horizontal_angle_rad) :
(end_to_begin.y < 0 ? Math_PI - horizontal_angle_rad : Math_PI);
- float arc_2_end_angle = arc_2_start_angle + horizontal_angle_rad;
+ real_t arc_2_end_angle = arc_2_start_angle + horizontal_angle_rad;
// Constrain arc to triangle width & max size
- float arc_2_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.x)), arc_max_radius);
+ real_t arc_2_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.x)), arc_max_radius);
viewport->draw_arc(begin, arc_1_radius, arc_1_start_angle, arc_1_end_angle, arc_point_count, ruler_primary_color, Math::round(EDSCALE * arc_line_width));
viewport->draw_arc(end, arc_2_radius, arc_2_start_angle, arc_2_end_angle, arc_point_count, ruler_primary_color, Math::round(EDSCALE * arc_line_width));
@@ -3020,7 +3022,7 @@ void CanvasItemEditor::_draw_control_anchors(Control *control) {
RID ci = viewport->get_canvas_item();
if (tool == TOOL_SELECT && !Object::cast_to<Container>(control->get_parent())) {
// Compute the anchors
- float anchors_values[4];
+ real_t anchors_values[4];
anchors_values[0] = control->get_anchor(SIDE_LEFT);
anchors_values[1] = control->get_anchor(SIDE_TOP);
anchors_values[2] = control->get_anchor(SIDE_RIGHT);
@@ -3059,7 +3061,7 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) {
Color color_base = Color(0.8, 0.8, 0.8, 0.5);
// Compute the anchors
- float anchors_values[4];
+ real_t anchors_values[4];
anchors_values[0] = control->get_anchor(SIDE_LEFT);
anchors_values[1] = control->get_anchor(SIDE_TOP);
anchors_values[2] = control->get_anchor(SIDE_RIGHT);
@@ -3105,7 +3107,7 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) {
Vector2 line_starts[4];
Vector2 line_ends[4];
for (int i = 0; i < 4; i++) {
- float anchor_val = (i >= 2) ? ANCHOR_END - anchors_values[i] : anchors_values[i];
+ real_t anchor_val = (i >= 2) ? ANCHOR_END - anchors_values[i] : anchors_values[i];
line_starts[i] = corners_pos[i].lerp(corners_pos[(i + 1) % 4], anchor_val);
line_ends[i] = corners_pos[(i + 3) % 4].lerp(corners_pos[(i + 2) % 4], anchor_val);
anchor_snapped = anchors_values[i] == 0.0 || anchors_values[i] == 0.5 || anchors_values[i] == 1.0;
@@ -3113,7 +3115,7 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) {
}
// Display the percentages next to the lines
- float percent_val;
+ real_t percent_val;
percent_val = anchors_values[(dragged_anchor + 2) % 4] - anchors_values[dragged_anchor];
percent_val = (dragged_anchor >= 2) ? -percent_val : percent_val;
_draw_percentage_at_position(percent_val, (anchors_pos[dragged_anchor] + anchors_pos[(dragged_anchor + 1) % 4]) / 2, (Side)((dragged_anchor + 1) % 4));
@@ -3132,9 +3134,9 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) {
}
// Draw the margin values and the node width/height when dragging control side
- float ratio = 0.33;
+ const real_t ratio = 0.33;
Transform2D parent_transform = xform * control->get_transform().affine_inverse();
- float node_pos_in_parent[4];
+ real_t node_pos_in_parent[4];
Rect2 parent_rect = control->get_parent_anchorable_rect();
@@ -3451,10 +3453,10 @@ void CanvasItemEditor::_draw_straight_line(Point2 p_from, Point2 p_to, Color p_c
points.push_back(Point2(0, to.y));
points.push_back(Point2(viewport_size.x, to.y));
} else {
- float y_for_zero_x = (to.y * from.x - from.y * to.x) / (from.x - to.x);
- float x_for_zero_y = (to.x * from.y - from.x * to.y) / (from.y - to.y);
- float y_for_viewport_x = ((to.y - from.y) * (viewport_size.x - from.x)) / (to.x - from.x) + from.y;
- float x_for_viewport_y = ((to.x - from.x) * (viewport_size.y - from.y)) / (to.y - from.y) + from.x; // faux
+ real_t y_for_zero_x = (to.y * from.x - from.y * to.x) / (from.x - to.x);
+ real_t x_for_zero_y = (to.x * from.y - from.x * to.y) / (from.y - to.y);
+ real_t y_for_viewport_x = ((to.y - from.y) * (viewport_size.x - from.x)) / (to.x - from.x) + from.y;
+ real_t x_for_viewport_y = ((to.x - from.x) * (viewport_size.y - from.y)) / (to.y - from.y) + from.x; // faux
//bool start_set = false;
if (y_for_zero_x >= 0 && y_for_zero_x <= viewport_size.y) {
@@ -3600,7 +3602,7 @@ void CanvasItemEditor::_draw_locks_and_groups(Node *p_node, const Transform2D &p
RID viewport_canvas_item = viewport->get_canvas_item();
if (canvas_item) {
- float offset = 0;
+ real_t offset = 0;
Ref<Texture2D> lock = get_theme_icon(SNAME("LockViewport"), SNAME("EditorIcons"));
if (p_node->has_meta("_edit_lock_") && show_edit_locks) {
@@ -3724,7 +3726,7 @@ void CanvasItemEditor::_notification(int p_what) {
Control *control = Object::cast_to<Control>(canvas_item);
if (control) {
- float anchors[4];
+ real_t anchors[4];
Vector2 pivot;
pivot = control->get_pivot_offset();
@@ -3853,7 +3855,10 @@ void CanvasItemEditor::_notification(int p_what) {
key_auto_insert_button->add_theme_color_override("icon_pressed_color", key_auto_color.lerp(Color(1, 0, 0), 0.55));
animation_menu->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
+ _update_context_menu_stylebox();
+
presets_menu->set_icon(get_theme_icon(SNAME("ControlLayout"), SNAME("EditorIcons")));
+
PopupMenu *p = presets_menu->get_popup();
p->clear();
@@ -3954,6 +3959,18 @@ void CanvasItemEditor::edit(CanvasItem *p_canvas_item) {
}
}
+void CanvasItemEditor::_update_context_menu_stylebox() {
+ // This must be called when the theme changes to follow the new accent color.
+ Ref<StyleBoxFlat> context_menu_stylebox = memnew(StyleBoxFlat);
+ const Color accent_color = EditorNode::get_singleton()->get_gui_base()->get_theme_color("accent_color", "Editor");
+ context_menu_stylebox->set_bg_color(accent_color * Color(1, 1, 1, 0.1));
+ // Add an underline to the StyleBox, but prevent its minimum vertical size from changing.
+ context_menu_stylebox->set_border_color(accent_color);
+ context_menu_stylebox->set_border_width(SIDE_BOTTOM, Math::round(2 * EDSCALE));
+ context_menu_stylebox->set_default_margin(SIDE_BOTTOM, 0);
+ context_menu_container->add_theme_style_override("panel", context_menu_stylebox);
+}
+
void CanvasItemEditor::_update_scrollbars() {
updating_scroll = true;
@@ -3986,7 +4003,7 @@ void CanvasItemEditor::_update_scrollbars() {
bool constrain_editor_view = bool(EditorSettings::get_singleton()->get("editors/2d/constrain_editor_view"));
if (canvas_item_rect.size.height <= (local_rect.size.y / zoom)) {
- float centered = -(size.y / 2) / zoom + screen_rect.y / 2;
+ real_t centered = -(size.y / 2) / zoom + screen_rect.y / 2;
if (constrain_editor_view && ABS(centered - previous_update_view_offset.y) < ABS(centered - view_offset.y)) {
view_offset.y = previous_update_view_offset.y;
}
@@ -4007,7 +4024,7 @@ void CanvasItemEditor::_update_scrollbars() {
}
if (canvas_item_rect.size.width <= (local_rect.size.x / zoom)) {
- float centered = -(size.x / 2) / zoom + screen_rect.x / 2;
+ real_t centered = -(size.x / 2) / zoom + screen_rect.x / 2;
if (constrain_editor_view && ABS(centered - previous_update_view_offset.x) < ABS(centered - view_offset.x)) {
view_offset.x = previous_update_view_offset.x;
}
@@ -4074,7 +4091,7 @@ void CanvasItemEditor::_popup_warning_temporarily(Control *p_control, const floa
info_overlay->set_offset(SIDE_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);
}
-void CanvasItemEditor::_update_scroll(float) {
+void CanvasItemEditor::_update_scroll(real_t) {
if (updating_scroll) {
return;
}
@@ -4168,14 +4185,14 @@ void CanvasItemEditor::_set_anchors_preset(Control::LayoutPreset p_preset) {
undo_redo->commit_action();
}
-void CanvasItemEditor::_zoom_on_position(float p_zoom, Point2 p_position) {
+void CanvasItemEditor::_zoom_on_position(real_t p_zoom, Point2 p_position) {
p_zoom = CLAMP(p_zoom, MIN_ZOOM, MAX_ZOOM);
if (p_zoom == zoom) {
return;
}
- float prev_zoom = zoom;
+ real_t prev_zoom = zoom;
zoom = p_zoom;
view_offset += p_position / prev_zoom - p_position / zoom;
@@ -4184,7 +4201,7 @@ void CanvasItemEditor::_zoom_on_position(float p_zoom, Point2 p_position) {
// in small details (texts, lines).
// This correction adds a jitter movement when zooming, so we correct only when the
// zoom factor is an integer. (in the other cases, all pixels won't be aligned anyway)
- float closest_zoom_factor = Math::round(zoom);
+ const real_t closest_zoom_factor = Math::round(zoom);
if (Math::is_zero_approx(zoom - closest_zoom_factor)) {
// make sure scene pixel at view_offset is aligned on a screen pixel
Vector2 view_offset_int = view_offset.floor();
@@ -4196,7 +4213,7 @@ void CanvasItemEditor::_zoom_on_position(float p_zoom, Point2 p_position) {
update_viewport();
}
-void CanvasItemEditor::_update_zoom(float p_zoom) {
+void CanvasItemEditor::_update_zoom(real_t p_zoom) {
_zoom_on_position(p_zoom, viewport_scrollable->get_size() / 2.0);
}
@@ -4881,8 +4898,8 @@ void CanvasItemEditor::_focus_selection(int p_op) {
} else { // VIEW_FRAME_TO_SELECTION
if (rect.size.x > CMP_EPSILON && rect.size.y > CMP_EPSILON) {
- float scale_x = viewport->get_size().x / rect.size.x;
- float scale_y = viewport->get_size().y / rect.size.y;
+ real_t scale_x = viewport->get_size().x / rect.size.x;
+ real_t scale_y = viewport->get_size().y / rect.size.y;
zoom = scale_x < scale_y ? scale_x : scale_y;
zoom *= 0.90;
viewport->update();
@@ -4947,7 +4964,7 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) {
if (state.has("zoom")) {
// Compensate the editor scale, so that the editor scale can be changed
// and the zoom level will still be the same (relative to the editor scale).
- zoom = float(p_state["zoom"]) * MAX(1, EDSCALE);
+ zoom = real_t(p_state["zoom"]) * MAX(1, EDSCALE);
zoom_widget->set_zoom(zoom);
}
@@ -5127,11 +5144,11 @@ void CanvasItemEditor::remove_control_from_info_overlay(Control *p_control) {
void CanvasItemEditor::add_control_to_menu_panel(Control *p_control) {
ERR_FAIL_COND(!p_control);
- hb->add_child(p_control);
+ hbc_context_menu->add_child(p_control);
}
void CanvasItemEditor::remove_control_from_menu_panel(Control *p_control) {
- hb->remove_child(p_control);
+ hbc_context_menu->remove_child(p_control);
}
HSplitContainer *CanvasItemEditor::get_palette_split() {
@@ -5516,10 +5533,21 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
p->add_separator();
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/preview_canvas_scale", TTR("Preview Canvas Scale"), KEY_MASK_SHIFT | KEY_MASK_CMD | KEY_P), PREVIEW_CANVAS_SCALE);
+ hb->add_child(memnew(VSeparator));
+
+ context_menu_container = memnew(PanelContainer);
+ hbc_context_menu = memnew(HBoxContainer);
+ context_menu_container->add_child(hbc_context_menu);
+ // Use a custom stylebox to make contextual menu items stand out from the rest.
+ // This helps with editor usability as contextual menu items change when selecting nodes,
+ // even though it may not be immediately obvious at first.
+ hb->add_child(context_menu_container);
+ _update_context_menu_stylebox();
+
presets_menu = memnew(MenuButton);
presets_menu->set_shortcut_context(this);
presets_menu->set_text(TTR("Layout"));
- hb->add_child(presets_menu);
+ hbc_context_menu->add_child(presets_menu);
presets_menu->hide();
presets_menu->set_switch_on_hover(true);
@@ -5533,17 +5561,18 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
anchor_mode_button = memnew(Button);
anchor_mode_button->set_flat(true);
- hb->add_child(anchor_mode_button);
+ hbc_context_menu->add_child(anchor_mode_button);
anchor_mode_button->set_toggle_mode(true);
anchor_mode_button->hide();
anchor_mode_button->connect("toggled", callable_mp(this, &CanvasItemEditor::_button_toggle_anchor_mode));
animation_hb = memnew(HBoxContainer);
- hb->add_child(animation_hb);
+ hbc_context_menu->add_child(animation_hb);
animation_hb->add_child(memnew(VSeparator));
animation_hb->hide();
key_loc_button = memnew(Button);
+ key_loc_button->set_flat(true);
key_loc_button->set_toggle_mode(true);
key_loc_button->set_pressed(true);
key_loc_button->set_focus_mode(FOCUS_NONE);
@@ -5552,6 +5581,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
animation_hb->add_child(key_loc_button);
key_rot_button = memnew(Button);
+ key_rot_button->set_flat(true);
key_rot_button->set_toggle_mode(true);
key_rot_button->set_pressed(true);
key_rot_button->set_focus_mode(FOCUS_NONE);
@@ -5560,6 +5590,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
animation_hb->add_child(key_rot_button);
key_scale_button = memnew(Button);
+ key_scale_button->set_flat(true);
key_scale_button->set_toggle_mode(true);
key_scale_button->set_focus_mode(FOCUS_NONE);
key_scale_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(ANIM_INSERT_SCALE));
@@ -5567,6 +5598,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
animation_hb->add_child(key_scale_button);
key_insert_button = memnew(Button);
+ key_insert_button->set_flat(true);
key_insert_button->set_focus_mode(FOCUS_NONE);
key_insert_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(ANIM_INSERT_KEY));
key_insert_button->set_tooltip(TTR("Insert keys (based on mask)."));
@@ -5733,11 +5765,14 @@ void CanvasItemEditorViewport::_create_preview(const Vector<String> &files) cons
preview_node->add_child(sprite);
label->show();
label_desc->show();
+ label_desc->set_text(TTR("Drag and drop to add as child of current scene's root node.\nHold Ctrl when dropping to add as child of selected node.\nHold Shift when dropping to add as sibling of selected node.\nHold Alt when dropping to add as a different node type."));
} else {
if (scene.is_valid()) {
Node *instance = scene->instantiate();
if (instance) {
preview_node->add_child(instance);
+ label_desc->show();
+ label_desc->set_text(TTR("Drag and drop to add as child of current scene's root node.\nHold Ctrl when dropping to add as child of selected node.\nHold Shift when dropping to add as sibling of selected node."));
}
}
}
@@ -6051,6 +6086,7 @@ bool CanvasItemEditorViewport::_only_packed_scenes_selected() const {
void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p_data) {
bool is_shift = Input::get_singleton()->is_key_pressed(KEY_SHIFT);
+ bool is_ctrl = Input::get_singleton()->is_key_pressed(KEY_CTRL);
bool is_alt = Input::get_singleton()->is_key_pressed(KEY_ALT);
selected_files.clear();
@@ -6062,24 +6098,25 @@ void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p
return;
}
- List<Node *> list = editor->get_editor_selection()->get_selected_node_list();
- if (list.size() == 0) {
- Node *root_node = editor->get_edited_scene();
+ List<Node *> selected_nodes = editor->get_editor_selection()->get_selected_node_list();
+ Node *root_node = editor->get_edited_scene();
+ if (selected_nodes.size() > 0) {
+ Node *selected_node = selected_nodes[0];
+ target_node = root_node;
+ if (is_ctrl) {
+ target_node = selected_node;
+ } else if (is_shift && selected_node != root_node) {
+ target_node = selected_node->get_parent();
+ }
+ } else {
if (root_node) {
- list.push_back(root_node);
+ target_node = root_node;
} else {
drop_pos = p_point;
target_node = nullptr;
}
}
- if (list.size() > 0) {
- target_node = list[0];
- if (is_shift && target_node != editor->get_edited_scene()) {
- target_node = target_node->get_parent();
- }
- }
-
drop_pos = p_point;
if (is_alt && !_only_packed_scenes_selected()) {
@@ -6160,7 +6197,6 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasIte
canvas_item_editor->get_controls_container()->add_child(label);
label_desc = memnew(Label);
- label_desc->set_text(TTR("Drag & drop + Shift : Add node as sibling\nDrag & drop + Alt : Change node type"));
label_desc->add_theme_color_override("font_color", Color(0.6f, 0.6f, 0.6f, 1));
label_desc->add_theme_color_override("font_shadow_color", Color(0.2f, 0.2f, 0.2f, 1));
label_desc->add_theme_constant_override("shadow_as_outline", 1 * EDSCALE);
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 7b64d0cb5d..1f59dfbc49 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -48,10 +48,10 @@ class CanvasItemEditorSelectedItem : public Object {
public:
Transform2D prev_xform;
- float prev_rot = 0;
+ real_t prev_rot = 0;
Rect2 prev_rect;
Vector2 prev_pivot;
- float prev_anchors[4] = { 0.0f };
+ real_t prev_anchors[4] = { (real_t)0.0 };
Transform2D pre_drag_xform;
Rect2 pre_drag_rect;
@@ -230,6 +230,10 @@ private:
HScrollBar *h_scroll;
VScrollBar *v_scroll;
HBoxContainer *hb;
+ // Used for secondary menu items which are displayed depending on the currently selected node
+ // (such as MeshInstance's "Mesh" menu).
+ PanelContainer *context_menu_container;
+ HBoxContainer *hbc_context_menu;
Map<Control *, Timer *> popup_temporarily_timers;
@@ -246,7 +250,7 @@ private:
bool show_edit_locks;
bool show_transformation_gizmos;
- float zoom;
+ real_t zoom;
Point2 view_offset;
Point2 previous_update_view_offset;
@@ -258,9 +262,9 @@ private:
int primary_grid_steps;
int grid_step_multiplier;
- float snap_rotation_step;
- float snap_rotation_offset;
- float snap_scale_step;
+ real_t snap_rotation_step;
+ real_t snap_rotation_offset;
+ real_t snap_scale_step;
bool smart_snap_active;
bool grid_snap_active;
@@ -288,7 +292,7 @@ private:
struct _SelectResult {
CanvasItem *item = nullptr;
- float z_index = 0;
+ real_t z_index = 0;
bool has_z = true;
_FORCE_INLINE_ bool operator<(const _SelectResult &p_rr) const {
return has_z && p_rr.has_z ? p_rr.z_index < z_index : p_rr.has_z;
@@ -305,7 +309,7 @@ private:
struct BoneList {
Transform2D xform;
- float length = 0.f;
+ real_t length = 0;
uint64_t last_pass = 0;
};
@@ -328,7 +332,7 @@ private:
struct PoseClipboard {
Vector2 pos;
Vector2 scale;
- float rot = 0;
+ real_t rot = 0;
ObjectID id;
};
List<PoseClipboard> pose_clipboard;
@@ -428,7 +432,7 @@ private:
void _popup_callback(int p_op);
bool updating_scroll;
- void _update_scroll(float);
+ void _update_scroll(real_t);
void _update_scrollbars();
void _append_canvas_item(CanvasItem *p_item);
void _snap_changed();
@@ -455,7 +459,7 @@ private:
void _draw_text_at_position(Point2 p_position, String p_string, Side p_side);
void _draw_margin_at_position(int p_value, Point2 p_position, Side p_side);
- void _draw_percentage_at_position(float p_value, Point2 p_position, Side p_side);
+ void _draw_percentage_at_position(real_t p_value, Point2 p_position, Side p_side);
void _draw_straight_line(Point2 p_from, Point2 p_to, Color p_color);
void _draw_smart_snapping();
@@ -497,16 +501,16 @@ private:
SnapTarget snap_target[2];
Transform2D snap_transform;
void _snap_if_closer_float(
- float p_value,
- float &r_current_snap, SnapTarget &r_current_snap_target,
- float p_target_value, SnapTarget p_snap_target,
- float p_radius = 10.0);
+ const real_t p_value,
+ real_t &r_current_snap, SnapTarget &r_current_snap_target,
+ const real_t p_target_value, const SnapTarget p_snap_target,
+ const real_t p_radius = 10.0);
void _snap_if_closer_point(
Point2 p_value,
Point2 &r_current_snap, SnapTarget (&r_current_snap_target)[2],
- Point2 p_target_value, SnapTarget p_snap_target,
- real_t rotation = 0.0,
- float p_radius = 10.0);
+ Point2 p_target_value, const SnapTarget p_snap_target,
+ const real_t rotation = 0.0,
+ const real_t p_radius = 10.0);
void _snap_other_nodes(
const Point2 p_value,
const Transform2D p_transform_to_snap,
@@ -523,8 +527,8 @@ private:
VBoxContainer *controls_vb;
EditorZoomWidget *zoom_widget;
- void _update_zoom(float p_zoom);
- void _zoom_on_position(float p_zoom, Point2 p_position = Point2());
+ void _update_zoom(real_t p_zoom);
+ void _zoom_on_position(real_t p_zoom, Point2 p_position = Point2());
void _button_toggle_smart_snap(bool p_status);
void _button_toggle_grid_snap(bool p_status);
void _button_override_camera(bool p_pressed);
@@ -535,6 +539,7 @@ private:
HSplitContainer *palette_split;
VSplitContainer *bottom_split;
+ void _update_context_menu_stylebox();
void _popup_warning_temporarily(Control *p_control, const float p_duration);
void _popup_warning_depop(Control *p_control);
@@ -552,28 +557,6 @@ protected:
HBoxContainer *get_panel_hb() { return hb; }
- struct compare_items_x {
- bool operator()(const CanvasItem *a, const CanvasItem *b) const {
- return a->get_global_transform().elements[2].x < b->get_global_transform().elements[2].x;
- }
- };
-
- struct compare_items_y {
- bool operator()(const CanvasItem *a, const CanvasItem *b) const {
- return a->get_global_transform().elements[2].y < b->get_global_transform().elements[2].y;
- }
- };
-
- struct proj_vector2_x {
- float get(const Vector2 &v) { return v.x; }
- void set(Vector2 &v, float f) { v.x = f; }
- };
-
- struct proj_vector2_y {
- float get(const Vector2 &v) { return v.y; }
- void set(Vector2 &v, float f) { v.y = f; }
- };
-
template <class P, class C>
void space_selected_items();
@@ -594,7 +577,7 @@ public:
};
Point2 snap_point(Point2 p_target, unsigned int p_modes = SNAP_DEFAULT, unsigned int p_forced_modes = 0, const CanvasItem *p_self_canvas_item = nullptr, List<CanvasItem *> p_other_nodes_exceptions = List<CanvasItem *>());
- float snap_angle(float p_target, float p_start = 0) const;
+ real_t snap_angle(real_t p_target, real_t p_start = 0) const;
Transform2D get_canvas_transform() const { return transform; }
diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp
index 81c340e9a4..d7618b973e 100644
--- a/editor/plugins/editor_preview_plugins.cpp
+++ b/editor/plugins/editor_preview_plugins.cpp
@@ -724,7 +724,7 @@ Ref<Texture2D> EditorMeshPreviewPlugin::generate(const RES &p_from, const Size2
xform.basis = Basis().rotated(Vector3(0, 1, 0), -Math_PI * 0.125);
xform.basis = Basis().rotated(Vector3(1, 0, 0), Math_PI * 0.125) * xform.basis;
AABB rot_aabb = xform.xform(aabb);
- float m = MAX(rot_aabb.size.x, rot_aabb.size.y) * 0.5;
+ real_t m = MAX(rot_aabb.size.x, rot_aabb.size.y) * 0.5;
if (m == 0) {
return Ref<Texture2D>();
}
diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp
index 2138f943da..46e15d97bf 100644
--- a/editor/plugins/node_3d_editor_gizmos.cpp
+++ b/editor/plugins/node_3d_editor_gizmos.cpp
@@ -320,7 +320,7 @@ void EditorNode3DGizmo::add_vertices(const Vector<Vector3> &p_vertices, const Re
instances.push_back(ins);
}
-void EditorNode3DGizmo::add_unscaled_billboard(const Ref<Material> &p_material, float p_scale, const Color &p_modulate) {
+void EditorNode3DGizmo::add_unscaled_billboard(const Ref<Material> &p_material, real_t p_scale, const Color &p_modulate) {
ERR_FAIL_COND(!spatial_node);
Instance ins;
diff --git a/editor/plugins/node_3d_editor_gizmos.h b/editor/plugins/node_3d_editor_gizmos.h
index 61ee3a95a9..f303a61607 100644
--- a/editor/plugins/node_3d_editor_gizmos.h
+++ b/editor/plugins/node_3d_editor_gizmos.h
@@ -84,7 +84,7 @@ public:
void add_mesh(const Ref<ArrayMesh> &p_mesh, const Ref<Material> &p_material = Ref<Material>(), const Transform3D &p_xform = Transform3D(), const Ref<SkinReference> &p_skin_reference = Ref<SkinReference>());
void add_collision_segments(const Vector<Vector3> &p_lines);
void add_collision_triangles(const Ref<TriangleMesh> &p_tmesh);
- void add_unscaled_billboard(const Ref<Material> &p_material, float p_scale = 1, const Color &p_modulate = Color(1, 1, 1));
+ void add_unscaled_billboard(const Ref<Material> &p_material, real_t p_scale = 1, const Color &p_modulate = Color(1, 1, 1));
void add_handles(const Vector<Vector3> &p_handles, const Ref<Material> &p_material, const Vector<int> &p_ids = Vector<int>(), bool p_billboard = false, bool p_secondary = false);
void add_solid_box(Ref<Material> &p_material, Vector3 p_size, Vector3 p_position = Vector3(), const Transform3D &p_xform = Transform3D());
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index ebd6615ac1..5f12294e22 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -107,8 +107,8 @@ void ViewportRotationControl::_notification(int p_what) {
}
void ViewportRotationControl::_draw() {
- Vector2i center = get_size() / 2.0;
- float radius = get_size().x / 2.0;
+ const Vector2i center = get_size() / 2.0;
+ const real_t radius = get_size().x / 2.0;
if (focused_axis > -2 || orbiting) {
draw_circle(center, radius, Color(0.5, 0.5, 0.5, 0.25));
@@ -149,15 +149,13 @@ void ViewportRotationControl::_draw_axis(const Axis2D &p_axis) {
}
void ViewportRotationControl::_get_sorted_axis(Vector<Axis2D> &r_axis) {
- Vector2i center = get_size() / 2.0;
- float radius = get_size().x / 2.0;
-
- float axis_radius = radius - AXIS_CIRCLE_RADIUS - 2.0 * EDSCALE;
- Basis camera_basis = viewport->to_camera_transform(viewport->cursor).get_basis().inverse();
+ const Vector2i center = get_size() / 2.0;
+ const real_t radius = get_size().x / 2.0 - AXIS_CIRCLE_RADIUS - 2.0 * EDSCALE;
+ const Basis camera_basis = viewport->to_camera_transform(viewport->cursor).get_basis().inverse();
for (int i = 0; i < 3; ++i) {
Vector3 axis_3d = camera_basis.get_axis(i);
- Vector2i axis_vector = Vector2(axis_3d.x, -axis_3d.y) * axis_radius;
+ Vector2i axis_vector = Vector2(axis_3d.x, -axis_3d.y) * radius;
if (Math::abs(axis_3d.z) < 1.0) {
Axis2D pos_axis;
@@ -259,7 +257,7 @@ void ViewportRotationControl::_bind_methods() {
ClassDB::bind_method(D_METHOD("_gui_input"), &ViewportRotationControl::_gui_input);
}
-void Node3DEditorViewport::_update_camera(float p_interp_delta) {
+void Node3DEditorViewport::_update_camera(real_t p_interp_delta) {
bool is_orthogonal = camera->get_projection() == Camera3D::PROJECTION_ORTHOGONAL;
Cursor old_camera_cursor = camera_cursor;
@@ -279,7 +277,7 @@ void Node3DEditorViewport::_update_camera(float p_interp_delta) {
// We interpolate a different point here, because in freelook mode the focus point (cursor.pos) orbits around eye_pos
camera_cursor.eye_pos = old_camera_cursor.eye_pos.lerp(cursor.eye_pos, CLAMP(factor, 0, 1));
- float orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia");
+ real_t orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia");
orbit_inertia = MAX(0.0001, orbit_inertia);
camera_cursor.x_rot = Math::lerp(old_camera_cursor.x_rot, cursor.x_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia)));
camera_cursor.y_rot = Math::lerp(old_camera_cursor.y_rot, cursor.y_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia)));
@@ -297,13 +295,13 @@ void Node3DEditorViewport::_update_camera(float p_interp_delta) {
} else {
//when not being manipulated, move softly
- float free_orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia");
- float free_translation_inertia = EDITOR_GET("editors/3d/navigation_feel/translation_inertia");
+ real_t free_orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia");
+ real_t free_translation_inertia = EDITOR_GET("editors/3d/navigation_feel/translation_inertia");
//when being manipulated, move more quickly
- float manip_orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/manipulation_orbit_inertia");
- float manip_translation_inertia = EDITOR_GET("editors/3d/navigation_feel/manipulation_translation_inertia");
+ real_t manip_orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/manipulation_orbit_inertia");
+ real_t manip_translation_inertia = EDITOR_GET("editors/3d/navigation_feel/manipulation_translation_inertia");
- float zoom_inertia = EDITOR_GET("editors/3d/navigation_feel/zoom_inertia");
+ real_t zoom_inertia = EDITOR_GET("editors/3d/navigation_feel/zoom_inertia");
//determine if being manipulated
bool manipulated = Input::get_singleton()->get_mouse_button_mask() & (2 | 4);
@@ -311,8 +309,8 @@ void Node3DEditorViewport::_update_camera(float p_interp_delta) {
manipulated |= Input::get_singleton()->is_key_pressed(KEY_ALT);
manipulated |= Input::get_singleton()->is_key_pressed(KEY_CTRL);
- float orbit_inertia = MAX(0.00001, manipulated ? manip_orbit_inertia : free_orbit_inertia);
- float translation_inertia = MAX(0.0001, manipulated ? manip_translation_inertia : free_translation_inertia);
+ real_t orbit_inertia = MAX(0.00001, manipulated ? manip_orbit_inertia : free_orbit_inertia);
+ real_t translation_inertia = MAX(0.0001, manipulated ? manip_translation_inertia : free_translation_inertia);
zoom_inertia = MAX(0.0001, zoom_inertia);
camera_cursor.x_rot = Math::lerp(old_camera_cursor.x_rot, cursor.x_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia)));
@@ -327,7 +325,7 @@ void Node3DEditorViewport::_update_camera(float p_interp_delta) {
}
camera_cursor.pos = old_camera_cursor.pos.lerp(cursor.pos, MIN(1.f, p_interp_delta * (1 / translation_inertia)));
- camera_cursor.distance = Math::lerp(old_camera_cursor.distance, cursor.distance, MIN(1.f, p_interp_delta * (1 / zoom_inertia)));
+ camera_cursor.distance = Math::lerp(old_camera_cursor.distance, cursor.distance, MIN((real_t)1.0, p_interp_delta * (1 / zoom_inertia)));
}
}
@@ -537,7 +535,7 @@ ObjectID Node3DEditorViewport::_select_ray(const Point2 &p_pos) {
continue;
}
- float dist = pos.distance_to(point);
+ const real_t dist = pos.distance_to(point);
if (dist < 0) {
continue;
@@ -601,7 +599,7 @@ void Node3DEditorViewport::_find_items_at_pos(const Point2 &p_pos, Vector<_RayRe
continue;
}
- float dist = pos.distance_to(point);
+ const real_t dist = pos.distance_to(point);
if (dist < 0) {
continue;
@@ -646,7 +644,7 @@ void Node3DEditorViewport::_select_region() {
return; //nothing really
}
- float z_offset = MAX(0.0, 5.0 - get_znear());
+ const real_t z_offset = MAX(0.0, 5.0 - get_znear());
Vector3 box[4] = {
Vector3(
@@ -912,20 +910,19 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b
Vector3 ray = _get_ray(Vector2(p_screenpos.x, p_screenpos.y));
Transform3D gt = spatial_editor->get_gizmo_transform();
- float gs = gizmo_scale;
if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE) {
int col_axis = -1;
- float col_d = 1e20;
+ real_t col_d = 1e20;
for (int i = 0; i < 3; i++) {
- Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gs * (GIZMO_ARROW_OFFSET + (GIZMO_ARROW_SIZE * 0.5));
- float grabber_radius = gs * GIZMO_ARROW_SIZE;
+ const Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gizmo_scale * (GIZMO_ARROW_OFFSET + (GIZMO_ARROW_SIZE * 0.5));
+ const real_t grabber_radius = gizmo_scale * GIZMO_ARROW_SIZE;
Vector3 r;
if (Geometry3D::segment_intersects_sphere(ray_pos, ray_pos + ray * MAX_Z, grabber_pos, grabber_radius, &r)) {
- float d = r.distance_to(ray_pos);
+ const real_t d = r.distance_to(ray_pos);
if (d < col_d) {
col_d = d;
col_axis = i;
@@ -944,17 +941,17 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b
// Allow some tolerance to make the plane easier to click,
// even if the click is actually slightly outside the plane.
- const Vector3 grabber_pos = gt.origin + (ivec2 + ivec3) * gs * (GIZMO_PLANE_SIZE + GIZMO_PLANE_DST * 0.6667);
+ const Vector3 grabber_pos = gt.origin + (ivec2 + ivec3) * gizmo_scale * (GIZMO_PLANE_SIZE + GIZMO_PLANE_DST * 0.6667);
Vector3 r;
Plane plane(gt.origin, gt.basis.get_axis(i).normalized());
if (plane.intersects_ray(ray_pos, ray, &r)) {
- float dist = r.distance_to(grabber_pos);
+ const real_t dist = r.distance_to(grabber_pos);
// Allow some tolerance to make the plane easier to click,
// even if the click is actually slightly outside the plane.
- if (dist < (gs * GIZMO_PLANE_SIZE * 1.5)) {
- float d = ray_pos.distance_to(r);
+ if (dist < (gizmo_scale * GIZMO_PLANE_SIZE * 1.5)) {
+ const real_t d = ray_pos.distance_to(r);
if (d < col_d) {
col_d = d;
col_axis = i;
@@ -991,12 +988,12 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b
continue;
}
- float dist = r.distance_to(gt.origin);
- Vector3 r_dir = (r - gt.origin).normalized();
+ const real_t dist = r.distance_to(gt.origin);
+ const Vector3 r_dir = (r - gt.origin).normalized();
if (_get_camera_normal().dot(r_dir) <= 0.005) {
- if (dist > gs * (GIZMO_CIRCLE_SIZE - GIZMO_RING_HALF_WIDTH) && dist < gs * (GIZMO_CIRCLE_SIZE + GIZMO_RING_HALF_WIDTH)) {
- float d = ray_pos.distance_to(r);
+ if (dist > gizmo_scale * (GIZMO_CIRCLE_SIZE - GIZMO_RING_HALF_WIDTH) && dist < gizmo_scale * (GIZMO_CIRCLE_SIZE + GIZMO_RING_HALF_WIDTH)) {
+ const real_t d = ray_pos.distance_to(r);
if (d < col_d) {
col_d = d;
col_axis = i;
@@ -1023,13 +1020,13 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b
float col_d = 1e20;
for (int i = 0; i < 3; i++) {
- Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gs * GIZMO_SCALE_OFFSET;
- float grabber_radius = gs * GIZMO_ARROW_SIZE;
+ const Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gizmo_scale * GIZMO_SCALE_OFFSET;
+ const real_t grabber_radius = gizmo_scale * GIZMO_ARROW_SIZE;
Vector3 r;
if (Geometry3D::segment_intersects_sphere(ray_pos, ray_pos + ray * MAX_Z, grabber_pos, grabber_radius, &r)) {
- float d = r.distance_to(ray_pos);
+ const real_t d = r.distance_to(ray_pos);
if (d < col_d) {
col_d = d;
col_axis = i;
@@ -1043,22 +1040,22 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b
col_d = 1e20;
for (int i = 0; i < 3; i++) {
- Vector3 ivec2 = gt.basis.get_axis((i + 1) % 3).normalized();
- Vector3 ivec3 = gt.basis.get_axis((i + 2) % 3).normalized();
+ const Vector3 ivec2 = gt.basis.get_axis((i + 1) % 3).normalized();
+ const Vector3 ivec3 = gt.basis.get_axis((i + 2) % 3).normalized();
// Allow some tolerance to make the plane easier to click,
// even if the click is actually slightly outside the plane.
- Vector3 grabber_pos = gt.origin + (ivec2 + ivec3) * gs * (GIZMO_PLANE_SIZE + GIZMO_PLANE_DST * 0.6667);
+ const Vector3 grabber_pos = gt.origin + (ivec2 + ivec3) * gizmo_scale * (GIZMO_PLANE_SIZE + GIZMO_PLANE_DST * 0.6667);
Vector3 r;
Plane plane(gt.origin, gt.basis.get_axis(i).normalized());
if (plane.intersects_ray(ray_pos, ray, &r)) {
- float dist = r.distance_to(grabber_pos);
+ const real_t dist = r.distance_to(grabber_pos);
// Allow some tolerance to make the plane easier to click,
// even if the click is actually slightly outside the plane.
- if (dist < (gs * GIZMO_PLANE_SIZE * 1.5)) {
- float d = ray_pos.distance_to(r);
+ if (dist < (gizmo_scale * GIZMO_PLANE_SIZE * 1.5)) {
+ const real_t d = ray_pos.distance_to(r);
if (d < col_d) {
col_d = d;
col_axis = i;
@@ -1293,7 +1290,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (b.is_valid()) {
emit_signal(SNAME("clicked"), this);
- float zoom_factor = 1 + (ZOOM_FREELOOK_MULTIPLIER - 1) * b->get_factor();
+ const real_t zoom_factor = 1 + (ZOOM_FREELOOK_MULTIPLIER - 1) * b->get_factor();
switch (b->get_button_index()) {
case MOUSE_BUTTON_WHEEL_UP: {
if (is_freelook_active()) {
@@ -1596,8 +1593,14 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
se->gizmo->commit_subgizmos(ids, restore, false);
spatial_editor->update_transform_gizmo();
} else {
- static const char *_transform_name[4] = { "None", "Rotate", "Translate", "Scale" };
- undo_redo->create_action(_transform_name[_edit.mode]);
+ static const char *_transform_name[4] = {
+ TTRC("None"),
+ TTRC("Rotate"),
+ // TRANSLATORS: This refers to the movement that changes the position of an object.
+ TTRC("Translate"),
+ TTRC("Scale"),
+ };
+ undo_redo->create_action(TTRGET(_transform_name[_edit.mode]));
List<Node *> &selection = editor_selection->get_selected_node_list();
@@ -1774,13 +1777,13 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
} else {
- float center_click_dist = click.distance_to(_edit.center);
- float center_inters_dist = intersection.distance_to(_edit.center);
+ const real_t center_click_dist = click.distance_to(_edit.center);
+ const real_t center_inters_dist = intersection.distance_to(_edit.center);
if (center_click_dist == 0) {
break;
}
- float scale = center_inters_dist - center_click_dist;
+ const real_t scale = center_inters_dist - center_click_dist;
motion = Vector3(scale, scale, scale);
}
@@ -2871,7 +2874,7 @@ void Node3DEditorViewport::_draw() {
if (surface->has_focus()) {
Size2 size = surface->get_size();
Rect2 r = Rect2(Point2(), size);
- get_theme_stylebox(SNAME("Focus"), SNAME("EditorStyles"))->draw(surface->get_canvas_item(), r);
+ get_theme_stylebox(SNAME("FocusViewport"), SNAME("EditorStyles"))->draw(surface->get_canvas_item(), r);
}
if (cursor.region_select) {
@@ -3521,18 +3524,15 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
return;
}
- Vector3 camz = -camera_xform.get_basis().get_axis(2).normalized();
- Vector3 camy = -camera_xform.get_basis().get_axis(1).normalized();
- Plane p(camera_xform.origin, camz);
- float gizmo_d = MAX(Math::abs(p.distance_to(xform.origin)), CMP_EPSILON);
- float d0 = camera->unproject_position(camera_xform.origin + camz * gizmo_d).y;
- float d1 = camera->unproject_position(camera_xform.origin + camz * gizmo_d + camy).y;
- float dd = Math::abs(d0 - d1);
- if (dd == 0) {
- dd = 0.0001;
- }
+ const Vector3 camz = -camera_xform.get_basis().get_axis(2).normalized();
+ const Vector3 camy = -camera_xform.get_basis().get_axis(1).normalized();
+ const Plane p(camera_xform.origin, camz);
+ const real_t gizmo_d = MAX(Math::abs(p.distance_to(xform.origin)), CMP_EPSILON);
+ const real_t d0 = camera->unproject_position(camera_xform.origin + camz * gizmo_d).y;
+ const real_t d1 = camera->unproject_position(camera_xform.origin + camz * gizmo_d + camy).y;
+ const real_t dd = MAX(Math::abs(d0 - d1), CMP_EPSILON);
- float gizmo_size = EditorSettings::get_singleton()->get("editors/3d/manipulator_gizmo_size");
+ const real_t gizmo_size = EditorSettings::get_singleton()->get("editors/3d/manipulator_gizmo_size");
// At low viewport heights, multiply the gizmo scale based on the viewport height.
// This prevents the gizmo from growing very large and going outside the viewport.
const int viewport_base_height = 400 * MAX(1, EDSCALE);
@@ -3788,7 +3788,7 @@ void Node3DEditorViewport::focus_selection() {
}
if (count != 0) {
- center /= float(count);
+ center /= count;
}
cursor.pos = center;
@@ -4066,6 +4066,7 @@ void Node3DEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p_
}
bool is_shift = Input::get_singleton()->is_key_pressed(KEY_SHIFT);
+ bool is_ctrl = Input::get_singleton()->is_key_pressed(KEY_CTRL);
selected_files.clear();
Dictionary d = p_data;
@@ -4073,29 +4074,32 @@ void Node3DEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p_
selected_files = d["files"];
}
- List<Node *> list = editor->get_editor_selection()->get_selected_node_list();
- if (list.size() == 0) {
- Node *root_node = editor->get_edited_scene();
+ List<Node *> selected_nodes = editor->get_editor_selection()->get_selected_node_list();
+ Node *root_node = editor->get_edited_scene();
+ if (selected_nodes.size() == 1) {
+ Node *selected_node = selected_nodes[0];
+ target_node = root_node;
+ if (is_ctrl) {
+ target_node = selected_node;
+ } else if (is_shift && selected_node != root_node) {
+ target_node = selected_node->get_parent();
+ }
+ } else if (selected_nodes.size() == 0) {
if (root_node) {
- list.push_back(root_node);
+ target_node = root_node;
} else {
- accept->set_text(TTR("No parent to instance a child at."));
+ accept->set_text(TTR("Cannot drag and drop into scene with no root node."));
accept->popup_centered();
_remove_preview();
return;
}
- }
- if (list.size() != 1) {
- accept->set_text(TTR("This operation requires a single selected node."));
+ } else {
+ accept->set_text(TTR("Cannot drag and drop into multiple selected nodes."));
accept->popup_centered();
_remove_preview();
return;
}
- target_node = list[0];
- if (is_shift && target_node != editor->get_edited_scene()) {
- target_node = target_node->get_parent();
- }
drop_pos = p_point;
_perform_drop_data();
@@ -4448,14 +4452,14 @@ void Node3DEditorViewportContainer::_gui_input(const Ref<InputEvent> &p_event) {
}
if (dragging_h) {
- float new_ratio = drag_begin_ratio.x + (mm->get_position().x - drag_begin_pos.x) / get_size().width;
+ real_t new_ratio = drag_begin_ratio.x + (mm->get_position().x - drag_begin_pos.x) / get_size().width;
new_ratio = CLAMP(new_ratio, 40 / get_size().width, (get_size().width - 40) / get_size().width);
ratio_h = new_ratio;
queue_sort();
update();
}
if (dragging_v) {
- float new_ratio = drag_begin_ratio.y + (mm->get_position().y - drag_begin_pos.y) / get_size().height;
+ real_t new_ratio = drag_begin_ratio.y + (mm->get_position().y - drag_begin_pos.y) / get_size().height;
new_ratio = CLAMP(new_ratio, 40 / get_size().height, (get_size().height - 40) / get_size().height);
ratio_v = new_ratio;
queue_sort();
@@ -5006,13 +5010,13 @@ void Node3DEditor::set_state(const Dictionary &p_state) {
}
if (d.has("zfar")) {
- settings_zfar->set_value(float(d["zfar"]));
+ settings_zfar->set_value(double(d["zfar"]));
}
if (d.has("znear")) {
- settings_znear->set_value(float(d["znear"]));
+ settings_znear->set_value(double(d["znear"]));
}
if (d.has("fov")) {
- settings_fov->set_value(float(d["fov"]));
+ settings_fov->set_value(double(d["fov"]));
}
if (d.has("show_grid")) {
bool use = d["show_grid"];
@@ -5968,6 +5972,18 @@ void fragment() {
_generate_selection_boxes();
}
+void Node3DEditor::_update_context_menu_stylebox() {
+ // This must be called when the theme changes to follow the new accent color.
+ Ref<StyleBoxFlat> context_menu_stylebox = memnew(StyleBoxFlat);
+ const Color accent_color = EditorNode::get_singleton()->get_gui_base()->get_theme_color("accent_color", "Editor");
+ context_menu_stylebox->set_bg_color(accent_color * Color(1, 1, 1, 0.1));
+ // Add an underline to the StyleBox, but prevent its minimum vertical size from changing.
+ context_menu_stylebox->set_border_color(accent_color);
+ context_menu_stylebox->set_border_width(SIDE_BOTTOM, Math::round(2 * EDSCALE));
+ context_menu_stylebox->set_default_margin(SIDE_BOTTOM, 0);
+ context_menu_container->add_theme_style_override("panel", context_menu_stylebox);
+}
+
void Node3DEditor::_update_gizmos_menu() {
gizmos_menu->clear();
@@ -6535,6 +6551,7 @@ void Node3DEditor::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED: {
_update_theme();
_update_gizmos_menu_theme();
+ _update_context_menu_stylebox();
sun_title->add_theme_font_override("font", get_theme_font(SNAME("title_font"), SNAME("Window")));
environ_title->add_theme_font_override("font", get_theme_font(SNAME("title_font"), SNAME("Window")));
} break;
@@ -6583,11 +6600,11 @@ Vector<int> Node3DEditor::get_subgizmo_selection() {
}
void Node3DEditor::add_control_to_menu_panel(Control *p_control) {
- hbc_menu->add_child(p_control);
+ hbc_context_menu->add_child(p_control);
}
void Node3DEditor::remove_control_from_menu_panel(Control *p_control) {
- hbc_menu->remove_child(p_control);
+ hbc_context_menu->remove_child(p_control);
}
void Node3DEditor::set_can_preview(Camera3D *p_preview) {
@@ -7170,7 +7187,20 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
view_menu->set_shortcut_context(this);
hbc_menu->add_child(view_menu);
+ hbc_menu->add_child(memnew(VSeparator));
+
+ context_menu_container = memnew(PanelContainer);
+ hbc_context_menu = memnew(HBoxContainer);
+ context_menu_container->add_child(hbc_context_menu);
+ // Use a custom stylebox to make contextual menu items stand out from the rest.
+ // This helps with editor usability as contextual menu items change when selecting nodes,
+ // even though it may not be immediately obvious at first.
+ hbc_menu->add_child(context_menu_container);
+ _update_context_menu_stylebox();
+
+ // Get the view menu popup and have it stay open when a checkable item is selected
p = view_menu->get_popup();
+ p->set_hide_on_checkable_item_selection(false);
accept = memnew(AcceptDialog);
editor->get_gui_base()->add_child(accept);
@@ -7589,8 +7619,8 @@ Vector3 Node3DEditor::snap_point(Vector3 p_target, Vector3 p_start) const {
return p_target;
}
-float Node3DEditor::get_translate_snap() const {
- float snap_value;
+double Node3DEditor::get_translate_snap() const {
+ double snap_value;
if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
snap_value = snap_translate->get_text().to_float() / 10.0;
} else {
@@ -7600,8 +7630,8 @@ float Node3DEditor::get_translate_snap() const {
return snap_value;
}
-float Node3DEditor::get_rotate_snap() const {
- float snap_value;
+double Node3DEditor::get_rotate_snap() const {
+ double snap_value;
if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
snap_value = snap_rotate->get_text().to_float() / 3.0;
} else {
@@ -7611,8 +7641,8 @@ float Node3DEditor::get_rotate_snap() const {
return snap_value;
}
-float Node3DEditor::get_scale_snap() const {
- float snap_value;
+double Node3DEditor::get_scale_snap() const {
+ double snap_value;
if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
snap_value = snap_scale->get_text().to_float() / 2.0;
} else {
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index 0c7a0d14a2..cb2edbcbc1 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -201,7 +201,7 @@ private:
bool orthogonal;
bool auto_orthogonal;
bool lock_rotation;
- float gizmo_scale;
+ real_t gizmo_scale;
bool freelook_active;
real_t freelook_speed;
@@ -221,7 +221,7 @@ private:
struct _RayResult {
Node3D *item = nullptr;
- float depth = 0;
+ real_t depth = 0;
_FORCE_INLINE_ bool operator<(const _RayResult &p_rr) const { return depth < p_rr.depth; }
};
@@ -306,7 +306,7 @@ private:
struct Cursor {
Vector3 pos;
- float x_rot, y_rot, distance;
+ real_t x_rot, y_rot, distance;
Vector3 eye_pos; // Used in freelook mode
bool region_select;
Point2 region_begin, region_end;
@@ -340,8 +340,7 @@ private:
void set_message(String p_message, float p_time = 5);
- //
- void _update_camera(float p_interp_delta);
+ void _update_camera(real_t p_interp_delta);
Transform3D to_camera_transform(const Cursor &p_cursor) const;
void _draw();
@@ -450,8 +449,8 @@ public:
private:
View view;
bool mouseover;
- float ratio_h;
- float ratio_v;
+ real_t ratio_h;
+ real_t ratio_v;
bool hovering_v;
bool hovering_h;
@@ -534,9 +533,9 @@ private:
Ref<Node3DGizmo> current_hover_gizmo;
int current_hover_gizmo_handle;
- float snap_translate_value;
- float snap_rotate_value;
- float snap_scale_value;
+ real_t snap_translate_value;
+ real_t snap_rotate_value;
+ real_t snap_scale_value;
Ref<ArrayMesh> selection_box_xray;
Ref<ArrayMesh> selection_box;
@@ -554,7 +553,7 @@ private:
struct Gizmo {
bool visible = false;
- float scale = 0;
+ real_t scale = 0;
Transform3D transform;
} gizmo;
@@ -625,6 +624,10 @@ private:
void _update_camera_override_viewport(Object *p_viewport);
HBoxContainer *hbc_menu;
+ // Used for secondary menu items which are displayed depending on the currently selected node
+ // (such as MeshInstance's "Mesh" menu).
+ PanelContainer *context_menu_container;
+ HBoxContainer *hbc_context_menu;
void _generate_selection_boxes();
UndoRedo *undo_redo;
@@ -632,6 +635,7 @@ private:
int camera_override_viewport_id;
void _init_indicators();
+ void _update_context_menu_stylebox();
void _update_gizmos_menu();
void _update_gizmos_menu_theme();
void _init_grid();
@@ -747,9 +751,9 @@ public:
ToolMode get_tool_mode() const { return tool_mode; }
bool are_local_coords_enabled() const { return tool_option_button[Node3DEditor::TOOL_OPT_LOCAL_COORDS]->is_pressed(); }
bool is_snap_enabled() const { return snap_enabled ^ snap_key_enabled; }
- float get_translate_snap() const;
- float get_rotate_snap() const;
- float get_scale_snap() const;
+ double get_translate_snap() const;
+ double get_rotate_snap() const;
+ double get_scale_snap() const;
Ref<ArrayMesh> get_move_gizmo(int idx) const { return move_gizmo[idx]; }
Ref<ArrayMesh> get_move_plane_gizmo(int idx) const { return move_plane_gizmo[idx]; }
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index b420372eff..9377395418 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -400,25 +400,25 @@ void Polygon2DEditor::_set_show_grid(bool p_show) {
uv_edit_draw->update();
}
-void Polygon2DEditor::_set_snap_off_x(float p_val) {
+void Polygon2DEditor::_set_snap_off_x(real_t p_val) {
snap_offset.x = p_val;
EditorSettings::get_singleton()->set_project_metadata("polygon_2d_uv_editor", "snap_offset", snap_offset);
uv_edit_draw->update();
}
-void Polygon2DEditor::_set_snap_off_y(float p_val) {
+void Polygon2DEditor::_set_snap_off_y(real_t p_val) {
snap_offset.y = p_val;
EditorSettings::get_singleton()->set_project_metadata("polygon_2d_uv_editor", "snap_offset", snap_offset);
uv_edit_draw->update();
}
-void Polygon2DEditor::_set_snap_step_x(float p_val) {
+void Polygon2DEditor::_set_snap_step_x(real_t p_val) {
snap_step.x = p_val;
EditorSettings::get_singleton()->set_project_metadata("polygon_2d_uv_editor", "snap_step", snap_step);
uv_edit_draw->update();
}
-void Polygon2DEditor::_set_snap_step_y(float p_val) {
+void Polygon2DEditor::_set_snap_step_y(real_t p_val) {
snap_step.y = p_val;
EditorSettings::get_singleton()->set_project_metadata("polygon_2d_uv_editor", "snap_step", snap_step);
uv_edit_draw->update();
@@ -569,11 +569,11 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
}
int closest = -1;
- float closest_dist = 1e20;
+ real_t closest_dist = 1e20;
for (int i = points_prev.size() - internal_vertices; i < points_prev.size(); i++) {
Vector2 tuv = mtx.xform(uv_create_poly_prev[i]);
- float dist = tuv.distance_to(Vector2(mb->get_position().x, mb->get_position().y));
+ real_t dist = tuv.distance_to(Vector2(mb->get_position().x, mb->get_position().y));
if (dist < 8 && dist < closest_dist) {
closest = i;
closest_dist = dist;
@@ -639,11 +639,11 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
if (uv_move_current == UV_MODE_ADD_POLYGON) {
int closest = -1;
- float closest_dist = 1e20;
+ real_t closest_dist = 1e20;
for (int i = 0; i < points_prev.size(); i++) {
Vector2 tuv = mtx.xform(points_prev[i]);
- float dist = tuv.distance_to(Vector2(mb->get_position().x, mb->get_position().y));
+ real_t dist = tuv.distance_to(Vector2(mb->get_position().x, mb->get_position().y));
if (dist < 8 && dist < closest_dist) {
closest = i;
closest_dist = dist;
@@ -825,7 +825,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
}
center /= uv_new.size();
- float angle = (uv_drag_from - mtx.xform(center)).normalized().angle_to((uv_drag_to - mtx.xform(center)).normalized());
+ real_t angle = (uv_drag_from - mtx.xform(center)).normalized().angle_to((uv_drag_to - mtx.xform(center)).normalized());
for (int i = 0; i < uv_new.size(); i++) {
Vector2 rel = points_prev[i] - center;
@@ -848,13 +848,13 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
}
center /= uv_new.size();
- float from_dist = uv_drag_from.distance_to(mtx.xform(center));
- float to_dist = uv_drag_to.distance_to(mtx.xform(center));
+ real_t from_dist = uv_drag_from.distance_to(mtx.xform(center));
+ real_t to_dist = uv_drag_to.distance_to(mtx.xform(center));
if (from_dist < 2) {
break;
}
- float scale = to_dist / from_dist;
+ real_t scale = to_dist / from_dist;
for (int i = 0; i < uv_new.size(); i++) {
Vector2 rel = points_prev[i] - center;
@@ -881,8 +881,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
{
int pc = painted_weights.size();
- float amount = bone_paint_strength->get_value();
- float radius = bone_paint_radius->get_value() * EDSCALE;
+ real_t amount = bone_paint_strength->get_value();
+ real_t radius = bone_paint_radius->get_value() * EDSCALE;
if (uv_mode == UV_MODE_CLEAR_WEIGHT) {
amount = -amount;
@@ -925,7 +925,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
}
}
-void Polygon2DEditor::_uv_scroll_changed(float) {
+void Polygon2DEditor::_uv_scroll_changed(real_t) {
if (updating_uv_scroll) {
return;
}
diff --git a/editor/plugins/polygon_2d_editor_plugin.h b/editor/plugins/polygon_2d_editor_plugin.h
index af3b2f5aef..cbe7ecf360 100644
--- a/editor/plugins/polygon_2d_editor_plugin.h
+++ b/editor/plugins/polygon_2d_editor_plugin.h
@@ -95,7 +95,7 @@ class Polygon2DEditor : public AbstractPolygon2DEditor {
void _update_bone_list();
Vector2 uv_draw_ofs;
- float uv_draw_zoom;
+ real_t uv_draw_zoom;
Vector<Vector2> points_prev;
Vector<Vector2> uv_create_uv_prev;
Vector<Vector2> uv_create_poly_prev;
@@ -127,17 +127,17 @@ class Polygon2DEditor : public AbstractPolygon2DEditor {
void _cancel_editing();
void _update_polygon_editing_state();
- void _uv_scroll_changed(float);
+ void _uv_scroll_changed(real_t);
void _uv_input(const Ref<InputEvent> &p_input);
void _uv_draw();
void _uv_mode(int p_mode);
void _set_use_snap(bool p_use);
void _set_show_grid(bool p_show);
- void _set_snap_off_x(float p_val);
- void _set_snap_off_y(float p_val);
- void _set_snap_step_x(float p_val);
- void _set_snap_step_y(float p_val);
+ void _set_snap_off_x(real_t p_val);
+ void _set_snap_off_y(real_t p_val);
+ void _set_snap_step_x(real_t p_val);
+ void _set_snap_step_y(real_t p_val);
void _uv_edit_mode_select(int p_mode);
void _uv_edit_popup_hide();
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 65459d159d..5bbe56a800 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -204,7 +204,13 @@ void ScriptTextEditor::_set_theme_for_script() {
for (const String &string : strings) {
String beg = string.get_slice(" ", 0);
String end = string.get_slice_count(" ") > 1 ? string.get_slice(" ", 1) : String();
- text_edit->add_string_delimiter(beg, end, end == "");
+ if (!text_edit->has_string_delimiter(beg)) {
+ text_edit->add_string_delimiter(beg, end, end == "");
+ }
+
+ if (!end.is_empty() && !text_edit->has_auto_brace_completion_open_key(beg)) {
+ text_edit->add_auto_brace_completion_pair(beg, end);
+ }
}
List<String> comments;
@@ -214,6 +220,10 @@ void ScriptTextEditor::_set_theme_for_script() {
String beg = comment.get_slice(" ", 0);
String end = comment.get_slice_count(" ") > 1 ? comment.get_slice(" ", 1) : String();
text_edit->add_comment_delimiter(beg, end, end == "");
+
+ if (!end.is_empty() && !text_edit->has_auto_brace_completion_open_key(beg)) {
+ text_edit->add_auto_brace_completion_pair(beg, end);
+ }
}
}
@@ -742,7 +752,7 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c
EditorNode::get_singleton()->load_resource(p_symbol);
}
- } else if (script->get_language()->lookup_code(code_editor->get_text_editor()->get_text_for_lookup_completion(), p_symbol, script->get_path(), base, result) == OK) {
+ } else if (script->get_language()->lookup_code(code_editor->get_text_editor()->get_text_for_symbol_lookup(), p_symbol, script->get_path(), base, result) == OK) {
_goto_line(p_row);
result.class_name = result.class_name.trim_prefix("_");
@@ -845,18 +855,17 @@ void ScriptTextEditor::_validate_symbol(const String &p_symbol) {
}
ScriptLanguage::LookupResult result;
- if (ScriptServer::is_global_class(p_symbol) || p_symbol.is_resource_file() || script->get_language()->lookup_code(code_editor->get_text_editor()->get_text_for_lookup_completion(), p_symbol, script->get_path(), base, result) == OK || (ProjectSettings::get_singleton()->has_autoload(p_symbol) && ProjectSettings::get_singleton()->get_autoload(p_symbol).is_singleton)) {
- text_edit->set_highlighted_word(p_symbol);
+ if (ScriptServer::is_global_class(p_symbol) || p_symbol.is_resource_file() || script->get_language()->lookup_code(code_editor->get_text_editor()->get_text_for_symbol_lookup(), p_symbol, script->get_path(), base, result) == OK || (ProjectSettings::get_singleton()->has_autoload(p_symbol) && ProjectSettings::get_singleton()->get_autoload(p_symbol).is_singleton)) {
+ text_edit->set_symbol_lookup_word_as_valid(true);
} else if (p_symbol.is_rel_path()) {
String path = _get_absolute_path(p_symbol);
if (FileAccess::exists(path)) {
- text_edit->set_highlighted_word(p_symbol);
+ text_edit->set_symbol_lookup_word_as_valid(true);
} else {
- text_edit->set_highlighted_word(String());
+ text_edit->set_symbol_lookup_word_as_valid(false);
}
-
} else {
- text_edit->set_highlighted_word(String());
+ text_edit->set_symbol_lookup_word_as_valid(false);
}
}
@@ -1544,7 +1553,7 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
base = _find_node_for_script(base, base, script);
}
ScriptLanguage::LookupResult result;
- if (script->get_language()->lookup_code(code_editor->get_text_editor()->get_text_for_lookup_completion(), word_at_pos, script->get_path(), base, result) == OK) {
+ if (script->get_language()->lookup_code(code_editor->get_text_editor()->get_text_for_symbol_lookup(), word_at_pos, script->get_path(), base, result) == OK) {
open_docs = true;
}
}
@@ -1829,7 +1838,7 @@ ScriptTextEditor::ScriptTextEditor() {
code_editor->get_text_editor()->set_code_hint_draw_below(EditorSettings::get_singleton()->get("text_editor/completion/put_callhint_tooltip_below_current_line"));
- code_editor->get_text_editor()->set_select_identifiers_on_hover(true);
+ code_editor->get_text_editor()->set_symbol_lookup_on_click_enabled(true);
code_editor->get_text_editor()->set_context_menu_enabled(false);
context_menu = memnew(PopupMenu);
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index 2c45b96106..95973f9dfd 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -158,6 +158,10 @@ void ShaderTextEditor::_load_theme_settings() {
text_editor->add_comment_delimiter("/*", "*/", false);
text_editor->add_comment_delimiter("//", "", true);
+ if (!text_editor->has_auto_brace_completion_open_key("/*")) {
+ text_editor->add_auto_brace_completion_pair("/*", "*/");
+ }
+
if (warnings_panel) {
// Warnings panel
warnings_panel->add_theme_font_override("normal_font", EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("main"), SNAME("EditorFonts")));
@@ -659,7 +663,7 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) {
shader_editor->get_text_editor()->set_code_hint_draw_below(EditorSettings::get_singleton()->get("text_editor/completion/put_callhint_tooltip_below_current_line"));
- shader_editor->get_text_editor()->set_select_identifiers_on_hover(true);
+ shader_editor->get_text_editor()->set_symbol_lookup_on_click_enabled(true);
shader_editor->get_text_editor()->set_context_menu_enabled(false);
shader_editor->get_text_editor()->connect("gui_input", callable_mp(this, &ShaderEditor::_text_edit_gui_input));
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index 6bcc65e30c..0929a629f8 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -3112,7 +3112,7 @@ void ThemeEditor::edit(const Ref<Theme> &p_theme) {
preview_tab->set_preview_theme(p_theme);
}
- theme_name->set_text(TTR("Theme") + ": " + theme->get_path().get_file());
+ theme_name->set_text(TTR("Theme:") + " " + theme->get_path().get_file());
}
Ref<Theme> ThemeEditor::get_edited_theme() {
@@ -3230,7 +3230,7 @@ ThemeEditor::ThemeEditor() {
add_child(top_menu);
theme_name = memnew(Label);
- theme_name->set_text(TTR("Theme") + ": ");
+ theme_name->set_text(TTR("Theme:"));
theme_name->set_theme_type_variation("HeaderSmall");
top_menu->add_child(theme_name);
diff --git a/editor/plugins/tiles/atlas_merging_dialog.cpp b/editor/plugins/tiles/atlas_merging_dialog.cpp
index bbafc7802b..d54906c98c 100644
--- a/editor/plugins/tiles/atlas_merging_dialog.cpp
+++ b/editor/plugins/tiles/atlas_merging_dialog.cpp
@@ -154,7 +154,7 @@ void AtlasMergingDialog::_merge_confirmed(String p_path) {
Ref<Texture2D> new_texture_resource = ResourceLoader::load(p_path, "Texture2D");
merged->set_texture(new_texture_resource);
- undo_redo->create_action("Merge TileSetAtlasSource");
+ undo_redo->create_action(TTR("Merge TileSetAtlasSource"));
int next_id = tile_set->get_next_source_id();
undo_redo->add_do_method(*tile_set, "add_source", merged, next_id);
undo_redo->add_undo_method(*tile_set, "remove_source", next_id);
diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp
index 84e40e2ffa..13f04cb804 100644
--- a/editor/plugins/tiles/tile_atlas_view.cpp
+++ b/editor/plugins/tiles/tile_atlas_view.cpp
@@ -32,6 +32,7 @@
#include "core/input/input.h"
#include "core/os/keyboard.h"
+#include "scene/2d/tile_map.h"
#include "scene/gui/box_container.h"
#include "scene/gui/label.h"
#include "scene/gui/panel.h"
@@ -259,7 +260,7 @@ void TileAtlasView::_draw_base_tiles() {
Vector2i offset_pos = (margins + (atlas_coords * texture_region_size) + tile_set_atlas_source->get_tile_texture_region(atlas_coords).size / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, 0));
// Draw the tile.
- TileSetPluginAtlasRendering::draw_tile(base_tiles_draw->get_canvas_item(), offset_pos, tile_set, source_id, atlas_coords, 0);
+ TileMap::draw_tile(base_tiles_draw->get_canvas_item(), offset_pos, tile_set, source_id, atlas_coords, 0);
}
}
}
@@ -375,7 +376,7 @@ void TileAtlasView::_draw_alternatives() {
}
// Draw the tile.
- TileSetPluginAtlasRendering::draw_tile(alternatives_draw->get_canvas_item(), offset_pos, tile_set, source_id, atlas_coords, alternative_id);
+ TileMap::draw_tile(alternatives_draw->get_canvas_item(), offset_pos, tile_set, source_id, atlas_coords, alternative_id);
// Increment the x position.
current_pos.x += transposed ? texture_region.size.y : texture_region.size.x;
diff --git a/editor/plugins/tiles/tile_data_editors.h b/editor/plugins/tiles/tile_data_editors.h
index 781f26cc02..99998dc779 100644
--- a/editor/plugins/tiles/tile_data_editors.h
+++ b/editor/plugins/tiles/tile_data_editors.h
@@ -36,10 +36,10 @@
#include "editor/editor_node.h"
#include "editor/editor_properties.h"
+#include "scene/2d/tile_map.h"
#include "scene/gui/box_container.h"
#include "scene/gui/control.h"
#include "scene/gui/label.h"
-#include "scene/resources/tile_set.h"
class TileDataEditor : public VBoxContainer {
GDCLASS(TileDataEditor, VBoxContainer);
diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp
index 4a4e81dae3..77084f551a 100644
--- a/editor/plugins/tiles/tile_map_editor.cpp
+++ b/editor/plugins/tiles/tile_map_editor.cpp
@@ -377,6 +377,11 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
return false;
}
+ if (tile_map_layer < 0) {
+ return false;
+ }
+ ERR_FAIL_INDEX_V(tile_map_layer, tile_map->get_layers_count(), false);
+
Ref<TileSet> tile_set = tile_map->get_tileset();
if (!tile_set.is_valid()) {
return false;
@@ -391,7 +396,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
coords_array.push_back(E->get());
}
- tile_map_clipboard = tile_map->get_pattern(coords_array);
+ tile_map_clipboard = tile_map->get_pattern(tile_map_layer, coords_array);
}
if (ED_IS_SHORTCUT("tiles_editor/cut", p_event)) {
@@ -399,8 +404,8 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
if (!tile_map_selection.is_empty()) {
undo_redo->create_action(TTR("Delete tiles"));
for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
- undo_redo->add_do_method(tile_map, "set_cell", E->get(), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
- undo_redo->add_undo_method(tile_map, "set_cell", E->get(), tile_map->get_cell_source_id(E->get()), tile_map->get_cell_atlas_coords(E->get()), tile_map->get_cell_alternative_tile(E->get()));
+ undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E->get(), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
+ undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E->get(), tile_map->get_cell_source_id(tile_map_layer, E->get()), tile_map->get_cell_atlas_coords(tile_map_layer, E->get()), tile_map->get_cell_alternative_tile(tile_map_layer, E->get()));
}
undo_redo->add_undo_method(this, "_set_tile_map_selection", _get_tile_map_selection());
tile_map_selection.clear();
@@ -430,8 +435,8 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
if (!tile_map_selection.is_empty()) {
undo_redo->create_action(TTR("Delete tiles"));
for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
- undo_redo->add_do_method(tile_map, "set_cell", E->get(), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
- undo_redo->add_undo_method(tile_map, "set_cell", E->get(), tile_map->get_cell_source_id(E->get()), tile_map->get_cell_atlas_coords(E->get()), tile_map->get_cell_alternative_tile(E->get()));
+ undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E->get(), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
+ undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E->get(), tile_map->get_cell_source_id(tile_map_layer, E->get()), tile_map->get_cell_atlas_coords(tile_map_layer, E->get()), tile_map->get_cell_alternative_tile(tile_map_layer, E->get()));
}
undo_redo->add_undo_method(this, "_set_tile_map_selection", _get_tile_map_selection());
tile_map_selection.clear();
@@ -456,9 +461,9 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
}
Vector2i coords = E->key();
if (!drag_modified.has(coords)) {
- drag_modified.insert(coords, tile_map->get_cell(coords));
+ drag_modified.insert(coords, tile_map->get_cell(tile_map_layer, coords));
}
- tile_map->set_cell(coords, E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ tile_map->set_cell(tile_map_layer, coords, E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
}
} break;
case DRAG_TYPE_BUCKET: {
@@ -472,9 +477,9 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
}
Vector2i coords = E->key();
if (!drag_modified.has(coords)) {
- drag_modified.insert(coords, tile_map->get_cell(coords));
+ drag_modified.insert(coords, tile_map->get_cell(tile_map_layer, coords));
}
- tile_map->set_cell(coords, E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ tile_map->set_cell(tile_map_layer, coords, E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
}
}
}
@@ -497,7 +502,9 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
// Pressed
- if (tool_buttons_group->get_pressed_button() == select_tool_button) {
+ if (drag_type == DRAG_TYPE_CLIPBOARD_PASTE) {
+ // Do nothing.
+ } else if (tool_buttons_group->get_pressed_button() == select_tool_button) {
drag_start_mouse_pos = mpos;
if (tile_map_selection.has(tile_map->world_to_map(drag_start_mouse_pos)) && !mb->is_shift_pressed()) {
// Move the selection
@@ -505,8 +512,8 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
drag_modified.clear();
for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
Vector2i coords = E->get();
- drag_modified.insert(coords, tile_map->get_cell(coords));
- tile_map->set_cell(coords, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
+ drag_modified.insert(coords, tile_map->get_cell(tile_map_layer, coords));
+ tile_map->set_cell(tile_map_layer, coords, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
}
} else {
// Select tiles
@@ -530,9 +537,9 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
}
Vector2i coords = E->key();
if (!drag_modified.has(coords)) {
- drag_modified.insert(coords, tile_map->get_cell(coords));
+ drag_modified.insert(coords, tile_map->get_cell(tile_map_layer, coords));
}
- tile_map->set_cell(coords, E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ tile_map->set_cell(tile_map_layer, coords, E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
}
} else if (tool_buttons_group->get_pressed_button() == line_tool_button) {
drag_type = DRAG_TYPE_LINE;
@@ -556,9 +563,9 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
}
Vector2i coords = E->key();
if (!drag_modified.has(coords)) {
- drag_modified.insert(coords, tile_map->get_cell(coords));
+ drag_modified.insert(coords, tile_map->get_cell(tile_map_layer, coords));
}
- tile_map->set_cell(coords, E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ tile_map->set_cell(tile_map_layer, coords, E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
}
}
}
@@ -587,6 +594,11 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
return;
}
+ if (tile_map_layer < 0) {
+ return;
+ }
+ ERR_FAIL_INDEX(tile_map_layer, tile_map->get_layers_count());
+
Ref<TileSet> tile_set = tile_map->get_tileset();
if (!tile_set.is_valid()) {
return;
@@ -623,7 +635,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
for (int x = rect.position.x; x < rect.get_end().x; x++) {
for (int y = rect.position.y; y < rect.get_end().y; y++) {
Vector2i coords = Vector2i(x, y);
- if (tile_map->get_cell_source_id(coords) != TileSet::INVALID_SOURCE) {
+ if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) {
Rect2 cell_region = xform.xform(Rect2(tile_map->map_to_world(coords) - tile_shape_size / 2, tile_shape_size));
tile_set->draw_tile_shape(p_overlay, cell_region, Color(1.0, 1.0, 1.0), false);
}
@@ -637,7 +649,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
for (int x = rect.position.x; x < rect.get_end().x; x++) {
for (int y = rect.position.y; y < rect.get_end().y; y++) {
Vector2i coords = Vector2i(x, y);
- if (tile_map->get_cell_source_id(coords) != TileSet::INVALID_SOURCE) {
+ if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) {
to_draw.insert(coords);
}
}
@@ -914,6 +926,8 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_rect(Vector2i p_start
TileMapPattern erase_pattern;
erase_pattern.set_cell(Vector2i(0, 0), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
TileMapPattern *pattern = erase_button->is_pressed() ? &erase_pattern : selection_pattern;
+ Map<Vector2i, TileMapCell> err_output;
+ ERR_FAIL_COND_V(pattern->is_empty(), err_output);
// Compute the offset to align things to the bottom or right.
bool aligned_right = p_end_cell.x < p_start_cell.x;
@@ -956,6 +970,12 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vector2i
return Map<Vector2i, TileMapCell>();
}
+ if (tile_map_layer < 0) {
+ return Map<Vector2i, TileMapCell>();
+ }
+ Map<Vector2i, TileMapCell> output;
+ ERR_FAIL_INDEX_V(tile_map_layer, tile_map->get_layers_count(), output);
+
Ref<TileSet> tile_set = tile_map->get_tileset();
if (!tile_set.is_valid()) {
return Map<Vector2i, TileMapCell>();
@@ -966,9 +986,8 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vector2i
erase_pattern.set_cell(Vector2i(0, 0), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
TileMapPattern *pattern = erase_button->is_pressed() ? &erase_pattern : selection_pattern;
- Map<Vector2i, TileMapCell> output;
if (!pattern->is_empty()) {
- TileMapCell source = tile_map->get_cell(p_coords);
+ TileMapCell source = tile_map->get_cell(tile_map_layer, p_coords);
// If we are filling empty tiles, compute the tilemap boundaries.
Rect2i boundaries;
@@ -985,9 +1004,9 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vector2i
Vector2i coords = to_check.back()->get();
to_check.pop_back();
if (!already_checked.has(coords)) {
- if (source.source_id == tile_map->get_cell_source_id(coords) &&
- source.get_atlas_coords() == tile_map->get_cell_atlas_coords(coords) &&
- source.alternative_tile == tile_map->get_cell_alternative_tile(coords) &&
+ if (source.source_id == tile_map->get_cell_source_id(tile_map_layer, coords) &&
+ source.get_atlas_coords() == tile_map->get_cell_atlas_coords(tile_map_layer, coords) &&
+ source.alternative_tile == tile_map->get_cell_alternative_tile(tile_map_layer, coords) &&
(source.source_id != TileSet::INVALID_SOURCE || boundaries.has_point(coords))) {
if (!erase_button->is_pressed() && random_tile_checkbox->is_pressed()) {
// Paint a random tile.
@@ -1027,13 +1046,13 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vector2i
}
}
} else {
- to_check = tile_map->get_used_cells();
+ to_check = tile_map->get_used_cells(tile_map_layer);
}
for (int i = 0; i < to_check.size(); i++) {
Vector2i coords = to_check[i];
- if (source.source_id == tile_map->get_cell_source_id(coords) &&
- source.get_atlas_coords() == tile_map->get_cell_atlas_coords(coords) &&
- source.alternative_tile == tile_map->get_cell_alternative_tile(coords) &&
+ if (source.source_id == tile_map->get_cell_source_id(tile_map_layer, coords) &&
+ source.get_atlas_coords() == tile_map->get_cell_atlas_coords(tile_map_layer, coords) &&
+ source.alternative_tile == tile_map->get_cell_alternative_tile(tile_map_layer, coords) &&
(source.source_id != TileSet::INVALID_SOURCE || boundaries.has_point(coords))) {
if (!erase_button->is_pressed() && random_tile_checkbox->is_pressed()) {
// Paint a random tile.
@@ -1066,6 +1085,11 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
return;
}
+ if (tile_map_layer < 0) {
+ return;
+ }
+ ERR_FAIL_INDEX(tile_map_layer, tile_map->get_layers_count());
+
Ref<TileSet> tile_set = tile_map->get_tileset();
if (!tile_set.is_valid()) {
return;
@@ -1091,7 +1115,7 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
tile_map_selection.erase(coords);
}
} else {
- if (tile_map->get_cell_source_id(coords) != TileSet::INVALID_SOURCE) {
+ if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) {
tile_map_selection.insert(coords);
}
}
@@ -1123,7 +1147,7 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
coords = tile_map->map_pattern(top_left, selection_used_cells[i], selection_pattern);
cells_undo[coords] = TileMapCell(drag_modified[coords].source_id, drag_modified[coords].get_atlas_coords(), drag_modified[coords].alternative_tile);
coords = tile_map->map_pattern(top_left + offset, selection_used_cells[i], selection_pattern);
- cells_undo[coords] = TileMapCell(tile_map->get_cell_source_id(coords), tile_map->get_cell_atlas_coords(coords), tile_map->get_cell_alternative_tile(coords));
+ cells_undo[coords] = TileMapCell(tile_map->get_cell_source_id(tile_map_layer, coords), tile_map->get_cell_atlas_coords(tile_map_layer, coords), tile_map->get_cell_alternative_tile(tile_map_layer, coords));
}
Map<Vector2i, TileMapCell> cells_do;
@@ -1138,10 +1162,10 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
undo_redo->create_action(TTR("Move tiles"));
// Move the tiles.
for (Map<Vector2i, TileMapCell>::Element *E = cells_do.front(); E; E = E->next()) {
- undo_redo->add_do_method(tile_map, "set_cell", E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
}
for (Map<Vector2i, TileMapCell>::Element *E = cells_undo.front(); E; E = E->next()) {
- undo_redo->add_undo_method(tile_map, "set_cell", E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
}
// Update the selection.
@@ -1162,12 +1186,12 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
for (int x = rect.position.x; x < rect.get_end().x; x++) {
for (int y = rect.position.y; y < rect.get_end().y; y++) {
Vector2i coords = Vector2i(x, y);
- if (tile_map->get_cell_source_id(coords) != TileSet::INVALID_SOURCE) {
+ if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) {
coords_array.push_back(coords);
}
}
}
- selection_pattern = tile_map->get_pattern(coords_array);
+ selection_pattern = tile_map->get_pattern(tile_map_layer, coords_array);
if (!selection_pattern->is_empty()) {
_update_tileset_selection_from_selection_pattern();
} else {
@@ -1178,8 +1202,8 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
case DRAG_TYPE_PAINT: {
undo_redo->create_action(TTR("Paint tiles"));
for (Map<Vector2i, TileMapCell>::Element *E = drag_modified.front(); E; E = E->next()) {
- undo_redo->add_do_method(tile_map, "set_cell", E->key(), tile_map->get_cell_source_id(E->key()), tile_map->get_cell_atlas_coords(E->key()), tile_map->get_cell_alternative_tile(E->key()));
- undo_redo->add_undo_method(tile_map, "set_cell", E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E->key(), tile_map->get_cell_source_id(tile_map_layer, E->key()), tile_map->get_cell_atlas_coords(tile_map_layer, E->key()), tile_map->get_cell_alternative_tile(tile_map_layer, E->key()));
+ undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
}
undo_redo->commit_action(false);
} break;
@@ -1190,8 +1214,8 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
if (!erase_button->is_pressed() && E->get().source_id == TileSet::INVALID_SOURCE) {
continue;
}
- undo_redo->add_do_method(tile_map, "set_cell", E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
- undo_redo->add_undo_method(tile_map, "set_cell", E->key(), tile_map->get_cell_source_id(E->key()), tile_map->get_cell_atlas_coords(E->key()), tile_map->get_cell_alternative_tile(E->key()));
+ undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E->key(), tile_map->get_cell_source_id(tile_map_layer, E->key()), tile_map->get_cell_atlas_coords(tile_map_layer, E->key()), tile_map->get_cell_alternative_tile(tile_map_layer, E->key()));
}
undo_redo->commit_action();
} break;
@@ -1202,16 +1226,16 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
if (!erase_button->is_pressed() && E->get().source_id == TileSet::INVALID_SOURCE) {
continue;
}
- undo_redo->add_do_method(tile_map, "set_cell", E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
- undo_redo->add_undo_method(tile_map, "set_cell", E->key(), tile_map->get_cell_source_id(E->key()), tile_map->get_cell_atlas_coords(E->key()), tile_map->get_cell_alternative_tile(E->key()));
+ undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E->key(), tile_map->get_cell_source_id(tile_map_layer, E->key()), tile_map->get_cell_atlas_coords(tile_map_layer, E->key()), tile_map->get_cell_alternative_tile(tile_map_layer, E->key()));
}
undo_redo->commit_action();
} break;
case DRAG_TYPE_BUCKET: {
undo_redo->create_action(TTR("Paint tiles"));
for (Map<Vector2i, TileMapCell>::Element *E = drag_modified.front(); E; E = E->next()) {
- undo_redo->add_do_method(tile_map, "set_cell", E->key(), tile_map->get_cell_source_id(E->key()), tile_map->get_cell_atlas_coords(E->key()), tile_map->get_cell_alternative_tile(E->key()));
- undo_redo->add_undo_method(tile_map, "set_cell", E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E->key(), tile_map->get_cell_source_id(tile_map_layer, E->key()), tile_map->get_cell_atlas_coords(tile_map_layer, E->key()), tile_map->get_cell_alternative_tile(tile_map_layer, E->key()));
+ undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
}
undo_redo->commit_action(false);
} break;
@@ -1221,8 +1245,8 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
TypedArray<Vector2i> used_cells = tile_map_clipboard->get_used_cells();
for (int i = 0; i < used_cells.size(); i++) {
Vector2i coords = tile_map->map_pattern(tile_map->world_to_map(mpos - mouse_offset), used_cells[i], tile_map_clipboard);
- undo_redo->add_do_method(tile_map, "set_cell", coords, tile_map_clipboard->get_cell_source_id(used_cells[i]), tile_map_clipboard->get_cell_atlas_coords(used_cells[i]), tile_map_clipboard->get_cell_alternative_tile(used_cells[i]));
- undo_redo->add_undo_method(tile_map, "set_cell", coords, tile_map->get_cell_source_id(coords), tile_map->get_cell_atlas_coords(coords), tile_map->get_cell_alternative_tile(coords));
+ undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, coords, tile_map_clipboard->get_cell_source_id(used_cells[i]), tile_map_clipboard->get_cell_atlas_coords(used_cells[i]), tile_map_clipboard->get_cell_alternative_tile(used_cells[i]));
+ undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, coords, tile_map->get_cell_source_id(tile_map_layer, coords), tile_map->get_cell_atlas_coords(tile_map_layer, coords), tile_map->get_cell_alternative_tile(tile_map_layer, coords));
}
undo_redo->commit_action();
} break;
@@ -1301,13 +1325,15 @@ void TileMapEditorTilesPlugin::_update_selection_pattern_from_tilemap_selection(
return;
}
+ ERR_FAIL_INDEX(tile_map_layer, tile_map->get_layers_count());
+
memdelete(selection_pattern);
TypedArray<Vector2i> coords_array;
for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
coords_array.push_back(E->get());
}
- selection_pattern = tile_map->get_pattern(coords_array);
+ selection_pattern = tile_map->get_pattern(tile_map_layer, coords_array);
}
void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_selection() {
@@ -1344,8 +1370,7 @@ void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_selection(
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
if (atlas_source) {
// Organize using coordinates.
- for (List<const TileMapCell *>::Element *E_cell = E_source->get().front(); E_cell; E_cell = E_cell->next()) {
- const TileMapCell *current = E_cell->get();
+ for (const TileMapCell *current : E_source->get()) {
if (current->alternative_tile == 0) {
organized_pattern[current->get_atlas_coords()] = current;
} else {
@@ -1364,8 +1389,8 @@ void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_selection(
}
} else {
// Add everything unorganized.
- for (List<const TileMapCell *>::Element *E_cell = E_source->get().front(); E_cell; E_cell = E_cell->next()) {
- unorganized.push_back(E_cell->get());
+ for (const TileMapCell *cell : E_source->get()) {
+ unorganized.push_back(cell);
}
}
@@ -1375,8 +1400,8 @@ void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_selection(
}
Vector2i organized_size = selection_pattern->get_size();
int unorganized_index = 0;
- for (List<const TileMapCell *>::Element *E_cell = unorganized.front(); E_cell; E_cell = E_cell->next()) {
- selection_pattern->set_cell(Vector2(organized_size.x + unorganized_index, vertical_offset), E_cell->get()->source_id, E_cell->get()->get_atlas_coords(), E_cell->get()->alternative_tile);
+ for (const TileMapCell *cell : unorganized) {
+ selection_pattern->set_cell(Vector2(organized_size.x + unorganized_index, vertical_offset), cell->source_id, cell->get_atlas_coords(), cell->alternative_tile);
unorganized_index++;
}
vertical_offset += MAX(organized_size.y, 1);
@@ -1711,13 +1736,19 @@ TypedArray<Vector2i> TileMapEditorTilesPlugin::_get_tile_map_selection() const {
return output;
}
-void TileMapEditorTilesPlugin::edit(ObjectID p_tile_map_id) {
- tile_map_id = p_tile_map_id;
+void TileMapEditorTilesPlugin::edit(ObjectID p_tile_map_id, int p_tile_map_layer) {
+ _stop_dragging(); // Avoids staying in a wrong drag state.
- // Clear the selection.
- tile_set_selection.clear();
- tile_map_selection.clear();
- selection_pattern->clear();
+ if (tile_map_id != p_tile_map_id) {
+ tile_map_id = p_tile_map_id;
+
+ // Clear the selection.
+ tile_set_selection.clear();
+ tile_map_selection.clear();
+ selection_pattern->clear();
+ }
+
+ tile_map_layer = p_tile_map_layer;
}
void TileMapEditorTilesPlugin::_bind_methods() {
@@ -1756,7 +1787,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
paint_tool_button->set_flat(true);
paint_tool_button->set_toggle_mode(true);
paint_tool_button->set_button_group(tool_buttons_group);
- paint_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/paint_tool", "Paint", KEY_E));
+ paint_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/paint_tool", "Paint", KEY_D));
paint_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(paint_tool_button);
@@ -2299,6 +2330,7 @@ Set<TileMapEditorTerrainsPlugin::Constraint> TileMapEditorTerrainsPlugin::_get_c
}
ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), Set<Constraint>());
+ ERR_FAIL_INDEX_V(tile_map_layer, tile_map->get_layers_count(), Set<Constraint>());
// Build a set of dummy constraints get the constrained points.
Set<Constraint> dummy_constraints;
@@ -2322,7 +2354,7 @@ Set<TileMapEditorTerrainsPlugin::Constraint> TileMapEditorTerrainsPlugin::_get_c
Map<Vector2i, TileSet::CellNeighbor> overlapping_terrain_bits = c.get_overlapping_coords_and_peering_bits();
for (Map<Vector2i, TileSet::CellNeighbor>::Element *E_overlapping = overlapping_terrain_bits.front(); E_overlapping; E_overlapping = E_overlapping->next()) {
if (!p_to_replace.has(E_overlapping->key())) {
- TileMapCell neighbor_cell = tile_map->get_cell(E_overlapping->key());
+ TileMapCell neighbor_cell = tile_map->get_cell(tile_map_layer, E_overlapping->key());
TileData *neighbor_tile_data = nullptr;
if (terrain_tiles.has(neighbor_cell) && terrain_tiles[neighbor_cell]->get_terrain_set() == p_terrain_set) {
neighbor_tile_data = terrain_tiles[neighbor_cell];
@@ -2629,6 +2661,90 @@ Map<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_terrains(const Map
return output;
}
+void TileMapEditorTerrainsPlugin::_stop_dragging() {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform();
+ Vector2 mpos = xform.affine_inverse().xform(CanvasItemEditor::get_singleton()->get_viewport_control()->get_local_mouse_position());
+
+ switch (drag_type) {
+ case DRAG_TYPE_PICK: {
+ Vector2i coords = tile_map->world_to_map(mpos);
+ TileMapCell tile = tile_map->get_cell(tile_map_layer, coords);
+
+ if (terrain_tiles.has(tile)) {
+ Array terrains_tile_pattern = _build_terrains_tile_pattern(terrain_tiles[tile]);
+
+ // Find the tree item for the right terrain set.
+ bool need_tree_item_switch = true;
+ TreeItem *tree_item = terrains_tree->get_selected();
+ if (tree_item) {
+ Dictionary metadata_dict = tree_item->get_metadata(0);
+ if (metadata_dict.has("terrain_set") && metadata_dict.has("terrain_id")) {
+ int terrain_set = metadata_dict["terrain_set"];
+ int terrain_id = metadata_dict["terrain_id"];
+ if (per_terrain_terrains_tile_patterns[terrain_set][terrain_id].has(terrains_tile_pattern)) {
+ need_tree_item_switch = false;
+ }
+ }
+ }
+
+ if (need_tree_item_switch) {
+ for (tree_item = terrains_tree->get_root()->get_first_child(); tree_item; tree_item = tree_item->get_next_visible()) {
+ Dictionary metadata_dict = tree_item->get_metadata(0);
+ if (metadata_dict.has("terrain_set") && metadata_dict.has("terrain_id")) {
+ int terrain_set = metadata_dict["terrain_set"];
+ int terrain_id = metadata_dict["terrain_id"];
+ if (per_terrain_terrains_tile_patterns[terrain_set][terrain_id].has(terrains_tile_pattern)) {
+ // Found
+ tree_item->select(0);
+ _update_tiles_list();
+ break;
+ }
+ }
+ }
+ }
+
+ // Find the list item for the given tile.
+ if (tree_item) {
+ for (int i = 0; i < terrains_tile_list->get_item_count(); i++) {
+ Dictionary metadata_dict = terrains_tile_list->get_item_metadata(i);
+ TerrainsTilePattern in_meta_terrains_tile_pattern = metadata_dict["terrains_tile_pattern"];
+ bool equals = true;
+ for (int j = 0; j < terrains_tile_pattern.size(); j++) {
+ if (terrains_tile_pattern[j] != in_meta_terrains_tile_pattern[j]) {
+ equals = false;
+ break;
+ }
+ }
+ if (equals) {
+ terrains_tile_list->select(i);
+ break;
+ }
+ }
+ } else {
+ ERR_PRINT("Terrain tile not found.");
+ }
+ }
+ picker_button->set_pressed(false);
+ } break;
+ case DRAG_TYPE_PAINT: {
+ undo_redo->create_action(TTR("Paint terrain"));
+ for (Map<Vector2i, TileMapCell>::Element *E = drag_modified.front(); E; E = E->next()) {
+ undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E->key(), tile_map->get_cell_source_id(tile_map_layer, E->key()), tile_map->get_cell_atlas_coords(tile_map_layer, E->key()), tile_map->get_cell_alternative_tile(tile_map_layer, E->key()));
+ undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ }
+ undo_redo->commit_action(false);
+ } break;
+ default:
+ break;
+ }
+ drag_type = DRAG_TYPE_NONE;
+}
+
bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
if (!is_visible_in_tree()) {
// If the bottom editor is not visible, we ignore inputs.
@@ -2649,6 +2765,11 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent>
return false;
}
+ if (tile_map_layer < 0) {
+ return false;
+ }
+ ERR_FAIL_COND_V(tile_map_layer >= tile_map->get_layers_count(), false);
+
// Get the selected terrain.
TerrainsTilePattern selected_terrains_tile_pattern;
int selected_terrain_set = -1;
@@ -2690,9 +2811,9 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent>
Map<Vector2i, TileMapCell> modified = _draw_terrains(to_draw, selected_terrain_set);
for (Map<Vector2i, TileMapCell>::Element *E = modified.front(); E; E = E->next()) {
if (!drag_modified.has(E->key())) {
- drag_modified[E->key()] = tile_map->get_cell(E->key());
+ drag_modified[E->key()] = tile_map->get_cell(tile_map_layer, E->key());
}
- tile_map->set_cell(E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ tile_map->set_cell(tile_map_layer, E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
}
}
} break;
@@ -2728,86 +2849,14 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent>
Map<Vector2i, TileMapCell> to_draw = _draw_terrains(terrains_to_draw, selected_terrain_set);
for (Map<Vector2i, TileMapCell>::Element *E = to_draw.front(); E; E = E->next()) {
- drag_modified[E->key()] = tile_map->get_cell(E->key());
- tile_map->set_cell(E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ drag_modified[E->key()] = tile_map->get_cell(tile_map_layer, E->key());
+ tile_map->set_cell(tile_map_layer, E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
}
}
}
} else {
// Released
- switch (drag_type) {
- case DRAG_TYPE_PICK: {
- Vector2i coords = tile_map->world_to_map(mpos);
- TileMapCell tile = tile_map->get_cell(coords);
-
- if (terrain_tiles.has(tile)) {
- Array terrains_tile_pattern = _build_terrains_tile_pattern(terrain_tiles[tile]);
-
- // Find the tree item for the right terrain set.
- bool need_tree_item_switch = true;
- TreeItem *tree_item = terrains_tree->get_selected();
- if (tree_item) {
- Dictionary metadata_dict = tree_item->get_metadata(0);
- if (metadata_dict.has("terrain_set") && metadata_dict.has("terrain_id")) {
- int terrain_set = metadata_dict["terrain_set"];
- int terrain_id = metadata_dict["terrain_id"];
- if (per_terrain_terrains_tile_patterns[terrain_set][terrain_id].has(terrains_tile_pattern)) {
- need_tree_item_switch = false;
- }
- }
- }
-
- if (need_tree_item_switch) {
- for (tree_item = terrains_tree->get_root()->get_first_child(); tree_item; tree_item = tree_item->get_next_visible()) {
- Dictionary metadata_dict = tree_item->get_metadata(0);
- if (metadata_dict.has("terrain_set") && metadata_dict.has("terrain_id")) {
- int terrain_set = metadata_dict["terrain_set"];
- int terrain_id = metadata_dict["terrain_id"];
- if (per_terrain_terrains_tile_patterns[terrain_set][terrain_id].has(terrains_tile_pattern)) {
- // Found
- tree_item->select(0);
- _update_tiles_list();
- break;
- }
- }
- }
- }
-
- // Find the list item for the given tile.
- if (tree_item) {
- for (int i = 0; i < terrains_tile_list->get_item_count(); i++) {
- Dictionary metadata_dict = terrains_tile_list->get_item_metadata(i);
- TerrainsTilePattern in_meta_terrains_tile_pattern = metadata_dict["terrains_tile_pattern"];
- bool equals = true;
- for (int j = 0; j < terrains_tile_pattern.size(); j++) {
- if (terrains_tile_pattern[j] != in_meta_terrains_tile_pattern[j]) {
- equals = false;
- break;
- }
- }
- if (equals) {
- terrains_tile_list->select(i);
- break;
- }
- }
- } else {
- ERR_PRINT("Terrain tile not found.");
- }
- }
- picker_button->set_pressed(false);
- } break;
- case DRAG_TYPE_PAINT: {
- undo_redo->create_action(TTR("Paint terrain"));
- for (Map<Vector2i, TileMapCell>::Element *E = drag_modified.front(); E; E = E->next()) {
- undo_redo->add_do_method(tile_map, "set_cell", E->key(), tile_map->get_cell_source_id(E->key()), tile_map->get_cell_atlas_coords(E->key()), tile_map->get_cell_alternative_tile(E->key()));
- undo_redo->add_undo_method(tile_map, "set_cell", E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
- }
- undo_redo->commit_action(false);
- } break;
- default:
- break;
- }
- drag_type = DRAG_TYPE_NONE;
+ _stop_dragging();
}
CanvasItemEditor::get_singleton()->update_viewport();
@@ -3080,8 +3129,12 @@ void TileMapEditorTerrainsPlugin::_update_tiles_list() {
}
}
-void TileMapEditorTerrainsPlugin::edit(ObjectID p_tile_map_id) {
+void TileMapEditorTerrainsPlugin::edit(ObjectID p_tile_map_id, int p_tile_map_layer) {
+ _stop_dragging(); // Avoids staying in a wrong drag state.
+
tile_map_id = p_tile_map_id;
+ tile_map_layer = p_tile_map_layer;
+
_update_terrains_cache();
_update_terrains_tree();
_update_tiles_list();
@@ -3166,10 +3219,12 @@ void TileMapEditor::_notification(int p_what) {
advanced_menu_button->set_icon(get_theme_icon(SNAME("Tools"), SNAME("EditorIcons")));
toggle_grid_button->set_icon(get_theme_icon(SNAME("Grid"), SNAME("EditorIcons")));
toggle_grid_button->set_pressed(EditorSettings::get_singleton()->get("editors/tiles_editor/display_grid"));
+ toogle_highlight_selected_layer_button->set_icon(get_theme_icon(SNAME("TileMapHighlightSelected"), SNAME("EditorIcons")));
break;
case NOTIFICATION_INTERNAL_PROCESS:
if (is_visible_in_tree() && tileset_changed_needs_update) {
_update_bottom_panel();
+ _update_layers_selection();
tile_map_editor_plugins[tabs->get_current_tab()]->tile_set_changed();
CanvasItemEditor::get_singleton()->update_viewport();
tileset_changed_needs_update = false;
@@ -3178,6 +3233,16 @@ void TileMapEditor::_notification(int p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED:
toggle_grid_button->set_pressed(EditorSettings::get_singleton()->get("editors/tiles_editor/display_grid"));
break;
+ case NOTIFICATION_VISIBILITY_CHANGED:
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (tile_map) {
+ if (is_visible_in_tree()) {
+ tile_map->set_selected_layer(tile_map_layer);
+ } else {
+ tile_map->set_selected_layer(-1);
+ }
+ }
+ break;
}
}
@@ -3185,6 +3250,63 @@ void TileMapEditor::_on_grid_toggled(bool p_pressed) {
EditorSettings::get_singleton()->set("editors/tiles_editor/display_grid", p_pressed);
}
+void TileMapEditor::_layers_selection_button_draw() {
+ if (!has_theme_icon(SNAME("arrow"), SNAME("OptionButton"))) {
+ return;
+ }
+
+ RID ci = layers_selection_button->get_canvas_item();
+ Ref<Texture2D> arrow = Control::get_theme_icon(SNAME("arrow"), SNAME("OptionButton"));
+
+ Color clr = Color(1, 1, 1);
+ if (get_theme_constant(SNAME("modulate_arrow"))) {
+ switch (layers_selection_button->get_draw_mode()) {
+ case BaseButton::DRAW_PRESSED:
+ clr = get_theme_color(SNAME("font_pressed_color"));
+ break;
+ case BaseButton::DRAW_HOVER:
+ clr = get_theme_color(SNAME("font_hover_color"));
+ break;
+ case BaseButton::DRAW_DISABLED:
+ clr = get_theme_color(SNAME("font_disabled_color"));
+ break;
+ default:
+ clr = get_theme_color(SNAME("font_color"));
+ }
+ }
+
+ Size2 size = layers_selection_button->get_size();
+
+ Point2 ofs;
+ if (is_layout_rtl()) {
+ ofs = Point2(get_theme_constant(SNAME("arrow_margin"), SNAME("OptionButton")), int(Math::abs((size.height - arrow->get_height()) / 2)));
+ } else {
+ ofs = Point2(size.width - arrow->get_width() - get_theme_constant(SNAME("arrow_margin"), SNAME("OptionButton")), int(Math::abs((size.height - arrow->get_height()) / 2)));
+ }
+ Rect2 dst_rect = Rect2(ofs, arrow->get_size());
+ if (!layers_selection_button->is_pressed()) {
+ dst_rect.size = -dst_rect.size;
+ }
+ arrow->draw_rect(ci, dst_rect, false, clr);
+}
+
+void TileMapEditor::_layers_selection_button_pressed() {
+ if (!layers_selection_popup->is_visible()) {
+ Size2 size = layers_selection_popup->get_contents_minimum_size();
+ size.x = MAX(size.x, layers_selection_button->get_size().x);
+ layers_selection_popup->set_position(layers_selection_button->get_screen_position() - Size2(0, size.y * get_global_transform().get_scale().y));
+ layers_selection_popup->set_size(size);
+ layers_selection_popup->popup();
+ } else {
+ layers_selection_popup->hide();
+ }
+}
+
+void TileMapEditor::_layers_selection_id_pressed(int p_id) {
+ tile_map_layer = p_id;
+ _update_layers_selection();
+}
+
void TileMapEditor::_advanced_menu_button_id_pressed(int p_id) {
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
if (!tile_map) {
@@ -3198,18 +3320,20 @@ void TileMapEditor::_advanced_menu_button_id_pressed(int p_id) {
if (p_id == 0) { // Replace Tile Proxies
undo_redo->create_action(TTR("Replace Tiles with Proxies"));
- TypedArray<Vector2i> used_cells = tile_map->get_used_cells();
- for (int i = 0; i < used_cells.size(); i++) {
- Vector2i cell_coords = used_cells[i];
- TileMapCell from = tile_map->get_cell(cell_coords);
- Array to_array = tile_set->map_tile_proxy(from.source_id, from.get_atlas_coords(), from.alternative_tile);
- TileMapCell to;
- to.source_id = to_array[0];
- to.set_atlas_coords(to_array[1]);
- to.alternative_tile = to_array[2];
- if (from != to) {
- undo_redo->add_do_method(tile_map, "set_cell", cell_coords, to.source_id, to.get_atlas_coords(), to.alternative_tile);
- undo_redo->add_undo_method(tile_map, "set_cell", cell_coords, from.source_id, from.get_atlas_coords(), from.alternative_tile);
+ for (int layer_index = 0; layer_index < tile_map->get_layers_count(); layer_index++) {
+ TypedArray<Vector2i> used_cells = tile_map->get_used_cells(layer_index);
+ for (int i = 0; i < used_cells.size(); i++) {
+ Vector2i cell_coords = used_cells[i];
+ TileMapCell from = tile_map->get_cell(layer_index, cell_coords);
+ Array to_array = tile_set->map_tile_proxy(from.source_id, from.get_atlas_coords(), from.alternative_tile);
+ TileMapCell to;
+ to.source_id = to_array[0];
+ to.set_atlas_coords(to_array[1]);
+ to.alternative_tile = to_array[2];
+ if (from != to) {
+ undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, cell_coords, to.source_id, to.get_atlas_coords(), to.alternative_tile);
+ undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, cell_coords, from.source_id, from.get_atlas_coords(), from.alternative_tile);
+ }
}
}
undo_redo->commit_action();
@@ -3315,7 +3439,7 @@ void TileMapEditor::_tile_map_changed() {
void TileMapEditor::_tab_changed(int p_tab_id) {
// Make the plugin edit the correct tilemap.
- tile_map_editor_plugins[tabs->get_current_tab()]->edit(tile_map_id);
+ tile_map_editor_plugins[tabs->get_current_tab()]->edit(tile_map_id, tile_map_layer);
// Update toolbar.
for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
@@ -3339,7 +3463,129 @@ void TileMapEditor::_tab_changed(int p_tab_id) {
CanvasItemEditor::get_singleton()->update_viewport();
}
+void TileMapEditor::_layers_select_next_or_previous(bool p_next) {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ if (tile_map->get_layers_count() < 1) {
+ return;
+ }
+
+ if (tile_map_layer < 0) {
+ tile_map_layer = 0;
+ }
+
+ int inc = p_next ? 1 : -1;
+ int origin_layer = tile_map_layer;
+ tile_map_layer = Math::posmod((tile_map_layer + inc), tile_map->get_layers_count());
+ while (tile_map_layer != origin_layer) {
+ if (tile_map->is_layer_enabled(tile_map_layer)) {
+ break;
+ }
+ tile_map_layer = Math::posmod((tile_map_layer + inc), tile_map->get_layers_count());
+ }
+
+ _update_layers_selection();
+}
+
+void TileMapEditor::_update_layers_selection() {
+ layers_selection_popup->clear();
+
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ // Update the selected layer.
+ if (is_visible_in_tree() && tile_map->get_layers_count() >= 1) {
+ tile_map_layer = CLAMP(tile_map_layer, 0, tile_map->get_layers_count() - 1);
+
+ // Search for an enabled layer if the current one is not.
+ int origin_layer = tile_map_layer;
+ while (tile_map_layer >= 0 && !tile_map->is_layer_enabled(tile_map_layer)) {
+ tile_map_layer--;
+ }
+ if (tile_map_layer < 0) {
+ tile_map_layer = origin_layer;
+ while (tile_map_layer < tile_map->get_layers_count() && !tile_map->is_layer_enabled(tile_map_layer)) {
+ tile_map_layer++;
+ }
+ }
+ if (tile_map_layer >= tile_map->get_layers_count()) {
+ tile_map_layer = -1;
+ }
+ } else {
+ tile_map_layer = -1;
+ }
+ tile_map->set_selected_layer(toogle_highlight_selected_layer_button->is_pressed() ? tile_map_layer : -1);
+
+ // Build the list of layers.
+ for (int i = 0; i < tile_map->get_layers_count(); i++) {
+ String name = tile_map->get_layer_name(i);
+ layers_selection_popup->add_item(name.is_empty() ? vformat(TTR("Layer #%d"), i) : name, i);
+ layers_selection_popup->set_item_as_radio_checkable(i, true);
+ layers_selection_popup->set_item_disabled(i, !tile_map->is_layer_enabled(i));
+ layers_selection_popup->set_item_checked(i, i == tile_map_layer);
+ }
+
+ // Update the button label.
+ if (tile_map_layer >= 0) {
+ layers_selection_button->set_text(layers_selection_popup->get_item_text(tile_map_layer));
+ } else {
+ layers_selection_button->set_text(TTR("Select a layer"));
+ }
+
+ // Set button minimum width.
+ Size2 min_button_size = Size2(layers_selection_popup->get_contents_minimum_size().x, 0);
+ if (has_theme_icon(SNAME("arrow"), SNAME("OptionButton"))) {
+ Ref<Texture2D> arrow = Control::get_theme_icon(SNAME("arrow"), SNAME("OptionButton"));
+ min_button_size.x += arrow->get_size().x;
+ }
+ layers_selection_button->set_custom_minimum_size(min_button_size);
+ layers_selection_button->update();
+
+ tile_map_editor_plugins[tabs->get_current_tab()]->edit(tile_map_id, tile_map_layer);
+}
+
+void TileMapEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) {
+ UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo);
+ ERR_FAIL_COND(!undo_redo);
+
+ TileMap *tile_map = Object::cast_to<TileMap>(p_edited);
+ if (tile_map) {
+ if (p_property == "layers_count") {
+ int new_layers_count = (int)p_new_value;
+ if (new_layers_count < tile_map->get_layers_count()) {
+ List<PropertyInfo> property_list;
+ tile_map->get_property_list(&property_list);
+
+ for (PropertyInfo property_info : property_list) {
+ Vector<String> components = String(property_info.name).split("/", true, 2);
+ if (components.size() == 2 && components[0].begins_with("layer_") && components[0].trim_prefix("layer_").is_valid_int()) {
+ int index = components[0].trim_prefix("layer_").to_int();
+ if (index >= new_layers_count) {
+ undo_redo->add_undo_property(tile_map, property_info.name, tile_map->get(property_info.name));
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
bool TileMapEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
+ if (ED_IS_SHORTCUT("tiles_editor/select_next_layer", p_event) && p_event->is_pressed()) {
+ _layers_select_next_or_previous(true);
+ return true;
+ }
+
+ if (ED_IS_SHORTCUT("tiles_editor/select_previous_layer", p_event) && p_event->is_pressed()) {
+ _layers_select_next_or_previous(false);
+ return true;
+ }
+
return tile_map_editor_plugins[tabs->get_current_tab()]->forward_canvas_gui_input(p_event);
}
@@ -3363,49 +3609,52 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
Vector2i tile_shape_size = tile_set->get_tile_size();
// Draw tiles with invalid IDs in the grid.
- TypedArray<Vector2i> used_cells = tile_map->get_used_cells();
- for (int i = 0; i < used_cells.size(); i++) {
- Vector2i coords = used_cells[i];
- int tile_source_id = tile_map->get_cell_source_id(coords);
- if (tile_source_id >= 0) {
- Vector2i tile_atlas_coords = tile_map->get_cell_atlas_coords(coords);
- int tile_alternative_tile = tile_map->get_cell_alternative_tile(coords);
-
- TileSetSource *source = nullptr;
- if (tile_set->has_source(tile_source_id)) {
- source = *tile_set->get_source(tile_source_id);
- }
-
- if (!source || !source->has_tile(tile_atlas_coords) || !source->has_alternative_tile(tile_atlas_coords, tile_alternative_tile)) {
- // Generate a random color from the hashed values of the tiles.
- Array a = tile_set->map_tile_proxy(tile_source_id, tile_atlas_coords, tile_alternative_tile);
- if (int(a[0]) == tile_source_id && Vector2i(a[1]) == tile_atlas_coords && int(a[2]) == tile_alternative_tile) {
- // Only display the pattern if we have no proxy tile.
- Array to_hash;
- to_hash.push_back(tile_source_id);
- to_hash.push_back(tile_atlas_coords);
- to_hash.push_back(tile_alternative_tile);
- uint32_t hash = RandomPCG(to_hash.hash()).rand();
-
- Color color;
- color = color.from_hsv(
- (float)((hash >> 24) & 0xFF) / 256.0,
- Math::lerp(0.5, 1.0, (float)((hash >> 16) & 0xFF) / 256.0),
- Math::lerp(0.5, 1.0, (float)((hash >> 8) & 0xFF) / 256.0),
- 0.8);
-
- // Draw the scaled tile.
- Rect2 cell_region = xform.xform(Rect2(tile_map->map_to_world(coords) - Vector2(tile_shape_size) / 2, Vector2(tile_shape_size)));
- tile_set->draw_tile_shape(p_overlay, cell_region, color, true, warning_pattern_texture);
+ if (tile_map_layer >= 0) {
+ ERR_FAIL_COND(tile_map_layer >= tile_map->get_layers_count());
+ TypedArray<Vector2i> used_cells = tile_map->get_used_cells(tile_map_layer);
+ for (int i = 0; i < used_cells.size(); i++) {
+ Vector2i coords = used_cells[i];
+ int tile_source_id = tile_map->get_cell_source_id(tile_map_layer, coords);
+ if (tile_source_id >= 0) {
+ Vector2i tile_atlas_coords = tile_map->get_cell_atlas_coords(tile_map_layer, coords);
+ int tile_alternative_tile = tile_map->get_cell_alternative_tile(tile_map_layer, coords);
+
+ TileSetSource *source = nullptr;
+ if (tile_set->has_source(tile_source_id)) {
+ source = *tile_set->get_source(tile_source_id);
}
- // Draw the warning icon.
- int min_axis = missing_tile_texture->get_size().min_axis();
- Vector2 icon_size;
- icon_size[min_axis] = tile_set->get_tile_size()[min_axis] / 3;
- icon_size[(min_axis + 1) % 2] = (icon_size[min_axis] * missing_tile_texture->get_size()[(min_axis + 1) % 2] / missing_tile_texture->get_size()[min_axis]);
- Rect2 rect = Rect2(xform.xform(tile_map->map_to_world(coords)) - (icon_size * xform.get_scale() / 2), icon_size * xform.get_scale());
- p_overlay->draw_texture_rect(missing_tile_texture, rect);
+ if (!source || !source->has_tile(tile_atlas_coords) || !source->has_alternative_tile(tile_atlas_coords, tile_alternative_tile)) {
+ // Generate a random color from the hashed values of the tiles.
+ Array a = tile_set->map_tile_proxy(tile_source_id, tile_atlas_coords, tile_alternative_tile);
+ if (int(a[0]) == tile_source_id && Vector2i(a[1]) == tile_atlas_coords && int(a[2]) == tile_alternative_tile) {
+ // Only display the pattern if we have no proxy tile.
+ Array to_hash;
+ to_hash.push_back(tile_source_id);
+ to_hash.push_back(tile_atlas_coords);
+ to_hash.push_back(tile_alternative_tile);
+ uint32_t hash = RandomPCG(to_hash.hash()).rand();
+
+ Color color;
+ color = color.from_hsv(
+ (float)((hash >> 24) & 0xFF) / 256.0,
+ Math::lerp(0.5, 1.0, (float)((hash >> 16) & 0xFF) / 256.0),
+ Math::lerp(0.5, 1.0, (float)((hash >> 8) & 0xFF) / 256.0),
+ 0.8);
+
+ // Draw the scaled tile.
+ Rect2 cell_region = xform.xform(Rect2(tile_map->map_to_world(coords) - Vector2(tile_shape_size) / 2, Vector2(tile_shape_size)));
+ tile_set->draw_tile_shape(p_overlay, cell_region, color, true, warning_pattern_texture);
+ }
+
+ // Draw the warning icon.
+ int min_axis = missing_tile_texture->get_size().min_axis();
+ Vector2 icon_size;
+ icon_size[min_axis] = tile_set->get_tile_size()[min_axis] / 3;
+ icon_size[(min_axis + 1) % 2] = (icon_size[min_axis] * missing_tile_texture->get_size()[(min_axis + 1) % 2] / missing_tile_texture->get_size()[min_axis]);
+ Rect2 rect = Rect2(xform.xform(tile_map->map_to_world(coords)) - (icon_size * xform.get_scale() / 2), icon_size * xform.get_scale());
+ p_overlay->draw_texture_rect(missing_tile_texture, rect);
+ }
}
}
}
@@ -3476,14 +3725,19 @@ void TileMapEditor::edit(TileMap *p_tile_map) {
return;
}
- // Disconnect to changes.
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
if (tile_map) {
+ // Unselect layer if we are changing tile_map.
+ if (tile_map != p_tile_map) {
+ tile_map->set_selected_layer(-1);
+ }
+
+ // Disconnect to changes.
tile_map->disconnect("changed", callable_mp(this, &TileMapEditor::_tile_map_changed));
}
- // Change the edited object.
if (p_tile_map) {
+ // Change the edited object.
tile_map_id = p_tile_map->get_instance_id();
tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
// Connect to changes.
@@ -3494,8 +3748,10 @@ void TileMapEditor::edit(TileMap *p_tile_map) {
tile_map_id = ObjectID();
}
+ _update_layers_selection();
+
// Call the plugins.
- tile_map_editor_plugins[tabs->get_current_tab()]->edit(tile_map_id);
+ tile_map_editor_plugins[tabs->get_current_tab()]->edit(tile_map_id, tile_map_layer);
_tile_map_changed();
}
@@ -3503,6 +3759,10 @@ void TileMapEditor::edit(TileMap *p_tile_map) {
TileMapEditor::TileMapEditor() {
set_process_internal(true);
+ // Shortcuts.
+ ED_SHORTCUT("tiles_editor/select_next_layer", TTR("Select Next Tile Map Layer"), KEY_PAGEUP);
+ ED_SHORTCUT("tiles_editor/select_previous_layer", TTR("Select Previous Tile Map Layer"), KEY_PAGEDOWN);
+
// TileMap editor plugins
tile_map_editor_plugins.push_back(memnew(TileMapEditorTilesPlugin));
tile_map_editor_plugins.push_back(memnew(TileMapEditorTerrainsPlugin));
@@ -3516,18 +3776,46 @@ TileMapEditor::TileMapEditor() {
tabs->connect("tab_changed", callable_mp(this, &TileMapEditor::_tab_changed));
// --- TileMap toolbar ---
- tilemap_toolbar = memnew(HBoxContainer);
- tilemap_toolbar->set_h_size_flags(SIZE_EXPAND_FILL);
- tilemap_toolbar->add_child(tabs);
+ tile_map_toolbar = memnew(HBoxContainer);
+ tile_map_toolbar->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ // Tabs.
+ tile_map_toolbar->add_child(tabs);
+
+ // Tabs toolbars.
for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
tile_map_editor_plugins[i]->get_toolbar()->hide();
- tilemap_toolbar->add_child(tile_map_editor_plugins[i]->get_toolbar());
+ tile_map_toolbar->add_child(tile_map_editor_plugins[i]->get_toolbar());
}
// Wide empty separation control.
Control *h_empty_space = memnew(Control);
h_empty_space->set_h_size_flags(SIZE_EXPAND_FILL);
- tilemap_toolbar->add_child(h_empty_space);
+ tile_map_toolbar->add_child(h_empty_space);
+
+ // Layer selector.
+ layers_selection_popup = memnew(PopupMenu);
+ layers_selection_popup->connect("id_pressed", callable_mp(this, &TileMapEditor::_layers_selection_id_pressed));
+ layers_selection_popup->set_close_on_parent_focus(false);
+
+ layers_selection_button = memnew(Button);
+ layers_selection_button->set_toggle_mode(true);
+ layers_selection_button->connect("draw", callable_mp(this, &TileMapEditor::_layers_selection_button_draw));
+ layers_selection_button->connect("pressed", callable_mp(this, &TileMapEditor::_layers_selection_button_pressed));
+ layers_selection_button->connect("hidden", callable_mp((Window *)layers_selection_popup, &Popup::hide));
+ layers_selection_button->set_tooltip(TTR("Tile Map Layer"));
+ layers_selection_button->add_child(layers_selection_popup);
+ tile_map_toolbar->add_child(layers_selection_button);
+
+ toogle_highlight_selected_layer_button = memnew(Button);
+ toogle_highlight_selected_layer_button->set_flat(true);
+ toogle_highlight_selected_layer_button->set_toggle_mode(true);
+ toogle_highlight_selected_layer_button->set_pressed(true);
+ toogle_highlight_selected_layer_button->connect("pressed", callable_mp(this, &TileMapEditor::_update_layers_selection));
+ toogle_highlight_selected_layer_button->set_tooltip(TTR("Highlight Selected TileMap Layer"));
+ tile_map_toolbar->add_child(toogle_highlight_selected_layer_button);
+
+ tile_map_toolbar->add_child(memnew(VSeparator));
// Grid toggle.
toggle_grid_button = memnew(Button);
@@ -3535,14 +3823,14 @@ TileMapEditor::TileMapEditor() {
toggle_grid_button->set_toggle_mode(true);
toggle_grid_button->set_tooltip(TTR("Toggle grid visibility."));
toggle_grid_button->connect("toggled", callable_mp(this, &TileMapEditor::_on_grid_toggled));
- tilemap_toolbar->add_child(toggle_grid_button);
+ tile_map_toolbar->add_child(toggle_grid_button);
// Advanced settings menu button.
advanced_menu_button = memnew(MenuButton);
advanced_menu_button->set_flat(true);
advanced_menu_button->get_popup()->add_item(TTR("Automatically Replace Tiles with Proxies"));
advanced_menu_button->get_popup()->connect("id_pressed", callable_mp(this, &TileMapEditor::_advanced_menu_button_id_pressed));
- tilemap_toolbar->add_child(advanced_menu_button);
+ tile_map_toolbar->add_child(advanced_menu_button);
missing_tileset_label = memnew(Label);
missing_tileset_label->set_text(TTR("The edited TileMap node has no TileSet resource."));
@@ -3561,6 +3849,9 @@ TileMapEditor::TileMapEditor() {
}
_tab_changed(0);
+
+ // Registers UndoRedo inspector callback.
+ EditorNode::get_singleton()->get_editor_data().add_undo_redo_inspector_hook_callback(callable_mp(this, &TileMapEditor::_undo_redo_inspector_callback));
}
TileMapEditor::~TileMapEditor() {
diff --git a/editor/plugins/tiles/tile_map_editor.h b/editor/plugins/tiles/tile_map_editor.h
index 236774a06b..6e2f2ce2ba 100644
--- a/editor/plugins/tiles/tile_map_editor.h
+++ b/editor/plugins/tiles/tile_map_editor.h
@@ -47,7 +47,7 @@ public:
virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return false; };
virtual void forward_canvas_draw_over_viewport(Control *p_overlay){};
virtual void tile_set_changed(){};
- virtual void edit(ObjectID p_tile_map_id){};
+ virtual void edit(ObjectID p_tile_map_id, int p_tile_map_layer){};
};
class TileMapEditorTilesPlugin : public TileMapEditorPlugin {
@@ -56,7 +56,8 @@ class TileMapEditorTilesPlugin : public TileMapEditorPlugin {
private:
UndoRedo *undo_redo = EditorNode::get_undo_redo();
ObjectID tile_map_id;
- virtual void edit(ObjectID p_tile_map_id) override;
+ int tile_map_layer = -1;
+ virtual void edit(ObjectID p_tile_map_id, int p_tile_map_layer) override;
///// Toolbar /////
HBoxContainer *toolbar;
@@ -185,7 +186,8 @@ class TileMapEditorTerrainsPlugin : public TileMapEditorPlugin {
private:
UndoRedo *undo_redo = EditorNode::get_undo_redo();
ObjectID tile_map_id;
- virtual void edit(ObjectID p_tile_map_id) override;
+ int tile_map_layer = -1;
+ virtual void edit(ObjectID p_tile_map_id, int p_tile_map_layer) override;
// Toolbar.
HBoxContainer *toolbar;
@@ -258,9 +260,9 @@ private:
Map<Vector2i, TerrainsTilePattern> _wave_function_collapse(const Set<Vector2i> &p_to_replace, int p_terrain_set, const Set<TileMapEditorTerrainsPlugin::Constraint> p_constraints) const;
TileMapCell _get_random_tile_from_pattern(int p_terrain_set, TerrainsTilePattern p_terrain_tile_pattern) const;
Map<Vector2i, TileMapCell> _draw_terrains(const Map<Vector2i, TerrainsTilePattern> &p_to_paint, int p_terrain_set) const;
+ void _stop_dragging();
// Cached data.
-
TerrainsTilePattern _build_terrains_tile_pattern(TileData *p_tile_data);
LocalVector<Map<TerrainsTilePattern, Set<TileMapCell>>> per_terrain_terrains_tile_patterns_tiles;
LocalVector<LocalVector<Set<TerrainsTilePattern>>> per_terrain_terrains_tile_patterns;
@@ -300,12 +302,20 @@ private:
UndoRedo *undo_redo = EditorNode::get_undo_redo();
bool tileset_changed_needs_update = false;
ObjectID tile_map_id;
+ int tile_map_layer = -1;
// Vector to keep plugins.
Vector<TileMapEditorPlugin *> tile_map_editor_plugins;
// Toolbar.
- HBoxContainer *tilemap_toolbar;
+ HBoxContainer *tile_map_toolbar;
+
+ PopupMenu *layers_selection_popup;
+ Button *layers_selection_button;
+ Button *toogle_highlight_selected_layer_button;
+ void _layers_selection_button_draw();
+ void _layers_selection_button_pressed();
+ void _layers_selection_id_pressed(int p_id);
Button *toggle_grid_button;
void _on_grid_toggled(bool p_pressed);
@@ -313,19 +323,26 @@ private:
MenuButton *advanced_menu_button;
void _advanced_menu_button_id_pressed(int p_id);
- // Bottom panel
+ // Bottom panel.
Label *missing_tileset_label;
Tabs *tabs;
void _update_bottom_panel();
- // TileMap
+ // TileMap.
Ref<Texture2D> missing_tile_texture;
Ref<Texture2D> warning_pattern_texture;
- // CallBack
+ // CallBack.
void _tile_map_changed();
void _tab_changed(int p_tab_changed);
+ // Updates.
+ void _layers_select_next_or_previous(bool p_next);
+ void _update_layers_selection();
+
+ // Inspector undo/redo callback.
+ void _undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value);
+
protected:
void _notification(int p_what);
void _draw_shape(Control *p_control, Rect2 p_region, TileSet::TileShape p_shape, TileSet::TileOffsetAxis p_offset_axis, Color p_color);
@@ -335,7 +352,7 @@ public:
void forward_canvas_draw_over_viewport(Control *p_overlay);
void edit(TileMap *p_tile_map);
- Control *get_toolbar() { return tilemap_toolbar; };
+ Control *get_toolbar() { return tile_map_toolbar; };
TileMapEditor();
~TileMapEditor();
diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp
index e5e7efa531..9e47a44b34 100644
--- a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp
+++ b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp
@@ -47,7 +47,7 @@ void TileProxiesManagerDialog::_menu_id_pressed(int p_id) {
}
void TileProxiesManagerDialog::_delete_selected_bindings() {
- undo_redo->create_action("Remove Tile Proxies");
+ undo_redo->create_action(TTR("Remove Tile Proxies"));
Vector<int> source_level_selected = source_level_list->get_selected_items();
for (int i = 0; i < source_level_selected.size(); i++) {
@@ -151,7 +151,7 @@ void TileProxiesManagerDialog::_add_button_pressed() {
Vector2i to_coords = to.get_atlas_coords();
if (from_coords.x >= 0 && from_coords.y >= 0 && to_coords.x >= 0 && to_coords.y >= 0) {
if (from.alternative_tile != TileSetSource::INVALID_TILE_ALTERNATIVE && to.alternative_tile != TileSetSource::INVALID_TILE_ALTERNATIVE) {
- undo_redo->create_action("Create Alternative-level Tile Proxy");
+ undo_redo->create_action(TTR("Create Alternative-level Tile Proxy"));
undo_redo->add_do_method(*tile_set, "set_alternative_level_tile_proxy", from.source_id, from.get_atlas_coords(), from.alternative_tile, to.source_id, to.get_atlas_coords(), to.alternative_tile);
if (tile_set->has_alternative_level_tile_proxy(from.source_id, from.get_atlas_coords(), from.alternative_tile)) {
Array a = tile_set->get_alternative_level_tile_proxy(from.source_id, from.get_atlas_coords(), from.alternative_tile);
@@ -160,7 +160,7 @@ void TileProxiesManagerDialog::_add_button_pressed() {
undo_redo->add_undo_method(*tile_set, "remove_alternative_level_tile_proxy", from.source_id, from.get_atlas_coords(), from.alternative_tile);
}
} else {
- undo_redo->create_action("Create Coords-level Tile Proxy");
+ undo_redo->create_action(TTR("Create Coords-level Tile Proxy"));
undo_redo->add_do_method(*tile_set, "set_coords_level_tile_proxy", from.source_id, from.get_atlas_coords(), to.source_id, to.get_atlas_coords());
if (tile_set->has_coords_level_tile_proxy(from.source_id, from.get_atlas_coords())) {
Array a = tile_set->get_coords_level_tile_proxy(from.source_id, from.get_atlas_coords());
@@ -170,7 +170,7 @@ void TileProxiesManagerDialog::_add_button_pressed() {
}
}
} else {
- undo_redo->create_action("Create source-level Tile Proxy");
+ undo_redo->create_action(TTR("Create source-level Tile Proxy"));
undo_redo->add_do_method(*tile_set, "set_source_level_tile_proxy", from.source_id, to.source_id);
if (tile_set->has_source_level_tile_proxy(from.source_id)) {
undo_redo->add_undo_method(*tile_set, "set_source_level_tile_proxy", to.source_id, tile_set->get_source_level_tile_proxy(from.source_id));
@@ -186,7 +186,7 @@ void TileProxiesManagerDialog::_add_button_pressed() {
}
void TileProxiesManagerDialog::_clear_invalid_button_pressed() {
- undo_redo->create_action("Delete All Invalid Tile Proxies");
+ undo_redo->create_action(TTR("Delete All Invalid Tile Proxies"));
undo_redo->add_do_method(*tile_set, "cleanup_invalid_tile_proxies");
@@ -213,7 +213,7 @@ void TileProxiesManagerDialog::_clear_invalid_button_pressed() {
}
void TileProxiesManagerDialog::_clear_all_button_pressed() {
- undo_redo->create_action("Delete All Tile Proxies");
+ undo_redo->create_action(TTR("Delete All Tile Proxies"));
undo_redo->add_do_method(*tile_set, "clear_tile_proxies");
diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.h b/editor/plugins/tiles/tile_proxies_manager_dialog.h
index f6898e960b..6849be2cd6 100644
--- a/editor/plugins/tiles/tile_proxies_manager_dialog.h
+++ b/editor/plugins/tiles/tile_proxies_manager_dialog.h
@@ -34,9 +34,9 @@
#include "editor/editor_node.h"
#include "editor/editor_properties.h"
+#include "scene/2d/tile_map.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/item_list.h"
-#include "scene/resources/tile_set.h"
class TileProxiesManagerDialog : public ConfirmationDialog {
GDCLASS(TileProxiesManagerDialog, ConfirmationDialog);
diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp
index 5804f54649..a9a36427db 100644
--- a/editor/plugins/version_control_editor_plugin.cpp
+++ b/editor/plugins/version_control_editor_plugin.cpp
@@ -31,6 +31,7 @@
#include "version_control_editor_plugin.h"
#include "core/object/script_language.h"
+#include "core/os/keyboard.h"
#include "editor/editor_file_system.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
@@ -292,6 +293,29 @@ void VersionControlEditorPlugin::_update_commit_button() {
commit_button->set_disabled(commit_message->get_text().strip_edges() == "");
}
+void VersionControlEditorPlugin::_commit_message_gui_input(const Ref<InputEvent> &p_event) {
+ if (!commit_message->has_focus()) {
+ return;
+ }
+ if (commit_message->get_text().strip_edges().is_empty()) {
+ // Do not allow empty commit messages.
+ return;
+ }
+ const Ref<InputEventKey> k = p_event;
+
+ if (k.is_valid() && k->is_pressed()) {
+ if (ED_IS_SHORTCUT("version_control/commit", p_event)) {
+ if (staged_files_count == 0) {
+ // Stage all files only when no files were previously staged.
+ _stage_all();
+ }
+ _send_commit_msg();
+ commit_message->accept_event();
+ return;
+ }
+ }
+}
+
void VersionControlEditorPlugin::register_editor() {
if (!EditorVCSInterface::get_singleton()) {
EditorNode::get_singleton()->add_control_to_dock(EditorNode::DOCK_SLOT_RIGHT_UL, version_commit_dock);
@@ -462,7 +486,9 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
commit_message->set_custom_minimum_size(Size2(200, 100));
commit_message->set_wrap_enabled(true);
commit_message->connect("text_changed", callable_mp(this, &VersionControlEditorPlugin::_update_commit_button));
+ commit_message->connect("gui_input", callable_mp(this, &VersionControlEditorPlugin::_commit_message_gui_input));
commit_box_vbc->add_child(commit_message);
+ ED_SHORTCUT("version_control/commit", TTR("Commit"), KEY_MASK_CMD | KEY_ENTER);
commit_button = memnew(Button);
commit_button->set_text(TTR("Commit Changes"));
diff --git a/editor/plugins/version_control_editor_plugin.h b/editor/plugins/version_control_editor_plugin.h
index 7d7c66a7ee..d2ba63c86c 100644
--- a/editor/plugins/version_control_editor_plugin.h
+++ b/editor/plugins/version_control_editor_plugin.h
@@ -111,6 +111,7 @@ private:
void _update_stage_status();
void _update_commit_status();
void _update_commit_button();
+ void _commit_message_gui_input(const Ref<InputEvent> &p_event);
friend class EditorVCSInterface;
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 46818afe45..452ad126b3 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -35,7 +35,6 @@
#include "core/io/resource_loader.h"
#include "core/math/math_defs.h"
#include "core/os/keyboard.h"
-#include "core/version.h"
#include "editor/editor_log.h"
#include "editor/editor_properties.h"
#include "editor/editor_scale.h"
@@ -921,6 +920,10 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
expression_box->add_comment_delimiter("/*", "*/", false);
expression_box->add_comment_delimiter("//", "", true);
+ if (!expression_box->has_auto_brace_completion_open_key("/*")) {
+ expression_box->add_auto_brace_completion_pair("/*", "*/");
+ }
+
expression_box->set_text(expression);
expression_box->set_context_menu_enabled(false);
expression_box->set_draw_line_numbers(true);
@@ -995,9 +998,23 @@ void VisualShaderEditor::edit(VisualShader *p_visual_shader) {
visual_shader->connect("changed", callable_mp(this, &VisualShaderEditor::_update_preview));
}
#ifndef DISABLE_DEPRECATED
- String version = VERSION_BRANCH;
- if (visual_shader->get_version() != version) {
- visual_shader->update_version(version);
+ Dictionary engine_version = Engine::get_singleton()->get_version_info();
+ static Array components;
+ if (components.is_empty()) {
+ components.push_back("major");
+ components.push_back("minor");
+ }
+ const Dictionary vs_version = visual_shader->get_engine_version();
+ if (!vs_version.has_all(components)) {
+ visual_shader->update_engine_version(engine_version);
+ } else {
+ for (int i = 0; i < components.size(); i++) {
+ if (vs_version[components[i]] != engine_version[components[i]]) {
+ visual_shader->update_engine_version(engine_version);
+ print_line(vformat(TTR("The shader (\"%s\") has been updated to correspond Godot %s.%s version."), visual_shader->get_path(), engine_version["major"], engine_version["minor"]));
+ break;
+ }
+ }
}
#endif
visual_shader->set_graph_offset(graph->get_scroll_ofs() / EDSCALE);
@@ -4143,6 +4160,8 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("OutputIsSRGB", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "output_is_srgb"), "output_is_srgb", VisualShaderNode::PORT_TYPE_BOOLEAN, -1, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Projection", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "projection"), "projection", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Time", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("UV", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "uv"), "uv", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("UV2", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "uv2"), "uv2", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("ViewportSize", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "viewport_size"), "viewport_size", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("World", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "world"), "world", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL));
@@ -4175,8 +4194,6 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Input", "Input", "Common", "VisualShaderNodeInput", TTR("Input parameter.")));
- // SPATIAL INPUTS
-
const String input_param_for_vertex_and_fragment_shader_modes = TTR("'%s' input parameter for vertex and fragment shader modes.");
const String input_param_for_fragment_and_light_shader_modes = TTR("'%s' input parameter for fragment and light shader modes.");
const String input_param_for_fragment_shader_mode = TTR("'%s' input parameter for fragment shader mode.");
@@ -4190,6 +4207,19 @@ VisualShaderEditor::VisualShaderEditor() {
const String input_param_for_process_and_collide_shader_mode = TTR("'%s' input parameter for process and collide shader modes.");
const String input_param_for_vertex_and_fragment_shader_mode = TTR("'%s' input parameter for vertex and fragment shader modes.");
+ // NODE3D INPUTS
+
+ add_options.push_back(AddOption("Alpha", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Binormal", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal"), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Color", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("InstanceId", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_id"), "instance_id", VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("InstanceCustom", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_custom"), "instance_custom", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("InstanceCustomAlpha", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_custom_alpha"), "instance_custom_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("ModelView", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "modelview"), "modelview", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("PointSize", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "point_size"), "point_size", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Tangent", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_mode, "tangent"), "tangent", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+
add_options.push_back(AddOption("Alpha", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Binormal", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal"), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
@@ -4199,15 +4229,13 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("PointCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "point_coord"), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("ScreenTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_texture"), "screen_texture", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("ScreenUV", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Side", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "side"), "side", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Tangent", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "tangent"), "tangent", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("UV", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "uv"), "uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("UV2", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "uv2"), "uv2", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Vertex", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("View", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "view"), "view", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Albedo", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "albedo"), "albedo", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Attenuation", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "attenuation"), "attenuation", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Backlight", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "backlight"), "backlight", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Diffuse", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "diffuse"), "diffuse", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("FragCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Light", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light"), "light", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
@@ -4215,21 +4243,19 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Metallic", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "metallic"), "metallic", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Roughness", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "roughness"), "roughness", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Specular", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "specular"), "specular", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Backlight", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "backlight"), "backlight", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("View", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "view"), "view", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Alpha", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Binormal", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal"), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Color", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("ModelView", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "modelview"), "modelview", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("PointSize", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "point_size"), "point_size", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Tangent", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_mode, "tangent"), "tangent", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("UV", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "uv"), "uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("UV2", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "uv2"), "uv2", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
-
// CANVASITEM INPUTS
+ add_options.push_back(AddOption("AtLightPass", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "at_light_pass"), "at_light_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("Canvas", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "canvas"), "canvas", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("InstanceCustom", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_custom"), "instance_custom", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("InstanceCustomAlpha", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_custom_alpha"), "instance_custom_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("PointSize", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "point_size"), "point_size", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("Screen", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "screen"), "screen", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_mode, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("World", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "world"), "world", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
+
add_options.push_back(AddOption("AtLightPass", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "at_light_pass"), "at_light_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("FragCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("NormalTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "normal_texture"), "normal_texture", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
@@ -4241,6 +4267,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("SpecularShininessAlpha", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "specular_shininess_alpha"), "specular_shininess_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("SpecularShininessTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "specular_shininess_texture"), "specular_shininess_texture", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("Texture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "texture"), "texture", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("Vertex", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_mode, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("FragCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("Light", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light"), "light", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
@@ -4248,23 +4275,16 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("LightColor", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_color"), "light_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("LightColorAlpha", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_color_alpha"), "light_color_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("LightPosition", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_position"), "light_position", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("LightVertex", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_vertex"), "light_vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("LightVertex", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "light_vertex"), "light_vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("Normal", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "normal"), "normal", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("PointCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "point_coord"), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("ScreenUV", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("Shadow", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "shadow"), "shadow", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("ShadowAlpha", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "shadow_alpha"), "shadow_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("ShadowColor", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "shadow_color"), "shadow_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("SpecularShininess", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "specular_shininess"), "specular_shininess", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("SpecularShininessAlpha", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "specular_shininess_alpha"), "specular_shininess_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("Texture", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "texture"), "texture", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("AtLightPass", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "at_light_pass"), "at_light_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("Canvas", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "canvas"), "canvas", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("PointSize", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "point_size"), "point_size", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("Screen", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "screen"), "screen", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("World", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "world"), "world", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
-
// SKY INPUTS
add_options.push_back(AddOption("AtCubeMapPass", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "at_cubemap_pass"), "at_cubemap_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
@@ -4297,12 +4317,14 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("SkyCoords", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "sky_coords"), "sky_coords", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
add_options.push_back(AddOption("Time", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- // PARTICLES
+ // PARTICLES INPUTS
add_options.push_back(AddOption("CollisionDepth", "Input", "Collide", "VisualShaderNodeInput", vformat(input_param_for_collide_shader_mode, "collision_depth"), "collision_depth", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
add_options.push_back(AddOption("CollisionNormal", "Input", "Collide", "VisualShaderNodeInput", vformat(input_param_for_collide_shader_mode, "collision_normal"), "collision_normal", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("EmitParticle", "Particles", "", "VisualShaderNodeParticleEmit", "", -1, -1, -1, Shader::MODE_PARTICLES));
+ // PARTICLES
+
+ add_options.push_back(AddOption("EmitParticle", "Particles", "", "VisualShaderNodeParticleEmit", "", -1, -1, TYPE_FLAGS_PROCESS | TYPE_FLAGS_PROCESS_CUSTOM | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
add_options.push_back(AddOption("ParticleAccelerator", "Particles", "", "VisualShaderNodeParticleAccelerator", "", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES));
add_options.push_back(AddOption("ParticleRandomness", "Particles", "", "VisualShaderNodeParticleRandomness", "", -1, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT | TYPE_FLAGS_PROCESS | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
add_options.push_back(AddOption("MultiplyByAxisAngle", "Particles", "Transform", "VisualShaderNodeParticleMultiplyByAxisAngle", "A node for help to multiply a position input vector by rotation using specific axis. Intended to work with emitters.", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT | TYPE_FLAGS_PROCESS | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
@@ -4320,7 +4342,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("FloatOp", "Scalar", "Common", "VisualShaderNodeFloatOp", TTR("Float operator."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("IntOp", "Scalar", "Common", "VisualShaderNodeIntOp", TTR("Integer operator."), -1, VisualShaderNode::PORT_TYPE_SCALAR_INT));
- //CONSTANTS
+ // CONSTANTS
for (int i = 0; i < MAX_FLOAT_CONST_DEFS; i++) {
add_options.push_back(AddOption(float_constant_defs[i].name, "Scalar", "Constants", "VisualShaderNodeFloatConstant", float_constant_defs[i].desc, -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, float_constant_defs[i].value));
@@ -4697,7 +4719,7 @@ public:
UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
updating = true;
- undo_redo->create_action(TTR("Edit Visual Property") + ": " + p_property, UndoRedo::MERGE_ENDS);
+ undo_redo->create_action(TTR("Edit Visual Property:") + " " + p_property, UndoRedo::MERGE_ENDS);
undo_redo->add_do_property(node.ptr(), p_property, p_value);
undo_redo->add_undo_property(node.ptr(), p_property, node->get(p_property));
diff --git a/editor/project_export.cpp b/editor/project_export.cpp
index fcb714bdf7..14158b02c8 100644
--- a/editor/project_export.cpp
+++ b/editor/project_export.cpp
@@ -1171,7 +1171,7 @@ ProjectExportDialog::ProjectExportDialog() {
script_key = memnew(LineEdit);
script_key->connect("text_changed", callable_mp(this, &ProjectExportDialog::_script_encryption_key_changed));
script_key_error = memnew(Label);
- script_key_error->set_text("- " + TTR("Invalid Encryption Key (must be 64 hexadecimal characters long)"));
+ script_key_error->set_text(String::utf8("• ") + TTR("Invalid Encryption Key (must be 64 hexadecimal characters long)"));
script_key_error->add_theme_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), SNAME("Editor")));
sec_vb->add_margin_child(TTR("Encryption Key (256-bits as hexadecimal):"), script_key);
sec_vb->add_child(script_key_error);
@@ -1250,7 +1250,7 @@ ProjectExportDialog::ProjectExportDialog() {
Label *export_error2 = memnew(Label);
export_templates_error->add_child(export_error2);
export_error2->add_theme_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), SNAME("Editor")));
- export_error2->set_text(" - " + TTR("Export templates for this platform are missing:") + " ");
+ export_error2->set_text(String::utf8("• ") + TTR("Export templates for this platform are missing:") + " ");
error_dialog = memnew(AcceptDialog);
error_dialog->set_title(TTR("Error"));
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index fd4f22425f..8d425a1e51 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -474,13 +474,7 @@ private:
return;
}
ProjectSettings::CustomMap initial_settings;
- if (rasterizer_button_group->get_pressed_button()->get_meta("driver_name") == "Vulkan") {
- initial_settings["rendering/driver/driver_name"] = "Vulkan";
- } else {
- initial_settings["rendering/driver/driver_name"] = "GLES2";
- initial_settings["rendering/textures/vram_compression/import_etc2"] = false;
- initial_settings["rendering/textures/vram_compression/import_etc"] = true;
- }
+ initial_settings["rendering/vulkan/rendering/back_end"] = rasterizer_button_group->get_pressed_button()->get_meta(SNAME("driver_name"));
initial_settings["application/config/name"] = project_name->get_text().strip_edges();
initial_settings["application/config/icon"] = "res://icon.png";
initial_settings["rendering/environment/defaults/default_environment"] = "res://default_env.tres";
@@ -869,37 +863,36 @@ public:
rshb->add_child(rvb);
Button *rs_button = memnew(CheckBox);
rs_button->set_button_group(rasterizer_button_group);
- rs_button->set_text(TTR("Vulkan"));
- rs_button->set_meta("driver_name", "Vulkan");
+ rs_button->set_text(TTR("Vulkan Clustered"));
+ rs_button->set_meta(SNAME("driver_name"), 0); // Vulkan backend "Forward Clustered"
rs_button->set_pressed(true);
rvb->add_child(rs_button);
l = memnew(Label);
- l->set_text(TTR("- Higher visual quality\n- More accurate API, which produces very fast code\n- Some features not implemented yet - work in progress\n- Incompatible with older hardware\n- Not recommended for web and mobile games"));
+ l->set_text(
+ String::utf8("• ") + TTR("Supports desktop platforms only.") +
+ String::utf8("\n• ") + TTR("Advanced 3D graphics available.") +
+ String::utf8("\n• ") + TTR("Can scale to large complex scenes.") +
+ String::utf8("\n• ") + TTR("Slower rendering of simple scenes."));
l->set_modulate(Color(1, 1, 1, 0.7));
rvb->add_child(l);
rshb->add_child(memnew(VSeparator));
- const String gles2_unsupported_tooltip =
- TTR("The GLES2 renderer is currently unavailable, as it needs to be reworked for Godot 4.0.\nUse Godot 3.2 if you need GLES2 support.");
-
rvb = memnew(VBoxContainer);
rvb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
rshb->add_child(rvb);
rs_button = memnew(CheckBox);
rs_button->set_button_group(rasterizer_button_group);
- rs_button->set_text(TTR("OpenGL ES 2.0 (currently unavailable)"));
- rs_button->set_meta("driver_name", "GLES2");
- rs_button->set_disabled(true);
- rs_button->set_tooltip(gles2_unsupported_tooltip);
+ rs_button->set_text(TTR("Vulkan Mobile"));
+ rs_button->set_meta(SNAME("driver_name"), 1); // Vulkan backend "Forward Mobile"
rvb->add_child(rs_button);
l = memnew(Label);
- l->set_text(TTR("- Lower visual quality\n- Some features not available\n- Works on most hardware\n- Recommended for web and mobile games"));
+ l->set_text(
+ String::utf8("• ") + TTR("Supports desktop + mobile platforms.") +
+ String::utf8("\n• ") + TTR("Less advanced 3D graphics.") +
+ String::utf8("\n• ") + TTR("Less scalable for complex scenes.") +
+ String::utf8("\n• ") + TTR("Faster rendering of simple scenes."));
l->set_modulate(Color(1, 1, 1, 0.7));
- // Also set the tooltip on the label so it appears when hovering either the checkbox or label.
- l->set_tooltip(gles2_unsupported_tooltip);
- // Required for the tooltip to show.
- l->set_mouse_filter(Control::MOUSE_FILTER_STOP);
rvb->add_child(l);
l = memnew(Label);
diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp
index 9a4b38db74..4cbc859e0c 100644
--- a/editor/script_create_dialog.cpp
+++ b/editor/script_create_dialog.cpp
@@ -604,7 +604,7 @@ void ScriptCreateDialog::_path_submitted(const String &p_path) {
}
void ScriptCreateDialog::_msg_script_valid(bool valid, const String &p_msg) {
- error_label->set_text("- " + p_msg);
+ error_label->set_text(String::utf8("• ") + p_msg);
if (valid) {
error_label->add_theme_color_override("font_color", get_theme_color(SNAME("success_color"), SNAME("Editor")));
} else {
@@ -613,7 +613,7 @@ void ScriptCreateDialog::_msg_script_valid(bool valid, const String &p_msg) {
}
void ScriptCreateDialog::_msg_path_valid(bool valid, const String &p_msg) {
- path_error_label->set_text("- " + p_msg);
+ path_error_label->set_text(String::utf8("• ") + p_msg);
if (valid) {
path_error_label->add_theme_color_override("font_color", get_theme_color(SNAME("success_color"), SNAME("Editor")));
} else {