1 /*
2  * Copyright (C) 2015-2017, by Laszlo Szeremi under the Boost license.
3  *
4  * Pixel Perfect Engine, concrete.elements module
5  */
6 
7 module PixelPerfectEngine.concrete.elements;
8 
9 import PixelPerfectEngine.graphics.bitmap;
10 import PixelPerfectEngine.graphics.draw;
11 import PixelPerfectEngine.system.etc;
12 import PixelPerfectEngine.system.inputHandler;
13 import std.algorithm;
14 import std.stdio;
15 import std.conv;
16 import PixelPerfectEngine.concrete.stylesheet;
17 
18 abstract class WindowElement{
19 	public ActionListener[] al;
20 	private wstring text;
21 	private string source;
22 	private Coordinate position;
23 	private int sizeX, sizeY;
24 	//public int font;
25 	public BitmapDrawer output;
26 	//public Bitmap16Bit[int] altStyleBrush;
27 	public ElementContainer elementContainer;
28 	public StyleSheet customStyle;
29 
30 	public static InputHandler inputHandler;
31 	//public static StyleSheet defaultStyle;
32 	
33 	public void onClick(int offsetX, int offsetY, int type = 0){
34 		
35 	}
36 	public void onKey(char c, int type){
37 		
38 	}
39 	public void onScroll(int x, int y, int wX, int wY){
40 		
41 	}
42 	public int getX(){
43 		return sizeX;
44 	}
45 	public int getY(){
46 		return sizeY;
47 	}
48 	public Coordinate getPosition(){
49 		return position;
50 	}
51 	/*
52 	 * Updates the output.
53 	 */
54 	public abstract void draw();
55 	
56 	private void invokeActionEvent(int type, int value, wstring message = ""){
57 		foreach(ActionListener a; al){
58 			//a.actionEvent(source, type, value, message);
59 			a.actionEvent(new Event(source, null, null, null, text, value, type));
60 		}
61 	}
62 	/*private Bitmap16Bit getBrush(int style){
63 		return altStyleBrush.get(style, elementContainer.getStyleBrush(style));
64 	}*/
65 	public wstring getText(){
66 		return text;
67 	}
68 	public void setText(wstring s){
69 		text = s;
70 		draw;
71 	}
72 
73 	public StyleSheet getAvailableStyleSheet(){
74 		if(customStyle is null){
75 			return elementContainer.getStyleSheet();
76 		}
77 		return customStyle;
78 	}
79 
80 	public void setCustomStyle(StyleSheet s){
81 		customStyle = s;
82 	}
83 
84 	/*public static void initalizeDefaultStyle(){
85 		defaultStyle = new StyleSheet();
86 	}*/
87 
88 	/*public static void setDefaultStyle(StyleSheet s){
89 		defaultStyle = s;
90 	}*/
91 }
92 
93 public class Button : WindowElement{
94 	
95 	private bool isPressed;
96 	public int brushPressed, brushNormal;
97 	
98 	public this(wstring text, string source, Coordinate coordinates){
99 		position = coordinates;
100 		sizeX = coordinates.getXSize();
101 		sizeY = coordinates.getYSize();
102 		this.text = text;
103 		this.source = source;
104 		output = new BitmapDrawer(sizeX, sizeY);
105 		brushPressed = 1;
106 		//draw();
107 	}
108 	public override void draw(){
109 		output.drawFilledRectangle(0, position.getXSize()-1, 0,position.getYSize()-1, getAvailableStyleSheet().getColor("window"));
110 		if(isPressed){
111 			/*output.drawRectangle(0, sizeX, 0, sizeY, getBrush(brushNormal));
112 			 int x = getBrush(brushNormal).getX() / 2, y = getBrush(brushNormal).getY() / 2;
113 			 output.drawFilledRectangle(x, sizeX - 1 - x, y, sizeY - 1 - y, getBrush(brushNormal).readPixel(x, y));*/
114 			output.drawLine(0, position.getXSize()-1, 0, 0, getAvailableStyleSheet().getColor("windowdescent"));
115 			output.drawLine(0, 0, 0, position.getYSize()-1, getAvailableStyleSheet().getColor("windowdescent"));
116 			output.drawLine(0, position.getXSize()-1, position.getYSize()-1, position.getYSize()-1, getAvailableStyleSheet().getColor("windowascent"));
117 			output.drawLine(position.getXSize()-1, position.getXSize()-1, 0, position.getYSize()-1, getAvailableStyleSheet().getColor("windowascent"));
118 		}else{
119 			/*output.drawRectangle(0, sizeX, 0, sizeY, getBrush(brushPressed));
120 			 int x = getBrush(brushNormal).getX() / 2, y = getBrush(brushNormal).getY() / 2;
121 			 output.drawFilledRectangle(x, sizeX - 1 - x, y, sizeY - 1 - y, getBrush(brushNormal).readPixel(x, y));*/
122 			output.drawLine(0, position.getXSize()-1, 0, 0, getAvailableStyleSheet().getColor("windowascent"));
123 			output.drawLine(0, 0, 0, position.getYSize()-1, getAvailableStyleSheet().getColor("windowascent"));
124 			output.drawLine(0, position.getXSize()-1, position.getYSize()-1, position.getYSize()-1, getAvailableStyleSheet().getColor("windowdescent"));
125 			output.drawLine(position.getXSize()-1, position.getXSize()-1, 0, position.getYSize()-1, getAvailableStyleSheet().getColor("windowdescent"));
126 		}
127 		
128 		output.drawText(sizeX/2, sizeY/2, text, getAvailableStyleSheet().getFontset("default"));
129 		elementContainer.drawUpdate(this);
130 	}
131 	public override void onClick(int offsetX, int offsetY, int type = 0){
132 		if(type == 0){
133 			isPressed = !isPressed;
134 			draw();
135 			invokeActionEvent(EventType.CLICK, isPressed);
136 			isPressed = !isPressed;
137 			draw();
138 		}
139 	}
140 }
141 
142 public class Label : WindowElement{
143 	public this(wstring text, string source, Coordinate coordinates){
144 		position = coordinates;
145 		sizeX = coordinates.getXSize();
146 		sizeY = coordinates.getYSize();
147 		this.text = text;
148 		this.source = source;
149 		output = new BitmapDrawer(sizeX, sizeY);
150 		//draw();
151 	}
152 	public override void draw(){
153 		//writeln(elementContainer);
154 		output.drawText(0, 0, text, getAvailableStyleSheet().getFontset("default"), 1);
155 		elementContainer.drawUpdate(this);
156 	}
157 	public override void onClick(int offsetX, int offsetY, int type = 0){
158 		if(type == 0)
159 			invokeActionEvent(EventType.CLICK, 0);
160 	}
161 }
162 
163 public class TextBox : WindowElement, TextInputListener{
164 	private bool enableEdit, insert;
165 	private uint pos;
166 	public int brush, textpos;
167 	//public TextInputHandler tih;
168 	
169 	public this(wstring text, string source, Coordinate coordinates){
170 		position = coordinates;
171 		sizeX = coordinates.getXSize();
172 		sizeY = coordinates.getYSize();
173 		this.text = text;
174 		this.source = source;
175 		output = new BitmapDrawer(sizeX, sizeY);
176 		inputHandler.addTextInputListener(source, this);
177 		//insert = true;
178 		//draw();
179 	}
180 
181 	public deprecated void addTextInputHandler(TextInputHandler t){	/** DEPRECATED. Will be removed soon in favor of static input handlers. */
182 		/*tih = t;*/
183 		inputHandler.addTextInputListener(source, this);
184 	}
185 	
186 	public void onClick(int offsetX, int offsetY, int type = 0){
187 		//writeln(0);
188 		if(!enableEdit && type == 0){
189 			invokeActionEvent(EventType.READYFORTEXTINPUT, 0);
190 			enableEdit = true;
191 			inputHandler.startTextInput(source);
192 			draw();
193 		}
194 	}
195 	public override void draw(){
196 		output.drawFilledRectangle(0, sizeX - 1, 0, sizeY - 1, getAvailableStyleSheet().getColor("window"));
197 		output.drawRectangle(0, sizeX - 1, 0, sizeY - 1, getAvailableStyleSheet().getColor("windowascent"));
198 		
199 		//draw cursor
200 		if(enableEdit){
201 			int x = getAvailableStyleSheet().getFontset("default").letters['A'].getX() , y = getAvailableStyleSheet().getFontset("default").letters['A'].getY();
202 			if(!insert)
203 				output.drawLine((x*pos) + 2, (x*pos) + 2, 2, 2 + y, getAvailableStyleSheet().getColor("selection"));
204 			else
205 				output.drawFilledRectangle((x*pos) + 2, (x*(pos + 1)) + 2, 2, 2 + y, getAvailableStyleSheet().getColor("selection"));
206 		}
207 		
208 		output.drawText(2, 2, text, getAvailableStyleSheet().getFontset("default"), 1);
209 		elementContainer.drawUpdate(this);
210 	}
211 	
212 	alias onKey = WindowElement.onKey;
213 	public void onKey(wchar c, int type){
214 		
215 		/*if(enableEdit){
216 		 if(type == 0){
217 		 text ~= c;
218 		 pos++;
219 		 draw();
220 		 }else if(type == 1){
221 		 pos++;
222 		 }else if(type == 2){
223 		 pos--;
224 		 }else if(type == 3){
225 		 invokeActionEvent(EventType.TEXTINPUT, 0, text);
226 		 }else{
227 		 deleteCharacter(pos);
228 		 pos--;
229 		 draw();
230 		 }
231 		 }*/
232 	}
233 	private void deleteCharacter(int n){
234 		//text = remove(text, i);
235 		wstring newtext;
236 		for(int i; i < text.length; i++){
237 			if(i != n - 1){
238 				newtext ~= text[i];
239 			}
240 		}
241 		text = newtext;
242 	}
243 	public void focusGiven(){}
244 	public void focusLost(){}
245 	public void textInputEvent(uint timestamp, uint windowID, char[32] text){
246 		//writeln(0);
247 		int j = pos;
248 		wstring newtext;
249 		for(int i ; i < pos ; i++){
250 			newtext ~= this.text[i];
251 		}
252 		for(int i ; i < 32 ; i++){
253 			if(text[i] == 0){
254 				break;
255 			}
256 			else{
257 				newtext ~= text[i];
258 				pos++;
259 				if(insert){
260 					j++;
261 				}
262 			}
263 		}
264 		for( ; j < this.text.length ; j++){
265 			newtext ~= this.text[j];
266 		}
267 		this.text = newtext;
268 		draw();
269 	}
270 	
271 	public void dropTextInput(){
272 		enableEdit = false;
273 		inputHandler.stopTextInput(source);
274 		draw();
275 		invokeActionEvent(EventType.TEXTINPUT, 0, text);
276 	}
277 
278 
279 	public void textInputKeyEvent(uint timestamp, uint windowID, InputKey key){
280 		if(key == InputKey.ESCAPE || key == InputKey.ENTER){
281 			enableEdit = false;
282 			inputHandler.stopTextInput(source);
283 			draw();
284 			invokeActionEvent(EventType.TEXTINPUT, 0, text);
285 		}else if(key == InputKey.BACKSPACE){
286 			if(pos > 0){
287 				deleteCharacter(pos);
288 				pos--;
289 				draw();
290 			}
291 			/*if(pos > 0){
292 			 if(pos == text.length){
293 			 text.length--;
294 			 pos--;
295 			 
296 			 }
297 			 }*/
298 		}else if(key == InputKey.DELETE){
299 			deleteCharacter(pos + 1);
300 			draw();
301 		}else if(key == InputKey.CURSORLEFT){
302 			if(pos > 0){
303 				--pos;
304 				draw();
305 			}
306 		}else if(key == InputKey.CURSORRIGHT){
307 			if(pos < text.length){
308 				++pos;
309 				draw();
310 			}
311 		}else if(key == InputKey.INSERT){
312 			insert = !insert;
313 			draw();
314 		}else if(key == InputKey.HOME){
315 			pos = 0;
316 			draw();
317 		}else if(key == InputKey.END){
318 			pos = text.length;
319 			draw();
320 		}
321 	}
322 }
323 
324 
325 public class ListBox : WindowElement, ActionListener, ElementContainer{
326 	public ListBoxColumn[] columns;
327 	public int[] columnWidth;
328 	public int brushHeader, brush, fontHeader, rowHeight;
329 	public ushort selectionColor;
330 	private bool fullRedraw, bodyDrawn;
331 	private VSlider vSlider;
332 	private HSlider hSlider;
333 	private int fullX, hposition, vposition, selection, sliderX, sliderY, startY, endY;
334 	private BitmapDrawer textArea, headerArea;
335 	
336 	public this(string source, Coordinate coordinates, ListBoxColumn[] columns, int[] columnWidth, int rowHeight, /*VSlider vSlider = null, HSlider = null*/){
337 		position = coordinates;
338 		sizeX = coordinates.getXSize();
339 		sizeY = coordinates.getYSize();
340 		//this.text = text;
341 		this.source = source;
342 		this.rowHeight = rowHeight;
343 		this.columnWidth = columnWidth;
344 		updateColumns(columns);
345 
346 		foreach(int i; columnWidth){
347 			fullX += i;
348 		}
349 		if(fullX < position.getXSize()){
350 			fullX = position.getXSize();
351 		}
352 		
353 		output = new BitmapDrawer(sizeX, sizeY);
354 
355 		int foo = rowHeight * this.columns[0].elements.length;
356 		if(foo < position.getYSize())
357 			foo = position.getXSize;
358 
359 		/*textArea = new BitmapDrawer(fullX, foo);
360 		headerArea = new BitmapDrawer(fullX, rowHeight);*/
361 		//writeln(columns[0].elements.length,',', ((position.getYSize()-16-rowHeight) / rowHeight));
362 		/*this.vSlider = new VSlider(columns[0].elements.length - 1, ((position.getYSize()-17-rowHeight) / rowHeight), "vslider", Coordinate(position.getXSize - 16, 0, position.getXSize, position.getYSize() - 16));
363 		this.hSlider = new HSlider(fullX - 16, position.getXSize() - 16, "hslider", Coordinate(0, position.getYSize() - 16, position.getXSize() - 16, position.getYSize() ));
364 		this.vSlider.al ~= this;
365 		this.vSlider.elementContainer = this;
366 		sliderX = vSlider.getX();
367 
368 
369 		this.hSlider.al ~= this;
370 		this.hSlider.elementContainer = this;
371 		sliderY = hSlider.getY();*/
372 	}
373 	
374 	public void actionEvent(string source, int type, int value, wstring message){
375 		draw();
376 	}
377 	public void actionEvent(string source, string subsource, int type, int value, wstring message){}
378 	public void actionEvent(Event event){}
379 	public void getFocus(WindowElement sender){}
380 	public void dropFocus(WindowElement sender){}
381 	public void drawUpdate(WindowElement sender){
382 		output.insertBitmap(sender.getPosition().left,sender.getPosition().top,sender.output.output);
383 
384 		if(!fullRedraw){
385 			/*output.insertBitmapSlice(0,0,headerArea.output,Coordinate(vposition,0,vposition + fullX - 1, rowHeight - 1));
386 			output.insertBitmapSlice(0, rowHeight, textArea.output, Coordinate(vposition,hposition * rowHeight,vposition + fullX - 1 , hposition * rowHeight + (sizeY - hSlider.getPosition().getYSize) - rowHeight));*/
387 			elementContainer.drawUpdate(this);
388 		}
389 	}
390 	/*public Bitmap16Bit getStyleBrush(int style){
391 		return elementContainer.getStyleBrush(style);
392 	}*/
393 	/*public Bitmap16Bit[wchar] getFontSet(int style){
394 		return elementContainer.getFontSet(style);
395 	}*/
396 	public void updateColumns(ListBoxColumn[] lbc){
397 		columns = lbc;
398 		fullX = 0;
399 		selection = 0;
400 		foreach(int i; columnWidth){
401 			fullX += i;
402 		}
403 		if(fullX < position.getXSize()){
404 			fullX = position.getXSize();
405 		}
406 		int foo2 = rowHeight * this.columns[0].elements.length;
407 		if(foo2 < position.getYSize())
408 			foo2 = position.getXSize;
409 		
410 		textArea = new BitmapDrawer(fullX, foo2);
411 		headerArea = new BitmapDrawer(fullX, rowHeight);
412 
413 		this.vSlider = new VSlider(columns[0].elements.length - 1, ((position.getYSize()-17-rowHeight) / rowHeight), "vslider", Coordinate(position.getXSize - 16, 0, position.getXSize, position.getYSize() - 16));
414 		this.hSlider = new HSlider(fullX - 16, position.getXSize() - 16, "hslider", Coordinate(0, position.getYSize() - 16, position.getXSize() - 16, position.getYSize() ));
415 		this.vSlider.al ~= this;
416 		this.vSlider.elementContainer = this;
417 		sliderX = vSlider.getX();
418 		
419 		
420 		this.hSlider.al ~= this;
421 		this.hSlider.elementContainer = this;
422 		sliderY = hSlider.getY();
423 		bodyDrawn = false;
424 	}
425 
426 	public StyleSheet getStyleSheet(){
427 		return getAvailableStyleSheet;
428 	}
429 
430 	private void drawBody(){
431 		int foo;
432 		for(int i; i < columns.length; i++){
433 			int bar;
434 			for(int j; j < columns[i].elements.length; j++){
435 				//writeln(foo + 1, bar);
436 				textArea.drawText(foo + 1, bar, columns[i].elements[j], getStyleSheet().getFontset("default"), 1);
437 
438 				bar += rowHeight;
439 			}
440 			foo += columnWidth[i];
441 			//writeln(foo, foo, 0, textArea.output.getX()-1);
442 			textArea.drawLine(foo, foo, 0, textArea.output.getY()-2, getStyleSheet().getColor("windowascent"));
443 		}
444 	}
445 
446 	public override void draw(){
447 		fullRedraw = true;
448 
449 
450 
451 
452 		int areaX, areaY;
453 
454 		vposition = vSlider.getSliderPosition();
455 		areaX = sizeX - vSlider.getPosition().getXSize;
456 
457 
458 		hposition = hSlider.getSliderPosition();
459 		areaY = sizeY - hSlider.getPosition().getYSize;
460 
461 		//writeln(vposition, hposition);
462 
463 
464 		output.drawFilledRectangle(0, position.getXSize(), 0, position.getYSize(),getStyleSheet().getColor("window"));
465 		output.drawRectangle(0, position.getXSize() - 1, 0, position.getYSize() - 1,getStyleSheet().getColor("windowascent"));
466 
467 
468 		// draw the header
469 		output.drawLine(0, position.getXSize() - 1, rowHeight, rowHeight, getStyleSheet().getColor("windowascent"));
470 		int foo;
471 		for(int i; i < columnWidth.length; i++){
472 			headerArea.drawText(foo + 1, 0, columns[i].header, getStyleSheet().getFontset("default"), 1);
473 			foo += columnWidth[i];
474 			headerArea.drawLine(foo, foo, 0, rowHeight - 2, getStyleSheet().getColor("windowascent"));
475 			//writeln(foo);
476 		}
477 
478 		output.insertBitmapSlice(0,0,headerArea.output,Coordinate(hposition,0,hposition + position.getXSize() - 17, rowHeight - 1));
479 
480 		//draw the selector
481 		if(selection - vposition >= 0 && vposition + ((position.getYSize()-17-rowHeight) / rowHeight) >= selection && columns[0].elements.length != 0)
482 			output.drawFilledRectangle(1, position.getXSize() - 2, rowHeight + (rowHeight * (selection - vposition)), (rowHeight * 2) + (rowHeight * (selection - vposition)), getStyleSheet().getColor("selection"));
483 
484 		// draw the body
485 		if(!bodyDrawn){
486 			bodyDrawn = true;
487 			drawBody();
488 		}
489 
490 		//writeln(textArea.output.getX(),textArea.output.getY());
491 		output.insertBitmapSlice(0, rowHeight, textArea.output, Coordinate(hposition,vposition * rowHeight,hposition + position.getXSize() - 17 , vposition * rowHeight + areaY - rowHeight));
492 
493 		vSlider.draw();
494 		hSlider.draw();
495 
496 		elementContainer.drawUpdate(this);
497 		fullRedraw = false;
498 		//writeln(0);
499 	}
500 	public override void onClick(int offsetX, int offsetY, int type = 0){
501 		if(offsetX > (vSlider.getPosition().left) && offsetY > (vSlider.getPosition().top)){
502 			vSlider.onClick(offsetX - vSlider.getPosition().left, offsetY - vSlider.getPosition().top, type);
503 			return;
504 
505 		}else if(offsetX > (hSlider.getPosition().left) && offsetY > (hSlider.getPosition().top)){
506 			//writeln(offsetX,',',offsetY);
507 			hSlider.onClick(offsetX - hSlider.getPosition().left, offsetY - hSlider.getPosition().top, type);
508 			return;
509 			
510 		}else if(offsetY > rowHeight && type == 0){
511 			offsetY -= rowHeight;
512 			//writeln(selection);
513 			if(selection == (offsetY / rowHeight) + vposition){
514 				invokeActionEvent(EventType.TEXTBOXSELECT, (offsetY / rowHeight) + vposition);
515 			}
516 			else{
517 				if((offsetY / rowHeight) + vposition < columns[0].elements.length){
518 					selection = (offsetY / rowHeight) + vposition;
519 					draw();
520 				}
521 			}
522 		}
523 	}
524 	public void onScroll(int x, int y, int wX, int wY){
525 
526 		vSlider.onScroll(x,y,0,0);
527 		hSlider.onScroll(x,y,0,0);
528 	}
529 }
530 
531 public class CheckBox : WindowElement{
532 	public int iconChecked, iconUnchecked;
533 	private bool checked;
534 	public int[] brush;
535 	
536 	public this(wstring text, string source, Coordinate coordinates){
537 		position = coordinates;
538 		sizeX = coordinates.getXSize();
539 		sizeY = coordinates.getYSize();
540 		this.text = text;
541 		this.source = source;
542 		brush ~= 2;
543 		brush ~= 3;
544 		output = new BitmapDrawer(sizeX, sizeY);
545 		//draw();
546 	}
547 	
548 	public override void draw(){
549 		output.drawText(0 , getAvailableStyleSheet().getImage("checkBoxA").getY, text, getAvailableStyleSheet().getFontset("default"), 1);
550 		if(checked){
551 			output.insertBitmap(0, 0, getAvailableStyleSheet().getImage("checkBoxB"));
552 		}else{
553 			output.insertBitmap(0, 0, getAvailableStyleSheet().getImage("checkBoxA"));
554 		}
555 		elementContainer.drawUpdate(this);
556 	}
557 	
558 	public override void onClick(int offsetX, int offsetY, int type = 0){
559 		checked = !checked;
560 		draw();
561 		invokeActionEvent(EventType.CHECKBOX, checked);
562 	}
563 }
564 
565 public class RadioButtonGroup : WindowElement{
566 	public int iconChecked, iconUnchecked;
567 	private int bposition, rowSpace, buttonpos;
568 	public wstring[] options;
569 	public int[] brush;
570 	public ushort border, background;
571 	
572 	public this(wstring text, string source, Coordinate coordinates, wstring[] options, int rowSpace, int buttonpos){
573 		this.position = coordinates;
574 		sizeX = coordinates.getXSize();
575 		sizeY = coordinates.getYSize();
576 		this.text = text;
577 		this.source = source;
578 		this.options = options;
579 		brush ~= 4;
580 		brush ~= 5;
581 		output = new BitmapDrawer(sizeX, sizeY);
582 		//draw();
583 	}
584 	
585 	public override void draw(){
586 		//output.drawFilledRectangle(0, sizeX-1, 0, sizeY-1, background);
587 		output.drawRectangle(0, sizeX-1, 0, sizeY-1, getAvailableStyleSheet().getColor("windowascent"));
588 		output.drawText(16,0,text, getAvailableStyleSheet().getFontset("default"),1);
589 		for(int i; i < options.length; i++){
590 
591 			output.drawText(16, 16 * (i+1),options[i],getAvailableStyleSheet().getFontset("default"),1);
592 			if(bposition == i){
593 				output.insertBitmap(1, 16 * (i+1),getAvailableStyleSheet.getImage("radioButtonB"));
594 			}else{
595 				output.insertBitmap(1, 16 * (i+1),getAvailableStyleSheet.getImage("radioButtonA"));
596 			}
597 		}
598 		elementContainer.drawUpdate(this);
599 	}
600 	
601 	public override void onClick(int offsetX, int offsetY, int type = 0){
602 		bposition = (offsetY) / 16;
603 		bposition--;
604 		draw();
605 		invokeActionEvent(EventType.RADIOBUTTON, bposition);
606 	}
607 	public int getValue(){
608 		return bposition;
609 	}
610 }
611 
612 abstract class Slider : WindowElement{
613 	public int[] brush;
614 	
615 	public int value, maxValue, barLength;
616 	
617 	/*
618 	 * Returns the slider position. If barLenght > 1, then it returns the lower value.
619 	 */
620 	public int getSliderPosition(){
621 		return value;
622 	}
623 }
624 
625 public class VSlider : Slider{
626 	//public int[] brush;
627 	
628 	//private int value, maxValue, barLength;
629 	
630 	public this(int maxValue, int barLenght, string source, Coordinate coordinates){
631 		position = coordinates;
632 		sizeX = coordinates.getXSize();
633 		sizeY = coordinates.getYSize();
634 		//this.text = text;
635 		this.source = source;
636 		this.maxValue = maxValue;
637 		this.barLength = barLenght;
638 		output = new BitmapDrawer(sizeX, sizeY);
639 		brush ~= 6;
640 		brush ~= 8;
641 		//brush ~= 10;
642 		//draw();
643 	}
644 	public override void draw(){
645 		//draw background
646 		//Bitmap16Bit sliderStyle = elementContainer.getStyleBrush(brush[2]);
647 		//ushort backgroundColor = sliderStyle.readPixel(0,0), sliderColor = sliderStyle.readPixel(1,0);
648 		output.drawFilledRectangle(0, sizeX , 0, sizeY , getAvailableStyleSheet.getColor("windowinactive"));
649 		//draw upper arrow
650 		output.insertBitmap(0,0,getAvailableStyleSheet.getImage("upArrowA"));
651 		//draw lower arrow
652 		output.insertBitmap(0, sizeY - getAvailableStyleSheet.getImage("downArrowA").getY(),getAvailableStyleSheet.getImage("downArrowA"));
653 		//draw slider
654 		if(maxValue > barLength){
655 			double sliderlength = position.getYSize() - (getAvailableStyleSheet.getImage("upArrowA")).getY()*2, unitlength = sliderlength/maxValue;
656 			double sliderpos = unitlength * value, bl = unitlength * barLength;
657 			int posA = to!int(sliderpos) + getAvailableStyleSheet.getImage("upArrowA").getY(), posB = to!int(bl + sliderpos) + getAvailableStyleSheet.getImage("upArrowA").getY();
658 
659 			output.drawFilledRectangle(0,sizeX,posA, posB, getAvailableStyleSheet.getColor("windowascent"));
660 		}
661 		elementContainer.drawUpdate(this);
662 	}
663 	
664 	
665 	public override void onClick(int offsetX, int offsetY, int type = 0){
666 		if(offsetY <= getAvailableStyleSheet.getImage("upArrowA").getY()){
667 			if(value != 0) value--;
668 		}
669 		else if(sizeY-getAvailableStyleSheet.getImage("upArrowA").getY() <= offsetY){
670 			if(value < maxValue - barLength) value++;
671 		}
672 		else{
673 			offsetY -= getAvailableStyleSheet.getImage("upArrowA").getY();
674 			double sliderlength = position.getYSize() - (getAvailableStyleSheet.getImage("upArrowA").getY()*2), unitlength = sliderlength/maxValue;
675 			int v = to!int(offsetY / unitlength);
676 			//value = ((sizeY - (elementContainer.getStyleBrush(brush[1]).getY() * 2)) - offsetY) * (value / maxValue);
677 			if(v < maxValue - barLength) value = v;
678 			else value = maxValue - barLength;
679 		}
680 		invokeActionEvent(EventType.SLIDER, value);
681 		draw();
682 
683 	}
684 	public override void onScroll(int x, int y, int wX, int wY){
685 
686 		if(x == 1){
687 			if(value != 0) value--;
688 		}else if(x == -1){
689 			if(value < maxValue - barLength) value++;
690 		}
691 		invokeActionEvent(EventType.SLIDER, value);
692 		draw();
693 	}
694 }
695 
696 public class HSlider : Slider{
697 	public this(int maxValue, int barLenght, string source, Coordinate coordinates){
698 		position = coordinates;
699 		sizeX = coordinates.getXSize();
700 		sizeY = coordinates.getYSize();
701 		//this.text = text;
702 		this.source = source;
703 		this.maxValue = maxValue;
704 		this.barLength = barLenght;
705 		//writeln(barLenght,',',maxValue);
706 		output = new BitmapDrawer(sizeX, sizeY);
707 		brush ~= 14;
708 		brush ~= 16;
709 		//brush ~= 10;
710 		//draw();
711 	}
712 	public override void draw(){
713 		//draw background
714 		//Bitmap16Bit sliderStyle = elementContainer.getStyleBrush(brush[2]);
715 		//ushort backgroundColor = sliderStyle.readPixel(0,0), sliderColor = sliderStyle.readPixel(1,0);
716 		output.drawFilledRectangle(0, sizeX , 0, sizeY , getAvailableStyleSheet().getColor("windowinactive"));
717 		//draw left arrow
718 		output.insertBitmap(0,0,getAvailableStyleSheet.getImage("leftArrowA"));
719 		//draw right arrow
720 		output.insertBitmap(sizeX - getAvailableStyleSheet.getImage("rightArrowA").getX(),0,getAvailableStyleSheet.getImage("rightArrowA"));
721 		//draw slider
722 		if(maxValue > barLength){
723 			double sliderlength = position.getXSize() - (getAvailableStyleSheet.getImage("rightArrowA").getX()*2), unitlength = sliderlength/maxValue;
724 			double sliderpos = unitlength * value, bl = unitlength * barLength;
725 
726 			int posA = to!int(sliderpos) + getAvailableStyleSheet.getImage("rightArrowA").getY(), posB = to!int(bl + sliderpos) + getAvailableStyleSheet.getImage("rightArrowA").getY();
727 		
728 			output.drawFilledRectangle(posA, posB, 0, position.getYSize(),getAvailableStyleSheet().getColor("windowascent"));
729 		}
730 		elementContainer.drawUpdate(this);
731 	}
732 	public override void onClick(int offsetX, int offsetY, int type = 0){
733 		if(offsetX <= getAvailableStyleSheet.getImage("rightArrowA").getX()){
734 			if(value != 0) value--;
735 		}
736 		else if(sizeX-getAvailableStyleSheet.getImage("rightArrowA").getX() <= offsetX){
737 			if(value < maxValue - barLength) value++;
738 		}
739 		else{
740 			offsetX -= getAvailableStyleSheet.getImage("rightArrowA").getX();
741 			double sliderlength = position.getXSize() - (elementContainer.getStyleSheet.getImage("rightArrowA").getX()*2), unitlength = sliderlength/maxValue;
742 			int v = to!int(offsetX / unitlength);
743 			if(v < maxValue - barLength) value = v;
744 			else value = maxValue - barLength;
745 		}
746 		invokeActionEvent(EventType.SLIDER, value);
747 		draw();
748 
749 	}
750 	public override void onScroll(int x, int y, int wX, int wY){
751 		if(y == -1){
752 			if(value != 0) value--;
753 		}else if(y == 1){
754 			if(value < maxValue - barLength) value++;
755 		}
756 		invokeActionEvent(EventType.SLIDER, value);
757 		draw();
758 	}
759 }
760 
761 /**
762  * To create drop-down lists, menu bars, etc.
763  */
764 public class PopUpMenu: PopUpElement{
765 	private wstring[] texts;
766 	private string[] sources;
767 	private string subsource;
768 	private uint[int] hotkeyCodes;
769 	private Bitmap16Bit[int] icons;
770 	public BitmapDrawer output;
771 	private ElementContainer elementContainer;
772 	public static InputHandler inputhandler;
773 
774 	public this(int columnheight, string subsource, string[] sources, wstring[] texts, uint[int] hotkeyCodes = null){
775 
776 	}
777 
778 	/**
779 	 * Use this if you want icons in your list.
780 	 * All the icons have to be the same exact size, otherwise it might cause exceptions.
781 	 */
782 	public this(int columnheight, string subsource, string[] sources, wstring[] texts, Bitmap16Bit[int] icons, uint[int] hotkeyCodes = null){
783 		
784 	}
785 
786 	public void onClick(int x, int y){
787 		
788 	}
789 	public void onKey(uint keycode){
790 		
791 	}
792 	public void onScroll(int x, int y, int wX, int wY){
793 		
794 	}
795 	public void addPopUpHandler(PopUpHandler p){}
796 }
797 public interface PopUpElement{
798 	public void onClick(int x, int y); 
799 	public void addPopUpHandler(PopUpHandler p);
800 }
801 public interface PopUpHandler{
802 	public void addPopUpElement(PopUpElement p);
803 }
804 
805 /*public interface IElement{
806 	public void onClick();
807 	public Coordinate getPosition();
808 }*/
809 /**
810  * For use with ListBoxes and similar types
811  */
812 public struct ListBoxColumn{
813 	public wstring header;
814 	public wstring[] elements;
815 	
816 	this(wstring header, wstring[] elements){
817 		this.header = header;
818 		this.elements = elements;
819 	}
820 
821 	/*this(string header, string[] elements){
822 		this.header = to!wstring(header);
823 		//this.elements = elements;
824 	}*/
825 	
826 	public void removeByNumber(int i){
827 		elements = remove(elements, i);
828 	}
829 }
830 
831 public class Event{
832 	public string source, subsource, path, filename;
833 	public wstring text;
834 	public int value, type;
835 	/**
836 	 *If a field is unneeded, leave it blank by setting it to null.
837 	 */
838 	this(string source, string subsource, string path, string filename, wstring textinput, int value, int type){
839 		this.source = source;
840 		this.subsource = subsource;
841 		this.path = path;
842 		this.filename = filename;
843 		this.text = textinput;
844 		this.value = value;
845 		this.type = type;
846 	}
847 }
848 
849 public interface ActionListener{
850 	//public void actionEvent(string source, int type, int value, wstring message);
851 	//public void actionEvent(string source, string subSource, int type, int value, wstring message);
852 	/// During development, I decided to move to a more "Swing-like" event system, use this instead. Better for adding new features in the future.
853 	public void actionEvent(Event event); 
854 }
855 
856 public interface ElementContainer{
857 	public StyleSheet getStyleSheet();
858 	//public Bitmap16Bit[wchar] getFontSet(int style);
859 	public void drawUpdate(WindowElement sender);
860 	public void getFocus(WindowElement sender);
861 	public void dropFocus(WindowElement sender);
862 }
863 
864 public interface Focusable{
865 	public void focusGiven();
866 	public void focusLost();
867 }
868 
869 public enum EventType{
870 	READYFORTEXTINPUT	=-1,
871 	CLICK 				= 0,
872 	TEXTINPUT			= 1,
873 	SLIDER				= 2,
874 	TEXTBOXSELECT		= 3,
875 	CHECKBOX			= 4,
876 	RADIOBUTTON			= 5,
877 	FILEDIALOGEVENT		= 6
878 }