diff options
Diffstat (limited to 'mac/tkMacButton.c')
-rw-r--r-- | mac/tkMacButton.c | 920 |
1 files changed, 769 insertions, 151 deletions
diff --git a/mac/tkMacButton.c b/mac/tkMacButton.c index 767baff..7becc36 100644 --- a/mac/tkMacButton.c +++ b/mac/tkMacButton.c @@ -16,6 +16,10 @@ #include "tkMacInt.h" #include <Controls.h> #include <LowMem.h> +#include <Appearance.h> + + +#include <ToolUtils.h> /* * Some defines used to control what type of control is drawn. @@ -24,6 +28,7 @@ #define DRAW_LABEL 0 /* Labels are treated genericly. */ #define DRAW_CONTROL 1 /* Draw using the Native control. */ #define DRAW_CUSTOM 2 /* Make our own button drawing. */ +#define DRAW_BEVEL 3 /* * The following structures are used to draw our controls. Rather than @@ -37,24 +42,61 @@ static CWindowRecord windowRecord; static ControlRef buttonHandle; static ControlRef checkHandle; static ControlRef radioHandle; +static ControlRef smallBevelHandle; +static ControlRef smallStickyBevelHandle; +static ControlRef medBevelHandle; +static ControlRef medStickyBevelHandle; +static ControlRef largeBevelHandle; +static ControlRef largeStickyBevelHandle; + +/* + * These are used to store the image content for + * beveled buttons - i.e. buttons with images. + */ + +static ControlButtonContentInfo bevelButtonContent; +static OpenCPicParams picParams; + static CCTabHandle buttonTabHandle; static CCTabHandle checkTabHandle; 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, +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_(( +static void DrawBufferedControl _ANSI_ARGS_((TkButton *butPtr, + GWorldPtr destPort, GC gc, Pixmap pixmap)); +static void InitSampleControls(); +static void SetupBevelButton _ANSI_ARGS_((TkButton *butPtr, + ControlRef controlHandle, + GWorldPtr destPort, GC gc, Pixmap pixmap)); +static void ChangeBackgroundWindowColor _ANSI_ARGS_(( WindowRef macintoshWindow, RGBColor rgbColor, RGBColor *oldColor)); -static void ButtonExitProc _ANSI_ARGS_((ClientData clientData)); +static void ButtonExitProc _ANSI_ARGS_((ClientData clientData)); /* * The class procedure table for the button widgets. @@ -124,6 +166,7 @@ TkpDisplayButton( * it is an image button, so we offset the * image to make the button appear to move * up and down as the relief changes. */ + int hasImageOrBitmap; CGrafPtr saveWorld; GDHandle saveDevice; GWorldPtr destPort; @@ -136,15 +179,30 @@ TkpDisplayButton( return; } + /* + * 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), + Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin)); + + hasImageOrBitmap = ((butPtr->image != NULL) || (butPtr->bitmap != None)); + offset = (butPtr->type == TYPE_BUTTON) && hasImageOrBitmap; + border = butPtr->normalBorder; if ((butPtr->state == tkDisabledUid) && (butPtr->disabledFg != NULL)) { gc = butPtr->disabledGC; - } else if ((butPtr->type == TYPE_BUTTON) && (butPtr->state == tkActiveUid)) { + } else if ((butPtr->type == TYPE_BUTTON) + && (butPtr->state == tkActiveUid)) { gc = butPtr->activeTextGC; border = butPtr->activeBorder; } else { gc = butPtr->normalTextGC; } + if ((butPtr->flags & SELECTED) && (butPtr->state != tkActiveUid) && (butPtr->selectBorder != NULL) && !butPtr->indicatorOn) { border = butPtr->selectBorder; @@ -153,41 +211,78 @@ TkpDisplayButton( /* * Override the relief specified for the button if this is a * checkbutton or radiobutton and there's no indicator. + * However, don't do this in the presence of Appearance, since + * then the bevel button will take care of the relief. */ relief = butPtr->relief; - if ((butPtr->type >= TYPE_CHECK_BUTTON) && !butPtr->indicatorOn) { - relief = (butPtr->flags & SELECTED) ? TK_RELIEF_SUNKEN - : TK_RELIEF_RAISED; - } - offset = ((butPtr->type == TYPE_BUTTON) && - ((butPtr->image != NULL) || (butPtr->bitmap != None))); + if ((butPtr->type >= TYPE_CHECK_BUTTON) && !butPtr->indicatorOn) { + if (!TkMacHaveAppearance() || !hasImageOrBitmap) { + relief = (butPtr->flags & SELECTED) ? TK_RELIEF_SUNKEN + : TK_RELIEF_RAISED; + } + } /* - * 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. + * See the comment in UpdateControlColors as to why we use the + * highlightbackground for the border of Macintosh buttons. */ - - pixmap = Tk_GetPixmap(butPtr->display, Tk_WindowId(tkwin), - Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin)); + + 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; } else if (butPtr->type == TYPE_BUTTON) { - if ((butPtr->image == None) && (butPtr->bitmap == None)) { + if (!hasImageOrBitmap) { drawType = DRAW_CONTROL; + } else if (butPtr->image != None) { + drawType = DRAW_BEVEL; } else { - drawType = DRAW_CUSTOM; + /* + * TO DO - The current way the we draw bitmaps (XCopyPlane) + * uses CopyDeepMask in this one case. The Picture recording + * does not record this call, and so we can't use the + * Appearance bevel button here. The only case that would + * exercise this is if you use a bitmap, with + * -data & -mask specified. We should probably draw the + * appearance button and overprint the image in this case. + * This just punts and draws the old-style, ugly, button. + */ + + if (gc->clip_mask == 0) { + drawType = DRAW_BEVEL; + } else { + TkpClipMask *clipPtr = (TkpClipMask*) gc->clip_mask; + if ((clipPtr->type == TKP_CLIP_PIXMAP) && + (clipPtr->value.pixmap != butPtr->bitmap)) { + drawType = DRAW_CUSTOM; + } else { + drawType = DRAW_BEVEL; + } + } } } else { if (butPtr->indicatorOn) { drawType = DRAW_CONTROL; + } else if (hasImageOrBitmap) { + if (gc->clip_mask == 0) { + drawType = DRAW_BEVEL; + } else { + TkpClipMask *clipPtr = (TkpClipMask*) gc->clip_mask; + if ((clipPtr->type == TKP_CLIP_PIXMAP) && + (clipPtr->value.pixmap != butPtr->bitmap)) { + drawType = DRAW_CUSTOM; + } else { + drawType = DRAW_BEVEL; + } + } } else { drawType = DRAW_CUSTOM; } @@ -199,7 +294,8 @@ TkpDisplayButton( * the Tk info. Finally, we call Draw1Control to draw to the screen. */ - if (drawType == DRAW_CONTROL) { + if ((drawType == DRAW_CONTROL) || + ((drawType == DRAW_BEVEL) && TkMacHaveAppearance())) { borderWidth = 0; /* @@ -209,7 +305,7 @@ TkpDisplayButton( destPort = TkMacGetDrawablePort(pixmap); SetGWorld(destPort, NULL); - DrawBufferedControl(butPtr, destPort); + DrawBufferedControl(butPtr, destPort, gc, pixmap); } if ((drawType == DRAW_CUSTOM) || (drawType == DRAW_LABEL)) { @@ -217,10 +313,14 @@ TkpDisplayButton( } /* - * Display image or bitmap or text for button. + * Display image or bitmap or text for button. This has + * already been done under Appearance with the Bevel + * button types. */ - if (butPtr->image != None) { + if ((drawType == DRAW_BEVEL) && TkMacHaveAppearance()) { + /* Empty Body */ + } else if (butPtr->image != None) { Tk_SizeOfImage(butPtr->image, &width, &height); imageOrBitmap: @@ -342,28 +442,11 @@ TkpComputeButtonGeometry( int width, height, avgWidth; Tk_FontMetrics fm; - if (butPtr->highlightWidth < 0) { - butPtr->highlightWidth = 0; - } - if ((butPtr->type == TYPE_BUTTON) && (butPtr->image == None) - && (butPtr->bitmap == None)) { - butPtr->inset = 0; - } else if ((butPtr->type != TYPE_LABEL) && butPtr->indicatorOn) { - butPtr->inset = 0; - } else { - butPtr->inset = butPtr->borderWidth; - } /* - * The highlight width corresponds to the default ring on the Macintosh. - * As such, the highlight width is only added if the button is the default - * button. The actual width of the default ring is one less than the - * highlight width as there is also one pixel of spacing. + * First figure out the size of the contents of the button. */ - - if (butPtr->defaultState != tkDisabledUid) { - butPtr->inset += butPtr->highlightWidth; - } + butPtr->indicatorSpace = 0; if (butPtr->image != NULL) { Tk_SizeOfImage(butPtr->image, &width, &height); @@ -388,8 +471,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); + butPtr->text, -1, butPtr->wrapLength, + butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight); width = butPtr->textWidth; height = butPtr->textHeight; @@ -412,21 +495,87 @@ TkpComputeButtonGeometry( } /* + * Now figure out the size of the border decorations for the button. + */ + + if (butPtr->highlightWidth < 0) { + butPtr->highlightWidth = 0; + } + + /* + * The width and height calculation for Appearance buttons with images & + * non-Appearance buttons with images is different. In the latter case, + * we add the borderwidth to the inset, since we are going to stamp a + * 3-D border over the image. In the former, we add it to the height, + * directly, since Appearance will draw the border as part of our control. + * * When issuing the geometry request, add extra space for the indicator, * if any, and for the border and padding, plus if this is an image two * extra pixels so the display can be offset by 1 pixel in either * direction for the raised or lowered effect. + * + * The highlight width corresponds to the default ring on the Macintosh. + * As such, the highlight width is only added if the button is the default + * button. The actual width of the default ring is one less than the + * highlight width as there is also one pixel of spacing. + * Appearance buttons with images do not have a highlight ring, because the + * Bevel button type does not support one. */ - if ((butPtr->image == NULL) && (butPtr->bitmap == None)) { + if ((butPtr->image == None) && (butPtr->bitmap == None)) { width += 2*butPtr->padX; height += 2*butPtr->padY; } - if ((butPtr->type == TYPE_BUTTON) && - ((butPtr->image != NULL) || (butPtr->bitmap != None))) { + + if ((butPtr->type == TYPE_BUTTON)) { + if ((butPtr->image == None) && (butPtr->bitmap == None)) { + butPtr->inset = 0; + if (butPtr->defaultState != tkDisabledUid) { + butPtr->inset += butPtr->highlightWidth; + } + } else if (TkMacHaveAppearance()) { + butPtr->inset = 0; + width += (2 * butPtr->borderWidth + 4); + height += (2 * butPtr->borderWidth + 4); + } else { + butPtr->inset = butPtr->borderWidth; width += 2; height += 2; + if (butPtr->defaultState != tkDisabledUid) { + butPtr->inset += butPtr->highlightWidth; + } + } + } else if ((butPtr->type != TYPE_LABEL)) { + if (butPtr->indicatorOn) { + butPtr->inset = 0; + } else { + /* + * Under Appearance, the Checkbutton or radiobutton with an image + * is represented by a BevelButton with the Sticky defProc... + * So we must set its height in the same way as the Button + * with an image or bitmap. + */ + if (((butPtr->image != None) || (butPtr->bitmap != None)) + && TkMacHaveAppearance()) { + int border; + butPtr->inset = 0; + if ( butPtr->borderWidth <= 2 ) { + border = 6; + } else { + border = 2 * butPtr->borderWidth + 2; + } + width += border; + height += border; + } else { + butPtr->inset = butPtr->borderWidth; + } + } + } else { + butPtr->inset = butPtr->borderWidth; } + + + Tk_GeometryRequest(butPtr->tkwin, (int) (width + butPtr->indicatorSpace + 2*butPtr->inset), (int) (height + 2*butPtr->inset)); Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset); @@ -478,20 +627,282 @@ TkpDestroyButton( static void DrawBufferedControl( TkButton *butPtr, /* Tk button. */ - GWorldPtr destPort) /* Off screen GWorld. */ + GWorldPtr destPort, /* Off screen GWorld. */ + GC gc, /* The GC we are drawing into - needed for + * the bevel button */ + Pixmap pixmap /* The pixmap we are drawing into - needed + for the bevel button */ + ) { ControlRef controlHandle; CCTabHandle ccTabHandle; int windowColorChanged = false; RGBColor saveBackColor; - + int isBevel = 0; + if (windowRef == NULL) { + InitSampleControls(); + } + + /* + * 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. + */ + + isBevel = 0; + switch (butPtr->type) { + case TYPE_BUTTON: + if (TkMacHaveAppearance()) { + if ((butPtr->image == None) && (butPtr->bitmap == None)) { + controlHandle = buttonHandle; + ccTabHandle = buttonTabHandle; + } else { + if (butPtr->borderWidth <= 2) { + controlHandle = smallBevelHandle; + } else if (butPtr->borderWidth == 3) { + controlHandle = medBevelHandle; + } else { + controlHandle = largeBevelHandle; + } + ccTabHandle = buttonTabHandle; + SetupBevelButton(butPtr, controlHandle, destPort, + gc, pixmap); + isBevel = 1; + } + } else { + controlHandle = buttonHandle; + ccTabHandle = buttonTabHandle; + } + break; + case TYPE_RADIO_BUTTON: + if (TkMacHaveAppearance()) { + if (((butPtr->image == None) && (butPtr->bitmap == None)) + || (butPtr->indicatorOn)) { + controlHandle = radioHandle; + ccTabHandle = radioTabHandle; + } else { + if (butPtr->borderWidth <= 2) { + controlHandle = smallStickyBevelHandle; + } else if (butPtr->borderWidth == 3) { + controlHandle = medStickyBevelHandle; + } else { + controlHandle = largeStickyBevelHandle; + } + ccTabHandle = radioTabHandle; + SetupBevelButton(butPtr, controlHandle, destPort, + gc, pixmap); + isBevel = 1; + } + } else { + controlHandle = radioHandle; + ccTabHandle = radioTabHandle; + } + break; + case TYPE_CHECK_BUTTON: + if (TkMacHaveAppearance()) { + if (((butPtr->image == None) && (butPtr->bitmap == None)) + || (butPtr->indicatorOn)) { + controlHandle = checkHandle; + ccTabHandle = checkTabHandle; + } else { + if (butPtr->borderWidth <= 2) { + controlHandle = smallStickyBevelHandle; + } else if (butPtr->borderWidth == 3) { + controlHandle = medStickyBevelHandle; + } else { + controlHandle = largeStickyBevelHandle; + } + ccTabHandle = checkTabHandle; + SetupBevelButton(butPtr, controlHandle, destPort, + gc, pixmap); + isBevel = 1; + } + } else { + controlHandle = checkHandle; + 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; + + /* + * 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 (isBevel) { + (**controlHandle).contrlHilite = kControlButtonPart; + } else { + switch (butPtr->type) { + case TYPE_BUTTON: + (**controlHandle).contrlHilite = kControlButtonPart; + break; + case TYPE_RADIO_BUTTON: + (**controlHandle).contrlHilite = kControlRadioButtonPart; + break; + case TYPE_CHECK_BUTTON: + (**controlHandle).contrlHilite = kControlCheckBoxPart; + break; + } + } + } else if (butPtr->state == tkDisabledUid) { + (**controlHandle).contrlHilite = kControlInactivePart; + } else { + (**controlHandle).contrlHilite = kControlNoPart; + } + + /* + * 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 + * proc needs to have the controls window in the window list. + */ + + ((CWindowPeek) windowRef)->nextWindow = (CWindowPeek) LMGetWindowList(); + LMSetWindowList(windowRef); + + /* + * Now we can set the port to our doctered up window. We next need + * 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. + */ + + if (TkMacHaveAppearance()) { + SetPort((GrafPort *) destPort); + } else { + SetPort(windowRef); + } + + windowColorChanged = UpdateControlColors(butPtr, controlHandle, + ccTabHandle, &saveBackColor); + + if ((butPtr->type == TYPE_BUTTON) && TkMacHaveAppearance()) { + Boolean isDefault; + + if (butPtr->defaultState == tkActiveUid) { + 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 == tkActiveUid)) { + Rect box = (**controlHandle).contrlRect; + RGBColor rgbColor; + + TkSetMacColor(butPtr->highlightColorPtr->pixel, &rgbColor); + RGBForeColor(&rgbColor); + PenSize(butPtr->highlightWidth - 1, butPtr->highlightWidth - 1); + 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, and + * hide the control we drew. + */ + + if (TkMacHaveAppearance()) { + SetControlVisibility(controlHandle, false, false); + if (isBevel) { + KillPicture(bevelButtonContent.u.picture); + } + } else { + (**controlHandle).contrlVis = 0; + } + LMSetWindowList((WindowRef) ((CWindowPeek) windowRef)->nextWindow); +} + +/* + *-------------------------------------------------------------- + * + * InitSampleControls -- + * + * This function initializes a dummy Macintosh window and + * sample controls to allow drawing Mac controls to any GWorld + * (including off-screen bitmaps). + * + * Results: + * None. + * + * Side effects: + * Controls & a window are created. + * + *-------------------------------------------------------------- + */ + +static void +InitSampleControls() +{ Rect geometry = {0, 0, 10, 10}; CWindowPeek windowList; /* * 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. @@ -507,9 +918,87 @@ DrawBufferedControl( * 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); + + 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) 0); + SetUserPaneSetUpSpecialBackgroundProc(userPaneHandle, + UserPaneBackgroundProc); + SetUserPaneDrawProc(userPaneHandle, UserPaneDraw); + + buttonHandle = NewControl(windowRef, &geometry, "\p", + false, 1, 0, 1, kControlPushButtonProc, (SInt32) 0); + EmbedControl(buttonHandle, userPaneHandle); + checkHandle = NewControl(windowRef, &geometry, "\p", + false, 1, 0, 1, kControlCheckBoxProc, (SInt32) 0); + EmbedControl(checkHandle, userPaneHandle); + radioHandle = NewControl(windowRef, &geometry, "\p", + false, 1, 0, 1, kControlRadioButtonProc, (SInt32) 0); + EmbedControl(radioHandle, userPaneHandle); + smallBevelHandle = NewControl(windowRef, &geometry, "\p", + false, 0, 0, + kControlBehaviorOffsetContents << 16 | kControlContentPictHandle, + kControlBevelButtonSmallBevelProc, (SInt32) 0); + EmbedControl(smallBevelHandle, userPaneHandle); + medBevelHandle = NewControl(windowRef, &geometry, "\p", + false, 0, 0, + kControlBehaviorOffsetContents << 16 | kControlContentPictHandle, + kControlBevelButtonNormalBevelProc, (SInt32) 0); + EmbedControl(medBevelHandle, userPaneHandle); + largeBevelHandle = NewControl(windowRef, &geometry, "\p", + false, 0, 0, + kControlBehaviorOffsetContents << 16 | kControlContentPictHandle, + kControlBevelButtonLargeBevelProc, (SInt32) 0); + EmbedControl(largeBevelHandle, userPaneHandle); + bevelButtonContent.contentType = kControlContentPictHandle; + smallStickyBevelHandle = NewControl(windowRef, &geometry, "\p", + false, 0, 0, + (kControlBehaviorOffsetContents | kControlBehaviorSticky) << 16 + | kControlContentPictHandle, + kControlBevelButtonSmallBevelProc, (SInt32) 0); + EmbedControl(smallStickyBevelHandle, userPaneHandle); + medStickyBevelHandle = NewControl(windowRef, &geometry, "\p", + false, 0, 0, + (kControlBehaviorOffsetContents | kControlBehaviorSticky) << 16 + | kControlContentPictHandle, + kControlBevelButtonNormalBevelProc, (SInt32) 0); + EmbedControl(medStickyBevelHandle, userPaneHandle); + largeStickyBevelHandle = NewControl(windowRef, &geometry, "\p", + false, 0, 0, + (kControlBehaviorOffsetContents | kControlBehaviorSticky) << 16 + | kControlContentPictHandle, + kControlBevelButtonLargeBevelProc, (SInt32) 0); + EmbedControl(largeStickyBevelHandle, userPaneHandle); + + picParams.version = -2; + picParams.hRes = 0x00480000; + picParams.vRes = 0x00480000; + picParams.srcRect.top = 0; + picParams.srcRect.left = 0; + + ((CWindowPeek) windowRef)->visible = true; + } else { buttonHandle = NewControl(windowRef, &geometry, "\p", false, 1, 0, 1, pushButProc, (SInt32) 0); checkHandle = NewControl(windowRef, &geometry, "\p", @@ -521,6 +1010,7 @@ DrawBufferedControl( 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 @@ -553,115 +1043,222 @@ DrawBufferedControl( oldPixPtr = ((CWindowPeek) windowRef)->port.portPixMap; Tcl_CreateExitHandler(ButtonExitProc, (ClientData) NULL); */ - } + +} + +/* + *-------------------------------------------------------------- + * + * SetupBevelButton -- + * + * Sets up the Bevel Button with image by copying the + * source image onto the PicHandle for the button. + * + * Results: + * None + * + * Side effects: + * The image or bitmap for the button is copied over to a picture. + * + *-------------------------------------------------------------- + */ +void +SetupBevelButton( + TkButton *butPtr, /* Tk button. */ + ControlRef controlHandle, /* The control to set this picture to */ + GWorldPtr destPort, /* Off screen GWorld. */ + GC gc, /* The GC we are drawing into - needed for + * the bevel button */ + Pixmap pixmap /* The pixmap we are drawing into - needed + for the bevel button */ + ) +{ + int height, width; + ControlButtonGraphicAlignment theAlignment; - /* - * Set up control in hidden window to match what we need - * to draw in the buffered window. - */ + SetPort((GrafPtr) destPort); - switch (butPtr->type) { - case TYPE_BUTTON: - controlHandle = buttonHandle; - ccTabHandle = buttonTabHandle; - break; - case TYPE_RADIO_BUTTON: - controlHandle = radioHandle; - ccTabHandle = radioTabHandle; - break; - case TYPE_CHECK_BUTTON: - controlHandle = checkHandle; - 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; - } - if (butPtr->flags & SELECTED) { - (**controlHandle).contrlValue = 1; + if (butPtr->image != None) { + Tk_SizeOfImage(butPtr->image, + &width, &height); } else { - (**controlHandle).contrlValue = 0; + Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, + &width, &height); } - if (butPtr->state == tkActiveUid) { - switch (butPtr->type) { - case TYPE_BUTTON: - (**controlHandle).contrlHilite = kControlButtonPart; - break; - case TYPE_RADIO_BUTTON: - (**controlHandle).contrlHilite = kControlRadioButtonPart; - break; - case TYPE_CHECK_BUTTON: - (**controlHandle).contrlHilite = kControlCheckBoxPart; - break; - } - } else if (butPtr->state == tkDisabledUid) { - (**controlHandle).contrlHilite = kControlInactivePart; - } else { - (**controlHandle).contrlHilite = kControlNoPart; + + if ((butPtr->width > 0) && (butPtr->width < width)) { + width = butPtr->width; + } + if ((butPtr->height > 0) && (butPtr->height < height)) { + height = butPtr->height; } - - /* - * 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); + + picParams.srcRect.right = width; + picParams.srcRect.bottom = height; + + bevelButtonContent.u.picture = OpenCPicture(&picParams); /* - * 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 - * proc needs to have the controls window in the window list. + * TO DO - There is one case where XCopyPlane calls CopyDeepMask, + * which does not get recorded in the picture. So the bitmap code + * will fail in that case. */ + + if ((butPtr->selectImage != NULL) && (butPtr->flags & SELECTED)) { + Tk_RedrawImage(butPtr->selectImage, 0, 0, width, height, + pixmap, 0, 0); + } else if (butPtr->image != NULL) { + Tk_RedrawImage(butPtr->image, 0, 0, width, + height, pixmap, 0, 0); + } else { + XSetClipOrigin(butPtr->display, gc, 0, 0); + XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, gc, 0, 0, + (unsigned int) width, (unsigned int) height, 0, 0, 1); + } + + ClosePicture(); + + SetControlData(controlHandle, kControlButtonPart, + kControlBevelButtonContentTag, + sizeof(ControlButtonContentInfo), + (char *) &bevelButtonContent); + + if (butPtr->anchor == TK_ANCHOR_N) { + theAlignment = kControlBevelButtonAlignTop; + } else if (butPtr->anchor == TK_ANCHOR_NE) { + theAlignment = kControlBevelButtonAlignTopRight; + } else if (butPtr->anchor == TK_ANCHOR_E) { + theAlignment = kControlBevelButtonAlignRight; + } else if (butPtr->anchor == TK_ANCHOR_SE) { + theAlignment = kControlBevelButtonAlignBottomRight; + } else if (butPtr->anchor == TK_ANCHOR_S) { + theAlignment = kControlBevelButtonAlignBottom; + } else if (butPtr->anchor == TK_ANCHOR_SW) { + theAlignment = kControlBevelButtonAlignBottomLeft; + } else if (butPtr->anchor == TK_ANCHOR_W) { + theAlignment = kControlBevelButtonAlignLeft; + } else if (butPtr->anchor == TK_ANCHOR_NW) { + theAlignment = kControlBevelButtonAlignTopLeft; + } else if (butPtr->anchor == TK_ANCHOR_CENTER) { + theAlignment = kControlBevelButtonAlignCenter; + } - ((CWindowPeek) windowRef)->nextWindow = (CWindowPeek) LMGetWindowList(); - LMSetWindowList(windowRef); - - /* - * Now we can set the port to our doctered up window. We next need - * 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. - */ + SetControlData(controlHandle, kControlButtonPart, + kControlBevelButtonGraphicAlignTag, + sizeof(ControlButtonGraphicAlignment), + (char *) &theAlignment); - SetPort(windowRef); - windowColorChanged = UpdateControlColors(butPtr, controlHandle, - ccTabHandle, &saveBackColor); - Draw1Control(controlHandle); - if ((butPtr->type == TYPE_BUTTON) && - (butPtr->defaultState == tkActiveUid)) { - Rect box = (**controlHandle).contrlRect; - RGBColor rgbColor; +} + +/* + *-------------------------------------------------------------- + * + * 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. + * + *-------------------------------------------------------------- + */ - TkSetMacColor(butPtr->highlightColorPtr->pixel, &rgbColor); - RGBForeColor(&rgbColor); - PenSize(butPtr->highlightWidth - 1, butPtr->highlightWidth - 1); - InsetRect(&box, -butPtr->highlightWidth, -butPtr->highlightWidth); - FrameRoundRect(&box, 16, 16); - } - if (windowColorChanged) { - RGBColor dummyColor; - ChangeBackgroundWindowColor(windowRef, saveBackColor, &dummyColor); +pascal void +UserPaneBackgroundProc( + ControlHandle, + ControlBackgroundPtr info) +{ + if (info->colorDevice) { + RGBBackColor (&gUserPaneBackground); } - - /* - * Clean up: remove the hidden window from the main window list. - */ - - LMSetWindowList((WindowRef) ((CWindowPeek) windowRef)->nextWindow); } /* @@ -674,6 +1271,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,8 +1292,25 @@ UpdateControlColors( { XColor *xcolor; + /* + * 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; @@ -718,6 +1335,7 @@ UpdateControlColors( newColor, saveColorPtr); return true; } + } return false; } |