home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / oledrop1.cpp < prev    next >
C/C++ Source or Header  |  1998-06-16  |  7KB  |  259 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12.  
  13. #ifdef AFX_OLE4_SEG
  14. #pragma code_seg(AFX_OLE4_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. #define new DEBUG_NEW
  23.  
  24. /////////////////////////////////////////////////////////////////////////////
  25. // COleDropSource implementation
  26.  
  27. AFX_DATADEF UINT COleDropSource::nDragMinDist;
  28. AFX_DATADEF UINT COleDropSource::nDragDelay;
  29.  
  30. COleDropSource::COleDropSource()
  31. {
  32.     m_bDragStarted = FALSE;
  33.     m_dwButtonCancel = 0;
  34.     m_dwButtonDrop = 0;
  35.  
  36.     AfxLockGlobals(CRIT_DROPSOURCE);
  37.     static BOOL bInitialized;
  38.     if (!bInitialized)
  39.     {
  40.         // get drag metrics from win.ini
  41.         static const TCHAR szWindows[] = _T("windows");
  42.         static const TCHAR szDragMinDist[] = _T("DragMinDist");
  43.         static const TCHAR szDragDelay[] = _T("DragDelay");
  44.  
  45.         nDragMinDist = GetProfileInt(szWindows, szDragMinDist, DD_DEFDRAGMINDIST);
  46.         nDragDelay = GetProfileInt(szWindows, szDragDelay, DD_DEFDRAGDELAY);
  47.  
  48.         // now initialized, no need to call Initialize any more
  49.         bInitialized = TRUE;
  50.     }
  51.     AfxUnlockGlobals(CRIT_DROPSOURCE);
  52.  
  53.     ASSERT_VALID(this);
  54. }
  55.  
  56. SCODE COleDropSource::QueryContinueDrag(BOOL bEscapePressed, DWORD dwKeyState)
  57. {
  58.     ASSERT_VALID(this);
  59.  
  60.     // check escape key or right button -- and cancel
  61.     if (bEscapePressed || (dwKeyState & m_dwButtonCancel) != 0)
  62.     {
  63.         m_bDragStarted = FALSE; // avoid unecessary cursor setting
  64.         return DRAGDROP_S_CANCEL;
  65.     }
  66.  
  67.     // check left-button up to end drag/drop and do the drop
  68.     if ((dwKeyState & m_dwButtonDrop) == 0)
  69.         return m_bDragStarted ? DRAGDROP_S_DROP : DRAGDROP_S_CANCEL;
  70.  
  71.     // otherwise, keep polling...
  72.     return S_OK;
  73. }
  74.  
  75. SCODE COleDropSource::GiveFeedback(DROPEFFECT /*dropEffect*/)
  76. {
  77.     ASSERT_VALID(this);
  78.  
  79.     // don't change the cursor until drag is officially started
  80.     return m_bDragStarted ? DRAGDROP_S_USEDEFAULTCURSORS : S_OK;
  81. }
  82.  
  83. BOOL COleDropSource::OnBeginDrag(CWnd* pWnd)
  84. {
  85.     ASSERT_VALID(this);
  86.  
  87.     m_bDragStarted = FALSE;
  88.  
  89.     // opposite button cancels drag operation
  90.     m_dwButtonCancel = 0;
  91.     m_dwButtonDrop = 0;
  92.     if (GetKeyState(VK_LBUTTON) < 0)
  93.     {
  94.         m_dwButtonDrop |= MK_LBUTTON;
  95.         m_dwButtonCancel |= MK_RBUTTON;
  96.     }
  97.     else if (GetKeyState(VK_RBUTTON) < 0)
  98.     {
  99.         m_dwButtonDrop |= MK_RBUTTON;
  100.         m_dwButtonCancel |= MK_LBUTTON;
  101.     }
  102.  
  103.     DWORD dwLastTick = GetTickCount();
  104.     pWnd->SetCapture();
  105.  
  106.     while (!m_bDragStarted)
  107.     {
  108.         // some applications steal capture away at random times
  109.         if (CWnd::GetCapture() != pWnd)
  110.             break;
  111.  
  112.         // peek for next input message
  113.         MSG msg;
  114.         if (PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE) ||
  115.             PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
  116.         {
  117.             // check for button cancellation (any button down will cancel)
  118.             if (msg.message == WM_LBUTTONUP || msg.message == WM_RBUTTONUP ||
  119.                 msg.message == WM_LBUTTONDOWN || msg.message == WM_RBUTTONDOWN)
  120.                 break;
  121.  
  122.             // check for keyboard cancellation
  123.             if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)
  124.                 break;
  125.  
  126.             // check for drag start transition
  127.             m_bDragStarted = !m_rectStartDrag.PtInRect(msg.pt);
  128.         }
  129.  
  130.         // if the user sits here long enough, we eventually start the drag
  131.         if (GetTickCount() - dwLastTick > nDragDelay)
  132.             m_bDragStarted = TRUE;
  133.     }
  134.     ReleaseCapture();
  135.  
  136.     return m_bDragStarted;
  137. }
  138.  
  139. BEGIN_INTERFACE_MAP(COleDropSource, CCmdTarget)
  140.     INTERFACE_PART(COleDropSource, IID_IDropSource, DropSource)
  141. END_INTERFACE_MAP()
  142.  
  143. STDMETHODIMP_(ULONG) COleDropSource::XDropSource::AddRef()
  144. {
  145.     METHOD_PROLOGUE_EX_(COleDropSource, DropSource)
  146.     return pThis->ExternalAddRef();
  147. }
  148.  
  149. STDMETHODIMP_(ULONG) COleDropSource::XDropSource::Release()
  150. {
  151.     METHOD_PROLOGUE_EX_(COleDropSource, DropSource)
  152.     return pThis->ExternalRelease();
  153. }
  154.  
  155. STDMETHODIMP COleDropSource::XDropSource::QueryInterface(
  156.     REFIID iid, LPVOID* ppvObj)
  157. {
  158.     METHOD_PROLOGUE_EX_(COleDropSource, DropSource)
  159.     return pThis->ExternalQueryInterface(&iid, ppvObj);
  160. }
  161.  
  162. STDMETHODIMP COleDropSource::XDropSource::QueryContinueDrag(
  163.     THIS_ BOOL fEscapePressed, DWORD dwKeyState)
  164. {
  165.     METHOD_PROLOGUE_EX_(COleDropSource, DropSource)
  166.  
  167.     return pThis->QueryContinueDrag(fEscapePressed, dwKeyState);
  168. }
  169.  
  170. STDMETHODIMP COleDropSource::XDropSource::GiveFeedback(THIS_ DWORD dwEffect)
  171. {
  172.     METHOD_PROLOGUE_EX(COleDropSource, DropSource)
  173.     ASSERT_VALID(pThis);
  174.  
  175.     return pThis->GiveFeedback(dwEffect);
  176. }
  177.  
  178. /////////////////////////////////////////////////////////////////////////////
  179. // helper for doing drag/drop with COleDataSource object
  180.  
  181. DROPEFFECT COleDataSource::DoDragDrop(DWORD dwEffects,
  182.     LPCRECT lpRectStartDrag, COleDropSource* pDropSource)
  183. {
  184.     ASSERT_VALID(this);
  185.     if (pDropSource != NULL)
  186.         ASSERT_VALID(pDropSource);
  187.     ASSERT(lpRectStartDrag == NULL ||
  188.         AfxIsValidAddress(lpRectStartDrag, sizeof(RECT), FALSE));
  189.  
  190.     // use standard drop source implementation if one not provided
  191.     COleDropSource dropSource;
  192.     if (pDropSource == NULL)
  193.         pDropSource = &dropSource;
  194.  
  195.     // setup drag/drop sensitivity rect
  196.     pDropSource->m_bDragStarted = FALSE;
  197.  
  198.     if (lpRectStartDrag != NULL)
  199.     {
  200.         // set drop source drag start rect to parameter provided
  201.         pDropSource->m_rectStartDrag.CopyRect(lpRectStartDrag);
  202.     }
  203.     else
  204.     {
  205.         // otherwise start with default empty rectangle around current point
  206.         CPoint ptCursor;
  207.         GetCursorPos(&ptCursor);
  208.         pDropSource->m_rectStartDrag.SetRect(
  209.             ptCursor.x, ptCursor.y, ptCursor.x, ptCursor.y);
  210.     }
  211.  
  212.     if (pDropSource->m_rectStartDrag.IsRectNull())
  213.     {
  214.         // null rect specifies no OnBeginDrag wait loop
  215.         pDropSource->m_bDragStarted = TRUE;
  216.     }
  217.     else if (pDropSource->m_rectStartDrag.IsRectEmpty())
  218.     {
  219.         // empty rect specifies drag drop around starting point
  220.         pDropSource->m_rectStartDrag.InflateRect(
  221.             COleDropSource::nDragMinDist, COleDropSource::nDragMinDist);
  222.     }
  223.     ASSERT_VALID(pDropSource);
  224.  
  225.     // before calling OLE drag/drop code, wait for mouse to move outside
  226.     //  the rectangle
  227.     ASSERT_VALID(AfxGetMainWnd());
  228.     if (!pDropSource->OnBeginDrag(AfxGetMainWnd()))
  229.         return DROPEFFECT_NONE;
  230.  
  231.     // call global OLE api to do the drag drop
  232.     LPDATAOBJECT lpDataObject = (LPDATAOBJECT)GetInterface(&IID_IDataObject);
  233.     LPDROPSOURCE lpDropSource =
  234.         (LPDROPSOURCE)pDropSource->GetInterface(&IID_IDropSource);
  235.     DWORD dwResultEffect = DROPEFFECT_NONE;
  236.     ::DoDragDrop(lpDataObject, lpDropSource, dwEffects, &dwResultEffect);
  237.     return dwResultEffect;
  238. }
  239.  
  240. /////////////////////////////////////////////////////////////////////////////
  241. // COleDropSource diagnostics
  242.  
  243. #ifdef _DEBUG
  244. void COleDropSource::Dump(CDumpContext& dc) const
  245. {
  246.     CCmdTarget::Dump(dc);
  247.  
  248.     dc << "m_bDragStarted = " << m_bDragStarted;
  249.     dc << "\nm_rectStartDrag.left = " << m_rectStartDrag.left;
  250.     dc << "\nm_rectStartDrag.top = " << m_rectStartDrag.top;
  251.     dc << "\nm_rectStartDrag.right = " << m_rectStartDrag.right;
  252.     dc << "\nm_rectStartDrag.bottom = " << m_rectStartDrag.bottom;
  253.  
  254.     dc << "\n";
  255. }
  256. #endif
  257.  
  258. /////////////////////////////////////////////////////////////////////////////
  259.