Merge branch 'master' into xcircuit-3.10
[xcircuit.git] / Xw / Toggle.c
blobfa3cdf6ac2da1367583e70e4afc8c058134f6927
1 /*************************************<+>*************************************
2 *****************************************************************************
3 **
4 ** File: Toggle.c
5 **
6 ** Project: X Widgets
7 **
8 ** Description: Contains code for primitive widget class: Toggle
9 **
10 *****************************************************************************
11 **
12 ** Copyright (c) 1988 by Hewlett-Packard Company
13 ** Copyright (c) 1988 by the Massachusetts Institute of Technology
14 **
15 ** Permission to use, copy, modify, and distribute this software
16 ** and its documentation for any purpose and without fee is hereby
17 ** granted, provided that the above copyright notice appear in all
18 ** copies and that both that copyright notice and this permission
19 ** notice appear in supporting documentation, and that the names of
20 ** Hewlett-Packard or M.I.T. not be used in advertising or publicity
21 ** pertaining to distribution of the software without specific, written
22 ** prior permission.
23 **
24 *****************************************************************************
25 *************************************<+>*************************************/
28 * Include files & Static Routine Definitions
32 #include <stdio.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <X11/Intrinsic.h>
36 #include <X11/IntrinsicP.h>
37 #include <Xw/Xw.h>
38 #include <Xw/XwP.h>
39 #include <Xw/ToggleP.h>
40 #include <Xw/Toggle.h>
41 #include <X11/StringDefs.h>
42 #include <X11/keysymdef.h>
44 #define SPACE_FACTOR 3
45 #define T_BW 2
47 static void Redisplay();
48 static Boolean SetValues();
49 static void ClassInitialize();
50 static void Initialize();
51 static void Destroy();
52 static void Toggle();
53 static void Select();
54 static void Unselect();
55 static void DrawToggle();
56 static void Resize();
57 static void DrawDiamondButton();
58 static void GetSelectGC();
62 /*************************************<->*************************************
65 * Description: default translation table for class: Toggle
66 * -----------
68 * Matches events with string descriptors for internal routines.
70 *************************************<->***********************************/
73 static char defaultTranslations[] =
74 "<EnterWindow>: enter() \n\
75 <LeaveWindow>: leave() \n\
76 <Btn1Down>: toggle() \n\
77 <Key>Select: toggle()";
81 /*************************************<->*************************************
84 * Description: action list for class: Toggle
85 * -----------
87 * Matches string descriptors with internal routines.
89 *************************************<->***********************************/
91 static XtActionsRec actionsList[] =
93 {"toggle", (XtActionProc) Toggle},
94 {"select", (XtActionProc) Select},
95 {"unselect", (XtActionProc) Unselect},
96 {"enter", (XtActionProc) _XwPrimitiveEnter},
97 {"leave", (XtActionProc) _XwPrimitiveLeave},
103 /*************************************<->*************************************
106 * Description: resource list for class: Toggle
107 * -----------
109 * Provides default resource settings for instances of this class.
110 * To get full set of default settings, examine resouce list of super
111 * classes of this class.
113 *************************************<->***********************************/
115 static XtResource resources[] =
118 XtNsquare, XtCSquare, XtRBoolean, sizeof (Boolean),
119 XtOffset (XwToggleWidget, toggle.square),
120 XtRString, "True"
124 XtNselectColor, XtCForeground, XtRPixel, sizeof (Pixel),
125 XtOffset (XwToggleWidget, toggle.select_color),
126 XtRString, "Black"
132 /*************************************<->*************************************
135 * Description: global class record for instances of class: Toggle
136 * -----------
138 * Defines default field settings for this class record.
140 *************************************<->***********************************/
142 XwToggleClassRec XwtoggleClassRec = {
144 /* core_class fields */
145 /* superclass */ (WidgetClass) &XwbuttonClassRec,
146 /* class_name */ "Toggle",
147 /* widget_size */ sizeof(XwToggleRec),
148 /* class_initialize */ ClassInitialize,
149 /* class_part_init */ NULL,
150 /* class_inited */ FALSE,
151 /* initialize */ Initialize,
152 /* initialize_hook */ NULL,
153 /* realize */ _XwRealize,
154 /* actions */ actionsList,
155 /* num_actions */ XtNumber(actionsList),
156 /* resources */ resources,
157 /* num_resources */ XtNumber(resources),
158 /* xrm_class */ NULLQUARK,
159 /* compress_motion */ TRUE,
160 /* compress_exposure */ TRUE,
161 /* compress_enterlv */ TRUE,
162 /* visible_interest */ FALSE,
163 /* destroy */ Destroy,
164 /* resize */ Resize,
165 /* expose */ Redisplay,
166 /* set_values */ SetValues,
167 /* set_values_hook */ NULL,
168 /* set_values_almost */ XtInheritSetValuesAlmost,
169 /* get_values_hook */ NULL,
170 /* accept_focus */ NULL,
171 /* version */ XtVersion,
172 /* callback_private */ NULL,
173 /* tm_table */ defaultTranslations,
174 /* query_geometry */ NULL,
175 /* display_accelerator */ XtInheritDisplayAccelerator,
176 /* extension */ NULL
179 WidgetClass XwtoggleWidgetClass = (WidgetClass)&XwtoggleClassRec;
181 /*************************************<->*************************************
183 * ComputeSpace (w, redisplay)
185 * Description:
186 * -----------
187 * Compute allowable space to display label and/or toggle.
188 * If this function is used in redisplay (i.e. redisplay
189 * flag is true), compute space for label as well as toggle.
190 * Compute for toggle only if redisplay flag is FALSE.
192 * Inputs:
193 * ------
194 * w = widget instance that was selected.
195 * redisplay = flag indicating routine is called from Redisplay()
197 * Outputs:
198 * -------
200 * Procedures Called
201 * -----------------
202 * XClearArea()
203 * _XwHighlightBorder()
204 * _XwUnhighlightBorder()
205 *************************************<->***********************************/
206 static void ComputeSpace(w, redisplay)
207 Widget w;
208 Boolean redisplay;
210 XwToggleWidget cbox = (XwToggleWidget)w;
211 Boolean clipHeight, clipWidth;
212 int x, available_width, available_height;
214 /* COMPUTE SPACE FOR DRAWING TOGGLE */
216 if (redisplay)
218 available_width = Max(0, (int)cbox->core.width - 2*
219 ((int)cbox->button.internal_width +
220 cbox->primitive.highlight_thickness));
222 /* SEE IF WE NEED TO CLIP THIS LABEL ON RIGHT */
224 if (((int)cbox->button.label_width +
225 (int)cbox->button.label_height +
226 (int)cbox->button.label_height/SPACE_FACTOR) > available_width)
227 clipWidth = True;
228 else
229 clipWidth = False;
232 else
234 available_width = Max(0,((int)cbox->core.width - 2*
235 ((int)cbox->button.internal_width +
236 cbox->primitive.highlight_thickness) -
237 (int)cbox->button.label_width -
238 (int)cbox->button.label_height/SPACE_FACTOR));
240 /* SEE IF WE NEED TO CLIP THIS LABEL ON RIGHT */
242 if ((int)cbox->button.label_height > available_width)
243 clipWidth = True;
244 else
245 clipWidth = False;
248 available_height = Max(0, (int)cbox->core.height - 2*
249 ((int)cbox->button.internal_height +
250 cbox->primitive.highlight_thickness));
253 /* SEE IF WE NEED TO CLIP THIS LABEL ON TOP AND/OR BOTTOM */
255 if ((int)cbox->button.label_height > available_height)
256 clipHeight = True;
257 else
258 clipHeight = False;
260 if (clipWidth)
262 x = (int)cbox->core.width - cbox->primitive.highlight_thickness -
263 (int)cbox->button.internal_width;
265 if ((cbox->button.label_location != XwRIGHT) && redisplay)
266 x -= Min((int)cbox->button.label_height,
267 Max(0, (int)cbox->core.height -
268 2*(cbox->primitive.highlight_thickness +
269 (int)cbox->button.internal_height)));
272 XClearArea (XtDisplay(w), XtWindow(w), x, 0,
273 ((int)cbox->core.width - x), cbox->core.height, FALSE);
276 if (clipHeight)
278 XClearArea (XtDisplay(w), XtWindow(w), 0,0, cbox->core.width,
279 (cbox->primitive.highlight_thickness +
280 cbox->button.internal_height), FALSE);
281 XClearArea (XtDisplay(w), XtWindow(w), 0,
282 ((int)cbox->core.height -
283 cbox->primitive.highlight_thickness -
284 (int)cbox->button.internal_height), cbox->core.width,
285 (cbox->primitive.highlight_thickness +
286 cbox->button.internal_height), FALSE);
289 if (cbox->primitive.highlighted)
290 _XwHighlightBorder(w);
291 else if (cbox->primitive.display_highlighted)
292 _XwUnhighlightBorder(w);
294 /* REDRAW THE TOGGLE ON LABEL LOCATION LEFT CONDITIONS AND RECURSIVELY
295 CALL THIS FUNCTION. THIS ENSURES VISIBILITY OF THE TOGGLE */
296 if ((cbox->button.label_location != XwRIGHT) && redisplay)
298 DrawToggle(w, FALSE);
299 ComputeSpace(w, FALSE);
302 } /* ComputeSpace */
305 /*************************************<->*************************************
307 * Toggle (w, event) PRIVATE
309 * Description:
310 * -----------
311 * When this Toggle is selected, toggle the activation state
312 * (i.e., draw it as active if it was not active and draw it as
313 * inactive if it was active). Generate the correct callbacks
314 * in response.
316 * NOTE: this code assumes that instances do not receive selection
317 * events when insensitive.
319 * Inputs:
320 * ------
321 * w = widget instance that was selected.
322 * event = event record
324 * Outputs:
325 * -------
327 * Procedures Called
328 * -----------------
329 * DrawToggle() [Toggle.c]
330 * ComputeSpace() [Toggle.c]
331 * XtCallCallbacks()
332 *************************************<->***********************************/
334 static void Toggle(w,event)
335 Widget w;
336 XEvent *event;
338 XwToggleWidget cbox = (XwToggleWidget)w;
340 cbox->button.set = (cbox->button.set == TRUE) ? FALSE : TRUE;
341 DrawToggle(w, FALSE);
342 ComputeSpace(w, FALSE);
343 XFlush(XtDisplay(w));
344 if (cbox->button.set == TRUE)
345 XtCallCallbacks (w, XtNselect, NULL);
346 else
347 XtCallCallbacks (w, XtNrelease, NULL);
351 /*************************************<->*************************************
353 * Select (w, event) PRIVATE
355 * Description:
356 * -----------
357 * Mark Toggle as selected, (i.e., draw it as active)
358 * Generate the correct callbacks.
360 * NOTE: this code assumes that instances do not receive selection
361 * events when insensitive.
363 * Inputs:
364 * ------
365 * w = widget instance that was selected.
366 * event = event record
368 * Outputs:
369 * -------
371 * Procedures Called
372 * -----------------
373 * DrawToggle() [Toggle.c]
374 * ComputeSpace() [Toggle.c]
375 * XtCallCallbacks()
376 *************************************<->***********************************/
378 static void Select(w,event)
379 Widget w;
380 XEvent *event;
382 XwToggleWidget cbox = (XwToggleWidget)w;
384 cbox->button.set = TRUE;
385 DrawToggle(w, FALSE);
386 ComputeSpace(w,FALSE);
387 XFlush(XtDisplay(w));
388 XtCallCallbacks (w, XtNselect, NULL);
392 /*************************************<->*************************************
394 * Unselect (w, event) PRIVATE
396 * Description:
397 * -----------
398 * When this Toggle is unselected draw it as inactive.
399 * Generate the correct callbacks.
401 * NOTE: this code assumes that instances do not receive selection
402 * events when insensitive.
404 * Inputs:
405 * ------
406 * w = widget instance that was selected.
407 * event = event record
409 * Outputs:
410 * -------
412 * Procedures Called
413 * -----------------
414 * DrawToggle() [Toggle.c]
415 * ComputeSpace() [Toggle.c]
416 * XtCallCallbacks()
417 *************************************<->***********************************/
419 static void Unselect(w,event)
420 Widget w;
421 XEvent *event;
423 XwToggleWidget cbox = (XwToggleWidget)w;
425 cbox->button.set = FALSE;
426 DrawToggle(w, FALSE);
427 ComputeSpace(w,FALSE);
428 XFlush(XtDisplay(w));
429 XtCallCallbacks (w, XtNrelease, NULL);
435 /************************************************************************
437 * GetSelectGC
438 * Get the graphics context to be used to fill the interior of
439 * a square or diamond when selected.
441 ************************************************************************/
443 static void GetSelectGC (tw)
444 XwToggleWidget tw;
447 XGCValues values;
449 values.foreground = tw -> toggle.select_color;
450 values.background = tw -> core.background_pixel;
451 values.fill_style = FillSolid;
453 tw -> toggle.select_GC =
454 XtGetGC ((Widget)tw, GCForeground | GCBackground | GCFillStyle, &values);
461 /*************************************<->*************************************
463 * Resize
465 * Description:
466 * -----------
467 * A resize event has been generated. Recompute location of button
468 * elements.
470 * Inputs:
471 * ------
472 * w = widget to be resized.
474 *************************************<->***********************************/
476 static void Resize(w)
477 Widget w;
479 register XwButtonWidget aButton = (XwButtonWidget) w;
480 int direction = aButton->button.label_location;
482 switch (direction)
484 case XwRIGHT:
485 aButton->button.label_x = aButton->button.internal_width +
486 aButton->primitive.highlight_thickness +
487 aButton->button.label_height +
488 aButton->button.label_height/SPACE_FACTOR;
489 break;
491 default:
492 aButton->button.label_x = aButton->button.internal_width +
493 aButton->primitive.highlight_thickness;
496 aButton->button.label_y =
497 (((int)aButton->core.height - (int)aButton->button.label_height) >> 1)
498 + aButton->button.font->max_bounds.ascent;
501 /*************************************<->*************************************
503 * Initialize
505 * Description:
506 * -----------
507 * If the core height and width fields are set to 0, treat that as a flag
508 * and compute the optimum size for this button. Then using what ever
509 * the core fields are set to, compute the text placement fields.
510 * Make sure that the label location field is properly set for the
511 * Resize call.
512 *************************************<->***********************************/
513 static void Initialize (request, new)
514 Widget request, new;
516 XwToggleWidget cbox = (XwToggleWidget) new;
518 if ((cbox->button.label_location != XwLEFT) &&
519 (cbox->button.label_location != XwRIGHT))
521 cbox->button.label_location = XwLEFT;
522 XtWarning ("XwToggle Initialize: invalid label location setting.");
525 if (request->core.width == 0) cbox->core.width +=
526 cbox->button.label_width +
527 2 * cbox->button.internal_width + /* white space */
528 cbox->button.label_height + /* size of box */
529 cbox->button.label_height/SPACE_FACTOR + /* space */
530 2 * cbox->primitive.highlight_thickness;
532 if (request->core.height == 0) cbox->core.height +=
533 cbox->button.label_height + 2 * cbox->button.internal_height
534 + 2 * cbox->primitive.highlight_thickness;
536 /* dana change */
537 if (!cbox->toggle.square) cbox->core.height += 2;
539 GetSelectGC (new);
540 Resize (new);
547 /************************************************************************
549 * Destroy
550 * Free toggle's graphic context.
552 ************************************************************************/
554 static void Destroy (tw)
555 XwToggleWidget tw;
558 XtDestroyGC (tw -> toggle.select_GC);
565 /*************************************<->*************************************
567 * DrawToggle(w)
569 * Description:
570 * -----------
571 * Depending on the state of this widget, draw the Toggle.
574 * Inputs:
575 * ------
576 * w = widget to be (re)displayed.
578 *************************************<->***********************************/
580 static void DrawToggle(w, all)
581 XwToggleWidget w;
582 Boolean all; /* redo all, or just center? */
584 int x, y, edge;
586 /***************************************************************
587 * Determine whether label should appear to the left or
588 * the right of the box and set label X coordinate accordingly.
589 ****************************************************************/
591 edge = Min((int)w->button.label_height,
592 Max(0, (int)w->core.height - 2*(w->primitive.highlight_thickness
593 + (int)w->button.internal_height)));
595 if (w->button.label_location == XwRIGHT)
596 x= w->button.internal_width + w->primitive.highlight_thickness;
597 else
598 x= Max(0, (int)w->core.width - (int)w->button.internal_width
599 - w->primitive.highlight_thickness - edge); /* size of box */
601 y= Max(0, ((int)w->core.height - edge) / 2);
603 if (w->toggle.square)
605 _XwDrawBox (XtDisplay (w), XtWindow (w),
606 w -> button.normal_GC, T_BW,
607 x, y, edge, edge);
608 if (edge > 6) XFillRectangle (XtDisplay ((Widget) w),
609 XtWindow ((Widget) w),
610 ((w->button.set) ? w -> toggle.select_GC :
611 w -> button.inverse_GC),
612 x+3, y+3, edge-6, edge-6);
614 else
615 DrawDiamondButton ((XwButtonWidget) w, x-1, y-1, edge+2,
616 w -> button.normal_GC,
617 ((w->button.set) ?
618 w -> toggle.select_GC :
619 w -> button.inverse_GC));
625 /*************************************<->*************************************
627 * ClassInitialize
629 * Description:
630 * -----------
631 * Set fields in primitive class part of our class record so that
632 * the traversal code can invoke our button select procedures.
634 *************************************<->***********************************/
635 static void ClassInitialize()
637 XwtoggleClassRec.primitive_class.select_proc = (XwEventProc) Select;
638 XwtoggleClassRec.primitive_class.release_proc = (XwEventProc) Unselect;
639 XwtoggleClassRec.primitive_class.toggle_proc = (XwEventProc) Toggle;
643 /*************************************<->*************************************
645 * Redisplay (w, event)
647 * Description:
648 * -----------
649 * Cause the widget, identified by w, to be redisplayed.
652 * Inputs:
653 * ------
654 * w = widget to be redisplayed;
655 * event = event structure identifying need for redisplay on this
656 * widget.
658 * Outputs:
659 * -------
661 * Procedures Called
662 * -----------------
663 * XDrawString()
664 * DrawToggle() [Toggle.c]
665 * ComputeSpace() [Toggle.c]
666 *************************************<->***********************************/
668 static void Redisplay(w, event)
669 Widget w;
670 XEvent *event;
672 register XwToggleWidget cbox = (XwToggleWidget) w;
674 if (cbox->button.label_len > 0)
675 XDrawString( XtDisplay(w), XtWindow(w), cbox->button.normal_GC,
676 cbox->button.label_x, cbox->button.label_y,
677 cbox->button.label, cbox->button.label_len);
678 DrawToggle(cbox, TRUE);
679 ComputeSpace(w, TRUE);
684 /*************************************<->*************************************
686 * SetValues(current, request, new)
688 * Description:
689 * -----------
690 * This is the set values procedure for the Toggle class. It is
691 * called last (the set values rtnes for its superclasses are called
692 * first).
695 * Inputs:
696 * ------
697 * current = original widget;
698 * request = copy of current (?);
699 * new = copy of request which reflects changes made to it by
700 * set values procedures of its superclasses;
703 *************************************<->***********************************/
705 static Boolean SetValues(current, request, new)
706 Widget current, request, new;
708 XwToggleWidget curcbox = (XwToggleWidget) current;
709 XwToggleWidget newcbox = (XwToggleWidget) new;
710 Boolean flag = FALSE; /* our return value */
713 /**********************************************************************
714 * Calculate the window size: The assumption here is that if
715 * the width and height are the same in the new and current instance
716 * record that those fields were not changed with set values. Therefore
717 * its okay to recompute the necessary width and height. However, if
718 * the new and current do have different width/heights then leave them
719 * alone because that's what the user wants.
720 *********************************************************************/
722 if ((curcbox->core.width == newcbox->core.width) &&
723 (_XwRecomputeSize(current, new)))
725 newcbox->core.width =
726 newcbox->button.label_width +2*newcbox->button.internal_width
727 + newcbox->button.label_height +
728 newcbox->button.label_height/SPACE_FACTOR +
729 2 * newcbox->primitive.highlight_thickness;
730 flag = TRUE;
733 if ((curcbox->core.height == newcbox->core.height) &&
734 (_XwRecomputeSize(current, new)))
736 newcbox->core.height =
737 newcbox->button.label_height + 2*newcbox->button.internal_height +
738 2 * newcbox->primitive.highlight_thickness;
739 flag = TRUE;
743 if (curcbox -> toggle.select_color != newcbox -> toggle.select_color)
745 XtDestroyGC (newcbox -> toggle.select_GC);
746 GetSelectGC (newcbox);
747 flag = True;
751 if (curcbox -> toggle.square != newcbox -> toggle.square)
753 flag = True;
757 Resize(new); /* fix label x and label y positioning */
758 return(flag);
765 /************************************************************************
767 * DrawDiamondButton()
768 * The dimond drawing routine. Used in place of primitives
769 * draw routine when toggle's square flag is False.
771 ************************************************************************/
774 static void DrawDiamondButton (bw, x, y, size, borderGC, centerGC)
775 XwButtonWidget bw;
776 int x, y, size;
777 GC borderGC, centerGC;
781 XSegment seg[8];
782 XPoint pt[5];
783 int midX, midY;
785 if (size % 2 == 0)
786 size--;
788 midX = x + (size + 1) / 2;
789 midY = y + (size + 1) / 2;
792 /* The top segments */
794 seg[0].x1 = x; /* 1 */
795 seg[0].y1 = midY - 1;
796 seg[0].x2 = midX - 1; /* 2 */
797 seg[0].y2 = y;
799 seg[1].x1 = x + 1; /* 3 */
800 seg[1].y1 = midY - 1;
801 seg[1].x2 = midX - 1; /* 4 */
802 seg[1].y2 = y + 1;
804 seg[2].x1 = midX - 1; /* 5 */
805 seg[2].y1 = y;
806 seg[2].x2 = x + size - 1; /* 6 */
807 seg[2].y2 = midY - 1;
809 seg[3].x1 = midX - 1; /* 7 */
810 seg[3].y1 = y + 1;
811 seg[3].x2 = x + size - 2; /* 8 */
812 seg[3].y2 = midY - 1;
815 /* The bottom segments */
817 seg[4].x1 = x; /* 9 */
818 seg[4].y1 = midY - 1;
819 seg[4].x2 = midX - 1; /* 10 */
820 seg[4].y2 = y + size - 1;
822 seg[5].x1 = x + 1; /* 11 */
823 seg[5].y1 = midY - 1;
824 seg[5].x2 = midX - 1; /* 12 */
825 seg[5].y2 = y + size - 2;
827 seg[6].x1 = midX - 1; /* 13 */
828 seg[6].y1 = y + size - 1;
829 seg[6].x2 = x + size - 1; /* 14 */
830 seg[6].y2 = midY - 1;
832 seg[7].x1 = midX - 1; /* 15 */
833 seg[7].y1 = y + size - 2;
834 seg[7].x2 = x + size - 2; /* 16 */
835 seg[7].y2 = midY - 1;
837 XDrawSegments (XtDisplay ((Widget) bw), XtWindow ((Widget) bw),
838 borderGC, &seg[2], 2);
840 XDrawSegments (XtDisplay ((Widget) bw), XtWindow ((Widget) bw),
841 borderGC, &seg[4], 4);
843 XDrawSegments (XtDisplay ((Widget) bw), XtWindow ((Widget) bw),
844 borderGC, &seg[0], 2);
847 pt[0].x = x + 3;
848 pt[0].y = midY - 1;
849 pt[1].x = midX - 1;
850 pt[1].y = y + 3;
851 pt[2].x = x + size - 4;
852 pt[2].y = midY - 1;
853 pt[3].x = midX - 2;
854 pt[3].y = y + size - 4;
856 XFillPolygon (XtDisplay ((Widget) bw), XtWindow ((Widget) bw),
857 centerGC, pt, 4, Convex, CoordModeOrigin);