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 	protected wstring text;
21 	protected string source;
22 	public 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 	protected bool state;
30 
31 	public static InputHandler inputHandler;
32 	public static PopUpHandler popUpHandler;
33 	public static StyleSheet styleSheet;
34 
35 	public static void delegate() onDraw;
36 
37 	public void delegate(Event ev) onMouseLClickRel;
38 	public void delegate(Event ev) onMouseRClickRel;
39 	public void delegate(Event ev) onMouseMClickRel;
40 	public void delegate(Event ev) onMouseHover;
41 	public void delegate(Event ev) onMouseMove;
42 	public void delegate(Event ev) onMouseLClickPre;
43 	public void delegate(Event ev) onMouseRClickPre;
44 	public void delegate(Event ev) onMouseMClickPre;
45 	
46 	public void onClick(int offsetX, int offsetY, int state, ubyte button){
47 		
48 	}
49 	public void onDrag(int x, int y, int relX, int relY, ubyte button){
50 		
51 	}
52 	public void onKey(char c, int type){
53 		
54 	}
55 	public void onScroll(int x, int y, int wX, int wY){
56 		
57 	}
58 	@nogc public int getX(){
59 		return position.width;
60 	}
61 	@nogc public int getY(){
62 		return position.height;
63 	}
64 	@nogc public Coordinate getPosition(){
65 		return position;
66 	}
67 	/**
68 	 * Updates the output.
69 	 */
70 	public abstract void draw();
71 	
72 	/+protected void invokeActionEvent(int type, int value, wstring message = ""){
73 		foreach(ActionListener a; al){
74 			if(a)
75 				a.actionEvent(new Event(source, null, null, null, text, value, type));
76 		}
77 	}
78 
79 	protected void invokeActionEvent(Event e) {
80 		foreach(ActionListener a; al){
81 			if(a)
82 				a.actionEvent(e);
83 		}
84 	}+/
85 	/*private Bitmap16Bit getBrush(int style){
86 		return altStyleBrush.get(style, elementContainer.getStyleBrush(style));
87 	}*/
88 	public @nogc wstring getText(){
89 		return text;
90 	}
91 	public void setText(wstring s){
92 		text = s;
93 		draw();
94 		
95 	}
96 
97 	public StyleSheet getAvailableStyleSheet(){
98 		if(customStyle !is null){
99 			return customStyle;
100 		}
101 		return elementContainer.getStyleSheet();
102 	}
103 
104 	public void setCustomStyle(StyleSheet s){
105 		customStyle = s;
106 	}
107 	/**
108 	 * Enables (b = true) or disables (b = false) the element. All element is enabled by default.
109 	 */
110 	@nogc public void setState(bool b){
111 		state = !b;
112 	}
113 	/**
114 	 * Gets the state of the element.
115 	 */
116 	@nogc public bool getState(){
117 		return !state;
118 	}
119 }
120 
121 public class Button : WindowElement{
122 	private bool isPressed;
123 	public bool enableRightButtonClick;
124 	public bool enableMiddleButtonClick;
125 	public this(wstring text, string source, Coordinate coordinates){
126 		position = coordinates;
127 		//sizeX = coordinates.width();
128 		//sizeY = coordinates.height();
129 		this.text = text;
130 		this.source = source;
131 		output = new BitmapDrawer(coordinates.width, coordinates.height);
132 		//brushPressed = 1;
133 		//draw();
134 	}
135 	public override void draw(){
136 		if(output.output.width != position.width || output.output.height != position.height)
137 			output = new BitmapDrawer(position.width(), position.height());
138 		if(isPressed){
139 			output.drawLine(0, position.width()-1, 0, 0, getAvailableStyleSheet().getColor("windowdescent"));
140 			output.drawLine(0, 0, 0, position.height()-1, getAvailableStyleSheet().getColor("windowdescent"));
141 			output.drawLine(0, position.width()-1, position.height()-1, position.height()-1, getAvailableStyleSheet().getColor("windowascent"));
142 			output.drawLine(position.width()-1, position.width()-1, 0, position.height()-1, getAvailableStyleSheet().getColor("windowascent"));
143 			output.drawFilledRectangle(1, position.width()-1, 1,position.height()-1, getAvailableStyleSheet().getColor("windowinactive"));
144 		}else{
145 			output.drawLine(0, position.width()-1, 0, 0, getAvailableStyleSheet().getColor("windowascent"));
146 			output.drawLine(0, 0, 0, position.height()-1, getAvailableStyleSheet().getColor("windowascent"));
147 			output.drawLine(0, position.width()-1, position.height()-1, position.height()-1, getAvailableStyleSheet().getColor("windowdescent"));
148 			output.drawLine(position.width()-1, position.width()-1, 0, position.height()-1, getAvailableStyleSheet().getColor("windowdescent"));
149 			output.drawFilledRectangle(1, position.width()-1, 1,position.height()-1, getAvailableStyleSheet().getColor("window"));
150 		}
151 		
152 		output.drawText(position.width/2, position.height/2, text, getAvailableStyleSheet().getFontset("default"));
153 		elementContainer.drawUpdate(this);
154 		if(onDraw !is null){
155 			onDraw();
156 		}
157 	}
158 	public override void onClick(int offsetX, int offsetY, int state, ubyte button){
159 		if(button == MouseButton.RIGHT && enableRightButtonClick){
160 			if(state == ButtonState.PRESSED){
161 				isPressed = true;
162 				draw();
163 				//invokeActionEvent(EventType.CLICK, -1);
164 				if(onMouseRClickPre !is null){
165 					onMouseRClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
166 				}
167 			}else{
168 				isPressed = false;
169 				draw();
170 				//invokeActionEvent(EventType.CLICK, 0);
171 				if(onMouseRClickRel !is null){
172 					onMouseRClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
173 				}
174 			}
175 		}else if(button == MouseButton.MID && enableMiddleButtonClick){
176 			if(state == ButtonState.PRESSED){
177 				isPressed = true;
178 				draw();
179 				//invokeActionEvent(EventType.CLICK, -1);
180 				if(onMouseMClickPre !is null){
181 					onMouseMClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
182 				}
183 			}else{
184 				isPressed = false;
185 				draw();
186 				//invokeActionEvent(EventType.CLICK, 0);
187 				if(onMouseMClickRel !is null){
188 					onMouseMClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
189 				}
190 			}
191 		}else{
192 			if(state == ButtonState.PRESSED){
193 				isPressed = true;
194 				draw();
195 				//invokeActionEvent(EventType.CLICK, -1);
196 				if(onMouseLClickPre !is null){
197 					onMouseLClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
198 				}
199 			}else{
200 				isPressed = false;
201 				draw();
202 				//invokeActionEvent(EventType.CLICK, 0);
203 				if(onMouseLClickRel !is null){
204 					onMouseLClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
205 				}
206 			}
207 		}
208 		
209 	}
210 }
211 
212 public class SmallButton : WindowElement{
213 	private string iconPressed, iconUnpressed;
214 	private bool isPressed;
215 	public bool enableRightButtonClick;
216 	public bool enableMiddleButtonClick;
217 	public int brushPressed, brushNormal;
218 	
219 	public this(string iconPressed, string iconUnpressed, string source, Coordinate coordinates){
220 		position = coordinates;
221 		
222 		//this.text = text;
223 		this.source = source;
224 		this.iconPressed = iconPressed;
225 		this.iconUnpressed = iconUnpressed;
226 		output = new BitmapDrawer(coordinates.width, coordinates.height);
227 		brushPressed = 1;
228 		//draw();
229 	}
230 	public override void draw(){
231 		output.drawFilledRectangle(0, position.width()-1, 0,position.height()-1, 0);
232 		if(isPressed){
233 			output.insertBitmap(0,0,getAvailableStyleSheet().getImage(iconPressed));
234 		}else{
235 			output.insertBitmap(0,0,getAvailableStyleSheet().getImage(iconUnpressed));
236 		}
237 		elementContainer.drawUpdate(this);
238 		if(onDraw !is null){
239 			onDraw();
240 		}
241 	}
242 	public override void onClick(int offsetX, int offsetY, int state, ubyte button){
243 		if(button == MouseButton.RIGHT && enableRightButtonClick){
244 			if(state == ButtonState.PRESSED){
245 				isPressed = true;
246 				draw();
247 				//invokeActionEvent(EventType.CLICK, -1);
248 				if(onMouseRClickPre !is null){
249 					onMouseRClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
250 				}
251 			}else{
252 				isPressed = false;
253 				draw();
254 				//invokeActionEvent(EventType.CLICK, 0);
255 				if(onMouseRClickRel !is null){
256 					onMouseRClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
257 				}
258 			}
259 		}else if(button == MouseButton.MID && enableMiddleButtonClick){
260 			if(state == ButtonState.PRESSED){
261 				isPressed = true;
262 				draw();
263 				//invokeActionEvent(EventType.CLICK, -1);
264 				if(onMouseMClickPre !is null){
265 					onMouseMClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
266 				}
267 			}else{
268 				isPressed = false;
269 				draw();
270 				//invokeActionEvent(EventType.CLICK, 0);
271 				if(onMouseMClickRel !is null){
272 					onMouseMClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
273 				}
274 			}
275 		}else{
276 			if(state == ButtonState.PRESSED){
277 				isPressed = true;
278 				draw();
279 				//invokeActionEvent(EventType.CLICK, -1);
280 				if(onMouseLClickPre !is null){
281 					onMouseLClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
282 				}
283 			}else{
284 				isPressed = false;
285 				draw();
286 				//invokeActionEvent(EventType.CLICK, 0);
287 				if(onMouseLClickRel !is null){
288 					onMouseLClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
289 				}
290 			}
291 		}
292 		
293 	}
294 }
295 
296 public class Label : WindowElement{
297 	public this(wstring text, string source, Coordinate coordinates){
298 		position = coordinates;
299 		this.text = text;
300 		this.source = source;
301 		output = new BitmapDrawer(coordinates.width, coordinates.height);
302 		//draw();
303 	}
304 	public override void draw(){
305 		//writeln(elementContainer);
306 		if(output.output.width != position.width || output.output.height != position.height)
307 			output = new BitmapDrawer(position.width, position.height);
308 		output.drawText(0, 0, text, getAvailableStyleSheet().getFontset("default"), 1);
309 		elementContainer.drawUpdate(this);
310 		if(onDraw !is null){
311 			onDraw();
312 		}
313 	}
314 	/*public override void onClick(int offsetX, int offsetY, int state, ubyte button){
315 		if(state == ButtonState.PRESSED)
316 			invokeActionEvent(EventType.CLICK, 0);
317 	}*/
318 	public override void setText(wstring s) {
319 		output.destroy();
320 		output = new BitmapDrawer(position.width, position.height);
321 		super.setText(s);
322 	}
323 	public override void onClick(int offsetX, int offsetY, int state, ubyte button){
324 		if(button == MouseButton.RIGHT){
325 			if(state == ButtonState.PRESSED){
326 				if(onMouseRClickPre !is null){
327 					onMouseRClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
328 				}
329 			}else{
330 				if(onMouseRClickRel !is null){
331 					onMouseRClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
332 				}
333 			}
334 		}else if(button == MouseButton.MID){
335 			if(state == ButtonState.PRESSED){
336 				if(onMouseMClickPre !is null){
337 					onMouseMClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
338 				}
339 			}else{
340 				if(onMouseMClickRel !is null){
341 					onMouseMClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
342 				}
343 			}
344 		}else{
345 			if(state == ButtonState.PRESSED){
346 				if(onMouseLClickPre !is null){
347 					onMouseLClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
348 				}
349 			}else{
350 				if(onMouseLClickRel !is null){
351 					onMouseLClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
352 				}
353 			}
354 		}
355 		
356 	}
357 }
358 
359 public class TextBox : WindowElement, TextInputListener{
360 	private bool enableEdit, insert;
361 	private uint pos;
362 	public int brush, textpos;
363 	//public TextInputHandler tih;
364 	public void delegate(Event ev) onTextInput;
365 	
366 	public this(wstring text, string source, Coordinate coordinates){
367 		position = coordinates;
368 		this.text = text;
369 		this.source = source;
370 		output = new BitmapDrawer(coordinates.width, coordinates.height);
371 		//inputHandler.addTextInputListener(source, this);
372 		//insert = true;
373 		//draw();
374 	}
375 
376 	~this(){
377 		//inputHandler.removeTextInputListener(source);
378 	}
379 	public deprecated void addTextInputHandler(TextInputHandler t){	/** DEPRECATED. Will be removed soon in favor of static input handlers. */
380 		/*tih = t;*/
381 		//inputHandler.addTextInputListener(source, this);
382 	}
383 	
384 	public override void onClick(int offsetX, int offsetY, int state, ubyte button){
385 		if(button == MouseButton.RIGHT){
386 			if(state == ButtonState.PRESSED){
387 				if(onMouseRClickPre !is null){
388 					onMouseRClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
389 				}
390 			}else{
391 				if(onMouseRClickRel !is null){
392 					onMouseRClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
393 				}
394 			}
395 		}else if(button == MouseButton.MID){
396 			if(state == ButtonState.PRESSED){
397 				if(onMouseMClickPre !is null){
398 					onMouseMClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
399 				}
400 			}else{
401 				if(onMouseMClickRel !is null){
402 					onMouseMClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
403 				}
404 			}
405 		}else{
406 			if(state == ButtonState.PRESSED){
407 				if(onMouseLClickPre !is null){
408 					onMouseLClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
409 				}
410 			}else{
411 				if(onMouseLClickRel !is null){
412 					onMouseLClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
413 				}
414 			}
415 		}
416 		if(!enableEdit && state == ButtonState.PRESSED && button == MouseButton.LEFT){
417 			//invokeActionEvent(EventType.READYFORTEXTINPUT, 0);
418 			enableEdit = true;
419 			inputHandler.startTextInput(this);
420 			draw();
421 		}
422 	}
423 	public override void draw(){
424 		if(output.output.width != position.width || output.output.height != position.height)
425 			output = new BitmapDrawer(position.width, position.height);
426 		output.drawFilledRectangle(0, position.width - 1, 0, position.height - 1, getAvailableStyleSheet().getColor("window"));
427 		output.drawRectangle(0, position.width - 1, 0, position.height - 1, getAvailableStyleSheet().getColor("windowascent"));
428 		
429 		//draw cursor
430 		if(enableEdit){
431 			int x = getAvailableStyleSheet().getFontset("default").letters['A'].width , y = getAvailableStyleSheet().getFontset("default").letters['A'].height;
432 			if(!insert)
433 				output.drawLine((x*pos) + 2, (x*pos) + 2, 2, 2 + y, getAvailableStyleSheet().getColor("selection"));
434 			else
435 				output.drawFilledRectangle((x*pos) + 2, (x*(pos + 1)) + 2, 2, 2 + y, getAvailableStyleSheet().getColor("selection"));
436 		}
437 		
438 		output.drawText(2, 2, text, getAvailableStyleSheet().getFontset("default"), 1);
439 		elementContainer.drawUpdate(this);
440 		if(onDraw !is null){
441 			onDraw();
442 		}
443 	}
444 	
445 	alias onKey = WindowElement.onKey;
446 	public void onKey(wchar c, int type){
447 		
448 		/*if(enableEdit){
449 		 if(type == 0){
450 		 text ~= c;
451 		 pos++;
452 		 draw();
453 		 }else if(type == 1){
454 		 pos++;
455 		 }else if(type == 2){
456 		 pos--;
457 		 }else if(type == 3){
458 		 invokeActionEvent(EventType.TEXTINPUT, 0, text);
459 		 }else{
460 		 deleteCharacter(pos);
461 		 pos--;
462 		 draw();
463 		 }
464 		 }*/
465 	}
466 	private void deleteCharacter(int n){
467 		//text = remove(text, i);
468 		wstring newtext;
469 		for(int i; i < text.length; i++){
470 			if(i != n - 1){
471 				newtext ~= text[i];
472 			}
473 		}
474 		text = newtext;
475 	}
476 	public void textInputEvent(uint timestamp, uint windowID, char[32] text){
477 		//writeln(0);
478 		int j = pos;
479 		wstring newtext;
480 		for(int i ; i < pos ; i++){
481 			newtext ~= this.text[i];
482 		}
483 		for(int i ; i < 32 ; i++){
484 			if(text[i] == 0){
485 				break;
486 			}
487 			else{
488 				newtext ~= text[i];
489 				pos++;
490 				if(insert){
491 					j++;
492 				}
493 			}
494 		}
495 		for( ; j < this.text.length ; j++){
496 			newtext ~= this.text[j];
497 		}
498 		this.text = newtext;
499 		draw();
500 	}
501 	
502 	public void dropTextInput(){
503 		enableEdit = false;
504 		//inputHandler.stopTextInput(source);
505 		draw();
506 		//invokeActionEvent(EventType.TEXTINPUT, 0, text);
507 		if(onTextInput !is null)
508 			onTextInput(new Event(source, null, null, null, text, 0, EventType.TEXTINPUT));
509 	}
510 
511 
512 	public void textInputKeyEvent(uint timestamp, uint windowID, TextInputKey key, ushort modifier = 0){
513 		if(key == TextInputKey.ESCAPE || key == TextInputKey.ENTER){
514 			enableEdit = false;
515 			inputHandler.stopTextInput(this);
516 			draw();
517 			//invokeActionEvent(EventType.TEXTINPUT, 0, text);
518 			if(onTextInput !is null){
519 				onTextInput(new Event(source, null, null, null, text, 0, EventType.TEXTINPUT));
520 			}
521 		}else if(key == TextInputKey.BACKSPACE){
522 			if(pos > 0){
523 				deleteCharacter(pos);
524 				pos--;
525 				draw();
526 			}
527 			/*if(pos > 0){
528 			 if(pos == text.length){
529 			 text.length--;
530 			 pos--;
531 			 
532 			 }
533 			 }*/
534 		}else if(key == TextInputKey.DELETE){
535 			deleteCharacter(pos + 1);
536 			draw();
537 		}else if(key == TextInputKey.CURSORLEFT){
538 			if(pos > 0){
539 				--pos;
540 				draw();
541 			}
542 		}else if(key == TextInputKey.CURSORRIGHT){
543 			if(pos < text.length){
544 				++pos;
545 				draw();
546 			}
547 		}else if(key == TextInputKey.INSERT){
548 			insert = !insert;
549 			draw();
550 		}else if(key == TextInputKey.HOME){
551 			pos = 0;
552 			draw();
553 		}else if(key == TextInputKey.END){
554 			pos = text.length;
555 			draw();
556 		}
557 	}
558 }
559 
560 /**
561  * Displays multiple columns of data, also provides general text input.
562  */
563 public class ListBox : WindowElement, ElementContainer{
564 	//public ListBoxColumn[] columns;
565 	public ListBoxHeader header;
566 	public ListBoxItem[] items;
567 	public int[] columnWidth;
568 	public int selection, brushHeader, brush, fontHeader, rowHeight;
569 	public ushort selectionColor;
570 	private bool fullRedraw, bodyDrawn, enableTextInput, textInputMode, insert, dragMid;
571 	private VSlider vSlider;
572 	private HSlider hSlider;
573 	private Slider dragSld;
574 	private int fullX, hposition, vposition, sliderX, sliderY, startY, endY, selectedColumn, textPos, previousEvent;
575 	private BitmapDrawer textArea, headerArea;
576 	private Coordinate textInputArea;
577 	public void delegate(Event ev) onTextInput;
578 	public void delegate(Event ev) onItemSelect;
579 	public void delegate(Event ev) onScrolling;
580 	
581 	public this(string source, Coordinate coordinates, ListBoxItem[] items, ListBoxHeader header, int rowHeight, bool enableTextInput = false){
582 		position = coordinates;
583 		this.source = source;
584 		this.rowHeight = rowHeight;
585 		this.items = items;
586 		this.header = header;
587 		updateColumns();
588 
589 		foreach(int i; columnWidth){
590 			fullX += i;
591 		}
592 		if(fullX < position.width()){
593 			fullX = position.width();
594 		}
595 		
596 		output = new BitmapDrawer(position.width, position.height);
597 
598 		int foo = rowHeight * this.items.length;
599 		if(foo < position.height())
600 			foo = position.width();
601 		this.enableTextInput = enableTextInput;
602 		//inputHandler.addTextInputListener(source, this);
603 		
604 	}
605 	/*~this(){
606 		if(!(inputHandler is null))
607 			inputHandler.removeTextInputListener(source);
608 	}*/
609 	/*public void actionEvent(Event event){
610 		if(event.source == "textInput"){
611 			items[selection].setText(selectedColumn, event.text);
612 			invokeActionEvent(new Event(source, null, null, null, event.text, selection,EventType.TEXTINPUT, items[selection]));
613 			updateColumns();
614 			draw();
615 		}else{
616 			draw();
617 		}
618 	}*/
619 	private void textInput(Event ev){
620 		items[selection].setText(selectedColumn, ev.text);
621 		//invokeActionEvent(new Event(source, null, null, null, event.text, selection,EventType.TEXTINPUT, items[selection]));
622 		if(onTextInput !is null){
623 			onTextInput(new Event(source, null, null, null, ev.text, selection,EventType.TEXTINPUT, items[selection]));
624 		}
625 		updateColumns();
626 		draw();
627 	}
628 	private void scrollHoriz(Event ev){
629 		draw();
630 		if(onScrolling !is null){
631 			onScrolling(ev);
632 		}
633 	}
634 	private void scrollVert(Event ev){
635 		draw();
636 		if(onScrolling !is null){
637 			onScrolling(ev);
638 		}
639 	}
640 	public void drawUpdate(WindowElement sender){
641 		output.insertBitmap(sender.getPosition().left,sender.getPosition().top,sender.output.output);
642 
643 		if(!fullRedraw){
644 			/*output.insertBitmapSlice(0,0,headerArea.output,Coordinate(vposition,0,vposition + fullX - 1, rowHeight - 1));
645 			output.insertBitmapSlice(0, rowHeight, textArea.output, Coordinate(vposition,hposition * rowHeight,vposition + fullX - 1 , hposition * rowHeight + (sizeY - hSlider.getPosition().getYSize) - rowHeight));*/
646 			elementContainer.drawUpdate(this);
647 		}
648 	}
649 	public Coordinate getAbsolutePosition(WindowElement sender){
650 		return sender.position;
651 	}
652 	/**
653 	 * Updates the columns with the given data.
654 	 */
655 	public void updateColumns(ListBoxItem[] items){
656 		this.items = items;
657 		updateColumns();
658 		draw();
659 	}
660 	/**
661 	 * Updates the columns with the given data and header.
662 	 */
663 	public void updateColumns(ListBoxItem[] items, ListBoxHeader header){
664 		this.items = items;
665 		this.header = header;
666 		updateColumns();
667 		draw();
668 	}
669 	/**
670 	 * Clears the content of the ListBox.
671 	 */
672 	public void clearData(){
673 		items.length = 0;
674 		updateColumns();
675 		draw();
676 	}
677 	public void updateColumns(){
678 		
679 		fullX = header.getFullWidth();
680 		selection = 0;
681 		
682 		if(fullX < position.width()){
683 			fullX = position.width();
684 		}
685 		int foo2 = rowHeight * this.items.length;
686 		if(foo2 < position.height())
687 			foo2 = position.height();
688 		
689 		textArea = new BitmapDrawer(fullX, foo2);
690 		headerArea = new BitmapDrawer(fullX, rowHeight);
691 
692 		this.vSlider = new VSlider(items.length - 1, ((position.height()-17-rowHeight) / rowHeight), "vslider", Coordinate(position.width() - 16, 0, position.width(), position.height() - 16));
693 		this.hSlider = new HSlider(fullX - 16, position.width() - 16, "hslider", Coordinate(0, position.height() - 16, position.width() - 16, position.height()));
694 		this.vSlider.onScrolling = &scrollVert;
695 		this.vSlider.elementContainer = this;
696 		sliderX = vSlider.getX();
697 		
698 		
699 		this.hSlider.onScrolling = &scrollHoriz;
700 		this.hSlider.elementContainer = this;
701 		sliderY = hSlider.getY();
702 		bodyDrawn = false;
703 	}
704 
705 	public StyleSheet getStyleSheet(){
706 		return getAvailableStyleSheet;
707 	}
708 
709 	private void drawBody(){
710 		int foo;
711 		for(int i; i < header.getNumberOfColumns(); i++){
712 			int bar;
713 			for(int j; j < items.length; j++){
714 				//writeln(foo + 1, bar);
715 				textArea.drawText(foo + 1, bar, items[j].getText(i), getStyleSheet().getFontset("default"), 1);
716 
717 				bar += rowHeight;
718 			}
719 			foo += header.getColumnWidth(i);
720 			
721 			textArea.drawLine(foo, foo, 0, textArea.output.height-2, getStyleSheet().getColor("windowascent"));
722 		}
723 	}
724 	
725 	public override void draw(){
726 		if(output.output.width != position.width || output.output.height != position.height){
727 			output = new BitmapDrawer(position.width(), position.height());
728 			bodyDrawn = false;
729 			updateColumns();
730 		}
731 		fullRedraw = true;
732 		int areaX, areaY;
733 
734 		vposition = vSlider.value;
735 		areaX = position.width - vSlider.getPosition().width();
736 
737 
738 		hposition = hSlider.value;
739 		areaY = position.height - hSlider.getPosition().height();
740 			
741 		output.drawFilledRectangle(0, position.width(), 0, position.height(),getStyleSheet().getColor("window"));
742 		output.drawRectangle(0, position.width() - 1, 0, position.height() - 1,getStyleSheet().getColor("windowascent"));
743 
744 
745 		// draw the header
746 		// TODO: Draw the header only once!!!
747 		output.drawLine(0, position.width() - 1, rowHeight, rowHeight, getStyleSheet().getColor("windowascent"));
748 		int foo;
749 		for(int i; i < header.getNumberOfColumns(); i++){
750 			headerArea.drawText(foo + 1, 0, header.getText(i), getStyleSheet().getFontset("default"), 1);
751 			foo += header.getColumnWidth(i);
752 			headerArea.drawLine(foo, foo, 0, rowHeight - 2, getStyleSheet().getColor("windowascent"));
753 		}
754 
755 		output.insertBitmapSlice(0,0,headerArea.output,Coordinate(hposition,0,hposition + position.width() - 17, rowHeight - 1));
756 
757 		//draw the selector
758 		if(selection - vposition >= 0 && vposition + ((position.height()-17-rowHeight) / rowHeight) >= selection && items.length != 0)
759 			output.drawFilledRectangle(1, position.width() - 2, rowHeight + (rowHeight * (selection - vposition)), (rowHeight * 2) + (rowHeight * (selection - vposition)), getStyleSheet().getColor("selection"));
760 
761 		// draw the body
762 		if(!bodyDrawn){
763 			bodyDrawn = true;
764 			drawBody();
765 		}
766 		//writeln(textArea.output.getX(),textArea.output.getY());
767 		output.insertBitmapSlice(0, rowHeight, textArea.output, Coordinate(hposition,vposition * rowHeight,hposition + position.width() - 17 , vposition * rowHeight + areaY - rowHeight));
768 
769 		vSlider.draw();
770 		hSlider.draw();
771 		elementContainer.drawUpdate(this);
772 		
773 		fullRedraw = false;
774 		if(onDraw !is null){
775 			onDraw();
776 		}
777 	}
778 	public override void onClick(int offsetX, int offsetY, int state, ubyte button){
779 		if(button == MouseButton.RIGHT){
780 			if(state == ButtonState.PRESSED){
781 				if(onMouseRClickPre !is null){
782 					onMouseRClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
783 				}
784 			}else{
785 				if(onMouseRClickRel !is null){
786 					onMouseRClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
787 				}
788 			}
789 		}else if(button == MouseButton.MID){
790 			if(state == ButtonState.PRESSED){
791 				if(onMouseMClickPre !is null){
792 					onMouseMClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
793 				}
794 			}else{
795 				if(onMouseMClickRel !is null){
796 					onMouseMClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
797 				}
798 			}
799 		}else{
800 			if(state == ButtonState.PRESSED){
801 				if(onMouseLClickPre !is null){
802 					onMouseLClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
803 				}
804 			}else{
805 				if(onMouseLClickRel !is null){
806 					onMouseLClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
807 				}
808 			}
809 		}
810 		if(state == ButtonState.PRESSED){
811 			if(button == MouseButton.LEFT){
812 				if(offsetX > (vSlider.getPosition().left) && offsetY > (vSlider.getPosition().top)){
813 					vSlider.onClick(offsetX - vSlider.getPosition().left, offsetY - vSlider.getPosition().top, state, button);
814 					dragSld = vSlider;
815 					return;
816 
817 				}else if(offsetX > (hSlider.getPosition().left) && offsetY > (hSlider.getPosition().top)){
818 					hSlider.onClick(offsetX - hSlider.getPosition().left, offsetY - hSlider.getPosition().top, state, button);
819 					dragSld = hSlider;
820 					return;
821 			
822 				}else if(offsetY > rowHeight && button == MouseButton.LEFT){
823 					offsetY -= rowHeight;
824 					//writeln(selection);
825 					if(selection == (offsetY / rowHeight) + vposition){
826 						//invokeActionEvent(EventType.TEXTBOXSELECT, (offsetY / rowHeight) + vposition);
827 						if(!enableTextInput){
828 							//invokeActionEvent(new Event(source, null, null, null, null, (offsetY / rowHeight) + vposition,EventType.TEXTBOXSELECT, items[selection]));
829 							if(onItemSelect !is null){
830 								onItemSelect(new Event(source, null, null, null, null, (offsetY / rowHeight) + vposition,EventType.TEXTBOXSELECT, items[selection]));
831 							}
832 						}else{
833 							offsetX += hposition;
834 							selectedColumn = header.getColumnNumFromX(offsetX);
835 							//writeln(offsetX);
836 							if(selectedColumn != -1){
837 								if(items[selection].getTextInputType(selectedColumn) != TextInputType.DISABLE){
838 									text = items[selection].getText(selectedColumn);
839 									//invokeActionEvent(EventType.READYFORTEXTINPUT,selectedColumn);
840 									PopUpTextInput p = new PopUpTextInput("textInput", text, Coordinate(0,0,header.getColumnWidth(selectedColumn),20));
841 									p.onTextInput = &textInput;
842 									popUpHandler.addPopUpElement(p);
843 									/+textInputArea = Coordinate(header.getRangeWidth(0, selectedColumn), (selection + 1) * rowHeight /*- hposition*/, 
844 													header.getRangeWidth(0, selectedColumn + 1), (selection + 2) * rowHeight /*- hposition*/);
845 									writeln(textInputArea);+/
846 							
847 								}/*else{*/
848 								if(onItemSelect !is null){
849 									onItemSelect(new Event(source, null, null, null, null, (offsetY / rowHeight) + vposition,EventType.TEXTBOXSELECT, items[selection]));
850 									/*}*/
851 								}
852 							}
853 						}
854 					}else{
855 						if((offsetY / rowHeight) + vposition < items.length){
856 							selection = (offsetY / rowHeight) + vposition;
857 							draw();
858 						}
859 					}
860 				}
861 			}else if(button == MouseButton.MID){
862 				dragMid = true;
863 			}
864 		}else{
865 			dragMid = false;
866 			dragSld = null;
867 		}
868 	}
869 	public override void onDrag(int x, int y, int relX, int relY, ubyte button){
870 		if(dragMid){
871 			hSlider.value += x;
872 			vSlider.value += y;
873 		}else if(dragSld){
874 			dragSld.onDrag(x,y,relX,relY,button);
875 		}
876 	}
877 	public override void onScroll(int x, int y, int wX, int wY){
878 		if(textInputMode) return;
879 		vSlider.onScroll(x,y,0,0);
880 		hSlider.onScroll(x,y,0,0);
881 	}
882 	/**
883 	 * Returns a line.
884 	 */
885 	public @nogc ListBoxItem readLine(int line){
886 		return items[line];
887 	}
888 	/**
889 	 * Adds a line to the bottom of the list.
890 	 */
891 	public void addLine(ListBoxItem i){
892 		items ~= i;
893 	}
894 	/**
895 	 * Inserts a line to a given point of the list.
896 	 */
897 	public void addLine(ListBoxItem i, int n){
898 		if(n == items.length){
899 			items ~= i;
900 		}else{
901 			items.length++;
902 			for(int j = items.length - 1; j > n; j++){
903 				items[j] = items[j - 1];
904 			}
905 			items[n] = i;
906 		}
907 	}
908 	/**
909 	 * Removes a line from the list.
910 	 */
911 	public void removeLine(int n){
912 		items.remove(n);
913 	}
914 }
915 /**
916  * A simple toggle button.
917  */
918 public class CheckBox : WindowElement{
919 	public int iconChecked, iconUnchecked;
920 	private bool checked;
921 	public int[] brush;
922 	public void delegate(Event ev) onToggle;
923 	
924 	public this(wstring text, string source, Coordinate coordinates){
925 		position = coordinates;
926 		this.text = text;
927 		this.source = source;
928 		brush ~= 2;
929 		brush ~= 3;
930 		output = new BitmapDrawer(position.width, position.height);
931 		//draw();
932 	}
933 	
934 	public override void draw(){
935 		if(output.output.width != position.width || output.output.height != position.height)
936 			output = new BitmapDrawer(position.width, position.height);
937 		output.drawText(getAvailableStyleSheet().getImage("checkBoxA").width, 0, text, getAvailableStyleSheet().getFontset("default"), 1);
938 		if(checked){
939 			output.insertBitmap(0, 0, getAvailableStyleSheet().getImage("checkBoxB"));
940 		}else{
941 			output.insertBitmap(0, 0, getAvailableStyleSheet().getImage("checkBoxA"));
942 		}
943 		elementContainer.drawUpdate(this);
944 		if(onDraw !is null){
945 			onDraw();
946 		}
947 	}
948 	
949 	public override void onClick(int offsetX, int offsetY, int state, ubyte button){
950 		/*if(state == ButtonState.PRESSED && button == MouseButton.LEFT){
951 			checked = !checked;
952 			draw();
953 			invokeActionEvent(EventType.CHECKBOX, checked);
954 		}*/
955 		if(button == MouseButton.RIGHT){
956 			if(state == ButtonState.PRESSED){
957 				if(onMouseRClickPre !is null){
958 					onMouseRClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
959 				}
960 			}else{
961 				if(onMouseRClickRel !is null){
962 					onMouseRClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
963 				}
964 			}
965 		}else if(button == MouseButton.MID){
966 			if(state == ButtonState.PRESSED){
967 				if(onMouseMClickPre !is null){
968 					onMouseMClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
969 				}
970 			}else{
971 				if(onMouseMClickRel !is null){
972 					onMouseMClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
973 				}
974 			}
975 		}else{
976 			if(state == ButtonState.PRESSED){
977 				checked = !checked;
978 				draw();
979 				if(onMouseLClickPre !is null){
980 					onMouseLClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
981 				}
982 				if(onToggle !is null){
983 					onToggle(new Event(source, null, null, null, null, checked ? 1 : 0, EventType.CHECKBOX));
984 				}
985 			}else{
986 				if(onMouseLClickRel !is null){
987 					onMouseLClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
988 				}
989 			}
990 		}
991 	}
992 	/**
993 	 * Returns the current value (whether it's checked or not) as a boolean.
994 	 */
995 	public @nogc @property bool value(){
996 		return checked;
997 	}
998 	/**
999 	 * Sets the new value (whether it's checked or not) as a boolean.
1000 	 */
1001 	public @property bool value(bool b){
1002 		checked = b;
1003 		draw();
1004 		return checked;
1005 	}
1006 }
1007 /**
1008  * Radio buttons, for selecting from multiple options.
1009  */
1010 public class RadioButtonGroup : WindowElement{
1011 	public int iconChecked, iconUnchecked;
1012 	private int bposition, rowHeight, buttonpos;
1013 	public wstring[] options;
1014 	public int[] brush;
1015 	public ushort border, background;
1016 	public void delegate(Event ev) onToggle;
1017 
1018 	public this(wstring text, string source, Coordinate coordinates, wstring[] options, int rowHeight, int buttonpos){
1019 		this.position = coordinates;
1020 		this.text = text;
1021 		this.source = source;
1022 		this.options = options;
1023 		this.rowHeight = rowHeight;
1024 		brush ~= 4;
1025 		brush ~= 5;
1026 		output = new BitmapDrawer(position.width, position.height);
1027 		//draw();
1028 	}
1029 	
1030 	public override void draw(){
1031 		//output.drawFilledRectangle(0, sizeX-1, 0, sizeY-1, background);
1032 		if(output.output.width != position.width || output.output.height != position.height)
1033 			output = new BitmapDrawer(position.width, position.height);
1034 		output.drawRectangle(0, position.width-1, 0, position.height-1, getAvailableStyleSheet().getColor("windowascent"));
1035 		output.drawText(16,0,text, getAvailableStyleSheet().getFontset("default"),1);
1036 		for(int i; i < options.length; i++){
1037 
1038 			output.drawText(16, rowHeight * (i+1),options[i],getAvailableStyleSheet().getFontset("default"),1);
1039 			if(bposition == i){
1040 				output.insertBitmap(1, rowHeight * (i+1),getAvailableStyleSheet.getImage("radioButtonB"));
1041 			}else{
1042 				output.insertBitmap(1, rowHeight * (i+1),getAvailableStyleSheet.getImage("radioButtonA"));
1043 			}
1044 		}
1045 		elementContainer.drawUpdate(this);
1046 		if(onDraw !is null){
1047 			onDraw();
1048 		}
1049 	}
1050 	
1051 	public override void onClick(int offsetX, int offsetY, int state, ubyte button){
1052 		if(button == MouseButton.RIGHT){
1053 			if(state == ButtonState.PRESSED){
1054 				if(onMouseRClickPre !is null){
1055 					onMouseRClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
1056 				}
1057 			}else{
1058 				if(onMouseRClickRel !is null){
1059 					onMouseRClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
1060 				}
1061 			}
1062 		}else if(button == MouseButton.MID){
1063 			if(state == ButtonState.PRESSED){
1064 				if(onMouseMClickPre !is null){
1065 					onMouseMClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
1066 				}
1067 			}else{
1068 				if(onMouseMClickRel !is null){
1069 					onMouseMClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
1070 				}
1071 			}
1072 		}else{
1073 			if(state == ButtonState.PRESSED){
1074 				if(onMouseLClickPre !is null){
1075 					onMouseLClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
1076 				}
1077 				bposition = (offsetY) / 16;
1078 				bposition--;
1079 				draw();
1080 				if(onToggle !is null){
1081 					onToggle(new Event(source, null, null, null, null, bposition, EventType.RADIOBUTTON));
1082 				}
1083 			}else{
1084 				if(onMouseLClickRel !is null){
1085 					onMouseLClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
1086 				}
1087 			}
1088 		}
1089 	}
1090 	public @property @nogc int value(){
1091 		return bposition;
1092 	}
1093 	public @property int value(int newval){
1094 		bposition = newval;
1095 		draw();
1096 		return bposition;
1097 	}
1098 }
1099 
1100 abstract class Slider : WindowElement{
1101 	public int[] brush;
1102 	
1103 	public int value, maxValue, barLength;
1104 	public void delegate(Event ev) onScrolling;
1105 	
1106 	/**
1107 	 * Returns the slider position. If barLenght > 1, then it returns the lower value.
1108 	 */
1109 	public @nogc @property int sliderPosition(){
1110 		return value;
1111 	}
1112 	public @property int sliderPosition(int newval){
1113 		if(newval < maxValue){
1114 			value = newval;
1115 			draw();
1116 		}
1117 		return value;
1118 	}
1119 }
1120 /**
1121  * Vertical slider.
1122  */
1123 public class VSlider : Slider{
1124 	//public int[] brush;
1125 	
1126 	//private int value, maxValue, barLength;
1127 	
1128 	public this(int maxValue, int barLenght, string source, Coordinate coordinates){
1129 		position = coordinates;
1130 		//this.text = text;
1131 		this.source = source;
1132 		this.maxValue = maxValue;
1133 		this.barLength = barLenght;
1134 		output = new BitmapDrawer(position.width, position.height);
1135 		brush ~= 6;
1136 		brush ~= 8;
1137 		//brush ~= 10;
1138 		//draw();
1139 	}
1140 	public override void draw(){
1141 		//draw background
1142 		//Bitmap16Bit sliderStyle = elementContainer.getStyleBrush(brush[2]);
1143 		//ushort backgroundColor = sliderStyle.readPixel(0,0), sliderColor = sliderStyle.readPixel(1,0);
1144 		if(output.output.width != position.width || output.output.height != position.height)
1145 			output = new BitmapDrawer(position.width, position.height);
1146 		output.drawFilledRectangle(0, position.width , 0, position.height , getAvailableStyleSheet.getColor("windowinactive"));
1147 		//draw upper arrow
1148 		output.insertBitmap(0,0,getAvailableStyleSheet.getImage("upArrowA"));
1149 		//draw lower arrow
1150 		output.insertBitmap(0, position.height - getAvailableStyleSheet.getImage("downArrowA").height,getAvailableStyleSheet.getImage("downArrowA"));
1151 		//draw slider
1152 		if(maxValue > barLength){
1153 			double sliderlength = position.height() - (getAvailableStyleSheet.getImage("upArrowA")).height*2, unitlength = sliderlength/maxValue;
1154 			double sliderpos = unitlength * value, bl = unitlength * barLength;
1155 			int posA = to!int(sliderpos) + getAvailableStyleSheet.getImage("upArrowA").height, posB = to!int(bl + sliderpos) + getAvailableStyleSheet.getImage("upArrowA").height;
1156 
1157 			output.drawFilledRectangle(0,position.width,posA, posB, getAvailableStyleSheet.getColor("windowascent"));
1158 		}
1159 		elementContainer.drawUpdate(this);
1160 		if(onDraw !is null){
1161 			onDraw();
1162 		}
1163 	}
1164 	
1165 	
1166 	public override void onClick(int offsetX, int offsetY, int state, ubyte button){
1167 		if(button == MouseButton.RIGHT){
1168 			if(state == ButtonState.PRESSED){
1169 				if(onMouseRClickPre !is null){
1170 					onMouseRClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
1171 				}
1172 			}else{
1173 				if(onMouseRClickRel !is null){
1174 					onMouseRClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
1175 				}
1176 			}
1177 		}else if(button == MouseButton.MID){
1178 			if(state == ButtonState.PRESSED){
1179 				if(onMouseMClickPre !is null){
1180 					onMouseMClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
1181 				}
1182 			}else{
1183 				if(onMouseMClickRel !is null){
1184 					onMouseMClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
1185 				}
1186 			}
1187 		}else{
1188 			if(state == ButtonState.PRESSED){
1189 				if(onMouseLClickPre !is null){
1190 					onMouseLClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
1191 				}
1192 				if(offsetY <= getAvailableStyleSheet.getImage("upArrowA").height){
1193 					if(value != 0) value--;
1194 				}else if(position.height-getAvailableStyleSheet.getImage("upArrowA").height <= offsetY){
1195 					if(value < maxValue - barLength) value++;
1196 				}else{
1197 					offsetY -= getAvailableStyleSheet.getImage("upArrowA").height;
1198 					double sliderlength = position.height() - (getAvailableStyleSheet.getImage("upArrowA").height*2), unitlength = sliderlength/maxValue;
1199 					int v = to!int(offsetY / unitlength);
1200 					//value = ((sizeY - (elementContainer.getStyleBrush(brush[1]).getY() * 2)) - offsetY) * (value / maxValue);
1201 					if(v < maxValue - barLength) value = v;
1202 					else value = maxValue - barLength;
1203 
1204 				}
1205 				draw();
1206 				if(onScrolling !is null){
1207 					onScrolling(new Event(source, null, null, null, null, value, EventType.SLIDER));
1208 				}
1209 			}else{
1210 				if(onMouseLClickRel !is null){
1211 					onMouseLClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
1212 				}
1213 			}
1214 		}
1215 		
1216 	}
1217 	public override void onScroll(int x, int y, int wX, int wY){
1218 
1219 		if(x == 1){
1220 			if(value != 0) value--;
1221 		}else if(x == -1){
1222 			if(value < maxValue - barLength) value++;
1223 		}
1224 		draw();
1225 		if(onScrolling !is null){
1226 			onScrolling(new Event(source, null, null, null, null, value, EventType.SLIDER));
1227 		}
1228 	}
1229 	override public void onDrag(int x,int y,int relX,int relY,ubyte button) {
1230 		value+=relY;
1231 		if(value >= maxValue - barLength)
1232 			value = maxValue;
1233 		else if(value < 0)
1234 			value = 0;
1235 		draw();
1236 		if(onScrolling !is null){
1237 			onScrolling(new Event(source, null, null, null, null, value, EventType.SLIDER));
1238 		}
1239 		
1240 	}
1241 }
1242 /**
1243  * Horizontal slider.
1244  */
1245 public class HSlider : Slider{
1246 	public this(int maxValue, int barLenght, string source, Coordinate coordinates){
1247 		position = coordinates;
1248 		//this.text = text;
1249 		this.source = source;
1250 		this.maxValue = maxValue;
1251 		this.barLength = barLenght;
1252 		//writeln(barLenght,',',maxValue);
1253 		output = new BitmapDrawer(position.width, position.height);
1254 		brush ~= 14;
1255 		brush ~= 16;
1256 		//brush ~= 10;
1257 		//draw();
1258 	}
1259 	public override void draw(){
1260 		//draw background
1261 		//Bitmap16Bit sliderStyle = elementContainer.getStyleBrush(brush[2]);
1262 		//ushort backgroundColor = sliderStyle.readPixel(0,0), sliderColor = sliderStyle.readPixel(1,0);
1263 		if(output.output.width != position.width || output.output.height != position.height)
1264 			output = new BitmapDrawer(position.width, position.height);
1265 		output.drawFilledRectangle(0, position.width , 0, position.height , getAvailableStyleSheet().getColor("windowinactive"));
1266 		//draw left arrow
1267 		output.insertBitmap(0,0,getAvailableStyleSheet.getImage("leftArrowA"));
1268 		//draw right arrow
1269 		output.insertBitmap(position.width - getAvailableStyleSheet.getImage("rightArrowA").width,0,getAvailableStyleSheet.getImage("rightArrowA"));
1270 		//draw slider
1271 		if(maxValue > barLength){
1272 			double sliderlength = position.width() - (getAvailableStyleSheet.getImage("rightArrowA").width*2), unitlength = sliderlength/maxValue;
1273 			double sliderpos = unitlength * value, bl = unitlength * barLength;
1274 
1275 			int posA = to!int(sliderpos) + getAvailableStyleSheet.getImage("rightArrowA").height, posB = to!int(bl + sliderpos) + getAvailableStyleSheet.getImage("rightArrowA").height;
1276 		
1277 			output.drawFilledRectangle(posA, posB, 0, position.height(),getAvailableStyleSheet().getColor("windowascent"));
1278 		}
1279 		elementContainer.drawUpdate(this);
1280 		if(onDraw !is null){
1281 			onDraw();
1282 		}
1283 	}
1284 	public override void onClick(int offsetX, int offsetY, int state, ubyte button){
1285 		if(button == MouseButton.RIGHT){
1286 			if(state == ButtonState.PRESSED){
1287 				if(onMouseRClickPre !is null){
1288 					onMouseRClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
1289 				}
1290 			}else{
1291 				if(onMouseRClickRel !is null){
1292 					onMouseRClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
1293 				}
1294 			}
1295 		}else if(button == MouseButton.MID){
1296 			if(state == ButtonState.PRESSED){
1297 				if(onMouseMClickPre !is null){
1298 					onMouseMClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
1299 				}
1300 			}else{
1301 				if(onMouseMClickRel !is null){
1302 					onMouseMClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
1303 				}
1304 			}
1305 		}else{
1306 			if(state == ButtonState.PRESSED){
1307 				if(onMouseLClickPre !is null){
1308 					onMouseLClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
1309 				}
1310 				if(offsetX <= getAvailableStyleSheet.getImage("rightArrowA").width){
1311 					if(value != 0) value--;
1312 				}
1313 				else if(position.width-getAvailableStyleSheet.getImage("rightArrowA").width <= offsetX){
1314 					if(value < maxValue - barLength) value++;
1315 				}
1316 				else{
1317 					offsetX -= getAvailableStyleSheet.getImage("rightArrowA").width;
1318 					double sliderlength = position.width() - (elementContainer.getStyleSheet.getImage("rightArrowA").width*2), unitlength = sliderlength/maxValue;
1319 					int v = to!int(offsetX / unitlength);
1320 					if(v < maxValue - barLength) value = v;
1321 					else value = maxValue - barLength;
1322 				}
1323 				draw();
1324 				if(onScrolling !is null){
1325 					onScrolling(new Event(source, null, null, null, null, value, EventType.SLIDER));
1326 				}
1327 			}else{
1328 				if(onMouseLClickRel !is null){
1329 					onMouseLClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
1330 				}
1331 			}
1332 		}
1333 	}
1334 	public override void onScroll(int x, int y, int wX, int wY){
1335 		if(y == -1){
1336 			if(value != 0) value--;
1337 		}else if(y == 1){
1338 			if(value < maxValue - barLength) value++;
1339 		}
1340 		draw();
1341 		if(onScrolling.ptr){
1342 			onScrolling(new Event(source, null, null, null, null, value, EventType.SLIDER));
1343 		}
1344 	}
1345 	override public void onDrag(int x,int y,int relX,int relY,ubyte button) {
1346 		value+=relX;
1347 		if(value >= maxValue - barLength)
1348 			value = maxValue;
1349 		else if(value < 0)
1350 			value = 0;
1351 		draw();
1352 		if(onScrolling.ptr){
1353 			onScrolling(new Event(source, null, null, null, null, value, EventType.SLIDER));
1354 		}
1355 	}
1356 	
1357 }
1358 /**
1359  * Menubar containing menus in a tree-like structure.
1360  */
1361 public class MenuBar: WindowElement{
1362 	private PopUpMenuElement[] menus;
1363 	//private wstring[] menuNames;
1364 	private int[] menuWidths;
1365 	//private PopUpHandler popUpHandler;
1366 	private int select, usedWidth;
1367 	public this(string source, Coordinate position, PopUpMenuElement[] menus){
1368 		this.source = source;
1369 		this.position = position;
1370 		//this.popUpHandler = popUpHandler;
1371 		this.menus = menus;
1372 		select = -1;
1373 	}
1374 	public override void draw() {
1375 		StyleSheet ss = getAvailableStyleSheet();
1376 		Fontset!Bitmap16Bit f = ss.getFontset("default");
1377 		if (output is null){
1378 			usedWidth = 1;
1379 			output = new BitmapDrawer(position.width(),position.height());
1380 			foreach(m ; menus){
1381 				menuWidths ~= usedWidth;
1382 				usedWidth += f.getTextLength(m.text) + (ss.drawParameters["MenuBarHorizPadding"] * 2);
1383 				
1384 			}
1385 			output.drawFilledRectangle(0, position.width(), 0, position.height(), ss.getColor("window"));
1386 		}else{
1387 			output.drawFilledRectangle(0, usedWidth, 0, position.height(), ss.getColor("window"));
1388 		}
1389 		if(select != -1){
1390 		
1391 		}
1392 		int x = ss.drawParameters["MenuBarHorizPadding"] + 1;
1393 		foreach(m ; menus){
1394 			output.drawText(x, ss.drawParameters["MenuBarVertPadding"],m.text,f,1);
1395 			x += f.getTextLength(m.text) + ss.drawParameters["MenuBarHorizPadding"];
1396 			output.drawLine(x, x, 0, position.height() - 1, ss.getColor("MenuBarSeparatorColor"));
1397 			x += ss.drawParameters["MenuBarHorizPadding"];
1398 		}
1399 		output.drawLine(0, 0, 0, position.height()-1, ss.getColor("windowascent"));
1400 		output.drawLine(0, position.width()-1, 0, 0, ss.getColor("windowascent"));
1401 		output.drawLine(0, position.width()-1, position.height()-1, position.height()-1, ss.getColor("windowdescent"));
1402 		output.drawLine(position.width()-1, position.width()-1, 0, position.height()-1, ss.getColor("windowdescent"));
1403 		elementContainer.drawUpdate(this);
1404 		if(onDraw !is null){
1405 			onDraw();
1406 		}
1407 	}
1408 	private void redirectIncomingEvents(Event ev){
1409 		if(onMouseLClickPre !is null){
1410 			onMouseLClickPre(ev);
1411 		}
1412 	}
1413 	override public void onClick(int offsetX,int offsetY,int state,ubyte button){
1414 		if(button == MouseButton.RIGHT){
1415 			if(state == ButtonState.PRESSED){
1416 				if(onMouseRClickPre !is null){
1417 					onMouseRClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
1418 				}
1419 			}else{
1420 				if(onMouseRClickRel !is null){
1421 					onMouseRClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
1422 				}
1423 			}
1424 		}else if(button == MouseButton.MID){
1425 			if(state == ButtonState.PRESSED){
1426 				if(onMouseMClickPre !is null){
1427 					onMouseMClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
1428 				}
1429 			}else{
1430 				if(onMouseMClickRel !is null){
1431 					onMouseMClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
1432 				}
1433 			}
1434 		}else{
1435 			if(state == ButtonState.PRESSED){
1436 				if(onMouseLClickPre !is null){
1437 					onMouseLClickPre(new Event(source, null, null, null, null, button, EventType.CLICK));
1438 				}
1439 			}else{
1440 				if(onMouseLClickRel !is null){
1441 					onMouseLClickRel(new Event(source, null, null, null, null, button, EventType.CLICK));
1442 				}
1443 			}
1444 		}
1445 		//writeln(onMouseLClickPre);
1446 		if(offsetX < usedWidth && button == MouseButton.LEFT && state == ButtonState.PRESSED){
1447 			for(int i = menuWidths.length - 1 ; i >= 0 ; i--){
1448 				if(menuWidths[i] < offsetX){
1449 					PopUpMenu p = new PopUpMenu(menus[i].getSubElements(), menus[i].source);
1450 					//p.al = al;
1451 					p.onMouseClick = onMouseLClickPre;//&redirectIncomingEvents;
1452 					Coordinate c = elementContainer.getAbsolutePosition(this);
1453 					popUpHandler.addPopUpElement(p, c.left + menuWidths[i], position.height());
1454 					return;
1455 				}
1456 			}
1457 		}
1458 
1459 	}
1460 	
1461 }
1462 /**
1463  * For creating pop-up elements like menus.
1464  */
1465 public abstract class PopUpElement{
1466 	//public ActionListener[] al;
1467 	public BitmapDrawer output;
1468 	public static InputHandler inputhandler;
1469 	public static StyleSheet styleSheet;
1470 	public Coordinate coordinates;
1471 	public StyleSheet customStyle;
1472 	protected PopUpHandler parent;
1473 	protected string source;
1474 	protected wstring text;
1475 	/*public void delegate(Event ev) onMouseLClickRel;
1476 	public void delegate(Event ev) onMouseRClickRel;
1477 	public void delegate(Event ev) onMouseMClickRel;
1478 	public void delegate(Event ev) onMouseHover;
1479 	public void delegate(Event ev) onMouseMove;
1480 	public void delegate(Event ev) onMouseLClickPre;
1481 	public void delegate(Event ev) onMouseRClickPre;
1482 	public void delegate(Event ev) onMouseMClickPre;*/
1483 
1484 	public static void delegate() onDraw;
1485 	public void delegate(Event ev) onMouseClick;
1486 
1487 	public abstract void draw();
1488 
1489 	public void onClick(int offsetX, int offsetY, int type = 0){
1490 		
1491 	}
1492 	public void onScroll(int x, int y, int wX, int wY){
1493 		
1494 	}
1495 	public void onMouseMovement(int x, int y){
1496 		
1497 	}
1498 	public void addParent(PopUpHandler p){
1499 		parent = p;
1500 	}
1501 	
1502 	protected StyleSheet getStyleSheet(){
1503 		if(customStyle !is null){
1504 			return customStyle;
1505 		}
1506 		if(styleSheet !is null){
1507 			return styleSheet;
1508 		}
1509 		return parent.getStyleSheet();
1510 	}
1511 	/*protected void invokeActionEvent(Event e){
1512 		foreach(ActionListener a; al){
1513 			//a.actionEvent(source, type, value, message);
1514 			//writeln(a);
1515 			a.actionEvent(e);
1516 		}
1517 	}*/
1518 }
1519 
1520 /**
1521  * To create drop-down lists, menu bars, etc.
1522  */
1523 public class PopUpMenu : PopUpElement{
1524 	//private wstring[] texts;
1525 	//private string[] sources;
1526 	
1527 	//private uint[int] hotkeyCodes;
1528 	//private Bitmap16Bit[int] icons;
1529 	private int minwidth, width, height, iconWidth, select;
1530 	PopUpMenuElement[] elements;
1531 
1532 	public this(PopUpMenuElement[] elements, string source, int iconWidth = 0){
1533 		this.elements = elements;
1534 		this.source = source;
1535 		this. iconWidth = iconWidth;
1536 		select = -1;
1537 	}
1538 	public override void draw(){
1539 		StyleSheet ss = getStyleSheet();
1540 		if(output is null){
1541 			
1542 			minwidth = (ss.drawParameters["PopUpMenuVertPadding"] * 2) + ss.drawParameters["PopUpMenuMinTextSpace"] + iconWidth;
1543 			width = minwidth;
1544 			foreach(e; elements){
1545 				int newwidth = ss.getFontset("default").getTextLength(e.text~e.secondaryText) + iconWidth;
1546 				if(newwidth > width){
1547 					width = newwidth;
1548 				}
1549 				height += ss.getFontset("default").getSize() + (ss.drawParameters["PopUpMenuVertPadding"] * 2);
1550 			}
1551 			width += (ss.drawParameters["PopUpMenuHorizPadding"] * 2) + ss.drawParameters["PopUpMenuMinTextSpace"];
1552 			height += ss.drawParameters["PopUpMenuVertPadding"] * 2;
1553 			output = new BitmapDrawer(width, height);
1554 			coordinates = Coordinate(0, 0, width, height);
1555 		}
1556 		output.drawFilledRectangle(0,width - 1,0,height - 1,ss.getColor("window"));
1557 		
1558 		if(select > -1){
1559 			int y0 = (height / elements.length) * select;
1560 			int y1 = (height / elements.length) + y0;
1561 			output.drawFilledRectangle(1, width - 1, y0 + 1, y1 + 1, ss.getColor("selection"));
1562 		}
1563 
1564 		
1565 		int y = 1 + ss.drawParameters["PopUpMenuVertPadding"];
1566 		foreach(e; elements){
1567 			if(e.secondaryText !is null){
1568 				output.drawColorText(width - ss.drawParameters["PopUpMenuHorizPadding"] - 1, y, e.secondaryText, ss.getFontset("default"), ss.getColor("PopUpMenuSecondaryTextColor"), 2);
1569 			}
1570 			output.drawText(ss.drawParameters["PopUpMenuHorizPadding"] + iconWidth, y, e.text, ss.getFontset("default"), 1);
1571 			if(e.getIcon() !is null){
1572 				output.insertBitmap(ss.drawParameters["PopUpMenuHorizPadding"], y, e.getIcon());
1573 			}
1574 			y += ss.getFontset("default").getSize() + (ss.drawParameters["PopUpMenuVertPadding"] * 2);
1575 		}
1576 
1577 		//output.drawRectangle(1,1,height-1,width-1,ss.getColor("windowascent"));
1578 		output.drawLine(0,0,0,height-1,ss.getColor("windowascent"));
1579 		output.drawLine(0,width-1,0,0,ss.getColor("windowascent"));
1580 		output.drawLine(0,width-1,height-1,height-1,ss.getColor("windowdescent"));
1581 		output.drawLine(width-1,width-1,0,height-1,ss.getColor("windowdescent"));
1582 		if(onDraw !is null){
1583 			onDraw();
1584 		}
1585 	}
1586 	public override void onClick(int offsetX, int offsetY, int type = 0){
1587 		offsetY /= height / elements.length;
1588 		if(elements[offsetY].source == "\\submenu\\"){
1589 			PopUpMenu m = new PopUpMenu(elements[offsetY].subElements, this.source, elements[offsetY].iconWidth);
1590 			m.onMouseClick = onMouseClick;
1591 			parent.addPopUpElement(m);
1592 			//parent.closePopUp(this);
1593 		}else{
1594 			//invokeActionEvent(new Event(elements[offsetY].source, source, null, null, null, offsetY, EventType.CLICK));
1595 			if(onMouseClick !is null)
1596 				onMouseClick(new Event(elements[offsetY].source, source, null, null, null, offsetY, EventType.CLICK));
1597 			parent.endPopUpSession();
1598 			//parent.closePopUp(this);
1599 		}
1600 		
1601 	}
1602 	public override void onMouseMovement(int x , int y) {
1603 		if(x == -1){
1604 			if(select != -1){
1605 				select = -1;
1606 				draw;
1607 			}
1608 		}else{
1609 			y /= height / elements.length;
1610 			if(y < elements.length){
1611 				select = y;
1612 			}
1613 			draw();
1614 		}
1615 	}
1616 	
1617 }
1618 /**
1619 * Defines a single MenuElement, also can contain multiple subelements.
1620 */
1621 public class PopUpMenuElement{
1622 	public string source;
1623 	public wstring text, secondaryText;
1624 	protected Bitmap16Bit icon;
1625 	private PopUpMenuElement[] subElements;
1626 	private ushort keymod;
1627 	private int keycode;
1628 	public int iconWidth;
1629 
1630 	public this(string source, wstring text, wstring secondaryText = null, Bitmap16Bit icon = null, int iconWidth = 0){
1631 		this.source = source;
1632 		this.text = text;
1633 		this.secondaryText = secondaryText;
1634 		this.icon = icon; 
1635 		this.iconWidth = iconWidth;
1636 	}
1637 	public this(string source, wstring text, wstring secondaryText, PopUpMenuElement[] subElements){
1638 		this.source = source;
1639 		this.text = text;
1640 		this.secondaryText = secondaryText;
1641 		this.subElements = subElements;
1642 		/+this.icon = icon; 
1643 		this.iconWidth = iconWidth;+/
1644 	}
1645 	public this(string source, wstring text, wstring secondaryText, PopUpMenuElement[] subElements, Bitmap16Bit icon = null, int iconWidth = 0){
1646 		this.source = source;
1647 		this.text = text;
1648 		this.secondaryText = secondaryText;
1649 		this.subElements = subElements;
1650 		/+this.icon = icon; 
1651 		this.iconWidth = iconWidth;+/
1652 	}
1653 	public Bitmap16Bit getIcon(){
1654 		return icon;
1655 	}
1656 	public void setIcon(Bitmap16Bit icon){
1657 		this.icon = icon;
1658 	}
1659 	public PopUpMenuElement[] getSubElements(){
1660 		return subElements;
1661 	}
1662 	public void loadSubElements(PopUpMenuElement[] e){
1663 		subElements = e;
1664 	}
1665 	public PopUpMenuElement opIndex(size_t i){
1666 		return subElements[i];
1667 	}
1668 	public PopUpMenuElement opIndexAssign(PopUpMenuElement value, size_t i){
1669 		subElements[i] = value;
1670 		return value;
1671 	}
1672 	public size_t getLength(){
1673 		return subElements.length;
1674 	}
1675 	public void setLength(int l){
1676 		subElements.length = l;
1677 	}
1678 
1679 }
1680 /**
1681  * Text input in pop-up fashion.
1682  */
1683 public class PopUpTextInput : PopUpElement, TextInputListener{
1684 	protected bool enableEdit, insert;
1685 	protected int textPos;
1686 	public void delegate(Event ev) onTextInput;
1687 
1688 	public this(string source, wstring text, Coordinate coordinates){
1689 		this.source = source;
1690 		this.text = text;
1691 		this.coordinates = coordinates;
1692 		enableEdit = true;
1693 		output = new BitmapDrawer(coordinates.width, coordinates.height);
1694 		inputhandler.startTextInput(this);
1695 	}
1696 	public override void draw(){
1697 		output.drawFilledRectangle(0, coordinates.width - 1, 0, coordinates.height - 1, getStyleSheet().getColor("window"));
1698 		output.drawRectangle(0, coordinates.width - 1, 0, coordinates.height - 1, getStyleSheet().getColor("windowascent"));
1699 		
1700 		//draw cursor
1701 		if(enableEdit){
1702 			int x = getStyleSheet().getFontset("default").letters['A'].width , y = getStyleSheet().getFontset("default").letters['A'].height;
1703 			if(!insert)
1704 				output.drawLine((x*textPos) + 2, (x*textPos) + 2, 2, 2 + y, getStyleSheet().getColor("selection"));
1705 			else
1706 				output.drawFilledRectangle((x*textPos) + 2, (x*(textPos + 1)) + 2, 2, 2 + y, getStyleSheet().getColor("selection"));
1707 		}
1708 		
1709 		output.drawText(2, 2, text, getStyleSheet().getFontset("default"), 1);
1710 		
1711 		if(onDraw !is null){
1712 			onDraw();
1713 		}
1714 	}
1715 	private void deleteCharacter(int n){
1716 		//text = remove(text, i);
1717 		wstring newtext;
1718 		for(int i; i < text.length; i++){
1719 			if(i != n - 1){
1720 				newtext ~= text[i];
1721 			}
1722 		}
1723 		text = newtext;
1724 	}
1725 	public void textInputEvent(uint timestamp, uint windowID, char[32] text){
1726 		int j = textPos;
1727 		wstring newtext;
1728 		for(int i ; i < textPos ; i++){
1729 			newtext ~= this.text[i];
1730 		}
1731 		for(int i ; i < 32 ; i++){
1732 			if(text[i] == 0){
1733 				break;
1734 			}
1735 			else{
1736 				newtext ~= text[i];
1737 				textPos++;
1738 				if(insert){
1739 					j++;
1740 				}
1741 			}
1742 		}
1743 		for( ; j < this.text.length ; j++){
1744 			newtext ~= this.text[j];
1745 		}
1746 		this.text = newtext;
1747 		draw();
1748 	}
1749 	public void textInputKeyEvent(uint timestamp, uint windowID, TextInputKey key, ushort modifier = 0){
1750 		switch(key){
1751 			case TextInputKey.ESCAPE:
1752 				inputhandler.stopTextInput(this);
1753 				/*draw();
1754 				invokeActionEvent(EventType.TEXTINPUT, 0, text);*/
1755 				break;
1756 			case TextInputKey.ENTER:
1757 				inputhandler.stopTextInput(this);
1758 				//invokeActionEvent(new Event(source, null, null, null, text, text.length, EventType.TEXTINPUT));
1759 				if(onTextInput !is null)
1760 					onTextInput(new Event(source, null, null, null, text, text.length, EventType.TEXTINPUT));
1761 				break;
1762 			case TextInputKey.BACKSPACE:
1763 				if(textPos > 0){
1764 					deleteCharacter(textPos);
1765 					textPos--;
1766 					draw();
1767 				}
1768 				break;
1769 			case TextInputKey.DELETE:
1770 				deleteCharacter(textPos + 1);
1771 				draw();
1772 				break;
1773 			case TextInputKey.CURSORLEFT:
1774 				if(textPos > 0){
1775 					--textPos;
1776 					draw();
1777 				}
1778 				break;
1779 			case TextInputKey.CURSORRIGHT:
1780 				if(textPos < text.length){
1781 					++textPos;
1782 					draw();
1783 				}
1784 				break;
1785 			case TextInputKey.INSERT:
1786 				insert = !insert;
1787 				draw();
1788 				break;
1789 			case TextInputKey.HOME:
1790 				textPos = 0;
1791 				draw();
1792 				break;
1793 			case TextInputKey.END:
1794 				textPos = text.length;
1795 				draw();
1796 				break;
1797 			default:
1798 				break;
1799 		
1800 		}
1801 	}
1802 	public void dropTextInput(){
1803 		parent.endPopUpSession();
1804 		//inputHandler.stopTextInput(source);
1805 		/*draw();
1806 		invokeActionEvent(EventType.TEXTINPUT, 0, text);*/
1807 	}
1808 }
1809 
1810 public interface PopUpHandler : StyleSheetContainer{
1811 	public void addPopUpElement(PopUpElement p);
1812 	public void addPopUpElement(PopUpElement p, int x, int y);
1813 	public void endPopUpSession();
1814 	public void closePopUp(PopUpElement p);
1815 	//public void drawUpdate(PopUpElement sender);
1816 	//public StyleSheet getDefaultStyleSheet();
1817 
1818 }
1819 
1820 /**
1821  * Defines the header of a ListBox.
1822  */
1823 public class ListBoxHeader{
1824 	private wstring[] text;
1825 	private int[] width;
1826 	private uint[] textInputType;
1827 	private int iconColumn;
1828 	public this(wstring[] text, int[] width, int iconColumn = 0){
1829 		this.width = width;
1830 		this.text = text;
1831 		this.iconColumn = iconColumn; 
1832 	}
1833 	/// Returns the number of columns before drawing
1834 	@nogc public int getNumberOfColumns(){
1835 		return this.text.length;
1836 	}
1837 	/// Returns the text at the given point
1838 	@nogc public wstring getText(int i){
1839 		return text[i];
1840 	}
1841 	/// Returns the width of the column
1842 	@nogc public int getColumnWidth(int i){
1843 		return width[i];
1844 	}
1845 	/// Sets the width of the column
1846 	@nogc public void setRowWidth(int i, int x){
1847 		width[i] = x;
1848 	}
1849 	/// Returns the number of column that contains the icon
1850 	@nogc public int getIconColumn(){
1851 		return iconColumn;
1852 	}
1853 	/// Returns the whole width of the header
1854 	@nogc public int getFullWidth(){
1855 		int result;
1856 		foreach(int i; width){
1857 			result += i;
1858 		}
1859 		return result;
1860 	}
1861 	/// Returns the column number from width, or -1 if x can't fit into any range
1862 	@nogc public int getColumnNumFromX(int x){
1863 		int result = -1;
1864 		if(width[0] > x) return 0;
1865 		for(int i = 1; i < width.length; i++){
1866 			if(width[i - 1] <= x || width[i] > x){
1867 				result = i;
1868 			}
1869 		}
1870 		return result;
1871 	}
1872 	/// Returns the width of the columns in a given range
1873 	@nogc public int getRangeWidth(int begin, int end){
1874 		int result;
1875 		for(; begin < end ; begin++){
1876 			result += width[begin];
1877 		}
1878 		return result;
1879 	}
1880 	/// Returns the TextInputType for the column
1881 	@nogc public uint getTextInputType(int column){
1882 		return textInputType[column];
1883 	}
1884 }
1885 /**
1886  * Defines an item in the row of a ListBox. Can be passed through the Event class
1887  */
1888  public class ListBoxItem{
1889 	private wstring[] text;
1890 	private uint[] textInputType;	///If value or array is null, the ListBoxHeader's textInputType is referred
1891 	private Bitmap16Bit icon;	/// If used, replaces the texts in the column defined by the ListBoxHeader, otherwise defaults to the text.
1892 	public this(wstring[] text, Bitmap16Bit icon = null, uint[] textInputType = null){
1893 		this.text = text;
1894 		this.icon = icon;
1895 		this.textInputType = textInputType;
1896 	}
1897 	public this(wstring[] text, uint[] textInputType){
1898 		this.text = text;
1899 		this.icon = null;
1900 		this.textInputType = textInputType;
1901 	}
1902 	/// Returns the text at the given column
1903 	@nogc public wstring getText(int column){
1904 		return text[column];
1905 	}
1906 	/// Sets the text in the given column
1907 	@nogc public void setText(int column, wstring text){
1908 		this.text[column] = text;
1909 	}
1910 	/// Returns the icon
1911 	public Bitmap16Bit getIcon(){
1912 		return icon;
1913 	}
1914 	/// Returns the input type of the given column. Refer to ListBoxHeader if return value = TextInputType.NULL
1915 	@nogc public uint getTextInputType(int column){
1916 		return textInputType[column];
1917 	}
1918 	public override string toString(){
1919 		wstring result;
1920 		foreach(ws; text)
1921 			result ~= ws;
1922 		return to!string(result);
1923 	}
1924  }
1925 /*
1926  * For use with ListBoxes and similar types. Currently left here for legacy purposes, being replaced with the classes ListBoxHeader and ListBoxElement
1927  *
1928 public struct ListBoxColumn{
1929 	public wstring header;
1930 	public wstring[] elements;
1931 	
1932 	this(wstring header, wstring[] elements){
1933 		this.header = header;
1934 		this.elements = elements;
1935 	}
1936 
1937 	/
1938 	public void removeByNumber(int i){
1939 		elements = remove(elements, i);
1940 	}
1941 }*/
1942 
1943 /**
1944  * Defines an action event in the concrete GUI.
1945  */
1946 public class Event{
1947 	public string source, subsource, path, filename;
1948 	public wstring text;
1949 	public int value, type;
1950 	public Object aux;
1951 	/**
1952 	 *If a field is unneeded, leave it blank by setting it to null.
1953 	 */
1954 	this(string source, string subsource, string path, string filename, wstring textinput, int value, int type, Object aux = null){
1955 		this.source = source;
1956 		this.subsource = subsource;
1957 		this.path = path;
1958 		this.filename = filename;
1959 		this.text = textinput;
1960 		this.value = value;
1961 		this.type = type;
1962 		this.aux = aux;
1963 	}
1964 }
1965 
1966 /+public interface ActionListener{
1967 	/**
1968 	 * Invoked mostly by WindowElements, Dialogs, and PopUpElements. Used to run the code and pass the eventdata.
1969 	 */
1970 	public void actionEvent(Event event); 
1971 }+/
1972 
1973 public interface ElementContainer : StyleSheetContainer{
1974 	public Coordinate getAbsolutePosition(WindowElement sender);
1975 }
1976 
1977 public interface StyleSheetContainer{
1978 	public StyleSheet getStyleSheet();
1979 	
1980 	public void drawUpdate(WindowElement sender);
1981 	
1982 }
1983 
1984 public interface Focusable{
1985 	public void focusGiven();
1986 	public void focusLost();
1987 }
1988 
1989 public enum EventType{
1990 	CLICK 				= 0,
1991 	TEXTINPUT			= 1,
1992 	SLIDER				= 2,
1993 	TEXTBOXSELECT		= 3,
1994 	CHECKBOX			= 4,
1995 	RADIOBUTTON			= 5,
1996 	FILEDIALOGEVENT		= 6,
1997 
1998 }