summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/core_constants.cpp2
-rw-r--r--core/multiplayer/multiplayer.h2
-rw-r--r--core/string/ustring.cpp15
-rw-r--r--doc/classes/@GlobalScope.xml4
-rw-r--r--doc/classes/NavigationObstacle2D.xml1
-rw-r--r--doc/classes/NavigationObstacle3D.xml1
-rw-r--r--doc/classes/Node.xml2
-rw-r--r--editor/plugins/node_3d_editor_gizmos.cpp85
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp23
-rw-r--r--editor/plugins/node_3d_editor_plugin.h1
-rw-r--r--editor/plugins/path_3d_editor_plugin.cpp20
-rw-r--r--modules/text_server_adv/text_server_adv.cpp2
-rw-r--r--platform/linuxbsd/display_server_x11.cpp15
-rw-r--r--platform/linuxbsd/display_server_x11.h2
-rw-r--r--platform/osx/display_server_osx.h2
-rw-r--r--platform/osx/display_server_osx.mm11
-rw-r--r--platform/osx/godot_application.mm5
-rw-r--r--platform/windows/display_server_windows.cpp1
-rw-r--r--scene/3d/audio_stream_player_3d.cpp3
-rw-r--r--scene/3d/navigation_region_3d.cpp11
-rw-r--r--scene/gui/graph_edit.cpp5
-rw-r--r--scene/gui/text_edit.cpp2
22 files changed, 170 insertions, 45 deletions
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
index a53929a3af..ea1304f5ba 100644
--- a/core/core_constants.cpp
+++ b/core/core_constants.cpp
@@ -645,7 +645,7 @@ void register_global_constants() {
// rpc
BIND_CORE_ENUM_CONSTANT_CUSTOM("RPC_MODE_DISABLED", Multiplayer::RPC_MODE_DISABLED);
BIND_CORE_ENUM_CONSTANT_CUSTOM("RPC_MODE_ANY_PEER", Multiplayer::RPC_MODE_ANY_PEER);
- BIND_CORE_ENUM_CONSTANT_CUSTOM("RPC_MODE_AUTH", Multiplayer::RPC_MODE_AUTHORITY);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("RPC_MODE_AUTHORITY", Multiplayer::RPC_MODE_AUTHORITY);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TRANSFER_MODE_UNRELIABLE", Multiplayer::TRANSFER_MODE_UNRELIABLE);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TRANSFER_MODE_UNRELIABLE_ORDERED", Multiplayer::TRANSFER_MODE_UNRELIABLE_ORDERED);
diff --git a/core/multiplayer/multiplayer.h b/core/multiplayer/multiplayer.h
index 5eb968171a..f4c965b0f8 100644
--- a/core/multiplayer/multiplayer.h
+++ b/core/multiplayer/multiplayer.h
@@ -46,7 +46,7 @@ enum TransferMode {
enum RPCMode {
RPC_MODE_DISABLED, // No rpc for this method, calls to this will be blocked (default)
RPC_MODE_ANY_PEER, // Any peer can call this RPC
- RPC_MODE_AUTHORITY, // / Only the node's multiplayer authority (server by default) can call this RPC
+ RPC_MODE_AUTHORITY, // Only the node's multiplayer authority (server by default) can call this RPC
};
struct RPCConfig {
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index 44df349613..d189f3224b 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -3712,18 +3712,15 @@ String String::uri_encode() const {
const CharString temp = utf8();
String res;
for (int i = 0; i < temp.length(); ++i) {
- char ord = temp[i];
+ uint8_t ord = temp[i];
if (ord == '.' || ord == '-' || ord == '~' || is_ascii_identifier_char(ord)) {
res += ord;
} else {
- char h_Val[3];
-#if defined(__GNUC__) || defined(_MSC_VER)
- snprintf(h_Val, 3, "%02hhX", ord);
-#else
- sprintf(h_Val, "%02hhX", ord);
-#endif
- res += "%";
- res += h_Val;
+ char p[4] = { '%', 0, 0, 0 };
+ static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+ p[1] = hex[ord >> 4];
+ p[2] = hex[ord & 0xF];
+ res += p;
}
}
return res;
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 5f81c80887..43101d6e5e 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -2640,8 +2640,8 @@
<constant name="RPC_MODE_ANY_PEER" value="1" enum="RPCMode">
Used with [method Node.rpc_config] to set a method to be callable remotely by any peer. Analogous to the [code]@rpc(any)[/code] annotation. Calls are accepted from all remote peers, no matter if they are node's authority or not.
</constant>
- <constant name="RPC_MODE_AUTH" value="2" enum="RPCMode">
- Used with [method Node.rpc_config] to set a method to be callable remotely only by the current multiplayer authority (which is the server by default). Analogous to the [code]@rpc(auth)[/code] annotation. See [method Node.set_multiplayer_authority].
+ <constant name="RPC_MODE_AUTHORITY" value="2" enum="RPCMode">
+ Used with [method Node.rpc_config] to set a method to be callable remotely only by the current multiplayer authority (which is the server by default). Analogous to the [code]@rpc(authority)[/code] annotation. See [method Node.set_multiplayer_authority].
</constant>
<constant name="TRANSFER_MODE_UNRELIABLE" value="0" enum="TransferMode">
Packets are not acknowledged, no resend attempts are made for lost packets. Packets may arrive in any order. Potentially faster than [constant TRANSFER_MODE_UNRELIABLE_ORDERED]. Use for non-critical data, and always consider whether the order matters.
diff --git a/doc/classes/NavigationObstacle2D.xml b/doc/classes/NavigationObstacle2D.xml
index f3690ce8a7..4ecdc06645 100644
--- a/doc/classes/NavigationObstacle2D.xml
+++ b/doc/classes/NavigationObstacle2D.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
2D Obstacle used in navigation for collision avoidance. The obstacle needs navigation data to work correctly. [NavigationObstacle2D] is physics safe.
+ [b]Note:[/b] Obstacles are intended as a last resort option for constantly moving objects that cannot be (re)baked to a navigation mesh efficiently.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/NavigationObstacle3D.xml b/doc/classes/NavigationObstacle3D.xml
index e6ea70b91a..ed8af3883c 100644
--- a/doc/classes/NavigationObstacle3D.xml
+++ b/doc/classes/NavigationObstacle3D.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
3D Obstacle used in navigation for collision avoidance. The obstacle needs navigation data to work correctly. [NavigationObstacle3D] is physics safe.
+ [b]Note:[/b] Obstacles are intended as a last resort option for constantly moving objects that cannot be (re)baked to a navigation mesh efficiently.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index e9000d4356..966e24c537 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -637,7 +637,7 @@
<argument index="3" name="transfer_mode" type="int" enum="TransferMode" default="2" />
<argument index="4" name="channel" type="int" default="0" />
<description>
- Changes the RPC mode for the given [code]method[/code] to the given [code]rpc_mode[/code], optionally specifying the [code]transfer_mode[/code] and [code]channel[/code] (on supported peers). See [enum RPCMode] and [enum TransferMode]. An alternative is annotating methods and properties with the corresponding annotation ([code]@rpc(any)[/code], [code]@rpc(auth)[/code]). By default, methods are not exposed to networking (and RPCs).
+ Changes the RPC mode for the given [code]method[/code] to the given [code]rpc_mode[/code], optionally specifying the [code]transfer_mode[/code] and [code]channel[/code] (on supported peers). See [enum RPCMode] and [enum TransferMode]. An alternative is annotating methods and properties with the corresponding annotation ([code]@rpc(any)[/code], [code]@rpc(authority)[/code]). By default, methods are not exposed to networking (and RPCs).
</description>
</method>
<method name="rpc_id" qualifiers="vararg">
diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp
index 37922dd5c9..64aeb9f2a8 100644
--- a/editor/plugins/node_3d_editor_gizmos.cpp
+++ b/editor/plugins/node_3d_editor_gizmos.cpp
@@ -1497,6 +1497,9 @@ AudioStreamPlayer3DGizmoPlugin::AudioStreamPlayer3DGizmoPlugin() {
create_icon_material("stream_player_3d_icon", Node3DEditor::get_singleton()->get_theme_icon(SNAME("Gizmo3DSamplePlayer"), SNAME("EditorIcons")));
create_material("stream_player_3d_material_primary", gizmo_color);
create_material("stream_player_3d_material_secondary", gizmo_color * Color(1, 1, 1, 0.35));
+ // Enable vertex colors for the billboard material as the gizmo color depends on the
+ // AudioStreamPlayer3D attenuation type and source (Unit Size or Max Distance).
+ create_material("stream_player_3d_material_billboard", Color(1, 1, 1), true, false, true);
create_handle_material("handles");
}
@@ -1580,6 +1583,88 @@ void AudioStreamPlayer3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
const Ref<Material> icon = get_material("stream_player_3d_icon", p_gizmo);
+ if (player->get_attenuation_model() != AudioStreamPlayer3D::ATTENUATION_DISABLED || player->get_max_distance() > CMP_EPSILON) {
+ // Draw a circle to represent sound volume attenuation.
+ // Use only a billboard circle to represent radius.
+ // This helps distinguish AudioStreamPlayer3D gizmos from OmniLight3D gizmos.
+ const Ref<Material> lines_billboard_material = get_material("stream_player_3d_material_billboard", p_gizmo);
+
+ // Soft distance cap varies depending on attenuation model, as some will fade out more aggressively than others.
+ // Multipliers were empirically determined through testing.
+ float soft_multiplier;
+ switch (player->get_attenuation_model()) {
+ case AudioStreamPlayer3D::ATTENUATION_INVERSE_DISTANCE:
+ soft_multiplier = 12.0;
+ break;
+ case AudioStreamPlayer3D::ATTENUATION_INVERSE_SQUARE_DISTANCE:
+ soft_multiplier = 4.0;
+ break;
+ case AudioStreamPlayer3D::ATTENUATION_LOGARITHMIC:
+ soft_multiplier = 3.25;
+ break;
+ default:
+ // Ensures Max Distance's radius visualization is not capped by Unit Size
+ // (when the attenuation mode is Disabled).
+ soft_multiplier = 10000.0;
+ break;
+ }
+
+ // Draw the distance at which the sound can be reasonably heard.
+ // This can be either a hard distance cap with the Max Distance property (if set above 0.0),
+ // or a soft distance cap with the Unit Size property (sound never reaches true zero).
+ // When Max Distance is 0.0, `r` represents the distance above which the
+ // sound can't be heard in *most* (but not all) scenarios.
+ float r;
+ if (player->get_max_distance() > CMP_EPSILON) {
+ r = MIN(player->get_unit_size() * soft_multiplier, player->get_max_distance());
+ } else {
+ r = player->get_unit_size() * soft_multiplier;
+ }
+ Vector<Vector3> points_billboard;
+
+ for (int i = 0; i < 120; i++) {
+ // Create a circle.
+ const float ra = Math::deg2rad((float)(i * 3));
+ const float rb = Math::deg2rad((float)((i + 1) * 3));
+ const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
+ const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
+
+ // Draw a billboarded circle.
+ points_billboard.push_back(Vector3(a.x, a.y, 0));
+ points_billboard.push_back(Vector3(b.x, b.y, 0));
+ }
+
+ Color color;
+ switch (player->get_attenuation_model()) {
+ // Pick cold colors for all attenuation models (except Disabled),
+ // so that soft caps can be easily distinguished from hard caps
+ // (which use warm colors).
+ case AudioStreamPlayer3D::ATTENUATION_INVERSE_DISTANCE:
+ color = Color(0.4, 0.8, 1);
+ break;
+ case AudioStreamPlayer3D::ATTENUATION_INVERSE_SQUARE_DISTANCE:
+ color = Color(0.4, 0.5, 1);
+ break;
+ case AudioStreamPlayer3D::ATTENUATION_LOGARITHMIC:
+ color = Color(0.4, 0.2, 1);
+ break;
+ default:
+ // Disabled attenuation mode.
+ // This is never reached when Max Distance is 0, but the
+ // hue-inverted form of this color will be used if Max Distance is greater than 0.
+ color = Color(1, 1, 1);
+ break;
+ }
+
+ if (player->get_max_distance() > CMP_EPSILON) {
+ // Sound is hard-capped by max distance. The attenuation model still matters,
+ // so invert the hue of the color that was chosen above.
+ color.set_h(color.get_h() + 0.5);
+ }
+
+ p_gizmo->add_lines(points_billboard, lines_billboard_material, true, color);
+ }
+
if (player->is_emission_angle_enabled()) {
const float pc = player->get_emission_angle();
const float ofs = -Math::cos(Math::deg2rad(pc));
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index cbdb1e520a..06ad0f8918 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -411,6 +411,11 @@ void Node3DEditorViewport::cancel_transform() {
set_message(TTR("Transform Aborted."), 3);
}
+void Node3DEditorViewport::_update_shrink() {
+ bool shrink = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION));
+ subviewport_container->set_stretch_shrink(shrink ? 2 : 1);
+}
+
float Node3DEditorViewport::get_znear() const {
return CLAMP(spatial_editor->get_znear(), MIN_Z, MAX_Z);
}
@@ -2387,11 +2392,7 @@ void Node3DEditorViewport::_project_settings_changed() {
viewport->set_shadow_atlas_quadrant_subdiv(2, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q2));
viewport->set_shadow_atlas_quadrant_subdiv(3, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q3));
- bool shrink = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION));
-
- if (shrink != (subviewport_container->get_stretch_shrink() > 1)) {
- subviewport_container->set_stretch_shrink(shrink ? 2 : 1);
- }
+ _update_shrink();
// Update MSAA, screen-space AA and debanding if changed
@@ -3085,8 +3086,8 @@ void Node3DEditorViewport::_menu_option(int p_option) {
case VIEW_HALF_RESOLUTION: {
int idx = view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION);
bool current = view_menu->get_popup()->is_item_checked(idx);
- current = !current;
- view_menu->get_popup()->set_item_checked(idx, current);
+ view_menu->get_popup()->set_item_checked(idx, !current);
+ _update_shrink();
} break;
case VIEW_INFORMATION: {
int idx = view_menu->get_popup()->get_item_index(VIEW_INFORMATION);
@@ -8126,7 +8127,13 @@ void Node3DEditorPlugin::edit(Object *p_object) {
}
bool Node3DEditorPlugin::handles(Object *p_object) const {
- return p_object->is_class("Node3D");
+ if (p_object->is_class("Node3D")) {
+ return true;
+ } else {
+ // This ensures that gizmos are cleared when selecting a non-Node3D node.
+ const_cast<Node3DEditorPlugin *>(this)->edit((Object *)nullptr);
+ return false;
+ }
}
Dictionary Node3DEditorPlugin::get_state() const {
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index 511135a5f1..627443bd62 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -251,6 +251,7 @@ private:
Transform3D _get_camera_transform() const;
int get_selected_count() const;
void cancel_transform();
+ void _update_shrink();
Vector3 _get_camera_position() const;
Vector3 _get_camera_normal() const;
diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp
index 3851738cfa..467af8c34b 100644
--- a/editor/plugins/path_3d_editor_plugin.cpp
+++ b/editor/plugins/path_3d_editor_plugin.cpp
@@ -52,7 +52,7 @@ String Path3DGizmo::get_handle_name(int p_id, bool p_secondary) const {
int idx = p_id / 2;
int t = p_id % 2;
String n = TTR("Curve Point #") + itos(idx);
- if (t == 0) {
+ if (t == 1) {
n += " In";
} else {
n += " Out";
@@ -78,7 +78,7 @@ Variant Path3DGizmo::get_handle_value(int p_id, bool p_secondary) const {
int t = p_id % 2;
Vector3 ofs;
- if (t == 0) {
+ if (t == 1) {
ofs = c->get_point_in(idx);
} else {
ofs = c->get_point_out(idx);
@@ -144,7 +144,7 @@ void Path3DGizmo::set_handle(int p_id, bool p_secondary, Camera3D *p_camera, con
local.snap(Vector3(snap, snap, snap));
}
- if (t == 0) {
+ if (t == 1) {
c->set_point_in(idx, local);
if (Path3DEditorPlugin::singleton->mirror_angle_enabled()) {
c->set_point_out(idx, Path3DEditorPlugin::singleton->mirror_length_enabled() ? -local : (-local.normalized() * orig_out_length));
@@ -184,7 +184,7 @@ void Path3DGizmo::commit_handle(int p_id, bool p_secondary, const Variant &p_res
int idx = p_id / 2;
int t = p_id % 2;
- if (t == 0) {
+ if (t == 1) {
if (p_cancel) {
c->set_point_in(p_id, p_restore);
return;
@@ -263,17 +263,17 @@ void Path3DGizmo::redraw() {
for (int i = 0; i < c->get_point_count(); i++) {
Vector3 p = c->get_point_position(i);
handles.push_back(p);
- if (i > 0) {
- v3p.push_back(p);
- v3p.push_back(p + c->get_point_in(i));
- sec_handles.push_back(p + c->get_point_in(i));
- }
-
+ // push Out points first so they get selected if the In and Out points are on top of each other.
if (i < c->get_point_count() - 1) {
v3p.push_back(p);
v3p.push_back(p + c->get_point_out(i));
sec_handles.push_back(p + c->get_point_out(i));
}
+ if (i > 0) {
+ v3p.push_back(p);
+ v3p.push_back(p + c->get_point_in(i));
+ sec_handles.push_back(p + c->get_point_in(i));
+ }
}
if (v3p.size() > 1) {
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 0f45855a76..598ccd1238 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -5640,8 +5640,10 @@ TextServerAdvanced::TextServerAdvanced() {
TextServerAdvanced::~TextServerAdvanced() {
_bmp_free_font_funcs();
+#ifdef MODULE_FREETYPE_ENABLED
if (ft_library != nullptr) {
FT_Done_FreeType(ft_library);
}
+#endif
u_cleanup();
}
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index 887d916f35..4aec111022 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -3298,19 +3298,20 @@ void DisplayServerX11::popup_close(WindowID p_window) {
}
}
-void DisplayServerX11::mouse_process_popups() {
+bool DisplayServerX11::mouse_process_popups() {
_THREAD_SAFE_METHOD_
if (popup_list.is_empty()) {
- return;
+ return false;
}
uint64_t delta = OS::get_singleton()->get_ticks_msec() - time_since_popup;
if (delta < 250) {
- return;
+ return false;
}
int number_of_screens = XScreenCount(x11_display);
+ bool closed = false;
for (int i = 0; i < number_of_screens; i++) {
Window root, child;
int root_x, root_y, win_x, win_y;
@@ -3340,6 +3341,7 @@ void DisplayServerX11::mouse_process_popups() {
}
if (C) {
_send_window_event(windows[C->get()], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST);
+ closed = true;
}
}
}
@@ -3347,6 +3349,7 @@ void DisplayServerX11::mouse_process_popups() {
last_mouse_monitor_pos = pos;
}
}
+ return closed;
}
void DisplayServerX11::process_events() {
@@ -3357,7 +3360,7 @@ void DisplayServerX11::process_events() {
++frame;
#endif
- mouse_process_popups();
+ bool ignore_events = mouse_process_popups();
if (app_focused) {
//verify that one of the windows has focus, else send focus out notification
@@ -3407,6 +3410,10 @@ void DisplayServerX11::process_events() {
for (uint32_t event_index = 0; event_index < events.size(); ++event_index) {
XEvent &event = events[event_index];
+ if (ignore_events) {
+ XFreeEventData(x11_display, &event.xcookie);
+ continue;
+ }
WindowID window_id = MAIN_WINDOW_ID;
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
index 872af3dc09..4beeddd3a8 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/display_server_x11.h
@@ -295,7 +295,7 @@ protected:
void _window_changed(XEvent *event);
public:
- void mouse_process_popups();
+ bool mouse_process_popups();
void popup_open(WindowID p_window);
void popup_close(WindowID p_window);
diff --git a/platform/osx/display_server_osx.h b/platform/osx/display_server_osx.h
index 52b4fab2ea..9575cb29a2 100644
--- a/platform/osx/display_server_osx.h
+++ b/platform/osx/display_server_osx.h
@@ -208,7 +208,7 @@ public:
void push_to_key_event_buffer(const KeyEvent &p_event);
void update_im_text(const Point2i &p_selection, const String &p_text);
void set_last_focused_window(WindowID p_window);
- void mouse_process_popups(bool p_close = false);
+ bool mouse_process_popups(bool p_close = false);
void popup_open(WindowID p_window);
void popup_close(WindowID p_window);
void set_is_resizing(bool p_is_resizing);
diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm
index 536751432b..b6a5813bd0 100644
--- a/platform/osx/display_server_osx.mm
+++ b/platform/osx/display_server_osx.mm
@@ -569,9 +569,6 @@ DisplayServerOSX::WindowData &DisplayServerOSX::get_window(WindowID p_window) {
}
void DisplayServerOSX::send_event(NSEvent *p_event) {
- if ([p_event type] == NSEventTypeLeftMouseDown || [p_event type] == NSEventTypeRightMouseDown || [p_event type] == NSEventTypeOtherMouseDown) {
- mouse_process_popups();
- }
// Special case handling of command-period, which is traditionally a special
// shortcut in macOS and doesn't arrive at our regular keyDown handler.
if ([p_event type] == NSEventTypeKeyDown) {
@@ -3085,15 +3082,17 @@ void DisplayServerOSX::popup_close(WindowID p_window) {
}
}
-void DisplayServerOSX::mouse_process_popups(bool p_close) {
+bool DisplayServerOSX::mouse_process_popups(bool p_close) {
_THREAD_SAFE_METHOD_
bool was_empty = popup_list.is_empty();
+ bool closed = false;
if (p_close) {
// Close all popups.
List<WindowID>::Element *E = popup_list.front();
if (E) {
send_window_event(windows[E->get()], DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST);
+ closed = true;
}
if (!was_empty) {
// Inform OS that all popups are closed.
@@ -3102,7 +3101,7 @@ void DisplayServerOSX::mouse_process_popups(bool p_close) {
} else {
uint64_t delta = OS::get_singleton()->get_ticks_msec() - time_since_popup;
if (delta < 250) {
- return;
+ return false;
}
Point2i pos = mouse_get_position();
@@ -3125,12 +3124,14 @@ void DisplayServerOSX::mouse_process_popups(bool p_close) {
}
if (C) {
send_window_event(windows[C->get()], DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST);
+ closed = true;
}
if (!was_empty && popup_list.is_empty()) {
// Inform OS that all popups are closed.
[[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.apple.HIToolbox.endMenuTrackingNotification" object:@"org.godotengine.godot.popup_window"];
}
}
+ return closed;
}
DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
diff --git a/platform/osx/godot_application.mm b/platform/osx/godot_application.mm
index 00a58700e8..13313a025a 100644
--- a/platform/osx/godot_application.mm
+++ b/platform/osx/godot_application.mm
@@ -37,6 +37,11 @@
- (void)sendEvent:(NSEvent *)event {
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
if (ds) {
+ if ([event type] == NSEventTypeLeftMouseDown || [event type] == NSEventTypeRightMouseDown || [event type] == NSEventTypeOtherMouseDown) {
+ if (ds->mouse_process_popups()) {
+ return;
+ }
+ }
ds->send_event(event);
}
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 9763fb1066..998b0882b3 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -2199,6 +2199,7 @@ LRESULT DisplayServerWindows::MouseProc(int code, WPARAM wParam, LPARAM lParam)
}
if (C) {
_send_window_event(windows[C->get()], DisplayServerWindows::WINDOW_EVENT_CLOSE_REQUEST);
+ return 1;
}
} break;
}
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 18a9cc5c8b..7c1fb3779f 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -541,6 +541,7 @@ float AudioStreamPlayer3D::get_unit_db() const {
void AudioStreamPlayer3D::set_unit_size(float p_volume) {
unit_size = p_volume;
+ update_gizmos();
}
float AudioStreamPlayer3D::get_unit_size() const {
@@ -669,6 +670,7 @@ void AudioStreamPlayer3D::_bus_layout_changed() {
void AudioStreamPlayer3D::set_max_distance(float p_metres) {
ERR_FAIL_COND(p_metres < 0.0);
max_distance = p_metres;
+ update_gizmos();
}
float AudioStreamPlayer3D::get_max_distance() const {
@@ -729,6 +731,7 @@ float AudioStreamPlayer3D::get_attenuation_filter_db() const {
void AudioStreamPlayer3D::set_attenuation_model(AttenuationModel p_model) {
ERR_FAIL_INDEX((int)p_model, 4);
attenuation_model = p_model;
+ update_gizmos();
}
AudioStreamPlayer3D::AttenuationModel AudioStreamPlayer3D::get_attenuation_model() const {
diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp
index 6404432631..cb8da182ee 100644
--- a/scene/3d/navigation_region_3d.cpp
+++ b/scene/3d/navigation_region_3d.cpp
@@ -131,6 +131,17 @@ void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &p_navmes
NavigationServer3D::get_singleton()->region_set_navmesh(region, p_navmesh);
+ if (debug_view == nullptr && is_inside_tree() && navmesh.is_valid() && get_tree()->is_debugging_navigation_hint()) {
+ MeshInstance3D *dm = memnew(MeshInstance3D);
+ dm->set_mesh(navmesh->get_debug_mesh());
+ if (is_enabled()) {
+ dm->set_material_override(get_tree()->get_debug_navigation_material());
+ } else {
+ dm->set_material_override(get_tree()->get_debug_navigation_disabled_material());
+ }
+ add_child(dm);
+ debug_view = dm;
+ }
if (debug_view && navmesh.is_valid()) {
Object::cast_to<MeshInstance3D>(debug_view)->set_mesh(navmesh->get_debug_mesh());
}
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 446d9e800a..8ad55fc6ef 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -508,8 +508,9 @@ void GraphEdit::_notification(int p_what) {
void GraphEdit::_update_comment_enclosed_nodes_list(GraphNode *p_node, HashMap<StringName, Vector<GraphNode *>> &p_comment_enclosed_nodes) {
Rect2 comment_node_rect = p_node->get_rect();
- Vector<GraphNode *> enclosed_nodes;
+ comment_node_rect.size *= zoom;
+ Vector<GraphNode *> enclosed_nodes;
for (int i = 0; i < get_child_count(); i++) {
GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
if (!gn || gn->is_selected()) {
@@ -517,6 +518,8 @@ void GraphEdit::_update_comment_enclosed_nodes_list(GraphNode *p_node, HashMap<S
}
Rect2 node_rect = gn->get_rect();
+ node_rect.size *= zoom;
+
bool included = comment_node_rect.encloses(node_rect);
if (included) {
enclosed_nodes.push_back(gn);
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 0f74c9c357..8e948203f1 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -3080,7 +3080,7 @@ void TextEdit::set_line(int p_line, const String &p_new_text) {
_remove_text(p_line, 0, p_line, text[p_line].length());
_insert_text(p_line, 0, p_new_text);
if (caret.line == p_line && caret.column > p_new_text.length()) {
- set_caret_column(MIN(caret.column, p_new_text.length()), false);
+ set_caret_column(p_new_text.length(), false);
}
if (has_selection() && p_line == selection.to_line && selection.to_column > text[p_line].length()) {
selection.to_column = text[p_line].length();