You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
561 lines
13 KiB
C++
561 lines
13 KiB
C++
// XTPResize.cpp: implementation of the CXTPResize class.
|
|
//
|
|
// This file is a part of the XTREME CONTROLS MFC class library.
|
|
// (c)1998-2012 Codejock Software, All Rights Reserved.
|
|
//
|
|
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
|
|
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
|
|
// CONSENT OF CODEJOCK SOFTWARE.
|
|
//
|
|
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
|
|
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
|
|
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
|
|
// SINGLE COMPUTER.
|
|
//
|
|
// CONTACT INFORMATION:
|
|
// support@codejock.com
|
|
// http://www.codejock.com
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "Common/XTPDrawHelpers.h"
|
|
|
|
#include "XTPResizeRect.h"
|
|
#include "XTPResizePoint.h"
|
|
#include "XTPResize.h"
|
|
#include "XTPResizeGroupBox.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#define new DEBUG_NEW
|
|
#endif
|
|
|
|
#ifndef OBM_SIZE
|
|
#define OBM_SIZE 32766
|
|
#endif
|
|
|
|
#define ENTRY_WINDOWPLACEMENT _T("WindowPlacement")
|
|
|
|
#define IDC_SIZEICON 0x7FFF
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Construction/Destruction
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
CXTPResize::CXTPResize(CWnd* pWnd, const UINT nFlags) :
|
|
m_pWnd(pWnd),
|
|
m_nFlagsXX(nFlags),
|
|
m_szMin(0, 0),
|
|
m_szMax(0, 0),
|
|
m_szWindow(0, 0),
|
|
m_szInitWindow(0, 0),
|
|
m_strSection(_T(""))
|
|
{
|
|
|
|
}
|
|
|
|
CXTPResize::~CXTPResize()
|
|
{
|
|
RemoveAllControls();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL CXTPResize::RemoveResize(const UINT nID)
|
|
{
|
|
// search for an item with the given id
|
|
|
|
for (int iItem = (int)m_arrItems.GetSize() - 1; iItem >= 0; iItem--)
|
|
{
|
|
CWnd* pWnd = m_arrItems[iItem]->m_pWnd;
|
|
ASSERT_VALID(pWnd);
|
|
|
|
if (pWnd->GetDlgCtrlID() == (int) nID)
|
|
{
|
|
CXTPResizeItem* pItem = m_arrItems[iItem];
|
|
if (pItem != NULL)
|
|
{
|
|
m_arrItems.RemoveAt(iItem);
|
|
SAFE_DELETE(pItem);
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void CXTPResize::RemoveAllControls()
|
|
{
|
|
// free allocated memory
|
|
for (int iIndex = 0; iIndex < m_arrItems.GetSize(); ++iIndex)
|
|
{
|
|
CXTPResizeItem* pItem = m_arrItems.GetAt(iIndex);
|
|
SAFE_DELETE(pItem);
|
|
}
|
|
|
|
// empty array
|
|
m_arrItems.RemoveAll();
|
|
}
|
|
|
|
void CXTPResize::SetResize(const UINT nID, const HWND hWnd, const XTP_RESIZERECT& rrcSizing)
|
|
{
|
|
CXTPResizeItem* pItem = 0;
|
|
|
|
// search for an item with the given id
|
|
for (int i = (int)m_arrItems.GetSize() - 1; i >= 0; i--)
|
|
{
|
|
CWnd* pWnd = m_arrItems[i]->m_pWnd;
|
|
if (pWnd && ::IsWindow(pWnd->m_hWnd) && (pWnd->GetDlgCtrlID() == (int)nID))
|
|
{
|
|
pItem = m_arrItems[i];
|
|
}
|
|
}
|
|
|
|
// if we didn't find it then create one
|
|
if (pItem == 0)
|
|
{
|
|
HWND hWndChild = hWnd;
|
|
if (hWndChild == NULL)
|
|
{
|
|
CWnd* pWnd = m_pWnd->GetDlgItem(nID);
|
|
if (pWnd && ::IsWindow(pWnd->m_hWnd))
|
|
{
|
|
hWndChild = pWnd->m_hWnd;
|
|
}
|
|
}
|
|
|
|
bool bDelete = false;
|
|
|
|
CWnd* pWnd = m_pWnd->FromHandlePermanent(hWndChild);
|
|
if (pWnd == NULL)
|
|
{
|
|
// there is no permanent window, create one
|
|
pWnd = new CWnd; // CXTPResizeItem handles the delete
|
|
pWnd->Attach(hWndChild);
|
|
|
|
bDelete = true;
|
|
}
|
|
|
|
CRect rcWindow;
|
|
pWnd->GetWindowRect(rcWindow);
|
|
m_pWnd->ScreenToClient(rcWindow);
|
|
|
|
pItem = new CXTPResizeItem(pWnd, rrcSizing, rcWindow, bDelete);
|
|
pItem->MakeTransparent(this);
|
|
|
|
m_arrItems.Add(pItem);
|
|
}
|
|
else
|
|
{
|
|
// the item already exists, just add the new sizing option
|
|
pItem->m_rrcSizing += rrcSizing;
|
|
}
|
|
|
|
// we should only allow sizing within the rect {0, 0, 1, 1}
|
|
ASSERT((CXTPResizeRect(0, 0, 1, 1) & pItem->m_rrcSizing) == pItem->m_rrcSizing);
|
|
}
|
|
|
|
void CXTPResize::Init()
|
|
{
|
|
if (m_pWnd == NULL)
|
|
return;
|
|
|
|
// clear the control list when initializing. The reason for this is we may have a
|
|
// static window that calls Init() multiple times for example CDialog::DoModal().
|
|
RemoveAllControls();
|
|
|
|
// get the dialog size
|
|
CRect rcWindow;
|
|
m_pWnd->GetClientRect(rcWindow);
|
|
m_szWindow = m_szInitWindow = rcWindow.Size();
|
|
|
|
if (!HasFlag(xtpResizeNoMinsize))
|
|
{
|
|
// set minimum size to current window size
|
|
m_szMin = m_szWindow;
|
|
}
|
|
|
|
// set the clip children style to prevent flickering
|
|
if (!HasFlag(xtpResizeNoClipChildren))
|
|
{
|
|
m_pWnd->ModifyStyle(0, WS_CLIPCHILDREN);
|
|
}
|
|
|
|
// add the size icon
|
|
if (!HasFlag(xtpResizeNoSizeIcon))
|
|
{
|
|
// Create the size icon if it already doesn't exist.
|
|
if (!::IsWindow(m_scSizeIcon.m_hWnd))
|
|
{
|
|
int cxGrip = GetSystemMetrics(SM_CXVSCROLL);
|
|
int cyGrip = GetSystemMetrics(SM_CYHSCROLL);
|
|
|
|
CRect rcIcon(rcWindow);
|
|
rcIcon.OffsetRect(-1, -1);
|
|
rcIcon.left = rcIcon.right - cxGrip;
|
|
rcIcon.top = rcIcon.bottom - cyGrip;
|
|
|
|
m_scSizeIcon.Create(WS_CHILD | WS_VISIBLE | SBS_SIZEGRIP,
|
|
rcIcon, m_pWnd, IDC_SIZEICON);
|
|
}
|
|
|
|
m_scSizeIcon.SetWindowPos(&CWnd::wndTop, 0, 0, 0, 0,
|
|
SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED);
|
|
|
|
SetResize(IDC_SIZEICON, XTP_ATTR_REPOS(1));
|
|
}
|
|
}
|
|
|
|
void CXTPResize::Offset(CPoint ptOffset)
|
|
{
|
|
if (m_arrItems.GetSize() > 0)
|
|
{
|
|
|
|
HDWP hDWP = ::BeginDeferWindowPos((int)m_arrItems.GetSize());
|
|
|
|
int i;
|
|
for (i = 0; i < (int)m_arrItems.GetSize(); i++)
|
|
{
|
|
CXTPResizeRect rrcSizing = m_arrItems[i]->m_rrcSizing;
|
|
m_arrItems[i]->m_rrcSizing = CRect(ptOffset.x, ptOffset.y, ptOffset.x, ptOffset.y);
|
|
m_arrItems[i]->m_bInitialSize = TRUE;
|
|
|
|
Defer(hDWP, m_arrItems[i], 1, 1);
|
|
|
|
m_arrItems[i]->m_rrcSizing = rrcSizing;
|
|
}
|
|
|
|
::EndDeferWindowPos(hDWP);
|
|
|
|
// refresh group box items.
|
|
for (i = 0; i < m_arrItems.GetSize(); i++)
|
|
{
|
|
if (m_arrItems[i]->m_bIsGroupBox)
|
|
m_arrItems[i]->m_pWnd->Invalidate();
|
|
}
|
|
}
|
|
}
|
|
|
|
void CXTPResize::AdjustResizeRect(CSize&)
|
|
{
|
|
}
|
|
|
|
void CXTPResize::Size()
|
|
{
|
|
if (m_arrItems.GetSize() > 0)
|
|
{
|
|
CSize szWindow = CXTPClientRect(m_pWnd).Size();
|
|
if (szWindow.cx == 0 || szWindow.cy == 0)
|
|
return;
|
|
|
|
AdjustResizeRect(szWindow);
|
|
|
|
CSize szDelta = szWindow - m_szWindow;
|
|
|
|
HDWP hDWP = ::BeginDeferWindowPos((int)m_arrItems.GetSize());
|
|
|
|
int i;
|
|
for (i = 0; i < (int)m_arrItems.GetSize(); i++)
|
|
{
|
|
Defer(hDWP, m_arrItems[i], szDelta.cx, szDelta.cy);
|
|
}
|
|
|
|
::EndDeferWindowPos(hDWP);
|
|
|
|
// refresh group box items.
|
|
for (i = 0; i < m_arrItems.GetSize(); i++)
|
|
{
|
|
if (m_arrItems[i]->m_bIsGroupBox)
|
|
m_arrItems[i]->m_pWnd->Invalidate();
|
|
}
|
|
|
|
m_szWindow = szWindow;
|
|
}
|
|
}
|
|
|
|
void CXTPResize::Reset()
|
|
{
|
|
int iSize = (int)m_arrItems.GetSize();
|
|
int i;
|
|
for (i = 0; i < iSize; i++)
|
|
{
|
|
CXTPResizeItem* pItem = m_arrItems[i];
|
|
pItem->m_bInitialSize = FALSE;
|
|
pItem->m_rrcWindow = pItem->m_rrcInitWindow;
|
|
}
|
|
}
|
|
|
|
BOOL CXTPResize::Defer(HDWP& hDWP, CXTPResizeItem* pItem, int dx, int dy)
|
|
{
|
|
HWND hWnd = pItem->m_pWnd->m_hWnd;
|
|
if (::IsWindow(hWnd))
|
|
{
|
|
if (!pItem->m_bInitialSize)
|
|
{
|
|
CSize szWindow = CXTPClientRect(m_pWnd).Size();
|
|
|
|
AdjustResizeRect(szWindow);
|
|
|
|
dx = szWindow.cx - m_szInitWindow.cx;
|
|
dy = szWindow.cy - m_szInitWindow.cy;
|
|
|
|
pItem->m_bInitialSize = TRUE;
|
|
}
|
|
|
|
CXTPResizeRect rrcItem = pItem->m_rrcWindow;
|
|
|
|
rrcItem.left += dx * pItem->m_rrcSizing.left;
|
|
rrcItem.top += dy * pItem->m_rrcSizing.top;
|
|
rrcItem.right += dx * pItem->m_rrcSizing.right;
|
|
rrcItem.bottom += dy * pItem->m_rrcSizing.bottom;
|
|
|
|
if (rrcItem != pItem->m_rrcWindow)
|
|
{
|
|
int x = (int) rrcItem.left;
|
|
int y = (int) rrcItem.top;
|
|
int cx = (int) rrcItem.Width();
|
|
int cy = (int) rrcItem.Height();
|
|
|
|
// Set positioning flags
|
|
UINT uFlags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER;
|
|
|
|
CRect rOld;
|
|
CRect rNew = rrcItem;
|
|
|
|
// get the size of the dialog item in client coordinates.
|
|
pItem->m_pWnd->GetWindowRect(&rOld);
|
|
m_pWnd->ScreenToClient(&rOld);
|
|
|
|
// if the x-y coordinates have not changed, there is no reason
|
|
// to move the dialog item.
|
|
if (rNew.TopLeft() == rOld.TopLeft())
|
|
uFlags |= SWP_NOMOVE;
|
|
|
|
// if the cx-cy size has not changed, there is no reason to
|
|
// size the dialog item. If size has changed, don't
|
|
// copy bits of the client area (i.e. have them invalidated/redrawn)
|
|
if (rNew.Size() == rOld.Size())
|
|
uFlags |= SWP_NOSIZE;
|
|
else
|
|
uFlags |= SWP_NOCOPYBITS;
|
|
|
|
hDWP = ::DeferWindowPos(hDWP, hWnd, 0, x, y, cx, cy, uFlags);
|
|
if (hDWP == NULL)
|
|
{
|
|
TRACE(_T("DeferWindowPos failed for ID %i\n"), GetDlgCtrlID(hWnd));
|
|
return FALSE;
|
|
}
|
|
pItem->m_rrcWindow = rrcItem;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
void CXTPResize::GetMinMaxInfo(MINMAXINFO* pMMI)
|
|
{
|
|
CXTPClientRect rcClient(m_pWnd);
|
|
CXTPWindowRect rcWindow(m_pWnd);
|
|
if (rcClient.IsRectEmpty())
|
|
return;
|
|
|
|
CSize szBorder(rcWindow.Width() - rcClient.Width(), rcWindow.Height() - rcClient.Height());
|
|
|
|
if (m_szWindow != CSize(0, 0))
|
|
{
|
|
if (HasFlag(xtpResizeNoHorizontal))
|
|
{
|
|
pMMI->ptMaxTrackSize.x = pMMI->ptMaxSize.x = m_szWindow.cx + szBorder.cx;
|
|
}
|
|
if (HasFlag(xtpResizeNoVertical))
|
|
{
|
|
pMMI->ptMaxTrackSize.y = pMMI->ptMaxSize.y = m_szWindow.cy + szBorder.cy;
|
|
}
|
|
}
|
|
if (m_szMin.cx != 0) pMMI->ptMinTrackSize.x = m_szMin.cx + szBorder.cx;
|
|
if (m_szMin.cy != 0) pMMI->ptMinTrackSize.y = m_szMin.cy + szBorder.cy;
|
|
if (m_szMax.cx != 0) pMMI->ptMaxTrackSize.x = m_szMax.cx + szBorder.cx;
|
|
if (m_szMax.cy != 0) pMMI->ptMaxTrackSize.y = m_szMax.cy + szBorder.cy;
|
|
}
|
|
|
|
BOOL CXTPResize::AutoLoadPlacement(LPCTSTR pszSection)
|
|
{
|
|
m_strSection = pszSection;
|
|
ASSERT(!m_strSection.IsEmpty());
|
|
return LoadPlacement(m_strSection);
|
|
}
|
|
|
|
BOOL CXTPResize::LoadPlacement(LPCTSTR pszSection)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
UINT nBytes = 0;
|
|
BYTE* pBytes = 0;
|
|
AfxGetApp()->GetProfileBinary(pszSection, ENTRY_WINDOWPLACEMENT, &pBytes, &nBytes);
|
|
if (nBytes == sizeof(WINDOWPLACEMENT))
|
|
{
|
|
bResult = m_pWnd->SetWindowPlacement((WINDOWPLACEMENT*) pBytes);
|
|
}
|
|
if (pBytes && nBytes) delete[] pBytes;
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL CXTPResize::SavePlacement(LPCTSTR pszSection)
|
|
{
|
|
WINDOWPLACEMENT wp;
|
|
if (!m_pWnd->GetWindowPlacement(&wp))
|
|
return FALSE;
|
|
|
|
AfxGetApp()->WriteProfileBinary(pszSection, ENTRY_WINDOWPLACEMENT, (BYTE*) &wp, sizeof(wp));
|
|
return TRUE;
|
|
}
|
|
|
|
void CXTPResize::SetFlag(XTPResize eFlag)
|
|
{
|
|
m_nFlagsXX &= (eFlag^0xFFFFFFFF);
|
|
m_nFlagsXX |= eFlag;
|
|
}
|
|
|
|
void CXTPResize::SetResize(CWnd* pWnd, const CXTPResizeRect& rrcSizing, CRect rcWindow)
|
|
{
|
|
CXTPResizeItem *pItem = new CXTPResizeItem(pWnd, rrcSizing, rcWindow, FALSE);
|
|
m_arrItems.Add(pItem);
|
|
}
|
|
|
|
void CXTPResize::UpdateControlRect(CWnd* pWnd)
|
|
{
|
|
if (!pWnd)
|
|
return;
|
|
|
|
for (int i = (int)m_arrItems.GetSize(); i--;)
|
|
{
|
|
if (m_arrItems[i]->m_pWnd->m_hWnd == pWnd->m_hWnd)
|
|
{
|
|
CRect rect;
|
|
pWnd->GetWindowRect(&rect);
|
|
m_pWnd->ScreenToClient(&rect);
|
|
m_arrItems[i]->m_rrcWindow = rect;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// CXTPResizeItem
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
CXTPResizeItem::CXTPResizeItem(CWnd* pWnd, const CXTPResizeRect& rrcSizing, CRect& rcWindow, BOOL bAutoDelete)
|
|
: m_pWnd(pWnd)
|
|
, m_rrcSizing(rrcSizing)
|
|
, m_rrcWindow(rcWindow)
|
|
, m_rrcInitWindow(rcWindow)
|
|
, m_bAutoDelete(bAutoDelete)
|
|
, m_bInitialSize(FALSE)
|
|
, m_bIsGroupBox(FALSE)
|
|
{
|
|
|
|
}
|
|
|
|
CXTPResizeItem::~CXTPResizeItem()
|
|
{
|
|
if (m_bAutoDelete)
|
|
{
|
|
m_pWnd->Detach();
|
|
SAFE_DELETE(m_pWnd);
|
|
}
|
|
}
|
|
|
|
bool CXTPResizeItem::MakeTransparent(CXTPResize* pXTPResize)
|
|
{
|
|
if (pXTPResize->HasFlag(xtpResizeNoTransparentGroup))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (m_pWnd && ::IsWindow(m_pWnd->m_hWnd))
|
|
{
|
|
TCHAR szClassName[8];
|
|
::GetClassName(m_pWnd->m_hWnd, szClassName, 8);
|
|
|
|
// not a CButton derived class.
|
|
if (_tcsicmp(szClassName, _T("Button")) != 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// get the window style if not a group box, return.
|
|
DWORD dwStyle = ::GetWindowLong(m_pWnd->m_hWnd, GWL_STYLE);
|
|
if ((dwStyle & (BS_GROUPBOX | WS_TABSTOP)) == BS_GROUPBOX)
|
|
{
|
|
// we don't want CXTPResizeGroupBox transparent.
|
|
if (m_pWnd->IsKindOf(RUNTIME_CLASS(CXTPResizeGroupBox)))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Get the extended style for the group box.
|
|
DWORD dwStyleEx = ::GetWindowLong(m_pWnd->m_hWnd, GWL_EXSTYLE);
|
|
|
|
// add the WS_EX_TRANSPARENT flag to the group box.
|
|
::SetWindowLong(m_pWnd->m_hWnd, GWL_EXSTYLE,
|
|
dwStyleEx | WS_EX_TRANSPARENT);
|
|
|
|
// apply the style for the window.
|
|
::SetWindowPos(m_pWnd->m_hWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
|
|
SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
|
|
|
|
m_bIsGroupBox = TRUE;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// CXTPSizeIcon
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
CXTPSizeIcon::CXTPSizeIcon()
|
|
{
|
|
// Load the size cursor
|
|
m_hCursor = AfxGetApp()->LoadStandardCursor(IDC_SIZENWSE);
|
|
}
|
|
|
|
CXTPSizeIcon::~CXTPSizeIcon()
|
|
{
|
|
}
|
|
|
|
BEGIN_MESSAGE_MAP(CXTPSizeIcon, CScrollBar)
|
|
//{{AFX_MSG_MAP(CXTPSizeIcon)
|
|
ON_WM_SETCURSOR()
|
|
ON_WM_SETFOCUS()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CXTPSizeIcon message handlers
|
|
|
|
void CXTPSizeIcon::OnSetFocus(CWnd* /*pOldWnd*/)
|
|
{
|
|
|
|
}
|
|
|
|
BOOL CXTPSizeIcon::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
|
|
{
|
|
// Set the cursor to the size cursor.
|
|
if (nHitTest == HTCLIENT && m_hCursor != NULL)
|
|
{
|
|
::SetCursor(m_hCursor);
|
|
return TRUE;
|
|
}
|
|
|
|
return CScrollBar::OnSetCursor(pWnd, nHitTest, message);
|
|
}
|