diff options
51 files changed, 441 insertions, 209 deletions
diff --git a/.github/actions/godot-build/action.yml b/.github/actions/godot-build/action.yml index 0a0899db78..bf29b7e430 100644 --- a/.github/actions/godot-build/action.yml +++ b/.github/actions/godot-build/action.yml @@ -13,10 +13,10 @@ inputs: sconsflags: default: "" scons-cache: - description: The scons cache path. + description: The SCons cache path. default: "${{ github.workspace }}/.scons-cache/" scons-cache-limit: - description: The scons cache size limit. + description: The SCons cache size limit. # actions/cache has 10 GiB limit, and GitHub runners have a 14 GiB disk. # Limit to 7 GiB to avoid having the extracted cache fill the disk. default: 7168 diff --git a/.github/actions/godot-cache/action.yml b/.github/actions/godot-cache/action.yml index b7ca01bb47..13142e7ed1 100644 --- a/.github/actions/godot-cache/action.yml +++ b/.github/actions/godot-cache/action.yml @@ -5,13 +5,13 @@ inputs: description: The cache base name (job name by default). default: "${{github.job}}" scons-cache: - description: The scons cache path. + description: The SCons cache path. default: "${{github.workspace}}/.scons-cache/" runs: using: "composite" steps: - # Upload cache on completion and check it out now - - name: Load .scons_cache directory + # Upload cache on completion and check it out now. + - name: Load SCons cache directory uses: actions/cache@v4 with: path: ${{inputs.scons-cache}} diff --git a/.github/actions/godot-deps/action.yml b/.github/actions/godot-deps/action.yml index cac72c436e..07a364cd79 100644 --- a/.github/actions/godot-deps/action.yml +++ b/.github/actions/godot-deps/action.yml @@ -1,27 +1,30 @@ -name: Setup python and scons -description: Setup python, install the pip version of scons. +name: Setup Python and SCons +description: Setup Python, install the pip version of SCons. inputs: python-version: - description: The python version to use. + description: The Python version to use. default: "3.x" python-arch: - description: The python architecture. + description: The Python architecture. default: "x64" + scons-version: + description: The SCons version to use. + default: "4.7.0" runs: using: "composite" steps: - # Use python 3.x release (works cross platform) - name: Set up Python 3.x uses: actions/setup-python@v5 with: - # Semantic version range syntax or exact version of a Python version + # Semantic version range syntax or exact version of a Python version. python-version: ${{ inputs.python-version }} - # Optional - x64 or x86 architecture, defaults to x64 + # Optional - x64 or x86 architecture, defaults to x64. architecture: ${{ inputs.python-arch }} - - name: Setup scons + - name: Setup SCons shell: bash run: | python -c "import sys; print(sys.version)" - python -m pip install scons==4.7.0 + python -m pip install wheel + python -m pip install scons==${{ inputs.scons-version }} scons --version diff --git a/.github/workflows/android_builds.yml b/.github/workflows/android_builds.yml index 5cb66a40ab..9a488bd095 100644 --- a/.github/workflows/android_builds.yml +++ b/.github/workflows/android_builds.yml @@ -32,7 +32,7 @@ jobs: uses: ./.github/actions/godot-cache continue-on-error: true - - name: Setup python and scons + - name: Setup Python and SCons uses: ./.github/actions/godot-deps - name: Compilation (arm32) diff --git a/.github/workflows/godot_cpp_test.yml b/.github/workflows/godot_cpp_test.yml index 7350920810..57114dacfc 100644 --- a/.github/workflows/godot_cpp_test.yml +++ b/.github/workflows/godot_cpp_test.yml @@ -22,7 +22,7 @@ jobs: with: submodules: recursive - - name: Setup python and scons + - name: Setup Python and SCons uses: ./.github/actions/godot-deps # Checkout godot-cpp @@ -47,7 +47,7 @@ jobs: cp -f godot-api/gdextension_interface.h godot-cpp/gdextension/ cp -f godot-api/extension_api.json godot-cpp/gdextension/ - # TODO: Add caching to the scons build and store it for CI via the godot-cache + # TODO: Add caching to the SCons build and store it for CI via the godot-cache # action. # Build godot-cpp test extension diff --git a/.github/workflows/ios_builds.yml b/.github/workflows/ios_builds.yml index e205d551ed..0546f43acc 100644 --- a/.github/workflows/ios_builds.yml +++ b/.github/workflows/ios_builds.yml @@ -26,7 +26,7 @@ jobs: uses: ./.github/actions/godot-cache continue-on-error: true - - name: Setup python and scons + - name: Setup Python and SCons uses: ./.github/actions/godot-deps - name: Compilation (arm64) diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml index 0420a02b1d..6b98256110 100644 --- a/.github/workflows/linux_builds.yml +++ b/.github/workflows/linux_builds.yml @@ -58,6 +58,8 @@ jobs: tests: true # Skip 2GiB artifact speeding up action. artifact: false + # Test our oldest supported SCons/Python versions on one arbitrary editor build. + legacy-scons: true - name: Editor with ThreadSanitizer (target=editor, tests=yes, dev_build=yes, use_tsan=yes, use_llvm=yes, linker=lld) cache-name: linux-editor-thread-sanitizer @@ -115,9 +117,18 @@ jobs: cache-name: ${{ matrix.cache-name }} continue-on-error: true - - name: Setup python and scons + - name: Setup Python and SCons + if: ${{ ! matrix.legacy-scons }} uses: ./.github/actions/godot-deps + - name: Setup Python and SCons (legacy versions) + if: ${{ matrix.legacy-scons }} + uses: ./.github/actions/godot-deps + with: + # Sync with Ensure*Version in SConstruct. + python-version: 3.6 + scons-version: 3.1.2 + - name: Setup GCC problem matcher uses: ammaraskar/gcc-problem-matcher@master diff --git a/.github/workflows/macos_builds.yml b/.github/workflows/macos_builds.yml index 70031ec4c3..badcb688d1 100644 --- a/.github/workflows/macos_builds.yml +++ b/.github/workflows/macos_builds.yml @@ -43,7 +43,7 @@ jobs: cache-name: ${{ matrix.cache-name }} continue-on-error: true - - name: Setup python and scons + - name: Setup Python and SCons uses: ./.github/actions/godot-deps - name: Setup Vulkan SDK diff --git a/.github/workflows/web_builds.yml b/.github/workflows/web_builds.yml index cfa1571d1f..1eb7b901cd 100644 --- a/.github/workflows/web_builds.yml +++ b/.github/workflows/web_builds.yml @@ -58,7 +58,7 @@ jobs: cache-name: ${{ matrix.cache-name }} continue-on-error: true - - name: Setup python and scons + - name: Setup Python and SCons uses: ./.github/actions/godot-deps - name: Compilation diff --git a/.github/workflows/windows_builds.yml b/.github/workflows/windows_builds.yml index 5443ba20ab..f9513af5e3 100644 --- a/.github/workflows/windows_builds.yml +++ b/.github/workflows/windows_builds.yml @@ -48,7 +48,7 @@ jobs: cache-name: ${{ matrix.cache-name }} continue-on-error: true - - name: Setup python and scons + - name: Setup Python and SCons uses: ./.github/actions/godot-deps - name: Download Direct3D 12 SDK components diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5c0c0b6917..5a0e919c47 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -125,8 +125,18 @@ repos: language: node entry: jsdoc files: ^platform/web/js/engine/(engine|config|features)\.js$ - args: [--template, platform/web/js/jsdoc2rst/, --destination, '', -d, dry-run] - additional_dependencies: ["jsdoc@4.0.2"] + args: + - --template + - platform/web/js/jsdoc2rst/ + - platform/web/js/engine/engine.js + - platform/web/js/engine/config.js + - platform/web/js/engine/features.js + - --destination + - '' + - -d + - dry-run + pass_filenames: false + additional_dependencies: ['jsdoc@^4.0.3'] - id: copyright-headers name: copyright-headers diff --git a/SConstruct b/SConstruct index 07ec014cf9..c668ac7df3 100644 --- a/SConstruct +++ b/SConstruct @@ -1,6 +1,6 @@ #!/usr/bin/env python -EnsureSConsVersion(3, 0, 0) +EnsureSConsVersion(3, 1, 2) EnsurePythonVersion(3, 6) # System @@ -365,7 +365,7 @@ if env["platform"] in platform_opts: opts.Add(opt) # Update the environment to take platform-specific options into account. -opts.Update(env, {**ARGUMENTS, **env}) +opts.Update(env, {**ARGUMENTS, **env.Dictionary()}) # Detect modules. modules_detected = OrderedDict() @@ -425,7 +425,7 @@ for name, path in modules_detected.items(): env.modules_detected = modules_detected # Update the environment again after all the module options are added. -opts.Update(env, {**ARGUMENTS, **env}) +opts.Update(env, {**ARGUMENTS, **env.Dictionary()}) Help(opts.GenerateHelpText(env)) # add default include paths diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 926d981f68..5ac4c96d93 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -554,10 +554,10 @@ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when defining a local or subclass member variable that would shadow a variable that is inherited from a parent class. </member> <member name="debug/gdscript/warnings/standalone_expression" type="int" setter="" getter="" default="1"> - When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when calling an expression that has no effect on the surrounding code, such as writing [code]2 + 2[/code] as a statement. + When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when calling an expression that may have no effect on the surrounding code, such as writing [code]2 + 2[/code] as a statement. </member> <member name="debug/gdscript/warnings/standalone_ternary" type="int" setter="" getter="" default="1"> - When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when calling a ternary expression that has no effect on the surrounding code, such as writing [code]42 if active else 0[/code] as a statement. + When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when calling a ternary expression that may have no effect on the surrounding code, such as writing [code]42 if active else 0[/code] as a statement. </member> <member name="debug/gdscript/warnings/static_called_on_instance" type="int" setter="" getter="" default="1"> When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when calling a static method from an instance of a class instead of from the class directly. diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index 4dda1f8db8..75cad4d08b 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -1314,7 +1314,7 @@ [b]Note:[/b] This method is only implemented on Linux. </member> <member name="minimap_draw" type="bool" setter="set_draw_minimap" getter="is_drawing_minimap" default="false"> - If [code]true[/code], a minimap is shown, providing an outline of your source code. + If [code]true[/code], a minimap is shown, providing an outline of your source code. The minimap uses a fixed-width text size. </member> <member name="minimap_width" type="int" setter="set_minimap_width" getter="get_minimap_width" default="80"> The width, in pixels, of the minimap. diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp index 57ef951bdf..2dcf623995 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -1495,14 +1495,18 @@ void TextureStorage::_texture_set_data(RID p_texture, const Ref<Image> &p_image, for (int i = 0; i < mipmaps; i++) { int size, ofs; img->get_mipmap_offset_and_size(i, ofs, size); - if (compressed) { glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - - int bw = w; - int bh = h; - - glCompressedTexImage2D(blit_target, i, internal_format, bw, bh, 0, size, &read[ofs]); + if (texture->target == GL_TEXTURE_2D_ARRAY) { + if (p_initialize) { + glCompressedTexImage3D(GL_TEXTURE_2D_ARRAY, i, internal_format, w, h, texture->layers, 0, + size * texture->layers, &read[ofs]); + } else { + glCompressedTexSubImage3D(GL_TEXTURE_2D_ARRAY, i, 0, 0, p_layer, w, h, 1, internal_format, size, &read[ofs]); + } + } else { + glCompressedTexImage2D(blit_target, i, internal_format, w, h, 0, size, &read[ofs]); + } } else { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); if (texture->target == GL_TEXTURE_2D_ARRAY) { diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp index 8ea1f52d15..a349a66f75 100644 --- a/drivers/wasapi/audio_driver_wasapi.cpp +++ b/drivers/wasapi/audio_driver_wasapi.cpp @@ -107,12 +107,6 @@ const IID IID_IAudioClient3 = __uuidof(IAudioClient3); const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient); const IID IID_IAudioCaptureClient = __uuidof(IAudioCaptureClient); -#define SAFE_RELEASE(memory) \ - if ((memory) != nullptr) { \ - (memory)->Release(); \ - (memory) = nullptr; \ - } - #define REFTIMES_PER_SEC 10000000 #define REFTIMES_PER_MILLISEC 10000 @@ -129,16 +123,10 @@ static bool default_input_device_changed = false; class CMMNotificationClient : public IMMNotificationClient { LONG _cRef = 1; - IMMDeviceEnumerator *_pEnumerator = nullptr; public: CMMNotificationClient() {} - virtual ~CMMNotificationClient() { - if ((_pEnumerator) != nullptr) { - (_pEnumerator)->Release(); - (_pEnumerator) = nullptr; - } - } + virtual ~CMMNotificationClient() {} ULONG STDMETHODCALLTYPE AddRef() { return InterlockedIncrement(&_cRef); @@ -203,8 +191,8 @@ static CMMNotificationClient notif_client; Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_input, bool p_reinit, bool p_no_audio_client_3) { WAVEFORMATEX *pwfex; - IMMDeviceEnumerator *enumerator = nullptr; - IMMDevice *output_device = nullptr; + ComPtr<IMMDeviceEnumerator> enumerator = nullptr; + ComPtr<IMMDevice> output_device = nullptr; HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator); ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); @@ -212,7 +200,7 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i if (p_device->device_name == "Default") { hr = enumerator->GetDefaultAudioEndpoint(p_input ? eCapture : eRender, eConsole, &output_device); } else { - IMMDeviceCollection *devices = nullptr; + ComPtr<IMMDeviceCollection> devices = nullptr; hr = enumerator->EnumAudioEndpoints(p_input ? eCapture : eRender, DEVICE_STATE_ACTIVE, &devices); ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); @@ -225,12 +213,12 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); for (ULONG i = 0; i < count && !found; i++) { - IMMDevice *tmp_device = nullptr; + ComPtr<IMMDevice> tmp_device = nullptr; hr = devices->Item(i, &tmp_device); ERR_BREAK(hr != S_OK); - IPropertyStore *props = nullptr; + ComPtr<IPropertyStore> props = nullptr; hr = tmp_device->OpenPropertyStore(STGM_READ, &props); ERR_BREAK(hr != S_OK); @@ -248,8 +236,6 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i } PropVariantClear(&propvar); - props->Release(); - tmp_device->Release(); } if (found) { @@ -276,7 +262,6 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i } hr = enumerator->RegisterEndpointNotificationCallback(¬if_client); - SAFE_RELEASE(enumerator) if (hr != S_OK) { ERR_PRINT("WASAPI: RegisterEndpointNotificationCallback error"); @@ -303,8 +288,6 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i hr = output_device->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, (void **)&p_device->audio_client); } - SAFE_RELEASE(output_device) - if (p_reinit) { if (hr != S_OK) { return ERR_CANT_OPEN; @@ -319,7 +302,7 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i audioProps.bIsOffload = FALSE; audioProps.eCategory = AudioCategory_GameEffects; - hr = ((IAudioClient3 *)p_device->audio_client)->SetClientProperties(&audioProps); + hr = ((IAudioClient3 *)p_device->audio_client.Get())->SetClientProperties(&audioProps); ERR_FAIL_COND_V_MSG(hr != S_OK, ERR_CANT_OPEN, "WASAPI: SetClientProperties failed with error 0x" + String::num_uint64(hr, 16) + "."); } @@ -402,7 +385,7 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i } } else { - IAudioClient3 *device_audio_client_3 = (IAudioClient3 *)p_device->audio_client; + IAudioClient3 *device_audio_client_3 = (IAudioClient3 *)p_device->audio_client.Get(); // AUDCLNT_STREAMFLAGS_RATEADJUST is an invalid flag with IAudioClient3, therefore we have to use // the closest supported mix rate supported by the audio driver. @@ -419,7 +402,6 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i if (hr != S_OK) { print_verbose("WASAPI: GetSharedModeEnginePeriod failed with error 0x" + String::num_uint64(hr, 16) + ", falling back to IAudioClient."); CoTaskMemFree(pwfex); - SAFE_RELEASE(output_device) return audio_device_init(p_device, p_input, p_reinit, true); } @@ -441,7 +423,6 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i if (hr != S_OK) { print_verbose("WASAPI: InitializeSharedAudioStream failed with error 0x" + String::num_uint64(hr, 16) + ", falling back to IAudioClient."); CoTaskMemFree(pwfex); - SAFE_RELEASE(output_device); return audio_device_init(p_device, p_input, p_reinit, true); } else { uint32_t output_latency_in_frames; @@ -453,7 +434,6 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i } else { print_verbose("WASAPI: GetCurrentSharedModeEnginePeriod failed with error 0x" + String::num_uint64(hr, 16) + ", falling back to IAudioClient."); CoTaskMemFree(pwfex); - SAFE_RELEASE(output_device); return audio_device_init(p_device, p_input, p_reinit, true); } } @@ -468,7 +448,6 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i // Free memory CoTaskMemFree(pwfex); - SAFE_RELEASE(output_device) return OK; } @@ -537,9 +516,9 @@ Error AudioDriverWASAPI::audio_device_finish(AudioDeviceWASAPI *p_device) { p_device->active.clear(); } - SAFE_RELEASE(p_device->audio_client) - SAFE_RELEASE(p_device->render_client) - SAFE_RELEASE(p_device->capture_client) + p_device->audio_client.Reset(); + p_device->render_client.Reset(); + p_device->capture_client.Reset(); return OK; } @@ -581,8 +560,8 @@ AudioDriver::SpeakerMode AudioDriverWASAPI::get_speaker_mode() const { PackedStringArray AudioDriverWASAPI::audio_device_get_list(bool p_input) { PackedStringArray list; - IMMDeviceCollection *devices = nullptr; - IMMDeviceEnumerator *enumerator = nullptr; + ComPtr<IMMDeviceCollection> devices = nullptr; + ComPtr<IMMDeviceEnumerator> enumerator = nullptr; list.push_back(String("Default")); @@ -597,12 +576,12 @@ PackedStringArray AudioDriverWASAPI::audio_device_get_list(bool p_input) { ERR_FAIL_COND_V(hr != S_OK, PackedStringArray()); for (ULONG i = 0; i < count; i++) { - IMMDevice *output_device = nullptr; + ComPtr<IMMDevice> output_device = nullptr; hr = devices->Item(i, &output_device); ERR_BREAK(hr != S_OK); - IPropertyStore *props = nullptr; + ComPtr<IPropertyStore> props = nullptr; hr = output_device->OpenPropertyStore(STGM_READ, &props); ERR_BREAK(hr != S_OK); @@ -615,12 +594,8 @@ PackedStringArray AudioDriverWASAPI::audio_device_get_list(bool p_input) { list.push_back(String(propvar.pwszVal)); PropVariantClear(&propvar); - props->Release(); - output_device->Release(); } - devices->Release(); - enumerator->Release(); return list; } diff --git a/drivers/wasapi/audio_driver_wasapi.h b/drivers/wasapi/audio_driver_wasapi.h index 367c30607a..d73cbf4a8a 100644 --- a/drivers/wasapi/audio_driver_wasapi.h +++ b/drivers/wasapi/audio_driver_wasapi.h @@ -40,15 +40,18 @@ #include <audioclient.h> #include <mmdeviceapi.h> +#include <wrl/client.h> #define WIN32_LEAN_AND_MEAN #include <windows.h> +using Microsoft::WRL::ComPtr; + class AudioDriverWASAPI : public AudioDriver { class AudioDeviceWASAPI { public: - IAudioClient *audio_client = nullptr; - IAudioRenderClient *render_client = nullptr; // Output - IAudioCaptureClient *capture_client = nullptr; // Input + ComPtr<IAudioClient> audio_client = nullptr; + ComPtr<IAudioRenderClient> render_client = nullptr; // Output + ComPtr<IAudioCaptureClient> capture_client = nullptr; // Input SafeFlag active; WORD format_tag = 0; diff --git a/editor/editor_run_native.cpp b/editor/editor_run_native.cpp index 4eb3f07c47..5c50231623 100644 --- a/editor/editor_run_native.cpp +++ b/editor/editor_run_native.cpp @@ -35,7 +35,6 @@ #include "editor/export/editor_export.h" #include "editor/export/editor_export_platform.h" #include "editor/themes/editor_scale.h" -#include "scene/resources/image_texture.h" void EditorRunNative::_notification(int p_what) { switch (p_what) { @@ -49,17 +48,26 @@ void EditorRunNative::_notification(int p_what) { if (changed) { PopupMenu *popup = remote_debug->get_popup(); popup->clear(); - for (int i = 0; i < EditorExport::get_singleton()->get_export_platform_count(); i++) { - Ref<EditorExportPlatform> eep = EditorExport::get_singleton()->get_export_platform(i); + for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) { + Ref<EditorExportPreset> preset = EditorExport::get_singleton()->get_export_preset(i); + Ref<EditorExportPlatform> eep = preset->get_platform(); if (eep.is_null()) { continue; } + int platform_idx = -1; + for (int j = 0; j < EditorExport::get_singleton()->get_export_platform_count(); j++) { + if (eep->get_name() == EditorExport::get_singleton()->get_export_platform(j)->get_name()) { + platform_idx = j; + } + } int dc = MIN(eep->get_options_count(), 9000); - if (dc > 0) { + bool needs_templates; + String error; + if (dc > 0 && preset->is_runnable() && eep->can_export(preset, error, needs_templates)) { popup->add_icon_item(eep->get_run_icon(), eep->get_name(), -1); popup->set_item_disabled(-1, true); for (int j = 0; j < dc; j++) { - popup->add_icon_item(eep->get_option_icon(j), eep->get_option_label(j), 10000 * i + j); + popup->add_icon_item(eep->get_option_icon(j), eep->get_option_label(j), 10000 * platform_idx + j); popup->set_item_tooltip(-1, eep->get_option_tooltip(j)); popup->set_item_indent(-1, 2); } diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index b05cafa694..5f311ae445 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -79,6 +79,15 @@ Control *FileSystemList::make_custom_tooltip(const String &p_text) const { } void FileSystemList::_line_editor_submit(const String &p_text) { + if (popup_edit_commited) { + return; // Already processed by _text_editor_popup_modal_close + } + + if (popup_editor->get_hide_reason() == Popup::HIDE_REASON_CANCELED) { + return; // ESC pressed, app focus lost, or forced close from code. + } + + popup_edit_commited = true; // End edit popup processing. popup_editor->hide(); emit_signal(SNAME("item_edited")); @@ -127,6 +136,7 @@ bool FileSystemList::edit_selected() { line_editor->set_text(name); line_editor->select(0, name.rfind(".")); + popup_edit_commited = false; // Start edit popup processing. popup_editor->popup(); popup_editor->child_controls_changed(); line_editor->grab_focus(); @@ -138,8 +148,12 @@ String FileSystemList::get_edit_text() { } void FileSystemList::_text_editor_popup_modal_close() { + if (popup_edit_commited) { + return; // Already processed by _text_editor_popup_modal_close + } + if (popup_editor->get_hide_reason() == Popup::HIDE_REASON_CANCELED) { - return; + return; // ESC pressed, app focus lost, or forced close from code. } _line_editor_submit(line_editor->get_text()); diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index 7449657c06..3fbff3ef19 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -59,6 +59,7 @@ class FileSystemTree : public Tree { class FileSystemList : public ItemList { GDCLASS(FileSystemList, ItemList); + bool popup_edit_commited = true; VBoxContainer *popup_editor_vb = nullptr; Popup *popup_editor = nullptr; LineEdit *line_editor = nullptr; diff --git a/editor/import/3d/post_import_plugin_skeleton_rest_fixer.cpp b/editor/import/3d/post_import_plugin_skeleton_rest_fixer.cpp index 3eabe46950..b69d38afa0 100644 --- a/editor/import/3d/post_import_plugin_skeleton_rest_fixer.cpp +++ b/editor/import/3d/post_import_plugin_skeleton_rest_fixer.cpp @@ -204,7 +204,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory } else { for (int j = 0; j < key_len; j++) { Basis sc = Basis().scaled(static_cast<Vector3>(anim->track_get_key_value(i, j))); - anim->track_set_key_value(i, j, (global_transform.basis * sc).get_scale()); + anim->track_set_key_value(i, j, (global_transform.orthonormalized().basis * sc).get_scale()); } } } diff --git a/editor/import/resource_importer_imagefont.cpp b/editor/import/resource_importer_imagefont.cpp index c454ebc6eb..94e5dd0f12 100644 --- a/editor/import/resource_importer_imagefont.cpp +++ b/editor/import/resource_importer_imagefont.cpp @@ -158,17 +158,16 @@ Error ResourceImporterImageFont::import(const String &p_source_file, const Strin c++; // Skip "+". continue; } - } else if (range[c] == '0') { - if ((c <= range.length() - 2) && range[c + 1] == 'x') { - token = String(); - if (step == STEP_START_BEGIN) { - step = STEP_START_READ_HEX; - } else { - step = STEP_END_READ_HEX; - } - c++; // Skip "x". - continue; + } else if (range[c] == '0' && (c <= range.length() - 2) && range[c + 1] == 'x') { + // Read hexadecimal value, start. + token = String(); + if (step == STEP_START_BEGIN) { + step = STEP_START_READ_HEX; + } else { + step = STEP_END_READ_HEX; } + c++; // Skip "x". + continue; } else if (range[c] == '\'' || range[c] == '\"') { if ((c <= range.length() - 3) && (range[c + 2] == '\'' || range[c + 2] == '\"')) { token = String(); @@ -184,14 +183,13 @@ Error ResourceImporterImageFont::import(const String &p_source_file, const Strin } } else if (is_digit(range[c])) { // Read decimal value, start. - c++; token = String(); + token += range[c]; if (step == STEP_START_BEGIN) { step = STEP_START_READ_DEC; } else { step = STEP_END_READ_DEC; } - token += range[c]; continue; } [[fallthrough]]; @@ -254,9 +252,19 @@ Error ResourceImporterImageFont::import(const String &p_source_file, const Strin } break; } } + if (step == STEP_START_READ_HEX) { + start = token.hex_to_int(); + } else if (step == STEP_START_READ_DEC) { + start = token.to_int(); + } else if (step == STEP_END_READ_HEX) { + end = token.hex_to_int(); + } else if (step == STEP_END_READ_DEC) { + end = token.to_int(); + } if (end == -1) { end = start; } + if (start == -1) { WARN_PRINT(vformat("Invalid range: \"%s\"", range)); continue; diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 731c89250e..a44430ca7f 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -5732,11 +5732,10 @@ void CanvasItemEditorViewport::_create_preview(const Vector<String> &files) cons Ref<Texture2D> texture = Ref<Texture2D>(Object::cast_to<Texture2D>(*res)); Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res)); if (texture != nullptr || scene != nullptr) { - bool root_node_selected = EditorNode::get_singleton()->get_editor_selection()->is_selected(EditorNode::get_singleton()->get_edited_scene()); - String desc = TTR("Drag and drop to add as child of selected node.") + "\n" + TTR("Hold Alt when dropping to add as child of root node."); - if (!root_node_selected) { - desc += "\n" + TTR("Hold Shift when dropping to add as sibling of selected node."); - } + String desc = TTR("Drag and drop to add as sibling of selected node (except when root is selected).") + + "\n" + TTR("Hold Shift when dropping to add as child of selected node.") + + "\n" + TTR("Hold Alt when dropping to add as child of root node."); + if (texture != nullptr) { Sprite2D *sprite = memnew(Sprite2D); sprite->set_texture(texture); @@ -6099,11 +6098,12 @@ void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p Node *root_node = EditorNode::get_singleton()->get_edited_scene(); if (selected_nodes.size() > 0) { Node *selected_node = selected_nodes.front()->get(); - target_node = selected_node; if (is_alt) { target_node = root_node; - } else if (is_shift && selected_node != root_node) { - target_node = selected_node->get_parent(); + } else if (is_shift) { + target_node = selected_node; + } else { // Default behavior. + target_node = (selected_node != root_node) ? selected_node->get_parent() : root_node; } } else { if (root_node) { diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 5873d10e76..ca7ea821e8 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -4593,11 +4593,12 @@ void Node3DEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p_ Node *root_node = EditorNode::get_singleton()->get_edited_scene(); if (selected_nodes.size() > 0) { Node *selected_node = selected_nodes.front()->get(); - target_node = selected_node; if (is_alt) { target_node = root_node; - } else if (is_shift && selected_node != root_node) { - target_node = selected_node->get_parent(); + } else if (is_shift) { + target_node = selected_node; + } else { // Default behavior. + target_node = (selected_node != root_node) ? selected_node->get_parent() : root_node; } } else { if (root_node) { diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 6cb49bbfa6..eb6282ca0c 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -731,6 +731,7 @@ void ScriptEditor::_go_to_tab(int p_idx) { _update_members_overview(); _update_help_overview(); _update_selected_editor_menu(); + _update_online_doc(); _update_members_overview_visibility(); _update_help_overview_visibility(); } @@ -903,6 +904,7 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) { _go_to_tab(idx); } else { _update_selected_editor_menu(); + _update_online_doc(); } _update_history_arrows(); @@ -1350,7 +1352,21 @@ void ScriptEditor::_menu_option(int p_option) { help_search_dialog->popup_dialog(); } break; case SEARCH_WEBSITE: { - OS::get_singleton()->shell_open(VERSION_DOCS_URL "/"); + Control *tab = tab_container->get_current_tab_control(); + + EditorHelp *eh = Object::cast_to<EditorHelp>(tab); + bool native_class_doc = false; + if (eh) { + const HashMap<String, DocData::ClassDoc>::ConstIterator E = EditorHelp::get_doc_data()->class_list.find(eh->get_class()); + native_class_doc = E && !E->value.is_script_doc; + } + if (native_class_doc) { + String name = eh->get_class().to_lower(); + String doc_url = vformat(VERSION_DOCS_URL "/classes/class_%s.html", name); + OS::get_singleton()->shell_open(doc_url); + } else { + OS::get_singleton()->shell_open(VERSION_DOCS_URL "/"); + } } break; case WINDOW_NEXT: { _history_forward(); @@ -2029,6 +2045,26 @@ void ScriptEditor::_update_help_overview() { } } +void ScriptEditor::_update_online_doc() { + Node *current = tab_container->get_tab_control(tab_container->get_current_tab()); + + EditorHelp *eh = Object::cast_to<EditorHelp>(current); + bool native_class_doc = false; + if (eh) { + const HashMap<String, DocData::ClassDoc>::ConstIterator E = EditorHelp::get_doc_data()->class_list.find(eh->get_class()); + native_class_doc = E && !E->value.is_script_doc; + } + if (native_class_doc) { + String name = eh->get_class(); + String tooltip = vformat(TTR("Open '%s' in Godot online documentation."), name); + site_search->set_text(TTR("Open in Online Docs")); + site_search->set_tooltip_text(tooltip); + } else { + site_search->set_text(TTR("Online Docs")); + site_search->set_tooltip_text(TTR("Open Godot online documentation.")); + } +} + void ScriptEditor::_update_script_colors() { bool script_temperature_enabled = EDITOR_GET("text_editor/script_list/script_temperature_enabled"); @@ -4147,10 +4183,8 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) { site_search = memnew(Button); site_search->set_flat(true); - site_search->set_text(TTR("Online Docs")); site_search->connect(SceneStringName(pressed), callable_mp(this, &ScriptEditor::_menu_option).bind(SEARCH_WEBSITE)); menu_hb->add_child(site_search); - site_search->set_tooltip_text(TTR("Open Godot online documentation.")); help_search = memnew(Button); help_search->set_flat(true); @@ -4271,6 +4305,8 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) { Ref<EditorJSONSyntaxHighlighter> json_syntax_highlighter; json_syntax_highlighter.instantiate(); register_syntax_highlighter(json_syntax_highlighter); + + _update_online_doc(); } ScriptEditor::~ScriptEditor() { diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index e6bb8f14a9..6f8e71ce75 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -450,6 +450,8 @@ class ScriptEditor : public PanelContainer { void _update_help_overview(); void _help_overview_selected(int p_idx); + void _update_online_doc(); + void _find_scripts(Node *p_base, Node *p_current, HashSet<Ref<Script>> &used); void _tree_changed(); diff --git a/editor/plugins/text_shader_editor.cpp b/editor/plugins/text_shader_editor.cpp index 637547062c..bb74bf8d1f 100644 --- a/editor/plugins/text_shader_editor.cpp +++ b/editor/plugins/text_shader_editor.cpp @@ -318,6 +318,8 @@ void ShaderTextEditor::_load_theme_settings() { const Color doc_comment_color = EDITOR_GET("text_editor/theme/highlighting/doc_comment_color"); syntax_highlighter->add_color_region("/**", "*/", doc_comment_color, false); + // "/**/" will be treated as the start of the "/**" region, this line is guaranteed to end the color_region. + syntax_highlighter->add_color_region("/**/", "", comment_color, true); // Disabled preprocessor branches use translucent text color to be easier to distinguish from comments. syntax_highlighter->set_disabled_branch_color(Color(EDITOR_GET("text_editor/theme/highlighting/text_color")) * Color(1, 1, 1, 0.5)); diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 38d5c59e0e..a2680c932f 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -3394,6 +3394,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a } #ifdef DEBUG_ENABLED + // FIXME: No warning for built-in constructors and utilities due to early return. if (p_is_root && return_type.kind != GDScriptParser::DataType::UNRESOLVED && return_type.builtin_type != Variant::NIL && !(p_call->is_super && p_call->function_name == GDScriptLanguage::get_singleton()->strings._init)) { parser->push_warning(p_call, GDScriptWarning::RETURN_VALUE_DISCARDED, p_call->function_name); diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 9be9307b8a..76f02e44e9 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -1877,6 +1877,10 @@ GDScriptParser::Node *GDScriptParser::parse_statement() { case Node::CALL: // Fine. break; + case Node::PRELOAD: + // `preload` is a function-like keyword. + push_warning(expression, GDScriptWarning::RETURN_VALUE_DISCARDED, "preload"); + break; case Node::LAMBDA: // Standalone lambdas can't be used, so make this an error. push_error("Standalone lambdas cannot be accessed. Consider assigning it to a variable.", expression); diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp index 48a0abe617..611a9ad2d9 100644 --- a/modules/gdscript/gdscript_warning.cpp +++ b/modules/gdscript/gdscript_warning.cpp @@ -74,7 +74,7 @@ String GDScriptWarning::get_message() const { case UNREACHABLE_PATTERN: return "Unreachable pattern (pattern after wildcard or bind)."; case STANDALONE_EXPRESSION: - return "Standalone expression (the line has no effect)."; + return "Standalone expression (the line may have no effect)."; case STANDALONE_TERNARY: return "Standalone ternary operator: the return value is being discarded."; case INCOMPATIBLE_TERNARY: diff --git a/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.gd b/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.gd index 00598e4d50..f8f70b8cc3 100644 --- a/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.gd +++ b/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.gd @@ -4,3 +4,4 @@ func i_return_int() -> int: func test(): i_return_int() + preload("../../utils.notest.gd") # `preload` is a function-like keyword. diff --git a/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.out b/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.out index f2db4e9307..107051df6c 100644 --- a/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.out +++ b/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.out @@ -3,3 +3,7 @@ GDTEST_OK >> Line: 6 >> RETURN_VALUE_DISCARDED >> The function "i_return_int()" returns a value that will be discarded if not used. +>> WARNING +>> Line: 7 +>> RETURN_VALUE_DISCARDED +>> The function "preload()" returns a value that will be discarded if not used. diff --git a/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.gd b/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.gd index dc4223ec2d..74f42b012b 100644 --- a/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.gd +++ b/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.gd @@ -6,3 +6,16 @@ func test(): Vector3.ZERO [true, false] float(125) + # The following statements should not produce `STANDALONE_EXPRESSION`: + var _a = 1 + _a = 2 # Assignment is a local (or global) side effect. + @warning_ignore("redundant_await") + await 3 # The `await` operand is usually a coroutine or a signal. + absi(4) # A call (in general) can have side effects. + @warning_ignore("return_value_discarded") + preload("../../utils.notest.gd") # A static initializer may have side effects. + """ + Python-like "comment". + """ + @warning_ignore("standalone_ternary") + 1 if 2 else 3 # Produces `STANDALONE_TERNARY` instead. diff --git a/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.out b/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.out index a2c67a6e51..72c659c952 100644 --- a/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.out +++ b/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.out @@ -2,16 +2,16 @@ GDTEST_OK >> WARNING >> Line: 3 >> STANDALONE_EXPRESSION ->> Standalone expression (the line has no effect). +>> Standalone expression (the line may have no effect). >> WARNING >> Line: 4 >> STANDALONE_EXPRESSION ->> Standalone expression (the line has no effect). +>> Standalone expression (the line may have no effect). >> WARNING >> Line: 6 >> STANDALONE_EXPRESSION ->> Standalone expression (the line has no effect). +>> Standalone expression (the line may have no effect). >> WARNING >> Line: 7 >> STANDALONE_EXPRESSION ->> Standalone expression (the line has no effect). +>> Standalone expression (the line may have no effect). diff --git a/modules/svg/SCsub b/modules/svg/SCsub index 0e21c1e6d7..a32be0e41a 100644 --- a/modules/svg/SCsub +++ b/modules/svg/SCsub @@ -26,7 +26,6 @@ thirdparty_sources = [ "src/loaders/raw/tvgRawLoader.cpp", # image loaders "src/loaders/external_png/tvgPngLoader.cpp", - "src/loaders/external_webp/tvgWebpLoader.cpp", "src/loaders/jpg/tvgJpgd.cpp", "src/loaders/jpg/tvgJpgLoader.cpp", # renderer common @@ -59,6 +58,10 @@ thirdparty_sources = [ "src/renderer/sw_engine/tvgSwStroke.cpp", ] +if env["module_webp_enabled"]: + thirdparty_sources += ["src/loaders/external_webp/tvgWebpLoader.cpp"] + env_svg.Append(CPPDEFINES=["THORVG_WEBP_LOADER_SUPPORT"]) + thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] env_svg.Prepend(CPPPATH=[thirdparty_dir + "inc"]) @@ -76,12 +79,15 @@ env_thirdparty.Prepend( thirdparty_dir + "src/renderer/sw_engine", thirdparty_dir + "src/loaders/raw", thirdparty_dir + "src/loaders/external_png", - thirdparty_dir + "src/loaders/external_webp", thirdparty_dir + "src/loaders/jpg", - "#thirdparty/libpng", - "#thirdparty/libwebp/src", ] ) +if env["builtin_libpng"]: + env_thirdparty.Prepend(CPPPATH=["#thirdparty/libpng"]) +if env["module_webp_enabled"]: + env_thirdparty.Prepend(CPPPATH=[thirdparty_dir + "src/loaders/external_webp"]) + if env["builtin_libwebp"]: + env_thirdparty.Prepend(CPPPATH=["#thirdparty/libwebp/src"]) env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources) env.modules_sources += thirdparty_obj diff --git a/platform/web/export/export_plugin.cpp b/platform/web/export/export_plugin.cpp index 0bf3927e14..06dfe7d646 100644 --- a/platform/web/export/export_plugin.cpp +++ b/platform/web/export/export_plugin.cpp @@ -585,17 +585,20 @@ bool EditorExportPlatformWeb::poll_export() { } } + int prev = menu_options; + menu_options = preset.is_valid(); HTTPServerState prev_server_state = server_state; server_state = HTTP_SERVER_STATE_OFF; if (server->is_listening()) { - if (preset.is_null()) { + if (preset.is_null() || menu_options == 0) { server->stop(); } else { server_state = HTTP_SERVER_STATE_ON; + menu_options += 1; } } - return server_state != prev_server_state; + return server_state != prev_server_state || menu_options != prev; } Ref<ImageTexture> EditorExportPlatformWeb::get_option_icon(int p_index) const { diff --git a/platform/web/export/export_plugin.h b/platform/web/export/export_plugin.h index 9d3a1a7861..d3d2083a23 100644 --- a/platform/web/export/export_plugin.h +++ b/platform/web/export/export_plugin.h @@ -58,6 +58,7 @@ class EditorExportPlatformWeb : public EditorExportPlatform { HTTPServerState server_state = HTTP_SERVER_STATE_OFF; Ref<EditorHTTPServer> server; + int menu_options = 0; String _get_template_name(bool p_extension, bool p_thread_support, bool p_debug) const { String name = "web"; diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index 15b7f62036..3bf9d79c7f 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -50,6 +50,83 @@ void Button::_set_internal_margin(Side p_side, float p_value) { void Button::_queue_update_size_cache() { } +void Button::_update_theme_item_cache() { + Control::_update_theme_item_cache(); + + const bool rtl = is_layout_rtl(); + if (rtl && has_theme_stylebox(SNAME("normal_mirrored"))) { + theme_cache.max_style_size = theme_cache.normal_mirrored->get_minimum_size(); + theme_cache.style_margin_left = theme_cache.normal_mirrored->get_margin(SIDE_LEFT); + theme_cache.style_margin_right = theme_cache.normal_mirrored->get_margin(SIDE_RIGHT); + theme_cache.style_margin_top = theme_cache.normal_mirrored->get_margin(SIDE_TOP); + theme_cache.style_margin_bottom = theme_cache.normal_mirrored->get_margin(SIDE_BOTTOM); + } else { + theme_cache.max_style_size = theme_cache.normal->get_minimum_size(); + theme_cache.style_margin_left = theme_cache.normal->get_margin(SIDE_LEFT); + theme_cache.style_margin_right = theme_cache.normal->get_margin(SIDE_RIGHT); + theme_cache.style_margin_top = theme_cache.normal->get_margin(SIDE_TOP); + theme_cache.style_margin_bottom = theme_cache.normal->get_margin(SIDE_BOTTOM); + } + if (has_theme_stylebox("hover_pressed")) { + if (rtl && has_theme_stylebox(SNAME("hover_pressed_mirrored"))) { + theme_cache.max_style_size = theme_cache.max_style_size.max(theme_cache.hover_pressed_mirrored->get_minimum_size()); + theme_cache.style_margin_left = MAX(theme_cache.style_margin_left, theme_cache.hover_pressed_mirrored->get_margin(SIDE_LEFT)); + theme_cache.style_margin_right = MAX(theme_cache.style_margin_right, theme_cache.hover_pressed_mirrored->get_margin(SIDE_RIGHT)); + theme_cache.style_margin_top = MAX(theme_cache.style_margin_top, theme_cache.hover_pressed_mirrored->get_margin(SIDE_TOP)); + theme_cache.style_margin_bottom = MAX(theme_cache.style_margin_bottom, theme_cache.hover_pressed_mirrored->get_margin(SIDE_BOTTOM)); + } else { + theme_cache.max_style_size = theme_cache.max_style_size.max(theme_cache.hover_pressed->get_minimum_size()); + theme_cache.style_margin_left = MAX(theme_cache.style_margin_left, theme_cache.hover_pressed->get_margin(SIDE_LEFT)); + theme_cache.style_margin_right = MAX(theme_cache.style_margin_right, theme_cache.hover_pressed->get_margin(SIDE_RIGHT)); + theme_cache.style_margin_top = MAX(theme_cache.style_margin_top, theme_cache.hover_pressed->get_margin(SIDE_TOP)); + theme_cache.style_margin_bottom = MAX(theme_cache.style_margin_bottom, theme_cache.hover_pressed->get_margin(SIDE_BOTTOM)); + } + } + if (rtl && has_theme_stylebox(SNAME("pressed_mirrored"))) { + theme_cache.max_style_size = theme_cache.max_style_size.max(theme_cache.pressed_mirrored->get_minimum_size()); + theme_cache.style_margin_left = MAX(theme_cache.style_margin_left, theme_cache.pressed_mirrored->get_margin(SIDE_LEFT)); + theme_cache.style_margin_right = MAX(theme_cache.style_margin_right, theme_cache.pressed_mirrored->get_margin(SIDE_RIGHT)); + theme_cache.style_margin_top = MAX(theme_cache.style_margin_top, theme_cache.pressed_mirrored->get_margin(SIDE_TOP)); + theme_cache.style_margin_bottom = MAX(theme_cache.style_margin_bottom, theme_cache.pressed_mirrored->get_margin(SIDE_BOTTOM)); + } else { + theme_cache.max_style_size = theme_cache.max_style_size.max(theme_cache.pressed->get_minimum_size()); + theme_cache.style_margin_left = MAX(theme_cache.style_margin_left, theme_cache.pressed->get_margin(SIDE_LEFT)); + theme_cache.style_margin_right = MAX(theme_cache.style_margin_right, theme_cache.pressed->get_margin(SIDE_RIGHT)); + theme_cache.style_margin_top = MAX(theme_cache.style_margin_top, theme_cache.pressed->get_margin(SIDE_TOP)); + theme_cache.style_margin_bottom = MAX(theme_cache.style_margin_bottom, theme_cache.pressed->get_margin(SIDE_BOTTOM)); + } + if (rtl && has_theme_stylebox(SNAME("hover_mirrored"))) { + theme_cache.max_style_size = theme_cache.max_style_size.max(theme_cache.hover_mirrored->get_minimum_size()); + theme_cache.style_margin_left = MAX(theme_cache.style_margin_left, theme_cache.hover_mirrored->get_margin(SIDE_LEFT)); + theme_cache.style_margin_right = MAX(theme_cache.style_margin_right, theme_cache.hover_mirrored->get_margin(SIDE_RIGHT)); + theme_cache.style_margin_top = MAX(theme_cache.style_margin_top, theme_cache.hover_mirrored->get_margin(SIDE_TOP)); + theme_cache.style_margin_bottom = MAX(theme_cache.style_margin_bottom, theme_cache.hover_mirrored->get_margin(SIDE_BOTTOM)); + } else { + theme_cache.max_style_size = theme_cache.max_style_size.max(theme_cache.hover->get_minimum_size()); + theme_cache.style_margin_left = MAX(theme_cache.style_margin_left, theme_cache.hover->get_margin(SIDE_LEFT)); + theme_cache.style_margin_right = MAX(theme_cache.style_margin_right, theme_cache.hover->get_margin(SIDE_RIGHT)); + theme_cache.style_margin_top = MAX(theme_cache.style_margin_top, theme_cache.hover->get_margin(SIDE_TOP)); + theme_cache.style_margin_bottom = MAX(theme_cache.style_margin_bottom, theme_cache.hover->get_margin(SIDE_BOTTOM)); + } + if (rtl && has_theme_stylebox(SNAME("disabled_mirrored"))) { + theme_cache.max_style_size = theme_cache.max_style_size.max(theme_cache.disabled_mirrored->get_minimum_size()); + theme_cache.style_margin_left = MAX(theme_cache.style_margin_left, theme_cache.disabled_mirrored->get_margin(SIDE_LEFT)); + theme_cache.style_margin_right = MAX(theme_cache.style_margin_right, theme_cache.disabled_mirrored->get_margin(SIDE_RIGHT)); + theme_cache.style_margin_top = MAX(theme_cache.style_margin_top, theme_cache.disabled_mirrored->get_margin(SIDE_TOP)); + theme_cache.style_margin_bottom = MAX(theme_cache.style_margin_bottom, theme_cache.disabled_mirrored->get_margin(SIDE_BOTTOM)); + } else { + theme_cache.max_style_size = theme_cache.max_style_size.max(theme_cache.disabled->get_minimum_size()); + theme_cache.style_margin_left = MAX(theme_cache.style_margin_left, theme_cache.disabled->get_margin(SIDE_LEFT)); + theme_cache.style_margin_right = MAX(theme_cache.style_margin_right, theme_cache.disabled->get_margin(SIDE_RIGHT)); + theme_cache.style_margin_top = MAX(theme_cache.style_margin_top, theme_cache.disabled->get_margin(SIDE_TOP)); + theme_cache.style_margin_bottom = MAX(theme_cache.style_margin_bottom, theme_cache.disabled->get_margin(SIDE_BOTTOM)); + } +} + +Size2 Button::_get_largest_stylebox_size() const { + return theme_cache.max_style_size; +} + Ref<StyleBox> Button::_get_current_stylebox() const { Ref<StyleBox> stylebox = theme_cache.normal; const bool rtl = is_layout_rtl(); @@ -137,16 +214,13 @@ void Button::_notification(int p_what) { const RID ci = get_canvas_item(); const Size2 size = get_size(); - const Ref<StyleBox> style = _get_current_stylebox(); - { // Draws the stylebox in the current state. - if (!flat) { - style->draw(ci, Rect2(Point2(), size)); - } + // Draws the stylebox in the current state. + if (!flat) { + _get_current_stylebox()->draw(ci, Rect2(Point2(), size)); + } - if (has_focus()) { - Ref<StyleBox> style2 = theme_cache.focus; - style2->draw(ci, Rect2(Point2(), size)); - } + if (has_focus()) { + theme_cache.focus->draw(ci, Rect2(Point2(), size)); } Ref<Texture2D> _icon = icon; @@ -158,16 +232,11 @@ void Button::_notification(int p_what) { break; } - const float style_margin_left = style->get_margin(SIDE_LEFT); - const float style_margin_right = style->get_margin(SIDE_RIGHT); - const float style_margin_top = style->get_margin(SIDE_TOP); - const float style_margin_bottom = style->get_margin(SIDE_BOTTOM); - Size2 drawable_size_remained = size; { // The size after the stelybox is stripped. - drawable_size_remained.width -= style_margin_left + style_margin_right; - drawable_size_remained.height -= style_margin_top + style_margin_bottom; + drawable_size_remained.width -= theme_cache.style_margin_left + theme_cache.style_margin_right; + drawable_size_remained.height -= theme_cache.style_margin_top + theme_cache.style_margin_bottom; } const int h_separation = MAX(0, theme_cache.h_separation); @@ -312,12 +381,12 @@ void Button::_notification(int p_what) { [[fallthrough]]; case HORIZONTAL_ALIGNMENT_FILL: case HORIZONTAL_ALIGNMENT_LEFT: { - icon_ofs.x += style_margin_left; + icon_ofs.x += theme_cache.style_margin_left; icon_ofs.x += left_internal_margin_with_h_separation; } break; case HORIZONTAL_ALIGNMENT_RIGHT: { - icon_ofs.x = size.x - style_margin_right; + icon_ofs.x = size.x - theme_cache.style_margin_right; icon_ofs.x -= right_internal_margin_with_h_separation; icon_ofs.x -= icon_size.width; } break; @@ -330,11 +399,11 @@ void Button::_notification(int p_what) { [[fallthrough]]; case VERTICAL_ALIGNMENT_FILL: case VERTICAL_ALIGNMENT_TOP: { - icon_ofs.y += style_margin_top; + icon_ofs.y += theme_cache.style_margin_top; } break; case VERTICAL_ALIGNMENT_BOTTOM: { - icon_ofs.y = size.y - style_margin_bottom - icon_size.height; + icon_ofs.y = size.y - theme_cache.style_margin_bottom - icon_size.height; } break; } icon_ofs = icon_ofs.floor(); @@ -373,7 +442,7 @@ void Button::_notification(int p_what) { case HORIZONTAL_ALIGNMENT_FILL: case HORIZONTAL_ALIGNMENT_LEFT: case HORIZONTAL_ALIGNMENT_RIGHT: { - text_ofs.x += style_margin_left; + text_ofs.x += theme_cache.style_margin_left; text_ofs.x += left_internal_margin_with_h_separation; if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_LEFT) { // Offset by the space's width that occupied by icon and h_separation together. @@ -382,7 +451,7 @@ void Button::_notification(int p_what) { } break; } - text_ofs.y = (drawable_size_remained.height - text_buf->get_size().height) / 2.0f + style_margin_top; + text_ofs.y = (drawable_size_remained.height - text_buf->get_size().height) / 2.0f + theme_cache.style_margin_top; if (vertical_icon_alignment == VERTICAL_ALIGNMENT_TOP) { text_ofs.y += custom_element_size.height - drawable_size_remained.height; // Offset by the icon's height. } @@ -452,7 +521,7 @@ Size2 Button::get_minimum_size_for_text_and_icon(const String &p_text, Ref<Textu } } - return _get_current_stylebox()->get_minimum_size() + minsize; + return _get_largest_stylebox_size() + minsize; } void Button::_shape(Ref<TextParagraph> p_paragraph, String p_text) { diff --git a/scene/gui/button.h b/scene/gui/button.h index 86fdbd35d5..d2f80893e0 100644 --- a/scene/gui/button.h +++ b/scene/gui/button.h @@ -69,6 +69,12 @@ private: Ref<StyleBox> disabled_mirrored; Ref<StyleBox> focus; + Size2 max_style_size; + float style_margin_left = 0; + float style_margin_right = 0; + float style_margin_top = 0; + float style_margin_bottom = 0; + Color font_color; Color font_focus_color; Color font_pressed_color; @@ -100,10 +106,13 @@ private: void _texture_changed(); protected: + virtual void _update_theme_item_cache() override; + void _set_internal_margin(Side p_side, float p_value); virtual void _queue_update_size_cache(); Ref<StyleBox> _get_current_stylebox() const; + Size2 _get_largest_stylebox_size() const; void _notification(int p_what); static void _bind_methods(); diff --git a/scene/gui/check_box.cpp b/scene/gui/check_box.cpp index af6696834e..0dcd1d4ac4 100644 --- a/scene/gui/check_box.cpp +++ b/scene/gui/check_box.cpp @@ -66,7 +66,7 @@ Size2 CheckBox::get_minimum_size() const { Size2 minsize = Button::get_minimum_size(); const Size2 tex_size = get_icon_size(); if (tex_size.width > 0 || tex_size.height > 0) { - const Size2 padding = _get_current_stylebox()->get_minimum_size(); + const Size2 padding = _get_largest_stylebox_size(); Size2 content_size = minsize - padding; if (content_size.width > 0 && tex_size.width > 0) { content_size.width += MAX(0, theme_cache.h_separation); diff --git a/scene/gui/check_button.cpp b/scene/gui/check_button.cpp index ab3b74a3c3..fe449fbfc3 100644 --- a/scene/gui/check_button.cpp +++ b/scene/gui/check_button.cpp @@ -70,7 +70,7 @@ Size2 CheckButton::get_minimum_size() const { Size2 minsize = Button::get_minimum_size(); const Size2 tex_size = get_icon_size(); if (tex_size.width > 0 || tex_size.height > 0) { - const Size2 padding = _get_current_stylebox()->get_minimum_size(); + const Size2 padding = _get_largest_stylebox_size(); Size2 content_size = minsize - padding; if (content_size.width > 0 && tex_size.width > 0) { content_size.width += MAX(0, theme_cache.h_separation); diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index 0f161a014a..68e72ea996 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -60,7 +60,7 @@ Size2 OptionButton::get_minimum_size() const { } if (has_theme_icon(SNAME("arrow"))) { - const Size2 padding = _get_current_stylebox()->get_minimum_size(); + const Size2 padding = _get_largest_stylebox_size(); const Size2 arrow_size = theme_cache.arrow_icon->get_size(); Size2 content_size = minsize - padding; diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index 1d45a10d2a..38204af6d5 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -37,6 +37,7 @@ void Popup::_input_from_window(const Ref<InputEvent> &p_event) { if (get_flag(FLAG_POPUP) && p_event->is_action_pressed(SNAME("ui_cancel"), false, true)) { + hide_reason = HIDE_REASON_CANCELED; // ESC pressed, mark as canceled unconditionally. _close_pressed(); } Window::_input_from_window(p_event); @@ -104,13 +105,18 @@ void Popup::_notification(int p_what) { case NOTIFICATION_WM_CLOSE_REQUEST: { if (!is_in_edited_scene_root()) { - hide_reason = HIDE_REASON_UNFOCUSED; + if (hide_reason == HIDE_REASON_NONE) { + hide_reason = HIDE_REASON_UNFOCUSED; + } _close_pressed(); } } break; case NOTIFICATION_APPLICATION_FOCUS_OUT: { if (!is_in_edited_scene_root() && get_flag(FLAG_POPUP)) { + if (hide_reason == HIDE_REASON_NONE) { + hide_reason = HIDE_REASON_UNFOCUSED; + } _close_pressed(); } } break; @@ -119,7 +125,9 @@ void Popup::_notification(int p_what) { void Popup::_parent_focused() { if (popped_up && get_flag(FLAG_POPUP)) { - hide_reason = HIDE_REASON_UNFOCUSED; + if (hide_reason == HIDE_REASON_NONE) { + hide_reason = HIDE_REASON_UNFOCUSED; + } _close_pressed(); } } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 49cfa8a030..69b84da23d 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -558,8 +558,6 @@ void TextEdit::_notification(int p_what) { int visible_rows = get_visible_line_count() + 1; - Color color = !editable ? theme_cache.font_readonly_color : theme_cache.font_color; - if (theme_cache.background_color.a > 0.01) { RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(), get_size()), theme_cache.background_color); } @@ -734,7 +732,7 @@ void TextEdit::_notification(int p_what) { if (draw_minimap) { int minimap_visible_lines = get_minimap_visible_lines(); int minimap_line_height = (minimap_char_size.y + minimap_line_spacing); - int minimap_tab_size = minimap_char_size.x * text.get_tab_size(); + int tab_size = text.get_tab_size(); // Calculate viewport size and y offset. int viewport_height = (draw_amount - 1) * minimap_line_height; @@ -839,68 +837,74 @@ void TextEdit::_notification(int p_what) { } } - Color previous_color; + Color next_color = current_color; int characters = 0; - int tabs = 0; + int tab_alignment = 0; + int xpos = xmargin_end + 2 + indent_px; for (int j = 0; j < str.length(); j++) { - const Variant *color_data = color_map.getptr(last_wrap_column + j); - if (color_data != nullptr) { - current_color = (color_data->operator Dictionary()).get("color", theme_cache.font_color); - if (!editable) { - current_color.a = theme_cache.font_readonly_color.a; + bool next_is_whitespace = false; + bool next_is_tab = false; + // Get the number of characters to draw together. + for (characters = 0; j + characters < str.length(); characters++) { + int next_char_index = j + characters; + const Variant *color_data = color_map.getptr(last_wrap_column + next_char_index); + if (color_data != nullptr) { + next_color = (color_data->operator Dictionary()).get("color", theme_cache.font_color); + if (!editable) { + next_color.a = theme_cache.font_readonly_color.a; + } + next_color.a *= 0.6; } - } - color = current_color; - - if (j == 0) { - previous_color = color; - } - - int xpos = indent_px + ((xmargin_end + minimap_char_size.x) + (minimap_char_size.x * j)) + tabs; - bool out_of_bounds = (xpos >= xmargin_end + minimap_width); - - bool whitespace = is_whitespace(str[j]); - if (!whitespace) { - characters++; - - if (j < str.length() - 1 && color == previous_color && !out_of_bounds) { - continue; + if (characters == 0) { + current_color = next_color; } - - // If we've changed color we are at the start of a new section, therefore we need to go back to the end - // of the previous section to draw it, we'll also add the character back on. - if (color != previous_color) { - characters--; - j--; - - if (str[j] == '\t') { - tabs -= minimap_tab_size; + if (next_color != current_color) { + break; + } + next_is_whitespace = is_whitespace(str[next_char_index]); + if (next_is_whitespace) { + if (str[next_char_index] == '\t') { + next_is_tab = true; } + break; + } + bool out_of_bounds = xpos + minimap_char_size.x * characters >= xmargin_end + minimap_width; + if (out_of_bounds) { + break; } } + if (!next_is_whitespace && characters == 0) { + break; + } if (characters > 0) { - previous_color.a *= 0.6; - // Take one for zero indexing, and if we hit whitespace / the end of a word. - int chars = MAX(0, (j - (characters - 1)) - (whitespace ? 1 : 0)) + 1; - int char_x_ofs = indent_px + ((xmargin_end + minimap_char_size.x) + (minimap_char_size.x * chars)) + tabs; if (rtl) { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(size.width - char_x_ofs - minimap_char_size.x * characters, minimap_line_height * i), Point2(minimap_char_size.x * characters, minimap_char_size.y)), previous_color); + RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(size.width - xpos - minimap_char_size.x * characters, minimap_line_height * i), Point2(minimap_char_size.x * characters, minimap_char_size.y)), current_color); } else { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(char_x_ofs, minimap_line_height * i), Point2(minimap_char_size.x * characters, minimap_char_size.y)), previous_color); + RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(xpos, minimap_line_height * i), Point2(minimap_char_size.x * characters, minimap_char_size.y)), current_color); } } - if (out_of_bounds) { - break; - } + j += characters - 1; + xpos += minimap_char_size.x * characters; + tab_alignment += characters; - if (str[j] == '\t') { - tabs += minimap_tab_size; + if (next_is_whitespace) { + if (next_is_tab) { + tab_alignment %= tab_size; + xpos += minimap_char_size.x * (tab_size - tab_alignment); + tab_alignment = 0; + } else { + xpos += minimap_char_size.x; + tab_alignment += 1; + } + j += 1; } - previous_color = color; - characters = 0; + if (xpos >= xmargin_end + minimap_width) { + // Out of bounds. + break; + } } } } @@ -1188,6 +1192,7 @@ void TextEdit::_notification(int p_what) { if (!clipped && lookup_symbol_word.length() != 0) { // Highlight word if (is_ascii_alphabet_char(lookup_symbol_word[0]) || lookup_symbol_word[0] == '_' || lookup_symbol_word[0] == '.') { + Color highlight_underline_color = !editable ? theme_cache.font_readonly_color : theme_cache.font_color; int lookup_symbol_word_col = _get_column_pos_of_word(lookup_symbol_word, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, 0); int lookup_symbol_word_len = lookup_symbol_word.length(); while (lookup_symbol_word_col != -1) { @@ -1205,7 +1210,7 @@ void TextEdit::_notification(int p_what) { } rect.position.y += ceil(TS->shaped_text_get_ascent(rid)) + ceil(theme_cache.font->get_underline_position(theme_cache.font_size)); rect.size.y = MAX(1, theme_cache.font->get_underline_thickness(theme_cache.font_size)); - draw_rect(rect, color); + draw_rect(rect, highlight_underline_color); } lookup_symbol_word_col = _get_column_pos_of_word(lookup_symbol_word, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, lookup_symbol_word_col + lookup_symbol_word_len); @@ -7973,7 +7978,7 @@ void TextEdit::_update_minimap_click() { Point2 mp = get_local_mouse_pos(); int xmargin_end = get_size().width - theme_cache.style_normal->get_margin(SIDE_RIGHT); - if (!dragging_minimap && (mp.x < xmargin_end - minimap_width || mp.y > xmargin_end)) { + if (!dragging_minimap && (mp.x < xmargin_end - minimap_width || mp.x > xmargin_end)) { minimap_clicked = false; return; } diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 133515754b..fc5b942918 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -3152,8 +3152,12 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int } void Tree::_text_editor_popup_modal_close() { + if (popup_edit_commited) { + return; // Already processed by LineEdit/TextEdit commit. + } + if (popup_editor->get_hide_reason() == Popup::HIDE_REASON_CANCELED) { - return; + return; // ESC pressed, app focus lost, or forced close from code. } if (value_editor->has_point(value_editor->get_local_mouse_position())) { @@ -3172,9 +3176,18 @@ void Tree::_text_editor_popup_modal_close() { } void Tree::_text_editor_gui_input(const Ref<InputEvent> &p_event) { + if (popup_edit_commited) { + return; // Already processed by _text_editor_popup_modal_close + } + + if (popup_editor->get_hide_reason() == Popup::HIDE_REASON_CANCELED) { + return; // ESC pressed, app focus lost, or forced close from code. + } + if (p_event->is_action_pressed("ui_text_newline_blank", true)) { accept_event(); } else if (p_event->is_action_pressed("ui_text_newline")) { + popup_edit_commited = true; // End edit popup processing. popup_editor->hide(); _apply_multiline_edit(); accept_event(); @@ -3205,6 +3218,15 @@ void Tree::_apply_multiline_edit() { } void Tree::_line_editor_submit(String p_text) { + if (popup_edit_commited) { + return; // Already processed by _text_editor_popup_modal_close + } + + if (popup_editor->get_hide_reason() == Popup::HIDE_REASON_CANCELED) { + return; // ESC pressed, app focus lost, or forced close from code. + } + + popup_edit_commited = true; // End edit popup processing. popup_editor->hide(); if (!popup_edited_item) { @@ -4072,6 +4094,7 @@ bool Tree::edit_selected(bool p_force_edit) { if (!popup_editor->is_embedded()) { popup_editor->set_content_scale_factor(popup_scale); } + popup_edit_commited = false; // Start edit popup processing. popup_editor->popup(); popup_editor->child_controls_changed(); @@ -4091,6 +4114,7 @@ bool Tree::edit_selected(bool p_force_edit) { if (!popup_editor->is_embedded()) { popup_editor->set_content_scale_factor(popup_scale); } + popup_edit_commited = false; // Start edit popup processing. popup_editor->popup(); popup_editor->child_controls_changed(); diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 311055a2f8..e9c93c6e03 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -479,6 +479,7 @@ private: VBoxContainer *popup_editor_vb = nullptr; + bool popup_edit_commited = true; Popup *popup_editor = nullptr; LineEdit *line_editor = nullptr; TextEdit *text_editor = nullptr; diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index 5e9510c1ac..8267e958b4 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -155,7 +155,7 @@ void Shader::get_shader_uniform_list(List<PropertyInfo> *p_params, bool p_get_gr DocData::PropertyDoc prop_doc; prop_doc.name = "shader_parameter/" + pi.name; #ifdef MODULE_REGEX_ENABLED - const RegEx pattern("/\\*\\*([^*]|[\\r\\n]|(\\*+([^*/]|[\\r\\n])))*\\*+/\\s*uniform\\s+\\w+\\s+" + pi.name + "(?=[\\s:;=])"); + const RegEx pattern("/\\*\\*\\s([^*]|[\\r\\n]|(\\*+([^*/]|[\\r\\n])))*\\*+/\\s*uniform\\s+\\w+\\s+" + pi.name + "(?=[\\s:;=])"); Ref<RegExMatch> pattern_ref = pattern.search(code); if (pattern_ref != nullptr) { RegExMatch *match = pattern_ref.ptr(); diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index 012451a5cd..14d138181f 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -169,7 +169,11 @@ void RendererCompositorRD::set_boot_image(const Ref<Image> &p_image, const Color return; } - RD::get_singleton()->screen_prepare_for_drawing(DisplayServer::MAIN_WINDOW_ID); + Error err = RD::get_singleton()->screen_prepare_for_drawing(DisplayServer::MAIN_WINDOW_ID); + if (err != OK) { + // Window is minimized and does not have valid swapchain, skip drawing without printing errors. + return; + } RID texture = texture_storage->texture_allocate(); texture_storage->texture_2d_initialize(texture, p_image); diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index d630238cb9..15e1731823 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -3154,9 +3154,6 @@ Error RenderingDevice::screen_create(DisplayServer::WindowID p_screen) { RDD::SwapChainID swap_chain = driver->swap_chain_create(surface); ERR_FAIL_COND_V_MSG(swap_chain.id == 0, ERR_CANT_CREATE, "Unable to create swap chain."); - Error err = driver->swap_chain_resize(main_queue, swap_chain, _get_swap_chain_desired_count()); - ERR_FAIL_COND_V_MSG(err != OK, ERR_CANT_CREATE, "Unable to resize the new swap chain."); - screen_swap_chains[p_screen] = swap_chain; return OK; diff --git a/thirdparty/thorvg/inc/config.h b/thirdparty/thorvg/inc/config.h index f271b52faf..3ae166cf22 100644 --- a/thirdparty/thorvg/inc/config.h +++ b/thirdparty/thorvg/inc/config.h @@ -5,9 +5,11 @@ #define THORVG_SVG_LOADER_SUPPORT #define THORVG_PNG_LOADER_SUPPORT #define THORVG_JPG_LOADER_SUPPORT -#define THORVG_WEBP_LOADER_SUPPORT #define THORVG_THREAD_SUPPORT +// Added conditionally if webp module is enabled. +//#define THORVG_WEBP_LOADER_SUPPORT + // For internal debugging: //#define THORVG_LOG_ENABLED diff --git a/thirdparty/thorvg/update-thorvg.sh b/thirdparty/thorvg/update-thorvg.sh index 23604afbcd..796060d3fb 100755 --- a/thirdparty/thorvg/update-thorvg.sh +++ b/thirdparty/thorvg/update-thorvg.sh @@ -38,9 +38,11 @@ cat << EOF > ../inc/config.h #define THORVG_SVG_LOADER_SUPPORT #define THORVG_PNG_LOADER_SUPPORT #define THORVG_JPG_LOADER_SUPPORT -#define THORVG_WEBP_LOADER_SUPPORT #define THORVG_THREAD_SUPPORT +// Added conditionally if webp module is enabled. +//#define THORVG_WEBP_LOADER_SUPPORT + // For internal debugging: //#define THORVG_LOG_ENABLED |