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
534579void 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
740795bool 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 );
0 commit comments