cvsimport
[fvwm.git] / modules / FvwmWharf / stepgfx.c
blob9f7faee13783085b742cd6887d6f0addb0f61d67
1 /* -*-c-*- */
2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * Generic graphics and misc. utilities
21 #include "config.h"
23 #include <X11/Xlib.h>
24 extern Window main_win;
25 #include "libs/fvwmlib.h"
26 #include "libs/PictureBase.h"
27 #include "libs/PictureUtils.h"
28 #include "libs/Graphics.h"
30 /* Masks to apply to color components when allocating colors
31 * you may want to set them to 0xffff if your display supports 16bpp+
33 #define RED_MASK 0xff00
34 #define GREEN_MASK 0xff00
35 #define BLUE_MASK 0xff00
37 * Allocates colors and fill a pixel value array. Color values are
38 * truncated with RED_MASK, GREEN_MASK and BLUE_MASK
40 * from,to are the primary colors to use
41 * maxcols is the number of colors
42 * colors is the array of pixel values
43 * light,dark are the colors for the relief
44 * dr,dg,db are the increment values for the colors
45 * alloc_relief if colors for relief should be allocated
46 * incr - 0 if gradient is light to dark, 1 if dark to light
48 int MakeColors(Display *dpy, Drawable d, int from[3], int to[3], int maxcols,
49 unsigned long *colors, unsigned long *dark,
50 unsigned long *light, int dr, int dg, int db,
51 int alloc_relief, int incr)
53 float rv, gv, bv;
54 float sr,sg,sb;
55 int red, green, blue;
56 XColor color;
57 int i;
59 sr = (float)dr / (float)maxcols;
60 sg = (float)dg / (float)maxcols;
61 sb = (float)db / (float)maxcols;
62 rv = (float)from[0];
63 gv = (float)from[1];
64 bv = (float)from[2];
65 /* kludge to frce color allocation in the first iteration on any case */
66 color.red = (from[0] == 0) ? 0xffff : 0;
67 color.green = 0;
68 color.blue = 0;
69 for(i = 0; i < maxcols; i++) {
70 /* color allocation saver */
71 red = ((short)rv) & RED_MASK;
72 green = ((short)gv) & GREEN_MASK;
73 blue = ((short)bv) & BLUE_MASK;
74 if (color.red != red || color.green != green || color.blue != blue) {
75 color.red = red;
76 color.green = green;
77 color.blue = blue;
78 if (PictureAllocColor(dpy, Pcmap, &color, True)==0) {
79 return 0;
82 colors[i] = color.pixel;
83 rv += sr;
84 gv += sg;
85 bv += sb;
86 if ((rv > 65535.0) || (rv < 0.0)) rv -= sr;
87 if ((gv > 65535.0) || (gv < 0.0)) gv -= sg;
88 if ((bv > 65535.0) || (bv < 0.0)) bv -= sb;
90 /* allocate 2 colors for the bevel */
91 if (alloc_relief) {
92 if (incr) {
93 rv = (float)from[0] * 0.8;
94 gv = (float)from[1] * 0.8;
95 bv = (float)from[2] * 0.8;
96 } else {
97 rv = (float)to[0] * 0.8;
98 gv = (float)to[1] * 0.8;
99 bv = (float)to[2] * 0.8;
101 color.red = (unsigned short)(rv<0?0:rv);
102 color.green = (unsigned short)(gv<0?0:gv);
103 color.blue = (unsigned short)(bv<0?0:bv);
104 if (PictureAllocColor(dpy, Pcmap, &color, True))
105 *dark = color.pixel;
106 else
107 *dark = colors[incr ? 0 : maxcols-1];
109 if (incr) {
110 float avg;
111 avg = (float)(to[0]+to[1]+to[2])/3;
112 rv = avg + (float)(to[0]/2);
113 gv = avg + (float)(to[1]/2);
114 bv = avg + (float)(to[2]/2);
115 } else {
116 float avg;
117 avg = (float)(from[0]+from[1]+from[2])/3;
118 rv = avg + (float)(from[0]/2);
119 gv = avg + (float)(from[1]/2);
120 bv = avg + (float)(from[2]/2);
122 color.red = (unsigned short)(rv>65535.0 ? 65535.0:rv);
123 color.green = (unsigned short)(gv>65535.0 ? 65535.0:gv);
124 color.blue = (unsigned short)(bv>65535.0 ? 65535.0:bv);
125 if (PictureAllocColor(dpy, Pcmap, &color, True))
126 *light = color.pixel;
127 else
128 *light = colors[incr ? maxcols-1 : 0];
129 } else {
130 *light = colors[incr ? maxcols-1 : 0];
131 *dark = colors[incr ? 0 : maxcols-1];
133 return 1;
139 * Draws a texture similar to Wharf's button background
141 * from: r,g,b values of top left color
142 * to: r,g,b values of bottom right color
143 * relief: relief to add to the borders. 0=flat, >0 raised, <0 sunken
144 * maxcols: # of max colors to use
146 * Aborts and returns 0 on error
149 int DrawDegradeRelief(Display *dpy, Drawable d, int x, int y, int w, int h,
150 int from[3], int to[3], int relief, int maxcols)
152 int i = 0,j,k;
153 int dr, dg, db; /* delta */
154 int dmax, dmax2;
155 GC gc, gc2;
156 XGCValues gcv;
157 int px, py, pd;
158 unsigned long lightcolor, darkcolor;
159 int alloc_relief;
160 unsigned long *colors;
161 float c1,s1;
163 if (w <= 0 || h <= 0)
164 return 0;
166 gcv.foreground = 1;
167 gc = fvwmlib_XCreateGC(dpy, d, GCForeground, &gcv);
168 gc2 = fvwmlib_XCreateGC(dpy, d, GCForeground, &gcv);
170 dr = to[0] - from[0];
171 dg = to[1] - from[1];
172 db = to[2] - from[2];
174 dmax = abs(dr);
175 dmax2 = dr;
176 if (dmax < abs(dg)) {
177 dmax = abs(dg);
178 dmax2 = dg;
180 if (dmax < abs(db)) {
181 dmax = abs(db);
182 dmax2 = db;
184 /* if colors from and to are the same, force to one color */
185 if (dmax==0) dmax=1;
187 if (relief!=0) {
188 if (maxcols>4) {
189 alloc_relief=1;
190 maxcols -= 2; /* reserve two colors for the relief */
191 } else {
192 alloc_relief=0;
194 } else
195 alloc_relief = 0;
197 if (dmax < maxcols) {
198 maxcols = dmax; /* we need less colors than we expected */
201 colors = malloc(sizeof(unsigned long)*maxcols);
202 /* alloc colors */
203 if (!MakeColors(dpy, d, from, to, maxcols, colors, &darkcolor, &lightcolor,
204 dr, dg, db, alloc_relief, dmax2>0))
205 return 0;
207 /* display it */
208 s1 = (float)(maxcols)/((float)w*2.0);
209 pd = relief==0 ? 0 : 1;
210 for(py = pd; py < h-pd; py++) {
211 c1 = ((float)maxcols/2.0)*((float)py/(float)((h-pd*2)-1));
212 j = -1;
213 k=pd+x;
214 for(px = pd+x; px < w-pd+x; px++) {
215 i = (int)c1;
216 if (i>=maxcols) i=maxcols-1;
217 if (j != colors[i]) {
218 j = colors[i];
219 XSetForeground(dpy, gc, j);
220 XDrawLine(dpy, d, gc, k, y+py, px, y+py);
221 k=px;
223 c1+=s1;
225 XSetForeground(dpy, gc, colors[i]);
226 XDrawLine(dpy, d, gc, k, y+py, w-pd+x, y+py);
228 /* draw borders */
229 if (relief != 0) {
230 if (relief>0) {
231 XSetForeground(dpy, gc, lightcolor);
232 XSetForeground(dpy, gc2, darkcolor);
233 } else {
234 XSetForeground(dpy, gc, darkcolor);
235 XSetForeground(dpy, gc2, lightcolor);
237 XDrawLine(dpy, d, gc, x, y, x, y+h-1);
238 XDrawLine(dpy, d, gc, x, y, x+w-1, y);
239 XDrawLine(dpy, d, gc2, x, y+h-1, x+w-1, y+h-1);
240 XDrawLine(dpy, d, gc2, x+w-1, y, x+w-1, y+h-1);
242 XFreeGC(dpy,gc);
243 XFreeGC(dpy,gc2);
244 free(colors);
245 return 1;
250 * Draws a horizontal gradient
252 * from: r,g,b values of top color
253 * to: r,g,b values of bottom color
254 * relief: relief to add to the borders. 0=flat, >0 raised, <0 sunken
255 * maxcols: max colors to use
256 * type: gradient type. 0 for one-way, != 0 for cilindrical
258 * aborts and returns 0 on error.
260 int DrawHGradient(Display *dpy, Drawable d, int x, int y, int w, int h,
261 int from[3], int to[3], int relief, int maxcols,
262 int type)
264 int i,j;
265 XGCValues gcv;
266 GC gc, gc2;
267 int dr,dg,db;
268 float s,c;
269 int dmax;
270 unsigned long *colors, lightcolor, darkcolor;
271 int py,pd;
272 int alloc_relief;
274 if (w <= 1 || h <= 1)
275 return 0;
277 gcv.foreground = 1;
278 gc = fvwmlib_XCreateGC(dpy, d, GCForeground, &gcv);
279 gc2 = fvwmlib_XCreateGC(dpy, d, GCForeground, &gcv);
281 dr = to[0] - from[0];
282 dg = to[1] - from[1];
283 db = to[2] - from[2];
285 dmax = dr;
286 if (abs(dmax) < abs(dg)) {
287 dmax = dg;
289 if (abs(dmax) < abs(db)) {
290 dmax = db;
292 if (relief!=0) {
293 if (maxcols>4) {
294 alloc_relief=1;
295 maxcols -= 2; /* reserve two colors for the relief */
296 } else {
297 alloc_relief=0;
299 } else
300 alloc_relief=0;
302 if (type) {
303 if (h/2 < maxcols) {
304 maxcols = h/2; /* we need less colors than we expected */
306 } else {
307 if (h < maxcols) {
308 maxcols = h; /* we need less colors than we expected */
311 /* alloc colors */
312 colors=malloc(maxcols*sizeof(unsigned long));
313 if (!MakeColors(dpy, d, from, to, maxcols, colors, &darkcolor, &lightcolor,
314 dr, dg, db, alloc_relief, dmax>0))
315 return 0;
316 /* display it */
317 if (type) {
318 s = ((float)maxcols*2)/(float)h;
319 } else {
320 s = (float)maxcols/(float)h;
322 pd = relief==0 ? 0 : 1;
323 c=0;
324 j=-1;
325 if (type==0) { /* one-way */
326 for(py = pd; py < h-pd; py++) {
327 i=(int)c;
328 if (i>=maxcols) i=maxcols-1;
329 if (j != i) {
330 XSetForeground(dpy, gc, colors[i]);
332 XDrawLine(dpy, d, gc, x+pd, y+py, x+w-1-pd, y+py);
333 j = i;
334 c += s;
336 } else { /* cylindrical */
337 for(py = pd; py < h-pd; py++) {
338 i=(int)c;
339 if (i>=maxcols) i=maxcols-1;
340 if (j != i) {
341 XSetForeground(dpy, gc, colors[i]);
343 XDrawLine(dpy, d, gc, x+pd, y+py, x+w-1-pd, y+py);
344 j = i;
345 if (py == h/2) s = -s;
346 c += s;
349 /* draw borders */
350 if (relief != 0) {
351 if (relief>0) {
352 XSetForeground(dpy, gc, lightcolor);
353 XSetForeground(dpy, gc2, darkcolor);
354 } else {
355 XSetForeground(dpy, gc, darkcolor);
356 XSetForeground(dpy, gc2, lightcolor);
358 XDrawLine(dpy, d, gc, x, y, x, y+h-1);
359 XDrawLine(dpy, d, gc, x, y, x+w-1, y);
360 XDrawLine(dpy, d, gc2, x, y+h-1, x+w-1, y+h-1);
361 XDrawLine(dpy, d, gc2, x+w-1, y, x+w-1, y+h-1);
363 XFreeGC(dpy,gc);
364 XFreeGC(dpy,gc2);
365 free(colors);
366 return 1;
371 * Draws a vertical gradient
373 * from: r,g,b values of left color
374 * to: r,g,b values of right color
375 * relief: relief to add to the borders. 0=flat, >0 raised, <0 sunken
376 * maxcols: max colors to use
377 * type: gradient type. 0 for one-way, != 0 for cilindrical
379 * aborts and returns 0 on error.
381 int DrawVGradient(Display *dpy, Drawable d, int x, int y, int w, int h,
382 int from[3], int to[3], int relief, int maxcols,
383 int type)
385 int i,j;
386 XGCValues gcv;
387 GC gc, gc2;
388 int dr,dg,db;
389 float s,c;
390 int dmax;
391 unsigned long *colors, lightcolor, darkcolor;
392 int px,pd;
393 int alloc_relief;
395 if (w <= 1 || h <= 1)
396 return 0;
398 gcv.foreground = 1;
399 gc = fvwmlib_XCreateGC(dpy, d, GCForeground, &gcv);
400 gc2 = fvwmlib_XCreateGC(dpy, d, GCForeground, &gcv);
402 dr = to[0] - from[0];
403 dg = to[1] - from[1];
404 db = to[2] - from[2];
406 dmax = dr;
407 if (abs(dmax) < abs(dg)) {
408 dmax = dg;
410 if (abs(dmax) < abs(db)) {
411 dmax = db;
413 if (relief!=0) {
414 if (maxcols>4) {
415 alloc_relief=1;
416 maxcols -= 2; /* reserve two colors for the relief */
417 } else {
418 alloc_relief=0;
420 } else
421 alloc_relief=0;
423 if (type) {
424 if (w/2 < maxcols) {
425 maxcols = w/2; /* we need less colors than we expected */
427 } else {
428 if (w < maxcols) {
429 maxcols = w; /* we need less colors than we expected */
432 /* alloc colors */
433 colors=malloc(maxcols*sizeof(unsigned long));
434 if (!MakeColors(dpy, d, from, to, maxcols, colors, &darkcolor, &lightcolor,
435 dr, dg, db, alloc_relief, dmax>0))
436 return 0;
437 /* display it */
438 if (type) {
439 s = ((float)maxcols*2)/(float)w;
440 } else {
441 s = (float)maxcols/(float)w;
443 pd = relief==0 ? 0 : 1;
444 c=0;
445 j=-1;
446 if (type==0) { /* one-way */
447 for(px = pd; px < w-pd; px++) {
448 i=(int)c;
449 if (i>=maxcols) i=maxcols-1;
450 if (j != i) {
451 XSetForeground(dpy, gc, colors[i]);
453 XDrawLine(dpy, d, gc, x+px, y+pd, x+px, y+h-pd-1);
454 j = i;
455 c += s;
457 } else { /* cylindrical */
458 for(px = pd; px < w-pd; px++) {
459 i=(int)c;
460 if (i>=maxcols) i=maxcols-1;
461 if (j != i) {
462 XSetForeground(dpy, gc, colors[i]);
464 XDrawLine(dpy, d, gc, x+px, y+pd, x+px, y+h-pd-1);
465 j = i;
466 if (px == w/2) s = -s;
467 c += s;
470 /* draw borders */
471 if (relief != 0) {
472 if (relief>0) {
473 XSetForeground(dpy, gc, lightcolor);
474 XSetForeground(dpy, gc2, darkcolor);
475 } else {
476 XSetForeground(dpy, gc, darkcolor);
477 XSetForeground(dpy, gc2, lightcolor);
479 XDrawLine(dpy, d, gc, x, y, x, y+h-1);
480 XDrawLine(dpy, d, gc, x, y, x+w-1, y);
481 XDrawLine(dpy, d, gc2, x, y+h-1, x+w-1, y+h-1);
482 XDrawLine(dpy, d, gc2, x+w-1, y, x+w-1, y+h-1);
484 XFreeGC(dpy,gc);
485 XFreeGC(dpy,gc2);
486 free(colors);
487 return 1;
491 /* Draws text with a texture
493 * d - target drawable
494 * font - font to draw text
495 * x,y - position of text
496 * gradient - texture pixmap. size must be at least as large as text
497 * text - text to draw
498 * chars - chars in text
500 void DrawTexturedText(Display *dpy, Drawable d, XFontStruct *font,
501 int x, int y, Pixmap gradient, char *text, int chars)
504 Pixmap mask;
505 int w,h;
506 GC gc;
507 XGCValues gcv;
509 /* make the mask pixmap */
510 w = XTextWidth(font,text,chars);
511 h = font->ascent+font->descent;
512 mask=XCreatePixmap(dpy,main_win,w+1,h+1,1);
513 gcv.foreground = 0;
514 gcv.function = GXcopy;
515 gcv.font = font->fid;
516 gc = fvwmlib_XCreateGC(dpy,mask,GCFunction|GCForeground|GCFont,&gcv);
517 XFillRectangle(dpy,mask,gc,0,0,w,h);
518 XSetForeground(dpy,gc,1);
519 XDrawString(dpy,mask,gc,0,font->ascent,text,chars);
520 XFreeGC(dpy,gc);
521 /* draw the texture */
522 gcv.function=GXcopy;
523 gc = fvwmlib_XCreateGC(dpy,d,GCFunction,&gcv);
524 XSetClipOrigin(dpy,gc,x,y);
525 XSetClipMask(dpy,gc,mask);
526 XCopyArea(dpy,gradient,d,gc,0,0,w,h,x,y);
527 XFreeGC(dpy,gc);
528 XFreePixmap(dpy,mask);
534 int MakeShadowColors(Display *dpy, int from[3], int to[3],
535 unsigned long *dark, unsigned long *light)
537 float rv, gv, bv;
538 XColor color;
539 int incr;
540 int dr,dg,db,dmax;
541 dr = to[0] - from[0];
542 dg = to[1] - from[1];
543 db = to[2] - from[2];
545 dmax = dr;
546 if (abs(dmax) < abs(dg)) {
547 dmax = dg;
549 if (abs(dmax) < abs(db)) {
550 dmax = db;
552 incr=(dmax>0);
553 /* allocate 2 colors for the bevel */
554 if (incr) {
555 rv = (float)from[0] * 0.8;
556 gv = (float)from[1] * 0.8;
557 bv = (float)from[2] * 0.8;
558 } else {
559 rv = (float)to[0] * 0.8;
560 gv = (float)to[1] * 0.8;
561 bv = (float)to[2] * 0.8;
563 color.red = (short)(rv<0?0:rv);
564 color.green = (short)(gv<0?0:gv);
565 color.blue = (short)(bv<0?0:bv);
566 if (PictureAllocColor(dpy, Pcmap ,&color, True))
567 *dark = color.pixel;
568 else
569 return 0;
571 if (incr) {
572 float avg;
573 avg = (float)(to[0]+to[1]+to[2])/3;
574 rv = avg + (float)(to[0]/2);
575 gv = avg + (float)(to[1]/2);
576 bv = avg + (float)(to[2]/2);
577 } else {
578 float avg;
579 avg = (float)(from[0]+from[1]+from[2])/3;
580 rv = avg + (float)(from[0]/2);
581 gv = avg + (float)(from[1]/2);
582 bv = avg + (float)(from[2]/2);
584 color.red = (unsigned short)(rv>65535.0 ? 65535.0:rv);
585 color.green = (unsigned short)(gv>65535.0 ? 65535.0:gv);
586 color.blue = (unsigned short)(bv>65535.0 ? 65535.0:bv);
587 if (PictureAllocColor(dpy, Pcmap, &color, True))
588 *light = color.pixel;
589 else
590 return 0;
591 return 1;