Windows NT 4.0 source code leak
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.

916 lines
21 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. button.c
  5. Abstract:
  6. This module contains the Procedure which subclasses all of the
  7. different controls which need to be tab'd to in the main screen.
  8. Author:
  9. John L. Miller (15-Feb-1993)
  10. --*/
  11. #include <windows.h>
  12. #include "cdplayer.h"
  13. #include <stdlib.h>
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include "trkinfo.h"
  17. LRESULT CALLBACK
  18. ButtonWndProc(
  19. IN HWND hwnd,
  20. IN UINT msg,
  21. IN WPARAM wParam,
  22. IN LPARAM lParam
  23. )
  24. /*++
  25. Routine Description:
  26. Implements class to sub-class button windows. If the
  27. Arguments:
  28. standard window proc vars
  29. Return Value:
  30. 0 for success, else error code.
  31. --*/
  32. #define CLICK_WAS_SPACE 1234
  33. {
  34. int i;
  35. UINT CurSel,MaxSel;
  36. UINT save;
  37. HWND hwndParent,hwndCap;
  38. WNDPROC lpfnDefWndProc;
  39. MSG PkMsg;
  40. BOOL bRet;
  41. //
  42. // Determine which control is sending the message.
  43. //
  44. for (i=0; i < gNumControls; i++) {
  45. if ((cChild[i].phwnd != NULL)&&(hwnd == *cChild[i].phwnd)) {
  46. lpfnDefWndProc = cChild[i].lpfnDefProc;
  47. hwndParent = GetParent(*cChild[i].phwnd);
  48. //
  49. // Actually, we need the parent's parent!
  50. //
  51. hwndParent = GetParent(hwndParent);
  52. break;
  53. }
  54. }
  55. //
  56. // Filter out the TAB, ESCAPE, and ENTER keystrokes.
  57. // We want to send messages back to the parent window when we
  58. // get these so that it can switch focus else select the appropriate
  59. // item from the control (if it's a combobox)
  60. //
  61. switch (msg) {
  62. case WM_KEYDOWN:
  63. switch (wParam) {
  64. case VK_UP:
  65. //
  66. // If the control is a combo box whose list is
  67. // down, then we need to index within it.
  68. //
  69. if ( (cChild[i].class == gszComboBox)&&
  70. SendMessage(hwnd,CB_GETDROPPEDSTATE,0,0)) {
  71. CurSel = SendMessage(hwnd,CB_GETCURSEL,0,0) - 1;
  72. if (CurSel < 0) {
  73. CurSel = 0;
  74. }
  75. SendMessage(hwnd,CB_SETCURSEL,(WPARAM) CurSel,0);
  76. } else {
  77. //
  78. // Otherwise, treat it as a tab/backtab.
  79. //
  80. SendMessage(hwndParent, WM_BACKTAB, 0, 0);
  81. }
  82. return 0;
  83. case VK_LEFT:
  84. SendMessage(hwndParent, WM_BACKTAB, 0, 0);
  85. return 0;
  86. case VK_DOWN:
  87. //
  88. // If the control is a combo box whose list is
  89. // down, then we need to index within it.
  90. //
  91. if ( (cChild[i].class == gszComboBox)&&
  92. SendMessage(hwnd,CB_GETDROPPEDSTATE,0,0)) {
  93. CurSel = SendMessage(hwnd,CB_GETCURSEL,0,0) + 1;
  94. MaxSel = SendMessage(hwnd,CB_GETCOUNT,0,0);
  95. if (CurSel >= MaxSel) {
  96. CurSel = MaxSel-1;
  97. }
  98. SendMessage(hwnd,CB_SETCURSEL,(WPARAM) CurSel,0);
  99. } else {
  100. //
  101. // Otherwise, treat it as a tab/backtab.
  102. //
  103. SendMessage(hwndParent, WM_TAB, 0, 0);
  104. }
  105. return 0;
  106. case VK_RIGHT:
  107. SendMessage(hwndParent, WM_TAB, 0, 0);
  108. return 0;
  109. case VK_TAB:
  110. //
  111. // Differentiate between TAB and SHIFT-TAB
  112. //
  113. if (GetKeyState(VK_SHIFT) < 0) {
  114. SendMessage(hwndParent, WM_BACKTAB, 0, 0);
  115. } else {
  116. SendMessage(hwndParent, WM_TAB, 0, 0);
  117. }
  118. return 0;
  119. case VK_ESCAPE:
  120. SendMessage(hwndParent, WM_ESC, 0, 0);
  121. return 0;
  122. case VK_RETURN:
  123. SendMessage(hwndParent, WM_ENTER, 0, 0);
  124. return 0;
  125. case VK_SPACE:
  126. if ((hwnd == ghwndScanF)||(hwnd == ghwndScanB)) {
  127. SendMessage(hwnd,WM_LBUTTONDOWN,CLICK_WAS_SPACE,0);
  128. return(0);
  129. }
  130. }
  131. break;
  132. case WM_KEYUP:
  133. case WM_CHAR:
  134. switch (wParam) {
  135. case VK_TAB:
  136. case VK_ESCAPE:
  137. case VK_RETURN:
  138. case VK_UP:
  139. case VK_LEFT:
  140. case VK_DOWN:
  141. case VK_RIGHT:
  142. return 0;
  143. case VK_SPACE:
  144. if ((hwnd == ghwndScanF)||(hwnd == ghwndScanB)) {
  145. return(0);
  146. }
  147. }
  148. break;
  149. case WM_LBUTTONDOWN:
  150. case WM_LBUTTONDBLCLK:
  151. if (gState&CD_LOADED) {
  152. if (hwnd==ghwndScanF) {
  153. //
  154. // Fast forward button has been pressed (and is
  155. // "legal").
  156. //
  157. //
  158. SetFocus(hwnd);
  159. gScanF = TRUE;
  160. SetOdCntl(hwnd,'D',TRUE);
  161. save = (gState & PLAYING);
  162. gState &= (~PLAYING);
  163. gState |= FF;
  164. //
  165. // Halt the play thread from updating the display
  166. //
  167. if (save==PLAYING) {
  168. ResetEvent( hPlayEv );
  169. PostDisplayMessage( MESS_PAUSE_AND_START_SCAN );
  170. } else {
  171. PostDisplayMessage( MESS_START_SCAN );
  172. }
  173. //
  174. // while the button is down (no other BUTTON messages
  175. // pending), keep trying to skip ahead another second
  176. // on this track
  177. //
  178. hwndCap=GetCapture();
  179. SetCapture(hwnd);
  180. i = 0;
  181. do {
  182. TimeAdjustIncSecond( gCurrCdrom );
  183. if (i>15) {
  184. TimeAdjustIncSecond( gCurrCdrom );
  185. TimeAdjustIncSecond( gCurrCdrom );
  186. }
  187. Sleep( 100 );
  188. i++;
  189. if (wParam == CLICK_WAS_SPACE) {
  190. bRet = PeekMessage(&PkMsg, NULL, WM_KEYUP, WM_KEYUP, PM_NOREMOVE);
  191. if (bRet) {
  192. bRet = (PkMsg.wParam == VK_SPACE);
  193. }
  194. } else {
  195. bRet = PeekMessage( &PkMsg, NULL, WM_LBUTTONUP, WM_LBUTTONUP, PM_NOREMOVE );
  196. }
  197. } while( !bRet );
  198. SetCapture(hwndCap);
  199. //
  200. // Restore play state so that MESS_END_SCAN will
  201. // know whether to just seek or seek and play.
  202. //
  203. if (save==PLAYING) {
  204. gState |= PLAYING;
  205. }
  206. if (gState & PAUSED) {
  207. gState |= PAUSED_AND_MOVED;
  208. }
  209. // PostDisplayMessage( MESS_END_SCAN );
  210. if (!(gDevices[ gCurrCdrom ]->State & PAUSED_AND_MOVED))
  211. SeekToCurrSecond( gCurrCdrom );
  212. //
  213. // Let go of the mutex. The play thread will be
  214. // restarted on the button-up event call to StateToState
  215. //
  216. if (save==PLAYING) {
  217. SetEvent( hPlayEv );
  218. }
  219. gState &= (~FF);
  220. gScanF = FALSE;
  221. SetOdCntl(hwnd,'U',TRUE);
  222. return(0L);
  223. } // end fast forward
  224. if (hwnd==ghwndScanB) {
  225. //
  226. // Rewind button was pressed and is "legal".
  227. //
  228. gScanB = TRUE;
  229. SetFocus(hwnd);
  230. SetOdCntl(hwnd,'D',TRUE);
  231. save = (gState & PLAYING);
  232. gState &= (~PLAYING);
  233. gState |= RW;
  234. //
  235. // Halt the play thread from updating the display
  236. //
  237. if (save==PLAYING) {
  238. ResetEvent( hPlayEv );
  239. PostDisplayMessage( MESS_PAUSE_AND_START_SCAN );
  240. } else {
  241. PostDisplayMessage( MESS_START_SCAN );
  242. }
  243. //
  244. // while the button is down (no other BUTTON messages
  245. // pending), keep trying to skip ahead another second
  246. // on this track
  247. //
  248. hwndCap=GetCapture();
  249. SetCapture(hwnd);
  250. i = 0;
  251. do {
  252. TimeAdjustDecSecond( gCurrCdrom );
  253. if (i>15) {
  254. TimeAdjustDecSecond( gCurrCdrom );
  255. TimeAdjustDecSecond( gCurrCdrom );
  256. }
  257. Sleep( 100 );
  258. i++;
  259. if (wParam == CLICK_WAS_SPACE) {
  260. bRet = PeekMessage(&PkMsg, NULL, WM_KEYUP, WM_KEYUP, PM_NOREMOVE);
  261. if (bRet) {
  262. bRet = (PkMsg.wParam == VK_SPACE);
  263. }
  264. } else {
  265. bRet = PeekMessage( &PkMsg, NULL, WM_LBUTTONUP, WM_LBUTTONUP, PM_NOREMOVE );
  266. }
  267. } while( !bRet );
  268. SetCapture(hwndCap);
  269. //
  270. // Restore play state so that MESS_END_SCAN will
  271. // know whether to just seek or seek and play.
  272. //
  273. if (save==PLAYING) {
  274. gState |= PLAYING;
  275. }
  276. if (gState & PAUSED) {
  277. gState |= PAUSED_AND_MOVED;
  278. }
  279. // PostDisplayMessage( MESS_END_SCAN );
  280. if (!(gDevices[ gCurrCdrom ]->State & PAUSED_AND_MOVED))
  281. SeekToCurrSecond( gCurrCdrom );
  282. //
  283. // Let go of the mutex. The play thread will be
  284. // restarted on the button-up event call to StateToState
  285. //
  286. if (save==PLAYING) {
  287. SetEvent( hPlayEv );
  288. }
  289. gState &= (~RW);
  290. gScanB = FALSE;
  291. SetOdCntl(hwnd,'U',TRUE);
  292. return(0L);
  293. } // end rewind
  294. }
  295. break;
  296. }
  297. return CallWindowProc(lpfnDefWndProc, hwnd, msg, wParam, lParam);
  298. }
  299. VOID
  300. DrawOdButton(
  301. IN LPDRAWITEMSTRUCT lpdis,
  302. IN HBITMAP hbmCtrlBtns,
  303. IN PCHILDCONTROL pcControl
  304. )
  305. /*++
  306. Routine Description:
  307. This routine will process the drawitemstruct, and draw an appropriate
  308. portion of the control buttons bitmap into the required rectangle.
  309. Information on the source rectangle extents and position can be tabulated
  310. using the child control and the drawitemstruct.
  311. Arguments:
  312. lpdis -- DrawItemStruct from a WM_DRAWITEM message for a BS_OWNERDRAW
  313. hbmCtrlBtns -- Large bitmap which has a set of 6 bitmaps for the button
  314. pcControl -- data structure for the control detailing size, etc.
  315. Return Value:
  316. none
  317. --*/
  318. {
  319. HDC hdc;
  320. INT bmNum;
  321. UINT State;
  322. UINT itemState;
  323. char WinText[3]="X";
  324. HGDIOBJ hBrush;
  325. if (lpdis->CtlType != ODT_BUTTON) {
  326. return;
  327. }
  328. //
  329. // Figure out which of the six button bitmaps to use
  330. //
  331. itemState = pcControl->state;
  332. State = lpdis->itemState;
  333. if (itemState & STATE_DISABLED) {
  334. bmNum = BTN_DISABLED;
  335. } else {
  336. if (State & ODS_SELECTED) {
  337. bmNum = BTN_DOWNSEL;
  338. } else {
  339. if (itemState & STATE_UP) {
  340. bmNum = (State & ODS_FOCUS) ? BTN_UP_FOCUS : BTN_UP;
  341. } else {
  342. bmNum = (State & ODS_FOCUS) ? BTN_DOWN_FOCUS : BTN_DOWN;
  343. }
  344. }
  345. }
  346. hdc = CreateCompatibleDC( lpdis->hDC );
  347. SelectObject( hdc, hbmCtrlBtns );
  348. //
  349. // BUGBUG - for now, just drawn one style of button.
  350. //
  351. FrameRect( lpdis->hDC, &lpdis->rcItem, hBrush = GetStockObject(BLACK_BRUSH));
  352. DeleteObject(hBrush);
  353. BitBlt( lpdis->hDC, lpdis->rcItem.left+1, lpdis->rcItem.top+1,
  354. lpdis->rcItem.right - lpdis->rcItem.left-2,
  355. lpdis->rcItem.bottom - lpdis->rcItem.top-2,
  356. hdc, pcControl->bmXOffset,
  357. BTN_Y_BORDER*(bmNum+1) + (pcControl->h * bmNum),
  358. SRCCOPY);
  359. DeleteDC(hdc);
  360. return;
  361. }
  362. VOID
  363. SetOdCntl(
  364. IN HWND hwndCntl,
  365. IN CHAR cState,
  366. IN BOOL RepaintIfDiff
  367. )
  368. /*++
  369. Routine Description:
  370. This routine takes care of making sure the Control in question is
  371. in the correct state. It sets the state, and Repaints if the old
  372. state was different and repaint is requested.
  373. Arguments:
  374. hwndCntl -- Handle to the control
  375. NewState -- Desired state -- X,D,U
  376. RepaintIfDiff -- whether or not to repaint the control if different
  377. Return Value:
  378. none
  379. --*/
  380. {
  381. UINT oldState,newState;
  382. INT i;
  383. if (hwndCntl == (HWND) NULL) {
  384. return;
  385. }
  386. for (i=0; i < gNumControls ; i++) {
  387. if ((cChild[i].phwnd != NULL)&&(*cChild[i].phwnd == hwndCntl)) {
  388. break;
  389. }
  390. }
  391. oldState = cChild[i].state;
  392. newState = (cState == 'X') ? STATE_DISABLED :
  393. (cState == 'U') ? STATE_UP :
  394. (cState == 'D') ? STATE_DOWN :
  395. STATE_NEW;
  396. if (oldState != newState) {
  397. cChild[i].state = newState;
  398. if (RepaintIfDiff) {
  399. RedrawWindow(hwndCntl,NULL,NULL,RDW_INVALIDATE);
  400. UpdateWindow(hwndCntl);
  401. }
  402. }
  403. return;
  404. }
  405. BOOL
  406. CreateChildWindows(
  407. IN DWORD windowId,
  408. IN HWND hwndParent
  409. )
  410. /*++
  411. Routine Description:
  412. This will create and initialize all the child windows we have in
  413. the cChild array which have ParentId of windowId.
  414. Arguments:
  415. windowId -- ID of the window whose child windows we are to create.
  416. hwndParent -- handle to the parent window
  417. Return Value:
  418. success/failure
  419. --*/
  420. {
  421. BOOL result = TRUE;
  422. HWND hwnd;
  423. INT i;
  424. //
  425. // Loop through all child controls, selecting the ones that apply.
  426. //
  427. for (i=0; i<gNumControls; i++) {
  428. if (cChild[i].ParentId == windowId) {
  429. hwnd = CreateWindow( (LPCTSTR)cChild[ i ].class,
  430. (LPCTSTR)cChild[ i ].name,
  431. CHILD_STYLE | cChild[i].style,
  432. cChild[ i ].x,
  433. cChild[ i ].y,
  434. cChild[ i ].w,
  435. cChild[ i ].h,
  436. hwndParent,
  437. (HMENU)cChild[ i ].id,
  438. (HINSTANCE)gInstance,
  439. NULL
  440. );
  441. result &= (hwnd != NULL);
  442. //
  443. // Save a handle to the control
  444. //
  445. if (cChild[i].phwnd != NULL) {
  446. *cChild[i].phwnd = hwnd;
  447. }
  448. //
  449. // Save the window proc, and subclass all tabstops.
  450. //
  451. cChild[i].lpfnDefProc = (WNDPROC) GetWindowLong(hwnd,GWL_WNDPROC);
  452. if (cChild[i].isTabstop) {
  453. SetWindowLong(hwnd,GWL_WNDPROC,(LONG) ButtonWndProc);
  454. }
  455. }
  456. }
  457. //
  458. // Make sure that all buttons are redrawn correctly.
  459. //
  460. CheckAndSetControls();
  461. return(result);
  462. }
  463. VOID
  464. CheckAndSetControls(
  465. )
  466. /*++
  467. Routine Description:
  468. This routine checks all the child controls, their states, and draws
  469. the ones whose states don't match their global variables.
  470. Arguments:
  471. None
  472. Return Value:
  473. None
  474. --*/
  475. {
  476. INT i;
  477. if ((gState & PLAYING)&&(gState & PLAY_PENDING)) {
  478. gState &= ~PLAY_PENDING;
  479. }
  480. gPlaying = (BOOL) (gState & (PLAYING|PLAY_PENDING));
  481. gPaused = (BOOL) (gState & PAUSED);
  482. gStopped = (BOOL) (gState & STOPPED);
  483. for (i=0; i < gNumControls ; i++) {
  484. //
  485. // If it's a valid, created window, continue to check.
  486. //
  487. // if ((cChild[i].phwnd != NULL)&&(*cChild[i].phwnd != (HWND) NULL)) {
  488. if (cChild[i].phwnd != NULL) {
  489. //
  490. // if its disabled status depends on the CD, disable/enable it.
  491. //
  492. if (cChild[i].cdDisable) {
  493. if ((gState & NO_CD) || (gState & DATA_CD_LOADED)) {
  494. if (!(cChild[i].state & STATE_DISABLED)) {
  495. //
  496. // Special case for eject button
  497. //
  498. if ((cChild[i].id == IDB_EJECT)&&(gState & DATA_CD_LOADED)) {
  499. SetOdCntl(*cChild[i].phwnd,'U',TRUE);
  500. } else {
  501. SetOdCntl(*cChild[i].phwnd,'X',TRUE);
  502. //
  503. // Special case for Edit Playlist
  504. //
  505. if (cChild[i].id == IDB_EDIT) {
  506. EnableMenuItem(GetSubMenu(GetMenu(gMainWnd),0),
  507. IDM_DATABASE_EDIT,MF_GRAYED);
  508. cChild[i].state = STATE_DISABLED;
  509. }
  510. //
  511. // Special case for Track combobox
  512. //
  513. if (cChild[i].id == IDT_TRACK_NAME) {
  514. EnableWindow(*cChild[i].phwnd,FALSE);
  515. cChild[i].state = STATE_DISABLED;
  516. }
  517. }
  518. }
  519. } else {
  520. if (cChild[i].state & STATE_DISABLED) {
  521. //
  522. // State NEW allows it to be redrawn by fall-through.
  523. //
  524. cChild[i].state &= ~STATE_DISABLED;
  525. cChild[i].state |= STATE_NEW;
  526. //
  527. // Special case for Edit Playlist
  528. //
  529. if (cChild[i].id == IDB_EDIT) {
  530. EnableMenuItem(GetSubMenu(GetMenu(gMainWnd),0),
  531. IDM_DATABASE_EDIT,MF_ENABLED);
  532. cChild[i].state &= ~STATE_DISABLED;
  533. cChild[i].state |= STATE_NEW;
  534. }
  535. //
  536. // Special case for track combobox
  537. //
  538. if (cChild[i].id == IDT_TRACK_NAME) {
  539. EnableWindow(*cChild[i].phwnd,TRUE);
  540. cChild[i].state &= ~STATE_DISABLED;
  541. cChild[i].state |= STATE_NEW;
  542. }
  543. }
  544. }
  545. }
  546. //
  547. // Only interpret the rest of the states if its not disabled.
  548. //
  549. if (!(cChild[i].state & STATE_DISABLED) ) {
  550. //
  551. // For now, only do buttons
  552. //
  553. if (cChild[i].style & BS_OWNERDRAW) {
  554. if (*cChild[i].pbMatch == cChild[i].bMatchState) {
  555. SetOdCntl(*cChild[i].phwnd,'U',TRUE);
  556. } else {
  557. SetOdCntl(*cChild[i].phwnd,'D',TRUE);
  558. }
  559. }
  560. }
  561. }
  562. }
  563. }
  564. //===================================================================
  565. //===================================================================
  566. BOOL fAdd, fRemove, fClear;