diff --git a/engine/mdlReader.cc b/engine/mdlReader.cc index aa6e842c3..802bec100 100644 --- a/engine/mdlReader.cc +++ b/engine/mdlReader.cc @@ -371,15 +371,15 @@ namespace minsky vector spec; for (size_t i=1; i<=match.size(); ++i) spec.push_back(match[i]); if (!spec.empty() && regex_match(spec[0],match,number)) - v->sliderMin=stod(spec[0]); + v->sliderMin(stod(spec[0])); else - v->sliderMin=0.1*stod(definition); + v->sliderMin(0.1*stod(definition)); if (spec.size()>1 && regex_match(spec[1],match,number)) - v->sliderMax=stod(spec[1]); + v->sliderMax(stod(spec[1])); else - v->sliderMax=10*stod(definition); + v->sliderMax(10*stod(definition)); if (spec.size()>2 && regex_match(spec[2],match,number)) - v->sliderStep=stod(spec[2]); + v->sliderStep(stod(spec[2])); v->adjustSliderBounds(); } else diff --git a/engine/variableSummary.h b/engine/variableSummary.h index fbeed11af..5429c8b41 100644 --- a/engine/variableSummary.h +++ b/engine/variableSummary.h @@ -33,6 +33,7 @@ namespace minsky std::string definition; ///< LaTeXable definition std::string udfDefinition; ///< use function compatible definition std::string init; ///< initial value + double sliderStep, sliderMin, sliderMax; ///< slider parameters double value=nan(""); ///< value, if scalar std::string scope; ///< name, id of scope if local, ":" if global std::string godley; ///< name or id of Godley table, if contained in a Godley table diff --git a/engine/variableValue.cc b/engine/variableValue.cc index 10fd07c36..16e5758e6 100644 --- a/engine/variableValue.cc +++ b/engine/variableValue.cc @@ -29,6 +29,7 @@ #include "index.rcd" #include "index.xcd" #include "nobble.h" +#include "slider.rcd" #include "tensorInterface.rcd" #include "tensorInterface.xcd" #include "tensorVal.rcd" @@ -533,6 +534,7 @@ namespace minsky definition, udfDefinition, init(), + sliderStep, sliderMin, sliderMax, value(), scopeName, godleyName, diff --git a/engine/variableValue.h b/engine/variableValue.h index 8ec661a67..3d047b077 100644 --- a/engine/variableValue.h +++ b/engine/variableValue.h @@ -41,7 +41,7 @@ namespace minsky typedef std::shared_ptr GroupPtr; using namespace civita; - struct VariableValueData: public civita::ITensorVal + struct VariableValueData: public civita::ITensorVal, public Slider { using ITensorVal::operator=; diff --git a/gui-js/libs/shared/src/lib/backend/minsky.ts b/gui-js/libs/shared/src/lib/backend/minsky.ts index 499c91c80..d7c9780c6 100644 --- a/gui-js/libs/shared/src/lib/backend/minsky.ts +++ b/gui-js/libs/shared/src/lib/backend/minsky.ts @@ -231,7 +231,7 @@ export class VariableBase extends Item { async drawSelected(a1: minsky__dummy): Promise {return this.$callMethod('drawSelected',a1);} async dummyDraw(): Promise {return this.$callMethod('dummyDraw');} async editorMode(): Promise {return this.$callMethod('editorMode');} - async enableSlider(...args: boolean[]): Promise {return this.$callMethod('enableSlider',...args);} + async enableSlider(...args: any[]): Promise {return this.$callMethod('enableSlider',...args);} async engExp(): Promise {return this.$callMethod('engExp');} async ensureBBValid(): Promise {return this.$callMethod('ensureBBValid');} async ensureValueExists(a1: VariableValue,a2: string): Promise {return this.$callMethod('ensureValueExists',a1,a2);} @@ -293,12 +293,12 @@ export class VariableBase extends Item { async selected(...args: boolean[]): Promise {return this.$callMethod('selected',...args);} async setDimLabelsPicked(a1: string,a2: string): Promise {return this.$callMethod('setDimLabelsPicked',a1,a2);} async setUnits(a1: string): Promise {return this.$callMethod('setUnits',a1);} - async sliderBoundsSet(...args: boolean[]): Promise {return this.$callMethod('sliderBoundsSet',...args);} - async sliderMax(...args: number[]): Promise {return this.$callMethod('sliderMax',...args);} - async sliderMin(...args: number[]): Promise {return this.$callMethod('sliderMin',...args);} + async sliderBoundsSet(...args: any[]): Promise {return this.$callMethod('sliderBoundsSet',...args);} + async sliderMax(...args: any[]): Promise {return this.$callMethod('sliderMax',...args);} + async sliderMin(...args: any[]): Promise {return this.$callMethod('sliderMin',...args);} async sliderSet(a1: number): Promise {return this.$callMethod('sliderSet',a1);} - async sliderStep(...args: number[]): Promise {return this.$callMethod('sliderStep',...args);} - async sliderStepRel(...args: boolean[]): Promise {return this.$callMethod('sliderStepRel',...args);} + async sliderStep(...args: any[]): Promise {return this.$callMethod('sliderStep',...args);} + async sliderStepRel(...args: any[]): Promise {return this.$callMethod('sliderStepRel',...args);} async sliderVisible(): Promise {return this.$callMethod('sliderVisible');} async temp(): Promise {return this.$callMethod('temp');} async throw_error(a1: string): Promise {return this.$callMethod('throw_error',a1);} @@ -2289,6 +2289,7 @@ export class VariableValue extends CppClass { async cancel(a1: boolean): Promise {return this.$callMethod('cancel',a1);} async data(): Promise {return this.$callMethod('data');} async detailedText(...args: string[]): Promise {return this.$callMethod('detailedText',...args);} + async enableSlider(...args: boolean[]): Promise {return this.$callMethod('enableSlider',...args);} async end(): Promise {return this.$callMethod('end');} async exportAsCSV(a1: string,a2: string,a3: boolean): Promise {return this.$callMethod('exportAsCSV',a1,a2,a3);} async godleyOverridden(...args: boolean[]): Promise {return this.$callMethod('godleyOverridden',...args);} @@ -2310,6 +2311,11 @@ export class VariableValue extends CppClass { async setValue(...args: any[]): Promise {return this.$callMethod('setValue',...args);} async shape(): Promise {return this.$callMethod('shape');} async size(): Promise {return this.$callMethod('size');} + async sliderBoundsSet(...args: boolean[]): Promise {return this.$callMethod('sliderBoundsSet',...args);} + async sliderMax(...args: number[]): Promise {return this.$callMethod('sliderMax',...args);} + async sliderMin(...args: number[]): Promise {return this.$callMethod('sliderMin',...args);} + async sliderStep(...args: number[]): Promise {return this.$callMethod('sliderStep',...args);} + async sliderStepRel(...args: boolean[]): Promise {return this.$callMethod('sliderStepRel',...args);} async sliderVisible(...args: boolean[]): Promise {return this.$callMethod('sliderVisible',...args);} async summary(): Promise {return this.$callMethod('summary');} async temp(): Promise {return this.$callMethod('temp');} diff --git a/gui-js/libs/ui-components/src/lib/summary/summary.component.html b/gui-js/libs/ui-components/src/lib/summary/summary.component.html index 8c5dce8ba..1598dfd9f 100644 --- a/gui-js/libs/ui-components/src/lib/summary/summary.component.html +++ b/gui-js/libs/ui-components/src/lib/summary/summary.component.html @@ -15,8 +15,11 @@
Name
Definition
Dimensions
-
Initial
Units
+
Initial
+
Step
+
Min
+
Max
Value
@@ -57,6 +60,22 @@ {{variable.dimensions.toString()}} +
+
+
+ +
+
+ class="data-cell">
-
-
+
- + +
+
+
+ +
+ +
+
+
+ +
+
+ + +
diff --git a/gui-js/libs/ui-components/src/lib/summary/summary.component.ts b/gui-js/libs/ui-components/src/lib/summary/summary.component.ts index 651163075..2d8fae379 100644 --- a/gui-js/libs/ui-components/src/lib/summary/summary.component.ts +++ b/gui-js/libs/ui-components/src/lib/summary/summary.component.ts @@ -143,6 +143,15 @@ export class SummaryComponent implements OnInit { case 'init': this.electronService.minsky.variableValues.elem(this.editRow.valueId).init(this.editCellContents); break; + case 'sliderMin': + this.electronService.minsky.variableValues.elem(this.editRow.valueId).sliderMin(+this.editCellContents); + break; + case 'sliderMax': + this.electronService.minsky.variableValues.elem(this.editRow.valueId).sliderMax(+this.editCellContents); + break; + case 'sliderStep': + this.electronService.minsky.variableValues.elem(this.editRow.valueId).sliderStep(+this.editCellContents); + break; case 'units': this.electronService.minsky.variableValues.elem(this.editRow.valueId).setUnits(this.editCellContents); break; diff --git a/model/cairoItems.cc b/model/cairoItems.cc index 8f422f757..c96a1edab 100644 --- a/model/cairoItems.cc +++ b/model/cairoItems.cc @@ -96,9 +96,9 @@ bool RenderVariable::inImage(float x, float y) double RenderVariable::handlePos() const { - if (var.sliderStep::min() || std::isnan(var.sliderStep)) var.initSliderBounds(); // this should only be used when sliderStep's value has not been set or is a nonsensicl + if (var.sliderStep()::min() || std::isnan(var.sliderStep())) var.initSliderBounds(); // this should only be used when sliderStep's value has not been set or is a nonsensicl var.adjustSliderBounds(); - return (w<0.5*var.iWidth()? 0.5*var.iWidth() : w)*(var.value()-0.5*(var.sliderMin+var.sliderMax))/(var.sliderMax-var.sliderMin); + return (w<0.5*var.iWidth()? 0.5*var.iWidth() : w)*(var.value()-0.5*(var.sliderMin()+var.sliderMax()))/(var.sliderMax()-var.sliderMin()); } void minsky::drawTriangle diff --git a/model/minsky.cc b/model/minsky.cc index b82658ac1..774614446 100644 --- a/model/minsky.cc +++ b/model/minsky.cc @@ -911,7 +911,7 @@ namespace minsky else if (auto v=(*i)->variableCast()) { //determine whether a slider should be shown if (auto vv=v->vValue()) - vv->sliderVisible = v->enableSlider && + vv->sliderVisible = v->enableSlider() && (v->type()==VariableType::parameter || (v->type()==VariableType::flow && !inputWired(v->valueId()))); v->resetMiniPlot(); } diff --git a/model/variable.cc b/model/variable.cc index 9dfd00cd8..340ce991f 100644 --- a/model/variable.cc +++ b/model/variable.cc @@ -544,7 +544,7 @@ bool VariableBase::visible() const bool VariableBase::sliderVisible() const { auto vv=vValue(); - return enableSlider && + return enableSlider() && ((!vv && type()==parameter) || (vv && vv->size()==1 && (type()==parameter || vv->sliderVisible))); @@ -553,55 +553,57 @@ bool VariableBase::sliderVisible() const void VariableBase::sliderSet(double x) { - if (xsliderMax) x=sliderMax; - sliderStep=maxSliderSteps(); + if (xsliderMax()) x=sliderMax(); + sliderStep(maxSliderSteps()); init(to_string(x)); value(x); } - +// TODO - refactor this to Slider class void VariableBase::initSliderBounds() const { - if (!sliderBoundsSet) + if (!sliderBoundsSet()) { if (value()==0) { - sliderMin=-1; - sliderMax=1; + sliderMin(-1); + sliderMax(1); } else { - sliderMin=-value()*10; - sliderMax=value()*10; + sliderMin(-value()*10); + sliderMax(value()*10); } - sliderStepRel=false; - sliderBoundsSet=true; - sliderStep=0.01*(sliderMax-sliderMin); + sliderStepRel(false); + sliderBoundsSet(true); + sliderStep(0.01*(sliderMax()-sliderMin())); } - sliderStep=maxSliderSteps(); + sliderStep(maxSliderSteps()); } +// TODO - refactor this to VariableValue class void VariableBase::adjustSliderBounds() const { if (auto vv=vValue()) // For feature 47 if (vv->size()==1 && !isnan(vv->value())) // make sure sliderBoundsSet is defined. for tickets 1258/1263 { - if (sliderMaxvalue()) - sliderMax=vv->value()? 10*vv->value():1; - if (sliderMin>vv->value()) - sliderMin=vv->value()? -10*vv->value():-1; - sliderStep=maxSliderSteps(); - sliderBoundsSet=true; + if (sliderMax()value()) + sliderMax(vv->value()? 10*vv->value():1); + if (sliderMin()>vv->value()) + sliderMin(vv->value()? -10*vv->value():-1); + sliderStep(maxSliderSteps()); + sliderBoundsSet(true); } } +// TODO - move to Slider double VariableBase::maxSliderSteps() const { // ensure there are at most 10000 steps between sliderMin and Max. for ticket 1255. - if ((sliderMax-sliderMin)/sliderStep > 1.0e04) return (sliderMax-sliderMin)/1.0e04; - return sliderStep; + if ((sliderMax()-sliderMin())/sliderStep() > 1.0e04) return (sliderMax()-sliderMin())/1.0e04; + return sliderStep(); } bool VariableBase::onKeyPress(int keySym, const std::string&,int) @@ -609,11 +611,11 @@ bool VariableBase::onKeyPress(int keySym, const std::string&,int) switch (keySym) { case 0xff52: case 0xff53: //Right, Up - sliderSet(value()+(sliderStepRel? value(): 1)*sliderStep); + sliderSet(value()+(sliderStepRel()? value(): 1)*sliderStep()); if (!minsky().running) minsky().requestReset(); return true; case 0xff51: case 0xff54: //Left, Down - sliderSet(value()-(sliderStepRel? value(): 1)*sliderStep); + sliderSet(value()-(sliderStepRel()? value(): 1)*sliderStep()); if (!minsky().running) minsky().requestReset(); return true; default: @@ -660,8 +662,8 @@ bool VariableBase::onMouseMotion(float x, float y) { const RenderVariable rv(*this); const double rw=fabs(zoomFactor()*(rv.width()x())* (sliderMax-sliderMin)/rw+0.5*(sliderMin+sliderMax); - const double sliderHatch=sliderPos-fmod(sliderPos,sliderStep); // matches slider's hatch marks to sliderStep value. for ticket 1258 + const double sliderPos=(x-this->x())* (sliderMax()-sliderMin())/rw+0.5*(sliderMin()+sliderMax()); + const double sliderHatch=sliderPos-fmod(sliderPos,sliderStep()); // matches slider's hatch marks to sliderStep value. for ticket 1258 sliderSet(sliderHatch); // push History to prevent an unnecessary reset when // adjusting the slider whilst paused. See ticket #812 @@ -672,6 +674,90 @@ bool VariableBase::onMouseMotion(float x, float y) return true; } +double VariableBase::sliderMin() const +{ + if (auto vv=vValue()) + return vv->sliderMin; + return 0; +} + + +double VariableBase::sliderMin(double x) const +{ + if (auto vv=vValue()) + return vv->sliderMin=x; + return 0; +} + +double VariableBase::sliderMax() const +{ + if (auto vv=vValue()) + return vv->sliderMax; + return 0; +} + +double VariableBase::sliderMax(double x) const +{ + if (auto vv=vValue()) + return vv->sliderMax=x; + return 0; +} + +double VariableBase::sliderStep() const +{ + if (auto vv=vValue()) + return vv->sliderStep; + return 0; +} + +double VariableBase::sliderStep(double x) const +{ + if (auto vv=vValue()) + return vv->sliderStep=x; + return 0; +} + +bool VariableBase::sliderBoundsSet() const +{ + if (auto vv=vValue()) + return vv->sliderBoundsSet; + return false; +} + +bool VariableBase::sliderBoundsSet(bool x) const +{ + if (auto vv=vValue()) + return vv->sliderBoundsSet=x; + return false; +} + +bool VariableBase::sliderStepRel() const +{ + if (auto vv=vValue()) + return vv->sliderStepRel; + return false; +} + +bool VariableBase::sliderStepRel(bool x) const + { + if (auto vv=vValue()) + return vv->sliderStepRel=x; + return false; +} + +bool VariableBase::enableSlider() const +{ + if (auto vv=vValue()) + return vv->enableSlider; + return false; +} + +bool VariableBase::enableSlider(bool x) +{ + if (auto vv=vValue()) + return vv->enableSlider=x; + return false; +} void VariableBase::draw(cairo_t *cairo) const @@ -748,11 +834,11 @@ void VariableBase::draw(cairo_t *cairo) const { cachedValue=value(); if (!isnan(value())) { - if (sliderBoundsSet && vv->sliderVisible) + if (sliderBoundsSet() && vv->sliderVisible) l_cachedMantissa->setMarkup (mantissa(val, int(1+ - (sliderStepRel? + (sliderStepRel()? -log10(maxSliderSteps()): log10(value()/maxSliderSteps()) )))); diff --git a/model/variable.h b/model/variable.h index 44ae560a1..ad47fc2e8 100644 --- a/model/variable.h +++ b/model/variable.h @@ -86,7 +86,7 @@ namespace minsky class VariableBase: virtual public classdesc::PolyPackBase, public BottomRightResizerItem, - public Slider, public VariableType, + public VariableType, public VarAccessors::NameAccessor, public VarAccessors::InitAccessor, public VarAccessors::ValueAccessor, @@ -251,7 +251,21 @@ namespace minsky void resetMiniPlot(); bool onMouseMotion(float x, float y) override; - + + /// @{ slider parameters + double sliderMin() const; + double sliderMin(double) const; + double sliderMax() const; + double sliderMax(double) const; + double sliderStep() const; + double sliderStep(double) const; + bool sliderBoundsSet() const; + bool sliderBoundsSet(bool) const; + bool sliderStepRel() const; + bool sliderStepRel(bool) const; + bool enableSlider() const; + bool enableSlider(bool); + /// @} }; template diff --git a/model/variablePane.cc b/model/variablePane.cc index 39768e529..910100184 100644 --- a/model/variablePane.cc +++ b/model/variablePane.cc @@ -47,7 +47,7 @@ namespace minsky void VariablePaneCell::show() { if (!cachedCairo || !var || var->type()==VariableType::undefined) return; - var->sliderBoundsSet=0; //TODO, this should be the case by default anyway + var->sliderBoundsSet(false); //TODO, this should be the case by default anyway RenderVariable rv(*var, cachedCairo); const ecolab::cairo::CairoSave cs(cachedCairo); cairo_translate(cachedCairo,0.5*m_width,0.5*m_height); diff --git a/schema/schema3.cc b/schema/schema3.cc index 024191952..450127beb 100644 --- a/schema/schema3.cc +++ b/schema/schema3.cc @@ -526,12 +526,12 @@ namespace schema3 x1->name(*y.name); if (y.slider) { - x1->sliderBoundsSet=true; - x1->sliderStepRel=y.slider->stepRel; - x1->enableSlider=y.slider->visible; - x1->sliderMin=y.slider->min; - x1->sliderMax=y.slider->max; - x1->sliderStep=y.slider->step; + x1->sliderBoundsSet(true); + x1->sliderStepRel(y.slider->stepRel); + x1->enableSlider(y.slider->visible); + x1->sliderMin(y.slider->min); + x1->sliderMax(y.slider->max); + x1->sliderStep(y.slider->step); } x1->miniPlotEnabled(y.miniPlot); // variableValue attributes populated later once variable is homed in its group diff --git a/schema/schema3.h b/schema/schema3.h index e055c651e..f73d69494 100644 --- a/schema/schema3.h +++ b/schema/schema3.h @@ -143,8 +143,8 @@ namespace schema3 ItemBase(id,static_cast(v),ports), init(v.init()), miniPlot(v.miniPlotEnabled()) { name=v.rawName(); - if (v.sliderBoundsSet) - slider.reset(new Slider(v.sliderStepRel,v.enableSlider,v.sliderMin,v.sliderMax,v.sliderStep)); + if (v.sliderBoundsSet()) + slider.reset(new Slider(v.sliderStepRel(),v.enableSlider(),v.sliderMin(),v.sliderMax(),v.sliderStep())); if (auto vv=v.vValue()) { units=vv->units.str();