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 cast(int)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 							cast(int)(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, string text) //Dstring text
3649 	{
3650 		size_t 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, __FILE__, __LINE__);
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 				
6412 			hwnd = dfl.internal.utf.createWindowEx(exStyle, className, caption, (style & ~WS_VISIBLE), x, y,
6413 				width, height, parent, menu, inst, param);
6414 			if(!hwnd)
6415 			{
6416 				debug(APP_PRINT)
6417 				{
6418 					cprintf("CreateWindowEx failed."
6419 						" (exStyle=0x%X, className=`%.*s`, caption=`%.*s`, style=0x%X, x=%d, y=%d, width=%d, height=%d,"
6420 						" parent=0x%X, menu=0x%X, inst=0x%X, param=0x%X)\n",
6421 						exStyle, className, caption, style, x, y, width, height,
6422 						parent, menu, inst, param);
6423 				}
6424 				
6425 				debug
6426 				{
6427 					er = std..string.format("CreateWindowEx failed {className=%s;exStyle=0x%X;style=0x%X;parent=0x%X;menu=0x%X;inst=0x%X;}",
6428 						className, exStyle, style, cast(void*)parent, cast(void*)menu, cast(void*)inst);
6429 				}
6430 				
6431 				goto create_err;
6432 			}
6433 			
6434 			if(vis)
6435 				doShow(); // Properly fires onVisibleChanged.
6436 		}
6437 		
6438 		//onHandleCreated(EventArgs.empty); // Called in WM_CREATE now.
6439 	}
6440 	
6441 	
6442 	package final void _createHandle()
6443 	{
6444 		createHandle();
6445 	}
6446 	
6447 	
6448 	///
6449 	public final @property bool recreatingHandle() // getter
6450 	{
6451 		if(cbits & CBits.RECREATING)
6452 			return true;
6453 		return false;
6454 	}
6455 	
6456 	
6457 	private void _setAllRecreating()
6458 	{
6459 		cbits |= CBits.RECREATING;
6460 		foreach(Control cc; controls)
6461 		{
6462 			cc._setAllRecreating();
6463 		}
6464 	}
6465 	
6466 	
6467 	///
6468 	protected void recreateHandle()
6469 	in
6470 	{
6471 		assert(!recreatingHandle);
6472 	}
6473 	body
6474 	{
6475 		if(!isHandleCreated)
6476 			return;
6477 		
6478 		if(recreatingHandle)
6479 			return;
6480 		
6481 		bool hfocus = focused;
6482 		HWND prevHwnd = GetWindow(hwnd, GW_HWNDPREV);
6483 		
6484 		_setAllRecreating();
6485 		//scope(exit)
6486 		//	cbits &= ~CBits.RECREATING; // Now done from WM_CREATE.
6487 		
6488 		destroyHandle();
6489 		createHandle();
6490 		
6491 		if(prevHwnd)
6492 			SetWindowPos(hwnd, prevHwnd, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
6493 		else
6494 			SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
6495 		if(hfocus)
6496 			select();
6497 	}
6498 	
6499 	
6500 	///
6501 	void destroyHandle()
6502 	{
6503 		if(!isHandleCreated)
6504 			return;
6505 		
6506 		DestroyWindow(hwnd);
6507 		
6508 		// This stuff is done in WM_DESTROY because DestroyWindow() could be called elsewhere..
6509 		//hwnd = HWND.init; // Done in WM_DESTROY.
6510 		//onHandleDestroyed(EventArgs.empty); // Done in WM_DESTROY.
6511 	}
6512 	
6513 	
6514 	private final void fillRecreationData()
6515 	{
6516 		//cprintf(" { fillRecreationData %.*s }\n", name);
6517 		
6518 		if(!(ctrlStyle & ControlStyles.CACHE_TEXT))
6519 			wtext = _fetchText();
6520 		
6521 		//wclassStyle = _fetchClassLong(); // ?
6522 		
6523 		// Fetch children.
6524 		Control[] ccs;
6525 		foreach(Control cc; controls)
6526 		{
6527 			ccs ~= cc;
6528 		}
6529 		ccollection.children = ccs;
6530 	}
6531 	
6532 	
6533 	///
6534 	protected void onDisposed(EventArgs ea)
6535 	{
6536 		disposed(this, ea);
6537 	}
6538 	
6539 	
6540 	///
6541 	protected final bool getStyle(ControlStyles flag)
6542 	{
6543 		return (ctrlStyle & flag) != 0;
6544 	}
6545 	
6546 	/// ditto
6547 	protected final void setStyle(ControlStyles flag, bool value)
6548 	{
6549 		if(flag & ControlStyles.CACHE_TEXT)
6550 		{
6551 			if(value)
6552 				wtext = _fetchText();
6553 			else
6554 				wtext = null;
6555 		}
6556 		
6557 		if(value)
6558 			ctrlStyle |= flag;
6559 		else
6560 			ctrlStyle &= ~flag;
6561 	}
6562 	
6563 	
6564 	///
6565 	// Only for setStyle() styles that are part of hwnd and wndclass styles.
6566 	protected final void updateStyles()
6567 	{
6568 		LONG newClassStyles = _classStyle();
6569 		LONG newWndStyles = _style();
6570 		
6571 		if(ctrlStyle & ControlStyles.STANDARD_DOUBLE_CLICK)
6572 			newClassStyles |= CS_DBLCLKS;
6573 		else
6574 			newClassStyles &= ~CS_DBLCLKS;
6575 		
6576 		/+
6577 		if(ctrlStyle & ControlStyles.RESIZE_REDRAW)
6578 			newClassStyles |= CS_HREDRAW | CS_VREDRAW;
6579 		else
6580 			newClassStyles &= ~(CS_HREDRAW | CS_VREDRAW);
6581 		+/
6582 		
6583 		/+
6584 		if(ctrlStyle & ControlStyles.SELECTABLE)
6585 			newWndStyles |= WS_TABSTOP;
6586 		else
6587 			newWndStyles &= ~WS_TABSTOP;
6588 		+/
6589 		
6590 		_classStyle(newClassStyles);
6591 		_style(newWndStyles);
6592 	}
6593 	
6594 	
6595 	///
6596 	final bool getTopLevel()
6597 	{
6598 		// return GetParent(hwnd) == HWND.init;
6599 		return wparent is null;
6600 	}
6601 	
6602 	
6603 	package final void alayout(Control ctrl, bool vcheck = true)
6604 	{
6605 		if(vcheck && !visible)
6606 			return;
6607 		
6608 		if(cbits & CBits.IN_LAYOUT)
6609 			return;
6610 		
6611 		//if(_allowLayout)
6612 		if(!_disallowLayout)
6613 		{
6614 			//cprintf("alayout\n");
6615 			scope LayoutEventArgs lea = new LayoutEventArgs(ctrl);
6616 			onLayout(lea);
6617 		}
6618 	}
6619 	
6620 	
6621 	// Z-order of controls has changed.
6622 	package final void vchanged()
6623 	{
6624 		// Z-order can't change if it's not created or invisible.
6625 		//if(!isHandleCreated || !visible)
6626 		//	return;
6627 		
6628 		version(RADIO_GROUP_LAYOUT)
6629 		{
6630 			//cprintf("vchanged\n");
6631 			
6632 			bool foundRadio = false;
6633 			
6634 			foreach(Control ctrl; ccollection)
6635 			{
6636 				if(!ctrl.visible)
6637 					continue;
6638 				
6639 				if(ctrl._rtype() & 1) // Radio type.
6640 				{
6641 					LONG wlg;
6642 					wlg = ctrl._style();
6643 					if(foundRadio)
6644 					{
6645 						if(wlg & WS_GROUP)
6646 							//ctrl._style(wlg & ~WS_GROUP);
6647 							ctrl._style(wlg & ~(WS_GROUP | WS_TABSTOP));
6648 					}
6649 					else
6650 					{
6651 						foundRadio = true;
6652 						
6653 						if(!(wlg & WS_GROUP))
6654 							//ctrl._style(wlg | WS_GROUP);
6655 							ctrl._style(wlg | WS_GROUP | WS_TABSTOP);
6656 					}
6657 				}
6658 				else
6659 				{
6660 					// Found non-radio so reset group.
6661 					// Update: only reset group if found ctrl with WS_EX_CONTROLPARENT.
6662 					// TODO: check if correct implementation.
6663 					if(ctrl._exStyle() & WS_EX_CONTROLPARENT)
6664 						foundRadio = false;
6665 				}
6666 			}
6667 		}
6668 	}
6669 	
6670 	
6671 	///
6672 	// Called after adding the control to a container.
6673 	protected void initLayout()
6674 	{
6675 		assert(wparent !is null);
6676 		if(visible && created) // ?
6677 		{
6678 			wparent.vchanged();
6679 			wparent.alayout(this);
6680 		}
6681 	}
6682 	
6683 	
6684 	///
6685 	protected void onLayout(LayoutEventArgs lea)
6686 	{
6687 		// Note: exception could cause failure to restore.
6688 		//suspendLayout();
6689 		cbits |= CBits.IN_LAYOUT;
6690 		
6691 		debug(EVENT_PRINT)
6692 		{
6693 			cprintf("{ Event: onLayout - Control %.*s }\n", name);
6694 		}
6695 		
6696 		Rect area;
6697 		area = displayRectangle;
6698 		
6699 		foreach(Control ctrl; ccollection)
6700 		{
6701 			if(!ctrl.visible || !ctrl.created)
6702 				continue;
6703 			if(ctrl._rtype() & (2 | 4)) // Mdichild | Tabpage
6704 				continue;
6705 			
6706 			//Rect prevctrlbounds;
6707 			//prevctrlbounds = ctrl.bounds;
6708 			//ctrl.suspendLayout(); // Note: exception could cause failure to restore.
6709 			switch(ctrl.sdock)
6710 			{
6711 				case DockStyle.NONE:
6712 					/+
6713 					if(ctrl.anch & (AnchorStyles.RIGHT | AnchorStyles.BOTTOM)) // If none of these are set, no point in doing any anchor code.
6714 					{
6715 						Rect newb;
6716 						newb = ctrl.bounds;
6717 						if(ctrl.anch & AnchorStyles.RIGHT)
6718 						{
6719 							if(ctrl.anch & AnchorStyles.LEFT)
6720 								newb.width += bounds.width - originalBounds.width;
6721 							else
6722 								newb.x += bounds.width - originalBounds.width;
6723 						}
6724 						if(ctrl.anch & AnchorStyles.BOTTOM)
6725 						{
6726 							if(ctrl.anch & AnchorStyles.LEFT)
6727 								newb.height += bounds.height - originalBounds.height;
6728 							else
6729 								newb.y += bounds.height - originalBounds.height;
6730 						}
6731 						if(newb != ctrl.bounds)
6732 							ctrl.bounds = newb;
6733 					}
6734 					+/
6735 					break;
6736 				
6737 				case DockStyle.LEFT:
6738 					ctrl.setBoundsCore(area.x, area.y, 0, area.height, cast(BoundsSpecified)(BoundsSpecified.LOCATION | BoundsSpecified.HEIGHT));
6739 					area.x = area.x + ctrl.width;
6740 					area.width = area.width - ctrl.width;
6741 					break;
6742 				
6743 				case DockStyle.TOP:
6744 					ctrl.setBoundsCore(area.x, area.y, area.width, 0, cast(BoundsSpecified)(BoundsSpecified.LOCATION | BoundsSpecified.WIDTH));
6745 					area.y = area.y + ctrl.height;
6746 					area.height = area.height - ctrl.height;
6747 					break;
6748 				
6749 				case DockStyle.FILL:
6750 					//ctrl.bounds(Rect(area.x, area.y, area.width, area.height));
6751 					ctrl.bounds = area;
6752 					// area = ?
6753 					break;
6754 				
6755 				case DockStyle.BOTTOM:
6756 					ctrl.setBoundsCore(area.x, area.bottom - ctrl.height, area.width, 0, cast(BoundsSpecified)(BoundsSpecified.LOCATION | BoundsSpecified.WIDTH));
6757 					area.height = area.height - ctrl.height;
6758 					break;
6759 				
6760 				case DockStyle.RIGHT:
6761 					ctrl.setBoundsCore(area.right - ctrl.width, area.y, 0, area.height, cast(BoundsSpecified)(BoundsSpecified.LOCATION | BoundsSpecified.HEIGHT));
6762 					area.width = area.width - ctrl.width;
6763 					break;
6764 				
6765 				default:
6766 					assert(0);
6767 			}
6768 			//ctrl.resumeLayout(true);
6769 			//ctrl.resumeLayout(prevctrlbounds != ctrl.bounds);
6770 		}
6771 		
6772 		layout(this, lea);
6773 		
6774 		//resumeLayout(false);
6775 		cbits &= ~CBits.IN_LAYOUT;
6776 	}
6777 	
6778 	
6779 	/+
6780 	// Not sure what to do here.
6781 	deprecated bool isInputChar(char charCode)
6782 	{
6783 		return false;
6784 	}
6785 	+/
6786 	
6787 	
6788 	///
6789 	void setVisibleCore(bool byes)
6790 	{
6791 		if(isHandleCreated)
6792 		{
6793 			//wstyle = GetWindowLongA(hwnd, GWL_STYLE);
6794 			if(visible == byes)
6795 				return;
6796 			
6797 			//ShowWindow(hwnd, byes ? SW_SHOW : SW_HIDE);
6798 			if(byes)
6799 				doShow();
6800 			else
6801 				doHide();
6802 		}
6803 		else
6804 		{
6805 			if(byes)
6806 			{
6807 				cbits |= CBits.VISIBLE;
6808 				wstyle |= WS_VISIBLE;
6809 				createControl();
6810 			}
6811 			else
6812 			{
6813 				cbits &= ~CBits.VISIBLE;
6814 				wstyle &= ~WS_VISIBLE;
6815 				return; // Not created and being hidden..
6816 			}
6817 		}
6818 	}
6819 	
6820 	
6821 	package final bool _wantTabKey()
6822 	{
6823 		if(ctrlStyle & ControlStyles.WANT_TAB_KEY)
6824 			return true;
6825 		return false;
6826 	}
6827 	
6828 	
6829 	///
6830 	// Return true if processed.
6831 	protected bool processKeyEventArgs(ref Message msg)
6832 	{
6833 		switch(msg.msg)
6834 		{
6835 			case WM_KEYDOWN:
6836 				{
6837 					scope KeyEventArgs kea = new KeyEventArgs(cast(Keys)(msg.wParam | modifierKeys));
6838 					
6839 					ushort repeat = msg.lParam & 0xFFFF; // First 16 bits.
6840 					for(; repeat; repeat--)
6841 					{
6842 						//kea.handled = false;
6843 						onKeyDown(kea);
6844 					}
6845 					
6846 					if(kea.handled)
6847 						return true;
6848 				}
6849 				break;
6850 			
6851 			case WM_KEYUP:
6852 				{
6853 					// Repeat count is always 1 for key up.
6854 					scope KeyEventArgs kea = new KeyEventArgs(cast(Keys)(msg.wParam | modifierKeys));
6855 					onKeyUp(kea);
6856 					if(kea.handled)
6857 						return true;
6858 				}
6859 				break;
6860 			
6861 			case WM_CHAR:
6862 				{
6863 					scope KeyPressEventArgs kpea = new KeyPressEventArgs(cast(dchar)msg.wParam, modifierKeys);
6864 					onKeyPress(kpea);
6865 					if(kpea.handled)
6866 						return true;
6867 				}
6868 				break;
6869 			
6870 			default:
6871 		}
6872 		
6873 		defWndProc(msg);
6874 		return !msg.result;
6875 	}
6876 	
6877 	
6878 	package final bool _processKeyEventArgs(ref Message msg)
6879 	{
6880 		return processKeyEventArgs(msg);
6881 	}
6882 	
6883 	
6884 	/+
6885 	bool processKeyPreview(ref Message m)
6886 	{
6887 		if(wparent)
6888 			return wparent.processKeyPreview(m);
6889 		return false;
6890 	}
6891 	
6892 	
6893 	protected bool processDialogChar(dchar charCode)
6894 	{
6895 		if(wparent)
6896 			return wparent.processDialogChar(charCode);
6897 		return false;
6898 	}
6899 	+/
6900 	
6901 	
6902 	///
6903 	protected bool processMnemonic(dchar charCode)
6904 	{
6905 		return false;
6906 	}
6907 	
6908 	
6909 	package bool _processMnemonic(dchar charCode)
6910 	{
6911 		return processMnemonic(charCode);
6912 	}
6913 	
6914 	
6915 	// Retain DFL 0.9.5 compatibility.
6916 	public deprecated void setDFL095()
6917 	{
6918 		version(SET_DFL_095)
6919 		{
6920 			pragma(msg, "DFL: DFL 0.9.5 compatibility set at compile time");
6921 		}
6922 		else
6923 		{
6924 			//_compat = CCompat.DFL095;
6925 			Application.setCompat(DflCompat.CONTROL_RECREATE_095);
6926 		}
6927 	}
6928 	
6929 	private enum CCompat: ubyte
6930 	{
6931 		NONE = 0,
6932 		DFL095 = 1,
6933 	}
6934 	
6935 	version(SET_DFL_095)
6936 		package enum _compat = CCompat.DFL095;
6937 	else version(DFL_NO_COMPAT)
6938 		package enum _compat = CCompat.NONE;
6939 	else
6940 		package @property CCompat _compat() // getter
6941 			{ if(Application._compat & DflCompat.CONTROL_RECREATE_095) return CCompat.DFL095; return CCompat.NONE; }
6942 	
6943 	
6944 	package final void _crecreate()
6945 	{
6946 		if(CCompat.DFL095 != _compat)
6947 		{
6948 			if(!recreatingHandle)
6949 				recreateHandle();
6950 		}
6951 	}
6952 	
6953 	
6954 	package:
6955 	HWND hwnd;
6956 	//AnchorStyles anch = cast(AnchorStyles)(AnchorStyles.TOP | AnchorStyles.LEFT);
6957 	//bool cvalidation = true;
6958 	version(DFL_NO_MENUS)
6959 	{
6960 	}
6961 	else
6962 	{
6963 		ContextMenu cmenu;
6964 	}
6965 	DockStyle sdock = DockStyle.NONE;
6966 	Dstring _ctrlname;
6967 	Object otag;
6968 	Color backc, forec;
6969 	Rect wrect;
6970 	//Rect oldwrect;
6971 	Size wclientsz;
6972 	Cursor wcurs;
6973 	Font wfont;
6974 	Control wparent;
6975 	Region wregion;
6976 	ControlCollection ccollection;
6977 	Dstring wtext; // After creation, this isn't used unless ControlStyles.CACHE_TEXT.
6978 	ControlStyles ctrlStyle = ControlStyles.STANDARD_CLICK | ControlStyles.STANDARD_DOUBLE_CLICK /+ | ControlStyles.RESIZE_REDRAW +/ ;
6979 	HBRUSH _hbrBg;
6980 	RightToLeft rtol = RightToLeft.INHERIT;
6981 	uint _disallowLayout = 0;
6982 	
6983 	version(DFL_NO_DRAG_DROP) {} else
6984 	{
6985 		DropTarget droptarget = null;
6986 	}
6987 	
6988 	// Note: WS_VISIBLE is not reliable.
6989 	LONG wstyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; // Child, visible and enabled by default.
6990 	LONG wexstyle;
6991 	LONG wclassStyle = WNDCLASS_STYLE;
6992 	
6993 	
6994 	enum CBits: uint
6995 	{
6996 		NONE = 0x0,
6997 		MENTER = 0x1, // Is mouse entered? Only valid if -trackMouseEvent- is non-null.
6998 		KILLING = 0x2,
6999 		OWNED = 0x4,
7000 		//ALLOW_LAYOUT = 0x8,
7001 		CLICKING = 0x10,
7002 		NEED_CALC_SIZE = 0x20,
7003 		SZDRAW = 0x40,
7004 		OWNEDBG = 0x80,
7005 		HANDLE_CREATED = 0x100, // debug only
7006 		SW_SHOWN = 0x200,
7007 		SW_HIDDEN = 0x400,
7008 		CREATED = 0x800,
7009 		NEED_INIT_LAYOUT = 0x1000,
7010 		IN_LAYOUT = 0x2000,
7011 		FVISIBLE = 0x4000,
7012 		VISIBLE = 0x8000,
7013 		NOCLOSING = 0x10000,
7014 		ASCROLL = 0x20000,
7015 		ASCALE = 0x40000,
7016 		FORM = 0x80000,
7017 		RECREATING = 0x100000,
7018 		HAS_LAYOUT = 0x200000,
7019 		VSTYLE = 0x400000, // If not forced off.
7020 		FORMLOADED = 0x800000, // If not forced off.
7021 		ENABLED = 0x1000000, // Enabled state, not considering the parent.
7022 	}
7023 	
7024 	//CBits cbits = CBits.ALLOW_LAYOUT;
7025 	//CBits cbits = CBits.NONE;
7026 	CBits cbits = CBits.VISIBLE | CBits.VSTYLE | CBits.ENABLED;
7027 	
7028 	
7029 	final:
7030 	
7031 	@property void menter(bool byes) // setter
7032 		{ if(byes) cbits |= CBits.MENTER; else cbits &= ~CBits.MENTER; }
7033 	@property bool menter() // getter
7034 		{ return (cbits & CBits.MENTER) != 0; }
7035 	
7036 	@property void killing(bool byes) // setter
7037 		//{ if(byes) cbits |= CBits.KILLING; else cbits &= ~CBits.KILLING; }
7038 		{ assert(byes); if(byes) cbits |= CBits.KILLING; }
7039 	@property bool killing() // getter
7040 		{ return (cbits & CBits.KILLING) != 0; }
7041 	
7042 	@property void owned(bool byes) // setter
7043 		{ if(byes) cbits |= CBits.OWNED; else cbits &= ~CBits.OWNED; }
7044 	@property bool owned() // getter
7045 		{ return (cbits & CBits.OWNED) != 0; }
7046 	
7047 	/+
7048 	void _allowLayout(bool byes) // setter
7049 		{ if(byes) cbits |= CBits.ALLOW_LAYOUT; else cbits &= ~CBits.ALLOW_LAYOUT; }
7050 	bool _allowLayout() // getter
7051 		{ return (cbits & CBits.ALLOW_LAYOUT) != 0; }
7052 	+/
7053 	
7054 	@property void _clicking(bool byes) // setter
7055 		{ if(byes) cbits |= CBits.CLICKING; else cbits &= ~CBits.CLICKING; }
7056 	@property bool _clicking() // getter
7057 		{ return (cbits & CBits.CLICKING) != 0; }
7058 	
7059 	@property void needCalcSize(bool byes) // setter
7060 		{ if(byes) cbits |= CBits.NEED_CALC_SIZE; else cbits &= ~CBits.NEED_CALC_SIZE; }
7061 	@property bool needCalcSize() // getter
7062 		{ return (cbits & CBits.NEED_CALC_SIZE) != 0; }
7063 	
7064 	@property void szdraw(bool byes) // setter
7065 		{ if(byes) cbits |= CBits.SZDRAW; else cbits &= ~CBits.SZDRAW; }
7066 	@property bool szdraw() // getter
7067 		{ return (cbits & CBits.SZDRAW) != 0; }
7068 	
7069 	@property void ownedbg(bool byes) // setter
7070 		{ if(byes) cbits |= CBits.OWNEDBG; else cbits &= ~CBits.OWNEDBG; }
7071 	@property bool ownedbg() // getter
7072 		{ return (cbits & CBits.OWNEDBG) != 0; }
7073 	
7074 	debug
7075 	{
7076 		@property void _handlecreated(bool byes) // setter
7077 			{ if(byes) cbits |= CBits.HANDLE_CREATED; else cbits &= ~CBits.HANDLE_CREATED; }
7078 		@property bool _handlecreated() // getter
7079 			{ return (cbits & CBits.HANDLE_CREATED) != 0; }
7080 	}
7081 	
7082 	
7083 	@property LONG _exStyle()
7084 	{
7085 		// return GetWindowLongA(hwnd, GWL_EXSTYLE);
7086 		return wexstyle;
7087 	}
7088 	
7089 	
7090 	@property void _exStyle(LONG wl)
7091 	{
7092 		if(isHandleCreated)
7093 		{
7094 			SetWindowLongA(hwnd, GWL_EXSTYLE, wl);
7095 		}
7096 		
7097 		wexstyle = wl;
7098 	}
7099 	
7100 	
7101 	@property LONG _style()
7102 	{
7103 		// return GetWindowLongA(hwnd, GWL_STYLE);
7104 		return wstyle;
7105 	}
7106 	
7107 	
7108 	@property void _style(LONG wl)
7109 	{
7110 		if(isHandleCreated)
7111 		{
7112 			SetWindowLongA(hwnd, GWL_STYLE, wl);
7113 		}
7114 		
7115 		wstyle = wl;
7116 	}
7117 	
7118 	
7119 	@property HBRUSH hbrBg() // getter
7120 	{
7121 		if(_hbrBg)
7122 			return _hbrBg;
7123 		if(backc == Color.empty && parent && backColor == parent.backColor)
7124 		{
7125 			ownedbg = false;
7126 			_hbrBg = parent.hbrBg;
7127 			return _hbrBg;
7128 		}
7129 		hbrBg = backColor.createBrush(); // Call hbrBg's setter and set ownedbg.
7130 		return _hbrBg;
7131 	}
7132 	
7133 	
7134 	@property void hbrBg(HBRUSH hbr) // setter
7135 	in
7136 	{
7137 		if(hbr)
7138 		{
7139 			assert(!_hbrBg);
7140 		}
7141 	}
7142 	body
7143 	{
7144 		_hbrBg = hbr;
7145 		ownedbg = true;
7146 	}
7147 	
7148 	
7149 	void deleteThisBackgroundBrush()
7150 	{
7151 		if(_hbrBg)
7152 		{
7153 			if(ownedbg)
7154 				DeleteObject(_hbrBg);
7155 			_hbrBg = HBRUSH.init;
7156 		}
7157 	}
7158 	
7159 	
7160 	LRESULT defwproc(UINT msg, WPARAM wparam, LPARAM lparam)
7161 	{
7162 		//return DefWindowProcA(hwnd, msg, wparam, lparam);
7163 		return dfl.internal.utf.defWindowProc(hwnd, msg, wparam, lparam);
7164 	}
7165 	
7166 	
7167 	LONG _fetchClassLong()
7168 	{
7169 		return GetClassLongA(hwnd, GCL_STYLE);
7170 	}
7171 	
7172 	
7173 	LONG _classStyle()
7174 	{
7175 		// return GetClassLongA(hwnd, GCL_STYLE);
7176 		// return wclassStyle;
7177 		
7178 		if(isHandleCreated)
7179 		{
7180 			// Always fetch because it's not guaranteed to be accurate.
7181 			wclassStyle = _fetchClassLong();
7182 		}
7183 		
7184 		return wclassStyle;
7185 	}
7186 	
7187 	
7188 	package void _classStyle(LONG cl)
7189 	{
7190 		if(isHandleCreated)
7191 		{
7192 			SetClassLongA(hwnd, GCL_STYLE, cl);
7193 		}
7194 		
7195 		wclassStyle = cl;
7196 	}
7197 }
7198 
7199 
7200 package abstract class ControlSuperClass: Control // dapi.d
7201 {
7202 	// Call previous wndProc().
7203 	abstract protected void prevWndProc(ref Message msg);
7204 	
7205 	
7206 	protected override void wndProc(ref Message msg)
7207 	{
7208 		switch(msg.msg)
7209 		{
7210 			case WM_PAINT:
7211 				{
7212 					RECT uprect;
7213 					//GetUpdateRect(hwnd, &uprect, true);
7214 					//onInvalidated(new InvalidateEventArgs(Rect(&uprect)));
7215 					
7216 					//if(!msg.wParam)
7217 						GetUpdateRect(hwnd, &uprect, false); // Preserve.
7218 					
7219 					prevWndProc(msg);
7220 					
7221 					// Now fake a normal paint event...
7222 					
7223 					scope Graphics gpx = new CommonGraphics(hwnd, GetDC(hwnd));
7224 					//scope Graphics gpx = new CommonGraphics(hwnd, msg.wParam ? cast(HDC)msg.wParam : GetDC(hwnd), msg.wParam ? false : true);
7225 					HRGN hrgn;
7226 					
7227 					hrgn = CreateRectRgnIndirect(&uprect);
7228 					SelectClipRgn(gpx.handle, hrgn);
7229 					DeleteObject(hrgn);
7230 					
7231 					scope PaintEventArgs pea = new PaintEventArgs(gpx, Rect(&uprect));
7232 					
7233 					// Can't erase the background now, Windows just painted..
7234 					//if(ps.fErase)
7235 					//{
7236 					//	prepareDc(gpx.handle);
7237 					//	onPaintBackground(pea);
7238 					//}
7239 					
7240 					prepareDc(gpx.handle);
7241 					onPaint(pea);
7242 				}
7243 				break;
7244 			
7245 			case WM_PRINTCLIENT:
7246 				{
7247 					prevWndProc(msg);
7248 					
7249 					scope Graphics gpx = new CommonGraphics(hwnd, GetDC(hwnd));
7250 					scope PaintEventArgs pea = new PaintEventArgs(gpx,
7251 						Rect(Point(0, 0), wclientsz));
7252 					
7253 					prepareDc(pea.graphics.handle);
7254 					onPaint(pea);
7255 				}
7256 				break;
7257 			
7258 			case WM_PRINT:
7259 				Control.defWndProc(msg);
7260 				break;
7261 			
7262 			case WM_ERASEBKGND:
7263 				Control.wndProc(msg);
7264 				break;
7265 			
7266 			case WM_NCACTIVATE:
7267 			case WM_NCCALCSIZE:
7268 			case WM_NCCREATE:
7269 			case WM_NCPAINT:
7270 				prevWndProc(msg);
7271 				break;
7272 			
7273 			case WM_KEYDOWN:
7274 			case WM_KEYUP:
7275 			case WM_CHAR:
7276 			case WM_SYSKEYDOWN:
7277 			case WM_SYSKEYUP:
7278 			case WM_SYSCHAR:
7279 			//case WM_IMECHAR:
7280 				super.wndProc(msg);
7281 				return;
7282 			
7283 			default:
7284 				prevWndProc(msg);
7285 				super.wndProc(msg);
7286 		}
7287 	}
7288 	
7289 	
7290 	override void defWndProc(ref Message m)
7291 	{
7292 		switch(m.msg)
7293 		{
7294 			case WM_KEYDOWN:
7295 			case WM_KEYUP:
7296 			case WM_CHAR:
7297 			case WM_SYSKEYDOWN:
7298 			case WM_SYSKEYUP:
7299 			case WM_SYSCHAR:
7300 			//case WM_IMECHAR: // ?
7301 				prevWndProc(m);
7302 				break;
7303 			
7304 			default:
7305 		}
7306 	}
7307 	
7308 	
7309 	protected override void onPaintBackground(PaintEventArgs pea)
7310 	{
7311 		Message msg;
7312 		
7313 		msg.hWnd = handle;
7314 		msg.msg = WM_ERASEBKGND;
7315 		msg.wParam = cast(WPARAM)pea.graphics.handle;
7316 		
7317 		prevWndProc(msg);
7318 		
7319 		// Don't paint the background twice.
7320 		//super.onPaintBackground(pea);
7321 		
7322 		// Event ?
7323 		//paintBackground(this, pea);
7324 	}
7325 }
7326 
7327 
7328 ///
7329 class ScrollableControl: Control // docmain
7330 {
7331 	// ///
7332 	deprecated void autoScroll(bool byes) // setter
7333 	{
7334 		if(byes)
7335 			cbits |= CBits.ASCROLL;
7336 		else
7337 			cbits &= ~CBits.ASCROLL;
7338 	}
7339 	
7340 	// /// ditto
7341 	deprecated bool autoScroll() // getter
7342 	{
7343 		return (cbits & CBits.ASCROLL) == CBits.ASCROLL;
7344 	}
7345 	
7346 	
7347 	// ///
7348 	deprecated final void autoScrollMargin(Size sz) // setter
7349 	{
7350 		//scrollmargin = sz;
7351 	}
7352 	
7353 	// /// ditto
7354 	deprecated final Size autoScrollMargin() // getter
7355 	{
7356 		//return scrollmargin;
7357 		return Size(0, 0);
7358 	}
7359 	
7360 	
7361 	// ///
7362 	deprecated final void autoScrollMinSize(Size sz) // setter
7363 	{
7364 		//scrollmin = sz;
7365 	}
7366 	
7367 	// /// ditto
7368 	deprecated final Size autoScrollMinSize() // getter
7369 	{
7370 		//return scrollmin;
7371 		return Size(0, 0);
7372 	}
7373 	
7374 	
7375 	// ///
7376 	deprecated final void autoScrollPosition(Point pt) // setter
7377 	{
7378 		//autoscrollpos = pt;
7379 	}
7380 	
7381 	// /// ditto
7382 	deprecated final Point autoScrollPosition() // getter
7383 	{
7384 		//return autoscrollpos;
7385 		return Point(0, 0);
7386 	}
7387 	
7388 	
7389 	///
7390 	final @property Size autoScaleBaseSize() // getter
7391 	{
7392 		return autossz;
7393 	}
7394 	
7395 	/// ditto
7396 	final @property void autoScaleBaseSize(Size newSize) // setter
7397 	in
7398 	{
7399 		assert(newSize.width > 0);
7400 		assert(newSize.height > 0);
7401 	}
7402 	body
7403 	{
7404 		autossz = newSize;
7405 	}
7406 	
7407 	
7408 	///
7409 	final @property void autoScale(bool byes) // setter
7410 	{
7411 		if(byes)
7412 			cbits |= CBits.ASCALE;
7413 		else
7414 			cbits &= ~CBits.ASCALE;
7415 	}
7416 	
7417 	/// ditto
7418 	final @property bool autoScale() // getter
7419 	{
7420 		return (cbits & CBits.ASCALE) == CBits.ASCALE;
7421 	}
7422 	
7423 	
7424 	final @property Point scrollPosition() // getter
7425 	{
7426 		return Point(xspos, yspos);
7427 	}
7428 	
7429 	
7430 	static Size calcScale(Size area, Size toScale, Size fromScale) // package
7431 	in
7432 	{
7433 		assert(fromScale.width);
7434 		assert(fromScale.height);
7435 	}
7436 	body
7437 	{
7438 		area.width = cast(int)(cast(float)area.width / cast(float)fromScale.width * cast(float)toScale.width);
7439 		area.height = cast(int)(cast(float)area.height / cast(float)fromScale.height * cast(float)toScale.height);
7440 		return area;
7441 	}
7442 	
7443 	
7444 	Size calcScale(Size area, Size toScale) // package
7445 	{
7446 		return calcScale(area, toScale, DEFAULT_SCALE);
7447 	}
7448 	
7449 	
7450 	final void _scale(Size toScale) // package
7451 	{
7452 		bool first = true;
7453 		
7454 		// Note: doesn't get to-scale for nested scrollable-controls.
7455 		void xscale(Control c, Size fromScale)
7456 		{
7457 			c.suspendLayout();
7458 			
7459 			if(first)
7460 			{
7461 				first = false;
7462 				c.size = calcScale(c.size, toScale, fromScale);
7463 			}
7464 			else
7465 			{
7466 				Point pt;
7467 				Size sz;
7468 				sz = calcScale(Size(c.left, c.top), toScale, fromScale);
7469 				pt = Point(sz.width, sz.height);
7470 				sz = calcScale(c.size, toScale, fromScale);
7471 				c.bounds = Rect(pt, sz);
7472 			}
7473 			
7474 			if(c.hasChildren)
7475 			{
7476 				ScrollableControl scc;
7477 				foreach(Control cc; c.controls)
7478 				{
7479 					scc = cast(ScrollableControl)cc;
7480 					if(scc)
7481 					{
7482 						if(scc.autoScale) // ?
7483 						{
7484 							xscale(scc, scc.autoScaleBaseSize);
7485 							scc.autoScaleBaseSize = toScale;
7486 						}
7487 					}
7488 					else
7489 					{
7490 						xscale(cc, fromScale);
7491 					}
7492 				}
7493 			}
7494 			
7495 			//c.resumeLayout(true);
7496 			c.resumeLayout(false); // Should still be perfectly proportionate if it was properly laid out before scaling.
7497 		}
7498 		
7499 		
7500 		xscale(this, autoScaleBaseSize);
7501 		autoScaleBaseSize = toScale;
7502 	}
7503 	
7504 	
7505 	final void _scale() // package
7506 	{
7507 		return _scale(getAutoScaleSize());
7508 	}
7509 	
7510 	
7511 	protected override void onControlAdded(ControlEventArgs ea)
7512 	{
7513 		super.onControlAdded(ea);
7514 		
7515 		if(created) // ?
7516 		if(isHandleCreated)
7517 		{
7518 			auto sc = cast(ScrollableControl)ea.control;
7519 			if(sc)
7520 			{
7521 				if(sc.autoScale)
7522 					sc._scale();
7523 			}
7524 			else
7525 			{
7526 				if(autoScale)
7527 					_scale();
7528 			}
7529 		}
7530 	}
7531 	
7532 	
7533 	//override final Rect displayRectangle() // getter
7534 	override @property Rect displayRectangle() // getter
7535 	{
7536 		Rect result = clientRectangle;
7537 		
7538 		// Subtract dock padding.
7539 		result.x = result.x + dpad.left;
7540 		result.width = result.width - dpad.right - dpad.left;
7541 		result.y = result.y + dpad.top;
7542 		result.height = result.height - dpad.bottom - dpad.top;
7543 		
7544 		// Add scroll width.
7545 		if(scrollSize.width > clientSize.width)
7546 			result.width = result.width + (scrollSize.width - clientSize.width);
7547 		if(scrollSize.height > clientSize.height)
7548 			result.height = result.height + (scrollSize.height - clientSize.height);
7549 		
7550 		// Adjust scroll position.
7551 		result.location = Point(result.location.x - scrollPosition.x, result.location.y - scrollPosition.y);
7552 		
7553 		return result;
7554 	}
7555 	
7556 	
7557 	///
7558 	final @property void scrollSize(Size sz) // setter
7559 	{
7560 		scrollsz = sz;
7561 		
7562 		_fixScrollBounds(); // Implies _adjustScrollSize().
7563 	}
7564 	
7565 	/// ditto
7566 	final @property Size scrollSize() // getter
7567 	{
7568 		return scrollsz;
7569 	}
7570 	
7571 	
7572 	///
7573 	class DockPaddingEdges
7574 	{
7575 		private:
7576 		
7577 		int _left, _top, _right, _bottom;
7578 		int _all;
7579 		//package void delegate() changed;
7580 		
7581 		
7582 		final:
7583 		
7584 		void changed()
7585 		{
7586 			dpadChanged();
7587 		}
7588 		
7589 		
7590 		public:
7591 		
7592 		///
7593 		@property void all(int x) // setter
7594 		{
7595 			_bottom = _right = _top = _left = _all = x;
7596 			
7597 			changed();
7598 		}
7599 		
7600 		/// ditto
7601 		final @property int all() // getter
7602 		{
7603 			return _all;
7604 		}
7605 		
7606 		/// ditto
7607 		@property void left(int x) // setter
7608 		{
7609 			_left = x;
7610 			
7611 			changed();
7612 		}
7613 		
7614 		/// ditto
7615 		@property int left() // getter
7616 		{
7617 			return _left;
7618 		}
7619 		
7620 		/// ditto
7621 		@property void top(int x) // setter
7622 		{
7623 			_top = x;
7624 			
7625 			changed();
7626 		}
7627 		
7628 		/// ditto
7629 		@property int top() // getter
7630 		{
7631 			return _top;
7632 		}
7633 		
7634 		/// ditto
7635 		@property void right(int x) // setter
7636 		{
7637 			_right = x;
7638 			
7639 			changed();
7640 		}
7641 		
7642 		/// ditto
7643 		@property int right() // getter
7644 		{
7645 			return _right;
7646 		}
7647 		
7648 		/// ditto
7649 		@property void bottom(int x) // setter
7650 		{
7651 			_bottom = x;
7652 			
7653 			changed();
7654 		}
7655 		
7656 		/// ditto
7657 		@property int bottom() // getter
7658 		{
7659 			return _bottom;
7660 		}
7661 	}
7662 	
7663 	
7664 	///
7665 	final @property DockPaddingEdges dockPadding() // getter
7666 	{
7667 		return dpad;
7668 	}
7669 	
7670 	
7671 	deprecated final void setAutoScrollMargin(int x, int y)
7672 	{
7673 		//
7674 	}
7675 	
7676 	
7677 	this()
7678 	{
7679 		super();
7680 		_init();
7681 	}
7682 	
7683 	
7684 	enum DEFAULT_SCALE = Size(5, 13);
7685 	
7686 	///
7687 	final @property void hScroll(bool byes) // setter
7688 	{
7689 		LONG wl = _style();
7690 		if(byes)
7691 			wl |= WS_HSCROLL;
7692 		else
7693 			wl &= ~WS_HSCROLL;
7694 		_style(wl);
7695 		
7696 		if(isHandleCreated)
7697 			redrawEntire();
7698 	}
7699 	
7700 	
7701 	/// ditto
7702 	final @property bool hScroll() // getter
7703 	{
7704 		return (_style() & WS_HSCROLL) != 0;
7705 	}
7706 	
7707 	
7708 	///
7709 	final @property void vScroll(bool byes) // setter
7710 	{
7711 		LONG wl = _style();
7712 		if(byes)
7713 			wl |= WS_VSCROLL;
7714 		else
7715 			wl &= ~WS_VSCROLL;
7716 		_style(wl);
7717 		
7718 		if(isHandleCreated)
7719 			redrawEntire();
7720 	}
7721 	
7722 	/// ditto
7723 	final @property bool vScroll() // getter
7724 	{
7725 		return (_style() & WS_VSCROLL) != 0;
7726 	}
7727 	
7728 	
7729 	protected:
7730 	
7731 	
7732 	/+
7733 	override void onLayout(LayoutEventArgs lea)
7734 	{
7735 		// ...
7736 		super.onLayout(lea);
7737 	}
7738 	+/
7739 	
7740 	
7741 	/+
7742 	override void scaleCore(float width, float height)
7743 	{
7744 		// Might not want to call super.scaleCore().
7745 	}
7746 	+/
7747 	
7748 	
7749 	override void wndProc(ref Message m)
7750 	{
7751 		switch(m.msg)
7752 		{
7753 			case WM_VSCROLL:
7754 				{
7755 					SCROLLINFO si = void;
7756 					si.cbSize = SCROLLINFO.sizeof;
7757 					si.fMask = SIF_ALL;
7758 					if(GetScrollInfo(m.hWnd, SB_VERT, &si))
7759 					{
7760 						int delta, maxp;
7761 						maxp = scrollSize.height - clientSize.height;
7762 						switch(LOWORD(m.wParam))
7763 						{
7764 							case SB_LINEDOWN:
7765 								if(yspos >= maxp)
7766 									return;
7767 								delta = maxp - yspos;
7768 								if(autossz.height < delta)
7769 									delta = autossz.height;
7770 								break;
7771 							case SB_LINEUP:
7772 								if(yspos <= 0)
7773 									return;
7774 								delta = yspos;
7775 								if(autossz.height < delta)
7776 									delta = autossz.height;
7777 								delta = -delta;
7778 								break;
7779 							case SB_PAGEDOWN:
7780 								if(yspos >= maxp)
7781 									return;
7782 								if(yspos >= maxp)
7783 									return;
7784 								delta = maxp - yspos;
7785 								if(clientSize.height < delta)
7786 									delta = clientSize.height;
7787 								break;
7788 							case SB_PAGEUP:
7789 								if(yspos <= 0)
7790 									return;
7791 								delta = yspos;
7792 								if(clientSize.height < delta)
7793 									delta = clientSize.height;
7794 								delta = -delta;
7795 								break;
7796 							case SB_THUMBTRACK:
7797 							case SB_THUMBPOSITION:
7798 								//delta = cast(int)HIWORD(m.wParam) - yspos; // Limited to 16-bits.
7799 								delta = si.nTrackPos - yspos;
7800 								break;
7801 							case SB_BOTTOM:
7802 								delta = maxp - yspos;
7803 								break;
7804 							case SB_TOP:
7805 								delta = -yspos;
7806 								break;
7807 							default:
7808 						}
7809 						yspos += delta;
7810 						SetScrollPos(m.hWnd, SB_VERT, yspos, TRUE);
7811 						ScrollWindow(m.hWnd, 0, -delta, null, null);
7812 					}
7813 				}
7814 				break;
7815 			
7816 			case WM_HSCROLL:
7817 				{
7818 					SCROLLINFO si = void;
7819 					si.cbSize = SCROLLINFO.sizeof;
7820 					si.fMask = SIF_ALL;
7821 					if(GetScrollInfo(m.hWnd, SB_HORZ, &si))
7822 					{
7823 						int delta, maxp;
7824 						maxp = scrollSize.width - clientSize.width;
7825 						switch(LOWORD(m.wParam))
7826 						{
7827 							case SB_LINERIGHT:
7828 								if(xspos >= maxp)
7829 									return;
7830 								delta = maxp - xspos;
7831 								if(autossz.width < delta)
7832 									delta = autossz.width;
7833 								break;
7834 							case SB_LINELEFT:
7835 								if(xspos <= 0)
7836 									return;
7837 								delta = xspos;
7838 								if(autossz.width < delta)
7839 									delta = autossz.width;
7840 								delta = -delta;
7841 								break;
7842 							case SB_PAGERIGHT:
7843 								if(xspos >= maxp)
7844 									return;
7845 								if(xspos >= maxp)
7846 									return;
7847 								delta = maxp - xspos;
7848 								if(clientSize.width < delta)
7849 									delta = clientSize.width;
7850 								break;
7851 							case SB_PAGELEFT:
7852 								if(xspos <= 0)
7853 									return;
7854 								delta = xspos;
7855 								if(clientSize.width < delta)
7856 									delta = clientSize.width;
7857 								delta = -delta;
7858 								break;
7859 							case SB_THUMBTRACK:
7860 							case SB_THUMBPOSITION:
7861 								//delta = cast(int)HIWORD(m.wParam) - xspos; // Limited to 16-bits.
7862 								delta = si.nTrackPos - xspos;
7863 								break;
7864 							case SB_RIGHT:
7865 								delta = maxp - xspos;
7866 								break;
7867 							case SB_LEFT:
7868 								delta = -xspos;
7869 								break;
7870 							default:
7871 						}
7872 						xspos += delta;
7873 						SetScrollPos(m.hWnd, SB_HORZ, xspos, TRUE);
7874 						ScrollWindow(m.hWnd, -delta, 0, null, null);
7875 					}
7876 				}
7877 				break;
7878 			
7879 			default:
7880 		}
7881 		
7882 		super.wndProc(m);
7883 	}
7884 	
7885 	
7886 	override void onMouseWheel(MouseEventArgs ea)
7887 	{
7888 		int maxp = scrollSize.height - clientSize.height;
7889 		int delta;
7890 		
7891 		UINT wlines;
7892 		if(!SystemParametersInfoA(SPI_GETWHEELSCROLLLINES, 0, &wlines, 0))
7893 			wlines = 3;
7894 		
7895 		if(ea.delta < 0)
7896 		{
7897 			if(yspos < maxp)
7898 			{
7899 				delta = maxp - yspos;
7900 				if(autossz.height * wlines < delta)
7901 					delta = autossz.height * wlines;
7902 				
7903 				yspos += delta;
7904 				SetScrollPos(hwnd, SB_VERT, yspos, TRUE);
7905 				ScrollWindow(hwnd, 0, -delta, null, null);
7906 			}
7907 		}
7908 		else
7909 		{
7910 			if(yspos > 0)
7911 			{
7912 				delta = yspos;
7913 				if(autossz.height * wlines < delta)
7914 					delta = autossz.height * wlines;
7915 				delta = -delta;
7916 				
7917 				yspos += delta;
7918 				SetScrollPos(hwnd, SB_VERT, yspos, TRUE);
7919 				ScrollWindow(hwnd, 0, -delta, null, null);
7920 			}
7921 		}
7922 		
7923 		super.onMouseWheel(ea);
7924 	}
7925 	
7926 	
7927 	override void onHandleCreated(EventArgs ea)
7928 	{
7929 		xspos = 0;
7930 		yspos = 0;
7931 		
7932 		super.onHandleCreated(ea);
7933 		
7934 		//_adjustScrollSize(FALSE);
7935 		if(hScroll || vScroll)
7936 		{
7937 			_adjustScrollSize(FALSE);
7938 			recalcEntire(); // Need to recalc frame.
7939 		}
7940 	}
7941 	
7942 	
7943 	override void onVisibleChanged(EventArgs ea)
7944 	{
7945 		if(visible)
7946 			_adjustScrollSize(FALSE);
7947 		
7948 		super.onVisibleChanged(ea);
7949 	}
7950 	
7951 	
7952 	private void _fixScrollBounds()
7953 	{
7954 		if(hScroll || vScroll)
7955 		{
7956 			int ydiff = 0, xdiff = 0;
7957 			
7958 			if(yspos > scrollSize.height - clientSize.height)
7959 			{
7960 				ydiff = (clientSize.height + yspos) - scrollSize.height;
7961 				yspos -= ydiff;
7962 				if(yspos < 0)
7963 				{
7964 					ydiff += yspos;
7965 					yspos = 0;
7966 				}
7967 			}
7968 			
7969 			if(xspos > scrollSize.width - clientSize.width)
7970 			{
7971 				xdiff = (clientSize.width + xspos) - scrollSize.width;
7972 				xspos -= xdiff;
7973 				if(xspos < 0)
7974 				{
7975 					xdiff += xspos;
7976 					xspos = 0;
7977 				}
7978 			}
7979 			
7980 			if(isHandleCreated)
7981 			{
7982 				if(xdiff || ydiff)
7983 					ScrollWindow(hwnd, xdiff, ydiff, null, null);
7984 				
7985 				_adjustScrollSize();
7986 			}
7987 		}
7988 	}
7989 	
7990 	
7991 	override void onResize(EventArgs ea)
7992 	{
7993 		super.onResize(ea);
7994 		
7995 		_fixScrollBounds();
7996 	}
7997 	
7998 	
7999 	private:
8000 	//Size scrollmargin, scrollmin;
8001 	//Point autoscrollpos;
8002 	DockPaddingEdges dpad;
8003 	Size autossz = DEFAULT_SCALE;
8004 	Size scrollsz = Size(0, 0);
8005 	int xspos = 0, yspos = 0;
8006 	
8007 	
8008 	void _init()
8009 	{
8010 		dpad = new DockPaddingEdges;
8011 		//dpad.changed = &dpadChanged;
8012 	}
8013 	
8014 	
8015 	void dpadChanged()
8016 	{
8017 		alayout(this);
8018 	}
8019 	
8020 	
8021 	void _adjustScrollSize(BOOL fRedraw = TRUE)
8022 	{
8023 		assert(isHandleCreated);
8024 		
8025 		if(!hScroll && !vScroll)
8026 			return;
8027 		
8028 		SCROLLINFO si;
8029 		//if(vScroll)
8030 		{
8031 			si.cbSize = SCROLLINFO.sizeof;
8032 			si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
8033 			si.nPos = yspos;
8034 			si.nMin = 0;
8035 			si.nMax = clientSize.height;
8036 			si.nPage = clientSize.height;
8037 			if(scrollSize.height > clientSize.height)
8038 				si.nMax = scrollSize.height;
8039 			if(si.nMax)
8040 				si.nMax--;
8041 			SetScrollInfo(hwnd, SB_VERT, &si, fRedraw);
8042 		}
8043 		//if(hScroll)
8044 		{
8045 			si.cbSize = SCROLLINFO.sizeof;
8046 			si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
8047 			si.nPos = xspos;
8048 			si.nMin = 0;
8049 			si.nMax = clientSize.width;
8050 			si.nPage = clientSize.width;
8051 			if(scrollSize.width > clientSize.width)
8052 				si.nMax = scrollSize.width;
8053 			if(si.nMax)
8054 				si.nMax--;
8055 			SetScrollInfo(hwnd, SB_HORZ, &si, fRedraw);
8056 		}
8057 	}
8058 }
8059 
8060 
8061 ///
8062 interface IContainerControl // docmain
8063 {
8064 	///
8065 	@property Control activeControl(); // getter
8066 	
8067 	deprecated void activeControl(Control); // setter
8068 	
8069 	deprecated bool activateControl(Control);
8070 }
8071 
8072 
8073 ///
8074 class ContainerControl: ScrollableControl, IContainerControl // docmain
8075 {
8076 	///
8077 	@property Control activeControl() // getter
8078 	{
8079 		/+
8080 		HWND hwfocus, hw;
8081 		hw = hwfocus = GetFocus();
8082 		while(hw)
8083 		{
8084 			if(hw == this.hwnd)
8085 				return Control.fromChildHandle(hwfocus);
8086 			hw = GetParent(hw);
8087 		}
8088 		return null;
8089 		+/
8090 		Control ctrlfocus, ctrl;
8091 		ctrl = ctrlfocus = Control.fromChildHandle(GetFocus());
8092 		while(ctrl)
8093 		{
8094 			if(ctrl is this)
8095 				return ctrlfocus;
8096 			ctrl = ctrl.parent;
8097 		}
8098 		return null;
8099 	}
8100 	
8101 	/// ditto
8102 	@property void activeControl(Control ctrl) // setter
8103 	{
8104 		if(!activateControl(ctrl))
8105 			throw new DflException("Unable to activate control");
8106 	}
8107 	
8108 	
8109 	///
8110 	// Returns true if successfully activated.
8111 	final bool activateControl(Control ctrl)
8112 	{
8113 		// Not sure if this is correct.
8114 		
8115 		if(!ctrl.canSelect)
8116 			return false;
8117 		//if(!SetActiveWindow(ctrl.handle))
8118 		//	return false;
8119 		ctrl.select();
8120 		return true;
8121 	}
8122 	
8123 	
8124 	///
8125 	final @property Form parentForm() // getter
8126 	{
8127 		Control par;
8128 		Form f;
8129 		
8130 		for(par = parent; par; par = par.parent)
8131 		{
8132 			f = cast(Form)par;
8133 			if(f)
8134 				return f;
8135 		}
8136 		
8137 		return null;
8138 	}
8139 	
8140 	
8141 	/+
8142 	final bool validate()
8143 	{
8144 		// ...
8145 	}
8146 	+/
8147 	
8148 	
8149 	this()
8150 	{
8151 		super();
8152 		_init();
8153 	}
8154 	
8155 	
8156 	/+
8157 	// Used internally.
8158 	this(HWND hwnd)
8159 	{
8160 		super(hwnd);
8161 		_init();
8162 	}
8163 	+/
8164 	
8165 	
8166 	private void _init()
8167 	{
8168 		//wexstyle |= WS_EX_CONTROLPARENT;
8169 		ctrlStyle |= ControlStyles.CONTAINER_CONTROL;
8170 	}
8171 	
8172 	
8173 	protected:
8174 	/+
8175 	override bool processDialogChar(char charCode)
8176 	{
8177 		// Not sure if this is correct.
8178 		return false;
8179 	}
8180 	+/
8181 	
8182 	
8183 	/+
8184 	deprecated protected override bool processMnemonic(dchar charCode)
8185 	{
8186 		return false;
8187 	}
8188 	
8189 	
8190 	bool processTabKey(bool forward)
8191 	{
8192 		if(isHandleCreated)
8193 		{
8194 			//SendMessageA(hwnd, WM_NEXTDLGCTL, !forward, 0);
8195 			//return true;
8196 			select(true, forward);
8197 		}
8198 		return false;
8199 	}
8200 	+/
8201 }
8202 
8203 
8204 import std.traits, std.typecons;
8205 private template hasLocalAliasing(T...)
8206 {
8207 	static if( !T.length )
8208 		enum hasLocalAliasing = false;
8209 	else
8210 		enum hasLocalAliasing = std.traits.hasLocalAliasing!(T[0]) ||
8211 			dfl.control.hasLocalAliasing!(T[1 .. $]);
8212 }
8213 
8214 ///
8215 shared class SharedControl
8216 {
8217 private:
8218 	Control _ctrl;
8219 	
8220 	LPARAM makeParam(ARGS...)(void function(Control, ARGS) fn, Tuple!(ARGS)* args)
8221 		if (ARGS.length)
8222 	{
8223 		static assert((DflInvokeParam*).sizeof <= LPARAM.sizeof);
8224 		static struct InvokeParam
8225 		{
8226 			void function(Control, ARGS) fn;
8227 			ARGS args;
8228 		}
8229 		alias dfl.internal.clib.malloc malloc;
8230 		alias dfl.internal.clib.free free;
8231 	
8232 		auto param = cast(InvokeParam*)malloc(InvokeParam.sizeof);
8233 		param.fn = fn;
8234 		param.args = args.field;
8235 		
8236 		if (!param)
8237 			throw new OomException();
8238 		
8239 		auto p = cast(DflInvokeParam*)malloc(DflInvokeParam.sizeof);
8240 		
8241 		if (!p)
8242 			throw new OomException();
8243 		
8244 		
8245 		static void fnentry(Control c, size_t[] p)
8246 		{
8247 			auto param = cast(InvokeParam*)p[0];
8248 			param.fn(c, param.args);
8249 			free(param);
8250 		}
8251 		
8252 		p.fp = &fnentry;
8253 		p.nparams = 1;
8254 		p.params[0] = cast(size_t)param;
8255 		
8256 		return cast(LPARAM)p;
8257 	}
8258 	
8259 	
8260 	LPARAM makeParamNoneArgs(void function(Control) fn)
8261 	{
8262 		static assert((DflInvokeParam*).sizeof <= LPARAM.sizeof);
8263 		alias dfl.internal.clib.malloc malloc;
8264 		alias dfl.internal.clib.free free;
8265 		
8266 		auto p = cast(DflInvokeParam*)malloc(DflInvokeParam.sizeof);
8267 		
8268 		if (!p)
8269 			throw new OomException();
8270 		
8271 		static void fnentry(Control c, size_t[] p)
8272 		{
8273 			auto fn = cast(void function(Control))p[0];
8274 			fn(c);
8275 		}
8276 		
8277 		p.fp = &fnentry;
8278 		p.nparams = 1;
8279 		p.params[0] = cast(size_t)fn;
8280 		
8281 		return cast(LPARAM)p;
8282 	}
8283 	
8284 	
8285 	
8286 public:
8287 	///
8288 	this(Control ctrl)
8289 	{
8290 		assert(ctrl);
8291 		_ctrl = cast(shared)ctrl;
8292 	}
8293 	
8294 	///
8295 	void invoke(ARGS...)(void function(Control, ARGS) fn, ARGS args)
8296 		if (ARGS.length && !hasLocalAliasing!(ARGS))
8297 	{
8298 		auto ctrl = cast(Control)_ctrl;
8299 		auto hwnd = ctrl.handle;
8300 		
8301 		if(!hwnd)
8302 			Control.badInvokeHandle();
8303 		
8304 		auto t = tuple(args);
8305 		auto p = makeParam(fn, &t);
8306 		SendMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, p);
8307 	}
8308 	
8309 	///
8310 	void invoke(ARGS...)(void function(Control, ARGS) fn, ARGS args)
8311 		if (!ARGS.length)
8312 	{
8313 		auto ctrl = cast(Control)_ctrl;
8314 		auto hwnd = ctrl.handle;
8315 		
8316 		if(!hwnd)
8317 			Control.badInvokeHandle();
8318 		
8319 		auto p = makeParamNoneArgs(fn);
8320 		SendMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, p);
8321 	}
8322 	
8323 	///
8324 	void delayInvoke(ARGS...)(void function(Control, ARGS) fn, ARGS args)
8325 		if (ARGS.length && !hasLocalAliasing!(ARGS))
8326 	{
8327 		auto ctrl = cast(Control)_ctrl;
8328 		auto hwnd = ctrl.handle;
8329 		
8330 		if(!hwnd)
8331 			Control.badInvokeHandle();
8332 		
8333 		auto t = tuple(args);
8334 		auto p = makeParam(fn, &t);
8335 		PostMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, p);
8336 	}
8337 	
8338 	///
8339 	void delayInvoke(ARGS...)(void function(Control, ARGS) fn, ARGS args)
8340 		if (!ARGS.length)
8341 	{
8342 		auto ctrl = cast(Control)_ctrl;
8343 		auto hwnd = ctrl.handle;
8344 		
8345 		if(!hwnd)
8346 			Control.badInvokeHandle();
8347 		
8348 		auto p = makeParamNoneArgs(fn);
8349 		PostMessageA(hwnd, wmDfl, WPARAM_DFL_DELAY_INVOKE_PARAMS, p);
8350 	}
8351 }