Mercurial > hg > xemacs-beta
annotate lwlib/xlwradio.c @ 4522:fc7067b7f407
Backout last patch; forgot to specify file.
author | Stephen J. Turnbull <stephen@xemacs.org> |
---|---|
date | Wed, 29 Oct 2008 03:37:16 +0900 |
parents | 383ab474a241 |
children | 726060ee587c |
rev | line source |
---|---|
424 | 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 | |
442 | 28 * |
424 | 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> | |
442 | 56 #include ATHENA_XawInit_h_ |
424 | 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 RadioClassInit (void); | |
93 static void RadioClassPartInit (WidgetClass); | |
94 static Boolean RadioSetValues (Widget, Widget, Widget, ArgList, Cardinal *); | |
95 static void DrawDiamond (Widget); | |
96 static XtGeometryResult RadioQueryGeometry (Widget, XtWidgetGeometry *, | |
97 XtWidgetGeometry *); | |
3072 | 98 #if 0 |
99 /* #### This function isn't used and is slated for destruction. | |
100 Can we just nuke it? */ | |
101 static void RadioDestroy (Widget, XtPointer, XtPointer); | |
102 #endif | |
424 | 103 |
104 /* Action procs */ | |
105 | |
106 static void RadioHighlight (Widget, XEvent *, String *, Cardinal *); | |
107 static void RadioUnhighlight (Widget, XEvent *, String *, Cardinal *); | |
108 | |
109 /* internal privates */ | |
110 | |
111 static void RadioSize (RadioWidget, Dimension *, Dimension *); | |
112 | |
113 /* The actions table from Toggle is almost perfect, but we need | |
114 * to override Highlight, Set, and Unset. | |
115 */ | |
116 | |
117 static XtActionsRec actionsList[] = | |
118 { | |
4522
fc7067b7f407
Backout last patch; forgot to specify file.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4521
diff
changeset
|
119 {"highlight", RadioHighlight}, |
fc7067b7f407
Backout last patch; forgot to specify file.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4521
diff
changeset
|
120 {"unhighlight", RadioUnhighlight}, |
424 | 121 }; |
122 | |
123 #define SuperClass ((ToggleWidgetClass)&toggleClassRec) | |
124 | |
125 RadioClassRec radioClassRec = { | |
126 { | |
442 | 127 (WidgetClass) SuperClass, /* superclass */ |
4522
fc7067b7f407
Backout last patch; forgot to specify file.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4521
diff
changeset
|
128 "Radio", /* class_name */ |
424 | 129 sizeof(RadioRec), /* size */ |
130 RadioClassInit, /* class_initialize */ | |
131 RadioClassPartInit, /* class_part_initialize */ | |
132 FALSE, /* class_inited */ | |
133 RadioInit, /* initialize */ | |
134 NULL, /* initialize_hook */ | |
135 XtInheritRealize, /* realize */ | |
136 actionsList, /* actions */ | |
137 XtNumber(actionsList), /* num_actions */ | |
138 NULL, /* resources */ | |
139 0, /* resource_count */ | |
140 NULLQUARK, /* xrm_class */ | |
141 TRUE, /* compress_motion */ | |
142 TRUE, /* compress_exposure */ | |
143 TRUE, /* compress_enterleave */ | |
144 FALSE, /* visible_interest */ | |
145 NULL, /* destroy */ | |
146 RadioResize, /* resize */ | |
147 RadioExpose, /* expose */ | |
148 RadioSetValues, /* set_values */ | |
149 NULL, /* set_values_hook */ | |
150 XtInheritSetValuesAlmost, /* set_values_almost */ | |
151 NULL, /* get_values_hook */ | |
152 NULL, /* accept_focus */ | |
153 XtVersion, /* version */ | |
154 NULL, /* callback_private */ | |
155 XtInheritTranslations, /* tm_table */ | |
156 RadioQueryGeometry, /* query_geometry */ | |
157 XtInheritDisplayAccelerator, /* display_accelerator */ | |
158 NULL /* extension */ | |
159 }, /* CoreClass fields initialization */ | |
160 { | |
442 | 161 XtInheritChangeSensitive /* change_sensitive */ |
424 | 162 }, /* SimpleClass fields initialization */ |
163 #ifdef _ThreeDP_h | |
164 { | |
165 XtInheritXaw3dShadowDraw /* field not used */ | |
166 }, /* ThreeDClass fields initialization */ | |
167 #endif | |
168 { | |
169 0 /* field not used */ | |
170 }, /* LabelClass fields initialization */ | |
171 { | |
172 0 /* field not used */ | |
173 }, /* CommandClass fields initialization */ | |
174 { | |
175 RadioSet, /* Set Procedure. */ | |
176 RadioUnset, /* Unset Procedure. */ | |
177 NULL /* extension. */ | |
178 }, /* ToggleClass fields initialization */ | |
179 { | |
180 BOX_SIZE, | |
181 DrawDiamond, /* draw procedure */ | |
182 NULL /* extension. */ | |
183 } /* RadioClass fields initialization */ | |
184 }; | |
185 | |
186 /* for public consumption */ | |
187 WidgetClass radioWidgetClass = (WidgetClass) &radioClassRec; | |
188 | |
189 | |
190 | |
191 | |
192 | |
193 | |
194 /**************************************************************** | |
195 * | |
196 * Class Methods | |
197 * | |
198 ****************************************************************/ | |
199 | |
200 static void | |
201 RadioClassInit (void) | |
202 { | |
203 XawInitializeWidgetSet(); | |
204 } | |
205 | |
206 static void | |
1201 | 207 RadioClassPartInit (WidgetClass class_) |
424 | 208 { |
1201 | 209 RadioWidgetClass c = (RadioWidgetClass) class_ ; |
424 | 210 RadioWidgetClass super = (RadioWidgetClass)c->core_class.superclass ; |
211 | |
212 if( c->radio_class.drawDiamond == NULL || | |
213 c->radio_class.drawDiamond == XtInheritDrawDiamond ) | |
214 { | |
215 c->radio_class.drawDiamond = super->radio_class.drawDiamond ; | |
216 } | |
217 } | |
218 | |
219 | |
220 | |
221 | |
222 /*ARGSUSED*/ | |
223 static void | |
224 RadioInit (Widget request, | |
3055 | 225 Widget new_, |
2286 | 226 ArgList UNUSED (args), |
227 Cardinal *UNUSED (num_args)) | |
424 | 228 { |
3055 | 229 RadioWidget rw = (RadioWidget) new_; |
424 | 230 RadioWidget rw_req = (RadioWidget) request; |
231 Dimension w,h ; | |
232 | |
233 /* Select initial size for the widget */ | |
234 if( rw_req->core.width == 0 || rw_req->core.height == 0 ) | |
235 { | |
236 RadioSize(rw, &w,&h) ; | |
237 if( rw_req->core.width == 0 ) | |
238 rw->core.width = w ; | |
239 if( rw_req->core.height == 0 ) | |
240 rw->core.height = h ; | |
3055 | 241 rw->core.widget_class->core_class.resize(new_) ; |
424 | 242 } |
243 } | |
244 | |
245 /* Function Name: RadioDestroy | |
246 * Description: Destroy Callback for radio widget. | |
247 * Arguments: w - the radio widget that is being destroyed. | |
442 | 248 * junk, garbage - not used. |
424 | 249 * Returns: none. |
250 */ | |
251 | |
3072 | 252 #if 0 |
253 /* #### This function isn't used and is slated for destruction. | |
254 Can we just nuke it? */ | |
424 | 255 /* ARGSUSED */ |
256 static void | |
2286 | 257 RadioDestroy (Widget UNUSED (w), |
258 XtPointer UNUSED (junk), | |
259 XtPointer UNUSED (garbage)) | |
424 | 260 { |
261 /* TODO: get rid of this */ | |
262 } | |
3072 | 263 #endif |
424 | 264 |
265 /* React to size change from manager. Label widget will compute some internal | |
266 * stuff, but we need to override. This code requires knowledge of the | |
267 * internals of the Label widget. | |
268 */ | |
269 | |
270 static void | |
271 RadioResize (Widget w) | |
272 { | |
273 RadioWidget rw = (RadioWidget)w ; | |
274 | |
275 /* call parent resize proc */ | |
276 SuperClass->core_class.resize(w) ; | |
277 | |
278 /* override label offset */ | |
279 | |
280 switch( rw->label.justify ) { | |
281 case XtJustifyLeft: | |
442 | 282 rw->label.label_x += (bs(rw) + rw->label.internal_width) ; |
424 | 283 break ; |
284 case XtJustifyRight: | |
285 break ; | |
286 case XtJustifyCenter: | |
287 default: | |
442 | 288 rw->label.label_x += (bs(rw) + rw->label.internal_width)/2; |
424 | 289 break ; |
290 } | |
291 } | |
292 | |
293 | |
294 /* | |
295 * Repaint the widget window. | |
296 */ | |
297 | |
298 static void | |
299 RadioExpose (Widget w, | |
300 XEvent *event, | |
301 Region region) | |
302 { | |
303 RadioWidget rw = (RadioWidget) w ; | |
304 Display *dpy = XtDisplay(w) ; | |
305 Window win = XtWindow(w) ; | |
306 GC gc ; | |
307 Pixmap left_bitmap ; | |
308 extern WidgetClass labelWidgetClass ; | |
309 | |
310 /* Note: the Label widget examines the region to decide if anything | |
311 * needs to be drawn. I'm not sure that this is worth the effort, | |
312 * but it bears thinking on. | |
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, | |
458 | 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 1UL) ; | |
424 | 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, | |
2286 | 354 Widget UNUSED (request), |
3055 | 355 Widget new_, |
2286 | 356 ArgList UNUSED (args), |
357 Cardinal *UNUSED (num_args)) | |
424 | 358 { |
359 RadioWidget oldrw = (RadioWidget) current; | |
3055 | 360 RadioWidget newrw = (RadioWidget) new_; |
424 | 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 | |
442 | 378 /* The label set values routine can resize the widget. We need to |
379 * recalculate if this is true. | |
380 */ | |
381 if (newrw->label.label_x != oldrw->label.label_x) | |
382 { | |
3055 | 383 RadioResize (new_); |
442 | 384 } |
424 | 385 return FALSE ; |
386 } | |
387 | |
388 static XtGeometryResult | |
389 RadioQueryGeometry (Widget w, | |
390 XtWidgetGeometry *intended, | |
391 XtWidgetGeometry *preferred) | |
392 { | |
393 RadioWidget rw = (RadioWidget) w; | |
394 | |
395 preferred->request_mode = CWWidth | CWHeight; | |
396 RadioSize(rw, &preferred->width, &preferred->height) ; | |
397 | |
398 if ( ((intended->request_mode & (CWWidth | CWHeight)) | |
399 == (CWWidth | CWHeight)) && | |
400 intended->width == preferred->width && | |
401 intended->height == preferred->height) | |
402 return XtGeometryYes; | |
403 else if (preferred->width == w->core.width && | |
404 preferred->height == w->core.height) | |
405 return XtGeometryNo; | |
406 else | |
407 return XtGeometryAlmost; | |
408 } | |
409 | |
410 | |
411 | |
412 | |
413 | |
414 /************************************************************ | |
415 * | |
416 * Action Procedures | |
417 * | |
418 ************************************************************/ | |
419 | |
420 /* | |
421 * Draw the highlight border around the widget. The Command widget | |
422 * did this by drawing through a mask. We do it by just drawing the | |
423 * border. | |
424 */ | |
425 | |
442 | 426 static void |
424 | 427 DrawHighlight (Widget w, |
428 GC gc) | |
429 { | |
430 RadioWidget rw = (RadioWidget)w; | |
431 XRectangle rects[4] ; | |
432 Dimension ht = rw->command.highlight_thickness ; | |
433 | |
434 if( ht <= 0 || | |
435 ht > rw->core.width/2 || | |
436 ht > rw->core.height/2 ) | |
437 return ; | |
438 | |
439 if( ! XtIsRealized(w) ) | |
440 return ; | |
441 | |
442 rects[0].x = 0 ; rects[0].y = 0 ; | |
443 rects[0].width = rw->core.width ; rects[0].height = ht ; | |
444 rects[1].x = 0 ; rects[1].y = rw->core.height - ht ; | |
445 rects[1].width = rw->core.width ; rects[1].height = ht ; | |
446 rects[2].x = 0 ; rects[2].y = ht ; | |
447 rects[2].width = ht ; rects[2].height = rw->core.height - ht*2 ; | |
448 rects[3].x = rw->core.width - ht ; rects[3].y = ht ; | |
449 rects[3].width = ht ; rects[3].height = rw->core.height - ht*2 ; | |
450 XFillRectangles( XtDisplay(w), XtWindow(w), gc, rects, 4) ; | |
451 } | |
452 | |
453 static void | |
454 RadioHighlight (Widget w, | |
2286 | 455 XEvent *UNUSED (event), |
456 String *UNUSED (params), | |
457 Cardinal *UNUSED (num_params)) | |
424 | 458 { |
459 RadioWidget rw = (RadioWidget)w; | |
460 DrawHighlight(w, rw->command.normal_GC) ; | |
461 } | |
462 | |
463 | |
464 static void | |
465 RadioUnhighlight (Widget w, | |
2286 | 466 XEvent *UNUSED (event), |
467 String *UNUSED (params), | |
468 Cardinal *UNUSED (num_params)) | |
424 | 469 { |
470 RadioWidget rw = (RadioWidget)w; | |
471 DrawHighlight(w, rw->command.inverse_GC) ; | |
472 } | |
473 | |
474 | |
475 /* ARGSUSED */ | |
442 | 476 void |
424 | 477 RadioSet (Widget w, |
2286 | 478 XEvent *UNUSED (event), |
479 String *UNUSED (params), | |
480 Cardinal *UNUSED (num_params)) | |
424 | 481 { |
482 RadioWidget rw = (RadioWidget)w; | |
1201 | 483 RadioWidgetClass class_ = (RadioWidgetClass) w->core.widget_class ; |
424 | 484 |
485 if( rw->command.set ) | |
486 return ; | |
487 | |
488 rw->command.set = TRUE ; | |
489 if( XtIsRealized(w) ) | |
1201 | 490 class_->radio_class.drawDiamond(w) ; |
424 | 491 } |
492 | |
493 | |
494 /* ARGSUSED */ | |
442 | 495 void |
424 | 496 RadioUnset (Widget w, |
2286 | 497 XEvent *UNUSED (event), |
498 String *UNUSED (params), | |
499 Cardinal *UNUSED (num_params)) | |
424 | 500 { |
501 RadioWidget rw = (RadioWidget)w; | |
1201 | 502 RadioWidgetClass class_ = (RadioWidgetClass) w->core.widget_class ; |
424 | 503 |
504 if( ! rw->command.set ) | |
505 return ; | |
506 | |
507 rw->command.set = FALSE ; | |
508 if( XtIsRealized(w) ) | |
1201 | 509 class_->radio_class.drawDiamond(w) ; |
424 | 510 } |
511 | |
512 | |
513 | |
514 | |
515 /************************************************************ | |
516 * | |
517 * Internal Procedures | |
518 * | |
519 ************************************************************/ | |
520 | |
521 | |
522 /* Size of widget. Width is size of box plus width of border around | |
523 * box plus width of label plus three margins plus the size of the left | |
524 * bitmap, if any. Height is max(box,bitmap,label) plus two margins. | |
525 */ | |
526 | |
527 static void | |
528 RadioSize (RadioWidget rw, | |
529 Dimension *w, | |
530 Dimension *h) | |
531 { | |
532 *w = rw->label.label_width + bs(rw) + LEFT_OFFSET(rw) + | |
533 3 * rw->label.internal_width ; | |
534 *h = Max( rw->label.label_height, bs(rw) ) + | |
535 2 * rw->label.internal_width ; | |
536 } | |
537 | |
538 | |
539 static void | |
540 DrawDiamond (Widget w) | |
541 { | |
542 RadioWidget rw = (RadioWidget) w ; | |
543 Display *dpy = XtDisplay(w) ; | |
544 Window win = XtWindow(w) ; | |
545 GC gc, gci ; | |
546 | |
547 XPoint pts[5] ; | |
548 Dimension del = bsize(rw)/2 ; | |
549 Position x,y ; /* diamond center */ | |
550 #ifdef _ThreeDP_h | |
551 int i=0; | |
552 Dimension s = swid(rw) ; | |
553 GC top, bot, ctr ; | |
554 #endif | |
555 gc = XtIsSensitive(w) ? rw->command.normal_GC : rw->label.gray_GC ; | |
556 | |
557 gci = rw->command.set ? rw->command.normal_GC : rw->command.inverse_GC ; | |
558 | |
559 x = rw->label.internal_width + bs(rw)/2 ; | |
560 y = rw->core.height/2 ; | |
561 | |
562 #ifdef _ThreeDP_h | |
563 if( ! rw->command.set ) { | |
564 top = rw->threeD.top_shadow_GC ; | |
565 bot = rw->threeD.bot_shadow_GC ; | |
566 ctr = gc ; /* TODO */ | |
567 } else { | |
568 top = rw->threeD.bot_shadow_GC ; | |
569 bot = rw->threeD.top_shadow_GC ; | |
570 ctr = gc ; /* TODO */ | |
571 } | |
572 #endif | |
573 | |
574 pts[0].x = x - del ; | |
575 pts[0].y = y ; | |
576 pts[1].x = x ; | |
577 pts[1].y = y - del ; | |
578 pts[2].x = x + del ; | |
579 pts[2].y = y ; | |
580 pts[3].x = x ; | |
581 pts[3].y = y + del ; | |
582 pts[4] = pts[0] ; | |
583 XFillPolygon(dpy,win,gci, pts,4, Convex, CoordModeOrigin) ; | |
584 | |
585 #ifdef _ThreeDP_h | |
586 for(i=0; i<s; ++i) { | |
587 XDrawLine(dpy,win,bot, x-i-del,y, x,y+del+i) ; | |
588 XDrawLine(dpy,win,bot, x+del+i,y, x,y+del+i) ; | |
589 } | |
590 for(i=0; i<s; ++i) { | |
591 XDrawLine(dpy,win,top, x-del-i,y, x,y-del-i) ; | |
592 XDrawLine(dpy,win,top, x+del+i,y, x,y-del-i) ; | |
593 } | |
594 #else | |
595 XDrawLines(dpy,win,gc, pts,5, CoordModeOrigin) ; | |
596 #endif | |
597 } |