home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 27 / IOPROG_27.ISO / SOFT / SPLITPRG.ZIP / xySplitterWnd.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-06-15  |  12.3 KB  |  499 lines

  1. // xySplitterWnd.cpp : implementation file
  2. //
  3.  
  4. #include "stdafx.h"
  5.  
  6. #include "xySplitterWnd.h"
  7.  
  8. #ifdef _DEBUG
  9. #define new DEBUG_NEW
  10. #undef THIS_FILE
  11. static char THIS_FILE[] = __FILE__;
  12. #endif
  13.  
  14. /////////////////////////////////////////////////////////////////////////////
  15. // CxSplitterWnd
  16.  
  17. CxSplitterWnd::CxSplitterWnd()
  18. {
  19. }
  20.  
  21. CxSplitterWnd::~CxSplitterWnd()
  22. {
  23. }
  24.  
  25. BOOL CxSplitterWnd::BindWithControl(CWnd *parent, DWORD ctrlId)
  26. {
  27.     m_Parent = parent;
  28.     m_minLeft = m_minRight = 10;
  29.  
  30.     SubclassWindow(m_Parent->GetDlgItem(ctrlId)->GetSafeHwnd());
  31.  
  32.     // Make sure to get mouse message from the dialog window
  33.     DWORD style = GetStyle();
  34.     ::SetWindowLong(GetSafeHwnd(), GWL_STYLE, style | SS_NOTIFY);
  35.  
  36.     return TRUE;
  37. }
  38.  
  39. void CxSplitterWnd::Unbind(void)
  40. {
  41.     DetachAllPanes();
  42.     UnsubclassWindow();
  43. }
  44.  
  45. void CxSplitterWnd::SetMinWidth(int left, int right)
  46. {
  47.     m_minLeft = left;
  48.     m_minRight = right;
  49. }
  50.  
  51. BOOL CxSplitterWnd::AttachAsLeftPane(DWORD ctrlId)
  52. {
  53.     m_leftIds.Add(ctrlId);
  54.     return TRUE;
  55. }
  56.  
  57. BOOL CxSplitterWnd::AttachAsRightPane(DWORD ctrlId)
  58. {
  59.     m_rightIds.Add(ctrlId);
  60.     return TRUE;
  61. }
  62.  
  63. BOOL CxSplitterWnd::DetachAllPanes(void)
  64. {
  65.     m_leftIds.RemoveAll();
  66.     m_rightIds.RemoveAll();
  67.     return TRUE;
  68. }
  69.  
  70. void CxSplitterWnd::RecalcLayout(void)
  71. {
  72.     CWnd *pane;
  73.     RECT rcBar, rcPane;
  74.  
  75.     GetWindowRect(&rcBar);
  76.     m_Parent->ScreenToClient(&rcBar);
  77.  
  78.     int i;
  79.     DWORD id;
  80.  
  81.     for (i=0; i<m_leftIds.GetSize(); i++) {
  82.         id = m_leftIds.GetAt(i);
  83.         pane = m_Parent->GetDlgItem(id);
  84.         pane->GetWindowRect(&rcPane);
  85.         m_Parent->ScreenToClient(&rcPane);
  86.         rcPane.right = rcBar.left - 1;
  87.         pane->MoveWindow(&rcPane, FALSE);
  88.     }
  89.  
  90.     for (i=0; i<m_rightIds.GetSize(); i++) {
  91.         id = m_rightIds.GetAt(i);
  92.         pane = m_Parent->GetDlgItem(id);
  93.         pane->GetWindowRect(&rcPane);
  94.         m_Parent->ScreenToClient(&rcPane);
  95.         rcPane.left = rcBar.right + 1;
  96.         pane->MoveWindow(&rcPane, FALSE);
  97.     }
  98.  
  99.     m_Parent->Invalidate();
  100. }
  101.  
  102. BOOL CxSplitterWnd::GetMouseClipRect(LPRECT rectClip, CPoint point)
  103. {
  104.     RECT rectOrg, rectTarget, rectParent, rectPane;
  105.     int i;
  106.     DWORD id;
  107.  
  108.     GetWindowRect(&rectOrg);
  109.     m_Parent->GetClientRect(&rectParent);
  110.     m_Parent->ClientToScreen(&rectParent);
  111.  
  112.     rectTarget = rectOrg;
  113.     rectTarget.left = rectParent.left + m_minLeft;
  114.     for (i=0; i<m_leftIds.GetSize(); i++) {
  115.         id = m_leftIds.GetAt(i);
  116.         m_Parent->GetDlgItem(id)->GetWindowRect(&rectPane);
  117.         if (rectTarget.left < rectPane.left + m_minLeft) {
  118.             rectTarget.left = rectPane.left + m_minLeft;
  119.         }
  120.     }
  121.  
  122.     rectTarget.right = rectParent.right - m_minRight;
  123.     for (i=0; i<m_rightIds.GetSize(); i++) {
  124.         id = m_rightIds.GetAt(i);
  125.         m_Parent->GetDlgItem(id)->GetWindowRect(&rectPane);
  126.         if (rectTarget.right > rectPane.right - m_minRight) {
  127.             rectTarget.right = rectPane.right - m_minRight;
  128.         }
  129.     }
  130.  
  131.     if (rectTarget.left >= rectTarget.right) {
  132.         TRACE("No room to drag the x-splitter bar");
  133.         return FALSE;
  134.     }
  135.  
  136.     rectClip->left = rectTarget.left + point.x;
  137.     rectClip->right = rectTarget.right - (rectOrg.right - rectOrg.left - point.x) + 1;
  138.     rectClip->top = rectOrg.top;
  139.     rectClip->bottom = rectOrg.bottom;
  140.  
  141.     return TRUE;
  142. }
  143.  
  144. BEGIN_MESSAGE_MAP(CxSplitterWnd, CWnd)
  145.     //{{AFX_MSG_MAP(CxSplitterWnd)
  146.     ON_WM_SETCURSOR()
  147.     ON_WM_LBUTTONDOWN()
  148.     //}}AFX_MSG_MAP
  149. END_MESSAGE_MAP()
  150.  
  151. /////////////////////////////////////////////////////////////////////////////
  152. // CxSplitterWnd message handlers
  153.  
  154. BOOL CxSplitterWnd::OnSetCursor(CWnd* /*pWnd*/, UINT /*nHitTest*/, UINT /*message*/) 
  155. {
  156.     // TODO: Add your message handler code here and/or call default
  157.     ::SetCursor(AfxGetApp()->LoadCursor(AFX_IDC_HSPLITBAR));
  158.     return TRUE;
  159.     
  160.     //return CWnd::OnSetCursor(pWnd, nHitTest, message);
  161. }
  162.  
  163.  
  164. void CxSplitterWnd::OnLButtonDown(UINT /*nFlags*/, CPoint point) 
  165. {
  166.     // TODO: Add your message handler code here and/or call default
  167.  
  168.     // don't handle if capture already set
  169.     if (::GetCapture() != NULL) return;
  170.  
  171.     // don't handle if no room to drag
  172.     RECT rectMouseClip;
  173.     if (!GetMouseClipRect(&rectMouseClip, point)) return;
  174.     ::ClipCursor(&rectMouseClip);
  175.  
  176.     // set capture to the window which received this message
  177.     SetCapture();
  178.     ASSERT(this == CWnd::GetCapture());
  179.  
  180.     // get DC for drawing
  181.     CDC* pDrawDC;
  182.     pDrawDC = m_Parent->GetDC();
  183.     ASSERT_VALID(pDrawDC);
  184.  
  185.     int     curX, curY;
  186.     int     xDiff, yDiff;
  187.     CRect   rectOrg, rectCur, rectOld;
  188.     CSize   sizeBar;
  189.  
  190.     GetWindowRect(rectOrg);
  191.     sizeBar = CSize(rectOrg.Width(), rectOrg.Height());
  192.  
  193.     m_Parent->ScreenToClient(rectOrg);
  194.     pDrawDC->DrawDragRect(&rectOrg, sizeBar, NULL, sizeBar);
  195.     rectOld = rectCur = rectOrg;
  196.     xDiff = yDiff = 0;
  197.  
  198.     // get messages until capture lost or cancelled/accepted
  199.     for (;;) {
  200.         MSG msg;
  201.         VERIFY(::GetMessage(&msg, NULL, 0, 0));
  202.  
  203.         if (CWnd::GetCapture() != this)
  204.             break;
  205.  
  206.         switch (msg.message) {
  207.         // handle movement/accept messages
  208.         case WM_MOUSEMOVE:
  209.             // handle resize cases (and part of move)
  210.             curX = (int)(short)LOWORD(msg.lParam);
  211.             curY = (int)(short)HIWORD(msg.lParam);
  212.  
  213.             xDiff = curX - point.x;
  214.             yDiff = curY - point.y;
  215.  
  216.             rectCur = rectOrg;
  217.             rectCur.left += xDiff;
  218.             rectCur.right += xDiff;
  219.             pDrawDC->DrawDragRect(&rectCur, sizeBar, &rectOld, sizeBar);
  220.             rectOld = rectCur;
  221.  
  222.             break;
  223.  
  224.         // handle cancel messages
  225.         case WM_KEYDOWN:
  226.             if (msg.wParam != VK_ESCAPE)
  227.                 break;
  228.         case WM_LBUTTONUP:
  229.         case WM_RBUTTONDOWN:
  230.             goto ExitLoop;
  231.  
  232.         // just dispatch rest of the messages
  233.         default:
  234.             DispatchMessage(&msg);
  235.             break;
  236.         }
  237.     }
  238.  
  239. ExitLoop:
  240.     pDrawDC->DrawDragRect(&rectCur, sizeBar, NULL, sizeBar);
  241.  
  242.     m_Parent->ReleaseDC(pDrawDC);
  243.     ReleaseCapture();
  244.     ::ClipCursor(NULL);
  245.  
  246.     if (xDiff == 0) return;
  247.  
  248.     // move the splitter bar & re-position the attached panes if necessary
  249.     MoveWindow(rectCur, FALSE);
  250.     RecalcLayout();
  251.  
  252.     m_Parent->SendMessage(WM_SPLITTER_MOVED, xDiff, GetDlgCtrlID());
  253.  
  254.     //CWnd::OnLButtonDown(nFlags, point);
  255. }
  256.  
  257. /////////////////////////////////////////////////////////////////////////////
  258. // CySplitterWnd
  259.  
  260. CySplitterWnd::CySplitterWnd()
  261. {
  262. }
  263.  
  264. CySplitterWnd::~CySplitterWnd()
  265. {
  266. }
  267.  
  268. BOOL CySplitterWnd::BindWithControl(CWnd *parent, DWORD ctrlId)
  269. {
  270.     m_Parent = parent;
  271.  
  272.     SubclassWindow(m_Parent->GetDlgItem(ctrlId)->GetSafeHwnd());
  273.     
  274.     // Make sure to get mouse message from the dialog window
  275.     DWORD style = GetStyle();
  276.     ::SetWindowLong(GetSafeHwnd(), GWL_STYLE, style | SS_NOTIFY);
  277.  
  278.     return TRUE;
  279. }
  280.  
  281. void CySplitterWnd::Unbind(void)
  282. {
  283.     DetachAllPanes();
  284.     UnsubclassWindow();
  285. }
  286.  
  287. void CySplitterWnd::SetMinHeight(int above, int below)
  288. {
  289.     m_minAbove = above;
  290.     m_minBelow = below;
  291. }
  292.  
  293. BOOL CySplitterWnd::AttachAsAbovePane(DWORD ctrlId)
  294. {
  295.     m_aboveIds.Add(ctrlId);
  296.     return TRUE;
  297. }
  298.  
  299. BOOL CySplitterWnd::AttachAsBelowPane(DWORD ctrlId)
  300. {
  301.     m_belowIds.Add(ctrlId);
  302.     return TRUE;
  303. }
  304.  
  305. BOOL CySplitterWnd::DetachAllPanes(void)
  306. {
  307.     m_aboveIds.RemoveAll();
  308.     m_belowIds.RemoveAll();
  309.     return TRUE;
  310. }
  311.  
  312. void CySplitterWnd::RecalcLayout(void)
  313. {
  314.     CWnd *pane;
  315.     RECT rcBar, rcPane;
  316.  
  317.     GetWindowRect(&rcBar);
  318.     m_Parent->ScreenToClient(&rcBar);
  319.  
  320.     int i;
  321.     DWORD id;
  322.  
  323.     for (i=0; i<m_aboveIds.GetSize(); i++) {
  324.         id = m_aboveIds.GetAt(i);
  325.         pane = m_Parent->GetDlgItem(id);
  326.         pane->GetWindowRect(&rcPane);
  327.         m_Parent->ScreenToClient(&rcPane);
  328.         rcPane.bottom = rcBar.top - 1;
  329.         pane->MoveWindow(&rcPane, FALSE);
  330.     }
  331.  
  332.     for (i=0; i<m_belowIds.GetSize(); i++) {
  333.         id = m_belowIds.GetAt(i);
  334.         pane = m_Parent->GetDlgItem(id);
  335.         pane->GetWindowRect(&rcPane);
  336.         m_Parent->ScreenToClient(&rcPane);
  337.         rcPane.top = rcBar.bottom + 1;
  338.         pane->MoveWindow(&rcPane, FALSE);
  339.     }
  340.  
  341.     m_Parent->Invalidate();
  342. }
  343.  
  344. BOOL CySplitterWnd::GetMouseClipRect(LPRECT rectClip, CPoint point)
  345. {
  346.     RECT rectOrg, rectTarget, rectParent, rectPane;
  347.     int i;
  348.     DWORD id;
  349.  
  350.     GetWindowRect(&rectOrg);
  351.     m_Parent->GetClientRect(&rectParent);
  352.     m_Parent->ClientToScreen(&rectParent);
  353.  
  354.     rectTarget = rectOrg;
  355.     rectTarget.top = rectParent.top + m_minAbove;
  356.     for (i=0; i<m_aboveIds.GetSize(); i++) {
  357.         id = m_aboveIds.GetAt(i);
  358.         m_Parent->GetDlgItem(id)->GetWindowRect(&rectPane);
  359.         if (rectTarget.top < rectPane.top + m_minAbove) {
  360.             rectTarget.top = rectPane.top + m_minAbove;
  361.         }
  362.     }
  363.  
  364.     rectTarget.bottom = rectParent.bottom - m_minBelow;
  365.     for (i=0; i<m_belowIds.GetSize(); i++) {
  366.         id = m_belowIds.GetAt(i);
  367.         m_Parent->GetDlgItem(id)->GetWindowRect(&rectPane);
  368.         if (rectTarget.bottom > rectPane.bottom - m_minBelow) {
  369.             rectTarget.bottom = rectPane.bottom - m_minBelow;
  370.         }
  371.     }
  372.  
  373.     if (rectTarget.top >= rectTarget.bottom) {
  374.         TRACE("No room to drag the y-splitter bar");
  375.         return FALSE;
  376.     }
  377.  
  378.     rectClip->left = rectOrg.left;
  379.     rectClip->right = rectOrg.right;
  380.     rectClip->top = rectTarget.top + point.y;
  381.     rectClip->bottom = rectTarget.bottom - (rectOrg.bottom - rectOrg.top - point.y) + 1;
  382.  
  383.     return TRUE;
  384. }
  385.  
  386.  
  387. BEGIN_MESSAGE_MAP(CySplitterWnd, CWnd)
  388.     //{{AFX_MSG_MAP(CySplitterWnd)
  389.     ON_WM_LBUTTONDOWN()
  390.     ON_WM_SETCURSOR()
  391.     //}}AFX_MSG_MAP
  392. END_MESSAGE_MAP()
  393.  
  394.  
  395. /////////////////////////////////////////////////////////////////////////////
  396. // CySplitterWnd message handlers
  397.  
  398. BOOL CySplitterWnd::OnSetCursor(CWnd* /*pWnd*/, UINT /*nHitTest*/, UINT /*message*/) 
  399. {
  400.     // TODO: Add your message handler code here and/or call default
  401.     ::SetCursor(AfxGetApp()->LoadCursor(AFX_IDC_VSPLITBAR));
  402.     return TRUE;
  403.     
  404.     //return CWnd::OnSetCursor(pWnd, nHitTest, message);
  405. }
  406.  
  407. void CySplitterWnd::OnLButtonDown(UINT /*nFlags*/, CPoint point) 
  408. {
  409.     // TODO: Add your message handler code here and/or call default
  410.  
  411.     // don't handle if capture already set
  412.     if (::GetCapture() != NULL) return;
  413.  
  414.     // don't handle if no room to drag
  415.     RECT rectMouseClip;
  416.     if (!GetMouseClipRect(&rectMouseClip, point)) return;
  417.     ::ClipCursor(&rectMouseClip);
  418.  
  419.     // set capture to the window which received this message
  420.     SetCapture();
  421.     ASSERT(this == CWnd::GetCapture());
  422.  
  423.     // get DC for drawing
  424.     CDC* pDrawDC;
  425.     pDrawDC = m_Parent->GetDC();
  426.     ASSERT_VALID(pDrawDC);
  427.  
  428.     int     curX, curY;
  429.     int     xDiff, yDiff;
  430.     CRect   rectOrg, rectCur, rectOld;
  431.     CSize   sizeBar;
  432.  
  433.     GetWindowRect(rectOrg);
  434.     sizeBar = CSize(rectOrg.Width(), rectOrg.Height());
  435.  
  436.     m_Parent->ScreenToClient(rectOrg);
  437.     pDrawDC->DrawDragRect(&rectOrg, sizeBar, NULL, sizeBar);
  438.     rectOld = rectCur = rectOrg;
  439.     xDiff = yDiff = 0;
  440.  
  441.     // get messages until capture lost or cancelled/accepted
  442.     for (;;) {
  443.         MSG msg;
  444.         VERIFY(::GetMessage(&msg, NULL, 0, 0));
  445.  
  446.         if (CWnd::GetCapture() != this)
  447.             break;
  448.  
  449.         switch (msg.message) {
  450.         // handle movement/accept messages
  451.         case WM_MOUSEMOVE:
  452.             // handle resize cases (and part of move)
  453.             curX = (int)(short)LOWORD(msg.lParam);
  454.             curY = (int)(short)HIWORD(msg.lParam);
  455.  
  456.             xDiff = curX - point.x;
  457.             yDiff = curY - point.y;
  458.  
  459.             rectCur = rectOrg;
  460.             rectCur.top += yDiff;
  461.             rectCur.bottom += yDiff;
  462.             pDrawDC->DrawDragRect(&rectCur, sizeBar, &rectOld, sizeBar);
  463.             rectOld = rectCur;
  464.  
  465.             break;
  466.  
  467.         // handle cancel messages
  468.         case WM_KEYDOWN:
  469.             if (msg.wParam != VK_ESCAPE)
  470.                 break;
  471.         case WM_LBUTTONUP:
  472.         case WM_RBUTTONDOWN:
  473.             goto ExitLoop;
  474.  
  475.         // just dispatch rest of the messages
  476.         default:
  477.             DispatchMessage(&msg);
  478.             break;
  479.         }
  480.     }
  481.  
  482. ExitLoop:
  483.     pDrawDC->DrawDragRect(&rectCur, sizeBar, NULL, sizeBar);
  484.  
  485.     m_Parent->ReleaseDC(pDrawDC);
  486.     ReleaseCapture();
  487.     ::ClipCursor(NULL);
  488.  
  489.     if (yDiff == 0) return;
  490.  
  491.     // move the splitter bar & re-position the attached panes if necessary
  492.     MoveWindow(rectCur, FALSE);
  493.     RecalcLayout();
  494.  
  495.     m_Parent->SendMessage(WM_SPLITTER_MOVED, yDiff, GetDlgCtrlID());
  496.  
  497.     //CWnd::OnLButtonDown(nFlags, point);
  498. }
  499.