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