Fernando_Fiore

atlsplit2.h - see BEGIN_CHANGE

Sep 21st, 2020 (edited)
35
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // Windows Template Library - WTL version 7.0
  2. // Copyright (C) 1997-2002 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This file is a part of the Windows Template Library.
  6. // The code and information is provided "as-is" without
  7. // warranty of any kind, either expressed or implied.
  8. // see BEGIN_CHANGE and END_CHANGE for the modifications
  9. // this splitter doesn't have to be parent of the contained windows
  10. // fernando fiore
  11.  
  12. #ifndef __ATLSPLIT_H__
  13. #define __ATLSPLIT_H__
  14.  
  15. #pragma once
  16.  
  17. #ifndef __cplusplus
  18.     #error ATL requires C++ compilation (use a .cpp suffix)
  19. #endif
  20.  
  21. #ifndef __ATLAPP_H__
  22.     #error atlsplit.h requires atlapp.h to be included first
  23. #endif
  24.  
  25. #ifndef __ATLWIN_H__
  26.     #error atlsplit.h requires atlwin.h to be included first
  27. #endif
  28.  
  29.  
  30. /////////////////////////////////////////////////////////////////////////////
  31. // Classes in this file
  32. //
  33. // CSplitterImpl<T, t_bVertical>
  34. // CSplitterWindowImpl<T, t_bVertical, TBase, TWinTraits>
  35. // CSplitterWindowT<t_bVertical>
  36.  
  37.  
  38. namespace WTL
  39. {
  40.  
  41. /////////////////////////////////////////////////////////////////////////////
  42. // CSplitterImpl - Provides splitter support to any window
  43.  
  44. // Splitter panes constants
  45. #define SPLIT_PANE_LEFT          0
  46. #define SPLIT_PANE_RIGHT         1
  47. #define SPLIT_PANE_TOP           SPLIT_PANE_LEFT
  48. #define SPLIT_PANE_BOTTOM        SPLIT_PANE_RIGHT
  49. #define SPLIT_PANE_NONE         -1
  50.  
  51. // Splitter extended styles
  52. #define SPLIT_PROPORTIONAL      0x00000001
  53. #define SPLIT_NONINTERACTIVE        0x00000002
  54. #define SPLIT_RIGHTALIGNED      0x00000004
  55. #define SPLIT_BOTTOMALIGNED     SPLIT_RIGHTALIGNED
  56.  
  57. // Note: SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED/SPLIT_BOTTOMALIGNED are
  58. // mutually exclusive. If both are set, splitter defaults to SPLIT_PROPORTIONAL
  59.  
  60.  
  61. template <class T, bool t_bVertical = true>
  62. class CSplitterImpl
  63. {
  64. public:
  65.     enum { m_nPanesCount = 2, m_nPropMax = 10000 };
  66.  
  67.     HWND m_hWndPane[m_nPanesCount];
  68.     RECT m_rcSplitter;
  69.     int m_xySplitterPos;
  70.     int m_nDefActivePane;
  71.     int m_cxySplitBar;      // splitter bar width/height
  72.     static HCURSOR m_hCursor;
  73.     int m_cxyMin;           // minimum pane size
  74.     int m_cxyBarEdge;       // splitter bar edge
  75.     bool m_bFullDrag;
  76.     int m_cxyDragOffset;
  77.     int m_nProportionalPos;
  78.     bool m_bUpdateProportionalPos;
  79.     DWORD m_dwExtendedStyle;    // splitter specific extended styles
  80.     int m_nSinglePane;      // single pane mode
  81.  
  82. // Constructor
  83.     CSplitterImpl() :
  84.             m_xySplitterPos(-1), m_nDefActivePane(SPLIT_PANE_NONE),
  85.             m_cxySplitBar(0), m_cxyMin(0), m_cxyBarEdge(0), m_bFullDrag(true),
  86.             m_cxyDragOffset(0), m_nProportionalPos(0), m_bUpdateProportionalPos(true),
  87.             m_dwExtendedStyle(SPLIT_PROPORTIONAL),
  88.             m_nSinglePane(SPLIT_PANE_NONE)
  89.     {
  90.         m_hWndPane[SPLIT_PANE_LEFT] = NULL;
  91.         m_hWndPane[SPLIT_PANE_RIGHT] = NULL;
  92.  
  93.         ::SetRectEmpty(&m_rcSplitter);
  94.  
  95.         if(m_hCursor == NULL)
  96.         {
  97.             ::EnterCriticalSection(&_Module.m_csStaticDataInit);
  98.             if(m_hCursor == NULL)
  99.                 m_hCursor = ::LoadCursor(NULL, t_bVertical ? IDC_SIZEWE : IDC_SIZENS);
  100.             ::LeaveCriticalSection(&_Module.m_csStaticDataInit);
  101.         }
  102.     }
  103.  
  104. // Attributes
  105.     void SetSplitterRect(LPRECT lpRect = NULL, bool bUpdate = true)
  106.     {
  107.         if(lpRect == NULL)
  108.         {
  109.             T* pT = static_cast<T*>(this);
  110.             pT->GetClientRect(&m_rcSplitter);
  111.         }
  112.         else
  113.         {
  114.             m_rcSplitter = *lpRect;
  115.         }
  116.  
  117.         if(IsProportional())
  118.             UpdateProportionalPos();
  119.         else if(IsRightAligned())
  120.             UpdateRightAlignPos();
  121.  
  122.         if(bUpdate)
  123.             UpdateSplitterLayout();
  124.     }
  125.  
  126.     void GetSplitterRect(LPRECT lpRect) const
  127.     {
  128.         ATLASSERT(lpRect != NULL);
  129.         *lpRect = m_rcSplitter;
  130.     }
  131.  
  132.     bool SetSplitterPos(int xyPos = -1, bool bUpdate = true)
  133.     {
  134.         if(xyPos == -1)     // -1 == middle
  135.         {
  136.             if(t_bVertical)
  137.                 xyPos = (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) / 2;
  138.             else
  139.                 xyPos = (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge) / 2;
  140.         }
  141.  
  142.         // Adjust if out of valid range
  143.         int cxyMax = 0;
  144.         if(t_bVertical)
  145.             cxyMax = m_rcSplitter.right - m_rcSplitter.left;
  146.         else
  147.             cxyMax = m_rcSplitter.bottom - m_rcSplitter.top;
  148.  
  149.         if(xyPos < m_cxyMin + m_cxyBarEdge)
  150.             xyPos = m_cxyMin;
  151.         else if(xyPos > (cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin))
  152.             xyPos = cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin;
  153.  
  154.         // Set new position and update if requested
  155.         bool bRet = (m_xySplitterPos != xyPos);
  156.         m_xySplitterPos = xyPos;
  157.  
  158.         if(m_bUpdateProportionalPos)
  159.         {
  160.             if(IsProportional())
  161.                 StoreProportionalPos();
  162.             else if(IsRightAligned())
  163.                 StoreRightAlignPos();
  164.         }
  165.         else
  166.         {
  167.             m_bUpdateProportionalPos = true;
  168.         }
  169.  
  170.         if(bUpdate && bRet)
  171.             UpdateSplitterLayout();
  172.  
  173.         return bRet;
  174.     }
  175.  
  176.     void SetSplitterPosPct(int nPct, bool bUpdate = true)
  177.     {
  178.         ATLASSERT((nPct >= 0) && (nPct <= 100));
  179.         m_nProportionalPos = ::MulDiv(nPct, m_nPropMax, 100);
  180.         UpdateProportionalPos();
  181.         if (bUpdate)
  182.             UpdateSplitterLayout();
  183.     }
  184.  
  185.     int GetSplitterPos() const
  186.     {
  187.         return m_xySplitterPos;
  188.     }
  189.  
  190.     bool SetSinglePaneMode(int nPane = SPLIT_PANE_NONE)
  191.     {
  192.         ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT || nPane == SPLIT_PANE_NONE);
  193.         if(!(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT || nPane == SPLIT_PANE_NONE))
  194.             return false;
  195.  
  196.         if(nPane != SPLIT_PANE_NONE)
  197.         {
  198.             if(!::IsWindowVisible(m_hWndPane[nPane]))
  199.                 ::ShowWindow(m_hWndPane[nPane], SW_SHOW);
  200.             int nOtherPane = (nPane == SPLIT_PANE_LEFT) ? SPLIT_PANE_RIGHT : SPLIT_PANE_LEFT;
  201.             ::ShowWindow(m_hWndPane[nOtherPane], SW_HIDE);
  202.             if(m_nDefActivePane != nPane)
  203.                 m_nDefActivePane = nPane;
  204.         }
  205.         else if(m_nSinglePane != SPLIT_PANE_NONE)
  206.         {
  207.             int nOtherPane = (m_nSinglePane == SPLIT_PANE_LEFT) ? SPLIT_PANE_RIGHT : SPLIT_PANE_LEFT;
  208.             ::ShowWindow(m_hWndPane[nOtherPane], SW_SHOW);
  209.         }
  210.  
  211.         m_nSinglePane = nPane;
  212.         UpdateSplitterLayout();
  213.         return true;
  214.     }
  215.  
  216.     int GetSinglePaneMode() const
  217.     {
  218.         return m_nSinglePane;
  219.     }
  220.  
  221.     DWORD GetSplitterExtendedStyle() const
  222.     {
  223.         return m_dwExtendedStyle;
  224.     }
  225.  
  226.     DWORD SetSplitterExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
  227.     {
  228.         DWORD dwPrevStyle = m_dwExtendedStyle;
  229.         if(dwMask == 0)
  230.             m_dwExtendedStyle = dwExtendedStyle;
  231.         else
  232.             m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
  233. #ifdef _DEBUG
  234.         if(IsProportional() && IsRightAligned())
  235.             ATLTRACE2(atlTraceUI, 0, "CSplitterImpl::SetSplitterExtendedStyle - SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED are mutually exclusive, defaulting to SPLIT_PROPORTIONAL.\n");
  236. #endif //_DEBUG
  237.         return dwPrevStyle;
  238.     }
  239.  
  240. // Splitter operations
  241.     void SetSplitterPanes(HWND hWndLeftTop, HWND hWndRightBottom, bool bUpdate = true)
  242.     {
  243.         m_hWndPane[SPLIT_PANE_LEFT] = hWndLeftTop;
  244.         m_hWndPane[SPLIT_PANE_RIGHT] = hWndRightBottom;
  245.         ATLASSERT(m_hWndPane[SPLIT_PANE_LEFT] == NULL || m_hWndPane[SPLIT_PANE_RIGHT] == NULL || m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RIGHT]);
  246.         if(bUpdate)
  247.             UpdateSplitterLayout();
  248.     }
  249.  
  250.     bool SetSplitterPane(int nPane, HWND hWnd, bool bUpdate = true)
  251.     {
  252.         ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
  253.  
  254.         if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT)
  255.             return false;
  256.         m_hWndPane[nPane] = hWnd;
  257.         ATLASSERT(m_hWndPane[SPLIT_PANE_LEFT] == NULL || m_hWndPane[SPLIT_PANE_RIGHT] == NULL || m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RIGHT]);
  258.         if(bUpdate)
  259.             UpdateSplitterLayout();
  260.         return true;
  261.     }
  262.  
  263.     HWND GetSplitterPane(int nPane) const
  264.     {
  265.         ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
  266.  
  267.         if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT)
  268.             return false;
  269.         return m_hWndPane[nPane];
  270.     }
  271.  
  272.     bool SetActivePane(int nPane)
  273.     {
  274.         ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
  275.  
  276.         if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT)
  277.             return false;
  278.         if(m_nSinglePane != SPLIT_PANE_NONE && nPane != m_nSinglePane)
  279.             return false;
  280.         ::SetFocus(m_hWndPane[nPane]);
  281.         m_nDefActivePane = nPane;
  282.         return true;
  283.     }
  284.  
  285.     int GetActivePane() const
  286.     {
  287.         int nRet = SPLIT_PANE_NONE;
  288.         HWND hWndFocus = ::GetFocus();
  289.         if(hWndFocus != NULL)
  290.         {
  291.             for(int nPane = 0; nPane < m_nPanesCount; nPane++)
  292.             {
  293.                 if(hWndFocus == m_hWndPane[nPane] || ::IsChild(m_hWndPane[nPane], hWndFocus))
  294.                 {
  295.                     nRet = nPane;
  296.                     break;
  297.                 }
  298.             }
  299.         }
  300.         return nRet;
  301.     }
  302.  
  303.     bool ActivateNextPane(bool bNext = true)
  304.     {
  305.         int nPane = m_nSinglePane;
  306.         if(nPane == SPLIT_PANE_NONE)
  307.         {
  308.             switch(GetActivePane())
  309.             {
  310.             case SPLIT_PANE_LEFT:
  311.                 nPane = SPLIT_PANE_RIGHT;
  312.                 break;
  313.             case SPLIT_PANE_RIGHT:
  314.                 nPane = SPLIT_PANE_LEFT;
  315.                 break;
  316.             default:
  317.                 nPane = bNext ? SPLIT_PANE_LEFT : SPLIT_PANE_RIGHT;
  318.                 break;
  319.             }
  320.         }
  321.         return SetActivePane(nPane);
  322.     }
  323.  
  324.     bool SetDefaultActivePane(int nPane)
  325.     {
  326.         ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
  327.  
  328.         if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT)
  329.             return false;
  330.         m_nDefActivePane = nPane;
  331.         return true;
  332.     }
  333.  
  334.     bool SetDefaultActivePane(HWND hWnd)
  335.     {
  336.         for(int nPane = 0; nPane < m_nPanesCount; nPane++)
  337.         {
  338.             if(hWnd == m_hWndPane[nPane])
  339.             {
  340.                 m_nDefActivePane = nPane;
  341.                 return true;
  342.             }
  343.         }
  344.         return false;   // not found
  345.     }
  346.  
  347.     int GetDefaultActivePane() const
  348.     {
  349.         return m_nDefActivePane;
  350.     }
  351.  
  352.     void DrawSplitter(CDCHandle dc)
  353.     {
  354.         ATLASSERT(dc.m_hDC != NULL);
  355.         if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1)
  356.             return;
  357.  
  358.         T* pT = static_cast<T*>(this);
  359.         if(m_nSinglePane == SPLIT_PANE_NONE)
  360.         {
  361.             pT->DrawSplitterBar(dc);
  362.  
  363.             for(int nPane = 0; nPane < m_nPanesCount; nPane++)
  364.             {
  365.                 if(m_hWndPane[nPane] == NULL)
  366.                     pT->DrawSplitterPane(dc, nPane);
  367.             }
  368.         }
  369.         else
  370.         {
  371.             if(m_hWndPane[m_nSinglePane] == NULL)
  372.                 pT->DrawSplitterPane(dc, m_nSinglePane);
  373.         }
  374.     }
  375.  
  376. // Overrideables
  377.     void DrawSplitterBar(CDCHandle dc)
  378.     {
  379.         RECT rect;
  380.         if(GetSplitterBarRect(&rect))
  381.         {
  382.             dc.FillRect(&rect, COLOR_3DFACE);
  383.             // draw 3D edge if needed
  384.             T* pT = static_cast<T*>(this);
  385.             if((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0)
  386.                 dc.DrawEdge(&rect, EDGE_RAISED, t_bVertical ? (BF_LEFT | BF_RIGHT) : (BF_TOP | BF_BOTTOM));
  387.         }
  388.     }
  389.  
  390.     // called only if pane is empty
  391.     void DrawSplitterPane(CDCHandle dc, int nPane)
  392.     {
  393.         RECT rect;
  394.         if(GetSplitterPaneRect(nPane, &rect))
  395.         {
  396.             T* pT = static_cast<T*>(this);
  397.             if((pT->GetExStyle() & WS_EX_CLIENTEDGE) == 0)
  398.                 dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
  399.             dc.FillRect(&rect, COLOR_APPWORKSPACE);
  400.         }
  401.     }
  402.  
  403. // Message map and handlers
  404.     typedef CSplitterImpl< T, t_bVertical>  thisClass;
  405.     BEGIN_MSG_MAP(thisClass)
  406.         MESSAGE_HANDLER(WM_CREATE, OnCreate)
  407.         MESSAGE_HANDLER(WM_PAINT, OnPaint)
  408.         MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
  409.         if(IsInteractive())
  410.         {
  411.             MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)
  412.             MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
  413.             MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
  414.             MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
  415.             MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDoubleClick)
  416.         }
  417.         MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
  418.         MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)
  419.         MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
  420.     END_MSG_MAP()
  421.  
  422.     LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  423.     {
  424.         GetSystemSettings(false);
  425.         bHandled = FALSE;
  426.         return 1;
  427.     }
  428.  
  429.     LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  430.     {
  431.         T* pT = static_cast<T*>(this);
  432.         // try setting position if not set
  433.         if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1)
  434.             pT->SetSplitterPos();
  435.         // do painting
  436.         CPaintDC dc(pT->m_hWnd);
  437.         pT->DrawSplitter(dc.m_hDC);
  438.         return 0;
  439.     }
  440.  
  441.     LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  442.     {
  443.         T* pT = static_cast<T*>(this);
  444.         if((HWND)wParam == pT->m_hWnd && LOWORD(lParam) == HTCLIENT)
  445.         {
  446.             DWORD dwPos = ::GetMessagePos();
  447.             POINT ptPos = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) };
  448.             pT->ScreenToClient(&ptPos);
  449.             if(IsOverSplitterBar(ptPos.x, ptPos.y))
  450.                 return 1;
  451.         }
  452.  
  453.         bHandled = FALSE;
  454.         return 0;
  455.     }
  456.  
  457.     LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  458.     {
  459.         T* pT = static_cast<T*>(this);
  460.         int xPos = GET_X_LPARAM(lParam);
  461.         int yPos = GET_Y_LPARAM(lParam);
  462.         if((wParam & MK_LBUTTON) && ::GetCapture() == pT->m_hWnd)
  463.         {
  464.             int xyNewSplitPos = 0;
  465.             if(t_bVertical)
  466.                 xyNewSplitPos = xPos - m_rcSplitter.left - m_cxyDragOffset;
  467.             else
  468.                 xyNewSplitPos = yPos - m_rcSplitter.top - m_cxyDragOffset;
  469.  
  470.             if(xyNewSplitPos == -1) // avoid -1, that means middle
  471.                 xyNewSplitPos = -2;
  472.  
  473.             if(m_xySplitterPos != xyNewSplitPos)
  474.             {
  475.                 if(m_bFullDrag)
  476.                 {
  477.                     if(pT->SetSplitterPos(xyNewSplitPos, true))
  478.                         pT->UpdateWindow();
  479.                 }
  480.                 else
  481.                 {
  482.                     DrawGhostBar();
  483.                     pT->SetSplitterPos(xyNewSplitPos, false);
  484.                     DrawGhostBar();
  485.                 }
  486.             }
  487.         }
  488.         else        // not dragging, just set cursor
  489.         {
  490.             if(IsOverSplitterBar(xPos, yPos))
  491.                 ::SetCursor(m_hCursor);
  492.             bHandled = FALSE;
  493.         }
  494.  
  495.         return 0;
  496.     }
  497.  
  498.     LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  499.     {
  500.         int xPos = GET_X_LPARAM(lParam);
  501.         int yPos = GET_Y_LPARAM(lParam);
  502.         if(IsOverSplitterBar(xPos, yPos))
  503.         {
  504.             T* pT = static_cast<T*>(this);
  505.             pT->SetCapture();
  506.             ::SetCursor(m_hCursor);
  507.             if(!m_bFullDrag)
  508.                 DrawGhostBar();
  509.             if(t_bVertical)
  510.                 m_cxyDragOffset = xPos - m_rcSplitter.left - m_xySplitterPos;
  511.             else
  512.                 m_cxyDragOffset = yPos - m_rcSplitter.top - m_xySplitterPos;
  513.         }
  514.         bHandled = FALSE;
  515.         return 1;
  516.     }
  517.  
  518.     LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  519.     {
  520.         if(!m_bFullDrag)
  521.         {
  522.             DrawGhostBar();
  523.             T* pT = static_cast<T*>(this);
  524.             UpdateSplitterLayout();
  525.             pT->UpdateWindow();
  526.         }
  527.         ::ReleaseCapture();
  528.         bHandled = FALSE;
  529.         return 1;
  530.     }
  531.  
  532.     LRESULT OnLButtonDoubleClick(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  533.     {
  534.         T* pT = static_cast<T*>(this);
  535.         pT->SetSplitterPos();   // middle
  536.         return 0;
  537.     }
  538.  
  539.     LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM, BOOL& bHandled)
  540.     {
  541.         if(m_nSinglePane == SPLIT_PANE_NONE)
  542.         {
  543.             if(m_nDefActivePane == SPLIT_PANE_LEFT || m_nDefActivePane == SPLIT_PANE_RIGHT)
  544.                 ::SetFocus(m_hWndPane[m_nDefActivePane]);
  545.         }
  546.         else
  547.         {
  548.             ::SetFocus(m_hWndPane[m_nSinglePane]);
  549.         }
  550.         bHandled = FALSE;
  551.         return 1;
  552.     }
  553.  
  554.     LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  555.     {
  556.         T* pT = static_cast<T*>(this);
  557.         LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam);
  558.         if(lRet == MA_ACTIVATE || lRet == MA_ACTIVATEANDEAT)
  559.         {
  560.             DWORD dwPos = ::GetMessagePos();
  561.             POINT pt = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) };
  562.             pT->ScreenToClient(&pt);
  563.             RECT rcPane;
  564.             for(int nPane = 0; nPane < m_nPanesCount; nPane++)
  565.             {
  566.                 if(GetSplitterPaneRect(nPane, &rcPane) && ::PtInRect(&rcPane, pt))
  567.                 {
  568.                     m_nDefActivePane = nPane;
  569.                     break;
  570.                 }
  571.             }
  572.         }
  573.         return lRet;
  574.     }
  575.  
  576.     LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  577.     {
  578.         GetSystemSettings(true);
  579.         return 0;
  580.     }
  581.  
  582. // Implementation - internal helpers
  583.     void UpdateSplitterLayout()
  584.     {
  585.         if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1)
  586.             return;
  587.  
  588.         T* pT = static_cast<T*>(this);
  589.         RECT rect = { 0, 0, 0, 0 };
  590.         if(m_nSinglePane == SPLIT_PANE_NONE)
  591.         {
  592.             if(GetSplitterBarRect(&rect))
  593.                 pT->InvalidateRect(&rect);
  594.  
  595.             for(int nPane = 0; nPane < m_nPanesCount; nPane++)
  596.             {
  597.                 if(GetSplitterPaneRect(nPane, &rect))
  598.                 {
  599.                     if(m_hWndPane[nPane] != NULL){
  600.                         /* BEGIN_CHANGE */
  601.                         CWindow wndParent = ::GetParent(m_hWndPane[nPane]);
  602.  
  603.                         if(pT->m_hWnd != wndParent.m_hWnd){
  604.                             pT->MapWindowPoints(wndParent,&rect);
  605.                         }
  606.                         BOOL bDebug = ::SetWindowPos(m_hWndPane[nPane], HWND_TOP, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0);
  607.                         ATLASSERT(bDebug);
  608.                         /* END_CHANGE */
  609.                     }
  610.                     else
  611.                         pT->InvalidateRect(&rect);
  612.                 }
  613.             }
  614.         }
  615.         else
  616.         {
  617.             if(GetSplitterPaneRect(m_nSinglePane, &rect))
  618.             {
  619.                 if(m_hWndPane[m_nSinglePane] != NULL){
  620.                         /* BEGIN_CHANGE */
  621.                         CWindow wndParent = ::GetParent(m_hWndPane[m_nSinglePane]);
  622.  
  623.                         if(pT->m_hWnd != wndParent.m_hWnd){
  624.                             pT->MapWindowPoints(wndParent,&rect);
  625.                         }
  626.                         BOOL bDebug = ::SetWindowPos(m_hWndPane[m_nSinglePane], HWND_TOP, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0);
  627.                         ATLASSERT(bDebug);
  628.                         /* END_CHANGE */
  629.                 }
  630.                 else
  631.                     pT->InvalidateRect(&rect);
  632.             }
  633.         }
  634.     }
  635.  
  636.     bool GetSplitterBarRect(LPRECT lpRect) const
  637.     {
  638.         ATLASSERT(lpRect != NULL);
  639.         if(m_nSinglePane != SPLIT_PANE_NONE || m_xySplitterPos == -1)
  640.             return false;
  641.  
  642.         if(t_bVertical)
  643.         {
  644.             lpRect->left = m_rcSplitter.left + m_xySplitterPos;
  645.             lpRect->top = m_rcSplitter.top;
  646.             lpRect->right = m_rcSplitter.left + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;
  647.             lpRect->bottom = m_rcSplitter.bottom;
  648.         }
  649.         else
  650.         {
  651.             lpRect->left = m_rcSplitter.left;
  652.             lpRect->top = m_rcSplitter.top + m_xySplitterPos;
  653.             lpRect->right = m_rcSplitter.right;
  654.             lpRect->bottom = m_rcSplitter.top + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;
  655.         }
  656.  
  657.         return true;
  658.     }
  659.  
  660.     bool GetSplitterPaneRect(int nPane, LPRECT lpRect) const
  661.     {
  662.         ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
  663.         ATLASSERT(lpRect != NULL);
  664.         bool bRet = true;
  665.         if(m_nSinglePane != SPLIT_PANE_NONE)
  666.         {
  667.             if(nPane == m_nSinglePane)
  668.                 *lpRect = m_rcSplitter;
  669.             else
  670.                 bRet = false;
  671.         }
  672.         else if(nPane == SPLIT_PANE_LEFT)
  673.         {
  674.             if(t_bVertical)
  675.             {
  676.                 lpRect->left = m_rcSplitter.left;
  677.                 lpRect->top = m_rcSplitter.top;
  678.                 lpRect->right = m_rcSplitter.left + m_xySplitterPos;
  679.                 lpRect->bottom = m_rcSplitter.bottom;
  680.             }
  681.             else
  682.             {
  683.                 lpRect->left = m_rcSplitter.left;
  684.                 lpRect->top = m_rcSplitter.top;
  685.                 lpRect->right = m_rcSplitter.right;
  686.                 lpRect->bottom = m_rcSplitter.top + m_xySplitterPos;
  687.             }
  688.         }  
  689.         else if(nPane == SPLIT_PANE_RIGHT)
  690.         {
  691.             if(t_bVertical)
  692.             {
  693.                 lpRect->left = m_rcSplitter.left + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;
  694.                 lpRect->top = m_rcSplitter.top;
  695.                 lpRect->right = m_rcSplitter.right;
  696.                 lpRect->bottom = m_rcSplitter.bottom;
  697.             }
  698.             else
  699.             {
  700.                 lpRect->left = m_rcSplitter.left;
  701.                 lpRect->top = m_rcSplitter.top + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;
  702.                 lpRect->right = m_rcSplitter.right;
  703.                 lpRect->bottom = m_rcSplitter.bottom;
  704.             }
  705.         }
  706.         else
  707.         {
  708.             bRet = false;
  709.         }
  710.         return bRet;
  711.     }
  712.  
  713.     bool IsOverSplitterRect(int x, int y) const
  714.     {
  715.         // -1 == don't check
  716.         return ((x == -1 || (x >= m_rcSplitter.left && x <= m_rcSplitter.right)) &&
  717.             (y == -1 || (y >= m_rcSplitter.top && y <= m_rcSplitter.bottom)));
  718.     }
  719.  
  720.     bool IsOverSplitterBar(int x, int y) const
  721.     {
  722.         if(m_nSinglePane != SPLIT_PANE_NONE)
  723.             return false;
  724.         if(m_xySplitterPos == -1 || !IsOverSplitterRect(x, y))
  725.             return false;
  726.         int xy = t_bVertical ? x : y;
  727.         int xyOff = t_bVertical ? m_rcSplitter.left : m_rcSplitter.top;
  728.         return ((xy >= (xyOff + m_xySplitterPos)) && (xy < xyOff + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge));
  729.     }
  730.  
  731.     void DrawGhostBar()
  732.     {
  733.         RECT rect = { 0, 0, 0, 0 };
  734.         if(GetSplitterBarRect(&rect))
  735.         {
  736.             // invert the brush pattern (looks just like frame window sizing)
  737.             T* pT = static_cast<T*>(this);
  738.             CWindowDC dc(pT->m_hWnd);
  739.             CBrush brush = CDCHandle::GetHalftoneBrush();
  740.             if(brush.m_hBrush != NULL)
  741.             {
  742.                 CBrushHandle brushOld = dc.SelectBrush(brush);
  743.                 dc.PatBlt(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, PATINVERT);
  744.                 dc.SelectBrush(brushOld);
  745.             }
  746.         }
  747.     }
  748.  
  749.     void GetSystemSettings(bool bUpdate)
  750.     {
  751.         m_cxySplitBar = ::GetSystemMetrics(t_bVertical ? SM_CXSIZEFRAME : SM_CYSIZEFRAME);
  752.  
  753.         T* pT = static_cast<T*>(this);
  754.         if((pT->GetExStyle() & WS_EX_CLIENTEDGE))
  755.         {
  756.             m_cxyBarEdge = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDGE : SM_CYEDGE);
  757.             m_cxyMin = 0;
  758.         }
  759.         else
  760.         {
  761.             m_cxyBarEdge = 0;
  762.             m_cxyMin = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDGE : SM_CYEDGE);
  763.         }
  764.  
  765.         ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &m_bFullDrag, 0);
  766.  
  767.         if(bUpdate)
  768.             UpdateSplitterLayout();
  769.     }
  770.  
  771.     bool IsProportional() const
  772.     {
  773.         return ((m_dwExtendedStyle & SPLIT_PROPORTIONAL) != 0);
  774.     }
  775.  
  776.     void StoreProportionalPos()
  777.     {
  778.         int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
  779.         if(cxyTotal > 0)
  780.             m_nProportionalPos = ::MulDiv(m_xySplitterPos, m_nPropMax, cxyTotal);
  781.         else
  782.             m_nProportionalPos = 0;
  783.         ATLTRACE2(atlTraceUI, 0, "CSplitterImpl::StoreProportionalPos - %i\n", m_nProportionalPos);
  784.     }
  785.  
  786.     void UpdateProportionalPos()
  787.     {
  788.         int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
  789.         if(cxyTotal > 0)
  790.         {
  791.             int xyNewPos = ::MulDiv(m_nProportionalPos, cxyTotal, m_nPropMax);
  792.             m_bUpdateProportionalPos = false;
  793.             T* pT = static_cast<T*>(this);
  794.             pT->SetSplitterPos(xyNewPos, false);
  795.         }
  796.     }
  797.  
  798.     bool IsRightAligned() const
  799.     {
  800.         return ((m_dwExtendedStyle & SPLIT_RIGHTALIGNED) != 0);
  801.     }
  802.  
  803.     void StoreRightAlignPos()
  804.     {
  805.         int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
  806.         if(cxyTotal > 0)
  807.             m_nProportionalPos = cxyTotal - m_xySplitterPos;
  808.         else
  809.             m_nProportionalPos = 0;
  810.         ATLTRACE2(atlTraceUI, 0, "CSplitterImpl::StoreRightAlignPos - %i\n", m_nProportionalPos);
  811.     }
  812.  
  813.     void UpdateRightAlignPos()
  814.     {
  815.         int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);
  816.         if(cxyTotal > 0)
  817.         {
  818.             m_bUpdateProportionalPos = false;
  819.             T* pT = static_cast<T*>(this);
  820.             pT->SetSplitterPos(cxyTotal - m_nProportionalPos, false);
  821.         }
  822.     }
  823.  
  824.     bool IsInteractive() const
  825.     {
  826.         return ((m_dwExtendedStyle & SPLIT_NONINTERACTIVE) == 0);
  827.     }
  828. };
  829.  
  830. template <class T, bool t_bVertical> HCURSOR CSplitterImpl< T, t_bVertical>::m_hCursor = NULL;
  831.  
  832.  
  833. /////////////////////////////////////////////////////////////////////////////
  834. // CSplitterWindowImpl - Implements a splitter window
  835.  
  836. template <class T, bool t_bVertical = true, class TBase = CWindow, class TWinTraits = CControlWinTraits>
  837. class ATL_NO_VTABLE CSplitterWindowImpl : public CWindowImpl< T, TBase, TWinTraits >, public CSplitterImpl< T , t_bVertical >
  838. {
  839. public:
  840.     DECLARE_WND_CLASS_EX(NULL, CS_DBLCLKS, COLOR_WINDOW)
  841.  
  842.     typedef CSplitterWindowImpl< T , t_bVertical, TBase, TWinTraits >   thisClass;
  843.     typedef CSplitterImpl< T , t_bVertical >                baseClass;
  844.     BEGIN_MSG_MAP(thisClass)
  845.         MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
  846.         MESSAGE_HANDLER(WM_SIZE, OnSize)
  847.         CHAIN_MSG_MAP(baseClass)
  848.         FORWARD_NOTIFICATIONS()
  849.     END_MSG_MAP()
  850.  
  851.     LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  852.     {
  853.         // handled, no background painting needed
  854.         return 1;
  855.     }
  856.  
  857.     LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
  858.     {
  859.         if(wParam != SIZE_MINIMIZED)
  860.             SetSplitterRect();
  861.  
  862.         bHandled = FALSE;
  863.         return 1;
  864.     }
  865. };
  866.  
  867.  
  868. /////////////////////////////////////////////////////////////////////////////
  869. // CSplitterWindow - Implements a splitter window to be used as is
  870.  
  871. template <bool t_bVertical = true>
  872. class CSplitterWindowT : public CSplitterWindowImpl<CSplitterWindowT<t_bVertical>, t_bVertical>
  873. {
  874. public:
  875.     DECLARE_WND_CLASS_EX(_T("WTL_SplitterWindow"), CS_DBLCLKS, COLOR_WINDOW)
  876. };
  877.  
  878. typedef CSplitterWindowT<true>  CSplitterWindow;
  879. typedef CSplitterWindowT<false> CHorSplitterWindow;
  880.  
  881. }; //namespace WTL
  882.  
  883. #endif // __ATLSPLIT_H__
  884.  
RAW Paste Data