diff options
Diffstat (limited to 'mac/tkMacButton.c')
-rw-r--r-- | mac/tkMacButton.c | 428 |
1 files changed, 341 insertions, 87 deletions
diff --git a/mac/tkMacButton.c b/mac/tkMacButton.c index 767baff..287c2ef 100644 --- a/mac/tkMacButton.c +++ b/mac/tkMacButton.c @@ -2,20 +2,21 @@ * tkMacButton.c -- * * This file implements the Macintosh specific portion of the - * button widgets. + * button widgets. * * Copyright (c) 1996-1997 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * SCCS: @(#) tkMacButton.c 1.18 97/11/20 18:27:21 + * SCCS: @(#) tkMacButton.c 1.20 98/02/18 10:48:42 */ #include "tkButton.h" #include "tkMacInt.h" #include <Controls.h> #include <LowMem.h> +#include <Appearance.h> /* * Some defines used to control what type of control is drawn. @@ -43,18 +44,36 @@ static CCTabHandle radioTabHandle; static PixMapHandle oldPixPtr; /* + * These functions are used when Appearance is present. + * By embedding all our controls in a userPane control, + * we can color the background of the text in radiobuttons + * and checkbuttons. Thanks to Peter Gontier of Apple DTS + * for help on this one. + */ + +static ControlRef userPaneHandle; +static RGBColor gUserPaneBackground = { ~0, ~0, ~0}; +static pascal OSErr SetUserPaneDrawProc(ControlRef control, + ControlUserPaneDrawProcPtr upp); +static pascal OSErr SetUserPaneSetUpSpecialBackgroundProc(ControlRef control, + ControlUserPaneBackgroundProcPtr upp); +static pascal void UserPaneDraw(ControlRef control, ControlPartCode cpc); +static pascal void UserPaneBackgroundProc(ControlHandle, + ControlBackgroundPtr info); + +/* * Forward declarations for procedures defined later in this file: */ -static int UpdateControlColors _ANSI_ARGS_((TkButton *butPtr, - ControlRef controlHandle, CCTabHandle ccTabHandle, - RGBColor *saveColorPtr)); -static void DrawBufferedControl _ANSI_ARGS_((TkButton *butPtr, - GWorldPtr destPort)); -static void ChangeBackgroundWindowColor _ANSI_ARGS_(( - WindowRef macintoshWindow, RGBColor rgbColor, - RGBColor *oldColor)); -static void ButtonExitProc _ANSI_ARGS_((ClientData clientData)); +static int UpdateControlColors _ANSI_ARGS_((TkButton *butPtr, + ControlRef controlHandle, CCTabHandle ccTabHandle, + RGBColor *saveColorPtr)); +static void DrawBufferedControl _ANSI_ARGS_((TkButton *butPtr, + GWorldPtr destPort)); +static void ChangeBackgroundWindowColor _ANSI_ARGS_(( + WindowRef macintoshWindow, RGBColor rgbColor, + RGBColor *oldColor)); +static void ButtonExitProc _ANSI_ARGS_((ClientData clientData)); /* * The class procedure table for the button widgets. @@ -137,15 +156,16 @@ TkpDisplayButton( } border = butPtr->normalBorder; - if ((butPtr->state == tkDisabledUid) && (butPtr->disabledFg != NULL)) { + if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) { gc = butPtr->disabledGC; - } else if ((butPtr->type == TYPE_BUTTON) && (butPtr->state == tkActiveUid)) { + } else if ((butPtr->type == TYPE_BUTTON) + && (butPtr->state == STATE_ACTIVE)) { gc = butPtr->activeTextGC; border = butPtr->activeBorder; } else { gc = butPtr->normalTextGC; } - if ((butPtr->flags & SELECTED) && (butPtr->state != tkActiveUid) + if ((butPtr->flags & SELECTED) && (butPtr->state != STATE_ACTIVE) && (butPtr->selectBorder != NULL) && !butPtr->indicatorOn) { border = butPtr->selectBorder; } @@ -173,9 +193,18 @@ TkpDisplayButton( pixmap = Tk_GetPixmap(butPtr->display, Tk_WindowId(tkwin), Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin)); - Tk_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0, - Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); - + /* + * See the comment in UpdateControlColors as to why we use the + * highlightbackground for the border of Macintosh buttons. + */ + + if (butPtr->type == TYPE_BUTTON) { + Tk_Fill3DRectangle(tkwin, pixmap, butPtr->highlightBorder, 0, 0, + Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); + } else { + Tk_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0, + Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); + } if (butPtr->type == TYPE_LABEL) { drawType = DRAW_LABEL; @@ -274,7 +303,7 @@ TkpDisplayButton( * must temporarily modify the GC. */ - if ((butPtr->state == tkDisabledUid) + if ((butPtr->state == STATE_DISABLED) && ((butPtr->disabledFg == NULL) || (butPtr->image != NULL))) { if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn && (butPtr->selectBorder != NULL)) { @@ -361,7 +390,7 @@ TkpComputeButtonGeometry( * highlight width as there is also one pixel of spacing. */ - if (butPtr->defaultState != tkDisabledUid) { + if (butPtr->defaultState != DEFAULT_DISABLED) { butPtr->inset += butPtr->highlightWidth; } butPtr->indicatorSpace = 0; @@ -388,8 +417,8 @@ TkpComputeButtonGeometry( } else { Tk_FreeTextLayout(butPtr->textLayout); butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont, - butPtr->text, -1, butPtr->wrapLength, butPtr->justify, 0, - &butPtr->textWidth, &butPtr->textHeight); + Tcl_GetString(butPtr->textPtr), -1, butPtr->wrapLength, + butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight); width = butPtr->textWidth; height = butPtr->textHeight; @@ -491,36 +520,74 @@ DrawBufferedControl( /* * Create a dummy window that we can draw to. We will - * actually replace this windows bitmap with a the one + * actually replace this window's bitmap with the one * we want to draw to at a later time. This window and * the data structures attached to it are only deallocated * on exit of the application. */ - - windowRef = NewCWindow(NULL, &geometry, "\pempty", false, + + windowRef = NewCWindow(NULL, &geometry, "\pempty", false, zoomDocProc, (WindowRef) -1, true, 0); if (windowRef == NULL) { panic("Can't allocate buffer window."); } - + /* * Now add the three standard controls to hidden window. We * only create one of each and reuse them for every widget in * Tk. + * Under Appearance, we have to embed the controls in a UserPane + * control, so that we can color the background text in + * radiobuttons and checkbuttons. */ SetPort(windowRef); - buttonHandle = NewControl(windowRef, &geometry, "\p", - false, 1, 0, 1, pushButProc, (SInt32) 0); - checkHandle = NewControl(windowRef, &geometry, "\p", - false, 1, 0, 1, checkBoxProc, (SInt32) 0); - radioHandle = NewControl(windowRef, &geometry, "\p", - false, 1, 0, 1, radioButProc, (SInt32) 0); - ((CWindowPeek) windowRef)->visible = true; - - buttonTabHandle = (CCTabHandle) NewHandle(sizeof(CtlCTab)); - checkTabHandle = (CCTabHandle) NewHandle(sizeof(CtlCTab)); - radioTabHandle = (CCTabHandle) NewHandle(sizeof(CtlCTab)); + + if (TkMacHaveAppearance()) { + + OSErr err; + ControlRef dontCare; + + /* Adding UserPaneBackgroundProcs to the root control does + * not seem to work, so we have to add another UserPane to + * the root control. + */ + + err = CreateRootControl(windowRef, &dontCare); + if (err != noErr) { + panic("Can't create root control in DrawBufferedControl"); + } + + userPaneHandle = NewControl(windowRef, &geometry, "\p", + true, kControlSupportsEmbedding|kControlHasSpecialBackground, + 0, 1, kControlUserPaneProc, (SInt32) 5); + SetUserPaneSetUpSpecialBackgroundProc(userPaneHandle, + UserPaneBackgroundProc); + SetUserPaneDrawProc(userPaneHandle, UserPaneDraw); + + buttonHandle = NewControl(windowRef, &geometry, "\p", + false, 1, 0, 1, kControlPushButtonProc, (SInt32) 6); + EmbedControl(buttonHandle, userPaneHandle); + checkHandle = NewControl(windowRef, &geometry, "\p", + false, 1, 0, 1, kControlCheckBoxProc, (SInt32) 7); + EmbedControl(checkHandle, userPaneHandle); + radioHandle = NewControl(windowRef, &geometry, "\p", + false, 1, 0, 1, kControlRadioButtonProc, (SInt32) 8); + EmbedControl(radioHandle, userPaneHandle); + ((CWindowPeek) windowRef)->visible = true; + } else { + buttonHandle = NewControl(windowRef, &geometry, "\p", + false, 1, 0, 1, pushButProc, (SInt32) 0); + checkHandle = NewControl(windowRef, &geometry, "\p", + false, 1, 0, 1, checkBoxProc, (SInt32) 0); + radioHandle = NewControl(windowRef, &geometry, "\p", + false, 1, 0, 1, radioButProc, (SInt32) 0); + ((CWindowPeek) windowRef)->visible = true; + + buttonTabHandle = (CCTabHandle) NewHandle(sizeof(CtlCTab)); + checkTabHandle = (CCTabHandle) NewHandle(sizeof(CtlCTab)); + radioTabHandle = (CCTabHandle) NewHandle(sizeof(CtlCTab)); + } /* * Remove our window from the window list. This way our @@ -556,10 +623,29 @@ DrawBufferedControl( } /* + * Now swap in the passed in GWorld for the portBits of our fake + * window. We also adjust various fields in the WindowRecord to make + * the system think this is a normal window. + * Note, we can use DrawControlInCurrentPort under Appearance, so we don't + * need to swap pixmaps. + */ + + if (!TkMacHaveAppearance()) { + ((CWindowPeek) windowRef)->port.portPixMap = destPort->portPixMap; + } + + ((CWindowPeek) windowRef)->port.portRect = destPort->portRect; + RectRgn(((CWindowPeek) windowRef)->port.visRgn, &destPort->portRect); + RectRgn(((CWindowPeek) windowRef)->strucRgn, &destPort->portRect); + RectRgn(((CWindowPeek) windowRef)->updateRgn, &destPort->portRect); + RectRgn(((CWindowPeek) windowRef)->contRgn, &destPort->portRect); + PortChanged(windowRef); + + /* * Set up control in hidden window to match what we need - * to draw in the buffered window. + * to draw in the buffered window. */ - + switch (butPtr->type) { case TYPE_BUTTON: controlHandle = buttonHandle; @@ -574,21 +660,38 @@ DrawBufferedControl( ccTabHandle = checkTabHandle; break; } + (**controlHandle).contrlRect.left = butPtr->inset; (**controlHandle).contrlRect.top = butPtr->inset; (**controlHandle).contrlRect.right = Tk_Width(butPtr->tkwin) - butPtr->inset; (**controlHandle).contrlRect.bottom = Tk_Height(butPtr->tkwin) - butPtr->inset; - if ((**controlHandle).contrlVis != 255) { - (**controlHandle).contrlVis = 255; - } + + /* + * Setting the control visibility by hand does not + * seem to work under Appearance. + */ + + if (TkMacHaveAppearance()) { + SetControlVisibility(controlHandle, true, false); + (**userPaneHandle).contrlRect.left = 0; + (**userPaneHandle).contrlRect.top = 0; + (**userPaneHandle).contrlRect.right = Tk_Width(butPtr->tkwin); + (**userPaneHandle).contrlRect.bottom = Tk_Height(butPtr->tkwin); + } else { + (**controlHandle).contrlVis = 255; + } + + + if (butPtr->flags & SELECTED) { (**controlHandle).contrlValue = 1; } else { (**controlHandle).contrlValue = 0; } - if (butPtr->state == tkActiveUid) { + + if (butPtr->state == STATE_ACTIVE) { switch (butPtr->type) { case TYPE_BUTTON: (**controlHandle).contrlHilite = kControlButtonPart; @@ -600,27 +703,13 @@ DrawBufferedControl( (**controlHandle).contrlHilite = kControlCheckBoxPart; break; } - } else if (butPtr->state == tkDisabledUid) { + } else if (butPtr->state == STATE_DISABLED) { (**controlHandle).contrlHilite = kControlInactivePart; } else { (**controlHandle).contrlHilite = kControlNoPart; } /* - * Now swap in the passed in GWorld for the portBits of our fake - * window. We also adjust various fields in the WindowRecord to make - * the system think this is a normal window. - */ - - ((CWindowPeek) windowRef)->port.portPixMap = destPort->portPixMap; - ((CWindowPeek) windowRef)->port.portRect = destPort->portRect; - RectRgn(((CWindowPeek) windowRef)->port.visRgn, &destPort->portRect); - RectRgn(((CWindowPeek) windowRef)->strucRgn, &destPort->portRect); - RectRgn(((CWindowPeek) windowRef)->updateRgn, &destPort->portRect); - RectRgn(((CWindowPeek) windowRef)->contRgn, &destPort->portRect); - PortChanged(windowRef); - - /* * Before we draw the control we must add the hidden window back to the * main window list. Otherwise, radiobuttons and checkbuttons will draw * incorrectly. I don't really know why - but clearly the control draw @@ -635,14 +724,41 @@ DrawBufferedControl( * to muck with the colors for the port & window to draw the control * with the proper Tk colors. If we need to we also draw a default * ring for buttons. + * Under Appearance, we draw the control directly into destPort, and + * just set the default control data. */ - SetPort(windowRef); + if (TkMacHaveAppearance()) { + SetPort((GrafPort *) destPort); + } else { + SetPort(windowRef); + } + windowColorChanged = UpdateControlColors(butPtr, controlHandle, ccTabHandle, &saveBackColor); - Draw1Control(controlHandle); - if ((butPtr->type == TYPE_BUTTON) && - (butPtr->defaultState == tkActiveUid)) { + + if ((butPtr->type == TYPE_BUTTON) && TkMacHaveAppearance()) { + Boolean isDefault; + + if (butPtr->defaultState == DEFAULT_ACTIVE) { + isDefault = true; + } else { + isDefault = false; + } + SetControlData(controlHandle, kControlNoPart, + kControlPushButtonDefaultTag, + sizeof(isDefault), (Ptr) &isDefault); + } + + if (TkMacHaveAppearance()) { + DrawControlInCurrentPort(userPaneHandle); + } else { + Draw1Control(controlHandle); + } + + if (!TkMacHaveAppearance() && + (butPtr->type == TYPE_BUTTON) && + (butPtr->defaultState == DEFAULT_ACTIVE)) { Rect box = (**controlHandle).contrlRect; RGBColor rgbColor; @@ -652,21 +768,139 @@ DrawBufferedControl( InsetRect(&box, -butPtr->highlightWidth, -butPtr->highlightWidth); FrameRoundRect(&box, 16, 16); } + if (windowColorChanged) { RGBColor dummyColor; ChangeBackgroundWindowColor(windowRef, saveBackColor, &dummyColor); } /* - * Clean up: remove the hidden window from the main window list. + * Clean up: remove the hidden window from the main window list, and + * hide the control we drew. */ + if (TkMacHaveAppearance()) { + SetControlVisibility(controlHandle, false, false); + } else { + (**controlHandle).contrlVis = 0; + } LMSetWindowList((WindowRef) ((CWindowPeek) windowRef)->nextWindow); } /* *-------------------------------------------------------------- * + * SetUserPaneDrawProc -- + * + * Utility function to add a UserPaneDrawProc + * to a userPane control. From MoreControls code + * from Apple DTS. + * + * Results: + * MacOS system error. + * + * Side effects: + * The user pane gets a new UserPaneDrawProc. + * + *-------------------------------------------------------------- + */ +pascal OSErr SetUserPaneDrawProc ( + ControlRef control, + ControlUserPaneDrawProcPtr upp) +{ + ControlUserPaneDrawUPP myControlUserPaneDrawUPP; + myControlUserPaneDrawUPP = NewControlUserPaneDrawProc(upp); + return SetControlData (control, + kControlNoPart, kControlUserPaneDrawProcTag, + sizeof(myControlUserPaneDrawUPP), + (Ptr) &myControlUserPaneDrawUPP); +} + +/* + *-------------------------------------------------------------- + * + * SetUserPaneSetUpSpecialBackgroundProc -- + * + * Utility function to add a UserPaneBackgroundProc + * to a userPane control + * + * Results: + * MacOS system error. + * + * Side effects: + * The user pane gets a new UserPaneBackgroundProc. + * + *-------------------------------------------------------------- + */ +pascal OSErr +SetUserPaneSetUpSpecialBackgroundProc( + ControlRef control, + ControlUserPaneBackgroundProcPtr upp) +{ + ControlUserPaneBackgroundUPP myControlUserPaneBackgroundUPP; + myControlUserPaneBackgroundUPP = NewControlUserPaneBackgroundProc(upp); + return SetControlData (control, kControlNoPart, + kControlUserPaneBackgroundProcTag, + sizeof(myControlUserPaneBackgroundUPP), + (Ptr) &myControlUserPaneBackgroundUPP); +} + +/* + *-------------------------------------------------------------- + * + * UserPaneDraw -- + * + * This function draws the background of the user pane that will + * lie under checkboxes and radiobuttons. + * + * Results: + * None. + * + * Side effects: + * The user pane gets updated to the current color. + * + *-------------------------------------------------------------- + */ +pascal void +UserPaneDraw( + ControlRef control, + ControlPartCode cpc) +{ + Rect contrlRect = (**control).contrlRect; + RGBBackColor (&gUserPaneBackground); + EraseRect (&contrlRect); +} + +/* + *-------------------------------------------------------------- + * + * UserPaneBackgroundProc -- + * + * This function sets up the background of the user pane that will + * lie under checkboxes and radiobuttons. + * + * Results: + * None. + * + * Side effects: + * The user pane background gets set to the current color. + * + *-------------------------------------------------------------- + */ + +pascal void +UserPaneBackgroundProc( + ControlHandle, + ControlBackgroundPtr info) +{ + if (info->colorDevice) { + RGBBackColor (&gUserPaneBackground); + } +} + +/* + *-------------------------------------------------------------- + * * UpdateControlColors -- * * This function will review the colors used to display @@ -674,6 +908,9 @@ DrawBufferedControl( * used we create a custom palette for the button, populate * with the colors for the button and install the palette. * + * Under Appearance, we just set the pointer that will be + * used by the UserPaneDrawProc. + * * Results: * None. * @@ -692,33 +929,50 @@ UpdateControlColors( { XColor *xcolor; - xcolor = Tk_3DBorderColor(butPtr->normalBorder); - - (**ccTabHandle).ccSeed = 0; - (**ccTabHandle).ccRider = 0; - (**ccTabHandle).ctSize = 3; - (**ccTabHandle).ctTable[0].value = cBodyColor; - TkSetMacColor(xcolor->pixel, - &(**ccTabHandle).ctTable[0].rgb); - (**ccTabHandle).ctTable[1].value = cTextColor; - TkSetMacColor(butPtr->normalFg->pixel, - &(**ccTabHandle).ctTable[1].rgb); - (**ccTabHandle).ctTable[2].value = cFrameColor; - TkSetMacColor(butPtr->highlightColorPtr->pixel, - &(**ccTabHandle).ctTable[2].rgb); - SetControlColor(controlHandle, ccTabHandle); - - if (((xcolor->pixel >> 24) != CONTROL_BODY_PIXEL) && - ((butPtr->type == TYPE_CHECK_BUTTON) || - (butPtr->type == TYPE_RADIO_BUTTON))) { - RGBColor newColor; + /* + * Under Appearance we cannot change the background of the + * button itself. However, the color we are setting is the color + * of the containing userPane. This will be the color that peeks + * around the rounded corners of the button. + * We make this the highlightbackground rather than the background, + * because if you color the background of a frame containing a + * button, you usually also color the highlightbackground as well, + * or you will get a thin grey ring around the button. + */ + + if (TkMacHaveAppearance() && (butPtr->type == TYPE_BUTTON)) { + xcolor = Tk_3DBorderColor(butPtr->highlightBorder); + } else { + xcolor = Tk_3DBorderColor(butPtr->normalBorder); + } + if (TkMacHaveAppearance()) { + TkSetMacColor(xcolor->pixel, &gUserPaneBackground); + } else { + (**ccTabHandle).ccSeed = 0; + (**ccTabHandle).ccRider = 0; + (**ccTabHandle).ctSize = 3; + (**ccTabHandle).ctTable[0].value = cBodyColor; + TkSetMacColor(xcolor->pixel, + &(**ccTabHandle).ctTable[0].rgb); + (**ccTabHandle).ctTable[1].value = cTextColor; + TkSetMacColor(butPtr->normalFg->pixel, + &(**ccTabHandle).ctTable[1].rgb); + (**ccTabHandle).ctTable[2].value = cFrameColor; + TkSetMacColor(butPtr->highlightColorPtr->pixel, + &(**ccTabHandle).ctTable[2].rgb); + SetControlColor(controlHandle, ccTabHandle); + if (((xcolor->pixel >> 24) != CONTROL_BODY_PIXEL) && + ((butPtr->type == TYPE_CHECK_BUTTON) || + (butPtr->type == TYPE_RADIO_BUTTON))) { + RGBColor newColor; - TkSetMacColor(xcolor->pixel, &newColor); - ChangeBackgroundWindowColor((**controlHandle).contrlOwner, - newColor, saveColorPtr); - return true; + TkSetMacColor(xcolor->pixel, &newColor); + ChangeBackgroundWindowColor((**controlHandle).contrlOwner, + newColor, saveColorPtr); + return true; + } } - + return false; } |