00001
00002
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00016
00017 #include "stdafx.h"
00018 #include "commctrl.h"
00019 #include "ResizableLayout.h"
00020 #include "ResizableMsgSupport.inl"
00021
00022 #ifdef _DEBUG
00023 #undef THIS_FILE
00024 static char THIS_FILE[]=__FILE__;
00025 #define new DEBUG_NEW
00026 #endif
00027
00029
00031
00032
00033
00034
00035
00036
00037
00038 #define _BS_TYPEMASK 0x0000000FL
00039
00040 void CResizableLayout::AddAnchor(HWND hWnd, CSize sizeTypeTL, CSize sizeTypeBR)
00041 {
00042 CWnd* pParent = GetResizableWnd();
00043
00044
00045 ASSERT(::IsWindow(hWnd));
00046
00047
00048
00049 ASSERT(sizeTypeTL != NOANCHOR);
00050
00051
00052 CString sClassName;
00053 GetClassName(hWnd, sClassName.GetBufferSetLength(MAX_PATH), MAX_PATH);
00054 sClassName.ReleaseBuffer();
00055
00056
00057 CRect rectParent;
00058 GetTotalClientRect(&rectParent);
00059
00060 CRect rectChild;
00061 ::GetWindowRect(hWnd, &rectChild);
00062 ::MapWindowPoints(NULL, pParent->m_hWnd, (LPPOINT)&rectChild, 2);
00063
00064
00065 rectChild.OffsetRect(-rectParent.TopLeft());
00066
00067
00068 CSize sizeMarginTL, sizeMarginBR;
00069
00070 if (sizeTypeBR == NOANCHOR)
00071 sizeTypeBR = sizeTypeTL;
00072
00073
00074
00075 sizeMarginTL.cx = rectChild.left - rectParent.Width() * sizeTypeTL.cx / 100;
00076 sizeMarginTL.cy = rectChild.top - rectParent.Height() * sizeTypeTL.cy / 100;
00077
00078
00079
00080 sizeMarginBR.cx = rectChild.right - rectParent.Width() * sizeTypeBR.cx / 100;
00081 sizeMarginBR.cy = rectChild.bottom - rectParent.Height() * sizeTypeBR.cy / 100;
00082
00083
00084 LayoutInfo layout(hWnd, sizeTypeTL, sizeMarginTL,
00085 sizeTypeBR, sizeMarginBR, sClassName);
00086
00087
00088 InitResizeProperties(layout);
00089
00090
00091
00092 POSITION pos;
00093 ASSERT(!m_mapLayout.Lookup(hWnd, pos));
00094
00095
00096 pos = m_listLayout.AddTail(layout);
00097 m_mapLayout.SetAt(hWnd, pos);
00098 }
00099
00100 void CResizableLayout::AddAnchorCallback(UINT nCallbackID)
00101 {
00102
00103
00104
00105
00106
00107 LayoutInfo layout;
00108 layout.nCallbackID = nCallbackID;
00109 m_listLayoutCB.AddTail(layout);
00110 }
00111
00112 BOOL CResizableLayout::ArrangeLayoutCallback(CResizableLayout::LayoutInfo& )
00113 {
00114 ASSERT(FALSE);
00115
00116
00117 return FALSE;
00118 }
00119
00120 void CResizableLayout::ArrangeLayout()
00121 {
00122
00123 UINT uFlags;
00124 LayoutInfo layout;
00125 CRect rectParent, rectChild;
00126 GetTotalClientRect(&rectParent);
00127 int count = m_listLayout.GetCount();
00128 int countCB = m_listLayoutCB.GetCount();
00129
00130
00131 HDWP hdwp = ::BeginDeferWindowPos(count + countCB);
00132
00133 POSITION pos = m_listLayout.GetHeadPosition();
00134 while (pos != NULL)
00135 {
00136
00137 layout = m_listLayout.GetNext(pos);
00138
00139
00140 CalcNewChildPosition(layout, rectParent, rectChild, uFlags);
00141
00142
00143 if ((uFlags & (SWP_NOMOVE|SWP_NOSIZE)) != (SWP_NOMOVE|SWP_NOSIZE))
00144 {
00145 hdwp = ::DeferWindowPos(hdwp, layout.hWnd, NULL, rectChild.left,
00146 rectChild.top, rectChild.Width(), rectChild.Height(), uFlags);
00147 }
00148 }
00149
00150
00151
00152
00153 pos = m_listLayoutCB.GetHeadPosition();
00154 while (pos != NULL)
00155 {
00156
00157 layout = m_listLayoutCB.GetNext(pos);
00158
00159 if (!ArrangeLayoutCallback(layout))
00160 continue;
00161
00162
00163 CalcNewChildPosition(layout, rectParent, rectChild, uFlags);
00164
00165
00166 if ((uFlags & (SWP_NOMOVE|SWP_NOSIZE)) != (SWP_NOMOVE|SWP_NOSIZE))
00167 {
00168 hdwp = ::DeferWindowPos(hdwp, layout.hWnd, NULL, rectChild.left,
00169 rectChild.top, rectChild.Width(), rectChild.Height(), uFlags);
00170 }
00171 }
00172
00173
00174 ::EndDeferWindowPos(hdwp);
00175 }
00176
00177 void CResizableLayout::ClipChildWindow(const CResizableLayout::LayoutInfo& layout,
00178 CRgn* pRegion)
00179 {
00180
00181 CRect rect;
00182 ::GetWindowRect(layout.hWnd, &rect);
00183 ::MapWindowPoints(NULL, GetResizableWnd()->m_hWnd, (LPPOINT)&rect, 2);
00184
00185
00186 CRgn rgn;
00187 rgn.CreateRectRgn(0,0,0,0);
00188 switch (::GetWindowRgn(layout.hWnd, rgn))
00189 {
00190 case COMPLEXREGION:
00191 case SIMPLEREGION:
00192 rgn.OffsetRgn(rect.TopLeft());
00193 break;
00194
00195 default:
00196 rgn.SetRectRgn(&rect);
00197 }
00198
00199
00200 BOOL bClipping = layout.properties.bAskClipping ?
00201 LikesClipping(layout) : layout.properties.bCachedLikesClipping;
00202
00203
00204 if (bClipping)
00205 pRegion->CombineRgn(pRegion, &rgn, RGN_DIFF);
00206 else
00207 pRegion->CombineRgn(pRegion, &rgn, RGN_OR);
00208 }
00209
00210 void CResizableLayout::GetClippingRegion(CRgn* pRegion)
00211 {
00212 CWnd* pWnd = GetResizableWnd();
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224 CRect rect;
00225 pWnd->GetClientRect(&rect);
00226 pRegion->CreateRectRgnIndirect(&rect);
00227
00228
00229 LayoutInfo layout;
00230 POSITION pos = m_listLayout.GetHeadPosition();
00231 while (pos != NULL)
00232 {
00233
00234 layout = m_listLayout.GetNext(pos);
00235
00236 if (::IsWindowVisible(layout.hWnd))
00237 ClipChildWindow(layout, pRegion);
00238 }
00239 pos = m_listLayoutCB.GetHeadPosition();
00240 while (pos != NULL)
00241 {
00242
00243 layout = m_listLayoutCB.GetNext(pos);
00244
00245 if (!ArrangeLayoutCallback(layout))
00246 continue;
00247
00248 if (::IsWindowVisible(layout.hWnd))
00249 ClipChildWindow(layout, pRegion);
00250 }
00251
00252
00253 if (pWnd->GetExStyle() & 0x00400000L)
00254 pRegion->OffsetRgn(-1,0);
00255 }
00256
00257 void CResizableLayout::EraseBackground(CDC* pDC)
00258 {
00259 HWND hWnd = GetResizableWnd()->GetSafeHwnd();
00260
00261
00262 HBRUSH hBrush = NULL;
00263
00264
00265
00266 ATOM atomWndClass = (ATOM)::GetClassLong(hWnd, GCW_ATOM);
00267 if (atomWndClass == (ATOM)0x8002)
00268 {
00269
00270 hBrush = (HBRUSH)::SendMessage(hWnd, WM_CTLCOLORDLG,
00271 (WPARAM)pDC->GetSafeHdc(), (LPARAM)hWnd);
00272 }
00273 else
00274 {
00275
00276 hBrush = (HBRUSH)::GetClassLongPtr(hWnd, GCL_HBRBACKGROUND);
00277 }
00278
00279
00280 CRgn rgn;
00281 GetClippingRegion(&rgn);
00282
00283 ::FillRgn(pDC->GetSafeHdc(), rgn, hBrush);
00284 }
00285
00286
00287 void CResizableLayout::ClipChildren(CDC* pDC)
00288 {
00289 CRgn rgn;
00290 GetClippingRegion(&rgn);
00291
00292 rgn.OffsetRgn(-pDC->GetWindowOrg());
00293 pDC->SelectClipRgn(&rgn);
00294 }
00295
00296 void CResizableLayout::GetTotalClientRect(LPRECT lpRect)
00297 {
00298 GetResizableWnd()->GetClientRect(lpRect);
00299 }
00300
00301 BOOL CResizableLayout::NeedsRefresh(const CResizableLayout::LayoutInfo& layout,
00302 const CRect& rectOld, const CRect& rectNew)
00303 {
00304 if (layout.bMsgSupport)
00305 {
00306 REFRESHPROPERTY refresh;
00307 refresh.rcOld = rectOld;
00308 refresh.rcNew = rectNew;
00309 if (Send_NeedsRefresh(layout.hWnd, &refresh))
00310 return refresh.bNeedsRefresh;
00311 }
00312
00313 int nDiffWidth = (rectNew.Width() - rectOld.Width());
00314 int nDiffHeight = (rectNew.Height() - rectOld.Height());
00315
00316
00317 if (nDiffWidth == 0 && nDiffHeight == 0)
00318 return FALSE;
00319
00320
00321 BOOL bRefresh = FALSE;
00322
00323
00324 if (layout.sWndClass == WC_STATIC)
00325 {
00326 DWORD style = ::GetWindowLong(layout.hWnd, GWL_STYLE);
00327
00328 switch (style & SS_TYPEMASK)
00329 {
00330 case SS_LEFT:
00331 case SS_CENTER:
00332 case SS_RIGHT:
00333
00334 bRefresh = bRefresh || (nDiffWidth != 0);
00335
00336 if (style & SS_CENTERIMAGE)
00337 bRefresh = bRefresh || (nDiffHeight != 0);
00338 break;
00339
00340 case SS_LEFTNOWORDWRAP:
00341
00342 if (style & SS_ELLIPSISMASK)
00343 bRefresh = bRefresh || (nDiffWidth != 0);
00344
00345 if (style & SS_CENTERIMAGE)
00346 bRefresh = bRefresh || (nDiffHeight != 0);
00347 break;
00348
00349 case SS_ENHMETAFILE:
00350 case SS_BITMAP:
00351 case SS_ICON:
00352
00353 case SS_BLACKFRAME:
00354 case SS_GRAYFRAME:
00355 case SS_WHITEFRAME:
00356 case SS_ETCHEDFRAME:
00357
00358 bRefresh = TRUE;
00359 break;
00360 }
00361 }
00362
00363
00364
00365 BOOL bHScroll = FALSE;
00366 if (layout.sWndClass == WC_LISTBOX)
00367 bHScroll = TRUE;
00368
00369
00370 if (bHScroll && (nDiffWidth > 0))
00371 {
00372
00373 SCROLLINFO info;
00374 info.cbSize = sizeof(SCROLLINFO);
00375 info.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
00376 if (::GetScrollInfo(layout.hWnd, SB_HORZ, &info))
00377 {
00378
00379 info.nMax -= __max(info.nPage-1,0);
00380 }
00381
00382
00383
00384 if ((info.nMax > 0) && (info.nPos + nDiffWidth > info.nMax))
00385 {
00386
00387 bRefresh = TRUE;
00388 }
00389 }
00390
00391 return bRefresh;
00392 }
00393
00394 BOOL CResizableLayout::LikesClipping(const CResizableLayout::LayoutInfo& layout)
00395 {
00396 if (layout.bMsgSupport)
00397 {
00398 CLIPPINGPROPERTY clipping;
00399 if (Send_LikesClipping(layout.hWnd, &clipping))
00400 return clipping.bLikesClipping;
00401 }
00402
00403 DWORD style = ::GetWindowLong(layout.hWnd, GWL_STYLE);
00404
00405
00406 if (layout.sWndClass == TOOLBARCLASSNAME && (style & TBSTYLE_TRANSPARENT))
00407 return FALSE;
00408 else if (layout.sWndClass == WC_BUTTON)
00409 {
00410 CRect rect;
00411 switch (style & _BS_TYPEMASK)
00412 {
00413 case BS_GROUPBOX:
00414 return FALSE;
00415
00416 case BS_OWNERDRAW:
00417
00418
00419 ::GetWindowRect(layout.hWnd, &rect);
00420 if ( HTTRANSPARENT == ::SendMessage(layout.hWnd,
00421 WM_NCHITTEST, 0, MAKELPARAM(rect.left, rect.top)) )
00422 return FALSE;
00423 break;
00424 }
00425 return TRUE;
00426 }
00427 else if (layout.sWndClass == WC_STATIC)
00428 {
00429 switch (style & SS_TYPEMASK)
00430 {
00431 case SS_LEFT:
00432 case SS_CENTER:
00433 case SS_RIGHT:
00434 case SS_SIMPLE:
00435 case SS_LEFTNOWORDWRAP:
00436
00437 case SS_BLACKRECT:
00438 case SS_GRAYRECT:
00439 case SS_WHITERECT:
00440
00441 case SS_ETCHEDHORZ:
00442 case SS_ETCHEDVERT:
00443
00444 case SS_BITMAP:
00445
00446 return TRUE;
00447 break;
00448
00449 case SS_ICON:
00450 case SS_ENHMETAFILE:
00451 if (style & SS_CENTERIMAGE)
00452 return FALSE;
00453 return TRUE;
00454 break;
00455
00456 default:
00457 return FALSE;
00458 }
00459 }
00460
00461
00462 return TRUE;
00463 }
00464
00465 void CResizableLayout::CalcNewChildPosition(const CResizableLayout::LayoutInfo& layout,
00466 const CRect &rectParent, CRect &rectChild, UINT& uFlags)
00467 {
00468 CWnd* pParent = GetResizableWnd();
00469
00470 ::GetWindowRect(layout.hWnd, &rectChild);
00471 ::MapWindowPoints(NULL, pParent->m_hWnd, (LPPOINT)&rectChild, 2);
00472
00473 CRect rectNew;
00474
00475
00476 rectNew.left = layout.sizeMarginTL.cx + rectParent.Width() * layout.sizeTypeTL.cx / 100;
00477 rectNew.top = layout.sizeMarginTL.cy + rectParent.Height() * layout.sizeTypeTL.cy / 100;
00478
00479
00480 rectNew.right = layout.sizeMarginBR.cx + rectParent.Width() * layout.sizeTypeBR.cx / 100;
00481 rectNew.bottom = layout.sizeMarginBR.cy + rectParent.Height() * layout.sizeTypeBR.cy / 100;
00482
00483
00484 rectNew.OffsetRect(rectParent.TopLeft());
00485
00486
00487 BOOL bRefresh = layout.properties.bAskRefresh ?
00488 NeedsRefresh(layout, rectChild, rectNew) : layout.properties.bCachedNeedsRefresh;
00489
00490
00491 uFlags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREPOSITION;
00492 if (bRefresh)
00493 uFlags |= SWP_NOCOPYBITS;
00494 if (rectNew.TopLeft() == rectChild.TopLeft())
00495 uFlags |= SWP_NOMOVE;
00496 if (rectNew.Size() == rectChild.Size())
00497 uFlags |= SWP_NOSIZE;
00498
00499
00500 rectChild = rectNew;
00501 }
00502
00503 void CResizableLayout::InitResizeProperties(CResizableLayout::LayoutInfo &layout)
00504 {
00505
00506
00507 layout.bMsgSupport = Send_QueryProperties(layout.hWnd, &layout.properties);
00508
00509
00510 if (!layout.bMsgSupport)
00511 {
00512
00513 layout.properties.bAskClipping = FALSE;
00514 layout.properties.bCachedLikesClipping = LikesClipping(layout);
00515
00516 layout.properties.bAskRefresh = TRUE;
00517 }
00518 }