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
65 private
66 type
69 public
85 public
103 public
116 private
121 private
129 // do box layouting; call `layBox()` recursively if necessary
138 public
139 type
141 private
146 public
154 public
158 // clear build lists
161 // build control and group lists
174 implementation
176 uses
177 utils;
180 // ////////////////////////////////////////////////////////////////////////// //
182 begin
189 function TFlexLayouterBase.TLayControl.horizBox (): Boolean; inline; begin result := ((flags and FlagHorizBox) <> 0); end;
190 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;
191 function TFlexLayouterBase.TLayControl.noPad (): Boolean; inline; begin result := ((flags and FlagNoPad) <> 0); end;
193 function TFlexLayouterBase.TLayControl.getExpand (): Boolean; inline; begin result := ((flags and FlagExpand) <> 0); end;
194 procedure TFlexLayouterBase.TLayControl.setExpand (v: Boolean); inline; begin if (v) then flags := flags or FlagExpand else flags := flags and (not FlagExpand); end;
196 function TFlexLayouterBase.TLayControl.alignLeft (): Boolean; inline; begin result := (aligndir < 0); end;
197 function TFlexLayouterBase.TLayControl.alignTop (): Boolean; inline; begin result := (aligndir < 0); end;
198 function TFlexLayouterBase.TLayControl.alignRight (): Boolean; inline; begin result := (aligndir > 0); end;
199 function TFlexLayouterBase.TLayControl.alignBottom (): Boolean; inline; begin result := (aligndir > 0); end;
200 function TFlexLayouterBase.TLayControl.alignCenter (): Boolean; inline; begin result := (aligndir = 0); end;
203 begin
208 // ////////////////////////////////////////////////////////////////////////// //
209 constructor TFlexLayouterBase.TChildrenEnumerator.Create (constref actls: TLayCtlArray; acur: Integer; aonlyvis: Boolean);
210 begin
218 begin
220 begin
222 begin
225 end
226 else
227 begin
237 begin
242 begin
247 // ////////////////////////////////////////////////////////////////////////// //
249 begin
258 begin
265 begin
269 function TFlexLayouterBase.forVisibleChildren (cidx: LayControlIdx): TChildrenEnumerator; inline;
270 begin
276 begin
283 var
286 begin
290 begin
292 //if (msz.w = 0) or (msz.h = 0) then continue; // hidden controls will have zero maxsize, so skip 'em
297 begin
300 end
301 else
302 begin
315 procedure TFlexLayouterBase.appendToGroup (const gname: AnsiString; cidx: LayControlIdx; gidx: Integer);
316 var
319 begin
326 begin
328 begin
331 exit;
334 // new group
344 var
346 begin
348 begin
356 var
360 begin
363 begin
368 // if control is only one in a group, mark is as "not grouped"
370 begin
374 begin
376 begin
377 // unmark controls
379 begin
383 // remove this group
389 end
390 else
391 begin
399 // build control and group lists
401 begin
405 try
411 except
419 var
421 begin
430 //lc.startsize.w := nmax(0, lc.startsize.w);
431 //lc.startsize.h := nmax(0, lc.startsize.h);
449 var
452 begin
456 // if we have any groups, set "group element changed" flag, so third pass will fix 'em
458 begin
460 begin
462 break;
469 var
483 begin
486 // cache some parameters
490 begin
495 end
496 else
497 begin
505 // horizontal boxes
507 // calc required space, count flexes
509 begin
512 // insert padding if both current and previous children allow padding
518 // add margins
521 // fix box size
524 // calculate free space
526 // distribute children
531 begin
533 // main direction
534 // insert padding if both current and previous children allow padding
541 // fix flexbox size
542 //writeln(':lcidx=', lc.myidx, '; tempFlex=', lc.tempFlex, '; spaceLeft=', spaceLeft);
544 begin
547 begin
548 // size changed
549 // compensate (crudely) rounding errors
551 //writeln('***curpos=', curpos, '; toadd=', toadd, '; spaceLeft=', spaceLeft);
552 // fix size
557 // secondary direction: expand or align
561 else if (lc.aligndir > 0) then lc.desiredpos[suppdir] := me.desiredsize[suppdir]-marg1Op-lc.desiredsize[suppdir] // right/bottom align
562 else if (lc.aligndir = 0) then lc.desiredpos[suppdir] := (me.desiredsize[suppdir]-lc.desiredsize[suppdir]) div 2; // center
564 // relayout children if size was changed
566 begin
574 // do box layouting; call `layBox()` recursively if necessary
576 var
580 begin
583 // if we have no children, there's nothing to do
585 begin
587 begin
589 // layout all children
591 // distribute children
593 // relayout children if size was changed
602 var
612 begin
614 begin
619 begin
622 // fix group sizes
624 begin
626 begin
630 begin
636 begin
644 // don't change group control sizes anymore
646 begin
649 begin
651 end
652 else
653 begin
665 var
667 begin
669 begin
676 begin
680 //writeln('============== AFTER FIRST PASS =============='); dump();
682 //writeln('============== AFTER SECOND PASS =============='); dump();
688 var
692 begin
694 begin
698 writeln(lc.myidx, ': startsize:', lc.startsize.toString(), '; desiredsize=', lc.desiredsize.toString(), '; maxsize=', lc.maxsize.toString(), '; tempFlex=', lc.tempFlex, '; flags=', lc.flags,
699 '; parent=', lc.parent, '; next=', lc.nextSibling, '; child=', lc.firstChild, '; ctl.size=', ds.toString(), '; ctl.maxsize=', ms.toString());
705 var
708 begin
710 begin
715 if (lc.ctl.id <> '') then write('<', lc.ctl.className, '> {', lc.ctl.id, '} ') else write('<', lc.ctl.className, '> ');
716 writeln('startsize:', lc.startsize.toString, '; desiredsize=', lc.desiredsize.toString, '; maxsize=', lc.maxsize.toString, '; tempFlex=', lc.tempFlex, '; despos=', lc.desiredpos.toString);
724 begin