1 module serializer;
2
3 import sdlang;
4 import editor;
5 import types;
6 import pixelperfectengine.graphics.common;
7 import pixelperfectengine.concrete.elements;
8 import std.utf;
9 import std.stdio;
10 import conv = std.conv;
11
12 public class WindowSerializer {
13 Tag root;
14 string filename;
15 public this(){
16 root = new Tag(null, null);
17 Tag window = new Tag(root, null, "Window", [Value("window")]);
18 new Tag(window, null, "title", [Value("New Window")]);
19 new Tag(window, "size", "x", [Value(640)]);
20 new Tag(window, "size", "y", [Value(480)]);
21 new Tag(window, null, "extraButtons");
22 }
23 public this(string filename) {
24 this.filename = filename;
25 }
26 public void store(string filename) {
27 this.filename = filename;
28 store();
29 }
30 public @property @nogc string getFilename() {
31 return filename;
32 }
33 public void store() {
34 import std.string : toStringz;
35 string fileout = root.toSDLDocument("\t",1);
36 debug writeln(fileout);
37 File filestream = File(filename, "w");
38 //filestream.open();
39 filestream.write(fileout);
40 filestream.close();
41 }
42 private Coordinate parseCoordinate(Tag t){
43 return Coordinate(t.values[0].get!int,t.values[1].get!int,t.values[2].get!int,t.values[3].get!int);
44 }
45 private string parseCoordinateIntoString(Tag t){
46 return conv.to!string(t.values[0].get!int) ~ ", " ~ conv.to!string(t.values[1].get!int) ~ ", " ~
47 conv.to!string(t.values[2].get!int) ~ ", " ~ conv.to!string(t.values[3].get!int);
48 }
49 public void deserialize(DummyWindow dw, Editor e) {
50 root = parseFile(filename);
51 foreach(t0; root.all.tags){
52 string name = t0.expectValue!string(), type;
53 WindowElement we;
54 switch(t0.getFullName.toString){
55 case "Label":
56 we = new Label(toUTF32(t0.expectTagValue!string("text")), t0.expectTagValue!string("source"),
57 parseCoordinate(t0.expectTag("position")));
58 dw.addElement(we);
59 type = "Label";
60 break;
61 case "Button":
62 we = new Button(toUTF32(t0.expectTagValue!string("text")), t0.expectTagValue!string("source"),
63 parseCoordinate(t0.expectTag("position")));
64 dw.addElement(we);
65 type = "Button";
66 break;
67 case "SmallButton":
68 break;
69 case "TextBox":
70 we = new TextBox(toUTF32(t0.expectTagValue!string("text")), t0.expectTagValue!string("source"),
71 parseCoordinate(t0.expectTag("position")));
72 dw.addElement(we);
73 type = "TextBox";
74 break;
75 case "SmallCheckBox":
76 break;
77 case "CheckBox":
78 we = new CheckBox(toUTF32(t0.expectTagValue!string("text")), t0.expectTagValue!string("source"),
79 parseCoordinate(t0.expectTag("position")));
80 dw.addElement(we);
81 type = "CheckBox";
82 break;
83 case "SmallRadioButton":
84 break;
85 case "RadioButton":
86 we = new RadioButton(toUTF32(t0.expectTagValue!string("text")), t0.expectTagValue!string("source"),
87 parseCoordinate(t0.expectTag("position")));
88 dw.addElement(we);
89 type = "RadioButton";
90 break;
91 case "ListView":
92 int[] columnWidths;
93 dstring[] columnTexts;
94 const int headerHeight = t0.expectTag("header").expectValue!int();
95 foreach(t1; t0.expectTag("header").tags){
96 columnTexts ~= toUTF32(t1.values[0].get!string);
97 columnWidths ~= t1.values[1].get!int;
98 }
99 we = new ListView(new ListViewHeader(headerHeight, columnWidths, columnTexts), [],
100 t0.expectTagValue!string("source"), parseCoordinate(t0.expectTag("position")));
101 dw.addElement(we);
102 type = "ListView";
103 break;
104 case "Window":
105 dw.setTitle(toUTF32(t0.expectTagValue!string("title")));
106 dw.setSize(t0.expectTagValue!int("size:x"),t0.expectTagValue!int("size:y"));
107 type = "Window";
108 break;
109 case "HorizScrollBar":
110 we = new HorizScrollBar(t0.expectTagValue!int("maxValue"), t0.expectTagValue!string("source"),
111 parseCoordinate(t0.expectTag("position")));
112 dw.addElement(we);
113 type = "HorizScrollBar";
114 break;
115 case "VertScrollBar":
116 we = new VertScrollBar(t0.expectTagValue!int("maxValue"), t0.expectTagValue!string("source"),
117 parseCoordinate(t0.expectTag("position")));
118 dw.addElement(we);
119 type = "VertScrollBar";
120 break;
121 default:
122 break;
123 }
124 if (type != "Window") {
125 e.elements[name] = ElementInfo(we, name, type);
126 //e.elementTypes[name] = type;
127 }
128 }
129 e.updateElementList;
130 }
131 public void generateDCode(string outputFile){
132 string outputCode = "import pixelperfectengine.concrete.window; \n\n", windowCtor, elementCtors, typeDefs;
133 foreach(t0; root.all.tags){
134 string typeName = t0.name;
135 switch (typeName) {
136 case "Window": break;
137 case "SmallRadioButton":
138 elementCtors ~= "\t\t" ~ t0.getValue!string() ~ " = ";
139 typeDefs ~= "\t" ~ "RadioButton" ~ " " ~ t0.getValue!string() ~ ";\n";
140 break;
141 case "SmallCheckBox":
142 elementCtors ~= "\t\t" ~ t0.getValue!string() ~ " = ";
143 typeDefs ~= "\t" ~ "CheckBox" ~ " " ~ t0.getValue!string() ~ ";\n";
144 break;
145 default:
146 elementCtors ~= "\t\t" ~ t0.getValue!string() ~ " = ";
147 typeDefs ~= "\t" ~ typeName ~ " " ~ t0.getValue!string() ~ ";\n";
148 break;
149 }
150 switch(typeName){
151 case "Button", "Label", "TextBox", "CheckBox", "RadioButton":
152 elementCtors ~= "new " ~ typeName ~ "(\"" ~ t0.getTagValue!string("text") ~ "\"d, \"" ~
153 t0.getTagValue!string("source") ~ "\", Box(" ~ parseCoordinateIntoString(t0.getTag("position")) ~ "));\n";
154 break;
155 case "HorizScrollBar", "VertScrollBar":
156 elementCtors ~= "new " ~ typeName ~ "(\"" ~ conv.to!string(t0.getTagValue!int("maxValue")) ~ ", \"" ~
157 t0.getTagValue!string("source") ~ "\", Box(" ~ parseCoordinateIntoString(t0.getTag("position")) ~ "));\n";
158 break;
159 case "ListView":
160 elementCtors ~= "new ListView(new ListViewHeader(" ~ conv.to!string(t0.getTagValue!int("header")) ~ ", ";
161 string intArr = "[", strArr = "[";
162 foreach (t1 ; t0.expectTag("header").tags) {
163 intArr ~= conv.to!string(t1.getValue!int()) ~ " ,";
164 strArr ~= "\"" ~ t1.getValue!string() ~ "\" ,";
165 }
166 intArr = intArr[0..$-2] ~ "]";
167 strArr = strArr[0..$-2] ~ "]";
168 elementCtors ~= intArr ~ ", " ~ strArr ~ "), null, \"" ~
169 t0.getTagValue!string("source") ~ "\", Box(" ~ parseCoordinateIntoString(t0.getTag("position")) ~ "));\n";
170 break;
171 case "Window":
172 outputCode ~= "public class " ~ t0.getValue!string() ~ " : Window {\n";
173 //string extraButtons;
174 /+Tag t1 = t0.getTag("extraButtons", null);
175 if(t1 !is null){
176 if(t1.values.length){
177 extraButtons = ", [";
178 foreach(Value v; t1.values){
179 extraButtons ~= v.get!string() ~ ", ";
180 }
181 extraButtons.length -= 2;
182 extraButtons = "]";
183 }
184 }+/
185 /+windowCtor = "super(\"" ~ t0.getTagValue!string("title") ~ "\"d, Box(0, 0, " ~
186 conv.to!string(t0.getTagValue!int("size:x")) ~ ", " ~ conv.to!string(t0.getTagValue!int("size:y")) ~ " )" ~
187 extraButtons ~ ");\n";+/
188 windowCtor = "super(Box(0, 0, " ~ conv.to!string(t0.getTagValue!int("size:x")) ~ ", " ~
189 conv.to!string(t0.getTagValue!int("size:y")) ~ "), \"" ~ t0.getTagValue!string("title") ~ "\");\n";
190 break;
191 default:
192 break;
193 }
194 }
195 outputCode ~= typeDefs ~ "\tpublic this(){\n\t\t" ~ windowCtor ~ elementCtors ~ "\t}\n}\n";
196 debug writeln(outputCode);
197 File filestream = File(outputFile, "w");
198 //filestream.open();
199 filestream.write(outputCode);
200 filestream.close();
201 }
202 /**
203 * Returns a complete tag for editing a tree, etc.
204 */
205 public Tag getTag(string target, string property){
206 foreach(t0; root.all.tags){
207 if(t0.getValue!string() == target){
208 return t0.getTag(property);
209 }
210 }
211 return null;
212 }
213 /**
214 * Replaces an existing tag with a new one.
215 * Params:
216 * target = The name of the window element, which tag must be replaced.
217 * property = The name of the property Tag.
218 * newTag = The new tag to be used in the place of the old
219 * Returns: The old tag as a backup.
220 */
221 public Tag replaceTag(string target, string property, Tag newTag) {
222 foreach(Tag t0; root.all.tags){
223 if(t0.getValue!string() == target){
224 Tag oldTag = t0.getTag(property);
225 oldTag.remove();
226 t0.add(newTag);
227 return oldTag;
228 }
229 }
230 return null;
231 }
232 /**
233 * Edits the value of an element.
234 * For MenuBar PopUpMenu trees, use the getTag function instead.
235 */
236 public Value[] editValue(string target, string property, Value[] val){
237 Value[] result;
238 foreach(t0; root.all.tags){
239 if(t0.getValue!string() == target){
240 result = t0.getTagValues(property);
241 t0.getTag(property).values = val;
242 return result;
243 }
244 }
245 return result;
246 }
247 public Value[] getValue(string target, string property){
248 foreach(t0; root.all.tags){
249 if(t0.getValue!string() == target){
250 return t0.getTagValues(property);
251 }
252 }
253 return null;
254 }
255 public string renameWindow(string name){
256 string oldname = root.getTag("Window").getValue!string();
257 root.getTag("Window").values[0] = Value(name);
258 return oldname;
259 }
260 public string getWindowName(){
261 return root.getTag("Window").getValue!string();
262 }
263 public Value[] editWindowValue(string property, Value[] val){
264 Value[] result = root.getTag("Window").getTag(property).values;
265 root.getTag("Window").getTag(property).values = val;
266 return result;
267 }
268 public Value[] getWindowValue(string property){
269 return root.getTag("Window").getTag(property).values;
270 }
271 public void renameElement(string oldName, string newName){
272 foreach(t; root.tags){
273 if(t.getValue!string() == oldName){
274 t.values[0] = Value(newName);
275 return;
276 }
277 }
278 }
279 public void addElement(string type, string name, Coordinate initPos){
280 foreach(t; root.tags){
281 if(t.getValue!string() == name)
282 throw new ElementCollisionException("Similarly named element already exists!");
283 }
284 Tag t1 = new Tag(root, null, type, [Value(name)]);
285 switch(type){
286 case "Label", "TextBox", "RadioButton", "CheckBox":
287 new Tag(t1, null, "text", [Value(name)]);
288 break;
289 case "Button":
290 new Tag(t1, null, "icon", [Value("null")]);
291 goto case "Label";
292 case "ListView":
293 Tag t2 = new Tag(t1, null, "header", [Value(16)]);
294 new Tag(t2, null, null, [Value("col0"), Value(40)]);
295 new Tag(t2, null, null, [Value("col1"), Value(40)]);
296 break;
297 case "HorizScrollBar", "VertScrollBar":
298 //new Tag(t1, null, "barLength", [Value(1)]);
299 new Tag(t1, null, "maxValue", [Value(16)]);
300 break;
301 case "MenuBar":
302 Tag t2 = new Tag(t1, null, "options");
303 Tag t3 = new Tag(t2, null, null, [Value("opt0")]);
304 new Tag(t3, null, null, [Value("opt0_0")]);
305 new Tag(t3, null, null, [Value("opt0_1")]);
306 Tag t4 = new Tag(t2, null, null, [Value("opt1")]);
307 new Tag(t4, null, null, [Value("opt1_0")]);
308 new Tag(t4, null, null, [Value("opt1_1")]);
309 break;
310 default:
311 break;
312 }
313 new Tag(t1, null, "source", [Value(name)]);
314 new Tag(t1, null, "position", [Value(initPos.left), Value(initPos.top), Value(initPos.right), Value(initPos.bottom)]);
315 //debug writeln(t1);
316 }
317 public void addElement(Tag tag){
318 foreach(t; root.tags){
319 if(t.values[0].get!string() == tag.values[0].get!string())
320 throw new ElementCollisionException("Similarly named element already exists!");
321 }
322 root.add(tag);
323 }
324 public Tag removeElement(string name){
325 foreach(t; root.tags){
326 if(t.values[0].get!string() == name){
327 t.remove;
328 return t;
329 }
330 }
331 return null;
332 }
333 }
334 class ElementCollisionException : Exception{
335 @nogc @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable nextInChain = null)
336 {
337 super(msg, file, line, nextInChain);
338 }
339
340 @nogc @safe pure nothrow this(string msg, Throwable nextInChain, string file = __FILE__, size_t line = __LINE__)
341 {
342 super(msg, file, line, nextInChain);
343 }
344 }