view 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
line wrap: on
line source
1 /*----------------------------------------------------------------------
2 Copyright (c) Gipsysoft. All Rights Reserved.
3 File: DialogSizer_Set.cpp
4 Web site: http://gipsysoft.com
6 This software is provided 'as-is', without any express or implied warranty.
8 In no event will the author be held liable for any damages arising from the
9 use of this software.
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:
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.
24 Owner: russf@gipsysoft.com
25 Purpose: Main functionality for sizeable dialogs
27 Store a local copy of the user settings
28 Subclass the window
29 Respond to various messages withinn the subclassed window.
31 ----------------------------------------------------------------------*/
32 // modified by the VBA-rr Team
34 #include "stdafx.h"
35 #include "ResizeDlg.h"
36 #include "VBA.h"
37 #include "Sound.h"
38 #include "WinHelper.h"
40 IMPLEMENT_DYNAMIC(ResizeDlg, CDialog)
42 // moved functions to this file to reduce number of files
44 struct RegistryData
45 {
46 WINDOWPLACEMENT m_wpl;
47 };
49 struct DialogData // dd
50 {
51 HKEY hkRootSave;
52 LPCTSTR pcszName;
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;
60 //
61 // We need the smallest to respond to the WM_GETMINMAXINFO message
62 POINT m_ptSmallest;
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;
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;
73 //
74 // Draw the sizing grip...or not
75 bool m_bMaximised;
76 BOOL m_bShowSizingGrip;
78 WinHelper::CRect m_rcGrip;
79 };
81 extern bool regEnabled;
82 extern const char *regGetINIPath();
84 void AssertFailed(char *file, int line, char *exp)
85 {
86 char buffer[1024];
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);
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 }
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);
114 char szExeName[ MAX_PATH ];
116 if (!GetModuleFileName(NULL, szExeName, countof(szExeName)))
117 strcpy(szExeName, "<No Program Name>");
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 );
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 }
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);
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 }
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 }
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 }
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 }
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);
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 }
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 }
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 }
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 }
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 }
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 }
298 void ResizeDlgUpdateGripper(HWND hwnd, DialogData *pdd)
299 {
300 if (pdd->m_bShowSizingGrip)
301 {
302 WinHelper::CRect rcOld(pdd->m_rcGrip);
304 ResizeDlgUpdateGripperRect(pdd->m_sizeClient.cx, pdd->m_sizeClient.cy, pdd->m_rcGrip);
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 }
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 }
331 ResizeDlg::ResizeDlg(UINT id, CWnd *parent)
332 : CDialog(id, parent)
333 {
334 dd = NULL;
335 }
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 }
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();
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 }
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 }
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;
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 }
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);
461 //
462 // Adjust the window horizontally
463 if (psd->uSizeInfo & DS_MoveX)
464 {
465 rc.left += nDeltaX;
466 rc.right += nDeltaX;
467 }
469 //
470 // Adjust the window vertically
471 if (psd->uSizeInfo & DS_MoveY)
472 {
473 rc.top += nDeltaY;
474 rc.bottom += nDeltaY;
475 }
477 //
478 // Size the window horizontally
479 if (psd->uSizeInfo & DS_SizeX)
480 {
481 rc.right += nDeltaX;
482 }
484 //
485 // Size the window vertically
486 if (psd->uSizeInfo & DS_SizeY)
487 {
488 rc.bottom += nDeltaY;
489 }
491 (void)def.DeferWindowPos(hwndChild, NULL, rc,
492 SWP_NOACTIVATE | SWP_NOZORDER);
493 }
494 psd++;
495 }
497 pdd->m_sizeClient.cx = cx;
498 pdd->m_sizeClient.cy = cy;
500 //
501 // If we have a sizing grip enabled then adjust it's position
502 ResizeDlgUpdateGripper(hwnd, pdd);
503 }
504 }
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));
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 }
597 if (pdd->psd)
598 {
599 free(pdd->psd);
600 }
601 free(pdd);
602 }
604 break;
605 }
606 }
607 return CDialog::OnWndMsg(msg, wParam, lParam, res);
608 }