This commit was generated by cvs2svn to compensate for changes in r4995,
[chise/xemacs-chise.git.1] / lwlib / xlwgcs.c
1  /* Tabs Widget for XEmacs.
2     Copyright (C) 1999 Edward A. Falk
3   
4  This file is part of XEmacs.
5  
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
9  later version.
10  
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
14  for more details.
15  
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.  */
20  
21 /* Synched up with: Gcs.c 1.7 */
22  
23  /* #### This code is duplicated many times within lwlib and XEmacs. It
24     should be modularised. */
25
26 /*
27  * Gcs.c - Utility functions to allocate GCs.
28  *
29  * Author: Edward A. Falk
30  *         falk@falconer.vip.best.com
31  *
32  * Date: Sept 29, 1998
33  */
34
35 /* Functions:
36  *
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.
41  *
42  * GC
43  * AllocBackgroundGC(w, font)
44  *      Return a GC with the foreground set to the widget's background color.
45  *
46  * GC
47  * AllocGreyGC(w, fg, font, contrast, be_nice_to_cmap)
48  *      Widget  w ;
49  *      Pixel   fg ;
50  *      Font    font ;
51  *      int     contrast ;
52  *      int     be_nice_to_cmap ;
53  *
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.
60  *
61  *
62  * GC
63  * AllocShadeGC(w, fg, bg, font, contrast, be_nice_to_cmap)
64  *      Widget  w ;
65  *      Pixel   fg, bg ;
66  *      Font    font ;
67  *      int     contrast ;
68  *      int     be_nice_to_cmap ;
69  *
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.
76  *
77  *
78  * GC
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.
85  *
86  * GC
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.
92  *
93  * GC
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.
100  *
101  *
102  * void
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.
107  *
108  */
109
110 #include        <config.h>
111 #include        <stdio.h>
112
113 #include        <X11/Xlib.h>
114 #include        <X11/IntrinsicP.h>
115 #include        <X11/StringDefs.h>
116 #include        "../src/xmu.h"
117 #include        "xlwgcs.h"
118
119         /* Color & GC allocation.
120          *
121          * Frame widgets use the following graphics contexts:
122          *
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
129          *
130          *
131          * GC's are defined as follows, depending on attributes and
132          * window depth:
133          *
134          * Monochrome:
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?)
141          *
142          * Color, beNiceToColormap=true:
143          *      Foreground = foreground color attribute or BlackPixel()
144          *      Grey = Foreground color + 50% dither
145          *      Background = background color attribute or WhitePixel()
146          *      top shadow = white
147          *      bottom shadow = black
148          *      arm shadow = (what?)
149          *
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
157          *
158          * Special cases:
159          *      If background is white,   ??
160          *      if background is black,   ??
161          *
162          *
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 compatibile with ThreeD interface.)
166          */
167
168
169
170 #if     XtSpecificationRelease  < 5
171
172 static  GC      XtAllocateGC(Widget, int, u_long, XGCValues *, u_long, u_long) ;
173
174 #endif
175
176
177 #if     NeedFunctionPrototypes
178 static  Pixmap  getDitherPixmap(Widget, int contrast) ;
179 #else
180 static  Pixmap  getDitherPixmap() ;
181 #endif
182
183         /* return a GC with the specified foreground and optional font */
184
185 GC
186 AllocFgGC(Widget w, Pixel fg, Font font)
187 {
188         XGCValues       values ;
189         u_long          vmask, dcmask ;
190
191         values.foreground = fg ;
192         values.font = font ;
193
194         if( font != None ) {
195           vmask = GCForeground|GCFont ;
196           dcmask = GCSubwindowMode|GCDashOffset|
197                 GCDashList|GCArcMode|GCBackground|GCGraphicsExposures ;
198         } else {
199           vmask = GCForeground ;
200           dcmask = GCFont|GCSubwindowMode|GCDashOffset|
201                 GCDashList|GCArcMode|GCBackground|GCGraphicsExposures ;
202         }
203
204         return XtAllocateGC(w, w->core.depth, vmask, &values, 0L, dcmask) ;
205 }
206
207
208         /* return gc with widget background color as the foreground */
209
210 GC
211 AllocBackgroundGC(Widget w, Font font)
212 {
213         return AllocFgGC(w, w->core.background_pixel, font) ;
214 }
215
216
217         /* Allocate an "inactive" GC.  Color is grey (possibly via
218          * dither pattern).
219          */
220
221 GC
222 AllocGreyGC(Widget w, Pixel fg, Font font, int contrast, Bool be_nice_to_cmap)
223 {
224         return AllocShadeGC(w, fg, w->core.background_pixel,
225                 font, contrast, be_nice_to_cmap) ;
226 }
227
228
229         /* Allocate a GC somewhere between two colors.  */
230
231 GC
232 AllocShadeGC(Widget w, Pixel fg, Pixel bg, Font font,
233         int contrast, Bool be_nice_to_cmap)
234 {
235         XGCValues       values ;
236         u_long          vmask, dcmask ;
237
238         values.foreground = fg ;
239         values.background = bg ;
240         values.font = font ;
241
242         if( font != None ) {
243           vmask = GCForeground|GCFont ;
244           dcmask = GCSubwindowMode|GCDashOffset|
245                 GCDashList|GCArcMode|GCGraphicsExposures ;
246         } else {
247           vmask = GCForeground;
248           dcmask = GCFont|GCSubwindowMode|GCDashOffset|
249                 GCDashList|GCArcMode|GCGraphicsExposures ;
250         }
251 #ifdef HAVE_XMU
252         if( be_nice_to_cmap || w->core.depth == 1)
253         {
254           if( contrast <= 5 )
255             values.foreground = bg ;
256           else if( contrast >= 95 )
257             values.foreground = fg ;
258           else {
259             vmask |= GCBackground|GCStipple|GCFillStyle ;
260             values.fill_style = FillOpaqueStippled ;
261             values.stipple = getDitherPixmap(w, contrast) ;
262           }
263
264           return XtAllocateGC(w, w->core.depth, vmask, &values, 0L, dcmask) ;
265         }
266         else
267 #endif
268         {
269           dcmask |= GCBackground ;
270           values.foreground = AllocGreyPixel(w, fg, bg, contrast) ;
271           return XtAllocateGC(w, w->core.depth, vmask, &values, 0L, dcmask) ;
272         }
273 }
274
275         /* return top-shadow gc. */
276
277 GC
278 AllocTopShadowGC(Widget w, int contrast, Bool be_nice_to_cmap)
279 {
280         Screen          *scr = XtScreen (w);
281         XGCValues       values ;
282
283         if( w->core.depth == 1 )
284           values.foreground = BlackPixelOfScreen(scr) ;
285         else if( be_nice_to_cmap )
286           values.foreground = WhitePixelOfScreen(scr) ;
287         else
288           values.foreground = AllocShadowPixel(w, 100+contrast) ;
289
290         return XtAllocateGC(w, w->core.depth,
291             GCForeground, &values,
292             0L,
293             GCBackground|GCFont|GCSubwindowMode|GCGraphicsExposures|
294                 GCDashOffset|GCDashList|GCArcMode) ;
295 }
296
297         /* return bottom-shadow gc. */
298
299 GC
300 AllocBotShadowGC(Widget w, int contrast, Bool be_nice_to_cmap)
301 {
302         Screen          *scr = XtScreen (w);
303         XGCValues       values ;
304
305         if( w->core.depth == 1 || be_nice_to_cmap )
306           values.foreground = BlackPixelOfScreen(scr) ;
307         else
308           values.foreground = AllocShadowPixel(w, 100-contrast) ;
309
310         return XtAllocateGC(w, w->core.depth,
311             GCForeground, &values,
312             0L,
313             GCBackground|GCFont|GCSubwindowMode|GCGraphicsExposures|
314                 GCDashOffset|GCDashList|GCArcMode) ;
315 }
316
317         /* return arm-shadow gc. */
318
319 GC
320 AllocArmGC(Widget w, int contrast, Bool be_nice_to_cmap)
321 {
322         Screen          *scr = XtScreen (w);
323         XGCValues       values ;
324
325         /* Not clear exactly what we should do here.  Take a look at
326          * Xaw3d to see what they do.
327          */
328 #ifdef HAVE_XMU
329         if( w->core.depth == 1 || be_nice_to_cmap )
330         {
331           values.background = w->core.background_pixel ;
332           if( values.background == BlackPixelOfScreen(scr) )
333             values.foreground = WhitePixelOfScreen(scr) ;
334           else
335             values.foreground = BlackPixelOfScreen(scr) ;
336           values.fill_style = FillStippled ;
337           values.stipple = XmuCreateStippledPixmap(XtScreen(w), 1L, 0L, 1) ;
338
339           return XtAllocateGC(w, w->core.depth,
340               GCForeground|GCBackground|GCStipple|GCFillStyle,
341               &values, 0L,
342               GCFont|GCSubwindowMode|GCGraphicsExposures|
343                   GCDashOffset|GCDashList|GCArcMode) ;
344         }
345         else 
346 #endif
347           {
348           values.foreground = AllocShadowPixel(w, 100-contrast) ;
349           return XtAllocateGC(w, w->core.depth,
350               GCForeground, &values,
351               0L,
352               GCBackground|GCFont|GCSubwindowMode|GCGraphicsExposures|
353                   GCDashOffset|GCDashList|GCArcMode) ;
354         }
355 }
356
357
358 Pixel
359 AllocShadowPixel(Widget w, int scale)
360 {
361         XColor  get_c, set_c ;
362         Display *dpy = XtDisplay(w) ;
363         Screen  *scr = XtScreen(w) ;
364         Colormap cmap ;
365         Pixel   maxColor ;
366
367         cmap = w->core.colormap ;
368
369         get_c.pixel = w->core.background_pixel ;
370         if( get_c.pixel == WhitePixelOfScreen(scr)  ||
371             get_c.pixel == BlackPixelOfScreen(scr) )
372         {
373           /* what we *ought* to do is choose gray75 as the base color,
374            * or perhaps gray83.  Instead, we choose colors that are
375            * the same as ThreeD would choose.
376            */
377           if( scale > 100 )     scale = 200 - scale ;
378           set_c.red = set_c.green = set_c.blue = 65535*scale/100 ;
379         }
380         else
381         {
382           XQueryColor(dpy, cmap, &get_c) ;
383           /* adjust scale so that brightest component does not
384            * exceed 65535; otherwise hue would change.
385            */
386           if( scale > 100 ) {
387             maxColor = Max(get_c.red, Max(get_c.green, get_c.blue)) ;
388             if( scale*maxColor > 65535*100 )
389               scale = 65535*100/maxColor ;
390           }
391           set_c.red = scale * get_c.red / 100 ;
392           set_c.green = scale * get_c.green / 100 ;
393           set_c.blue = scale * get_c.blue / 100 ;
394         }
395         set_c.flags = DoRed | DoGreen | DoBlue ;
396         if( XAllocColor(dpy, cmap, &set_c) )
397           return set_c.pixel ;
398         else if( scale > 100 )
399           return WhitePixelOfScreen(scr) ;
400         else
401           return BlackPixelOfScreen(scr) ;
402 }
403
404
405         /* Allocate a pixel partway between foreground and background */
406
407
408 Pixel
409 AllocGreyPixel(Widget w, Pixel fg, Pixel bg, int scale)
410 {
411   XColor        get_cf, get_cb ;
412   Display       *dpy = XtDisplay(w) ;
413   Colormap cmap ;
414
415   cmap = w->core.colormap ;
416
417   get_cf.pixel = fg ;
418   get_cb.pixel = bg ;
419
420   XQueryColor(dpy, cmap, &get_cf) ;
421   XQueryColor(dpy, cmap, &get_cb) ;
422
423   return AllocGreyPixelC(w, &get_cf, &get_cb, scale) ;
424 }
425
426
427
428         /* Allocate a pixel partway between foreground and background */
429
430
431 Pixel
432 AllocGreyPixelC(Widget w, XColor *fg, XColor *bg, int scale)
433 {
434   XColor        set_c ;
435   Display       *dpy = XtDisplay(w) ;
436   int           r,g,b ;
437   Colormap      cmap = w->core.colormap ;
438
439   r = (fg->red * scale +   bg->red * (100-scale)) / 100 ;
440   g = (fg->green * scale + bg->green * (100-scale)) / 100 ;
441   b = (fg->blue * scale +  bg->blue * (100-scale)) / 100 ;
442
443   if( scale > 100 || scale < 0 )        /* look out for overflow */
444   {
445     int minc, maxc ;
446     maxc = Max(r, Max(g,b)) ;
447     minc = Min(r, Min(g,b)) ;
448     if( maxc > 65535 )
449     {
450       maxc /= 16 ;
451       r = r*(65535/16) / maxc ;
452       g = g*(65535/16) / maxc ;
453       b = b*(65535/16) / maxc ;
454     }
455     if( minc < 0 )
456     {
457       r = Max(r,0) ;
458       g = Max(g,0) ;
459       b = Max(b,0) ;
460     }
461   }
462
463   set_c.red = r ; set_c.green = g ; set_c.blue = b ;
464   set_c.flags = DoRed | DoGreen | DoBlue ;
465   (void)XAllocColor(dpy, cmap, &set_c) ;
466   return set_c.pixel ;
467 }
468
469
470
471
472
473         /* draw a 3-d box */
474
475 void
476 Draw3dBox(Widget w, int x, int y, int wid, int hgt, int s, GC topgc, GC botgc)
477 {
478         Display         *dpy = XtDisplay(w) ;
479         Window          win = XtWindow(w) ;
480
481         if( s == 0 ) return ;
482
483         if( s == 1 ) {
484           XDrawLine(dpy,win,botgc, x,y+hgt-1, x+wid-1,y+hgt-1) ;
485           XDrawLine(dpy,win,botgc, x+wid-1,y, x+wid-1,y+hgt-1) ;
486           XDrawLine(dpy,win,topgc, x,y, x,y+hgt-1) ;
487           XDrawLine(dpy,win,topgc, x,y, x+wid-1,y) ;
488         }
489         else
490         {
491           XPoint pts[6] ;
492
493           /* bottom-right shadow */
494           pts[0].x = x ;        pts[0].y = y + hgt ;
495           pts[1].x = s ;        pts[1].y = -s ;
496           pts[2].x = wid-2*s ;  pts[2].y = 0 ;
497           pts[3].x = 0 ;        pts[3].y = -(hgt-2*s) ;
498           pts[4].x = s ;        pts[4].y = -s ;
499           pts[5].x = 0 ;        pts[5].y = hgt ;
500           XFillPolygon(dpy,win,botgc, pts,6, Nonconvex,CoordModePrevious) ;
501
502           /* top-left shadow */
503           pts[0].x = x ;        pts[0].y = y ;
504           pts[1].x = wid ;      pts[1].y = 0 ;
505           pts[2].x = -s ;       pts[2].y = s ;
506           pts[3].x = -wid+2*s ; pts[3].y = 0 ;
507           pts[4].x = 0 ;        pts[4].y = hgt-2*s ;
508           pts[5].x = -s ;       pts[5].y = s ;
509           XFillPolygon(dpy,win,topgc, pts,6, Nonconvex,CoordModePrevious) ;
510         }
511 }
512
513 #if XtSpecificationRelease < 5
514
515 static  GC
516 XtAllocateGC(Widget w, int depth, u_long mask, XGCValues *values,
517         u_long dynamic, du_long ontcare)
518 {
519         return XtGetGC(w, mask, values) ;
520 }
521 #endif
522
523
524 static  u_char  screen0[2] = {0,0} ;
525 static  u_char  screen25[2] = {0,0xaa} ;
526 static  u_char  screen75[2] = {0xaa,0xff} ;
527 static  u_char  screen100[2] = {0xff,0xff} ;
528
529 static  Pixmap
530 getDitherPixmap(Widget w, int contrast)
531 {
532         Display *dpy = XtDisplay(w) ;
533         Window  win = XtWindow(w) ;
534
535         if( contrast <= 5 )
536           return XCreateBitmapFromData(dpy,win, (char *)screen0, 2,2) ;
537         else if( contrast <= 37 )
538           return XCreateBitmapFromData(dpy,win, (char *)screen25, 2,2) ;
539         else if( contrast <= 62 )
540           return XmuCreateStippledPixmap(XtScreen(w), 1L, 0L, 1) ;
541         else if( contrast <= 95 )
542           return XCreateBitmapFromData(dpy,win, (char *)screen75, 2,2) ;
543         else
544           return XCreateBitmapFromData(dpy,win, (char *)screen100, 2,2) ;
545 }