diff options
-rw-r--r-- | core/image.cpp | 27 | ||||
-rw-r--r-- | doc/classes/Tween.xml | 2 | ||||
-rw-r--r-- | editor/code_editor.cpp | 3 | ||||
-rw-r--r-- | editor/editor_node.cpp | 13 | ||||
-rw-r--r-- | editor/editor_themes.cpp | 9 | ||||
-rw-r--r-- | editor/plugins/script_editor_plugin.cpp | 2 | ||||
-rw-r--r-- | editor/plugins/script_text_editor.cpp | 5 | ||||
-rw-r--r-- | editor/plugins/script_text_editor.h | 1 | ||||
-rw-r--r-- | main/main.cpp | 6 | ||||
-rw-r--r-- | modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs | 3 | ||||
-rw-r--r-- | modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs | 8 | ||||
-rw-r--r-- | modules/mono/editor/GodotTools/GodotTools/Utils/FsPathUtils.cs | 48 | ||||
-rw-r--r-- | platform/iphone/in_app_store.mm | 2 | ||||
-rw-r--r-- | scene/gui/tab_container.cpp | 23 | ||||
-rw-r--r-- | scene/gui/tab_container.h | 2 | ||||
-rw-r--r-- | scene/resources/default_theme/default_theme.cpp | 16 |
16 files changed, 105 insertions, 65 deletions
diff --git a/core/image.cpp b/core/image.cpp index 0f15574053..45f10625a9 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -678,34 +678,35 @@ static void _scale_bilinear(const uint8_t *__restrict p_src, uint8_t *__restrict enum { FRAC_BITS = 8, FRAC_LEN = (1 << FRAC_BITS), + FRAC_HALF = (FRAC_LEN >> 1), FRAC_MASK = FRAC_LEN - 1 - }; for (uint32_t i = 0; i < p_dst_height; i++) { - uint32_t src_yofs_up_fp = (i * p_src_height * FRAC_LEN / p_dst_height); - uint32_t src_yofs_frac = src_yofs_up_fp & FRAC_MASK; - uint32_t src_yofs_up = src_yofs_up_fp >> FRAC_BITS; - - uint32_t src_yofs_down = (i + 1) * p_src_height / p_dst_height; + // Add 0.5 in order to interpolate based on pixel center + uint32_t src_yofs_up_fp = (i + 0.5) * p_src_height * FRAC_LEN / p_dst_height; + // Calculate nearest src pixel center above current, and truncate to get y index + uint32_t src_yofs_up = src_yofs_up_fp >= FRAC_HALF ? (src_yofs_up_fp - FRAC_HALF) >> FRAC_BITS : 0; + uint32_t src_yofs_down = (src_yofs_up_fp + FRAC_HALF) >> FRAC_BITS; if (src_yofs_down >= p_src_height) { src_yofs_down = p_src_height - 1; } - - //src_yofs_up*=CC; - //src_yofs_down*=CC; + // Calculate distance to pixel center of src_yofs_up + uint32_t src_yofs_frac = src_yofs_up_fp & FRAC_MASK; + src_yofs_frac = src_yofs_frac >= FRAC_HALF ? src_yofs_frac - FRAC_HALF : src_yofs_frac + FRAC_HALF; uint32_t y_ofs_up = src_yofs_up * p_src_width * CC; uint32_t y_ofs_down = src_yofs_down * p_src_width * CC; for (uint32_t j = 0; j < p_dst_width; j++) { - uint32_t src_xofs_left_fp = (j * p_src_width * FRAC_LEN / p_dst_width); - uint32_t src_xofs_frac = src_xofs_left_fp & FRAC_MASK; - uint32_t src_xofs_left = src_xofs_left_fp >> FRAC_BITS; - uint32_t src_xofs_right = (j + 1) * p_src_width / p_dst_width; + uint32_t src_xofs_left_fp = (j + 0.5) * p_src_width * FRAC_LEN / p_dst_width; + uint32_t src_xofs_left = src_xofs_left_fp >= FRAC_HALF ? (src_xofs_left_fp - FRAC_HALF) >> FRAC_BITS : 0; + uint32_t src_xofs_right = (src_xofs_left_fp + FRAC_HALF) >> FRAC_BITS; if (src_xofs_right >= p_src_width) { src_xofs_right = p_src_width - 1; } + uint32_t src_xofs_frac = src_xofs_left_fp & FRAC_MASK; + src_xofs_frac = src_xofs_frac >= FRAC_HALF ? src_xofs_frac - FRAC_HALF : src_xofs_frac + FRAC_HALF; src_xofs_left *= CC; src_xofs_right *= CC; diff --git a/doc/classes/Tween.xml b/doc/classes/Tween.xml index 1938a3facb..56ccaaf383 100644 --- a/doc/classes/Tween.xml +++ b/doc/classes/Tween.xml @@ -15,7 +15,7 @@ tween.start() [/codeblock] Many methods require a property name, such as [code]"position"[/code] above. You can find the correct property name by hovering over the property in the Inspector. You can also provide the components of a property directly by using [code]"property:component"[/code] (eg. [code]position:x[/code]), where it would only apply to that particular component. - Many of the methods accept [code]trans_type[/code] and [code]ease_type[/code]. The first accepts an [enum TransitionType] constant, and refers to the way the timing of the animation is handled (see [url=https://easings.net/]easings.net[/url] for some examples). The second accepts an [enum EaseType] constant, and controls the where [code]trans_type[/code] is applied to the interpolation (in the beginning, the end, or both). If you don't know which transition and easing to pick, you can try different [enum TransitionType] constants with [constant EASE_IN_OUT], and use the one that looks best. + Many of the methods accept [code]trans_type[/code] and [code]ease_type[/code]. The first accepts an [enum TransitionType] constant, and refers to the way the timing of the animation is handled (see [url=https://easings.net/]easings.net[/url] for some examples). The second accepts an [enum EaseType] constant, and controls where the [code]trans_type[/code] is applied to the interpolation (in the beginning, the end, or both). If you don't know which transition and easing to pick, you can try different [enum TransitionType] constants with [constant EASE_IN_OUT], and use the one that looks best. [url=https://raw.githubusercontent.com/godotengine/godot-docs/master/img/tween_cheatsheet.png]Tween easing and transition types cheatsheet[/url] </description> <tutorials> diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index c5df947d64..b73a27214d 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -1541,7 +1541,7 @@ void CodeTextEditor::_toggle_scripts_pressed() { void CodeTextEditor::_error_pressed(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { - emit_signal("error_pressed"); + goto_error(); } } @@ -1651,7 +1651,6 @@ void CodeTextEditor::_bind_methods() { ADD_SIGNAL(MethodInfo("validate_script")); ADD_SIGNAL(MethodInfo("load_theme_settings")); ADD_SIGNAL(MethodInfo("show_warnings_panel")); - ADD_SIGNAL(MethodInfo("error_pressed")); } void CodeTextEditor::set_code_complete_func(CodeTextEditorCodeCompleteFunc p_code_complete_func, void *p_ud) { diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index bb34a45938..d8bc555d6d 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -3642,17 +3642,12 @@ Ref<Texture2D> EditorNode::get_class_icon(const String &p_class, const String &p } if (ScriptServer::is_global_class(p_class)) { - String icon_path = EditorNode::get_editor_data().script_class_get_icon_path(p_class); - Ref<ImageTexture> icon = _load_custom_class_icon(icon_path); - if (icon.is_valid()) { - return icon; - } - - Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(p_class), "Script"); + Ref<ImageTexture> icon; + Ref<Script> script = EditorNode::get_editor_data().script_class_load_script(p_class); while (script.is_valid()) { - String current_icon_path; - script->get_language()->get_global_class_name(script->get_path(), nullptr, ¤t_icon_path); + StringName name = EditorNode::get_editor_data().script_class_get_name(script->get_path()); + String current_icon_path = EditorNode::get_editor_data().script_class_get_icon_path(name); icon = _load_custom_class_icon(current_icon_path); if (icon.is_valid()) { return icon; diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 5f59e6e70a..a93763810b 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -570,17 +570,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_stylebox("focus", "PopupMenu", style_menu); theme->set_stylebox("disabled", "PopupMenu", style_menu); - theme->set_stylebox("normal", "Button", style_menu); - theme->set_stylebox("hover", "Button", style_menu); - theme->set_stylebox("pressed", "Button", style_menu); - theme->set_stylebox("focus", "Button", style_menu); - theme->set_stylebox("disabled", "Button", style_menu); - theme->set_color("font_color", "MenuButton", font_color); theme->set_color("font_color_hover", "MenuButton", font_color_hl); - theme->set_color("font_color", "Button", font_color); - theme->set_color("font_color_hover", "Button", font_color_hl); - theme->set_color("font_color_pressed", "Button", accent_color); theme->set_stylebox("MenuHover", "EditorStyles", style_menu_hover_border); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 3f17bf57c4..96079d5418 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -3050,7 +3050,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { file_menu->get_popup()->add_separator(); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save", TTR("Save"), KEY_MASK_ALT | KEY_MASK_CMD | KEY_S), FILE_SAVE); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_as", TTR("Save As...")), FILE_SAVE_AS); - file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_all", TTR("Save All"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_MASK_ALT | KEY_S), FILE_SAVE_ALL); + file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_all", TTR("Save All"), KEY_MASK_SHIFT | KEY_MASK_ALT | KEY_S), FILE_SAVE_ALL); file_menu->get_popup()->add_separator(); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/reload_script_soft", TTR("Soft Reload Script"), KEY_MASK_CMD | KEY_MASK_ALT | KEY_R), FILE_TOOL_RELOAD_SOFT); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/copy_path", TTR("Copy Script Path")), FILE_COPY_PATH); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 4b79d8c344..1c9dadc0dd 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -383,10 +383,6 @@ void ScriptTextEditor::_show_warnings_panel(bool p_show) { warnings_panel->set_visible(p_show); } -void ScriptTextEditor::_error_pressed() { - code_editor->goto_error(); -} - void ScriptTextEditor::_warning_clicked(Variant p_line) { if (p_line.get_type() == Variant::INT) { code_editor->get_text_edit()->cursor_set_line(p_line.operator int64_t()); @@ -1759,7 +1755,6 @@ ScriptTextEditor::ScriptTextEditor() { warnings_panel->set_focus_mode(FOCUS_CLICK); warnings_panel->hide(); - code_editor->connect("error_pressed", callable_mp(this, &ScriptTextEditor::_error_pressed)); code_editor->connect("show_warnings_panel", callable_mp(this, &ScriptTextEditor::_show_warnings_panel)); warnings_panel->connect("meta_clicked", callable_mp(this, &ScriptTextEditor::_warning_clicked)); diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index adcd0218bc..8fa380b64d 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -159,7 +159,6 @@ protected: void _load_theme_settings(); void _set_theme_for_script(); void _show_warnings_panel(bool p_show); - void _error_pressed(); void _warning_clicked(Variant p_line); void _notification(int p_what); diff --git a/main/main.cpp b/main/main.cpp index 747b12677d..91ff222f57 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -2321,8 +2321,8 @@ void Main::cleanup() { ResourceLoader::remove_custom_loaders(); ResourceSaver::remove_custom_savers(); + // Flush before uninitializing the scene, but delete the MessageQueue as late as possible. message_queue->flush(); - memdelete(message_queue); OS::get_singleton()->delete_main_loop(); @@ -2408,6 +2408,10 @@ void Main::cleanup() { OS::get_singleton()->set_restart_on_exit(false, List<String>()); //clear list (uses memory) } + // Now should be safe to delete MessageQueue (famous last words). + message_queue->flush(); + memdelete(message_queue); + unregister_core_driver_types(); unregister_core_types(); diff --git a/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs b/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs index 7ab5c5fc59..012b69032e 100644 --- a/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs +++ b/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs @@ -25,8 +25,9 @@ namespace GodotTools.Core bool rooted = path.IsAbsolutePath(); path = path.Replace('\\', '/'); + path = path[path.Length - 1] == '/' ? path.Substring(0, path.Length - 1) : path; - string[] parts = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); + string[] parts = path.Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries); path = string.Join(Path.DirectorySeparatorChar.ToString(), parts).Trim(); diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs index 98e8d13be0..17f3339560 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs @@ -12,6 +12,7 @@ using GodotTools.IdeMessaging; using GodotTools.IdeMessaging.Requests; using GodotTools.IdeMessaging.Utils; using GodotTools.Internals; +using GodotTools.Utils; using Newtonsoft.Json; using Directory = System.IO.Directory; using File = System.IO.File; @@ -362,8 +363,13 @@ namespace GodotTools.Ides private static async Task<Response> HandleCodeCompletionRequest(CodeCompletionRequest request) { + // This is needed if the "resource path" part of the path is case insensitive. + // However, it doesn't fix resource loading if the rest of the path is also case insensitive. + string scriptFileLocalized = FsPathUtils.LocalizePathWithCaseChecked(request.ScriptFile); + var response = new CodeCompletionResponse {Kind = request.Kind, ScriptFile = request.ScriptFile}; - response.Suggestions = await Task.Run(() => Internal.CodeCompletionRequest(response.Kind, response.ScriptFile)); + response.Suggestions = await Task.Run(() => + Internal.CodeCompletionRequest(response.Kind, scriptFileLocalized ?? request.ScriptFile)); return response; } } diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/FsPathUtils.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/FsPathUtils.cs new file mode 100644 index 0000000000..c6724ccaf7 --- /dev/null +++ b/modules/mono/editor/GodotTools/GodotTools/Utils/FsPathUtils.cs @@ -0,0 +1,48 @@ +using System; +using System.IO; +using Godot; +using GodotTools.Core; +using JetBrains.Annotations; + +namespace GodotTools.Utils +{ + public static class FsPathUtils + { + private static readonly string ResourcePath = ProjectSettings.GlobalizePath("res://"); + + private static bool PathStartsWithAlreadyNorm(this string childPath, string parentPath) + { + // This won't work for Linux/macOS case insensitive file systems, but it's enough for our current problems + bool caseSensitive = !OS.IsWindows; + + string parentPathNorm = parentPath.NormalizePath() + Path.DirectorySeparatorChar; + string childPathNorm = childPath.NormalizePath() + Path.DirectorySeparatorChar; + + return childPathNorm.StartsWith(parentPathNorm, + caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase); + } + + public static bool PathStartsWith(this string childPath, string parentPath) + { + string childPathNorm = childPath.NormalizePath() + Path.DirectorySeparatorChar; + string parentPathNorm = parentPath.NormalizePath() + Path.DirectorySeparatorChar; + + return childPathNorm.PathStartsWithAlreadyNorm(parentPathNorm); + } + + [CanBeNull] + public static string LocalizePathWithCaseChecked(string path) + { + string pathNorm = path.NormalizePath() + Path.DirectorySeparatorChar; + string resourcePathNorm = ResourcePath.NormalizePath() + Path.DirectorySeparatorChar; + + if (!pathNorm.PathStartsWithAlreadyNorm(resourcePathNorm)) + return null; + + string result = "res://" + pathNorm.Substring(resourcePathNorm.Length); + + // Remove the last separator we added + return result.Substring(0, result.Length - 1); + } + } +} diff --git a/platform/iphone/in_app_store.mm b/platform/iphone/in_app_store.mm index a2efd6691b..548dcc549d 100644 --- a/platform/iphone/in_app_store.mm +++ b/platform/iphone/in_app_store.mm @@ -207,7 +207,7 @@ Error InAppStore::restore_purchases() { NSString *receipt_to_send = nil; if (receipt != nil) { - receipt_to_send = [receipt description]; + receipt_to_send = [receipt base64EncodedStringWithOptions:0]; } Dictionary receipt_ret; receipt_ret["receipt"] = String::utf8(receipt_to_send != nil ? [receipt_to_send UTF8String] : ""); diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 0d48fde642..41b8fad49d 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -71,6 +71,8 @@ int TabContainer::_get_top_margin() const { void TabContainer::_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> mb = p_event; + Popup *popup = get_popup(); + if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { Point2 pos(mb->get_position().x, mb->get_position().y); Size2 size = get_size(); @@ -82,6 +84,7 @@ void TabContainer::_gui_input(const Ref<InputEvent> &p_event) { // Handle menu button. Ref<Texture2D> menu = get_theme_icon("menu"); + if (popup && pos.x > size.width - menu->get_width()) { emit_signal("pre_popup_pressed"); @@ -223,6 +226,7 @@ void TabContainer::_notification(int p_what) { int header_width = get_size().width - side_margin * 2; // Find the width of the header area. + Popup *popup = get_popup(); if (popup) { header_width -= menu->get_width(); } @@ -284,6 +288,7 @@ void TabContainer::_notification(int p_what) { int header_x = side_margin; int header_width = size.width - side_margin * 2; int header_height = _get_top_margin(); + Popup *popup = get_popup(); if (popup) { header_width -= menu->get_width(); } @@ -749,6 +754,7 @@ int TabContainer::get_tab_idx_at_point(const Point2 &p_point) const { Size2 size = get_size(); int right_ofs = 0; + Popup *popup = get_popup(); if (popup) { Ref<Texture2D> menu = get_theme_icon("menu"); right_ofs += menu->get_width(); @@ -948,12 +954,24 @@ Size2 TabContainer::get_minimum_size() const { void TabContainer::set_popup(Node *p_popup) { ERR_FAIL_NULL(p_popup); - popup = Object::cast_to<Popup>(p_popup); + Popup *popup = Object::cast_to<Popup>(p_popup); + popup_obj_id = popup ? popup->get_instance_id() : ObjectID(); update(); } Popup *TabContainer::get_popup() const { - return popup; + if (popup_obj_id.is_valid()) { + Popup *popup = Object::cast_to<Popup>(ObjectDB::get_instance(popup_obj_id)); + if (popup) { + return popup; + } else { +#ifdef DEBUG_ENABLED + ERR_PRINT("Popup assigned to TabContainer is gone!"); +#endif + popup_obj_id = ObjectID(); + } + } + return nullptr; } void TabContainer::set_drag_to_rearrange_enabled(bool p_enabled) { @@ -1037,7 +1055,6 @@ TabContainer::TabContainer() { previous = 0; align = ALIGN_CENTER; tabs_visible = true; - popup = nullptr; 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 55a5d35b30..6ee72a379a 100644 --- a/scene/gui/tab_container.h +++ b/scene/gui/tab_container.h @@ -57,7 +57,7 @@ private: TabAlign align; Control *_get_tab(int p_idx) const; int _get_top_margin() const; - Popup *popup; + mutable ObjectID popup_obj_id; bool drag_to_rearrange_enabled; bool use_hidden_tabs_for_min_size; int tabs_rearrange_group; diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index aebb0d7ba4..83d4db7bae 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -219,22 +219,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("hseparation", "ColorPickerButton", 2 * scale); - // Button - - theme->set_stylebox("normal", "Button", make_empty_stylebox(6, 4, 6, 4)); - theme->set_stylebox("pressed", "Button", make_stylebox(button_pressed_png, 4, 4, 4, 4, 6, 4, 6, 4)); - theme->set_stylebox("hover", "Button", make_stylebox(button_normal_png, 4, 4, 4, 4, 6, 4, 6, 4)); - theme->set_stylebox("disabled", "Button", make_empty_stylebox(6, 4, 6, 4)); - theme->set_stylebox("focus", "Button", focus); - theme->set_font("font", "Button", default_font); - - theme->set_color("font_color", "Button", control_font_color); - theme->set_color("font_color_pressed", "Button", control_font_color_pressed); - theme->set_color("font_color_hover", "Button", control_font_color_hover); - theme->set_color("font_color_disabled", "Button", Color(0.9, 0.95, 1, 0.3)); - - theme->set_constant("hseparation", "Button", 3); - // OptionButton Ref<StyleBox> sb_optbutton_normal = sb_expand(make_stylebox(option_button_normal_png, 4, 4, 21, 4, 6, 3, 9, 3), 2, 2, 2, 2); |