comparison lwlib/xlwradio.c @ 398:74fd4e045ea6 r21-2-29

Import from CVS: tag r21-2-29
author cvs
date Mon, 13 Aug 2007 11:13:30 +0200
parents
children b8cc9ab3f761
comparison
equal deleted inserted replaced
397:f4aeb21a5bad 398:74fd4e045ea6
1 /* Radio 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: Radio.c 1.1 */
22
23 /*
24 * Radio.c - Radio button widget
25 *
26 * Author: Edward A. Falk
27 * falk@falconer.vip.best.com
28 *
29 * Date: June 30, 1997
30 *
31 *
32 * Overview: This widget is identical to the Toggle widget in behavior,
33 * but completely different in appearance. This widget looks like a small
34 * diamond-shaped button with a label to the right.
35 *
36 * To make this work, we subclass the Toggle widget to inherit its behavior
37 * and to inherit the label-drawing function from which Toggle is
38 * subclassed. We then completely replace the Expose, Set, Unset
39 * and Highlight member functions.
40 *
41 * The Set and Unset actions are slightly unorthodox. In Toggle's
42 * ClassInit function, Toggle searches the Command actions list and
43 * "steals" the Set and Unset functions, caching pointers to them in its
44 * class record. It then calls these functions from its own ToggleSet
45 * and Toggle actions.
46 *
47 * We, in turn, override the Set() and Unset() actions in our own ClassRec.
48 */
49
50
51 #include <config.h>
52 #include <stdio.h>
53
54 #include <X11/IntrinsicP.h>
55 #include <X11/StringDefs.h>
56 #include ATHENA_INCLUDE(XawInit.h)
57 #include "../src/xmu.h"
58 #include "xlwradioP.h"
59
60 #define BOX_SIZE 13
61
62 #define rclass(w) ((RadioWidgetClass)((w)->core.widget_class))
63
64
65 #ifdef _ThreeDP_h
66 #define swid(rw) ((rw)->threeD.shadow_width)
67 #else
68 #define swid(rw) ((rw)->core.border_width)
69 #endif
70
71 #define bsize(rw) (rclass(rw)->radio_class.dsize)
72 #define bs(rw) (bsize(rw) + 2*swid(rw))
73
74
75
76 /****************************************************************
77 *
78 * Full class record constant
79 *
80 ****************************************************************/
81
82 /* The translations table from Toggle do not need to be
83 * overridden by Radio
84 */
85
86
87 /* Member functions */
88
89 static void RadioInit (Widget, Widget, ArgList, Cardinal *);
90 static void RadioExpose (Widget, XEvent *, Region);
91 static void RadioResize (Widget);
92 static void RadioDestroy (Widget, XtPointer, XtPointer);
93 static void RadioClassInit (void);
94 static void RadioClassPartInit (WidgetClass);
95 static Boolean RadioSetValues (Widget, Widget, Widget, ArgList, Cardinal *);
96 static void DrawDiamond (Widget);
97 static XtGeometryResult RadioQueryGeometry (Widget, XtWidgetGeometry *,
98 XtWidgetGeometry *);
99
100 /* Action procs */
101
102 static void RadioHighlight (Widget, XEvent *, String *, Cardinal *);
103 static void RadioUnhighlight (Widget, XEvent *, String *, Cardinal *);
104
105 /* internal privates */
106
107 static void RadioSize (RadioWidget, Dimension *, Dimension *);
108
109 /* The actions table from Toggle is almost perfect, but we need
110 * to override Highlight, Set, and Unset.
111 */
112
113 static XtActionsRec actionsList[] =
114 {
115 {"highlight", RadioHighlight},
116 {"unhighlight", RadioUnhighlight},
117 };
118
119 #define SuperClass ((ToggleWidgetClass)&toggleClassRec)
120
121 RadioClassRec radioClassRec = {
122 {
123 (WidgetClass) SuperClass, /* superclass */
124 "Radio", /* class_name */
125 sizeof(RadioRec), /* size */
126 RadioClassInit, /* class_initialize */
127 RadioClassPartInit, /* class_part_initialize */
128 FALSE, /* class_inited */
129 RadioInit, /* initialize */
130 NULL, /* initialize_hook */
131 XtInheritRealize, /* realize */
132 actionsList, /* actions */
133 XtNumber(actionsList), /* num_actions */
134 NULL, /* resources */
135 0, /* resource_count */
136 NULLQUARK, /* xrm_class */
137 TRUE, /* compress_motion */
138 TRUE, /* compress_exposure */
139 TRUE, /* compress_enterleave */
140 FALSE, /* visible_interest */
141 NULL, /* destroy */
142 RadioResize, /* resize */
143 RadioExpose, /* expose */
144 RadioSetValues, /* set_values */
145 NULL, /* set_values_hook */
146 XtInheritSetValuesAlmost, /* set_values_almost */
147 NULL, /* get_values_hook */
148 NULL, /* accept_focus */
149 XtVersion, /* version */
150 NULL, /* callback_private */
151 XtInheritTranslations, /* tm_table */
152 RadioQueryGeometry, /* query_geometry */
153 XtInheritDisplayAccelerator, /* display_accelerator */
154 NULL /* extension */
155 }, /* CoreClass fields initialization */
156 {
157 XtInheritChangeSensitive /* change_sensitive */
158 }, /* SimpleClass fields initialization */
159 #ifdef _ThreeDP_h
160 {
161 XtInheritXaw3dShadowDraw /* field not used */
162 }, /* ThreeDClass fields initialization */
163 #endif
164 {
165 0 /* field not used */
166 }, /* LabelClass fields initialization */
167 {
168 0 /* field not used */
169 }, /* CommandClass fields initialization */
170 {
171 RadioSet, /* Set Procedure. */
172 RadioUnset, /* Unset Procedure. */
173 NULL /* extension. */
174 }, /* ToggleClass fields initialization */
175 {
176 BOX_SIZE,
177 DrawDiamond, /* draw procedure */
178 NULL /* extension. */
179 } /* RadioClass fields initialization */
180 };
181
182 /* for public consumption */
183 WidgetClass radioWidgetClass = (WidgetClass) &radioClassRec;
184
185
186
187
188
189
190 /****************************************************************
191 *
192 * Class Methods
193 *
194 ****************************************************************/
195
196 static void
197 RadioClassInit (void)
198 {
199 XawInitializeWidgetSet();
200 }
201
202 static void
203 RadioClassPartInit (WidgetClass class)
204 {
205 RadioWidgetClass c = (RadioWidgetClass) class ;
206 RadioWidgetClass super = (RadioWidgetClass)c->core_class.superclass ;
207
208 if( c->radio_class.drawDiamond == NULL ||
209 c->radio_class.drawDiamond == XtInheritDrawDiamond )
210 {
211 c->radio_class.drawDiamond = super->radio_class.drawDiamond ;
212 }
213 }
214
215
216
217
218 /*ARGSUSED*/
219 static void
220 RadioInit (Widget request,
221 Widget new,
222 ArgList args,
223 Cardinal *num_args)
224 {
225 RadioWidget rw = (RadioWidget) new;
226 RadioWidget rw_req = (RadioWidget) request;
227 Dimension w,h ;
228
229 /* Select initial size for the widget */
230 if( rw_req->core.width == 0 || rw_req->core.height == 0 )
231 {
232 RadioSize(rw, &w,&h) ;
233 if( rw_req->core.width == 0 )
234 rw->core.width = w ;
235 if( rw_req->core.height == 0 )
236 rw->core.height = h ;
237 rw->core.widget_class->core_class.resize(new) ;
238 }
239 }
240
241 /* Function Name: RadioDestroy
242 * Description: Destroy Callback for radio widget.
243 * Arguments: w - the radio widget that is being destroyed.
244 * junk, grabage - not used.
245 * Returns: none.
246 */
247
248 /* ARGSUSED */
249 static void
250 RadioDestroy (Widget w,
251 XtPointer junk,
252 XtPointer garbage)
253 {
254 /* TODO: get rid of this */
255 }
256
257
258 /* React to size change from manager. Label widget will compute some internal
259 * stuff, but we need to override. This code requires knowledge of the
260 * internals of the Label widget.
261 */
262
263 static void
264 RadioResize (Widget w)
265 {
266 RadioWidget rw = (RadioWidget)w ;
267
268 /* call parent resize proc */
269 SuperClass->core_class.resize(w) ;
270
271 /* override label offset */
272
273 switch( rw->label.justify ) {
274 case XtJustifyLeft:
275 rw->label.label_x += bs(rw) + rw->label.internal_width ;
276 break ;
277 case XtJustifyRight:
278 break ;
279 case XtJustifyCenter:
280 default:
281 rw->label.label_x += (bs(rw) + rw->label.internal_width)/2 ;
282 break ;
283 }
284 }
285
286
287 /*
288 * Repaint the widget window.
289 */
290
291 static void
292 RadioExpose (Widget w,
293 XEvent *event,
294 Region region)
295 {
296 RadioWidget rw = (RadioWidget) w ;
297 Display *dpy = XtDisplay(w) ;
298 Window win = XtWindow(w) ;
299 GC gc ;
300 Pixmap left_bitmap ;
301 extern WidgetClass labelWidgetClass ;
302
303 /* Note: the Label widget examines the region to decide if anything
304 * needs to be drawn. I'm not sure that this is worth the effort,
305 * but it bears thinking on.
306 */
307
308 /* Command widget may sometimes override the label GC in order
309 * to draw inverse video. We don't use inverse video, so we need
310 * to restore the label's normal GC.
311 */
312 rw->label.normal_GC = rw->command.normal_GC ;
313
314
315 /* Let label widget draw the label. If there was an lbm_x
316 * field, we could let Label draw the bitmap too. But there
317 * isn't, so we need to temporarily remove the bitmap and
318 * draw it ourself later.
319 */
320 left_bitmap = rw->label.left_bitmap ;
321 rw->label.left_bitmap = None ;
322 labelWidgetClass->core_class.expose(w,event,region) ;
323 rw->label.left_bitmap = left_bitmap ;
324
325 /* now manually draw the left bitmap. TODO: 3-d look, xaw-xpm */
326 gc = XtIsSensitive(w) ? rw->label.normal_GC : rw->label.gray_GC ;
327 if( left_bitmap != None && rw->label.lbm_width > 0 )
328 {
329 /* TODO: handle pixmaps */
330 XCopyPlane(dpy, left_bitmap, win, gc,
331 0,0, rw->label.lbm_width, rw->label.lbm_height,
332 (int) rw->label.internal_width*2 + bs(rw),
333 (int) rw->label.internal_height + rw->label.lbm_y,
334 (u_long) 1L) ;
335 }
336
337 /* Finally, the button itself */
338 ((RadioWidgetClass)(w->core.widget_class))->radio_class.drawDiamond(w) ;
339 }
340
341
342
343
344 /************************************************************
345 *
346 * Set specified arguments into widget
347 *
348 ***********************************************************/
349
350
351 /* ARGSUSED */
352 static Boolean
353 RadioSetValues (Widget current,
354 Widget request,
355 Widget new,
356 ArgList args,
357 Cardinal *num_args)
358 {
359 RadioWidget oldrw = (RadioWidget) current;
360 RadioWidget newrw = (RadioWidget) new;
361
362 /* Need to find out if the size of the widget changed. Set new size
363 * if it did and resize is permitted. One way to determine of the
364 * widget changed size would be to scan the args list. Another way
365 * is to compare the old and new widgets and see if any of several
366 * size-related fields have been changed. The Label widget chose the
367 * former method, but I choose the latter.
368 */
369
370 if( newrw->label.resize &&
371 ( newrw->core.width != oldrw->core.width ||
372 newrw->core.height != oldrw->core.height ||
373 newrw->core.border_width != oldrw->core.border_width ) )
374 {
375 RadioSize(newrw, &newrw->core.width, &newrw->core.height) ;
376 }
377
378 return FALSE ;
379 }
380
381 static XtGeometryResult
382 RadioQueryGeometry (Widget w,
383 XtWidgetGeometry *intended,
384 XtWidgetGeometry *preferred)
385 {
386 RadioWidget rw = (RadioWidget) w;
387
388 preferred->request_mode = CWWidth | CWHeight;
389 RadioSize(rw, &preferred->width, &preferred->height) ;
390
391 if ( ((intended->request_mode & (CWWidth | CWHeight))
392 == (CWWidth | CWHeight)) &&
393 intended->width == preferred->width &&
394 intended->height == preferred->height)
395 return XtGeometryYes;
396 else if (preferred->width == w->core.width &&
397 preferred->height == w->core.height)
398 return XtGeometryNo;
399 else
400 return XtGeometryAlmost;
401 }
402
403
404
405
406
407 /************************************************************
408 *
409 * Action Procedures
410 *
411 ************************************************************/
412
413 /*
414 * Draw the highlight border around the widget. The Command widget
415 * did this by drawing through a mask. We do it by just drawing the
416 * border.
417 */
418
419 static void
420 DrawHighlight (Widget w,
421 GC gc)
422 {
423 RadioWidget rw = (RadioWidget)w;
424 XRectangle rects[4] ;
425 Dimension ht = rw->command.highlight_thickness ;
426
427 if( ht <= 0 ||
428 ht > rw->core.width/2 ||
429 ht > rw->core.height/2 )
430 return ;
431
432 if( ! XtIsRealized(w) )
433 return ;
434
435 rects[0].x = 0 ; rects[0].y = 0 ;
436 rects[0].width = rw->core.width ; rects[0].height = ht ;
437 rects[1].x = 0 ; rects[1].y = rw->core.height - ht ;
438 rects[1].width = rw->core.width ; rects[1].height = ht ;
439 rects[2].x = 0 ; rects[2].y = ht ;
440 rects[2].width = ht ; rects[2].height = rw->core.height - ht*2 ;
441 rects[3].x = rw->core.width - ht ; rects[3].y = ht ;
442 rects[3].width = ht ; rects[3].height = rw->core.height - ht*2 ;
443 XFillRectangles( XtDisplay(w), XtWindow(w), gc, rects, 4) ;
444 }
445
446 static void
447 RadioHighlight (Widget w,
448 XEvent *event,
449 String *params,
450 Cardinal *num_params)
451 {
452 RadioWidget rw = (RadioWidget)w;
453 DrawHighlight(w, rw->command.normal_GC) ;
454 }
455
456
457 static void
458 RadioUnhighlight (Widget w,
459 XEvent *event,
460 String *params,
461 Cardinal *num_params)
462 {
463 RadioWidget rw = (RadioWidget)w;
464 DrawHighlight(w, rw->command.inverse_GC) ;
465 }
466
467
468 /* ARGSUSED */
469 void
470 RadioSet (Widget w,
471 XEvent *event,
472 String *params, /* unused */
473 Cardinal *num_params) /* unused */
474 {
475 RadioWidget rw = (RadioWidget)w;
476 RadioWidgetClass class = (RadioWidgetClass) w->core.widget_class ;
477
478 if( rw->command.set )
479 return ;
480
481 rw->command.set = TRUE ;
482 if( XtIsRealized(w) )
483 class->radio_class.drawDiamond(w) ;
484 }
485
486
487 /* ARGSUSED */
488 void
489 RadioUnset (Widget w,
490 XEvent *event,
491 String *params, /* unused */
492 Cardinal *num_params) /* unused */
493 {
494 RadioWidget rw = (RadioWidget)w;
495 RadioWidgetClass class = (RadioWidgetClass) w->core.widget_class ;
496
497 if( ! rw->command.set )
498 return ;
499
500 rw->command.set = FALSE ;
501 if( XtIsRealized(w) )
502 class->radio_class.drawDiamond(w) ;
503 }
504
505
506
507
508 /************************************************************
509 *
510 * Internal Procedures
511 *
512 ************************************************************/
513
514
515 /* Size of widget. Width is size of box plus width of border around
516 * box plus width of label plus three margins plus the size of the left
517 * bitmap, if any. Height is max(box,bitmap,label) plus two margins.
518 */
519
520 static void
521 RadioSize (RadioWidget rw,
522 Dimension *w,
523 Dimension *h)
524 {
525 *w = rw->label.label_width + bs(rw) + LEFT_OFFSET(rw) +
526 3 * rw->label.internal_width ;
527 *h = Max( rw->label.label_height, bs(rw) ) +
528 2 * rw->label.internal_width ;
529 }
530
531
532 static void
533 DrawDiamond (Widget w)
534 {
535 RadioWidget rw = (RadioWidget) w ;
536 Display *dpy = XtDisplay(w) ;
537 Window win = XtWindow(w) ;
538 GC gc, gci ;
539
540 XPoint pts[5] ;
541 Dimension del = bsize(rw)/2 ;
542 Position x,y ; /* diamond center */
543 #ifdef _ThreeDP_h
544 int i=0;
545 Dimension s = swid(rw) ;
546 GC top, bot, ctr ;
547 #endif
548 gc = XtIsSensitive(w) ? rw->command.normal_GC : rw->label.gray_GC ;
549
550 gci = rw->command.set ? rw->command.normal_GC : rw->command.inverse_GC ;
551
552 x = rw->label.internal_width + bs(rw)/2 ;
553 y = rw->core.height/2 ;
554
555 #ifdef _ThreeDP_h
556 if( ! rw->command.set ) {
557 top = rw->threeD.top_shadow_GC ;
558 bot = rw->threeD.bot_shadow_GC ;
559 ctr = gc ; /* TODO */
560 } else {
561 top = rw->threeD.bot_shadow_GC ;
562 bot = rw->threeD.top_shadow_GC ;
563 ctr = gc ; /* TODO */
564 }
565 #endif
566
567 pts[0].x = x - del ;
568 pts[0].y = y ;
569 pts[1].x = x ;
570 pts[1].y = y - del ;
571 pts[2].x = x + del ;
572 pts[2].y = y ;
573 pts[3].x = x ;
574 pts[3].y = y + del ;
575 pts[4] = pts[0] ;
576 XFillPolygon(dpy,win,gci, pts,4, Convex, CoordModeOrigin) ;
577
578 #ifdef _ThreeDP_h
579 for(i=0; i<s; ++i) {
580 XDrawLine(dpy,win,bot, x-i-del,y, x,y+del+i) ;
581 XDrawLine(dpy,win,bot, x+del+i,y, x,y+del+i) ;
582 }
583 for(i=0; i<s; ++i) {
584 XDrawLine(dpy,win,top, x-del-i,y, x,y-del-i) ;
585 XDrawLine(dpy,win,top, x+del+i,y, x,y-del-i) ;
586 }
587 #else
588 XDrawLines(dpy,win,gc, pts,5, CoordModeOrigin) ;
589 #endif
590 }