1 // Written by Christopher E. Miller
2 // See the included license.txt for copyright and license details.
3 
4 module dfl.colordialog;
5 
6 import core.sys.windows.windows;
7 import dfl.commondialog;
8 import dfl.base;
9 // FIX: import dfl.internal.winapi;
10 // FIX: import dfl.internal.wincom;
11 
12 import dfl.internal.utf;
13 import dfl.application;
14 import dfl.drawing;
15 import dfl.internal.dlib;
16 
17 class ColorDialog : CommonDialog {
18    this() {
19       Application.ppin(cast(void*) this);
20 
21       cc.lStructSize = cc.sizeof;
22       cc.Flags = INIT_FLAGS;
23       cc.rgbResult = Color.empty.toArgb();
24       cc.lCustData = cast(typeof(cc.lCustData)) cast(void*) this;
25       cc.lpfnHook = cast(typeof(cc.lpfnHook))&ccHookProc;
26       _initcust();
27    }
28 
29    @property void allowFullOpen(bool byes) {
30       if (byes) {
31          cc.Flags &= ~CC_PREVENTFULLOPEN;
32       } else {
33          cc.Flags |= CC_PREVENTFULLOPEN;
34       }
35    }
36 
37    @property bool allowFullOpen() {
38       return (cc.Flags & CC_PREVENTFULLOPEN) != CC_PREVENTFULLOPEN;
39    }
40 
41    @property void anyColor(bool byes) {
42       if (byes) {
43          cc.Flags |= CC_ANYCOLOR;
44       } else {
45          cc.Flags &= ~CC_ANYCOLOR;
46       }
47    }
48 
49    @property bool anyColor() {
50       return (cc.Flags & CC_ANYCOLOR) == CC_ANYCOLOR;
51    }
52 
53    @property void solidColorOnly(bool byes) {
54       if (byes) {
55          cc.Flags |= CC_SOLIDCOLOR;
56       } else {
57          cc.Flags &= ~CC_SOLIDCOLOR;
58       }
59    }
60 
61    @property bool solidColorOnly() {
62       return (cc.Flags & CC_SOLIDCOLOR) == CC_SOLIDCOLOR;
63    }
64 
65    final @property void color(Color c) {
66       cc.rgbResult = c.toRgb();
67    }
68 
69    final @property Color color() {
70       return Color.fromRgb(cc.rgbResult);
71    }
72 
73    final @property void customColors(COLORREF[] colors) {
74       if (colors.length >= _cust.length) {
75          _cust[] = colors[0 .. _cust.length];
76       } else {
77          _cust[0 .. colors.length] = colors[];
78       }
79    }
80 
81    final @property COLORREF[] customColors() {
82       return _cust;
83    }
84 
85    @property void fullOpen(bool byes) {
86       if (byes) {
87          cc.Flags |= CC_FULLOPEN;
88       } else {
89          cc.Flags &= ~CC_FULLOPEN;
90       }
91    }
92 
93    @property bool fullOpen() {
94       return (cc.Flags & CC_FULLOPEN) == CC_FULLOPEN;
95    }
96 
97    @property void showHelp(bool byes) {
98       if (byes) {
99          cc.Flags |= CC_SHOWHELP;
100       } else {
101          cc.Flags &= ~CC_SHOWHELP;
102       }
103    }
104 
105    @property bool showHelp() {
106       return (cc.Flags & CC_SHOWHELP) == CC_SHOWHELP;
107    }
108 
109    override DialogResult showDialog() {
110       return runDialog(GetActiveWindow()) ? DialogResult.OK : DialogResult.CANCEL;
111    }
112 
113    override DialogResult showDialog(IWindow owner) {
114       return runDialog(owner ? owner.handle : GetActiveWindow()) ? DialogResult.OK
115          : DialogResult.CANCEL;
116    }
117 
118    override void reset() {
119       cc.Flags = INIT_FLAGS;
120       cc.rgbResult = Color.empty.toArgb();
121       _initcust();
122    }
123 
124    protected override bool runDialog(HWND owner) {
125       if (!_runDialog(owner)) {
126          if (!CommDlgExtendedError()) {
127             return false;
128          }
129          _cantrun();
130       }
131       return true;
132    }
133 
134    private BOOL _runDialog(HWND owner) {
135       if (cc.rgbResult == Color.empty.toArgb()) {
136          cc.Flags &= ~CC_RGBINIT;
137       } else {
138          cc.Flags |= CC_RGBINIT;
139       }
140       cc.hwndOwner = owner;
141       cc.lpCustColors = _cust.ptr;
142       return ChooseColorA(&cc);
143    }
144 
145    private:
146    enum DWORD INIT_FLAGS = CC_ENABLEHOOK;
147 
148    CHOOSECOLORA cc;
149    COLORREF[16] _cust;
150 
151    void _initcust() {
152       COLORREF cdef;
153       cdef = Color(0xFF, 0xFF, 0xFF).toRgb();
154       foreach (ref COLORREF cref; _cust) {
155          cref = cdef;
156       }
157    }
158 }
159 
160 private extern (Windows) UINT ccHookProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
161    enum PROP_STR = "DFL_ColorDialog";
162    ColorDialog cd;
163    UINT result = 0;
164 
165    try {
166       if (msg == WM_INITDIALOG) {
167          CHOOSECOLORA* cc;
168          cc = cast(CHOOSECOLORA*) lparam;
169          SetPropA(hwnd, PROP_STR.ptr, cast(HANDLE) cc.lCustData);
170          cd = cast(ColorDialog) cast(void*) cc.lCustData;
171       } else {
172          cd = cast(ColorDialog) cast(void*) GetPropA(hwnd, PROP_STR.ptr);
173       }
174 
175       if (cd) {
176          result = cast(UINT) cd.hookProc(hwnd, msg, wparam, lparam);
177       }
178    }
179    catch (DThrowable e) {
180       Application.onThreadException(e);
181    }
182 
183    return result;
184 }