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 #if defined(HAVE_IOSTREAM)
13 #include <iostream>
14 #elif defined(HAVE_IOSTREAM_H)
15 #include <iostream.h>
16 #endif
17 
18 #if defined(HAVE_UNISTD_H)
19 #include <unistd.h>
20 #endif
21 
22 #if defined(HAVE_NETDB_H)
23 #include <netdb.h>
24 #endif
25 
26 #include "DXApplication.h"
27 
28 #include <Xm/BulletinB.h>
29 #include <Xm/PushB.h>
30 #include <Xm/Label.h>
31 #include <Xm/DragDrop.h>
32 
33 #include <X11/Intrinsic.h>
34 #include <X11/StringDefs.h>
35 #include <X11/Xatom.h>
36 #ifndef XK_MISCELLANY
37 #define XK_MISCELLANY
38 #endif
39 #include <X11/keysym.h>
40 
41 #include "../widgets/WorkspaceW.h"
42 
43 #include "StandIn.h"
44 #include "Tab.h"
45 #include "Parameter.h"
46 #include "List.h"
47 #include "ListIterator.h"
48 #include "DXStrings.h"
49 #include "Node.h"
50 #include "Ark.h"
51 #include "ArkStandIn.h"
52 #include "Command.h"
53 #include "EditorWindow.h"
54 #include "Network.h"
55 #include "EditorWorkSpace.h"
56 #include "UIComponent.h"
57 #include "ErrorDialogManager.h"
58 #include "TransmitterNode.h"
59 #include "ReceiverNode.h"
60 #include "DXDragSource.h"
61 
62 #include "moduledrag.bm"
63 #include "moduledragmask.bm"
64 
65 // gethostname is needed by selectedNodesCB which is part of drag-n-drop
66 #if defined(NEEDS_GETHOSTNAME_DECL)
67 extern "C" int gethostname(char *address, int address_len);
68 #endif
69 
70 #if 0
71 #if defined(DXD_WIN)
72 #include <winsock.h>
73 #endif
74 #endif
75 
76 #ifdef DXD_XTOFFSET_HOSED
77 #undef XtOffset
78 #define XtOffset( p_type, field ) ((size_t)&((( p_type )0)->field))
79 #endif
80 
81 
82 #define DXXOFFSET "DX_XOFFSET"
83 #define DXYOFFSET "DX_YOFFSET"
84 
85 
86 String StandIn::DefaultResources[] =
87 {
88         ".marginWidth:     1",
89         NULL
90 };
91 
92 
93 typedef struct _NodeAttrs
94 {
95     struct
96     {
97 // This Pixel value now comes from DXApplication::getStandInBackground().
98 //        Pixel           background;     /* bboard background color      */
99         Pixel           foreground;     /* bboard normal foreground     */
100         Pixel           highlight_foreground;
101     }                   bboard;
102 
103     struct
104     {
105         Pixel           background;
106                                         /* i/o tag BG color             */
107         Pixel           highlight_background;
108                                         /* i/o highlighted tab BG color */
109         Pixel           required_background;
110                                         /* i/o required tag BG color    */
111         Dimension       width;          /* i/o tag height               */
112         Dimension       height;         /* i/o tag width                */
113 
114     }                   io;
115 
116     struct
117     {
118         Pixel           color;          /* line color                   */
119         short           thickness;      /* line thickness               */
120 
121     }                   line;
122 
123 } standInDefaultsStruct;
124 
125 static standInDefaultsStruct standInDefaults;
126 
127 static
128 XtResource _SIColorResources[] = {
129 // This guy now lives in DXApplication. His value is shared with c.p.
130 //    {
131 //	"standInBackground",
132 //	"StandInBackground",
133 //	XmRPixel,
134 //	sizeof(Pixel),
135 //	XtOffset(standInDefaultsStruct*, bboard.background),
136 //	XmRString,
137 //	(XtPointer)"CadetBlue"
138 //    },
139     {
140 	"standInForeground",
141 	"StandInForeground",
142 	XmRPixel,
143 	sizeof(Pixel),
144 	XtOffset(standInDefaultsStruct*, bboard.foreground),
145 	XmRString,
146 	(XtPointer)"White"
147     },
148     {
149 	"standInHighlightForeground",
150 	"StandInHighlightForeground",
151 	XmRPixel,
152 	sizeof(Pixel),
153 	XtOffset(standInDefaultsStruct*, bboard.highlight_foreground),
154 	XmRString,
155 	(XtPointer)"SpringGreen"
156     },
157     {
158 	"standInLineColor",
159 	"StandInLineColor",
160 	XmRPixel,
161 	sizeof(Pixel),
162 	XtOffset(standInDefaultsStruct*, line.color),
163 	XmRString,
164 	(XtPointer)"Black"
165     },
166     {
167 	"standInIORequiredBackground",
168 	"StandInIORequiredBackground",
169 	XmRPixel,
170 	sizeof(Pixel),
171 	XtOffset(standInDefaultsStruct*, io.required_background),
172 	XmRString,
173 	(XtPointer)"MediumTurquoise"
174     },
175     {
176 	"standInIOHighlightBackground",
177 	"StandInIOHighlightBackground",
178 	XmRPixel,
179 	sizeof(Pixel),
180 	XtOffset(standInDefaultsStruct*, io.highlight_background),
181 	XmRString,
182 	(XtPointer)"SpringGreen"
183     },
184 };
185 
186 static
187 XtResource _SIResourceList[] =
188 {
189     {
190 	"standInIOWidth",
191 	"StandInIOWidth",
192 	XmRDimension,
193 	sizeof(Dimension),
194 	XtOffset(standInDefaultsStruct*, io.width),
195 	XmRString,
196 	(XtPointer)"16"
197     },
198     {
199 	"standInIOHeight",
200 	"StandInIOHeight",
201 	XmRDimension,
202 	sizeof(Dimension),
203 	XtOffset(standInDefaultsStruct*, io.height),
204 	XmRString,
205 	(XtPointer)"10"
206     },
207 };
208 
standInGetDefaultForeground()209 Pixel standInGetDefaultForeground()
210 {
211         return standInDefaults.bboard.foreground;
212 }
213 
214 Boolean StandIn::ClassInitialized = FALSE;
215 Widget  StandIn::DragIcon = NULL;
216 Dictionary* StandIn::DragTypeDictionary = new Dictionary;
217 
StandIn(WorkSpace * w,Node * node)218 StandIn::StandIn(WorkSpace *w, Node *node):
219                  UIComponent(node->getNameString()),
220 		 DXDragSource(PrintCut)
221 {
222     this->workSpace = w;
223     this->node = node;
224     this->buttonWidget = NULL;
225     this->requiredButtonWidth = 0;
226     this->drag_drop_wpid = 0;
227 }
228 
229 
230 
231 //
232 // Destructor
233 //
~StandIn()234 StandIn::~StandIn()
235 {
236     Tab *tab;
237     ListIterator iterator;
238 
239     iterator.setList(this->inputTabList);
240     while ( (tab = (Tab*)iterator.getNext()) )
241         delete tab;
242 
243     iterator.setList(this->outputTabList);
244     while ( (tab = (Tab*)iterator.getNext()) )
245         delete tab;
246 
247     this->node->standin = NULL;
248 
249     if (this->drag_drop_wpid)
250 	XtRemoveWorkProc (this->drag_drop_wpid);
251 
252     //
253     // Remove it (visually) from the work space,
254     // because when opening a new network, we don't make it back to
255     // the X main loop before we start reading in new stand-ins over
256     // the old ones.
257     //
258     XtUnmapWidget(this->getRootWidget());
259 }
260 
drawTab(int paramIndex,boolean outputTab)261 void StandIn::drawTab(int         paramIndex,
262                       boolean     outputTab)
263 {
264     XtWidgetGeometry geometry;
265     int              x,x2;
266     int              y;
267     int              n;
268     Arg              arg[10];
269     Tab              *tab;
270     Widget           line;
271     Node*            node;
272     int              inputTab;
273     int              in = FALSE;
274 
275 
276     inputTab = !outputTab;
277 
278     node = this->node;
279 
280 
281     if ((node->isParameterVisible(paramIndex,inputTab) == FALSE) ||
282         (inputTab && node->getInputCount() == 0))
283 	return;
284 
285     if (!node->isParameterViewable(paramIndex,inputTab))
286 	return;
287 
288     tab = this->getParameterTab(paramIndex,inputTab);
289     y = tab->getTabY();
290     boolean is_connected = node->isParameterConnected(paramIndex,inputTab);
291 
292     if  (is_connected OR (inputTab && !node->isInputDefaulting(paramIndex)))
293         {
294             /*
295              * Move the tab in.
296              */
297             in = TRUE;
298             int new_y = y + (outputTab ? - standInDefaults.io.height
299                              : standInDefaults.io.height);
300             tab->setBackground(standInDefaults.io.background);
301 	    tab->moveTabY(new_y, FALSE);
302         }
303         else
304         {
305             /*
306              * Move the tab out.
307              */
308             in = FALSE;
309             if (inputTab && node->isInputRequired(paramIndex))
310 		tab->setBackground(standInDefaults.io.required_background);
311 	    tab->moveTabY(y, FALSE);
312         }
313 
314     /*
315      * Now, make sure that the tab widget is on top of the name widget.
316      */
317     geometry.request_mode = CWStackMode;
318     geometry.stack_mode   = Above;
319     XtMakeGeometryRequest(tab->getRootWidget(), &geometry, NULL);
320 
321 // FIXME
322 //    if (inputTab && !node->isInputDefaulting(paramIndex)) {
323 //       return;
324 //    }
325 //
326     /*
327      * Create/delete line stub as circumstance dictates.
328      */
329 
330     line = tab->getLine();
331 
332     if (is_connected)
333     {
334         /*
335          * If the line already exists, adjust it (in case this is a
336          * tab/line adjustment).  Otherwise, create a new line.
337          */
338         /*
339          * Calculate the (x, y) coordinates.
340          */
341         x2 = tab->getTabX();
342         x = (x2 + standInDefaults.io.width / 2) -
343             standInDefaults.line.thickness / 2;
344 
345         n = 0;
346         XtSetArg(arg[n], XmNx, x); n++;
347         XtSetArg(arg[n], XmNy, y); n++;
348         if (line != NULL) {
349             XtSetValues(line, arg, n);
350         } else if (in) {
351              /*
352              * Create line stub.
353              */
354              XtSetArg(arg[n], XmNheight,standInDefaults.io.height);n++;
355              XtSetArg(arg[n], XmNwidth, standInDefaults.line.thickness); n++;
356              XtSetArg(arg[n], XmNbackground,standInDefaults.line.color); n++;
357              XtSetArg(arg[n], XmNforeground,standInDefaults.line.color); n++;
358              line = XmCreateLabel(this->getRootWidget(), "line", arg, n);
359 	     tab->setLine(line);
360              XtManageChild(line);
361          }
362     } else {
363              /*
364               * Delete the line widget, if it exists.
365               */
366             if (line != NULL) {
367                 XtDestroyWidget(line);
368 	        tab->setLine(NULL);
369             }
370     }
371 }
372 
373 #if 0
374 static
375 Pixel getColor(Widget widget,
376                 char*  color)
377 {
378     XrmValue from;
379     XrmValue to;
380     Pixel *pixel;
381 
382 
383     from.size = sizeof(char*);
384     from.addr = color;
385 
386     XtConvert(widget, XmRString, &from, XmRPixel, &to);
387 
388     if (to.addr) {
389 	pixel = (Pixel*)to.addr;
390 	return *pixel;
391     } else
392 	return 0;
393 }
394 #endif
395 
396 //
397 // Provide tabs with their width and height
398 //
getIOWidth()399 int StandIn::getIOWidth()
400 {
401     return standInDefaults.io.width;
402 }
getIOHeight()403 int StandIn::getIOHeight()
404 {
405     return standInDefaults.io.height;
406 }
407 
408 //
409 // Static allocator found in theSIAllocatorDictionary
410 //
AllocateStandIn(WorkSpace * w,Node * node)411 StandIn *StandIn::AllocateStandIn(WorkSpace *w, Node *node)
412 {
413     StandIn *si = new StandIn(w,node);
414     si->createStandIn();
415     return si;
416 }
417 
418 
419 //
420 // See ::createStandIn for more code related to initialization. Hmmmmm
421 //
initialize()422 void StandIn::initialize()
423 {
424     if (!StandIn::ClassInitialized) {
425 	this->setDefaultResources(theApplication->getRootWidget(),
426                               StandIn::DefaultResources);
427 
428 	// DnD requires the ability to read and write .net and .cfg files.
429 	if ((theDXApplication->appAllowsSavingNetFile()) &&
430 	    (theDXApplication->appAllowsSavingCfgFile()) &&
431 	    (theDXApplication->appAllowsEditorAccess())) {
432 	    this->addSupportedType (StandIn::Modules, DXMODULES, TRUE);
433 	    this->addSupportedType (StandIn::Interactors, DXINTERACTOR_NODES,FALSE);
434 	}
435 	if (theDXApplication->appAllowsEditorAccess())
436 	    this->addSupportedType (StandIn::Trash, DXTRASH, FALSE);
437 
438 	//
439 	// Delete the atoms set up when starting the drag
440 	//
441 	Display *d = XtDisplay(theDXApplication->getRootWidget());
442 	Atom xoff_atom = XInternAtom (d, DXXOFFSET, True);
443 	Atom yoff_atom = XInternAtom (d, DXYOFFSET, True);
444 	Screen *screen = XtScreen(theDXApplication->getRootWidget());
445 	Window root = RootWindowOfScreen(screen);
446 	if (xoff_atom != None)
447 	    XDeleteProperty (d, root, xoff_atom);
448 	if (yoff_atom != None)
449 	    XDeleteProperty (d, root, yoff_atom);
450     }
451 
452 
453     if (!StandIn::DragIcon) {
454 	StandIn::DragIcon =
455 		this->createDragIcon(moduledrag_width, moduledrag_height,
456 				     (char *)moduledrag_bits,
457 				     (char *)moduledragmask_bits);
458     }
459     this->setDragIcon(StandIn::DragIcon);
460 }
461 
getOutputParameterLine(int i)462 Widget StandIn::getOutputParameterLine(int i)
463 {
464     Tab *tab;
465     tab = (Tab *) outputTabList.getElement(i);
466 
467     return tab->getLine();
468 }
469 
getInputParameterLine(int i)470 Widget StandIn::getInputParameterLine(int i)
471 {
472     Tab *tab;
473     tab = (Tab *) inputTabList.getElement(i);
474 
475     return tab->getLine();
476 }
477 
setInputParameterLine(int i,Widget w)478 void StandIn::setInputParameterLine(int i, Widget w)
479 {
480     Tab *tab;
481     tab = (Tab *) inputTabList.getElement(i);
482 
483     tab->setLine(w);
484 }
485 
setOutputParameterLine(int i,Widget w)486 void StandIn::setOutputParameterLine(int i, Widget w)
487 {
488     Tab *tab;
489     tab = (Tab *) outputTabList.getElement(i);
490 
491     tab->setLine(w);
492 }
493 
getInputParameterTab(int i)494 Tab *StandIn::getInputParameterTab(int i)
495 {
496     Tab *tab;
497     tab = (Tab *) inputTabList.getElement(i);
498 
499     ASSERT(tab);
500     return tab;
501 }
502 
getOutputParameterTab(int i)503 Tab *StandIn::getOutputParameterTab(int i)
504 {
505     Tab *tab;
506     tab = (Tab *) outputTabList.getElement(i);
507 
508     ASSERT(tab);
509     return tab;
510 }
511 
getInputParameterTabX(int i)512 int StandIn::getInputParameterTabX(int i)
513 {
514     Tab *tab;
515     tab = (Tab *) inputTabList.getElement(i);
516 
517     return tab->getTabX();
518 }
519 
getInputParameterTabY(int i)520 int StandIn::getInputParameterTabY(int i)
521 {
522     Tab *tab;
523     tab = (Tab *) inputTabList.getElement(i);
524 
525     return tab->getTabY();
526 }
527 
getOutputParameterTabX(int i)528 int StandIn::getOutputParameterTabX(int i)
529 {
530     Tab *tab;
531     tab = (Tab *) outputTabList.getElement(i);
532 
533     return tab->getTabX();
534 }
535 
getOutputParameterTabY(int i)536 int StandIn::getOutputParameterTabY(int i)
537 {
538     Tab *tab;
539     tab = (Tab *) outputTabList.getElement(i);
540 
541     return tab->getTabY();
542 }
543 
544 
545 
displayTabLabel(int index,boolean outputTab)546 void StandIn::displayTabLabel(int index, boolean outputTab)
547 {
548 char             str1[64];
549 char             str2[64];
550 XmString         xmstr1;
551 XmString         xmstr2;
552 Dimension        width;
553 Dimension        height;
554 Dimension        str1_width;
555 Dimension        str1_height;
556 Dimension        str2_width;
557 Dimension        str2_height;
558 Parameter        *p;
559 EditorWorkSpace* workspace;
560 Position         y;
561 unsigned char    alignment;
562 Dimension	 shadow_thickness;
563 XRectangle	 xrect;
564 XmFontList       font_list;
565 
566     /*network = this->node->getNetwork();*/
567     /*editor = network->getEditor();*/
568     workspace =  (EditorWorkSpace*)this->workSpace;
569 
570     if(!outputTab)
571     {
572 	p = this->node->getInputParameter(index);
573 	sprintf(str1, "%s", p->getNameString());
574 	sprintf(str2, "%s", this->node->getNameString());
575     }
576     else
577     {
578 	p = this->node->getOutputParameter(index);
579 	sprintf(str1, "%s", this->node->getNameString());
580 	sprintf(str2, "%s", p->getNameString());
581     }
582 
583 #if 0
584     if(!workspace->font_list)
585     {
586 	XFontStruct *font_struct;
587 	font_struct =
588 	    XLoadQueryFont(workspace->display, "-adobe-helvetica*bold-r*--12*");
589 	if (font_struct)
590 	{
591 	    workspace->font_list = XmFontListCreate(font_struct, "small");
592 	    XSetFont(XtDisplay(this->buttonWidget),
593 		     workspace->gc,
594 		     font_struct->fid);
595 	}
596     }
597 #endif
598 
599     // Clear the PB label
600     XtVaGetValues(this->buttonWidget,
601 		  XmNwidth, &width,
602 		  XmNheight, &height,
603 		  XmNshadowThickness, &shadow_thickness,
604 		  XmNfontList, &font_list,
605 		  NULL);
606     XClearArea(XtDisplay(this->buttonWidget), XtWindow(this->buttonWidget),
607 		shadow_thickness, shadow_thickness,
608 		width - 2*shadow_thickness, height - 2*shadow_thickness, False);
609 
610     xrect.x = shadow_thickness;
611     xrect.y = shadow_thickness;
612     xrect.width = width - 2*shadow_thickness;
613     xrect.height = height - 2*shadow_thickness;
614 
615     xmstr1 = XmStringCreateLtoR(str1, "small_canvas");
616     xmstr2 = XmStringCreateLtoR(str2, "small_canvas");
617 
618     XmStringExtent(font_list, xmstr1, &str1_width, &str1_height);
619     XmStringExtent(font_list, xmstr2, &str2_width, &str2_height);
620 
621     y = height/2 - str1_height + 1;
622     if(str1_width <= width)
623 	alignment = XmALIGNMENT_CENTER;
624     else
625 	alignment = XmALIGNMENT_BEGINNING;
626 
627     XmStringDraw(XtDisplay(this->buttonWidget),
628 		 XtWindow(this->buttonWidget),
629 		 font_list,
630 		 xmstr1,
631 		 workspace->gc,
632 		 0, y, width,
633 		 alignment,
634 		 XmSTRING_DIRECTION_L_TO_R,
635 		 &xrect);
636 
637     y = height/2 - 1;
638     if(str2_width <= width)
639 	alignment = XmALIGNMENT_CENTER;
640     else
641 	alignment = XmALIGNMENT_BEGINNING;
642     XmStringDraw(XtDisplay(this->buttonWidget),
643 		 XtWindow(this->buttonWidget),
644 		 font_list,
645 		 xmstr2,
646 		 workspace->gc,
647 		 0, y, width,
648 		 alignment,
649 		 XmSTRING_DIRECTION_L_TO_R,
650 		 &xrect);
651 
652     XmStringFree(xmstr1);
653     XmStringFree(xmstr2);
654 }
clearTabLabel()655 void StandIn::clearTabLabel()
656 {
657 //    this->setButtonLabel();
658 XmString         xmstr;
659 XmFontList       font_list;
660 Dimension        width;
661 Dimension        height;
662 Dimension        str_width;
663 Dimension        str_height;
664 EditorWorkSpace* workspace;
665 Position         y;
666 Dimension	 shadow_thickness;
667 XRectangle	 xrect;
668 
669     /*network = this->node->getNetwork();*/
670     /*editor = network->getEditor();*/
671     workspace =  (EditorWorkSpace*)this->workSpace;
672 
673     // Clear the PB label
674     XtVaGetValues(this->buttonWidget,
675 		  XmNwidth, &width,
676 		  XmNheight, &height,
677 		  XmNfontList, &font_list,
678 		  XmNshadowThickness, &shadow_thickness,
679 		  NULL);
680 
681     XClearArea(XtDisplay(this->buttonWidget), XtWindow(this->buttonWidget),
682 		shadow_thickness, shadow_thickness,
683 		width - 2*shadow_thickness, height - 2*shadow_thickness, False);
684 
685     xrect.x = shadow_thickness;
686     xrect.y = shadow_thickness;
687     xrect.width = width - 2*shadow_thickness;
688     xrect.height = height - 2*shadow_thickness;
689 
690     xmstr = this->createButtonLabel();
691 
692     XmStringExtent(font_list, xmstr, &str_width, &str_height);
693 
694     y = height/2 - str_height/2;
695 
696     XmStringDraw(XtDisplay(this->buttonWidget),
697 		 XtWindow(this->buttonWidget),
698 		 font_list,
699 		 xmstr,
700 		 workspace->gc,
701 		 0, y, width,
702 		 XmALIGNMENT_CENTER,
703 		 XmSTRING_DIRECTION_L_TO_R,
704 		 &xrect);
705     XmStringFree(xmstr);
706 }
707 
ToggleHotSpots(EditorWindow * editor,Node * destnode,boolean on)708 void StandIn::ToggleHotSpots(EditorWindow* editor,
709                     Node*    destnode,
710                     boolean  on)
711 {
712     Node*  srcnode;
713     ListIterator iterator;
714     EditorWorkSpace* workspace;
715     StandIn* standIn;
716     int       i;
717     int       icnt,ocnt;
718     int       outsrc;
719     Tab	      *tab;
720 
721 
722     standIn = destnode->getStandIn();
723     workspace = (EditorWorkSpace*)standIn->workSpace;
724 
725     ASSERT(editor);
726 
727     if (on)
728     {
729         if (workspace->origin == ORG_SOURCE)
730         {
731             /*
732              * The origin is a source node; therefore, the current node
733              * being examined is a destination node, and we must find
734              * the source node.
735              */
736             srcnode  = workspace->src.node;
737 
738             outsrc   = workspace->src.param;
739 
740             icnt = destnode->getInputCount();
741 
742             for (i=1 ; i<=icnt ; i++) {
743                    if (destnode->isInputConnected(i) ||
744                        !destnode->isInputDefaulting(i) ||
745                        !destnode->isInputVisible(i))
746                        continue;
747 
748                    if (srcnode->typeMatchOutputToInput(outsrc, destnode, i)) {
749 			tab = standIn->getInputParameterTab(i);
750 			tab->setBackground(standInDefaults.io.highlight_background);
751                    }
752             }
753         }
754         else
755         {
756 
757             /*
758              * The origin is a destination node; therefore, the current
759              * node being examined is a source node, and we must find
760              * the destination node.
761              */
762             srcnode  = workspace->dst.node;
763             outsrc   = workspace->dst.param;
764 
765 
766             ocnt = destnode->getOutputCount();
767 
768             for (i=1 ; i<=ocnt ; i++)
769             {
770                 if (destnode->typeMatchOutputToInput(i, srcnode, outsrc)){
771 		    tab = standIn->getOutputParameterTab(i);
772 		    tab->setBackground(standInDefaults.io.highlight_background);
773 		}
774             }
775         }
776 
777     }
778     else
779     {
780 
781         if (workspace->origin == ORG_SOURCE) {
782             icnt = destnode->getInputCount();
783 
784             for (i=1 ; i<=icnt ; i++) {
785                 if (destnode->isInputConnected(i) ||
786                     !destnode->isInputDefaulting(i) ||
787                     !destnode->isInputVisible(i))
788                            continue;
789 
790                 srcnode  = workspace->src.node;
791                 outsrc   = workspace->src.param;
792 
793 
794                 if (srcnode->typeMatchOutputToInput(outsrc, destnode, i)) {
795 
796 		    tab = standIn->getInputParameterTab(i);
797 		    tab->setBackground(destnode->isInputRequired(i) ?
798                                       standInDefaults.io.required_background :
799                                       standInDefaults.io.background);
800                  }
801             }
802         }
803         else
804         {
805 
806             srcnode  = workspace->dst.node;
807             outsrc   = workspace->dst.param;
808 
809             ocnt = destnode->getOutputCount();
810 
811             for (i=1 ; i<=ocnt ; i++) {
812                 if (destnode->typeMatchOutputToInput(i, srcnode, outsrc)) {
813 		    tab = standIn->getOutputParameterTab(i);
814 		    tab->setBackground(standInDefaults.io.background);
815 		}
816             }
817         }
818     }
819 }
820 
821 
StandIn_TrackArkEH(Widget widget,XtPointer clientData,XEvent * event,Boolean *)822 extern "C" void StandIn_TrackArkEH(Widget widget,
823                 XtPointer clientData,
824                 XEvent* event,
825 		Boolean *)
826 {
827     Node *node = (Node *) clientData;
828     StandIn *standIn = node->getStandIn();
829     ASSERT(standIn);
830     standIn->trackArk(widget, event);
831 }
832 
trackArk(Widget widget,XEvent * event)833 void StandIn::trackArk(Widget widget, XEvent *event)
834 {
835     Network*      network;
836     Node*         node;
837     Node*         nodePtr;
838     StandIn*      standInPtr;
839     StandIn*      curNodeStandInPtr = NUL(StandIn*);
840     EditorWindow* editor;
841     EditorWorkSpace*    workspace;
842     ListIterator  iterator;
843     Widget        hot_spot;
844     Widget        bboard;
845     Window        window;
846     int           x,y;
847     Widget	  labeled_tab;
848 
849     node = this->node;
850     network = node->getNetwork();
851     editor = network->getEditor();
852     workspace =  (EditorWorkSpace*)this->workSpace;
853 
854     if (workspace->first)
855     {
856         workspace->first = FALSE;
857     }
858     else
859     {
860         /*
861          * Remove the previous line.
862          */
863         XDrawLine(workspace->display,
864                   XtWindow(workspace->getRootWidget()),
865                   workspace->gc_xor,
866                   workspace->first_x + workspace->start_x,
867                   workspace->first_y + workspace->start_y,
868                   workspace->last_x  + workspace->start_x,
869                   workspace->last_y  + workspace->start_y);
870     }
871 
872     /*
873      * Determine if we are in a node boundary.
874      */
875     XTranslateCoordinates(workspace->display,
876                           XtWindow(widget),
877                           XtWindow(workspace->getRootWidget()),
878                           event->xbutton.x,
879                           event->xbutton.y,
880                           &x,
881                           &y,
882                           &window);
883 
884     if (window == None)
885     {
886         if (workspace->hot_spot)
887         {
888             ToggleHotSpots
889                 (editor, workspace->hot_spot_node , FALSE);
890                  workspace->hot_spot = NUL(Widget);
891         }
892 	if(workspace->labeled_tab)
893 	{
894 	    workspace->labeled_si->clearTabLabel();
895 	    workspace->labeled_tab = NULL;
896 	}
897     }
898     else
899     {
900         /*
901          * Convert windows to widgets.
902          */
903         hot_spot = XtWindowToWidget(workspace->display, window);
904 
905         FOR_EACH_NETWORK_NODE(network, nodePtr, iterator)
906 	{
907             standInPtr = nodePtr->getStandIn();
908 #if WORKSPACE_PAGES
909 	    if (standInPtr == NUL(StandIn*)) continue;
910 #endif
911             bboard = standInPtr->getRootWidget();
912 
913 	    if(hot_spot == bboard) curNodeStandInPtr = standInPtr;
914 
915 	    /*
916 	     * Turn off the previous hot spot.
917 	     */
918 	    if ((bboard == workspace->hot_spot) AND
919 		(bboard != hot_spot)            AND
920 		workspace->hot_spot)
921 	    {
922 		ToggleHotSpots
923 		    (editor, nodePtr, FALSE);
924 		workspace->hot_spot = NUL(Widget);
925 	    }
926 
927 	    /*
928 	     * Turn on the new hot spot.
929 	     */
930             if ((bboard  == hot_spot) AND
931                 (bboard  != workspace->source_spot) AND
932 		(NOT workspace->hot_spot))
933 
934             {
935 		workspace->hot_spot      = hot_spot;
936 		workspace->hot_spot_node = nodePtr;
937 
938 		ToggleHotSpots
939 		    (editor, nodePtr, TRUE);
940             }
941         }
942 	/*
943 	 * Determine if we are in a tab boundary.
944 	 */
945 	XTranslateCoordinates(workspace->display,
946 			      XtWindow(widget),
947 			      window,
948 			      event->xbutton.x,
949 			      event->xbutton.y,
950 			      &x,
951 			      &y,
952 			      &window);
953 	labeled_tab = XtWindowToWidget(workspace->display, window);
954 
955 	if(labeled_tab AND
956 	   (labeled_tab != workspace->labeled_tab))
957 	{
958 	    workspace->labeled_si->clearTabLabel();
959 	    workspace->labeled_tab = NULL;
960 	}
961 	if ((labeled_tab) && (curNodeStandInPtr))
962 	{
963 	    Tab *tab;
964 	    int i;
965 	    boolean found;
966 
967 	    found = FALSE;
968 	    int count = curNodeStandInPtr->node->getInputCount();
969 	    for (i = 1; i <= count ; i++ )
970 	    {
971 		tab = (Tab *) curNodeStandInPtr->inputTabList.getElement(i);
972 		if(labeled_tab == tab->getRootWidget())
973 		{
974 		    if(workspace->labeled_tab != labeled_tab)
975 		    {
976 			workspace->labeled_tab = labeled_tab;
977 			workspace->labeled_si = curNodeStandInPtr;
978 			curNodeStandInPtr->displayTabLabel(i, FALSE);
979 		    }
980 		    found = TRUE;
981 		    break;
982 		}
983 	    }
984 	    if(!found)
985 	    {
986 	        count = curNodeStandInPtr->node->getOutputCount();
987 		for (i = 1; i <= count; i++)
988 		{
989 		    tab = (Tab *)curNodeStandInPtr->outputTabList.getElement(i);
990 		    if(labeled_tab == tab->getRootWidget())
991 		    {
992 			if(workspace->labeled_tab != labeled_tab)
993 			{
994 			    workspace->labeled_tab = labeled_tab;
995 			    workspace->labeled_si = curNodeStandInPtr;
996 			    curNodeStandInPtr->displayTabLabel(i, TRUE);
997 			}
998 			found = TRUE;
999 			break;
1000 		    }
1001 		}
1002 	    }
1003 	    if(!found && workspace->labeled_tab)
1004 	    {
1005 		curNodeStandInPtr->clearTabLabel();
1006 		workspace->labeled_tab = NULL;
1007 	    }
1008 	}
1009 	else if ((workspace->labeled_tab) && (curNodeStandInPtr))
1010 	{
1011 	    curNodeStandInPtr->clearTabLabel();
1012 	    workspace->labeled_tab = NULL;
1013 	}
1014     }
1015 
1016     /*
1017      * Draw the new line.
1018      */
1019     workspace->last_x = event->xmotion.x_root;
1020     workspace->last_y = event->xmotion.y_root;
1021 
1022     XDrawLine(workspace->display,
1023               XtWindow(workspace->getRootWidget()),
1024               workspace->gc_xor,
1025               workspace->first_x + workspace->start_x,
1026               workspace->first_y + workspace->start_y,
1027               workspace->last_x  + workspace->start_x,
1028               workspace->last_y  + workspace->start_y);
1029 }
1030 
1031 
StandIn_ArmInputCB(Widget widget,XtPointer clientData,XtPointer cdata)1032 extern "C" void StandIn_ArmInputCB(Widget widget,
1033                 XtPointer clientData,
1034                 XtPointer cdata)
1035 {
1036     Node *node = (Node *) clientData;
1037     StandIn *standIn = node->getStandIn();
1038     ASSERT(standIn);
1039     standIn->armInput(widget, cdata);
1040 }
1041 
armInput(Widget widget,XtPointer cdata)1042 void StandIn::armInput(Widget widget, XtPointer cdata)
1043 {
1044     Node*         node;
1045     Node*         node2;
1046     StandIn*      standIn2;
1047     EditorWorkSpace*    workspace;
1048     ListIterator  iterator;
1049     XEvent*       event;
1050     Ark*          a;
1051     List*         arcs;
1052     int           paramInd;
1053     Tab*          tab;
1054     int           n;
1055     int           i;
1056     int           j;
1057     Position      nx;
1058     Position      ny;
1059     Position      px;
1060     Position      py;
1061     int           cursor;
1062     Arg           arg[4];
1063     XmAnyCallbackStruct* callData = (XmAnyCallbackStruct*) cdata;
1064 
1065 
1066     ASSERT(widget);
1067 
1068     node = this->node;
1069     /*network = node->getNetwork();*/
1070     /*editor = network->getEditor();*/
1071     workspace =  (EditorWorkSpace*)this->workSpace;
1072 
1073 
1074     event   = callData->event;
1075 
1076     if (event->type != ButtonPress)
1077     {
1078         return;
1079     }
1080 
1081     /*
1082      * Get pointers to the node and the param of the destination
1083      * end of the arc and remember it.
1084      */
1085 
1086 
1087     iterator.setList(this->inputTabList);
1088     for (i = 1; (tab = (Tab*)iterator.getNext()) ; i++) {
1089         if (tab->getRootWidget() == widget) {
1090             break;
1091         }
1092     }
1093 
1094     workspace->src.node  = NULL;
1095     workspace->src.param = -1;
1096 
1097     // Display the parameter name
1098     workspace->labeled_tab = widget;
1099     workspace->labeled_si = this;
1100     this->displayTabLabel(i, FALSE);
1101 
1102     /*
1103      * If this input parameter is "pressed in" (in use),
1104      * then no need to go further.
1105      */
1106     if (!node->isInputDefaulting(i) &&
1107 	!node->isInputConnected(i))
1108     {
1109         workspace->dst.node  = NULL;
1110         workspace->dst.param = -1;
1111         return;
1112     }
1113 
1114     /*
1115      * Get the current locations of the node and param.
1116      */
1117     Widget standInRoot = this->getRootWidget();
1118     n = 0;
1119     XtSetArg(arg[n], XmNx, &nx); n++;
1120     XtSetArg(arg[n], XmNy, &ny); n++;
1121     XtGetValues(standInRoot, arg, n);
1122 
1123     n = 0;
1124     XtSetArg(arg[n], XmNx, &px); n++;
1125     XtSetArg(arg[n], XmNy, &py); n++;
1126     XtGetValues(widget, arg, n);
1127 
1128     /*
1129      * Set up tracking params.
1130      */
1131     workspace->tracker     = (XtEventHandler)StandIn_TrackArkEH;
1132     workspace->io_tab      = widget;
1133     workspace->source_spot = standInRoot;
1134     workspace->first       = TRUE;
1135 
1136     /*
1137      * Get current node and param location.
1138      */
1139     workspace->first_x =
1140         (event->xbutton.x_root - event->xbutton.x)
1141         + standInDefaults.io.width / 2;
1142 
1143     workspace->first_y =
1144         (event->xbutton.y_root - event->xbutton.y);
1145 
1146     workspace->start_x =
1147         (nx + px + event->xbutton.x) - event->xbutton.x_root;
1148     workspace->start_y =
1149         (ny + py + event->xbutton.y) - event->xbutton.y_root;
1150 
1151     if (node->isInputConnected(i))
1152     {
1153 	  // Remember the dst node and param so that we can set the param's
1154 	  // defaulting status if the user winds up deleting an arc.
1155 	  workspace->dst.node  = node;
1156 	  workspace->dst.param = i;
1157 
1158         /*
1159          * If the input tab is already connected, we need to anchor the
1160          * rubber band line from the output node....
1161          * So, find the other end, and remember it.
1162          */
1163 
1164 
1165           arcs = (List *) node->getInputArks(i);
1166 
1167           for (j = 1; (a = (Ark*) arcs->getElement(j)) != NULL; j++) {
1168             a->getDestinationNode(paramInd);
1169             if (paramInd == i) {
1170               break;
1171             }
1172           }
1173 
1174           workspace->remove_arcs = True;
1175           workspace->arc = a;
1176 
1177           node2 = a->getSourceNode(paramInd);
1178 
1179           standIn2 = node2->getStandIn();
1180 
1181           ASSERT(node2);
1182 
1183           workspace->src.node  = node2;
1184           workspace->src.param = paramInd;
1185 
1186         /*
1187          * Get the pointers to the source node and param.
1188          */
1189 
1190         /*
1191          * Start rubber band from source node.
1192          */
1193         workspace->first_x -= nx + px;
1194         workspace->first_y -= ny + py;
1195 
1196         /*
1197          * Get (x, y) of the bulletinboard and output tab widget.
1198          */
1199         n = 0;
1200         XtSetArg(arg[n], XmNx, &nx); n++;
1201         XtSetArg(arg[n], XmNy, &ny); n++;
1202         XtGetValues(standIn2->getRootWidget(), arg, n);
1203 
1204         n = 0;
1205         XtSetArg(arg[n], XmNx, &px); n++;
1206         XtSetArg(arg[n], XmNy, &py); n++;
1207         XtGetValues(standIn2->getOutputParameterTab(paramInd)->getRootWidget(), 		arg, n);
1208 
1209         workspace->first_x += nx + px;
1210         workspace->first_y += ny + py + standInDefaults.io.height;
1211 
1212         workspace->origin = ORG_SOURCE;
1213 
1214         cursor = DOWN_CURSOR;
1215 
1216 
1217         /*
1218          * Reset the source widget to be the source node.
1219          */
1220         workspace->source_spot = standIn2->getRootWidget();
1221     }
1222     else
1223     {
1224         /*
1225          * If the input tab is not currently connected,
1226          * then there is no source (output) tab to disconnect.
1227          */
1228 
1229         workspace->dst.node  = node;
1230         workspace->dst.param = i;
1231 
1232         workspace->origin = ORG_DESTINATION;
1233 
1234         cursor = UP_CURSOR;
1235     }
1236 
1237     /*
1238      * Prepare for tracking.
1239      */
1240     XGrabPointer(workspace->display,
1241                  XtWindow(widget),
1242                  FALSE,
1243                  ButtonPressMask | ButtonMotionMask | ButtonReleaseMask,
1244                  GrabModeAsync,
1245                  GrabModeAsync,
1246                  XtWindow(workspace->getRootWidget()),
1247                  workspace->cursor[cursor],
1248                  CurrentTime);
1249     /*
1250      * Draw the initial line.
1251      */
1252     workspace->last_x = event->xmotion.x_root;
1253     workspace->last_y = event->xmotion.y_root;
1254 
1255     XDrawLine(workspace->display,
1256               XtWindow(workspace->getRootWidget()),
1257               workspace->gc_xor,
1258               workspace->first_x + workspace->start_x,
1259               workspace->first_y + workspace->start_y,
1260               workspace->last_x  + workspace->start_x,
1261               workspace->last_y  + workspace->start_y);
1262 
1263     workspace->first = FALSE;
1264 
1265     /*
1266      * Add cursor tracking handler.
1267      */
1268     XtAddEventHandler(widget,
1269                       ButtonMotionMask,
1270                       FALSE,
1271                       workspace->tracker,
1272                       (XtPointer)node);
1273 }
1274 
1275 
StandIn_ArmOutputCB(Widget widget,XtPointer clientData,XtPointer cdata)1276 extern "C" void StandIn_ArmOutputCB(Widget widget,
1277                 XtPointer clientData,
1278                 XtPointer cdata)
1279 {
1280     Node *node = (Node *) clientData;
1281     StandIn *standIn = node->getStandIn();
1282     ASSERT(standIn);
1283     standIn->armOutput(widget, cdata);
1284 }
1285 
armOutput(Widget widget,XtPointer cdata)1286 void StandIn::armOutput(Widget widget, XtPointer cdata)
1287 {
1288     Node*    node;
1289     EditorWorkSpace*    workspace;
1290     XEvent*     event;
1291     int         n;
1292     int         i;
1293     Position    nx;
1294     Position    ny;
1295     Position    px;
1296     Position    py;
1297     int         cursor;
1298     Arg         arg[4];
1299     XmAnyCallbackStruct* callData = (XmAnyCallbackStruct*) cdata;
1300     Tab         *tab;
1301 
1302     ASSERT(widget);
1303 
1304     node = this->node;
1305     /*network = node->getNetwork();*/
1306     /*editor = network->getEditor();*/
1307     workspace =  (EditorWorkSpace*)this->workSpace;
1308 
1309 
1310     event   = callData->event;
1311 
1312     if (event->type != ButtonPress)
1313     {
1314         return;
1315     }
1316 
1317     /*
1318      * Get pointers to the node and the param.
1319      */
1320 
1321     ListIterator iterator(this->outputTabList);
1322     for (i = 1; (tab = (Tab*)iterator.getNext()) ; i++) {
1323         if (tab->getRootWidget() == widget) {
1324             break;
1325         }
1326     }
1327 
1328     // Display the parameter name
1329     workspace->labeled_tab = widget;
1330     workspace->labeled_si = this;
1331     this->displayTabLabel(i, TRUE);
1332 
1333     /*
1334      * Remember the source (output) end of the arc (no destination yet).
1335      */
1336     workspace->src.node  = node;
1337     workspace->src.param = i;
1338 
1339     workspace->dst.node  = NULL;
1340     workspace->dst.param = -1;
1341 
1342 
1343     /*
1344      * Get the current locations of the node and param.
1345      */
1346     Widget standInRoot = this->getRootWidget();
1347     n = 0;
1348     XtSetArg(arg[n], XmNx, &nx); n++;
1349     XtSetArg(arg[n], XmNy, &ny); n++;
1350     XtGetValues(standInRoot, arg, n);
1351 
1352     n = 0;
1353     XtSetArg(arg[n], XmNx, &px); n++;
1354     XtSetArg(arg[n], XmNy, &py); n++;
1355     XtGetValues(tab->getRootWidget(), arg, n);
1356 
1357     /*
1358      * Set up tracking params.
1359      */
1360     workspace->tracker     = (XtEventHandler)StandIn_TrackArkEH;
1361     workspace->io_tab      = widget;
1362     workspace->source_spot = standInRoot;
1363     workspace->first       = TRUE;
1364 
1365     workspace->origin = ORG_SOURCE;
1366 
1367     cursor = DOWN_CURSOR;
1368 
1369     workspace->first_x =
1370         (event->xbutton.x_root - event->xbutton.x) +
1371          standInDefaults.io.width / 2;
1372     workspace->first_y =
1373         (event->xbutton.y_root - event->xbutton.y) + standInDefaults.io.height;
1374 
1375     workspace->start_x =
1376         (nx + px + event->xbutton.x) - event->xbutton.x_root;
1377     workspace->start_y =
1378         (ny + py + event->xbutton.y) - event->xbutton.y_root;
1379 
1380     /*
1381      * Prepare for tracking.
1382      */
1383     XGrabPointer(workspace->display,
1384                  XtWindow(widget),
1385                  FALSE,
1386                  ButtonPressMask | ButtonMotionMask | ButtonReleaseMask,
1387                  GrabModeAsync,
1388                  GrabModeAsync,
1389                  XtWindow(workspace->getRootWidget()),
1390                  workspace->cursor[cursor],
1391                  CurrentTime);
1392     /*
1393      * Add cursor tracking handler.
1394      */
1395     XtAddEventHandler(widget,
1396                       ButtonMotionMask,
1397                       FALSE,
1398                       workspace->tracker,
1399                       (XtPointer)node);
1400 }
1401 
deleteArk(Ark * a)1402 void StandIn::deleteArk(Ark *a)
1403 {
1404     EditorWindow* editor = this->node->getNetwork()->getEditor();
1405     if (editor) editor->notifyArk(a,FALSE);
1406     delete a;
1407 }
1408 
StandIn_DisarmTabCB(Widget widget,XtPointer clientData,XtPointer cdata)1409 extern "C" void StandIn_DisarmTabCB(Widget widget,
1410                 XtPointer clientData,
1411                 XtPointer cdata)
1412 {
1413     XUngrabPointer(XtDisplay(widget), CurrentTime);
1414     XFlush(XtDisplay(widget));
1415     Node *node = (Node *) clientData;
1416     StandIn *standIn = node->getStandIn();
1417     ASSERT(standIn);
1418     standIn->disarmTab(widget, cdata);
1419 }
1420 
disarmTab(Widget widget,XtPointer cdata)1421 void StandIn::disarmTab(Widget widget, XtPointer cdata)
1422 {
1423     XEvent*        event;
1424     Network*       network;
1425     Node*          node;
1426     Node*          nodePtr = NULL;
1427     EditorWorkSpace*     workspace;
1428     EditorWindow*  editor;
1429     StandIn	   *standIn = NULL;
1430     int            icnt;
1431     ListIterator   iterator;
1432     Node*          node2;
1433     Node*          to_node = NULL;
1434     int            to_param = -1;
1435     Ark*           newArk;
1436     int            param2;
1437     int         i;
1438     int         x;
1439     int         y;
1440     int         ocnt;
1441     Widget      n_widget;
1442     Widget      t_widget = (Widget)None;
1443     Window      n_window;
1444     Window      t_window;
1445     XmAnyCallbackStruct* callData = (XmAnyCallbackStruct*) cdata;
1446     static char *type_error =
1447 	"Output parameter type and input parameter type do not match.";
1448     static char *cycle_error = "Connections cannot be cyclic.";
1449     static char *connect_error = "The input is already connected or set.";
1450 
1451     ASSERT(widget);
1452     ASSERT(callData);
1453 
1454     node = this->node;
1455     network = node->getNetwork();
1456     editor = network->getEditor();
1457     workspace =  (EditorWorkSpace*)this->workSpace;
1458 
1459     event   = callData->event;
1460 
1461     /*
1462      * Release the pointer.
1463      */
1464     XUngrabPointer(workspace->display, CurrentTime);
1465 
1466     /*
1467      * If there is a tracking routine installed, remove it.
1468      * Otherwise, no need to process further (since one of
1469      * the arming routines didn't need to track the cursor).
1470      */
1471     if (workspace->tracker)
1472     {
1473         XtRemoveEventHandler(workspace->io_tab,
1474                              ButtonMotionMask,
1475                              FALSE,
1476                              workspace->tracker,
1477                              (XtPointer)node);
1478         workspace->tracker = NUL(XtEventHandler);
1479     }
1480     else
1481     {
1482 	// Clear the parameter name if required
1483 	if(workspace->labeled_tab)
1484 	{
1485 	    workspace->labeled_si->clearTabLabel();
1486 	    workspace->labeled_tab = NULL;
1487 	}
1488         return;
1489     }
1490 
1491     /*
1492      * Determine where the cursor stopped.
1493      */
1494     Window src_w = XtWindow(widget);
1495     Window dst_w = XtWindow(workspace->getRootWidget());
1496     XTranslateCoordinates(workspace->display,
1497                           src_w, //XtWindow(widget),
1498                           dst_w, //XtWindow(workspace->getRootWidget()),
1499                           event->xbutton.x,
1500                           event->xbutton.y,
1501                           &x,
1502                           &y,
1503                           &n_window);
1504 
1505     /*
1506      * If the release point is in the node....
1507      */
1508     if (n_window != None)
1509     {
1510 
1511         /*
1512          * Determine which node bboard widget the cursor is in.
1513          */
1514         XTranslateCoordinates(workspace->display,
1515                               XtWindow(workspace->getRootWidget()),
1516                               n_window,
1517                               x,
1518                               y,
1519                               &x,
1520                               &y,
1521                               &t_window);
1522 
1523         n_widget = XtWindowToWidget(workspace->display, n_window);
1524 
1525         FOR_EACH_NETWORK_NODE(network, nodePtr, iterator)
1526         {
1527             standIn = nodePtr->getStandIn();
1528 #if WORKSPACE_PAGES
1529 	    if (!standIn) continue;
1530 #endif
1531             if (standIn->getRootWidget() == n_widget) {
1532 		if (standIn->workSpace != workspace) {
1533 		    ErrorMessage ("Connections cannot cross page boundaries");
1534 		    /*
1535 		     * Remove the last line.
1536 		     */
1537 		    XDrawLine(workspace->display,
1538 			      XtWindow(workspace->getRootWidget()),
1539 			      workspace->gc_xor,
1540 			      workspace->first_x + workspace->start_x,
1541 			      workspace->first_y + workspace->start_y,
1542 			      workspace->last_x + workspace->start_x,
1543 			      workspace->last_y + workspace->start_y);
1544 		    return ;
1545 		}
1546                 break;
1547             }
1548         }
1549 
1550 	if (!nodePtr) {
1551 	    /*
1552 	     * Remove the last line.
1553 	     */
1554 	    XDrawLine(workspace->display,
1555 		      XtWindow(workspace->getRootWidget()),
1556 		      workspace->gc_xor,
1557 		      workspace->first_x + workspace->start_x,
1558 		      workspace->first_y + workspace->start_y,
1559 		      workspace->last_x + workspace->start_x,
1560 		      workspace->last_y + workspace->start_y);
1561 	    return ;
1562 	}
1563 
1564         /*
1565          * Determine which child widget of the node bulletinboard widget
1566          * the cursor is in, if any.
1567          */
1568         if (t_window == None)
1569         {
1570             t_widget = NUL(Widget);
1571         }
1572         else
1573         {
1574             t_widget = XtWindowToWidget(workspace->display, t_window);
1575         }
1576 
1577         /*
1578          * If the pointer is in the node button widget or just on the
1579          * bulletin widget, calculate the left-most legal connection,
1580          * if any.
1581          */
1582         if (t_widget == standIn->buttonWidget OR t_widget == NUL(Widget))
1583         {
1584             if (workspace->origin == ORG_SOURCE)
1585             {
1586                 node2  = workspace->src.node;
1587                 param2 = workspace->src.param;
1588 
1589                 icnt = nodePtr->getInputCount();
1590                 for(i=1; i<=icnt; i++) {
1591                     if (nodePtr->isInputConnected(i) ||
1592                         !nodePtr->isInputDefaulting(i) ||
1593                         !nodePtr->isInputVisible(i))
1594                         continue;
1595                     //
1596                     // Make sure the input types match
1597                     //
1598                     if (node2->typeMatchOutputToInput(param2,
1599                                                       nodePtr,
1600                                                       i))
1601                         {
1602                             to_node = nodePtr;
1603                             to_param = i;
1604                             break;
1605                         }
1606                     }
1607             }
1608             else
1609             {
1610                 node2  = workspace->dst.node;
1611                 param2 = workspace->dst.param;
1612 
1613                 ocnt = nodePtr->getOutputCount();
1614                 for(i=1; i<=ocnt; i++) {
1615                     if (!nodePtr->isOutputVisible(i))
1616                         continue;
1617                     if (nodePtr->typeMatchOutputToInput(i, node2, param2))
1618                         {
1619                             to_node = nodePtr;
1620                             to_param = i;
1621                             break;
1622                         }
1623                 }
1624             }
1625         }
1626 
1627         /*
1628          * Else if the cursor is in a input tab widget, determine which
1629          * input parameter it corresponds to.
1630          */
1631         else if (workspace->origin == ORG_SOURCE)
1632         {
1633             node2  = workspace->src.node;
1634             param2 = workspace->src.param;
1635 
1636             icnt = nodePtr->getInputCount();
1637             for(i=1; i<=icnt; i++) {
1638                 if (standIn->getInputParameterTab(i)->getRootWidget()==t_widget)
1639                 {
1640 		    if(!nodePtr->isInputDefaulting(i)){
1641 		    	if(widget == t_widget) break;
1642 			ErrorMessage(connect_error);
1643 			break;
1644 		    }
1645                     if (node2->typeMatchOutputToInput(param2,
1646                                                       nodePtr,
1647                                                       i)) {
1648                         to_node = nodePtr;
1649                         to_param = i;
1650                     } else {
1651 			ErrorMessage(type_error);
1652                     }
1653 		    break;
1654                 }
1655             }
1656         /*
1657          * Else the cursor has to be in an output tab widget; determine
1658          * which output parameter it corresponds to.
1659          */
1660         } else {
1661                 node2  = workspace->dst.node;
1662                 param2 = workspace->dst.param;
1663 
1664                 ocnt = nodePtr->getOutputCount();
1665 
1666                 for(i=1; i<=ocnt; i++) {
1667                     if (standIn->getOutputParameterTab(i)->getRootWidget() == t_widget)
1668                     {
1669                         if (nodePtr->typeMatchOutputToInput(i, node2, param2))
1670                         {
1671                             to_node = nodePtr;
1672                             to_param = i;
1673                         } else {
1674 			    ErrorMessage(type_error);
1675                         }
1676                         break;
1677                     }
1678 
1679                 }
1680           }
1681      }
1682 
1683 
1684     /*
1685      * If cursor moved...
1686      */
1687     if (NOT workspace->first)
1688     {
1689         /*
1690          * Remove the last line.
1691          */
1692         XDrawLine(workspace->display,
1693                   XtWindow(workspace->getRootWidget()),
1694                   workspace->gc_xor,
1695                   workspace->first_x + workspace->start_x,
1696                   workspace->first_y + workspace->start_y,
1697                   workspace->last_x + workspace->start_x,
1698                   workspace->last_y + workspace->start_y);
1699 
1700 
1701 	// Clear the parameter name if required
1702 	if(workspace->labeled_tab)
1703 	{
1704 	    workspace->labeled_si->clearTabLabel();
1705 	    workspace->labeled_tab = NULL;
1706 	}
1707 
1708         /*
1709          * Remove hot spots.
1710          */
1711         if (workspace->hot_spot && nodePtr != NULL)
1712         {
1713             ToggleHotSpots(editor, nodePtr, FALSE);
1714             workspace->hot_spot = NUL(Widget);
1715         }
1716 
1717         /*
1718          * Delete the old arc, if applicable.
1719          */
1720 	if(workspace->io_tab == t_widget) workspace->remove_arcs = FALSE;
1721         /*notified = FALSE;*/
1722         if (workspace->remove_arcs) {
1723 	      if (!standIn) {
1724 		  int dummy;
1725 		  Node* src = workspace->arc->getSourceNode(dummy);
1726 		  standIn = src->getStandIn();
1727 	      }
1728               standIn->deleteArk(workspace->arc);
1729               workspace->remove_arcs = False;
1730 
1731 	      // Reset the Defaulting status of the dst param
1732 
1733 	      node2  = workspace->dst.node;
1734 	      param2 = workspace->dst.param;
1735 	      node2->setIODefaultingStatus(param2, TRUE, TRUE, FALSE);
1736         }
1737 
1738         /*
1739          * Cause the originating parameter tab to be redrawn.
1740          */
1741         if (workspace->origin == ORG_SOURCE)
1742         {
1743             node2  = workspace->src.node;
1744             param2 = workspace->src.param;
1745         }
1746         else
1747         {
1748             node2  = workspace->dst.node;
1749             param2 = workspace->dst.param;
1750         }
1751         XtUnmanageChild(widget);
1752         XtManageChild(widget);
1753 
1754 
1755 
1756 //
1757 // Was any matching parameter found ? If not just return.
1758 //
1759         if (to_node == NULL)
1760            return;
1761 
1762         /*
1763          * Now add the new arc, if applicable.
1764          */
1765 
1766         if (workspace->origin == ORG_SOURCE) {
1767             //
1768             // Make sure adding this arc won't add a cycle
1769             //
1770             if (!network->checkForCycle(node2, to_node)) {
1771                 newArk = new Ark(node2,
1772                         param2,
1773                         to_node,
1774                         to_param);
1775                 editor->notifyArk(newArk);
1776             } else  {
1777 		/* don't complain if you drop the arc back on the
1778 		 * originating node.  this often happens when
1779 		 * disconnecting existing arcs.
1780 		 */
1781 		if (node2 != to_node)
1782 		    ErrorMessage(cycle_error);
1783             }
1784         } else {
1785             if (!network->checkForCycle(to_node, workspace->dst.node)) {
1786                 newArk = new Ark(to_node,
1787                         to_param,
1788                         workspace->dst.node,
1789                         workspace->dst.param);
1790                 editor->notifyArk(newArk);
1791             } else  {
1792 		/* see comment above about existing arcs */
1793 		if (to_node != workspace->dst.node)
1794 		    ErrorMessage(cycle_error);
1795             }
1796 
1797         }
1798     }
1799 
1800     // Clear the parameter name if required
1801     if(workspace->labeled_tab)
1802     {
1803 	workspace->labeled_si->clearTabLabel();
1804 	workspace->labeled_tab = NULL;
1805     }
1806 
1807     /*
1808      * Reinitialize the node descriptors.
1809      */
1810     workspace->origin = ORG_NONE;
1811 
1812     workspace->src.node  = NULL;
1813     workspace->src.param = 0;
1814     workspace->dst.node  = NULL;
1815     workspace->dst.param = 0;
1816 
1817     workspace->first       = TRUE;
1818     workspace->io_tab      = NUL(Widget);
1819     workspace->source_spot = NUL(Widget);
1820 }
1821 
1822 
1823 
1824 
1825 //
1826 // was _uinSelectNodeCB
1827 //
StandIn_SelectNodeCB(Widget,XtPointer clientData,XtPointer cdata)1828 extern "C" void StandIn_SelectNodeCB(Widget,
1829                 XtPointer clientData,
1830                 XtPointer cdata)
1831 {
1832     XmWorkspaceChildCallbackStruct* cb =(XmWorkspaceChildCallbackStruct*)cdata;
1833     StandIn* standin= (StandIn*) clientData;
1834 
1835     standin->setSelected(cb->status);
1836 
1837 }
1838 
handleSelectionChange(boolean select)1839 void StandIn::handleSelectionChange(boolean select)
1840 {
1841     Node *node = this->node;
1842     ASSERT(node);
1843     EditorWindow *editor = node->network->editor;
1844     ASSERT(editor);
1845 
1846     editor->handleNodeStatusChange(node,
1847 	select? Node::NodeSelected: Node::NodeDeselected);
1848 }
1849 
setButtonLabel()1850 void StandIn::setButtonLabel()
1851 {
1852     XmString string = this->createButtonLabel();
1853     Widget button = this->buttonWidget;
1854 #if 0
1855     XtVaSetValues(button,
1856 	XmNlabelString, string,
1857 	NULL);
1858 #else
1859     Arg arg[1];
1860     XtSetArg(arg[0], XmNlabelString, string);
1861     XtSetValues(button,arg,1);
1862 #endif
1863 
1864     XmFontList fonts;
1865 #if 0
1866     XtVaGetValues(button, XmNfontList, &fonts, NULL);
1867 #else
1868     XtSetArg(arg[0], XmNfontList, &fonts);
1869     XtGetValues(button,arg,1);
1870 #endif
1871 
1872     Dimension buttonHeight;
1873     Dimension buttonWidth;
1874     XmStringExtent(fonts, string, &buttonWidth, &buttonHeight);
1875 
1876     XmStringFree(string);
1877 
1878     this->requiredButtonWidth = buttonWidth + 6;
1879 
1880     int width;
1881     this->setMinimumWidth(width);
1882     this->adjustParameterLocations(width);
1883 }
1884 
createButtonLabel()1885 XmString StandIn::createButtonLabel()
1886 {
1887     XmString xms;
1888     const char *label = this->getButtonLabel();
1889     const char *font = this->getButtonLabelFont();
1890 
1891     if (theDXApplication->showInstanceNumbers()) {
1892         char buffer[128];
1893 	sprintf(buffer,"%s:%d",label,this->node->getInstanceNumber());
1894 	label = buffer;
1895     }
1896     xms = XmStringCreateLtoR((char*)label, (char*)font);
1897     return xms;
1898 }
1899 
getButtonLabel()1900 const char* StandIn::getButtonLabel()
1901 {
1902    return this->node->getNameString();
1903 }
getButtonLabelFont()1904 const char* StandIn::getButtonLabelFont()
1905 {
1906    return "canvas";
1907 }
1908 
getVisibleOutputCount()1909 int StandIn::getVisibleOutputCount()
1910 {
1911     int i;
1912     int vo = 0;
1913 
1914     for (i=1; i <= node->getOutputCount(); i++)
1915       if (node->isOutputVisible(i))
1916         vo++;
1917 
1918     return vo;
1919 }
1920 
getVisibleInputCount()1921 int StandIn::getVisibleInputCount()
1922 {
1923     int i;
1924     int vi = 0;
1925 
1926     for (i=1; i <= node->getInputCount(); i++)
1927       if (node->isInputVisible(i) && node->isInputViewable(i))
1928         vi++;
1929 
1930     return vi;
1931 }
1932 
adjustParameterLocations(int width)1933 void StandIn::adjustParameterLocations(int width)
1934 {
1935     int             vi, vo, i, x, j;
1936     int             icnt, ocnt;
1937     List            *arcs;
1938     Ark             *a;
1939     ArkStandIn      *asi;
1940     Network         *network;
1941     EditorWindow    *editor;
1942     Tab             *tab;
1943 
1944 
1945     vi = getVisibleInputCount();
1946     icnt = node->getInputCount();
1947     ocnt = node->getOutputCount();
1948 
1949     j = 0;  // use j to keep track of the visible parameters
1950 
1951 
1952     for (i = 1; i <= icnt; i++) {
1953         if ( (node->isInputVisible(i) == FALSE) ||
1954 	     (node->isInputViewable(i) == FALSE) )
1955            continue;
1956 
1957         tab = (Tab *) inputTabList.getElement(i);
1958 	if (tab == NULL)
1959 	    continue;
1960 
1961         j++;
1962 
1963         x = ((2 * (j-1) + 1) * (width)) /
1964             (2 * vi) - (standInDefaults.io.width / 2);
1965 
1966 	tab->moveTabX(x, TRUE);
1967 
1968         x =  (x + standInDefaults.io.width / 2) -
1969               standInDefaults.line.thickness / 2;
1970         if (tab->getLine() != NULL) {
1971             arcs = (List *) this->node->getInputArks(i);
1972             if (arcs->getSize() != 0) {
1973                 a = (Ark *) arcs->getElement(1);
1974                 asi = a->getArkStandIn();
1975 		if(asi) delete asi;
1976                 network = node->getNetwork();
1977                 editor = network->getEditor();
1978                 addArk(editor, a);
1979             }
1980         }
1981     }
1982 
1983 
1984     vo = getVisibleOutputCount();
1985 
1986     j = 0;
1987 
1988     for (i = 1; i <= ocnt; i++) {
1989         if (node->isOutputVisible(i) == FALSE)
1990            continue;
1991 
1992         tab = (Tab *) outputTabList.getElement(i);
1993 	if (tab == NULL)
1994 	    continue;
1995 
1996         j++;
1997 
1998         x = ((2 * (j-1) + 1) * (width)) /
1999           (2 * vo) - (standInDefaults.io.width / 2);
2000         /*n = 0;*/
2001 
2002 	//
2003 	// Move it and show it
2004 	//
2005 	tab->moveTabX(x, TRUE);
2006 	tab->manage();
2007 
2008         if (tab->getLine() != NULL) {
2009             arcs = (List *) this->node->getOutputArks(i);
2010 
2011 	    int k;
2012             for (k = 1; k <= arcs->getSize(); k++) {
2013                 a = (Ark *) arcs->getElement(k);
2014                 asi = a->getArkStandIn();
2015                 if (asi) delete asi;
2016                 network = node->getNetwork();
2017                 editor = network->getEditor();
2018                 addArk(editor, a);
2019             }
2020         }
2021     }
2022 }
2023 
createOutputTab(Widget,int ndx,int width)2024 Tab *StandIn::createOutputTab(Widget, int ndx, int width)
2025 {
2026     int      i;
2027     Position x;
2028     int      visible_outputs;
2029     Tab      *tab = new Tab(this);
2030     int	     vindex;
2031 
2032     visible_outputs = getVisibleOutputCount();
2033 
2034     vindex = 0;
2035     for(i = 1; i <= ndx; i++)
2036 	if(node->isOutputVisible(i)) vindex++ ;
2037 
2038     if(visible_outputs > 0)
2039 	x = ((2 * (vindex-1) + 1) * (width)) /
2040 	      (2 * visible_outputs) - (standInDefaults.io.width / 2);
2041     else
2042 	x = 0;
2043 
2044 
2045     tab->createTab(this->getRootWidget());
2046     XtAddEventHandler (tab->getRootWidget(), KeyPressMask, False,
2047 	(XtEventHandler)StandIn_TabKeyNavEH, (XtPointer)NULL);
2048 
2049     /*
2050      * Set background color.
2051      */
2052 
2053     tab->setBackground(standInDefaults.io.background);
2054 
2055     Position y = this->buttonHeight + standInDefaults.io.height;
2056     tab->moveTabXY(x, y, TRUE);
2057 
2058     Widget tabRoot = tab->getRootWidget();
2059     XtAddCallback(tabRoot,
2060                       XmNarmCallback,
2061                       (XtCallbackProc)StandIn_ArmOutputCB,
2062                       (XtPointer)this->node);
2063 
2064     XtAddCallback(tabRoot,
2065                       XmNdisarmCallback,
2066                       (XtCallbackProc)StandIn_DisarmTabCB,
2067                       (XtPointer)this->node);
2068 
2069 #if OLD_LESSTIF == 1
2070     char *str = "\
2071     	<Btn1Down>: Arm() \n\
2072     	<Btn1Up>: Disarm()";
2073     XtVaSetValues(tabRoot, XmNtranslations,  XtParseTranslationTable(str), NULL);
2074 #endif
2075 
2076     return tab;
2077 }
2078 
createInputTab(Widget,int ndx,int width)2079 Tab *StandIn::createInputTab(Widget, int ndx, int width)
2080 {
2081     int      i;
2082     int      visible_inputs;
2083     Position x;
2084     Tab      *tab = new Tab(this);
2085     int	     vindex;
2086 
2087     visible_inputs = getVisibleInputCount();
2088 
2089     vindex = 0;
2090     for(i = 1; i <= ndx; i++)
2091 	if(node->isInputVisible(i)) vindex++ ;
2092 
2093     if(visible_inputs > 0)
2094 	x = ((2 * (vindex-1) + 1) * (width)) /
2095 	      (2 * visible_inputs) - (standInDefaults.io.width / 2);
2096     else
2097 	x = 0;
2098 
2099 
2100     tab->createTab(this->getRootWidget());
2101     XtAddEventHandler (tab->getRootWidget(), KeyPressMask, False,
2102 	(XtEventHandler)StandIn_TabKeyNavEH, (XtPointer)NULL);
2103 
2104     /*
2105      * Set background color.
2106      */
2107 
2108     if (node->isInputRequired(ndx)) {
2109         tab->setBackground(standInDefaults.io.required_background);
2110     } else {
2111         tab->setBackground(standInDefaults.io.background);
2112     }
2113 
2114     tab->moveTabXY(x, 0, TRUE);
2115 
2116     XtAddCallback(tab->getRootWidget(),
2117                       XmNarmCallback,
2118                       (XtCallbackProc)StandIn_ArmInputCB,
2119                       (XtPointer)this->node);
2120 
2121     XtAddCallback(tab->getRootWidget(),
2122                       XmNdisarmCallback,
2123                       (XtCallbackProc)StandIn_DisarmTabCB,
2124                       (XtPointer)this->node);
2125 #if OLD_LESSTIF == 1
2126     char *str = "\
2127     	<Btn1Down>: Arm() \n\
2128     	<Btn1Up>: Disarm()";
2129     XtVaSetValues(tab->getRootWidget(), XmNtranslations,  XtParseTranslationTable(str), NULL);
2130 #endif
2131 
2132     return tab;
2133 }
2134 
2135 
createStandIn()2136 void StandIn::createStandIn()
2137 {
2138     Network              *network;
2139     long                 mask;
2140     ListIterator         iterator;
2141     Tab                  *tab;
2142     int                  n;
2143     Arg                  arg[100];
2144     int                  i;
2145     int                  icnt,ocnt;
2146     Dimension            height;
2147     Dimension            total_width;
2148     int                  width;
2149     Position             y;
2150     XmString       	 string;
2151     WorkSpace		*workspace;
2152 
2153     ASSERT(this->node);
2154     this->initialize();
2155     network = this->node->getNetwork();
2156     /*editor = network->getEditor();*/
2157     workspace = (EditorWorkSpace*)this->workSpace;
2158     Widget parent = workspace->getRootWidget();
2159 
2160     /***
2161      *** Create the node bulletin board.
2162      ***/
2163 
2164     n = 0;
2165     XtSetArg(arg[n], XmNx,            node->getVpeX());    n++;
2166     XtSetArg(arg[n], XmNy,            node->getVpeY());    n++;
2167     XtSetArg(arg[n], XmNmarginHeight, 0);                  n++;
2168     XtSetArg(arg[n], XmNmarginWidth,  0);                  n++;
2169     XtSetArg(arg[n], XmNdialogStyle,  XmDIALOG_WORK_AREA); n++;
2170     XtSetArg(arg[n], XmNresizePolicy, XmRESIZE_NONE);      n++;
2171     XtSetArg(arg[n], XmNuserData,     network);   n++;
2172 
2173     Widget standInRoot = XtCreateWidget
2174             (this->name,
2175              xmBulletinBoardWidgetClass,
2176              parent,
2177              arg,
2178              n);
2179 
2180     this->setRootWidget(standInRoot);
2181     this->setDragWidget(standInRoot);
2182 
2183     //
2184     // Provide Button2 selectability.  Prefer doing it via translation inside
2185     // Workspace widget however DragSource already applies a Button2 translation
2186     // which takes precedence.  Would have to either override that, or else
2187     // provide a method for supplying the DragSource's preferred translation.
2188     // This is fast, easy, but not flexible.
2189     //
2190     XtAddEventHandler (standInRoot, ButtonPressMask, False,
2191         (XtEventHandler)StandIn_Button2PressEH, (XtPointer)NULL);
2192     XtAddEventHandler (standInRoot, ButtonReleaseMask, False,
2193         (XtEventHandler)StandIn_Button2ReleaseEH, (XtPointer)NULL);
2194 
2195     //
2196     // Do this here, because we can do getResources() until we have
2197     // a root widget.
2198     //
2199     if (!StandIn::ClassInitialized) {
2200 
2201         standInDefaults.io.background=theDXApplication->getStandInBackground();
2202 	this->getResources((XtPointer)&standInDefaults,
2203 			_SIColorResources, XtNumber(_SIColorResources));
2204     	this->getResources((XtPointer)&standInDefaults,
2205 		       _SIResourceList,
2206 		       XtNumber(_SIResourceList));
2207 	StandIn::ClassInitialized = TRUE;
2208     }
2209 
2210     XtVaGetValues(parent, XmNlineThickness, &(standInDefaults.line.thickness), NULL);
2211 
2212     standInDefaults.line.thickness = MAX(standInDefaults.line.thickness, 1);
2213 
2214     //
2215     // Mark node as unselected
2216     //
2217 
2218     /*
2219      * Register selection callback.
2220      */
2221     this->selected = FALSE;
2222     XmWorkspaceAddCallback
2223         (standInRoot,
2224         XmNselectionCallback,
2225         (XtCallbackProc)StandIn_SelectNodeCB,
2226         (XtPointer)this);
2227 
2228     /*
2229      * Determine the border width of the bulletinboard widget
2230      */
2231 
2232     string = this->createButtonLabel();
2233 
2234     /*
2235      * Create name button.
2236      * armColor added to the list to accompany background because Motif does
2237      * adds a white border when the color map fills up if armColor isn't set.
2238      */
2239     n = 0;
2240     XtSetArg(arg[n], XmNy, standInDefaults.io.height); 		         n++;
2241     XtSetArg(arg[n], XmNborderWidth, 0);                      		 n++;
2242     XtSetArg(arg[n], XmNx,           0);                                 n++;
2243     XtSetArg(arg[n], XmNforeground,  standInDefaults.bboard.foreground); n++;
2244     XtSetArg(arg[n], XmNbackground,  standInDefaults.io.background); n++;
2245     XtSetArg(arg[n], XmNarmColor,    standInDefaults.io.background); n++;
2246     XtSetArg(arg[n], XmNlabelString, string);                            n++;
2247 
2248     Widget button = this->buttonWidget =
2249         XtCreateManagedWidget("standInButton",
2250                                xmPushButtonWidgetClass,
2251                                standInRoot, arg, n);
2252 
2253     XmStringFree(string);
2254 
2255     /*
2256      * Get created width.
2257      */
2258     n = 0;
2259     XtSetArg(arg[n], XmNheight, &height);      n++;
2260     XtSetArg(arg[n], XmNwidth, &this->requiredButtonWidth);      n++;
2261     XtGetValues(button, arg, n);
2262 
2263 
2264     this->setMinimumWidth(width);
2265 
2266     total_width = width;
2267     height += 2 * standInDefaults.io.height;
2268 
2269     this->buttonHeight = height;
2270 
2271     n = 0;
2272     XtSetArg(arg[n], XmNheight,        this->buttonHeight); n++;
2273     XtSetArg(arg[n], XmNrecomputeSize, FALSE);  n++;
2274     XtSetValues(button, arg, n);
2275 
2276 
2277     /***
2278      *** Create input param buttons.
2279      ***/
2280 
2281     string = XmStringCreateLtoR("", "canvas");
2282 
2283     y  = 0;
2284 #if 0
2285     n0 = 0;
2286     XtSetArg(arg[n0], XmNlabelString, string);                       n0++;
2287     XtSetArg(arg[n0], XmNwidth,       standInDefaults.io.width);     n0++;
2288     XtSetArg(arg[n0], XmNheight,      standInDefaults.io.height);    n0++;
2289     XtSetArg(arg[n0], XmNborderWidth, 0);                 n0++;
2290     XtSetArg(arg[n0], XmNfillOnArm,   FALSE);                        n0++;
2291     XtSetArg(arg[n0], XmNy,           y);                            n0++;
2292 #endif
2293 
2294 
2295     icnt = node->getInputCount();
2296 
2297 
2298     /*visible_inputs = getVisibleInputCount();*/
2299     /*visible_outputs = getVisibleOutputCount();*/
2300 
2301 
2302     for(i=1; i<=icnt; i++)
2303     {
2304 
2305         tab = new Tab(this);
2306         if (node->isInputViewable(i)) {
2307             tab->createTab(standInRoot,node->isInputVisible(i));
2308 	    XtAddEventHandler (tab->getRootWidget(), KeyPressMask, False,
2309 		(XtEventHandler)StandIn_TabKeyNavEH, (XtPointer)NULL);
2310 	}
2311 	tab->moveTabY(0, FALSE);
2312 	tab->setBackground(standInDefaults.io.background);
2313 	inputTabList.appendElement((void *) tab);
2314 
2315 	Widget tabRoot = tab->getRootWidget();
2316 	if(tabRoot)
2317 	{
2318 	    XtAddCallback(tabRoot,
2319 			      XmNarmCallback,
2320 			      (XtCallbackProc)StandIn_ArmInputCB,
2321 			      (XtPointer)this->node);
2322 
2323 	    XtAddCallback(tabRoot,
2324 			      XmNdisarmCallback,
2325 			      (XtCallbackProc)StandIn_DisarmTabCB,
2326 			      (XtPointer)this->node);
2327 
2328 #if OLD_LESSTIF == 1
2329 	    char *str = "\
2330 		<Btn1Down>: Arm() \n\
2331 		<Btn1Up>: Disarm()";
2332 	    XtVaSetValues(tabRoot, XmNtranslations,  XtParseTranslationTable(str), NULL);
2333 #endif
2334 	}
2335     }
2336 
2337     /***
2338      *** Create output param buttons.
2339      ***/
2340 
2341     y = height + standInDefaults.io.height;
2342 
2343     ocnt = node->getOutputCount();
2344 
2345 
2346     for (i=1; i<=ocnt; i++) {
2347         tab = new Tab(this);
2348         if (node->isOutputViewable(i)) {
2349             tab->createTab(standInRoot,node->isOutputVisible(i));
2350 	    XtAddEventHandler (tab->getRootWidget(), KeyPressMask, False,
2351 		(XtEventHandler)StandIn_TabKeyNavEH, (XtPointer)NULL);
2352 	}
2353 
2354 	tab->moveTabY(y, TRUE);
2355 	tab->setBackground(standInDefaults.io.background);
2356 	outputTabList.appendElement((void *) tab);
2357 
2358 	Widget tabRoot = tab->getRootWidget();
2359 	if(tabRoot)
2360 	{
2361 	    XtAddCallback(tabRoot,
2362 			      XmNarmCallback,
2363 			      (XtCallbackProc)StandIn_ArmOutputCB,
2364 			      (XtPointer)this->node);
2365 
2366 	    XtAddCallback(tabRoot,
2367 			      XmNdisarmCallback,
2368 			      (XtCallbackProc)StandIn_DisarmTabCB,
2369 			      (XtPointer)this->node);
2370 
2371 #if OLD_LESSTIF == 1
2372 	    char *str = "\
2373 		<Btn1Down>: Arm() \n\
2374 		<Btn1Up>: Disarm()";
2375 	    XtVaSetValues(tabRoot, XmNtranslations,  XtParseTranslationTable(str), NULL);
2376 #endif
2377 	}
2378     }
2379     this->setMinimumWidth(width);
2380     this->adjustParameterLocations(width);
2381     XmStringFree(string);
2382 
2383     /***
2384      *** Center and display the widgets.
2385      ***/
2386 
2387     /*
2388      * Get and save widget size and location.
2389      */
2390     height += 2 * (standInDefaults.io.height);
2391     this->setXYSize(total_width, height);
2392 
2393     /*
2394      * Display it.
2395      */
2396     this->manage();
2397 
2398     mask = ButtonPressMask | ButtonReleaseMask | ButtonMotionMask |
2399 	KeyPressMask | KeyReleaseMask;
2400     StandIn::ModifyButtonWindowAttributes (button, mask);
2401 #if XmVersion >= 1001
2402 // FIXME
2403 //    XtAddEventHandler(this->getRootWidget(), ButtonPressMask,
2404 //                      FALSE, _uinHelpEventHandler, (XtPointer)NULL);
2405 #endif
2406 
2407 }
2408 
2409 //
2410 // Was part of ::createStandIn().  ...is now broken out so that it
2411 // can be used on the io tabs as well as the main part of the standin.
2412 // We want to pass thru kbd events on io tabs so that keyboard events
2413 // will work in the vpe.
2414 //
ModifyButtonWindowAttributes(Widget button,int mask)2415 void StandIn::ModifyButtonWindowAttributes (Widget button, int mask)
2416 {
2417     /*
2418      * Make sure button and motion events get passed through.
2419      */
2420     Window button_window = XtWindow(button);
2421     if (!button_window) {
2422 	printf ("%s[%d] no window to modify\n", __FILE__,__LINE__);
2423 	return ;
2424     }
2425     Display *dsp = XtDisplay(button);
2426     XWindowAttributes    getatt;
2427 
2428     //
2429     // Arrange to call XGetWindowAttributes only once.  It's too
2430     // expensive an unnecessary to do every time we create a StandIn.
2431     //
2432     static boolean getatt_initialized = FALSE;
2433     static int your_event_mask = 0;
2434     static int do_not_propagate_mask = 0;
2435 
2436     if (!getatt_initialized) {
2437 	XGetWindowAttributes(dsp, button_window, &getatt);
2438 	//getatt_initialized = TRUE;
2439 	your_event_mask = getatt.your_event_mask;
2440 	do_not_propagate_mask = getatt.do_not_propagate_mask;
2441     }
2442 
2443     XSetWindowAttributes setatt;
2444     setatt.event_mask            = your_event_mask & ~mask;
2445     setatt.do_not_propagate_mask = do_not_propagate_mask & ~mask;
2446 
2447     XChangeWindowAttributes(dsp,
2448                             button_window,
2449                             CWEventMask | CWDontPropagate,
2450                             &setatt);
2451 
2452 }
2453 
drawArks(Node *)2454 void StandIn::drawArks(Node* )
2455 {
2456 }
2457 
addArk(EditorWindow * editor,Ark * a)2458 void StandIn::addArk(EditorWindow* editor, Ark *a)
2459 {
2460     EditorWorkSpace*      workspace;
2461     StandIn*        src_standIn;
2462     StandIn*        dst_standIn;
2463     ArkStandIn*     asi;
2464     Node*           src_node;
2465     Node*           dst_node;
2466     int             paramInd, arcIndex;
2467     XmWorkspaceLine l;
2468 
2469     src_node = a->getSourceNode(paramInd);
2470     dst_node = a->getDestinationNode(arcIndex);
2471     src_standIn = src_node->getStandIn();
2472     dst_standIn = dst_node->getStandIn();
2473 
2474     workspace = (EditorWorkSpace*)this->workSpace;
2475 
2476     //
2477     // Create the StandIn if neccessary.  This should probably be done in
2478     // getStandIn().
2479     //
2480     if(!src_standIn)
2481     {
2482 	src_node->newStandIn(workspace);
2483         src_standIn = src_node->getStandIn();
2484     }
2485     if(!dst_standIn)
2486     {
2487 	dst_node->newStandIn(workspace);
2488         dst_standIn = dst_node->getStandIn();
2489     }
2490 
2491     if (src_node->isParameterVisible(paramInd, FALSE) &&
2492 	src_node->isParameterViewable(paramInd,FALSE) &&
2493 	dst_node->isParameterVisible(arcIndex, TRUE)  &&
2494 	dst_node->isParameterViewable(arcIndex,TRUE))
2495     {
2496 
2497 	l = XmCreateWorkspaceLine((XmWorkspaceWidget)workspace->getRootWidget(),
2498 		standInDefaults.line.color,
2499 		src_standIn->getRootWidget(),
2500 		src_standIn->getOutputParameterTabX(paramInd)
2501 			     + standInDefaults.io.width /2,
2502 		src_standIn->getOutputParameterTabY(paramInd)
2503 			     + standInDefaults.io.height,
2504 		dst_standIn->getRootWidget(),
2505 		dst_standIn->getInputParameterTabX(arcIndex)
2506 			     + standInDefaults.io.width / 2,
2507 		dst_standIn->getInputParameterTabY(arcIndex));
2508 
2509 	asi = new ArkStandIn((XmWorkspaceWidget) workspace->getRootWidget(), l);
2510 	a->setArkStandIn(asi);
2511 	src_standIn->drawTab(paramInd, TRUE);
2512 	dst_standIn->drawTab(arcIndex, FALSE);
2513     }
2514 }
2515 
2516 
2517 
2518 //
2519 // Caution:  We're going to refuse to set our own selected state, if we see that
2520 // the Workspace we inhabit is unmanaged.  This is on behalf of WorkSpage pages.
2521 // The motivation is primarily the EditorWindow menu bar option -
2522 // Edit/Select Unconnected.  This option produces a traversal of the network selecting
2523 // potentially many standins.  The standins might occupy pages which aren't at the
2524 // foreground.   This will need to be revisited if pages can be managed inside a
2525 // separated unmanaged window.  The point is to prevent operating of selected nodes
2526 // you don't know are selected.
2527 //
setSelected(boolean s)2528 void StandIn::setSelected(boolean s)
2529 {
2530     WorkSpace* ws = this->getWorkSpace();
2531     if (ws->isManaged() == FALSE) return ;
2532 
2533     boolean old_s = this->selected;
2534 
2535     this->selected = s;
2536 
2537     if (old_s != s)  {
2538         this->indicateSelection(s);
2539 	this->handleSelectionChange(s);
2540     }
2541 
2542 }
indicateSelection(boolean select)2543 void StandIn::indicateSelection(boolean select)
2544 {
2545     Arg     arg[1];
2546 
2547     if (!this->getRootWidget())
2548 	return;
2549 
2550     XtSetArg(arg[0], XmNselected, select);
2551     XtSetValues(this->getRootWidget(), arg, 1);
2552 }
2553 
2554 
ioStatusChange(int index,boolean outputTab,NodeParameterStatusChange status)2555 void StandIn::ioStatusChange(int index, boolean outputTab,
2556 				NodeParameterStatusChange status)
2557 {
2558     if (status == Node::ParameterSetValueChanged)
2559 	return;
2560 
2561     setVisibility(index, outputTab);
2562     drawTab(index,outputTab);
2563 }
2564 
setMinimumWidth(int & width)2565 boolean StandIn::setMinimumWidth(int &width)
2566 {
2567     int     min_width, visible_inputs, visible_outputs;
2568     int     curr_width, curr_height;
2569     Arg     arg[3];
2570 
2571 
2572    /*
2573     * Calculate the minimum width needed for i/o labels.
2574     */
2575 
2576     visible_inputs = this->getVisibleInputCount();
2577     visible_outputs = this->getVisibleOutputCount();
2578     min_width = MAX(visible_inputs, visible_outputs);
2579 
2580     min_width = (standInDefaults.io.width +
2581                  standInDefaults.io.width / 2 ) * min_width;
2582 
2583     //
2584     // Don't let the button width get smaller than what is
2585     // needed for the text.
2586     //
2587 
2588     width = MAX(min_width, this->requiredButtonWidth);
2589 
2590     this->getXYSize(&curr_width, &curr_height);
2591 
2592     if (curr_width  == width)
2593         return(FALSE);  // no change necessary
2594 
2595     this->setXYSize(width, curr_height);
2596 
2597     XtSetArg(arg[0], XmNwidth, width);
2598     XtSetValues(this->buttonWidget, arg, 1);
2599 
2600     return(TRUE);
2601 }
2602 
2603 //
2604 // Add a tab at the given index.
2605 // This generally called by Node::addRepeats(), so we don't need to
2606 // notify the node or set the network dirty (node does that).
2607 //
2608 
addInput(int index)2609 void StandIn::addInput(int index)
2610 {
2611     int      width;
2612     Tab      *tab;
2613 
2614 
2615     ASSERT(index > 0);
2616 
2617     this->setMinimumWidth(width);
2618     tab = createInputTab(this->getRootWidget(), index, width);
2619     if ((this->node->isInputVisible(index) == FALSE) ||
2620         (this->node->isInputViewable(index) == FALSE))
2621 	tab->unmanage();
2622 
2623 
2624     inputTabList.insertElement(tab, index);
2625 
2626     this->adjustParameterLocations(width);
2627 }
2628 
removeLastInput()2629 void StandIn::removeLastInput()
2630 {
2631     Tab *tab;
2632     int width;
2633 
2634     int index = this->inputTabList.getSize();
2635     if (index == 0)
2636 	return;
2637     tab = (Tab  *) this->inputTabList.getElement(index);
2638     this->inputTabList.deleteElement(index);
2639     delete tab;
2640 
2641     this->setMinimumWidth(width);
2642     this->adjustParameterLocations(width);
2643 }
2644 
setVisibility(int index,boolean outputTab)2645 void StandIn::setVisibility(int index, boolean outputTab)
2646 {
2647     int width;
2648     Tab  *tab;
2649 
2650     if (outputTab)
2651         tab = (Tab  *) outputTabList.getElement(index);
2652     else
2653         tab = (Tab  *) inputTabList.getElement(index);
2654 
2655     if (tab->getRootWidget() == NULL)
2656         return;    // this parameter has no standIn representation
2657 
2658     //
2659     // If our visibility is currently correct...
2660     //
2661     if (node->isParameterVisible(index,!outputTab) == tab->isManaged()) return;
2662 
2663     if (node->isParameterVisible(index,!outputTab) == FALSE) {
2664         if (tab->isManaged())
2665             tab->unmanage();
2666     } else {
2667         tab->manage();
2668     }
2669 
2670     this->setMinimumWidth(width);
2671     this->adjustParameterLocations(width);
2672 }
2673 
addOutput(int index)2674 void StandIn::addOutput(int index)
2675 {
2676     ASSERT(index > 0);
2677 
2678     int      width;
2679     Tab      *tab;
2680 
2681     this->setMinimumWidth(width);
2682     tab = this->createOutputTab(this->getRootWidget(), index, width);
2683 
2684     this->outputTabList.insertElement(tab, index);
2685 
2686     this->adjustParameterLocations(width);
2687 }
2688 
removeLastOutput()2689 void StandIn::removeLastOutput()
2690 {
2691     Tab *tab;
2692     int width;
2693 
2694 
2695     int index = this->outputTabList.getSize();
2696     if (index == 0)
2697 	return;
2698 
2699     tab = (Tab  *) this->outputTabList.getElement(index);
2700     this->outputTabList.deleteElement(index);
2701     delete tab;
2702 
2703     this->setMinimumWidth(width);
2704     this->adjustParameterLocations(width);
2705 }
2706 
setLabelColor(Pixel color)2707 void StandIn::setLabelColor(Pixel color)
2708 {
2709     Arg     arg[1];
2710     XtSetArg(arg[0], XmNforeground, color);
2711     XtSetValues(this->buttonWidget,arg,1);
2712 }
getLabelColor()2713 Pixel StandIn::getLabelColor()
2714 {
2715     Pixel color;
2716 #if 0
2717     XtVaGetValues(this->buttonWidget,
2718 	 XmNforeground, &color, NULL);
2719 #else
2720     Arg     arg[1];
2721     XtSetArg(arg[0], XmNforeground, &color);
2722     XtGetValues(this->buttonWidget,arg,1);
2723 #endif
2724 
2725     return color;
2726 }
2727 
2728 //
2729 // Print a representation of the stand in on a PostScript device.  We
2730 // assume that the device is in the same coordinate space as the parent
2731 // of this uicomponent (i.e. we send the current geometry to the
2732 // PostScript output file).  We do not print the ArkStandIns, but do
2733 // print the Tabs.
2734 //
PrintPostScriptSetup(FILE * f)2735 boolean StandIn::PrintPostScriptSetup(FILE *f)
2736 {
2737 
2738     if (fprintf(f,"/Box { %% Usage : r g b x y width height\n"
2739 			"\t2 dict begin\n"
2740 			"\t/height 2 1 roll def\n"
2741 			"\t/width  2 1 roll def\n"
2742 			"\t%% First, draw a filled box\n"
2743 			"\tmoveto		%% move to lower left\n"
2744 			"\t0 height rlineto 	%% move to upper left\n"
2745 			"\twidth 0  rlineto   	%% Move to upper right\n"
2746 			"\t0 height neg rlineto %% move to lower right\n"
2747 			"\tclosepath\n"
2748 			"\tgsave\n"
2749 			"\tsetrgbcolor fill 	%% set the given gray & fill\n"
2750 			"\tgrestore		%% restore original state\n"
2751 			"\t%% Second, draw an outline for the box\n"
2752 			"\t1 setlinewidth stroke\n"
2753 			"\tend			%% end of dictionary\n"
2754 			"} bind def \n") <= 0)
2755 	return FALSE;
2756 
2757     return TRUE;
2758 }
2759 
2760 //
2761 // Get the position of a widget relative to one of its ancestor widgets.
2762 //
GetPositionRelativeTo(Widget relative_to,Widget of,int * x,int * y)2763 static void GetPositionRelativeTo(Widget relative_to, Widget of, int *x, int *y)
2764 {
2765     Widget parent = XtParent(of);
2766 
2767     if (parent == relative_to)  {
2768 	*x = *y = 0;
2769     } else {
2770 	int parent_x, parent_y;
2771 	Position of_x, of_y;
2772 
2773 	GetPositionRelativeTo(relative_to, parent, &parent_x, &parent_y);
2774 
2775 	XtVaGetValues(of,
2776 	    XmNx, &of_x,
2777 	    XmNy, &of_y,
2778 	    NULL);
2779 
2780 	*x = of_x + parent_x;
2781 	*y = of_y + parent_y;
2782     }
2783 
2784 }
getPostScriptLabelFont()2785 const char *StandIn::getPostScriptLabelFont()
2786 {
2787     return "Helvetica-Bold";
2788 }
PixelToRGB(Widget w,Pixel p,float * r,float * g,float * b)2789 void PixelToRGB(Widget w, Pixel p, float *r, float *g, float *b)
2790 {
2791     Colormap cmap = 0;
2792     XColor xcolor;
2793     Display *d = XtDisplay(w);
2794     xcolor.pixel = p;
2795     XtVaGetValues (w, XmNcolormap, &cmap, NULL); //XmNcolormap comes from Core
2796     ASSERT(cmap);
2797     XQueryColor(d,cmap,&xcolor);
2798 
2799     *r = xcolor.red   / 65535.0;
2800     *g = xcolor.green / 65535.0;
2801     *b = xcolor.blue  / 65535.0;
2802 }
printPostScriptPage(FILE * f,boolean label_parameters)2803 boolean StandIn::printPostScriptPage(FILE *f, boolean label_parameters)
2804 {
2805     int tab_xpos, tab_ypos, button_xpos, button_ypos, xpos, ypos, xsize, ysize;
2806     int i, standin_xpos, standin_ypos, standin_ysize, standin_xsize;;
2807     ListIterator iterator;
2808     Tab *t;
2809     // Network *network = this->node->getNetwork();
2810     // EditorWindow *editor = network->getEditor();
2811     Widget workspace = this->workSpace->getRootWidget();
2812     float red,green,blue;
2813     Pixel pixel;
2814 
2815     //
2816     // Print the root widget box
2817     //
2818 
2819     Position x,y;
2820     Dimension w,h;
2821 
2822     this->getGeometry(&xpos, &ypos, &xsize, &ysize);
2823     standin_ysize = ysize;
2824     standin_xsize = xsize;
2825     standin_xpos = xpos;
2826     standin_ypos = ypos;
2827 
2828     XtVaGetValues(this->buttonWidget,
2829         XmNx, &x,
2830         XmNy, &y,
2831         XmNwidth, &w,
2832         XmNheight, &h,
2833 	NULL);
2834     button_xpos = xpos + x; button_ypos = ypos + y; xsize = w; ysize = h;
2835     int font_scale_height = ysize;
2836 
2837     XtVaGetValues(this->buttonWidget, XmNbackground, &pixel, NULL);
2838     PixelToRGB(this->buttonWidget,pixel, &red, &green, &blue);
2839     if (fprintf(f,"%f %f %f %d %d %d %d Box\n",
2840 			red,green,blue,
2841 			button_xpos,button_ypos, xsize, ysize) < 0)
2842 	return FALSE;
2843     float font_scale = ysize/3;
2844     const char *label = this->getButtonLabel();
2845     char *esc_label;
2846     if (strchr(label,'(') || strchr(label,')')) {
2847 	//
2848 	// If the label has left/right parens, then we must escape them.
2849 	//
2850 	esc_label = new char[2 * STRLEN(label) + 1];
2851 	const char *src = label;
2852 	char c, *dest = esc_label;
2853 	for (src = label, dest = esc_label ; (c = *src) ; src++, dest++) {
2854 	    if ((c == ')' || c == '(')) {
2855 		*dest = '\\';
2856 		dest++;
2857 	    }
2858 	    *dest = c;
2859 	}
2860 	*dest = '\0';
2861     } else {
2862 	esc_label = (char*)label;
2863     }
2864 
2865     if (fprintf(f,"/%s findfont\n"
2866 		  "[ %f 0 0 -%f 0 0 ] makefont setfont\n"
2867 		  "(%s) stringwidth\n"
2868 		  "pop 3 %d mul 5 div %d add %% y position\n"
2869 		  "2 1 roll\n"
2870 		  "neg %d add 2 div %d add %% x position\n"
2871 		  "2 1 roll\n"
2872 		  "moveto (%s) show\n",
2873 		   this->getPostScriptLabelFont(),
2874 		   font_scale, font_scale,
2875 		   esc_label,
2876 		   ysize, button_ypos,
2877 		   xsize, button_xpos,
2878 		   esc_label) <=0)
2879 	return FALSE;
2880 
2881 
2882     if (esc_label != label)
2883 	delete esc_label;
2884 
2885     boolean param_font_set = FALSE;
2886     font_scale = ysize/7;
2887     //
2888     // Print the input tabs
2889     //
2890     iterator.setList(this->inputTabList);
2891     i = 0;
2892     while ( (t = (Tab*)iterator.getNext()) ) {
2893 	i++;
2894 	if (t->isManaged()) {
2895 	    Node *tnode = this->node;
2896 	    t->getXYSize(&xsize, &ysize);
2897 	    GetPositionRelativeTo(workspace,t->getRootWidget(),
2898 							&tab_xpos,&tab_ypos);
2899 
2900 	    XtVaGetValues(t->getRootWidget(), XmNbackground, &pixel, NULL);
2901 	    PixelToRGB(t->getRootWidget(),pixel, &red, &green, &blue);
2902 	    if (fprintf(f,"%f %f %f %d %d %d %d Box\n",
2903 			red,green,blue,
2904 			xpos + tab_xpos,ypos + tab_ypos, xsize, ysize) < 0)
2905 		return FALSE;
2906 
2907 	    if (tnode->isInputConnected(i)) {
2908 		int x =  (int) (xpos + tab_xpos + xsize/2.0);
2909 		int y =  ypos + tab_ypos - ysize;
2910 		if (fprintf(f,"%d %d moveto %d %d lineto stroke\n",
2911 			    x, y, x, y+ysize) < 0)
2912 		    return FALSE;
2913 
2914 	    } else if (label_parameters && !tnode->isInputDefaulting(i)) {
2915 		int x =  (int) (xpos + tab_xpos + .50*xsize);
2916 		int y =  (int) (ypos + tab_ypos - .20*ysize);
2917 		// Input is set
2918 		if (!param_font_set) {
2919 		    param_font_set = TRUE;
2920 		    if (fprintf(f,"/Helvetica findfont\n"
2921 		      "[ %f 0 0 -%f 0 0 ] makefont setfont\n",
2922 		       font_scale, font_scale) <= 0)
2923 			return FALSE;
2924 		}
2925 		char buf[1024];
2926 		if (tnode->isInputDefaulting(i)) {
2927 		    strcpy(buf, tnode->getInputNameString(i));
2928 		} else {
2929 		    int ii, jj;
2930 		    int cutoff;
2931 		    char* doublequote;
2932 		    char dup_val[64];
2933 		    char escaped_val[128];
2934 		    const char *val = tnode->getInputValueString(i);
2935 		    //trim the string if too long, don't count escape for escaped chars
2936 		    if (STRLEN(val) > 32) {
2937 			if(STRLEN(val) > 58 ) {
2938 				strncpy(dup_val,val,58);
2939 				dup_val[57] = '\0';
2940 			} else {
2941 				strcpy(dup_val,val);
2942 			}
2943 			cutoff=0;
2944 			for (ii=0; ii<STRLEN(dup_val); ii++) {
2945 				if(dup_val[ii]!='\\') {
2946 					++cutoff;
2947 					// don't have escape character be last!
2948 					if((cutoff>31)&&(ii>0)&&(dup_val[ii-1]!='\\')) dup_val[ii]='\0';
2949 				}
2950 			}
2951 			strcat(dup_val,"...");
2952 			// restore balanced quotes for postscript
2953 			// ---turns out it isn't a requirement, but it is aesthetic
2954 			ii=0;
2955 			doublequote=dup_val;
2956 			while((doublequote=strchr(doublequote,'\"'))!=NULL) {
2957 				++doublequote;
2958 				++ii;
2959 			}
2960 			if(ii&1) strcat(dup_val,"\"");
2961 		    } else {
2962 			strcpy(dup_val,val);
2963 		    }
2964 		    jj=0;
2965 		    for (ii=0; ii<=STRLEN(dup_val); ++ii) {
2966 			//some characters require escaping, feel free to expand the list
2967 		 	if(ii<STRLEN(dup_val) && strchr("()",dup_val[ii])) escaped_val[jj++]='\\';
2968 			escaped_val[jj++]=dup_val[ii];
2969 			}
2970 		    sprintf(buf,"%s = %s",
2971 				tnode->getInputNameString(i),escaped_val);
2972 	 	}
2973 
2974 		if (fprintf(f,"gsave %d %d translate -45 rotate "
2975 		      	"0 0 moveto\n"
2976 			"(%s) show grestore\n",
2977 			x, y, buf) <=0)
2978 			return FALSE;
2979 
2980 	    }
2981 	}
2982     }
2983     //
2984     // Print the output tabs
2985     //
2986     iterator.setList(this->outputTabList) ;
2987     i = 0;
2988     while ( (t = (Tab*)iterator.getNext()) ) {
2989 	i++;
2990 	if (t->isManaged()) {
2991 	    t->getXYSize(&xsize, &ysize);
2992 	    GetPositionRelativeTo(workspace,t->getRootWidget(),
2993 							&tab_xpos,&tab_ypos);
2994 	    XtVaGetValues(t->getRootWidget(), XmNbackground, &pixel, NULL);
2995 	    PixelToRGB(t->getRootWidget(),pixel, &red, &green, &blue);
2996 	    if (fprintf(f,"%f %f %f %d %d %d %d Box\n",
2997 			red,green,blue,
2998 			xpos + tab_xpos,ypos + tab_ypos, xsize, ysize) < 0)
2999 		return FALSE;
3000 	    if (this->node->isOutputConnected(i)) {
3001 		int x =  (int) (xpos + tab_xpos + xsize/2.0);
3002 		int y =  ypos + tab_ypos + ysize;
3003 		if (fprintf(f,"%d %d moveto %d %d lineto stroke\n",
3004 			    x, y, x, y+ysize) < 0)
3005 		    return FALSE;
3006 
3007 	    }
3008 	}
3009     }
3010 
3011     //
3012     // We'll try to print 1 extra piece of text if our node supplies one.
3013     // This is really on behalf of ComputeNode since he has nowhere to show
3014     // the compute expr since the expr input tab is not viewable.
3015     // Inside a standin there might be some extra room.  There is the area
3016     // below a standin which is blank if all output tabs are connected.  Then
3017     // there is the area below the label which is blank if all output tabs
3018     // are unconnected.  To figure out where to display extra text, loop over
3019     // outputs to find if either situation prevails.  If so you're in luck.
3020     //
3021     // Oridinarily we would handle a task like this inside a subclass of
3022     // StandIn and make new subclass of StandIn on behalf of ComputeNode.
3023     // I'm not doing that in this case because printPostScriptPage isn't
3024     // virtual.  Having PostScript generation code be virtual might not be
3025     // so cool because it's complicated and no one knows how to work on it,
3026     // unlike the code that writes other types of files.
3027     //
3028     const char* extra_text = NUL(char*);
3029     if (label_parameters)
3030 	extra_text = this->node->getExtraPSText();
3031     if (extra_text) {
3032 
3033 	boolean below_box = TRUE;
3034 	boolean inside_box = TRUE;
3035 	int i = 1;
3036 	iterator.setList(this->outputTabList) ;
3037 	Tab* t;
3038 	while ( (t = (Tab*)iterator.getNext()) ) {
3039 	    if (!t->isManaged()) continue;
3040 	    boolean iscon = this->node->isOutputConnected(i);
3041 	    if (iscon) inside_box = FALSE;
3042 	    else below_box = FALSE;
3043 	    i++;
3044 	}
3045 
3046 	if (this->outputTabList.getSize() == 1) {
3047 	    if (this->node->isOutputConnected(1))
3048 		below_box = TRUE;
3049 	    else
3050 		below_box = FALSE;
3051 	    inside_box = !below_box;
3052 	}
3053 
3054 	if ((inside_box) || (below_box)) {
3055 	    //
3056 	    // If the label has left/right parens, then we must escape them.
3057 	    //
3058 	    if (strchr(extra_text,'(') || strchr(extra_text,')')) {
3059 		esc_label = new char[2 * STRLEN(extra_text) + 6];
3060 		const char *src = extra_text;
3061 		char c, *dest = esc_label;
3062 		for (src = extra_text, dest = esc_label ; (c = *src) ; src++, dest++) {
3063 		    if ((c == ')' || c == '(')) {
3064 			*dest = '\\';
3065 			dest++;
3066 		    }
3067 		    *dest = c;
3068 		}
3069 		*dest = '\0';
3070 	    } else {
3071 		esc_label = new char[STRLEN(extra_text) + 6];
3072 		strcpy (esc_label, extra_text);
3073 	    }
3074 
3075 	    //
3076 	    // for every tab more than 3 add some bytes to max len.
3077 	    //
3078 	    int max_len = (below_box?26:20);
3079 	    int mgd_i_tab_cnt = 0;
3080 	    int mgd_o_tab_cnt = 0;
3081 	    iterator.setList(this->inputTabList) ;
3082 	    while ( (t = (Tab*)iterator.getNext()) ) if (t->isManaged()) mgd_i_tab_cnt++;
3083 	    iterator.setList(this->outputTabList) ;
3084 	    while ( (t = (Tab*)iterator.getNext()) ) if (t->isManaged()) mgd_o_tab_cnt++;
3085 
3086 	    int tab_cnt = MAX(mgd_i_tab_cnt, mgd_o_tab_cnt);
3087 	    int diff = tab_cnt - 2;
3088 	    max_len+= (diff>0?diff*8:0);
3089 	    if (strlen(esc_label) >= max_len)
3090 		strcpy (&esc_label[max_len], "...");
3091 
3092 	    int box_relative (below_box?-2:-14);
3093 
3094 	    font_scale = font_scale_height/7;
3095 	    if (!param_font_set) {
3096 		param_font_set = TRUE;
3097 		if (fprintf(f,"/Helvetica findfont\n"
3098 		  "[ %f 0 0 -%f 0 0 ] makefont setfont\n",
3099 		   font_scale, font_scale) <= 0)
3100 		    return FALSE;
3101 	    }
3102 	    if (fprintf(f,"(%s) stringwidth pop\n"
3103 			  "0.5 neg mul 0.5 %d mul add %d add  %% x position\n"
3104 			  "%d\n"
3105 			  "moveto (%s) show\n",
3106 			   esc_label,
3107 			   standin_xsize, standin_xpos,
3108 			   standin_ysize + standin_ypos + box_relative,
3109 			   esc_label) <=0)
3110 		return FALSE;
3111 
3112 	    delete esc_label;
3113 	}
3114     }
3115 
3116     return TRUE;
3117 }
3118 
dropFinish(long operation,int tag,unsigned char status)3119 void StandIn::dropFinish(long operation, int tag, unsigned char status)
3120 {
3121     Network*         network;
3122     EditorWindow*    editor;
3123 
3124     network = this->node->getNetwork();
3125     editor = network->getEditor();
3126 
3127     //
3128     // Delete the atoms set up when starting the drag
3129     //
3130     Display *d = XtDisplay(this->getRootWidget());
3131     Atom xoff_atom = XInternAtom (d, DXXOFFSET, True);
3132     Atom yoff_atom = XInternAtom (d, DXYOFFSET, True);
3133     Screen *screen = XtScreen(this->getRootWidget());
3134     Window root = RootWindowOfScreen(screen);
3135     if (xoff_atom != None)
3136 	XDeleteProperty (d, root, xoff_atom);
3137     if (yoff_atom != None)
3138 	XDeleteProperty (d, root, yoff_atom);
3139 
3140 
3141     // If the operation was a copy and the type was Trash,
3142     // then it would be better to treat it like a move
3143     // so that the user isn't required to use the Shift key.
3144     // When dragging from vpe to c.p. disallow cutting with the shift key.
3145     if (status) {
3146 	if (tag == StandIn::Interactors) {
3147 	} else if ((operation == XmDROP_MOVE) || (tag == StandIn::Trash)) {
3148 	    //editor->getDeleteNodeCmd()->execute();
3149 	    XtAppContext apcxt = theApplication->getApplicationContext();
3150 	    this->drag_drop_wpid = XtAppAddWorkProc (apcxt,
3151 		    StandIn_DragDropWP, (XtPointer)this);
3152 	}
3153     }
3154 }
3155 
3156 
decodeDragType(int tag,char * a,XtPointer * value,unsigned long * length,long operation)3157 boolean StandIn::decodeDragType (int tag,
3158 	char * a, XtPointer *value, unsigned long *length, long operation)
3159 {
3160 boolean retVal;
3161 char *hostname;
3162 int len;
3163 
3164     switch (tag) {
3165 	case StandIn::Modules:
3166 	    // this-convert() comes from DXDragSource and can't be overridden.
3167 	    retVal = this->convert (this->node->getNetwork(), a,value, length, operation);
3168 	    break;
3169 
3170 
3171 	// The only data needed is hostname:pid.  That string is used to verify that
3172 	// this operation is taking place in intra-executable fashion and not between
3173 	// executables.  This is necessary because placing an interactor in a panel
3174 	// depends on what is in the net.
3175 	case StandIn::Interactors:
3176 	    hostname = new char[MAXHOSTNAMELEN + 16];
3177 	    if (gethostname (hostname, MAXHOSTNAMELEN) == -1) {
3178 		retVal = FALSE;
3179 		break;
3180 	    }
3181 	    len = strlen(hostname);
3182 	    sprintf (&hostname[len], ":%d", getpid());
3183 
3184 	    *value = hostname;
3185 	    *length = strlen(hostname);
3186 	    retVal = TRUE;
3187 	    break;
3188 
3189 	// this->dropFinish will take care of the delete.  No data is required.
3190 	case StandIn::Trash:
3191 	    retVal = TRUE;
3192 
3193 	    // dummy pointer. This memory shouldn't be referenced anywhere.
3194 	    *value = (XtPointer)malloc(4);
3195 	    *length = 4;
3196 	    break;
3197 
3198 	default:
3199 	    retVal = FALSE;
3200 	    break;
3201     }
3202     return retVal;
3203 }
3204 
3205 
3206 // Is it ok to start a drag?  This depends only on the selected state of
3207 // the node.
decideToDrag(XEvent * xev)3208 int StandIn::decideToDrag(XEvent *xev)
3209 {
3210     if (!this->selected) return DragSource::Abort;
3211 
3212     // Node *node = this->node;
3213     // Network *network = node->getNetwork();
3214     ListIterator it;
3215 
3216     Display *d = XtDisplay(this->getRootWidget());
3217     Atom xoff_atom = XInternAtom (d, DXXOFFSET, False);
3218     Atom yoff_atom = XInternAtom (d, DXYOFFSET, False);
3219     Screen *screen = XtScreen(this->getRootWidget());
3220     Window root = RootWindowOfScreen(screen);
3221     int x;
3222     int y;
3223     this->getXYPosition (&x, &y);
3224     int minx = x;
3225     int miny = y;
3226     int junk;
3227 
3228     this->workSpace->getSelectedBoundingBox (&minx, &miny, &junk, &junk);
3229 #if defined(alphax)
3230     // unaligned access error otherwise
3231     long int xoffset = x - minx;
3232     long int yoffset = y - miny;
3233 #else
3234     int xoffset = x - minx;
3235     int yoffset = y - miny;
3236 #endif
3237 
3238     if (xev->type == ButtonPress) {
3239 	xoffset+= xev->xbutton.x;
3240 	yoffset+= xev->xbutton.y;
3241     }
3242 
3243     XChangeProperty (d, root, xoff_atom, XA_INTEGER, 32, PropModeReplace,
3244 	(unsigned char*)&xoffset, 1);
3245     XChangeProperty (d, root, yoff_atom, XA_INTEGER, 32, PropModeReplace,
3246 	(unsigned char*)&yoffset, 1);
3247 
3248     return DragSource::Proceed;
3249 }
3250 
3251 extern "C"  {
3252 //
3253 // Provide Button2 selectability on standins so that an attempt to drag something
3254 // unselected might select the thing instead of beeping.
3255 //
StandIn_Button2ReleaseEH(Widget w,XtPointer,XEvent * xev,Boolean * keep_going)3256 void StandIn_Button2ReleaseEH
3257 (Widget w, XtPointer , XEvent *xev, Boolean *keep_going)
3258 {
3259     *keep_going = True;
3260     if (xev->xbutton.button != 2)
3261         return ;
3262 
3263     if (xev->xbutton.state & ShiftMask)
3264         return ;
3265     XtCallActionProc (w, "release_w", xev, NULL, 0);
3266 }
StandIn_Button2PressEH(Widget w,XtPointer,XEvent * xev,Boolean * keep_going)3267 void StandIn_Button2PressEH
3268 (Widget w, XtPointer , XEvent *xev, Boolean *keep_going)
3269 {
3270     *keep_going = True;
3271     if (xev->xbutton.button != 2)
3272         return ;
3273 
3274     if (xev->xbutton.state & ShiftMask)
3275         return ;
3276     XtCallActionProc (w, "select_w", xev, NULL, 0);
3277 }
3278 
3279 //
3280 // Pass keyboard events thru to the workspace.  This ought to be handled
3281 // either with translations or with the same mechanism used for standInRoot.
3282 //
StandIn_TabKeyNavEH(Widget w,XtPointer,XEvent * xev,Boolean * keep_going)3283 void StandIn_TabKeyNavEH
3284 (Widget w, XtPointer , XEvent *xev, Boolean *keep_going)
3285 {
3286     *keep_going = TRUE;
3287     boolean is_help_key = FALSE;
3288     XKeyEvent* xke = (XKeyEvent*)xev;
3289     KeySym lookedup = XLookupKeysym (xke, 0);
3290 
3291     //
3292     // problem here is that we don't know for sure that F1 is help.
3293     // What we really want is to compare to osfHelp, not XK_F1.
3294     //
3295     if (lookedup == XK_F1) is_help_key = TRUE;
3296 
3297     // the meaning of False here, is that we have no need for <Key> events
3298     // in the io tabs.  They have always been hooked up and working but
3299     // for no purpose.  You could hit the space bar on a tab and watch
3300     // it wiggle, but so what.
3301 
3302     if (!is_help_key) {
3303 	*keep_going = False;
3304 	XtCallActionProc (w, "child_nav", xev, NULL, 0);
3305     }
3306 }
3307 
3308 //
3309 // Used during drag-n-drop operations that result in deletion of nodes.
3310 // The Command passed in is the EditorWindow's delete-selected-nodes
3311 // command.
3312 //
StandIn_DragDropWP(XtPointer clientData)3313 Boolean StandIn_DragDropWP (XtPointer clientData)
3314 {
3315     StandIn* si = (StandIn*)clientData;
3316     Network*         network;
3317     EditorWindow*    editor;
3318 
3319     network = si->node->getNetwork();
3320     editor = network->getEditor();
3321     si->drag_drop_wpid = 0;
3322     editor->getDeleteNodeCmd()->execute();
3323     return TRUE;
3324 }
3325 } // extern C
3326 
3327 //
3328 // This function can be called to notify a standin that its label
3329 // has changed.  By default, this standin just calls setButtonLabel()
3330 // to reset the label.
notifyLabelChange()3331 void StandIn::notifyLabelChange()
3332 {
3333     this->setButtonLabel();
3334 }
3335 
3336 //
3337 // In addition to superclass work, we'll need to create new workspace
3338 // lines since the start/end points of
3339 // In the case of StandIn, using the superclass doesn't do any good
3340 // since the widget is geometry-managed by the containing widget.  Setting
3341 // XmN{x,y} has no effect.
3342 //
setXYPosition(int x,int y)3343 void StandIn::setXYPosition (int x, int y)
3344 {
3345     this->UIComponent::setXYPosition (x,y);
3346     if (this->isManaged())
3347 	XmWorkspaceSetLocation (this->getRootWidget(), x, y);
3348 }
3349 
3350 //
3351 // Store the this pointer in the widget's XmNuserData so that we
3352 // can retrieve the Object in a callback in EditorWorkSpace.C
3353 //
setRootWidget(Widget root,boolean standardDestroy)3354 void StandIn::setRootWidget(Widget root, boolean standardDestroy)
3355 {
3356     this->UIComponent::setRootWidget(root, standardDestroy);
3357     this->setLocalData(this);
3358 }
3359 
3360