bncvw.cpp
上传用户:liudazhe
上传日期:2007-01-02
资源大小:51k
文件大小:12k
源码类别:

菜单

开发平台:

Visual C++

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