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