tkUnix3d.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:14k
- /*
- * tkUnix3d.c --
- *
- * This file contains the platform specific routines for
- * drawing 3d borders in the Motif style.
- *
- * Copyright (c) 1996 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.
- *
- * RCS: @(#) $Id: tkUnix3d.c,v 1.7 2002/08/31 06:12:31 das Exp $
- */
- #include <tk3d.h>
- #if !(defined(__WIN32__) || defined(MAC_TCL) || defined(MAC_OSX_TK))
- #include "tkUnixInt.h"
- #endif
- /*
- * This structure is used to keep track of the extra colors used
- * by Unix 3d borders.
- */
- typedef struct {
- TkBorder info;
- GC solidGC; /* Used to draw solid relief. */
- } UnixBorder;
- /*
- *----------------------------------------------------------------------
- *
- * TkpGetBorder --
- *
- * This function allocates a new TkBorder structure.
- *
- * Results:
- * Returns a newly allocated TkBorder.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- TkBorder *
- TkpGetBorder()
- {
- UnixBorder *borderPtr = (UnixBorder *) ckalloc(sizeof(UnixBorder));
- borderPtr->solidGC = None;
- return (TkBorder *) borderPtr;
- }
- /*
- *----------------------------------------------------------------------
- *
- * TkpFreeBorder --
- *
- * This function frees any colors allocated by the platform
- * specific part of this module.
- *
- * Results:
- * None.
- *
- * Side effects:
- * May deallocate some colors.
- *
- *----------------------------------------------------------------------
- */
- void
- TkpFreeBorder(borderPtr)
- TkBorder *borderPtr;
- {
- UnixBorder *unixBorderPtr = (UnixBorder *) borderPtr;
- Display *display = DisplayOfScreen(borderPtr->screen);
- if (unixBorderPtr->solidGC != None) {
- Tk_FreeGC(display, unixBorderPtr->solidGC);
- }
- }
- /*
- *--------------------------------------------------------------
- *
- * Tk_3DVerticalBevel --
- *
- * This procedure draws a vertical bevel along one side of
- * an object. The bevel is always rectangular in shape:
- * |||
- * |||
- * |||
- * |||
- * |||
- * |||
- * An appropriate shadow color is chosen for the bevel based
- * on the leftBevel and relief arguments. Normally this
- * procedure is called first, then Tk_3DHorizontalBevel is
- * called next to draw neat corners.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Graphics are drawn in drawable.
- *
- *--------------------------------------------------------------
- */
- void
- Tk_3DVerticalBevel(tkwin, drawable, border, x, y, width, height,
- leftBevel, relief)
- Tk_Window tkwin; /* Window for which border was allocated. */
- Drawable drawable; /* X window or pixmap in which to draw. */
- Tk_3DBorder border; /* Token for border to draw. */
- int x, y, width, height; /* Area of vertical bevel. */
- int leftBevel; /* Non-zero means this bevel forms the
- * left side of the object; 0 means it
- * forms the right side. */
- int relief; /* Kind of bevel to draw. For example,
- * TK_RELIEF_RAISED means interior of
- * object should appear higher than
- * exterior. */
- {
- TkBorder *borderPtr = (TkBorder *) border;
- GC left, right;
- Display *display = Tk_Display(tkwin);
- if ((borderPtr->lightGC == None) && (relief != TK_RELIEF_FLAT)) {
- TkpGetShadows(borderPtr, tkwin);
- }
- if (relief == TK_RELIEF_RAISED) {
- XFillRectangle(display, drawable,
- (leftBevel) ? borderPtr->lightGC : borderPtr->darkGC,
- x, y, (unsigned) width, (unsigned) height);
- } else if (relief == TK_RELIEF_SUNKEN) {
- XFillRectangle(display, drawable,
- (leftBevel) ? borderPtr->darkGC : borderPtr->lightGC,
- x, y, (unsigned) width, (unsigned) height);
- } else if (relief == TK_RELIEF_RIDGE) {
- int half;
- left = borderPtr->lightGC;
- right = borderPtr->darkGC;
- ridgeGroove:
- half = width/2;
- if (!leftBevel && (width & 1)) {
- half++;
- }
- XFillRectangle(display, drawable, left, x, y, (unsigned) half,
- (unsigned) height);
- XFillRectangle(display, drawable, right, x+half, y,
- (unsigned) (width-half), (unsigned) height);
- } else if (relief == TK_RELIEF_GROOVE) {
- left = borderPtr->darkGC;
- right = borderPtr->lightGC;
- goto ridgeGroove;
- } else if (relief == TK_RELIEF_FLAT) {
- XFillRectangle(display, drawable, borderPtr->bgGC, x, y,
- (unsigned) width, (unsigned) height);
- } else if (relief == TK_RELIEF_SOLID) {
- UnixBorder *unixBorderPtr = (UnixBorder *) borderPtr;
- if (unixBorderPtr->solidGC == None) {
- XGCValues gcValues;
- gcValues.foreground = BlackPixelOfScreen(borderPtr->screen);
- unixBorderPtr->solidGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
- }
- XFillRectangle(display, drawable, unixBorderPtr->solidGC, x, y,
- (unsigned) width, (unsigned) height);
- }
- }
- /*
- *--------------------------------------------------------------
- *
- * Tk_3DHorizontalBevel --
- *
- * This procedure draws a horizontal bevel along one side of
- * an object. The bevel has mitered corners (depending on
- * leftIn and rightIn arguments).
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *--------------------------------------------------------------
- */
- void
- Tk_3DHorizontalBevel(tkwin, drawable, border, x, y, width, height,
- leftIn, rightIn, topBevel, relief)
- Tk_Window tkwin; /* Window for which border was allocated. */
- Drawable drawable; /* X window or pixmap in which to draw. */
- Tk_3DBorder border; /* Token for border to draw. */
- int x, y, width, height; /* Bounding box of area of bevel. Height
- * gives width of border. */
- int leftIn, rightIn; /* Describes whether the left and right
- * edges of the bevel angle in or out as
- * they go down. For example, if "leftIn"
- * is true, the left side of the bevel
- * looks like this:
- * ___________
- * __________
- * _________
- * ________
- */
- int topBevel; /* Non-zero means this bevel forms the
- * top side of the object; 0 means it
- * forms the bottom side. */
- int relief; /* Kind of bevel to draw. For example,
- * TK_RELIEF_RAISED means interior of
- * object should appear higher than
- * exterior. */
- {
- TkBorder *borderPtr = (TkBorder *) border;
- Display *display = Tk_Display(tkwin);
- int bottom, halfway, x1, x2, x1Delta, x2Delta;
- UnixBorder *unixBorderPtr = (UnixBorder *) borderPtr;
- GC topGC = None, bottomGC = None;
- /* Initializations needed only to prevent
- * compiler warnings. */
- if ((borderPtr->lightGC == None) && (relief != TK_RELIEF_FLAT) &&
- (relief != TK_RELIEF_SOLID)) {
- TkpGetShadows(borderPtr, tkwin);
- }
- /*
- * Compute a GC for the top half of the bevel and a GC for the
- * bottom half (they're the same in many cases).
- */
- switch (relief) {
- case TK_RELIEF_FLAT:
- topGC = bottomGC = borderPtr->bgGC;
- break;
- case TK_RELIEF_GROOVE:
- topGC = borderPtr->darkGC;
- bottomGC = borderPtr->lightGC;
- break;
- case TK_RELIEF_RAISED:
- topGC = bottomGC =
- (topBevel) ? borderPtr->lightGC : borderPtr->darkGC;
- break;
- case TK_RELIEF_RIDGE:
- topGC = borderPtr->lightGC;
- bottomGC = borderPtr->darkGC;
- break;
- case TK_RELIEF_SOLID:
- if (unixBorderPtr->solidGC == None) {
- XGCValues gcValues;
- gcValues.foreground = BlackPixelOfScreen(borderPtr->screen);
- unixBorderPtr->solidGC = Tk_GetGC(tkwin, GCForeground,
- &gcValues);
- }
- XFillRectangle(display, drawable, unixBorderPtr->solidGC, x, y,
- (unsigned) width, (unsigned) height);
- return;
- case TK_RELIEF_SUNKEN:
- topGC = bottomGC =
- (topBevel) ? borderPtr->darkGC : borderPtr->lightGC;
- break;
- }
- /*
- * Compute various other geometry-related stuff.
- */
- x1 = x;
- if (!leftIn) {
- x1 += height;
- }
- x2 = x+width;
- if (!rightIn) {
- x2 -= height;
- }
- x1Delta = (leftIn) ? 1 : -1;
- x2Delta = (rightIn) ? -1 : 1;
- halfway = y + height/2;
- if (!topBevel && (height & 1)) {
- halfway++;
- }
- bottom = y + height;
- /*
- * Draw one line for each y-coordinate covered by the bevel.
- */
- for ( ; y < bottom; y++) {
- /*
- * X Dimensions are 16-bit, so avoid wraparound or display errors
- * by limiting these here.
- */
- if (x1 < -32767)
- x1 = -32767;
- if (x2 > 32767)
- x2 = 32767;
- /*
- * In some weird cases (such as large border widths for skinny
- * rectangles) x1 can be >= x2. Don't draw the lines
- * in these cases.
- */
- if (x1 < x2) {
- XFillRectangle(display, drawable,
- (y < halfway) ? topGC : bottomGC, x1, y,
- (unsigned) (x2-x1), (unsigned) 1);
- }
- x1 += x1Delta;
- x2 += x2Delta;
- }
- }
- /*
- *----------------------------------------------------------------------
- *
- * TkpGetShadows --
- *
- * This procedure computes the shadow colors for a 3-D border
- * and fills in the corresponding fields of the Border structure.
- * It's called lazily, so that the colors aren't allocated until
- * something is actually drawn with them. That way, if a border
- * is only used for flat backgrounds the shadow colors will
- * never be allocated.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The lightGC and darkGC fields in borderPtr get filled in,
- * if they weren't already.
- *
- *----------------------------------------------------------------------
- */
- void
- TkpGetShadows(borderPtr, tkwin)
- TkBorder *borderPtr; /* Information about border. */
- Tk_Window tkwin; /* Window where border will be used for
- * drawing. */
- {
- XColor lightColor, darkColor;
- int stressed, tmp1, tmp2;
- int r, g, b;
- XGCValues gcValues;
- if (borderPtr->lightGC != None) {
- return;
- }
- stressed = TkpCmapStressed(tkwin, borderPtr->colormap);
- /*
- * First, handle the case of a color display with lots of colors.
- * The shadow colors get computed using whichever formula results
- * in the greatest change in color:
- * 1. Lighter shadow is half-way to white, darker shadow is half
- * way to dark.
- * 2. Lighter shadow is 40% brighter than background, darker shadow
- * is 40% darker than background.
- */
- if (!stressed && (Tk_Depth(tkwin) >= 6)) {
- /*
- * This is a color display with lots of colors. For the dark
- * shadow, cut 40% from each of the background color components.
- * But if the background is already very dark, make the
- * dark color a little lighter than the background by increasing
- * each color component 1/4th of the way to MAX_INTENSITY.
- *
- * For the light shadow, boost each component by 40% or half-way
- * to white, whichever is greater (the first approach works
- * better for unsaturated colors, the second for saturated ones).
- * But if the background is already very bright, instead choose a
- * slightly darker color for the light shadow by reducing each
- * color component by 10%.
- *
- * Compute the colors using integers, not using lightColor.red
- * etc.: these are shorts and may have problems with integer
- * overflow.
- */
- /*
- * Compute the dark shadow color
- */
- r = (int) borderPtr->bgColorPtr->red;
- g = (int) borderPtr->bgColorPtr->green;
- b = (int) borderPtr->bgColorPtr->blue;
- if (r*0.5*r + g*1.0*g + b*0.28*b < MAX_INTENSITY*0.05*MAX_INTENSITY) {
- darkColor.red = (MAX_INTENSITY + 3*r)/4;
- darkColor.green = (MAX_INTENSITY + 3*g)/4;
- darkColor.blue = (MAX_INTENSITY + 3*b)/4;
- } else {
- darkColor.red = (60 * r)/100;
- darkColor.green = (60 * g)/100;
- darkColor.blue = (60 * b)/100;
- }
- /*
- * Allocate the dark shadow color and its GC
- */
- borderPtr->darkColorPtr = Tk_GetColorByValue(tkwin, &darkColor);
- gcValues.foreground = borderPtr->darkColorPtr->pixel;
- borderPtr->darkGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
- /*
- * Compute the light shadow color
- */
- if (g > MAX_INTENSITY*0.95) {
- lightColor.red = (90 * r)/100;
- lightColor.green = (90 * g)/100;
- lightColor.blue = (90 * b)/100;
- } else {
- tmp1 = (14 * r)/10;
- if (tmp1 > MAX_INTENSITY) {
- tmp1 = MAX_INTENSITY;
- }
- tmp2 = (MAX_INTENSITY + r)/2;
- lightColor.red = (tmp1 > tmp2) ? tmp1 : tmp2;
- tmp1 = (14 * g)/10;
- if (tmp1 > MAX_INTENSITY) {
- tmp1 = MAX_INTENSITY;
- }
- tmp2 = (MAX_INTENSITY + g)/2;
- lightColor.green = (tmp1 > tmp2) ? tmp1 : tmp2;
- tmp1 = (14 * b)/10;
- if (tmp1 > MAX_INTENSITY) {
- tmp1 = MAX_INTENSITY;
- }
- tmp2 = (MAX_INTENSITY + b)/2;
- lightColor.blue = (tmp1 > tmp2) ? tmp1 : tmp2;
- }
-
- /*
- * Allocate the light shadow color and its GC
- */
- borderPtr->lightColorPtr = Tk_GetColorByValue(tkwin, &lightColor);
- gcValues.foreground = borderPtr->lightColorPtr->pixel;
- borderPtr->lightGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
- return;
- }
- if (borderPtr->shadow == None) {
- borderPtr->shadow = Tk_GetBitmap((Tcl_Interp *) NULL, tkwin,
- Tk_GetUid("gray50"));
- if (borderPtr->shadow == None) {
- panic("TkpGetShadows couldn't allocate bitmap for border");
- }
- }
- if (borderPtr->visual->map_entries > 2) {
- /*
- * This isn't a monochrome display, but the colormap either
- * ran out of entries or didn't have very many to begin with.
- * Generate the light shadows with a white stipple and the
- * dark shadows with a black stipple.
- */
- gcValues.foreground = borderPtr->bgColorPtr->pixel;
- gcValues.background = BlackPixelOfScreen(borderPtr->screen);
- gcValues.stipple = borderPtr->shadow;
- gcValues.fill_style = FillOpaqueStippled;
- borderPtr->darkGC = Tk_GetGC(tkwin,
- GCForeground|GCBackground|GCStipple|GCFillStyle, &gcValues);
- gcValues.background = WhitePixelOfScreen(borderPtr->screen);
- borderPtr->lightGC = Tk_GetGC(tkwin,
- GCForeground|GCBackground|GCStipple|GCFillStyle, &gcValues);
- return;
- }
- /*
- * This is just a measly monochrome display, hardly even worth its
- * existence on this earth. Make one shadow a 50% stipple and the
- * other the opposite of the background.
- */
- gcValues.foreground = WhitePixelOfScreen(borderPtr->screen);
- gcValues.background = BlackPixelOfScreen(borderPtr->screen);
- gcValues.stipple = borderPtr->shadow;
- gcValues.fill_style = FillOpaqueStippled;
- borderPtr->lightGC = Tk_GetGC(tkwin,
- GCForeground|GCBackground|GCStipple|GCFillStyle, &gcValues);
- if (borderPtr->bgColorPtr->pixel
- == WhitePixelOfScreen(borderPtr->screen)) {
- gcValues.foreground = BlackPixelOfScreen(borderPtr->screen);
- borderPtr->darkGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
- } else {
- borderPtr->darkGC = borderPtr->lightGC;
- borderPtr->lightGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
- }
- }