|
1
|
1 // Windows Template Library - WTL version 10.0
|
|
|
2 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.
|
|
|
3 //
|
|
|
4 // This file is a part of the Windows Template Library.
|
|
|
5 // The use and distribution terms for this software are covered by the
|
|
|
6 // Microsoft Public License (http://opensource.org/licenses/MS-PL)
|
|
|
7 // which can be found in the file MS-PL.txt at the root folder.
|
|
|
8
|
|
|
9 #ifndef __ATLDDX_H__
|
|
|
10 #define __ATLDDX_H__
|
|
|
11
|
|
|
12 #pragma once
|
|
|
13
|
|
|
14 #ifndef __ATLAPP_H__
|
|
|
15 #error atlddx.h requires atlapp.h to be included first
|
|
|
16 #endif
|
|
|
17
|
|
|
18 #include <float.h>
|
|
|
19
|
|
|
20
|
|
|
21 ///////////////////////////////////////////////////////////////////////////////
|
|
|
22 // Classes in this file:
|
|
|
23 //
|
|
|
24 // CWinDataExchange<T>
|
|
|
25
|
|
|
26
|
|
|
27 namespace WTL
|
|
|
28 {
|
|
|
29
|
|
|
30 // Constants
|
|
|
31 #define DDX_LOAD FALSE
|
|
|
32 #define DDX_SAVE TRUE
|
|
|
33
|
|
|
34 // DDX map macros
|
|
|
35 #define BEGIN_DDX_MAP(thisClass) \
|
|
|
36 BOOL DoDataExchange(BOOL bSaveAndValidate = FALSE, UINT nCtlID = (UINT)-1) \
|
|
|
37 { \
|
|
|
38 (bSaveAndValidate); \
|
|
|
39 (nCtlID);
|
|
|
40
|
|
|
41 #define DDX_TEXT(nID, var) \
|
|
|
42 if((nCtlID == (UINT)-1) || (nCtlID == nID)) \
|
|
|
43 { \
|
|
|
44 if(!DDX_Text(nID, var, sizeof(var), bSaveAndValidate)) \
|
|
|
45 return FALSE; \
|
|
|
46 }
|
|
|
47
|
|
|
48 #define DDX_TEXT_LEN(nID, var, len) \
|
|
|
49 if((nCtlID == (UINT)-1) || (nCtlID == nID)) \
|
|
|
50 { \
|
|
|
51 if(!DDX_Text(nID, var, sizeof(var), bSaveAndValidate, TRUE, len)) \
|
|
|
52 return FALSE; \
|
|
|
53 }
|
|
|
54
|
|
|
55 #define DDX_INT(nID, var) \
|
|
|
56 if((nCtlID == (UINT)-1) || (nCtlID == nID)) \
|
|
|
57 { \
|
|
|
58 if(!DDX_Int(nID, var, TRUE, bSaveAndValidate)) \
|
|
|
59 return FALSE; \
|
|
|
60 }
|
|
|
61
|
|
|
62 #define DDX_INT_RANGE(nID, var, min, max) \
|
|
|
63 if((nCtlID == (UINT)-1) || (nCtlID == nID)) \
|
|
|
64 { \
|
|
|
65 if(!DDX_Int(nID, var, TRUE, bSaveAndValidate, TRUE, min, max)) \
|
|
|
66 return FALSE; \
|
|
|
67 }
|
|
|
68
|
|
|
69 #define DDX_UINT(nID, var) \
|
|
|
70 if((nCtlID == (UINT)-1) || (nCtlID == nID)) \
|
|
|
71 { \
|
|
|
72 if(!DDX_Int(nID, var, FALSE, bSaveAndValidate)) \
|
|
|
73 return FALSE; \
|
|
|
74 }
|
|
|
75
|
|
|
76 #define DDX_UINT_RANGE(nID, var, min, max) \
|
|
|
77 if((nCtlID == (UINT)-1) || (nCtlID == nID)) \
|
|
|
78 { \
|
|
|
79 if(!DDX_Int(nID, var, FALSE, bSaveAndValidate, TRUE, min, max)) \
|
|
|
80 return FALSE; \
|
|
|
81 }
|
|
|
82
|
|
|
83 #define DDX_FLOAT(nID, var) \
|
|
|
84 if((nCtlID == (UINT)-1) || (nCtlID == nID)) \
|
|
|
85 { \
|
|
|
86 if(!DDX_Float(nID, var, bSaveAndValidate)) \
|
|
|
87 return FALSE; \
|
|
|
88 }
|
|
|
89
|
|
|
90 #define DDX_FLOAT_RANGE(nID, var, min, max) \
|
|
|
91 if((nCtlID == (UINT)-1) || (nCtlID == nID)) \
|
|
|
92 { \
|
|
|
93 if(!DDX_Float(nID, var, bSaveAndValidate, TRUE, min, max)) \
|
|
|
94 return FALSE; \
|
|
|
95 }
|
|
|
96 #define DDX_FLOAT_P(nID, var, precision) \
|
|
|
97 if((nCtlID == (UINT)-1) || (nCtlID == nID)) \
|
|
|
98 { \
|
|
|
99 if(!DDX_Float(nID, var, bSaveAndValidate, FALSE, 0, 0, precision)) \
|
|
|
100 return FALSE; \
|
|
|
101 }
|
|
|
102
|
|
|
103 #define DDX_FLOAT_P_RANGE(nID, var, min, max, precision) \
|
|
|
104 if((nCtlID == (UINT)-1) || (nCtlID == nID)) \
|
|
|
105 { \
|
|
|
106 if(!DDX_Float(nID, var, bSaveAndValidate, TRUE, min, max, precision)) \
|
|
|
107 return FALSE; \
|
|
|
108 }
|
|
|
109
|
|
|
110 #define DDX_CONTROL(nID, obj) \
|
|
|
111 if((nCtlID == (UINT)-1) || (nCtlID == nID)) \
|
|
|
112 DDX_Control(nID, obj, bSaveAndValidate);
|
|
|
113
|
|
|
114 #define DDX_CONTROL_HANDLE(nID, obj) \
|
|
|
115 if((nCtlID == (UINT)-1) || (nCtlID == nID)) \
|
|
|
116 DDX_Control_Handle(nID, obj, bSaveAndValidate);
|
|
|
117
|
|
|
118 #define DDX_CHECK(nID, var) \
|
|
|
119 if((nCtlID == (UINT)-1) || (nCtlID == nID)) \
|
|
|
120 DDX_Check(nID, var, bSaveAndValidate);
|
|
|
121
|
|
|
122 #define DDX_RADIO(nID, var) \
|
|
|
123 if((nCtlID == (UINT)-1) || (nCtlID == nID)) \
|
|
|
124 DDX_Radio(nID, var, bSaveAndValidate);
|
|
|
125
|
|
|
126 #define END_DDX_MAP() \
|
|
|
127 return TRUE; \
|
|
|
128 }
|
|
|
129
|
|
|
130 // DDX support for Tab, Combo, ListBox and ListView selection index
|
|
|
131 // Note: Specialized versions require atlctrls.h to be included first
|
|
|
132
|
|
|
133 #define DDX_INDEX(CtrlClass, nID, var) \
|
|
|
134 if((nCtlID == (UINT)-1) || (nCtlID == nID)) \
|
|
|
135 DDX_Index<CtrlClass>(nID, var, bSaveAndValidate);
|
|
|
136
|
|
|
137 #ifdef __ATLCTRLS_H__
|
|
|
138 #define DDX_TAB_INDEX(nID, var) DDX_INDEX(WTL::CTabCtrl, nID, var)
|
|
|
139 #define DDX_COMBO_INDEX(nID, var) DDX_INDEX(WTL::CComboBox, nID, var)
|
|
|
140 #define DDX_LISTBOX_INDEX(nID, var) DDX_INDEX(WTL::CListBox, nID, var)
|
|
|
141 #define DDX_LISTVIEW_INDEX(nID, var) DDX_INDEX(WTL::CListViewCtrl, nID, var)
|
|
|
142 #endif // __ATLCTRLS_H__
|
|
|
143
|
|
|
144
|
|
|
145 ///////////////////////////////////////////////////////////////////////////////
|
|
|
146 // CWinDataExchange - provides support for DDX
|
|
|
147
|
|
|
148 template <class T>
|
|
|
149 class CWinDataExchange
|
|
|
150 {
|
|
|
151 public:
|
|
|
152 // Data exchange method - override in your derived class
|
|
|
153 BOOL DoDataExchange(BOOL /*bSaveAndValidate*/ = FALSE, UINT /*nCtlID*/ = (UINT)-1)
|
|
|
154 {
|
|
|
155 // this one should never be called, override it in
|
|
|
156 // your derived class by implementing DDX map
|
|
|
157 ATLASSERT(FALSE);
|
|
|
158 return FALSE;
|
|
|
159 }
|
|
|
160
|
|
|
161 // Helpers for validation error reporting
|
|
|
162 enum _XDataType
|
|
|
163 {
|
|
|
164 ddxDataNull = 0,
|
|
|
165 ddxDataText = 1,
|
|
|
166 ddxDataInt = 2,
|
|
|
167 ddxDataFloat = 3,
|
|
|
168 ddxDataDouble = 4
|
|
|
169 };
|
|
|
170
|
|
|
171 struct _XTextData
|
|
|
172 {
|
|
|
173 int nLength;
|
|
|
174 int nMaxLength;
|
|
|
175 };
|
|
|
176
|
|
|
177 struct _XIntData
|
|
|
178 {
|
|
|
179 long nVal;
|
|
|
180 long nMin;
|
|
|
181 long nMax;
|
|
|
182 };
|
|
|
183
|
|
|
184 struct _XFloatData
|
|
|
185 {
|
|
|
186 double nVal;
|
|
|
187 double nMin;
|
|
|
188 double nMax;
|
|
|
189 };
|
|
|
190
|
|
|
191 struct _XData
|
|
|
192 {
|
|
|
193 _XDataType nDataType;
|
|
|
194 union
|
|
|
195 {
|
|
|
196 _XTextData textData;
|
|
|
197 _XIntData intData;
|
|
|
198 _XFloatData floatData;
|
|
|
199 };
|
|
|
200 };
|
|
|
201
|
|
|
202 // Text exchange
|
|
|
203 BOOL DDX_Text(UINT nID, LPTSTR lpstrText, int cbSize, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0)
|
|
|
204 {
|
|
|
205 T* pT = static_cast<T*>(this);
|
|
|
206 BOOL bSuccess = TRUE;
|
|
|
207
|
|
|
208 if(bSave)
|
|
|
209 {
|
|
|
210 HWND hWndCtrl = pT->GetDlgItem(nID);
|
|
|
211 int nRetLen = ::GetWindowText(hWndCtrl, lpstrText, cbSize / sizeof(TCHAR));
|
|
|
212 if(nRetLen < ::GetWindowTextLength(hWndCtrl))
|
|
|
213 bSuccess = FALSE;
|
|
|
214 }
|
|
|
215 else
|
|
|
216 {
|
|
|
217 ATLASSERT(!bValidate || (lstrlen(lpstrText) <= nLength));
|
|
|
218 bSuccess = pT->SetDlgItemText(nID, lpstrText);
|
|
|
219 }
|
|
|
220
|
|
|
221 if(!bSuccess)
|
|
|
222 {
|
|
|
223 pT->OnDataExchangeError(nID, bSave);
|
|
|
224 }
|
|
|
225 else if(bSave && bValidate) // validation
|
|
|
226 {
|
|
|
227 ATLASSERT(nLength > 0);
|
|
|
228 if(lstrlen(lpstrText) > nLength)
|
|
|
229 {
|
|
|
230 _XData data = { ddxDataText };
|
|
|
231 data.textData.nLength = lstrlen(lpstrText);
|
|
|
232 data.textData.nMaxLength = nLength;
|
|
|
233 pT->OnDataValidateError(nID, bSave, data);
|
|
|
234 bSuccess = FALSE;
|
|
|
235 }
|
|
|
236 }
|
|
|
237 return bSuccess;
|
|
|
238 }
|
|
|
239
|
|
|
240 BOOL DDX_Text(UINT nID, BSTR& bstrText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0)
|
|
|
241 {
|
|
|
242 T* pT = static_cast<T*>(this);
|
|
|
243 BOOL bSuccess = TRUE;
|
|
|
244
|
|
|
245 if(bSave)
|
|
|
246 {
|
|
|
247 bSuccess = pT->GetDlgItemText(nID, bstrText);
|
|
|
248 }
|
|
|
249 else
|
|
|
250 {
|
|
|
251 USES_CONVERSION;
|
|
|
252 LPTSTR lpstrText = OLE2T(bstrText);
|
|
|
253 ATLASSERT(!bValidate || (lstrlen(lpstrText) <= nLength));
|
|
|
254 bSuccess = pT->SetDlgItemText(nID, lpstrText);
|
|
|
255 }
|
|
|
256
|
|
|
257 if(!bSuccess)
|
|
|
258 {
|
|
|
259 pT->OnDataExchangeError(nID, bSave);
|
|
|
260 }
|
|
|
261 else if(bSave && bValidate) // validation
|
|
|
262 {
|
|
|
263 ATLASSERT(nLength > 0);
|
|
|
264 if((int)::SysStringLen(bstrText) > nLength)
|
|
|
265 {
|
|
|
266 _XData data = { ddxDataText };
|
|
|
267 data.textData.nLength = (int)::SysStringLen(bstrText);
|
|
|
268 data.textData.nMaxLength = nLength;
|
|
|
269 pT->OnDataValidateError(nID, bSave, data);
|
|
|
270 bSuccess = FALSE;
|
|
|
271 }
|
|
|
272 }
|
|
|
273 return bSuccess;
|
|
|
274 }
|
|
|
275
|
|
|
276 BOOL DDX_Text(UINT nID, ATL::CComBSTR& bstrText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0)
|
|
|
277 {
|
|
|
278 T* pT = static_cast<T*>(this);
|
|
|
279 BOOL bSuccess = TRUE;
|
|
|
280
|
|
|
281 if(bSave)
|
|
|
282 {
|
|
|
283 bSuccess = pT->GetDlgItemText(nID, (BSTR&)bstrText);
|
|
|
284 }
|
|
|
285 else
|
|
|
286 {
|
|
|
287 USES_CONVERSION;
|
|
|
288 LPTSTR lpstrText = OLE2T(bstrText);
|
|
|
289 ATLASSERT(!bValidate || (lstrlen(lpstrText) <= nLength));
|
|
|
290 bSuccess = pT->SetDlgItemText(nID, lpstrText);
|
|
|
291 }
|
|
|
292
|
|
|
293 if(!bSuccess)
|
|
|
294 {
|
|
|
295 pT->OnDataExchangeError(nID, bSave);
|
|
|
296 }
|
|
|
297 else if(bSave && bValidate) // validation
|
|
|
298 {
|
|
|
299 ATLASSERT(nLength > 0);
|
|
|
300 if((int)bstrText.Length() > nLength)
|
|
|
301 {
|
|
|
302 _XData data = { ddxDataText };
|
|
|
303 data.textData.nLength = (int)bstrText.Length();
|
|
|
304 data.textData.nMaxLength = nLength;
|
|
|
305 pT->OnDataValidateError(nID, bSave, data);
|
|
|
306 bSuccess = FALSE;
|
|
|
307 }
|
|
|
308 }
|
|
|
309 return bSuccess;
|
|
|
310 }
|
|
|
311
|
|
|
312 #ifdef __ATLSTR_H__
|
|
|
313 BOOL DDX_Text(UINT nID, ATL::CString& strText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0)
|
|
|
314 {
|
|
|
315 T* pT = static_cast<T*>(this);
|
|
|
316 BOOL bSuccess = TRUE;
|
|
|
317
|
|
|
318 if(bSave)
|
|
|
319 {
|
|
|
320 HWND hWndCtrl = pT->GetDlgItem(nID);
|
|
|
321 int nLen = ::GetWindowTextLength(hWndCtrl);
|
|
|
322 int nRetLen = -1;
|
|
|
323 LPTSTR lpstr = strText.GetBufferSetLength(nLen);
|
|
|
324 if(lpstr != NULL)
|
|
|
325 {
|
|
|
326 nRetLen = ::GetWindowText(hWndCtrl, lpstr, nLen + 1);
|
|
|
327 strText.ReleaseBuffer();
|
|
|
328 }
|
|
|
329 if(nRetLen < nLen)
|
|
|
330 bSuccess = FALSE;
|
|
|
331 }
|
|
|
332 else
|
|
|
333 {
|
|
|
334 bSuccess = pT->SetDlgItemText(nID, strText);
|
|
|
335 }
|
|
|
336
|
|
|
337 if(!bSuccess)
|
|
|
338 {
|
|
|
339 pT->OnDataExchangeError(nID, bSave);
|
|
|
340 }
|
|
|
341 else if(bSave && bValidate) // validation
|
|
|
342 {
|
|
|
343 ATLASSERT(nLength > 0);
|
|
|
344 if(strText.GetLength() > nLength)
|
|
|
345 {
|
|
|
346 _XData data = { ddxDataText };
|
|
|
347 data.textData.nLength = strText.GetLength();
|
|
|
348 data.textData.nMaxLength = nLength;
|
|
|
349 pT->OnDataValidateError(nID, bSave, data);
|
|
|
350 bSuccess = FALSE;
|
|
|
351 }
|
|
|
352 }
|
|
|
353 return bSuccess;
|
|
|
354 }
|
|
|
355 #endif // __ATLSTR_H__
|
|
|
356
|
|
|
357 // Numeric exchange
|
|
|
358 template <class Type>
|
|
|
359 BOOL DDX_Int(UINT nID, Type& nVal, BOOL bSigned, BOOL bSave, BOOL bValidate = FALSE, Type nMin = 0, Type nMax = 0)
|
|
|
360 {
|
|
|
361 T* pT = static_cast<T*>(this);
|
|
|
362 BOOL bSuccess = TRUE;
|
|
|
363
|
|
|
364 if(bSave)
|
|
|
365 {
|
|
|
366 nVal = (Type)pT->GetDlgItemInt(nID, &bSuccess, bSigned);
|
|
|
367 }
|
|
|
368 else
|
|
|
369 {
|
|
|
370 ATLASSERT(!bValidate || ((nVal >= nMin) && (nVal <= nMax)));
|
|
|
371 bSuccess = pT->SetDlgItemInt(nID, nVal, bSigned);
|
|
|
372 }
|
|
|
373
|
|
|
374 if(!bSuccess)
|
|
|
375 {
|
|
|
376 pT->OnDataExchangeError(nID, bSave);
|
|
|
377 }
|
|
|
378 else if(bSave && bValidate) // validation
|
|
|
379 {
|
|
|
380 ATLASSERT(nMin != nMax);
|
|
|
381 if((nVal < nMin) || (nVal > nMax))
|
|
|
382 {
|
|
|
383 _XData data = { ddxDataInt };
|
|
|
384 data.intData.nVal = (long)nVal;
|
|
|
385 data.intData.nMin = (long)nMin;
|
|
|
386 data.intData.nMax = (long)nMax;
|
|
|
387 pT->OnDataValidateError(nID, bSave, data);
|
|
|
388 bSuccess = FALSE;
|
|
|
389 }
|
|
|
390 }
|
|
|
391 return bSuccess;
|
|
|
392 }
|
|
|
393
|
|
|
394 // Float exchange
|
|
|
395 static BOOL _AtlSimpleFloatParse(LPCTSTR lpszText, double& d)
|
|
|
396 {
|
|
|
397 ATLASSERT(lpszText != NULL);
|
|
|
398 while ((*lpszText == _T(' ')) || (*lpszText == _T('\t')))
|
|
|
399 lpszText++;
|
|
|
400
|
|
|
401 TCHAR chFirst = lpszText[0];
|
|
|
402 d = _tcstod(lpszText, (LPTSTR*)&lpszText);
|
|
|
403 if ((d == 0.0) && (chFirst != _T('0')))
|
|
|
404 return FALSE; // could not convert
|
|
|
405 while ((*lpszText == _T(' ')) || (*lpszText == _T('\t')))
|
|
|
406 lpszText++;
|
|
|
407
|
|
|
408 if (*lpszText != _T('\0'))
|
|
|
409 return FALSE; // not terminated properly
|
|
|
410
|
|
|
411 return TRUE;
|
|
|
412 }
|
|
|
413
|
|
|
414 BOOL DDX_Float(UINT nID, float& nVal, BOOL bSave, BOOL bValidate = FALSE, float nMin = 0.F, float nMax = 0.F, int nPrecision = FLT_DIG)
|
|
|
415 {
|
|
|
416 T* pT = static_cast<T*>(this);
|
|
|
417 BOOL bSuccess = TRUE;
|
|
|
418 const int cchBuff = 32;
|
|
|
419 TCHAR szBuff[cchBuff] = {};
|
|
|
420
|
|
|
421 if(bSave)
|
|
|
422 {
|
|
|
423 pT->GetDlgItemText(nID, szBuff, cchBuff);
|
|
|
424 double d = 0;
|
|
|
425 if(_AtlSimpleFloatParse(szBuff, d))
|
|
|
426 nVal = (float)d;
|
|
|
427 else
|
|
|
428 bSuccess = FALSE;
|
|
|
429 }
|
|
|
430 else
|
|
|
431 {
|
|
|
432 ATLASSERT(!bValidate || ((nVal >= nMin) && (nVal <= nMax)));
|
|
|
433 _stprintf_s(szBuff, cchBuff, _T("%.*g"), nPrecision, nVal);
|
|
|
434 bSuccess = pT->SetDlgItemText(nID, szBuff);
|
|
|
435 }
|
|
|
436
|
|
|
437 if(!bSuccess)
|
|
|
438 {
|
|
|
439 pT->OnDataExchangeError(nID, bSave);
|
|
|
440 }
|
|
|
441 else if(bSave && bValidate) // validation
|
|
|
442 {
|
|
|
443 ATLASSERT(nMin != nMax);
|
|
|
444 if((nVal < nMin) || (nVal > nMax))
|
|
|
445 {
|
|
|
446 _XData data = { ddxDataFloat };
|
|
|
447 data.floatData.nVal = (double)nVal;
|
|
|
448 data.floatData.nMin = (double)nMin;
|
|
|
449 data.floatData.nMax = (double)nMax;
|
|
|
450 pT->OnDataValidateError(nID, bSave, data);
|
|
|
451 bSuccess = FALSE;
|
|
|
452 }
|
|
|
453 }
|
|
|
454 return bSuccess;
|
|
|
455 }
|
|
|
456
|
|
|
457 BOOL DDX_Float(UINT nID, double& nVal, BOOL bSave, BOOL bValidate = FALSE, double nMin = 0., double nMax = 0., int nPrecision = DBL_DIG)
|
|
|
458 {
|
|
|
459 T* pT = static_cast<T*>(this);
|
|
|
460 BOOL bSuccess = TRUE;
|
|
|
461 const int cchBuff = 32;
|
|
|
462 TCHAR szBuff[cchBuff] = {};
|
|
|
463
|
|
|
464 if(bSave)
|
|
|
465 {
|
|
|
466 pT->GetDlgItemText(nID, szBuff, cchBuff);
|
|
|
467 double d = 0;
|
|
|
468 if(_AtlSimpleFloatParse(szBuff, d))
|
|
|
469 nVal = d;
|
|
|
470 else
|
|
|
471 bSuccess = FALSE;
|
|
|
472 }
|
|
|
473 else
|
|
|
474 {
|
|
|
475 ATLASSERT(!bValidate || ((nVal >= nMin) && (nVal <= nMax)));
|
|
|
476 _stprintf_s(szBuff, cchBuff, _T("%.*g"), nPrecision, nVal);
|
|
|
477 bSuccess = pT->SetDlgItemText(nID, szBuff);
|
|
|
478 }
|
|
|
479
|
|
|
480 if(!bSuccess)
|
|
|
481 {
|
|
|
482 pT->OnDataExchangeError(nID, bSave);
|
|
|
483 }
|
|
|
484 else if(bSave && bValidate) // validation
|
|
|
485 {
|
|
|
486 ATLASSERT(nMin != nMax);
|
|
|
487 if((nVal < nMin) || (nVal > nMax))
|
|
|
488 {
|
|
|
489 _XData data = { ddxDataFloat };
|
|
|
490 data.floatData.nVal = nVal;
|
|
|
491 data.floatData.nMin = nMin;
|
|
|
492 data.floatData.nMax = nMax;
|
|
|
493 pT->OnDataValidateError(nID, bSave, data);
|
|
|
494 bSuccess = FALSE;
|
|
|
495 }
|
|
|
496 }
|
|
|
497 return bSuccess;
|
|
|
498 }
|
|
|
499
|
|
|
500 // Full control subclassing (for CWindowImpl derived controls)
|
|
|
501 template <class TControl>
|
|
|
502 void DDX_Control(UINT nID, TControl& ctrl, BOOL bSave)
|
|
|
503 {
|
|
|
504 if(!bSave && (ctrl.m_hWnd == NULL))
|
|
|
505 {
|
|
|
506 T* pT = static_cast<T*>(this);
|
|
|
507 ctrl.SubclassWindow(pT->GetDlgItem(nID));
|
|
|
508 }
|
|
|
509 }
|
|
|
510
|
|
|
511 // Simple control attaching (for HWND wrapper controls)
|
|
|
512 template <class TControl>
|
|
|
513 void DDX_Control_Handle(UINT nID, TControl& ctrl, BOOL bSave)
|
|
|
514 {
|
|
|
515 if(!bSave && (ctrl.m_hWnd == NULL))
|
|
|
516 {
|
|
|
517 T* pT = static_cast<T*>(this);
|
|
|
518 ctrl = pT->GetDlgItem(nID);
|
|
|
519 }
|
|
|
520 }
|
|
|
521
|
|
|
522 // Control state
|
|
|
523 void DDX_Check(UINT nID, int& nValue, BOOL bSave)
|
|
|
524 {
|
|
|
525 T* pT = static_cast<T*>(this);
|
|
|
526 HWND hWndCtrl = pT->GetDlgItem(nID);
|
|
|
527 if(bSave)
|
|
|
528 {
|
|
|
529 nValue = (int)::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L);
|
|
|
530 ATLASSERT((nValue >= 0) && (nValue <= 2));
|
|
|
531 }
|
|
|
532 else
|
|
|
533 {
|
|
|
534 if((nValue < 0) || (nValue > 2))
|
|
|
535 {
|
|
|
536 ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - dialog data checkbox value (%d) out of range.\n"), nValue);
|
|
|
537 nValue = 0; // default to off
|
|
|
538 }
|
|
|
539 ::SendMessage(hWndCtrl, BM_SETCHECK, nValue, 0L);
|
|
|
540 }
|
|
|
541 }
|
|
|
542
|
|
|
543 // variant that supports bool (checked/not-checked, no intermediate state)
|
|
|
544 void DDX_Check(UINT nID, bool& bCheck, BOOL bSave)
|
|
|
545 {
|
|
|
546 int nValue = bCheck ? 1 : 0;
|
|
|
547 DDX_Check(nID, nValue, bSave);
|
|
|
548
|
|
|
549 if(bSave)
|
|
|
550 {
|
|
|
551 if(nValue == 2)
|
|
|
552 ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - checkbox state (%d) out of supported range.\n"), nValue);
|
|
|
553 bCheck = (nValue == 1);
|
|
|
554 }
|
|
|
555 }
|
|
|
556
|
|
|
557 void DDX_Radio(UINT nID, int& nValue, BOOL bSave)
|
|
|
558 {
|
|
|
559 T* pT = static_cast<T*>(this);
|
|
|
560 HWND hWndCtrl = pT->GetDlgItem(nID);
|
|
|
561 ATLASSERT(hWndCtrl != NULL);
|
|
|
562
|
|
|
563 // must be first in a group of auto radio buttons
|
|
|
564 ATLASSERT(::GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP);
|
|
|
565 ATLASSERT(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON);
|
|
|
566
|
|
|
567 if(bSave)
|
|
|
568 nValue = -1; // value if none found
|
|
|
569
|
|
|
570 // walk all children in group
|
|
|
571 int nButton = 0;
|
|
|
572 do
|
|
|
573 {
|
|
|
574 if(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON)
|
|
|
575 {
|
|
|
576 // control in group is a radio button
|
|
|
577 if(bSave)
|
|
|
578 {
|
|
|
579 if(::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L) != 0)
|
|
|
580 {
|
|
|
581 ATLASSERT(nValue == -1); // only set once
|
|
|
582 nValue = nButton;
|
|
|
583 }
|
|
|
584 }
|
|
|
585 else
|
|
|
586 {
|
|
|
587 // select button
|
|
|
588 ::SendMessage(hWndCtrl, BM_SETCHECK, (nButton == nValue), 0L);
|
|
|
589 }
|
|
|
590 nButton++;
|
|
|
591 }
|
|
|
592 else
|
|
|
593 {
|
|
|
594 ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - skipping non-radio button in group.\n"));
|
|
|
595 }
|
|
|
596 hWndCtrl = ::GetWindow(hWndCtrl, GW_HWNDNEXT);
|
|
|
597 }
|
|
|
598 while ((hWndCtrl != NULL) && !(GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP));
|
|
|
599 }
|
|
|
600
|
|
|
601 // DDX support for Tab, Combo, ListBox and ListView selection index
|
|
|
602 template <class TCtrl>
|
|
|
603 INT _getSel(TCtrl& tCtrl)
|
|
|
604 {
|
|
|
605 return tCtrl.GetCurSel();
|
|
|
606 }
|
|
|
607
|
|
|
608 template <class TCtrl>
|
|
|
609 void _setSel(TCtrl& tCtrl, INT iSel)
|
|
|
610 {
|
|
|
611 if(iSel < 0)
|
|
|
612 tCtrl.SetCurSel(-1);
|
|
|
613 else
|
|
|
614 tCtrl.SetCurSel(iSel);
|
|
|
615 }
|
|
|
616
|
|
|
617 #ifdef __ATLCTRLS_H__
|
|
|
618 // ListViewCtrl specialization
|
|
|
619 template <>
|
|
|
620 INT _getSel(WTL::CListViewCtrl& tCtrl)
|
|
|
621 {
|
|
|
622 return tCtrl.GetSelectedIndex();
|
|
|
623 }
|
|
|
624
|
|
|
625 template <>
|
|
|
626 void _setSel(WTL::CListViewCtrl& tCtrl, INT iSel)
|
|
|
627 {
|
|
|
628 if(iSel < 0)
|
|
|
629 tCtrl.SelectItem(-1);
|
|
|
630 else
|
|
|
631 tCtrl.SelectItem(iSel);
|
|
|
632 }
|
|
|
633 #endif // __ATLCTRLS_H__
|
|
|
634
|
|
|
635 template <class TCtrl>
|
|
|
636 void DDX_Index(UINT nID, INT& nVal, BOOL bSave)
|
|
|
637 {
|
|
|
638 T* pT = static_cast<T*>(this);
|
|
|
639 TCtrl ctrl(pT->GetDlgItem(nID));
|
|
|
640
|
|
|
641 if(bSave)
|
|
|
642 nVal = _getSel(ctrl);
|
|
|
643 else
|
|
|
644 _setSel(ctrl, nVal);
|
|
|
645 }
|
|
|
646
|
|
|
647 // Overrideables
|
|
|
648 void OnDataExchangeError(UINT nCtrlID, BOOL /*bSave*/)
|
|
|
649 {
|
|
|
650 // Override to display an error message
|
|
|
651 ::MessageBeep((UINT)-1);
|
|
|
652 T* pT = static_cast<T*>(this);
|
|
|
653 ::SetFocus(pT->GetDlgItem(nCtrlID));
|
|
|
654 }
|
|
|
655
|
|
|
656 void OnDataValidateError(UINT nCtrlID, BOOL /*bSave*/, _XData& /*data*/)
|
|
|
657 {
|
|
|
658 // Override to display an error message
|
|
|
659 ::MessageBeep((UINT)-1);
|
|
|
660 T* pT = static_cast<T*>(this);
|
|
|
661 ::SetFocus(pT->GetDlgItem(nCtrlID));
|
|
|
662 }
|
|
|
663 };
|
|
|
664
|
|
|
665 } // namespace WTL
|
|
|
666
|
|
|
667 #endif // __ATLDDX_H__
|