|
|
1.1 root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.