DEADSOFTWARE

FlexUI: added 8/14/16 winN/winN-prop fonts; removed horizontal wrapping
[d2df-sdl.git] / src / flexui / fui_flexlay.pas
1 (* coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
2 * Understanding is not required. Only obedience.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *)
17 {$INCLUDE ../shared/a_modes.inc}
18 unit fui_flexlay;
19 (*
20 control default size will be increased by margins
21 negative margins are ignored
22 ControlT:
23 procedure layPrepare (); // called before registering control in layouter
24 function getDefSize (): TLaySize; // default size; <0: use max size
25 function getMargins (): TLayMargins;
26 function getPadding (): TLaySize; // children padding (each non-first child will get this on left/top)
27 function getMaxSize (): TLaySize; // max size; <0: set to some huge value
28 function getFlex (): Integer; // <=0: not flexible
29 function isHorizBox (): Boolean; // horizontal layout for children?
30 function noPad (): Boolean; // ignore padding in box direction for this control
31 function getAlign (): Integer; // aligning in non-main direction: <0: left/up; 0: center; >0: right/down
32 function getExpand (): Boolean; // expanding in non-main direction: `true` will ignore align and eat all available space
33 procedure setActualSizePos (constref apos: TLayPos; constref asize: TLaySize);
34 function getHGroup (): AnsiString; // empty: not grouped
35 function getVGroup (): AnsiString; // empty: not grouped
36 function nextSibling (): ControlT;
37 function firstChild (): ControlT;
38 *)
40 interface
42 uses
43 fui_common;
46 // ////////////////////////////////////////////////////////////////////////// //
47 type
48 generic TFlexLayouterBase<ControlT> = class
49 public
50 type CtlT = ControlT;
52 private
53 type LayControlIdx = Integer;
55 private
56 // flags
57 const
58 FlagHorizBox = LongWord(1) shl 0; // horizontal layout for children
59 FlagNoPad = LongWord(1) shl 1;
60 FlagExpand = LongWord(1) shl 2;
61 // internal
62 FlagInGroup = LongWord(1) shl 8; // set if this control is a member of any group
64 private
65 type
66 PLayControl = ^TLayControl;
67 TLayControl = record
68 public
69 myidx: LayControlIdx;
70 tempFlex: Integer;
71 flags: LongWord; // see above
72 aligndir: Integer;
73 startsize: TLaySize; // original size
74 desiredsize: TLaySize; // current size
75 maxsize: TLaySize; // current maximum size
76 margins: TLayMargins; // can never be negative
77 padding: TLaySize;
78 desiredpos: TLayPos;
79 ctl: ControlT;
80 parent: LayControlIdx; // = -1;
81 firstChild: LayControlIdx; // = -1;
82 nextSibling: LayControlIdx; // = -1;
84 public
85 procedure initialize (); inline;
87 function horizBox (): Boolean; inline;
88 function inGroup (): Boolean; inline;
89 function noPad (): Boolean; inline;
91 function getExpand (): Boolean; inline;
92 procedure setExpand (v: Boolean); inline;
94 function alignLeft (): Boolean; inline;
95 function alignTop (): Boolean; inline;
96 function alignRight (): Boolean; inline;
97 function alignBottom (): Boolean; inline;
98 function alignCenter (): Boolean; inline;
100 function visible (): Boolean; inline;
102 public
103 property expand: Boolean read getExpand write setExpand;
104 end;
106 PLayGroup = ^TLayGroup;
107 TLayGroup = record
108 name: AnsiString;
109 ctls: array of LayControlIdx;
110 end;
112 TLayCtlArray = array of TLayControl;
113 TLayGrpArray = array of TLayGroup;
115 private
116 ctlist: TLayCtlArray;
117 groups: array[0..1] of TLayGrpArray; // horiz, vert
118 groupElementChanged: Boolean;
120 private
121 procedure firstTimeSetup (cidx: LayControlIdx);
122 procedure doChildren (parent: LayControlIdx; child: ControlT);
123 procedure appendToGroup (const gname: AnsiString;cidx: LayControlIdx;gidx: Integer);
124 procedure setupGroups ();
126 procedure distributeChildren (boxidx: LayControlIdx; maindir: Integer);
127 // do box layouting; call `layBox()` recursively if necessary
128 procedure layBox (boxidx: LayControlIdx);
130 procedure firstPass ();
131 procedure secondPass ();
132 procedure thirdPass ();
134 procedure dumpList (cidx: LayControlIdx; indent: Integer);
136 public
137 type
138 TChildrenEnumerator = record
139 private
140 ctls: TLayCtlArray;
141 cur: Integer;
142 first: Boolean;
143 onlyVisible: Boolean;
144 public
145 constructor Create (constref actls: TLayCtlArray; acur: Integer; aonlyvis: Boolean);
146 function moveNext (): Boolean; inline;
147 function getCurrent (): PLayControl; inline;
148 function getEnumerator (): TChildrenEnumerator; inline;
149 property current: PLayControl read getCurrent;
150 end;
152 public
153 constructor Create ();
154 destructor Destroy (); override;
156 // clear build lists
157 procedure clear ();
159 // build control and group lists
160 procedure setup (root: ControlT);
162 function forChildren (cidx: LayControlIdx): TChildrenEnumerator; inline;
163 function forVisibleChildren (cidx: LayControlIdx): TChildrenEnumerator; inline;
165 procedure layout ();
167 procedure dumpFlat ();
168 procedure dump ();
169 end;
172 implementation
174 uses
175 utils;
178 // ////////////////////////////////////////////////////////////////////////// //
179 procedure TFlexLayouterBase.TLayControl.initialize (); inline;
180 begin
181 FillChar(self, 0, sizeof(self));
182 parent := -1;
183 firstChild := -1;
184 nextSibling := -1;
185 end;
187 function TFlexLayouterBase.TLayControl.horizBox (): Boolean; inline; begin result := ((flags and FlagHorizBox) <> 0); end;
188 function TFlexLayouterBase.TLayControl.inGroup (): Boolean; inline; begin result := ((flags and FlagInGroup) <> 0); end;
189 function TFlexLayouterBase.TLayControl.noPad (): Boolean; inline; begin result := ((flags and FlagNoPad) <> 0); end;
191 function TFlexLayouterBase.TLayControl.getExpand (): Boolean; inline; begin result := ((flags and FlagExpand) <> 0); end;
192 procedure TFlexLayouterBase.TLayControl.setExpand (v: Boolean); inline; begin if (v) then flags := flags or FlagExpand else flags := flags and (not FlagExpand); end;
194 function TFlexLayouterBase.TLayControl.alignLeft (): Boolean; inline; begin result := (aligndir < 0); end;
195 function TFlexLayouterBase.TLayControl.alignTop (): Boolean; inline; begin result := (aligndir < 0); end;
196 function TFlexLayouterBase.TLayControl.alignRight (): Boolean; inline; begin result := (aligndir > 0); end;
197 function TFlexLayouterBase.TLayControl.alignBottom (): Boolean; inline; begin result := (aligndir > 0); end;
198 function TFlexLayouterBase.TLayControl.alignCenter (): Boolean; inline; begin result := (aligndir = 0); end;
200 function TFlexLayouterBase.TLayControl.visible (): Boolean; inline;
201 begin
202 result := (startsize.w <> 0) or (startsize.h <> 0);
203 end;
206 // ////////////////////////////////////////////////////////////////////////// //
207 constructor TFlexLayouterBase.TChildrenEnumerator.Create (constref actls: TLayCtlArray; acur: Integer; aonlyvis: Boolean);
208 begin
209 ctls := actls;
210 cur := acur;
211 first := true;
212 onlyVisible := aonlyvis;
213 end;
215 function TFlexLayouterBase.TChildrenEnumerator.moveNext (): Boolean; inline;
216 begin
217 while true do
218 begin
219 if first then
220 begin
221 if (cur >= 0) and (cur < Length(ctls)) then cur := ctls[cur].firstChild else cur := -1;
222 first := false;
223 end
224 else
225 begin
226 cur := ctls[cur].nextSibling;
227 end;
228 result := (cur >= 0);
229 if (not result) or (not onlyVisible) then break;
230 if (ctls[cur].visible) then break;
231 end;
232 end;
234 function TFlexLayouterBase.TChildrenEnumerator.getCurrent (): PLayControl; inline;
235 begin
236 result := @ctls[cur];
237 end;
239 function TFlexLayouterBase.TChildrenEnumerator.getEnumerator (): TChildrenEnumerator; inline;
240 begin
241 result := self;
242 end;
245 // ////////////////////////////////////////////////////////////////////////// //
246 constructor TFlexLayouterBase.Create ();
247 begin
248 ctlist := nil;
249 groups[0] := nil;
250 groups[1] := nil;
251 groupElementChanged := false;
252 end;
255 destructor TFlexLayouterBase.Destroy ();
256 begin
257 clear();
258 inherited;
259 end;
262 function TFlexLayouterBase.forChildren (cidx: LayControlIdx): TChildrenEnumerator; inline;
263 begin
264 result := TChildrenEnumerator.Create(ctlist, cidx, false);
265 end;
267 function TFlexLayouterBase.forVisibleChildren (cidx: LayControlIdx): TChildrenEnumerator; inline;
268 begin
269 result := TChildrenEnumerator.Create(ctlist, cidx, true);
270 end;
273 procedure TFlexLayouterBase.clear ();
274 begin
275 ctlist := nil;
276 groups[0] := nil;
277 groups[1] := nil;
278 end;
281 procedure TFlexLayouterBase.doChildren (parent: LayControlIdx; child: ControlT);
282 var
283 cidx: LayControlIdx = -1;
284 lc: PLayControl;
285 begin
286 assert((parent >= 0) and (parent < Length(ctlist)));
287 assert(ctlist[parent].firstChild = -1);
288 while (child <> nil) do
289 begin
290 child.layPrepare;
291 //if (msz.w = 0) or (msz.h = 0) then continue; // hidden controls will have zero maxsize, so skip 'em
292 SetLength(ctlist, Length(ctlist)+1);
293 lc := @ctlist[High(ctlist)];
294 lc.initialize();
295 if (cidx = -1) then
296 begin
297 cidx := LayControlIdx(High(ctlist));
298 ctlist[parent].firstChild := cidx;
299 end
300 else
301 begin
302 ctlist[cidx].nextSibling := LayControlIdx(High(ctlist));
303 cidx := LayControlIdx(High(ctlist));
304 end;
305 lc.myidx := cidx;
306 lc.ctl := child;
307 lc.parent := parent;
308 doChildren(cidx, child.firstChild);
309 child := child.nextSibling;
310 end;
311 end;
314 procedure TFlexLayouterBase.appendToGroup (const gname: AnsiString; cidx: LayControlIdx; gidx: Integer);
315 var
316 f: Integer;
317 begin
318 if (Length(gname) = 0) then exit;
319 assert((cidx >= 0) and (cidx < Length(ctlist)));
320 assert((gidx = 0) or (gidx = 1));
321 ctlist[cidx].flags := ctlist[cidx].flags or FlagInGroup;
322 for f := 0 to High(groups[gidx]) do
323 begin
324 if (groups[gidx][f].name = gname) then
325 begin
326 SetLength(groups[gidx][f].ctls, Length(groups[gidx][f].ctls)+1);
327 groups[gidx][f].ctls[High(groups[gidx][f].ctls)] := cidx;
328 exit;
329 end;
330 end;
331 // new group
332 f := Length(groups[gidx]);
333 SetLength(groups[gidx], f+1);
334 groups[gidx][f].name := gname;
335 SetLength(groups[gidx][f].ctls, Length(groups[gidx][f].ctls)+1);
336 groups[gidx][f].ctls[High(groups[gidx][f].ctls)] := cidx;
337 end;
340 procedure TFlexLayouterBase.setupGroups ();
341 var
342 idx: Integer;
343 lc: PLayControl;
344 begin
345 for idx := 0 to High(ctlist) do
346 begin
347 lc := @ctlist[idx];
348 appendToGroup(lc.ctl.getHGroup, LayControlIdx(idx), 0);
349 appendToGroup(lc.ctl.getVGroup, LayControlIdx(idx), 1);
350 end;
351 end;
354 // build control and group lists
355 procedure TFlexLayouterBase.setup (root: ControlT);
356 begin
357 clear();
358 if (root = nil) then exit;
359 root.layPrepare;
360 try
361 SetLength(ctlist, 1);
362 ctlist[0].initialize();
363 ctlist[0].myidx := 0;
364 ctlist[0].ctl := root;
365 doChildren(0, root.firstChild);
366 setupGroups();
367 except
368 clear();
369 raise;
370 end;
371 end;
374 procedure TFlexLayouterBase.firstTimeSetup (cidx: LayControlIdx);
375 var
376 lc: PLayControl;
377 begin
378 assert((cidx >= 0) and (cidx < Length(ctlist)));
379 lc := @ctlist[cidx];
380 lc.flags := 0;
381 if (lc.ctl.isHorizBox) then lc.flags := lc.flags or FlagHorizBox;
382 if (lc.ctl.getExpand) then lc.flags := lc.flags or FlagExpand;
383 if (lc.ctl.noPad) then lc.flags := lc.flags or FlagNoPad;
384 lc.aligndir := lc.ctl.getAlign;
385 lc.startsize := lc.ctl.getDefSize;
386 //lc.startsize.w := nmax(0, lc.startsize.w);
387 //lc.startsize.h := nmax(0, lc.startsize.h);
388 lc.margins := lc.ctl.getMargins;
389 lc.margins.left := nmax(0, lc.margins.left);
390 lc.margins.top := nmax(0, lc.margins.top);
391 lc.margins.right := nmax(0, lc.margins.right);
392 lc.margins.bottom := nmax(0, lc.margins.bottom);
393 lc.padding := lc.ctl.getPadding;
394 lc.padding.w := nmax(0, lc.padding.w);
395 lc.padding.h := nmax(0, lc.padding.h);
396 lc.maxsize := TLaySize.Create(-1, -1);
397 if (lc.maxsize.w >= 0) then lc.startsize.w := nmin(lc.maxsize.w, lc.startsize.w);
398 if (lc.maxsize.h >= 0) then lc.startsize.h := nmin(lc.maxsize.h, lc.startsize.h);
399 lc.desiredsize := lc.startsize;
400 lc.tempFlex := lc.ctl.getFlex;
401 end;
404 procedure TFlexLayouterBase.firstPass ();
405 var
406 f: Integer;
407 gtype: Integer;
408 begin
409 groupElementChanged := false;
410 for f := 0 to High(ctlist) do firstTimeSetup(f);
411 // if we have any groups, set "group element changed" flag, so third pass will fix 'em
412 for gtype := 0 to 1 do
413 begin
414 if (Length(groups[gtype]) > 0) then
415 begin
416 groupElementChanged := true;
417 break;
418 end;
419 end;
420 end;
423 procedure TFlexLayouterBase.distributeChildren (boxidx: LayControlIdx; maindir: Integer);
424 var
425 me, lc: PLayControl;
426 suppdir: Integer;
427 marg0, marg1, margtotal: Integer;
428 marg0Op, marg1Op, margtotalOp: Integer;
429 flexTotal: Integer = 0; // total sum of flex fields
430 spaceLeft: Integer = 0;
431 dopad: Boolean = false;
432 prevpad: Boolean = false;
433 maxdim: Integer = 0;
434 curpos: Integer;
435 toadd: Integer;
436 pad: Integer;
437 osz: TLaySize;
438 begin
439 assert((boxidx >= 0) and (boxidx < Length(ctlist)));
440 assert((maindir = 0) or (maindir = 1));
441 // cache some parameters
442 me := @ctlist[boxidx];
443 suppdir := 1-maindir;
444 if (maindir = 0) then
445 begin
446 marg0 := me.margins.left;
447 marg1 := me.margins.right;
448 marg0Op := me.margins.top;
449 marg1Op := me.margins.bottom;
450 end
451 else
452 begin
453 marg0 := me.margins.top;
454 marg1 := me.margins.bottom;
455 marg0Op := me.margins.left;
456 marg1Op := me.margins.right;
457 end;
458 margtotal := marg0+marg1;
459 margtotalOp := marg0Op+marg1Op;
460 // horizontal boxes
461 pad := nmax(0, me.padding[maindir]);
462 // calc required space, count flexes
463 for lc in forVisibleChildren(boxidx) do
464 begin
465 if (lc.tempFlex > 0) then flexTotal += lc.tempFlex;
466 spaceLeft += nmax(0, lc.desiredsize[maindir]);
467 // insert padding if both current and previous children allow padding
468 dopad := (not lc.noPad);
469 if (prevpad) and (dopad) then spaceLeft += pad;
470 prevpad := dopad;
471 maxdim := nmax(maxdim, lc.desiredsize[suppdir]);
472 end;
473 // add margins
474 spaceLeft += margtotal;
475 maxdim += margtotalOp;
476 // fix box size
477 me.desiredsize[maindir] := nmax(spaceLeft, me.desiredsize[maindir]);
478 me.desiredsize[suppdir] := nmax(maxdim, me.desiredsize[suppdir]);
479 // calculate free space
480 spaceLeft := me.desiredsize[maindir]-spaceLeft;
481 // distribute children
482 dopad := false;
483 prevpad := false;
484 curpos := marg0;
485 for lc in forVisibleChildren(boxidx) do
486 begin
487 osz := lc.desiredsize;
488 // main direction
489 // insert padding if both current and previous children allow padding
490 dopad := (not lc.noPad);
491 if (prevpad) and (dopad) then curpos += pad;
492 prevpad := dopad;
493 lc.desiredpos[maindir] := curpos;
494 if (lc.desiredsize[maindir] < 0) then lc.desiredsize[maindir] := 0;
495 curpos += lc.desiredsize[maindir];
496 // fix flexbox size
497 //writeln(':lcidx=', lc.myidx, '; tempFlex=', lc.tempFlex, '; spaceLeft=', spaceLeft);
498 if (spaceLeft > 0) and (lc.tempFlex > 0) then
499 begin
500 toadd := trunc(spaceLeft*lc.tempFlex/flexTotal+0.5);
501 if (toadd > 0) then
502 begin
503 // size changed
504 // compensate (crudely) rounding errors
505 if (curpos+toadd > me.desiredsize[maindir]-margtotal) then toadd -= 1;
506 //writeln('***curpos=', curpos, '; toadd=', toadd, '; spaceLeft=', spaceLeft);
507 // fix size
508 lc.desiredsize[maindir] := lc.desiredsize[maindir]+toadd;
509 curpos += toadd;
510 end;
511 end;
512 // secondary direction: expand or align
513 if (lc.desiredsize[suppdir] < 0) then lc.desiredsize[suppdir] := 0;
514 lc.desiredpos[suppdir] := marg0Op; // left/top align
515 if (lc.expand) then lc.desiredsize[suppdir] := me.desiredsize[suppdir]-margtotalOp // expand
516 else if (lc.aligndir > 0) then lc.desiredpos[suppdir] := me.desiredsize[suppdir]-marg1Op-lc.desiredsize[suppdir] // right/bottom align
517 else if (lc.aligndir = 0) then lc.desiredpos[suppdir] := (me.desiredsize[suppdir]-lc.desiredsize[suppdir]) div 2; // center
518 lc.desiredsize[suppdir] := nmax(lc.desiredsize[suppdir], osz[suppdir]);
519 // relayout children if size was changed
520 if (not osz.equals(lc.desiredsize)) then
521 begin
522 if (lc.inGroup) then groupElementChanged := true;
523 layBox(lc.myidx);
524 end;
525 end;
526 end;
529 // do box layouting; call `layBox()` recursively if necessary
530 procedure TFlexLayouterBase.layBox (boxidx: LayControlIdx);
531 var
532 me: PLayControl;
533 lc: PLayControl;
534 osz: TLaySize;
535 begin
536 if (boxidx < 0) or (boxidx >= Length(ctlist)) then exit;
537 me := @ctlist[boxidx];
538 // if we have no children, there's nothing to do
539 if (me.firstChild <> -1) then
540 begin
541 while true do
542 begin
543 osz := me.desiredsize;
544 // layout all children
545 for lc in forVisibleChildren(boxidx) do layBox(lc.myidx);
546 // distribute children
547 if (me.horizBox) then distributeChildren(me.myidx, 0) else distributeChildren(me.myidx, 1);
548 // relayout children if size was changed
549 if (osz.equals(me.desiredsize)) then break;
550 if (me.inGroup) then groupElementChanged := true;
551 end;
552 end;
553 end;
556 procedure TFlexLayouterBase.secondPass ();
557 var
558 secondAgain: Boolean;
559 gtype: Integer;
560 maxsz: Integer;
561 grp: PLayGroup;
562 f, c: Integer;
563 cidx: LayControlIdx;
564 ct: PLayControl;
565 loopsLeft: Integer = 64;
566 begin
567 while (loopsLeft > 0) do
568 begin
569 Dec(loopsLeft);
570 layBox(0);
571 secondAgain := false;
572 if (groupElementChanged) then
573 begin
574 secondAgain := true;
575 groupElementChanged := false;
576 // fix group sizes
577 for gtype := 0 to 1 do
578 begin
579 for f := 0 to High(groups[gtype]) do
580 begin
581 grp := @groups[gtype][f];
582 maxsz := 0;
583 for c := 0 to High(grp.ctls) do
584 begin
585 cidx := grp.ctls[c];
586 ct := @ctlist[cidx];
587 maxsz := nmax(maxsz, ct.desiredsize[gtype]);
588 end;
589 for c := 0 to High(grp.ctls) do
590 begin
591 cidx := grp.ctls[c];
592 ct := @ctlist[cidx];
593 ct.desiredsize[gtype] := maxsz;
594 end;
595 end;
596 end;
597 end;
598 // don't change group control sizes anymore
599 for f := 0 to High(ctlist) do
600 begin
601 ct := @ctlist[f];
602 if (ct.inGroup) then
603 begin
604 ct.expand := false; // don't expand grouped controls anymore
605 ct.tempFlex := 0; // don't change control size anymore
606 end;
607 end;
608 if (not secondAgain) then break;
609 end;
610 end;
613 procedure TFlexLayouterBase.thirdPass ();
614 var
615 f: Integer;
616 begin
617 for f := 0 to High(ctlist) do
618 begin
619 ctlist[f].ctl.setActualSizePos(ctlist[f].desiredpos, ctlist[f].desiredsize);
620 end;
621 end;
624 procedure TFlexLayouterBase.layout ();
625 begin
626 if (Length(ctlist) = 0) then exit;
627 ctlist[0].desiredpos := TLayPos.Create(0, 0);
628 firstPass();
629 //writeln('============== AFTER FIRST PASS =============='); dump();
630 secondPass();
631 //writeln('============== AFTER SECOND PASS =============='); dump();
632 thirdPass();
633 end;
636 procedure TFlexLayouterBase.dumpFlat ();
637 var
638 f: Integer;
639 lc: PLayControl;
640 ds, ms: TLaySize;
641 begin
642 for f := 0 to High(ctlist) do
643 begin
644 lc := @ctlist[f];
645 ds := lc.ctl.getDefSize;
646 ms := lc.ctl.getMaxSize;
647 writeln(lc.myidx, ': startsize:', lc.startsize.toString(), '; desiredsize=', lc.desiredsize.toString(), '; maxsize=', lc.maxsize.toString(), '; tempFlex=', lc.tempFlex, '; flags=', lc.flags,
648 '; parent=', lc.parent, '; next=', lc.nextSibling, '; child=', lc.firstChild, '; ctl.size=', ds.toString(), '; ctl.maxsize=', ms.toString());
649 end;
650 end;
653 procedure TFlexLayouterBase.dumpList (cidx: LayControlIdx; indent: Integer);
654 var
655 lc: PLayControl;
656 f: Integer;
657 begin
658 while (cidx >= 0) do
659 begin
660 lc := @ctlist[cidx];
661 for f := 0 to indent do write(' ');
662 if (not lc.visible) then write('!');
663 write(lc.myidx, ': ');
664 if (lc.ctl.id <> '') then write('<', lc.ctl.className, '> {', lc.ctl.id, '} ') else write('<', lc.ctl.className, '> ');
665 writeln('startsize:', lc.startsize.toString, '; desiredsize=', lc.desiredsize.toString, '; maxsize=', lc.maxsize.toString, '; tempFlex=', lc.tempFlex, '; despos=', lc.desiredpos.toString);
666 dumpList(lc.firstChild, indent+2);
667 cidx := lc.nextSibling;
668 end;
669 end;
672 procedure TFlexLayouterBase.dump ();
673 begin
674 dumpList(0, 0);
675 end;
678 end.