forked from metin2/client
1413 lines
42 KiB
C++
1413 lines
42 KiB
C++
/////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CSizingControlBar Version 2.43
|
|
//
|
|
// Created: Jan 24, 1998 Last Modified: August 03, 2000
|
|
//
|
|
// See the official site at www.datamekanix.com for documentation and
|
|
// the latest news.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// Copyright (C) 1998-2000 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 or post them at the message board at the site.
|
|
//
|
|
// The sources and a short version of the docs are also available at
|
|
// www.codeproject.com . Look for a "Docking Windows" section and check
|
|
// the version to be sure you get the latest one ;)
|
|
//
|
|
// Hint: These classes are intended to be used as base classes. Do not
|
|
// simply add your code to these file - instead create a new class
|
|
// derived from one of CSizingControlBarXX classes and put there what
|
|
// you need. See CMyBar classes in the demo projects for examples.
|
|
// Modify this file only to fix bugs, and don't forget to send me a copy.
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// Acknowledgements:
|
|
// o Thanks to Harlan R. Seymour 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.
|
|
// o Some ideas for the gripper came from the CToolBarEx flat toolbar
|
|
// by Joerg Koenig. Thanks, Joerg!
|
|
// o Thanks to Robert Wolpow for the code on which CDockContext based
|
|
// dialgonal resizing is based.
|
|
// o Thanks to the following people for various bug fixes and/or
|
|
// enhancements: Chris Maunder, Jakawan Ratiwanich, Udo Schaefer,
|
|
// Anatoly Ivasyuk, Peter Hauptmann.
|
|
// 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
|
|
|
|
IMPLEMENT_DYNAMIC(CSizingControlBar, baseCSizingControlBar);
|
|
|
|
CSizingControlBar::CSizingControlBar()
|
|
{
|
|
m_szMinHorz = CSize(33, 32);
|
|
m_szMinVert = CSize(33, 32);
|
|
m_szMinFloat = CSize(37, 32);
|
|
m_szHorz = CSize(200, 200);
|
|
m_szVert = CSize(200, 200);
|
|
m_szFloat = CSize(200, 200);
|
|
m_bTracking = FALSE;
|
|
m_bKeepSize = FALSE;
|
|
m_bParentSizing = FALSE;
|
|
m_cxEdge = 5;
|
|
m_bDragShowContent = FALSE;
|
|
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_NCMOUSEMOVE()
|
|
ON_WM_NCHITTEST()
|
|
ON_WM_CLOSE()
|
|
ON_WM_SIZE()
|
|
//}}AFX_MSG_MAP
|
|
ON_MESSAGE(WM_SETTEXT, OnSetText)
|
|
END_MESSAGE_MAP()
|
|
|
|
// old creation method, still here for compatibility reasons
|
|
BOOL CSizingControlBar::Create(LPCTSTR lpszWindowName, CWnd* pParentWnd,
|
|
CSize sizeDefault, BOOL bHasGripper,
|
|
UINT nID, DWORD dwStyle)
|
|
{
|
|
UNUSED_ALWAYS(bHasGripper);
|
|
|
|
m_szHorz = m_szVert = m_szFloat = sizeDefault;
|
|
return Create(lpszWindowName, pParentWnd, nID, dwStyle);
|
|
}
|
|
|
|
// preffered creation method
|
|
BOOL CSizingControlBar::Create(LPCTSTR lpszWindowName,
|
|
CWnd* pParentWnd, 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
|
|
|
|
// 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
|
|
#if defined(_SCB_REPLACE_MINIFRAME) && !defined(_SCB_MINIFRAME_CAPTION)
|
|
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);
|
|
}
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// CSizingControlBar message handlers
|
|
|
|
int CSizingControlBar::OnCreate(LPCREATESTRUCT lpCreateStruct)
|
|
{
|
|
if (baseCSizingControlBar::OnCreate(lpCreateStruct) == -1)
|
|
return -1;
|
|
|
|
// query SPI_GETDRAGFULLWINDOWS system parameter
|
|
// OnSettingChange() will update m_bDragShowContent
|
|
m_bDragShowContent = FALSE;
|
|
::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0,
|
|
&m_bDragShowContent, 0);
|
|
|
|
// uncomment this line if you want raised borders
|
|
// m_dwSCBStyle |= SCBS_SHOWEDGES;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
LRESULT CSizingControlBar::OnSetText(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
UNUSED_ALWAYS(wParam);
|
|
|
|
LRESULT lResult = CWnd::Default();
|
|
|
|
if (IsFloating() &&
|
|
GetParentFrame()->IsKindOf(RUNTIME_CLASS(CMiniDockFrameWnd)))
|
|
{
|
|
m_pDockBar->SetWindowText((LPCTSTR) lParam); // update dockbar
|
|
GetParentFrame()->DelayRecalcLayout(); // refresh miniframe
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
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_bTracking && !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
|
|
CSCBArray 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_bParentSizing && arrSCBars[0] == this)
|
|
if (NegotiateSpace(nLengthTotal, (bHorz != FALSE)))
|
|
AlignControlBars();
|
|
|
|
m_bParentSizing = FALSE;
|
|
|
|
if (bHorz)
|
|
return CSize(max(m_szMinHorz.cx, m_szHorz.cx),
|
|
max(m_szMinHorz.cy, m_szHorz.cy));
|
|
|
|
return CSize(max(m_szMinVert.cx, m_szVert.cx),
|
|
max(m_szMinVert.cy, m_szVert.cy));
|
|
}
|
|
|
|
CSize CSizingControlBar::CalcDynamicLayout(int nLength, DWORD dwMode)
|
|
{
|
|
if (dwMode & (LM_HORZDOCK | LM_VERTDOCK)) // docked ?
|
|
{
|
|
if (nLength == -1)
|
|
m_bParentSizing = TRUE;
|
|
|
|
return baseCSizingControlBar::CalcDynamicLayout(nLength, dwMode);
|
|
}
|
|
|
|
if (dwMode & LM_MRUWIDTH) return m_szFloat;
|
|
if (dwMode & LM_COMMIT) return m_szFloat; // already committed
|
|
|
|
#ifndef _SCB_REPLACE_MINIFRAME
|
|
// check for dialgonal resizing hit test
|
|
int nHitTest = m_pDockContext->m_nHitTest;
|
|
if (IsFloating() &&
|
|
(nHitTest == HTTOPLEFT || nHitTest == HTBOTTOMLEFT ||
|
|
nHitTest == HTTOPRIGHT || nHitTest == HTBOTTOMRIGHT))
|
|
{
|
|
CPoint ptCursor;
|
|
::GetCursorPos(&ptCursor);
|
|
|
|
CRect rFrame, rBar;
|
|
GetParentFrame()->GetWindowRect(&rFrame);
|
|
GetWindowRect(&rBar);
|
|
|
|
if (nHitTest == HTTOPLEFT || nHitTest == HTBOTTOMLEFT)
|
|
{
|
|
m_szFloat.cx = rFrame.left + rBar.Width() - ptCursor.x;
|
|
m_pDockContext->m_rectFrameDragHorz.left =
|
|
min(ptCursor.x, rFrame.left + rBar.Width() - m_szMinFloat.cx);
|
|
}
|
|
|
|
if (nHitTest == HTTOPLEFT || nHitTest == HTTOPRIGHT)
|
|
{
|
|
m_szFloat.cy = rFrame.top + rBar.Height() - ptCursor.y;
|
|
m_pDockContext->m_rectFrameDragHorz.top =
|
|
min(ptCursor.y, rFrame.top + rBar.Height() - m_szMinFloat.cy);
|
|
}
|
|
|
|
if (nHitTest == HTTOPRIGHT || nHitTest == HTBOTTOMRIGHT)
|
|
m_szFloat.cx = rBar.Width() + ptCursor.x - rFrame.right;
|
|
|
|
if (nHitTest == HTBOTTOMLEFT || nHitTest == HTBOTTOMRIGHT)
|
|
m_szFloat.cy = rBar.Height() + ptCursor.y - rFrame.bottom;
|
|
}
|
|
else
|
|
#endif //_SCB_REPLACE_MINIFRAME
|
|
((dwMode & LM_LENGTHY) ? m_szFloat.cy : m_szFloat.cx) = nLength;
|
|
|
|
m_szFloat.cx = max(m_szFloat.cx, m_szMinFloat.cx);
|
|
m_szFloat.cy = max(m_szFloat.cy, m_szMinFloat.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
|
|
m_nDockBarID = GetParent()->GetDlgCtrlID();
|
|
|
|
if (!IsFloating())
|
|
if (lpwndpos->flags & SWP_SHOWWINDOW)
|
|
m_bKeepSize = TRUE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// 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)
|
|
{
|
|
UNUSED_ALWAYS(point);
|
|
|
|
if (m_bTracking || IsFloating())
|
|
return;
|
|
|
|
if ((nHitTest >= HTSIZEFIRST) && (nHitTest <= HTSIZELAST))
|
|
StartTracking(nHitTest, point); // sizing edge hit
|
|
}
|
|
|
|
void CSizingControlBar::OnLButtonUp(UINT nFlags, CPoint point)
|
|
{
|
|
if (m_bTracking)
|
|
StopTracking();
|
|
|
|
baseCSizingControlBar::OnLButtonUp(nFlags, point);
|
|
}
|
|
|
|
void CSizingControlBar::OnRButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
if (m_bTracking)
|
|
StopTracking();
|
|
|
|
baseCSizingControlBar::OnRButtonDown(nFlags, point);
|
|
}
|
|
|
|
void CSizingControlBar::OnMouseMove(UINT nFlags, CPoint point)
|
|
{
|
|
if (m_bTracking)
|
|
{
|
|
CPoint ptScreen = point;
|
|
ClientToScreen(&ptScreen);
|
|
|
|
OnTrackUpdateSize(ptScreen);
|
|
}
|
|
|
|
baseCSizingControlBar::OnMouseMove(nFlags, point);
|
|
}
|
|
|
|
void CSizingControlBar::OnCaptureChanged(CWnd *pWnd)
|
|
{
|
|
if (m_bTracking && (pWnd != this))
|
|
StopTracking();
|
|
|
|
baseCSizingControlBar::OnCaptureChanged(pWnd);
|
|
}
|
|
|
|
void CSizingControlBar::OnNcCalcSize(BOOL bCalcValidRects,
|
|
NCCALCSIZE_PARAMS FAR* lpncsp)
|
|
{
|
|
UNUSED_ALWAYS(bCalcValidRects);
|
|
|
|
#ifndef _SCB_REPLACE_MINIFRAME
|
|
// Enable diagonal resizing for floating miniframe
|
|
if (IsFloating())
|
|
{
|
|
CFrameWnd* pFrame = GetParentFrame();
|
|
if (pFrame != NULL &&
|
|
pFrame->IsKindOf(RUNTIME_CLASS(CMiniFrameWnd)))
|
|
{
|
|
DWORD dwStyle = ::GetWindowLong(pFrame->m_hWnd, GWL_STYLE);
|
|
if ((dwStyle & MFS_4THICKFRAME) != 0)
|
|
{
|
|
pFrame->ModifyStyle(MFS_4THICKFRAME, 0); // clear
|
|
GetParent()->ModifyStyle(0, WS_CLIPCHILDREN);
|
|
}
|
|
}
|
|
}
|
|
#endif _SCB_REPLACE_MINIFRAME
|
|
|
|
// compute the the client area
|
|
m_dwSCBStyle &= ~SCBS_EDGEALL;
|
|
|
|
// add resizing edges between bars on the same row
|
|
if (!IsFloating() && m_pDockBar != NULL)
|
|
{
|
|
CSCBArray arrSCBars;
|
|
int nThis;
|
|
GetRowSizingBars(arrSCBars, nThis);
|
|
|
|
BOOL bHorz = IsHorzDocked();
|
|
if (nThis > 0)
|
|
m_dwSCBStyle |= bHorz ? SCBS_EDGELEFT : SCBS_EDGETOP;
|
|
|
|
if (nThis < arrSCBars.GetUpperBound())
|
|
m_dwSCBStyle |= bHorz ? SCBS_EDGERIGHT : SCBS_EDGEBOTTOM;
|
|
}
|
|
|
|
NcCalcClient(&lpncsp->rgrc[0], m_nDockBarID);
|
|
}
|
|
|
|
void CSizingControlBar::NcCalcClient(LPRECT pRc, UINT nDockBarID)
|
|
{
|
|
CRect rc(pRc);
|
|
|
|
rc.DeflateRect(3, 5, 3, 3);
|
|
if (nDockBarID != AFX_IDW_DOCKBAR_FLOAT)
|
|
rc.DeflateRect(2, 0, 2, 2);
|
|
|
|
switch(nDockBarID)
|
|
{
|
|
case AFX_IDW_DOCKBAR_TOP:
|
|
m_dwSCBStyle |= SCBS_EDGEBOTTOM;
|
|
break;
|
|
case AFX_IDW_DOCKBAR_BOTTOM:
|
|
m_dwSCBStyle |= SCBS_EDGETOP;
|
|
break;
|
|
case AFX_IDW_DOCKBAR_LEFT:
|
|
m_dwSCBStyle |= SCBS_EDGERIGHT;
|
|
break;
|
|
case AFX_IDW_DOCKBAR_RIGHT:
|
|
m_dwSCBStyle |= SCBS_EDGELEFT;
|
|
break;
|
|
}
|
|
|
|
// make room for edges only if they will be painted
|
|
if (m_dwSCBStyle & SCBS_SHOWEDGES)
|
|
rc.DeflateRect(
|
|
(m_dwSCBStyle & SCBS_EDGELEFT) ? m_cxEdge : 0,
|
|
(m_dwSCBStyle & SCBS_EDGETOP) ? m_cxEdge : 0,
|
|
(m_dwSCBStyle & SCBS_EDGERIGHT) ? m_cxEdge : 0,
|
|
(m_dwSCBStyle & SCBS_EDGEBOTTOM) ? m_cxEdge : 0);
|
|
|
|
*pRc = rc;
|
|
}
|
|
|
|
void CSizingControlBar::OnNcPaint()
|
|
{
|
|
// get window DC that is clipped to the non-client area
|
|
CWindowDC dc(this);
|
|
|
|
CRect rcClient, rcBar;
|
|
GetClientRect(rcClient);
|
|
ClientToScreen(rcClient);
|
|
GetWindowRect(rcBar);
|
|
rcClient.OffsetRect(-rcBar.TopLeft());
|
|
rcBar.OffsetRect(-rcBar.TopLeft());
|
|
|
|
CDC mdc;
|
|
mdc.CreateCompatibleDC(&dc);
|
|
|
|
CBitmap bm;
|
|
bm.CreateCompatibleBitmap(&dc, rcBar.Width(), rcBar.Height());
|
|
CBitmap* pOldBm = mdc.SelectObject(&bm);
|
|
|
|
// draw borders in non-client area
|
|
CRect rcDraw = rcBar;
|
|
DrawBorders(&mdc, rcDraw);
|
|
|
|
// erase the NC background
|
|
mdc.FillRect(rcDraw, CBrush::FromHandle(
|
|
(HBRUSH) GetClassLong(m_hWnd, GCL_HBRBACKGROUND)));
|
|
|
|
if (m_dwSCBStyle & SCBS_SHOWEDGES)
|
|
{
|
|
CRect rcEdge; // paint the sizing edges
|
|
for (int i = 0; i < 4; i++)
|
|
if (GetEdgeRect(rcBar, GetEdgeHTCode(i), rcEdge))
|
|
mdc.Draw3dRect(rcEdge, ::GetSysColor(COLOR_BTNHIGHLIGHT),
|
|
::GetSysColor(COLOR_BTNSHADOW));
|
|
}
|
|
|
|
NcPaintGripper(&mdc, rcClient);
|
|
|
|
// client area is not our bussiness :)
|
|
dc.IntersectClipRect(rcBar);
|
|
dc.ExcludeClipRect(rcClient);
|
|
|
|
dc.BitBlt(0, 0, rcBar.Width(), rcBar.Height(), &mdc, 0, 0, SRCCOPY);
|
|
|
|
ReleaseDC(&dc);
|
|
|
|
mdc.SelectObject(pOldBm);
|
|
bm.DeleteObject();
|
|
mdc.DeleteDC();
|
|
}
|
|
|
|
void CSizingControlBar::NcPaintGripper(CDC* pDC, CRect rcClient)
|
|
{
|
|
UNUSED_ALWAYS(pDC);
|
|
UNUSED_ALWAYS(rcClient);
|
|
}
|
|
|
|
void CSizingControlBar::OnPaint()
|
|
{
|
|
// overridden to skip border painting based on clientrect
|
|
CPaintDC dc(this);
|
|
}
|
|
|
|
LRESULT CSizingControlBar::OnNcHitTest(CPoint point)
|
|
{
|
|
CRect rcBar, rcEdge;
|
|
GetWindowRect(rcBar);
|
|
|
|
if (!IsFloating())
|
|
for (int i = 0; i < 4; i++)
|
|
if (GetEdgeRect(rcBar, GetEdgeHTCode(i), rcEdge))
|
|
if (rcEdge.PtInRect(point))
|
|
return GetEdgeHTCode(i);
|
|
|
|
return HTCLIENT;
|
|
}
|
|
|
|
void CSizingControlBar::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
|
|
{
|
|
baseCSizingControlBar::OnSettingChange(uFlags, lpszSection);
|
|
|
|
m_bDragShowContent = FALSE;
|
|
::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0,
|
|
&m_bDragShowContent, 0); // update
|
|
}
|
|
|
|
void CSizingControlBar::OnSize(UINT nType, int cx, int cy)
|
|
{
|
|
UNUSED_ALWAYS(nType);
|
|
|
|
if ((m_dwSCBStyle & SCBS_SIZECHILD) != 0)
|
|
{
|
|
// automatic child resizing - only one child is allowed
|
|
CWnd* pWnd = GetWindow(GW_CHILD);
|
|
if (pWnd != NULL)
|
|
{
|
|
pWnd->MoveWindow(0, 0, cx, cy);
|
|
ASSERT(pWnd->GetWindow(GW_HWNDNEXT) == NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CSizingControlBar::OnClose()
|
|
{
|
|
// do nothing: protection against accidentally destruction by the
|
|
// child control (i.e. if user hits Esc in a child editctrl)
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// CSizingControlBar implementation helpers
|
|
|
|
void CSizingControlBar::StartTracking(UINT nHitTest, CPoint point)
|
|
{
|
|
SetCapture();
|
|
|
|
// make sure no updates are pending
|
|
if (!m_bDragShowContent)
|
|
RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW);
|
|
|
|
m_htEdge = nHitTest;
|
|
m_bTracking = TRUE;
|
|
|
|
BOOL bHorz = IsHorzDocked();
|
|
BOOL bHorzTracking = m_htEdge == HTLEFT || m_htEdge == HTRIGHT;
|
|
|
|
m_nTrackPosOld = bHorzTracking ? point.x : point.y;
|
|
|
|
CRect rcBar, rcEdge;
|
|
GetWindowRect(rcBar);
|
|
GetEdgeRect(rcBar, m_htEdge, rcEdge);
|
|
m_nTrackEdgeOfs = m_nTrackPosOld -
|
|
(bHorzTracking ? rcEdge.CenterPoint().x : rcEdge.CenterPoint().y);
|
|
|
|
CSCBArray arrSCBars;
|
|
int nThis;
|
|
GetRowSizingBars(arrSCBars, nThis);
|
|
|
|
m_nTrackPosMin = m_nTrackPosMax = m_nTrackPosOld;
|
|
if (!IsSideTracking())
|
|
{
|
|
// calc minwidth as the max minwidth of the sizing bars on row
|
|
int nMinWidth = bHorz ? m_szMinHorz.cy : m_szMinVert.cx;
|
|
for (int i = 0; i < arrSCBars.GetSize(); i++)
|
|
nMinWidth = max(nMinWidth, bHorz ?
|
|
arrSCBars[i]->m_szMinHorz.cy :
|
|
arrSCBars[i]->m_szMinVert.cx);
|
|
int nExcessWidth = (bHorz ? m_szHorz.cy : m_szVert.cx) - nMinWidth;
|
|
|
|
// the control bar cannot grow with more than the width of
|
|
// remaining client area of the mainframe
|
|
CRect rcT;
|
|
m_pDockSite->RepositionBars(0, 0xFFFF, AFX_IDW_PANE_FIRST,
|
|
reposQuery, &rcT, NULL, TRUE);
|
|
int nMaxWidth = bHorz ? rcT.Height() - 2 : rcT.Width() - 2;
|
|
|
|
BOOL bTopOrLeft = m_htEdge == HTTOP || m_htEdge == HTLEFT;
|
|
|
|
m_nTrackPosMin -= bTopOrLeft ? nMaxWidth : nExcessWidth;
|
|
m_nTrackPosMax += bTopOrLeft ? nExcessWidth : nMaxWidth;
|
|
}
|
|
else
|
|
{
|
|
// side tracking:
|
|
// max size is the actual size plus the amount the other
|
|
// sizing bars can be decreased until they reach their minsize
|
|
if (m_htEdge == HTBOTTOM || m_htEdge == HTRIGHT)
|
|
nThis++;
|
|
|
|
for (int i = 0; i < arrSCBars.GetSize(); i++)
|
|
{
|
|
CSizingControlBar* pBar = arrSCBars[i];
|
|
|
|
int nExcessWidth = bHorz ?
|
|
pBar->m_szHorz.cx - pBar->m_szMinHorz.cx :
|
|
pBar->m_szVert.cy - pBar->m_szMinVert.cy;
|
|
|
|
if (i < nThis)
|
|
m_nTrackPosMin -= nExcessWidth;
|
|
else
|
|
m_nTrackPosMax += nExcessWidth;
|
|
}
|
|
}
|
|
|
|
OnTrackInvertTracker(); // draw tracker
|
|
}
|
|
|
|
void CSizingControlBar::StopTracking()
|
|
{
|
|
OnTrackInvertTracker(); // erase tracker
|
|
|
|
m_bTracking = FALSE;
|
|
ReleaseCapture();
|
|
|
|
m_pDockSite->DelayRecalcLayout();
|
|
}
|
|
|
|
void CSizingControlBar::OnTrackUpdateSize(CPoint& point)
|
|
{
|
|
ASSERT(!IsFloating());
|
|
|
|
BOOL bHorzTrack = m_htEdge == HTLEFT || m_htEdge == HTRIGHT;
|
|
|
|
int nTrackPos = bHorzTrack ? point.x : point.y;
|
|
nTrackPos = max(m_nTrackPosMin, min(m_nTrackPosMax, nTrackPos));
|
|
|
|
int nDelta = nTrackPos - m_nTrackPosOld;
|
|
|
|
if (nDelta == 0)
|
|
return; // no pos change
|
|
|
|
OnTrackInvertTracker(); // erase tracker
|
|
|
|
m_nTrackPosOld = nTrackPos;
|
|
|
|
BOOL bHorz = IsHorzDocked();
|
|
|
|
CSize sizeNew = bHorz ? m_szHorz : m_szVert;
|
|
switch (m_htEdge)
|
|
{
|
|
case HTLEFT: sizeNew -= CSize(nDelta, 0); break;
|
|
case HTTOP: sizeNew -= CSize(0, nDelta); break;
|
|
case HTRIGHT: sizeNew += CSize(nDelta, 0); break;
|
|
case HTBOTTOM: sizeNew += CSize(0, nDelta); break;
|
|
}
|
|
|
|
CSCBArray arrSCBars;
|
|
int nThis;
|
|
GetRowSizingBars(arrSCBars, nThis);
|
|
|
|
if (!IsSideTracking())
|
|
for (int i = 0; i < arrSCBars.GetSize(); i++)
|
|
{
|
|
CSizingControlBar* pBar = arrSCBars[i];
|
|
// make same width (or height)
|
|
(bHorz ? pBar->m_szHorz.cy : pBar->m_szVert.cx) =
|
|
bHorz ? sizeNew.cy : sizeNew.cx;
|
|
}
|
|
else
|
|
{
|
|
int nGrowingBar = nThis;
|
|
BOOL bBefore = m_htEdge == HTTOP || m_htEdge == HTLEFT;
|
|
if (bBefore && nDelta > 0)
|
|
nGrowingBar--;
|
|
if (!bBefore && nDelta < 0)
|
|
nGrowingBar++;
|
|
if (nGrowingBar != nThis)
|
|
bBefore = !bBefore;
|
|
|
|
// nGrowing is growing
|
|
nDelta = abs(nDelta);
|
|
CSizingControlBar* pBar = arrSCBars[nGrowingBar];
|
|
(bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy) += nDelta;
|
|
|
|
// the others are shrinking
|
|
int nFirst = bBefore ? nGrowingBar - 1 : nGrowingBar + 1;
|
|
int nLimit = bBefore ? -1 : arrSCBars.GetSize();
|
|
|
|
for (int i = nFirst; nDelta != 0 && i != nLimit; i += (bBefore ? -1 : 1))
|
|
{
|
|
CSizingControlBar* pBar = arrSCBars[i];
|
|
|
|
int nDeltaT = min(nDelta,
|
|
(bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy) -
|
|
(bHorz ? pBar->m_szMinHorz.cx : pBar->m_szMinVert.cy));
|
|
|
|
(bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy) -= nDeltaT;
|
|
nDelta -= nDeltaT;
|
|
}
|
|
}
|
|
|
|
OnTrackInvertTracker(); // redraw tracker at new pos
|
|
|
|
if (m_bDragShowContent)
|
|
m_pDockSite->DelayRecalcLayout();
|
|
}
|
|
|
|
void CSizingControlBar::OnTrackInvertTracker()
|
|
{
|
|
ASSERT(m_bTracking);
|
|
|
|
if (m_bDragShowContent)
|
|
return; // don't show tracker if DragFullWindows is on
|
|
|
|
BOOL bHorz = IsHorzDocked();
|
|
CRect rc, rcBar, rcDock, rcFrame;
|
|
GetWindowRect(rcBar);
|
|
m_pDockBar->GetWindowRect(rcDock);
|
|
m_pDockSite->GetWindowRect(rcFrame);
|
|
VERIFY(GetEdgeRect(rcBar, m_htEdge, rc));
|
|
if (!IsSideTracking())
|
|
rc = bHorz ?
|
|
CRect(rcDock.left + 1, rc.top, rcDock.right - 1, rc.bottom) :
|
|
CRect(rc.left, rcDock.top + 1, rc.right, rcDock.bottom - 1);
|
|
|
|
BOOL bHorzTracking = m_htEdge == HTLEFT || m_htEdge == HTRIGHT;
|
|
int nOfs = m_nTrackPosOld - m_nTrackEdgeOfs;
|
|
nOfs -= bHorzTracking ? rc.CenterPoint().x : rc.CenterPoint().y;
|
|
rc.OffsetRect(bHorzTracking ? nOfs : 0, bHorzTracking ? 0 : nOfs);
|
|
rc.OffsetRect(-rcFrame.TopLeft());
|
|
|
|
CDC *pDC = m_pDockSite->GetDCEx(NULL,
|
|
DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
|
|
CBrush* pBrush = CDC::GetHalftoneBrush();
|
|
CBrush* pBrushOld = pDC->SelectObject(pBrush);
|
|
|
|
pDC->PatBlt(rc.left, rc.top, rc.Width(), rc.Height(), PATINVERT);
|
|
|
|
pDC->SelectObject(pBrushOld);
|
|
m_pDockSite->ReleaseDC(pDC);
|
|
}
|
|
|
|
BOOL CSizingControlBar::GetEdgeRect(CRect rcWnd, UINT nHitTest,
|
|
CRect& rcEdge)
|
|
{
|
|
rcEdge = rcWnd;
|
|
if (m_dwSCBStyle & SCBS_SHOWEDGES)
|
|
rcEdge.DeflateRect(1, 1);
|
|
BOOL bHorz = IsHorzDocked();
|
|
|
|
switch (nHitTest)
|
|
{
|
|
case HTLEFT:
|
|
if (!(m_dwSCBStyle & SCBS_EDGELEFT)) return FALSE;
|
|
rcEdge.right = rcEdge.left + m_cxEdge;
|
|
rcEdge.DeflateRect(0, bHorz ? m_cxEdge: 0);
|
|
break;
|
|
case HTTOP:
|
|
if (!(m_dwSCBStyle & SCBS_EDGETOP)) return FALSE;
|
|
rcEdge.bottom = rcEdge.top + m_cxEdge;
|
|
rcEdge.DeflateRect(bHorz ? 0 : m_cxEdge, 0);
|
|
break;
|
|
case HTRIGHT:
|
|
if (!(m_dwSCBStyle & SCBS_EDGERIGHT)) return FALSE;
|
|
rcEdge.left = rcEdge.right - m_cxEdge;
|
|
rcEdge.DeflateRect(0, bHorz ? m_cxEdge: 0);
|
|
break;
|
|
case HTBOTTOM:
|
|
if (!(m_dwSCBStyle & SCBS_EDGEBOTTOM)) return FALSE;
|
|
rcEdge.top = rcEdge.bottom - m_cxEdge;
|
|
rcEdge.DeflateRect(bHorz ? 0 : m_cxEdge, 0);
|
|
break;
|
|
default:
|
|
ASSERT(FALSE); // invalid hit test code
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
UINT CSizingControlBar::GetEdgeHTCode(int nEdge)
|
|
{
|
|
if (nEdge == 0) return HTLEFT;
|
|
if (nEdge == 1) return HTTOP;
|
|
if (nEdge == 2) return HTRIGHT;
|
|
if (nEdge == 3) return HTBOTTOM;
|
|
ASSERT(FALSE); // invalid edge code
|
|
return HTNOWHERE;
|
|
}
|
|
|
|
void CSizingControlBar::GetRowInfo(int& nFirst, int& nLast, int& nThis)
|
|
{
|
|
ASSERT_VALID(m_pDockBar); // verify bounds
|
|
|
|
nThis = m_pDockBar->FindBar(this);
|
|
ASSERT(nThis != -1);
|
|
|
|
int i, nBars = m_pDockBar->m_arrBars.GetSize();
|
|
|
|
// find the first and the last bar in row
|
|
for (nFirst = -1, i = nThis - 1; i >= 0 && nFirst == -1; i--)
|
|
if (m_pDockBar->m_arrBars[i] == NULL)
|
|
nFirst = i + 1;
|
|
for (nLast = -1, i = nThis + 1; i < nBars && nLast == -1; i++)
|
|
if (m_pDockBar->m_arrBars[i] == NULL)
|
|
nLast = i - 1;
|
|
|
|
ASSERT((nLast != -1) && (nFirst != -1));
|
|
}
|
|
|
|
void CSizingControlBar::GetRowSizingBars(CSCBArray& arrSCBars)
|
|
{
|
|
int nThis; // dummy
|
|
GetRowSizingBars(arrSCBars, nThis);
|
|
}
|
|
|
|
void CSizingControlBar::GetRowSizingBars(CSCBArray& arrSCBars, int& nThis)
|
|
{
|
|
arrSCBars.RemoveAll();
|
|
|
|
int nFirstT, nLastT, nThisT;
|
|
GetRowInfo(nFirstT, nLastT, nThisT);
|
|
|
|
nThis = -1;
|
|
for (int i = nFirstT; i <= nLastT; i++)
|
|
{
|
|
CSizingControlBar* pBar =
|
|
(CSizingControlBar*) m_pDockBar->m_arrBars[i];
|
|
if (HIWORD(pBar) == 0) continue; // placeholder
|
|
if (!pBar->IsVisible()) continue;
|
|
if (pBar->IsKindOf(RUNTIME_CLASS(CSizingControlBar)))
|
|
{
|
|
if (pBar == this)
|
|
nThis = arrSCBars.GetSize();
|
|
|
|
arrSCBars.Add(pBar);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL CSizingControlBar::NegotiateSpace(int nLengthTotal, BOOL bHorz)
|
|
{
|
|
ASSERT(bHorz == IsHorzDocked());
|
|
|
|
int nFirst, nLast, nThis;
|
|
GetRowInfo(nFirst, nLast, nThis);
|
|
|
|
int nLengthAvail = nLengthTotal;
|
|
int nLengthActual = 0;
|
|
int nLengthMin = 2;
|
|
int nWidthMax = 0;
|
|
CSizingControlBar* pBar;
|
|
|
|
for (int i = nFirst; i <= nLast; i++)
|
|
{
|
|
pBar = (CSizingControlBar*) m_pDockBar->m_arrBars[i];
|
|
if (HIWORD(pBar) == 0) continue; // placeholder
|
|
if (!pBar->IsVisible()) continue;
|
|
BOOL bIsSizingBar =
|
|
pBar->IsKindOf(RUNTIME_CLASS(CSizingControlBar));
|
|
|
|
int nLengthBar; // minimum length of the bar
|
|
if (bIsSizingBar)
|
|
nLengthBar = bHorz ? pBar->m_szMinHorz.cx - 2 :
|
|
pBar->m_szMinVert.cy - 2;
|
|
else
|
|
{
|
|
CRect rcBar;
|
|
pBar->GetWindowRect(&rcBar);
|
|
nLengthBar = bHorz ? rcBar.Width() - 2 : rcBar.Height() - 2;
|
|
}
|
|
|
|
nLengthMin += nLengthBar;
|
|
if (nLengthMin > nLengthTotal)
|
|
{
|
|
// split the row after fixed bar
|
|
if (i < nThis)
|
|
{
|
|
m_pDockBar->m_arrBars.InsertAt(i + 1,
|
|
(CControlBar*) NULL);
|
|
return FALSE;
|
|
}
|
|
|
|
// only this sizebar remains on the row, adjust it to minsize
|
|
if (i == nThis)
|
|
{
|
|
if (bHorz)
|
|
m_szHorz.cx = m_szMinHorz.cx;
|
|
else
|
|
m_szVert.cy = m_szMinVert.cy;
|
|
|
|
return TRUE; // the dockbar will split the row for us
|
|
}
|
|
|
|
// we have enough bars - go negotiate with them
|
|
m_pDockBar->m_arrBars.InsertAt(i, (CControlBar*) NULL);
|
|
nLast = i - 1;
|
|
break;
|
|
}
|
|
|
|
if (bIsSizingBar)
|
|
{
|
|
nLengthActual += bHorz ? pBar->m_szHorz.cx - 2 :
|
|
pBar->m_szVert.cy - 2;
|
|
nWidthMax = max(nWidthMax, bHorz ? pBar->m_szHorz.cy :
|
|
pBar->m_szVert.cx);
|
|
}
|
|
else
|
|
nLengthAvail -= nLengthBar;
|
|
}
|
|
|
|
CSCBArray arrSCBars;
|
|
GetRowSizingBars(arrSCBars);
|
|
int nNumBars = arrSCBars.GetSize();
|
|
int nDelta = nLengthAvail - nLengthActual;
|
|
|
|
// return faster when there is only one sizing bar per row (this one)
|
|
if (nNumBars == 1)
|
|
{
|
|
ASSERT(arrSCBars[0] == this);
|
|
|
|
if (nDelta == 0)
|
|
return TRUE;
|
|
|
|
m_bKeepSize = FALSE;
|
|
(bHorz ? m_szHorz.cx : m_szVert.cy) += nDelta;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// make all the bars the same width
|
|
for (int i = 0; i < nNumBars; i++)
|
|
if (bHorz)
|
|
arrSCBars[i]->m_szHorz.cy = nWidthMax;
|
|
else
|
|
arrSCBars[i]->m_szVert.cx = nWidthMax;
|
|
|
|
// distribute the difference between the bars,
|
|
// but don't shrink them below their minsizes
|
|
while (nDelta != 0)
|
|
{
|
|
int nDeltaOld = nDelta;
|
|
for (int i = 0; i < nNumBars; i++)
|
|
{
|
|
pBar = arrSCBars[i];
|
|
int nLMin = bHorz ?
|
|
pBar->m_szMinHorz.cx : pBar->m_szMinVert.cy;
|
|
int nL = bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy;
|
|
|
|
if ((nL == nLMin) && (nDelta < 0) || // already at min length
|
|
pBar->m_bKeepSize) // or wants to keep its size
|
|
continue;
|
|
|
|
// sign of nDelta
|
|
int nDelta2 = (nDelta == 0) ? 0 : ((nDelta < 0) ? -1 : 1);
|
|
|
|
(bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy) += nDelta2;
|
|
nDelta -= nDelta2;
|
|
if (nDelta == 0) break;
|
|
}
|
|
// clear m_bKeepSize flags
|
|
if ((nDeltaOld == nDelta) || (nDelta == 0))
|
|
for (int i = 0; i < nNumBars; i++)
|
|
arrSCBars[i]->m_bKeepSize = FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CSizingControlBar::AlignControlBars()
|
|
{
|
|
int nFirst, nLast, nThis;
|
|
GetRowInfo(nFirst, nLast, nThis);
|
|
|
|
BOOL bHorz = IsHorzDocked();
|
|
BOOL bNeedRecalc = FALSE;
|
|
int nAlign = bHorz ? -2 : 0;
|
|
|
|
CRect rc, rcDock;
|
|
m_pDockBar->GetWindowRect(&rcDock);
|
|
|
|
for (int i = nFirst; i <= nLast; i++)
|
|
{
|
|
CSizingControlBar* pBar =
|
|
(CSizingControlBar*) m_pDockBar->m_arrBars[i];
|
|
if (HIWORD(pBar) == 0) continue; // placeholder
|
|
if (!pBar->IsVisible()) continue;
|
|
|
|
pBar->GetWindowRect(&rc);
|
|
rc.OffsetRect(-rcDock.TopLeft());
|
|
|
|
if (pBar->IsKindOf(RUNTIME_CLASS(CSizingControlBar)))
|
|
rc = CRect(rc.TopLeft(),
|
|
bHorz ? pBar->m_szHorz : pBar->m_szVert);
|
|
|
|
if ((bHorz ? rc.left : rc.top) != nAlign)
|
|
{
|
|
if (!bHorz)
|
|
rc.OffsetRect(0, nAlign - rc.top - 2);
|
|
else if (m_nDockBarID == AFX_IDW_DOCKBAR_TOP)
|
|
rc.OffsetRect(nAlign - rc.left, -2);
|
|
else
|
|
rc.OffsetRect(nAlign - rc.left, 0);
|
|
pBar->MoveWindow(rc);
|
|
bNeedRecalc = TRUE;
|
|
}
|
|
nAlign += (bHorz ? rc.Width() : rc.Height()) - 2;
|
|
}
|
|
|
|
if (bNeedRecalc)
|
|
m_pDockSite->DelayRecalcLayout();
|
|
}
|
|
|
|
void CSizingControlBar::OnUpdateCmdUI(CFrameWnd* pTarget,
|
|
BOOL bDisableIfNoHndler)
|
|
{
|
|
UNUSED_ALWAYS(bDisableIfNoHndler);
|
|
UNUSED_ALWAYS(pTarget);
|
|
}
|
|
|
|
void CSizingControlBar::LoadState(LPCTSTR lpszProfileName)
|
|
{
|
|
ASSERT_VALID(this);
|
|
ASSERT(GetSafeHwnd()); // must be called after Create()
|
|
|
|
#if defined(_SCB_REPLACE_MINIFRAME) && !defined(_SCB_MINIFRAME_CAPTION)
|
|
// compensate the caption miscalculation in CFrameWnd::SetDockState()
|
|
CDockState state;
|
|
state.LoadState(lpszProfileName);
|
|
|
|
UINT nID = GetDlgCtrlID();
|
|
for (int i = 0; i < state.m_arrBarInfo.GetSize(); i++)
|
|
{
|
|
CControlBarInfo* pInfo = (CControlBarInfo*)state.m_arrBarInfo[i];
|
|
ASSERT(pInfo != NULL);
|
|
if (!pInfo->m_bFloating)
|
|
continue;
|
|
|
|
// this is a floating dockbar - check the ID array
|
|
for (int j = 0; j < pInfo->m_arrBarID.GetSize(); j++)
|
|
if ((DWORD) pInfo->m_arrBarID[j] == nID)
|
|
{
|
|
// found this bar - offset origin and save settings
|
|
pInfo->m_pointPos.x++;
|
|
pInfo->m_pointPos.y +=
|
|
::GetSystemMetrics(SM_CYSMCAPTION) + 1;
|
|
pInfo->SaveState(lpszProfileName, i);
|
|
}
|
|
}
|
|
#endif //_SCB_REPLACE_MINIFRAME && !_SCB_MINIFRAME_CAPTION
|
|
|
|
CWinApp* pApp = AfxGetApp();
|
|
|
|
TCHAR szSection[256];
|
|
wsprintf(szSection, _T("%s-SCBar-%d"), lpszProfileName,
|
|
GetDlgCtrlID());
|
|
|
|
m_szHorz.cx = max(m_szMinHorz.cx, (int) pApp->GetProfileInt(
|
|
szSection, _T("sizeHorzCX"), m_szHorz.cx));
|
|
m_szHorz.cy = max(m_szMinHorz.cy, (int) pApp->GetProfileInt(
|
|
szSection, _T("sizeHorzCY"), m_szHorz.cy));
|
|
|
|
m_szVert.cx = max(m_szMinVert.cx, (int) pApp->GetProfileInt(
|
|
szSection, _T("sizeVertCX"), m_szVert.cx));
|
|
m_szVert.cy = max(m_szMinVert.cy, (int) pApp->GetProfileInt(
|
|
szSection, _T("sizeVertCY"), m_szVert.cy));
|
|
|
|
m_szFloat.cx = max(m_szMinFloat.cx, (int) pApp->GetProfileInt(
|
|
szSection, _T("sizeFloatCX"), m_szFloat.cx));
|
|
m_szFloat.cy = max(m_szMinFloat.cy, (int) pApp->GetProfileInt(
|
|
szSection, _T("sizeFloatCY"), m_szFloat.cy));
|
|
}
|
|
|
|
void CSizingControlBar::SaveState(LPCTSTR lpszProfileName)
|
|
{
|
|
// place your SaveState or GlobalSaveState call in
|
|
// CMainFrame's OnClose() or DestroyWindow(), not in OnDestroy()
|
|
ASSERT_VALID(this);
|
|
ASSERT(GetSafeHwnd());
|
|
|
|
CWinApp* pApp = AfxGetApp();
|
|
|
|
TCHAR szSection[256];
|
|
wsprintf(szSection, _T("%s-SCBar-%d"), lpszProfileName,
|
|
GetDlgCtrlID());
|
|
|
|
pApp->WriteProfileInt(szSection, _T("sizeHorzCX"), m_szHorz.cx);
|
|
pApp->WriteProfileInt(szSection, _T("sizeHorzCY"), m_szHorz.cy);
|
|
|
|
pApp->WriteProfileInt(szSection, _T("sizeVertCX"), m_szVert.cx);
|
|
pApp->WriteProfileInt(szSection, _T("sizeVertCY"), m_szVert.cy);
|
|
|
|
pApp->WriteProfileInt(szSection, _T("sizeFloatCX"), m_szFloat.cx);
|
|
pApp->WriteProfileInt(szSection, _T("sizeFloatCY"), m_szFloat.cy);
|
|
}
|
|
|
|
void CSizingControlBar::GlobalLoadState(CFrameWnd* pFrame,
|
|
LPCTSTR lpszProfileName)
|
|
{
|
|
POSITION pos = pFrame->m_listControlBars.GetHeadPosition();
|
|
while (pos != NULL)
|
|
{
|
|
CSizingControlBar* pBar =
|
|
(CSizingControlBar*) pFrame->m_listControlBars.GetNext(pos);
|
|
ASSERT(pBar != NULL);
|
|
if (pBar->IsKindOf(RUNTIME_CLASS(CSizingControlBar)))
|
|
pBar->LoadState(lpszProfileName);
|
|
}
|
|
}
|
|
|
|
void CSizingControlBar::GlobalSaveState(CFrameWnd* pFrame,
|
|
LPCTSTR lpszProfileName)
|
|
{
|
|
POSITION pos = pFrame->m_listControlBars.GetHeadPosition();
|
|
while (pos != NULL)
|
|
{
|
|
CSizingControlBar* pBar =
|
|
(CSizingControlBar*) pFrame->m_listControlBars.GetNext(pos);
|
|
ASSERT(pBar != NULL);
|
|
if (pBar->IsKindOf(RUNTIME_CLASS(CSizingControlBar)))
|
|
pBar->SaveState(lpszProfileName);
|
|
}
|
|
}
|
|
|
|
#ifdef _SCB_REPLACE_MINIFRAME
|
|
#ifndef _SCB_MINIFRAME_CAPTION
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CSCBDockContext Drag Operations
|
|
|
|
static void 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);
|
|
}
|
|
|
|
void CSCBDockContext::StartDrag(CPoint pt)
|
|
{
|
|
ASSERT_VALID(m_pBar);
|
|
m_bDragging = TRUE;
|
|
|
|
InitLoop();
|
|
|
|
ASSERT((m_pBar->m_dwStyle & CBRS_SIZE_DYNAMIC) != 0);
|
|
|
|
// get true bar size (including borders)
|
|
CRect rect;
|
|
m_pBar->GetWindowRect(rect);
|
|
m_ptLast = pt;
|
|
CSize sizeHorz = m_pBar->CalcDynamicLayout(0, LM_HORZ | LM_HORZDOCK);
|
|
CSize sizeVert = m_pBar->CalcDynamicLayout(0, LM_VERTDOCK);
|
|
CSize sizeFloat = m_pBar->CalcDynamicLayout(0, LM_HORZ | LM_MRUWIDTH);
|
|
|
|
m_rectDragHorz = CRect(rect.TopLeft(), sizeHorz);
|
|
m_rectDragVert = CRect(rect.TopLeft(), sizeVert);
|
|
|
|
// calculate frame dragging rectangle
|
|
m_rectFrameDragHorz = CRect(rect.TopLeft(), sizeFloat);
|
|
|
|
#ifdef _MAC
|
|
CMiniFrameWnd::CalcBorders(&m_rectFrameDragHorz,
|
|
WS_THICKFRAME, WS_EX_FORCESIZEBOX);
|
|
#else
|
|
CMiniFrameWnd::CalcBorders(&m_rectFrameDragHorz, WS_THICKFRAME);
|
|
#endif
|
|
m_rectFrameDragHorz.DeflateRect(2, 2);
|
|
m_rectFrameDragVert = m_rectFrameDragHorz;
|
|
|
|
// adjust rectangles so that point is inside
|
|
AdjustRectangle(m_rectDragHorz, pt);
|
|
AdjustRectangle(m_rectDragVert, pt);
|
|
AdjustRectangle(m_rectFrameDragHorz, pt);
|
|
AdjustRectangle(m_rectFrameDragVert, pt);
|
|
|
|
// initialize tracking state and enter tracking loop
|
|
m_dwOverDockStyle = CanDock();
|
|
Move(pt); // call it here to handle special keys
|
|
Track();
|
|
}
|
|
#endif //_SCB_MINIFRAME_CAPTION
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CSCBMiniDockFrameWnd
|
|
|
|
IMPLEMENT_DYNCREATE(CSCBMiniDockFrameWnd, baseCSCBMiniDockFrameWnd);
|
|
|
|
BEGIN_MESSAGE_MAP(CSCBMiniDockFrameWnd, baseCSCBMiniDockFrameWnd)
|
|
//{{AFX_MSG_MAP(CSCBMiniDockFrameWnd)
|
|
ON_WM_NCLBUTTONDOWN()
|
|
ON_WM_GETMINMAXINFO()
|
|
ON_WM_WINDOWPOSCHANGING()
|
|
ON_WM_SIZE()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
BOOL CSCBMiniDockFrameWnd::Create(CWnd* pParent, DWORD dwBarStyle)
|
|
{
|
|
// set m_bInRecalcLayout to avoid flashing during creation
|
|
// RecalcLayout will be called once something is docked
|
|
m_bInRecalcLayout = TRUE;
|
|
|
|
DWORD dwStyle = WS_POPUP|WS_CAPTION|WS_SYSMENU|MFS_MOVEFRAME|
|
|
MFS_4THICKFRAME|MFS_SYNCACTIVE|MFS_BLOCKSYSMENU|
|
|
FWS_SNAPTOBARS;
|
|
|
|
if (dwBarStyle & CBRS_SIZE_DYNAMIC)
|
|
dwStyle &= ~MFS_MOVEFRAME;
|
|
|
|
DWORD dwExStyle = 0;
|
|
#ifdef _MAC
|
|
if (dwBarStyle & CBRS_SIZE_DYNAMIC)
|
|
dwExStyle |= WS_EX_FORCESIZEBOX;
|
|
else
|
|
dwStyle &= ~(MFS_MOVEFRAME|MFS_4THICKFRAME);
|
|
#endif
|
|
|
|
if (!CMiniFrameWnd::CreateEx(dwExStyle,
|
|
NULL, &afxChNil, dwStyle, rectDefault, pParent))
|
|
{
|
|
m_bInRecalcLayout = FALSE;
|
|
return FALSE;
|
|
}
|
|
dwStyle = dwBarStyle & (CBRS_ALIGN_LEFT|CBRS_ALIGN_RIGHT) ?
|
|
CBRS_ALIGN_LEFT : CBRS_ALIGN_TOP;
|
|
dwStyle |= dwBarStyle & CBRS_FLOAT_MULTI;
|
|
CMenu* pSysMenu = GetSystemMenu(FALSE);
|
|
//pSysMenu->DeleteMenu(SC_SIZE, MF_BYCOMMAND);
|
|
CString strHide;
|
|
if (strHide.LoadString(AFX_IDS_HIDE))
|
|
{
|
|
pSysMenu->DeleteMenu(SC_CLOSE, MF_BYCOMMAND);
|
|
pSysMenu->AppendMenu(MF_STRING|MF_ENABLED, SC_CLOSE, strHide);
|
|
}
|
|
|
|
// must initially create with parent frame as parent
|
|
if (!m_wndDockBar.Create(pParent, WS_CHILD | WS_VISIBLE | dwStyle,
|
|
AFX_IDW_DOCKBAR_FLOAT))
|
|
{
|
|
m_bInRecalcLayout = FALSE;
|
|
return FALSE;
|
|
}
|
|
|
|
// set parent to CMiniDockFrameWnd
|
|
m_wndDockBar.SetParent(this);
|
|
m_bInRecalcLayout = FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CSCBMiniDockFrameWnd::OnNcLButtonDown(UINT nHitTest, CPoint point)
|
|
{
|
|
if (nHitTest == HTCAPTION || nHitTest == HTCLOSE)
|
|
{
|
|
baseCSCBMiniDockFrameWnd::OnNcLButtonDown(nHitTest, point);
|
|
return;
|
|
}
|
|
|
|
if (GetSizingControlBar() != NULL)
|
|
CMiniFrameWnd::OnNcLButtonDown(nHitTest, point);
|
|
else
|
|
baseCSCBMiniDockFrameWnd::OnNcLButtonDown(nHitTest, point);
|
|
}
|
|
|
|
CSizingControlBar* CSCBMiniDockFrameWnd::GetSizingControlBar()
|
|
{
|
|
CWnd* pWnd = GetWindow(GW_CHILD); // get the dockbar
|
|
if (pWnd == NULL)
|
|
return NULL;
|
|
|
|
pWnd = pWnd->GetWindow(GW_CHILD); // get the controlbar
|
|
if (pWnd == NULL)
|
|
return NULL;
|
|
|
|
if (!pWnd->IsKindOf(RUNTIME_CLASS(CSizingControlBar)))
|
|
return NULL;
|
|
|
|
return (CSizingControlBar*) pWnd;
|
|
}
|
|
|
|
void CSCBMiniDockFrameWnd::OnSize(UINT nType, int cx, int cy)
|
|
{
|
|
CSizingControlBar* pBar = GetSizingControlBar();
|
|
if ((pBar != NULL) && (GetStyle() & MFS_4THICKFRAME) == 0
|
|
&& pBar->IsVisible())
|
|
pBar->m_szFloat = CSize(cx + 4, cy + 4);
|
|
|
|
baseCSCBMiniDockFrameWnd::OnSize(nType, cx, cy);
|
|
}
|
|
|
|
void CSCBMiniDockFrameWnd::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
|
|
{
|
|
baseCSCBMiniDockFrameWnd::OnGetMinMaxInfo(lpMMI);
|
|
|
|
CSizingControlBar* pBar = GetSizingControlBar();
|
|
if (pBar != NULL)
|
|
{
|
|
CRect r(CPoint(0, 0), pBar->m_szMinFloat - CSize(4, 4));
|
|
#ifndef _SCB_MINIFRAME_CAPTION
|
|
CMiniFrameWnd::CalcBorders(&r, WS_THICKFRAME);
|
|
#else
|
|
CMiniFrameWnd::CalcBorders(&r, WS_THICKFRAME|WS_CAPTION);
|
|
#endif //_SCB_MINIFRAME_CAPTION
|
|
lpMMI->ptMinTrackSize.x = r.Width();
|
|
lpMMI->ptMinTrackSize.y = r.Height();
|
|
}
|
|
}
|
|
|
|
void CSCBMiniDockFrameWnd::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos)
|
|
{
|
|
if ((GetStyle() & MFS_4THICKFRAME) != 0)
|
|
{
|
|
CSizingControlBar* pBar = GetSizingControlBar();
|
|
if (pBar != NULL)
|
|
{
|
|
lpwndpos->flags |= SWP_NOSIZE; // don't size this time
|
|
// prevents flicker
|
|
pBar->m_pDockBar->ModifyStyle(0, WS_CLIPCHILDREN);
|
|
// enable diagonal resizing
|
|
ModifyStyle(MFS_4THICKFRAME, 0);
|
|
#ifndef _SCB_MINIFRAME_CAPTION
|
|
// remove caption
|
|
ModifyStyle(WS_SYSMENU|WS_CAPTION, 0);
|
|
#endif
|
|
DelayRecalcLayout();
|
|
pBar->PostMessage(WM_NCPAINT);
|
|
}
|
|
}
|
|
|
|
CMiniFrameWnd::OnWindowPosChanging(lpwndpos);
|
|
}
|
|
|
|
#endif //_SCB_REPLACE_MINIFRAME
|