diff options
80 files changed, 738 insertions, 370 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/core/io/resource.cpp b/core/io/resource.cpp index 573692f41e..1ecfd8366d 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -569,11 +569,18 @@ Resource::Resource() : remapped_list(this) {} Resource::~Resource() { - if (!path_cache.is_empty()) { - ResourceCache::lock.lock(); - ResourceCache::resources.erase(path_cache); - ResourceCache::lock.unlock(); + if (unlikely(path_cache.is_empty())) { + return; } + + ResourceCache::lock.lock(); + // Only unregister from the cache if this is the actual resource listed there. + // (Other resources can have the same value in `path_cache` if loaded with `CACHE_IGNORE`.) + HashMap<String, Resource *>::Iterator E = ResourceCache::resources.find(path_cache); + if (likely(E && E->value == this)) { + ResourceCache::resources.remove(E); + } + ResourceCache::lock.unlock(); } HashMap<String, Resource *> ResourceCache::resources; 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 a65347a5b1..2dcf623995 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -1391,7 +1391,7 @@ void TextureStorage::texture_debug_usage(List<RS::TextureInfo> *r_info) { tinfo.format = t->format; tinfo.width = t->alloc_width; tinfo.height = t->alloc_height; - tinfo.depth = 0; + tinfo.depth = t->depth; tinfo.bytes = t->total_data_size; r_info->push_back(tinfo); } @@ -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_help.cpp b/editor/editor_help.cpp index a8d978c66d..9884241708 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -1967,7 +1967,7 @@ void EditorHelp::_update_doc() { class_desc->add_text(argument.name); class_desc->add_text(": "); - _add_type(argument.type); + _add_type(argument.type, argument.enumeration, argument.is_bitfield); if (!argument.default_value.is_empty()) { class_desc->push_color(theme_cache.symbol_color); 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/main/main.cpp b/main/main.cpp index 66706be745..65f637d778 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -2196,11 +2196,11 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph if (globals->has_setting("display/window/size/window_width_override") && globals->has_setting("display/window/size/window_height_override")) { - int desired_width = globals->get("display/window/size/window_width_override"); + int desired_width = GLOBAL_GET("display/window/size/window_width_override"); if (desired_width > 0) { window_size.width = desired_width; } - int desired_height = globals->get("display/window/size/window_height_override"); + int desired_height = GLOBAL_GET("display/window/size/window_height_override"); if (desired_height > 0) { window_size.height = desired_height; } @@ -4295,9 +4295,6 @@ void Main::cleanup(bool p_force) { if (globals) { memdelete(globals); } - if (engine) { - memdelete(engine); - } if (OS::get_singleton()->is_restart_on_exit_set()) { //attempt to restart with arguments @@ -4315,6 +4312,10 @@ void Main::cleanup(bool p_force) { uninitialize_modules(MODULE_INITIALIZATION_LEVEL_CORE); unregister_core_types(); + if (engine) { + memdelete(engine); + } + OS::get_singleton()->benchmark_end_measure("Shutdown", "Total"); OS::get_singleton()->benchmark_dump(); diff --git a/misc/scripts/dotnet_format.py b/misc/scripts/dotnet_format.py index 51fd7a1223..51fd7a1223 100644..100755 --- a/misc/scripts/dotnet_format.py +++ b/misc/scripts/dotnet_format.py diff --git a/misc/scripts/file_format.py b/misc/scripts/file_format.py index a4ea544a45..a4ea544a45 100644..100755 --- a/misc/scripts/file_format.py +++ b/misc/scripts/file_format.py diff --git a/misc/scripts/gitignore_check.sh b/misc/scripts/gitignore_check.sh index f162e25391..f162e25391 100644..100755 --- a/misc/scripts/gitignore_check.sh +++ b/misc/scripts/gitignore_check.sh diff --git a/misc/scripts/header_guards.py b/misc/scripts/header_guards.py index b554be5159..b554be5159 100644..100755 --- a/misc/scripts/header_guards.py +++ b/misc/scripts/header_guards.py diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 07d917ea04..1909ca5ab5 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -349,10 +349,11 @@ <param index="1" name="hint_string" type="String" /> <param index="2" name="usage" type="int" enum="PropertyUsageFlags" is_bitfield="true" default="6" /> <description> - Allows you to set a custom hint, hint string, and usage flags for the exported property. Note that there's no validation done in GDScript, it will just pass the hint along to the editor. + Allows you to set a custom hint, hint string, and usage flags for the exported property. Note that there's no validation done in GDScript, it will just pass the parameters to the editor. [codeblock] @export_custom(PROPERTY_HINT_NONE, "suffix:m") var suffix: Vector3 [/codeblock] + [b]Note:[/b] Regardless of the [param usage] value, the [constant PROPERTY_USAGE_SCRIPT_VARIABLE] flag is always added, as with any explicitly declared script variable. </description> </annotation> <annotation name="@export_dir"> 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_editor.cpp b/modules/gdscript/gdscript_editor.cpp index cae85d7c70..4ae39d80cd 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -911,6 +911,29 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a option.insert_text = option.display.quote(p_quote_style); r_result.insert(option.display, option); } + } else if (p_annotation->name == SNAME("@export_custom")) { + switch (p_argument) { + case 0: { + static HashMap<StringName, int64_t> items; + if (unlikely(items.is_empty())) { + CoreConstants::get_enum_values(SNAME("PropertyHint"), &items); + } + for (const KeyValue<StringName, int64_t> &item : items) { + ScriptLanguage::CodeCompletionOption option(item.key, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT); + r_result.insert(option.display, option); + } + } break; + case 2: { + static HashMap<StringName, int64_t> items; + if (unlikely(items.is_empty())) { + CoreConstants::get_enum_values(SNAME("PropertyUsageFlags"), &items); + } + for (const KeyValue<StringName, int64_t> &item : items) { + ScriptLanguage::CodeCompletionOption option(item.key, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT); + r_result.insert(option.display, option); + } + } break; + } } else if (p_annotation->name == SNAME("@warning_ignore")) { for (int warning_code = 0; warning_code < GDScriptWarning::WARNING_MAX; warning_code++) { ScriptLanguage::CodeCompletionOption warning(GDScriptWarning::get_name_from_code((GDScriptWarning::Code)warning_code).to_lower(), ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); @@ -2065,6 +2088,12 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, found = false; } + // If the found type was not fully analyzed we analyze it now. + if (found && r_type.type.kind == GDScriptParser::DataType::CLASS && !r_type.type.class_type->resolved_body) { + Error err; + Ref<GDScriptParserRef> r = GDScriptCache::get_parser(r_type.type.script_path, GDScriptParserRef::FULLY_SOLVED, err); + } + // Check type hint last. For collections we want chance to get the actual value first // This way we can detect types from the content of dictionaries and arrays if (!found && p_expression->get_datatype().is_hard_type()) { diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 9be9307b8a..9a4c92f601 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -101,7 +101,6 @@ GDScriptParser::GDScriptParser() { register_annotation(MethodInfo("@onready"), AnnotationInfo::VARIABLE, &GDScriptParser::onready_annotation); // Export annotations. register_annotation(MethodInfo("@export"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NONE, Variant::NIL>); - register_annotation(MethodInfo("@export_storage"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NONE, Variant::NIL>); register_annotation(MethodInfo("@export_enum", PropertyInfo(Variant::STRING, "names")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_ENUM, Variant::NIL>, varray(), true); register_annotation(MethodInfo("@export_file", PropertyInfo(Variant::STRING, "filter")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_FILE, Variant::STRING>, varray(""), true); register_annotation(MethodInfo("@export_dir"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_DIR, Variant::STRING>); @@ -121,6 +120,7 @@ GDScriptParser::GDScriptParser() { register_annotation(MethodInfo("@export_flags_3d_physics"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_PHYSICS, Variant::INT>); register_annotation(MethodInfo("@export_flags_3d_navigation"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_NAVIGATION, Variant::INT>); register_annotation(MethodInfo("@export_flags_avoidance"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_AVOIDANCE, Variant::INT>); + register_annotation(MethodInfo("@export_storage"), AnnotationInfo::VARIABLE, &GDScriptParser::export_storage_annotation); register_annotation(MethodInfo("@export_custom", PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_CLASS_IS_ENUM, "PropertyHint"), PropertyInfo(Variant::STRING, "hint_string"), PropertyInfo(Variant::INT, "usage", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_CLASS_IS_BITFIELD, "PropertyUsageFlags")), AnnotationInfo::VARIABLE, &GDScriptParser::export_custom_annotation, varray(PROPERTY_USAGE_DEFAULT)); // Export grouping annotations. register_annotation(MethodInfo("@export_category", PropertyInfo(Variant::STRING, "name")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_CATEGORY>); @@ -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); @@ -4295,7 +4299,7 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node case GDScriptParser::DataType::BUILTIN: variable->export_info.type = export_type.builtin_type; variable->export_info.hint = PROPERTY_HINT_NONE; - variable->export_info.hint_string = Variant::get_type_name(export_type.builtin_type); + variable->export_info.hint_string = String(); break; case GDScriptParser::DataType::NATIVE: if (ClassDB::is_parent_class(export_type.native_type, SNAME("Resource"))) { @@ -4396,12 +4400,6 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node push_error(_get_annotation_error_string(p_annotation->name, expected_types, variable->get_datatype()), p_annotation); return false; } - } else if (p_annotation->name == SNAME("@export_storage")) { - use_default_variable_type_check = false; // Can be applied to a variable of any type. - - // Save the info because the compiler uses export info for overwriting member info. - variable->export_info = export_type.to_property_info(variable->identifier->name); - variable->export_info.usage |= PROPERTY_USAGE_STORAGE; } if (use_default_variable_type_check) { @@ -4421,19 +4419,50 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node if (variable->export_info.hint) { hint_prefix += "/" + itos(variable->export_info.hint); } + variable->export_info.type = original_export_type_builtin; variable->export_info.hint = PROPERTY_HINT_TYPE_STRING; variable->export_info.hint_string = hint_prefix + ":" + variable->export_info.hint_string; - variable->export_info.type = original_export_type_builtin; + variable->export_info.usage = PROPERTY_USAGE_DEFAULT; + variable->export_info.class_name = StringName(); } return true; } +// For `@export_storage` and `@export_custom`, there is no need to check the variable type, argument values, +// or handle array exports in a special way, so they are implemented as separate methods. + +bool GDScriptParser::export_storage_annotation(const AnnotationNode *p_annotation, Node *p_node, ClassNode *p_class) { + ERR_FAIL_COND_V_MSG(p_node->type != Node::VARIABLE, false, vformat(R"("%s" annotation can only be applied to variables.)", p_annotation->name)); + + VariableNode *variable = static_cast<VariableNode *>(p_node); + if (variable->is_static) { + push_error(vformat(R"(Annotation "%s" cannot be applied to a static variable.)", p_annotation->name), p_annotation); + return false; + } + if (variable->exported) { + push_error(vformat(R"(Annotation "%s" cannot be used with another "@export" annotation.)", p_annotation->name), p_annotation); + return false; + } + + variable->exported = true; + + // Save the info because the compiler uses export info for overwriting member info. + variable->export_info = variable->get_datatype().to_property_info(variable->identifier->name); + variable->export_info.usage |= PROPERTY_USAGE_STORAGE; + + return true; +} + bool GDScriptParser::export_custom_annotation(const AnnotationNode *p_annotation, Node *p_node, ClassNode *p_class) { ERR_FAIL_COND_V_MSG(p_node->type != Node::VARIABLE, false, vformat(R"("%s" annotation can only be applied to variables.)", p_annotation->name)); ERR_FAIL_COND_V_MSG(p_annotation->resolved_arguments.size() < 2, false, R"(Annotation "@export_custom" requires 2 arguments.)"); VariableNode *variable = static_cast<VariableNode *>(p_node); + if (variable->is_static) { + push_error(vformat(R"(Annotation "%s" cannot be applied to a static variable.)", p_annotation->name), p_annotation); + return false; + } if (variable->exported) { push_error(vformat(R"(Annotation "%s" cannot be used with another "@export" annotation.)", p_annotation->name), p_annotation); return false; diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 4c11fa7f8b..96358165c0 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -1497,6 +1497,7 @@ private: bool onready_annotation(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class); template <PropertyHint t_hint, Variant::Type t_type> bool export_annotations(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class); + bool export_storage_annotation(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class); bool export_custom_annotation(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class); template <PropertyUsageFlags t_usage> bool export_group_annotations(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class); 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/analyzer/features/export_enum_as_dictionary.out b/modules/gdscript/tests/scripts/analyzer/features/export_enum_as_dictionary.out index 505af5f1f3..0d96f8c021 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/export_enum_as_dictionary.out +++ b/modules/gdscript/tests/scripts/analyzer/features/export_enum_as_dictionary.out @@ -1,11 +1,11 @@ GDTEST_OK var test_1: Dictionary - hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_2: TestExportEnumAsDictionary.MyEnum - hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM + hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"TestExportEnumAsDictionary.MyEnum" var test_3: Dictionary - hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_4: TestExportEnumAsDictionary.MyEnum - hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM + hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"TestExportEnumAsDictionary.MyEnum" var test_5: TestExportEnumAsDictionary.MyEnum - hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM + hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"TestExportEnumAsDictionary.MyEnum" diff --git a/modules/gdscript/tests/scripts/parser/features/annotations.out b/modules/gdscript/tests/scripts/parser/features/annotations.out index 2ba9dd7496..6516672820 100644 --- a/modules/gdscript/tests/scripts/parser/features/annotations.out +++ b/modules/gdscript/tests/scripts/parser/features/annotations.out @@ -1,25 +1,25 @@ GDTEST_OK var test_1: int = null - hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE + hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_2: int = null - hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE + hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_3: int = null - hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE + hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_4: int = null - hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE + hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_5: int = 0 - hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_6: int = 0 - hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_7: int = 42 - hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_8: int = 0 - hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_9: int = 0 - hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_10: int = 0 - hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_11: int = 0 - hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_12: int = 0 - hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" diff --git a/modules/gdscript/tests/scripts/parser/features/export_arrays.out b/modules/gdscript/tests/scripts/parser/features/export_arrays.out index acbf389645..f1522d096f 100644 --- a/modules/gdscript/tests/scripts/parser/features/export_arrays.out +++ b/modules/gdscript/tests/scripts/parser/features/export_arrays.out @@ -1,139 +1,139 @@ GDTEST_OK var test_dir: Array - hint=TYPE_STRING hint_string="String/DIR:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<DIR>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_dir_packed: PackedStringArray - hint=TYPE_STRING hint_string="String/DIR:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<DIR>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_file: Array - hint=TYPE_STRING hint_string="String/FILE:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<FILE>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_file_packed: PackedStringArray - hint=TYPE_STRING hint_string="String/FILE:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<FILE>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_global_dir: Array - hint=TYPE_STRING hint_string="String/GLOBAL_DIR:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<GLOBAL_DIR>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_global_dir_packed: PackedStringArray - hint=TYPE_STRING hint_string="String/GLOBAL_DIR:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<GLOBAL_DIR>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_global_file: Array - hint=TYPE_STRING hint_string="String/GLOBAL_FILE:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<GLOBAL_FILE>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_global_file_packed: PackedStringArray - hint=TYPE_STRING hint_string="String/GLOBAL_FILE:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<GLOBAL_FILE>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag: Array - hint=TYPE_STRING hint_string="int/FLAGS:A,B,C" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<FLAGS>:A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_packed_byte: PackedByteArray - hint=TYPE_STRING hint_string="int/FLAGS:A,B,C" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<FLAGS>:A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_packed32: PackedInt32Array - hint=TYPE_STRING hint_string="int/FLAGS:A,B,C" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<FLAGS>:A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_packed64: PackedInt64Array - hint=TYPE_STRING hint_string="int/FLAGS:A,B,C" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<FLAGS>:A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_2d_nav: Array - hint=TYPE_STRING hint_string="int/LAYERS_2D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_2D_NAVIGATION>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_2d_nav_packed_byte: PackedByteArray - hint=TYPE_STRING hint_string="int/LAYERS_2D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_2D_NAVIGATION>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_2d_nav_packed32: PackedInt32Array - hint=TYPE_STRING hint_string="int/LAYERS_2D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_2D_NAVIGATION>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_2d_nav_packed64: PackedInt64Array - hint=TYPE_STRING hint_string="int/LAYERS_2D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_2D_NAVIGATION>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_2d_phys: Array - hint=TYPE_STRING hint_string="int/LAYERS_2D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_2D_PHYSICS>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_2d_phys_packed_byte: PackedByteArray - hint=TYPE_STRING hint_string="int/LAYERS_2D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_2D_PHYSICS>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_2d_phys_packed32: PackedInt32Array - hint=TYPE_STRING hint_string="int/LAYERS_2D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_2D_PHYSICS>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_2d_phys_packed64: PackedInt64Array - hint=TYPE_STRING hint_string="int/LAYERS_2D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_2D_PHYSICS>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_2d_render: Array - hint=TYPE_STRING hint_string="int/LAYERS_2D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_2D_RENDER>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_2d_render_packed_byte: PackedByteArray - hint=TYPE_STRING hint_string="int/LAYERS_2D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_2D_RENDER>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_2d_render_packed32: PackedInt32Array - hint=TYPE_STRING hint_string="int/LAYERS_2D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_2D_RENDER>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_2d_render_packed64: PackedInt64Array - hint=TYPE_STRING hint_string="int/LAYERS_2D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_2D_RENDER>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_3d_nav: Array - hint=TYPE_STRING hint_string="int/LAYERS_3D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_3D_NAVIGATION>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_3d_nav_packed_byte: PackedByteArray - hint=TYPE_STRING hint_string="int/LAYERS_3D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_3D_NAVIGATION>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_3d_nav_packed32: PackedInt32Array - hint=TYPE_STRING hint_string="int/LAYERS_3D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_3D_NAVIGATION>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_3d_nav_packed64: PackedInt64Array - hint=TYPE_STRING hint_string="int/LAYERS_3D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_3D_NAVIGATION>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_3d_phys: Array - hint=TYPE_STRING hint_string="int/LAYERS_3D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_3D_PHYSICS>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_3d_phys_packed_byte: PackedByteArray - hint=TYPE_STRING hint_string="int/LAYERS_3D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_3D_PHYSICS>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_3d_phys_packed32: PackedInt32Array - hint=TYPE_STRING hint_string="int/LAYERS_3D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_3D_PHYSICS>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_3d_phys_packed64: PackedInt64Array - hint=TYPE_STRING hint_string="int/LAYERS_3D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_3D_PHYSICS>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_3d_render: Array - hint=TYPE_STRING hint_string="int/LAYERS_3D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_3D_RENDER>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_3d_render_packed_byte: PackedByteArray - hint=TYPE_STRING hint_string="int/LAYERS_3D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_3D_RENDER>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_3d_render_packed32: PackedInt32Array - hint=TYPE_STRING hint_string="int/LAYERS_3D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_3D_RENDER>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_bit_flag_3d_render_packed64: PackedInt64Array - hint=TYPE_STRING hint_string="int/LAYERS_3D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<LAYERS_3D_RENDER>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_multiline: Array - hint=TYPE_STRING hint_string="String/MULTILINE_TEXT:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<MULTILINE_TEXT>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_multiline_packed: PackedStringArray - hint=TYPE_STRING hint_string="String/MULTILINE_TEXT:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<MULTILINE_TEXT>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_placeholder: Array - hint=TYPE_STRING hint_string="String/PLACEHOLDER_TEXT:Placeholder" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<PLACEHOLDER_TEXT>:Placeholder" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_placeholder_packed: PackedStringArray - hint=TYPE_STRING hint_string="String/PLACEHOLDER_TEXT:Placeholder" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<PLACEHOLDER_TEXT>:Placeholder" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_int: Array - hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_int_packed_byte: PackedByteArray - hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_int_packed32: PackedInt32Array - hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_int_packed64: PackedInt64Array - hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_int_float_step: Array - hint=TYPE_STRING hint_string="int/RANGE:1,10,0.01" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<RANGE>:1,10,0.01" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_float: Array - hint=TYPE_STRING hint_string="float/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<float>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_float_packed32: PackedFloat32Array - hint=TYPE_STRING hint_string="float/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<float>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_float_packed64: PackedFloat64Array - hint=TYPE_STRING hint_string="float/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<float>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_exp_easing: Array - hint=TYPE_STRING hint_string="float/EXP_EASING:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<float>/<EXP_EASING>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_exp_easing_packed32: PackedFloat32Array - hint=TYPE_STRING hint_string="float/EXP_EASING:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<float>/<EXP_EASING>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_exp_easing_packed64: PackedFloat64Array - hint=TYPE_STRING hint_string="float/EXP_EASING:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<float>/<EXP_EASING>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_node_path: Array - hint=TYPE_STRING hint_string="NodePath/NODE_PATH_VALID_TYPES:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<NodePath>/<NODE_PATH_VALID_TYPES>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_color: Array - hint=TYPE_STRING hint_string="Color/COLOR_NO_ALPHA:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<Color>/<COLOR_NO_ALPHA>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_color_packed: PackedColorArray - hint=TYPE_STRING hint_string="Color/COLOR_NO_ALPHA:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<Color>/<COLOR_NO_ALPHA>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_packed_byte_array: PackedByteArray - hint=TYPE_STRING hint_string="int:int" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_packed_int32_array: PackedInt32Array - hint=TYPE_STRING hint_string="int:int" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_packed_int64_array: PackedInt64Array - hint=TYPE_STRING hint_string="int:int" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_packed_float32_array: PackedFloat32Array - hint=TYPE_STRING hint_string="float:float" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<float>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_packed_float64_array: PackedFloat64Array - hint=TYPE_STRING hint_string="float:float" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<float>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_packed_color_array: PackedColorArray - hint=TYPE_STRING hint_string="Color:Color" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<Color>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_packed_vector2_array: PackedVector2Array - hint=TYPE_STRING hint_string="Vector2:Vector2" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<Vector2>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_packed_vector3_array: PackedVector3Array - hint=TYPE_STRING hint_string="Vector3:Vector3" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<Vector3>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_packed_vector4_array: PackedVector4Array - hint=TYPE_STRING hint_string="Vector4:Vector4" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<Vector4>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_weak_packed_byte_array: PackedByteArray - hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_weak_packed_int32_array: PackedInt32Array - hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_weak_packed_int64_array: PackedInt64Array - hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_weak_packed_float32_array: PackedFloat32Array - hint=TYPE_STRING hint_string="float/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<float>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_weak_packed_float64_array: PackedFloat64Array - hint=TYPE_STRING hint_string="float/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<float>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_noalpha_weak_packed_color_array: PackedColorArray - hint=TYPE_STRING hint_string="Color/COLOR_NO_ALPHA:" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<Color>/<COLOR_NO_ALPHA>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" diff --git a/modules/gdscript/tests/scripts/parser/features/export_enum.out b/modules/gdscript/tests/scripts/parser/features/export_enum.out index c87f9b17f0..31d3fa8902 100644 --- a/modules/gdscript/tests/scripts/parser/features/export_enum.out +++ b/modules/gdscript/tests/scripts/parser/features/export_enum.out @@ -1,41 +1,41 @@ GDTEST_OK var test_untyped: int = null - hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_with_values: int = null - hint=ENUM hint_string="Red:10,Green:20,Blue:30" usage=DEFAULT|SCRIPT_VARIABLE + hint=ENUM hint_string="Red:10,Green:20,Blue:30" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_variant: int = null - hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_int: int = 0 - hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_string: String = "" - hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_array_int: Array = Array[int]([]) - hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<ENUM>:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_array_string: Array = Array[String]([]) - hint=TYPE_STRING hint_string="String/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<ENUM>:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_packed_byte_array: PackedByteArray = PackedByteArray() - hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<ENUM>:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_packed_int32_array: PackedInt32Array = PackedInt32Array() - hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<ENUM>:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_packed_int64_array: PackedInt64Array = PackedInt64Array() - hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<ENUM>:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_weak_packed_string_array: PackedStringArray = PackedStringArray() - hint=TYPE_STRING hint_string="String/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<ENUM>:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_hard_variant: int = null - hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_hard_int: int = 0 - hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_hard_string: String = "" - hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_hard_array_int: Array = Array[int]([]) - hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<ENUM>:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_hard_array_string: Array = Array[String]([]) - hint=TYPE_STRING hint_string="String/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<ENUM>:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_variant_array_int: Array = Array[int]([]) - hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<ENUM>:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_variant_packed_int32_array: PackedInt32Array = PackedInt32Array() - hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<int>/<ENUM>:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_variant_array_string: Array = Array[String]([]) - hint=TYPE_STRING hint_string="String/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<ENUM>:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_variant_packed_string_array: PackedStringArray = PackedStringArray() - hint=TYPE_STRING hint_string="String/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE + hint=TYPE_STRING hint_string="<String>/<ENUM>:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" diff --git a/modules/gdscript/tests/scripts/parser/features/export_variable.gd b/modules/gdscript/tests/scripts/parser/features/export_variable.gd index 2a218774de..8b343de5ef 100644 --- a/modules/gdscript/tests/scripts/parser/features/export_variable.gd +++ b/modules/gdscript/tests/scripts/parser/features/export_variable.gd @@ -2,19 +2,43 @@ extends Node const Utils = preload("../../utils.notest.gd") +# Built-in types. @export var test_weak_int = 1 @export var test_hard_int: int = 2 -@export_storage var test_storage_untyped -@export_storage var test_storage_weak_int = 3 # Property info still `Variant`, unlike `@export`. -@export_storage var test_storage_hard_int: int = 4 @export_range(0, 100) var test_range = 100 @export_range(0, 100, 1) var test_range_step = 101 @export_range(0, 100, 1, "or_greater") var test_range_step_or_greater = 102 @export var test_color: Color @export_color_no_alpha var test_color_no_alpha: Color @export_node_path("Sprite2D", "Sprite3D", "Control", "Node") var test_node_path := ^"hello" -@export var test_node: Node -@export var test_node_array: Array[Node] + +# Enums. +@export var test_side: Side +@export var test_atm: AutoTranslateMode + +# Resources and nodes. +@export var test_image: Image +@export var test_timer: Timer + +# Arrays. +@export var test_array: Array +@export var test_array_bool: Array[bool] +@export var test_array_array: Array[Array] +@export var test_array_side: Array[Side] +@export var test_array_atm: Array[AutoTranslateMode] +@export var test_array_image: Array[Image] +@export var test_array_timer: Array[Timer] + +# `@export_storage`. +@export_storage var test_storage_untyped +@export_storage var test_storage_weak_int = 3 # Property info still `Variant`, unlike `@export`. +@export_storage var test_storage_hard_int: int = 4 + +# `@export_custom`. +# NOTE: `PROPERTY_USAGE_NIL_IS_VARIANT` flag will be removed. +@export_custom(PROPERTY_HINT_ENUM, "A,B,C") var test_export_custom_untyped +@export_custom(PROPERTY_HINT_ENUM, "A,B,C") var test_export_custom_weak_int = 5 +@export_custom(PROPERTY_HINT_ENUM, "A,B,C") var test_export_custom_hard_int: int = 6 func test(): for property in get_property_list(): diff --git a/modules/gdscript/tests/scripts/parser/features/export_variable.out b/modules/gdscript/tests/scripts/parser/features/export_variable.out index b3f9d0ca9c..99d7b27130 100644 --- a/modules/gdscript/tests/scripts/parser/features/export_variable.out +++ b/modules/gdscript/tests/scripts/parser/features/export_variable.out @@ -1,27 +1,51 @@ GDTEST_OK var test_weak_int: int = 1 - hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_hard_int: int = 2 - hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE -var test_storage_untyped: Variant = null - hint=NONE hint_string="" usage=STORAGE|SCRIPT_VARIABLE|NIL_IS_VARIANT -var test_storage_weak_int: Variant = 3 - hint=NONE hint_string="" usage=STORAGE|SCRIPT_VARIABLE|NIL_IS_VARIANT -var test_storage_hard_int: int = 4 - hint=NONE hint_string="" usage=STORAGE|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range: int = 100 - hint=RANGE hint_string="0,100" usage=DEFAULT|SCRIPT_VARIABLE + hint=RANGE hint_string="0,100" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_step: int = 101 - hint=RANGE hint_string="0,100,1" usage=DEFAULT|SCRIPT_VARIABLE + hint=RANGE hint_string="0,100,1" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_step_or_greater: int = 102 - hint=RANGE hint_string="0,100,1,or_greater" usage=DEFAULT|SCRIPT_VARIABLE + hint=RANGE hint_string="0,100,1,or_greater" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_color: Color = Color(0, 0, 0, 1) - hint=NONE hint_string="Color" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_color_no_alpha: Color = Color(0, 0, 0, 1) - hint=COLOR_NO_ALPHA hint_string="" usage=DEFAULT|SCRIPT_VARIABLE + hint=COLOR_NO_ALPHA hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_node_path: NodePath = NodePath("hello") - hint=NODE_PATH_VALID_TYPES hint_string="Sprite2D,Sprite3D,Control,Node" usage=DEFAULT|SCRIPT_VARIABLE -var test_node: Node = null - hint=NODE_TYPE hint_string="Node" usage=DEFAULT|SCRIPT_VARIABLE -var test_node_array: Array = Array[Node]([]) - hint=TYPE_STRING hint_string="Object/NODE_TYPE:Node" usage=DEFAULT|SCRIPT_VARIABLE + hint=NODE_PATH_VALID_TYPES hint_string="Sprite2D,Sprite3D,Control,Node" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" +var test_side: Side = 0 + hint=ENUM hint_string="Side Left:0,Side Top:1,Side Right:2,Side Bottom:3" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Side" +var test_atm: Node.AutoTranslateMode = 0 + hint=ENUM hint_string="Auto Translate Mode Inherit:0,Auto Translate Mode Always:1,Auto Translate Mode Disabled:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Node.AutoTranslateMode" +var test_image: Image = null + hint=RESOURCE_TYPE hint_string="Image" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"Image" +var test_timer: Timer = null + hint=NODE_TYPE hint_string="Timer" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"Timer" +var test_array: Array = [] + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" +var test_array_bool: Array = Array[bool]([]) + hint=TYPE_STRING hint_string="<bool>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" +var test_array_array: Array = Array[Array]([]) + hint=TYPE_STRING hint_string="<Array>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" +var test_array_side: Array = Array[int]([]) + hint=TYPE_STRING hint_string="<int>/<ENUM>:Side Left:0,Side Top:1,Side Right:2,Side Bottom:3" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" +var test_array_atm: Array = Array[int]([]) + hint=TYPE_STRING hint_string="<int>/<ENUM>:Auto Translate Mode Inherit:0,Auto Translate Mode Always:1,Auto Translate Mode Disabled:2" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" +var test_array_image: Array = Array[Image]([]) + hint=TYPE_STRING hint_string="<Object>/<RESOURCE_TYPE>:Image" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" +var test_array_timer: Array = Array[Timer]([]) + hint=TYPE_STRING hint_string="<Object>/<NODE_TYPE>:Timer" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" +var test_storage_untyped: Variant = null + hint=NONE hint_string="" usage=STORAGE|SCRIPT_VARIABLE|NIL_IS_VARIANT class_name=&"" +var test_storage_weak_int: Variant = 3 + hint=NONE hint_string="" usage=STORAGE|SCRIPT_VARIABLE|NIL_IS_VARIANT class_name=&"" +var test_storage_hard_int: int = 4 + hint=NONE hint_string="" usage=STORAGE|SCRIPT_VARIABLE class_name=&"" +var test_export_custom_untyped: null = null + hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" +var test_export_custom_weak_int: int = 5 + hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" +var test_export_custom_hard_int: int = 6 + hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" 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/gdscript/tests/scripts/runtime/features/export_group_no_name_conflict_with_properties.out b/modules/gdscript/tests/scripts/runtime/features/export_group_no_name_conflict_with_properties.out index 9387ec50d7..a1e7233078 100644 --- a/modules/gdscript/tests/scripts/runtime/features/export_group_no_name_conflict_with_properties.out +++ b/modules/gdscript/tests/scripts/runtime/features/export_group_no_name_conflict_with_properties.out @@ -1,8 +1,8 @@ GDTEST_OK Not shadowed: Resource var test_1: int = 0 - hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" @export_category("test_1") - hint=NONE hint_string="" usage=CATEGORY + hint=NONE hint_string="" usage=CATEGORY class_name=&"" var test_2: int = 0 - hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE + hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" diff --git a/modules/gdscript/tests/scripts/utils.notest.gd b/modules/gdscript/tests/scripts/utils.notest.gd index 1cf46c179e..7fdd6556ec 100644 --- a/modules/gdscript/tests/scripts/utils.notest.gd +++ b/modules/gdscript/tests/scripts/utils.notest.gd @@ -55,18 +55,18 @@ static func get_human_readable_hint_string(property: Dictionary) -> String: if elem_type_hint.is_valid_int(): elem_type = elem_type_hint.to_int() - type_hint_prefixes += type_string(elem_type) + ":" + type_hint_prefixes += "<%s>:" % type_string(elem_type) else: if elem_type_hint.count("/") != 1: push_error("Invalid PROPERTY_HINT_TYPE_STRING format.") elem_type = elem_type_hint.get_slice("/", 0).to_int() elem_hint = elem_type_hint.get_slice("/", 1).to_int() - type_hint_prefixes += "%s/%s:" % [ - type_string(elem_type), - get_property_hint_name(elem_hint).trim_prefix("PROPERTY_HINT_"), + type_hint_prefixes += "<%s>/<%s>:" % [ + type_string(elem_type), + get_property_hint_name(elem_hint).trim_prefix("PROPERTY_HINT_"), ] - if elem_type < TYPE_ARRAY: + if elem_type < TYPE_ARRAY or hint_string.is_empty(): break return type_hint_prefixes + hint_string @@ -76,10 +76,11 @@ static func get_human_readable_hint_string(property: Dictionary) -> String: static func print_property_extended_info(property: Dictionary, base: Object = null, is_static: bool = false) -> void: print(get_property_signature(property, base, is_static)) - print(' hint=%s hint_string="%s" usage=%s' % [ + print(' hint=%s hint_string="%s" usage=%s class_name=&"%s"' % [ get_property_hint_name(property.hint).trim_prefix("PROPERTY_HINT_"), - get_human_readable_hint_string(property), + get_human_readable_hint_string(property).c_escape(), get_property_usage_string(property.usage).replace("PROPERTY_USAGE_", ""), + property.class_name.c_escape(), ]) diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildProblemsView.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildProblemsView.cs index b6d6d9ebf8..35a62a0eab 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildProblemsView.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildProblemsView.cs @@ -280,7 +280,7 @@ namespace GodotTools.Build if (_problemsContextMenu.ItemCount > 0) { - _problemsContextMenu.Position = (Vector2I)(_problemsTree.GlobalPosition + position); + _problemsContextMenu.Position = (Vector2I)(GetScreenPosition() + position); _problemsContextMenu.Popup(); } } diff --git a/modules/noise/noise_texture_2d.cpp b/modules/noise/noise_texture_2d.cpp index 0443fec4a0..0960b2ad36 100644 --- a/modules/noise/noise_texture_2d.cpp +++ b/modules/noise/noise_texture_2d.cpp @@ -119,6 +119,7 @@ void NoiseTexture2D::_set_texture_image(const Ref<Image> &p_image) { } else { texture = RS::get_singleton()->texture_2d_create(p_image); } + RS::get_singleton()->texture_set_path(texture, get_path()); } emit_changed(); } 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/gradient_texture.cpp b/scene/resources/gradient_texture.cpp index 7df439a799..6ec9422d2d 100644 --- a/scene/resources/gradient_texture.cpp +++ b/scene/resources/gradient_texture.cpp @@ -136,6 +136,7 @@ void GradientTexture1D::_update() { texture = RS::get_singleton()->texture_2d_create(image); } } + RS::get_singleton()->texture_set_path(texture, get_path()); } void GradientTexture1D::set_width(int p_width) { @@ -275,6 +276,7 @@ void GradientTexture2D::_update() { } else { texture = RS::get_singleton()->texture_2d_create(image); } + RS::get_singleton()->texture_set_path(texture, get_path()); } float GradientTexture2D::_get_gradient_offset_at(int x, int y) const { 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/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index f844919df1..6e5e8f63e0 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -1457,6 +1457,23 @@ void TextureStorage::texture_set_detect_roughness_callback(RID p_texture, RS::Te } void TextureStorage::texture_debug_usage(List<RS::TextureInfo> *r_info) { + List<RID> textures; + texture_owner.get_owned_list(&textures); + + for (List<RID>::Element *E = textures.front(); E; E = E->next()) { + Texture *t = texture_owner.get_or_null(E->get()); + if (!t) { + continue; + } + RS::TextureInfo tinfo; + tinfo.path = t->path; + tinfo.format = t->format; + tinfo.width = t->width; + tinfo.height = t->height; + tinfo.depth = t->depth; + tinfo.bytes = Image::get_image_data_size(t->width, t->height, t->format, t->mipmaps); + r_info->push_back(tinfo); + } } void TextureStorage::texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) { @@ -3042,6 +3059,7 @@ void TextureStorage::_update_render_target(RenderTarget *rt) { texture_2d_placeholder_initialize(rt->texture); Texture *tex = get_texture(rt->texture); tex->is_render_target = true; + tex->path = "Render Target (Internal)"; } _clear_render_target(rt); 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/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 020be6be18..42773fc347 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -797,6 +797,8 @@ private: #endif public: + RenderingContextDriver *get_context_driver() const { return context; } + const RDD::Capabilities &get_device_capabilities() const { return driver->get_capabilities(); } bool has_feature(const Features p_feature) const; diff --git a/tests/create_test.py b/tests/create_test.py index deb53aca20..deb53aca20 100644..100755 --- a/tests/create_test.py +++ b/tests/create_test.py diff --git a/thirdparty/glslang/SPIRV/GlslangToSpv.cpp b/thirdparty/glslang/SPIRV/GlslangToSpv.cpp index ec40f663a7..ec40f663a7 100755..100644 --- a/thirdparty/glslang/SPIRV/GlslangToSpv.cpp +++ b/thirdparty/glslang/SPIRV/GlslangToSpv.cpp diff --git a/thirdparty/glslang/SPIRV/doc.cpp b/thirdparty/glslang/SPIRV/doc.cpp index 1a05c67360..1a05c67360 100755..100644 --- a/thirdparty/glslang/SPIRV/doc.cpp +++ b/thirdparty/glslang/SPIRV/doc.cpp diff --git a/thirdparty/glslang/glslang/Include/BaseTypes.h b/thirdparty/glslang/glslang/Include/BaseTypes.h index 64bffa8926..64bffa8926 100755..100644 --- a/thirdparty/glslang/glslang/Include/BaseTypes.h +++ b/thirdparty/glslang/glslang/Include/BaseTypes.h diff --git a/thirdparty/glslang/glslang/MachineIndependent/Initialize.cpp b/thirdparty/glslang/glslang/MachineIndependent/Initialize.cpp index af333f3f16..af333f3f16 100755..100644 --- a/thirdparty/glslang/glslang/MachineIndependent/Initialize.cpp +++ b/thirdparty/glslang/glslang/MachineIndependent/Initialize.cpp diff --git a/thirdparty/glslang/glslang/MachineIndependent/Versions.h b/thirdparty/glslang/glslang/MachineIndependent/Versions.h index 475cb89341..475cb89341 100755..100644 --- a/thirdparty/glslang/glslang/MachineIndependent/Versions.h +++ b/thirdparty/glslang/glslang/MachineIndependent/Versions.h 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 |