3232
3333#include " core/config/project_settings.h"
3434#include " scene/gui/panel_container.h"
35+ #include " scene/gui/texture_rect.h"
3536#include " scene/main/window.h"
3637#include " scene/theme/theme_db.h"
3738
@@ -343,6 +344,7 @@ void ScrollContainer::ensure_control_visible(Control *p_control) {
343344
344345void ScrollContainer::_reposition_children () {
345346 update_scrollbars ();
347+ update_scroll_hints ();
346348
347349 Rect2 margins = _get_margins ();
348350 Size2 size = get_size ();
@@ -362,10 +364,7 @@ void ScrollContainer::_reposition_children() {
362364
363365 for (int i = 0 ; i < get_child_count (); i++) {
364366 Control *c = as_sortable_control (get_child (i));
365- if (!c) {
366- continue ;
367- }
368- if (c == h_scroll || c == v_scroll || c == focus_panel) {
367+ if (!c || c->is_internal ()) {
369368 continue ;
370369 }
371370 Size2 minsize = c->get_combined_minimum_size ();
@@ -445,7 +444,10 @@ void ScrollContainer::_notification(int p_what) {
445444 DisplayServer::get_singleton ()->accessibility_update_add_action (ae, DisplayServer::AccessibilityAction::ACTION_SET_SCROLL_OFFSET, callable_mp (this , &ScrollContainer::_accessibility_action_scroll_set));
446445 } break ;
447446
448- case NOTIFICATION_THEME_CHANGED:
447+ case NOTIFICATION_THEME_CHANGED: {
448+ update_scroll_hints ();
449+ [[fallthrough]];
450+ }
449451 case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
450452 case NOTIFICATION_TRANSLATION_CHANGED: {
451453 _updating_scrollbars = true ;
@@ -602,6 +604,42 @@ void ScrollContainer::update_scrollbars() {
602604 callable_mp (this , &ScrollContainer::_update_scrollbar_position).call_deferred ();
603605}
604606
607+ void ScrollContainer::update_scroll_hints () {
608+ Size2 size = get_size ();
609+ Rect2 margins = _get_margins ();
610+ Size2 scroll_size = size - margins.position + margins.size ;
611+
612+ float v_scroll_value = v_scroll->get_value ();
613+ bool v_scroll_below_max = v_scroll_value < (largest_child_min_size.height - scroll_size.height - 1 );
614+ bool show_vertical_hints = v_scroll_value > 1 || v_scroll_below_max;
615+
616+ float h_scroll_value = h_scroll->get_value ();
617+ bool h_scroll_below_max = h_scroll_value < (largest_child_min_size.width - scroll_size.width - 1 );
618+ bool show_horizontal_hints = h_scroll_value > 1 || h_scroll_below_max;
619+
620+ if (show_vertical_hints) {
621+ scroll_hint_top_left->set_texture (theme_cache.scroll_hint_vertical );
622+ scroll_hint_top_left->set_offsets_preset (PRESET_TOP_WIDE, LayoutPresetMode::PRESET_MODE_MINSIZE);
623+ scroll_hint_top_left->set_visible (!show_horizontal_hints && (scroll_hint_mode == SCROLL_HINT_MODE_ALL || scroll_hint_mode == SCROLL_HINT_MODE_TOP_AND_LEFT) && v_scroll_value > 1 );
624+
625+ scroll_hint_bottom_right->set_flip_h (false );
626+ scroll_hint_bottom_right->set_flip_v (true );
627+ scroll_hint_bottom_right->set_texture (theme_cache.scroll_hint_vertical );
628+ scroll_hint_bottom_right->set_offsets_preset (PRESET_BOTTOM_WIDE, LayoutPresetMode::PRESET_MODE_MINSIZE);
629+ scroll_hint_bottom_right->set_visible (!show_horizontal_hints && (scroll_hint_mode == SCROLL_HINT_MODE_ALL || scroll_hint_mode == SCROLL_HINT_MODE_BOTTOM_AND_RIGHT) && v_scroll_below_max);
630+ } else {
631+ scroll_hint_top_left->set_texture (theme_cache.scroll_hint_horizontal );
632+ scroll_hint_top_left->set_offsets_preset (PRESET_LEFT_WIDE, LayoutPresetMode::PRESET_MODE_MINSIZE);
633+ scroll_hint_top_left->set_visible (!show_vertical_hints && (scroll_hint_mode == SCROLL_HINT_MODE_ALL || scroll_hint_mode == SCROLL_HINT_MODE_TOP_AND_LEFT) && h_scroll_value > 1 );
634+
635+ scroll_hint_bottom_right->set_flip_h (true );
636+ scroll_hint_bottom_right->set_flip_v (false );
637+ scroll_hint_bottom_right->set_texture (theme_cache.scroll_hint_horizontal );
638+ scroll_hint_bottom_right->set_offsets_preset (PRESET_RIGHT_WIDE, LayoutPresetMode::PRESET_MODE_MINSIZE);
639+ scroll_hint_bottom_right->set_visible (!show_vertical_hints && (scroll_hint_mode == SCROLL_HINT_MODE_ALL || scroll_hint_mode == SCROLL_HINT_MODE_BOTTOM_AND_RIGHT) && h_scroll_below_max);
640+ }
641+ }
642+
605643void ScrollContainer::_scroll_moved (float ) {
606644 queue_sort ();
607645}
@@ -676,6 +714,32 @@ void ScrollContainer::set_deadzone(int p_deadzone) {
676714 deadzone = p_deadzone;
677715}
678716
717+ void ScrollContainer::set_scroll_hint_mode (ScrollHintMode p_mode) {
718+ ScrollHintMode prev_mode = scroll_hint_mode;
719+ scroll_hint_mode = p_mode;
720+
721+ if (scroll_hint_mode != prev_mode) {
722+ queue_redraw ();
723+ }
724+ }
725+
726+ ScrollContainer::ScrollHintMode ScrollContainer::get_scroll_hint_mode () const {
727+ return scroll_hint_mode;
728+ }
729+
730+ void ScrollContainer::set_tile_scroll_hint (bool p_enable) {
731+ bool prev_tile = tile_scroll_hint;
732+ tile_scroll_hint = p_enable;
733+
734+ if (tile_scroll_hint != prev_tile) {
735+ queue_redraw ();
736+ }
737+ }
738+
739+ bool ScrollContainer::is_scroll_hint_tiled () {
740+ return tile_scroll_hint;
741+ }
742+
679743bool ScrollContainer::is_following_focus () const {
680744 return follow_focus;
681745}
@@ -742,6 +806,12 @@ void ScrollContainer::_bind_methods() {
742806 ClassDB::bind_method (D_METHOD (" set_deadzone" , " deadzone" ), &ScrollContainer::set_deadzone);
743807 ClassDB::bind_method (D_METHOD (" get_deadzone" ), &ScrollContainer::get_deadzone);
744808
809+ ClassDB::bind_method (D_METHOD (" set_scroll_hint_mode" , " scroll_hint_mode" ), &ScrollContainer::set_scroll_hint_mode);
810+ ClassDB::bind_method (D_METHOD (" get_scroll_hint_mode" ), &ScrollContainer::get_scroll_hint_mode);
811+
812+ ClassDB::bind_method (D_METHOD (" set_tile_scroll_hint" , " tile_scroll_hint" ), &ScrollContainer::set_tile_scroll_hint);
813+ ClassDB::bind_method (D_METHOD (" is_scroll_hint_tiled" ), &ScrollContainer::is_scroll_hint_tiled);
814+
745815 ClassDB::bind_method (D_METHOD (" set_follow_focus" , " enabled" ), &ScrollContainer::set_follow_focus);
746816 ClassDB::bind_method (D_METHOD (" is_following_focus" ), &ScrollContainer::is_following_focus);
747817
@@ -758,7 +828,7 @@ void ScrollContainer::_bind_methods() {
758828 ADD_PROPERTY (PropertyInfo (Variant::BOOL, " follow_focus" ), " set_follow_focus" , " is_following_focus" );
759829 ADD_PROPERTY (PropertyInfo (Variant::BOOL, " draw_focus_border" ), " set_draw_focus_border" , " get_draw_focus_border" );
760830
761- ADD_GROUP (" Scroll " , " scroll_ " );
831+ ADD_GROUP (" Scrollbar " , " " );
762832 ADD_PROPERTY (PropertyInfo (Variant::INT, " scroll_horizontal" , PROPERTY_HINT_NONE, " suffix:px" ), " set_h_scroll" , " get_h_scroll" );
763833 ADD_PROPERTY (PropertyInfo (Variant::INT, " scroll_vertical" , PROPERTY_HINT_NONE, " suffix:px" ), " set_v_scroll" , " get_v_scroll" );
764834 ADD_PROPERTY (PropertyInfo (Variant::FLOAT, " scroll_horizontal_custom_step" , PROPERTY_HINT_RANGE, " -1,4096,suffix:px" ), " set_horizontal_custom_step" , " get_horizontal_custom_step" );
@@ -767,18 +837,30 @@ void ScrollContainer::_bind_methods() {
767837 ADD_PROPERTY (PropertyInfo (Variant::INT, " vertical_scroll_mode" , PROPERTY_HINT_ENUM, " Disabled,Auto,Always Show,Never Show,Reserve" ), " set_vertical_scroll_mode" , " get_vertical_scroll_mode" );
768838 ADD_PROPERTY (PropertyInfo (Variant::INT, " scroll_deadzone" ), " set_deadzone" , " get_deadzone" );
769839
840+ ADD_GROUP (" Scroll Hint" , " " );
841+ ADD_PROPERTY (PropertyInfo (Variant::INT, " scroll_hint_mode" , PROPERTY_HINT_ENUM, " Disabled,All,Top and Left,Bottom and Right" ), " set_scroll_hint_mode" , " get_scroll_hint_mode" );
842+ ADD_PROPERTY (PropertyInfo (Variant::BOOL, " tile_scroll_hint" ), " set_tile_scroll_hint" , " is_scroll_hint_tiled" );
843+
770844 BIND_ENUM_CONSTANT (SCROLL_MODE_DISABLED);
771845 BIND_ENUM_CONSTANT (SCROLL_MODE_AUTO);
772846 BIND_ENUM_CONSTANT (SCROLL_MODE_SHOW_ALWAYS);
773847 BIND_ENUM_CONSTANT (SCROLL_MODE_SHOW_NEVER);
774848 BIND_ENUM_CONSTANT (SCROLL_MODE_RESERVE);
775849
850+ BIND_ENUM_CONSTANT (SCROLL_HINT_MODE_DISABLED);
851+ BIND_ENUM_CONSTANT (SCROLL_HINT_MODE_ALL);
852+ BIND_ENUM_CONSTANT (SCROLL_HINT_MODE_TOP_AND_LEFT);
853+ BIND_ENUM_CONSTANT (SCROLL_HINT_MODE_BOTTOM_AND_RIGHT);
854+
776855 BIND_THEME_ITEM (Theme::DATA_TYPE_CONSTANT, ScrollContainer, scrollbar_h_separation);
777856 BIND_THEME_ITEM (Theme::DATA_TYPE_CONSTANT, ScrollContainer, scrollbar_v_separation);
778857
779858 BIND_THEME_ITEM_CUSTOM (Theme::DATA_TYPE_STYLEBOX, ScrollContainer, panel_style, " panel" );
780859 BIND_THEME_ITEM_CUSTOM (Theme::DATA_TYPE_STYLEBOX, ScrollContainer, focus_style, " focus" );
781860
861+ BIND_THEME_ITEM (Theme::DATA_TYPE_ICON, ScrollContainer, scroll_hint_vertical);
862+ BIND_THEME_ITEM (Theme::DATA_TYPE_ICON, ScrollContainer, scroll_hint_horizontal);
863+
782864 GLOBAL_DEF (" gui/common/default_scroll_deadzone" , 0 );
783865}
784866
@@ -802,6 +884,16 @@ bool ScrollContainer::child_has_focus() {
802884}
803885
804886ScrollContainer::ScrollContainer () {
887+ scroll_hint_top_left = memnew (TextureRect);
888+ scroll_hint_top_left->set_mouse_filter (MOUSE_FILTER_IGNORE);
889+ scroll_hint_top_left->hide ();
890+ add_child (scroll_hint_top_left, false , INTERNAL_MODE_BACK);
891+
892+ scroll_hint_bottom_right = memnew (TextureRect);
893+ scroll_hint_bottom_right->set_mouse_filter (MOUSE_FILTER_IGNORE);
894+ scroll_hint_bottom_right->hide ();
895+ add_child (scroll_hint_bottom_right, false , INTERNAL_MODE_BACK);
896+
805897 h_scroll = memnew (HScrollBar);
806898 h_scroll->set_name (" _h_scroll" );
807899 add_child (h_scroll, false , INTERNAL_MODE_BACK);
0 commit comments