Dialog.c revision 5ec34c4c
1/***********************************************************
2
3Copyright 1987, 1988, 1994, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25
26Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
27
28                        All Rights Reserved
29
30Permission to use, copy, modify, and distribute this software and its
31documentation for any purpose and without fee is hereby granted,
32provided that the above copyright notice appear in all copies and that
33both that copyright notice and this permission notice appear in
34supporting documentation, and that the name of Digital not be
35used in advertising or publicity pertaining to distribution of the
36software without specific, written prior permission.
37
38DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44SOFTWARE.
45
46******************************************************************/
47
48#ifdef HAVE_CONFIG_H
49#include <config.h>
50#endif
51#include <X11/IntrinsicP.h>
52#include <X11/StringDefs.h>
53#include <X11/Xos.h>
54#include <X11/Xmu/Misc.h>
55#include <X11/Xaw/AsciiText.h>
56#include <X11/Xaw/Cardinals.h>
57#include <X11/Xaw/Command.h>
58#include <X11/Xaw/Label.h>
59#include <X11/Xaw/DialogP.h>
60#include <X11/Xaw/XawInit.h>
61#include "Private.h"
62
63/*
64 * After we have set the string in the value widget we set the
65 * string to a magic value.  So that when a SetValues request is made
66 * on the dialog value we will notice it, and reset the string
67 */
68#define MAGIC_VALUE	((char *)3)
69
70#define streq(a,b)	(strcmp((a), (b)) == 0)
71
72/*
73 * Class Methods
74 */
75static void XawDialogConstraintInitialize(Widget, Widget,
76					  ArgList, Cardinal*);
77static void XawDialogGetValuesHook(Widget, ArgList, Cardinal*);
78static void XawDialogInitialize(Widget, Widget, ArgList, Cardinal*);
79static Boolean XawDialogSetValues(Widget, Widget, Widget,
80				  ArgList, Cardinal*);
81
82/*
83 * Prototypes
84 */
85static void CreateDialogValueWidget(Widget);
86
87/*
88 * Initialization
89 */
90static XtResource resources[] = {
91  {
92    XtNlabel,
93    XtCLabel,
94    XtRString,
95    sizeof(String),
96    XtOffsetOf(DialogRec, dialog.label),
97    XtRString,
98    NULL
99  },
100  {
101    XtNvalue,
102    XtCValue,
103    XtRString,
104    sizeof(String),
105    XtOffsetOf(DialogRec, dialog.value),
106    XtRString,
107    NULL
108  },
109  {
110    XtNicon,
111    XtCIcon,
112    XtRBitmap,
113    sizeof(Pixmap),
114    XtOffsetOf(DialogRec, dialog.icon),
115    XtRImmediate,
116    NULL
117  },
118};
119
120DialogClassRec dialogClassRec = {
121  /* core */
122  {
123    (WidgetClass)&formClassRec,		/* superclass */
124    "Dialog",				/* class_name */
125    sizeof(DialogRec),			/* widget_size */
126    XawInitializeWidgetSet,		/* class_initialize */
127    NULL,				/* class_part init */
128    False,				/* class_inited */
129    XawDialogInitialize,		/* initialize */
130    NULL,				/* initialize_hook */
131    XtInheritRealize,			/* 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    NULL,				/* destroy */
142    XtInheritResize,			/* resize */
143    XtInheritExpose,			/* expose */
144    XawDialogSetValues,			/* set_values */
145    NULL,				/* set_values_hook */
146    XtInheritSetValuesAlmost,		/* set_values_almost */
147    XawDialogGetValuesHook,		/* get_values_hook */
148    NULL,				/* accept_focus */
149    XtVersion,				/* version */
150    NULL,				/* callback_private */
151    NULL,				/* tm_table */
152    XtInheritQueryGeometry,		/* query_geometry */
153    XtInheritDisplayAccelerator,	/* display_accelerator */
154    NULL,				/* extension */
155  },
156  /* composite */
157  {
158    XtInheritGeometryManager,		/* geometry_manager */
159    XtInheritChangeManaged,		/* change_managed */
160    XtInheritInsertChild,		/* insert_child */
161    XtInheritDeleteChild,		/* delete_child */
162    NULL,				/* extension */
163  },
164  /* constraint */
165  {
166    NULL,				/* subresourses */
167    0,					/* subresource_count */
168    sizeof(DialogConstraintsRec),	/* constraint_size */
169    XawDialogConstraintInitialize,	/* initialize */
170    NULL,				/* destroy */
171    NULL,				/* set_values */
172    NULL,				/* extension */
173  },
174  /* form */
175  {
176    XtInheritLayout,			/* layout */
177  },
178  /* dialog */
179  {
180    NULL,				/* extension */
181  }
182};
183
184WidgetClass dialogWidgetClass = (WidgetClass)&dialogClassRec;
185
186/*
187 * Implementation
188 */
189/*ARGSUSED*/
190static void
191XawDialogInitialize(Widget request _X_UNUSED, Widget cnew,
192		    ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
193{
194    DialogWidget dw = (DialogWidget)cnew;
195    Arg arglist[9];
196    Cardinal arg_cnt = 0;
197
198    XtSetArg(arglist[arg_cnt], XtNborderWidth, 0);		    arg_cnt++;
199    XtSetArg(arglist[arg_cnt], XtNleft, XtChainLeft);		    arg_cnt++;
200
201    if (dw->dialog.icon != (Pixmap)0) {
202	XtSetArg(arglist[arg_cnt], XtNbitmap, dw->dialog.icon);     arg_cnt++;
203	XtSetArg(arglist[arg_cnt], XtNright, XtChainLeft);	    arg_cnt++;
204	dw->dialog.iconW = XtCreateManagedWidget("icon", labelWidgetClass,
205						 cnew, arglist, arg_cnt);
206	arg_cnt = 2;
207	XtSetArg(arglist[arg_cnt], XtNfromHoriz, dw->dialog.iconW); arg_cnt++;
208    }
209    else
210	dw->dialog.iconW = NULL;
211
212    XtSetArg(arglist[arg_cnt], XtNlabel, dw->dialog.label);	    arg_cnt++;
213    XtSetArg(arglist[arg_cnt], XtNright, XtChainRight);		    arg_cnt++;
214
215    dw->dialog.labelW = XtCreateManagedWidget("label", labelWidgetClass,
216					      cnew, arglist, arg_cnt);
217
218    if (dw->dialog.iconW != NULL &&
219        XtHeight(dw->dialog.labelW) < XtHeight(dw->dialog.iconW)) {
220	XtSetArg(arglist[0], XtNheight, XtHeight(dw->dialog.iconW));
221	XtSetValues(dw->dialog.labelW, arglist, 1);
222    }
223    if (dw->dialog.value != NULL)
224	CreateDialogValueWidget((Widget)dw);
225    else
226        dw->dialog.valueW = NULL;
227}
228
229/*ARGSUSED*/
230static void
231XawDialogConstraintInitialize(Widget request _X_UNUSED, Widget cnew,
232			      ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
233{
234    DialogWidget dw = (DialogWidget)cnew->core.parent;
235    DialogConstraints constraint = (DialogConstraints)cnew->core.constraints;
236
237    if (!XtIsSubclass(cnew, commandWidgetClass)) /* if not a button */
238	return;					 /* then just use defaults */
239
240    constraint->form.left = constraint->form.right = XtChainLeft;
241    if (dw->dialog.valueW == NULL)
242	constraint->form.vert_base = dw->dialog.labelW;
243    else
244	constraint->form.vert_base = dw->dialog.valueW;
245
246    if (dw->composite.num_children > 1) {
247	WidgetList children = dw->composite.children;
248	Widget *childP;
249
250        for (childP = children + dw->composite.num_children - 1;
251	   childP >= children; childP-- ) {
252	    if (*childP == dw->dialog.labelW || *childP == dw->dialog.valueW)
253		break;
254	    if (XtIsManaged(*childP) &&
255	        XtIsSubclass(*childP, commandWidgetClass)) {
256		constraint->form.horiz_base = *childP;
257		break;
258	    }
259	}
260    }
261}
262
263#define ICON 0
264#define LABEL 1
265#define NUM_CHECKS 2
266/*ARGSUSED*/
267static Boolean
268XawDialogSetValues(Widget current, Widget request _X_UNUSED, Widget cnew,
269		   ArgList in_args, Cardinal *in_num_args)
270{
271    DialogWidget w = (DialogWidget)cnew;
272    DialogWidget old = (DialogWidget)current;
273    Arg args[5];
274    Cardinal num_args;
275    unsigned int i;
276    Bool checks[NUM_CHECKS];
277
278    for (i = 0; i < NUM_CHECKS; i++)
279	checks[i] = False;
280
281    for (i = 0; i < *in_num_args; i++) {
282	if (streq(XtNicon, in_args[i].name))
283	    checks[ICON] = True;
284	else if (streq(XtNlabel, in_args[i].name))
285	    checks[LABEL] = True;
286    }
287
288    if (checks[ICON]) {
289	if (w->dialog.icon != 0) {
290	    XtSetArg(args[0], XtNbitmap, w->dialog.icon);
291	    if (old->dialog.iconW != NULL)
292		XtSetValues(old->dialog.iconW, args, 1);
293	    else {
294		XtSetArg(args[1], XtNborderWidth, 0);
295		XtSetArg(args[2], XtNleft, XtChainLeft);
296		XtSetArg(args[3], XtNright, XtChainLeft);
297		w->dialog.iconW = XtCreateWidget("icon", labelWidgetClass,
298						 cnew, args, 4);
299		((DialogConstraints)w->dialog.labelW->core.constraints)->
300		    form.horiz_base = w->dialog.iconW;
301		XtManageChild(w->dialog.iconW);
302	    }
303	}
304	else if (old->dialog.icon != 0) {
305	    ((DialogConstraints)w->dialog.labelW->core.constraints)->
306		form.horiz_base = NULL;
307	    XtDestroyWidget(old->dialog.iconW);
308	    w->dialog.iconW = NULL;
309	}
310    }
311
312    if (checks[LABEL]) {
313	num_args = 0;
314	XtSetArg(args[num_args], XtNlabel, w->dialog.label);	num_args++;
315	if (w->dialog.iconW != NULL &&
316	    XtHeight(w->dialog.labelW) <= XtHeight(w->dialog.iconW)) {
317	    XtSetArg(args[num_args], XtNheight, XtHeight(w->dialog.iconW));
318	    num_args++;
319	}
320	XtSetValues(w->dialog.labelW, args, num_args);
321    }
322
323    if (w->dialog.value != old->dialog.value) {
324	if (w->dialog.value == NULL)	/* only get here if it
325					   wasn't NULL before */
326	    XtDestroyWidget(old->dialog.valueW);
327	else if (old->dialog.value == NULL) {	/* create a new value widget */
328	    XtWidth(w) = XtWidth(old);
329	    XtHeight(w) = XtHeight(old);
330	    CreateDialogValueWidget(cnew);
331	}
332	else {				/* Widget ok, just change string */
333	    Arg nargs[1];
334
335	    XtSetArg(nargs[0], XtNstring, w->dialog.value);
336	    XtSetValues(w->dialog.valueW, nargs, 1);
337	    w->dialog.value = MAGIC_VALUE;
338	}
339    }
340
341    return (False);
342}
343
344/*
345 * Function:
346 *	XawDialogGetValuesHook
347 *
348 * Parameters:
349 *	w	 - Dialog Widget
350 *	args	 - argument list
351 *	num_args - number of args
352 *
353 * Description:
354 *	This is a get values hook routine that gets the values in the dialog.
355 */
356static void
357XawDialogGetValuesHook(Widget w, ArgList args, Cardinal *num_args)
358{
359    Arg a[1];
360    char * s;
361    DialogWidget src = (DialogWidget)w;
362    unsigned int i;
363
364    for (i = 0; i < *num_args; i++)
365	if (streq(args[i].name, XtNvalue)) {
366	    XtSetArg(a[0], XtNstring, &s);
367	    XtGetValues(src->dialog.valueW, a, 1);
368	    *((char **)args[i].value) = s;
369	}
370	else if (streq(args[i].name, XtNlabel)) {
371	    XtSetArg(a[0], XtNlabel, &s);
372	    XtGetValues(src->dialog.labelW, a, 1);
373	    *((char **)args[i].value) = s;
374	}
375}
376
377/*
378 * Function:
379 *	CreateDialogValueWidget
380 *
381 * Parameters:
382 *	w - dialog widget
383 *
384 * Description:
385 *	Creates the dialog widgets value widget.
386 *
387 * Note
388 *	Must be called only when w->dialog.value is non-nil
389 */
390static void
391CreateDialogValueWidget(Widget w)
392{
393    DialogWidget dw = (DialogWidget)w;
394    Arg arglist[10];
395    Cardinal num_args = 0;
396
397    XtSetArg(arglist[num_args], XtNstring, dw->dialog.value);     num_args++;
398    XtSetArg(arglist[num_args], XtNresizable, True);              num_args++;
399    XtSetArg(arglist[num_args], XtNeditType, XawtextEdit);        num_args++;
400    XtSetArg(arglist[num_args], XtNfromVert, dw->dialog.labelW);  num_args++;
401    XtSetArg(arglist[num_args], XtNleft, XtChainLeft);            num_args++;
402    XtSetArg(arglist[num_args], XtNright, XtChainRight);          num_args++;
403
404    dw->dialog.valueW = XtCreateWidget("value", asciiTextWidgetClass,
405				       w, arglist, num_args);
406
407    /* if the value widget is being added after buttons,
408     * then the buttons need new layout constraints
409     */
410    if (dw->composite.num_children > 1) {
411	WidgetList children = dw->composite.children;
412	Widget *childP;
413
414        for (childP = children + dw->composite.num_children - 1;
415	     childP >= children; childP-- ) {
416	    if (*childP == dw->dialog.labelW || *childP == dw->dialog.valueW)
417		continue;
418
419	    if (XtIsManaged(*childP) &&
420	        XtIsSubclass(*childP, commandWidgetClass)) {
421		((DialogConstraints)(*childP)->core.constraints)->
422		    form.vert_base = dw->dialog.valueW;
423	    }
424	}
425    }
426    XtManageChild(dw->dialog.valueW);
427
428    /*
429     * Value widget gets the keyboard focus
430     */
431    XtSetKeyboardFocus(w, dw->dialog.valueW);
432    dw->dialog.value = MAGIC_VALUE;
433}
434
435void
436XawDialogAddButton(Widget dialog, _Xconst char* name, XtCallbackProc function,
437		   XtPointer param)
438{
439    /*
440     * Correct Constraints are all set in ConstraintInitialize()
441     */
442    Widget button;
443
444    button = XtCreateManagedWidget(name, commandWidgetClass, dialog, NULL, 0);
445
446    if (function != NULL)	/* don't add NULL callback func */
447	XtAddCallback(button, XtNcallback, function, param);
448}
449
450char *
451XawDialogGetValueString(Widget w)
452{
453    Arg args[1];
454    char *value;
455
456    XtSetArg(args[0], XtNstring, &value);
457    XtGetValues(((DialogWidget)w)->dialog.valueW, args, 1);
458
459    return(value);
460}
461