@@ -360,6 +360,45 @@ void ScrollContainer::_reposition_children() {
360360 size.x -= v_scroll->get_minimum_size ().x ;
361361 }
362362
363+ float viewport_w = size.x ;
364+ float viewport_h = size.y ;
365+
366+ float total_content_w = 0 .0f ;
367+ float total_content_h = 0 .0f ;
368+ for (int ci = 0 ; ci < get_child_count (); ci++) {
369+ Control *cc = as_sortable_control (get_child (ci));
370+ if (!cc || cc == h_scroll || cc == v_scroll || cc == focus_panel) {
371+ continue ;
372+ }
373+ Size2 ms = cc->get_combined_minimum_size ();
374+ float child_w = ms.x ;
375+ float child_h = ms.y ;
376+ if (cc->get_h_size_flags ().has_flag (SIZE_EXPAND)) {
377+ child_w = MAX (viewport_w, ms.x );
378+ }
379+ if (cc->get_v_size_flags ().has_flag (SIZE_EXPAND)) {
380+ child_h = MAX (viewport_h, ms.y );
381+ }
382+ total_content_w = MAX (total_content_w, child_w);
383+ total_content_h += child_h;
384+ }
385+
386+ float max_scroll_x = total_content_w > viewport_w ? (total_content_w - viewport_w) : 0 .0f ;
387+ float max_scroll_y = total_content_h > viewport_h ? (total_content_h - viewport_h) : 0 .0f ;
388+ float scroll_x = h_scroll ? CLAMP (h_scroll->get_value (), 0 .0f , max_scroll_x) : 0 .0f ;
389+ float scroll_y = v_scroll ? CLAMP (v_scroll->get_value (), 0 .0f , max_scroll_y) : 0 .0f ;
390+
391+ float group_v_offset = 0 .0f ;
392+ if (max_scroll_y <= 0 .0f && total_content_h < viewport_h) {
393+ float extra = viewport_h - total_content_h;
394+ if (vertical_content_align == CONTENT_V_ALIGN_CENTER) {
395+ group_v_offset = Math::floor (extra * 0 .5f );
396+ } else if (vertical_content_align == CONTENT_V_ALIGN_BOTTOM) {
397+ group_v_offset = Math::floor (extra);
398+ }
399+ }
400+ ofs.y += group_v_offset;
401+
363402 for (int i = 0 ; i < get_child_count (); i++) {
364403 Control *c = as_sortable_control (get_child (i));
365404 if (!c) {
@@ -370,18 +409,44 @@ void ScrollContainer::_reposition_children() {
370409 }
371410 Size2 minsize = c->get_combined_minimum_size ();
372411
373- Rect2 r = Rect2 (- Size2 ( get_h_scroll (), get_v_scroll ()) , minsize);
412+ Rect2 r = Rect2 (ofs , minsize);
374413 if (c->get_h_size_flags ().has_flag (SIZE_EXPAND)) {
375414 r.size .width = MAX (size.width , minsize.width );
376415 }
377416 if (c->get_v_size_flags ().has_flag (SIZE_EXPAND)) {
378417 r.size .height = MAX (size.height , minsize.height );
379418 }
380- r.position += ofs;
381419 if (rtl && reserve_vscroll) {
382420 r.position .x += v_scroll->get_minimum_size ().x ;
383421 }
384422 r.position = r.position .floor ();
423+
424+ {
425+ float content_w = r.size .width ;
426+ float viewport_w_local = viewport_w;
427+ ContentHAlign align_h = horizontal_content_align;
428+ if (is_layout_rtl ()) {
429+ if (align_h == CONTENT_H_ALIGN_LEFT) {
430+ align_h = CONTENT_H_ALIGN_RIGHT;
431+ } else if (align_h == CONTENT_H_ALIGN_RIGHT) {
432+ align_h = CONTENT_H_ALIGN_LEFT;
433+ }
434+ }
435+ if (max_scroll_x <= 0 .0f && content_w < viewport_w_local) {
436+ float extra = viewport_w_local - content_w;
437+ if (align_h == CONTENT_H_ALIGN_CENTER) {
438+ r.position .x += Math::floor (extra * 0 .5f );
439+ } else if (align_h == CONTENT_H_ALIGN_RIGHT) {
440+ r.position .x += Math::floor (extra);
441+ }
442+ }
443+ }
444+
445+ r.position .x -= scroll_x;
446+ r.position .y -= scroll_y;
447+
448+ r.position = r.position .floor ();
449+
385450 fit_child_in_rect (c, r);
386451 }
387452
@@ -752,12 +817,21 @@ void ScrollContainer::_bind_methods() {
752817 ClassDB::bind_method (D_METHOD (" set_draw_focus_border" , " draw" ), &ScrollContainer::set_draw_focus_border);
753818 ClassDB::bind_method (D_METHOD (" get_draw_focus_border" ), &ScrollContainer::get_draw_focus_border);
754819
820+ ClassDB::bind_method (D_METHOD (" set_horizontal_content_align" , " alignment" ), &ScrollContainer::set_horizontal_content_align);
821+ ClassDB::bind_method (D_METHOD (" get_horizontal_content_align" ), &ScrollContainer::get_horizontal_content_align);
822+
823+ ClassDB::bind_method (D_METHOD (" set_vertical_content_align" , " alignment" ), &ScrollContainer::set_vertical_content_align);
824+ ClassDB::bind_method (D_METHOD (" get_vertical_content_align" ), &ScrollContainer::get_vertical_content_align);
825+
755826 ADD_SIGNAL (MethodInfo (" scroll_started" ));
756827 ADD_SIGNAL (MethodInfo (" scroll_ended" ));
757828
758829 ADD_PROPERTY (PropertyInfo (Variant::BOOL, " follow_focus" ), " set_follow_focus" , " is_following_focus" );
759830 ADD_PROPERTY (PropertyInfo (Variant::BOOL, " draw_focus_border" ), " set_draw_focus_border" , " get_draw_focus_border" );
760831
832+ ADD_PROPERTY (PropertyInfo (Variant::INT, " horizontal_content_align" , PROPERTY_HINT_ENUM, " Left,Center,Right" ), " set_horizontal_content_align" , " get_horizontal_content_align" );
833+ ADD_PROPERTY (PropertyInfo (Variant::INT, " vertical_content_align" , PROPERTY_HINT_ENUM, " Top,Center,Bottom" ), " set_vertical_content_align" , " get_vertical_content_align" );
834+
761835 ADD_GROUP (" Scroll" , " scroll_" );
762836 ADD_PROPERTY (PropertyInfo (Variant::INT, " scroll_horizontal" , PROPERTY_HINT_NONE, " suffix:px" ), " set_h_scroll" , " get_h_scroll" );
763837 ADD_PROPERTY (PropertyInfo (Variant::INT, " scroll_vertical" , PROPERTY_HINT_NONE, " suffix:px" ), " set_v_scroll" , " get_v_scroll" );
@@ -773,6 +847,14 @@ void ScrollContainer::_bind_methods() {
773847 BIND_ENUM_CONSTANT (SCROLL_MODE_SHOW_NEVER);
774848 BIND_ENUM_CONSTANT (SCROLL_MODE_RESERVE);
775849
850+ BIND_ENUM_CONSTANT (CONTENT_H_ALIGN_LEFT);
851+ BIND_ENUM_CONSTANT (CONTENT_H_ALIGN_CENTER);
852+ BIND_ENUM_CONSTANT (CONTENT_H_ALIGN_RIGHT);
853+
854+ BIND_ENUM_CONSTANT (CONTENT_V_ALIGN_TOP);
855+ BIND_ENUM_CONSTANT (CONTENT_V_ALIGN_CENTER);
856+ BIND_ENUM_CONSTANT (CONTENT_V_ALIGN_BOTTOM);
857+
776858 BIND_THEME_ITEM_CUSTOM (Theme::DATA_TYPE_STYLEBOX, ScrollContainer, panel_style, " panel" );
777859 BIND_THEME_ITEM_CUSTOM (Theme::DATA_TYPE_STYLEBOX, ScrollContainer, focus_style, " focus" );
778860
@@ -824,3 +906,29 @@ ScrollContainer::ScrollContainer() {
824906
825907 set_clip_contents (true );
826908}
909+
910+ void ScrollContainer::set_horizontal_content_align (ContentHAlign p_align) {
911+ ERR_FAIL_INDEX (p_align, CONTENT_H_ALIGN_MAX);
912+ ContentHAlign new_align = static_cast <ContentHAlign>(p_align);
913+ if (horizontal_content_align != new_align) {
914+ horizontal_content_align = new_align;
915+ queue_sort ();
916+ }
917+ }
918+
919+ ScrollContainer::ContentHAlign ScrollContainer::get_horizontal_content_align () const {
920+ return horizontal_content_align;
921+ }
922+
923+ void ScrollContainer::set_vertical_content_align (ContentVAlign p_align) {
924+ ERR_FAIL_INDEX (p_align, CONTENT_V_ALIGN_MAX);
925+ ContentVAlign new_align = static_cast <ContentVAlign>(p_align);
926+ if (vertical_content_align != new_align) {
927+ vertical_content_align = new_align;
928+ queue_sort ();
929+ }
930+ }
931+
932+ ScrollContainer::ContentVAlign ScrollContainer::get_vertical_content_align () const {
933+ return vertical_content_align;
934+ }
0 commit comments