sizecbar.cpp
上传用户:maryhy001
上传日期:2007-05-02
资源大小:2317k
文件大小:32k
源码类别:

网格计算

开发平台:

Visual C++

  1. /////////////////////////////////////////////////////////////////////////
  2. // Copyright (C) 1998, 1999 by Cristi Posea
  3. // All rights reserved
  4. //
  5. // Use and distribute freely, except: don't remove my name from the
  6. // source or documentation (don't take credit for my work), mark your
  7. // changes (don't get me blamed for your possible bugs), don't alter
  8. // or remove this notice.
  9. // No warrantee of any kind, express or implied, is included with this
  10. // software; use at your own risk, responsibility for damages (if any) to
  11. // anyone resulting from the use of this software rests entirely with the
  12. // user.
  13. //
  14. // This class is intended to be used as a base class. Do not simply add
  15. // your code to this file - instead create a new class derived from
  16. // CSizingControlBar and put there what you need.
  17. // Modify this file only to fix bugs, and don't forget to send me a copy.
  18. //
  19. // Send bug reports, bug fixes, enhancements, requests, flames, etc.,
  20. // and I'll try to keep a version up to date.  I can be reached at:
  21. //    cristip@dundas.com
  22. //
  23. // More details at MFC Programmer's SourceBook
  24. // http://www.codeguru.com/docking/docking_window.shtml or search
  25. // www.codeguru.com for my name if the article was moved.
  26. //
  27. /////////////////////////////////////////////////////////////////////////
  28. //
  29. // Acknowledgements:
  30. //  o   Thanks to Harlan R. Seymour (harlans@dundas.com) for his continuous
  31. //      support during development of this code.
  32. //  o   Thanks to Dundas Software for the opportunity to test this code
  33. //      on real-life applications.
  34. //      If you don't know who they are, visit them at www.dundas.com .
  35. //      Their award winning components and development suites are
  36. //      a pile of gold.
  37. //  o   Thanks to Chris Maunder (chrism@dundas.com) who came with the
  38. //      simplest way to query "Show window content while dragging" system
  39. //      setting.
  40. //  o   Thanks to Zafir Anjum (zafir@codeguru.com) for publishing this
  41. //      code on his cool site (www.codeguru.com).
  42. //  o   Some ideas for the gripper came from the CToolBarEx flat toolbar
  43. //      by Joerg Koenig (Joerg.Koenig@rhein-neckar.de). Also he inspired
  44. //      me on writing this notice:) . Thanks, Joerg!
  45. //  o   Thanks to Jakawan Ratiwanich (jack@alpha.fsec.ucf.edu) and to
  46. //      Udo Schaefer (Udo.Schaefer@vcase.de) for the dwStyle bug fix under
  47. //      VC++ 6.0.
  48. //  o   And, of course, many thanks to all of you who used this code,
  49. //      for the invaluable feedback I received.
  50. //      
  51. /////////////////////////////////////////////////////////////////////////
  52. // sizecbar.cpp : implementation file
  53. //
  54. #include "stdafx.h"
  55. #include "sizecbar.h"
  56. #ifdef _DEBUG
  57. #define new DEBUG_NEW
  58. #undef THIS_FILE
  59. static char THIS_FILE[] = __FILE__;
  60. #endif
  61. /////////////////////////////////////////////////////////////////////////
  62. // CSizingControlBar
  63. CSCBArray CSizingControlBar::m_arrBars; // static member
  64. IMPLEMENT_DYNAMIC(CSizingControlBar, baseCSizingControlBar);
  65. CSizingControlBar::CSizingControlBar()
  66. {
  67.     m_szMin = CSize(33, 32);
  68.     m_szHorz = CSize(200, 200);
  69.     m_szVert = CSize(200, 200);
  70.     m_szFloat = CSize(200, 200);
  71.     m_bTracking = FALSE;
  72.     m_bKeepSize = FALSE;
  73.     m_bParentSizing = FALSE;
  74.     m_cxEdge = 5;
  75.     m_bDragShowContent = FALSE;
  76.     m_nDockBarID = 0;
  77.     m_dwSCBStyle = 0;
  78. }
  79. CSizingControlBar::~CSizingControlBar()
  80. {
  81. }
  82. BEGIN_MESSAGE_MAP(CSizingControlBar, baseCSizingControlBar)
  83.     //{{AFX_MSG_MAP(CSizingControlBar)
  84.     ON_WM_CREATE()
  85.     ON_WM_PAINT()
  86.     ON_WM_NCPAINT()
  87.     ON_WM_NCCALCSIZE()
  88.     ON_WM_WINDOWPOSCHANGING()
  89.     ON_WM_CAPTURECHANGED()
  90.     ON_WM_SETTINGCHANGE()
  91.     ON_WM_LBUTTONUP()
  92.     ON_WM_MOUSEMOVE()
  93.     ON_WM_NCLBUTTONDOWN()
  94.     ON_WM_LBUTTONDOWN()
  95.     ON_WM_LBUTTONDBLCLK()
  96.     ON_WM_RBUTTONDOWN()
  97.     ON_WM_NCLBUTTONUP()
  98.     ON_WM_NCMOUSEMOVE()
  99.     ON_WM_NCHITTEST()
  100.     //}}AFX_MSG_MAP
  101. END_MESSAGE_MAP()
  102. BOOL CSizingControlBar::Create(LPCTSTR lpszWindowName, CWnd* pParentWnd,
  103.                                CSize sizeDefault, BOOL bHasGripper,
  104.                                UINT nID, DWORD dwStyle)
  105. {
  106.     // must have a parent
  107.     ASSERT_VALID(pParentWnd);
  108.     // cannot be both fixed and dynamic
  109.     // (CBRS_SIZE_DYNAMIC is used for resizng when floating)
  110.     ASSERT (!((dwStyle & CBRS_SIZE_FIXED) &&
  111.               (dwStyle & CBRS_SIZE_DYNAMIC)));
  112.     m_dwStyle = dwStyle & CBRS_ALL; // save the control bar styles
  113.     m_szHorz = sizeDefault; // set the size members
  114.     m_szVert = sizeDefault;
  115.     m_szFloat = sizeDefault;
  116.     m_cyGripper = bHasGripper ? 12 : 0; // set the gripper width
  117.     // register and create the window - skip CControlBar::Create()
  118.     CString wndclass = ::AfxRegisterWndClass(CS_DBLCLKS,
  119.         ::LoadCursor(NULL, IDC_ARROW),
  120.         ::GetSysColorBrush(COLOR_BTNFACE), 0);
  121.     dwStyle &= ~CBRS_ALL; // keep only the generic window styles
  122.     dwStyle |= WS_CLIPCHILDREN; // prevents flashing
  123.     if (!CWnd::Create(wndclass, lpszWindowName, dwStyle,
  124.         CRect(0, 0, 0, 0), pParentWnd, nID))
  125.         return FALSE;
  126.     return TRUE;
  127. }
  128. /////////////////////////////////////////////////////////////////////////
  129. // CSizingControlBar message handlers
  130. int CSizingControlBar::OnCreate(LPCREATESTRUCT lpCreateStruct) 
  131. {
  132.     if (baseCSizingControlBar::OnCreate(lpCreateStruct) == -1)
  133.         return -1;
  134.     
  135.     // querry SPI_GETDRAGFULLWINDOWS system parameter
  136.     // OnSettingChange() will update m_bDragShowContent
  137.     m_bDragShowContent = FALSE;
  138.     ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0,
  139.         &m_bDragShowContent, 0);
  140.     m_arrBars.Add(this);        // register
  141.     
  142. //    m_dwSCBStyle |= SCBS_SHOWEDGES;
  143.     return 0;
  144. }
  145. BOOL CSizingControlBar::DestroyWindow() 
  146. {
  147.     int nPos = FindSizingBar(this);
  148.     ASSERT(nPos >= 0);
  149.     m_arrBars.RemoveAt(nPos);   // unregister
  150.     return baseCSizingControlBar::DestroyWindow();
  151. }
  152. const BOOL CSizingControlBar::IsFloating() const
  153. {
  154.     return !IsHorzDocked() && !IsVertDocked();
  155. }
  156. const BOOL CSizingControlBar::IsHorzDocked() const
  157. {
  158.     return (m_nDockBarID == AFX_IDW_DOCKBAR_TOP ||
  159.         m_nDockBarID == AFX_IDW_DOCKBAR_BOTTOM);
  160. }
  161. const BOOL CSizingControlBar::IsVertDocked() const
  162. {
  163.     return (m_nDockBarID == AFX_IDW_DOCKBAR_LEFT ||
  164.         m_nDockBarID == AFX_IDW_DOCKBAR_RIGHT);
  165. }
  166. const BOOL CSizingControlBar::IsSideTracking() const
  167. {
  168.     // don't call this when not tracking
  169.     ASSERT(m_bTracking && !IsFloating());
  170.     return (m_htEdge == HTLEFT || m_htEdge == HTRIGHT) ?
  171.         IsHorzDocked() : IsVertDocked();
  172. }
  173. CSize CSizingControlBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
  174. {
  175.     if (bStretch) // the bar is stretched (is not the child of a dockbar)
  176.         if (bHorz)
  177.             return CSize(32767, m_szHorz.cy);
  178.         else
  179.             return CSize(m_szVert.cx, 32767);
  180.     // dirty cast - using CSCBDockBar to access protected CDockBar members
  181.     CSCBDockBar* pDockBar = (CSCBDockBar*) m_pDockBar;
  182.     // force imediate RecalcDelayShow() for all sizing bars on the row
  183.     // with delayShow/delayHide flags set to avoid IsVisible() problems
  184.     CSCBArray arrSCBars;
  185.     GetRowSizingBars(arrSCBars);
  186.     AFX_SIZEPARENTPARAMS layout;
  187.     layout.hDWP = pDockBar->m_bLayoutQuery ?
  188.         NULL : ::BeginDeferWindowPos(arrSCBars.GetSize());
  189.     for (int i = 0; i < arrSCBars.GetSize(); i++)
  190.         arrSCBars[i]->RecalcDelayShow(&layout);
  191.     if (layout.hDWP != NULL)
  192.         ::EndDeferWindowPos(layout.hDWP);
  193.     // get available length
  194.     CRect rc = pDockBar->m_rectLayout;
  195.     if (rc.IsRectEmpty())
  196.         m_pDockSite->GetClientRect(&rc);
  197.     int nLengthAvail = bHorz ? rc.Width() + 2 : rc.Height() - 2;
  198.     if (IsVisible() && !IsFloating() &&
  199.         m_bParentSizing && arrSCBars[0] == this)
  200.         if (NegociateSpace(nLengthAvail, (bHorz != FALSE)))
  201.             AlignControlBars();
  202.     m_bParentSizing = FALSE;
  203.     
  204.     CSize szRet = bHorz ? m_szHorz : m_szVert;
  205.     szRet.cx = max(m_szMin.cx, szRet.cx);
  206.     szRet.cy = max(m_szMin.cy, szRet.cy);
  207.     return szRet;
  208. }
  209. CSize CSizingControlBar::CalcDynamicLayout(int nLength, DWORD dwMode)
  210. {
  211.     if (dwMode & (LM_HORZDOCK | LM_VERTDOCK)) // docked ?
  212.     {
  213.         if (nLength == -1)
  214.             m_bParentSizing = TRUE;
  215.         return baseCSizingControlBar::CalcDynamicLayout(nLength, dwMode);
  216.     }
  217.     if (dwMode & LM_MRUWIDTH) return m_szFloat;
  218.     if (dwMode & LM_COMMIT) return m_szFloat; // already committed
  219.     ((dwMode & LM_LENGTHY) ? m_szFloat.cy : m_szFloat.cx) = nLength;
  220.     m_szFloat.cx = max(m_szFloat.cx, m_szMin.cx);
  221.     m_szFloat.cy = max(m_szFloat.cy, m_szMin.cy);
  222.     return m_szFloat;
  223. }
  224. void CSizingControlBar::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos)
  225. {
  226.     // force non-client recalc if moved or resized
  227.     lpwndpos->flags |= SWP_FRAMECHANGED;
  228.     baseCSizingControlBar::OnWindowPosChanging(lpwndpos);
  229.     // find on which side are we docked
  230.     UINT nOldDockBarID = m_nDockBarID;
  231.     m_nDockBarID = GetParent()->GetDlgCtrlID();
  232.     if (!IsFloating())
  233.         if (lpwndpos->flags & SWP_SHOWWINDOW)
  234.             m_bKeepSize = TRUE;
  235. }
  236. /////////////////////////////////////////////////////////////////////////
  237. // Mouse Handling
  238. //
  239. void CSizingControlBar::OnLButtonDown(UINT nFlags, CPoint point) 
  240. {
  241.     if (m_pDockBar != NULL)
  242.     {
  243.         // start the drag
  244.         ASSERT(m_pDockContext != NULL);
  245.         ClientToScreen(&point);
  246.         m_pDockContext->StartDrag(point);
  247.     }
  248.     else
  249.         CWnd::OnLButtonDown(nFlags, point);
  250. }
  251. void CSizingControlBar::OnLButtonDblClk(UINT nFlags, CPoint point) 
  252. {
  253.     if (m_pDockBar != NULL)
  254.     {
  255.         // toggle docking
  256.         ASSERT(m_pDockContext != NULL);
  257.         m_pDockContext->ToggleDocking();
  258.     }
  259.     else
  260.         CWnd::OnLButtonDblClk(nFlags, point);
  261. }
  262. void CSizingControlBar::OnNcLButtonDown(UINT nHitTest, CPoint point) 
  263. {
  264.     if (IsFloating())
  265.     {
  266.         baseCSizingControlBar::OnNcLButtonDown(nHitTest, point);
  267.         return;
  268.     }
  269.     if (m_bTracking) return;
  270.     if ((nHitTest >= HTSIZEFIRST) && (nHitTest <= HTSIZELAST))
  271.         StartTracking(nHitTest); // sizing edge hit
  272. }
  273. void CSizingControlBar::OnNcLButtonUp(UINT nHitTest, CPoint point) 
  274. {
  275.     if (nHitTest == HTCLOSE)
  276.         m_pDockSite->ShowControlBar(this, FALSE, FALSE); // hide
  277.     baseCSizingControlBar::OnNcLButtonUp(nHitTest, point);
  278. }
  279. void CSizingControlBar::OnLButtonUp(UINT nFlags, CPoint point) 
  280. {
  281.     if (m_bTracking)
  282.         StopTracking();
  283.     baseCSizingControlBar::OnLButtonUp(nFlags, point);
  284. }
  285. void CSizingControlBar::OnRButtonDown(UINT nFlags, CPoint point) 
  286. {
  287.     if (m_bTracking)
  288.         StopTracking();
  289.     
  290.     baseCSizingControlBar::OnRButtonDown(nFlags, point);
  291. }
  292. void CSizingControlBar::OnMouseMove(UINT nFlags, CPoint point) 
  293. {
  294.     if (m_bTracking)
  295.         OnTrackUpdateSize(point);
  296.     
  297.     baseCSizingControlBar::OnMouseMove(nFlags, point);
  298. }
  299. void CSizingControlBar::OnCaptureChanged(CWnd *pWnd) 
  300. {
  301.     if (m_bTracking && (pWnd != this))
  302.         StopTracking();
  303.     baseCSizingControlBar::OnCaptureChanged(pWnd);
  304. }
  305. void CSizingControlBar::OnNcCalcSize(BOOL bCalcValidRects,
  306.                                      NCCALCSIZE_PARAMS FAR* lpncsp) 
  307. {
  308.     // compute the the client area
  309.     CRect rcClient = lpncsp->rgrc[0];
  310.     rcClient.DeflateRect(5, 5);
  311.     m_dwSCBStyle &= ~SCBS_EDGEALL;
  312.     switch(m_nDockBarID)
  313.     {
  314.     case AFX_IDW_DOCKBAR_TOP:
  315.         m_dwSCBStyle |= SCBS_EDGEBOTTOM;
  316.         rcClient.DeflateRect(m_cyGripper, 0, 0, 0);
  317.         break;
  318.     case AFX_IDW_DOCKBAR_BOTTOM:
  319.         m_dwSCBStyle |= SCBS_EDGETOP;
  320.         rcClient.DeflateRect(m_cyGripper, 0, 0, 0);
  321.         break;
  322.     case AFX_IDW_DOCKBAR_LEFT:
  323.         m_dwSCBStyle |= SCBS_EDGERIGHT;
  324.         rcClient.DeflateRect(0, m_cyGripper, 0, 0);
  325.         break;
  326.     case AFX_IDW_DOCKBAR_RIGHT:
  327.         m_dwSCBStyle |= SCBS_EDGELEFT;
  328.         rcClient.DeflateRect(0, m_cyGripper, 0, 0);
  329.         break;
  330.     default:
  331.         break;
  332.     }
  333.     if (!IsFloating() && m_pDockBar != NULL)
  334.     {
  335.         CSCBArray arrSCBars;
  336.         GetRowSizingBars(arrSCBars);
  337.         for (int i = 0; i < arrSCBars.GetSize(); i++)
  338.             if (arrSCBars[i] == this)
  339.             {
  340.                 if (i > 0)
  341.                     m_dwSCBStyle |= IsHorzDocked() ?
  342.                         SCBS_EDGELEFT : SCBS_EDGETOP;
  343.                 if (i < arrSCBars.GetSize() - 1)
  344.                     m_dwSCBStyle |= IsHorzDocked() ?
  345.                         SCBS_EDGERIGHT : SCBS_EDGEBOTTOM;
  346.             }
  347.     }
  348.     // make room for edges only if they will be painted
  349.     if (m_dwSCBStyle & SCBS_SHOWEDGES)
  350.         rcClient.DeflateRect(
  351.             (m_dwSCBStyle & SCBS_EDGELEFT) ? m_cxEdge : 0,
  352.             (m_dwSCBStyle & SCBS_EDGETOP) ? m_cxEdge : 0,
  353.             (m_dwSCBStyle & SCBS_EDGERIGHT) ? m_cxEdge : 0,
  354.             (m_dwSCBStyle & SCBS_EDGEBOTTOM) ? m_cxEdge : 0);
  355.     // "hide" button positioning
  356.     CPoint ptOrgBtn;
  357.     if (IsHorzDocked())
  358.         ptOrgBtn = CPoint(rcClient.left - m_cyGripper - 1,
  359.             rcClient.top - 1);
  360.     else
  361.         ptOrgBtn = CPoint(rcClient.right - 11,
  362.             rcClient.top - m_cyGripper - 1);
  363.     m_biHide.Move(ptOrgBtn - CRect(lpncsp->rgrc[0]).TopLeft());
  364.     lpncsp->rgrc[0] = rcClient;
  365. }
  366. void CSizingControlBar::OnNcPaint() 
  367. {
  368.     // get window DC that is clipped to the non-client area
  369.     CWindowDC dc(this);
  370.     CRect rcClient, rcBar;
  371.     GetClientRect(rcClient);
  372.     ClientToScreen(rcClient);
  373.     GetWindowRect(rcBar);
  374.     rcClient.OffsetRect(-rcBar.TopLeft());
  375.     rcBar.OffsetRect(-rcBar.TopLeft());
  376.     // client area is not our bussiness :)
  377.     dc.ExcludeClipRect(rcClient);
  378.     // draw borders in non-client area
  379.     CRect rcDraw = rcBar;
  380.     DrawBorders(&dc, rcDraw);
  381.     // erase parts not drawn
  382.     dc.IntersectClipRect(rcDraw);
  383.     // erase NC background the hard way
  384.     HBRUSH hbr = (HBRUSH)GetClassLong(m_hWnd, GCL_HBRBACKGROUND);
  385.     ::FillRect(dc.m_hDC, rcDraw, hbr);
  386.     if (m_dwSCBStyle & SCBS_SHOWEDGES)
  387.     {
  388.         CRect rcEdge; // paint the sizing edges
  389.         for (int i = 0; i < 4; i++)
  390.             if (GetEdgeRect(rcBar, GetEdgeHTCode(i), rcEdge))
  391.                 dc.Draw3dRect(rcEdge, ::GetSysColor(COLOR_BTNHIGHLIGHT),
  392.                     ::GetSysColor(COLOR_BTNSHADOW));
  393.     }
  394.     if (m_cyGripper && !IsFloating())
  395.         NcPaintGripper(&dc, rcClient);
  396.     ReleaseDC(&dc);
  397. }
  398. void CSizingControlBar::NcPaintGripper(CDC* pDC, CRect rcClient)
  399. {
  400.     // paints a simple "two raised lines" gripper
  401.     // override this if you want a more sophisticated gripper
  402.     CRect gripper = rcClient;
  403.     CRect rcbtn = m_biHide.GetRect();
  404.     BOOL bHorz = IsHorzDocked();
  405.     
  406.     gripper.DeflateRect(1, 1);
  407.     if (bHorz)
  408.     {   // gripper at left
  409.         gripper.left -= m_cyGripper;
  410.         gripper.right = gripper.left + 3;
  411.         gripper.top = rcbtn.bottom + 3;
  412.     }
  413.     else
  414.     {   // gripper at top
  415.         gripper.top -= m_cyGripper;
  416.         gripper.bottom = gripper.top + 3;
  417.         gripper.right = rcbtn.left - 3;
  418.     }
  419.     pDC->Draw3dRect(gripper, ::GetSysColor(COLOR_BTNHIGHLIGHT),
  420.         ::GetSysColor(COLOR_BTNSHADOW));
  421.     gripper.OffsetRect(bHorz ? 3 : 0, bHorz ? 0 : 3);
  422.     
  423.     pDC->Draw3dRect(gripper, ::GetSysColor(COLOR_BTNHIGHLIGHT),
  424.         ::GetSysColor(COLOR_BTNSHADOW));
  425.     m_biHide.Paint(pDC);
  426. }
  427. void CSizingControlBar::OnPaint()
  428. {
  429.     // overridden to skip border painting based on clientrect
  430.     CPaintDC dc(this);
  431. }
  432. UINT CSizingControlBar::OnNcHitTest(CPoint point)
  433. {
  434.     if (IsFloating())
  435.         return baseCSizingControlBar::OnNcHitTest(point);
  436.     CRect rcBar, rcEdge;
  437.     GetWindowRect(rcBar);
  438.     for (int i = 0; i < 4; i++)
  439.         if (GetEdgeRect(rcBar, GetEdgeHTCode(i), rcEdge))
  440.             if (rcEdge.PtInRect(point)) return GetEdgeHTCode(i);
  441.     CRect rc = m_biHide.GetRect();
  442.     rc.OffsetRect(rcBar.TopLeft());
  443.     if (rc.PtInRect(point))
  444.         return HTCLOSE;
  445.     return HTCLIENT;
  446. }
  447. void CSizingControlBar::OnSettingChange(UINT uFlags, LPCTSTR lpszSection) 
  448. {
  449.     baseCSizingControlBar::OnSettingChange(uFlags, lpszSection);
  450.     m_bDragShowContent = FALSE;
  451.     ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0,
  452.         &m_bDragShowContent, 0); // update
  453. }
  454. /////////////////////////////////////////////////////////////////////////
  455. // CSizingControlBar implementation helpers
  456. void CSizingControlBar::StartTracking(UINT nHitTest)
  457. {
  458.     SetCapture();
  459.     // make sure no updates are pending
  460.     RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW);
  461.     
  462.     BOOL bHorz = IsHorzDocked();
  463.     m_szOld = bHorz ? m_szHorz : m_szVert;
  464.     CRect rc;
  465.     GetWindowRect(&rc);
  466.     CRect rcEdge;
  467.     VERIFY(GetEdgeRect(rc, nHitTest, rcEdge));
  468.     m_ptOld = rcEdge.CenterPoint();
  469.     m_htEdge = nHitTest;
  470.     m_bTracking = TRUE;
  471.     CSCBArray arrSCBars;
  472.     GetRowSizingBars(arrSCBars);
  473.     // compute the minsize as the max minsize of the sizing bars on row
  474.     m_szMinT = m_szMin;
  475.     for (int i = 0; i < arrSCBars.GetSize(); i++)
  476.         if (bHorz)
  477.             m_szMinT.cy = max(m_szMinT.cy, arrSCBars[i]->m_szMin.cy);
  478.         else
  479.             m_szMinT.cx = max(m_szMinT.cx, arrSCBars[i]->m_szMin.cx);
  480.     if (!IsSideTracking())
  481.     {
  482.         // the control bar cannot grow with more than the size of 
  483.         // remaining client area of the mainframe
  484.         m_pDockSite->RepositionBars(0, 0xFFFF, AFX_IDW_PANE_FIRST,
  485.             reposQuery, &rc, NULL, TRUE);
  486.         m_szMaxT = m_szOld + rc.Size() - CSize(4, 4);
  487.     }
  488.     else
  489.     {
  490.         // side tracking: max size is the actual size plus the amount
  491.         // the neighbour bar can be decreased to reach its minsize
  492.         for (int i = 0; i < arrSCBars.GetSize(); i++)
  493.             if (arrSCBars[i] == this) break;
  494.         CSizingControlBar* pBar = arrSCBars[i +
  495.             ((m_htEdge == HTTOP || m_htEdge == HTLEFT) ? -1 : 1)];
  496.         m_szMaxT = m_szOld + (bHorz ? pBar->m_szHorz :
  497.             pBar->m_szVert) - pBar->m_szMin;
  498.     }
  499.     OnTrackInvertTracker(); // draw tracker
  500. }
  501. void CSizingControlBar::StopTracking()
  502. {
  503.     OnTrackInvertTracker(); // erase tracker
  504.     m_bTracking = FALSE;
  505.     ReleaseCapture();
  506.     
  507.     m_pDockSite->DelayRecalcLayout();
  508. }
  509. void CSizingControlBar::OnTrackUpdateSize(CPoint& point)
  510. {
  511.     ASSERT(!IsFloating());
  512.     CPoint pt = point;
  513.     ClientToScreen(&pt);
  514.     CSize szDelta = pt - m_ptOld;
  515.     CSize sizeNew = m_szOld;
  516.     switch (m_htEdge)
  517.     {
  518.     case HTLEFT:    sizeNew -= CSize(szDelta.cx, 0); break;
  519.     case HTTOP:     sizeNew -= CSize(0, szDelta.cy); break;
  520.     case HTRIGHT:   sizeNew += CSize(szDelta.cx, 0); break;
  521.     case HTBOTTOM:  sizeNew += CSize(0, szDelta.cy); break;
  522.     }
  523.     // enforce the limits
  524.     sizeNew.cx = max(m_szMinT.cx, min(m_szMaxT.cx, sizeNew.cx));
  525.     sizeNew.cy = max(m_szMinT.cy, min(m_szMaxT.cy, sizeNew.cy));
  526.     BOOL bHorz = IsHorzDocked();
  527.     szDelta = sizeNew - (bHorz ? m_szHorz : m_szVert);
  528.     
  529.     if (szDelta == CSize(0, 0)) return; // no size change
  530.     OnTrackInvertTracker(); // erase tracker
  531.     (bHorz ? m_szHorz : m_szVert) = sizeNew; // save the new size
  532.     CSCBArray arrSCBars;
  533.     GetRowSizingBars(arrSCBars);
  534.     for (int i = 0; i < arrSCBars.GetSize(); i++)
  535.         if (!IsSideTracking())
  536.         {   // track simultaneously
  537.             CSizingControlBar* pBar = arrSCBars[i];
  538.             (bHorz ? pBar->m_szHorz.cy : pBar->m_szVert.cx) =
  539.                 bHorz ? sizeNew.cy : sizeNew.cx;
  540.         }
  541.         else
  542.         {   // adjust the neighbour's size too
  543.             if (arrSCBars[i] != this) continue;
  544.             CSizingControlBar* pBar = arrSCBars[i +
  545.                 ((m_htEdge == HTTOP || m_htEdge == HTLEFT) ? -1 : 1)];
  546.             (bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy) -=
  547.                 bHorz ? szDelta.cx : szDelta.cy;
  548.         }
  549.     OnTrackInvertTracker(); // redraw tracker at new pos
  550.     if (m_bDragShowContent)
  551.         m_pDockSite->DelayRecalcLayout();
  552. }
  553. void CSizingControlBar::OnTrackInvertTracker()
  554. {
  555.     ASSERT(m_bTracking);
  556.     if (m_bDragShowContent)
  557.         return; // don't show tracker if DragFullWindows is on
  558.     BOOL bHorz = IsHorzDocked();
  559.     CRect rc, rcBar, rcDock, rcFrame;
  560.     GetWindowRect(rcBar);
  561.     m_pDockBar->GetWindowRect(rcDock);
  562.     m_pDockSite->GetWindowRect(rcFrame);
  563.     VERIFY(GetEdgeRect(rcBar, m_htEdge, rc));
  564.     if (!IsSideTracking())
  565.         rc = bHorz ? 
  566.             CRect(rcDock.left + 1, rc.top, rcDock.right - 1, rc.bottom) :
  567.             CRect(rc.left, rcDock.top + 1, rc.right, rcDock.bottom - 1);
  568.     rc.OffsetRect(-rcFrame.TopLeft());
  569.     CSize sizeNew = bHorz ? m_szHorz : m_szVert;
  570.     CSize sizeDelta = sizeNew - m_szOld;
  571.     if (m_nDockBarID == AFX_IDW_DOCKBAR_LEFT && m_htEdge == HTTOP ||
  572.         m_nDockBarID == AFX_IDW_DOCKBAR_RIGHT && m_htEdge != HTBOTTOM ||
  573.         m_nDockBarID == AFX_IDW_DOCKBAR_TOP && m_htEdge == HTLEFT ||
  574.         m_nDockBarID == AFX_IDW_DOCKBAR_BOTTOM && m_htEdge != HTRIGHT)
  575.         sizeDelta = -sizeDelta;
  576.     rc.OffsetRect(sizeDelta);
  577.     CDC *pDC = m_pDockSite->GetDCEx(NULL,
  578.         DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
  579.     CBrush* pBrush = CDC::GetHalftoneBrush();
  580.     CBrush* pBrushOld = pDC->SelectObject(pBrush);
  581.     pDC->PatBlt(rc.left, rc.top, rc.Width(), rc.Height(), PATINVERT);
  582.     
  583.     pDC->SelectObject(pBrushOld);
  584.     m_pDockSite->ReleaseDC(pDC);
  585. }
  586. BOOL CSizingControlBar::GetEdgeRect(CRect rcWnd, UINT nHitTest,
  587.                                     CRect& rcEdge)
  588. {
  589.     rcEdge = rcWnd;
  590.     if (m_dwSCBStyle & SCBS_SHOWEDGES)
  591.         rcEdge.DeflateRect(1, 1);
  592.     BOOL bHorz = IsHorzDocked();
  593.     switch (nHitTest)
  594.     {
  595.     case HTLEFT:
  596.         if (!(m_dwSCBStyle & SCBS_EDGELEFT)) return FALSE;
  597.         rcEdge.right = rcEdge.left + m_cxEdge;
  598.         rcEdge.DeflateRect(0, bHorz ? m_cxEdge: 0);
  599.         break;
  600.     case HTTOP:
  601.         if (!(m_dwSCBStyle & SCBS_EDGETOP)) return FALSE;
  602.         rcEdge.bottom = rcEdge.top + m_cxEdge;
  603.         rcEdge.DeflateRect(bHorz ? 0 : m_cxEdge, 0);
  604.         break;
  605.     case HTRIGHT:
  606.         if (!(m_dwSCBStyle & SCBS_EDGERIGHT)) return FALSE;
  607.         rcEdge.left = rcEdge.right - m_cxEdge;
  608.         rcEdge.DeflateRect(0, bHorz ? m_cxEdge: 0);
  609.         break;
  610.     case HTBOTTOM:
  611.         if (!(m_dwSCBStyle & SCBS_EDGEBOTTOM)) return FALSE;
  612.         rcEdge.top = rcEdge.bottom - m_cxEdge;
  613.         rcEdge.DeflateRect(bHorz ? 0 : m_cxEdge, 0);
  614.         break;
  615.     default:
  616.         ASSERT(FALSE); // invalid hit test code
  617.     }
  618.     return TRUE;
  619. }
  620. UINT CSizingControlBar::GetEdgeHTCode(int nEdge)
  621. {
  622.     if (nEdge == 0) return HTLEFT;
  623.     if (nEdge == 1) return HTTOP;
  624.     if (nEdge == 2) return HTRIGHT;
  625.     if (nEdge == 3) return HTBOTTOM;
  626.     ASSERT(FALSE); // invalid edge no
  627.     return HTNOWHERE;
  628. }
  629. void CSizingControlBar::GetRowInfo(int& nFirst, int& nLast, int& nThis)
  630. {
  631.     ASSERT_VALID(m_pDockBar); // verify bounds
  632.     nThis = m_pDockBar->FindBar(this);
  633.     ASSERT(nThis != -1);
  634.     int i, nBars = m_pDockBar->m_arrBars.GetSize();
  635.     // find the first and the last bar in row
  636.     for (nFirst = -1, i = nThis - 1; i >= 0 && nFirst == -1; i--)
  637.         if (m_pDockBar->m_arrBars[i] == NULL)
  638.             nFirst = i + 1;
  639.     for (nLast = -1, i = nThis + 1; i < nBars && nLast == -1; i++)
  640.         if (m_pDockBar->m_arrBars[i] == NULL)
  641.             nLast = i - 1;
  642.     ASSERT((nLast != -1) && (nFirst != -1));
  643. }
  644. void CSizingControlBar::GetRowSizingBars(CSCBArray& arrSCBars)
  645. {
  646.     arrSCBars.RemoveAll();
  647.     int nFirst, nLast, nThis;
  648.     GetRowInfo(nFirst, nLast, nThis);
  649.     for (int i = nFirst; i <= nLast; i++)
  650.     {
  651.         CControlBar* pBar = (CControlBar*)m_pDockBar->m_arrBars[i];
  652.         if (HIWORD(pBar) == 0) continue; // placeholder
  653.         if (!pBar->IsVisible()) continue;
  654.         if (FindSizingBar(pBar) >= 0)
  655.             arrSCBars.Add((CSizingControlBar*)pBar);
  656.     }
  657. }
  658. const int CSizingControlBar::FindSizingBar(CControlBar* pBar) const
  659. {
  660.     for (int nPos = 0; nPos < m_arrBars.GetSize(); nPos++)
  661.         if (m_arrBars[nPos] == pBar)
  662.             return nPos; // got it
  663.     return -1; // not found
  664. }
  665. BOOL CSizingControlBar::NegociateSpace(int nLengthAvail, BOOL bHorz)
  666. {
  667.     ASSERT(bHorz == IsHorzDocked());
  668.     int nFirst, nLast, nThis;
  669.     GetRowInfo(nFirst, nLast, nThis);
  670.     // step 1: subtract the visible fixed bars' lengths
  671.     for (int i = nFirst; i <= nLast; i++)
  672.     {
  673.         CControlBar* pFBar = (CControlBar*)m_pDockBar->m_arrBars[i];
  674.         if (HIWORD(pFBar) == 0) continue; // placeholder
  675.         if (!pFBar->IsVisible() || (FindSizingBar(pFBar) >= 0)) continue;
  676.         CRect rcBar;
  677.         pFBar->GetWindowRect(&rcBar);
  678.         nLengthAvail -= (bHorz ? rcBar.Width() - 2 : rcBar.Height() - 2);
  679.     }
  680.     CSCBArray arrSCBars;
  681.     GetRowSizingBars(arrSCBars);
  682.     CSizingControlBar* pBar;
  683.     // step 2: compute actual and min lengths; also the common width
  684.     int nActualLength = 0;
  685.     int nMinLength = 2;
  686.     int nWidth = 0;
  687.     for (i = 0; i < arrSCBars.GetSize(); i++)
  688.     {
  689.         pBar = arrSCBars[i];
  690.         nActualLength += bHorz ? pBar->m_szHorz.cx - 2 :
  691.             pBar->m_szVert.cy - 2;
  692.         nMinLength += bHorz ? pBar->m_szMin.cx - 2:
  693.             pBar->m_szMin.cy - 2;
  694.         nWidth = max(nWidth, bHorz ? pBar->m_szHorz.cy :
  695.             pBar->m_szVert.cx);
  696.     }
  697.     
  698.     // step 3: pop the bar out of the row if not enough room
  699.     if (nMinLength > nLengthAvail)
  700.     {
  701.         if (nFirst < nThis || nThis < nLast)
  702.         {   // not enough room - create a new row
  703.             m_pDockBar->m_arrBars.InsertAt(nLast + 1, this);
  704.             m_pDockBar->m_arrBars.InsertAt(nLast + 1, (CControlBar*) NULL);
  705.             m_pDockBar->m_arrBars.RemoveAt(nThis);
  706.         }
  707.         return FALSE;
  708.     }
  709.     // step 4: make the bars same width
  710.     for (i = 0; i < arrSCBars.GetSize(); i++)
  711.         if (bHorz)
  712.             arrSCBars[i]->m_szHorz.cy = nWidth;
  713.         else
  714.             arrSCBars[i]->m_szVert.cx = nWidth;
  715.     if (nActualLength == nLengthAvail)
  716.         return TRUE; // no change
  717.     // step 5: distribute the difference between the bars, but
  718.     //         don't shrink them below minsize
  719.     int nDelta = nLengthAvail - nActualLength;
  720.     while (nDelta != 0)
  721.     {
  722.         int nDeltaOld = nDelta;
  723.         for (i = 0; i < arrSCBars.GetSize(); i++)
  724.         {
  725.             pBar = arrSCBars[i];
  726.             int nLMin = bHorz ? pBar->m_szMin.cx : pBar->m_szMin.cy;
  727.             int nL = bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy;
  728.             
  729.             if ((nL == nLMin) && (nDelta < 0) || // already at min length
  730.                 pBar->m_bKeepSize) // or wants to keep its size
  731.                 continue;
  732.             
  733.             // sign of nDelta
  734.             int nDelta2 = (nDelta == 0) ? 0 : ((nDelta < 0) ? -1 : 1);
  735.             (bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy) += nDelta2;
  736.             nDelta -= nDelta2;
  737.             if (nDelta == 0) break;
  738.         }
  739.         // clear m_bKeepSize flags
  740.         if ((nDeltaOld == nDelta) || (nDelta == 0))
  741.             for (i = 0; i < arrSCBars.GetSize(); i++)
  742.                 arrSCBars[i]->m_bKeepSize = FALSE;
  743.     }
  744.     return TRUE;
  745. }
  746. void CSizingControlBar::AlignControlBars()
  747. {
  748.     int nFirst, nLast, nThis;
  749.     GetRowInfo(nFirst, nLast, nThis);
  750.     BOOL bHorz = IsHorzDocked();
  751.     BOOL bNeedRecalc = FALSE;
  752.     int nPos, nAlign = bHorz ? -2 : 0;
  753.     CRect rc, rcDock;
  754.     m_pDockBar->GetWindowRect(&rcDock);
  755.     for (int i = nFirst; i <= nLast; i++)
  756.     {
  757.         CControlBar* pBar = (CControlBar*)m_pDockBar->m_arrBars[i];
  758.         if (HIWORD(pBar) == 0) continue; // placeholder
  759.         if (!pBar->IsVisible()) continue;
  760.         pBar->GetWindowRect(&rc);
  761.         rc.OffsetRect(-rcDock.TopLeft());
  762.         if ((nPos = FindSizingBar(pBar)) >= 0)
  763.             rc = CRect(rc.TopLeft(), bHorz ?
  764.                 m_arrBars[nPos]->m_szHorz : m_arrBars[nPos]->m_szVert);
  765.         if ((bHorz ? rc.left : rc.top) != nAlign)
  766.         {
  767.             if (!bHorz)
  768.                 rc.OffsetRect(0, nAlign - rc.top - 2);
  769.             else if (m_nDockBarID == AFX_IDW_DOCKBAR_TOP)
  770.                 rc.OffsetRect(nAlign - rc.left, -2);
  771.             else
  772.                 rc.OffsetRect(nAlign - rc.left, 0);
  773.             pBar->MoveWindow(rc);
  774.             bNeedRecalc = TRUE;
  775.         }
  776.         nAlign += (bHorz ? rc.Width() : rc.Height()) - 2;
  777.     }
  778.     if (bNeedRecalc)
  779.     {
  780.         m_pDockSite->DelayRecalcLayout();
  781.         TRACE("cccn");
  782.     }
  783. }
  784. void CSizingControlBar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler)
  785. {
  786.     BOOL bNeedPaint = FALSE;
  787.     CPoint pt;
  788.     ::GetCursorPos(&pt);
  789.     BOOL bHit = (OnNcHitTest(pt) == HTCLOSE);
  790.     BOOL bLButtonDown = (::GetKeyState(VK_LBUTTON) < 0);
  791.     BOOL bWasPushed = m_biHide.bPushed;
  792.     m_biHide.bPushed = bHit && bLButtonDown;
  793.     BOOL bWasRaised = m_biHide.bRaised;
  794.     m_biHide.bRaised = bHit && !bLButtonDown;
  795.     bNeedPaint |= (m_biHide.bPushed ^ bWasPushed) || 
  796.                   (m_biHide.bRaised ^ bWasRaised);
  797.     if (bNeedPaint)
  798.         SendMessage(WM_NCPAINT);
  799. }
  800. void CSizingControlBar::LoadState(LPCTSTR lpszProfileName)
  801. {
  802.     ASSERT_VALID(this);
  803.     ASSERT(GetSafeHwnd()); // must be called after Create()
  804.     CWinApp* pApp = AfxGetApp();
  805.     TCHAR szSection[256];
  806.     wsprintf(szSection, _T("%s-SCBar-%d"), lpszProfileName,
  807.         GetDlgCtrlID());
  808.     m_szHorz.cx = max(m_szMin.cx, (int) pApp->GetProfileInt(szSection,
  809.         _T("sizeHorzCX"), m_szHorz.cx));
  810.     m_szHorz.cy = max(m_szMin.cy, (int) pApp->GetProfileInt(szSection, 
  811.         _T("sizeHorzCY"), m_szHorz.cy));
  812.     m_szVert.cx = max(m_szMin.cx, (int) pApp->GetProfileInt(szSection, 
  813.         _T("sizeVertCX"), m_szVert.cx));
  814.     m_szVert.cy = max(m_szMin.cy, (int) pApp->GetProfileInt(szSection, 
  815.         _T("sizeVertCY"), m_szVert.cy));
  816.     m_szFloat.cx = max(m_szMin.cx, (int) pApp->GetProfileInt(szSection,
  817.         _T("sizeFloatCX"), m_szFloat.cx));
  818.     m_szFloat.cy = max(m_szMin.cy, (int) pApp->GetProfileInt(szSection,
  819.         _T("sizeFloatCY"), m_szFloat.cy));
  820. }
  821. void CSizingControlBar::SaveState(LPCTSTR lpszProfileName)
  822. {
  823.     // place your SaveState or GlobalSaveState call in
  824.     // CMainFrame::DestroyWindow(), not in OnDestroy()
  825.     ASSERT_VALID(this);
  826.     ASSERT(GetSafeHwnd());
  827.     CWinApp* pApp = AfxGetApp();
  828.     TCHAR szSection[256];
  829.     wsprintf(szSection, _T("%s-SCBar-%d"), lpszProfileName,
  830.         GetDlgCtrlID());
  831.     pApp->WriteProfileInt(szSection, _T("sizeHorzCX"), m_szHorz.cx);
  832.     pApp->WriteProfileInt(szSection, _T("sizeHorzCY"), m_szHorz.cy);
  833.     pApp->WriteProfileInt(szSection, _T("sizeVertCX"), m_szVert.cx);
  834.     pApp->WriteProfileInt(szSection, _T("sizeVertCY"), m_szVert.cy);
  835.     pApp->WriteProfileInt(szSection, _T("sizeFloatCX"), m_szFloat.cx);
  836.     pApp->WriteProfileInt(szSection, _T("sizeFloatCY"), m_szFloat.cy);
  837. }
  838. void CSizingControlBar::GlobalLoadState(LPCTSTR lpszProfileName)
  839. {
  840.     for (int i = 0; i < m_arrBars.GetSize(); i++)
  841.         ((CSizingControlBar*) m_arrBars[i])->LoadState(lpszProfileName);
  842. }
  843. void CSizingControlBar::GlobalSaveState(LPCTSTR lpszProfileName)
  844. {
  845.     for (int i = 0; i < m_arrBars.GetSize(); i++)
  846.         ((CSizingControlBar*) m_arrBars[i])->SaveState(lpszProfileName);
  847. }
  848. /////////////////////////////////////////////////////////////////////////
  849. // CSCBButton
  850. CSCBButton::CSCBButton()
  851. {
  852.     bRaised = FALSE;
  853.     bPushed = FALSE;
  854. }
  855. void CSCBButton::Paint(CDC* pDC)
  856. {
  857.     CRect rc = GetRect();
  858.     if (bPushed)
  859.         pDC->Draw3dRect(rc, ::GetSysColor(COLOR_BTNSHADOW),
  860.             ::GetSysColor(COLOR_BTNHIGHLIGHT));
  861.     else
  862.         if (bRaised)
  863.             pDC->Draw3dRect(rc, ::GetSysColor(COLOR_BTNHIGHLIGHT),
  864.                 ::GetSysColor(COLOR_BTNSHADOW));
  865.     COLORREF clrOldTextColor = pDC->GetTextColor();
  866.     pDC->SetTextColor(::GetSysColor(COLOR_BTNTEXT));
  867.     int nPrevBkMode = pDC->SetBkMode(TRANSPARENT);
  868.     CFont font;
  869.     int ppi = pDC->GetDeviceCaps(LOGPIXELSX);
  870.     int pointsize = MulDiv(60, 96, ppi); // 6 points at 96 ppi
  871.     font.CreatePointFont(pointsize, _T("Marlett"));
  872.     CFont* oldfont = pDC->SelectObject(&font);
  873.     pDC->TextOut(ptOrg.x + 2, ptOrg.y + 2, CString(_T("r"))); // x-like
  874.     
  875.     pDC->SelectObject(oldfont);
  876.     pDC->SetBkMode(nPrevBkMode);
  877.     pDC->SetTextColor(clrOldTextColor);
  878. }