1 module common; 2 3 /* 4 GUI technology stack: 5 * program text is parsed to 6 * DOM that is traversed by high level renderer that issues 7 * graphics command independent on anything like OS, drivers et al 8 * low level renderer that renders gfx command to target 9 * target - framebuffer, texture etc 10 11 every visual has x, y (origin), width and height. but all of them may be optional. for example the root visual has x and y equal to zero. Also child visuals parameter can be calculated and doen't need to be set. 12 13 Only mandatory values are: 14 current x, y, width and height. Current x and y are given in parent visual coordinate system. 15 count of widgets 16 direction 17 alignment 18 justification 19 wrapping 20 */ 21 22 /// What direction the children are laid out in 23 enum Direction { 24 row, // items are placed in row from start to end 25 column, // items are placed in column from start to end 26 rowReverse, // items are placed in row from end to start 27 columnReverse, // items are placed in column from end to start 28 } 29 /// Cross axis aligment 30 enum Alignment { 31 stretch, // items fill the parent in the direction of the cross axis 32 center, // items maintain their intrinsic dimensions, but are centered along the cross axis 33 start, // items are aligned at the start of the cross axis 34 end, // items are aligned at the end of the cross axis 35 } 36 37 /// Main axis alignment 38 enum Justification { 39 start, // items sit at the start of the main axis 40 end, // items sit at the end of the main axis 41 center, // items sit in the center of the main axis 42 around, // items are evenly distributed along the main axis, with a bit of space left at either end 43 between, // like `around` except that it doesn't leave any space at either end. 44 } 45 46 struct WorkArea 47 { 48 float x, y, w, h, margin, padding; 49 } 50 51 struct Attributes 52 { 53 import std.typecons : Nullable; 54 55 private Nullable!Direction _direction; 56 private Nullable!int _margin; 57 private Nullable!int _padding; 58 59 ref auto direction() 60 { 61 return _direction; 62 } 63 64 ref auto margin() 65 { 66 return _margin; 67 } 68 69 ref auto padding() 70 { 71 return _padding; 72 } 73 } 74 75 /// Full description of current renderer state 76 /// for debug use 77 struct RenderState 78 { 79 // node(widget) name 80 string name; 81 WorkArea area; 82 Direction direction; 83 84 // for debug purposes 85 long misc; 86 int nestingLevel; 87 } 88 89 class DomNode 90 { 91 bool state; 92 DomNode[] child; 93 Attributes attributes; 94 string name; 95 96 this(bool s, DomNode[] ch) 97 { 98 state = s; 99 child = ch; 100 } 101 } 102 103 auto makeDom(Data)(Data data) 104 { 105 import traverse : traverseImpl; 106 107 static struct DomMaker 108 { 109 DomNode[] current; 110 } 111 112 auto dommaker = DomMaker(); 113 dommaker.current ~= new DomNode(false, null); 114 traverseImpl!(domLeaf, domNodeEnter, domNodeLeave)(dommaker, data); 115 assert(dommaker.current.length); 116 assert(dommaker.current[0].child.length); 117 118 return dommaker.current[0].child[0]; 119 } 120 121 auto domLeaf(Context, Data)(ref Context ctx, Data data) 122 { 123 // do nothing 124 } 125 126 auto domNodeEnter(Context, Data)(ref Context ctx, Data data) 127 { 128 import std.array : back; 129 auto node = new DomNode(false, null); 130 node.name = typeof(data).stringof; 131 ctx.current.back.child ~= node; 132 ctx.current ~= node; 133 } 134 135 auto domNodeLeave(Context, Data)(ref Context ctx, Data data) 136 { 137 import std.array : popBack; 138 ctx.current.popBack; 139 } 140 141 void printDom(Context, Node)(ref Context ctx, Node mn) 142 { 143 import std.stdio; 144 import std.range; 145 146 write("\n", "-".repeat(ctx.indent).join, "state: "); 147 ctx.indent += 4; 148 scope(exit) ctx.indent -= 4; 149 write(mn.state, " '", mn.name, "' ", mn.child.length); 150 foreach(ch; mn.child) 151 printDom(ctx, ch); 152 }