2681 lines
71 KiB
C++
2681 lines
71 KiB
C++
// ===================================================================================
|
|
// Class Implementation : COXSizeDockBar
|
|
// ===================================================================================
|
|
|
|
// Header file : OXSizeDockBar.cpp
|
|
|
|
// Version: 9.3
|
|
|
|
// This software along with its related components, documentation and files ("The Libraries")
|
|
// is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
|
|
// governed by a software license agreement ("Agreement"). Copies of the Agreement are
|
|
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
|
|
// to obtain this file, or directly from our office. For a copy of the license governing
|
|
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
|
|
// Some portions Copyright (C)1994-5 Micro Focus Inc, 2465 East Bayshore Rd, Palo Alto, CA 94303.
|
|
|
|
// //////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include <afxole.h>
|
|
|
|
|
|
#ifndef __OXMFCIMPL_H__
|
|
#if _MFC_VER >= 0x0700
|
|
#if _MFC_VER >= 1400
|
|
#include <afxtempl.h>
|
|
#endif
|
|
#include <..\src\mfc\afximpl.h>
|
|
#else
|
|
#include <..\src\afximpl.h>
|
|
#endif
|
|
#define __OXMFCIMPL_H__
|
|
#endif
|
|
|
|
#pragma warning(disable : 4355)
|
|
|
|
#include "OXSplitterRect.h" // used class specification
|
|
#include "OXRectTracker.h" // used class specification
|
|
#include "OXSizeCtrlBar.h" // used class specification
|
|
#include "OXSizeToolBar.h" // used class specification
|
|
|
|
#include "OXSizeDockBar.h" // this class specification
|
|
#include "OXSkins.h"
|
|
#include "OXMenuBar.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char BASED_CODE THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
IMPLEMENT_DYNAMIC(COXSizeDockBar, CDockBar)
|
|
|
|
#define new DEBUG_NEW
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Definition of static members
|
|
|
|
// Data members -------------------------------------------------------------
|
|
// protected:
|
|
|
|
// private:
|
|
|
|
// Member functions ---------------------------------------------------------
|
|
// public:
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CDockBar layout
|
|
|
|
const int IDC_DOCKTAB = 3000;
|
|
|
|
// helper which can acts on any array of windows
|
|
CControlBar* GetDockedControlBar(int nPos, const CPtrArray& arrBars)
|
|
{
|
|
CControlBar* pResult = (CControlBar*)arrBars[nPos];
|
|
if (HIWORD(pResult) == 0)
|
|
return NULL;
|
|
if(pResult!=NULL && !::IsWindow(pResult->m_hWnd))
|
|
return NULL;
|
|
return pResult;
|
|
}
|
|
|
|
COXSizeDockBar::COXSizeDockBar()
|
|
: m_hcurSizeNS(NULL),
|
|
m_hcurSizeWE(NULL),
|
|
m_pSplitCapture(NULL),
|
|
m_hcurLast(NULL),
|
|
m_LayoutSize(0xffff,0xffff), // some values to force automatic resize
|
|
m_CountBars(0),
|
|
m_pDockbarSkin(NULL),
|
|
m_wndDockTabCtrl(this)
|
|
{
|
|
}
|
|
|
|
|
|
COXSizeDockBar::~COXSizeDockBar()
|
|
{
|
|
// delete any outstanding splitter rects
|
|
DeleteSplitterRects();
|
|
|
|
// delete the classic skin
|
|
if (m_pDockbarSkin != NULL)
|
|
delete m_pDockbarSkin;
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(COXSizeDockBar, CDockBar)
|
|
//{{AFX_MSG_MAP(COXSizeDockBar)
|
|
ON_WM_PAINT()
|
|
ON_WM_MOUSEMOVE()
|
|
ON_WM_LBUTTONDOWN()
|
|
ON_WM_LBUTTONUP()
|
|
ON_WM_SETCURSOR()
|
|
ON_WM_NCPAINT()
|
|
ON_WM_CREATE()
|
|
ON_WM_SIZE()
|
|
ON_WM_ERASEBKGND()
|
|
//}}AFX_MSG_MAP
|
|
ON_MESSAGE(WM_SIZEPARENT, OnSizeParent)
|
|
END_MESSAGE_MAP()
|
|
|
|
|
|
#ifdef _DEBUG
|
|
void DumpArrayBars(CDumpContext& dc, const CPtrArray& arrBars)
|
|
{
|
|
for (int nPos = 0; nPos < arrBars.GetSize(); nPos++)
|
|
{
|
|
LPVOID pVoid = arrBars[nPos];
|
|
dc << _T(" [") << nPos << _T("]") << pVoid;
|
|
CControlBar* pBar = ::GetDockedControlBar(nPos, arrBars);
|
|
if (pBar!=NULL && ::IsWindow(pBar->GetSafeHwnd()))
|
|
{
|
|
CString strTitle;
|
|
pBar->GetWindowText(strTitle);
|
|
dc << _T(" ") << strTitle;
|
|
if (!pBar->IsVisible())
|
|
{
|
|
dc << _T(" hidden");
|
|
}
|
|
}
|
|
dc << _T("\n");
|
|
}
|
|
}
|
|
|
|
|
|
void COXSizeDockBar::Dump( CDumpContext& dc ) const
|
|
{
|
|
CDockBar::Dump(dc);
|
|
DumpArrayBars(dc, m_arrBars);
|
|
|
|
// now go through the splitter array.
|
|
int nDepth = dc.GetDepth();
|
|
dc.SetDepth(1);
|
|
m_SplitArr.Dump(dc);
|
|
dc.SetDepth(nDepth);
|
|
}
|
|
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// COXSizeDockBar message handlers
|
|
|
|
// most of this code is copied from MFC CDockBar - with additional comments to help
|
|
// my understanding of it. The basic idea is that our DockBar is being asked how big
|
|
// it is. To find out, it looks at the bars inside it
|
|
CSize COXSizeDockBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
|
|
{
|
|
ASSERT_VALID(this);
|
|
|
|
CSize sizeFixed = CControlBar::CalcFixedLayout(bStretch, bHorz);
|
|
if(m_arrBars.GetSize()<=1)
|
|
{
|
|
return sizeFixed;
|
|
}
|
|
|
|
// ID for this bar...used to set MRU docked position
|
|
UINT uDockBarID = PtrToUint(::GetWindowLongPtr(m_hWnd, GWL_ID));
|
|
|
|
// prepare for layout
|
|
AFX_SIZEPARENTPARAMS layout;
|
|
layout.hDWP= (m_bLayoutQuery)? NULL : ::BeginDeferWindowPos(PtrToInt(m_arrBars.GetSize()));
|
|
|
|
CPoint pt(-afxData.cxBorder2, -afxData.cyBorder2);
|
|
|
|
// get max size
|
|
CSize sizeMax;
|
|
if (!m_rectLayout.IsRectEmpty())
|
|
{
|
|
sizeMax = m_rectLayout.Size();
|
|
}
|
|
else
|
|
{
|
|
CRect rectFrame;
|
|
CFrameWnd* pFrame = GetParentFrame();
|
|
pFrame->GetClientRect(rectFrame);
|
|
pFrame->ClientToScreen(rectFrame);
|
|
|
|
for(int nID = AFX_IDW_CONTROLBAR_FIRST; nID<=AFX_IDW_CONTROLBAR_LAST; nID++)
|
|
{
|
|
CControlBar* pBar=m_pDockSite->GetControlBar(nID);
|
|
|
|
if(pBar!=NULL && pBar->IsDockBar() &&
|
|
pBar->IsVisible() && !pBar->IsFloating())
|
|
{
|
|
CRect rectBar;
|
|
pBar->GetWindowRect(rectBar);
|
|
if(pBar->GetStyle() & CBRS_TOP)
|
|
{
|
|
rectFrame.top=__max(rectFrame.top,rectBar.bottom);
|
|
}
|
|
else if(pBar->GetStyle() & CBRS_BOTTOM)
|
|
{
|
|
rectFrame.bottom=__min(rectFrame.bottom,rectBar.top);
|
|
}
|
|
}
|
|
}
|
|
|
|
sizeMax = rectFrame.Size();
|
|
}
|
|
|
|
// true if we should draw a bar for this row
|
|
BOOL bDrawBarForRow = FALSE;
|
|
|
|
DeleteSplitterRects(); // clear the splitter rects
|
|
int nWidth = 0;
|
|
int nFirstSplitterInRow = 0;
|
|
int nFirstPaneInRow = 0;
|
|
BOOL bFirstPaneInRow = TRUE;
|
|
|
|
int nCountSizeBars = 0;
|
|
BOOL bLastWasResizable=FALSE;
|
|
|
|
BOOL bWrapped = FALSE;
|
|
|
|
// layout all the control bars
|
|
int nLastVisSep = -1;
|
|
for (int nPos = 0; nPos < m_arrBars.GetSize(); nPos++)
|
|
{
|
|
void* pVoid = m_arrBars[nPos];
|
|
CControlBar* pBar = GetDockedControlBar(nPos);
|
|
if (pVoid != NULL)
|
|
{
|
|
if (pBar!=NULL && ::IsWindow(pBar->GetSafeHwnd()) && pBar->IsVisible())
|
|
{
|
|
BOOL bSomeToolBar = (BOOL) (((CControlBar*)pBar)->
|
|
IsKindOf(RUNTIME_CLASS(COXSizeToolBar)));
|
|
|
|
if (bFirstPaneInRow)
|
|
{
|
|
bFirstPaneInRow = FALSE;
|
|
// remember where the first pane in the row is..
|
|
nFirstPaneInRow = nPos;
|
|
|
|
if (m_dwStyle & (CBRS_ALIGN_BOTTOM | CBRS_ALIGN_RIGHT))
|
|
{
|
|
bDrawBarForRow = IsRowSizeable(nPos) && !bSomeToolBar;
|
|
}
|
|
|
|
if (bDrawBarForRow)
|
|
{
|
|
if (bHorz)
|
|
{
|
|
AddSplitterRect(SPLITTER_HORZ, pt.x, pt.y, 0 ,
|
|
pt.y + CY_SPLIT, nPos); // width set at end
|
|
pt.y += CY_SPLIT;
|
|
}
|
|
else
|
|
{
|
|
AddSplitterRect(SPLITTER_VERT, pt.x, pt.y,
|
|
pt.x + CX_SPLIT, 0, nPos); // height set at end
|
|
pt.x += CX_SPLIT;
|
|
}
|
|
bDrawBarForRow = FALSE;
|
|
}
|
|
}
|
|
|
|
// draw a bar between 2 previous
|
|
if (bLastWasResizable && IsSizeable(pBar)&!bSomeToolBar)
|
|
{
|
|
if (bHorz)
|
|
{
|
|
// width set at end of row
|
|
AddSplitterRect(SPLITTER_VERT, pt.x, pt.y,
|
|
pt.x + CX_SPLIT, 0, nPos);
|
|
pt.x += CX_SPLIT;
|
|
}
|
|
else
|
|
{
|
|
// width set at end of row
|
|
AddSplitterRect(SPLITTER_HORZ, pt.x, pt.y, 0,
|
|
pt.y + CY_SPLIT, nPos);
|
|
pt.y += CY_SPLIT;
|
|
}
|
|
}
|
|
|
|
// if the bar is sizeable, then we'll need a sizer after it
|
|
if (IsSizeable(pBar))
|
|
{
|
|
bDrawBarForRow|=!bSomeToolBar;
|
|
}
|
|
|
|
// get ideal rect for bar to be docked
|
|
DWORD dwMode = 0;
|
|
if ((pBar->m_dwStyle & CBRS_SIZE_DYNAMIC) &&
|
|
(pBar->m_dwStyle & CBRS_FLOATING))
|
|
dwMode |= LM_HORZ | LM_MRUWIDTH;
|
|
else if (pBar->m_dwStyle & CBRS_ORIENT_HORZ)
|
|
dwMode |= LM_HORZ | LM_HORZDOCK;
|
|
else
|
|
dwMode |= LM_VERTDOCK;
|
|
|
|
CSize sizeBar = pBar->CalcDynamicLayout(-1, dwMode);
|
|
CRect rect(pt, sizeBar);
|
|
|
|
// get current rect for bar to be docked
|
|
CRect rectBar;
|
|
pBar->GetWindowRect(&rectBar);
|
|
ScreenToClient(&rectBar);
|
|
|
|
if (bHorz)
|
|
{
|
|
if(IsSizeable(pBar) && !bSomeToolBar)
|
|
{
|
|
// This is a control bar
|
|
|
|
// If ControlBar has been wrapped, then left justify
|
|
if (bWrapped)
|
|
{
|
|
bWrapped = FALSE;
|
|
rect.OffsetRect(-(rect.left + afxData.cxBorder2), 0);
|
|
}
|
|
else if(rect.left>=sizeMax.cx-afxData.cxBorder2 ||
|
|
rectBar.right<=rectBar.left || rectBar.right<=0)
|
|
{
|
|
if(nFirstPaneInRow==nPos)
|
|
{
|
|
m_arrBars.InsertAt(nPos+1, (CObject*)NULL);
|
|
AdjustRowSizes(nPos,sizeMax.cx,m_arrBars);
|
|
AdjustRowSizes(nPos+2,sizeMax.cx,m_arrBars);
|
|
pBar = NULL;
|
|
pVoid = NULL;
|
|
bWrapped = TRUE;
|
|
nPos--;
|
|
}
|
|
else
|
|
{
|
|
m_arrBars.InsertAt(nPos, (CObject*)NULL);
|
|
AdjustRowSizes(nPos+1,sizeMax.cx,m_arrBars);
|
|
pBar = NULL;
|
|
pVoid = NULL;
|
|
bWrapped = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else // this is a toolbar
|
|
{
|
|
// Offset Calculated Rect out to Actual
|
|
if (rectBar.left > rect.left && !m_bFloating)
|
|
{
|
|
if(!bLastWasResizable && nCountSizeBars==0)
|
|
rect.OffsetRect(rectBar.left - rect.left, 0);
|
|
}
|
|
|
|
// If ControlBar goes off the right, then right justify
|
|
if (rect.right > sizeMax.cx && !m_bFloating)
|
|
{
|
|
int x = rect.Width() - afxData.cxBorder2;
|
|
x = max(sizeMax.cx - x, pt.x);
|
|
rect.OffsetRect(x - rect.left, 0);
|
|
}
|
|
|
|
// If ControlBar has been wrapped, then left justify
|
|
if (bWrapped)
|
|
{
|
|
bWrapped = FALSE;
|
|
rect.OffsetRect(-(rect.left + afxData.cxBorder2), 0);
|
|
}
|
|
// If ControlBar is completely invisible, then wrap it
|
|
else if ((rect.left >= (sizeMax.cx - afxData.cxBorder2)) &&
|
|
(nPos > 0) && (m_arrBars[nPos - 1] != NULL))
|
|
{
|
|
m_arrBars.InsertAt(nPos, (CObject*)NULL);
|
|
pBar = NULL; pVoid = NULL;
|
|
bWrapped = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!bWrapped)
|
|
{
|
|
if (rect != rectBar)
|
|
{
|
|
if (!m_bLayoutQuery &&
|
|
!(pBar->m_dwStyle & CBRS_FLOATING))
|
|
{
|
|
pBar->m_pDockContext->m_rectMRUDockPos = rect;
|
|
}
|
|
AfxRepositionWindow(&layout, pBar->m_hWnd, &rect);
|
|
}
|
|
pt.x = rect.left + sizeBar.cx - afxData.cxBorder2;
|
|
nWidth = max(nWidth, sizeBar.cy);
|
|
}
|
|
}
|
|
else // vertical
|
|
{
|
|
if(IsSizeable(pBar) && !bSomeToolBar)
|
|
{
|
|
// If ControlBar has been wrapped, then top justify
|
|
if (bWrapped)
|
|
{
|
|
bWrapped = FALSE;
|
|
rect.OffsetRect(0, -(rect.top + afxData.cyBorder2));
|
|
}
|
|
else if(rect.top>=sizeMax.cy-afxData.cyBorder2 ||
|
|
rectBar.bottom<=rectBar.top || rectBar.bottom<=0)
|
|
{
|
|
if(nFirstPaneInRow==nPos)
|
|
{
|
|
m_arrBars.InsertAt(nPos+1, (CObject*)NULL);
|
|
AdjustRowSizes(nPos,sizeMax.cy,m_arrBars);
|
|
AdjustRowSizes(nPos+2,sizeMax.cy,m_arrBars);
|
|
pBar = NULL;
|
|
pVoid = NULL;
|
|
bWrapped = TRUE;
|
|
nPos--;
|
|
}
|
|
else
|
|
{
|
|
m_arrBars.InsertAt(nPos, (CObject*)NULL);
|
|
AdjustRowSizes(nPos+1,sizeMax.cy,m_arrBars);
|
|
pBar = NULL;
|
|
pVoid = NULL;
|
|
bWrapped = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Offset Calculated Rect out to Actual
|
|
if (rectBar.top > rect.top && !m_bFloating)
|
|
{
|
|
if(!bLastWasResizable && nCountSizeBars==0)
|
|
rect.OffsetRect(0, rectBar.top - rect.top);
|
|
}
|
|
|
|
// If ControlBar goes off the bottom, then bottom justify
|
|
if (rect.bottom > sizeMax.cy && !m_bFloating)
|
|
{
|
|
int y = rect.Height() - afxData.cyBorder2;
|
|
y = max(sizeMax.cy - y, pt.y);
|
|
rect.OffsetRect(0, y - rect.top);
|
|
}
|
|
|
|
// If ControlBar has been wrapped, then top justify
|
|
if (bWrapped)
|
|
{
|
|
bWrapped = FALSE;
|
|
rect.OffsetRect(0, -(rect.top + afxData.cyBorder2));
|
|
}
|
|
// If ControlBar is completely invisible, then wrap it
|
|
else if ((rect.top >= (sizeMax.cy - afxData.cyBorder2)) &&
|
|
(nPos > 0) && (m_arrBars[nPos - 1] != NULL))
|
|
{
|
|
m_arrBars.InsertAt(nPos, (CObject*)NULL);
|
|
pBar = NULL; pVoid = NULL;
|
|
bWrapped = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!bWrapped)
|
|
{
|
|
if (rect != rectBar)
|
|
{
|
|
if (!m_bLayoutQuery &&
|
|
!(pBar->m_dwStyle & CBRS_FLOATING))
|
|
{
|
|
pBar->m_pDockContext->m_rectMRUDockPos = rect;
|
|
}
|
|
AfxRepositionWindow(&layout, pBar->m_hWnd, &rect);
|
|
}
|
|
pt.y = rect.top + sizeBar.cy - afxData.cyBorder2;
|
|
nWidth = max(nWidth, sizeBar.cx);
|
|
}
|
|
}
|
|
|
|
/////////////////////////
|
|
if(pBar!=NULL)
|
|
{
|
|
// repositioned the bar, so update the MRU dock position.
|
|
CDockContext* pDockContext = pBar->m_pDockContext;
|
|
ASSERT(pDockContext != NULL);
|
|
if (pDockContext != NULL)
|
|
{
|
|
pDockContext->m_rectMRUDockPos = rect;
|
|
pDockContext->m_uMRUDockID = uDockBarID;
|
|
}
|
|
|
|
// handle any delay/show hide for the bar
|
|
pBar->RecalcDelayShow(&layout);
|
|
|
|
bLastWasResizable=IsSizeable(pBar)&!bSomeToolBar;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nCountSizeBars=0;
|
|
// calculate the number of sizable bars in the row
|
|
for (int nPos2 = nPos + 1; nPos2 < m_arrBars.GetSize(); nPos2++)
|
|
{
|
|
void* pVoid = m_arrBars[nPos2];
|
|
CControlBar* pBar = GetDockedControlBar(nPos2);
|
|
if (pVoid == NULL)
|
|
break; // end of row
|
|
|
|
if (pBar!=NULL && ::IsWindow(pBar->GetSafeHwnd()) &&
|
|
pBar->IsVisible())
|
|
{
|
|
if (IsSizeable(pBar) && !((CControlBar*)pBar)->
|
|
IsKindOf(RUNTIME_CLASS(COXSizeToolBar)))
|
|
{
|
|
nCountSizeBars++;
|
|
}
|
|
}
|
|
}
|
|
////////////////////////////////////
|
|
if (!bFirstPaneInRow) // FALSE if we've hit anything....
|
|
{
|
|
// end of row because pBar == NULL
|
|
if (bHorz)
|
|
{
|
|
pt.y += nWidth - afxData.cyBorder2;
|
|
sizeFixed.cx = __max(sizeFixed.cx, pt.x);
|
|
sizeFixed.cy = __max(sizeFixed.cy, pt.y);
|
|
pt.x = -afxData.cxBorder2;
|
|
SetSplitterSizeInRange(nFirstSplitterInRow, SPLITTER_VERT, pt.y);
|
|
}
|
|
else
|
|
{
|
|
pt.x += nWidth - afxData.cxBorder2;
|
|
sizeFixed.cx = __max(sizeFixed.cx, pt.x);
|
|
sizeFixed.cy = __max(sizeFixed.cy, pt.y);
|
|
pt.y = -afxData.cyBorder2;
|
|
SetSplitterSizeInRange(nFirstSplitterInRow, SPLITTER_HORZ, pt.x);
|
|
}
|
|
nLastVisSep = nPos; // record separator for last vis position
|
|
}
|
|
|
|
nFirstSplitterInRow = PtrToInt(__max(m_SplitArr.GetSize(), 0));
|
|
nWidth = 0;
|
|
bFirstPaneInRow = TRUE;
|
|
bLastWasResizable=FALSE;
|
|
}
|
|
}
|
|
// special case when bars are at top or left.
|
|
// use of nFirstPaneInRow (nPos where row started) so that sizing code can cope ok
|
|
|
|
if (nFirstPaneInRow != 0 && bDrawBarForRow &&
|
|
(m_dwStyle & (CBRS_ALIGN_TOP | CBRS_ALIGN_LEFT))) // there is at least one pane.
|
|
{
|
|
ASSERT(nLastVisSep != -1);
|
|
if (m_dwStyle & CBRS_ALIGN_TOP)
|
|
{
|
|
AddSplitterRect(SPLITTER_HORZ, pt.x, pt.y, 0 ,
|
|
pt.y + CY_SPLIT, nLastVisSep);
|
|
sizeFixed.cy += CY_SPLIT;
|
|
}
|
|
else
|
|
{
|
|
AddSplitterRect(SPLITTER_VERT, pt.x, pt.y,
|
|
pt.x + CX_SPLIT, 0, nLastVisSep);
|
|
sizeFixed.cx += CX_SPLIT - 1;
|
|
}
|
|
}
|
|
|
|
if (!m_bLayoutQuery)
|
|
{
|
|
// move and resize all the windows at once!
|
|
if (layout.hDWP == NULL || !::EndDeferWindowPos(layout.hDWP))
|
|
{
|
|
TRACE(_T("COXSizeDockBar::CalcFixedLayout: DeferWindowPos failed - low system resources\n"));
|
|
}
|
|
}
|
|
|
|
// Finally go back and set the size of the bars between the rows
|
|
if (bHorz)
|
|
{
|
|
// set widths of inter-rows
|
|
SetSplitterSizeInRange(0, SPLITTER_HORZ, sizeFixed.cx);
|
|
}
|
|
else
|
|
{
|
|
// set heights of inte-rcolumns
|
|
SetSplitterSizeInRange(0, SPLITTER_VERT, sizeFixed.cy);
|
|
}
|
|
|
|
// adjust size for borders on the dock bar itself
|
|
CRect rect;
|
|
rect.SetRectEmpty();
|
|
CalcInsideRect(rect, bHorz);
|
|
|
|
if ((!bStretch || !bHorz) && sizeFixed.cx != 0)
|
|
{
|
|
sizeFixed.cx += -rect.right + rect.left;
|
|
}
|
|
if ((!bStretch || bHorz) && sizeFixed.cy != 0)
|
|
{
|
|
sizeFixed.cy += -rect.bottom + rect.top;
|
|
}
|
|
|
|
// Allocate space for the tab container
|
|
sizeFixed.cy += GetTabHeight();
|
|
return sizeFixed;
|
|
}
|
|
|
|
void COXSizeDockBar::AddSplitterRect(int type, int x1, int y1, int x2, int y2, int nPos)
|
|
{
|
|
COXSplitterRect* pSplit = new COXSplitterRect(type, CRect(x1, y1, x2, y2));
|
|
pSplit->m_nPos = nPos;
|
|
ASSERT( pSplit != NULL);
|
|
m_SplitArr.Add(pSplit);
|
|
}
|
|
|
|
|
|
// helper function: Sets the length of all COXSplitterRects in the range
|
|
// (start->end of array) with the specified type. Used at the end of a row
|
|
// to set all the heights to the calculated width.
|
|
void COXSizeDockBar::SetSplitterSizeInRange(int start, int type, int length)
|
|
{
|
|
ASSERT(type == SPLITTER_VERT || type == SPLITTER_HORZ);
|
|
ASSERT(start >= 0 && start <= m_SplitArr.GetSize());
|
|
|
|
for (int i = PtrToInt(m_SplitArr.GetUpperBound()); i >= start; i--)
|
|
{
|
|
COXSplitterRect* pItem = (COXSplitterRect*)m_SplitArr[i];
|
|
if (pItem->m_type == type)
|
|
{
|
|
if (type == SPLITTER_VERT)
|
|
pItem->m_rect.bottom = length;
|
|
else
|
|
pItem->m_rect.right = length;
|
|
}
|
|
}
|
|
}
|
|
|
|
void COXSizeDockBar::DeleteSplitterRects()
|
|
{
|
|
for (int i = PtrToInt(m_SplitArr.GetUpperBound()); i >= 0 ; i--)
|
|
delete (m_SplitArr[i]);
|
|
m_SplitArr.RemoveAll();
|
|
}
|
|
|
|
void COXSizeDockBar::OnPaint()
|
|
{
|
|
CPaintDC dc(this); // device context for painting
|
|
for(int nIndex=PtrToInt(m_SplitArr.GetUpperBound()); nIndex>=0; nIndex--)
|
|
{
|
|
COXSplitterRect* pSplit=(COXSplitterRect*)m_SplitArr[nIndex];
|
|
GetDockbarSkin()->DrawSplitter(&dc, pSplit, this);
|
|
}
|
|
}
|
|
|
|
BOOL COXSizeDockBar::OnEraseBkgnd(CDC* pDC)
|
|
{
|
|
GetDockbarSkin()->DrawBackground(pDC, this);
|
|
return FALSE;
|
|
}
|
|
|
|
COXSplitterRect* COXSizeDockBar::HitTest(CPoint pt)
|
|
{
|
|
for (int i = PtrToInt(m_SplitArr.GetUpperBound()); i >= 0; i--)
|
|
{
|
|
COXSplitterRect* pSplit = GetSplitter(i);
|
|
if (pSplit->m_rect.PtInRect(pt))
|
|
{
|
|
return(pSplit);
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
BOOL COXSizeDockBar::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
|
|
{
|
|
if(nHitTest==HTCLIENT && pWnd==this) // && !m_bTracking)
|
|
{
|
|
return TRUE; // we will handle it in the mouse move
|
|
}
|
|
|
|
return CDockBar::OnSetCursor(pWnd, nHitTest, message);
|
|
}
|
|
|
|
|
|
|
|
// if already positioned on NULL, go back one further
|
|
int COXSizeDockBar::StartPosOfRow(int nPos)
|
|
{
|
|
if (nPos > 0)
|
|
{
|
|
if (m_arrBars[nPos] == NULL)
|
|
nPos --;
|
|
while (nPos >= 0)
|
|
{
|
|
if (m_arrBars[nPos] == NULL)
|
|
return (nPos + 1);
|
|
nPos --;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// returns strart of previous row.
|
|
// This function includes logic to cope with nPos beyond the end of the array.
|
|
int COXSizeDockBar::StartPosOfPreviousRow(int nPos)
|
|
{
|
|
ASSERT (nPos > 0);
|
|
if (nPos >= m_arrBars.GetUpperBound())
|
|
return (StartPosOfRow(nPos));
|
|
else
|
|
return StartPosOfRow(nPos - 1);
|
|
}
|
|
|
|
|
|
|
|
// Go through control bars in the row.
|
|
// returns the number of sizeable bars in the row, and the total space they currently
|
|
// take up
|
|
void COXSizeDockBar::GetRowSizeInfo(int nPos, ROWSIZEINFO* pRZI,
|
|
const CPtrArray& arrBars)
|
|
{
|
|
BOOL bHorz = IsBarHorizontal();
|
|
|
|
// zero all the fields
|
|
memset (pRZI, 0, sizeof (ROWSIZEINFO));
|
|
|
|
BOOL bLastWasResizable=FALSE;
|
|
while (nPos <= arrBars.GetUpperBound())
|
|
{
|
|
CRect rect;
|
|
void* pVoid = arrBars[nPos];
|
|
if (pVoid == NULL)
|
|
{
|
|
break; // end of the row
|
|
}
|
|
CControlBar* pBar=::GetDockedControlBar(nPos, arrBars);
|
|
if (pBar!= NULL && ::IsWindow(pBar->GetSafeHwnd()) && pBar->IsVisible())
|
|
{
|
|
// add a splitter size
|
|
if((IsSizeable(pBar) &&
|
|
!pBar->IsKindOf(RUNTIME_CLASS(COXSizeToolBar))))
|
|
{
|
|
if(bLastWasResizable)
|
|
pRZI->nFixedWidth += (bHorz ? CX_SPLIT : CY_SPLIT);
|
|
}
|
|
|
|
pBar->GetWindowRect(&rect);
|
|
int nWidth = __max(0, (bHorz ? rect.Width() : rect.Height()) );
|
|
int nHeight = __max(0, (bHorz ? rect.Height() : rect.Width()) );
|
|
|
|
pRZI->nTotalBars ++;
|
|
if(nHeight > pRZI->nMaxHeight)
|
|
{
|
|
pRZI->nMaxHeight = nHeight;
|
|
}
|
|
|
|
MINMAXINFO minmaxInfo={ 0 };
|
|
pBar->SendMessage(WM_GETMINMAXINFO,0,(LPARAM)&minmaxInfo);
|
|
if(pRZI->nMinWidth<minmaxInfo.ptMinTrackSize.x)
|
|
{
|
|
pRZI->nMinWidth=minmaxInfo.ptMinTrackSize.x;
|
|
}
|
|
if(pRZI->nMinHeight<minmaxInfo.ptMinTrackSize.y)
|
|
{
|
|
pRZI->nMinHeight=minmaxInfo.ptMinTrackSize.y;
|
|
}
|
|
|
|
if(IsSizeable(pBar))
|
|
{
|
|
pRZI->nFlexBars ++;
|
|
pRZI->nFlexWidth += nWidth;
|
|
}
|
|
else
|
|
{
|
|
pRZI->nFixedWidth += nWidth;
|
|
if (nHeight > pRZI->nMaxFixedHeight)
|
|
pRZI->nMaxFixedHeight = nHeight;
|
|
}
|
|
bLastWasResizable=IsSizeable(pBar) &&
|
|
!pBar->IsKindOf(RUNTIME_CLASS(COXSizeToolBar));
|
|
}
|
|
nPos++;
|
|
}
|
|
|
|
pRZI->nTotalWidth=pRZI->nFixedWidth+pRZI->nFlexWidth;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// Adjusts the sizes of all the bars on a dockbar to fit a new size
|
|
BOOL COXSizeDockBar::AdjustAllRowSizes(int nNewSize)
|
|
{
|
|
BOOL bAdjusted = FALSE;
|
|
int nPos = 0;
|
|
while (nPos < m_arrBars.GetSize())
|
|
{
|
|
CControlBar* pBar = (CControlBar*)m_arrBars[nPos];
|
|
if (pBar == NULL)
|
|
{
|
|
// skip over NULLs
|
|
nPos++;
|
|
continue;
|
|
}
|
|
|
|
// adjust the sizes on a row
|
|
bAdjusted |= AdjustRowSizes(nPos, nNewSize, m_arrBars);
|
|
// skip to end of row
|
|
while (m_arrBars[nPos] != NULL)
|
|
nPos++;
|
|
}
|
|
return bAdjusted;
|
|
}
|
|
|
|
|
|
// Adjusts the size of a row - returns TRUE if any changes were made
|
|
BOOL COXSizeDockBar::AdjustRowSizes(int nPos, int nNewSize, CPtrArray& arrBars)
|
|
{
|
|
BOOL bHorz = IsBarHorizontal();
|
|
|
|
ROWSIZEINFO RZI;
|
|
GetRowSizeInfo(nPos, &RZI, arrBars);
|
|
if (RZI.nFlexBars == 0)
|
|
return FALSE; // no flexible bars - nothing to do !
|
|
|
|
// prepare for layout
|
|
int nTotalSize = (nNewSize - RZI.nFixedWidth)
|
|
+(bHorz ? afxData.cxBorder2 : afxData.cyBorder2)*RZI.nTotalBars;
|
|
int nSizeRemaining = nTotalSize;
|
|
int nSize=0;
|
|
|
|
// have to apply this size change to the bars on this row. Note: This will work
|
|
// by setting the docked size of the controls bars directly.
|
|
// Then RecalcLayout will do the rest.
|
|
int nCountFlexBars = 0;
|
|
while (TRUE)
|
|
{
|
|
void* pVoid = arrBars[nPos];
|
|
if (pVoid == NULL)
|
|
break; // end of the row, stop
|
|
// note:slight abuse of cast
|
|
COXSizeControlBar* pBar =
|
|
(COXSizeControlBar*)::GetDockedControlBar(nPos, arrBars);
|
|
|
|
if (pBar!=NULL && ::IsWindow(pBar->GetSafeHwnd()) &&
|
|
pBar->IsVisible() && IsSizeable(pBar))
|
|
{
|
|
CRect rect;
|
|
pBar->GetWindowRect(&rect);
|
|
int nWidth = (bHorz ? rect.Width() : rect.Height());
|
|
nCountFlexBars ++;
|
|
if(RZI.nFlexWidth==0)
|
|
nSize = nSizeRemaining;
|
|
else
|
|
nSize = (int)((float)(((nWidth * nTotalSize)) / RZI.nFlexWidth) + (float) 0.5);
|
|
|
|
#ifdef _VERBOSE_TRACE
|
|
CString strTitle;
|
|
pBar->GetWindowText(strTitle);
|
|
TRACE2("New Size : %d on %s\n", nSize, strTitle);
|
|
#endif
|
|
|
|
nSizeRemaining -= nSize;
|
|
|
|
if (bHorz)
|
|
{
|
|
pBar->m_HorzDockSize.cx = nSize;
|
|
pBar->m_HorzDockSize.cy = RZI.nMaxHeight;
|
|
if(!m_bLayoutQuery)
|
|
SetWindowSize(pBar, pBar->m_HorzDockSize);
|
|
}
|
|
else
|
|
{
|
|
pBar->m_VertDockSize.cy = nSize;
|
|
pBar->m_VertDockSize.cx = RZI.nMaxHeight;
|
|
if(!m_bLayoutQuery)
|
|
SetWindowSize(pBar, pBar->m_VertDockSize);
|
|
}
|
|
}
|
|
nPos++;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
// Adjusts the sizes of all the bars on a dockbar to fit a new size
|
|
void COXSizeDockBar::TileDockedBars()
|
|
{
|
|
int nPos = 0;
|
|
while (nPos < m_arrBars.GetSize())
|
|
{
|
|
CControlBar* pBar = (CControlBar*)m_arrBars[nPos];
|
|
if (pBar == NULL)
|
|
{ // skip over NULLs
|
|
nPos ++;
|
|
continue;
|
|
}
|
|
TileDockedBarsRow(nPos); // adjust the sizes on a row
|
|
while (m_arrBars[nPos] != NULL) // skip to end of row
|
|
nPos++;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
// Tiles the docked bars:
|
|
void COXSizeDockBar::TileDockedBarsRow(int nPos)
|
|
{
|
|
BOOL bHorz = IsBarHorizontal();
|
|
|
|
ROWSIZEINFO RZI;
|
|
GetRowSizeInfo(nPos, &RZI, m_arrBars);
|
|
if (RZI.nFlexBars == 0)
|
|
return; // no flexible bars - nothing to do !
|
|
|
|
int nNewSize = (bHorz ? m_LayoutSize.cx : m_LayoutSize.cy);
|
|
int nTotalSize = __max(0, nNewSize - RZI.nFixedWidth);
|
|
int nNewWidth = nTotalSize / RZI.nFlexBars;
|
|
|
|
int nCountFlexBars = 0;
|
|
while(TRUE)
|
|
{
|
|
void* pVoid = m_arrBars[nPos];
|
|
if (pVoid == NULL)
|
|
break; // end of the row, stop
|
|
COXSizeControlBar* pBar = (COXSizeControlBar*)GetDockedControlBar(nPos); // note:slight abuse of cast
|
|
|
|
if (pBar!=NULL && ::IsWindow(pBar->GetSafeHwnd()) &&
|
|
IsSizeable(pBar) && pBar->IsVisible())
|
|
{
|
|
nCountFlexBars ++;
|
|
if (nCountFlexBars == RZI.nFlexBars) // last bar adjust size change
|
|
{
|
|
nNewWidth = nTotalSize - ((RZI.nFlexBars - 1) * nNewWidth);
|
|
}
|
|
if (bHorz)
|
|
{
|
|
pBar->m_HorzDockSize.cx = nNewWidth;
|
|
pBar->m_HorzDockSize.cy = RZI.nMaxHeight;
|
|
}
|
|
else
|
|
{
|
|
pBar->m_VertDockSize.cy = nNewWidth;
|
|
pBar->m_VertDockSize.cx = RZI.nMaxHeight;
|
|
}
|
|
}
|
|
nPos++;
|
|
}
|
|
}
|
|
|
|
// Returns TRUE if BAR is in m_arrInvisibleBars
|
|
BOOL COXSizeDockBar::WasBarHidden(CControlBar* pBar)
|
|
{
|
|
for (int i= 0; i < m_arrHiddenBars.GetSize(); i++)
|
|
{
|
|
if (m_arrHiddenBars[i] == pBar)
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// WM_SIZEPARENT message is sent from CFrameWnd::RepositionBars() to tell the
|
|
// dockbar to calculate it's size. The only reason for intercepting this was
|
|
// to actually find out the size the dockbar is taking up in the layout,
|
|
// so we can opt to re-layout a row to fit the desired size. There might well
|
|
// be a better way of doing this.
|
|
LRESULT COXSizeDockBar::OnSizeParent(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
AFX_SIZEPARENTPARAMS* lpLayout = (AFX_SIZEPARENTPARAMS*)lParam;
|
|
|
|
BOOL bHorz = IsBarHorizontal();
|
|
CRect LayRect;
|
|
LayRect.CopyRect(&lpLayout->rect);
|
|
CSize LaySize = LayRect.Size(); // maximum size available
|
|
LaySize.cy -= GetTabHeight();
|
|
int nLayoutWidth = bHorz ? LaySize.cx : LaySize.cy;
|
|
|
|
BOOL bLayoutWidthChanged=
|
|
(nLayoutWidth != (bHorz ? m_LayoutSize.cx : m_LayoutSize.cy));
|
|
m_LayoutSize = LaySize;
|
|
|
|
// Attempt to detect bars that have changed state from Hidden->Visible.
|
|
// For these we attempt to adjust the other (previously visible) bars on
|
|
// the row so that the newly shown bars restore their previous size.
|
|
|
|
// Bars visible in the row (ones we can shrink)
|
|
CPtrArray arrVisibleBarsInRow;
|
|
int nWidthNeeded = 0;
|
|
int i = 0;
|
|
for (i = 0; i < m_arrBars.GetSize(); i++)
|
|
{
|
|
if (m_arrBars[i] == NULL)
|
|
{
|
|
ROWSIZEINFO RZI;
|
|
if (arrVisibleBarsInRow.GetSize() != 0 && nWidthNeeded != 0)
|
|
{
|
|
arrVisibleBarsInRow.Add(NULL);
|
|
|
|
GetRowSizeInfo(0, &RZI, arrVisibleBarsInRow);
|
|
int nNewWidth = __max(0, RZI.nTotalWidth - nWidthNeeded);
|
|
AdjustRowSizes(0, nNewWidth, arrVisibleBarsInRow);
|
|
}
|
|
nWidthNeeded = 0;
|
|
arrVisibleBarsInRow.RemoveAll();
|
|
}
|
|
else
|
|
{
|
|
CControlBar* pBar = GetDockedControlBar(i);
|
|
if (pBar!=NULL && ::IsWindow(pBar->GetSafeHwnd()))
|
|
{
|
|
if (pBar->IsVisible())
|
|
{
|
|
if (WasBarHidden(pBar))
|
|
{
|
|
TRACE0("Bar hidden->visible\n");
|
|
CRect rect;
|
|
pBar->GetWindowRect(&rect);
|
|
nWidthNeeded += (bHorz ? rect.Width() : rect.Height());
|
|
}
|
|
else
|
|
{
|
|
arrVisibleBarsInRow.Add(pBar); // Track visible bars in this row that we can shrink
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// construct new array of bars that are hidden in this dockbar
|
|
m_arrHiddenBars.RemoveAll();
|
|
for (i = 0; i < m_arrBars.GetSize(); i++)
|
|
{
|
|
CControlBar* pBar = GetDockedControlBar(i);
|
|
if (pBar!=NULL && ::IsWindow(pBar->GetSafeHwnd()) && ! pBar->IsVisible())
|
|
m_arrHiddenBars.Add(pBar);
|
|
}
|
|
|
|
int nCheckSum = CheckSumBars();
|
|
|
|
// any other changes and we size the bars to fit the layout width
|
|
if (bLayoutWidthChanged || nCheckSum != m_CountBars)
|
|
{
|
|
AdjustAllRowSizes(nLayoutWidth);
|
|
m_CountBars = nCheckSum;
|
|
// force redraw of the dock bar - seems a bit of a sledgehammer
|
|
// InvalidateRect(NULL);
|
|
// force redraw of the dock bar - seems a bit of a sledgehammer
|
|
// RedrawWindow(NULL,NULL,RDW_FRAME|RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE);
|
|
// SetWindowPos(NULL,0,0,0,0,SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_DRAWFRAME);
|
|
for(int i = PtrToInt(m_SplitArr.GetUpperBound()); i >= 0; i--)
|
|
InvalidateRect(((COXSplitterRect*)(m_SplitArr[i]))->m_rect);
|
|
}
|
|
|
|
// set m_bLayoutQuery to TRUE if lpLayout->hDWP == NULL
|
|
BOOL bLayoutQuery = m_bLayoutQuery;
|
|
m_bLayoutQuery = (lpLayout->hDWP == NULL);
|
|
LRESULT lResult = CDockBar::OnSizeParent(wParam, lParam);
|
|
// restore m_bLayoutQuery
|
|
m_bLayoutQuery = bLayoutQuery;
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
|
|
// Simple checksum for bars. Designed to spot the case when a bars moves within
|
|
// a dockrow.
|
|
int COXSizeDockBar::CheckSumBars() const
|
|
{
|
|
int nCount = 0; // total no of bars
|
|
int nCheckSum = 0; // XOR, power of 2 checksum
|
|
for (int i = 0; i < m_arrBars.GetSize(); i++)
|
|
{
|
|
if (m_arrBars[i] == NULL)
|
|
nCheckSum *= 2;
|
|
else
|
|
{
|
|
CControlBar* pBar = GetDockedControlBar(i);
|
|
ASSERT(pBar == NULL || pBar->IsKindOf(RUNTIME_CLASS(CControlBar)));
|
|
if (pBar!=NULL && ::IsWindow(pBar->GetSafeHwnd()) && pBar->IsVisible())
|
|
{
|
|
nCheckSum++;
|
|
if(IsSizeable(pBar) && !pBar->IsKindOf(RUNTIME_CLASS(COXSizeToolBar)))
|
|
nCheckSum+=i;
|
|
nCount++;
|
|
}
|
|
}
|
|
}
|
|
// LSB = actual no of dockbars (limited to 256 !)
|
|
// bits 8-31 = checksum based on layout of rows.
|
|
return ((nCheckSum << 8) | (nCount & 0xff));
|
|
}
|
|
|
|
|
|
// Adjust sizes for specified newly added bar.
|
|
void COXSizeDockBar::AdjustForNewBar(CControlBar* pNewBar)
|
|
{
|
|
int nPos = FindBar(pNewBar);
|
|
ASSERT(nPos != -1); // bar should have been found.
|
|
|
|
// Go back to start of row.
|
|
while (m_arrBars[nPos] != NULL)
|
|
nPos--;
|
|
|
|
nPos++;
|
|
|
|
// create an array for the bars on the row, that aren't this one
|
|
CPtrArray arrOtherBarsInRow;
|
|
while (nPos < m_arrBars.GetSize() && m_arrBars[nPos] != NULL)
|
|
{
|
|
CControlBar* pBar = GetDockedControlBar(nPos);
|
|
if (pBar != pNewBar)
|
|
arrOtherBarsInRow.Add(pBar);
|
|
nPos++;
|
|
}
|
|
|
|
ROWSIZEINFO RZI;
|
|
arrOtherBarsInRow.Add(NULL);
|
|
GetRowSizeInfo(0, &RZI, arrOtherBarsInRow);
|
|
CRect rcNewBar;
|
|
pNewBar->GetWindowRect(&rcNewBar);
|
|
int nWidthNeeded = (IsBarHorizontal() ? rcNewBar.Width() : rcNewBar.Height());
|
|
if(IsSizeable(pNewBar) && RZI.nFlexBars>0)
|
|
{
|
|
nWidthNeeded+=(IsBarHorizontal() ? CX_SPLIT : CY_SPLIT);
|
|
}
|
|
int nNewWidth = __max(0, RZI.nTotalWidth - nWidthNeeded);
|
|
|
|
AdjustRowSizes(0, nNewWidth, arrOtherBarsInRow);
|
|
}
|
|
|
|
|
|
// Hit test the mouse position - and set cursor accordingly
|
|
COXSplitterRect* COXSizeDockBar::SetHitCursor(CPoint pt)
|
|
{
|
|
// Set up the split cursors here. This guarantees the app is around
|
|
if(m_hcurSizeWE==NULL)
|
|
{
|
|
m_hcurSizeWE=AfxGetApp()->LoadCursor(AFX_IDC_HSPLITBAR);
|
|
if(m_hcurSizeWE==NULL)
|
|
{
|
|
m_hcurSizeWE=::LoadCursor(NULL, IDC_SIZEWE);
|
|
}
|
|
}
|
|
|
|
if(m_hcurSizeNS==NULL)
|
|
{
|
|
m_hcurSizeNS=AfxGetApp()->LoadCursor(AFX_IDC_VSPLITBAR);
|
|
if(m_hcurSizeNS==NULL)
|
|
{
|
|
m_hcurSizeNS=::LoadCursor(NULL,IDC_SIZENS);
|
|
}
|
|
}
|
|
|
|
|
|
HCURSOR hcurNew=NULL;
|
|
COXSplitterRect* pSplit=HitTest(pt);
|
|
if(pSplit!=NULL)
|
|
{
|
|
hcurNew=(pSplit->m_type == SPLITTER_VERT ? m_hcurSizeWE : m_hcurSizeNS);
|
|
}
|
|
else
|
|
{
|
|
hcurNew=afxData.hcurArrow;
|
|
}
|
|
ASSERT(hcurNew!=NULL);
|
|
|
|
::SetCursor(hcurNew);
|
|
|
|
return pSplit;
|
|
}
|
|
|
|
|
|
void COXSizeDockBar::OnMouseMove(UINT nFlags, CPoint point)
|
|
{
|
|
SetHitCursor(point);
|
|
CDockBar::OnMouseMove(nFlags, point);
|
|
}
|
|
|
|
|
|
|
|
void COXSizeDockBar::OnLButtonDown(UINT /* nFlags */, CPoint point)
|
|
{
|
|
if (m_pSplitCapture == NULL)
|
|
{
|
|
m_pSplitCapture = SetHitCursor(point);
|
|
if (m_pSplitCapture != NULL)
|
|
{
|
|
StartTracking(point);
|
|
m_pSplitCapture = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void COXSizeDockBar::OnLButtonUp(UINT nFlags, CPoint point)
|
|
{
|
|
CDockBar::OnLButtonUp(nFlags, point);
|
|
}
|
|
|
|
|
|
void COXSizeDockBar::StartTracking(CPoint pt)
|
|
{
|
|
ASSERT(m_pSplitCapture != NULL);
|
|
|
|
// Some organizational flags: helps to cut down the cases
|
|
BOOL bHorz=IsBarHorizontal();
|
|
BOOL bVertSplitter=(m_pSplitCapture->m_type == SPLITTER_VERT);
|
|
BOOL bRowDivider=((!bVertSplitter) && bHorz) || (bVertSplitter && (!bHorz));
|
|
int nPos=m_pSplitCapture->m_nPos;
|
|
|
|
COXRectTracker MvRect;
|
|
|
|
// attempt to clip move rect by current layout size of the dockbar
|
|
CRect LayoutRect(CPoint(0,0), m_LayoutSize);
|
|
MvRect.m_rect=m_pSplitCapture->m_rect;
|
|
|
|
// Shrink the splitter rectangle to end up with a solid bar
|
|
if(bVertSplitter)
|
|
{
|
|
MvRect.m_rect.InflateRect(-2,0);
|
|
}
|
|
else
|
|
{
|
|
MvRect.m_rect.InflateRect(0,-2);
|
|
}
|
|
|
|
MvRect.m_rect.IntersectRect(MvRect.m_rect, LayoutRect);
|
|
ASSERT(!(MvRect.m_rect.IsRectEmpty()));
|
|
|
|
// get main window - all dragging is done relative to this window.
|
|
// this should be the frame window.....
|
|
CWnd* pClipWnd = GetParentFrame();
|
|
|
|
if (bVertSplitter)
|
|
{
|
|
MvRect.m_nStyle |= RectTracker_OnlyMoveHorz; // allow horizontal movement
|
|
}
|
|
else
|
|
{
|
|
MvRect.m_nStyle |= RectTracker_OnlyMoveVert; // allow vertical movement
|
|
}
|
|
|
|
// workout a limiting rectangle; - very dependent on orientation. Eventually may need to work
|
|
// out the fixed size of the windows beyond the current splitter, so it could get nasty.
|
|
// for now just use the client area of the window
|
|
ROWSIZEINFO RZI;
|
|
::ZeroMemory((void*)&RZI,sizeof(RZI));
|
|
CRect LimitRect;
|
|
pClipWnd->GetClientRect(&LimitRect);
|
|
pClipWnd->ClientToScreen(&LimitRect);
|
|
ScreenToClient(&LimitRect); // map to co-ords of pWnd
|
|
|
|
#ifdef _VERBOSE_TRACE
|
|
Dump(afxDump);
|
|
#endif
|
|
|
|
if(bRowDivider)
|
|
{
|
|
if (m_dwStyle & (CBRS_ALIGN_TOP | CBRS_ALIGN_LEFT)) // apply to previous row for top/bottom
|
|
{
|
|
nPos = StartPosOfPreviousRow(nPos);
|
|
ASSERT(nPos != 0);
|
|
}
|
|
GetRowSizeInfo(nPos,&RZI,m_arrBars); // get the row information:
|
|
switch (m_dwStyle & CBRS_ALIGN_ANY)
|
|
{
|
|
case CBRS_ALIGN_TOP:
|
|
LimitRect.top=__max(LimitRect.top,
|
|
MvRect.m_rect.top-(RZI.nMaxHeight-RZI.nMaxFixedHeight));
|
|
if(RZI.nMinHeight>0)
|
|
{
|
|
LimitRect.top=__max(LimitRect.top,
|
|
RZI.nMinHeight+MvRect.m_rect.top-RZI.nMaxHeight);
|
|
}
|
|
break;
|
|
|
|
case CBRS_ALIGN_BOTTOM:
|
|
LimitRect.bottom=__min(LimitRect.bottom,
|
|
MvRect.m_rect.top+(RZI.nMaxHeight-RZI.nMaxFixedHeight));
|
|
if(RZI.nMinHeight>0)
|
|
{
|
|
LimitRect.bottom=__min(LimitRect.bottom,
|
|
RZI.nMaxHeight-RZI.nMinHeight+CY_SPLIT+2*CY_BORDER);
|
|
}
|
|
break;
|
|
|
|
case CBRS_ALIGN_LEFT:
|
|
LimitRect.left=__max(LimitRect.left,
|
|
MvRect.m_rect.left-(RZI.nMaxHeight-RZI.nMaxFixedHeight));
|
|
if(RZI.nMinWidth>0)
|
|
{
|
|
LimitRect.left=__max(LimitRect.left,
|
|
RZI.nMinWidth+MvRect.m_rect.left-RZI.nMaxHeight);
|
|
}
|
|
break;
|
|
|
|
case CBRS_ALIGN_RIGHT:
|
|
LimitRect.right=__max(LimitRect.right,
|
|
MvRect.m_rect.left+(RZI.nMaxHeight-RZI.nMaxFixedHeight));
|
|
if(RZI.nMinWidth>0)
|
|
{
|
|
LimitRect.right=__min(LimitRect.right,RZI.nMaxHeight-RZI.nMinWidth);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// How far can we go to down/right
|
|
int nFlexToRight, nFlexToLeft;
|
|
int nDownRight = ShrinkRowToRight(nPos, 16000, FALSE, &nFlexToRight);
|
|
int nUpLeft = ShrinkRowToLeft(nPos - 1, 16000, FALSE, &nFlexToLeft);
|
|
|
|
if ((nFlexToRight + nFlexToLeft) <= 1 ) // only 1 flex bar in the array - no movement !
|
|
{
|
|
nDownRight = 0;
|
|
nUpLeft = 0;
|
|
}
|
|
|
|
if (bHorz)
|
|
{
|
|
LimitRect.left = __max(LimitRect.left, MvRect.m_rect.left - nUpLeft);
|
|
LimitRect.right = __min(LimitRect.right, MvRect.m_rect.left + nDownRight);
|
|
}
|
|
else
|
|
{
|
|
LimitRect.top = __max(LimitRect.top , MvRect.m_rect.top - nUpLeft);
|
|
LimitRect.bottom = __min(LimitRect.bottom, MvRect.m_rect.top + nDownRight);
|
|
}
|
|
}
|
|
|
|
// Now enter the COXSplitterRect's modal track function
|
|
MvRect.m_LimitRect = LimitRect;
|
|
if (!MvRect.TrackFromHitTest (HTCAPTION, this, pt, pClipWnd))
|
|
return;
|
|
|
|
// Workout the size change cause by the drag:
|
|
int nSizeChange;
|
|
if (m_pSplitCapture->m_type == SPLITTER_VERT)
|
|
nSizeChange = MvRect.m_rect.left - MvRect.m_OrigRect.left;
|
|
else
|
|
nSizeChange = MvRect.m_rect.top - MvRect.m_OrigRect.top;
|
|
if (nSizeChange == 0)
|
|
return;
|
|
|
|
// COXSplitterRect::m_nPos is the pane position that the splitter was created at.
|
|
// For a row divider: this is the pane that immediately starts the next row
|
|
// For a column divider: this is the pane that is to the right of it.
|
|
// special case will be needed for the splitter used at the end of a left/top aligned
|
|
// dockbar.
|
|
int nSizeMoved;
|
|
if (bRowDivider)
|
|
{
|
|
if (m_dwStyle & (CBRS_ALIGN_TOP | CBRS_ALIGN_LEFT)) // apply to previous row for top/bottom
|
|
{
|
|
nSizeChange = -nSizeChange; // reverse polarity of change
|
|
}
|
|
|
|
int nNewHeight = __max(RZI.nMaxFixedHeight, RZI.nMaxHeight - nSizeChange);
|
|
|
|
// go along the rows applying size change to each bar in turn....
|
|
while (nPos < m_arrBars.GetSize()) // need to check size now
|
|
{
|
|
void* pVoid = m_arrBars[nPos];
|
|
if (pVoid == NULL)
|
|
break;
|
|
COXSizeControlBar* pBar = (COXSizeControlBar*)GetDockedControlBar(nPos);
|
|
// should check for visible ???
|
|
if (pBar!=NULL && ::IsWindow(pBar->GetSafeHwnd()) &&
|
|
pBar->IsVisible() && IsSizeable(pBar))
|
|
{
|
|
if (bHorz)
|
|
pBar->m_HorzDockSize.cy = nNewHeight;
|
|
else
|
|
pBar->m_VertDockSize.cx = nNewHeight;
|
|
|
|
}
|
|
nPos ++;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if (nSizeChange < 0)
|
|
{
|
|
// move to left/up
|
|
nSizeMoved = ShrinkRowToLeft(nPos - 1, - nSizeChange, TRUE);
|
|
ShrinkRowToRight(nPos, - nSizeMoved, TRUE);
|
|
}
|
|
else
|
|
{
|
|
// move to right/down
|
|
nSizeMoved = ShrinkRowToRight(nPos, nSizeChange, TRUE);
|
|
ShrinkRowToLeft(nPos - 1, - nSizeMoved, TRUE);
|
|
}
|
|
|
|
}
|
|
// reposition the bars..
|
|
InvalidateRect(NULL);
|
|
ASSERT(pClipWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd)));
|
|
((CFrameWnd*)pClipWnd)->RecalcLayout();
|
|
return;
|
|
}
|
|
|
|
|
|
// amount to shrink row to left.
|
|
// nPos = current pane: nPos -1 = pane to go for:
|
|
// return value = amount of space we actually sized
|
|
// bApply: if TRUE, apply changes to bar sizes
|
|
int COXSizeDockBar::ShrinkRowToLeft(int nPos, int nOrigAmount, BOOL bApply, int* pnFlexBars)
|
|
{
|
|
ASSERT(nPos >= 0 && nPos <= m_arrBars.GetSize());
|
|
|
|
int nAmount = nOrigAmount;
|
|
int nFlexBars = 0;
|
|
while (nPos >= 0)
|
|
{
|
|
if (m_arrBars[nPos] == NULL)
|
|
{
|
|
break;
|
|
}
|
|
COXSizeControlBar* pBar = (COXSizeControlBar*)GetDockedControlBar(nPos);
|
|
if (pBar!= NULL && ::IsWindow(pBar->GetSafeHwnd()) &&
|
|
IsSizeable(pBar) && pBar->IsVisible())
|
|
{
|
|
nFlexBars ++;
|
|
if (IsBarHorizontal())
|
|
{
|
|
if (pBar->m_HorzDockSize.cx >= nAmount)
|
|
{
|
|
if (bApply)
|
|
{
|
|
pBar->m_HorzDockSize.cx -= nAmount;
|
|
}
|
|
nAmount = 0;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
nAmount -= pBar->m_HorzDockSize.cx;
|
|
if (bApply)
|
|
{
|
|
pBar->m_HorzDockSize.cx = 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pBar->m_VertDockSize.cy >= nAmount)
|
|
{
|
|
if (bApply)
|
|
{
|
|
pBar->m_VertDockSize.cy -= nAmount;
|
|
}
|
|
nAmount = 0;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (bApply)
|
|
{
|
|
pBar->m_VertDockSize.cy = 0;
|
|
}
|
|
nAmount -= pBar->m_VertDockSize.cy;
|
|
}
|
|
}
|
|
}
|
|
nPos--;
|
|
}
|
|
|
|
// return no of flexible components encountered (if pointer supplied)
|
|
if (pnFlexBars != NULL)
|
|
{
|
|
*pnFlexBars = nFlexBars;
|
|
}
|
|
|
|
// reached left/top of row - return what size is still left to allocate
|
|
return (nOrigAmount - nAmount);
|
|
}
|
|
|
|
|
|
// amount to shrink row to right.
|
|
// nPos = current pane: nPos -1 = pane to go for:
|
|
// return value = amount of space we actually sized
|
|
int COXSizeDockBar::ShrinkRowToRight(int nPos, int nOrigAmount, BOOL bApply, int* pnFlexBars)
|
|
{
|
|
ASSERT(nPos >= 0 && nPos <= m_arrBars.GetSize());
|
|
int nAmount = nOrigAmount;
|
|
int nFlexBars = 0;
|
|
|
|
COXSizeControlBar* pLastBar = NULL;
|
|
|
|
while (nPos < m_arrBars.GetSize())
|
|
{
|
|
if (m_arrBars[nPos] == NULL)
|
|
break;
|
|
|
|
COXSizeControlBar* pBar = (COXSizeControlBar*)GetDockedControlBar(nPos);
|
|
if (pBar!=NULL && ::IsWindow(pBar->GetSafeHwnd()))
|
|
{
|
|
pLastBar = pBar;
|
|
if (IsSizeable(pBar) && pBar->IsVisible())
|
|
{
|
|
nFlexBars ++;
|
|
if (IsBarHorizontal())
|
|
{
|
|
if (pBar->m_HorzDockSize.cx >= nAmount)
|
|
{
|
|
if (bApply)
|
|
pBar->m_HorzDockSize.cx -= nAmount;
|
|
nAmount = 0;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
nAmount -= pBar->m_HorzDockSize.cx;
|
|
if (bApply)
|
|
pBar->m_HorzDockSize.cx = 0;
|
|
}
|
|
}
|
|
else // Vertical
|
|
{
|
|
if (pBar->m_VertDockSize.cy >= nAmount)
|
|
{
|
|
if (bApply)
|
|
pBar->m_VertDockSize.cy -= nAmount;
|
|
nAmount = 0;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
nAmount -= pBar->m_VertDockSize.cy;
|
|
if (bApply)
|
|
pBar->m_VertDockSize.cy = 0;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
nPos++;
|
|
}
|
|
// We've reached the end of the row. If we still have size left to find, the only way we can do it is if there
|
|
// is a flexble area at the end of the control bars..
|
|
if (nAmount > 0 && pLastBar != NULL)
|
|
{
|
|
int nSub;
|
|
CRect rect;
|
|
pLastBar->GetWindowRect(&rect);
|
|
ScreenToClient(&rect);
|
|
if (IsBarHorizontal())
|
|
nSub = m_LayoutSize.cx - rect.right;
|
|
else
|
|
nSub = m_LayoutSize.cy - rect.bottom;
|
|
nAmount -= __min(__max( 0, nSub), nAmount);
|
|
}
|
|
|
|
// return no of flexible components encountered (if pointer supplied)
|
|
if (pnFlexBars != NULL)
|
|
*pnFlexBars = nFlexBars;
|
|
|
|
// return amount allocated
|
|
return (nOrigAmount - nAmount);
|
|
}
|
|
|
|
|
|
|
|
// returns the first bar in the array - NULL if none
|
|
// used by the simplistic floating size routine
|
|
COXSizeControlBar* COXSizeDockBar::GetFirstControlBar()
|
|
{
|
|
// CMiniDockFrameWnd assumes that if there's only one bar, then it's at position 1
|
|
// in the array
|
|
// need to make a check for 0 sized array however
|
|
if (m_arrBars.GetSize() > 1)
|
|
return ((COXSizeControlBar*)GetDockedControlBar(1));
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
// returns TRUE if a CControlBar in the row is sizeable;
|
|
// intended to determine if the row should contain a splitter or not
|
|
BOOL COXSizeDockBar::IsRowSizeable(int nPos)
|
|
{
|
|
ASSERT(nPos >= 0 && nPos < m_arrBars.GetSize());
|
|
while (nPos < m_arrBars.GetSize())
|
|
{
|
|
if (m_arrBars[nPos] == NULL)
|
|
break;
|
|
CControlBar* pBar = GetDockedControlBar(nPos);
|
|
if (pBar!= NULL && ::IsWindow(pBar->GetSafeHwnd()) &&
|
|
IsSizeable(pBar) && pBar->IsVisible())
|
|
return TRUE;
|
|
nPos++;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// Essentially the same as CDockBar::Insert(). Returns the position in the
|
|
// bar array that the object will be inserted.
|
|
// nPos = 0 => before first position... But will have to check if this dockbar
|
|
// is the same as the present one...(perhaps)
|
|
int COXSizeDockBar::TestInsertPosition(CControlBar* pBarIns, CRect rect)
|
|
{
|
|
CPoint ptMid(rect.left + rect.Width()/2, rect.top + rect.Height()/2);
|
|
// hang-on: Don't we want to work in client co-ords ???
|
|
ScreenToClient(&ptMid);
|
|
|
|
ASSERT_VALID(this);
|
|
ASSERT(pBarIns != NULL);
|
|
UNUSED(pBarIns);
|
|
|
|
int nPos = 0;
|
|
int nPosInsAfter = 0;
|
|
int nWidth = 0;
|
|
int nTotalWidth = 0;
|
|
BOOL bHorz = m_dwStyle & CBRS_ORIENT_HORZ ? TRUE : FALSE;
|
|
|
|
for (nPos = 0; nPos < m_arrBars.GetSize(); nPos++)
|
|
{
|
|
void* pVoid = m_arrBars[nPos];
|
|
CControlBar* pBar = GetDockedControlBar(nPos);
|
|
|
|
if (pVoid == NULL)
|
|
{
|
|
nTotalWidth += nWidth - afxData.cyBorder2;
|
|
nWidth = 0;
|
|
if ((bHorz ? ptMid.y : ptMid.x) < nTotalWidth)
|
|
{
|
|
if (nPos == 0) // ie in first section....
|
|
return 0; // indicate before first position....
|
|
|
|
return nPosInsAfter+1;
|
|
}
|
|
nPosInsAfter = nPos;
|
|
}
|
|
else
|
|
if (pBar!=NULL && ::IsWindow(pBar->GetSafeHwnd()) && pBar->IsVisible())
|
|
{
|
|
CRect rectBar;
|
|
pBar->GetWindowRect(&rectBar);
|
|
ScreenToClient(&rectBar);
|
|
nWidth = __max(nWidth,
|
|
bHorz ? rectBar.Size().cy : rectBar.Size().cx - 1);
|
|
//if (bHorz ? rect.left > rectBar.left : rect.top > rectBar.top)
|
|
// don't need above test - only interested if it should go on the row or not...
|
|
nPosInsAfter = nPos;
|
|
}
|
|
}
|
|
|
|
return nPosInsAfter+1;
|
|
}
|
|
|
|
|
|
// returns no of bars that will be in the row (excluding the one to be inserted)
|
|
int COXSizeDockBar::BarsOnThisRow(CControlBar* pBarIns, CRect rect)
|
|
{
|
|
int nPos = TestInsertPosition(pBarIns, rect);
|
|
|
|
// if inserting before the first row, or after the last row, then return 0
|
|
// (there are no bars on this row).
|
|
if (nPos == 0 ||nPos > m_arrBars.GetUpperBound()) // case if inserting before first bar in the array.
|
|
return 0; // return 0 to use the full size
|
|
|
|
// go back to start of row.
|
|
while (nPos != 0 && m_arrBars[nPos - 1] != 0)
|
|
nPos --;
|
|
|
|
int nCount = 0;
|
|
while (TRUE)
|
|
{
|
|
void* pVoid = m_arrBars[nPos];
|
|
CControlBar* pBar = GetDockedControlBar(nPos);
|
|
if (pVoid == NULL)
|
|
break;
|
|
if (pBar!=NULL && ::IsWindow(pBar->GetSafeHwnd()) && pBar != pBarIns)
|
|
nCount++;
|
|
nPos++;
|
|
}
|
|
return nCount;
|
|
}
|
|
|
|
|
|
void COXSizeDockBar::ResizeBar(COXSizeControlBar* pBar, BOOL bMaximize)
|
|
{
|
|
ASSERT(pBar!=NULL);
|
|
ASSERT(pBar->CanResize());
|
|
|
|
CRect rect;
|
|
pBar->GetWindowRect(rect);
|
|
int nPos=TestInsertPosition(pBar,rect);
|
|
// go back to start of row.
|
|
while (nPos != 0 && m_arrBars[nPos - 1] != 0)
|
|
nPos --;
|
|
|
|
// Defines whether we should save the sizes of the other bars in the
|
|
// row/column or not
|
|
//
|
|
BOOL bSaveSize=TRUE;
|
|
if(bMaximize)
|
|
{
|
|
int nPosCopy=nPos;
|
|
while(TRUE)
|
|
{
|
|
void* pVoid = m_arrBars[nPos];
|
|
if (pVoid == NULL)
|
|
break; // end of the row, stop
|
|
CControlBar* pControlBar = GetDockedControlBar(nPos);
|
|
|
|
if(pBar!=pControlBar && pControlBar!=NULL &&
|
|
pControlBar->IsKindOf(RUNTIME_CLASS(COXSizeControlBar)) &&
|
|
::IsWindow(pControlBar->GetSafeHwnd()) &&
|
|
IsSizeable(pControlBar) && pControlBar->IsVisible())
|
|
{
|
|
COXSizeControlBar* pSizeControlBar=(COXSizeControlBar*)pControlBar;
|
|
if(pSizeControlBar->IsMaximized())
|
|
{
|
|
bSaveSize=FALSE;
|
|
break;
|
|
}
|
|
}
|
|
nPos++;
|
|
}
|
|
nPos=nPosCopy;
|
|
}
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
BOOL bHorz = IsBarHorizontal();
|
|
|
|
int nMargin=0;
|
|
|
|
while(TRUE)
|
|
{
|
|
void* pVoid = m_arrBars[nPos];
|
|
if (pVoid == NULL)
|
|
break; // end of the row, stop
|
|
|
|
CControlBar* pControlBar = GetDockedControlBar(nPos);
|
|
|
|
if(pBar!=pControlBar && pControlBar!=NULL &&
|
|
pControlBar->IsKindOf(RUNTIME_CLASS(COXSizeControlBar)) &&
|
|
::IsWindow(pControlBar->GetSafeHwnd()) &&
|
|
IsSizeable(pControlBar) && pControlBar->IsVisible())
|
|
{
|
|
COXSizeControlBar* pSizeControlBar=(COXSizeControlBar*)pControlBar;
|
|
if(bHorz)
|
|
{
|
|
if(bMaximize)
|
|
{
|
|
if(bSaveSize)
|
|
{
|
|
pSizeControlBar->m_SavedDockSize=
|
|
pSizeControlBar->m_HorzDockSize;
|
|
}
|
|
|
|
nMargin+=pSizeControlBar->m_HorzDockSize.cx-
|
|
2*ID_CONTAINER_GAP-ID_BUTTON_SIDE;
|
|
pSizeControlBar->m_HorzDockSize.cx=2*ID_CONTAINER_GAP+
|
|
ID_BUTTON_SIDE;
|
|
}
|
|
else
|
|
{
|
|
pSizeControlBar->m_HorzDockSize=
|
|
pSizeControlBar->m_SavedDockSize;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(bMaximize)
|
|
{
|
|
if(bSaveSize)
|
|
{
|
|
pSizeControlBar->m_SavedDockSize=
|
|
pSizeControlBar->m_VertDockSize;
|
|
}
|
|
|
|
nMargin+=pSizeControlBar->m_VertDockSize.cy-
|
|
2*ID_CONTAINER_GAP-ID_BUTTON_SIDE;
|
|
pSizeControlBar->m_VertDockSize.cy = 2*ID_CONTAINER_GAP+
|
|
ID_BUTTON_SIDE;
|
|
}
|
|
else
|
|
{
|
|
pSizeControlBar->m_VertDockSize=
|
|
pSizeControlBar->m_SavedDockSize;
|
|
}
|
|
}
|
|
pSizeControlBar->SetMaximized(FALSE);
|
|
}
|
|
nPos++;
|
|
}
|
|
|
|
if(bMaximize)
|
|
{
|
|
if(bHorz)
|
|
{
|
|
if(bSaveSize)
|
|
pBar->m_SavedDockSize=pBar->m_HorzDockSize;
|
|
pBar->m_HorzDockSize.cx+=nMargin;
|
|
}
|
|
else
|
|
{
|
|
if(bSaveSize)
|
|
pBar->m_SavedDockSize=pBar->m_VertDockSize;
|
|
pBar->m_VertDockSize.cy+=nMargin;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(bHorz)
|
|
{
|
|
pBar->m_HorzDockSize=pBar->m_SavedDockSize;
|
|
}
|
|
else
|
|
{
|
|
pBar->m_VertDockSize=pBar->m_SavedDockSize;
|
|
}
|
|
}
|
|
|
|
GetParentFrame()->RecalcLayout();
|
|
|
|
pBar->SetMaximized(bMaximize);
|
|
}
|
|
|
|
COXDockbarSkin* COXSizeDockBar::GetDockbarSkin()
|
|
{
|
|
// Check if the app is derived from COXSkinnedApp
|
|
COXSkinnedApp* pSkinnedApp = DYNAMIC_DOWNCAST(COXSkinnedApp, AfxGetApp());
|
|
if (pSkinnedApp != NULL && pSkinnedApp->GetCurrentSkin() != NULL)
|
|
return pSkinnedApp->GetCurrentSkin()->GetDockbarSkin();
|
|
else
|
|
{
|
|
// Create a classic skin for this class if not created already
|
|
if (m_pDockbarSkin == NULL)
|
|
m_pDockbarSkin = new COXDockbarSkinClassic();
|
|
|
|
return m_pDockbarSkin;
|
|
}
|
|
}
|
|
|
|
// Helper functions
|
|
int FindInArray(const CPtrArray& arrBars, int nStartIndex, void* pFind)
|
|
{
|
|
while (nStartIndex < arrBars.GetUpperBound())
|
|
{
|
|
if (arrBars[nStartIndex] == pFind)
|
|
return nStartIndex;
|
|
if (arrBars[nStartIndex] == NULL)
|
|
break;
|
|
nStartIndex++;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void* FindInArray(void* pFindId, void** pArray)
|
|
{
|
|
while (*pArray != NULL)
|
|
{
|
|
if (*pArray == pFindId)
|
|
return pArray;
|
|
pArray++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
#ifdef _DEBUG
|
|
// DEBUG only helper function
|
|
CString GetBarTitles(const CPtrArray& arrBars, int nPos)
|
|
{
|
|
CString strMsg, strTitle;
|
|
while (arrBars[nPos] != 0)
|
|
{
|
|
CControlBar* pBar = ::GetDockedControlBar(nPos, arrBars);
|
|
pBar->GetWindowText(strTitle);
|
|
strMsg += strTitle;
|
|
strMsg += ",";
|
|
nPos ++;
|
|
}
|
|
return strMsg;
|
|
}
|
|
#endif
|
|
|
|
|
|
void COXSizeDockBar::OnNcPaint()
|
|
{
|
|
CDockBar::OnNcPaint();
|
|
GetDockbarSkin()->OnNcPaintSizeDockBar(this);
|
|
}
|
|
|
|
void COXSizeDockBar::DockControlBar(CControlBar* pBar, LPCRECT lpRect)
|
|
{
|
|
ASSERT_VALID(this);
|
|
ASSERT_VALID(pBar);
|
|
ASSERT_KINDOF(CControlBar, pBar);
|
|
|
|
bool bNewDockBar = (pBar->m_pDockBar != this); // true if docking to a new dock bar
|
|
bool bInsertedToTab = false; // determines whether the control bar was just tabbed
|
|
|
|
if (bNewDockBar && pBar->m_pDockBar != NULL)
|
|
{
|
|
COXSizeDockBar* pOldDockBar = DYNAMIC_DOWNCAST(COXSizeDockBar, pBar->m_pDockBar);
|
|
if (pOldDockBar != NULL)
|
|
{
|
|
// Check to see if this control bar is tabbed to the old dock bar
|
|
if (pOldDockBar->m_wndDockTabCtrl.FindTab(pBar) != -1)
|
|
{
|
|
pOldDockBar->m_wndDockTabCtrl.RemoveTab(pBar);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (lpRect != NULL && DYNAMIC_DOWNCAST(COXSizeControlBar, pBar))
|
|
{
|
|
// Determine if this control bar needs to be tabbed
|
|
|
|
int iOldIndex = m_wndDockTabCtrl.FindTab(pBar);
|
|
CPoint ptMouse(lpRect->left, lpRect->top);
|
|
int iNewTabIndex = m_wndDockTabCtrl.HitTestTabControl(ptMouse, pBar);
|
|
if (iNewTabIndex != -1)
|
|
{
|
|
// Yes, it does
|
|
if (iOldIndex != -1 && iOldIndex != iNewTabIndex)
|
|
{
|
|
// We need to reposition
|
|
m_wndDockTabCtrl.RepositionTabs(iOldIndex, iNewTabIndex, ptMouse);
|
|
}
|
|
else if (iOldIndex == -1)
|
|
{
|
|
// Not tabbed, so add it
|
|
|
|
if (GetTabHeight() > 0)
|
|
{
|
|
// The tab control is already visible
|
|
m_wndDockTabCtrl.InsertTab(pBar, iNewTabIndex);
|
|
bInsertedToTab = true;
|
|
}
|
|
else if (GetVisibleSizeControlBarCount(pBar) > 1)
|
|
{
|
|
// The rule is that it is okay to tab only if
|
|
// there is another control bar in this column for vertical
|
|
// dock bars. For horizontal dock bars there must be another
|
|
// control bar in the same row.
|
|
m_wndDockTabCtrl.InsertTab(pBar, iNewTabIndex);
|
|
bInsertedToTab = true;
|
|
}
|
|
}
|
|
}
|
|
else if (iOldIndex != -1)
|
|
{
|
|
m_wndDockTabCtrl.RemoveTab(pBar);
|
|
}
|
|
}
|
|
|
|
CRect rectBar;
|
|
pBar->GetWindowRect(&rectBar);
|
|
if (pBar->m_pDockBar == this && (lpRect == NULL || rectBar.EqualRect(lpRect)))
|
|
{
|
|
// already docked and no change in position
|
|
return;
|
|
}
|
|
|
|
// set CBRS_FLOAT_MULTI style if docking bar has it
|
|
if (m_bFloating && (pBar->m_dwDockStyle & CBRS_FLOAT_MULTI))
|
|
m_dwStyle |= CBRS_FLOAT_MULTI;
|
|
|
|
m_dwStyle &= ~(CBRS_SIZE_FIXED | CBRS_SIZE_DYNAMIC);
|
|
m_dwStyle |= pBar->m_dwStyle & (CBRS_SIZE_FIXED | CBRS_SIZE_DYNAMIC);
|
|
|
|
if (!(m_dwStyle & CBRS_FLOAT_MULTI))
|
|
{
|
|
TCHAR szTitle[_MAX_PATH];
|
|
pBar->GetWindowText(szTitle, _countof(szTitle));
|
|
AfxSetWindowText(m_hWnd, szTitle);
|
|
}
|
|
|
|
// align correctly and turn on all borders
|
|
DWORD dwStyle = pBar->GetBarStyle();
|
|
dwStyle &= ~(CBRS_ALIGN_ANY);
|
|
dwStyle |= (m_dwStyle & CBRS_ALIGN_ANY) | CBRS_BORDER_ANY;
|
|
|
|
if (m_bFloating)
|
|
dwStyle |= CBRS_FLOATING;
|
|
else
|
|
dwStyle &= ~CBRS_FLOATING;
|
|
|
|
pBar->SetBarStyle(dwStyle);
|
|
|
|
// hide first if changing to a new docking site to avoid flashing
|
|
BOOL bShow = FALSE;
|
|
if (pBar->m_pDockBar != this && pBar->IsWindowVisible())
|
|
{
|
|
pBar->SetWindowPos(NULL, 0, 0, 0, 0,
|
|
SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_HIDEWINDOW);
|
|
bShow = TRUE;
|
|
}
|
|
|
|
int nPos = -1;
|
|
if (lpRect != NULL)
|
|
{
|
|
// Get the rectangle of the dockbar
|
|
CRect rectThis;
|
|
GetWindowRect(rectThis);
|
|
ScreenToClient(&rectThis);
|
|
|
|
// insert into appropriate row
|
|
CRect rect(lpRect);
|
|
ScreenToClient(&rect);
|
|
CPoint ptInsertion = GetInsertionPoint(pBar, rect);
|
|
|
|
// To prevent flashing we need to stay away from a couple of coordinates
|
|
// For vertical dockbars
|
|
if (ptInsertion.x >= rectThis.left - 11 && ptInsertion.x <= rectThis.left - 3)
|
|
{
|
|
// Figure out the offset and shift
|
|
int iOffset = rectThis.left - 3 - ptInsertion.x + 1;
|
|
ptInsertion.x += iOffset;
|
|
}
|
|
|
|
// For horizontal dockbars
|
|
if (ptInsertion.y >= rectThis.top - 11 && ptInsertion.y <= rectThis.top - 3)
|
|
{
|
|
// Figure out the offset and shift
|
|
int iOffset = rectThis.top - 3 - ptInsertion.y + 1;
|
|
ptInsertion.y += iOffset;
|
|
}
|
|
|
|
nPos = Insert(pBar, rect, ptInsertion);
|
|
|
|
// position at requested position
|
|
CRect rectPrev;
|
|
pBar->GetWindowRect(rectPrev);
|
|
ScreenToClient(&rectPrev);
|
|
|
|
CRect rectNew(lpRect);
|
|
ScreenToClient(&rectNew);
|
|
|
|
// Determine if this is a horizontal or a vertical dockbar
|
|
if (m_dwStyle & CBRS_ORIENT_HORZ)
|
|
{
|
|
// Horizontal
|
|
rectNew.SetRect(rect.left, rectPrev.top, rect.Width(), rectPrev.Height());
|
|
COXSizeControlBar* pOXBar = DYNAMIC_DOWNCAST(COXSizeControlBar, pBar);
|
|
if (pOXBar != NULL && bNewDockBar && !bInsertedToTab)
|
|
rectNew.bottom = pOXBar->m_FloatSize.cx;
|
|
|
|
// Adjust the x cordinates so there would be no snapping
|
|
|
|
if (pOXBar != NULL)
|
|
rectNew.left = GetXCoord(pBar, rectNew.top, rect.left);
|
|
else // we have a COXCoolToolbar
|
|
{
|
|
// Make sure we are not going outside the boundaries
|
|
int iXMinimun = GetXCoord(pBar, rectNew.top, rect.left);
|
|
int iXMaximum = rectThis.right;
|
|
|
|
// Make sure we don't exceed the minimum
|
|
if (rectNew.left < iXMinimun)
|
|
rectNew.left = iXMinimun;
|
|
|
|
// Make sure we don't exceed the maximum
|
|
else if (rectNew.left + rectNew.right > iXMaximum)
|
|
rectNew.left = iXMaximum - rectNew.right;
|
|
|
|
// Make sure we don't exceed the minimum again
|
|
if (rectNew.left < iXMinimun)
|
|
rectNew.left = iXMinimun;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Vertical
|
|
rectNew.SetRect(rectPrev.left, rect.top, rectPrev.Width(), rect.Height());
|
|
COXSizeControlBar* pOXBar = DYNAMIC_DOWNCAST(COXSizeControlBar, pBar);
|
|
if (pOXBar != NULL && bNewDockBar && !bInsertedToTab)
|
|
rectNew.right = pOXBar->m_FloatSize.cx;
|
|
|
|
// Adjust the x cordinates so there would be no snapping
|
|
|
|
if (pOXBar != NULL)
|
|
rectNew.top = GetYCoord(pBar, rectNew.left, rect.top);
|
|
else // we have a COXCoolToolbar
|
|
{
|
|
// Make sure we are not going outside the boundaries
|
|
int iYMinimun = GetYCoord(pBar, rectNew.left, rect.top);
|
|
int iYMaximum = rectThis.bottom - GetTabHeight();
|
|
|
|
// Make sure we don't exceed the minimum
|
|
if (rectNew.top < iYMinimun)
|
|
rectNew.top = iYMinimun;
|
|
|
|
// Make sure we don't exceed the maximum
|
|
else if (rectNew.top + rectNew.bottom > iYMaximum)
|
|
rectNew.top = iYMaximum - rectNew.bottom;
|
|
|
|
// Make sure we don't exceed the minimum again
|
|
if (rectNew.top < iYMinimun)
|
|
rectNew.top = iYMinimun;
|
|
}
|
|
}
|
|
|
|
pBar->SetWindowPos(NULL, rectNew.left, rectNew.top, rectNew.right, rectNew.bottom,
|
|
SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSENDCHANGING);
|
|
}
|
|
else
|
|
{
|
|
// always add on current row, then create new one
|
|
m_arrBars.Add(pBar);
|
|
m_arrBars.Add(NULL);
|
|
|
|
// align off the edge initially
|
|
pBar->SetWindowPos(NULL, -afxData.cxBorder2, -afxData.cyBorder2, 0, 0,
|
|
SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOCOPYBITS);
|
|
}
|
|
|
|
// attach it to the docking site
|
|
if (pBar->GetParent() != this)
|
|
pBar->SetParent(this);
|
|
if (pBar->m_pDockBar == this)
|
|
pBar->m_pDockBar->RemoveControlBar(pBar, nPos);
|
|
else if (pBar->m_pDockBar != NULL)
|
|
pBar->m_pDockBar->RemoveControlBar(pBar, -1, m_bFloating && !pBar->m_pDockBar->m_bFloating);
|
|
pBar->m_pDockBar = this;
|
|
|
|
if (bShow)
|
|
{
|
|
ASSERT(!pBar->IsWindowVisible());
|
|
pBar->SetWindowPos(NULL, 0, 0, 0, 0,
|
|
SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_SHOWWINDOW);
|
|
}
|
|
|
|
// remove any place holder for pBar in this dockbar
|
|
RemovePlaceHolder(pBar);
|
|
|
|
// get parent frame for recalc layout
|
|
CFrameWnd* pFrameWnd = GetDockingFrame();
|
|
pFrameWnd->DelayRecalcLayout();
|
|
}
|
|
|
|
// This function returns the minimum X-coordinate that a control bar can take at a given
|
|
// Y-coordinate
|
|
int COXSizeDockBar::GetXCoord(CControlBar* pBar, int iYCoord, int iXCoord)
|
|
{
|
|
CRect rectDockBar;
|
|
GetWindowRect(rectDockBar);
|
|
ScreenToClient(&rectDockBar);
|
|
int iXMin = rectDockBar.left - 2;
|
|
|
|
// Loop through all control bars in m_arrBars
|
|
for (int i = 0; i < m_arrBars.GetSize(); i++)
|
|
{
|
|
CControlBar* pCurrentBar = GetDockedControlBar(i);
|
|
if (pCurrentBar == NULL || !IsWindow(pCurrentBar->m_hWnd))
|
|
continue;
|
|
else if (pCurrentBar == pBar)
|
|
continue; // skip the bar which we are trying to dock
|
|
else if (!pCurrentBar->IsVisible())
|
|
continue;
|
|
|
|
// Get the window rectable of the current control bar
|
|
CRect rectBar;
|
|
pCurrentBar->GetWindowRect(rectBar);
|
|
ScreenToClient(&rectBar);
|
|
if (rectBar.top != iYCoord)
|
|
continue; // this control bar is on a different column
|
|
|
|
// The current bar is on the same row
|
|
|
|
// If the iXCoord is to the left of the midpoint of the current
|
|
// bar stop and return whatever iXMin was accumulated so far
|
|
if (iXCoord < rectBar.left)
|
|
return iXMin;
|
|
|
|
if (DYNAMIC_DOWNCAST(COXSizeControlBar, pCurrentBar) &&
|
|
DYNAMIC_DOWNCAST(COXSizeControlBar, pBar))
|
|
rectBar.right += CX_SPLIT; // separator
|
|
|
|
if (iXMin < rectBar.right)
|
|
iXMin = rectBar.right - 2;
|
|
}
|
|
|
|
return iXMin;
|
|
}
|
|
|
|
// This function returns the minimum Y-coordinate that a control bar can take at a given
|
|
// X-coordinate
|
|
int COXSizeDockBar::GetYCoord(CControlBar *pBar, int iXCoord, int iYCoord)
|
|
{
|
|
CRect rectDockBar;
|
|
GetWindowRect(rectDockBar);
|
|
ScreenToClient(&rectDockBar);
|
|
int iYMin = rectDockBar.top;
|
|
|
|
// Loop through all control bars in m_arrBars in order to determine the control bar
|
|
// after which the new control bar will be docked
|
|
for (int i = 0; i < m_arrBars.GetSize(); i++)
|
|
{
|
|
CControlBar* pCurrentBar = GetDockedControlBar(i);
|
|
if (pCurrentBar == NULL || !IsWindow(pCurrentBar->m_hWnd))
|
|
continue;
|
|
else if (pCurrentBar == pBar)
|
|
continue; // skip the bar which we are trying to dock
|
|
else if (!pCurrentBar->IsVisible())
|
|
continue; // skin the hidden bars
|
|
|
|
// Get the window rectanle of the current control bar
|
|
CRect rectBar;
|
|
pCurrentBar->GetWindowRect(rectBar);
|
|
ScreenToClient(&rectBar);
|
|
if (rectBar.left != iXCoord)
|
|
continue; // this control bar is on a different column
|
|
|
|
// The current bar is on the same column
|
|
|
|
// If the iYCoord is higher than the midpoint of the current
|
|
// bar stop and return whatever iYMin was accumulated so far
|
|
if (iYCoord < rectBar.top)
|
|
return iYMin;
|
|
|
|
if (DYNAMIC_DOWNCAST(COXSizeControlBar, pCurrentBar) &&
|
|
DYNAMIC_DOWNCAST(COXSizeControlBar, pBar))
|
|
rectBar.bottom += CY_SPLIT; // separator
|
|
|
|
if (iYMin < rectBar.bottom)
|
|
iYMin = rectBar.bottom - 2;
|
|
}
|
|
|
|
return iYMin;
|
|
}
|
|
|
|
// Determines the point that should be passed to the Insert(...) method
|
|
CPoint COXSizeDockBar::GetInsertionPoint(CControlBar *pBar, CRect rect)
|
|
{
|
|
// Set the default insertion position
|
|
CPoint ptInsertion(rect.left - 5, rect.top);
|
|
|
|
// The purpose here is to examine the default insetion position and make sure it does
|
|
// not interfere with another control bar and cause an extra snap
|
|
|
|
// Get the dockbar rectangle
|
|
CRect rectDockBar;
|
|
GetWindowRect(rectDockBar);
|
|
ScreenToClient(&rectDockBar);
|
|
|
|
// Loop through all control bars in m_arrBars
|
|
for (int i = 0; i < m_arrBars.GetSize(); i++)
|
|
{
|
|
CControlBar* pCurrentBar = GetDockedControlBar(i);
|
|
if (pCurrentBar == NULL || !IsWindow(pCurrentBar->m_hWnd))
|
|
continue;
|
|
else if (pCurrentBar == pBar)
|
|
continue; // skip the bar which we are trying to dock
|
|
|
|
// Get the window rectable of the current control bar
|
|
CRect rectBar;
|
|
pCurrentBar->GetWindowRect(rectBar);
|
|
ScreenToClient(&rectBar);
|
|
|
|
// Determine if we have a vertical or a horizontal dockbar
|
|
if (m_dwStyle & CBRS_ORIENT_HORZ)
|
|
{
|
|
// Horizontal
|
|
if (ptInsertion.y >= rectBar.top && ptInsertion.y <= rectBar.bottom)
|
|
{
|
|
// If the current control bar is a menubar move one row down
|
|
if (DYNAMIC_DOWNCAST(COXMenuBar, pCurrentBar))
|
|
{
|
|
ptInsertion.y = rectBar.bottom + 2;
|
|
return ptInsertion;
|
|
}
|
|
|
|
// If the control bar we are trying to dock is a menu bar
|
|
if (DYNAMIC_DOWNCAST(COXMenuBar, pBar))
|
|
{
|
|
ptInsertion.y = rectBar.bottom + 2;
|
|
return ptInsertion;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Vertical
|
|
if (ptInsertion.x >= rectBar.left && ptInsertion.x <= rectBar.right)
|
|
{
|
|
// If the current control bar is a menubar move one row to the right
|
|
if (DYNAMIC_DOWNCAST(COXMenuBar, pCurrentBar))
|
|
{
|
|
ptInsertion.x = rectBar.right + 2;
|
|
return ptInsertion;
|
|
}
|
|
|
|
// If the control bar we are trying to dock is a menu bar
|
|
if (DYNAMIC_DOWNCAST(COXMenuBar, pBar))
|
|
{
|
|
ptInsertion.x = rectBar.right + 2;
|
|
return ptInsertion;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return ptInsertion;
|
|
}
|
|
|
|
BOOL COXSizeDockBar::RemoveControlBar(CControlBar* pBar, int nPosExclude, int nAddPlaceHolder)
|
|
{
|
|
ASSERT(nAddPlaceHolder == 1 || nAddPlaceHolder == 0 || nAddPlaceHolder == -1);
|
|
ASSERT_VALID(this);
|
|
ASSERT(pBar != NULL);
|
|
int nPos = FindBar(pBar, nPosExclude);
|
|
ASSERT(nPos > 0);
|
|
|
|
if (nAddPlaceHolder == 1)
|
|
{
|
|
m_arrBars[nPos] = (void*)(UINT_PTR)_AfxGetDlgCtrlID(pBar->m_hWnd);
|
|
|
|
// check for already existing place holder
|
|
int nPosOld = FindBar((CControlBar*)m_arrBars[nPos], nPos);
|
|
if (nPosOld > 0)
|
|
{
|
|
m_arrBars.RemoveAt(nPos);
|
|
|
|
// remove section indicator (NULL) if nothing else in section
|
|
if (m_arrBars[nPos-1] == NULL && m_arrBars[nPos] == NULL)
|
|
m_arrBars.RemoveAt(nPos);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_arrBars.RemoveAt(nPos);
|
|
if (m_arrBars[nPos-1] == NULL && m_arrBars[nPos] == NULL)
|
|
m_arrBars.RemoveAt(nPos);
|
|
|
|
// Remove any pre-existing place holders.
|
|
if (nAddPlaceHolder != -1)
|
|
RemovePlaceHolder(pBar);
|
|
}
|
|
|
|
// don't do anything more in the shutdown case!
|
|
if (pBar->m_pDockContext == NULL)
|
|
return FALSE;
|
|
|
|
// get parent frame for recalc layout/frame destroy
|
|
CFrameWnd* pFrameWnd = GetDockingFrame();
|
|
if (m_bFloating && GetDockedVisibleCount() == 0)
|
|
{
|
|
if (GetDockedCount() == 0)
|
|
{
|
|
pFrameWnd->DestroyWindow();
|
|
return TRUE; // Self-Destruct
|
|
}
|
|
else
|
|
pFrameWnd->ShowWindow(SW_HIDE);
|
|
}
|
|
else
|
|
pFrameWnd->DelayRecalcLayout();
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// This function returns the appropriate dockbar for the given point.
|
|
// If no dockbar is suitable then it returns NULL
|
|
COXSizeDockBar* COXSizeDockBar::GetAppropriateDockBar(CPoint point, CControlBar* pControlBar)
|
|
{
|
|
// Get a pointer to the main frame
|
|
CFrameWnd* pFrameWnd = DYNAMIC_DOWNCAST(CFrameWnd, ::AfxGetMainWnd());
|
|
if (pFrameWnd == NULL)
|
|
return NULL;
|
|
|
|
// Check the left, top, right and bottom dock bars
|
|
DWORD arDockPos[4] = {AFX_IDW_DOCKBAR_LEFT, AFX_IDW_DOCKBAR_RIGHT,
|
|
AFX_IDW_DOCKBAR_TOP, AFX_IDW_DOCKBAR_BOTTOM};
|
|
int i = 0;
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
COXSizeDockBar* pDockBar = (COXSizeDockBar*) pFrameWnd->GetControlBar(arDockPos[i]);
|
|
|
|
CRect rectDockBar;
|
|
pDockBar->GetWindowRect(rectDockBar);
|
|
|
|
if (rectDockBar.PtInRect(point))
|
|
{
|
|
// Make sure the appropriate flag is set
|
|
if (arDockPos[i] == AFX_IDW_DOCKBAR_LEFT &&
|
|
!(pControlBar->m_dwDockStyle & CBRS_ALIGN_LEFT))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (arDockPos[i] == AFX_IDW_DOCKBAR_TOP &&
|
|
!(pControlBar->m_dwDockStyle & CBRS_ALIGN_TOP))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (arDockPos[i] == AFX_IDW_DOCKBAR_RIGHT &&
|
|
!(pControlBar->m_dwDockStyle & CBRS_ALIGN_RIGHT))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (arDockPos[i] == AFX_IDW_DOCKBAR_BOTTOM &&
|
|
!(pControlBar->m_dwDockStyle & CBRS_ALIGN_BOTTOM))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Prevent a COXSizeControlBar to be docked to a dockbar which contains COXCoolToolBar
|
|
if (pControlBar->IsKindOf(RUNTIME_CLASS(COXSizeControlBar)) &&
|
|
pDockBar->GetFirstDockedCoolToolBar(NULL) != NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Prevent a COXCoolToolBar to be docked to a dockbar which contains COXSizeControlBar
|
|
if (pControlBar->IsKindOf(RUNTIME_CLASS(COXCoolToolBar)) &&
|
|
pDockBar->GetFirstDockedSizeControlBar(NULL) != NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// If the tab control is visible do not allow docking except if the cursor is
|
|
// over the tab control
|
|
if (pDockBar->GetTabHeight() > 0)
|
|
{
|
|
if (pDockBar->m_wndDockTabCtrl.HitTestTabControl(point, pControlBar) == -1)
|
|
continue;
|
|
else
|
|
return pDockBar;
|
|
}
|
|
else
|
|
return pDockBar;
|
|
}
|
|
}
|
|
|
|
// Second pass - this time inflate the rectangle
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
COXSizeDockBar* pDockBar = (COXSizeDockBar*) pFrameWnd->GetControlBar(arDockPos[i]);
|
|
CRect rectDockBar;
|
|
pDockBar->GetWindowRect(rectDockBar);
|
|
|
|
if (arDockPos[i] == AFX_IDW_DOCKBAR_LEFT || arDockPos[i] == AFX_IDW_DOCKBAR_RIGHT)
|
|
{
|
|
rectDockBar.InflateRect(20, 20);
|
|
rectDockBar.bottom -= 28;
|
|
}
|
|
else if (arDockPos[i] == AFX_IDW_DOCKBAR_TOP || arDockPos[i] == AFX_IDW_DOCKBAR_BOTTOM)
|
|
rectDockBar.InflateRect(20, 20);
|
|
|
|
if (rectDockBar.PtInRect(point))
|
|
{
|
|
// Make sure the appropriate flag is set
|
|
if (arDockPos[i] == AFX_IDW_DOCKBAR_LEFT &&
|
|
!(pControlBar->m_dwDockStyle & CBRS_ALIGN_LEFT))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (arDockPos[i] == AFX_IDW_DOCKBAR_TOP &&
|
|
!(pControlBar->m_dwDockStyle & CBRS_ALIGN_TOP))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (arDockPos[i] == AFX_IDW_DOCKBAR_RIGHT &&
|
|
!(pControlBar->m_dwDockStyle & CBRS_ALIGN_RIGHT))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (arDockPos[i] == AFX_IDW_DOCKBAR_BOTTOM &&
|
|
!(pControlBar->m_dwDockStyle & CBRS_ALIGN_BOTTOM))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Prevent a COXSizeControlBar to be docked to a dockbar which contains COXCoolToolBar
|
|
if (pControlBar->IsKindOf(RUNTIME_CLASS(COXSizeControlBar)) &&
|
|
pDockBar->GetFirstDockedCoolToolBar(NULL) != NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Prevent a COXCoolToolBar to be docked to a dockbar which contains COXSizeControlBar
|
|
if (pControlBar->IsKindOf(RUNTIME_CLASS(COXCoolToolBar)) &&
|
|
pDockBar->GetFirstDockedSizeControlBar(NULL) != NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// If the tab control is visible do not allow docking except if the cursor is
|
|
// over the tab control
|
|
if (pDockBar->GetTabHeight() > 0)
|
|
{
|
|
if (pDockBar->m_wndDockTabCtrl.HitTestTabControl(point, pControlBar) == -1)
|
|
continue;
|
|
else
|
|
return pDockBar;
|
|
}
|
|
else
|
|
return pDockBar;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// Returns the hight of the tab control at the bottom or 0 if not visible
|
|
int COXSizeDockBar::GetTabHeight()
|
|
{
|
|
if (m_wndDockTabCtrl.GetItemCount() > 0)
|
|
{
|
|
// Determine the tab height
|
|
return 28;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
int COXSizeDockBar::OnCreate(LPCREATESTRUCT lpCreateStruct)
|
|
{
|
|
if (CDockBar::OnCreate(lpCreateStruct) == -1)
|
|
return -1;
|
|
|
|
// Create the tabs container
|
|
if (!m_wndDockTabCtrl.Create(WS_CHILD | WS_VISIBLE | TCS_BOTTOM | TCS_FOCUSNEVER,
|
|
CRect(0,0,0,0), this, IDC_DOCKTAB))
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void COXSizeDockBar::OnSize(UINT nType, int cx, int cy)
|
|
{
|
|
CDockBar::OnSize(nType, cx, cy);
|
|
|
|
// Size the tabs container accordingly
|
|
CRect rectClient;
|
|
GetClientRect(rectClient);
|
|
rectClient.top = rectClient.bottom - GetTabHeight();
|
|
m_wndDockTabCtrl.MoveWindow(rectClient);
|
|
}
|
|
|
|
// This function returns the number of COXSizeControlBar items in this dock bar
|
|
int COXSizeDockBar::GetSizeControlBarCount(CControlBar* pExcludeFromCount)
|
|
{
|
|
int iCount = 0;
|
|
for (int i = 0; i < m_arrBars.GetSize(); i++)
|
|
{
|
|
COXSizeControlBar* pSizeBar = DYNAMIC_DOWNCAST(COXSizeControlBar, GetDockedControlBar(i));
|
|
if (pSizeBar != NULL && pSizeBar != pExcludeFromCount)
|
|
iCount++;
|
|
}
|
|
return iCount;
|
|
}
|
|
|
|
COXSizeControlBar* COXSizeDockBar::GetFirstDockedSizeControlBar(CControlBar* pExclude)
|
|
{
|
|
for (int i = 0; i < m_arrBars.GetSize(); i++)
|
|
{
|
|
COXSizeControlBar* pSizeBar = DYNAMIC_DOWNCAST(COXSizeControlBar, GetDockedControlBar(i));
|
|
if (pSizeBar != NULL && pSizeBar != pExclude)
|
|
return pSizeBar;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
COXCoolToolBar* COXSizeDockBar::GetFirstDockedCoolToolBar(CControlBar* pExclude)
|
|
{
|
|
for (int i = 0; i < m_arrBars.GetSize(); i++)
|
|
{
|
|
COXCoolToolBar* pToolBar = DYNAMIC_DOWNCAST(COXCoolToolBar, GetDockedControlBar(i));
|
|
if (pToolBar != NULL && pToolBar != pExclude)
|
|
return pToolBar;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void COXSizeDockBar::PositionTabCtrl()
|
|
{
|
|
// Size the tabs container accordingly
|
|
CRect rectClient;
|
|
GetClientRect(rectClient);
|
|
rectClient.top = rectClient.bottom - GetTabHeight();
|
|
m_wndDockTabCtrl.MoveWindow(rectClient);
|
|
}
|
|
|
|
// This function returns the number of visible size control bars in this dockbar that are
|
|
// on the same row (for vertical dockbars) or on the same column (for horizontal dockbars)
|
|
// as the diven control bar
|
|
int COXSizeDockBar::GetVisibleSizeControlBarCount(CControlBar* pBar)
|
|
{
|
|
int iCount = 1;
|
|
|
|
// Get the client rectangle of the given control bar
|
|
CRect rectGiven;
|
|
pBar->GetWindowRect(rectGiven);
|
|
|
|
for (int i = 0; i < m_arrBars.GetSize(); i++)
|
|
{
|
|
COXSizeControlBar* pCurrentSizeBar = DYNAMIC_DOWNCAST(COXSizeControlBar, GetDockedControlBar(i));
|
|
if (pCurrentSizeBar != NULL && pCurrentSizeBar != pBar && pCurrentSizeBar->IsVisible())
|
|
{
|
|
CRect rectCurrent;
|
|
pCurrentSizeBar->GetWindowRect(rectCurrent);
|
|
if (IsBarHorizontal())
|
|
{
|
|
if (rectGiven.left == rectCurrent.left)
|
|
{
|
|
iCount++;
|
|
}
|
|
}
|
|
else // vertical
|
|
{
|
|
if (::abs(rectGiven.left - rectCurrent.left) < 5)
|
|
{
|
|
iCount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return iCount;
|
|
}
|
|
|
|
void COXSizeDockBar::TabAllDockedControlBars(COXSizeControlBar* pSelected)
|
|
{
|
|
for (int i = 0; i < m_arrBars.GetSize(); i++)
|
|
{
|
|
COXSizeControlBar* pSizeBar = DYNAMIC_DOWNCAST(COXSizeControlBar, GetDockedControlBar(i));
|
|
if (pSizeBar != NULL)
|
|
{
|
|
if (m_wndDockTabCtrl.FindTab(pSizeBar) < 0)
|
|
m_wndDockTabCtrl.InsertTab(pSizeBar, 0, FALSE);
|
|
}
|
|
}
|
|
|
|
if (pSelected)
|
|
{
|
|
m_wndDockTabCtrl.SetCurSel(m_wndDockTabCtrl.FindTab(pSelected));
|
|
m_wndDockTabCtrl.ShowSelectedTab();
|
|
}
|
|
}
|
|
|
|
void COXSizeDockBar::TabAllDockedControlBars(int selectedIndex)
|
|
{
|
|
for (int i = 0; i < m_arrBars.GetSize(); i++)
|
|
{
|
|
COXSizeControlBar* pSizeBar = DYNAMIC_DOWNCAST(COXSizeControlBar, GetDockedControlBar(i));
|
|
if (pSizeBar != NULL)
|
|
{
|
|
if (m_wndDockTabCtrl.FindTab(pSizeBar) < 0)
|
|
m_wndDockTabCtrl.InsertTab(pSizeBar, 0, FALSE);
|
|
}
|
|
}
|
|
|
|
if (selectedIndex >= 0 && selectedIndex < m_CountBars)
|
|
{
|
|
m_wndDockTabCtrl.SetCurSel(m_wndDockTabCtrl.FindTab(GetDockedControlBar(selectedIndex)));
|
|
m_wndDockTabCtrl.ShowSelectedTab();
|
|
}
|
|
}
|
|
|