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

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