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

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