1 /*
2 * xvbutt.c - regular, 'radio', 'checkbox', and 'menu' pushbuttons
3 *
4 * callable functions:
5 *
6 * BTCreate() - create a button
7 * BTSetActive() - change 'active' status of button
8 * BTRedraw() - redraw button
9 * BTTrack() - clicked in button. track until mouse up
10 *
11 * RBCreate() - create an RBUTT and append to supplied list
12 * RBRedraw() - redraw one or all RBUTTs in a list
13 * RBSelect() - change selected item in list of RBUTTs
14 * RBWhich() - returns index of selected RBUTT in list
15 * RBCount() - returns # of RBUTTs in list
16 * RBSetActive() - sets active status of an RBUTT
17 * RBClick() - finds clicked-on rb in a list
18 * RBTrack() - tracks rb after click, until release
19 *
20 * CBCreate() - create a CBUTT (checkbox button)
21 * CBRedraw() - redraw a CBUTT
22 * CBSetActive() - change active status of a CBUTT
23 * CBClick() - returns true if given CB was clicked on
24 * CBTrack() - tracks CBUTT after click, until release
25 *
26 * MBCreate() - create a MBUTT (menu button)
27 * MBRedraw() - redraw a MBUTT
28 * MBSetActive() - change active status of a MBUTT
29 * MBWhich() - returns # of first checked selection
30 * MBSelect() - similar to RBSelect() ...
31 * MBClick() - returns true if given MB was clicked on
32 * MBTrack() - tracks MBUTT after click, until release
33 */
34
35
36 #include "copyright.h"
37 #include "xv.h"
38
39 #include "bits/cboard50"
40 #include "bits/rb_frame"
41 #include "bits/rb_frame1"
42 #include "bits/rb_top"
43 #include "bits/rb_bot"
44 #include "bits/rb_dtop"
45 #include "bits/rb_dbot"
46 #include "bits/rb_body"
47 #include "bits/rb_dot"
48 #include "bits/cb_check"
49 #include "bits/mb_chk"
50
51
52 static Pixmap cboard50 = (Pixmap) NULL; /* 50% gray checkerboard */
53
54
55 static int rbpixmade = 0;
56 static Pixmap rb_on, rb_on1, rb_off, rb_off1;
57
58 static int cbpixmade = 0;
59 static Pixmap cbcheck;
60
61 static int mbpixmade = 0;
62 static Pixmap mbchk;
63
64 static void drawRB PARM((RBUTT *, int));
65 static void drawCB PARM((CBUTT *, int));
66
67
68
69 /******************* BUTT ROUTINES ************************/
70
71
72
73 /**********************************************/
BTCreate(bp,win,x,y,w,h,str,fg,bg,hi,lo)74 void BTCreate(bp,win,x,y,w,h,str,fg,bg,hi,lo)
75 BUTT *bp;
76 Window win;
77 int x,y;
78 unsigned int w,h;
79 const char *str;
80 unsigned long fg,bg,hi,lo;
81 {
82 bp->win = win;
83 bp->x = x; bp->y = y; bp->w = w; bp->h = h;
84 bp->str = str;
85 bp->fg = fg; bp->bg = bg; bp->hi = hi; bp->lo = lo;
86 bp->lit = 0;
87 bp->active = 1;
88 bp->toggle = 0;
89 bp->pix = None;
90 bp->colorpix = 0;
91 bp->style = 0;
92 bp->fwidth = 3;
93
94 if (!cboard50) {
95 cboard50 = MakePix1(rootW, cboard50_bits, cboard50_width, cboard50_height);
96 if (!cboard50) FatalError("Unable to create cboard50 bitmap\n");
97 }
98 }
99
100
101
102 /**********************************************/
BTSetActive(bp,act)103 void BTSetActive(bp,act)
104 BUTT *bp;
105 int act;
106 {
107 if (bp->active != act) {
108 bp->active = act;
109 BTRedraw(bp);
110 }
111 }
112
113
114
115 /**********************************************/
BTRedraw(bp)116 void BTRedraw(bp)
117 BUTT *bp;
118 {
119 int x,y,r,x1,y1;
120 unsigned int w,h;
121 XPoint tpts[10], bpts[10], ipts[5];
122
123 x = bp->x; y=bp->y; w=bp->w; h=bp->h; r=bp->fwidth;
124
125 if (!bp->active) bp->lit = 0;
126 if (bp->lit) {
127 r -= 1;
128 if (r<0) r = 0;
129 }
130
131 if (!ctrlColor) {
132 /* set up 'ipts' */
133 ipts[0].x = x+r; ipts[0].y = y+r; /* topleft */
134 ipts[1].x = x+r; ipts[1].y = y+h-r; /* botleft */
135 ipts[2].x = x+w-r; ipts[2].y = y+h-r; /* botright */
136 ipts[3].x = x+w-r; ipts[3].y = y+r; /* topright */
137 ipts[4].x = ipts[0].x; ipts[4].y = ipts[0].y; /* close path */
138
139 /* top left polygon */
140 tpts[0].x = x; tpts[0].y = y;
141 tpts[1].x = x; tpts[1].y = y+h;
142 tpts[2].x = ipts[1].x; tpts[2].y = ipts[1].y;
143 tpts[3].x = ipts[0].x; tpts[3].y = ipts[0].y;
144 tpts[4].x = ipts[3].x; tpts[4].y = ipts[3].y;
145 tpts[5].x = x+w; tpts[5].y = y;
146 tpts[6].x = x; tpts[6].y = y;
147
148 /* bot left polygon */
149 bpts[0].x = x; bpts[0].y = y+h;
150 bpts[1].x = ipts[1].x; bpts[1].y = ipts[1].y;
151 bpts[2].x = ipts[2].x; bpts[2].y = ipts[2].y;
152 bpts[3].x = ipts[3].x; bpts[3].y = ipts[3].y;
153 bpts[4].x = x+w; bpts[4].y = y;
154 bpts[5].x = x+w; bpts[5].y = y+h;
155 bpts[6].x = x; bpts[6].y = y+h;
156
157
158 /* clear button and draw frame */
159 XSetForeground(theDisp, theGC, bp->bg);
160 XFillRectangle(theDisp, bp->win, theGC, x, y, w, h);
161 XSetForeground(theDisp, theGC, bp->fg);
162 XDrawRectangle(theDisp, bp->win, theGC, x, y, w, h);
163
164 XSetForeground(theDisp, theGC, bp->fg);
165 XSetFillStyle(theDisp, theGC, FillStippled);
166 XSetStipple(theDisp, theGC, cboard50);
167 XFillPolygon(theDisp, bp->win, theGC, bpts, 7, Nonconvex, CoordModeOrigin);
168 XSetFillStyle(theDisp,theGC,FillSolid);
169
170 XSetForeground(theDisp, theGC, bp->fg);
171 XDrawLines(theDisp, bp->win, theGC, ipts, 5, CoordModeOrigin); /* inset */
172
173 XDrawLine(theDisp, bp->win, theGC, x+1, y + 1,
174 ipts[0].x, ipts[0].y);
175 XDrawLine(theDisp, bp->win, theGC, x+1, y + (int) h - 1,
176 ipts[1].x, ipts[1].y);
177 XDrawLine(theDisp, bp->win, theGC, x + (int) w - 1, y + (int) h - 1,
178 ipts[2].x, ipts[2].y);
179 XDrawLine(theDisp, bp->win, theGC, x + (int) w - 1, y+1,
180 ipts[3].x, ipts[3].y);
181
182 if (bp->lit) {
183 XDrawRectangle(theDisp, bp->win, theGC, x+2, y+2, w-4, h-4);
184 XDrawRectangle(theDisp, bp->win, theGC, x+1, y+1, w-2, h-2);
185 }
186 }
187
188 else { /* ctrlColor */
189 XSetForeground(theDisp, theGC, bp->bg);
190 XFillRectangle(theDisp, bp->win, theGC, x+1, y+1, w-1, h-1);
191
192 Draw3dRect(bp->win, x+1, y+1, w-2, h-2, R3D_OUT, bp->fwidth,
193 bp->hi, bp->lo, bp->bg);
194
195 XSetForeground(theDisp, theGC, bp->fg);
196 XDrawRectangle(theDisp, bp->win, theGC, x, y, w, h);
197
198 if (bp->lit)
199 XDrawRectangle(theDisp, bp->win, theGC, x+1, y+1, w-2, h-2);
200 }
201
202
203
204
205 XSetForeground(theDisp, theGC, bp->fg);
206
207 if (bp->pix != None) { /* draw pixmap centered in butt */
208 x1 = x+(1+w-bp->pw)/2;
209 y1 = y+(1+h-bp->ph)/2;
210
211 XSetBackground(theDisp, theGC, bp->bg);
212
213 if (bp->colorpix)
214 XCopyArea (theDisp,bp->pix, bp->win, theGC, 0,0,bp->pw,bp->ph, x1,y1);
215 else
216 XCopyPlane(theDisp,bp->pix, bp->win, theGC, 0,0,bp->pw,bp->ph, x1,y1,1L);
217
218 if (!bp->active) DimRect(bp->win, x1,y1, bp->pw, bp->ph, bp->bg);
219 }
220
221 else { /* draw string centered in butt */
222 x1 = CENTERX(mfinfo, x + w/2, bp->str);
223 y1 = CENTERY(mfinfo, y + h/2);
224
225 if (bp->active) {
226 DrawString(bp->win, x1,y1, bp->str);
227 }
228 else { /* stipple if not active */
229 XSetFillStyle(theDisp, theGC, FillStippled);
230 XSetStipple(theDisp, theGC, dimStip);
231 DrawString(bp->win, x1,y1, bp->str);
232 XSetFillStyle(theDisp,theGC,FillSolid);
233 }
234 }
235
236 }
237
238
239
240 /**********************************************/
BTTrack(bp)241 int BTTrack(bp)
242 BUTT *bp;
243 {
244 /* called when we've gotten a click inside 'bp'. returns 1 if button
245 was still selected lit when mouse was released. */
246
247 Window rW, cW;
248 int x, y, rx, ry, rval, inval;
249 unsigned int mask;
250
251 if (!bp->active) return 0; /* inactive button */
252
253 inval = bp->lit;
254 bp->lit = !bp->lit;
255
256 BTRedraw(bp); XFlush(theDisp);
257 Timer(120); /* long enough for turn on to be visible */
258
259 while (XQueryPointer(theDisp,bp->win,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
260 if (!(mask & Button1Mask)) break; /* button released */
261
262 if (bp->lit==inval && PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) {
263 bp->lit = !inval; BTRedraw(bp); XFlush(theDisp);
264 }
265
266 if (bp->lit!=inval && !PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) {
267 bp->lit = inval; BTRedraw(bp); XFlush(theDisp);
268 }
269 }
270
271 rval = (bp->lit != inval);
272
273 if (bp->lit && !bp->toggle)
274 { bp->lit = 0; BTRedraw(bp); XFlush(theDisp); }
275
276 return(rval);
277 }
278
279
280
281
282 /******************* RBUTT ROUTINES ************************/
283
284
285 #define RBSIZE rb_frame_width
286
287
288 /***********************************************/
RBCreate(rblist,win,x,y,str,fg,bg,hi,lo)289 RBUTT *RBCreate(rblist, win, x,y,str, fg, bg, hi, lo)
290 RBUTT *rblist;
291 Window win;
292 int x,y;
293 const char *str;
294 unsigned long fg,bg,hi,lo;
295 {
296 /* mallocs an RBUTT, fills in the fields, and appends it to rblist
297 if rblist is NULL, this is the first rb in the list. It will
298 be made the 'selected' one
299
300 Note: no need to check return status. It'll fatal error if it
301 can't malloc */
302
303 RBUTT *rb, *rbptr;
304 Pixmap rb_frame, rb_frame1, rb_top, rb_bot, rb_dtop, rb_dbot, rb_body,
305 rb_dot;
306
307 rb = (RBUTT *) malloc(sizeof(RBUTT));
308 if (!rb) FatalError("couldn't malloc RBUTT");
309
310 /* fill in the fields of the structure */
311 rb->win = win;
312 rb->x = x;
313 rb->y = y;
314 rb->str = str;
315 rb->selected = 0;
316 rb->active = 1;
317 rb->next = (struct rbutt *) NULL;
318 rb->fg = fg;
319 rb->bg = bg;
320 rb->hi = hi;
321 rb->lo = lo;
322
323 if (rblist) { /* append to end of list */
324 rbptr = rblist;
325 while (rbptr->next) rbptr = (RBUTT *) rbptr->next;
326 rbptr->next = (struct rbutt *) rb;
327 }
328 else { /* this is the first one in the list. select it */
329 rb->selected = 1;
330 }
331
332
333 /* and, on an unrelated note, if the RB pixmaps haven't been created yet,
334 do so. We'll be needing them, y'see... */
335
336 if (!rbpixmade) {
337 rb_frame = MakePix1(rootW, rb_frame_bits, RBSIZE, RBSIZE);
338 rb_frame1 = MakePix1(rootW, rb_frame1_bits, RBSIZE, RBSIZE);
339 rb_top = MakePix1(rootW, rb_top_bits, RBSIZE, RBSIZE);
340 rb_bot = MakePix1(rootW, rb_bot_bits, RBSIZE, RBSIZE);
341 rb_dtop = MakePix1(rootW, rb_dtop_bits, RBSIZE, RBSIZE);
342 rb_dbot = MakePix1(rootW, rb_dbot_bits, RBSIZE, RBSIZE);
343 rb_body = MakePix1(rootW, rb_body_bits, RBSIZE, RBSIZE);
344 rb_dot = MakePix1(rootW, rb_dot_bits, RBSIZE, RBSIZE);
345
346 rb_on = XCreatePixmap(theDisp, rootW, RBSIZE, RBSIZE, dispDEEP);
347 rb_on1 = XCreatePixmap(theDisp, rootW, RBSIZE, RBSIZE, dispDEEP);
348 rb_off = XCreatePixmap(theDisp, rootW, RBSIZE, RBSIZE, dispDEEP);
349 rb_off1 = XCreatePixmap(theDisp, rootW, RBSIZE, RBSIZE, dispDEEP);
350
351 if (!rb_frame || !rb_frame1 || !rb_top || !rb_bot || !rb_dtop ||
352 !rb_dbot || !rb_body || !rb_dot || !rb_on || !rb_on1 ||
353 !rb_off || !rb_off1)
354 FatalError("unable to create radio-button pixmaps");
355
356
357 /* generate rb_on,on1,off,off1 pixmaps from mask pixmaps */
358 XSetForeground(theDisp, theGC, bg);
359 XFillRectangle(theDisp, rb_on, theGC, 0,0,RBSIZE,RBSIZE);
360 XFillRectangle(theDisp, rb_on1, theGC, 0,0,RBSIZE,RBSIZE);
361 XFillRectangle(theDisp, rb_off, theGC, 0,0,RBSIZE,RBSIZE);
362 XFillRectangle(theDisp, rb_off1, theGC, 0,0,RBSIZE,RBSIZE);
363
364 XSetFillStyle(theDisp, theGC, FillStippled);
365
366 if (ctrlColor) {
367 XSetStipple(theDisp, theGC, rb_top);
368 XSetForeground(theDisp, theGC, fg);
369 XFillRectangle(theDisp, rb_on, theGC, 0,0,RBSIZE,RBSIZE);
370 XFillRectangle(theDisp, rb_on1, theGC, 0,0,RBSIZE,RBSIZE);
371 XSetForeground(theDisp, theGC, hi);
372 XFillRectangle(theDisp, rb_off, theGC, 0,0,RBSIZE,RBSIZE);
373 XFillRectangle(theDisp, rb_off1, theGC, 0,0,RBSIZE,RBSIZE);
374
375 XSetStipple(theDisp, theGC, rb_body);
376 XSetForeground(theDisp, theGC, lo);
377 XFillRectangle(theDisp, rb_on, theGC, 0,0,RBSIZE,RBSIZE);
378 XFillRectangle(theDisp, rb_on1, theGC, 0,0,RBSIZE,RBSIZE);
379 XSetForeground(theDisp, theGC, bg);
380 XFillRectangle(theDisp, rb_off, theGC, 0,0,RBSIZE,RBSIZE);
381 XFillRectangle(theDisp, rb_off1, theGC, 0,0,RBSIZE,RBSIZE);
382
383 XSetStipple(theDisp, theGC, rb_bot);
384 XSetForeground(theDisp, theGC, bg);
385 XFillRectangle(theDisp, rb_on, theGC, 0,0,RBSIZE,RBSIZE);
386 XFillRectangle(theDisp, rb_on1, theGC, 0,0,RBSIZE,RBSIZE);
387 XSetForeground(theDisp, theGC, lo);
388 XFillRectangle(theDisp, rb_off, theGC, 0,0,RBSIZE,RBSIZE);
389 XFillRectangle(theDisp, rb_off1, theGC, 0,0,RBSIZE,RBSIZE);
390
391 XSetStipple(theDisp, theGC, rb_dtop);
392 XSetForeground(theDisp, theGC, bg);
393 XFillRectangle(theDisp, rb_on, theGC, 0,0,RBSIZE,RBSIZE);
394 XFillRectangle(theDisp, rb_on1, theGC, 0,0,RBSIZE,RBSIZE);
395 XSetForeground(theDisp, theGC, hi);
396 XFillRectangle(theDisp, rb_off, theGC, 0,0,RBSIZE,RBSIZE);
397 XFillRectangle(theDisp, rb_off1, theGC, 0,0,RBSIZE,RBSIZE);
398
399 XSetStipple(theDisp, theGC, rb_dbot);
400 XSetForeground(theDisp, theGC, fg);
401 XFillRectangle(theDisp, rb_on, theGC, 0,0,RBSIZE,RBSIZE);
402 XFillRectangle(theDisp, rb_on1, theGC, 0,0,RBSIZE,RBSIZE);
403 XSetForeground(theDisp, theGC, lo);
404 XFillRectangle(theDisp, rb_off, theGC, 0,0,RBSIZE,RBSIZE);
405 XFillRectangle(theDisp, rb_off1, theGC, 0,0,RBSIZE,RBSIZE);
406 }
407 else {
408 XSetStipple(theDisp, theGC, rb_dot);
409 XSetForeground(theDisp, theGC, fg);
410 XFillRectangle(theDisp, rb_on, theGC, 0,0,RBSIZE,RBSIZE);
411 XFillRectangle(theDisp, rb_on1, theGC, 0,0,RBSIZE,RBSIZE);
412 }
413
414 XSetStipple(theDisp, theGC, rb_frame);
415 XSetForeground(theDisp, theGC, fg);
416 XFillRectangle(theDisp, rb_on, theGC, 0,0,RBSIZE,RBSIZE);
417 XFillRectangle(theDisp, rb_off, theGC, 0,0,RBSIZE,RBSIZE);
418
419 XSetStipple(theDisp, theGC, rb_frame1);
420 XSetForeground(theDisp, theGC, fg);
421 XFillRectangle(theDisp, rb_on1, theGC, 0,0,RBSIZE,RBSIZE);
422 XFillRectangle(theDisp, rb_off1, theGC, 0,0,RBSIZE,RBSIZE);
423
424 XSetFillStyle(theDisp, theGC, FillSolid);
425
426 /* destroy mask pixmaps */
427 XFreePixmap(theDisp, rb_frame);
428 XFreePixmap(theDisp, rb_frame1);
429 XFreePixmap(theDisp, rb_top);
430 XFreePixmap(theDisp, rb_bot);
431 XFreePixmap(theDisp, rb_dtop);
432 XFreePixmap(theDisp, rb_dbot);
433 XFreePixmap(theDisp, rb_body);
434
435 rbpixmade = 1;
436 }
437
438 return(rb);
439 }
440
441
442
443
444 /***********************************************/
RBRedraw(rblist,num)445 void RBRedraw(rblist, num)
446 RBUTT *rblist;
447 int num;
448 {
449 /* redraws the 'num-th' RB in the list. if num < 0, redraws entire list */
450
451 RBUTT *rb;
452 int i;
453
454 /* point 'rb' at the appropriate RBUTT, *if* we're not drawing entire list */
455 if (num>=0) {
456 i=0; rb=rblist;
457 while (i!=num && rb) { rb = (RBUTT *) rb->next; i++; }
458 if (!rb) return; /* num is out of range. do nothing */
459 drawRB(rb,0);
460 }
461
462 else { /* draw entire list */
463 rb = rblist;
464 while (rb) {
465 drawRB(rb,0);
466 rb = (RBUTT *) rb->next;
467 }
468 }
469 }
470
471
472 /***********************************************/
drawRB(rb,lit)473 static void drawRB(rb, lit)
474 RBUTT *rb;
475 int lit;
476 {
477 /* draws the rb being pointed at */
478
479 Pixmap pix;
480
481 if (!rb) return; /* rb = NULL */
482
483 XSetForeground(theDisp, theGC, rb->fg);
484
485 if (rb->selected) { pix = (lit) ? rb_on1 : rb_on; }
486 else { pix = (lit) ? rb_off1 : rb_off; }
487
488 XCopyArea(theDisp, pix, rb->win, theGC, 0,0,RBSIZE,RBSIZE, rb->x, rb->y);
489 DrawString(rb->win, rb->x + RBSIZE + 4,
490 rb->y + RBSIZE/2 - CHIGH/2 + ASCENT, rb->str);
491
492 if (!rb->active) { /* if non-active, dim button and string */
493 DimRect(rb->win, rb->x, rb->y, RBSIZE, RBSIZE, rb->bg);
494 DimRect(rb->win, rb->x + RBSIZE + 4, rb->y + RBSIZE/2 - CHIGH/2,
495 (u_int) StringWidth(rb->str), (u_int) CHIGH, rb->bg);
496 }
497 }
498
499
500 /***********************************************/
RBSelect(rblist,n)501 void RBSelect(rblist, n)
502 RBUTT *rblist;
503 int n;
504 {
505 RBUTT *rbold, *rb;
506 int i;
507
508 /* makes rb #n the selected rb in the list. Does all redrawing. Does
509 nothing if rb already selected */
510
511 /* get pointers to the currently selected rb and the desired rb */
512 rbold = rblist;
513 while (rbold && !rbold->selected) rbold = (RBUTT *) rbold->next;
514 if (!rbold) return; /* no currently selected item. shouldn't happen */
515
516 rb = rblist; i=0;
517 while (rb && i!=n) {rb = (RBUTT *) rb->next; i++; }
518 if (!rb) return; /* 'n' is out of range */
519
520
521 if (rb == rbold) return; /* 'n' is already selected. do nothing */
522
523 rbold->selected = 0;
524 rb->selected = 1;
525 drawRB(rbold, 0);
526 drawRB(rb, 0);
527 }
528
529
530
531 /***********************************************/
RBWhich(rblist)532 int RBWhich(rblist)
533 RBUTT *rblist;
534 {
535 int i;
536
537 /* returns index of currently selected rb. if none, returns -1 */
538
539 i = 0;
540 while (rblist && !rblist->selected)
541 { rblist = (RBUTT *) rblist->next; i++; }
542
543 if (!rblist) return -1; /* didn't find one */
544 return i;
545 }
546
547
548 /***********************************************/
RBCount(rblist)549 int RBCount(rblist)
550 RBUTT *rblist;
551 {
552 int i;
553
554 /* returns # of rb's in the list */
555
556 i = 0;
557 while (rblist) { rblist = (RBUTT *) rblist->next; i++; }
558 return i;
559 }
560
561
562 /***********************************************/
RBSetActive(rblist,n,act)563 void RBSetActive(rblist, n, act)
564 RBUTT *rblist;
565 int n,act;
566 {
567 RBUTT *rb;
568 int i;
569
570 /* sets 'active' status of rb #n. does redrawing */
571
572 rb=rblist; i=0;
573 while (rb && i!=n) { rb = (RBUTT *) rb->next; i++; }
574 if (!rb) return; /* n out of range. do nothing */
575
576 if (rb->active != act) {
577 rb->active = act;
578 drawRB(rb, 0);
579 }
580 }
581
582
583 /***********************************************/
RBClick(rblist,mx,my)584 int RBClick(rblist, mx, my)
585 RBUTT *rblist;
586 int mx,my;
587 {
588 int i;
589
590 /* searches through rblist to see if mouse click at mx,my is in the
591 clickable region of any of the rb's. If it finds one, it returns
592 it's index in the list. If not, returns -1 */
593
594 i = 0;
595 while (rblist) {
596 if (PTINRECT(mx, my, rblist->x, rblist->y, RBSIZE, RBSIZE)) break;
597
598 rblist = (RBUTT *) rblist->next;
599 i++;
600 }
601
602 if (!rblist) return -1;
603 return(i);
604 }
605
606
607 /***********************************************/
RBTrack(rblist,n)608 int RBTrack(rblist, n)
609 RBUTT *rblist;
610 int n;
611 {
612 RBUTT *rb;
613 Window rW, cW;
614 int i, x, y, rx, ry, lit, rv;
615 unsigned int mask;
616
617 /* returns '1' if selection changed */
618
619 rb=rblist; i=0;
620 while (rb && i!=n) { rb = (RBUTT *) rb->next; i++; }
621 if (!rb) return 0; /* n out of range */
622
623 /* called once we've figured out that the mouse clicked in 'rb' */
624
625 if (!rb->active) return 0;
626
627 lit = 1;
628 drawRB(rb, lit);
629 XFlush(theDisp);
630 Timer(75); /* give chance for 'turn on' to become visible */
631
632 while (XQueryPointer(theDisp,rb->win,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
633 if (!(mask & Button1Mask)) break; /* button released */
634
635 if (!lit && PTINRECT(x, y, rb->x, rb->y, RBSIZE, RBSIZE)) {
636 lit=1;
637 drawRB(rb, lit);
638 XFlush(theDisp);
639 }
640
641 if (lit && !PTINRECT(x, y, rb->x, rb->y, RBSIZE, RBSIZE)) {
642 lit=0;
643 drawRB(rb, lit);
644 XFlush(theDisp);
645 }
646 }
647
648 rv = 0;
649
650 if (lit) {
651 drawRB(rb, 0);
652 if (RBWhich(rblist) != n) rv = 1;
653 RBSelect(rblist, n);
654 }
655
656 XFlush(theDisp);
657 return rv;
658 }
659
660
661
662
663 /******************* CBUTT ROUTINES ************************/
664
665
666
667 #define XVCBSIZE 16
668
669 /***********************************************/
CBCreate(cb,win,x,y,str,fg,bg,hi,lo)670 void CBCreate(cb, win, x,y, str, fg, bg, hi, lo)
671 CBUTT *cb;
672 Window win;
673 int x,y;
674 const char *str;
675 unsigned long fg,bg,hi,lo;
676 {
677 /* fill in the fields of the structure */
678 cb->win = win;
679 cb->x = x;
680 cb->y = y;
681 cb->str = str;
682 cb->val = 0;
683 cb->active = 1;
684 cb->fg = fg;
685 cb->bg = bg;
686 cb->hi = hi;
687 cb->lo = lo;
688
689 /* and, on an unrelated note, if the CB pixmaps haven't been created yet,
690 do so. We'll be needing them, y'see... */
691
692 if (!cbpixmade) {
693 cbcheck = XCreatePixmapFromBitmapData(theDisp, rootW,
694 (char *) cb_check_bits,
695 cb_check_width, cb_check_height, fg, bg, dispDEEP);
696
697 cbpixmade = 1;
698 }
699 }
700
701
702
703
704 /***********************************************/
CBRedraw(cb)705 void CBRedraw(cb)
706 CBUTT *cb;
707 {
708 /* draws the cb being pointed at */
709
710 XSetForeground(theDisp, theGC, cb->bg);
711 XFillRectangle(theDisp, cb->win, theGC, cb->x+2, cb->y+2,
712 XVCBSIZE-3,XVCBSIZE-3);
713
714 XSetForeground(theDisp, theGC, cb->fg);
715 XDrawRectangle(theDisp, cb->win, theGC, cb->x, cb->y, XVCBSIZE, XVCBSIZE);
716 Draw3dRect(cb->win, cb->x+1, cb->y+1, XVCBSIZE-2, XVCBSIZE-2, R3D_OUT, 2,
717 cb->hi, cb->lo, cb->bg);
718
719 if (cb->val) XCopyArea(theDisp, cbcheck, cb->win, theGC,
720 0, 0, cb_check_width, cb_check_height,
721 cb->x+3, cb->y+3);
722
723 XSetForeground(theDisp, theGC, cb->fg);
724 DrawString(cb->win, cb->x + XVCBSIZE+4,
725 cb->y+XVCBSIZE/2 - CHIGH/2 + ASCENT, cb->str);
726
727 if (!cb->active) { /* if non-active, dim button and string */
728 DimRect(cb->win, cb->x, cb->y, XVCBSIZE, XVCBSIZE, cb->bg);
729 DimRect(cb->win, cb->x + XVCBSIZE+4, cb->y+XVCBSIZE/2 - CHIGH/2,
730 (u_int) StringWidth(cb->str), (u_int) CHIGH, cb->bg);
731 }
732 }
733
734
735 /**********************************************/
CBSetActive(cb,act)736 void CBSetActive(cb,act)
737 CBUTT *cb;
738 int act;
739 {
740 if (cb->active != act) {
741 cb->active = act;
742 CBRedraw(cb);
743 }
744 }
745
746
747 /***********************************************/
CBClick(cb,mx,my)748 int CBClick(cb, mx, my)
749 CBUTT *cb;
750 int mx,my;
751 {
752 if (PTINRECT(mx, my, cb->x, cb->y, XVCBSIZE,XVCBSIZE)) return 1;
753 return 0;
754 }
755
756
757 /***********************************************/
CBTrack(cb)758 int CBTrack(cb)
759 CBUTT *cb;
760 {
761 Window rW, cW;
762 int x, y, rx, ry, lit;
763 unsigned int mask;
764
765 /* called once we've figured out that the mouse clicked in 'cb' */
766
767 if (!cb->active) return 0;
768
769 XSetForeground(theDisp, theGC, cb->fg);
770
771 lit = 1;
772 drawCB(cb, lit);
773 XFlush(theDisp);
774 Timer(75); /* give chance for 'turn on' to become visible */
775
776 while (XQueryPointer(theDisp,cb->win,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
777 if (!(mask & Button1Mask)) break; /* button released */
778
779 if (!lit && PTINRECT(x, y, cb->x, cb->y, XVCBSIZE, XVCBSIZE)) {
780 lit=1;
781 drawCB(cb,lit);
782 XFlush(theDisp);
783 }
784
785 if (lit && !PTINRECT(x, y, cb->x, cb->y, XVCBSIZE, XVCBSIZE)) {
786 lit=0;
787 drawCB(cb,lit);
788 XFlush(theDisp);
789 }
790 }
791
792 if (lit) {
793 cb->val = !cb->val;
794 drawCB(cb,0);
795 CBRedraw(cb);
796 }
797
798 XFlush(theDisp);
799
800 return(lit);
801 }
802
803
804 /***********************************************/
drawCB(cb,lit)805 static void drawCB(cb, lit)
806 CBUTT *cb;
807 int lit;
808 {
809 /* draws highlighting */
810 if (lit) {
811 if (ctrlColor)
812 Draw3dRect(cb->win, cb->x+1, cb->y+1, XVCBSIZE-2, XVCBSIZE-2, R3D_IN, 2,
813 cb->hi, cb->lo, cb->bg);
814 else {
815 XSetForeground(theDisp, theGC, cb->fg);
816 XDrawRectangle(theDisp, cb->win, theGC, cb->x+1, cb->y+1,
817 XVCBSIZE-2, XVCBSIZE-2);
818 }
819 }
820
821 else {
822 if (ctrlColor)
823 Draw3dRect(cb->win, cb->x+1, cb->y+1, XVCBSIZE-2, XVCBSIZE-2, R3D_OUT, 2,
824 cb->hi, cb->lo, cb->bg);
825 else {
826 XSetForeground(theDisp, theGC, cb->bg);
827 XDrawRectangle(theDisp, cb->win, theGC, cb->x+1, cb->y+1,
828 XVCBSIZE-2, XVCBSIZE-2);
829 }
830 }
831 }
832
833
834
835 /******************* MBUTT ROUTINES ************************/
836
837
838
839 /***********************************************/
MBCreate(mb,win,x,y,w,h,title,list,nlist,fg,bg,hi,lo)840 void MBCreate(mb, win, x, y, w, h, title, list, nlist, fg, bg, hi, lo)
841 MBUTT *mb;
842 Window win;
843 int x,y;
844 unsigned int w,h;
845 const char *title;
846 const char * const *list;
847 int nlist;
848 unsigned long fg,bg,hi,lo;
849 {
850 XSetWindowAttributes xswa;
851 unsigned long xswamask;
852 int i;
853
854 if (!mbpixmade) {
855 mbchk = XCreatePixmapFromBitmapData(theDisp, rootW, (char *) mb_chk_bits,
856 mb_chk_width, mb_chk_height, fg, bg, dispDEEP);
857 mbpixmade = 1;
858 }
859
860
861 /* fill in the fields of the structure */
862 mb->win = win;
863 mb->x = x;
864 mb->y = y;
865 mb->w = w;
866 mb->h = h;
867 mb->title = title;
868 mb->active = 1;
869 mb->list = list;
870 mb->nlist = nlist;
871 mb->hascheck = 0;
872 mb->fg = fg;
873 mb->bg = bg;
874 mb->hi = hi;
875 mb->lo = lo;
876
877 mb->pix = (Pixmap) NULL;
878 mb->pw = mb->ph = 0;
879
880 for (i=0; i<MAXMBLEN; i++) {
881 mb->flags[i] = 0;
882 mb->dim[i] = 0;
883 }
884
885 /* create popup window (it gets mapped, pos'd and sized later) */
886 xswa.background_pixel = bg;
887 xswa.border_pixel = fg;
888 xswa.save_under = True;
889 xswamask = CWBackPixel | CWBorderPixel | CWSaveUnder;
890
891 mb->mwin = XCreateWindow(theDisp, mb->win, x, y, w, h,
892 (u_int) 2, (int) dispDEEP, InputOutput,
893 theVisual, xswamask, &xswa);
894
895 if (!mb->mwin) FatalError("can't create popup menu window!");
896
897 XSelectInput(theDisp, mb->mwin, ExposureMask | VisibilityChangeMask);
898 XSetTransientForHint(theDisp, mb->mwin, mb->win);
899 }
900
901
902
903
904 /***********************************************/
MBRedraw(mb)905 void MBRedraw(mb)
906 MBUTT *mb;
907 {
908 /* draws a menu button in it's normal state. (When it's actively being
909 used (to select an item), all drawing is handled in MBTrack) */
910
911 int x,y,i,r,x1,y1;
912 unsigned int w,h;
913
914 r = 2; /* amt of shadow */
915 x = mb->x; y = mb->y; w = mb->w; h = mb->h;
916 x1 = x + (int) w;
917 y1 = y + (int) h;
918
919 XSetForeground(theDisp, theGC, mb->bg);
920 XFillRectangle(theDisp, mb->win, theGC, x+1, y+1, w-1, h-1);
921
922 XSetForeground(theDisp, theGC, mb->fg);
923 XDrawRectangle(theDisp, mb->win, theGC, x, y, w, h);
924 Draw3dRect(mb->win, x+1, y+1, w-2, h-2, R3D_OUT, 2, mb->hi, mb->lo, mb->bg);
925
926 XSetForeground(theDisp, theGC, mb->fg);
927
928 /* draw shadow */
929 for (i=1; i<=r; i++) {
930 XDrawLine(theDisp, mb->win, theGC, x+r, y1+i, x1+i, y1+i);
931 XDrawLine(theDisp, mb->win, theGC, x1+i, y1+i, x1+i, y+r);
932 }
933
934 if (mb->pix != None) { /* draw pixmap centered in butt */
935 x1 = x + (1+w - mb->pw)/2;
936 y1 = y + (1+h - mb->ph)/2;
937
938 XSetForeground(theDisp, theGC, mb->fg);
939 XSetBackground(theDisp, theGC, mb->bg);
940 XCopyPlane(theDisp, mb->pix, mb->win, theGC, 0,0,
941 (u_int) mb->pw, (u_int) mb->ph, x1,y1, 1L);
942 if (!mb->active)
943 DimRect(mb->win, x1,y1, (u_int) mb->pw, (u_int) mb->ph, mb->bg);
944 }
945
946 else { /* draw string centered in butt */
947 const char *str;
948 char *tmp;
949 char stbuf[256];
950
951 if (mb->title) str = mb->title;
952 else { /* find first checked item, and show that as the title */
953 int i;
954
955 if (mb->list) {
956 for (i=0; i<mb->nlist && !mb->flags[i]; i++);
957 if (i==mb->nlist) i = 0; /* shouldn't happen */
958 str = mb->list[i];
959 }
960 else str = "";
961 }
962
963 /* truncate at TAB, if any */
964 strcpy(stbuf, str);
965 if ((tmp = (char *) index(stbuf, '\t')) != NULL) *tmp = '\0';
966 str = stbuf;
967
968 x1 = CENTERX(mfinfo, x + w/2, str);
969 y1 = CENTERY(mfinfo, y + h/2);
970
971 if (mb->active) {
972 DrawString(mb->win, x1,y1, str);
973 }
974 else { /* stipple if not active */
975 XSetFillStyle(theDisp, theGC, FillStippled);
976 XSetStipple(theDisp, theGC, dimStip);
977 DrawString(mb->win, x1,y1, str);
978 XSetFillStyle(theDisp,theGC,FillSolid);
979 }
980 }
981 }
982
983
984 /**********************************************/
MBSetActive(mb,act)985 void MBSetActive(mb,act)
986 MBUTT *mb;
987 int act;
988 {
989 if (mb->active != act) {
990 mb->active = act;
991 MBRedraw(mb);
992 }
993 }
994
995
996 /**********************************************/
MBWhich(mb)997 int MBWhich(mb)
998 MBUTT *mb;
999 {
1000 /* returns index of first checked selection, or '-1' if nothing selected */
1001
1002 int i;
1003
1004 if (!mb->hascheck) return -1;
1005
1006 for (i=0; i<mb->nlist; i++)
1007 if (mb->flags[i]) return i;
1008
1009 return -1;
1010 }
1011
1012
1013 /**********************************************/
MBSelect(mb,n)1014 void MBSelect(mb, n)
1015 MBUTT *mb;
1016 int n;
1017 {
1018 /* makes entry #n the selected entry (ie, the only one with a check mark)
1019 Does all redrawing. Does nothing if entry #n already selected.
1020 Don't let it select 'dim' entries */
1021
1022 int i;
1023
1024 if (n<0 || n>mb->nlist) return; /* # out of range */
1025 if (!mb->hascheck) return; /* shouldn't happen */
1026 if (mb->flags[n]) return; /* already selected */
1027
1028 for (i=0; i<MAXMBLEN; i++) mb->flags[i] = 0;
1029
1030 mb->flags[n] = 1;
1031 if (!mb->title) MBRedraw(mb); /* mb shows cur selection */
1032 }
1033
1034
1035
1036 /***********************************************/
MBClick(mb,mx,my)1037 int MBClick(mb, mx, my)
1038 MBUTT *mb;
1039 int mx,my;
1040 {
1041 if (PTINRECT(mx, my, mb->x, mb->y, mb->w, mb->h)) return 1;
1042 return 0;
1043 }
1044
1045
1046 /***********************************************/
MBTrack(mb)1047 int MBTrack(mb)
1048 MBUTT *mb;
1049 {
1050 Window rW, cW, win;
1051 int i, x, y, rx, ry, extratop, hascheck;
1052 unsigned int mask;
1053 int mwide, mhigh, mx, my, j, lit, lastlit;
1054 int mtabwide;
1055 XSizeHints hints;
1056 XEvent event;
1057
1058
1059 /* returns selected menu choice index, or '-1' if none */
1060
1061 if (!mb->active || !mb->nlist) return -1;
1062
1063 extratop = (mb->title) ? LINEHIGH+3 : 1-SPACING; /*add extra line for title*/
1064
1065 mtabwide = 0;
1066
1067 mwide = 1; /* compute maximum width */
1068 for (i=0; i<mb->nlist; i++) {
1069 if (!index(mb->list[i], '\t')) {
1070 j = StringWidth(mb->list[i]);
1071 if (j > mwide) mwide = j;
1072 }
1073 else {
1074 char *sp, str[256];
1075
1076 strcpy(str, mb->list[i]);
1077 sp = (char *) index(str, '\t');
1078 j = StringWidth(sp+1);
1079 if (j>mtabwide) mtabwide = j;
1080
1081 *sp = '\0';
1082 j = StringWidth(str);
1083 if ((j + 4 + mtabwide)>mwide) mwide = (j+4+mtabwide);
1084 }
1085 }
1086 mwide += 8; /* extra room at edges */
1087
1088 /* make wider if any checked menu items */
1089 for (i=0; i<mb->nlist && !mb->flags[i]; i++);
1090 hascheck = (i<mb->nlist || mb->hascheck);
1091
1092 if (hascheck && mb->title) mwide += 8;
1093
1094 if (mwide < (mb->w+1)) mwide = mb->w+1; /* at least as wide as button */
1095
1096 mhigh = mb->nlist * LINEHIGH + 2 + extratop;
1097
1098 mx = mb->x-1; my = mb->y - 1;
1099 if (mb->title && mwide > mb->w) mx -= ((mwide - mb->w)/2);
1100
1101
1102 /* create/map window, and warp mouse if we had to move the window */
1103 win = mb->mwin;
1104 XMoveResizeWindow(theDisp, win, mx, my, (u_int) mwide, (u_int) mhigh);
1105
1106 hints.width = hints.min_width = hints.max_width = mwide;
1107 hints.height = hints.min_height = hints.max_height = mhigh;
1108 hints.x = mx; hints.y = my;
1109 hints.flags = (USSize | PMinSize | PMaxSize | PPosition);
1110 XSetNormalHints(theDisp, win, &hints);
1111
1112 XMapRaised(theDisp, win);
1113
1114 /* wait for window to become mapped */
1115 XWindowEvent(theDisp, win, VisibilityChangeMask, &event);
1116
1117
1118 /* draw the menu */
1119 XSetForeground(theDisp, theGC, mb->fg);
1120 x = (hascheck) ? 12 : 4;
1121 if (mb->title) { /* draw a title on this menu */
1122 CenterString(win, mwide/2-1, (extratop-2)/2, mb->title);
1123
1124 if (ctrlColor) {
1125 XSetForeground(theDisp, theGC, mb->fg);
1126 XDrawLine(theDisp, win, theGC, 0, extratop-2, mwide, extratop-2);
1127 XSetForeground(theDisp, theGC, mb->lo);
1128 XDrawLine(theDisp, win, theGC, 0, extratop-1, mwide, extratop-1);
1129 XSetForeground(theDisp, theGC, mb->hi);
1130 XDrawLine(theDisp, win, theGC, 0, extratop, mwide, extratop);
1131 XSetForeground(theDisp, theGC, mb->fg);
1132 }
1133 else { /* b/w system */
1134 XDrawLine(theDisp, win, theGC, 0, extratop-2, mwide, extratop-2);
1135 XDrawLine(theDisp, win, theGC, 0, extratop, mwide, extratop);
1136 }
1137 }
1138
1139 y = ASCENT + SPACING + extratop;
1140 for (i=0; i<mb->nlist; i++) {
1141 char txtstr[256], *tabstr;
1142
1143 strcpy(txtstr, mb->list[i]);
1144 if ((tabstr = (char *) index(txtstr, '\t'))) {
1145 *tabstr = '\0'; tabstr++;
1146 }
1147
1148 if (mb->flags[i]) {
1149 XCopyArea(theDisp, mbchk, win, theGC, 0, 0, mb_chk_width, mb_chk_height,
1150 x - 10, y - 8);
1151 }
1152
1153 if (!strcmp(mb->list[i], MBSEP)) {
1154 mb->dim[i] = 1; /* don't select this one */
1155 if (ctrlColor) {
1156 XSetForeground(theDisp, theGC, mb->fg);
1157 XDrawLine(theDisp,win,theGC,4,y-(ASCENT/2)-1, mwide-5, y-(ASCENT/2)-1);
1158
1159 XSetForeground(theDisp, theGC, mb->lo);
1160 XDrawLine(theDisp,win,theGC,4,y-(ASCENT/2), mwide-5, y-(ASCENT/2));
1161
1162 XSetForeground(theDisp, theGC, mb->hi);
1163 XDrawLine(theDisp,win,theGC,4,y-(ASCENT/2)+1, mwide-5, y-(ASCENT/2)+1);
1164 XSetForeground(theDisp, theGC, mb->fg);
1165 }
1166 else
1167 XDrawLine(theDisp, win, theGC, 4, y-(ASCENT/2), mwide-5, y-(ASCENT/2));
1168 }
1169 else {
1170 DrawString(win, x, y, txtstr);
1171 if (tabstr)
1172 DrawString(win, mwide - mtabwide - 4, y, tabstr);
1173
1174 if (mb->dim[i])
1175 DimRect(win, x, y-ASCENT, (u_int) mwide, (u_int) CHIGH, mb->bg);
1176 XSetForeground(theDisp, theGC, mb->fg);
1177 }
1178
1179 y += LINEHIGH;
1180 }
1181
1182 XFlush(theDisp);
1183
1184
1185 /* track the mouse */
1186 XSetFunction(theDisp, theGC, GXinvert); /* go in to 'invert' mode */
1187 XSetPlaneMask(theDisp, theGC, mb->fg ^ mb->bg);
1188
1189 lit = lastlit = -1;
1190 while (XQueryPointer(theDisp,win,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
1191 if (!(mask & Button1Mask)) break; /* button released */
1192
1193 /* determine which choice the mouse is in. -1 if none */
1194 j = extratop+2;
1195 if (x < 0 || x > mwide) lit = -1;
1196 else {
1197 for (i=0; i<mb->nlist; i++, j+=LINEHIGH) {
1198 if (y>=j && y < j+LINEHIGH) { lit = i; break; }
1199 }
1200 if (i == mb->nlist) lit = -1;
1201 }
1202
1203 /* handle dimmed selections */
1204 if (lit >= 0 && mb->dim[lit]) lit = -1;
1205
1206 if (lit != lastlit) {
1207 if (lit >= 0) {
1208 y = extratop + 2 + lit*LINEHIGH;
1209 XFillRectangle(theDisp,win,theGC,0,y,(u_int) mwide,(u_int) LINEHIGH);
1210 }
1211 if (lastlit >= 0) {
1212 y = extratop + 2 + lastlit*LINEHIGH;
1213 XFillRectangle(theDisp,win,theGC,0,y,(u_int) mwide,(u_int) LINEHIGH);
1214 }
1215 lastlit = lit;
1216 }
1217 }
1218
1219 /* flash the selected choice, if any */
1220 if (lit >= 0) {
1221 y = extratop + 2 + lit*LINEHIGH;
1222 for (i=0; i<5; i++) {
1223 XFillRectangle(theDisp, win, theGC, 0,y,(u_int) mwide,(u_int) LINEHIGH);
1224 XFlush(theDisp);
1225 Timer(50);
1226 }
1227 }
1228
1229 XSetFunction(theDisp, theGC, GXcopy); /* back to 'normal' mode */
1230 XSetPlaneMask(theDisp, theGC, AllPlanes);
1231
1232 /* could try eating all remaining events for 'win' before unmapping */
1233
1234 XSync(theDisp, False); /* make sure 'map' has taken place */
1235 XUnmapWindow(theDisp, win);
1236
1237 MBRedraw(mb);
1238
1239 return lit;
1240 }
1241
1242
1243
1244
1245