/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ #include #include "UIConfig.h" #include #ifdef ABS_IN_MATH_H # define abs __Dont_define_abs #endif #include #ifdef ABS_IN_MATH_H # undef abs #endif #include "defines.h" #include "lex.h" #include "ScalarNode.h" #include "ScalarInstance.h" #include "ErrorDialogManager.h" #include "Parameter.h" #include "AttributeParameter.h" #include "Network.h" #include "ListIterator.h" #include "WarningDialogManager.h" // // The following define the mapping of parameter indices to parameter // functionality in the module that is used to 'data-drive' the // ScalarNode class and Nodes derived from it. // These MUST match the entries in the ui.mdf file for the interactors // that expect to be implemented by the ScalarInteractor class. // #define ID_PARAM_NUM 1 // Id used for UI messages #define DATA_PARAM_NUM 2 // The input object #define CVAL_PARAM_NUM 3 // Current Value #define REFRESH_PARAM_NUM 4 // Does the module refresh #define MIN_PARAM_NUM 5 // The current minimum #define MAX_PARAM_NUM 6 // The current maximum #define INCR_PARAM_NUM 7 // The current increment #define INCRMETHOD_PARAM_NUM 8 // Method used to interpret incr. #define DECIMALS_PARAM_NUM 9 // The number of decimals to display #define DFLTVAL_PARAM_NUM 10 // The default output indicator #define LABEL_PARAM_NUM 11 // The label // The total number of inputs as defined in the mdf file. #define EXPECTED_SCALAR_INPUTS LABEL_PARAM_NUM #define DEFAULT_VALUE 0.0 #define DEFAULT_INCR 1.0 #define DEFAULT_MAX 1.0e6 #define DEFAULT_MIN -1.0e6 #define DEFAULT_SCALAR_DECIMALS 5 #define DEFAULT_VALUE_STR " 0 " #define DEFAULT_INCR_STR " 1 " #define DEFAULT_MAX_STR " 100000 " #define DEFAULT_MIN_STR " -100000 " #define DEFAULT_SCALAR_DECIMALS_STR " 5 " // // Create the component // ScalarNode::ScalarNode(NodeDefinition *nd, Network *net, int instance, boolean isVector, int dimensions) : InteractorNode(nd, net, instance) { ASSERT(dimensions > 0); this->isContinuousUpdate = FALSE; this->vectorType = isVector; this->numComponents = dimensions; this->rangeCheckDeferrals = 0; this->needsRangeCheck = FALSE; if (!this->verifyInputCount()) return; // // The attribute is an absolute increment and the parameter value // is a relative increment (between 0..1). They have the same types // so turn off value synchronization in the increment parameter (which // is where the increment value is stored). // AttributeParameter *ap = (AttributeParameter*) this->getInputParameter(INCR_PARAM_NUM); ASSERT(ap); ap->setSyncOnTypeMatch(FALSE); } boolean ScalarNode::hasDynamicDimensionality(boolean ignoreDataDriven) { return this->isVectorType() && (ignoreDataDriven || !this->isDataDriven()); } // // Change the dimensionality of a Vector interactor. // boolean ScalarNode::doDimensionalityChange(int new_dim) { ScalarInstance *si; int old_dim = this->getComponentCount(); ASSERT(this->isVectorType()); if (new_dim == old_dim) return TRUE; this->numComponents = new_dim; // // Delete the interactors, so that they don't get updated when setting // the output value. If we don't do this, we can get references to // non-existent vector components. // ListIterator iterator(this->instanceList); while (si = (ScalarInstance*)iterator.getNext()) si->uncreateInteractor(); // // Adjust the and output values first. // this->adjustOutputDimensions(old_dim, new_dim); // // Adjust all the attribute values. // this->adjustAttributeDimensions(old_dim,new_dim); // // Now have all the instances adjust themselves // iterator.setList(this->instanceList); while (si = (ScalarInstance*)iterator.getNext()) { if (!si->handleNewDimensionality()) return FALSE; } return TRUE; } boolean ScalarNode::adjustOutputDimensions(int old_dim, int new_dim) { const char *oldval = this->getOutputValueString(1); char *newval = DXValue::AdjustVectorDimensions(oldval, new_dim, DEFAULT_VALUE, this->isIntegerTypeComponent()); if (!newval) return FALSE; this->setOutputValue(1,newval,DXType::VectorType,TRUE); delete newval; return TRUE; } boolean ScalarNode::adjustAttributeDimensions(int old_dim, int new_dim) { boolean is_int = this->isIntegerTypeComponent(); const char *v; char *newval; // // Adjust the min attribute // v = this->getInputAttributeParameterValue(MIN_PARAM_NUM); newval = DXValue::AdjustVectorDimensions(v, new_dim, DEFAULT_MIN,is_int); this->setMinimumAttribute(newval); delete newval; // // Adjust the max attribute // v = this->getInputAttributeParameterValue(MAX_PARAM_NUM); newval = DXValue::AdjustVectorDimensions(v, new_dim, DEFAULT_MAX, is_int); this->setMaximumAttribute(newval); delete newval; // // Adjust the delta attribute // v = this->getInputAttributeParameterValue(INCR_PARAM_NUM); newval = DXValue::AdjustVectorDimensions(v, new_dim, DEFAULT_INCR, is_int); this->setDeltaAttribute(newval); delete newval; // // Adjust the decimals attribute // double decimals; if (is_int) decimals = 0; else decimals = DEFAULT_SCALAR_DECIMALS; v = this->getInputAttributeParameterValue(DECIMALS_PARAM_NUM); newval = DXValue::AdjustVectorDimensions(v, new_dim, decimals, TRUE); this->setDecimalsAttribute(newval); delete newval; return TRUE; } // // Set the interactor's default attributes. // boolean ScalarNode::setDefaultAttributes() { const char *id; char *min, *max, *incr, *decimals; boolean r; // FIXME: these strings should be build from DEFAULT_*_STR switch (this->numComponents) { case 1: if (this->isVectorType()) { min = "[ -1000000 ]"; max = "[ 1000000 ]"; incr = "[ 1 ]"; decimals = (this->isIntegerTypeComponent() ? "[0]" : "[5]"); } else { min = "-1000000"; max = "1000000"; incr = "1"; decimals = (this->isIntegerTypeComponent() ? "0" : "5"); } break; case 2: min = "[-1000000 -1000000]"; max = "[ 1000000 1000000]"; incr = "[ 1 1]"; decimals= "[ 5 5]"; break; case 3: min = "[-1000000 -1000000 -1000000]"; max = "[ 1000000 1000000 1000000]"; incr = "[ 1 1 1]"; decimals= "[ 5 5 5]"; break; default: ASSERT(0); } id = this->getModuleMessageIdString(); if ((this->setInputValue(ID_PARAM_NUM,id, DXType::UndefinedType,FALSE) == DXType::UndefinedType) || !this->initMinimumAttribute(min) || !this->initMaximumAttribute(max) || !this->initDeltaAttribute(incr) || !this->initDecimalsAttribute(decimals) ) { r = FALSE; } else r = TRUE; return r; } // // Make sure the number of inputs is the number expected. // boolean ScalarNode::verifyInputCount() { if (this->getInputCount() != EXPECTED_SCALAR_INPUTS) { ErrorMessage( "Expected %d inputs for %s interactor, please check the mdf file.\n", EXPECTED_SCALAR_INPUTS, this->getNameString()); return FALSE; } return TRUE; } // // Called after allocation is complete. // The work done here is to assigned default values to the InteractorNode inputs // so that we can use them later when setting the attributes for the // Interactor. // boolean ScalarNode::initialize() { if (!this->verifyInputCount()) return FALSE; // FIXME: these strings should be build from DEFAULT_*_STR const char *value; switch (this->numComponents) { case 1: if (this->isVectorType()) value = "[ 0 ]"; else value = "0"; break; case 2: value = "[ 0 0 ]"; break; case 3: value = "[ 0 0 0 ]"; break; default: return FALSE; } if (!this->setDefaultAttributes() || (this->setOutputValue(1,value, DXType::UndefinedType,FALSE) == DXType::UndefinedType) ){ ErrorMessage( "Error setting default attributes for %s interactor, check ui.mdf\n", this->getNameString()); return FALSE; } // // Make the shadows defaulting (even though we have a current output) // so that the executive module can tell when it is executing a just // placed module and one that is read in from a .net or .cfg file. // When read in, the output will be set again which should make the // corresponding shadowing input be non-defaulting. // this->setShadowingInputsDefaulting(); return TRUE; } // The messages we parse can contain one or more of the following... // // 'min=%g' 'max=%g' 'delta=%g' 'value=%g' 'decimals=%d' // // or one or more of the following... // // 'min=[%g %g %g]' 'max=[%g %g %g]' 'delta=[%g %g %g]' 'value=[%g %g %g]' // 'decimals=[%g %g %g]' // // If any input or output values are to be changed, don't send them // because the module backing up the interactor will have just executed // and if the UI is in 'execute on change' mode then there will be an // extra execution. // // Returns the number of attributes parsed. // int ScalarNode::handleInteractorMsgInfo(const char *line) { int values; if (this->isVectorType()) values = this->handleVectorMsgInfo(line); else values = this->handleScalarMsgInfo(line); // // Handle the 'method="%s"' part of the message. // We only need to look for the message if we don't already have it. // if (this->isInputConnected(INCRMETHOD_PARAM_NUM)) { char *p, buf[128]; if ((p = strstr((char*)line,"method=")) && FindDelimitedString(p,'"','"', buf)) { values++; this->setInputAttributeFromServer(INCRMETHOD_PARAM_NUM,buf, DXType::StringType); } } // // Make sure that the min or max sent back from the executive is // consistent. If the user has not connected the data tab and has // only one of min and max set then it is possible that the value sent // back by the module conflicts with the other value stored in the ui. // if (!this->isInputDefaulting(DATA_PARAM_NUM)) { boolean min_dflting = this->isInputDefaulting(MIN_PARAM_NUM); boolean max_dflting = this->isInputDefaulting(MAX_PARAM_NUM); if ((min_dflting && !max_dflting) || (!min_dflting && max_dflting)) { int i, comps = this->getComponentCount(); boolean issue_warning = FALSE; for (i=1 ; i<=comps ; i++) { double minval = this->getComponentMinimum(i); double maxval = this->getComponentMaximum(i); if (minval > maxval) { issue_warning = TRUE; if (min_dflting) this->setComponentMinimum(i,maxval); else this->setComponentMaximum(i,minval); } } if (issue_warning) { char *setattr, *set; if (min_dflting) { set = "maximum"; setattr = "minimum"; } else { set = "minimum"; setattr = "maximum"; } WarningMessage("%s value provided to %s conflicts " "with %s value set with 'Set Attributes' dialog" "...adjusting %s.", set, this->getNameString(), setattr,setattr); } } } return values; } // The messages we parse can contain one or more of the following... // // 'min=%g' 'max=%g' 'delta=%g' 'value=%g' 'decimals=%d' // // If any input or output values are to be changed, don't send them // because the module backing up the interactor will have just executed // and if the UI is in 'execute on change' mode then there will be an // extra execution. // // Returns the number of attributes parsed. // int ScalarNode::handleScalarMsgInfo(const char *line) { int index, values = 0; char *p, *buf = NULL; // // Handle the 'min=%g' part of the message. // if (p = strstr((char*)line,"min=")) { values++; while (*p != '=') p++; p++; buf = DuplicateString(p); index = 0; if (IsScalar(buf, index)) { buf[index] = '\0'; this->setInputAttributeFromServer(MIN_PARAM_NUM,buf, DXType::UndefinedType); } delete buf; } // // Handle the 'max=%g' part of the message. // if (p = strstr((char*)line,"max=")) { values++; while (*p != '=') p++; p++; buf = DuplicateString(p); index = 0; if (IsScalar(buf, index)) { buf[index] = '\0'; this->setInputAttributeFromServer(MAX_PARAM_NUM,buf, DXType::UndefinedType); } delete buf; } // // Handle the 'delta=%g' part of the message. // Since the attribute and parameter value have the same type, but // different meanings we only set the attribute value as received from // the exec. // if (p = strstr((char*)line,"delta=")) { values++; while (*p != '=') p++; p++; buf = DuplicateString(p); index = 0; if (IsScalar(buf, index)) { buf[index] = '\0'; this->setInputAttributeFromServer(INCR_PARAM_NUM,buf, DXType::UndefinedType); } delete buf; } // // Handle the 'decimals=%d' part of the message. // if (p = strstr((char*)line,"decimals=")) { values++; while (*p != '=') p++; p++; buf = DuplicateString(p); index = 0; if (IsScalar(buf, index)) { buf[index] = '\0'; this->setInputAttributeFromServer(DECIMALS_PARAM_NUM,buf, DXType::UndefinedType); } delete buf; } // // Handle the 'value=%g' part of the message. // if (p = strstr((char*)line,"value=")) { values++; while (*p != '=') p++; p++; buf = DuplicateString(p); index = 0; if (IsScalar(buf, index)) { buf[index] = '\0'; this->setShadowedOutputSentFromServer(1,buf, DXType::UndefinedType); } delete buf; } return values; } // // Called when a message is received from the executive to parse class // specific message information. // // The messages we handle can contain one or more of the following... // // 'dim=%d' // 'min=[%g %g %g]' 'max=[%g %g %g]' 'delta=[%g %g %g]' 'value=[%g %g %g]' // 'decimals=[%g %g %g]' // // If any input or output values are to be changed, don't send them // because the module backing up the interactor will have just executed // and if the UI is in 'execute on change' mode then there will be an // extra execution. // // Returns the number of attributes parsed. // int ScalarNode::handleVectorMsgInfo(const char *line) { char *p; int values = 0; char buf[256]; // // Handle the 'dim=%d' part of the message. // This message must be handled first, because changing the dimensionality // resets all the interactor values which can be reset by subsequent // assignments in the current message. // We don't need to do a 'values++' since the info is handled locally // with this->changeDimensionality(). // if (p = strstr((char*)line,"dim=")) { while (*p != '=') p++; p++; int dim = atoi(p); if (this->isVectorType() && (this->getComponentCount() != dim)) this->changeDimensionality(dim); } // // Handle the 'min=[%g...]' part of the message. // if (p = strstr((char*)line,"min=")) { values++; while (*p != '=') p++; p++; if (FindDelimitedString(p,'[',']', buf)) { this->setInputAttributeFromServer(MIN_PARAM_NUM,buf, DXType::UndefinedType); } } // // Handle the 'max=[%g...]' part of the message. // if (p = strstr((char*)line,"max=")) { values++; while (*p != '=') p++; p++; if (FindDelimitedString(p,'[',']', buf)) { this->setInputAttributeFromServer(MAX_PARAM_NUM,buf, DXType::UndefinedType); } } // // Handle the 'delta=[%g...]' part of the message. // Since the attribute and parameter value have the same type, but // different meanings we only set the attribute value as received from // the exec. // if (p = strstr((char*)line,"delta=")) { values++; while (*p != '=') p++; p++; if (FindDelimitedString(p,'[',']', buf)) { this->setInputAttributeFromServer(INCR_PARAM_NUM,buf, DXType::UndefinedType); } } // // Handle the 'decimals=[%g...]' part of the message. // if (p = strstr((char*)line,"decimals=")) { values++; while (*p != '=') p++; p++; if (FindDelimitedString(p,'[',']', buf)) { this->setInputAttributeFromServer(DECIMALS_PARAM_NUM,buf, DXType::UndefinedType); } } // // Handle the 'value=[%g...]' part of the message. // if (p = strstr((char*)line,"value=")) { values++; while (*p != '=') p++; p++; if (FindDelimitedString(p,'[',']', buf)) { this->setShadowedOutputSentFromServer(1,buf, DXType::UndefinedType); } } return values; } boolean ScalarNode::cfgParseComment(const char *comment, const char *filename, int lineno) { // // Don't do range checking until after the value AND the component's // min/max have been set (see cfgParseComponentComment()). // if (strncmp(" interactor",comment,11)) this->deferRangeChecking(); return this->cfgParseComponentComment(comment, filename,lineno) || this->cfgParseInstanceComment(comment, filename, lineno) || this->cfgParseLocalIncrementComment(comment, filename, lineno) || this->cfgParseLocalContinuousComment(comment, filename, lineno) || this->InteractorNode::cfgParseComment(comment, filename, lineno); } // // Print the '// interactor...' comment to the file. // We override the parent's method so that we can print num_components // correctly. // boolean ScalarNode::cfgPrintInteractorComment(FILE *f) { return fprintf(f, "// interactor %s[%d]: num_components = %d, value = %s\n", this->getNameString(), this->getInstanceNumber(), this->getComponentCount(), this->getOutputValueString(1)) >= 0; } // // Print auxiliary info for this interactor, which includes all global // information about each component. // boolean ScalarNode::cfgPrintInteractorAuxInfo(FILE *f) { int i, ncomp = this->getComponentCount(); for (i=1 ; i<=ncomp ; i++ ) { if (fprintf(f, "// component[%d]: minimum = %g, maximum = %g, " "global increment = %g, decimal = %d, global continuous = %d\n", i-1, // File uses 0 based indexing this->getComponentMinimum(i), this->getComponentMaximum(i), this->getComponentDelta(i), this->getComponentDecimals(i), this->isContinuous()) < 0) return FALSE; } return TRUE; } // // Print auxiliary info for the interactor instance, which include all local // information about each component. // boolean ScalarNode::cfgPrintInstanceAuxInfo(FILE *f, InteractorInstance *ii) { int i, ncomp = this->getComponentCount(); ScalarInstance *si = (ScalarInstance *)ii; if (fprintf(f, "// local continuous: value = %d, mode = %s\n", (si->getLocalContinuous() ? 1 : 0), (si->usingGlobalContinuous() ? "global" : "local") ) < 0) return FALSE; for (i=1 ; i<=ncomp ; i++ ) { if (fprintf(f, "// local increment[%d]: value = %g, mode = %s\n", i-1, // File uses 0 based indexing si->getLocalDelta(i), (si->isLocalDelta(i) ? "local" : "global") ) < 0) return FALSE; } return TRUE; } // // This is the same as for the super class except that when we get a new // instance we build the list of local attributes (one LocalAttributes // for each component). // boolean ScalarNode::cfgParseInstanceComment(const char *comment, const char *filename, int lineno) { int i, instance, components; if (!this->InteractorNode::cfgParseInstanceComment(comment,filename,lineno)) return FALSE; #if 0 // // Get the instance added above. // instance = this->getInstanceCount(); // The just added instance # ScalarInstance *si = (ScalarInstance*)this->getInstance(instance); // // Copy the global attributes to the local. // for (i=1 ; i<=this->getComponentCount() ; i++) { double dval; int ival = this->getComponentDecimals(i); dval = this->getComponentMinimum(i); si->setLocalMinimum(i, dval); dval = this->getComponentMaximum(i); si->setLocalMaximum(i, dval); dval = this->getComponentDelta(i); si->setLocalDelta(i, dval); ival = this->getComponentDecimals(i); si->setLocalDecimals(i, ival); } #endif return TRUE; } boolean ScalarNode::cfgParseComponentComment(const char *comment, const char *filename, int lineno) { int items_parsed; double minimum; double maximum; double delta; int instance; int decimal; int component_num; int continuous; if (strncmp(comment," component",10)) return FALSE; items_parsed = sscanf (comment, " component[%d]: minimum = %lf, maximum = %lf, global increment = %lf, decimal = %d, global continuous = %d", &component_num, &minimum, &maximum, &delta, &decimal, &continuous); if (items_parsed != 5 && items_parsed != 6) { ErrorMessage("Bad 'component' comment (file %s, line %d)", filename,lineno); return FALSE; } component_num++; // 1 based indexing. #if 0 Parameter *p = this->getOutputParameter(1); Type t = p->getValueType(); // // The following is done most for lists, which when the list is empty // have "NULL" value. In this case we want to set the type to the // default type. // if ((t == DXType::ObjectType) || EqualString("NULL",p->getValueString())) { t = p->getDefaultType(); this->clearOutputValue(1); p->setValue(NULL,t); } #endif this->setComponentMinimum(component_num,minimum); this->setComponentMaximum(component_num,maximum); this->setComponentDelta(component_num,delta); this->setComponentDecimals(component_num,decimal); if ((items_parsed == 6) && continuous) this->setContinuous(); else this->clrContinuous(); // // Enable range checking of the output value after the last component // min/max has been set (see cfgParseComments() for matching // deferComponentCount()). // if (component_num == this->getComponentCount()) this->undeferRangeChecking(); return TRUE; } // // Get a an ScalarInstance instead of an InteractorInstance. // InteractorInstance *ScalarNode::newInteractorInstance() { ScalarInstance *si = new ScalarInstance(this); return (InteractorInstance*)si; } // // G/Set the 'minimum' attribute for the given component // boolean ScalarNode::setAllComponentRanges(double *min, double *max) { this->deferRangeChecking(); int i, ncomps = this->getComponentCount(); for (i=1 ; i<=ncomps ; i++) { if (min) this->setComponentMinimum(i,min[i-1]); if (max) this->setComponentMaximum(i,max[i-1]); } this->undeferRangeChecking(); return TRUE; } boolean ScalarNode::initMinimumAttribute(const char *val) { AttributeParameter *p = (AttributeParameter*) this->getInputParameter( MIN_PARAM_NUM); return p->initAttributeValue(val); } boolean ScalarNode::setMinimumAttribute(const char *val) { AttributeParameter *p = (AttributeParameter*) this->getInputParameter( MIN_PARAM_NUM); return p->setAttributeValue(val); } boolean ScalarNode::setComponentMinimum(int component, double min) { AttributeParameter *p = (AttributeParameter*) this->getInputParameter( MIN_PARAM_NUM); double oldmin = p->getAttributeComponentValue(component); if (!p->setAttributeComponentValue(component, min)) return FALSE; if (min > oldmin) this->rangeCheckComponentValue(component, min, this->getComponentMaximum(component)); return TRUE; } double ScalarNode::getComponentMinimum(int component) { AttributeParameter *p = (AttributeParameter*) this->getInputParameter( MIN_PARAM_NUM); if (p->getAttributeComponentCount() < component) return DEFAULT_MIN; else return p->getAttributeComponentValue(component); } // // G/Set the 'maximum' attribute for the given component // boolean ScalarNode::initMaximumAttribute(const char *val) { AttributeParameter *p = (AttributeParameter*) this->getInputParameter( MAX_PARAM_NUM); return p->initAttributeValue(val); } boolean ScalarNode::setMaximumAttribute(const char *val) { AttributeParameter *p = (AttributeParameter*) this->getInputParameter( MAX_PARAM_NUM); return p->setAttributeValue(val); } boolean ScalarNode::setComponentMaximum(int component, double max) { AttributeParameter *p = (AttributeParameter*) this->getInputParameter( MAX_PARAM_NUM); double oldmax = p->getAttributeComponentValue(component); if (!p->setAttributeComponentValue(component, max)) return FALSE; if (max < oldmax) this->rangeCheckComponentValue(component, this->getComponentMinimum(component), max); return TRUE; } double ScalarNode::getComponentMaximum(int component) { AttributeParameter *p = (AttributeParameter*) this->getInputParameter( MAX_PARAM_NUM); if (p->getAttributeComponentCount() < component) return DEFAULT_MAX; else return p->getAttributeComponentValue(component); } // // G/Set the 'delta' attribute for the given component // boolean ScalarNode::initDeltaAttribute(const char *val) { AttributeParameter *p = (AttributeParameter*) this->getInputParameter( INCR_PARAM_NUM); return p->initAttributeValue(val); } boolean ScalarNode::setDeltaAttribute(const char *val) { AttributeParameter *p = (AttributeParameter*) this->getInputParameter( INCR_PARAM_NUM); return p->setAttributeValue(val); } boolean ScalarNode::setComponentDelta(int component, double delta) { AttributeParameter *p = (AttributeParameter*) this->getInputParameter( INCR_PARAM_NUM); return p->setAttributeComponentValue(component, delta); } double ScalarNode::getComponentDelta(int component) { AttributeParameter *p = (AttributeParameter*) this->getInputParameter( INCR_PARAM_NUM); if (p->getAttributeComponentCount() < component) return DEFAULT_INCR; else return p->getAttributeComponentValue(component); } // // G/Set the 'decimal places' attribute for the given component // boolean ScalarNode::initDecimalsAttribute(const char *val) { AttributeParameter *p = (AttributeParameter*) this->getInputParameter( DECIMALS_PARAM_NUM); return p->initAttributeValue(val); } boolean ScalarNode::setDecimalsAttribute(const char *val) { AttributeParameter *p = (AttributeParameter*) this->getInputParameter( DECIMALS_PARAM_NUM); return p->setAttributeValue(val); } boolean ScalarNode::setComponentDecimals(int component, int decimals) { AttributeParameter *p = (AttributeParameter*) this->getInputParameter( DECIMALS_PARAM_NUM); return p->setAttributeComponentValue(component, decimals); } int ScalarNode::getComponentDecimals(int component) { AttributeParameter *p = (AttributeParameter*) this->getInputParameter( DECIMALS_PARAM_NUM); if (p->getAttributeComponentCount() < component) { if (this->isIntegerTypeComponent()) return 0; else return DEFAULT_SCALAR_DECIMALS; } else return p->getAttributeComponentValue(component); } boolean ScalarNode::setComponentValue(int component, double value) { Parameter *out = this->getOutputParameter(1); if (!out->setComponentValue(component, value)) return FALSE; const char *v = this->getOutputValueString(1); // This forces update of the shadowing input. return this->setOutputValue(1,v,DXType::UndefinedType,FALSE); } double ScalarNode::getComponentValue(int component) { Parameter *p = this->getOutputParameter(1); ASSERT(p->getComponentCount() >= component); return p->getComponentValue(component); } // // Call doRangeCheckComponentValue() if range checking is not // deferred. // void ScalarNode::rangeCheckComponentValue(int component, double min, double max) { if (!this->isRangeCheckingDeferred()) { this->needsRangeCheck = FALSE; this->doRangeCheckComponentValue(component, min,max); } else { this->needsRangeCheck = TRUE; } } // // Do what ever is necessary when the given component of the output // value is out of range as indicated by the limits. Typically, this just // means resetting the current output value that is associated with the // node. ScalarListNodes however, have the current (non-output) value // associated with the interactor instance. Therefore, ScalarListNodes, // re-implement this to reset the component values of all their instances. // If 'component' is less than 0, then min/max are ignored and all // components are checked with the current min/max values. // void ScalarNode::doRangeCheckComponentValue(int component, double min, double max) { double val; if (component < 0) { // // Check all components of current output value against current // component min/max values (ignore input min/max). // int i, ncomp = this->getComponentCount(); double *mins = new double[ncomp]; double *maxs = new double[ncomp]; Type output_type = this->getOutputSetValueType(1); char *newval; for (i=1 ; i<=ncomp ; i++) { mins[i-1] = this->getComponentMinimum(i); maxs[i-1] = this->getComponentMaximum(i); } if (DXValue::ClampVSIValue(this->getOutputValueString(1), output_type, mins,maxs,&newval)) { ASSERT(newval); this->setOutputValue(1,newval,output_type,TRUE); delete newval; } delete[] mins; delete[] maxs; } else { // // Just do a single component. // Instead of doing this we could just always do the above, but // this is much faster. // Eventually, this causes a setOutputValue() just as above. // val = this->getComponentValue(component); if (val < min) { this->setComponentValue(component,min); } else if (val > max) { this->setComponentValue(component,max); } } } // // Determine if the given component is an integer type. // We ignore component and assume all components have the same type. // boolean ScalarNode::isIntegerTypeComponent() { // FIXME: is there a better way to do this. if (!strncmp("Integer",this->getNameString(),7)) return TRUE; else return FALSE; } boolean ScalarNode::cfgParseLocalIncrementComment( const char *comment, const char *filename, int lineno) { int items_parsed; int component_num; int int_step; double double_step; char mode[32]; ASSERT(comment); if (strncmp(comment," local increment",16)) return FALSE; #if 0 is_int = uiuEqualString(_interactor_name, "Integer"); #endif items_parsed = sscanf(comment, " local increment[%d]: value = %lf, mode = %s", &component_num, // Ignoring component number (always 0?) &double_step, mode); component_num++; // 1 based indexing if (component_num < 1 || component_num > this->getComponentCount()) { ErrorMessage( "'local increment' comment references undefined component (file %s, line %d)", filename, lineno); return FALSE; } if (items_parsed != 3) { #if 1 ErrorMessage("Bad 'local increment' comment (file %s, line %d)", filename, lineno); return FALSE; } #else uiuModelessErrorMessageDialog (_parse_widget, "#10001", "local increment", _parse_file, yylineno); _error_occurred = TRUE; return; } if (_interactor_index < 0) { uiuModelessErrorMessageDialog (_parse_widget, "#10011", "local increment", "interactor", _parse_file, yylineno); _error_occurred = TRUE; return; } interactor = _network->interactor + _interactor_index; if (NOT interactor->in_use) { uiuModelessErrorMessageDialog (_parse_widget, "#10011", "local increment", "interactor", _parse_file, yylineno); _error_occurred = TRUE; return; } #endif #if 1 int instance = this->getInstanceCount(); ScalarInstance *si = (ScalarInstance*)this->getInstance(instance); if (!si) { ErrorMessage("'local increment' comment out of order (file %s, line%d)", filename, lineno); return FALSE; } si->useLocalDelta(component_num, double_step); if (!EqualString(mode,"local")) si->clrLocalDelta(component_num); #else if (is_int) { interactor->increment[component_num].integer = interactor->restore_increment[component_num].integer = int_step; } else { interactor->increment[component_num].real = interactor->restore_increment[component_num].real = double_step; } interactor->local_increment[component_num] = interactor->restore_local_increment[component_num] = uiuEqualString(mode, "local"); #endif return TRUE; } boolean ScalarNode::cfgParseLocalContinuousComment( const char *comment, const char *filename, int lineno) { int items_parsed; int continuous; char mode[32]; ASSERT(comment); if (strncmp(comment," local continuous",17)) return FALSE; items_parsed = sscanf(comment, " local continuous: value = %d, mode = %s", &continuous, mode); /* * Backwards compatibility... */ if (items_parsed != 2) { items_parsed = sscanf(comment, " local continuous[0]: value = %d, mode = %s", &continuous, mode); } if (items_parsed != 2) { #if 1 ErrorMessage("Bad 'local continuous' comment (file %s, line %d)", filename, lineno); return FALSE; #else uiuModelessErrorMessageDialog (_parse_widget, "#10001", "local continuous", _parse_file, yylineno); _error_occurred = TRUE; return; #endif } #if 0 if (_interactor_index < 0) { uiuModelessErrorMessageDialog (_parse_widget, "#10011", "local continuous", "interactor", _parse_file, yylineno); _error_occurred = TRUE; return; } interactor = _network->interactor + _interactor_index; if (NOT interactor->in_use) { uiuModelessErrorMessageDialog (_parse_widget, "#10011", "local continuous", "interactor", _parse_file, yylineno); _error_occurred = TRUE; return; } #endif #if 1 int instance = this->getInstanceCount(); ScalarInstance *si = (ScalarInstance*)this->getInstance(instance); if (!si) { ErrorMessage("'local continuous' comment out of order (file %s, line%d)", filename, lineno); return FALSE; } si->useLocalContinuous((continuous == 0 ? FALSE : TRUE)); if (!EqualString(mode,"local")) si->useGlobalContinuous(); #else interactor->continuous = interactor->restore_continuous = continuous; interactor->restore_local_continuous = interactor->local_continuous = uiuEqualString(mode, "local"); #endif return TRUE; } // // Determine if this node is of the given class. // boolean ScalarNode::isA(Symbol classname) { Symbol s = theSymbolManager->registerSymbol(ClassScalarNode); if (s == classname) return TRUE; else return this->InteractorNode::isA(classname); } boolean ScalarNode::isMinimumVisuallyWriteable() { return this->isInputDefaulting(DATA_PARAM_NUM) && this->isAttributeVisuallyWriteable(MIN_PARAM_NUM); } boolean ScalarNode::isMaximumVisuallyWriteable() { return this->isInputDefaulting(DATA_PARAM_NUM) && this->isAttributeVisuallyWriteable(MAX_PARAM_NUM); } boolean ScalarNode::isDecimalsVisuallyWriteable() { return this->isInputDefaulting(DATA_PARAM_NUM) && (this->isInputDefaulting(MIN_PARAM_NUM) || this->isInputDefaulting(MAX_PARAM_NUM)) && this->isAttributeVisuallyWriteable(DECIMALS_PARAM_NUM); } boolean ScalarNode::isDeltaVisuallyWriteable() { const char *delta_method = this->getInputValueString(INCRMETHOD_PARAM_NUM); // // Check to see of the tab-down value of the method input is set to // 'absolute'. We can only write this value when using absolute // increments. Actually, this test should be moved to the set attributes // code since it is the one that decides what kind of increments it // can support. // if (!this->isInputDefaulting(INCRMETHOD_PARAM_NUM) && !this->isInputConnected(INCRMETHOD_PARAM_NUM) && !EqualString(delta_method,"absolute")) return FALSE; return this->isInputDefaulting(DATA_PARAM_NUM) && (this->isInputDefaulting(MIN_PARAM_NUM) || this->isInputDefaulting(MAX_PARAM_NUM)) && this->isAttributeVisuallyWriteable(INCR_PARAM_NUM); } // // Catch the output comment to determine the number of components. // We need to do this when we have a 2d vector and no .cfg file to // tell us so. We then get numComponent==3, but all the parameter // values are 2d, which results in an ASSERTion failure. // boolean ScalarNode::netParseComment(const char* comment, const char *file, int lineno) { boolean r = this->InteractorNode::netParseComment(comment,file,lineno); if (r && EqualSubstring(comment," output[",8)) { Parameter *p = this->getOutputParameter(1); this->numComponents = p->getComponentCount(); } return r; } // // If we're parsing input #4 (which is now REFRESH and was at one point REMAP) // and the net version is older than 3.1.0 (which is compiled in by DXVersion.h), // then set the defaulting status = TRUE. Reason: the older ui was setting // the defaulting status of this unused param to FALSE. Now that we want to use // the param again, old nets believe the param is set. // // So, this chunk of code should go away if REFRESH goes away. It should also // go away sometime in the future (after no more old nets exist). // // In case it's not obvious, I'll tell you: this code was copy/pasted from // Node.C. Maybe it should be kept up to date with Node.C, but really its only // purpose is to deal with old nets, so if comments change this code won't really // affected. // boolean ScalarNode::parseIOComment(boolean input, const char* comment, const char* filename, int lineno, boolean valueOnly) { int defaulting = 0, items_parsed, ionum, r; boolean visible = TRUE; Type type = DXType::UndefinedType; char *value; boolean parse_error = FALSE; if(this->Node::parseIOComment(input, comment, filename, lineno, valueOnly) == FALSE) return FALSE; // // // If the net version is less than 3.1.0 then set param 4 defaulting status // to true. The ui had mistakenly been setting it to false although the param // was not in use by the module. Now we want to use that param but existing // nets don't work unless param 4 (REFRESH) starts out defaulting. // // This code turns into NoOp starting with net version == 3.1.0 // Network *net = this->getNetwork(); if (net->getNetMajorVersion() > 3) return TRUE; if (net->getNetMinorVersion() >= 1) return TRUE; ASSERT(comment); if ((input) && (!parse_error)) { if (valueOnly) { if (sscanf(comment, " input[%d]: defaulting = %d", &ionum, &defaulting) != 2) parse_error = TRUE; type = DXType::UndefinedType; } else { items_parsed = sscanf(comment, " input[%d]: defaulting = %d, visible = %d, type = %d", &ionum, &defaulting, &visible, &type); if (items_parsed != 4) { // Invisibility added 3/30/93 items_parsed = sscanf(comment, " input[%d]: visible = %d", &ionum, &visible); if (items_parsed != 2) { // Backwards compatibility added 3/25/93 items_parsed = sscanf(comment, " input[%d]: type = %d", &ionum, &type); if (items_parsed != 2) { items_parsed = sscanf(comment, " input[%d]: defaulting = %d, type = %d", &ionum, &defaulting, &type); if (items_parsed != 3) parse_error = TRUE; } } else { defaulting = 1; } } } } if ((!parse_error) && (input) && (ionum == REFRESH_PARAM_NUM) && (defaulting == FALSE)) { Parameter *par = this->getInputParameter(REFRESH_PARAM_NUM); par->setUnconnectedDefaultingStatus(TRUE); } return TRUE; } boolean ScalarNode::printJavaValue (FILE* jf) { const char* indent = " "; int comp_count = this->getComponentCount(); const char* var_name = this->getJavaVariable(); int i; for (i=1; i<=comp_count; i++) { if (this->isIntegerTypeComponent()) { int min = (int)this->getComponentMinimum(i); int max = (int)this->getComponentMaximum(i); int step = (int)this->getComponentDelta(i); int value = (int)this->getComponentValue(i); fprintf (jf, "%s%s.setValues(%d,%d,%d,%d,%d);\n", indent, var_name, i,min,max,step,value); } else { double min = this->getComponentMinimum(i); double max = this->getComponentMaximum(i); double step = this->getComponentDelta(i); double value = this->getComponentValue(i); int decimals = this->getComponentDecimals(i); fprintf (jf, "%s%s.setValues(%d,%lg,%lg,%lg,%d,%lg);\n", indent, var_name, i,min,max,step,decimals,value); } } return TRUE; }