1 /*************************************<+>*************************************
2 *****************************************************************************
8 ** Description: Contains code for primitive widget class: PushButton
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
34 #include <X11/Intrinsic.h>
35 #include <X11/IntrinsicP.h>
36 #include <X11/StringDefs.h>
39 #include <Xw/PButtonP.h>
40 #include <Xw/PButton.h>
41 #include <X11/keysymdef.h>
47 static void Redisplay();
48 static void RedrawButtonFace();
49 static Boolean
SetValues();
50 static void ClassInitialize();
51 static void Initialize();
53 static void ToggleRelease();
55 static void Unselect();
59 /*************************************<->*************************************
62 * Description: default translation table for class: PushButton
65 * Matches events with string descriptors for internal routines.
67 *************************************<->***********************************/
69 static char defaultTranslations
[] =
70 "<Btn1Down>: select() \n\
71 <Btn1Up>: unselect() \n\
72 <EnterWindow>: enter() \n\
73 <LeaveWindow>: leave() \n\
74 <KeyDown>Select: select() \n\
75 <KeyUp>Select: unselect()";
79 /*************************************<->*************************************
82 * Description: action list for class: PushButton
85 * Matches string descriptors with internal routines.
86 * Note that Primitive will register additional event handlers
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
},
101 /* The resource list for Push Button */
103 static XtResource resources
[] =
106 XtNtoggle
, XtCToggle
, XtRBoolean
, sizeof (Boolean
),
107 XtOffset (XwPushButtonWidget
, pushbutton
.toggle
), XtRString
, "False"
113 /*************************************<->*************************************
116 * Description: global class record for instances of class: PushButton
119 * Defines default field settings for this class record.
121 *************************************<->***********************************/
123 XwPushButtonClassRec XwpushButtonClassRec
= {
125 /* core_class fields */
126 /* superclass */ (WidgetClass
) &XwbuttonClassRec
,
127 /* class_name */ "XwPushButton",
128 /* widget_size */ sizeof(XwPushButtonRec
),
129 /* class_initialize */ ClassInitialize
,
130 /* class_part_init */ NULL
,
131 /* class_inited */ FALSE
,
132 /* initialize */ Initialize
,
133 /* initialize_hook */ NULL
,
134 /* realize */ _XwRealize
,
135 /* actions */ actionsList
,
136 /* num_actions */ XtNumber(actionsList
),
137 /* resources */ resources
,
138 /* num_resources */ XtNumber(resources
),
139 /* xrm_class */ NULLQUARK
,
140 /* compress_motion */ TRUE
,
141 /* compress_exposure */ TRUE
,
142 /* compress_enterlv */ TRUE
,
143 /* visible_interest */ FALSE
,
146 /* expose */ Redisplay
,
147 /* set_values */ SetValues
,
148 /* set_values_hook */ NULL
,
149 /* set_values_almost */ XtInheritSetValuesAlmost
,
150 /* get_values_hook */ NULL
,
151 /* accept_focus */ NULL
,
152 /* version */ XtVersion
,
153 /* callback_private */ NULL
,
154 /* tm_table */ defaultTranslations
,
155 /* query_geometry */ NULL
,
156 /* display_accelerator */ XtInheritDisplayAccelerator
,
160 WidgetClass XwpushButtonWidgetClass
= (WidgetClass
)&XwpushButtonClassRec
;
163 /*************************************<->*************************************
165 * Toggle (w, event) PRIVATE
169 * When this pushbutton is selected, toggle the activation state
170 * (i.e., draw it as active if it was not active and draw it as
171 * inactive if it was active). Generate the correct callbacks
174 * NOTE: this code assumes that instances do not receive selection
175 * events when insensitive.
179 * w = widget instance that was selected.
180 * event = event record
187 * XtCallCallbacks() [libXtk]
188 * Redisplay [PushButton.c]
189 *************************************<->***********************************/
191 static void Toggle (w
,event
)
196 XwPushButtonWidget pb
= (XwPushButtonWidget
)w
;
199 if (pb
-> button
.set
)
200 pb
-> button
.set
= False
;
202 pb
-> button
.set
= True
;
204 RedrawButtonFace (w
, event
, FALSE
);
205 XFlush(XtDisplay(w
));
206 XtCallCallbacks (w
, ((pb
->button
.set
) ? XtNselect
: XtNrelease
), NULL
);
210 /*************************************<->*************************************
212 * Select (w, event) PRIVATE
216 * Mark pushbutton as selected, (i.e., draw it as active)
217 * Generate the correct callbacks. If "toggle" flag is
218 * TRUE then call the Toggle routine.
220 * NOTE: this code assumes that instances do not receive selection
221 * events when insensitive.
225 * w = widget instance that was selected.
226 * event = event record
233 * XtCallCallbacks() [libXtk]
234 *************************************<->***********************************/
236 static void Select (w
,event
)
241 XwPushButtonWidget pb
= (XwPushButtonWidget
) w
;
243 if (pb
->pushbutton
.toggle
== TRUE
)
247 pb
->button
.set
= TRUE
;
249 RedrawButtonFace (w
, event
, FALSE
);
250 XFlush (XtDisplay(w
));
251 XtCallCallbacks (w
, XtNselect
, NULL
);
258 /*************************************<->*************************************
260 * Unselect (w, event) PRIVATE
264 * When this pushbutton is unselected draw it as inactive.
265 * Generate the correct callbacks.
267 * NOTE: this code respects the utility flag "toggle" if this
268 * flag is set to true then this routine is a no op.
272 * w = widget instance that was selected.
273 * event = event record
280 * XtCallCallbacks() [libXtk]
281 *************************************<->***********************************/
283 static void Unselect(w
,event
)
288 XwPushButtonWidget pb
= (XwPushButtonWidget
) w
;
291 if (! pb
->pushbutton
.toggle
)
293 pb
->button
.set
= FALSE
;
295 RedrawButtonFace (w
, event
, FALSE
);
296 XFlush(XtDisplay(w
));
297 XtCallCallbacks (w
, XtNrelease
, NULL
);
302 static void ToggleRelease(w
,event
)
307 XwPushButtonWidget pb
= (XwPushButtonWidget
) w
;
309 pb
->button
.set
= FALSE
;
311 RedrawButtonFace (w
, event
, FALSE
);
312 XFlush(XtDisplay(w
));
313 XtCallCallbacks (w
, XtNrelease
, NULL
);
318 /*************************************<->*************************************
324 * If the core height and width fields are set to 0, treat that as a flag
325 * and compute the optimum size for this button. Then using what ever
326 * the core fields are set to, compute the text placement fields.
327 * Make sure that the label location field is properly set for the
333 * request = request widget, old data.
335 * new = new widget, new data; cumulative effect
336 * of initialize procedures.
344 *************************************<->***********************************/
345 static void Initialize (request
, new)
349 XwPushButtonWidget pb
= (XwPushButtonWidget
) new;
351 /********************************************************************
353 2 * highlight thickness
354 2 * button overhead: 2 lines for button outline
355 2 * internal width (padding between label and button)
359 2 * highlight thickness
360 2 * button overhead: 2 lines for outline
361 2 * internal height (padding)
364 ************************************************************************/
366 if (request
->core
.width
== 0) pb
->core
.width
= pb
->button
.label_width
+
367 2 * ( pb
->button
.internal_width
+ /* white space */
368 pb
->primitive
.highlight_thickness
+ PB_BW
);
370 if (request
->core
.height
== 0) pb
->core
.height
= pb
->button
.label_height
+
371 2 * (pb
->button
.internal_height
+ pb
->primitive
.highlight_thickness
+ PB_BW
);
378 /*************************************<->*************************************
384 * Set fields in primitive class part of our class record so that
385 * the traversal code can invoke our button select procedures.
387 *************************************<->***********************************/
389 static void ClassInitialize()
391 XwpushButtonClassRec
.primitive_class
.select_proc
= (XwEventProc
) Select
;
392 XwpushButtonClassRec
.primitive_class
.release_proc
= (XwEventProc
) ToggleRelease
;
393 XwpushButtonClassRec
.primitive_class
.toggle_proc
= (XwEventProc
) Toggle
;
398 /*************************************<->*************************************
400 * Redisplay (w, event, region)
404 * Cause the widget, identified by w, to be redisplayed.
409 * w = widget to be redisplayed;
410 * event = event structure identifying need for redisplay on this
419 *************************************<->***********************************/
421 static void Redisplay (w
, event
, region
)
427 RedrawButtonFace (w
, event
, TRUE
);
431 static void RedrawButtonFace (w
, event
, all
)
432 XwPushButtonWidget w
;
437 register XwPushButtonWidget pb
= (XwPushButtonWidget
) w
;
438 int available_height
, available_width
;
439 Boolean clipHeight
, clipWidth
;
441 /* COMPUTE SPACE AVAILABLE FOR DRAWING LABEL */
443 available_width
= Max(0,(int)pb
->core
.width
- 2*((int)pb
->button
.internal_width
+ pb
->primitive
.highlight_thickness
+ PB_BW
));
445 available_height
= Max(0, (int)pb
->core
.height
- 2*((int)pb
->button
.internal_height
+ pb
->primitive
.highlight_thickness
+ PB_BW
));
449 /* SEE IF WE NEED TO CLIP THIS LABEL ON TOP AND/OR BOTTOM */
451 if (pb
->button
.label_width
> available_width
)
457 if (pb
->button
.label_height
> available_height
)
464 /* COMPUTE & DRAW PUSHBUTTON */
468 /* COMPUTE x LOCATION FOR STRING & DRAW STRING */
469 XFillRectangle (XtDisplay(w
), XtWindow(w
),
472 ? pb
->button
.normal_GC
473 : pb
->button
.inverse_GC
),
474 w
-> primitive
.highlight_thickness
+ 1 + PB_BW
,
475 w
-> primitive
.highlight_thickness
+ 1 + PB_BW
,
476 w
->core
.width
- 2 * (w
->primitive
.highlight_thickness
478 w
->core
.height
- 2 * (w
->primitive
.highlight_thickness
481 if (pb
->button
.label_len
> 0)
483 XDrawString(XtDisplay(w
), XtWindow(w
),
486 ? pb
->button
.inverse_GC
487 : pb
->button
.normal_GC
),
488 (((int)pb
->core
.width
+ 1 - pb
->button
.label_width
) / 2),
489 pb
->button
.label_y
, pb
->button
.label
,
490 pb
->button
.label_len
);
495 XClearArea (XtDisplay(w
), XtWindow(w
), 0,0,
496 (pb
->primitive
.highlight_thickness
+ PB_BW
+
497 pb
->button
.internal_width
), pb
->core
.height
, FALSE
);
499 XClearArea (XtDisplay(w
), XtWindow(w
),
500 ((int)pb
->core
.width
- pb
->primitive
.highlight_thickness
-
501 PB_BW
- (int)pb
->button
.internal_width
),0,
502 (pb
->primitive
.highlight_thickness
+ PB_BW
+
503 pb
->button
.internal_width
), pb
->core
.height
, FALSE
);
508 XClearArea (XtDisplay(w
), XtWindow(w
), 0,0, pb
->core
.width
,
509 (pb
->primitive
.highlight_thickness
+ PB_BW
+
510 pb
->button
.internal_height
), FALSE
);
511 XClearArea (XtDisplay(w
), XtWindow(w
), 0,
512 ((int)pb
->core
.height
- pb
->primitive
.highlight_thickness
-
513 PB_BW
- (int)pb
->button
.internal_height
), pb
->core
.width
,
514 (pb
->primitive
.highlight_thickness
+ PB_BW
+
515 pb
->button
.internal_height
), FALSE
);
520 _XwDrawBox (XtDisplay (w
), XtWindow (w
),
521 w
-> button
.normal_GC
, PB_BW
,
522 w
-> primitive
.highlight_thickness
,
523 w
-> primitive
.highlight_thickness
,
524 w
->core
.width
- 2 * w
->primitive
.highlight_thickness
,
525 w
->core
.height
- 2 * w
->primitive
.highlight_thickness
);
530 * Draw traversal/enter highlight if actual exposure or
531 * if we had to clip text area
534 if (all
|| clipWidth
|| clipHeight
)
536 if (pb
->primitive
.highlighted
)
537 _XwHighlightBorder(w
);
538 else if (pb
->primitive
.display_highlighted
)
539 _XwUnhighlightBorder(w
);
545 /*************************************<->*************************************
547 * SetValues(current, request, new)
551 * This is the set values procedure for the pushbutton class. It is
552 * called last (the set values rtnes for its superclasses are called
558 * current = original widget;
559 * request = copy of current (?);
560 * new = copy of request which reflects changes made to it by
561 * set values procedures of its superclasses;
562 * last = TRUE if this is the last set values procedure to be called.
570 *************************************<->***********************************/
572 static Boolean
SetValues(current
, request
, new)
573 Widget current
, request
, new;
576 XtWidgetGeometry reqGeo
;
577 XwPushButtonWidget curpb
= (XwPushButtonWidget
) current
;
578 XwPushButtonWidget newpb
= (XwPushButtonWidget
) new;
579 Boolean flag
= FALSE
; /* our return value */
582 /**********************************************************************
583 * Calculate the window size: The assumption here is that if
584 * the width and height are the same in the new and current instance
585 * record that those fields were not changed with set values. Therefore
586 * its okay to recompute the necessary width and height. However, if
587 * the new and current do have different width/heights then leave them
588 * alone because that's what the user wants.
589 *********************************************************************/
590 if ((curpb
->core
.width
== newpb
->core
.width
) &&
591 (_XwRecomputeSize(current
, new)))
594 newpb
->button
.label_width
+ 2*(newpb
->button
.internal_width
+
595 newpb
->primitive
.highlight_thickness
+ PB_BW
);
599 if ((curpb
->core
.height
== newpb
->core
.height
) &&
600 (_XwRecomputeSize(current
, new)))
603 newpb
->button
.label_height
+ 2*(newpb
->button
.internal_height
+
604 newpb
->primitive
.highlight_thickness
+ PB_BW
);
614 /*************************************<->*************************************
620 * Recompute location of button text
624 * w = widget to be resized.
627 *************************************<->***********************************/
630 static void Resize(w
)
633 XwPushButtonWidget pb
= (XwPushButtonWidget
) w
;
635 pb
->button
.label_x
= ((int)pb
->core
.width
+ 1 - pb
->button
.label_width
) / 2;
638 ((int)pb
->core
.height
- pb
->button
.label_height
) / 2
639 + pb
->button
.font
->max_bounds
.ascent
;