1 // Written by Christopher E. Miller
2 // See the included license.txt for copyright and license details.
3 
4 
5 
6 module dfl.base;
7 
8 private import dfl.internal.dlib, dfl.internal.clib;
9 
10 private import dfl.internal.winapi, dfl.drawing, dfl.event;
11 
12 
13 alias HWND HWindow;
14 
15 
16 
17 interface IWindow { // docmain
18 
19    @property HWindow handle(); // getter
20 }
21 
22 alias IWindow IWin32Window; // deprecated
23 
24 
25 
26 class DflException: Exception { // docmain
27 
28    this(Dstring msg, string file = __FILE__, int line = __LINE__) {
29       super(msg, file, line);
30    }
31 }
32 
33 
34 
35 alias DThrowable DflThrowable;
36 
37 
38 
39 class StringObject: DObject {
40 
41    Dstring value;
42 
43 
44 
45    this(Dstring str) pure nothrow {
46       this.value = str;
47    }
48 
49 
50    override Dstring toString() {
51       return value;
52    }
53 
54 
55    override Dequ opEquals(Object o) {
56       return value == getObjectString(o); // ?
57    }
58 
59 
60    Dequ opEquals(StringObject s) {
61       return value == s.value;
62    }
63 
64 
65    override int opCmp(Object o) {
66       return stringICmp(value, getObjectString(o)); // ?
67    }
68 
69 
70    int opCmp(StringObject s) {
71       return stringICmp(value, s.value);
72    }
73 }
74 
75 
76 
77 enum Keys: uint { // docmain
78    NONE =     0, /// No keys specified.
79 
80 
81    SHIFT =    0x10000, /// Modifier keys.
82    CONTROL =  0x20000, /// ditto
83    ALT =      0x40000, /// ditto
84    WINDOWS =  0x80000, /// ditto
85 
86    A = 'A', /// Letters.
87    B = 'B', /// ditto
88    C = 'C', /// ditto
89    D = 'D', /// ditto
90    E = 'E', /// ditto
91    F = 'F', /// ditto
92    G = 'G', /// ditto
93    H = 'H', /// ditto
94    I = 'I', /// ditto
95    J = 'J', /// ditto
96    K = 'K', /// ditto
97    L = 'L', /// ditto
98    M = 'M', /// ditto
99    N = 'N', /// ditto
100    O = 'O', /// ditto
101    P = 'P', /// ditto
102    Q = 'Q', /// ditto
103    R = 'R', /// ditto
104    S = 'S', /// ditto
105    T = 'T', /// ditto
106    U = 'U', /// ditto
107    V = 'V', /// ditto
108    W = 'W', /// ditto
109    X = 'X', /// ditto
110    Y = 'Y', /// ditto
111    Z = 'Z', /// ditto
112 
113    D0 = '0', /// Digits.
114    D1 = '1', /// ditto
115    D2 = '2', /// ditto
116    D3 = '3', /// ditto
117    D4 = '4', /// ditto
118    D5 = '5', /// ditto
119    D6 = '6', /// ditto
120    D7 = '7', /// ditto
121    D8 = '8', /// ditto
122    D9 = '9', /// ditto
123 
124    F1 = 112, /// F - function keys.
125    F2 = 113, /// ditto
126    F3 = 114, /// ditto
127    F4 = 115, /// ditto
128    F5 = 116, /// ditto
129    F6 = 117, /// ditto
130    F7 = 118, /// ditto
131    F8 = 119, /// ditto
132    F9 = 120, /// ditto
133    F10 = 121, /// ditto
134    F11 = 122, /// ditto
135    F12 = 123, /// ditto
136    F13 = 124, /// ditto
137    F14 = 125, /// ditto
138    F15 = 126, /// ditto
139    F16 = 127, /// ditto
140    F17 = 128, /// ditto
141    F18 = 129, /// ditto
142    F19 = 130, /// ditto
143    F20 = 131, /// ditto
144    F21 = 132, /// ditto
145    F22 = 133, /// ditto
146    F23 = 134, /// ditto
147    F24 = 135, /// ditto
148 
149    NUM_PAD0 = 96, /// Numbers on keypad.
150    NUM_PAD1 = 97, /// ditto
151    NUM_PAD2 = 98, /// ditto
152    NUM_PAD3 = 99, /// ditto
153    NUM_PAD4 = 100, /// ditto
154    NUM_PAD5 = 101, /// ditto
155    NUM_PAD6 = 102, /// ditto
156    NUM_PAD7 = 103, /// ditto
157    NUM_PAD8 = 104, /// ditto
158    NUM_PAD9 = 105, /// ditto
159 
160    ADD = 107, ///
161    APPS = 93, /// Application.
162    ATTN = 246, ///
163    BACK = 8, /// Backspace.
164    CANCEL = 3, ///
165    CAPITAL = 20, ///
166    CAPS_LOCK = 20, /// ditto
167    CLEAR = 12, ///
168    CONTROL_KEY = 17, ///
169    CRSEL = 247, ///
170    DECIMAL = 110, ///
171    DEL = 46, ///
172    DELETE = DEL, ///
173    PERIOD = 190, ///
174    DOT = PERIOD, /// ditto
175    DIVIDE = 111, ///
176    DOWN = 40, /// Down arrow.
177    END = 35, ///
178    ENTER = 13, ///
179    ERASE_EOF = 249, ///
180    ESCAPE = 27, ///
181    EXECUTE = 43, ///
182    EXSEL = 248, ///
183    FINAL_MODE = 4, /// IME final mode.
184    HANGUL_MODE = 21, /// IME Hangul mode.
185    HANGUEL_MODE = 21, /// ditto
186    HANJA_MODE = 25, /// IME Hanja mode.
187    HELP = 47, ///
188    HOME = 36, ///
189    IME_ACCEPT = 30, ///
190    IME_CONVERT = 28, ///
191    IME_MODE_CHANGE = 31, ///
192    IME_NONCONVERT = 29, ///
193    INSERT = 45, ///
194    JUNJA_MODE = 23, ///
195    KANA_MODE = 21, ///
196    KANJI_MODE = 25, ///
197    LEFT_CONTROL = 162, /// Left Ctrl.
198    LEFT = 37, /// Left arrow.
199    LINE_FEED = 10, ///
200    LEFT_MENU = 164, /// Left Alt.
201    LEFT_SHIFT = 160, ///
202    LEFT_WIN = 91, /// Left Windows logo.
203    MENU = 18, /// Alt.
204    MULTIPLY = 106, ///
205    NEXT = 34, /// Page down.
206    NO_NAME = 252, // Reserved for future use.
207    NUM_LOCK = 144, ///
208    OEM8 = 223, // OEM specific.
209    OEM_CLEAR = 254,
210    PA1 = 253,
211    PAGE_DOWN = 34, ///
212    PAGE_UP = 33, ///
213    PAUSE = 19, ///
214    PLAY = 250, ///
215    PRINT = 42, ///
216    PRINT_SCREEN = 44, ///
217    PROCESS_KEY = 229, ///
218    RIGHT_CONTROL = 163, /// Right Ctrl.
219    RETURN = 13, ///
220    RIGHT = 39, /// Right arrow.
221    RIGHT_MENU = 165, /// Right Alt.
222    RIGHT_SHIFT = 161, ///
223    RIGHT_WIN = 92, /// Right Windows logo.
224    SCROLL = 145, /// Scroll lock.
225    SELECT = 41, ///
226    SEPARATOR = 108, ///
227    SHIFT_KEY = 16, ///
228    SNAPSHOT = 44, /// Print screen.
229    SPACE = 32, ///
230    SPACEBAR = SPACE, // Extra.
231    SUBTRACT = 109, ///
232    TAB = 9, ///
233    UP = 38, /// Up arrow.
234    ZOOM = 251, ///
235 
236    // Windows 2000+
237    BROWSER_BACK = 166, ///
238    BROWSER_FAVORITES = 171, /// ditto
239    BROWSER_FORWARD = 167, /// ditto
240    BROWSER_HOME = 172, /// ditto
241    BROWSER_REFRESH = 168, /// ditto
242    BROWSER_SEARCH = 170, /// ditto
243    BROWSER_STOP = 169, /// ditto
244    LAUNCH_APPLICATION1 = 182, ///
245    LAUNCH_APPLICATION2 = 183, /// ditto
246    LAUNCH_MAIL = 180, /// ditto
247    MEDIA_NEXT_TRACK = 176, ///
248    MEDIA_PLAY_PAUSE = 179, /// ditto
249    MEDIA_PREVIOUS_TRACK = 177, /// ditto
250    MEDIA_STOP = 178, /// ditto
251    OEM_BACKSLASH = 226, // OEM angle bracket or backslash.
252    OEM_CLOSE_BRACKETS = 221,
253    OEM_COMMA = 188,
254    OEM_MINUS = 189,
255    OEM_OPEN_BRACKETS = 219,
256    OEM_PERIOD = 190,
257    OEM_PIPE = 220,
258    OEM_PLUS = 187,
259    OEM_QUESTION = 191,
260    OEM_QUOTES = 222,
261    OEM_SEMICOLON = 186,
262    OEM_TILDE = 192,
263    SELECT_MEDIA = 181, ///
264    VOLUME_DOWN = 174, ///
265    VOLUME_MUTE = 173, /// ditto
266    VOLUME_UP = 175, /// ditto
267 
268    /// Bit mask to extract key code from key value.
269    KEY_CODE = 0xFFFF,
270 
271    /// Bit mask to extract modifiers from key value.
272    MODIFIERS = 0xFFFF0000,
273 }
274 
275 
276 
277 enum MouseButtons: uint { // docmain
278    /// No mouse buttons specified.
279    NONE =      0,
280 
281    LEFT =      0x100000, ///
282    RIGHT =     0x200000, /// ditto
283    MIDDLE =    0x400000, /// ditto
284 
285    // Windows 2000+
286    //XBUTTON1 =  0x800000,
287    //XBUTTON2 =  0x1000000,
288 }
289 
290 
291 
292 enum CheckState: ubyte {
293    UNCHECKED = BST_UNCHECKED, ///
294    CHECKED = BST_CHECKED, /// ditto
295    INDETERMINATE = BST_INDETERMINATE, /// ditto
296 }
297 
298 
299 
300 struct Message { // docmain
301    union {
302       struct {
303          HWND hWnd; ///
304          UINT msg; /// ditto
305          WPARAM wParam; /// ditto
306          LPARAM lParam; /// ditto
307       }
308 
309       package MSG _winMsg; // .time and .pt are not always valid.
310    }
311    LRESULT result; ///
312 
313 
314    /// Construct a Message struct.
315    this(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) pure nothrow {
316       this.hWnd = hWnd;
317       this.msg = msg;
318       this.wParam = wParam;
319       this.lParam = lParam;
320       result = 0;
321    }
322 }
323 
324 
325 
326 interface IMessageFilter { // docmain
327 
328    // Return false to allow the message to be dispatched.
329    // Filter functions cannot modify messages.
330    bool preFilterMessage(ref Message m);
331 }
332 
333 
334 abstract class WaitHandle {
335    enum WAIT_TIMEOUT = dfl.internal.winapi.WAIT_TIMEOUT; // DMD 1.028: needs fqn, otherwise conflicts with std.thread
336    enum INVALID_HANDLE = .INVALID_HANDLE_VALUE;
337 
338 
339    this() {
340       h = INVALID_HANDLE;
341    }
342 
343 
344    // Used internally.
345    this(HANDLE h, bool owned = true) {
346       this.h = h;
347       this.owned = owned;
348    }
349 
350 
351    @property HANDLE handle() nothrow { // getter
352       return h;
353    }
354 
355 
356    @property void handle(HANDLE h) { // setter
357       this.h = h;
358    }
359 
360 
361    void close() {
362       CloseHandle(h);
363       h = INVALID_HANDLE;
364    }
365 
366 
367    ~this() {
368       if(owned) {
369          close();
370       }
371    }
372 
373 
374    private static DWORD _wait(WaitHandle[] handles, BOOL waitall, DWORD msTimeout) {
375       DWORD result;
376       HANDLE* hs;
377       // Some implementations fail with > 64 handles, but that will return WAIT_FAILED;
378       // all implementations fail with >= 128 handles due to WAIT_ABANDONED_0 being 128.
379       if(handles.length >= 128) {
380          goto fail;
381       }
382 
383       //hs = new HANDLE[handles.length];
384       hs = cast(HANDLE*)alloca(HANDLE.sizeof * handles.length);
385 
386       foreach(size_t i, WaitHandle wh; handles) {
387          hs[i] = wh.handle;
388       }
389 
390       result = WaitForMultipleObjects(handles.length, hs, waitall, msTimeout);
391       if(WAIT_FAILED == result) {
392       fail:
393          throw new DflException("Wait failure");
394       }
395       return result;
396    }
397 
398 
399    static void waitAll(WaitHandle[] handles) {
400       return waitAll(handles, INFINITE);
401    }
402 
403 
404    static void waitAll(WaitHandle[] handles, DWORD msTimeout) {
405       _wait(handles, true, msTimeout);
406    }
407 
408 
409    static int waitAny(WaitHandle[] handles) {
410       return waitAny(handles, INFINITE);
411    }
412 
413 
414    static int waitAny(WaitHandle[] handles, DWORD msTimeout) {
415       DWORD result;
416       result = _wait(handles, false, msTimeout);
417       return cast(int)result; // Same return info.
418    }
419 
420 
421    void waitOne() {
422       return waitOne(INFINITE);
423    }
424 
425 
426    void waitOne(DWORD msTimeout) {
427       DWORD result;
428       result = WaitForSingleObject(handle, msTimeout);
429       if(WAIT_FAILED == result) {
430          throw new DflException("Wait failure");
431       }
432    }
433 
434 
435  private:
436    HANDLE h;
437    bool owned = true;
438 }
439 
440 
441 interface IAsyncResult {
442    @property WaitHandle asyncWaitHandle(); // getter
443 
444    // Usually just returns false.
445    @property bool completedSynchronously(); // getter
446 
447    // When true, it is safe to release its resources.
448    @property bool isCompleted(); // getter
449 }
450 
451 
452 /+
453 class AsyncResult: IAsyncResult {
454 }
455 +/
456 
457 
458 
459 interface IButtonControl { // docmain
460 
461    @property DialogResult dialogResult(); // getter
462    /// ditto
463    @property void dialogResult(DialogResult); // setter
464 
465 
466    void notifyDefault(bool); // True if default button.
467 
468 
469    void performClick(); // Raise click event.
470 }
471 
472 
473 
474 enum DialogResult: ubyte { // docmain
475    NONE, ///
476 
477    ABORT = IDABORT, ///
478    CANCEL = IDCANCEL, ///
479    IGNORE = IDIGNORE, ///
480    NO = IDNO, ///
481    OK = IDOK, ///
482    RETRY = IDRETRY, ///
483    YES = IDYES, ///
484 
485    // Extra.
486    CLOSE = IDCLOSE,
487    HELP = IDHELP,
488 }
489 
490 
491 interface IDialogResult {
492    // ///
493    @property DialogResult dialogResult(); // getter
494    // /// ditto
495    @property void dialogResult(DialogResult); // setter
496 }
497 
498 
499 
500 enum SortOrder: ubyte {
501    NONE, ///
502 
503    ASCENDING, ///
504    DESCENDING, /// ditto
505 }
506 
507 
508 
509 enum View: ubyte {
510    LARGE_ICON, ///
511    SMALL_ICON, ///
512    LIST, ///
513    DETAILS, ///
514 }
515 
516 
517 
518 enum ItemBoundsPortion: ubyte {
519    ENTIRE, ///
520    ICON, ///
521    ITEM_ONLY, /// Excludes other stuff like check boxes.
522    LABEL, /// Item's text.
523 }
524 
525 
526 
527 enum ItemActivation: ubyte {
528    STANDARD, ///
529    ONE_CLICK, ///
530    TWO_CLICK, ///
531 }
532 
533 
534 
535 enum ColumnHeaderStyle: ubyte {
536    CLICKABLE, ///
537    NONCLICKABLE, ///
538    NONE, /// No column header.
539 }
540 
541 
542 
543 enum BorderStyle: ubyte {
544    NONE, ///
545 
546    FIXED_3D, ///
547    FIXED_SINGLE, /// ditto
548 }
549 
550 
551 
552 enum FlatStyle: ubyte {
553    STANDARD, ///
554    FLAT, /// ditto
555    POPUP, /// ditto
556    SYSTEM, /// ditto
557 }
558 
559 
560 
561 enum Appearance: ubyte {
562    NORMAL, ///
563    BUTTON, ///
564 }
565 
566 
567 
568 enum ContentAlignment: ubyte {
569    TOP_LEFT, ///
570    BOTTOM_CENTER, ///
571    BOTTOM_LEFT, ///
572    BOTTOM_RIGHT, ///
573    MIDDLE_CENTER, ///
574    MIDDLE_LEFT, ///
575    MIDDLE_RIGHT, ///
576    TOP_CENTER, ///
577    TOP_RIGHT, ///
578 }
579 
580 
581 
582 enum CharacterCasing: ubyte {
583    NORMAL, ///
584    LOWER, ///
585    UPPER, ///
586 }
587 
588 
589 
590 // Not flags.
591 enum ScrollBars: ubyte {
592    NONE, ///
593 
594    HORIZONTAL, ///
595    VERTICAL, /// ditto
596    BOTH, /// ditto
597 }
598 
599 
600 
601 enum HorizontalAlignment: ubyte {
602    LEFT, ///
603    RIGHT, /// ditto
604    CENTER, /// ditto
605 }
606 
607 
608 
609 enum DrawMode: ubyte {
610    NORMAL, ///
611    OWNER_DRAW_FIXED, ///
612    OWNER_DRAW_VARIABLE, /// ditto
613 }
614 
615 
616 
617 enum DrawItemState: uint {
618    NONE = 0, ///
619    SELECTED = 1, /// ditto
620    DISABLED = 2, /// ditto
621    CHECKED = 8, /// ditto
622    FOCUS = 0x10, /// ditto
623    DEFAULT = 0x20, /// ditto
624    HOT_LIGHT = 0x40, /// ditto
625    NO_ACCELERATOR = 0x80, /// ditto
626    INACTIVE = 0x100, /// ditto
627    NO_FOCUS_RECT = 0x200, /// ditto
628    COMBO_BOX_EDIT = 0x1000, /// ditto
629 }
630 
631 
632 
633 enum RightToLeft: ubyte {
634    INHERIT = 2, ///
635    YES = 1, /// ditto
636    NO = 0, /// ditto
637 }
638 
639 
640 
641 enum ColorDepth: ubyte {
642    DEPTH_4BIT = 0x04, ///
643    DEPTH_8BIT = 0x08, /// ditto
644    DEPTH_16BIT = 0x10, /// ditto
645    DEPTH_24BIT = 0x18, /// ditto
646    DEPTH_32BIT = 0x20, /// ditto
647 }
648 
649 
650 
651 class PaintEventArgs: EventArgs {
652 
653    this(Graphics graphics, Rect clipRect) pure nothrow {
654       g = graphics;
655       cr = clipRect;
656    }
657 
658 
659 
660    final @property Graphics graphics() pure nothrow { // getter
661       return g;
662    }
663 
664 
665 
666    final @property Rect clipRectangle() pure nothrow { // getter
667       return cr;
668    }
669 
670 
671  private:
672    Graphics g;
673    Rect cr;
674 }
675 
676 
677 
678 class CancelEventArgs: EventArgs {
679 
680    // Initialize cancel to false.
681    this() pure nothrow {
682       cncl = false;
683    }
684 
685    /// ditto
686    this(bool cancel) pure nothrow {
687       cncl = cancel;
688    }
689 
690 
691 
692    final @property void cancel(bool byes) pure nothrow { // setter
693       cncl = byes;
694    }
695 
696    /// ditto
697    final @property bool cancel() pure nothrow { // getter
698       return cncl;
699    }
700 
701 
702  private:
703    bool cncl;
704 }
705 
706 
707 class SizingEventArgs: EventArgs {
708 
709    // Initialize cancel to false.
710    this(Size sz) pure nothrow {
711       _sz = sz;
712    }
713 
714 
715    @property Size size() pure nothrow {
716       return _sz;
717    }
718 
719    /// ditto
720    @property void size(Size sz) pure nothrow {
721       _sz = sz;
722    }
723 
724 
725    @property void width(int w) pure nothrow {
726       _sz.width = w;
727    }
728 
729    /// ditto
730    @property int width() pure nothrow {
731       return _sz.width;
732    }
733 
734 
735    @property void height(int h) pure nothrow {
736       _sz.height = h;
737    }
738 
739    /// ditto
740    @property int height() pure nothrow {
741       return _sz.height;
742    }
743 
744 
745  private:
746    Size _sz;
747 }
748 
749 
750 class MovingEventArgs: EventArgs {
751 
752    // Initialize cancel to false.
753    this(Point loc) pure nothrow {
754       _loc = loc;
755    }
756 
757 
758    @property Point location() pure nothrow {
759       return _loc;
760    }
761 
762    /// ditto
763    @property void location(Point loc) pure nothrow {
764       _loc = loc;
765    }
766 
767 
768    @property void x(int posX) pure nothrow {
769       _loc.x = posX;
770    }
771 
772    /// ditto
773    @property int x() pure nothrow {
774       return _loc.x;
775    }
776 
777 
778    @property void y(int posY) pure nothrow {
779       _loc.y = posY;
780    }
781 
782    /// ditto
783    @property int y() pure nothrow {
784       return _loc.y;
785    }
786 
787 
788  private:
789    Point _loc;
790 }
791 
792 
793 class KeyEventArgs: EventArgs {
794 
795    this(Keys keys) pure nothrow {
796       ks = keys;
797    }
798 
799 
800 
801    final @property bool alt() pure nothrow { // getter
802       return (ks & Keys.ALT) != 0;
803    }
804 
805 
806 
807    final @property bool control() pure nothrow { // getter
808       return (ks & Keys.CONTROL) != 0;
809    }
810 
811 
812 
813    final @property void handled(bool byes) pure nothrow { // setter
814       hand = byes;
815    }
816 
817 
818    final @property bool handled() pure nothrow { // getter
819       return hand;
820    }
821 
822 
823 
824    final @property Keys keyCode() pure nothrow { // getter
825       return ks & Keys.KEY_CODE;
826    }
827 
828 
829 
830    final @property Keys keyData() pure nothrow { // getter
831       return ks;
832    }
833 
834 
835 
836    // -keyData- as an int.
837    final @property int keyValue() pure nothrow { // getter
838       return cast(int)ks;
839    }
840 
841 
842 
843    final @property Keys modifiers() pure nothrow { // getter
844       return ks & Keys.MODIFIERS;
845    }
846 
847 
848 
849    final @property bool shift() pure nothrow { // getter
850       return (ks & Keys.SHIFT) != 0;
851    }
852 
853 
854 
855    final @property bool windows() pure nothrow { // getter
856       return (ks & Keys.WINDOWS) != 0;
857    }
858 
859 
860  private:
861    Keys ks;
862    bool hand = false;
863 }
864 
865 
866 
867 class KeyPressEventArgs: KeyEventArgs {
868 
869    this(dchar ch) {
870       this(ch, (ch >= 'A' && ch <= 'Z') ? Keys.SHIFT : Keys.NONE);
871    }
872 
873    /// ditto
874    this(dchar ch, Keys modifiers)
875    in {
876       assert((modifiers & Keys.MODIFIERS) == modifiers, "modifiers parameter can only contain modifiers");
877    }
878    body {
879       _keych = ch;
880 
881       int vk;
882       if(dfl.internal.utf.useUnicode) {
883          vk = 0xFF & VkKeyScanW(cast(WCHAR)ch);
884       } else
885       { vk = 0xFF & VkKeyScanA(cast(char)ch); }
886 
887       super(cast(Keys)(vk | modifiers));
888    }
889 
890 
891 
892    final @property dchar keyChar() { // getter
893       return _keych;
894    }
895 
896 
897  private:
898    dchar _keych;
899 }
900 
901 
902 
903 class MouseEventArgs: EventArgs {
904 
905    // -delta- is mouse wheel rotations.
906    this(MouseButtons button, int clicks, int x, int y, int delta) pure nothrow {
907       btn = button;
908       clks = clicks;
909       _x = x;
910       _y = y;
911       dlt = delta;
912    }
913 
914 
915 
916    final @property MouseButtons button() pure nothrow { // getter
917       return btn;
918    }
919 
920 
921 
922    final @property int clicks() pure nothrow { // getter
923       return clks;
924    }
925 
926 
927 
928    final @property int delta() pure nothrow { // getter
929       return dlt;
930    }
931 
932 
933 
934    final @property int x() pure nothrow { // getter
935       return _x;
936    }
937 
938 
939 
940    final @property int y() pure nothrow { // getter
941       return _y;
942    }
943 
944 
945  private:
946    MouseButtons btn;
947    int clks;
948    int _x, _y;
949    int dlt;
950 }
951 
952 
953 /+
954 
955 class LabelEditEventArgs: EventArgs {
956 
957    this(int index) {
958 
959    }
960 
961    /// ditto
962    this(int index, Dstring labelText) {
963       this.idx = index;
964       this.ltxt = labelText;
965    }
966 
967 
968 
969    final @property void cancelEdit(bool byes) { // setter
970       cancl = byes;
971    }
972 
973    /// ditto
974    final @property bool cancelEdit() { // getter
975       return cancl;
976    }
977 
978 
979 
980    // The text of the label's edit.
981    final @property Dstring label() { // getter
982       return ltxt;
983    }
984 
985 
986 
987    // Gets the item's index.
988    final @property int item() { // getter
989       return idx;
990    }
991 
992 
993  private:
994    int idx;
995    Dstring ltxt;
996    bool cancl = false;
997 }
998 +/
999 
1000 
1001 
1002 class ColumnClickEventArgs: EventArgs {
1003 
1004    this(int col) pure nothrow {
1005       this.col = col;
1006    }
1007 
1008 
1009 
1010    final @property int column() pure nothrow { // getter
1011       return col;
1012    }
1013 
1014 
1015  private:
1016    int col;
1017 }
1018 
1019 
1020 
1021 class DrawItemEventArgs: EventArgs {
1022 
1023    this(Graphics g, Font f, Rect r, int i, DrawItemState dis) pure nothrow {
1024       this(g, f, r, i , dis, Color.empty, Color.empty);
1025    }
1026 
1027    /// ditto
1028    this(Graphics g, Font f, Rect r, int i, DrawItemState dis, Color fc, Color bc) pure nothrow {
1029       gpx = g;
1030       fnt = f;
1031       rect = r;
1032       idx = i;
1033       distate = dis;
1034       fcolor = fc;
1035       bcolor = bc;
1036    }
1037 
1038 
1039 
1040    final @property Color backColor() pure nothrow { // getter
1041       return bcolor;
1042    }
1043 
1044 
1045 
1046    final @property Rect bounds() pure nothrow { // getter
1047       return rect;
1048    }
1049 
1050 
1051 
1052    final @property Font font() pure nothrow { // getter
1053       return fnt;
1054    }
1055 
1056 
1057 
1058    final @property Color foreColor() pure nothrow { // getter
1059       return fcolor;
1060    }
1061 
1062 
1063 
1064    final @property Graphics graphics() pure nothrow { // getter
1065       return gpx;
1066    }
1067 
1068 
1069 
1070    final @property int index() pure nothrow { // getter
1071       return idx;
1072    }
1073 
1074 
1075 
1076    final @property DrawItemState state() pure nothrow { // getter
1077       return distate;
1078    }
1079 
1080 
1081 
1082    void drawBackground() {
1083       /+
1084       HBRUSH hbr;
1085       RECT _rect;
1086 
1087       hbr = bcolor.createBrush();
1088       try {
1089          rect.getRect(&_rect);
1090          FillRect(gpx.handle, &_rect, hbr);
1091       }
1092       finally {
1093          DeleteObject(hbr);
1094       }
1095       +/
1096 
1097       gpx.fillRectangle(bcolor, rect);
1098    }
1099 
1100 
1101 
1102    void drawFocusRectangle() {
1103       if(distate & DrawItemState.FOCUS) {
1104          RECT _rect;
1105          rect.getRect(&_rect);
1106          DrawFocusRect(gpx.handle, &_rect);
1107       }
1108    }
1109 
1110 
1111  private:
1112    Graphics gpx;
1113    Font fnt; // Suggestion; the parent's font.
1114    Rect rect;
1115    int idx;
1116    DrawItemState distate;
1117    Color fcolor, bcolor; // Suggestion; depends on item state.
1118 }
1119 
1120 
1121 
1122 class MeasureItemEventArgs: EventArgs {
1123 
1124    this(Graphics g, int index, int itemHeight) {
1125       gpx = g;
1126       idx = index;
1127       iheight = itemHeight;
1128    }
1129 
1130    /// ditto
1131    this(Graphics g, int index) {
1132       this(g, index, 0);
1133    }
1134 
1135 
1136 
1137    final @property Graphics graphics() { // getter
1138       return gpx;
1139    }
1140 
1141 
1142 
1143    final @property int index() { // getter
1144       return idx;
1145    }
1146 
1147 
1148 
1149    final @property void itemHeight(int height) { // setter
1150       iheight = height;
1151    }
1152 
1153    /// ditto
1154    final @property int itemHeight() { // getter
1155       return iheight;
1156    }
1157 
1158 
1159 
1160    final @property void itemWidth(int width) { // setter
1161       iwidth = width;
1162    }
1163 
1164    /// ditto
1165    final @property int itemWidth() { // getter
1166       return iwidth;
1167    }
1168 
1169 
1170  private:
1171    Graphics gpx;
1172    int idx, iheight, iwidth = 0;
1173 }
1174 
1175 
1176 
1177 class Cursor { // docmain
1178    private static Cursor _cur;
1179 
1180 
1181    // Used internally.
1182    this(HCURSOR hcur, bool owned = true) {
1183       this.hcur = hcur;
1184       this.owned = owned;
1185    }
1186 
1187 
1188    ~this() {
1189       if(owned) {
1190          dispose();
1191       }
1192    }
1193 
1194 
1195 
1196    void dispose() {
1197       assert(owned);
1198       DestroyCursor(hcur);
1199       hcur = HCURSOR.init;
1200    }
1201 
1202 
1203 
1204    static @property void current(Cursor cur) { // setter
1205       // Keep a reference so that it doesn't get garbage collected until set again.
1206       _cur = cur;
1207 
1208       SetCursor(cur ? cur.hcur : HCURSOR.init);
1209    }
1210 
1211    /// ditto
1212    static @property Cursor current() { // getter
1213       HCURSOR hcur = GetCursor();
1214       return hcur ? new Cursor(hcur, false) : null;
1215    }
1216 
1217 
1218 
1219    static @property void clip(Rect r) { // setter
1220       RECT rect;
1221       r.getRect(&rect);
1222       ClipCursor(&rect);
1223    }
1224 
1225    /// ditto
1226    static @property Rect clip() { // getter
1227       RECT rect;
1228       GetClipCursor(&rect);
1229       return Rect(&rect);
1230    }
1231 
1232 
1233 
1234    final @property HCURSOR handle() { // getter
1235       return hcur;
1236    }
1237 
1238 
1239    /+
1240    // TODO:
1241    final @property Size size() { // getter
1242       Size result;
1243       ICONINFO iinfo;
1244 
1245       if(GetIconInfo(hcur, &iinfo)) {
1246 
1247       }
1248 
1249       return result;
1250    }
1251    +/
1252 
1253 
1254 
1255    // Uses the actual size.
1256    final void draw(Graphics g, Point pt) {
1257       DrawIconEx(g.handle, pt.x, pt.y, hcur, 0, 0, 0, HBRUSH.init, DI_NORMAL);
1258    }
1259 
1260    /+
1261    /// ditto
1262    // Should not stretch if bigger, but should crop if smaller.
1263    final void draw(Graphics g, Rect r) {
1264    }
1265    +/
1266 
1267 
1268 
1269    final void drawStretched(Graphics g, Rect r) {
1270       // DrawIconEx operates differently if the width or height is zero
1271       // so bail out if zero and pretend the zero size cursor was drawn.
1272       int width = r.width;
1273       if(!width) {
1274          return;
1275       }
1276       int height = r.height;
1277       if(!height) {
1278          return;
1279       }
1280 
1281       DrawIconEx(g.handle, r.x, r.y, hcur, width, height, 0, HBRUSH.init, DI_NORMAL);
1282    }
1283 
1284 
1285    override Dequ opEquals(Object o) {
1286       Cursor cur = cast(Cursor)o;
1287       if(!cur) {
1288          return 0;   // Not equal.
1289       }
1290       return opEquals(cur);
1291    }
1292 
1293 
1294    Dequ opEquals(Cursor cur) {
1295       return hcur == cur.hcur;
1296    }
1297 
1298 
1299    /// Show/hide the current mouse cursor; reference counted.
1300    // show/hide are ref counted.
1301    static void hide() {
1302       ShowCursor(false);
1303    }
1304 
1305    /// ditto
1306    // show/hide are ref counted.
1307    static void show() {
1308       ShowCursor(true);
1309    }
1310 
1311 
1312    /// The position of the current mouse cursor.
1313    static @property void position(Point pt) { // setter
1314       SetCursorPos(pt.x, pt.y);
1315    }
1316 
1317    /// ditto
1318    static @property Point position() { // getter
1319       Point pt;
1320       GetCursorPos(&pt.point);
1321       return pt;
1322    }
1323 
1324 
1325  private:
1326    HCURSOR hcur;
1327    bool owned = true;
1328 }
1329 
1330 
1331 
1332 class Cursors { // docmain
1333    private this() {}
1334 
1335 
1336  static:
1337 
1338 
1339    @property Cursor appStarting() { // getter
1340       return new Cursor(LoadCursorA(HINSTANCE.init, IDC_APPSTARTING), false);
1341    }
1342 
1343 
1344    @property Cursor arrow() { // getter
1345       return new Cursor(LoadCursorA(HINSTANCE.init, IDC_ARROW), false);
1346    }
1347 
1348 
1349    @property Cursor cross() { // getter
1350       return new Cursor(LoadCursorA(HINSTANCE.init, IDC_CROSS), false);
1351    }
1352 
1353 
1354    //@property Cursor default() // getter
1355    @property Cursor defaultCursor() { // getter
1356       return arrow;
1357    }
1358 
1359 
1360    @property Cursor hand() { // getter
1361       version(SUPPORTS_HAND_CURSOR) { // Windows 98+
1362          return new Cursor(LoadCursorA(HINSTANCE.init, IDC_HAND), false);
1363       }
1364       else {
1365          static HCURSOR hcurHand;
1366 
1367          if(!hcurHand) {
1368             hcurHand = LoadCursorA(HINSTANCE.init, IDC_HAND);
1369             if(!hcurHand) { // Must be Windows 95, so load the cursor from winhlp32.exe.
1370                UINT len;
1371                char[MAX_PATH] winhlppath = void;
1372 
1373                len = GetWindowsDirectoryA(winhlppath.ptr, winhlppath.length - 16);
1374                if(!len || len > winhlppath.length - 16) {
1375                load_failed:
1376                   return arrow; // Just fall back to a normal arrow.
1377                }
1378                strcpy(winhlppath.ptr + len, "\\winhlp32.exe");
1379 
1380                HINSTANCE hinstWinhlp;
1381                hinstWinhlp = LoadLibraryExA(winhlppath.ptr, HANDLE.init, LOAD_LIBRARY_AS_DATAFILE);
1382                if(!hinstWinhlp) {
1383                   goto load_failed;
1384                }
1385 
1386                HCURSOR hcur;
1387                hcur = LoadCursorA(hinstWinhlp, cast(char*)106);
1388                if(!hcur) { // No such cursor resource.
1389                   FreeLibrary(hinstWinhlp);
1390                   goto load_failed;
1391                }
1392                hcurHand = CopyCursor(hcur);
1393                if(!hcurHand) {
1394                   FreeLibrary(hinstWinhlp);
1395                   //throw new DflException("Unable to copy cursor resource");
1396                   goto load_failed;
1397                }
1398 
1399                FreeLibrary(hinstWinhlp);
1400             }
1401          }
1402 
1403          assert(hcurHand);
1404          // Copy the cursor and own it here so that it's safe to dispose it.
1405          return new Cursor(CopyCursor(hcurHand));
1406       }
1407    }
1408 
1409 
1410    @property Cursor help() { // getter
1411       HCURSOR hcur;
1412       hcur = LoadCursorA(HINSTANCE.init, IDC_HELP);
1413       if(!hcur) { // IDC_HELP might not be supported on Windows 95, so fall back to a normal arrow.
1414          return arrow;
1415       }
1416       return new Cursor(hcur);
1417    }
1418 
1419 
1420    @property Cursor hSplit() { // getter
1421       // ...
1422       return sizeNS;
1423    }
1424 
1425    /// ditto
1426    @property Cursor vSplit() { // getter
1427       // ...
1428       return sizeWE;
1429    }
1430 
1431 
1432 
1433    @property Cursor iBeam() { // getter
1434       return new Cursor(LoadCursorA(HINSTANCE.init, IDC_IBEAM), false);
1435    }
1436 
1437 
1438    @property Cursor no() { // getter
1439       return new Cursor(LoadCursorA(HINSTANCE.init, IDC_NO), false);
1440    }
1441 
1442 
1443 
1444    @property Cursor sizeAll() { // getter
1445       return new Cursor(LoadCursorA(HINSTANCE.init, IDC_SIZEALL), false);
1446    }
1447 
1448    /// ditto
1449    @property Cursor sizeNESW() { // getter
1450       return new Cursor(LoadCursorA(HINSTANCE.init, IDC_SIZENESW), false);
1451    }
1452 
1453    /// ditto
1454    @property Cursor sizeNS() { // getter
1455       return new Cursor(LoadCursorA(HINSTANCE.init, IDC_SIZENS), false);
1456    }
1457 
1458    /// ditto
1459    @property Cursor sizeNWSE() { // getter
1460       return new Cursor(LoadCursorA(HINSTANCE.init, IDC_SIZENWSE), false);
1461    }
1462 
1463    /// ditto
1464    @property Cursor sizeWE() { // getter
1465       return new Cursor(LoadCursorA(HINSTANCE.init, IDC_SIZEWE), false);
1466    }
1467 
1468 
1469    /+
1470 
1471    // Insertion point.
1472    @property Cursor upArrow() { // getter
1473       // ...
1474    }
1475    +/
1476 
1477 
1478    @property Cursor waitCursor() { // getter
1479       return new Cursor(LoadCursorA(HINSTANCE.init, IDC_WAIT), false);
1480    }
1481 }
1482