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.inputHandler;
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 derelict.sdl2.sdl;
26 import bindbc.sdl;
27 import PixelPerfectEngine.concrete.window;
28 import PixelPerfectEngine.concrete.eventChainSystem;
29 import PixelPerfectEngine.map.mapload;
30 
31 import converterdialog;
32 import tileLayer;
33 import newLayerDialog;
34 import about;
35 import editorEvents;
36 //import bmfontimport;
37 
38 public interface IEditor{
39 	public void onExit();
40 	public void newDocument();
41 	public void newLayer();
42 	public void xmpToolkit();
43 	public void passActionEvent(Event e);
44 	public void createNewDocument(dstring name, int rX, int rY, int pal);
45 	//public void createNewLayer(string name, int type, int tX, int tY, int mX, int mY, int priority);
46 }
47 
48 public class NewDocumentDialog : Window{
49 	public IEditor ie;
50 	private TextBox[] textBoxes;
51 	public this(Coordinate size, dstring title){
52 		super(size, title);
53 	}
54 	public this(InputHandler inputhandler){
55 		this(Coordinate(10,10,220,150),"New Document"d);
56 
57 		Button[] buttons;
58 		Label[] labels;
59 		buttons ~= new Button("Ok", "ok", Coordinate(150,110,200,130));
60 
61 		labels ~= new Label("Name:","",Coordinate(5,20,80,39));
62 		labels ~= new Label("RasterX:","",Coordinate(5,40,80,59));
63 		labels ~= new Label("RasterY:","",Coordinate(5,60,80,79));
64 		labels ~= new Label("N. of colors:","",Coordinate(5,80,120,99));
65 		textBoxes ~= new TextBox("","name",Coordinate(81,20,200,39));
66 		textBoxes ~= new TextBox("","rX",Coordinate(121,40,200,59));
67 		textBoxes ~= new TextBox("","rY",Coordinate(121,60,200,79));
68 		textBoxes ~= new TextBox("","pal",Coordinate(121,80,200,99));
69 		addElement(buttons[0], EventProperties.MOUSE);
70 		foreach(WindowElement we; labels){
71 			addElement(we, EventProperties.MOUSE);
72 		}
73 		foreach(TextBox we; textBoxes){
74 			//we.addTextInputHandler(inputhandler);
75 			addElement(we, EventProperties.MOUSE);
76 		}
77 		buttons[0].onMouseLClickRel = &buttonOn_onMouseLClickRel;
78 	}
79 
80 	public void buttonOn_onMouseLClickRel(Event event){
81 		ie.createNewDocument(textBoxes[0].getText(), to!int(textBoxes[1].getText()), to!int(textBoxes[2].getText()), to!int(textBoxes[3].getText()));
82 
83 		parent.closeWindow(this);
84 	}
85 }
86 
87 public class EditorWindowHandler : WindowHandler, ElementContainer{
88 	private WindowElement[] elements, mouseC, keyboardC, scrollC;
89 	private ListBox layerList, prop;
90 	//private ListBoxColumn[] propTL, propSL, propSLE;
91 	//private ListBoxColumn[] layerListE;
92 	public Label[] labels;
93 	private int[] propTLW, propSLW, propSLEW;
94 	public IEditor ie;
95 
96 	//public InputHandler ih;
97 
98 	private BitmapDrawer output;
99 	public this(int sx, int sy, int rx, int ry,ISpriteLayer sl){
100 		super(sx,sy,rx,ry,sl);
101 		output = new BitmapDrawer(rx, ry);
102 		addBackground(output.output);
103 		propTLW = [40, 320];
104 		propSLW = [160, 320, 48, 64];
105 		propSLEW = [160, 320, 40, 56];
106 		WindowElement.popUpHandler = this;
107 	}
108 	public void clearArea(WindowElement sender){
109 
110 	}
111 	public void initGUI(){
112 		output.drawFilledRectangle(0, rasterX, 0, rasterY, 0x0005);
113 
114 		PopUpMenuElement[] menuElements;
115 		menuElements ~= new PopUpMenuElement("file", "FILE");
116 
117 		menuElements[0].setLength(7);
118 		menuElements[0][0] = new PopUpMenuElement("new", "New PPE map", "Ctrl + N");
119 		menuElements[0][1] = new PopUpMenuElement("newTemp", "New PPE map from template", "Ctrl + Shift + N");
120 		menuElements[0][2] = new PopUpMenuElement("load", "Load PPE map", "Ctrl + L");
121 		menuElements[0][3] = new PopUpMenuElement("save", "Save PPE map", "Ctrl + S");
122 		menuElements[0][4] = new PopUpMenuElement("saveAs", "Save PPE map as", "Ctrl + Shift + S");
123 		menuElements[0][5] = new PopUpMenuElement("saveTemp", "Save PPE map as template", "Ctrl + Shift + T");
124 		menuElements[0][6] = new PopUpMenuElement("exit", "Exit application", "Alt + F4");
125 
126 		menuElements ~= new PopUpMenuElement("edit", "EDIT");
127 
128 		menuElements[1].setLength(7);
129 		menuElements[1][0] = new PopUpMenuElement("undo", "Undo", "Ctrl + Z");
130 		menuElements[1][1] = new PopUpMenuElement("redo", "Redo", "Ctrl + Shift + Z");
131 		menuElements[1][2] = new PopUpMenuElement("copy", "Copy", "Ctrl + C");
132 		menuElements[1][3] = new PopUpMenuElement("cut", "Cut", "Ctrl + X");
133 		menuElements[1][4] = new PopUpMenuElement("paste", "Paste", "Ctrl + V");
134 		menuElements[1][5] = new PopUpMenuElement("editorSetup", "Editor Settings");
135 		menuElements[1][6] = new PopUpMenuElement("docSetup", "Document Settings");
136 
137 		menuElements ~= new PopUpMenuElement("view", "VIEW");
138 
139 		menuElements[2].setLength(2);
140 		menuElements[2][0] = new PopUpMenuElement("layerList", "Layer list", "Alt + L");
141 		menuElements[2][1] = new PopUpMenuElement("layerTools", "Layer tools", "Alt + T");
142 
143 		menuElements ~= new PopUpMenuElement("layers", "LAYERS");
144 
145 		menuElements[3].setLength(4);
146 		menuElements[3][0] = new PopUpMenuElement("newLayer", "New layer", "Alt + N");
147 		menuElements[3][1] = new PopUpMenuElement("delLayer", "Delete layer", "Alt + Del");
148 		menuElements[3][2] = new PopUpMenuElement("impLayer", "Import layer", "Alt + Shift + I");
149 		menuElements[3][3] = new PopUpMenuElement("layerSrc", "Layer resources", "Alt + R");
150 
151 		menuElements ~= new PopUpMenuElement("tools", "TOOLS");
152 
153 		menuElements[4].setLength(2);
154 		menuElements[4][0] = new PopUpMenuElement("xmpTool", "XMP Toolkit", "Alt + X");
155 		menuElements[4][1] = new PopUpMenuElement("mapXMLEdit", "Edit map as XML", "Ctrl + Alt + X");
156 		//menuElements[4][2] = new PopUpMenuElement("bmfontimport", "Import BMFont File");
157 
158 		menuElements ~= new PopUpMenuElement("help", "HELP");
159 
160 		menuElements[5].setLength(2);
161 		menuElements[5][0] = new PopUpMenuElement("helpFile", "Content", "F1");
162 		menuElements[5][1] = new PopUpMenuElement("about", "About");
163 
164 
165 		MenuBar mb = new MenuBar("menubar",Coordinate(0,0,848,16),menuElements);
166 		addElement(mb, EventProperties.MOUSE);
167 		mb.onMouseLClickPre = &actionEvent;
168 		foreach(WindowElement we; labels){
169 			addElement(we, 0);
170 		}
171 		foreach(WindowElement we; elements){
172 			we.draw();
173 		}
174 	}
175 
176 	public override StyleSheet getStyleSheet(){
177 		return defaultStyle;
178 	}
179 
180 	public void addElement(WindowElement we, int eventProperties){
181 		elements ~= we;
182 		we.elementContainer = this;
183 		//we.al ~= this;
184 		if((eventProperties & EventProperties.KEYBOARD) == EventProperties.KEYBOARD){
185 			keyboardC ~= we;
186 		}
187 		if((eventProperties & EventProperties.MOUSE) == EventProperties.MOUSE){
188 			mouseC ~= we;
189 		}
190 		if((eventProperties & EventProperties.SCROLL) == EventProperties.SCROLL){
191 			scrollC ~= we;
192 		}
193 	}
194 
195 
196 	public void actionEvent(Event event){
197 		writeln(event.source);
198 		switch(event.source){
199 			case "exit":
200 				ie.onExit;
201 				break;
202 			case "new":
203 				ie.newDocument;
204 				break;
205 			case "newL":
206 				ie.newLayer;
207 				break;
208 			case "xmpTool":
209 				ie.xmpToolkit();
210 				break;
211 			case "about":
212 				Window w = new AboutWindow();
213 				addWindow(w);
214 				w.relMove(30,30);
215 				break;
216 			case "bmfontimport":
217 				//addWindow(new BMFontImport());
218 				break;
219 			default:
220 				ie.passActionEvent(event);
221 				break;
222 		}
223 	}
224 
225 	public override void drawUpdate(WindowElement sender){
226 		output.insertBitmap(sender.getPosition().left,sender.getPosition().top,sender.output.output);
227 	}
228 
229 	override public void passMouseEvent(int x,int y,int state,ubyte button) {
230 		foreach(WindowElement e; mouseC){
231 			if(e.getPosition().left < x && e.getPosition().right > x && e.getPosition().top < y && e.getPosition().bottom > y){
232 				e.onClick(x - e.getPosition().left, y - e.getPosition().top, state, button);
233 				return;
234 			}
235 		}
236 	}
237 	public override void passScrollEvent(int wX, int wY, int x, int y){
238 		foreach(WindowElement e; scrollC){
239 			if(e.getPosition().left < wX && e.getPosition().right > wX && e.getPosition().top < wX && e.getPosition().bottom > wY){
240 
241 				e.onScroll(y, x, wX, wY);
242 
243 				return;
244 			}
245 		}
246 	}
247 	public Coordinate getAbsolutePosition(WindowElement sender){
248 		return sender.position;
249 	}
250 }
251 
252 public enum PlacementMode : uint{
253 	NULL		=	0,
254 	NORMAL		=	1,
255 	VOIDFILL	=	2,
256 	OVERWRITE	=	3,
257 
258 }
259 
260 public class Editor : InputListener, MouseListener, IEditor, SystemEventListener, NewLayerDialogListener{
261 	public OutputScreen[] ow;
262 	public Raster[] rasters;
263 	public InputHandler input;
264 	public TileLayer[int] backgroundLayers;
265 	//public TileLayer8Bit[int] backgroundLayers8;
266 	//public TileLayer32Bit[int] backgroundLayers32;
267 	public Layer[int] layers;
268 	public wchar selectedTile;
269 	public BitmapAttrib selectedTileAttrib;
270 	public int selectedLayer;
271 	public SpriteLayer windowing;
272 	public SpriteLayer bitmapPreview;
273 	public bool onexit, exitDialog, newLayerDialog, mouseState, rasterRefresh;
274 	public WindowElement[] elements;
275 	public Window test;
276 	public EditorWindowHandler wh;
277 	public ExtendibleMap document;
278 	public EffectLayer selectionLayer;
279 	//public ForceFeedbackHandler ffb;
280 	private uint[5] framecounter;
281 	public char[40] windowTitle;
282 	public ConfigurationProfile configFile;
283 	private int mouseX, mouseY;
284 	private Coordinate selection, selectedTiles;
285 	public PlacementMode pm;
286 	public UndoableStack undoStack;
287 	public PaletteManager palman;
288 
289 	public void mouseButtonEvent(Uint32 which, Uint32 timestamp, Uint32 windowID, Uint8 button, Uint8 state, Uint8 clicks, Sint32 x, Sint32 y){
290 		//writeln(windowID);
291 		x /= 2;
292 		y /= 2;
293 		if(windowID == 2){
294 			if(button == MouseButton.LEFT){//placement
295 				if(state == ButtonState.PRESSED && !mouseState){
296 					mouseX = x;
297 					mouseY = y;
298 					mouseState = true;
299 				}else if(mouseState){
300 					mouseState = false;
301 					if(mouseX == x && mouseY == y){//single placement
302 						if(layers[selectedLayer].classinfo == typeid(TileLayer)){
303 							TileLayer tl = cast(TileLayer)(layers[selectedLayer]);
304 							int targetX = (x + tl.getSX()) / tl.getTileWidth();
305 							int targetY = (y + tl.getSY()) / tl.getTileHeight();
306 							if(targetX >= 0 && targetY >= 0 && targetX < tl.getMX && targetY < tl.getMY){
307 								if(pm == PlacementMode.NORMAL || (pm == PlacementMode.VOIDFILL && tl.readMapping(targetX,targetY).tileID == 0xFFFF
308 															|| (pm == PlacementMode.OVERWRITE))){
309 									undoStack.addToTop(new WriteToMapSingle(cast(ITileLayer)(layers[selectedLayer]), x, y, MappingElement(selectedTile, selectedTileAttrib)));
310 								}
311 							}
312 						}else{//sprite placement
313 
314 						}
315 					}else{		//select or region fill
316 						Coordinate c = Coordinate();
317 						if(mouseX>x){
318 							c.left = x;
319 							c.right = mouseX;
320 						}else{
321 							c.left = mouseX;
322 							c.right = x;
323 						}
324 						if(mouseY>y){
325 							c.top = y;
326 							c.bottom = mouseY;
327 						}else{
328 							c.top = mouseY;
329 							c.bottom = y;
330 						}
331 						if(layers[selectedLayer].classinfo == typeid(TileLayer)){
332 							TileLayer tl = cast(TileLayer)(layers[selectedLayer]);
333 							c.left = (c.left + tl.getSX()) / tl.getTileWidth();
334 							c.right = (c.right + tl.getSX()) / tl.getTileWidth();
335 							c.top = (c.top + tl.getSY()) / tl.getTileHeight();
336 							c.bottom = (c.bottom + tl.getSY()) / tl.getTileHeight();
337 							//Fill
338 							if(pm == PlacementMode.VOIDFILL){
339 								undoStack.addToTop(new WriteToMapVoidFill(cast(ITileLayer)(layers[selectedLayer]), c, MappingElement(selectedTile, selectedTileAttrib)));
340 							}else{
341 								undoStack.addToTop(new WriteToMapOverwrite(cast(ITileLayer)(layers[selectedLayer]), c, MappingElement(selectedTile, selectedTileAttrib)));
342 							}
343 						}
344 					}
345 				}
346 			}else if(button == MouseButton.MID){//deletion
347 
348 			}
349 		}
350 		setRasterRefresh;
351 	}
352 	public void mouseWheelEvent(uint type, uint timestamp, uint windowID, uint which, int x, int y, int wX, int wY){
353 		setRasterRefresh;
354 	}
355 	public void mouseMotionEvent(uint timestamp, uint windowID, uint which, uint state, int x, int y, int relX, int relY){
356 		setRasterRefresh;
357 	}
358 	public void keyPressed(string ID, Uint32 timestamp, Uint32 devicenumber, Uint32 devicetype){
359 		switch(ID){
360 			case "nextLayer":
361 				break;
362 			case "prevLayer":
363 				break;
364 			case "scrollUp":
365 				break;
366 			case "scrollDown":
367 				break;
368 			case "scrollLeft":
369 				break;
370 			case "scrollRight":
371 				break;
372 			case "quit":
373 				break;
374 			case "xmpTool":
375 				break;
376 			case "load":
377 				break;
378 			case "save":
379 				break;
380 			case "saveAs":
381 				break;
382 			default:
383 				break;
384 		}
385 	}
386 	public void keyReleased(string ID, Uint32 timestamp, Uint32 devicenumber, Uint32 devicetype){}
387 	public void passActionEvent(Event e){
388 		switch(e.source){
389 			case "saveas":
390 				FileDialog fd = new FileDialog("Save document as","docSave",&actionEvent,[FileDialog.FileAssociationDescriptor("PPE map file", ["*.xmf"])],".\\",true);
391 				wh.addWindow(fd);
392 				break;
393 			case "load":
394 				FileDialog fd = new FileDialog("Load document","docLoad",&actionEvent,[FileDialog.FileAssociationDescriptor("PPE map file", ["*.xmf"])],".\\",false);
395 				wh.addWindow(fd);
396 				break;
397 			case "newLayer":
398 				NewLayerDialog nld = new NewLayerDialog(this);
399 				wh.addWindow(nld);
400 				break;
401 			case "layerTools":
402 				TileLayerEditor tle = new TileLayerEditor(this);
403 				wh.addWindow(tle);
404 				break;
405 			default: break;
406 		}
407 	}
408 	/*public void actionEvent(string source, int type, int value, wstring message){
409 		writeln(source);
410 
411 		if(source == "file"){
412 			writeln(message);
413 		}
414 	}
415 	public void actionEvent(string source, string subSource, int type, int value, wstring message){
416 		switch(subSource){
417 			case "exitdialog":
418 				if(source == "Yes"){
419 					onexit = true;
420 				}
421 				break;
422 			default: break;
423 		}
424 	}*/
425 	public void actionEvent(Event event){
426 		//writeln(event.subsource);
427 		switch(event.subsource){
428 			case "exitdialog":
429 				if(event.source == "ok"){
430 					onexit = true;
431 				}
432 				break;
433 			case FileDialog.subsourceID:
434 				switch(event.source){
435 					case "docSave":
436 						break;
437 					case "docLoad":
438 						string path = event.path;
439 						path ~= event.filename;
440 						document = new ExtendibleMap(path);
441 						break;
442 					default: break;
443 				}
444 				break;
445 			default:
446 				break;
447 		}
448 	}
449 	public void onQuit(){onExit();}
450 	public void controllerRemoved(uint ID){}
451 	public void controllerAdded(uint ID){}
452 	public void xmpToolkit(){
453 		wh.addWindow(new ConverterDialog(input,bitmapPreview));
454 	}
455 	/*public void placeObject(int x, int y){
456 		if(backgroundLayers.get(selectedLayer, null) !is null){
457 			int sX = backgroundLayers[selectedLayer].getSX(), sY = backgroundLayers[selectedLayer].getSY();
458 			sX += x;
459 			sY += y;
460 			sX /= backgroundLayers[selectedLayer].getTileWidth();
461 			sY /= backgroundLayers[selectedLayer].getTileHeight();
462 			if(sX >= 0 && sY >= 0){
463 				backgroundLayers[selectedLayer].writeMapping(sX, sY, selectedTile);
464 			}
465 		}
466 	}*/
467 	public this(string[] args){
468 		pm = PlacementMode.OVERWRITE;
469 		ConfigurationProfile.setVaultPath("ZILtoid1991","PixelPerfectEditor");
470 		configFile = new ConfigurationProfile();
471 
472 		windowing = new SpriteLayer(LayerRenderingMode.COPY);
473 		bitmapPreview = new SpriteLayer();
474 
475 		wh = new EditorWindowHandler(1696,960,848,480,windowing);
476 		wh.ie = this;
477 
478 		//Initialize the Concrete framework
479 		INIT_CONCRETE(wh);
480 
481 
482 		wh.initGUI();
483 
484 		input = new InputHandler();
485 		input.ml ~= this;
486 		input.ml ~= wh;
487 		input.il ~= this;
488 		input.sel ~= this;
489 		input.kb ~= KeyBinding(0, SDL_SCANCODE_ESCAPE, 0, "sysesc", Devicetype.KEYBOARD);
490 		WindowElement.inputHandler = input;
491 		//wh.ih = input;
492 		//ffb = new ForceFeedbackHandler(input);
493 
494 		//OutputWindow.setScalingQuality("2");
495 		//OutputWindow.setDriver("software");
496 		ow ~= new OutputScreen("Pixel Perfect Editor", 1696, 960);
497 
498 		rasters ~= new Raster(848, 480, ow[0], 0);
499 		ow[0].setMainRaster(rasters[0]);
500 		rasters[0].addLayer(windowing, 0);
501 		rasters[0].addLayer(bitmapPreview, 1);
502 		//rasters[0].setupPalette(512);
503 		//loadPaletteFromFile("VDPeditUI0.pal", guiR);
504 		//load24bitPaletteFromFile("VDPeditUI0.pal", rasters[0]);
505 		//loadPaletteFromXMP(ssOrigin, "default", rasters[0]);
506 		rasters[0].palette = [Color(0x00,0x00,0x00,0x00),	//transparent
507 	Color(0xFF,0xFF,0xFF,0xFF),		//normaltext
508 	Color(0xFF,0x77,0x77,0x77),		//window
509 	Color(0xFF,0xCC,0xCC,0xCC),		//windowascent
510 	Color(0xFF,0x33,0x33,0x33),		//windowdescent
511 	Color(0xff,0x22,0x22,0x22),		//windowinactive
512 	Color(0xff,0xff,0x00,0x00),		//selection
513 	Color(0xFF,0x77,0x77,0xFF),		//WHAascent
514 	Color(0xFF,0x00,0x00,0x77),		//WHAdescent
515 	Color(0xFF,0x00,0x00,0xDD),		//WHAtop
516 	Color(0xFF,0x00,0x00,0xFF),
517 	Color(0xFF,0x00,0x00,0x7F),
518 	Color(0xFF,0x22,0x22,0x22),
519 	Color(0xFF,0x22,0x22,0x22),
520 	Color(0xFF,0x7F,0x7F,0x7F),
521 	Color(0xFF,0x00,0x00,0x00)];
522 
523 		writeln(rasters[0].palette);
524 		//rasters[0].addRefreshListener(ow[0],0);
525 		WindowElement.onDraw = &setRasterRefresh;
526 		PopUpElement.onDraw = &setRasterRefresh;
527 		Window.onDrawUpdate = &setRasterRefresh;
528 	}
529 	public void setRasterRefresh(){
530 		rasterRefresh = true;
531 	}
532 	public void whereTheMagicHappens(){
533 		rasters[0].refresh();
534 		while(!onexit){
535 			input.test();
536 			if(rasterRefresh){
537 				rasters[0].refresh();
538 				//rasterRefresh = false;
539 			}
540 			if(rasters.length == 2){
541 				rasters[1].refresh();
542 			}
543 			//rudamentaryFrameCounter();
544 			//onexit = true;
545 		}
546 		configFile.store();
547 	}
548 	public void onExit(){
549 
550 		exitDialog=true;
551 		DefaultDialog dd = new DefaultDialog(Coordinate(10,10,220,75), "exitdialog","Exit application", ["Are you sure?"],
552 				["Yes","No","Pls save"],["ok","close","save"]);
553 
554 		dd.output = &actionEvent;
555 		wh.addWindow(dd);
556 
557 	}
558 	public void newDocument(){
559 		NewDocumentDialog ndd = new NewDocumentDialog(input);
560 		ndd.ie = this;
561 		wh.addWindow(ndd);
562 	}
563 	public void createNewDocument(dstring name, int rX, int rY, int pal){
564 		ow ~= new OutputScreen("Edit window", to!ushort(rX*2),to!ushort(rY*2));
565 		rasters ~= new Raster(to!ushort(rX), to!ushort(rY), ow[1]);
566 		rasters[1].setupPalette(pal);
567 		ow[1].setMainRaster(rasters[1]);
568 		selectionLayer = new EffectLayer();
569 		rasters[1].addLayer(selectionLayer, 65536);
570 		document = new ExtendibleMap();
571 		document.metaData["name"] = to!string(name);
572 		document.metaData["rX"] = to!string(rX);
573 		document.metaData["rY"] = to!string(rY);
574 		document.metaData["pal"] = to!string(pal);
575 	}
576 
577 	public void newLayer(){
578 		if(document !is null){
579 			NewLayerDialog ndd = new NewLayerDialog(this);
580 			wh.addWindow(ndd);
581 		}
582 	}
583 	private void updateLayerList(){
584 
585 	}
586 	public void newTileLayerEvent(string name, string file, bool embed, bool preexisting, int tX, int tY, int mX, int mY){
587 		import std.path;
588 		TileLayer tl = new TileLayer(tX, tY, LayerRenderingMode.ALPHA_BLENDING);
589 
590 		while(layers.get(selectedLayer, null)){
591 			selectedLayer++;
592 		}
593 		TileLayerData tld;
594 		if(preexisting && !embed){
595 			//tld = new TileLayerData(tX, tY, mX, mY, 1.0, 1.0, selectedLayer, MapData.load(file), name);
596 		}else if(!preexisting && embed){
597 			tld = new TileLayerData(tX, tY, mX, mY, 1.0, 1.0, selectedLayer, name);
598 		}else if(!preexisting && !embed){
599 			tld = new TileLayerData(tX, tY, mX, mY, 1.0, 1.0, selectedLayer, name);
600 			//tld.mapping.save(file);
601 		}else if(extension(file) == ".xmf"){
602 			wh.messageWindow("Error"d, "Function of importing embedded mapping from *.xmf files not yet implemented"d, 320);
603 			return;
604 		}
605 		tld.isEmbedded = embed;
606 		//tl.loadMapping(mX,mY,tld.mapping.getCharMapping(),tld.mapping.getAttribMapping());
607 		layers[selectedLayer] = tl;
608 		if(rasters.length > 1){
609 			rasters[1].addLayer(tl,selectedLayer);
610 		}
611 	}
612 	public void newSpriteLayerEvent(string name){
613 		SpriteLayer sl = new SpriteLayer();
614 
615 		while(layers.get(selectedLayer, null)){
616 			selectedLayer++;
617 		}
618 		SpriteLayerData sld = new SpriteLayerData(name, 1.0, 1.0, selectedLayer);
619 		layers[selectedLayer] = sl;
620 		if(rasters.length > 1){
621 			rasters[1].addLayer(sl,selectedLayer);
622 		}
623 	}
624 	public void importTileLayerSymbolData(string file){
625 
626 	}
627 	public int getPreviousTileLayer(int pri){
628 		import std.algorithm.sorting;
629 		int[] list = document.tld.keys;
630 		list.sort();
631 		int n, i;
632 		for( ; i < list.length ; i++){
633 			if(pri == list[i]){
634 				n = list[i];
635 				break;
636 			}
637 		}
638 		selectedLayer--;
639 		if(i == 0){
640 			return n;
641 		}else{
642 			return list[i - 1];
643 		}
644 	}
645 	public int getNextTileLayer(int pri){
646 		import std.algorithm.sorting;
647 		int[] list = document.tld.keys;
648 		list.sort();
649 		int n, i;
650 		for( ; i < list.length ; i++){
651 			if(pri == list[i]){
652 				n = list[i];
653 				break;
654 			}
655 		}
656 		selectedLayer++;
657 		if(i == list.length - 1){
658 			return n;
659 		}else{
660 			return list[i + 1];
661 		}
662 	}
663 	public int moveLayerDown(int pri){
664 		selectedLayer--;
665 		import std.algorithm.sorting;
666 		int[] list = layers.keys;
667 		list.sort();
668 		int n, i;
669 		for( ; i < list.length ; i++){
670 			if(pri == list[i]){
671 				n = list[i];
672 				break;
673 			}
674 		}
675 		if(i == 0){
676 			Layer l = layers[n];
677 			layers[n] = layers[n - 1];
678 			if(document.tld.get(n, null)){
679 				document.tld[n - 1] = document.tld[n];
680 				document.tld.remove(n);
681 				document.tld[n - 1].priority -= 1;
682 			}else{
683 				document.sld[n - 1] = document.sld[n];
684 				document.sld.remove(n);
685 				document.sld[n - 1].priority -= 1;
686 			}
687 			n--;
688 			return n;
689 		}
690 		if(list[i - 1] == n - 1){	//swap two layers
691 			Layer l = layers[n];
692 			layers[n] = layers[n - 1];
693 			if(document.tld.get(n, null)){
694 				document.tld[n - 1] = document.tld[n];
695 				document.tld.remove(n);
696 				document.tld[n - 1].priority -= 1;
697 			}else{
698 				document.sld[n - 1] = document.sld[n];
699 				document.sld.remove(n);
700 				document.sld[n - 1].priority -= 1;
701 			}
702 			n--;
703 			layers[n] = l;
704 			if(document.tld.get(n, null)){
705 				document.tld[n + 1] = document.tld[n];
706 				document.tld.remove(n);
707 				document.tld[n + 1].priority += 1;
708 			}else{
709 				document.sld[n + 1] = document.sld[n];
710 				document.sld.remove(n);
711 				document.sld[n + 1].priority += 1;
712 			}
713 		}else{						//lower the priority of the current layer
714 			Layer l = layers[n];
715 			layers.remove(n);
716 			if(document.tld.get(n, null)){
717 				document.tld[n - 1] = document.tld[n];
718 				document.tld.remove(n);
719 				document.tld[n - 1].priority -= 1;
720 			}else{
721 				document.sld[n - 1] = document.sld[n];
722 				document.sld.remove(n);
723 				document.sld[n - 1].priority -= 1;
724 			}
725 			n--;
726 			layers[n] = l;
727 
728 		}
729 		return n;
730 	}
731 	public int moveLayerUp(int pri){
732 		selectedLayer++;
733 		import std.algorithm.sorting;
734 		int[] list = layers.keys;
735 		list.sort();
736 		int n, i;
737 		for( ; i < list.length ; i++){
738 			if(pri == list[i]){
739 				n = list[i];
740 				break;
741 			}
742 		}
743 		if(i == list.length - 1){
744 			Layer l = layers[n];
745 			layers[n] = layers[n - 1];
746 			if(document.tld.get(n, null)){
747 				document.tld[n - 1] = document.tld[n];
748 				document.tld.remove(n);
749 				document.tld[n - 1].priority -= 1;
750 			}else{
751 				document.sld[n - 1] = document.sld[n];
752 				document.sld.remove(n);
753 				document.sld[n - 1].priority -= 1;
754 			}
755 			n--;
756 			return n;
757 		}
758 		if(list[i + 1] == n + 1){	//swap two layers
759 			Layer l = layers[n];
760 			layers[n] = layers[n + 1];
761 			if(document.tld.get(n, null)){
762 				document.tld[n + 1] = document.tld[n];
763 				document.tld.remove(n);
764 				document.tld[n + 1].priority += 1;
765 			}else{
766 				document.sld[n + 1] = document.sld[n];
767 				document.sld.remove(n);
768 				document.sld[n + 1].priority += 1;
769 			}
770 			n++;
771 			layers[n] = l;
772 			if(document.tld.get(n, null)){
773 				document.tld[n - 1] = document.tld[n];
774 				document.tld.remove(n);
775 				document.tld[n - 1].priority -= 1;
776 			}else{
777 				document.sld[n - 1] = document.sld[n];
778 				document.sld.remove(n);
779 				document.sld[n - 1].priority -= 1;
780 			}
781 		}else{						//higher the priority of the current layer
782 			Layer l = layers[n];
783 			layers.remove(n);
784 			if(document.tld.get(n, null)){
785 				document.tld[n + 1] = document.tld[n];
786 				document.tld.remove(n);
787 				document.tld[n + 1].priority += 1;
788 			}else{
789 				document.sld[n + 1] = document.sld[n];
790 				document.sld.remove(n);
791 				document.sld[n + 1].priority += 1;
792 			}
793 			n++;
794 			layers[n] = l;
795 
796 		}
797 		return n;
798 	}
799 }