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 }