Merge branch 'master' into xcircuit-3.10
[xcircuit.git] / Xw / PButton.c
blob187a3f2d2210cbf815363f7b0ab31a9fbdbed760
1 /*************************************<+>*************************************
2 *****************************************************************************
3 **
4 ** File: PButton.c
5 **
6 ** Project: X Widgets
7 **
8 ** Description: Contains code for primitive widget class: PushButton
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
31 #include <stdio.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <X11/Intrinsic.h>
35 #include <X11/IntrinsicP.h>
36 #include <X11/StringDefs.h>
37 #include <Xw/Xw.h>
38 #include <Xw/XwP.h>
39 #include <Xw/PButtonP.h>
40 #include <Xw/PButton.h>
41 #include <X11/keysymdef.h>
44 #define PB_BW 2
47 static void Redisplay();
48 static void RedrawButtonFace();
49 static Boolean SetValues();
50 static void ClassInitialize();
51 static void Initialize();
52 static void Toggle();
53 static void ToggleRelease();
54 static void Select();
55 static void Unselect();
56 static void Resize();
59 /*************************************<->*************************************
62 * Description: default translation table for class: PushButton
63 * -----------
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
83 * -----------
85 * Matches string descriptors with internal routines.
86 * Note that Primitive will register additional event handlers
87 * for traversal.
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
117 * -----------
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,
144 /* destroy */ NULL,
145 /* resize */ Resize,
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,
157 /* extension */ NULL
160 WidgetClass XwpushButtonWidgetClass = (WidgetClass)&XwpushButtonClassRec;
163 /*************************************<->*************************************
165 * Toggle (w, event) PRIVATE
167 * Description:
168 * -----------
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
172 * in response.
174 * NOTE: this code assumes that instances do not receive selection
175 * events when insensitive.
177 * Inputs:
178 * ------
179 * w = widget instance that was selected.
180 * event = event record
182 * Outputs:
183 * -------
185 * Procedures Called
186 * -----------------
187 * XtCallCallbacks() [libXtk]
188 * Redisplay [PushButton.c]
189 *************************************<->***********************************/
191 static void Toggle (w,event)
192 Widget w;
193 XEvent *event;
196 XwPushButtonWidget pb = (XwPushButtonWidget)w;
199 if (pb -> button.set)
200 pb -> button.set = False;
201 else
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
214 * Description:
215 * -----------
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.
223 * Inputs:
224 * ------
225 * w = widget instance that was selected.
226 * event = event record
228 * Outputs:
229 * -------
231 * Procedures Called
232 * -----------------
233 * XtCallCallbacks() [libXtk]
234 *************************************<->***********************************/
236 static void Select (w,event)
237 Widget w;
238 XEvent *event;
241 XwPushButtonWidget pb = (XwPushButtonWidget) w;
243 if (pb->pushbutton.toggle == TRUE)
244 Toggle(w,event);
245 else
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
262 * Description:
263 * -----------
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.
270 * Inputs:
271 * ------
272 * w = widget instance that was selected.
273 * event = event record
275 * Outputs:
276 * -------
278 * Procedures Called
279 * -----------------
280 * XtCallCallbacks() [libXtk]
281 *************************************<->***********************************/
283 static void Unselect(w,event)
284 Widget w;
285 XEvent *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)
303 Widget w;
304 XEvent *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 /*************************************<->*************************************
320 * Initialize
322 * Description:
323 * -----------
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
328 * Resize call.
331 * Inputs:
332 * ------
333 * request = request widget, old data.
335 * new = new widget, new data; cumulative effect
336 * of initialize procedures.
338 * Outputs:
339 * -------
341 * Procedures Called
342 * -----------------
344 *************************************<->***********************************/
345 static void Initialize (request, new)
346 Widget request, new;
349 XwPushButtonWidget pb = (XwPushButtonWidget) new;
351 /********************************************************************
352 Needed width:
353 2 * highlight thickness
354 2 * button overhead: 2 lines for button outline
355 2 * internal width (padding between label and button)
356 width of label
358 Needed height:
359 2 * highlight thickness
360 2 * button overhead: 2 lines for outline
361 2 * internal height (padding)
362 label height
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);
373 Resize(new);
378 /*************************************<->*************************************
380 * ClassInitialize
382 * Description:
383 * -----------
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)
402 * Description:
403 * -----------
404 * Cause the widget, identified by w, to be redisplayed.
407 * Inputs:
408 * ------
409 * w = widget to be redisplayed;
410 * event = event structure identifying need for redisplay on this
411 * widget.
413 * Outputs:
414 * -------
416 * Procedures Called
417 * -----------------
418 * XDrawString()
419 *************************************<->***********************************/
421 static void Redisplay (w, event, region)
422 Widget w;
423 XEvent *event;
424 Region region;
427 RedrawButtonFace (w, event, TRUE);
431 static void RedrawButtonFace (w, event, all)
432 XwPushButtonWidget w;
433 XEvent *event;
434 Boolean all;
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)
452 clipWidth = True;
453 else
454 clipWidth = False;
457 if (pb->button.label_height > available_height)
458 clipHeight = True;
459 else
460 clipHeight = False;
464 /* COMPUTE & DRAW PUSHBUTTON */
468 /* COMPUTE x LOCATION FOR STRING & DRAW STRING */
469 XFillRectangle (XtDisplay(w), XtWindow(w),
470 ((pb->button.set
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
477 + 1 + PB_BW),
478 w->core.height- 2 * (w->primitive.highlight_thickness
479 + 1 + PB_BW));
481 if (pb->button.label_len > 0)
483 XDrawString(XtDisplay(w), XtWindow(w),
484 ((pb->button.set
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);
493 if (clipWidth)
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);
506 if (clipHeight)
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)
549 * Description:
550 * -----------
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
553 * first).
556 * Inputs:
557 * ------
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.
564 * Outputs:
565 * -------
567 * Procedures Called
568 * -----------------
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)))
593 newpb->core.width =
594 newpb->button.label_width + 2*(newpb->button.internal_width +
595 newpb->primitive.highlight_thickness + PB_BW);
596 flag = TRUE;
599 if ((curpb->core.height == newpb->core.height) &&
600 (_XwRecomputeSize(current, new)))
602 newpb->core.height =
603 newpb->button.label_height + 2*(newpb->button.internal_height +
604 newpb->primitive.highlight_thickness + PB_BW);
605 flag = TRUE;
608 return(flag);
614 /*************************************<->*************************************
616 * Resize(w)
618 * Description:
619 * -----------
620 * Recompute location of button text
622 * Inputs:
623 * ------
624 * w = widget to be resized.
627 *************************************<->***********************************/
630 static void Resize(w)
631 Widget w;
633 XwPushButtonWidget pb = (XwPushButtonWidget) w;
635 pb->button.label_x = ((int)pb->core.width + 1 - pb->button.label_width) / 2;
637 pb->button.label_y =
638 ((int)pb->core.height - pb->button.label_height) / 2
639 + pb->button.font->max_bounds.ascent;