Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

535 lines
11 KiB

  1. /*************************************************
  2. * blockvw.cpp *
  3. * *
  4. * Copyright (C) 1995-1999 Microsoft Inc. *
  5. * *
  6. *************************************************/
  7. // blockview.cpp : implementation file
  8. //
  9. #include "stdafx.h"
  10. #include "cblocks.h"
  11. #include "dib.h"
  12. #include "dibpal.h"
  13. #include "spriteno.h"
  14. #include "sprite.h"
  15. #include "phsprite.h"
  16. #include "myblock.h"
  17. #include "splstno.h"
  18. #include "spritlst.h"
  19. #include "osbview.h"
  20. #include "slot.h"
  21. #include "about.h"
  22. #include "blockvw.h"
  23. #include "blockdoc.h"
  24. #ifdef _DEBUG
  25. #undef THIS_FILE
  26. static char BASED_CODE THIS_FILE[] = __FILE__;
  27. #endif
  28. /////////////////////////////////////////////////////////////////////////////
  29. // CBlockView
  30. IMPLEMENT_DYNCREATE(CBlockView, COSBView)
  31. int GSpeed=SPEED_SLOW;
  32. BOOL m_bTimer2;
  33. BOOL m_bShowTip;
  34. CString GHint="";
  35. CBlockView::CBlockView()
  36. {
  37. m_bMouseCaptured = FALSE;
  38. m_pCapturedSprite = NULL;
  39. m_uiTimer = 0;
  40. m_iSpeed = 0;
  41. m_bStart = FALSE;
  42. m_bSuspend = FALSE;
  43. m_bShowTip = FALSE;
  44. m_bFocusWnd = TRUE;
  45. }
  46. CBlockView::~CBlockView()
  47. {
  48. }
  49. BEGIN_MESSAGE_MAP(CBlockView, COSBView)
  50. //{{AFX_MSG_MAP(CBlockView)
  51. ON_WM_CREATE()
  52. ON_WM_DESTROY()
  53. ON_WM_TIMER()
  54. ON_COMMAND(ID_ACTION_FAST, OnActionFast)
  55. ON_COMMAND(ID_ACTION_SLOW, OnActionSlow)
  56. ON_COMMAND(ID_ACTION_STOP, OnActionStop)
  57. ON_COMMAND(ID_FILE_START, OnFileStart)
  58. ON_COMMAND(ID_FILE_SUSPEND, OnFileSuspend)
  59. ON_UPDATE_COMMAND_UI(ID_FILE_SUSPEND, OnUpdateFileSuspend)
  60. ON_WM_CHAR()
  61. ON_UPDATE_COMMAND_UI(ID_ACTION_FAST, OnUpdateActionFast)
  62. ON_UPDATE_COMMAND_UI(ID_ACTION_SLOW, OnUpdateActionSlow)
  63. ON_COMMAND(ID_ACTION_NORMAL, OnActionNormal)
  64. ON_UPDATE_COMMAND_UI(ID_ACTION_NORMAL, OnUpdateActionNormal)
  65. ON_COMMAND(ID_ACTION_NORMALFAST, OnActionNormalfast)
  66. ON_UPDATE_COMMAND_UI(ID_ACTION_NORMALFAST, OnUpdateActionNormalfast)
  67. ON_UPDATE_COMMAND_UI(ID_ACTION_NORMALSLOW, OnUpdateActionNormalslow)
  68. ON_COMMAND(ID_ACTION_NORMALSLOW, OnActionNormalslow)
  69. ON_WM_LBUTTONDOWN()
  70. ON_WM_MENUSELECT()
  71. ON_WM_MOUSEMOVE()
  72. ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
  73. ON_WM_KILLFOCUS()
  74. ON_WM_SETFOCUS()
  75. //}}AFX_MSG_MAP
  76. END_MESSAGE_MAP()
  77. /////////////////////////////////////////////////////////////////////////////
  78. // CBlockView drawing
  79. void CBlockView::OnInitialUpdate()
  80. {
  81. COSBView::OnInitialUpdate();
  82. m_bStart = FALSE;
  83. m_bSuspend = FALSE;
  84. }
  85. void CBlockView::OnDraw(CDC* pDC)
  86. {
  87. COSBView::OnDraw(pDC);
  88. }
  89. /////////////////////////////////////////////////////////////////////////////
  90. // CBlockView message handlers
  91. // Create a new buffer and palette to match a new
  92. // background DIB
  93. BOOL CBlockView::NewBackground(CDIB* pDIB)
  94. {
  95. // Create a new buffer and palette
  96. if (!Create(pDIB)) {
  97. return FALSE;
  98. }
  99. // Map the colors of the background DIB to
  100. // the identity palette we just created for the background
  101. pDIB->MapColorsToPalette(GetPalette());
  102. // Resize the main frame window to fit the background image
  103. GetParentFrame()->RecalcLayout();
  104. if ((GetVersion() & 0x80000000) == 0)
  105. {
  106. ResizeParentToFit(FALSE); // Try shrinking first
  107. ResizeParentToFit(TRUE); // Let's be daring
  108. }
  109. else
  110. {
  111. Resize(FALSE); // Try shrinking first
  112. Resize(TRUE); // Let's be daring
  113. }
  114. // Render the entire scene to the off-screen buffer
  115. Render();
  116. // Paint the off-screen buffer to the window
  117. Draw();
  118. return TRUE;
  119. }
  120. // Render the scene to the off-screen buffer
  121. // pClipRect defaults to NULL
  122. void CBlockView::Render(CRect* pClipRect)
  123. {
  124. CBlockDoc* pDoc = GetDocument();
  125. CRect rcDraw;
  126. // get the background DIB and render it
  127. CDIB* pDIB = pDoc->GetBackground();
  128. if (pDIB) {
  129. pDIB->GetRect(&rcDraw);
  130. // If a clip rect was supplied use it
  131. if (pClipRect) {
  132. rcDraw.IntersectRect(pClipRect, &rcDraw);
  133. }
  134. // draw the image of the DIB to the os buffer
  135. ASSERT(m_pDIB);
  136. pDIB->CopyBits(m_pDIB,
  137. rcDraw.left,
  138. rcDraw.top,
  139. rcDraw.right - rcDraw.left,
  140. rcDraw.bottom - rcDraw.top,
  141. rcDraw.left,
  142. rcDraw.top);
  143. }
  144. // Render the sprite list from the bottom of the list to the top
  145. // Note that we always clip to the background DIB
  146. CSpriteList* pList = pDoc->GetSpriteList();
  147. POSITION pos = pList->GetTailPosition();
  148. CSprite *pSprite;
  149. while (pos) {
  150. pSprite = pList->GetPrev(pos);
  151. pSprite->Render(m_pDIB, &rcDraw);
  152. }
  153. }
  154. // A new sprite has been added to the document
  155. void CBlockView::NewSprite(CSprite* pSprite)
  156. {
  157. // map the colors in the sprite DIB to the
  158. // palette in the off-screen buffered view
  159. if (m_pPal) {
  160. pSprite->MapColorsToPalette(m_pPal);
  161. }
  162. // Render the scene
  163. // Render();
  164. // Draw the new scene to the screen
  165. // Draw();
  166. }
  167. int CBlockView::OnCreate(LPCREATESTRUCT lpCreateStruct)
  168. {
  169. if (COSBView::OnCreate(lpCreateStruct) == -1)
  170. return -1;
  171. return 0;
  172. }
  173. void CBlockView::OnDestroy()
  174. {
  175. if (m_uiTimer) {
  176. KillTimer(1);
  177. m_uiTimer = 0;
  178. }
  179. if (m_bTimer2)
  180. {
  181. VERIFY(KillTimer(2));
  182. m_bTimer2 = 0;
  183. }
  184. COSBView::OnDestroy();
  185. }
  186. void CBlockView::OnActionStop()
  187. {
  188. SetSpeed(0);
  189. }
  190. void CBlockView::SetSpeed(int iSpeed)
  191. {
  192. // Stop the current timer
  193. if (m_uiTimer) {
  194. KillTimer(1);
  195. m_uiTimer = 0;
  196. }
  197. // Stop idle loop mode
  198. CBlockApp* pApp = (CBlockApp*) AfxGetApp();
  199. pApp->SetIdleEvent(NULL);
  200. m_iSpeed = iSpeed;
  201. if (iSpeed == 0) return;
  202. if (iSpeed > 0) {
  203. m_uiTimer = (UINT)SetTimer(1, iSpeed, NULL);
  204. return;
  205. }
  206. // Set up idle loop mode
  207. //pApp->SetIdleEvent(this);
  208. }
  209. void CBlockView::OnFileStart()
  210. {
  211. AfxGetApp()->m_pMainWnd->SendMessage(WM_COMMAND,ID_FILE_NEW);
  212. SetSpeed(GSpeed);
  213. m_bStart = TRUE;
  214. }
  215. void CBlockView::GameOver(BOOL bHighScore)
  216. {
  217. SetSpeed(0);
  218. m_bStart = FALSE;
  219. if (bHighScore)
  220. {
  221. CString szMsg1,szMsg2;
  222. szMsg1.LoadString(IDS_SUPERMAN);
  223. szMsg2.LoadString(IDS_BLOCK);
  224. MessageBox(szMsg1,szMsg2,MB_OK);
  225. }
  226. }
  227. void CBlockView::OnUpdateFileSuspend(CCmdUI* pCmdUI)
  228. {
  229. CString szMsg;
  230. /*
  231. if (m_bSuspend)
  232. szMsg.LoadString(IDS_RESUME);
  233. else
  234. szMsg.LoadString(IDS_SUSPEND);
  235. pCmdUI->SetText((const char *) szMsg);
  236. */
  237. pCmdUI->Enable(m_bStart);
  238. pCmdUI->SetCheck(m_bSuspend);
  239. }
  240. void CBlockView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
  241. {
  242. static BYTE wCode[2];
  243. static BOOL bGetNext = FALSE;
  244. if (m_bStart)
  245. {
  246. if (bGetNext)
  247. {
  248. wCode[1] = (BYTE) nChar;
  249. bGetNext = FALSE;
  250. GetDocument()->Hit(MAKEWORD(wCode[1],wCode[0]));
  251. }
  252. else if (IsDBCSLeadByte((BYTE)nChar))
  253. {
  254. wCode[0] = (BYTE) nChar;
  255. bGetNext = TRUE;
  256. }
  257. }
  258. COSBView::OnChar(nChar, nRepCnt, nFlags);
  259. }
  260. void CBlockView::OnActionFast()
  261. {
  262. GSpeed = SPEED_FAST;
  263. if (m_bStart && !m_bSuspend)
  264. SetSpeed(GSpeed);
  265. }
  266. void CBlockView::OnActionNormalfast()
  267. {
  268. GSpeed = SPEED_NORMALFAST;
  269. if (m_bStart && !m_bSuspend)
  270. SetSpeed(GSpeed);
  271. AfxGetApp()->OnIdle(RANK_USER);
  272. }
  273. void CBlockView::OnActionNormal()
  274. {
  275. GSpeed = SPEED_NORMAL;
  276. if (m_bStart && !m_bSuspend)
  277. SetSpeed(GSpeed);
  278. AfxGetApp()->OnIdle(RANK_USER);
  279. }
  280. void CBlockView::OnActionNormalslow()
  281. {
  282. GSpeed = SPEED_NORMALSLOW;
  283. if (m_bStart && !m_bSuspend)
  284. SetSpeed(GSpeed);
  285. AfxGetApp()->OnIdle(RANK_USER);
  286. }
  287. void CBlockView::OnActionSlow()
  288. {
  289. GSpeed = SPEED_SLOW;
  290. if (m_bStart && !m_bSuspend)
  291. SetSpeed(GSpeed);
  292. AfxGetApp()->OnIdle(RANK_USER);
  293. }
  294. void CBlockView::OnUpdateActionFast(CCmdUI* pCmdUI)
  295. {
  296. pCmdUI->SetCheck(GSpeed == SPEED_FAST ? 1 : 0);
  297. }
  298. void CBlockView::OnUpdateActionNormalfast(CCmdUI* pCmdUI)
  299. {
  300. pCmdUI->SetCheck(GSpeed == SPEED_NORMALFAST ? 1 : 0);
  301. }
  302. void CBlockView::OnUpdateActionNormal(CCmdUI* pCmdUI)
  303. {
  304. pCmdUI->SetCheck(GSpeed == SPEED_NORMAL ? 1 : 0);
  305. }
  306. void CBlockView::OnUpdateActionNormalslow(CCmdUI* pCmdUI)
  307. {
  308. pCmdUI->SetCheck(GSpeed == SPEED_NORMALSLOW ? 1 : 0);
  309. }
  310. void CBlockView::OnUpdateActionSlow(CCmdUI* pCmdUI)
  311. {
  312. pCmdUI->SetCheck(GSpeed == SPEED_SLOW ? 1 : 0);
  313. }
  314. void CBlockView::OnLButtonDown(UINT nFlags, CPoint point)
  315. {
  316. COSBView::OnLButtonDown(nFlags, point);
  317. }
  318. void CBlockView::OnMenuSelect( UINT nItemID, UINT nFlag, HMENU hMenu )
  319. {
  320. if ((nFlag == 0xFFFF) && (hMenu == NULL))
  321. {
  322. if (m_bStart && !m_bSuspend)
  323. SetSpeed(GSpeed);
  324. }
  325. else
  326. {
  327. if (GSpeed != 0)
  328. SetSpeed(0);
  329. }
  330. UNREFERENCED_PARAMETER(nItemID);
  331. }
  332. CPoint m_ptLoc;
  333. int m_nCount=0;
  334. void CBlockView::OnFileSuspend()
  335. {
  336. LONG_PTR hOldCur=0;
  337. m_bSuspend = !m_bSuspend;
  338. if (m_bSuspend)
  339. {
  340. SetSpeed(0);
  341. m_nCount = 0;
  342. VERIFY(m_bTimer2 = (INT)SetTimer(2, 300, NULL));
  343. hOldCur = (LONG_PTR)GetClassLongPtr(GetSafeHwnd(),GCLP_HCURSOR);
  344. SetClassLongPtr(GetSafeHwnd(),GCLP_HCURSOR,(LONG_PTR)AfxGetApp()->LoadCursor(IDC_HAND_CBLOCK));
  345. }
  346. else
  347. {
  348. SetSpeed(GSpeed);
  349. VERIFY(KillTimer(2));
  350. m_bTimer2 = 0;
  351. SetClassLongPtr(GetSafeHwnd(),GCLP_HCURSOR,(LONG_PTR)hOldCur);
  352. }
  353. }
  354. void CBlockView::OnTimer(UINT nIDEvent)
  355. {
  356. switch (nIDEvent)
  357. {
  358. case 1:
  359. {
  360. if (! m_bFocusWnd)
  361. GetDocument()->UpdateAllViews(NULL);
  362. GetDocument()->Tick();
  363. int i = 0;
  364. POSITION pos;
  365. CBlock *pBlock;
  366. CBlockDoc* pDoc = GetDocument();
  367. CSpriteList* pspList = pDoc->GetSpriteList();
  368. if (pspList->IsEmpty()) return; // no sprites
  369. // update the position of each sprite
  370. for (pos = pspList->GetHeadPosition(); pos != NULL;)
  371. {
  372. pBlock = (CBlock *)pspList->GetNext(pos);
  373. ASSERT(pBlock->IsKindOf(RUNTIME_CLASS(CBlock)));
  374. i += pBlock->UpdatePosition(pDoc);
  375. GetDocument()->Land();
  376. }
  377. if (i) {
  378. // draw the changes
  379. RenderAndDrawDirtyList();
  380. }
  381. break;
  382. }
  383. case 2:
  384. {
  385. if (! m_bSuspend)
  386. break;
  387. m_nCount++;
  388. if (m_nCount >= 2)
  389. {
  390. if (!m_bShowTip)
  391. {
  392. WORD wCode = GetDocument()->GetFocusChar(m_ptLoc);
  393. if (wCode)
  394. {
  395. if (! GetDocument()->GetKeyStroke(wCode))
  396. {
  397. char szBuf[6];
  398. wsprintf(szBuf,"%X",wCode);
  399. GHint = CString(szBuf);
  400. }
  401. m_bShowTip = TRUE;
  402. AfxGetApp()->OnIdle(RANK_USER);
  403. }
  404. }
  405. }
  406. else
  407. {
  408. if (m_bShowTip)
  409. {
  410. GHint = "";
  411. m_bShowTip = FALSE;
  412. AfxGetApp()->OnIdle(RANK_USER);
  413. }
  414. }
  415. }
  416. }
  417. UNREFERENCED_PARAMETER(nIDEvent);
  418. }
  419. void CBlockView::OnMouseMove(UINT nFlags, CPoint point)
  420. {
  421. if (m_bSuspend)
  422. {
  423. if (m_ptLoc != point)
  424. {
  425. m_ptLoc = point;
  426. m_nCount = 0;
  427. }
  428. }
  429. COSBView::OnMouseMove(nFlags,point);
  430. UNREFERENCED_PARAMETER(nFlags);
  431. }
  432. void CBlockView::OnAppAbout()
  433. {
  434. CString szAppName;
  435. szAppName.LoadString(IDS_BLOCK);
  436. ShellAbout(GetSafeHwnd(),szAppName,TEXT(""), AfxGetApp()->LoadIcon(IDR_MAINFRAME));
  437. if (m_bStart && !m_bSuspend)
  438. SetSpeed(GSpeed);
  439. }
  440. void CBlockView::OnKillFocus(CWnd* pNewWnd)
  441. {
  442. COSBView::OnKillFocus(pNewWnd);
  443. m_bFocusWnd = FALSE;
  444. }
  445. void CBlockView::OnSetFocus(CWnd* pOldWnd)
  446. {
  447. COSBView::OnSetFocus(pOldWnd);
  448. // because there is a gap between next time tick,
  449. // so force update veiw first.
  450. GetDocument()->UpdateAllViews(NULL);
  451. m_bFocusWnd = TRUE;
  452. }
  453. void CBlockView::ForceSpeed(int nSpeed)
  454. {
  455. if (m_bSuspend || !m_bStart)
  456. return;
  457. SetSpeed(nSpeed);
  458. }