home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / C++-7 / DISK8 / MFC / SAMPLES / MDI / BOUNCE.CP$ / bounce
Encoding:
Text File  |  1992-03-18  |  8.3 KB  |  352 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 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 Microsoft
  9. // QuickHelp documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12. //
  13.  
  14. #include "mdi.h"
  15.  
  16. static COLORREF clrTextArray[] = { RGB (0,   0, 0), RGB (255, 0,   0),
  17.                                    RGB (0, 255, 0), RGB (  0, 0, 255),
  18.                                    RGB (255, 255, 255) };
  19.  
  20. #define ABS(x) ((x) < 0? -(x) : (x) > 0? (x) : 0)
  21.  
  22.  
  23. /////////////////////////////////////////////////////////////////////////////
  24. // CBounceWnd
  25.  
  26. BEGIN_MESSAGE_MAP(CBounceWnd, CMDIChildWnd)
  27.     ON_WM_CREATE()
  28.     ON_WM_DESTROY()
  29.     ON_WM_SIZE()
  30.     ON_WM_TIMER()
  31.     ON_WM_MDIACTIVATE()
  32.     ON_COMMAND(IDM_BLACK, OnColor)
  33.     ON_COMMAND(IDM_RED,   OnColor)
  34.     ON_COMMAND(IDM_GREEN, OnColor)
  35.     ON_COMMAND(IDM_BLUE,  OnColor)
  36.     ON_COMMAND(IDM_WHITE, OnColor)
  37.     ON_COMMAND(IDM_CUSTOM, OnColor)
  38.     ON_COMMAND(IDM_SLOW,  OnSpeed)
  39.     ON_COMMAND(IDM_FAST,  OnSpeed)
  40. END_MESSAGE_MAP()
  41.  
  42. // Create:
  43. // Register a custom WndClass and create a window.
  44. // This must be done because CBounceWnd has a custom cursor.
  45. // 
  46. BOOL CBounceWnd::Create(LPCSTR szTitle, LONG style /* = 0 */,
  47.     const RECT& rect /* = rectDefault */,
  48.     CMDIFrameWnd* parent /* = NULL */)
  49. {
  50.     const char* pszBounceClass = 
  51.         AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,
  52.             LoadCursor(NULL, IDC_UPARROW), 
  53.             (HBRUSH)(COLOR_WINDOW+1),
  54.             NULL);
  55.  
  56.     return CMDIChildWnd::Create(pszBounceClass, szTitle, style, rect, parent);
  57. }
  58.  
  59. // Constructor:
  60. // Minimum initialization
  61. //
  62. CBounceWnd::CBounceWnd()
  63. {
  64.     m_pBitmap = NULL;
  65.     m_pMenuCurrent = NULL;
  66.     m_bWindowActive = FALSE;
  67. }
  68.  
  69. // Destructor:
  70. // Release Windows resources
  71. //
  72. CBounceWnd::~CBounceWnd()
  73. {
  74.     if (m_bWindowActive)
  75.     {
  76.         // Suppress Foundation DestroyMenu done in CMenu destructor 
  77.         // (Windows takes care of menu cleanup for the active window)
  78.         //
  79.         m_pMenuCurrent->Detach();
  80.     }
  81.  
  82.     delete m_pBitmap;
  83.  
  84.     if (m_nSpeed != 0)
  85.         KillTimer(1);
  86. }
  87.  
  88.  
  89. // OnCreate:
  90. // Set up the ball parameters and start a timer.
  91. //
  92. int CBounceWnd::OnCreate(LPCREATESTRUCT /* p */)
  93. {
  94.     m_nSpeed = IDM_SLOW;
  95.     if (!SetTimer(1, (m_nSpeed==IDM_SLOW? 100 : 0), NULL))
  96.     {
  97.         MessageBox("Not enough timers available for this window.",
  98.                 "MDI:Bounce", MB_ICONEXCLAMATION | MB_OK);
  99.  
  100.         m_nSpeed = 0;
  101.  
  102.         // signal creation failure...
  103.         return -1;
  104.     }
  105.     else
  106.     {
  107.         m_nColor = IDM_BLACK;
  108.         m_clrBall = clrTextArray[m_nColor - IDM_BLACK];
  109.  
  110.         CDC* pDC = GetDC();
  111.         m_xPixel = pDC->GetDeviceCaps(ASPECTX);
  112.         m_yPixel = pDC->GetDeviceCaps(ASPECTY);
  113.         ReleaseDC(pDC);
  114.  
  115.     // Note that we could call MakeNewBall here (which should be called
  116.     // whenever the ball's speed, color or size has been changed), but the
  117.     // OnSize member function is always called after the OnCreate. Since
  118.     // the OnSize member has to call MakeNewBall anyway, we don't here.
  119.     //
  120.  
  121.     }
  122.  
  123.     return 0;
  124. }
  125.  
  126. // OnDestroy:
  127. // Notify app main MDI frame window of destruction so it may
  128. // do some cleanup.  Note: this uses a custom message -- see
  129. // mdi.h and mdi.cpp for the custom message handler
  130. //
  131. void CBounceWnd::OnDestroy()
  132. {
  133.     m_pMDIFrameWnd->SendMessage(WM_CHILDDESTROY, (UINT)m_hWnd, 0);
  134. }
  135.  
  136. // MakeNewBall:
  137. // Whenever a parameter changes which would affect the speed or appearance
  138. // of the ball, call this to regenerate the ball bitmap.
  139. //
  140. void CBounceWnd::MakeNewBall()
  141. {
  142.     if (m_pBitmap != NULL)
  143.     {
  144.         // Reclaim Windows resources associated with the ball bitmap
  145.         // before redrawing
  146.  
  147.         m_pBitmap->DeleteObject();
  148.     }
  149.     else
  150.     {
  151.         m_pBitmap = new CBitmap;
  152.     }
  153.  
  154.     m_cxTotal = (m_cxRadius + ABS(m_cxMove)) << 1;
  155.     m_cyTotal = (m_cyRadius + ABS(m_cyMove)) << 1;
  156.  
  157.     CDC dcMem;
  158.     CDC* pDC = GetDC();
  159.     
  160.     dcMem.CreateCompatibleDC(pDC);
  161.  
  162.     m_pBitmap->CreateCompatibleBitmap(pDC, m_cxTotal, m_cyTotal);
  163.  
  164.     ASSERT(m_pBitmap->m_hObject != NULL);
  165.  
  166.     ReleaseDC(pDC);
  167.  
  168.  
  169.     CBitmap* pOldBitmap = dcMem.SelectObject(m_pBitmap);
  170.  
  171.     // draw a rectangle in the background (window) color
  172.     CRect rect(0, 0, m_cxTotal, m_cyTotal);
  173.     CBrush brBackground(::GetSysColor(COLOR_WINDOW));
  174.     dcMem.FillRect(rect, &brBackground);
  175.  
  176.     CBrush brCross(HS_DIAGCROSS, 0L);
  177.     CBrush* pOldBrush = dcMem.SelectObject(&brCross);
  178.  
  179.     dcMem.SetBkColor(m_clrBall);
  180.     dcMem.Ellipse(ABS(m_cxMove), ABS(m_cyMove),
  181.                     m_cxTotal - ABS(m_cxMove), m_cyTotal - ABS(m_cyMove));
  182.  
  183.     dcMem.SelectObject(pOldBrush);
  184.     dcMem.SelectObject(pOldBitmap);
  185.     dcMem.DeleteDC();
  186. }
  187.  
  188. // OnSize:
  189. // The ball's size and displacement change according to the window size.
  190. //
  191. void CBounceWnd::OnSize(UINT nType, int cx, int cy)
  192. {
  193.     LONG lScale;
  194.  
  195.     m_xCenter = (m_cxClient = cx) >> 1;
  196.     m_yCenter = (m_cyClient = cy) >> 1;
  197.     m_xCenter += m_cxClient >> 3; // make the ball a little off-center
  198.  
  199.     lScale = min((LONG)m_cxClient * m_xPixel,
  200.         (LONG)m_cyClient * m_yPixel) >> 4;
  201.     m_cxRadius = (short)(lScale / m_xPixel);
  202.     m_cyRadius = (short)(lScale / m_yPixel);
  203.     m_cxMove = max(1, m_cyRadius >> 2);
  204.     m_cyMove = max(1, m_cyRadius >> 2);
  205.  
  206.     MakeNewBall();
  207.  
  208.     CMDIChildWnd::OnSize(nType, cx, cy);
  209. }
  210.  
  211. // OnColor:
  212. // The ball's color needs to be changed.  Checkmark the right color on the
  213. // menu.
  214. //
  215. void CBounceWnd::OnColor()
  216. {
  217.     CMenu* pMenu = m_pMDIFrameWnd->GetMenu();
  218.     pMenu->CheckMenuItem(m_nColor, MF_UNCHECKED);
  219.  
  220.     m_nColor = GetCurrentMessage()->wParam;
  221.     pMenu->CheckMenuItem(m_nColor, MF_CHECKED);
  222.  
  223.     if (m_nColor != IDM_CUSTOM)
  224.         m_clrBall = clrTextArray[m_nColor - IDM_BLACK];
  225.     else
  226.     {
  227.         CColorDialog dlgColor(m_clrBall);
  228.         if (dlgColor.DoModal() == IDOK)
  229.             m_clrBall = dlgColor.GetColor();
  230.     }
  231.  
  232.     MakeNewBall();
  233.  
  234.     Invalidate();
  235. }
  236.  
  237. // OnSpeed:
  238. // The ball's speed needs to be changed.  Checkmark the menus, kill the
  239. // current timer and start a new one at the new speed.
  240. //
  241. void CBounceWnd::OnSpeed()
  242. {
  243.     CMenu* pMenu = m_pMDIFrameWnd->GetMenu();
  244.     pMenu->CheckMenuItem(m_nSpeed, MF_UNCHECKED);
  245.  
  246.     m_nSpeed = GetCurrentMessage()->wParam;
  247.     pMenu->CheckMenuItem(m_nSpeed, MF_CHECKED);
  248.  
  249.     KillTimer(1);
  250.     if (!SetTimer(1, (m_nSpeed==IDM_SLOW? 100 : 0), NULL))
  251.     {
  252.         MessageBox("Not enough timers available for this window.",
  253.                 "MDI:Bounce", MB_ICONEXCLAMATION | MB_OK);
  254.  
  255.         m_nSpeed = 0;
  256.  
  257.         DestroyWindow();
  258.     }
  259. }
  260.  
  261. // OnTimer:
  262. // Animate the ball.
  263. //
  264. void CBounceWnd::OnTimer(UINT /* wParam */)
  265. {
  266.     if (m_pBitmap != NULL)
  267.     {
  268.         CDC dcMem;
  269.         CDC* pdcScreen = NULL;
  270.         CBitmap* pOldMap = NULL;
  271.  
  272.         pdcScreen = GetDC();    
  273.  
  274.         dcMem.CreateCompatibleDC(pdcScreen);
  275.  
  276.         ASSERT(m_pBitmap->m_hObject != NULL);
  277.  
  278.         pOldMap = dcMem.SelectObject(m_pBitmap);
  279.     
  280.         pdcScreen->BitBlt(m_xCenter - m_cxTotal / 2,
  281.                     m_yCenter - m_cyTotal / 2, m_cxTotal, m_cyTotal,
  282.                     &dcMem, 0, 0, SRCCOPY);
  283.     
  284.         ReleaseDC(pdcScreen);
  285.     
  286.         m_xCenter += m_cxMove;
  287.         m_yCenter += m_cyMove;
  288.     
  289.         if ((m_xCenter + m_cxRadius >= m_cxClient) || 
  290.             (m_xCenter - m_cxRadius <= 0))
  291.         {
  292.             m_cxMove = -m_cxMove;
  293.         }
  294.     
  295.         if ((m_yCenter + m_cyRadius >= m_cyClient) || 
  296.             (m_yCenter - m_cyRadius <= 0))
  297.         {
  298.             m_cyMove = -m_cyMove;
  299.         }
  300.     
  301.         dcMem.SelectObject(pOldMap);
  302.         dcMem.DeleteDC();
  303.     }
  304. }
  305.  
  306. // OnMDIActivate:
  307. // The current window is being activated or deactivated.  
  308. // Change MDI frame window menu as appropriate.
  309. //
  310.  
  311. void CBounceWnd::OnMDIActivate(BOOL bActivate, CWnd* /*pActive*/, 
  312.                                CWnd* /*pDeActive*/)
  313. {
  314.  
  315.     CMDIFrameWnd* pFrame = m_pMDIFrameWnd;
  316.     CMenu* pWinPopupMenu = NULL;
  317.     CMenu* pMenu = NULL;
  318.  
  319.     m_bWindowActive = bActivate;
  320.  
  321.     if (bActivate)
  322.     {
  323.         pMenu = new CMenu;
  324.         pMenu->LoadMenu("MdiMenuBounce");
  325.         pWinPopupMenu = pMenu->GetSubMenu(BOUNCE_MENU_POS);
  326.  
  327.         CMenu* pLastMenu = pFrame->MDISetMenu(pMenu, pWinPopupMenu);
  328.         pLastMenu->DestroyMenu();
  329.  
  330.         pMenu->CheckMenuItem(m_nColor, bActivate ? MF_CHECKED : MF_UNCHECKED);
  331.         pMenu->CheckMenuItem(m_nSpeed, bActivate ? MF_CHECKED : MF_UNCHECKED);
  332.  
  333.         delete m_pMenuCurrent;
  334.         m_pMenuCurrent = pMenu;
  335.  
  336.     }
  337.     else
  338.     {
  339.         pMenu = new CMenu;
  340.         pMenu->LoadMenu("MdiMenuInit");
  341.         pWinPopupMenu = pMenu->GetSubMenu(INIT_MENU_POS);
  342.  
  343.         CMenu* pLastMenu = pFrame->MDISetMenu(pMenu, pWinPopupMenu);
  344.         pLastMenu->DestroyMenu();
  345.  
  346.         delete m_pMenuCurrent;
  347.         m_pMenuCurrent = pMenu;
  348.     }
  349.  
  350.     pFrame->DrawMenuBar();
  351. }
  352.