1 /*************************************<+>*************************************
2 *****************************************************************************
8 ** Description: Contains code for primitive widget class: Toggle
10 *****************************************************************************
12 ** Copyright (c) 1988 by Hewlett-Packard Company
13 ** Copyright (c) 1988 by the Massachusetts Institute of Technology
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
24 *****************************************************************************
25 *************************************<+>*************************************/
28 * Include files & Static Routine Definitions
35 #include <X11/Intrinsic.h>
36 #include <X11/IntrinsicP.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
47 static void Redisplay();
48 static Boolean
SetValues();
49 static void ClassInitialize();
50 static void Initialize();
51 static void Destroy();
54 static void Unselect();
55 static void DrawToggle();
57 static void DrawDiamondButton();
58 static void GetSelectGC();
62 /*************************************<->*************************************
65 * Description: default translation table for class: Toggle
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
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
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
),
124 XtNselectColor
, XtCForeground
, XtRPixel
, sizeof (Pixel
),
125 XtOffset (XwToggleWidget
, toggle
.select_color
),
132 /*************************************<->*************************************
135 * Description: global class record for instances of class: Toggle
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
,
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
,
179 WidgetClass XwtoggleWidgetClass
= (WidgetClass
)&XwtoggleClassRec
;
181 /*************************************<->*************************************
183 * ComputeSpace (w, redisplay)
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.
194 * w = widget instance that was selected.
195 * redisplay = flag indicating routine is called from Redisplay()
203 * _XwHighlightBorder()
204 * _XwUnhighlightBorder()
205 *************************************<->***********************************/
206 static void ComputeSpace(w
, redisplay
)
210 XwToggleWidget cbox
= (XwToggleWidget
)w
;
211 Boolean clipHeight
, clipWidth
;
212 int x
, available_width
, available_height
;
214 /* COMPUTE SPACE FOR DRAWING TOGGLE */
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
)
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
)
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
)
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
);
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
);
305 /*************************************<->*************************************
307 * Toggle (w, event) PRIVATE
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
316 * NOTE: this code assumes that instances do not receive selection
317 * events when insensitive.
321 * w = widget instance that was selected.
322 * event = event record
329 * DrawToggle() [Toggle.c]
330 * ComputeSpace() [Toggle.c]
332 *************************************<->***********************************/
334 static void Toggle(w
,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
);
347 XtCallCallbacks (w
, XtNrelease
, NULL
);
351 /*************************************<->*************************************
353 * Select (w, event) PRIVATE
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.
365 * w = widget instance that was selected.
366 * event = event record
373 * DrawToggle() [Toggle.c]
374 * ComputeSpace() [Toggle.c]
376 *************************************<->***********************************/
378 static void Select(w
,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
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.
406 * w = widget instance that was selected.
407 * event = event record
414 * DrawToggle() [Toggle.c]
415 * ComputeSpace() [Toggle.c]
417 *************************************<->***********************************/
419 static void Unselect(w
,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 /************************************************************************
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
)
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 /*************************************<->*************************************
467 * A resize event has been generated. Recompute location of button
472 * w = widget to be resized.
474 *************************************<->***********************************/
476 static void Resize(w
)
479 register XwButtonWidget aButton
= (XwButtonWidget
) w
;
480 int direction
= aButton
->button
.label_location
;
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
;
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 /*************************************<->*************************************
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
512 *************************************<->***********************************/
513 static void Initialize (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
;
537 if (!cbox
->toggle
.square
) cbox
->core
.height
+= 2;
547 /************************************************************************
550 * Free toggle's graphic context.
552 ************************************************************************/
554 static void Destroy (tw
)
558 XtDestroyGC (tw
-> toggle
.select_GC
);
565 /*************************************<->*************************************
571 * Depending on the state of this widget, draw the Toggle.
576 * w = widget to be (re)displayed.
578 *************************************<->***********************************/
580 static void DrawToggle(w
, all
)
582 Boolean all
; /* redo all, or just center? */
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
;
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
,
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);
615 DrawDiamondButton ((XwButtonWidget
) w
, x
-1, y
-1, edge
+2,
616 w
-> button
.normal_GC
,
618 w
-> toggle
.select_GC
:
619 w
-> button
.inverse_GC
));
625 /*************************************<->*************************************
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)
649 * Cause the widget, identified by w, to be redisplayed.
654 * w = widget to be redisplayed;
655 * event = event structure identifying need for redisplay on this
664 * DrawToggle() [Toggle.c]
665 * ComputeSpace() [Toggle.c]
666 *************************************<->***********************************/
668 static void Redisplay(w
, 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)
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
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
;
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
;
743 if (curcbox
-> toggle
.select_color
!= newcbox
-> toggle
.select_color
)
745 XtDestroyGC (newcbox
-> toggle
.select_GC
);
746 GetSelectGC (newcbox
);
751 if (curcbox
-> toggle
.square
!= newcbox
-> toggle
.square
)
757 Resize(new); /* fix label x and label y positioning */
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
)
777 GC borderGC
, centerGC
;
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 */
799 seg
[1].x1
= x
+ 1; /* 3 */
800 seg
[1].y1
= midY
- 1;
801 seg
[1].x2
= midX
- 1; /* 4 */
804 seg
[2].x1
= midX
- 1; /* 5 */
806 seg
[2].x2
= x
+ size
- 1; /* 6 */
807 seg
[2].y2
= midY
- 1;
809 seg
[3].x1
= midX
- 1; /* 7 */
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);
851 pt
[2].x
= x
+ size
- 4;
854 pt
[3].y
= y
+ size
- 4;
856 XFillPolygon (XtDisplay ((Widget
) bw
), XtWindow ((Widget
) bw
),
857 centerGC
, pt
, 4, Convex
, CoordModeOrigin
);