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 / pagemous.cpp < prev    next >
C/C++ Source or Header  |  1996-05-20  |  21KB  |  865 lines

  1. /*
  2.  * PAGEMOUS.CPP
  3.  * Patron Chapter 13
  4.  *
  5.  * Implementation of mouse-related member functions of CPage.
  6.  * The remainder is in PAGE.CPP.  This separate file keeps this
  7.  * grungy hit-testing/drawing code out of our way.
  8.  *
  9.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  10.  *
  11.  * Kraig Brockschmidt, Microsoft
  12.  * Internet  :  kraigb@microsoft.com
  13.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  14.  */
  15.  
  16.  
  17. #include "patron.h"
  18.  
  19.  
  20. //Lookups into the array using g_rgHTCode[x+y*3] in PAGEMOUS.CPP
  21. #define YTOP            0
  22. #define YMID            1
  23. #define YBOT            2
  24. #define XLEFT           0
  25. #define XMID            1
  26. #define XRIGHT          2
  27.  
  28. //Values to restrict sizing in CPage::OnMouseMove
  29. #define SIZINGTOP       0x0001
  30. #define SIZINGBOTTOM    0x0002
  31. #define SIZINGLEFT      0x0004
  32. #define SIZINGRIGHT     0x0008
  33.  
  34.  
  35. //This array is for hit-testing lookups
  36. static UINT g_rgHTCode[9]={HTTOPLEFT, HTTOP, HTTOPRIGHT
  37.     , HTLEFT, HTCLIENT, HTRIGHT, HTBOTTOMLEFT, HTBOTTOM
  38.     , HTBOTTOMRIGHT};
  39.  
  40.  
  41. //This is for restricting tracking based on the hit-test
  42. static UINT g_rguSizingFlags[9]={SIZINGTOP | SIZINGLEFT, SIZINGTOP
  43.     , SIZINGTOP | SIZINGRIGHT, SIZINGLEFT, 0, SIZINGRIGHT
  44.     , SIZINGBOTTOM | SIZINGLEFT, SIZINGBOTTOM
  45.     , SIZINGBOTTOM | SIZINGRIGHT};
  46.  
  47.  
  48.  
  49. /*
  50.  * CPage::OnLeftDown
  51.  *
  52.  * Purpose:
  53.  *  Called when the user clicks with the left button on this page.
  54.  *  We find the object under that position that is visibly on top
  55.  *  (always the first one under this location in the page list since
  56.  *  we paint in reverse order) and select it.
  57.  *
  58.  * Parameters:
  59.  *  uKeys           UINT carrying the key state.
  60.  *  x, y            UINT coordinates of the click in device units.
  61.  *
  62.  * Return Value:
  63.  *  BOOL            Indicates if the action changed the object.
  64.  */
  65.  
  66. BOOL CPage::OnLeftDown(UINT uKeys, UINT x, UINT y)
  67.     {
  68.     UINT        iTenant;
  69.     PCTenant    pTenant;
  70.  
  71.     //CHAPTER13MOD
  72.     /*
  73.      * If the mouse is in a position to start dragging,
  74.      * start the timer as with sizing below.
  75.      */
  76.     if (HTCAPTION==m_uHTCode)
  77.         {
  78.         m_fDragPending=TRUE;
  79.  
  80.         //Save down point and start timer.
  81.         m_ptDown.x=x;
  82.         m_ptDown.y=y;
  83.  
  84.         m_uKeysDown=uKeys;
  85.  
  86.         m_fTimer=TRUE;
  87.         SetTimer(m_hWnd, IDTIMER_DEBOUNCE, m_cDelay, NULL);
  88.         return FALSE;
  89.         }
  90.     //End CHAPTER13MOD
  91.  
  92.     /*
  93.      * If the mouse is in a position to start sizing, start
  94.      * the debounce timer and note the condition.  The sizing
  95.      * will start in OnTimer or OnMouseMove.  This will always
  96.      * happen on the currently selected tenant, and m_uHTCode is
  97.      * set in OnNCHitTest below.
  98.      */
  99.     if (HTNOWHERE!=m_uHTCode && HTCLIENT!=m_uHTCode)
  100.         {
  101.         m_fSizePending=TRUE;
  102.  
  103.         //Save down point and start timer.
  104.         m_ptDown.x=x;
  105.         m_ptDown.y=y;
  106.  
  107.         m_fTimer=TRUE;
  108.         SetTimer(m_hWnd, IDTIMER_DEBOUNCE, m_cDelay, NULL);
  109.         return FALSE;
  110.         }
  111.  
  112.     iTenant=TenantFromPoint(x, y, &pTenant);
  113.  
  114.     if (NULL==pTenant)
  115.         return FALSE;
  116.  
  117.     //If this one is already current, we might be now sizing.
  118.     if (pTenant==m_pTenantCur)
  119.         return FALSE;
  120.  
  121.     //Deselect the current tenant
  122.     if (NULL!=m_pTenantCur)
  123.         m_pTenantCur->Select(FALSE);
  124.  
  125.     //Move this tenant to the top of the list
  126.     m_iTenantCur=0;
  127.  
  128.     SendMessage(m_hWndTenantList, LB_DELETESTRING, iTenant, 0L);
  129.     SendMessage(m_hWndTenantList, LB_INSERTSTRING, 0,(LONG)pTenant);
  130.  
  131.     //Select and repaint the new tenant to show it up front
  132.     m_pTenantCur=pTenant;
  133.  
  134.     m_pTenantCur->Repaint();
  135.     m_pTenantCur->Select(TRUE);
  136.  
  137.     return FALSE;
  138.     }
  139.  
  140.  
  141.  
  142.  
  143.  
  144.  
  145. /*
  146.  * CPage::OnLeftUp
  147.  *
  148.  * Purpose:
  149.  *  Called when the user clicks up with the left button on this
  150.  *  page. We stop tracking on this message, if necessary, and
  151.  *  resize the object.
  152.  *
  153.  * Parameters:
  154.  *  uKeys           UINT carrying the key state.
  155.  *  x, y            UINT coordinates of the click in device units.
  156.  *
  157.  * Return Value:
  158.  *  BOOL            Indicates if this action changed the object.
  159.  */
  160.  
  161. BOOL CPage::OnLeftUp(UINT uKeys, UINT x, UINT y)
  162.     {
  163.     RECT    rc, rcT;
  164.  
  165.     //CHAPTER13MOD
  166.     if (m_fSizePending || m_fDragPending)
  167.     //End CHAPTER13MOD
  168.         {
  169.         m_fSizePending=FALSE;
  170.         //CHAPTER13MOD
  171.         m_fDragPending=FALSE;
  172.         //#nd CHAPTER13MOD
  173.  
  174.         if (m_fTimer)
  175.             {
  176.             KillTimer(m_hWnd, IDTIMER_DEBOUNCE);
  177.             m_fTimer=FALSE;
  178.             }
  179.  
  180.         return FALSE;
  181.         }
  182.  
  183.     if (!m_fTracking)
  184.         return FALSE;
  185.  
  186.     //Remove the dotted rectangle.
  187.     RECTFROMRECTL(rc, m_rcl)
  188.     DrawFocusRect(m_hDC, &rc);
  189.     ReleaseDC(m_hWnd, m_hDC);
  190.  
  191.     ReleaseCapture();
  192.     m_fTracking=FALSE;
  193.  
  194.     //If the original and new rects are the same, nothing happened.
  195.     RECTFROMRECTL(rcT, m_rclOrg);
  196.  
  197.     if (EqualRect(&rc, &rcT))
  198.         return FALSE;
  199.  
  200.     RECTFROMRECTL(rcT, m_rclOrg);
  201.     InvalidateRect(m_hWnd, &rcT, TRUE);
  202.  
  203.     //Invalidate on the screen before accounting for scrolling
  204.     InvalidateRect(m_hWnd, &rc, TRUE);
  205.  
  206.     //Factor in scrolling and tell the tenant where it now stands.
  207.     OffsetRect(&rc, (int)m_pPG->m_xPos, (int)m_pPG->m_yPos);
  208.     RECTLFROMRECT(m_rcl, rc);
  209.     m_pTenantCur->RectSet(&m_rcl, TRUE);
  210.  
  211.     UpdateWindow(m_hWnd);
  212.     return TRUE;
  213.     }
  214.  
  215.  
  216.  
  217.  
  218.  
  219. /*
  220.  * CPage::OnLeftDoubleClick
  221.  *
  222.  * Purpose:
  223.  *  Called when the user double-clicks with the left button on this
  224.  *  page.  We find the object under that position that is visibly on
  225.  *  top (always the first one under this location in the page list
  226.  *  since we paint in reverse order) and activate it.
  227.  *
  228.  * Parameters:
  229.  *  uKeys           UINT carrying the key state.
  230.  *  x, y            UINT coordinates of the click in device units.
  231.  *
  232.  * Return Value:
  233.  *  BOOL            Indicates if the action changed the object.
  234.  */
  235.  
  236. BOOL CPage::OnLeftDoubleClick(UINT uKeys, UINT x, UINT y)
  237.     {
  238.     /*
  239.      * The current tenant is the only one that can be activated, so
  240.      * we just have to make sure the mouse is there.  For that we
  241.      * can use the last hit-test code we saw since it's updated on
  242.      * every mouse move.
  243.      */
  244.  
  245.     if (HTNOWHERE!=m_uHTCode)
  246.         return m_pTenantCur->Activate(OLEIVERB_PRIMARY);
  247.  
  248.     return FALSE;
  249.     }
  250.  
  251.  
  252.  
  253.  
  254.  
  255.  
  256. /*
  257.  * CPage::OnMouseMove
  258.  *
  259.  * Purpose:
  260.  *  Processes WM_MOUSEMOVE on a page so we can handle tracking
  261.  *  resize of a tenant.
  262.  *
  263.  * Parameters:
  264.  *  x, y            int device coordinates to check.
  265.  *
  266.  * Return Value:
  267.  *  None
  268.  */
  269.  
  270. void CPage::OnMouseMove(UINT uKeys, int x, int y)
  271.     {
  272.     RECT        rc, rcO, rcB;
  273.     int         cxy;
  274.  
  275.     //CHAPTER13MOD
  276.     if (m_fSizePending || m_fDragPending)
  277.     //End CHAPTER13MOD
  278.         {
  279.         int     dx, dy;
  280.  
  281.         dx=(x > m_ptDown.x) ? (x-m_ptDown.x) : (m_ptDown.x-x);
  282.         dy=(y > m_ptDown.y) ? (y-m_ptDown.y) : (m_ptDown.y-y);
  283.  
  284.         /*
  285.          * Has the mouse moved outside the debounce distance?  If
  286.          * so, we can start sizing.  Note that this happens
  287.          * regardless of the timer state.
  288.          */
  289.         if (dx > m_cxyDist || dy > m_cxyDist)
  290.             {
  291.             POINT       pt;
  292.             //CHAPTER13MOD
  293.             BOOL        fSize=m_fSizePending;
  294.             BOOL        fDrag=m_fDragPending;
  295.  
  296.             m_fSizePending=FALSE;
  297.             m_fDragPending=FALSE;
  298.             //End CHAPTER13MOD
  299.  
  300.             if (m_fTimer)
  301.                 {
  302.                 KillTimer(m_hWnd, IDTIMER_DEBOUNCE);
  303.                 m_fTimer=FALSE;
  304.                 }
  305.  
  306.             //CHAPTER13MOD
  307.             if (fDrag)
  308.                 {
  309.                 //Set dirty flag if drag & drop changed things.
  310.                 m_pPG->m_fDirty |= DragDrop(m_uKeysDown, x, y);
  311.                 return;
  312.                 }
  313.  
  314.             if (fSize)
  315.                 StartSizeTracking();
  316.             //End CHAPTER13MOD
  317.  
  318.             /*
  319.              * Since we might have moved out of the sizing handle
  320.              * in order to start the operation, we need to set the
  321.              * m_uSizingFlags field based on the original down point
  322.              * for subsequent mouse moves to function properly.
  323.              * Note that OnNCHitTest expects screen coordinates.
  324.              */
  325.             SETPOINT(pt, m_ptDown.x, m_ptDown.y);
  326.             ClientToScreen(m_hWnd, &pt);
  327.             OnNCHitTest(pt.x, pt.y);
  328.             OnSetCursor(m_uHTCode);
  329.             return;
  330.             }
  331.         }
  332.  
  333.     if (!m_fTracking)
  334.         return;
  335.  
  336.     //Get rid of the old rectangle.
  337.     RECTFROMRECTL(rc, m_rcl)
  338.     DrawFocusRect(m_hDC, &rc);
  339.  
  340.     /*
  341.      * Calculate the new.  The flags in m_uSizingFlags tell us what
  342.      * to change.  We limit the object by the page margins and a
  343.      * minimum size of 3*CXYHANDLE in either dimension.
  344.      */
  345.     cxy=3*CXYHANDLE;
  346.  
  347.     RECTFROMRECTL(rcO, m_rclOrg);
  348.     RECTFROMRECTL(rcB, m_rclBounds);
  349.  
  350.     if (m_uSizingFlags & SIZINGTOP)
  351.         {
  352.         if (y >= rcO.bottom-cxy)
  353.             y=rcO.bottom-cxy;
  354.  
  355.         if (y <= rcB.top)           //Limit to top of page.
  356.             y=rcB.top;
  357.  
  358.         m_rcl.top=y;
  359.         }
  360.  
  361.     if (m_uSizingFlags & SIZINGBOTTOM)
  362.         {
  363.         if (y <= rcO.top+cxy)
  364.             y=rcO.top+cxy;
  365.  
  366.         if (y >= rcB.bottom)         //Limit to bottom of page.
  367.             y=rcB.bottom;
  368.  
  369.         m_rcl.bottom=y;
  370.         }
  371.  
  372.     if (m_uSizingFlags & SIZINGLEFT)
  373.         {
  374.         if (x >= rcO.right-cxy)
  375.             x=rcO.right-cxy;
  376.  
  377.         if (x <= rcB.left)           //Limit to left of page.
  378.             x=rcB.left;
  379.  
  380.         m_rcl.left=x;
  381.         }
  382.  
  383.     if (m_uSizingFlags & SIZINGRIGHT)
  384.         {
  385.         if (x <= rcO.left+cxy)
  386.             x=rcO.left+cxy;
  387.  
  388.         if (x >= rcB.right)          //Limit to right of page.
  389.             x=rcB.right;
  390.  
  391.         m_rcl.right=x;
  392.         }
  393.  
  394.  
  395.     //Draw the new
  396.     RECTFROMRECTL(rc, m_rcl)
  397.     DrawFocusRect(m_hDC, &rc);
  398.  
  399.     return;
  400.     }
  401.  
  402.  
  403.  
  404.  
  405. /*
  406.  * CPage::OnTimer
  407.  *
  408.  * Purpose:
  409.  *  Processes WM_TIMER messages to a page used to perform mouse
  410.  *  debouncing.
  411.  *
  412.  * Parameters:
  413.  *  uID             UINT timer ID.
  414.  *
  415.  * Return Value:
  416.  *  None
  417.  */
  418.  
  419. void CPage::OnTimer(UINT uID)
  420.     {
  421.     //CHAPTER13MOD
  422.     if (m_fSizePending || m_fDragPending)
  423.         {
  424.         BOOL        fSize=m_fSizePending;
  425.         BOOL        fDrag=m_fDragPending;
  426.  
  427.         /*
  428.          * Having this function called means the delay requirement
  429.          * is satisfied.  Start tracking for sizing or dragging.
  430.          */
  431.  
  432.         m_fSizePending=FALSE;
  433.         m_fDragPending=FALSE;
  434.  
  435.         KillTimer(m_hWnd, IDTIMER_DEBOUNCE);
  436.         m_fTimer=FALSE;
  437.  
  438.         if (fDrag)
  439.             {
  440.             POINT       pt;
  441.  
  442.             GetCursorPos(&pt);
  443.             m_pPG->m_fDirty |= DragDrop(m_uKeysDown
  444.                 , m_ptDown.x, m_ptDown.y);
  445.             return;
  446.             }
  447.  
  448.         if (fSize)
  449.             StartSizeTracking();
  450.         }
  451.     //End CHAPTER13MOD
  452.  
  453.     return;
  454.     }
  455.  
  456.  
  457.  
  458.  
  459.  
  460. /*
  461.  * CPage::StartSizeTracking
  462.  *
  463.  * Purpose:
  464.  *  Begins sizing of a tenant when mouse debounce conditions are
  465.  *  met.
  466.  *
  467.  * Parameters:
  468.  *  uID             UINT timer ID.
  469.  *
  470.  * Return Value:
  471.  *  None
  472.  */
  473.  
  474. void CPage::StartSizeTracking(void)
  475.     {
  476.     RECT        rc;
  477.  
  478.     m_pTenantCur->RectGet(&m_rcl, TRUE);
  479.     SetCapture(m_hWnd);
  480.     m_fTracking=TRUE;
  481.  
  482.     m_hDC=GetDC(m_hWnd);
  483.  
  484.     //Place the rectangle exactly where it is on the screen.
  485.     RECTFROMRECTL(rc, m_rcl)
  486.     OffsetRect(&rc, -(int)m_pPG->m_xPos, -(int)m_pPG->m_yPos);
  487.     RECTLFROMRECT(m_rcl, rc);
  488.     m_rclOrg=m_rcl;
  489.  
  490.     DrawFocusRect(m_hDC, &rc);
  491.  
  492.     m_pPG->CalcBoundingRect(&rc, TRUE);
  493.     RECTLFROMRECT(m_rclBounds, rc);
  494.     return;
  495.     }
  496.  
  497.  
  498.  
  499.  
  500.  
  501. /*
  502.  * CPage::OnNCHitTest
  503.  *
  504.  * Purpose:
  505.  *  Processes WM_NCHITTEST on a page so we can check for hits on the
  506.  *  handles of the selected object for resizing.  We only save
  507.  *  information for ourselves and do not interfere with normal
  508.  *  hit-testing.
  509.  *
  510.  * Parameters:
  511.  *  x, y            UINT device coordinates to check.
  512.  *
  513.  * Return Value:
  514.  *  None
  515.  */
  516.  
  517. void CPage::OnNCHitTest(UINT x, UINT y)
  518.     {
  519.     RECT        rc;
  520.     RECTL       rcl;
  521.     int         iMid1, iMid2;
  522.     int         xHit, yHit;
  523.     POINT       pt;
  524.     int         x0, y0;
  525.  
  526.     /*
  527.      * Ignore this message if it occurs during tracking to adjust
  528.      * for the behavior of oddball mouse drivers.
  529.      */
  530.     if (m_fSizePending || m_fTracking)
  531.         return;
  532.  
  533.     //Default: don't start sizing on a click, don't hit an object.
  534.     m_uSizingFlags=0;
  535.     m_uHTCode=HTNOWHERE;
  536.  
  537.     if (NULL==m_pTenantCur)
  538.         return;
  539.  
  540.     //Convert device points to our coordinates
  541.     m_pTenantCur->RectGet(&rcl, FALSE);
  542.     RECTFROMRECTL(rc, rcl);
  543.     RectConvertMappings(&rc, NULL, TRUE);
  544.     OffsetRect(&rc, -(int)m_pPG->m_xPos, -(int)m_pPG->m_yPos);
  545.  
  546.     SETPOINT(pt, x, y);
  547.     ScreenToClient(m_hWnd, &pt);
  548.     x0=pt.x;
  549.     y0=pt.y;
  550.  
  551.     if (x0 < rc.left || x0 > rc.right)
  552.         return;
  553.  
  554.     if (y0 < rc.top || y0 > rc.bottom)
  555.         return;
  556.  
  557.     //It's at least in the object.
  558.     m_uHTCode=HTCLIENT;
  559.  
  560.     //Check for hits in horizontal regions
  561.     xHit=NOVALUE;
  562.     iMid1=rc.left+((rc.right-rc.left-CXYHANDLE) >> 1);
  563.     iMid2=rc.left+((rc.right-rc.left+CXYHANDLE) >> 1);
  564.  
  565.     if (x0 >= rc.left && x0 <= rc.left+CXYHANDLE)
  566.         xHit=XLEFT;
  567.     else if (x0 >= iMid1 && x0 <= iMid2)
  568.         xHit=XMID;
  569.     else if (x0 >= rc.right-CXYHANDLE && x0 <= rc.right)
  570.         xHit=XRIGHT;
  571.  
  572.     //CHAPTER13MOD
  573.     //Don't exit yet if we didn't hit a handle--might hit a y edge.
  574.     //End CHAPTER13MOD
  575.  
  576.     //Check for hits in vertical regions
  577.     yHit=NOVALUE;
  578.     iMid1=rc.top+((rc.bottom-rc.top-CXYHANDLE) >> 1);
  579.     iMid2=rc.top+((rc.bottom-rc.top+CXYHANDLE) >> 1);
  580.  
  581.     if (y0 >= rc.top && y0 <= rc.top+CXYHANDLE)
  582.         yHit=YTOP;
  583.     else if (y0 >= iMid1 && y0 <= iMid2)
  584.         yHit=YMID;
  585.     else if (y0 >= rc.bottom-CXYHANDLE && y0 <= rc.bottom)
  586.         yHit=YBOT;
  587.  
  588.     //CHAPTER13MOD
  589.     /*
  590.      * If we hit any edge, but didn't hit a handle, then one of xHit
  591.      * and yHit will be NOVALUE and the other something else.  When
  592.      * we hit an edge on the 'something else' then we're on a drag
  593.      * point.
  594.      */
  595.  
  596.     if ((NOVALUE==xHit && NOVALUE==yHit)
  597.         || (XMID==xHit && YMID==yHit)
  598.         || (NOVALUE==xHit && YMID==yHit)
  599.         || (XMID==xHit && NOVALUE==yHit))
  600.         return;
  601.  
  602.     if ((NOVALUE==xHit && (YTOP==yHit || YBOT==yHit))
  603.         || ((XLEFT==xHit || XRIGHT==xHit) && NOVALUE==yHit))
  604.         {
  605.         m_uHTCode=HTCAPTION;
  606.         return;
  607.         }
  608.     //End CHAPTER13MOD
  609.  
  610.     //We hit a handle, so save our HT code
  611.     m_uSizingFlags=g_rguSizingFlags[xHit+(yHit*3)];
  612.     m_uHTCode=g_rgHTCode[xHit+(yHit*3)];
  613.     return;
  614.     }
  615.  
  616.  
  617.  
  618.  
  619.  
  620. /*
  621.  * CPage::SetCursor
  622.  *
  623.  * Purpose:
  624.  *  Processes WM_SETCURSOR using the code from OnNCHitTest.
  625.  *
  626.  * Parameters:
  627.  *  x, y            UINT device coordinates to check.
  628.  *
  629.  * Return Value:
  630.  *  LRESULT         HT* code for Windows.
  631.  */
  632.  
  633. BOOL CPage::OnSetCursor(UINT uHTCode)
  634.     {
  635.     HCURSOR     hCur;
  636.     UINT        iCur;
  637.  
  638.     /*
  639.      * We really just ignore uHTCode and use the one we saved
  640.      * in OnNCHitTest.
  641.      */
  642.  
  643.     switch (m_uHTCode)
  644.         {
  645.         case HTTOP:
  646.         case HTBOTTOM:
  647.             iCur=IDC_VARROWS;
  648.             break;
  649.  
  650.         case HTLEFT:
  651.         case HTRIGHT:
  652.             iCur=IDC_HARROWS;
  653.             break;
  654.  
  655.  
  656.         case HTTOPLEFT:
  657.         case HTBOTTOMRIGHT:
  658.             iCur=IDC_NWSEARROWS;
  659.             break;
  660.  
  661.         case HTTOPRIGHT:
  662.         case HTBOTTOMLEFT:
  663.             iCur=IDC_NESWARROWS;
  664.             break;
  665.  
  666.         //CHAPTER13MOD
  667.         case HTCAPTION:
  668.             iCur=IDC_SMALLARROWS;
  669.             break;
  670.         //End CHAPTER13MOD
  671.  
  672.         default:
  673.             return FALSE;
  674.         }
  675.  
  676.     hCur=UICursorLoad(iCur);
  677.     SetCursor(hCur);
  678.  
  679.     return TRUE;
  680.     }
  681.  
  682.  
  683.  
  684.  
  685.  
  686. /*
  687.  * CPage::TenantFromPoint
  688.  * (Protected)
  689.  *
  690.  * Purpose:
  691.  *  Finds the tenant under the given device coordinates on this
  692.  *  page.
  693.  *
  694.  * Parmeters:
  695.  *  x, y            UINT coordinates.
  696.  *  ppTenant        PCTenant * in which to return the pointer.
  697.  *
  698.  * Return Value:
  699.  *  UINT            Index of the matched tenant, NOVALUE if not
  700.  *                  found.
  701.  */
  702.  
  703. UINT CPage::TenantFromPoint(UINT x, UINT y, PCTenant *ppTenant)
  704.     {
  705.     PCTenant    pTenant;
  706.     RECTL       rcl;
  707.     UINT        i;
  708.     int         x0, y0;
  709.  
  710.     x0=x+m_pPG->m_xPos;
  711.     y0=y+m_pPG->m_yPos;
  712.  
  713.     for (i=0; i < m_cTenants; i++)
  714.         {
  715.         if (!TenantGet(i, &pTenant, FALSE))
  716.             continue;
  717.  
  718.         pTenant->RectGet(&rcl, TRUE);
  719.  
  720.         //Essentially Perform PointInRECTL
  721.         if (x0 >= rcl.left && x0 <= rcl.right)
  722.             {
  723.             if (y0 <=rcl.bottom && y0 >=rcl.top)
  724.                 {
  725.                 *ppTenant=pTenant;
  726.                 return i;
  727.                 }
  728.             }
  729.         }
  730.  
  731.     *ppTenant=NULL;
  732.     return NOVALUE;
  733.     }
  734.  
  735.  
  736.  
  737.  
  738.  
  739. //CHAPTER13MOD
  740.  
  741.  
  742. /*
  743.  * CPage::DragDrop
  744.  *
  745.  * Purpose:
  746.  *  Performs drag-drop operations from the page window
  747.  *
  748.  * Parmeters:
  749.  *  uKeys           UINT state of the keyboard
  750.  *  x, y            UINT mouse coordinates of the starting click.
  751.  *
  752.  * Return Value:
  753.  *  BOOL            TRUE if we modified the page, FALSE otherwise.
  754.  */
  755.  
  756. BOOL CPage::DragDrop(UINT uKeys, UINT x, UINT y)
  757.     {
  758.     LPDROPSOURCE    pIDropSource;
  759.     LPDATAOBJECT    pIDataObject;
  760.     HRESULT         hr;
  761.     DWORD           dwEffect;
  762.     POINTL          ptl;
  763.     SIZEL           szl;
  764.     RECTL           rcl;
  765.     RECT            rc, rcT;
  766.  
  767.     pIDropSource=new CDropSource();
  768.  
  769.     if (NULL==pIDropSource)
  770.         return FALSE;
  771.  
  772.     pIDropSource->AddRef();
  773.     m_pPG->m_fDragSource=TRUE;
  774.  
  775.  
  776.     /*
  777.      * Store a pick point with the data indicating the offset from
  778.      * the upper left of the rectangle where we grabbed it.  This is
  779.      * so the UI feedback in IDropTarget lines up with this tenant.
  780.      */
  781.  
  782.     m_pTenantCur->RectGet(&rcl, TRUE);
  783.     ptl.x=x+m_pPG->m_xPos-rcl.left;
  784.     ptl.y=y+m_pPG->m_yPos-rcl.top;
  785.     pIDataObject=TransferObjectCreate(&ptl);
  786.  
  787.     if (NULL==pIDataObject)
  788.         {
  789.         pIDropSource->Release();
  790.         return FALSE;
  791.         }
  792.  
  793.     m_pPG->m_fMoveInPage=FALSE;
  794.  
  795.     dwEffect=DROPEFFECT_COPY | DROPEFFECT_MOVE;
  796.     hr=DoDragDrop(pIDataObject, pIDropSource
  797.         , DROPEFFECT_COPY | DROPEFFECT_MOVE, &dwEffect);
  798.  
  799.     pIDataObject->Release();
  800.     pIDropSource->Release();
  801.  
  802.     m_pPG->m_fDragSource=FALSE;
  803.  
  804.     //No drop-no action.
  805.     if (DRAGDROP_S_DROP!=GetScode(hr) || DROPEFFECT_NONE==dwEffect)
  806.         return FALSE;
  807.  
  808.     /*
  809.      * If m_pPG->m_fMoveInPage is set, then we just change the
  810.      * coordinates on m_pTenantCur and we're done.
  811.      */
  812.     if (m_pPG->m_fMoveInPage)
  813.         {
  814.         m_pTenantCur->Invalidate();
  815.  
  816.         /*
  817.          * Clip to page boundaries.  We know that ptDrop has to be
  818.          * in the page somewhere or we would not have dropped
  819.          * (effect was NONE).  So first make sure that ptDrop is
  820.          * within 3*CXYHANDLE of the right or bottom, and if so,
  821.          * pull it out to 3*CXYHANDLE.  Then we can just clip the
  822.          * size to the page rectangle and we'll always be sure to
  823.          * have at least a sizeable object.
  824.          */
  825.         m_pTenantCur->SizeGet(&szl, TRUE);
  826.         SetRect(&rc, (int)m_pPG->m_ptDrop.x, (int)m_pPG->m_ptDrop.y
  827.             , 0, 0);
  828.         RectConvertMappings(&rc, NULL, TRUE);
  829.  
  830.         m_pPG->CalcBoundingRect(&rcT, FALSE);
  831.         OffsetRect(&rcT, (int)m_pPG->m_xPos, (int)m_pPG->m_yPos);
  832.  
  833.         if (rc.left >= rcT.right-3*CXYHANDLE)
  834.             rc.left=rcT.right-3*CXYHANDLE;
  835.  
  836.         if (rc.top >= rcT.bottom-3*CXYHANDLE)
  837.             rc.top=rcT.bottom-3*CXYHANDLE;
  838.  
  839.         rc.right=rc.left+(int)szl.cx;
  840.         rc.bottom=rc.top+(int)szl.cy;
  841.         IntersectRect(&rc, &rc, &rcT);
  842.  
  843.         RECTLFROMRECT(rcl, rc);
  844.  
  845.         m_pTenantCur->RectSet(&rcl, TRUE);
  846.         m_pTenantCur->Repaint();
  847.         return TRUE;
  848.         }
  849.  
  850.     /*
  851.      * Otherwise we may have to delete the old tenant if the effect
  852.      * was move.  This will not happen in the move in page case.
  853.      */
  854.  
  855.     if (DROPEFFECT_MOVE==dwEffect)
  856.         {
  857.         TenantDestroy();
  858.         return TRUE;
  859.         }
  860.  
  861.     //Copy is a clean operation
  862.     return FALSE;
  863.     }
  864. //End CHAPTER13MOD
  865.