#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)
-static DWORD buttonStyles[] = {
- LABEL_STYLE, PUSH_STYLE, CHECK_STYLE, RADIO_STYLE
-};
-
/*
* Declaration of Windows specific button structure.
*/
WNDPROC oldProc; /* Old window procedure. */
HWND hwnd; /* Current window handle. */
Pixmap pixmap; /* Bitmap for rendering the button. */
- int pixFlags; /* Button flags for pixmap field. */
DWORD style; /* Window style flags. */
} WinButton;
/*
* Declarations for functions defined in this file.
*/
-
-static int ButtonBindProc _ANSI_ARGS_((ClientData clientData,
- Tcl_Interp *interp, XEvent *eventPtr,
- Tk_Window tkwin, KeySym keySym));
static LRESULT CALLBACK ButtonProc _ANSI_ARGS_((HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam));
-static DWORD ComputeStyle _ANSI_ARGS_((WinButton* butPtr));
static Window CreateProc _ANSI_ARGS_((Tk_Window tkwin,
Window parent, ClientData instanceData));
static void InitBoxes _ANSI_ARGS_((void));
-/* CYGNUS LOCAL. */
-static void TkpRealDisplayButton _ANSI_ARGS_((ClientData, int));
-
/*
* The class procedure table for the button widgets.
*/
-TkClassProcs tkpButtonProcs = {
- CreateProc, /* createProc. */
- TkButtonWorldChanged, /* geometryProc. */
- NULL /* modalProc. */
+Tk_ClassProcs tkpButtonProcs = {
+ sizeof(Tk_ClassProcs), /* size */
+ TkButtonWorldChanged, /* worldChangedProc */
+ CreateProc, /* createProc */
};
\f
butPtr = (WinButton *)ckalloc(sizeof(WinButton));
butPtr->hwnd = NULL;
- /* CYGNUS LOCAL: Use the pixmap field. */
- butPtr->pixmap = 0;
- butPtr->pixFlags = 0;
return (TkButton *) butPtr;
}
\f
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
window = Tk_AttachHWND(tkwin, butPtr->hwnd);
return window;
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);
- }
- /* CYGNUS LOCAL: Free the pixmap. */
- if (winButPtr->pixmap != 0) {
- Tk_FreePixmap(butPtr->display, winButPtr->pixmap);
- winButPtr->pixmap = 0;
+#endif
}
}
\f
TkpDisplayButton(clientData)
ClientData clientData; /* Information about widget. */
{
- /* CYGNUS LOCAL: Use a subroutine. */
- TkpRealDisplayButton(clientData, 1);
-}
-
-/* CYGNUS LOCAL: This is the old TkpDisplayButton, with a force
- argument added. The idea is to speed up redrawing a button due to
- a WM_PAINT event by saving a pixmap of the image. */
-
-static void
-TkpRealDisplayButton(clientData, force)
- ClientData clientData;
- int force;
-{
TkWinDCState state;
HDC dc;
register TkButton *butPtr = (TkButton *) clientData;
* compiler warning. */
int y, relief;
register Tk_Window tkwin = butPtr->tkwin;
- int width, height;
+ int width, height, 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 */
DWORD *boxesPalette;
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
return;
}
- /* CYGNUS LOCAL: Use the saved pixmap if we can. */
- if (! force && ((WinButton *)butPtr)->pixmap != 0
- && ((WinButton *)butPtr)->pixFlags == butPtr->flags) {
- XCopyArea(butPtr->display, ((WinButton *)butPtr)->pixmap,
- Tk_WindowId(tkwin), butPtr->copyGC, 0, 0,
- (unsigned) Tk_Width(tkwin), (unsigned) Tk_Height(tkwin),
- 0, 0);
- return;
- }
-
- if (((WinButton *)butPtr)->pixmap != 0) {
- Tk_FreePixmap(butPtr->display, ((WinButton*)butPtr)->pixmap);
- ((WinButton*)butPtr)->pixmap = 0;
- }
-
border = butPtr->normalBorder;
if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) {
gc = butPtr->disabledGC;
/*
* Override the relief specified for the button if this is a
- * checkbutton or radiobutton and there's no indicator.
+ * 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
+ *
+ * The effect we are trying to achieve is as follows:
+ *
+ * value mouse-over? --> relief
+ * ------- ------------ --------
+ * off no flat
+ * off yes raised
+ * on no sunken
+ * on yes sunken
+ *
+ * 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
+ * compatible.
*/
relief = butPtr->relief;
if ((butPtr->type >= TYPE_CHECK_BUTTON) && !butPtr->indicatorOn) {
- relief = (butPtr->flags & SELECTED) ? TK_RELIEF_SUNKEN
- : TK_RELIEF_RAISED;
+ if (butPtr->flags & SELECTED) {
+ relief = TK_RELIEF_SUNKEN;
+ } else if (butPtr->overRelief != relief) {
+ relief = butPtr->offRelief;
+ }
}
/*
if (butPtr->image != None) {
Tk_SizeOfImage(butPtr->image, &width, &height);
+ haveImage = 1;
+ } else if (butPtr->bitmap != None) {
+ Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
+ haveImage = 1;
+ }
- imageOrBitmap:
- TkComputeAnchor(butPtr->anchor, tkwin, 0, 0,
- butPtr->indicatorSpace + width, height, &x, &y);
+ haveText = (butPtr->textWidth != 0 && butPtr->textHeight != 0);
+
+ if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) {
+ int imageXOffset, imageYOffset, fullWidth,
+ fullHeight;
+ imageXOffset = 0;
+ imageYOffset = 0;
+ 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_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);
x += butPtr->indicatorSpace;
if (relief == TK_RELIEF_SUNKEN) {
x += offset;
y += offset;
}
+
if (butPtr->image != NULL) {
if ((butPtr->selectImage != NULL) && (butPtr->flags & SELECTED)) {
- Tk_RedrawImage(butPtr->selectImage, 0, 0, width, height,
- pixmap, x, y);
+ Tk_RedrawImage(butPtr->selectImage, 0, 0,
+ width, height, pixmap, x + imageXOffset,
+ y + imageYOffset);
} else {
- Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap,
- x, y);
+ Tk_RedrawImage(butPtr->image, 0, 0, width,
+ height, pixmap, x + imageXOffset, y + imageYOffset);
}
} else {
- XSetClipOrigin(butPtr->display, gc, x, y);
- XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, gc, 0, 0,
- (unsigned int) width, (unsigned int) height, x, y, 1);
+ XSetClipOrigin(butPtr->display, gc, x + imageXOffset,
+ y + imageYOffset);
+ XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, gc,
+ 0, 0, (unsigned int) width,
+ (unsigned int) height, x + imageXOffset,
+ y + imageYOffset, 1);
XSetClipOrigin(butPtr->display, gc, 0, 0);
}
- y += height/2;
- } else if (butPtr->bitmap != None) {
- Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
- goto imageOrBitmap;
- } else {
- RECT rect;
- TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY,
- butPtr->indicatorSpace + butPtr->textWidth, butPtr->textHeight,
- &x, &y);
-
- x += butPtr->indicatorSpace;
-
- if (relief == TK_RELIEF_SUNKEN) {
- x += offset;
- y += offset;
- }
+
Tk_DrawTextLayout(butPtr->display, pixmap, gc, butPtr->textLayout,
- x, y, 0, -1);
+ x + textXOffset, y + textYOffset, 0, -1);
Tk_UnderlineTextLayout(butPtr->display, pixmap, gc,
- butPtr->textLayout, x, y, butPtr->underline);
-
- /*
- * 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.
- */
-
- if (butPtr->flags & GOT_FOCUS && butPtr->type != TYPE_LABEL) {
- dc = TkWinGetDrawableDC(butPtr->display, pixmap, &state);
- if (butPtr->type == TYPE_BUTTON || !butPtr->indicatorOn) {
- rect.top = butPtr->borderWidth + 1 + defaultWidth;
- rect.left = rect.top;
- rect.right = Tk_Width(tkwin) - rect.left;
- rect.bottom = Tk_Height(tkwin) - rect.top;
+ butPtr->textLayout, x + textXOffset, y + textYOffset,
+ butPtr->underline);
+ height = fullHeight;
+ drawRing = 1;
+ } else {
+ if (haveImage) {
+ TkComputeAnchor(butPtr->anchor, tkwin, 0, 0,
+ butPtr->indicatorSpace + width, height, &x, &y);
+ x += butPtr->indicatorSpace;
+
+ if (relief == TK_RELIEF_SUNKEN) {
+ x += offset;
+ y += offset;
+ }
+ if (butPtr->image != NULL) {
+ if ((butPtr->selectImage != NULL) &&
+ (butPtr->flags & SELECTED)) {
+ Tk_RedrawImage(butPtr->selectImage, 0, 0, width, height,
+ pixmap, x, y);
+ } else {
+ Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap,
+ x, y);
+ }
} else {
- rect.top = y-2;
- rect.left = x-2;
- rect.right = x+butPtr->textWidth + 1;
- rect.bottom = y+butPtr->textHeight + 1;
+ XSetClipOrigin(butPtr->display, gc, x, y);
+ XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, gc, 0, 0,
+ (unsigned int) width, (unsigned int) height, x, y, 1);
+ XSetClipOrigin(butPtr->display, gc, 0, 0);
}
- SetTextColor(dc, gc->foreground);
- SetBkColor(dc, gc->background);
- DrawFocusRect(dc, &rect);
- TkWinReleaseDrawableDC(pixmap, dc, &state);
+
+ } else {
+ TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY,
+ butPtr->indicatorSpace + butPtr->textWidth,
+ butPtr->textHeight, &x, &y);
+
+ x += butPtr->indicatorSpace;
+
+ if (relief == TK_RELIEF_SUNKEN) {
+ x += offset;
+ y += offset;
+ }
+ Tk_DrawTextLayout(butPtr->display, pixmap, gc, butPtr->textLayout,
+ x, y, 0, -1);
+ Tk_UnderlineTextLayout(butPtr->display, pixmap, gc,
+ butPtr->textLayout, x, y, butPtr->underline);
+
+ height = butPtr->textHeight;
+ drawRing = 1;
+ }
+ }
+
+ /*
+ * 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) {
+ rect.top = butPtr->borderWidth + 1 + defaultWidth;
+ rect.left = rect.top;
+ rect.right = Tk_Width(tkwin) - rect.left;
+ rect.bottom = Tk_Height(tkwin) - rect.top;
+ } else {
+ rect.top = y-1 + textYOffset;
+ rect.left = x-1 + textXOffset;
+ rect.right = x+butPtr->textWidth + 1 + textXOffset;
+ rect.bottom = y+butPtr->textHeight + 2 + textYOffset;
}
- y += butPtr->textHeight/2;
+ SetTextColor(dc, gc->foreground);
+ SetBkColor(dc, gc->background);
+ DrawFocusRect(dc, &rect);
+ TkWinReleaseDrawableDC(pixmap, dc, &state);
}
+ 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
TkWinReleaseDrawableDC(pixmap, dc, &state);
}
+ if (butPtr->flags & GOT_FOCUS) {
+ Tk_SetCaretPos(tkwin, x, y, 0 /* not used */);
+ }
+
/*
* Copy the information from the off-screen pixmap onto the screen,
* then delete the pixmap.
XCopyArea(butPtr->display, pixmap, Tk_WindowId(tkwin),
butPtr->copyGC, 0, 0, (unsigned) Tk_Width(tkwin),
(unsigned) Tk_Height(tkwin), 0, 0);
-
- /* CYGNUS LOCAL: Don't free the pixmap; save it for the next
- redisplay.
- Tk_FreePixmap(butPtr->display, pixmap);
- */
- ((WinButton*)butPtr)->pixmap = pixmap;
- ((WinButton*)butPtr)->pixFlags = butPtr->flags;
+ Tk_FreePixmap(butPtr->display, pixmap);
}
\f
/*
TkpComputeButtonGeometry(butPtr)
register TkButton *butPtr; /* Button whose geometry may have changed. */
{
- int width, height, avgWidth;
+ 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));
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
if (butPtr->highlightWidth < 0) {
butPtr->highlightWidth = 0;
InitBoxes();
}
+ /* Figure out image metrics */
if (butPtr->image != NULL) {
- Tk_SizeOfImage(butPtr->image, &width, &height);
- imageOrBitmap:
- if (butPtr->width > 0) {
+ Tk_SizeOfImage(butPtr->image, &imgWidth, &imgHeight);
+ haveImage = 1;
+ } else if (butPtr->bitmap != None) {
+ Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap,
+ &imgWidth, &imgHeight);
+ haveImage = 1;
+ } else {
+ imgWidth = 0;
+ imgHeight = 0;
+ 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,
+ butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight);
+
+ txtWidth = butPtr->textWidth;
+ txtHeight = butPtr->textHeight;
+ haveText = (*(Tcl_GetString(butPtr->textPtr)) != '\0');
+ avgWidth = (Tk_TextWidth(butPtr->tkfont,
+ "abcdefghijklmnopqurstuvwzyABCDEFGHIJKLMNOPQURSTUVWZY",
+ 52) + 26) / 52;
+ Tk_GetFontMetrics(butPtr->tkfont, &fm);
+
+ /* Compute dialog units for layout calculations. */
+ hDLU = avgWidth / 4.0;
+ vDLU = fm.linespace / 8.0;
+
+ /*
+ * First, let's try to compute button size "by the book" (See "Microsoft
+ * Windows User Experience" (ISBN 0-7356-0566-1), Chapter 14 - Visual
+ * Design, Section 4 - Layout (page 448)).
+ *
+ * Note, that Tk "buttons" are Microsoft "Command buttons", Tk
+ * "checkbuttons" are Microsoft "check boxes", Tk "radiobuttons" are
+ * Microsoft "option buttons", and Tk "labels" are Microsoft "text
+ * labels".
+ */
+
+ /*
+ * 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.
+ */
+ 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));
+ }
+
+ /*
+ * 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) {
+ /*
+ * Extra inset for the focus ring.
+ */
+ 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 {
+ /*
+ * 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;
+ }
+ }/* 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.
+ */
+
+ /*
+ * 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_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;
+ }
+
+ if (imgHeight > height) {
+ height = imgHeight;
+ }
+ break;
+ }
+ case COMPOUND_CENTER: {
+ /* Image and text are superimposed */
+ if (imgWidth > width) {
+ width = imgWidth;
+ }
+ if (imgHeight > height) {
+ height = imgHeight;
+ }
+ 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) {
width = butPtr->width;
}
+
if (butPtr->height > 0) {
height = butPtr->height;
}
- if ((butPtr->type >= TYPE_CHECK_BUTTON) && butPtr->indicatorOn) {
- butPtr->indicatorSpace = tsdPtr->boxWidth * 2;
- butPtr->indicatorDiameter = tsdPtr->boxHeight;
+
+ width += 2*butPtr->padX;
+ height += 2*butPtr->padY;
+ } else if (haveImage) {
+ if (butPtr->width > 0) {
+ width = butPtr->width;
+ } else {
+ width = imgWidth;
+ }
+ if (butPtr->height > 0) {
+ height = butPtr->height;
+ } else {
+ height = imgHeight;
}
- } else if (butPtr->bitmap != None) {
- Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
- goto imageOrBitmap;
} else {
- Tk_FreeTextLayout(butPtr->textLayout);
- butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont,
- Tcl_GetString(butPtr->textPtr), -1, butPtr->wrapLength,
- butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight);
-
- width = butPtr->textWidth;
- height = butPtr->textHeight;
- avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1);
- Tk_GetFontMetrics(butPtr->tkfont, &fm);
+ /* No image. May or may not be text. May or may not be compound. */
- if (butPtr->width > 0) {
+ /*
+ * 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) {
width = butPtr->width * avgWidth;
}
- if (butPtr->type == TYPE_BUTTON) {
- height = butPtr->height * fm.ascent;
- } else if (butPtr->height > 0) {
+ /*
+ * 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]
+ */
+
+ 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;
+ }
+ }
}
+
+ width += 2 * butPtr->padX;
+ height += 2 * butPtr->padY;
+ }
- if ((butPtr->type >= TYPE_CHECK_BUTTON) && butPtr->indicatorOn) {
+ /* 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;
- butPtr->indicatorSpace = butPtr->indicatorDiameter + avgWidth;
- }
- /*
- * Increase the inset to allow for the focus ring.
- */
+ /*
+ * Make sure we can see the whole indicator, even if the text
+ * or image is very small.
+ */
+ if (height < butPtr->indicatorDiameter) {
+ height = butPtr->indicatorDiameter;
+ }
- if (butPtr->type != TYPE_LABEL) {
- butPtr->inset += 3;
+ /*
+ * 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));
+ width += butPtr->indicatorSpace;
}
}
/*
- * When issuing the geometry request, add extra space for the indicator,
- * if any, and for the border and padding, plus an extra pixel so the
- * display can be offset by 1 pixel in either direction for the raised
- * or lowered effect.
+ * Inset is always added to the size.
*/
+ width += 2 * butPtr->inset;
+ height += 2 * butPtr->inset;
- if ((butPtr->image == NULL) && (butPtr->bitmap == None)) {
- width += 2*butPtr->padX;
- height += 2*butPtr->padY;
- }
- if ((butPtr->type == TYPE_BUTTON)
- || ((butPtr->type >= TYPE_CHECK_BUTTON) && !butPtr->indicatorOn)) {
- width += 1;
- height += 1;
- }
- Tk_GeometryRequest(butPtr->tkwin, (int) (width + butPtr->indicatorSpace
- + 2*butPtr->inset), (int) (height + 2*butPtr->inset));
+ Tk_GeometryRequest(butPtr->tkwin, width, height);
Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset);
-
- /* CYGNUS LOCAL: Discard any saved pixmap. */
- if (((WinButton*)butPtr)->pixmap != 0) {
- Tk_FreePixmap(butPtr->display, ((WinButton*)butPtr)->pixmap);
- ((WinButton*)butPtr)->pixmap = 0;
- }
}
\f
/*
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
-