Mercurial > vba-clojure
comparison src/win32/ResizeDlg.cpp @ 1:f9f4f1b99eed
importing src directory
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 03 Mar 2012 10:31:27 -0600 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:8ced16adf2e1 | 1:f9f4f1b99eed |
---|---|
1 /*---------------------------------------------------------------------- | |
2 Copyright (c) Gipsysoft. All Rights Reserved. | |
3 File: DialogSizer_Set.cpp | |
4 Web site: http://gipsysoft.com | |
5 | |
6 This software is provided 'as-is', without any express or implied warranty. | |
7 | |
8 In no event will the author be held liable for any damages arising from the | |
9 use of this software. | |
10 | |
11 Permission is granted to anyone to use this software for any purpose, including | |
12 commercial applications, and to alter it and redistribute it freely, subject | |
13 to the following restrictions: | |
14 | |
15 1) The origin of this software must not be misrepresented; you must not claim | |
16 that you wrote the original software. If you use this software in a product, | |
17 an acknowledgment in the product documentation is requested but not required. | |
18 2) Altered source versions must be plainly marked as such, and must not be | |
19 misrepresented as being the original software. Altered source is encouraged | |
20 to be submitted back to the original author so it can be shared with the | |
21 community. Please share your changes. | |
22 3) This notice may not be removed or altered from any source distribution. | |
23 | |
24 Owner: russf@gipsysoft.com | |
25 Purpose: Main functionality for sizeable dialogs | |
26 | |
27 Store a local copy of the user settings | |
28 Subclass the window | |
29 Respond to various messages withinn the subclassed window. | |
30 | |
31 ----------------------------------------------------------------------*/ | |
32 // modified by the VBA-rr Team | |
33 | |
34 #include "stdafx.h" | |
35 #include "ResizeDlg.h" | |
36 #include "VBA.h" | |
37 #include "Sound.h" | |
38 #include "WinHelper.h" | |
39 | |
40 IMPLEMENT_DYNAMIC(ResizeDlg, CDialog) | |
41 | |
42 // moved functions to this file to reduce number of files | |
43 | |
44 struct RegistryData | |
45 { | |
46 WINDOWPLACEMENT m_wpl; | |
47 }; | |
48 | |
49 struct DialogData // dd | |
50 { | |
51 HKEY hkRootSave; | |
52 LPCTSTR pcszName; | |
53 | |
54 // | |
55 // The number of items contained in the psd member. | |
56 // Used in the DeferWindowPos structure and in allocating memory | |
57 int nItemCount; | |
58 DialogSizerSizingItem *psd; | |
59 | |
60 // | |
61 // We need the smallest to respond to the WM_GETMINMAXINFO message | |
62 POINT m_ptSmallest; | |
63 | |
64 // | |
65 // We don't strictly speaking need to say how big the biggest can be but | |
66 POINT m_ptLargest; | |
67 bool m_bLargestSet; | |
68 | |
69 // | |
70 // we need this to decide how much the window has changed size when we get a WM_SIZE message | |
71 SIZE m_sizeClient; | |
72 | |
73 // | |
74 // Draw the sizing grip...or not | |
75 bool m_bMaximised; | |
76 BOOL m_bShowSizingGrip; | |
77 | |
78 WinHelper::CRect m_rcGrip; | |
79 }; | |
80 | |
81 extern bool regEnabled; | |
82 extern const char *regGetINIPath(); | |
83 | |
84 void AssertFailed(char *file, int line, char *exp) | |
85 { | |
86 char buffer[1024]; | |
87 | |
88 sprintf(buffer, "File %s\nLine %d\nExpression %s\nPress Retry to debug", | |
89 file, line, exp); | |
90 systemSoundClearBuffer(); | |
91 int res = MessageBox(*theApp.m_pMainWnd, buffer, "Assertion failed!", | |
92 MB_ICONHAND | MB_SETFOREGROUND | MB_TASKMODAL | | |
93 MB_ABORTRETRYIGNORE); | |
94 | |
95 if (res == IDRETRY) | |
96 { | |
97 __asm int 3; | |
98 } | |
99 else if (res == IDABORT) | |
100 SendMessage(*theApp.m_pMainWnd, WM_QUIT, 0, 0); | |
101 } | |
102 | |
103 void ApiFailure(char *pcszFilename, int nLine, char *pcszExpression) | |
104 { | |
105 const DWORD dwLastError = ::GetLastError(); | |
106 LPCTSTR lpMsgBuf; | |
107 (void)::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | | |
108 FORMAT_MESSAGE_FROM_SYSTEM | | |
109 FORMAT_MESSAGE_IGNORE_INSERTS, | |
110 NULL, dwLastError, | |
111 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | |
112 (LPTSTR) &lpMsgBuf, 0, NULL); | |
113 | |
114 char szExeName[ MAX_PATH ]; | |
115 | |
116 if (!GetModuleFileName(NULL, szExeName, countof(szExeName))) | |
117 strcpy(szExeName, "<No Program Name>"); | |
118 | |
119 char szMessage[ 1024 ]; | |
120 _snprintf(szMessage, countof(szMessage), | |
121 "API VERIFY Failure!" | |
122 "\nProgram: %s" | |
123 "\n" | |
124 "\nFile %s" | |
125 "\nLine %d" | |
126 "\n" | |
127 "\nExpression %s" | |
128 "\n" | |
129 "\nLast Error %d" | |
130 "\n %s" | |
131 "\n\nPress Retry to debug the application", | |
132 szExeName, | |
133 pcszFilename, | |
134 nLine, | |
135 pcszExpression, | |
136 dwLastError, | |
137 lpMsgBuf | |
138 ); | |
139 | |
140 (void)LocalFree((LPVOID)lpMsgBuf); | |
141 HWND hwndParent = ::GetActiveWindow(); | |
142 hwndParent = ::GetLastActivePopup(hwndParent); | |
143 systemSoundClearBuffer(); | |
144 int nCode = ::MessageBoxA(hwndParent, | |
145 szMessage, | |
146 "Debug Helper", | |
147 MB_TASKMODAL | MB_ICONHAND | MB_ABORTRETRYIGNORE | | |
148 MB_SETFOREGROUND); | |
149 if (nCode == IDABORT) | |
150 { | |
151 ::SendMessage(*theApp.m_pMainWnd, WM_QUIT, 0, 0); | |
152 } | |
153 else if (nCode == IDRETRY) | |
154 __asm int 3; | |
155 } | |
156 | |
157 long FASTCALL RegQueryValueExRecursive(HKEY hKey, | |
158 LPCTSTR lpValueName, | |
159 LPDWORD lpReserved, | |
160 LPDWORD lpType, | |
161 LPBYTE lpData, | |
162 LPDWORD lpcbData) | |
163 { | |
164 TCHAR szBuffer[ 256 ]; | |
165 R_ASSERT(lstrlen(lpValueName) < countof(szBuffer)); | |
166 (void)lstrcpy(szBuffer, lpValueName); | |
167 | |
168 LPTSTR pszBuffer = szBuffer; | |
169 LPTSTR pszLast = szBuffer; | |
170 while (*pszBuffer) | |
171 { | |
172 if (*pszBuffer == _T('\\') || *pszBuffer == _T('/')) | |
173 { | |
174 pszLast = pszBuffer; | |
175 lpValueName = pszLast + 1; | |
176 } | |
177 pszBuffer++; | |
178 } | |
179 | |
180 if (!regEnabled) | |
181 { | |
182 if (GetPrivateProfileStruct("Viewer", | |
183 lpValueName, | |
184 lpData, | |
185 *lpcbData, | |
186 regGetINIPath())) | |
187 { | |
188 *lpType = REG_BINARY; | |
189 return ERROR_SUCCESS; | |
190 } | |
191 return -1; | |
192 } | |
193 | |
194 bool m_bNeedToCloseKey = false; | |
195 if (pszLast != szBuffer) | |
196 { | |
197 *pszLast = _T('\000'); | |
198 HKEY hkeyTemp; | |
199 long lRet = RegOpenKey(hKey, szBuffer, &hkeyTemp); | |
200 if (lRet != ERROR_SUCCESS) | |
201 { | |
202 return lRet; | |
203 } | |
204 hKey = hkeyTemp; | |
205 m_bNeedToCloseKey = true; | |
206 } | |
207 | |
208 long lRet = RegQueryValueEx(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData); | |
209 if (m_bNeedToCloseKey) | |
210 { | |
211 R_VERIFY(RegCloseKey(hKey) == ERROR_SUCCESS); | |
212 } | |
213 return lRet; | |
214 } | |
215 | |
216 long FASTCALL RegSetValueExRecursive(HKEY hKey, | |
217 LPCTSTR lpValueName, | |
218 DWORD Reserved, | |
219 DWORD dwType, | |
220 CONST BYTE*lpData, | |
221 DWORD cbData) | |
222 { | |
223 TCHAR szBuffer[ 256 ]; | |
224 R_ASSERT(lstrlen(lpValueName) < countof(szBuffer)); | |
225 (void)lstrcpy(szBuffer, lpValueName); | |
226 | |
227 LPTSTR pszBuffer = szBuffer; | |
228 LPTSTR pszLast = szBuffer; | |
229 while (*pszBuffer) | |
230 { | |
231 if (*pszBuffer == _T('\\') || *pszBuffer == _T('/')) | |
232 { | |
233 pszLast = pszBuffer; | |
234 lpValueName = pszLast + 1; | |
235 } | |
236 pszBuffer++; | |
237 } | |
238 | |
239 if (!regEnabled) | |
240 { | |
241 if (WritePrivateProfileStruct("Viewer", | |
242 lpValueName, | |
243 (LPVOID)lpData, | |
244 cbData, | |
245 regGetINIPath())) | |
246 { | |
247 return ERROR_SUCCESS; | |
248 } | |
249 return -1; | |
250 } | |
251 | |
252 bool m_bNeedToCloseKey = false; | |
253 if (pszLast != szBuffer) | |
254 { | |
255 *pszLast = _T('\000'); | |
256 HKEY hkeyTemp; | |
257 long lRet = RegOpenKey(hKey, szBuffer, &hkeyTemp); | |
258 if (lRet != ERROR_SUCCESS) | |
259 { | |
260 lRet = RegCreateKey(hKey, szBuffer, &hkeyTemp); | |
261 if (lRet != ERROR_SUCCESS) | |
262 return lRet; | |
263 } | |
264 hKey = hkeyTemp; | |
265 m_bNeedToCloseKey = true; | |
266 } | |
267 | |
268 long lRet = RegSetValueEx(hKey, lpValueName, Reserved, dwType, lpData, cbData); | |
269 if (m_bNeedToCloseKey) | |
270 { | |
271 R_VERIFY(RegCloseKey(hKey) == ERROR_SUCCESS); | |
272 } | |
273 return lRet; | |
274 } | |
275 | |
276 int ResizeDlgGetItemCount(const DialogSizerSizingItem *psd) | |
277 { | |
278 R_ASSERT(psd); | |
279 int nCount = 0; | |
280 while (psd->uSizeInfo != 0xFFFFFFFF) | |
281 { | |
282 nCount++; | |
283 psd++; | |
284 } | |
285 return nCount; | |
286 } | |
287 | |
288 void ResizeDlgUpdateGripperRect(const int cx, const int cy, WinHelper::CRect &rcGrip) | |
289 { | |
290 const int nGripWidth = GetSystemMetrics(SM_CYVSCROLL); | |
291 const int nGripHeight = GetSystemMetrics(SM_CXVSCROLL); | |
292 rcGrip.left = cx - nGripWidth; | |
293 rcGrip.top = cy - nGripHeight; | |
294 rcGrip.right = cx; | |
295 rcGrip.bottom = cy; | |
296 } | |
297 | |
298 void ResizeDlgUpdateGripper(HWND hwnd, DialogData *pdd) | |
299 { | |
300 if (pdd->m_bShowSizingGrip) | |
301 { | |
302 WinHelper::CRect rcOld(pdd->m_rcGrip); | |
303 | |
304 ResizeDlgUpdateGripperRect(pdd->m_sizeClient.cx, pdd->m_sizeClient.cy, pdd->m_rcGrip); | |
305 | |
306 // | |
307 // We also need to invalidate the combined area of the old and new rectangles | |
308 // otherwise we would have trail of grippers when we sized the dialog larger | |
309 // in any axis | |
310 (void)UnionRect(&rcOld, &rcOld, &pdd->m_rcGrip); | |
311 (void)InvalidateRect(hwnd, &rcOld, TRUE); | |
312 } | |
313 } | |
314 | |
315 void ResizeDlgCopyItems(DialogSizerSizingItem *psdDest, const DialogSizerSizingItem *psdSource) | |
316 // | |
317 // Will copy all of the items in psdSource into psdDest. | |
318 { | |
319 // | |
320 // Loop til we reach the end | |
321 while (psdSource->uSizeInfo != 0xFFFFFFFF) | |
322 { | |
323 *psdDest = *psdSource; | |
324 psdDest++; | |
325 psdSource++; | |
326 } | |
327 // And when we do copy the last item | |
328 *psdDest = *psdSource; | |
329 } | |
330 | |
331 ResizeDlg::ResizeDlg(UINT id, CWnd *parent) | |
332 : CDialog(id, parent) | |
333 { | |
334 dd = NULL; | |
335 } | |
336 | |
337 void *ResizeDlg::AddDialogData() | |
338 // | |
339 // Firstly determine if the data already exists, if it does then return that, if not then we will | |
340 // create and initialise a brand new structure. | |
341 { | |
342 DialogData *pdd = (DialogData *)dd; | |
343 if (!pdd) | |
344 { | |
345 pdd = (DialogData *)calloc(1, sizeof(DialogData)); | |
346 } | |
347 | |
348 if (pdd) | |
349 { | |
350 // | |
351 // Store some sizes etc. for later. | |
352 CRect rc; | |
353 GetWindowRect(rc); | |
354 pdd->m_ptSmallest.x = rc.Width(); | |
355 pdd->m_ptSmallest.y = rc.Height(); | |
356 | |
357 GetClientRect(rc); | |
358 pdd->m_sizeClient = rc.Size(); | |
359 dd = pdd; | |
360 ResizeDlgUpdateGripperRect(pdd->m_sizeClient.cx, pdd->m_sizeClient.cy, pdd->m_rcGrip); | |
361 } | |
362 return pdd; | |
363 } | |
364 | |
365 BOOL ResizeDlg::SetData(const DialogSizerSizingItem *psd, | |
366 BOOL bShowSizingGrip, | |
367 HKEY hkRootSave, | |
368 LPCTSTR pcszName, | |
369 SIZE *psizeMax) | |
370 // | |
371 // Setting a dialog sizeable involves subclassing the window and handling it's | |
372 // WM_SIZE messages, if we have a hkRootSave and pcszName then we will also be loading/saving | |
373 // the size and position of the window from the registry. We load from the registry when we | |
374 // subclass the window and we save to the registry when we get a WM_DESTROY. | |
375 // | |
376 // It will return non-zero for success and zero if it fails | |
377 { | |
378 R_ASSERT(psd); | |
379 R_ASSERT((hkRootSave != NULL && pcszName != NULL) | |
380 || (hkRootSave == NULL && pcszName == NULL)); | |
381 // | |
382 // Make sure all of the parameters are valid. | |
383 if (::IsWindow(*this) | |
384 && psd | |
385 && ((hkRootSave != NULL && pcszName != NULL && | |
386 !IsBadStringPtr(pcszName, 0xFFFF)) || | |
387 (hkRootSave == NULL && pcszName == NULL)) | |
388 && (psizeMax == NULL || !IsBadReadPtr(psizeMax, sizeof(SIZE))) | |
389 ) | |
390 { | |
391 DialogData *pdd = (DialogData *)AddDialogData(); | |
392 if (pdd) | |
393 { | |
394 pdd->hkRootSave = hkRootSave; | |
395 pdd->pcszName = pcszName; | |
396 pdd->m_bShowSizingGrip = bShowSizingGrip; | |
397 pdd->nItemCount = ResizeDlgGetItemCount(psd) + 1; | |
398 pdd->psd = (DialogSizerSizingItem *) | |
399 calloc(pdd->nItemCount, | |
400 sizeof(DialogSizerSizingItem)); | |
401 if (pdd->psd) | |
402 { | |
403 // | |
404 // Copy all of the user controls etc. for later, this way the user can quite happily | |
405 // let the structure go out of scope. | |
406 ResizeDlgCopyItems(pdd->psd, psd); | |
407 if (psizeMax) | |
408 { | |
409 pdd->m_ptLargest.x = psizeMax->cx; | |
410 pdd->m_ptLargest.y = psizeMax->cy; | |
411 pdd->m_bLargestSet = true; | |
412 } | |
413 | |
414 // | |
415 // If the there was save info passed in then we need to make damn good use of it | |
416 // by attempting to load the RegistryData structure | |
417 if (hkRootSave && pcszName) | |
418 { | |
419 RegistryData rd; | |
420 DWORD dwSize = sizeof(RegistryData); | |
421 DWORD dwType = REG_BINARY; | |
422 if (RegQueryValueExRecursive(hkRootSave, pcszName, NULL, &dwType, reinterpret_cast<LPBYTE>(&rd), | |
423 &dwSize) == ERROR_SUCCESS && dwSize == sizeof(rd)) | |
424 { | |
425 if (!(GetWindowLong(*this, GWL_STYLE) & WS_VISIBLE)) | |
426 rd.m_wpl.showCmd = SW_HIDE; | |
427 | |
428 VAPI(SetWindowPlacement(&rd.m_wpl)); | |
429 } | |
430 } | |
431 return TRUE; | |
432 } | |
433 else | |
434 { | |
435 free(pdd); | |
436 } | |
437 } | |
438 } | |
439 return FALSE; | |
440 } | |
441 | |
442 void ResizeDlg::UpdateWindowSize(const int cx, const int cy, HWND hwnd) | |
443 { | |
444 DialogData *pdd = (DialogData *)dd; | |
445 if (pdd) | |
446 { | |
447 const int nDeltaX = cx - pdd->m_sizeClient.cx; | |
448 const int nDeltaY = cy - pdd->m_sizeClient.cy; | |
449 WinHelper::CDeferWindowPos def(pdd->nItemCount); | |
450 WinHelper::CRect rc; | |
451 const DialogSizerSizingItem *psd = pdd->psd; | |
452 while (psd->uSizeInfo != 0xFFFFFFFF) | |
453 { | |
454 HWND hwndChild = ::GetDlgItem(*this, psd->uControlID); | |
455 if (::IsWindow(hwndChild)) | |
456 { | |
457 VAPI(::GetWindowRect(hwndChild, rc)); | |
458 (void)::MapWindowPoints(::GetDesktopWindow(), hwnd, | |
459 (LPPOINT)&rc, 2); | |
460 | |
461 // | |
462 // Adjust the window horizontally | |
463 if (psd->uSizeInfo & DS_MoveX) | |
464 { | |
465 rc.left += nDeltaX; | |
466 rc.right += nDeltaX; | |
467 } | |
468 | |
469 // | |
470 // Adjust the window vertically | |
471 if (psd->uSizeInfo & DS_MoveY) | |
472 { | |
473 rc.top += nDeltaY; | |
474 rc.bottom += nDeltaY; | |
475 } | |
476 | |
477 // | |
478 // Size the window horizontally | |
479 if (psd->uSizeInfo & DS_SizeX) | |
480 { | |
481 rc.right += nDeltaX; | |
482 } | |
483 | |
484 // | |
485 // Size the window vertically | |
486 if (psd->uSizeInfo & DS_SizeY) | |
487 { | |
488 rc.bottom += nDeltaY; | |
489 } | |
490 | |
491 (void)def.DeferWindowPos(hwndChild, NULL, rc, | |
492 SWP_NOACTIVATE | SWP_NOZORDER); | |
493 } | |
494 psd++; | |
495 } | |
496 | |
497 pdd->m_sizeClient.cx = cx; | |
498 pdd->m_sizeClient.cy = cy; | |
499 | |
500 // | |
501 // If we have a sizing grip enabled then adjust it's position | |
502 ResizeDlgUpdateGripper(hwnd, pdd); | |
503 } | |
504 } | |
505 | |
506 BOOL ResizeDlg::OnWndMsg(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *res) | |
507 // Actual window procedure that will handle saving window size/position and moving | |
508 // the controls whilst the window sizes. | |
509 { | |
510 if (dd == NULL) | |
511 { | |
512 return CDialog::OnWndMsg(msg, wParam, lParam, res); | |
513 } | |
514 switch (msg) | |
515 { | |
516 case WM_ERASEBKGND: | |
517 { | |
518 BOOL r = CDialog::OnWndMsg(msg, wParam, lParam, res); | |
519 DialogData *pdd = (DialogData *)dd; | |
520 if (pdd && pdd->m_bShowSizingGrip && !pdd->m_bMaximised) | |
521 { | |
522 VAPI(::DrawFrameControl(reinterpret_cast<HDC>(wParam), | |
523 pdd->m_rcGrip, | |
524 DFC_SCROLL, DFCS_SCROLLSIZEGRIP)); | |
525 } | |
526 return r; | |
527 } | |
528 case WM_SIZE: | |
529 { | |
530 DialogData *pdd = (DialogData *)dd; | |
531 if (pdd && wParam != SIZE_MINIMIZED) | |
532 { | |
533 pdd->m_bMaximised = (wParam == SIZE_MAXIMIZED ? true : false); | |
534 UpdateWindowSize(LOWORD(lParam), HIWORD(lParam), *this); | |
535 } | |
536 break; | |
537 } | |
538 case WM_NCHITTEST: | |
539 { | |
540 // | |
541 // If the gripper is enabled then perform a simple hit test on our gripper area. | |
542 DialogData *pdd = (DialogData *)dd; | |
543 if (pdd && pdd->m_bShowSizingGrip) | |
544 { | |
545 POINT pt = { LOWORD(lParam), HIWORD(lParam) }; | |
546 (void)ScreenToClient(&pt); | |
547 if (PtInRect(pdd->m_rcGrip, pt)) | |
548 return (BOOL)HTBOTTOMRIGHT; | |
549 } | |
550 break; | |
551 } | |
552 case WM_GETMINMAXINFO: | |
553 { | |
554 // | |
555 // Our opportunity to say that we do not want the dialog to grow or shrink any more. | |
556 DialogData * pdd = (DialogData *)dd; | |
557 LPMINMAXINFO lpmmi = reinterpret_cast<LPMINMAXINFO>(lParam); | |
558 lpmmi->ptMinTrackSize = pdd->m_ptSmallest; | |
559 if (pdd->m_bLargestSet) | |
560 { | |
561 lpmmi->ptMaxTrackSize = pdd->m_ptLargest; | |
562 } | |
563 } | |
564 return (BOOL)0; | |
565 case WM_NOTIFY: | |
566 { | |
567 if (reinterpret_cast<LPNMHDR>(lParam)->code == PSN_SETACTIVE) | |
568 { | |
569 CRect rc; | |
570 VAPI(::GetClientRect(*GetParent(), &rc)); | |
571 UpdateWindowSize(rc.Width(), rc.Height(), *GetParent()); | |
572 } | |
573 break; | |
574 } | |
575 case WM_DESTROY: | |
576 { | |
577 // | |
578 // Our opportunty for cleanup. | |
579 // Simply acquire all of our objects, free the appropriate memory and remove the | |
580 // properties from the window. If we do not remove the properties then they will constitute | |
581 // a resource leak. | |
582 DialogData *pdd = (DialogData *)dd; | |
583 if (pdd) | |
584 { | |
585 RegistryData rd; | |
586 rd.m_wpl.length = sizeof(rd.m_wpl); | |
587 VAPI(GetWindowPlacement(&rd.m_wpl)); | |
588 | |
589 if (pdd->hkRootSave && pdd->pcszName) | |
590 { | |
591 (void)RegSetValueExRecursive(pdd->hkRootSave, pdd->pcszName, | |
592 NULL, REG_BINARY, | |
593 reinterpret_cast<LPBYTE>(&rd), | |
594 sizeof(rd)); | |
595 } | |
596 | |
597 if (pdd->psd) | |
598 { | |
599 free(pdd->psd); | |
600 } | |
601 free(pdd); | |
602 } | |
603 | |
604 break; | |
605 } | |
606 } | |
607 return CDialog::OnWndMsg(msg, wParam, lParam, res); | |
608 } | |
609 |