home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / BC_502 / MDIMFC.PAK / BOUNCE.CPP next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  7.1 KB  |  274 lines

  1. // bounce.cpp : Defines the class behaviors for the Bounce child window.
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1992-1995 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.  
  14. #include "stdafx.h"
  15. #include "mdi.h"
  16. #include "bounce.h"
  17.  
  18. #define ABS(x) ((x) < 0? -(x) : (x) > 0? (x) : 0)
  19.  
  20.  
  21. /////////////////////////////////////////////////////////////////////////////
  22. // CBounceWnd
  23.  
  24. BEGIN_MESSAGE_MAP(CBounceWnd, CMDIChildWnd)
  25.     //{{AFX_MSG_MAP(CBounceWnd)
  26.     ON_WM_CREATE()
  27.     ON_WM_SIZE()
  28.     ON_WM_TIMER()
  29.     ON_COMMAND(IDM_BLACK, OnColor)
  30.     ON_COMMAND(IDM_CUSTOM, OnCustomColor)
  31.     ON_COMMAND(IDM_RED, OnColor)
  32.     ON_COMMAND(IDM_GREEN, OnColor)
  33.     ON_COMMAND(IDM_BLUE, OnColor)
  34.     ON_COMMAND(IDM_WHITE, OnColor)
  35.     ON_UPDATE_COMMAND_UI(IDM_SLOW, OnUpdateSlow)
  36.     ON_COMMAND(IDM_SLOW, OnSlow)
  37.     ON_UPDATE_COMMAND_UI(IDM_RED, OnUpdateColor)
  38.     ON_UPDATE_COMMAND_UI(IDM_WHITE, OnUpdateColor)
  39.     ON_UPDATE_COMMAND_UI(IDM_GREEN, OnUpdateColor)
  40.     ON_COMMAND(IDM_FAST, OnFast)
  41.     ON_UPDATE_COMMAND_UI(IDM_FAST, OnUpdateFast)
  42.     ON_UPDATE_COMMAND_UI(IDM_CUSTOM, OnUpdateColor)
  43.     ON_UPDATE_COMMAND_UI(IDM_BLUE, OnUpdateColor)
  44.     ON_UPDATE_COMMAND_UI(IDM_BLACK, OnUpdateColor)
  45.     //}}AFX_MSG_MAP
  46. END_MESSAGE_MAP()
  47.  
  48. CMenu NEAR CBounceWnd::menu;        // menu for all BOUNCE windows
  49.  
  50. /////////////////////////////////////////////////////////////////////////////
  51. // CBounceWnd creation
  52.  
  53. BOOL CBounceWnd::Create(LPCTSTR szTitle, LONG style /* = 0 */,
  54.     const RECT& rect /* = rectDefault */,
  55.     CMDIFrameWnd* parent /* = NULL */)
  56. {
  57.     // Setup the shared menu
  58.     if (menu.m_hMenu == NULL)
  59.         menu.LoadMenu(IDR_BOUNCE);
  60.     m_hMenuShared = menu.m_hMenu;
  61.  
  62.     // Register a custom WndClass and create a window.
  63.     // This must be done because CBounceWnd has a custom cursor, and
  64.     //  no icon.
  65.     LPCTSTR lpszBounceClass =
  66.         AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,
  67.         #ifdef _MAC
  68.             LoadCursor(NULL, IDC_ARROW),  // Mac does not support custom cursor.
  69.         #else
  70.             LoadCursor(NULL, IDC_UPARROW),
  71.         #endif
  72.             (HBRUSH)(COLOR_WINDOW+1),
  73.             NULL);
  74.  
  75.     return CMDIChildWnd::Create(lpszBounceClass, szTitle, style, rect, parent);
  76. }
  77.  
  78. CBounceWnd::CBounceWnd()
  79. {
  80.     m_nIDColor = IDM_BLACK;
  81.     m_clrBall = RGB(0,0,0);
  82.     m_bFastSpeed = FALSE;
  83. }
  84.  
  85.  
  86. // Set up the ball parameters and start a timer.
  87. int CBounceWnd::OnCreate(LPCREATESTRUCT /* p */)
  88. {
  89.     if (!SetTimer(1, 100 /*start slow*/, NULL))
  90.     {
  91.         MessageBox(_T("Not enough timers available for this window."),
  92.                 _T("MDI:Bounce"), MB_ICONEXCLAMATION | MB_OK);
  93.  
  94.         // signal creation failure...
  95.         return -1;
  96.     }
  97.  
  98.     CDC* pDC = GetDC();
  99.     m_ptPixel.x = pDC->GetDeviceCaps(ASPECTX);
  100.     m_ptPixel.y = pDC->GetDeviceCaps(ASPECTY);
  101.     ReleaseDC(pDC);
  102.  
  103.     // Note that we could call MakeNewBall here (which should be called
  104.     // whenever the ball's speed, color or size has been changed), but the
  105.     // OnSize member function is always called after the OnCreate. Since
  106.     // the OnSize member has to call MakeNewBall anyway, we don't here.
  107.  
  108.     return 0;
  109. }
  110.  
  111. // MakeNewBall:
  112. // Whenever a parameter changes which would affect the speed or appearance
  113. // of the ball, call this to regenerate the ball bitmap.
  114. //
  115. void CBounceWnd::MakeNewBall()
  116. {
  117.     m_sizeTotal.cx = (m_sizeRadius.cx + ABS(m_sizeMove.cx)) << 1;
  118.     m_sizeTotal.cy = (m_sizeRadius.cy + ABS(m_sizeMove.cy)) << 1;
  119.  
  120.     if (m_bmBall.m_hObject != NULL)
  121.         m_bmBall.DeleteObject();        // get rid of old bitmap
  122.  
  123.     CClientDC dc(this);
  124.     CDC dcMem;
  125.     dcMem.CreateCompatibleDC(&dc);
  126.  
  127.     m_bmBall.CreateCompatibleBitmap(&dc, m_sizeTotal.cx, m_sizeTotal.cy);
  128.     ASSERT(m_bmBall.m_hObject != NULL);
  129.  
  130.     CBitmap* pOldBitmap = dcMem.SelectObject(&m_bmBall);
  131.  
  132.     // draw a rectangle in the background (window) color
  133.     CRect rect(0, 0, m_sizeTotal.cx, m_sizeTotal.cy);
  134.     CBrush brBackground(::GetSysColor(COLOR_WINDOW));
  135.     dcMem.FillRect(rect, &brBackground);
  136.  
  137.     CBrush brCross(HS_DIAGCROSS, 0L);
  138.     CBrush* pOldBrush = dcMem.SelectObject(&brCross);
  139.  
  140.     dcMem.SetBkColor(m_clrBall);
  141.     dcMem.Ellipse(ABS(m_sizeMove.cx), ABS(m_sizeMove.cy),
  142.         m_sizeTotal.cx - ABS(m_sizeMove.cx),
  143.         m_sizeTotal.cy - ABS(m_sizeMove.cy));
  144.  
  145.     dcMem.SelectObject(pOldBrush);
  146.     dcMem.SelectObject(pOldBitmap);
  147.     dcMem.DeleteDC();
  148. }
  149.  
  150. // The ball's size and displacement change according to the window size.
  151. void CBounceWnd::OnSize(UINT nType, int cx, int cy)
  152. {
  153.     LONG lScale;
  154.  
  155.     m_ptCenter.x = cx >> 1;
  156.     m_ptCenter.y = cy >> 1;
  157.     m_ptCenter.x += cx >> 3; // make the ball a little off-center
  158.  
  159.     lScale = min((LONG)cx * m_ptPixel.x,
  160.         (LONG)cy * m_ptPixel.y) >> 4;
  161.     m_sizeRadius.cx = (int)(lScale / m_ptPixel.x);
  162.     m_sizeRadius.cy = (int)(lScale / m_ptPixel.y);
  163.     m_sizeMove.cx = max(1, m_sizeRadius.cy >> 2);
  164.     m_sizeMove.cy = max(1, m_sizeRadius.cy >> 2);
  165.  
  166.     MakeNewBall();
  167.  
  168.     CMDIChildWnd::OnSize(nType, cx, cy);
  169. }
  170.  
  171. /////////////////////////////////////////////////////////////////////////////
  172. // CBounceWnd commands
  173.  
  174. void CBounceWnd::OnUpdateColor(CCmdUI* pCmdUI)
  175. {
  176.     pCmdUI->SetCheck(pCmdUI->m_nID == m_nIDColor);
  177. }
  178.  
  179. void CBounceWnd::OnColor()
  180. {
  181.     m_nIDColor = LOWORD(GetCurrentMessage()->wParam);
  182.     m_clrBall = colorArray[m_nIDColor - IDM_BLACK];
  183.  
  184.     // Force the client area text to be repainted in the new color
  185.     MakeNewBall();
  186.     Invalidate();
  187. }
  188.  
  189. void CBounceWnd::OnCustomColor()
  190. {
  191.     CColorDialog dlgColor(m_clrBall);
  192.     if (dlgColor.DoModal() == IDOK)
  193.     {
  194.         m_clrBall = dlgColor.GetColor();
  195.         m_nIDColor = IDM_CUSTOM;
  196.         MakeNewBall();
  197.         Invalidate();
  198.     }
  199. }
  200.  
  201. // Change the ball's speed
  202. void CBounceWnd::ChangeSpeed()
  203. {
  204.     // re-create the timer
  205.     KillTimer(1);
  206.     if (!SetTimer(1, m_bFastSpeed ? 0 : 100, NULL))
  207.     {
  208.         MessageBox(_T("Not enough timers available for this window."),
  209.                 _T("MDI:Bounce"), MB_ICONEXCLAMATION | MB_OK);
  210.         DestroyWindow();
  211.     }
  212. }
  213.  
  214. // Animate the ball.
  215. void CBounceWnd::OnTimer(UINT /* wParam */)
  216. {
  217.     if (m_bmBall.m_hObject == NULL)
  218.         return;     // no bitmap for the ball
  219.  
  220.     CRect rcClient;
  221.     GetClientRect(rcClient);
  222.  
  223.     CClientDC dc(this);
  224.     CBitmap* pbmOld = NULL;
  225.  
  226.     CDC dcMem;
  227.     dcMem.CreateCompatibleDC(&dc);
  228.     pbmOld = dcMem.SelectObject(&m_bmBall);
  229.  
  230.     dc.BitBlt(m_ptCenter.x - m_sizeTotal.cx / 2,
  231.             m_ptCenter.y - m_sizeTotal.cy / 2,
  232.             m_sizeTotal.cx, m_sizeTotal.cy,
  233.             &dcMem, 0, 0, SRCCOPY);
  234.  
  235.     m_ptCenter += m_sizeMove;
  236.  
  237.     if ((m_ptCenter.x + m_sizeRadius.cx >= rcClient.right) ||
  238.         (m_ptCenter.x - m_sizeRadius.cx <= 0))
  239.     {
  240.         m_sizeMove.cx = -m_sizeMove.cx;
  241.     }
  242.  
  243.     if ((m_ptCenter.y + m_sizeRadius.cy >= rcClient.bottom) ||
  244.         (m_ptCenter.y - m_sizeRadius.cy <= 0))
  245.     {
  246.         m_sizeMove.cy = -m_sizeMove.cy;
  247.     }
  248.  
  249.     dcMem.SelectObject(pbmOld);
  250.     dcMem.DeleteDC();
  251. }
  252.  
  253. void CBounceWnd::OnUpdateSlow(CCmdUI* pCmdUI)
  254. {
  255.     pCmdUI->SetCheck(!m_bFastSpeed);
  256. }
  257.  
  258. void CBounceWnd::OnSlow()
  259. {
  260.     m_bFastSpeed = FALSE;
  261.     ChangeSpeed();
  262. }
  263.  
  264. void CBounceWnd::OnUpdateFast(CCmdUI* pCmdUI)
  265. {
  266.     pCmdUI->SetCheck(m_bFastSpeed);
  267. }
  268.  
  269. void CBounceWnd::OnFast()
  270. {
  271.     m_bFastSpeed = TRUE;
  272.     ChangeSpeed();
  273. }
  274.