Update NEWS for 1.6.22
[pkg-k5-afs_openafs.git] / src / WINNT / afsapplib / resize.cpp
blob0c1c5014bb932179431050521ec121f021a144d5
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
10 extern "C" {
11 #include <afs/param.h>
12 #include <afs/stds.h>
15 #include <windows.h>
16 #include <stdlib.h>
17 #include <WINNT/al_resource.h> // To see if you have IDC_HSPLIT etc
18 #include <WINNT/resize.h>
19 #include <WINNT/subclass.h>
20 #include <WINNT/TaLocale.h>
24 * DEFINITIONS ________________________________________________________________
28 #ifndef limit
29 #define limit(_a,_x,_b) (min( max( (_a),(_x) ), (_b) ))
30 #endif
31 #ifndef inlimit
32 #define inlimit(_a,_x,_b) ( (_x >= _a) && (_x <= _b) )
33 #endif
35 #ifndef THIS_HINST
36 #define THIS_HINST (GetModuleHandle (NULL))
37 #endif
39 #ifndef GWL_USER
40 #define GWL_USER 0
41 #endif
43 #ifndef cxRECT
44 #define cxRECT(_r) ((_r).right - (_r).left)
45 #endif
46 #ifndef cyRECT
47 #define cyRECT(_r) ((_r).bottom - (_r).top)
48 #endif
50 typedef struct // SplitterData
52 LONG *pcDelta; // pointer to LONG to hold cx/yDelta
53 int idWnd1; // first window to split between
54 int idWnd2; // second window to split between
55 rwWindowData *awd; // data list for using splitter
56 BOOL fX; // TRUE if moves in X, FALSE if in Y
57 BOOL fDragging; // TRUE if dragging with the mouse
58 POINT ptStart; // point at which started dragging
59 BOOL fMovedBeforeCreate; // TRUE if windows moved before create
60 } SplitterData;
64 * VARIABLES __________________________________________________________________
68 typedef struct
70 HWND hWnd;
71 RECT rWnd;
72 LONG cxDeltaCenter;
73 LONG cyDeltaCenter;
74 rwWindowData *awdLast;
75 } WindowList;
77 static WindowList *awl;
78 static size_t cwl = 0;
82 * PROTOTYPES _________________________________________________________________
86 int rwFindOrAddWnd (HWND, rwWindowData * = 0);
87 void rwFindAndRemoveWnd (HWND);
88 DWORD rwFindAction (rwWindowData *, int);
90 BOOL WhereShouldSplitterGo (HWND, int, int, RECT *, BOOL *);
91 void EnsureSplitterRegistered (void);
92 LONG APIENTRY SplitterWndProc (HWND, UINT, WPARAM, LPARAM);
93 void ResizeSplitter (HWND, SplitterData *, LONG, LONG*);
94 void FindSplitterMinMax (HWND, SplitterData *, LONG,
95 LONG*, LONG*);
97 void FindResizeLimits (HWND hWnd, LONG *pcxMin, LONG *pcxMax, LONG *pcyMin, LONG *pcyMax, rwWindowData * = 0);
99 HRESULT CALLBACK Resize_DialogProc (HWND hWnd, UINT msg, WPARAM wp, LPARAM lp);
103 * ROUTINES ___________________________________________________________________
107 #ifndef REALLOC
108 #define REALLOC(_a,_c,_r,_i) ResizeReallocFunction ((LPVOID*)&_a,sizeof(*_a),&_c,_r,_i)
109 BOOL ResizeReallocFunction (LPVOID *ppTarget, size_t cbElement, size_t *pcTarget, size_t cReq, size_t cInc)
111 LPVOID pNew;
112 size_t cNew;
114 if (cReq <= *pcTarget)
115 return TRUE;
117 if ((cNew = cInc * ((cReq + cInc-1) / cInc)) <= 0)
118 return FALSE;
120 if ((pNew = (LPVOID)Allocate (cbElement * cNew)) == NULL)
121 return FALSE;
122 memset (pNew, 0x00, cbElement * cNew);
124 if (*pcTarget != 0)
126 memcpy (pNew, *ppTarget, cbElement * (*pcTarget));
127 Free (*ppTarget);
130 *ppTarget = pNew;
131 *pcTarget = cNew;
132 return TRUE;
134 #endif
137 void ResizeWindow (HWND hWnd, rwWindowData *awd, rwAction rwa, RECT *pr)
139 static BOOL fInHere = FALSE; // prevent reentrancy during SetWindowPos().
140 int ii;
141 RECT rOld, rNew;
143 if (fInHere)
144 return;
146 // We maintain list of where-was-this-window-last-time; find
147 // This window in that list, or add it.
149 if ((ii = rwFindOrAddWnd (hWnd, awd)) == -1)
150 goto lblDONE;
152 rOld = awl[ii].rWnd; // previous position
154 // If the window disappears, then remove its entry from the
155 // list of windows.
157 if (!IsWindow (hWnd))
159 awl[ii].hWnd = NULL;
160 goto lblDONE;
163 // If told to, move and/or resize this parent window.
165 if (rwa == rwaMoveToHere)
167 if (pr == NULL)
168 goto lblDONE;
170 fInHere = TRUE;
172 SetWindowPos (hWnd, NULL,
173 pr->left,
174 pr->top,
175 pr->right - pr->left,
176 pr->bottom - pr->top,
177 SWP_NOZORDER | SWP_NOACTIVATE);
179 fInHere = FALSE;
181 rNew = *pr;
183 else
185 GetWindowRect (hWnd, &rNew);
188 // Window has moved from {rOld} to {rNew},
189 // or
190 // Window's client area has been changed by {*pr}
192 if (rwa == rwaMoveToHere || rwa == rwaFixupGuts || rwa == rwaNewClientArea)
194 LONG dx, dy;
195 LONG dxc, dyc;
197 if (rwa == rwaNewClientArea)
199 dx = pr->right - pr->left;
200 dy = pr->bottom - pr->top;
202 else
204 dx = (rNew.right -rNew.left) - (rOld.right -rOld.left);
205 dy = (rNew.bottom -rNew.top) - (rOld.bottom -rOld.top);
208 if (abs(dx) & 1)
209 awl[ii].cxDeltaCenter += (dx > 0) ? 1 : -1;
210 if (abs(dy) & 1)
211 awl[ii].cyDeltaCenter += (dy > 0) ? 1 : -1;
213 dxc = dx + awl[ii].cxDeltaCenter/2;
214 dyc = dy + awl[ii].cyDeltaCenter/2;
216 awl[ii].cxDeltaCenter %= 2;
217 awl[ii].cyDeltaCenter %= 2;
219 if (dx != 0 || dy != 0)
221 HWND hItem;
222 size_t nItems = 0;
224 for (hItem = GetWindow (hWnd, GW_CHILD);
225 hItem != NULL;
226 hItem = GetWindow (hItem, GW_HWNDNEXT))
228 nItems++;
231 if (nItems != 0)
233 DWORD ra;
234 HDWP dwp = BeginDeferWindowPos (nItems);
235 BOOL fRepaint = FALSE;
237 for (hItem = GetWindow (hWnd, GW_CHILD);
238 hItem != NULL;
239 hItem = GetWindow (hItem, GW_HWNDNEXT))
241 RECT rItem;
243 GetRectInParent (hItem, &rItem);
245 ra = rwFindAction (awd, (GetWindowLong (hItem, GWL_ID)));
247 DeferWindowPos (dwp, hItem, NULL,
248 rItem.left + ((ra & raMoveX) ? dx :
249 (ra & raMoveXB) ? (0-dx) :
250 (ra & raMoveXC) ? (dxc/2) : 0),
251 rItem.top + ((ra & raMoveY) ? dy :
252 (ra & raMoveYB) ? (0-dy) :
253 (ra & raMoveYC) ? (dyc/2) : 0),
254 rItem.right -rItem.left
255 + ((ra & raSizeX) ? dx :
256 (ra & raSizeXB) ? (0-dx) :
257 (ra & raSizeXC) ? (dxc/2) : 0),
258 rItem.bottom -rItem.top
259 + ((ra & raSizeY) ? dy :
260 (ra & raSizeYB) ? (0-dy) :
261 (ra & raSizeYC) ? (dyc/2) : 0),
262 SWP_NOACTIVATE | SWP_NOZORDER);
265 EndDeferWindowPos (dwp);
267 for (hItem = GetWindow (hWnd, GW_CHILD);
268 hItem != NULL;
269 hItem = GetWindow (hItem, GW_HWNDNEXT))
271 ra = rwFindAction (awd, (GetWindowLong (hItem, GWL_ID)));
273 if (ra & raRepaint)
275 RECT rItem;
276 GetRectInParent (hItem, &rItem);
277 InvalidateRect (hWnd, &rItem, TRUE);
278 fRepaint = TRUE;
281 if (ra & raNotify)
283 RECT rClient;
284 GetClientRect (hItem, &rClient);
285 SendMessage (hItem, WM_SIZE, SIZE_RESTORED, MAKELPARAM( rClient.right-rClient.left, rClient.bottom-rClient.top ));
289 if (fRepaint)
291 UpdateWindow (hWnd);
297 // Record this window's current position
299 awl[ii].rWnd = rNew;
301 lblDONE:
302 fInHere = FALSE;
306 int rwFindOrAddWnd (HWND hWnd, rwWindowData *awd)
308 // Is the window handle listed in awl[] already?
310 int ii;
311 for (ii = 0; ii < (int)cwl; ii++)
313 if (awl[ii].hWnd == hWnd)
315 if (awd)
316 awl[ii].awdLast = awd;
317 return ii;
321 // No? Then add it.
323 for (ii = 0; ii < (int)cwl; ii++)
325 if (awl[ii].hWnd == NULL)
326 break;
328 if (ii == (int)cwl)
330 if (!REALLOC (awl, cwl, ii+1, 1))
331 return (DWORD)-1;
334 awl[ii].hWnd = hWnd;
335 awl[ii].awdLast = awd;
337 if (IsWindow (hWnd))
339 GetWindowRect (hWnd, &awl[ii].rWnd);
340 Subclass_AddHook (hWnd, Resize_DialogProc);
342 else
344 awl[ii].rWnd.left = 0;
345 awl[ii].rWnd.right = 0;
346 awl[ii].rWnd.top = 0;
347 awl[ii].rWnd.bottom = 0;
349 awl[ii].cxDeltaCenter = 0;
350 awl[ii].cyDeltaCenter = 0;
352 return ii;
356 void rwFindAndRemoveWnd (HWND hWnd)
358 for (size_t ii = 0; ii < (int)cwl; ii++)
360 if (awl[ii].hWnd == hWnd)
362 Subclass_RemoveHook (awl[ii].hWnd, hWnd);
363 awl[ii].hWnd = NULL;
364 return;
370 DWORD rwFindAction (rwWindowData *awd, int id)
372 DWORD raDefault = raLeaveAlone;
374 if (awd != NULL)
376 for (int ii = 0; awd[ii].id != idENDLIST; ++ii)
378 if (awd[ii].id == id)
379 return awd[ii].ra;
380 if (awd[ii].id == idDEFAULT)
381 raDefault = awd[ii].ra;
385 return raDefault;
389 void GetRectInParent (HWND hWnd, RECT *pr)
391 POINT pt;
393 GetWindowRect (hWnd, pr);
395 pr->right -= pr->left;
396 pr->bottom -= pr->top; // right/bottom == width/height for now
398 pt.x = pr->left;
399 pt.y = pr->top;
401 ScreenToClient (GetParent (hWnd), &pt);
403 pr->left = pt.x;
404 pr->top = pt.y;
405 pr->right += pr->left;
406 pr->bottom += pr->top;
411 * SPLITTERS __________________________________________________________________
415 static BOOL fRegistered = FALSE; // TRUE If registered class
417 static TCHAR cszSplitterClassX[] = TEXT("SplitterWindowClassX");
418 static TCHAR cszSplitterClassY[] = TEXT("SplitterWindowClassY");
421 HWND CreateSplitter (HWND hWnd, int id1, int id2, int id,
422 LONG *pcd, rwWindowData *awd, BOOL fMovedAlready)
424 SplitterData *psd;
425 RECT rWnd;
426 BOOL fX;
428 if (!WhereShouldSplitterGo (hWnd, id1, id2, &rWnd, &fX))
429 return NULL;
431 EnsureSplitterRegistered ();
433 psd = (SplitterData *)Allocate (sizeof(SplitterData));
434 if (psd == NULL)
435 return NULL;
437 psd->pcDelta = pcd;
438 psd->awd = awd;
439 psd->fX = fX;
440 psd->idWnd1 = id1;
441 psd->idWnd2 = id2;
442 psd->fMovedBeforeCreate = fMovedAlready;
444 return CreateWindow(
445 (fX) ? cszSplitterClassX : cszSplitterClassY,
446 TEXT(""), // Title
447 WS_CHILD | WS_VISIBLE, // Window style
448 rWnd.left, // Default horizontal position
449 rWnd.top, // Default vertical position
450 rWnd.right -rWnd.left, // Default width
451 rWnd.bottom -rWnd.top, // Default height
452 hWnd, // Parent window
453 (HMENU)id, // Use ID given us by caller
454 THIS_HINST, // This instance owns this window
455 (void *)psd // Pointer not needed
459 void DeleteSplitter (HWND hWnd, int id1)
461 HWND hSplit;
463 if (hSplit = GetDlgItem (hWnd, id1))
465 DestroyWindow (hSplit);
469 void EnsureSplitterRegistered (void)
471 WNDCLASS wc;
473 if (fRegistered)
474 return;
475 fRegistered = TRUE;
477 wc.style = CS_HREDRAW | CS_VREDRAW;
478 wc.lpfnWndProc = (WNDPROC)SplitterWndProc;
479 wc.cbClsExtra = 0;
480 wc.cbWndExtra = sizeof(SplitterData *);
481 wc.hInstance = THIS_HINST;
482 wc.hIcon = NULL;
483 wc.hbrBackground = CreateSolidBrush( GetSysColor( COLOR_BTNFACE ));
484 wc.lpszMenuName = NULL;
486 // Register the X-moving class:
488 #ifdef IDC_HSPLIT
489 wc.hCursor = LoadCursor (THIS_HINST, MAKEINTRESOURCE( IDC_HSPLIT ));
490 #else
491 wc.hCursor = LoadCursor (NULL, IDC_SIZEWE);
492 #endif
494 wc.lpszClassName = cszSplitterClassX;
496 (void)RegisterClass (&wc);
498 // Register the Y-moving class:
500 #ifdef IDC_VSPLIT
501 wc.hCursor = LoadCursor (THIS_HINST, MAKEINTRESOURCE( IDC_VSPLIT ));
502 #else
503 wc.hCursor = LoadCursor (NULL, IDC_SIZENS);
504 #endif
506 wc.lpszClassName = cszSplitterClassY;
508 (void)RegisterClass (&wc);
513 BOOL WhereShouldSplitterGo (HWND hWnd, int id1, int id2, RECT *prWnd, BOOL *pfX)
515 RECT r1, r2;
516 BOOL rc = TRUE;
518 GetRectInParent (GetDlgItem (hWnd, id1), &r1);
519 GetRectInParent (GetDlgItem (hWnd, id2), &r2);
521 if (r2.left > r1.right) // R1 on left, R2 on right?
523 *pfX = TRUE;
524 prWnd->top = min (r1.top, r2.top);
525 prWnd->bottom = max (r1.bottom, r2.bottom);
526 prWnd->left = r1.right;
527 prWnd->right = r2.left;
529 else if (r2.right < r1.left) // R2 on left, R1 on right?
531 *pfX = TRUE;
532 prWnd->top = min (r1.top, r2.top);
533 prWnd->bottom = max (r1.bottom, r2.bottom);
534 prWnd->left = r2.right;
535 prWnd->right = r1.left;
537 else if (r2.top > r1.bottom) // R1 on top, R2 on bottom?
539 *pfX = FALSE;
540 prWnd->left = min (r1.left, r2.left);
541 prWnd->right = max (r1.right, r2.right);
542 prWnd->top = r1.bottom;
543 prWnd->bottom = r2.top;
545 else if (r2.bottom < r1.top) // R2 on top, R1 on bottom?
547 *pfX = FALSE;
548 prWnd->left = min (r1.left, r2.left);
549 prWnd->right = max (r1.right, r2.right);
550 prWnd->top = r2.bottom;
551 prWnd->bottom = r1.top;
553 else // Rectangles intersect!
554 { // Don't know where it should go.
555 rc = FALSE;
558 return rc;
562 LONG APIENTRY SplitterWndProc (HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
564 SplitterData *psd;
565 static LONG cdAtStart;
567 if (msg == WM_CREATE)
569 SetWindowLong (hWnd,GWL_USER,(LONG)((LPCREATESTRUCT)lp)->lpCreateParams);
572 if ((psd = (SplitterData *)GetWindowLong (hWnd, GWL_USER)) != NULL)
574 switch (msg)
576 case WM_CREATE:
577 if (!psd->fMovedBeforeCreate)
578 ResizeSplitter (GetParent (hWnd), psd, 0, psd->pcDelta);
579 psd->fDragging = FALSE;
580 break;
582 case WM_LBUTTONDOWN:
583 if (!psd->fDragging)
585 SetCapture (hWnd);
586 psd->fDragging = TRUE;
587 cdAtStart = *psd->pcDelta;
589 GetCursorPos (&psd->ptStart);
590 ScreenToClient (GetParent (hWnd), &psd->ptStart);
592 break;
594 case WM_MOUSEMOVE:
595 if (psd->fDragging)
597 POINT pt;
598 LONG cx, cy;
599 LONG cd;
601 GetCursorPos (&pt);
602 ScreenToClient (GetParent (hWnd), &pt);
604 cx = (LONG)pt.x - (LONG)psd->ptStart.x;
605 cy = (LONG)pt.y - (LONG)psd->ptStart.y;
607 if (psd->fX)
608 cd = cdAtStart + cx;
609 else // (!psd->fX)
610 cd = cdAtStart + cy;
612 if (cd != *(psd->pcDelta))
614 ResizeSplitter (GetParent(hWnd), psd, *psd->pcDelta, &cd);
615 *psd->pcDelta = cd;
618 break;
620 case WM_LBUTTONUP:
621 if (psd->fDragging)
623 ReleaseCapture ();
624 psd->fDragging = FALSE;
626 break;
628 case WM_DESTROY:
629 if (psd->fDragging)
631 ReleaseCapture ();
632 psd->fDragging = FALSE;
634 Free (psd);
635 psd = NULL; // fault blatantly if you use {psd} now
636 SetWindowLong (hWnd, GWL_USER, 0);
638 break;
640 #if 0 // Enable me to make the splitters draw in black
641 case WM_PAINT:
643 PAINTSTRUCT ps;
644 HDC hdc = BeginPaint (hWnd, &ps);
645 FillRect (hdc, &ps.rcPaint, GetStockObject(BLACK_BRUSH));
646 EndPaint (hWnd, &ps);
647 return 0;
649 break;
650 #endif
654 return DefWindowProc (hWnd, msg, wp, lp);
658 void ResizeSplitter (HWND hWnd, SplitterData *psd, LONG cOld, LONG *pcNew)
660 LONG dx, dy;
661 HWND hItem;
662 size_t nItems = 0;
663 LONG cdMin, cdMax;
665 if (psd == NULL || pcNew == NULL || hWnd == NULL)
666 return;
668 FindSplitterMinMax (hWnd, psd, cOld, &cdMin, &cdMax);
669 *pcNew = limit (cdMin, *pcNew, cdMax);
671 if (*pcNew == cOld)
672 return;
674 dx = (psd->fX) ? (*pcNew - cOld) : 0;
675 dy = (psd->fX) ? 0 : (*pcNew - cOld);
677 for (hItem = GetWindow (hWnd, GW_CHILD);
678 hItem != NULL;
679 hItem = GetWindow (hItem, GW_HWNDNEXT))
681 nItems++;
684 if (nItems != 0)
686 BOOL fRepaint = FALSE;
687 HDWP dwp = BeginDeferWindowPos (nItems);
689 for (hItem = GetWindow (hWnd, GW_CHILD);
690 hItem != NULL;
691 hItem = GetWindow (hItem, GW_HWNDNEXT))
693 RECT rItem;
694 DWORD ra;
696 GetRectInParent (hItem, &rItem);
698 ra = rwFindAction (psd->awd, (GetWindowLong (hItem, GWL_ID)));
700 DeferWindowPos (dwp, hItem, NULL,
701 rItem.left + ((ra & raMoveX) ? dx :
702 (ra & raMoveXB) ? (0-dx) : 0),
703 rItem.top + ((ra & raMoveY) ? dy :
704 (ra & raMoveYB) ? (0-dy) : 0),
705 rItem.right -rItem.left
706 + ((ra & raSizeX) ? dx :
707 (ra & raSizeXB) ? (0-dx) : 0),
708 rItem.bottom -rItem.top
709 + ((ra & raSizeY) ? dy :
710 (ra & raSizeYB) ? (0-dy) : 0),
711 SWP_NOACTIVATE | SWP_NOZORDER);
714 EndDeferWindowPos (dwp);
716 for (hItem = GetWindow (hWnd, GW_CHILD);
717 hItem != NULL;
718 hItem = GetWindow (hItem, GW_HWNDNEXT))
720 DWORD ra = rwFindAction (psd->awd, (GetWindowLong (hItem, GWL_ID)));
722 if (ra & raRepaint)
724 RECT rItem;
726 GetRectInParent (hItem, &rItem);
728 InvalidateRect (hWnd, &rItem, TRUE);
729 fRepaint = TRUE;
733 if (fRepaint)
735 UpdateWindow (hWnd);
741 void FindSplitterMinMax (HWND hWnd, SplitterData *psd, LONG cOld, LONG *pcdMin, LONG *pcdMax)
743 *pcdMin = 0;
744 *pcdMax = 0;
746 for (int ii = 0; psd->awd[ ii ].id != idENDLIST; ++ii)
748 HWND hControl;
749 if ((hControl = GetDlgItem (hWnd, psd->awd[ ii ].id)) != NULL)
751 RECT rControl;
752 GetRectInParent (hControl, &rControl);
754 if (psd->fX)
756 LONG cxMin = 0;
757 LONG cxMax = 0;
759 if (LOWORD(psd->awd[ ii ].cMinimum)) // X minimum?
761 if (psd->awd[ ii ].ra & raSizeX)
762 cxMin = cOld - cxRECT(rControl) + LOWORD(psd->awd[ ii ].cMinimum);
763 else if (psd->awd[ ii ].ra & raSizeXB)
764 cxMax = cOld + cxRECT(rControl) - LOWORD(psd->awd[ ii ].cMinimum);
765 else if (psd->awd[ ii ].ra & raSizeXC)
766 cxMin = cOld - (cxRECT(rControl) - LOWORD(psd->awd[ ii ].cMinimum))*2;
769 if (LOWORD(psd->awd[ ii ].cMaximum)) // X maximum?
771 if (psd->awd[ ii ].ra & raSizeX)
772 cxMax = cOld - cxRECT(rControl) + LOWORD(psd->awd[ ii ].cMaximum);
773 else if (psd->awd[ ii ].ra & raSizeXB)
774 cxMin = cOld + cxRECT(rControl) - LOWORD(psd->awd[ ii ].cMaximum);
775 else if (psd->awd[ ii ].ra & raSizeXC)
776 cxMin = cOld - (cxRECT(rControl) - LOWORD(psd->awd[ ii ].cMaximum))*2;
779 if (cxMin) *pcdMin = (*pcdMin) ? max( *pcdMin, cxMin ) : cxMin;
780 if (cxMax) *pcdMax = (*pcdMax) ? min( *pcdMax, cxMax ) : cxMax;
782 else
784 LONG cyMin = 0;
785 LONG cyMax = 0;
787 if (HIWORD(psd->awd[ ii ].cMinimum)) // Y minimum?
789 if (psd->awd[ ii ].ra & raSizeY)
790 cyMin = cOld - cyRECT(rControl) + HIWORD(psd->awd[ ii ].cMinimum);
791 else if (psd->awd[ ii ].ra & raSizeYB)
792 cyMax = cOld + cyRECT(rControl) - HIWORD(psd->awd[ ii ].cMinimum);
793 else if (psd->awd[ ii ].ra & raSizeYC)
794 cyMin = cOld - (cyRECT(rControl) - HIWORD(psd->awd[ ii ].cMinimum))*2;
797 if (HIWORD(psd->awd[ ii ].cMaximum)) // Y maximum?
799 if (psd->awd[ ii ].ra & raSizeY)
800 cyMax = cOld - cyRECT(rControl) + HIWORD(psd->awd[ ii ].cMaximum);
801 else if (psd->awd[ ii ].ra & raSizeYB)
802 cyMin = cOld + cyRECT(rControl) - HIWORD(psd->awd[ ii ].cMaximum);
803 else if (psd->awd[ ii ].ra & raSizeYC)
804 cyMin = cOld - (cyRECT(rControl) - HIWORD(psd->awd[ ii ].cMaximum))*2;
807 if (cyMin) *pcdMin = (*pcdMin) ? max( *pcdMin, cyMin ) : cyMin;
808 if (cyMax) *pcdMax = (*pcdMax) ? min( *pcdMax, cyMax ) : cyMax;
815 void FindResizeLimits (HWND hWnd, LONG *pcxMin, LONG *pcxMax, LONG *pcyMin, LONG *pcyMax, rwWindowData *awd)
817 *pcxMin = 0;
818 *pcxMax = 0;
819 *pcyMin = 0;
820 *pcyMax = 0;
822 if (awd == NULL)
824 int iwl;
825 if ((iwl = rwFindOrAddWnd (hWnd)) == -1)
826 return;
828 if ((awd = awl[ iwl ].awdLast) == NULL)
829 return;
832 RECT rNow;
833 GetWindowRect (hWnd, &rNow);
835 for (DWORD ii = 0; awd[ ii ].id != idENDLIST; ++ii)
837 HWND hControl;
838 if ((hControl = GetDlgItem (hWnd, awd[ ii ].id)) != NULL)
840 RECT rControl;
841 GetRectInParent (hControl, &rControl);
843 LONG cxMin = 0;
844 LONG cyMin = 0;
845 LONG cxMax = 0;
846 LONG cyMax = 0;
848 if (LOWORD(awd[ ii ].cMinimum)) // X minimum?
850 if (awd[ ii ].ra & raSizeX)
851 cxMin = cxRECT(rNow) - cxRECT(rControl) + LOWORD(awd[ ii ].cMinimum);
852 else if (awd[ ii ].ra & raSizeXB)
853 cxMax = cxRECT(rNow) + cxRECT(rControl) - LOWORD(awd[ ii ].cMinimum);
854 else if (awd[ ii ].ra & raSizeXC)
855 cxMin = cxRECT(rNow) - (cxRECT(rControl) - LOWORD(awd[ ii ].cMinimum))*2;
858 if (LOWORD(awd[ ii ].cMaximum)) // X maximum?
860 if (awd[ ii ].ra & raSizeX)
861 cxMax = cxRECT(rNow) - cxRECT(rControl) + LOWORD(awd[ ii ].cMaximum);
862 else if (awd[ ii ].ra & raSizeXB)
863 cxMin = cxRECT(rNow) + cxRECT(rControl) - LOWORD(awd[ ii ].cMaximum);
864 else if (awd[ ii ].ra & raSizeXC)
865 cxMax = cxRECT(rNow) - (cxRECT(rControl) - LOWORD(awd[ ii ].cMaximum))*2;
868 if (HIWORD(awd[ ii ].cMinimum)) // Y minimum?
870 if (awd[ ii ].ra & raSizeY)
871 cyMin = cyRECT(rNow) - cyRECT(rControl) + HIWORD(awd[ ii ].cMinimum);
872 else if (awd[ ii ].ra & raSizeYB)
873 cyMax = cyRECT(rNow) + cyRECT(rControl) - HIWORD(awd[ ii ].cMinimum);
874 else if (awd[ ii ].ra & raSizeYC)
875 cyMin = cyRECT(rNow) - (cyRECT(rControl) - HIWORD(awd[ ii ].cMinimum))*2;
878 if (HIWORD(awd[ ii ].cMaximum)) // Y maximum?
880 if (awd[ ii ].ra & raSizeY)
881 cyMax = cyRECT(rNow) - cyRECT(rControl) + HIWORD(awd[ ii ].cMaximum);
882 else if (awd[ ii ].ra & raSizeYB)
883 cyMin = cyRECT(rNow) + cyRECT(rControl) - HIWORD(awd[ ii ].cMaximum);
884 else if (awd[ ii ].ra & raSizeYC)
885 cyMax = cyRECT(rNow) - (cyRECT(rControl) - HIWORD(awd[ ii ].cMaximum))*2;
888 if (cxMin) *pcxMin = (*pcxMin) ? max( *pcxMin, cxMin ) : cxMin;
889 if (cyMin) *pcyMin = (*pcyMin) ? max( *pcyMin, cyMin ) : cyMin;
890 if (cxMax) *pcxMax = (*pcxMax) ? min( *pcxMax, cxMax ) : cxMax;
891 if (cyMax) *pcyMax = (*pcyMax) ? min( *pcyMax, cyMax ) : cyMax;
897 HRESULT CALLBACK Resize_DialogProc (HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
899 PVOID fnNext = Subclass_FindNextHook (hWnd, Resize_DialogProc);
901 switch (msg)
903 case WM_GETMINMAXINFO:
904 LONG cxMin;
905 LONG cyMin;
906 LONG cxMax;
907 LONG cyMax;
908 FindResizeLimits (hWnd, &cxMin, &cxMax, &cyMin, &cyMax);
910 LPMINMAXINFO lpmmi;
911 lpmmi = (LPMINMAXINFO)lp;
913 if (cxMin)
914 lpmmi->ptMinTrackSize.x = cxMin;
915 if (cyMin)
916 lpmmi->ptMinTrackSize.y = cyMin;
917 if (cxMax)
918 lpmmi->ptMaxTrackSize.x = cxMax;
919 if (cyMax)
920 lpmmi->ptMaxTrackSize.y = cyMax;
921 return FALSE;
923 case WM_DESTROY:
924 rwFindAndRemoveWnd (hWnd);
925 break;
928 return (fnNext) ? CallWindowProc ((WNDPROC)fnNext, hWnd, msg, wp, lp) : FALSE;