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, version 3 of the License ONLY.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *)
16 {$INCLUDE ../shared/a_modes.inc}
18 (*
19 control default size will be increased by margins
20 negative margins are ignored
21 ControlT:
22 procedure layPrepare (); // called before registering control in layouter
23 function getDefSize (): TLaySize; // default size; <0: use max size
24 function getMargins (): TLayMargins;
25 function getPadding (): TLaySize; // children padding (each non-first child will get this on left/top)
26 function getMaxSize (): TLaySize; // max size; <0: set to some huge value
27 function getFlex (): Integer; // <=0: not flexible
28 function isHorizBox (): Boolean; // horizontal layout for children?
29 function noPad (): Boolean; // ignore padding in box direction for this control
30 function getAlign (): Integer; // aligning in non-main direction: <0: left/up; 0: center; >0: right/down
31 function getExpand (): Boolean; // expanding in non-main direction: `true` will ignore align and eat all available space
32 procedure setActualSizePos (constref apos: TLayPos; constref asize: TLaySize);
33 function getHGroup (): AnsiString; // empty: not grouped
34 function getVGroup (): AnsiString; // empty: not grouped
35 function nextSibling (): ControlT;
36 function firstChild (): ControlT;
37 *)
39 interface
41 uses
42 fui_common;
45 // ////////////////////////////////////////////////////////////////////////// //
46 type
48 public
51 private
54 private
55 // flags
56 const
60 // internal
64 private
65 type
68 public
84 public
102 public
115 private
120 private
128 // do box layouting; call `layBox()` recursively if necessary
137 public
138 type
140 private
145 public
153 public
157 // clear build lists
160 // build control and group lists
173 implementation
175 uses
176 utils;
179 // ////////////////////////////////////////////////////////////////////////// //
181 begin
188 function TFlexLayouterBase.TLayControl.horizBox (): Boolean; inline; begin result := ((flags and FlagHorizBox) <> 0); end;
189 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;
190 function TFlexLayouterBase.TLayControl.noPad (): Boolean; inline; begin result := ((flags and FlagNoPad) <> 0); end;
192 function TFlexLayouterBase.TLayControl.getExpand (): Boolean; inline; begin result := ((flags and FlagExpand) <> 0); end;
193 procedure TFlexLayouterBase.TLayControl.setExpand (v: Boolean); inline; begin if (v) then flags := flags or FlagExpand else flags := flags and (not FlagExpand); end;
195 function TFlexLayouterBase.TLayControl.alignLeft (): Boolean; inline; begin result := (aligndir < 0); end;
196 function TFlexLayouterBase.TLayControl.alignTop (): Boolean; inline; begin result := (aligndir < 0); end;
197 function TFlexLayouterBase.TLayControl.alignRight (): Boolean; inline; begin result := (aligndir > 0); end;
198 function TFlexLayouterBase.TLayControl.alignBottom (): Boolean; inline; begin result := (aligndir > 0); end;
199 function TFlexLayouterBase.TLayControl.alignCenter (): Boolean; inline; begin result := (aligndir = 0); end;
202 begin
207 // ////////////////////////////////////////////////////////////////////////// //
208 constructor TFlexLayouterBase.TChildrenEnumerator.Create (constref actls: TLayCtlArray; acur: Integer; aonlyvis: Boolean);
209 begin
217 begin
219 begin
221 begin
224 end
225 else
226 begin
236 begin
241 begin
246 // ////////////////////////////////////////////////////////////////////////// //
248 begin
257 begin
264 begin
268 function TFlexLayouterBase.forVisibleChildren (cidx: LayControlIdx): TChildrenEnumerator; inline;
269 begin
275 begin
282 var
285 begin
289 begin
291 //if (msz.w = 0) or (msz.h = 0) then continue; // hidden controls will have zero maxsize, so skip 'em
296 begin
299 end
300 else
301 begin
314 procedure TFlexLayouterBase.appendToGroup (const gname: AnsiString; cidx: LayControlIdx; gidx: Integer);
315 var
318 begin
325 begin
327 begin
330 exit;
333 // new group
343 var
345 begin
347 begin
355 var
359 begin
362 begin
367 // if control is only one in a group, mark is as "not grouped"
369 begin
373 begin
375 begin
376 // unmark controls
378 begin
382 // remove this group
388 end
389 else
390 begin
398 // build control and group lists
400 begin
404 try
410 except
418 var
420 begin
429 //lc.startsize.w := nmax(0, lc.startsize.w);
430 //lc.startsize.h := nmax(0, lc.startsize.h);
448 var
451 begin
455 // if we have any groups, set "group element changed" flag, so third pass will fix 'em
457 begin
459 begin
461 break;
468 var
482 begin
485 // cache some parameters
489 begin
494 end
495 else
496 begin
504 // horizontal boxes
506 // calc required space, count flexes
508 begin
511 // insert padding if both current and previous children allow padding
517 // add margins
520 // fix box size
523 // calculate free space
525 // distribute children
530 begin
532 // main direction
533 // insert padding if both current and previous children allow padding
540 // fix flexbox size
541 //writeln(':lcidx=', lc.myidx, '; tempFlex=', lc.tempFlex, '; spaceLeft=', spaceLeft);
543 begin
546 begin
547 // size changed
548 // compensate (crudely) rounding errors
550 //writeln('***curpos=', curpos, '; toadd=', toadd, '; spaceLeft=', spaceLeft);
551 // fix size
556 // secondary direction: expand or align
560 else if (lc.aligndir > 0) then lc.desiredpos[suppdir] := me.desiredsize[suppdir]-marg1Op-lc.desiredsize[suppdir] // right/bottom align
561 else if (lc.aligndir = 0) then lc.desiredpos[suppdir] := (me.desiredsize[suppdir]-lc.desiredsize[suppdir]) div 2; // center
563 // relayout children if size was changed
565 begin
573 // do box layouting; call `layBox()` recursively if necessary
575 var
579 begin
582 // if we have no children, there's nothing to do
584 begin
586 begin
588 // layout all children
590 // distribute children
592 // relayout children if size was changed
601 var
611 begin
613 begin
618 begin
621 // fix group sizes
623 begin
625 begin
629 begin
635 begin
643 // don't change group control sizes anymore
645 begin
648 begin
650 end
651 else
652 begin
664 var
666 begin
668 begin
675 begin
679 //writeln('============== AFTER FIRST PASS =============='); dump();
681 //writeln('============== AFTER SECOND PASS =============='); dump();
687 var
691 begin
693 begin
697 writeln(lc.myidx, ': startsize:', lc.startsize.toString(), '; desiredsize=', lc.desiredsize.toString(), '; maxsize=', lc.maxsize.toString(), '; tempFlex=', lc.tempFlex, '; flags=', lc.flags,
698 '; parent=', lc.parent, '; next=', lc.nextSibling, '; child=', lc.firstChild, '; ctl.size=', ds.toString(), '; ctl.maxsize=', ms.toString());
704 var
707 begin
709 begin
714 if (lc.ctl.id <> '') then write('<', lc.ctl.className, '> {', lc.ctl.id, '} ') else write('<', lc.ctl.className, '> ');
715 writeln('startsize:', lc.startsize.toString, '; desiredsize=', lc.desiredsize.toString, '; maxsize=', lc.maxsize.toString, '; tempFlex=', lc.tempFlex, '; despos=', lc.desiredpos.toString);
723 begin