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