DEADSOFTWARE

HolmesUI: rendering cosmetix
[d2df-sdl.git] / src / gx / gh_flexlay.pas
index 3eed2e410e14dd7b1f8c94026aabc540518be32c..9692f0d1353f0319fb407204f7feb37dcf8338de 100644 (file)
@@ -139,11 +139,20 @@ type
         function lineStart (): Boolean; inline;
         function canWrap (): Boolean; inline;
         function inGroup (): Boolean; inline;
-        function expand (): Boolean; inline;
         function firstInLine (): Boolean; inline;
 
+        function getExpand (): Boolean; inline;
+        procedure setExpand (v: Boolean); inline;
+
+        function alignLeft (): Boolean; inline;
+        function alignTop (): Boolean; inline;
+        function alignRight (): Boolean; inline;
+        function alignBottom (): Boolean; inline;
+        function alignCenter (): Boolean; inline;
+
       public
         property didWrap: Boolean read getDidWrap write setDidWrap;
+        property expand: Boolean read getExpand write setExpand;
       end;
 
       PLayGroup = ^TLayGroup;
@@ -172,7 +181,7 @@ type
     // this also sets `tempFlex`
     procedure calcMaxSizeInternal (cidx: LayControlIdx);
 
-    procedure fixLine (me: PLayControl; i0, i1: LayControlIdx; cury: Integer; var spaceLeft: Single; var flexTotal: Integer; var flexBoxCount: Integer);
+    procedure fixLine (me: PLayControl; i0, i1: LayControlIdx; var cury: Integer; var spaceLeft: Single);
     // do box layouting; call `layBox()` recursively if necessary
     procedure layBox (boxidx: LayControlIdx);
 
@@ -236,12 +245,20 @@ function TFlexLayouterBase.TLayControl.horizBox (): Boolean; inline; begin resul
 function TFlexLayouterBase.TLayControl.lineStart (): Boolean; inline; begin result := ((flags and FlagLineStart) <> 0); end;
 function TFlexLayouterBase.TLayControl.canWrap (): Boolean; inline; begin result := ((flags and FlagLineCanWrap) <> 0); end;
 function TFlexLayouterBase.TLayControl.inGroup (): Boolean; inline; begin result := ((flags and FlagInGroup) <> 0); end;
-function TFlexLayouterBase.TLayControl.expand (): Boolean; inline; begin result := ((flags and FlagExpand) <> 0); end;
 function TFlexLayouterBase.TLayControl.firstInLine (): Boolean; inline; begin result := ((flags and FlagLineFirst) <> 0); end;
 
 function TFlexLayouterBase.TLayControl.getDidWrap (): Boolean; inline; begin result := ((flags and FlagLineDidWrap) <> 0); end;
 procedure TFlexLayouterBase.TLayControl.setDidWrap (v: Boolean); inline; begin if (v) then flags := flags or FlagLineDidWrap else flags := flags and (not FlagLineDidWrap); end;
 
+function TFlexLayouterBase.TLayControl.getExpand (): Boolean; inline; begin result := ((flags and FlagExpand) <> 0); end;
+procedure TFlexLayouterBase.TLayControl.setExpand (v: Boolean); inline; begin if (v) then flags := flags or FlagExpand else flags := flags and (not FlagExpand); end;
+
+function TFlexLayouterBase.TLayControl.alignLeft (): Boolean; inline; begin result := (aligndir < 0); end;
+function TFlexLayouterBase.TLayControl.alignTop (): Boolean; inline; begin result := (aligndir < 0); end;
+function TFlexLayouterBase.TLayControl.alignRight (): Boolean; inline; begin result := (aligndir > 0); end;
+function TFlexLayouterBase.TLayControl.alignBottom (): Boolean; inline; begin result := (aligndir > 0); end;
+function TFlexLayouterBase.TLayControl.alignCenter (): Boolean; inline; begin result := (aligndir = 0); end;
+
 
 // ////////////////////////////////////////////////////////////////////////// //
 constructor TFlexLayouterBase.TChildrenEnumerator.Create (constref actls: TLayCtlArray; acur: Integer);
@@ -428,6 +445,7 @@ var
   lc, c: PLayControl;
   msz: TLaySize;
   negw, negh: Boolean;
+  zerow: Boolean;
   curwdt, curhgt, totalhgt: Integer;
   doWrap: Boolean;
 begin
@@ -435,8 +453,9 @@ begin
 
   lc := @ctlist[cidx];
   msz := lc.ctl.getMaxSize;
-  negw := (lc.startsize.w <= 0);
-  negh := (lc.startsize.h <= 0);
+  negw := (lc.startsize.w < 0);
+  negh := (lc.startsize.h < 0);
+  zerow := (lc.startsize.w = 0);
 
   lc.tempFlex := lc.ctl.getFlex;
 
@@ -447,14 +466,14 @@ begin
     // horizontal boxes
     if (negw) then lc.tempFlex := 0; // size is negative: don't expand
     curwdt := lc.margins.horiz;
-    curhgt := lc.margins.vert;
-    totalhgt := 0;
+    curhgt := 0;
+    totalhgt := lc.margins.vert;
     for c in forChildren(cidx) do
     begin
       // new line?
       doWrap := (not c.firstInLine) and (c.lineStart);
       // need to wrap?
-      if (not doWrap) and (lc.canWrap) and (c.canWrap) and (msz.w > 0) and (curwdt+c.startsize.w > lc.startsize.w) then doWrap := true;
+      if (not doWrap) and zerow and (lc.canWrap) and (c.canWrap) and (msz.w > 0) and (curwdt+c.startsize.w > lc.startsize.w) then doWrap := true;
       if (doWrap) then
       begin
         totalhgt += curhgt;
@@ -465,7 +484,9 @@ begin
       curwdt += c.startsize.w;
       if (curhgt < c.startsize.h) then curhgt := c.startsize.h;
     end;
+    //writeln('00: ', cidx, ': totalhgt=', totalhgt);
     totalhgt += curhgt;
+    //writeln('01: ', cidx, ': totalhgt=', totalhgt);
     if (lc.startsize.w < curwdt) then lc.startsize.w := curwdt;
     if (lc.startsize.h < totalhgt) then lc.startsize.h := totalhgt;
   end
@@ -497,6 +518,7 @@ var
   grp: PLayGroup;
   maxsz: Integer;
   cidx: LayControlIdx;
+  ct: PLayControl;
   mr: TLayMargins;
 begin
   // reset all 'laywrap' flags for controls, set initial 'startsize'
@@ -506,11 +528,12 @@ begin
     ctlist[f].startsize := ctlist[f].ctl.getDefSize;
     mr := ctlist[f].ctl.getMargins;
     ctlist[f].margins := mr;
-    ctlist[f].startsize.w += mr.horiz;
-    ctlist[f].startsize.h += mr.vert;
+    //ctlist[f].startsize.w += mr.horiz;
+    //ctlist[f].startsize.h += mr.vert;
   end;
   // setup sizes
   calcMaxSizeInternal(0); // this also sets `tempFlex`
+  //writeln('=== calculated max size (0) ==='); dump();
   // find max size for group, adjust 'startsize' controls to group max size
   needRecalcMaxSize := false;
   for gtype := 0 to 1 do
@@ -522,15 +545,17 @@ begin
       for c := 0 to High(grp.ctls) do
       begin
         cidx := grp.ctls[c];
-        if (maxsz < ctlist[cidx].startsize[gtype]) then maxsz := ctlist[cidx].startsize[gtype];
+        ct := @ctlist[cidx];
+        if (maxsz < ct.startsize[gtype]) then maxsz := ct.startsize[gtype];
       end;
       for c := 0 to High(grp.ctls) do
       begin
         cidx := grp.ctls[c];
-        if (maxsz <> ctlist[cidx].startsize[gtype]) then
+        ct := @ctlist[cidx];
+        if (maxsz <> ct.startsize[gtype]) then
         begin
           needRecalcMaxSize := true;
-          ctlist[cidx].startsize[gtype] := maxsz;
+          ct.startsize[gtype] := maxsz;
         end;
       end;
     end;
@@ -541,13 +566,14 @@ begin
   for f := 0 to High(ctlist) do ctlist[f].desiredsize := ctlist[f].startsize;
   // set flags
   firstTime := true;
-  //writeln('=== calculated max size ===');
-  //dump();
+  //writeln('=== calculated max size (final) ==='); dump();
 end;
 
 
-procedure TFlexLayouterBase.fixLine (me: PLayControl; i0, i1: LayControlIdx; cury: Integer; var spaceLeft: Single; var flexTotal: Integer; var flexBoxCount: Integer);
+procedure TFlexLayouterBase.fixLine (me: PLayControl; i0, i1: LayControlIdx; var cury: Integer; var spaceLeft: Single);
 var
+  flexTotal: Integer = 0; // total sum of flex fields
+  flexBoxCount: Integer = 0; // number of boxes
   curx: Integer;
   lc: PLayControl;
   osz: TLaySize;
@@ -557,12 +583,13 @@ var
 begin
   curx := me.margins.left;
   sti0 := i0;
-  // calc minimal line height
+  // calc minimal line height, count flexboxes
   lineh := 0;
   while (i0 <> i1) do
   begin
     lc := @ctlist[i0];
     lineh := nmax(lineh, lc.startsize.h);
+    if (lc.tempFlex > 0) then begin flexTotal += lc.tempFlex; flexBoxCount += 1; end;
     i0 := lc.nextSibling;
   end;
   // distribute space, expand/align
@@ -592,8 +619,8 @@ begin
     end;
     // expand or align
          if (lc.expand) then lc.desiredsize.h := nmin(lc.maxsize.h, lineh) // expand
-    else if (lc.aligndir > 0) then lc.desiredpos.y := cury+(lineh-lc.desiredsize.h) // bottom align
-    else if (lc.aligndir = 0) then lc.desiredpos.y := cury+(lineh-lc.desiredsize.h) div 2; // center
+    else if (lc.alignBottom) then lc.desiredpos.y := cury+(lineh-lc.desiredsize.h) // bottom align
+    else if (lc.alignCenter) then lc.desiredpos.y := cury+(lineh-lc.desiredsize.h) div 2; // center
     if (not osz.equals(lc.desiredsize)) then
     begin
       if (lc.inGroup) then groupElementChanged := true;
@@ -605,6 +632,7 @@ begin
   flexTotal := 0;
   flexBoxCount := 0;
   spaceLeft := me.desiredsize.w-me.margins.horiz;
+  cury += lineh;
 end;
 
 
@@ -616,7 +644,7 @@ var
   flexBoxCount: Integer; // number of boxes
   spaceLeft: Single;
   cury: Integer;
-  maxwdt, maxhgt: Integer;
+  maxwdt: Integer;
   lineStartIdx: LayControlIdx;
   lc: PLayControl;
   doWrap: Boolean;
@@ -637,12 +665,10 @@ begin
   begin
     // horizontal boxes
     cury := me.margins.top;
-    maxhgt := 0;
 
-    fixLine(me, -1, -1, cury, spaceLeft, flexTotal, flexBoxCount); //HACK!
+    fixLine(me, -1, -1, cury, spaceLeft); //HACK!
 
     lineStartIdx := me.firstChild;
-
     for lc in forChildren(boxidx) do
     begin
       // new line?
@@ -652,33 +678,20 @@ begin
       if (doWrap) then
       begin
         // new line, fix this one
-        if (not lc.didWrap) then
-        begin
-          wrappingChanged := true;
-          lc.didWrap := true;
-        end;
-        fixLine(me, lineStartIdx, lc.myidx, cury, spaceLeft, flexTotal, flexBoxCount);
-        cury += maxhgt;
+        if (not lc.didWrap) then begin wrappingChanged := true; lc.didWrap := true; end;
+        fixLine(me, lineStartIdx, lc.myidx, cury, spaceLeft);
         lineStartIdx := lc.myidx;
       end
       else
       begin
-        if (lc.didWrap) then
-        begin
-          wrappingChanged := true;
-          lc.didWrap := false;
-        end;
+        if (lc.didWrap) then begin wrappingChanged := true; lc.didWrap := false; end;
       end;
       spaceLeft -= lc.desiredsize.w;
-      if (maxhgt < lc.desiredsize.h) then maxhgt := lc.desiredsize.h;
-      if (lc.tempFlex > 0) then
-      begin
-        flexTotal += lc.tempFlex;
-        flexBoxCount += 1;
-      end;
+      //if (maxhgt < lc.desiredsize.h) then maxhgt := lc.desiredsize.h;
+      //if (lc.tempFlex > 0) then begin flexTotal += lc.tempFlex; flexBoxCount += 1; end;
     end;
     // fix last line
-    fixLine(me, lineStartIdx, -1, cury, spaceLeft, flexTotal, flexBoxCount);
+    fixLine(me, lineStartIdx, -1, cury, spaceLeft);
   end
   else
   begin
@@ -693,11 +706,7 @@ begin
     begin
       spaceLeft -= lc.desiredsize.h;
       if (maxwdt < lc.desiredsize.w) then maxwdt := lc.desiredsize.w;
-      if (lc.tempFlex > 0) then
-      begin
-        flexTotal += lc.tempFlex;
-        flexBoxCount += 1;
-      end;
+      if (lc.tempFlex > 0) then begin flexTotal += lc.tempFlex; flexBoxCount += 1; end;
     end;
 
     // distribute space
@@ -725,8 +734,8 @@ begin
       end;
       // expand or align
            if (lc.expand) then lc.desiredsize.w := nmin(lc.maxsize.w, me.desiredsize.w-me.margins.vert) // expand
-      else if (lc.aligndir > 0) then lc.desiredpos.x := me.desiredsize.w-me.margins.right-lc.desiredsize.w // right align
-      else if (lc.aligndir = 0) then lc.desiredpos.x := (me.desiredsize.w-me.margins.horiz-lc.desiredsize.w) div 2; // center
+      else if (lc.alignRight) then lc.desiredpos.x := me.desiredsize.w-me.margins.right-lc.desiredsize.w // right align
+      else if (lc.alignCenter) then lc.desiredpos.x := (me.desiredsize.w-lc.desiredsize.w) div 2; // center
       if (not osz.equals(lc.desiredsize)) then
       begin
         if (lc.inGroup) then groupElementChanged := true;
@@ -782,6 +791,7 @@ var
   grp: PLayGroup;
   f, c: Integer;
   cidx: LayControlIdx;
+  ct: PLayControl;
 begin
   while true do
   begin
@@ -800,14 +810,17 @@ begin
           for c := 0 to High(grp.ctls) do
           begin
             cidx := grp.ctls[c];
-            if (maxsz < ctlist[cidx].startsize[gtype]) then maxsz := ctlist[cidx].startsize[gtype];
+            ct := @ctlist[cidx];
+            ct.expand := false; // don't expand grouped controls anymore
+            if (maxsz < ct.startsize[gtype]) then maxsz := ct.startsize[gtype];
           end;
           for c := 0 to High(grp.ctls) do
           begin
             cidx := grp.ctls[c];
-            ctlist[cidx].startsize[gtype] := maxsz;
-            ctlist[cidx].desiredsize[gtype] := maxsz;
-            ctlist[cidx].tempFlex := 0; // don't change control size anymore
+            ct := @ctlist[cidx];
+            ct.startsize[gtype] := maxsz;
+            ct.desiredsize[gtype] := maxsz;
+            ct.tempFlex := 0; // don't change control size anymore
           end;
         end;
       end;
@@ -816,15 +829,21 @@ begin
     begin
       for f := 0 to High(ctlist) do
       begin
+        ct := @ctlist[f];
+        if (ct.inGroup) then
+        begin
+          ct.expand := false; // don't expand grouped controls anymore
+          ct.tempFlex := 0; // don't change control size anymore
+        end;
         for c := 0 to 1 do
         begin
-          if (ctlist[f].maxsize[c] <= 0) then continue;
-          if (ctlist[f].desiredsize[c] > ctlist[f].maxsize[c]) then
+          if (ct.maxsize[c] < 0) then continue;
+          if (ct.desiredsize[c] > ct.maxsize[c]) then
           begin
             //writeln('ctl #', f, '; dimension #', c, ': desired=', ctlist[f].desiredsize[c], '; max=', ctlist[f].maxsize[c]);
-            ctlist[f].startsize[c] := ctlist[f].maxsize[c];
-            ctlist[f].desiredsize[c] := ctlist[f].maxsize[c];
-            ctlist[f].tempFlex := 0; // don't change control size anymore
+            ct.startsize[c] := ct.maxsize[c];
+            ct.desiredsize[c] := ct.maxsize[c];
+            ct.tempFlex := 0; // don't change control size anymore
             secondAgain := true;
           end;
         end;