sizecbar.cpp
上传用户:lds876
上传日期:2013-05-25
资源大小:567k
文件大小:33k
源码类别:

P2P编程

开发平台:

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