DEADSOFTWARE

sdl1/2: fix invalid window title
[d2df-sdl.git] / src / flexui / fui_flexlay.pas
index a941f554dda7c9a76fe95319c90721b4113ebcb3..4bf7ce791a7ba5ebfe8eeec21dc212f92dc32686 100644 (file)
@@ -3,8 +3,7 @@
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
+ * the Free Software Foundation, version 3 of the License ONLY.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -59,7 +58,8 @@ type
       FlagNoPad = LongWord(1) shl 1;
       FlagExpand = LongWord(1) shl 2;
       // internal
-      FlagInGroup = LongWord(1) shl 8; // set if this control is a member of any group
+      FlagInGroupH = LongWord(1) shl 8; // set if this control is a member of any group
+      FlagInGroupV = LongWord(1) shl 9; // set if this control is a member of any group
 
   private
     type
@@ -85,7 +85,7 @@ type
         procedure initialize (); inline;
 
         function horizBox (): Boolean; inline;
-        function inGroup (): Boolean; inline;
+        function inGroup (idx: Integer): Boolean; inline;
         function noPad (): Boolean; inline;
 
         function getExpand (): Boolean; inline;
@@ -121,6 +121,7 @@ type
     procedure firstTimeSetup (cidx: LayControlIdx);
     procedure doChildren (parent: LayControlIdx; child: ControlT);
     procedure appendToGroup (const gname: AnsiString;cidx: LayControlIdx;gidx: Integer);
+    procedure clearGroups ();
     procedure setupGroups ();
 
     procedure distributeChildren (boxidx: LayControlIdx; maindir: Integer);
@@ -185,7 +186,7 @@ begin
 end;
 
 function TFlexLayouterBase.TLayControl.horizBox (): Boolean; inline; begin result := ((flags and FlagHorizBox) <> 0); end;
-function TFlexLayouterBase.TLayControl.inGroup (): Boolean; inline; begin result := ((flags and FlagInGroup) <> 0); end;
+function TFlexLayouterBase.TLayControl.inGroup (idx: Integer): Boolean; inline; begin if (idx = 0) then result := ((flags and FlagInGroupH) <> 0) else if (idx = 1) then result := ((flags and FlagInGroupV) <> 0) else result := false; end;
 function TFlexLayouterBase.TLayControl.noPad (): Boolean; inline; begin result := ((flags and FlagNoPad) <> 0); end;
 
 function TFlexLayouterBase.TLayControl.getExpand (): Boolean; inline; begin result := ((flags and FlagExpand) <> 0); end;
@@ -272,9 +273,8 @@ end;
 
 procedure TFlexLayouterBase.clear ();
 begin
+  clearGroups();
   ctlist := nil;
-  groups[0] := nil;
-  groups[1] := nil;
 end;
 
 
@@ -314,11 +314,13 @@ end;
 procedure TFlexLayouterBase.appendToGroup (const gname: AnsiString; cidx: LayControlIdx; gidx: Integer);
 var
   f: Integer;
+  gflg: LongWord;
 begin
   if (Length(gname) = 0) then exit;
   assert((cidx >= 0) and (cidx < Length(ctlist)));
   assert((gidx = 0) or (gidx = 1));
-  ctlist[cidx].flags := ctlist[cidx].flags or FlagInGroup;
+  if (gidx = 0) then gflg := FlagInGroupH else gflg := FlagInGroupV;
+  ctlist[cidx].flags := ctlist[cidx].flags or gflg;
   for f := 0 to High(groups[gidx]) do
   begin
     if (groups[gidx][f].name = gname) then
@@ -337,17 +339,59 @@ begin
 end;
 
 
+procedure TFlexLayouterBase.clearGroups ();
+var
+  gidx, f: Integer;
+begin
+  for gidx := 0 to 1 do
+  begin
+    for f := 0 to High(groups[gidx]) do groups[gidx][f].ctls := nil;
+    groups[gidx] := nil;
+  end;
+end;
+
+
 procedure TFlexLayouterBase.setupGroups ();
 var
-  idx: Integer;
+  gflg: LongWord;
+  idx, gidx, f, c: Integer;
   lc: PLayControl;
 begin
+  clearGroups();
   for idx := 0 to High(ctlist) do
   begin
     lc := @ctlist[idx];
     appendToGroup(lc.ctl.getHGroup, LayControlIdx(idx), 0);
     appendToGroup(lc.ctl.getVGroup, LayControlIdx(idx), 1);
   end;
+  // if control is only one in a group, mark is as "not grouped"
+  for gidx := 0 to 1 do
+  begin
+    if (gidx = 0) then gflg := LongWord(not FlagInGroupH) else gflg := LongWord(not FlagInGroupV);
+    f := 0;
+    while (f < Length(groups[gidx])) do
+    begin
+      if (Length(groups[gidx][f].ctls) < 2) then
+      begin
+        // unmark controls
+        for c := 0 to High(groups[gidx][f].ctls) do
+        begin
+          lc := @ctlist[groups[gidx][f].ctls[c]];
+          lc.flags := lc.flags and gflg;
+        end;
+        // remove this group
+        groups[gidx][f].ctls := nil;
+        for c := f+1 to High(groups[gidx]) do groups[gidx][c-1] := groups[gidx][c];
+        c := High(groups[gidx]);
+        groups[gidx][c].ctls := nil;
+        SetLength(groups[gidx], c);
+      end
+      else
+      begin
+        Inc(f);
+      end;
+    end;
+  end;
 end;
 
 
@@ -363,7 +407,6 @@ begin
     ctlist[0].myidx := 0;
     ctlist[0].ctl := root;
     doChildren(0, root.firstChild);
-    setupGroups();
   except
     clear();
     raise;
@@ -407,6 +450,7 @@ var
   gtype: Integer;
 begin
   groupElementChanged := false;
+  setupGroups();
   for f := 0 to High(ctlist) do firstTimeSetup(f);
   // if we have any groups, set "group element changed" flag, so third pass will fix 'em
   for gtype := 0 to 1 do
@@ -519,7 +563,7 @@ begin
     // relayout children if size was changed
     if (not osz.equals(lc.desiredsize)) then
     begin
-      if (lc.inGroup) then groupElementChanged := true;
+      if (lc.inGroup(0)) or (lc.inGroup(1)) then groupElementChanged := true;
       layBox(lc.myidx);
     end;
   end;
@@ -547,7 +591,7 @@ begin
       if (me.horizBox) then distributeChildren(me.myidx, 0) else distributeChildren(me.myidx, 1);
       // relayout children if size was changed
       if (osz.equals(me.desiredsize)) then break;
-      if (me.inGroup) then groupElementChanged := true;
+      if (me.inGroup(0)) or (me.inGroup(1)) then groupElementChanged := true;
     end;
   end;
 end;
@@ -560,6 +604,7 @@ var
   maxsz: Integer;
   grp: PLayGroup;
   f, c: Integer;
+  maindir: Integer;
   cidx: LayControlIdx;
   ct: PLayControl;
   loopsLeft: Integer = 64;
@@ -599,11 +644,16 @@ begin
     for f := 0 to High(ctlist) do
     begin
       ct := @ctlist[f];
-      if (ct.inGroup) then
+      if (ct.parent <> -1) then
+      begin
+        if (ctlist[ct.parent].horizBox) then maindir := 0 else maindir := 1;
+      end
+      else
       begin
-        ct.expand := false; // don't expand grouped controls anymore
-        ct.tempFlex := 0; // don't change control size anymore
+        maindir := 0; // arbitrary
       end;
+      if (ct.inGroup(maindir)) then ct.tempFlex := 0; // don't change control size anymore
+      if (ct.inGroup(1-maindir)) then ct.expand := false; // don't expand grouped controls anymore
     end;
     if (not secondAgain) then break;
   end;