1738 lines
54 KiB
C
1738 lines
54 KiB
C
|
/**************************************************************************
|
||
|
*
|
||
|
* 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 <string.h>
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <windowsx.h>
|
||
|
//#include <win32.h>
|
||
|
#include "toolbar.h" // use this for generic app
|
||
|
/************************************************************************/
|
||
|
|
||
|
/* work for win3.0 */
|
||
|
#ifndef COLOR_BTNHIGHLIGHT
|
||
|
#define COLOR_BTNHIGHLIGHT 20
|
||
|
#endif
|
||
|
|
||
|
char szToolBarClass[] = "ToolBarClass";
|
||
|
HBRUSH ghbrToolbar; // brush for toolbar background
|
||
|
|
||
|
//
|
||
|
// Window proc for buttons, THIS FUNCTION MUST BE EXPORTED
|
||
|
//
|
||
|
LONG FAR PASCAL toolbarWndProc(HWND, unsigned, UINT, LONG);
|
||
|
|
||
|
typedef long (FAR PASCAL *LPWNDPROC)();
|
||
|
|
||
|
/*
|
||
|
Defines
|
||
|
*/
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
|
||
|
#define GETARRAYBUTT(hwnd) ((HANDLE)GetWindowLong(hwnd,GWL_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)GetWindowLong(hwnd,GWL_BMPHANDLE))
|
||
|
#define GETBMPINT(hwnd) ((int)GetWindowLong(hwnd,GWL_BMPINT))
|
||
|
#define GETBUTTONSIZE(hwnd) GetWindowLong(hwnd,GWL_BUTTONSIZE)
|
||
|
#define GETHINST(hwnd) ((HANDLE)GetWindowLong(hwnd,GWL_HINST))
|
||
|
|
||
|
|
||
|
#define SETARRAYBUTT(hwnd, h) SetWindowLong(hwnd, GWL_ARRAYBUTT, (UINT)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) SetWindowLong(hwnd, GWL_BMPHANDLE, (UINT)h)
|
||
|
#define SETBMPINT(hwnd, i) SetWindowLong(hwnd, GWL_BMPINT, (UINT)i)
|
||
|
#define SETBUTTONSIZE(hwnd, l) SetWindowLong(hwnd, GWL_BUTTONSIZE, l)
|
||
|
#define SETHINST(hwnd, h) SetWindowLong(hwnd, GWL_HINST, (UINT)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;
|
||
|
|
||
|
/* 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;
|
||
|
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))
|
||
|
|
||
|
h = LoadResource (hInstance,FindResource(hInstance, szName, RT_BITMAP));
|
||
|
|
||
|
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);
|
||
|
UnlockResource(h);
|
||
|
FreeResource(h);
|
||
|
|
||
|
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
|
||
|
|
||
|
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
|
||
|
****************************************************************************/
|
||
|
|
||
|
LONG FAR PASCAL toolbarWndProc(HWND hwnd, unsigned message,
|
||
|
UINT wParam, LONG 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) 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);
|
||
|
|
||
|
}
|