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 #include <Xm/CascadeB.h>
15 #include <Xm/CascadeBG.h>
16
17 #include "XmUtility.h"
18 #include "DXStrings.h"
19 #include "WorkSpaceComponent.h"
20 #include "DXApplication.h"
21 #include "../widgets/WorkspaceW.h"
22 #include <Xm/Form.h>
23 #include <Xm/Label.h>
24 #include "List.h"
25 #include "ListIterator.h"
26 #include "DynamicResource.h"
27 #include "Network.h" // for setFileDirty
28
29 boolean WorkSpaceComponent::WorkSpaceComponentClassInitialized = FALSE;
30
31 #if KEEP_USING_TRANSLATIONS
32 static XtTranslations wwTranslations = 0;
33 //
34 // This translation table makes descendants of a Workspace widget participate
35 // in selecting, moving, and resizing operations. This is an alternative to
36 // the ::PassEvents() method which used to do some Xlib stuff. PassEvents()
37 // is now replaced with a call to install this translation table on a widget.
38 // The call is now ::passEvents -- it's not static and it uses the "this" pointer.
39 //
40 static String wwTable = "\
41 <Btn1Down>: select_w()\n\
42 <Btn1Motion>: move_w()\n\
43 <Btn1Up>(2+): select_w() release_w() select_w() release_w()\n\
44 <Btn1Up>: release_w()\n\
45 ";
46 #else
47 //
48 // Stop using translations and use event handlers instead because on some widgets
49 // the <Btn1Motion> translations doesn't do anything until the mouse leaves the
50 // the window which is pretty bizarre behavior, but at least the lower level
51 // mechanism works properly.
52 //
53 #endif
54
55 long WorkSpaceComponent::NextInstanceNumber = 1;
56
57 String WorkSpaceComponent::DefaultResources[] =
58 {
59 NUL(char*)
60 };
61
62
WorkSpaceComponent(const char * name,boolean developerStyle)63 WorkSpaceComponent::WorkSpaceComponent(const char *name, boolean developerStyle) :
64 UIComponent(name)
65 {
66 this->developerStyle = developerStyle;
67 this->selected = FALSE;
68 this->customPart = 0;
69 this->visualsInited = FALSE;
70 this->userAssignedWidth = this->userAssignedHeight = 0;
71 this->currentLayout = WorkSpaceComponent::NotSet;
72 this->setResourceList = NUL(List*);
73 this->instance = WorkSpaceComponent::NextInstanceNumber++;
74
75 if (NOT WorkSpaceComponent::WorkSpaceComponentClassInitialized)
76 {
77 WorkSpaceComponent::WorkSpaceComponentClassInitialized = TRUE;
78 #if KEEP_USING_TRANSLATIONS
79 wwTranslations = XtParseTranslationTable (wwTable);
80 #endif
81 }
82 }
83
~WorkSpaceComponent()84 WorkSpaceComponent::~WorkSpaceComponent()
85 {
86 if (this->setResourceList) {
87 ListIterator it(*this->setResourceList);
88 DynamicResource *dynres;
89 while ( (dynres = (DynamicResource *)it.getNext()) ) {
90 delete dynres;
91 }
92 this->setResourceList->clear();
93 delete this->setResourceList;
94 }
95 }
96
97
98 //
99 // Pass button and motion events through to the parent of w.
100 // The boolean arg is here only because the subclass version of
101 // passEvents needs to have one.
102 //
passEvents(Widget w,boolean)103 void WorkSpaceComponent::passEvents(Widget w, boolean )
104 {
105 ASSERT(WorkSpaceComponent::WorkSpaceComponentClassInitialized);
106 #if KEEP_USING_TRANSLATIONS
107 ASSERT(wwTranslations);
108 XtOverrideTranslations (w, wwTranslations);
109 #else
110 XtAddEventHandler (w, Button1MotionMask, False,
111 (XtEventHandler)Component_motionEH, (XtPointer)NULL);
112 XtAddEventHandler (w, ButtonPressMask, False,
113 (XtEventHandler)Component_buttonPressEH, (XtPointer)NULL);
114 XtAddEventHandler (w, ButtonReleaseMask, False,
115 (XtEventHandler)Component_buttonReleaseEH, (XtPointer)NULL);
116 #endif
117 }
118
119
120 extern "C" void
Component_SelectWorkSpaceComponentCB(Widget,XtPointer clientdata,XtPointer callData)121 Component_SelectWorkSpaceComponentCB(Widget , XtPointer clientdata, XtPointer callData)
122 {
123 XmWorkspaceChildCallbackStruct* cb =
124 (XmWorkspaceChildCallbackStruct*)callData;
125 WorkSpaceComponent *d = (WorkSpaceComponent*) clientdata;
126 ASSERT(d);
127 d->setSelected(cb->status);
128 }
129
130
131
132 //
133 // Indicate that the interactor is selected.
134 //
setSelected(boolean state)135 void WorkSpaceComponent::setSelected(boolean state)
136 {
137 Widget root = this->getRootWidget();
138
139 this->selected = state;
140 if (root) {
141 Boolean oldState;
142 XtVaGetValues(root, XmNselected, &oldState, NULL);
143 if (oldState != state) {
144 XtVaSetValues(root, XmNselected, (Boolean)state, NULL);
145 }
146 }
147 }
148
149 //
150 // Filter the given label string so that among other things, "\n"
151 // becomes "<newline>". The returned string must be freed by the
152 // caller.
153 //
FilterLabelString(const char * label)154 char *WorkSpaceComponent::FilterLabelString(const char *label)
155 {
156 char *filtered_string = DeEscapeString(label);
157 return filtered_string;
158 }
159
160 //
161 // Make the interactor "blend into" its environment by turning of
162 // shadowThickness and setting colors to match those of the parent.
163 //
setAppearance(boolean developerStyle)164 void WorkSpaceComponent::setAppearance(boolean developerStyle)
165 {
166 static struct {
167 Pixel fg,bg,ts,bs,arm;
168 } cadet;
169
170 Pixel fg, bg, ts, bs, arm, white;
171 static short init = 0;
172 Screen *screen;
173 Colormap cmap;
174 Arg args[20];
175 Widget root;
176
177 if ((this->visualsInited) && (this->developerStyle == developerStyle)) return ;
178 this->visualsInited = TRUE;
179 this->developerStyle = developerStyle;
180 root = this->getRootWidget();
181 if (!root) return ;
182
183 Display *d = XtDisplay(root);
184 white = WhitePixelOfScreen (DefaultScreenOfDisplay(d));
185
186 if (developerStyle) {
187 if (!init) {
188 init = 1;
189 XtVaGetValues (root, XmNcolormap, &cmap, XmNscreen, &screen, NULL);
190
191 cadet.bg = bg = theDXApplication->getStandInBackground();
192 XmGetColors (screen,cmap,bg,&cadet.fg, &cadet.ts, &cadet.bs, &cadet.arm);
193 cadet.fg = WhitePixelOfScreen (DefaultScreenOfDisplay(d));
194 }
195 bg = cadet.bg; fg = cadet.fg;
196 ts = cadet.ts; bs = cadet.bs;
197 arm = cadet.arm;
198 } else {
199 XtVaGetValues (XtParent(root), XmNbackground, &bg,
200 XmNcolormap, &cmap, XmNscreen, &screen, NULL);
201 XmGetColors (screen, cmap, bg, &fg, &ts, &bs, &arm);
202 }
203
204
205 //
206 // Perform a test of DynamicResource by using it set fg,bg,ts, and bs.
207 //
208 //#define TESTING_DYNAMIC_RESOURCE_CLASS 1
209 #if TESTING_DYNAMIC_RESOURCE_CLASS
210 if (!this->setResourceList) {
211 this->setResourceList = new List;
212 DynamicResource *drbg = new DynamicResource (XmNbackground, root);
213 DynamicResource *drfg = new DynamicResource (XmNforeground, root);
214 DynamicResource *drts = new DynamicResource (XmNtopShadowColor, root);
215 DynamicResource *drbs = new DynamicResource (XmNbottomShadowColor, root);
216 DynamicResource *drsc = new DynamicResource (XmNselectColor, root);
217 DynamicResource *drac = new DynamicResource (XmNarmColor, root);
218 DynamicResource *drtc = new DynamicResource (XmNtroughColor, root);
219
220 this->setResourceList->appendElement ((void *)drbg);
221 this->setResourceList->appendElement ((void *)drfg);
222 this->setResourceList->appendElement ((void *)drts);
223 this->setResourceList->appendElement ((void *)drbs);
224 this->setResourceList->appendElement ((void *)drsc);
225 this->setResourceList->appendElement ((void *)drac);
226 this->setResourceList->appendElement ((void *)drtc);
227
228 drbg->setDataDirectly ((void*)bg);
229 drfg->setDataDirectly ((void*)fg);
230 drts->setDataDirectly ((void*)ts);
231 drbs->setDataDirectly ((void*)bs);
232 drsc->setDataDirectly ((void*)white);
233 drac->setDataDirectly ((void*)arm);
234 drtc->setDataDirectly ((void*)arm);
235
236 drbg->addWidgetsToNameList (root);
237 drfg->addWidgetsToNameList (root);
238 drts->addWidgetsToNameList (root);
239 drbs->addWidgetsToNameList (root);
240 drsc->addWidgetsToNameList (root);
241 drac->addWidgetsToNameList (root);
242 drtc->addWidgetsToNameList (root);
243 } else {
244 ListIterator it(*this->setResourceList);
245 DynamicResource *dr;
246 while (dr = (DynamicResource*)it.getNext()) {
247 const char *cp = dr->getResourceName();
248 if (!strcmp(cp, XmNbackground)) dr->setDataDirectly ((void*)bg);
249 else if (!strcmp(cp, XmNforeground)) dr->setDataDirectly ((void*)fg);
250 else if (!strcmp(cp, XmNtopShadowColor)) dr->setDataDirectly ((void*)ts);
251 else if (!strcmp(cp, XmNbottomShadowColor)) dr->setDataDirectly ((void*)bs);
252 }
253 }
254
255 #else
256 // Set bg == ts == bs for root widget instead of setting shadowThickness.
257 int n = 0;
258 XtSetArg (args[n], XmNbackground, bg); n++;
259 if (developerStyle) {
260 XtSetArg (args[n], XmNtopShadowColor, ts); n++;
261 XtSetArg (args[n], XmNbottomShadowColor, bs); n++;
262 } else {
263 XtSetArg (args[n], XmNtopShadowColor, bg); n++;
264 XtSetArg (args[n], XmNbottomShadowColor, bg); n++;
265 }
266 XtSetArg (args[n], XmNselectColor, white); n++;
267 XtSetArg (args[n], XmNarmColor, arm); n++;
268 XtSetArg (args[n], XmNtroughColor, arm); n++;
269 XtSetArg (args[n], XmNforeground, fg); n++;
270 XtSetArg (args[n], XmNselectable, (developerStyle?True:False) ); n++;
271 XtSetValues (root, args, n);
272
273 n = 0;
274 XtSetArg (args[n], XmNbackground, bg); n++;
275 XtSetArg (args[n], XmNtopShadowColor, ts); n++;
276 XtSetArg (args[n], XmNbottomShadowColor, bs); n++;
277 XtSetArg (args[n], XmNselectColor, white); n++;
278 XtSetArg (args[n], XmNarmColor, arm); n++;
279 XtSetArg (args[n], XmNtroughColor, arm); n++;
280 XtSetArg (args[n], XmNforeground, fg); n++;
281 SetAllChildrenOf (root, args, n);
282
283
284 #endif
285
286 //
287 // Restore those DynamicResource settings which might have been affected
288 // by the change in modes. Currently setting them all, but one day it may be more
289 // work than is necessary. The settings in setResourceList might be touched
290 // by the SetAllChildrenOf call, i.e. XmNforeground which conflicts with
291 // the DynamicResource for Decorators.
292 //
293 if (this->setResourceList) {
294 ListIterator it(*this->setResourceList);
295 DynamicResource *dr;
296 while ( (dr = (DynamicResource*)it.getNext()) ) {
297 dr->setData();
298 }
299 }
300 }
301
302 //
303 // walk the widget tree setting resources.
304 //
SetAllChildrenOf(Widget w,Arg * args,int n)305 void WorkSpaceComponent::SetAllChildrenOf (Widget w, Arg *args, int n)
306 {
307 Widget *kids, menu;
308 int nkids, i;
309
310
311 if ((XtIsSubclass (w, xmCascadeButtonWidgetClass))||
312 (XtIsSubclass (w, xmCascadeButtonGadgetClass))) {
313 menu = 0;
314 XtVaGetValues (w, XmNsubMenuId, &menu, NULL);
315 if (!menu) return ;
316 XtSetValues (menu, args, n);
317 SetAllChildrenOf (menu, args, n);
318 }
319 if (!XtIsComposite (w)) return ;
320
321 XtVaGetValues (w, XmNchildren, &kids, XmNnumChildren, &nkids, NULL);
322 for (i=0; i<nkids; i++) {
323 if (XtIsShell (kids[i])) continue ;
324 XtSetValues (kids[i], args, n);
325 SetAllChildrenOf (kids[i], args, n);
326 }
327 }
328
329 //
330 // Determine if this Component is a node of the given class
331 //
isA(const char * classname)332 boolean WorkSpaceComponent::isA(const char *classname)
333 {
334 Symbol s = theSymbolManager->registerSymbol(classname);
335 return this->isA(s);
336 }
337 //
338 // Determine if this Component is of the given class.
339 //
isA(Symbol classname)340 boolean WorkSpaceComponent::isA(Symbol classname)
341 {
342 Symbol s = theSymbolManager->registerSymbol(ClassWorkSpaceComponent);
343 return (s == classname);
344 }
345
346
347 void
GetDimensions(Widget w,int * height,int * width)348 WorkSpaceComponent::GetDimensions(Widget w, int *height, int *width)
349 {
350 Dimension wdim, hdim;
351
352 XtVaGetValues(w, XmNheight, &hdim, XmNwidth, &wdim, NULL);
353 *width = wdim; *height = hdim;
354 }
355
installResizeHandler()356 void WorkSpaceComponent::installResizeHandler()
357 {
358 XmWorkspaceAddCallback(this->getRootWidget(), XmNresizingCallback,
359 (XtCallbackProc)Component_ResizeCB, (XtPointer)this);
360 }
361
Component_ResizeCB(Widget,XtPointer clientdata,XtPointer)362 extern "C" void Component_ResizeCB(Widget , XtPointer clientdata, XtPointer)
363 {
364 WorkSpaceComponent *wcs = (WorkSpaceComponent*) clientdata;
365 wcs->GetDimensions (wcs->getRootWidget() ,
366 &wcs->userAssignedHeight, &wcs->userAssignedWidth);
367 wcs->resizeCB();
368 wcs->getNetwork()->setFileDirty();
369 }
370
371 void
SetLabelResource(Widget w,const char * labelString)372 WorkSpaceComponent::SetLabelResource (Widget w, const char *labelString)
373 {
374 char *filtered_string;
375 XmString string;
376 XmFontList xmfl;
377 Dimension neww, newh;
378 XtWidgetGeometry req;
379 Dimension mw,mh,mt,mb,ml,mr; // margin sizes
380 Dimension ht,st; // thicknesses
381 Dimension width, height;
382
383 if (!labelString) return ;
384
385 // FIXME: is it necessary to free the fontList acquired thru XtGetValues ?
386
387 /*
388 * Replace "\n" character sequences with the '\n' character.
389 */
390 filtered_string = WorkSpaceComponent::FilterLabelString(labelString);
391 string = XmStringCreateLtoR((char*)filtered_string, "canvas");
392
393 mw = mh = mt = mb = ml = mr = ht = st = 0;
394 XtVaGetValues (w, XmNfontList, &xmfl, XmNmarginWidth, &mw,
395 XmNmarginHeight, &mh, XmNmarginWidth, &mw, XmNmarginHeight, &mh,
396 XmNmarginLeft, &ml, XmNmarginRight, &mr, XmNmarginTop, &mt,
397 XmNmarginBottom, &mb, XmNshadowThickness, &st, XmNhighlightThickness, &ht,
398 XmNwidth, &width, XmNheight, &height, NULL);
399 XmStringExtent (xmfl, string, &neww, &newh);
400 req.width = neww + (2*(mw + ht + st)) + ml + mr;
401 req.height = newh + (2*(mh + ht + st)) + mt + mb;
402 req.request_mode = 0;
403 /*if (req.width > width)*/ req.request_mode|= CWWidth;
404 /*if (req.height > height)*/ req.request_mode|= CWHeight;
405 if (req.request_mode) XtMakeGeometryRequest (w, &req, NULL);
406 XtVaSetValues(w,XmNlabelString, string, NULL);
407
408 XmStringFree(string);
409 delete filtered_string;
410 }
411
412 //
413 // If there as never been an explicit size requested by the user, then
414 // return 0,0 so that the Motif's geometry mgmt will always provide the
415 // smallest necessary size. If the user or cfg file did specify a size,
416 // then use the actual size. Ironically, we never return the size the
417 // user explicitly made.
418 //
419 void
getXYSize(int * width,int * height)420 WorkSpaceComponent::getXYSize (int *width, int *height)
421 {
422
423 #if USE_OWN_SIZES
424 int uw, uh;
425 int cw, ch;
426 this->getUserDimensions (&uw, &uh);
427 if (uw && uh)
428 this->UIComponent::getXYSize (width, height);
429 else
430 *width = *height = 0 ;
431 #else
432 this->UIComponent::getXYSize (width, height);
433 #endif
434 }
435
436 void
setVerticalLayout(boolean vertical)437 WorkSpaceComponent::setVerticalLayout (boolean vertical)
438 {
439 if (!this->acceptsLayoutChanges()) return ;
440 ASSERT (
441 ((this->currentLayout & WorkSpaceComponent::Vertical) !=
442 (this->currentLayout & WorkSpaceComponent::Horizontal))
443 ||
444 (this->currentLayout == WorkSpaceComponent::NotSet)
445 );
446
447 if (vertical) {
448 this->currentLayout&= ~WorkSpaceComponent::Horizontal;
449 this->currentLayout|= WorkSpaceComponent::Vertical;
450 } else {
451 this->currentLayout&= ~WorkSpaceComponent::Vertical;
452 this->currentLayout|= WorkSpaceComponent::Horizontal;
453 }
454 this->getNetwork()->setFileDirty();
455 }
456
457 boolean
verticallyLaidOut()458 WorkSpaceComponent::verticallyLaidOut()
459 {
460 if (this->currentLayout & WorkSpaceComponent::NotSet) return FALSE;
461
462 return (this->currentLayout & WorkSpaceComponent::Vertical);
463 }
464
465
466 #if MIGHT_NEED_THIS_LATER
467 //
468 // Get the actual value which used to set some XmNresource. This data would
469 // have started out as a null-terminated char* and been converted to a value
470 // thru some type convertor called from DynamicResource. I think this function
471 // is not currently in use, but it's purpose is to enable copying resource values
472 // around.
473 //
474 void *
getResource(const char * res)475 WorkSpaceComponent::getResource (const char *res)
476 {
477 ListIterator it;
478 DynamicResource *dr;
479
480 if (!this->setResourceList) return NUL(void *);
481
482 it.setList (*this->setResourceList);
483 while (dr = (DynamicResource *)it.getNext()) {
484 if (!strcmp (dr->getResourceName(), res)) {
485 break;
486 }
487 }
488 if (!dr) return NUL(void*);
489
490 return (void*)dr->getData();
491 }
492 #endif
493
494 //
495 // Get the null-terminated char* which was used to set some XmNresource.
496 //
497 const char *
getResourceString(const char * res)498 WorkSpaceComponent::getResourceString (const char *res)
499 {
500 ListIterator it;
501 DynamicResource *dr;
502
503 if (!this->setResourceList) return NUL(const char *);
504
505 it.setList (*this->setResourceList);
506 while ( (dr = (DynamicResource *)it.getNext()) ) {
507 if (!strcmp (dr->getResourceName(), res)) {
508 break;
509 }
510 }
511 if (!dr) return NUL(const char*);
512 return (const char *)dr->getStringRepresentation();
513 }
514
515 boolean
isResourceSet(const char * res)516 WorkSpaceComponent::isResourceSet (const char *res)
517 {
518 ListIterator it;
519 DynamicResource *dr;
520
521 if (!this->setResourceList) return FALSE;
522
523 it.setList (*this->setResourceList);
524 while ( (dr = (DynamicResource *)it.getNext()) ) {
525 if (!strcmp (dr->getResourceName(), res)) {
526 return TRUE;
527 }
528 }
529 return FALSE;
530 }
531
532 //
533 // Copy my DynamicResource settings into someone else
534 //
transferResources(WorkSpaceComponent * wsc)535 void WorkSpaceComponent::transferResources (WorkSpaceComponent *wsc)
536 {
537 if (!this->setResourceList) return ;
538 if (!wsc->setResourceList)
539 wsc->setResourceList = new List;
540
541 ListIterator it (*this->setResourceList);
542 DynamicResource *dr;
543 while ( (dr = (DynamicResource*)it.getNext()) ) {
544 wsc->setResourceList->appendElement((void*)dr);
545 if (this->customPart) dr->setRootWidget(this->getRootWidget());
546 else dr->setRootWidget(NUL(Widget));
547 }
548 this->setResourceList->clear();
549 }
550
widgetDestroyed()551 void WorkSpaceComponent::widgetDestroyed ()
552 {
553 if (this->setResourceList) {
554 ListIterator it (*this->setResourceList);
555 DynamicResource *dr;
556 while ( (dr = (DynamicResource*)it.getNext()) )
557 dr->setRootWidget(NUL(Widget));
558 }
559 this->UIComponent::widgetDestroyed ();
560 }
561
562 //
563 // In addition to superclass work, we'll need to create new workspace
564 // lines since the start/end points of
565 // In the case of StandIn, using the superclass doesn't do any good
566 // since the widget is geometry-managed by the containing widget. Setting
567 // XmN{x,y} has no effect.
568 //
setXYPosition(int x,int y)569 void WorkSpaceComponent::setXYPosition (int x, int y)
570 {
571 this->UIComponent::setXYPosition (x,y);
572 if (this->isManaged())
573 XmWorkspaceSetLocation (this->getRootWidget(), x, y);
574 }
575
576 //
577 // Store the this pointer in the widget's XmNuserData so that we
578 // can retrieve the Object in a callback in EditorWorkSpace.C
579 //
setRootWidget(Widget root,boolean standardDestroy)580 void WorkSpaceComponent::setRootWidget(Widget root, boolean standardDestroy)
581 {
582 this->UIComponent::setRootWidget(root, standardDestroy);
583 this->setLocalData(this);
584 }
585
586 extern "C" {
Component_motionEH(Widget w,XtPointer,XEvent * xev,Boolean * keep_going)587 void Component_motionEH
588 (Widget w, XtPointer , XEvent *xev, Boolean *keep_going)
589 {
590 *keep_going = True;
591 XtCallActionProc (w, "move_w", xev, NULL, 0);
592 }
Component_buttonReleaseEH(Widget w,XtPointer,XEvent * xev,Boolean * keep_going)593 void Component_buttonReleaseEH
594 (Widget w, XtPointer , XEvent *xev, Boolean *keep_going)
595 {
596 *keep_going = True;
597 if ((xev->xbutton.button != 1)&&(xev->xbutton.button != 2))
598 return ;
599
600 if ((xev->xbutton.button == 2) && (xev->xbutton.state & ShiftMask))
601 return ;
602 XtCallActionProc (w, "release_w", xev, NULL, 0);
603 }
Component_buttonPressEH(Widget w,XtPointer,XEvent * xev,Boolean * keep_going)604 void Component_buttonPressEH
605 (Widget w, XtPointer , XEvent *xev, Boolean *keep_going)
606 {
607 *keep_going = True;
608 if ((xev->xbutton.button != 1)&&(xev->xbutton.button != 2))
609 return ;
610
611 if ((xev->xbutton.button == 2) && (xev->xbutton.state & ShiftMask))
612 return ;
613 XtCallActionProc (w, "select_w", xev, NULL, 0);
614 }
615 } // extern C
616