/*++ Copyright (c) 1993 Microsoft Corporation Module Name: button.c Abstract: This module contains the Procedure which subclasses all of the different controls which need to be tab'd to in the main screen. Author: John L. Miller (15-Feb-1993) --*/ #include #include "cdplayer.h" #include #include #include #include "trkinfo.h" LRESULT CALLBACK ButtonWndProc( IN HWND hwnd, IN UINT msg, IN WPARAM wParam, IN LPARAM lParam ) /*++ Routine Description: Implements class to sub-class button windows. If the Arguments: standard window proc vars Return Value: 0 for success, else error code. --*/ #define CLICK_WAS_SPACE 1234 { int i; UINT CurSel,MaxSel; UINT save; HWND hwndParent,hwndCap; WNDPROC lpfnDefWndProc; MSG PkMsg; BOOL bRet; // // Determine which control is sending the message. // for (i=0; i < gNumControls; i++) { if ((cChild[i].phwnd != NULL)&&(hwnd == *cChild[i].phwnd)) { lpfnDefWndProc = cChild[i].lpfnDefProc; hwndParent = GetParent(*cChild[i].phwnd); // // Actually, we need the parent's parent! // hwndParent = GetParent(hwndParent); break; } } // // Filter out the TAB, ESCAPE, and ENTER keystrokes. // We want to send messages back to the parent window when we // get these so that it can switch focus else select the appropriate // item from the control (if it's a combobox) // switch (msg) { case WM_KEYDOWN: switch (wParam) { case VK_UP: // // If the control is a combo box whose list is // down, then we need to index within it. // if ( (cChild[i].class == gszComboBox)&& SendMessage(hwnd,CB_GETDROPPEDSTATE,0,0)) { CurSel = SendMessage(hwnd,CB_GETCURSEL,0,0) - 1; if (CurSel < 0) { CurSel = 0; } SendMessage(hwnd,CB_SETCURSEL,(WPARAM) CurSel,0); } else { // // Otherwise, treat it as a tab/backtab. // SendMessage(hwndParent, WM_BACKTAB, 0, 0); } return 0; case VK_LEFT: SendMessage(hwndParent, WM_BACKTAB, 0, 0); return 0; case VK_DOWN: // // If the control is a combo box whose list is // down, then we need to index within it. // if ( (cChild[i].class == gszComboBox)&& SendMessage(hwnd,CB_GETDROPPEDSTATE,0,0)) { CurSel = SendMessage(hwnd,CB_GETCURSEL,0,0) + 1; MaxSel = SendMessage(hwnd,CB_GETCOUNT,0,0); if (CurSel >= MaxSel) { CurSel = MaxSel-1; } SendMessage(hwnd,CB_SETCURSEL,(WPARAM) CurSel,0); } else { // // Otherwise, treat it as a tab/backtab. // SendMessage(hwndParent, WM_TAB, 0, 0); } return 0; case VK_RIGHT: SendMessage(hwndParent, WM_TAB, 0, 0); return 0; case VK_TAB: // // Differentiate between TAB and SHIFT-TAB // if (GetKeyState(VK_SHIFT) < 0) { SendMessage(hwndParent, WM_BACKTAB, 0, 0); } else { SendMessage(hwndParent, WM_TAB, 0, 0); } return 0; case VK_ESCAPE: SendMessage(hwndParent, WM_ESC, 0, 0); return 0; case VK_RETURN: SendMessage(hwndParent, WM_ENTER, 0, 0); return 0; case VK_SPACE: if ((hwnd == ghwndScanF)||(hwnd == ghwndScanB)) { SendMessage(hwnd,WM_LBUTTONDOWN,CLICK_WAS_SPACE,0); return(0); } } break; case WM_KEYUP: case WM_CHAR: switch (wParam) { case VK_TAB: case VK_ESCAPE: case VK_RETURN: case VK_UP: case VK_LEFT: case VK_DOWN: case VK_RIGHT: return 0; case VK_SPACE: if ((hwnd == ghwndScanF)||(hwnd == ghwndScanB)) { return(0); } } break; case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: if (gState&CD_LOADED) { if (hwnd==ghwndScanF) { // // Fast forward button has been pressed (and is // "legal"). // // SetFocus(hwnd); gScanF = TRUE; SetOdCntl(hwnd,'D',TRUE); save = (gState & PLAYING); gState &= (~PLAYING); gState |= FF; // // Halt the play thread from updating the display // if (save==PLAYING) { ResetEvent( hPlayEv ); PostDisplayMessage( MESS_PAUSE_AND_START_SCAN ); } else { PostDisplayMessage( MESS_START_SCAN ); } // // while the button is down (no other BUTTON messages // pending), keep trying to skip ahead another second // on this track // hwndCap=GetCapture(); SetCapture(hwnd); i = 0; do { TimeAdjustIncSecond( gCurrCdrom ); if (i>15) { TimeAdjustIncSecond( gCurrCdrom ); TimeAdjustIncSecond( gCurrCdrom ); } Sleep( 100 ); i++; if (wParam == CLICK_WAS_SPACE) { bRet = PeekMessage(&PkMsg, NULL, WM_KEYUP, WM_KEYUP, PM_NOREMOVE); if (bRet) { bRet = (PkMsg.wParam == VK_SPACE); } } else { bRet = PeekMessage( &PkMsg, NULL, WM_LBUTTONUP, WM_LBUTTONUP, PM_NOREMOVE ); } } while( !bRet ); SetCapture(hwndCap); // // Restore play state so that MESS_END_SCAN will // know whether to just seek or seek and play. // if (save==PLAYING) { gState |= PLAYING; } if (gState & PAUSED) { gState |= PAUSED_AND_MOVED; } // PostDisplayMessage( MESS_END_SCAN ); if (!(gDevices[ gCurrCdrom ]->State & PAUSED_AND_MOVED)) SeekToCurrSecond( gCurrCdrom ); // // Let go of the mutex. The play thread will be // restarted on the button-up event call to StateToState // if (save==PLAYING) { SetEvent( hPlayEv ); } gState &= (~FF); gScanF = FALSE; SetOdCntl(hwnd,'U',TRUE); return(0L); } // end fast forward if (hwnd==ghwndScanB) { // // Rewind button was pressed and is "legal". // gScanB = TRUE; SetFocus(hwnd); SetOdCntl(hwnd,'D',TRUE); save = (gState & PLAYING); gState &= (~PLAYING); gState |= RW; // // Halt the play thread from updating the display // if (save==PLAYING) { ResetEvent( hPlayEv ); PostDisplayMessage( MESS_PAUSE_AND_START_SCAN ); } else { PostDisplayMessage( MESS_START_SCAN ); } // // while the button is down (no other BUTTON messages // pending), keep trying to skip ahead another second // on this track // hwndCap=GetCapture(); SetCapture(hwnd); i = 0; do { TimeAdjustDecSecond( gCurrCdrom ); if (i>15) { TimeAdjustDecSecond( gCurrCdrom ); TimeAdjustDecSecond( gCurrCdrom ); } Sleep( 100 ); i++; if (wParam == CLICK_WAS_SPACE) { bRet = PeekMessage(&PkMsg, NULL, WM_KEYUP, WM_KEYUP, PM_NOREMOVE); if (bRet) { bRet = (PkMsg.wParam == VK_SPACE); } } else { bRet = PeekMessage( &PkMsg, NULL, WM_LBUTTONUP, WM_LBUTTONUP, PM_NOREMOVE ); } } while( !bRet ); SetCapture(hwndCap); // // Restore play state so that MESS_END_SCAN will // know whether to just seek or seek and play. // if (save==PLAYING) { gState |= PLAYING; } if (gState & PAUSED) { gState |= PAUSED_AND_MOVED; } // PostDisplayMessage( MESS_END_SCAN ); if (!(gDevices[ gCurrCdrom ]->State & PAUSED_AND_MOVED)) SeekToCurrSecond( gCurrCdrom ); // // Let go of the mutex. The play thread will be // restarted on the button-up event call to StateToState // if (save==PLAYING) { SetEvent( hPlayEv ); } gState &= (~RW); gScanB = FALSE; SetOdCntl(hwnd,'U',TRUE); return(0L); } // end rewind } break; } return CallWindowProc(lpfnDefWndProc, hwnd, msg, wParam, lParam); } VOID DrawOdButton( IN LPDRAWITEMSTRUCT lpdis, IN HBITMAP hbmCtrlBtns, IN PCHILDCONTROL pcControl ) /*++ Routine Description: This routine will process the drawitemstruct, and draw an appropriate portion of the control buttons bitmap into the required rectangle. Information on the source rectangle extents and position can be tabulated using the child control and the drawitemstruct. Arguments: lpdis -- DrawItemStruct from a WM_DRAWITEM message for a BS_OWNERDRAW hbmCtrlBtns -- Large bitmap which has a set of 6 bitmaps for the button pcControl -- data structure for the control detailing size, etc. Return Value: none --*/ { HDC hdc; INT bmNum; UINT State; UINT itemState; char WinText[3]="X"; HGDIOBJ hBrush; if (lpdis->CtlType != ODT_BUTTON) { return; } // // Figure out which of the six button bitmaps to use // itemState = pcControl->state; State = lpdis->itemState; if (itemState & STATE_DISABLED) { bmNum = BTN_DISABLED; } else { if (State & ODS_SELECTED) { bmNum = BTN_DOWNSEL; } else { if (itemState & STATE_UP) { bmNum = (State & ODS_FOCUS) ? BTN_UP_FOCUS : BTN_UP; } else { bmNum = (State & ODS_FOCUS) ? BTN_DOWN_FOCUS : BTN_DOWN; } } } hdc = CreateCompatibleDC( lpdis->hDC ); SelectObject( hdc, hbmCtrlBtns ); // // BUGBUG - for now, just drawn one style of button. // FrameRect( lpdis->hDC, &lpdis->rcItem, hBrush = GetStockObject(BLACK_BRUSH)); DeleteObject(hBrush); BitBlt( lpdis->hDC, lpdis->rcItem.left+1, lpdis->rcItem.top+1, lpdis->rcItem.right - lpdis->rcItem.left-2, lpdis->rcItem.bottom - lpdis->rcItem.top-2, hdc, pcControl->bmXOffset, BTN_Y_BORDER*(bmNum+1) + (pcControl->h * bmNum), SRCCOPY); DeleteDC(hdc); return; } VOID SetOdCntl( IN HWND hwndCntl, IN CHAR cState, IN BOOL RepaintIfDiff ) /*++ Routine Description: This routine takes care of making sure the Control in question is in the correct state. It sets the state, and Repaints if the old state was different and repaint is requested. Arguments: hwndCntl -- Handle to the control NewState -- Desired state -- X,D,U RepaintIfDiff -- whether or not to repaint the control if different Return Value: none --*/ { UINT oldState,newState; INT i; if (hwndCntl == (HWND) NULL) { return; } for (i=0; i < gNumControls ; i++) { if ((cChild[i].phwnd != NULL)&&(*cChild[i].phwnd == hwndCntl)) { break; } } oldState = cChild[i].state; newState = (cState == 'X') ? STATE_DISABLED : (cState == 'U') ? STATE_UP : (cState == 'D') ? STATE_DOWN : STATE_NEW; if (oldState != newState) { cChild[i].state = newState; if (RepaintIfDiff) { RedrawWindow(hwndCntl,NULL,NULL,RDW_INVALIDATE); UpdateWindow(hwndCntl); } } return; } BOOL CreateChildWindows( IN DWORD windowId, IN HWND hwndParent ) /*++ Routine Description: This will create and initialize all the child windows we have in the cChild array which have ParentId of windowId. Arguments: windowId -- ID of the window whose child windows we are to create. hwndParent -- handle to the parent window Return Value: success/failure --*/ { BOOL result = TRUE; HWND hwnd; INT i; // // Loop through all child controls, selecting the ones that apply. // for (i=0; i