1 /*
2  * PixelPerfectEditor, converterdialog module 
3  *
4  * Copyright 2017, under Boost License
5  *
6  * by Laszlo Szeremi
7  */
8 module converterdialog;
9 
10 import std.conv;
11 import std.stdio;
12 
13 import PixelPerfectEngine.concrete.window;
14 import PixelPerfectEngine.concrete.elements;
15 
16 import PixelPerfectEngine.map.mapload;
17 
18 import PixelPerfectEngine.system.etc;
19 import PixelPerfectEngine.system.inputHandler;
20 
21 import PixelPerfectEngine.graphics.bitmap;
22 import PixelPerfectEngine.graphics.layers;
23 
24 import PixelPerfectEngine.extbmp.extbmp;
25 
26 import converter;
27 import importDialog;
28 import multiImportDialog;
29 /**
30  *Creates a window for converting external bitmaps for the engine's native format 
31  */
32 public class ConverterDialog : Window{
33 	private ListBox imageList, fileList, animationList, frameList;
34 	private string[] filenames;
35 	private string importFileName,animationSelection;
36 	private Label[string] labels;
37 	private InputHandler inputHandler;
38 	public ExtendibleBitmap[] files;
39 	private ISpriteLayer viewer;
40 	private Bitmap32Bit preview;
41 	private PreviewWindow previewWindow;
42 	private int imageSelection, frameSelection;
43 
44 	public bool previewModeOn;
45 	ExtendibleBitmap selection;
46 	public this(InputHandler inputhandler, ISpriteLayer viewer, ExtendibleMap mh = null, ExtendibleBitmap[] documentFiles = null){
47 		this(Coordinate(0,16,640,480), "XMP Converter Toolkit");
48 		this.inputHandler = inputhandler;
49 		this.viewer = viewer;
50 		files = documentFiles;
51 		Button [] buttons;
52 		if(mh !is null){
53 			//filenames = mh.getAllFilenames();
54 			//fileList = new ListBox("fileList",Coordinate(4,20,204,101), [ListBoxColumn("Filename",filenames)], [256], 15);
55 		}else{
56 			labels["0x00"] = new Label("Path:", "", Coordinate(4,20,204,40));
57 			labels["path"] = new Label("n/a", "path", Coordinate(4,40,204,60));
58 		}
59 		buttons ~= new Button("New File","newfile", Coordinate(210,20,294,39));
60 		buttons ~= new Button("Load File","loadfile", Coordinate(210,40,294,59));
61 		buttons ~= new Button("Save File","savefile", Coordinate(210,60,294,79));
62 		//buttons ~= new Button("Rem File","removefile", Coordinate(210,60,294,79)); //[ListBoxColumn("BitmapID",[""]),ListBoxColumn("Bitdepth",[""]),ListBoxColumn("Format",[""]),ListBoxColumn("PalMode",[""])] //[128,64,64,80]
63 		imageList = new ListBox("imageList",Coordinate(4,104,204,304),null,new ListBoxHeader(["BitmapID","Bitdepth","Format","PalMode","sizeX","sizeY"], [128,64,64,80,42,42]), 15);
64 		buttons ~= new Button("Import New","inportnew", Coordinate(210,110,294,129));
65 		buttons ~= new Button("Imp Multi","inportmultiple", Coordinate(210,130,294,149));
66 		buttons ~= new Button("Export As","exportas", Coordinate(210,150,294,169));
67 		buttons ~= new Button("Remove","remove", Coordinate(210,170,294,189));
68 		buttons ~= new Button("Preview","preview", Coordinate(210,190,294,209));
69 		buttons ~= new Button("Imp Pal","paletteImport", Coordinate(210,210,294,229));
70 		animationList = new ListBox("animationList", Coordinate(300,20,500,120), null, new ListBoxHeader(["AnimID","Frames"], [128,80]), 15);
71 		buttons ~= new Button("New Anim","newAnim", Coordinate(506,20,590,39));
72 		buttons ~= new Button("Edit","animProp", Coordinate(506,40,590,59));
73 		//buttons ~= new Button("Save File","savefile", Coordinate(506,60,590,79));
74 		buttons ~= new Button("Rem Anim","removeAnim", Coordinate(506,60,590,79));
75 		frameList = new ListBox("frameList", Coordinate(300,122,500,304), null, new ListBoxHeader(["Num","ImageID","Dur"],[40,128,64]), 15);
76 		buttons ~= new Button("Add Frame","addFrame", Coordinate(506,130,590,149));
77 		buttons ~= new Button("Edit","editFr", Coordinate(506,150,590,169));
78 		buttons ~= new Button("Remove","removeFr", Coordinate(506,170,590,189));
79 
80 		foreach(Button e; buttons){
81 			addElement(e, EventProperties.MOUSE);
82 			e.onMouseLClickRel = &actionEvent;
83 		}
84 		foreach(WindowElement e; labels){
85 			addElement(e, EventProperties.MOUSE);
86 		}
87 		addElement(imageList, EventProperties.MOUSE);
88 		imageList.onItemSelect = &actionEvent;
89 		addElement(animationList, EventProperties.MOUSE);
90 		addElement(frameList, EventProperties.MOUSE);
91 	}
92 
93 	public this(Coordinate size, wstring title){
94 		super(size, title);
95 	}
96 	
97 	public void singleImport(string bitmapID, string paletteID, bool importPal, string bitDepth){
98 		try{
99 			importDirectlyToXMP(importFileName,paletteID,selection,new ImportData([bitmapID],bitDepth,0,0,0));
100 			if(importPal){//
101 				importPaletteDirectlyToXMP(importFileName,selection,paletteID);
102 			}
103 		}catch(Exception e){
104 			writeln(e);
105 		}
106 	}
107 
108 	public void multiImport(string foretag, string aftertag, int digits, string paletteID, bool importPal, string bitDepth, int numFrom, int sX, int sY, bool useHex){
109 		try{
110 			NamingConvention nc = new NamingConvention(foretag, aftertag, useHex ? NumberingStyle.HEXADECIMAL : NumberingStyle.DECIMAL, numFrom, digits);
111 			importDirectlyToXMP(importFileName, paletteID, selection, new ImportData(nc, bitDepth, sX, sY, 0));
112 			if(importPal){//
113 				importPaletteDirectlyToXMP(importFileName,selection,paletteID);
114 			}
115 		}catch(Exception e){
116 			parent.messageWindow(to!wstring(e.classinfo.toString()), to!wstring(e.msg));
117 		}
118 	}
119 
120 	public void actionEvent(Event event){
121 		//writeln(event.subsource);
122 		//writeln(event.source);
123 		switch(event.subsource){
124 			case "filedialog":
125 				switch(event.source){
126 					case "xmpfiledialog":
127 						ExtendibleBitmap newFile = new ExtendibleBitmap();
128 						string fileName = event.path ;
129 						fileName ~= '\\';
130 						fileName ~= event.filename;
131 						newFile.saveFile(fileName);
132 						if(files is null){
133 							selection = newFile;
134 							labels["path"].setText(to!wstring(fileName));
135 						}else{
136 							files ~= newFile;
137 							filenames ~= fileName;
138 							selection = newFile;
139 						}
140 
141 						break;
142 					case "xmpload":
143 						string fileName = event.path ;
144 						//writeln(fileName);
145 						fileName ~= '\\';
146 						//writeln(fileName);
147 						fileName ~= event.filename;
148 						//writeln(fileName);
149 						ExtendibleBitmap newFile = new ExtendibleBitmap(fileName);
150 						if(files is null){
151 							selection = newFile;
152 							labels["path"].setText(to!wstring(fileName));
153 						}else{
154 							files ~= newFile;
155 							filenames ~= fileName;
156 							selection = newFile;
157 						}
158 						updateImageList();
159 						updateAnimationList();
160 						break;
161 					case "importfile":
162 						string fileName = event.path ;
163 						fileName ~= '\\';
164 						fileName ~= event.filename;
165 						importFileName = fileName;
166 						//Bitmap32Bit bmp = importBitmapFromFile(fileName);
167 						//ImportDialog id = new ImportDialog(this);
168 						//id.al ~= this;
169 						parent.addWindow(new ImportDialog(this));
170 						break;
171 					case "importmulti": 
172 						string fileName = event.path;
173 						fileName ~= '\\';
174 						fileName ~= event.filename;
175 						importFileName = fileName;
176 						BitmapInfo bi = getBitmapInfo(importFileName);
177 						 
178 						parent.addWindow(new MultiImportDialog(bi.width, bi.height, this));
179 						break;
180 					case "palettefile":
181 						string fileName = event.path;
182 						fileName ~= '\\';
183 						fileName ~= event.filename;
184 						importFileName = fileName;
185 						TextInputDialog tid = new TextInputDialog(Coordinate(0,0,200,90),"palName","Import Palette","Palette ID:");
186 						
187 						parent.addWindow(tid);
188 						break;
189 					default: break;
190 				}
191 				break;
192 			/+case "impDial":
193 				
194 				try{
195 					/*Bitmap32Bit bmp = import32BitBitmapFromFile(importFileName);
196 					 selection.addBitmap(cast(void[])bmp.getRawdata(),bmp.getX,bmp.getY,"32bit",to!string(event.text),"ARGB");
197 					 updateImageList();
198 					 previewModeOn = true;
199 					 //set sprite for preview mode
200 					 //writeln(preview);
201 					 viewer.addSprite(bmp, 0, 0, 0);*/
202 					string bitdepth;
203 					switch(event.value){
204 						case 0: bitdepth = "8bit"; break;
205 						case 1: bitdepth = "16bit"; break;
206 						case 2: bitdepth = "32bit"; break;
207 						default: bitdepth = "1bit"; break;
208 					}
209 					importDirectlyToXMP(importFileName,selection,new ImportData([to!string(event.text)],bitdepth,0,0,0));
210 
211 					}catch(Exception e){
212 						writeln(e);
213 					}
214 				break;+/
215 			case "TextInputDialog":
216 				switch(event.source){
217 					case "palName": 
218 						importPaletteDirectlyToXMP(importFileName,selection,to!string(event.text));
219 						break;
220 					default: break;
221 				}
222 				break;
223 			default:
224 				switch(event.source){
225 					case "newfile":
226 						// create new filedialog to save the new file to the given location
227 						FileDialog fileDialog = new FileDialog("Create new XMP file", "xmpfiledialog", &actionEvent, [FileDialog.FileAssociationDescriptor("Extendible bitmap file", ["*.xmp"])], ".\\", true);
228 						parent.addWindow(fileDialog);
229 						break;
230 					case "loadfile":
231 						FileDialog fileDialog = new FileDialog("Load XMP file", "xmpload", &actionEvent, [FileDialog.FileAssociationDescriptor("Extendible bitmap file", ["*.xmp"])], ".\\", false);
232 						parent.addWindow(fileDialog);
233 						break;
234 					case "savefile":
235 						selection.saveFile();
236 						break;
237 					case "preview":
238 						if(preview !is null){
239 							if(previewModeOn){
240 								previewModeOn = false;
241 								previewWindow.close();
242 							}else{
243 								previewModeOn = true;
244 								
245 								previewWindow = new PreviewWindow(preview, viewer, this);
246 								parent.addWindow(previewWindow);
247 							}
248 						}
249 						break;
250 					case "inportnew":
251 						FileDialog fileDialog = new FileDialog("Import PNG/TGA/BMP", "importfile", &actionEvent, [FileDialog.FileAssociationDescriptor("All supported files", ["*.png","*.tga","*.bmp"]),
252 								FileDialog.FileAssociationDescriptor("Portable network graphics", ["*.png"]), FileDialog.FileAssociationDescriptor("Targa graphics file", ["*.tga"]),
253 								FileDialog.FileAssociationDescriptor("Windows bitmap", ["*.bmp"])], ".\\");
254 						parent.addWindow(fileDialog);
255 						break;
256 					case "inportmultiple":
257 						//parent.addWindow(new SpriteSheetDialog());
258 						FileDialog fileDialog = new FileDialog("Import PNG/TGA/BMP", "importmulti", &actionEvent, [FileDialog.FileAssociationDescriptor("All supported files", ["*.png","*.tga","*.bmp"]),
259 								FileDialog.FileAssociationDescriptor("Portable network graphics", ["*.png"]), FileDialog.FileAssociationDescriptor("Targa graphics file", ["*.tga"]),
260 								FileDialog.FileAssociationDescriptor("Windows bitmap", ["*.bmp"])], ".\\");
261 						parent.addWindow(fileDialog);
262 						break;
263 					case "imageList":
264 						//if(!selection.isEmpty){
265 						imageSelection = event.value;
266 							//update image information
267 							//preview = new Bitmap32Bit(selection.getBitmap(imageSelection),selection.getXsize(imageSelection),selection.getYsize(imageSelection));
268 							//writeln(preview);
269 						preview = getBitmapPreview(selection,selection.bitmapID[imageSelection]);
270 						//writeln(preview);
271 						//}
272 						break;
273 					case "paletteImport":
274 						FileDialog fileDialog = new FileDialog("Import Palette", "palettefile", &actionEvent, [FileDialog.FileAssociationDescriptor("All supported files", ["*.png","*.tga","*.bmp"]),
275 							FileDialog.FileAssociationDescriptor("Portable network graphics", ["*.png"]), FileDialog.FileAssociationDescriptor("Targa graphics file", ["*.tga"]),
276 							FileDialog.FileAssociationDescriptor("Windows bitmap", ["*.bmp"])], ".\\");
277 						parent.addWindow(fileDialog);
278 						break;
279 					case "remove":
280 						selection.removeBitmap(imageList.selection);
281 						updateImageList();
282 						break;
283 					default: break;
284 				}
285 				break;
286 		}
287 	}
288 	/+public void sheetDialogEvent(string a, string b, int numFrom, int numOfDigits, int x, int y, int bitdepth, NumberingStyle ns){
289 		string bd;
290 		switch(bitdepth){
291 			case 0: bd="8bit"; break;
292 			case 1: bd="16bit"; break;
293 			case 2: bd="32bit"; break;
294 			default: bd="1bit"; break;
295 		}
296 		importDirectlyToXMP(importFileName,selection,new ImportData(new NamingConvention(a,b,ns,numFrom,numOfDigits),bd,x,y,0));
297 	}+/
298 
299 	private void updateFileList(){
300 
301 	}
302 	private void updateImageList(){
303 		//wstring[] IDs = stringArrayConv(selection.bitmapID);
304 		//wstring[] bt = stringArrayConv(selection.bitdepth), form = stringArrayConv(selection.format), pm = stringArrayConv(selection.paletteMode);
305 		ListBoxItem[] items;
306 		for(int i; i < selection.bitmapID.length; i++){
307 			items ~= new ListBoxItem([to!wstring(selection.bitmapID[i]),to!wstring(selection.bitdepth[i]),to!wstring(selection.format[i]),to!wstring(selection.paletteMode[i]),
308 					to!wstring(selection.getXsize(i)),to!wstring(selection.getYsize(i))]);
309 		}
310 		//imageList.updateColumns([ListBoxColumn("BitmapID",IDs),ListBoxColumn("Bitdepth",bt),ListBoxColumn("Format",form),ListBoxColumn("PalMode",pm)]);
311 		imageList.updateColumns(items);
312 		imageList.draw();
313 	}
314 	private void updateAnimationList(){
315 		//wstring[] IDs, frames;
316 		ListBoxItem[] items;
317 		foreach(s; selection.animData.byKey){
318 			items ~=  new ListBoxItem([to!wstring(s), to!wstring(selection.animData[s].ID.length)]);
319 		}
320 		animationList.updateColumns(items);
321 		animationList.draw();
322 	}
323 	private void updateFrameList(){
324 		//wstring[] num, IDs, dur;
325 		ListBoxItem[] items;
326 		for(int i ; i < selection.animData[animationSelection].ID.length ; i++){
327 			items ~=  new ListBoxItem([to!wstring(i), to!wstring(selection.animData[animationSelection].ID[i]), to!wstring(selection.animData[animationSelection].duration[i])]);
328 		}
329 		frameList.updateColumns(items);
330 		frameList.draw();
331 	}
332 
333 }
334 
335 interface SheetDialogListener{
336 	public void SheetDialogEvent(string a, string b, int numFrom, int numOfDigits, int x, int y, int bitdepth, NumberingStyle ns);
337 }
338 
339 /+public class SpriteSheetDialog : Window, ActionListener{
340 	private TextBox nameA, nameB, numFrom, gridX, gridY, nOfZeros;
341 	private RadioButtonGroup numberingConvention, bitDepthSetter;
342 	//private InputHandler inputHandler;
343 	public SheetDialogListener sdl;
344 	public this(SheetDialogListener sdl){
345 		this.sdl = sdl;
346 		this(Coordinate(0,0,230,340),"Sheet import settings");
347 		nameA = new TextBox("","nameA",Coordinate(120,20,220,40));
348 		addElement(nameA,EventProperties.MOUSE);
349 		addElement(new Label("NameA:","reversed",Coordinate(10,20,120,40)),EventProperties.MOUSE);
350 
351 		nameB = new TextBox("","nameB",Coordinate(120,50,220,70));
352 		addElement(nameB,EventProperties.MOUSE);
353 		addElement(new Label("NameB:","reversed",Coordinate(10,50,120,70)),EventProperties.MOUSE);
354 
355 		numFrom = new TextBox("","numFrom",Coordinate(120,80,220,100));
356 		addElement(numFrom,EventProperties.MOUSE);
357 		addElement(new Label("NumFrom:","reversed",Coordinate(10,80,120,100)),EventProperties.MOUSE);
358 
359 		gridX = new TextBox("","gridX",Coordinate(120,110,220,130));
360 		addElement(gridX,EventProperties.MOUSE);
361 		addElement(new Label("gridX:","reversed",Coordinate(10,110,120,130)),EventProperties.MOUSE);
362 
363 		gridY = new TextBox("","gridY",Coordinate(120,140,220,160));
364 		addElement(gridY,EventProperties.MOUSE);
365 		addElement(new Label("gridY:","reversed",Coordinate(10,140,120,160)),EventProperties.MOUSE);
366 
367 		nOfZeros = new TextBox("","nOfZeros",Coordinate(120,170,220,190));
368 		addElement(nOfZeros,EventProperties.MOUSE);
369 		addElement(new Label("NumOfZeros:","reversed",Coordinate(10,170,120,190)),EventProperties.MOUSE);
370 
371 		bitDepthSetter = new RadioButtonGroup("Bitdepth:","cmode",Coordinate(10,210,110,310),["8Bit","16Bit","32Bit","1Bit"],16,0);
372 		addElement(bitDepthSetter,EventProperties.MOUSE);
373 		numberingConvention = new RadioButtonGroup("numConv:","numConv",Coordinate(120,210,220,310),["Dec","Oct","Hex"],16,0);
374 		addElement(numberingConvention,EventProperties.MOUSE);
375 		Button ok = new Button("Ok","ok",Coordinate(160,315,220,335));
376 		addElement(ok,EventProperties.MOUSE);
377 		ok.al~=this;
378 	}
379 
380 	public this(Coordinate size, wstring title){
381 		super(size, title);
382 	}
383 	public void actionEvent(string source, int type, int value, wstring message){}
384 	public void actionEvent(string source, string subSource, int type, int value, wstring message){}
385 	public void actionEvent(Event event){
386 		if(event.source == "ok"){
387 			NumberingStyle ns;
388 			switch(numberingConvention.getValue){
389 				case 0: ns = NumberingStyle.DECIMAL; break;
390 				case 1: ns = NumberingStyle.OCTAL; break;
391 				case 2: ns = NumberingStyle.HEXADECIMAL; break;
392 				default: break;
393 			}
394 			sdl.SheetDialogEvent(to!string(nameA.getText),to!string(nameB.getText),to!int(numFrom.getText),to!int(nOfZeros.getText),to!int(gridX.getText),to!int(gridY.getText),bitDepthSetter.getValue,ns);
395 			parent.closeWindow(this);
396 		}
397 	}
398 }+/
399 
400 /+public class ImportDialog : Window, ActionListener{
401 	private TextBox name;
402 	private RadioButtonGroup bitdepthSetter;
403 	public ActionListener[] al;
404 	public this(InputHandler inputhandler){
405 		this(Coordinate(0,0,220,200), "Import settings");
406 		addElement(new Label("ID:","0000",Coordinate(10,20,80,40)), EventProperties.MOUSE);
407 		name = new TextBox("","name", Coordinate(100,20,210,40));
408 		//name.addTextInputHandler(inputhandler);
409 		bitdepthSetter = new RadioButtonGroup("Bitdepth:","cmode",Coordinate(20,50,200,150),["8Bit","16Bit","32Bit","1Bit"],16,0);
410 		Button b1 = new Button("Ok","ok",Coordinate(80,160,140,180));
411 		addElement(b1, EventProperties.MOUSE);
412 		b1.al ~= this;
413 		Button b2 = new Button("Cancel","cancel",Coordinate(150,160,210,180));
414 		addElement(b2, EventProperties.MOUSE);
415 		b2.al ~= this;
416 		addElement(bitdepthSetter, EventProperties.MOUSE);
417 		addElement(name, EventProperties.MOUSE);
418 	}
419 
420 	public this(Coordinate size, wstring title){
421 		super(size, title);
422 	}
423 	public void actionEvent(string source, int type, int value, wstring message){}
424 	public void actionEvent(string source, string subSource, int type, int value, wstring message){}
425 	public void actionEvent(Event event){
426 		//writeln(event.source);
427 		switch(event.source){
428 			case "ok": 
429 				foreach(a; al){
430 					a.actionEvent(new Event("impDial","impDial","","",name.getText,bitdepthSetter.getValue,-3));
431 
432 				}
433 				parent.closeWindow(this);
434 				break;
435 			case "cancel": parent.closeWindow(this); break;
436 			default: break;
437 		}
438 	}
439 }+/
440 
441 public class PreviewWindow : Window{
442 	Bitmap32Bit previewImage;
443 	ISpriteLayer spriteLayer;
444 	ConverterDialog cd;
445 	public this(Bitmap32Bit previewImage, ISpriteLayer spriteLayer, ConverterDialog cd){
446 		Coordinate size = Coordinate(0,0,previewImage.width > 78 ? previewImage.width + 2 : 80, previewImage.height + 18);
447 		super(size, "Preview");
448 		spriteLayer.addSprite(previewImage, -1, 2, 18, BitmapAttrib(false,false));
449 		this.spriteLayer = spriteLayer;
450 		this.cd = cd;
451 	}
452 	
453 	public deprecated void actionEvent(Event event) {
454 	
455 	}
456 	
457 	override public void move(int x,int y) {
458 		spriteLayer.moveSprite(-1,x+2,y+18);
459 		super.move(x,y);
460 	}
461 	override public void relMove(int x,int y) {
462 		spriteLayer.relMoveSprite(-1,x,y);
463 		super.relMove(x,y);
464 	}
465 	override public void close() {
466 		spriteLayer.removeSprite(-1);
467 		cd.previewModeOn = false;
468 		super.close;
469 	}
470 	
471 }
472