📄 bcgpdockbar.cpp
字号:
// BCGPDockBar.cpp : implementation file
//
#include "stdafx.h"
#include "BCGPFrameWnd.h"
#include "BCGPMDIFrameWnd.h"
#include "BCGPOleIPFrameWnd.h"
#include "BCGPOleDocIPFrameWnd.h"
#include "BCGPMDIChildWnd.h"
#include "BCGPOleCntrFrameWnd.h"
#include "BCGPControlBar.h"
#include "BCGPDockBarRow.h"
#include "BCGPReBar.h"
#include "BCGPGlobalUtils.h"
#include "BCGPDockBar.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNCREATE(CBCGPDockBar, CBCGPBaseControlBar)
/////////////////////////////////////////////////////////////////////////////
// CBCGPDockBar
CBCGPDockBar::CBCGPDockBar() : m_nDockBarID (0)
{
}
CBCGPDockBar::~CBCGPDockBar()
{
while (!m_lstDockBarRows.IsEmpty ())
{
delete m_lstDockBarRows.RemoveHead ();
}
}
BEGIN_MESSAGE_MAP(CBCGPDockBar, CBCGPBaseControlBar)
//{{AFX_MSG_MAP(CBCGPDockBar)
ON_WM_PAINT()
ON_WM_SIZE()
ON_WM_ERASEBKGND()
ON_WM_CONTEXTMENU()
ON_WM_NCDESTROY()
ON_WM_DESTROY()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CBCGPDockBar message handlers
BOOL CBCGPDockBar::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, DWORD dwBCGStyle, CCreateContext* pContext)
{
ASSERT_VALID (this);
return CBCGPDockBar::CreateEx (0, dwStyle, rect, pParentWnd, dwBCGStyle, pContext);
}
//----------------------------------------------------------------------------------//
BOOL CBCGPDockBar::CreateEx(DWORD dwStyleEx, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, DWORD dwBCGStyle, CCreateContext* pContext)
{
ASSERT_VALID (this);
DWORD dwEnableAlignment = GetEnabledAlignment ();
EnableDocking (dwEnableAlignment | dwStyle);
SetBarAlignment (dwStyle);
dwStyle |= WS_CHILDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPED;
dwStyleEx = WS_EX_LEFT;
//-----------------------------
// Register a new window class:
//-----------------------------
HINSTANCE hInst = AfxGetInstanceHandle();
UINT uiClassStyle = CS_DBLCLKS;
HCURSOR hCursor = ::LoadCursor (NULL, IDC_ARROW);
HBRUSH hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
CString strClassName;
strClassName.Format (_T("BCGDockBar:%x:%x:%x:%x"),
(UINT)hInst, uiClassStyle, (UINT)hCursor, (UINT)hbrBackground);
//---------------------------------
// See if the class already exists:
//---------------------------------
WNDCLASS wndcls;
if (::GetClassInfo (hInst, strClassName, &wndcls))
{
//-----------------------------------------------
// Already registered, assert everything is good:
//-----------------------------------------------
ASSERT (wndcls.style == uiClassStyle);
}
else
{
//-------------------------------------------
// Otherwise we need to register a new class:
//-------------------------------------------
wndcls.style = uiClassStyle;
wndcls.lpfnWndProc = ::DefWindowProc;
wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
wndcls.hInstance = hInst;
wndcls.hIcon = NULL;
wndcls.hCursor = hCursor;
wndcls.hbrBackground = hbrBackground;
wndcls.lpszMenuName = NULL;
wndcls.lpszClassName = strClassName;
if (!AfxRegisterClass (&wndcls))
{
AfxThrowResourceException();
}
}
// Align the bar along borders; initially, create the dock bar with zero height/width
CRect rectDockBar = rect;
CRect rectParent;
pParentWnd->GetClientRect (&rectParent);
rectDockBar = rectParent;
switch (GetCurrentAlignment ())
{
case CBRS_ALIGN_LEFT:
rectDockBar.right = 0;
m_nDockBarID = AFX_IDW_DOCKBAR_LEFT;
break;
case CBRS_ALIGN_RIGHT:
rectDockBar.left = rectParent.right;
m_nDockBarID = AFX_IDW_DOCKBAR_RIGHT;
break;
case CBRS_ALIGN_TOP:
rectDockBar.bottom = rectParent.top;
m_nDockBarID = AFX_IDW_DOCKBAR_TOP;
break;
case CBRS_ALIGN_BOTTOM:
rectDockBar.top = rectParent.bottom;
m_nDockBarID = AFX_IDW_DOCKBAR_BOTTOM;
break;
}
m_dwBCGStyle = dwBCGStyle;
m_pDockSite = pParentWnd;
return CWnd::CreateEx (dwStyleEx, strClassName, NULL, dwStyle, rectDockBar, pParentWnd, m_nDockBarID, pContext);
}
//----------------------------------------------------------------------------------//
void CBCGPDockBar::AlignDockBar (const CRect& rectToAlignBy, CRect& rectResult,
BOOL bMoveImmediately)
{
ASSERT_VALID (this);
if (rectResult.IsRectEmpty ())
{
GetWindowRect (rectResult);
}
CRect rectOld;
GetWindowRect (rectOld);
int nCurrWidth = rectResult.Width ();
int nCurrHeight = rectResult.Height ();
switch (GetCurrentAlignment ())
{
case CBRS_ALIGN_LEFT:
rectResult.TopLeft () = rectToAlignBy.TopLeft ();
rectResult.bottom = rectResult.top + rectToAlignBy.Height ();
rectResult.right = rectResult.left + nCurrWidth;
break;
case CBRS_ALIGN_TOP:
rectResult.TopLeft () = rectToAlignBy.TopLeft ();
rectResult.right = rectResult.left + rectToAlignBy.Width ();
rectResult.bottom = rectResult.top + nCurrHeight;
break;
case CBRS_ALIGN_RIGHT:
rectResult.BottomRight () = rectToAlignBy.BottomRight ();
rectResult.top = rectResult.bottom - rectToAlignBy.Height ();
rectResult.left = rectResult.right - nCurrWidth;
break;
case CBRS_ALIGN_BOTTOM:
rectResult.BottomRight () = rectToAlignBy.BottomRight ();
rectResult.left = rectResult.right - rectToAlignBy.Width ();
rectResult.top = rectResult.bottom - nCurrHeight;
break;
}
if (rectResult != rectOld && bMoveImmediately)
{
CRect rectNew = rectResult;
ASSERT_VALID (GetParent ());
GetParent ()->ScreenToClient (rectNew);
OnSetWindowPos (&wndBottom, rectNew, SWP_NOACTIVATE | SWP_NOZORDER);
}
}
//----------------------------------------------------------------------------------//
// Moves control bar within row; floats the bar or moves it to an adjustent row
// if the bar' virtual rectangle is being moved out of row beyond a limit
//----------------------------------------------------------------------------------//
BOOL CBCGPDockBar::MoveControlBar (CBCGPControlBar* pControlBar, UINT /*nFlags*/,
CPoint ptOffset)
{
ASSERT_VALID (this);
ASSERT_VALID (pControlBar);
CBCGPDockBarRow* pRow = pControlBar->GetDockBarRow ();
ASSERT_VALID (pRow);
CRect rectVirtual;
pControlBar->GetVirtualRect (rectVirtual);
// where the virtual rectangle will be if it's moved according to ptOffset
rectVirtual.OffsetRect (ptOffset);
CPoint ptMouse;
GetCursorPos (&ptMouse);
CRect rectRow;
pRow->GetWindowRect (rectRow);
CPoint ptDelta (0, 0);
// check whether the control bar should change its state from docked to floated
CBCGPBaseControlBar* pDockBar = NULL;
if (pControlBar->IsChangeState (15, &pDockBar))
{
pControlBar->UpdateVirtualRect (ptOffset);
pControlBar->GetVirtualRect (rectVirtual);
pControlBar->FloatControlBar (rectVirtual, DM_MOUSE);
return TRUE; // indicates that the bar was floated and shouldn't be moved anymore within the dock bar
}
bool bOuterRow = false;
CBCGPDockBarRow* pNextRow = RowFromPoint (rectVirtual.CenterPoint (), bOuterRow);
int nBaseLineOffset = 0;
int nOffsetLimit = 0;
if (IsHorizontal ())
{
nBaseLineOffset = min (rectRow.bottom - rectVirtual.bottom, rectRow.top - rectVirtual.top);
nOffsetLimit = rectVirtual.Height () * 2 / 3; // / 2;
}
else
{
nBaseLineOffset = min (rectRow.right - rectVirtual.right, rectRow.left - rectVirtual.left);
nOffsetLimit = rectVirtual.Width () * 2 /3 ; // / 2;
}
if (abs (nBaseLineOffset) > nOffsetLimit)
{
if (pRow->GetBarCount () > 1 && nBaseLineOffset < pRow->GetRowHeight ())
{
// the bar should be put on the separate row, find a position to insert the row
POSITION pos = m_lstDockBarRows.Find (pRow);
ASSERT (pos != NULL);
if (nBaseLineOffset < 0) // moving down - find the next visible row
{
// the new row should be inserted before next visible row
FindNextVisibleRow (pos);
}
// otherwise the new row will be inserted before the current row
// (that's visible for sure) by AddRow (it inserts a row before spec. pos).
pRow->RemoveControlBar (pControlBar);
CBCGPDockBarRow* pNewRow =
AddRow (pos, IsHorizontal () ? rectVirtual.Height () : rectVirtual.Width ());
pNewRow->AddControlBarFromRow (pControlBar, DM_MOUSE);
return FALSE;
}
else if (pRow != pNextRow && pNextRow != NULL)
{
ASSERT_VALID (pNextRow);
//the bar is moved from the separate row to adjustent row (if exist)
if (pRow->IsExclusiveRow ())
{
SwapRows (pNextRow, pRow);
}
else
{
if (pNextRow->IsExclusiveRow ())
{
SwapRows (pRow, pNextRow);
}
else
{
pRow->RemoveControlBar (pControlBar);
pNextRow->AddControlBarFromRow (pControlBar, DM_MOUSE);
}
}
pControlBar->m_bDisableMove = true;
return FALSE;
}
}
// just move the bar within the row
if (abs (nBaseLineOffset) < rectRow.Height ())
{
HDWP hdwp = BeginDeferWindowPos (pRow->GetBarCount ());
pRow->MoveControlBar (pControlBar, ptOffset, TRUE, hdwp);
EndDeferWindowPos (hdwp);
return FALSE;
}
return FALSE;
}
//----------------------------------------------------------------------------------//
CBCGPDockBarRow* CBCGPDockBar::FindNextVisibleRow (POSITION& pos, BOOL bForward)
{
if (m_lstDockBarRows.IsEmpty ())
{
pos = NULL;
return NULL;
}
if (pos == NULL)
{
pos = bForward ? m_lstDockBarRows.GetHeadPosition ()
: m_lstDockBarRows.GetTailPosition ();
}
else
{
// we need to skip to the next / prev row from the current position
bForward ? m_lstDockBarRows.GetNext (pos) : m_lstDockBarRows.GetPrev (pos);
}
while (pos != NULL)
{
POSITION posSave = pos;
CBCGPDockBarRow* pRow = (CBCGPDockBarRow*)
(bForward ? m_lstDockBarRows.GetNext (pos)
: m_lstDockBarRows.GetPrev (pos));
ASSERT_VALID (pRow);
if (pRow->IsVisible ())
{
pos = posSave;
return pRow;
}
}
return NULL;
}
//----------------------------------------------------------------------------------//
void CBCGPDockBar::CalcWindowRect(LPRECT lpClientRect, UINT nAdjustType)
{
ASSERT_VALID (this);
CWnd::CalcWindowRect(lpClientRect, nAdjustType);
}
//----------------------------------------------------------------------------------//
void CBCGPDockBar::DockControlBar (CBCGPControlBar* pControlBar, BCGP_DOCK_METHOD dockMethod,
LPCRECT lpRect)
{
ASSERT_VALID (this);
ASSERT_VALID (pControlBar);
CRect rectDockArea; rectDockArea.SetRectEmpty ();
if (lpRect != NULL)
{
rectDockArea = lpRect;
}
BOOL bVertDock = !IsHorizontal ();
CSize szBarSize = pControlBar->CalcFixedLayout (FALSE, !bVertDock);
if (!m_lstControlBars.Find (pControlBar))
{
CBCGPDockBarRow* pRowToDock = NULL;
bool bOuterRow = false;
if (dockMethod == DM_MOUSE)
{
// calculate from which side the control bar is coming, using mouse cursor position.
// the default bar width (for side bars) and height (for top/bottom bars)
// is 30 for this example
CPoint ptMouse;
GetCursorPos (&ptMouse);
CRect rectDockBar;
GetWindowRect (&rectDockBar);
// get pointer to the row on which the bar should be placed
pRowToDock = RowFromPoint (ptMouse, bOuterRow);
}
else if (dockMethod == DM_DBL_CLICK || dockMethod == DM_RECT)
{
if (dockMethod == DM_DBL_CLICK &&
m_lstDockBarRows.Find (pControlBar->m_recentDockInfo.m_pRecentDockBarRow) != NULL)
{
pRowToDock = pControlBar->m_recentDockInfo.m_pRecentDockBarRow;
}
else
{
int nRowCount = m_lstDockBarRows.GetCount ();
if (CBCGPDockManager::m_bRestoringDockState)
{
if (pControlBar->m_recentDockInfo.m_nRecentRowIndex > nRowCount - 1)
{
for (int i = 0;
i < pControlBar->m_recentDockInfo.m_nRecentRowIndex - nRowCount + 1; i++)
{
AddRow (NULL, bVertDock ? szBarSize.cx : szBarSize.cy);
}
}
POSITION posRow = m_lstDockBarRows.FindIndex (pControlBar->m_recentDockInfo.m_nRecentRowIndex);
pRowToDock = (CBCGPDockBarRow*) m_lstDockBarRows.GetAt (posRow);
}
else
{
if (pControlBar->m_recentDockInfo.m_nRecentRowIndex < nRowCount &&
dockMethod == DM_DBL_CLICK)
{
POSITION pos = m_lstDockBarRows.FindIndex (pControlBar->m_recentDockInfo.m_nRecentRowIndex);
pRowToDock = (CBCGPDockBarRow*) m_lstDockBarRows.GetAt (pos);
}
else if (dockMethod == DM_DBL_CLICK &&
!pControlBar->m_recentDockInfo.m_recentSliderInfo.m_rectDockedRect.IsRectEmpty ())
{
pRowToDock = FindRowByRect (pControlBar->m_recentDockInfo.m_recentSliderInfo.m_rectDockedRect);
}
else if (dockMethod == DM_RECT && lpRect != NULL)
{
pRowToDock = FindRowByRect (lpRect);
}
}
if (pRowToDock == NULL)
{
AddRow (NULL, bVertDock ? szBarSize.cx : szBarSize.cy);
pRowToDock = (CBCGPDockBarRow*) m_lstDockBarRows.GetTail ();
}
}
ASSERT_VALID (pRowToDock);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -