1 /*
2 * Motif Tools Library, Version 3.1
3 * $Id: Chooser.c,v 1.1.1.1 2001/02/10 13:41:19 motiftools Exp $
4 *
5 * Written by David Flanagan.
6 * Copyright (c) 1992-2001 by David Flanagan.
7 * All Rights Reserved. See the file COPYRIGHT for details.
8 * This is open source software. See the file LICENSE for details.
9 * There is no warranty for this software. See NO_WARRANTY for details.
10 *
11 * $Log: Chooser.c,v $
12 * Revision 1.1.1.1 2001/02/10 13:41:19 motiftools
13 * Initial import of Xmt310 to CVS
14 *
15 *
16 */
17
18 #include <stdio.h>
19 #include <string.h>
20 #include <Xmt/XmtP.h>
21 #include <Xmt/ChooserP.h>
22 #include <Xmt/Symbols.h>
23 #include <Xmt/Converters.h>
24 #include <Xmt/WidgetType.h>
25 #include <Xmt/Layout.h> /* for XmtNlayoutSensitive resource */
26 #include <Xm/Label.h>
27 #include <Xm/CascadeB.h>
28 #include <Xm/PushB.h>
29 #include <Xm/ToggleB.h>
30 #include <Xm/List.h>
31 #if XmVersion >= 2000
32 #include <Xm/ComboBox.h>
33 #endif
34
35 static XtResource resources[] = {
36 {XmtNchooserType, XmtCChooserType, XmtRXmtChooserType,
37 sizeof(XmtChooserType), XtOffsetOf(XmtChooserRec, chooser.type),
38 XtRImmediate, (XtPointer)XmtChooserRadioBox},
39 {XmtNnumItems, XmtCNumItems, XtRInt,
40 sizeof(int), XtOffsetOf(XmtChooserRec, chooser.num_items),
41 XtRImmediate, (XtPointer) -1},
42 {XmtNstrings, XmtCStrings, XmtRStringList,
43 sizeof(String *), XtOffsetOf(XmtChooserRec, chooser.strings),
44 XmtRStringList, NULL},
45 {XmtNpixmaps, XmtCPixmaps, XmtRPixmapList,
46 sizeof(Pixmap *), XtOffsetOf(XmtChooserRec, chooser.pixmaps),
47 XmtRPixmapList, NULL},
48 {XmtNselectPixmaps, XmtCSelectPixmaps, XmtRPixmapList,
49 sizeof(Pixmap *), XtOffsetOf(XmtChooserRec, chooser.select_pixmaps),
50 XmtRPixmapList, NULL},
51 {XmtNinsensitivePixmaps, XmtCInsensitivePixmaps, XmtRPixmapList,
52 sizeof(Pixmap *), XtOffsetOf(XmtChooserRec, chooser.insensitive_pixmaps),
53 XmtRPixmapList, NULL},
54 {XmtNvalues, XmtCValues, XtRPointer,
55 sizeof(XtPointer), XtOffsetOf(XmtChooserRec, chooser.values),
56 XtRImmediate, NULL},
57 {XmtNvalueStrings, XmtCValueStrings, XmtRStringList,
58 sizeof(String *), XtOffsetOf(XmtChooserRec, chooser.value_strings),
59 XmtRStringList, NULL},
60 {XmtNvalueType, XmtCValueType, XtRString,
61 sizeof(String), XtOffsetOf(XmtChooserRec, chooser.value_type),
62 XtRString, NULL},
63 {XmtNvalueSize, XmtCValueSize, XtRInt,
64 sizeof(int), XtOffsetOf(XmtChooserRec, chooser.value_size),
65 XtRImmediate, (XtPointer) 0},
66 {XmtNfontList, XmCFontList, XmRFontList,
67 sizeof(XmFontList), XtOffsetOf(XmtChooserRec, chooser.font_list),
68 XtRImmediate, NULL},
69 #if XmVersion >= 2000
70 {XmtNrenderTable, XmCRenderTable, XmRRenderTable,
71 sizeof(XmRenderTable), XtOffsetOf(XmtChooserRec, chooser.render_table),
72 XtRImmediate, (XtPointer) NULL},
73 #endif
74 {XmtNvisibleItems, XmtCVisibleItems, XtRInt,
75 sizeof(int), XtOffsetOf(XmtChooserRec, chooser.visible_items),
76 XtRImmediate, (XtPointer) 8},
77 {XmtNstate, XmtCState, XtRInt,
78 sizeof(int), XtOffsetOf(XmtChooserRec, chooser.state),
79 XtRImmediate, (XtPointer) 0},
80 {XmtNsymbolName, XmtCSymbolName, XtRString,
81 sizeof(String), XtOffsetOf(XmtChooserRec, chooser.symbol_name),
82 XtRImmediate, NULL},
83 {XmtNlabelType, XmtCLabelType, XmRLabelType,
84 sizeof(unsigned char), XtOffsetOf(XmtChooserRec, chooser.label_type),
85 XtRImmediate, (XtPointer)XmSTRING},
86 {XmtNvalueChangedCallback, XtCCallback, XtRCallback,
87 sizeof(XtCallbackList), XtOffsetOf(XmtChooserRec, chooser.callback),
88 XtRCallback, NULL},
89 {XmtNitemWidgets, XtCReadOnly, XtRWidgetList,
90 sizeof(WidgetList), XtOffsetOf(XmtChooserRec, chooser.item_widgets),
91 XtRImmediate, NULL},
92 /*
93 * override defaults for some RowColumn resources
94 */
95 {XmNadjustLast, XmCAdjustLast, XtRBoolean,
96 sizeof(Boolean), XtOffsetOf(XmtChooserRec, row_column.adjust_last),
97 XtRImmediate, (XtPointer) False},
98 {XmNpacking, XmCPacking, XmRPacking,
99 sizeof(unsigned char), XtOffsetOf(XmtChooserRec, row_column.packing),
100 XtRImmediate, (XtPointer) XmPACK_COLUMN},
101
102 };
103
104 #if NeedFunctionPrototypes
105 static void ClassInitialize(void);
106 static void ClassPartInitialize(WidgetClass);
107 static void Initialize(Widget, Widget, ArgList, Cardinal *);
108 static void Destroy(Widget);
109 static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *);
110 #else
111 static void ClassInitialize();
112 static void ClassPartInitialize();
113 static void Initialize();
114 static void Destroy();
115 static Boolean SetValues();
116 #endif
117
118 #define Superclass (&xmRowColumnClassRec)
119
120 externaldef(xmtchooserclassrec) XmtChooserClassRec xmtChooserClassRec = { {
121 /* core_class fields */
122 /* superclass */ (WidgetClass) Superclass,
123 /* class_name */ "XmtChooser",
124 /* widget_size */ sizeof(XmtChooserRec),
125 /* class_initialize */ ClassInitialize,
126 /* class_part_init */ ClassPartInitialize,
127 /* class_inited */ FALSE,
128 /* initialize */ Initialize,
129 /* initialize_hook */ NULL,
130 /* realize */ XtInheritRealize,
131 /* actions */ NULL,
132 /* num_actions */ 0,
133 /* resources */ resources,
134 /* num_resources */ XtNumber(resources),
135 /* xrm_class */ NULLQUARK,
136 /* compress_motion */ TRUE,
137 /* compress_exposure */ XtExposeCompressMaximal,
138 /* compress_enterleave*/ FALSE,
139 /* visible_interest */ FALSE,
140 /* destroy */ Destroy,
141 /* resize */ XtInheritResize,
142 /* expose */ XtInheritExpose,
143 /* set_values */ SetValues,
144 /* set_values_hook */ NULL,
145 /* set_values_almost */ XtInheritSetValuesAlmost,
146 /* get_values_hook */ NULL,
147 /* accept_focus */ XtInheritAcceptFocus,
148 /* version */ XtVersion,
149 /* callback_private */ NULL,
150 /* tm_table */ XtInheritTranslations,
151 /* query_geometry */ XtInheritQueryGeometry,
152 /* display_accelerator*/ XtInheritDisplayAccelerator,
153 /* extension */ NULL
154 },
155 { /* composite_class fields */
156 /* geometry_manager */ XtInheritGeometryManager,
157 /* change_managed */ XtInheritChangeManaged,
158 /* insert_child */ XtInheritInsertChild,
159 /* delete_child */ XtInheritDeleteChild,
160 /* extension */ NULL
161 },
162 { /* constraint_class fields */
163 /* resource list */ NULL,
164 /* num resources */ 0,
165 /* constraint size */ sizeof(XmRowColumnConstraintRec),
166 /* init proc */ NULL,
167 /* destroy proc */ NULL,
168 /* set values proc */ NULL,
169 /* extension */ NULL
170 },
171 { /* manager_class */
172 /* translations */ XtInheritTranslations,
173 /* syn_resources */ NULL,
174 /* num_syn_resources */ 0,
175 /* syn_cont_resources */ NULL,
176 /* num_syn_cont_resources */0,
177 /* parent_process */ XmInheritParentProcess,
178 /* extension */ NULL
179 },
180 { /* row column class record */
181 /* proc to interface with widgets */ XmInheritMenuProc,
182 /* proc to arm&activate menu */ XmInheritArmAndActivate,
183 /* traversal handler */ XmInheritMenuTraversalProc,
184 /* extension */ NULL,
185 },
186 { /* XmtChooser */
187 /* extension */ NULL
188 }
189 };
190
191 externaldef(xmtchooserwidgetclass) WidgetClass xmtChooserWidgetClass =
192 (WidgetClass)&xmtChooserClassRec;
193
194
195 #if NeedFunctionPrototypes
SetStateOnWidgets(XmtChooserWidget cw)196 static void SetStateOnWidgets(XmtChooserWidget cw)
197 #else
198 static void SetStateOnWidgets(cw)
199 XmtChooserWidget cw;
200 #endif
201 {
202 int i, bit;
203
204 /*
205 * update the subwidgets to reflect the current state. Don't touch
206 * the symbol value or call callbacks.
207 */
208
209 if (cw->chooser.num_items == 0) return;
210
211 if (cw->chooser.type == XmtChooserRadioList) {
212 XmListDeselectAllItems(cw->chooser.list);
213 XmListSelectPos(cw->chooser.list, cw->chooser.state+1, False);
214 }
215 #if XmVersion >= 2000
216 else if (cw->chooser.type == XmtChooserComboBox) {
217 XtVaSetValues(cw->chooser.combo_box,
218 XmNselectedPosition, cw->chooser.state+1,
219 NULL);
220 }
221 #endif
222 else if (cw->chooser.type == XmtChooserCheckList) {
223 XmListDeselectAllItems(cw->chooser.list);
224 for(i=0, bit = 1; i < cw->chooser.num_items; i++, bit = bit << 1)
225 if (cw->chooser.state & bit)
226 XmListSelectPos(cw->chooser.list, i+1, False);
227 }
228 else if (cw->chooser.type == XmtChooserOption) {
229 /* XXX this may not work before Motif 1.1.4 */
230 XtVaSetValues(cw->chooser.option,
231 XmNmenuHistory,
232 cw->chooser.item_widgets[cw->chooser.state],
233 NULL);
234 }
235 else if ((cw->chooser.type == XmtChooserCheckBox) ||
236 (cw->chooser.type == XmtChooserCheckPalette)) {
237 for(i=0, bit = 1; i < cw->chooser.num_items; i++, bit = bit << 1)
238 if (cw->chooser.state & bit)
239 XmToggleButtonSetState(cw->chooser.item_widgets[i],
240 True, False);
241 else
242 XmToggleButtonSetState(cw->chooser.item_widgets[i],
243 False, False);
244 }
245 else if ((cw->chooser.type == XmtChooserRadioBox) ||
246 (cw->chooser.type == XmtChooserRadioPalette)) {
247 for(i=0; i < cw->chooser.num_items; i++)
248 XmToggleButtonSetState(cw->chooser.item_widgets[i], False, False);
249 XmToggleButtonSetState(cw->chooser.item_widgets[cw->chooser.state],
250 True, False);
251 }
252 else { /* a button box; it doesn't have state */
253 ;
254 }
255 }
256
257 /* ARGSUSED */
258 #if NeedFunctionPrototypes
ChooserCallback(Widget w,XtPointer tag,XtPointer data)259 static void ChooserCallback(Widget w, XtPointer tag, XtPointer data)
260 #else
261 static void ChooserCallback(w, tag, data)
262 Widget w;
263 XtPointer tag;
264 XtPointer data;
265 #endif
266 {
267 XmtChooserWidget cw = (XmtChooserWidget) tag;
268 XmListCallbackStruct *listdata = (XmListCallbackStruct *) data;
269 #if XmVersion >= 2000
270 XmComboBoxCallbackStruct *combodata = (XmComboBoxCallbackStruct *) data;
271 #endif
272 XmtChooserCallbackStruct call_data;
273 int i;
274
275 /*
276 * Figure out and record the new state of the Chooser.
277 * Enforce RadioBox behavior where required.
278 * Enforce sensitivity where required (in list widgets).
279 * Update the symbol value, if a symbol was specified.
280 * Invoke the callback that was registered with this Chooser, if it exists.
281 */
282
283 /*
284 * if a list, check sensitivity. If the item that was
285 * clicked on is insensitive, restore the old state and return
286 */
287 if ((cw->chooser.type == XmtChooserRadioList) ||
288 (cw->chooser.type == XmtChooserCheckList)) {
289 if (cw->chooser.insensitive & (1 << (listdata->item_position-1))) {
290 SetStateOnWidgets(cw);
291 return;
292 }
293 }
294 #if XmVersion >= 2000
295 else if (cw->chooser.type == XmtChooserComboBox) {
296 if (cw->chooser.insensitive & (1 << (combodata->item_position-1))) {
297 SetStateOnWidgets(cw);
298 return;
299 }
300 }
301 #endif
302
303 if (cw->chooser.type == XmtChooserRadioList) {
304 /* list positions start numbering from 1 */
305 call_data.item = call_data.state = cw->chooser.state =
306 listdata->item_position - 1;
307 }
308 #if XmVersion >= 2000
309 else if (cw->chooser.type == XmtChooserComboBox) {
310 /* list positions start numbering from 1 */
311 call_data.item = call_data.state = cw->chooser.state =
312 combodata->item_position - 1;
313 }
314 #endif
315 else if (cw->chooser.type == XmtChooserCheckList) {
316 cw->chooser.state = 0;
317 for(i=0; i < listdata->selected_item_count; i++)
318 cw->chooser.state |= (1<<(listdata->selected_item_positions[i]-1));
319 call_data.state = cw->chooser.state;
320 call_data.item = listdata->item_position;
321 }
322 else {
323 /* figure out which button was pressed */
324 for(i = 0; i < cw->chooser.num_items; i++)
325 if (cw->chooser.item_widgets[i] == w) break;
326 if (i == cw->chooser.num_items) return; /* just in case */
327 call_data.item = i;
328 if ((cw->chooser.type == XmtChooserCheckBox) ||
329 (cw->chooser.type == XmtChooserCheckPalette)) {
330 cw->chooser.state ^= (1 << i);
331 call_data.state = cw->chooser.state;
332 }
333 else if ((cw->chooser.type == XmtChooserRadioBox) ||
334 (cw->chooser.type == XmtChooserRadioPalette)) {
335 /*
336 * if user clicked on an already selected item, reselect it
337 * otherwise unselect the old selected item.
338 */
339 if (cw->chooser.state == i)
340 XmToggleButtonSetState(w, True, False);
341 else
342 XmToggleButtonSetState(cw->chooser.item_widgets
343 [cw->chooser.state],
344 False,False);
345 cw->chooser.state = call_data.state = i;
346 }
347 else if (cw->chooser.type == XmtChooserOption)
348 cw->chooser.state = call_data.state = i;
349 else /* button box */
350 call_data.state = -1;
351 }
352
353 /*
354 * update the symbol value, if we have one.
355 * set a flag that tells our own symbol notify callback that the
356 * widgets are already in the correct state and it need not do
357 * anything.
358 */
359 if (cw->chooser.symbol) {
360 cw->chooser.ignore_symbol_notify = True;
361 XmtSymbolSetValue(cw->chooser.symbol, (XtArgVal)cw->chooser.state);
362 cw->chooser.ignore_symbol_notify = False;
363 }
364
365 /*
366 * figure out the call_data.valuep, if we have values set.
367 */
368 if (cw->chooser.values)
369 call_data.valuep = (XtPointer) &((char *)cw->chooser.values)
370 [call_data.item * cw->chooser.value_size];
371 else
372 call_data.valuep = NULL;
373
374 /* invoke the callbacks registered for this Chooser */
375 XtCallCallbackList((Widget)cw, cw->chooser.callback,(XtPointer)&call_data);
376 }
377
378 #if NeedFunctionPrototypes
SetStateOnSymbol(XmtChooserWidget cw)379 static void SetStateOnSymbol(XmtChooserWidget cw)
380 #else
381 static void SetStateOnSymbol(cw)
382 XmtChooserWidget cw;
383 #endif
384 {
385 /*
386 * set the symbol state. This will cause the notify callbacks to
387 * be invoked, which in our case will call SetStateOnWidgets.
388 * So if you call this function, don't call SetStateOnWidgets.
389 */
390 if (cw->chooser.symbol)
391 XmtSymbolSetValue(cw->chooser.symbol, (XtArgVal)cw->chooser.state);
392 }
393
394
395 /* ARGSUSED */
396 #if NeedFunctionPrototypes
ValueChanged(XmtSymbol s,XtPointer tag,XtArgVal value)397 static void ValueChanged(XmtSymbol s, XtPointer tag, XtArgVal value)
398 #else
399 static void ValueChanged(s, tag, value)
400 XmtSymbol s;
401 XtPointer tag;
402 XtArgVal value;
403 #endif
404 {
405 XmtChooserWidget cw = (XmtChooserWidget)tag;
406
407 /*
408 * update the widget's internal and displayed state when the symbol value
409 * changes from underneath us. Note that we do not call the
410 * valueChangedCallback; this is only called when the user changes the
411 * state by interacting with the widget. Also, it prevents us from
412 * getting into a loop.
413 *
414 * We don't do anything if the ignore flag is set. This is the case
415 * when the user interacts with the widget to change the state--the widget
416 * state and the subwidgets are already correct, the symbol is updated
417 * and the notify callbacks are called to notify anyone else who cares
418 * about the symbol.
419 */
420
421 if (cw->chooser.ignore_symbol_notify) return;
422
423 cw->chooser.state = (int) value;
424 SetStateOnWidgets(cw);
425 }
426
427
428 #if NeedFunctionPrototypes
BindSymbol(XmtChooserWidget cw)429 static void BindSymbol(XmtChooserWidget cw)
430 #else
431 static void BindSymbol(cw)
432 XmtChooserWidget cw;
433 #endif
434 {
435 if (cw->chooser.symbol_name) {
436 cw->chooser.symbol = XmtLookupSymbol(cw->chooser.symbol_name);
437 if (cw->chooser.symbol) {
438 if (XmtSymbolSize(cw->chooser.symbol)!=sizeof(cw->chooser.state)) {
439 XmtWarningMsg("XmtChooser", "symbolSize",
440 "%s: symbol '%s' has wrong size;\n\tshould be int.",
441 XtName((Widget)cw), cw->chooser.symbol_name);
442 cw->chooser.symbol = NULL;
443 }
444 else {
445 XmtSymbolAddCallback(cw->chooser.symbol,
446 ValueChanged, (XtPointer)cw);
447 XmtSymbolGetValue(cw->chooser.symbol,
448 (XtArgVal*) &cw->chooser.state);
449 }
450 }
451 else {
452 XmtWarningMsg("XmtChooser", "badSymbol",
453 "%s: symbol '%s' is undefined.",
454 XtName((Widget)cw), cw->chooser.symbol_name);
455 }
456 }
457 else
458 cw->chooser.symbol = NULL;
459 }
460
461
462 #if NeedFunctionPrototypes
ReleaseSymbol(XmtChooserWidget cw)463 static void ReleaseSymbol(XmtChooserWidget cw)
464 #else
465 static void ReleaseSymbol(cw)
466 XmtChooserWidget cw;
467 #endif
468 {
469 if (cw->chooser.symbol) {
470 XmtSymbolRemoveCallback(cw->chooser.symbol,
471 ValueChanged, (XtPointer)cw);
472 cw->chooser.symbol = NULL;
473 }
474 }
475
476 #if NeedFunctionPrototypes
CheckType(XmtChooserWidget cw)477 static void CheckType(XmtChooserWidget cw)
478 #else
479 static void CheckType(cw)
480 XmtChooserWidget cw;
481 #endif
482 {
483 /* if this is a check box, then we can't have values */
484 if ((cw->chooser.type == XmtChooserCheckBox) ||
485 (cw->chooser.type == XmtChooserCheckPalette) ||
486 (cw->chooser.type == XmtChooserCheckList)) {
487 XmtWarningMsg("XmtChooser", "badType",
488 "%s: XmtNvalues and XmtNvalueStrings resources ignored\n\twhen XmtNchooserType is CheckBox, CheckPalette or CheckList",
489 XtName((Widget)cw));
490 cw->chooser.values = NULL;
491 cw->chooser.value_strings = NULL;
492 return;
493 }
494
495 /* also check that value type and size are set */
496 if (!cw->chooser.value_type || !cw->chooser.value_size) {
497 XmtWarningMsg("XmtChooser", "badValues",
498 "%s: can't set XmtNvalues or XmtNvalueStrings without\n\talso setting XmtNvalueType and XmtNvalueSize resources",
499 XtName((Widget)cw));
500 cw->chooser.values = NULL;
501 cw->chooser.value_strings = NULL;
502 }
503 }
504
505 #if NeedFunctionPrototypes
CopyValues(XmtChooserWidget cw)506 static void CopyValues(XmtChooserWidget cw)
507 #else
508 static void CopyValues(cw)
509 XmtChooserWidget cw;
510 #endif
511 {
512 char *values;
513 int size = cw->chooser.num_items * cw->chooser.value_size;
514
515 /* if XmtNvalues is set, be sure to ignore XmtNvalueStrings */
516 cw->chooser.value_strings = NULL;
517
518 values = XtMalloc(size);
519 memcpy(values, (char *)cw->chooser.values, size);
520 cw->chooser.values = (XtPointer) values;
521 }
522
523 #if NeedFunctionPrototypes
ConvertValueStrings(XmtChooserWidget cw)524 static void ConvertValueStrings(XmtChooserWidget cw)
525 #else
526 static void ConvertValueStrings(cw)
527 XmtChooserWidget cw;
528 #endif
529 {
530 char *values;
531 XrmValue from, to;
532 Boolean status;
533 int i;
534
535 values = XtCalloc(cw->chooser.num_items, cw->chooser.value_size);
536
537 /* String values are a special case; no conversion required */
538 if (strcmp(cw->chooser.value_type, XtRString) == 0) {
539 for(i=0; i < cw->chooser.num_items; i++)
540 ((String *)values)[i] = cw->chooser.value_strings[i];
541 }
542 else{
543 for(i=0; i < cw->chooser.num_items; i++) {
544 from.addr = cw->chooser.value_strings[i];
545 from.size = strlen(cw->chooser.value_strings[i]) + 1;
546 to.addr = &values[i * cw->chooser.value_size];
547 to.size = cw->chooser.value_size;
548 status = XtConvertAndStore((Widget)cw, XtRString, &from,
549 cw->chooser.value_type, &to);
550 if (!status) {
551 XmtWarningMsg("XmtChooser", "convert",
552 "%s: conversion failed for item %d of XmtNvalueStrings",
553 XtName((Widget)cw), i);
554 }
555 else if (to.size != cw->chooser.value_size) {
556 XmtWarningMsg("XmtChooser", "badSize",
557 "%s: size of converted values not equal to XmtNvalueSize",
558 XtName((Widget)cw));
559 XtFree(values);
560 values = NULL;
561 break;
562 }
563 }
564 }
565
566 cw->chooser.values = values;
567 /*
568 * we set value_strings to NULL, because we're not making a copy of them,
569 * and so we'll notice a change if the programmer specifies the same
570 * array with different values in it. This means that querying this
571 * resource doesn't make sense.
572 */
573 cw->chooser.value_strings = NULL;
574 }
575
576
577 #if NeedFunctionPrototypes
ClassInitialize(void)578 static void ClassInitialize(void)
579 #else
580 static void ClassInitialize()
581 #endif
582 {
583 static String names[] = {
584 "ButtonBox", "CheckBox", "CheckList", "CheckPalette",
585 #if XmVersion >= 2000
586 "ComboBox",
587 #endif
588 "Option", "RadioBox", "RadioList", "RadioPalette"
589 };
590 static int values[] = {
591 XmtChooserButtonBox, XmtChooserCheckBox, XmtChooserCheckList,
592 XmtChooserCheckPalette,
593 #if XmVersion >= 2000
594 XmtChooserComboBox,
595 #endif
596 XmtChooserOption, XmtChooserRadioBox,
597 XmtChooserRadioList, XmtChooserRadioPalette
598 };
599 static String prefixes[] = {"Xmt", "Chooser", NULL};
600
601 XmtRegisterStringListConverter();
602 XmtRegisterEnumConverter(XmtRXmtChooserType, names, values,
603 XtNumber(names), prefixes);
604 }
605
606 #if NeedFunctionPrototypes
ClassPartInitialize(WidgetClass subclass)607 static void ClassPartInitialize(WidgetClass subclass)
608 #else
609 static void ClassPartInitialize(subclass)
610 WidgetClass subclass;
611 #endif
612 {
613 XmtChooserWidgetClass sub = (XmtChooserWidgetClass)subclass;
614 XmtChooserWidgetClass sup =
615 (XmtChooserWidgetClass)sub->core_class.superclass;
616
617 /*
618 * the XmtChooser widget doesn't have any class fields that need
619 * inheritance, but the XmRowColumn does, and that widget does not
620 * handle the inheritance itself. So we do it here.
621 */
622 #define inherit(field) \
623 if ((XtProc)sub->field == _XtInherit) sub->field = sup->field
624
625 inherit(row_column_class.menuProcedures);
626 inherit(row_column_class.armAndActivate);
627 inherit(row_column_class.traversalHandler);
628
629 #undef inherit
630 }
631
632 /* ARGSUSED */
633 #if NeedFunctionPrototypes
Initialize(Widget request,Widget init,ArgList arglist,Cardinal * num_args)634 static void Initialize(Widget request, Widget init,
635 ArgList arglist, Cardinal *num_args)
636 #else
637 static void Initialize(request, init, arglist, num_args)
638 Widget request;
639 Widget init;
640 ArgList arglist;
641 Cardinal *num_args;
642 #endif
643 {
644 XmtChooserWidget nw = (XmtChooserWidget) init;
645 String *array;
646 Pixmap *p;
647 XmString *item_labels = NULL;
648 char namebuf[200];
649 Arg args[10];
650 int i,j;
651 #if XmVersion >= 2000
652 int len;
653 short num_columns;
654 #endif
655
656 /* lists can't have pixmaps */
657 #if XmVersion < 2000
658 if ((nw->chooser.label_type == XmPIXMAP) &&
659 ((nw->chooser.type == XmtChooserRadioList) ||
660 (nw->chooser.type == XmtChooserCheckList))) {
661 #else /* Motif 2.0 or later */
662 if ((nw->chooser.label_type == XmPIXMAP) &&
663 ((nw->chooser.type == XmtChooserRadioList) ||
664 (nw->chooser.type == XmtChooserCheckList) ||
665 (nw->chooser.type == XmtChooserComboBox))) {
666 #endif
667 nw->chooser.label_type = XmSTRING;
668 XmtWarningMsg("XmtChooser", "pixmapType",
669 "%s: XmtNlabelType must be XmSTRING for XmList types.",
670 XtName((Widget)nw));
671 }
672
673 /*
674 * Palettes have zero spacing. This is a dynamic default resource,
675 * so we can't just override it. RowCol may do some special processing
676 * on it, so we don't just set it directly.
677 */
678 if ((nw->chooser.type == XmtChooserRadioPalette) ||
679 (nw->chooser.type == XmtChooserCheckPalette))
680 XtVaSetValues(init, XmNspacing, 0, NULL);
681
682 #if XmVersion < 2000
683 /* get the default font from an ancestor font list if none set. */
684 if (nw->chooser.font_list == NULL)
685 nw->chooser.font_list = _XmGetDefaultFontList(init, XmBUTTON_FONTLIST);
686
687 /* make a private copy of the font list */
688 nw->chooser.font_list = XmFontListCopy(nw->chooser.font_list);
689
690 #else /* Motif 2.0 or later */
691
692 if (!nw->chooser.render_table) {
693 if (nw->chooser.font_list) {
694 /*
695 * There is a fontList, so copy it to the renderTable.
696 * NOTE: This code relies on the fact that there is no
697 * disitinction between a fontList and a renderTable
698 * in Motif 2.0.
699 */
700 nw->chooser.render_table = XmFontListCopy(nw->chooser.font_list);
701 }
702 else {
703 /*
704 * Nothing was specified, so look up the default
705 * renderTable.
706 */
707 nw->chooser.render_table =
708 XmeGetDefaultRenderTable(init, XmBUTTON_FONTLIST);
709
710 /* Make a copy of the renderTable. */
711 nw->chooser.render_table =
712 XmRenderTableCopy(nw->chooser.render_table, NULL, 0);
713 }
714 }
715 else {
716 /* Make a copy of the renderTable. */
717 nw->chooser.render_table =
718 XmRenderTableCopy(nw->chooser.render_table, NULL, 0);
719 }
720 #endif
721
722 /*
723 * if we're insensitve, set layoutSensitive, in case we're a child
724 * of a layout and have a caption
725 */
726 if (!nw->core.sensitive || !nw->core.ancestor_sensitive)
727 XtVaSetValues(init, XmtNlayoutSensitive, False, NULL);
728
729 /*
730 * Count the strings or pixmaps.
731 * The strings resource may be NULL terminated at this point, or it may
732 * not be. If num_items is -1 (ie. unspecified) then it had better be
733 * NULL-terminated. The resource converter delivers a NULL-terminated
734 * array, but most programmers will probably use counted arrays. It is
735 * also possible that strings is NULL-terminated at less than num_items.
736 * So figure out num_items.
737 */
738 if (nw->chooser.label_type == XmSTRING)
739 array = nw->chooser.strings;
740 else
741 array = (String *)nw->chooser.pixmaps;
742
743 if (array != NULL) {
744 if (nw->chooser.num_items == -1) /* if unspecified look for a NULL */
745 for(i=0; array[i]; i++);
746 else /* if specified, look for a NULL anyway */
747 for(i=0; i < nw->chooser.num_items && array[i]; i++);
748 nw->chooser.num_items = i;
749 }
750 else /* if no strings are specified */
751 nw->chooser.num_items = 0;
752
753 /*
754 * Now copy the array of strings and the arrays of pixmaps.
755 * We copy all arrays, regardless of mode.
756 * We copy the array, but not the strings in it.
757 * While copying the selected and insensitive pixmaps we count them, too.
758 */
759 if (nw->chooser.strings != NULL) {
760 array = (String *)XtMalloc(nw->chooser.num_items*sizeof(String));
761 for(i=0; i < nw->chooser.num_items; i++) {
762 if (nw->chooser.strings[i] == NULL) break;
763 array[i] = nw->chooser.strings[i];
764 }
765 for(; i < nw->chooser.num_items; i++) array[i] = NULL;
766 nw->chooser.strings = array;
767 }
768
769 if (nw->chooser.pixmaps != NULL) {
770 p = (Pixmap *)XtMalloc(nw->chooser.num_items*sizeof(Pixmap));
771 for(i=0; i < nw->chooser.num_items; i++) {
772 if (nw->chooser.pixmaps[i] == None) break;
773 p[i] = nw->chooser.pixmaps[i];
774 }
775 for(; i < nw->chooser.num_items; i++) p[i] = XmUNSPECIFIED_PIXMAP;
776 nw->chooser.pixmaps = p;
777 }
778
779 if (nw->chooser.select_pixmaps != NULL) {
780 p = (Pixmap *)XtMalloc(nw->chooser.num_items*sizeof(Pixmap));
781 for(i=0; i < nw->chooser.num_items; i++) {
782 if (nw->chooser.select_pixmaps[i] == None) break;
783 p[i] = nw->chooser.select_pixmaps[i];
784 }
785 for(; i < nw->chooser.num_items; i++) p[i] = XmUNSPECIFIED_PIXMAP;
786 nw->chooser.select_pixmaps = p;
787 }
788
789 if (nw->chooser.insensitive_pixmaps != NULL) {
790 p = (Pixmap *)XtMalloc(nw->chooser.num_items*sizeof(Pixmap));
791 for(i=0; i < nw->chooser.num_items; i++) {
792 if (nw->chooser.insensitive_pixmaps[i] == None) break;
793 p[i] = nw->chooser.insensitive_pixmaps[i];
794 }
795 for(; i < nw->chooser.num_items; i++) p[i] = XmUNSPECIFIED_PIXMAP;
796 nw->chooser.insensitive_pixmaps = p;
797 }
798
799 /*
800 * if values or valueStrings is set, make sure that the type is okay,
801 * and make sure we have a size and type
802 */
803 if (nw->chooser.values || nw->chooser.value_strings)
804 CheckType(nw);
805
806 /*
807 * if values is set, copy the array.
808 * otherwise, if values is not set, but valueStrings is,
809 * convert the strings, and store in values. We don't copy
810 * valueStrings, because we'll never need to referece it again,
811 * but we set it to NULL, so we can detect when it changes.
812 */
813 if (nw->chooser.values) CopyValues(nw);
814 else if (nw->chooser.value_strings) ConvertValueStrings(nw);
815
816 /* create the label XmStrings in string mode */
817 if (nw->chooser.label_type == XmSTRING) {
818 item_labels = (XmString *)
819 XtMalloc(nw->chooser.num_items*sizeof(XmString));
820 for(i = 0; i < nw->chooser.num_items; i++)
821 item_labels[i] = XmtCreateXmString(nw->chooser.strings[i]);
822 }
823
824 /*
825 * Create the widgets. Option menus are handled separately.
826 */
827 if (nw->chooser.type == XmtChooserOption) {
828 /*
829 * In order to create an Option menu, we have to create the
830 * menu pane first before the cascade button and label.
831 * The menu shell is automatically created, and
832 * its name is not publicly documented.
833 */
834 i = 0;
835 nw->chooser.pane = XmCreatePulldownMenu(init, "pane", NULL, 0);
836 XtSetArg(args[i], XmNsubMenuId, nw->chooser.pane); i++;
837 nw->chooser.option = XmCreateOptionMenu(init, "option", args, i);
838 #if XmVersion >= 1002
839 /*
840 * In Motif 1.2.0, a NULL option label string gives an option menu
841 * with some bogus widget name as the label, so we just unmanage
842 * the label altogether. We don't do this in 1.1.4, because
843 * with ICS 1.1.4, at least, the option menu doesn't shrink; it
844 * continues to allocate space for the label gadget.
845 */
846 XtUnmanageChild(XmOptionLabelGadget(nw->chooser.option));
847 #endif
848 XtManageChild(nw->chooser.option);
849 #if XmVersion < 2000
850 XtVaSetValues(XmOptionButtonGadget(nw->chooser.option),
851 XmNfontList, nw->chooser.font_list,
852 NULL);
853 #else /* Motif 2.0 or later */
854 XtVaSetValues(XmOptionButtonGadget(nw->chooser.option),
855 XmNrenderTable, nw->chooser.render_table,
856 NULL);
857 #endif
858 }
859 else if ((nw->chooser.type == XmtChooserRadioList) ||
860 (nw->chooser.type == XmtChooserCheckList)) {
861 i = 0;
862 XtSetArg(args[i], XmNitems, item_labels); i++;
863 #if XmVersion < 2000
864 XtSetArg(args[i], XmNfontList, nw->chooser.font_list); i++;
865 #else /* Motif 2.0 or later */
866 XtSetArg(args[i], XmNrenderTable, nw->chooser.render_table); i++;
867 #endif
868 XtSetArg(args[i], XmNitemCount, nw->chooser.num_items); i++;
869 XtSetArg(args[i], XmNvisibleItemCount, nw->chooser.visible_items); i++;
870 XtSetArg(args[i], XmNselectionPolicy,
871 ((nw->chooser.type==XmtChooserRadioList)
872 ? XmBROWSE_SELECT : XmMULTIPLE_SELECT)); i++;
873 nw->chooser.list =
874 XmCreateScrolledList(init, "list", args, i);
875 if (nw->chooser.type == XmtChooserRadioList)
876 XtAddCallback(nw->chooser.list, XmNbrowseSelectionCallback,
877 ChooserCallback, (XtPointer) nw);
878 else
879 XtAddCallback(nw->chooser.list, XmNmultipleSelectionCallback,
880 ChooserCallback, (XtPointer) nw);
881
882 XtManageChild(nw->chooser.list);
883 }
884 #if XmVersion >= 2000
885 else if (nw->chooser.type == XmtChooserComboBox) {
886 i = 0;
887 XtSetArg(args[i], XmNitems, item_labels); i++;
888 XtSetArg(args[i], XmNrenderTable, nw->chooser.render_table); i++;
889 XtSetArg(args[i], XmNitemCount, nw->chooser.num_items); i++;
890
891 /*
892 * ComboBoxes look funny with blank space at the bottom, so
893 * if the actual number of items is smaller than the visible
894 * items resource, we override the visible item count.
895 */
896 if (nw->chooser.visible_items > nw->chooser.num_items)
897 nw->chooser.visible_items = nw->chooser.num_items;
898 XtSetArg(args[i], XmNvisibleItemCount, nw->chooser.visible_items); i++;
899
900 XtSetArg(args[i], XmNcomboBoxType, XmDROP_DOWN_LIST); i++;
901 XtSetArg(args[i], XmNmatchBehavior, XmQUICK_NAVIGATE); i++;
902
903 /*
904 * ComboBoxes do not automatically size themselves based on
905 * their contents. We therefore change the width manually to
906 * match the widest item.
907 */
908 num_columns = 0;
909 for(j=0; j < nw->chooser.num_items; j++) {
910 len = strlen(nw->chooser.strings[j]);
911 if (len > num_columns)
912 num_columns = len;
913 }
914 XtSetArg(args[i], XmNcolumns, num_columns); i++;
915
916 nw->chooser.combo_box =
917 XmCreateComboBox(init, "combobox", args, i);
918
919 XtAddCallback(nw->chooser.combo_box, XmNselectionCallback,
920 ChooserCallback, (XtPointer) nw);
921
922 /*
923 * Get the list widget that was created as part of the ComboBox
924 * so we can manipulate it directly.
925 */
926 nw->chooser.list = XmtNameToWidget(nw->chooser.combo_box, "*List");
927
928 XtManageChild(nw->chooser.combo_box);
929 }
930 #endif
931
932 /* If it is not a List widget, go create the internal buttons */
933 #if XmVersion < 2000
934 if ((nw->chooser.type != XmtChooserRadioList) &&
935 (nw->chooser.type != XmtChooserCheckList)) {
936 #else /* Motif 2.0 or later */
937 if ((nw->chooser.type != XmtChooserRadioList) &&
938 (nw->chooser.type != XmtChooserCheckList) &&
939 (nw->chooser.type != XmtChooserComboBox)) {
940 #endif
941 int ac;
942 Widget parent;
943
944 /* For a menu, parent is pane; otherwise self */
945 if (nw->chooser.type == XmtChooserOption)
946 parent = nw->chooser.pane;
947 else
948 parent = (Widget) nw;
949
950 /* set up the fixed arguments */
951 i = 0;
952 XtSetArg(args[i], XmNlabelType, nw->chooser.label_type); i++;
953 #if XmVersion < 2000
954 XtSetArg(args[i], XmNfontList, nw->chooser.font_list); i++;
955 #else /* Motif 2.0 or later */
956 XtSetArg(args[i], XmNrenderTable, nw->chooser.render_table); i++;
957 #endif
958 if ((nw->chooser.type != XmtChooserButtonBox) &&
959 (nw->chooser.type != XmtChooserOption)) {
960 XtSetArg(args[i], XmNset, False); i++;
961 if (nw->chooser.type == XmtChooserCheckBox) {
962 XtSetArg(args[i], XmNindicatorType, XmN_OF_MANY); i++;
963 }
964 else if (nw->chooser.type == XmtChooserRadioBox) {
965 #if XmVersion < 2000
966 XtSetArg(args[i], XmNindicatorType, XmONE_OF_MANY); i++;
967 #else /* Motif 2.0 or later */
968 Boolean enable_toggle_visual;
969 XtVaGetValues(XmGetXmDisplay(XtDisplay((Widget) nw)),
970 XmNenableToggleVisual, &enable_toggle_visual,
971 NULL);
972
973 if (!enable_toggle_visual) {
974 XtSetArg(args[i], XmNindicatorType, XmONE_OF_MANY); i++;
975 }
976 else {
977 XtSetArg(args[i], XmNindicatorType, XmONE_OF_MANY_ROUND);
978 i++;
979 }
980 #endif
981 }
982 else if ((nw->chooser.type == XmtChooserRadioPalette) ||
983 (nw->chooser.type == XmtChooserCheckPalette)) {
984 XtSetArg(args[i], XmNindicatorOn, False); i++;
985 XtSetArg(args[i], XmNshadowThickness, 2); i++;
986 /* XXX shadow thickness should not be hardcoded. */
987 }
988 }
989
990 /* remember the number of fixed arguments */
991 ac = i;
992
993 /* create an array to hold the widgets we create */
994 nw->chooser.item_widgets = (Widget *)
995 XtMalloc(nw->chooser.num_items * sizeof(Widget));
996
997 /* set up the label arg(s) and create the widgets */
998 for(j = 0; j < nw->chooser.num_items; j++) {
999 i = ac;
1000 sprintf(namebuf, "item%d", j);
1001 if (nw->chooser.label_type == XmSTRING) {
1002 XtSetArg(args[i], XmNlabelString, item_labels[j]);
1003 i++;
1004 }
1005 else {
1006 XtSetArg(args[i], XmNlabelPixmap, nw->chooser.pixmaps[j]); i++;
1007 if (nw->chooser.select_pixmaps) {
1008 XtSetArg(args[i], XmNselectPixmap,
1009 nw->chooser.select_pixmaps[j]);
1010 i++;
1011 }
1012 if (nw->chooser.insensitive_pixmaps) {
1013 XtSetArg(args[i], XmNlabelInsensitivePixmap,
1014 nw->chooser.insensitive_pixmaps[j]);
1015 i++;
1016 }
1017 }
1018 if ((nw->chooser.type == XmtChooserOption) ||
1019 (nw->chooser.type == XmtChooserButtonBox)) {
1020 nw->chooser.item_widgets[j] =
1021 XmCreatePushButton(parent, namebuf, args,i);
1022 XtAddCallback(nw->chooser.item_widgets[j], XmNactivateCallback,
1023 ChooserCallback, (XtPointer)nw);
1024 }
1025 else {
1026 nw->chooser.item_widgets[j] =
1027 XmCreateToggleButton(parent, namebuf, args,i);
1028 XtAddCallback(nw->chooser.item_widgets[j],
1029 XmNvalueChangedCallback,
1030 ChooserCallback, (XtPointer)nw);
1031 }
1032 }
1033 XtManageChildren(nw->chooser.item_widgets, nw->chooser.num_items);
1034 }
1035 else { /* if it is a list */
1036 nw->chooser.item_widgets = NULL;
1037 }
1038
1039 /* free all the item XmStrings */
1040 if (nw->chooser.label_type == XmSTRING) {
1041 for(i = 0; i < nw->chooser.num_items; i++)
1042 XmStringFree(item_labels[i]);
1043 XtFree((char *)item_labels);
1044 }
1045
1046 /*
1047 * if there is a symbol, bind the symbol,
1048 * set up notification, read the initial state,
1049 * and copy the symbol_name.
1050 */
1051 if (nw->chooser.symbol_name) {
1052 nw->chooser.symbol_name = XtNewString(nw->chooser.symbol_name);
1053 BindSymbol(nw);
1054 }
1055 else nw->chooser.symbol = NULL;
1056
1057 /* make the widgets correspond to the initial state */
1058 SetStateOnWidgets(nw);
1059
1060 /* set initial sensitivity */
1061 nw->chooser.insensitive = 0;
1062
1063 /* and do other initialization */
1064 nw->chooser.ignore_symbol_notify = False;
1065 }
1066
1067 #if NeedFunctionPrototypes
Destroy(Widget w)1068 static void Destroy(Widget w)
1069 #else
1070 static void Destroy(w)
1071 Widget w;
1072 #endif
1073 {
1074 XmtChooserWidget cw = (XmtChooserWidget)w;
1075
1076 #if XmVersion < 2000
1077 /* free the font list */
1078 XmFontListFree(cw->chooser.font_list);
1079 #else /* Motif 2.0 or later */
1080 /* free the renderTable */
1081 XmRenderTableFree(cw->chooser.render_table);
1082 #endif
1083
1084 /* free the widget array */
1085 XtFree((char *)cw->chooser.item_widgets);
1086
1087 /* free the arrays, but not the strings themselves */
1088 XtFree((char *)cw->chooser.strings);
1089 XtFree((char *)cw->chooser.pixmaps);
1090 XtFree((char *)cw->chooser.select_pixmaps);
1091 XtFree((char *)cw->chooser.insensitive_pixmaps);
1092 XtFree((char *)cw->chooser.values);
1093
1094 /* free the symbol name */
1095 XtFree(cw->chooser.symbol_name);
1096
1097 /* remove symbol callback and free the symbol, if we have one */
1098 ReleaseSymbol(cw);
1099 }
1100
1101 /* ARGSUSED */
1102 #if NeedFunctionPrototypes
SetValues(Widget current,Widget request,Widget set,ArgList arglist,Cardinal * num_args)1103 static Boolean SetValues(Widget current, Widget request, Widget set,
1104 ArgList arglist, Cardinal *num_args)
1105 #else
1106 static Boolean SetValues(current, request, set, arglist, num_args)
1107 Widget current;
1108 Widget request;
1109 Widget set;
1110 ArgList arglist;
1111 Cardinal *num_args;
1112 #endif
1113 {
1114 XmtChooserWidget cw = (XmtChooserWidget) current;
1115 XmtChooserWidget nw = (XmtChooserWidget) set;
1116 Arg args[5];
1117
1118 if (nw->chooser.type != cw->chooser.type) {
1119 nw->chooser.type = cw->chooser.type;
1120 XmtWarningMsg("XmtChooser","cantChangeType",
1121 "%s: can't change XmtNchooserType resource.",
1122 XtName(set));
1123 }
1124
1125 if ((nw->chooser.strings != cw->chooser.strings) ||
1126 (nw->chooser.pixmaps != cw->chooser.pixmaps) ||
1127 (nw->chooser.select_pixmaps != cw->chooser.select_pixmaps) ||
1128 (nw->chooser.insensitive_pixmaps != cw->chooser.insensitive_pixmaps))
1129 XmtWarningMsg("XmtChooser", "cantChange",
1130 "%s: can't change labels or pixmaps.",
1131 XtName((Widget) nw));
1132
1133 if (nw->chooser.values != cw->chooser.values) {
1134 XtFree((char *)cw->chooser.values);
1135 CheckType(nw);
1136 if (nw->chooser.values) CopyValues(nw);
1137 }
1138 else if (nw->chooser.value_strings != cw->chooser.value_strings) {
1139 XtFree((char*) cw->chooser.values);
1140 CheckType(nw);
1141 if (nw->chooser.value_strings) ConvertValueStrings(nw);
1142 }
1143
1144 if (nw->chooser.visible_items != cw->chooser.visible_items) {
1145 #if XmVersion < 2000
1146 if ((nw->chooser.type==XmtChooserRadioList) ||
1147 (nw->chooser.type==XmtChooserCheckList)) {
1148 #else /* Motif 2.0 or later */
1149 if ((nw->chooser.type==XmtChooserRadioList) ||
1150 (nw->chooser.type==XmtChooserCheckList) ||
1151 (nw->chooser.type==XmtChooserComboBox)) {
1152 #endif
1153 XtSetArg(args[0], XmNvisibleItemCount, nw->chooser.visible_items);
1154 XtSetValues(nw->chooser.list, args, (Cardinal) 1);
1155 }
1156 }
1157
1158 if (nw->chooser.symbol_name != cw->chooser.symbol_name) {
1159 /*
1160 * forget the old symbol, if there is one.
1161 * bind the new, if not NULL, register callbacks, set new state.
1162 * If there is a new state, update the widgets.
1163 */
1164 XtFree(cw->chooser.symbol_name);
1165 nw->chooser.symbol_name = XtNewString(nw->chooser.symbol_name);
1166 ReleaseSymbol(cw);
1167 BindSymbol(nw);
1168 if (nw->chooser.state != cw->chooser.state)
1169 SetStateOnWidgets(nw);
1170 }
1171 else if (nw->chooser.state != cw->chooser.state) {
1172 /* if state changed, but symbol name didn't */
1173 if (nw->chooser.symbol) SetStateOnSymbol(nw); /* sets widgets too */
1174 else SetStateOnWidgets(nw);
1175 }
1176
1177 /*
1178 * if sensitivity changes, set the layoutSensitive resource, in case
1179 * we're a child of XmtLayout, and have a caption.
1180 */
1181 if ((nw->core.sensitive != cw->core.sensitive) ||
1182 (nw->core.ancestor_sensitive != cw->core.ancestor_sensitive)) {
1183 XtVaSetValues(set, XmtNlayoutSensitive,
1184 nw->core.sensitive && nw->core.ancestor_sensitive, NULL);
1185 }
1186
1187 return False;
1188 }
1189
1190
1191 #if NeedFunctionPrototypes
BoundsWarning(XmtChooserWidget cw,int n)1192 static void BoundsWarning(XmtChooserWidget cw, int n)
1193 #else
1194 static void BoundsWarning(cw, n)
1195 XmtChooserWidget cw;
1196 int n;
1197 #endif
1198 {
1199 XmtWarningMsg("XmtChooser", "bounds",
1200 "Widget '%s' has %d items. Item %d requested.",
1201 XtName((Widget) cw), cw->chooser.num_items, n);
1202 }
1203
1204
1205 #if NeedFunctionPrototypes
XmtCreateChooser(Widget parent,StringConst name,ArgList args,Cardinal n)1206 Widget XmtCreateChooser(Widget parent, StringConst name,
1207 ArgList args, Cardinal n)
1208 #else
1209 Widget XmtCreateChooser(parent, name, args, n)
1210 Widget parent;
1211 StringConst name;
1212 ArgList args;
1213 Cardinal n;
1214 #endif
1215 {
1216 return XtCreateWidget((String)name,xmtChooserWidgetClass, parent, args, n);
1217 }
1218
1219 #if NeedFunctionPrototypes
XmtChooserGetState(Widget w)1220 int XmtChooserGetState(Widget w)
1221 #else
1222 int XmtChooserGetState(w)
1223 Widget w;
1224 #endif
1225 {
1226 XmtAssertWidgetClass(w, xmtChooserWidgetClass, "XmtChooserGetState");
1227 return ((XmtChooserWidget)w)->chooser.state;
1228 }
1229
1230 #if NeedFunctionPrototypes
XmtChooserGetValue(Widget w)1231 XtPointer XmtChooserGetValue(Widget w)
1232 #else
1233 XtPointer XmtChooserGetValue(w)
1234 Widget w;
1235 #endif
1236 {
1237 XmtChooserWidget cw = (XmtChooserWidget) w;
1238 XmtAssertWidgetClass(w, xmtChooserWidgetClass, "XmtChooserGetValue");
1239
1240 if (cw->chooser.values)
1241 return (XtPointer) &((char *)cw->chooser.values)
1242 [cw->chooser.state * cw->chooser.value_size];
1243 else return NULL;
1244 }
1245
1246 #if NeedFunctionPrototypes
XmtChooserLookupItemValue(Widget w,int item)1247 XtPointer XmtChooserLookupItemValue(Widget w, int item)
1248 #else
1249 XtPointer XmtChooserLookupItemValue(w, item)
1250 Widget w;
1251 int item;
1252 #endif
1253 {
1254 XmtChooserWidget cw = (XmtChooserWidget) w;
1255 XmtAssertWidgetClass(w, xmtChooserWidgetClass,"XmtChooserLookupItemValue");
1256
1257 if ((item < 0) || (item > cw->chooser.num_items)) {
1258 BoundsWarning(cw, item);
1259 return NULL;
1260 }
1261
1262 if (cw->chooser.values)
1263 return (XtPointer)&((char *)cw->chooser.values)
1264 [item * cw->chooser.value_size];
1265 else return NULL;
1266 }
1267
1268 #if NeedFunctionPrototypes
XmtChooserSetItemValue(Widget w,int item,XtPointer valuep)1269 void XmtChooserSetItemValue(Widget w, int item, XtPointer valuep)
1270 #else
1271 void XmtChooserSetItemValue(w, item, valuep)
1272 Widget w;
1273 int item;
1274 XtPointer valuep;
1275 #endif
1276 {
1277 XmtChooserWidget cw = (XmtChooserWidget) w;
1278 XmtAssertWidgetClass(w, xmtChooserWidgetClass,"XmtChooserLookupItemValue");
1279
1280 if ((item < 0) || (item > cw->chooser.num_items)) {
1281 BoundsWarning(cw, item);
1282 return;
1283 }
1284
1285 if (!cw->chooser.values)
1286 cw->chooser.values = (XtPointer) XtCalloc(cw->chooser.num_items,
1287 cw->chooser.value_size);
1288
1289 memmove(&((char *)cw->chooser.values)[item * cw->chooser.value_size],
1290 valuep,
1291 cw->chooser.value_size);
1292 }
1293
1294
1295 #if NeedFunctionPrototypes
XmtChooserSetState(Widget w,int state,XmtWideBoolean notify)1296 void XmtChooserSetState(Widget w, int state, XmtWideBoolean notify)
1297 #else
1298 void XmtChooserSetState(w, state, notify)
1299 Widget w;
1300 int state;
1301 int notify;
1302 #endif
1303 {
1304 XmtChooserWidget cw = (XmtChooserWidget)w;
1305 XmtChooserCallbackStruct call_data;
1306
1307 XmtAssertWidgetClass(w, xmtChooserWidgetClass, "XmtChooserSetState");
1308
1309 /* the XmtChooserButtonBox doesn't have a state to set */
1310 if (cw->chooser.type == XmtChooserButtonBox) return;
1311
1312 /* if this chooser has radio behavior, check bounds on state */
1313 if ((cw->chooser.type != XmtChooserCheckBox) &&
1314 (cw->chooser.type != XmtChooserCheckPalette) &&
1315 (cw->chooser.type != XmtChooserCheckList) &&
1316 ((state < 0) || (state > cw->chooser.num_items))) {
1317 BoundsWarning(cw, state);
1318 return;
1319 }
1320
1321 cw->chooser.state = state;
1322
1323 if (cw->chooser.symbol) SetStateOnSymbol(cw); /* indirectly sets widgets */
1324 else SetStateOnWidgets(cw);
1325
1326 if (notify) {
1327 call_data.state = state;
1328 call_data.item = -1; /* -1 flags synthetic state changes */
1329 if (cw->chooser.values &&
1330 #if XmVersion < 2000
1331 ((cw->chooser.type == XmtChooserRadioBox) ||
1332 (cw->chooser.type == XmtChooserRadioPalette) ||
1333 (cw->chooser.type == XmtChooserRadioList) ||
1334 (cw->chooser.type == XmtChooserOption)))
1335 #else /* Motif 2.0 or later */
1336 ((cw->chooser.type == XmtChooserRadioBox) ||
1337 (cw->chooser.type == XmtChooserRadioPalette) ||
1338 (cw->chooser.type == XmtChooserRadioList) ||
1339 (cw->chooser.type == XmtChooserOption) ||
1340 (cw->chooser.type == XmtChooserComboBox)))
1341 #endif
1342 call_data.valuep = (XtPointer) &((char *)cw->chooser.values)
1343 [state * cw->chooser.value_size];
1344 else
1345 call_data.valuep = NULL;
1346 XtCallCallbackList(w, cw->chooser.callback, (XtPointer)&call_data);
1347 }
1348 }
1349
1350 #if NeedFunctionPrototypes
XmtChooserLookupItemByName(Widget w,StringConst name)1351 int XmtChooserLookupItemByName(Widget w, StringConst name)
1352 #else
1353 int XmtChooserLookupItemByName(w, name)
1354 Widget w;
1355 StringConst name;
1356 #endif
1357 {
1358 XmtChooserWidget cw = (XmtChooserWidget)w;
1359 int i;
1360
1361 XmtAssertWidgetClass(w, xmtChooserWidgetClass,"XmtChooserLookupItemByName");
1362
1363 if (!name || !cw->chooser.strings) return -1;
1364
1365 for(i = cw->chooser.num_items-1; i >= 0; i--)
1366 if (cw->chooser.strings[i] && (strcmp(name, cw->chooser.strings[i])==0))
1367 break;
1368
1369 return i;
1370 }
1371
1372 #if NeedFunctionPrototypes
XmtChooserLookupItemByValue(Widget w,XtPointer valuep)1373 int XmtChooserLookupItemByValue(Widget w, XtPointer valuep)
1374 #else
1375 int XmtChooserLookupItemByValue(w, valuep)
1376 Widget w;
1377 XtPointer valuep;
1378 #endif
1379 {
1380 XmtChooserWidget cw = (XmtChooserWidget)w;
1381 int i;
1382
1383 XmtAssertWidgetClass(w, xmtChooserWidgetClass,
1384 "XmtChooserLookupItemByValue");
1385
1386 if (!cw->chooser.values) return -1;
1387
1388 if (strcmp(cw->chooser.value_type, XtRString) == 0) {
1389 for(i = cw->chooser.num_items-1; i >= 0; i--)
1390 if (strcmp(*(String *)valuep,
1391 *(String*)&((char *)cw->chooser.values)[i*cw->chooser.value_size]) == 0)
1392 break;
1393 }
1394 else {
1395 for(i = cw->chooser.num_items-1; i >= 0; i--)
1396 if (memcmp(valuep,
1397 &((char*)cw->chooser.values)[i*cw->chooser.value_size],
1398 cw->chooser.value_size) == 0) break;
1399 }
1400 return i;
1401 }
1402
1403 #if NeedFunctionPrototypes
XmtChooserLookupItemName(Widget w,int n)1404 String XmtChooserLookupItemName(Widget w, int n)
1405 #else
1406 String XmtChooserLookupItemName(w, n)
1407 Widget w;
1408 int n;
1409 #endif
1410 {
1411 XmtChooserWidget cw = (XmtChooserWidget)w;
1412
1413 XmtAssertWidgetClass(w, xmtChooserWidgetClass,"XmtChooserLookupItemName");
1414
1415 if ((n < 0) || (n > cw->chooser.num_items)) {
1416 BoundsWarning(cw, n);
1417 return NULL;
1418 }
1419
1420 if (cw->chooser.strings)
1421 return cw->chooser.strings[n];
1422 else
1423 return NULL;
1424 }
1425
1426
1427 #if NeedFunctionPrototypes
XmtChooserSetSensitive(Widget w,int n,XmtWideBoolean sensitive)1428 void XmtChooserSetSensitive(Widget w, int n, XmtWideBoolean sensitive)
1429 #else
1430 void XmtChooserSetSensitive(w, n, sensitive)
1431 Widget w;
1432 int n;
1433 int sensitive;
1434 #endif
1435 {
1436 XmtChooserWidget cw = (XmtChooserWidget)w;
1437
1438 XmtAssertWidgetClass(w, xmtChooserWidgetClass,"XmtChooserSetSensitive");
1439
1440 if ((n < 0) || (n > cw->chooser.num_items)) {
1441 BoundsWarning(cw, n);
1442 return;
1443 }
1444
1445 if (n > 31) {
1446 XmtWarningMsg("XmtChooserSetSensitive", "size",
1447 "can only set sensitivity on first 32 items.");
1448 return;
1449 }
1450
1451 /*
1452 * if this is not a list chooser, set the button's sensitivity.
1453 */
1454 if (cw->chooser.item_widgets)
1455 XtSetSensitive(cw->chooser.item_widgets[n], sensitive);
1456
1457 /*
1458 * set our internal state
1459 */
1460 if (sensitive)
1461 cw->chooser.insensitive &= ~(1 << n);
1462 else
1463 cw->chooser.insensitive |= 1 << n;
1464 }
1465
1466 #if NeedFunctionPrototypes
XmtChooserGetSensitivity(Widget w,int n)1467 Boolean XmtChooserGetSensitivity(Widget w, int n)
1468 #else
1469 Boolean XmtChooserGetSensitivity(w, n)
1470 Widget w;
1471 int n;
1472 #endif
1473 {
1474 XmtChooserWidget cw = (XmtChooserWidget)w;
1475
1476 XmtAssertWidgetClass(w, xmtChooserWidgetClass,"XmtChooserGetSensitivity");
1477
1478 if ((n < 0) || (n > cw->chooser.num_items)) {
1479 BoundsWarning(cw, n);
1480 return False;
1481 }
1482
1483 if (n > 31) {
1484 XmtWarningMsg("XmtChooserGetSensitivity", "size",
1485 "can only get sensitivity on first 32 items.");
1486 return False;
1487 }
1488
1489 if (cw->chooser.insensitive & (1 << n)) return False;
1490 else return True;
1491 }
1492
1493 #if NeedFunctionPrototypes
setvalue(Widget w,XtPointer address,XrmQuark type,Cardinal size)1494 static void setvalue(Widget w, XtPointer address, XrmQuark type, Cardinal size)
1495 #else
1496 static void setvalue(w, address, type, size)
1497 Widget w;
1498 XtPointer address;
1499 XrmQuark type;
1500 Cardinal size;
1501 #endif
1502 {
1503 XmtChooserWidget cw = (XmtChooserWidget) w;
1504
1505 if (cw->chooser.values) {
1506 if (XrmStringToQuark(cw->chooser.value_type) == type) {
1507 int i = XmtChooserLookupItemByValue(w, address);
1508 if (i != -1)
1509 XmtChooserSetState(w, i, False);
1510 else
1511 XmtWarningMsg("XmtChooser", "setvalue0",
1512 "Widget '%s':\n\tCan't set value from resource.\n\tSpecified value is not one of the legal values.",
1513 XtName(w));
1514 }
1515 else
1516 XmtWarningMsg("XmtChooser", "setvalue1",
1517 "Type mismatch:\n\tcan't set value from a resource of type '%s';\n\tWidget '%s' expects a value of type '%s'",
1518 XrmQuarkToString(type), XtName(w), cw->chooser.value_type);
1519 }
1520 else {
1521 int value;
1522
1523 if (size == sizeof(int))
1524 value = *(int *)address;
1525 else if (size == sizeof(short))
1526 value = (int) *(short *)address;
1527 else if (size == sizeof(char))
1528 value = (int) *(char *)address;
1529 else {
1530 XmtWarningMsg("XmtChooser", "setvalue2",
1531 "Type mismatch: \n\tCan't set value from a resource of non-scalar type '%s'.",
1532 XrmQuarkToString(type));
1533 return;
1534 }
1535
1536 XmtChooserSetState(w, value, False);
1537 }
1538 }
1539
1540 #if NeedFunctionPrototypes
getvalue(Widget w,XtPointer address,XrmQuark type,Cardinal size)1541 static void getvalue(Widget w, XtPointer address, XrmQuark type, Cardinal size)
1542 #else
1543 static void getvalue(w, address, type, size)
1544 Widget w;
1545 XtPointer address;
1546 XrmQuark type;
1547 Cardinal size;
1548 #endif
1549 {
1550 XmtChooserWidget cw = (XmtChooserWidget) w;
1551
1552 if (cw->chooser.values) {
1553 if (XrmStringToQuark(cw->chooser.value_type) == type)
1554 memmove(address, XmtChooserGetValue(w), cw->chooser.value_size);
1555 else
1556 XmtWarningMsg("XmtChooser", "getvalue0",
1557 "Type mismatch:\n\tcan't set value on a resource of type '%s';\n\tWidget '%s' has values of type '%s'",
1558 XrmQuarkToString(type), XtName(w), cw->chooser.value_type);
1559 }
1560 else {
1561 int state = XmtChooserGetState(w);
1562
1563 if (size == sizeof(int))
1564 *(int *)address = state;
1565 else if (size == sizeof(short)) /* note we don't warn on overflow */
1566 *(short *)address = state;
1567 else if (size == sizeof(char))
1568 *(char *)address = state;
1569 else {
1570 XmtWarningMsg("XmtChooser", "setvalue2",
1571 "Type mismatch: \n\tCan't set value from a resource of non-scalar type '%s'.",
1572 XrmQuarkToString(type));
1573 return;
1574 }
1575 }
1576 }
1577
1578
1579 static XmtWidgetType chooser_widget = {
1580 "XmtChooser",
1581 (WidgetClass)&xmtChooserClassRec,
1582 NULL,
1583 setvalue,
1584 getvalue,
1585 };
1586
1587 #if NeedFunctionPrototypes
XmtRegisterChooser(void)1588 void XmtRegisterChooser(void)
1589 #else
1590 void XmtRegisterChooser()
1591 #endif
1592 {
1593 XmtRegisterWidgetTypes(&chooser_widget, 1);
1594 }
1595