home *** CD-ROM | disk | FTP | other *** search
/ Mastering MFC Development / MMD.ISO / labs / c07 / lab03 / ex02 / textview.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-20  |  7.0 KB  |  291 lines

  1. // TextView.cpp : implementation of the CTextView class
  2. //
  3.  
  4. #include "stdafx.h"
  5. #include "Text.h"
  6.  
  7. #include "TextDoc.h"
  8. #include "TextView.h"
  9.  
  10. #ifdef _DEBUG
  11. #define new DEBUG_NEW
  12. #undef THIS_FILE
  13. static char THIS_FILE[] = __FILE__;
  14. #endif
  15.  
  16. /////////////////////////////////////////////////////////////////////////////
  17. // CTextView
  18.  
  19. IMPLEMENT_DYNCREATE(CTextView, CScrollView)
  20.  
  21. BEGIN_MESSAGE_MAP(CTextView, CScrollView)
  22.     //{{AFX_MSG_MAP(CTextView)
  23.     ON_COMMAND(ID_FORMAT_FONT, OnFormatFont)
  24.     //}}AFX_MSG_MAP
  25.     // Standard printing commands
  26.     ON_COMMAND(ID_FILE_PRINT, CScrollView::OnFilePrint)
  27.     ON_COMMAND(ID_FILE_PRINT_DIRECT, CScrollView::OnFilePrint)
  28.     ON_COMMAND(ID_FILE_PRINT_PREVIEW, CScrollView::OnFilePrintPreview)
  29. END_MESSAGE_MAP()
  30.  
  31. /////////////////////////////////////////////////////////////////////////////
  32. // CTextView construction/destruction
  33.  
  34. CTextView::CTextView()
  35.         :    m_ViewCharSize(0,0),
  36.             m_DocSize(0,0)
  37.  
  38. {
  39.     m_pFont = NULL;
  40. }
  41.  
  42. CTextView::~CTextView()
  43. {
  44. }
  45.  
  46. BOOL CTextView::PreCreateWindow(CREATESTRUCT& cs)
  47. {
  48.     // TODO: Modify the Window class or styles here by modifying
  49.     //  the CREATESTRUCT cs
  50.  
  51.     return CScrollView::PreCreateWindow(cs);
  52. }
  53.  
  54. /////////////////////////////////////////////////////////////////////////////
  55. // CTextView drawing
  56.  
  57. void CTextView::OnDraw(CDC* pDC)
  58. {
  59.     int nFirstLn, nLastLn;
  60.  
  61.     ComputeVisibleLines(pDC, nFirstLn, nLastLn);
  62.  
  63.        int nYPos = - nFirstLn * GetCharSize().cy; 
  64.     int nXPos = 4 * GetCharSize().cx;
  65.     OnDraw(pDC, nFirstLn, nLastLn,nXPos,nYPos);
  66. }
  67.  
  68. void CTextView::OnDraw(CDC* pDC, int nFirstLn, int nLastLn, 
  69.                         int nXPos /*= 0*/, int nYPos /*= 0*/)
  70. {
  71.     //     Select specified font
  72.     CFont* pPreviousFont = pDC->SelectObject(GetFont());
  73.  
  74.     //    Needed for height of each line
  75.     CSize CharSize = GetCharSize();
  76.  
  77.     //    Get list of strings from the document
  78.     //    and output them to the display context
  79.     CStringList *pLineList = GetDocument()->GetLineList();
  80.  
  81.     CString     strLine;
  82.     POSITION     pos;
  83.     while (nFirstLn <= nLastLn)
  84.     {
  85.         if( ( pos = pLineList->FindIndex( nFirstLn )) != NULL )
  86.         {
  87.             strLine = pLineList->GetAt(pos); 
  88.             pDC->TabbedTextOut(nXPos, nYPos, strLine, 0, NULL, 0);
  89.             nYPos -= CharSize.cy;
  90.             nFirstLn++;
  91.         }
  92.     }
  93.  
  94.     //    Cleanup and restore original GDI Objects
  95.     if(pPreviousFont)
  96.     {
  97.         pDC->SelectObject(pPreviousFont);
  98.     }
  99. }
  100.  
  101. /*
  102. void CTextView::OnInitialUpdate()
  103. {
  104.     CScrollView::OnInitialUpdate();
  105.     CSize sizeTotal;
  106.     // TODO: calculate the total size of this view
  107.     sizeTotal.cx = sizeTotal.cy = 100;
  108.     SetScrollSizes(MM_TEXT, sizeTotal);
  109. }
  110. */
  111. CFont *    CTextView::GetFont()
  112. {
  113.     if(m_pFont == NULL)
  114.     {
  115.         m_pFont = new CFont;
  116.         if(m_pFont)
  117.         {
  118.             //    Default to 9 pt Arial
  119.             m_pFont->CreatePointFont(90, "Arial");
  120.         }
  121.     }
  122.     return m_pFont;
  123. }
  124.  
  125. void CTextView::ComputeViewMetrics()
  126. {   
  127.  
  128.     // get a CDC* for the screen
  129.     CDC* pDC = CDC::FromHandle(::GetDC(NULL));
  130.     int nSaveDC = pDC->SaveDC();
  131.  
  132.  
  133.     // select mapping mode
  134.     pDC->SetMapMode(MM_LOENGLISH); 
  135.     
  136.     // select the font and get its metrics
  137.     CFont* pPreviousFont = pDC->SelectObject(GetFont());
  138.     TEXTMETRIC tm;
  139.     pDC->GetTextMetrics(&tm);
  140.     
  141.     //    Calculate view character size
  142.     m_ViewCharSize.cy = tm.tmHeight + tm.tmExternalLeading;
  143.     m_ViewCharSize.cx = tm.tmAveCharWidth; 
  144.      
  145.        // convert to device units to minimize round off error
  146.        pDC->LPtoDP(&m_ViewCharSize);                                   
  147.    
  148.     //    Calculate document size
  149.     CTextDoc* pDoc = GetDocument();
  150.     m_DocSize.cx = 0;
  151.     m_DocSize.cy = m_ViewCharSize.cy * 
  152.                     pDoc->GetLineList()->GetCount();
  153.  
  154.     // loop through the document and find the longest line    
  155.     CString    Line;
  156.     CSize size;
  157.     POSITION pos = pDoc->GetLineList()->GetHeadPosition();
  158.     while( pos != NULL )
  159.     {
  160.         Line = pDoc->GetLineList()->GetNext( pos );
  161.         size = pDC->GetTextExtent(Line, Line.GetLength()); 
  162.         m_DocSize.cx = max(size.cx, m_DocSize.cx);
  163.     }
  164.  
  165.     //    Account for our simple margin
  166.     m_DocSize.cx += 4 * m_ViewCharSize.cx;
  167.  
  168.     // clean up
  169.     if(pPreviousFont)
  170.     {
  171.         pDC->SelectObject(pPreviousFont);
  172.     }
  173.     pDC->RestoreDC(nSaveDC);
  174.     ::ReleaseDC(NULL,pDC->GetSafeHdc());
  175. }
  176.  
  177. void CTextView::ComputeVisibleLines(CDC* pDC, int& nFirst, int& nLast)
  178. {
  179.     int nLineCount = GetDocument()->GetLineList()->GetCount();
  180.  
  181.     // Get the viewport origin, convert to logical coordinates
  182.     CPoint pt = pDC->GetViewportOrg();
  183.     pDC->DPtoLP(&pt,1);
  184.     
  185.     // Get the clipping region, in logical coordinates
  186.     CRect rc;   
  187.     pDC->GetClipBox(&rc);
  188.  
  189.     // Get the logical line height
  190.     CSize CharSize = GetCharSize();
  191.     
  192.     // Compute the first visible line
  193.     // The algorithm for the first visible line is
  194.     //    ╖ Calculate the distance from the top of the viewport to the top of clipping region
  195.     //    ╖ Divide this distance by the height of a line, giving the number of lines
  196.     //    ╖ Ensure that at least one line will be show
  197.  
  198.     nFirst = min(abs((rc.top - pt.y)/CharSize.cy), 
  199.                 nLineCount-1);
  200.     
  201.     // compute the last visible line
  202.     // The algorithm for the last visible line is
  203.     //    ╖ Calculate the number of lines that will fit into the clipping region
  204.     //    ╖ Add that to the starting line
  205.     //    ╖ Add one more line to make sure that partial lines are displayed
  206.     //    ╖ Make sure that this is less than the total number of lines
  207.  
  208.     nLast = min(abs(rc.Height())/CharSize.cy + nFirst + 1, 
  209.                 nLineCount-1); 
  210. }
  211.  
  212.  
  213. /////////////////////////////////////////////////////////////////////////////
  214. // CTextView printing
  215.  
  216. BOOL CTextView::OnPreparePrinting(CPrintInfo* pInfo)
  217. {
  218.     // default preparation
  219.     return DoPreparePrinting(pInfo);
  220. }
  221.  
  222. void CTextView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
  223. {
  224.     // TODO: add extra initialization before printing
  225. }
  226.  
  227. void CTextView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
  228. {
  229.     // TODO: add cleanup after printing
  230. }
  231.  
  232. /////////////////////////////////////////////////////////////////////////////
  233. // CTextView diagnostics
  234.  
  235. #ifdef _DEBUG
  236. void CTextView::AssertValid() const
  237. {
  238.     CScrollView::AssertValid();
  239. }
  240.  
  241. void CTextView::Dump(CDumpContext& dc) const
  242. {
  243.     CScrollView::Dump(dc);
  244. }
  245.  
  246. CTextDoc* CTextView::GetDocument() // non-debug version is inline
  247. {
  248.     ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CTextDoc)));
  249.     return (CTextDoc*)m_pDocument;
  250. }
  251. #endif //_DEBUG
  252.  
  253. /////////////////////////////////////////////////////////////////////////////
  254. // CTextView message handlers
  255.  
  256. void CTextView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) 
  257. {
  258.     ComputeViewMetrics();
  259.  
  260.     SetScrollSizes(MM_LOENGLISH, GetDocSize());
  261.     Invalidate();
  262. }
  263.  
  264. void CTextView::OnFormatFont() 
  265. {
  266.     CFont * pFont = GetFont();
  267.  
  268.     LOGFONT    lf;
  269.     pFont->GetObject(sizeof(LOGFONT), &lf);
  270.     
  271.     CFontDialog    dlg(&lf, CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT);
  272.  
  273.     if(dlg.DoModal() == IDOK)
  274.     {
  275.         if(m_pFont)
  276.         {
  277.             delete m_pFont;
  278.         }
  279.  
  280.         m_pFont = new CFont;
  281.         if(m_pFont)
  282.         {
  283.             m_pFont->CreateFontIndirect(&lf);
  284.         }
  285.  
  286.         //    This will cause OnUpdate() to be called ensuring
  287.         //    that our cached metrics and scrolling get updated
  288.         GetDocument()->UpdateAllViews(NULL);
  289.     }
  290. }
  291.