📄 sizecbar.cpp
字号:
/////////////////////////////////////////////////////////////////////////
//
// CSizingControlBar Version 2.3
// Created: Jan 24, 1998 Last Modified: Nov 12, 1999
//
// See the official page at www.datamekanix.com for documentation and
// the latest news.
//
/////////////////////////////////////////////////////////////////////////
// Copyright (C) 1998, 1999 by Cristi Posea. All rights reserved.
//
// This code is free for personal and commercial use, providing this
// notice remains intact in the source files and all eventual changes are
// clearly marked with comments.
//
// You must obtain the author's consent before you can include this code
// in a software library.
//
// No warrantee of any kind, express or implied, is included with this
// software; use at your own risk, responsibility for damages (if any) to
// anyone resulting from the use of this software rests entirely with the
// user.
//
// Send bug reports, bug fixes, enhancements, requests, flames, etc. to:
//
// cristi@datamekanix.com
//
// Copies of the article/sources are also available at:
// o www.codeproject.com
// o www.codeguru.com
// Look for a "Docking Windows" section on the sites above and check
// the version to be sure you get the latest one ;)
//
// Hint: This class is intended to be used as a base class. Do not simply
// add your code to this file - instead create a new class derived from
// CSizingControlBar and put there what you need.
// Modify this file only to fix bugs, and don't forget to send me a copy.
//
/////////////////////////////////////////////////////////////////////////
//
// Acknowledgements:
// o Thanks to Harlan R. Seymour (harlan@harlanseymour.com) for his
// continuous support during development of this code.
// o Thanks to Dundas Software for the opportunity to test this code
// on real-life applications. If you don't know who they are, visit
// them at www.dundas.com . Their award winning components and
// development suites are a pile of gold.
// o Some ideas for the gripper came from the CToolBarEx flat toolbar
// by Joerg Koenig (Joerg.Koenig@rhein-neckar.de). Thanks, Joerg!
// o Thanks to the following people for various bug fixes and/or
// enhancements: Chris Maunder, Jakawan Ratiwanich, Udo Schaefer,
// Anatoly Ivasyuk.
// o And, of course, many thanks to all of you who used this code,
// for the invaluable feedback I received.
//
/////////////////////////////////////////////////////////////////////////
// sizecbar.cpp : implementation file
//
#include "stdafx.h"
#include "sizecbar.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////
// CSizingControlBar
CSizingControlBarArray CSizingControlBar::m_arrBars; // static member
IMPLEMENT_DYNAMIC(CSizingControlBar, baseCSizingControlBar);
CSizingControlBar::CSizingControlBar()
{
m_szMin = CSize(33, 32);
m_szHorz = CSize(200, 200);
m_szVert = CSize(200, 200);
m_szFloat = CSize(200, 200);
m_cxEdge = 5;
m_nDockBarID = 0;
m_dwSCBStyle = 0;
}
CSizingControlBar::~CSizingControlBar()
{
}
BEGIN_MESSAGE_MAP(CSizingControlBar, baseCSizingControlBar)
//{{AFX_MSG_MAP(CSizingControlBar)
ON_WM_CREATE()
ON_WM_PAINT()
ON_WM_NCPAINT()
ON_WM_NCCALCSIZE()
ON_WM_WINDOWPOSCHANGING()
ON_WM_CAPTURECHANGED()
ON_WM_SETTINGCHANGE()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_NCLBUTTONDOWN()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONDBLCLK()
ON_WM_RBUTTONDOWN()
ON_WM_NCLBUTTONUP()
ON_WM_NCMOUSEMOVE()
ON_WM_NCHITTEST()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_SETTEXT, OnSetText)
END_MESSAGE_MAP()
BOOL CSizingControlBar::Create(LPCTSTR lpszWindowName, CWnd* pParentWnd,
CSize sizeDefault, BOOL bHasGripper,
UINT nID, DWORD dwStyle)
{
// must have a parent
ASSERT_VALID(pParentWnd);
// cannot be both fixed and dynamic
// (CBRS_SIZE_DYNAMIC is used for resizng when floating)
ASSERT (!((dwStyle & CBRS_SIZE_FIXED) &&
(dwStyle & CBRS_SIZE_DYNAMIC)));
m_dwStyle = dwStyle & CBRS_ALL; // save the control bar styles
m_szHorz = sizeDefault; // set the size members
m_szVert = sizeDefault;
m_szFloat = sizeDefault;
m_cyGripper = bHasGripper ? 12 : 0; // set the gripper width
// register and create the window - skip CControlBar::Create()
CString wndclass = ::AfxRegisterWndClass(CS_DBLCLKS,
::LoadCursor(NULL, IDC_ARROW),
::GetSysColorBrush(COLOR_BTNFACE), 0);
dwStyle &= ~CBRS_ALL; // keep only the generic window styles
dwStyle |= WS_CLIPCHILDREN; // prevents flashing
if (!CWnd::Create(wndclass, lpszWindowName, dwStyle,
CRect(0, 0, 0, 0), pParentWnd, nID))
return FALSE;
return TRUE;
}
/////////////////////////////////////////////////////////////////////////
// CSizingControlBar operations
void CSizingControlBar::EnableDocking(DWORD dwDockStyle)
{
// must be CBRS_ALIGN_XXX or CBRS_FLOAT_MULTI only
ASSERT((dwDockStyle & ~(CBRS_ALIGN_ANY|CBRS_FLOAT_MULTI)) == 0);
// cannot have the CBRS_FLOAT_MULTI style
ASSERT((dwDockStyle & CBRS_FLOAT_MULTI) == 0);
// the bar must have CBRS_SIZE_DYNAMIC style
ASSERT((m_dwStyle & CBRS_SIZE_DYNAMIC) != 0);
m_dwDockStyle = dwDockStyle;
if (m_pDockContext == NULL)
m_pDockContext = new CSCBDockContext(this);
// permanently wire the bar's owner to its current parent
if (m_hWndOwner == NULL)
m_hWndOwner = ::GetParent(m_hWnd);
}
void CSizingControlBar::ToggleDocking ()
{
if (m_pDockBar != NULL)
{
// toggle docking
ASSERT (m_pDockContext != NULL);
m_pDockContext->ToggleDocking ();
}
}
/////////////////////////////////////////////////////////////////////////
// CSizingControlBar message handlers
int CSizingControlBar::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (baseCSizingControlBar::OnCreate(lpCreateStruct) == -1)
return -1;
// query SPI_GETDRAGFULLWINDOWS system parameter
// OnSettingChange() will update SCBS_DRAGSHOWCONTENT
m_dwSCBStyle &= ~SCBS_DRAGSHOWCONTENT;
BOOL bDragShowContent = FALSE;
if (m_dwSCBStyle & SCBS_FULLDRAG)
::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0,
&bDragShowContent, 0);
if (bDragShowContent)
m_dwSCBStyle |= SCBS_DRAGSHOWCONTENT;
else
m_dwSCBStyle &= ~SCBS_DRAGSHOWCONTENT;
m_arrBars.Add(this); // register
// uncomment this line if you want raised borders
// m_dwSCBStyle |= SCBS_SHOWEDGES;
return 0;
}
LRESULT CSizingControlBar::OnSetText(WPARAM wParam, LPARAM lParam)
{
LRESULT lResult = CWnd::Default();
if (IsFloating())
{
ASSERT_KINDOF(CMiniDockFrameWnd, GetParentFrame());
m_pDockBar->SetWindowText((LPCTSTR) lParam); // update dockbar
GetParentFrame()->DelayRecalcLayout(); // refresh miniframe
}
return lResult;
}
BOOL CSizingControlBar::DestroyWindow()
{
int nPos = FindSizingBar(this);
ASSERT(nPos >= 0);
m_arrBars.RemoveAt(nPos); // unregister
return baseCSizingControlBar::DestroyWindow();
}
const BOOL CSizingControlBar::IsFloating() const
{
return !IsHorzDocked() && !IsVertDocked();
}
const BOOL CSizingControlBar::IsHorzDocked() const
{
return (m_nDockBarID == AFX_IDW_DOCKBAR_TOP ||
m_nDockBarID == AFX_IDW_DOCKBAR_BOTTOM);
}
const BOOL CSizingControlBar::IsVertDocked() const
{
return (m_nDockBarID == AFX_IDW_DOCKBAR_LEFT ||
m_nDockBarID == AFX_IDW_DOCKBAR_RIGHT);
}
const BOOL CSizingControlBar::IsSideTracking() const
{
// don't call this when not tracking
ASSERT(((m_dwSCBStyle & SCBS_TRACKING) != 0) && !IsFloating());
return (m_htEdge == HTLEFT || m_htEdge == HTRIGHT) ?
IsHorzDocked() : IsVertDocked();
}
CSize CSizingControlBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
{
if (bStretch) // the bar is stretched (is not the child of a dockbar)
if (bHorz)
return CSize(32767, m_szHorz.cy);
else
return CSize(m_szVert.cx, 32767);
// dirty cast - we need access to protected CDockBar members
CSCBDockBar* pDockBar = (CSCBDockBar*) m_pDockBar;
// force imediate RecalcDelayShow() for all sizing bars on the row
// with delayShow/delayHide flags set to avoid IsVisible() problems
CSizingControlBarArray arrSCBars;
GetRowSizingBars(arrSCBars);
AFX_SIZEPARENTPARAMS layout;
layout.hDWP = pDockBar->m_bLayoutQuery ?
NULL : ::BeginDeferWindowPos(arrSCBars.GetSize());
for (int i = 0; i < arrSCBars.GetSize(); i++)
if (arrSCBars[i]->m_nStateFlags & (delayHide|delayShow))
arrSCBars[i]->RecalcDelayShow(&layout);
if (layout.hDWP != NULL)
::EndDeferWindowPos(layout.hDWP);
// get available length
CRect rc = pDockBar->m_rectLayout;
if (rc.IsRectEmpty())
m_pDockSite->GetClientRect(&rc);
int nLengthTotal = bHorz ? rc.Width() + 2 : rc.Height() - 2;
if (IsVisible() && !IsFloating() &&
(m_dwSCBStyle & SCBS_PARENTSIZING) != 0 && arrSCBars[0] == this)
if (NegotiateSpace(nLengthTotal, (bHorz != FALSE)))
AlignControlBars();
m_dwSCBStyle &= ~SCBS_PARENTSIZING;
CSize szRet = bHorz ? m_szHorz : m_szVert;
szRet.cx = max(m_szMin.cx, szRet.cx);
szRet.cy = max(m_szMin.cy, szRet.cy);
return szRet;
}
CSize CSizingControlBar::CalcDynamicLayout(int nLength, DWORD dwMode)
{
if (dwMode & (LM_HORZDOCK | LM_VERTDOCK)) // docked ?
{
if (nLength == -1)
m_dwSCBStyle |= SCBS_PARENTSIZING;
return baseCSizingControlBar::CalcDynamicLayout(nLength, dwMode);
}
if (dwMode & LM_MRUWIDTH) return m_szFloat;
if (dwMode & LM_COMMIT) return m_szFloat; // already committed
((dwMode & LM_LENGTHY) ? m_szFloat.cy : m_szFloat.cx) = nLength;
m_szFloat.cx = max(m_szFloat.cx, m_szMin.cx);
m_szFloat.cy = max(m_szFloat.cy, m_szMin.cy);
return m_szFloat;
}
void CSizingControlBar::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos)
{
// force non-client recalc if moved or resized
lpwndpos->flags |= SWP_FRAMECHANGED;
baseCSizingControlBar::OnWindowPosChanging(lpwndpos);
// find on which side are we docked
UINT nOldDockBarID = m_nDockBarID;
m_nDockBarID = GetParent()->GetDlgCtrlID();
if (!IsFloating())
if (lpwndpos->flags & SWP_SHOWWINDOW)
m_dwSCBStyle |= SCBS_KEEPSIZE;
}
/////////////////////////////////////////////////////////////////////////
// Mouse Handling
//
void CSizingControlBar::OnLButtonDown(UINT nFlags, CPoint point)
{
if (m_pDockBar != NULL)
{
// start the drag
ASSERT(m_pDockContext != NULL);
ClientToScreen(&point);
m_pDockContext->StartDrag(point);
}
else
CWnd::OnLButtonDown(nFlags, point);
}
void CSizingControlBar::OnLButtonDblClk(UINT nFlags, CPoint point)
{
if (m_pDockBar != NULL)
{
// toggle docking
ASSERT(m_pDockContext != NULL);
m_pDockContext->ToggleDocking();
}
else
CWnd::OnLButtonDblClk(nFlags, point);
}
void CSizingControlBar::OnNcLButtonDown(UINT nHitTest, CPoint point)
{
if (((m_dwSCBStyle & SCBS_TRACKING) != 0) || IsFloating())
return;
if ((nHitTest >= HTSIZEFIRST) && (nHitTest <= HTSIZELAST))
StartTracking(nHitTest); // sizing edge hit
}
void CSizingControlBar::OnNcLButtonUp(UINT nHitTest, CPoint point)
{
if (nHitTest == HTCLOSE)
m_pDockSite->ShowControlBar(this, FALSE, FALSE); // hide
baseCSizingControlBar::OnNcLButtonUp(nHitTest, point);
}
void CSizingControlBar::OnLButtonUp(UINT nFlags, CPoint point)
{
if ((m_dwSCBStyle & SCBS_TRACKING) != 0)
StopTracking();
baseCSizingControlBar::OnLButtonUp(nFlags, point);
}
void CSizingControlBar::OnRButtonDown(UINT nFlags, CPoint point)
{
if ((m_dwSCBStyle & SCBS_TRACKING) != 0)
StopTracking();
baseCSizingControlBar::OnRButtonDown(nFlags, point);
}
void CSizingControlBar::OnMouseMove(UINT nFlags, CPoint point)
{
if ((m_dwSCBStyle & SCBS_TRACKING) != 0)
OnTrackUpdateSize(point);
baseCSizingControlBar::OnMouseMove(nFlags, point);
}
void CSizingControlBar::OnCaptureChanged(CWnd *pWnd)
{
if (((m_dwSCBStyle & SCBS_TRACKING) != 0) && (pWnd != this))
StopTracking();
baseCSizingControlBar::OnCaptureChanged(pWnd);
}
void CSizingControlBar::OnNcCalcSize(BOOL bCalcValidRects,
NCCALCSIZE_PARAMS FAR* lpncsp)
{
// compute the the client area
CRect rcClient = lpncsp->rgrc[0];
rcClient.DeflateRect(3, 5, 3, 3);
if (!IsFloating())
rcClient.DeflateRect(2, 0, 2, 2);
m_dwSCBStyle &= ~SCBS_EDGEALL;
switch(m_nDockBarID)
{
case AFX_IDW_DOCKBAR_TOP:
m_dwSCBStyle |= SCBS_EDGEBOTTOM;
rcClient.DeflateRect(m_cyGripper, 0, 0, 0);
break;
case AFX_IDW_DOCKBAR_BOTTOM:
m_dwSCBStyle |= SCBS_EDGETOP;
rcClient.DeflateRect(m_cyGripper, 0, 0, 0);
break;
case AFX_IDW_DOCKBAR_LEFT:
m_dwSCBStyle |= SCBS_EDGERIGHT;
rcClient.DeflateRect(0, m_cyGripper, 0, 0);
break;
case AFX_IDW_DOCKBAR_RIGHT:
m_dwSCBStyle |= SCBS_EDGELEFT;
rcClient.DeflateRect(0, m_cyGripper, 0, 0);
break;
default:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -