📄 resizablelayout.cpp
字号:
// ResizableLayout.cpp: implementation of the CResizableLayout class.
//
/////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2000-2002 by Paolo Messina
// (http://www.geocities.com/ppescher - ppescher@yahoo.com)
//
// The contents of this file are subject to the Artistic License (the "License").
// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
// http://www.opensource.org/licenses/artistic-license.html
//
// If you find this code useful, credits would be nice!
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "ResizableLayout.h"
#include "ResizableMsgSupport.inl"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
// Update for CTreePropSheetEx to allow compilation on machines without
// Platform SDK installed (Yves Tkaczyk).
// Define constants that are in the Platform SDK, but not in the default VC6
// installation.
// Thank to Don M for suggestion
// (http://www.codeproject.com/property/TreePropSheetEx.asp?msg=939854#xx939854xx)
#ifndef WS_EX_LAYOUTRTL
#define WS_EX_LAYOUTRTL 0x400000 /* w98, w2k */
#endif
#ifndef WC_BUTTON
#define WC_BUTTON _T("Button")
#endif
#ifndef WC_STATIC
#define WC_STATIC _T("Static")
#endif
#ifndef WC_LISTBOX
#define WC_LISTBOX _T("ListBox")
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
// In August 2002 Platform SDK, some guy at MS thought it was time to
// add the missing symbol BS_TYPEMASK, but forgot its original meaning
// and so now he's telling us not to use that symbol because its
// value is likely to change in the future SDK releases, including all
// the BS_* style bits in the mask, not just the button's type as the
// symbol's name suggests. So now we're forced to use another symbol!
#define _BS_TYPEMASK 0x0000000FL
void CResizableLayout::AddAnchor(HWND hWnd, CSize sizeTypeTL, CSize sizeTypeBR)
{
CWnd* pParent = GetResizableWnd();
// child window must be valid
ASSERT(::IsWindow(hWnd));
// must be child of parent window
ASSERT(::IsChild(pParent->GetSafeHwnd(), hWnd));
// top-left anchor must be valid
ASSERT(sizeTypeTL != NOANCHOR);
// get control's window class
CString sClassName;
GetClassName(hWnd, sClassName.GetBufferSetLength(MAX_PATH), MAX_PATH);
sClassName.ReleaseBuffer();
// get parent window's rect
CRect rectParent;
GetTotalClientRect(&rectParent);
// and child control's rect
CRect rectChild;
::GetWindowRect(hWnd, &rectChild);
::MapWindowPoints(NULL, pParent->m_hWnd, (LPPOINT)&rectChild, 2);
// adjust position, if client area has been scrolled
rectChild.OffsetRect(-rectParent.TopLeft());
// go calculate margins
CSize sizeMarginTL, sizeMarginBR;
if (sizeTypeBR == NOANCHOR)
sizeTypeBR = sizeTypeTL;
// calculate margin for the top-left corner
sizeMarginTL.cx = rectChild.left - rectParent.Width() * sizeTypeTL.cx / 100;
sizeMarginTL.cy = rectChild.top - rectParent.Height() * sizeTypeTL.cy / 100;
// calculate margin for the bottom-right corner
sizeMarginBR.cx = rectChild.right - rectParent.Width() * sizeTypeBR.cx / 100;
sizeMarginBR.cy = rectChild.bottom - rectParent.Height() * sizeTypeBR.cy / 100;
// prepare the structure
LayoutInfo layout(hWnd, sizeTypeTL, sizeMarginTL,
sizeTypeBR, sizeMarginBR, sClassName);
// initialize resize properties (overridable)
InitResizeProperties(layout);
// must not be already there!
// (this is probably due to a duplicate call to AddAnchor)
POSITION pos;
ASSERT(!m_mapLayout.Lookup(hWnd, pos));
// add to the list and the map
pos = m_listLayout.AddTail(layout);
m_mapLayout.SetAt(hWnd, pos);
}
void CResizableLayout::AddAnchorCallback(UINT nCallbackID)
{
// one callback control cannot rely upon another callback control's
// size and/or position (they're updated all together at the end)
// it can however use a non-callback control, which is updated before
// add to the list
LayoutInfo layout;
layout.nCallbackID = nCallbackID;
m_listLayoutCB.AddTail(layout);
}
BOOL CResizableLayout::ArrangeLayoutCallback(CResizableLayout::LayoutInfo& /*layout*/)
{
ASSERT(FALSE);
// must be overridden, if callback is used
return FALSE; // no output data
}
void CResizableLayout::ArrangeLayout()
{
// common vars
UINT uFlags;
LayoutInfo layout;
CRect rectParent, rectChild;
GetTotalClientRect(&rectParent); // get parent window's rect
int count = m_listLayout.GetCount();
int countCB = m_listLayoutCB.GetCount();
// reposition child windows
HDWP hdwp = ::BeginDeferWindowPos(count + countCB);
POSITION pos = m_listLayout.GetHeadPosition();
while (pos != NULL)
{
// get layout info
layout = m_listLayout.GetNext(pos);
// calculate new child's position, size and flags for SetWindowPos
CalcNewChildPosition(layout, rectParent, rectChild, uFlags);
// only if size or position changed
if ((uFlags & (SWP_NOMOVE|SWP_NOSIZE)) != (SWP_NOMOVE|SWP_NOSIZE))
{
hdwp = ::DeferWindowPos(hdwp, layout.hWnd, NULL, rectChild.left,
rectChild.top, rectChild.Width(), rectChild.Height(), uFlags);
}
}
// for callback items you may use GetAnchorPosition to know the
// new position and size of a non-callback item after resizing
pos = m_listLayoutCB.GetHeadPosition();
while (pos != NULL)
{
// get layout info
layout = m_listLayoutCB.GetNext(pos);
// request layout data
if (!ArrangeLayoutCallback(layout))
continue;
// calculate new child's position, size and flags for SetWindowPos
CalcNewChildPosition(layout, rectParent, rectChild, uFlags);
// only if size or position changed
if ((uFlags & (SWP_NOMOVE|SWP_NOSIZE)) != (SWP_NOMOVE|SWP_NOSIZE))
{
hdwp = ::DeferWindowPos(hdwp, layout.hWnd, NULL, rectChild.left,
rectChild.top, rectChild.Width(), rectChild.Height(), uFlags);
}
}
// finally move all the windows at once
::EndDeferWindowPos(hdwp);
}
void CResizableLayout::ClipChildWindow(const CResizableLayout::LayoutInfo& layout,
CRgn* pRegion)
{
// obtain window position
CRect rect;
::GetWindowRect(layout.hWnd, &rect);
::MapWindowPoints(NULL, GetResizableWnd()->m_hWnd, (LPPOINT)&rect, 2);
// use window region if any
CRgn rgn;
rgn.CreateRectRgn(0,0,0,0);
switch (::GetWindowRgn(layout.hWnd, rgn))
{
case COMPLEXREGION:
case SIMPLEREGION:
rgn.OffsetRgn(rect.TopLeft());
break;
default:
rgn.SetRectRgn(&rect);
}
// get the clipping property
BOOL bClipping = layout.properties.bAskClipping ?
LikesClipping(layout) : layout.properties.bCachedLikesClipping;
// modify region accordingly
if (bClipping)
pRegion->CombineRgn(pRegion, &rgn, RGN_DIFF);
else
pRegion->CombineRgn(pRegion, &rgn, RGN_OR);
}
void CResizableLayout::GetClippingRegion(CRgn* pRegion)
{
CWnd* pWnd = GetResizableWnd();
// System's default clipping area is screen's size,
// not enough for max track size, for example:
// if screen is 1024 x 768 and resizing border is 4 pixels,
// maximized size is 1024+4*2=1032 x 768+4*2=776,
// but max track size is 4 pixels bigger 1036 x 780 (don't ask me why!)
// So, if you resize the window to maximum size, the last 4 pixels
// are clipped out by the default clipping region, that gets created
// as soon as you call clipping functions (my guess).
// reset clipping region to the whole client area
CRect rect;
pWnd->GetClientRect(&rect);
pRegion->CreateRectRgnIndirect(&rect);
// clip only anchored controls
LayoutInfo layout;
POSITION pos = m_listLayout.GetHeadPosition();
while (pos != NULL)
{
// get layout info
layout = m_listLayout.GetNext(pos);
if (::IsWindowVisible(layout.hWnd))
ClipChildWindow(layout, pRegion);
}
pos = m_listLayoutCB.GetHeadPosition();
while (pos != NULL)
{
// get layout info
layout = m_listLayoutCB.GetNext(pos);
// request data
if (!ArrangeLayoutCallback(layout))
continue;
if (::IsWindowVisible(layout.hWnd))
ClipChildWindow(layout, pRegion);
}
// fix for RTL layouts (1 pixel of horz offset)
if (pWnd->GetExStyle() & WS_EX_LAYOUTRTL)
pRegion->OffsetRgn(-1,0);
}
void CResizableLayout::EraseBackground(HDC hDC)
{
HWND hWnd = GetResizableWnd()->GetSafeHwnd();
// retrieve the background brush
HBRUSH hBrush = NULL;
// is this a dialog box?
// (using class atom is quickier than using the class name)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -