egra: some agg mini optimisations (rendering, hittest)
[iv.d.git] / flexlay2_test / laytest.d
blobc2b64667d988c2075c5f48d5bc125c2bf5cd7d0f
1 import std.stdio;
3 import iv.flexlay2;
6 // ////////////////////////////////////////////////////////////////////////// //
7 ///
8 enum FuiDir {
9 Horiz, ///
10 Vert, ///
14 // ////////////////////////////////////////////////////////////////////////// //
15 /// point
16 public align(1) struct FuiPoint {
17 align(1):
18 int x, y;
20 nothrow @safe @nogc:
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 == "/") {
25 pragma(inline, true);
26 mixin("x"~op~"=v; y"~op~"=v;");
29 void opOpAssign(string op) (in auto ref FuiPoint pt) if (op == "+" || op == "-") {
30 pragma(inline, true);
31 mixin("x"~op~"=pt.x; y"~op~"=pt.y;");
34 FuiPoint opBinary(string op) (in auto ref FuiPoint pt) if (op == "+" || op == "-") {
35 pragma(inline, true);
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 == "-") {
44 pragma(inline, true);
45 if (dir == FuiDir.Horiz) mixin("x "~op~"= v;"); else mixin("y "~op~"= v;");
50 // ////////////////////////////////////////////////////////////////////////// //
51 /// size
52 public align(1) struct FuiSize {
53 align(1):
54 int w, h;
56 nothrow @safe @nogc:
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 == "/") {
65 pragma(inline, true);
66 mixin("w"~op~"=v; h"~op~"=v;");
69 void opOpAssign(string op) (in auto ref FuiSize sz) if (op == "+" || op == "-") {
70 pragma(inline, true);
71 mixin("w"~op~"=sz.w; h"~op~"=sz.h;");
74 FuiSize opBinary(string op) (in auto ref FuiSize sz) if (op == "+" || op == "-") {
75 pragma(inline, true);
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; }
83 //FIXME: overflow!
84 void opIndexOpAssign(string op) (in int v, in FuiDir dir) if (op == "+" || op == "-") {
85 pragma(inline, true);
86 if (dir == FuiDir.Horiz) {
87 mixin("w "~op~"= v;");
88 if (w < 0) w = 0;
89 } else {
90 mixin("h "~op~"= v;");
91 if (h < 0) h = 0;
97 // ////////////////////////////////////////////////////////////////////////// //
98 /// UI box (container)
99 class FuiBox {
100 FuiBox parent;
101 FuiBox firstChild;
102 FuiBox nextSibling;
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
115 this () {}
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);
122 box.parent = this;
123 FuiBox lc = firstChild;
124 if (lc is null) {
125 firstChild = box;
126 } else {
127 while (lc.nextSibling) lc = lc.nextSibling;
128 lc.nextSibling = box;
132 public:
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;
145 ind(indent);
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");
154 dumpBox(this, 0);
159 void main () {
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; };
186 FuiBox root = null;
187 FuiBox ctr = null;
189 void newSpring (int flex) {
190 FuiBox box = new FuiBox(ctr);
191 box.flex = flex;
192 if (root is null) root = box;
195 void newBox (in FuiSize psz) {
196 FuiBox box = new FuiBox(ctr);
197 box.prefSize = psz;
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);
203 box.childDir = dir;
204 if (psz.w >= 0) box.prefSize.w = psz.w;
205 if (psz.h >= 0) box.prefSize.h = psz.h;
206 ctr = box;
207 if (root is null) root = box;
210 void closeContainer () {
211 assert(ctr !is null);
212 ctr = ctr.parent;
215 newContainer(FuiDir.Vert);
217 newContainer(FuiDir.Horiz, FuiSize(96, 16));
218 newSpring(1);
219 newBox(FuiSize(8, 17));
220 newBox(FuiSize(2, 0));
221 newBox(FuiSize(12, 17));
222 newSpring(1);
223 closeContainer();
225 newContainer(FuiDir.Horiz);
226 newSpring(1);
227 newBox(FuiSize(12, 6));
228 closeContainer();
230 closeContainer();
231 assert(ctr is null);
232 assert(root !is null);
234 root.dumpLayout();
235 lay.layout(root);
236 root.dumpLayout();