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.

397 lines
9.5 KiB
C++

// XTPDockContext.cpp : implementation of the CXTPDockContext class.
//
// This file is a part of the XTREME COMMANDBARS 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 "Common/XTPSystemHelpers.h"
#include "Common/XTPHookManager.h"
#include "XTPCommandBarsDefines.h"
#include "XTPDockContext.h"
#include "XTPCommandBar.h"
#include "XTPToolBar.h"
#include "XTPCommandBars.h"
#include "XTPMouseManager.h"
#include "XTPDockBar.h"
#include "XTPDialogBar.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
void CXTPDockContext::AdjustRectangle(CRect& rect, CPoint pt)
{
int nXOffset = (pt.x < rect.left) ? (pt.x - rect.left) :
(pt.x > rect.right) ? (pt.x - rect.right) : 0;
int nYOffset = (pt.y < rect.top) ? (pt.y - rect.top) :
(pt.y > rect.bottom) ? (pt.y - rect.bottom) : 0;
rect.OffsetRect(nXOffset, nYOffset);
}
CXTPDockContext::CXTPDockContext(CXTPToolBar* pBar)
{
m_pBar = pBar;
m_uMRUDockPosition = xtpBarTop;
m_rectMRUDockPos.SetRectEmpty();
m_ptMRUFloatPos.y = m_ptMRUFloatPos.x = 0;
m_nHitTest = 0;
}
CXTPDockContext::~CXTPDockContext()
{
}
void CXTPDockContext::StartDrag(CPoint pt)
{
m_nHitTest = HTCLIENT;
CRect rectMRUDockPos = m_rectMRUDockPos;
XTPBarPosition uMRUDockPosition = m_uMRUDockPosition;
BOOL bFloating = m_pBar->m_barPosition == xtpBarFloating;
CXTPWindowRect rect(m_pBar);
m_ptLast = pt;
AdjustRectangle(rect, pt);
m_rectDragFrame = m_rectDragDock = rect;
SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEALL));
XTPMouseManager()->LockMouseMove();
Track();
XTPMouseManager()->UnlockMouseMove();
if (m_pBar->m_barPosition == xtpBarFloating)
{
m_ptMRUFloatPos = m_rectDragFrame.TopLeft();
if (!bFloating)
{
m_rectMRUDockPos = rectMRUDockPos;
m_uMRUDockPosition = uMRUDockPosition;
}
}
}
void CXTPDockContext::StartResize(int nHitTest, CPoint pt)
{
m_nHitTest = nHitTest;
m_ptLast = pt;
m_pBar->GetWindowRect(m_rectDragFrame);
Track();
m_pBar->GetWindowRect(m_rectDragFrame);
if (m_pBar->m_barPosition == xtpBarFloating)
m_ptMRUFloatPos = m_rectDragFrame.TopLeft();
m_pBar->m_nMRUWidth = m_rectDragFrame.Width();
}
void CXTPDockContext::Track()
{
// don't handle if capture already set
if (::GetCapture() != NULL)
return;
// set capture to the window which received this message
m_pBar->SetCapture();
ASSERT(m_pBar == CWnd::GetCapture());
CXTPCommandBars* pCommandBars = m_pBar->GetCommandBars();
ASSERT(pCommandBars);
if (!pCommandBars)
return;
CPoint pt(0, 0);
// get messages until capture lost or cancelled/accepted
while (CWnd::GetCapture() == m_pBar)
{
MSG msg;
if (!::GetMessage(&msg, NULL, 0, 0))
{
AfxPostQuitMessage((int)msg.wParam);
break;
}
if (msg.message == WM_LBUTTONUP)
break;
else if (msg.message == WM_MOUSEMOVE && pt != msg.pt)
{
pt = msg.pt;
if (m_nHitTest == HTCLIENT)
Move(msg.pt);
else if (m_pBar->IsDialogBar())
Resize(msg.pt);
else
Stretch(msg.pt);
}
else if (msg.message == WM_KEYDOWN)
{
if (msg.wParam == VK_ESCAPE)
{
break;
}
}
else
DispatchMessage(&msg);
pCommandBars->IdleRecalcLayout();
}
ReleaseCapture();
pCommandBars->GetCommandBarsOptions()->bDirtyState = TRUE;
}
void CXTPDockContext::EnsureVisible(CRect& rectDragFrame)
{
CRect rcWork = XTPMultiMonitor()->GetWorkArea();
int nGap = 10;
if (rcWork.bottom - rectDragFrame.top < nGap)
{
rectDragFrame.OffsetRect(0, rcWork.bottom - rectDragFrame.top - nGap);
}
if (rectDragFrame.bottom - rcWork.top < nGap)
{
rectDragFrame.OffsetRect(0, rcWork.top - rectDragFrame.bottom + nGap);
}
if (rcWork.right - rectDragFrame.left < nGap)
{
rectDragFrame.OffsetRect(rcWork.right - rectDragFrame.left - nGap, 0);
}
if (rectDragFrame.right - rcWork.left < nGap)
{
rectDragFrame.OffsetRect(rcWork.left - rectDragFrame.right + nGap, 0);
}
}
void CXTPDockContext::Move(CPoint pt)
{
CPoint ptOffset = pt - m_ptLast;
CXTPCommandBars* pCommandBars = m_pBar->GetCommandBars();
ASSERT(pCommandBars);
if (!pCommandBars)
return;
m_rectDragFrame.OffsetRect(ptOffset);
m_rectDragDock.OffsetRect(ptOffset);
DWORD dwFlags = m_pBar->GetFlags();
BOOL bDocked = FALSE;
CXTPDockBar* pDockBar = pCommandBars->CanDock(pt, m_pBar->m_pDockBar);
if (pDockBar)
{
XTPBarPosition position = pDockBar->GetPosition();
if ((position == xtpBarTop && dwFlags & xtpFlagAlignTop) ||
(position == xtpBarLeft && dwFlags & xtpFlagAlignLeft) ||
(position == xtpBarRight && dwFlags & xtpFlagAlignRight) ||
(position == xtpBarBottom && dwFlags & xtpFlagAlignBottom))
{
CXTPDockBar* pOldDockBar = m_pBar->m_pDockBar;
pCommandBars->DockCommandBar(m_pBar, &m_rectDragDock, pDockBar);
if (pDockBar != pOldDockBar || m_pBar->GetPosition() == xtpBarFloating)
{
pCommandBars->RecalcFrameLayout();
m_pBar->GetWindowRect(m_rectDragDock);
}
bDocked = TRUE;
}
}
if (!bDocked && (dwFlags & xtpFlagFloating))
{
if (m_pBar->GetPosition() != xtpBarFloating)
{
pCommandBars->FloatCommandBar(m_pBar);
CSize sz = m_pBar->CalcDynamicLayout(0, LM_HORZ | LM_MRUWIDTH | LM_COMMIT);
m_rectDragFrame = CRect(m_rectDragFrame.TopLeft(), sz);
AdjustRectangle(m_rectDragFrame, pt);
}
EnsureVisible(m_rectDragFrame);
m_pBar->MoveWindow(m_rectDragFrame);
}
m_ptLast = pt;
}
void CXTPDockContext::Resize(CPoint pt)
{
CPoint ptOffset = pt - m_ptLast;
ASSERT(m_pBar->IsDialogBar());
if (m_nHitTest == HTLEFT || m_nHitTest == HTTOPLEFT || m_nHitTest == HTBOTTOMLEFT)
m_rectDragFrame.left += ptOffset.x;
if (m_nHitTest == HTRIGHT || m_nHitTest == HTTOPRIGHT || m_nHitTest == HTBOTTOMRIGHT)
m_rectDragFrame.right += ptOffset.x;
if (m_nHitTest == HTTOP || m_nHitTest == HTTOPRIGHT || m_nHitTest == HTTOPLEFT)
m_rectDragFrame.top += ptOffset.y;
if (m_nHitTest == HTBOTTOM || m_nHitTest == HTBOTTOMRIGHT || m_nHitTest == HTBOTTOMLEFT)
m_rectDragFrame.bottom += ptOffset.y;
CRect rectTemp;
m_pBar->GetWindowRect(rectTemp);
if (rectTemp.Size() != m_rectDragFrame.Size())
{
if (CRect().IntersectRect(XTPMultiMonitor()->GetWorkArea(m_pBar), m_rectDragFrame))
{
((CXTPDialogBar*)m_pBar)->OnResize(m_rectDragFrame, m_nHitTest);
m_pBar->Redraw();
}
}
m_ptLast = pt;
}
void CXTPDockContext::Stretch(CPoint pt)
{
CPoint ptOffset = pt - m_ptLast;
DWORD dwMode = LM_HORZ | LM_COMMIT;
int nLength = 0;
if (m_nHitTest == HTLEFT || m_nHitTest == HTRIGHT)
{
if (m_nHitTest == HTLEFT)
m_rectDragFrame.left += ptOffset.x;
else
m_rectDragFrame.right += ptOffset.x;
nLength = m_rectDragFrame.Width();
}
else
{
dwMode |= LM_LENGTHY;
if (m_nHitTest == HTTOP)
m_rectDragFrame.top += ptOffset.y;
else
m_rectDragFrame.bottom += ptOffset.y;
nLength = m_rectDragFrame.Height();
}
nLength = (nLength >= 0) ? nLength : 0;
CSize size = m_pBar->CalcDynamicLayout(nLength, dwMode);
CRect rectTemp;
m_pBar->GetWindowRect(rectTemp);
if (rectTemp.Size() != size)
{
if (m_nHitTest == HTRIGHT || m_nHitTest == HTBOTTOM)
{
rectTemp.BottomRight() = rectTemp.TopLeft() + size;
}
else if (m_nHitTest == HTLEFT)
{
rectTemp.bottom = rectTemp.top + size.cy;
rectTemp.left = rectTemp.right - size.cx;
}
else if (m_nHitTest == HTTOP)
{
rectTemp.top = rectTemp.bottom - size.cy;
rectTemp.right = rectTemp.left + size.cx;
}
CRect rcWork = XTPMultiMonitor()->GetWorkArea(m_pBar);
if (!CRect().IntersectRect(rcWork, rectTemp))
{
if (rectTemp.right < rcWork.left) rectTemp.OffsetRect(rcWork.left - rectTemp.left, 0);
else if (rectTemp.left > rcWork.right) rectTemp.OffsetRect(rcWork.right - rectTemp.right, 0);
if (rectTemp.bottom < rcWork.top) rectTemp.OffsetRect(0, rcWork.top - rectTemp.top);
else if (rectTemp.top > rcWork.bottom) rectTemp.OffsetRect(0, rcWork.bottom - rectTemp.bottom);
}
m_pBar->MoveWindow(rectTemp);
m_pBar->Redraw();
}
m_ptLast = pt;
}
BOOL CXTPDockContext::ToggleDocking()
{
CXTPCommandBars* pCommandBars = m_pBar->GetCommandBars();
if (m_pBar->GetPosition() == xtpBarFloating)
{
// Dock it only if is allowed to be docked
if (!(m_pBar->m_dwFlags & xtpFlagAlignAny))
return FALSE;
CRect rect = m_rectMRUDockPos;
CXTPDockBar* pDockBar = pCommandBars->GetDockBar(m_uMRUDockPosition);
pDockBar->ClientToScreen(&rect);
// dock it at the specified position, RecalcLayout will snap
pCommandBars->DockCommandBar(m_pBar, &rect, pDockBar);
pCommandBars->RecalcFrameLayout();
}
else
{
if (!(m_pBar->m_dwFlags & xtpFlagFloating))
return FALSE;
if (!pCommandBars->GetCommandBarsOptions()->bDblClickFloat)
return FALSE;
CPoint ptFloat = m_ptMRUFloatPos;
if (ptFloat.x <= 0 || ptFloat.y <= 0)
{
ptFloat = m_rectMRUDockPos.TopLeft();
m_pBar->GetParent()->ClientToScreen(&ptFloat);
}
pCommandBars->FloatCommandBar(m_pBar);
CSize sz = m_pBar->CalcDynamicLayout(0, LM_HORZ | LM_MRUWIDTH | LM_COMMIT);
m_pBar->MoveWindow(CRect(ptFloat, sz));
}
pCommandBars->GetCommandBarsOptions()->bDirtyState = TRUE;
return TRUE;
}