1 /***********************************************************************/
2 /* Open Visualization Data Explorer */
3 /* (C) Copyright IBM Corp. 1989,1999 */
4 /* ALL RIGHTS RESERVED */
5 /* This code licensed under the */
6 /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */
7 /***********************************************************************/
8
9 #include <dxconfig.h>
10 #include "../base/defines.h"
11
12
13
14
15 #include <Xm/Xm.h>
16 #include <Xm/RowColumn.h>
17 #include <Xm/Form.h>
18 #include <Xm/PushB.h>
19 #include <Xm/CascadeB.h>
20 #include <X11/IntrinsicP.h>
21 #include "XmUtility.h"
22
23 #include "SelectorInteractor.h"
24 #include "InteractorStyle.h"
25 #include "ListIterator.h"
26
27 #include "SelectorNode.h"
28
29 #include "SelectorInstance.h"
30 #include "DXApplication.h"
31 #include "ErrorDialogManager.h"
32 #include "../widgets/XmDX.h"
33
34 boolean SelectorInteractor::SelectorInteractorClassInitialized = FALSE;
35
36 String SelectorInteractor::DefaultResources[] = {
37 "*allowHorizontalResizing: True",
38 "*optionMenu.spacing: 0",
39 "*optionMenu.topOffset: 4",
40 "*optionMenu.leftOffset: 1",
41 "*optionMenu.rightOffset: 1",
42 "*optionMenu.bottomOffset: 4",
43 "*optionMenu.marginHeight: 1",
44 "*optionMenu.marginWidth: 0",
45 "*interactive_form.resizePolicy: XmRESIZE_NONE",
46 NUL(char*)
47 };
48
49
SelectorInteractor(const char * name,InteractorInstance * ii)50 SelectorInteractor::SelectorInteractor(const char *name,
51 InteractorInstance *ii) : Interactor(name,ii)
52 {
53 this->pulldown = NULL;
54 this->optionMenu = NULL;
55 this->optionForm = NULL;
56 this->visinit = FALSE;
57 }
58
59 //
60 // One time class initializations.
61 //
initialize()62 void SelectorInteractor::initialize()
63 {
64 //
65 // Initialize default resources (once only).
66 //
67 if (NOT SelectorInteractor::SelectorInteractorClassInitialized)
68 {
69 ASSERT(theApplication);
70 this->setDefaultResources(theApplication->getRootWidget(),
71 SelectorInteractor::DefaultResources);
72 this->setDefaultResources(theApplication->getRootWidget(),
73 Interactor::DefaultResources);
74 SelectorInteractor::SelectorInteractorClassInitialized = TRUE;
75 }
76 }
77
78
79 //
80 // Allocate an n-dimensional stepper for the given instance.
81 //
AllocateInteractor(const char * name,InteractorInstance * ii)82 Interactor *SelectorInteractor::AllocateInteractor(const char *name,
83 InteractorInstance *ii)
84 {
85
86 SelectorInteractor *si = new SelectorInteractor(name,ii);
87 return (Interactor*)si;
88 }
89
90 //
91 // Accepts value changes and reflects them into other interactors, cdbs
92 // and off course the interactor node output.
93 //
SelectorInteractor_OptionMenuCB(Widget widget,XtPointer clientData,XtPointer callData)94 extern "C" void SelectorInteractor_OptionMenuCB(Widget widget,
95 XtPointer clientData,
96 XtPointer callData)
97 {
98 SelectorInteractor *si = (SelectorInteractor*)clientData;
99
100 ASSERT(widget);
101 ASSERT(si);
102
103
104 int optnum = (int)(long)GetUserData(widget);
105 si->optionMenuCallback(widget, optnum, callData);
106 }
107
108 //
109 // Perform anything that needs to be done after the parent of
110 // this->interactivePart has been managed.
111 //
completeInteractivePart()112 void SelectorInteractor::completeInteractivePart()
113 {
114 }
115
116 //
117 // Build the selector interactor option menu.
118 // Note that we also use this to rebuild the list of options seen in the menu
119 // In this case the
120 //
createInteractivePart(Widget form)121 Widget SelectorInteractor::createInteractivePart(Widget form)
122 {
123 SelectorNode *node;
124 SelectorInstance *si = (SelectorInstance*)this->interactorInstance;
125
126 ASSERT(si);
127
128 node = (SelectorNode*)si->getNode();
129
130 ASSERT(si->getStyle()->getStyleEnum() == SelectorOptionMenuStyle);
131 ASSERT(form);
132 ASSERT(node);
133 ASSERT(EqualString(node->getClassName(), ClassSelectorNode));
134
135 this->optionForm = form;
136
137 //
138 // Build the option menu
139 //
140 this->reloadMenuOptions();
141
142 XtManageChild(this->optionForm);
143 return this->optionForm;
144 }
145
146
147 //
148 // [Re]load the options into this->pulldown.
149 //
reloadMenuOptions()150 void SelectorInteractor::reloadMenuOptions()
151 {
152 SelectorInstance *si = (SelectorInstance*) this->interactorInstance;
153 Widget sbutton;
154 int options, n, i;
155 Arg wargs[20];
156 Pixel bg, fg;
157 unsigned char rsp;
158
159 XtVaGetValues (this->optionForm, XmNresizePolicy, &rsp, NULL);
160 XtVaSetValues (this->optionForm, XmNresizePolicy, XmRESIZE_GROW, NULL);
161
162 ASSERT(this->optionForm);
163
164 if (this->optionMenu) {
165 XtUnmanageChild (this->optionMenu);
166 XtDestroyWidget (this->optionMenu);
167 this->optionMenu = NULL;
168 XtDestroyWidget (this->pulldown);
169 }
170
171 /*
172 * The pulldown already exists so remove all its children,
173 * which are assumed to be contained in this->optionWidgets.
174 */
175 this->optionWidgets.clear();
176
177
178 //
179 // colors change with panel style. It's better to start out with
180 // the proper colors than to switch to ther proper colors.
181 //
182 XtVaGetValues (this->optionForm, XmNforeground, &fg, XmNbackground, &bg, NULL);
183 n = 0;
184 XtSetArg (wargs[n], XmNbackground, bg); n++;
185 XtSetArg (wargs[n], XmNforeground, fg); n++;
186 this->pulldown = XmCreatePulldownMenu(this->optionForm, "pulldownMenu", wargs, n);
187
188 /*
189 * Create the options in the pulldown menu according to specified
190 * option list.
191 */
192
193 Dimension strw, strh;
194 int maxw = 0;
195 XmFontList xmfl = 0;
196 options = si->getOptionCount();
197 XmString xmstr;
198 if (options > 0) {
199 int selectedOption = si->getSelectedOptionIndex();
200 ASSERT(selectedOption <= options);
201 sbutton = NULL;
202 for (i = 1; i <= options; i++)
203 {
204 char *optname = (char*)si->getOptionNameString(i);
205 ASSERT(optname);
206 Widget button;
207 xmstr = XmStringCreateLtoR(optname, "canvas");
208 n = 0;
209 XtSetArg(wargs[n], XmNuserData, i); n++;
210 XtSetArg(wargs[n], XmNlabelString, xmstr ); n++;
211 XtSetArg (wargs[n], XmNbackground, bg); n++;
212 XtSetArg (wargs[n], XmNforeground, fg); n++;
213 button = XmCreatePushButton(this->pulldown, optname, wargs, n);
214
215 if (!xmfl)
216 XtVaGetValues (button,
217 XmNfontList, &xmfl,
218 NULL);
219
220 XmStringExtent (xmfl, xmstr, &strw, &strh);
221 maxw = MAX(maxw, strw);
222
223 XtAddCallback
224 (button,
225 XmNactivateCallback,
226 (XtCallbackProc)SelectorInteractor_OptionMenuCB,
227 (XtPointer)this);
228 XtManageChild(button);
229 if (i == selectedOption) {
230 sbutton = button;
231 }
232 this->appendOptionWidget(button);
233 delete optname;
234 XmStringFree(xmstr);
235 }
236 ASSERT(sbutton);
237 // Certainly not a solution to the problem, but using multi columns
238 // makes marginally better those situations in which a huge number of
239 // options makes the list go off the screen.
240 // FIXME: MAX_OPTIONS must be determined at run time by comparing the
241 // height of the XmStrings with the height of the display. Besides
242 // the number 40 is almost certainly wrong.
243 #define MAX_OPTIONS 40
244 int columns = (options/MAX_OPTIONS) + ((options%MAX_OPTIONS)?1:0);
245 if (columns > 1) {
246 XtVaSetValues (this->pulldown,
247 XmNpacking, XmPACK_COLUMN,
248 XmNnumColumns, columns,
249 NULL);
250 }
251 } else {
252 n = 0;
253 xmstr = XmStringCreateLtoR("(empty)", "canvas");
254 XtSetArg(wargs[n], XmNlabelString, xmstr); n++;
255 sbutton = XmCreatePushButton(this->pulldown, "(empty)", wargs, n);
256 XtManageChild(sbutton);
257 if (!xmfl) XtVaGetValues (sbutton, XmNfontList, &xmfl, NULL);
258 XmStringExtent (xmfl, xmstr, &strw, &strh);
259 maxw = MAX(maxw, strw);
260 this->appendOptionWidget(sbutton);
261 XmStringFree(xmstr);
262 }
263
264 /*
265 * Create the option menu itself or just reset the current selection
266 * if the menu already exists.
267 */
268 n = 0;
269 XtSetArg(wargs[n], XmNmenuHistory, sbutton); n++;
270 if (!this->optionMenu) {
271 XtSetArg(wargs[n], XmNsubMenuId, this->pulldown); n++;
272 XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_FORM); n++;
273 XtSetArg(wargs[n], XmNleftOffset, -(18 + (maxw>>1))); n++;
274 XtSetArg(wargs[n], XmNrightAttachment, XmATTACH_FORM); n++;
275 XtSetArg(wargs[n], XmNbottomAttachment, XmATTACH_FORM); n++;
276 if (this->currentLayout & WorkSpaceComponent::Vertical) {
277 XtSetArg (wargs[n], XmNleftAttachment, XmATTACH_POSITION); n++;
278 XtSetArg (wargs[n], XmNleftPosition, 50); n++;
279 } else {
280 XtSetArg (wargs[n], XmNleftAttachment, XmATTACH_NONE); n++;
281 }
282 XtSetArg(wargs[n], XmNbackground, bg); n++;
283 XtSetArg(wargs[n], XmNforeground, fg); n++;
284 this->optionMenu = XmCreateOptionMenu(this->optionForm,
285 "optionMenu", wargs, n);
286 Widget og = XmOptionButtonGadget(this->optionMenu);
287 XtVaSetValues(og,
288 XmNbackground, bg,
289 XmNforeground, fg,
290 NULL);
291 //
292 // Every motif option menu comes with its own label widget which we
293 // never use.
294 // For the sake of dgux, set the labelString to "", because it defaults
295 // to "OptionLabel" unlike everywhere else.
296 //
297 xmstr = XmStringCreateLtoR ("", "canvas");
298 Widget labelgadget = XmOptionLabelGadget (this->optionMenu);
299 XtVaSetValues (labelgadget,
300 XmNlabelString, xmstr,
301 XmNbackground, bg,
302 XmNforeground, fg,
303 NULL);
304 XmStringFree (xmstr);
305 XtManageChild(this->optionMenu);
306 }
307 if (options <= 0)
308 XtSetSensitive(this->optionMenu,False);
309 else if (!XtIsSensitive (this->optionMenu))
310 XtSetSensitive(this->optionMenu,True);
311
312 XtVaSetValues (this->optionForm, XmNresizePolicy, rsp, NULL);
313 }
314
315 //
316 // Accepts value changes and reflects them into other interactors, cdbs
317 // and off course the interactor node output.
318 //
optionMenuCallback(Widget w,int optnum,XtPointer cb)319 void SelectorInteractor::optionMenuCallback(Widget w, int optnum, XtPointer cb)
320 {
321 SelectorInstance *si = (SelectorInstance*)this->interactorInstance;
322
323 ASSERT(w);
324 ASSERT(optnum > 0);
325
326 si->setSelectedOptionIndex(optnum, TRUE);
327 }
328
329 //
330 // Update the displayed values for this interactor.
331 //
updateDisplayedInteractorValue()332 void SelectorInteractor::updateDisplayedInteractorValue()
333 {
334 // FIXME: should check to make sure we have the correct class of node.
335 SelectorInstance *si = (SelectorInstance*)this->interactorInstance;
336 ASSERT(si);
337
338 //
339 // There are no options, so there is nothing to update.
340 //
341 if (si->getOptionCount() <= 0)
342 return;
343
344 /*
345 * Just display the currently selected option.
346 */
347 int option = si->getSelectedOptionIndex();
348 if (option == 0)
349 return;
350
351 Widget w = this->getOptionWidget(option);
352 ASSERT(w);
353 XtVaSetValues(this->optionMenu, XmNmenuHistory, w, NULL);
354 }
355
356 //
357 // Make sure the attributes match the resources for the widgets.
358 //
handleInteractivePartStateChange(InteractorInstance * src_ii,boolean major_change)359 void SelectorInteractor::handleInteractivePartStateChange(
360 InteractorInstance *src_ii,
361 boolean major_change)
362 {
363 this->reloadMenuOptions();
364 if (this->currentLayout & WorkSpaceComponent::Horizontal) {
365 this->currentLayout|= WorkSpaceComponent::NotSet;
366 this->layoutInteractor();
367 }
368 }
369
layoutInteractorHorizontally()370 void SelectorInteractor::layoutInteractorHorizontally()
371 {
372 this->Interactor::layoutInteractorHorizontally();
373
374 if (!this->optionMenu) return ;
375 XtVaSetValues (this->optionMenu,
376 XmNleftAttachment, XmATTACH_NONE,
377 NULL);
378 }
379
380 //
381 // The setting and resetting of marginHeight and topAttachment deals with the
382 // absence of a topAttachment. XmNtopAttachment is NONE because it permits
383 // the optionmenu to wind up roughly in the middle of its parent even if a change
384 // in the implementation of the interactor causes us to crave a different height
385 // than is saved in the .cfg file. The button widget musn't change height but
386 // the rowcolumn can.
387 //
layoutInteractorVertically()388 void SelectorInteractor::layoutInteractorVertically()
389 {
390 this->Interactor::layoutInteractorVertically();
391
392 if (!this->optionMenu) return ;
393 XtVaSetValues (this->optionMenu,
394 XmNleftAttachment, XmATTACH_POSITION,
395 XmNleftPosition, 50,
396 NULL);
397 }
398
399
setAppearance(boolean developer_style)400 void SelectorInteractor::setAppearance(boolean developer_style)
401 {
402 boolean changing = (developer_style != this->getAppearance());
403 this->Interactor::setAppearance(developer_style);
404 if ((changing) || (this->visinit == FALSE)) {
405 this->reloadMenuOptions();
406 this->visinit = TRUE;
407 }
408 }
409