a941f554dda7c9a76fe95319c90721b4113ebcb3
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}
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
49 public
52 private
55 private
56 // flags
57 const
61 // internal
64 private
65 type
68 public
84 public
102 public
115 private
120 private
127 // do box layouting; call `layBox()` recursively if necessary
136 public
137 type
139 private
144 public
152 public
156 // clear build lists
159 // build control and group lists
172 implementation
174 uses
175 utils;
178 // ////////////////////////////////////////////////////////////////////////// //
180 begin
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;
201 begin
206 // ////////////////////////////////////////////////////////////////////////// //
207 constructor TFlexLayouterBase.TChildrenEnumerator.Create (constref actls: TLayCtlArray; acur: Integer; aonlyvis: Boolean);
208 begin
216 begin
218 begin
220 begin
223 end
224 else
225 begin
235 begin
240 begin
245 // ////////////////////////////////////////////////////////////////////////// //
247 begin
256 begin
263 begin
267 function TFlexLayouterBase.forVisibleChildren (cidx: LayControlIdx): TChildrenEnumerator; inline;
268 begin
274 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
317 begin
323 begin
325 begin
328 exit;
331 // new group
341 var
344 begin
346 begin
354 // build control and group lists
356 begin
360 try
367 except
375 var
377 begin
386 //lc.startsize.w := nmax(0, lc.startsize.w);
387 //lc.startsize.h := nmax(0, lc.startsize.h);
405 var
408 begin
411 // if we have any groups, set "group element changed" flag, so third pass will fix 'em
413 begin
415 begin
417 break;
424 var
438 begin
441 // cache some parameters
445 begin
450 end
451 else
452 begin
460 // horizontal boxes
462 // calc required space, count flexes
464 begin
467 // insert padding if both current and previous children allow padding
473 // add margins
476 // fix box size
479 // calculate free space
481 // distribute children
486 begin
488 // main direction
489 // insert padding if both current and previous children allow padding
496 // fix flexbox size
497 //writeln(':lcidx=', lc.myidx, '; tempFlex=', lc.tempFlex, '; spaceLeft=', spaceLeft);
499 begin
502 begin
503 // size changed
504 // compensate (crudely) rounding errors
506 //writeln('***curpos=', curpos, '; toadd=', toadd, '; spaceLeft=', spaceLeft);
507 // fix size
512 // secondary direction: expand or align
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
519 // relayout children if size was changed
521 begin
529 // do box layouting; call `layBox()` recursively if necessary
531 var
535 begin
538 // if we have no children, there's nothing to do
540 begin
542 begin
544 // layout all children
546 // distribute children
548 // relayout children if size was changed
557 var
566 begin
568 begin
573 begin
576 // fix group sizes
578 begin
580 begin
584 begin
590 begin
598 // don't change group control sizes anymore
600 begin
603 begin
614 var
616 begin
618 begin
625 begin
629 //writeln('============== AFTER FIRST PASS =============='); dump();
631 //writeln('============== AFTER SECOND PASS =============='); dump();
637 var
641 begin
643 begin
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());
654 var
657 begin
659 begin
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);
673 begin