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 / chap12 / patron / pagewin.cpp < prev    next >
C/C++ Source or Header  |  1995-05-03  |  16KB  |  579 lines

  1. /*
  2.  * PAGEWIN.CPP
  3.  * Patron Chapter 12
  4.  *
  5.  * Window procedure for the Pages window and support functions.
  6.  * This window manages its own scrollbars and viewport and provides
  7.  * printing capabilities as well.
  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. /*
  21.  * PagesWndProc
  22.  *
  23.  * Purpose:
  24.  *  Window procedure for the Pages window.
  25.  */
  26.  
  27. LRESULT APIENTRY PagesWndProc(HWND hWnd, UINT iMsg, WPARAM wParam
  28.     , LPARAM lParam)
  29.     {
  30.     PCPages         ppg;
  31.     PAINTSTRUCT     ps;
  32.     HDC             hDC;
  33.     int             iPos, iTmp;
  34.     int             iMin, iMax;
  35.     UINT            idScroll;
  36.     //CHAPTER12MOD
  37.     BOOL            fDirty=FALSE;
  38.     //End CHAPTER12MOD
  39.  
  40.     ppg=(PCPages)GetWindowLong(hWnd, PAGEWL_STRUCTURE);
  41.  
  42.     switch (iMsg)
  43.         {
  44.         case WM_CREATE:
  45.             ppg=(PCPages)((LPCREATESTRUCT)lParam)->lpCreateParams;
  46.             SetWindowLong(hWnd, PAGEWL_STRUCTURE, (LONG)ppg);
  47.  
  48.             ppg->m_hWnd=hWnd;
  49.             break;
  50.  
  51.  
  52.         case WM_PAINT:
  53.             hDC=BeginPaint(hWnd, &ps);
  54.  
  55.             //Draw only if we have a page to show.
  56.             if (0!=ppg->m_cPages)
  57.                 ppg->Draw(hDC, FALSE, FALSE);
  58.  
  59.             EndPaint(hWnd, &ps);
  60.             break;
  61.  
  62.  
  63.         case WM_HSCROLL:
  64.         case WM_VSCROLL:
  65.             idScroll=(WM_HSCROLL==iMsg) ? SB_HORZ : SB_VERT;
  66.  
  67.             iPos=GetScrollPos(hWnd, idScroll);
  68.             iTmp=iPos;
  69.             GetScrollRange(hWnd, idScroll, &iMin, &iMax);
  70.  
  71.             switch (LOWORD(wParam))
  72.                 {
  73.                 case SB_LINEUP:     iPos -= 20;  break;
  74.                 case SB_PAGEUP:     iPos -=100;  break;
  75.                 case SB_LINEDOWN:   iPos += 20;  break;
  76.                 case SB_PAGEDOWN:   iPos +=100;  break;
  77.  
  78.                 case SB_THUMBPOSITION:
  79.                     iPos=ScrollThumbPosition(wParam, lParam);
  80.                     break;
  81.  
  82.                 //We don't want scrolling on this message.
  83.                 case SB_THUMBTRACK:
  84.                     return 0L;
  85.                 }
  86.  
  87.             iPos=max(iMin, min(iPos, iMax));
  88.  
  89.             if (iPos!=iTmp)
  90.                 {
  91.                 //Set the new position and scroll the window
  92.                 SetScrollPos(hWnd, idScroll, iPos, TRUE);
  93.  
  94.                 if (SB_HORZ==idScroll)
  95.                     {
  96.                     ppg->m_xPos=iPos;
  97.                     ScrollWindow(hWnd, iTmp-iPos, 0, NULL, NULL);
  98.                     }
  99.                 else
  100.                     {
  101.                     ppg->m_yPos=iPos;
  102.                     ScrollWindow(hWnd, 0, iTmp-iPos, NULL, NULL);
  103.                     }
  104.                 }
  105.  
  106.             break;
  107.  
  108.         //CHAPTER12MOD
  109.         case WM_LBUTTONDOWN:
  110.             if (NULL==ppg->m_pPageCur)
  111.                 break;
  112.  
  113.             fDirty=ppg->m_pPageCur->OnLeftDown(wParam
  114.                 , LOWORD(lParam), HIWORD(lParam));
  115.             break;
  116.  
  117.         case WM_LBUTTONUP:
  118.             if (NULL==ppg->m_pPageCur)
  119.                 break;
  120.  
  121.             fDirty=ppg->m_pPageCur->OnLeftUp(wParam
  122.                 , LOWORD(lParam), HIWORD(lParam));
  123.             break;
  124.  
  125.         case WM_LBUTTONDBLCLK:
  126.             if (NULL==ppg->m_pPageCur)
  127.                 break;
  128.  
  129.             fDirty=ppg->m_pPageCur->OnLeftDoubleClick(wParam, LOWORD(lParam)
  130.                 , HIWORD(lParam));
  131.             break;
  132.  
  133.         case WM_MOUSEMOVE:
  134.             if (NULL==ppg->m_pPageCur)
  135.                 break;
  136.  
  137.             ppg->m_pPageCur->OnMouseMove(wParam, LOWORD(lParam)
  138.                 , HIWORD(lParam));
  139.             break;
  140.  
  141.         case WM_TIMER:
  142.             if (NULL==ppg->m_pPageCur)
  143.                 break;
  144.  
  145.             ppg->m_pPageCur->OnTimer(wParam);
  146.             break;
  147.  
  148.         case WM_NCHITTEST:
  149.             if (NULL!=ppg->m_pPageCur)
  150.                 {
  151.                 /*
  152.                  * This just saves information in the page for
  153.                  * OnSetCursor
  154.                  */
  155.                 ppg->m_pPageCur->OnNCHitTest(LOWORD(lParam)
  156.                     , HIWORD(lParam));
  157.                 }
  158.  
  159.             return DefWindowProc(hWnd, iMsg, wParam, lParam);
  160.  
  161.         case WM_SETCURSOR:
  162.             if (NULL!=ppg->m_pPageCur)
  163.                 {
  164.                 if (ppg->m_pPageCur->OnSetCursor(LOWORD(lParam)))
  165.                     break;
  166.                 }
  167.  
  168.             return DefWindowProc(hWnd, iMsg, wParam, lParam);
  169.  
  170.         //End CHAPTER12MOD
  171.  
  172.         default:
  173.             return DefWindowProc(hWnd, iMsg, wParam, lParam);
  174.         }
  175.  
  176.     //CHAPTER12MOD
  177.     ppg->m_fDirty |= fDirty;
  178.     //End CHAPTER12MOD
  179.     return 0L;
  180.     }
  181.  
  182.  
  183.  
  184.  
  185.  
  186. /*
  187.  * RectConvertMappings
  188.  *
  189.  * Purpose:
  190.  *  Converts the contents of a rectangle from device to logical
  191.  *  coordinates where the hDC defines the logical coordinates.
  192.  *
  193.  * Parameters:
  194.  *  pRect           LPRECT containing the rectangle to convert.
  195.  *  hDC             HDC describing the logical coordinate system.
  196.  *                  if NULL, uses a screen DC in MM_LOMETRIC.
  197.  *  fToDevice       BOOL TRUE to convert from uConv to device,
  198.  *                  FALSE to convert device to uConv.
  199.  *
  200.  * Return Value:
  201.  *  None
  202.  */
  203.  
  204. void RectConvertMappings(LPRECT pRect, HDC hDC, BOOL fToDevice)
  205.     {
  206.     POINT   rgpt[2];
  207.     BOOL    fSysDC=FALSE;
  208.  
  209.     if (NULL==pRect)
  210.         return;
  211.  
  212.     rgpt[0].x=pRect->left;
  213.     rgpt[0].y=pRect->top;
  214.     rgpt[1].x=pRect->right;
  215.     rgpt[1].y=pRect->bottom;
  216.  
  217.     if (NULL==hDC)
  218.         {
  219.         hDC=GetDC(NULL);
  220.         SetMapMode(hDC, MM_LOMETRIC);
  221.         fSysDC=TRUE;
  222.         }
  223.  
  224.     if (fToDevice)
  225.         LPtoDP(hDC, rgpt, 2);
  226.     else
  227.         DPtoLP(hDC, rgpt, 2);
  228.  
  229.     if (fSysDC)
  230.         ReleaseDC(NULL, hDC);
  231.  
  232.     pRect->left=rgpt[0].x;
  233.     pRect->top=rgpt[0].y;
  234.     pRect->right=rgpt[1].x;
  235.     pRect->bottom=rgpt[1].y;
  236.  
  237.     return;
  238.     }
  239.  
  240.  
  241.  
  242.  
  243.  
  244.  
  245. /*
  246.  * CPages::Draw
  247.  *
  248.  * Purpose:
  249.  *  Paints the current page in the pages window.
  250.  *
  251.  * Parameters:
  252.  *  hDC             HDC to draw on, could be a metafile or printer
  253.  *                  DC or any other type of DC.
  254.  *  fNoColor        BOOL indicating if we should use screen colors
  255.  *                  or printer colors (B&W).  Objects are printed
  256.  *                  as-is, however.  This is TRUE for printer DCs
  257.  *                  or print preview.
  258.  *  fPrinter        BOOL indicating if this is a printer DC in which
  259.  *                  case we eliminate some of the fancy drawing,
  260.  *                  like shadows on the page and so forth.
  261.  *
  262.  * Return Value:
  263.  *  None
  264.  */
  265.  
  266. void CPages::Draw(HDC hDC, BOOL fNoColor, BOOL fPrinter)
  267.     {
  268.     RECT            rc, rcT;
  269.     UINT            uMM;
  270.     HPEN            hPen;
  271.     HBRUSH          hBrush;
  272.     HGDIOBJ         hObj1, hObj2;
  273.     COLORREF        cr;
  274.     TCHAR           szTemp[20];
  275.     UINT            cch;
  276.     SIZE            sz;
  277.     //CHAPTER12MOD
  278.     PCPage          pPage;
  279.     RECT            rcPos;
  280.     //End CHAPTER12MOD
  281.  
  282.     //Make sure the DC is in LOMETRIC
  283.     uMM=SetMapMode(hDC, MM_LOMETRIC);
  284.  
  285.     if (!fPrinter)
  286.         {
  287.         /*
  288.          * We maintain a 6mm border around the page on the screen
  289.          * besides 12.7mm margins.  We also have to account for
  290.          * the scroll position with m_*Pos which are in pixels so
  291.          * we have to convert them.
  292.          */
  293.  
  294.         //CHAPTER12MOD
  295.         SetRect(&rcPos, m_xPos, m_yPos, 0, 0);
  296.         RectConvertMappings(&rcPos, hDC, FALSE);
  297.  
  298.         rc.left  = LOMETRIC_BORDER-rcPos.left;
  299.         rc.top   =-LOMETRIC_BORDER-rcPos.top;
  300.         //End CHAPTER12MOD
  301.         }
  302.     else
  303.         {
  304.         /*
  305.          * We define the corner of the printed paper at a negative
  306.          * offset so rc.right and rc.bottom come out right below.
  307.          */
  308.         SetRect(&rc, -(int)m_xMarginLeft, m_yMarginTop, 0, 0);
  309.         }
  310.  
  311.     rc.right=rc.left+m_cx+(m_xMarginLeft+m_xMarginRight);
  312.     rc.bottom=rc.top-m_cy-(m_yMarginTop+m_yMarginBottom);
  313.  
  314.     //Draw a rect filled with the window color to show the page.
  315.     if (!fPrinter)
  316.         {
  317.         if (fNoColor)
  318.             {
  319.             //Black frame, white box for printed colors.
  320.             hPen  =CreatePen(PS_SOLID, 0, RGB(0,0,0));
  321.             hBrush=CreateSolidBrush(RGB(255, 255, 255));
  322.             }
  323.         else
  324.             {
  325.             //Normal colors on display
  326.             hPen=CreatePen(PS_SOLID, 0
  327.                 , GetSysColor(COLOR_WINDOWFRAME));
  328.             hBrush=CreateSolidBrush(GetSysColor(COLOR_WINDOW));
  329.             }
  330.  
  331.         hObj1=SelectObject(hDC, hPen);
  332.         hObj2=SelectObject(hDC, hBrush);
  333.  
  334.         //Paper boundary
  335.         Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom+1);
  336.  
  337.         /*
  338.          * Draw a shadow on the *visual* bottom and right edges
  339.          * .5mm wide.  If the button shadow color and workspace
  340.          * colors match, then use black.  We always use black
  341.          * when printing as well.
  342.          */
  343.         if (fNoColor)
  344.             cr=RGB(0,0,0);
  345.         else
  346.             {
  347.             cr=GetSysColor(COLOR_BTNSHADOW);
  348.  
  349.             if (GetSysColor(COLOR_APPWORKSPACE)==cr)
  350.                 cr=RGB(0,0,0);
  351.             }
  352.  
  353.         cr=SetBkColor(hDC, cr);
  354.         SetRect(&rcT, rc.left+5, rc.bottom, rc.right+5,rc.bottom-5);
  355.         ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rcT, NULL, 0, NULL);
  356.  
  357.         SetRect(&rcT, rc.right, rc.top-5, rc.right+5, rc.bottom-5);
  358.         ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rcT, NULL, 0, NULL);
  359.         SetBkColor(hDC, cr);
  360.  
  361.         SelectObject(hDC, hObj1);
  362.         SelectObject(hDC, hObj2);
  363.         DeleteObject(hBrush);
  364.         DeleteObject(hPen);
  365.         }
  366.  
  367.     //Write the page number in the lower left corner
  368.     if (!fNoColor)
  369.         {
  370.         SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
  371.         SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
  372.         }
  373.  
  374.     //Write the page number in our page font.
  375.     cch=wsprintf(szTemp, TEXT("Page %d"), m_iPageCur+1);
  376.  
  377.     hObj1=SelectObject(hDC, m_hFont);
  378.     GetTextExtentPoint(hDC, szTemp, cch, &sz);
  379.  
  380.     TextOut(hDC, rc.left+m_xMarginLeft
  381.         , rc.bottom+m_yMarginBottom+sz.cy, szTemp, cch);
  382.  
  383.     SelectObject(hDC, hObj1);
  384.  
  385.     //Rectangle to show border.
  386.     MoveToEx(hDC, rc.left+m_xMarginLeft, rc.top-m_yMarginTop, NULL);
  387.     LineTo(hDC, rc.left+m_xMarginLeft,   rc.bottom+m_yMarginBottom);
  388.     LineTo(hDC, rc.right-m_xMarginRight, rc.bottom+m_yMarginBottom);
  389.     LineTo(hDC, rc.right-m_xMarginRight, rc.top-m_yMarginTop);
  390.     LineTo(hDC, rc.left+m_xMarginLeft,   rc.top-m_yMarginTop);
  391.  
  392.     //CHAPTER12MOD
  393.     /*
  394.      * Go draw the objects on this page.  If the page is not open,
  395.      * we open it anyway.  If it is already open, then opening again
  396.      * will bump it's reference count, so the Close in ineffectual.
  397.      */
  398.     if (PageGet(m_iPageCur, &pPage, TRUE))
  399.         {
  400.         if (!fPrinter)
  401.             {
  402.             pPage->Draw(hDC, rcPos.left, rcPos.top, fNoColor
  403.                 , fPrinter);
  404.             }
  405.         else
  406.             pPage->Draw(hDC, 0, 0, fNoColor, fPrinter);
  407.  
  408.         pPage->Close(FALSE);
  409.         }
  410.     //End CHAPTER12MOD
  411.  
  412.     SetMapMode(hDC, uMM);
  413.     return;
  414.     }
  415.  
  416.  
  417.  
  418.  
  419.  
  420. /*
  421.  * CPages::UpdateScrollRanges
  422.  *
  423.  * Purpose:
  424.  *  Reset scrollbar ranges (horizontal and vertical) depending on
  425.  *  the window size and the page size.  This function may remove
  426.  *  the scrollbars altogether.
  427.  *
  428.  * Parameters:
  429.  *  None, but set m_cx, m_cy and size m_hWnd before calling.
  430.  *
  431.  * Return Value:
  432.  *  None
  433.  */
  434.  
  435. void CPages::UpdateScrollRanges(void)
  436.     {
  437.     UINT        cxSB;   //Scrollbar width and height.
  438.     UINT        cySB;
  439.     UINT        cx, cy;
  440.     UINT        dx, dy;
  441.     UINT        u;
  442.     int         iMin, iMax;
  443.     RECT        rc;
  444.     BOOL        fHScroll;
  445.     BOOL        fVScroll;
  446.     BOOL        fWasThere;
  447.  
  448.     GetClientRect(m_hWnd, &rc);
  449.  
  450.     cx=rc.right-rc.left;
  451.     cy=rc.bottom-rc.top;
  452.  
  453.     //Convert dimensions of the image in LOMETRIC to pixels.
  454.     SetRect(&rc, (m_cx+m_xMarginLeft+m_xMarginRight
  455.         +LOMETRIC_BORDER*2), (m_cy+m_yMarginTop
  456.         +m_yMarginBottom+LOMETRIC_BORDER*2), 0, 0);
  457.  
  458.     RectConvertMappings(&rc, NULL, TRUE);
  459.  
  460.     dx=rc.left;
  461.     dy=-rc.top;
  462.  
  463.     //Assume that both scrollbars will be visible.
  464.     fHScroll=TRUE;
  465.     fVScroll=TRUE;
  466.  
  467.     /*
  468.      * Determine:
  469.      *  1)  Which scrollbars are needed.
  470.      *  2)  How many divisions to give scrollbars so as to
  471.      *      only scroll as little as necessary.
  472.      */
  473.  
  474.     //Scrollbar dimensions in our units.
  475.     cxSB=GetSystemMetrics(SM_CXVSCROLL);
  476.     cySB=GetSystemMetrics(SM_CYHSCROLL);
  477.  
  478.     //Remove horizontal scroll if window >= cxPage+borders
  479.     if (cx >= dx)
  480.         fHScroll=FALSE;
  481.  
  482.  
  483.     /*
  484.      * If we still need a horizontal scroll, see if we need a
  485.      * vertical taking the height of the horizontal scroll into
  486.      * account.
  487.      */
  488.  
  489.     u=fHScroll ? cySB : 0;
  490.  
  491.     if ((cy-u) >= dy)
  492.         fVScroll=FALSE;
  493.  
  494.     //Check if adding vert scrollbar necessitates a horz now.
  495.     u=fVScroll ? cxSB : 0;
  496.     fHScroll=((cx-u) < dx);
  497.  
  498.     /*
  499.      * Modify cx,cy to reflect the new client area before scaling
  500.      * scrollbars.  We only affect the client size if there is a
  501.      * *change* in scrollbar status:  if the scrollbar was there
  502.      * but is no longer, then add to the client size; if it was
  503.      * not there but now is, then subtract.
  504.      */
  505.  
  506.     //Change cx depending on vertical scrollbar change
  507.     GetScrollRange(m_hWnd, SB_VERT, &iMin, &iMax);
  508.     fWasThere=(0!=iMin || 0!=iMax);
  509.  
  510.     if (fWasThere && !fVScroll)
  511.         cx+=cxSB;
  512.  
  513.     if (!fWasThere && fVScroll)
  514.         cx-=cxSB;
  515.  
  516.     //Change cy depending on horizontal scrollbar change
  517.     GetScrollRange(m_hWnd, SB_HORZ, &iMin, &iMax);
  518.     fWasThere=(0!=iMin || 0!=iMax);
  519.  
  520.     if (fWasThere && !fHScroll)
  521.         cy+=cySB;
  522.  
  523.     if (!fWasThere && fHScroll)
  524.         cy-=cySB;
  525.  
  526.  
  527.     /*
  528.      * Show/Hide the scrollbars if necessary and set the ranges.
  529.      * The range is the number of units of the page we cannot see.
  530.      */
  531.     if (fHScroll)
  532.         {
  533.         //Convert current scroll position to new range.
  534.         u=GetScrollPos(m_hWnd, SB_HORZ);
  535.  
  536.         if (0!=u)
  537.             {
  538.             GetScrollRange(m_hWnd, SB_HORZ, &iMin, &iMax);
  539.             u=MulDiv(u, (dx-cx), (iMax-iMin));
  540.             }
  541.  
  542.         SetScrollRange(m_hWnd, SB_HORZ, 0, dx-cx, FALSE);
  543.         SetScrollPos(m_hWnd, SB_HORZ, u, TRUE);
  544.         m_xPos=u;
  545.         }
  546.     else
  547.         {
  548.         SetScrollRange(m_hWnd, SB_HORZ, 0, 0, TRUE);
  549.         m_xPos=0;
  550.         }
  551.  
  552.     if (fVScroll)
  553.         {
  554.         //Convert current scroll position to new range.
  555.         u=GetScrollPos(m_hWnd, SB_VERT);
  556.  
  557.         if (0!=u)
  558.             {
  559.             GetScrollRange(m_hWnd, SB_VERT, &iMin, &iMax);
  560.             u=MulDiv(u, (dy-cy), (iMax-iMin));
  561.             }
  562.  
  563.         SetScrollRange(m_hWnd, SB_VERT, 0, dy-cy, FALSE);
  564.         SetScrollPos(m_hWnd, SB_VERT, u, TRUE);
  565.  
  566.         m_yPos=u;
  567.         }
  568.     else
  569.         {
  570.         SetScrollRange(m_hWnd, SB_VERT, 0, 0, TRUE);
  571.         m_yPos=0;
  572.         }
  573.  
  574.     //Repaint to insure that changes to m_x/yPos are reflected
  575.     InvalidateRect(m_hWnd, NULL, TRUE);
  576.  
  577.     return;
  578.     }
  579.