diff options
Diffstat (limited to 'win/tkWinButton.c')
-rw-r--r-- | win/tkWinButton.c | 937 |
1 files changed, 511 insertions, 426 deletions
diff --git a/win/tkWinButton.c b/win/tkWinButton.c index a002b9c..af1058d 100644 --- a/win/tkWinButton.c +++ b/win/tkWinButton.c @@ -19,9 +19,9 @@ */ #define LABEL_STYLE (BS_OWNERDRAW | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS) -#define PUSH_STYLE (BS_OWNERDRAW | BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS) -#define CHECK_STYLE (BS_OWNERDRAW | BS_CHECKBOX | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS) -#define RADIO_STYLE (BS_OWNERDRAW | BS_RADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS) +#define PUSH_STYLE (LABEL_STYLE | BS_PUSHBUTTON) +#define CHECK_STYLE (LABEL_STYLE | BS_CHECKBOX) +#define RADIO_STYLE (LABEL_STYLE | BS_RADIOBUTTON) /* * Declaration of Windows specific button structure. @@ -64,11 +64,11 @@ enum { */ typedef struct ThreadSpecificData { - BITMAPINFOHEADER *boxesPtr; /* Information about the bitmap. */ - DWORD *boxesPalette; /* Pointer to color palette. */ - LPSTR boxesBits; /* Pointer to bitmap data. */ - DWORD boxHeight; /* Height of each sub-image. */ - DWORD boxWidth ; /* Width of each sub-image. */ + BITMAPINFOHEADER *boxesPtr; /* Information about the bitmap. */ + DWORD *boxesPalette; /* Pointer to color palette. */ + LPSTR boxesBits; /* Pointer to bitmap data. */ + DWORD boxHeight; /* Height of each sub-image. */ + DWORD boxWidth; /* Width of each sub-image. */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; @@ -76,11 +76,11 @@ static Tcl_ThreadDataKey dataKey; * Declarations for functions defined in this file. */ -static LRESULT CALLBACK ButtonProc _ANSI_ARGS_((HWND hwnd, UINT message, - WPARAM wParam, LPARAM lParam)); -static Window CreateProc _ANSI_ARGS_((Tk_Window tkwin, - Window parent, ClientData instanceData)); -static void InitBoxes _ANSI_ARGS_((void)); +static LRESULT CALLBACK ButtonProc(HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam); +static Window CreateProc(Tk_Window tkwin, Window parent, + ClientData instanceData); +static void InitBoxes(void); /* * The class procedure table for the button widgets. @@ -90,6 +90,7 @@ Tk_ClassProcs tkpButtonProcs = { sizeof(Tk_ClassProcs), /* size */ TkButtonWorldChanged, /* worldChangedProc */ CreateProc, /* createProc */ + NULL }; @@ -98,13 +99,13 @@ Tk_ClassProcs tkpButtonProcs = { * * InitBoxes -- * - * This function load the Tk 3d button bitmap. "buttons" is a 16 - * color bitmap that is laid out such that the top row contains - * the 4 checkbox images, and the bottom row contains the radio - * button images. Note that the bitmap is stored in bottom-up - * format. Also, the first seven palette entries are used to - * identify the different parts of the bitmaps so we can do the - * appropriate color mappings based on the current button colors. + * This function load the Tk 3d button bitmap. "buttons" is a 16 color + * bitmap that is laid out such that the top row contains the 4 checkbox + * images, and the bottom row contains the radio button images. Note that + * the bitmap is stored in bottom-up format. Also, the first seven + * palette entries are used to identify the different parts of the + * bitmaps so we can do the appropriate color mappings based on the + * current button colors. * * Results: * None. @@ -116,7 +117,7 @@ Tk_ClassProcs tkpButtonProcs = { */ static void -InitBoxes() +InitBoxes(void) { /* * For DLLs like Tk, the HINSTANCE is the same as the HMODULE. @@ -127,11 +128,14 @@ InitBoxes() HGLOBAL hblk; LPBITMAPINFOHEADER newBitmap; DWORD size; - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); hrsrc = FindResource(module, "buttons", RT_BITMAP); - if (hrsrc) { + if (hrsrc == NULL) { + Tcl_Panic("FindResource() failed for buttons bitmap resource, " + "resources in tk_base.rc must be linked into Tk dll or static executable"); + } else { hblk = LoadResource(module, hrsrc); tsdPtr->boxesPtr = (LPBITMAPINFOHEADER)LockResource(hblk); } @@ -142,15 +146,15 @@ InitBoxes() if (tsdPtr->boxesPtr != NULL && !(tsdPtr->boxesPtr->biWidth % 4) && !(tsdPtr->boxesPtr->biHeight % 2)) { - size = tsdPtr->boxesPtr->biSize + (1 << tsdPtr->boxesPtr->biBitCount) - * sizeof(RGBQUAD) + tsdPtr->boxesPtr->biSizeImage; + size = tsdPtr->boxesPtr->biSize + (1 << tsdPtr->boxesPtr->biBitCount) + * sizeof(RGBQUAD) + tsdPtr->boxesPtr->biSizeImage; newBitmap = (LPBITMAPINFOHEADER) ckalloc(size); memcpy(newBitmap, tsdPtr->boxesPtr, size); tsdPtr->boxesPtr = newBitmap; tsdPtr->boxWidth = tsdPtr->boxesPtr->biWidth / 4; tsdPtr->boxHeight = tsdPtr->boxesPtr->biHeight / 2; - tsdPtr->boxesPalette = (DWORD*) (((LPSTR) tsdPtr->boxesPtr) - + tsdPtr->boxesPtr->biSize); + tsdPtr->boxesPalette = (DWORD*) (((LPSTR) tsdPtr->boxesPtr) + + tsdPtr->boxesPtr->biSize); tsdPtr->boxesBits = ((LPSTR) tsdPtr->boxesPalette) + ((1 << tsdPtr->boxesPtr->biBitCount) * sizeof(RGBQUAD)); } else { @@ -164,8 +168,8 @@ InitBoxes() * TkpButtonSetDefaults -- * * This procedure is invoked before option tables are created for - * buttons. It modifies some of the default values to match the - * current values defined for this platform. + * buttons. It modifies some of the default values to match the current + * values defined for this platform. * * Results: * Some of the default values in *specPtr are modified. @@ -177,8 +181,8 @@ InitBoxes() */ void -TkpButtonSetDefaults(specPtr) - Tk_OptionSpec *specPtr; /* Points to an array of option specs, +TkpButtonSetDefaults( + Tk_OptionSpec *specPtr) /* Points to an array of option specs, * terminated by one with type * TK_OPTION_END. */ { @@ -205,8 +209,8 @@ TkpButtonSetDefaults(specPtr) */ TkButton * -TkpCreateButton(tkwin) - Tk_Window tkwin; +TkpCreateButton( + Tk_Window tkwin) { WinButton *butPtr; @@ -220,8 +224,8 @@ TkpCreateButton(tkwin) * * CreateProc -- * - * This function creates a new Button control, subclasses - * the instance, and generates a new Window object. + * This function creates a new Button control, subclasses the instance, + * and generates a new Window object. * * Results: * Returns the newly allocated Window object, or None on failure. @@ -233,10 +237,10 @@ TkpCreateButton(tkwin) */ static Window -CreateProc(tkwin, parentWin, instanceData) - Tk_Window tkwin; /* Token for window. */ - Window parentWin; /* Parent of new window. */ - ClientData instanceData; /* Button instance data. */ +CreateProc( + Tk_Window tkwin, /* Token for window. */ + Window parentWin, /* Parent of new window. */ + ClientData instanceData) /* Button instance data. */ { Window window; HWND parent; @@ -256,13 +260,8 @@ CreateProc(tkwin, parentWin, instanceData) parent, NULL, Tk_GetHINSTANCE(), NULL); SetWindowPos(butPtr->hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); -#ifdef _WIN64 butPtr->oldProc = (WNDPROC)SetWindowLongPtr(butPtr->hwnd, GWLP_WNDPROC, - (LONG_PTR) ButtonProc); -#else - butPtr->oldProc = (WNDPROC)SetWindowLong(butPtr->hwnd, GWL_WNDPROC, - (DWORD) ButtonProc); -#endif + (INT_PTR) ButtonProc); window = Tk_AttachHWND(tkwin, butPtr->hwnd); return window; @@ -285,17 +284,14 @@ CreateProc(tkwin, parentWin, instanceData) */ void -TkpDestroyButton(butPtr) - TkButton *butPtr; +TkpDestroyButton( + TkButton *butPtr) { WinButton *winButPtr = (WinButton *)butPtr; HWND hwnd = winButPtr->hwnd; + if (hwnd) { -#ifdef _WIN64 - SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) winButPtr->oldProc); -#else - SetWindowLong(hwnd, GWL_WNDPROC, (DWORD) winButPtr->oldProc); -#endif + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (INT_PTR) winButPtr->oldProc); } } @@ -304,22 +300,21 @@ TkpDestroyButton(butPtr) * * TkpDisplayButton -- * - * This procedure is invoked to display a button widget. It is - * normally invoked as an idle handler. + * This procedure is invoked to display a button widget. It is normally + * invoked as an idle handler. * * Results: * None. * * Side effects: - * Information appears on the screen. The REDRAW_PENDING flag - * is cleared. + * Information appears on the screen. The REDRAW_PENDING flag is cleared. * *---------------------------------------------------------------------- */ void -TkpDisplayButton(clientData) - ClientData clientData; /* Information about widget. */ +TkpDisplayButton( + ClientData clientData) /* Information about widget. */ { TkWinDCState state; HDC dc; @@ -327,27 +322,28 @@ TkpDisplayButton(clientData) GC gc; Tk_3DBorder border; Pixmap pixmap; - int x = 0; /* Initialization only needed to stop - * compiler warning. */ + int x = 0; /* Initialization only needed to stop compiler + * warning. */ int y, relief; register Tk_Window tkwin = butPtr->tkwin; int width = 0, height = 0, haveImage = 0, haveText = 0, drawRing = 0; RECT rect; int defaultWidth; /* Width of default ring. */ - int offset; /* 0 means this is a label widget. 1 means - * it is a flavor of button, so we offset - * the text to make the button appear to - * move up and down as the relief changes. */ - int textXOffset = 0, textYOffset = 0; /* text offsets for use with - * compound buttons and focus ring */ + int offset; /* 0 means this is a label widget. 1 means it + * is a flavor of button, so we offset the + * text to make the button appear to move up + * and down as the relief changes. */ + int textXOffset = 0, textYOffset = 0; + /* Text offsets for use with compound buttons + * and focus ring. */ int imageWidth, imageHeight; - int imageXOffset = 0, imageYOffset = 0; /* image information that will - * be used to restrict disabled - * pixmap as well */ + int imageXOffset = 0, imageYOffset = 0; + /* Image information that will be used to + * restrict disabled pixmap as well. */ DWORD *boxesPalette; - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); boxesPalette= tsdPtr->boxesPalette; butPtr->flags &= ~REDRAW_PENDING; @@ -371,9 +367,8 @@ TkpDisplayButton(clientData) } /* - * Override the relief specified for the button if this is a - * checkbutton or radiobutton and there's no indicator. The new - * relief is as follows: + * Override the relief specified for the button if this is a checkbutton + * or radiobutton and there's no indicator. The new relief is as follows: * If the button is select --> "sunken" * If relief==overrelief --> relief * Otherwise --> overrelief @@ -387,15 +382,15 @@ TkpDisplayButton(clientData) * on no sunken * on yes sunken * - * This is accomplished by configuring the checkbutton or radiobutton - * like this: + * This is accomplished by configuring the checkbutton or radiobutton like + * this: * * -indicatoron 0 -overrelief raised -offrelief flat * * Bindings (see library/button.tcl) will copy the -overrelief into - * -relief on mouseover. Hence, we can tell if we are in mouse-over by - * comparing relief against overRelief. This is an aweful kludge, but - * it gives use the desired behavior while keeping the code backwards + * -relief on mouseover. Hence, we can tell if we are in mouse-over by + * comparing relief against overRelief. This is an aweful kludge, but it + * gives use the desired behavior while keeping the code backwards * compatible. */ @@ -426,10 +421,10 @@ TkpDisplayButton(clientData) } /* - * In order to avoid screen flashes, this procedure redraws - * the button in a pixmap, then copies the pixmap to the - * screen in a single operation. This means that there's no - * point in time where the on-sreen image has been cleared. + * In order to avoid screen flashes, this procedure redraws the button in + * a pixmap, then copies the pixmap to the screen in a single operation. + * This means that there's no point in time where the on-sreen image has + * been cleared. */ pixmap = Tk_GetPixmap(butPtr->display, Tk_WindowId(tkwin), @@ -448,7 +443,7 @@ TkpDisplayButton(clientData) Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height); haveImage = 1; } - imageWidth = width; + imageWidth = width; imageHeight = height; haveText = (butPtr->textWidth != 0 && butPtr->textHeight != 0); @@ -457,49 +452,58 @@ TkpDisplayButton(clientData) int fullWidth = 0, fullHeight = 0; switch ((enum compound) butPtr->compound) { - case COMPOUND_TOP: - case COMPOUND_BOTTOM: { - /* Image is above or below text */ - if (butPtr->compound == COMPOUND_TOP) { - textYOffset = height + butPtr->padY; - } else { - imageYOffset = butPtr->textHeight + butPtr->padY; - } - fullHeight = height + butPtr->textHeight + butPtr->padY; - fullWidth = (width > butPtr->textWidth ? width : - butPtr->textWidth); - textXOffset = (fullWidth - butPtr->textWidth)/2; - imageXOffset = (fullWidth - width)/2; - break; - } - case COMPOUND_LEFT: - case COMPOUND_RIGHT: { - /* Image is left or right of text */ - if (butPtr->compound == COMPOUND_LEFT) { - textXOffset = width + butPtr->padX; - } else { - imageXOffset = butPtr->textWidth + butPtr->padX; - } - fullWidth = butPtr->textWidth + butPtr->padX + width; - fullHeight = (height > butPtr->textHeight ? height : - butPtr->textHeight); - textYOffset = (fullHeight - butPtr->textHeight)/2; - imageYOffset = (fullHeight - height)/2; - break; + case COMPOUND_TOP: + case COMPOUND_BOTTOM: + /* + * Image is above or below text. + */ + + if (butPtr->compound == COMPOUND_TOP) { + textYOffset = height + butPtr->padY; + } else { + imageYOffset = butPtr->textHeight + butPtr->padY; } - case COMPOUND_CENTER: { - /* Image and text are superimposed */ - fullWidth = (width > butPtr->textWidth ? width : - butPtr->textWidth); - fullHeight = (height > butPtr->textHeight ? height : - butPtr->textHeight); - textXOffset = (fullWidth - butPtr->textWidth)/2; - imageXOffset = (fullWidth - width)/2; - textYOffset = (fullHeight - butPtr->textHeight)/2; - imageYOffset = (fullHeight - height)/2; - break; + fullHeight = height + butPtr->textHeight + butPtr->padY; + fullWidth = (width > butPtr->textWidth ? width : + butPtr->textWidth); + textXOffset = (fullWidth - butPtr->textWidth)/2; + imageXOffset = (fullWidth - width)/2; + break; + + case COMPOUND_LEFT: + case COMPOUND_RIGHT: + /* + * Image is left or right of text. + */ + + if (butPtr->compound == COMPOUND_LEFT) { + textXOffset = width + butPtr->padX; + } else { + imageXOffset = butPtr->textWidth + butPtr->padX; } - case COMPOUND_NONE: {break;} + fullWidth = butPtr->textWidth + butPtr->padX + width; + fullHeight = (height > butPtr->textHeight ? height : + butPtr->textHeight); + textYOffset = (fullHeight - butPtr->textHeight)/2; + imageYOffset = (fullHeight - height)/2; + break; + + case COMPOUND_CENTER: + /* + * Image and text are superimposed. + */ + + fullWidth = (width > butPtr->textWidth ? width : + butPtr->textWidth); + fullHeight = (height > butPtr->textHeight ? height : + butPtr->textHeight); + textXOffset = (fullWidth - butPtr->textWidth)/2; + imageXOffset = (fullWidth - width)/2; + textYOffset = (fullHeight - butPtr->textHeight)/2; + imageYOffset = (fullHeight - height)/2; + break; + case COMPOUND_NONE: + break; } TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY, butPtr->indicatorSpace + fullWidth, fullHeight, &x, &y); @@ -515,9 +519,13 @@ TkpDisplayButton(clientData) if ((butPtr->selectImage != NULL) && (butPtr->flags & SELECTED)) { Tk_RedrawImage(butPtr->selectImage, 0, 0, width, height, pixmap, imageXOffset, imageYOffset); - } else { - Tk_RedrawImage(butPtr->image, 0, 0, + } else if ((butPtr->tristateImage != NULL) + && (butPtr->flags & TRISTATED)) { + Tk_RedrawImage(butPtr->tristateImage, 0, 0, width, height, pixmap, imageXOffset, imageYOffset); + } else { + Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap, + imageXOffset, imageYOffset); } } else { XSetClipOrigin(butPtr->display, gc, imageXOffset, imageYOffset); @@ -526,6 +534,22 @@ TkpDisplayButton(clientData) imageXOffset, imageYOffset, 1); XSetClipOrigin(butPtr->display, gc, 0, 0); } + if ((butPtr->state == STATE_DISABLED) && + (butPtr->disabledFg != NULL)) { + COLORREF oldFgColor = gc->foreground; + + if (gc->background == GetSysColor(COLOR_BTNFACE)) { + gc->foreground = GetSysColor(COLOR_3DHILIGHT); + Tk_DrawTextLayout(butPtr->display, pixmap, gc, + butPtr->textLayout, x + textXOffset + 1, + y + textYOffset + 1, 0, -1); + Tk_UnderlineTextLayout(butPtr->display, pixmap, gc, + butPtr->textLayout, x + textXOffset + 1, + y + textYOffset + 1, + butPtr->underline); + gc->foreground = oldFgColor; + } + } Tk_DrawTextLayout(butPtr->display, pixmap, gc, butPtr->textLayout, x + textXOffset, y + textYOffset, 0, -1); @@ -539,7 +563,7 @@ TkpDisplayButton(clientData) TkComputeAnchor(butPtr->anchor, tkwin, 0, 0, butPtr->indicatorSpace + width, height, &x, &y); x += butPtr->indicatorSpace; - + if (relief == TK_RELIEF_SUNKEN) { x += offset; y += offset; @@ -551,6 +575,10 @@ TkpDisplayButton(clientData) (butPtr->flags & SELECTED)) { Tk_RedrawImage(butPtr->selectImage, 0, 0, width, height, pixmap, imageXOffset, imageYOffset); + } else if ((butPtr->tristateImage != NULL) && + (butPtr->flags & TRISTATED)) { + Tk_RedrawImage(butPtr->tristateImage, 0, 0, width, height, + pixmap, imageXOffset, imageYOffset); } else { Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap, imageXOffset, imageYOffset); @@ -567,11 +595,24 @@ TkpDisplayButton(clientData) butPtr->textHeight, &x, &y); x += butPtr->indicatorSpace; - + if (relief == TK_RELIEF_SUNKEN) { x += offset; y += offset; } + if ((butPtr->state == STATE_DISABLED) && + (butPtr->disabledFg != NULL)) { + COLORREF oldFgColor = gc->foreground; + if (gc->background == GetSysColor(COLOR_BTNFACE)) { + gc->foreground = GetSysColor(COLOR_3DHILIGHT); + Tk_DrawTextLayout(butPtr->display, pixmap, gc, + butPtr->textLayout, + x + 1, y + 1, 0, -1); + Tk_UnderlineTextLayout(butPtr->display, pixmap, gc, + butPtr->textLayout, x + 1, y + 1, butPtr->underline); + gc->foreground = oldFgColor; + } + } Tk_DrawTextLayout(butPtr->display, pixmap, gc, butPtr->textLayout, x, y, 0, -1); Tk_UnderlineTextLayout(butPtr->display, pixmap, gc, @@ -583,12 +624,12 @@ TkpDisplayButton(clientData) } /* - * Draw the focus ring. If this is a push button then we need to - * put it around the inner edge of the border, otherwise we put it - * around the text. The text offsets are only non-zero when this - * is a compound button. + * Draw the focus ring. If this is a push button then we need to put it + * around the inner edge of the border, otherwise we put it around the + * text. The text offsets are only non-zero when this is a compound + * button. */ - + if (drawRing && butPtr->flags & GOT_FOCUS && butPtr->type != TYPE_LABEL) { dc = TkWinGetDrawableDC(butPtr->display, pixmap, &state); if (butPtr->type == TYPE_BUTTON || !butPtr->indicatorOn) { @@ -609,11 +650,10 @@ TkpDisplayButton(clientData) } y += height/2; - + /* - * Draw the indicator for check buttons and radio buttons. At this - * point x and y refer to the top-left corner of the text or image - * or bitmap. + * Draw the indicator for check buttons and radio buttons. At this point x + * and y refer to the top-left corner of the text or image or bitmap. */ if ((butPtr->type >= TYPE_CHECK_BUTTON) && butPtr->indicatorOn @@ -623,7 +663,7 @@ TkpDisplayButton(clientData) x -= butPtr->indicatorSpace; y -= butPtr->indicatorDiameter / 2; - xSrc = (butPtr->flags & SELECTED) ? tsdPtr->boxWidth : 0; + xSrc = (butPtr->flags & (SELECTED|TRISTATED)) ? tsdPtr->boxWidth : 0; if (butPtr->state == STATE_ACTIVE) { xSrc += tsdPtr->boxWidth*2; } @@ -631,11 +671,11 @@ TkpDisplayButton(clientData) /* * Update the palette in the boxes bitmap to reflect the current - * button colors. Note that this code relies on the layout of the - * bitmap's palette. Also, all of the colors used to draw the - * bitmap must be in the palette that is selected into the DC of - * the offscreen pixmap. This requires that the static colors - * be placed into the palette. + * button colors. Note that this code relies on the layout of the + * bitmap's palette. Also, all of the colors used to draw the bitmap + * must be in the palette that is selected into the DC of the + * offscreen pixmap. This requires that the static colors be placed + * into the palette. */ if ((butPtr->state == STATE_DISABLED) @@ -653,7 +693,7 @@ TkpDisplayButton(clientData) border, TK_3D_LIGHT2)); boxesPalette[PAL_BOTTOM_OUTER] = FlipColor(TkWinGetBorderPixels(tkwin, border, TK_3D_LIGHT_GC)); - if (butPtr->state == STATE_DISABLED) { + if ((butPtr->state == STATE_DISABLED) || (butPtr->flags & TRISTATED)) { boxesPalette[PAL_INTERIOR] = FlipColor(TkWinGetBorderPixels(tkwin, border, TK_3D_LIGHT2)); } else if (butPtr->selectBorder != NULL) { @@ -666,18 +706,18 @@ TkpDisplayButton(clientData) border, TK_3D_FLAT_GC)); dc = TkWinGetDrawableDC(butPtr->display, pixmap, &state); - StretchDIBits(dc, x, y, tsdPtr->boxWidth, tsdPtr->boxHeight, - xSrc, ySrc, tsdPtr->boxWidth, tsdPtr->boxHeight, - tsdPtr->boxesBits, (LPBITMAPINFO) tsdPtr->boxesPtr, - DIB_RGB_COLORS, SRCCOPY); + StretchDIBits(dc, x, y, (int)tsdPtr->boxWidth, (int)tsdPtr->boxHeight, + xSrc, ySrc, (int)tsdPtr->boxWidth, (int)tsdPtr->boxHeight, + tsdPtr->boxesBits, (LPBITMAPINFO) tsdPtr->boxesPtr, + DIB_RGB_COLORS, SRCCOPY); TkWinReleaseDrawableDC(pixmap, dc, &state); } /* * If the button is disabled with a stipple rather than a special - * foreground color, generate the stippled effect. If the widget - * is selected and we use a different background color when selected, - * must temporarily modify the GC so the stippling is the right color. + * foreground color, generate the stippled effect. If the widget is + * selected and we use a different background color when selected, must + * temporarily modify the GC so the stippling is the right color. */ if ((butPtr->state == STATE_DISABLED) @@ -687,10 +727,12 @@ TkpDisplayButton(clientData) XSetForeground(butPtr->display, butPtr->stippleGC, Tk_3DBorderColor(butPtr->selectBorder)->pixel); } + /* - * Stipple the whole button if no disabledFg was specified, - * otherwise restrict stippling only to displayed image + * Stipple the whole button if no disabledFg was specified, otherwise + * restrict stippling only to displayed image */ + if (butPtr->disabledFg == NULL) { XFillRectangle(butPtr->display, pixmap, butPtr->stippleGC, 0, 0, (unsigned) Tk_Width(tkwin), (unsigned) Tk_Height(tkwin)); @@ -707,8 +749,8 @@ TkpDisplayButton(clientData) } /* - * Draw the border and traversal highlight last. This way, if the - * button's contents overflow they'll be covered up by the border. + * Draw the border and traversal highlight last. This way, if the button's + * contents overflow they'll be covered up by the border. */ if (relief != TK_RELIEF_FLAT) { @@ -721,15 +763,15 @@ TkpDisplayButton(clientData) if (defaultWidth != 0) { dc = TkWinGetDrawableDC(butPtr->display, pixmap, &state); TkWinFillRect(dc, 0, 0, Tk_Width(tkwin), defaultWidth, - butPtr->highlightColorPtr->pixel); + (int) butPtr->highlightColorPtr->pixel); TkWinFillRect(dc, 0, 0, defaultWidth, Tk_Height(tkwin), - butPtr->highlightColorPtr->pixel); + (int) butPtr->highlightColorPtr->pixel); TkWinFillRect(dc, 0, Tk_Height(tkwin) - defaultWidth, Tk_Width(tkwin), defaultWidth, - butPtr->highlightColorPtr->pixel); + (int) butPtr->highlightColorPtr->pixel); TkWinFillRect(dc, Tk_Width(tkwin) - defaultWidth, 0, defaultWidth, Tk_Height(tkwin), - butPtr->highlightColorPtr->pixel); + (int) butPtr->highlightColorPtr->pixel); TkWinReleaseDrawableDC(pixmap, dc, &state); } @@ -738,8 +780,8 @@ TkpDisplayButton(clientData) } /* - * Copy the information from the off-screen pixmap onto the screen, - * then delete the pixmap. + * Copy the information from the off-screen pixmap onto the screen, then + * delete the pixmap. */ XCopyArea(butPtr->display, pixmap, Tk_WindowId(tkwin), @@ -753,9 +795,9 @@ TkpDisplayButton(clientData) * * TkpComputeButtonGeometry -- * - * After changes in a button's text or bitmap, this procedure - * recomputes the button's geometry and passes this information - * along to the geometry manager for the window. + * After changes in a button's text or bitmap, this procedure recomputes + * the button's geometry and passes this information along to the + * geometry manager for the window. * * Results: * None. @@ -767,21 +809,21 @@ TkpDisplayButton(clientData) */ void -TkpComputeButtonGeometry(butPtr) - register TkButton *butPtr; /* Button whose geometry may have changed. */ +TkpComputeButtonGeometry( + register TkButton *butPtr) /* Button whose geometry may have changed. */ { - int txtWidth, txtHeight; /* Width and height of text */ - int imgWidth, imgHeight; /* Width and height of image */ - int width = 0, height = 0; /* Width and height of button */ + int txtWidth, txtHeight; /* Width and height of text */ + int imgWidth, imgHeight; /* Width and height of image */ + int width = 0, height = 0; /* Width and height of button */ int haveImage, haveText; int avgWidth; int minWidth; /* Vertical and horizontal dialog units size in pixels. */ double vDLU, hDLU; Tk_FontMetrics fm; - - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); if (butPtr->highlightWidth < 0) { butPtr->highlightWidth = 0; @@ -793,13 +835,16 @@ TkpComputeButtonGeometry(butPtr) InitBoxes(); } - /* Figure out image metrics */ + /* + * Figure out image metrics. + */ + if (butPtr->image != NULL) { Tk_SizeOfImage(butPtr->image, &imgWidth, &imgHeight); haveImage = 1; } else if (butPtr->bitmap != None) { Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, - &imgWidth, &imgHeight); + &imgWidth, &imgHeight); haveImage = 1; } else { imgWidth = 0; @@ -807,10 +852,11 @@ TkpComputeButtonGeometry(butPtr) haveImage = 0; } - /* + /* * Figure out font metrics (even if we don't have text because we need * DLUs (based on font, not text) for some spacing calculations below). */ + Tk_FreeTextLayout(butPtr->textLayout); butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont, Tcl_GetString(butPtr->textPtr), -1, butPtr->wrapLength, @@ -824,7 +870,10 @@ TkpComputeButtonGeometry(butPtr) 52) + 26) / 52; Tk_GetFontMetrics(butPtr->tkfont, &fm); - /* Compute dialog units for layout calculations. */ + /* + * Compute dialog units for layout calculations. + */ + hDLU = avgWidth / 4.0; vDLU = fm.linespace / 8.0; @@ -841,182 +890,199 @@ TkpComputeButtonGeometry(butPtr) /* * Set width and height by button type; See User Experience table, p449. - * These are text-based measurements, even if the text is "". - * If there is an image, height will get set again later. + * These are text-based measurements, even if the text is "". If there is + * an image, height will get set again later. */ + switch (butPtr->type) { - case TYPE_BUTTON: { - /* - * First compute the minimum width of the button in - * characters. MWUE says that the button should be - * 50 DLUs. We allow 6 DLUs padding left and right. - * (There is no rule but this is consistent with the - * fact that button text is 8 DLUs high and buttons - * are 14 DLUs high.) - * - * The width is specified in characters. A character - * is, by definition, 4 DLUs wide. 11 char * 4 DLU - * is 44 DLU + 6 DLU padding = 50 DLU. Therefore, - * width = -11 -> MWUE compliant buttons. - */ - if (butPtr->width < 0) { - /* Min width in characters */ - minWidth = -(butPtr->width); - /* Allow for characters */ - width = avgWidth * minWidth; - /* Add for padding */ - width += (int)(0.5 + (6 * hDLU)); - } + case TYPE_BUTTON: + /* + * First compute the minimum width of the button in characters. MWUE + * says that the button should be 50 DLUs. We allow 6 DLUs padding + * left and right. (There is no rule but this is consistent with the + * fact that button text is 8 DLUs high and buttons are 14 DLUs high.) + * + * The width is specified in characters. A character is, by + * definition, 4 DLUs wide. 11 char * 4 DLU is 44 DLU + 6 DLU padding + * = 50 DLU. Therefore, width = -11 -> MWUE compliant buttons. + */ - /* - * If shrink-wrapping was requested (width = 0) or - * if the text is wider than the default button width, - * adjust the button width up to suit. - */ - if (butPtr->width == 0 - || (txtWidth + (int)(0.5 + (6 * hDLU)) > width)) { - width = txtWidth + (int)(0.5 + (6 * hDLU)); - } + if (butPtr->width < 0) { + minWidth = -(butPtr->width); /* Min width in chars */ + width = avgWidth * minWidth; /* Allow for characters */ + width += (int)(0.5 + (6 * hDLU)); /* Add for padding */ + } + + /* + * If shrink-wrapping was requested (width = 0) or if the text is + * wider than the default button width, adjust the button width up to + * suit. + */ + + if (butPtr->width == 0 + || (txtWidth + (int)(0.5 + (6 * hDLU)) > width)) { + width = txtWidth + (int)(0.5 + (6 * hDLU)); + } + + /* + * The User Experience says 14 DLUs. Since text is, by definition, 8 + * DLU/line, this allows for multi-line text while working perfectly + * for single-line text. + */ + + height = txtHeight + (int)(0.5 + (6 * vDLU)); + /* + * The above includes 6 DLUs of padding which should include defaults + * of 1 pixel of highlightwidth, 2 pixels of borderwidth, 1 pixel of + * padding and 1 pixel of extra inset on each side. Those will be + * added later so reduce width and height now to compensate. + */ + + width -= 10; + height -= 10; + + if (!haveImage) { /* - * The User Experience says 14 DLUs. Since text is, by - * definition, 8 DLU/line, this allows for multi-line text - * while working perfectly for single-line text. + * Extra inset for the focus ring. */ - height = txtHeight + (int)(0.5 + (6 * vDLU)); + butPtr->inset += 1; + } + break; + + case TYPE_LABEL: + /* + * The User Experience says, "as wide as needed". + */ + + width = txtWidth; + + /* + * The User Experience says, "8 (DLUs) per line of text". Since text + * is, by definition, 8 DLU/line, this allows for multi-line text + * while working perfectly for single-line text. + */ + + if (txtHeight) { + height = txtHeight; + } else { /* - * The above includes 6 DLUs of padding which should include - * defaults of 1 pixel of highlightwidth, 2 pixels of - * borderwidth, 1 pixel of padding and 1 pixel of extra inset - * on each side. Those will be added later so reduce width - * and height now to compensate. + * If there's no text, we want the height to be one linespace. */ - width -= 10; - height -= 10; - - if (!haveImage) { - /* - * Extra inset for the focus ring. - */ - butPtr->inset += 1; - } - break; + height = fm.linespace; } + break; - case TYPE_LABEL: { - /* - * The User Experience says, "as wide as needed". - */ - width = txtWidth; - - /* - * The User Experience says, "8 (DLUs) per line of text." - * Since text is, by definition, 8 DLU/line, this allows - * for multi-line text while working perfectly for single-line - * text. - */ - if (txtHeight) { - height = txtHeight; - } else { - /* - * If there's no text, we want the height to be one linespace. - */ - height = fm.linespace; - } - break; - } - - case TYPE_RADIO_BUTTON: - case TYPE_CHECK_BUTTON: { - /* See note for TYPE_LABEL */ - width = txtWidth; - /* - * The User Experience says 10 DLUs. (Is that one DLU above - * and below for the focus ring?) See note above about - * multi-line text and 8 DLU/line. - */ - height = txtHeight + (int)(0.5 + (2.0 * vDLU)); - - /* - * The above includes 2 DLUs of padding which should include - * defaults of 1 pixel of highlightwidth, 0 pixels of - * borderwidth, and 1 pixel of padding on each side. Those - * will be added later so reduce height now to compensate. - */ - height -= 4; - - /* - * Extra inset for the focus ring. - */ - butPtr->inset += 1; - break; - } + case TYPE_RADIO_BUTTON: + case TYPE_CHECK_BUTTON: { + /* + * See note for TYPE_LABEL. + */ + + width = txtWidth; + + /* + * The User Experience says 10 DLUs. (Is that one DLU above and below + * for the focus ring?) See note above about multi-line text and 8 + * DLU/line. + */ + + height = txtHeight + (int)(0.5 + (2.0 * vDLU)); + + /* + * The above includes 2 DLUs of padding which should include defaults + * of 1 pixel of highlightwidth, 0 pixels of borderwidth, and 1 pixel + * of padding on each side. Those will be added later so reduce height + * now to compensate. + */ + + height -= 4; + + /* + * Extra inset for the focus ring. + */ + butPtr->inset += 1; + break; + } }/* switch */ /* - * At this point, the width and height are correct for a Tk text - * button, excluding padding and inset, but we have to allow for - * compound buttons. The image may be above, below, left, or right - * of the text. + * At this point, the width and height are correct for a Tk text button, + * excluding padding and inset, but we have to allow for compound buttons. + * The image may be above, below, left, or right of the text. */ /* - * If the button is compound (i.e., it shows both an image and text), - * the new geometry is a combination of the image and text geometry. - * We only honor the compound bit if the button has both text and an - * image, because otherwise it is not really a compound button. + * If the button is compound (i.e., it shows both an image and text), the + * new geometry is a combination of the image and text geometry. We only + * honor the compound bit if the button has both text and an image, + * because otherwise it is not really a compound button. */ + if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) { switch ((enum compound) butPtr->compound) { - case COMPOUND_TOP: - case COMPOUND_BOTTOM: { - /* Image is above or below text */ - if (imgWidth > width) { - width = imgWidth; - } - height += imgHeight + butPtr->padY; - break; + case COMPOUND_TOP: + case COMPOUND_BOTTOM: + /* + * Image is above or below text. + */ + + if (imgWidth > width) { + width = imgWidth; } - case COMPOUND_LEFT: - case COMPOUND_RIGHT: { - /* Image is left or right of text */ - /* - * Only increase width of button if image doesn't fit in - * slack space of default button width - */ - if ((imgWidth + txtWidth + butPtr->padX) > width) { - width = imgWidth + txtWidth + butPtr->padX; - } + height += imgHeight + butPtr->padY; + break; - if (imgHeight > height) { - height = imgHeight; - } - break; + case COMPOUND_LEFT: + case COMPOUND_RIGHT: + + /* + * Image is left or right of text. + * + * Only increase width of button if image doesn't fit in slack + * space of default button width + */ + + if ((imgWidth + txtWidth + butPtr->padX) > width) { + width = imgWidth + txtWidth + butPtr->padX; } - case COMPOUND_CENTER: { - /* Image and text are superimposed */ - if (imgWidth > width) { - width = imgWidth; - } - if (imgHeight > height) { - height = imgHeight; - } - break; + + if (imgHeight > height) { + height = imgHeight; } - case COMPOUND_NONE: { - break; + break; + + case COMPOUND_CENTER: + /* + * Image and text are superimposed. + */ + + if (imgWidth > width) { + width = imgWidth; } + if (imgHeight > height) { + height = imgHeight; + } + break; + case COMPOUND_NONE: + break; } /* switch */ - /* Fix up for minimum width */ - if (butPtr->width < 0) { - /* minWidth in pixels (because there's an image */ - minWidth = -(butPtr->width); - if (width < minWidth) { - width = minWidth; - } - } else if (butPtr->width > 0) { + /* + * Fix up for minimum width. + */ + + if (butPtr->width < 0) { + /* + * minWidth in pixels (because there's an image. + */ + + minWidth = -(butPtr->width); + if (width < minWidth) { + width = minWidth; + } + } else if (butPtr->width > 0) { width = butPtr->width; } @@ -1038,68 +1104,76 @@ TkpComputeButtonGeometry(butPtr) height = imgHeight; } } else { - /* No image. May or may not be text. May or may not be compound. */ + /* + * No image. May or may not be text. May or may not be compound. + */ - /* - * butPtr->width is in characters. We need to allow for that - * many characters on the face, not in the over-all button width + /* + * butPtr->width is in characters. We need to allow for that many + * characters on the face, not in the over-all button width */ - if (butPtr->width > 0) { + + if (butPtr->width > 0) { width = butPtr->width * avgWidth; } /* - * butPtr->height is in lines of text. We need to allow for - * that many lines on the face, not in the over-all button - * height. + * butPtr->height is in lines of text. We need to allow for that many + * lines on the face, not in the over-all button height. */ + if (butPtr->height > 0) { height = butPtr->height * fm.linespace; /* - * Make the same adjustments as above to get same height for - * e.g. a one line text with -height 0 or 1. [Bug #565485] + * Make the same adjustments as above to get same height for e.g. + * a one line text with -height 0 or 1. [Bug #565485] */ switch (butPtr->type) { - case TYPE_BUTTON: { - height += (int)(0.5 + (6 * vDLU)) - 10; - break; - } - case TYPE_RADIO_BUTTON: - case TYPE_CHECK_BUTTON: { - height += (int)(0.5 + (2.0 * vDLU)) - 4; - break; - } + case TYPE_BUTTON: { + height += (int)(0.5 + (6 * vDLU)) - 10; + break; + } + case TYPE_RADIO_BUTTON: + case TYPE_CHECK_BUTTON: { + height += (int)(0.5 + (2.0 * vDLU)) - 4; + break; + } } } - - width += 2 * butPtr->padX; + + width += 2 * butPtr->padX; height += 2 * butPtr->padY; } - /* Fix up width and height for indicator sizing and spacing */ + /* + * Fix up width and height for indicator sizing and spacing. + */ + if (butPtr->type == TYPE_RADIO_BUTTON || butPtr->type == TYPE_CHECK_BUTTON) { if (butPtr->indicatorOn) { butPtr->indicatorDiameter = tsdPtr->boxHeight; - /* - * Make sure we can see the whole indicator, even if the text - * or image is very small. - */ - if (height < butPtr->indicatorDiameter) { - height = butPtr->indicatorDiameter; - } + /* + * Make sure we can see the whole indicator, even if the text or + * image is very small. + */ + + if (height < butPtr->indicatorDiameter) { + height = butPtr->indicatorDiameter; + } /* - * There is no rule for space between the indicator and - * the text (the two are atomic on 'Windows) but the User - * Experience page 451 says leave 3 hDLUs between "text - * labels and their associated controls". + * There is no rule for space between the indicator and the text + * (the two are atomic on 'Windows) but the User Experience page + * 451 says leave 3 hDLUs between "text labels and their + * associated controls". */ + butPtr->indicatorSpace = butPtr->indicatorDiameter + - (int)(0.5 + (3.0 * hDLU)); + (int)(0.5 + (3.0 * hDLU)); width += butPtr->indicatorSpace; } } @@ -1107,7 +1181,8 @@ TkpComputeButtonGeometry(butPtr) /* * Inset is always added to the size. */ - width += 2 * butPtr->inset; + + width += 2 * butPtr->inset; height += 2 * butPtr->inset; Tk_GeometryRequest(butPtr->tkwin, width, height); @@ -1119,8 +1194,8 @@ TkpComputeButtonGeometry(butPtr) * * ButtonProc -- * - * This function is call by Windows whenever an event occurs on - * a button control created by Tk. + * This function is call by Windows whenever an event occurs on a button + * control created by Tk. * * Results: * Standard Windows return value. @@ -1132,86 +1207,96 @@ TkpComputeButtonGeometry(butPtr) */ static LRESULT CALLBACK -ButtonProc(hwnd, message, wParam, lParam) - HWND hwnd; - UINT message; - WPARAM wParam; - LPARAM lParam; +ButtonProc( + HWND hwnd, + UINT message, + WPARAM wParam, + LPARAM lParam) { LRESULT result; WinButton *butPtr; Tk_Window tkwin = Tk_HWNDToWindow(hwnd); if (tkwin == NULL) { - panic("ButtonProc called on an invalid HWND"); + Tcl_Panic("ButtonProc called on an invalid HWND"); } butPtr = (WinButton *)((TkWindow*)tkwin)->instanceData; switch(message) { - case WM_ERASEBKGND: - return 0; - - case BM_GETCHECK: - if (((butPtr->info.type == TYPE_CHECK_BUTTON) - || (butPtr->info.type == TYPE_RADIO_BUTTON)) - && butPtr->info.indicatorOn) { - return (butPtr->info.flags & SELECTED) - ? BST_CHECKED : BST_UNCHECKED; - } - return 0; - - case BM_GETSTATE: { - DWORD state = 0; - if (((butPtr->info.type == TYPE_CHECK_BUTTON) - || (butPtr->info.type == TYPE_RADIO_BUTTON)) - && butPtr->info.indicatorOn) { - state = (butPtr->info.flags & SELECTED) + case WM_ERASEBKGND: + return 0; + + case BM_GETCHECK: + if (((butPtr->info.type == TYPE_CHECK_BUTTON) + || (butPtr->info.type == TYPE_RADIO_BUTTON)) + && butPtr->info.indicatorOn) { + return (butPtr->info.flags & SELECTED) ? BST_CHECKED : BST_UNCHECKED; - } - if (butPtr->info.flags & GOT_FOCUS) { - state |= BST_FOCUS; - } - return state; } - case WM_ENABLE: - break; + return 0; - case WM_PAINT: { - PAINTSTRUCT ps; - BeginPaint(hwnd, &ps); - EndPaint(hwnd, &ps); - TkpDisplayButton((ClientData)butPtr); + case BM_GETSTATE: { + DWORD state = 0; - /* - * Special note: must cancel any existing idle handler - * for TkpDisplayButton; it's no longer needed, and - * TkpDisplayButton cleared the REDRAW_PENDING flag. - */ - - Tcl_CancelIdleCall(TkpDisplayButton, (ClientData)butPtr); - return 0; + if (((butPtr->info.type == TYPE_CHECK_BUTTON) + || (butPtr->info.type == TYPE_RADIO_BUTTON)) + && butPtr->info.indicatorOn) { + state = (butPtr->info.flags & SELECTED) + ? BST_CHECKED : BST_UNCHECKED; } - case BN_CLICKED: { - int code; - Tcl_Interp *interp = butPtr->info.interp; - if (butPtr->info.state != STATE_DISABLED) { - Tcl_Preserve((ClientData)interp); - code = TkInvokeButton((TkButton*)butPtr); - if (code != TCL_OK && code != TCL_CONTINUE - && code != TCL_BREAK) { - Tcl_AddErrorInfo(interp, "\n (button invoke)"); - Tcl_BackgroundError(interp); - } - Tcl_Release((ClientData)interp); - } - Tcl_ServiceAll(); - return 0; + if (butPtr->info.flags & GOT_FOCUS) { + state |= BST_FOCUS; } + return state; + } + case WM_ENABLE: + break; + + case WM_PAINT: { + PAINTSTRUCT ps; + BeginPaint(hwnd, &ps); + EndPaint(hwnd, &ps); + TkpDisplayButton((ClientData)butPtr); - default: - if (Tk_TranslateWinEvent(hwnd, message, wParam, lParam, &result)) { - return result; + /* + * Special note: must cancel any existing idle handler for + * TkpDisplayButton; it's no longer needed, and TkpDisplayButton + * cleared the REDRAW_PENDING flag. + */ + + Tcl_CancelIdleCall(TkpDisplayButton, (ClientData)butPtr); + return 0; + } + case BN_CLICKED: { + int code; + Tcl_Interp *interp = butPtr->info.interp; + + if (butPtr->info.state != STATE_DISABLED) { + Tcl_Preserve((ClientData)interp); + code = TkInvokeButton((TkButton*)butPtr); + if (code != TCL_OK && code != TCL_CONTINUE + && code != TCL_BREAK) { + Tcl_AddErrorInfo(interp, "\n (button invoke)"); + Tcl_BackgroundError(interp); } + Tcl_Release((ClientData)interp); + } + Tcl_ServiceAll(); + return 0; + } + + default: + if (Tk_TranslateWinEvent(hwnd, message, wParam, lParam, &result)) { + return result; + } } return DefWindowProc(hwnd, message, wParam, lParam); } + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ |