home *** CD-ROM | disk | FTP | other *** search
/ Prima Shareware 3 / DuCom_Prima-Shareware-3_cd1.bin / PROGRAMO / C / MRCE / SOURCE.ZIP / SIZEDOCK.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-18  |  62.5 KB  |  1,889 lines

  1. // MRCEXT: Micro Focus Extension DLL for MFC 2.1+
  2. // Copyright (C)1994-5    Micro Focus Inc, 2465 East Bayshore Rd, Palo Alto, CA 94303.
  3. // 
  4. //  This program is free software; you can redistribute it and/or modify
  5. //  it under the terms of the GNU General Public License as published by
  6. //  the Free Software Foundation. In addition, you may also charge for any
  7. //  application    using MRCEXT, and are under no obligation to supply source
  8. //  code. You must accredit Micro Focus Inc in the "About Box", or banner
  9. //  of your application. 
  10. //
  11. //  This program is distributed in the hope that it will be useful,
  12. //  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. //  GNU General Public License for more details.
  15. //
  16. //  You should also have received a copy of the GNU General Public License with this
  17. //  software, also indicating additional rights you have when using MRCEXT.  
  18. //
  19. //
  20. // SIZEDOCK.CPP
  21. // $Date:   18 Jan 1996 16:53:56  $
  22. // $Revision:   1.6  $
  23. // $Author:   MRC  $
  24. // sizedock.cpp : implementation file
  25. // Sizeable Dock Frame Window
  26.  
  27. #include "mrcstafx.h"
  28. #include "mrcpriv.h"
  29.  
  30.  
  31.  
  32. #ifdef _DEBUG
  33. #undef THIS_FILE
  34. static char BASED_CODE THIS_FILE[] = __FILE__;
  35. #endif
  36.  
  37.  
  38. IMPLEMENT_DYNCREATE(CSizableMiniDockFrameWnd, CMiniDockFrameWnd)
  39.  
  40. //#define new DEBUG_NEW        // using this means the DEF file is not portable across directories
  41.  
  42. MRC_AUX_DATA afxData;
  43.  
  44. ////////////////////////////////////////////////////////////////////////////////////
  45.  
  46. //----------------------------------------------------------------------------------
  47. MRC_AUX_DATA::MRC_AUX_DATA()
  48. // constructor ensures we have all the colors to hand
  49. //----------------------------------------------------------------------------------
  50. {
  51.     DWORD dwVersion = ::GetVersion();
  52.     //nWinVer = (LOBYTE(dwVersion) << 8) + HIBYTE(dwVersion);
  53.     //bWin32s = (dwVersion & 0x80000000) != 0;
  54.     bWin4 = (BYTE)dwVersion >= 4;
  55.     
  56.     cxBorder2 = bWin4 ? CX_BORDER*2 : CX_BORDER;
  57.     cyBorder2 = bWin4 ? CY_BORDER*2 : CY_BORDER;
  58.  
  59.     hcurWait = ::LoadCursor(NULL, IDC_WAIT);
  60.     hcurArrow = ::LoadCursor(NULL, IDC_ARROW);
  61.     hcurSizeWE = NULL;
  62.     hcurSizeNS = NULL;
  63.             
  64.     UpdateSysColors();
  65. }
  66.  
  67.  
  68. MRC_AUX_DATA::~MRC_AUX_DATA()
  69. {
  70. }
  71.  
  72.  
  73. //------------------------------------------------------------------------------
  74. void MRC_AUX_DATA::UpdateSysColors()
  75. // Update the cached colors we use. Eventually, need to call this when the
  76. // main frame window receives a WM_SYSCOLORCHANGE
  77. //------------------------------------------------------------------------------
  78. {
  79.  
  80.     clrBtnFace = ::GetSysColor(COLOR_BTNFACE);
  81.     clrBtnShadow = ::GetSysColor(COLOR_BTNSHADOW);
  82.     clrBtnHilite = ::GetSysColor(COLOR_BTNHIGHLIGHT);
  83.     clrBtnText = ::GetSysColor(COLOR_BTNTEXT);
  84.     clrWindowFrame = ::GetSysColor(COLOR_WINDOWFRAME);
  85. }
  86.  
  87.  
  88. ////////////////////////////////////////////////////////////////////////////////////
  89. // CSplitterRect Functions
  90.  
  91.  
  92. //-----------------------------------------------------------------------------------
  93. CSplitterRect::CSplitterRect(int type, const RECT & rect)
  94. // in-line constructor moved out of line as ASSERT causes problems for .DEF file
  95. // (end up with a symbol that contains THIS_FILE, and hence a path name, so we can't
  96. // by portable across directories).
  97. //-----------------------------------------------------------------------------------
  98. {
  99.     ASSERT(type == SPLITTER_VERT || type == SPLITTER_HORZ);
  100.     m_rect = rect; m_type = type;
  101. }; 
  102.  
  103. //-----------------------------------------------------------------------------------
  104. void CSplitterRect::Draw(CDC *pDC)
  105. //-----------------------------------------------------------------------------------
  106. {
  107.     CRect rect = m_rect;
  108.     switch (m_type)
  109.     {
  110.         case SPLITTER_VERT:
  111.             rect.left ++;
  112.             pDC->FillSolidRect(rect.left, rect.top, 1, rect.Height(), afxData.clrBtnFace);
  113.             rect.left ++;
  114.             pDC->FillSolidRect(rect.left, rect.top, 1, rect.Height(), afxData.clrBtnHilite);
  115.  
  116.             rect.right --;
  117.             pDC->FillSolidRect(rect.right, rect.top, 1, rect.Height(), afxData.clrWindowFrame);
  118.             rect.right --;
  119.             pDC->FillSolidRect(rect.right, rect.top, 1, rect.Height(), afxData.clrBtnShadow);
  120.             break;
  121.  
  122.  
  123.         case SPLITTER_HORZ:
  124.             rect.top ++;
  125.             pDC->FillSolidRect(rect.left, rect.top, rect.Width(), 1, afxData.clrBtnFace);
  126.             rect.top ++;
  127.             pDC->FillSolidRect(rect.left, rect.top, rect.Width(), 1, afxData.clrBtnHilite);
  128.  
  129.             rect.bottom --;
  130.             pDC->FillSolidRect(rect.left, rect.bottom, rect.Width(), 1, afxData.clrWindowFrame);
  131.             rect.bottom --;
  132.             pDC->FillSolidRect(rect.left, rect.bottom, rect.Width(), 1, afxData.clrBtnShadow);
  133.             break;
  134.  
  135.          default:
  136.             ASSERT(FALSE);
  137.             break;
  138.      }
  139. }
  140.  
  141.  
  142.  
  143. /////////////////////////////////////////////////////////////////////////////
  144. // CSizableMiniDockFrameWnd
  145.  
  146. BEGIN_MESSAGE_MAP(CSizableMiniDockFrameWnd, CMiniDockFrameWnd)
  147.     //{{AFX_MSG_MAP(CSizableMiniDockFrameWnd)
  148.     ON_WM_CREATE()
  149.     ON_WM_SIZE()
  150.     ON_WM_CLOSE()
  151.     ON_WM_NCLBUTTONDBLCLK()
  152.     ON_WM_NCLBUTTONDOWN()
  153.     ON_WM_WINDOWPOSCHANGED()
  154.     ON_WM_NCHITTEST()
  155.     ON_WM_MOUSEACTIVATE()
  156.     //}}AFX_MSG_MAP
  157.     // Global help commands
  158. END_MESSAGE_MAP()
  159.  
  160. //-------------------------------------------------------------------
  161. int CSizableMiniDockFrameWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
  162. //-------------------------------------------------------------------
  163. {
  164.     if (CMiniDockFrameWnd::OnCreate(lpCreateStruct) == -1)
  165.         return -1;
  166.     m_nContainedBarType = Unknown;
  167.     return 1;
  168. }
  169.  
  170.  
  171. //------------------------------------------------------------------------------
  172. void AdjustForBorders(CRect& rect, DWORD dwStyle)
  173. // Helper function: used below
  174. // adjusts the size, depending on the borders specified by the CControlBar style
  175. //------------------------------------------------------------------------------
  176. {
  177.     if (dwStyle & CBRS_BORDER_LEFT)
  178.         rect.left -= afxData.cxBorder2;
  179.     if (dwStyle & CBRS_BORDER_TOP)
  180.         rect.top -= afxData.cyBorder2;
  181.     if (dwStyle & CBRS_BORDER_RIGHT)
  182.         rect.right += afxData.cxBorder2;
  183.     if (dwStyle & CBRS_BORDER_BOTTOM)
  184.         rect.bottom += afxData.cyBorder2;
  185. }
  186.  
  187.  
  188. //--------------------------------------------------------------------------
  189. void CSizableMiniDockFrameWnd::OnSize(UINT nType, int cx, int cy)
  190. // respond to the miniframe resizing. If we've got a sizeable control
  191. // bar in the window, then we set it's size. Need to adjust for the
  192. // window borders. The window will then get repositioned by a ReCalcLayout()
  193. //--------------------------------------------------------------------------
  194. {
  195.     if (cx == 0 && cy == 0)
  196.         return;
  197.  
  198.     // We don't support CBRS_FLOAT_MULTI
  199.     if ((m_wndDockBar.m_dwStyle & CBRS_FLOAT_MULTI) == 0)
  200.     {
  201.         // CMiniDockFrameWnd class assumes if there is only 1 bar, then it's at position 1
  202.         // in the array
  203.         CMRCSizeControlBar* pBar = ((CSizeDockBar *)(&m_wndDockBar))->GetFirstControlBar();
  204.         // ignore size request if not visible....
  205.         if (pBar != NULL && IsSizeable(pBar) && pBar->IsVisible())
  206.         {
  207.             CRect rect(0, 0, cx, cy);
  208.             AdjustForBorders(rect, pBar->m_dwStyle);
  209.  
  210.             pBar->m_FloatSize.cx = rect.Width();
  211.             pBar->m_FloatSize.cy = rect.Height();
  212.         }
  213.     }
  214.     RecalcLayout();
  215. }
  216.  
  217.  
  218. //-------------------------------------------------------------------
  219. BOOL CSizableMiniDockFrameWnd::PreCreateWindow(CREATESTRUCT &cs)
  220. //-------------------------------------------------------------------
  221. {
  222. // modify frame style so it is fully sizeable - we will modify this again later
  223. // if we discover that we have a standard MFC control bar inside the frame
  224. // turn on thick frame styles. MFS_THICKFRAME is what's expected, but also need WS_THICKFRAME,
  225. // as NT expects this to be able to do the resizing.
  226.     cs.style |= MFS_THICKFRAME | WS_THICKFRAME; 
  227.     cs.style &= ~( MFS_MOVEFRAME | MFS_4THICKFRAME );        
  228.     return CMiniDockFrameWnd::PreCreateWindow(cs);
  229. }
  230.  
  231.  
  232.  
  233. //-------------------------------------------------------------------
  234. UINT CSizableMiniDockFrameWnd::OnNcHitTest(CPoint point)
  235. // over-ridden so we can find out the type of the bar in this window
  236. //-------------------------------------------------------------------
  237. {
  238.     enum ContainedBarType Type = GetContainedBarType();
  239.     return CMiniDockFrameWnd::OnNcHitTest(point);
  240. }
  241.  
  242.  
  243. //-------------------------------------------------------------------
  244. void CSizableMiniDockFrameWnd::OnNcLButtonDown(UINT nHitTest, CPoint point)
  245. // if we've got a CMRCSizeControlBar inside this frame, and it's a resize,
  246. // then we can use the default window's sizing. 
  247. //-------------------------------------------------------------------
  248. {
  249.     enum ContainedBarType Type = GetContainedBarType();
  250.     if (Type == MRCSizeBar)
  251.     {
  252.         if (nHitTest >= HTSIZEFIRST && nHitTest <= HTSIZELAST)
  253.         {
  254.             // special activation for floating toolbars
  255.             ActivateTopParent();
  256.             CMiniFrameWnd::OnNcLButtonDown(nHitTest, point);
  257.             return;
  258.         }
  259.         else if (nHitTest == HTSYSMENU)
  260.         {
  261.             // do the system menu - ie give move,size,hide, etc options as would Win95.                        
  262.             InvertSysMenu();
  263.             CPoint pt(0,0);
  264.             ClientToScreen(&pt);
  265.             CRect rcSysIcon;
  266.             GetWindowRect(&rcSysIcon);
  267.             rcSysIcon.right = rcSysIcon.left + 12;        // NB:hard-coded value for width of system icon
  268.             rcSysIcon.bottom = pt.y;                    
  269.             
  270.             CMenu * pSysMenu = GetSystemMenu(FALSE);
  271.             int nCmd = pSysMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RETURNCMD, pt.x, pt.y, this, & rcSysIcon);
  272.             InvertSysMenu();
  273.             if (nCmd != 0)
  274.             {
  275.                 SendMessage(WM_SYSCOMMAND, nCmd, 0);
  276.             }
  277.             return;
  278.         }
  279.     }
  280.     CMiniDockFrameWnd::OnNcLButtonDown(nHitTest, point);
  281. }
  282.  
  283.  
  284. //-------------------------------------------------------------------
  285. int CSizableMiniDockFrameWnd::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message)
  286. //-------------------------------------------------------------------
  287. {
  288.     enum ContainedBarType Type = GetContainedBarType();
  289.     if (Type == MRCSizeBar)
  290.     {
  291.         if (nHitTest >= HTSIZEFIRST && nHitTest <= HTSIZELAST)
  292.             return CMiniFrameWnd::OnMouseActivate(pDesktopWnd, nHitTest, message);
  293.     }
  294.     return CMiniDockFrameWnd::OnMouseActivate(pDesktopWnd, nHitTest, message);
  295. }
  296.  
  297.  
  298.  
  299. //-------------------------------------------------------------------
  300. enum CSizableMiniDockFrameWnd::ContainedBarType CSizableMiniDockFrameWnd::GetContainedBarType()
  301. // returns the type of the contained bar
  302. // Floating frames are created from CFrameWnd::CreateFloatingFrame(), and at this point,
  303. // we don't know what type of control bar will eventually be in this frame. This routine
  304. // determines the type of control bar, and sets the neccessary styles. Generally this routine gets
  305. // called as soon as we do a WM_NCHITTEST on the window - ie before the user can get a chance to
  306. // manipulate it with the mouse
  307. //
  308. // CMRCSizeControlBar - default style of WS_THICKFRAME is ok (we've overridden the create too)
  309. //                        but we need to ensure "SC_SIZE" is on the menu, otherwise we can't
  310. //                        the default WM_NCLBUTTONDOWN won't generate an SC_SIZE.
  311. //
  312. // CControlBar, CBRS_SIZE_DYNAMIC
  313. //                      - set MFS_4THICKFRAME (disallow diagonal sizing)
  314. //
  315. // CControlBar, not CBRS_SIZE_DYNAMIC
  316. //                      - remove WS_THICKFRAME & add MFS_MOVEFRAME (we don't want sizing hit test values)
  317. //-------------------------------------------------------------------
  318. {
  319.     if (m_nContainedBarType == Unknown)
  320.     {
  321.         m_nContainedBarType = MFCBase;
  322.         if ((m_wndDockBar.m_dwStyle & CBRS_FLOAT_MULTI) == 0) // don't handle this
  323.         {
  324.                CMRCSizeControlBar* pBar = ((CSizeDockBar *)(&m_wndDockBar))->GetFirstControlBar();
  325.             if (pBar != NULL)
  326.             {
  327.                 if (IsSizeable(pBar))
  328.                 {        
  329.                     m_nContainedBarType = MRCSizeBar;
  330.                     GetSystemMenu(TRUE);                    // reset the system menu
  331.                     
  332.                     // delete sys menu items that might be present....
  333.                     CMenu* pSysMenu = GetSystemMenu(FALSE);
  334.                     pSysMenu->DeleteMenu(SC_MAXIMIZE, MF_BYCOMMAND);
  335.                     pSysMenu->DeleteMenu(SC_MINIMIZE, MF_BYCOMMAND);
  336.                     pSysMenu->DeleteMenu(SC_RESTORE, MF_BYCOMMAND);
  337.                     pSysMenu->DeleteMenu(SC_TASKLIST, MF_BYCOMMAND);
  338.                     while (pSysMenu->DeleteMenu(0, MF_BYCOMMAND));    // remove anything with ID=0
  339.                     
  340.                     //pSysMenu->AppendMenu(MF_STRING | MF_ENABLED, SC_SIZE, "&Size");
  341.  
  342.                     // if window is meant to close, ensure sysmenu has "Close" on it, not "Hide"
  343.                     // MFC4.0 replaces "Close" with "Hide"
  344.                     // extract close text from ID_FILE_CLOSE after the "\n" for the tooltip prompt
  345.                     if (!(pBar->m_Style & SZBARF_DESTROY_ON_CLOSE))
  346.                     {
  347.                         CString strHide;
  348.                         if (strHide.LoadString(AFX_IDS_HIDE))
  349.                         {
  350.                             // modify menu text to be "Hide" instrad of close
  351.                             VERIFY(pSysMenu->ModifyMenu(SC_CLOSE, MF_BYCOMMAND | MF_STRING, SC_CLOSE, strHide));  
  352.                             
  353.                             //pSysMenu->DeleteMenu(SC_CLOSE, MF_BYCOMMAND);
  354.                             //pSysMenu->AppendMenu(MF_STRING|MF_ENABLED, SC_CLOSE, strHide);
  355.                         } 
  356.                         /*
  357.                         CString strClose;
  358.                         if (strClose.LoadString(ID_FILE_CLOSE))
  359.                         {
  360.                             LPCTSTR pCloseText = strchr(strClose, '\n');
  361.                             if (pCloseText != NULL)
  362.                                 pSysMenu->DeleteMenu(SC_CLOSE, MF_BYCOMMAND);
  363.                                 pSysMenu->AppendMenu(MF_STRING|MF_ENABLED, SC_CLOSE, pCloseText + 1);
  364.                         } */
  365.                     }
  366.                 }
  367.                 else
  368.                 {
  369.                     if ((pBar->m_dwStyle & CBRS_SIZE_DYNAMIC))     // dynamic bar - turn on MFS_4THICKFRAME
  370.                     {
  371.                         ModifyStyle(0, MFS_4THICKFRAME);    
  372.                         return m_nContainedBarType;
  373.                     }
  374.             
  375.                 }
  376.             }
  377.         }
  378.         if (m_nContainedBarType == MFCBase)
  379.         {
  380.             ModifyStyle(WS_THICKFRAME, MFS_MOVEFRAME);
  381.         }
  382.     }        
  383.     // if bar is MFC bar (and not CBRS_SIZE_DYNAMIC, turn on MFS_MOVEFRAME)
  384.     return m_nContainedBarType;
  385. }
  386.  
  387.  
  388. //-------------------------------------------------------------------
  389. void CSizableMiniDockFrameWnd::OnClose()
  390. //-------------------------------------------------------------------
  391. {
  392.     if ((m_wndDockBar.m_dwStyle & CBRS_FLOAT_MULTI) == 0)
  393.     {
  394.      // CMiniDockFrameWnd class assumes if there is only 1 bar, then it's at position 1
  395.      // in the array
  396.         CControlBar* pBar = ((CSizeDockBar *) &m_wndDockBar)->GetFirstControlBar();
  397.          if (pBar != NULL && pBar->IsKindOf(RUNTIME_CLASS(CMRCSizeControlBar)) )
  398.              if (((CMRCSizeControlBar *)pBar)->m_Style & SZBARF_DESTROY_ON_CLOSE)
  399.             {
  400.               // close the Frame Window
  401.               CFrameWnd::OnClose();       // close the window
  402.               delete pBar;            // now explicitly delete the control bar
  403.               return;
  404.              }
  405.     }
  406.  
  407.     // otherwise just show it.
  408.     CMiniDockFrameWnd::OnClose();
  409.     return;
  410. }
  411.  
  412.  
  413. //--------------------------------------------------------------------------
  414. void MiniDockToClient(CRect & rect, BOOL bConvertToClient)
  415. // convert MiniDock size to a client size.. or vice versa.
  416. //--------------------------------------------------------------------------
  417. {
  418.     static int nCaptionY = -1;
  419.     static int nBorderX, nBorderY;
  420.  
  421.     // if not set up, create a temporary floating frame to see how big it is.
  422.     if (nCaptionY == -1)
  423.     {
  424.         CFrameWnd * pMainFrame = (CFrameWnd *) AfxGetMainWnd();
  425.         CMiniDockFrameWnd * pTmpFloatFrame = pMainFrame->CreateFloatingFrame(0);
  426.     
  427.         // calculate frame dragging rectangle
  428.         CRect rcFloat(0,0,0,0);
  429.         
  430.         pTmpFloatFrame->CalcWindowRect(&rcFloat);
  431.     
  432.         rcFloat.InflateRect(-afxData.cxBorder2, -afxData.cyBorder2);
  433.         
  434.         nCaptionY = - rcFloat.top;
  435.         nBorderY = rcFloat.bottom;
  436.         nBorderX = rcFloat.right;
  437.         
  438.         pTmpFloatFrame->DestroyWindow();
  439.     }        
  440.  
  441.     if (bConvertToClient)
  442.     {
  443.         rect.left += nBorderX;
  444.         rect.right -= nBorderX;
  445.         rect.top += nCaptionY;
  446.         rect.bottom -= nBorderY;
  447.     }
  448.     else
  449.     {
  450.         rect.left -= nBorderX;
  451.         rect.right += nBorderX;
  452.         rect.top -= nCaptionY;
  453.         rect.bottom += nBorderY;
  454.     }
  455. }
  456.  
  457.  
  458. /////////////////////////////////////////////////////////////////////////////
  459. // CSizeDockBar - derived from CDockBar
  460.  
  461. CSizeDockBar::CSizeDockBar() 
  462. {
  463.     m_pSplitCapture = FALSE;
  464.     m_hcurLast = NULL;
  465.     m_LayoutSize.cx = 0xffff;       // some stupid values to force automatic resize
  466.     m_LayoutSize.cy = 0xffff;
  467.     m_CountBars = 0;
  468. }
  469.  
  470.  
  471. CSizeDockBar::~CSizeDockBar()
  472. {
  473.     DeleteSplitterRects();          // delete any outstanding splitter rects
  474. }
  475.  
  476.  
  477. BEGIN_MESSAGE_MAP(CSizeDockBar, CDockBar)
  478.         //{{AFX_MSG_MAP(CSizeDockBar)
  479.         ON_WM_PAINT()
  480.         ON_WM_MOUSEMOVE()
  481.         ON_WM_LBUTTONDOWN()
  482.         ON_WM_LBUTTONUP()
  483.         ON_WM_SETCURSOR()
  484.         //}}AFX_MSG_MAP
  485.         ON_MESSAGE(WM_SIZEPARENT, OnSizeParent)
  486. END_MESSAGE_MAP()
  487.  
  488.  
  489. /////////////////////////////////////////////////////////////////////////////
  490. // CSizeDockBar message handlers
  491.  
  492.  
  493. /////////////////////////////////////////////////////////////////////////////
  494. // CDockBar layout
  495.  
  496. //------------------------------------------------------------------------
  497. CControlBar * GetDockedControlBar(int nPos, const CPtrArray & arrBars)
  498. // helper which can acts on any array of windows
  499. //------------------------------------------------------------------------
  500. {
  501.     CControlBar* pResult = (CControlBar*)arrBars[nPos];
  502.     if (HIWORD(pResult) == 0)
  503.         return NULL;
  504.     return pResult;
  505. }
  506.  
  507.  
  508. //---------------------------------------------------------------------------
  509. CSize CSizeDockBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
  510. // most of this code is copied from MFC CDockBar - with additional comments to help
  511. // my understanding of it. The basic idea is that our DockBar is being asked how big
  512. // it is. To find out, it looks at the bars inside it
  513. //---------------------------------------------------------------------------
  514. {
  515.     ASSERT_VALID(this);
  516.  
  517.     CSize sizeFixed = CControlBar::CalcFixedLayout(bStretch, bHorz);
  518.  
  519.     // prepare for layout
  520.     AFX_SIZEPARENTPARAMS layout;
  521.     layout.hDWP = m_bLayoutQuery ?
  522.             NULL : ::BeginDeferWindowPos(m_arrBars.GetSize());
  523.  
  524.     CPoint pt(-afxData.cxBorder2, -afxData.cyBorder2);
  525.  
  526.     BOOL bDrawBarForRow = FALSE;                    // true if we should draw a bar for this row
  527.     BOOL bDrawBarWithinRow = FALSE;                 // true if we should draw a bar for this column
  528.  
  529.  
  530.     DeleteSplitterRects();          // clear the splitter rects
  531.     int nWidth = 0;
  532.     int nFirstSplitterInRow = 0;
  533.     int nFirstPaneInRow = 0;
  534.     BOOL bFirstPaneInRow = TRUE;
  535.  
  536.     // layout all the control bars
  537.     for (int nPos = 0; nPos < m_arrBars.GetSize(); nPos++)
  538.     {
  539.         void * pVoid = m_arrBars[nPos];
  540.         CControlBar* pBar = GetDockedControlBar(nPos);
  541.         if (pVoid != NULL)
  542.         {
  543.             if (pBar != NULL && pBar->IsVisible())
  544.             {
  545.                 if (bFirstPaneInRow)
  546.                 {
  547.                     bFirstPaneInRow = FALSE;        // remember where the first pane in the row is..
  548.                     nFirstPaneInRow = nPos;
  549.  
  550.                     if (m_dwStyle & (CBRS_ALIGN_BOTTOM | CBRS_ALIGN_RIGHT))
  551.                     {
  552.                         bDrawBarForRow = IsRowSizeable(nPos);
  553.                     }
  554.  
  555.                     if (bDrawBarForRow)
  556.                     {
  557.                         if (bHorz)
  558.                         {
  559.                             AddSplitterRect(SPLITTER_HORZ, pt.x, pt.y, 0 ,pt.y + CY_SPLIT, nPos);   // width set at end
  560.                             pt.y += CY_SPLIT;
  561.                         }
  562.                         else
  563.                         {
  564.                             AddSplitterRect(SPLITTER_VERT, pt.x, pt.y, pt.x + CX_SPLIT, 0, nPos);   // height set at end
  565.                             pt.x += CX_SPLIT;
  566.                         }
  567.                         bDrawBarForRow = FALSE;
  568.                     }
  569.                 }
  570.  
  571.                 if (bDrawBarWithinRow)  // draw a bar between 2 previous
  572.                 {
  573.                     if (bHorz)
  574.                     {
  575.                         AddSplitterRect(SPLITTER_VERT, pt.x, pt.y, pt.x + CX_SPLIT, 0, nPos); // width set at end of row
  576.                         pt.x += CX_SPLIT;
  577.                     }
  578.                     else
  579.                     {
  580.                         AddSplitterRect(SPLITTER_HORZ, pt.x, pt.y, 0, pt.y + CY_SPLIT, nPos); // width set at end of row
  581.                         pt.y += CY_SPLIT;
  582.                     }
  583.  
  584.                 }
  585.                 bDrawBarWithinRow = TRUE;               // potentially could clear this if 2 dockbars
  586.                                                                                 // side by side are non-sizeable
  587.  
  588.                 if (IsSizeable(pBar))                   // if the bar is sizeable, then we'll need a sizer after it
  589.                 {
  590.                     bDrawBarForRow = TRUE;
  591.                 }
  592.  
  593.                 // get ideal rect for bar
  594.                 CSize sizeBar = pBar->CalcFixedLayout(FALSE,
  595.                         (pBar->m_dwStyle & CBRS_ORIENT_HORZ) ? TRUE : FALSE);
  596.                 CRect rect(pt, sizeBar);
  597.  
  598.                 // get current rect for bar
  599.                 CRect rectBar;
  600.                 pBar->GetWindowRect(&rectBar);
  601.                 ScreenToClient(&rectBar);
  602.  
  603.                 if (bHorz)
  604.                 {
  605.  
  606.                     // change position if size changed or top not the same or
  607.                     // rectbar.left < rect.left
  608.                     // if floating compress
  609.                     pt.x = rectBar.left;
  610.                     if (rect.Size() != rectBar.Size() ||
  611.                             rect.top != rectBar.top ||
  612.                             (rectBar.left != rect.left && !m_bFloating) ||
  613.                             (rectBar.left != rect.left && m_bFloating))
  614.                     {
  615.                         AfxRepositionWindow(&layout, pBar->m_hWnd, &rect);
  616.                         pt.x = rect.left;
  617.                     }
  618.                     pt.x += sizeBar.cx - afxData.cxBorder2;
  619.                     nWidth = max(nWidth, sizeBar.cy);
  620.                 }
  621.                 else
  622.                 {
  623.                     // change position if size changed or top not the same or
  624.                     // rectbar.left < rect.left
  625.                     // if floating compress
  626.                     pt.y = rectBar.top;
  627.                     if (rect.Size() != rectBar.Size() ||
  628.                             rect.left != rectBar.left ||
  629.                             (rectBar.top != rect.top && !m_bFloating) ||
  630.                             (rectBar.top != rect.top && m_bFloating))
  631.                     {
  632.                         AfxRepositionWindow(&layout, pBar->m_hWnd, &rect);
  633.                         pt.y = rect.top;
  634.                     }
  635.                     pt.y += sizeBar.cy - afxData.cyBorder2;
  636.                     nWidth = max(nWidth, sizeBar.cx);
  637.                 }
  638.             // handle any delay/show hide for the bar
  639.                 pBar->RecalcDelayShow(&layout);
  640.             }
  641.         }
  642.         else
  643.             if (nWidth != 0)
  644.             {
  645.                  // end of row because pBar == NULL
  646.                 if (bHorz)
  647.                 {
  648.                     pt.y += nWidth - afxData.cyBorder2;
  649.                     sizeFixed.cx = max(sizeFixed.cx, pt.x);
  650.                     sizeFixed.cy = max(sizeFixed.cy, pt.y);
  651.                     pt.x = -afxData.cxBorder2;
  652.                     SetSplitterSizeInRange(nFirstSplitterInRow, SPLITTER_VERT, pt.y);
  653.                 }
  654.                 else
  655.                 {
  656.                     pt.x += nWidth - afxData.cxBorder2;
  657.                     sizeFixed.cx = max(sizeFixed.cx, pt.x);
  658.                     sizeFixed.cy = max(sizeFixed.cy, pt.y);
  659.                     pt.y = -afxData.cyBorder2;
  660.                     SetSplitterSizeInRange(nFirstSplitterInRow, SPLITTER_HORZ, pt.x);
  661.                 }
  662.                 nFirstSplitterInRow = max(m_SplitArr.GetSize(), 0);
  663.                 nWidth = 0;
  664.                 bDrawBarWithinRow = FALSE;
  665.                 bFirstPaneInRow = TRUE;
  666.         }
  667.     }
  668.  
  669.     // special case when bars are at top or left.
  670.     // use of nFirstPaneInRow (nPos where row started) so that sizing code can cope ok
  671.  
  672.     if (nFirstPaneInRow != 0 && bDrawBarForRow && (m_dwStyle & (CBRS_ALIGN_TOP | CBRS_ALIGN_LEFT)))                         // there is at least one pane.
  673.     {
  674.         if (m_dwStyle & CBRS_ALIGN_TOP)
  675.         {
  676.             AddSplitterRect(SPLITTER_HORZ, pt.x, pt.y, 0 , pt.y + CY_SPLIT, m_arrBars.GetUpperBound());
  677.             sizeFixed.cy += CY_SPLIT;
  678.         }
  679.         else
  680.         {
  681.             AddSplitterRect(SPLITTER_VERT, pt.x, pt.y, pt.x + CX_SPLIT, 0, m_arrBars.GetUpperBound());
  682.             sizeFixed.cx += CX_SPLIT;
  683.         }
  684.     }
  685.  
  686.     if (!m_bLayoutQuery)
  687.     {
  688.             // move and resize all the windows at once!
  689.         if (layout.hDWP == NULL || !::EndDeferWindowPos(layout.hDWP))
  690.             TRACE0("Warning: DeferWindowPos failed - low system resources.\n");
  691.     }
  692.  
  693.     // Finally go back and set the size of the bars between the rows
  694.     if (bHorz)
  695.         SetSplitterSizeInRange(0, SPLITTER_HORZ, sizeFixed.cx);         // set widths of inter-rows
  696.     else
  697.         SetSplitterSizeInRange(0, SPLITTER_VERT, sizeFixed.cy);         // set heights of inte-rcolumns
  698.  
  699.     return sizeFixed;
  700.  
  701. }
  702.  
  703.  
  704.  
  705.  
  706. //-----------------------------------------------------------------------------
  707. void CSizeDockBar::AddSplitterRect(int type, int x1, int y1, int x2, int y2, int nPos)
  708. //-----------------------------------------------------------------------------
  709. {
  710.     CSplitterRect * pSplit = new CSplitterRect(type, CRect(x1, y1, x2, y2));
  711.     pSplit->m_nPos = nPos;
  712.     ASSERT( pSplit != NULL);
  713.     m_SplitArr.Add(pSplit);
  714. }
  715.  
  716.  
  717. //-----------------------------------------------------------------------------
  718. void CSizeDockBar::SetSplitterSizeInRange(int start, int type, int length)
  719. // helper function: Sets the length of all CSplitterRects in the range (start->end of array)
  720. // with the specified type. Used at the end of a row to set all the heights to
  721. // the calculated width.
  722. //-----------------------------------------------------------------------------
  723. {
  724.     ASSERT(type == SPLITTER_VERT || type == SPLITTER_HORZ);
  725.     ASSERT(start >= 0 && start <= m_SplitArr.GetSize());
  726.  
  727.     for (int i = m_SplitArr.GetUpperBound(); i >= start; i--)
  728.     {
  729.         CSplitterRect * pItem = (CSplitterRect *)m_SplitArr[i];
  730.         if (pItem->m_type == type)
  731.         {
  732.             if (type == SPLITTER_VERT)
  733.                 pItem->m_rect.bottom = length;
  734.             else
  735.                 pItem->m_rect.right = length;
  736.         }
  737.     }
  738. }
  739.  
  740.  
  741. //-----------------------------------------------------------------------------
  742. void CSizeDockBar::DeleteSplitterRects()
  743. //-----------------------------------------------------------------------------
  744. {
  745.     for (int i = m_SplitArr.GetUpperBound(); i >= 0 ; i--)
  746.         delete (m_SplitArr[i]);
  747.     m_SplitArr.RemoveAll();
  748. }
  749.  
  750.  
  751. //-----------------------------------------------------------------------------
  752. void CSizeDockBar::OnPaint()
  753. //-----------------------------------------------------------------------------
  754. {
  755.     CPaintDC dc(this); // device context for painting
  756.  
  757.     for (int i = m_SplitArr.GetUpperBound(); i >= 0; i--)
  758.         ((CSplitterRect *)(m_SplitArr[i]))->Draw(&dc);
  759. }
  760.  
  761.  
  762.  
  763.  
  764. //----------------------------------------------------------------------------
  765. CSplitterRect * CSizeDockBar::HitTest(CPoint pt)
  766. //----------------------------------------------------------------------------
  767. {
  768.     for (int i = m_SplitArr.GetUpperBound(); i >= 0; i--)
  769.     {
  770.         CSplitterRect *pSplit = GetSplitter(i);
  771.         if (pSplit->m_rect.PtInRect(pt))
  772.             return(pSplit);
  773.     }
  774.     return NULL;
  775. }
  776.  
  777.  
  778. //---------------------------------------------------------------------------------
  779. BOOL CSizeDockBar::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
  780. //---------------------------------------------------------------------------------
  781. {
  782.     if (nHitTest == HTCLIENT && pWnd == this) // && !m_bTracking)
  783.         return TRUE;    // we will handle it in the mouse move
  784.  
  785.     return CDockBar::OnSetCursor(pWnd, nHitTest, message);
  786. }
  787.  
  788.  
  789.  
  790. //-------------------------------------------------------------------------------------
  791. int CSizeDockBar::StartPosOfRow(int nPos)
  792. // if already positioned on NULL, go back one further
  793. //-------------------------------------------------------------------------------------
  794. {
  795.     if (nPos > 0)
  796.     {
  797.         if (m_arrBars[nPos] == NULL)
  798.             nPos --;
  799.         while (nPos >= 0)
  800.         {
  801.             if (m_arrBars[nPos] == NULL)
  802.                 return (nPos + 1);
  803.             nPos --;
  804.         }
  805.     }
  806.     return 0;
  807. }
  808.  
  809.  
  810. //-------------------------------------------------------------------------------------
  811. int CSizeDockBar::StartPosOfPreviousRow(int nPos)
  812. // returns strart of previous row.
  813. // This function includes logic to cope with nPos beyond the end of the array.
  814. //-------------------------------------------------------------------------------------
  815. {
  816.     ASSERT (nPos > 0);
  817.     if (nPos >= m_arrBars.GetUpperBound())
  818.         return (StartPosOfRow(nPos));
  819.     else
  820.         return StartPosOfRow(nPos - 1);
  821.  }
  822.  
  823.  
  824.  
  825. //-------------------------------------------------------------------------------------
  826. void CSizeDockBar::GetRowSizeInfo(int nPos,  ROWSIZEINFO * pRZI, const CPtrArray & arrBars)
  827. // Go through control bars in the row.
  828. // returns the number of sizeable bars in the row, and the total space they currently
  829. // take up
  830. //-------------------------------------------------------------------------------------
  831. {
  832.     BOOL bHorz = IsBarHorizontal();
  833.  
  834.     // zero all the fields
  835.     memset (pRZI, 0, sizeof (ROWSIZEINFO));
  836.  
  837.     while (nPos <= arrBars.GetUpperBound())
  838.     {
  839.         CRect rect;
  840.         void * pVoid = arrBars[nPos];
  841.         if (pVoid == NULL)
  842.             break;                  // end of the row
  843.         CControlBar * pBar = ::GetDockedControlBar(nPos, arrBars);
  844.         if (pBar!= NULL && pBar->IsVisible())
  845.         {    
  846.             if (pRZI->nTotalBars != 0)
  847.                 pRZI->nFixedWidth += (bHorz ? CX_SPLIT : CY_SPLIT);     // add a splitter size
  848.  
  849.             pBar->GetWindowRect(&rect);
  850.             int nWidth = max (0, (bHorz ? rect.Width() : rect.Height()) );
  851.             int nHeight = max (0, (bHorz ? rect.Height() : rect.Width()) );
  852.  
  853.             pRZI->nTotalBars ++;
  854.             if (nHeight > pRZI->nMaxHeight)
  855.                 pRZI->nMaxHeight = nHeight;
  856.  
  857.             if (IsSizeable(pBar))
  858.             {
  859.                 pRZI->nFlexBars ++;
  860.                 pRZI->nFlexWidth += nWidth;
  861.             }
  862.             else
  863.             {
  864.                 pRZI->nFixedWidth += nWidth;
  865.                 if (nHeight > pRZI->nMaxFixedHeight)
  866.                      pRZI->nMaxFixedHeight = nHeight;
  867.             }
  868.         }
  869.         nPos ++;
  870.     }
  871.        pRZI->nTotalWidth = pRZI->nFixedWidth + pRZI->nFlexWidth;
  872.     return;
  873. }
  874.  
  875.  
  876. //------------------------------------------------------------------------
  877. BOOL CSizeDockBar::AdjustAllRowSizes(int nNewSize)
  878. // Adjusts the sizes of all the bars on a dockbar to fit a new size
  879. //------------------------------------------------------------------------
  880. {
  881.     BOOL bAdjusted = FALSE;
  882.     int nPos = 0;
  883.     while (nPos < m_arrBars.GetSize())
  884.     {
  885.         CControlBar * pBar = (CControlBar *) m_arrBars[nPos];
  886.         if (pBar == NULL)
  887.         {                                               // skip over NULLs
  888.             nPos ++;
  889.             continue;
  890.         }
  891.         bAdjusted |= AdjustRowSizes(nPos, nNewSize, m_arrBars);                    // adjust the sizes on a row
  892.         while (m_arrBars[nPos] != NULL)                 // skip to end of row
  893.                 nPos++;
  894.     }
  895.     return bAdjusted;
  896. }
  897.  
  898.  
  899. //------------------------------------------------------------------------
  900. BOOL CSizeDockBar::AdjustRowSizes(int nPos, int nNewSize, CPtrArray & arrBars)
  901. // Adjusts the size of a row - returns TRUE if any changes were made
  902. //------------------------------------------------------------------------
  903. {
  904.     BOOL bHorz = IsBarHorizontal();
  905.  
  906.     ROWSIZEINFO RZI;
  907.     GetRowSizeInfo(nPos, &RZI, arrBars);
  908.     if (RZI.nFlexBars == 0)
  909.         return FALSE;                   // no flexible bars - nothing to do !
  910.  
  911.     int nTotalSizeChange = (nNewSize - RZI.nTotalWidth);
  912.     int nSizeChangeRemaining = nTotalSizeChange;
  913.     int nSizeChange = nTotalSizeChange / RZI.nFlexBars;
  914.     // have to apply this size change to the bars on this row. Note: This will work
  915.     // by setting the docked size of the controls bars directly. Then ReCalcLayout will
  916.     // do the rest.
  917.     int nCountFlexBars = 0;
  918.     while (TRUE)
  919.     {
  920.         void * pVoid = arrBars[nPos];
  921.         if (pVoid == NULL)
  922.             break;          // end of the row, stop
  923.         CMRCSizeControlBar * pBar = (CMRCSizeControlBar *)::GetDockedControlBar(nPos, arrBars);    // note:slight abuse of cast
  924.         
  925.         if (pBar != NULL && pBar->IsVisible() && IsSizeable(pBar))
  926.         {
  927.             int nWidth = (bHorz ? pBar->m_HorzDockSize.cx : pBar->m_VertDockSize.cy);
  928.             nCountFlexBars ++;
  929.             if (nCountFlexBars == RZI.nFlexBars)    // last bar adjust size change
  930.             {
  931.                 nSizeChange = nSizeChangeRemaining;
  932.                 // nSizeChange = nTotalSizeChange - ((RZI.nFlexBars - 1) * nSizeChange);
  933.             }
  934.             else
  935.             {
  936.                 nSizeChange = (nWidth + 1) * nTotalSizeChange / (RZI.nFlexWidth + RZI.nFlexBars);
  937.             }
  938.             int nNewWidth = max(nWidth + nSizeChange, 0);
  939.             nSizeChangeRemaining -= (nNewWidth - nWidth);
  940.             
  941.             if (bHorz)
  942.             {
  943.                 pBar->m_HorzDockSize.cx = nNewWidth;
  944.                 pBar->m_HorzDockSize.cy = RZI.nMaxHeight;
  945.                 SetWindowSize(pBar, pBar->m_HorzDockSize);
  946.             }
  947.             else
  948.             {
  949.                 pBar->m_VertDockSize.cy = nNewWidth;
  950.                 pBar->m_VertDockSize.cx = RZI.nMaxHeight;
  951.                 SetWindowSize(pBar, pBar->m_VertDockSize);
  952.             }
  953.          }
  954.         nPos++;
  955.     }
  956.  
  957.     return TRUE;
  958. }
  959.  
  960.  
  961. //------------------------------------------------------------------------
  962. void CSizeDockBar::TileDockedBars()
  963. // Adjusts the sizes of all the bars on a dockbar to fit a new size
  964. //------------------------------------------------------------------------
  965. {
  966.     int nPos = 0;
  967.     while (nPos < m_arrBars.GetSize())
  968.     {
  969.         CControlBar * pBar = (CControlBar *) m_arrBars[nPos];
  970.         if (pBar == NULL)
  971.         {                                               // skip over NULLs
  972.             nPos ++;
  973.             continue;
  974.         }
  975.         TileDockedBarsRow(nPos);                                        // adjust the sizes on a row
  976.         while (m_arrBars[nPos] != NULL)                         // skip to end of row
  977.             nPos++;
  978.     }
  979.     return;
  980. }
  981.  
  982.  
  983. //---------------------------------------------------------------------------
  984. void CSizeDockBar::TileDockedBarsRow(int nPos)
  985. // Tiles the docked bars:
  986. //---------------------------------------------------------------------------
  987. {
  988.     BOOL bHorz = IsBarHorizontal();
  989.  
  990.     ROWSIZEINFO RZI;
  991.     GetRowSizeInfo(nPos, &RZI, m_arrBars);
  992.     if (RZI.nFlexBars == 0)
  993.             return;                         // no flexible bars - nothing to do !
  994.  
  995.     int nNewSize = (bHorz ? m_LayoutSize.cx : m_LayoutSize.cy);
  996.     int nTotalSize = max (0, nNewSize - RZI.nFixedWidth);
  997.     int nNewWidth = nTotalSize / RZI.nFlexBars;
  998.  
  999.     int nCountFlexBars = 0;
  1000.     while(TRUE)
  1001.     {
  1002.         void * pVoid = m_arrBars[nPos];    
  1003.         if (pVoid == NULL)
  1004.                 break;          // end of the row, stop
  1005.         CMRCSizeControlBar * pBar = (CMRCSizeControlBar *) GetDockedControlBar(nPos); // note:slight abuse of cast
  1006.         
  1007.         if (pBar != NULL && IsSizeable(pBar) && pBar->IsVisible())
  1008.         {
  1009.             nCountFlexBars ++;
  1010.             if (nCountFlexBars == RZI.nFlexBars)    // last bar adjust size change
  1011.             {
  1012.                 nNewWidth = nTotalSize - ((RZI.nFlexBars - 1) * nNewWidth);
  1013.             }
  1014.             if (bHorz)
  1015.             {
  1016.                 pBar->m_HorzDockSize.cx = nNewWidth;
  1017.                 pBar->m_HorzDockSize.cy = RZI.nMaxHeight;
  1018.             }
  1019.             else
  1020.             {
  1021.                 pBar->m_VertDockSize.cy = nNewWidth;
  1022.                 pBar->m_VertDockSize.cx = RZI.nMaxHeight;
  1023.             }
  1024.         }
  1025.         nPos++;
  1026.     }
  1027. }
  1028.  
  1029.  
  1030. //-------------------------------------------------------------------------------------
  1031. int FindInArray(const CPtrArray & arrBars, int nStartIndex, void * pFind)
  1032. //-------------------------------------------------------------------------------------
  1033. {
  1034.     
  1035.     while (nStartIndex < arrBars.GetUpperBound())    
  1036.     {
  1037.         if (arrBars[nStartIndex] == pFind)
  1038.             return nStartIndex;
  1039.         if (arrBars[nStartIndex] == NULL)
  1040.             break;        
  1041.         nStartIndex++;
  1042.     }
  1043.     return -1;
  1044. }
  1045.  
  1046. //-------------------------------------------------------------------------------------
  1047. void * FindInArray(void * pFindId, void ** pArray)
  1048. //-------------------------------------------------------------------------------------
  1049. {
  1050.     while (*pArray != NULL)
  1051.     {
  1052.         if (*pArray == pFindId)
  1053.             return pArray;
  1054.         pArray++;
  1055.     }
  1056.     return NULL;
  1057. }    
  1058.  
  1059.  
  1060. #ifdef _DEBUG
  1061. //-------------------------------------------------------------------------------------
  1062. CString GetBarTitles(const CPtrArray & arrBars, int nPos)  
  1063. // DEBUG only helper function  
  1064. //-------------------------------------------------------------------------------------
  1065. {
  1066.     CString strMsg, strTitle;
  1067.     while (arrBars[nPos] != 0)
  1068.     {
  1069.         CControlBar * pBar = GetDockedControlBar(nPos, arrBars);
  1070.         pBar->GetWindowText(strTitle);
  1071.         strMsg += strTitle;
  1072.         strMsg += ",";
  1073.         nPos ++;
  1074.     }
  1075.     return strMsg;    
  1076. }
  1077. #endif
  1078.  
  1079. //-------------------------------------------------------------------------------------
  1080. BOOL CSizeDockBar::WasBarHidden(CControlBar *pBar)
  1081. // Returns TRUE is BAR is in m_arrInvisibleBars
  1082. //-------------------------------------------------------------------------------------
  1083. {
  1084.     for (int i= 0; i < m_arrHiddenBars.GetSize(); i++)
  1085.         {                            
  1086.             if (m_arrHiddenBars[i] == pBar)
  1087.                 return TRUE;
  1088.         }
  1089.     return FALSE;
  1090. }
  1091.  
  1092.  
  1093. //-------------------------------------------------------------------------------------
  1094. LRESULT CSizeDockBar::OnSizeParent(WPARAM wParam, LPARAM lParam)
  1095. // WM_SIZEPARENT message is sent from CFrameWnd::RepositionBars() to tell the dockbar to
  1096. // calculate it's size.
  1097. // The only reason for intercepting this was to actually find out the size the dockbar is taking
  1098. // up in the layout, so we can opt to re-layout a row to fit the desired size.
  1099. // There might well be a better way of doing this.
  1100. //-------------------------------------------------------------------------------------
  1101. {
  1102.     AFX_SIZEPARENTPARAMS* lpLayout = (AFX_SIZEPARENTPARAMS*)lParam;
  1103.     
  1104.     BOOL bInvalidate = FALSE;
  1105.     BOOL bHorz = IsBarHorizontal();
  1106.  
  1107.     CRect LayRect;
  1108.     LayRect.CopyRect(&lpLayout->rect);
  1109.     CSize LaySize = LayRect.Size();  // maximum size available
  1110.     int nLayoutWidth = bHorz ? LaySize.cx : LaySize.cy;
  1111.     BOOL bLayoutWidthChanged = (nLayoutWidth != (bHorz ? m_LayoutSize.cx : m_LayoutSize.cy));
  1112.     m_LayoutSize = LaySize;
  1113.  
  1114.     // Attempt to detect bars that have changed state from Hidden->Visible. For these we attempt
  1115.     // to adjust the other (previously visible) bars on the row so that the newly shown bars
  1116.     // restore their previous size.
  1117.     CPtrArray    arrVisibleBarsInRow;        // Bars visible in the row (ones we can shrink)
  1118.     int nWidthNeeded = 0;
  1119.     for (int i = 0; i < m_arrBars.GetSize(); i++)
  1120.     {
  1121.         if (m_arrBars[i] == NULL)
  1122.         {
  1123.             ROWSIZEINFO RZI;
  1124.             if (arrVisibleBarsInRow.GetSize() != 0 && nWidthNeeded != 0)
  1125.             {
  1126.                 arrVisibleBarsInRow.Add(NULL);
  1127.                 
  1128.                 GetRowSizeInfo(0, &RZI, arrVisibleBarsInRow);
  1129.                 int nNewWidth = max(0, RZI.nTotalWidth - nWidthNeeded);
  1130.                 AdjustRowSizes(0, nNewWidth, arrVisibleBarsInRow);
  1131.             }
  1132.             nWidthNeeded = 0;
  1133.             arrVisibleBarsInRow.RemoveAll();
  1134.         }
  1135.         else
  1136.         {
  1137.             CControlBar* pBar = GetDockedControlBar(i);
  1138.             if (pBar != NULL)
  1139.             {
  1140.                 if (pBar->IsVisible())
  1141.                 {
  1142.                     if (WasBarHidden(pBar))
  1143.                     {
  1144.                         TRACE("Bar hidden->visible\n");
  1145.                         CRect rect;
  1146.                         pBar->GetWindowRect(&rect);
  1147.                         nWidthNeeded += (bHorz ? rect.Width() : rect.Height());
  1148.                     }
  1149.                     else
  1150.                     {
  1151.                         arrVisibleBarsInRow.Add(pBar);        // Track visible bars in this row that we can shrink
  1152.                     }
  1153.                 }
  1154.             }
  1155.         }
  1156.     }
  1157.  
  1158.     // construct new array of bars that are hidden in this dockbar
  1159.     m_arrHiddenBars.RemoveAll();
  1160.     for (i = 0; i < m_arrBars.GetSize(); i++)
  1161.     {
  1162.         CControlBar* pBar = GetDockedControlBar(i);
  1163.         if (pBar != NULL && ! pBar->IsVisible())
  1164.             m_arrHiddenBars.Add(pBar);
  1165.     }
  1166.  
  1167.     int nCheckSum = CheckSumBars();
  1168.  
  1169.     // any other changes and we size the bars to fit the layout width
  1170.     if (bLayoutWidthChanged || nCheckSum != m_CountBars)
  1171.     {
  1172.         AdjustAllRowSizes(nLayoutWidth);
  1173.         m_CountBars = nCheckSum;
  1174.         InvalidateRect(NULL);   // force redraw of the dock bar - seems a bit of a sledgehammer
  1175.     }
  1176.  
  1177.     // set m_bLayoutQuery to TRUE if lpLayout->hDWP == NULL
  1178.     BOOL bLayoutQuery = m_bLayoutQuery;
  1179.     m_bLayoutQuery = (lpLayout->hDWP == NULL);
  1180.     LRESULT lResult = CControlBar::OnSizeParent(wParam, lParam);
  1181.     // restore m_bLayoutQuery
  1182.     m_bLayoutQuery = bLayoutQuery;
  1183.  
  1184.     return lResult;
  1185. }
  1186.  
  1187.  
  1188.  
  1189. //---------------------------------------------------------------------------
  1190. int CSizeDockBar::CheckSumBars() const
  1191. // Simple checksum for bars. Designed to spot the case when a bars moves within
  1192. // a dockrow.
  1193. //---------------------------------------------------------------------------
  1194. {
  1195.     int nCount = 0;         // total no of bars
  1196.     int nCheckSum = 0;      // XOR, power of 2 checksum
  1197.     for (int i = 0; i < m_arrBars.GetSize(); i++)
  1198.     {
  1199.         if (m_arrBars[i] == NULL)
  1200.             nCheckSum *= 2;
  1201.         else
  1202.         {        
  1203.             CControlBar* pBar = GetDockedControlBar(i);
  1204.             ASSERT(pBar == NULL || pBar->IsKindOf(RUNTIME_CLASS(CControlBar)));
  1205.             if (pBar != NULL && pBar->IsVisible())
  1206.             {
  1207.                 nCheckSum++;
  1208.                 nCount++;
  1209.             }
  1210.         }
  1211.     }
  1212.         // LSB = actual no of dockbars (limited to 256 !)
  1213.         // bits 8-31 = checksum based on layout of rows.
  1214.     return ((nCheckSum << 8) | (nCount & 0xff));
  1215. }
  1216.  
  1217.  
  1218. //-----------------------------------------------------------------------------
  1219. void CSizeDockBar::AdjustForNewBar(CControlBar *pNewBar)        
  1220. // Adjust sizes for specified newly added bar.
  1221. //-----------------------------------------------------------------------------
  1222. {
  1223.     int nPos = FindBar(pNewBar);
  1224.     ASSERT(nPos != -1);            // bar should have been found.
  1225.     
  1226.     // Go back to start of row.
  1227.     while (m_arrBars[nPos] != NULL)
  1228.         nPos--;
  1229.  
  1230.     nPos++;
  1231.  
  1232.     // create an array for the bars on the row, that aren't this one
  1233.     CPtrArray arrOtherBarsInRow;
  1234.     while (nPos < m_arrBars.GetSize() && m_arrBars[nPos] != NULL)
  1235.     {
  1236.         CControlBar* pBar = GetDockedControlBar(nPos);
  1237.         if (pBar != pNewBar)
  1238.             arrOtherBarsInRow.Add(pBar);
  1239.         nPos--;
  1240.     }
  1241.  
  1242.     ROWSIZEINFO RZI;
  1243.     arrOtherBarsInRow.Add(NULL);
  1244.     GetRowSizeInfo(0, &RZI, arrOtherBarsInRow);
  1245.     CRect rcNewBar;
  1246.     pNewBar->GetWindowRect(&rcNewBar);
  1247.     int nWidthNeeded = (IsBarHorizontal() ? rcNewBar.Width() : rcNewBar.Height());
  1248.     int nNewWidth = max(0, RZI.nTotalWidth - nWidthNeeded);
  1249.     AdjustRowSizes(0, nNewWidth, arrOtherBarsInRow);
  1250. }
  1251.  
  1252. //-----------------------------------------------------------------------------
  1253. CSplitterRect * CSizeDockBar::SetHitCursor(CPoint pt)
  1254. // Hit test the mouse position - and set cursor accordingly
  1255. //-----------------------------------------------------------------------------
  1256. {
  1257.     // Set up the split cursors here. This guarantees the app is around
  1258.     if (afxData.hcurSizeWE == NULL)
  1259.     { 
  1260.         afxData.hcurSizeWE = AfxGetApp()->LoadCursor(AFX_IDC_HSPLITBAR);
  1261.         if (afxData.hcurSizeWE == NULL)
  1262.             afxData.hcurSizeWE = ::LoadCursor(NULL, IDC_SIZEWE);
  1263.     }            
  1264.    
  1265.     if (afxData.hcurSizeNS == NULL)
  1266.     {
  1267.         afxData.hcurSizeNS = AfxGetApp()->LoadCursor(AFX_IDC_VSPLITBAR);
  1268.         if (afxData.hcurSizeNS == NULL)
  1269.             afxData.hcurSizeNS = ::LoadCursor(NULL, IDC_SIZENS);
  1270.     }
  1271.  
  1272.  
  1273.     HCURSOR hcurNew;
  1274.     CSplitterRect * pSplit = HitTest(pt);
  1275.     if (pSplit != NULL)
  1276.            hcurNew = (pSplit->m_type == SPLITTER_VERT ? afxData.hcurSizeWE : afxData.hcurSizeNS);
  1277.     else
  1278.         hcurNew = afxData.hcurArrow;
  1279.  
  1280.     ::SetCursor(hcurNew);
  1281.     return pSplit;
  1282. }
  1283.  
  1284.  
  1285. //-----------------------------------------------------------------------------
  1286. void CSizeDockBar::OnMouseMove(UINT nFlags, CPoint point)
  1287. //-----------------------------------------------------------------------------
  1288. {
  1289.     SetHitCursor(point);
  1290.     CDockBar::OnMouseMove(nFlags, point);
  1291. }
  1292.  
  1293.  
  1294.  
  1295. //-----------------------------------------------------------------------------
  1296. void CSizeDockBar::OnLButtonDown(UINT nFlags, CPoint point)
  1297. //-----------------------------------------------------------------------------
  1298. {
  1299.     m_pSplitCapture = SetHitCursor(point);
  1300.     if (m_pSplitCapture != NULL)
  1301.     {
  1302.         StartTracking(point);
  1303.         m_pSplitCapture = NULL;
  1304.     }
  1305. }
  1306.  
  1307.  
  1308. //-----------------------------------------------------------------------------
  1309. void CSizeDockBar::OnLButtonUp(UINT nFlags, CPoint point)
  1310. //-----------------------------------------------------------------------------
  1311. {
  1312.     m_pSplitCapture = NULL;
  1313.     CDockBar::OnLButtonUp(nFlags, point);
  1314. }
  1315.  
  1316.  
  1317. //-----------------------------------------------------------------------------
  1318. void CSizeDockBar::StartTracking(CPoint pt)
  1319. //-----------------------------------------------------------------------------
  1320. {
  1321.     ASSERT(m_pSplitCapture != NULL);
  1322.  
  1323.     // Some organizational flags: helps to cut down the cases
  1324.     BOOL bHorz      = IsBarHorizontal();
  1325.     BOOL bVertSplitter = (m_pSplitCapture->m_type == SPLITTER_VERT);
  1326.     BOOL bRowDivider = ((!bVertSplitter) && bHorz) || (bVertSplitter && (!bHorz));
  1327.     int nPos = m_pSplitCapture->m_nPos;
  1328.  
  1329.     CMRCRectTracker MvRect;
  1330.  
  1331.     // attempt to clip move rect by current layout size of the dockbar
  1332.     CRect LayoutRect(CPoint(0,0), m_LayoutSize);
  1333.     MvRect.m_rect = m_pSplitCapture->m_rect;
  1334.  
  1335.     MvRect.m_rect.IntersectRect(MvRect.m_rect, LayoutRect);
  1336.     ASSERT(!(MvRect.m_rect.IsRectEmpty()));
  1337.     
  1338.     // get main window - all dragging is done relative to this window.
  1339.     // this should be the frame window.....
  1340.     CWnd * pClipWnd = GetParentFrame();
  1341.  
  1342.     // map rectangle to co-ord system of clipping window....
  1343.     //ClientToScreen(&MvRect.m_rect);
  1344.     //pClipWnd->ScreenToClient(&MvRect.m_rect);
  1345.  
  1346.     // map mouse point also....
  1347.     //ClientToScreen(&pt);
  1348.     //pClipWnd->ScreenToClient(&pt);
  1349.  
  1350.     
  1351.     if (bVertSplitter)
  1352.         MvRect.m_nStyle |= RectTracker_OnlyMoveHorz;      // allow horizontal movement
  1353.     else
  1354.         MvRect.m_nStyle |= RectTracker_OnlyMoveVert;      // allow horizontal movement
  1355.  
  1356.     // workout a limiting rectangle; - very dependent on orientation. Eventually may need to work
  1357.     // out the fixed size of the windows beyond the current splitter, so it could get nasty.
  1358.     // for now just use the client area of the window
  1359.     ROWSIZEINFO RZI;
  1360.     CRect LimitRect;
  1361.     pClipWnd->GetClientRect(&LimitRect);
  1362.     pClipWnd->ClientToScreen(&LimitRect);
  1363.     ScreenToClient(&LimitRect);            // map to co-ords of pWnd
  1364.  
  1365.     if (bRowDivider)
  1366.     {
  1367.         if (m_dwStyle & (CBRS_ALIGN_TOP | CBRS_ALIGN_LEFT))             // apply to previous row for top/bottom
  1368.         {
  1369.             nPos = StartPosOfPreviousRow(nPos);
  1370.             ASSERT(nPos != 0);
  1371.            }
  1372.            GetRowSizeInfo(nPos, &RZI, m_arrBars);             // get the row information:
  1373.            switch (m_dwStyle & CBRS_ALIGN_ANY)
  1374.            {
  1375.             case CBRS_ALIGN_BOTTOM:
  1376.                 LimitRect.bottom = min (LimitRect.bottom, MvRect.m_rect.top + (RZI.nMaxHeight - RZI.nMaxFixedHeight));
  1377.                 break;
  1378.             case CBRS_ALIGN_TOP:
  1379.                 LimitRect.top = max (LimitRect.top, MvRect.m_rect.top - (RZI.nMaxHeight - RZI.nMaxFixedHeight));
  1380.                   break;
  1381.             case CBRS_ALIGN_LEFT:
  1382.                 LimitRect.left = max (LimitRect.left, MvRect.m_rect.left - (RZI.nMaxHeight - RZI.nMaxFixedHeight));
  1383.                 break;
  1384.             case CBRS_ALIGN_RIGHT:
  1385.                 LimitRect.right = max (LimitRect.right, MvRect.m_rect.left + (RZI.nMaxHeight - RZI.nMaxFixedHeight));
  1386.                 break;
  1387.             default:
  1388.                 ASSERT(FALSE);
  1389.           }
  1390.     }
  1391.     else
  1392.     {
  1393.         // How far can we go to down/right
  1394.         int nFlexToRight, nFlexToLeft;
  1395.         int nDownRight = ShrinkRowToRight(nPos, 16000, FALSE, &nFlexToRight);
  1396.         int nUpLeft = ShrinkRowToLeft(nPos - 1, 16000, FALSE, &nFlexToLeft);
  1397.  
  1398.         if ((nFlexToRight + nFlexToLeft) <= 1 )  // only 1 flex bar in the array - no movement !
  1399.         {
  1400.             nDownRight = 0;
  1401.             nUpLeft = 0;
  1402.         }
  1403.  
  1404.         if (bHorz)
  1405.         {
  1406.             LimitRect.left = max(LimitRect.left, MvRect.m_rect.left - nUpLeft);
  1407.             LimitRect.right = min(LimitRect.right, MvRect.m_rect.left + nDownRight);
  1408.         }
  1409.         else
  1410.         {
  1411.             LimitRect.top = max(LimitRect.top , MvRect.m_rect.top - nUpLeft);
  1412.             LimitRect.bottom = min(LimitRect.bottom, MvRect.m_rect.top + nDownRight);
  1413.         }
  1414.     }
  1415.  
  1416.     // Now enter the CMoveRect's modal track function
  1417.     MvRect.m_LimitRect = LimitRect;
  1418.     if (!MvRect.TrackFromHitTest (HTCAPTION, this, pt, pClipWnd))
  1419.          return;
  1420.  
  1421.         // Workout the size change cause by the drag:
  1422.     int nSizeChange;
  1423.     if (m_pSplitCapture->m_type == SPLITTER_VERT)
  1424.         nSizeChange = MvRect.m_rect.left - MvRect.m_OrigRect.left;
  1425.     else
  1426.         nSizeChange = MvRect.m_rect.top - MvRect.m_OrigRect.top;
  1427.     if (nSizeChange == 0)
  1428.         return;
  1429.  
  1430.     // CSplitterRect::m_nPos is the pane position that the splitter was created at.
  1431.     // For a row divider: this is the pane that immediately starts the next row
  1432.     // For a column divider: this is the pane that is to the right of it.
  1433.     // special case will be needed for the splitter used at the end of a left/top aligned
  1434.     // dockbar.
  1435.     int nSizeMoved;
  1436.     if (bRowDivider)
  1437.     {
  1438.         if (m_dwStyle & (CBRS_ALIGN_TOP | CBRS_ALIGN_LEFT))             // apply to previous row for top/bottom
  1439.         {
  1440.              nSizeChange = -nSizeChange;             // reverse polarity of change
  1441.         }
  1442.  
  1443.         int nNewHeight = max (RZI.nMaxFixedHeight, RZI.nMaxHeight - nSizeChange);
  1444.  
  1445.         // go along the rows applying size change to each bar in turn....
  1446.         while (nPos < m_arrBars.GetSize())    // need to check size now
  1447.         {
  1448.             void * pVoid = m_arrBars[nPos];
  1449.             if (pVoid == NULL)
  1450.                 break;
  1451.             CMRCSizeControlBar * pBar = (CMRCSizeControlBar *)GetDockedControlBar(nPos);
  1452.             // should check for visible ???
  1453.             if (pBar != NULL && pBar->IsVisible() && IsSizeable(pBar))
  1454.             {
  1455.                 if (bHorz)
  1456.                        pBar->m_HorzDockSize.cy = nNewHeight;
  1457.                 else
  1458.                     pBar->m_VertDockSize.cx = nNewHeight;
  1459.             }
  1460.             nPos ++;
  1461.          }
  1462.  
  1463.     }
  1464.     else
  1465.     {
  1466.         if (nSizeChange < 0)
  1467.         {                                                               // move to left/up
  1468.             nSizeMoved = ShrinkRowToLeft(nPos - 1, - nSizeChange, TRUE);
  1469.             ShrinkRowToRight(nPos, - nSizeMoved, TRUE);
  1470.         }
  1471.         else
  1472.         {                                                               // move to right/down
  1473.             nSizeMoved = ShrinkRowToRight(nPos, nSizeChange, TRUE);
  1474.             ShrinkRowToLeft(nPos - 1, - nSizeMoved, TRUE);
  1475.         }
  1476.  
  1477.     }
  1478.     // reposition the bars..
  1479.     InvalidateRect(NULL);
  1480.     //((CFrameWnd *)AfxGetMainWnd())->RecalcLayout();
  1481.     ASSERT(pClipWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd)));
  1482.     ((CFrameWnd *)pClipWnd)->RecalcLayout();
  1483.     return;
  1484. }
  1485.  
  1486.  
  1487.  
  1488.  
  1489. //----------------------------------------------------------------------------
  1490. int CSizeDockBar::ShrinkRowToLeft(int nPos, int nOrigAmount, BOOL bApply, int * pnFlexBars)
  1491. // amount to shrink row to left.
  1492. // nPos = current pane: nPos -1 = pane to go for:
  1493. // return value = amount of space we actually sized
  1494. // bApply: if TRUE, apply changes to bar sizes
  1495. //----------------------------------------------------------------------------
  1496. {
  1497.     ASSERT(nPos >= 0 && nPos <= m_arrBars.GetSize());
  1498.  
  1499.     int nAmount = nOrigAmount;
  1500.     int nFlexBars = 0;
  1501.     while (nPos >= 0)
  1502.     {
  1503.         if (m_arrBars[nPos] == NULL)
  1504.             break;
  1505.         CMRCSizeControlBar * pBar = (CMRCSizeControlBar *)GetDockedControlBar(nPos);
  1506.         if (pBar!= NULL && IsSizeable(pBar) && pBar->IsVisible())
  1507.         {
  1508.             nFlexBars ++;
  1509.             if (IsBarHorizontal())
  1510.             {
  1511.                 if (pBar->m_HorzDockSize.cx >= nAmount)
  1512.                 {
  1513.                     if (bApply)
  1514.                         pBar->m_HorzDockSize.cx -= nAmount;
  1515.                     nAmount = 0;
  1516.                     break;
  1517.                 }
  1518.                 else
  1519.                 {
  1520.                     nAmount -= pBar->m_HorzDockSize.cx;
  1521.                     if (bApply)
  1522.                         pBar->m_HorzDockSize.cx = 0;
  1523.                 }
  1524.             }
  1525.             else
  1526.             {
  1527.                 if (pBar->m_VertDockSize.cy >= nAmount)
  1528.                 {
  1529.                     if (bApply)
  1530.                         pBar->m_VertDockSize.cy -= nAmount;
  1531.                     nAmount = 0;
  1532.                     break;
  1533.                 }
  1534.                 else
  1535.                 {
  1536.                     if (bApply)
  1537.                         pBar->m_VertDockSize.cy = 0;
  1538.                     nAmount -= pBar->m_VertDockSize.cy;
  1539.                 }
  1540.             }
  1541.  
  1542.         }
  1543.         nPos--;
  1544.     }
  1545.  
  1546.     // return no of flexible components encountered (if pointer supplied)
  1547.     if (pnFlexBars != NULL)
  1548.         *pnFlexBars = nFlexBars;
  1549.  
  1550.     // reached left/top of row - return what size is still left to allocate
  1551.     return (nOrigAmount - nAmount);
  1552. }
  1553.  
  1554.  
  1555. //----------------------------------------------------------------------------
  1556. int CSizeDockBar::ShrinkRowToRight(int nPos, int nOrigAmount, BOOL bApply, int *pnFlexBars)
  1557. // amount to shrink row to right.
  1558. // nPos = current pane: nPos -1 = pane to go for:
  1559. // return value = amount of space we actually sized
  1560. //----------------------------------------------------------------------------
  1561. {
  1562.     ASSERT(nPos >= 0 && nPos <= m_arrBars.GetSize());
  1563.     int nAmount = nOrigAmount;
  1564.     int nFlexBars = 0;
  1565.  
  1566.     CMRCSizeControlBar * pLastBar = NULL;
  1567.  
  1568.     while (nPos < m_arrBars.GetSize())
  1569.     {
  1570.         if (m_arrBars[nPos] == NULL)
  1571.             break;
  1572.  
  1573.         CMRCSizeControlBar * pBar = (CMRCSizeControlBar *)GetDockedControlBar(nPos);
  1574.         if (pBar != NULL)
  1575.         {                
  1576.             pLastBar = pBar;
  1577.             if (IsSizeable(pBar) && pBar->IsVisible())
  1578.             {
  1579.                 nFlexBars ++;
  1580.                 if (IsBarHorizontal())
  1581.                 {
  1582.                     if (pBar->m_HorzDockSize.cx >= nAmount)
  1583.                     {
  1584.                         if (bApply)
  1585.                             pBar->m_HorzDockSize.cx -= nAmount;
  1586.                         nAmount = 0;
  1587.                         break;
  1588.                     }
  1589.                     else
  1590.                     {
  1591.                         nAmount -= pBar->m_HorzDockSize.cx;
  1592.                         if (bApply)
  1593.                             pBar->m_HorzDockSize.cx = 0;
  1594.                     }
  1595.                 }
  1596.                 else        // Vertical
  1597.                 {
  1598.                     if (pBar->m_VertDockSize.cy >= nAmount)
  1599.                     {
  1600.                         if (bApply)
  1601.                             pBar->m_VertDockSize.cy -= nAmount;
  1602.                         nAmount = 0;
  1603.                         break;
  1604.                     }
  1605.                     else
  1606.                     {
  1607.                         nAmount -= pBar->m_VertDockSize.cy;
  1608.                         if (bApply)
  1609.                             pBar->m_VertDockSize.cy = 0;
  1610.                     }
  1611.                 }
  1612.                 
  1613.             }
  1614.         }
  1615.         nPos++;
  1616.     }
  1617.     // 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
  1618.     // is a flexble area at the end of the control bars..
  1619.     if (nAmount > 0 && pLastBar != NULL)
  1620.     {
  1621.         int nSub;
  1622.         CRect rect;
  1623.         pLastBar->GetWindowRect(&rect);
  1624.         ScreenToClient(&rect);
  1625.         if (IsBarHorizontal())
  1626.             nSub = m_LayoutSize.cx - rect.right;
  1627.         else
  1628.             nSub = m_LayoutSize.cy - rect.bottom;
  1629.         nAmount -= min (max( 0, nSub), nAmount);
  1630.     }
  1631.  
  1632.     // return no of flexible components encountered (if pointer supplied)
  1633.     if (pnFlexBars != NULL)
  1634.         *pnFlexBars = nFlexBars;
  1635.  
  1636.     // return amount allocated
  1637.     return (nOrigAmount - nAmount);
  1638. }
  1639.  
  1640.  
  1641.  
  1642. //---------------------------------------------------------------------------
  1643. CMRCSizeControlBar * CSizeDockBar::GetFirstControlBar()
  1644. // returns the first bar in the array - NULL if none
  1645. // used by the simplistic floating size routine
  1646. //---------------------------------------------------------------------------
  1647. {
  1648.     // CMiniDockFrameWnd assumes that if there's only one bar, then it's at position 1
  1649.     // in the array
  1650.     // need to make a check for 0 sized array however
  1651.     if (m_arrBars.GetSize() > 1)
  1652.         return ((CMRCSizeControlBar *) m_arrBars[1]);
  1653.     else
  1654.         return NULL;
  1655. }
  1656.  
  1657.  
  1658. //---------------------------------------------------------------------------
  1659. BOOL CSizeDockBar::IsRowSizeable(int nPos)
  1660. // returns TRUE if a CControlBar in the row is sizeable;
  1661. // intended to determine if the row should contain a splitter or not
  1662. //---------------------------------------------------------------------------
  1663. {
  1664.     ASSERT(nPos >= 0 && nPos < m_arrBars.GetSize());
  1665.     while (nPos < m_arrBars.GetSize())
  1666.     {
  1667.         if (m_arrBars[nPos] == NULL)
  1668.             break;
  1669.         CControlBar *pBar = GetDockedControlBar(nPos);
  1670.         if (pBar!= NULL && IsSizeable(pBar)  && pBar->IsVisible())
  1671.             return TRUE;
  1672.         nPos++;
  1673.     }
  1674.     return FALSE;
  1675. }
  1676.  
  1677.  
  1678. //-------------------------------------------------------------------------
  1679. int CSizeDockBar::TestInsertPosition(CControlBar* pBarIns, CRect rect)
  1680. // Essentially the same as CDockBar::Insert(). Returns the position in the 
  1681. // bar array that the object will be inserted.
  1682. // nPos = 0 => before first position... But will have to check if this dockbar
  1683. // is the same as the present one...(perhaps)
  1684. //-------------------------------------------------------------------------
  1685. {
  1686.     CPoint ptMid(rect.left + rect.Width()/2, rect.top + rect.Height()/2);
  1687.     // hang-on: Don't we want to work in client co-ords ???
  1688.     ScreenToClient(&ptMid);
  1689.     
  1690.     ASSERT_VALID(this);
  1691.     ASSERT(pBarIns != NULL);
  1692.  
  1693.     int nPos = 0;
  1694.     int nPosInsAfter = 0;
  1695.     int nWidth = 0;
  1696.     int nTotalWidth = 0;
  1697.     BOOL bHorz = m_dwStyle & CBRS_ORIENT_HORZ ? TRUE : FALSE;
  1698.  
  1699.     for (nPos = 0; nPos < m_arrBars.GetSize(); nPos++)
  1700.     {
  1701.         void * pVoid = m_arrBars[nPos];
  1702.         CControlBar* pBar = GetDockedControlBar(nPos);
  1703.  
  1704.         if (pVoid == NULL)
  1705.         {
  1706.             nTotalWidth += nWidth - afxData.cyBorder2;
  1707.             nWidth = 0;
  1708.             if ((bHorz ? ptMid.y : ptMid.x) < nTotalWidth)
  1709.             {
  1710.                 if (nPos == 0) // ie in first section....
  1711.                     return 0;  // indicate before first position....
  1712.             //    if (nPos == 0) // first section
  1713.             //        m_arrBars.InsertAt(nPosInsAfter+1, (CObject*)NULL);
  1714.             //    m_arrBars.InsertAt(nPosInsAfter+1, pBarIns);
  1715.                 return nPosInsAfter+1;
  1716.             }
  1717.             nPosInsAfter = nPos;
  1718.         }
  1719.         else
  1720.             if (pBar != NULL && pBar->IsVisible())    
  1721.             {
  1722.                 CRect rectBar;
  1723.                 pBar->GetWindowRect(&rectBar);
  1724.                 ScreenToClient(&rectBar);
  1725.                 nWidth = max(nWidth,
  1726.                     bHorz ? rectBar.Size().cy : rectBar.Size().cx - 1);
  1727.                 //if (bHorz ? rect.left > rectBar.left : rect.top > rectBar.top)
  1728.                 // don't need above test - only interested if it should go on the row or not...
  1729.                 nPosInsAfter = nPos;
  1730.             }
  1731.     }
  1732.  
  1733.     return nPosInsAfter+1;
  1734. }
  1735.  
  1736.  
  1737. //---------------------------------------------------------------------------
  1738. int CSizeDockBar::BarsOnThisRow(CControlBar *pBarIns, CRect rect)
  1739. // returns no of bars that will be in the row (excluding the one to be inserted)
  1740. //---------------------------------------------------------------------------
  1741. {
  1742.     int nPos = TestInsertPosition(pBarIns, rect);
  1743.     
  1744.     // if inserting before the first row, or after the last row, then return 0
  1745.     // (there are no bars on this row).
  1746.     if (nPos == 0 ||nPos > m_arrBars.GetUpperBound())        // case if inserting before first bar in the array.
  1747.         return 0;        // return 0 to use the full size
  1748.     
  1749.     // go back to start of row.
  1750.     while (nPos != 0 && m_arrBars[nPos - 1] != 0)
  1751.         nPos --;
  1752.  
  1753.     int nCount = 0;
  1754.     while (TRUE)
  1755.     {
  1756.         void * pVoid = m_arrBars[nPos];
  1757.         CControlBar * pBar = GetDockedControlBar(nPos);
  1758.         if (pVoid == NULL)
  1759.             break;
  1760.         if (pBar != NULL && pBar != pBarIns) 
  1761.             nCount++;
  1762.         nPos++;
  1763.     }
  1764.     return nCount;
  1765. }
  1766.  
  1767.  
  1768.  
  1769. CMRCRectTracker::CMRCRectTracker()
  1770. {
  1771.     m_LimitRect.SetRectEmpty();
  1772. }
  1773.  
  1774.  
  1775.  
  1776.  
  1777. //------------------------------------------------------------------------------
  1778. BOOL CMRCRectTracker::TrackFromHitTest(int nHitTest, CWnd* pWnd, CPoint point,
  1779.     CWnd* pWndClipTo, BOOL bAllowInvert)
  1780. //------------------------------------------------------------------------------
  1781. {
  1782.     m_OrigRect = m_rect;        // save original rectangle
  1783.     m_bAllowInvert = bAllowInvert;
  1784.     int nHandle;
  1785.     switch (nHitTest)
  1786.     {
  1787.     case HTLEFT:
  1788.         nHandle = hitLeft;
  1789.         break;
  1790.     case HTRIGHT:
  1791.         nHandle = hitRight;
  1792.         break;
  1793.     case HTTOP:         
  1794.         nHandle = hitTop;
  1795.         break;
  1796.     case HTTOPLEFT:    
  1797.         nHandle = hitTopLeft;
  1798.         break;
  1799.     case HTTOPRIGHT:    
  1800.         nHandle = hitTopRight;
  1801.         break;
  1802.     case HTBOTTOM:      
  1803.         nHandle = hitBottom;
  1804.         break;
  1805.     case HTBOTTOMLEFT:  
  1806.         nHandle = hitBottomLeft;
  1807.         break;
  1808.     case HTBOTTOMRIGHT: 
  1809.         nHandle = hitBottomRight;
  1810.         break;
  1811.     default:
  1812.         nHandle = hitMiddle;        // default is move
  1813.         break;
  1814.     }
  1815.  
  1816.     return CRectTracker::TrackHandle(nHandle, pWnd, point, pWndClipTo);
  1817. }
  1818.  
  1819.  
  1820.  
  1821.  
  1822. //-----------------------------------------------------------------------------
  1823. void CMRCRectTracker::DrawTrackerRect(LPCRECT lpRect, CWnd* pWndClipTo, CDC* pDC, CWnd* pWnd)
  1824. //-----------------------------------------------------------------------------
  1825. {
  1826.     // first, normalize the rectangle for drawing
  1827.     CRect rect = *lpRect;
  1828.     rect.NormalizeRect();
  1829.  
  1830.     // convert to client coordinates
  1831.     if (pWndClipTo != NULL)
  1832.     {
  1833.         pWnd->ClientToScreen(&rect);
  1834.         pWndClipTo->ScreenToClient(&rect);
  1835.     }
  1836.     CSize size(0, 0);
  1837.     if (!m_bFinalErase)
  1838.     {
  1839.         size.cx = 2;
  1840.         size.cy = 2;
  1841.     }
  1842.     // and draw it
  1843.     if (m_bFinalErase || !m_bErase)
  1844.         pDC->DrawDragRect(rect, size, m_rectLast, m_sizeLast);
  1845.     m_rectLast = rect;
  1846.     m_sizeLast = size; 
  1847. }
  1848.  
  1849.  
  1850. //-----------------------------------------------------------------------------
  1851. void CMRCRectTracker::AdjustRect(int nHandle, LPRECT lpRect)
  1852. //-----------------------------------------------------------------------------
  1853. {
  1854. // clips to limiting rectangle...
  1855.     if (!m_LimitRect.IsRectNull())
  1856.     {
  1857.         if (nHandle == hitMiddle)  // if moving then have to ensure size is maintained...
  1858.         {
  1859.             CSize size = m_OrigRect.Size();
  1860.             lpRect->left = max (m_LimitRect.left , min (m_LimitRect.right , lpRect->left));
  1861.             lpRect->top =  max (m_LimitRect.top  , min (m_LimitRect.bottom - 10, lpRect->top ));
  1862.             lpRect->right  = lpRect->left + size.cx;
  1863.             lpRect->bottom = lpRect->top  + size.cy;
  1864.         }
  1865.         else
  1866.         {        
  1867.             CRect iRect;
  1868.             iRect.IntersectRect(m_LimitRect, lpRect);
  1869.             ::CopyRect(lpRect, iRect);        
  1870.         }
  1871.     }
  1872.  
  1873. // enforces minimum width, etc
  1874.     CRectTracker::AdjustRect(nHandle, lpRect);
  1875.  
  1876.     if (m_nStyle & RectTracker_OnlyMoveHorz)
  1877.     {
  1878.         lpRect->top = m_OrigRect.top;
  1879.         lpRect->bottom = m_OrigRect.bottom;
  1880.     }
  1881.     
  1882.     if (m_nStyle & RectTracker_OnlyMoveVert)
  1883.     {
  1884.         lpRect->left = m_OrigRect.left;
  1885.         lpRect->right = m_OrigRect.right;
  1886.     }
  1887.     
  1888. }
  1889.