@@ -1309,6 +1309,24 @@ public override void PaintDOM(CharacterBuffer buffer, LayoutRect bounds, LayoutR
13091309
13101310 List < IWindowControl > paintSnapshot ;
13111311 lock ( _childrenLock ) { paintSnapshot = new List < IWindowControl > ( _children ) ; }
1312+
1313+ // Two-pass: measure non-Fill children first to determine remaining space for Fill children.
1314+ int fixedHeight = 0 ;
1315+ if ( _viewportHeight > 0 )
1316+ {
1317+ foreach ( var child in paintSnapshot )
1318+ {
1319+ if ( ! child . Visible || child . VerticalAlignment == VerticalAlignment . Fill ) continue ;
1320+ var node = LayoutNodeFactory . CreateSubtree ( child ) ;
1321+ node . IsVisible = true ;
1322+ node . Measure ( new LayoutConstraints ( 1 , contentWidth , 1 , int . MaxValue ) ) ;
1323+ fixedHeight += node . DesiredSize . Height ;
1324+ }
1325+ }
1326+ int fillCount = paintSnapshot . Count ( c => c . Visible && c . VerticalAlignment == VerticalAlignment . Fill ) ;
1327+ int perFillHeight = ( _viewportHeight > 0 && fillCount > 0 )
1328+ ? Math . Max ( 0 , ( _viewportHeight - fixedHeight ) / fillCount ) : _viewportHeight ;
1329+
13121330 foreach ( var child in paintSnapshot )
13131331 {
13141332 if ( ! child . Visible ) continue ;
@@ -1318,10 +1336,10 @@ public override void PaintDOM(CharacterBuffer buffer, LayoutRect bounds, LayoutR
13181336 childNode . IsVisible = true ;
13191337
13201338 // Measure using full layout pipeline.
1321- // Fill-aligned children: cap to viewport so they fill the visible area .
1339+ // Fill-aligned children: get remaining space after fixed children .
13221340 // Content-sized children: measure unbounded for correct scroll positioning.
13231341 int maxChildHeight = ( _viewportHeight > 0 && child . VerticalAlignment == VerticalAlignment . Fill )
1324- ? _viewportHeight : int . MaxValue ;
1342+ ? perFillHeight : int . MaxValue ;
13251343 var constraints = new LayoutConstraints ( 1 , contentWidth , 1 , maxChildHeight ) ;
13261344 childNode . Measure ( constraints ) ;
13271345 int childHeight = childNode . DesiredSize . Height ;
@@ -1457,18 +1475,36 @@ private int CalculateContentHeight(int viewportWidth, int maxHeight = 0)
14571475 availableWidth = Math . Max ( 1 , viewportWidth - 1 ) ;
14581476 }
14591477
1460- int totalHeight = 0 ;
14611478 List < IWindowControl > calcSnapshot ;
14621479 lock ( _childrenLock ) { calcSnapshot = new List < IWindowControl > ( _children ) ; }
1463- foreach ( var child in calcSnapshot . Where ( c => c . Visible ) )
1480+ var visible = calcSnapshot . Where ( c => c . Visible ) . ToList ( ) ;
1481+
1482+ // Two-pass measurement: fixed children first, then Fill children get remaining space.
1483+ // Pass 1: measure non-Fill children to determine fixed height.
1484+ int fixedHeight = 0 ;
1485+ foreach ( var child in visible )
1486+ {
1487+ if ( child . VerticalAlignment == VerticalAlignment . Fill ) continue ;
1488+ var childNode = LayoutNodeFactory . CreateSubtree ( child ) ;
1489+ childNode . IsVisible = true ;
1490+ var constraints = new LayoutConstraints ( 1 , availableWidth , 1 , int . MaxValue ) ;
1491+ childNode . Measure ( constraints ) ;
1492+ fixedHeight += childNode . DesiredSize . Height ;
1493+ }
1494+
1495+ // Pass 2: measure Fill children with remaining space.
1496+ int fillCount = visible . Count ( c => c . VerticalAlignment == VerticalAlignment . Fill ) ;
1497+ int remainingHeight = ( maxH < int . MaxValue ) ? Math . Max ( 0 , maxH - fixedHeight ) : int . MaxValue ;
1498+ int perFillHeight = ( fillCount > 0 && remainingHeight < int . MaxValue )
1499+ ? Math . Max ( 0 , remainingHeight / fillCount ) : int . MaxValue ;
1500+
1501+ int totalHeight = fixedHeight ;
1502+ foreach ( var child in visible )
14641503 {
1504+ if ( child . VerticalAlignment != VerticalAlignment . Fill ) continue ;
14651505 var childNode = LayoutNodeFactory . CreateSubtree ( child ) ;
14661506 childNode . IsVisible = true ;
1467- // Fill-aligned children: measure with viewport constraint so they fill the visible area.
1468- // Content-sized children: measure unbounded to get natural height for scroll range.
1469- int childMaxH = ( child . VerticalAlignment == VerticalAlignment . Fill && maxH < int . MaxValue )
1470- ? maxH : int . MaxValue ;
1471- var constraints = new LayoutConstraints ( 1 , availableWidth , 1 , childMaxH ) ;
1507+ var constraints = new LayoutConstraints ( 1 , availableWidth , 1 , perFillHeight ) ;
14721508 childNode . Measure ( constraints ) ;
14731509 totalHeight += childNode . DesiredSize . Height ;
14741510 }
0 commit comments