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 / chap20 / patron / droptgt.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-03  |  15.0 KB  |  598 lines

  1. /*
  2.  * DROPTGT.CPP
  3.  * Patron Chapter 20
  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.     //CHAPTER20MOD
  127.     //Check if we can link from this data object as well.
  128.     ppg->m_fLinkAllowed
  129.         =(NOERROR==OleQueryLinkFromData(pIDataSource));
  130.  
  131.     //We never allow it dragging in ourselves.
  132.     ppg->m_fLinkAllowed &= !ppg->m_fDragSource;
  133.     //End CHAPTER20MOD
  134.  
  135.     //Check if this is a valid drop point.
  136.     uRet=ppg->UTestDroppablePoint(&pt);
  137.     ppg->m_uLastTest=uRet;
  138.  
  139.     if (UDROP_NONE==uRet)
  140.         *pdwEffect=DROPEFFECT_NONE;
  141.     else
  142.         {
  143.         //Default is move if we can, in fact drop here.
  144.         *pdwEffect=DROPEFFECT_MOVE;
  145.  
  146.         //CHAPTER20MOD
  147.         if (grfKeyState & MK_CONTROL)
  148.             {
  149.             if (ppg->m_fLinkAllowed && (grfKeyState & MK_SHIFT))
  150.                 *pdwEffect=DROPEFFECT_LINK;
  151.             else
  152.                 *pdwEffect=DROPEFFECT_COPY;
  153.             }
  154.         //End CHAPTER20MOD
  155.         }
  156.  
  157.     m_pIDataObject=pIDataSource;
  158.     m_pIDataObject->AddRef();
  159.  
  160.     /*
  161.      * Determine the size of the data, if we can.  The default is
  162.      * a small rectangle since we can't easily tell what size
  163.      * something will be if we're pulling in a metafile or bitmap.
  164.      * It's not a good idea to render it here with GetData just to
  165.      * find that out. We only know the size if it's our own object
  166.      * in which case a GetData will be fast.
  167.      */
  168.  
  169.     if (fe.cfFormat==m_pDoc->m_cf)
  170.         {
  171.         if (SUCCEEDED(pIDataSource->GetData(&fe, &stm)))
  172.             {
  173.             PPATRONOBJECT   ppo;
  174.             RECT            rc;
  175.  
  176.             ppo=(PPATRONOBJECT)GlobalLock(stm.hGlobal);
  177.  
  178.             SetRect(&rc, (int)ppo->szl.cx, -(int)ppo->szl.cy, 0, 0);
  179.             RectConvertMappings(&rc, NULL, TRUE);
  180.             SETSIZEL(m_szl, rc.left, rc.top);
  181.  
  182.             m_ptPick=ppo->ptlPick;
  183.             m_fe=ppo->fe;
  184.  
  185.             GlobalUnlock(stm.hGlobal);
  186.             ReleaseStgMedium(&stm);
  187.             }
  188.         }
  189.     else
  190.         {
  191.         SETSIZEL(m_szl, 30, 30);
  192.         m_ptPick.x=0;
  193.         m_ptPick.y=0;
  194.         m_fe.cfFormat=0;
  195.  
  196.         /*
  197.          * Try to get CFSTR_OBJECTDESCRIPTOR which might have a size
  198.          * and a pick point.  If it exists, then always use the
  199.          * point but still default to a 30*30 size if the sizes
  200.          * are zero.
  201.          */
  202.         uRet=RegisterClipboardFormat(CFSTR_OBJECTDESCRIPTOR);
  203.         SETDefFormatEtc(fe, uRet, TYMED_HGLOBAL);
  204.  
  205.         if (SUCCEEDED(pIDataSource->GetData(&fe, &stm)))
  206.             {
  207.             LPOBJECTDESCRIPTOR  pOD;
  208.  
  209.             pOD=(LPOBJECTDESCRIPTOR)GlobalLock(stm.hGlobal);
  210.  
  211.             //Get the size, converting to LOMETRIC.
  212.             if (0!=pOD->sizel.cx && 0!=pOD->sizel.cy)
  213.                 {
  214.                 XformSizeInHimetricToPixels(NULL, &pOD->sizel
  215.                     , &m_szl);
  216.                 }
  217.  
  218.             //POINTL and SIZEL are interchangeable
  219.             XformSizeInHimetricToPixels(NULL, (LPSIZEL)&pOD->pointl
  220.                 , (LPSIZEL)&m_ptPick);
  221.  
  222.             GlobalUnlock(stm.hGlobal);
  223.             ReleaseStgMedium(&stm);
  224.             }
  225.         }
  226.  
  227.  
  228.     //Bring the document window up front, show what a drop will do.
  229.     hWnd=m_pDoc->Window();
  230.     BringWindowToTop(hWnd);
  231.     UpdateWindow(hWnd);
  232.  
  233.     ppg->m_uVScrollCode=NOVALUE;
  234.     ppg->m_uHScrollCode=NOVALUE;
  235.     m_fPendingRepaint=FALSE;
  236.  
  237.     pt.x-=m_ptPick.x;
  238.     pt.y-=m_ptPick.y;
  239.  
  240.     m_ptLast=pt;
  241.     m_fFeedback=TRUE;
  242.     ppg->DrawDropTargetRect(&pt, &m_szl);
  243.  
  244.     return NOERROR;
  245.     }
  246.  
  247.  
  248.  
  249.  
  250.  
  251.  
  252. /*
  253.  * CDropTarget::DragOver
  254.  *
  255.  * Purpose:
  256.  *  Indicates that the mouse was moved inside the window represented
  257.  *  by this drop target.  This happens on every WM_MOUSEMOVE, so
  258.  *  this function should be very efficient.
  259.  *
  260.  * Parameters:
  261.  *  grfKeyState     DWORD providing the current keyboard and
  262.  *                  mouse states
  263.  *  pt              POINTL where the mouse currently is.
  264.  *  pdwEffect       LPDWORD in which to store the effect flag
  265.  *                  for this point.
  266.  *
  267.  * Return Value:
  268.  *  HRESULT         NOERROR
  269.  */
  270.  
  271. STDMETHODIMP CDropTarget::DragOver(DWORD grfKeyState, POINTL pt
  272.     , LPDWORD pdwEffect)
  273.     {
  274.     PCPages     ppg=m_pDoc->m_pPG;
  275.     UINT        uRet, uLast;
  276.     UINT        xPos, yPos;
  277.  
  278.     *pdwEffect=DROPEFFECT_NONE;
  279.  
  280.     if (NULL==m_pIDataObject)
  281.         return NOERROR;
  282.  
  283.     //Check if this is still a valid point.  uRet used below as well
  284.     uRet=ppg->UTestDroppablePoint(&pt);
  285.  
  286.     if (UDROP_NONE==uRet)
  287.         *pdwEffect=DROPEFFECT_NONE;
  288.     else
  289.         {
  290.         //Store these before possibly ORing in DROPEFFECT_SCROLL
  291.         *pdwEffect=DROPEFFECT_MOVE;
  292.  
  293.         //CHAPTER20MOD
  294.         if (grfKeyState & MK_CONTROL)
  295.             {
  296.             if (ppg->m_fLinkAllowed && (grfKeyState & MK_SHIFT))
  297.                 *pdwEffect=DROPEFFECT_LINK;
  298.             else
  299.                 *pdwEffect=DROPEFFECT_COPY;
  300.             }
  301.         //End CHAPTER20MOD
  302.         }
  303.  
  304.     //If we haven't moved and we are not scrolling, then we're done.
  305.     if ((pt.x-m_ptPick.x==m_ptLast.x)
  306.         && (pt.y-m_ptPick.y==m_ptLast.y)
  307.         && !((UDROP_INSETHORZ|UDROP_INSETVERT) & ppg->m_uLastTest))
  308.         {
  309.         return NOERROR;
  310.         }
  311.  
  312.     //Remove the last feedback rectangle.
  313.     if (m_fFeedback)
  314.         ppg->DrawDropTargetRect(&m_ptLast, &m_szl);
  315.  
  316.     uLast=ppg->m_uLastTest;
  317.     ppg->m_uLastTest=uRet;
  318.  
  319.     if (UDROP_NONE==uRet)
  320.         {
  321.         //If we're now an invalid point, better repaint as necessary
  322.         if (m_fPendingRepaint)
  323.             {
  324.             UpdateWindow(ppg->m_hWnd);
  325.             m_fPendingRepaint=FALSE;
  326.             }
  327.  
  328.         ppg->m_uVScrollCode=NOVALUE;
  329.         ppg->m_uHScrollCode=NOVALUE;
  330.         m_fFeedback=FALSE;
  331.         return NOERROR;
  332.         }
  333.  
  334.  
  335.     /*
  336.      * Scrolling is a little tricky:  We get a DragOver pulse even
  337.      * if we didn't move.  First we have to delay scrolling for
  338.      * ppg->m_uScrollDelay clock ticks which we can determine using
  339.      * GetTickCount.  Timers do not work here since we may not be
  340.      * yielding to our message loop.
  341.      *
  342.      * Once we know we are scrolling then we determine if we
  343.      * scroll again or if we reset the scrolling state.
  344.      */
  345.  
  346.     if ((UDROP_INSETHORZ & uLast) && !(UDROP_INSETHORZ & uRet))
  347.         ppg->m_uHScrollCode=NOVALUE;
  348.  
  349.     if (!(UDROP_INSETHORZ & uLast) && (UDROP_INSETHORZ & uRet))
  350.         {
  351.         ppg->m_dwTimeLast=GetTickCount();
  352.         ppg->m_uHScrollCode=(0!=(UDROP_INSETLEFT & uRet))
  353.             ? SB_LINELEFT : SB_LINERIGHT; //Same as UP & DOWN codes.
  354.         }
  355.  
  356.     if ((UDROP_INSETVERT & uLast) && !(UDROP_INSETVERT & uRet))
  357.         ppg->m_uVScrollCode=NOVALUE;
  358.  
  359.     if (!(UDROP_INSETVERT & uLast) && (UDROP_INSETVERT & uRet))
  360.         {
  361.         ppg->m_dwTimeLast=GetTickCount();
  362.         ppg->m_uVScrollCode=(0!=(UDROP_INSETTOP & uRet))
  363.             ? SB_LINEUP : SB_LINEDOWN;
  364.         }
  365.  
  366.     //Only change the last time if ALL scrolling stops.
  367.     if (NOVALUE==ppg->m_uHScrollCode && NOVALUE==ppg->m_uVScrollCode)
  368.         ppg->m_dwTimeLast=0L;
  369.  
  370.     //Set the scroll effect on any inset hit.
  371.     if ((UDROP_INSETHORZ | UDROP_INSETVERT) & uRet)
  372.         *pdwEffect |= DROPEFFECT_SCROLL;
  373.  
  374.     xPos=ppg->m_xPos;
  375.     yPos=ppg->m_yPos;
  376.  
  377.     //Has the delay elapsed?  We can scroll if so
  378.     if (ppg->m_dwTimeLast!=0
  379.         && (GetTickCount()-ppg->m_dwTimeLast)
  380.         > (DWORD)ppg->m_uScrollDelay)
  381.         {
  382.         if (NOVALUE!=ppg->m_uHScrollCode)
  383.             {
  384.             m_fPendingRepaint=TRUE;
  385.             SendMessage(ppg->m_hWnd, WM_HSCROLL
  386.                 , ppg->m_uHScrollCode, 0L);
  387.             }
  388.  
  389.         if (NOVALUE!=ppg->m_uVScrollCode)
  390.             {
  391.             m_fPendingRepaint=TRUE;
  392.             SendMessage(ppg->m_hWnd, WM_VSCROLL
  393.                 , ppg->m_uVScrollCode, 0L);
  394.             }
  395.         }
  396.  
  397.     //If we didn't scroll but have a pending repaint, do it now.
  398.     if (xPos==ppg->m_xPos && yPos==ppg->m_yPos && m_fPendingRepaint)
  399.         {
  400.         UpdateWindow(ppg->m_hWnd);
  401.         m_fPendingRepaint=FALSE;
  402.         }
  403.  
  404.     pt.x-=m_ptPick.x;
  405.     pt.y-=m_ptPick.y;
  406.  
  407.     m_ptLast=pt;
  408.     m_fFeedback=TRUE;
  409.     ppg->DrawDropTargetRect(&pt, &m_szl);
  410.  
  411.     return NOERROR;
  412.     }
  413.  
  414.  
  415.  
  416.  
  417.  
  418.  
  419. /*
  420.  * CDropTarget::DragLeave
  421.  *
  422.  * Purpose:
  423.  *  Informs the drop target that the operation has left its window.
  424.  *
  425.  * Parameters:
  426.  *  None
  427.  *
  428.  * Return Value:
  429.  *  HRESULT         NOERROR
  430.  */
  431.  
  432. STDMETHODIMP CDropTarget::DragLeave(void)
  433.     {
  434.     PCPages         ppg=m_pDoc->m_pPG;
  435.  
  436.     if (NULL==m_pIDataObject)
  437.         return NOERROR;
  438.  
  439.     //Stop scrolling
  440.     ppg->m_uHScrollCode=NOVALUE;
  441.     ppg->m_uVScrollCode=NOVALUE;
  442.  
  443.     if (m_fPendingRepaint)
  444.         UpdateWindow(ppg->m_hWnd);
  445.  
  446.     //Remove the last feedback rectangle.
  447.     if (m_fFeedback)
  448.         ppg->DrawDropTargetRect(&m_ptLast, &m_szl);
  449.  
  450.     m_fFeedback=FALSE;
  451.     m_pIDataObject->Release();
  452.     return NOERROR;
  453.     }
  454.  
  455.  
  456.  
  457.  
  458.  
  459. /*
  460.  * CDropTarget::Drop
  461.  *
  462.  * Purpose:
  463.  *  Instructs the drop target to paste the data that was just now
  464.  *  dropped on it.
  465.  *
  466.  * Parameters:
  467.  *  pIDataSource    LPDATAOBJECT from which we'll paste.
  468.  *  grfKeyState     DWORD providing current keyboard/mouse state.
  469.  *  pt              POINTL at which the drop occurred.
  470.  *  pdwEffect       LPDWORD in which to store what you did.
  471.  *
  472.  * Return Value:
  473.  *  HRESULT         NOERROR
  474.  */
  475.  
  476. STDMETHODIMP CDropTarget::Drop(LPDATAOBJECT pIDataSource
  477.     , DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
  478.     {
  479.     PCPages         ppg=m_pDoc->m_pPG;
  480.     BOOL            fRet=TRUE;
  481.     FORMATETC       fe;
  482.     TENANTTYPE      tType;
  483.     PATRONOBJECT    po;
  484.     POINT           ptS;
  485.  
  486.     *pdwEffect=DROPEFFECT_NONE;
  487.  
  488.     if (NULL==m_pIDataObject)
  489.         return ResultFromScode(E_FAIL);
  490.  
  491.     if (UDROP_NONE==ppg->UTestDroppablePoint(&pt))
  492.         return ResultFromScode(E_FAIL);
  493.  
  494.     //Stop scrolling
  495.     ppg->m_uHScrollCode=NOVALUE;
  496.     ppg->m_uVScrollCode=NOVALUE;
  497.  
  498.     if (m_fPendingRepaint)
  499.         UpdateWindow(ppg->m_hWnd);
  500.  
  501.     //2.  Remove the UI feedback
  502.     if (m_fFeedback)
  503.         ppg->DrawDropTargetRect(&m_ptLast, &m_szl);
  504.  
  505.     m_pIDataObject->Release();
  506.  
  507.  
  508.     /*
  509.      * Check if we can do the paste, and if so, tell our pasting
  510.      * mechanism exactly where to place us.
  511.      */
  512.     pt.x-=m_ptPick.x;
  513.     pt.y-=m_ptPick.y;
  514.  
  515.     POINTFROMPOINTL(ptS, pt);
  516.     ScreenToClient(ppg->Window(), &ptS);
  517.     POINTLFROMPOINT(po.ptl, ptS);
  518.  
  519.     //This is true if we didn't see placement data in DragEnter
  520.     if (0!=m_fe.cfFormat)
  521.         {
  522.         po.szl.cx=m_szl.cx;         //We stored these positive
  523.         po.szl.cy=-m_szl.cy;
  524.         }
  525.     else
  526.         SETSIZEL(po.szl, 0, 0); //Ask object for its size.
  527.  
  528.     //Adjust for scrolling and mapping mode.
  529.     ppg->AdjustPosition(&po.ptl, &po.szl);
  530.  
  531.  
  532.     /*
  533.      * If we're in the same document and moving, then we can just
  534.      * stuff the Pages' m_ptDrop which will move us and return.
  535.      */
  536.     if (ppg->m_fDragSource && !(grfKeyState & MK_CONTROL))
  537.         {
  538.         *pdwEffect=DROPEFFECT_MOVE;
  539.         ppg->m_fMoveInPage=TRUE;
  540.         ppg->m_ptDrop=po.ptl;
  541.         return NOERROR;
  542.         }
  543.  
  544.     /*
  545.      * Otherwise, paste either from another document or from
  546.      * the same document which will always be a copy to the new
  547.      * point.
  548.      */
  549.  
  550.     //CHAPTER20MOD
  551.     *pdwEffect=DROPEFFECT_MOVE;
  552.  
  553.     if (grfKeyState & MK_CONTROL)
  554.         {
  555.         if (ppg->m_fLinkAllowed && (grfKeyState & MK_SHIFT))
  556.             *pdwEffect=DROPEFFECT_LINK;
  557.         else
  558.             *pdwEffect=DROPEFFECT_COPY;
  559.         }
  560.  
  561.     ppg->m_fMoveInPage=FALSE;
  562.  
  563.     /*
  564.      * We know linking is desired if effect flag is set, so this
  565.      * function will get the FORMATETC for linking.  Otherwise
  566.      * FQueryPasteFromData will get the other FORMATETC to use.
  567.      */
  568.     if (DROPEFFECT_LINK==*pdwEffect)
  569.         {
  570.         fRet=m_pDoc->FQueryPasteLinkFromData(pIDataSource, &fe
  571.             , &tType);
  572.         }
  573.     else
  574.         fRet=m_pDoc->FQueryPasteFromData(pIDataSource, &fe, &tType);
  575.     //End CHAPTER20MOD
  576.  
  577.     if (fRet)
  578.         {
  579.         //Copy the real format if we have placement data.
  580.         po.fe=(m_pDoc->m_cf==fe.cfFormat) ? m_fe : fe;
  581.  
  582.         //Flag PasteFromData to use CFSTR_OBJECTDESCRIPTOR
  583.         fRet=m_pDoc->PasteFromData(pIDataSource, &fe, tType
  584.             , &po, 0, TRUE);
  585.         }
  586.  
  587.     if (!fRet)
  588.         return ResultFromScode(E_FAIL);
  589.  
  590.  
  591.     *pdwEffect=DROPEFFECT_MOVE;
  592.  
  593.     if (grfKeyState & MK_CONTROL)
  594.         *pdwEffect=DROPEFFECT_COPY;
  595.  
  596.     return NOERROR;
  597.     }
  598.