/************************************************************************** * * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR * PURPOSE. * * Copyright (c) 1992 - 1995 Microsoft Corporation. All Rights Reserved. * **************************************************************************/ /**************************************************************************** * * toolbar.c: Toolbar control window * * Vidcap32 Source code * ***************************************************************************/ #include #include #include //#include #include "toolbar.h" // use this for generic app /************************************************************************/ /* work for win3.0 */ #ifndef COLOR_BTNHIGHLIGHT #define COLOR_BTNHIGHLIGHT 20 #endif TCHAR szToolBarClass[] = "ToolBarClass"; HBRUSH ghbrToolbar; // brush for toolbar background // // Window proc for buttons, THIS FUNCTION MUST BE EXPORTED // LRESULT FAR PASCAL toolbarWndProc(HWND, unsigned, WPARAM, LPARAM); typedef long (FAR PASCAL *LPWNDPROC)(); /* Defines */ #ifdef _WIN32 #define GETARRAYBUTT(hwnd) ((HANDLE)GetWindowLongPtr(hwnd,GWLP_ARRAYBUTT)) #define GETNUMBUTTONS(hwnd) ((int)GetWindowLong(hwnd,GWL_NUMBUTTONS)) #define GETPRESSED(hwnd) ((BOOL)GetWindowLong(hwnd,GWL_PRESSED)) #define GETKEYPRESSED(hwnd) ((BOOL)GetWindowLong(hwnd,GWL_KEYPRESSED)) #define GETWHICH(hwnd) ((int)GetWindowLong(hwnd,GWL_WHICH)) #define GETSHIFTED(hwnd) ((BOOL)GetWindowLong(hwnd,GWL_SHIFTED)) #define GETBMPHANDLE(hwnd) ((HANDLE)GetWindowLongPtr(hwnd,GWLP_BMPHANDLE)) #define GETBMPINT(hwnd) ((int)GetWindowLong(hwnd,GWL_BMPINT)) #define GETBUTTONSIZE(hwnd) GetWindowLong(hwnd,GWL_BUTTONSIZE) #define GETHINST(hwnd) ((HANDLE)GetWindowLongPtr(hwnd,GWLP_HINST)) #define SETARRAYBUTT(hwnd, h) SetWindowLongPtr(hwnd, GWLP_ARRAYBUTT, (UINT_PTR)h) #define SETNUMBUTTONS(hwnd, wNumButtons) \ SetWindowLong(hwnd, GWL_NUMBUTTONS, wNumButtons) #define SETPRESSED(hwnd, f) SetWindowLong(hwnd, GWL_PRESSED, (UINT)f) #define SETKEYPRESSED(hwnd, f) SetWindowLong(hwnd, GWL_KEYPRESSED, (UINT)f) #define SETWHICH(hwnd, i) SetWindowLong(hwnd, GWL_WHICH, (UINT)i) #define SETSHIFTED(hwnd, i) SetWindowLong(hwnd, GWL_SHIFTED, (UINT)i) #define SETBMPHANDLE(hwnd, h) SetWindowLongPtr(hwnd, GWLP_BMPHANDLE, (UINT_PTR)h) #define SETBMPINT(hwnd, i) SetWindowLong(hwnd, GWL_BMPINT, (UINT)i) #define SETBUTTONSIZE(hwnd, l) SetWindowLong(hwnd, GWL_BUTTONSIZE, l) #define SETHINST(hwnd, h) SetWindowLongPtr(hwnd, GWLP_HINST, (UINT_PTR)h) #else #define GETARRAYBUTT(hwnd) ((HANDLE)GetWindowWord(hwnd,GWW_ARRAYBUTT)) #define GETNUMBUTTONS(hwnd) ((int)GetWindowWord(hwnd,GWW_NUMBUTTONS)) #define GETPRESSED(hwnd) ((BOOL)GetWindowWord(hwnd,GWW_PRESSED)) #define GETKEYPRESSED(hwnd) ((BOOL)GetWindowWord(hwnd,GWW_KEYPRESSED)) #define GETWHICH(hwnd) ((int)GetWindowWord(hwnd,GWW_WHICH)) #define GETSHIFTED(hwnd) ((BOOL)GetWindowWord(hwnd,GWW_SHIFTED)) #define GETBMPHANDLE(hwnd) ((HANDLE)GetWindowWord(hwnd,GWW_BMPHANDLE)) #define GETBMPINT(hwnd) ((int)GetWindowWord(hwnd,GWW_BMPINT)) #define GETBUTTONSIZE(hwnd) GetWindowLong(hwnd,GWL_BUTTONSIZE) #define GETHINST(hwnd) ((HANDLE)GetWindowWord(hwnd,GWW_HINST)) #define SETARRAYBUTT(hwnd, h) SetWindowWord(hwnd, GWW_ARRAYBUTT, (WORD)h) #define SETNUMBUTTONS(hwnd, wNumButtons) \ SetWindowWord(hwnd, GWW_NUMBUTTONS, wNumButtons) #define SETPRESSED(hwnd, f) SetWindowWord(hwnd, GWW_PRESSED, (WORD)f) #define SETKEYPRESSED(hwnd, f) SetWindowWord(hwnd, GWW_KEYPRESSED, (WORD)f) #define SETWHICH(hwnd, i) SetWindowWord(hwnd, GWW_WHICH, (WORD)i) #define SETSHIFTED(hwnd, i) SetWindowWord(hwnd, GWW_SHIFTED, (WORD)i) #define SETBMPHANDLE(hwnd, h) SetWindowWord(hwnd, GWW_BMPHANDLE, (WORD)h) #define SETBMPINT(hwnd, i) SetWindowWord(hwnd, GWW_BMPINT, (WORD)i) #define SETBUTTONSIZE(hwnd, l) SetWindowLong(hwnd, GWL_BUTTONSIZE, l) #define SETHINST(hwnd, h) SetWindowWord(hwnd, GWW_HINST, (WORD)h) #endif #define lpCreate ((LPCREATESTRUCT)lParam) /* Prototypes */ static void NEAR PASCAL NotifyParent(HWND, int); /************************************************************************** toolbarInit( hInst, hPrev ) Call this routine to initialize the toolbar code. Arguments: hPrev instance handle of previous instance hInst instance handle of current instance Returns: TRUE if successful, FALSE if not ***************************************************************************/ BOOL FAR PASCAL toolbarInit(HANDLE hInst, HANDLE hPrev) { WNDCLASS cls; /* Register the tool bar window class */ if (!hPrev) { cls.hCursor = LoadCursor(NULL,IDC_ARROW); cls.hIcon = NULL; cls.lpszMenuName = NULL; cls.lpszClassName = (LPSTR)szToolBarClass; cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); cls.hInstance = hInst; cls.style = CS_DBLCLKS; cls.lpfnWndProc = toolbarWndProc; cls.cbClsExtra = 0; cls.cbWndExtra = TOOLBAR_EXTRABYTES; if (!RegisterClass(&cls)) return FALSE; } return TRUE; } /***************************************************************************/ /* toolbarSetBitmap: takes a resource ID and associates that bitmap with */ /* a given toolbar. Also takes the instance handle and */ /* the size of the buttons on the toolbar. */ /***************************************************************************/ BOOL FAR PASCAL toolbarSetBitmap(HWND hwnd, HANDLE hInst, int ibmp, POINT ptSize) { SETHINST(hwnd, hInst); SETBMPHANDLE(hwnd, NULL); SETBMPINT(hwnd, ibmp); SETBUTTONSIZE(hwnd, MAKELONG(ptSize.y, ptSize.x)); return (BOOL)SendMessage(hwnd, WM_SYSCOLORCHANGE, 0, 0L); // do the work } /***************************************************************************/ /* toolbarGetNumButtons: return the number of buttons registered on a */ /* given toolbar window. */ /***************************************************************************/ int FAR PASCAL toolbarGetNumButtons(HWND hwnd) { return GETNUMBUTTONS(hwnd); } /***************************************************************************/ /* toolbarButtonFromIndex: Given an index into the array of buttons on */ /* this toolbar, return which button is there. */ /* Returns -1 for an error code. */ /***************************************************************************/ int FAR PASCAL toolbarButtonFromIndex(HWND hwnd, int iBtnPos) { int iButton; HANDLE h; TOOLBUTTON far *lpaButtons; /* Get the array of buttons on this toolbar */ h = GETARRAYBUTT(hwnd); if (!h) return -1; /* Validate the index passed in */ if (iBtnPos > GETNUMBUTTONS(hwnd) || iBtnPos < 0) return -1; lpaButtons = (TOOLBUTTON far *)GlobalLock(h); /* Read off the answer */ iButton = lpaButtons[iBtnPos].iButton; GlobalUnlock(h); return iButton; } /***************************************************************************/ /* toolbarIndexFromButton: Given a button ID, return the position in the */ /* array that it appears at. */ /* Returns -1 for an error code. */ /***************************************************************************/ int FAR PASCAL toolbarIndexFromButton(HWND hwnd, int iButton) { int i, iBtnPos = -1; HANDLE h; TOOLBUTTON far *lpButton; /* Get the array of buttons */ h = GETARRAYBUTT(hwnd); if (!h) return -1; lpButton = (TOOLBUTTON far *)GlobalLock(h); /* loop through until you find it */ for(i = 0; i < GETNUMBUTTONS(hwnd); i++, lpButton++) if (lpButton->iButton == iButton) { iBtnPos = i; break; } GlobalUnlock(h); return iBtnPos; } /***************************************************************************/ /* toolbarPrevStateFromButton: Given a button ID, return the state that */ /* the button was in before it was pressed */ /* all the way down (for non-push buttons). */ /* Return -1 for an error code. */ /***************************************************************************/ int FAR PASCAL toolbarPrevStateFromButton(HWND hwnd, int iButton) { int i, iPrevState = -1; HANDLE h; TOOLBUTTON far *lpButton; /* Get the array of buttons */ h = GETARRAYBUTT(hwnd); if (!h) return -1; lpButton = (TOOLBUTTON far *)GlobalLock(h); /* look for what we need */ for(i = 0; i < GETNUMBUTTONS(hwnd); i++, lpButton++) if (lpButton->iButton == iButton) { iPrevState = lpButton->iPrevState; break; } GlobalUnlock(h); return iPrevState; } /***************************************************************************/ /* toolbarActivityFromButton: Given a button ID, return the most recent */ /* activity that happened to it. (eg DBLCLK) */ /* Return -1 for an error code. */ /***************************************************************************/ int FAR PASCAL toolbarActivityFromButton(HWND hwnd, int iButton) { int i, iActivity = -1; HANDLE h; TOOLBUTTON far *lpButton; /* Get the array of buttons */ h = GETARRAYBUTT(hwnd); if (!h) return -1; lpButton = (TOOLBUTTON far *)GlobalLock(h); /* loop through until you find it */ for(i = 0; i < GETNUMBUTTONS(hwnd); i++, lpButton++) if (lpButton->iButton == iButton) iActivity = lpButton->iActivity; GlobalUnlock(h); return iActivity; } /***************************************************************************/ /* toolbarIndexFromPoint: Given a point in the toolbar window, return the */ /* index of the button beneath that point. */ /* Return -1 for an error code. */ /***************************************************************************/ int FAR PASCAL toolbarIndexFromPoint(HWND hwnd, POINT pt) { int i, iBtnPos = -1; HANDLE h; TOOLBUTTON far *lpButton; /* Get the array of buttons */ h = GETARRAYBUTT(hwnd); if (!h) return -1; lpButton = (TOOLBUTTON far *)GlobalLock(h); /* loop through until we find an intersection */ for(i = 0; i < GETNUMBUTTONS(hwnd); i++, lpButton++) if (PtInRect(&lpButton->rc, pt)) { iBtnPos = i; break; } GlobalUnlock(h); return iBtnPos; } /***************************************************************************/ /* toolbarRectFromIndex: Given an index into our array of buttons, return*/ /* the rect occupied by that button. */ /* Return a NULL rect for an error. */ /***************************************************************************/ BOOL FAR PASCAL toolbarRectFromIndex(HWND hwnd, int iBtnPos, LPRECT lprc) { HANDLE h; TOOLBUTTON far *lpaButtons; /* Get the array of buttons */ h = GETARRAYBUTT(hwnd); if (!h) return FALSE; /* Validate the index passed in */ if (iBtnPos > GETNUMBUTTONS(hwnd) || iBtnPos < 0) return FALSE; lpaButtons = (TOOLBUTTON far *)GlobalLock(h); /* Read off the rect */ *lprc = lpaButtons[iBtnPos].rc; GlobalUnlock(h); return TRUE; } /***************************************************************************/ /* toolbarFullStateFromButton: Given a button in our array of buttons, */ /* return the state of that button. */ /* (including the wierd state FULLDOWN). For */ /* just UP or DOWN or GRAYED, */ /* call toolbarStateFromButton. */ /* Return -1 for an error. */ /***************************************************************************/ int FAR PASCAL toolbarFullStateFromButton(HWND hwnd, int iButton) { int iState, iBtnPos; HANDLE h; TOOLBUTTON far *lpaButtons; iBtnPos = toolbarIndexFromButton(hwnd, iButton); if (iBtnPos == -1) return -1; /* Get the array of buttons */ h = GETARRAYBUTT(hwnd); if (!h) return -1; lpaButtons = (TOOLBUTTON far *)GlobalLock(h); /* Read off the state */ iState = lpaButtons[iBtnPos].iState; GlobalUnlock(h); return iState; } /***************************************************************************/ /* toolbarStateFromButton: This fn is called by the parent application */ /* to get the state of a button. It will only */ /* return DOWN, or UP or GRAYED as opposed to */ /* toolbarFullStateFromButton which could return */ /* FULLDOWN. */ /***************************************************************************/ int FAR PASCAL toolbarStateFromButton(HWND hwnd, int iButton) { int iState; /* If a checkbox button is all the way down, it's previous state is */ /* the one we want. */ if ((iState = toolbarFullStateFromButton(hwnd, iButton)) == BTNST_FULLDOWN) { iState = toolbarPrevStateFromButton(hwnd, iButton); return iState; } else return iState; } /***************************************************************************/ /* toolbarStringFromIndex: Given an index into our array of buttons, return*/ /* the string resource associated with it. */ /* Return -1 for an error. */ /***************************************************************************/ int FAR PASCAL toolbarStringFromIndex(HWND hwnd, int iBtnPos) { int iString; HANDLE h; TOOLBUTTON far *lpaButtons; /* Get the array of buttons */ h = GETARRAYBUTT(hwnd); if (!h) return -1; /* Validate the index passed in */ if (iBtnPos > GETNUMBUTTONS(hwnd) || iBtnPos < 0) return -1; lpaButtons = (TOOLBUTTON far *)GlobalLock(h); /* Read off the ID */ iString = lpaButtons[iBtnPos].iString; GlobalUnlock(h); return iString; } /***************************************************************************/ /* toolbarTypeFromIndex: Given an index into our array of buttons, return*/ /* the type of button it is (PUSH, RADIO, etc.) */ /* Return -1 for an error. */ /***************************************************************************/ int FAR PASCAL toolbarTypeFromIndex(HWND hwnd, int iBtnPos) { int iType; HANDLE h; TOOLBUTTON far *lpaButtons; /* Get the Array of buttons */ h = GETARRAYBUTT(hwnd); if (!h) return -1; /* Validate the index passed in */ if (iBtnPos > GETNUMBUTTONS(hwnd) || iBtnPos < 0) return -1; lpaButtons = (TOOLBUTTON far *)GlobalLock(h); /* Read off the type */ iType = lpaButtons[iBtnPos].iType; GlobalUnlock(h); return iType; } /***************************************************************************/ /* toolbarAddTool: Add a button to this toolbar. Sort them by leftmost */ /* position in the window (for tabbing order). */ /* Return FALSE for an error. */ /***************************************************************************/ BOOL FAR PASCAL toolbarAddTool(HWND hwnd, TOOLBUTTON tb) { HANDLE h; TOOLBUTTON far *lpaButtons; int cButtons, i, j; BOOL fInsert = FALSE; /* We better not have this button on the toolbar already */ if (toolbarIndexFromButton(hwnd, tb.iButton) != -1) return FALSE; /* Get the array of buttons */ h = GETARRAYBUTT(hwnd); if (!h) return FALSE; /* How many buttons are there already? */ cButtons = GETNUMBUTTONS(hwnd); /* If we have filled our alloced memory for this array already, we */ /* need to re-alloc some more memory */ if ( ((cButtons & (TOOLGROW - 1)) == 0) && (cButtons > 0) ) { /* Re-alloc it bigger */ h = GlobalReAlloc(h, GlobalSize(h) + TOOLGROW * sizeof(TOOLBUTTON), GMEM_MOVEABLE | GMEM_SHARE); if (!h) return FALSE; } lpaButtons = (TOOLBUTTON far *)GlobalLock(h); /* Look for the spot we need to insert this new guy at. */ /* Remember, we sort by left x position breaking ties */ /* with top y position. */ for (i = 0; i < cButtons; i++) { // Here it goes if (lpaButtons[i].rc.left > tb.rc.left || (lpaButtons[i].rc.left == tb.rc.left && lpaButtons[i].rc.top > tb.rc.top)) { fInsert = TRUE; /* Open up a spot in the array */ for (j = cButtons; j > i; j--) lpaButtons[j] = lpaButtons[j-1]; /* Add our new guy */ lpaButtons[i] = tb; // redraw now InvalidateRect(hwnd, &(lpaButtons[i].rc), FALSE); break; } } /* If our loop didn't insert it, we need to add it to the end */ if (!fInsert) lpaButtons[i] = tb; /* If we are told that this button has the focus, we better */ /* change the focus to it. Then use the normal state. */ if (tb.iState == BTNST_FOCUSUP) { tb.iState = BTNST_UP; SETWHICH(hwnd, i); } else if (tb.iState == BTNST_FOCUSDOWN || tb.iState == BTNST_FULLDOWN){ tb.iState = BTNST_DOWN; // nonsense to init to FULLDOWN SETWHICH(hwnd, i); } cButtons++; // one more button now. GlobalUnlock(h); SETNUMBUTTONS(hwnd, cButtons); // new count SETARRAYBUTT(hwnd, h); // re-alloc might have changed it /* Just in case no one else makes this new button draw */ InvalidateRect(hwnd, &(tb.rc), FALSE); return TRUE; } /***************************************************************************/ /* toolbarRetrieveTool: Get the TOOLBUTTON struct for the given button. */ /* Return FALSE for an error. */ /***************************************************************************/ BOOL FAR PASCAL toolbarRetrieveTool(HWND hwnd, int iButton, LPTOOLBUTTON lptb) { int i; HANDLE h; TOOLBUTTON far *lpButton; BOOL fFound = FALSE; /* Get the array of buttons */ h = GETARRAYBUTT(hwnd); if (!h) return FALSE; lpButton = (TOOLBUTTON far *)GlobalLock(h); /* look for what we need */ for(i = 0; i < GETNUMBUTTONS(hwnd); i++, lpButton++) if (lpButton->iButton == iButton) { *lptb = *lpButton; fFound = TRUE; break; } GlobalUnlock(h); return fFound; } /***************************************************************************/ /* toolbarRemoveTool: Remove this button ID from our array of buttons on */ /* the toolbar. (only 1 of each button ID allowed). */ /* Return FALSE for an error. */ /***************************************************************************/ BOOL FAR PASCAL toolbarRemoveTool(HWND hwnd, int iButton) { HANDLE h; TOOLBUTTON far *lpaButtons; int cButtons, i, j; BOOL fFound = FALSE; /* Get the array of buttons */ h = GETARRAYBUTT(hwnd); if (!h) return FALSE; /* How many buttons are on there now? */ cButtons = GETNUMBUTTONS(hwnd); lpaButtons = (TOOLBUTTON far *)GlobalLock(h); /* Find a match, remove it, and close the array around it. */ for (i = 0; i < cButtons; i++) if (lpaButtons[i].iButton == iButton) { fFound = TRUE; // redraw now InvalidateRect(hwnd, &(lpaButtons[i].rc), FALSE); if (i != cButtons - 1) // Last button? Don't bother! for (j = i; j < cButtons; j++) lpaButtons[j] = lpaButtons[j + 1]; break; } GlobalUnlock(h); /* Didn't find it! */ if (!fFound) return FALSE; /* One less button */ cButtons--; /* Every once in a while, re-alloc a smaller array chunk to */ /* save memory. */ if ( ((cButtons & (TOOLGROW - 1)) == 0) && (cButtons > 0) ) { /* Re-alloc it smaller */ h = GlobalReAlloc(h, GlobalSize(h) - TOOLGROW * sizeof(TOOLBUTTON), GMEM_MOVEABLE | GMEM_SHARE); if (!h) return FALSE; } SETNUMBUTTONS(hwnd, cButtons); // new count SETARRAYBUTT(hwnd, h); // re-alloc could have changed it return TRUE; } /***************************************************************************/ /* toolbarModifyString: Given a button ID on the toolbar, change it's */ /* string resource associated with it. */ /* returns FALSE for an error or if no such button */ /***************************************************************************/ BOOL FAR PASCAL toolbarModifyString(HWND hwnd, int iButton, int iString) { HANDLE h; TOOLBUTTON far *lpButton; int cButtons, i; BOOL fFound = FALSE; /* Get the array of buttons */ h = GETARRAYBUTT(hwnd); if (!h) return FALSE; /* How many buttons? */ cButtons = GETNUMBUTTONS(hwnd); lpButton = (TOOLBUTTON far *)GlobalLock(h); /* Find that button, and change it's state */ for (i = 0; i < cButtons; i++, lpButton++) if (lpButton->iButton == iButton) { lpButton->iString = iString; fFound = TRUE; // redraw now break; } GlobalUnlock(h); return fFound; } /***************************************************************************/ /* toolbarModifyState: Given a button ID on the toolbar, change it's */ /* state. */ /* returns FALSE for an error or if no such button */ /***************************************************************************/ BOOL FAR PASCAL toolbarModifyState(HWND hwnd, int iButton, int iState) { HANDLE h; TOOLBUTTON far *lpButton; int cButtons, i; BOOL fFound = FALSE; /* Get the array of buttons */ h = GETARRAYBUTT(hwnd); if (!h) return FALSE; /* How many buttons? */ cButtons = GETNUMBUTTONS(hwnd); lpButton = (TOOLBUTTON far *)GlobalLock(h); /* Find that button, and change it's state */ for (i = 0; i < cButtons; i++, lpButton++) if (lpButton->iButton == iButton) { if (lpButton->iState != iState) { lpButton->iState = iState; InvalidateRect(hwnd, &(lpButton->rc), FALSE); } fFound = TRUE; // redraw now /* if we're pushing a radio button down, bring */ /* all others in its group up */ if (lpButton->iType >= BTNTYPE_RADIO && iState == BTNST_DOWN) toolbarExclusiveRadio(hwnd, lpButton->iType, iButton); break; } GlobalUnlock(h); return fFound; } /***************************************************************************/ /* toolbarModifyPrevState: Given a button on the toolbar, change it's prev-*/ /* ious state. Used for non-PUSH buttons to remember */ /* what state a button was in before pressed all the */ /* way down, so that when you let go, you know what */ /* state to set it to (the opposite of what it was). */ /* returns FALSE for an error (no button array) */ /***************************************************************************/ BOOL FAR PASCAL toolbarModifyPrevState(HWND hwnd, int iButton, int iPrevState) { HANDLE h; TOOLBUTTON far *lpButton; int cButtons, i; /* Get button array */ h = GETARRAYBUTT(hwnd); if (!h) return FALSE; /* How many buttons? */ cButtons = GETNUMBUTTONS(hwnd); lpButton = (TOOLBUTTON far *)GlobalLock(h); /* Find the button, change the state */ for (i = 0; i < cButtons; i++, lpButton++) if (lpButton->iButton == iButton) { lpButton->iPrevState = iPrevState; break; } GlobalUnlock(h); return TRUE; } /***************************************************************************/ /* toolbarModifyActivity: Given a button ID on the toolbar, change it's */ /* activity. This tells the app what just happened */ /* to the button (ie. KEYUP, MOUSEDBLCLK, etc.) */ /* returns FALSE for an error or if no such button */ /***************************************************************************/ BOOL FAR PASCAL toolbarModifyActivity(HWND hwnd, int iButton, int iActivity) { HANDLE h; TOOLBUTTON far *lpButton; int cButtons, i; /* Get the button array */ h = GETARRAYBUTT(hwnd); if (!h) return FALSE; /* How many buttons */ cButtons = GETNUMBUTTONS(hwnd); lpButton = (TOOLBUTTON far *)GlobalLock(h); /* loop through and change the right one */ for (i = 0; i < cButtons; i++, lpButton++) if (lpButton->iButton == iButton) { lpButton->iActivity = iActivity; break; } GlobalUnlock(h); return TRUE; } /***************************************************************************/ /* toolbarFixFocus: SETWHICH() has been called to tell us which button */ /* has the focus, but the states of all the buttons are */ /* not updated (ie. take focus away from the old button) */ /* This routine is called from the Paint routine to fix */ /* the states of all the buttons before drawing them. */ /* Returns FALSE for an error. */ /***************************************************************************/ BOOL FAR PASCAL toolbarFixFocus(HWND hwnd) { int iFocus; HANDLE h; TOOLBUTTON far *lpaButtons; /* Get the array of buttons */ h = GETARRAYBUTT(hwnd); if (!h) return FALSE; lpaButtons = (TOOLBUTTON far *)GlobalLock(h); /* if focus is on an illegal button, default to the first one */ iFocus = GETWHICH(hwnd); if (iFocus < 0 || iFocus >= GETNUMBUTTONS(hwnd)) SETWHICH(hwnd, 0); /* First of all, make sure that the focus in not on a grayed button. */ /* if so, we advance focus. If it runs out of buttons without */ /* finding a non-gray one, we start back at the beginning and start */ /* looking for a non-gray one from there. If every button is grayed,*/ /* we leave no focus anywhere. */ if (lpaButtons[GETWHICH(hwnd)].iState == BTNST_GRAYED) { if (!toolbarMoveFocus(hwnd, FALSE)) { SETWHICH(hwnd, -1); toolbarMoveFocus(hwnd, FALSE); } } GlobalUnlock(h); return TRUE; } /***************************************************************************/ /* toolbarExclusiveRadio: For radio buttons, we need to pop all others */ /* in the group up when one goes down. Pass the */ /* button that is going down, and its group, and */ /* this routine will pop all others up. */ /* Returns FALSE for an error. */ /***************************************************************************/ BOOL FAR PASCAL toolbarExclusiveRadio(HWND hwnd, int iType, int iButton) { int i; HANDLE h; TOOLBUTTON far *lpButton; /* Get the array of buttons */ h = GETARRAYBUTT(hwnd); if (!h) return FALSE; lpButton = (TOOLBUTTON far *)GlobalLock(h); /* all buttons with this type that aren't this button come up */ /* if they are not grayed */ for(i = 0; i < GETNUMBUTTONS(hwnd); i++, lpButton++) if (lpButton->iType == iType) if (lpButton->iButton != iButton && lpButton->iState != BTNST_GRAYED) { toolbarModifyState(hwnd, lpButton->iButton, BTNST_UP); } GlobalUnlock(h); return TRUE; } /* NotifyParent() of activity to a button */ static void NEAR PASCAL NotifyParent(HWND hwnd, int iButton) { #ifdef _WIN32 PostMessage( GetParent(hwnd), WM_COMMAND, GET_WM_COMMAND_MPS(GetWindowLong(hwnd, GWL_ID), hwnd, iButton)); #else PostMessage(GetParent(hwnd),WM_COMMAND, GetWindowWord(hwnd,GWW_ID),MAKELONG(hwnd,iButton)); #endif } /***************************************************************************/ /* toolbarPaintControl: Handles paint messages by blitting each bitmap */ /* that is on the toolbar to its rect. */ /* First, it fixes the states of the buttons to give */ /* the focus to the proper button. */ /* Returns FALSE for an error. */ /***************************************************************************/ static BOOL NEAR PASCAL toolbarPaintControl(HWND hwnd, HDC hdc) { int iBtnPos; /* 0 to toolbarGetNumButtons inclusive */ int iButton; /* 0 to NUMBUTTONS-1 inclusive */ int iState; /* 0 to NUMSTATES-1 inclusive */ HDC hdcBtn; /* DC onto button bitmap */ RECT rcDest; POINT pt; long l; HANDLE hbm; /* Make a source HDC for the button pictures, and select the button */ /* bitmap into it. */ hdcBtn = CreateCompatibleDC(hdc); if (!hdcBtn) return FALSE; hbm = GETBMPHANDLE(hwnd); if (hbm) { if (!SelectObject(hdcBtn, GETBMPHANDLE(hwnd))) { DeleteDC(hdcBtn); return FALSE; } } toolbarFixFocus(hwnd); // set the focus field correctly /* Go through all buttons on the toolbar */ for (iBtnPos = 0; iBtnPos < toolbarGetNumButtons(hwnd); iBtnPos++) { iButton = toolbarButtonFromIndex(hwnd, iBtnPos); // button iState = toolbarFullStateFromButton(hwnd, iButton); // state toolbarRectFromIndex(hwnd, iBtnPos, &rcDest); // Dest Rect /* If we have the focus, we should draw it that way */ if (GetFocus() == hwnd && GETWHICH(hwnd) == iBtnPos && iState == BTNST_UP) iState = BTNST_FOCUSUP; if (GetFocus() == hwnd && GETWHICH(hwnd) == iBtnPos && iState == BTNST_DOWN) iState = BTNST_FOCUSDOWN; /* If we don't have the focus, we should take it away */ if ((GetFocus() != hwnd || GETWHICH(hwnd) != iBtnPos) && iState == BTNST_FOCUSUP) iState = BTNST_UP; if ((GetFocus() != hwnd || GETWHICH(hwnd) == iBtnPos) && iState == BTNST_FOCUSDOWN) iState = BTNST_DOWN; /* The size of each button */ l = GETBUTTONSIZE(hwnd); pt.x = HIWORD(l); pt.y = LOWORD(l); /* Blit from the button picture to the toolbar window */ BitBlt(hdc, rcDest.left, rcDest.top, rcDest.right - rcDest.left, rcDest.bottom - rcDest.top, hdcBtn, pt.x * iButton, pt.y * iState, SRCCOPY); } DeleteDC(hdcBtn); return TRUE; } /***************************************************************************/ /* toolbarMoveFocus: Move Focus forward or backward one button. You give */ /* it the direction to move the focus. The routine will*/ /* stop at the end of the button list without wrapping */ /* around. */ /* Returns TRUE if focus moved, or FALSE if it ran out */ /* of buttons before finding a non-grayed one. */ /***************************************************************************/ BOOL FAR PASCAL toolbarMoveFocus(HWND hwnd, BOOL fBackward) { int iBtnPos, iButton, nOffset, nStopAt; RECT rc; int iPrevPos = GETWHICH(hwnd); /* Who used to have focus? */ /* Fix illegal value. It's OK to be one less or greater than range */ if (iPrevPos < -1 || iPrevPos > GETNUMBUTTONS(hwnd)) SETWHICH(hwnd, 0); // good a default as any if (fBackward) { nOffset = -1; nStopAt = -1; } else { nOffset = 1; nStopAt = GETNUMBUTTONS(hwnd); } /* look for next button that isn't grayed */ /* DON'T wrap around - future code will pass */ /* the focus to another window (???) */ for (iBtnPos = GETWHICH(hwnd) + nOffset; iBtnPos != nStopAt; iBtnPos += nOffset) { iButton = toolbarButtonFromIndex(hwnd, iBtnPos); if (toolbarStateFromButton(hwnd, iButton) != BTNST_GRAYED) { SETWHICH(hwnd, iBtnPos); // set focus /* Redraw both old and new focused button */ toolbarRectFromIndex(hwnd, iPrevPos, &rc); InvalidateRect(hwnd, &rc, FALSE); toolbarRectFromIndex(hwnd, iBtnPos, &rc); InvalidateRect(hwnd, &rc, FALSE); break; } } if (GETWHICH(hwnd) != iPrevPos) return TRUE; else return FALSE; } /***************************************************************************/ /* toolbarSetFocus : Set the focus in the toolbar to the specified button.*/ /* If it's gray, it'll set focus to next ungrayed btn. */ /* Returns TRUE if focus set, or FALSE if the button */ /* doesn't exist or if it and all buttons after it were */ /* grayed... You can use TB_FIRST or TB_LAST in */ /* place of a button ID. This uses the first or last */ /* un-grayed button. */ /***************************************************************************/ BOOL FAR PASCAL toolbarSetFocus(HWND hwnd, int iButton) { int iBtnPos; RECT rc = {0}; /* Don't move focus while a button is down */ if (GetCapture() != hwnd && !GETKEYPRESSED(hwnd)) { /* redraw button with focus in case focus moves */ toolbarRectFromIndex(hwnd, GETWHICH(hwnd), &rc); InvalidateRect(hwnd, &rc, FALSE); if (iButton == TB_FIRST) { SETWHICH(hwnd, -1); // move forward to 1st button return toolbarMoveFocus(hwnd, FALSE); } else if (iButton == TB_LAST) { SETWHICH(hwnd, GETNUMBUTTONS(hwnd)); return toolbarMoveFocus(hwnd, TRUE); } else { iBtnPos = toolbarIndexFromButton(hwnd, iButton); if (iBtnPos != -1) { SETWHICH(hwnd, --iBtnPos); return toolbarMoveFocus(hwnd, FALSE); } else return FALSE; } return TRUE; } else return FALSE; } // // LoadUIBitmap() - load a bitmap resource // // load a bitmap resource from a resource file, converting all // the standard UI colors to the current user specifed ones. // // this code is designed to load bitmaps used in "gray ui" or // "toolbar" code. // // the bitmap must be a 4bpp windows 3.0 DIB, with the standard // VGA 16 colors. // // the bitmap must be authored with the following colors // // Button Text Black (index 0) // Button Face lt gray (index 7) // Button Shadow gray (index 8) // Button Highlight white (index 15) // Window Color yellow (index 11) // Window Frame green (index 10) // // Example: // // hbm = LoadUIBitmap(hInstance, "TestBmp", // GetSysColor(COLOR_BTNTEXT), // GetSysColor(COLOR_BTNFACE), // GetSysColor(COLOR_BTNSHADOW), // GetSysColor(COLOR_BTNHIGHLIGHT), // GetSysColor(COLOR_WINDOW), // GetSysColor(COLOR_WINDOWFRAME)); // // Author: JimBov, ToddLa // // HBITMAP FAR PASCAL LoadUIBitmap( HANDLE hInstance, // EXE file to load resource from LPCSTR szName, // name of bitmap resource COLORREF rgbText, // color to use for "Button Text" COLORREF rgbFace, // color to use for "Button Face" COLORREF rgbShadow, // color to use for "Button Shadow" COLORREF rgbHighlight, // color to use for "Button Hilight" COLORREF rgbWindow, // color to use for "Window Color" COLORREF rgbFrame) // color to use for "Window Frame" { LPBYTE lpb; HBITMAP hbm = NULL; LPBITMAPINFOHEADER lpbi; HANDLE h; HDC hdc; LPDWORD lprgb; int isize; HANDLE hmem; LPBYTE lpCopy; // convert a RGB into a RGBQ #define RGBQ(dw) RGB(GetBValue(dw),GetGValue(dw),GetRValue(dw)) if ( !(h = LoadResource (hInstance,FindResource(hInstance, szName, RT_BITMAP)) ) ) return NULL; lpbi = (LPBITMAPINFOHEADER)LockResource(h); if (!lpbi) return(NULL); if (lpbi->biSize != sizeof(BITMAPINFOHEADER)) return NULL; if (lpbi->biBitCount != 4) return NULL; /* * copy the resource since they are now loaded read-only */ #ifdef _WIN32 isize = lpbi->biSize + lpbi->biSizeImage + ((int)lpbi->biClrUsed ? (int)lpbi->biClrUsed : (1 << (int)lpbi->biBitCount)) * sizeof(RGBQUAD); hmem = GlobalAlloc(GHND, isize); lpCopy = GlobalLock(hmem); if ((hmem == NULL) || (lpCopy == NULL)) { UnlockResource(h); FreeResource(h); return(NULL); } CopyMemory(lpCopy, lpbi, isize); lpbi = (LPBITMAPINFOHEADER)lpCopy; #endif /* Calcluate the pointer to the Bits information */ /* First skip over the header structure */ lprgb = (LPDWORD)((LPBYTE)(lpbi) + lpbi->biSize); /* Skip the color table entries, if any */ lpb = (LPBYTE)lprgb + ((int)lpbi->biClrUsed ? (int)lpbi->biClrUsed : (1 << (int)lpbi->biBitCount)) * sizeof(RGBQUAD); lprgb[0] = RGBQ(rgbText); // Black lprgb[7] = RGBQ(rgbFace); // lt gray lprgb[8] = RGBQ(rgbShadow); // gray lprgb[15] = RGBQ(rgbHighlight); // white lprgb[11] = RGBQ(rgbWindow); // yellow lprgb[10] = RGBQ(rgbFrame); // green if ( hdc = GetDC(NULL) ) { hbm = CreateDIBitmap (hdc, lpbi, CBM_INIT, (LPVOID)lpb, (LPBITMAPINFO)lpbi, DIB_RGB_COLORS); ReleaseDC(NULL, hdc); } UnlockResource(h); FreeResource(h); return(hbm); } /**************************************************************************** toolbarWndProc() Window proc for toolbar. Arguments: Standard window proc ****************************************************************************/ LRESULT FAR PASCAL toolbarWndProc(HWND hwnd, unsigned message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; POINT pt; RECT rc; int iBtnPos, iButton, ibmp; HANDLE lpaButtons, hbm, hInst; switch (message) { case WM_CREATE: // do all initialization /* What do these do? */ SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); SetWindowLong(hwnd,GWL_STYLE,lpCreate->style & 0xFFFF00FF); /* Alloc some space for the array of buttons on this bar */ lpaButtons = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, TOOLGROW * sizeof(TOOLBUTTON)); SETARRAYBUTT(hwnd, lpaButtons); // list of buttons on toolbar SETNUMBUTTONS(hwnd, 0); // # buttons in toolbar SETPRESSED(hwnd, FALSE); // mouse button being pressed? SETKEYPRESSED(hwnd, FALSE); // is a key being pressed? SETWHICH(hwnd, -1); // which button has the focus? SETSHIFTED(hwnd, FALSE); // shift-click or right-click? /* This wParam will be sent to the parent window to indentify */ /* that the toolbar sent the WM_COMMAND msg. The hwnd of the */ /* toolbar that sent the msg will be in the lParam. */ #ifdef _WIN32 SetWindowLong(hwnd, GWL_ID, IDC_TOOLBAR); #else SetWindowWord(hwnd, GWW_ID, (WORD)IDC_TOOLBAR); #endif /* later on, someone will set the bmp handle of the buttons */ SETBMPHANDLE(hwnd, NULL); break; case WM_LBUTTONDOWN: // button goes down on a toolbar button case WM_RBUTTONDOWN: case WM_LBUTTONDBLCLK: case WM_RBUTTONDBLCLK: /* If we don't give ourself focus, we'll never get KEYDOWN */ /* or KEYUP messages. */ /* Get the focus only if we're a TABSTOP and the app wants */ /* us to take focus. */ if ( (GetWindowLong(hwnd, GWL_STYLE) & WS_TABSTOP) && GetFocus() != hwnd) SetFocus(hwnd); /* ignore messages if window is disabled */ if (!IsWindowEnabled(hwnd)) return 0L; /* ignore multiple down messages (we set Capture here) */ /* also ignore if a key is down */ if (GetCapture() == hwnd || GETPRESSED(hwnd)) return 0L; /* Where did the mouse go down? */ pt.x = (short)LOWORD(lParam); pt.y = (short)HIWORD(lParam); /* which button was pressed? */ iBtnPos = toolbarIndexFromPoint(hwnd, pt); /* If it was a valid button... */ if (iBtnPos >= 0) { int iOldPos; int iState, iType, iButton; /* Everything you wanted to know about this button */ iType = toolbarTypeFromIndex(hwnd, iBtnPos); iButton = toolbarButtonFromIndex(hwnd, iBtnPos); iState = toolbarFullStateFromButton(hwnd, iButton); /* ignore downs on a grayed button, unless it's a */ /* custom button, then tell them anyway */ if (iType != BTNTYPE_CUSTOM && iState == BTNST_GRAYED) return 0; /* We better get all mouse messages from now on */ SetCapture(hwnd); /* Shift key or right button indicates a SHIFT down */ SETSHIFTED(hwnd, (message == WM_RBUTTONDOWN) || (wParam & MK_SHIFT)); /* Yes, we've pressed the button down */ SETPRESSED(hwnd, TRUE); /* Remember who used to have the focus, and we get it now */ iOldPos = GETWHICH(hwnd); SETWHICH(hwnd, iBtnPos); /* For a push button, send it down */ if (iType == BTNTYPE_PUSH) toolbarModifyState(hwnd, iButton, BTNST_DOWN); /* for a checkbox or radio button (of any group), */ /* remember what state it was in, and send it FULL down */ /* (with focus). */ if (iType == BTNTYPE_CHECKBOX || iType >= BTNTYPE_RADIO) { toolbarModifyPrevState(hwnd, iButton, iState); toolbarModifyState(hwnd,iButton,BTNST_FULLDOWN); } toolbarModifyActivity(hwnd, iButton, BTNACT_MOUSEDOWN); /* Set Double click flag appropriately */ if (message == WM_LBUTTONDBLCLK || message == WM_RBUTTONDBLCLK) NotifyParent(hwnd, (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) + BTN_DBLCLICK + iButton); else NotifyParent(hwnd, (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) + iButton); /* Invalidate the Rect of the button being pressed */ toolbarRectFromIndex(hwnd, iBtnPos, &rc); InvalidateRect(hwnd, &rc, FALSE); /* Invalidate the Rect of the button losing focus */ toolbarRectFromIndex(hwnd, iOldPos, &rc); InvalidateRect(hwnd, &rc, FALSE); /* Force re-paint now */ UpdateWindow(hwnd); /* Set a timer for repeated mouse downs */ SetTimer(hwnd, TIMER_BUTTONREPEAT, MSEC_BUTTONREPEAT, NULL); } return 0L; case WM_MOUSEMOVE: #if 0 /* This should be impossible - it means that the system lost */ /* a mouse up (maybe codeview is up?) We need to force a */ /* mouse up at this point. */ if (GetCapture() == hwnd && (wParam & (MK_LBUTTON | MK_RBUTTON) == 0)) SendMessage(hwnd, WM_LBUTTONUP, 0, lParam); #endif /* Mouse moving while pressing a button? If not, ignore. */ if (GetCapture() == hwnd) { int iPrevState, iState, iButton, iType; BOOL fPressed; /* Which button is being pressed down? */ iBtnPos = GETWHICH(hwnd); /* Where is mouse cursor now? */ pt.x = (short)LOWORD(lParam); pt.y = (short)HIWORD(lParam); /* where is button being pressed? Are we still on */ /* top of that button or have we moved? */ toolbarRectFromIndex(hwnd, iBtnPos, &rc); fPressed = PtInRect(&rc, pt); /* Let go if we move off of the button, but don't */ /* act like it was pressed. */ /* Also, push it back down if we move back on top */ /* of it (while the mouse button is STILL down). */ if (fPressed != GETPRESSED(hwnd)) { /* update: is this button pressed anymore? */ SETPRESSED(hwnd, fPressed); iType = toolbarTypeFromIndex(hwnd, iBtnPos); iButton = toolbarButtonFromIndex(hwnd, iBtnPos); iState = toolbarFullStateFromButton(hwnd, iButton); /* The mouse moved back onto the button while */ /* the mouse button was still pressed. */ if (fPressed) { /* Push the push button back down again */ if (iType == BTNTYPE_PUSH) toolbarModifyState(hwnd, iButton, BTNST_DOWN); /* Push the radio or checkbox button ALL the */ /* way down again. */ if (iType >= BTNTYPE_RADIO || iType == BTNTYPE_CHECKBOX) toolbarModifyState(hwnd, iButton, BTNST_FULLDOWN); toolbarModifyActivity(hwnd, iButton, BTNACT_MOUSEMOVEON); NotifyParent(hwnd, (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) + iButton); /* We moved the mouse off of the toolbar button */ /* while still holding the mouse button down. */ } else { /* lift the push button up */ if (iType == BTNTYPE_PUSH) toolbarModifyState(hwnd, iButton, BTNST_UP); /* Restore radio button or checkbox button to */ /* where it was before pressed */ if (iType >= BTNTYPE_RADIO || iType == BTNTYPE_CHECKBOX) { iPrevState = toolbarPrevStateFromButton(hwnd, iButton); toolbarModifyState(hwnd, iButton, iPrevState); } toolbarModifyActivity(hwnd, iButton, BTNACT_MOUSEMOVEOFF); NotifyParent(hwnd, (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) + toolbarButtonFromIndex(hwnd, iBtnPos)); } } } return 0L; case WM_LBUTTONUP: case WM_RBUTTONUP: /* If we don't have capture, we aren't expecting this. Ignore */ if (GetCapture() == hwnd) { int iPrevState, iState, iButton, iType; /* Who has the focus? */ iBtnPos = GETWHICH(hwnd); /* Release the mouse */ ReleaseCapture(); /* No more repeats of the mouse button downs */ KillTimer(hwnd, TIMER_BUTTONREPEAT); /* Everything you wanted to know about the button */ toolbarRectFromIndex(hwnd, iBtnPos, &rc); iType = toolbarTypeFromIndex(hwnd, iBtnPos); iButton = toolbarButtonFromIndex(hwnd, iBtnPos); iState = toolbarFullStateFromButton(hwnd, iButton); /* Don't do anything if we've moved off the button */ if (GETPRESSED(hwnd)) { /* No longer down */ SETPRESSED(hwnd, FALSE); /* Bring the push button up */ if (iType == BTNTYPE_PUSH) toolbarModifyState(hwnd, iButton, BTNST_UP); /* Bring the checkbox to the opposite state it was in */ if (iType == BTNTYPE_CHECKBOX) { iPrevState = toolbarPrevStateFromButton(hwnd, iButton); if (iPrevState == BTNST_DOWN) toolbarModifyState(hwnd, iButton, BTNST_UP); if (iPrevState == BTNST_UP) toolbarModifyState(hwnd, iButton, BTNST_DOWN); } /* Force a radio button down, and bring all */ /* other radio buttons of this type up */ if (iType >= BTNTYPE_RADIO) { toolbarModifyState(hwnd, iButton, BTNST_DOWN); toolbarExclusiveRadio(hwnd, iType, iButton); } /* Notify the parent that the mouse button came up */ /* on this button so the app can do something. */ /* Every button should notify the app, not just a */ /* custom button. */ toolbarModifyActivity(hwnd, iButton, BTNACT_MOUSEUP); NotifyParent(hwnd, (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) + iButton); } } return 0L; case WM_TIMER: /* If we have a tool button down, send a repeat message */ if (GETPRESSED(hwnd)) { int iButton, iType; iBtnPos = GETWHICH(hwnd); iButton = toolbarButtonFromIndex(hwnd, iBtnPos); iType = toolbarTypeFromIndex(hwnd, iBtnPos); NotifyParent(hwnd, BTN_REPEAT + (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) + toolbarButtonFromIndex(hwnd, iBtnPos)); } break; case WM_DESTROY: if (GETBMPHANDLE(hwnd)) DeleteObject(GETBMPHANDLE(hwnd)); SETBMPHANDLE(hwnd, NULL); if (GETARRAYBUTT(hwnd)) GlobalFree(GETARRAYBUTT(hwnd)); SETARRAYBUTT(hwnd, NULL); break; case WM_SETTEXT: break; /* MANY, MANY cases deleted */ case WM_SETFOCUS: // focus comes to toolbar window { /* Remember who had the focus and give it back. Of course, */ /* if by some wierdness that button is now grayed, give it */ /* to the next person in line. */ iBtnPos = GETWHICH(hwnd); if (iBtnPos < 0 || iBtnPos >= toolbarGetNumButtons(hwnd)) { iBtnPos = 0; SETWHICH(hwnd, 0); } do { iButton = toolbarButtonFromIndex(hwnd, iBtnPos); if (toolbarFullStateFromButton(hwnd, iButton) != BTNST_GRAYED) break; // give it here iBtnPos++; if (iBtnPos >= toolbarGetNumButtons(hwnd)) iBtnPos = 0; // wrap around if (iBtnPos == GETWHICH(hwnd)) return 0L; // uh-oh! They're all gray! } while (iBtnPos != GETWHICH(hwnd)); SETWHICH(hwnd, iBtnPos); // give focus here /* And redraw! */ toolbarRectFromIndex(hwnd, iBtnPos, &rc); InvalidateRect(hwnd, &rc, FALSE); UpdateWindow(hwnd); return 0; } case WM_KILLFOCUS: /* Send a KEYUP if one is pending */ if (GETKEYPRESSED(hwnd)) SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0L); /* Redraw the focused button, because now that focus is gone */ /* from our toolbar window, the focused button won't be */ /* focused anymore, although we remember which one it was. */ toolbarRectFromIndex(hwnd, GETWHICH(hwnd), &rc); InvalidateRect(hwnd, &rc, FALSE); UpdateWindow(hwnd); return 0; case WM_SYSKEYDOWN: /* Send a KEYUP if one is pending */ if (GETKEYPRESSED(hwnd)) SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0L); break; // MUST LET DEFWNDPROC RUN!!! (to handle the key) case WM_GETDLGCODE: return DLGC_WANTARROWS | DLGC_WANTTAB; case WM_KEYDOWN: /* Window disabled or a key is already down */ if (IsWindowEnabled(hwnd) && !GETPRESSED(hwnd)) { /* Tab forward to next button and move focus there */ if (wParam == VK_TAB && GetKeyState(VK_SHIFT) >= 0 ) { /* Move Focus forward one. If */ /* we've tabbed off of the toolbar, it's time */ /* to go on to the next control. We need to invldte */ /* because we might be the only control and we need */ /* to repaint to show the new button with highlight */ /* after it wrapped around the end of the toolbar. */ if (!toolbarMoveFocus(hwnd, FALSE)) { PostMessage(GetParent(hwnd), WM_NEXTDLGCTL, 0, 0L); toolbarRectFromIndex(hwnd, GETWHICH(hwnd), &rc); InvalidateRect(hwnd, &rc, FALSE); } return 0L; } if (wParam == VK_TAB && GetKeyState(VK_SHIFT) < 0 ) { /* Move focus backward one. If */ /* We've tabbed off of the toolbar, it's time */ /* to go on to the next control. We need to invldte */ /* because we might be the only control and we need */ /* to repaint to show the new button with highlight */ /* after it wrapped around the end of the toolbar. */ if (!toolbarMoveFocus(hwnd, TRUE)) { PostMessage(GetParent(hwnd), WM_NEXTDLGCTL, 1, 0L); toolbarRectFromIndex(hwnd, GETWHICH(hwnd), &rc); InvalidateRect(hwnd, &rc, FALSE); } return 0L; } if ((wParam == VK_SPACE) && (GetCapture() != hwnd)) { int iButton, iType, iState; /* Same as mouse button down -- Press the button! */ iBtnPos = GETWHICH(hwnd); iType = toolbarTypeFromIndex(hwnd, iBtnPos); iButton = toolbarButtonFromIndex(hwnd, iBtnPos); iState = toolbarFullStateFromButton(hwnd, iButton); /* ignore multiple key downs */ if (!GETKEYPRESSED(hwnd)) { SETKEYPRESSED(hwnd, TRUE); // a key is pressed SETSHIFTED(hwnd, FALSE); // NEVER shifted SETPRESSED(hwnd, TRUE); // a button is pressed /* Push button goes down - with focus */ if (iType == BTNTYPE_PUSH) toolbarModifyState(hwnd, iButton, BTNST_DOWN); /* Radio or checkbox button goes full down */ /* with focus - and remember previous state*/ if (iType >= BTNTYPE_RADIO || iType == BTNTYPE_CHECKBOX) { toolbarModifyPrevState(hwnd, iButton, iState); toolbarModifyState(hwnd, iButton, BTNST_FULLDOWN); } toolbarModifyActivity(hwnd, iButton, BTNACT_KEYDOWN); NotifyParent(hwnd, (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) + iButton); return 0L; } /* If this is another KEYDOWN msg, it's a REPEAT */ /* Notify parent. */ NotifyParent(hwnd, BTN_REPEAT + (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) + toolbarButtonFromIndex(hwnd, GETWHICH(hwnd))); } } break; case WM_KEYUP: /* A button was pressed and should come up now */ if ((wParam == VK_SPACE) && (GETKEYPRESSED(hwnd))) { int iButton, iState, iType, iPrevState; iBtnPos = GETWHICH(hwnd); // which button? SETKEYPRESSED(hwnd, FALSE); // let go SETPRESSED(hwnd, FALSE); /* Everything about this button */ toolbarRectFromIndex(hwnd, iBtnPos, &rc); iType = toolbarTypeFromIndex(hwnd, iBtnPos); iButton = toolbarButtonFromIndex(hwnd, iBtnPos); iState = toolbarFullStateFromButton(hwnd, iButton); /* Bring a push button up */ if (iType == BTNTYPE_PUSH) toolbarModifyState(hwnd, iButton, BTNST_UP); /* Bring a checkbox to the opposite state it was in */ if (iType == BTNTYPE_CHECKBOX) { iPrevState = toolbarPrevStateFromButton(hwnd, iButton); if (iPrevState == BTNST_DOWN) toolbarModifyState(hwnd, iButton, BTNST_UP); if (iPrevState == BTNST_UP) toolbarModifyState(hwnd, iButton, BTNST_DOWN); } /* Bring a radio button down, and bring all others in */ /* its group up. */ if (iType >= BTNTYPE_RADIO) { toolbarModifyState(hwnd, iButton, BTNST_DOWN); toolbarExclusiveRadio(hwnd, iType, iButton); } toolbarModifyActivity(hwnd, iButton, BTNACT_KEYUP); NotifyParent(hwnd, toolbarButtonFromIndex(hwnd, (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) + GETWHICH(hwnd))); } break; case WM_SYSCOLORCHANGE: /* load the bitmap of what all the buttons look like */ /* and change the colours to the system colours. */ hInst = GETHINST(hwnd); ibmp = GETBMPINT(hwnd); hbm = GETBMPHANDLE(hwnd); if (hbm) DeleteObject(hbm); hbm = LoadUIBitmap(hInst, MAKEINTRESOURCE(ibmp), GetSysColor(COLOR_BTNTEXT), GetSysColor(COLOR_BTNFACE), GetSysColor(COLOR_BTNSHADOW), GetSysColor(COLOR_BTNHIGHLIGHT), GetSysColor(COLOR_BTNFACE), GetSysColor(COLOR_WINDOWFRAME)); SETBMPHANDLE(hwnd, hbm); #ifdef _WIN32 return (LONG_PTR) hbm; #else return MAKELONG(hbm, 0); #endif case WM_ERASEBKGND: break; case WM_PAINT: /* Call our paint code */ BeginPaint(hwnd, &ps); toolbarPaintControl(hwnd, ps.hdc); EndPaint(hwnd, &ps); return 0L; } return DefWindowProc(hwnd, message, wParam, lParam); }