home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / inole2 / chap13 / patron / droptgt.cpp < prev    next >
C/C++ Source or Header  |  1995-05-03  |  13KB  |  520 lines

  1. /*
  2.  * DROPTGT.CPP
  3.  * Patron Chapter 13
  4.  *
  5.  * Implementation of a DropTarget object
  6.  *
  7.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  8.  *
  9.  * Kraig Brockschmidt, Microsoft
  10.  * Internet  :  kraigb@microsoft.com
  11.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  12.  */
  13.  
  14.  
  15. #include "patron.h"
  16.  
  17.  
  18. /*
  19.  * CDropTarget::CDropTarget
  20.  * CDropTarget::~CDropTarget
  21.  *
  22.  * Constructor Parameters:
  23.  *  pDoc            PCPatronDoc of the window containing us.
  24.  */
  25.  
  26. CDropTarget::CDropTarget(PCPatronDoc pDoc)
  27.     {
  28.     m_cRef=0;
  29.     m_pDoc=pDoc;
  30.  
  31.     m_pIDataObject=NULL;
  32.     return;
  33.     }
  34.  
  35.  
  36. CDropTarget::~CDropTarget(void)
  37.     {
  38.     return;
  39.     }
  40.  
  41.  
  42.  
  43.  
  44. /*
  45.  * CDropTarget::QueryInterface
  46.  * CDropTarget::AddRef
  47.  * CDropTarget::Release
  48.  *
  49.  * Purpose:
  50.  *  IUnknown members for CDropTarget object.
  51.  */
  52.  
  53. STDMETHODIMP CDropTarget::QueryInterface(REFIID riid, PPVOID ppv)
  54.     {
  55.     *ppv=NULL;
  56.  
  57.     if (IID_IUnknown==riid || IID_IDropTarget==riid)
  58.         *ppv=this;
  59.  
  60.     if (NULL!=*ppv)
  61.         {
  62.         ((LPUNKNOWN)*ppv)->AddRef();
  63.         return NOERROR;
  64.         }
  65.  
  66.     return ResultFromScode(E_NOINTERFACE);
  67.     }
  68.  
  69.  
  70. STDMETHODIMP_(ULONG) CDropTarget::AddRef(void)
  71.     {
  72.     return ++m_cRef;
  73.     }
  74.  
  75. STDMETHODIMP_(ULONG) CDropTarget::Release(void)
  76.     {
  77.     if (0!=--m_cRef)
  78.         return m_cRef;
  79.  
  80.     delete this;
  81.     return 0;
  82.     }
  83.  
  84.  
  85.  
  86.  
  87.  
  88. /*
  89.  * CDropTarget::DragEnter
  90.  *
  91.  * Purpose:
  92.  *  Indicates that data in a drag operation has been dragged over
  93.  *  our window that's a potential target.  We are to decide if it's
  94.  *  something in which we're interested.
  95.  *
  96.  * Parameters:
  97.  *  pIDataSource    LPDATAOBJECT providing the source data.
  98.  *  grfKeyState     DWORD flags: states of keys and mouse buttons.
  99.  *  pt              POINTL coordinates in the client space of
  100.  *                  the document.
  101.  *  pdwEffect       LPDWORD into which we'll place the appropriate
  102.  *                  effect flag for this point.
  103.  *
  104.  * Return Value:
  105.  *  HRESULT         NOERROR
  106.  */
  107.  
  108. STDMETHODIMP CDropTarget::DragEnter(LPDATAOBJECT pIDataSource
  109.     , DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
  110.     {
  111.     PCPages         ppg=m_pDoc->m_pPG;
  112.     HWND            hWnd;
  113.     FORMATETC       fe;
  114.     STGMEDIUM       stm;
  115.     UINT            uRet;
  116.  
  117.     m_fFeedback=FALSE;
  118.     m_pIDataObject=NULL;
  119.  
  120.     if (!m_pDoc->FQueryPasteFromData(pIDataSource, &fe, NULL))
  121.         {
  122.         *pdwEffect=DROPEFFECT_NONE;
  123.         return NOERROR;
  124.         }
  125.  
  126.     //Check if this is a valid drop point.
  127.     uRet=ppg->UTestDroppablePoint(&pt);
  128.     ppg->m_uLastTest=uRet;
  129.  
  130.     if (UDROP_NONE==uRet)
  131.         *pdwEffect=DROPEFFECT_NONE;
  132.     else
  133.         {
  134.         //Default is move if we can, in fact drop here.
  135.         *pdwEffect=DROPEFFECT_MOVE;
  136.  
  137.         if (grfKeyState & MK_CONTROL)
  138.             *pdwEffect=DROPEFFECT_COPY;
  139.         }
  140.  
  141.     m_pIDataObject=pIDataSource;
  142.     m_pIDataObject->AddRef();
  143.  
  144.     /*
  145.      * Determine the size of the data, if we can.  The default is
  146.      * a small rectangle since we can't easily tell what size
  147.      * something will be if we're pulling in a metafile or bitmap.
  148.      * It's not a good idea to render it here with GetData just to
  149.      * find that out. We only know the size if it's our own object
  150.      * in which case a GetData will be fast.
  151.      */
  152.  
  153.     if (fe.cfFormat==m_pDoc->m_cf)
  154.         {
  155.         if (SUCCEEDED(pIDataSource->GetData(&fe, &stm)))
  156.             {
  157.             PPATRONOBJECT   ppo;
  158.             RECT            rc;
  159.  
  160.             ppo=(PPATRONOBJECT)GlobalLock(stm.hGlobal);
  161.  
  162.             SetRect(&rc, (int)ppo->szl.cx, -(int)ppo->szl.cy, 0, 0);
  163.             RectConvertMappings(&rc, NULL, TRUE);
  164.             SETSIZEL(m_szl, rc.left, rc.top);
  165.  
  166.             m_ptPick=ppo->ptlPick;
  167.             m_fe=ppo->fe;
  168.  
  169.             GlobalUnlock(stm.hGlobal);
  170.             ReleaseStgMedium(&stm);
  171.             }
  172.         }
  173.     else
  174.         {
  175.         SETSIZEL(m_szl, 30, 30);
  176.         m_ptPick.x=0;
  177.         m_ptPick.y=0;
  178.         m_fe.cfFormat=0;
  179.         }
  180.  
  181.  
  182.     //Bring the document window up front, show what a drop will do.
  183.     hWnd=m_pDoc->Window();
  184.     BringWindowToTop(hWnd);
  185.     UpdateWindow(hWnd);
  186.  
  187.     ppg->m_uVScrollCode=NOVALUE;
  188.     ppg->m_uHScrollCode=NOVALUE;
  189.     m_fPendingRepaint=FALSE;
  190.  
  191.     pt.x-=m_ptPick.x;
  192.     pt.y-=m_ptPick.y;
  193.  
  194.     m_ptLast=pt;
  195.     m_fFeedback=TRUE;
  196.     ppg->DrawDropTargetRect(&pt, &m_szl);
  197.  
  198.     return NOERROR;
  199.     }
  200.  
  201.  
  202.  
  203.  
  204.  
  205.  
  206. /*
  207.  * CDropTarget::DragOver
  208.  *
  209.  * Purpose:
  210.  *  Indicates that the mouse was moved inside the window represented
  211.  *  by this drop target.  This happens on every WM_MOUSEMOVE, so
  212.  *  this function should be very efficient.
  213.  *
  214.  * Parameters:
  215.  *  grfKeyState     DWORD providing the current keyboard and
  216.  *                  mouse states
  217.  *  pt              POINTL where the mouse currently is.
  218.  *  pdwEffect       LPDWORD in which to store the effect flag
  219.  *                  for this point.
  220.  *
  221.  * Return Value:
  222.  *  HRESULT         NOERROR
  223.  */
  224.  
  225. STDMETHODIMP CDropTarget::DragOver(DWORD grfKeyState, POINTL pt
  226.     , LPDWORD pdwEffect)
  227.     {
  228.     PCPages     ppg=m_pDoc->m_pPG;
  229.     UINT        uRet, uLast;
  230.     UINT        xPos, yPos;
  231.  
  232.     *pdwEffect=DROPEFFECT_NONE;
  233.  
  234.     if (NULL==m_pIDataObject)
  235.         return NOERROR;
  236.  
  237.     //Check if this is still a valid point.  uRet used below as well
  238.     uRet=ppg->UTestDroppablePoint(&pt);
  239.  
  240.     if (UDROP_NONE==uRet)
  241.         *pdwEffect=DROPEFFECT_NONE;
  242.     else
  243.         {
  244.         //Store these before possibly ORing in DROPEFFECT_SCROLL
  245.         *pdwEffect=DROPEFFECT_MOVE;
  246.  
  247.         if (grfKeyState & MK_CONTROL)
  248.             *pdwEffect=DROPEFFECT_COPY;
  249.         }
  250.  
  251.     //If we haven't moved and we are not scrolling, then we're done.
  252.     if ((pt.x-m_ptPick.x==m_ptLast.x)
  253.         && (pt.y-m_ptPick.y==m_ptLast.y)
  254.         && !((UDROP_INSETHORZ|UDROP_INSETVERT) & ppg->m_uLastTest))
  255.         {
  256.         return NOERROR;
  257.         }
  258.  
  259.     //Remove the last feedback rectangle.
  260.     if (m_fFeedback)
  261.         ppg->DrawDropTargetRect(&m_ptLast, &m_szl);
  262.  
  263.     uLast=ppg->m_uLastTest;
  264.     ppg->m_uLastTest=uRet;
  265.  
  266.     if (UDROP_NONE==uRet)
  267.         {
  268.         //If we're now an invalid point, better repaint as necessary
  269.         if (m_fPendingRepaint)
  270.             {
  271.             UpdateWindow(ppg->m_hWnd);
  272.             m_fPendingRepaint=FALSE;
  273.             }
  274.  
  275.         ppg->m_uVScrollCode=NOVALUE;
  276.         ppg->m_uHScrollCode=NOVALUE;
  277.         m_fFeedback=FALSE;
  278.         return NOERROR;
  279.         }
  280.  
  281.  
  282.     /*
  283.      * Scrolling is a little tricky:  We get a DragOver pulse even
  284.      * if we didn't move.  First we have to delay scrolling for
  285.      * ppg->m_uScrollDelay clock ticks which we can determine using
  286.      * GetTickCount.  Timers do not work here since we may not be
  287.      * yielding to our message loop.
  288.      *
  289.      * Once we know we are scrolling then we determine if we
  290.      * scroll again or if we reset the scrolling state.
  291.      */
  292.  
  293.     if ((UDROP_INSETHORZ & uLast) && !(UDROP_INSETHORZ & uRet))
  294.         ppg->m_uHScrollCode=NOVALUE;
  295.  
  296.     if (!(UDROP_INSETHORZ & uLast) && (UDROP_INSETHORZ & uRet))
  297.         {
  298.         ppg->m_dwTimeLast=GetTickCount();
  299.         ppg->m_uHScrollCode=(0!=(UDROP_INSETLEFT & uRet))
  300.             ? SB_LINELEFT : SB_LINERIGHT; //Same as UP & DOWN codes.
  301.         }
  302.  
  303.     if ((UDROP_INSETVERT & uLast) && !(UDROP_INSETVERT & uRet))
  304.         ppg->m_uVScrollCode=NOVALUE;
  305.  
  306.     if (!(UDROP_INSETVERT & uLast) && (UDROP_INSETVERT & uRet))
  307.         {
  308.         ppg->m_dwTimeLast=GetTickCount();
  309.         ppg->m_uVScrollCode=(0!=(UDROP_INSETTOP & uRet))
  310.             ? SB_LINEUP : SB_LINEDOWN;
  311.         }
  312.  
  313.     //Only change the last time if ALL scrolling stops.
  314.     if (NOVALUE==ppg->m_uHScrollCode && NOVALUE==ppg->m_uVScrollCode)
  315.         ppg->m_dwTimeLast=0L;
  316.  
  317.     //Set the scroll effect on any inset hit.
  318.     if ((UDROP_INSETHORZ | UDROP_INSETVERT) & uRet)
  319.         *pdwEffect |= DROPEFFECT_SCROLL;
  320.  
  321.     xPos=ppg->m_xPos;
  322.     yPos=ppg->m_yPos;
  323.  
  324.     //Has the delay elapsed?  We can scroll if so
  325.     if (ppg->m_dwTimeLast!=0
  326.         && (GetTickCount()-ppg->m_dwTimeLast)
  327.         > (DWORD)ppg->m_uScrollDelay)
  328.         {
  329.         if (NOVALUE!=ppg->m_uHScrollCode)
  330.             {
  331.             m_fPendingRepaint=TRUE;
  332.             SendMessage(ppg->m_hWnd, WM_HSCROLL
  333.                 , ppg->m_uHScrollCode, 0L);
  334.             }
  335.  
  336.         if (NOVALUE!=ppg->m_uVScrollCode)
  337.             {
  338.             m_fPendingRepaint=TRUE;
  339.             SendMessage(ppg->m_hWnd, WM_VSCROLL
  340.                 , ppg->m_uVScrollCode, 0L);
  341.             }
  342.         }
  343.  
  344.     //If we didn't scroll but have a pending repaint, do it now.
  345.     if (xPos==ppg->m_xPos && yPos==ppg->m_yPos && m_fPendingRepaint)
  346.         {
  347.         UpdateWindow(ppg->m_hWnd);
  348.         m_fPendingRepaint=FALSE;
  349.         }
  350.  
  351.     pt.x-=m_ptPick.x;
  352.     pt.y-=m_ptPick.y;
  353.  
  354.     m_ptLast=pt;
  355.     m_fFeedback=TRUE;
  356.     ppg->DrawDropTargetRect(&pt, &m_szl);
  357.  
  358.     return NOERROR;
  359.     }
  360.  
  361.  
  362.  
  363.  
  364.  
  365.  
  366. /*
  367.  * CDropTarget::DragLeave
  368.  *
  369.  * Purpose:
  370.  *  Informs the drop target that the operation has left its window.
  371.  *
  372.  * Parameters:
  373.  *  None
  374.  *
  375.  * Return Value:
  376.  *  HRESULT         NOERROR
  377.  */
  378.  
  379. STDMETHODIMP CDropTarget::DragLeave(void)
  380.     {
  381.     PCPages         ppg=m_pDoc->m_pPG;
  382.  
  383.     if (NULL==m_pIDataObject)
  384.         return NOERROR;
  385.  
  386.     //Stop scrolling
  387.     ppg->m_uHScrollCode=NOVALUE;
  388.     ppg->m_uVScrollCode=NOVALUE;
  389.  
  390.     if (m_fPendingRepaint)
  391.         UpdateWindow(ppg->m_hWnd);
  392.  
  393.     //Remove the last feedback rectangle.
  394.     if (m_fFeedback)
  395.         ppg->DrawDropTargetRect(&m_ptLast, &m_szl);
  396.  
  397.     m_fFeedback=FALSE;
  398.     m_pIDataObject->Release();
  399.     return NOERROR;
  400.     }
  401.  
  402.  
  403.  
  404.  
  405.  
  406. /*
  407.  * CDropTarget::Drop
  408.  *
  409.  * Purpose:
  410.  *  Instructs the drop target to paste the data that was just now
  411.  *  dropped on it.
  412.  *
  413.  * Parameters:
  414.  *  pIDataSource    LPDATAOBJECT from which we'll paste.
  415.  *  grfKeyState     DWORD providing current keyboard/mouse state.
  416.  *  pt              POINTL at which the drop occurred.
  417.  *  pdwEffect       LPDWORD in which to store what you did.
  418.  *
  419.  * Return Value:
  420.  *  HRESULT         NOERROR
  421.  */
  422.  
  423. STDMETHODIMP CDropTarget::Drop(LPDATAOBJECT pIDataSource
  424.     , DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
  425.     {
  426.     PCPages         ppg=m_pDoc->m_pPG;
  427.     BOOL            fRet=TRUE;
  428.     FORMATETC       fe;
  429.     TENANTTYPE      tType;
  430.     PATRONOBJECT    po;
  431.     POINT           ptS;
  432.  
  433.     *pdwEffect=DROPEFFECT_NONE;
  434.  
  435.     if (NULL==m_pIDataObject)
  436.         return ResultFromScode(E_FAIL);
  437.  
  438.     if (UDROP_NONE==ppg->UTestDroppablePoint(&pt))
  439.         return ResultFromScode(E_FAIL);
  440.  
  441.     //Stop scrolling
  442.     ppg->m_uHScrollCode=NOVALUE;
  443.     ppg->m_uVScrollCode=NOVALUE;
  444.  
  445.     if (m_fPendingRepaint)
  446.         UpdateWindow(ppg->m_hWnd);
  447.  
  448.     //2.  Remove the UI feedback
  449.     if (m_fFeedback)
  450.         ppg->DrawDropTargetRect(&m_ptLast, &m_szl);
  451.  
  452.     m_pIDataObject->Release();
  453.  
  454.  
  455.     /*
  456.      * Check if we can do the paste, and if so, tell our pasting
  457.      * mechanism exactly where to place us.
  458.      */
  459.     pt.x-=m_ptPick.x;
  460.     pt.y-=m_ptPick.y;
  461.  
  462.     POINTFROMPOINTL(ptS, pt);
  463.     ScreenToClient(ppg->Window(), &ptS);
  464.     POINTLFROMPOINT(po.ptl, ptS);
  465.  
  466.     //This is true if we didn't see placement data in DragEnter
  467.     if (0!=m_fe.cfFormat)
  468.         {
  469.         po.szl.cx=m_szl.cx;         //We stored these positive
  470.         po.szl.cy=-m_szl.cy;
  471.         }
  472.     else
  473.         SETSIZEL(po.szl, 0, 0); //Ask object for its size.
  474.  
  475.     //Adjust for scrolling and mapping mode.
  476.     ppg->AdjustPosition(&po.ptl, &po.szl);
  477.  
  478.  
  479.     /*
  480.      * If we're in the same document and moving, then we can just
  481.      * stuff the Pages' m_ptDrop which will move us and return.
  482.      */
  483.     if (ppg->m_fDragSource && !(grfKeyState & MK_CONTROL))
  484.         {
  485.         *pdwEffect=DROPEFFECT_MOVE;
  486.         ppg->m_fMoveInPage=TRUE;
  487.         ppg->m_ptDrop=po.ptl;
  488.         return NOERROR;
  489.         }
  490.  
  491.     /*
  492.      * Otherwise, paste either from another document or from
  493.      * the same document which will always be a copy to the new
  494.      * point.
  495.      */
  496.  
  497.     ppg->m_fMoveInPage=FALSE;
  498.     fRet=m_pDoc->FQueryPasteFromData(pIDataSource, &fe, &tType);
  499.  
  500.     if (fRet)
  501.         {
  502.         //Copy the real format if we have placement data.
  503.         po.fe=(m_pDoc->m_cf==fe.cfFormat) ? m_fe : fe;
  504.  
  505.         fRet=m_pDoc->PasteFromData(pIDataSource, &fe, tType
  506.             , &po, 0);
  507.         }
  508.  
  509.     if (!fRet)
  510.         return ResultFromScode(E_FAIL);
  511.  
  512.  
  513.     *pdwEffect=DROPEFFECT_MOVE;
  514.  
  515.     if (grfKeyState & MK_CONTROL)
  516.         *pdwEffect=DROPEFFECT_COPY;
  517.  
  518.     return NOERROR;
  519.     }
  520.