home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / mfc / advanced / chkbook / rowview.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-27  |  10.3 KB  |  361 lines

  1. // rowview.cpp : implementation of the CRowView class
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1992-1998 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Microsoft Foundation Classes Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12.  
  13. #include "stdafx.h"
  14. #include "chkbook.h"
  15. #include <stdlib.h>
  16. #include <limits.h> // for INT_MAX
  17.  
  18. #ifdef _DEBUG
  19. #undef THIS_FILE
  20. static char BASED_CODE THIS_FILE[] = __FILE__;
  21. #endif
  22.  
  23. IMPLEMENT_DYNAMIC(CRowView, CScrollView)
  24.  
  25. /////////////////////////////////////////////////////////////////////////////
  26. // CRowView
  27.  
  28. BEGIN_MESSAGE_MAP(CRowView, CScrollView)
  29.     //{{AFX_MSG_MAP(CRowView)
  30.     ON_WM_KEYDOWN()
  31.     ON_WM_SIZE()
  32.     ON_WM_LBUTTONDOWN()
  33.     //}}AFX_MSG_MAP
  34.     // Standard printing commands
  35.     ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
  36.     ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
  37. END_MESSAGE_MAP()
  38.  
  39. /////////////////////////////////////////////////////////////////////////////
  40. // CRowView construction, initialization, and destruction
  41.  
  42. CRowView::CRowView()
  43. {
  44.     m_nPrevSelectedRow = 0;
  45. }
  46.  
  47. CRowView::~CRowView()
  48. {
  49. }
  50.  
  51. /////////////////////////////////////////////////////////////////////////////
  52. // CRowView updating and drawing
  53.  
  54. void CRowView::OnInitialUpdate()
  55. {
  56.     m_nPrevRowCount = GetRowCount();
  57.     m_nPrevSelectedRow = GetActiveRow();
  58. }
  59.  
  60. void CRowView::UpdateRow(int nInvalidRow)
  61. {
  62.     int nRowCount = GetRowCount();
  63.     // If the number of rows has changed, then adjust the scrolling range.
  64.     if (nRowCount != m_nPrevRowCount)
  65.     {
  66.         UpdateScrollSizes();
  67.         m_nPrevRowCount = nRowCount;
  68.     }
  69.  
  70.     // When the currently selected row changes:
  71.     // scroll the view so that the newly selected row is visible, and
  72.     // ask the derived class to repaint the selected and previously
  73.     // selected rows.
  74.  
  75.     CClientDC dc(this);
  76.     OnPrepareDC(&dc);
  77.  
  78.     // Determine the range of the rows that are currently fully visible
  79.     // in the window.  We want to do discrete scrolling by so that
  80.     // the next or previous row is always fully visible.
  81.     int nFirstRow, nLastRow;
  82.     CRect rectClient;
  83.     GetClientRect(&rectClient);
  84.     dc.DPtoLP(&rectClient);
  85.     RectLPtoRowRange(rectClient, nFirstRow, nLastRow, FALSE);
  86.  
  87.     // If necessary, scroll the window so the newly selected row is
  88.     // visible.
  89.     POINT pt;
  90.     pt.x = 0;
  91.     BOOL bNeedToScroll = TRUE;
  92.     if (nInvalidRow < nFirstRow)
  93.     {
  94.         // The newly selected row is above those currently visible
  95.         // in the window.  Scroll so the newly selected row is at the
  96.         // very top of the window.  The last row in the window might
  97.         // be only partially visible.
  98.         pt.y = RowToYPos(nInvalidRow);
  99.     }
  100.     else if (nInvalidRow > nLastRow)
  101.     {
  102.         // The newly selected row is below those currently visible
  103.         // in the window.  Scroll so the newly selected row is at the
  104.         // very bottom of the window.  The first row in the window might
  105.         // be only partially visible.
  106.         pt.y = max(0, RowToYPos(nInvalidRow+1) - rectClient.Height());
  107.     }
  108.     else
  109.     {
  110.         bNeedToScroll = FALSE;
  111.     }
  112.     if (bNeedToScroll)
  113.     {
  114.         ScrollToDevicePosition(pt);
  115.         // Scrolling will cause the newly selected row to be
  116.         // redrawn in the invalidated area of the window.
  117.  
  118.         OnPrepareDC(&dc);  // Need to prepare the DC again because
  119.             // ScrollToDevicePosition() will have changed the viewport
  120.             // origin.  The DC is used some more below.
  121.     }
  122.  
  123.     CRect rectInvalid = RowToWndRect(&dc, nInvalidRow);
  124.     InvalidateRect(&rectInvalid);
  125.  
  126.     // Give the derived class an opportunity to repaint the
  127.     // previously selected row, perhaps to un-highlight it.
  128.  
  129.     int nSelectedRow = GetActiveRow();
  130.     if (m_nPrevSelectedRow != nSelectedRow)
  131.     {
  132.         CRect rectOldSelection = RowToWndRect(&dc, m_nPrevSelectedRow);
  133.         InvalidateRect(&rectOldSelection);
  134.         m_nPrevSelectedRow = nSelectedRow;
  135.     }
  136.  
  137.  
  138. }
  139.  
  140. void CRowView::UpdateScrollSizes()
  141. {
  142.     // UpdateScrollSizes() is called when it is necessary to adjust the
  143.     // scrolling range or page/line sizes.  There are two occassions
  144.     // where this is necessary:  (1) when a new row is added-- see
  145.     // UpdateRow()-- and (2) when the window size changes-- see OnSize().
  146.  
  147.     CRect rectClient;
  148.     GetClientRect(&rectClient);
  149.  
  150.     CClientDC dc(this);
  151.     CalculateRowMetrics(&dc);
  152.  
  153.     // The vert scrolling range is the total display height of all
  154.     // of the rows.
  155.     CSize sizeTotal(m_nRowWidth,
  156.         m_nRowHeight * (min(GetRowCount(), LastViewableRow())));
  157.  
  158.     // The vertical per-page scrolling distance is equal to the
  159.     // how many rows can be displayed in the current window, less
  160.     // one row for paging overlap.
  161.     CSize sizePage(m_nRowWidth/5,
  162.             max(m_nRowHeight,
  163.                 ((rectClient.bottom/m_nRowHeight)-1)*m_nRowHeight));
  164.  
  165.     // The vertical per-line scrolling distance is equal to the
  166.         // height of the row.
  167.     CSize sizeLine(m_nRowWidth/20, m_nRowHeight);
  168.  
  169.     SetScrollSizes(MM_TEXT, sizeTotal, sizePage, sizeLine);
  170. }
  171.  
  172.  
  173. void CRowView::OnDraw(CDC* pDC)
  174. {
  175.     if (GetRowCount() == 0)
  176.         return;
  177.  
  178.     // The window has been invalidated and needs to be repainted;
  179.     // or a page needs to be printed (or previewed).
  180.     // First, determine the range of rows that need to be displayed or
  181.     // printed.
  182.  
  183.     int nFirstRow, nLastRow;
  184.     CRect rectClip;
  185.     pDC->GetClipBox(&rectClip); // Get the invalidated region.
  186.     RectLPtoRowRange(rectClip, nFirstRow, nLastRow, TRUE);
  187.  
  188.     // Draw each row in the invalidated region of the window,
  189.     // or on the printed (previewed) page.
  190.     int nActiveRow = GetActiveRow();
  191.     int nRow, y;
  192.     int nLastViewableRow = LastViewableRow();
  193.     for (nRow = nFirstRow,
  194.             y = m_nRowHeight * nFirstRow;
  195.             nRow <= nLastRow;
  196.             nRow++, y += m_nRowHeight)
  197.     {
  198.         if (nRow > nLastViewableRow)
  199.         {
  200.             CString strWarning;
  201.             strWarning.LoadString(IDS_TOO_MANY_ROWS);
  202.             pDC->TextOut(0, y, strWarning);
  203.             break;
  204.         }
  205.         OnDrawRow(pDC, nRow, y, nRow == nActiveRow);
  206.     }
  207. }
  208.  
  209.  
  210. /////////////////////////////////////////////////////////////////////////////
  211. // Implementation
  212.  
  213. int CRowView::RowToYPos(int nRow)
  214. {
  215.     return (nRow * m_nRowHeight);
  216. }
  217.  
  218. CRect CRowView::RowToWndRect(CDC* pDC, int nRow)
  219. {
  220.     int nHorzRes = pDC->GetDeviceCaps(HORZRES);;
  221.     CRect rect(0, nRow * m_nRowHeight,
  222.         nHorzRes, (nRow + 1) * m_nRowHeight);
  223.     pDC->LPtoDP(&rect);
  224.     return rect;
  225. }
  226.  
  227.  
  228. int CRowView::LastViewableRow()
  229. {
  230.     return (INT_MAX / m_nRowHeight - 1);
  231. }
  232.  
  233. void CRowView::RectLPtoRowRange(const CRect& rect,
  234.             int& nFirstRow, int& nLastRow,
  235.             BOOL bIncludePartiallyShownRows)
  236. {
  237.     int nRounding = bIncludePartiallyShownRows? 0 : (m_nRowHeight - 1);
  238.     nFirstRow = (rect.top + nRounding) / m_nRowHeight;
  239.     nLastRow = min( (rect.bottom - nRounding) / m_nRowHeight,
  240.         GetRowCount() - 1);
  241. }
  242.  
  243. void CRowView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
  244. {
  245.     // The size of text that is displayed, printed or previewed changes
  246.     // depending on the DC.  We explicitly call OnPrepareDC() to prepare
  247.     // CClientDC objects used for calculating text positions and to
  248.     // prepare the text metric member variables of the CRowView object.
  249.     // The framework also calls OnPrepareDC() before passing the DC to
  250.     // OnDraw().
  251.  
  252.     CScrollView::OnPrepareDC(pDC, pInfo);
  253.     CalculateRowMetrics(pDC);
  254. }
  255.  
  256. /////////////////////////////////////////////////////////////////////////////
  257. // Overrides of CView for implementing printing.
  258.  
  259. BOOL CRowView::OnPreparePrinting(CPrintInfo* pInfo)
  260. {
  261.     return DoPreparePrinting(pInfo);
  262. }
  263.  
  264. void CRowView::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo)
  265. {
  266.     // OnBeginPrinting() is called after the user has committed to
  267.     // printing by OK'ing the Print dialog, and after the framework
  268.     // has created a CDC object for the printer or the preview view.
  269.  
  270.     // This is the right opportunity to set up the page range.
  271.     // Given the CDC object, we can determine how many rows will
  272.     // fit on a page, so we can in turn determine how many printed
  273.     // pages represent the entire document.
  274.  
  275.     int nPageHeight = pDC->GetDeviceCaps(VERTRES);
  276.     CalculateRowMetrics(pDC);
  277.     m_nRowsPerPrintedPage = nPageHeight / m_nRowHeight;
  278.     int nPrintableRowCount = LastViewableRow() + 1;
  279.     if (GetRowCount() < nPrintableRowCount)
  280.         nPrintableRowCount = GetRowCount();
  281.     pInfo->SetMaxPage((nPrintableRowCount + m_nRowsPerPrintedPage - 1)
  282.         / m_nRowsPerPrintedPage);
  283.     pInfo->m_nCurPage = 1;  // start previewing at page# 1
  284. }
  285.  
  286. void CRowView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
  287. {
  288.     // Print the rows for the current page.
  289.  
  290.     int yTopOfPage = (pInfo->m_nCurPage -1) * m_nRowsPerPrintedPage
  291.         * m_nRowHeight;
  292.  
  293.     // Orient the viewport so that the first row to be printed
  294.     // has a viewport coordinate of (0,0).
  295.     pDC->SetViewportOrg(0, -yTopOfPage);
  296.  
  297.     // Draw as many rows as will fit on the printed page.
  298.     // Clip the printed page so that there is no partially shown
  299.     // row at the bottom of the page (the same row which will be fully
  300.     // shown at the top of the next page).
  301.  
  302.     int nPageWidth = pDC->GetDeviceCaps(HORZRES);
  303.     CRect rectClip = CRect(0, yTopOfPage, nPageWidth,
  304.          yTopOfPage + m_nRowsPerPrintedPage * m_nRowHeight);
  305.     pDC->IntersectClipRect(&rectClip);
  306.     OnDraw(pDC);
  307. }
  308.  
  309. /////////////////////////////////////////////////////////////////////////////
  310. // CRowView commands
  311.  
  312.  
  313. void CRowView::OnSize(UINT nType, int cx, int cy)
  314. {
  315.     UpdateScrollSizes();
  316.     CScrollView::OnSize(nType, cx, cy);
  317. }
  318.  
  319. void CRowView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  320. {
  321.     switch (nChar)
  322.     {
  323.         case VK_HOME:
  324.             ChangeSelectionToRow(0);
  325.             break;
  326.         case VK_END:
  327.             ChangeSelectionToRow(GetRowCount() - 1);
  328.             break;
  329.         case VK_UP:
  330.             ChangeSelectionNextRow(FALSE);
  331.             break;
  332.         case VK_DOWN:
  333.             ChangeSelectionNextRow(TRUE);
  334.             break;
  335.         case VK_PRIOR:
  336.             OnVScroll(SB_PAGEUP,
  337.                 0,  // nPos not used for PAGEUP
  338.                 GetScrollBarCtrl(SB_VERT));
  339.             break;
  340.         case VK_NEXT:
  341.             OnVScroll(SB_PAGEDOWN,
  342.                 0,  // nPos not used for PAGEDOWN
  343.                 GetScrollBarCtrl(SB_VERT));
  344.             break;
  345.         default:
  346.             CScrollView::OnKeyDown(nChar, nRepCnt, nFlags);
  347.     }
  348. }
  349.  
  350. void CRowView::OnLButtonDown(UINT, CPoint point)
  351. {
  352.     CClientDC dc(this);
  353.     OnPrepareDC(&dc);
  354.     dc.DPtoLP(&point);
  355.     CRect rect(point, CSize(1,1));
  356.     int nFirstRow, nLastRow;
  357.     RectLPtoRowRange(rect, nFirstRow, nLastRow, TRUE);
  358.     if (nFirstRow <= (GetRowCount() - 1))
  359.         ChangeSelectionToRow(nFirstRow);
  360. }
  361.