1 /***********************************************************************/
2 /* Open Visualization Data Explorer */
3 /* (C) Copyright IBM Corp. 1989,1999 */
4 /* ALL RIGHTS RESERVED */
5 /* This code licensed under the */
6 /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */
7 /***********************************************************************/
8
9 #include <dxconfig.h>
10 #include "../base/defines.h"
11
12
13 #include "lex.h"
14 #include "Parameter.h"
15 #include "DXApplication.h"
16 #include "SequencerNode.h"
17 #include "SequencerWindow.h"
18 #include "DXStrings.h"
19 #include "ErrorDialogManager.h"
20 #include "Network.h"
21 #include "Command.h"
22 #include "WarningDialogManager.h"
23 #include "IBMVersion.h"
24
25 #include "../widgets/XmDX.h"
26
27 #define ID_PARAM_NUM 1
28 #define DATA_PARAM_NUM 2
29 #define FRAME_PARAM_NUM 3
30 #define MIN_PARAM_NUM 4
31 #define MAX_PARAM_NUM 5
32 #ifndef HAS_START_STOP
33 #define DELTA_PARAM_NUM 6
34 #define ATTR_PARAM_NUM 7
35 #define EXPECTED_INPUTS ATTR_PARAM_NUM
36 #else
37 #define START_PARAM_NUM 6
38 #define STOP_PARAM_NUM 7
39 #define DELTA_PARAM_NUM 8
40 #define EXPECTED_INPUTS DELTA_PARAM_NUM
41 #endif
42
43
SequencerNode(NodeDefinition * nd,Network * net,int instnc)44 SequencerNode::SequencerNode(NodeDefinition *nd, Network *net, int instnc) :
45 ShadowedOutputNode(nd, net, instnc)
46 {
47 this->seq_window = NULL;
48 this->wasExecuted = FALSE;
49 this->xpos = this->ypos = UIComponent::UnspecifiedPosition;
50 this->width = this->height = UIComponent::UnspecifiedDimension;
51
52 //
53 // Initialize the startup value based on the net version number. This preserves
54 // an old behvior: the sequencer always appears when you startup in image mode.
55 // It also provides a new behavior: you can mark the vcr as non-startup window
56 // so that it won't automatically appear when loading the .net in image mode.
57 // The behavior for new nets will be to mark the vcr as a startup window if
58 // it's startup flag was set. The startup flag will be set thru the vcr's
59 // manage/unmange methods rather than a toggle button.
60 //
61 int major = net->getNetMajorVersion();
62 int minor = net->getNetMinorVersion();
63 int micro = net->getNetMicroVersion();
64 if (VERSION_NUMBER (major, minor, micro) < VERSION_NUMBER (3,1,4))
65 this->startup = TRUE;
66 else
67 this->startup = FALSE;
68 }
69
~SequencerNode()70 SequencerNode::~SequencerNode()
71 {
72 theDXApplication->openSequencerCmd->deactivate();
73 #if 00
74 theDXApplication->network->sequencer = NUL(SequencerNode*);
75 #endif
76
77 if (this->seq_window) delete this->seq_window;
78 }
79
initialize()80 boolean SequencerNode::initialize()
81 {
82 this->seq_window = NUL(SequencerWindow*);
83
84 if (this->getInputCount() != EXPECTED_INPUTS) {
85 fprintf(stderr,
86 "Expected %d inputs for %s node, please check the mdf file.\n",
87 EXPECTED_INPUTS,
88 this->getNameString());
89 return FALSE;
90 }
91
92 //
93 // This keeps updateAttributes() from sending messages until
94 // we're done.
95 //
96 this->deferVisualNotification();
97
98 if (!this->setMessageIdParameter(ID_PARAM_NUM) ||
99 !this->initMinimumValue(1) ||
100 !this->initMaximumValue(100) ||
101 !this->initDeltaValue( 1) ||
102 !this->initStartValue( 1) ||
103 !this->initStopValue( 100)) {
104 ErrorMessage("Error setting default attributes for %s",
105 this->getNameString());
106 return FALSE;
107 }
108
109 this->undeferVisualNotification();
110
111 this->current = 0;
112 this->next = 1;
113 this->previous = 1;
114 this->step = FALSE;
115 this->loop = FALSE;
116 this->palindrome = FALSE;
117 this->current_defined = FALSE;
118 this->ignoreFirstFrameMsg = FALSE;
119
120 this->transmitted = False;
121
122 #if 00
123 theDXApplication->network->sequencer = this;
124 #endif
125
126 theDXApplication->openSequencerCmd->activate();
127
128 return TRUE;
129 }
130
131 //
132 // If the min or max input has changed, update the attribute parameter
133 // (integer list of min and max) and then call the super class method
134 // if the input is not the attribute parameter.
135 //
ioParameterStatusChanged(boolean input,int index,NodeParameterStatusChange status)136 void SequencerNode::ioParameterStatusChanged(boolean input, int index,
137 NodeParameterStatusChange status)
138 {
139 if (input && (status & Node::ParameterValueChanged) &&
140 ((index == MIN_PARAM_NUM) ||
141 (index == DELTA_PARAM_NUM) ||
142 (index == MAX_PARAM_NUM))) {
143 //
144 // Each time the min or max attribute values (which are stored
145 // in AttributeParamters and so we come here each time they are
146 // changed) update the attribute parameter which is an integer
147 // list of the min and max values.
148 // Note that the attribute parameter is expected to have
149 // InputDoesNotDeriveOutputCacheTag cacheability, so that setting
150 // this over and over again will not cause executions.
151 //
152 this->updateAttributes();
153 }
154 if (!input || (index != ATTR_PARAM_NUM))
155 ShadowedOutputNode::ioParameterStatusChanged(input,index,status);
156 }
openDefaultWindow(Widget parent)157 void SequencerNode::openDefaultWindow(Widget parent)
158 {
159 if (this->seq_window)
160 this->seq_window->manage();
161 else
162 {
163 this->seq_window = new SequencerWindow(this);
164 if ((this->xpos != UIComponent::UnspecifiedPosition) &&
165 theDXApplication->applyWindowPlacements())
166 this->seq_window->setGeometry(this->xpos,this->ypos,
167 this->width,this->height);
168 this->seq_window->initialize();
169 this->seq_window->manage();
170
171 if (theDXApplication->getExecCtl()->isExecuting())
172 this->disableFrameControl();
173 else
174 this->enableFrameControl();
175 }
176 }
177
netNodeString(const char * prefix)178 char* SequencerNode::netNodeString(const char *prefix)
179 {
180 char *s;
181
182 if (!this->isDataDriven()) {
183 int inst = this->getInstanceNumber();
184 s = new char[96];
185 sprintf(s, " %sSequencer_%d_out_1 = @frame;\n", prefix, inst);
186 } else {
187 //
188 // Sequencer_%d_in_(FRAME_PARAM_NUM) = @frame;
189 // Sequencer_%d_out_1 = Sequencer(xxx, xxx,
190 // Sequencer_%d_in_(FRAME_PARAM_NUM)....);
191 //
192 char buf[128];
193 char *call = this->ShadowedOutputNode::netNodeString(prefix);
194 this->getNetworkInputNameString(FRAME_PARAM_NUM,buf);
195 int len = STRLEN(call) + STRLEN(buf) + 64;
196 s = new char[len];
197 sprintf(s," %s = @frame;\n%s", buf, call);
198 delete call;
199 }
200 return s;
201 }
202
netPrintAuxComment(FILE * f)203 boolean SequencerNode::netPrintAuxComment(FILE *f)
204 {
205 this->wasExecuted = TRUE;
206
207 if (!this->DrivenNode::netPrintAuxComment(f))
208 return FALSE;
209
210 if (!this->printCommonComments(f," "))
211 return FALSE;
212
213 return TRUE;
214
215 }
netParseAuxComment(const char * comment,const char * file,int lineno)216 boolean SequencerNode::netParseAuxComment(const char* comment,
217 const char *file,
218 int lineno)
219 {
220 this->wasExecuted = TRUE;
221
222 if (this->DrivenNode::netParseAuxComment(comment,file,lineno))
223 return TRUE;
224
225 if (this->parseCommonComments(comment,file,lineno))
226 return TRUE;
227
228 return FALSE;
229
230 }
231
cfgPrintNode(FILE * f,PrintType dest)232 boolean SequencerNode::cfgPrintNode(FILE *f, PrintType dest)
233 {
234 if (!this->cfgPrintNodeLeader(f))
235 return FALSE;
236
237 if (!this->printCommonComments(f))
238 return FALSE;
239
240 //
241 // Print startup mode into the cfg file.
242 // Do this only when saving a file because Network will need to manage
243 // the sequencer window if the startup flag is turned on. That's unwanted
244 // behavior during drag-n-drop and not relevant when printing to the exec.
245 //
246 if (fprintf (f, "// startup = %d\n", (dest == PrintFile ? this->startup: 0)) < 0)
247 return FALSE;
248
249 return TRUE;
250 }
cfgParseComment(const char * comment,const char * file,int lineno)251 boolean SequencerNode::cfgParseComment(const char* comment,
252 const char *file,
253 int lineno)
254 {
255 if (this->cfgParseNodeLeader(comment,file,lineno))
256 return TRUE;
257
258 if (this->parseCommonComments(comment,file,lineno))
259 return TRUE;
260
261 //
262 // Parse the startup mode from the cfg file.
263 //
264 const char* substr = " startup";
265 if (EqualSubstring (comment, substr, strlen(substr))) {
266 int startup_flag;
267 int items_parsed = sscanf (comment, " startup = %d", &startup_flag);
268 if (items_parsed == 1) {
269 this->setStartup(startup_flag);
270 return TRUE;
271 }
272 }
273
274 return FALSE;
275 }
276
printCommonComments(FILE * f,const char * indent)277 boolean SequencerNode::printCommonComments(FILE *f, const char *indent)
278 {
279 if (!indent)
280 indent = "";
281
282 //
283 // Include the instance number for forward compatibility reasons
284 // since we don't enforce sequencer instance numbers to be 1.
285 //
286 if (fprintf(f, "%s//"
287 " vcr[%d]: min = %d, max = %d, beg = %d, end = %d, cur = %d, "
288 "inc = %d, loop = %s, step = %s, pal = %s\n",
289 indent,
290 this->getInstanceNumber(),
291 this->getMinimumValue(),
292 this->getMaximumValue(),
293 this->getStartValue(),
294 this->getStopValue(),
295 this->next,
296 this->getDeltaValue(),
297 this->loop ? "on" : "off",
298 this->isStepMode() ? "on" : "off",
299 this->palindrome ? "on" : "off") < 0)
300 return FALSE;
301
302 int x,y,w,h;
303 if (this->seq_window) {
304 this->seq_window->getGeometry(&x,&y,&w,&h);
305 } else {
306 x = this->xpos; y = this->ypos;
307 w = this->width; h = this->height;
308 }
309
310 if (x != UIComponent::UnspecifiedPosition) {
311 if (!UIComponent::PrintGeometryComment(f,x,y,w,h,NULL,indent))
312 return FALSE;
313 }
314 return TRUE;
315 }
316
317
parseCommonComments(const char * comment,const char * file,int lineno)318 boolean SequencerNode::parseCommonComments(const char* comment,
319 const char *file,
320 int lineno)
321 {
322 int expected_items, items, instance;
323 int min, max, beg, end, cur, inc;
324 char loop[64];
325 char step[64];
326 char pal[64];
327
328 if (EqualSubstring(comment," vcr",4)) {
329
330 //
331 // See comment in :cfgPrint. This is to preserve behavior of existing
332 // nets.
333 //
334 this->startup = TRUE;
335
336 if (EqualSubstring(comment," vcr[",5)) {
337 expected_items = 10;
338 items = sscanf(comment,
339 " vcr[%d]: min = %d, max = %d, beg = %d, end = %d, cur = %d,"
340 " inc = %d, loop = %[^,], step = %[^,], pal = %[^\n]",
341 &instance, // Drop this on the floor until we support >1 Sequencers
342 &min, &max, &beg, &end, &cur, &inc,
343 loop, step, pal);
344 } else {
345 //
346 // Pre 2.0.0 nets
347 //
348 expected_items = 9;
349 items = sscanf(comment,
350 " vcr: min = %d, max = %d, beg = %d, end = %d, cur = %d, inc = %d,"
351 " loop = %[^,], step = %[^,], pal = %[^\n]",
352 &min, &max, &beg, &end, &cur, &inc,
353 loop, step, pal);
354 }
355
356 if(items < expected_items)
357 {
358 ErrorMessage("Malformed comment at line %d in file %s (ignoring)",
359 lineno, file);
360 return TRUE;
361 }
362
363 //
364 // This keeps updateAttributes() from sending messages until
365 // we're done.
366 //
367 this->deferVisualNotification();
368
369 this->setMinimumValue(min);
370 this->setMaximumValue(max);
371 this->setDeltaValue(inc);
372 this->setStartValue(beg);
373 this->setStopValue(end);
374
375 this->undeferVisualNotification();
376
377 this->next = cur;
378 this->loop = EqualString(loop, "on");
379 this->step = EqualString(step, "on");
380 this->palindrome = EqualString(pal, "on");
381 return TRUE;
382
383 }
384
385
386 if (UIComponent::ParseGeometryComment(comment,file,lineno,
387 &this->xpos,&this->ypos,
388 &this->width, &this->height)) {
389 if (this->seq_window &&
390 (this->xpos != UIComponent::UnspecifiedPosition) &&
391 theDXApplication->applyWindowPlacements())
392 this->seq_window->setGeometry(this->xpos,this->ypos,
393 this->width,this->height);
394
395 return TRUE;
396 }
397
398 return FALSE;
399 }
400
401 //
402 // Send the values as per the super class method and also send the
403 // @startframe, @nextframe, @endframe, @deltaframe values. If the
404 // Sequencer is data-driven then we send the @*frame values as NULL,
405 // since the Sequencer module will set these internally. Also, we
406 // want to be sure we don't pass in any values that might be replicated
407 // later in the sequence which would confuse the caching mechanism.
408 // For example, if we set @nextframe=2, and the sequence goes 0 1 2 3 ...,
409 // then the output will be 0 1 2 0, because the executive thinks the
410 // Sequencer has already seen the 4th set of values (remember that the
411 // Sequencer is called something like the following...
412 // Sequencer_1_in_3 = @frame ;
413 // Sequencer_1_out_1 = Sequencer(...,Sequencer_1_in_3,...);
414 // The idea here is to set @nextframe to something that will never be
415 // seen during the sequence.
416 //
valuesString(const char * prefix)417 char* SequencerNode::valuesString(const char *prefix)
418 {
419 char* inputs = this->ShadowedOutputNode::valuesString(prefix);
420 char* s = new char[STRLEN(inputs) + 128];
421
422 #if 0
423 if (this->isDataDriven()) {
424 sprintf(s,
425 "%s\n"
426 // FIXME: these -1e6's should be replaced by NULLs and 'play'
427 // should not init @nextframe=0 if it sees @nextframe==NULL;
428 "@startframe = -1e6;\n"
429 "@nextframe = -1e6;\n"
430 "@endframe = -1e6;\n"
431 "@deltaframe = -1e6;\n",
432 inputs);
433 } else
434 #endif
435 {
436 sprintf(s,
437 "%s\n"
438 "@startframe = %d;\n"
439 "@nextframe = @startframe;\n"
440 "@endframe = %d;\n"
441 "@deltaframe = %d;\n",
442 inputs,
443 this->getStartValue(),
444 this->getStopValue(),
445 this->getDeltaValue());
446 }
447
448 delete inputs;
449 return s;
450 }
451
getVCRWidget()452 Widget SequencerNode::getVCRWidget()
453 {
454 if(this->seq_window)
455 return seq_window->vcr;
456 else
457 return NUL(Widget);
458 }
459
460 // The messages we parse can contain one or more of the following...
461 //
462 // 'min=%g' 'max=%g' 'start=%d' 'end=%d' 'delta=%g'
463 //
464 // If any input or output values are to be changed, don't send them
465 // because the module backing up the sequencer will have just executed
466 // and if the UI is in 'execute on change' mode then there will be an
467 // extra execution.
468 //
469 // Returns the number of attributes parsed.
470 //
handleNodeMsgInfo(const char * line)471 int SequencerNode::handleNodeMsgInfo(const char *line)
472 {
473 int index, values = 0;
474 char *p, *buf = NULL;
475
476 this->wasExecuted = TRUE;
477
478 //
479 // Handle the 'min=%g' part of the message.
480 //
481 if ( (p = strstr((char*)line,"min=")) ) {
482 values++;
483 while (*p != '=') p++;
484 p++;
485 buf = DuplicateString(p);
486 index = 0;
487 if (IsScalar(buf, index)) {
488 buf[index] = '\0';
489 this->setInputAttributeFromServer(MIN_PARAM_NUM,
490 buf, DXType::UndefinedType);
491 #ifndef HAS_START_STOP
492 this->setStartValue(atoi(buf));
493 #endif
494 }
495 delete buf;
496 }
497 //
498 // Handle the 'max=%g' part of the message.
499 //
500 if ( (p = strstr((char*)line,"max=")) ) {
501 values++;
502 while (*p != '=') p++;
503 p++;
504 buf = DuplicateString(p);
505 index = 0;
506 if (IsScalar(buf, index)) {
507 buf[index] = '\0';
508 this->setInputAttributeFromServer(MAX_PARAM_NUM,
509 buf, DXType::UndefinedType);
510 #ifndef HAS_START_STOP
511 this->setStopValue(atoi(buf));
512 #endif
513 }
514 delete buf;
515 }
516 //
517 // Handle the 'delta=%g' part of the message.
518 // Since the attribute and parameter value have the same type, but
519 // different meanings we only set the attribute value as received from
520 // the exec.
521 // NOTE: this is done before 'frame=' so that we can compute an accurate
522 // next frame.
523 //
524 if ( (p = strstr((char*)line,"delta=")) ) {
525 values++;
526 while (*p != '=') p++;
527 p++;
528 buf = DuplicateString(p);
529 index = 0;
530 if (IsScalar(buf, index)) {
531 buf[index] = '\0';
532 this->setInputAttributeFromServer(DELTA_PARAM_NUM,
533 buf, DXType::UndefinedType);
534 }
535 delete buf;
536 }
537
538 //
539 // Handle the 'frame=%g' part of the message.
540 //
541 if ( (p = strstr((char*)line,"frame=")) ) {
542 values++;
543 while (*p != '=') p++;
544 p++;
545 //
546 // Change the currently display frame and ignore the next
547 // 'frame %d %d' message from the executive (not Sequencer).
548 //
549 this->current_defined = TRUE;
550 this->current = atoi(p);
551 this->next = this->current + this->getDeltaValue();
552 this->ignoreFirstFrameMsg = TRUE;
553 }
554
555 //
556 // If min/max is defaulting (i.e. set from the frame control) and
557 // max/min is set then we need to be sure that the defaulting value
558 // is consistent with the set value.
559 //
560 int min_val = this->getMinimumValue();
561 int max_val = this->getMaximumValue();
562 boolean min_dflting = this->isInputDefaulting(MIN_PARAM_NUM);
563 boolean max_dflting = this->isInputDefaulting(MAX_PARAM_NUM);
564 if (min_dflting || max_dflting) {
565 char *setattr = NULL, *set = NULL;
566 if (max_dflting && (min_val > max_val)) {
567 this->setMaximumValue(min_val);
568 max_val = min_val;
569 set = "minimum";
570 setattr = "maximum";
571 } else if (min_dflting && (min_val > max_val)) {
572 this->setMinimumValue(max_val);
573 min_val = max_val;
574 set = "maximum";
575 setattr = "minimum";
576 }
577 if (setattr) {
578 WarningMessage("%s value provided to %s conflicts "
579 "with %s value set with 'Frame Control' dialog"
580 "...adjusting %s.",
581 set, this->getNameString(),
582 setattr,setattr);
583 }
584 }
585
586 //
587 // Make sure that the start/stop values are both within range of the
588 // possibly new min and/or max values.
589 //
590 int stop_val = this->getStopValue();
591 int start_val = this->getStartValue();
592 if ((start_val < min_val) || (start_val > max_val))
593 this->setStartValue(min_val);
594 if ((stop_val < min_val) || (stop_val > max_val))
595 this->setStopValue(max_val);
596
597 #ifdef HAS_START_STOP
598 //
599 // Handle the 'start=%d' part of the message.
600 //
601 if (p = strstr((char*)line,"start=")) {
602 values++;
603 while (*p != '=') p++;
604 p++;
605 buf = DuplicateString(p);
606 index = 0;
607 if (IsScalar(buf, index)) {
608 buf[index] = '\0';
609 this->setInputAttributeFromServer(START_PARAM_NUM,
610 buf, DXType::UndefinedType);
611 //
612 // Change the currently display frame and ignore the next
613 // 'frame %d %d' message.
614 //
615 this->current_defined = TRUE;
616 this->current = this->getStartValue();
617 this->next = this->current + this->getDeltaValue();
618 this->ignoreFirstFrameMsg = TRUE;
619 }
620 delete buf;
621 }
622 //
623 // Handle the 'end=%d' part of the message.
624 //
625 if (p = strstr((char*)line,"end=")) {
626 values++;
627 while (*p != '=') p++;
628 p++;
629 buf = DuplicateString(p);
630 index = 0;
631 if (IsScalar(buf, index)) {
632 buf[index] = '\0';
633 this->setInputAttributeFromServer(STOP_PARAM_NUM,
634 buf, DXType::UndefinedType);
635 }
636 delete buf;
637 }
638 #endif
639
640 return values;
641 }
642
reflectStateChange(boolean unmanage)643 void SequencerNode::reflectStateChange(boolean unmanage)
644 {
645 if (this->seq_window)
646 this->seq_window->handleStateChange(unmanage);
647
648 //
649 // We do this here because we use isVisualNotificationDeferred() in
650 // in this->updateAttributes() which means that we must call it again
651 // once notification is undeferred (i.e. in reflectStateChange()).
652 //
653 this->updateAttributes();
654 }
655
656 #if 0 // 8/9/93
657 boolean SequencerNode::isAttributeVisuallyWriteable(int input_index)
658 {
659 return
660 this->isInputDefaulting(DATA_PARAM_NUM) &&
661 this->ShadowedOutputNode::isAttributeVisuallyWriteable(input_index);
662 }
663 #endif
isMinimumVisuallyWriteable()664 boolean SequencerNode::isMinimumVisuallyWriteable()
665 {
666 return this->isInputDefaulting(DATA_PARAM_NUM) &&
667 this->isAttributeVisuallyWriteable(MIN_PARAM_NUM);
668 }
isMaximumVisuallyWriteable()669 boolean SequencerNode::isMaximumVisuallyWriteable()
670 {
671 return this->isInputDefaulting(DATA_PARAM_NUM) &&
672 this->isAttributeVisuallyWriteable(MAX_PARAM_NUM);
673 }
674 #ifdef HAS_START_STOP
isStartVisuallyWriteable()675 boolean SequencerNode::isStartVisuallyWriteable()
676 { return this->isAttributeVisuallyWriteable(START_PARAM_NUM); }
isStopVisuallyWriteable()677 boolean SequencerNode::isStopVisuallyWriteable()
678 { return this->isAttributeVisuallyWriteable(STOP_PARAM_NUM); }
679 #endif
isDeltaVisuallyWriteable()680 boolean SequencerNode::isDeltaVisuallyWriteable()
681 { return this->isAttributeVisuallyWriteable(DELTA_PARAM_NUM); }
682
initMinimumValue(int val)683 boolean SequencerNode::initMinimumValue(int val)
684 {
685 char buf[64];
686 sprintf(buf,"%d",val);
687 return this->initInputAttributeParameter(MIN_PARAM_NUM,buf);
688 }
setMinimumValue(int val)689 boolean SequencerNode::setMinimumValue(int val)
690 {
691 char buf[64];
692 sprintf(buf,"%d",val);
693 return this->setInputAttributeParameter(MIN_PARAM_NUM,buf);
694 }
695 #if 0
696 boolean SequencerNode::setMinimumValue(const char *val)
697 {
698 return this->setInputAttributeParameter(MIN_PARAM_NUM,val);
699 }
700 #endif
getMinimumValue()701 int SequencerNode::getMinimumValue()
702 {
703 const char *val = this->getInputAttributeParameterValue(MIN_PARAM_NUM);
704 return atoi(val);
705 }
initMaximumValue(int val)706 boolean SequencerNode::initMaximumValue(int val)
707 {
708 char buf[64];
709 sprintf(buf,"%d",val);
710 return this->initInputAttributeParameter(MAX_PARAM_NUM,buf);
711 }
setMaximumValue(int val)712 boolean SequencerNode::setMaximumValue(int val)
713 {
714 char buf[64];
715 sprintf(buf,"%d",val);
716 return this->setInputAttributeParameter(MAX_PARAM_NUM,buf);
717 }
718 #if 0
719 boolean SequencerNode::setMaximumValue(const char *val)
720 {
721 return this->setInputAttributeParameter(MAX_PARAM_NUM,val);
722 }
723 #endif
getMaximumValue()724 int SequencerNode::getMaximumValue()
725 {
726 const char *val = this->getInputAttributeParameterValue(MAX_PARAM_NUM);
727 return atoi(val);
728 }
initDeltaValue(int val)729 boolean SequencerNode::initDeltaValue(int val)
730 {
731 char buf[64];
732 sprintf(buf,"%d",val);
733 return this->initInputAttributeParameter(DELTA_PARAM_NUM,buf);
734 }
setDeltaValue(int val)735 boolean SequencerNode::setDeltaValue(int val)
736 {
737 char buf[64];
738 sprintf(buf,"%d",val);
739 return this->setInputAttributeParameter(DELTA_PARAM_NUM,buf);
740 }
741 #if 0
742 boolean SequencerNode::setDeltaValue(const char *val)
743 {
744 return this->setInputAttributeParameter(DELTA_PARAM_NUM,val);
745 }
746 #endif
getDeltaValue()747 int SequencerNode::getDeltaValue()
748 {
749 const char *val = this->getInputAttributeParameterValue(DELTA_PARAM_NUM);
750 return atoi(val);
751 }
initStartValue(int val)752 boolean SequencerNode::initStartValue(int val)
753 {
754 #ifndef HAS_START_STOP
755 this->startValue = val;
756 this->updateAttributes();
757 return TRUE;
758 #else
759 char buf[64];
760 sprintf(buf,"%d",val);
761 return this->initInputAttributeParameter(START_PARAM_NUM,buf);
762 #endif
763 }
setStartValue(int val)764 boolean SequencerNode::setStartValue(int val)
765 {
766 #ifndef HAS_START_STOP
767 this->startValue = val;
768 this->updateAttributes();
769 return TRUE;
770 #else
771 char buf[64];
772 sprintf(buf,"%d",val);
773 return this->setInputAttributeParameter(START_PARAM_NUM,buf);
774 #endif
775 }
776 #if 0
777 boolean SequencerNode::setStartValue(const char *val)
778 {
779 return this->setInputAttributeParameter(START_PARAM_NUM,val);
780 }
781 #endif
getStartValue()782 int SequencerNode::getStartValue()
783 {
784 #ifndef HAS_START_STOP
785 return this->startValue;
786 #else
787 const char *val = this->getInputAttributeParameterValue(START_PARAM_NUM);
788 return atoi(val);
789 #endif
790 }
initStopValue(int val)791 boolean SequencerNode::initStopValue(int val)
792 {
793 #ifndef HAS_START_STOP
794 this->stopValue = val;
795 this->updateAttributes();
796 return TRUE;
797 #else
798 char buf[64];
799 sprintf(buf,"%d",val);
800 return this->initInputAttributeParameter(STOP_PARAM_NUM,buf);
801 #endif
802 }
setStopValue(int val)803 boolean SequencerNode::setStopValue(int val)
804 {
805 #ifndef HAS_START_STOP
806 this->stopValue = val;
807 this->updateAttributes();
808 return TRUE;
809 #else
810 char buf[64];
811 sprintf(buf,"%d",val);
812 return this->setInputAttributeParameter(STOP_PARAM_NUM,buf);
813 #endif
814 }
815 #if 0
816 boolean SequencerNode::setStopValue(const char *val)
817 {
818 return this->setInputAttributeParameter(STOP_PARAM_NUM,val);
819 }
820 #endif
getStopValue()821 int SequencerNode::getStopValue()
822 {
823 #ifndef HAS_START_STOP
824 return this->stopValue;
825 #else
826 const char *val = this->getInputAttributeParameterValue(STOP_PARAM_NUM);
827 return atoi(val);
828 #endif
829 }
830
831 //
832 // Disable the Frame control.
833 //
disableFrameControl()834 void SequencerNode::disableFrameControl()
835 {
836 if (this->seq_window)
837 this->seq_window->disableFrameControl();
838 }
839 //
840 // Enable the Frame control if the node is not data driven.
841 //
enableFrameControl()842 void SequencerNode::enableFrameControl()
843 {
844 if (this->seq_window)
845 this->seq_window->enableFrameControl();
846 }
setPlayDirection(SequencerDirection dir)847 void SequencerNode::setPlayDirection(SequencerDirection dir)
848 {
849 if (this->seq_window)
850 this->seq_window->setPlayDirection(dir);
851 }
setForwardPlay()852 void SequencerNode::setForwardPlay()
853 {
854 if (this->seq_window)
855 this->seq_window->setPlayDirection(SequencerNode::ForwardDirection);
856 }
setBackwardPlay()857 void SequencerNode::setBackwardPlay()
858 {
859 if (this->seq_window)
860 this->seq_window->setPlayDirection(SequencerNode::BackwardDirection);
861 }
setStepMode(boolean val)862 void SequencerNode::setStepMode(boolean val)
863 {
864 if (this->step == val)
865 return;
866
867 this->step = val;
868 if (this->seq_window)
869 this->seq_window->handleStateChange(FALSE);
870
871 }
setLoopMode(boolean val)872 void SequencerNode::setLoopMode(boolean val)
873 {
874 if (this->loop == val)
875 return;
876
877 this->loop = val;
878 if (this->seq_window)
879 this->seq_window->handleStateChange(FALSE);
880
881 }
setPalindromeMode(boolean val)882 void SequencerNode::setPalindromeMode(boolean val)
883 {
884 if (this->palindrome == val)
885 return;
886
887 this->palindrome = val;
888 if (this->seq_window)
889 this->seq_window->handleStateChange(FALSE);
890
891 }
892 //
893 // Get a string representing the assignment to the global vcr variables,
894 // @startframe, @frame, @nextframe, @endframe and @deltaframe.
895 // The returned string must be deleted by the caller.
896 // If the Sequencer is data-driven then we send the @*frame values as NULL,
897 // since the Sequencer module will set these internally. Also, we
898 // want to be sure we don't pass in any values that might be replicated
899 // later in the sequence which would confuse the caching mechanism.
900 // For example, if we set @nextframe=2, and the sequence goes 0 1 2 3 ...,
901 // then the output will be 0 1 2 0, because the executive thinks the
902 // Sequencer has already seen the 4th set of values (remember that the
903 // Sequencer is called something like the following...
904 // Sequencer_1_in_3 = @frame ;
905 // Sequencer_1_out_1 = Sequencer(...,Sequencer_1_in_3,...);
906 // The idea here is to set @nextframe to something that will never be
907 // seen during the sequence.
908 //
909 //
getFrameControlString()910 char *SequencerNode::getFrameControlString()
911 {
912 char *command = new char[128];
913
914 #if 0
915 if (this->isDataDriven()) {
916 // FIXME: these -1e6's should be replaced by NULLs and 'play'
917 // should not init @nextframe=0 if it sees @nextframe==NULL;
918 strcpy(command, "@startframe,@frame,@nextframe,@endframe,@deltaframe ="
919 " -1e6, -1e6, -1e6, -1e6, -1e6;\n");
920 }
921 else
922 #endif
923 {
924 sprintf(command,
925 "@startframe,@frame,@nextframe,@endframe,@deltaframe "
926 "= %d,%d,%d,%d,%d;\n",
927 this->getStartValue(),
928 this->current_defined ? this->current : this->next,
929 this->next,
930 this->getStopValue(),
931 this->getDeltaValue());
932 }
933
934 return command;
935 }
936 //
937 // The Sequencer always expects the 'frame %d %d' message and when
938 // data-driven expects 'Sequencer_%d: ...' messages. We install the
939 // handler for the 'frame' message here and then call the super class
940 // to install the 'Sequencer_%d:' handler.
941 //
updateModuleMessageProtocol(DXPacketIF * pif)942 void SequencerNode::updateModuleMessageProtocol(DXPacketIF *pif)
943 {
944
945 pif->setHandler(DXPacketIF::INTERRUPT,
946 SequencerNode::ProcessFrameInterrupt,
947 (void*)this,
948 "frame ");
949
950 this->ShadowedOutputNode::updateModuleMessageProtocol(pif);
951 }
952
953 //
954 // Handler for 'frame %d %d' messages.
955 // If the Sequencer is data-driven and has received a 'frame=%d:%d' message
956 // then we ignore the next 'frame %d %d' message.
957 //
ProcessFrameInterrupt(void * clientData,int id,void * p)958 void SequencerNode::ProcessFrameInterrupt(void *clientData, int id, void *p)
959 {
960 char *line = (char *)p;
961 char buffer[10];
962 int frame, next_frame, parsed;
963 Widget vcr = NUL(Widget);
964 SequencerNode* sequencer = (SequencerNode*)clientData;
965
966 if (sequencer->ignoreFirstFrameMsg == TRUE) {
967 sequencer->ignoreFirstFrameMsg = FALSE;
968 return;
969 }
970
971 vcr = sequencer->getVCRWidget();
972
973 parsed = sscanf(line,"%s %d %d", buffer, &frame, &next_frame);
974 ASSERT(parsed == 3);
975
976 sequencer->current = frame;
977 sequencer->next = next_frame;
978 sequencer->current_defined = TRUE;
979
980 if (vcr)
981 XtVaSetValues(vcr,
982 XmNcurrent, sequencer->current,
983 XmNcurrentVisible, sequencer->current_defined,
984 XmNnext, sequencer->next,
985 NULL);
986 }
987
988 //
989 // Determine if this node is of the given class.
990 //
isA(Symbol classname)991 boolean SequencerNode::isA(Symbol classname)
992 {
993 Symbol s = theSymbolManager->registerSymbol(ClassSequencerNode);
994 if (s == classname)
995 return TRUE;
996 else
997 return this->ShadowedOutputNode::isA(classname);
998 }
999
1000 //
1001 // Make sure the value of the parameter that holds a list of ui attributes
1002 // (i.e. min/max/incr) is up to date in the executive.
1003 // Always send it since the input attribute is cache:0.
1004 //
updateAttributes()1005 void SequencerNode::updateAttributes()
1006 {
1007 char val[128];
1008
1009 //
1010 // Using isVisualNotificationDeferred() is somewhat inconsistent,
1011 // but we're using it here to avoid sending multiple messages back to
1012 // the executive when inside this->handleModuleMessage() during which
1013 // time we know that visual notification is deferred.
1014 // This of course means that we must call this again when notification
1015 // is undeferred (i.e. in reflectStateChange);
1016 //
1017 if (!this->isVisualNotificationDeferred()) {
1018 sprintf(val,"{ %d %d %d %d %d %d }",
1019 this->getMinimumValue(),
1020 this->getMaximumValue(),
1021 this->getDeltaValue(),
1022 this->getStartValue(),
1023 this->getStopValue(),
1024 this->wasExecuted ? 1 : 0);
1025 this->setInputValueQuietly(ATTR_PARAM_NUM,val,
1026 DXType::IntegerListType);
1027 }
1028 }
canSwitchNetwork(Network * from,Network * to)1029 boolean SequencerNode::canSwitchNetwork(Network *from, Network *to)
1030 {
1031 if (to->sequencer != NULL) {
1032 WarningMessage("Attempt to add a second Sequencer to network ignored.");
1033 return FALSE;
1034 }
1035
1036 return TRUE;
1037 }
1038 //
1039 // Return TRUE if this node has state that will be saved in a .cfg file.
1040 //
hasCfgState()1041 boolean SequencerNode::hasCfgState()
1042 {
1043 return TRUE;
1044 }
1045
1046
getMessageIdParamNumber()1047 int SequencerNode::getMessageIdParamNumber() { return ID_PARAM_NUM; }
1048
isStartup()1049 boolean SequencerNode::isStartup()
1050 {
1051 if (!this->seq_window) return this->startup;
1052 return this->seq_window->isStartup();
1053 }
1054
printInputAsJava(int input)1055 boolean SequencerNode::printInputAsJava(int input)
1056 {
1057 boolean retval = FALSE;
1058 switch (input) {
1059 case MIN_PARAM_NUM:
1060 case MAX_PARAM_NUM:
1061 case DELTA_PARAM_NUM:
1062 retval = TRUE;
1063 break;
1064 default:
1065 break;
1066 }
1067 return retval;
1068 }
1069
getJavaInputValueString(int input)1070 const char* SequencerNode::getJavaInputValueString(int input)
1071 {
1072 const char* retval = NUL(char*);
1073 static char tbuf[32];
1074 switch (input) {
1075 case MIN_PARAM_NUM:
1076 sprintf (tbuf, "%d", this->getMinimumValue());
1077 retval = tbuf;
1078 break;
1079 case MAX_PARAM_NUM:
1080 sprintf (tbuf, "%d", this->getMaximumValue());
1081 retval = tbuf;
1082 break;
1083 case DELTA_PARAM_NUM:
1084 sprintf (tbuf, "%d", this->getDeltaValue());
1085 retval = tbuf;
1086 break;
1087 default:
1088 retval = this->ShadowedOutputNode::getInputValueString(input);
1089 break;
1090 }
1091 return retval;
1092 }
1093