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 				
160 				case "Window":
161 					outputCode ~= "public class " ~ t0.getValue!string() ~ " : Window {\n";
162 					//string extraButtons;
163 					/+Tag t1 = t0.getTag("extraButtons", null);
164 					if(t1 !is null){
165 						if(t1.values.length){
166 							extraButtons = ", [";
167 							foreach(Value v; t1.values){
168 								extraButtons ~= v.get!string() ~ ", ";
169 							}
170 							extraButtons.length -= 2;
171 							extraButtons = "]";
172 						}
173 					}+/
174 					/+windowCtor = "super(\"" ~ t0.getTagValue!string("title") ~ "\"d, Box(0, 0, " ~
175 							conv.to!string(t0.getTagValue!int("size:x")) ~ ", " ~ conv.to!string(t0.getTagValue!int("size:y")) ~ " )" ~
176 							extraButtons ~ ");\n";+/
177 					windowCtor = "super(Box(0, 0, " ~ conv.to!string(t0.getTagValue!int("size:x")) ~ ", " ~ 
178 							conv.to!string(t0.getTagValue!int("size:y")) ~ "), \"" ~ t0.getTagValue!string("title") ~ "\");\n";
179 					break;
180 				default:
181 					break;
182 			}
183 		}
184 		outputCode ~= typeDefs ~ "\tpublic this(){\n\t\t" ~ windowCtor ~ elementCtors ~ "\t}\n}\n";
185 		debug writeln(outputCode);
186 		File filestream = File(outputFile, "w");
187 		//filestream.open();
188 		filestream.write(outputCode);
189 		filestream.close();
190 	}
191 	/**
192 	 * Returns a complete tag for editing a tree, etc.
193 	 */
194 	public Tag getTag(string target, string property){
195 		foreach(t0; root.all.tags){
196 			if(t0.getValue!string() == target){
197 				return t0.getTag(property);
198 			}
199 		}
200 		return null;
201 	}
202 	/**
203 	 * Edits the value of an element.
204 	 * For MenuBar PopUpMenu trees, use the getTag function instead.
205 	 */
206 	public Value[] editValue(string target, string property, Value[] val){
207 		Value[] result;
208 		foreach(t0; root.all.tags){
209 			if(t0.getValue!string() == target){
210 				result = t0.getTagValues(property);
211 				t0.getTag(property).values = val;
212 				return result;
213 			}
214 		}
215 		return result;
216 	}
217 	public Value[] getValue(string target, string property){
218 		foreach(t0; root.all.tags){
219 			if(t0.getValue!string() == target){
220 				return t0.getTagValues(property);
221 			}
222 		}
223 		return null;
224 	}
225 	public string renameWindow(string name){
226 		string oldname = root.getTag("Window").getValue!string();
227 		root.getTag("Window").values[0] = Value(name);
228 		return oldname;
229 	}
230 	public string getWindowName(){
231 		return root.getTag("Window").getValue!string();
232 	}
233 	public Value[] editWindowValue(string property, Value[] val){
234 		Value[] result = root.getTag("Window").getTag(property).values;
235 		root.getTag("Window").getTag(property).values = val;
236 		return result;
237 	}
238 	public Value[] getWindowValue(string property){
239 		return root.getTag("Window").getTag(property).values;
240 	}
241 	public void renameElement(string oldName, string newName){
242 		foreach(t; root.tags){
243 			if(t.getValue!string() == oldName){
244 				t.values[0] = Value(newName);
245 				return;
246 			}
247 		}
248 	}
249 	public void addElement(string type, string name, Coordinate initPos){
250 		foreach(t; root.tags){
251 			if(t.getValue!string() == name)
252 				throw new ElementCollisionException("Similarly named element already exists!");
253 		}
254 		Tag t1 = new Tag(root, null, type, [Value(name)]);
255 		switch(type){
256 			case "Label", "TextBox", "RadioButton", "CheckBox":
257 				new Tag(t1, null, "text", [Value(name)]);
258 				break;
259 			case "Button":
260 				new Tag(t1, null, "icon", [Value("null")]);
261 				goto case "Label";
262 			case "ListView":
263 				Tag t2 = new Tag(t1, null, "header", [Value(16)]);
264 				new Tag(t2, null, null, [Value("col0"), Value(40)]);
265 				new Tag(t2, null, null, [Value("col1"), Value(40)]);
266 				break;
267 			case "HorizScrollBar", "VertScrollBar":
268 				//new Tag(t1, null, "barLength", [Value(1)]);
269 				new Tag(t1, null, "maxValue", [Value(16)]);
270 				break;
271 			case "MenuBar":
272 				Tag t2 = new Tag(t1, null, "options");
273 				Tag t3 = new Tag(t2, null, null, [Value("opt0")]);
274 				new Tag(t3, null, null, [Value("opt0_0")]);
275 				new Tag(t3, null, null, [Value("opt0_1")]);
276 				Tag t4 = new Tag(t2, null, null, [Value("opt1")]);
277 				new Tag(t4, null, null, [Value("opt1_0")]);
278 				new Tag(t4, null, null, [Value("opt1_1")]);
279 				break;
280 			default:
281 				break;
282 		}
283 		new Tag(t1, null, "source", [Value(name)]);
284 		new Tag(t1, null, "position", [Value(initPos.left), Value(initPos.top), Value(initPos.right), Value(initPos.bottom)]);
285 		//debug writeln(t1);
286 	}
287 	public void addElement(Tag tag){
288 		foreach(t; root.tags){
289 			if(t.values[0].get!string() == tag.values[0].get!string())
290 				throw new ElementCollisionException("Similarly named element already exists!");
291 		}
292 		root.add(tag);
293 	}
294 	public Tag removeElement(string name){
295 		foreach(t; root.tags){
296 			if(t.values[0].get!string() == name){
297 				t.remove;
298 				return t;
299 			}
300 		}
301 		return null;
302 	}
303 }
304 class ElementCollisionException : Exception{
305 	@nogc @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable nextInChain = null)
306     {
307         super(msg, file, line, nextInChain);
308     }
309 
310     @nogc @safe pure nothrow this(string msg, Throwable nextInChain, string file = __FILE__, size_t line = __LINE__)
311     {
312         super(msg, file, line, nextInChain);
313     }
314 }