// =================================================================================== // 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 #ifndef __OXMFCIMPL_H__ #if _MFC_VER >= 0x0700 #if _MFC_VER >= 1400 #include #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->nMinWidthnMinWidth=minmaxInfo.ptMinTrackSize.x; } if(pRZI->nMinHeightnMinHeight=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(); } }