Browse Source

base: compute scroll gutter

mattias 4 months ago
parent
commit
ffdb99d302
2 changed files with 200 additions and 65 deletions
  1. 26 28
      src/base/fresnel.dom.pas
  2. 174 37
      src/base/fresnel.layouter.pas

+ 26 - 28
src/base/fresnel.dom.pas

@@ -700,7 +700,7 @@ type
     function GetPlaceItems(El: TFresnelElement): string; virtual;
     function GetPlaceItems(El: TFresnelElement): string; virtual;
     function GetPlaceSelf(El: TFresnelElement): string; virtual;
     function GetPlaceSelf(El: TFresnelElement): string; virtual;
 
 
-    // get length
+    // get length for percentage values
     function GetLength_ContainerContentWidth(const aComp: TCSSResCompValue; El: TFresnelElement; NoChildren: boolean): TFresnelLength; virtual;
     function GetLength_ContainerContentWidth(const aComp: TCSSResCompValue; El: TFresnelElement; NoChildren: boolean): TFresnelLength; virtual;
     function GetLength_ContainerContentHeight(const aComp: TCSSResCompValue; El: TFresnelElement; NoChildren: boolean): TFresnelLength; virtual;
     function GetLength_ContainerContentHeight(const aComp: TCSSResCompValue; El: TFresnelElement; NoChildren: boolean): TFresnelLength; virtual;
     function GetLength_BorderWidth(const aComp: TCSSResCompValue; El: TFresnelElement; NoChildren: boolean): TFresnelLength; virtual;
     function GetLength_BorderWidth(const aComp: TCSSResCompValue; El: TFresnelElement; NoChildren: boolean): TFresnelLength; virtual;
@@ -1105,8 +1105,11 @@ type
     PaddingTop: TFresnelLength;
     PaddingTop: TFresnelLength;
     PaddingBottom: TFresnelLength;
     PaddingBottom: TFresnelLength;
     LineHeight: TFresnelLength;
     LineHeight: TFresnelLength;
-    ScrollBarVerticalVisible: boolean;
-    ScrollBarHorizontalVisible: boolean;
+    ScrollGutterBothEdges: boolean; // when scrollbar needs gutter space, add space it on both edges
+    ScrollGutterStable: boolean; // classic(not overlay) scrollbars need gutter if overflow is auto, scroll, or hidden, even if the box is not overflowing
+    ScrollGutterWidth: TCSSNumericalID; // 0, none, thin, auto, see attribute 'scrollbar-width'
+    CanScrollX: boolean; // overflow-x in hidden, scroll or auto
+    CanScrollY: boolean; // overflow-y in hidden, scroll or auto
 
 
     // attributes depending on position:
     // attributes depending on position:
     //  static: left, top, right, bottom are ignored
     //  static: left, top, right, bottom are ignored
@@ -1589,7 +1592,7 @@ type
     FDPI: array[boolean] of TFresnelLength;
     FDPI: array[boolean] of TFresnelLength;
     FScrollbarThinWidth: array[boolean] of TFresnelLength;
     FScrollbarThinWidth: array[boolean] of TFresnelLength;
     FScrollbarWidth: array[boolean] of TFresnelLength;
     FScrollbarWidth: array[boolean] of TFresnelLength;
-    FScrollbarStable: boolean;
+    FScrollbarOverlay: boolean;
     FHeight: TFresnelLength;
     FHeight: TFresnelLength;
     FWidth: TFresnelLength;
     FWidth: TFresnelLength;
     FFocusedElement : TFresnelElement;
     FFocusedElement : TFresnelElement;
@@ -1603,7 +1606,7 @@ type
     procedure Bubble(lElement: TFresnelElement; lEvt: TFresnelEvent);
     procedure Bubble(lElement: TFresnelElement; lEvt: TFresnelEvent);
     function GetDPI(IsHorizontal: boolean): TFresnelLength; override;
     function GetDPI(IsHorizontal: boolean): TFresnelLength; override;
     function GetHeight: TFresnelLength; virtual;
     function GetHeight: TFresnelLength; virtual;
-    function GetScrollbarsStable: boolean; virtual;
+    function GetScrollbarsOverlay: boolean; virtual;
     function GetScrollbarsThinWidth(IsHorizontal: boolean): TFresnelLength; virtual;
     function GetScrollbarsThinWidth(IsHorizontal: boolean): TFresnelLength; virtual;
     function GetScrollbarsWidth(IsHorizontal: boolean): TFresnelLength; virtual;
     function GetScrollbarsWidth(IsHorizontal: boolean): TFresnelLength; virtual;
     function GetVPLength(l: TFresnelViewportLength): TFresnelLength; virtual;
     function GetVPLength(l: TFresnelViewportLength): TFresnelLength; virtual;
@@ -1614,7 +1617,7 @@ type
     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
     procedure SetDPI(IsHorizontal: boolean; const AValue: TFresnelLength);
     procedure SetDPI(IsHorizontal: boolean; const AValue: TFresnelLength);
     procedure SetHeight(AValue: TFresnelLength); virtual;
     procedure SetHeight(AValue: TFresnelLength); virtual;
-    procedure SetScrollbarsStable(const AValue: boolean); virtual;
+    procedure SetScrollbarsOverlay(const AValue: boolean); virtual;
     procedure SetScrollbarsThinWidth(IsHorizontal: boolean; const AValue: TFresnelLength); virtual;
     procedure SetScrollbarsThinWidth(IsHorizontal: boolean; const AValue: TFresnelLength); virtual;
     procedure SetScrollbarsWidth(IsHorizontal: boolean; const AValue: TFresnelLength); virtual;
     procedure SetScrollbarsWidth(IsHorizontal: boolean; const AValue: TFresnelLength); virtual;
     procedure SetStylesheet(AValue: TStrings); virtual;
     procedure SetStylesheet(AValue: TStrings); virtual;
@@ -1699,7 +1702,7 @@ type
     function WSInput(WSData: TFresnelInputEventInit) : boolean; virtual;
     function WSInput(WSData: TFresnelInputEventInit) : boolean; virtual;
     property VPApplication: IFresnelVPApplication read FVPApplication;
     property VPApplication: IFresnelVPApplication read FVPApplication;
     property DPI[IsHorizontal: boolean]: TFresnelLength read GetDPI write SetDPI;
     property DPI[IsHorizontal: boolean]: TFresnelLength read GetDPI write SetDPI;
-    property ScrollbarsStable: boolean read GetScrollbarsStable write SetScrollbarsStable;
+    property ScrollbarsOverlay: boolean read GetScrollbarsOverlay write SetScrollbarsOverlay;
     property ScrollbarsWidth[IsHorizontal: boolean]: TFresnelLength read GetScrollbarsWidth write SetScrollbarsWidth;
     property ScrollbarsWidth[IsHorizontal: boolean]: TFresnelLength read GetScrollbarsWidth write SetScrollbarsWidth;
     property ScrollbarsThinWidth[IsHorizontal: boolean]: TFresnelLength read GetScrollbarsThinWidth write SetScrollbarsThinWidth;
     property ScrollbarsThinWidth[IsHorizontal: boolean]: TFresnelLength read GetScrollbarsThinWidth write SetScrollbarsThinWidth;
     property VPLength[l: TFresnelViewportLength]: TFresnelLength read GetVPLength write SetVPLength;
     property VPLength[l: TFresnelViewportLength]: TFresnelLength read GetVPLength write SetVPLength;
@@ -6424,26 +6427,20 @@ end;
 function TFresnelLayoutNode.FitWidth(aWidth: TFresnelLength): TFresnelLength;
 function TFresnelLayoutNode.FitWidth(aWidth: TFresnelLength): TFresnelLength;
 begin
 begin
   Result:=aWidth;
   Result:=aWidth;
-  if not IsNan(MinWidth) then
-  begin
-    if not IsNan(MaxWidth) then
-      Result:=MinWidth
-    else if (not IsNan(Result)) and (Result<MinWidth) then
-      Result:=MinWidth;
-  end else if (not IsNan(MaxWidth)) and (not IsNan(Result)) and (Result>MaxWidth) then
+  if IsNan(Result) then exit;
+  if (not IsNan(MinWidth)) and (Result<MinWidth) then
+    Result:=MinWidth
+  else if (not IsNan(MaxWidth)) and (Result>MaxWidth) then
     Result:=MaxWidth;
     Result:=MaxWidth;
 end;
 end;
 
 
 function TFresnelLayoutNode.FitHeight(aHeight: TFresnelLength): TFresnelLength;
 function TFresnelLayoutNode.FitHeight(aHeight: TFresnelLength): TFresnelLength;
 begin
 begin
   Result:=aHeight;
   Result:=aHeight;
-  if not IsNan(MinHeight) then
-  begin
-    if not IsNan(MaxHeight) then
-      Result:=MinHeight
-    else if (not IsNan(Result)) and (Result<MinHeight) then
-      Result:=MinHeight;
-  end else if (not IsNan(MaxHeight)) and (not IsNan(Result)) and (Result>MaxHeight) then
+  if IsNan(Result) then exit;
+  if (not IsNan(MinHeight)) and (Result<MinHeight) then
+    Result:=MinHeight
+  else if (not IsNan(MaxHeight)) and (Result>MaxHeight) then
     Result:=MaxHeight;
     Result:=MaxHeight;
 end;
 end;
 
 
@@ -6466,8 +6463,9 @@ begin
   PaddingTop:=0;
   PaddingTop:=0;
   PaddingBottom:=0;
   PaddingBottom:=0;
   LineHeight:=0;
   LineHeight:=0;
-  ScrollBarVerticalVisible:=false;
-  ScrollBarHorizontalVisible:=false;
+  ScrollGutterBothEdges:=false;
+  ScrollGutterStable:=false;
+  ScrollGutterWidth:=0;
 
 
   Left:=NaN;
   Left:=NaN;
   Top:=NaN;
   Top:=NaN;
@@ -6579,9 +6577,9 @@ begin
   Result:=FHeight;
   Result:=FHeight;
 end;
 end;
 
 
-function TFresnelViewport.GetScrollbarsStable: boolean;
+function TFresnelViewport.GetScrollbarsOverlay: boolean;
 begin
 begin
-  Result:=FScrollbarStable;
+  Result:=FScrollbarOverlay;
 end;
 end;
 
 
 function TFresnelViewport.GetVPLength(l: TFresnelViewportLength
 function TFresnelViewport.GetVPLength(l: TFresnelViewportLength
@@ -6751,10 +6749,10 @@ begin
   DomChanged;
   DomChanged;
 end;
 end;
 
 
-procedure TFresnelViewport.SetScrollbarsStable(const AValue: boolean);
+procedure TFresnelViewport.SetScrollbarsOverlay(const AValue: boolean);
 begin
 begin
-  if FScrollbarStable=AValue then exit;
-  FScrollbarStable:=AValue;
+  if FScrollbarOverlay=AValue then exit;
+  FScrollbarOverlay:=AValue;
   DomChanged;
   DomChanged;
 end;
 end;
 
 

+ 174 - 37
src/base/fresnel.layouter.pas

@@ -64,6 +64,9 @@ type
     procedure ApplyMinMaxHeight; virtual;
     procedure ApplyMinMaxHeight; virtual;
     procedure ApplyMinMaxWidth; virtual;
     procedure ApplyMinMaxWidth; virtual;
     procedure ComputeUsedLengths(NoChildren: boolean); virtual;
     procedure ComputeUsedLengths(NoChildren: boolean); virtual;
+    procedure ComputeScrollbarGutter; virtual; // compute attribute scrollbar-gutter
+    procedure ComputeScrollbarsNoChildren; virtual;
+    procedure AddScrollGutter(Horizontal: boolean);
     procedure DeductUsedLengths(NoChildren: boolean); virtual;
     procedure DeductUsedLengths(NoChildren: boolean); virtual;
     function GetIntrinsicContentSize(aMode: TFresnelLayoutMode; aMaxWidth: TFresnelLength=NaN;
     function GetIntrinsicContentSize(aMode: TFresnelLayoutMode; aMaxWidth: TFresnelLength=NaN;
       aMaxHeight: TFresnelLength=NaN): TFresnelPoint; override;
       aMaxHeight: TFresnelLength=NaN): TFresnelPoint; override;
@@ -244,20 +247,70 @@ end;
 
 
 procedure TFLNodeLayouter.Apply;
 procedure TFLNodeLayouter.Apply;
 var
 var
-  MaxWidth, MaxHeight: TFresnelLength;
+  MaxWidth, MaxHeight, Avail: TFresnelLength;
   Size: TFresnelPoint;
   Size: TFresnelPoint;
+  VP: TFresnelViewport;
+  NeedScrollX, NeedScrollY: Boolean;
+
+  procedure CheckScrollY;
+  begin
+    if not Node.CanScrollY then exit;
+    Avail:=Node.Height+Node.PaddingTop+Node.PaddingBottom-Node.ScrollGutterTop-Node.ScrollGutterBottom;
+    NeedScrollY:=(Avail<Size.Y);
+    if NeedScrollY and (not VP.ScrollbarsOverlay) and (Node.ScrollGutterRight=0) then
+      Node.AddScrollGutter(false);
+  end;
+
 begin
 begin
-  MaxWidth:=Node.Width;
-  if IsNan(MaxWidth) then
-    MaxWidth:=Node.MaxWidth;
-  MaxHeight:=Node.Height;
-  if IsNan(MaxHeight) then
-    MaxHeight:=Node.MaxWidth;
+  // get maximum width/height for content
+  if Node.CanScrollX then
+    MaxWidth:=NaN
+  else begin
+    MaxWidth:=Node.Width;
+    if IsNan(MaxWidth) then
+      MaxWidth:=Node.MaxWidth;
+  end;
+
+  if Node.CanScrollY then
+    MaxHeight:=NaN
+  else begin
+    MaxHeight:=Node.Height;
+    if IsNan(MaxHeight) then
+      MaxHeight:=Node.MaxWidth;
+  end;
+
+  // layout content and compute its size
+  //writeln('TFLNodeLayouter.Apply "',Node.Element.Name,'" CanScrollX=',Node.CanScrollX,' CanScrollY=',Node.CanScrollY,' MaxWidth=',FloatToCSSStr(MaxWidth),' MaxHeight=',FloatToCSSStr(MaxHeight));
   Size:=ComputeLayoutContent(flmMaxWidth,MaxWidth,MaxHeight,true);
   Size:=ComputeLayoutContent(flmMaxWidth,MaxWidth,MaxHeight,true);
   if IsNan(Node.Width) then
   if IsNan(Node.Width) then
-    Node.Width:=Size.X;
+    Node.Width:=Node.FitWidth(Size.X);
   if IsNan(Node.Height) then
   if IsNan(Node.Height) then
-    Node.Height:=Size.Y;
+    Node.Height:=Node.FitHeight(Size.Y);
+  Node.ScrollWidth:=Max(Size.X,Node.Width);
+  Node.ScrollHeight:=Max(Size.Y,Node.Height);
+
+  // check if scrolling is needed and add scrollbar gutter
+  {$IFDEF VerboseFresnelScrolling}
+  writeln('TFLNodeLayouter.Apply CHECK SCROLL NEEDED: "',Node.Element.Name,'" CanScrollX=',Node.CanScrollX,' CanScrollY=',Node.CanScrollY,' Width=',FloatToCSSStr(Node.Width),' Height=',FloatToCSSStr(Node.Height),' SizeX=',FloatToCSSStr(Size.X),' SizeY=',FloatToCSSStr(Size.Y));
+  {$ENDIF}
+  VP:=Node.Element.Viewport;
+  CheckScrollY;
+  if Node.CanScrollX then
+  begin
+    Avail:=Node.Width+Node.PaddingLeft+Node.PaddingRight-Node.ScrollGutterLeft-Node.ScrollGutterRight;
+    NeedScrollX:=(Avail<Size.X);
+    if NeedScrollX and (not VP.ScrollbarsOverlay) and (Node.ScrollGutterBottom=0) then
+    begin
+      Node.AddScrollGutter(true);
+      CheckScrollY;
+    end;
+    {$IFDEF VerboseFresnelScrolling}
+    writeln('TFLNodeLayouter.Apply "',Node.Element.Name,'" NeedScrollX=',NeedScrollX,' NeedScrollY=',NeedScrollY,' Gutter: Left=',FloatToCSSStr(Node.ScrollGutterLeft),' Right=',FloatToCSSStr(Node.ScrollGutterRight),' Top=',FloatToCSSStr(Node.ScrollGutterTop),' Bottom=',FloatToCSSStr(Node.ScrollGutterBottom));
+    {$ENDIF}
+  end;
+
+  // todo: ScrollLeft, ScrollTop
+  // todo: scroll anchor
 end;
 end;
 
 
 procedure TFLNodeLayouter.Init;
 procedure TFLNodeLayouter.Init;
@@ -486,12 +539,11 @@ begin
   Right:=ComputeDistance(fcaRight);
   Right:=ComputeDistance(fcaRight);
   Bottom:=ComputeDistance(fcaBottom);
   Bottom:=ComputeDistance(fcaBottom);
 
 
-  if NoChildren then begin
-    if Element.ComputedOverflowX=CSSRegistry.kwScroll then
-      ScrollBarHorizontalVisible:=true;
-    if Element.ComputedOverflowY=CSSRegistry.kwScroll then
-      ScrollBarVerticalVisible:=true;
-  end;
+  CanScrollX:=Element.ComputedOverflowX in [CSSRegistry.kwScroll,CSSRegistry.kwAuto,CSSRegistry.kwHidden];
+  CanScrollY:=Element.ComputedOverflowY in [CSSRegistry.kwScroll,CSSRegistry.kwAuto,CSSRegistry.kwHidden];
+
+  if NoChildren then
+    ComputeScrollbarsNoChildren;
 
 
   // compute width and height after border and padding
   // compute width and height after border and padding
   MinWidth:=GetContentSize(fcaMinWidth,true);
   MinWidth:=GetContentSize(fcaMinWidth,true);
@@ -505,14 +557,102 @@ begin
 
 
   DeductUsedLengths(NoChildren);
   DeductUsedLengths(NoChildren);
 
 
-  if Element.ComputedOverflowX=CSSRegistry.kwAuto then
-  begin
+  {$IFDEF VerboseFresnelPlacing}
+  writeln('TUsedLayoutNode.ComputeUsedLengths ',Element.GetPath,' NoChildren=',NoChildren,' Width=',FloatToCSSStr(Width),' Height=',FloatToCSSStr(Height),' MinWidth=',FloatToCSSStr(MinWidth),' MaxWidth=',FloatToCSSStr(MaxWidth));
+  {$ENDIF}
+end;
+
+procedure TUsedLayoutNode.ComputeScrollbarGutter;
+var
+  AttrID, KW: TCSSNumericalID;
+  Complete: boolean;
+  aValue: String;
+  aComp: TCSSResCompValue;
+begin
+  AttrID:=CSSRegistry.FresnelAttrs[fcaScrollbarGutter].Index;
+  aValue:=Element.GetCSSString(AttrID,false,Complete);
+  aComp.EndP:=PChar(aValue);
+  repeat
+    if not Element.Resolver.ReadComp(aComp) then break;
+    if (aComp.Kind=rvkKeyword) then
+    begin
+      KW:=aComp.KeywordID;
+      case KW of
+      CSSRegistry.kwStable: ScrollGutterStable:=true;
+      CSSRegistry.kwBothEdges: ScrollGutterBothEdges:=true;
+      end;
+    end;
+  until false;
+end;
+
+procedure TUsedLayoutNode.ComputeScrollbarsNoChildren;
 
 
+  procedure CalcGutter(ComputedOverflow: TCSSNumericalID; Horizontal: boolean);
+  var
+    GutterNeeded: Boolean;
+  begin
+    GutterNeeded:=false;
+    case ComputedOverflow of
+    CSSRegistry.kwScroll:
+      GutterNeeded:=true;
+    CSSRegistry.kwAuto,CSSRegistry.kwHidden:
+      GutterNeeded:=ScrollGutterStable;
+    end;
+    if GutterNeeded then
+      AddScrollGutter(Horizontal);
   end;
   end;
 
 
-  {$IFDEF VerboseFresnelPlacing}
-  writeln('TUsedLayoutNode.ComputeUsedLengths ',Element.GetPath,' NoChildren=',NoChildren,' Width=',FloatToCSSStr(Width),' Height=',FloatToCSSStr(Height),' MinWidth=',FloatToCSSStr(MinWidth),' MaxWidth=',FloatToCSSStr(MaxWidth));
+begin
+  if Element.Viewport.ScrollbarsOverlay then exit;
+  // scrollbars require gutter space
+  // A gutter is needed, when ...
+  // overflow-x is scroll -> check here
+  // overflow-x is auto or hidden and scrollbar-gutter is stable -> check here
+  // overflow-x is auto and content does not fit -> check later
+
+  if CanScrollX or CanScrollY then
+  begin
+    ComputeScrollbarGutter;
+    if ScrollGutterWidth=CSSIDNone then
+      ScrollGutterWidth:=Element.GetComputedKeyword(fcaScrollbarWidth,CSSRegistry.Chk_ScrollbarWidth_KeywordIDs);
+    if ScrollGutterWidth=CSSIDNone then
+      ScrollGutterWidth:=CSSRegistry.kwAuto;
+  end else
+    exit;
+  {$IFDEF VerboseFresnelScrolling}
+  writeln('TUsedLayoutNode.ComputeScrollbarsNoChildren ',Element.Name,' ComputedOverflowX=',CSSRegistry.Keywords[Element.ComputedOverflowX],' ComputedOverflowY=',CSSRegistry.Keywords[Element.ComputedOverflowY],' BothEdges=',ScrollGutterBothEdges,' Stable=',ScrollGutterStable,' ScrollGutterWidth=',ScrollGutterWidth);
   {$ENDIF}
   {$ENDIF}
+
+  CalcGutter(Element.ComputedOverflowX,true);
+  CalcGutter(Element.ComputedOverflowY,false);
+end;
+
+procedure TUsedLayoutNode.AddScrollGutter(Horizontal: boolean);
+var
+  VP: TFresnelViewport;
+  GutterW: TFresnelLength;
+begin
+  VP:=Element.Viewport;
+  case ScrollGutterWidth of
+  CSSRegistry.kwThin:
+    GutterW:=VP.ScrollbarsThinWidth[Horizontal];
+  CSSRegistry.kwAuto:
+    GutterW:=VP.ScrollbarsWidth[Horizontal];
+  else
+    exit; // none
+  end;
+
+  if Horizontal then
+    ScrollGutterBottom:=GutterW
+  else
+    ScrollGutterRight:=GutterW;
+  if ScrollGutterBothEdges then
+  begin
+    if Horizontal then
+      ScrollGutterTop:=GutterW
+    else
+      ScrollGutterLeft:=GutterW;
+  end;
 end;
 end;
 
 
 procedure TUsedLayoutNode.DeductUsedLengths(NoChildren: boolean);
 procedure TUsedLayoutNode.DeductUsedLengths(NoChildren: boolean);
@@ -1668,29 +1808,26 @@ begin
     NewHeight:=NaN;
     NewHeight:=NaN;
   end;
   end;
 
 
-  // Note: The DeductUsedLengths has already computed simple cases like
-  //   given container's width and child's left and right => child's width
+  // Note: The DeductUsedLengths has already computed simple cases
+  //   e.g. given container's width and child's left and right => child's width
 
 
-  if IsNan(NewWidth) or IsNan(NewHeight) then
+  if IsNan(NewWidth) then
   begin
   begin
-    if IsNan(NewWidth) then
+    if IsNan(NewHeight) then
     begin
     begin
-      if IsNan(NewHeight) then
-      begin
-        // auto width and height
-        p:=ChildEl.GetIntrinsicContentSize(aMode,ChildNode.MaxWidth,ChildNode.MaxHeight);
-      end else begin
-        // height set, width auto
-        p:=ChildEl.GetIntrinsicContentSize(aMode,ChildNode.MaxWidth,NewHeight);
-      end;
-    end else begin
-      // width set, height auto
-      p:=ChildEl.GetIntrinsicContentSize(aMode,NewWidth,ChildNode.MaxHeight);
-    end;
-    if IsNan(NewWidth) then
+      // auto width and height
+      p:=ChildEl.GetIntrinsicContentSize(aMode,ChildNode.MaxWidth,ChildNode.MaxHeight);
       NewWidth:=ChildNode.FitWidth(p.X);
       NewWidth:=ChildNode.FitWidth(p.X);
-    if IsNan(NewHeight) then
       NewHeight:=ChildNode.FitHeight(p.Y);
       NewHeight:=ChildNode.FitHeight(p.Y);
+    end else begin
+      // height set, width auto
+      p:=ChildEl.GetIntrinsicContentSize(aMode,ChildNode.MaxWidth,NewHeight);
+      NewWidth:=ChildNode.FitWidth(p.X);
+    end;
+  end else if IsNan(NewHeight) then begin
+    // width set, height auto
+    p:=ChildEl.GetIntrinsicContentSize(aMode,NewWidth,ChildNode.MaxHeight);
+    NewHeight:=ChildNode.FitHeight(p.Y);
   end;
   end;
 
 
   FrameLeft:=ChildNode.MarginLeft+ChildNode.BorderLeft+ChildNode.PaddingLeft;
   FrameLeft:=ChildNode.MarginLeft+ChildNode.BorderLeft+ChildNode.PaddingLeft;