Repository: godotengine/godot (language: cpp)

Issue:
Material Inspector Panel Scrolls Down Erratically
### Tested versions

Godot 4.3 .Net
Godot 4.4 .Net

### System information

Win10 22H2 x64
RTX 3070, Driver 572.60

### Issue description
Clicking any setting in the Material Inspector Panel, then clicking anything else in the Material Inspector Panel causes the panel to scroll down by a large amount. This becomes more annoying if the Inspector Panel is made smaller.

Issue occurs in Normal Mode, in Self Contained Mode, and even after setting layout to default.
https://docs.godotengine.org/en/stable/tutorials/io/data_paths.html#self-contained-mode

Issue does NOT occur if the Inspector Panel is Floating.

### Steps to reproduce

1) Add any node that supports a material, then add a material to the node. For example, add CSGBox with a StandardMaterial3D.
2) Click on the StandardMaterial to view its properties in the Inspector Panel.
3) Open up any section in the Material Inspector Panel. For example, I will open up Transparency.
4) Click on any dropdown within Transparency. For example, Cull Mode's dropdown. Close the dropdown by selecting a dropdown option, or clicking outside the dropdown.
5) Click again anywhere in the Material Inspector Panel that is NOT a setting. For example, click on the actual word "Cull Mode". This will trigger the bug -> The inspector scrolls down by a large amount.
6) This may not seem like a big deal, but let's say you want to change Cull Mode's dropdown, and then the Albedo settings.
You click the Cull Mode dropdown and choose your setting. You then scroll down to click on Albedo section to expand it. Clicking on Albedo section will cause the inspector to scroll down by a large amount, forcing the user to scroll back up to Albedo.

Perform the above with a floating Inspector Panel, and the bug will not occur.

### Minimal reproduction project (MRP)

N/A


Discussion / hints:

Fix patch:
diff --git a/doc/classes/EditorInspector.xml b/doc/classes/EditorInspector.xml
index 644cbe5b5817..0bbd55f00757 100644
--- a/doc/classes/EditorInspector.xml
+++ b/doc/classes/EditorInspector.xml
@@ -51,6 +51,7 @@
 	<members>
 		<member name="draw_focus_border" type="bool" setter="set_draw_focus_border" getter="get_draw_focus_border" overrides="ScrollContainer" default="true" />
 		<member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" overrides="Control" enum="Control.FocusMode" default="2" />
+		<member name="follow_focus" type="bool" setter="set_follow_focus" getter="is_following_focus" overrides="ScrollContainer" default="true" />
 		<member name="horizontal_scroll_mode" type="int" setter="set_horizontal_scroll_mode" getter="get_horizontal_scroll_mode" overrides="ScrollContainer" enum="ScrollContainer.ScrollMode" default="0" />
 	</members>
 	<signals>
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 58b02ed2b8a1..5818c863538b 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -918,6 +918,9 @@ void EditorProperty::gui_input(const Ref<InputEvent> &p_event) {
 
 	if (me.is_valid()) {
 		Vector2 mpos = me->get_position();
+		if (bottom_child_rect.has_point(mpos)) {
+			return; // Makes child EditorProperties behave like sibling nodes when handling mouse events.
+		}
 		if (is_layout_rtl()) {
 			mpos.x = get_size().x - mpos.x;
 		}
@@ -2715,8 +2718,6 @@ VBoxContainer *EditorInspectorArray::get_vbox(int p_index) {
 EditorInspectorArray::EditorInspectorArray(bool p_read_only) {
 	read_only = p_read_only;
 
-	set_mouse_filter(Control::MOUSE_FILTER_STOP);
-
 	odd_style.instantiate();
 	even_style.instantiate();
 
@@ -3046,7 +3047,6 @@ void EditorInspector::update_tree() {
 	int current_focusable = -1;
 
 	// Temporarily disable focus following on the root inspector to avoid jumping while the inspector is updating.
-	bool was_following = get_root_inspector()->is_following_focus();
 	get_root_inspector()->set_follow_focus(false);
 
 	if (property_focusable != -1) {
@@ -3075,7 +3075,7 @@ void EditorInspector::update_tree() {
 	_clear(!object);
 
 	if (!object) {
-		get_root_inspector()->set_follow_focus(was_following);
+		get_root_inspector()->set_follow_focus(true);
 		return;
 	}
 
@@ -3954,7 +3954,7 @@ void EditorInspector::update_tree() {
 		EditorNode::get_singleton()->hide_unused_editors();
 	}
 
-	get_root_inspector()->set_follow_focus(was_following);
+	get_root_inspector()->set_follow_focus(true);
 }
 
 void EditorInspector::update_property(const String &p_prop) {
@@ -4528,14 +4528,6 @@ void EditorInspector::_node_removed(Node *p_node) {
 	}
 }
 
-void EditorInspector::_gui_focus_changed(Control *p_control) {
-	if (!is_visible_in_tree() && !is_following_focus()) {
-		return;
-	}
-	// Don't follow focus when the inspector nor any of its children is focused. Prevents potential jumping when gaining focus.
-	set_follow_focus(has_focus() || child_has_focus());
-}
-
 void EditorInspector::_update_current_favorites() {
 	current_favorites.clear();
 	if (!can_favorite) {
@@ -4733,10 +4725,6 @@ void EditorInspector::_notification(int p_what) {
 			if (!is_sub_inspector()) {
 				get_tree()->connect("node_removed", callable_mp(this, &EditorInspector::_node_removed));
 			}
-
-			Viewport *viewport = get_viewport();
-			ERR_FAIL_NULL(viewport);
-			viewport->connect("gui_focus_changed", callable_mp(this, &EditorInspector::_gui_focus_changed));
 		} break;
 
 		case NOTIFICATION_PREDELETE: {
@@ -4975,6 +4963,7 @@ EditorInspector::EditorInspector() {
 	base_vbox->add_child(main_vbox);
 
 	set_horizontal_scroll_mode(SCROLL_MODE_DISABLED);
+	set_follow_focus(true);
 
 	changing = 0;
 	search_box = nullptr;
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index 9baf65444f27..ee82806003b2 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -606,7 +606,6 @@ class EditorInspector : public ScrollContainer {
 	void _clear_current_favorites();
 
 	void _node_removed(Node *p_node);
-	void _gui_focus_changed(Control *p_control);
 
 	HashMap<StringName, int> per_array_page;
 	void _page_change_request(int p_new_page, const StringName &p_array_prefix);
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 52780d7c5889..935915a0c080 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -3303,11 +3303,11 @@ void EditorPropertyResource::update_property() {
 				sub_inspector->set_use_folding(is_using_folding());
 
 				sub_inspector->set_draw_focus_border(false);
+				sub_inspector->set_focus_mode(FocusMode::FOCUS_NONE);
 
 				sub_inspector->set_use_filter(use_filter);
 				sub_inspector->register_text_enter(parent_inspector->search_box);
 
-				sub_inspector->set_mouse_filter(MOUSE_FILTER_STOP);
 				add_child(sub_inspector);
 				set_bottom_editor(sub_inspector);
 
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index 93c5a70cf907..066c0d7d9e32 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -430,7 +430,6 @@ void EditorPropertyArray::update_property() {
 
 		if (!container) {
 			container = memnew(PanelContainer);
-			container->set_mouse_filter(MOUSE_FILTER_STOP);
 			add_child(container);
 			set_bottom_editor(container);
 
@@ -1208,7 +1207,6 @@ void EditorPropertyDictionary::update_property() {
 
 		if (!container) {
 			container = memnew(PanelContainer);
-			container->set_mouse_filter(MOUSE_FILTER_STOP);
 			add_child(container);
 			set_bottom_editor(container);
 
diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h
index 408f70157dfe..ea6309f57e80 100644
--- a/scene/gui/scroll_container.h
+++ b/scene/gui/scroll_container.h
@@ -82,6 +82,7 @@ class ScrollContainer : public Container {
 
 	bool draw_focus_border = false;
 	bool focus_border_is_drawn = false;
+	bool child_has_focus();
 
 protected:
 	Size2 get_minimum_size() const override;
@@ -98,7 +99,6 @@ class ScrollContainer : public Container {
 
 public:
 	virtual void gui_input(const Ref<InputEvent> &p_gui_input) override;
-	bool child_has_focus();
 
 	void set_h_scroll(int p_pos);
 	int get_h_scroll() const;


Test patch: