diff options
32 files changed, 291 insertions, 210 deletions
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index de10fe1376..0ad2479b05 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -1786,6 +1786,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p if (f->get_error() != OK && f->get_error() != ERR_FILE_EOF) { f->close(); + memdelete(f); return ERR_CANT_CREATE; } @@ -1938,10 +1939,12 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p if (f->get_error() != OK && f->get_error() != ERR_FILE_EOF) { f->close(); + memdelete(f); return ERR_CANT_CREATE; } f->close(); + memdelete(f); return OK; } diff --git a/editor/collada/collada.cpp b/editor/collada/collada.cpp index aea7f461f1..1bb49a4167 100644 --- a/editor/collada/collada.cpp +++ b/editor/collada/collada.cpp @@ -28,8 +28,6 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef TOOLS_ENABLED - #include "collada.h" #include <stdio.h> @@ -2576,5 +2574,3 @@ Error Collada::load(const String &p_path, int p_flags) { Collada::Collada() { } - -#endif diff --git a/editor/collada/collada.h b/editor/collada/collada.h index 9ed62b46b7..317c3f1d37 100644 --- a/editor/collada/collada.h +++ b/editor/collada/collada.h @@ -28,8 +28,6 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef TOOLS_ENABLED - #ifndef COLLADA_H #define COLLADA_H @@ -647,5 +645,3 @@ private: // private stuff }; #endif // COLLADA_H - -#endif diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index 8a8d52c6f1..d5f0dc01ee 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -191,34 +191,41 @@ void CreateDialog::add_type(const String &p_type, HashMap<String, TreeItem *> &p item->set_custom_color(0, get_color("disabled_font_color", "Editor")); item->set_selectable(0, false); } else if (!(*to_select && (*to_select)->get_text(0) == search_box->get_text())) { - bool current_type_prefered = _is_type_prefered(p_type); - bool selected_type_prefered = *to_select ? _is_type_prefered((*to_select)->get_text(0).split(" ")[0]) : false; - String search_term = search_box->get_text().to_lower(); - bool is_subsequence_of_type = search_box->get_text().is_subsequence_ofi(p_type); - bool is_substring_of_type = p_type.to_lower().find(search_term) >= 0; - bool is_substring_of_selected = false; - bool is_subsequence_of_selected = false; - bool is_selected_equal = false; - - if (*to_select) { - String name = (*to_select)->get_text(0).split(" ")[0].to_lower(); - is_substring_of_selected = name.find(search_term) >= 0; - is_subsequence_of_selected = search_term.is_subsequence_of(name); - is_selected_equal = name == search_term; - } - if (is_subsequence_of_type && !is_selected_equal) { - if (is_substring_of_type) { - if (!is_substring_of_selected || (current_type_prefered && !selected_type_prefered)) { - *to_select = item; - } - } else { - // substring results weigh more than subsequences, so let's make sure we don't override them - if (!is_substring_of_selected) { - if (!is_subsequence_of_selected || (current_type_prefered && !selected_type_prefered)) { + // if the node name matches exactly as the search, the node should be selected. + // this also fixes when the user clicks on recent nodes. + if (p_type.to_lower() == search_term) { + *to_select = item; + } else { + bool current_type_prefered = _is_type_prefered(p_type); + bool selected_type_prefered = *to_select ? _is_type_prefered((*to_select)->get_text(0).split(" ")[0]) : false; + + bool is_subsequence_of_type = search_box->get_text().is_subsequence_ofi(p_type); + bool is_substring_of_type = p_type.to_lower().find(search_term) >= 0; + bool is_substring_of_selected = false; + bool is_subsequence_of_selected = false; + bool is_selected_equal = false; + + if (*to_select) { + String name = (*to_select)->get_text(0).split(" ")[0].to_lower(); + is_substring_of_selected = name.find(search_term) >= 0; + is_subsequence_of_selected = search_term.is_subsequence_of(name); + is_selected_equal = name == search_term; + } + + if (is_subsequence_of_type && !is_selected_equal) { + if (is_substring_of_type) { + if (!is_substring_of_selected || (current_type_prefered && !selected_type_prefered)) { *to_select = item; } + } else { + // substring results weigh more than subsequences, so let's make sure we don't override them + if (!is_substring_of_selected) { + if (!is_subsequence_of_selected || (current_type_prefered && !selected_type_prefered)) { + *to_select = item; + } + } } } } diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 8b3e108690..a76d34e122 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -1044,7 +1044,6 @@ void EditorInspectorSection::_notification(int p_what) { Ref<Font> font = get_font("font", "Tree"); Ref<Texture> arrow; -#ifdef TOOLS_ENABLED if (foldable) { if (object->editor_is_section_unfolded(section)) { arrow = get_icon("arrow_up", "Tree"); @@ -1052,7 +1051,6 @@ void EditorInspectorSection::_notification(int p_what) { arrow = get_icon("arrow", "Tree"); } } -#endif Size2 size = get_size(); Point2 offset; @@ -1087,7 +1085,6 @@ void EditorInspectorSection::_notification(int p_what) { Ref<Texture> arrow; -#ifdef TOOLS_ENABLED if (foldable) { if (object->editor_is_section_unfolded(section)) { arrow = get_icon("arrow_up", "Tree"); @@ -1095,7 +1092,6 @@ void EditorInspectorSection::_notification(int p_what) { arrow = get_icon("arrow", "Tree"); } } -#endif Ref<Font> font = get_font("font", "Tree"); @@ -1155,7 +1151,6 @@ void EditorInspectorSection::setup(const String &p_section, const String &p_labe vbox_added = true; } -#ifdef TOOLS_ENABLED if (foldable) { _test_unfold(); if (object->editor_is_section_unfolded(section)) { @@ -1164,7 +1159,6 @@ void EditorInspectorSection::setup(const String &p_section, const String &p_labe vbox->hide(); } } -#endif } void EditorInspectorSection::_gui_input(const Ref<InputEvent> &p_event) { @@ -1172,7 +1166,6 @@ void EditorInspectorSection::_gui_input(const Ref<InputEvent> &p_event) { if (!foldable) return; -#ifdef TOOLS_ENABLED Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { @@ -1191,7 +1184,6 @@ void EditorInspectorSection::_gui_input(const Ref<InputEvent> &p_event) { vbox->hide(); } } -#endif } VBoxContainer *EditorInspectorSection::get_vbox() { @@ -1205,11 +1197,9 @@ void EditorInspectorSection::unfold() { _test_unfold(); -#ifdef TOOLS_ENABLED object->editor_set_section_unfold(section, true); vbox->show(); update(); -#endif } void EditorInspectorSection::fold() { @@ -1219,11 +1209,9 @@ void EditorInspectorSection::fold() { if (!vbox_added) return; //kinda pointless -#ifdef TOOLS_ENABLED object->editor_set_section_unfold(section, false); vbox->hide(); update(); -#endif } void EditorInspectorSection::_bind_methods() { diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 635f6d4fc7..8ed6cec779 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -2632,11 +2632,8 @@ void EditorNode::_exit_editor() { resource_preview->stop(); //stop early to avoid crashes _save_docks(); - // Dim the editor window while it's quitting to make it clearer that it's busy. - // No transition is applied, as the effect needs to be visible immediately - float c = 0.4f; - Color dim_color = Color(c, c, c); - gui_base->set_modulate(dim_color); + // Dim the editor window while it's quitting to make it clearer that it's busy + dim_editor(true, true); get_tree()->quit(); } @@ -5133,46 +5130,12 @@ void EditorNode::_open_imported() { load_scene(open_import_request, true, false, true, true); } -void EditorNode::dim_editor(bool p_dimming) { - static int dim_count = 0; - bool dim_ui = EditorSettings::get_singleton()->get("interface/editor/dim_editor_on_dialog_popup"); - if (p_dimming) { - if (dim_ui && dim_count == 0) { - _start_dimming(true); - } - dim_count++; - } else { - if (dim_count == 1) { - _start_dimming(false); - } - if (dim_count > 0) { - dim_count--; - } else { - ERR_PRINT("Undimmed before dimming!"); - } - } -} - -void EditorNode::_start_dimming(bool p_dimming) { - _dimming = p_dimming; - _dim_time = 0.0f; - _dim_timer->start(); -} - -void EditorNode::_dim_timeout() { - - _dim_time += _dim_timer->get_wait_time(); - float wait_time = 0.08f; - float c = 0.4f; - - Color base = _dimming ? Color(1, 1, 1) : Color(c, c, c); - Color final = _dimming ? Color(c, c, c) : Color(1, 1, 1); - - if (_dim_time + _dim_timer->get_wait_time() >= wait_time) { - gui_base->set_modulate(final); - _dim_timer->stop(); +void EditorNode::dim_editor(bool p_dimming, bool p_force_dim) { + // Dimming can be forced regardless of the editor setting, which is useful when quitting the editor + if ((p_force_dim || EditorSettings::get_singleton()->get("interface/editor/dim_editor_on_dialog_popup")) && p_dimming) { + gui_base->set_modulate(Color(0.5, 0.5, 0.5)); } else { - gui_base->set_modulate(base.linear_interpolate(final, _dim_time / wait_time)); + gui_base->set_modulate(Color(1, 1, 1)); } } @@ -5356,7 +5319,6 @@ void EditorNode::_bind_methods() { ClassDB::bind_method(D_METHOD("_open_imported"), &EditorNode::_open_imported); ClassDB::bind_method(D_METHOD("_inherit_imported"), &EditorNode::_inherit_imported); - ClassDB::bind_method(D_METHOD("_dim_timeout"), &EditorNode::_dim_timeout); ClassDB::bind_method("_copy_warning", &EditorNode::_copy_warning); @@ -5818,6 +5780,7 @@ EditorNode::EditorNode() { dock_slot[i]->set_drag_to_rearrange_enabled(true); dock_slot[i]->set_tabs_rearrange_group(1); dock_slot[i]->connect("tab_changed", this, "_dock_tab_changed"); + dock_slot[i]->set_use_hidden_tabs_for_min_size(true); } dock_drag_timer = memnew(Timer); @@ -6411,13 +6374,13 @@ EditorNode::EditorNode() { gui_base->add_child(custom_build_manage_templates); install_android_build_template = memnew(ConfirmationDialog); - install_android_build_template->set_text(TTR("This will install the Android project for custom builds.\nNote that, in order to use it, it needs to be enabled per export preset.")); + install_android_build_template->set_text(TTR("This will set up your project for custom Android builds by installing the source template to \"res://android/build\".\nYou can then apply modifications and build your own custom APK on export (adding modules, changing the AndroidManifest.xml, etc.).\nNote that in order to make custom builds instead of using pre-built APKs, the \"Use Custom Build\" option should be enabled in the Android export preset.")); install_android_build_template->get_ok()->set_text(TTR("Install")); install_android_build_template->connect("confirmed", this, "_menu_confirm_current"); gui_base->add_child(install_android_build_template); remove_android_build_template = memnew(ConfirmationDialog); - remove_android_build_template->set_text(TTR("Android build template is already installed and it won't be overwritten.\nRemove the \"build\" directory manually before attempting this operation again.")); + remove_android_build_template->set_text(TTR("The Android build template is already installed in this project and it won't be overwritten.\nRemove the \"res://android/build\" directory manually before attempting this operation again.")); remove_android_build_template->get_ok()->set_text(TTR("Show in File Manager")); remove_android_build_template->connect("confirmed", this, "_menu_option", varray(FILE_EXPLORE_ANDROID_BUILD_TEMPLATES)); gui_base->add_child(remove_android_build_template); @@ -6687,13 +6650,6 @@ EditorNode::EditorNode() { waiting_for_first_scan = true; - _dimming = false; - _dim_time = 0.0f; - _dim_timer = memnew(Timer); - _dim_timer->set_wait_time(0.01666f); - _dim_timer->connect("timeout", this, "_dim_timeout"); - add_child(_dim_timer); - print_handler.printfunc = _print_handler; print_handler.userdata = this; add_print_handler(&print_handler); diff --git a/editor/editor_node.h b/editor/editor_node.h index 61bbb7b86d..54bcf14c1b 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -633,13 +633,6 @@ private: static int build_callback_count; static EditorBuildCallback build_callbacks[MAX_BUILD_CALLBACKS]; - bool _dimming; - float _dim_time; - Timer *_dim_timer; - - void _start_dimming(bool p_dimming); - void _dim_timeout(); - void _license_tree_selected(); void _update_update_spinner(); @@ -849,7 +842,7 @@ public: void save_scene_list(Vector<String> p_scene_filenames); void restart_editor(); - void dim_editor(bool p_dimming); + void dim_editor(bool p_dimming, bool p_force_dim = false); void edit_current() { _edit_current(); }; diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 378dd34e39..d7b3c7733b 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -2540,7 +2540,7 @@ void EditorPropertyResource::update_property() { if (res.is_valid() != assign->is_toggle_mode()) { assign->set_toggle_mode(res.is_valid()); } -#ifdef TOOLS_ENABLED + if (res.is_valid() && get_edited_object()->editor_is_section_unfolded(get_edited_property())) { if (!sub_inspector) { @@ -2609,7 +2609,6 @@ void EditorPropertyResource::update_property() { } } } -#endif } preview->set_texture(Ref<Texture>()); diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index d1371a04b1..ff19be8bd5 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -271,8 +271,6 @@ void EditorPropertyArray::update_property() { edit->set_text(arrtype + " (size " + itos(array.call("size")) + ")"); -#ifdef TOOLS_ENABLED - bool unfolded = get_edited_object()->editor_is_section_unfolded(get_edited_property()); if (edit->is_pressed() != unfolded) { edit->set_pressed(unfolded); @@ -397,7 +395,6 @@ void EditorPropertyArray::update_property() { vbox = NULL; } } -#endif } void EditorPropertyArray::_remove_pressed(int p_index) { @@ -643,8 +640,6 @@ void EditorPropertyDictionary::update_property() { edit->set_text("Dictionary (size " + itos(dict.size()) + ")"); -#ifdef TOOLS_ENABLED - bool unfolded = get_edited_object()->editor_is_section_unfolded(get_edited_property()); if (edit->is_pressed() != unfolded) { edit->set_pressed(unfolded); @@ -959,7 +954,6 @@ void EditorPropertyDictionary::update_property() { vbox = NULL; } } -#endif } void EditorPropertyDictionary::_object_id_selected(const String &p_property, ObjectID p_id) { diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 56eed96e31..c15d24719f 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -108,16 +108,17 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme = #ifdef SVG_ENABLED Dictionary dark_icon_color_dictionary; if (!p_dark_theme) { - //convert color: FROM TO - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#e0e0e0", "#4f4f4f"); // common icon color - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ffffff", "#000000"); // white - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#b4b4b4", "#000000"); // script darker color + // convert color: FROM TO + ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#e0e0e0", "#5a5a5a"); // common icon color + ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ffffff", "#414141"); // white + ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#b4b4b4", "#363636"); // script darker color + ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f9f9f9", "#606060"); // scrollbar grabber highlight color ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#cea4f1", "#a85de9"); // animation ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#fc9c9c", "#cd3838"); // spatial ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#a5b7f3", "#3d64dd"); // 2d ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#708cea", "#1a3eac"); // 2d dark - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#a5efac", "#2aa235"); // control + ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#a5efac", "#2fa139"); // control // rainbow ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ff7070", "#ff2929"); // red @@ -145,9 +146,14 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme = ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ea9568", "#bd5e2c"); // 3D Transform track ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#66f376", "#16a827"); // Call Method track ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#5792f6", "#236be6"); // Bezier Curve track - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#eae668", "#aea923"); // Audio Playback track + ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#eae668", "#9f9722"); // Audio Playback track ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#b76ef0", "#9853ce"); // Animation Playback track + // TileSet editor icons + ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#fce844", "#aa8d24"); // New Single Tile + ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#4490fc", "#0350bd"); // New Autotile + ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#c9cfd4", "#828f9b"); // New Atlas + ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#69ecbd", "#25e3a0"); // VS variant ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#8da6f0", "#6d8eeb"); // VS bool ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#7dc6ef", "#4fb2e9"); // VS int @@ -339,6 +345,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { const Color color_disabled = mono_color.inverted().linear_interpolate(base_color, 0.7); const Color color_disabled_bg = mono_color.inverted().linear_interpolate(base_color, 0.9); + Color icon_color_hover = Color(1, 1, 1) * (dark_theme ? 1.15 : 1.45); + icon_color_hover.a = 1.0; + // Make the pressed icon color overbright because icons are not completely white on a dark theme. + // On a light theme, icons are dark, so we need to modulate them with an even brighter color. + Color icon_color_pressed = accent_color * (dark_theme ? 1.15 : 3.5); + icon_color_pressed.a = 1.0; + const Color separator_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.1); const Color highlight_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.2); @@ -565,9 +578,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_color_hover", "Button", font_color_hl); theme->set_color("font_color_pressed", "Button", accent_color); theme->set_color("font_color_disabled", "Button", font_color_disabled); - theme->set_color("icon_color_hover", "Button", font_color_hl); - // make icon color value bigger because icon image is not complete white - theme->set_color("icon_color_pressed", "Button", Color(accent_color.r * 1.15, accent_color.g * 1.15, accent_color.b * 1.15, accent_color.a)); + theme->set_color("icon_color_hover", "Button", icon_color_hover); + theme->set_color("icon_color_pressed", "Button", icon_color_pressed); // OptionButton theme->set_stylebox("normal", "OptionButton", style_widget); @@ -580,7 +592,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_color_hover", "OptionButton", font_color_hl); theme->set_color("font_color_pressed", "OptionButton", accent_color); theme->set_color("font_color_disabled", "OptionButton", font_color_disabled); - theme->set_color("icon_color_hover", "OptionButton", font_color_hl); + theme->set_color("icon_color_hover", "OptionButton", icon_color_hover); theme->set_icon("arrow", "OptionButton", theme->get_icon("GuiOptionArrow", "EditorIcons")); theme->set_constant("arrow_margin", "OptionButton", default_margin_size * EDSCALE); theme->set_constant("modulate_arrow", "OptionButton", true); @@ -601,7 +613,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_color_hover", "CheckButton", font_color_hl); theme->set_color("font_color_pressed", "CheckButton", accent_color); theme->set_color("font_color_disabled", "CheckButton", font_color_disabled); - theme->set_color("icon_color_hover", "CheckButton", font_color_hl); + theme->set_color("icon_color_hover", "CheckButton", icon_color_hover); theme->set_constant("hseparation", "CheckButton", 4 * EDSCALE); theme->set_constant("check_vadjust", "CheckButton", 0 * EDSCALE); @@ -626,7 +638,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_color_hover", "CheckBox", font_color_hl); theme->set_color("font_color_pressed", "CheckBox", accent_color); theme->set_color("font_color_disabled", "CheckBox", font_color_disabled); - theme->set_color("icon_color_hover", "CheckBox", font_color_hl); + theme->set_color("icon_color_hover", "CheckBox", icon_color_hover); theme->set_constant("hseparation", "CheckBox", 4 * EDSCALE); theme->set_constant("check_vadjust", "CheckBox", 0 * EDSCALE); @@ -983,8 +995,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // GraphEdit theme->set_stylebox("bg", "GraphEdit", style_tree_bg); - theme->set_color("grid_major", "GraphEdit", Color(1.0, 1.0, 1.0, 0.15)); - theme->set_color("grid_minor", "GraphEdit", Color(1.0, 1.0, 1.0, 0.07)); + if (dark_theme) { + theme->set_color("grid_major", "GraphEdit", Color(1.0, 1.0, 1.0, 0.15)); + theme->set_color("grid_minor", "GraphEdit", Color(1.0, 1.0, 1.0, 0.07)); + } else { + theme->set_color("grid_major", "GraphEdit", Color(0.0, 0.0, 0.0, 0.15)); + theme->set_color("grid_minor", "GraphEdit", Color(0.0, 0.0, 0.0, 0.07)); + } theme->set_color("activity", "GraphEdit", accent_color); theme->set_icon("minus", "GraphEdit", theme->get_icon("ZoomLess", "EditorIcons")); theme->set_icon("more", "GraphEdit", theme->get_icon("ZoomMore", "EditorIcons")); @@ -1068,7 +1085,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_icon("folder", "FileDialog", theme->get_icon("Folder", "EditorIcons")); // Use a different color for folder icons to make them easier to distinguish from files. // On a light theme, the icon will be dark, so we need to lighten it before blending it with the accent color. - theme->set_color("folder_icon_modulate", "FileDialog", (dark_theme ? Color(1, 1, 1) : Color(5, 5, 5)).linear_interpolate(accent_color, 0.7)); + theme->set_color("folder_icon_modulate", "FileDialog", (dark_theme ? Color(1, 1, 1) : Color(4.25, 4.25, 4.25)).linear_interpolate(accent_color, 0.7)); theme->set_color("files_disabled", "FileDialog", font_color_disabled); // color picker diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp index 1447a143d4..536cfaa1dd 100644 --- a/editor/export_template_manager.cpp +++ b/editor/export_template_manager.cpp @@ -542,7 +542,6 @@ void ExportTemplateManager::_notification(int p_what) { template_list_state->set_text(status); if (errored) { set_process(false); - ; } } @@ -555,25 +554,33 @@ void ExportTemplateManager::_notification(int p_what) { bool ExportTemplateManager::can_install_android_template() { - return FileAccess::exists(EditorSettings::get_singleton()->get_templates_dir().plus_file(VERSION_FULL_CONFIG).plus_file("android_source.zip")); + const String templates_dir = EditorSettings::get_singleton()->get_templates_dir().plus_file(VERSION_FULL_CONFIG); + return FileAccess::exists(templates_dir.plus_file("android_source.zip")) && + FileAccess::exists(templates_dir.plus_file("android_release.apk")) && + FileAccess::exists(templates_dir.plus_file("android_debug.apk")); } Error ExportTemplateManager::install_android_template() { + // To support custom Android builds, we install various things to the project's res://android folder. + // First is the Java source code and buildsystem from android_source.zip. + // Then we extract the Godot Android libraries from pre-build android_release.apk + // and android_debug.apk, to place them in the libs folder. + DirAccessRef da = DirAccess::open("res://"); ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); - //make android dir (if it does not exist) + // Make res://android dir (if it does not exist). da->make_dir("android"); { - //add an empty .gdignore file to avoid scan + // Add an empty .gdignore file to avoid scan. FileAccessRef f = FileAccess::open("res://android/.gdignore", FileAccess::WRITE); ERR_FAIL_COND_V(!f, ERR_CANT_CREATE); f->store_line(""); f->close(); } { - //add version, to ensure building won't work if template and Godot version don't match + // Add version, to ensure building won't work if template and Godot version don't match. FileAccessRef f = FileAccess::open("res://android/.build_version", FileAccess::WRITE); ERR_FAIL_COND_V(!f, ERR_CANT_CREATE); f->store_line(VERSION_FULL_CONFIG); @@ -583,7 +590,10 @@ Error ExportTemplateManager::install_android_template() { Error err = da->make_dir_recursive("android/build"); ERR_FAIL_COND_V(err != OK, err); - String source_zip = EditorSettings::get_singleton()->get_templates_dir().plus_file(VERSION_FULL_CONFIG).plus_file("android_source.zip"); + // Uncompress source template. + + const String &templates_path = EditorSettings::get_singleton()->get_templates_dir().plus_file(VERSION_FULL_CONFIG); + const String &source_zip = templates_path.plus_file("android_source.zip"); ERR_FAIL_COND_V(!FileAccess::exists(source_zip), ERR_CANT_OPEN); FileAccess *src_f = NULL; @@ -593,37 +603,33 @@ Error ExportTemplateManager::install_android_template() { ERR_FAIL_COND_V_MSG(!pkg, ERR_CANT_OPEN, "Android sources not in ZIP format."); int ret = unzGoToFirstFile(pkg); - int total_files = 0; - //count files + // Count files to unzip. while (ret == UNZ_OK) { total_files++; ret = unzGoToNextFile(pkg); } - ret = unzGoToFirstFile(pkg); - //decompress files - ProgressDialog::get_singleton()->add_task("uncompress", TTR("Uncompressing Android Build Sources"), total_files); - Set<String> dirs_tested; + ProgressDialog::get_singleton()->add_task("uncompress_src", TTR("Uncompressing Android Build Sources"), total_files); + Set<String> dirs_tested; int idx = 0; while (ret == UNZ_OK) { - //get filename + // Get file path. unz_file_info info; - char fname[16384]; - ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, NULL, 0, NULL, 0); - - String name = fname; + char fpath[16384]; + ret = unzGetCurrentFileInfo(pkg, &info, fpath, 16384, NULL, 0, NULL, 0); - String base_dir = name.get_base_dir(); + String path = fpath; + String base_dir = path.get_base_dir(); - if (!name.ends_with("/")) { + if (!path.ends_with("/")) { Vector<uint8_t> data; data.resize(info.uncompressed_size); - //read + // Read. unzOpenCurrentFile(pkg); unzReadCurrentFile(pkg, data.ptrw(), data.size()); unzCloseCurrentFile(pkg); @@ -633,7 +639,7 @@ Error ExportTemplateManager::install_android_template() { dirs_tested.insert(base_dir); } - String to_write = String("res://android/build").plus_file(name); + String to_write = String("res://android/build").plus_file(path); FileAccess *f = FileAccess::open(to_write, FileAccess::WRITE); if (f) { f->store_buffer(data.ptr(), data.size()); @@ -646,13 +652,96 @@ Error ExportTemplateManager::install_android_template() { } } - ProgressDialog::get_singleton()->task_step("uncompress", name, idx); + ProgressDialog::get_singleton()->task_step("uncompress_src", path, idx); + + idx++; + ret = unzGoToNextFile(pkg); + } + + ProgressDialog::get_singleton()->end_task("uncompress_src"); + unzClose(pkg); + + // Extract libs from pre-built APKs. + err = _extract_libs_from_apk("release"); + ERR_FAIL_COND_V_MSG(err != OK, err, "Can't extract Android libs from android_release.apk."); + err = _extract_libs_from_apk("debug"); + ERR_FAIL_COND_V_MSG(err != OK, err, "Can't extract Android libs from android_debug.apk."); + + return OK; +} + +Error ExportTemplateManager::_extract_libs_from_apk(const String &p_target_name) { + + const String &templates_path = EditorSettings::get_singleton()->get_templates_dir().plus_file(VERSION_FULL_CONFIG); + const String &apk_file = templates_path.plus_file("android_" + p_target_name + ".apk"); + ERR_FAIL_COND_V(!FileAccess::exists(apk_file), ERR_CANT_OPEN); + + FileAccess *src_f = NULL; + zlib_filefunc_def io = zipio_create_io_from_file(&src_f); + + unzFile pkg = unzOpen2(apk_file.utf8().get_data(), &io); + ERR_FAIL_COND_V_MSG(!pkg, ERR_CANT_OPEN, "Android APK can't be extracted."); + + DirAccessRef da = DirAccess::open("res://"); + ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); + + // 8 steps because 4 arches, 2 libs per arch. + ProgressDialog::get_singleton()->add_task("extract_libs_from_apk", TTR("Extracting Android Libraries From APKs"), 8); + + int ret = unzGoToFirstFile(pkg); + Set<String> dirs_tested; + int idx = 0; + while (ret == UNZ_OK) { + // Get file path. + unz_file_info info; + char fpath[16384]; + ret = unzGetCurrentFileInfo(pkg, &info, fpath, 16384, NULL, 0, NULL, 0); + + String path = fpath; + String base_dir = path.get_base_dir(); + String file = path.get_file(); + + if (!base_dir.begins_with("lib") || path.ends_with("/")) { + ret = unzGoToNextFile(pkg); + continue; + } + + Vector<uint8_t> data; + data.resize(info.uncompressed_size); + + // Read. + unzOpenCurrentFile(pkg); + unzReadCurrentFile(pkg, data.ptrw(), data.size()); + unzCloseCurrentFile(pkg); + + // We have a "lib" folder in the APK, but it should be "libs/{release,debug}" in the source dir. + String target_base_dir = base_dir.replace_first("lib", String("libs").plus_file(p_target_name)); + + if (!dirs_tested.has(base_dir)) { + da->make_dir_recursive(String("android/build").plus_file(target_base_dir)); + dirs_tested.insert(base_dir); + } + + String to_write = String("res://android/build").plus_file(target_base_dir.plus_file(path.get_file())); + FileAccess *f = FileAccess::open(to_write, FileAccess::WRITE); + if (f) { + f->store_buffer(data.ptr(), data.size()); + memdelete(f); +#ifndef WINDOWS_ENABLED + // We can't retrieve Unix permissions from the APK it seems, so simply set 0755 as should be. + FileAccess::set_unix_permissions(to_write, 0755); +#endif + } else { + ERR_PRINTS("Can't uncompress file: " + to_write); + } + + ProgressDialog::get_singleton()->task_step("extract_libs_from_apk", path, idx); idx++; ret = unzGoToNextFile(pkg); } - ProgressDialog::get_singleton()->end_task("uncompress"); + ProgressDialog::get_singleton()->end_task("extract_libs_from_apk"); unzClose(pkg); return OK; diff --git a/editor/export_template_manager.h b/editor/export_template_manager.h index ad3ab507b3..ecb8e85b21 100644 --- a/editor/export_template_manager.h +++ b/editor/export_template_manager.h @@ -72,6 +72,8 @@ class ExportTemplateManager : public ConfirmationDialog { virtual void ok_pressed(); bool _install_from_file(const String &p_file, bool p_use_progress = true); + Error _extract_libs_from_apk(const String &p_target_name); + void _http_download_mirror_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data); void _http_download_templates_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data); diff --git a/editor/import/resource_importer_wav.cpp b/editor/import/resource_importer_wav.cpp index 4fd4ab2f2e..f1de71e25e 100644 --- a/editor/import/resource_importer_wav.cpp +++ b/editor/import/resource_importer_wav.cpp @@ -83,8 +83,8 @@ void ResourceImporterWAV::get_import_options(List<ImportOption> *r_options, int r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "force/mono"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "force/max_rate", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "force/max_rate_hz", PROPERTY_HINT_EXP_RANGE, "11025,192000,1"), 44100)); - r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "edit/trim"), true)); - r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "edit/normalize"), true)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "edit/trim"), false)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "edit/normalize"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "edit/loop"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode", PROPERTY_HINT_ENUM, "Disabled,RAM (Ima-ADPCM)"), 0)); } diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index bded590351..edc454ad1c 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -1436,8 +1436,6 @@ bool ScriptTextEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_ return false; } -#ifdef TOOLS_ENABLED - static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const Ref<Script> &script) { if (p_edited_scene != p_current_node && p_current_node->get_owner() != p_edited_scene) @@ -1457,14 +1455,6 @@ static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const return NULL; } -#else - -static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const Ref<Script> &script) { - - return NULL; -} -#endif - void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) { Dictionary d = p_data; diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 2eb3ce1ec3..ecc631d045 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -74,14 +74,6 @@ #define MIN_FOV 0.01 #define MAX_FOV 179 -#ifdef TOOLS_ENABLED -#define get_global_gizmo_transform get_global_gizmo_transform -#define get_local_gizmo_transform get_local_gizmo_transform -#else -#define get_global_gizmo_transform get_global_transform -#define get_local_gizmo_transform get_transform -#endif - void SpatialEditorViewport::_update_camera(float p_interp_delta) { bool is_orthogonal = camera->get_projection() == Camera::PROJECTION_ORTHOGONAL; @@ -5298,6 +5290,10 @@ void SpatialEditor::_notification(int p_what) { tool_button[SpatialEditor::TOOL_MODE_ROTATE]->set_icon(get_icon("ToolRotate", "EditorIcons")); tool_button[SpatialEditor::TOOL_MODE_SCALE]->set_icon(get_icon("ToolScale", "EditorIcons")); tool_button[SpatialEditor::TOOL_MODE_LIST_SELECT]->set_icon(get_icon("ListSelect", "EditorIcons")); + tool_button[SpatialEditor::TOOL_LOCK_SELECTED]->set_icon(get_icon("Lock", "EditorIcons")); + tool_button[SpatialEditor::TOOL_UNLOCK_SELECTED]->set_icon(get_icon("Unlock", "EditorIcons")); + tool_button[SpatialEditor::TOOL_GROUP_SELECTED]->set_icon(get_icon("Group", "EditorIcons")); + tool_button[SpatialEditor::TOOL_UNGROUP_SELECTED]->set_icon(get_icon("Ungroup", "EditorIcons")); tool_option_button[SpatialEditor::TOOL_OPT_LOCAL_COORDS]->set_icon(get_icon("Object", "EditorIcons")); tool_option_button[SpatialEditor::TOOL_OPT_USE_SNAP]->set_icon(get_icon("Snap", "EditorIcons")); diff --git a/editor/project_export.cpp b/editor/project_export.cpp index 956da92c35..c54103f6f7 100644 --- a/editor/project_export.cpp +++ b/editor/project_export.cpp @@ -1116,6 +1116,7 @@ ProjectExportDialog::ProjectExportDialog() { sections = memnew(TabContainer); sections->set_tab_align(TabContainer::ALIGN_LEFT); + sections->set_use_hidden_tabs_for_min_size(true); settings_vb->add_child(sections); sections->set_v_size_flags(SIZE_EXPAND_FILL); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 98335c8367..c6e3dc1e32 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -1754,7 +1754,7 @@ void ProjectManager::_dim_window() { // Dim the project manager window while it's quitting to make it clearer that it's busy. // No transition is applied, as the effect needs to be visible immediately - float c = 0.4f; + float c = 0.5f; Color dim_color = Color(c, c, c); gui_base->set_modulate(dim_color); } diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index 1c588a45f1..a0d2332ffc 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -1674,6 +1674,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { tab_container = memnew(TabContainer); tab_container->set_tab_align(TabContainer::ALIGN_LEFT); + tab_container->set_use_hidden_tabs_for_min_size(true); add_child(tab_container); VBoxContainer *props_base = memnew(VBoxContainer); diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj index c745fe321b..ab3a5d1aea 100644 --- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj @@ -37,9 +37,8 @@ entire solution. $(SolutionDir) is not defined in that case, so we need to workaround that. We make SCons restore the NuGet packages in the project directory instead in this case. --> - <HintPath Condition=" '$(SolutionDir)' != '' ">$(SolutionDir)\packages\DotNet.Glob.2.1.1\lib\net45\DotNet.Glob.dll</HintPath> - <HintPath>$(ProjectDir)\packages\DotNet.Glob.2.1.1\lib\net45\DotNet.Glob.dll</HintPath> - <HintPath>packages\DotNet.Glob.2.1.1\lib\net45\DotNet.Glob.dll</HintPath> <!-- Are you happy CI? --> + <HintPath Condition=" '$(SolutionDir)' != '' And Exists('$(SolutionDir)\packages\DotNet.Glob.2.1.1\lib\net45\DotNet.Glob.dll') ">$(SolutionDir)\packages\DotNet.Glob.2.1.1\lib\net45\DotNet.Glob.dll</HintPath> + <HintPath Condition=" '$(SolutionDir)' == '' Or !Exists('$(SolutionDir)\packages\DotNet.Glob.2.1.1\lib\net45\DotNet.Glob.dll') ">$(ProjectDir)\packages\DotNet.Glob.2.1.1\lib\net45\DotNet.Glob.dll</HintPath> </Reference> </ItemGroup> <ItemGroup> diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index aa69803a58..cd111abd4d 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -317,6 +317,13 @@ void GDMono::initialize() { return; #endif +#if !defined(WINDOWS_ENABLED) && !defined(NO_MONO_THREADS_SUSPEND_WORKAROUND) + // FIXME: Temporary workaround. See: https://github.com/godotengine/godot/issues/29812 + if (!OS::get_singleton()->has_environment("MONO_THREADS_SUSPEND")) { + OS::get_singleton()->set_environment("MONO_THREADS_SUSPEND", "preemptive"); + } +#endif + root_domain = mono_jit_init_version("GodotEngine.RootDomain", "v4.0.30319"); ERR_FAIL_NULL_MSG(root_domain, "Mono: Failed to initialize runtime."); diff --git a/platform/android/SCsub b/platform/android/SCsub index d2f27817c6..1bd8161fa7 100644 --- a/platform/android/SCsub +++ b/platform/android/SCsub @@ -55,3 +55,25 @@ if lib_arch_dir != '': stl_lib_path = str(env['ANDROID_NDK_ROOT']) + '/sources/cxx-stl/llvm-libc++/libs/' + lib_arch_dir + '/libc++_shared.so' env_android.Command(out_dir + '/libc++_shared.so', stl_lib_path, Copy("$TARGET", "$SOURCE")) + +# Zip android/java folder for the source export template. +print("Archiving platform/android/java as bin/android_source.zip...") +import os +import zipfile +# Change dir to avoid have zipped paths start from the android/java folder. +olddir = os.getcwd() +os.chdir(Dir('#platform/android/java').abspath) +bindir = Dir('#bin').abspath +# Make 'bin' dir if missing, can happen on fresh clone. +if not os.path.exists(bindir): + os.makedirs(bindir) +zipf = zipfile.ZipFile(os.path.join(bindir, 'android_source.zip'), 'w', zipfile.ZIP_DEFLATED) +exclude_dirs = ['.gradle', 'build', 'libs', 'patches'] +for root, dirs, files in os.walk('.', topdown=True): + # Change 'dirs' in place to exclude folders we don't want. + # https://stackoverflow.com/a/19859907 + dirs[:] = [d for d in dirs if d not in exclude_dirs] + for f in files: + zipf.write(os.path.join(root, f)) +zipf.close() +os.chdir(olddir) diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 16e49e8a38..441fa38bff 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -1610,19 +1610,16 @@ public: valid = false; } else { Error errn; - DirAccess *da = DirAccess::open(sdk_path.plus_file("tools"), &errn); + DirAccessRef da = DirAccess::open(sdk_path.plus_file("tools"), &errn); if (errn != OK) { err += TTR("Invalid Android SDK path for custom build in Editor Settings.") + "\n"; valid = false; } - if (da) { - memdelete(da); - } } if (!FileAccess::exists("res://android/build/build.gradle")) { - err += TTR("Android project is not installed for compiling. Install from Editor menu.") + "\n"; + err += TTR("Android build template not installed in the project. Install it from the Project menu.") + "\n"; valid = false; } } @@ -2513,7 +2510,7 @@ void register_android_exporter() { EDITOR_DEF("export/android/debug_keystore_pass", "android"); EDITOR_DEF("export/android/force_system_user", false); EDITOR_DEF("export/android/custom_build_sdk_path", ""); - EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/custom_build_sdk_path", PROPERTY_HINT_GLOBAL_DIR, "*.keystore")); + EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/custom_build_sdk_path", PROPERTY_HINT_GLOBAL_DIR)); EDITOR_DEF("export/android/timestamping_authority_url", ""); EDITOR_DEF("export/android/shutdown_adb_on_exit", true); diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index 202c7c9cf2..228b67990c 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -376,11 +376,12 @@ void CollisionObject2D::set_only_update_transform_changes(bool p_enable) { void CollisionObject2D::_update_pickable() { if (!is_inside_tree()) return; - bool pickable = this->pickable && is_inside_tree() && is_visible_in_tree(); + + bool is_pickable = pickable && is_visible_in_tree(); if (area) - Physics2DServer::get_singleton()->area_set_pickable(rid, pickable); + Physics2DServer::get_singleton()->area_set_pickable(rid, is_pickable); else - Physics2DServer::get_singleton()->body_set_pickable(rid, pickable); + Physics2DServer::get_singleton()->body_set_pickable(rid, is_pickable); } String CollisionObject2D::get_configuration_warning() const { diff --git a/scene/3d/collision_object.cpp b/scene/3d/collision_object.cpp index 63301fc226..735b393171 100644 --- a/scene/3d/collision_object.cpp +++ b/scene/3d/collision_object.cpp @@ -105,7 +105,8 @@ void CollisionObject::_mouse_exit() { void CollisionObject::_update_pickable() { if (!is_inside_tree()) return; - bool pickable = ray_pickable && is_inside_tree() && is_visible_in_tree(); + + bool pickable = ray_pickable && is_visible_in_tree(); if (area) PhysicsServer::get_singleton()->area_set_ray_pickable(rid, pickable); else diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index fdffb26cb5..7827c66841 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -276,6 +276,11 @@ void GraphEdit::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { port_grab_distance_horizontal = get_constant("port_grab_distance_horizontal"); port_grab_distance_vertical = get_constant("port_grab_distance_vertical"); + + zoom_minus->set_icon(get_icon("minus")); + zoom_reset->set_icon(get_icon("reset")); + zoom_plus->set_icon(get_icon("more")); + snap_button->set_icon(get_icon("snap")); } if (p_what == NOTIFICATION_READY) { Size2 hmin = h_scroll->get_combined_minimum_size(); @@ -290,11 +295,6 @@ void GraphEdit::_notification(int p_what) { h_scroll->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 0); h_scroll->set_anchor_and_margin(MARGIN_TOP, ANCHOR_END, -hmin.height); h_scroll->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, 0); - - zoom_minus->set_icon(get_icon("minus")); - zoom_reset->set_icon(get_icon("reset")); - zoom_plus->set_icon(get_icon("more")); - snap_button->set_icon(get_icon("snap")); } if (p_what == NOTIFICATION_DRAW) { diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 8223ea6d1e..1aed858c94 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -916,9 +916,12 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const { - if (!underline_meta || selection.click) + if (!underline_meta) return CURSOR_ARROW; + if (selection.click) + return CURSOR_IBEAM; + if (main->first_invalid_line < main->lines.size()) return CURSOR_ARROW; //invalid diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index 6ada0cba97..172c366c41 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "spin_box.h" +#include "core/math/expression.h" #include "core/os/input.h" Size2 SpinBox::get_minimum_size() const { @@ -50,15 +51,19 @@ void SpinBox::_value_changed(double) { void SpinBox::_text_entered(const String &p_string) { - /* - if (!p_string.is_numeric()) + Ref<Expression> expr; + expr.instance(); + // Ignore the prefix and suffix in the expression + Error err = expr->parse(p_string.trim_prefix(prefix + " ").trim_suffix(" " + suffix)); + if (err != OK) { return; - */ - String value = p_string; - if (prefix != "" && p_string.begins_with(prefix)) - value = p_string.substr(prefix.length(), p_string.length() - prefix.length()); - set_value(value.to_double()); - _value_changed(0); + } + + Variant value = expr->execute(Array(), NULL, false); + if (value.get_type() != Variant::NIL) { + set_value(value); + _value_changed(0); + } } LineEdit *SpinBox::get_line_edit() { diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index be8f1cf36e..292d80be9d 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -840,7 +840,7 @@ Size2 TabContainer::get_minimum_size() const { Control *c = tabs[i]; - if (!c->is_visible_in_tree()) + if (!c->is_visible_in_tree() && !use_hidden_tabs_for_min_size) continue; Size2 cms = c->get_combined_minimum_size(); @@ -887,6 +887,13 @@ int TabContainer::get_tabs_rearrange_group() const { return tabs_rearrange_group; } +void TabContainer::set_use_hidden_tabs_for_min_size(bool p_use_hidden_tabs) { + use_hidden_tabs_for_min_size = p_use_hidden_tabs; +} + +bool TabContainer::get_use_hidden_tabs_for_min_size() const { + return use_hidden_tabs_for_min_size; +} void TabContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("_gui_input"), &TabContainer::_gui_input); @@ -913,6 +920,9 @@ void TabContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_tabs_rearrange_group", "group_id"), &TabContainer::set_tabs_rearrange_group); ClassDB::bind_method(D_METHOD("get_tabs_rearrange_group"), &TabContainer::get_tabs_rearrange_group); + ClassDB::bind_method(D_METHOD("set_use_hidden_tabs_for_min_size", "enabled"), &TabContainer::set_use_hidden_tabs_for_min_size); + ClassDB::bind_method(D_METHOD("get_use_hidden_tabs_for_min_size"), &TabContainer::get_use_hidden_tabs_for_min_size); + ClassDB::bind_method(D_METHOD("_child_renamed_callback"), &TabContainer::_child_renamed_callback); ClassDB::bind_method(D_METHOD("_on_theme_changed"), &TabContainer::_on_theme_changed); ClassDB::bind_method(D_METHOD("_update_current_tab"), &TabContainer::_update_current_tab); @@ -925,6 +935,7 @@ void TabContainer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE, "-1,4096,1", PROPERTY_USAGE_EDITOR), "set_current_tab", "get_current_tab"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tabs_visible"), "set_tabs_visible", "are_tabs_visible"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_to_rearrange_enabled"), "set_drag_to_rearrange_enabled", "get_drag_to_rearrange_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hidden_tabs_for_min_size"), "set_use_hidden_tabs_for_min_size", "get_use_hidden_tabs_for_min_size"); BIND_ENUM_CONSTANT(ALIGN_LEFT); BIND_ENUM_CONSTANT(ALIGN_CENTER); @@ -945,4 +956,5 @@ TabContainer::TabContainer() { popup = NULL; drag_to_rearrange_enabled = false; tabs_rearrange_group = -1; + use_hidden_tabs_for_min_size = false; } diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h index f7a9fb64fd..0314f86837 100644 --- a/scene/gui/tab_container.h +++ b/scene/gui/tab_container.h @@ -59,6 +59,7 @@ private: int _get_top_margin() const; Popup *popup; bool drag_to_rearrange_enabled; + bool use_hidden_tabs_for_min_size; int tabs_rearrange_group; Vector<Control *> _get_tabs() const; @@ -118,6 +119,8 @@ public: bool get_drag_to_rearrange_enabled() const; void set_tabs_rearrange_group(int p_group_id); int get_tabs_rearrange_group() const; + void set_use_hidden_tabs_for_min_size(bool p_use_hidden_tabs); + bool get_use_hidden_tabs_for_min_size() const; TabContainer(); }; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 1d434e5a2a..65554b1f5e 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -2194,12 +2194,6 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { int row, col; _get_mouse_pos(Point2i(mb->get_position().x, mb->get_position().y), row, col); - if (mb->get_command() && highlighted_word != String()) { - - emit_signal("symbol_lookup", highlighted_word, row, col); - return; - } - // Toggle breakpoint on gutter click. if (draw_breakpoint_gutter) { int gutter = cache.style_normal->get_margin(MARGIN_LEFT); @@ -2368,6 +2362,14 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } else { if (mb->get_button_index() == BUTTON_LEFT) { + if (mb->get_command() && highlighted_word != String()) { + int row, col; + _get_mouse_pos(Point2i(mb->get_position().x, mb->get_position().y), row, col); + + emit_signal("symbol_lookup", highlighted_word, row, col); + return; + } + dragging_minimap = false; dragging_selection = false; can_drag_minimap = false; @@ -4613,7 +4615,7 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const { return CURSOR_ARROW; } else { int xmargin_end = get_size().width - cache.style_normal->get_margin(MARGIN_RIGHT); - if (p_pos.x > xmargin_end - minimap_width && p_pos.x <= xmargin_end) { + if (draw_minimap && p_pos.x > xmargin_end - minimap_width && p_pos.x <= xmargin_end) { return CURSOR_ARROW; } diff --git a/scene/gui/viewport_container.cpp b/scene/gui/viewport_container.cpp index 3f7a110c1b..35696a0459 100644 --- a/scene/gui/viewport_container.cpp +++ b/scene/gui/viewport_container.cpp @@ -211,4 +211,5 @@ ViewportContainer::ViewportContainer() { stretch = false; shrink = 1; set_process_input(true); + set_process_unhandled_input(true); } diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index e21e47f8a8..6c922adbd2 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -60,10 +60,10 @@ Error HTTPRequest::_parse_url(const String &p_url) { use_ssl = true; port = 443; } else { - ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Malformed URL."); + ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Malformed URL: " + url + "."); } - ERR_FAIL_COND_V_MSG(url.length() < 1, ERR_INVALID_PARAMETER, "URL too short."); + ERR_FAIL_COND_V_MSG(url.length() < 1, ERR_INVALID_PARAMETER, "URL too short: " + url + "."); int slash_pos = url.find("/"); |