1 /* Tabs Widget for XEmacs.
2 Copyright (C) 1999 Edward A. Falk
4 This file is part of XEmacs.
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 /* Synched up with: Gcs.c 1.7 */
23 /* #### This code is duplicated many times within lwlib and XEmacs. It
24 should be modularised. */
27 * Gcs.c - Utility functions to allocate GCs.
29 * Author: Edward A. Falk
30 * falk@falconer.vip.best.com
37 * GC AllocFgGC(w, fg, font)
38 * Return a GC with foreground set as specified.
39 * If font is None, then the returned GC is allocated with font specified
40 * as a "don't care" value.
43 * AllocBackgroundGC(w, font)
44 * Return a GC with the foreground set to the widget's background color.
47 * AllocGreyGC(w, fg, font, contrast, be_nice_to_cmap)
52 * int be_nice_to_cmap ;
54 * Return a GC suitable for rendering a widget in its "inactive" color.
55 * Normally returns a GC with a color somewhere between the widget's
56 * background color and the specified foreground. If font is None, then
57 * the returned GC is allocated with font specified as "don't care".
58 * If be_nice_to_cmap is True, the returned GC is created using a 50%
59 * dither instead of a new color.
63 * AllocShadeGC(w, fg, bg, font, contrast, be_nice_to_cmap)
68 * int be_nice_to_cmap ;
70 * Return a GC suitable for rendering in a shade somewhere between
71 * bg and fg, as determined by contrast (0 = bg, 100 = fg)
72 * If font is None, then the returned GC is allocated with
73 * font specified as "don't care". If be_nice_to_cmap
74 * is True, the returned GC is created using a 50% dither
75 * instead of a new color.
79 * AllocTopShadowGC(w, contrast, be_nice_to_cmap)
80 * Return a GC suitable for rendering the "top shadow" decorations of
81 * a widget. Returns a GC with foreground computed from widget's
82 * background color and contrast. If be_nice_to_cmap is True, the
83 * returned GC will use a foreground color of white. If widget depth
84 * is 1, this function will use a foreground color of black.
87 * AllocBotShadowGC(w, contrast, be_nice_to_cmap)
88 * Return a GC suitable for rendering the "bottom shadow" decorations
89 * of a widget. Returns a GC with foreground computed from widget's
90 * background color and contrast. If be_nice_to_cmap is True, the
91 * returned GC will use a foreground color of black.
94 * AllocArmGC(w, contrast, be_nice_to_cmap)
95 * Return a GC suitable for rendering the "armed" decorations of a
96 * widget. This GC would typically be used to fill in the widget's
97 * background. Returns a GC with foreground computed from widget's
98 * background color and contrast. If be_nice_to_cmap is True, the
99 * returned GC will use a foreground color of black and a 50% dither.
103 * Draw3dBox(w, x,y,wid,hgt,s, topgc, botgc)
104 * Utility function. Draws a raised shadow box with outside dimensions
105 * as specified by x,y,wid,hgt and shadow width specified by s.
106 * A lowered shadow box may be generated by swapping topgc and botgc.
113 #include <X11/Xlib.h>
114 #include <X11/IntrinsicP.h>
115 #include <X11/StringDefs.h>
116 #include "../src/xmu.h"
119 /* Color & GC allocation.
121 * Frame widgets use the following graphics contexts:
123 * Foreground tab label text drawn this way
124 * Insensitive Fg foreground color greyed out.
125 * Background frame background color
126 * Top shadow upper-left highlight around widget
127 * Bottom shadow lower-right highlight around widget
128 * Arm shadow button pressed and ready to be released
131 * GC's are defined as follows, depending on attributes and
135 * Foreground = foreground color attribute or BlackPixel()
136 * Grey = Foreground color + 50% dither
137 * Background = background color attribute or WhitePixel()
138 * top shadow = foreground
139 * bottom shadow = foreground
140 * arm shadow = (what?)
142 * Color, beNiceToColormap=true:
143 * Foreground = foreground color attribute or BlackPixel()
144 * Grey = Foreground color + 50% dither
145 * Background = background color attribute or WhitePixel()
147 * bottom shadow = black
148 * arm shadow = (what?)
150 * Color, beNiceToColormap=false:
151 * Foreground = foreground color attribute or BlackPixel()
152 * Grey = (foreground color + background color)/2
153 * Background = background color attribute or WhitePixel()
154 * top shadow = background * 1.2
155 * bottom shadow = background * .6
156 * arm shadow = background * .8
159 * If background is white, ??
160 * if background is black, ??
163 * If the widget's background is solid white or solid black,
164 * this code just picks some numbers. (The choice is designed
165 * to be compatible with ThreeD interface.)
170 #if XtSpecificationRelease < 5
172 static GC XtAllocateGC(Widget, int, unsigned long, XGCValues *,
173 unsigned long, unsigned long) ;
178 #if NeedFunctionPrototypes
179 static Pixmap getDitherPixmap(Widget, int contrast) ;
181 static Pixmap getDitherPixmap() ;
184 /* return a GC with the specified foreground and optional font */
187 AllocFgGC(Widget w, Pixel fg, Font font)
190 unsigned long vmask, dcmask ;
192 values.foreground = fg ;
196 vmask = GCForeground|GCFont ;
197 dcmask = GCSubwindowMode|GCDashOffset|
198 GCDashList|GCArcMode|GCBackground|GCGraphicsExposures ;
200 vmask = GCForeground ;
201 dcmask = GCFont|GCSubwindowMode|GCDashOffset|
202 GCDashList|GCArcMode|GCBackground|GCGraphicsExposures ;
205 return XtAllocateGC(w, w->core.depth, vmask, &values, 0L, dcmask) ;
209 /* return gc with widget background color as the foreground */
212 AllocBackgroundGC(Widget w, Font font)
214 return AllocFgGC(w, w->core.background_pixel, font) ;
218 /* Allocate an "inactive" GC. Color is grey (possibly via
223 AllocGreyGC(Widget w, Pixel fg, Font font, int contrast, Bool be_nice_to_cmap)
225 return AllocShadeGC(w, fg, w->core.background_pixel,
226 font, contrast, be_nice_to_cmap) ;
230 /* Allocate a GC somewhere between two colors. */
233 AllocShadeGC(Widget w, Pixel fg, Pixel bg, Font font,
234 int contrast, Bool be_nice_to_cmap)
237 unsigned long vmask, dcmask ;
239 values.foreground = fg ;
240 values.background = bg ;
244 vmask = GCForeground|GCFont ;
245 dcmask = GCSubwindowMode|GCDashOffset|
246 GCDashList|GCArcMode|GCGraphicsExposures ;
248 vmask = GCForeground;
249 dcmask = GCFont|GCSubwindowMode|GCDashOffset|
250 GCDashList|GCArcMode|GCGraphicsExposures ;
253 if( be_nice_to_cmap || w->core.depth == 1)
256 values.foreground = bg ;
257 else if( contrast >= 95 )
258 values.foreground = fg ;
260 vmask |= GCBackground|GCStipple|GCFillStyle ;
261 values.fill_style = FillOpaqueStippled ;
262 values.stipple = getDitherPixmap(w, contrast) ;
265 return XtAllocateGC(w, w->core.depth, vmask, &values, 0L, dcmask) ;
270 dcmask |= GCBackground ;
271 values.foreground = AllocGreyPixel(w, fg, bg, contrast) ;
272 return XtAllocateGC(w, w->core.depth, vmask, &values, 0L, dcmask) ;
276 /* return top-shadow gc. */
279 AllocTopShadowGC(Widget w, int contrast, Bool be_nice_to_cmap)
281 Screen *scr = XtScreen (w);
284 if( w->core.depth == 1 )
285 values.foreground = BlackPixelOfScreen(scr) ;
286 else if( be_nice_to_cmap )
287 values.foreground = WhitePixelOfScreen(scr) ;
289 values.foreground = AllocShadowPixel(w, 100+contrast) ;
291 return XtAllocateGC(w, w->core.depth,
292 GCForeground, &values,
294 GCBackground|GCFont|GCSubwindowMode|GCGraphicsExposures|
295 GCDashOffset|GCDashList|GCArcMode) ;
298 /* return bottom-shadow gc. */
301 AllocBotShadowGC(Widget w, int contrast, Bool be_nice_to_cmap)
303 Screen *scr = XtScreen (w);
306 if( w->core.depth == 1 || be_nice_to_cmap )
307 values.foreground = BlackPixelOfScreen(scr) ;
309 values.foreground = AllocShadowPixel(w, 100-contrast) ;
311 return XtAllocateGC(w, w->core.depth,
312 GCForeground, &values,
314 GCBackground|GCFont|GCSubwindowMode|GCGraphicsExposures|
315 GCDashOffset|GCDashList|GCArcMode) ;
318 /* return arm-shadow gc. */
321 AllocArmGC(Widget w, int contrast, Bool be_nice_to_cmap)
323 Screen *scr = XtScreen (w);
326 /* Not clear exactly what we should do here. Take a look at
327 * Xaw3d to see what they do.
330 if( w->core.depth == 1 || be_nice_to_cmap )
332 values.background = w->core.background_pixel ;
333 if( values.background == BlackPixelOfScreen(scr) )
334 values.foreground = WhitePixelOfScreen(scr) ;
336 values.foreground = BlackPixelOfScreen(scr) ;
337 values.fill_style = FillStippled ;
338 values.stipple = XmuCreateStippledPixmap(XtScreen(w), 1L, 0L, 1) ;
340 return XtAllocateGC(w, w->core.depth,
341 GCForeground|GCBackground|GCStipple|GCFillStyle,
343 GCFont|GCSubwindowMode|GCGraphicsExposures|
344 GCDashOffset|GCDashList|GCArcMode) ;
349 values.foreground = AllocShadowPixel(w, 100-contrast) ;
350 return XtAllocateGC(w, w->core.depth,
351 GCForeground, &values,
353 GCBackground|GCFont|GCSubwindowMode|GCGraphicsExposures|
354 GCDashOffset|GCDashList|GCArcMode) ;
360 AllocShadowPixel(Widget w, int scale)
362 XColor get_c, set_c ;
363 Display *dpy = XtDisplay(w) ;
364 Screen *scr = XtScreen(w) ;
368 cmap = w->core.colormap ;
370 get_c.pixel = w->core.background_pixel ;
371 if( get_c.pixel == WhitePixelOfScreen(scr) ||
372 get_c.pixel == BlackPixelOfScreen(scr) )
374 /* what we *ought* to do is choose gray75 as the base color,
375 * or perhaps gray83. Instead, we choose colors that are
376 * the same as ThreeD would choose.
378 if( scale > 100 ) scale = 200 - scale ;
379 set_c.red = set_c.green = set_c.blue = 65535*scale/100 ;
383 XQueryColor(dpy, cmap, &get_c) ;
384 /* adjust scale so that brightest component does not
385 * exceed 65535; otherwise hue would change.
388 maxColor = Max(get_c.red, Max(get_c.green, get_c.blue)) ;
389 if( scale*maxColor > 65535*100 )
390 scale = 65535*100/maxColor ;
392 set_c.red = scale * get_c.red / 100 ;
393 set_c.green = scale * get_c.green / 100 ;
394 set_c.blue = scale * get_c.blue / 100 ;
396 set_c.flags = DoRed | DoGreen | DoBlue ;
397 if( XAllocColor(dpy, cmap, &set_c) )
399 else if( scale > 100 )
400 return WhitePixelOfScreen(scr) ;
402 return BlackPixelOfScreen(scr) ;
406 /* Allocate a pixel partway between foreground and background */
410 AllocGreyPixel(Widget w, Pixel fg, Pixel bg, int scale)
412 XColor get_cf, get_cb ;
413 Display *dpy = XtDisplay(w) ;
416 cmap = w->core.colormap ;
421 XQueryColor(dpy, cmap, &get_cf) ;
422 XQueryColor(dpy, cmap, &get_cb) ;
424 return AllocGreyPixelC(w, &get_cf, &get_cb, scale) ;
429 /* Allocate a pixel partway between foreground and background */
433 AllocGreyPixelC(Widget w, XColor *fg, XColor *bg, int scale)
436 Display *dpy = XtDisplay(w) ;
438 Colormap cmap = w->core.colormap ;
440 r = (fg->red * scale + bg->red * (100-scale)) / 100 ;
441 g = (fg->green * scale + bg->green * (100-scale)) / 100 ;
442 b = (fg->blue * scale + bg->blue * (100-scale)) / 100 ;
444 if( scale > 100 || scale < 0 ) /* look out for overflow */
447 maxc = Max(r, Max(g,b)) ;
448 minc = Min(r, Min(g,b)) ;
452 r = r*(65535/16) / maxc ;
453 g = g*(65535/16) / maxc ;
454 b = b*(65535/16) / maxc ;
464 set_c.red = r ; set_c.green = g ; set_c.blue = b ;
465 set_c.flags = DoRed | DoGreen | DoBlue ;
466 (void)XAllocColor(dpy, cmap, &set_c) ;
477 Draw3dBox(Widget w, int x, int y, int wid, int hgt, int s, GC topgc, GC botgc)
479 Display *dpy = XtDisplay(w) ;
480 Window win = XtWindow(w) ;
482 if( s == 0 ) return ;
485 XDrawLine(dpy,win,botgc, x,y+hgt-1, x+wid-1,y+hgt-1) ;
486 XDrawLine(dpy,win,botgc, x+wid-1,y, x+wid-1,y+hgt-1) ;
487 XDrawLine(dpy,win,topgc, x,y, x,y+hgt-1) ;
488 XDrawLine(dpy,win,topgc, x,y, x+wid-1,y) ;
494 /* bottom-right shadow */
495 pts[0].x = x ; pts[0].y = y + hgt ;
496 pts[1].x = s ; pts[1].y = -s ;
497 pts[2].x = wid-2*s ; pts[2].y = 0 ;
498 pts[3].x = 0 ; pts[3].y = -(hgt-2*s) ;
499 pts[4].x = s ; pts[4].y = -s ;
500 pts[5].x = 0 ; pts[5].y = hgt ;
501 XFillPolygon(dpy,win,botgc, pts,6, Nonconvex,CoordModePrevious) ;
503 /* top-left shadow */
504 pts[0].x = x ; pts[0].y = y ;
505 pts[1].x = wid ; pts[1].y = 0 ;
506 pts[2].x = -s ; pts[2].y = s ;
507 pts[3].x = -wid+2*s ; pts[3].y = 0 ;
508 pts[4].x = 0 ; pts[4].y = hgt-2*s ;
509 pts[5].x = -s ; pts[5].y = s ;
510 XFillPolygon(dpy,win,topgc, pts,6, Nonconvex,CoordModePrevious) ;
514 #if XtSpecificationRelease < 5
517 XtAllocateGC(Widget w, int depth, unsigned long mask, XGCValues *values,
518 unsigned long dynamic, unsigned long dontcare)
520 return XtGetGC(w, mask, values) ;
527 static unsigned char screen0[2] = {0,0} ;
528 static unsigned char screen25[2] = {0,0xaa} ;
529 static unsigned char screen75[2] = {0xaa,0xff} ;
530 static unsigned char screen100[2] = {0xff,0xff} ;
533 getDitherPixmap(Widget w, int contrast)
535 Display *dpy = XtDisplay(w) ;
536 Window win = XtWindow(w) ;
539 return XCreateBitmapFromData(dpy,win, (char *)screen0, 2,2) ;
540 else if( contrast <= 37 )
541 return XCreateBitmapFromData(dpy,win, (char *)screen25, 2,2) ;
542 else if( contrast <= 62 )
543 return XmuCreateStippledPixmap(XtScreen(w), 1L, 0L, 1) ;
544 else if( contrast <= 95 )
545 return XCreateBitmapFromData(dpy,win, (char *)screen75, 2,2) ;
547 return XCreateBitmapFromData(dpy,win, (char *)screen100, 2,2) ;
550 #endif /* HAVE_XMU */