4 * This file contains the platform specific routines for
5 * drawing 3d borders in the Windows 95 style.
7 * Copyright (c) 1996 by Sun Microsystems, Inc.
9 * See the file "license.terms" for information on usage and redistribution
10 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
19 * This structure is used to keep track of the extra colors used by
25 XColor *light2ColorPtr; /* System3dLight */
26 XColor *dark2ColorPtr; /* System3dDarkShadow */
31 *----------------------------------------------------------------------
35 * This function allocates a new TkBorder structure.
38 * Returns a newly allocated TkBorder.
43 *----------------------------------------------------------------------
49 WinBorder *borderPtr = (WinBorder *) ckalloc(sizeof(WinBorder));
50 borderPtr->light2ColorPtr = NULL;
51 borderPtr->dark2ColorPtr = NULL;
52 return (TkBorder *) borderPtr;
56 *----------------------------------------------------------------------
60 * This function frees any colors allocated by the platform
61 * specific part of this module.
67 * May deallocate some colors.
69 *----------------------------------------------------------------------
73 TkpFreeBorder(borderPtr)
76 WinBorder *winBorderPtr = (WinBorder *) borderPtr;
77 if (winBorderPtr->light2ColorPtr) {
78 Tk_FreeColor(winBorderPtr->light2ColorPtr);
80 if (winBorderPtr->dark2ColorPtr) {
81 Tk_FreeColor(winBorderPtr->dark2ColorPtr);
86 *--------------------------------------------------------------
88 * Tk_3DVerticalBevel --
90 * This procedure draws a vertical bevel along one side of
91 * an object. The bevel is always rectangular in shape:
98 * An appropriate shadow color is chosen for the bevel based
99 * on the leftBevel and relief arguments. Normally this
100 * procedure is called first, then Tk_3DHorizontalBevel is
101 * called next to draw neat corners.
107 * Graphics are drawn in drawable.
109 *--------------------------------------------------------------
113 Tk_3DVerticalBevel(tkwin, drawable, border, x, y, width, height,
115 Tk_Window tkwin; /* Window for which border was allocated. */
116 Drawable drawable; /* X window or pixmap in which to draw. */
117 Tk_3DBorder border; /* Token for border to draw. */
118 int x, y, width, height; /* Area of vertical bevel. */
119 int leftBevel; /* Non-zero means this bevel forms the
120 * left side of the object; 0 means it
121 * forms the right side. */
122 int relief; /* Kind of bevel to draw. For example,
123 * TK_RELIEF_RAISED means interior of
124 * object should appear higher than
127 TkBorder *borderPtr = (TkBorder *) border;
129 Display *display = Tk_Display(tkwin);
131 HDC dc = TkWinGetDrawableDC(display, drawable, &state);
134 if ((borderPtr->lightGC == None) && (relief != TK_RELIEF_FLAT)) {
135 TkpGetShadows(borderPtr, tkwin);
139 case TK_RELIEF_RAISED:
141 ? borderPtr->lightGC->foreground
142 : borderPtr->darkGC->foreground;
144 ? ((WinBorder *)borderPtr)->light2ColorPtr->pixel
145 : ((WinBorder *)borderPtr)->dark2ColorPtr->pixel;
147 case TK_RELIEF_SUNKEN:
149 ? borderPtr->darkGC->foreground
150 : ((WinBorder *)borderPtr)->light2ColorPtr->pixel;
152 ? ((WinBorder *)borderPtr)->dark2ColorPtr->pixel
153 : borderPtr->lightGC->foreground;
155 case TK_RELIEF_RIDGE:
156 left = borderPtr->lightGC->foreground;
157 right = borderPtr->darkGC->foreground;
159 case TK_RELIEF_GROOVE:
160 left = borderPtr->darkGC->foreground;
161 right = borderPtr->lightGC->foreground;
164 left = right = borderPtr->bgGC->foreground;
166 case TK_RELIEF_SOLID:
167 left = right = RGB(0,0,0);
171 if (leftBevel && (width & 1)) {
174 TkWinFillRect(dc, x, y, half, height, left);
175 TkWinFillRect(dc, x+half, y, width-half, height, right);
176 TkWinReleaseDrawableDC(drawable, dc, &state);
180 *--------------------------------------------------------------
182 * Tk_3DHorizontalBevel --
184 * This procedure draws a horizontal bevel along one side of
185 * an object. The bevel has mitered corners (depending on
186 * leftIn and rightIn arguments).
194 *--------------------------------------------------------------
198 Tk_3DHorizontalBevel(tkwin, drawable, border, x, y, width, height,
199 leftIn, rightIn, topBevel, relief)
200 Tk_Window tkwin; /* Window for which border was allocated. */
201 Drawable drawable; /* X window or pixmap in which to draw. */
202 Tk_3DBorder border; /* Token for border to draw. */
203 int x, y, width, height; /* Bounding box of area of bevel. Height
204 * gives width of border. */
205 int leftIn, rightIn; /* Describes whether the left and right
206 * edges of the bevel angle in or out as
207 * they go down. For example, if "leftIn"
208 * is true, the left side of the bevel
215 int topBevel; /* Non-zero means this bevel forms the
216 * top side of the object; 0 means it
217 * forms the bottom side. */
218 int relief; /* Kind of bevel to draw. For example,
219 * TK_RELIEF_RAISED means interior of
220 * object should appear higher than
223 TkBorder *borderPtr = (TkBorder *) border;
224 Display *display = Tk_Display(tkwin);
225 int bottom, halfway, x1, x2, x1Delta, x2Delta;
227 HDC dc = TkWinGetDrawableDC(display, drawable, &state);
228 int topColor, bottomColor;
230 if ((borderPtr->lightGC == None) && (relief != TK_RELIEF_FLAT)) {
231 TkpGetShadows(borderPtr, tkwin);
235 * Compute a GC for the top half of the bevel and a GC for the
236 * bottom half (they're the same in many cases).
240 case TK_RELIEF_RAISED:
241 topColor = (topBevel)
242 ? borderPtr->lightGC->foreground
243 : borderPtr->darkGC->foreground;
244 bottomColor = (topBevel)
245 ? ((WinBorder *)borderPtr)->light2ColorPtr->pixel
246 : ((WinBorder *)borderPtr)->dark2ColorPtr->pixel;
248 case TK_RELIEF_SUNKEN:
249 topColor = (topBevel)
250 ? borderPtr->darkGC->foreground
251 : ((WinBorder *)borderPtr)->light2ColorPtr->pixel;
252 bottomColor = (topBevel)
253 ? ((WinBorder *)borderPtr)->dark2ColorPtr->pixel
254 : borderPtr->lightGC->foreground;
256 case TK_RELIEF_RIDGE:
257 topColor = borderPtr->lightGC->foreground;
258 bottomColor = borderPtr->darkGC->foreground;
260 case TK_RELIEF_GROOVE:
261 topColor = borderPtr->darkGC->foreground;
262 bottomColor = borderPtr->lightGC->foreground;
265 topColor = bottomColor = borderPtr->bgGC->foreground;
267 case TK_RELIEF_SOLID:
268 topColor = bottomColor = RGB(0,0,0);
272 * Compute various other geometry-related stuff.
286 x1Delta = (leftIn) ? 1 : -1;
287 x2Delta = (rightIn) ? -1 : 1;
288 halfway = y + height/2;
289 if (topBevel && (height & 1)) {
295 * Draw one line for each y-coordinate covered by the bevel.
298 for ( ; y < bottom; y++) {
300 * In some weird cases (such as large border widths for skinny
301 * rectangles) x1 can be >= x2. Don't draw the lines
306 TkWinFillRect(dc, x1, y, x2-x1, 1,
307 (y < halfway) ? topColor : bottomColor);
312 TkWinReleaseDrawableDC(drawable, dc, &state);
316 *----------------------------------------------------------------------
320 * This procedure computes the shadow colors for a 3-D border
321 * and fills in the corresponding fields of the Border structure.
322 * It's called lazily, so that the colors aren't allocated until
323 * something is actually drawn with them. That way, if a border
324 * is only used for flat backgrounds the shadow colors will
325 * never be allocated.
331 * The lightGC and darkGC fields in borderPtr get filled in,
332 * if they weren't already.
334 *----------------------------------------------------------------------
338 TkpGetShadows(borderPtr, tkwin)
339 TkBorder *borderPtr; /* Information about border. */
340 Tk_Window tkwin; /* Window where border will be used for
343 XColor lightColor, darkColor;
347 if (borderPtr->lightGC != None) {
352 * Handle the special case of the default system colors.
355 if ((TkWinIndexOfColor(borderPtr->bgColorPtr) == COLOR_3DFACE)
356 || (TkWinIndexOfColor(borderPtr->bgColorPtr) == COLOR_WINDOW)) {
357 borderPtr->darkColorPtr = Tk_GetColor(NULL, tkwin,
358 Tk_GetUid("SystemButtonShadow"));
359 gcValues.foreground = borderPtr->darkColorPtr->pixel;
360 borderPtr->darkGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
361 borderPtr->lightColorPtr = Tk_GetColor(NULL, tkwin,
362 Tk_GetUid("SystemButtonHighlight"));
363 gcValues.foreground = borderPtr->lightColorPtr->pixel;
364 borderPtr->lightGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
365 ((WinBorder*)borderPtr)->dark2ColorPtr = Tk_GetColor(NULL, tkwin,
366 Tk_GetUid("System3dDarkShadow"));
367 ((WinBorder*)borderPtr)->light2ColorPtr = Tk_GetColor(NULL, tkwin,
368 Tk_GetUid("System3dLight"));
374 ((WinBorder*)borderPtr)->dark2ColorPtr = Tk_GetColorByValue(tkwin,
376 lightColor = *(borderPtr->bgColorPtr);
377 ((WinBorder*)borderPtr)->light2ColorPtr = Tk_GetColorByValue(tkwin,
382 * First, handle the case of a color display with lots of colors.
383 * The shadow colors get computed using whichever formula results
384 * in the greatest change in color:
385 * 1. Lighter shadow is half-way to white, darker shadow is half
387 * 2. Lighter shadow is 40% brighter than background, darker shadow
388 * is 40% darker than background.
391 if (Tk_Depth(tkwin) >= 6) {
393 * This is a color display with lots of colors. For the dark
394 * shadow, cut 40% from each of the background color components.
395 * For the light shadow, boost each component by 40% or half-way
396 * to white, whichever is greater (the first approach works
397 * better for unsaturated colors, the second for saturated ones).
400 darkColor.red = (60 * (int) borderPtr->bgColorPtr->red)/100;
401 darkColor.green = (60 * (int) borderPtr->bgColorPtr->green)/100;
402 darkColor.blue = (60 * (int) borderPtr->bgColorPtr->blue)/100;
403 borderPtr->darkColorPtr = Tk_GetColorByValue(tkwin, &darkColor);
404 gcValues.foreground = borderPtr->darkColorPtr->pixel;
405 borderPtr->darkGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
408 * Compute the colors using integers, not using lightColor.red
409 * etc.: these are shorts and may have problems with integer
413 tmp1 = (14 * (int) borderPtr->bgColorPtr->red)/10;
414 if (tmp1 > MAX_INTENSITY) {
415 tmp1 = MAX_INTENSITY;
417 tmp2 = (MAX_INTENSITY + (int) borderPtr->bgColorPtr->red)/2;
418 lightColor.red = (tmp1 > tmp2) ? tmp1 : tmp2;
419 tmp1 = (14 * (int) borderPtr->bgColorPtr->green)/10;
420 if (tmp1 > MAX_INTENSITY) {
421 tmp1 = MAX_INTENSITY;
423 tmp2 = (MAX_INTENSITY + (int) borderPtr->bgColorPtr->green)/2;
424 lightColor.green = (tmp1 > tmp2) ? tmp1 : tmp2;
425 tmp1 = (14 * (int) borderPtr->bgColorPtr->blue)/10;
426 if (tmp1 > MAX_INTENSITY) {
427 tmp1 = MAX_INTENSITY;
429 tmp2 = (MAX_INTENSITY + (int) borderPtr->bgColorPtr->blue)/2;
430 lightColor.blue = (tmp1 > tmp2) ? tmp1 : tmp2;
431 borderPtr->lightColorPtr = Tk_GetColorByValue(tkwin, &lightColor);
432 gcValues.foreground = borderPtr->lightColorPtr->pixel;
433 borderPtr->lightGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
437 if (borderPtr->shadow == None) {
438 borderPtr->shadow = Tk_GetBitmap((Tcl_Interp *) NULL, tkwin,
439 Tk_GetUid("gray50"));
440 if (borderPtr->shadow == None) {
441 panic("TkpGetShadows couldn't allocate bitmap for border");
444 if (borderPtr->visual->map_entries > 2) {
446 * This isn't a monochrome display, but the colormap either
447 * ran out of entries or didn't have very many to begin with.
448 * Generate the light shadows with a white stipple and the
449 * dark shadows with a black stipple.
452 gcValues.foreground = borderPtr->bgColorPtr->pixel;
453 gcValues.background = BlackPixelOfScreen(borderPtr->screen);
454 gcValues.stipple = borderPtr->shadow;
455 gcValues.fill_style = FillOpaqueStippled;
456 borderPtr->darkGC = Tk_GetGC(tkwin,
457 GCForeground|GCBackground|GCStipple|GCFillStyle, &gcValues);
458 gcValues.foreground = WhitePixelOfScreen(borderPtr->screen);
459 gcValues.background = borderPtr->bgColorPtr->pixel;
460 borderPtr->lightGC = Tk_GetGC(tkwin,
461 GCForeground|GCBackground|GCStipple|GCFillStyle, &gcValues);
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.
471 gcValues.foreground = WhitePixelOfScreen(borderPtr->screen);
472 gcValues.background = BlackPixelOfScreen(borderPtr->screen);
473 gcValues.stipple = borderPtr->shadow;
474 gcValues.fill_style = FillOpaqueStippled;
475 borderPtr->lightGC = Tk_GetGC(tkwin,
476 GCForeground|GCBackground|GCStipple|GCFillStyle, &gcValues);
477 if (borderPtr->bgColorPtr->pixel
478 == WhitePixelOfScreen(borderPtr->screen)) {
479 gcValues.foreground = BlackPixelOfScreen(borderPtr->screen);
480 borderPtr->darkGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
482 borderPtr->darkGC = borderPtr->lightGC;
483 borderPtr->lightGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
488 *----------------------------------------------------------------------
490 * TkWinGetBorderPixels --
492 * This routine returns the 5 COLORREFs used to draw a given
496 * Returns the colors in the specified array.
499 * May cause the remaining colors to be allocated.
501 *----------------------------------------------------------------------
505 TkWinGetBorderPixels(tkwin, border, which)
508 int which; /* One of TK_3D_FLAT_GC, TK_3D_LIGHT_GC,
509 * TK_3D_DARK_GC, TK_3D_LIGHT2, TK_3D_DARK2 */
511 WinBorder *borderPtr = (WinBorder *) border;
513 if (borderPtr->info.lightGC == None) {
514 TkpGetShadows(&borderPtr->info, tkwin);
518 return borderPtr->info.bgColorPtr->pixel;
520 if (borderPtr->info.lightColorPtr == NULL) {
521 return WhitePixelOfScreen(borderPtr->info.screen);
523 return borderPtr->info.lightColorPtr->pixel;
525 if (borderPtr->info.darkColorPtr == NULL) {
526 return BlackPixelOfScreen(borderPtr->info.screen);
528 return borderPtr->info.darkColorPtr->pixel;
530 return borderPtr->light2ColorPtr->pixel;
532 return borderPtr->dark2ColorPtr->pixel;