Skip to content

Commit 039d9ff

Browse files
committed
Merge pull request godotengine#104317 from pafuent/fixing_wrong_focus_style_clipping_on_scroll_container
Fix `ScrollContainer` focus border issue
2 parents c6341f4 + e1384dd commit 039d9ff

File tree

5 files changed

+98
-43
lines changed

5 files changed

+98
-43
lines changed

editor/editor_inspector.cpp

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4956,12 +4956,6 @@ void EditorInspector::_clear_current_favorites() {
49564956
update_tree();
49574957
}
49584958

4959-
void EditorInspector::_update_theme() {
4960-
updating_theme = true;
4961-
add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));
4962-
updating_theme = false;
4963-
}
4964-
49654959
void EditorInspector::_notification(int p_what) {
49664960
switch (p_what) {
49674961
case NOTIFICATION_TRANSLATION_CHANGED: {
@@ -4989,17 +4983,11 @@ void EditorInspector::_notification(int p_what) {
49894983
ERR_FAIL_NULL(EditorFeatureProfileManager::get_singleton());
49904984
EditorFeatureProfileManager::get_singleton()->connect("current_feature_profile_changed", callable_mp(this, &EditorInspector::_feature_profile_changed));
49914985
set_process(is_visible_in_tree());
4992-
get_parent()->connect(SceneStringName(theme_changed), callable_mp(this, &EditorInspector::_update_theme));
4993-
_update_theme();
49944986
if (!is_sub_inspector()) {
49954987
get_tree()->connect("node_removed", callable_mp(this, &EditorInspector::_node_removed));
49964988
}
49974989
} break;
49984990

4999-
case NOTIFICATION_EXIT_TREE: {
5000-
get_parent()->disconnect(SceneStringName(theme_changed), callable_mp(this, &EditorInspector::_update_theme));
5001-
} break;
5002-
50034991
case NOTIFICATION_PREDELETE: {
50044992
if (!is_sub_inspector() && is_inside_tree()) {
50054993
get_tree()->disconnect("node_removed", callable_mp(this, &EditorInspector::_node_removed));
@@ -5059,10 +5047,6 @@ void EditorInspector::_notification(int p_what) {
50595047
} break;
50605048

50615049
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
5062-
if (!is_sub_inspector() && EditorThemeManager::is_generated_theme_outdated()) {
5063-
_update_theme();
5064-
}
5065-
50665050
if (use_settings_name_style && EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/localize_settings")) {
50675051
EditorPropertyNameProcessor::Style style = EditorPropertyNameProcessor::get_settings_style();
50685052
if (property_name_style != style) {

editor/editor_inspector.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -638,8 +638,6 @@ class EditorInspector : public ScrollContainer {
638638
void _set_property_favorited(const String &p_path, bool p_favorited);
639639
void _clear_current_favorites();
640640

641-
void _update_theme();
642-
643641
void _node_removed(Node *p_node);
644642

645643
HashMap<StringName, int> per_array_page;

editor/themes/editor_theme_manager.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1888,8 +1888,6 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme
18881888
p_theme->set_stylebox("FocusViewport", EditorStringName(EditorStyles), style_widget_focus_viewport);
18891889

18901890
Ref<StyleBoxFlat> style_widget_scroll_container = p_config.button_style_focus->duplicate();
1891-
// Make the focus outline appear to be flush with the buttons it's focusing, so not draw on top of the content.
1892-
style_widget_scroll_container->set_expand_margin_all(4);
18931891
p_theme->set_stylebox("focus", "ScrollContainer", style_widget_scroll_container);
18941892

18951893
// This stylebox is used in 3d and 2d viewports (no borders).
@@ -2241,6 +2239,12 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme
22412239

22422240
// Editor inspector.
22432241
{
2242+
// Panel.
2243+
Ref<StyleBoxFlat> editor_inspector_panel = p_config.tree_panel_style->duplicate();
2244+
editor_inspector_panel->set_border_width_all(0);
2245+
editor_inspector_panel->set_content_margin_all(0);
2246+
p_theme->set_stylebox(SceneStringName(panel), "EditorInspector", editor_inspector_panel);
2247+
22442248
// Vertical separation between inspector categories and sections.
22452249
p_theme->set_constant("v_separation", "EditorInspector", 0);
22462250

scene/gui/scroll_container.cpp

Lines changed: 89 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "scroll_container.h"
3232

3333
#include "core/config/project_settings.h"
34+
#include "scene/gui/panel_container.h"
3435
#include "scene/main/window.h"
3536
#include "scene/theme/theme_db.h"
3637

@@ -44,7 +45,7 @@ Size2 ScrollContainer::get_minimum_size() const {
4445
if (!c) {
4546
continue;
4647
}
47-
if (c == h_scroll || c == v_scroll) {
48+
if (c == h_scroll || c == v_scroll || c == focus_panel) {
4849
continue;
4950
}
5051

@@ -72,7 +73,16 @@ Size2 ScrollContainer::get_minimum_size() const {
7273
}
7374
}
7475

75-
min_size += theme_cache.panel_style->get_minimum_size();
76+
Size2 panel_size = theme_cache.panel_style->get_minimum_size();
77+
min_size += panel_size;
78+
if (draw_focus_border) {
79+
Size2 focus_size = theme_cache.focus_style->get_minimum_size();
80+
// Only update the minimum size if the focus style's minimum size doesn't fit into the panel style's minimum size.
81+
if (focus_size > panel_size) {
82+
min_size += focus_size - panel_size;
83+
}
84+
}
85+
7686
return min_size;
7787
}
7888

@@ -258,21 +268,45 @@ void ScrollContainer::_update_scrollbar_position() {
258268
return;
259269
}
260270

271+
float right_margin = theme_cache.panel_style->get_margin(SIDE_RIGHT);
272+
float left_margin = theme_cache.panel_style->get_margin(SIDE_LEFT);
273+
float top_margin = theme_cache.panel_style->get_margin(SIDE_TOP);
274+
float bottom_margin = theme_cache.panel_style->get_margin(SIDE_BOTTOM);
275+
if (draw_focus_border) {
276+
// Only update margins if the focus style's margins don't fit into the panel style's margins.
277+
float focus_margin = theme_cache.focus_style->get_margin(SIDE_RIGHT);
278+
if (focus_margin > right_margin) {
279+
right_margin += focus_margin;
280+
}
281+
focus_margin = theme_cache.focus_style->get_margin(SIDE_LEFT);
282+
if (focus_margin > left_margin) {
283+
left_margin += focus_margin;
284+
}
285+
focus_margin = theme_cache.focus_style->get_margin(SIDE_TOP);
286+
if (focus_margin > top_margin) {
287+
top_margin += focus_margin;
288+
}
289+
focus_margin = theme_cache.focus_style->get_margin(SIDE_BOTTOM);
290+
if (focus_margin > bottom_margin) {
291+
bottom_margin += focus_margin;
292+
}
293+
}
294+
261295
Size2 hmin = h_scroll->is_visible() ? h_scroll->get_combined_minimum_size() : Size2();
262296
Size2 vmin = v_scroll->is_visible() ? v_scroll->get_combined_minimum_size() : Size2();
263297

264-
int lmar = is_layout_rtl() ? theme_cache.panel_style->get_margin(SIDE_RIGHT) : theme_cache.panel_style->get_margin(SIDE_LEFT);
265-
int rmar = is_layout_rtl() ? theme_cache.panel_style->get_margin(SIDE_LEFT) : theme_cache.panel_style->get_margin(SIDE_RIGHT);
298+
int lmar = is_layout_rtl() ? right_margin : left_margin;
299+
int rmar = is_layout_rtl() ? left_margin : right_margin;
266300

267301
h_scroll->set_anchor_and_offset(SIDE_LEFT, ANCHOR_BEGIN, lmar);
268302
h_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, -rmar - vmin.width);
269-
h_scroll->set_anchor_and_offset(SIDE_TOP, ANCHOR_END, -hmin.height - theme_cache.panel_style->get_margin(SIDE_BOTTOM));
270-
h_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -theme_cache.panel_style->get_margin(SIDE_BOTTOM));
303+
h_scroll->set_anchor_and_offset(SIDE_TOP, ANCHOR_END, -hmin.height - bottom_margin);
304+
h_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -bottom_margin);
271305

272306
v_scroll->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -vmin.width - rmar);
273307
v_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, -rmar);
274-
v_scroll->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, theme_cache.panel_style->get_margin(SIDE_TOP));
275-
v_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -hmin.height - theme_cache.panel_style->get_margin(SIDE_BOTTOM));
308+
v_scroll->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, top_margin);
309+
v_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -hmin.height - bottom_margin);
276310

277311
_updating_scrollbars = false;
278312
}
@@ -313,8 +347,22 @@ void ScrollContainer::_reposition_children() {
313347
Size2 size = get_size();
314348
Point2 ofs;
315349

316-
size -= theme_cache.panel_style->get_minimum_size();
317-
ofs += theme_cache.panel_style->get_offset();
350+
Size2 panel_size = theme_cache.panel_style->get_minimum_size();
351+
Point2 panel_offset = theme_cache.panel_style->get_offset();
352+
size -= panel_size;
353+
ofs += panel_offset;
354+
if (draw_focus_border) {
355+
// Only update the size and offset if focus style's doesn't fit into the panel style's.
356+
Size2 focus_size = theme_cache.focus_style->get_minimum_size();
357+
if (focus_size > panel_size) {
358+
size -= focus_size - panel_size;
359+
}
360+
Point2 focus_offset = theme_cache.focus_style->get_offset();
361+
if (focus_offset > panel_offset) {
362+
ofs += focus_offset - panel_offset;
363+
}
364+
}
365+
318366
bool rtl = is_layout_rtl();
319367

320368
if (_is_h_scroll_visible() || horizontal_scroll_mode == SCROLL_MODE_RESERVE) {
@@ -330,7 +378,7 @@ void ScrollContainer::_reposition_children() {
330378
if (!c) {
331379
continue;
332380
}
333-
if (c == h_scroll || c == v_scroll) {
381+
if (c == h_scroll || c == v_scroll || c == focus_panel) {
334382
continue;
335383
}
336384
Size2 minsize = c->get_combined_minimum_size();
@@ -350,6 +398,9 @@ void ScrollContainer::_reposition_children() {
350398
fit_child_in_rect(c, r);
351399
}
352400

401+
if (draw_focus_border) {
402+
focus_panel->set_size(get_size());
403+
}
353404
queue_redraw();
354405
}
355406

@@ -399,6 +450,7 @@ void ScrollContainer::_notification(int p_what) {
399450
if (p_what == NOTIFICATION_THEME_CHANGED) {
400451
scroll_border = get_theme_constant(SNAME("scroll_border"), SNAME("Tree"));
401452
scroll_speed = get_theme_constant(SNAME("scroll_speed"), SNAME("Tree"));
453+
focus_panel->add_theme_style_override("panel", theme_cache.focus_style);
402454
}
403455
} break;
404456

@@ -415,15 +467,8 @@ void ScrollContainer::_notification(int p_what) {
415467

416468
case NOTIFICATION_DRAW: {
417469
draw_style_box(theme_cache.panel_style, Rect2(Vector2(), get_size()));
418-
if (draw_focus_border && (has_focus() || child_has_focus())) {
419-
RID ci = get_canvas_item();
420-
RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, true);
421-
draw_style_box(theme_cache.focus_style, Rect2(Point2(), get_size()));
422-
RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, false);
423-
focus_border_is_drawn = true;
424-
} else {
425-
focus_border_is_drawn = false;
426-
}
470+
focus_border_is_drawn = draw_focus_border && (has_focus() || child_has_focus());
471+
focus_panel->set_visible(focus_border_is_drawn);
427472
} break;
428473

429474
case NOTIFICATION_DRAG_BEGIN: {
@@ -533,7 +578,15 @@ void ScrollContainer::_notification(int p_what) {
533578

534579
void ScrollContainer::update_scrollbars() {
535580
Size2 size = get_size();
536-
size -= theme_cache.panel_style->get_minimum_size();
581+
Size2 panel_size = theme_cache.panel_style->get_minimum_size();
582+
size -= panel_size;
583+
if (draw_focus_border) {
584+
Size2 focus_size = theme_cache.focus_style->get_minimum_size();
585+
// Only update the size if the focus style's minimum size doesn't fit into the panel style's minimum size.
586+
if (focus_size > panel_size) {
587+
size -= focus_size - panel_size;
588+
}
589+
}
537590

538591
Size2 hmin = h_scroll->get_combined_minimum_size();
539592
Size2 vmin = v_scroll->get_combined_minimum_size();
@@ -644,7 +697,7 @@ PackedStringArray ScrollContainer::get_configuration_warnings() const {
644697
if (!c) {
645698
continue;
646699
}
647-
if (c == h_scroll || c == v_scroll) {
700+
if (c == h_scroll || c == v_scroll || c == focus_panel) {
648701
continue;
649702
}
650703

@@ -734,7 +787,9 @@ void ScrollContainer::set_draw_focus_border(bool p_draw) {
734787
return;
735788
}
736789
draw_focus_border = p_draw;
737-
queue_redraw();
790+
if (is_ready()) {
791+
_reposition_children();
792+
}
738793
}
739794

740795
bool ScrollContainer::get_draw_focus_border() {
@@ -757,6 +812,17 @@ ScrollContainer::ScrollContainer() {
757812
add_child(v_scroll, false, INTERNAL_MODE_BACK);
758813
v_scroll->connect(SceneStringName(value_changed), callable_mp(this, &ScrollContainer::_scroll_moved));
759814

815+
// We need to use a PanelContainer for the focus style instead of just drawing it directly with RenderingService
816+
// due to a clippling issues. The Control that is being scrolled will be over the focus border because both will be
817+
// drawn on the same CanvasItem. If we decide to ignore clipping, the focus border will be drawn even over other
818+
// CanvasItems.
819+
focus_panel = memnew(PanelContainer);
820+
focus_panel->set_name("_focus");
821+
focus_panel->set_mouse_filter(MOUSE_FILTER_IGNORE);
822+
focus_panel->set_focus_mode(FOCUS_NONE);
823+
focus_panel->set_visible(draw_focus_border);
824+
add_child(focus_panel, false, INTERNAL_MODE_BACK);
825+
760826
deadzone = GLOBAL_GET("gui/common/default_scroll_deadzone");
761827

762828
set_clip_contents(true);

scene/gui/scroll_container.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434

3535
#include "scroll_bar.h"
3636

37+
class PanelContainer;
38+
3739
class ScrollContainer : public Container {
3840
GDCLASS(ScrollContainer, Container);
3941

@@ -49,6 +51,7 @@ class ScrollContainer : public Container {
4951
private:
5052
HScrollBar *h_scroll = nullptr;
5153
VScrollBar *v_scroll = nullptr;
54+
PanelContainer *focus_panel = nullptr;
5255

5356
mutable Size2 largest_child_min_size; // The largest one among the min sizes of all available child controls.
5457

0 commit comments

Comments
 (0)