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