Minsky
godleyIcon.cc
Go to the documentation of this file.
1 /*
2  @copyright Steve Keen 2012
3  @author Russell Standish
4  This file is part of Minsky.
5 
6  Minsky is free software: you can redistribute it and/or modify it
7  under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  Minsky is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with Minsky. If not, see <http://www.gnu.org/licenses/>.
18 */
19 #include "minsky.h"
20 #include "variable.h"
21 #include "godleyIcon.h"
22 #include "godleyTableWindow.h"
23 #include "cairoItems.h"
24 #include "selection.h"
25 #include <flowCoef.h>
26 #include <evalGodley.h>
27 #include <arrays.h>
28 #include <cairo_base.h>
29 #include <ctype.h>
30 #include "godleyIcon.rcd"
31 #include "itemT.rcd"
32 #include "minsky_epilogue.h"
33 #include <boost/locale.hpp>
34 using namespace boost::locale::conv;
35 using namespace ecolab::cairo;
36 using namespace ecolab;
37 using namespace std;
38 
39 // width of draggable border
40 const float border=10;
41 
42 namespace minsky
43 {
44  namespace
45  {
46  struct OrderByName
47  {
48  bool operator()(const VariablePtr& x, const VariablePtr& y) const
49  {assert(x&&y); return x->valueId() < y->valueId();}
50  };
51 
52  struct DrawVars
53  {
54  cairo_t* cairo;
55  float x, y; // position of this icon
56  DrawVars(cairo_t* cairo, float x, float y):
57  cairo(cairo), x(x), y(y) {}
58 
59  void operator()(const GodleyIcon::Variables& vars) const
60  {
61  for (GodleyIcon::Variables::const_iterator v=vars.begin();
62  v!=vars.end(); ++v)
63  {
64  const ecolab::cairo::CairoSave cs(cairo);
65  const VariableBase& vv=**v;
66  // coordinates of variable within the cairo context
67  cairo_translate(cairo, vv.x()-x, vv.y()-y);
68  vv.draw(cairo);
69  }
70  }
71  };
72 
73  // determine the width and maximum height on screen of variables in vars
75  float& height, float& width)
76  {
77  float h=0;
78  for (const auto& v: vars)
79  {
80  const RenderVariable rv(*v);
81  h+=2*rv.height();
82  if (h>height) height=h;
83  const float w=2*rv.width();
84  if (w>width) width=w;
85  }
86  }
87  }
88 
89  bool GodleyIcon::inItem(float xx, float yy) const
90  {
91  return abs(xx-x())<0.5*width()-border && abs(yy-y())<0.5*height()-border;
92  }
93 
94  void GodleyIcon::updateVars(GodleyIcon::Variables& vars,
95  const vector<string>& varNames,
96  VariableType::Type varType)
97  {
98  // update the map of variables from the Godley table
99  set<VariablePtr, OrderByName> oldVars(vars.begin(), vars.end());
100  set<string> alreadyAdded;
101 
102  vars.clear();
103  shared_ptr<GodleyIcon> self;
104  if (auto g=group.lock())
105  self=dynamic_pointer_cast<GodleyIcon>(g->findItem(*this));
106 
107  for (vector<string>::const_iterator nm=varNames.begin(); nm!=varNames.end(); ++nm)
108  {
109  const VariablePtr newVar(varType, *nm);
110  auto myGroup=group.lock();
111  if (myGroup) myGroup->addItem(newVar); // get scope right
112  auto v=oldVars.find(newVar);
113 
114  if (v==oldVars.end())
115  {
116  // allow for the possibility that multiple names map to the same valueId
117  if (!alreadyAdded.contains(newVar->valueId()))
118  {
119  // add new variable
120  vars.push_back(newVar);
121  alreadyAdded.insert(newVar->valueId());
122  if (varType==VariableType::stock) // newly added variables should take the default dimension
123  newVar->setUnits(currency);
124  }
125  else
126  if (myGroup)
127  myGroup->removeItem(*newVar);
128  }
129  else
130  {
131  // move existing variable
132  assert(*v);
133  vars.push_back(*v);
134  alreadyAdded.insert(newVar->valueId());
135  oldVars.erase(v);
136  if (myGroup) myGroup->removeItem(*newVar);
137  }
138  if (myGroup) myGroup->addItem(vars.back(),true);
139  vars.back()->controller=self;
140  // ensure variable type is consistent
141  minsky::minsky().convertVarType(vars.back()->valueId(), varType);
142  }
143  // remove any previously existing variables
144  if (auto g=group.lock())
145  for (const auto& v: oldVars)
146  g->deleteItem(*v);
147  }
148 
149  void GodleyIcon::toggleVariableDisplay()
150  {
151  m_variableDisplay=!m_variableDisplay;
152  update();
153  }
154 
155  void GodleyIcon::toggleEditorMode()
156  {
157  m_editorMode=!m_editorMode;
158  updateBoundingBox();
159  }
160 
161  bool GodleyIcon::buttonDisplay() const {return m_editorMode && editor.drawButtons;}
162  void GodleyIcon::toggleButtons()
163  {
164  if (editor.drawButtons)
165  editor.disableButtons();
166  else
167  editor.enableButtons();
168  updateBoundingBox();
169  }
170 
171  void GodleyIcon::scaleIcon(float w, float h)
172  {
173  update();
174  scaleFactor(min(w/(leftMargin()+iWidth()*zoomFactor()),h/(bottomMargin()+iHeight()*zoomFactor())));
175  }
176 
177  void GodleyIcon::resize(const LassoBox& b)
178  {
179  const float invZ=1.0/(this->zoomFactor());
180  auto bw=abs(b.x0-b.x1), bh=abs(b.y0-b.y1);
181  if (bw<=leftMargin() || bh<=bottomMargin()) return;
182  moveTo(0.5*(b.x0+b.x1), 0.5*(b.y0+b.y1));
183  iWidth((bw-leftMargin())*invZ);
184  iHeight((bh-bottomMargin())*invZ);
185  scaleIcon(bw,bh);
186  updateBoundingBox();
187  }
188 
189  void GodleyIcon::removeControlledItems(GroupItems& g)
190  {
191  for (auto& i: m_flowVars)
192  {
193  assert(i);
194  i->deleteAttachedWires();
195  auto item=g.removeItem(*i);
196  assert(item.use_count()!=1);
197  }
198  m_flowVars.clear();
199  for (auto& i: m_stockVars)
200  {
201  assert(i);
202  i->deleteAttachedWires();
203  auto item=g.removeItem(*i);
204  assert(item.use_count()!=1);
205  }
206  m_stockVars.clear();
207  }
208 
209  void GodleyIcon::setCell(int row, int col, const string& newVal)
210  {
211  if (!table.cellInTable(row,col)) return;
212  // if this operation is clearing an initial condition cell, set it to 0
213  string& c=table.cell(row,col);
214  if (newVal.empty() && !c.empty() && table.initialConditionRow(row))
215  c="0";
216  else
217  c=newVal;
218  if (row==0)
219  minsky().importDuplicateColumn(table, col);
220  else
221  minsky().balanceDuplicateColumns(*this, col);
222  table.markEdited();
223  }
224 
225  void GodleyIcon::deleteRow(unsigned row)
226  {
227  if (row>0 && row<=table.rows())
228  {
229  table.deleteRow(row-1);
230  // if shared column data is deleted, remove it from the other tables too
231  for (size_t col=1; col<table.cols(); ++col)
232  minsky().balanceDuplicateColumns(*this, col);
233  table.markEdited();
234  }
235  }
236 
237  //void GodleyIcon::moveCell(int srcRow, int srcCol, int destRow, int destCol)
238  void GodleyIcon::moveCell(const MoveCellArgs& args)
239  {
240  if (!table.cellInTable(args.srcRow, args.srcCol) || !table.cellInTable(args.destRow, args.destCol)) return;
241  if (args.srcCol!=args.destCol) // if moving between columns, we can delete and
242  // add, which ensures any linked columns are
243  // correctly updated
244  {
245  // create a copy here, as setCell may resize the array, changing
246  // what the reference referred to.
247  const string oldVal=table.cell(args.srcRow, args.srcCol);
248  setCell(args.destRow, args.destCol, oldVal);
249  setCell(args.srcRow, args.srcCol, "");
250  }
251  else // within a column, just move the data without affecting any linked column
252  {
253  table.cell(args.destRow, args.destCol)=table.cell(args.srcRow, args.srcCol);
254  table.cell(args.srcRow, args.srcCol)="";
255  }
256  }
257 
258  map<string,double> GodleyIcon::flowSignature(unsigned col) const
259  {
260  map<string,double> r;
261  for (size_t row=1; row<table.rows() && col<table.cols(); ++row)
262  if (!table.initialConditionRow(row))
263  {
264  const FlowCoef fc(table.cell(row,col));
265  if (!fc.name.empty())
266  r[fc.name]+=fc.coef;
267  }
268  return r;
269  }
270 
271  vector<Summary> GodleyIcon::summarise() const
272  {
273  vector<Summary> r;
274  for (auto& i: stockVars())
275  if (auto vv=i->vValue())
276  {
277  r.push_back(vv->summary());
278  r.back().godley=table.title.empty()? id(): table.title;
279  }
280  for (auto& i: flowVars())
281  if (auto vv=i->vValue())
282  {
283  r.push_back(vv->summary());
284  r.back().godley=table.title.empty()? id(): table.title;
285  }
286  return r;
287  }
288 
289  void GodleyIcon::update()
290  {
291  updateVars(m_stockVars, table.getColumnVariables(), VariableType::stock);
292  updateVars(m_flowVars, table.getVariables(), VariableType::flow);
293 
294  // retrieve initial conditions, if any
295  for (size_t r=1; r<table.rows(); ++r)
296  if (table.initialConditionRow(r))
297  for (size_t c=1; c<table.cols(); ++c)
298  {
299  const string name=trimWS(table.cell(0,c));
300  auto vi=minsky().variableValues.find(minsky::valueId(group.lock(),name));
301  if (vi==minsky().variableValues.end()) continue;
302  VariableValue& v=*vi->second;
303  v.godleyOverridden=false;
304  const string::size_type start=table.cell(r,c).find_first_not_of(' ');
305  if (start!=string::npos)
306  {
307  const FlowCoef fc(table.cell(r,c).substr(start));
308  v.init(fc.str());
309  // set initial value of stock var to init value of flow that is defined by a parameter or a constant. for ticket 1137
310  if (auto initVar=minsky().definingVar(minsky::valueId(group.lock(),fc.str())))
311  if (initVar->inputWired() && initVar->type()==VariableType::flow)
312  if (auto* lhsVar=initVar->ports(1).lock()->wires()[0]->from()->item().variableCast()) {
313  FlowCoef fc1(lhsVar->vValue()->init());
314  fc1.coef*=fc.coef;
315  v.init(fc1.str());
316  }
317  v.godleyOverridden=true;
318  }
319  else
320  {
321  // populate cell with current variable's initial value
322  const FlowCoef fc(v.init());
323  table.cell(r,c)=fc.str();
324  v.godleyOverridden=true;
325  }
326 
327  }
328 
329  if (m_variableDisplay)
330  {
331  // determine height of variables part of icon
332  float stockH=0, flowH=0;
333  stockMargin=0;
334  flowMargin=0;
335  accumulateWidthHeight(m_stockVars, stockH, stockMargin);
336  accumulateWidthHeight(m_flowVars, flowH, flowMargin);
337  // allow for notches on variables
338  stockMargin+=4;
339  flowMargin+=4;
340  const float iw=this->iWidth(), ih=this->iHeight();
341  this->iWidth(max(iw, 1.8f*stockH));
342  this->iHeight(max(ih, 1.8f*flowH));
343  }
344  else
345  { // if any variables have attached wires, create a copy to carry the wire
346  for (auto& v: m_stockVars)
347  if (auto p=v->ports(0).lock())
348  if (!p->wires().empty())
349  {
350  if (auto g=group.lock())
351  {
352  auto newVar=g->addItem(v->clone());
353  if (auto w=p->wires().front())
354  if (auto from=newVar->ports(0).lock())
355  {
356  w->moveToPorts(from, w->to());
357  continue;
358  }
359  }
360  // in falling through to here, we've failed to create and wire a variable copy
361  m_variableDisplay=true;
362  throw_error("Cowardly refusing to hide a wired variable");
363  }
364 
365  for (auto& v: m_flowVars)
366  if (auto p=v->ports(1).lock())
367  if (!p->wires().empty())
368  {
369  if (auto g=group.lock())
370  {
371  auto newVar=g->addItem(v->clone());
372  if (auto w=p->wires().front())
373  if (auto to=newVar->ports(1).lock())
374  {
375  w->moveToPorts(w->from(), to);
376  continue;
377  }
378  }
379  // in falling through to here, we've failed to create and wire a variable copy
380  m_variableDisplay=true;
381  throw_error("Cowardly refusing to hide a wired variable");
382  }
383  }
384 
385  positionVariables();
386  updateBB();
387  }
388 
389  void GodleyIcon::positionVariables() const
390  {
391  // position of margin in absolute canvas coordinate
392  const float z=this->zoomFactor()*scaleFactor();
393  float x= this->x() - 0.5*iWidth()*z+0.5*leftMargin();
394  float y= this->y() - 0.5*bottomMargin()-0.15*iHeight()*z;
395  for (const auto& v: m_flowVars)
396  {
397  // right justification if displayed, left otherwisw
398  v->rotation(0);
399  v->moveTo(x+v->x() - (m_variableDisplay? v->right(): v->left()), y);
400  y+=v->height();
401  }
402  x= this->x() + 0.55*leftMargin()-0.45*iWidth()*z;
403  y= this->y() + 0.5*iHeight()*z-0.5*bottomMargin();
404 
405  for (const auto& v: m_stockVars)
406  {
407  // top justification at bottom of icon if displayed, bottom justified otherwise
408  v->rotation(90);
409  v->moveTo(x, y + v->y() - (m_variableDisplay? v->top(): v->bottom()));
410  x+=v->width();
411  }
412  }
413 
414  ItemPtr GodleyIcon::select(float x, float y) const
415  {
416  if (m_variableDisplay) // Disable selection of stock and flow vars when they are hidden. for tickets 1217 and 1220.
417  {
418  for (const auto& v: m_flowVars)
419  if (v->contains(x,y))
420  return v;
421  for (const auto& v: m_stockVars)
422  if (v->contains(x,y))
423  return v;
424  }
425  return ItemPtr();
426  }
427 
428  bool GodleyIcon::wiresAttached() const
429  {
430  bool r=false;
431  for (auto& v: m_flowVars)
432  if (auto p=v->ports(1).lock())
433  r|=p->wires().size();
434  for (auto& v: m_stockVars)
435  if (auto p=v->ports(0).lock())
436  r|=p->wires().size();
437  return r;
438  }
439 
440 
441  void GodleyIcon::draw(cairo_t* cairo) const
442  {
443  positionVariables();
444  const float z=zoomFactor()*scaleFactor();
445  float w=iWidth()*z+leftMargin(), h=iHeight()*z+bottomMargin(), left=-0.5*w, top=-0.5*h;
446  double titley;
447 
448  if (m_editorMode)
449  {
450  const CairoSave cs(cairo);
451  cairo_rectangle(cairo, left, top, w, h);
452  cairo_rectangle(cairo, left-border*z, top-border*z, w+2*border*z, h+2*border*z);
453  cairo_stroke_preserve(cairo);
454  if (onBorder)
455  { // shadow the border when mouse is over it
456  const cairo::CairoSave cs(cairo);
457  cairo_set_source_rgba(cairo,0.5,0.5,0.5,0.5);
458  cairo_set_fill_rule(cairo,CAIRO_FILL_RULE_EVEN_ODD);
459  cairo_fill(cairo);
460  }
461  cairo_new_path(cairo);
462  cairo_rectangle(cairo, left, top, w, h);
463  cairo_clip(cairo);
464  cairo_translate(cairo,left+border*z+leftMargin(),top+border*z+titleOffs()/* space for title*/);
465  // render to a recording surface to determine size of editor table
466  // TODO - maybe move this stuff into update()
467  const Surface surf(cairo_recording_surface_create(CAIRO_CONTENT_COLOR, nullptr));
468  const_cast<GodleyTableEditor&>(editor).zoomFactor=1;
469  const_cast<GodleyTableEditor&>(editor).draw(surf.cairo());
470  const_cast<GodleyTableEditor&>(editor).zoomFactor=min((w-leftMargin()-2*border*z)/surf.width(),(h-bottomMargin()-2*border*z-titleOffs())/surf.height());
471  const_cast<GodleyTableEditor&>(editor).draw(cairo);
472  titley=-0.5*h;
473  w+=2*border*z;
474  h+=2*border*z;
475  left-=border*z;
476  top-=border*z;
477  }
478  else
479  {
480  const CairoSave cs(cairo);
481  cairo_translate(cairo,left+leftMargin(),top);
482  cairo_scale(cairo, (w-leftMargin())/svgRenderer.width(), (h-bottomMargin())/svgRenderer.height());
483  svgRenderer.render(cairo);
484  titley=top+0.1*(h-bottomMargin());
485  }
486 
487  if (!table.title.empty())
488  {
489  const CairoSave cs(cairo);
490  Pango pango(cairo);
491  pango.setMarkup("<b>"+latexToPango(table.title)+"</b>");
492  pango.setFontSize(titleOffs());
493  cairo_move_to(cairo,-0.5*(pango.width()-leftMargin()), titley);
494  pango.show();
495  }
496 
497 
498 
499  if (m_variableDisplay && (!m_editorMode || wiresAttached()))
500  {
501  // render the variables
502  const DrawVars drawVars(cairo,x(),y());
503  drawVars(m_flowVars);
504  drawVars(m_stockVars);
505  }
506 
507  if (mouseFocus)
508  {
509  drawPorts(cairo);
510  displayTooltip(cairo,tooltip());
511  drawResizeHandles(cairo);
512  }
513 
514  cairo_rectangle(cairo, left,top, w, h);
515  cairo_clip(cairo);
516  if (selected)
517  {
518  drawSelected(cairo);
519  }
520  }
521 
522  string GodleyIcon::rowSum(int row) const
523  {
524  if (row==0) // A-L-E sum values across stockvars
525  {
526  map<string,VariablePtr> stockVars;
527  for (const auto& i: m_stockVars)
528  stockVars[i->valueId()]=i;
529  double sum=0, absSum=0;
530  for (size_t c=1; c<table.cols(); ++c)
531  {
532  auto i=stockVars.find(minsky::valueId(group.lock(), trimWS(table.cell(0,c))));
533  if (i!=stockVars.end())
534  {
535  sum+=(table.signConventionReversed(c)? -1: 1)*i->second->value();
536  absSum+=abs(i->second->value());
537  }
538  }
539  if (sum<1E-4*absSum) sum=0; // eschew excess precision. For #1328
540  return str(sum);
541  }
542  return table.rowSum(row);
543  }
544 
545  Units GodleyIcon::stockVarUnits(const string& stockName, bool check) const
546  {
547  unsigned stockCol=1;
548  auto valId=valueId(stockName);
549  for (; stockCol<table.cols(); ++stockCol)
550  if (valueId(table.cell(0,stockCol))==valId)
551  break;
552 
553  if (stockCol>=table.cols()) return {};
554 
555  bool foundFlow=false;
556  Units units;
557  for (unsigned row=1; row<table.rows(); ++row)
558  {
559  if (table.initialConditionRow(row)) continue;
560  const FlowCoef fc(table.cell(row,stockCol));
561  if (fc.coef!=0)
562  {
563  auto vid=valueId(fc.name);
564  // find variable assciated with this flow
565  for (const auto& v: flowVars())
566  if (v->valueId()==vid)
567  {
568  auto flowUnits=v->units(check);
569  if (check && foundFlow && units!=flowUnits)
570  throw_error("incompatible units: "+flowUnits.str()+"≠"+units.str()+" on stock "+stockName);
571  foundFlow=true;
572  units=flowUnits;
573  }
574  }
575  }
576  if (!cminsky().timeUnit.empty())
577  units[cminsky().timeUnit]++;
578  return foundFlow? units: cminsky().variableValues[valId]->units;
579  }
580 
581  void GodleyIcon::insertControlled(Selection& selection)
582  {
583  for (const auto& i: flowVars())
584  selection.ensureItemInserted(i);
585  for (const auto& i: stockVars())
586  selection.ensureItemInserted(i);
587  }
588 
589  ClickType::Type GodleyIcon::clickType(float x, float y) const
590  {
591  if (m_editorMode) return Item::clickType(x,y);
592  const double dx=fabs(x-this->x()), dy=fabs(y-this->y());
593  auto z=zoomFactor()*scaleFactor();
594  const double w=0.5*iWidth()*z, h=0.5*iHeight()*z;
595  if (onResizeHandle(x,y)) return ClickType::onResize;
596  // Make it possible to pull wires from variables attached to Godley icons. For ticket 940
597  if (auto item=select(x,y))
598  return item->clickType(x,y);
599  if (dx < w && dy < h)
600  return ClickType::onItem;
601  return ClickType::outside;
602  }
603 
604  float GodleyIcon::toEditorX(float xx) const
605  {return xx-x()+0.5f*width()-2*border*zoomFactor()-leftMargin();}
606  float GodleyIcon::toEditorY(float yy) const
607  {return yy-y()+0.5f*height()-2*border*zoomFactor()-titleOffs();}
608 
609  void GodleyIcon::onMouseDown(float x, float y)
610  {if (m_editorMode) editor.mouseDown(toEditorX(x),toEditorY(y));}
611 
612  void GodleyIcon::onMouseUp(float x, float y)
613  {if (m_editorMode) editor.mouseUp(toEditorX(x),toEditorY(y));}
614 
615  bool GodleyIcon::onMouseMotion(float x, float y)
616  {
617  if (m_editorMode) editor.mouseMoveB1(toEditorX(x),toEditorY(y));
618  return false;
619  }
620 
621  bool GodleyIcon::onMouseOver(float x, float y)
622  {
623  if (m_editorMode) editor.mouseMove(toEditorX(x),toEditorY(y));
624  return false;
625  }
626 
627  void GodleyIcon::onMouseLeave()
628  {
629  if (m_editorMode)
630  {
631  editor.mouseMove(-1,-1);
632  // May be a bit overzealous, but it solves bug 1273, which is caused by a flow which has not yet fully come into existence....
633  editor.selectedCol=-1;
634  editor.selectedRow=-1;
635  editor.update();
636  }
637  }
638 
639  bool GodleyIcon::onKeyPress(int keySym, const std::string& utf8, int)
640  {
641  if (m_editorMode) editor.keyPress(keySym, utf8);
642  return m_editorMode;
643  }
644 
645  SVGRenderer GodleyIcon::svgRenderer;
646 }
void importDuplicateColumn(GodleyTable &srcTable, int srcCol)
find any duplicate column, and use it as a source column for balanceDuplicateColumns ...
Definition: minsky.cc:618
represents items that have been selected
Definition: selection.h:32
function f
Definition: canvas.m:1
void balanceDuplicateColumns(const GodleyIcon &srcTable, int srcCol)
makes all duplicated columns consistent with srcTable, srcCol
Definition: minsky.cc:753
std::string latexToPango(const char *s)
Definition: latexMarkup.h:30
std::string str() const
Definition: variableType.cc:33
virtual float x() const
Definition: item.cc:107
VariableValues variableValues
Definition: minsky.h:200
virtual float y() const
Definition: item.cc:114
minsky::Minsky minsky
Definition: pyminsky.cc:28
DrawVars(cairo_t *cairo, float x, float y)
Definition: godleyIcon.cc:56
represents rectangular region of a lasso operation
Definition: lasso.h:28
STL namespace.
std::shared_ptr< Item > ItemPtr
Definition: item.h:57
string valueId(const string &name)
construct a valueId from fully qualified name @ name should not be canonicalised
Definition: valueId.cc:75
const std::string & init() const
std::string str() const
Definition: flowCoef.cc:81
move the contents of cell at (srcRow, srcCol) to (destRow, destCol).
Definition: godleyIcon.h:103
void operator()(const GodleyIcon::Variables &vars) const
Definition: godleyIcon.cc:59
Creation and access to the minskyTCL_obj object, which has code to record whenever Minsky&#39;s state cha...
Definition: constMap.h:22
std::string timeUnit
Definition: simulation.h:35
std::string trimWS(const std::string &s)
Definition: str.h:49
represents the units (in sense of dimensional analysis) of a variable.
Definition: units.h:34
std::string str(T x)
utility function to create a string representation of a numeric type
Definition: str.h:33
VariablePtr definingVar(const std::string &valueId) const
returns reference to variable defining (ie input wired) for valueId
Definition: minsky.cc:205
const Minsky & cminsky()
const version to help in const correctness
Definition: minsky.h:549
bool operator()(const VariablePtr &x, const VariablePtr &y) const
Definition: godleyIcon.cc:48
const float border
Definition: godleyIcon.cc:40
void ensureItemInserted(const ItemPtr &item)
check if item already present, and if not, inserts item delegates to ensureGroupInserted if passed a ...
Definition: selection.cc:60
represents a numerical coefficient times a variable (a "flow")
Definition: flowCoef.h:27
std::vector< VariablePtr > Variables
Definition: godleyIcon.h:111
float x0
Definition: lasso.h:30
float y1
Definition: lasso.h:30
float x1
Definition: lasso.h:30
void convertVarType(const std::string &name, VariableType::Type type)
Converts variable(s) named by name into a variable of type type.
Definition: minsky.cc:1457
float y0
Definition: lasso.h:30
Definition: group.tcl:84
void draw(cairo_t *) const override
Definition: variable.cc:704
Minsky & minsky()
global minsky object
Definition: minskyTCL.cc:51
void accumulateWidthHeight(const GodleyIcon::Variables &vars, float &height, float &width)
Definition: godleyIcon.cc:74
CLASSDESC_ACCESS_EXPLICIT_INSTANTIATION(minsky::GodleyIcon)
float height() const
half height of unrotated image
Definition: cairoItems.h:47
ItemPtr removeItem(const Item &)
Definition: group.cc:212
float width() const
half width of unrotated image
Definition: cairoItems.h:45