1 /* 2 * Copyright (C) 2016-2017, by Laszlo Szeremi under the Boost license. 3 * 4 * Pixel Perfect Editor, graphics.outputScreen module 5 */ 6 7 module editor; 8 9 import PixelPerfectEngine.graphics.outputScreen; 10 import PixelPerfectEngine.graphics.raster; 11 import PixelPerfectEngine.graphics.layers; 12 import PixelPerfectEngine.graphics.paletteMan; 13 //import PixelPerfectEngine.extbmp.extbmp; 14 15 import PixelPerfectEngine.graphics.bitmap; 16 import PixelPerfectEngine.graphics.draw; 17 //import collision; 18 import PixelPerfectEngine.system.input; 19 import PixelPerfectEngine.system.file; 20 import PixelPerfectEngine.system.etc; 21 import PixelPerfectEngine.system.config; 22 import PixelPerfectEngine.system.systemUtility; 23 import std.stdio; 24 import std.conv; 25 import core.stdc..string : memcpy; 26 //import derelict.sdl2.sdl; 27 import bindbc.sdl; 28 import PixelPerfectEngine.concrete.window; 29 import PixelPerfectEngine.concrete.eventChainSystem; 30 import PixelPerfectEngine.map.mapformat; 31 32 //import converterdialog; 33 import windows.resizemap; 34 import windows.about; 35 import editorevents; 36 public import windows.layerlist; 37 public import windows.materiallist; 38 import document; 39 import windows.rasterwindow; 40 import windows.newtilelayer; 41 42 43 44 public class NewDocumentDialog : Window{ 45 public Editor ie; 46 private TextBox[] textBoxes; 47 public this(Coordinate size, dstring title){ 48 super(size, title); 49 } 50 public this(Editor ie){ 51 this(Box(10,10,220,150),"New Document"d); 52 this.ie = ie; 53 Button[] buttons; 54 Label[] labels; 55 buttons ~= new Button("Ok", "ok", Box(150,110,200,130)); 56 57 labels ~= new Label("Name:","",Box(5,20,80,39)); 58 labels ~= new Label("RasterX:","",Box(5,40,80,59)); 59 labels ~= new Label("RasterY:","",Box(5,60,80,79)); 60 //labels ~= new Label("N. of colors:","",Coordinate(5,80,120,99)); 61 textBoxes ~= new TextBox("newdocument","name",Box(81,20,200,39)); 62 textBoxes ~= new TextBox("424","rX",Box(121,40,200,59)); 63 textBoxes ~= new TextBox("240","rY",Box(121,60,200,79)); 64 //textBoxes ~= new TextBox("","pal",Coordinate(121,80,200,99)); 65 addElement(buttons[0]); 66 foreach(WindowElement we; labels){ 67 addElement(we); 68 } 69 foreach(TextBox we; textBoxes){ 70 //we.addTextInputHandler(inputhandler); 71 addElement(we); 72 } 73 buttons[0].onMouseLClick = &buttonOn_onMouseLClickRel; 74 } 75 76 public void buttonOn_onMouseLClickRel(Event event){ 77 ie.createNewDocument(textBoxes[0].getText().text, to!int(textBoxes[1].getText().text), to!int(textBoxes[2].getText().text)); 78 79 close(); 80 } 81 } 82 83 public class TopLevelWindow : Window { 84 public this(int width, int height, Editor prg) { 85 Text mt(dstring text) @safe nothrow { 86 return new Text(text, globalDefaultStyle.getChrFormatting("menuBar")); 87 } 88 super(Box(0, 0, width, height), ""d, [], null); 89 MenuBar mb; 90 { 91 PopUpMenuElement[] menuElements; 92 menuElements ~= new PopUpMenuElement("file", mt("FILE")); 93 94 menuElements[0].setLength(7); 95 menuElements[0][0] = new PopUpMenuElement("new", "New PPE map"); 96 menuElements[0][1] = new PopUpMenuElement("newTemp", "New PPE map from template"); 97 menuElements[0][2] = new PopUpMenuElement("load", "Load PPE map"); 98 menuElements[0][3] = new PopUpMenuElement("save", "Save PPE map"); 99 menuElements[0][4] = new PopUpMenuElement("saveAs", "Save PPE map as"); 100 menuElements[0][5] = new PopUpMenuElement("saveTemp", "Save PPE map as template"); 101 menuElements[0][6] = new PopUpMenuElement("exit", "Exit application"); 102 103 menuElements ~= new PopUpMenuElement("edit", mt("EDIT")); 104 105 menuElements[1].setLength(7); 106 menuElements[1][0] = new PopUpMenuElement("undo", "Undo"); 107 menuElements[1][1] = new PopUpMenuElement("redo", "Redo"); 108 menuElements[1][2] = new PopUpMenuElement("copy", "Copy"); 109 menuElements[1][3] = new PopUpMenuElement("cut", "Cut"); 110 menuElements[1][4] = new PopUpMenuElement("paste", "Paste"); 111 menuElements[1][5] = new PopUpMenuElement("editorSetup", "Editor settings"); 112 menuElements[1][6] = new PopUpMenuElement("docSetup", "Document settings"); 113 114 menuElements ~= new PopUpMenuElement("view", mt("VIEW")); 115 116 menuElements[2].setLength(2); 117 menuElements[2][0] = new PopUpMenuElement("layerList", "Layers"); 118 menuElements[2][1] = new PopUpMenuElement("materialList", "Materials"); 119 //menuElements[2][2] = new PopUpMenuElement("layerTools", "Layer tools", "Alt + T"); 120 121 menuElements ~= new PopUpMenuElement("layers", mt("LAYERS")); 122 123 menuElements[3].setLength(5); 124 menuElements[3][0] = new PopUpMenuElement("newLayer", "New layer"); 125 menuElements[3][1] = new PopUpMenuElement("delLayer", "Delete layer"); 126 menuElements[3][2] = new PopUpMenuElement("impLayer", "Import layer"); 127 menuElements[3][3] = new PopUpMenuElement("layerSrc", "Layer resources"); 128 menuElements[3][4] = new PopUpMenuElement("resizeLayer", "Resize layer"); 129 130 menuElements ~= new PopUpMenuElement("tools", mt("TOOLS")); 131 132 menuElements[4].setLength(2); 133 menuElements[4][0] = new PopUpMenuElement("tgaTool", "TGA Toolkit"); 134 menuElements[4][1] = new PopUpMenuElement("bmfontTool", "BMFont Toolkit"); 135 136 menuElements ~= new PopUpMenuElement("help", mt("HELP")); 137 138 menuElements[5].setLength(2); 139 menuElements[5][0] = new PopUpMenuElement("helpFile", "Content"); 140 menuElements[5][1] = new PopUpMenuElement("about", "About"); 141 142 mb = new MenuBar("mb", Box(0,0, width - 1, 15), menuElements); 143 144 mb.onMenuEvent = &prg.menuEvent; 145 } 146 addElement(mb); 147 } 148 public override void draw(bool drawHeaderOnly = false) { 149 output.drawFilledBox(position, 0); 150 foreach (WindowElement we; elements) { 151 we.draw(); 152 } 153 } 154 public override void drawHeader() { 155 156 } 157 ///Passes mouse click event 158 public override void passMCE(MouseEventCommons mec, MouseClickEvent mce) { 159 lastMousePos = Point(mce.x - position.left, mce.y - position.top); 160 foreach (WindowElement we; elements) { 161 if (we.getPosition.isBetween(lastMousePos)) { 162 lastMouseEventTarget = we; 163 mce.x = lastMousePos.x; 164 mce.y = lastMousePos.y; 165 we.passMCE(mec, mce); 166 return; 167 } 168 } 169 foreach (ISmallButton sb; smallButtons) { 170 WindowElement we = cast(WindowElement)sb; 171 if (we.getPosition.isBetween(lastMousePos)) { 172 lastMouseEventTarget = we; 173 mce.x = lastMousePos.x; 174 mce.y = lastMousePos.y; 175 we.passMCE(mec, mce); 176 return; 177 } 178 } 179 lastMouseEventTarget = null; 180 } 181 ///Passes mouse move event 182 public override void passMME(MouseEventCommons mec, MouseMotionEvent mme) { 183 lastMousePos = Point(mme.x - position.left, mme.y - position.top); 184 if (lastMouseEventTarget) { 185 mme.x = lastMousePos.x; 186 mme.y = lastMousePos.y; 187 lastMouseEventTarget.passMME(mec, mme); 188 if (!lastMouseEventTarget.getPosition.isBetween(mme.x, mme.y)) { 189 lastMouseEventTarget = null; 190 } 191 } else { 192 foreach (WindowElement we; elements) { 193 if (we.getPosition.isBetween(lastMousePos)) { 194 lastMouseEventTarget = we; 195 mme.x = lastMousePos.x; 196 mme.y = lastMousePos.y; 197 we.passMME(mec, mme); 198 return; 199 } 200 } 201 } 202 } 203 } 204 /+public enum PlacementMode : uint{ 205 NULL = 0, 206 NORMAL = 1, 207 VOIDFILL = 2, 208 OVERWRITE = 3, 209 210 }+/ 211 212 public class Editor : InputListener, SystemEventListener { 213 public OutputScreen[] ow; 214 public Raster rasters; 215 public InputHandler input; 216 public wchar selectedTile; 217 public BitmapAttrib selectedTileAttrib; 218 public int selectedLayer; 219 public SpriteLayer windowing; 220 public SpriteLayer bitmapPreview; 221 public bool onexit, exitDialog, newLayerDialog, mouseState, rasterRefresh; 222 public Window test; 223 public WindowHandler wh; 224 //public EffectLayer selectionLayer; 225 //public ForceFeedbackHandler ffb; 226 //private uint[5] framecounter; 227 public char[40] windowTitle; 228 public ConfigurationProfile configFile; 229 private int mouseX, mouseY; 230 private Coordinate selection, selectedTiles; 231 //public PlacementMode pm; 232 //public UndoableStack undoStack; 233 public PaletteManager palman; 234 public MapDocument[dstring] documents; 235 public MapDocument selDoc; 236 public LayerList layerList; 237 public MaterialList materialList; 238 239 public this(string[] args){ 240 ConfigurationProfile.setVaultPath("ZILtoid1991","PixelPerfectEditor"); 241 configFile = new ConfigurationProfile(); 242 243 windowing = new SpriteLayer(RenderingMode.Copy); 244 bitmapPreview = new SpriteLayer(); 245 246 wh = new WindowHandler(1696,960,848,480,windowing); 247 //wh.ie = this; 248 249 //Initialize the Concrete framework 250 INIT_CONCRETE(wh); 251 writeln(globalDefaultStyle.drawParameters); 252 //Initialize custom GUI elements 253 { 254 Bitmap8Bit[] customGUIElems = loadBitmapSheetFromFile!Bitmap8Bit("../system/concreteGUIE1.tga", 16, 16); 255 globalDefaultStyle.setImage(customGUIElems[0], "menuButtonA"); 256 globalDefaultStyle.setImage(customGUIElems[1], "menuButtonB"); 257 globalDefaultStyle.setImage(customGUIElems[2], "fullSizeButtonA"); 258 globalDefaultStyle.setImage(customGUIElems[3], "fullSizeButtonB"); 259 globalDefaultStyle.setImage(customGUIElems[4], "smallSizeButtonA"); 260 globalDefaultStyle.setImage(customGUIElems[5], "smallSizeButtonB"); 261 globalDefaultStyle.setImage(customGUIElems[6], "newDocumentButtonA"); 262 globalDefaultStyle.setImage(customGUIElems[7], "newDocumentButtonB"); 263 globalDefaultStyle.setImage(customGUIElems[8], "saveDocumentButtonA"); 264 globalDefaultStyle.setImage(customGUIElems[9], "saveDocumentButtonB"); 265 globalDefaultStyle.setImage(customGUIElems[10], "loadDocumentButtonA"); 266 globalDefaultStyle.setImage(customGUIElems[11], "loadDocumentButtonB"); 267 globalDefaultStyle.setImage(customGUIElems[12], "settingsButtonA"); 268 globalDefaultStyle.setImage(customGUIElems[13], "settingsButtonB"); 269 globalDefaultStyle.setImage(customGUIElems[14], "blankButtonA"); 270 globalDefaultStyle.setImage(customGUIElems[15], "blankButtonB"); 271 } 272 { 273 Bitmap8Bit[] customGUIElems = loadBitmapSheetFromFile!Bitmap8Bit("../system/concreteGUIE4.tga", 16, 16); 274 globalDefaultStyle.setImage(customGUIElems[0], "addMaterialA"); 275 globalDefaultStyle.setImage(customGUIElems[1], "addMaterialB"); 276 globalDefaultStyle.setImage(customGUIElems[2], "removeMaterialA"); 277 globalDefaultStyle.setImage(customGUIElems[3], "removeMaterialB"); 278 globalDefaultStyle.setImage(customGUIElems[4], "horizMirrorA"); 279 globalDefaultStyle.setImage(customGUIElems[5], "horizMirrorB"); 280 globalDefaultStyle.setImage(customGUIElems[6], "vertMirrorA"); 281 globalDefaultStyle.setImage(customGUIElems[7], "vertMirrorB"); 282 globalDefaultStyle.setImage(customGUIElems[8], "ovrwrtInsA"); 283 globalDefaultStyle.setImage(customGUIElems[9], "ovrwrtInsB"); 284 //globalDefaultStyle.setImage(customGUIElems[10], ""); 285 //globalDefaultStyle.setImage(customGUIElems[11], ""); 286 globalDefaultStyle.setImage(customGUIElems[12], "paletteDownA"); 287 globalDefaultStyle.setImage(customGUIElems[13], "paletteDownB"); 288 globalDefaultStyle.setImage(customGUIElems[14], "paletteUpA"); 289 globalDefaultStyle.setImage(customGUIElems[15], "paletteUpB"); 290 } 291 { 292 Bitmap8Bit[] customGUIElems = loadBitmapSheetFromFile!Bitmap8Bit("../system/concreteGUIE3.tga", 16, 16); 293 globalDefaultStyle.setImage(customGUIElems[0], "trashButtonA"); 294 globalDefaultStyle.setImage(customGUIElems[1], "trashButtonB"); 295 globalDefaultStyle.setImage(customGUIElems[2], "visibilityButtonA"); 296 globalDefaultStyle.setImage(customGUIElems[3], "visibilityButtonB"); 297 globalDefaultStyle.setImage(customGUIElems[4], "newTileLayerButtonA"); 298 globalDefaultStyle.setImage(customGUIElems[5], "newTileLayerButtonB"); 299 globalDefaultStyle.setImage(customGUIElems[6], "newSpriteLayerButtonA"); 300 globalDefaultStyle.setImage(customGUIElems[7], "newSpriteLayerButtonB"); 301 globalDefaultStyle.setImage(customGUIElems[8], "newTransformableTileLayerButtonA"); 302 globalDefaultStyle.setImage(customGUIElems[9], "newTransformableTileLayerButtonB"); 303 globalDefaultStyle.setImage(customGUIElems[10], "importLayerDataButtonA"); 304 globalDefaultStyle.setImage(customGUIElems[11], "importLayerDataButtonB"); 305 globalDefaultStyle.setImage(customGUIElems[12], "importMaterialDataButtonA"); 306 globalDefaultStyle.setImage(customGUIElems[13], "importMaterialDataButtonB"); 307 globalDefaultStyle.setImage(customGUIElems[14], "paletteButtonA"); 308 globalDefaultStyle.setImage(customGUIElems[15], "paletteButtonB"); 309 } 310 { 311 Bitmap8Bit[] customGUIElems = loadBitmapSheetFromFile!Bitmap8Bit("../system/concreteGUIE5.tga", 16, 16); 312 globalDefaultStyle.setImage(customGUIElems[0], "percentButtonA"); 313 globalDefaultStyle.setImage(customGUIElems[1], "percentButtonB"); 314 globalDefaultStyle.setImage(customGUIElems[2], "tileButtonA"); 315 globalDefaultStyle.setImage(customGUIElems[3], "tileButtonB"); 316 globalDefaultStyle.setImage(customGUIElems[4], "selMoveButtonA"); 317 globalDefaultStyle.setImage(customGUIElems[5], "selMoveButtonB"); 318 globalDefaultStyle.setImage(customGUIElems[6], "tilePlacementButtonA"); 319 globalDefaultStyle.setImage(customGUIElems[7], "tilePlacementButtonB"); 320 globalDefaultStyle.setImage(customGUIElems[8], "objPlacementButtonA"); 321 globalDefaultStyle.setImage(customGUIElems[9], "objPlacementButtonB"); 322 globalDefaultStyle.setImage(customGUIElems[10], "sprtPlacementButtonA"); 323 globalDefaultStyle.setImage(customGUIElems[11], "sprtPlacementButtonB"); 324 //globalDefaultStyle.setImage(customGUIElems[12], "importMaterialDataButtonA"); 325 //globalDefaultStyle.setImage(customGUIElems[13], "importMaterialDataButtonB"); 326 //globalDefaultStyle.setImage(customGUIElems[14], "paletteButtonA"); 327 //globalDefaultStyle.setImage(customGUIElems[15], "paletteButtonB"); 328 } 329 330 //wh.initGUI(); 331 332 input = new InputHandler(); 333 //input.ml ~= this; 334 input.mouseListener = wh; 335 input.inputListener = this; 336 input.systemEventListener = this; 337 //input.kb ~= KeyBinding(0, SDL_SCANCODE_ESCAPE, 0, "sysesc", Devicetype.KEYBOARD); 338 //input.kb ~= configFile.keyBindingList; 339 input.addBinding(InputHandler.getSysEscKey, InputBinding(InputHandler.sysescCode)); 340 configFile.loadBindings(input); 341 342 WindowElement.inputHandler = input; 343 344 ow ~= new OutputScreen("Pixel Perfect Editor", 1696, 960); 345 346 rasters = new Raster(848, 480, ow[0], 0, 2); 347 ow[0].setMainRaster(rasters); 348 rasters.addLayer(windowing, 0); 349 rasters.addLayer(bitmapPreview, 1); 350 //ISSUE: Copying the palette from StyleSheet.defaultPaletteForGUI doesn't work 351 //SOLUTION: Load the palette from a file 352 rasters.loadPalette(loadPaletteFromFile("../system/concreteGUIE1.tga")); 353 wh.setBaseWindow(new TopLevelWindow(848, 480, this)); 354 wh.addBackground(loadBitmapFromFile!Bitmap32Bit("../system/background.png")); 355 openMaterialList(); 356 openLayerList(); 357 } 358 public void menuEvent(Event ev) { 359 if (ev.type == EventType.Menu){ 360 MenuEvent mev = cast(MenuEvent)ev; 361 switch (mev.itemSource) { 362 case "save": 363 onSave(); 364 break; 365 case "saveAs": 366 onSaveAs(); 367 break; 368 case "load": 369 onLoad(); 370 break; 371 case "newLayer": 372 initNewTileLayer(); 373 break; 374 case "new": 375 //TileLayerEditor tle = new TileLayerEditor(this); 376 //wh.addWindow(tle); 377 onNewDocument(); 378 break; 379 case "resizeLayer": 380 initResizeLayer(); 381 break; 382 case "undo": 383 onUndo(); 384 break; 385 case "redo": 386 onRedo(); 387 break; 388 case "exit": 389 onQuit(); 390 break; 391 case "layerList": 392 openLayerList(); 393 break; 394 case "materialList": 395 openMaterialList(); 396 break; 397 default: 398 break; 399 } 400 } 401 } 402 403 /** 404 * Called when a keybinding event is generated. 405 * The `id` should be generated from a string, usually the name of the binding. 406 * `code` is a duplicate of the code used for fast lookup of the binding, which also contains other info (deviceID, etc). 407 * `timestamp` is the time lapsed since the start of the program, can be used to measure time between keypresses. 408 * NOTE: Hat events on joysticks don't generate keyReleased events, instead they generate keyPressed events on release. 409 */ 410 public void keyEvent(uint id, BindingCode code, uint timestamp, bool isPressed) { 411 import PixelPerfectEngine.system.etc : hashCalc; 412 switch (id) { 413 case hashCalc("copy"): 414 break; 415 case hashCalc("cut"): 416 break; 417 case hashCalc("paste"): 418 break; 419 case hashCalc("undo"): 420 if (!isPressed) 421 onUndo; 422 break; 423 case hashCalc("redo"): 424 if (!isPressed) 425 onRedo; 426 break; 427 case hashCalc("save"): 428 if (!isPressed) 429 onSave; 430 break; 431 case hashCalc("saveAs"): 432 if (!isPressed) 433 onSaveAs; 434 break; 435 case hashCalc("insert"): 436 if (!isPressed){ 437 if (materialList) 438 materialList.ovrwrtIns.toggle(); 439 else if (selDoc) 440 selDoc.voidfill = !selDoc.voidfill; 441 } 442 break; 443 case hashCalc("delArea"): 444 445 break; 446 case hashCalc("palUp"): 447 if (isPressed) { 448 if (materialList) 449 materialList.palUp_onClick(null); 450 else if (selDoc) 451 selDoc.tileMaterial_PaletteUp; 452 } 453 break; 454 case hashCalc("palDown"): 455 if (isPressed) { 456 if (materialList) 457 materialList.palDown_onClick(null); 458 else if (selDoc) 459 selDoc.tileMaterial_PaletteDown; 460 } 461 break; 462 case hashCalc("hMirror"): 463 if (!isPressed) { 464 if (materialList) 465 materialList.horizMirror.toggle; 466 } 467 break; 468 case hashCalc("vMirror"): 469 if (!isPressed) { 470 if (materialList) 471 materialList.vertMirror.toggle; 472 } 473 break; 474 case hashCalc("place"): 475 476 break; 477 case hashCalc("nextTile"): 478 break; 479 case hashCalc("prevTile"): 480 break; 481 case hashCalc("moveUp"): 482 break; 483 case hashCalc("moveDown"): 484 break; 485 case hashCalc("moveLeft"): 486 break; 487 case hashCalc("moveRight"): 488 break; 489 case hashCalc("scrollUp"): 490 if (selDoc) { 491 if (isPressed) 492 selDoc.sYAmount = -1; 493 else 494 selDoc.sYAmount = 0; 495 } 496 break; 497 case hashCalc("scrollDown"): 498 if (selDoc) { 499 if (isPressed) 500 selDoc.sYAmount = 1; 501 else 502 selDoc.sYAmount = 0; 503 } 504 break; 505 case hashCalc("scrollLeft"): 506 if (selDoc) { 507 if (isPressed) 508 selDoc.sXAmount = 1; 509 else 510 selDoc.sXAmount = 0; 511 } 512 break; 513 case hashCalc("scrollRight"): 514 if (selDoc) { 515 if (isPressed) 516 selDoc.sXAmount = -1; 517 else 518 selDoc.sXAmount = 0; 519 } 520 break; 521 case hashCalc("nextLayer"): 522 break; 523 case hashCalc("prevLayer"): 524 break; 525 case hashCalc("hideLayer"): 526 break; 527 case hashCalc("soloLayer"): 528 break; 529 default: 530 break; 531 } 532 } 533 /** 534 * Called when an axis is being operated. 535 * The `id` should be generated from a string, usually the name of the binding. 536 * `code` is a duplicate of the code used for fast lookup of the binding, which also contains other info (deviceID, etc). 537 * `timestamp` is the time lapsed since the start of the program, can be used to measure time between keypresses. 538 * `value` is the current position of the axis normalized between -1.0 and +1.0 for joysticks, and 0.0 and +1.0 for analog 539 * triggers. 540 */ 541 public void axisEvent(uint id, BindingCode code, uint timestamp, float value) { 542 543 } 544 public void onUndo () { 545 if(selDoc !is null){ 546 selDoc.events.undo; 547 selDoc.outputWindow.updateRaster; 548 } 549 } 550 public void onRedo () { 551 if(selDoc !is null){ 552 selDoc.events.redo; 553 selDoc.outputWindow.updateRaster; 554 } 555 } 556 public void onLoad () { 557 import PixelPerfectEngine.concrete.dialogs.filedialog; 558 FileDialog fd = new FileDialog("Load document","docLoad",&onLoadDialog,[FileDialog.FileAssociationDescriptor( 559 "PPE map file", ["*.xmf"])],"./",false); 560 wh.addWindow(fd); 561 } 562 public void onNewDocument () { 563 wh.addWindow(new NewDocumentDialog(this)); 564 } 565 public void onLoadDialog (Event ev) { 566 import std.utf : toUTF32; 567 try { 568 FileEvent event = cast(FileEvent)ev; 569 selDoc = new MapDocument(event.getFullPath); 570 dstring name = toUTF32(selDoc.mainDoc.getName); 571 RasterWindow w = new RasterWindow(selDoc.mainDoc.getHorizontalResolution, selDoc.mainDoc.getVerticalResolution, 572 rasters.palette.ptr, name, selDoc); 573 selDoc.outputWindow = w; 574 wh.addWindow(w); 575 documents[name] = selDoc; 576 selDoc.updateLayerList(); 577 selDoc.updateMaterialList(); 578 selDoc.mainDoc.loadTiles(w); 579 selDoc.mainDoc.loadMappingData(); 580 w.loadLayers(); 581 w.updateRaster(); 582 } catch (Exception e) { 583 debug writeln(e); 584 } 585 586 } 587 public void onSave () { 588 if (selDoc.filename) { 589 try { 590 selDoc.mainDoc.save(selDoc.filename); 591 } catch (Exception e) { 592 debug writeln(e); 593 } 594 } else { 595 onSaveAs(); 596 } 597 } 598 public void onSaveAs () { 599 import PixelPerfectEngine.concrete.dialogs.filedialog; 600 FileDialog fd = new FileDialog("Save document as","docSave",&onSaveDialog,[FileDialog.FileAssociationDescriptor( 601 "PPE map file", ["*.xmf"])],"./",true); 602 wh.addWindow(fd); 603 } 604 public void onSaveDialog(Event ev) { 605 import std.path : extension; 606 import std.ascii : toLower; 607 FileEvent event = cast(FileEvent)ev; 608 selDoc.filename = event.getFullPath(); 609 if(extension(selDoc.filename) != ".xmf"){ 610 selDoc.filename ~= ".xmf"; 611 } 612 try { 613 selDoc.mainDoc.save(selDoc.filename); 614 } catch (Exception e) { 615 debug writeln(e); 616 } 617 } 618 619 public void onQuit(){onExit();} 620 public void controllerRemoved(uint ID){} 621 public void controllerAdded(uint ID){} 622 public void initResizeLayer() { 623 //import resizeMap; 624 if (selDoc !is null) { 625 wh.addWindow(new ResizeMap(selDoc)); 626 } 627 } 628 629 630 /** 631 * Opens a window to ask the user for the data on the new tile layer 632 */ 633 public void initNewTileLayer(){ 634 wh.addWindow(new NewTileLayerDialog(this)); 635 } 636 /** 637 * Opens a window to ask the user for input on materials to be added 638 */ 639 public void initAddMaterials() { 640 import windows.addtiles; 641 if(selDoc){ 642 ITileLayer itl = cast(ITileLayer)selDoc.mainDoc.layeroutput[selDoc.selectedLayer]; 643 const int tileX = itl.getTileWidth, tileY = itl.getTileHeight; 644 wh.addWindow(new AddTiles(this, tileX, tileY)); 645 } 646 } 647 /** 648 * Creates a new tile layer with the given data. 649 * 650 * file: Optional field. If given, it specifies the external file for binary map data. If it specifies an already 651 * existing file, then that file will be loaded. If null, then the map data will be embedded as a BASE64 chunk. 652 * tmplt: Optional field. Specifies the initial tile source data from a map file alongside with the name of the layer 653 */ 654 public void newTileLayer(int tX, int tY, int mX, int mY, dstring name, string file, bool embed) { 655 selDoc.events.addToTop(new CreateTileLayerEvent(selDoc, tX, tY, mX, mY, name, file, embed)); 656 } 657 public void setRasterRefresh(){ 658 rasterRefresh = true; 659 } 660 public void whereTheMagicHappens(){ 661 //rasters.refresh(); 662 while(!onexit){ 663 input.test(); 664 665 rasters.refresh(); 666 if (selDoc) { 667 selDoc.contScrollLayer(); 668 } 669 } 670 configFile.store(); 671 } 672 public void onExit(){ 673 import PixelPerfectEngine.concrete.dialogs.defaultdialog; 674 exitDialog=true; 675 DefaultDialog dd = new DefaultDialog(Coordinate(10,10,220,75), "exitdialog","Exit application", ["Are you sure?"], 676 ["Yes","No","Pls save"],["ok","close","save"]); 677 678 dd.output = &confirmExit; 679 wh.addWindow(dd); 680 681 } 682 private void confirmExit(Event ev) { 683 WindowElement we = cast(WindowElement)ev.sender; 684 if (we.getSource == "ok") { 685 onexit = true; 686 } 687 } 688 /+public void newDocument(){ 689 NewDocumentDialog ndd = new NewDocumentDialog(input); 690 ndd.ie = this; 691 wh.addWindow(ndd); 692 }+/ 693 public void createNewDocument(dstring name, int rX, int rY){ 694 import std.utf : toUTF8; 695 MapDocument md = new MapDocument(toUTF8(name), rX, rY); 696 RasterWindow w = new RasterWindow(rX, rY, rasters.palette.ptr, name, md); 697 md.outputWindow = w; 698 wh.addWindow(w); 699 documents[name] = md; 700 selDoc = md; 701 } 702 public void openLayerList() { 703 if (!layerList) { 704 layerList = new LayerList(0, 16, &onLayerListClosed); 705 wh.addWindow(layerList); 706 } 707 } 708 private void onLayerListClosed() { 709 layerList = null; 710 } 711 public void openMaterialList() { 712 if (!materialList) { 713 materialList = new MaterialList(0, 230, &onMaterialListClosed); 714 wh.addWindow(materialList); 715 } 716 } 717 private void onMaterialListClosed() { 718 materialList = null; 719 } 720 }