diff options
Diffstat (limited to 'editor')
-rw-r--r-- | editor/connections_dialog.cpp | 58 | ||||
-rw-r--r-- | editor/connections_dialog.h | 3 | ||||
-rw-r--r-- | editor/editor_about.cpp | 7 | ||||
-rw-r--r-- | editor/editor_export.cpp | 9 | ||||
-rw-r--r-- | editor/editor_export.h | 4 | ||||
-rw-r--r-- | editor/editor_properties.cpp | 33 | ||||
-rw-r--r-- | editor/editor_settings.cpp | 1 | ||||
-rw-r--r-- | editor/filesystem_dock.cpp | 47 | ||||
-rw-r--r-- | editor/filesystem_dock.h | 1 | ||||
-rw-r--r-- | editor/icons/GuiToggleOff.svg | 2 | ||||
-rw-r--r-- | editor/icons/GuiToggleOn.svg | 2 | ||||
-rw-r--r-- | editor/plugins/node_3d_editor_plugin.cpp | 34 | ||||
-rw-r--r-- | editor/plugins/sprite_frames_editor_plugin.cpp | 186 | ||||
-rw-r--r-- | editor/plugins/sprite_frames_editor_plugin.h | 25 | ||||
-rw-r--r-- | editor/plugins/tile_set_editor_plugin.cpp | 18 | ||||
-rw-r--r-- | editor/project_settings_editor.cpp | 36 | ||||
-rw-r--r-- | editor/project_settings_editor.h | 4 | ||||
-rw-r--r-- | editor/property_selector.cpp | 27 | ||||
-rw-r--r-- | editor/rename_dialog.cpp | 29 |
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)); } |