diff --git a/SConstruct b/SConstruct index 8f8f329f233d..f4500d752522 100644 --- a/SConstruct +++ b/SConstruct @@ -313,7 +313,7 @@ if not env["platform"]: env["platform"] = "windows" if env["platform"]: - print(f'Automatically detected platform: {env["platform"]}') + print(f"Automatically detected platform: {env['platform']}") # Deprecated aliases kept for compatibility. if env["platform"] in compatibility_platform_aliases: @@ -998,8 +998,7 @@ if env["disable_3d"]: if env["disable_advanced_gui"]: if env.editor_build: print_error( - "Build option `disable_advanced_gui=yes` cannot be used for editor builds, " - "only for export template builds." + "Build option `disable_advanced_gui=yes` cannot be used for editor builds, only for export template builds." ) Exit(255) else: diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp index 230184ad04b6..7d422bf09467 100644 --- a/core/io/file_access.cpp +++ b/core/io/file_access.cpp @@ -451,7 +451,7 @@ String FileAccess::get_line() const { uint8_t c = get_8(); while (!eof_reached()) { - if (c == '\n' || c == '\0') { + if (c == '\n' || c == '\0' || get_error() != OK) { line.push_back(0); return String::utf8(line.get_data()); } else if (c != '\r') { diff --git a/doc/classes/FileAccess.xml b/doc/classes/FileAccess.xml index a2ee5a132304..03a1146a9134 100644 --- a/doc/classes/FileAccess.xml +++ b/doc/classes/FileAccess.xml @@ -204,7 +204,7 @@ - Returns the size of the file in bytes. + Returns the size of the file in bytes. For a pipe, returns the number of bytes available for reading from the pipe. diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml index e4fb3ee9abe8..a55c40d0187a 100644 --- a/doc/classes/Viewport.xml +++ b/doc/classes/Viewport.xml @@ -188,6 +188,20 @@ If [member handle_input_locally] is set to [code]false[/code], this method will try finding the first parent viewport that is set to handle input locally, and return its value for [method is_input_handled] instead. + + + + Inform the Viewport that the mouse has entered its area. Use this function before sending an [InputEventMouseButton] or [InputEventMouseMotion] to the [Viewport] with [method Viewport.push_input]. See also [method notify_mouse_exited]. + [b]Note:[/b] In most cases, it is not necessary to call this function because [SubViewport] nodes that are children of [SubViewportContainer] are notified automatically. This is only necessary when interacting with viewports in non-default ways, for example as textures in [TextureRect] or with an [Area3D] that forwards input events. + + + + + + Inform the Viewport that the mouse has left its area. Use this function when the node that displays the viewport notices the mouse has left the area of the displayed viewport. See also [method notify_mouse_entered]. + [b]Note:[/b] In most cases, it is not necessary to call this function because [SubViewport] nodes that are children of [SubViewportContainer] are notified automatically. This is only necessary when interacting with viewports in non-default ways, for example as textures in [TextureRect] or with an [Area3D] that forwards input events. + + diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py index adb7500528bd..744325f1435f 100755 --- a/doc/tools/make_rst.py +++ b/doc/tools/make_rst.py @@ -920,7 +920,7 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir: # Ascendants if class_def.inherits: inherits = class_def.inherits.strip() - f.write(f'**{translate("Inherits:")}** ') + f.write(f"**{translate('Inherits:')}** ") first = True while inherits is not None: if not first: @@ -947,7 +947,7 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir: inherited.append(c.name) if len(inherited): - f.write(f'**{translate("Inherited By:")}** ') + f.write(f"**{translate('Inherited By:')}** ") for i, child in enumerate(inherited): if i > 0: f.write(", ") @@ -1496,7 +1496,7 @@ def resolve_type(link_type: str) -> str: return f"``{link_type}``" if klass.endswith("[]"): # Typed array, strip [] to link to contained type. - return f":ref:`Array`\\[{resolve_type(klass[:-len('[]')])}\\]" + return f":ref:`Array`\\[{resolve_type(klass[: -len('[]')])}\\]" if klass.startswith("Dictionary["): # Typed dictionary, split elements to link contained types. parts = klass[len("Dictionary[") : -len("]")].partition(", ") @@ -2542,7 +2542,7 @@ def format_table(f: TextIO, data: List[Tuple[Optional[str], ...]], remove_empty_ for i, text in enumerate(row): if column_sizes[i] == 0 and remove_empty_columns: continue - row_text += f' {(text or "").ljust(column_sizes[i])} |' + row_text += f" {(text or '').ljust(column_sizes[i])} |" row_text += "\n" f.write(f" {row_text}") diff --git a/drivers/unix/file_access_unix_pipe.cpp b/drivers/unix/file_access_unix_pipe.cpp index 775d3f7d8676..56be559a34cc 100644 --- a/drivers/unix/file_access_unix_pipe.cpp +++ b/drivers/unix/file_access_unix_pipe.cpp @@ -37,6 +37,7 @@ #include #include +#include #include #include #include @@ -132,6 +133,14 @@ String FileAccessUnixPipe::get_path_absolute() const { return path_src; } +uint64_t FileAccessUnixPipe::get_length() const { + ERR_FAIL_COND_V_MSG(fd[0] < 0, 0, "Pipe must be opened before use."); + + int buf_rem = 0; + ERR_FAIL_COND_V(ioctl(fd[0], FIONREAD, &buf_rem) != 0, 0); + return buf_rem; +} + uint64_t FileAccessUnixPipe::get_buffer(uint8_t *p_dst, uint64_t p_length) const { ERR_FAIL_COND_V_MSG(fd[0] < 0, -1, "Pipe must be opened before use."); ERR_FAIL_COND_V(!p_dst && p_length > 0, -1); diff --git a/drivers/unix/file_access_unix_pipe.h b/drivers/unix/file_access_unix_pipe.h index a95cbc8e614f..b1633db015c5 100644 --- a/drivers/unix/file_access_unix_pipe.h +++ b/drivers/unix/file_access_unix_pipe.h @@ -61,7 +61,7 @@ class FileAccessUnixPipe : public FileAccess { virtual void seek(uint64_t p_position) override {} virtual void seek_end(int64_t p_position = 0) override {} virtual uint64_t get_position() const override { return 0; } - virtual uint64_t get_length() const override { return 0; } + virtual uint64_t get_length() const override; virtual bool eof_reached() const override { return false; } diff --git a/drivers/windows/file_access_windows_pipe.cpp b/drivers/windows/file_access_windows_pipe.cpp index 88e76f67ef50..6960e9d71536 100644 --- a/drivers/windows/file_access_windows_pipe.cpp +++ b/drivers/windows/file_access_windows_pipe.cpp @@ -102,6 +102,14 @@ String FileAccessWindowsPipe::get_path_absolute() const { return path_src; } +uint64_t FileAccessWindowsPipe::get_length() const { + ERR_FAIL_COND_V_MSG(fd[0] == nullptr, -1, "Pipe must be opened before use."); + + DWORD buf_rem = 0; + ERR_FAIL_COND_V(!PeekNamedPipe(fd[0], nullptr, 0, nullptr, &buf_rem, nullptr), 0); + return buf_rem; +} + uint64_t FileAccessWindowsPipe::get_buffer(uint8_t *p_dst, uint64_t p_length) const { ERR_FAIL_COND_V_MSG(fd[0] == nullptr, -1, "Pipe must be opened before use."); ERR_FAIL_COND_V(!p_dst && p_length > 0, -1); diff --git a/drivers/windows/file_access_windows_pipe.h b/drivers/windows/file_access_windows_pipe.h index b01b48fe133e..0eb570ae2294 100644 --- a/drivers/windows/file_access_windows_pipe.h +++ b/drivers/windows/file_access_windows_pipe.h @@ -60,7 +60,7 @@ class FileAccessWindowsPipe : public FileAccess { virtual void seek(uint64_t p_position) override {} virtual void seek_end(int64_t p_position = 0) override {} virtual uint64_t get_position() const override { return 0; } - virtual uint64_t get_length() const override { return 0; } + virtual uint64_t get_length() const override; virtual bool eof_reached() const override { return false; } diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index 273b374b80a3..96fb8323704c 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -1085,7 +1085,6 @@ void EditorResourcePicker::_duplicate_selected_resources() { EditorResourcePicker::EditorResourcePicker(bool p_hide_assign_button_controls) { assign_button = memnew(Button); assign_button->set_flat(true); - assign_button->set_action_mode(BaseButton::ACTION_MODE_BUTTON_PRESS); assign_button->set_h_size_flags(SIZE_EXPAND_FILL); assign_button->set_expand_icon(true); assign_button->set_clip_text(true); diff --git a/editor/plugins/embedded_process.cpp b/editor/plugins/embedded_process.cpp index 10c7188b5c53..1638c437125d 100644 --- a/editor/plugins/embedded_process.cpp +++ b/editor/plugins/embedded_process.cpp @@ -40,20 +40,6 @@ void EmbeddedProcess::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { window = get_window(); } break; - case NOTIFICATION_PROCESS: { - _check_focused_process_id(); - _check_mouse_over(); - - // We need to detect when the control globally changes location or size on the screen. - // NOTIFICATION_RESIZED and NOTIFICATION_WM_POSITION_CHANGED are not enough to detect - // resized parent to siblings controls that can affect global position. - Rect2i new_global_rect = get_global_rect(); - if (last_global_rect != new_global_rect) { - last_global_rect = new_global_rect; - queue_update_embedded_process(); - } - - } break; case NOTIFICATION_DRAW: { _draw(); } break; @@ -192,7 +178,7 @@ void EmbeddedProcess::embed_process(OS::ProcessID p_pid) { current_process_id = p_pid; start_embedding_time = OS::get_singleton()->get_ticks_msec(); embedding_grab_focus = has_focus(); - set_process(true); + timer_update_embedded_process->start(); set_notify_transform(true); // Attempt to embed the process, but if it has just started and the window is not ready yet, @@ -209,7 +195,7 @@ void EmbeddedProcess::reset() { start_embedding_time = 0; embedding_grab_focus = false; timer_embedding->stop(); - set_process(false); + timer_update_embedded_process->stop(); set_notify_transform(false); queue_redraw(); } @@ -242,18 +228,31 @@ bool EmbeddedProcess::_is_embedded_process_updatable() { } void EmbeddedProcess::queue_update_embedded_process() { - if (updated_embedded_process_queued || !_is_embedded_process_updatable()) { - return; - } - updated_embedded_process_queued = true; +} - callable_mp(this, &EmbeddedProcess::_update_embedded_process).call_deferred(); +void EmbeddedProcess::_timer_update_embedded_process_timeout() { + _check_focused_process_id(); + _check_mouse_over(); + + if (!updated_embedded_process_queued) { + // We need to detect when the control globally changes location or size on the screen. + // NOTIFICATION_RESIZED and NOTIFICATION_WM_POSITION_CHANGED are not enough to detect + // resized parent to siblings controls that can affect global position. + Rect2i new_global_rect = get_global_rect(); + if (last_global_rect != new_global_rect) { + last_global_rect = new_global_rect; + queue_update_embedded_process(); + } + } + + if (updated_embedded_process_queued) { + updated_embedded_process_queued = false; + _update_embedded_process(); + } } void EmbeddedProcess::_update_embedded_process() { - updated_embedded_process_queued = false; - if (!_is_embedded_process_updatable()) { return; } @@ -352,6 +351,12 @@ EmbeddedProcess::EmbeddedProcess() { timer_embedding->set_one_shot(true); add_child(timer_embedding); timer_embedding->connect("timeout", callable_mp(this, &EmbeddedProcess::_timer_embedding_timeout)); + + timer_update_embedded_process = memnew(Timer); + timer_update_embedded_process->set_wait_time(0.1); + add_child(timer_update_embedded_process); + timer_update_embedded_process->connect("timeout", callable_mp(this, &EmbeddedProcess::_timer_update_embedded_process_timeout)); + set_focus_mode(FOCUS_ALL); } diff --git a/editor/plugins/embedded_process.h b/editor/plugins/embedded_process.h index 14ad44fdaedd..3e800923a75d 100644 --- a/editor/plugins/embedded_process.h +++ b/editor/plugins/embedded_process.h @@ -48,6 +48,7 @@ class EmbeddedProcess : public Control { Window *window = nullptr; Timer *timer_embedding = nullptr; + Timer *timer_update_embedded_process = nullptr; const int embedding_timeout = 45000; @@ -61,6 +62,7 @@ class EmbeddedProcess : public Control { void _try_embed_process(); void _update_embedded_process(); void _timer_embedding_timeout(); + void _timer_update_embedded_process_timeout(); void _draw(); void _check_mouse_over(); void _check_focused_process_id(); diff --git a/editor/plugins/game_view_plugin.cpp b/editor/plugins/game_view_plugin.cpp index 6cc54ab34c97..a6d73cf9e153 100644 --- a/editor/plugins/game_view_plugin.cpp +++ b/editor/plugins/game_view_plugin.cpp @@ -979,6 +979,11 @@ GameView::GameView(Ref p_debugger, WindowWrapper *p_wrapper) { game_size_label = memnew(Label()); main_menu_hbox->add_child(game_size_label); game_size_label->hide(); + // Setting the minimum size prevents the game workspace from resizing indefinitely + // due to the label size oscillating by a few pixels when the game is in stretch mode + // and the game workspace is at its minimum size. + game_size_label->set_custom_minimum_size(Size2(80 * EDSCALE, 0)); + game_size_label->set_horizontal_alignment(HorizontalAlignment::HORIZONTAL_ALIGNMENT_RIGHT); panel = memnew(Panel); add_child(panel); diff --git a/gles3_builders.py b/gles3_builders.py index 85b2c8e4c43e..a9d735ae5b6a 100644 --- a/gles3_builders.py +++ b/gles3_builders.py @@ -499,7 +499,7 @@ def build_gles3_header( fd.write("\t\t};\n\n") variant_count = len(header_data.variant_defines) else: - fd.write("\t\tstatic const char **_variant_defines[]={" "};\n") + fd.write('\t\tstatic const char **_variant_defines[]={" "};\n') if header_data.texunits: fd.write("\t\tstatic TexUnitPair _texunit_pairs[]={\n") diff --git a/methods.py b/methods.py index 0d1e78c7fb22..85fdf1978fb1 100644 --- a/methods.py +++ b/methods.py @@ -7,7 +7,7 @@ import subprocess import sys from collections import OrderedDict -from io import StringIO, TextIOWrapper +from io import StringIO, TextIOBase from pathlib import Path from typing import Generator, List, Optional, Union, cast @@ -1201,7 +1201,7 @@ def get_dependencies(file, env, exts, headers, sources, others): vsconf = "" for a in vs_configuration["arches"]: if arch == a["architecture"]: - vsconf = f'{target}|{a["platform"]}' + vsconf = f"{target}|{a['platform']}" break condition = "'$(GodotConfiguration)|$(GodotPlatform)'=='" + vsconf + "'" @@ -1217,7 +1217,7 @@ def get_dependencies(file, env, exts, headers, sources, others): properties.append( ";%s;" % (x, ";".join(itemlist[x]), x) ) - output = f'bin\\godot{env["PROGSUFFIX"]}' + output = f"bin\\godot{env['PROGSUFFIX']}" with open("misc/msvs/props.template", "r", encoding="utf-8") as file: props_template = file.read() @@ -1453,7 +1453,7 @@ def generated_wrapper( guard: Optional[bool] = None, prefix: str = "", suffix: str = "", -) -> Generator[TextIOWrapper, None, None]: +) -> Generator[TextIOBase, None, None]: """ Wrapper class to automatically handle copyright headers and header guards for generated scripts. Meant to be invoked via `with` statement similar to @@ -1475,8 +1475,7 @@ def generated_wrapper( if isinstance(path, list): if len(path) > 1: print_warning( - "Attempting to use generated wrapper with multiple targets; " - f"will only use first entry: {path[0]}" + f"Attempting to use generated wrapper with multiple targets; will only use first entry: {path[0]}" ) path = path[0] if not hasattr(path, "get_abspath"): diff --git a/modules/text_server_adv/gdextension_build/SConstruct b/modules/text_server_adv/gdextension_build/SConstruct index e78d66afcafd..36d210ef8991 100644 --- a/modules/text_server_adv/gdextension_build/SConstruct +++ b/modules/text_server_adv/gdextension_build/SConstruct @@ -110,7 +110,7 @@ if env["thorvg_enabled"] and env["freetype_enabled"]: env.Append(CPPDEFINES=["MODULE_SVG_ENABLED"]) lib = env_tvg.Library( - f'tvg_builtin{env["suffix"]}{env["LIBSUFFIX"]}', + f"tvg_builtin{env['suffix']}{env['LIBSUFFIX']}", thirdparty_tvg_sources, ) env.Append(LIBS=[lib]) @@ -155,7 +155,7 @@ if env["msdfgen_enabled"] and env["freetype_enabled"]: env.Append(CPPDEFINES=["MODULE_MSDFGEN_ENABLED"]) lib = env_msdfgen.Library( - f'msdfgen_builtin{env["suffix"]}{env["LIBSUFFIX"]}', + f"msdfgen_builtin{env['suffix']}{env['LIBSUFFIX']}", thirdparty_msdfgen_sources, ) env.Append(LIBS=[lib]) @@ -284,7 +284,7 @@ if env["freetype_enabled"]: env.Append(CPPDEFINES=["MODULE_FREETYPE_ENABLED"]) lib = env_freetype.Library( - f'freetype_builtin{env["suffix"]}{env["LIBSUFFIX"]}', + f"freetype_builtin{env['suffix']}{env['LIBSUFFIX']}", thirdparty_freetype_sources, ) env.Append(LIBS=[lib]) @@ -418,7 +418,7 @@ if env["freetype_enabled"]: env.Append(CPPPATH=["../../../thirdparty/harfbuzz/src"]) lib = env_harfbuzz.Library( - f'harfbuzz_builtin{env["suffix"]}{env["LIBSUFFIX"]}', + f"harfbuzz_builtin{env['suffix']}{env['LIBSUFFIX']}", thirdparty_harfbuzz_sources, ) env.Prepend(LIBS=[lib]) @@ -478,7 +478,7 @@ if env["graphite_enabled"] and env["freetype_enabled"]: ) lib = env_graphite.Library( - f'graphite_builtin{env["suffix"]}{env["LIBSUFFIX"]}', + f"graphite_builtin{env['suffix']}{env['LIBSUFFIX']}", thirdparty_graphite_sources, ) env.Append(LIBS=[lib]) @@ -737,7 +737,7 @@ env.Append(CPPPATH=["../../../thirdparty/icu4c/common/", "../../../thirdparty/ic if env["platform"] == "windows": env.Append(LIBS=["advapi32"]) -lib = env_icu.Library(f'icu_builtin{env["suffix"]}{env["LIBSUFFIX"]}', thirdparty_icu_sources) +lib = env_icu.Library(f"icu_builtin{env['suffix']}{env['LIBSUFFIX']}", thirdparty_icu_sources) env.Append(LIBS=[lib]) env.Append(CPPDEFINES=["GDEXTENSION"]) @@ -746,18 +746,18 @@ sources = Glob("../*.cpp") if env["platform"] == "macos": methods.write_macos_plist( - f'./bin/libtextserver_advanced.macos.{env["target"]}.framework', - f'libtextserver_advanced.macos.{env["target"]}', + f"./bin/libtextserver_advanced.macos.{env['target']}.framework", + f"libtextserver_advanced.macos.{env['target']}", "org.godotengine.textserver_advanced", "ICU / HarfBuzz / Graphite Text Server", ) library = env.SharedLibrary( - f'./bin/libtextserver_advanced.macos.{env["target"]}.framework/libtextserver_advanced.macos.{env["target"]}', + f"./bin/libtextserver_advanced.macos.{env['target']}.framework/libtextserver_advanced.macos.{env['target']}", source=sources, ) else: library = env.SharedLibrary( - f'./bin/libtextserver_advanced{env["suffix"]}{env["SHLIBSUFFIX"]}', + f"./bin/libtextserver_advanced{env['suffix']}{env['SHLIBSUFFIX']}", source=sources, ) diff --git a/modules/text_server_fb/gdextension_build/SConstruct b/modules/text_server_fb/gdextension_build/SConstruct index 6f97ccf9dd6b..5a0adef7c5ae 100644 --- a/modules/text_server_fb/gdextension_build/SConstruct +++ b/modules/text_server_fb/gdextension_build/SConstruct @@ -105,7 +105,7 @@ if env["thorvg_enabled"] and env["freetype_enabled"]: env.Append(CPPDEFINES=["MODULE_SVG_ENABLED"]) lib = env_tvg.Library( - f'tvg_builtin{env["suffix"]}{env["LIBSUFFIX"]}', + f"tvg_builtin{env['suffix']}{env['LIBSUFFIX']}", thirdparty_tvg_sources, ) env.Append(LIBS=[lib]) @@ -150,7 +150,7 @@ if env["msdfgen_enabled"] and env["freetype_enabled"]: env.Append(CPPDEFINES=["MODULE_MSDFGEN_ENABLED"]) lib = env_msdfgen.Library( - f'msdfgen_builtin{env["suffix"]}{env["LIBSUFFIX"]}', + f"msdfgen_builtin{env['suffix']}{env['LIBSUFFIX']}", thirdparty_msdfgen_sources, ) env.Append(LIBS=[lib]) @@ -279,7 +279,7 @@ if env["freetype_enabled"]: env.Append(CPPDEFINES=["MODULE_FREETYPE_ENABLED"]) lib = env_freetype.Library( - f'freetype_builtin{env["suffix"]}{env["LIBSUFFIX"]}', + f"freetype_builtin{env['suffix']}{env['LIBSUFFIX']}", thirdparty_freetype_sources, ) env.Append(LIBS=[lib]) @@ -291,18 +291,18 @@ sources = Glob("../*.cpp") if env["platform"] == "macos": methods.write_macos_plist( - f'./bin/libtextserver_fallback.macos.{env["target"]}.framework', - f'libtextserver_fallback.macos.{env["target"]}', + f"./bin/libtextserver_fallback.macos.{env['target']}.framework", + f"libtextserver_fallback.macos.{env['target']}", "org.godotengine.textserver_fallback", "Fallback Text Server", ) library = env.SharedLibrary( - f'./bin/libtextserver_fallback.macos.{env["target"]}.framework/libtextserver_fallback.macos.{env["target"]}', + f"./bin/libtextserver_fallback.macos.{env['target']}.framework/libtextserver_fallback.macos.{env['target']}", source=sources, ) else: library = env.SharedLibrary( - f'./bin/libtextserver_fallback{env["suffix"]}{env["SHLIBSUFFIX"]}', + f"./bin/libtextserver_fallback{env['suffix']}{env['SHLIBSUFFIX']}", source=sources, ) diff --git a/scene/gui/color_mode.cpp b/scene/gui/color_mode.cpp index 5f58a16d50fe..0ebb529d82b5 100644 --- a/scene/gui/color_mode.cpp +++ b/scene/gui/color_mode.cpp @@ -267,7 +267,7 @@ void ColorModeRAW::slider_draw(int p_which) { } bool ColorModeRAW::apply_theme() const { - for (int i = 0; i < 4; i++) { + for (int i = 0; i < ColorPicker::SLIDER_COUNT; i++) { HSlider *slider = color_picker->get_slider(i); slider->remove_theme_icon_override("grabber"); slider->remove_theme_icon_override("grabber_highlight"); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index f290774e2385..43c0b146df9c 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1637,6 +1637,7 @@ void TextEdit::_notification(int p_what) { } if (has_ime_text() && has_selection()) { + set_selection_mode(SELECTION_MODE_NONE); delete_selection(); } @@ -1965,6 +1966,7 @@ void TextEdit::gui_input(const Ref &p_gui_input) { _reset_caret_blink_timer(); apply_ime(); _cancel_drag_and_drop_text(); + set_selection_mode(SELECTION_MODE_NONE); Point2i pos = get_line_column_at_pos(mpos); int mouse_line = pos.y; @@ -4743,6 +4745,8 @@ void TextEdit::add_caret_at_carets(bool p_below) { } const int last_line_max_wrap = get_line_wrap_count(text.size() - 1); + set_selection_mode(SELECTION_MODE_NONE); + begin_multicaret_edit(); int view_target_caret = -1; int view_line = p_below ? -1 : INT_MAX; @@ -5289,6 +5293,8 @@ void TextEdit::select_word_under_caret(int p_caret) { return; } + set_selection_mode(SELECTION_MODE_NONE); + for (int c = 0; c < carets.size(); c++) { if (p_caret != -1 && p_caret != c) { continue; @@ -5342,6 +5348,8 @@ void TextEdit::add_selection_for_next_occurrence() { return; } + set_selection_mode(SELECTION_MODE_NONE); + const String &highlighted_text = get_selected_text(caret); int column = get_selection_from_column(caret) + 1; int line = get_selection_from_line(caret); @@ -5373,6 +5381,8 @@ void TextEdit::skip_selection_for_next_occurrence() { return; } + set_selection_mode(SELECTION_MODE_NONE); + // Always use the last caret, to correctly search for // the next occurrence that comes after this caret. int caret = get_caret_count() - 1; @@ -5916,6 +5926,9 @@ void TextEdit::set_line_as_first_visible(int p_line, int p_wrap_index) { ERR_FAIL_COND(p_wrap_index < 0); ERR_FAIL_COND(p_wrap_index > get_line_wrap_count(p_line)); set_v_scroll(get_scroll_pos_for_line(p_line, p_wrap_index)); + + scrolling = false; + minimap_clicked = false; } int TextEdit::get_first_visible_line() const { @@ -5927,6 +5940,9 @@ void TextEdit::set_line_as_center_visible(int p_line, int p_wrap_index) { ERR_FAIL_COND(p_wrap_index < 0); ERR_FAIL_COND(p_wrap_index > get_line_wrap_count(p_line)); + scrolling = false; + minimap_clicked = false; + int visible_rows = get_visible_line_count(); Point2i next_line = get_next_visible_line_index_offset_from(p_line, p_wrap_index, (-visible_rows / 2) - 1); int first_line = p_line - next_line.x + 1; @@ -5943,6 +5959,9 @@ void TextEdit::set_line_as_last_visible(int p_line, int p_wrap_index) { ERR_FAIL_COND(p_wrap_index < 0); ERR_FAIL_COND(p_wrap_index > get_line_wrap_count(p_line)); + scrolling = false; + minimap_clicked = false; + Point2i next_line = get_next_visible_line_index_offset_from(p_line, p_wrap_index, -get_visible_line_count() - 1); int first_line = p_line - next_line.x + 1; @@ -6005,8 +6024,6 @@ void TextEdit::adjust_viewport_to_caret(int p_caret) { ERR_FAIL_INDEX(p_caret, carets.size()); // Move viewport so the caret is visible on the screen vertically. - scrolling = false; - minimap_clicked = false; int cur_line = get_caret_line(p_caret); int cur_wrap = get_caret_wrap_index(p_caret); @@ -7699,7 +7716,7 @@ void TextEdit::_selection_changed(int p_caret) { void TextEdit::_click_selection_held() { // Update the selection mode on a timer so it is updated when the view scrolls even if the mouse isn't moving. - if (!Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT) || get_selection_mode() == SelectionMode::SELECTION_MODE_NONE) { + if (!Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT)) { click_select_held->stop(); return; } @@ -7714,6 +7731,7 @@ void TextEdit::_click_selection_held() { _update_selection_mode_line(); } break; default: { + click_select_held->stop(); break; } } diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 76b2502bade3..d0054baeff25 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -3352,6 +3352,22 @@ void Viewport::_push_unhandled_input_internal(const Ref &p_event) { } } +void Viewport::notify_mouse_entered() { + if (gui.mouse_in_viewport) { + WARN_PRINT_ED("The Viewport was previously notified that the mouse is in its area. There is no need to notify it at this time."); + return; + } + notification(NOTIFICATION_VP_MOUSE_ENTER); +} + +void Viewport::notify_mouse_exited() { + if (!gui.mouse_in_viewport) { + WARN_PRINT_ED("The Viewport was previously notified that the mouse has left its area. There is no need to notify it at this time."); + return; + } + _mouse_leave_viewport(); +} + void Viewport::set_physics_object_picking(bool p_enable) { ERR_MAIN_THREAD_GUARD; physics_object_picking = p_enable; @@ -4799,6 +4815,8 @@ void Viewport::_bind_methods() { #ifndef DISABLE_DEPRECATED ClassDB::bind_method(D_METHOD("push_unhandled_input", "event", "in_local_coords"), &Viewport::push_unhandled_input, DEFVAL(false)); #endif // DISABLE_DEPRECATED + ClassDB::bind_method(D_METHOD("notify_mouse_entered"), &Viewport::notify_mouse_entered); + ClassDB::bind_method(D_METHOD("notify_mouse_exited"), &Viewport::notify_mouse_exited); ClassDB::bind_method(D_METHOD("get_mouse_position"), &Viewport::get_mouse_position); ClassDB::bind_method(D_METHOD("warp_mouse", "position"), &Viewport::warp_mouse); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 63bec5b01c37..5260b513a951 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -596,6 +596,8 @@ class Viewport : public Node { #ifndef DISABLE_DEPRECATED void push_unhandled_input(const Ref &p_event, bool p_local_coords = false); #endif // DISABLE_DEPRECATED + void notify_mouse_entered(); + void notify_mouse_exited(); void set_disable_input(bool p_disable); bool is_input_disabled() const;