1 // Written by Christopher E. Miller
2 // See the included license.txt for copyright and license details.
3 
4 
5 ///
6 module dfl.control;
7 
8 private import dfl.internal.dlib, dfl.internal.clib;
9 	
10 private import dfl.base, dfl.form, dfl.drawing;
11 private import dfl.internal.winapi, dfl.application, dfl.event, dfl.label;
12 private import dfl.internal.wincom, dfl.internal.utf, dfl.collections, dfl.internal.com;
13 private import core.memory;
14 
15 version(NO_DRAG_DROP)
16 	version = DFL_NO_DRAG_DROP;
17 
18 version(DFL_NO_DRAG_DROP)
19 {
20 }
21 else
22 {
23 	private import dfl.data;
24 }
25 
26 version(DFL_NO_MENUS)
27 {
28 }
29 else
30 {
31 	private import dfl.menu;
32 }
33 
34 //version = RADIO_GROUP_LAYOUT;
35 version = DFL_NO_ZOMBIE_FORM;
36 
37 
38 ///
39 enum AnchorStyles: ubyte
40 {
41 	NONE = 0, ///
42 	TOP = 1, /// ditto
43 	BOTTOM = 2, /// ditto
44 	LEFT = 4, /// ditto
45 	RIGHT = 8, /// ditto
46 	
47 	/+
48 	// Extras:
49 	VERTICAL = TOP | BOTTOM,
50 	HORIZONTAL = LEFT | RIGHT,
51 	ALL = TOP | BOTTOM | LEFT | RIGHT,
52 	DEFAULT = TOP | LEFT,
53 	TOP_LEFT = TOP | LEFT,
54 	TOP_RIGHT = TOP | RIGHT,
55 	BOTTOM_LEFT = BOTTOM | LEFT,
56 	BOTTOM_RIGHT = BOTTOM | RIGHT,
57 	+/
58 }
59 
60 
61 /// Flags for setting control bounds.
62 enum BoundsSpecified: ubyte
63 {
64 	NONE = 0, ///
65 	X = 1, /// ditto
66 	Y = 2, /// ditto
67 	LOCATION = 1 | 2, /// ditto
68 	WIDTH = 4, /// ditto
69 	HEIGHT = 8, /// ditto
70 	SIZE = 4 | 8, /// ditto
71 	ALL = 1 | 2 | 4 | 8, /// ditto
72 }
73 
74 
75 /// Layout docking style.
76 enum DockStyle: ubyte
77 {
78 	NONE, ///
79 	BOTTOM, ///
80 	FILL, ///
81 	LEFT, ///
82 	RIGHT, ///
83 	TOP, ///
84 }
85 
86 
87 private
88 {
89 	struct GetZIndex
90 	{
91 		Control find;
92 		int index = -1;
93 		private int _tmp = 0;
94 	}
95 	
96 	
97 	extern(Windows) BOOL getZIndexCallback(HWND hwnd, LPARAM lparam)
98 	{
99 		GetZIndex* gzi = cast(GetZIndex*)lparam;
100 		if(hwnd == gzi.find.hwnd)
101 		{
102 			gzi.index = gzi._tmp;
103 			return FALSE; // Stop, found it.
104 		}
105 		
106 		Control ctrl;
107 		ctrl = Control.fromHandle(hwnd);
108 		if(ctrl && ctrl.parent is gzi.find.parent)
109 		{
110 			gzi._tmp++;
111 		}
112 		
113 		return TRUE; // Keep looking.
114 	}
115 }
116 
117 
118 /// Effect flags for drag/drop operations.
119 enum DragDropEffects: DWORD
120 {
121 	NONE = 0, ///
122 	COPY = 1, /// ditto
123 	MOVE = 2, /// ditto
124 	LINK = 4, /// ditto
125 	SCROLL = 0x80000000, /// ditto
126 	ALL = COPY | MOVE | LINK | SCROLL, /// ditto
127 }
128 
129 
130 /// Drag/drop action.
131 enum DragAction: HRESULT
132 {
133 	CONTINUE = S_OK, ///
134 	CANCEL = DRAGDROP_S_CANCEL, /// ditto
135 	DROP = DRAGDROP_S_DROP, /// ditto
136 }
137 
138 
139 // Flags.
140 deprecated enum UICues: uint
141 {
142 	NONE = 0,
143 	SHOW_FOCUS = 1,
144 	SHOW_KEYBOARD = 2,
145 	SHOWN = SHOW_FOCUS | SHOW_KEYBOARD,
146 	CHANGE_FOCUS = 4,
147 	CHANGE_KEYBOARD = 8, // Key mnemonic underline cues are on.
148 	CHANGED = CHANGE_FOCUS | CHANGE_KEYBOARD,
149 }
150 
151 
152 // May be OR'ed together.
153 /// Style flags of a control.
154 enum ControlStyles: uint
155 {
156 	NONE = 0, ///
157 	
158 	CONTAINER_CONTROL =                0x1, /// ditto
159 	
160 	// TODO: implement.
161 	USER_PAINT =                       0x2, /// ditto
162 	
163 	OPAQUE =                           0x4, /// ditto
164 	RESIZE_REDRAW =                    0x10, /// ditto
165 	//FIXED_WIDTH =                      0x20, // TODO: implement.
166 	//FIXED_HEIGHT =                     0x40, // TODO: implement.
167 	STANDARD_CLICK =                   0x100, /// ditto
168 	SELECTABLE =                       0x200, /// ditto
169 	
170 	// TODO: implement.
171 	USER_MOUSE =                       0x400, ///  ditto
172 	
173 	//SUPPORTS_TRANSPARENT_BACK_COLOR =  0x800, // Only if USER_PAINT and parent is derived from Control. TODO: implement.
174 	STANDARD_DOUBLE_CLICK =            0x1000, /// ditto
175 	ALL_PAINTING_IN_WM_PAINT =         0x2000, /// ditto
176 	CACHE_TEXT =                       0x4000, /// ditto
177 	ENABLE_NOTIFY_MESSAGE =            0x8000, // deprecated. Calls onNotifyMessage() for every message.
178 	//DOUBLE_BUFFER =                    0x10000, // TODO: implement.
179 	
180 	WANT_TAB_KEY = 0x01000000,
181 	WANT_ALL_KEYS = 0x02000000,
182 }
183 
184 
185 /// Control creation parameters.
186 struct CreateParams
187 {
188 	Dstring className; ///
189 	Dstring caption; /// ditto
190 	void* param; /// ditto
191 	HWND parent; /// ditto
192 	HMENU menu; /// ditto
193 	HINSTANCE inst; /// ditto
194 	int x; /// ditto
195 	int y; /// ditto
196 	int width; /// ditto
197 	int height; /// ditto
198 	DWORD classStyle; /// ditto
199 	DWORD exStyle; /// ditto
200 	DWORD style; /// ditto
201 }
202 
203 
204 deprecated class UICuesEventArgs: EventArgs
205 {
206 	deprecated:
207 	
208 	this(UICues uic)
209 	{
210 		chg = uic;
211 	}
212 	
213 	
214 	final UICues changed() // getter
215 	{
216 		return chg;
217 	}
218 	
219 	
220 	final bool changeFocus()
221 	{
222 		return (chg & UICues.CHANGE_FOCUS) != 0;
223 	}
224 	
225 	
226 	final bool changeKeyboard()
227 	{
228 		return (chg & UICues.CHANGE_KEYBOARD) != 0;
229 	}
230 	
231 	
232 	final bool showFocus()
233 	{
234 		return (chg & UICues.SHOW_FOCUS) != 0;
235 	}
236 	
237 	
238 	final bool showKeyboard()
239 	{
240 		return (chg & UICues.SHOW_KEYBOARD) != 0;
241 	}
242 	
243 	
244 	private:
245 	UICues chg;
246 }
247 
248 
249 ///
250 class ControlEventArgs: EventArgs
251 {
252 	///
253 	this(Control ctrl)
254 	{
255 		this.ctrl = ctrl;
256 	}
257 	
258 	
259 	///
260 	final @property Control control() // getter
261 	{
262 		return ctrl;
263 	}
264 	
265 	
266 	private:
267 	Control ctrl;
268 }
269 
270 
271 ///
272 class HelpEventArgs: EventArgs
273 {
274 	///
275 	this(Point mousePos)
276 	{
277 		mpos = mousePos;
278 	}
279 	
280 	
281 	///
282 	final @property void handled(bool byes) // setter
283 	{
284 		hand = byes;
285 	}
286 	
287 	/// ditto
288 	final @property bool handled() // getter
289 	{
290 		return hand;
291 	}
292 	
293 	
294 	///
295 	final @property Point mousePos() // getter
296 	{
297 		return mpos;
298 	}
299 	
300 	
301 	private:
302 	Point mpos;
303 	bool hand = false;
304 }
305 
306 
307 ///
308 class InvalidateEventArgs: EventArgs
309 {
310 	///
311 	this(Rect invalidRect)
312 	{
313 		ir = invalidRect;
314 	}
315 	
316 	
317 	///
318 	final @property Rect invalidRect() // getter
319 	{
320 		return ir;
321 	}
322 	
323 	
324 	private:
325 	Rect ir;
326 }
327 
328 
329 // ///
330 // New dimensions before resizing.
331 deprecated class BeforeResizeEventArgs: EventArgs
332 {
333 	deprecated:
334 	
335 	///
336 	this(int width, int height)
337 	{
338 		this.w = width;
339 		this.h = height;
340 	}
341 	
342 	
343 	///
344 	void width(int cx) // setter
345 	{
346 		w = cx;
347 	}
348 	
349 	/// ditto
350 	int width() // getter
351 	{
352 		return w;
353 	}
354 	
355 	
356 	///
357 	void height(int cy) // setter
358 	{
359 		h = cy;
360 	}
361 	
362 	/// ditto
363 	int height() // getter
364 	{
365 		return h;
366 	}
367 	
368 	
369 	private:
370 	int w, h;
371 }
372 
373 
374 ///
375 class LayoutEventArgs: EventArgs
376 {
377 	///
378 	this(Control affectedControl)
379 	{
380 		ac = affectedControl;
381 	}
382 	
383 	
384 	///
385 	final @property Control affectedControl() // getter
386 	{
387 		return ac;
388 	}
389 	
390 	
391 	private:
392 	Control ac;
393 }
394 
395 
396 version(DFL_NO_DRAG_DROP) {} else
397 {
398 	///
399 	class DragEventArgs: EventArgs
400 	{
401 		///
402 		this(dfl.data.IDataObject dataObj, int keyState, int x, int y,
403 			DragDropEffects allowedEffect, DragDropEffects effect)
404 		{
405 			_dobj = dataObj;
406 			_keyState = keyState;
407 			_x = x;
408 			_y = y;
409 			_allowedEffect = allowedEffect;
410 			_effect = effect;
411 		}
412 		
413 		
414 		///
415 		final @property DragDropEffects allowedEffect() // getter
416 		{
417 			return _allowedEffect;
418 		}
419 		
420 		
421 		///
422 		final @property void effect(DragDropEffects newEffect) // setter
423 		{
424 			_effect = newEffect;
425 		}
426 		
427 		
428 		/// ditto
429 		final @property DragDropEffects effect() // getter
430 		{
431 			return _effect;
432 		}
433 		
434 		
435 		///
436 		final @property dfl.data.IDataObject data() // getter
437 		{
438 			return _dobj;
439 		}
440 		
441 		
442 		///
443 		// State of ctrl, alt, shift, and mouse buttons.
444 		final @property int keyState() // getter
445 		{
446 			return _keyState;
447 		}
448 		
449 		
450 		///
451 		final @property int x() // getter
452 		{
453 			return _x;
454 		}
455 		
456 		
457 		///
458 		final @property int y() // getter
459 		{
460 			return _y;
461 		}
462 		
463 		
464 		private:
465 		dfl.data.IDataObject _dobj;
466 		int _keyState;
467 		int _x, _y;
468 		DragDropEffects _allowedEffect, _effect;
469 	}
470 	
471 	
472 	///
473 	class GiveFeedbackEventArgs: EventArgs
474 	{
475 		///
476 		this(DragDropEffects effect, bool useDefaultCursors)
477 		{
478 			_effect = effect;
479 			udefcurs = useDefaultCursors;
480 		}
481 		
482 		
483 		///
484 		final @property DragDropEffects effect() // getter
485 		{
486 			return _effect;
487 		}
488 		
489 		
490 		///
491 		final @property void useDefaultCursors(bool byes) // setter
492 		{
493 			udefcurs = byes;
494 		}
495 		
496 		/// ditto
497 		final @property bool useDefaultCursors() // getter
498 		{
499 			return udefcurs;
500 		}
501 		
502 		
503 		private:
504 		DragDropEffects _effect;
505 		bool udefcurs;
506 	}
507 	
508 	
509 	///
510 	class QueryContinueDragEventArgs: EventArgs
511 	{
512 		///
513 		this(int keyState, bool escapePressed, DragAction action)
514 		{
515 			_keyState = keyState;
516 			escp = escapePressed;
517 			_action = action;
518 		}
519 		
520 		
521 		///
522 		final @property void action(DragAction newAction) // setter
523 		{
524 			_action = newAction;
525 		}
526 		
527 		/// ditto
528 		final @property DragAction action() // getter
529 		{
530 			return _action;
531 		}
532 		
533 		
534 		///
535 		final @property bool escapePressed() // getter
536 		{
537 			return escp;
538 		}
539 		
540 		
541 		///
542 		// State of ctrl, alt and shift.
543 		final @property int keyState() // getter
544 		{
545 			return _keyState;
546 		}
547 		
548 		
549 		private:
550 		int _keyState;
551 		bool escp;
552 		DragAction _action;
553 	}
554 }
555 
556 
557 version(NO_WINDOWS_HUNG_WORKAROUND)
558 {
559 }
560 else
561 {
562 	version = WINDOWS_HUNG_WORKAROUND;
563 }
564 debug
565 {
566 	version=_DFL_WINDOWS_HUNG_WORKAROUND;
567 }
568 version(WINDOWS_HUNG_WORKAROUND)
569 {
570 	version=_DFL_WINDOWS_HUNG_WORKAROUND;
571 }
572 
573 version(_DFL_WINDOWS_HUNG_WORKAROUND)
574 {
575 	class WindowsHungDflException: DflException
576 	{
577 		this(Dstring msg)
578 		{
579 			super(msg);
580 		}
581 	}
582 }
583 
584 alias BOOL delegate(HWND) EnumWindowsCallback;
585 package struct EnumWindowsCallbackData
586 {
587 	EnumWindowsCallback callback;
588 	DThrowable exception;
589 }
590 
591 
592 // Callback for EnumWindows() and EnumChildWindows().
593 private extern(Windows) BOOL enumingWindows(HWND hwnd, LPARAM lparam) nothrow
594 {
595 	auto cbd = *(cast(EnumWindowsCallbackData*)lparam);
596 	try
597 	{
598 		return cbd.callback(hwnd);
599 	}
600 	catch (DThrowable e)
601 	{
602 		cbd.exception = e;
603 		return FALSE;
604 	}
605 	assert(0);
606 }
607 
608 
609 private struct Efi
610 {
611 	HWND hwParent;
612 	EnumWindowsCallbackData cbd;
613 }
614 
615 
616 // Callback for EnumChildWindows(). -lparam- = pointer to Efi;
617 private extern(Windows) BOOL enumingFirstWindows(HWND hwnd, LPARAM lparam) nothrow
618 {
619 	auto efi = cast(Efi*)lparam;
620 	if(efi.hwParent == GetParent(hwnd))
621 	{
622 		try
623 		{
624 			return efi.cbd.callback(hwnd);
625 		}
626 		catch (DThrowable e)
627 		{
628 			efi.cbd.exception = e;
629 			return FALSE;
630 		}
631 	}
632 	return TRUE;
633 }
634 
635 
636 package BOOL enumWindows(EnumWindowsCallback dg)
637 {
638 	EnumWindowsCallbackData cbd;
639 	cbd.callback = dg;
640 	scope (exit) if (cbd.exception) throw cbd.exception;
641 	static assert((&cbd).sizeof <= LPARAM.sizeof);
642 	return EnumWindows(&enumingWindows, cast(LPARAM)&cbd);
643 }
644 
645 
646 package BOOL enumChildWindows(HWND hwParent, EnumWindowsCallback dg)
647 {
648 	EnumWindowsCallbackData cbd;
649 	cbd.callback = dg;
650 	scope (exit) if (cbd.exception) throw cbd.exception;
651 	static assert((&cbd).sizeof <= LPARAM.sizeof);
652 	return EnumChildWindows(hwParent, &enumingWindows, cast(LPARAM)&cbd);
653 }
654 
655 
656 // Only the parent's children, not its children.
657 package BOOL enumFirstChildWindows(HWND hwParent, EnumWindowsCallback dg)
658 {
659 	Efi efi;
660 	efi.hwParent = hwParent;
661 	efi.cbd.callback = dg;
662 	scope (exit) if (efi.cbd.exception) throw efi.cbd.exception;
663 	return EnumChildWindows(hwParent, &enumingFirstWindows, cast(LPARAM)&efi);
664 }
665 
666 
667 ///
668 enum ControlFont: ubyte
669 {
670 	COMPATIBLE, ///
671 	OLD, /// ditto
672 	NATIVE, /// ditto
673 }
674 
675 
676 debug
677 {
678 	import std.string;
679 }
680 
681 
682 /// Control class.
683 class Control: DObject, IWindow // docmain
684 {
685 	///
686 	static class ControlCollection
687 	{
688 		protected this(Control owner)
689 		{
690 			_owner = owner;
691 		}
692 		
693 		
694 		deprecated alias length count;
695 		
696 		///
697 		@property int length() // getter
698 		{
699 			if(_owner.isHandleCreated)
700 			{
701 				// Inefficient :(
702 				uint len = 0;
703 				foreach(Control ctrl; this)
704 				{
705 					len++;
706 				}
707 				return len;
708 			}
709 			else
710 			{
711 				return children.length;
712 			}
713 		}
714 		
715 		
716 		///
717 		@property Control opIndex(int i) // getter
718 		{
719 			if(_owner.isHandleCreated)
720 			{
721 				int oni = 0;
722 				foreach(Control ctrl; this)
723 				{
724 					if(oni == i)
725 						return ctrl;
726 					oni++;
727 				}
728 				// Index out of bounds, bad things happen.
729 				assert(0);
730 			}
731 			else
732 			{
733 				return children[i];
734 			}
735 		}
736 		
737 		
738 		///
739 		void add(Control ctrl)
740 		{
741 			ctrl.parent = _owner;
742 		}
743 		
744 		
745 		///
746 		// opIn ?
747 		bool contains(Control ctrl)
748 		{
749 			return indexOf(ctrl) != -1;
750 		}
751 		
752 		
753 		///
754 		int indexOf(Control ctrl)
755 		{
756 			if(_owner.isHandleCreated)
757 			{
758 				int i = 0;
759 				int foundi = -1;
760 				
761 				
762 				BOOL enuming(HWND hwnd)
763 				{
764 					if(hwnd == ctrl.handle)
765 					{
766 						foundi = i;
767 						return false; // Stop.
768 					}
769 					
770 					i++;
771 					return true; // Continue.
772 				}
773 				
774 				
775 				enumFirstChildWindows(_owner.handle, &enuming);
776 				return foundi;
777 			}
778 			else
779 			{
780 				foreach(int i, Control onCtrl; children)
781 				{
782 					if(onCtrl == ctrl)
783 						return i;
784 				}
785 				return -1;
786 			}
787 		}
788 		
789 		
790 		///
791 		void remove(Control ctrl)
792 		{
793 			if(_owner.isHandleCreated)
794 			{
795 				_removeCreated(ctrl.handle);
796 			}
797 			else
798 			{
799 				int i = indexOf(ctrl);
800 				if(i != -1)
801 					_removeNotCreated(i);
802 			}
803 		}
804 		
805 		
806 		private void _removeCreated(HWND hwnd)
807 		{
808 			DestroyWindow(hwnd); // ?
809 		}
810 		
811 		
812 		package void _removeNotCreated(int i)
813 		{
814 			if(!i)
815 				children = children[1 .. children.length];
816 			else if(i == children.length - 1)
817 				children = children[0 .. i];
818 			else
819 				children = children[0 .. i] ~ children[i + 1 .. children.length];
820 		}
821 		
822 		
823 		///
824 		void removeAt(int i)
825 		{
826 			if(_owner.isHandleCreated)
827 			{
828 				int ith = 0;
829 				HWND hwndith;
830 				
831 				
832 				BOOL enuming(HWND hwnd)
833 				{
834 					if(ith == i)
835 					{
836 						hwndith = hwnd;
837 						return false; // Stop.
838 					}
839 					
840 					ith++;
841 					return true; // Continue.
842 				}
843 				
844 				
845 				enumFirstChildWindows(_owner.handle, &enuming);
846 				if(hwndith)
847 					_removeCreated(hwndith);
848 			}
849 			else
850 			{
851 				_removeNotCreated(i);
852 			}
853 		}
854 		
855 		
856 		protected final @property Control owner() // getter
857 		{
858 			return _owner;
859 		}
860 		
861 		
862 		///
863 		int opApply(int delegate(ref Control) dg)
864 		{
865 			int result = 0;
866 			
867 			if(_owner.isHandleCreated)
868 			{
869 				BOOL enuming(HWND hwnd)
870 				{
871 					Control ctrl = fromHandle(hwnd);
872 					if(ctrl)
873 					{
874 						result = dg(ctrl);
875 						if(result)
876 							return false; // Stop.
877 					}
878 					
879 					return true; // Continue.
880 				}
881 				
882 				
883 				enumFirstChildWindows(_owner.handle, &enuming);
884 			}
885 			else
886 			{
887 				foreach(Control ctrl; children)
888 				{
889 					result = dg(ctrl);
890 					if(result)
891 						break;
892 				}
893 			}
894 			
895 			return result;
896 		}
897 		
898 		mixin OpApplyAddIndex!(opApply, Control);
899 		
900 		
901 		package:
902 		Control _owner;
903 		Control[] children; // Only valid if -owner- isn't created yet (or is recreating).
904 		
905 		
906 		/+
907 		final void _array_swap(int ifrom, int ito)
908 		{
909 			if(ifrom == ito ||
910 				ifrom < 0 || ito < 0 ||
911 				ifrom >= length || ito >= length)
912 				return;
913 			
914 			Control cto;
915 			cto = children[ito];
916 			children[ito] = children[ifrom];
917 			children[ifrom] = cto;
918 		}
919 		+/
920 		
921 		
922 		final void _simple_front_one(int i)
923 		{
924 			if(i < 0 || i >= length - 1)
925 				return;
926 			
927 			children = children[0 .. i] ~ children[i + 1 .. i + 2] ~ children[i .. i + 1] ~ children[i + 2 .. children.length];
928 		}
929 		
930 		
931 		final void _simple_front_one(Control c)
932 		{
933 			return _simple_front_one(indexOf(c));
934 		}
935 		
936 		
937 		final void _simple_back_one(int i)
938 		{
939 			if(i <= 0 || i >= length)
940 				return;
941 			
942 			children = children[0 .. i - 1] ~ children[i + 1 .. i + 2] ~ children[i .. i + 1] ~ children[i + 2 .. children.length];
943 		}
944 		
945 		
946 		final void _simple_back_one(Control c)
947 		{
948 			return _simple_back_one(indexOf(c));
949 		}
950 		
951 		
952 		final void _simple_back(int i)
953 		{
954 			if(i <= 0 || i >= length)
955 				return;
956 			
957 			children = children[i .. i + 1] ~ children[0 .. i] ~ children[i + 1 .. children.length];
958 		}
959 		
960 		
961 		final void _simple_back(Control c)
962 		{
963 			return _simple_back(indexOf(c));
964 		}
965 		
966 		
967 		final void _simple_front(int i)
968 		{
969 			if(i < 0 || i >= length - 1)
970 				return;
971 			
972 			children = children[0 .. i] ~ children[i + 1 .. children.length] ~ children[i .. i + 1];
973 		}
974 		
975 		
976 		final void _simple_front(Control c)
977 		{
978 			return _simple_front(indexOf(c));
979 		}
980 	}
981 	
982 	
983 	private void _ctrladded(ControlEventArgs cea)
984 	{
985 		if(Application._compat & DflCompat.CONTROL_PARENT_096)
986 		{
987 			if(!(_exStyle() & WS_EX_CONTROLPARENT))
988 			{
989 				if(!(cbits & CBits.FORM))
990 				{
991 					//if((cea.control._style() & WS_TABSTOP) || (cea.control._exStyle() & WS_EX_CONTROLPARENT))
992 						_exStyle(_exStyle() | WS_EX_CONTROLPARENT);
993 				}
994 			}
995 		}
996 		else
997 		{
998 			assert(getStyle(ControlStyles.CONTAINER_CONTROL), "Control added to non-container parent");
999 		}
1000 		
1001 		onControlAdded(cea);
1002 	}
1003 	
1004 	
1005 	private void _ctrlremoved(ControlEventArgs cea)
1006 	{
1007 		alayout(cea.control);
1008 		
1009 		onControlRemoved(cea);
1010 	}
1011 	
1012 	
1013 	///
1014 	protected void onControlAdded(ControlEventArgs cea)
1015 	{
1016 		controlAdded(this, cea);
1017 	}
1018 	
1019 	
1020 	///
1021 	protected void onControlRemoved(ControlEventArgs cea)
1022 	{
1023 		controlRemoved(this, cea);
1024 	}
1025 	
1026 	
1027 	///
1028 	@property final HWindow handle() // IWindow getter
1029 	{
1030 		if(!isHandleCreated)
1031 		{
1032 			debug(APP_PRINT)
1033 				cprintf("Control created due to handle request.\n");
1034 			
1035 			createHandle();
1036 		}
1037 		
1038 		return hwnd;
1039 	}
1040 	
1041 	
1042 	version(DFL_NO_DRAG_DROP) {} else
1043 	{
1044 		///
1045 		@property void allowDrop(bool byes) // setter
1046 		{
1047 			/+
1048 			if(dyes)
1049 				_exStyle(_exStyle() | WS_EX_ACCEPTFILES);
1050 			else
1051 				_exStyle(_exStyle() & ~WS_EX_ACCEPTFILES);
1052 			+/
1053 			
1054 			if(byes)
1055 			{
1056 				if(!droptarget)
1057 				{
1058 					droptarget = new DropTarget(this);
1059 					if(isHandleCreated)
1060 					{
1061 						switch(RegisterDragDrop(hwnd, droptarget))
1062 						{
1063 							case S_OK:
1064 							case DRAGDROP_E_ALREADYREGISTERED: // Hmm.
1065 								break;
1066 							
1067 							default:
1068 								droptarget = null;
1069 								throw new DflException("Unable to register drag-drop");
1070 						}
1071 					}
1072 				}
1073 			}
1074 			else
1075 			{
1076 				delete droptarget;
1077 				droptarget = null;
1078 				RevokeDragDrop(hwnd);
1079 			}
1080 		}
1081 		
1082 		/// ditto
1083 		@property bool allowDrop() // getter
1084 		{
1085 			/+
1086 			return (_exStyle() & WS_EX_ACCEPTFILES) != 0;
1087 			+/
1088 			
1089 			return droptarget !is null;
1090 		}
1091 	}
1092 	
1093 	
1094 	/+
1095 	deprecated void anchor(AnchorStyles a) // setter
1096 	{
1097 		/+
1098 		anch = a;
1099 		if(!(anch & (AnchorStyles.LEFT | AnchorStyles.RIGHT)))
1100 			anch |= AnchorStyles.LEFT;
1101 		if(!(anch & (AnchorStyles.TOP | AnchorStyles.BOTTOM)))
1102 			anch |= AnchorStyles.TOP;
1103 		+/
1104 		
1105 		sdock = DockStyle.NONE; // Can't be set at the same time.
1106 	}
1107 	
1108 	
1109 	deprecated AnchorStyles anchor() // getter
1110 	{
1111 		//return anch;
1112 		return cast(AnchorStyles)(AnchorStyles.LEFT | AnchorStyles.TOP);
1113 	}
1114 	+/
1115 	
1116 	
1117 	private void _propagateBackColorAmbience()
1118 	{
1119 		Color bc;
1120 		bc = backColor;
1121 		
1122 		
1123 		void pa(Control pc)
1124 		{
1125 			foreach(Control ctrl; pc.ccollection)
1126 			{
1127 				if(Color.empty == ctrl.backc) // If default.
1128 				{
1129 					if(bc == ctrl.backColor) // If same default.
1130 					{
1131 						ctrl.deleteThisBackgroundBrush(); // Needs to be recreated with new color.
1132 						ctrl.onBackColorChanged(EventArgs.empty);
1133 						
1134 						pa(ctrl); // Recursive.
1135 					}
1136 				}
1137 			}
1138 		}
1139 		
1140 		
1141 		pa(this);
1142 	}
1143 	
1144 	
1145 	///
1146 	protected void onBackColorChanged(EventArgs ea)
1147 	{
1148 		debug(EVENT_PRINT)
1149 		{
1150 			cprintf("{ Event: onBackColorChanged - Control %.*s }\n", name);
1151 		}
1152 		
1153 		backColorChanged(this, ea);
1154 	}
1155 	
1156 	
1157 	///
1158 	@property void backColor(Color c) // setter
1159 	{
1160 		if(backc == c)
1161 			return;
1162 		
1163 		deleteThisBackgroundBrush(); // Needs to be recreated with new color.
1164 		backc = c;
1165 		onBackColorChanged(EventArgs.empty);
1166 		
1167 		_propagateBackColorAmbience();
1168 		if(isHandleCreated)
1169 			invalidate(true); // Redraw!
1170 	}
1171 	
1172 	/// ditto
1173 	@property Color backColor() // getter
1174 	{
1175 		if(Color.empty == backc)
1176 		{
1177 			if(parent)
1178 			{
1179 				return parent.backColor;
1180 			}
1181 			return defaultBackColor;
1182 		}
1183 		return backc;
1184 	}
1185 	
1186 	
1187 	///
1188 	final @property int bottom() // getter
1189 	{
1190 		return wrect.bottom;
1191 	}
1192 	
1193 	
1194 	///
1195 	final @property void bounds(Rect r) // setter
1196 	{
1197 		setBoundsCore(r.x, r.y, r.width, r.height, BoundsSpecified.ALL);
1198 	}
1199 	
1200 	/// ditto
1201 	final @property Rect bounds() // getter
1202 	{
1203 		return wrect;
1204 	}
1205 	
1206 	
1207 	/+
1208 	final @property Rect originalBounds() // getter package
1209 	{
1210 		return oldwrect;
1211 	}
1212 	+/
1213 	
1214 	
1215 	///
1216 	protected void setBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
1217 	{
1218 		// Make sure at least one flag is set.
1219 		//if(!(specified & BoundsSpecified.ALL))
1220 		if(!specified)
1221 			return;
1222 		
1223 		if(isHandleCreated)
1224 		{
1225 			UINT swpf = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOSIZE;
1226 			
1227 			if(specified & BoundsSpecified.X)
1228 			{
1229 				if(!(specified & BoundsSpecified.Y))
1230 					y = this.top();
1231 				swpf &= ~SWP_NOMOVE;
1232 			}
1233 			else if(specified & BoundsSpecified.Y)
1234 			{
1235 				x = this.left();
1236 				swpf &= ~SWP_NOMOVE;
1237 			}
1238 			
1239 			if(specified & BoundsSpecified.WIDTH)
1240 			{
1241 				if(!(specified & BoundsSpecified.HEIGHT))
1242 					height = this.height();
1243 				swpf &= ~SWP_NOSIZE;
1244 			}
1245 			else if(specified & BoundsSpecified.HEIGHT)
1246 			{
1247 				width = this.width();
1248 				swpf &= ~SWP_NOSIZE;
1249 			}
1250 			
1251 			SetWindowPos(hwnd, HWND.init, x, y, width, height, swpf);
1252 			// Window events will update -wrect-.
1253 		}
1254 		else
1255 		{
1256 			if(specified & BoundsSpecified.X)
1257 				wrect.x = x;
1258 			if(specified & BoundsSpecified.Y)
1259 				wrect.y = y;
1260 			if(specified & BoundsSpecified.WIDTH)
1261 			{
1262 				if(width < 0)
1263 					width = 0;
1264 				
1265 				wrect.width = width;
1266 				wclientsz.width = width;
1267 			}
1268 			if(specified & BoundsSpecified.HEIGHT)
1269 			{
1270 				if(height < 0)
1271 					height = 0;
1272 				
1273 				wrect.height = height;
1274 				wclientsz.height = height;
1275 			}
1276 			
1277 			//oldwrect = wrect;
1278 		}
1279 	}
1280 	
1281 	
1282 	///
1283 	final @property bool canFocus() // getter
1284 	{
1285 		/+
1286 		LONG wl = _style();
1287 		return /+ hwnd && +/ (wl & WS_VISIBLE) && !(wl & WS_DISABLED);
1288 		+/
1289 		//return visible && enabled;
1290 		// Don't need to check -isHandleCreated- because IsWindowVisible() will fail from a null HWND.
1291 		return /+ isHandleCreated && +/ IsWindowVisible(hwnd) && IsWindowEnabled(hwnd);
1292 	}
1293 	
1294 	
1295 	///
1296 	final @property bool canSelect() // getter
1297 	out(result)
1298 	{
1299 		if(result)
1300 		{
1301 			assert(isHandleCreated);
1302 		}
1303 	}
1304 	body
1305 	{
1306 		// All parent controls need to be visible and enabled, too.
1307 		// Don't need to check -isHandleCreated- because IsWindowVisible() will fail from a null HWND.
1308 		return /+ isHandleCreated && +/ (ctrlStyle & ControlStyles.SELECTABLE) &&
1309 			IsWindowVisible(hwnd) && IsWindowEnabled(hwnd);
1310 	}
1311 	
1312 	
1313 	package final bool _hasSelStyle()
1314 	{
1315 		return getStyle(ControlStyles.SELECTABLE);
1316 	}
1317 	
1318 	
1319 	///
1320 	// Returns true if this control has the mouse capture.
1321 	final @property bool capture() // getter
1322 	{
1323 		return isHandleCreated && hwnd == GetCapture();
1324 	}
1325 	
1326 	/// ditto
1327 	final @property void capture(bool cyes) // setter
1328 	{
1329 		if(cyes)
1330 			SetCapture(hwnd);
1331 		else
1332 			ReleaseCapture();
1333 	}
1334 	
1335 	
1336 	// When true, validating and validated events are fired when the control
1337 	// receives focus. Typically set to false for controls such as a Help button.
1338 	// Default is true.
1339 	deprecated final bool causesValidation() // getter
1340 	{
1341 		//return cvalidation;
1342 		return false;
1343 	}
1344 	
1345 	
1346 	deprecated protected void onCausesValidationChanged(EventArgs ea)
1347 	{
1348 		//causesValidationChanged(this, ea);
1349 	}
1350 	
1351 	
1352 	deprecated final void causesValidation(bool vyes) // setter
1353 	{
1354 		/+
1355 		if(cvalidation == vyes)
1356 			return;
1357 		
1358 		cvalidation = vyes;
1359 		
1360 		onCausesValidationChanged(EventArgs.empty);
1361 		+/
1362 	}
1363 	
1364 	
1365 	///
1366 	final @property Rect clientRectangle() // getter
1367 	{
1368 		return Rect(Point(0, 0), wclientsz);
1369 	}
1370 	
1371 	
1372 	///
1373 	final bool contains(Control ctrl)
1374 	{
1375 		//return ccollection.contains(ctrl);
1376 		return ctrl && ctrl.parent is this;
1377 	}
1378 	
1379 	
1380 	///
1381 	final @property Size clientSize() // getter
1382 	{
1383 		return wclientsz;
1384 	}
1385 	
1386 	/// ditto
1387 	final @property void clientSize(Size sz) // setter
1388 	{
1389 		setClientSizeCore(sz.width, sz.height);
1390 	}
1391 	
1392 	
1393 	///
1394 	protected void setClientSizeCore(int width, int height)
1395 	{
1396 		/+
1397 		if(isHandleCreated)
1398 			setBoundsCore(0, 0, width, height, BoundsSpecified.SIZE);
1399 		
1400 		//wclientsz = Size(width, height);
1401 		+/
1402 		
1403 		RECT r;
1404 		
1405 		r.left = 0;
1406 		r.top = 0;
1407 		r.right = width;
1408 		r.bottom = height;
1409 		
1410 		AdjustWindowRectEx(&r, _style(), FALSE, _exStyle());
1411 		
1412 		setBoundsCore(0, 0, r.right - r.left, r.bottom - r.top, BoundsSpecified.SIZE);
1413 	}
1414 	
1415 	
1416 	///
1417 	// This window or one of its children has focus.
1418 	final @property bool containsFocus() // getter
1419 	{
1420 		if(!isHandleCreated)
1421 			return false;
1422 		
1423 		HWND hwfocus = GetFocus();
1424 		return hwfocus == hwnd || IsChild(hwnd, hwfocus);
1425 	}
1426 	
1427 	
1428 	version(DFL_NO_MENUS)
1429 	{
1430 	}
1431 	else
1432 	{
1433 		///
1434 		protected void onContextMenuChanged(EventArgs ea)
1435 		{
1436 			contextMenuChanged(this, ea);
1437 		}
1438 		
1439 		
1440 		///
1441 		@property void contextMenu(ContextMenu menu) // setter
1442 		{
1443 			if(cmenu is menu)
1444 				return;
1445 			
1446 			cmenu = menu;
1447 			
1448 			if(isHandleCreated)
1449 			{
1450 				onContextMenuChanged(EventArgs.empty);
1451 			}
1452 		}
1453 		
1454 		/// ditto
1455 		@property ContextMenu contextMenu() // getter
1456 		{
1457 			return cmenu;
1458 		}
1459 	}
1460 	
1461 	
1462 	///
1463 	final @property ControlCollection controls() // getter
1464 	{
1465 		//return new ControlCollection(this);
1466 		return ccollection;
1467 	}
1468 	
1469 	
1470 	///
1471 	final @property bool created() // getter
1472 	{
1473 		// To-do: only return true when createHandle finishes.
1474 		// Will also need to update uses of created/isHandleCreated.
1475 		// Return false again when disposing/killing.
1476 		//return isHandleCreated;
1477 		return isHandleCreated || recreatingHandle;
1478 	}
1479 	
1480 	
1481 	private void _propagateCursorAmbience()
1482 	{
1483 		Cursor cur;
1484 		cur = cursor;
1485 		
1486 		
1487 		void pa(Control pc)
1488 		{
1489 			foreach(Control ctrl; pc.ccollection)
1490 			{
1491 				if(ctrl.wcurs is null) // If default.
1492 				{
1493 					if(cur is ctrl.cursor) // If same default.
1494 					{
1495 						ctrl.onCursorChanged(EventArgs.empty);
1496 						
1497 						pa(ctrl); // Recursive.
1498 					}
1499 				}
1500 			}
1501 		}
1502 		
1503 		
1504 		pa(this);
1505 	}
1506 	
1507 	
1508 	///
1509 	protected void onCursorChanged(EventArgs ea)
1510 	{
1511 		/+
1512 		debug(EVENT_PRINT)
1513 		{
1514 			cprintf("{ Event: onCursorChanged - Control %.*s }\n", name);
1515 		}
1516 		+/
1517 		
1518 		if(isHandleCreated)
1519 		{
1520 			if(visible && enabled)
1521 			{
1522 				Point curpt = Cursor.position;
1523 				if(hwnd == WindowFromPoint(curpt.point))
1524 				{
1525 					SendMessageA(hwnd, WM_SETCURSOR, cast(WPARAM)hwnd,
1526 						MAKELPARAM(
1527 							SendMessageA(hwnd, WM_NCHITTEST, 0, MAKELPARAM(curpt.x, curpt.y)),
1528 							WM_MOUSEMOVE)
1529 							);
1530 				}
1531 			}
1532 		}
1533 		
1534 		cursorChanged(this, ea);
1535 	}
1536 	
1537 	
1538 	///
1539 	@property void cursor(Cursor cur) // setter
1540 	{
1541 		if(cur is wcurs)
1542 			return;
1543 		
1544 		wcurs = cur;
1545 		onCursorChanged(EventArgs.empty);
1546 		
1547 		_propagateCursorAmbience();
1548 	}
1549 	
1550 	/// ditto
1551 	@property Cursor cursor() // getter
1552 	{
1553 		if(!wcurs)
1554 		{
1555 			if(parent)
1556 			{
1557 				return parent.cursor;
1558 			}
1559 			return _defaultCursor;
1560 		}
1561 		return wcurs;
1562 	}
1563 	
1564 	
1565 	///
1566 	static @property Color defaultBackColor() // getter
1567 	{
1568 		return Color.systemColor(COLOR_BTNFACE);
1569 	}
1570 	
1571 	
1572 	///
1573 	static @property Color defaultForeColor() //getter
1574 	{
1575 		return Color.systemColor(COLOR_BTNTEXT);
1576 	}
1577 	
1578 	
1579 	private static Font _deffont = null;
1580 	
1581 	
1582 	private static Font _createOldFont()
1583 	{
1584 		return new Font(cast(HFONT)GetStockObject(DEFAULT_GUI_FONT), false);
1585 	}
1586 	
1587 	
1588 	private static Font _createCompatibleFont()
1589 	{
1590 		Font result;
1591 		result = _createOldFont();
1592 		
1593 		try
1594 		{
1595 			OSVERSIONINFOA osi;
1596 			osi.dwOSVersionInfoSize = osi.sizeof;
1597 			if(GetVersionExA(&osi) && osi.dwMajorVersion >= 5)
1598 			{
1599 				// "MS Shell Dlg" / "MS Shell Dlg 2" not always supported.
1600 				result = new Font("MS Shell Dlg 2", result.getSize(GraphicsUnit.POINT), GraphicsUnit.POINT);
1601 			}
1602 		}
1603 		catch
1604 		{
1605 		}
1606 		
1607 		//if(!result)
1608 		//	result = _createOldFont();
1609 		assert(result !is null);
1610 		
1611 		return result;
1612 	}
1613 	
1614 	
1615 	private static Font _createNativeFont()
1616 	{
1617 		Font result;
1618 		
1619 		NONCLIENTMETRICSA ncm;
1620 		ncm.cbSize = ncm.sizeof;
1621 		if(!SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, ncm.sizeof, &ncm, 0))
1622 		{
1623 			result = _createCompatibleFont();
1624 		}
1625 		else
1626 		{
1627 			result = new Font(&ncm.lfMessageFont, true);
1628 		}
1629 		
1630 		return result;
1631 	}
1632 	
1633 	
1634 	private static void _setDeffont(ControlFont cf)
1635 	{
1636 		synchronized
1637 		{
1638 			assert(_deffont is null);
1639 			switch(cf)
1640 			{
1641 				case ControlFont.COMPATIBLE:
1642 					_deffont = _createCompatibleFont();
1643 					break;
1644 				case ControlFont.NATIVE:
1645 					_deffont = _createNativeFont();
1646 					break;
1647 				case ControlFont.OLD:
1648 					_deffont = _createOldFont();
1649 					break;
1650 				default:
1651 					assert(0);
1652 			}
1653 		}
1654 	}
1655 	
1656 	
1657 	deprecated alias defaultFont controlFont;
1658 	
1659 	///
1660 	static @property void defaultFont(ControlFont cf) // setter
1661 	{
1662 		if(_deffont)
1663 			throw new DflException("Control font already selected");
1664 		_setDeffont(cf);
1665 	}
1666 	
1667 	/// ditto
1668 	static @property void defaultFont(Font f) // setter
1669 	{
1670 		if(_deffont)
1671 			throw new DflException("Control font already selected");
1672 		_deffont = f;
1673 	}
1674 	
1675 	/// ditto
1676 	static @property Font defaultFont() // getter
1677 	{
1678 		if(!_deffont)
1679 		{
1680 			_setDeffont(ControlFont.COMPATIBLE);
1681 		}
1682 		
1683 		return _deffont;
1684 	}
1685 	
1686 	
1687 	package static class SafeCursor: Cursor
1688 	{
1689 		this(HCURSOR hcur)
1690 		{
1691 			super(hcur, false);
1692 		}
1693 		
1694 		
1695 		override void dispose()
1696 		{
1697 		}
1698 		
1699 		
1700 		/+
1701 		~this()
1702 		{
1703 			super.dispose();
1704 		}
1705 		+/
1706 	}
1707 	
1708 	
1709 	package static @property Cursor _defaultCursor() // getter
1710 	{
1711 		static Cursor def = null;
1712 		
1713 		if(!def)
1714 		{
1715 			synchronized
1716 			{
1717 				if(!def)
1718 					def = new SafeCursor(LoadCursorA(HINSTANCE.init, IDC_ARROW));
1719 			}
1720 		}
1721 		
1722 		return def;
1723 	}
1724 	
1725 	
1726 	///
1727 	@property Rect displayRectangle() // getter
1728 	{
1729 		return clientRectangle;
1730 	}
1731 	
1732 	
1733 	///
1734 	//protected void onDockChanged(EventArgs ea)
1735 	protected void onHasLayoutChanged(EventArgs ea)
1736 	{
1737 		if(parent)
1738 			parent.alayout(this);
1739 		
1740 		//dockChanged(this, ea);
1741 		hasLayoutChanged(this, ea);
1742 	}
1743 	
1744 	alias onHasLayoutChanged onDockChanged;
1745 	
1746 	
1747 	private final void _alreadyLayout()
1748 	{
1749 		throw new DflException("Control already has a layout");
1750 	}
1751 	
1752 	
1753 	///
1754 	@property DockStyle dock() // getter
1755 	{
1756 		return sdock;
1757 	}
1758 	
1759 	/// ditto
1760 	@property void dock(DockStyle ds) // setter
1761 	{
1762 		if(ds == sdock)
1763 			return;
1764 		
1765 		DockStyle _olddock = sdock;
1766 		sdock = ds;
1767 		/+
1768 		anch = AnchorStyles.NONE; // Can't be set at the same time.
1769 		+/
1770 		
1771 		if(DockStyle.NONE == ds)
1772 		{
1773 			if(DockStyle.NONE != _olddock) // If it was even docking before; don't unset hasLayout for something else.
1774 				hasLayout = false;
1775 		}
1776 		else
1777 		{
1778 			// Ensure not replacing some other layout, but OK if replacing another dock.
1779 			if(DockStyle.NONE == _olddock)
1780 			{
1781 				if(hasLayout)
1782 					_alreadyLayout();
1783 			}
1784 			hasLayout = true;
1785 		}
1786 		
1787 		/+ // Called by hasLayout.
1788 		if(isHandleCreated)
1789 		{
1790 			onDockChanged(EventArgs.empty);
1791 		}
1792 		+/
1793 	}
1794 	
1795 	
1796 	/// Get or set whether or not this control currently has its bounds managed. Fires onHasLayoutChanged as needed.
1797 	final @property bool hasLayout() // getter
1798 	{
1799 		if(cbits & CBits.HAS_LAYOUT)
1800 			return true;
1801 		return false;
1802 	}
1803 	
1804 	/// ditto
1805 	final @property void hasLayout(bool byes) // setter
1806 	{
1807 		//if(byes == hasLayout)
1808 		//	return; // No! setting this property again must trigger onHasLayoutChanged again.
1809 		
1810 		if(byes)
1811 			cbits |= CBits.HAS_LAYOUT;
1812 		else
1813 			cbits &= ~CBits.HAS_LAYOUT;
1814 		
1815 		if(byes) // No need if layout is removed.
1816 		{
1817 			if(isHandleCreated)
1818 			{
1819 				onHasLayoutChanged(EventArgs.empty);
1820 			}
1821 		}
1822 	}
1823 	
1824 	
1825 	package final void _venabled(bool byes)
1826 	{
1827 		if(isHandleCreated)
1828 		{
1829 			EnableWindow(hwnd, byes);
1830 			// Window events will update -wstyle-.
1831 		}
1832 		else
1833 		{
1834 			if(byes)
1835 				wstyle &= ~WS_DISABLED;
1836 			else
1837 				wstyle |= WS_DISABLED;
1838 		}
1839 	}
1840 	
1841 	
1842 	///
1843 	final @property void enabled(bool byes) // setter
1844 	{
1845 		if(byes)
1846 			cbits |= CBits.ENABLED;
1847 		else
1848 			cbits &= ~CBits.ENABLED;
1849 		
1850 		/+
1851 		if(!byes)
1852 		{
1853 			_venabled(false);
1854 		}
1855 		else
1856 		{
1857 			if(!parent || parent.enabled)
1858 				_venabled(true);
1859 		}
1860 		
1861 		_propagateEnabledAmbience();
1862 		+/
1863 		
1864 		_venabled(byes);
1865 	}
1866 	
1867 	///
1868 	final @property bool enabled() // getter
1869 	{
1870 		/*
1871 		return IsWindowEnabled(hwnd) ? true : false;
1872 		*/
1873 		
1874 		return (wstyle & WS_DISABLED) == 0;
1875 	}
1876 	
1877 	
1878 	private void _propagateEnabledAmbience()
1879 	{
1880 		/+ // Isn't working...
1881 		if(cbits & CBits.FORM)
1882 			return;
1883 		
1884 		bool en = enabled;
1885 		
1886 		void pa(Control pc)
1887 		{
1888 			foreach(Control ctrl; pc.ccollection)
1889 			{
1890 				if(ctrl.cbits & CBits.ENABLED)
1891 				{
1892 					_venabled(en);
1893 					
1894 					pa(ctrl);
1895 				}
1896 			}
1897 		}
1898 		
1899 		pa(this);
1900 		+/
1901 	}
1902 	
1903 	
1904 	///
1905 	final void enable()
1906 	{
1907 		enabled = true;
1908 	}
1909 	
1910 	/// ditto
1911 	final void disable()
1912 	{
1913 		enabled = false;
1914 	}
1915 	
1916 	
1917 	///
1918 	@property bool focused() // getter
1919 	{
1920 		//return isHandleCreated && hwnd == GetFocus();
1921 		return created && fromChildHandle(GetFocus()) is this;
1922 	}
1923 	
1924 	
1925 	///
1926 	@property void font(Font f) // setter
1927 	{
1928 		if(wfont is f)
1929 			return;
1930 		
1931 		wfont = f;
1932 		if(isHandleCreated)
1933 			SendMessageA(hwnd, WM_SETFONT, cast(WPARAM)wfont.handle, MAKELPARAM(true, 0));
1934 		onFontChanged(EventArgs.empty);
1935 		
1936 		_propagateFontAmbience();
1937 	}
1938 	
1939 	/// ditto
1940 	@property Font font() // getter
1941 	{
1942 		if(!wfont)
1943 		{
1944 			if(parent)
1945 			{
1946 				return parent.font;
1947 			}
1948 			return defaultFont;
1949 		}
1950 		return wfont;
1951 	}
1952 	
1953 	
1954 	private void _propagateForeColorAmbience()
1955 	{
1956 		Color fc;
1957 		fc = foreColor;
1958 		
1959 		
1960 		void pa(Control pc)
1961 		{
1962 			foreach(Control ctrl; pc.ccollection)
1963 			{
1964 				if(Color.empty == ctrl.forec) // If default.
1965 				{
1966 					if(fc == ctrl.foreColor) // If same default.
1967 					{
1968 						ctrl.onForeColorChanged(EventArgs.empty);
1969 						
1970 						pa(ctrl); // Recursive.
1971 					}
1972 				}
1973 			}
1974 		}
1975 		
1976 		
1977 		pa(this);
1978 	}
1979 	
1980 	
1981 	///
1982 	protected void onForeColorChanged(EventArgs ea)
1983 	{
1984 		debug(EVENT_PRINT)
1985 		{
1986 			cprintf("{ Event: onForeColorChanged - Control %.*s }\n", name);
1987 		}
1988 		
1989 		foreColorChanged(this, ea);
1990 	}
1991 	
1992 	
1993 	///
1994 	@property void foreColor(Color c) // setter
1995 	{
1996 		if(c == forec)
1997 			return;
1998 		
1999 		forec = c;
2000 		onForeColorChanged(EventArgs.empty);
2001 		
2002 		_propagateForeColorAmbience();
2003 		if(isHandleCreated)
2004 			invalidate(true); // Redraw!
2005 	}
2006 	
2007 	/// ditto
2008 	@property Color foreColor() // getter
2009 	{
2010 		if(Color.empty == forec)
2011 		{
2012 			if(parent)
2013 			{
2014 				return parent.foreColor;
2015 			}
2016 			return defaultForeColor;
2017 		}
2018 		return forec;
2019 	}
2020 	
2021 	
2022 	///
2023 	// Doesn't cause a ControlCollection to be constructed so
2024 	// it could improve performance when walking through children.
2025 	final @property bool hasChildren() // getter
2026 	{
2027 		//return isHandleCreated && GetWindow(hwnd, GW_CHILD) != HWND.init;
2028 		
2029 		if(isHandleCreated)
2030 		{
2031 			return GetWindow(hwnd, GW_CHILD) != HWND.init;
2032 		}
2033 		else
2034 		{
2035 			return ccollection.children.length != 0;
2036 		}
2037 	}
2038 	
2039 	
2040 	///
2041 	final @property void height(int h) // setter
2042 	{
2043 		/*
2044 		RECT rect;
2045 		GetWindowRect(hwnd, &rect);
2046 		SetWindowPos(hwnd, HWND.init, 0, 0, rect.right - rect.left, h, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
2047 		*/
2048 		
2049 		setBoundsCore(0, 0, 0, h, BoundsSpecified.HEIGHT);
2050 	}
2051 	
2052 	/// ditto
2053 	final @property int height() // getter
2054 	{
2055 		return wrect.height;
2056 	}
2057 	
2058 	
2059 	///
2060 	final @property bool isHandleCreated() // getter
2061 	{
2062 		return hwnd != HWND.init;
2063 	}
2064 	
2065 	
2066 	///
2067 	final @property void left(int l) // setter
2068 	{
2069 		/*
2070 		RECT rect;
2071 		GetWindowRect(hwnd, &rect);
2072 		SetWindowPos(hwnd, HWND.init, l, rect.top, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
2073 		*/
2074 		
2075 		setBoundsCore(l, 0, 0, 0, BoundsSpecified.X);
2076 	}
2077 	
2078 	/// ditto
2079 	final @property int left() // getter
2080 	{
2081 		return wrect.x;
2082 	}
2083 	
2084 	
2085 	/// Property: get or set the X and Y location of the control.
2086 	final @property void location(Point pt) // setter
2087 	{
2088 		/*
2089 		SetWindowPos(hwnd, HWND.init, pt.x, pt.y, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
2090 		*/
2091 		
2092 		setBoundsCore(pt.x, pt.y, 0, 0, BoundsSpecified.LOCATION);
2093 	}
2094 	
2095 	/// ditto
2096 	final @property Point location() // getter
2097 	{
2098 		return wrect.location;
2099 	}
2100 	
2101 	
2102 	/// Currently depressed modifier keys.
2103 	static @property Keys modifierKeys() // getter
2104 	{
2105 		// Is there a better way to do this?
2106 		Keys ks = Keys.NONE;
2107 		if(GetAsyncKeyState(VK_SHIFT) & 0x8000)
2108 			ks |= Keys.SHIFT;
2109 		if(GetAsyncKeyState(VK_MENU) & 0x8000)
2110 			ks |= Keys.ALT;
2111 		if(GetAsyncKeyState(VK_CONTROL) & 0x8000)
2112 			ks|= Keys.CONTROL;
2113 		return ks;
2114 	}
2115 	
2116 	
2117 	/// Currently depressed mouse buttons.
2118 	static @property MouseButtons mouseButtons() // getter
2119 	{
2120 		MouseButtons result;
2121 		
2122 		result = MouseButtons.NONE;
2123 		if(GetSystemMetrics(SM_SWAPBUTTON))
2124 		{
2125 			if(GetAsyncKeyState(VK_LBUTTON) & 0x8000)
2126 				result |= MouseButtons.RIGHT; // Swapped.
2127 			if(GetAsyncKeyState(VK_RBUTTON) & 0x8000)
2128 				result |= MouseButtons.LEFT; // Swapped.
2129 		}
2130 		else
2131 		{
2132 			if(GetAsyncKeyState(VK_LBUTTON) & 0x8000)
2133 				result |= MouseButtons.LEFT;
2134 			if(GetAsyncKeyState(VK_RBUTTON) & 0x8000)
2135 				result |= MouseButtons.RIGHT;
2136 		}
2137 		if(GetAsyncKeyState(VK_MBUTTON) & 0x8000)
2138 			result |= MouseButtons.MIDDLE;
2139 		
2140 		return result;
2141 	}
2142 	
2143 	
2144 	///
2145 	static @property Point mousePosition() // getter
2146 	{
2147 		Point pt;
2148 		GetCursorPos(&pt.point);
2149 		return pt;
2150 	}
2151 	
2152 	
2153 	/// Property: get or set the name of this control used in code.
2154 	final @property void name(Dstring txt) // setter
2155 	{
2156 		_ctrlname = txt;
2157 	}
2158 	
2159 	/// ditto
2160 	final @property Dstring name() // getter
2161 	{
2162 		return _ctrlname;
2163 	}
2164 	
2165 	
2166 	///
2167 	protected void onParentChanged(EventArgs ea)
2168 	{
2169 		debug(EVENT_PRINT)
2170 		{
2171 			cprintf("{ Event: onParentChanged - Control %.*s }\n", name);
2172 		}
2173 		
2174 		parentChanged(this, ea);
2175 	}
2176 	
2177 	
2178 	/+
2179 	///
2180 	// ea is the new parent.
2181 	protected void onParentChanging(ControlEventArgs ea)
2182 	{
2183 	}
2184 	+/
2185 	
2186 	
2187 	///
2188 	final Form findForm()
2189 	{
2190 		Form f;
2191 		Control c;
2192 		
2193 		c = this;
2194 		for(;;)
2195 		{
2196 			f = cast(Form)c;
2197 			if(f)
2198 				break;
2199 			c = c.parent;
2200 			if(!c)
2201 				return null;
2202 		}
2203 		return f;
2204 	}
2205 	
2206 	
2207 	///
2208 	final @property void parent(Control c) // setter
2209 	{
2210 		if(c is wparent)
2211 			return;
2212 		
2213 		if(!(_style() & WS_CHILD) || (_exStyle() & WS_EX_MDICHILD))
2214 			throw new DflException("Cannot add a top level control to a control");
2215 		
2216 		//scope ControlEventArgs pcea = new ControlEventArgs(c);
2217 		//onParentChanging(pcea);
2218 		
2219 		Control oldparent;
2220 		_FixAmbientOld oldinfo;
2221 		
2222 		oldparent = wparent;
2223 		
2224 		if(oldparent)
2225 		{
2226 			oldinfo.set(oldparent);
2227 			
2228 			if(!oldparent.isHandleCreated)
2229 			{
2230 				int oi = oldparent.controls.indexOf(this);
2231 				//assert(-1 != oi); // Fails if the parent (and thus this) handles destroyed.
2232 				if(-1 != oi)
2233 					oldparent.controls._removeNotCreated(oi);
2234 			}
2235 		}
2236 		else
2237 		{
2238 			oldinfo.set(this);
2239 		}
2240 		
2241 		scope ControlEventArgs cea = new ControlEventArgs(this);
2242 		
2243 		if(c)
2244 		{
2245 			wparent = c;
2246 			
2247 			// I want the destroy notification. Don't need it anymore.
2248 			//c._exStyle(c._exStyle() & ~WS_EX_NOPARENTNOTIFY);
2249 			
2250 			if(c.isHandleCreated)
2251 			{
2252 				cbits &= ~CBits.NEED_INIT_LAYOUT;
2253 				
2254 				//if(created)
2255 				if(isHandleCreated)
2256 				{
2257 					SetParent(hwnd, c.hwnd);
2258 				}
2259 				else
2260 				{
2261 					// If the parent is created, create me!
2262 					createControl();
2263 				}
2264 				
2265 				onParentChanged(EventArgs.empty);
2266 				if(oldparent)
2267 					oldparent._ctrlremoved(cea);
2268 				c._ctrladded(cea);
2269 				_fixAmbient(&oldinfo);
2270 				
2271 				initLayout();
2272 			}
2273 			else
2274 			{
2275 				// If the parent exists and isn't created, need to add
2276 				// -this- to its children array.
2277 				c.ccollection.children ~= this;
2278 				
2279 				onParentChanged(EventArgs.empty);
2280 				if(oldparent)
2281 					oldparent._ctrlremoved(cea);
2282 				c._ctrladded(cea);
2283 				_fixAmbient(&oldinfo);
2284 				
2285 				cbits |= CBits.NEED_INIT_LAYOUT;
2286 			}
2287 		}
2288 		else
2289 		{
2290 			assert(c is null);
2291 			//wparent = c;
2292 			wparent = null;
2293 			
2294 			if(isHandleCreated)
2295 				SetParent(hwnd, HWND.init);
2296 			
2297 			onParentChanged(EventArgs.empty);
2298 			assert(oldparent !is null);
2299 			oldparent._ctrlremoved(cea);
2300 			_fixAmbient(&oldinfo);
2301 		}
2302 	}
2303 	
2304 	/// ditto
2305 	final @property Control parent() // getter
2306 	{
2307 		return wparent;
2308 	}
2309 	
2310 	
2311 	private final Control _fetchParent()
2312 	{
2313 		HWND hwParent = GetParent(hwnd);
2314 		return fromHandle(hwParent);
2315 	}
2316 	
2317 	
2318 	// TODO: check implementation.
2319 	private static HRGN dupHrgn(HRGN hrgn)
2320 	{
2321 		HRGN rdup = CreateRectRgn(0, 0, 1, 1);
2322 		CombineRgn(rdup, hrgn, HRGN.init, RGN_COPY);
2323 		return rdup;
2324 	}
2325 	
2326 	
2327 	///
2328 	final @property void region(Region rgn) // setter
2329 	{
2330 		if(isHandleCreated)
2331 		{
2332 			// Need to make a copy of the region.
2333 			SetWindowRgn(hwnd, dupHrgn(rgn.handle), true);
2334 		}
2335 		
2336 		wregion = rgn;
2337 	}
2338 	
2339 	/// ditto
2340 	final @property Region region() // getter
2341 	{
2342 		return wregion;
2343 	}
2344 	
2345 	
2346 	private final Region _fetchRegion()
2347 	{
2348 		HRGN hrgn = CreateRectRgn(0, 0, 1, 1);
2349 		GetWindowRgn(hwnd, hrgn);
2350 		return new Region(hrgn); // Owned because GetWindowRgn() gives a copy.
2351 	}
2352 	
2353 	
2354 	///
2355 	final @property int right() // getter
2356 	{
2357 		return wrect.right;
2358 	}
2359 	
2360 	
2361 	/+
2362 	@property void rightToLeft(bool byes) // setter
2363 	{
2364 		LONG wl = _exStyle();
2365 		if(byes)
2366 			wl |= WS_EX_RTLREADING;
2367 		else
2368 			wl &= ~WS_EX_RTLREADING;
2369 		_exStyle(wl);
2370 	}
2371 	
2372 	
2373 	@property bool rightToLeft() // getter
2374 	{
2375 		return (_exStyle() & WS_EX_RTLREADING) != 0;
2376 	}
2377 	+/
2378 	
2379 	
2380 	deprecated @property void rightToLeft(bool byes) // setter
2381 	{
2382 		rightToLeft = byes ? RightToLeft.YES : RightToLeft.NO;
2383 	}
2384 	
2385 	
2386 	package final void _fixRtol(RightToLeft val)
2387 	{
2388 		switch(val)
2389 		{
2390 			case RightToLeft.INHERIT:
2391 				if(parent && parent.rightToLeft == RightToLeft.YES)
2392 				{
2393 					goto case RightToLeft.YES;
2394 				}
2395 				goto case RightToLeft.NO;
2396 			
2397 			case RightToLeft.YES:
2398 				_exStyle(_exStyle() | WS_EX_RTLREADING);
2399 				break;
2400 			
2401 			case RightToLeft.NO:
2402 				_exStyle(_exStyle() & ~WS_EX_RTLREADING);
2403 				break;
2404 			
2405 			default:
2406 				assert(0);
2407 		}
2408 		
2409 		//invalidate(true); // Children too in case they inherit.
2410 		invalidate(false); // Since children are enumerated.
2411 	}
2412 	
2413 	
2414 	private void _propagateRtolAmbience()
2415 	{
2416 		RightToLeft rl;
2417 		rl = rightToLeft;
2418 		
2419 		
2420 		void pa(Control pc)
2421 		{
2422 			if(RightToLeft.INHERIT == pc.rtol)
2423 			{
2424 				//pc._fixRtol(rtol);
2425 				pc._fixRtol(rl); // Set the specific parent value so it doesn't have to look up the chain.
2426 				
2427 				foreach(Control ctrl; pc.ccollection)
2428 				{
2429 					ctrl.onRightToLeftChanged(EventArgs.empty);
2430 					
2431 					pa(ctrl);
2432 				}
2433 			}
2434 		}
2435 		
2436 		
2437 		pa(this);
2438 	}
2439 	
2440 	
2441 	///
2442 	@property void rightToLeft(RightToLeft val) // setter
2443 	{
2444 		if(rtol != val)
2445 		{
2446 			rtol = val;
2447 			onRightToLeftChanged(EventArgs.empty);
2448 			_propagateRtolAmbience(); // Also sets the class style and invalidates.
2449 		}
2450 	}
2451 	
2452 	/// ditto
2453 	// Returns YES or NO; if inherited, returns parent's setting.
2454 	@property RightToLeft rightToLeft() // getter
2455 	{
2456 		if(RightToLeft.INHERIT == rtol)
2457 		{
2458 			return parent ? parent.rightToLeft : RightToLeft.NO;
2459 		}
2460 		return rtol;
2461 	}
2462 	
2463 	
2464 	package struct _FixAmbientOld
2465 	{
2466 		Font font;
2467 		Cursor cursor;
2468 		Color backColor;
2469 		Color foreColor;
2470 		RightToLeft rightToLeft;
2471 		//CBits cbits;
2472 		bool enabled;
2473 		
2474 		
2475 		void set(Control ctrl)
2476 		{
2477 			if(ctrl)
2478 			{
2479 				font = ctrl.font;
2480 				cursor = ctrl.cursor;
2481 				backColor = ctrl.backColor;
2482 				foreColor = ctrl.foreColor;
2483 				rightToLeft = ctrl.rightToLeft;
2484 				//cbits = ctrl.cbits;
2485 				enabled = ctrl.enabled;
2486 			}
2487 			/+else
2488 			{
2489 				font = null;
2490 				cursor = null;
2491 				backColor = Color.empty;
2492 				foreColor = Color.empty;
2493 				rightToLeft = RightToLeft.INHERIT;
2494 				//cbits = CBits.init;
2495 				enabled = true;
2496 			}+/
2497 		}
2498 	}
2499 	
2500 	
2501 	// This is called when the inherited ambience changes.
2502 	package final void _fixAmbient(_FixAmbientOld* oldinfo)
2503 	{
2504 		// Note: exception will screw things up.
2505 		
2506 		_FixAmbientOld newinfo;
2507 		if(parent)
2508 			newinfo.set(parent);
2509 		else
2510 			newinfo.set(this);
2511 		
2512 		if(RightToLeft.INHERIT == rtol)
2513 		{
2514 			if(newinfo.rightToLeft !is oldinfo.rightToLeft)
2515 			{
2516 				onRightToLeftChanged(EventArgs.empty);
2517 				_propagateRtolAmbience();
2518 			}
2519 		}
2520 		
2521 		if(Color.empty == backc)
2522 		{
2523 			if(newinfo.backColor !is oldinfo.backColor)
2524 			{
2525 				onBackColorChanged(EventArgs.empty);
2526 				_propagateBackColorAmbience();
2527 			}
2528 		}
2529 		
2530 		if(Color.empty == forec)
2531 		{
2532 			if(newinfo.foreColor !is oldinfo.foreColor)
2533 			{
2534 				onForeColorChanged(EventArgs.empty);
2535 				_propagateForeColorAmbience();
2536 			}
2537 		}
2538 		
2539 		if(!wfont)
2540 		{
2541 			if(newinfo.font !is oldinfo.font)
2542 			{
2543 				onFontChanged(EventArgs.empty);
2544 				_propagateFontAmbience();
2545 			}
2546 		}
2547 		
2548 		if(!wcurs)
2549 		{
2550 			if(newinfo.cursor !is oldinfo.cursor)
2551 			{
2552 				onCursorChanged(EventArgs.empty);
2553 				_propagateCursorAmbience();
2554 			}
2555 		}
2556 		
2557 		/+
2558 		if(newinfo.enabled != oldinfo.enabled)
2559 		{
2560 			if(cbits & CBits.ENABLED)
2561 			{
2562 				_venabled(newinfo.enabled);
2563 				_propagateEnabledAmbience();
2564 			}
2565 		}
2566 		+/
2567 	}
2568 	
2569 	
2570 	/+
2571 	package final void _fixAmbientChildren()
2572 	{
2573 		foreach(Control ctrl; ccollection.children)
2574 		{
2575 			ctrl._fixAmbient();
2576 		}
2577 	}
2578 	+/
2579 	
2580 	
2581 	///
2582 	final @property void size(Size sz) // setter
2583 	{
2584 		/*
2585 		SetWindowPos(hwnd, HWND.init, 0, 0, sz.width, sz.height, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
2586 		*/
2587 		
2588 		setBoundsCore(0, 0, sz.width, sz.height, BoundsSpecified.SIZE);
2589 	}
2590 	
2591 	/// ditto
2592 	final @property Size size() // getter
2593 	{
2594 		return wrect.size; // struct Size, not sizeof.
2595 	}
2596 	
2597 	
2598 	/+
2599 	final @property void tabIndex(int i) // setter
2600 	{
2601 		// TODO: ?
2602 	}
2603 	
2604 	
2605 	final @property int tabIndex() // getter
2606 	{
2607 		return tabidx;
2608 	}
2609 	+/
2610 	
2611 	
2612 	// Use -zIndex- instead.
2613 	// -tabIndex- may return different values in the future.
2614 	deprecated int tabIndex() // getter
2615 	{
2616 		return zIndex;
2617 	}
2618 	
2619 	
2620 	///
2621 	final @property int zIndex() // getter
2622 	out(result)
2623 	{
2624 		assert(result >= 0);
2625 	}
2626 	body
2627 	{
2628 		if(!parent)
2629 			return 0;
2630 		
2631 		if(isHandleCreated)
2632 		{
2633 			GetZIndex gzi;
2634 			gzi.find = this;
2635 			int index;
2636 			int tmp;
2637 			
2638 			BOOL getZIndexCallback(HWND hWnd)
2639 			{
2640 				if(hWnd is hwnd)
2641 				{
2642 					index = tmp;
2643 					return FALSE; // Stop, found it.
2644 				}
2645 				
2646 				auto ctrl = Control.fromHandle(hWnd);
2647 				if(ctrl && ctrl.parent is parent)
2648 				{
2649 					tmp++;
2650 				}
2651 				
2652 				return TRUE; // Keep looking.
2653 			}
2654 			
2655 			enumChildWindows(parent.hwnd, &getZIndexCallback);
2656 			return index;
2657 		}
2658 		else
2659 		{
2660 			return parent.controls.indexOf(this);
2661 		}
2662 	}
2663 	
2664 	
2665 	///
2666 	// True if control can be tabbed to.
2667 	final @property void tabStop(bool byes) // setter
2668 	{
2669 		LONG wl = _style();
2670 		if(byes)
2671 			wl |= WS_TABSTOP;
2672 		else
2673 			wl &= ~WS_TABSTOP;
2674 		_style(wl);
2675 	}
2676 	
2677 	/// ditto
2678 	final @property bool tabStop() // getter
2679 	{
2680 		return (_style() & WS_TABSTOP) != 0;
2681 	}
2682 	
2683 	
2684 	/// Property: get or set additional data tagged onto the control.
2685 	final @property void tag(Object o) // setter
2686 	{
2687 		otag = o;
2688 	}
2689 	
2690 	/// ditto
2691 	final @property Object tag() // getter
2692 	{
2693 		return otag;
2694 	}
2695 	
2696 	
2697 	private final Dstring _fetchText()
2698 	{
2699 		return dfl.internal.utf.getWindowText(hwnd);
2700 	}
2701 	
2702 	
2703 	///
2704 	@property void text(Dstring txt) // setter
2705 	{
2706 		if(isHandleCreated)
2707 		{
2708 			if(ctrlStyle & ControlStyles.CACHE_TEXT)
2709 			{
2710 				//if(wtext == txt)
2711 				//	return;
2712 				wtext = txt;
2713 			}
2714 			
2715 			dfl.internal.utf.setWindowText(hwnd, txt);
2716 		}
2717 		else
2718 		{
2719 			wtext = txt;
2720 		}
2721 	}
2722 	
2723 	/// ditto
2724 	@property Dstring text() // getter
2725 	{
2726 		if(isHandleCreated)
2727 		{
2728 			if(ctrlStyle & ControlStyles.CACHE_TEXT)
2729 				return wtext;
2730 			
2731 			return _fetchText();
2732 		}
2733 		else
2734 		{
2735 			return wtext;
2736 		}
2737 	}
2738 	
2739 	
2740 	///
2741 	final @property void top(int t) // setter
2742 	{
2743 		setBoundsCore(0, t, 0, 0, BoundsSpecified.Y);
2744 	}
2745 	
2746 	/// ditto
2747 	final @property int top() // getter
2748 	{
2749 		return wrect.y;
2750 	}
2751 	
2752 	
2753 	/// Returns the topmost Control related to this control.
2754 	// Returns the owner control that has no parent.
2755 	// Returns this Control if no owner ?
2756 	final @property Control topLevelControl() // getter
2757 	{
2758 		if(isHandleCreated)
2759 		{
2760 			HWND hwCurrent = hwnd;
2761 			HWND hwParent;
2762 			
2763 			for(;;)
2764 			{
2765 				hwParent = GetParent(hwCurrent); // This gets the top-level one, whereas the previous code jumped owners.
2766 				if(!hwParent)
2767 					break;
2768 				
2769 				hwCurrent = hwParent;
2770 			}
2771 			
2772 			return fromHandle(hwCurrent);
2773 		}
2774 		else
2775 		{
2776 			Control ctrl;
2777 			ctrl = this;
2778 			while(ctrl.parent)
2779 			{
2780 				ctrl = ctrl.parent; // This shouldn't jump owners..
2781 			}
2782 			return ctrl;
2783 		}
2784 	}
2785 	
2786 	
2787 	/+
2788 	private DWORD _fetchVisible()
2789 	{
2790 		//return IsWindowVisible(hwnd) != FALSE;
2791 		wstyle = GetWindowLongA(hwnd, GWL_STYLE);
2792 		return wstyle & WS_VISIBLE;
2793 	}
2794 	+/
2795 	
2796 	
2797 	///
2798 	final @property void visible(bool byes) // setter
2799 	{
2800 		setVisibleCore(byes);
2801 	}
2802 	
2803 	/// ditto
2804 	final @property bool visible() // getter
2805 	{
2806 		//if(isHandleCreated)
2807 		//	wstyle = GetWindowLongA(hwnd, GWL_STYLE); // ...
2808 		//return (wstyle & WS_VISIBLE) != 0;
2809 		return (cbits & CBits.VISIBLE) != 0;
2810 	}
2811 	
2812 	
2813 	///
2814 	final @property void width(int w) // setter
2815 	{
2816 		setBoundsCore(0, 0, w, 0, BoundsSpecified.WIDTH);
2817 	}
2818 	
2819 	/// ditto
2820 	final @property int width() // getter
2821 	{
2822 		return wrect.width;
2823 	}
2824 	
2825 	
2826 	///
2827 	final void sendToBack()
2828 	{
2829 		if(!isHandleCreated)
2830 		{
2831 			if(parent)
2832 				parent.ccollection._simple_front(this);
2833 			return;
2834 		}
2835 		
2836 		SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2837 	}
2838 	
2839 	
2840 	///
2841 	final void bringToFront()
2842 	{
2843 		if(!isHandleCreated)
2844 		{
2845 			if(parent)
2846 				parent.ccollection._simple_back(this);
2847 			return;
2848 		}
2849 		
2850 		SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2851 		//BringWindowToTop(hwnd);
2852 	}
2853 	
2854 	
2855 	deprecated alias bringUpOne zIndexUp;
2856 	
2857 	///
2858 	// Move up one.
2859 	final void bringUpOne()
2860 	{
2861 		if(!isHandleCreated)
2862 		{
2863 			if(parent)
2864 				parent.ccollection._simple_front_one(this);
2865 			return;
2866 		}
2867 		
2868 		HWND hw;
2869 		
2870 		// Need to move back twice because the previous one already precedes this one.
2871 		hw = GetWindow(hwnd, GW_HWNDPREV);
2872 		if(!hw)
2873 		{
2874 			hw = HWND_TOP;
2875 		}
2876 		else
2877 		{
2878 			hw = GetWindow(hw, GW_HWNDPREV);
2879 			if(!hw)
2880 				hw = HWND_TOP;
2881 		}
2882 		
2883 		SetWindowPos(hwnd, hw, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2884 	}
2885 	
2886 	
2887 	deprecated alias sendBackOne zIndexDown;
2888 	
2889 	///
2890 	// Move back one.
2891 	final void sendBackOne()
2892 	{
2893 		if(!isHandleCreated)
2894 		{
2895 			if(parent)
2896 				parent.ccollection._simple_back_one(this);
2897 			return;
2898 		}
2899 		
2900 		HWND hw;
2901 		
2902 		hw = GetWindow(hwnd, GW_HWNDNEXT);
2903 		if(!hw)
2904 			hw = HWND_BOTTOM;
2905 		
2906 		SetWindowPos(hwnd, hw, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2907 	}
2908 	
2909 	
2910 	// Note: true if no children, even if this not created.
2911 	package final @property bool areChildrenCreated() // getter
2912 	{
2913 		return !ccollection.children.length;
2914 	}
2915 	
2916 	
2917 	package final void createChildren()
2918 	{
2919 		assert(isHandleCreated);
2920 		
2921 		Control[] ctrls;
2922 		ctrls = ccollection.children;
2923 		ccollection.children = null;
2924 		
2925 		foreach(Control ctrl; ctrls)
2926 		{
2927 			assert(ctrl.parent is this);
2928 			assert(!(ctrl is null));
2929 			assert(ctrl);
2930 			ctrl.createControl();
2931 		}
2932 	}
2933 	
2934 	
2935 	///
2936 	// Force creation of the window and its child controls.
2937 	final void createControl()
2938 	{
2939 		createHandle();
2940 		
2941 		// Called in WM_CREATE also.
2942 		createChildren();
2943 	}
2944 	
2945 	
2946 	/// Returns a new Graphics object for this control, creating the control handle if necessary.
2947 	final Graphics createGraphics()
2948 	{
2949 		HDC hdc = GetDC(handle); // Create handle as necessary.
2950 		SetTextColor(hdc, foreColor.toRgb());
2951 		return new CommonGraphics(hwnd, hdc);
2952 	}
2953 	
2954 	
2955 	version(DFL_NO_DRAG_DROP) {} else
2956 	{
2957 		private static class DropTarget: DflComObject, IDropTarget
2958 		{
2959 			this(Control ctrl)
2960 			{
2961 				this.ctrl = ctrl;
2962 			}
2963 			~this()
2964 			{
2965 				if (dataObj)
2966 				{
2967 					GC.removeRoot(cast(void*)dataObj);
2968 					destroy(dataObj);
2969 				}
2970 			}
2971 			
2972 			
2973 			extern(Windows):
2974 			override HRESULT QueryInterface(IID* riid, void** ppv)
2975 			{
2976 				if(*riid == _IID_IDropTarget)
2977 				{
2978 					*ppv = cast(void*)cast(IDropTarget)this;
2979 					AddRef();
2980 					return S_OK;
2981 				}
2982 				else if(*riid == _IID_IUnknown)
2983 				{
2984 					*ppv = cast(void*)cast(IUnknown)this;
2985 					AddRef();
2986 					return S_OK;
2987 				}
2988 				else
2989 				{
2990 					*ppv = null;
2991 					return E_NOINTERFACE;
2992 				}
2993 			}
2994 			
2995 			
2996 			HRESULT DragEnter(dfl.internal.wincom.IDataObject pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2997 			{
2998 				HRESULT result;
2999 				
3000 				try
3001 				{
3002 					//dataObj = new ComToDdataObject(pDataObject);
3003 					ensureDataObj(pDataObject);
3004 					
3005 					scope DragEventArgs ea = new DragEventArgs(dataObj, cast(int)grfKeyState, pt.x, pt.y, 
3006 						cast(DragDropEffects)*pdwEffect, DragDropEffects.NONE); // ?
3007 					ctrl.onDragEnter(ea);
3008 					*pdwEffect = ea.effect;
3009 					
3010 					result = S_OK;
3011 				}
3012 				catch(DThrowable e)
3013 				{
3014 					Application.onThreadException(e);
3015 					
3016 					result = E_UNEXPECTED;
3017 				}
3018 				
3019 				return result;
3020 			}
3021 			
3022 			
3023 			HRESULT DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3024 			{
3025 				HRESULT result;
3026 				
3027 				try
3028 				{
3029 					assert(dataObj !is null);
3030 					
3031 					scope DragEventArgs ea = new DragEventArgs(dataObj, cast(int)grfKeyState, pt.x, pt.y, 
3032 						cast(DragDropEffects)*pdwEffect, DragDropEffects.NONE); // ?
3033 					ctrl.onDragOver(ea);
3034 					*pdwEffect = ea.effect;
3035 					
3036 					result = S_OK;
3037 				}
3038 				catch(DThrowable e)
3039 				{
3040 					Application.onThreadException(e);
3041 					
3042 					result = E_UNEXPECTED;
3043 				}
3044 				
3045 				return result;
3046 			}
3047 			
3048 			
3049 			HRESULT DragLeave()
3050 			{
3051 				HRESULT result;
3052 				
3053 				try
3054 				{
3055 					ctrl.onDragLeave(EventArgs.empty);
3056 					
3057 					killDataObj();
3058 					
3059 					result = S_OK;
3060 				}
3061 				catch(DThrowable e)
3062 				{
3063 					Application.onThreadException(e);
3064 					
3065 					result = E_UNEXPECTED;
3066 				}
3067 				
3068 				return result;
3069 			}
3070 			
3071 			
3072 			HRESULT Drop(dfl.internal.wincom.IDataObject pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3073 			{
3074 				HRESULT result;
3075 				
3076 				try
3077 				{
3078 					//assert(dataObj !is null);
3079 					ensureDataObj(pDataObject);
3080 					
3081 					scope DragEventArgs ea = new DragEventArgs(dataObj, cast(int)grfKeyState, pt.x, pt.y, 
3082 						cast(DragDropEffects)*pdwEffect, DragDropEffects.NONE); // ?
3083 					ctrl.onDragDrop(ea);
3084 					*pdwEffect = ea.effect;
3085 					
3086 					result = S_OK;
3087 				}
3088 				catch(DThrowable e)
3089 				{
3090 					Application.onThreadException(e);
3091 					
3092 					result = E_UNEXPECTED;
3093 				}
3094 				
3095 				return result;
3096 			}
3097 			
3098 			
3099 			private:
3100 			
3101 			Control ctrl;
3102 			//dfl.data.IDataObject dataObj;
3103 			ComToDdataObject dataObj;
3104 			
3105 			
3106 			void ensureDataObj(dfl.internal.wincom.IDataObject pDataObject)
3107 			{
3108 				if(!dataObj)
3109 				{
3110 					dataObj = new ComToDdataObject(pDataObject);
3111 					GC.addRoot(cast(void*)dataObj);
3112 				}
3113 				else if (!dataObj.isSameDataObject(pDataObject))
3114 				{
3115 					GC.removeRoot(cast(void*)dataObj);
3116 					dataObj = new ComToDdataObject(pDataObject);
3117 					GC.addRoot(cast(void*)dataObj);
3118 				}
3119 			}
3120 			
3121 			
3122 			void killDataObj()
3123 			{
3124 				// Can't do this because the COM object might still need to be released elsewhere.
3125 				//delete dataObj;
3126 				//dataObj = null;
3127 			}
3128 		}
3129 		
3130 		
3131 		///
3132 		protected void onDragLeave(EventArgs ea)
3133 		{
3134 			dragLeave(this, ea);
3135 		}
3136 		
3137 		
3138 		///
3139 		protected void onDragEnter(DragEventArgs ea)
3140 		{
3141 			dragEnter(this, ea);
3142 		}
3143 		
3144 		
3145 		///
3146 		protected void onDragOver(DragEventArgs ea)
3147 		{
3148 			dragOver(this, ea);
3149 		}
3150 		
3151 		
3152 		///
3153 		protected void onDragDrop(DragEventArgs ea)
3154 		{
3155 			dragDrop(this, ea);
3156 		}
3157 		
3158 		
3159 		private static class DropSource: DflComObject, IDropSource
3160 		{
3161 			this(Control ctrl)
3162 			{
3163 				this.ctrl = ctrl;
3164 				mbtns = Control.mouseButtons;
3165 			}
3166 			
3167 			
3168 			extern(Windows):
3169 			override HRESULT QueryInterface(IID* riid, void** ppv)
3170 			{
3171 				if(*riid == _IID_IDropSource)
3172 				{
3173 					*ppv = cast(void*)cast(IDropSource)this;
3174 					AddRef();
3175 					return S_OK;
3176 				}
3177 				else if(*riid == _IID_IUnknown)
3178 				{
3179 					*ppv = cast(void*)cast(IUnknown)this;
3180 					AddRef();
3181 					return S_OK;
3182 				}
3183 				else
3184 				{
3185 					*ppv = null;
3186 					return E_NOINTERFACE;
3187 				}
3188 			}
3189 			
3190 			
3191 			HRESULT QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
3192 			{
3193 				HRESULT result;
3194 				
3195 				try
3196 				{
3197 					DragAction act;
3198 					
3199 					if(fEscapePressed)
3200 					{
3201 						act = cast(DragAction)DragAction.CANCEL;
3202 					}
3203 					else
3204 					{
3205 						if(mbtns & MouseButtons.LEFT)
3206 						{
3207 							if(!(grfKeyState & MK_LBUTTON))
3208 							{
3209 								act = cast(DragAction)DragAction.DROP;
3210 								goto qdoit;
3211 							}
3212 						}
3213 						else
3214 						{
3215 							if(grfKeyState & MK_LBUTTON)
3216 							{
3217 								act = cast(DragAction)DragAction.CANCEL;
3218 								goto qdoit;
3219 							}
3220 						}
3221 						if(mbtns & MouseButtons.RIGHT)
3222 						{
3223 							if(!(grfKeyState & MK_RBUTTON))
3224 							{
3225 								act = cast(DragAction)DragAction.DROP;
3226 								goto qdoit;
3227 							}
3228 						}
3229 						else
3230 						{
3231 							if(grfKeyState & MK_RBUTTON)
3232 							{
3233 								act = cast(DragAction)DragAction.CANCEL;
3234 								goto qdoit;
3235 							}
3236 						}
3237 						if(mbtns & MouseButtons.MIDDLE)
3238 						{
3239 							if(!(grfKeyState & MK_MBUTTON))
3240 							{
3241 								act = cast(DragAction)DragAction.DROP;
3242 								goto qdoit;
3243 							}
3244 						}
3245 						else
3246 						{
3247 							if(grfKeyState & MK_MBUTTON)
3248 							{
3249 								act = cast(DragAction)DragAction.CANCEL;
3250 								goto qdoit;
3251 							}
3252 						}
3253 						
3254 						act = cast(DragAction)DragAction.CONTINUE;
3255 					}
3256 					
3257 					qdoit:
3258 					scope QueryContinueDragEventArgs ea = new QueryContinueDragEventArgs(cast(int)grfKeyState,
3259 						fEscapePressed != FALSE, act); // ?
3260 					ctrl.onQueryContinueDrag(ea);
3261 					
3262 					result = cast(HRESULT)ea.action;
3263 				}
3264 				catch(DThrowable e)
3265 				{
3266 					Application.onThreadException(e);
3267 					
3268 					result = E_UNEXPECTED;
3269 				}
3270 				
3271 				return result;
3272 			}
3273 			
3274 			
3275 			HRESULT GiveFeedback(DWORD dwEffect)
3276 			{
3277 				HRESULT result;
3278 				
3279 				try
3280 				{
3281 					scope GiveFeedbackEventArgs ea = new GiveFeedbackEventArgs(cast(DragDropEffects)dwEffect, true);
3282 					ctrl.onGiveFeedback(ea);
3283 					
3284 					result = ea.useDefaultCursors ? DRAGDROP_S_USEDEFAULTCURSORS : S_OK;
3285 				}
3286 				catch(DThrowable e)
3287 				{
3288 					Application.onThreadException(e);
3289 					
3290 					result = E_UNEXPECTED;
3291 				}
3292 				
3293 				return result;
3294 			}
3295 			
3296 			
3297 			private:
3298 			Control ctrl;
3299 			MouseButtons mbtns;
3300 		}
3301 		
3302 		
3303 		///
3304 		protected void onQueryContinueDrag(QueryContinueDragEventArgs ea)
3305 		{
3306 			queryContinueDrag(this, ea);
3307 		}
3308 		
3309 		
3310 		///
3311 		protected void onGiveFeedback(GiveFeedbackEventArgs ea)
3312 		{
3313 			giveFeedback(this, ea);
3314 		}
3315 		
3316 		
3317 		/// Perform a drag/drop operation.
3318 		final DragDropEffects doDragDrop(dfl.data.IDataObject dataObj, DragDropEffects allowedEffects)
3319 		{
3320 			Object foo = cast(Object)dataObj; // Hold a reference to the Object...
3321 			
3322 			DWORD effect;
3323 			DropSource dropsrc;
3324 			dfl.internal.wincom.IDataObject dropdata;
3325 			
3326 			dropsrc = new DropSource(this);
3327 			dropdata = new DtoComDataObject(dataObj);
3328 			
3329 			// dataObj seems to be killed too early.
3330 			switch(DoDragDrop(dropdata, dropsrc, cast(DWORD)allowedEffects, &effect))
3331 			{
3332 				case DRAGDROP_S_DROP: // All good.
3333 					break;
3334 				
3335 				case DRAGDROP_S_CANCEL:
3336 					return DragDropEffects.NONE; // ?
3337 				
3338 				default:
3339 					throw new DflException("Unable to complete drag-drop operation");
3340 			}
3341 			
3342 			return cast(DragDropEffects)effect;
3343 		}
3344 		
3345 		/// ditto
3346 		final DragDropEffects doDragDrop(Data obj, DragDropEffects allowedEffects)
3347 		{
3348 			dfl.data.IDataObject dd;
3349 			dd = new DataObject;
3350 			dd.setData(obj);
3351 			return doDragDrop(dd, allowedEffects);
3352 		}
3353 	}
3354 	
3355 	
3356 	override Dequ opEquals(Object o)
3357 	{
3358 		Control ctrl = cast(Control)o;
3359 		if(!ctrl)
3360 			return 0; // Not equal.
3361 		return opEquals(ctrl);
3362 	}
3363 	
3364 	
3365 	Dequ opEquals(Control ctrl)
3366 	{
3367 		if(!isHandleCreated)
3368 			return super.opEquals(ctrl);
3369 		return hwnd == ctrl.hwnd;
3370 	}
3371 	
3372 	
3373 	override int opCmp(Object o)
3374 	{
3375 		Control ctrl = cast(Control)o;
3376 		if(!ctrl)
3377 			return -1;
3378 		return opCmp(ctrl);
3379 	}
3380 	
3381 	
3382 	int opCmp(Control ctrl)
3383 	{
3384 		if(!isHandleCreated || hwnd != ctrl.hwnd)
3385 			return super.opCmp(ctrl);
3386 		return 0;
3387 	}
3388 	
3389 	
3390 	///
3391 	final bool focus()
3392 	{
3393 		return SetFocus(hwnd) != HWND.init;
3394 	}
3395 	
3396 	
3397 	/// Returns the Control instance from one of its window handles, or null if none.
3398 	// Finds controls that own more than one handle.
3399 	// A combo box has several HWNDs, this would return the
3400 	// correct combo box control if any of those handles are
3401 	// provided.
3402 	static Control fromChildHandle(HWND hwChild)
3403 	{
3404 		Control result;
3405 		for(;;)
3406 		{
3407 			if(!hwChild)
3408 				return null;
3409 			
3410 			result = fromHandle(hwChild);
3411 			if(result)
3412 				return result;
3413 			
3414 			hwChild = GetParent(hwChild);
3415 		}
3416 	}
3417 	
3418 	
3419 	/// Returns the Control instance from its window handle, or null if none.
3420 	static Control fromHandle(HWND hw)
3421 	{
3422 		return Application.lookupHwnd(hw);
3423 	}
3424 	
3425 	
3426 	///
3427 	final Control getChildAtPoint(Point pt)
3428 	{
3429 		HWND hwChild;
3430 		hwChild = ChildWindowFromPoint(hwnd, pt.point);
3431 		if(!hwChild)
3432 			return null;
3433 		return fromChildHandle(hwChild);
3434 	}
3435 	
3436 	
3437 	///
3438 	final void hide()
3439 	{
3440 		setVisibleCore(false);
3441 	}
3442 	
3443 	/// ditto
3444 	final void show()
3445 	{
3446 		/*
3447 		ShowWindow(hwnd, SW_SHOW);
3448 		doShow();
3449 		*/
3450 		
3451 		setVisibleCore(true);
3452 	}
3453 	
3454 	
3455 	package final void redrawEntire()
3456 	{
3457 		if(hwnd)
3458 		{
3459 			SetWindowPos(hwnd, HWND.init, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_DRAWFRAME | SWP_NOMOVE
3460 				| SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
3461 		}
3462 	}
3463 	
3464 	
3465 	package final void recalcEntire()
3466 	{
3467 		if(hwnd)
3468 		{
3469 			SetWindowPos(hwnd, HWND.init, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE
3470 				| SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
3471 		}
3472 	}
3473 	
3474 	
3475 	///
3476 	final void invalidate()
3477 	{
3478 		if(!hwnd)
3479 			return;
3480 		
3481 		RedrawWindow(hwnd, null, HRGN.init, RDW_ERASE | RDW_INVALIDATE | RDW_NOCHILDREN);
3482 	}
3483 	
3484 	/// ditto
3485 	final void invalidate(bool andChildren)
3486 	{
3487 		if(!hwnd)
3488 			return;
3489 		
3490 		RedrawWindow(hwnd, null, HRGN.init, RDW_ERASE | RDW_INVALIDATE | (andChildren ? RDW_ALLCHILDREN : RDW_NOCHILDREN));
3491 	}
3492 	
3493 	/// ditto
3494 	final void invalidate(Rect r)
3495 	{
3496 		if(!hwnd)
3497 			return;
3498 		
3499 		RECT rect;
3500 		r.getRect(&rect);
3501 		
3502 		RedrawWindow(hwnd, &rect, HRGN.init, RDW_ERASE | RDW_INVALIDATE | RDW_NOCHILDREN);
3503 	}
3504 	
3505 	/// ditto
3506 	final void invalidate(Rect r, bool andChildren)
3507 	{
3508 		if(!hwnd)
3509 			return;
3510 		
3511 		RECT rect;
3512 		r.getRect(&rect);
3513 		
3514 		RedrawWindow(hwnd, &rect, HRGN.init, RDW_ERASE | RDW_INVALIDATE | (andChildren ? RDW_ALLCHILDREN : RDW_NOCHILDREN));
3515 	}
3516 	
3517 	/// ditto
3518 	final void invalidate(Region rgn)
3519 	{
3520 		if(!hwnd)
3521 			return;
3522 		
3523 		RedrawWindow(hwnd, null, rgn.handle, RDW_ERASE | RDW_INVALIDATE | RDW_NOCHILDREN);
3524 	}
3525 	
3526 	/// ditto
3527 	final void invalidate(Region rgn, bool andChildren)
3528 	{
3529 		if(!hwnd)
3530 			return;
3531 		
3532 		RedrawWindow(hwnd, null, rgn.handle, RDW_ERASE | RDW_INVALIDATE | (andChildren ? RDW_ALLCHILDREN : RDW_NOCHILDREN));
3533 	}
3534 	
3535 	
3536 	///
3537 	// Redraws the entire control, including nonclient area.
3538 	final void redraw()
3539 	{
3540 		if(!hwnd)
3541 			return;
3542 		
3543 		RedrawWindow(hwnd, null, HRGN.init, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME);
3544 	}
3545 	
3546 	
3547 	/// Returns true if the window does not belong to the current thread.
3548 	@property bool invokeRequired() // getter
3549 	{
3550 		DWORD tid = GetWindowThreadProcessId(hwnd, null);
3551 		return tid != GetCurrentThreadId();
3552 	}
3553 	
3554 	
3555 	private static void badInvokeHandle()
3556 	{
3557 		//throw new DflException("Must invoke after creating handle");
3558 		throw new DflException("Must invoke with created handle");
3559 	}
3560 	
3561 	
3562 	/// Synchronously calls a delegate in this Control's thread. This function is thread safe and exceptions are propagated to the caller.
3563 	// Exceptions are propagated back to the caller of invoke().
3564 	final Object invoke(Object delegate(Object[]) dg, Object[] args ...)
3565 	{
3566 		if(!hwnd)
3567 			badInvokeHandle();
3568 		
3569 		InvokeData inv;
3570 		inv.dg = dg;
3571 		inv.args = args;
3572 		
3573 		if(LRESULT_DFL_INVOKE != SendMessageA(hwnd, wmDfl, WPARAM_DFL_INVOKE, cast(LRESULT)&inv))
3574 			throw new DflException("Invoke failure");
3575 		if(inv.exception)
3576 			throw inv.exception;
3577 		
3578 		return inv.result;
3579 	}
3580 	
3581 	/// ditto
3582 	final void invoke(void delegate() dg)
3583 	{
3584 		if(!hwnd)
3585 			badInvokeHandle();
3586 		
3587 		InvokeSimpleData inv;
3588 		inv.dg = dg;
3589 		
3590 		if(LRESULT_DFL_INVOKE != SendMessageA(hwnd, wmDfl, WPARAM_DFL_INVOKE_SIMPLE, cast(LRESULT)&inv))
3591 			throw new DflException("Invoke failure");
3592 		if(inv.exception)
3593 			throw inv.exception;
3594 	}
3595 	
3596 	
3597 	/** Asynchronously calls a function after the window message queue processes its current messages.
3598 	    It is generally not safe to pass references to the delayed function.
3599 	    Exceptions are not propagated to the caller.
3600 	**/
3601 	// Extra.
3602 	// Exceptions will be passed to Application.onThreadException() and
3603 	// trigger the threadException event or the default exception dialog.
3604 	final void delayInvoke(void function() fn)
3605 	{
3606 		if(!hwnd)
3607 			badInvokeHandle();
3608 		
3609 		assert(!invokeRequired);
3610 		
3611 		static assert(fn.sizeof <= LPARAM.sizeof);
3612 		PostMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE, cast(LPARAM)fn);
3613 	}
3614 	
3615 	/// ditto
3616 	// Extra.
3617 	// Exceptions will be passed to Application.onThreadException() and
3618 	// trigger the threadException event or the default exception dialog.
3619 	// Copy of params are passed to fn, they do not exist after it returns.
3620 	// It is unsafe to pass references to a delayed function.
3621 	final void delayInvoke(void function(Control, size_t[]) fn, size_t[] params ...)
3622 	{
3623 		if(!hwnd)
3624 			badInvokeHandle();
3625 		
3626 		assert(!invokeRequired);
3627 		
3628 		static assert((DflInvokeParam*).sizeof <= LPARAM.sizeof);
3629 		
3630 		DflInvokeParam* p;
3631 		p = cast(DflInvokeParam*)dfl.internal.clib.malloc(
3632 			(DflInvokeParam.sizeof - size_t.sizeof)
3633 				+ params.length * size_t.sizeof);
3634 		if(!p)
3635 			throw new OomException();
3636 		
3637 		p.fp = fn;
3638 		p.nparams = params.length;
3639 		p.params.ptr[0 .. params.length] = params[];
3640 		
3641 		PostMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, cast(LPARAM)p);
3642 	}
3643 	
3644 	deprecated alias delayInvoke beginInvoke;
3645 	
3646 	
3647 	///
3648 	static bool isMnemonic(dchar charCode, Dstring text)
3649 	{
3650 		uint ui;
3651 		for(ui = 0; ui != text.length; ui++)
3652 		{
3653 			if('&' == text[ui])
3654 			{
3655 				if(++ui == text.length)
3656 					break;
3657 				if('&' == text[ui]) // && means literal & so skip it.
3658 					continue;
3659 				dchar dch;
3660 				dch = utf8stringGetUtf32char(text, ui);
3661 				return utf32charToLower(charCode) == utf32charToLower(dch);
3662 			}
3663 		}
3664 		return false;
3665 	}
3666 	
3667 	
3668 	/// Converts a screen Point to a client Point.
3669 	final Point pointToClient(Point pt)
3670 	{
3671 		ScreenToClient(hwnd, &pt.point);
3672 		return pt;
3673 	}
3674 	
3675 	
3676 	/// Converts a client Point to a screen Point.
3677 	final Point pointToScreen(Point pt)
3678 	{
3679 		ClientToScreen(hwnd, &pt.point);
3680 		return pt;
3681 	}
3682 	
3683 	
3684 	/// Converts a screen Rectangle to a client Rectangle.
3685 	final Rect rectangleToClient(Rect r)
3686 	{
3687 		RECT rect;
3688 		r.getRect(&rect);
3689 		
3690 		MapWindowPoints(HWND.init, hwnd, cast(POINT*)&rect, 2);
3691 		return Rect(&rect);
3692 	}
3693 	
3694 	
3695 	/// Converts a client Rectangle to a screen Rectangle.
3696 	final Rect rectangleToScreen(Rect r)
3697 	{
3698 		RECT rect;
3699 		r.getRect(&rect);
3700 		
3701 		MapWindowPoints(hwnd, HWND.init, cast(POINT*)&rect, 2);
3702 		return Rect(&rect);
3703 	}
3704 	
3705 	
3706 	///
3707 	// Return true if processed.
3708 	bool preProcessMessage(ref Message msg)
3709 	{
3710 		return false;
3711 	}
3712 	
3713 	
3714 	///
3715 	final Size getAutoScaleSize(Font f)
3716 	{
3717 		Size result;
3718 		Graphics g;
3719 		g = createGraphics();
3720 		result = g.getScaleSize(f);
3721 		g.dispose();
3722 		return result;
3723 	}
3724 	
3725 	/// ditto
3726 	final Size getAutoScaleSize()
3727 	{
3728 		return getAutoScaleSize(font);
3729 	}
3730 	
3731 	
3732 	///
3733 	void refresh()
3734 	{
3735 		invalidate(true);
3736 	}
3737 	
3738 	
3739 	///
3740 	void resetBackColor()
3741 	{
3742 		//backColor = defaultBackColor;
3743 		backColor = Color.empty;
3744 	}
3745 	
3746 	
3747 	///
3748 	void resetCursor()
3749 	{
3750 		//cursor = new Cursor(LoadCursorA(HINSTANCE.init, IDC_ARROW), false);
3751 		cursor = null;
3752 	}
3753 	
3754 	
3755 	///
3756 	void resetFont()
3757 	{
3758 		//font = defaultFont;
3759 		font = null;
3760 	}
3761 	
3762 	
3763 	///
3764 	void resetForeColor()
3765 	{
3766 		//foreColor = defaultForeColor;
3767 		foreColor = Color.empty;
3768 	}
3769 	
3770 	
3771 	///
3772 	void resetRightToLeft()
3773 	{
3774 		//rightToLeft = false;
3775 		rightToLeft = RightToLeft.INHERIT;
3776 	}
3777 	
3778 	
3779 	///
3780 	void resetText()
3781 	{
3782 		//text = "";
3783 		text = null;
3784 	}
3785 	
3786 	
3787 	///
3788 	// Just allow layout recalc, but don't do it right now.
3789 	final void resumeLayout()
3790 	{
3791 		//_allowLayout = true;
3792 		if(_disallowLayout)
3793 			_disallowLayout--;
3794 	}
3795 	
3796 	/// ditto
3797 	// Allow layout recalc, only do it now if -byes- is true.
3798 	final void resumeLayout(bool byes)
3799 	{
3800 		if(_disallowLayout)
3801 			_disallowLayout--;
3802 		
3803 		// This is correct.
3804 		if(byes)
3805 		{
3806 			if(!_disallowLayout)
3807 				alayout(null);
3808 		}
3809 	}
3810 	
3811 	
3812 	///
3813 	final void suspendLayout()
3814 	{
3815 		//_allowLayout = false;
3816 		_disallowLayout++;
3817 	}
3818 	
3819 	
3820 	final void performLayout(Control affectedControl)
3821 	{
3822 		alayout(affectedControl, false);
3823 	}
3824 	
3825 	
3826 	final void performLayout()
3827 	{
3828 		return performLayout(this);
3829 	}
3830 	
3831 	
3832 	/+
3833 	// TODO: implement.
3834 	
3835 	// Scale both height and width to -ratio-.
3836 	final void scale(float ratio)
3837 	{
3838 		scaleCore(ratio, ratio);
3839 	}
3840 	
3841 	
3842 	// Scale -width- and -height- ratios.
3843 	final void scale(float width, float height)
3844 	{
3845 		scaleCore(width, height);
3846 	}
3847 	
3848 	
3849 	// Also scales child controls recursively.
3850 	protected void scaleCore(float width, float height)
3851 	{
3852 		suspendLayout();
3853 		
3854 		// ...
3855 		
3856 		resumeLayout();
3857 	}
3858 	+/
3859 	
3860 	
3861 	private static bool _eachild(HWND hw, bool delegate(HWND hw) callback, ref size_t xiter, bool nested)
3862 	{
3863 		for(; hw; hw = GetWindow(hw, GW_HWNDNEXT))
3864 		{
3865 			if(!xiter)
3866 				return false;
3867 			xiter--;
3868 			
3869 			LONG st = GetWindowLongA(hw, GWL_STYLE);
3870 			if(!(st & WS_VISIBLE))
3871 				continue;
3872 			if(st & WS_DISABLED)
3873 				continue;
3874 			
3875 			if(!callback(hw))
3876 				return false;
3877 			
3878 			if(nested)
3879 			{
3880 				//LONG exst = GetWindowLongA(hw, GWL_EXSTYLE);
3881 				//if(exst & WS_EX_CONTROLPARENT) // It's no longer added.
3882 				{
3883 					HWND hwc = GetWindow(hw, GW_CHILD);
3884 					if(hwc)
3885 					{
3886 						//if(!_eachild(hwc, callback, xiter, nested))
3887 						if(!_eachild(hwc, callback, xiter, true))
3888 							return false;
3889 					}
3890 				}
3891 			}
3892 		}
3893 		return true;
3894 	}
3895 	
3896 	package static void eachGoodChildHandle(HWND hwparent, bool delegate(HWND hw) callback, bool nested = true)
3897 	{
3898 		HWND hw = GetWindow(hwparent, GW_CHILD);
3899 		size_t xiter = 2000;
3900 		_eachild(hw, callback, xiter, nested);
3901 	}
3902 	
3903 	
3904 	private static bool _isHwndControlSel(HWND hw)
3905 	{
3906 		Control c = Control.fromHandle(hw);
3907 		return c && c.getStyle(ControlStyles.SELECTABLE);
3908 	}
3909 	
3910 	
3911 	package static void _dlgselnext(Form dlg, HWND hwcursel, bool forward,
3912 		bool tabStopOnly = true, bool selectableOnly = false,
3913 		bool nested = true, bool wrap = true,
3914 		HWND hwchildrenof = null)
3915 	{
3916 		//assert(cast(Form)Control.fromHandle(hwdlg) !is null);
3917 		
3918 		if(!hwchildrenof)
3919 			hwchildrenof = dlg.handle;
3920 		if(forward)
3921 		{
3922 			bool foundthis = false, tdone = false;
3923 			HWND hwfirst;
3924 			eachGoodChildHandle(hwchildrenof,
3925 				(HWND hw)
3926 				{
3927 					assert(!tdone);
3928 					if(hw == hwcursel)
3929 					{
3930 						foundthis = true;
3931 					}
3932 					else
3933 					{
3934 						if(!tabStopOnly || (GetWindowLongA(hw, GWL_STYLE) & WS_TABSTOP))
3935 						{
3936 							if(!selectableOnly || _isHwndControlSel(hw))
3937 							{
3938 								if(foundthis)
3939 								{
3940 									//DefDlgProcA(dlg.handle, WM_NEXTDLGCTL, cast(WPARAM)hw, MAKELPARAM(true, 0));
3941 									dlg._selectChild(hw);
3942 									tdone = true;
3943 									return false; // Break.
3944 								}
3945 								else
3946 								{
3947 									if(HWND.init == hwfirst)
3948 										hwfirst = hw;
3949 								}
3950 							}
3951 						}
3952 					}
3953 					return true; // Continue.
3954 				}, nested);
3955 			if(!tdone && HWND.init != hwfirst)
3956 			{
3957 				// If it falls through without finding hwcursel, let it select the first one, even if not wrapping.
3958 				if(wrap || !foundthis)
3959 				{
3960 					//DefDlgProcA(dlg.handle, WM_NEXTDLGCTL, cast(WPARAM)hwfirst, MAKELPARAM(true, 0));
3961 					dlg._selectChild(hwfirst);
3962 				}
3963 			}
3964 		}
3965 		else
3966 		{
3967 			HWND hwprev;
3968 			eachGoodChildHandle(hwchildrenof,
3969 				(HWND hw)
3970 				{
3971 					if(hw == hwcursel)
3972 					{
3973 						if(HWND.init != hwprev) // Otherwise, keep looping and get last one.
3974 							return false; // Break.
3975 						if(!wrap) // No wrapping, so don't get last one.
3976 						{
3977 							assert(HWND.init == hwprev);
3978 							return false; // Break.
3979 						}
3980 					}
3981 					if(!tabStopOnly || (GetWindowLongA(hw, GWL_STYLE) & WS_TABSTOP))
3982 					{
3983 						if(!selectableOnly || _isHwndControlSel(hw))
3984 						{
3985 							hwprev = hw;
3986 						}
3987 					}
3988 					return true; // Continue.
3989 				}, nested);
3990 			// If it falls through without finding hwcursel, let it select the last one, even if not wrapping.
3991 			if(HWND.init != hwprev)
3992 				//DefDlgProcA(dlg.handle, WM_NEXTDLGCTL, cast(WPARAM)hwprev, MAKELPARAM(true, 0));
3993 				dlg._selectChild(hwprev);
3994 		}
3995 	}
3996 	
3997 	
3998 	package final void _selectNextControl(Form ctrltoplevel,
3999 		Control ctrl, bool forward, bool tabStopOnly, bool nested, bool wrap)
4000 	{
4001 		if(!created)
4002 			return;
4003 		
4004 		assert(ctrltoplevel !is null);
4005 		assert(ctrltoplevel.isHandleCreated);
4006 		
4007 		_dlgselnext(ctrltoplevel,
4008 			(ctrl && ctrl.isHandleCreated) ? ctrl.handle : null,
4009 			forward, tabStopOnly, !tabStopOnly, nested, wrap,
4010 			this.handle);
4011 	}
4012 	
4013 	
4014 	package final void _selectThisControl()
4015 	{
4016 		
4017 	}
4018 	
4019 	
4020 	// Only considers child controls of this control.
4021 	final void selectNextControl(Control ctrl, bool forward, bool tabStopOnly, bool nested, bool wrap)
4022 	{
4023 		if(!created)
4024 			return;
4025 		
4026 		auto ctrltoplevel = findForm();
4027 		if(ctrltoplevel)
4028 			return _selectNextControl(ctrltoplevel, ctrl, forward, tabStopOnly, nested, wrap);
4029 	}
4030 	
4031 	
4032 	///
4033 	final void select()
4034 	{
4035 		select(false, false);
4036 	}
4037 	
4038 	/// ditto
4039 	// If -directed- is true, -forward- is used; otherwise, selects this control.
4040 	// If -forward- is true, the next control in the tab order is selected,
4041 	// otherwise the previous control in the tab order is selected.
4042 	// Controls without style ControlStyles.SELECTABLE are skipped.
4043 	void select(bool directed, bool forward)
4044 	{
4045 		if(!created)
4046 			return;
4047 		
4048 		auto ctrltoplevel = findForm();
4049 		if(ctrltoplevel && ctrltoplevel !is this)
4050 		{
4051 			/+ // Old...
4052 			// Even if directed, ensure THIS one is selected first.
4053 			if(!directed || hwnd != GetFocus())
4054 			{
4055 				DefDlgProcA(ctrltoplevel.handle, WM_NEXTDLGCTL, cast(WPARAM)hwnd, MAKELPARAM(true, 0));
4056 			}
4057 			
4058 			if(directed)
4059 			{
4060 				DefDlgProcA(ctrltoplevel.handle, WM_NEXTDLGCTL, !forward, MAKELPARAM(false, 0));
4061 			}
4062 			+/
4063 			
4064 			if(directed)
4065 			{
4066 				_dlgselnext(ctrltoplevel, this.handle, forward);
4067 			}
4068 			else
4069 			{
4070 				ctrltoplevel._selectChild(this);
4071 			}
4072 		}
4073 		else
4074 		{
4075 			focus(); // This must be a form so just focus it ?
4076 		}
4077 	}
4078 	
4079 	
4080 	///
4081 	final void setBounds(int x, int y, int width, int height)
4082 	{
4083 		setBoundsCore(x, y, width, height, BoundsSpecified.ALL);
4084 	}
4085 	
4086 	/// ditto
4087 	final void setBounds(int x, int y, int width, int height, BoundsSpecified specified)
4088 	{
4089 		setBoundsCore(x, y, width, height, specified);
4090 	}
4091 	
4092 	
4093 	override Dstring toString()
4094 	{
4095 		return text;
4096 	}
4097 	
4098 	
4099 	///
4100 	final void update()
4101 	{
4102 		if(!created)
4103 			return;
4104 		
4105 		UpdateWindow(hwnd);
4106 	}
4107 	
4108 	
4109 	///
4110 	// If mouseEnter, mouseHover and mouseLeave events are supported.
4111 	// Returns true on Windows 95 with IE 5.5, Windows 98+ or Windows NT 4.0+.
4112 	static @property bool supportsMouseTracking() // getter
4113 	{
4114 		return trackMouseEvent != null;
4115 	}
4116 	
4117 	
4118 	package final Rect _fetchBounds()
4119 	{
4120 		RECT r;
4121 		GetWindowRect(hwnd, &r);
4122 		HWND hwParent = GetParent(hwnd);
4123 		if(hwParent && (_style() & WS_CHILD))
4124 			MapWindowPoints(HWND.init, hwParent, cast(POINT*)&r, 2);
4125 		return Rect(&r);
4126 	}
4127 	
4128 	
4129 	package final Size _fetchClientSize()
4130 	{
4131 		RECT r;
4132 		GetClientRect(hwnd, &r);
4133 		return Size(r.right, r.bottom);
4134 	}
4135 	
4136 	
4137 	deprecated protected void onInvalidated(InvalidateEventArgs iea)
4138 	{
4139 		//invalidated(this, iea);
4140 	}
4141 	
4142 	
4143 	///
4144 	protected void onPaint(PaintEventArgs pea)
4145 	{
4146 		paint(this, pea);
4147 	}
4148 	
4149 	
4150 	///
4151 	protected void onMove(EventArgs ea)
4152 	{
4153 		move(this, ea);
4154 	}
4155 	
4156 	
4157 	/+
4158 	protected void onLocationChanged(EventArgs ea)
4159 	{
4160 		locationChanged(this, ea);
4161 	}
4162 	+/
4163 	alias onMove onLocationChanged;
4164 	
4165 	
4166 	///
4167 	protected void onResize(EventArgs ea)
4168 	{
4169 		resize(this, ea);
4170 	}
4171 	
4172 	
4173 	/+
4174 	protected void onSizeChanged(EventArgs ea)
4175 	{
4176 		sizeChanged(this, ea);
4177 	}
4178 	+/
4179 	alias onResize onSizeChanged;
4180 	
4181 	
4182 	/+
4183 	// ///
4184 	// Allows comparing before and after dimensions, and also allows modifying the new dimensions.
4185 	deprecated protected void onBeforeResize(BeforeResizeEventArgs ea)
4186 	{
4187 	}
4188 	+/
4189 	
4190 	
4191 	///
4192 	protected void onMouseEnter(MouseEventArgs mea)
4193 	{
4194 		mouseEnter(this, mea);
4195 	}
4196 	
4197 	
4198 	///
4199 	protected void onMouseMove(MouseEventArgs mea)
4200 	{
4201 		mouseMove(this, mea);
4202 	}
4203 	
4204 	
4205 	///
4206 	protected void onKeyDown(KeyEventArgs kea)
4207 	{
4208 		keyDown(this, kea);
4209 	}
4210 	
4211 	
4212 	///
4213 	protected void onKeyPress(KeyPressEventArgs kea)
4214 	{
4215 		keyPress(this, kea);
4216 	}
4217 	
4218 	
4219 	///
4220 	protected void onKeyUp(KeyEventArgs kea)
4221 	{
4222 		keyUp(this, kea);
4223 	}
4224 	
4225 	
4226 	///
4227 	protected void onMouseWheel(MouseEventArgs mea)
4228 	{
4229 		mouseWheel(this, mea);
4230 	}
4231 	
4232 	
4233 	///
4234 	protected void onMouseHover(MouseEventArgs mea)
4235 	{
4236 		mouseHover(this, mea);
4237 	}
4238 	
4239 	
4240 	///
4241 	protected void onMouseLeave(MouseEventArgs mea)
4242 	{
4243 		mouseLeave(this, mea);
4244 	}
4245 	
4246 	
4247 	///
4248 	protected void onMouseDown(MouseEventArgs mea)
4249 	{
4250 		mouseDown(this, mea);
4251 	}
4252 	
4253 	
4254 	///
4255 	protected void onMouseUp(MouseEventArgs mea)
4256 	{
4257 		mouseUp(this, mea);
4258 	}
4259 	
4260 	
4261 	///
4262 	protected void onClick(EventArgs ea)
4263 	{
4264 		click(this, ea);
4265 	}
4266 	
4267 	
4268 	///
4269 	protected void onDoubleClick(EventArgs ea)
4270 	{
4271 		doubleClick(this, ea);
4272 	}
4273 	
4274 	
4275 	///
4276 	protected void onGotFocus(EventArgs ea)
4277 	{
4278 		gotFocus(this, ea);
4279 	}
4280 	
4281 	
4282 	/+
4283 	deprecated protected void onEnter(EventArgs ea)
4284 	{
4285 		//enter(this, ea);
4286 	}
4287 	
4288 	
4289 	deprecated protected void onLeave(EventArgs ea)
4290 	{
4291 		//leave(this, ea);
4292 	}
4293 	
4294 	
4295 	deprecated protected void onValidated(EventArgs ea)
4296 	{
4297 		//validated(this, ea);
4298 	}
4299 	
4300 	
4301 	deprecated protected void onValidating(CancelEventArgs cea)
4302 	{
4303 		/+
4304 		foreach(CancelEventHandler.Handler handler; validating.handlers())
4305 		{
4306 			handler(this, cea);
4307 			
4308 			if(cea.cancel)
4309 				return; // Not validated.
4310 		}
4311 		
4312 		onValidated(EventArgs.empty);
4313 		+/
4314 	}
4315 	+/
4316 	
4317 	
4318 	///
4319 	protected void onLostFocus(EventArgs ea)
4320 	{
4321 		lostFocus(this, ea);
4322 	}
4323 	
4324 	
4325 	///
4326 	protected void onEnabledChanged(EventArgs ea)
4327 	{
4328 		enabledChanged(this, ea);
4329 	}
4330 	
4331 	
4332 	///
4333 	protected void onTextChanged(EventArgs ea)
4334 	{
4335 		textChanged(this, ea);
4336 	}
4337 	
4338 	
4339 	private void _propagateFontAmbience()
4340 	{
4341 		Font fon;
4342 		fon = font;
4343 		
4344 		
4345 		void pa(Control pc)
4346 		{
4347 			foreach(Control ctrl; pc.ccollection)
4348 			{
4349 				if(!ctrl.wfont) // If default.
4350 				{
4351 					if(fon is ctrl.font) // If same default.
4352 					{
4353 						if(ctrl.isHandleCreated)
4354 							SendMessageA(ctrl.hwnd, WM_SETFONT, cast(WPARAM)fon.handle, MAKELPARAM(true, 0));
4355 						ctrl.onFontChanged(EventArgs.empty);
4356 						
4357 						pa(ctrl); // Recursive.
4358 					}
4359 				}
4360 			}
4361 		}
4362 		
4363 		
4364 		pa(this);
4365 	}
4366 	
4367 	
4368 	///
4369 	protected void onFontChanged(EventArgs ea)
4370 	{
4371 		debug(EVENT_PRINT)
4372 		{
4373 			cprintf("{ Event: onFontChanged - Control %.*s }\n", name);
4374 		}
4375 		
4376 		fontChanged(this, ea);
4377 	}
4378 	
4379 	
4380 	///
4381 	protected void onRightToLeftChanged(EventArgs ea)
4382 	{
4383 		debug(EVENT_PRINT)
4384 		{
4385 			cprintf("{ Event: onRightToLeftChanged - Control %.*s }\n", name);
4386 		}
4387 		
4388 		rightToLeftChanged(this, ea);
4389 	}
4390 	
4391 	
4392 	///
4393 	protected void onVisibleChanged(EventArgs ea)
4394 	{
4395 		if(wparent)
4396 		{
4397 			wparent.vchanged();
4398 			suspendLayout(); // Note: exception could cause failure to restore.
4399 			wparent.alayout(this);
4400 			resumeLayout(false);
4401 		}
4402 		if(visible)
4403 			alayout(this);
4404 		
4405 		visibleChanged(this, ea);
4406 		
4407 		if(visible)
4408 		{
4409 			// If no focus or the focused control is hidden, try to select something...
4410 			HWND hwfocus = GetFocus();
4411 			if(!hwfocus
4412 				|| (hwfocus == hwnd && !getStyle(ControlStyles.SELECTABLE))
4413 				|| !IsWindowVisible(hwfocus))
4414 			{
4415 				selectNextControl(null, true, true, true, false);
4416 			}
4417 		}
4418 	}
4419 	
4420 	
4421 	///
4422 	protected void onHelpRequested(HelpEventArgs hea)
4423 	{
4424 		debug(EVENT_PRINT)
4425 		{
4426 			cprintf("{ Event: onHelpRequested - Control %.*s }\n", name);
4427 		}
4428 		
4429 		helpRequested(this, hea);
4430 	}
4431 	
4432 	
4433 	///
4434 	protected void onSystemColorsChanged(EventArgs ea)
4435 	{
4436 		debug(EVENT_PRINT)
4437 		{
4438 			cprintf("{ Event: onSystemColorsChanged - Control %.*s }\n", name);
4439 		}
4440 		
4441 		systemColorsChanged(this, ea);
4442 	}
4443 	
4444 	
4445 	///
4446 	protected void onHandleCreated(EventArgs ea)
4447 	{
4448 		if(!(cbits & CBits.VSTYLE))
4449 			_disableVisualStyle();
4450 		
4451 		Font fon;
4452 		fon = font;
4453 		if(fon)
4454 			SendMessageA(hwnd, WM_SETFONT, cast(WPARAM)fon.handle, 0);
4455 		
4456 		if(wregion)
4457 		{
4458 			// Need to make a copy of the region.
4459 			SetWindowRgn(hwnd, dupHrgn(wregion.handle), true);
4460 		}
4461 		
4462 		version(DFL_NO_DRAG_DROP) {} else
4463 		{
4464 			if(droptarget)
4465 			{
4466 				if(S_OK != RegisterDragDrop(hwnd, droptarget))
4467 				{
4468 					droptarget = null;
4469 					throw new DflException("Unable to register drag-drop");
4470 				}
4471 			}
4472 		}
4473 		
4474 		debug
4475 		{
4476 			_handlecreated = true;
4477 		}
4478 	}
4479 	
4480 	
4481 	///
4482 	protected void onHandleDestroyed(EventArgs ea)
4483 	{
4484 		handleDestroyed(this, ea);
4485 	}
4486 	
4487 	
4488 	///
4489 	protected void onPaintBackground(PaintEventArgs pea)
4490 	{
4491 		RECT rect;
4492 		pea.clipRectangle.getRect(&rect);
4493 		FillRect(pea.graphics.handle, &rect, hbrBg);
4494 	}
4495 	
4496 	
4497 	private static MouseButtons wparamMouseButtons(WPARAM wparam)
4498 	{
4499 		MouseButtons result;
4500 		if(wparam & MK_LBUTTON)
4501 			result |= MouseButtons.LEFT;
4502 		if(wparam & MK_RBUTTON)
4503 			result |= MouseButtons.RIGHT;
4504 		if(wparam & MK_MBUTTON)
4505 			result |= MouseButtons.MIDDLE;
4506 		return result;
4507 	}
4508 	
4509 	
4510 	package final void prepareDc(HDC hdc)
4511 	{
4512 		//SetBkMode(hdc, TRANSPARENT); // ?
4513 		//SetBkMode(hdc, OPAQUE); // ?
4514 		SetBkColor(hdc, backColor.toRgb());
4515 		SetTextColor(hdc, foreColor.toRgb());
4516 	}
4517 	
4518 	
4519 	// Message copy so it cannot be modified.
4520 	deprecated protected void onNotifyMessage(Message msg)
4521 	{
4522 	}
4523 	
4524 	
4525 	/+
4526 	/+package+/ LRESULT customMsg(ref CustomMsg msg) // package
4527 	{
4528 		return 0;
4529 	}
4530 	+/
4531 	
4532 	
4533 	///
4534 	protected void onReflectedMessage(ref Message m)
4535 	{
4536 		switch(m.msg)
4537 		{
4538 			case WM_CTLCOLORSTATIC:
4539 			case WM_CTLCOLORLISTBOX:
4540 			case WM_CTLCOLOREDIT:
4541 			case WM_CTLCOLORSCROLLBAR:
4542 			case WM_CTLCOLORBTN:
4543 			//case WM_CTLCOLORDLG: // ?
4544 			//case 0x0019: //WM_CTLCOLOR; obsolete.
4545 				prepareDc(cast(HDC)m.wParam);
4546 				//assert(GetObjectA(hbrBg, 0, null));
4547 				m.result = cast(LRESULT)hbrBg;
4548 				break;
4549 			
4550 			default:
4551 		}
4552 	}
4553 	
4554 	
4555 	// ChildWindowFromPoint includes both hidden and disabled.
4556 	// This includes disabled windows, but not hidden.
4557 	// Here is a point in this control, see if it's over a visible child.
4558 	// Returns null if not even in this control's client.
4559 	final HWND pointOverVisibleChild(Point pt) // package
4560 	{
4561 		if(pt.x < 0 || pt.y < 0)
4562 			return HWND.init;
4563 		if(pt.x > wclientsz.width || pt.y > wclientsz.height)
4564 			return HWND.init;
4565 		
4566 		// Note: doesn't include non-DFL windows... TO-DO: fix.
4567 		foreach(Control ctrl; ccollection)
4568 		{
4569 			if(!ctrl.visible)
4570 				continue;
4571 			if(!ctrl.isHandleCreated) // Shouldn't..
4572 				continue;
4573 			if(ctrl.bounds.contains(pt))
4574 				return ctrl.hwnd;
4575 		}
4576 		
4577 		return hwnd; // Just over this control.
4578 	}
4579 	
4580 	
4581 	version(_DFL_WINDOWS_HUNG_WORKAROUND)
4582 	{
4583 		DWORD ldlgcode = 0;
4584 	}
4585 	
4586 	
4587 	///
4588 	protected void wndProc(ref Message msg)
4589 	{
4590 		//if(ctrlStyle & ControlStyles.ENABLE_NOTIFY_MESSAGE)
4591 		//	onNotifyMessage(msg);
4592 		
4593 		switch(msg.msg)
4594 		{
4595 			case WM_PAINT:
4596 				{
4597 					// This can't be done in BeginPaint() becuase part might get
4598 					// validated during this event ?
4599 					//RECT uprect;
4600 					//GetUpdateRect(hwnd, &uprect, true);
4601 					//onInvalidated(new InvalidateEventArgs(Rect(&uprect)));
4602 					
4603 					PAINTSTRUCT ps;
4604 					BeginPaint(msg.hWnd, &ps);
4605 					try
4606 					{
4607 						//onInvalidated(new InvalidateEventArgs(Rect(&uprect)));
4608 						
4609 						scope PaintEventArgs pea = new PaintEventArgs(new Graphics(ps.hdc, false), Rect(&ps.rcPaint));
4610 						
4611 						// Probably because ControlStyles.ALL_PAINTING_IN_WM_PAINT.
4612 						if(ps.fErase)
4613 						{
4614 							prepareDc(ps.hdc);
4615 							onPaintBackground(pea);
4616 						}
4617 						
4618 						prepareDc(ps.hdc);
4619 						onPaint(pea);
4620 					}
4621 					finally
4622 					{
4623 						EndPaint(hwnd, &ps);
4624 					}
4625 				}
4626 				return;
4627 			
4628 			case WM_ERASEBKGND:
4629 				if(ctrlStyle & ControlStyles.OPAQUE)
4630 				{
4631 					msg.result = 1; // Erased.
4632 				}
4633 				else if(!(ctrlStyle & ControlStyles.ALL_PAINTING_IN_WM_PAINT))
4634 				{
4635 					RECT uprect;
4636 					/+
4637 					GetUpdateRect(hwnd, &uprect, false);
4638 					+/
4639 					uprect.left = 0;
4640 					uprect.top = 0;
4641 					uprect.right = clientSize.width;
4642 					uprect.bottom = clientSize.height;
4643 					
4644 					prepareDc(cast(HDC)msg.wParam);
4645 					scope PaintEventArgs pea = new PaintEventArgs(new Graphics(cast(HDC)msg.wParam, false), Rect(&uprect));
4646 					onPaintBackground(pea);
4647 					msg.result = 1; // Erased.
4648 				}
4649 				return;
4650 			
4651 			case WM_PRINTCLIENT:
4652 				prepareDc(cast(HDC)msg.wParam);
4653 				scope PaintEventArgs pea = new PaintEventArgs(new Graphics(cast(HDC)msg.wParam, false), Rect(Point(0, 0), wclientsz));
4654 				onPaint(pea);
4655 				return;
4656 			
4657 			case WM_CTLCOLORSTATIC:
4658 			case WM_CTLCOLORLISTBOX:
4659 			case WM_CTLCOLOREDIT:
4660 			case WM_CTLCOLORSCROLLBAR:
4661 			case WM_CTLCOLORBTN:
4662 			//case WM_CTLCOLORDLG: // ?
4663 			//case 0x0019: //WM_CTLCOLOR; obsolete.
4664 				{
4665 					Control ctrl = fromChildHandle(cast(HWND)msg.lParam);
4666 					if(ctrl)
4667 					{
4668 						//ctrl.prepareDc(cast(HDC)msg.wParam);
4669 						//msg.result = cast(LRESULT)ctrl.hbrBg;
4670 						ctrl.onReflectedMessage(msg);
4671 						return;
4672 					}
4673 				}
4674 				break;
4675 			
4676 			case WM_WINDOWPOSCHANGED:
4677 				{
4678 					WINDOWPOS* wp = cast(WINDOWPOS*)msg.lParam;
4679 					bool needLayout = false;
4680 					
4681 					//if(!wp.hwndInsertAfter)
4682 					//	wp.flags |= SWP_NOZORDER; // ?
4683 					
4684 					bool didvis = false;
4685 					if(wp.flags & (SWP_HIDEWINDOW | SWP_SHOWWINDOW))
4686 					{
4687 						needLayout = true; // Only if not didvis / if not recreating.
4688 						if(!recreatingHandle) // Note: suppresses onVisibleChanged
4689 						{
4690 							if(wp.flags & SWP_HIDEWINDOW) // Hiding.
4691 								_clicking = false;
4692 							onVisibleChanged(EventArgs.empty);
4693 							didvis = true;
4694 							//break; // Showing min/max includes other flags.
4695 						}
4696 					}
4697 					
4698 					if(!(wp.flags & SWP_NOZORDER) /+ || (wp.flags & SWP_SHOWWINDOW) +/)
4699 					{
4700 						if(wparent)
4701 							wparent.vchanged();
4702 					}
4703 					
4704 					if(!(wp.flags & SWP_NOMOVE))
4705 					{
4706 						onMove(EventArgs.empty);
4707 					}
4708 					
4709 					if(!(wp.flags & SWP_NOSIZE))
4710 					{
4711 						if(szdraw)
4712 							invalidate(true);
4713 						
4714 						onResize(EventArgs.empty);
4715 						
4716 						needLayout = true;
4717 					}
4718 					
4719 					// Frame change results in a new client size.
4720 					if(wp.flags & SWP_FRAMECHANGED)
4721 					{
4722 						if(szdraw)
4723 							invalidate(true);
4724 						
4725 						needLayout = true;
4726 					}
4727 					
4728 					if(!didvis) // onVisibleChanged already triggers layout.
4729 					{
4730 						if(/+ (wp.flags & SWP_SHOWWINDOW) || +/ !(wp.flags & SWP_NOSIZE) ||
4731 							!(wp.flags & SWP_NOZORDER)) // z-order determines what is positioned first.
4732 						{
4733 							suspendLayout(); // Note: exception could cause failure to restore.
4734 							if(wparent)
4735 								wparent.alayout(this);
4736 							resumeLayout(false);
4737 							needLayout = true;
4738 						}
4739 						
4740 						if(needLayout)
4741 						{
4742 							alayout(this);
4743 						}
4744 					}
4745 				}
4746 				break;
4747 			
4748 			/+
4749 			case WM_WINDOWPOSCHANGING:
4750 				{
4751 					WINDOWPOS* wp = cast(WINDOWPOS*)msg.lParam;
4752 					
4753 					/+
4754 					//if(!(wp.flags & SWP_NOSIZE))
4755 					if(width != wp.cx || height != wp.cy)
4756 					{
4757 						scope BeforeResizeEventArgs ea = new BeforeResizeEventArgs(wp.cx, wp.cy);
4758 						onBeforeResize(ea);
4759 						/+if(wp.cx == ea.width && wp.cy == ea.height)
4760 						{
4761 							wp.flags |= SWP_NOSIZE;
4762 						}
4763 						else+/
4764 						{
4765 							wp.cx = ea.width;
4766 							wp.cy = ea.height;
4767 						}
4768 					}
4769 					+/
4770 				}
4771 				break;
4772 			+/
4773 			
4774 			case WM_MOUSEMOVE:
4775 				if(_clicking)
4776 				{
4777 					if(!(msg.wParam & MK_LBUTTON))
4778 						_clicking = false;
4779 				}
4780 				
4781 				if(trackMouseEvent) // Requires Windows 95 with IE 5.5, 98 or NT4.
4782 				{
4783 					if(!menter)
4784 					{
4785 						menter = true;
4786 						
4787 						POINT pt;
4788 						GetCursorPos(&pt);
4789 						MapWindowPoints(HWND.init, hwnd, &pt, 1);
4790 						scope MouseEventArgs mea = new MouseEventArgs(wparamMouseButtons(msg.wParam), 0, pt.x, pt.y, 0);
4791 						onMouseEnter(mea);
4792 						
4793 						TRACKMOUSEEVENT tme;
4794 						tme.cbSize = TRACKMOUSEEVENT.sizeof;
4795 						tme.dwFlags = TME_HOVER | TME_LEAVE;
4796 						tme.hwndTrack = msg.hWnd;
4797 						tme.dwHoverTime = HOVER_DEFAULT;
4798 						trackMouseEvent(&tme);
4799 					}
4800 				}
4801 				
4802 				onMouseMove(new MouseEventArgs(wparamMouseButtons(msg.wParam), 0, cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam), 0));
4803 				break;
4804 			
4805 			case WM_SETCURSOR:
4806 				// Just update it so that Control.defWndProc() can set it correctly.
4807 				if(cast(HWND)msg.wParam == hwnd)
4808 				{
4809 					Cursor cur;
4810 					cur = cursor;
4811 					if(cur)
4812 					{
4813 						if(cast(HCURSOR)GetClassLongA(hwnd, GCL_HCURSOR) != cur.handle)
4814 							SetClassLongA(hwnd, GCL_HCURSOR, cast(LONG)cur.handle);
4815 					}
4816 					else
4817 					{
4818 						if(cast(HCURSOR)GetClassLongA(hwnd, GCL_HCURSOR) != HCURSOR.init)
4819 							SetClassLongA(hwnd, GCL_HCURSOR, cast(LONG)cast(HCURSOR)null);
4820 					}
4821 					Control.defWndProc(msg);
4822 					return;
4823 				}
4824 				break;
4825 			
4826 			/+
4827 			case WM_NEXTDLGCTL:
4828 				if(!LOWORD(msg.lParam))
4829 				{
4830 					select(true, msg.wParam != 0);
4831 					return;
4832 				}
4833 				break;
4834 			+/
4835 			
4836 			case WM_KEYDOWN:
4837 			case WM_KEYUP:
4838 			case WM_CHAR:
4839 			case WM_SYSKEYDOWN:
4840 			case WM_SYSKEYUP:
4841 			case WM_SYSCHAR:
4842 			//case WM_IMECHAR:
4843 				/+
4844 				if(processKeyEventArgs(msg))
4845 				{
4846 					// The key was processed.
4847 					msg.result = 0;
4848 					return;
4849 				}
4850 				msg.result = 1; // The key was not processed.
4851 				break;
4852 				+/
4853 				msg.result = !processKeyEventArgs(msg);
4854 				return;
4855 			
4856 			case WM_MOUSEWHEEL: // Requires Windows 98 or NT4.
4857 				{
4858 					scope MouseEventArgs mea = new MouseEventArgs(wparamMouseButtons(LOWORD(msg.wParam)), 0, cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam), cast(short)HIWORD(msg.wParam));
4859 					onMouseWheel(mea);
4860 				}
4861 				break;
4862 			
4863 			case WM_MOUSEHOVER: // Requires Windows 95 with IE 5.5, 98 or NT4.
4864 				{
4865 					scope MouseEventArgs mea = new MouseEventArgs(wparamMouseButtons(msg.wParam), 0, cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam), 0);
4866 					onMouseHover(mea);
4867 				}
4868 				break;
4869 			
4870 			case WM_MOUSELEAVE: // Requires Windows 95 with IE 5.5, 98 or NT4.
4871 				{
4872 					menter = false;
4873 					
4874 					POINT pt;
4875 					GetCursorPos(&pt);
4876 					MapWindowPoints(HWND.init, hwnd, &pt, 1);
4877 					scope MouseEventArgs mea = new MouseEventArgs(wparamMouseButtons(msg.wParam), 0, pt.x, pt.y, 0);
4878 					onMouseLeave(mea);
4879 				}
4880 				break;
4881 			
4882 			case WM_LBUTTONDOWN:
4883 				{
4884 					_clicking = true;
4885 					
4886 					scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.LEFT, 1, cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam), 0);
4887 					onMouseDown(mea);
4888 					
4889 					//if(ctrlStyle & ControlStyles.SELECTABLE)
4890 					//	SetFocus(hwnd); // No, this goofs up stuff, including the ComboBox dropdown.
4891 				}
4892 				break;
4893 			
4894 			case WM_RBUTTONDOWN:
4895 				{
4896 					scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.RIGHT, 1, cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam), 0);
4897 					onMouseDown(mea);
4898 				}
4899 				break;
4900 			
4901 			case WM_MBUTTONDOWN:
4902 				{
4903 					scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.MIDDLE, 1, cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam), 0);
4904 					onMouseDown(mea);
4905 				}
4906 				break;
4907 			
4908 			case WM_LBUTTONUP:
4909 				{
4910 					if(msg.lParam == -1)
4911 						break;
4912 					
4913 					// Use temp in case of exception.
4914 					bool wasClicking = _clicking;
4915 					_clicking = false;
4916 					
4917 					scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.LEFT, 1, cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam), 0);
4918 					onMouseUp(mea);
4919 					
4920 					if(wasClicking && (ctrlStyle & ControlStyles.STANDARD_CLICK))
4921 					{
4922 						// See if the mouse up was over the control.
4923 						if(Rect(0, 0, wclientsz.width, wclientsz.height).contains(mea.x, mea.y))
4924 						{
4925 							// Now make sure there's no child in the way.
4926 							//if(ChildWindowFromPoint(hwnd, Point(mea.x, mea.y).point) == hwnd) // Includes hidden windows.
4927 							if(pointOverVisibleChild(Point(mea.x, mea.y)) == hwnd)
4928 								onClick(EventArgs.empty);
4929 						}
4930 					}
4931 				}
4932 				break;
4933 			
4934 			version(CUSTOM_MSG_HOOK)
4935 			{}
4936 			else
4937 			{
4938 				case WM_DRAWITEM:
4939 					{
4940 						Control ctrl;
4941 						
4942 						DRAWITEMSTRUCT* dis = cast(DRAWITEMSTRUCT*)msg.lParam;
4943 						if(dis.CtlType == ODT_MENU)
4944 						{
4945 							// dis.hwndItem is the HMENU.
4946 						}
4947 						else
4948 						{
4949 							ctrl = Control.fromChildHandle(dis.hwndItem);
4950 							if(ctrl)
4951 							{
4952 								//msg.result = ctrl.customMsg(*(cast(CustomMsg*)&msg));
4953 								ctrl.onReflectedMessage(msg);
4954 								return;
4955 							}
4956 						}
4957 					}
4958 					break;
4959 				
4960 				case WM_MEASUREITEM:
4961 					{
4962 						Control ctrl;
4963 						
4964 						MEASUREITEMSTRUCT* mis = cast(MEASUREITEMSTRUCT*)msg.lParam;
4965 						if(!(mis.CtlType == ODT_MENU))
4966 						{
4967 							ctrl = Control.fromChildHandle(cast(HWND)mis.CtlID);
4968 							if(ctrl)
4969 							{
4970 								//msg.result = ctrl.customMsg(*(cast(CustomMsg*)&msg));
4971 								ctrl.onReflectedMessage(msg);
4972 								return;
4973 							}
4974 						}
4975 					}
4976 					break;
4977 				
4978 				case WM_COMMAND:
4979 					{
4980 						/+
4981 						switch(LOWORD(msg.wParam))
4982 						{
4983 							case IDOK:
4984 							case IDCANCEL:
4985 								if(parent)
4986 								{
4987 									parent.wndProc(msg);
4988 								}
4989 								//break;
4990 								return; // ?
4991 							
4992 							default:
4993 						}
4994 						+/
4995 						
4996 						Control ctrl;
4997 						
4998 						ctrl = Control.fromChildHandle(cast(HWND)msg.lParam);
4999 						if(ctrl)
5000 						{
5001 							//msg.result = ctrl.customMsg(*(cast(CustomMsg*)&msg));
5002 							ctrl.onReflectedMessage(msg);
5003 							return;
5004 						}
5005 						else
5006 						{
5007 							version(DFL_NO_MENUS)
5008 							{
5009 							}
5010 							else
5011 							{
5012 								MenuItem m;
5013 								
5014 								m = cast(MenuItem)Application.lookupMenuID(LOWORD(msg.wParam));
5015 								if(m)
5016 								{
5017 									//msg.result = m.customMsg(*(cast(CustomMsg*)&msg));
5018 									m._reflectMenu(msg);
5019 									//return; // ?
5020 								}
5021 							}
5022 						}
5023 					}
5024 					break;
5025 				
5026 				case WM_NOTIFY:
5027 					{
5028 						Control ctrl;
5029 						NMHDR* nmh;
5030 						nmh = cast(NMHDR*)msg.lParam;
5031 						
5032 						ctrl = Control.fromChildHandle(nmh.hwndFrom);
5033 						if(ctrl)
5034 						{
5035 							//msg.result = ctrl.customMsg(*(cast(CustomMsg*)&msg));
5036 							ctrl.onReflectedMessage(msg);
5037 							return;
5038 						}
5039 					}
5040 					break;
5041 				
5042 				version(DFL_NO_MENUS)
5043 				{
5044 				}
5045 				else
5046 				{
5047 					case WM_MENUSELECT:
5048 						{
5049 							UINT mflags;
5050 							UINT uitem;
5051 							int mid;
5052 							MenuItem m;
5053 							
5054 							mflags = HIWORD(msg.wParam);
5055 							uitem = LOWORD(msg.wParam); // Depends on the flags.
5056 							
5057 							if(mflags & MF_SYSMENU)
5058 								break;
5059 							
5060 							if(mflags & MF_POPUP)
5061 							{
5062 								// -uitem- is an index.
5063 								mid = GetMenuItemID(cast(HMENU)msg.lParam, uitem);
5064 							}
5065 							else
5066 							{
5067 								// -uitem- is the item identifier.
5068 								mid = uitem;
5069 							}
5070 							
5071 							m = cast(MenuItem)Application.lookupMenuID(mid);
5072 							if(m)
5073 							{
5074 								//msg.result = m.customMsg(*(cast(CustomMsg*)&msg));
5075 								m._reflectMenu(msg);
5076 								//return;
5077 							}
5078 						}
5079 						break;
5080 					
5081 					case WM_INITMENUPOPUP:
5082 						if(HIWORD(msg.lParam))
5083 						{
5084 							// System menu.
5085 						}
5086 						else
5087 						{
5088 							MenuItem m;
5089 							
5090 							//m = cast(MenuItem)Application.lookupMenuID(GetMenuItemID(cast(HMENU)msg.wParam, LOWORD(msg.lParam)));
5091 							m = cast(MenuItem)Application.lookupMenu(cast(HMENU)msg.wParam);
5092 							if(m)
5093 							{
5094 								//msg.result = m.customMsg(*(cast(CustomMsg*)&msg));
5095 								m._reflectMenu(msg);
5096 								//return;
5097 							}
5098 						}
5099 						break;
5100 					
5101 					case WM_INITMENU:
5102 						{
5103 							ContextMenu m;
5104 							
5105 							m = cast(ContextMenu)Application.lookupMenu(cast(HMENU)msg.wParam);
5106 							if(m)
5107 							{
5108 								//msg.result = m.customMsg(*(cast(CustomMsg*)&msg));
5109 								m._reflectMenu(msg);
5110 								//return;
5111 							}
5112 						}
5113 						break;
5114 				}
5115 			}
5116 			
5117 			case WM_RBUTTONUP:
5118 				{
5119 					scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.RIGHT, 1, cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam), 0);
5120 					onMouseUp(mea);
5121 				}
5122 				break;
5123 			
5124 			case WM_MBUTTONUP:
5125 				{
5126 					scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.MIDDLE, 1, cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam), 0);
5127 					onMouseUp(mea);
5128 				}
5129 				break;
5130 			
5131 			case WM_LBUTTONDBLCLK:
5132 				{
5133 					scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.LEFT, 2, cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam), 0);
5134 					onMouseDown(mea);
5135 					
5136 					if((ctrlStyle & (ControlStyles.STANDARD_CLICK | ControlStyles.STANDARD_DOUBLE_CLICK))
5137 						== (ControlStyles.STANDARD_CLICK | ControlStyles.STANDARD_DOUBLE_CLICK))
5138 					{
5139 						onDoubleClick(EventArgs.empty);
5140 					}
5141 				}
5142 				break;
5143 			
5144 			case WM_RBUTTONDBLCLK:
5145 				{
5146 					scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.RIGHT, 2, cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam), 0);
5147 					onMouseDown(mea);
5148 				}
5149 				break;
5150 			
5151 			case WM_MBUTTONDBLCLK:
5152 				{
5153 					scope MouseEventArgs mea = new MouseEventArgs(MouseButtons.MIDDLE, 2, cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam), 0);
5154 					onMouseDown(mea);
5155 				}
5156 				break;
5157 			
5158 			case WM_SETFOCUS:
5159 				_wmSetFocus();
5160 				// defWndProc* Form focuses a child.
5161 				break;
5162 			
5163 			case WM_KILLFOCUS:
5164 				_wmKillFocus();
5165 				break;
5166 			
5167 			case WM_ENABLE:
5168 				onEnabledChanged(EventArgs.empty);
5169 				
5170 				// defWndProc*
5171 				break;
5172 			
5173 			/+
5174 			case WM_NEXTDLGCTL:
5175 				if(msg.wParam && !LOWORD(msg.lParam))
5176 				{
5177 					HWND hwf;
5178 					hwf = GetFocus();
5179 					if(hwf)
5180 					{
5181 						Control hwc;
5182 						hwc = Control.fromHandle(hwf);
5183 						if(hwc)
5184 						{
5185 							if(hwc._rtype() & 0x20) // TabControl
5186 							{
5187 								hwf = GetWindow(hwf, GW_CHILD);
5188 								if(hwf)
5189 								{
5190 									// Can't do this because it could be modifying someone else's memory.
5191 									//msg.wParam = cast(WPARAM)hwf;
5192 									//msg.lParam = MAKELPARAM(1, 0);
5193 									msg.result = DefWindowProcA(msg.hWnd, WM_NEXTDLGCTL, cast(WPARAM)hwf, MAKELPARAM(TRUE, 0));
5194 									return;
5195 								}
5196 							}
5197 						}
5198 					}
5199 				}
5200 				break;
5201 			+/
5202 			
5203 			case WM_SETTEXT:
5204 				defWndProc(msg);
5205 				
5206 				// Need to fetch it because cast(char*)lparam isn't always accessible ?
5207 				// Should this go in _wndProc()? Need to defWndProc() first ?
5208 				if(ctrlStyle & ControlStyles.CACHE_TEXT)
5209 					wtext = _fetchText();
5210 				
5211 				onTextChanged(EventArgs.empty);
5212 				return;
5213 			
5214 			case WM_SETFONT:
5215 				// Don't replace -wfont- if it's the same one, beacuse the old Font
5216 				// object will get garbage collected and probably delete the HFONT.
5217 				
5218 				//onFontChanged(EventArgs.empty);
5219 				
5220 				// defWndProc*
5221 				return;
5222 			
5223 			/+
5224 			case WM_STYLECHANGED:
5225 				{
5226 					//defWndProc(msg);
5227 					
5228 					STYLESTRUCT* ss = cast(STYLESTRUCT*)msg.lParam;
5229 					DWORD changed = ss.styleOld ^ ss.styleNew;
5230 					
5231 					if(msg.wParam == GWL_EXSTYLE)
5232 					{
5233 						//if(changed & WS_EX_RTLREADING)
5234 						//	onRightToLeftChanged(EventArgs.empty);
5235 					}
5236 				}
5237 				break;
5238 			+/
5239 			
5240 			case WM_ACTIVATE:
5241 				switch(LOWORD(msg.wParam))
5242 				{
5243 					case WA_INACTIVE:
5244 						_clicking = false;
5245 						break;
5246 					
5247 					default:
5248 				}
5249 				break;
5250 			
5251 			version(DFL_NO_MENUS)
5252 			{
5253 			}
5254 			else
5255 			{
5256 				case WM_CONTEXTMENU:
5257 					if(hwnd == cast(HWND)msg.wParam)
5258 					{
5259 						if(cmenu)
5260 						{
5261 							// Shift+F10 causes xPos and yPos to be -1.
5262 							
5263 							Point point;
5264 							
5265 							if(msg.lParam == -1)
5266 								point = pointToScreen(Point(0, 0));
5267 							else
5268 								point = Point(cast(short)LOWORD(msg.lParam), cast(short)HIWORD(msg.lParam));
5269 							
5270 							SetFocus(handle); // ?
5271 							cmenu.show(this, point);
5272 							
5273 							return;
5274 						}
5275 					}
5276 					break;
5277 			}
5278 			
5279 			case WM_HELP:
5280 				{
5281 					HELPINFO* hi = cast(HELPINFO*)msg.lParam;
5282 					
5283 					scope HelpEventArgs hea = new HelpEventArgs(Point(hi.MousePos.x, hi.MousePos.y));
5284 					onHelpRequested(hea);
5285 					if(hea.handled)
5286 					{
5287 						msg.result = TRUE;
5288 						return;
5289 					}
5290 				}
5291 				break;
5292 			
5293 			case WM_SYSCOLORCHANGE:
5294 				onSystemColorsChanged(EventArgs.empty);
5295 				
5296 				// Need to send the message to children for some common controls to update properly.
5297 				foreach(Control ctrl; ccollection)
5298 				{
5299 					SendMessageA(ctrl.handle, WM_SYSCOLORCHANGE, msg.wParam, msg.lParam);
5300 				}
5301 				break;
5302 			
5303 			case WM_SETTINGCHANGE:
5304 				// Send the message to children.
5305 				foreach(Control ctrl; ccollection)
5306 				{
5307 					SendMessageA(ctrl.handle, WM_SETTINGCHANGE, msg.wParam, msg.lParam);
5308 				}
5309 				break;
5310 			
5311 			case WM_PALETTECHANGED:
5312 				/+
5313 				if(cast(HWND)msg.wParam != hwnd)
5314 				{
5315 					// Realize palette.
5316 				}
5317 				+/
5318 				
5319 				// Send the message to children.
5320 				foreach(Control ctrl; ccollection)
5321 				{
5322 					SendMessageA(ctrl.handle, WM_PALETTECHANGED, msg.wParam, msg.lParam);
5323 				}
5324 				break;
5325 			
5326 			//case WM_QUERYNEWPALETTE: // Send this message to children ?
5327 			
5328 			/+
5329 			// Moved this stuff to -parent-.
5330 			case WM_PARENTNOTIFY:
5331 				switch(LOWORD(msg.wParam))
5332 				{
5333 					case WM_DESTROY:
5334 						Control ctrl = fromChildHandle(cast(HWND)msg.lParam);
5335 						if(ctrl)
5336 						{
5337 							_ctrlremoved(new ControlEventArgs(ctrl));
5338 							
5339 							// ?
5340 							vchanged();
5341 							//alayout(ctrl); // This is already being called from somewhere else..
5342 						}
5343 						break;
5344 					
5345 					/+
5346 					case WM_CREATE:
5347 						initLayout();
5348 						break;
5349 					+/
5350 					
5351 					default:
5352 				}
5353 				break;
5354 			+/
5355 			
5356 			case WM_CREATE:
5357 				/+
5358 				if(wparent)
5359 					initLayout(); // ?
5360 				+/
5361 				if(cbits & CBits.NEED_INIT_LAYOUT)
5362 				{
5363 					if(visible)
5364 					{
5365 						if(wparent)
5366 						{
5367 							wparent.vchanged();
5368 							suspendLayout(); // Note: exception could cause failure to restore.
5369 							wparent.alayout(this);
5370 							resumeLayout(false);
5371 						}
5372 						alayout(this);
5373 					}
5374 				}
5375 				break;
5376 			
5377 			case WM_DESTROY:
5378 				onHandleDestroyed(EventArgs.empty);
5379 				break;
5380 			
5381 			case WM_GETDLGCODE:
5382 				{
5383 					version(_DFL_WINDOWS_HUNG_WORKAROUND)
5384 					{
5385 						/+
5386 						if(ctrlStyle & ControlStyles.CONTAINER_CONTROL)
5387 						{
5388 							if(!(_exStyle & WS_EX_CONTROLPARENT))
5389 								assert(0);
5390 						}
5391 						+/
5392 						
5393 						DWORD dw;
5394 						dw = GetTickCount();
5395 						if(ldlgcode < dw - 1020)
5396 						{
5397 							ldlgcode = dw - 1000;
5398 						}
5399 						else
5400 						{
5401 							ldlgcode += 50;
5402 							if(ldlgcode > dw)
5403 							{
5404 								// Probably a problem with WS_EX_CONTROLPARENT and WS_TABSTOP.
5405 								if(ldlgcode >= ldlgcode.max - 10_000)
5406 								{
5407 									ldlgcode = 0;
5408 									throw new WindowsHungDflException("Windows hung");
5409 								}
5410 								//msg.result |= 0x0004 | 0x0002 | 0x0001; //DLGC_WANTALLKEYS | DLGC_WANTTAB | DLGC_WANTARROWS;
5411 								ldlgcode = ldlgcode.max - 10_000;
5412 								return;
5413 							}
5414 						}
5415 					}
5416 					
5417 					/+
5418 					if(msg.lParam)
5419 					{
5420 						Message m;
5421 						m._winMsg = *cast(MSG*)msg.lParam;
5422 						if(processKeyEventArgs(m))
5423 							return;
5424 					}
5425 					+/
5426 					
5427 					defWndProc(msg);
5428 					
5429 					if(ctrlStyle & ControlStyles.WANT_ALL_KEYS)
5430 						msg.result |= DLGC_WANTALLKEYS;
5431 					
5432 					// Only want chars if ALT isn't down, because it would break mnemonics.
5433 					if(!(GetKeyState(VK_MENU) & 0x8000))
5434 						msg.result |= DLGC_WANTCHARS;
5435 					
5436 				}
5437 				return;
5438 			
5439 			case WM_CLOSE:
5440 				/+{
5441 					if(parent)
5442 					{
5443 						Message mp;
5444 						mp = msg;
5445 						mp.hWnd = parent.handle;
5446 						parent.wndProc(mp); // Pass to parent so it can decide what to do.
5447 					}
5448 				}+/
5449 				return; // Prevent defWndProc from destroying the window!
5450 			
5451 			case 0: // WM_NULL
5452 				// Don't confuse with failed RegisterWindowMessage().
5453 				break;
5454 			
5455 			default:
5456 				//defWndProc(msg);
5457 				version(DFL_NO_WM_GETCONTROLNAME)
5458 				{
5459 				}
5460 				else
5461 				{
5462 					if(msg.msg == wmGetControlName)
5463 					{
5464 						//cprintf("WM_GETCONTROLNAME: %.*s; wparam: %d\n", cast(uint)name.length, name.ptr, msg.wParam);
5465 						if(msg.wParam && this.name.length)
5466 						{
5467 							OSVERSIONINFOA osver;
5468 							osver.dwOSVersionInfoSize = OSVERSIONINFOA.sizeof;
5469 							if(GetVersionExA(&osver))
5470 							{
5471 								try
5472 								{
5473 									if(osver.dwPlatformId <= VER_PLATFORM_WIN32_WINDOWS)
5474 									{
5475 										version(DFL_UNICODE)
5476 										{
5477 										}
5478 										else
5479 										{
5480 											// ANSI.
5481 											Dstring ansi;
5482 											ansi = dfl.internal.utf.toAnsi(this.name);
5483 											if(msg.wParam <= ansi.length)
5484 												ansi = ansi[0 .. msg.wParam - 1];
5485 											(cast(char*)msg.lParam)[0 .. ansi.length] = ansi[];
5486 											(cast(char*)msg.lParam)[ansi.length] = 0;
5487 											msg.result = ansi.length + 1;
5488 										}
5489 									}
5490 									else
5491 									{
5492 										// Unicode.
5493 										Dwstring uni;
5494 										uni = dfl.internal.utf.toUnicode(this.name);
5495 										if(msg.wParam <= uni.length)
5496 											uni = uni[0 .. msg.wParam - 1];
5497 										(cast(wchar*)msg.lParam)[0 .. uni.length] = uni[];
5498 										(cast(wchar*)msg.lParam)[uni.length] = 0;
5499 										msg.result = uni.length + 1;
5500 									}
5501 								}
5502 								catch
5503 								{
5504 								}
5505 								return;
5506 							}
5507 						}
5508 					}
5509 				}
5510 		}
5511 		
5512 		defWndProc(msg);
5513 		
5514 		if(msg.msg == WM_CREATE)
5515 		{
5516 			EventArgs ea;
5517 			ea = EventArgs.empty;
5518 			onHandleCreated(ea);
5519 			
5520 			debug
5521 			{
5522 				assert(_handlecreated, "If overriding onHandleCreated(), be sure to call super.onHandleCreated()!");
5523 			}
5524 			handleCreated(this, ea);
5525 			debug
5526 			{
5527 				_handlecreated = false; // Reset.
5528 			}
5529 		}
5530 	}
5531 	
5532 	
5533 	package final void _wmSetFocus()
5534 	{
5535 		//onEnter(EventArgs.empty);
5536 		
5537 		onGotFocus(EventArgs.empty);
5538 		
5539 		// defWndProc* Form focuses a child.
5540 	}
5541 	
5542 	
5543 	package final void _wmKillFocus()
5544 	{
5545 		_clicking = false;
5546 		
5547 		//onLeave(EventArgs.empty);
5548 		
5549 		//if(cvalidation)
5550 		//	onValidating(new CancelEventArgs);
5551 		
5552 		onLostFocus(EventArgs.empty);
5553 	}
5554 	
5555 	
5556 	///
5557 	protected void defWndProc(ref Message msg)
5558 	{
5559 		//msg.result = DefWindowProcA(msg.hWnd, msg.msg, msg.wParam, msg.lParam);
5560 		msg.result = dfl.internal.utf.defWindowProc(msg.hWnd, msg.msg, msg.wParam, msg.lParam);
5561 	}
5562 	
5563 	
5564 	// Always called right when destroyed, before doing anything else.
5565 	// hwnd is cleared after this step.
5566 	void _destroying() // package
5567 	{
5568 		//wparent = null; // ?
5569 	}
5570 	
5571 	
5572 	// This function must be called FIRST for EVERY message to this
5573 	// window in order to keep the correct window state.
5574 	// This function must not throw exceptions.
5575 	package final void mustWndProc(ref Message msg)
5576 	{
5577 		if(needCalcSize)
5578 		{
5579 			needCalcSize = false;
5580 			RECT crect;
5581 			GetClientRect(msg.hWnd, &crect);
5582 			wclientsz.width = crect.right;
5583 			wclientsz.height = crect.bottom;
5584 		}
5585 		
5586 		switch(msg.msg)
5587 		{
5588 			case WM_NCCALCSIZE:
5589 				needCalcSize = true;
5590 				break;
5591 			
5592 			case WM_WINDOWPOSCHANGED:
5593 				{
5594 					WINDOWPOS* wp = cast(WINDOWPOS*)msg.lParam;
5595 					
5596 					if(!recreatingHandle)
5597 					{
5598 						//wstyle = GetWindowLongA(hwnd, GWL_STYLE); // ..WM_SHOWWINDOW.
5599 						if(wp.flags & (SWP_HIDEWINDOW | SWP_SHOWWINDOW))
5600 						{
5601 							//wstyle = GetWindowLongA(hwnd, GWL_STYLE);
5602 							cbits |= CBits.VISIBLE;
5603 							wstyle |= WS_VISIBLE;
5604 							if(wp.flags & SWP_HIDEWINDOW) // Hiding.
5605 							{
5606 								cbits &= ~CBits.VISIBLE;
5607 								wstyle &= ~WS_VISIBLE;
5608 							}
5609 							//break; // Showing min/max includes other flags.
5610 						}
5611 					}
5612 					
5613 					//if(!(wp.flags & SWP_NOMOVE))
5614 					//	wrect.location = Point(wp.x, wp.y);
5615 					if(!(wp.flags & SWP_NOSIZE) || !(wp.flags & SWP_NOMOVE) || (wp.flags & SWP_FRAMECHANGED))
5616 					{
5617 						//wrect = _fetchBounds();
5618 						wrect = Rect(wp.x, wp.y, wp.cx, wp.cy);
5619 						wclientsz = _fetchClientSize();
5620 					}
5621 					
5622 					if((wp.flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW)) || !(wp.flags & SWP_NOSIZE))
5623 					{
5624 						DWORD rstyle;
5625 						rstyle = GetWindowLongA(msg.hWnd, GWL_STYLE);
5626 						rstyle &= WS_MAXIMIZE | WS_MINIMIZE;
5627 						wstyle &= ~(WS_MAXIMIZE | WS_MINIMIZE);
5628 						wstyle |= rstyle;
5629 					}
5630 				}
5631 				break;
5632 			
5633 			/+
5634 			case WM_WINDOWPOSCHANGING:
5635 				//oldwrect = wrect;
5636 				break;
5637 			+/
5638 			
5639 			/+
5640 			case WM_SETFONT:
5641 				//wfont = _fetchFont();
5642 				break;
5643 			+/
5644 			
5645 			case WM_STYLECHANGED:
5646 				{
5647 					STYLESTRUCT* ss = cast(STYLESTRUCT*)msg.lParam;
5648 					
5649 					if(msg.wParam == GWL_STYLE)
5650 						wstyle = ss.styleNew;
5651 					else if(msg.wParam == GWL_EXSTYLE)
5652 						wexstyle = ss.styleNew;
5653 					
5654 					/+
5655 					wrect = _fetchBounds();
5656 					wclientsz = _fetchClientSize();
5657 					+/
5658 				}
5659 				break;
5660 			
5661 			/+
5662 			// NOTE: this is sent even if the parent is shown.
5663 			case WM_SHOWWINDOW:
5664 				if(!msg.lParam)
5665 				{
5666 					/+
5667 					{
5668 						cbits &= ~(CBits.SW_SHOWN | CBits.SW_HIDDEN);
5669 						DWORD rstyle;
5670 						rstyle = GetWindowLongA(msg.hWnd, GWL_STYLE);
5671 						if(cast(BOOL)msg.wParam)
5672 						{
5673 							//wstyle |= WS_VISIBLE;
5674 							if(!(WS_VISIBLE & wstyle) && (WS_VISIBLE & rstyle))
5675 							{
5676 								wstyle = rstyle;
5677 								cbits |= CBits.SW_SHOWN;
5678 								
5679 								try
5680 								{
5681 									createChildren(); // Might throw.
5682 								}
5683 								catch(DThrowable e)
5684 								{
5685 									Application.onThreadException(e);
5686 								}
5687 							}
5688 							wstyle = rstyle;
5689 						}
5690 						else
5691 						{
5692 							//wstyle &= ~WS_VISIBLE;
5693 							if((WS_VISIBLE & wstyle) && !(WS_VISIBLE & rstyle))
5694 							{
5695 								wstyle = rstyle;
5696 								cbits |= CBits.SW_HIDDEN;
5697 							}
5698 							wstyle = rstyle;
5699 						}
5700 					}
5701 					+/
5702 					wstyle = GetWindowLongA(msg.hWnd, GWL_STYLE);
5703 					//if(cbits & CBits.FVISIBLE)
5704 					//	wstyle |= WS_VISIBLE;
5705 				}
5706 				break;
5707 			+/
5708 			
5709 			case WM_ENABLE:
5710 				/+
5711 				//if(IsWindowEnabled(hwnd))
5712 				if(cast(BOOL)msg.wParam)
5713 					wstyle &= ~WS_DISABLED;
5714 				else
5715 					wstyle |= WS_DISABLED;
5716 				+/
5717 				wstyle = GetWindowLongA(hwnd, GWL_STYLE);
5718 				break;
5719 			
5720 			/+
5721 			case WM_PARENTNOTIFY:
5722 				switch(LOWORD(msg.wParam))
5723 				{
5724 					case WM_DESTROY:
5725 						// ...
5726 						break;
5727 					
5728 					default:
5729 				}
5730 				break;
5731 			+/
5732 			
5733 			case WM_NCCREATE:
5734 				{
5735 					//hwnd = msg.hWnd;
5736 					
5737 					/+
5738 					// Not using CREATESTRUCT for window bounds because it can contain
5739 					// CW_USEDEFAULT and other magic values.
5740 					
5741 					CREATESTRUCTA* cs;
5742 					cs = cast(CREATESTRUCTA*)msg.lParam;
5743 					
5744 					//wrect = Rect(cs.x, cs.y, cs.cx, cs.cy);
5745 					+/
5746 					
5747 					wrect = _fetchBounds();
5748 					//oldwrect = wrect;
5749 					wclientsz = _fetchClientSize();
5750 				}
5751 				break;
5752 			
5753 			case WM_CREATE:
5754 				try
5755 				{
5756 					cbits |= CBits.CREATED;
5757 					
5758 					//hwnd = msg.hWnd;
5759 					
5760 					CREATESTRUCTA* cs;
5761 					cs = cast(CREATESTRUCTA*)msg.lParam;
5762 					/+
5763 					// Done in WM_NCCREATE now.
5764 					//wrect = _fetchBounds();
5765 					wrect = Rect(cs.x, cs.y, cs.cx, cs.cy);
5766 					wclientsz = _fetchClientSize();
5767 					+/
5768 					
5769 					// If class style was changed, update.
5770 					if(_fetchClassLong() != wclassStyle)
5771 						SetClassLongA(hwnd, GCL_STYLE, wclassStyle);
5772 					
5773 					// Need to update clientSize in case of styles in createParams().
5774 					wclientsz = _fetchClientSize();
5775 					
5776 					//finishCreating(msg.hWnd);
5777 					
5778 					if(!(ctrlStyle & ControlStyles.CACHE_TEXT))
5779 						wtext = null;
5780 					
5781 					/+
5782 					// Gets created on demand instead.
5783 					if(Color.empty != backc)
5784 					{
5785 						hbrBg = backc.createBrush();
5786 					}
5787 					+/
5788 					
5789 					/+
5790 					// ?
5791 					wstyle = cs.style;
5792 					wexstyle = cs.dwExStyle;
5793 					+/
5794 					
5795 					createChildren(); // Might throw. Used to be commented-out.
5796 					
5797 					if(recreatingHandle)
5798 					{
5799 						// After existing messages and functions are done.
5800 						delayInvoke(function(Control cthis, size_t[] params){ cthis.cbits &= ~CBits.RECREATING; });
5801 					}
5802 				}
5803 				catch(DThrowable e)
5804 				{
5805 					Application.onThreadException(e);
5806 				}
5807 				break;
5808 			
5809 			case WM_DESTROY:
5810 				cbits &= ~CBits.CREATED;
5811 				if(!recreatingHandle)
5812 					cbits &= ~CBits.FORMLOADED;
5813 				_destroying();
5814 				//if(!killing)
5815 				if(recreatingHandle)
5816 					fillRecreationData();
5817 				break;
5818 			
5819 			case WM_NCDESTROY:
5820 				Application.removeHwnd(hwnd);
5821 				hwnd = HWND.init;
5822 				break;
5823 			
5824 			default:
5825 				/+
5826 				if(msg.msg == wmDfl)
5827 				{
5828 					switch(msg.wParam)
5829 					{
5830 						case WPARAM_DFL_:
5831 						
5832 						default:
5833 					}
5834 				}
5835 				+/
5836 		}
5837 	}
5838 	
5839 	
5840 	package final void _wndProc(ref Message msg)
5841 	{
5842 		//mustWndProc(msg); // Done in dflWndProc() now.
5843 		wndProc(msg);
5844 	}
5845 	
5846 	
5847 	package final void _defWndProc(ref Message msg)
5848 	{
5849 		defWndProc(msg);
5850 	}
5851 	
5852 	
5853 	package final void doShow()
5854 	{
5855 		if(wparent) // Exclude owner.
5856 		{
5857 			SetWindowPos(hwnd, HWND.init, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER);
5858 		}
5859 		else
5860 		{
5861 			SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
5862 		}
5863 	}
5864 	
5865 	
5866 	package final void doHide()
5867 	{
5868 		SetWindowPos(hwnd, HWND.init, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOZORDER);
5869 	}
5870 	
5871 	
5872 	//EventHandler backColorChanged;
5873 	Event!(Control, EventArgs) backColorChanged; ///
5874 	// EventHandler backgroundImageChanged;
5875 	/+
5876 	deprecated EventHandler causesValidationChanged;
5877 	deprecated InvalidateEventHandler invalidated;
5878 	deprecated EventHandler validated;
5879 	deprecated CancelEventHandler validating; // Once cancel is true, remaining events are suppressed (including validated).
5880 	deprecated EventHandler enter; // Cascades up. TODO: fix implementation.
5881 	deprecated EventHandler leave; // Cascades down. TODO: fix implementation.
5882 	deprecated UICuesEventHandler changeUICues; // TODO: properly fire.
5883 	+/
5884 	//EventHandler click;
5885 	Event!(Control, EventArgs) click; ///
5886 	version(DFL_NO_MENUS)
5887 	{
5888 	}
5889 	else
5890 	{
5891 		//EventHandler contextMenuChanged;
5892 		Event!(Control, EventArgs) contextMenuChanged; ///
5893 	}
5894 	//ControlEventHandler controlAdded;
5895 	Event!(Control, ControlEventArgs) controlAdded; ///
5896 	//ControlEventHandler controlRemoved;
5897 	Event!(Control, ControlEventArgs) controlRemoved; ///
5898 	//EventHandler cursorChanged;
5899 	Event!(Control, EventArgs) cursorChanged; ///
5900 	//EventHandler disposed;
5901 	Event!(Control, EventArgs) disposed; ///
5902 	//EventHandler dockChanged;
5903 	//Event!(Control, EventArgs) dockChanged; ///
5904 	Event!(Control, EventArgs) hasLayoutChanged; ///
5905 	alias hasLayoutChanged dockChanged;
5906 	//EventHandler doubleClick;
5907 	Event!(Control, EventArgs) doubleClick; ///
5908 	//EventHandler enabledChanged;
5909 	Event!(Control, EventArgs) enabledChanged; ///
5910 	//EventHandler fontChanged;
5911 	Event!(Control, EventArgs) fontChanged; ///
5912 	//EventHandler foreColorChanged;
5913 	Event!(Control, EventArgs) foreColorChanged; ///
5914 	//EventHandler gotFocus; // After enter.
5915 	Event!(Control, EventArgs) gotFocus; ///
5916 	//EventHandler handleCreated;
5917 	Event!(Control, EventArgs) handleCreated; ///
5918 	//EventHandler handleDestroyed;
5919 	Event!(Control, EventArgs) handleDestroyed; ///
5920 	//HelpEventHandler helpRequested;
5921 	Event!(Control, HelpEventArgs) helpRequested; ///
5922 	//KeyEventHandler keyDown;
5923 	Event!(Control, KeyEventArgs) keyDown; ///
5924 	//KeyEventHandler keyPress;
5925 	Event!(Control, KeyPressEventArgs) keyPress; ///
5926 	//KeyEventHandler keyUp;
5927 	Event!(Control, KeyEventArgs) keyUp; ///
5928 	//LayoutEventHandler layout;
5929 	Event!(Control, LayoutEventArgs) layout; ///
5930 	//EventHandler lostFocus;
5931 	Event!(Control, EventArgs) lostFocus; ///
5932 	//MouseEventHandler mouseDown;
5933 	Event!(Control, MouseEventArgs) mouseDown; ///
5934 	//MouseEventHandler mouseEnter;
5935 	Event!(Control, MouseEventArgs) mouseEnter; ///
5936 	//MouseEventHandler mouseHover;
5937 	Event!(Control, MouseEventArgs) mouseHover; ///
5938 	//MouseEventHandler mouseLeave;
5939 	Event!(Control, MouseEventArgs) mouseLeave; ///
5940 	//MouseEventHandler mouseMove;
5941 	Event!(Control, MouseEventArgs) mouseMove; ///
5942 	//MouseEventHandler mouseUp;
5943 	Event!(Control, MouseEventArgs) mouseUp; ///
5944 	//MouseEventHandler mouseWheel;
5945 	Event!(Control, MouseEventArgs) mouseWheel; ///
5946 	//EventHandler move;
5947 	Event!(Control, EventArgs) move; ///
5948 	//EventHandler locationChanged;
5949 	alias move locationChanged;
5950 	//PaintEventHandler paint;
5951 	Event!(Control, PaintEventArgs) paint; ///
5952 	//EventHandler parentChanged;
5953 	Event!(Control, EventArgs) parentChanged; ///
5954 	//EventHandler resize;
5955 	Event!(Control, EventArgs) resize; ///
5956 	//EventHandler sizeChanged;
5957 	alias resize sizeChanged;
5958 	//EventHandler rightToLeftChanged;
5959 	Event!(Control, EventArgs) rightToLeftChanged; ///
5960 	// EventHandler styleChanged;
5961 	//EventHandler systemColorsChanged;
5962 	Event!(Control, EventArgs) systemColorsChanged; ///
5963 	// EventHandler tabIndexChanged;
5964 	// EventHandler tabStopChanged;
5965 	//EventHandler textChanged;
5966 	Event!(Control, EventArgs) textChanged; ///
5967 	//EventHandler visibleChanged;
5968 	Event!(Control, EventArgs) visibleChanged; ///
5969 	
5970 	version(DFL_NO_DRAG_DROP) {} else
5971 	{
5972 		//DragEventHandler dragDrop;
5973 		Event!(Control, DragEventArgs) dragDrop; ///
5974 		//DragEventHandler dragEnter;
5975 		Event!(Control, DragEventArgs) dragEnter; ///
5976 		//EventHandler dragLeave;
5977 		Event!(Control, EventArgs) dragLeave; ///
5978 		//DragEventHandler dragOver;
5979 		Event!(Control, DragEventArgs) dragOver; ///
5980 		//GiveFeedbackEventHandler giveFeedback;
5981 		Event!(Control, GiveFeedbackEventArgs) giveFeedback; ///
5982 		//QueryContinueDragEventHandler queryContinueDrag;
5983 		Event!(Control, QueryContinueDragEventArgs) queryContinueDrag; ///
5984 	}
5985 	
5986 	
5987 	/// Construct a new Control instance.
5988 	this()
5989 	{
5990 		//name = DObject.toString(); // ?
5991 		
5992 		wrect.size = defaultSize;
5993 		//oldwrect = wrect;
5994 		
5995 		/+
5996 		backc = defaultBackColor;
5997 		forec = defaultForeColor;
5998 		wfont = defaultFont;
5999 		wcurs = new Cursor(LoadCursorA(HINSTANCE.init, IDC_ARROW), false);
6000 		+/
6001 		backc = Color.empty;
6002 		forec = Color.empty;
6003 		wfont = null;
6004 		wcurs = null;
6005 		
6006 		ccollection = createControlsInstance();
6007 	}
6008 	
6009 	/// ditto
6010 	this(Dstring text)
6011 	{
6012 		this();
6013 		wtext = text;
6014 		
6015 		ccollection = createControlsInstance();
6016 	}
6017 	
6018 	/// ditto
6019 	this(Control cparent, Dstring text)
6020 	{
6021 		this();
6022 		wtext = text;
6023 		parent = cparent;
6024 		
6025 		ccollection = createControlsInstance();
6026 	}
6027 	
6028 	/// ditto
6029 	this(Dstring text, int left, int top, int width, int height)
6030 	{
6031 		this();
6032 		wtext = text;
6033 		wrect = Rect(left, top, width, height);
6034 		
6035 		ccollection = createControlsInstance();
6036 	}
6037 	
6038 	/// ditto
6039 	this(Control cparent, Dstring text, int left, int top, int width, int height)
6040 	{
6041 		this();
6042 		wtext = text;
6043 		wrect = Rect(left, top, width, height);
6044 		parent = cparent;
6045 		
6046 		ccollection = createControlsInstance();
6047 	}
6048 	
6049 	
6050 	/+
6051 	// Used internally.
6052 	this(HWND hwnd)
6053 	in
6054 	{
6055 		assert(hwnd);
6056 	}
6057 	body
6058 	{
6059 		this.hwnd = hwnd;
6060 		owned = false;
6061 		
6062 		ccollection = new ControlCollection(this);
6063 	}
6064 	+/
6065 	
6066 	
6067 	~this()
6068 	{
6069 		debug(APP_PRINT)
6070 			cprintf("~Control %p\n", cast(void*)this);
6071 		
6072 		version(DFL_NO_ZOMBIE_FORM)
6073 		{
6074 		}
6075 		else
6076 		{
6077 			Application.zombieKill(this); // Does nothing if not zombie.
6078 		}
6079 		
6080 		//dispose(false);
6081 		destroyHandle();
6082 		deleteThisBackgroundBrush();
6083 	}
6084 	
6085 	
6086 	/+ package +/ /+ protected +/ int _rtype() // package
6087 	{
6088 		return 0;
6089 	}
6090 	
6091 	
6092 	///
6093 	void dispose()
6094 	{
6095 		dispose(true);
6096 	}
6097 	
6098 	/// ditto
6099 	protected void dispose(bool disposing)
6100 	{
6101 		if(disposing)
6102 		{
6103 			killing = true;
6104 			
6105 			version(DFL_NO_MENUS)
6106 			{
6107 			}
6108 			else
6109 			{
6110 				cmenu = cmenu.init;
6111 			}
6112 			_ctrlname = _ctrlname.init;
6113 			otag = otag.init;
6114 			wcurs = wcurs.init;
6115 			wfont = wfont.init;
6116 			wparent = wparent.init;
6117 			wregion = wregion.init;
6118 			wtext = wtext.init;
6119 			deleteThisBackgroundBrush();
6120 			//ccollection.children = null; // Not GC-safe in dtor.
6121 			//ccollection = null; // ? Causes bad things. Leaving it will do just fine.
6122 		}
6123 		
6124 		if(!isHandleCreated)
6125 			return;
6126 		
6127 		destroyHandle();
6128 		/+
6129 		//assert(hwnd == HWND.init); // Zombie trips this. (Not anymore with the hwnd-prop)
6130 		if(hwnd)
6131 		{
6132 			assert(!IsWindow(hwnd));
6133 			hwnd = HWND.init;
6134 		}
6135 		+/
6136 		assert(hwnd == HWND.init);
6137 		
6138 		onDisposed(EventArgs.empty);
6139 	}
6140 	
6141 	
6142 	protected:
6143 	
6144 	///
6145 	@property Size defaultSize() // getter
6146 	{
6147 		return Size(0, 0);
6148 	}
6149 	
6150 	
6151 	/+
6152 	// TODO: implement.
6153 	@property EventHandlerList events() // getter
6154 	{
6155 	}
6156 	+/
6157 	
6158 	
6159 	/+
6160 	// TODO: implement. Is this worth implementing?
6161 	
6162 	// Set to -1 to reset cache.
6163 	final @property void fontHeight(int fh) // setter
6164 	{
6165 		
6166 	}
6167 	
6168 	
6169 	final @property int fontHeight() // getter
6170 	{
6171 		return fonth;
6172 	}
6173 	+/
6174 	
6175 	
6176 	///
6177 	//final void resizeRedraw(bool byes) // setter
6178 	public final @property void resizeRedraw(bool byes) // setter
6179 	{
6180 		/+
6181 		// These class styles get lost sometimes so don't rely on them.
6182 		LONG cl = _classStyle();
6183 		if(byes)
6184 			cl |= CS_HREDRAW | CS_VREDRAW;
6185 		else
6186 			cl &= ~(CS_HREDRAW | CS_VREDRAW);
6187 		
6188 		_classStyle(cl);
6189 		+/
6190 		szdraw = byes;
6191 	}
6192 	
6193 	/// ditto
6194 	final @property bool resizeRedraw() // getter
6195 	{
6196 		//return (_classStyle() & (CS_HREDRAW | CS_VREDRAW)) != 0;
6197 		return szdraw;
6198 	}
6199 	
6200 	
6201 	/+
6202 	// ///
6203 	// I don't think this is reliable.
6204 	final bool hasVisualStyle() // getter
6205 	{
6206 		bool result = false;
6207 		HWND hw = handle; // Always reference handle.
6208 		HMODULE huxtheme = GetModuleHandleA("uxtheme.dll");
6209 		//HMODULE huxtheme = LoadLibraryA("uxtheme.dll");
6210 		if(huxtheme)
6211 		{
6212 			auto getwintheme = cast(typeof(&GetWindowTheme))GetProcAddress(huxtheme, "GetWindowTheme");
6213 			if(getwintheme)
6214 			{
6215 				result = getwintheme(hw) != null;
6216 			}
6217 			//FreeLibrary(huxtheme);
6218 		}
6219 		return result;
6220 	}
6221 	+/
6222 	
6223 	
6224 	package final void _disableVisualStyle()
6225 	{
6226 		assert(isHandleCreated);
6227 		
6228 		HMODULE hmuxt;
6229 		hmuxt = GetModuleHandleA("uxtheme.dll");
6230 		if(hmuxt)
6231 		{
6232 			auto setWinTheme = cast(typeof(&SetWindowTheme))GetProcAddress(hmuxt, "SetWindowTheme");
6233 			if(setWinTheme)
6234 			{
6235 				setWinTheme(hwnd, " "w.ptr, " "w.ptr); // Clear the theme.
6236 			}
6237 		}
6238 	}
6239 	
6240 	
6241 	///
6242 	public final void disableVisualStyle(bool byes = true)
6243 	{
6244 		if(!byes)
6245 		{
6246 			if(cbits & CBits.VSTYLE)
6247 				return;
6248 			cbits |= CBits.VSTYLE;
6249 			
6250 			if(isHandleCreated)
6251 			{
6252 				_crecreate();
6253 			}
6254 		}
6255 		else
6256 		{
6257 			if(!(cbits & CBits.VSTYLE))
6258 				return;
6259 			cbits &= ~CBits.VSTYLE;
6260 			
6261 			if(isHandleCreated)
6262 				_disableVisualStyle();
6263 		}
6264 	}
6265 	
6266 	deprecated public final void enableVisualStyle(bool byes = true)
6267 	{
6268 		return disableVisualStyle(!byes);
6269 	}
6270 	
6271 	
6272 	///
6273 	ControlCollection createControlsInstance()
6274 	{
6275 		return new ControlCollection(this);
6276 	}
6277 	
6278 	
6279 	deprecated package final void createClassHandle(Dstring className)
6280 	{
6281 		if(!wparent || !wparent.handle || killing)
6282 		{
6283 			create_err:
6284 			throw new DflException("Control creation failure");
6285 		}
6286 		
6287 		// This is here because referencing wparent.handle might create me.
6288 		//if(created)
6289 		if(isHandleCreated)
6290 			return;
6291 		
6292 		Application.creatingControl(this);
6293 		hwnd = dfl.internal.utf.createWindowEx(wexstyle, className, wtext, wstyle, wrect.x, wrect.y,
6294 			wrect.width, wrect.height, wparent.handle, HMENU.init, Application.getInstance(), null);
6295 		if(!hwnd)
6296 			goto create_err;
6297 	}
6298 	
6299 	
6300 	///
6301 	// Override to change the creation parameters.
6302 	// Be sure to call super.createParams() or all the create params will need to be filled.
6303 	protected void createParams(ref CreateParams cp)
6304 	{
6305 		with(cp)
6306 		{
6307 			className = CONTROL_CLASSNAME;
6308 			caption = wtext;
6309 			param = null;
6310 			//parent = wparent.handle;
6311 			parent = wparent ? wparent.handle : HWND.init;
6312 			menu = HMENU.init;
6313 			inst = Application.getInstance();
6314 			x = wrect.x;
6315 			y = wrect.y;
6316 			width = wrect.width;
6317 			height = wrect.height;
6318 			classStyle = wclassStyle;
6319 			exStyle = wexstyle;
6320 			wstyle |= WS_VISIBLE;
6321 			if(!(cbits & CBits.VISIBLE))
6322 				wstyle &= ~WS_VISIBLE;
6323 			style = wstyle;
6324 		}
6325 	}
6326 	
6327 	
6328 	///
6329 	protected void createHandle()
6330 	{
6331 		// Note: if modified, Form.createHandle() should be modified as well.
6332 		
6333 		if(isHandleCreated)
6334 			return;
6335 		
6336 		//createClassHandle(CONTROL_CLASSNAME);
6337 		
6338 		/+
6339 		if(!wparent || !wparent.handle || killing)
6340 		{
6341 			create_err:
6342 			//throw new DflException("Control creation failure");
6343 			throw new DflException(Object.toString() ~ " creation failure"); // ?
6344 		}
6345 		+/
6346 		
6347 		debug
6348 		{
6349 			Dstring er;
6350 		}
6351 		if(killing)
6352 		{
6353 			debug
6354 			{
6355 				er = "the control is being disposed";
6356 			}
6357 			
6358 			debug(APP_PRINT)
6359 			{
6360 				cprintf("Creating Control handle while disposing.\n");
6361 			}
6362 			
6363 			create_err:
6364 			Dstring kmsg = "Control creation failure";
6365 			if(name.length)
6366 				kmsg ~= " (" ~ name ~ ")";
6367 			debug
6368 			{
6369 				if(er.length)
6370 					kmsg ~= " - " ~ er;
6371 			}
6372 			throw new DflException(kmsg);
6373 			//throw new DflException(Object.toString() ~ " creation failure"); // ?
6374 		}
6375 		
6376 		// Need the parent's handle to exist.
6377 		if(wparent)
6378 			wparent.createHandle();
6379 		
6380 		// This is here because wparent.createHandle() might create me.
6381 		//if(created)
6382 		if(isHandleCreated)
6383 			return;
6384 		
6385 		CreateParams cp;
6386 		/+
6387 		DWORD prevClassStyle;
6388 		prevClassStyle = wclassStyle;
6389 		+/
6390 		
6391 		createParams(cp);
6392 		assert(!isHandleCreated); // Make sure the handle wasn't created in createParams().
6393 		
6394 		with(cp)
6395 		{
6396 			wtext = caption;
6397 			//wrect = Rect(x, y, width, height); // This gets updated in WM_CREATE.
6398 			wclassStyle = classStyle;
6399 			wexstyle = exStyle;
6400 			wstyle = style;
6401 			
6402 			//if(style & WS_CHILD) // Breaks context-help.
6403 			if((ctrlStyle & ControlStyles.CONTAINER_CONTROL) && (style & WS_CHILD))
6404 			{
6405 				exStyle |= WS_EX_CONTROLPARENT;
6406 			}
6407 			
6408 			bool vis = (style & WS_VISIBLE) != 0;
6409 			
6410 			Application.creatingControl(this);
6411 			hwnd = dfl.internal.utf.createWindowEx(exStyle, className, caption, (style & ~WS_VISIBLE), x, y,
6412 				width, height, parent, menu, inst, param);
6413 			if(!hwnd)
6414 			{
6415 				debug(APP_PRINT)
6416 				{
6417 					cprintf("CreateWindowEx failed."
6418 						" (exStyle=0x%X, className=`%.*s`, caption=`%.*s`, style=0x%X, x=%d, y=%d, width=%d, height=%d,"
6419 						" parent=0x%X, menu=0x%X, inst=0x%X, param=0x%X)\n",
6420 						exStyle, className, caption, style, x, y, width, height,
6421 						parent, menu, inst, param);
6422 				}
6423 				
6424 				debug
6425 				{
6426 					er = std..string.format("CreateWindowEx failed {className=%s;exStyle=0x%X;style=0x%X;parent=0x%X;menu=0x%X;inst=0x%X;}",
6427 						className, exStyle, style, cast(void*)parent, cast(void*)menu, cast(void*)inst);
6428 				}
6429 				
6430 				goto create_err;
6431 			}
6432 			
6433 			if(vis)
6434 				doShow(); // Properly fires onVisibleChanged.
6435 		}
6436 		
6437 		//onHandleCreated(EventArgs.empty); // Called in WM_CREATE now.
6438 	}
6439 	
6440 	
6441 	package final void _createHandle()
6442 	{
6443 		createHandle();
6444 	}
6445 	
6446 	
6447 	///
6448 	public final @property bool recreatingHandle() // getter
6449 	{
6450 		if(cbits & CBits.RECREATING)
6451 			return true;
6452 		return false;
6453 	}
6454 	
6455 	
6456 	private void _setAllRecreating()
6457 	{
6458 		cbits |= CBits.RECREATING;
6459 		foreach(Control cc; controls)
6460 		{
6461 			cc._setAllRecreating();
6462 		}
6463 	}
6464 	
6465 	
6466 	///
6467 	protected void recreateHandle()
6468 	in
6469 	{
6470 		assert(!recreatingHandle);
6471 	}
6472 	body
6473 	{
6474 		if(!isHandleCreated)
6475 			return;
6476 		
6477 		if(recreatingHandle)
6478 			return;
6479 		
6480 		bool hfocus = focused;
6481 		HWND prevHwnd = GetWindow(hwnd, GW_HWNDPREV);
6482 		
6483 		_setAllRecreating();
6484 		//scope(exit)
6485 		//	cbits &= ~CBits.RECREATING; // Now done from WM_CREATE.
6486 		
6487 		destroyHandle();
6488 		createHandle();
6489 		
6490 		if(prevHwnd)
6491 			SetWindowPos(hwnd, prevHwnd, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
6492 		else
6493 			SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
6494 		if(hfocus)
6495 			select();
6496 	}
6497 	
6498 	
6499 	///
6500 	void destroyHandle()
6501 	{
6502 		if(!isHandleCreated)
6503 			return;
6504 		
6505 		DestroyWindow(hwnd);
6506 		
6507 		// This stuff is done in WM_DESTROY because DestroyWindow() could be called elsewhere..
6508 		//hwnd = HWND.init; // Done in WM_DESTROY.
6509 		//onHandleDestroyed(EventArgs.empty); // Done in WM_DESTROY.
6510 	}
6511 	
6512 	
6513 	private final void fillRecreationData()
6514 	{
6515 		//cprintf(" { fillRecreationData %.*s }\n", name);
6516 		
6517 		if(!(ctrlStyle & ControlStyles.CACHE_TEXT))
6518 			wtext = _fetchText();
6519 		
6520 		//wclassStyle = _fetchClassLong(); // ?
6521 		
6522 		// Fetch children.
6523 		Control[] ccs;
6524 		foreach(Control cc; controls)
6525 		{
6526 			ccs ~= cc;
6527 		}
6528 		ccollection.children = ccs;
6529 	}
6530 	
6531 	
6532 	///
6533 	protected void onDisposed(EventArgs ea)
6534 	{
6535 		disposed(this, ea);
6536 	}
6537 	
6538 	
6539 	///
6540 	protected final bool getStyle(ControlStyles flag)
6541 	{
6542 		return (ctrlStyle & flag) != 0;
6543 	}
6544 	
6545 	/// ditto
6546 	protected final void setStyle(ControlStyles flag, bool value)
6547 	{
6548 		if(flag & ControlStyles.CACHE_TEXT)
6549 		{
6550 			if(value)
6551 				wtext = _fetchText();
6552 			else
6553 				wtext = null;
6554 		}
6555 		
6556 		if(value)
6557 			ctrlStyle |= flag;
6558 		else
6559 			ctrlStyle &= ~flag;
6560 	}
6561 	
6562 	
6563 	///
6564 	// Only for setStyle() styles that are part of hwnd and wndclass styles.
6565 	protected final void updateStyles()
6566 	{
6567 		LONG newClassStyles = _classStyle();
6568 		LONG newWndStyles = _style();
6569 		
6570 		if(ctrlStyle & ControlStyles.STANDARD_DOUBLE_CLICK)
6571 			newClassStyles |= CS_DBLCLKS;
6572 		else
6573 			newClassStyles &= ~CS_DBLCLKS;
6574 		
6575 		/+
6576 		if(ctrlStyle & ControlStyles.RESIZE_REDRAW)
6577 			newClassStyles |= CS_HREDRAW | CS_VREDRAW;
6578 		else
6579 			newClassStyles &= ~(CS_HREDRAW | CS_VREDRAW);
6580 		+/
6581 		
6582 		/+
6583 		if(ctrlStyle & ControlStyles.SELECTABLE)
6584 			newWndStyles |= WS_TABSTOP;
6585 		else
6586 			newWndStyles &= ~WS_TABSTOP;
6587 		+/
6588 		
6589 		_classStyle(newClassStyles);
6590 		_style(newWndStyles);
6591 	}
6592 	
6593 	
6594 	///
6595 	final bool getTopLevel()
6596 	{
6597 		// return GetParent(hwnd) == HWND.init;
6598 		return wparent is null;
6599 	}
6600 	
6601 	
6602 	package final void alayout(Control ctrl, bool vcheck = true)
6603 	{
6604 		if(vcheck && !visible)
6605 			return;
6606 		
6607 		if(cbits & CBits.IN_LAYOUT)
6608 			return;
6609 		
6610 		//if(_allowLayout)
6611 		if(!_disallowLayout)
6612 		{
6613 			//cprintf("alayout\n");
6614 			scope LayoutEventArgs lea = new LayoutEventArgs(ctrl);
6615 			onLayout(lea);
6616 		}
6617 	}
6618 	
6619 	
6620 	// Z-order of controls has changed.
6621 	package final void vchanged()
6622 	{
6623 		// Z-order can't change if it's not created or invisible.
6624 		//if(!isHandleCreated || !visible)
6625 		//	return;
6626 		
6627 		version(RADIO_GROUP_LAYOUT)
6628 		{
6629 			//cprintf("vchanged\n");
6630 			
6631 			bool foundRadio = false;
6632 			
6633 			foreach(Control ctrl; ccollection)
6634 			{
6635 				if(!ctrl.visible)
6636 					continue;
6637 				
6638 				if(ctrl._rtype() & 1) // Radio type.
6639 				{
6640 					LONG wlg;
6641 					wlg = ctrl._style();
6642 					if(foundRadio)
6643 					{
6644 						if(wlg & WS_GROUP)
6645 							//ctrl._style(wlg & ~WS_GROUP);
6646 							ctrl._style(wlg & ~(WS_GROUP | WS_TABSTOP));
6647 					}
6648 					else
6649 					{
6650 						foundRadio = true;
6651 						
6652 						if(!(wlg & WS_GROUP))
6653 							//ctrl._style(wlg | WS_GROUP);
6654 							ctrl._style(wlg | WS_GROUP | WS_TABSTOP);
6655 					}
6656 				}
6657 				else
6658 				{
6659 					// Found non-radio so reset group.
6660 					// Update: only reset group if found ctrl with WS_EX_CONTROLPARENT.
6661 					// TODO: check if correct implementation.
6662 					if(ctrl._exStyle() & WS_EX_CONTROLPARENT)
6663 						foundRadio = false;
6664 				}
6665 			}
6666 		}
6667 	}
6668 	
6669 	
6670 	///
6671 	// Called after adding the control to a container.
6672 	protected void initLayout()
6673 	{
6674 		assert(wparent !is null);
6675 		if(visible && created) // ?
6676 		{
6677 			wparent.vchanged();
6678 			wparent.alayout(this);
6679 		}
6680 	}
6681 	
6682 	
6683 	///
6684 	protected void onLayout(LayoutEventArgs lea)
6685 	{
6686 		// Note: exception could cause failure to restore.
6687 		//suspendLayout();
6688 		cbits |= CBits.IN_LAYOUT;
6689 		
6690 		debug(EVENT_PRINT)
6691 		{
6692 			cprintf("{ Event: onLayout - Control %.*s }\n", name);
6693 		}
6694 		
6695 		Rect area;
6696 		area = displayRectangle;
6697 		
6698 		foreach(Control ctrl; ccollection)
6699 		{
6700 			if(!ctrl.visible || !ctrl.created)
6701 				continue;
6702 			if(ctrl._rtype() & (2 | 4)) // Mdichild | Tabpage
6703 				continue;
6704 			
6705 			//Rect prevctrlbounds;
6706 			//prevctrlbounds = ctrl.bounds;
6707 			//ctrl.suspendLayout(); // Note: exception could cause failure to restore.
6708 			switch(ctrl.sdock)
6709 			{
6710 				case DockStyle.NONE:
6711 					/+
6712 					if(ctrl.anch & (AnchorStyles.RIGHT | AnchorStyles.BOTTOM)) // If none of these are set, no point in doing any anchor code.
6713 					{
6714 						Rect newb;
6715 						newb = ctrl.bounds;
6716 						if(ctrl.anch & AnchorStyles.RIGHT)
6717 						{
6718 							if(ctrl.anch & AnchorStyles.LEFT)
6719 								newb.width += bounds.width - originalBounds.width;
6720 							else
6721 								newb.x += bounds.width - originalBounds.width;
6722 						}
6723 						if(ctrl.anch & AnchorStyles.BOTTOM)
6724 						{
6725 							if(ctrl.anch & AnchorStyles.LEFT)
6726 								newb.height += bounds.height - originalBounds.height;
6727 							else
6728 								newb.y += bounds.height - originalBounds.height;
6729 						}
6730 						if(newb != ctrl.bounds)
6731 							ctrl.bounds = newb;
6732 					}
6733 					+/
6734 					break;
6735 				
6736 				case DockStyle.LEFT:
6737 					ctrl.setBoundsCore(area.x, area.y, 0, area.height, cast(BoundsSpecified)(BoundsSpecified.LOCATION | BoundsSpecified.HEIGHT));
6738 					area.x = area.x + ctrl.width;
6739 					area.width = area.width - ctrl.width;
6740 					break;
6741 				
6742 				case DockStyle.TOP:
6743 					ctrl.setBoundsCore(area.x, area.y, area.width, 0, cast(BoundsSpecified)(BoundsSpecified.LOCATION | BoundsSpecified.WIDTH));
6744 					area.y = area.y + ctrl.height;
6745 					area.height = area.height - ctrl.height;
6746 					break;
6747 				
6748 				case DockStyle.FILL:
6749 					//ctrl.bounds(Rect(area.x, area.y, area.width, area.height));
6750 					ctrl.bounds = area;
6751 					// area = ?
6752 					break;
6753 				
6754 				case DockStyle.BOTTOM:
6755 					ctrl.setBoundsCore(area.x, area.bottom - ctrl.height, area.width, 0, cast(BoundsSpecified)(BoundsSpecified.LOCATION | BoundsSpecified.WIDTH));
6756 					area.height = area.height - ctrl.height;
6757 					break;
6758 				
6759 				case DockStyle.RIGHT:
6760 					ctrl.setBoundsCore(area.right - ctrl.width, area.y, 0, area.height, cast(BoundsSpecified)(BoundsSpecified.LOCATION | BoundsSpecified.HEIGHT));
6761 					area.width = area.width - ctrl.width;
6762 					break;
6763 				
6764 				default:
6765 					assert(0);
6766 			}
6767 			//ctrl.resumeLayout(true);
6768 			//ctrl.resumeLayout(prevctrlbounds != ctrl.bounds);
6769 		}
6770 		
6771 		layout(this, lea);
6772 		
6773 		//resumeLayout(false);
6774 		cbits &= ~CBits.IN_LAYOUT;
6775 	}
6776 	
6777 	
6778 	/+
6779 	// Not sure what to do here.
6780 	deprecated bool isInputChar(char charCode)
6781 	{
6782 		return false;
6783 	}
6784 	+/
6785 	
6786 	
6787 	///
6788 	void setVisibleCore(bool byes)
6789 	{
6790 		if(isHandleCreated)
6791 		{
6792 			//wstyle = GetWindowLongA(hwnd, GWL_STYLE);
6793 			if(visible == byes)
6794 				return;
6795 			
6796 			//ShowWindow(hwnd, byes ? SW_SHOW : SW_HIDE);
6797 			if(byes)
6798 				doShow();
6799 			else
6800 				doHide();
6801 		}
6802 		else
6803 		{
6804 			if(byes)
6805 			{
6806 				cbits |= CBits.VISIBLE;
6807 				wstyle |= WS_VISIBLE;
6808 				createControl();
6809 			}
6810 			else
6811 			{
6812 				cbits &= ~CBits.VISIBLE;
6813 				wstyle &= ~WS_VISIBLE;
6814 				return; // Not created and being hidden..
6815 			}
6816 		}
6817 	}
6818 	
6819 	
6820 	package final bool _wantTabKey()
6821 	{
6822 		if(ctrlStyle & ControlStyles.WANT_TAB_KEY)
6823 			return true;
6824 		return false;
6825 	}
6826 	
6827 	
6828 	///
6829 	// Return true if processed.
6830 	protected bool processKeyEventArgs(ref Message msg)
6831 	{
6832 		switch(msg.msg)
6833 		{
6834 			case WM_KEYDOWN:
6835 				{
6836 					scope KeyEventArgs kea = new KeyEventArgs(cast(Keys)(msg.wParam | modifierKeys));
6837 					
6838 					ushort repeat = msg.lParam & 0xFFFF; // First 16 bits.
6839 					for(; repeat; repeat--)
6840 					{
6841 						//kea.handled = false;
6842 						onKeyDown(kea);
6843 					}
6844 					
6845 					if(kea.handled)
6846 						return true;
6847 				}
6848 				break;
6849 			
6850 			case WM_KEYUP:
6851 				{
6852 					// Repeat count is always 1 for key up.
6853 					scope KeyEventArgs kea = new KeyEventArgs(cast(Keys)(msg.wParam | modifierKeys));
6854 					onKeyUp(kea);
6855 					if(kea.handled)
6856 						return true;
6857 				}
6858 				break;
6859 			
6860 			case WM_CHAR:
6861 				{
6862 					scope KeyPressEventArgs kpea = new KeyPressEventArgs(cast(dchar)msg.wParam, modifierKeys);
6863 					onKeyPress(kpea);
6864 					if(kpea.handled)
6865 						return true;
6866 				}
6867 				break;
6868 			
6869 			default:
6870 		}
6871 		
6872 		defWndProc(msg);
6873 		return !msg.result;
6874 	}
6875 	
6876 	
6877 	package final bool _processKeyEventArgs(ref Message msg)
6878 	{
6879 		return processKeyEventArgs(msg);
6880 	}
6881 	
6882 	
6883 	/+
6884 	bool processKeyPreview(ref Message m)
6885 	{
6886 		if(wparent)
6887 			return wparent.processKeyPreview(m);
6888 		return false;
6889 	}
6890 	
6891 	
6892 	protected bool processDialogChar(dchar charCode)
6893 	{
6894 		if(wparent)
6895 			return wparent.processDialogChar(charCode);
6896 		return false;
6897 	}
6898 	+/
6899 	
6900 	
6901 	///
6902 	protected bool processMnemonic(dchar charCode)
6903 	{
6904 		return false;
6905 	}
6906 	
6907 	
6908 	package bool _processMnemonic(dchar charCode)
6909 	{
6910 		return processMnemonic(charCode);
6911 	}
6912 	
6913 	
6914 	// Retain DFL 0.9.5 compatibility.
6915 	public deprecated void setDFL095()
6916 	{
6917 		version(SET_DFL_095)
6918 		{
6919 			pragma(msg, "DFL: DFL 0.9.5 compatibility set at compile time");
6920 		}
6921 		else
6922 		{
6923 			//_compat = CCompat.DFL095;
6924 			Application.setCompat(DflCompat.CONTROL_RECREATE_095);
6925 		}
6926 	}
6927 	
6928 	private enum CCompat: ubyte
6929 	{
6930 		NONE = 0,
6931 		DFL095 = 1,
6932 	}
6933 	
6934 	version(SET_DFL_095)
6935 		package enum _compat = CCompat.DFL095;
6936 	else version(DFL_NO_COMPAT)
6937 		package enum _compat = CCompat.NONE;
6938 	else
6939 		package @property CCompat _compat() // getter
6940 			{ if(Application._compat & DflCompat.CONTROL_RECREATE_095) return CCompat.DFL095; return CCompat.NONE; }
6941 	
6942 	
6943 	package final void _crecreate()
6944 	{
6945 		if(CCompat.DFL095 != _compat)
6946 		{
6947 			if(!recreatingHandle)
6948 				recreateHandle();
6949 		}
6950 	}
6951 	
6952 	
6953 	package:
6954 	HWND hwnd;
6955 	//AnchorStyles anch = cast(AnchorStyles)(AnchorStyles.TOP | AnchorStyles.LEFT);
6956 	//bool cvalidation = true;
6957 	version(DFL_NO_MENUS)
6958 	{
6959 	}
6960 	else
6961 	{
6962 		ContextMenu cmenu;
6963 	}
6964 	DockStyle sdock = DockStyle.NONE;
6965 	Dstring _ctrlname;
6966 	Object otag;
6967 	Color backc, forec;
6968 	Rect wrect;
6969 	//Rect oldwrect;
6970 	Size wclientsz;
6971 	Cursor wcurs;
6972 	Font wfont;
6973 	Control wparent;
6974 	Region wregion;
6975 	ControlCollection ccollection;
6976 	Dstring wtext; // After creation, this isn't used unless ControlStyles.CACHE_TEXT.
6977 	ControlStyles ctrlStyle = ControlStyles.STANDARD_CLICK | ControlStyles.STANDARD_DOUBLE_CLICK /+ | ControlStyles.RESIZE_REDRAW +/ ;
6978 	HBRUSH _hbrBg;
6979 	RightToLeft rtol = RightToLeft.INHERIT;
6980 	uint _disallowLayout = 0;
6981 	
6982 	version(DFL_NO_DRAG_DROP) {} else
6983 	{
6984 		DropTarget droptarget = null;
6985 	}
6986 	
6987 	// Note: WS_VISIBLE is not reliable.
6988 	LONG wstyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; // Child, visible and enabled by default.
6989 	LONG wexstyle;
6990 	LONG wclassStyle = WNDCLASS_STYLE;
6991 	
6992 	
6993 	enum CBits: uint
6994 	{
6995 		NONE = 0x0,
6996 		MENTER = 0x1, // Is mouse entered? Only valid if -trackMouseEvent- is non-null.
6997 		KILLING = 0x2,
6998 		OWNED = 0x4,
6999 		//ALLOW_LAYOUT = 0x8,
7000 		CLICKING = 0x10,
7001 		NEED_CALC_SIZE = 0x20,
7002 		SZDRAW = 0x40,
7003 		OWNEDBG = 0x80,
7004 		HANDLE_CREATED = 0x100, // debug only
7005 		SW_SHOWN = 0x200,
7006 		SW_HIDDEN = 0x400,
7007 		CREATED = 0x800,
7008 		NEED_INIT_LAYOUT = 0x1000,
7009 		IN_LAYOUT = 0x2000,
7010 		FVISIBLE = 0x4000,
7011 		VISIBLE = 0x8000,
7012 		NOCLOSING = 0x10000,
7013 		ASCROLL = 0x20000,
7014 		ASCALE = 0x40000,
7015 		FORM = 0x80000,
7016 		RECREATING = 0x100000,
7017 		HAS_LAYOUT = 0x200000,
7018 		VSTYLE = 0x400000, // If not forced off.
7019 		FORMLOADED = 0x800000, // If not forced off.
7020 		ENABLED = 0x1000000, // Enabled state, not considering the parent.
7021 	}
7022 	
7023 	//CBits cbits = CBits.ALLOW_LAYOUT;
7024 	//CBits cbits = CBits.NONE;
7025 	CBits cbits = CBits.VISIBLE | CBits.VSTYLE | CBits.ENABLED;
7026 	
7027 	
7028 	final:
7029 	
7030 	@property void menter(bool byes) // setter
7031 		{ if(byes) cbits |= CBits.MENTER; else cbits &= ~CBits.MENTER; }
7032 	@property bool menter() // getter
7033 		{ return (cbits & CBits.MENTER) != 0; }
7034 	
7035 	@property void killing(bool byes) // setter
7036 		//{ if(byes) cbits |= CBits.KILLING; else cbits &= ~CBits.KILLING; }
7037 		{ assert(byes); if(byes) cbits |= CBits.KILLING; }
7038 	@property bool killing() // getter
7039 		{ return (cbits & CBits.KILLING) != 0; }
7040 	
7041 	@property void owned(bool byes) // setter
7042 		{ if(byes) cbits |= CBits.OWNED; else cbits &= ~CBits.OWNED; }
7043 	@property bool owned() // getter
7044 		{ return (cbits & CBits.OWNED) != 0; }
7045 	
7046 	/+
7047 	void _allowLayout(bool byes) // setter
7048 		{ if(byes) cbits |= CBits.ALLOW_LAYOUT; else cbits &= ~CBits.ALLOW_LAYOUT; }
7049 	bool _allowLayout() // getter
7050 		{ return (cbits & CBits.ALLOW_LAYOUT) != 0; }
7051 	+/
7052 	
7053 	@property void _clicking(bool byes) // setter
7054 		{ if(byes) cbits |= CBits.CLICKING; else cbits &= ~CBits.CLICKING; }
7055 	@property bool _clicking() // getter
7056 		{ return (cbits & CBits.CLICKING) != 0; }
7057 	
7058 	@property void needCalcSize(bool byes) // setter
7059 		{ if(byes) cbits |= CBits.NEED_CALC_SIZE; else cbits &= ~CBits.NEED_CALC_SIZE; }
7060 	@property bool needCalcSize() // getter
7061 		{ return (cbits & CBits.NEED_CALC_SIZE) != 0; }
7062 	
7063 	@property void szdraw(bool byes) // setter
7064 		{ if(byes) cbits |= CBits.SZDRAW; else cbits &= ~CBits.SZDRAW; }
7065 	@property bool szdraw() // getter
7066 		{ return (cbits & CBits.SZDRAW) != 0; }
7067 	
7068 	@property void ownedbg(bool byes) // setter
7069 		{ if(byes) cbits |= CBits.OWNEDBG; else cbits &= ~CBits.OWNEDBG; }
7070 	@property bool ownedbg() // getter
7071 		{ return (cbits & CBits.OWNEDBG) != 0; }
7072 	
7073 	debug
7074 	{
7075 		@property void _handlecreated(bool byes) // setter
7076 			{ if(byes) cbits |= CBits.HANDLE_CREATED; else cbits &= ~CBits.HANDLE_CREATED; }
7077 		@property bool _handlecreated() // getter
7078 			{ return (cbits & CBits.HANDLE_CREATED) != 0; }
7079 	}
7080 	
7081 	
7082 	@property LONG _exStyle()
7083 	{
7084 		// return GetWindowLongA(hwnd, GWL_EXSTYLE);
7085 		return wexstyle;
7086 	}
7087 	
7088 	
7089 	@property void _exStyle(LONG wl)
7090 	{
7091 		if(isHandleCreated)
7092 		{
7093 			SetWindowLongA(hwnd, GWL_EXSTYLE, wl);
7094 		}
7095 		
7096 		wexstyle = wl;
7097 	}
7098 	
7099 	
7100 	@property LONG _style()
7101 	{
7102 		// return GetWindowLongA(hwnd, GWL_STYLE);
7103 		return wstyle;
7104 	}
7105 	
7106 	
7107 	@property void _style(LONG wl)
7108 	{
7109 		if(isHandleCreated)
7110 		{
7111 			SetWindowLongA(hwnd, GWL_STYLE, wl);
7112 		}
7113 		
7114 		wstyle = wl;
7115 	}
7116 	
7117 	
7118 	@property HBRUSH hbrBg() // getter
7119 	{
7120 		if(_hbrBg)
7121 			return _hbrBg;
7122 		if(backc == Color.empty && parent && backColor == parent.backColor)
7123 		{
7124 			ownedbg = false;
7125 			_hbrBg = parent.hbrBg;
7126 			return _hbrBg;
7127 		}
7128 		hbrBg = backColor.createBrush(); // Call hbrBg's setter and set ownedbg.
7129 		return _hbrBg;
7130 	}
7131 	
7132 	
7133 	@property void hbrBg(HBRUSH hbr) // setter
7134 	in
7135 	{
7136 		if(hbr)
7137 		{
7138 			assert(!_hbrBg);
7139 		}
7140 	}
7141 	body
7142 	{
7143 		_hbrBg = hbr;
7144 		ownedbg = true;
7145 	}
7146 	
7147 	
7148 	void deleteThisBackgroundBrush()
7149 	{
7150 		if(_hbrBg)
7151 		{
7152 			if(ownedbg)
7153 				DeleteObject(_hbrBg);
7154 			_hbrBg = HBRUSH.init;
7155 		}
7156 	}
7157 	
7158 	
7159 	LRESULT defwproc(UINT msg, WPARAM wparam, LPARAM lparam)
7160 	{
7161 		//return DefWindowProcA(hwnd, msg, wparam, lparam);
7162 		return dfl.internal.utf.defWindowProc(hwnd, msg, wparam, lparam);
7163 	}
7164 	
7165 	
7166 	LONG _fetchClassLong()
7167 	{
7168 		return GetClassLongA(hwnd, GCL_STYLE);
7169 	}
7170 	
7171 	
7172 	LONG _classStyle()
7173 	{
7174 		// return GetClassLongA(hwnd, GCL_STYLE);
7175 		// return wclassStyle;
7176 		
7177 		if(isHandleCreated)
7178 		{
7179 			// Always fetch because it's not guaranteed to be accurate.
7180 			wclassStyle = _fetchClassLong();
7181 		}
7182 		
7183 		return wclassStyle;
7184 	}
7185 	
7186 	
7187 	package void _classStyle(LONG cl)
7188 	{
7189 		if(isHandleCreated)
7190 		{
7191 			SetClassLongA(hwnd, GCL_STYLE, cl);
7192 		}
7193 		
7194 		wclassStyle = cl;
7195 	}
7196 }
7197 
7198 
7199 package abstract class ControlSuperClass: Control // dapi.d
7200 {
7201 	// Call previous wndProc().
7202 	abstract protected void prevWndProc(ref Message msg);
7203 	
7204 	
7205 	protected override void wndProc(ref Message msg)
7206 	{
7207 		switch(msg.msg)
7208 		{
7209 			case WM_PAINT:
7210 				{
7211 					RECT uprect;
7212 					//GetUpdateRect(hwnd, &uprect, true);
7213 					//onInvalidated(new InvalidateEventArgs(Rect(&uprect)));
7214 					
7215 					//if(!msg.wParam)
7216 						GetUpdateRect(hwnd, &uprect, false); // Preserve.
7217 					
7218 					prevWndProc(msg);
7219 					
7220 					// Now fake a normal paint event...
7221 					
7222 					scope Graphics gpx = new CommonGraphics(hwnd, GetDC(hwnd));
7223 					//scope Graphics gpx = new CommonGraphics(hwnd, msg.wParam ? cast(HDC)msg.wParam : GetDC(hwnd), msg.wParam ? false : true);
7224 					HRGN hrgn;
7225 					
7226 					hrgn = CreateRectRgnIndirect(&uprect);
7227 					SelectClipRgn(gpx.handle, hrgn);
7228 					DeleteObject(hrgn);
7229 					
7230 					scope PaintEventArgs pea = new PaintEventArgs(gpx, Rect(&uprect));
7231 					
7232 					// Can't erase the background now, Windows just painted..
7233 					//if(ps.fErase)
7234 					//{
7235 					//	prepareDc(gpx.handle);
7236 					//	onPaintBackground(pea);
7237 					//}
7238 					
7239 					prepareDc(gpx.handle);
7240 					onPaint(pea);
7241 				}
7242 				break;
7243 			
7244 			case WM_PRINTCLIENT:
7245 				{
7246 					prevWndProc(msg);
7247 					
7248 					scope Graphics gpx = new CommonGraphics(hwnd, GetDC(hwnd));
7249 					scope PaintEventArgs pea = new PaintEventArgs(gpx,
7250 						Rect(Point(0, 0), wclientsz));
7251 					
7252 					prepareDc(pea.graphics.handle);
7253 					onPaint(pea);
7254 				}
7255 				break;
7256 			
7257 			case WM_PRINT:
7258 				Control.defWndProc(msg);
7259 				break;
7260 			
7261 			case WM_ERASEBKGND:
7262 				Control.wndProc(msg);
7263 				break;
7264 			
7265 			case WM_NCACTIVATE:
7266 			case WM_NCCALCSIZE:
7267 			case WM_NCCREATE:
7268 			case WM_NCPAINT:
7269 				prevWndProc(msg);
7270 				break;
7271 			
7272 			case WM_KEYDOWN:
7273 			case WM_KEYUP:
7274 			case WM_CHAR:
7275 			case WM_SYSKEYDOWN:
7276 			case WM_SYSKEYUP:
7277 			case WM_SYSCHAR:
7278 			//case WM_IMECHAR:
7279 				super.wndProc(msg);
7280 				return;
7281 			
7282 			default:
7283 				prevWndProc(msg);
7284 				super.wndProc(msg);
7285 		}
7286 	}
7287 	
7288 	
7289 	override void defWndProc(ref Message m)
7290 	{
7291 		switch(m.msg)
7292 		{
7293 			case WM_KEYDOWN:
7294 			case WM_KEYUP:
7295 			case WM_CHAR:
7296 			case WM_SYSKEYDOWN:
7297 			case WM_SYSKEYUP:
7298 			case WM_SYSCHAR:
7299 			//case WM_IMECHAR: // ?
7300 				prevWndProc(m);
7301 				break;
7302 			
7303 			default:
7304 		}
7305 	}
7306 	
7307 	
7308 	protected override void onPaintBackground(PaintEventArgs pea)
7309 	{
7310 		Message msg;
7311 		
7312 		msg.hWnd = handle;
7313 		msg.msg = WM_ERASEBKGND;
7314 		msg.wParam = cast(WPARAM)pea.graphics.handle;
7315 		
7316 		prevWndProc(msg);
7317 		
7318 		// Don't paint the background twice.
7319 		//super.onPaintBackground(pea);
7320 		
7321 		// Event ?
7322 		//paintBackground(this, pea);
7323 	}
7324 }
7325 
7326 
7327 ///
7328 class ScrollableControl: Control // docmain
7329 {
7330 	// ///
7331 	deprecated void autoScroll(bool byes) // setter
7332 	{
7333 		if(byes)
7334 			cbits |= CBits.ASCROLL;
7335 		else
7336 			cbits &= ~CBits.ASCROLL;
7337 	}
7338 	
7339 	// /// ditto
7340 	deprecated bool autoScroll() // getter
7341 	{
7342 		return (cbits & CBits.ASCROLL) == CBits.ASCROLL;
7343 	}
7344 	
7345 	
7346 	// ///
7347 	deprecated final void autoScrollMargin(Size sz) // setter
7348 	{
7349 		//scrollmargin = sz;
7350 	}
7351 	
7352 	// /// ditto
7353 	deprecated final Size autoScrollMargin() // getter
7354 	{
7355 		//return scrollmargin;
7356 		return Size(0, 0);
7357 	}
7358 	
7359 	
7360 	// ///
7361 	deprecated final void autoScrollMinSize(Size sz) // setter
7362 	{
7363 		//scrollmin = sz;
7364 	}
7365 	
7366 	// /// ditto
7367 	deprecated final Size autoScrollMinSize() // getter
7368 	{
7369 		//return scrollmin;
7370 		return Size(0, 0);
7371 	}
7372 	
7373 	
7374 	// ///
7375 	deprecated final void autoScrollPosition(Point pt) // setter
7376 	{
7377 		//autoscrollpos = pt;
7378 	}
7379 	
7380 	// /// ditto
7381 	deprecated final Point autoScrollPosition() // getter
7382 	{
7383 		//return autoscrollpos;
7384 		return Point(0, 0);
7385 	}
7386 	
7387 	
7388 	///
7389 	final @property Size autoScaleBaseSize() // getter
7390 	{
7391 		return autossz;
7392 	}
7393 	
7394 	/// ditto
7395 	final @property void autoScaleBaseSize(Size newSize) // setter
7396 	in
7397 	{
7398 		assert(newSize.width > 0);
7399 		assert(newSize.height > 0);
7400 	}
7401 	body
7402 	{
7403 		autossz = newSize;
7404 	}
7405 	
7406 	
7407 	///
7408 	final @property void autoScale(bool byes) // setter
7409 	{
7410 		if(byes)
7411 			cbits |= CBits.ASCALE;
7412 		else
7413 			cbits &= ~CBits.ASCALE;
7414 	}
7415 	
7416 	/// ditto
7417 	final @property bool autoScale() // getter
7418 	{
7419 		return (cbits & CBits.ASCALE) == CBits.ASCALE;
7420 	}
7421 	
7422 	
7423 	final @property Point scrollPosition() // getter
7424 	{
7425 		return Point(xspos, yspos);
7426 	}
7427 	
7428 	
7429 	static Size calcScale(Size area, Size toScale, Size fromScale) // package
7430 	in
7431 	{
7432 		assert(fromScale.width);
7433 		assert(fromScale.height);
7434 	}
7435 	body
7436 	{
7437 		area.width = cast(int)(cast(float)area.width / cast(float)fromScale.width * cast(float)toScale.width);
7438 		area.height = cast(int)(cast(float)area.height / cast(float)fromScale.height * cast(float)toScale.height);
7439 		return area;
7440 	}
7441 	
7442 	
7443 	Size calcScale(Size area, Size toScale) // package
7444 	{
7445 		return calcScale(area, toScale, DEFAULT_SCALE);
7446 	}
7447 	
7448 	
7449 	final void _scale(Size toScale) // package
7450 	{
7451 		bool first = true;
7452 		
7453 		// Note: doesn't get to-scale for nested scrollable-controls.
7454 		void xscale(Control c, Size fromScale)
7455 		{
7456 			c.suspendLayout();
7457 			
7458 			if(first)
7459 			{
7460 				first = false;
7461 				c.size = calcScale(c.size, toScale, fromScale);
7462 			}
7463 			else
7464 			{
7465 				Point pt;
7466 				Size sz;
7467 				sz = calcScale(Size(c.left, c.top), toScale, fromScale);
7468 				pt = Point(sz.width, sz.height);
7469 				sz = calcScale(c.size, toScale, fromScale);
7470 				c.bounds = Rect(pt, sz);
7471 			}
7472 			
7473 			if(c.hasChildren)
7474 			{
7475 				ScrollableControl scc;
7476 				foreach(Control cc; c.controls)
7477 				{
7478 					scc = cast(ScrollableControl)cc;
7479 					if(scc)
7480 					{
7481 						if(scc.autoScale) // ?
7482 						{
7483 							xscale(scc, scc.autoScaleBaseSize);
7484 							scc.autoScaleBaseSize = toScale;
7485 						}
7486 					}
7487 					else
7488 					{
7489 						xscale(cc, fromScale);
7490 					}
7491 				}
7492 			}
7493 			
7494 			//c.resumeLayout(true);
7495 			c.resumeLayout(false); // Should still be perfectly proportionate if it was properly laid out before scaling.
7496 		}
7497 		
7498 		
7499 		xscale(this, autoScaleBaseSize);
7500 		autoScaleBaseSize = toScale;
7501 	}
7502 	
7503 	
7504 	final void _scale() // package
7505 	{
7506 		return _scale(getAutoScaleSize());
7507 	}
7508 	
7509 	
7510 	protected override void onControlAdded(ControlEventArgs ea)
7511 	{
7512 		super.onControlAdded(ea);
7513 		
7514 		if(created) // ?
7515 		if(isHandleCreated)
7516 		{
7517 			auto sc = cast(ScrollableControl)ea.control;
7518 			if(sc)
7519 			{
7520 				if(sc.autoScale)
7521 					sc._scale();
7522 			}
7523 			else
7524 			{
7525 				if(autoScale)
7526 					_scale();
7527 			}
7528 		}
7529 	}
7530 	
7531 	
7532 	//override final Rect displayRectangle() // getter
7533 	override @property Rect displayRectangle() // getter
7534 	{
7535 		Rect result = clientRectangle;
7536 		
7537 		// Subtract dock padding.
7538 		result.x = result.x + dpad.left;
7539 		result.width = result.width - dpad.right - dpad.left;
7540 		result.y = result.y + dpad.top;
7541 		result.height = result.height - dpad.bottom - dpad.top;
7542 		
7543 		// Add scroll width.
7544 		if(scrollSize.width > clientSize.width)
7545 			result.width = result.width + (scrollSize.width - clientSize.width);
7546 		if(scrollSize.height > clientSize.height)
7547 			result.height = result.height + (scrollSize.height - clientSize.height);
7548 		
7549 		// Adjust scroll position.
7550 		result.location = Point(result.location.x - scrollPosition.x, result.location.y - scrollPosition.y);
7551 		
7552 		return result;
7553 	}
7554 	
7555 	
7556 	///
7557 	final @property void scrollSize(Size sz) // setter
7558 	{
7559 		scrollsz = sz;
7560 		
7561 		_fixScrollBounds(); // Implies _adjustScrollSize().
7562 	}
7563 	
7564 	/// ditto
7565 	final @property Size scrollSize() // getter
7566 	{
7567 		return scrollsz;
7568 	}
7569 	
7570 	
7571 	///
7572 	class DockPaddingEdges
7573 	{
7574 		private:
7575 		
7576 		int _left, _top, _right, _bottom;
7577 		int _all;
7578 		//package void delegate() changed;
7579 		
7580 		
7581 		final:
7582 		
7583 		void changed()
7584 		{
7585 			dpadChanged();
7586 		}
7587 		
7588 		
7589 		public:
7590 		
7591 		///
7592 		@property void all(int x) // setter
7593 		{
7594 			_bottom = _right = _top = _left = _all = x;
7595 			
7596 			changed();
7597 		}
7598 		
7599 		/// ditto
7600 		final @property int all() // getter
7601 		{
7602 			return _all;
7603 		}
7604 		
7605 		/// ditto
7606 		@property void left(int x) // setter
7607 		{
7608 			_left = x;
7609 			
7610 			changed();
7611 		}
7612 		
7613 		/// ditto
7614 		@property int left() // getter
7615 		{
7616 			return _left;
7617 		}
7618 		
7619 		/// ditto
7620 		@property void top(int x) // setter
7621 		{
7622 			_top = x;
7623 			
7624 			changed();
7625 		}
7626 		
7627 		/// ditto
7628 		@property int top() // getter
7629 		{
7630 			return _top;
7631 		}
7632 		
7633 		/// ditto
7634 		@property void right(int x) // setter
7635 		{
7636 			_right = x;
7637 			
7638 			changed();
7639 		}
7640 		
7641 		/// ditto
7642 		@property int right() // getter
7643 		{
7644 			return _right;
7645 		}
7646 		
7647 		/// ditto
7648 		@property void bottom(int x) // setter
7649 		{
7650 			_bottom = x;
7651 			
7652 			changed();
7653 		}
7654 		
7655 		/// ditto
7656 		@property int bottom() // getter
7657 		{
7658 			return _bottom;
7659 		}
7660 	}
7661 	
7662 	
7663 	///
7664 	final @property DockPaddingEdges dockPadding() // getter
7665 	{
7666 		return dpad;
7667 	}
7668 	
7669 	
7670 	deprecated final void setAutoScrollMargin(int x, int y)
7671 	{
7672 		//
7673 	}
7674 	
7675 	
7676 	this()
7677 	{
7678 		super();
7679 		_init();
7680 	}
7681 	
7682 	
7683 	enum DEFAULT_SCALE = Size(5, 13);
7684 	
7685 	///
7686 	final @property void hScroll(bool byes) // setter
7687 	{
7688 		LONG wl = _style();
7689 		if(byes)
7690 			wl |= WS_HSCROLL;
7691 		else
7692 			wl &= ~WS_HSCROLL;
7693 		_style(wl);
7694 		
7695 		if(isHandleCreated)
7696 			redrawEntire();
7697 	}
7698 	
7699 	
7700 	/// ditto
7701 	final @property bool hScroll() // getter
7702 	{
7703 		return (_style() & WS_HSCROLL) != 0;
7704 	}
7705 	
7706 	
7707 	///
7708 	final @property void vScroll(bool byes) // setter
7709 	{
7710 		LONG wl = _style();
7711 		if(byes)
7712 			wl |= WS_VSCROLL;
7713 		else
7714 			wl &= ~WS_VSCROLL;
7715 		_style(wl);
7716 		
7717 		if(isHandleCreated)
7718 			redrawEntire();
7719 	}
7720 	
7721 	/// ditto
7722 	final @property bool vScroll() // getter
7723 	{
7724 		return (_style() & WS_VSCROLL) != 0;
7725 	}
7726 	
7727 	
7728 	protected:
7729 	
7730 	
7731 	/+
7732 	override void onLayout(LayoutEventArgs lea)
7733 	{
7734 		// ...
7735 		super.onLayout(lea);
7736 	}
7737 	+/
7738 	
7739 	
7740 	/+
7741 	override void scaleCore(float width, float height)
7742 	{
7743 		// Might not want to call super.scaleCore().
7744 	}
7745 	+/
7746 	
7747 	
7748 	override void wndProc(ref Message m)
7749 	{
7750 		switch(m.msg)
7751 		{
7752 			case WM_VSCROLL:
7753 				{
7754 					SCROLLINFO si = void;
7755 					si.cbSize = SCROLLINFO.sizeof;
7756 					si.fMask = SIF_ALL;
7757 					if(GetScrollInfo(m.hWnd, SB_VERT, &si))
7758 					{
7759 						int delta, maxp;
7760 						maxp = scrollSize.height - clientSize.height;
7761 						switch(LOWORD(m.wParam))
7762 						{
7763 							case SB_LINEDOWN:
7764 								if(yspos >= maxp)
7765 									return;
7766 								delta = maxp - yspos;
7767 								if(autossz.height < delta)
7768 									delta = autossz.height;
7769 								break;
7770 							case SB_LINEUP:
7771 								if(yspos <= 0)
7772 									return;
7773 								delta = yspos;
7774 								if(autossz.height < delta)
7775 									delta = autossz.height;
7776 								delta = -delta;
7777 								break;
7778 							case SB_PAGEDOWN:
7779 								if(yspos >= maxp)
7780 									return;
7781 								if(yspos >= maxp)
7782 									return;
7783 								delta = maxp - yspos;
7784 								if(clientSize.height < delta)
7785 									delta = clientSize.height;
7786 								break;
7787 							case SB_PAGEUP:
7788 								if(yspos <= 0)
7789 									return;
7790 								delta = yspos;
7791 								if(clientSize.height < delta)
7792 									delta = clientSize.height;
7793 								delta = -delta;
7794 								break;
7795 							case SB_THUMBTRACK:
7796 							case SB_THUMBPOSITION:
7797 								//delta = cast(int)HIWORD(m.wParam) - yspos; // Limited to 16-bits.
7798 								delta = si.nTrackPos - yspos;
7799 								break;
7800 							case SB_BOTTOM:
7801 								delta = maxp - yspos;
7802 								break;
7803 							case SB_TOP:
7804 								delta = -yspos;
7805 								break;
7806 							default:
7807 						}
7808 						yspos += delta;
7809 						SetScrollPos(m.hWnd, SB_VERT, yspos, TRUE);
7810 						ScrollWindow(m.hWnd, 0, -delta, null, null);
7811 					}
7812 				}
7813 				break;
7814 			
7815 			case WM_HSCROLL:
7816 				{
7817 					SCROLLINFO si = void;
7818 					si.cbSize = SCROLLINFO.sizeof;
7819 					si.fMask = SIF_ALL;
7820 					if(GetScrollInfo(m.hWnd, SB_HORZ, &si))
7821 					{
7822 						int delta, maxp;
7823 						maxp = scrollSize.width - clientSize.width;
7824 						switch(LOWORD(m.wParam))
7825 						{
7826 							case SB_LINERIGHT:
7827 								if(xspos >= maxp)
7828 									return;
7829 								delta = maxp - xspos;
7830 								if(autossz.width < delta)
7831 									delta = autossz.width;
7832 								break;
7833 							case SB_LINELEFT:
7834 								if(xspos <= 0)
7835 									return;
7836 								delta = xspos;
7837 								if(autossz.width < delta)
7838 									delta = autossz.width;
7839 								delta = -delta;
7840 								break;
7841 							case SB_PAGERIGHT:
7842 								if(xspos >= maxp)
7843 									return;
7844 								if(xspos >= maxp)
7845 									return;
7846 								delta = maxp - xspos;
7847 								if(clientSize.width < delta)
7848 									delta = clientSize.width;
7849 								break;
7850 							case SB_PAGELEFT:
7851 								if(xspos <= 0)
7852 									return;
7853 								delta = xspos;
7854 								if(clientSize.width < delta)
7855 									delta = clientSize.width;
7856 								delta = -delta;
7857 								break;
7858 							case SB_THUMBTRACK:
7859 							case SB_THUMBPOSITION:
7860 								//delta = cast(int)HIWORD(m.wParam) - xspos; // Limited to 16-bits.
7861 								delta = si.nTrackPos - xspos;
7862 								break;
7863 							case SB_RIGHT:
7864 								delta = maxp - xspos;
7865 								break;
7866 							case SB_LEFT:
7867 								delta = -xspos;
7868 								break;
7869 							default:
7870 						}
7871 						xspos += delta;
7872 						SetScrollPos(m.hWnd, SB_HORZ, xspos, TRUE);
7873 						ScrollWindow(m.hWnd, -delta, 0, null, null);
7874 					}
7875 				}
7876 				break;
7877 			
7878 			default:
7879 		}
7880 		
7881 		super.wndProc(m);
7882 	}
7883 	
7884 	
7885 	override void onMouseWheel(MouseEventArgs ea)
7886 	{
7887 		int maxp = scrollSize.height - clientSize.height;
7888 		int delta;
7889 		
7890 		UINT wlines;
7891 		if(!SystemParametersInfoA(SPI_GETWHEELSCROLLLINES, 0, &wlines, 0))
7892 			wlines = 3;
7893 		
7894 		if(ea.delta < 0)
7895 		{
7896 			if(yspos < maxp)
7897 			{
7898 				delta = maxp - yspos;
7899 				if(autossz.height * wlines < delta)
7900 					delta = autossz.height * wlines;
7901 				
7902 				yspos += delta;
7903 				SetScrollPos(hwnd, SB_VERT, yspos, TRUE);
7904 				ScrollWindow(hwnd, 0, -delta, null, null);
7905 			}
7906 		}
7907 		else
7908 		{
7909 			if(yspos > 0)
7910 			{
7911 				delta = yspos;
7912 				if(autossz.height * wlines < delta)
7913 					delta = autossz.height * wlines;
7914 				delta = -delta;
7915 				
7916 				yspos += delta;
7917 				SetScrollPos(hwnd, SB_VERT, yspos, TRUE);
7918 				ScrollWindow(hwnd, 0, -delta, null, null);
7919 			}
7920 		}
7921 		
7922 		super.onMouseWheel(ea);
7923 	}
7924 	
7925 	
7926 	override void onHandleCreated(EventArgs ea)
7927 	{
7928 		xspos = 0;
7929 		yspos = 0;
7930 		
7931 		super.onHandleCreated(ea);
7932 		
7933 		//_adjustScrollSize(FALSE);
7934 		if(hScroll || vScroll)
7935 		{
7936 			_adjustScrollSize(FALSE);
7937 			recalcEntire(); // Need to recalc frame.
7938 		}
7939 	}
7940 	
7941 	
7942 	override void onVisibleChanged(EventArgs ea)
7943 	{
7944 		if(visible)
7945 			_adjustScrollSize(FALSE);
7946 		
7947 		super.onVisibleChanged(ea);
7948 	}
7949 	
7950 	
7951 	private void _fixScrollBounds()
7952 	{
7953 		if(hScroll || vScroll)
7954 		{
7955 			int ydiff = 0, xdiff = 0;
7956 			
7957 			if(yspos > scrollSize.height - clientSize.height)
7958 			{
7959 				ydiff = (clientSize.height + yspos) - scrollSize.height;
7960 				yspos -= ydiff;
7961 				if(yspos < 0)
7962 				{
7963 					ydiff += yspos;
7964 					yspos = 0;
7965 				}
7966 			}
7967 			
7968 			if(xspos > scrollSize.width - clientSize.width)
7969 			{
7970 				xdiff = (clientSize.width + xspos) - scrollSize.width;
7971 				xspos -= xdiff;
7972 				if(xspos < 0)
7973 				{
7974 					xdiff += xspos;
7975 					xspos = 0;
7976 				}
7977 			}
7978 			
7979 			if(isHandleCreated)
7980 			{
7981 				if(xdiff || ydiff)
7982 					ScrollWindow(hwnd, xdiff, ydiff, null, null);
7983 				
7984 				_adjustScrollSize();
7985 			}
7986 		}
7987 	}
7988 	
7989 	
7990 	override void onResize(EventArgs ea)
7991 	{
7992 		super.onResize(ea);
7993 		
7994 		_fixScrollBounds();
7995 	}
7996 	
7997 	
7998 	private:
7999 	//Size scrollmargin, scrollmin;
8000 	//Point autoscrollpos;
8001 	DockPaddingEdges dpad;
8002 	Size autossz = DEFAULT_SCALE;
8003 	Size scrollsz = Size(0, 0);
8004 	int xspos = 0, yspos = 0;
8005 	
8006 	
8007 	void _init()
8008 	{
8009 		dpad = new DockPaddingEdges;
8010 		//dpad.changed = &dpadChanged;
8011 	}
8012 	
8013 	
8014 	void dpadChanged()
8015 	{
8016 		alayout(this);
8017 	}
8018 	
8019 	
8020 	void _adjustScrollSize(BOOL fRedraw = TRUE)
8021 	{
8022 		assert(isHandleCreated);
8023 		
8024 		if(!hScroll && !vScroll)
8025 			return;
8026 		
8027 		SCROLLINFO si;
8028 		//if(vScroll)
8029 		{
8030 			si.cbSize = SCROLLINFO.sizeof;
8031 			si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
8032 			si.nPos = yspos;
8033 			si.nMin = 0;
8034 			si.nMax = clientSize.height;
8035 			si.nPage = clientSize.height;
8036 			if(scrollSize.height > clientSize.height)
8037 				si.nMax = scrollSize.height;
8038 			if(si.nMax)
8039 				si.nMax--;
8040 			SetScrollInfo(hwnd, SB_VERT, &si, fRedraw);
8041 		}
8042 		//if(hScroll)
8043 		{
8044 			si.cbSize = SCROLLINFO.sizeof;
8045 			si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
8046 			si.nPos = xspos;
8047 			si.nMin = 0;
8048 			si.nMax = clientSize.width;
8049 			si.nPage = clientSize.width;
8050 			if(scrollSize.width > clientSize.width)
8051 				si.nMax = scrollSize.width;
8052 			if(si.nMax)
8053 				si.nMax--;
8054 			SetScrollInfo(hwnd, SB_HORZ, &si, fRedraw);
8055 		}
8056 	}
8057 }
8058 
8059 
8060 ///
8061 interface IContainerControl // docmain
8062 {
8063 	///
8064 	@property Control activeControl(); // getter
8065 	
8066 	deprecated void activeControl(Control); // setter
8067 	
8068 	deprecated bool activateControl(Control);
8069 }
8070 
8071 
8072 ///
8073 class ContainerControl: ScrollableControl, IContainerControl // docmain
8074 {
8075 	///
8076 	@property Control activeControl() // getter
8077 	{
8078 		/+
8079 		HWND hwfocus, hw;
8080 		hw = hwfocus = GetFocus();
8081 		while(hw)
8082 		{
8083 			if(hw == this.hwnd)
8084 				return Control.fromChildHandle(hwfocus);
8085 			hw = GetParent(hw);
8086 		}
8087 		return null;
8088 		+/
8089 		Control ctrlfocus, ctrl;
8090 		ctrl = ctrlfocus = Control.fromChildHandle(GetFocus());
8091 		while(ctrl)
8092 		{
8093 			if(ctrl is this)
8094 				return ctrlfocus;
8095 			ctrl = ctrl.parent;
8096 		}
8097 		return null;
8098 	}
8099 	
8100 	/// ditto
8101 	@property void activeControl(Control ctrl) // setter
8102 	{
8103 		if(!activateControl(ctrl))
8104 			throw new DflException("Unable to activate control");
8105 	}
8106 	
8107 	
8108 	///
8109 	// Returns true if successfully activated.
8110 	final bool activateControl(Control ctrl)
8111 	{
8112 		// Not sure if this is correct.
8113 		
8114 		if(!ctrl.canSelect)
8115 			return false;
8116 		//if(!SetActiveWindow(ctrl.handle))
8117 		//	return false;
8118 		ctrl.select();
8119 		return true;
8120 	}
8121 	
8122 	
8123 	///
8124 	final @property Form parentForm() // getter
8125 	{
8126 		Control par;
8127 		Form f;
8128 		
8129 		for(par = parent; par; par = par.parent)
8130 		{
8131 			f = cast(Form)par;
8132 			if(f)
8133 				return f;
8134 		}
8135 		
8136 		return null;
8137 	}
8138 	
8139 	
8140 	/+
8141 	final bool validate()
8142 	{
8143 		// ...
8144 	}
8145 	+/
8146 	
8147 	
8148 	this()
8149 	{
8150 		super();
8151 		_init();
8152 	}
8153 	
8154 	
8155 	/+
8156 	// Used internally.
8157 	this(HWND hwnd)
8158 	{
8159 		super(hwnd);
8160 		_init();
8161 	}
8162 	+/
8163 	
8164 	
8165 	private void _init()
8166 	{
8167 		//wexstyle |= WS_EX_CONTROLPARENT;
8168 		ctrlStyle |= ControlStyles.CONTAINER_CONTROL;
8169 	}
8170 	
8171 	
8172 	protected:
8173 	/+
8174 	override bool processDialogChar(char charCode)
8175 	{
8176 		// Not sure if this is correct.
8177 		return false;
8178 	}
8179 	+/
8180 	
8181 	
8182 	/+
8183 	deprecated protected override bool processMnemonic(dchar charCode)
8184 	{
8185 		return false;
8186 	}
8187 	
8188 	
8189 	bool processTabKey(bool forward)
8190 	{
8191 		if(isHandleCreated)
8192 		{
8193 			//SendMessageA(hwnd, WM_NEXTDLGCTL, !forward, 0);
8194 			//return true;
8195 			select(true, forward);
8196 		}
8197 		return false;
8198 	}
8199 	+/
8200 }
8201 
8202 
8203 import std.traits, std.typecons;
8204 private template hasLocalAliasing(T...)
8205 {
8206 	static if( !T.length )
8207 		enum hasLocalAliasing = false;
8208 	else
8209 		enum hasLocalAliasing = std.traits.hasLocalAliasing!(T[0]) ||
8210 			dfl.control.hasLocalAliasing!(T[1 .. $]);
8211 }
8212 
8213 ///
8214 shared class SharedControl
8215 {
8216 private:
8217 	Control _ctrl;
8218 	
8219 	LPARAM makeParam(ARGS...)(void function(Control, ARGS) fn, Tuple!(ARGS)* args)
8220 		if (ARGS.length)
8221 	{
8222 		static assert((DflInvokeParam*).sizeof <= LPARAM.sizeof);
8223 		static struct InvokeParam
8224 		{
8225 			void function(Control, ARGS) fn;
8226 			ARGS args;
8227 		}
8228 		alias dfl.internal.clib.malloc malloc;
8229 		alias dfl.internal.clib.free free;
8230 	
8231 		auto param = cast(InvokeParam*)malloc(InvokeParam.sizeof);
8232 		param.fn = fn;
8233 		param.args = args.field;
8234 		
8235 		if (!param)
8236 			throw new OomException();
8237 		
8238 		auto p = cast(DflInvokeParam*)malloc(DflInvokeParam.sizeof);
8239 		
8240 		if (!p)
8241 			throw new OomException();
8242 		
8243 		
8244 		static void fnentry(Control c, size_t[] p)
8245 		{
8246 			auto param = cast(InvokeParam*)p[0];
8247 			param.fn(c, param.args);
8248 			free(param);
8249 		}
8250 		
8251 		p.fp = &fnentry;
8252 		p.nparams = 1;
8253 		p.params[0] = cast(size_t)param;
8254 		
8255 		return cast(LPARAM)p;
8256 	}
8257 	
8258 	
8259 	LPARAM makeParamNoneArgs(void function(Control) fn)
8260 	{
8261 		static assert((DflInvokeParam*).sizeof <= LPARAM.sizeof);
8262 		alias dfl.internal.clib.malloc malloc;
8263 		alias dfl.internal.clib.free free;
8264 		
8265 		auto p = cast(DflInvokeParam*)malloc(DflInvokeParam.sizeof);
8266 		
8267 		if (!p)
8268 			throw new OomException();
8269 		
8270 		static void fnentry(Control c, size_t[] p)
8271 		{
8272 			auto fn = cast(void function(Control))p[0];
8273 			fn(c);
8274 		}
8275 		
8276 		p.fp = &fnentry;
8277 		p.nparams = 1;
8278 		p.params[0] = cast(size_t)fn;
8279 		
8280 		return cast(LPARAM)p;
8281 	}
8282 	
8283 	
8284 	
8285 public:
8286 	///
8287 	this(Control ctrl)
8288 	{
8289 		assert(ctrl);
8290 		_ctrl = cast(shared)ctrl;
8291 	}
8292 	
8293 	///
8294 	void invoke(ARGS...)(void function(Control, ARGS) fn, ARGS args)
8295 		if (ARGS.length && !hasLocalAliasing!(ARGS))
8296 	{
8297 		auto ctrl = cast(Control)_ctrl;
8298 		auto hwnd = ctrl.handle;
8299 		
8300 		if(!hwnd)
8301 			Control.badInvokeHandle();
8302 		
8303 		auto t = tuple(args);
8304 		auto p = makeParam(fn, &t);
8305 		SendMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, p);
8306 	}
8307 	
8308 	///
8309 	void invoke(ARGS...)(void function(Control, ARGS) fn, ARGS args)
8310 		if (!ARGS.length)
8311 	{
8312 		auto ctrl = cast(Control)_ctrl;
8313 		auto hwnd = ctrl.handle;
8314 		
8315 		if(!hwnd)
8316 			Control.badInvokeHandle();
8317 		
8318 		auto p = makeParamNoneArgs(fn);
8319 		SendMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, p);
8320 	}
8321 	
8322 	///
8323 	void delayInvoke(ARGS...)(void function(Control, ARGS) fn, ARGS args)
8324 		if (ARGS.length && !hasLocalAliasing!(ARGS))
8325 	{
8326 		auto ctrl = cast(Control)_ctrl;
8327 		auto hwnd = ctrl.handle;
8328 		
8329 		if(!hwnd)
8330 			Control.badInvokeHandle();
8331 		
8332 		auto t = tuple(args);
8333 		auto p = makeParam(fn, &t);
8334 		PostMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, p);
8335 	}
8336 	
8337 	///
8338 	void delayInvoke(ARGS...)(void function(Control, ARGS) fn, ARGS args)
8339 		if (!ARGS.length)
8340 	{
8341 		auto ctrl = cast(Control)_ctrl;
8342 		auto hwnd = ctrl.handle;
8343 		
8344 		if(!hwnd)
8345 			Control.badInvokeHandle();
8346 		
8347 		auto p = makeParamNoneArgs(fn);
8348 		PostMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, p);
8349 	}
8350 }