summaryrefslogtreecommitdiff
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/connections_dialog.cpp58
-rw-r--r--editor/connections_dialog.h3
-rw-r--r--editor/editor_about.cpp7
-rw-r--r--editor/editor_export.cpp9
-rw-r--r--editor/editor_export.h4
-rw-r--r--editor/editor_properties.cpp33
-rw-r--r--editor/editor_settings.cpp1
-rw-r--r--editor/filesystem_dock.cpp47
-rw-r--r--editor/filesystem_dock.h1
-rw-r--r--editor/icons/GuiToggleOff.svg2
-rw-r--r--editor/icons/GuiToggleOn.svg2
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp34
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp186
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.h25
-rw-r--r--editor/plugins/tile_set_editor_plugin.cpp18
-rw-r--r--editor/project_settings_editor.cpp36
-rw-r--r--editor/project_settings_editor.h4
-rw-r--r--editor/property_selector.cpp27
-rw-r--r--editor/rename_dialog.cpp29
19 files changed, 411 insertions, 115 deletions
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index facd57418d..d3dff3f375 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -477,11 +477,6 @@ ConnectDialog::ConnectDialog() {
advanced->set_text(TTR("Advanced"));
advanced->connect("pressed", callable_mp(this, &ConnectDialog::_advanced_pressed));
- // Add spacing so the tree and inspector are the same size.
- Control *spacing = memnew(Control);
- spacing->set_custom_minimum_size(Size2(0, 4) * EDSCALE);
- vbc_right->add_child(spacing);
-
deferred = memnew(CheckBox);
deferred->set_h_size_flags(0);
deferred->set_text(TTR("Deferred"));
@@ -528,6 +523,10 @@ struct _ConnectionsDockMethodInfoSort {
}
};
+void ConnectionsDock::_filter_changed(const String &p_text) {
+ update_tree();
+}
+
/*
* Post-ConnectDialog callback for creating/editing connections.
* Creates or edits connections based on state of the ConnectDialog when "Connect" is pressed.
@@ -903,6 +902,7 @@ void ConnectionsDock::update_tree() {
String name;
if (!did_script) {
+ // Get script signals (including signals from any base scripts).
Ref<Script> scr = selectedNode->get_script();
if (scr.is_valid()) {
scr->get_script_signal_list(&node_signals2);
@@ -928,15 +928,16 @@ void ConnectionsDock::update_tree() {
icon = get_theme_icon("Object", "EditorIcons");
}
- TreeItem *pitem = nullptr;
+ TreeItem *section_item = nullptr;
+ // Create subsections.
if (node_signals2.size()) {
- pitem = tree->create_item(root);
- pitem->set_text(0, name);
- pitem->set_icon(0, icon);
- pitem->set_selectable(0, false);
- pitem->set_editable(0, false);
- pitem->set_custom_bg_color(0, get_theme_color("prop_subsection", "Editor"));
+ section_item = tree->create_item(root);
+ section_item->set_text(0, name);
+ section_item->set_icon(0, icon);
+ section_item->set_selectable(0, false);
+ section_item->set_editable(0, false);
+ section_item->set_custom_bg_color(0, get_theme_color("prop_subsection", "Editor"));
node_signals2.sort();
}
@@ -946,6 +947,12 @@ void ConnectionsDock::update_tree() {
StringName signal_name = mi.name;
String signaldesc = "(";
PackedStringArray argnames;
+
+ String filter_text = search_box->get_text();
+ if (!filter_text.is_subsequence_ofi(signal_name)) {
+ continue;
+ }
+
if (mi.arguments.size()) {
for (int i = 0; i < mi.arguments.size(); i++) {
PropertyInfo &pi = mi.arguments[i];
@@ -965,13 +972,14 @@ void ConnectionsDock::update_tree() {
}
signaldesc += ")";
- TreeItem *item = tree->create_item(pitem);
- item->set_text(0, String(signal_name) + signaldesc);
+ // Create the children of the subsection - the actual list of signals.
+ TreeItem *signal_item = tree->create_item(section_item);
+ signal_item->set_text(0, String(signal_name) + signaldesc);
Dictionary sinfo;
sinfo["name"] = signal_name;
sinfo["args"] = argnames;
- item->set_metadata(0, sinfo);
- item->set_icon(0, get_theme_icon("Signal", "EditorIcons"));
+ signal_item->set_metadata(0, sinfo);
+ signal_item->set_icon(0, get_theme_icon("Signal", "EditorIcons"));
// Set tooltip with the signal's documentation.
{
@@ -1007,7 +1015,7 @@ void ConnectionsDock::update_tree() {
}
// "::" separators used in make_custom_tooltip for formatting.
- item->set_tooltip(0, String(signal_name) + "::" + signaldesc + "::" + descr);
+ signal_item->set_tooltip(0, String(signal_name) + "::" + signaldesc + "::" + descr);
}
// List existing connections
@@ -1044,11 +1052,11 @@ void ConnectionsDock::update_tree() {
path += ")";
}
- TreeItem *item2 = tree->create_item(item);
- item2->set_text(0, path);
+ TreeItem *connection_item = tree->create_item(signal_item);
+ connection_item->set_text(0, path);
Connection cd = c;
- item2->set_metadata(0, cd);
- item2->set_icon(0, get_theme_icon("Slot", "EditorIcons"));
+ connection_item->set_metadata(0, cd);
+ connection_item->set_icon(0, get_theme_icon("Slot", "EditorIcons"));
}
}
@@ -1069,6 +1077,14 @@ ConnectionsDock::ConnectionsDock(EditorNode *p_editor) {
VBoxContainer *vbc = this;
+ search_box = memnew(LineEdit);
+ search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ search_box->set_placeholder(TTR("Filter signals"));
+ search_box->set_right_icon(get_theme_icon("Search", "EditorIcons"));
+ search_box->set_clear_button_enabled(true);
+ search_box->connect("text_changed", callable_mp(this, &ConnectionsDock::_filter_changed));
+ vbc->add_child(search_box);
+
tree = memnew(ConnectionsDockTree);
tree->set_columns(1);
tree->set_select_mode(Tree::SELECT_ROW);
diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h
index 9da9a8fb2c..48fdb91f5a 100644
--- a/editor/connections_dialog.h
+++ b/editor/connections_dialog.h
@@ -169,9 +169,12 @@ class ConnectionsDock : public VBoxContainer {
PopupMenu *signal_menu;
PopupMenu *slot_menu;
UndoRedo *undo_redo;
+ LineEdit *search_box;
Map<StringName, Map<StringName, String>> descr_cache;
+ void _filter_changed(const String &p_text);
+
void _make_or_edit_connection();
void _connect(ConnectDialog::ConnectionData cToMake);
void _disconnect(TreeItem &item);
diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp
index d99726c57c..aae476ccf4 100644
--- a/editor/editor_about.cpp
+++ b/editor/editor_about.cpp
@@ -155,12 +155,15 @@ EditorAbout::EditorAbout() {
List<String> donor_sections;
donor_sections.push_back(TTR("Platinum Sponsors"));
donor_sections.push_back(TTR("Gold Sponsors"));
+ donor_sections.push_back(TTR("Silver Sponsors"));
+ donor_sections.push_back(TTR("Bronze Sponsors"));
donor_sections.push_back(TTR("Mini Sponsors"));
donor_sections.push_back(TTR("Gold Donors"));
donor_sections.push_back(TTR("Silver Donors"));
donor_sections.push_back(TTR("Bronze Donors"));
- const char *const *donor_src[] = { DONORS_SPONSOR_PLAT, DONORS_SPONSOR_GOLD,
- DONORS_SPONSOR_MINI, DONORS_GOLD, DONORS_SILVER, DONORS_BRONZE };
+ const char *const *donor_src[] = { DONORS_SPONSOR_PLATINUM, DONORS_SPONSOR_GOLD,
+ DONORS_SPONSOR_SILVER, DONORS_SPONSOR_BRONZE, DONORS_SPONSOR_MINI,
+ DONORS_GOLD, DONORS_SILVER, DONORS_BRONZE };
tc->add_child(_populate_list(TTR("Donors"), donor_sections, donor_src, 3));
// License
diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp
index 951bec2c83..16e69734d3 100644
--- a/editor/editor_export.cpp
+++ b/editor/editor_export.cpp
@@ -512,10 +512,18 @@ void EditorExportPlugin::add_ios_framework(const String &p_path) {
ios_frameworks.push_back(p_path);
}
+void EditorExportPlugin::add_ios_embedded_framework(const String &p_path) {
+ ios_embedded_frameworks.push_back(p_path);
+}
+
Vector<String> EditorExportPlugin::get_ios_frameworks() const {
return ios_frameworks;
}
+Vector<String> EditorExportPlugin::get_ios_embedded_frameworks() const {
+ return ios_embedded_frameworks;
+}
+
void EditorExportPlugin::add_ios_plist_content(const String &p_plist_content) {
ios_plist_content += p_plist_content + "\n";
}
@@ -592,6 +600,7 @@ void EditorExportPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_ios_project_static_lib", "path"), &EditorExportPlugin::add_ios_project_static_lib);
ClassDB::bind_method(D_METHOD("add_file", "path", "file", "remap"), &EditorExportPlugin::add_file);
ClassDB::bind_method(D_METHOD("add_ios_framework", "path"), &EditorExportPlugin::add_ios_framework);
+ ClassDB::bind_method(D_METHOD("add_ios_embedded_framework", "path"), &EditorExportPlugin::add_ios_embedded_framework);
ClassDB::bind_method(D_METHOD("add_ios_plist_content", "plist_content"), &EditorExportPlugin::add_ios_plist_content);
ClassDB::bind_method(D_METHOD("add_ios_linker_flags", "flags"), &EditorExportPlugin::add_ios_linker_flags);
ClassDB::bind_method(D_METHOD("add_ios_bundle_file", "path"), &EditorExportPlugin::add_ios_bundle_file);
diff --git a/editor/editor_export.h b/editor/editor_export.h
index e31b53ad67..bb701b94ec 100644
--- a/editor/editor_export.h
+++ b/editor/editor_export.h
@@ -290,6 +290,7 @@ class EditorExportPlugin : public Reference {
bool skipped;
Vector<String> ios_frameworks;
+ Vector<String> ios_embedded_frameworks;
Vector<String> ios_project_static_libs;
String ios_plist_content;
String ios_linker_flags;
@@ -304,6 +305,7 @@ class EditorExportPlugin : public Reference {
_FORCE_INLINE_ void _export_end() {
ios_frameworks.clear();
+ ios_embedded_frameworks.clear();
ios_bundle_files.clear();
ios_plist_content = "";
ios_linker_flags = "";
@@ -322,6 +324,7 @@ protected:
void add_shared_object(const String &p_path, const Vector<String> &tags);
void add_ios_framework(const String &p_path);
+ void add_ios_embedded_framework(const String &p_path);
void add_ios_project_static_lib(const String &p_path);
void add_ios_plist_content(const String &p_plist_content);
void add_ios_linker_flags(const String &p_flags);
@@ -337,6 +340,7 @@ protected:
public:
Vector<String> get_ios_frameworks() const;
+ Vector<String> get_ios_embedded_frameworks() const;
Vector<String> get_ios_project_static_libs() const;
String get_ios_plist_content() const;
String get_ios_linker_flags() const;
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index dea76ac997..34d553b5f9 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -946,14 +946,11 @@ void EditorPropertyEasing::_drag_easing(const Ref<InputEvent> &p_ev) {
}
float val = get_edited_object()->get(get_edited_property());
- if (val == 0) {
- return;
- }
bool sg = val < 0;
val = Math::absf(val);
val = Math::log(val) / Math::log((float)2.0);
- //logspace
+ // Logarithmic space.
val += rel * 0.05;
val = Math::pow(2.0f, val);
@@ -961,6 +958,16 @@ void EditorPropertyEasing::_drag_easing(const Ref<InputEvent> &p_ev) {
val = -val;
}
+ // 0 is a singularity, but both positive and negative values
+ // are otherwise allowed. Enforce 0+ as workaround.
+ if (Math::is_zero_approx(val)) {
+ val = 0.00001;
+ }
+
+ // Limit to a reasonable value to prevent the curve going into infinity,
+ // which can cause crashes and other issues.
+ val = CLAMP(val, -1'000'000, 1'000'000);
+
emit_changed(get_edited_property(), val);
easing_draw->update();
}
@@ -1003,7 +1010,18 @@ void EditorPropertyEasing::_draw_easing() {
}
easing_draw->draw_multiline(lines, line_color, 1.0);
- f->draw(ci, Point2(10, 10 + f->get_ascent()), String::num(exp, 2), font_color);
+ // Draw more decimals for small numbers since higher precision is usually required for fine adjustments.
+ int decimals;
+ if (Math::abs(exp) < 0.1 - CMP_EPSILON) {
+ decimals = 4;
+ } else if (Math::abs(exp) < 1 - CMP_EPSILON) {
+ decimals = 3;
+ } else if (Math::abs(exp) < 10 - CMP_EPSILON) {
+ decimals = 2;
+ } else {
+ decimals = 1;
+ }
+ f->draw(ci, Point2(10, 10 + f->get_ascent()), rtos(exp).pad_decimals(decimals), font_color);
}
void EditorPropertyEasing::update_property() {
@@ -1035,6 +1053,11 @@ void EditorPropertyEasing::_spin_value_changed(double p_value) {
if (Math::is_zero_approx(p_value)) {
p_value = 0.00001;
}
+
+ // Limit to a reasonable value to prevent the curve going into infinity,
+ // which can cause crashes and other issues.
+ p_value = CLAMP(p_value, -1'000'000, 1'000'000);
+
emit_changed(get_edited_property(), p_value);
_spin_focus_exited();
}
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index f86b485dd1..7b24e6967a 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -543,6 +543,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
// 3D: Navigation
_initial_set("editors/3d/navigation/navigation_scheme", 0);
_initial_set("editors/3d/navigation/invert_y_axis", false);
+ _initial_set("editors/3d/navigation/invert_x_axis", false);
hints["editors/3d/navigation/navigation_scheme"] = PropertyInfo(Variant::INT, "editors/3d/navigation/navigation_scheme", PROPERTY_HINT_ENUM, "Godot,Maya,Modo");
_initial_set("editors/3d/navigation/zoom_style", 0);
hints["editors/3d/navigation/zoom_style"] = PropertyInfo(Variant::INT, "editors/3d/navigation/zoom_style", PROPERTY_HINT_ENUM, "Vertical, Horizontal");
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 4f37fcf39c..31903c89be 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -2430,11 +2430,31 @@ void FileSystemDock::_file_list_gui_input(Ref<InputEvent> p_event) {
}
}
-void FileSystemDock::_update_import_dock() {
- if (!import_dock_needs_update) {
+void FileSystemDock::_get_imported_files(const String &p_path, Vector<String> &files) const {
+ if (!p_path.ends_with("/")) {
+ if (FileAccess::exists(p_path + ".import")) {
+ files.push_back(p_path);
+ }
return;
}
+ DirAccess *da = DirAccess::open(p_path);
+ da->list_dir_begin();
+ String n = da->get_next();
+ while (n != String()) {
+ if (n != "." && n != ".." && !n.ends_with(".import")) {
+ String npath = p_path + n + (da->current_is_dir() ? "/" : "");
+ _get_imported_files(npath, files);
+ }
+ n = da->get_next();
+ }
+ da->list_dir_end();
+}
+
+void FileSystemDock::_update_import_dock() {
+ if (!import_dock_needs_update)
+ return;
+
// List selected.
Vector<String> selected;
if (display_mode == DISPLAY_MODE_TREE_ONLY) {
@@ -2444,29 +2464,24 @@ void FileSystemDock::_update_import_dock() {
} else {
// Use the file list.
for (int i = 0; i < files->get_item_count(); i++) {
- if (!files->is_selected(i)) {
+ if (!files->is_selected(i))
continue;
- }
selected.push_back(files->get_item_metadata(i));
}
}
+ // Expand directory selection
+ Vector<String> efiles;
+ for (int i = 0; i < selected.size(); i++) {
+ _get_imported_files(selected[i], efiles);
+ }
+
// Check import.
Vector<String> imports;
String import_type;
- for (int i = 0; i < selected.size(); i++) {
- String fpath = selected[i];
-
- if (fpath.ends_with("/")) {
- imports.clear();
- break;
- }
-
- if (!FileAccess::exists(fpath + ".import")) {
- imports.clear();
- break;
- }
+ for (int i = 0; i < efiles.size(); i++) {
+ String fpath = efiles[i];
Ref<ConfigFile> cf;
cf.instance();
Error err = cf->load(fpath + ".import");
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index b0118f11aa..ec2a075834 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -195,6 +195,7 @@ private:
void _file_multi_selected(int p_index, bool p_selected);
void _tree_multi_selected(Object *p_item, int p_column, bool p_selected);
+ void _get_imported_files(const String &p_path, Vector<String> &files) const;
void _update_import_dock();
void _get_all_items_in_dir(EditorFileSystemDirectory *efsd, Vector<String> &files, Vector<String> &folders) const;
diff --git a/editor/icons/GuiToggleOff.svg b/editor/icons/GuiToggleOff.svg
index 928b55b201..9644ef176c 100644
--- a/editor/icons/GuiToggleOff.svg
+++ b/editor/icons/GuiToggleOff.svg
@@ -1 +1 @@
-<svg height="26" viewBox="0 0 42 25.999998" width="42" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><rect fill-opacity=".188235" height="16" rx="9" stroke-width="55.8958" width="38" x="2" y="5"/><circle cx="10" cy="13" r="5" stroke-width="97.3613"/></g></svg>
+<svg height="16" viewBox="0 0 38 15.999999" width="38" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><rect fill-opacity=".188235" height="14" rx="7" stroke-width="55.8958" width="36" x="1" y="1"/><circle cx="8" cy="8" r="5" stroke-width="97.3613"/></g></svg>
diff --git a/editor/icons/GuiToggleOn.svg b/editor/icons/GuiToggleOn.svg
index a79a8290b1..8ab0998f71 100644
--- a/editor/icons/GuiToggleOn.svg
+++ b/editor/icons/GuiToggleOn.svg
@@ -1 +1 @@
-<svg height="26" viewBox="0 0 42 25.999998" width="42" xmlns="http://www.w3.org/2000/svg"><path d="m11 5c-4.986 0-9 3.568-9 8s4.014 8 9 8h20c4.986 0 9-3.568 9-8s-4.014-8-9-8zm21 3a5 5 0 0 1 5 5 5 5 0 0 1 -5 5 5 5 0 0 1 -5-5 5 5 0 0 1 5-5z" fill="#e0e0e0" stroke-width="55.8958"/></svg>
+<svg height="16" viewBox="0 0 38 15.999999" width="38" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-3.878 0-7 3.122-7 7s3.122 7 7 7h22c3.878 0 7-3.122 7-7s-3.122-7-7-7zm22 2a5 5 0 0 1 5 5 5 5 0 0 1 -5 5 5 5 0 0 1 -5-5 5 5 0 0 1 5-5z" fill="#e0e0e0" stroke-width="55.8958"/></svg>
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index b4b81cc7f0..21a75c2f5d 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -2059,7 +2059,12 @@ void Node3DEditorViewport::_nav_pan(Ref<InputEventWithModifiers> p_event, const
camera_transform.translate(cursor.pos);
camera_transform.basis.rotate(Vector3(1, 0, 0), -cursor.x_rot);
camera_transform.basis.rotate(Vector3(0, 1, 0), -cursor.y_rot);
- Vector3 translation(-p_relative.x * pan_speed, p_relative.y * pan_speed, 0);
+ const bool invert_x_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_x_axis");
+ const bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis");
+ Vector3 translation(
+ (invert_x_axis ? -1 : 1) * -p_relative.x * pan_speed,
+ (invert_y_axis ? -1 : 1) * p_relative.y * pan_speed,
+ 0);
translation *= cursor.distance / DISTANCE_DEFAULT;
camera_transform.translate(translation);
cursor.pos = camera_transform.origin;
@@ -2100,17 +2105,24 @@ void Node3DEditorViewport::_nav_orbit(Ref<InputEventWithModifiers> p_event, cons
_menu_option(VIEW_PERSPECTIVE);
}
- real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity");
- real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel);
- bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis");
+ const real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity");
+ const real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel);
+ const bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis");
+ const bool invert_x_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_x_axis");
if (invert_y_axis) {
cursor.x_rot -= p_relative.y * radians_per_pixel;
} else {
cursor.x_rot += p_relative.y * radians_per_pixel;
}
- cursor.y_rot += p_relative.x * radians_per_pixel;
+ // Clamp the Y rotation to roughly -90..90 degrees so the user can't look upside-down and end up disoriented.
cursor.x_rot = CLAMP(cursor.x_rot, -1.57, 1.57);
+
+ if (invert_x_axis) {
+ cursor.y_rot -= p_relative.x * radians_per_pixel;
+ } else {
+ cursor.y_rot += p_relative.x * radians_per_pixel;
+ }
name = "";
_update_name();
}
@@ -2125,21 +2137,23 @@ void Node3DEditorViewport::_nav_look(Ref<InputEventWithModifiers> p_event, const
_menu_option(VIEW_PERSPECTIVE);
}
- real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_sensitivity");
- real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel);
- bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis");
+ const real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_sensitivity");
+ const real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel);
+ const bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis");
// Note: do NOT assume the camera has the "current" transform, because it is interpolated and may have "lag".
- Transform prev_camera_transform = to_camera_transform(cursor);
+ const Transform prev_camera_transform = to_camera_transform(cursor);
if (invert_y_axis) {
cursor.x_rot -= p_relative.y * radians_per_pixel;
} else {
cursor.x_rot += p_relative.y * radians_per_pixel;
}
- cursor.y_rot += p_relative.x * radians_per_pixel;
+ // Clamp the Y rotation to roughly -90..90 degrees so the user can't look upside-down and end up disoriented.
cursor.x_rot = CLAMP(cursor.x_rot, -1.57, 1.57);
+ cursor.y_rot += p_relative.x * radians_per_pixel;
+
// Look is like the opposite of Orbit: the focus point rotates around the camera
Transform camera_transform = to_camera_transform(cursor);
Vector3 pos = camera_transform.xform(Vector3(0, 0, 0));
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index 1073da7d8c..18942b371c 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -36,6 +36,8 @@
#include "editor/editor_settings.h"
#include "scene/3d/sprite_3d.h"
#include "scene/gui/center_container.h"
+#include "scene/gui/margin_container.h"
+#include "scene/gui/panel_container.h"
void SpriteFramesEditor::_gui_input(Ref<InputEvent> p_event) {
}
@@ -140,8 +142,27 @@ void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) {
}
}
+void SpriteFramesEditor::_sheet_scroll_input(const Ref<InputEvent> &p_event) {
+ const Ref<InputEventMouseButton> mb = p_event;
+
+ if (mb.is_valid()) {
+ // Zoom in/out using Ctrl + mouse wheel. This is done on the ScrollContainer
+ // to allow performing this action anywhere, even if the cursor isn't
+ // hovering the texture in the workspace.
+ if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) {
+ _sheet_zoom_in();
+ // Don't scroll up after zooming in.
+ accept_event();
+ } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) {
+ _sheet_zoom_out();
+ // Don't scroll down after zooming out.
+ accept_event();
+ }
+ }
+}
+
void SpriteFramesEditor::_sheet_add_frames() {
- Size2i size = split_sheet_preview->get_size();
+ Size2i size = split_sheet_preview->get_texture()->get_size();
int h = split_sheet_h->get_value();
int v = split_sheet_v->get_value();
@@ -180,6 +201,28 @@ void SpriteFramesEditor::_sheet_add_frames() {
undo_redo->commit_action();
}
+void SpriteFramesEditor::_sheet_zoom_in() {
+ if (sheet_zoom < max_sheet_zoom) {
+ sheet_zoom *= scale_ratio;
+ Size2 texture_size = split_sheet_preview->get_texture()->get_size();
+ split_sheet_preview->set_custom_minimum_size(texture_size * sheet_zoom);
+ }
+}
+
+void SpriteFramesEditor::_sheet_zoom_out() {
+ if (sheet_zoom > min_sheet_zoom) {
+ sheet_zoom /= scale_ratio;
+ Size2 texture_size = split_sheet_preview->get_texture()->get_size();
+ split_sheet_preview->set_custom_minimum_size(texture_size * sheet_zoom);
+ }
+}
+
+void SpriteFramesEditor::_sheet_zoom_reset() {
+ sheet_zoom = 1.f;
+ Size2 texture_size = split_sheet_preview->get_texture()->get_size();
+ split_sheet_preview->set_custom_minimum_size(texture_size * sheet_zoom);
+}
+
void SpriteFramesEditor::_sheet_select_clear_all_frames() {
bool should_clear = true;
for (int i = 0; i < split_sheet_h->get_value() * split_sheet_v->get_value(); i++) {
@@ -207,15 +250,18 @@ void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) {
EditorNode::get_singleton()->show_warning(TTR("Unable to load images"));
ERR_FAIL_COND(!texture.is_valid());
}
- if (texture != split_sheet_preview->get_texture()) {
- //different texture, reset to 4x4
- split_sheet_h->set_value(4);
- split_sheet_v->set_value(4);
- }
+ bool new_texture = texture != split_sheet_preview->get_texture();
frames_selected.clear();
last_frame_selected = -1;
split_sheet_preview->set_texture(texture);
+ if (new_texture) {
+ //different texture, reset to 4x4
+ split_sheet_h->set_value(4);
+ split_sheet_v->set_value(4);
+ //reset zoom
+ _sheet_zoom_reset();
+ }
split_sheet_dialog->popup_centered_ratio(0.65);
}
@@ -231,8 +277,14 @@ void SpriteFramesEditor::_notification(int p_what) {
move_up->set_icon(get_theme_icon("MoveLeft", "EditorIcons"));
move_down->set_icon(get_theme_icon("MoveRight", "EditorIcons"));
_delete->set_icon(get_theme_icon("Remove", "EditorIcons"));
+ zoom_out->set_icon(get_theme_icon("ZoomLess", "EditorIcons"));
+ zoom_1->set_icon(get_theme_icon("ZoomReset", "EditorIcons"));
+ zoom_in->set_icon(get_theme_icon("ZoomMore", "EditorIcons"));
new_anim->set_icon(get_theme_icon("New", "EditorIcons"));
remove_anim->set_icon(get_theme_icon("Remove", "EditorIcons"));
+ split_sheet_zoom_out->set_icon(get_theme_icon("ZoomLess", "EditorIcons"));
+ split_sheet_zoom_1->set_icon(get_theme_icon("ZoomReset", "EditorIcons"));
+ split_sheet_zoom_in->set_icon(get_theme_icon("ZoomMore", "EditorIcons"));
[[fallthrough]];
}
case NOTIFICATION_THEME_CHANGED: {
@@ -636,6 +688,54 @@ void SpriteFramesEditor::_animation_fps_changed(double p_value) {
undo_redo->commit_action();
}
+void SpriteFramesEditor::_tree_input(const Ref<InputEvent> &p_event) {
+ const Ref<InputEventMouseButton> mb = p_event;
+
+ if (mb.is_valid()) {
+ if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) {
+ _zoom_in();
+ // Don't scroll up after zooming in.
+ accept_event();
+ } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) {
+ _zoom_out();
+ // Don't scroll down after zooming out.
+ accept_event();
+ }
+ }
+}
+
+void SpriteFramesEditor::_zoom_in() {
+ // Do not zoom in or out with no visible frames
+ if (frames->get_frame_count(edited_anim) <= 0) {
+ return;
+ }
+ if (thumbnail_zoom < max_thumbnail_zoom) {
+ thumbnail_zoom *= scale_ratio;
+ int thumbnail_size = (int)(thumbnail_default_size * thumbnail_zoom);
+ tree->set_fixed_column_width(thumbnail_size * 3 / 2);
+ tree->set_fixed_icon_size(Size2(thumbnail_size, thumbnail_size));
+ }
+}
+
+void SpriteFramesEditor::_zoom_out() {
+ // Do not zoom in or out with no visible frames
+ if (frames->get_frame_count(edited_anim) <= 0) {
+ return;
+ }
+ if (thumbnail_zoom > min_thumbnail_zoom) {
+ thumbnail_zoom /= scale_ratio;
+ int thumbnail_size = (int)(thumbnail_default_size * thumbnail_zoom);
+ tree->set_fixed_column_width(thumbnail_size * 3 / 2);
+ tree->set_fixed_icon_size(Size2(thumbnail_size, thumbnail_size));
+ }
+}
+
+void SpriteFramesEditor::_zoom_reset() {
+ thumbnail_zoom = 1.0f;
+ tree->set_fixed_column_width(thumbnail_default_size * 3 / 2);
+ tree->set_fixed_icon_size(Size2(thumbnail_default_size, thumbnail_default_size));
+}
+
void SpriteFramesEditor::_update_library(bool p_skip_selector) {
updating = true;
@@ -727,6 +827,9 @@ void SpriteFramesEditor::edit(SpriteFrames *p_frames) {
}
_update_library();
+ // Clear zoom and split sheet texture
+ split_sheet_preview->set_texture(Ref<Texture2D>());
+ _zoom_reset();
} else {
hide();
}
@@ -965,6 +1068,24 @@ SpriteFramesEditor::SpriteFramesEditor() {
_delete->set_tooltip(TTR("Delete"));
hbc->add_child(_delete);
+ hbc->add_spacer();
+
+ zoom_out = memnew(Button);
+ zoom_out->connect("pressed", callable_mp(this, &SpriteFramesEditor::_zoom_out));
+ zoom_out->set_flat(true);
+ zoom_out->set_tooltip(TTR("Zoom Out"));
+ hbc->add_child(zoom_out);
+ zoom_1 = memnew(Button);
+ zoom_1->connect("pressed", callable_mp(this, &SpriteFramesEditor::_zoom_reset));
+ zoom_1->set_flat(true);
+ zoom_1->set_tooltip(TTR("Zoom Reset"));
+ hbc->add_child(zoom_1);
+ zoom_in = memnew(Button);
+ zoom_in->connect("pressed", callable_mp(this, &SpriteFramesEditor::_zoom_in));
+ zoom_in->set_flat(true);
+ zoom_in->set_tooltip(TTR("Zoom In"));
+ hbc->add_child(zoom_in);
+
file = memnew(EditorFileDialog);
add_child(file);
@@ -972,13 +1093,11 @@ SpriteFramesEditor::SpriteFramesEditor() {
tree->set_v_size_flags(SIZE_EXPAND_FILL);
tree->set_icon_mode(ItemList::ICON_MODE_TOP);
- int thumbnail_size = 96;
tree->set_max_columns(0);
tree->set_icon_mode(ItemList::ICON_MODE_TOP);
- tree->set_fixed_column_width(thumbnail_size * 3 / 2);
tree->set_max_text_lines(2);
- tree->set_fixed_icon_size(Size2(thumbnail_size, thumbnail_size));
tree->set_drag_forwarding(this);
+ tree->connect("gui_input", callable_mp(this, &SpriteFramesEditor::_tree_input));
sub_vb->add_child(tree);
@@ -1042,8 +1161,13 @@ SpriteFramesEditor::SpriteFramesEditor() {
split_sheet_vb->add_child(split_sheet_hb);
+ PanelContainer *split_sheet_panel = memnew(PanelContainer);
+ split_sheet_panel->set_h_size_flags(SIZE_EXPAND_FILL);
+ split_sheet_panel->set_v_size_flags(SIZE_EXPAND_FILL);
+ split_sheet_vb->add_child(split_sheet_panel);
+
split_sheet_preview = memnew(TextureRect);
- split_sheet_preview->set_expand(false);
+ split_sheet_preview->set_expand(true);
split_sheet_preview->set_mouse_filter(MOUSE_FILTER_PASS);
split_sheet_preview->connect("draw", callable_mp(this, &SpriteFramesEditor::_sheet_preview_draw));
split_sheet_preview->connect("gui_input", callable_mp(this, &SpriteFramesEditor::_sheet_preview_input));
@@ -1051,20 +1175,58 @@ SpriteFramesEditor::SpriteFramesEditor() {
splite_sheet_scroll = memnew(ScrollContainer);
splite_sheet_scroll->set_enable_h_scroll(true);
splite_sheet_scroll->set_enable_v_scroll(true);
- splite_sheet_scroll->set_v_size_flags(SIZE_EXPAND_FILL);
+ splite_sheet_scroll->connect("gui_input", callable_mp(this, &SpriteFramesEditor::_sheet_scroll_input));
+ split_sheet_panel->add_child(splite_sheet_scroll);
CenterContainer *cc = memnew(CenterContainer);
cc->add_child(split_sheet_preview);
cc->set_h_size_flags(SIZE_EXPAND_FILL);
cc->set_v_size_flags(SIZE_EXPAND_FILL);
splite_sheet_scroll->add_child(cc);
- split_sheet_vb->add_child(splite_sheet_scroll);
+ MarginContainer *split_sheet_zoom_margin = memnew(MarginContainer);
+ split_sheet_panel->add_child(split_sheet_zoom_margin);
+ split_sheet_zoom_margin->set_h_size_flags(0);
+ split_sheet_zoom_margin->set_v_size_flags(0);
+ split_sheet_zoom_margin->add_theme_constant_override("margin_top", 5);
+ split_sheet_zoom_margin->add_theme_constant_override("margin_left", 5);
+ HBoxContainer *split_sheet_zoom_hb = memnew(HBoxContainer);
+ split_sheet_zoom_margin->add_child(split_sheet_zoom_hb);
+
+ split_sheet_zoom_out = memnew(Button);
+ split_sheet_zoom_out->set_flat(true);
+ split_sheet_zoom_out->set_focus_mode(FOCUS_NONE);
+ split_sheet_zoom_out->set_tooltip(TTR("Zoom Out"));
+ split_sheet_zoom_out->connect("pressed", callable_mp(this, &SpriteFramesEditor::_sheet_zoom_out));
+ split_sheet_zoom_hb->add_child(split_sheet_zoom_out);
+ split_sheet_zoom_1 = memnew(Button);
+ split_sheet_zoom_1->set_flat(true);
+ split_sheet_zoom_1->set_focus_mode(FOCUS_NONE);
+ split_sheet_zoom_1->set_tooltip(TTR("Zoom Reset"));
+ split_sheet_zoom_1->connect("pressed", callable_mp(this, &SpriteFramesEditor::_sheet_zoom_reset));
+ split_sheet_zoom_hb->add_child(split_sheet_zoom_1);
+ split_sheet_zoom_in = memnew(Button);
+ split_sheet_zoom_in->set_flat(true);
+ split_sheet_zoom_in->set_focus_mode(FOCUS_NONE);
+ split_sheet_zoom_in->set_tooltip(TTR("Zoom In"));
+ split_sheet_zoom_in->connect("pressed", callable_mp(this, &SpriteFramesEditor::_sheet_zoom_in));
+ split_sheet_zoom_hb->add_child(split_sheet_zoom_in);
file_split_sheet = memnew(EditorFileDialog);
file_split_sheet->set_title(TTR("Create Frames from Sprite Sheet"));
file_split_sheet->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
add_child(file_split_sheet);
file_split_sheet->connect("file_selected", callable_mp(this, &SpriteFramesEditor::_prepare_sprite_sheet));
+
+ // Config scale.
+ scale_ratio = 1.2f;
+ thumbnail_default_size = 96;
+ thumbnail_zoom = 1.0f;
+ max_thumbnail_zoom = 8.0f;
+ min_thumbnail_zoom = 0.1f;
+ sheet_zoom = 1.0f;
+ max_sheet_zoom = 16.0f;
+ min_sheet_zoom = 0.01f;
+ _zoom_reset();
}
void SpriteFramesEditorPlugin::edit(Object *p_object) {
diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h
index ee743fe60d..0dce93f55a 100644
--- a/editor/plugins/sprite_frames_editor_plugin.h
+++ b/editor/plugins/sprite_frames_editor_plugin.h
@@ -36,6 +36,7 @@
#include "scene/2d/animated_sprite_2d.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/file_dialog.h"
+#include "scene/gui/scroll_container.h"
#include "scene/gui/split_container.h"
#include "scene/gui/texture_rect.h"
#include "scene/gui/tree.h"
@@ -52,6 +53,9 @@ class SpriteFramesEditor : public HSplitContainer {
Button *empty2;
Button *move_up;
Button *move_down;
+ Button *zoom_out;
+ Button *zoom_1;
+ Button *zoom_in;
ItemList *tree;
bool loading_scene;
int sel;
@@ -79,10 +83,22 @@ class SpriteFramesEditor : public HSplitContainer {
TextureRect *split_sheet_preview;
SpinBox *split_sheet_h;
SpinBox *split_sheet_v;
+ Button *split_sheet_zoom_out;
+ Button *split_sheet_zoom_1;
+ Button *split_sheet_zoom_in;
EditorFileDialog *file_split_sheet;
Set<int> frames_selected;
int last_frame_selected;
+ float scale_ratio;
+ int thumbnail_default_size;
+ float thumbnail_zoom;
+ float max_thumbnail_zoom;
+ float min_thumbnail_zoom;
+ float sheet_zoom;
+ float max_sheet_zoom;
+ float min_sheet_zoom;
+
void _load_pressed();
void _load_scene_pressed();
void _file_load_request(const Vector<String> &p_path, int p_at_pos = -1);
@@ -103,6 +119,11 @@ class SpriteFramesEditor : public HSplitContainer {
void _animation_loop_changed();
void _animation_fps_changed(double p_value);
+ void _tree_input(const Ref<InputEvent> &p_event);
+ void _zoom_in();
+ void _zoom_out();
+ void _zoom_reset();
+
bool updating;
UndoRedo *undo_redo;
@@ -117,7 +138,11 @@ class SpriteFramesEditor : public HSplitContainer {
void _sheet_preview_draw();
void _sheet_spin_changed(double);
void _sheet_preview_input(const Ref<InputEvent> &p_event);
+ void _sheet_scroll_input(const Ref<InputEvent> &p_event);
void _sheet_add_frames();
+ void _sheet_zoom_in();
+ void _sheet_zoom_out();
+ void _sheet_zoom_reset();
void _sheet_select_clear_all_frames();
protected:
diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp
index a613174ed9..274c64263f 100644
--- a/editor/plugins/tile_set_editor_plugin.cpp
+++ b/editor/plugins/tile_set_editor_plugin.cpp
@@ -342,11 +342,13 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
left_container->add_child(tileset_toolbar_container);
tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE] = memnew(Button);
+ tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->set_flat(true);
tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tileset_toolbar_button_pressed), varray(TOOL_TILESET_ADD_TEXTURE));
tileset_toolbar_container->add_child(tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]);
tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->set_tooltip(TTR("Add Texture(s) to TileSet."));
tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE] = memnew(Button);
+ tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->set_flat(true);
tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tileset_toolbar_button_pressed), varray(TOOL_TILESET_REMOVE_TEXTURE));
tileset_toolbar_container->add_child(tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]);
tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->set_tooltip(TTR("Remove selected Texture from TileSet."));
@@ -405,12 +407,14 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
tools[SELECT_NEXT] = memnew(Button);
tool_hb->add_child(tools[SELECT_NEXT]);
tool_hb->move_child(tools[SELECT_NEXT], WORKSPACE_CREATE_SINGLE);
+ tools[SELECT_NEXT]->set_flat(true);
tools[SELECT_NEXT]->set_shortcut(ED_SHORTCUT("tileset_editor/next_shape", TTR("Next Coordinate"), KEY_PAGEDOWN));
tools[SELECT_NEXT]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(SELECT_NEXT));
tools[SELECT_NEXT]->set_tooltip(TTR("Select the next shape, subtile, or Tile."));
tools[SELECT_PREVIOUS] = memnew(Button);
tool_hb->add_child(tools[SELECT_PREVIOUS]);
tool_hb->move_child(tools[SELECT_PREVIOUS], WORKSPACE_CREATE_SINGLE);
+ tools[SELECT_PREVIOUS]->set_flat(true);
tools[SELECT_PREVIOUS]->set_shortcut(ED_SHORTCUT("tileset_editor/previous_shape", TTR("Previous Coordinate"), KEY_PAGEUP));
tools[SELECT_PREVIOUS]->set_tooltip(TTR("Select the previous shape, subtile, or Tile."));
tools[SELECT_PREVIOUS]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(SELECT_PREVIOUS));
@@ -467,6 +471,7 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
tools[TOOL_SELECT] = memnew(Button);
toolbar->add_child(tools[TOOL_SELECT]);
+ tools[TOOL_SELECT]->set_flat(true);
tools[TOOL_SELECT]->set_toggle_mode(true);
tools[TOOL_SELECT]->set_button_group(tg);
tools[TOOL_SELECT]->set_pressed(true);
@@ -475,20 +480,24 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
separator_bitmask = memnew(VSeparator);
toolbar->add_child(separator_bitmask);
tools[BITMASK_COPY] = memnew(Button);
+ tools[BITMASK_COPY]->set_flat(true);
tools[BITMASK_COPY]->set_tooltip(TTR("Copy bitmask."));
tools[BITMASK_COPY]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(BITMASK_COPY));
toolbar->add_child(tools[BITMASK_COPY]);
tools[BITMASK_PASTE] = memnew(Button);
+ tools[BITMASK_PASTE]->set_flat(true);
tools[BITMASK_PASTE]->set_tooltip(TTR("Paste bitmask."));
tools[BITMASK_PASTE]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(BITMASK_PASTE));
toolbar->add_child(tools[BITMASK_PASTE]);
tools[BITMASK_CLEAR] = memnew(Button);
+ tools[BITMASK_CLEAR]->set_flat(true);
tools[BITMASK_CLEAR]->set_tooltip(TTR("Erase bitmask."));
tools[BITMASK_CLEAR]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(BITMASK_CLEAR));
toolbar->add_child(tools[BITMASK_CLEAR]);
tools[SHAPE_NEW_RECTANGLE] = memnew(Button);
toolbar->add_child(tools[SHAPE_NEW_RECTANGLE]);
+ tools[SHAPE_NEW_RECTANGLE]->set_flat(true);
tools[SHAPE_NEW_RECTANGLE]->set_toggle_mode(true);
tools[SHAPE_NEW_RECTANGLE]->set_button_group(tg);
tools[SHAPE_NEW_RECTANGLE]->set_tooltip(TTR("Create a new rectangle."));
@@ -496,6 +505,7 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
tools[SHAPE_NEW_POLYGON] = memnew(Button);
toolbar->add_child(tools[SHAPE_NEW_POLYGON]);
+ tools[SHAPE_NEW_POLYGON]->set_flat(true);
tools[SHAPE_NEW_POLYGON]->set_toggle_mode(true);
tools[SHAPE_NEW_POLYGON]->set_button_group(tg);
tools[SHAPE_NEW_POLYGON]->set_tooltip(TTR("Create a new polygon."));
@@ -504,12 +514,14 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
separator_shape_toggle = memnew(VSeparator);
toolbar->add_child(separator_shape_toggle);
tools[SHAPE_TOGGLE_TYPE] = memnew(Button);
+ tools[SHAPE_TOGGLE_TYPE]->set_flat(true);
tools[SHAPE_TOGGLE_TYPE]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(SHAPE_TOGGLE_TYPE));
toolbar->add_child(tools[SHAPE_TOGGLE_TYPE]);
separator_delete = memnew(VSeparator);
toolbar->add_child(separator_delete);
tools[SHAPE_DELETE] = memnew(Button);
+ tools[SHAPE_DELETE]->set_flat(true);
tools[SHAPE_DELETE]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(SHAPE_DELETE));
toolbar->add_child(tools[SHAPE_DELETE]);
@@ -534,11 +546,13 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
separator_grid = memnew(VSeparator);
toolbar->add_child(separator_grid);
tools[SHAPE_KEEP_INSIDE_TILE] = memnew(Button);
+ tools[SHAPE_KEEP_INSIDE_TILE]->set_flat(true);
tools[SHAPE_KEEP_INSIDE_TILE]->set_toggle_mode(true);
tools[SHAPE_KEEP_INSIDE_TILE]->set_pressed(true);
tools[SHAPE_KEEP_INSIDE_TILE]->set_tooltip(TTR("Keep polygon inside region Rect."));
toolbar->add_child(tools[SHAPE_KEEP_INSIDE_TILE]);
tools[TOOL_GRID_SNAP] = memnew(Button);
+ tools[TOOL_GRID_SNAP]->set_flat(true);
tools[TOOL_GRID_SNAP]->set_toggle_mode(true);
tools[TOOL_GRID_SNAP]->set_tooltip(TTR("Enable snap and show grid (configurable via the Inspector)."));
tools[TOOL_GRID_SNAP]->connect("toggled", callable_mp(this, &TileSetEditor::_on_grid_snap_toggled));
@@ -549,19 +563,23 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
toolbar->add_child(separator);
tools[ZOOM_OUT] = memnew(Button);
+ tools[ZOOM_OUT]->set_flat(true);
tools[ZOOM_OUT]->connect("pressed", callable_mp(this, &TileSetEditor::_zoom_out));
toolbar->add_child(tools[ZOOM_OUT]);
tools[ZOOM_OUT]->set_tooltip(TTR("Zoom Out"));
tools[ZOOM_1] = memnew(Button);
+ tools[ZOOM_1]->set_flat(true);
tools[ZOOM_1]->connect("pressed", callable_mp(this, &TileSetEditor::_zoom_reset));
toolbar->add_child(tools[ZOOM_1]);
tools[ZOOM_1]->set_tooltip(TTR("Zoom Reset"));
tools[ZOOM_IN] = memnew(Button);
+ tools[ZOOM_IN]->set_flat(true);
tools[ZOOM_IN]->connect("pressed", callable_mp(this, &TileSetEditor::_zoom_in));
toolbar->add_child(tools[ZOOM_IN]);
tools[ZOOM_IN]->set_tooltip(TTR("Zoom In"));
tools[VISIBLE_INFO] = memnew(Button);
+ tools[VISIBLE_INFO]->set_flat(true);
tools[VISIBLE_INFO]->set_toggle_mode(true);
tools[VISIBLE_INFO]->set_tooltip(TTR("Display Tile Names (Hold Alt Key)"));
toolbar->add_child(tools[VISIBLE_INFO]);
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index 9be1a7c2fe..82ac225ddb 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -113,11 +113,17 @@ void ProjectSettingsEditor::_add_setting() {
inspector->set_current_section(setting.get_slice("/", 1));
}
-void ProjectSettingsEditor::_delete_setting() {
+void ProjectSettingsEditor::_delete_setting(bool p_confirmed) {
String setting = _get_setting_name();
Variant value = ps->get(setting);
int order = ps->get_order(setting);
+ if (!p_confirmed) {
+ del_confirmation->set_text(vformat(TTR("Are you sure you want to delete '%s'?"), setting));
+ del_confirmation->popup_centered();
+ return;
+ }
+
undo_redo->create_action(TTR("Delete Item"));
undo_redo->add_do_method(ps, "clear", setting);
@@ -171,7 +177,7 @@ void ProjectSettingsEditor::_update_advanced_bar() {
}
}
- disable_add = !bad_category;
+ disable_add = bad_category;
if (!property_text.is_valid_identifier()) {
disable_add = true;
@@ -327,11 +333,9 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
header->add_child(search_bar);
search_box = memnew(LineEdit);
- search_box->set_custom_minimum_size(Size2(300, 0));
+ search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
search_bar->add_child(search_box);
- search_bar->add_spacer();
-
advanced = memnew(CheckButton);
advanced->set_text(TTR("Advanced"));
advanced->connect("pressed", callable_mp(this, &ProjectSettingsEditor::_advanced_pressed));
@@ -345,12 +349,14 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
advanced_bar->hide();
header->add_child(advanced_bar);
+ advanced_bar->add_child(memnew(HSeparator));
+
HBoxContainer *hbc = memnew(HBoxContainer);
hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- advanced_bar->add_margin_child(TTR("Add or remove custom project settings."), hbc, true);
+ advanced_bar->add_margin_child(TTR("Add or Remove Custom Project Settings:"), hbc, true);
category_box = memnew(LineEdit);
- category_box->set_custom_minimum_size(Size2(140, 0) * EDSCALE);
+ category_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
category_box->connect("text_changed", callable_mp(this, &ProjectSettingsEditor::_text_field_changed));
category_box->set_placeholder(TTR("Category"));
hbc->add_child(category_box);
@@ -370,7 +376,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
hbc->add_child(l);
type = memnew(OptionButton);
- type->set_custom_minimum_size(Size2(70, 0) * EDSCALE);
+ type->set_custom_minimum_size(Size2(100, 0) * EDSCALE);
hbc->add_child(type);
// Start at 1 to avoid adding "Nil" as an option
@@ -383,26 +389,24 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
hbc->add_child(l);
feature_override = memnew(OptionButton);
- feature_override->set_custom_minimum_size(Size2(70, 0) * EDSCALE);
+ feature_override->set_custom_minimum_size(Size2(100, 0) * EDSCALE);
feature_override->connect("item_selected", callable_mp(this, &ProjectSettingsEditor::_feature_selected));
hbc->add_child(feature_override);
- hbc->add_spacer();
-
add_button = memnew(Button);
+ add_button->set_flat(true);
add_button->connect("pressed", callable_mp(this, &ProjectSettingsEditor::_add_setting));
hbc->add_child(add_button);
del_button = memnew(Button);
- del_button->connect("pressed", callable_mp(this, &ProjectSettingsEditor::_delete_setting));
+ del_button->set_flat(true);
+ del_button->connect("pressed", callable_mp(this, &ProjectSettingsEditor::_delete_setting), varray(false));
hbc->add_child(del_button);
error_label = memnew(Label);
advanced_bar->add_child(error_label);
}
- header->add_child(memnew(HSeparator));
-
inspector = memnew(SectionedInspector);
inspector->get_inspector()->set_undo_redo(EditorNode::get_singleton()->get_undo_redo());
inspector->set_v_size_flags(Control::SIZE_EXPAND_FILL);
@@ -468,6 +472,10 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
timer->set_one_shot(true);
add_child(timer);
+ del_confirmation = memnew(ConfirmationDialog);
+ del_confirmation->connect("confirmed", callable_mp(this, &ProjectSettingsEditor::_delete_setting), varray(true));
+ add_child(del_confirmation);
+
get_ok()->set_text(TTR("Close"));
set_hide_on_ok(true);
}
diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h
index 0d7e19b242..4ecd28e514 100644
--- a/editor/project_settings_editor.h
+++ b/editor/project_settings_editor.h
@@ -77,6 +77,8 @@ class ProjectSettingsEditor : public AcceptDialog {
OptionButton *feature_override;
Label *error_label;
+ ConfirmationDialog *del_confirmation;
+
Label *restart_label;
TextureRect *restart_icon;
PanelContainer *restart_container;
@@ -94,7 +96,7 @@ class ProjectSettingsEditor : public AcceptDialog {
void _setting_edited(const String &p_name);
void _setting_selected(const String &p_path);
void _add_setting();
- void _delete_setting();
+ void _delete_setting(bool p_confirmed);
void _editor_restart_request();
void _editor_restart();
diff --git a/editor/property_selector.cpp b/editor/property_selector.cpp
index c6c93fae83..27b11e4fb5 100644
--- a/editor/property_selector.cpp
+++ b/editor/property_selector.cpp
@@ -84,6 +84,9 @@ void PropertySelector::_update_search() {
TreeItem *root = search_options->create_item();
+ // Allow using spaces in place of underscores in the search string (makes the search more fault-tolerant).
+ const String search_text = search_box->get_text().replace(" ", "_");
+
if (properties) {
List<PropertyInfo> props;
@@ -167,7 +170,7 @@ void PropertySelector::_update_search() {
continue;
}
- if (search_box->get_text() != String() && E->get().name.find(search_box->get_text()) == -1) {
+ if (search_box->get_text() != String() && E->get().name.findn(search_text) == -1) {
continue;
}
@@ -180,7 +183,7 @@ void PropertySelector::_update_search() {
item->set_metadata(0, E->get().name);
item->set_icon(0, type_icons[E->get().type]);
- if (!found && search_box->get_text() != String() && E->get().name.find(search_box->get_text()) != -1) {
+ if (!found && search_box->get_text() != String() && E->get().name.findn(search_text) != -1) {
item->select(0);
found = true;
}
@@ -255,7 +258,7 @@ void PropertySelector::_update_search() {
continue;
}
- if (search_box->get_text() != String() && name.find(search_box->get_text()) == -1) {
+ if (search_box->get_text() != String() && name.findn(search_text) == -1) {
continue;
}
@@ -270,29 +273,29 @@ void PropertySelector::_update_search() {
} else if (mi.return_val.type != Variant::NIL) {
desc = Variant::get_type_name(mi.return_val.type);
} else {
- desc = "void ";
+ desc = "void";
}
- desc += " " + mi.name + " ( ";
+ desc += vformat(" %s(", mi.name);
for (int i = 0; i < mi.arguments.size(); i++) {
if (i > 0) {
desc += ", ";
}
+ desc += mi.arguments[i].name;
+
if (mi.arguments[i].type == Variant::NIL) {
- desc += "var ";
+ desc += ": Variant";
} else if (mi.arguments[i].name.find(":") != -1) {
- desc += mi.arguments[i].name.get_slice(":", 1) + " ";
+ desc += vformat(": %s", mi.arguments[i].name.get_slice(":", 1));
mi.arguments[i].name = mi.arguments[i].name.get_slice(":", 0);
} else {
- desc += Variant::get_type_name(mi.arguments[i].type) + " ";
+ desc += vformat(": %s", Variant::get_type_name(mi.arguments[i].type));
}
-
- desc += mi.arguments[i].name;
}
- desc += " )";
+ desc += ")";
if (E->get().flags & METHOD_FLAG_CONST) {
desc += " const";
@@ -306,7 +309,7 @@ void PropertySelector::_update_search() {
item->set_metadata(0, name);
item->set_selectable(0, true);
- if (!found && search_box->get_text() != String() && name.find(search_box->get_text()) != -1) {
+ if (!found && search_box->get_text() != String() && name.findn(search_text) != -1) {
item->select(0);
found = true;
}
diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp
index 211e365454..23990bca07 100644
--- a/editor/rename_dialog.cpp
+++ b/editor/rename_dialog.cpp
@@ -61,18 +61,16 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
// ---- 1st & 2nd row
Label *lbl_search = memnew(Label);
- lbl_search->set_text(TTR("Search"));
+ lbl_search->set_text(TTR("Search:"));
lne_search = memnew(LineEdit);
- lne_search->set_placeholder(TTR("Search"));
lne_search->set_name("lne_search");
lne_search->set_h_size_flags(Control::SIZE_EXPAND_FILL);
Label *lbl_replace = memnew(Label);
- lbl_replace->set_text(TTR("Replace"));
+ lbl_replace->set_text(TTR("Replace:"));
lne_replace = memnew(LineEdit);
- lne_replace->set_placeholder(TTR("Replace"));
lne_replace->set_name("lne_replace");
lne_replace->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -84,18 +82,16 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
// ---- 3rd & 4th row
Label *lbl_prefix = memnew(Label);
- lbl_prefix->set_text(TTR("Prefix"));
+ lbl_prefix->set_text(TTR("Prefix:"));
lne_prefix = memnew(LineEdit);
- lne_prefix->set_placeholder(TTR("Prefix"));
lne_prefix->set_name("lne_prefix");
lne_prefix->set_h_size_flags(Control::SIZE_EXPAND_FILL);
Label *lbl_suffix = memnew(Label);
- lbl_suffix->set_text(TTR("Suffix"));
+ lbl_suffix->set_text(TTR("Suffix:"));
lne_suffix = memnew(LineEdit);
- lne_suffix->set_placeholder(TTR("Suffix"));
lne_suffix->set_name("lne_suffix");
lne_suffix->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -106,8 +102,6 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
// -- Feature Tabs
- const int feature_min_height = 160 * EDSCALE;
-
cbut_regex = memnew(CheckButton);
cbut_regex->set_text(TTR("Use Regular Expressions"));
vbc->add_child(cbut_regex);
@@ -118,13 +112,13 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
tabc_features = memnew(TabContainer);
tabc_features->set_tab_align(TabContainer::ALIGN_LEFT);
+ tabc_features->set_use_hidden_tabs_for_min_size(true);
vbc->add_child(tabc_features);
// ---- Tab Substitute
VBoxContainer *vbc_substitute = memnew(VBoxContainer);
vbc_substitute->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- vbc_substitute->set_custom_minimum_size(Size2(0, feature_min_height));
vbc_substitute->set_name(TTR("Substitute"));
tabc_features->add_child(vbc_substitute);
@@ -199,7 +193,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
chk_per_level_counter = memnew(CheckBox);
chk_per_level_counter->set_text(TTR("Per-level Counter"));
- chk_per_level_counter->set_tooltip(TTR("If set the counter restarts for each group of child nodes."));
+ chk_per_level_counter->set_tooltip(TTR("If set, the counter restarts for each group of child nodes."));
vbc_substitute->add_child(chk_per_level_counter);
HBoxContainer *hbc_count_options = memnew(HBoxContainer);
@@ -241,7 +235,6 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
VBoxContainer *vbc_process = memnew(VBoxContainer);
vbc_process->set_h_size_flags(Control::SIZE_EXPAND_FILL);
vbc_process->set_name(TTR("Post-Process"));
- vbc_process->set_custom_minimum_size(Size2(0, feature_min_height));
tabc_features->add_child(vbc_process);
cbut_process = memnew(CheckBox);
@@ -285,18 +278,14 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
vbc->add_child(sep_preview);
lbl_preview_title = memnew(Label);
- lbl_preview_title->set_text(TTR("Preview"));
vbc->add_child(lbl_preview_title);
lbl_preview = memnew(Label);
- lbl_preview->set_text("");
- lbl_preview->add_theme_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_theme_color("error_color", "Editor"));
vbc->add_child(lbl_preview);
// ---- Dialog related
set_min_size(Size2(383, 0));
- //set_as_toplevel(true);
get_ok()->set_text(TTR("Rename"));
Button *but_reset = add_button(TTR("Reset"));
@@ -307,7 +296,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
cbut_collapse_features->connect("toggled", callable_mp(this, &RenameDialog::_features_toggled));
- // Substitite Buttons
+ // Substitute Buttons
lne_search->connect("focus_entered", callable_mp(this, &RenameDialog::_update_substitute));
lne_search->connect("focus_exited", callable_mp(this, &RenameDialog::_update_substitute));
@@ -391,7 +380,7 @@ void RenameDialog::_update_preview(String new_text) {
String new_name = _apply_rename(preview_node, spn_count_start->get_value());
if (!has_errors) {
- lbl_preview_title->set_text(TTR("Preview"));
+ lbl_preview_title->set_text(TTR("Preview:"));
lbl_preview->set_text(new_name);
if (new_name == preview_node->get_name()) {
@@ -482,7 +471,7 @@ void RenameDialog::_error_handler(void *p_self, const char *p_func, const char *
}
self->has_errors = true;
- self->lbl_preview_title->set_text(TTR("Regular Expression Error"));
+ self->lbl_preview_title->set_text(TTR("Regular Expression Error:"));
self->lbl_preview->add_theme_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_theme_color("error_color", "Editor"));
self->lbl_preview->set_text(vformat(TTR("At character %s"), err_str));
}