6 // ////////////////////////////////////////////////////////////////////////// //
14 // ////////////////////////////////////////////////////////////////////////// //
16 public align(1) struct FuiPoint
{
21 bool inside() (in auto ref FuiRect rc
) pure const { pragma(inline
, true); return (x
>= rc
.pos
.x
&& y
>= rc
.pos
.y
&& x
< rc
.pos
.x
+rc
.size
.w
&& y
< rc
.pos
.y
+rc
.size
.h
); }
22 bool inside() (in auto ref FuiSize sz
) pure const { pragma(inline
, true); return (x
>= 0 && y
>= 0 && x
< sz
.w
&& y
< sz
.h
); }
24 void opOpAssign(string op
) (in int v
) if (op
== "+" || op
== "-" || op
== "*" || op
== "/") {
26 mixin("x"~op
~"=v; y"~op
~"=v;");
29 void opOpAssign(string op
) (in auto ref FuiPoint pt
) if (op
== "+" || op
== "-") {
31 mixin("x"~op
~"=pt.x; y"~op
~"=pt.y;");
34 FuiPoint
opBinary(string op
) (in auto ref FuiPoint pt
) if (op
== "+" || op
== "-") {
36 mixin("return FuiPoint(x"~op
~"pt.x, y"~op
~"pt.y);");
39 int opIndex (in FuiDir dir
) pure const { pragma(inline
, true); return (dir
== FuiDir
.Horiz ? x
: y
); }
41 void opIndexAssign (in int v
, in FuiDir dir
) { pragma(inline
, true); if (dir
== FuiDir
.Horiz
) x
= v
; else y
= v
; }
43 void opIndexOpAssign(string op
) (in int v
, in FuiDir dir
) if (op
== "+" || op
== "-") {
45 if (dir
== FuiDir
.Horiz
) mixin("x "~op
~"= v;"); else mixin("y "~op
~"= v;");
50 // ////////////////////////////////////////////////////////////////////////// //
52 public align(1) struct FuiSize
{
57 @property bool valid () pure const { pragma(inline
, true); return (w
>= 0 && h
>= 0); }
58 @property bool empty () pure const { pragma(inline
, true); return (w
< 1 && h
< 1); }
60 bool inside() (in auto ref FuiPoint pt
) pure const { pragma(inline
, true); return (x
>= 0 && y
>= 0 && x
< w
&& y
< h
); }
62 void sanitize () { pragma(inline
, true); if (w
< 0) w
= 0; if (h
< 0) h
= 0; }
64 void opOpAssign(string op
) (in int v
) if (op
== "+" || op
== "-" || op
== "*" || op
== "/") {
66 mixin("w"~op
~"=v; h"~op
~"=v;");
69 void opOpAssign(string op
) (in auto ref FuiSize sz
) if (op
== "+" || op
== "-") {
71 mixin("w"~op
~"=sz.w; h"~op
~"=sz.h;");
74 FuiSize
opBinary(string op
) (in auto ref FuiSize sz
) if (op
== "+" || op
== "-") {
76 mixin("return FuiSize(w"~op
~"sz.w, h"~op
~"sz.h);");
79 int opIndex (in FuiDir dir
) pure const { pragma(inline
, true); return (dir
== FuiDir
.Horiz ? w
: h
); }
81 void opIndexAssign (in int v
, in FuiDir dir
) { pragma(inline
, true); if (dir
== FuiDir
.Horiz
) w
= v
; else h
= v
; }
84 void opIndexOpAssign(string op
) (in int v
, in FuiDir dir
) if (op
== "+" || op
== "-") {
86 if (dir
== FuiDir
.Horiz
) {
87 mixin("w "~op
~"= v;");
90 mixin("h "~op
~"= v;");
97 // ////////////////////////////////////////////////////////////////////////// //
98 /// UI box (container)
104 FuiSize minSize
; /// minimum size
105 FuiSize maxSize
= FuiSize(int.max
, int.max
); /// maximum size
106 FuiSize prefSize
; /// preferred (initial) size
108 FuiSize size
; /// box size
109 FuiSize finalSize
; /// final size (can be bigger than `size)`
110 FuiPoint finalPos
; /// final position (for the final size); relative to the parent origin
112 FuiDir childDir
= FuiDir
.Horiz
; /// children orientation
113 int flex
; /// <=0: not flexible
116 this (FuiBox aparent
) { if (aparent
!is null) aparent
.appendChild(this); }
118 void appendChild (FuiBox box
) {
119 assert(box
!is this);
120 if (box
is null) return;
121 assert(box
.parent
is null);
123 FuiBox lc
= firstChild
;
127 while (lc
.nextSibling
) lc
= lc
.nextSibling
;
128 lc
.nextSibling
= box
;
133 void dumpLayout (const(char)[] foname
=null) {
134 import core
.stdc
.stdio
: stderr
, fopen
, fclose
, fprintf
, fputc
;
135 import std
.internal
.cstring
;
137 auto fo
= (!foname
.length ? stderr
: fopen(foname
.tempCString
, "w"));
138 if (fo
is null) return;
139 scope(exit
) if (foname
.length
) fclose(fo
);
141 void ind (in int indent
) { foreach (immutable _
; 0..indent
) fputc(' ', fo
); }
143 void dumpBox (FuiBox id
, in int indent
) {
144 if (id
is null) return;
146 fo
.fprintf("Ctl#%08x: rpos:(%3d,%3d); rsize:(%3d,%3d); size:(%3d,%3d); pref:(%3d,%3d); flex:%02d; min:(%3d,%3d); max:(%3d,%3d)\n",
147 cast(uint)cast(void*)id
,
148 id
.finalPos
.x
, id
.finalPos
.y
, id
.finalSize
.w
, id
.finalSize
.h
, id
.size
.w
, id
.size
.h
,
149 id
.prefSize
.w
, id
.prefSize
.h
, id
.flex
, id
.minSize
.w
, id
.minSize
.h
, id
.maxSize
.w
, id
.maxSize
.h
);
150 for (id
= id
.firstChild
; id
!is null; id
= id
.nextSibling
) dumpBox(id
, indent
+2);
153 fprintf(fo
, "==== boxes ====\n");
160 alias BoxIdT
= FuiBox
;
162 FuiFlexLayouter
!BoxIdT lay
;
164 lay
.isValidBoxId
= delegate bool (BoxIdT id
) { return (id
!is null); };
166 lay
.firstChild
= delegate BoxIdT (BoxIdT id
) { return id
.firstChild
; };
167 lay
.nextSibling
= delegate BoxIdT (BoxIdT id
) { return id
.nextSibling
; };
169 lay
.getMinSize
= delegate int (BoxIdT id
, in bool horiz
) { return (horiz ? id
.minSize
.w
: id
.minSize
.h
); };
170 lay
.getMaxSize
= delegate int (BoxIdT id
, in bool horiz
) { return (horiz ? id
.maxSize
.w
: id
.maxSize
.h
); };
171 lay
.getPrefSize
= delegate int (BoxIdT id
, in bool horiz
) { return (horiz ? id
.prefSize
.w
: id
.prefSize
.h
); };
173 lay
.isHorizBox
= delegate bool (BoxIdT id
) { return (id
.childDir
== FuiDir
.Horiz
); };
175 lay
.getFlex
= delegate int (BoxIdT id
) { return id
.flex
; };
177 lay
.getSize
= delegate int (BoxIdT id
, in bool horiz
) { return (horiz ? id
.size
.w
: id
.size
.h
); };
178 lay
.setSize
= delegate void (BoxIdT id
, in bool horiz
, int val
) { if (horiz
) id
.size
.w
= val
; else id
.size
.h
= val
; };
180 lay
.getFinalSize
= delegate int (BoxIdT id
, in bool horiz
) { return (horiz ? id
.finalSize
.w
: id
.finalSize
.h
); };
181 lay
.setFinalSize
= delegate void (BoxIdT id
, in bool horiz
, int val
) { if (horiz
) id
.finalSize
.w
= val
; else id
.finalSize
.h
= val
; };
183 lay
.setFinalPos
= delegate void (BoxIdT id
, in bool horiz
, int val
) { if (horiz
) id
.finalPos
.x
= val
; else id
.finalPos
.y
= val
; };
189 void newSpring (int flex
) {
190 FuiBox box
= new FuiBox(ctr
);
192 if (root
is null) root
= box
;
195 void newBox (in FuiSize psz
) {
196 FuiBox box
= new FuiBox(ctr
);
198 if (root
is null) root
= box
;
201 void newContainer (in FuiDir dir
, in FuiSize psz
=FuiSize(int.min
, int.min
)) {
202 FuiBox box
= new FuiBox(ctr
);
204 if (psz
.w
>= 0) box
.prefSize
.w
= psz
.w
;
205 if (psz
.h
>= 0) box
.prefSize
.h
= psz
.h
;
207 if (root
is null) root
= box
;
210 void closeContainer () {
211 assert(ctr
!is null);
215 newContainer(FuiDir
.Vert
);
217 newContainer(FuiDir
.Horiz
, FuiSize(96, 16));
219 newBox(FuiSize(8, 17));
220 newBox(FuiSize(2, 0));
221 newBox(FuiSize(12, 17));
225 newContainer(FuiDir
.Horiz
);
227 newBox(FuiSize(12, 6));
232 assert(root
!is null);