Corrected a long-standing error in which ending text with a literal
[xcircuit.git] / Xw / Button.c
blobf49538032f8cf58728b4255c2729b203361502b1
1 /*************************************<+>*************************************
2 *****************************************************************************
3 **
4 ** File: Button.c
5 **
6 ** Project: X Widgets
7 **
8 ** Description: Code/Definitions for Button widget meta class.
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 *************************************<+>************************************/
29 * Include files & Static Routine Definitions
32 #include <stdio.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <X11/StringDefs.h>
36 #include <X11/IntrinsicP.h>
37 #include <X11/Intrinsic.h>
38 #include <X11/Xatom.h>
39 #include <Xw/Xw.h>
40 #include <Xw/XwP.h>
42 static Boolean SetValues();
43 static void ButtonDestroy();
46 /*************************************<->*************************************
49 * Description: resource list for class: Button
50 * -----------
52 * Provides default resource settings for instances of this class.
53 * To get full set of default settings, examine resouce list of super
54 * classes of this class.
56 *************************************<->***********************************/
58 static XtResource resources[] =
62 XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
63 XtOffset (XwButtonWidget, button.font), XtRString, "Fixed"
67 XtNlabel, XtCLabel, XtRString, sizeof (caddr_t),
68 XtOffset (XwButtonWidget, button.label), XtRString, NULL
72 XtNlabelLocation, XtCLabelLocation, XtRLabelLocation, sizeof(int),
73 XtOffset (XwButtonWidget, button.label_location), XtRString, "right"
77 XtNvSpace, XtCVSpace, XtRDimension, sizeof(Dimension),
78 XtOffset (XwButtonWidget, button.internal_height), XtRString, "2"
82 XtNhSpace, XtCHSpace, XtRDimension, sizeof(Dimension),
83 XtOffset (XwButtonWidget, button.internal_width), XtRString, "2"
87 XtNset, XtCSet, XtRBoolean, sizeof (Boolean),
88 XtOffset (XwButtonWidget, button.set), XtRString, "False"
92 XtNsensitiveTile, XtCSensitiveTile, XtRTileType, sizeof (int),
93 XtOffset(XwButtonWidget, button.sensitive_tile),
94 XtRString, "foreground"
98 XtNborderWidth, XtCBorderWidth, XtRDimension, sizeof(Dimension),
99 XtOffset(XwButtonWidget,core.border_width), XtRString, "0"
106 /*************************************<->*************************************
109 * Description: global class record for instances of class: Button
110 * -----------
112 * Defines default field settings for this class record. Note that
113 * while Button needs a special type converter, it doesn't need to
114 * register that converter since Primitive takes care of registering
115 * all of the converters for the X Widgets library and Button is a
116 * subclass of Primitive.
118 *************************************<->***********************************/
120 XwButtonClassRec XwbuttonClassRec =
123 (WidgetClass) &XwprimitiveClassRec, /* superclass */
124 "XwButton", /* class_name */
125 sizeof(XwButtonRec), /* widget_size */
126 NULL, /* class_initialize */
127 NULL, /* class part initialize */
128 FALSE, /* class_inited */
129 _XwInitializeButton, /* initialize */
130 NULL, /* initialize hook */
131 NULL, /* realize */
132 NULL, /* actions */
133 0, /* num_actions */
134 resources, /* resources */
135 XtNumber(resources), /* num_resources */
136 NULLQUARK, /* xrm_class */
137 TRUE, /* compress_motion */
138 TRUE, /* compress_exposure */
139 TRUE, /* compress_enterleave */
140 FALSE, /* visible_interest */
141 ButtonDestroy, /* destroy */
142 NULL, /* resize */
143 NULL, /* expose */
144 SetValues, /* set_values */
145 NULL, /* set_values_hook */
146 XtInheritSetValuesAlmost, /* set_values_almost */
147 NULL, /* get_values_hook */
148 NULL, /* accept_focus */
149 XtVersion, /* toolkit version */
150 NULL, /* PRIVATE callback */
151 NULL, /* tm_table */
152 NULL, /* query_geometry */
153 /* display_accelerator */ XtInheritDisplayAccelerator,
154 /* extension */ NULL
157 /* Inherit procedures for handling traversal and selection */
159 (XtWidgetProc) XtInheritBorderHighlight,
160 (XtWidgetProc) XtInheritBorderUnhighlight,
161 (XwEventProc) XtInheritSelectProc,
162 (XwEventProc) XtInheritReleaseProc,
163 (XwEventProc) XtInheritToggleProc,
167 0, /* Button class part - unused */
171 WidgetClass XwbuttonWidgetClass = (WidgetClass) &XwbuttonClassRec;
175 /*************************************<->*************************************
177 * ButtonDestroy (bw)
179 * Description:
180 * -----------
181 * Free up the space taken by the button's label and free up the
182 * button's graphic contexts.
185 * Inputs:
186 * ------
187 * bw = button (or subclass of button) to be destroyed.
189 *************************************<->***********************************/
190 static void ButtonDestroy (bw)
191 XwButtonWidget bw;
193 if (bw->button.label)
194 XtFree (bw->button.label);
195 XtDestroyGC (bw->button.normal_GC);
196 XtDestroyGC (bw->button.inverse_GC);
199 /*************************************<->*************************************
201 * SetValues(current, request, new, last)
203 * Description:
204 * -----------
205 * This is the set values procedure for the button class.
208 * Inputs:
209 * ------
210 * current = original widget;
211 * request = copy of current (?);
212 * new = copy of request which reflects changes made to it by
213 * set values procedures of its superclasses;
214 * last = TRUE if this is the last set values procedure to be called.
216 * Outputs:
217 * -------
219 * Procedures Called
220 * -----------------
222 *************************************<->***********************************/
224 static Boolean SetValues(current, request, new)
225 Widget current, request, new;
227 XwButtonWidget curcbox = (XwButtonWidget) current;
228 XwButtonWidget newcbox = (XwButtonWidget) new;
229 Boolean flag = FALSE; /* our return value */
230 int GCflag = 0;
232 #define NewNormal 1
233 #define NewInverse 2
236 /************************************************************
237 * If the button setting has been changed then set flag so that
238 * button will be redisplayed. NOTE THAT IF THE APPLICATION
239 * WANTS THE CALLBACKS ASSOCIATED WITH THE BUTTON TO BE INVOKED
240 * IT WILL HAVE TO DIRECTLY CALL XTCALLCALLBACKS.
241 ************************************************************/
242 if (curcbox->button.set != newcbox->button.set) flag = TRUE;
245 /************************************************************
246 * If the font has been changed then we need to
247 * recompute the text width and height. We'll also have
248 * to change other things, see below...
249 ************************************************************/
250 if (curcbox->button.font != newcbox->button.font)
252 _XwSetTextWidthAndHeight(newcbox);
253 flag = TRUE;
257 /**************************************************************
258 * If a new label has been provided then we'll need to copy it
259 * into our data space.
260 * Free up any space previously allocated for the label name.
261 * NOTE: We allow them to specify a NULL label.
262 ***************************************************************/
263 if (curcbox->button.label != newcbox->button.label)
265 /* Set label length, height and width */
266 _XwSetTextWidthAndHeight(newcbox);
268 if (newcbox->button.label)
269 newcbox->button.label = strcpy(
270 XtMalloc((unsigned) newcbox->button.label_len + 1),
271 newcbox->button.label);
273 if (curcbox->button.label)
274 XtFree ((char *) curcbox->button.label);
275 flag = TRUE;
280 /**********************************************************************
281 * If the label location flag has changed set the redisplay flag TRUE
282 * and check that it has a valid setting. If its invalid, then issue
283 * a warning.
284 ********************************************************************/
285 if (curcbox->button.label_location != newcbox->button.label_location)
287 flag = TRUE;
288 if ((newcbox->button.label_location != XwLEFT) &&
289 (newcbox->button.label_location != XwRIGHT) &&
290 (newcbox->button.label_location != XwCENTER))
292 XtWarning("SetValues: Invalid Label Location Setting.");
293 newcbox->button.label_location =
294 curcbox->button.label_location;
298 /*********************************************************************
299 * If the sensitive tile has changed, validate it. Then, if the
300 * foreground or background or font or sensitive tile has changed
301 * then recompute/get a new (In)sensitive GC.
302 ********************************************************************/
303 if (newcbox->button.sensitive_tile != XwFOREGROUND)
305 newcbox->button.sensitive_tile = curcbox->button.sensitive_tile;
306 XtWarning("SetValues: Invalid sensitive tile setting.");
309 if (curcbox->primitive.foreground != newcbox->primitive.foreground ||
310 curcbox->core.background_pixel != newcbox->core.background_pixel)
312 /* GET ALL NEW GC's */
313 GCflag = NewNormal | NewInverse;
316 if (curcbox->button.font->fid != newcbox->button.font->fid)
318 /* GET NEW GC's FOR normal & inverse */
319 GCflag = NewNormal | NewInverse;
322 if ((curcbox->button.sensitive_tile != newcbox->button.sensitive_tile) &&
323 (! newcbox->core.sensitive || ! newcbox->core.ancestor_sensitive))
325 /* GET NEW normal GC */
326 GCflag |= NewNormal;
329 if ((newcbox->core.sensitive != curcbox->core.sensitive) &&
330 ((newcbox->core.sensitive && newcbox->core.ancestor_sensitive) ||
331 (!newcbox->core.sensitive && curcbox->core.ancestor_sensitive)))
333 /* GET NEW normal GC */
334 GCflag |= NewNormal;
336 else if (newcbox->core.sensitive &&
337 (curcbox->core.ancestor_sensitive != newcbox->core.ancestor_sensitive))
339 /* GET NEW normal GC */
340 GCflag |= NewNormal;
345 if (GCflag & NewNormal)
347 XtDestroyGC(curcbox->button.normal_GC);
348 _XwGetNormalGC(newcbox);
349 flag = TRUE;
351 if (GCflag & NewInverse)
353 XtDestroyGC(curcbox->button.inverse_GC);
354 _XwGetInverseGC(newcbox);
355 flag = TRUE;
359 /********************************************************************
360 * NOTE THAT SUBCLASSES OF BUTTON WILL HAVE TO CHECK FOR CHANGES IN
361 * internal_width, internal_height AND DETERMINE WHAT SHOULD BE DONE.
362 * WE'RE JUST BEING GOOD CITIZENS HERE AND FLAGING THAT IT WILL HAVE
363 * TO BE REDISPLAYED BECAUSE OF THE CHANGE.
364 *********************************************************************/
365 if ((curcbox->button.internal_width
366 != newcbox->button.internal_width) ||
367 (curcbox->button.internal_height
368 != newcbox->button.internal_height)) flag = TRUE;
371 return( flag );
376 /*************************************<->*************************************
378 * void _XwSetTextWidthAndHeight (aButton)
380 * Description:
381 * -----------
382 * Calculate width and height of displayed text in pixels.
383 * Sets the following fields in the button portion of a button
384 * instance record:
386 * label_len
387 * label_height
388 * label_width
390 * Inputs:
391 * ------
392 * aButton = XwButtonWidget
394 * Procedures Called
395 * -----------------
396 * XwStrlen() [a macro: #define XwStrlen(s) ((s) ? strlen(s) : 0) ]
397 * XTextWidth()
398 *************************************<->***********************************/
400 void _XwSetTextWidthAndHeight(aButton)
401 XwButtonWidget aButton;
403 register XFontStruct *fs = aButton->button.font;
405 aButton->button.label_height =
406 fs->max_bounds.ascent + fs->max_bounds.descent;
408 if (aButton->button.label)
410 aButton->button.label_len = XwStrlen(aButton->button.label);
412 aButton->button.label_width = XTextWidth(
413 fs, aButton->button.label,
414 (int) aButton->button.label_len);
416 else
418 aButton->button.label_len = 0;
419 aButton->button.label_width = 0;
423 /*************************************<->*************************************
425 * void _XwGetNormalGC(aButton)
426 * XwButtonWidget aButton;
428 * Description:
429 * -----------
430 * Uses the widget specific foreground to generate the "normal"
431 * graphic context. Note that this is a XToolkit sharable GC.
432 * Creates the needed GC and sets ptr. in instance record.
434 * Inputs:
435 * ------
436 * aButton = widget instance.
438 * Outputs:
439 * -------
441 * Procedures Called
442 * -----------------
443 * XtGetGC
444 *************************************<->***********************************/
446 void _XwGetNormalGC(aButton)
447 XwButtonWidget aButton;
449 XGCValues values;
451 values.foreground = aButton->primitive.foreground;
452 values.background = aButton->core.background_pixel;
453 values.font = aButton->button.font->fid;
455 values.line_width = 1;
456 aButton->button.normal_GC = XtGetGC((Widget)aButton,
457 (unsigned) GCForeground |
458 (unsigned) GCBackground |
459 GCLineWidth |
460 GCFont,
461 &values);
464 /*************************************<->*************************************
466 * void _XwGetInverseGC(aButton)
467 * XwButtonWidget aButton;
469 * Description:
470 * -----------
472 * Inputs:
473 * ------
474 * aButton = widget instance.
476 * Outputs:
477 * -------
479 * Procedures Called
480 * -----------------
481 * XwGetGC
482 *************************************<->***********************************/
484 void _XwGetInverseGC(aButton)
485 XwButtonWidget aButton;
487 XGCValues values;
488 values.foreground = aButton->core.background_pixel;
489 values.background = aButton->primitive.foreground;
490 values.font = aButton->button.font->fid;
491 values.line_width = 1;
493 aButton->button.inverse_GC = XtGetGC((Widget)aButton,
494 (unsigned) GCForeground | (unsigned) GCBackground |
495 GCLineWidth | GCFont, &values);
498 /*************************************<->*************************************
500 * _XwInitializeButton (request, new)
502 * Description:
503 * -----------
504 * This is the button instance initialize procedure. Make sure
505 * that the button has a label, compute its height and width fields;
506 * set the appropriate graphic contexts.
508 * Inputs:
509 * ------
510 * request = original instance record;
512 * new = instance record with modifications induced by
513 * other initialize routines, changes are made to this
514 * record;
516 * args = argument list specified in XtCreateWidget;
518 * num_args = argument count;
520 * Outputs:
521 * -------
523 * Procedures Called
524 * -----------------
526 *************************************<->***********************************/
528 void _XwInitializeButton (request, new)
529 Widget request, new;
532 XwButtonWidget aButton = (XwButtonWidget) new;
535 * NOTE: we don't allow a NULL string for our button label.
536 * If we do find a NULL at initialize time then we will use the
537 * button name. The rationale for this is that this allows someone
538 * to change the button label in the .Xdefaults file, whereas if
539 * the application programmer hardwired the name into an arg list
540 * it would be impossible to change. However, if you really want
541 * a NULL string, do a SetValues and change the label to NULL.
543 * We need to malloc space for this string and copy it to our
544 * space. The toolkit simply copies the pointer to the string.
546 if (aButton->button.label == NULL) aButton->button.label =
547 aButton->core.name;
549 aButton->button.label = strcpy( XtMalloc((unsigned)
550 (XwStrlen(aButton->button.label)+1)),
551 aButton->button.label);
555 * make sure that sensitive_tile is valid
557 if (aButton->button.sensitive_tile != XwFOREGROUND)
559 aButton->button.sensitive_tile = XwFOREGROUND;
560 XtWarning("Initialize: Invalid sensitive tile setting.");
564 _XwGetInverseGC(aButton);
565 _XwGetNormalGC(aButton);
567 _XwSetTextWidthAndHeight(aButton);
569 aButton->primitive.display_sensitive = FALSE;
570 aButton->primitive.highlighted = FALSE;
573 } /* _XwInitializeButton */
576 /*************************************<->*************************************
578 * _XwRealize
580 * Description:
581 * -----------
582 * This is a generalize routine used by both subclasses of Primitive
583 * and Manager. It sets bit gravity to NW for managers and to Forget
584 * for others, but for Buttons is sets it according to the setting of
585 * label location.
587 * Inputs
588 * ------
589 * w = widget to be realized.
591 * valueMask = contains event mask for this window/widget.
593 * attributes = window attributes for this window/widget.
595 * Outputs:
596 * -------
598 * Procedures Called
599 * -----------------
600 * XCreateWindow()
601 *************************************<->***********************************/
603 void _XwRealize(w, p_valueMask, attributes)
604 register Widget w;
605 Mask *p_valueMask;
606 XSetWindowAttributes *attributes;
608 Mask valueMask = *p_valueMask;
609 valueMask |= CWBitGravity;
611 if (XtIsSubclass(w, XwprimitiveWidgetClass)) {
612 register XwPrimitiveWidget pw = (XwPrimitiveWidget) w;
613 if (pw->primitive.cursor != None) valueMask |= CWCursor;
614 attributes->cursor = pw->primitive.cursor;
617 if (XtIsSubclass(w, XwmanagerWidgetClass))
618 attributes->bit_gravity = NorthWestGravity;
619 else
620 if (w->core.widget_class != XwbuttonWidgetClass)
621 attributes->bit_gravity = ForgetGravity;
622 else
623 switch (((XwButtonWidget)w)->button.label_location)
625 case XwRIGHT:
626 attributes->bit_gravity = EastGravity; break;
627 case XwLEFT:
628 attributes->bit_gravity = WestGravity; break;
629 case XwCENTER:
630 attributes->bit_gravity = CenterGravity; break;
633 XtCreateWindow(w, InputOutput, (Visual *)CopyFromParent,
634 valueMask, attributes);
636 _XwRegisterName(w); /* hang widget name as property on window */
638 } /* _XwRealize */
641 /*************************************<->*************************************
643 * _XwResizeButton(w)
645 * Description:
646 * -----------
647 * A resize event has been generated. Recompute location of button
648 * elements.
650 * USED BY CHECKBOX AND PUSHBUTTON CLASSES.
652 * Inputs:
653 * ------
654 * w = widget to be resized.
656 * Outputs:
657 * -------
659 * Procedures Called
660 * -----------------
662 *************************************<->***********************************/
665 void _XwResizeButton(w)
666 Widget w;
668 register XwButtonWidget aButton = (XwButtonWidget) w;
669 int direction = aButton->button.label_location;
671 switch (direction)
673 case XwCENTER:
674 aButton->button.label_x = ((int)aButton->core.width + 1 -
675 (int)aButton->button.label_width) / 2;
676 break;
678 case XwRIGHT:
679 aButton->button.label_x = (int)aButton->core.width -
680 (int)aButton->button.internal_width -
681 aButton->primitive.highlight_thickness -
682 (int)aButton->button.label_width;
683 break;
685 default:
686 aButton->button.label_x = aButton->button.internal_width +
687 aButton->primitive.highlight_thickness;
690 aButton->button.label_y =
691 (((int)aButton->core.height - (int)aButton->button.label_height) >> 1)
692 + aButton->button.font->max_bounds.ascent;
697 /*************************************<->*************************************
699 * ProcedureName (parameters)
701 * Description:
702 * -----------
703 * This procedure is used to store the name of the widget as a
704 * property on the widget's window. The property name is the
705 * string "XW_NAME". Note that we do not malloc space for the
706 * widget's name, we merely use the pointer to this string which
707 * is already in core.name. This shouldn't be a problem since
708 * the name will remain as long as the widget exists.
710 * We only want to do this one time, thus the hokey method of
711 * initializing a static boolean which prevents us from registering
712 * this atom more than once on the server.
714 * If possible, we should put this together with other functions done
715 * once. Also, WILL THIS BE A PROBLEM WHEN THE TOOLKIT ALLOWS MORE
716 * THAN ONE DISPLAY TO BE OPENED?????
718 * Inputs:
719 * ------
720 * w = widget being created.
722 * Outputs:
723 * -------
725 * Procedures Called
726 * -----------------
728 *************************************<->***********************************/
730 static Atom widget_name;
731 static Boolean first=True;
733 void _XwRegisterName(w)
734 Widget w;
736 if (first)
738 widget_name = XInternAtom (XtDisplay(w), "XW_NAME", False);
739 first = False;
741 XChangeProperty (XtDisplay(w), XtWindow(w), widget_name, XA_STRING, 8,
742 PropModeReplace, w->core.name,
743 XwStrlen(w->core.name)+1);
747 /*************************************<->*************************************
748 * Boolean
749 * _XwRecomputeSize(current, new)
751 * Description:
752 * -----------
753 * Used during SetValues for PButton and Toggle.
754 * If the font has changed OR the label has changed OR
755 * the internal spacing has changed OR the highlight
756 * thickness has changed AND the recompute flag is TRUE
757 * (in the new widget) return TRUE, else return FALSE.
760 * Inputs:
761 * ------
762 * current = current version of widget
763 * new = new version of widget
765 * Outputs:
766 * -------
767 * TRUE if resize is needed and okay, FALSE otherwise.
769 *************************************<->***********************************/
770 Boolean _XwRecomputeSize(current, new)
771 XwButtonWidget current, new;
773 if (((new->button.font != current->button.font) ||
774 (new->button.label != current->button.label) ||
775 (new->primitive.highlight_thickness !=
776 current->primitive.highlight_thickness) ||
777 (new->button.internal_height != current->button.internal_height) ||
778 (new->button.internal_width != current->button.internal_width)) &&
779 (new->primitive.recompute_size == TRUE))
780 return(TRUE);
781 else
782 return(FALSE);