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

  1. // BounceVw.cpp : implementation file
  2. //
  3.  
  4. // This is a part of the Microsoft Foundation Classes C++ library.
  5. // Copyright (C) 1992-1998 Microsoft Corporation
  6. // All rights reserved.
  7. //
  8. // This source code is only intended as a supplement to the
  9. // Microsoft Foundation Classes Reference and related
  10. // electronic documentation provided with the library.
  11. // See these sources for detailed information regarding the
  12. // Microsoft Foundation Classes product.
  13.  
  14. #include "stdafx.h"
  15. #include "MDI.h"
  16.  
  17. #include "BncDoc.h"
  18. #include "BncVw.h"
  19.  
  20. #ifdef _DEBUG
  21. #define new DEBUG_NEW
  22. #undef THIS_FILE
  23. static char THIS_FILE[] = __FILE__;
  24. #endif
  25.  
  26. #define ABS(x) ((x) < 0? -(x) : (x) > 0? (x) : 0)
  27.  
  28. /////////////////////////////////////////////////////////////////////////////
  29. // CBounceView
  30.  
  31. IMPLEMENT_DYNCREATE(CBounceView, CView)
  32.  
  33. CBounceView::CBounceView()
  34. {
  35. }
  36.  
  37. CBounceView::~CBounceView()
  38. {
  39. }
  40.  
  41.  
  42. BEGIN_MESSAGE_MAP(CBounceView, CView)
  43.     //{{AFX_MSG_MAP(CBounceView)
  44.     ON_COMMAND(ID_CUSTOM, OnCustomColor)
  45.     ON_COMMAND(ID_SPEED_FAST, OnFast)
  46.     ON_COMMAND(ID_SPEED_SLOW, OnSlow)
  47.     ON_WM_CREATE()
  48.     ON_WM_SIZE()
  49.     ON_WM_TIMER()
  50.     ON_UPDATE_COMMAND_UI(ID_SPEED_FAST, OnUpdateFast)
  51.     ON_UPDATE_COMMAND_UI(ID_SPEED_SLOW, OnUpdateSlow)
  52.     ON_UPDATE_COMMAND_UI(ID_CUSTOM, OnUpdateCustom)
  53.     ON_UPDATE_COMMAND_UI(ID_BLACK, OnUpdateBlack)
  54.     ON_UPDATE_COMMAND_UI(ID_BLUE, OnUpdateBlue)
  55.     ON_UPDATE_COMMAND_UI(ID_GREEN, OnUpdateGreen)
  56.     ON_UPDATE_COMMAND_UI(ID_RED, OnUpdateRed)
  57.     ON_UPDATE_COMMAND_UI(ID_WHITE, OnUpdateWhite)
  58.     ON_COMMAND(ID_BLACK, OnColor)
  59.     ON_COMMAND(ID_BLUE, OnColor)
  60.     ON_COMMAND(ID_GREEN, OnColor)
  61.     ON_COMMAND(ID_RED, OnColor)
  62.     ON_COMMAND(ID_WHITE, OnColor)
  63.     //}}AFX_MSG_MAP
  64. END_MESSAGE_MAP()
  65.  
  66. /////////////////////////////////////////////////////////////////////////////
  67. // CBounceView drawing
  68.  
  69. void CBounceView::OnDraw(CDC* pDC)
  70. {
  71.     CDocument* pDoc = GetDocument();
  72.  
  73. // NOTE: Because the animation depends on timer events
  74. // and resizing of the window, the rendering code is
  75. // mostly found in the MakeNewBall function; called by handlers
  76. // for WM_TIMER and WM_SIZE commands. These handlers make the code easier
  77. // to read. However, the side-effect is that the ball will not be
  78. // rendered when the document is printed because there is no rendering
  79. // code in the OnDraw override.
  80.  
  81. }
  82.  
  83. /////////////////////////////////////////////////////////////////////////////
  84. // CBounceView diagnostics
  85.  
  86. #ifdef _DEBUG
  87. void CBounceView::AssertValid() const
  88. {
  89.     CView::AssertValid();
  90. }
  91.  
  92. void CBounceView::Dump(CDumpContext& dc) const
  93. {
  94.     CView::Dump(dc);
  95. }
  96.  
  97. CBounceDoc* CBounceView::GetDocument() // non-debug version is inline
  98. {
  99.     ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CBounceDoc)));
  100.     return (CBounceDoc*)m_pDocument;
  101. }
  102. #endif //_DEBUG
  103.  
  104. /////////////////////////////////////////////////////////////////////////////
  105. // CBounceView message handlers
  106.  
  107. void CBounceView::ChangeSpeed()
  108. {
  109.     CBounceDoc* pDoc = GetDocument();
  110.     ASSERT_VALID(pDoc);
  111.  
  112. // re-create the timer
  113.     KillTimer(1);
  114.     if (!SetTimer(1, pDoc->m_bFastSpeed ? 0 : 100, NULL))
  115.     {
  116.         AfxMessageBox(_T("Not enough timers available for this window"),
  117.             MB_ICONEXCLAMATION | MB_OK);
  118.         DestroyWindow();
  119.     }
  120. }
  121.  
  122. void CBounceView::MakeNewBall()
  123. {
  124.  
  125. // Computes the attributes of the ball bitmap using
  126. // aspect and window size
  127.  
  128.     CBounceDoc* pDoc = GetDocument();
  129.     ASSERT_VALID(pDoc);
  130.  
  131.     CSize radius, move, total;
  132.     CBitmap* pbmBall;
  133.  
  134.     pbmBall = &(pDoc->m_bmBall);
  135.     radius = pDoc->m_sizeRadius;
  136.     move = pDoc->m_sizeMove;
  137.  
  138.     total.cx = (radius.cx + ABS(move.cx)) << 1;
  139.     total.cy = (radius.cy + ABS(move.cy)) << 1;
  140.     pDoc->m_sizeTotal = total;
  141.  
  142.     if (pbmBall->m_hObject != NULL)
  143.         pbmBall->DeleteObject();        //get rid of old bitmap
  144.  
  145.     CClientDC dc(this);
  146.     CDC dcMem;
  147.     dcMem.CreateCompatibleDC(&dc);
  148.  
  149.     pbmBall->CreateCompatibleBitmap(&dc, total.cx, total.cy);
  150.     ASSERT(pbmBall->m_hObject != NULL);
  151.  
  152.     CBitmap* pOldBitmap = dcMem.SelectObject(pbmBall);
  153.  
  154.     // draw a rectangle in the background (window) color
  155.  
  156.     CRect rect(0, 0, total.cx, total.cy);
  157.     CBrush brBackground(::GetSysColor(COLOR_WINDOW));
  158.     dcMem.FillRect(rect, &brBackground);
  159.  
  160.     CBrush brCross(HS_DIAGCROSS, 0L);
  161.     CBrush* pOldBrush = dcMem.SelectObject(&brCross);
  162.  
  163.     dcMem.SetBkColor(pDoc->m_clrBall);
  164.     dcMem.Ellipse(ABS(move.cx), ABS(move.cy),
  165.         total.cx - ABS(move.cx),
  166.         total.cy - ABS(move.cy));
  167.  
  168.     dcMem.SelectObject(pOldBrush);
  169.     dcMem.SelectObject(pOldBitmap);
  170.     dcMem.DeleteDC();
  171. }
  172.  
  173. void CBounceView::OnFast()
  174. {
  175.     CBounceDoc* pDoc = GetDocument();
  176.     ASSERT_VALID(pDoc);
  177.  
  178.     pDoc->m_bFastSpeed = TRUE;
  179.     ChangeSpeed();
  180. }
  181.  
  182. void CBounceView::OnSlow()
  183. {
  184.     CBounceDoc* pDoc = GetDocument();
  185.     ASSERT_VALID(pDoc);
  186.  
  187.     pDoc->m_bFastSpeed = FALSE;
  188.     ChangeSpeed();
  189. }
  190.  
  191. int CBounceView::OnCreate(LPCREATESTRUCT lpCreateStruct)
  192. {
  193.     if (CView::OnCreate(lpCreateStruct) == -1)
  194.         return -1;
  195.  
  196.     CBounceDoc* pDoc = GetDocument();
  197.     ASSERT_VALID(pDoc);
  198.  
  199.     if (!SetTimer(1, 100 /* start slow */, NULL))
  200.     {
  201.         MessageBox(_T("Not enough timers available for this window."),
  202.                 _T("MDI:Bounce"), MB_ICONEXCLAMATION | MB_OK);
  203.  
  204.         // signal creation failure...
  205.         return -1;
  206.     }
  207.  
  208.     // Get the aspect ratio of the device the ball will be drawn
  209.     // on and then update the document data with the correct value.
  210.  
  211.     CDC* pDC = GetDC();
  212.     CPoint aspect;
  213.     aspect.x = pDC->GetDeviceCaps(ASPECTX);
  214.     aspect.y = pDC->GetDeviceCaps(ASPECTY);
  215.     ReleaseDC(pDC);
  216.     pDoc->m_ptPixel = aspect;
  217.  
  218.     // Note that we could call MakeNewBall here (which should be called
  219.     // whenever the ball's speed, color or size has been changed), but the
  220.     // OnSize member function is always called after the OnCreate. Since
  221.     // the OnSize member has to call MakeNewBall anyway, we don't here.
  222.  
  223.     return 0;
  224. }
  225.  
  226. void CBounceView::OnSize(UINT nType, int cx, int cy)
  227. {
  228.     CView::OnSize(nType, cx, cy);
  229.  
  230.     CBounceDoc* pDoc = GetDocument();
  231.     ASSERT_VALID(pDoc);
  232.  
  233.     LONG lScale;
  234.     CPoint center, ptPixel;
  235.  
  236.     center.x = cx >> 1;
  237.     center.y = cy >> 1;
  238.     center.x += cx >> 3; // make the ball a little off-center
  239.     pDoc->m_ptCenter = center;
  240.  
  241.     CSize radius, move;
  242.  
  243.     // Because the window size has changed, re-calculate
  244.     // the ball's dimensions.
  245.  
  246.     ptPixel = pDoc->m_ptPixel;
  247.  
  248.     lScale = min((LONG)cx * ptPixel.x,
  249.         (LONG)cy * ptPixel.y) >> 4;
  250.  
  251.     radius.cx = (int)(lScale / ptPixel.x);
  252.     radius.cy = (int)(lScale / ptPixel.y);
  253.     pDoc->m_sizeRadius = radius;
  254.  
  255.     //Re-calculate the ball's rate of movement.
  256.  
  257.     move.cx = max(1, radius.cy >> 2);
  258.     move.cy = max(1, radius.cy >> 2);
  259.     pDoc->m_sizeMove = move;
  260.  
  261.     // Redraw ball.
  262.  
  263.     MakeNewBall();
  264. }
  265.  
  266. void CBounceView::OnTimer(UINT nIDEvent)
  267. {
  268.     //Time to redraw the ball.
  269.  
  270.     CBounceDoc* pDoc = GetDocument();
  271.     ASSERT_VALID(pDoc);
  272.  
  273.     CBitmap* pbmBall;
  274.     pbmBall = &(pDoc->m_bmBall);
  275.  
  276.     if (pbmBall->m_hObject == NULL)
  277.         return;     // no bitmap for the ball
  278.  
  279.     // Get the current dimensions and create
  280.     // a compatible DC to work with.
  281.  
  282.     CRect rcClient;
  283.     GetClientRect(rcClient);
  284.  
  285.     CClientDC dc(this);
  286.     CBitmap* pbmOld = NULL;
  287.  
  288.     CDC dcMem;
  289.     dcMem.CreateCompatibleDC(&dc);
  290.     pbmOld = dcMem.SelectObject(pbmBall);
  291.  
  292.     CPoint center;
  293.     CSize total, move, radius;
  294.  
  295.     // Get the current dimensions and create
  296.     // a compatible DC to work with.
  297.  
  298.     center = pDoc->m_ptCenter;
  299.     radius = pDoc->m_sizeRadius;
  300.     total = pDoc->m_sizeTotal;
  301.     move = pDoc->m_sizeMove;
  302.  
  303.     // Now that the ball has been updated, draw it
  304.     // by BitBlt'ing to the view.
  305.  
  306.     dc.BitBlt(center.x - total.cx / 2, center.y - total.cy / 2,
  307.             total.cx, total.cy, &dcMem, 0, 0, SRCCOPY);
  308.  
  309.     // Move ball and check for collisions
  310.  
  311.     center += move;
  312.     pDoc->m_ptCenter = center;
  313.  
  314.     if ((center.x + radius.cx >= rcClient.right) ||
  315.         (center.x - radius.cx <= 0))
  316.     {
  317.         move.cx = -move.cx;
  318.     }
  319.  
  320.     if ((center.y + radius.cy >= rcClient.bottom) ||
  321.         (center.y - radius.cy <= 0))
  322.     {
  323.         move.cy = -move.cy;
  324.     }
  325.     pDoc->m_sizeMove = move;
  326.  
  327.     dcMem.SelectObject(pbmOld);
  328.     dcMem.DeleteDC();
  329. }
  330.  
  331. void CBounceView::OnUpdateFast(CCmdUI* pCmdUI)
  332. {
  333.     CBounceDoc* pDoc = GetDocument();
  334.     ASSERT_VALID(pDoc);
  335.  
  336.     pCmdUI->SetCheck(pDoc->m_bFastSpeed);
  337.  
  338. }
  339.  
  340. void CBounceView::OnUpdateSlow(CCmdUI* pCmdUI)
  341. {
  342.     CBounceDoc* pDoc = GetDocument();
  343.     ASSERT_VALID(pDoc);
  344.  
  345.     pCmdUI->SetCheck(!pDoc->m_bFastSpeed);
  346. }
  347.  
  348. void CBounceView::OnCustomColor()
  349. {
  350.     CBounceDoc* pDoc = GetDocument();
  351.     ASSERT_VALID(pDoc);
  352.  
  353.     CColorDialog dlgColor(pDoc->m_clrBall);
  354.     if (dlgColor.DoModal() == IDOK)
  355.     {
  356.         pDoc->SetCustomBallColor(dlgColor.GetColor());
  357.         pDoc->ClearAllColors();
  358.         pDoc->m_bCustom = TRUE;
  359.         MakeNewBall();
  360.     }
  361. }
  362.  
  363. void CBounceView::OnUpdateCustom(CCmdUI* pCmdUI)
  364. {
  365.     CBounceDoc* pDoc = GetDocument();
  366.     ASSERT_VALID(pDoc);
  367.  
  368.     pCmdUI->SetCheck(pDoc->m_bCustom);
  369. }
  370.  
  371. void CBounceView::MixColors()
  372. {
  373. // This function will take the current color selections, mix
  374. // them, and use the result as the current color of the ball.
  375.  
  376.     CBounceDoc* pDoc = GetDocument();
  377.     ASSERT_VALID(pDoc);
  378.  
  379.     COLORREF tmpClr;
  380.     int r, g, b;
  381.     BOOL bSetColor;
  382.  
  383.     bSetColor = pDoc->m_bRed || pDoc->m_bGreen || pDoc->m_bBlue
  384.         || pDoc->m_bWhite || pDoc->m_bBlack;
  385.     if(!bSetColor && pDoc->m_bCustom)
  386.         return;
  387.  
  388.     r = g = b = 0;
  389.  
  390.     if(pDoc->m_bRed)
  391.         r = 255;
  392.     if(pDoc->m_bGreen)
  393.         g = 255;
  394.     if(pDoc->m_bBlue)
  395.         b = 255;
  396.     tmpClr = RGB(r, g, b);
  397.  
  398. // NOTE: Because a simple algorithm is used to mix colors
  399. // if the current selection contains black or white, the
  400. // result will be black or white; respectively. This is due
  401. // to the additive method for mixing the colors
  402.  
  403.     if(pDoc->m_bWhite)
  404.         tmpClr = RGB(255, 255, 255);
  405.  
  406.     if((pDoc->m_bBlack))
  407.         tmpClr = RGB(0, 0, 0);
  408.  
  409.     // Once the color has been determined, update document
  410.     // data, and force repaint of all views.
  411.  
  412.     if(!bSetColor)
  413.         pDoc->m_bBlack = TRUE;
  414.      pDoc->m_clrBall = tmpClr;
  415.      pDoc->m_bCustom = FALSE;
  416.      MakeNewBall();
  417. }
  418. void CBounceView::OnUpdateBlack(CCmdUI* pCmdUI)
  419. {
  420.     CBounceDoc* pDoc = GetDocument();
  421.     ASSERT_VALID(pDoc);
  422.  
  423.     pCmdUI->SetCheck(pDoc->m_bBlack);
  424. }
  425.  
  426. void CBounceView::OnUpdateWhite(CCmdUI* pCmdUI)
  427. {
  428.     CBounceDoc* pDoc = GetDocument();
  429.     ASSERT_VALID(pDoc);
  430.  
  431.     pCmdUI->SetCheck(pDoc->m_bWhite);
  432. }
  433.  
  434. void CBounceView::OnUpdateBlue(CCmdUI* pCmdUI)
  435. {
  436.     CBounceDoc* pDoc = GetDocument();
  437.     ASSERT_VALID(pDoc);
  438.  
  439.     pCmdUI->SetCheck(pDoc->m_bBlue);
  440. }
  441.  
  442. void CBounceView::OnUpdateGreen(CCmdUI* pCmdUI)
  443. {
  444.     CBounceDoc* pDoc = GetDocument();
  445.     ASSERT_VALID(pDoc);
  446.  
  447.     pCmdUI->SetCheck(pDoc->m_bGreen);
  448. }
  449.  
  450. void CBounceView::OnUpdateRed(CCmdUI* pCmdUI)
  451. {
  452.     CBounceDoc* pDoc = GetDocument();
  453.     ASSERT_VALID(pDoc);
  454.  
  455.     pCmdUI->SetCheck(pDoc->m_bRed);
  456. }
  457.  
  458. void CBounceView::OnColor()
  459. {
  460.     CBounceDoc* pDoc = GetDocument();
  461.     ASSERT_VALID(pDoc);
  462.  
  463.     UINT m_nIDColor;
  464.  
  465.     m_nIDColor = LOWORD(GetCurrentMessage()->wParam);
  466.  
  467. // Determines the color being modified
  468. // and then updates the color state
  469.  
  470.     switch(m_nIDColor)
  471.     {
  472.      case ID_BLACK:
  473.         pDoc->ClearAllColors();
  474.         pDoc->m_bBlack = !(pDoc->m_bBlack);
  475.         break;
  476.      case ID_WHITE:
  477.         pDoc->ClearAllColors();
  478.         pDoc->m_bWhite = !(pDoc->m_bWhite);
  479.         break;
  480.      case ID_RED:
  481.         pDoc->m_bRed = !(pDoc->m_bRed);
  482.         pDoc->m_bBlack = FALSE;
  483.         pDoc->m_bWhite = FALSE;
  484.         break;
  485.      case ID_GREEN:
  486.         pDoc->m_bGreen = !(pDoc->m_bGreen);
  487.         pDoc->m_bBlack = FALSE;
  488.         pDoc->m_bWhite = FALSE;
  489.         break;
  490.      case ID_BLUE:
  491.         pDoc->m_bBlue = !(pDoc->m_bBlue);
  492.         pDoc->m_bBlack = FALSE;
  493.         pDoc->m_bWhite = FALSE;
  494.         break;
  495.      default:
  496.          AfxMessageBox(IDS_UNKCOLOR);
  497.          return;
  498.     }
  499.     MixColors();
  500. }
  501.  
  502. BOOL CBounceView::PreCreateWindow(CREATESTRUCT& cs)
  503. {
  504.     if (!CView::PreCreateWindow(cs))
  505.         return FALSE;
  506.  
  507.     cs.lpszClass = AfxRegisterWndClass(CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW,
  508.             AfxGetApp()->LoadStandardCursor(IDC_SIZENS),
  509.             (HBRUSH)(COLOR_WINDOW+1));
  510.  
  511.     if (cs.lpszClass != NULL)
  512.         return TRUE;
  513.     else
  514.         return FALSE;
  515. }
  516.  
  517. void CBounceView::OnInitialUpdate()
  518. {
  519.     CView::OnInitialUpdate();
  520.  
  521.     MixColors();
  522. }
  523.