NEURON
graph.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 
3 #include <cstring>
4 #include <cstdio>
5 #include <cmath>
6 #include <assert.h>
7 
8 #include "code.h"
9 
10 #if HAVE_IV
11 #include <string>
12 #include <InterViews/glyph.h>
13 #include <InterViews/hit.h>
14 #include <InterViews/event.h>
15 #include <InterViews/color.h>
16 #include <InterViews/brush.h>
17 #include <InterViews/window.h>
18 #include <InterViews/printer.h>
19 #include <InterViews/label.h>
20 #include <InterViews/font.h>
21 #include <InterViews/background.h>
22 #include <InterViews/style.h>
23 #include <InterViews/telltale.h>
24 #include <OS/string.h>
25 #include <InterViews/image.h>
26 extern Image* gif_image(const char*);
27 
28 
29 #include <IV-look/kit.h>
30 
31 #include "apwindow.h"
32 #include "ivoc.h"
33 #include "graph.h"
34 #include "axis.h"
35 #include "hocmark.h"
36 #include "mymath.h"
37 #include "idraw.h"
38 #include "symchoos.h"
39 #include "scenepic.h"
40 #include "oc_ansi.h"
41 #include "oc2iv.h"
42 #include "objcmd.h"
43 #include "ocjump.h"
44 #include "utility.h"
45 #include "cbwidget.h"
46 #include "xmenu.h"
47 #include "ivocvect.h"
48 #endif /* HAVE_IV */
49 
50 #include "classreg.h"
51 #include "gui-redirect.h"
52 
53 #if HAVE_IV
54 #define Graph_Crosshair_ "Crosshair Graph"
55 #define Graph_Change_label_ "ChangeText Graph"
56 #define Graph_keep_lines_toggle_ "KeepLines Graph"
57 #define Graph_erase_axis_ "AxisType Graph"
58 #define Graph_new_axis_ "NewAxis AxisType Graph"
59 #define Graph_view_axis_ "ViewAxis AxisType Graph"
60 #define Graph_view_box_ "ViewBox AxisType Graph"
61 #define Graph_erase_lines_ "Erase Graph"
62 #define Graph_choose_sym_ "PlotWhat Graph"
63 #define Graph_choose_family_label_ "FamilyLabel Graph"
64 #define Graph_choose_rvp_ "PlotRange Graph"
65 
67  return false;
68 }
70  return true;
71 }
72 bool GraphItem::is_mark() {
73  return false;
74 }
75 
76 
77 /*static*/ class GraphLabelItem: public GraphItem {
78  public:
79  GraphLabelItem(Glyph* g)
80  : GraphItem(g) {}
81  virtual ~GraphLabelItem(){};
82  virtual void save(std::ostream& o, Coord x, Coord y) {
83  ((GLabel*) body())->save(o, x, y);
84  }
85  virtual void erase(Scene* s, GlyphIndex i, int type) {
86  if ((type & GraphItem::ERASE_LINE) && ((GLabel*) body())->erase_flag()) {
87  s->remove(i);
88  }
89  };
90 };
91 
92 /*static*/ class GraphAxisItem: public GraphItem {
93  public:
94  GraphAxisItem(Glyph* g)
95  : GraphItem(g) {}
96  virtual ~GraphAxisItem(){};
97  virtual void save(std::ostream& o, Coord, Coord) {
98  ((Axis*) body())->save(o);
99  }
100  virtual void erase(Scene* s, GlyphIndex i, int type) {
101  if (type & GraphItem::ERASE_AXIS) {
102  s->remove(i);
103  }
104  }
105 };
106 
107 /*static*/ class GraphMarkItem: public GraphItem {
108  public:
109  GraphMarkItem(Glyph* g)
110  : GraphItem(g) {}
111  virtual ~GraphMarkItem(){};
112  virtual void erase(Scene* s, GlyphIndex i, int type) {
113  if (type & GraphItem::ERASE_LINE) {
114  s->remove(i);
115  }
116  }
117  virtual bool is_mark() {
118  return true;
119  }
120 };
121 
122 /*static*/ class VectorLineItem: public GPolyLineItem {
123  public:
124  VectorLineItem(Glyph* g)
125  : GPolyLineItem(g) {}
126  virtual ~VectorLineItem(){};
127  virtual void erase(Scene* s, GlyphIndex i, int type) {}
128  virtual bool is_graphVector() {
129  return true;
130  }
131 };
132 
133 /*static*/ class LineExtension: public Glyph {
134  public:
135  LineExtension(GPolyLine*);
136  virtual ~LineExtension();
137 
138  void begin();
139  void extend();
140  void damage(Graph*);
141 
142  virtual void request(Requisition&) const;
143  virtual void allocate(Canvas*, const Allocation&, Extension&);
144  virtual void draw(Canvas*, const Allocation&) const;
145 
146  DataVec* xd() const {
147  return (DataVec*) gp_->x_data();
148  }
149  DataVec* yd() const {
150  return (DataVec*) gp_->y_data();
151  }
152 
153  private:
154  GPolyLine* gp_;
155  int start_;
156  int previous_;
157 };
158 
159 /*static*/ class NewLabelHandler: public Handler {
160  public:
161  NewLabelHandler(Graph*, Coord, Coord);
162  ~NewLabelHandler();
163  virtual bool event(Event&);
164 
165  private:
166  Graph* g_;
167  Coord x_, y_;
168 };
169 
170 NewLabelHandler::NewLabelHandler(Graph* g, Coord x, Coord y) {
171  // printf("NewLabelHandler\n");
172  g_ = g;
173  x_ = x;
174  y_ = y;
175 }
176 
177 NewLabelHandler::~NewLabelHandler() {
178  // printf("~NewLabelHandler\n");
179 }
180 bool NewLabelHandler::event(Event& e) {
181  char buf[200];
182  buf[0] = '\0';
183  GLabel* gl = g_->new_proto_label();
184  gl->ref();
185  if (Graph::label_chooser("Enter new label", buf, gl, e.pointer_root_x(), e.pointer_root_y())) {
186  if (gl->fixed()) {
187  g_->fixed(gl->scale());
188  } else {
189  g_->vfixed(gl->scale());
190  }
191  if (g_->labeltype() == 2) {
192  XYView::current_pick_view()->s2o().inverse_transform(x_, y_);
194  }
195  g_->label(x_, y_, buf);
196  }
197  gl->unref();
198  return true;
199 }
200 
201 // Graph registration for oc
202 static void gr_axis(Graph* g, DimensionName d) {
203  if (hoc_usegui) {
204  int ntic = -1;
205  int nminor = 0;
206  int invert = 0;
207  bool number = true;
208  float x1 = 0;
209  float x2 = -1;
210  float pos = 0.;
211  if (!ifarg(2)) {
212  int i = 0;
213  if (ifarg(1)) {
214  i = int(chkarg(1, 0, 3));
215  }
216  switch (i) {
217  case 0:
218  g->view_axis();
219  break;
220  case 1:
221  g->erase_axis();
222  g->axis(Dimension_X, x1, x2, pos, ntic, nminor, invert, number);
223  g->axis(Dimension_Y, x1, x2, pos, ntic, nminor, invert, number);
224  break;
225  case 2:
226  g->view_box();
227  break;
228  case 3:
229  g->erase_axis();
230  break;
231  }
232  return;
233  }
234  if (ifarg(3)) {
235  pos = *getarg(3);
236  }
237  if (ifarg(4)) {
238  ntic = int(chkarg(4, -1, 100));
239  }
240  if (ifarg(2)) {
241  x1 = *getarg(1);
242  x2 = *getarg(2);
243  }
244  if (ifarg(5)) {
245  nminor = int(chkarg(5, 0, 100));
246  }
247  if (ifarg(6)) {
248  invert = int(chkarg(6, -1, 1));
249  }
250  if (ifarg(7) && !int(chkarg(7, 0, 1))) {
251  number = false;
252  }
253  g->axis(d, x1, x2, pos, ntic, nminor, invert, number);
254  }
255 }
256 #endif /* HAVE_IV */
257 
258 static double gr_xaxis(void* v) {
259  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.xaxis", v);
260 #if HAVE_IV
261  gr_axis((Graph*) v, Dimension_X);
262  return 1.;
263 #else
264  return 0.;
265 #endif /* HAVE_IV */
266 }
267 static double gr_yaxis(void* v) {
268  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.yaxis", v);
269 #if HAVE_IV
270  gr_axis((Graph*) v, Dimension_Y);
271  return 1.;
272 #else
273  return 0.;
274 #endif /* HAVE_IV */
275 }
276 static double gr_save_name(void* v) {
277  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.save_name", v);
278 #if HAVE_IV
279  if (hoc_usegui) {
280  Graph* g = (Graph*) v;
281  g->name(gargstr(1));
282  if (ifarg(2) && (chkarg(2, 0, 1) == 1.) && Oc::save_stream) {
283  *Oc::save_stream << "{\nsave_window_=" << gargstr(1) << std::endl;
284  *Oc::save_stream << "save_window_.size(" << g->x1() << "," << g->x2() << "," << g->y1()
285  << "," << g->y2() << ")\n";
286  long i = Scene::scene_list_index(g);
287  *Oc::save_stream << "scene_vector_[" << i << "] = save_window_" << std::endl;
289  g->Scene::mark(true);
290  }
291  }
292  return 1.;
293 #else
294  return 0.;
295 #endif /* HAVE_IV */
296 }
297 #if HAVE_IV
298 
299 static void move_label(Graph* g, const GLabel* lab, int ioff = 0) {
300  float x, y;
301  if (ifarg(4 + ioff) && lab) {
302  x = *getarg(4 + ioff);
303  y = *getarg(5 + ioff);
304  g->move(g->glyph_index(lab), x, y);
305  }
306 }
307 #endif /* HAVE_IV */
308 
309 static double gr_family(void* v) {
310  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.family", v);
311 #if HAVE_IV
312  if (hoc_usegui) {
313  if (hoc_is_str_arg(1)) {
314  ((Graph*) v)->family(gargstr(1));
315  } else {
316  ((Graph*) v)->family(int(chkarg(1, 0, 1)));
317  }
318  }
319  return 1.;
320 #else
321  return 0.;
322 #endif /* HAVE_IV */
323 }
324 
325 double ivoc_gr_menu_action(void* v) {
326  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.menu_action", v);
327 #if HAVE_IV
328  if (hoc_usegui) {
329  HocCommand* hc;
330  if (hoc_is_object_arg(2)) {
331  hc = new HocCommand(*hoc_objgetarg(2));
332  } else {
333  hc = new HocCommand(gargstr(2));
334  }
335  ((Scene*) v)->picker()->add_menu(gargstr(1), new HocCommandAction(hc));
336  }
337  return 1.;
338 #else
339  return 0.;
340 #endif /* HAVE_IV */
341 }
342 
343 double ivoc_gr_menu_tool(void* v) {
344  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.menu_tool", v);
345 #if HAVE_IV
346  if (hoc_usegui) {
347  if (hoc_is_object_arg(2)) { // python style
349  NULL,
350  NULL,
351  ((Scene*) v)->picker(),
352  *hoc_objgetarg(2),
353  ifarg(3) ? *hoc_objgetarg(3) : NULL);
354  } else {
356  gargstr(2),
357  ifarg(3) ? gargstr(3) : NULL,
358  ((Scene*) v)->picker());
359  }
360  }
361  return 1.;
362 #else
363  return 0.;
364 #endif /* HAVE_IV */
365 }
366 
367 double ivoc_view_info(void* v) {
368  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.view_info", v);
369 #if HAVE_IV
370  if (hoc_usegui) {
371  int i;
372  Scene* s = (Scene*) v;
373  XYView* view;
374  if (!ifarg(1)) {
375  view = XYView::current_pick_view();
376  for (i = 0; i < s->view_count(); ++i) {
377  if (s->sceneview(i) == view) {
378  return double(i);
379  }
380  }
381  return -1.;
382  }
383  view = s->sceneview(int(chkarg(1, 0, s->view_count() - 1)));
384  float x1, y1, x2, y2;
385  i = int(chkarg(2, 1, 15));
386  switch (i) {
387  case 1: // width
388  return view->width();
389  case 2: // height
390  return view->height();
391  case 3: // point width
392  view->view_ratio(0., 0., x1, y1);
393  view->view_ratio(1., 1., x2, y2);
394  return x2 - x1;
395  case 4: // point height
396  view->view_ratio(0., 0., x1, y1);
397  view->view_ratio(1., 1., x2, y2);
398  return y2 - y1;
399  case 5: // left
400  return view->left();
401  case 6: // right
402  return view->right();
403  case 7: // bottom
404  return view->bottom();
405  case 8: // top
406  return view->top();
407  case 9: // model x distance for one point
408  view->view_ratio(0., 0., x1, y1);
409  view->view_ratio(1., 1., x2, y2);
410  if (x2 > x1) {
411  return view->width() / (x2 - x1);
412  } else {
413  return 1.;
414  }
415  case 10: // model y distance for one point
416  view->view_ratio(0., 0., x1, y1);
417  view->view_ratio(1., 1., x2, y2);
418  if (y2 > y1) {
419  return view->height() / (y2 - y1);
420  } else {
421  return 1.;
422  }
423  case 11: // relative x location (from x model coord)
424  return (*getarg(3) - view->left()) / view->width();
425  case 12: // relative y location (from y model coord)
426  return (*getarg(3) - view->bottom()) / view->height();
427  case 13: // points from left (from x model coord)
428  x1 = (*getarg(3) - view->left()) / view->width();
429  view->view_ratio(x1, 1., x2, y2);
430  view->view_ratio(0., 1., x1, y1);
431  return x2 - x1;
432  case 14: // points from top (from y model coord)
433  y1 = (*getarg(3) - view->bottom()) / view->height();
434  view->view_ratio(1., y1, x2, y2);
435  view->view_ratio(1., 1., x1, y1);
436  return y1 - y2;
437  case 15: // label height in points
438  // return WidgetKit::instance()->font()->size();
439  {
440  FontBoundingBox b;
441  WidgetKit::instance()->font()->font_bbox(b);
442  return b.ascent() + b.descent();
443  }
444  }
445  }
446 #endif /* HAVE_IV */
447  return -1.;
448 }
449 
450 double ivoc_view_size(void* v) {
451  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.view_size", v);
452 #if HAVE_IV
453  if (hoc_usegui) {
454  int i;
455  Scene* s = (Scene*) v;
456  XYView* view;
457  view = s->sceneview(int(chkarg(1, 0, s->view_count() - 1)));
458  view->size(*getarg(2), *getarg(4), *getarg(3), *getarg(5));
459  view->damage_all();
460  }
461 #endif /* HAVE_IV */
462  return 0.;
463 }
464 
465 double gr_line_info(void* v) {
466  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.line_info", v);
467 #if HAVE_IV
468  if (hoc_usegui) {
469  Graph* g = (Graph*) v;
470  GlyphIndex i, cnt;
471  double* p;
472  cnt = g->count();
473  i = (int) chkarg(1, -1, cnt);
474  if (i < 0 || i > cnt - 1) {
475  i = -1;
476  }
477  Vect* x = vector_arg(2);
478  for (i += 1; i < cnt; ++i) {
479  GraphItem* gi = (GraphItem*) g->component(i);
480  if (gi->is_polyline()) {
481  GPolyLine* gpl = (GPolyLine*) gi->body();
482  x->resize(5);
483  p = vector_vec(x);
484  p[0] = colors->color(gpl->color());
485  p[1] = brushes->brush(gpl->brush());
486  if (gpl->label()) {
487  Coord a, b;
488  x->label(gpl->label()->text());
489  g->location(g->glyph_index(gpl->label()), a, b);
490  p[2] = a;
491  p[3] = b;
492  p[4] = gpl->label()->fixtype();
493  }
494  return (double) i;
495  }
496  }
497  }
498 #endif /* HAVE_IV */
499  return -1.;
500 }
501 
502 #if HAVE_IV
503 static void gr_add(void* v, bool var) {
504  if (hoc_usegui) {
505  Graph* g = (Graph*) v;
506  GraphLine* gl;
507  Object* obj = NULL;
508  char* lab = NULL;
509  char* expr = NULL;
510  int ioff = 0; // deal with 0, 1, or 2 optional arguments after first
511  // pointer to varname if second arg is varname string
513  int fixtype = g->labeltype();
514  // organize args for backward compatibility and the new
515  // addexpr("label, "expr", obj,.... style
516  if (ifarg(2)) {
517  if (var) { // if string or address then variable and 1 was label
518  expr = hoc_gargstr(1);
519  if (hoc_is_str_arg(2)) {
520  pd = hoc_val_handle(hoc_gargstr(2));
521  ioff += 1;
522  } else if (hoc_is_pdouble_arg(2)) {
523  pd = hoc_hgetarg<double>(2);
524  ioff += 1;
525  }
526  } else if (hoc_is_str_arg(2)) { // 1 label, 2 expression
527  lab = hoc_gargstr(1);
528  expr = hoc_gargstr(2);
529  ioff += 1;
530  if (ifarg(3) && hoc_is_object_arg(3)) { // object context
531  obj = *hoc_objgetarg(3);
532  ioff += 1;
533  }
534  } else if (hoc_is_object_arg(2)) { // 1 expr, 2 object context
535  expr = hoc_gargstr(1);
536  obj = *hoc_objgetarg(2);
537  ioff += 1;
538  } else {
539  expr = hoc_gargstr(1);
540  }
541  } else {
542  expr = hoc_gargstr(1);
543  }
544  if (ifarg(3 + ioff)) {
545  if (ifarg(6 + ioff)) {
546  fixtype = int(chkarg(6 + ioff, 0, 2));
547  } else if (ifarg(4 + ioff)) {
548  // old versions did not have the fixtype and for
549  // backward compatibility it must therefore be
550  // fixed.
551  fixtype = 1;
552  }
553  gl = g->add_var(expr,
554  colors->color(int(*getarg(2 + ioff))),
555  brushes->brush(int(*getarg(3 + ioff))),
556  var,
557  fixtype,
558  pd,
559  lab,
560  obj);
561  } else {
562  gl = g->add_var(expr, g->color(), g->brush(), var, fixtype, pd, lab, obj);
563  }
564  move_label(g, gl->label(), ioff);
565  }
566 }
567 #endif /* HAVE_IV */
568 static double gr_addvar(void* v) {
569  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.addvar", v);
570 #if HAVE_IV
571  gr_add(v, 1);
572  return 1.;
573 #else
574  return 0.;
575 #endif /* HAVE_IV */
576 }
577 static double gr_addexpr(void* v) {
578  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.addexpr", v);
579 #if HAVE_IV
580  gr_add(v, 0);
581  return 1.;
582 #else
583  return 0.;
584 #endif /* HAVE_IV */
585 }
586 static double gr_addobject(void* v) {
587  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.addobject", v);
588 #if HAVE_IV
589  if (hoc_usegui) {
590  Graph* g = (Graph*) v;
591  Object* obj = *hoc_objgetarg(1);
592  if (is_obj_type(obj, "RangeVarPlot")) {
593  GraphVector* gv = (GraphVector*) obj->u.this_pointer;
594  if (ifarg(3)) {
595  gv->color(colors->color(int(*getarg(2))));
596  gv->brush(brushes->brush(int(*getarg(3))));
597  } else {
598  gv->color(g->color());
599  gv->brush(g->brush());
600  }
601  g->append(new VectorLineItem(gv));
602  GLabel* glab = g->label(gv->name());
603  gv->label(glab);
604  ((GraphItem*) g->component(g->glyph_index(glab)))->save(false);
605  g->see_range_plot(gv);
606  move_label(g, glab);
607  } else {
608  hoc_execerror("Don't know how to plot this object type", 0);
609  }
610  }
611  return 1.;
612 #else
613  return 0.;
614 #endif /* HAVE_IV */
615 }
616 
617 static double gr_vector(void* v) {
618  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.vector", v);
619 #if HAVE_IV
620  if (hoc_usegui) {
621  Graph* g = (Graph*) v;
622  int n = int(chkarg(1, 1., 1.e5));
623  double* x = hoc_pgetarg(2);
624  auto y_handle = hoc_hgetarg<double>(3);
625  GraphVector* gv = new GraphVector("");
626  if (ifarg(4)) {
627  gv->color(colors->color(int(*getarg(4))));
628  gv->brush(brushes->brush(int(*getarg(5))));
629  } else {
630  gv->color(g->color());
631  gv->brush(g->brush());
632  }
633  for (int i = 0; i < n; ++i) {
634  gv->add(x[i], y_handle.next_array_element(i));
635  }
636  // GLabel* glab = g->label(gv->name());
637  // ((GraphItem*)g->component(g->glyph_index(glab)))->save(false);
638  g->append(new GPolyLineItem(gv));
639  }
640  return 1.;
641 #else
642  return 0.;
643 #endif /* HAVE_IV */
644 }
645 
646 static double gr_xexpr(void* v) {
647  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.xexpr", v);
648 #if HAVE_IV
649  if (hoc_usegui) {
650  Graph* g = (Graph*) v;
651  int i = 0;
652  if (ifarg(2)) {
653  i = int(chkarg(2, 0, 1));
654  }
655  g->x_expr(gargstr(1), i);
656  }
657  return 1.;
658 #else
659  return 0.;
660 #endif /* HAVE_IV */
661 }
662 
663 static double gr_begin(void* v) {
664  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.begin", v);
665 #if HAVE_IV
666  if (hoc_usegui) {
667  ((Graph*) v)->begin();
668  }
669  return 1.;
670 #else
671  return 0.;
672 #endif /* HAVE_IV */
673 }
674 
675 static double gr_plot(void* v) {
676  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.plot", v);
677 #if HAVE_IV
678  if (hoc_usegui) {
679  ((Graph*) v)->plot(*getarg(1));
680  }
681  return 1.;
682 #else
683  return 0.;
684 #endif /* HAVE_IV */
685 }
686 
687 static double gr_simgraph(void* v) {
688  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.simgraph", v);
689 #if HAVE_IV
690  if (hoc_usegui) {
691  ((Graph*) v)->simgraph();
692  }
693  return 1.;
694 #else
695  return 0.;
696 #endif /* HAVE_IV */
697 }
698 
699 double ivoc_gr_begin_line(void* v) {
700  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.beginline", v);
701 #if HAVE_IV
702  if (hoc_usegui) {
703  Graph* g = (Graph*) v;
704  int i = 1;
705  char* s = NULL;
706  if (ifarg(i) && hoc_is_str_arg(1)) {
707  s = gargstr(i++);
708  }
709  if (ifarg(i)) {
710  g->begin_line(colors->color(int(*getarg(i))), brushes->brush(int(*getarg(i + 1))), s);
711  } else {
712  g->begin_line(s);
713  }
714  }
715  return 1.;
716 #else
717  return 0.;
718 #endif /* HAVE_IV */
719 }
720 double ivoc_gr_line(void* v) {
721  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.line", v);
722 #if HAVE_IV
723  if (hoc_usegui) {
724  ((Graph*) v)->line(*getarg(1), *getarg(2));
725  }
726  return 1.;
727 #else
728  return 0.;
729 #endif /* HAVE_IV */
730 }
731 static double gr_flush(void* v) {
732  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.flush", v);
733 
734 #if HAVE_IV
735  if (hoc_usegui) {
736  ((Graph*) v)->flush();
737  }
738  return 1.;
739 #else
740  return 0.;
741 #endif /* HAVE_IV */
742 }
743 static double gr_fast_flush(void* v) {
744  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.fast_flush", v);
745 
746 #if HAVE_IV
747  if (hoc_usegui) {
748  ((Graph*) v)->fast_flush();
749  }
750  return 1.;
751 #else
752  return 0.;
753 #endif /* HAVE_IV */
754 }
755 double ivoc_gr_erase(void* v) {
756  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.erase", v);
757 #if HAVE_IV
758  if (hoc_usegui) {
759  ((Graph*) v)->erase_lines();
760  }
761  return 1.;
762 #else
763  return 0.;
764 #endif /* HAVE_IV */
765 }
766 
767 double ivoc_erase_all(void* v) {
768  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.erase_all", v);
769 #if HAVE_IV
770  if (hoc_usegui) {
771  ((Graph*) v)->erase_all();
772  }
773  return 1.;
774 #else
775  return 0.;
776 #endif /* HAVE_IV */
777 }
778 
779 double ivoc_gr_gif(void* v) {
780  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.gif", v);
781 #if HAVE_IV
782  if (hoc_usegui) {
783  Graph* g = (Graph*) v;
784  Glyph* i = gif_image(gargstr(1));
785  if (i) {
786  Transformer t;
787  if (ifarg(4)) {
788  Coord x = *getarg(4);
789  Coord y = *getarg(5);
790  Requisition r;
791  i->request(r);
792  t.scale(x / r.x_requirement().natural(), y / r.y_requirement().natural());
793  i = new TransformSetter(i, t);
794  }
795  if (!ifarg(2)) { // resize if smaller than gif
796  Requisition r;
797  i->request(r);
798  if (r.x_requirement().natural() > (g->x2() - g->x1()) ||
799  r.y_requirement().natural() > (g->y2() - g->y1())) {
800  g->new_size(0, 0, r.x_requirement().natural(), r.y_requirement().natural());
801  }
802  }
803  g->append(new GraphItem(i, false, false));
804  if (ifarg(2)) {
805  g->move(g->count() - 1, *getarg(2), *getarg(3));
806  }
807  return 1.;
808  }
809  }
810 #endif /* HAVE_IV */
811  return 0.;
812 }
813 
814 double ivoc_gr_size(void* v) {
815  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.size", v);
816 #if HAVE_IV
817  if (hoc_usegui) {
818  Coord x1, y1, x2, y2;
819  Graph* g = (Graph*) v;
820  XYView* view = g->sceneview(0);
821  if (ifarg(2)) {
822  g->new_size(*getarg(1), *getarg(3), *getarg(2), *getarg(4));
823  }
824  if (hoc_is_pdouble_arg(1)) {
825  g->wholeplot(x1, y1, x2, y2);
826  double* x = hoc_pgetarg(1);
827  x[0] = x1;
828  x[1] = x2;
829  x[2] = y1;
830  x[3] = y2;
831  return 0.;
832  }
833  if (!view) {
834  return 0.;
835  }
836 
837  if (ifarg(2)) {
838  view->zout(x1, y1, x2, y2);
839  view->size(x1, y1, x2, y2);
840  return 1.;
841  } else {
842  view->zin(x1, y1, x2, y2);
843  double x = 0.;
844  switch (int(chkarg(1, 1., 4.))) {
845  case 1:
846  x = x1;
847  break;
848  case 2:
849  x = x2;
850  break;
851  case 3:
852  x = y1;
853  break;
854  case 4:
855  x = y2;
856  break;
857  }
858  return x;
859  }
860  }
861  return 0.;
862 #else
863  return 0.;
864 #endif /* HAVE_IV */
865 }
866 
867 double ivoc_gr_label(void* v) {
868  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.label", v);
869 #if HAVE_IV
870  if (hoc_usegui) {
871  Graph* g = (Graph*) v;
872  if (ifarg(8)) {
873  g->label(*getarg(1),
874  *getarg(2),
875  gargstr(3),
876  int(*getarg(4)),
877  *getarg(5),
878  *getarg(6),
879  *getarg(7),
880  colors->color(int(*getarg(8))));
881  } else if (ifarg(2)) {
882  char* s = NULL;
883  if (ifarg(3)) {
884  s = gargstr(3);
885  }
886  g->label(*getarg(1), *getarg(2), s);
887  } else {
888  g->label(gargstr(1));
889  }
890  }
891  return 1.;
892 #else
893  return 0.;
894 #endif /* HAVE_IV */
895 }
896 static double gr_fixed(void* v) {
897  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.fixed", v);
898 #if HAVE_IV
899  if (hoc_usegui) {
900  float scale = 1;
901  if (ifarg(1)) {
902  scale = chkarg(1, .01, 100);
903  }
904  ((Graph*) v)->fixed(scale);
905  }
906  return 1.;
907 #else
908  return 0.;
909 #endif /* HAVE_IV */
910 }
911 static double gr_vfixed(void* v) {
912  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.vfixed", v);
913 #if HAVE_IV
914  if (hoc_usegui) {
915  float scale = 1;
916  if (ifarg(1)) {
917  scale = chkarg(1, .01, 100);
918  }
919  ((Graph*) v)->vfixed(scale);
920  }
921  return 1.;
922 #else
923  return 0.;
924 #endif /* HAVE_IV */
925 }
926 static double gr_relative(void* v) {
927  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.relative", v);
928 #if HAVE_IV
929  if (hoc_usegui) {
930  float scale = 1.;
931  if (ifarg(1)) {
932  scale = chkarg(1, .01, 100.);
933  }
934  ((Graph*) v)->relative(scale);
935  }
936  return 1.;
937 #else
938  return 0.;
939 #endif /* HAVE_IV */
940 }
941 static double gr_align(void* v) {
942  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.align", v);
943 #if HAVE_IV
944  if (hoc_usegui) {
945  float x = 0, y = 0;
946  if (ifarg(1)) {
947  x = chkarg(1, -10, 10);
948  }
949  if (ifarg(2)) {
950  y = chkarg(2, -10, 10);
951  }
952  ((Graph*) v)->align(x, y);
953  }
954  return 1.;
955 #else
956  return 0.;
957 #endif /* HAVE_IV */
958 }
959 static double gr_color(void* v) {
960  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.color", v);
961 #if HAVE_IV
962  if (hoc_usegui) {
963  int i = 1;
964  if (ifarg(2)) {
965  colors->color(int(chkarg(1, 2, ColorPalette::COLOR_SIZE - 1)), gargstr(2));
966  return 1.;
967  }
968  if (ifarg(1)) {
969  i = int(chkarg(1, -1, ColorPalette::COLOR_SIZE - 1));
970  }
971  ((Graph*) v)->color(i);
972  }
973  return 1.;
974 #else
975  return 0.;
976 #endif /* HAVE_IV */
977 }
978 static double gr_brush(void* v) {
979  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.brush", v);
980 #if HAVE_IV
981  if (hoc_usegui) {
982  int i = 0;
983  if (ifarg(3)) {
984  brushes->brush(int(chkarg(1, 1, BrushPalette::BRUSH_SIZE - 1)),
985  int(*getarg(2)),
986  float(chkarg(3, 0, 1000)));
987  return 1.;
988  }
989  if (ifarg(1)) {
990  i = int(chkarg(1, -1, 20));
991  }
992  ((Graph*) v)->brush(i);
993  }
994  return 1.;
995 #else
996  return 0.;
997 #endif /* HAVE_IV */
998 }
999 
1000 static double gr_view(void* v) {
1001  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.view", v);
1002 #if HAVE_IV
1003  if (hoc_usegui) {
1004  Graph* g = (Graph*) v;
1005  if (ifarg(8)) {
1006  Coord x[8];
1007  int i;
1008  for (i = 0; i < 8; ++i) {
1009  x[i] = *getarg(i + 1);
1010  }
1011  XYView* view = new XYView(x[0], x[1], x[2], x[3], g, x[6], x[7]);
1012  Coord x1, x2, y1, y2;
1013  view->zout(x1, y1, x2, y2);
1014  view->size(x1, y1, x2, y2);
1015  // printf("%g %g %g %g\n", view->left(), view->bottom(), view->right(), view->top());
1016  ViewWindow* w = new ViewWindow(view, hoc_object_name(g->hoc_obj_ptr()));
1017  w->xplace(int(x[4]), int(x[5]));
1018  w->map();
1019  } else if (ifarg(1) && *getarg(1) == 2.) {
1020  View* view = new View(g);
1021  ViewWindow* w = new ViewWindow(view, hoc_object_name(g->hoc_obj_ptr()));
1022  w->map();
1023  }
1024  }
1025 
1026  return 1.;
1027 #else
1028  return 0.;
1029 #endif /* HAVE_IV */
1030 }
1031 
1032 double ivoc_gr_mark(void* v) {
1033  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.mark", v);
1034 #if HAVE_IV
1035  if (hoc_usegui) {
1036  Graph* g = (Graph*) v;
1037  Coord x = *getarg(1);
1038  Coord y = *getarg(2);
1039  char style = '+';
1040  if (ifarg(3)) {
1041  if (hoc_is_str_arg(3)) {
1042  style = *gargstr(3);
1043  } else {
1044  style = char(chkarg(3, 0, 10));
1045  }
1046  }
1047  if (!ifarg(4)) {
1048  g->mark(x, y, style);
1049  } else if (!ifarg(5)) {
1050  g->mark(x, y, style, chkarg(4, .1, 100.), g->color(), g->brush());
1051  } else {
1052  g->mark(x,
1053  y,
1054  style,
1055  chkarg(4, .1, 100.),
1056  colors->color(int(*getarg(5))),
1057  brushes->brush(int(*getarg(6))));
1058  }
1059  }
1060  return 1.;
1061 #else
1062  return 0.;
1063 #endif /* HAVE_IV */
1064 }
1065 
1066 static double gr_view_count(void* v) {
1068  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.view_count", v);
1069 #if HAVE_IV
1070  int n = 0;
1071  if (hoc_usegui) {
1072  n = ((Scene*) v)->view_count();
1073  }
1074  return double(n);
1075 #else
1076  return 0.;
1077 #endif /* HAVE_IV */
1078 }
1079 
1080 static double gr_unmap(void* v) {
1081  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.unmap", v);
1082 #if HAVE_IV
1083  if (hoc_usegui) {
1084  Graph* g = (Graph*) v;
1085  g->dismiss();
1086  }
1087  return 0.;
1088 #else
1089  return 0.;
1090 #endif /* HAVE_IV */
1091 }
1092 
1093 static double gr_set_cross_action(void* v) {
1094  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.crosshair_action", v);
1095 #if HAVE_IV
1096  if (hoc_usegui) {
1097  Graph* g = (Graph*) v;
1098  bool vector_copy = false;
1099  if (ifarg(2)) {
1100  vector_copy = int(chkarg(2, 0, 1));
1101  }
1102  if (hoc_is_str_arg(1)) {
1103  g->set_cross_action(gargstr(1), NULL, vector_copy);
1104  } else {
1105  g->set_cross_action(NULL, *hoc_objgetarg(1), vector_copy);
1106  }
1107  }
1108  return 0.;
1109 #else
1110  return 0.;
1111 #endif /* HAVE_IV */
1112 }
1113 
1114 static double gr_printfile(void* v) {
1115  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.printfile", v);
1116 #if HAVE_IV
1117  if (hoc_usegui) {
1118  Graph* g = (Graph*) v;
1119  g->printfile(gargstr(1));
1120  }
1121  return 1.;
1122 #else
1123  return 0.;
1124 #endif /* HAVE_IV */
1125 }
1126 
1127 static double exec_menu(void* v) {
1128  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.exec_menu", v);
1129 #if HAVE_IV
1130  if (hoc_usegui) {
1131  ((Scene*) v)->picker()->exec_item(gargstr(1));
1132  }
1133 #endif
1134  return 0.;
1135 }
1136 
1137 double ivoc_gr_menu_remove(void* v) {
1138  TRY_GUI_REDIRECT_ACTUAL_DOUBLE("Graph.menu_remove", v);
1139 #if HAVE_IV
1140  if (hoc_usegui) {
1141  ((Scene*) v)->picker()->remove_item(gargstr(1));
1142  }
1143 #endif
1144  return 0.;
1145 }
1146 
1147 #if HAVE_IV
1148 extern double gr_getline(void*);
1149 #endif
1150 extern double gr_addglyph(void*);
1151 
1152 static Member_func gr_members[] = {{"plot", gr_plot},
1153  {"fastflush", gr_fast_flush},
1154  {"flush", gr_flush},
1155  {"xaxis", gr_xaxis},
1156  {"yaxis", gr_yaxis},
1157  {"addvar", gr_addvar},
1158  {"addexpr", gr_addexpr},
1159  {"addobject", gr_addobject},
1160  {"glyph", gr_addglyph},
1161  {"vector", gr_vector},
1162  {"xexpr", gr_xexpr},
1163  {"begin", gr_begin},
1164  {"erase", ivoc_gr_erase},
1165  {"size", ivoc_gr_size},
1166  {"label", ivoc_gr_label},
1167  {"fixed", gr_fixed},
1168  {"vfixed", gr_vfixed},
1169  {"relative", gr_relative},
1170  {"align", gr_align},
1171  {"color", gr_color},
1172  {"brush", gr_brush},
1173  {"view", gr_view},
1174  {"save_name", gr_save_name},
1175  {"beginline", ivoc_gr_begin_line},
1176  {"line", ivoc_gr_line},
1177  {"mark", ivoc_gr_mark},
1178  {"simgraph", gr_simgraph},
1179  {"view_count", gr_view_count},
1180  {"erase_all", ivoc_erase_all},
1181  {"unmap", gr_unmap},
1182  {"crosshair_action", gr_set_cross_action},
1183  {"printfile", gr_printfile},
1184  {"family", gr_family},
1185  {"menu_action", ivoc_gr_menu_action},
1186  {"menu_tool", ivoc_gr_menu_tool},
1187  {"view_info", ivoc_view_info},
1188  {"view_size", ivoc_view_size},
1189 #if HAVE_IV
1190  {"getline", gr_getline},
1191 #endif
1192  {"exec_menu", exec_menu},
1193  {"gif", ivoc_gr_gif},
1194  {"menu_remove", ivoc_gr_menu_remove},
1195  {"line_info", gr_line_info},
1196  {nullptr, nullptr}};
1197 
1198 static void* gr_cons(Object* ho) {
1199  TRY_GUI_REDIRECT_OBJ("Graph", NULL);
1200 #if HAVE_IV
1201  Graph* g = NULL;
1202  if (hoc_usegui) {
1203  int i = 1;
1204  if (ifarg(1)) {
1205  i = (int) chkarg(1, 0, 1);
1206  }
1207  g = new Graph(i);
1208  g->ref();
1209  g->hoc_obj_ptr(ho);
1210  }
1211  return (void*) g;
1212 #else
1213  return (void*) 0;
1214 #endif /* HAVE_IV */
1215 }
1216 static void gr_destruct(void* v) {
1217  TRY_GUI_REDIRECT_NO_RETURN("~Graph", v);
1218 #if HAVE_IV
1219  if (hoc_usegui) {
1220  Graph* g = (Graph*) v;
1221  g->dismiss();
1222  Resource::unref(g);
1223  }
1224 #endif /* HAVE_IV */
1225 }
1226 void Graph_reg() {
1227  // printf("Graph_reg\n");
1229 #if HAVE_IV
1230  if (hoc_usegui) {
1231  colors = new ColorPalette();
1232  brushes = new BrushPalette();
1233  }
1234 #endif
1235 }
1236 #if HAVE_IV
1237 static const char* colorname[] =
1238  {"white", "black", "red", "blue", "green", "orange", "brown", "violet", "yellow", "gray", 0};
1239 
1241  int i;
1242  for (i = 0; i < COLOR_SIZE && colorname[i]; ++i) {
1243  color_palette[i] = NULL;
1244  color(i, colorname[i]);
1245  }
1246 
1249 
1250  int j;
1251  for (j = 0; i < COLOR_SIZE; ++i, ++j) {
1252  // color_palette[i] = color_palette[j];
1253  // ZFM fix to allow more colors (COLOR_SIZE > 20)
1254  color_palette[i] = color_palette[j % 10];
1256  }
1257 };
1259  for (int i = 0; i < COLOR_SIZE; ++i) {
1261  }
1262 }
1263 
1264 const Color* ColorPalette::color(int i) const {
1265  if (hoc_usegui) {
1266  if (i < 0)
1267  i = 1;
1268  i = i % COLOR_SIZE;
1269  return color_palette[i];
1270  } else
1271  return NULL;
1272 }
1273 const Color* ColorPalette::color(int i, const char* name) {
1274  const Color* c = Color::lookup(Session::instance()->default_display(), name);
1275  if (c == NULL) {
1276  printf(
1277  "couldn't lookup color \"%s\", you must be missing the\n\
1278 colormap.ini file or else the name isn't in it\n",
1279  name);
1280  }
1281  return color(i, c);
1282 }
1283 const Color* ColorPalette::color(int i, const Color* c) {
1284  if (c) {
1285  Resource::ref(c);
1287  color_palette[i] = c;
1288  }
1289  return color_palette[i];
1290 }
1291 
1292 int ColorPalette::color(const Color* c) const {
1293  for (int i = 0; i < COLOR_SIZE; ++i) {
1294  if (color_palette[i] == c) {
1295  return i;
1296  }
1297  }
1298  return 1;
1299 }
1300 
1301 static int brush_pattern[] = {0x0, 0xcccc, 0xfff0, 0xff00, 0xf000};
1302 
1304  int i;
1305  for (i = 0; i < BRUSH_SIZE; ++i) {
1306  brush_palette[i] = NULL;
1307  }
1308  i = 0;
1309  for (int j = 0; j < 5; ++j) {
1310  for (int k = 0; k < 5; ++k) {
1311  if (i < BRUSH_SIZE) {
1312  brush(i++, brush_pattern[j], k);
1313  }
1314  }
1315  }
1316 }
1318  for (int i = 0; i < BRUSH_SIZE; ++i) {
1320  }
1321 }
1322 
1323 const Brush* BrushPalette::brush(int i) const {
1324  if (hoc_usegui) {
1325  if (i < 0)
1326  i = 1;
1327  i = i % BRUSH_SIZE;
1328  return brush_palette[i];
1329  } else
1330  return NULL;
1331 }
1332 const Brush* BrushPalette::brush(int i, int pattern, Coord width) {
1333  Brush* b;
1334  if (pattern) {
1335  b = new Brush(pattern, width);
1336  } else {
1337  b = new Brush(width);
1338  }
1339  Resource::ref(b);
1341  brush_palette[i] = b;
1342  return b;
1343 }
1344 
1345 int BrushPalette::brush(const Brush* b) const {
1346  for (int i = 0; i < BRUSH_SIZE; ++i) {
1347  if (brush_palette[i] == b) {
1348  return i;
1349  }
1350  }
1351  return 0;
1352 }
1353 
1354 
1357 
1358 GraphItem::GraphItem(Glyph* g, bool s, bool p)
1359  : MonoGlyph(g) {
1360  save_ = s;
1361  pick_ = p;
1362 }
1364 void GraphItem::save(std::ostream&, Coord, Coord) {}
1365 void GraphItem::erase(Scene*, GlyphIndex, int) {}
1366 void GraphItem::pick(Canvas* c, const Allocation& a, int depth, Hit& h) {
1367  if (pick_) {
1368  MonoGlyph::pick(c, a, depth, h);
1369  }
1370 }
1371 
1372 // Graph
1373 declareActionCallback(Graph);
1374 implementActionCallback(Graph);
1375 
1376 #define XSCENE 300.
1377 #define YSCENE 200.
1378 Graph::Graph(bool b)
1379  : Scene(0, 0, XSCENE, YSCENE) {
1380  loc_ = 0;
1381  x_expr_ = NULL;
1382  x_pval_ = {};
1383  rvp_ = NULL;
1384  cross_action_ = NULL;
1385  vector_copy_ = false;
1386  family_on_ = false;
1387  family_label_ = NULL;
1388  family_cnt_ = 0;
1389  current_polyline_ = NULL;
1390  label_fixtype_ = 2;
1391  label_scale_ = 1.;
1392  label_x_align_ = 0;
1393  label_y_align_ = 0;
1394  label_x_ = 0;
1395  label_y_ = 1;
1396  label_n_ = 0;
1397  picker();
1398  picker()->bind_select((OcHandler*) NULL);
1399  MenuItem* mi = picker()->add_radio_menu("Crosshair", (OcHandler*) NULL, CROSSHAIR);
1400  mi->state()->set(TelltaleState::is_chosen, true);
1401  tool(CROSSHAIR);
1402  picker()->add_menu("Plot what?", new ActionCallback(Graph)(this, &Graph::choose_sym));
1403  picker()->add_radio_menu("Pick Vector", (OcHandler*) NULL, PICK);
1404  picker()->add_radio_menu("Color/Brush", new ActionCallback(Graph)(this, &Graph::change_prop));
1405 #if 1
1406  WidgetKit& wk = *WidgetKit::instance();
1407  Menu* m = wk.pullright();
1408  picker()->add_menu("View Axis", new ActionCallback(Graph)(this, &Graph::view_axis), m);
1409  picker()->add_menu("New Axis", new ActionCallback(Graph)(this, &Graph::new_axis), m);
1410  picker()->add_menu("View Box", new ActionCallback(Graph)(this, &Graph::view_box), m);
1411  picker()->add_menu("Erase Axis", new ActionCallback(Graph)(this, &Graph::erase_axis), m);
1412  mi = K::menu_item("Axis Type");
1413  mi->menu(m);
1414  picker()->add_menu(mi);
1415 #else
1416  picker()->add_menu("New Axis", new ActionCallback(Graph)(this, &Graph::new_axis));
1417 #endif
1418  mi = WidgetKit::instance()->check_menu_item("Keep Lines");
1419  mi->action(new ActionCallback(Graph)(this, &Graph::keep_lines_toggle));
1420  keep_lines_toggle_ = mi->state();
1421  keep_lines_toggle_->ref();
1422  picker()->add_menu("Keep Lines", mi);
1423  picker()->add_menu("Family Label?",
1424  new ActionCallback(Graph)(this, &Graph::family_label_chooser));
1425  picker()->add_menu("Erase", new ActionCallback(Graph)(this, &Graph::erase_lines));
1426  picker()->add_radio_menu("Move Text", (OcHandler*) NULL, Scene::MOVE);
1427  picker()->add_radio_menu("Change Text", (OcHandler*) NULL, Graph::CHANGELABEL);
1428  picker()->add_radio_menu("Delete", (OcHandler*) NULL, Scene::DELETE);
1429  sc_ = NULL;
1430  if (!colors) {
1431  colors = new ColorPalette();
1432  }
1433  if (!brushes) {
1434  brushes = new BrushPalette();
1435  }
1436  color_ = NULL;
1437  color(1);
1438  brush_ = NULL;
1439  brush(1);
1440  x_ = new DataVec(200);
1441  x_->ref();
1442  extension_flushed_ = true;
1443  symlist_ = NULL;
1444  if (b) {
1445  XYView* v = new XYView((Scene*) this, XSCENE, YSCENE);
1446  Window* w = new ViewWindow(v, "Graph");
1447  w->map();
1448  }
1449  long i = 3;
1450  if (WidgetKit::instance()->style()->find_attribute("graph_axis_default", i)) {
1451  switch (i) {
1452  case 0:
1453  view_axis();
1454  break;
1455  case 2:
1456  view_box();
1457  break;
1458  }
1459  }
1460 }
1461 
1462 Graph::~Graph() {
1463  // printf("~Graph\n");
1464  for (auto& item: line_list_) {
1465  Resource::unref(item);
1466  }
1476  if (cross_action_) {
1477  delete cross_action_;
1478  }
1479 }
1480 
1481 void Graph::name(char* s) {
1482  var_name_ = s;
1483 }
1484 
1485 void Graph::help() {
1486  switch (tool()) {
1487  case CROSSHAIR:
1488  Oc::help(Graph_Crosshair_);
1489  break;
1490  case CHANGELABEL:
1491  Oc::help(Graph_Change_label_);
1492  break;
1493  default:
1494  Scene::help();
1495  break;
1496  }
1497 }
1498 
1499 void Graph::delete_label(GLabel* glab) {
1500  GraphLine* glin = nullptr;
1501  auto it = std::find_if(line_list_.begin(), line_list_.end(), [&](const auto& e) {
1502  return e->label() == glab;
1503  });
1504  if (it != line_list_.end()) {
1505  glin = *it;
1506  line_list_.erase(it);
1507  glin->unref();
1508  GlyphIndex index = glyph_index(glin);
1509  remove(index);
1510  }
1511  if (!glin) { // but possibly a vector line
1512  for (GlyphIndex index = 0; index < count(); ++index) {
1513  GraphItem* gi = (GraphItem*) component(index);
1514  if (gi->is_polyline()) {
1515  GPolyLine* gpl = (GPolyLine*) gi->body();
1516  if (gpl->label() == glab) {
1517  remove(index);
1518  break;
1519  }
1520  }
1521  }
1522  }
1523  GlyphIndex index = glyph_index(glab);
1524  remove(index);
1525 }
1526 
1527 GLabel* Graph::new_proto_label() const {
1529 }
1530 
1531 bool Graph::change_label(GLabel* glab, const char* text, GLabel* gl) {
1532  if (strcmp(glab->text(), text)) {
1533  for (auto& line: line_list_) {
1534  if (line->label() == glab) {
1535  if (!line->change_expr(text, &symlist_)) {
1536  return false;
1537  }
1538  }
1539  }
1540  glab->text(text);
1541  }
1542  GlyphIndex i = glyph_index(glab);
1543  if (glab->fixtype() != gl->fixtype()) {
1544  if (gl->fixed()) {
1545  glab->fixed(gl->scale());
1547  } else {
1548  glab->vfixed(gl->scale());
1550  }
1551  }
1552  change(i);
1553  return true;
1554 }
1555 
1556 void Graph::change_label_color(GLabel* glab) {
1557  glab->color(color());
1558  damage(glyph_index(glab));
1559  if (glab->labeled_line()) {
1560  glab->labeled_line()->brush(brush());
1561  damage(glyph_index(glab->labeled_line()));
1562  }
1563 }
1564 
1565 void Graph::change_line_color(GPolyLine* glin) {
1566  glin->color(color());
1567  glin->brush(brush());
1568  damage(glyph_index(glin));
1569  if (glin->label()) {
1570  damage(glyph_index(glin->label()));
1571  }
1572 }
1573 
1574 GlyphIndex Graph::glyph_index(const Glyph* gl) {
1575  GlyphIndex cnt = count();
1576  for (GlyphIndex i = 0; i < cnt; ++i) {
1577  Glyph* g = ((GraphItem*) component(i))->body();
1578  if (g == gl) {
1579  return i;
1580  }
1581  }
1582  return -1;
1583 }
1584 
1585 std::ostream* Graph::ascii_;
1587 
1588 void Graph::ascii(std::ostream* o) {
1589  ascii_ = o;
1590 }
1591 std::ostream* Graph::ascii() {
1592  return ascii_;
1593 }
1594 
1595 void Graph::draw(Canvas* c, const Allocation& a) const {
1596  // if (!extension_flushed_) {
1597  Scene::draw(c, a);
1598  //}
1599  if (extension_flushed_) {
1600  for (auto& item: line_list_) {
1601  item->extension()->draw(c, a);
1602  }
1603  }
1604  if (ascii_) {
1605  ascii_save(*ascii_);
1606  }
1607 }
1608 
1609 void Graph::ascii_save(std::ostream& o) const {
1610  long line, lcnt = line_list_.size();
1611  int i, dcnt;
1612  if (lcnt == 0 || !x_ || family_label_) {
1613  // tries to print in matrix form is labels and each line the same
1614  // size.
1615  o << "PolyLines" << std::endl;
1616  if (x_expr_) {
1617  o << "x expression: " << x_expr_->name;
1618  }
1619  if (lcnt) {
1620  o << lcnt << " addvar/addexpr lines:";
1621  for (const auto& line: line_list_) {
1622  o << " " << line->name();
1623  }
1624  o << std::endl;
1625  }
1626 
1627 
1628  lcnt = count();
1629  // check to see if all y_data has same count and a label.
1630  // If so print as matrix. (Assumption that all x_data same is
1631  // dangerous.)
1632  bool matrix_form = true;
1633  int col = 0;
1634  int xcnt = 0;
1635  const DataVec* xvec = NULL;
1636  for (i = 0; i < lcnt; ++i) {
1637  GraphItem* gi = (GraphItem*) component(i);
1638  if (gi->is_polyline()) {
1639  GPolyLine* gpl = (GPolyLine*) gi->body();
1640  if (gpl->label() && (xcnt == 0 || gpl->x_data()->count() == xcnt)) {
1641  xcnt = gpl->x_data()->count();
1642  xvec = gpl->x_data();
1643  if (gpl->y_data()->count() == xcnt) {
1644  ++col;
1645  }
1646  } else {
1647  matrix_form = false;
1648  break;
1649  }
1650  }
1651  }
1652  if (matrix_form) {
1653  if (x_expr_) {
1654  o << x_expr_->name;
1655  } else {
1656  o << "x";
1657  }
1658  for (i = 0; i < lcnt; ++i) {
1659  GraphItem* gi = (GraphItem*) component(i);
1660  if (gi->is_polyline()) {
1661  GPolyLine* gpl = (GPolyLine*) gi->body();
1662  if (gpl->y_data()->count() == xcnt) {
1663  o << " " << gpl->label()->text();
1664  }
1665  }
1666  }
1667  o << std::endl;
1668  o << xcnt << " rows, " << col + 1 << " columns" << std::endl;
1669  int j;
1670  for (j = 0; j < xcnt; ++j) {
1671  o << xvec->get_val(j);
1672  for (i = 0; i < lcnt; ++i) {
1673  GraphItem* gi = (GraphItem*) component(i);
1674  if (gi->is_polyline()) {
1675  GPolyLine* gpl = (GPolyLine*) gi->body();
1676  if (gpl->y_data()->count() == xcnt) {
1677  o << "\t" << gpl->y(j);
1678  }
1679  }
1680  }
1681  o << std::endl;
1682  }
1683  }
1684  if (!matrix_form) {
1685  o << "Line Manifest:" << std::endl;
1686  for (i = 0; i < lcnt; ++i) {
1687  GraphItem* gi = (GraphItem*) component(i);
1688  if (gi->is_polyline()) {
1689  GPolyLine* gpl = (GPolyLine*) gi->body();
1690  int j, jcnt;
1691  jcnt = gpl->y_data()->count();
1692  if (jcnt && family_label_ && gpl->label()) {
1693  o << jcnt << " " << family_label_->text() << "=" << gpl->label()->text()
1694  << std::endl;
1695  } else {
1696  o << jcnt << std::endl;
1697  }
1698  }
1699  }
1700  o << "End of Line Manifest" << std::endl;
1701  for (i = 0; i < lcnt; ++i) {
1702  GraphItem* gi = (GraphItem*) component(i);
1703  if (gi->is_polyline()) {
1704  GPolyLine* gpl = (GPolyLine*) gi->body();
1705  int j, jcnt;
1706  jcnt = gpl->y_data()->count();
1707  if (jcnt && family_label_ && gpl->label()) {
1708  o << jcnt << " " << family_label_->text() << "=" << gpl->label()->text()
1709  << std::endl;
1710  } else {
1711  o << jcnt << std::endl;
1712  }
1713  for (j = 0; j < jcnt; ++j) {
1714  o << gpl->x(j) << "\t" << gpl->y(j) << "\n";
1715  }
1716  }
1717  }
1718  }
1719  return;
1720  }
1721  o << "Graph addvar/addexpr lines" << std::endl;
1722  o << lcnt << " " << x_->count() << std::endl;
1723  if (x_expr_) {
1724  o << x_expr_->name;
1725  } else {
1726  o << "x";
1727  }
1728  for (const auto& item: line_list_) {
1729  o << " " << item->name();
1730  }
1731  o << std::endl;
1732  dcnt = x_->count();
1733  for (i = 0; i < dcnt; ++i) {
1734  o << x_->get_val(i);
1735  for (const auto& item: line_list_) {
1736  o << "\t" << item->y(i);
1737  }
1738  o << std::endl;
1739  }
1740  // print the remaining unlabeled polylines. i.e. saved with KeepLines
1741  lcnt = count();
1742  int n = 0;
1743  for (i = 0; i < lcnt; ++i) {
1744  GraphItem* gi = (GraphItem*) component(i);
1745  if (gi->is_polyline()) {
1746  GPolyLine* gpl = (GPolyLine*) gi->body();
1747  if (!gpl->label()) {
1748  ++n;
1749  }
1750  }
1751  }
1752  o << n << " unlabeled lines" << std::endl;
1753  for (i = 0; i < lcnt; ++i) {
1754  GraphItem* gi = (GraphItem*) component(i);
1755  if (gi->is_polyline()) {
1756  GPolyLine* gpl = (GPolyLine*) gi->body();
1757  if (!gpl->label()) {
1758  int n = gpl->x_data()->count();
1759  o << n << std::endl;
1760  int j;
1761  for (j = 0; j < n; ++j) {
1762  o << gpl->x(j) << "\t" << gpl->y(j) << std::endl;
1763  }
1764  }
1765  }
1766  }
1767 }
1768 
1769 void Graph::pick(Canvas* c, const Allocation& a, int depth, Hit& h) {
1770 #if 1
1771  Scene::pick(c, a, depth, h);
1772  if (tool() == CHANGELABEL && !menu_picked() && h.event() && h.event()->type() == Event::down &&
1773  h.event()->pointer_button() == Event::left && h.count() < 2) {
1774  h.target(depth, this, 0, new NewLabelHandler(this, h.left(), h.bottom()));
1775  }
1776 #else
1777  if (h.event() && h.event()->type() == Event::down) {
1778  if (h.event()->pointer_button() == Event::right) {
1779  h.target(depth, this, 0, new RubberRect(c, new NewView(this)));
1780  } else if (h.event()->pointer_button() == Event::middle) {
1781  choose_sym(c->window());
1782  } else {
1783  Scene::pick(c, a, depth, h);
1784  }
1785  } else {
1786  Scene::pick(c, a, depth, h);
1787  }
1788 #endif
1789 }
1790 
1791 void Graph::new_size(Coord x1, Coord y1, Coord x2, Coord y2) {
1792  Scene::new_size(x1, y1, x2, y2);
1793  if (label_fixtype_ == 1) {
1794  label_x_ = x2 - .2 * (x2 - x1);
1795  label_y_ = y2 - .1 * (y2 - y1);
1796  } else if (label_fixtype_ == 2) {
1797  label_x_ = .8;
1798  label_y_ = .9;
1799  }
1800  label_n_ = 0;
1801 }
1802 
1803 void Graph::wholeplot(Coord& l, Coord& b, Coord& r, Coord& t) const {
1804  GlyphIndex i, cnt;
1805  GraphLine* gl;
1806  l = b = 1e9;
1807  r = t = -1e9;
1808  cnt = count();
1809  for (i = 0; i < cnt; ++i) {
1810  GraphItem* gi = (GraphItem*) component(i);
1811  if (gi->is_polyline()) {
1812  GPolyLine* gpl = (GPolyLine*) gi->body();
1813  if (gpl->x_data()->count() > 1) {
1814  l = std::min(l, gpl->x_data()->min());
1815  b = std::min(b, gpl->y_data()->min());
1816  r = std::max(r, gpl->x_data()->max());
1817  t = std::max(t, gpl->y_data()->max());
1818  }
1819  }
1820  if (gi->is_mark()) {
1821  Coord x, y;
1822  location(i, x, y);
1823  l = std::min(l, x);
1824  b = std::min(b, y);
1825  r = std::max(r, x);
1826  t = std::max(t, y);
1827  }
1828  }
1829  if (l >= r || b >= t) {
1830  Coord x1, y1, x2, y2;
1831  Scene::wholeplot(x1, y1, x2, y2);
1832  if (l >= r) {
1833  l = x1;
1834  r = x2;
1835  }
1836  if (b >= t) {
1837  b = y1;
1838  t = y2;
1839  }
1840  }
1841  if (t > 1e30) {
1842  t = 1e30;
1843  }
1844  if (b < -1e30) {
1845  t = -1e30;
1846  }
1847  return;
1848 }
1849 
1850 void Graph::axis(DimensionName d,
1851  float x1,
1852  float x2,
1853  float pos,
1854  int ntic,
1855  int nminor,
1856  int invert,
1857  bool number) {
1858  // printf("%d %g %g %g %d %d %d %d %g\n", d, x1, x2, pos, ntic, nminor, invert, number);
1859  Axis* a;
1860  if (x2 < x1) {
1861  a = new Axis(this, d);
1862  } else if (ntic < 0) {
1863  a = new Axis(this, d, x1, x2);
1864  } else {
1865  a = new Axis(this, d, x1, x2, pos, ntic, nminor, invert, number);
1866  }
1867  append_fixed(new GraphAxisItem(a));
1868 }
1869 void Graph::color(int i) {
1870  const Color* color = colors->color(i);
1873  color_ = color;
1874 }
1875 void Graph::brush(int i) {
1876  const Brush* b = brushes->brush(i);
1877  Resource::ref(b);
1879  brush_ = b;
1880 }
1881 GraphLine* Graph::add_var(const char* expr,
1882  const Color* color,
1883  const Brush* brush,
1884  bool usepointer,
1885  int fixtype,
1887  const char* lab,
1888  Object* obj) {
1889  GraphLine* gl = new GraphLine(expr, x_, &symlist_, color, brush, usepointer, pd, obj);
1890  GLabel* glab;
1891  if (lab) {
1892  glab = label(lab, fixtype);
1893  } else {
1894  glab = label(expr, fixtype);
1895  }
1896  GlyphIndex i = glyph_index(glab);
1897  ((GraphItem*) component(i))->save(false);
1898  glab->color(color);
1899  gl->label(glab);
1900  line_list_.push_back(gl);
1901  gl->ref();
1902  Scene::append(new GPolyLineItem(gl));
1903  return gl;
1904 }
1905 
1906 void Graph::add_polyline(GPolyLine* gp) {
1907  Scene::append(new GPolyLineItem(gp));
1908 }
1909 
1911  Scene::append(new VectorLineItem(gv));
1912 }
1913 
1914 void Graph::x_expr(const char* expr, bool usepointer) {
1915  Oc oc;
1916  x_expr_ = oc.parseExpr(expr, &symlist_);
1917  if (!x_expr_) {
1918  hoc_execerror(expr, "not an expression");
1919  }
1920  if (usepointer) {
1921  x_pval_ = hoc_val_handle(expr);
1922  if (!x_pval_) {
1923  hoc_execerror(expr, "is invalid left hand side of assignment statement");
1924  }
1925  } else {
1926  x_pval_ = {};
1927  }
1928 }
1929 
1930 extern int hoc_execerror_messages;
1931 void Graph::begin() {
1932  if (keep_lines_toggle_->test(TelltaleState::is_chosen)) {
1933  keep_lines();
1934  family_value();
1935  }
1936  int hem = hoc_execerror_messages;
1937  for (auto& gl: line_list_) {
1938  gl->erase();
1939  if (family_on_) {
1940  ((GPolyLine*) gl)->color(color());
1941  ((GPolyLine*) gl)->brush(brush());
1942  }
1943  hoc_execerror_messages = false;
1944  if (gl->valid(true) == false) {
1945  printf("Graph:: presently invalid expression: %s\n", gl->name());
1946  }
1947  }
1948  hoc_execerror_messages = hem;
1949  x_->erase();
1950  extension_start();
1951 }
1952 void Graph::plot(float x) {
1953  if (extension_flushed_) {
1955  }
1956  if (x_expr_) {
1957  if (x_pval_) {
1958  x_->add(float(*x_pval_));
1959  } else {
1960  Oc oc;
1961  x_->add(oc.runExpr(x_expr_));
1962  }
1963  } else {
1964  x_->add(x);
1965  }
1966  for (auto& item: line_list_) {
1967  item->plot();
1968  }
1969 }
1970 void Graph::begin_line(const char* s) {
1972 }
1973 void Graph::begin_line(const Color* c, const Brush* b, const char* s) {
1975  current_polyline_ = new GPolyLine(new DataVec(2), c, b);
1977  if (s && s[0]) {
1978  GLabel* glab = label(s);
1979  current_polyline_->label(glab);
1980  ((GraphItem*) component(glyph_index(glab)))->save(false);
1981  }
1983 }
1984 void Graph::line(Coord x, Coord y) {
1985  if (!current_polyline_) {
1986  begin_line();
1987  }
1988  current_polyline_->plot(x, y);
1989 }
1990 void Graph::flush() {
1991  extension_start();
1992  long i, cnt = count();
1993  for (i = 0; i < cnt; ++i) {
1994  modified(i);
1995  }
1996  // damage_all();//too conservative. plots everything every time
1997 }
1998 void Graph::fast_flush() {
1999  for (auto& item: line_list_) {
2000  item->extension()->damage(this);
2001  }
2002  extension_flushed_ = true;
2003 }
2004 
2005 void Graph::extension_start() {
2006  x_->running_start();
2007  for (auto& item: line_list_) {
2008  item->extension_start();
2009  }
2010  extension_flushed_ = false;
2011 }
2013  x_->running_start();
2014  for (auto& item: line_list_) {
2015  item->extension_continue();
2016  }
2017  extension_flushed_ = false;
2018 }
2019 
2020 void Graph::mark(Coord x, Coord y, char style, float size, const Color* c, const Brush* b) {
2021  HocMark* m = HocMark::instance(style, size, c, b);
2022  append_fixed(new GraphMarkItem(m));
2023  move(Scene::count() - 1, x, y);
2024 }
2025 
2026 void Graph::set_cross_action(const char* cp, Object* pyact, bool vector_copy) {
2027  if (cross_action_) {
2028  delete cross_action_;
2029  cross_action_ = NULL;
2030  }
2031  if (cp && strlen(cp) > 0) {
2032  cross_action_ = new HocCommand(cp);
2033  } else if (pyact) {
2034  cross_action_ = new HocCommand(pyact);
2035  }
2036  vector_copy_ = vector_copy;
2037 }
2038 
2039 void Graph::cross_action(char c, GPolyLine* gpl, int i) {
2040  if (cross_action_) {
2041  char buf[256];
2042  if (vector_copy_) {
2043  Object* op1 = *(gpl->x_data()->new_vect());
2044  Object* op2 = *(gpl->y_data()->new_vect(gpl->label()));
2045  hoc_pushx(double(i));
2046  hoc_pushx(double(c));
2047  hoc_push_object(op1);
2048  hoc_push_object(op2);
2050  hoc_obj_unref(op1);
2051  hoc_obj_unref(op2);
2052  } else {
2053  hoc_pushx(double(gpl->x_data()->get_val(i)));
2054  hoc_pushx(double(gpl->y_data()->get_val(i)));
2055  hoc_pushx(double(c));
2057  }
2058  } else {
2059  printf("{x=%g y=%g}\n", gpl->x(i), gpl->y(i));
2060  }
2061 }
2062 
2063 void Graph::cross_action(char c, Coord x, Coord y) {
2064  if (cross_action_) {
2065  char buf[256];
2066  if (vector_copy_) {
2067  } else {
2068  Sprintf(buf, "%s(%g, %g, %d)", cross_action_->name(), x, y, c);
2070  }
2071  } else {
2072  printf("{x=%g y=%g}\n", x, y);
2073  }
2074 }
2075 void Graph::erase() {
2076  for (auto& item: line_list_) {
2077  item->erase();
2078  }
2079  damage_all();
2080 }
2081 
2082 void Graph::erase_all() {
2083  for (int i = count() - 1; i >= 0; --i) {
2084  remove(i);
2085  }
2086  for (auto& item: line_list_) {
2087  Resource::unref(item);
2088  }
2089  line_list_.clear();
2090  line_list_.shrink_to_fit();
2091  label_n_ = 0;
2092 }
2093 void Graph::family_value() {
2094  if (family_label_) {
2095  char buf[256];
2096  Sprintf(buf, "hoc_ac_ = %s\n", family_label_->text());
2097  Oc oc;
2098  oc.run(buf);
2099  family_val_ = hoc_ac_;
2100  }
2101 }
2102 
2103 void Graph::keep_lines_toggle() {
2104  if (Oc::helpmode()) {
2105  Oc::help(Graph_keep_lines_toggle_);
2106  keep_lines_toggle_->set(TelltaleState::is_chosen,
2107  !keep_lines_toggle_->test(TelltaleState::is_chosen));
2108  return;
2109  }
2110  family_value();
2111  if (!keep_lines_toggle_->test(TelltaleState::is_chosen)) { // keep the ones already there
2112  keep_lines();
2113  }
2114 }
2115 
2116 void Graph::keep_lines() {
2117  char buf[256];
2118  int fi;
2119  Coord x, y;
2120  GLabel* f = family_label_;
2121  if (f) {
2122  fi = glyph_index(f);
2123  location(fi, x, y);
2124  Sprintf(buf, "%g", family_val_);
2125  }
2126  long lcnt = count();
2127  for (long i = lcnt - 1; i >= 0; --i) {
2128  GraphItem* gi = (GraphItem*) component(i);
2129  if (gi->is_polyline()) {
2130  GPolyLine* gpl = (GPolyLine*) gi->body();
2131  if (gpl->keepable() && gpl->y_data()->count() > 1) {
2132  GPolyLine* g2 = new GPolyLine(new DataVec(gpl->x_data()),
2133  new DataVec(gpl->y_data()),
2134  gpl->color(),
2135  gpl->brush());
2136 
2137  if (f) {
2138  GLabel* gl =
2139  label(x, y, buf, f->fixtype(), f->scale(), 0, family_cnt_, gpl->color());
2140  family_cnt_++;
2141  g2->label(gl);
2142  ((GraphItem*) component(glyph_index(gl)))->save(false);
2143  }
2144  Scene::insert(i, new GPolyLineItem(g2));
2145  modified(i);
2146  gpl->erase();
2147  }
2148  }
2149  }
2150  flush();
2151 }
2152 
2153 void Graph::family(bool i) {
2154  if (i) {
2155  erase_lines();
2156  family_on_ = true;
2157  keep_lines_toggle_->set(TelltaleState::is_chosen, true);
2158  } else {
2159  family_on_ = false;
2160  keep_lines_toggle_->set(TelltaleState::is_chosen, false);
2161  for (auto& gl: line_list_) {
2162  gl->color(gl->save_color());
2163  gl->brush(gl->save_brush());
2164  }
2165  }
2166 }
2167 
2168 void Graph::family(const char* s) {
2169  if (family_label_) {
2170  if (s && s[1]) {
2171  family_label_->text(s);
2173  } else {
2175  family_label_->unref();
2176  family_label_ = NULL;
2177  }
2178  } else if (s && s[1]) {
2179  family_label_ = label(.95, .95, s, 2, 1, 1, 0, color_);
2180  family_label_->ref();
2182  }
2183 }
2184 
2185 void Graph::erase_axis() {
2186  if (Oc::helpmode()) {
2187  Oc::help(Graph_erase_axis_);
2188  return;
2189  }
2190  GlyphIndex i, cnt;
2191  cnt = count();
2192  for (i = cnt - 1; i >= 0; --i) {
2194  }
2196  damage_all();
2197 }
2198 
2199 void Graph::new_axis() {
2200  if (Oc::helpmode()) {
2201  Oc::help(Graph_new_axis_);
2202  return;
2203  }
2205  erase_axis();
2206  Coord x1{}, x2{}, y1{}, y2{};
2207  if (v) {
2208  v->zin(x1, y1, x2, y2);
2209  }
2210  Axis* a = new Axis(this, Dimension_X, x1, x2);
2211  append_fixed(new GraphAxisItem(a));
2212  a = new Axis(this, Dimension_Y, y1, y2);
2213  append_fixed(new GraphAxisItem(a));
2214 }
2215 
2216 void Graph::view_axis() {
2217  if (Oc::helpmode()) {
2218  Oc::help(Graph_view_axis_);
2219  return;
2220  }
2221  erase_axis();
2223  damage_all();
2224 }
2225 
2226 void Graph::view_box() {
2227  if (Oc::helpmode()) {
2228  Oc::help(Graph_view_box_);
2229  return;
2230  }
2231  erase_axis();
2233  damage_all();
2234 }
2235 
2236 #if 0
2237 void Graph::spec_axis() {
2239  Coord x1, x2, y1, y2;
2240  v->zin(x1, y1, x2, y2);
2241  bool bx = var_pair_chooser("X-Axis", x1, x2);
2242  bool by = var_pair_chooser("Y-Axis", y1, y2);
2243  v->size(x1, y1, x2, y2);
2244  erase_axis();
2245  if (bx) {
2246  Axis* a = new Axis(this, Dimension_X, x1, x2);
2247  append_fixed(new GraphAxisItem(a));
2248  }
2249  if (by) {
2250  Axis* a = new Axis(this, Dimension_Y, y1, y2);
2251  append_fixed(new GraphAxisItem(a));
2252  }
2253 }
2254 #endif
2255 
2256 void Graph::erase_lines() {
2257  if (Oc::helpmode()) {
2258  Oc::help(Graph_erase_lines_);
2259  return;
2260  }
2261  // when labels are attached to lines some get erased and some do not
2262  // the issue invalid pointers is also a problem (delete when removed
2263  // from scene which screws up the GlyphIndex iterators. For this reason
2264  // we just unshow all gpolyline labels,
2265  // then show the labels for line list and GraphVector then
2266  // remove all unshow.
2267  GlyphIndex i, cnt = count();
2268  for (i = 0; i < cnt; ++i) {
2269  GraphItem* gi = (GraphItem*) component(i);
2270  if (gi->is_polyline() && !gi->is_graphVector()) {
2271  GLabel* gl = ((GPolyLine*) (gi->body()))->label();
2272  if (gl) {
2273  gl->erase_flag(true);
2274  }
2275  }
2276  }
2277  for (auto& gl: line_list_) {
2278  gl->label()->erase_flag(false);
2279  }
2280  cnt = count();
2281  for (i = cnt - 1; i >= 0; --i) {
2283  }
2284  for (auto& gl: line_list_) {
2285  Scene::append(new GPolyLineItem(gl));
2286  }
2287  erase();
2288  if (family_label_) {
2289  family_cnt_ = 0;
2290  }
2291 }
2292 GLabel* Graph::label(float x,
2293  float y,
2294  const char* s,
2295  int fixtype,
2296  float scale,
2297  float x_align,
2298  float y_align,
2299  const Color* color) {
2300  GLabel* l = new GLabel(s, color, fixtype, scale, x_align, y_align);
2301  if (fixtype == 1) {
2302  append_fixed(new GraphLabelItem(l));
2303  } else if (fixtype == 2) {
2304  append_viewfixed(new GraphLabelItem(l));
2305  } else if (fixtype == 0) {
2306  append(new GraphLabelItem(l));
2307  }
2308  move(count() - 1, x, y);
2309  return l;
2310 }
2311 GLabel* Graph::label(float x, float y, const char* s, float n, int fixtype) {
2312  label_x_ = x;
2313  label_y_ = y;
2314  label_n_ = n;
2315  if (!s) {
2316  return NULL;
2317  }
2318  return label(x,
2319  y,
2320  s,
2321  (fixtype != -1) ? fixtype : label_fixtype_,
2322  label_scale_,
2325  color_);
2326 }
2327 GLabel* Graph::label(const char* s, int fixtype) {
2328  label_n_ += 1.;
2329  return label(label_x_, label_y_, s, label_n_, fixtype);
2330 }
2331 void Graph::fixed(float scale) {
2332  label_fixtype_ = 1;
2333  label_scale_ = scale;
2334 }
2335 void Graph::vfixed(float scale) {
2336  label_fixtype_ = 2;
2337  label_scale_ = scale;
2338 }
2339 void Graph::relative(float fraction) {
2340  label_fixtype_ = 0;
2341  label_scale_ = fraction;
2342 }
2343 void Graph::align(float x, float y) {
2344  label_x_align_ = x;
2345  label_y_align_ = y;
2346 }
2347 
2349  if (rvp_) {
2350  rvp_->unref();
2351  }
2352  rvp_ = rvp;
2353  Resource::ref(rvp);
2354 }
2355 
2356 void Graph::save_phase1(std::ostream& o) {
2357  o << "{" << std::endl;
2358  save_class(o, "Graph");
2359 }
2360 
2361 static Graph* current_save_graph;
2362 
2363 void Graph::save_phase2(std::ostream& o) {
2364  char buf[256];
2365  if (family_label_) {
2366  o << "save_window_.family(\"" << family_label_->text() << "\")" << std::endl;
2367  }
2368  if (!var_name_.empty()) {
2369  if (var_name_.back() == '.') {
2370  Sprintf(buf, "%sappend(save_window_)", var_name_.c_str());
2371  } else {
2372  Sprintf(buf, "%s = save_window_", var_name_.c_str());
2373  }
2374  o << buf << std::endl;
2375  o << "save_window_.save_name(\"" << var_name_ << "\")" << std::endl;
2376  }
2377  if (x_expr_) {
2378  o << "save_window_.xexpr(\"" << x_expr_->name << "\", " << (x_pval_ ? 1 : 0) << ")"
2379  << std::endl;
2380  }
2381  long cnt = count();
2382  current_save_graph = this;
2383  for (long i = 0; i < cnt; ++i) {
2384  GraphItem* g = (GraphItem*) component(i);
2385  Coord x, y;
2386  location(i, x, y);
2387  if (g->save()) {
2388  g->save(o, x, y);
2389  }
2390  }
2391  o << "}" << std::endl;
2392 }
2393 
2394 
2396  // it is a range variable plot where we get a different result
2397  return false;
2398 }
2399 
2400 void Graph::choose_sym() {
2401  Oc oc;
2402  if (Oc::helpmode()) {
2403  if (rvp_) {
2404  Oc::help(Graph_choose_rvp_);
2405  } else {
2406  Oc::help(Graph_choose_sym_);
2407  }
2408  }
2409  if (rvp_ && rvp_->choose_sym((Graph*) this)) {
2410  return;
2411  }
2412  if (!sc_) {
2413  Style* style = new Style(Session::instance()->style());
2414  style->attribute("caption", "Variable to graph");
2415  sc_ = new SymChooser(NULL, WidgetKit::instance(), style);
2416  sc_->ref();
2417  }
2418  Window* w = NULL;
2420  if (!v || v->scene() != (Scene*) this || !v->canvas() || !v->canvas()->window()) {
2421  if (view_count() > 0 && sceneview(0)->canvas() && sceneview(0)->canvas()->window()) {
2422  w = sceneview(0)->canvas()->window();
2423  }
2424  } else {
2425  w = v->canvas()->window();
2426  }
2427  while ((w && sc_->post_for_aligned(w, .5, 1.)) || (!w && sc_->post_at(300, 300))) {
2428  char buf[256];
2429  double* pd = sc_->selected_var();
2431 
2432  if (sc_->selected_vector_count()) {
2433  Sprintf(buf, "%s", sc_->selected().c_str());
2434  GraphVector* gv = new GraphVector(buf);
2435  gv->color(color());
2436  gv->brush(brush());
2437  int n = sc_->selected_vector_count();
2438  for (int i = 0; i < n; ++i) {
2439  gv->add(double(i), pd_handle.next_array_element(i));
2440  }
2441  GLabel* glab = label(gv->name());
2442  ((GraphItem*) component(glyph_index(glab)))->save(false);
2443  gv->label(glab);
2444  append(new VectorLineItem(gv));
2445  flush();
2446  break;
2447  } else if (pd) {
2448  add_var(sc_->selected().c_str(), color(), brush(), 1, 2);
2449  break;
2450  } else {
2451  auto s = sc_->selected();
2452  // above required due to bug in mswindows version in which
2453  // sc_->selected seems volatile under some kinds of hoc
2454  // executions.
2455  Sprintf(buf, "hoc_ac_ = %s\n", s.c_str());
2456  if (oc.run(buf) == 0) {
2457  add_var(s.c_str(), color(), brush(), 0, 2);
2458  break;
2459  }
2460  hoc_warning(s.c_str(), "is not an expression.");
2461  }
2462  }
2463  // sc_->unref();
2464 }
2465 
2467  Oc oc;
2468  if (Oc::helpmode()) {
2469  Oc::help(Graph_choose_family_label_);
2470  }
2471  if (!fsc_) {
2472  Style* style = new Style(Session::instance()->style());
2473  style->attribute("caption", "Family label variable");
2474  fsc_ = new SymChooser(NULL, WidgetKit::instance(), style);
2475  fsc_->ref();
2476  }
2477  while (fsc_->post_for_aligned(XYView::current_pick_view()->canvas()->window(), .5, 1.)) {
2478  auto buf = std::string("hoc_ac_ = ") + fsc_->selected() + "\n";
2479  if (oc.run(buf) == 0) {
2480  family(fsc_->selected().c_str());
2481  break;
2482  }
2483  hoc_warning(sc_->selected().c_str(), "is not an expression.");
2484  }
2485 }
2486 
2487 // GraphLine and GPolyLine
2488 GraphLine::GraphLine(const char* expr,
2489  DataVec* x,
2490  Symlist** symlist,
2491  const Color* c,
2492  const Brush* b,
2493  bool usepointer,
2495  Object* obj)
2496  : GPolyLine(x, c, b) {
2497  Oc oc;
2498  valid_ = true;
2499  obj_ = NULL;
2500  simgraph_x_sav_ = NULL;
2501  if (usepointer) {
2502  if (pd) {
2503  // char buf[256];
2504  // Sprintf(buf, "%s", expr);
2505  // expr_ = oc.parseExpr(buf, symlist);
2506  expr_ = nullptr;
2507  pval_ = pd;
2508  } else {
2509  expr_ = oc.parseExpr(expr, symlist);
2510  pval_ = hoc_val_handle(expr);
2511  if (!pval_) {
2512  hoc_execerror(expr, "is invalid left hand side of assignment statement");
2513  }
2514  }
2516  } else {
2517  if (obj) {
2518  obj_ = obj;
2519  oc.notify_when_freed((void*) obj_, this);
2520  ObjectContext objc(obj_);
2521  expr_ = oc.parseExpr(expr, symlist);
2522  } else {
2523  expr_ = oc.parseExpr(expr, symlist);
2524  }
2525  pval_ = {};
2526  }
2527  if (!pval_ && !expr_) {
2528  hoc_execerror(expr, "not an expression");
2529  }
2530  save_color_ = c;
2531  Resource::ref(c);
2532  save_brush_ = b;
2533  Resource::ref(b);
2534  extension_ = new LineExtension(this);
2535  extension_->ref();
2536  keepable_ = true;
2537 }
2538 
2539 GPolyLine::GPolyLine(DataVec* x, const Color* c, const Brush* b) {
2540  init(x, new DataVec(x->size()), c, b);
2541 }
2542 
2543 GPolyLine::GPolyLine(DataVec* x, DataVec* y, const Color* c, const Brush* b) {
2544  init(x, y, c, b);
2545 }
2546 
2548  init(new DataVec(gp->x_data()), new DataVec(gp->y_data()), gp->color(), gp->brush());
2549 }
2550 
2551 void GPolyLine::init(DataVec* x, DataVec* y, const Color* c, const Brush* b) {
2552  keepable_ = false;
2553  glabel_ = NULL;
2554  x_ = x;
2555  x_->ref();
2556  y_ = y;
2557  y_->ref();
2558  color_ = NULL;
2559  color(c);
2560  brush_ = NULL;
2561  brush(b);
2562  Resource::ref(b);
2563 }
2564 
2565 void GPolyLine::pick_vector() {
2566  Object* op1 = *(x_data()->new_vect());
2567  Object* op2 = *(y_data()->new_vect(label()));
2568  hoc_obj_set(1, op1);
2569  hoc_obj_set(0, op2);
2570  hoc_obj_unref(op1);
2571  hoc_obj_unref(op2);
2572 }
2573 
2574 extern void graphLineRecDeleted(GraphLine*);
2575 
2577  // expr_ deleted when its symlist is deleted
2578  // printf("~GraphLine %s\n", name());
2579  simgraph_activate(false);
2580  graphLineRecDeleted(this);
2582  Oc oc;
2583  if (pval_ || obj_) {
2584  // printf("~graphline notify disconnect\n");
2585  oc.notify_pointer_disconnect(this);
2586  }
2587 }
2588 
2589 void GraphLine::simgraph_activate(bool act_) {
2590  if (act_) {
2591  if (!simgraph_x_sav_) {
2592  simgraph_x_sav_ = x_;
2593  x_ = new DataVec(x_->size());
2594  Resource::ref(x_);
2595  // printf("simgraph activate %s x_->size = %d\n", name(), x_->size());
2596  }
2597  } else {
2598  if (simgraph_x_sav_) {
2600  x_ = simgraph_x_sav_;
2602  // printf("simgraph inactivate %s x_->size = %d\n", name(), x_->size());
2603  }
2604  }
2605 }
2606 
2607 void GraphLine::simgraph_init() {
2608  x_->erase();
2609  erase();
2610 }
2611 
2612 void GraphLine::simgraph_continuous(double tt) {
2613  x_->add(tt);
2614  plot();
2615 }
2616 
2617 void GraphLine::update(Observable*) { // *pval_ has been freed
2618  // printf("GraphLine::update pval_ has been freed\n");
2619  pval_ = {};
2620  if (obj_) {
2621  expr_ = NULL;
2622  }
2623  obj_ = NULL;
2624 }
2625 
2626 bool GraphLine::change_expr(const char* expr, Symlist** symlist) {
2627  Oc oc;
2628  if (pval_ || obj_) {
2629  printf("Can't change.\n");
2630  return false;
2631  }
2632  Symbol* sym = oc.parseExpr(expr, symlist);
2633  if (sym) {
2634  expr_ = sym;
2635  if (pval_) {
2636  // we are no longer interested in updates to pval_
2638  pval_ = {};
2639  }
2640  return true;
2641  } else {
2642  return false;
2643  }
2644 }
2645 
2646 void GPolyLine::label(GLabel* l) {
2647  Resource::ref(l);
2648  if (l && l->gpl_ && l->gpl_->label()) {
2649  l->gpl_->label(NULL);
2650  }
2651  if (glabel_) {
2652  glabel_->gpl_ = NULL;
2653  }
2655  glabel_ = l;
2656  if (glabel_) {
2657  glabel_->color(color());
2658  glabel_->gpl_ = (GPolyLine*) this;
2659  }
2660 }
2661 
2667  label(NULL);
2668 }
2670  GLabel* gl = label();
2671  s->remove(i);
2672  if (gl) {
2673  s->remove(s->glyph_index(gl));
2674  }
2675 }
2676 const char* GraphLine::name() const {
2677  Oc oc;
2678  if (label()) {
2679  return label()->text();
2680  } else if (expr_) {
2681  return oc.name(expr_);
2682  } else {
2683  return "no name";
2684  }
2685 }
2686 
2688  extension_->begin();
2689 }
2690 
2692  extension_->extend();
2693 }
2694 
2695 void GraphLine::save(std::ostream& o) {
2696  char buf[256];
2697  float x, y;
2698  if (!label()) {
2699  return;
2700  }
2701  GlyphIndex i = current_save_graph->glyph_index(label());
2702  current_save_graph->location(i, x, y);
2703  if (pval_) {
2704  Sprintf(buf,
2705  "save_window_.addvar(\"%s\", %d, %d, %g, %g, %d)",
2706  name(),
2707  colors->color(color_),
2708  brushes->brush(brush_),
2709  x,
2710  y,
2711  label()->fixtype());
2712  } else {
2713  // following is not exactly correct if the label or object args were
2714  // used but it is expected that in that case the graph is
2715  // encapsulated in an object and this info is incorrect anyway.
2716  // Can revisit later if this is a problem.
2717  Sprintf(buf,
2718  "save_window_.addexpr(\"%s\", %d, %d, %g, %g, %d)",
2719  name(),
2720  colors->color(color_),
2721  brushes->brush(brush_),
2722  x,
2723  y,
2724  label()->fixtype());
2725  }
2726  o << buf << std::endl;
2727 }
2728 
2729 void GPolyLine::save(std::ostream&) {}
2730 
2731 void GPolyLine::label_loc(Coord& x, Coord& y) const {
2732  if (label()) {
2733  GlyphIndex i = current_save_graph->glyph_index(label());
2734  current_save_graph->location(i, x, y);
2735  } else {
2736  x = 0.;
2737  y = 0.;
2738  }
2739 }
2740 
2741 void GPolyLine::request(Requisition& req) const {
2742  // printf("GPolyLine::request\n");
2743  Coord x, span;
2744  const float eps = 1e-4;
2745  x = x_->min();
2746  span = x_->max() - x + eps;
2747  x = (span > 0) ? x / span : 0;
2748  Requirement rx(span, 0, 0, -x);
2749  x = y_->min();
2750  span = y_->max() - x + eps;
2751  x = (span > 0) ? x / span : 0;
2752  Requirement ry(span, 0, 0, -x);
2753  req.require_x(rx);
2754  req.require_y(ry);
2755 }
2756 void GPolyLine::allocate(Canvas* c, const Allocation& a, Extension& e) {
2757  // printf("GPolyLine::allocate\n");
2758  e.set(c, a);
2759  MyMath::extend(e, brush()->width() / 2 + 1);
2760 }
2761 void GPolyLine::draw(Canvas* c, const Allocation& a) const {
2762  draw_specific(c, a, 0, y_->count());
2763 }
2764 
2765 void GPolyLine::draw_specific(Canvas* c, const Allocation&, int begin, int end) const {
2766  // printf("GPolyLine::draw %d %g %g\n", y_->count(), a.x(), a.y());
2767  int i, cnt = end;
2768  if (cnt - begin < 2) {
2769  return;
2770  }
2771 #if 0
2772  Coord x1, y1, x2, y2;
2773  XYView::current_draw_view()->damage_area(x1, y1, x2, y2);
2774 
2775 #define GPIN(arg) MyMath::inside(x_->get_val(arg), y_->get_val(arg), x1, y1, x2, y2)
2776 
2777  /* this works most of the time in preventing extraneous lines during
2778  very large zoom but can fail */
2779  for (i=begin; i > 0; --i) { // begin plotting outside of damage
2780  if (!GPIN(i)) {
2781  break;
2782  }
2783  }
2784  for (; i < cnt; ++i) {
2785  if (GPIN(i)) {
2786  if (i > 0) {
2787  --i;
2788  }
2789  break;
2790  }
2791  }
2792  int j;
2793  for (j=cnt-1 ; i < j; --j) {
2794  if (GPIN(j)) {
2795  if (j < cnt-1) {
2796  ++j;
2797  }
2798  break;
2799  }
2800  }
2801  cnt = j + 1;
2802  if (cnt - i < 2) {
2803  return;
2804  }
2805 #else
2806  i = begin;
2807 #endif
2808 
2809  // xwindows limited to 65000 point polylines and mswindows
2810  // limited even more. So split into max 8000 point polylines for drawing
2811  // with large fonts on windows 98 there is a 6000 point limit so
2812  // change to 4000. If the problem recurs we will need to have a property
2813  // option
2814  long cnt1;
2815  while (i < cnt) {
2816 #ifdef WIN32
2817  cnt1 = i + 4000;
2818 #else
2819  cnt1 = i + 8000;
2820 #endif
2821  if (cnt1 > cnt - 2) { // the -2 prevents a one point final polyline
2822  cnt1 = cnt;
2823  }
2824  c->new_path();
2825  c->move_to(x_->get_val(i), y_->get_val(i));
2826  for (++i; i < cnt1; ++i) {
2827  c->line_to(x_->get_val(i), y_->get_val(i));
2828  }
2829  c->stroke(color_, brush_);
2830  }
2831  IfIdraw(mline(c, cnt, x_->vec(), y_->vec(), color_, brush_));
2832 }
2833 
2834 void GPolyLine::print(Printer* c, const Allocation&) const {
2835  int i, cnt = y_->count();
2836  if (cnt < 2) {
2837  return;
2838  }
2839 #if 1
2840  float xmax, xmin, ymax, ymin;
2842  xmax = v->right();
2843  xmin = v->left();
2844  ymax = v->top();
2845  ymin = v->bottom();
2846 
2847  /* this works most of the time in preventing extraneous lines during
2848  very large zoom but can fail */
2849  for (i = 0; i < cnt; ++i) {
2850  if (MyMath::inside(x_->get_val(i), y_->get_val(i), xmin, ymin, xmax, ymax)) {
2851  if (i > 0) {
2852  --i;
2853  }
2854  break;
2855  }
2856  }
2857  int j;
2858  for (j = cnt - 1; i < j; --j) {
2859  if (MyMath::inside(x_->get_val(j), y_->get_val(j), xmin, ymin, xmax, ymax)) {
2860  if (j < cnt - 1) {
2861  ++j;
2862  }
2863  break;
2864  }
2865  }
2866  cnt = j + 1;
2867  if (cnt - i < 2) {
2868  return;
2869  }
2870 #else
2871  i = 0;
2872 #endif
2873 
2875  // Scene::view_transform((Canvas*)c, 1, t); //2 would keep fixed width
2876  // line even after scaling by Print Window Manager
2877 
2878  c->new_path();
2879  c->move_to(x_->get_val(i), y_->get_val(i));
2880 #if 0
2881  for (++i; i < cnt; ++i) {
2882  c->line_to(x_->get_val(i), y_->get_val(i));
2883  }
2884 // some printers can't take very long lines
2885 // from alain@helmholtz.sdsc.edu
2886 #else
2887  char counter = 0;
2888  for (++i; i < cnt; ++i) {
2889  c->line_to(x_->get_val(i), y_->get_val(i));
2890  if (!++counter) {
2891  c->push_transform();
2892  c->transform(t);
2893  c->stroke(color_, brush_);
2894  c->pop_transform();
2895  c->new_path();
2896  c->move_to(x_->get_val(i), y_->get_val(i));
2897  }
2898  }
2899 #endif
2900  c->push_transform();
2901  c->transform(t);
2902  c->stroke(color_, brush_);
2903  c->pop_transform();
2904 }
2905 
2906 void GraphLine::plot() {
2907  if (pval_) {
2908  y_->add(*pval_);
2909  } else {
2910  Oc oc;
2911  nrn_hoc_lock();
2912  if (obj_) {
2913  ObjectContext obc(obj_);
2914  y_->add(oc.runExpr(expr_));
2915  } else if (valid()) {
2916  y_->add(oc.runExpr(expr_));
2917  }
2918  nrn_hoc_unlock();
2919  }
2920  // printf("GPolyLine::plot(%d) value = %g\n", loc, y_->value(loc));
2921 }
2922 
2923 bool GraphLine::valid(bool check) {
2924  if (check && !pval_) {
2925  Oc oc;
2926  valid_ = oc.valid_expr(expr_);
2927  }
2928  return valid_;
2929 }
2930 
2931 void GPolyLine::plot(Coord x, Coord y) {
2932  x_->add(x);
2933  y_->add(y);
2934 }
2935 
2936 void GPolyLine::color(const Color* col) {
2937  const Color* c = col;
2938  if (!c) {
2939  c = colors->color(1);
2940  }
2941  Resource::ref(c);
2943  color_ = c;
2944  if (glabel_ && glabel_->color() != color()) {
2945  glabel_->color(color());
2946  }
2947 }
2948 
2949 void GPolyLine::brush(const Brush* brush) {
2950  const Brush* b = brush;
2951  if (!b) {
2952  b = brushes->brush(1);
2953  }
2954  Resource::ref(b);
2956  brush_ = b;
2957 }
2958 
2959 void GraphLine::save_color(const Color* color) {
2960  const Color* c = color;
2961  if (!c) {
2962  c = colors->color(1);
2963  }
2964  Resource::ref(c);
2966  save_color_ = c;
2968 }
2969 
2970 void GraphLine::save_brush(const Brush* brush) {
2971  const Brush* b = brush;
2972  if (!b) {
2973  b = brushes->brush(1);
2974  }
2975  Resource::ref(b);
2977  save_brush_ = b;
2978  GPolyLine::brush(b);
2979 }
2980 
2981 // GLabel
2982 GLabel::GLabel(const char* s,
2983  const Color* color,
2984  int fixtype,
2985  float size,
2986  float x_align,
2987  float y_align) {
2988  gpl_ = NULL;
2989  WidgetKit& kit = *WidgetKit::instance();
2990  label_ = new Label(s, kit.font(), color);
2991  label_->ref();
2992  erase_flag_ = false;
2993  color_ = color;
2994  color_->ref();
2995  text_ = s;
2996  if (fixtype == 2) {
2997  vfixed(size);
2998  } else if (fixtype == 1) {
2999  fixed(size);
3000  } else {
3001  relative(size);
3002  }
3003  align(x_align, y_align);
3004 }
3005 GLabel::~GLabel() {
3006  // printf("~GLabel %s\n", text());
3009  assert(!labeled_line());
3010 }
3011 
3012 Glyph* GLabel::clone() const {
3013  return new GLabel(text_.c_str(), color_, fixtype_, scale_, x_align_, y_align_);
3014 }
3015 
3016 void GLabel::save(std::ostream& o, Coord x, Coord y) {
3017  if (labeled_line()) {
3018  return;
3019  }
3020  char buf[256];
3021  Sprintf(buf,
3022  "save_window_.label(%g, %g, \"%s\", %d, %g, %g, %g, %d)",
3023  x,
3024  y,
3025  text_.c_str(),
3026  fixtype_,
3027  scale_,
3028  x_align_,
3029  y_align_,
3030  colors->color(color_));
3031  o << buf << std::endl;
3032 }
3033 
3034 void GLabel::fixed(float scale) {
3035  fixtype_ = 1;
3036  scale_ = scale;
3037 }
3038 void GLabel::vfixed(float scale) {
3039  fixtype_ = 2;
3040  scale_ = scale;
3041 }
3042 void GLabel::relative(float scale) {
3043  fixtype_ = 0;
3044  scale_ = scale;
3045 }
3046 void GLabel::align(float x, float y) {
3047  x_align_ = x;
3048  y_align_ = y;
3049 }
3050 void GLabel::color(const Color* c) {
3052  WidgetKit& kit = *WidgetKit::instance();
3053  label_ = new Label(text_.c_str(), kit.font(), c);
3054  label_->ref();
3055  Resource::ref(c);
3057  color_ = c;
3058  if (gpl_ && gpl_->color() != color()) {
3059  gpl_->color(color());
3060  }
3061 }
3062 
3063 void GLabel::text(const char* t) {
3065  WidgetKit& kit = *WidgetKit::instance();
3066  text_ = t;
3067  label_ = new Label(text_.c_str(), kit.font(), color_);
3068  label_->ref();
3069 }
3070 
3071 void GLabel::request(Requisition& req) const {
3072  label_->request(req);
3073  Requirement& rx = req.x_requirement();
3074  Requirement& ry = req.y_requirement();
3075  rx.natural(rx.natural() * scale_);
3076  ry.natural(ry.natural() * scale_);
3077  // printf("ry.alignment=%g\n", ry.alignment());
3078  rx.alignment(x_align_);
3079  ry.alignment(y_align_ + ry.alignment());
3080 }
3081 void GLabel::allocate(Canvas* c, const Allocation& a, Extension& e) {
3082  e.set(c, a);
3083 }
3084 
3085 void GLabel::draw(Canvas* c, const Allocation& a1) const {
3086  // printf("GLabel::draw\n");
3087  Transformer t;
3088  Coord width = a1.x_allotment().span();
3089  Coord height = a1.y_allotment().span();
3090  Coord x = a1.x() - width * x_align_;
3091  Coord y = a1.y() - height * y_align_;
3092  // printf("x=%g y=%g\n", x, y);
3093  Allotment ax(0, width, 0);
3094  Allotment ay(0, height, 0);
3095  Allocation a2;
3096  a2.allot_x(ax);
3097  a2.allot_y(ay);
3098 
3099  // printf("xend = %g, yend=%g\n", a2.right(), a2.top());
3100  c->push_transform();
3101  t.scale(scale_, scale_);
3102  t.translate(x, y);
3103  c->transform(t);
3104  // float a00, a01, a10,a11,a20,a21;
3105  // c->transformer().matrix(a00,a01,a10,a11,a20,a21);
3106  // printf("transformer %g %g %g %g %g %g\n", a00, a01, a10, a11, a20, a21);
3107  label_->draw(c, a2);
3108  c->pop_transform();
3109  IfIdraw(text(c, text_.c_str(), t, NULL, color()));
3110 }
3111 
3112 // DataVec------------------
3113 
3114 DataVec::DataVec(int size) {
3115  y_ = new float[size];
3116  y_[0] = 0.;
3117  size_ = size;
3118  count_ = 0;
3119  iMinLoc_ = iMaxLoc_ = -1;
3121 }
3122 
3123 DataVec::DataVec(const DataVec* v) {
3124  size_ = v->size_;
3125  y_ = new float[size_];
3126  count_ = v->count_;
3127  y_[0] = 0.;
3128  for (int i = 0; i < count_; ++i) {
3129  y_[i] = v->y_[i];
3130  }
3131  iMinLoc_ = v->iMinLoc_;
3132  iMaxLoc_ = v->iMaxLoc_;
3133  running_min_loc_ = v->running_min_loc_;
3134  running_max_loc_ = v->running_max_loc_;
3135 }
3136 
3138  delete[] y_;
3139 }
3140 
3141 void DataVec::running_start() {
3142  if (count_) {
3144  } else {
3146  }
3147 }
3148 
3149 void DataVec::add(float x) {
3150  if (count_ == size_) {
3151  size_ *= 2;
3152  float* y = new float[size_];
3153  for (int i = 0; i < count_; i++) {
3154  y[i] = y_[i];
3155  }
3156  delete[] y_;
3157  y_ = y;
3158  }
3159  if (x > 1e30) {
3160  x = 1e32;
3161  } else if (x < -1e32) {
3162  x = -1e32;
3163  }
3164  y_[count_] = x;
3165  if (running_min_loc_ >= 0) {
3166  if (x < get_val(running_min_loc_)) {
3168  }
3169  if (x > get_val(running_max_loc_)) {
3171  }
3172  }
3173  ++count_;
3174  iMinLoc_ = iMaxLoc_ = -1;
3175 }
3176 
3177 float DataVec::max() const {
3178  return get_val(loc_max());
3179 }
3180 float DataVec::min() const {
3181  return get_val(loc_min());
3182 }
3183 
3184 float DataVec::running_max() {
3185  if (running_max_loc_ < 0) {
3186  return max();
3187  } else {
3188  return get_val(running_max_loc_);
3189  }
3190 }
3191 
3192 float DataVec::running_min() {
3193  if (running_min_loc_ < 0) {
3194  return min();
3195  } else {
3196  return get_val(running_min_loc_);
3197  }
3198 }
3199 
3200 int DataVec::loc_max() const {
3201  DataVec* dv = (DataVec*) this;
3202  if (iMaxLoc_ < 0) {
3203  int i;
3204  float m;
3205  for (i = 0, dv->iMaxLoc_ = 0, m = y_[i++]; i < count_; i++) {
3206  if (m < y_[i]) {
3207  m = y_[i];
3208  dv->iMaxLoc_ = i;
3209  }
3210  }
3211  }
3212  return iMaxLoc_;
3213 }
3214 
3215 int DataVec::loc_min() const {
3216  DataVec* dv = (DataVec*) this;
3217  if (iMinLoc_ < 0) {
3218  int i;
3219  float m;
3220  for (i = 0, dv->iMinLoc_ = 0, m = y_[i++]; i < count_; i++) {
3221  if (m > y_[i]) {
3222  m = y_[i];
3223  dv->iMinLoc_ = i;
3224  }
3225  }
3226  }
3227  return iMinLoc_;
3228 }
3229 
3230 float DataVec::max(int low, int high) {
3231  int imax = loc_max();
3232  if (imax >= low && imax < high) {
3233  return get_val(imax);
3234  }
3235  float m;
3236  for (m = y_[low++]; low < high; low++) {
3237  if (m < y_[low]) {
3238  m = y_[low];
3239  }
3240  }
3241  return m;
3242 }
3243 
3244 float DataVec::min(int low, int high) {
3245  int imin = loc_min();
3246  if (imin >= low && imin < high) {
3247  return get_val(imin);
3248  }
3249  float m;
3250  for (m = y_[low++]; low < high; low++) {
3251  if (m > y_[low]) {
3252  m = y_[low];
3253  }
3254  }
3255  return m;
3256 }
3257 
3258 void DataVec::erase() {
3259  count_ = 0;
3260  iMinLoc_ = iMaxLoc_ = -1;
3262 }
3263 
3264 void DataVec::write() {
3265 #if 0
3266  cout << get_name() << std::endl;
3267  cout << count_ << std::endl;
3268  for (int i=0; i<count_; i++) {
3269  cout << y_[i] << std::endl;
3270  }
3271 #endif
3272 }
3273 
3274 GraphVector::GraphVector(const char* name, const Color* color, const Brush* brush)
3275  : GPolyLine(new DataVec(50), color, brush) {
3276  dp_ = new DataPointers();
3277  dp_->ref();
3278  name_ = name;
3279  keepable_ = true;
3280  disconnect_defer_ = false;
3281  record_install();
3282 }
3284  Oc oc;
3285  oc.notify_pointer_disconnect(this);
3286  dp_->unref();
3287  record_uninstall();
3288 }
3289 
3290 const char* GraphVector::name() const {
3291  return name_.c_str();
3292 }
3293 
3294 void GraphVector::save(std::ostream&) {}
3295 
3296 void GraphVector::begin() {
3297  dp_->erase();
3298  y_->erase();
3299  x_->erase();
3300 }
3301 
3302 static double zero;
3303 
3305  // cant notify_pointer_disconnect from here, it will screw up list
3306  disconnect_defer_ = true;
3307  begin();
3308 }
3309 
3311  if (disconnect_defer_) {
3312  Oc oc;
3313  oc.notify_pointer_disconnect(this);
3314  disconnect_defer_ = false;
3315  }
3316  // Dubious
3317  if (dp_->count() == 0 ||
3318  static_cast<double*>(py) != static_cast<double*>(dp_->p(dp_->count() - 1)) + 1) {
3320  }
3321  x_->add(x);
3322  if (!py) {
3324  }
3325  y_->add(*py);
3326  dp_->add(std::move(py));
3327 }
3328 
3329 bool GraphVector::trivial() const {
3330  for (int i = 0; i < dp_->count(); ++i) {
3331  if (static_cast<double const*>(dp_->p(i)) != &zero) {
3332  return false;
3333  }
3334  }
3335  return true;
3336 }
3337 
3338 void GraphVector::request(Requisition& req) const {
3339  y_->erase();
3340  for (int i = 0; i < dp_->count(); ++i) {
3341  y_->add(*dp_->p(i));
3342  }
3343  GPolyLine::request(req);
3344 }
3345 
3346 // LineExtension
3347 LineExtension::LineExtension(GPolyLine* gp) {
3348  gp_ = gp; // don't ref since this is referenced by the polyline
3349  start_ = previous_ = -1;
3350 }
3351 LineExtension::~LineExtension() {}
3352 
3353 void LineExtension::begin() {
3354  previous_ = yd()->count() - 1;
3355  start_ = yd()->count() - 1;
3356  yd()->running_start();
3357 }
3358 void LineExtension::extend() {
3359  previous_ = start_;
3360  start_ = yd()->count() - 1;
3361  yd()->running_start();
3362 }
3363 
3364 
3365 void LineExtension::request(Requisition& req) const {
3366  Coord x, span;
3367  Coord x1, x2;
3368  const float eps = 1e-4;
3369  x1 = xd()->running_min();
3370  x2 = xd()->running_max();
3371  span = (x2 - x1);
3372  x = (x1);
3373  x = (span > 0) ? x / span : 0;
3374  Requirement rx(span, 0, 0, -x);
3375  x1 = yd()->running_min();
3376  x2 = yd()->running_max();
3377  span = (x2 - x1) / 2;
3378  x = (x1);
3379  x = (span > 0) ? x / span : 0;
3380  Requirement ry(span, 0, 0, -x);
3381  req.require_x(rx);
3382  req.require_y(ry);
3383 }
3384 
3385 void LineExtension::allocate(Canvas* c, const Allocation& a, Extension& e) {
3386  e.set(c, a);
3387  // MyMath::extend(e, gp_->brush()->width()/2 + 1);
3388 }
3389 
3390 void LineExtension::draw(Canvas* c, const Allocation& a) const {
3391 #if 0
3392  if (previous_ >= 0) {
3393  gp_->draw_specific(c, a, previous_, xd()->count());
3394  }else
3395 #endif
3396  if (start_ >= 0) {
3397  gp_->draw_specific(c, a, start_, xd()->count());
3398  }
3399 }
3400 
3401 void LineExtension::damage(Graph* g) {
3402  g->damage(xd()->running_min(), yd()->running_min(), xd()->running_max(), yd()->running_max());
3403 }
3404 
3405 void Graph::change_prop() {
3409  if (Oc::helpmode()) {
3410  help();
3411  }
3412 }
3413 
3414 #endif /* HAVE_IV */
#define Image
Definition: _defines.h:148
#define Window
Definition: _defines.h:330
#define Handler
Definition: _defines.h:144
#define Color
Definition: _defines.h:72
#define Menu
Definition: _defines.h:174
#define FontBoundingBox
Definition: _defines.h:119
#define Transformer
Definition: _defines.h:313
#define Canvas
Definition: _defines.h:63
#define Style
Definition: _defines.h:278
#define Label
Definition: _defines.h:157
#define Coord
Definition: _defines.h:17
#define Brush
Definition: _defines.h:57
#define Hit
Definition: _defines.h:145
#define WidgetKit
Definition: _defines.h:328
#define Printer
Definition: _defines.h:209
#define MonoGlyph
Definition: _defines.h:179
#define GlyphIndex
Definition: _defines.h:21
#define MenuItem
Definition: _defines.h:177
#define Event
Definition: _defines.h:105
#define TransformSetter
Definition: _defines.h:312
#define RubberRect
Definition: _defines.h:237
#define Glyph
Definition: _defines.h:130
#define symlist
Definition: cabcode.cpp:49
Coord x() const
Definition: geometry.h:286
void allot_y(const Allotment &)
Definition: geometry.h:279
Coord y() const
Definition: geometry.h:287
Allotment & x_allotment()
Definition: geometry.h:281
Allotment & y_allotment()
Definition: geometry.h:282
void allot_x(const Allotment &)
Definition: geometry.h:278
void span(Coord)
Definition: geometry.h:265
Definition: axis.h:8
const Brush * brush_palette[BRUSH_SIZE]
Definition: graph.h:514
virtual ~BrushPalette()
@ BRUSH_SIZE
Definition: graph.h:511
const Brush * brush(int) const
static void start(Graph *)
const Color * color_palette[COLOR_SIZE]
Definition: graph.h:502
const Color * color(int) const
@ COLOR_SIZE
Definition: graph.h:499
virtual ~ColorPalette()
void erase()
Definition: graph.h:236
void add(neuron::container::data_handle< double > dh)
Definition: graph.h:233
std::size_t count()
Definition: graph.h:242
neuron::container::data_handle< double > p(std::size_t i)
Definition: graph.h:245
Definition: graph.h:196
const Coord * vec()
Definition: graph.h:216
void running_start()
int running_max_loc_
Definition: graph.h:226
float running_min()
void add(float)
int running_min_loc_
Definition: graph.h:226
DataVec(int size)
float running_max()
Object ** new_vect(GLabel *g=NULL) const
float get_val(int i) const
Definition: graph.h:210
float min() const
int loc_min() const
void write()
float max() const
int loc_max() const
void erase()
int iMinLoc_
Definition: graph.h:225
int size_
Definition: graph.h:225
virtual ~DataVec()
int count_
Definition: graph.h:225
float * y_
Definition: graph.h:227
int size() const
Definition: graph.h:213
int count() const
Definition: graph.h:206
int iMaxLoc_
Definition: graph.h:225
void set(Canvas *, const Allocation &)
Definition: graph.h:418
void text(const char *)
float y_align_
Definition: graph.h:481
int fixtype_
Definition: graph.h:479
float scale() const
Definition: graph.h:445
void fixed(float scale)
const Color * color_
Definition: graph.h:484
Glyph * label_
Definition: graph.h:483
virtual ~GLabel()
virtual void draw(Canvas *, const Allocation &) const
void align(float x, float y)
virtual void allocate(Canvas *, const Allocation &, Extension &)
std::string text_
Definition: graph.h:482
int fixtype() const
Definition: graph.h:451
float y_align() const
Definition: graph.h:457
void relative(float scale)
const char * text() const
Definition: graph.h:448
GPolyLine * labeled_line() const
Definition: graph.h:470
GLabel(const char *s, const Color *, int fixtype=1, float size=12, float x_align=0., float y_align=0.)
virtual void save(std::ostream &, Coord, Coord)
bool erase_flag_
Definition: graph.h:486
void color(const Color *)
bool erase_flag()
Definition: graph.h:463
float scale_
Definition: graph.h:480
GPolyLine * gpl_
Definition: graph.h:485
void vfixed(float scale)
virtual void request(Requisition &) const
float x_align() const
Definition: graph.h:454
virtual Glyph * clone() const
bool fixed() const
Definition: graph.h:442
const Color * color() const
Definition: graph.h:460
float x_align_
Definition: graph.h:481
virtual void request(Requisition &) const
bool keepable()
Definition: graph.h:308
void init(DataVec *, DataVec *, const Color *, const Brush *)
Coord x(int index) const
Definition: graph.h:285
void brush(const Brush *)
const DataVec * y_data() const
Definition: graph.h:294
void erase()
Definition: graph.h:271
const Brush * brush() const
Definition: graph.h:281
GLabel * glabel_
Definition: graph.h:320
virtual void allocate(Canvas *, const Allocation &, Extension &)
const DataVec * x_data() const
Definition: graph.h:291
const Color * color() const
Definition: graph.h:278
virtual void print(Printer *, const Allocation &) const
void color(const Color *)
void plot(Coord x, Coord y)
bool keepable_
Definition: graph.h:321
const Brush * brush_
Definition: graph.h:319
GPolyLine(DataVec *x, const Color *=NULL, const Brush *=NULL)
DataVec * y_
Definition: graph.h:316
GLabel * label() const
Definition: graph.h:298
Coord y(int index) const
Definition: graph.h:288
virtual ~GPolyLine()
virtual void save(std::ostream &)
virtual void draw_specific(Canvas *, const Allocation &, int, int) const
virtual void erase_line(Scene *, GlyphIndex)
const Color * color_
Definition: graph.h:318
virtual void draw(Canvas *, const Allocation &) const
virtual void pick_vector()
DataVec * x_
Definition: graph.h:317
void label_loc(Coord &x, Coord &y) const
virtual void erase(Scene *s, GlyphIndex i, int type)
Definition: graph.h:411
virtual bool is_polyline()
Definition: graph.h:54
void new_axis()
void change_line_color(GPolyLine *)
const Color * color() const
Definition: graph.h:109
virtual void new_size(Coord x1, Coord y1, Coord x2, Coord y2)
float label_scale_
Definition: graph.h:178
void erase()
SymChooser * sc_
Definition: graph.h:170
virtual ~Graph()
static std::ostream * ascii_
Definition: graph.h:193
int labeltype() const
Definition: graph.h:149
static SymChooser * fsc_
Definition: graph.h:171
float label_y_align_
Definition: graph.h:179
void cross_action(char, GPolyLine *, int)
void choose_sym()
const Brush * brush() const
Definition: graph.h:112
virtual bool change_label(GLabel *, const char *, GLabel *gl=NULL)
void name(char *)
Graph(bool=true)
void extension_start()
void keep_lines()
void line(Coord x, Coord y)
int label_fixtype_
Definition: graph.h:177
virtual GlyphIndex glyph_index(const Glyph *)
GraphVector * rvp_
Definition: graph.h:192
void family(bool)
float label_x_
Definition: graph.h:180
GraphLine * add_var(const char *, const Color *, const Brush *, bool usepointer, int fixtype=1, neuron::container::data_handle< double > p={}, const char *lab=NULL, Object *obj=NULL)
Symlist * symlist_
Definition: graph.h:165
void ascii_save(std::ostream &o) const
float label_x_align_
Definition: graph.h:179
void add_polyline(GPolyLine *)
bool vector_copy_
Definition: graph.h:187
TelltaleState * keep_lines_toggle_
Definition: graph.h:181
virtual void see_range_plot(GraphVector *)
static bool label_chooser(const char *, char *, GLabel *, Coord x=400., Coord y=400.)
void erase_lines()
void erase_axis()
void fixed(float scale)
void family_label_chooser()
double family_val_
Definition: graph.h:184
bool family_on_
Definition: graph.h:182
void begin_line(const char *s=NULL)
virtual void save_phase2(std::ostream &)
void view_axis()
void change_label_color(GLabel *)
virtual void help()
void color(int)
void add_graphVector(GraphVector *)
virtual void save_phase1(std::ostream &)
void x_expr(const char *, bool usepointer)
@ CROSSHAIR
Definition: graph.h:56
@ CHANGELABEL
Definition: graph.h:56
std::string var_name_
Definition: graph.h:172
DataVec * x_
Definition: graph.h:168
GLabel * new_proto_label() const
virtual void delete_label(GLabel *)
void fast_flush()
neuron::container::data_handle< double > x_pval_
Definition: graph.h:190
virtual void wholeplot(Coord &x1, Coord &y1, Coord &x2, Coord &y2) const
void flush()
GPolyLine * current_polyline_
Definition: graph.h:173
void plot(float)
float label_y_
Definition: graph.h:180
void relative(float scale)
HocCommand * cross_action_
Definition: graph.h:186
Symbol * x_expr_
Definition: graph.h:189
void begin()
void align(float x, float y)
virtual void erase_all()
void family_value()
void view_box()
virtual void draw(Canvas *, const Allocation &) const
void keep_lines_toggle()
int family_cnt_
Definition: graph.h:185
void mark(Coord x, Coord y, char style='+', float size=12, const Color *=NULL, const Brush *=NULL)
bool extension_flushed_
Definition: graph.h:169
float label_n_
Definition: graph.h:180
std::vector< GraphLine * > line_list_
Definition: graph.h:166
const Brush * brush_
Definition: graph.h:176
void extension_continue()
GLabel * label(float x, float y, const char *s, int fixtype, float scale, float x_align, float y_align, const Color *)
void vfixed(float scale)
void change_prop()
static std::ostream * ascii()
GLabel * family_label_
Definition: graph.h:183
void axis(DimensionName, float min, float max, float pos=0., int ntics=-1, int nminor=0, int invert=0, bool number=true)
void set_cross_action(const char *, Object *, bool vectorcopy=false)
const Color * color_
Definition: graph.h:175
virtual void pick(Canvas *, const Allocation &, int depth, Hit &)
void brush(int)
virtual void pick(Canvas *, const Allocation &, int depth, Hit &)
virtual void erase(Scene *, GlyphIndex, int erase_type)
virtual bool is_graphVector()
Definition: graph.h:45
@ ERASE_LINE
Definition: graph.h:28
@ ERASE_AXIS
Definition: graph.h:28
virtual bool is_mark()
bool save()
Definition: graph.h:34
virtual void save(std::ostream &, Coord, Coord)
GraphItem(Glyph *g, bool=true, bool pick=true)
bool pick_
Definition: graph.h:51
virtual ~GraphItem()
virtual bool is_polyline()
bool valid(bool check=false)
LineExtension * extension_
Definition: graph.h:370
neuron::container::data_handle< double > pval_
Definition: graph.h:366
const Brush * save_brush_
Definition: graph.h:372
void simgraph_init()
const Color * save_color_
Definition: graph.h:371
const Color * save_color() const
Definition: graph.h:347
bool valid_
Definition: graph.h:373
bool change_expr(const char *, Symlist **)
virtual void save(std::ostream &)
void plot()
virtual void update(Observable *)
void extension_start()
const char * name() const
GraphLine(const char *, DataVec *x, Symlist **, const Color *=NULL, const Brush *=NULL, bool usepointer=0, neuron::container::data_handle< double > pd={}, Object *obj=NULL)
Object * obj_
Definition: graph.h:367
void extension_continue()
virtual ~GraphLine()
void simgraph_continuous(double)
void simgraph_activate(bool)
const Brush * save_brush() const
Definition: graph.h:350
Symbol * expr_
Definition: graph.h:365
DataVec * simgraph_x_sav_
Definition: graph.h:374
virtual void save(std::ostream &)
virtual bool choose_sym(Graph *)
std::string name_
Definition: graph.h:398
const char * name() const
GraphVector(const char *, const Color *=NULL, const Brush *=NULL)
virtual ~GraphVector()
void record_uninstall()
DataPointers * dp_
Definition: graph.h:397
virtual void request(Requisition &) const
virtual void update(Observable *)
void add(float, neuron::container::data_handle< double >)
void begin()
bool trivial() const
bool disconnect_defer_
Definition: graph.h:399
double func_call(int narg, int *perr=NULL)
Definition: objcmd.cpp:140
int execute(bool notify=true)
Definition: objcmd.cpp:94
const char * name()
Definition: objcmd.cpp:73
static HocMark * instance(char style, float size, const Color *, const Brush *)
static void paneltool(const char *name, const char *procname, const char *action, ScenePicker *, Object *pycallback=NULL, Object *pyselact=NULL)
void label(const char *)
Definition: ivocvect.cpp:175
void resize(size_t n)
Definition: ivocvect.h:46
static MenuItem * menu_item(const char *)
static void extend(Extension &, Coord)
Definition: mymath.h:79
static bool inside(Coord x, Coord min, Coord max)
Definition: mymath.h:91
Definition: ivoc.h:36
double runExpr(Symbol *)
static void help(const char *)
int run(int argc, const char **argv)
static bool valid_expr(Symbol *)
static std::ostream * save_stream
Definition: ivoc.h:77
void notify_when_freed(void *p, Observer *)
const char * name(Symbol *)
Symbol * parseExpr(const char *, Symlist **=NULL)
void notify_pointer_disconnect(Observer *)
static bool helpmode()
Definition: ivoc.h:70
void xplace(int left, int top)
virtual void map()
void alignment(float)
Definition: geometry.h:237
void natural(Coord)
Definition: geometry.h:231
void require_x(const Requirement &)
Definition: geometry.h:243
const Requirement & x_requirement() const
Definition: geometry.h:245
void require_y(const Requirement &)
Definition: geometry.h:244
const Requirement & y_requirement() const
Definition: geometry.h:246
virtual void ref() const
Definition: resource.cpp:42
virtual void unref() const
Definition: resource.cpp:47
bool menu_picked()
Definition: scenevie.h:310
virtual void pick(Canvas *, const Allocation &, int depth, Hit &)
static long scene_list_index(Scene *)
Object * hoc_obj_ptr()
Definition: scenevie.h:304
virtual XYView * sceneview(int) const
virtual void printfile(const char *)
void move(GlyphIndex, Coord x, Coord y)
virtual Coord y2() const
Definition: scenevie.h:364
virtual void change_to_fixed(GlyphIndex, XYView *)
virtual Coord y1() const
Definition: scenevie.h:361
virtual void damage(GlyphIndex)
virtual void background(Glyph *bg=NULL)
@ MOVE
Definition: scenevie.h:256
@ CHANGECOLOR
Definition: scenevie.h:256
@ DELETE
Definition: scenevie.h:256
virtual void append_viewfixed(Glyph *)
virtual void dismiss()
ScenePicker * picker()
static const Color * default_background()
void location(GlyphIndex, Coord &x, Coord &y) const
virtual void damage_all()
virtual void append(Glyph *)
virtual void change_to_vfixed(GlyphIndex, XYView *)
virtual void new_size(Coord x1, Coord y1, Coord x2, Coord y2)
virtual int tool()
static const Color * default_foreground()
virtual void change(GlyphIndex)
virtual void save_class(std::ostream &, const char *)
virtual int view_count() const
bool mark()
Definition: scenevie.h:290
virtual void wholeplot(Coord &x1, Coord &y1, Coord &x2, Coord &y2) const
virtual Coord x2() const
Definition: scenevie.h:358
virtual GlyphIndex count() const
virtual Glyph * component(GlyphIndex) const
virtual void remove(GlyphIndex)
virtual Coord x1() const
Definition: scenevie.h:355
virtual void insert(GlyphIndex, Glyph *)
virtual void append_fixed(Glyph *)
virtual void help()
virtual void modified(GlyphIndex)
virtual void draw(Canvas *, const Allocation &) const
virtual void set_scene_tool(int)
void bind_select(Rubberband *rb)
Definition: ocpicker.h:24
virtual double * selected_var()
virtual const std::string & selected() const
virtual int selected_vector_count()
Definition: scenevie.h:201
virtual void damage_area(Coord &x1, Coord &y1, Coord &x2, Coord &y2) const
Canvas * canvas()
virtual Coord bottom() const
virtual Coord height() const
virtual Coord top() const
virtual void view_ratio(float xratio, float yratio, Coord &x, Coord &y) const
virtual void zout(Coord &x1, Coord &y1, Coord &x2, Coord &y2) const
void size(Coord x1, Coord y1, Coord x2, Coord y2)
virtual Coord width() const
virtual Coord left() const
virtual void ratio_view(Coord x, Coord y, float &xratio, float &yratio) const
virtual void damage_all()
virtual Coord right() const
virtual void zin(Coord &x1, Coord &y1, Coord &x2, Coord &y2) const
static XYView * current_draw_view()
static XYView * current_pick_view()
const Transformer & s2o() const
Definition: scenevie.h:137
void class2oc(const char *, ctor_f *cons, dtor_f *destruct, Member_func *, Member_ret_obj_func *, Member_ret_str_func *)
Definition: hoc_oop.cpp:1631
char * gargstr(int narg)
Definition: code2.cpp:227
HocReturnType hoc_return_type_code
Definition: code.cpp:42
#define cnt
Definition: tqueue.hpp:44
#define v
Definition: md1redef.h:11
#define i
Definition: md1redef.h:19
#define y_(arg)
Crout matrix decomposition : Forward/Backward substitution.
Definition: crout.hpp:136
double chkarg(int, double low, double high)
Definition: code2.cpp:626
@ Dimension_Y
Definition: geometry.h:39
@ Dimension_X
Definition: geometry.h:39
unsigned int DimensionName
Definition: geometry.h:36
static RNG::key_type k
Definition: nrnran123.cpp:9
static double gr_view(void *v)
Definition: graph.cpp:1000
static double gr_simgraph(void *v)
Definition: graph.cpp:687
double gr_addglyph(void *)
Definition: grglyph.cpp:29
double ivoc_gr_menu_action(void *v)
Definition: graph.cpp:325
static double gr_addexpr(void *v)
Definition: graph.cpp:577
static double gr_view_count(void *v)
Definition: graph.cpp:1066
static double gr_addobject(void *v)
Definition: graph.cpp:586
void Graph_reg()
Definition: graph.cpp:1226
static void gr_destruct(void *v)
Definition: graph.cpp:1216
static double gr_fast_flush(void *v)
Definition: graph.cpp:743
static double gr_begin(void *v)
Definition: graph.cpp:663
static double gr_family(void *v)
Definition: graph.cpp:309
double ivoc_gr_size(void *v)
Definition: graph.cpp:814
static double gr_xaxis(void *v)
Definition: graph.cpp:258
static double gr_align(void *v)
Definition: graph.cpp:941
static double gr_vfixed(void *v)
Definition: graph.cpp:911
static double exec_menu(void *v)
Definition: graph.cpp:1127
static double gr_set_cross_action(void *v)
Definition: graph.cpp:1093
static double gr_color(void *v)
Definition: graph.cpp:959
static double gr_relative(void *v)
Definition: graph.cpp:926
double ivoc_erase_all(void *v)
Definition: graph.cpp:767
double ivoc_gr_line(void *v)
Definition: graph.cpp:720
static double gr_flush(void *v)
Definition: graph.cpp:731
double ivoc_gr_begin_line(void *v)
Definition: graph.cpp:699
static Member_func gr_members[]
Definition: graph.cpp:1152
static double gr_plot(void *v)
Definition: graph.cpp:675
double ivoc_view_size(void *v)
Definition: graph.cpp:450
static double gr_addvar(void *v)
Definition: graph.cpp:568
static double gr_save_name(void *v)
Definition: graph.cpp:276
static double gr_fixed(void *v)
Definition: graph.cpp:896
double gr_line_info(void *v)
Definition: graph.cpp:465
static void * gr_cons(Object *ho)
Definition: graph.cpp:1198
static double gr_xexpr(void *v)
Definition: graph.cpp:646
double ivoc_gr_menu_remove(void *v)
Definition: graph.cpp:1137
double ivoc_gr_gif(void *v)
Definition: graph.cpp:779
double ivoc_gr_erase(void *v)
Definition: graph.cpp:755
double ivoc_gr_mark(void *v)
Definition: graph.cpp:1032
static double gr_vector(void *v)
Definition: graph.cpp:617
static double gr_printfile(void *v)
Definition: graph.cpp:1114
static double gr_brush(void *v)
Definition: graph.cpp:978
static double gr_unmap(void *v)
Definition: graph.cpp:1080
double ivoc_view_info(void *v)
Definition: graph.cpp:367
double ivoc_gr_menu_tool(void *v)
Definition: graph.cpp:343
static double gr_yaxis(void *v)
Definition: graph.cpp:267
double ivoc_gr_label(void *v)
Definition: graph.cpp:867
BrushPalette * brushes
ColorPalette * colors
char buf[512]
Definition: init.cpp:13
int hoc_is_object_arg(int narg)
Definition: code.cpp:876
void hoc_obj_set(int i, Object *obj)
Definition: hoc_oop.cpp:66
void nrn_hoc_unlock()
Definition: multicore.cpp:827
neuron::container::data_handle< double > hoc_val_handle(std::string_view s)
Definition: code2.cpp:715
char * hoc_gargstr(int)
int hoc_is_str_arg(int narg)
Definition: code.cpp:872
int is_obj_type(Object *obj, const char *type_name)
Definition: hoc_oop.cpp:2110
void hoc_free_list(Symlist **)
Definition: symbol.cpp:254
IvocVect * vector_arg(int i)
Definition: ivocvect.cpp:265
double hoc_ac_
Definition: hoc_init.cpp:222
char * hoc_object_name(Object *ob)
Definition: hoc_oop.cpp:73
double * hoc_pgetarg(int narg)
Definition: oc_ansi.h:253
void nrn_hoc_lock()
Definition: multicore.cpp:819
int hoc_is_pdouble_arg(int narg)
Definition: code.cpp:868
void hoc_obj_unref(Object *obj)
Definition: hoc_oop.cpp:1881
void hoc_push_object(Object *d)
Definition: code.cpp:793
#define TRY_GUI_REDIRECT_ACTUAL_DOUBLE(name, obj)
Definition: gui-redirect.h:55
#define TRY_GUI_REDIRECT_NO_RETURN(name, obj)
Definition: gui-redirect.h:40
#define TRY_GUI_REDIRECT_OBJ(name, obj)
Definition: gui-redirect.h:10
static int c
Definition: hoc.cpp:169
int hoc_usegui
Definition: hoc.cpp:121
#define assert(ex)
Definition: hocassrt.h:24
#define getarg
Definition: hocdec.h:17
Object ** hoc_objgetarg(int)
Definition: code.cpp:1614
#define IfIdraw(arg)
Definition: idraw.h:102
void nrn_notify_pointer_disconnect(Observer *ob)
Definition: ivoc.cpp:70
void hoc_pushx(double)
Definition: code.cpp:779
double var(InputIterator begin, InputIterator end)
Definition: ivocvect.h:108
Symbol * lookup(const char *)
invert
Definition: extdef.h:9
printf
Definition: extdef.h:5
const char * name
Definition: init.cpp:16
void move(Item *q1, Item *q2, Item *q3)
Definition: list.cpp:200
double * vector_vec(IvocVect *v)
Definition: ivocvect.cpp:19
void hoc_execerror(const char *s1, const char *s2)
Definition: nrnoc_aux.cpp:39
void hoc_warning(const char *s1, const char *s2)
Definition: nrnoc_aux.cpp:44
auto get_name(Tag const &tag, int field_index)
Get the nicest available name for the field_index-th instance of Tag.
void notify_when_handle_dies(data_handle< double > dh, Observer *obs)
Register that obs should be notified when dh dies.
Definition: ivoc.cpp:91
constexpr do_not_search_t do_not_search
Definition: data_handle.hpp:11
int Sprintf(char(&buf)[N], const char *fmt, Args &&... args)
Redirect sprintf to snprintf if the buffer size can be deduced.
Definition: wrap_sprintf.h:14
if(ncell==0)
Definition: cellorder.cpp:785
static void check(VecTNode &)
Definition: cellorder1.cpp:401
int const size_t const size_t n
Definition: nrngsl.h:10
size_t p
size_t j
s
Definition: multisend.cpp:521
int ifarg(int)
Definition: code.cpp:1607
short index
Definition: cabvars.h:11
short type
Definition: cabvars.h:10
static N_Vector x_
HOC interpreter function declarations (included by hocdec.h)
static double save(void *v)
Definition: ocbox.cpp:344
int hoc_execerror_messages
Definition: hoc.cpp:607
#define text
Definition: plot.cpp:60
#define NULL
Definition: spdefs.h:105
Definition: hocdec.h:173
void * this_pointer
Definition: hocdec.h:178
union Object::@47 u
Definition: model.h:47
char * name
Definition: model.h:61
Definition: hocdec.h:75
bool var_pair_chooser(const char *, float &x, float &y, Window *w=NULL, Coord x1=400., Coord y1=400.)