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 switch(t0.getFullName.toString){ 53 case "Label": 54 WindowElement we = new Label(toUTF32(t0.expectTagValue!string("text")), t0.expectTagValue!string("source"), 55 parseCoordinate(t0.expectTag("position"))); 56 e.elements[t0.expectValue!string()] = we; 57 dw.addElement(we,0); 58 break; 59 case "Button": 60 WindowElement we = new Button(toUTF32(t0.expectTagValue!string("text")), t0.expectTagValue!string("source"), 61 parseCoordinate(t0.expectTag("position"))); 62 e.elements[t0.expectValue!string()] = we; 63 dw.addElement(we,0); 64 break; 65 case "TextBox": 66 WindowElement we = new TextBox(toUTF32(t0.expectTagValue!string("text")), t0.expectTagValue!string("source"), 67 parseCoordinate(t0.expectTag("position"))); 68 e.elements[t0.expectValue!string()] = we; 69 dw.addElement(we,0); 70 break; 71 case "CheckBox": 72 WindowElement we = new CheckBox(toUTF32(t0.expectTagValue!string("text")), t0.expectTagValue!string("source"), 73 parseCoordinate(t0.expectTag("position"))); 74 e.elements[t0.expectValue!string()] = we; 75 dw.addElement(we,0); 76 break; 77 case "ListBox": 78 int[] columnWidths; 79 dstring[] columnTexts; 80 foreach(t1; t0.expectTag("header").tags){ 81 columnTexts ~= toUTF32(t1.values[0].get!string); 82 columnWidths ~= t1.values[1].get!int; 83 } 84 WindowElement we = new ListBox(t0.expectTagValue!string("source"), parseCoordinate(t0.expectTag("position")), [], 85 new ListBoxHeader(columnTexts, columnWidths)); 86 e.elements[t0.expectValue!string()] = we; 87 dw.addElement(we,0); 88 break; 89 case "RadioButtonGroup": 90 dstring[] options; 91 Value[] vals = t0.expectTag("options").values; 92 foreach(v; vals){ 93 options ~= toUTF32(v.get!string); 94 } 95 WindowElement we = new RadioButtonGroup(toUTF32(t0.expectTagValue!string("text")), t0.expectTagValue!string("source"), 96 parseCoordinate(t0.expectTag("position")), options, 16, 0); 97 e.elements[t0.expectValue!string()] = we; 98 dw.addElement(we,0); 99 break; 100 case "Window": 101 dw.setTitle(toUTF32(t0.expectTagValue!string("title"))); 102 dw.setSize(t0.expectTagValue!int("size:x"),t0.expectTagValue!int("size:y")); 103 break; 104 default: 105 break; 106 } 107 } 108 e.updateElementList; 109 } 110 public void generateDCode(string outputFile){ 111 string outputCode = "import PixelPerfectEngine.concrete.window \n\n", windowCtor, elementCtors, typeDefs; 112 foreach(t0; root.all.tags){ 113 if(t0.getFullName.toString != "Window"){ 114 elementCtors ~= "\t\t" ~ t0.getValue!string() ~ " = "; 115 typeDefs ~= "\t" ~ t0.name ~ " " ~ t0.getValue!string() ~ ";\n"; 116 } 117 switch(t0.getFullName.toString){ 118 case "Button", "Label", "TextBox", "CheckBox": 119 elementCtors ~= "new " ~ t0.getFullName.toString ~ "(\"" ~ t0.getTagValue!string("text") ~ "\"d, \"" ~ 120 t0.getTagValue!string("source") ~ "\", Coordinate(" ~ parseCoordinateIntoString(t0.getTag("position")) ~ "));\n"; 121 break; 122 case "RadioButtonGroup": 123 string options = "["; 124 foreach(v; t0.getTagValues("options")){ 125 options ~= "\"" ~ v.get!string() ~ "\"d, "; 126 } 127 if(options != "[") 128 options.length -= 2; 129 options ~= "]"; 130 elementCtors ~= "\t\tnew RadioButtonGroup(\"" ~ t0.getTagValue!string("text") ~ "\"d, \"" ~ t0.getTagValue!string("source") 131 ~ "\", Coordinate(" ~ parseCoordinateIntoString(t0.getTag("position")) ~ "), " ~ options ~ ",16,0);\n"; 132 break; 133 case "HSlider", "VSlider": 134 elementCtors ~= "\t\tnew " ~ t0.getFullName.toString ~ "(\"" ~ conv.to!string(t0.getTagValue!int("maxValue")) ~ 135 ", " ~ conv.to!string(t0.getTagValue!int("barLength")) ~ ", " ~ t0.getTagValue!string("source") ~ 136 "\", Coordinate(" ~ parseCoordinateIntoString(t0.getTag("position")) ~ "));\n"; 137 break; 138 case "ListBox": 139 string headerCtorA = "new ListBoxHeader([", headerCtorB = "], ["; 140 foreach(t1; t0.expectTag("header").tags){ 141 headerCtorA ~= "\"" ~ t1.values[0].get!string ~ "\"d, "; 142 headerCtorB ~= conv.to!string(t1.values[1].get!int) ~ ", "; 143 } 144 headerCtorA.length -= 2; 145 headerCtorB.length -= 2; 146 elementCtors ~= "\t\tnew ListBox(\"" ~ t0.getTagValue!string("source") 147 ~ "\", Coordinate(" ~ parseCoordinateIntoString(t0.getTag("position")) ~ "), [], " ~ 148 headerCtorA ~ headerCtorB ~ "]));\n"; 149 break; 150 case "Window": 151 outputCode ~= "public class " ~ t0.getValue!string() ~ " : Window {\n"; 152 string extraButtons; 153 Tag t1 = t0.getTag("extraButtons", null); 154 if(t1 !is null){ 155 if(t1.values.length){ 156 extraButtons = ", ["; 157 foreach(Value v; t1.values){ 158 extraButtons ~= v.get!string() ~ ", "; 159 } 160 extraButtons.length -= 2; 161 extraButtons = "]"; 162 } 163 } 164 windowCtor = "super(\"" ~ t0.getTagValue!string("title") ~ "\"d, Coordinate(0, 0, " ~ 165 conv.to!string(t0.getTagValue!int("size:x")) ~ ", " ~ conv.to!string(t0.getTagValue!int("size:y")) ~ " )" ~ 166 extraButtons ~ ");\n"; 167 break; 168 default: 169 break; 170 } 171 } 172 outputCode ~= typeDefs ~ "\tpublic this(){\n\t\t" ~ windowCtor ~ elementCtors ~ "\t}\n}\n"; 173 debug writeln(outputCode); 174 File filestream = File(outputFile, "w"); 175 //filestream.open(); 176 filestream.write(outputCode); 177 filestream.close(); 178 } 179 /** 180 * Returns a complete tag for editing a tree, etc. 181 */ 182 public Tag getTag(string target, string property){ 183 foreach(t0; root.all.tags){ 184 if(t0.getValue!string() == target){ 185 return t0.getTag(property); 186 } 187 } 188 return null; 189 } 190 /** 191 * Edits the value of an element. 192 * For MenuBar PopUpMenu trees, use the getTag function instead. 193 */ 194 public Value[] editValue(string target, string property, Value[] val){ 195 Value[] result; 196 foreach(t0; root.all.tags){ 197 if(t0.getValue!string() == target){ 198 result = t0.getTagValues(property); 199 t0.getTag(property).values = val; 200 return result; 201 } 202 } 203 return result; 204 } 205 public Value[] getValue(string target, string property){ 206 foreach(t0; root.all.tags){ 207 if(t0.getValue!string() == target){ 208 return t0.getTagValues(property); 209 } 210 } 211 return null; 212 } 213 public string renameWindow(string name){ 214 string oldname = root.getTag("Window").getValue!string(); 215 root.getTag("Window").values[0] = Value(name); 216 return oldname; 217 } 218 public string getWindowName(){ 219 return root.getTag("Window").getValue!string(); 220 } 221 public Value[] editWindowValue(string property, Value[] val){ 222 Value[] result = root.getTag("Window").getTag(property).values; 223 root.getTag("Window").getTag(property).values = val; 224 return result; 225 } 226 public Value[] getWindowValue(string property){ 227 return root.getTag("Window").getTag(property).values; 228 } 229 public void renameElement(string oldName, string newName){ 230 foreach(t; root.tags){ 231 if(t.getValue!string() == oldName){ 232 t.values[0] = Value(newName); 233 return; 234 } 235 } 236 } 237 public void addElement(ElementType type, string name, Coordinate initPos){ 238 foreach(t; root.tags){ 239 if(t.getValue!string() == name) 240 throw new ElementCollisionException("Similarly named element already exists!"); 241 } 242 Tag t1; 243 switch(type){ 244 case ElementType.Label: 245 t1 = new Tag(root, null, "Label", [Value(name)]); 246 new Tag(t1, null, "text", [Value(name)]); 247 break; 248 case ElementType.Button: 249 t1 = new Tag(root, null, "Button", [Value(name)]); 250 new Tag(t1, null, "text", [Value(name)]); 251 new Tag(t1, null, "icon", [Value("null")]); 252 break; 253 case ElementType.TextBox: 254 t1 = new Tag(root, null, "TextBox", [Value(name)]); 255 new Tag(t1, null, "text", [Value(name)]); 256 break; 257 case ElementType.ListBox: 258 t1 = new Tag(root, null, "ListBox", [Value(name)]); 259 Tag t2 = new Tag(t1, null, "header"); 260 new Tag(t2, null, null, [Value("col0"), Value(40)]); 261 new Tag(t2, null, null, [Value("col1"), Value(40)]); 262 break; 263 case ElementType.RadioButtonGroup: 264 t1 = new Tag(root, null, "RadioButtonGroup", [Value(name)]); 265 new Tag(t1, null, "text", [Value(name)]); 266 new Tag(t1, null, "options", [Value("opt0"), Value("opt1")]); 267 break; 268 case ElementType.CheckBox: 269 t1 = new Tag(root, null, "CheckBox", [Value(name)]); 270 new Tag(t1, null, "text", [Value(name)]); 271 break; 272 case ElementType.HSlider: 273 t1 = new Tag(root, null, "HSlider", [Value(name)]); 274 new Tag(t1, null, "barLength", [Value(1)]); 275 new Tag(t1, null, "maxValue", [Value(16)]); 276 break; 277 case ElementType.VSlider: 278 t1 = new Tag(root, null, "VSlider", [Value(name)]); 279 new Tag(t1, null, "barLength", [Value(1)]); 280 new Tag(t1, null, "maxValue", [Value(16)]); 281 break; 282 case ElementType.MenuBar: 283 t1 = new Tag(root, null, "MenuBar", [Value(name)]); 284 break; 285 default: 286 break; 287 } 288 new Tag(t1, null, "source", [Value(name)]); 289 new Tag(t1, null, "position", [Value(initPos.left), Value(initPos.top), Value(initPos.right), Value(initPos.bottom)]); 290 //debug writeln(t1); 291 } 292 public void addElement(Tag tag){ 293 foreach(t; root.tags){ 294 if(t.values[0].get!string() == tag.values[0].get!string()) 295 throw new ElementCollisionException("Similarly named element already exists!"); 296 } 297 root.add(tag); 298 } 299 public Tag removeElement(string name){ 300 foreach(t; root.tags){ 301 if(t.values[0].get!string() == name){ 302 t.remove; 303 return t; 304 } 305 } 306 return null; 307 } 308 } 309 class ElementCollisionException : Exception{ 310 @nogc @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable nextInChain = null) 311 { 312 super(msg, file, line, nextInChain); 313 } 314 315 @nogc @safe pure nothrow this(string msg, Throwable nextInChain, string file = __FILE__, size_t line = __LINE__) 316 { 317 super(msg, file, line, nextInChain); 318 } 319 }