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

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tkWin3d.c --
  3.  *
  4.  * This file contains the platform specific routines for
  5.  * drawing 3d borders in the Windows 95 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: tkWin3d.c,v 1.5 2000/04/14 01:36:35 ericm Exp $
  13.  */
  14. #include "tkWinInt.h"
  15. #include "tk3d.h"
  16. /*
  17.  * This structure is used to keep track of the extra colors used by
  18.  * Windows 3d borders.
  19.  */
  20. typedef struct {
  21.     TkBorder info;
  22.     XColor *light2ColorPtr; /* System3dLight */
  23.     XColor *dark2ColorPtr;  /* System3dDarkShadow */
  24. } WinBorder;
  25. /*
  26.  *----------------------------------------------------------------------
  27.  *
  28.  * TkpGetBorder --
  29.  *
  30.  * This function allocates a new TkBorder structure.
  31.  *
  32.  * Results:
  33.  * Returns a newly allocated TkBorder.
  34.  *
  35.  * Side effects:
  36.  * None.
  37.  *
  38.  *----------------------------------------------------------------------
  39.  */
  40. TkBorder *
  41. TkpGetBorder()
  42. {
  43.     WinBorder *borderPtr = (WinBorder *) ckalloc(sizeof(WinBorder));
  44.     borderPtr->light2ColorPtr = NULL;
  45.     borderPtr->dark2ColorPtr = NULL;
  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.     WinBorder *winBorderPtr = (WinBorder *) borderPtr;
  69.     if (winBorderPtr->light2ColorPtr) {
  70. Tk_FreeColor(winBorderPtr->light2ColorPtr);
  71.     }
  72.     if (winBorderPtr->dark2ColorPtr) {
  73. Tk_FreeColor(winBorderPtr->dark2ColorPtr);
  74.     }
  75. }
  76. /*
  77.  *--------------------------------------------------------------
  78.  *
  79.  * Tk_3DVerticalBevel --
  80.  *
  81.  * This procedure draws a vertical bevel along one side of
  82.  * an object.  The bevel is always rectangular in shape:
  83.  * |||
  84.  * |||
  85.  * |||
  86.  * |||
  87.  * |||
  88.  * |||
  89.  * An appropriate shadow color is chosen for the bevel based
  90.  * on the leftBevel and relief arguments.  Normally this
  91.  * procedure is called first, then Tk_3DHorizontalBevel is
  92.  * called next to draw neat corners.
  93.  *
  94.  * Results:
  95.  * None.
  96.  *
  97.  * Side effects:
  98.  * Graphics are drawn in drawable.
  99.  *
  100.  *--------------------------------------------------------------
  101.  */
  102. void
  103. Tk_3DVerticalBevel(tkwin, drawable, border, x, y, width, height,
  104. leftBevel, relief)
  105.     Tk_Window tkwin; /* Window for which border was allocated. */
  106.     Drawable drawable; /* X window or pixmap in which to draw. */
  107.     Tk_3DBorder border; /* Token for border to draw. */
  108.     int x, y, width, height; /* Area of vertical bevel. */
  109.     int leftBevel; /* Non-zero means this bevel forms the
  110.  * left side of the object;  0 means it
  111.  * forms the right side. */
  112.     int relief; /* Kind of bevel to draw.  For example,
  113.  * TK_RELIEF_RAISED means interior of
  114.  * object should appear higher than
  115.  * exterior. */
  116. {
  117.     TkBorder *borderPtr = (TkBorder *) border;
  118.     int left, right;
  119.     Display *display = Tk_Display(tkwin);
  120.     TkWinDCState state;
  121.     HDC dc = TkWinGetDrawableDC(display, drawable, &state);
  122.     int half;
  123.     if ((borderPtr->lightGC == None) && (relief != TK_RELIEF_FLAT)) {
  124. TkpGetShadows(borderPtr, tkwin);
  125.     }
  126.     switch (relief) {
  127. case TK_RELIEF_RAISED:
  128.     left = (leftBevel)
  129. ? borderPtr->lightGC->foreground
  130. : borderPtr->darkGC->foreground;
  131.     right = (leftBevel)
  132. ? ((WinBorder *)borderPtr)->light2ColorPtr->pixel
  133. : ((WinBorder *)borderPtr)->dark2ColorPtr->pixel;
  134.     break;
  135. case TK_RELIEF_SUNKEN:
  136.     left = (leftBevel)
  137. ? ((WinBorder *)borderPtr)->dark2ColorPtr->pixel
  138. : ((WinBorder *)borderPtr)->light2ColorPtr->pixel;
  139.     right = (leftBevel)
  140. ? borderPtr->darkGC->foreground
  141. : borderPtr->lightGC->foreground;
  142.     break;
  143. case TK_RELIEF_RIDGE:
  144.     left = borderPtr->lightGC->foreground;
  145.     right = borderPtr->darkGC->foreground;
  146.     break;
  147. case TK_RELIEF_GROOVE:
  148.     left = borderPtr->darkGC->foreground;
  149.     right = borderPtr->lightGC->foreground;
  150.     break;
  151. case TK_RELIEF_FLAT:
  152.     left = right = borderPtr->bgGC->foreground;
  153.     break;
  154. case TK_RELIEF_SOLID:
  155.     left = right = RGB(0,0,0);
  156.     break;
  157.     }
  158.     half = width/2;
  159.     if (leftBevel && (width & 1)) {
  160. half++;
  161.     }
  162.     TkWinFillRect(dc, x, y, half, height, left);
  163.     TkWinFillRect(dc, x+half, y, width-half, height, right);
  164.     TkWinReleaseDrawableDC(drawable, dc, &state);
  165. }
  166. /*
  167.  *--------------------------------------------------------------
  168.  *
  169.  * Tk_3DHorizontalBevel --
  170.  *
  171.  * This procedure draws a horizontal bevel along one side of
  172.  * an object.  The bevel has mitered corners (depending on
  173.  * leftIn and rightIn arguments).
  174.  *
  175.  * Results:
  176.  * None.
  177.  *
  178.  * Side effects:
  179.  * None.
  180.  *
  181.  *--------------------------------------------------------------
  182.  */
  183. void
  184. Tk_3DHorizontalBevel(tkwin, drawable, border, x, y, width, height,
  185. leftIn, rightIn, topBevel, relief)
  186.     Tk_Window tkwin; /* Window for which border was allocated. */
  187.     Drawable drawable; /* X window or pixmap in which to draw. */
  188.     Tk_3DBorder border; /* Token for border to draw. */
  189.     int x, y, width, height; /* Bounding box of area of bevel.  Height
  190.  * gives width of border. */
  191.     int leftIn, rightIn; /* Describes whether the left and right
  192.  * edges of the bevel angle in or out as
  193.  * they go down.  For example, if "leftIn"
  194.  * is true, the left side of the bevel
  195.  * looks like this:
  196.  * ___________
  197.  *  __________
  198.  *   _________
  199.  *    ________
  200.  */
  201.     int topBevel; /* Non-zero means this bevel forms the
  202.  * top side of the object;  0 means it
  203.  * forms the bottom side. */
  204.     int relief; /* Kind of bevel to draw.  For example,
  205.  * TK_RELIEF_RAISED means interior of
  206.  * object should appear higher than
  207.  * exterior. */
  208. {
  209.     TkBorder *borderPtr = (TkBorder *) border;
  210.     Display *display = Tk_Display(tkwin);
  211.     int bottom, halfway, x1, x2, x1Delta, x2Delta;
  212.     TkWinDCState state;
  213.     HDC dc = TkWinGetDrawableDC(display, drawable, &state);
  214.     int topColor, bottomColor;
  215.     if ((borderPtr->lightGC == None) && (relief != TK_RELIEF_FLAT)) {
  216. TkpGetShadows(borderPtr, tkwin);
  217.     }
  218.     /*
  219.      * Compute a GC for the top half of the bevel and a GC for the
  220.      * bottom half (they're the same in many cases).
  221.      */
  222.     switch (relief) {
  223. case TK_RELIEF_RAISED:
  224.     topColor = (topBevel)
  225. ? borderPtr->lightGC->foreground
  226. : borderPtr->darkGC->foreground;
  227.     bottomColor = (topBevel)
  228. ? ((WinBorder *)borderPtr)->light2ColorPtr->pixel
  229. : ((WinBorder *)borderPtr)->dark2ColorPtr->pixel;
  230.     break;
  231. case TK_RELIEF_SUNKEN:
  232.     topColor = (topBevel)
  233. ? ((WinBorder *)borderPtr)->dark2ColorPtr->pixel
  234. : ((WinBorder *)borderPtr)->light2ColorPtr->pixel;
  235.     bottomColor = (topBevel)
  236. ? borderPtr->darkGC->foreground
  237. : borderPtr->lightGC->foreground;
  238.     break;
  239. case TK_RELIEF_RIDGE:
  240.     topColor = borderPtr->lightGC->foreground;
  241.     bottomColor = borderPtr->darkGC->foreground;
  242.     break;
  243. case TK_RELIEF_GROOVE:
  244.     topColor = borderPtr->darkGC->foreground;
  245.     bottomColor = borderPtr->lightGC->foreground;
  246.     break;
  247. case TK_RELIEF_FLAT:
  248.     topColor = bottomColor = borderPtr->bgGC->foreground;
  249.     break;
  250. case TK_RELIEF_SOLID:
  251.     topColor = bottomColor = RGB(0,0,0);
  252.     }
  253.     /*
  254.      * Compute various other geometry-related stuff.
  255.      */
  256.     if (leftIn) {
  257. x1 = x+1;
  258.     } else {
  259. x1 = x+height-1;
  260.     }
  261.     x2 = x+width;
  262.     if (rightIn) {
  263. x2--;
  264.     } else {
  265. x2 -= height;
  266.     }
  267.     x1Delta = (leftIn) ? 1 : -1;
  268.     x2Delta = (rightIn) ? -1 : 1;
  269.     halfway = y + height/2;
  270.     if (topBevel && (height & 1)) {
  271. halfway++;
  272.     }
  273.     bottom = y + height;
  274.     /*
  275.      * Draw one line for each y-coordinate covered by the bevel.
  276.      */
  277.     for ( ; y < bottom; y++) {
  278. /*
  279.  * In some weird cases (such as large border widths for skinny
  280.  * rectangles) x1 can be >= x2.  Don't draw the lines
  281.  * in these cases.
  282.  */
  283. if (x1 < x2) {
  284.     TkWinFillRect(dc, x1, y, x2-x1, 1,
  285. (y < halfway) ? topColor : bottomColor);
  286. }
  287. x1 += x1Delta;
  288. x2 += x2Delta;
  289.     }
  290.     TkWinReleaseDrawableDC(drawable, dc, &state);
  291. }
  292. /*
  293.  *----------------------------------------------------------------------
  294.  *
  295.  * TkpGetShadows --
  296.  *
  297.  * This procedure computes the shadow colors for a 3-D border
  298.  * and fills in the corresponding fields of the Border structure.
  299.  * It's called lazily, so that the colors aren't allocated until
  300.  * something is actually drawn with them.  That way, if a border
  301.  * is only used for flat backgrounds the shadow colors will
  302.  * never be allocated.
  303.  *
  304.  * Results:
  305.  * None.
  306.  *
  307.  * Side effects:
  308.  * The lightGC and darkGC fields in borderPtr get filled in,
  309.  * if they weren't already.
  310.  *
  311.  *----------------------------------------------------------------------
  312.  */
  313. void
  314. TkpGetShadows(borderPtr, tkwin)
  315.     TkBorder *borderPtr; /* Information about border. */
  316.     Tk_Window tkwin; /* Window where border will be used for
  317.  * drawing. */
  318. {
  319.     XColor lightColor, darkColor;
  320.     int tmp1, tmp2;
  321.     int r, g, b;
  322.     XGCValues gcValues;
  323.     if (borderPtr->lightGC != None) {
  324. return;
  325.     }
  326.     /*
  327.      * Handle the special case of the default system colors.
  328.      */
  329.     if ((TkWinIndexOfColor(borderPtr->bgColorPtr) == COLOR_3DFACE)
  330. || (TkWinIndexOfColor(borderPtr->bgColorPtr) == COLOR_WINDOW)) {
  331. borderPtr->darkColorPtr = Tk_GetColor(NULL, tkwin,
  332.     Tk_GetUid("SystemButtonShadow"));
  333. gcValues.foreground = borderPtr->darkColorPtr->pixel;
  334. borderPtr->darkGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  335. borderPtr->lightColorPtr = Tk_GetColor(NULL, tkwin,
  336.     Tk_GetUid("SystemButtonHighlight"));
  337. gcValues.foreground = borderPtr->lightColorPtr->pixel;
  338. borderPtr->lightGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  339. ((WinBorder*)borderPtr)->dark2ColorPtr = Tk_GetColor(NULL, tkwin,
  340. Tk_GetUid("System3dDarkShadow"));
  341. ((WinBorder*)borderPtr)->light2ColorPtr = Tk_GetColor(NULL, tkwin,
  342. Tk_GetUid("System3dLight"));
  343. return;
  344.     } else {
  345. darkColor.red = 0;
  346. darkColor.green = 0;
  347. darkColor.blue = 0;
  348. ((WinBorder*)borderPtr)->dark2ColorPtr = Tk_GetColorByValue(tkwin,
  349.     &darkColor);
  350. lightColor = *(borderPtr->bgColorPtr);
  351. ((WinBorder*)borderPtr)->light2ColorPtr = Tk_GetColorByValue(tkwin, 
  352.     &lightColor);
  353.     }
  354.     
  355.     /*
  356.      * First, handle the case of a color display with lots of colors.
  357.      * The shadow colors get computed using whichever formula results
  358.      * in the greatest change in color:
  359.      * 1. Lighter shadow is half-way to white, darker shadow is half
  360.      *    way to dark.
  361.      * 2. Lighter shadow is 40% brighter than background, darker shadow
  362.      *    is 40% darker than background.
  363.      */
  364.     if (Tk_Depth(tkwin) >= 6) {
  365. /*
  366.  * This is a color display with lots of colors.  For the dark
  367.  * shadow, cut 40% from each of the background color components.
  368.  * But if the background is already very dark, make the
  369.  * dark color a little lighter than the background by increasing
  370.  * each color component 1/4th of the way to MAX_INTENSITY.
  371.  *
  372.  * For the light shadow, boost each component by 40% or half-way
  373.  * to white, whichever is greater (the first approach works
  374.  * better for unsaturated colors, the second for saturated ones).
  375.  * But if the background is already very bright, instead choose a
  376.  * slightly darker color for the light shadow by reducing each
  377.  * color component by 10%.
  378.  *
  379.  * Compute the colors using integers, not using lightColor.red
  380.  * etc.: these are shorts and may have problems with integer
  381.  * overflow.
  382.  */
  383. /*
  384.  * Compute the dark shadow color
  385.  */
  386. r = (int) borderPtr->bgColorPtr->red;
  387. g = (int) borderPtr->bgColorPtr->green;
  388. b = (int) borderPtr->bgColorPtr->blue;
  389. if (r*0.5*r + g*1.0*g + b*0.28*b < MAX_INTENSITY*0.05*MAX_INTENSITY) {
  390.     darkColor.red = (MAX_INTENSITY + 3*r)/4;
  391.     darkColor.green = (MAX_INTENSITY + 3*g)/4;
  392.     darkColor.blue = (MAX_INTENSITY + 3*b)/4;
  393. } else {
  394.     darkColor.red = (60 * r)/100;
  395.     darkColor.green = (60 * g)/100;
  396.     darkColor.blue = (60 * b)/100;
  397. }
  398. /*
  399.  * Allocate the dark shadow color and its GC
  400.  */
  401. borderPtr->darkColorPtr = Tk_GetColorByValue(tkwin, &darkColor);
  402. gcValues.foreground = borderPtr->darkColorPtr->pixel;
  403. borderPtr->darkGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  404. /*
  405.  * Compute the light shadow color
  406.  */
  407. if (g > MAX_INTENSITY*0.95) {
  408.     lightColor.red = (90 * r)/100;
  409.     lightColor.green = (90 * g)/100;
  410.     lightColor.blue = (90 * b)/100;
  411. } else {
  412.     tmp1 = (14 * r)/10;
  413.     if (tmp1 > MAX_INTENSITY) {
  414. tmp1 = MAX_INTENSITY;
  415.     }
  416.     tmp2 = (MAX_INTENSITY + r)/2;
  417.     lightColor.red = (tmp1 > tmp2) ? tmp1 : tmp2;
  418.     tmp1 = (14 * g)/10;
  419.     if (tmp1 > MAX_INTENSITY) {
  420. tmp1 = MAX_INTENSITY;
  421.     }
  422.     tmp2 = (MAX_INTENSITY + g)/2;
  423.     lightColor.green = (tmp1 > tmp2) ? tmp1 : tmp2;
  424.     tmp1 = (14 * b)/10;
  425.     if (tmp1 > MAX_INTENSITY) {
  426. tmp1 = MAX_INTENSITY;
  427.     }
  428.     tmp2 = (MAX_INTENSITY + b)/2;
  429.     lightColor.blue = (tmp1 > tmp2) ? tmp1 : tmp2;
  430. }
  431.        /*
  432.         * Allocate the light shadow color and its GC
  433.         */
  434. borderPtr->lightColorPtr = Tk_GetColorByValue(tkwin, &lightColor);
  435. gcValues.foreground = borderPtr->lightColorPtr->pixel;
  436. borderPtr->lightGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  437. return;
  438.     }
  439.     if (borderPtr->shadow == None) {
  440. borderPtr->shadow = Tk_GetBitmap((Tcl_Interp *) NULL, tkwin,
  441. Tk_GetUid("gray50"));
  442. if (borderPtr->shadow == None) {
  443.     panic("TkpGetShadows couldn't allocate bitmap for border");
  444. }
  445.     }
  446.     if (borderPtr->visual->map_entries > 2) {
  447. /*
  448.  * This isn't a monochrome display, but the colormap either
  449.  * ran out of entries or didn't have very many to begin with.
  450.  * Generate the light shadows with a white stipple and the
  451.  * dark shadows with a black stipple.
  452.  */
  453. gcValues.foreground = borderPtr->bgColorPtr->pixel;
  454. gcValues.background = BlackPixelOfScreen(borderPtr->screen);
  455. gcValues.stipple = borderPtr->shadow;
  456. gcValues.fill_style = FillOpaqueStippled;
  457. borderPtr->darkGC = Tk_GetGC(tkwin,
  458. GCForeground|GCBackground|GCStipple|GCFillStyle, &gcValues);
  459. gcValues.foreground = WhitePixelOfScreen(borderPtr->screen);
  460. gcValues.background = borderPtr->bgColorPtr->pixel;
  461. borderPtr->lightGC = Tk_GetGC(tkwin,
  462. GCForeground|GCBackground|GCStipple|GCFillStyle, &gcValues);
  463. return;
  464.     }
  465.     /*
  466.      * This is just a measly monochrome display, hardly even worth its
  467.      * existence on this earth.  Make one shadow a 50% stipple and the
  468.      * other the opposite of the background.
  469.      */
  470.     gcValues.foreground = WhitePixelOfScreen(borderPtr->screen);
  471.     gcValues.background = BlackPixelOfScreen(borderPtr->screen);
  472.     gcValues.stipple = borderPtr->shadow;
  473.     gcValues.fill_style = FillOpaqueStippled;
  474.     borderPtr->lightGC = Tk_GetGC(tkwin,
  475.     GCForeground|GCBackground|GCStipple|GCFillStyle, &gcValues);
  476.     if (borderPtr->bgColorPtr->pixel
  477.     == WhitePixelOfScreen(borderPtr->screen)) {
  478. gcValues.foreground = BlackPixelOfScreen(borderPtr->screen);
  479. borderPtr->darkGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  480.     } else {
  481. borderPtr->darkGC = borderPtr->lightGC;
  482. borderPtr->lightGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  483.     }
  484. }
  485. /*
  486.  *----------------------------------------------------------------------
  487.  *
  488.  * TkWinGetBorderPixels --
  489.  *
  490.  * This routine returns the 5 COLORREFs used to draw a given
  491.  * 3d border.  
  492.  *
  493.  * Results:
  494.  * Returns the colors in the specified array.
  495.  *
  496.  * Side effects:
  497.  * May cause the remaining colors to be allocated.
  498.  *
  499.  *----------------------------------------------------------------------
  500.  */
  501. COLORREF
  502. TkWinGetBorderPixels(tkwin, border, which)
  503.     Tk_Window tkwin;
  504.     Tk_3DBorder border;
  505.     int which; /* One of TK_3D_FLAT_GC, TK_3D_LIGHT_GC,
  506.  * TK_3D_DARK_GC, TK_3D_LIGHT2, TK_3D_DARK2 */
  507. {
  508.     WinBorder *borderPtr = (WinBorder *) border;
  509.     
  510.     if (borderPtr->info.lightGC == None) {
  511. TkpGetShadows(&borderPtr->info, tkwin);
  512.     }
  513.     switch (which) {
  514. case TK_3D_FLAT_GC:
  515.     return borderPtr->info.bgColorPtr->pixel;
  516. case TK_3D_LIGHT_GC:
  517.     if (borderPtr->info.lightColorPtr == NULL) {
  518. return WhitePixelOfScreen(borderPtr->info.screen);
  519.     }
  520.     return borderPtr->info.lightColorPtr->pixel;
  521. case TK_3D_DARK_GC:
  522.     if (borderPtr->info.darkColorPtr == NULL) {
  523. return BlackPixelOfScreen(borderPtr->info.screen);
  524.     }
  525.     return borderPtr->info.darkColorPtr->pixel;
  526. case TK_3D_LIGHT2:
  527.     return borderPtr->light2ColorPtr->pixel;
  528. case TK_3D_DARK2:
  529.     return borderPtr->dark2ColorPtr->pixel;
  530.     }
  531.     return 0;
  532. }