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 / chap21 / patron / pagemous.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-20  |  23.0 KB  |  965 lines

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