tkUnix3d.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:14k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tkUnix3d.c --
  3.  *
  4.  * This file contains the platform specific routines for
  5.  * drawing 3d borders in the Motif style.
  6.  *
  7.  * Copyright (c) 1996 by Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * RCS: @(#) $Id: tkUnix3d.c,v 1.7 2002/08/31 06:12:31 das Exp $
  13.  */
  14. #include <tk3d.h>
  15. #if !(defined(__WIN32__) || defined(MAC_TCL) || defined(MAC_OSX_TK))
  16. #include "tkUnixInt.h"
  17. #endif
  18. /*
  19.  * This structure is used to keep track of the extra colors used
  20.  * by Unix 3d borders.
  21.  */
  22. typedef struct {
  23.     TkBorder info;
  24.     GC solidGC; /* Used to draw solid relief. */
  25. } UnixBorder;
  26. /*
  27.  *----------------------------------------------------------------------
  28.  *
  29.  * TkpGetBorder --
  30.  *
  31.  * This function allocates a new TkBorder structure.
  32.  *
  33.  * Results:
  34.  * Returns a newly allocated TkBorder.
  35.  *
  36.  * Side effects:
  37.  * None.
  38.  *
  39.  *----------------------------------------------------------------------
  40.  */
  41. TkBorder *
  42. TkpGetBorder()
  43. {
  44.     UnixBorder *borderPtr = (UnixBorder *) ckalloc(sizeof(UnixBorder));
  45.     borderPtr->solidGC = None;
  46.     return (TkBorder *) borderPtr;
  47. }
  48. /*
  49.  *----------------------------------------------------------------------
  50.  *
  51.  * TkpFreeBorder --
  52.  *
  53.  * This function frees any colors allocated by the platform
  54.  * specific part of this module.
  55.  *
  56.  * Results:
  57.  * None.
  58.  *
  59.  * Side effects:
  60.  * May deallocate some colors.
  61.  *
  62.  *----------------------------------------------------------------------
  63.  */
  64. void
  65. TkpFreeBorder(borderPtr)
  66.     TkBorder *borderPtr;
  67. {
  68.     UnixBorder *unixBorderPtr = (UnixBorder *) borderPtr;
  69.     Display *display = DisplayOfScreen(borderPtr->screen);
  70.     if (unixBorderPtr->solidGC != None) {
  71. Tk_FreeGC(display, unixBorderPtr->solidGC);
  72.     }
  73. }
  74. /*
  75.  *--------------------------------------------------------------
  76.  *
  77.  * Tk_3DVerticalBevel --
  78.  *
  79.  * This procedure draws a vertical bevel along one side of
  80.  * an object.  The bevel is always rectangular in shape:
  81.  * |||
  82.  * |||
  83.  * |||
  84.  * |||
  85.  * |||
  86.  * |||
  87.  * An appropriate shadow color is chosen for the bevel based
  88.  * on the leftBevel and relief arguments.  Normally this
  89.  * procedure is called first, then Tk_3DHorizontalBevel is
  90.  * called next to draw neat corners.
  91.  *
  92.  * Results:
  93.  * None.
  94.  *
  95.  * Side effects:
  96.  * Graphics are drawn in drawable.
  97.  *
  98.  *--------------------------------------------------------------
  99.  */
  100. void
  101. Tk_3DVerticalBevel(tkwin, drawable, border, x, y, width, height,
  102. leftBevel, relief)
  103.     Tk_Window tkwin; /* Window for which border was allocated. */
  104.     Drawable drawable; /* X window or pixmap in which to draw. */
  105.     Tk_3DBorder border; /* Token for border to draw. */
  106.     int x, y, width, height; /* Area of vertical bevel. */
  107.     int leftBevel; /* Non-zero means this bevel forms the
  108.  * left side of the object;  0 means it
  109.  * forms the right side. */
  110.     int relief; /* Kind of bevel to draw.  For example,
  111.  * TK_RELIEF_RAISED means interior of
  112.  * object should appear higher than
  113.  * exterior. */
  114. {
  115.     TkBorder *borderPtr = (TkBorder *) border;
  116.     GC left, right;
  117.     Display *display = Tk_Display(tkwin);
  118.     if ((borderPtr->lightGC == None) && (relief != TK_RELIEF_FLAT)) {
  119. TkpGetShadows(borderPtr, tkwin);
  120.     }
  121.     if (relief == TK_RELIEF_RAISED) {
  122. XFillRectangle(display, drawable, 
  123. (leftBevel) ? borderPtr->lightGC : borderPtr->darkGC,
  124. x, y, (unsigned) width, (unsigned) height);
  125.     } else if (relief == TK_RELIEF_SUNKEN) {
  126. XFillRectangle(display, drawable, 
  127. (leftBevel) ? borderPtr->darkGC : borderPtr->lightGC,
  128. x, y, (unsigned) width, (unsigned) height);
  129.     } else if (relief == TK_RELIEF_RIDGE) {
  130. int half;
  131. left = borderPtr->lightGC;
  132. right = borderPtr->darkGC;
  133. ridgeGroove:
  134. half = width/2;
  135. if (!leftBevel && (width & 1)) {
  136.     half++;
  137. }
  138. XFillRectangle(display, drawable, left, x, y, (unsigned) half,
  139. (unsigned) height);
  140. XFillRectangle(display, drawable, right, x+half, y,
  141. (unsigned) (width-half), (unsigned) height);
  142.     } else if (relief == TK_RELIEF_GROOVE) {
  143. left = borderPtr->darkGC;
  144. right = borderPtr->lightGC;
  145. goto ridgeGroove;
  146.     } else if (relief == TK_RELIEF_FLAT) {
  147. XFillRectangle(display, drawable, borderPtr->bgGC, x, y,
  148. (unsigned) width, (unsigned) height);
  149.     } else if (relief == TK_RELIEF_SOLID) {
  150. UnixBorder *unixBorderPtr = (UnixBorder *) borderPtr;
  151. if (unixBorderPtr->solidGC == None) {
  152.     XGCValues gcValues;
  153.     gcValues.foreground = BlackPixelOfScreen(borderPtr->screen);
  154.     unixBorderPtr->solidGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  155. }
  156. XFillRectangle(display, drawable, unixBorderPtr->solidGC, x, y,
  157. (unsigned) width, (unsigned) height);
  158.     }
  159. }
  160. /*
  161.  *--------------------------------------------------------------
  162.  *
  163.  * Tk_3DHorizontalBevel --
  164.  *
  165.  * This procedure draws a horizontal bevel along one side of
  166.  * an object.  The bevel has mitered corners (depending on
  167.  * leftIn and rightIn arguments).
  168.  *
  169.  * Results:
  170.  * None.
  171.  *
  172.  * Side effects:
  173.  * None.
  174.  *
  175.  *--------------------------------------------------------------
  176.  */
  177. void
  178. Tk_3DHorizontalBevel(tkwin, drawable, border, x, y, width, height,
  179. leftIn, rightIn, topBevel, relief)
  180.     Tk_Window tkwin; /* Window for which border was allocated. */
  181.     Drawable drawable; /* X window or pixmap in which to draw. */
  182.     Tk_3DBorder border; /* Token for border to draw. */
  183.     int x, y, width, height; /* Bounding box of area of bevel.  Height
  184.  * gives width of border. */
  185.     int leftIn, rightIn; /* Describes whether the left and right
  186.  * edges of the bevel angle in or out as
  187.  * they go down.  For example, if "leftIn"
  188.  * is true, the left side of the bevel
  189.  * looks like this:
  190.  * ___________
  191.  *  __________
  192.  *   _________
  193.  *    ________
  194.  */
  195.     int topBevel; /* Non-zero means this bevel forms the
  196.  * top side of the object;  0 means it
  197.  * forms the bottom side. */
  198.     int relief; /* Kind of bevel to draw.  For example,
  199.  * TK_RELIEF_RAISED means interior of
  200.  * object should appear higher than
  201.  * exterior. */
  202. {
  203.     TkBorder *borderPtr = (TkBorder *) border;
  204.     Display *display = Tk_Display(tkwin);
  205.     int bottom, halfway, x1, x2, x1Delta, x2Delta;
  206.     UnixBorder *unixBorderPtr = (UnixBorder *) borderPtr;
  207.     GC topGC = None, bottomGC = None;
  208. /* Initializations needed only to prevent
  209.  * compiler warnings. */
  210.     if ((borderPtr->lightGC == None) && (relief != TK_RELIEF_FLAT) &&
  211.     (relief != TK_RELIEF_SOLID)) {
  212. TkpGetShadows(borderPtr, tkwin);
  213.     }
  214.     /*
  215.      * Compute a GC for the top half of the bevel and a GC for the
  216.      * bottom half (they're the same in many cases).
  217.      */
  218.     switch (relief) {
  219. case TK_RELIEF_FLAT:
  220.     topGC = bottomGC = borderPtr->bgGC;
  221.     break;
  222. case TK_RELIEF_GROOVE:
  223.     topGC = borderPtr->darkGC;
  224.     bottomGC = borderPtr->lightGC;
  225.     break;
  226. case TK_RELIEF_RAISED:
  227.     topGC = bottomGC =
  228.     (topBevel) ? borderPtr->lightGC : borderPtr->darkGC;
  229.     break;
  230. case TK_RELIEF_RIDGE:
  231.     topGC = borderPtr->lightGC;
  232.     bottomGC = borderPtr->darkGC;
  233.     break;
  234. case TK_RELIEF_SOLID:
  235.     if (unixBorderPtr->solidGC == None) {
  236. XGCValues gcValues;
  237. gcValues.foreground = BlackPixelOfScreen(borderPtr->screen);
  238. unixBorderPtr->solidGC = Tk_GetGC(tkwin, GCForeground,
  239. &gcValues);
  240.     }
  241.     XFillRectangle(display, drawable, unixBorderPtr->solidGC, x, y,
  242. (unsigned) width, (unsigned) height);
  243.     return;
  244. case TK_RELIEF_SUNKEN:
  245.     topGC = bottomGC =
  246.     (topBevel) ? borderPtr->darkGC : borderPtr->lightGC;
  247.     break;
  248.     }
  249.     /*
  250.      * Compute various other geometry-related stuff.
  251.      */
  252.     x1 = x;
  253.     if (!leftIn) {
  254. x1 += height;
  255.     }
  256.     x2 = x+width;
  257.     if (!rightIn) {
  258. x2 -= height;
  259.     }
  260.     x1Delta = (leftIn) ? 1 : -1;
  261.     x2Delta = (rightIn) ? -1 : 1;
  262.     halfway = y + height/2;
  263.     if (!topBevel && (height & 1)) {
  264. halfway++;
  265.     }
  266.     bottom = y + height;
  267.     /*
  268.      * Draw one line for each y-coordinate covered by the bevel.
  269.      */
  270.     for ( ; y < bottom; y++) {
  271. /*
  272.  * X Dimensions are 16-bit, so avoid wraparound or display errors
  273.  * by limiting these here.
  274.  */
  275. if (x1 < -32767)
  276.     x1 = -32767;
  277. if (x2 > 32767)
  278.     x2 = 32767;
  279. /*
  280.  * In some weird cases (such as large border widths for skinny
  281.  * rectangles) x1 can be >= x2.  Don't draw the lines
  282.  * in these cases.
  283.  */
  284. if (x1 < x2) {
  285.     XFillRectangle(display, drawable,
  286. (y < halfway) ? topGC : bottomGC, x1, y,
  287. (unsigned) (x2-x1), (unsigned) 1);
  288. }
  289. x1 += x1Delta;
  290. x2 += x2Delta;
  291.     }
  292. }
  293. /*
  294.  *----------------------------------------------------------------------
  295.  *
  296.  * TkpGetShadows --
  297.  *
  298.  * This procedure computes the shadow colors for a 3-D border
  299.  * and fills in the corresponding fields of the Border structure.
  300.  * It's called lazily, so that the colors aren't allocated until
  301.  * something is actually drawn with them.  That way, if a border
  302.  * is only used for flat backgrounds the shadow colors will
  303.  * never be allocated.
  304.  *
  305.  * Results:
  306.  * None.
  307.  *
  308.  * Side effects:
  309.  * The lightGC and darkGC fields in borderPtr get filled in,
  310.  * if they weren't already.
  311.  *
  312.  *----------------------------------------------------------------------
  313.  */
  314. void
  315. TkpGetShadows(borderPtr, tkwin)
  316.     TkBorder *borderPtr; /* Information about border. */
  317.     Tk_Window tkwin; /* Window where border will be used for
  318.  * drawing. */
  319. {
  320.     XColor lightColor, darkColor;
  321.     int stressed, tmp1, tmp2;
  322.     int r, g, b;
  323.     XGCValues gcValues;
  324.     if (borderPtr->lightGC != None) {
  325. return;
  326.     }
  327.     stressed = TkpCmapStressed(tkwin, borderPtr->colormap);
  328.     /*
  329.      * First, handle the case of a color display with lots of colors.
  330.      * The shadow colors get computed using whichever formula results
  331.      * in the greatest change in color:
  332.      * 1. Lighter shadow is half-way to white, darker shadow is half
  333.      *    way to dark.
  334.      * 2. Lighter shadow is 40% brighter than background, darker shadow
  335.      *    is 40% darker than background.
  336.      */
  337.     if (!stressed && (Tk_Depth(tkwin) >= 6)) {
  338. /*
  339.  * This is a color display with lots of colors.  For the dark
  340.  * shadow, cut 40% from each of the background color components.
  341.  * But if the background is already very dark, make the
  342.  * dark color a little lighter than the background by increasing
  343.  * each color component 1/4th of the way to MAX_INTENSITY.
  344.  *
  345.  * For the light shadow, boost each component by 40% or half-way
  346.  * to white, whichever is greater (the first approach works
  347.  * better for unsaturated colors, the second for saturated ones).
  348.  * But if the background is already very bright, instead choose a
  349.  * slightly darker color for the light shadow by reducing each
  350.  * color component by 10%.
  351.  *
  352.  * Compute the colors using integers, not using lightColor.red
  353.  * etc.: these are shorts and may have problems with integer
  354.  * overflow.
  355.  */
  356. /*
  357.  * Compute the dark shadow color
  358.  */
  359. r = (int) borderPtr->bgColorPtr->red;
  360. g = (int) borderPtr->bgColorPtr->green;
  361. b = (int) borderPtr->bgColorPtr->blue;
  362. if (r*0.5*r + g*1.0*g + b*0.28*b < MAX_INTENSITY*0.05*MAX_INTENSITY) {
  363.     darkColor.red = (MAX_INTENSITY + 3*r)/4;
  364.     darkColor.green = (MAX_INTENSITY + 3*g)/4;
  365.     darkColor.blue = (MAX_INTENSITY + 3*b)/4;
  366. } else {
  367.     darkColor.red = (60 * r)/100;
  368.     darkColor.green = (60 * g)/100;
  369.     darkColor.blue = (60 * b)/100;
  370. }
  371. /*
  372.  * Allocate the dark shadow color and its GC
  373.  */
  374. borderPtr->darkColorPtr = Tk_GetColorByValue(tkwin, &darkColor);
  375. gcValues.foreground = borderPtr->darkColorPtr->pixel;
  376. borderPtr->darkGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  377. /*
  378.  * Compute the light shadow color
  379.  */
  380. if (g > MAX_INTENSITY*0.95) {
  381.     lightColor.red = (90 * r)/100;
  382.     lightColor.green = (90 * g)/100;
  383.     lightColor.blue = (90 * b)/100;
  384. } else {
  385.     tmp1 = (14 * r)/10;
  386.     if (tmp1 > MAX_INTENSITY) {
  387. tmp1 = MAX_INTENSITY;
  388.     }
  389.     tmp2 = (MAX_INTENSITY + r)/2;
  390.     lightColor.red = (tmp1 > tmp2) ? tmp1 : tmp2;
  391.     tmp1 = (14 * g)/10;
  392.     if (tmp1 > MAX_INTENSITY) {
  393. tmp1 = MAX_INTENSITY;
  394.     }
  395.     tmp2 = (MAX_INTENSITY + g)/2;
  396.     lightColor.green = (tmp1 > tmp2) ? tmp1 : tmp2;
  397.     tmp1 = (14 * b)/10;
  398.     if (tmp1 > MAX_INTENSITY) {
  399. tmp1 = MAX_INTENSITY;
  400.     }
  401.     tmp2 = (MAX_INTENSITY + b)/2;
  402.     lightColor.blue = (tmp1 > tmp2) ? tmp1 : tmp2;
  403. }
  404.        /*
  405.         * Allocate the light shadow color and its GC
  406.         */
  407. borderPtr->lightColorPtr = Tk_GetColorByValue(tkwin, &lightColor);
  408. gcValues.foreground = borderPtr->lightColorPtr->pixel;
  409. borderPtr->lightGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  410. return;
  411.     }
  412.     if (borderPtr->shadow == None) {
  413. borderPtr->shadow = Tk_GetBitmap((Tcl_Interp *) NULL, tkwin,
  414. Tk_GetUid("gray50"));
  415. if (borderPtr->shadow == None) {
  416.     panic("TkpGetShadows couldn't allocate bitmap for border");
  417. }
  418.     }
  419.     if (borderPtr->visual->map_entries > 2) {
  420. /*
  421.  * This isn't a monochrome display, but the colormap either
  422.  * ran out of entries or didn't have very many to begin with.
  423.  * Generate the light shadows with a white stipple and the
  424.  * dark shadows with a black stipple.
  425.  */
  426. gcValues.foreground = borderPtr->bgColorPtr->pixel;
  427. gcValues.background = BlackPixelOfScreen(borderPtr->screen);
  428. gcValues.stipple = borderPtr->shadow;
  429. gcValues.fill_style = FillOpaqueStippled;
  430. borderPtr->darkGC = Tk_GetGC(tkwin,
  431. GCForeground|GCBackground|GCStipple|GCFillStyle, &gcValues);
  432. gcValues.background = WhitePixelOfScreen(borderPtr->screen);
  433. borderPtr->lightGC = Tk_GetGC(tkwin,
  434. GCForeground|GCBackground|GCStipple|GCFillStyle, &gcValues);
  435. return;
  436.     }
  437.     /*
  438.      * This is just a measly monochrome display, hardly even worth its
  439.      * existence on this earth.  Make one shadow a 50% stipple and the
  440.      * other the opposite of the background.
  441.      */
  442.     gcValues.foreground = WhitePixelOfScreen(borderPtr->screen);
  443.     gcValues.background = BlackPixelOfScreen(borderPtr->screen);
  444.     gcValues.stipple = borderPtr->shadow;
  445.     gcValues.fill_style = FillOpaqueStippled;
  446.     borderPtr->lightGC = Tk_GetGC(tkwin,
  447.     GCForeground|GCBackground|GCStipple|GCFillStyle, &gcValues);
  448.     if (borderPtr->bgColorPtr->pixel
  449.     == WhitePixelOfScreen(borderPtr->screen)) {
  450. gcValues.foreground = BlackPixelOfScreen(borderPtr->screen);
  451. borderPtr->darkGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  452.     } else {
  453. borderPtr->darkGC = borderPtr->lightGC;
  454. borderPtr->lightGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  455.     }
  456. }