GNU Octave  4.2.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
__init_fltk__.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2007-2017 Shai Ayal
4 Copyright (C) 2014-2016 Andreas Weber
5 
6 This file is part of Octave.
7 
8 Octave is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <http://www.gnu.org/licenses/>.
21 
22 */
23 
24 /*
25 
26 To initialize:
27 
28  graphics_toolkit ("fltk");
29  plot (randn (1e3, 1));
30 
31 */
32 
33 // PKG_ADD: if (__have_feature__ ("FLTK") && __have_feature__ ("OPENGL") && have_window_system ()) register_graphics_toolkit ("fltk"); endif
34 
35 #if defined (HAVE_CONFIG_H)
36 # include "config.h"
37 #endif
38 
39 #include "builtin-defun-decls.h"
40 #include "defun-dld.h"
41 #include "error.h"
42 #include "errwarn.h"
43 #include "oct-opengl.h"
44 #include "ov-fcn-handle.h"
45 
46 #if defined (HAVE_FLTK)
47 
48 #if defined (HAVE_X_WINDOWS)
49 # include <X11/Xlib.h>
50 #endif
51 
52 #include <map>
53 #include <set>
54 #include <sstream>
55 #include <iostream>
56 
57 #if defined (WIN32)
58 # define WIN32_LEAN_AND_MEAN
59 #endif
60 
61 #include <FL/Fl.H>
62 #include <FL/Fl_Box.H>
63 #include <FL/Fl_Button.H>
64 #include <FL/Fl_Choice.H>
65 #include <FL/Fl_File_Chooser.H>
66 #include <FL/Fl_Gl_Window.H>
67 #include <FL/names.h>
68 #include <FL/Fl_Menu_Bar.H>
69 #include <FL/Fl_Menu_Button.H>
70 #include <FL/Fl_Output.H>
71 #include <FL/Fl_Window.H>
72 #include <FL/fl_ask.H>
73 #include <FL/fl_draw.H>
74 #include <FL/gl.h>
75 
76 // FLTK headers may include X11/X.h which defines Complex, and that
77 // conflicts with Octave's Complex typedef. We don't need the X11
78 // Complex definition in this file, so remove it before including Octave
79 // headers which may require Octave's Complex typedef.
80 #undef Complex
81 
82 #include "cmd-edit.h"
83 #include "lo-ieee.h"
84 #include "oct-env.h"
85 
86 #include "display.h"
87 #include "file-ops.h"
88 #include "gl-render.h"
89 #include "gl2ps-print.h"
90 #include "graphics.h"
91 #include "parse.h"
92 #include "interpreter.h"
93 #include "variables.h"
94 
95 #define FLTK_GRAPHICS_TOOLKIT_NAME "fltk"
96 
97 const char* help_text = "\
98 Keyboard Shortcuts\n\
99 a - autoscale\n\
100 p - pan/zoom\n\
101 r - rotate\n\
102 g - toggle grid\n\
103 \n\
104 Mouse\n\
105 left drag - pan\n\
106 mouse wheel - zoom\n\
107 right drag - rectangle zoom\n\
108 left double click - autoscale\n\
109 ";
110 
111 class OpenGL_fltk : public Fl_Gl_Window
112 {
113 public:
114  OpenGL_fltk (int xx, int yy, int ww, int hh, double num)
115  : Fl_Gl_Window (xx, yy, ww, hh, 0), number (num), renderer (),
116  in_zoom (false), zoom_box ()
117  {
118 #if defined (HAVE_OPENGL)
119  // Ask for double buffering and a depth buffer.
120  mode (FL_DEPTH | FL_DOUBLE | FL_MULTISAMPLE);
121 #else
122  err_disabled_feature ("OpenGL_fltk", "OpenGL");
123 #endif
124  }
125 
126  ~OpenGL_fltk (void) { }
127 
128  void zoom (bool z)
129  {
130  in_zoom = z;
131  if (! in_zoom)
132  hide_overlay ();
133  }
134 
135  bool zoom (void) { return in_zoom; }
136  void set_zoom_box (const Matrix& zb) { zoom_box = zb; }
137 
138  void print (const std::string& cmd, const std::string& term)
139  {
140  //std::cout << "OpenGL_fltk::print(cmd=" << cmd << ", term=" << term << ") canvas size = " << w () << "x" << h () << std::endl;
141 
143  }
144 
145  void resize (int xx, int yy, int ww, int hh)
146  {
147 #if defined (HAVE_OPENGL)
148 
149  Fl_Gl_Window::resize (xx, yy, ww, hh);
150 
151 #else
152  // This shouldn't happen because construction of Opengl_fltk
153  // objects is supposed to be impossible if OpenGL is not available.
154 
155  panic_impossible ();
156 #endif
157  }
158 
159  bool renumber (double new_number)
160  {
161  bool retval = false;
162 
163  if (number != new_number)
164  {
165  number = new_number;
166  retval = true;
167  }
168 
169  return retval;
170  }
171 
172 private:
173  double number;
174  octave::opengl_renderer renderer;
175  bool in_zoom;
176  // (x1,y1,x2,y2)
177  Matrix zoom_box;
178 
179  void draw (void)
180  {
181 #if defined (HAVE_OPENGL)
182 
183  if (! valid ())
184  {
185  glMatrixMode (GL_PROJECTION);
186  glLoadIdentity ();
187  glViewport (0, 0, w (), h ());
188  }
189 
190  renderer.draw (gh_manager::get_object (number));
191 
192  if (zoom ())
193  overlay ();
194 
195 #else
196  // This shouldn't happen because construction of Opengl_fltk
197  // objects is supposed to be impossible if OpenGL is not available.
198 
199  panic_impossible ();
200 #endif
201  }
202 
203  void zoom_box_vertex (void)
204  {
205 #if defined (HAVE_OPENGL)
206 
207  glVertex2d (zoom_box(0), h () - zoom_box(1));
208  glVertex2d (zoom_box(0), h () - zoom_box(3));
209  glVertex2d (zoom_box(2), h () - zoom_box(3));
210  glVertex2d (zoom_box(2), h () - zoom_box(1));
211  glVertex2d (zoom_box(0), h () - zoom_box(1));
212 
213 #else
214  // This shouldn't happen because construction of Opengl_fltk
215  // objects is supposed to be impossible if OpenGL is not available.
216 
217  panic_impossible ();
218 #endif
219  }
220 
221  void overlay (void)
222  {
223 #if defined (HAVE_OPENGL)
224 
225  glMatrixMode (GL_MODELVIEW);
226  glPushMatrix ();
227  glLoadIdentity ();
228 
229  glMatrixMode (GL_PROJECTION);
230  glPushMatrix ();
231  glLoadIdentity ();
232  gluOrtho2D (0.0, w (), 0.0, h ());
233 
234  glPushAttrib (GL_DEPTH_BUFFER_BIT | GL_CURRENT_BIT);
235  glDisable (GL_DEPTH_TEST);
236 
237  glBegin (GL_POLYGON);
238  glColor4f (0.45, 0.62, 0.81, 0.1);
239  zoom_box_vertex ();
240  glEnd ();
241 
242  glLineWidth (1.5);
243  glBegin (GL_LINE_STRIP);
244  glColor4f (0.45, 0.62, 0.81, 0.9);
245  zoom_box_vertex ();
246  glEnd ();
247 
248  glPopAttrib ();
249  glMatrixMode (GL_MODELVIEW);
250  glPopMatrix ();
251  glMatrixMode (GL_PROJECTION);
252  glPopMatrix ();
253 
254 #else
255  // This shouldn't happen because construction of Opengl_fltk
256  // objects is supposed to be impossible if OpenGL is not available.
257 
258  panic_impossible ();
259 #endif
260  }
261 
262  int handle (int event)
263  {
264 #if defined (HAVE_OPENGL)
265 
266  switch (event)
267  {
268  case FL_ENTER:
269  cursor (FL_CURSOR_CROSS);
270  return 1;
271 
272  case FL_LEAVE:
273  cursor (FL_CURSOR_DEFAULT);
274  return 1;
275  }
276 
277  return Fl_Gl_Window::handle (event);
278 
279 #else
280  // This shouldn't happen because construction of Opengl_fltk
281  // objects is supposed to be impossible if OpenGL is not available.
282 
283  panic_impossible ();
284 #endif
285  }
286 };
287 
288 void script_cb (Fl_Widget*, void* data)
289 {
290  static_cast<uimenu::properties*> (data)->execute_callback ();
291 }
292 
293 
294 class fltk_uimenu
295 {
296 public:
297  fltk_uimenu (int xx, int yy, int ww, int hh)
298  {
299  menubar = new Fl_Menu_Bar (xx, yy, ww, hh);
300  }
301 
302  int items_to_show (void)
303  {
304  //returns the number of visible menu items
305  int len = menubar->size ();
306  int n = 0;
307  for (int t = 0; t < len; t++)
308  {
309  const Fl_Menu_Item *m = static_cast<const Fl_Menu_Item*> (&
310  (menubar->menu ()[t]));
311  if (m->label () && m->visible ())
312  n++;
313  }
314 
315  return n;
316  }
317 
318  void show (void)
319  {
320  menubar->show ();
321  menubar->redraw ();
322  }
323 
324  void hide (void)
325  {
326  menubar->hide ();
327  menubar->redraw ();
328  }
329 
330  bool is_visible (void)
331  {
332  return menubar->visible ();
333  }
334 
335  int find_index_by_name (const std::string& findname)
336  {
337  // This function is derived from Greg Ercolano's function
338  // int GetIndexByName(...), see:
339  // http://seriss.com/people/erco/fltk/#Menu_ChangeLabel
340  // He agreed via PM that it can be included in octave using GPLv3
341  // Kai Habel (14.10.2010)
342 
343  std::string menupath;
344  for (int t = 0; t < menubar->size (); t++)
345  {
346  Fl_Menu_Item *m = const_cast<Fl_Menu_Item*> (&(menubar->menu ()[t]));
347  if (m->submenu ())
348  {
349  // item has submenu
350  if (! menupath.empty ())
351  menupath += "/";
352  menupath += m->label ();
353 
354  if (menupath == findname)
355  return (t);
356  }
357  else
358  {
359  // End of submenu? Pop back one level.
360  if (! m->label ())
361  {
362  size_t idx = menupath.find_last_of ("/");
363  if (idx != std::string::npos)
364  menupath.erase (idx);
365  else
366  menupath.clear ();
367  continue;
368  }
369  // Menu item?
370  std::string itempath = menupath;
371  if (! itempath.empty ())
372  itempath += "/";
373  itempath += m->label ();
374 
375  if (itempath == findname)
376  return (t);
377  }
378  }
379  return (-1);
380  }
381 
382  Matrix find_uimenu_children (uimenu::properties& uimenup) const
383  {
384  Matrix uimenu_childs = uimenup.get_all_children ();
385  Matrix retval = do_find_uimenu_children (uimenu_childs);
386  return retval;
387  }
388 
389  Matrix find_uimenu_children (figure::properties& figp) const
390  {
391  Matrix uimenu_childs = figp.get_all_children ();
392  Matrix retval = do_find_uimenu_children (uimenu_childs);
393  return retval;
394  }
395 
396  Matrix do_find_uimenu_children (Matrix uimenu_childs) const
397  {
398  octave_idx_type k = 0;
399 
400  Matrix pos = Matrix (uimenu_childs.numel (), 1);
401 
402  for (octave_idx_type ii = 0; ii < uimenu_childs.numel (); ii++)
403  {
404  graphics_object kidgo = gh_manager::get_object (uimenu_childs (ii));
405 
406  if (kidgo.valid_object () && kidgo.isa ("uimenu"))
407  {
408  uimenu_childs(k) = uimenu_childs(ii);
409  pos(k++) =
410  dynamic_cast<uimenu::properties&>
411  (kidgo.get_properties ()).get_position ();
412  }
413  }
414 
415  uimenu_childs.resize (k, 1);
416  pos.resize (k, 1);
417  Matrix retval = Matrix (k, 1);
418  // Don't know if this is the best method to sort.
419  // Can we avoid the for loop?
421  for (octave_idx_type ii = 0; ii < k; ii++)
422  retval(ii) = uimenu_childs (sidx(ii));
423 
424  return retval;
425  }
426 
427  void delete_entry (uimenu::properties& uimenup)
428  {
429  std::string fltk_label = uimenup.get_fltk_label ();
430  int idx = find_index_by_name (fltk_label.c_str ());
431 
432  if (idx >= 0)
433  menubar->remove (idx);
434  }
435 
436  void update_accelerator (uimenu::properties& uimenup)
437  {
438  std::string fltk_label = uimenup.get_fltk_label ();
439  if (! fltk_label.empty ())
440  {
441  Fl_Menu_Item* item = const_cast<Fl_Menu_Item*> (menubar->find_item (
442  fltk_label.c_str ()));
443  if (item)
444  {
445  std::string acc = uimenup.get_accelerator ();
446  if (acc.length () > 0)
447  {
448  int key = FL_CTRL + acc[0];
449  item->shortcut (key);
450  }
451  }
452  }
453  }
454 
455  void update_callback (uimenu::properties& uimenup)
456  {
457  std::string fltk_label = uimenup.get_fltk_label ();
458  if (! fltk_label.empty ())
459  {
460  Fl_Menu_Item* item = const_cast<Fl_Menu_Item*> (menubar->find_item (
461  fltk_label.c_str ()));
462  if (item)
463  {
464  if (! uimenup.get_callback ().is_empty ())
465  item->callback (static_cast<Fl_Callback*> (script_cb),
466  static_cast<void*> (&uimenup));
467  else
468  item->callback (0, static_cast<void*> (0));
469  }
470  }
471  }
472 
473  void update_enable (uimenu::properties& uimenup)
474  {
475  std::string fltk_label = uimenup.get_fltk_label ();
476  if (! fltk_label.empty ())
477  {
478  Fl_Menu_Item* item = const_cast<Fl_Menu_Item*> (menubar->find_item (
479  fltk_label.c_str ()));
480  if (item)
481  {
482  if (uimenup.is_enable ())
483  item->activate ();
484  else
485  item->deactivate ();
486  }
487  }
488  }
489 
490  void update_foregroundcolor (uimenu::properties& uimenup)
491  {
492  std::string fltk_label = uimenup.get_fltk_label ();
493  if (! fltk_label.empty ())
494  {
495  Fl_Menu_Item* item = const_cast<Fl_Menu_Item*> (menubar->find_item (
496  fltk_label.c_str ()));
497  if (item)
498  {
499  Matrix rgb = uimenup.get_foregroundcolor_rgb ();
500 
501  uchar r = static_cast<uchar> (std::floor (rgb (0) * 255));
502  uchar g = static_cast<uchar> (std::floor (rgb (1) * 255));
503  uchar b = static_cast<uchar> (std::floor (rgb (2) * 255));
504 
505  item->labelcolor (fl_rgb_color (r, g, b));
506  }
507  }
508  }
509 
510  void update_seperator (const uimenu::properties& uimenup)
511  {
512  // Matlab places the separator before the current
513  // menu entry, while fltk places it after. So we need to find
514  // the previous item in this menu/submenu. (Kai)
515  std::string fltk_label = uimenup.get_fltk_label ();
516  if (! fltk_label.empty ())
517  {
518  int itemflags = 0, idx;
519  int curr_idx = find_index_by_name (fltk_label.c_str ());
520 
521  for (idx = curr_idx - 1; idx >= 0; idx--)
522  {
523  Fl_Menu_Item* item
524  = const_cast<Fl_Menu_Item*> (&menubar->menu () [idx]);
525  itemflags = item->flags;
526  if (item->label ())
527  break;
528  }
529 
530  if (idx >= 0 && idx < menubar->size ())
531  {
532  if (uimenup.is_separator ())
533  {
534  if (idx >= 0 && !(itemflags & FL_SUBMENU))
535  menubar->mode (idx, itemflags | FL_MENU_DIVIDER);
536  }
537  else
538  menubar->mode (idx, itemflags & (~FL_MENU_DIVIDER));
539  }
540  }
541  }
542 
543  void update_visible (uimenu::properties& uimenup)
544  {
545  std::string fltk_label = uimenup.get_fltk_label ();
546  if (! fltk_label.empty ())
547  {
548  Fl_Menu_Item* item
549  = const_cast<Fl_Menu_Item*> (menubar->find_item (fltk_label.c_str ()));
550  if (item)
551  {
552  if (uimenup.is_visible ())
553  item->show ();
554  else
555  item->hide ();
556  }
557  }
558  }
559 
560  void update_position (uimenu::properties& uimenup, int pos)
561  {
562  uimenup.get_property ("position").set (octave_value (static_cast<double> (pos)),
563  true, false);
564  }
565 
566  void add_entry (uimenu::properties& uimenup)
567  {
568 
569  std::string fltk_label = uimenup.get_fltk_label ();
570 
571  if (! fltk_label.empty ())
572  {
573  bool item_added = false;
574  do
575  {
576  const Fl_Menu_Item* item
577  = menubar->find_item (fltk_label.c_str ());
578 
579  if (item)
580  {
581  //avoid duplicate menulabels
582  size_t idx1 = fltk_label.find_last_of ("(");
583  size_t idx2 = fltk_label.find_last_of (")");
584  int len = idx2 - idx1;
585  int val = 1;
586  if (len > 0)
587  {
588  std::string valstr = fltk_label.substr (idx1 + 1, len - 1);
589  fltk_label.erase (idx1, len + 1);
590  val = atoi (valstr.c_str ());
591  if (val > 0 && val < 99)
592  val++;
593  }
594  std::ostringstream valstream;
595  valstream << val;
596  fltk_label += "(" + valstream.str () + ")";
597  }
598  else
599  {
600  Matrix uimenu_ch = find_uimenu_children (uimenup);
601  int len = uimenu_ch.numel ();
602  int flags = 0;
603  if (len > 0)
604  flags = FL_SUBMENU;
605  if (len == 0 && uimenup.is_checked ())
606  flags += FL_MENU_TOGGLE + FL_MENU_VALUE;
607  menubar->add (fltk_label.c_str (), 0, 0, 0, flags);
608  item_added = true;
609  }
610  }
611  while (! item_added);
612  uimenup.set_fltk_label (fltk_label);
613  }
614  }
615 
616  void add_to_menu (uimenu::properties& uimenup)
617  {
618  std::vector<int> delayed_menus;
619  Matrix kids = find_uimenu_children (uimenup);
620  int len = kids.numel ();
621  std::string fltk_label = uimenup.get_fltk_label ();
622  int count = 0;
623 
624  add_entry (uimenup);
625  update_foregroundcolor (uimenup);
626  update_callback (uimenup);
627  update_accelerator (uimenup);
628  update_enable (uimenup);
629  update_visible (uimenup);
630  update_seperator (uimenup);
631 
632  for (octave_idx_type ii = 0; ii < len; ii++)
633  {
634  graphics_object kgo = gh_manager::get_object (kids (len - (ii + 1)));
635  if (kgo.valid_object ())
636  {
637  uimenu::properties& kprop = dynamic_cast<uimenu::properties&>
638  (kgo.get_properties ());
639 
640  // if no pos yet, delay adding menu until after other menus
641  int pos = kprop.get_position ();
642  if (pos <= 0)
643  delayed_menus.push_back ((len - (ii + 1)));
644  else
645  {
646  add_to_menu (kprop);
647  }
648  }
649  }
650 
651  // create any delayed menus
652  for (size_t ii = 0; ii < delayed_menus.size (); ii++)
653  {
654  graphics_object kgo = gh_manager::get_object (kids (delayed_menus[ii]));
655 
656  if (kgo.valid_object ())
657  {
658  uimenu::properties& kprop = dynamic_cast<uimenu::properties&>
659  (kgo.get_properties ());
660  add_to_menu (kprop);
661  update_position (kprop, ++count);
662  }
663  }
664  }
665 
666  void add_to_menu (figure::properties& figp)
667  {
668  std::vector<int> delayed_menus;
669  Matrix kids = find_uimenu_children (figp);
670  int len = kids.numel ();
671  int count = 0;
672  menubar->clear ();
673  for (octave_idx_type ii = 0; ii < len; ii++)
674  {
675  graphics_object kgo = gh_manager::get_object (kids (len - (ii + 1)));
676 
677  if (kgo.valid_object ())
678  {
679  uimenu::properties& kprop = dynamic_cast<uimenu::properties&>
680  (kgo.get_properties ());
681 
682  // if no pos yet, delay adding menu until after other menus
683  int pos = kprop.get_position ();
684  if (pos <= 0)
685  delayed_menus.push_back ((len - (ii + 1)));
686  else
687  {
688  add_to_menu (kprop);
689  update_position (kprop, ++count);
690  }
691  }
692  }
693 
694  // create any delayed menus
695  for (size_t ii = 0; ii < delayed_menus.size (); ii++)
696  {
697  graphics_object kgo = gh_manager::get_object (kids (delayed_menus[ii]));
698 
699  if (kgo.valid_object ())
700  {
701  uimenu::properties& kprop = dynamic_cast<uimenu::properties&>
702  (kgo.get_properties ());
703  add_to_menu (kprop);
704  update_position (kprop, ++count);
705  }
706  }
707  }
708 
709  template <typename T_prop>
710  void remove_from_menu (T_prop& prop)
711  {
712  Matrix kids;
713  std::string type = prop.get_type ();
714  kids = find_uimenu_children (prop);
715  int len = kids.numel ();
716 
717  for (octave_idx_type ii = 0; ii < len; ii++)
718  {
719  graphics_object kgo = gh_manager::get_object (kids (len - (ii + 1)));
720 
721  if (kgo.valid_object ())
722  {
723  uimenu::properties kprop = dynamic_cast<uimenu::properties&>
724  (kgo.get_properties ());
725  remove_from_menu (kprop);
726  }
727  }
728 
729  if (type == "uimenu")
730  delete_entry (dynamic_cast<uimenu::properties&> (prop));
731  else if (type == "figure")
732  menubar->clear ();
733  }
734 
735  ~fltk_uimenu (void)
736  {
737  delete menubar;
738  }
739 
740 private:
741 
742  // No copying!
743 
744  fltk_uimenu (const fltk_uimenu&);
745 
746  fltk_uimenu operator = (const fltk_uimenu&);
747 
748  Fl_Menu_Bar* menubar;
749 };
750 
751 #if defined (HAVE_X_WINDOWS)
752 static int
753 xerror_handler (Display *, XErrorEvent *)
754 {
755  return 0;
756 }
757 #endif
758 
759 class plot_window : public Fl_Window
760 {
761  friend class fltk_uimenu;
762 public:
763  plot_window (int xx, int yy, int ww, int hh, figure::properties& xfp,
764  bool internal)
765  : Fl_Window (xx, yy, ww, hh + menu_h + status_h + 2, "octave"),
766  window_label (), fp (xfp), canvas (0),
767  autoscale (0), togglegrid (0), panzoom (0), rotate (0), help (0),
768  status (0), resize_dummy (0), ax_obj (), pos_x (0), pos_y (0)
769  {
770  callback (window_close, static_cast<void*> (this));
771 
772  // The size of the resize_dummy box also determines the minimum window size
773  resize_dummy = new Fl_Box (5 * status_h, menu_h,
774  ww - 5 * status_h, hh);
775  // See http://fltk.org/articles.php?L415+I0+T+M1000+P1
776  // for how resizable works
777  resizable (resize_dummy);
778 
779  // FIXME: The function below is only available in FLTK >= 1.3
780  // At some point support for FLTK 1.1 will be dropped in Octave.
781  // At that point this function should be uncommented.
782  // The current solution is to call xclass() before show() for each window.
783  // Set WM_CLASS which allows window managers to properly group related
784  // windows. Otherwise, the class is just "FLTK"
785  //default_xclass ("Octave");
786 
787  uimenu = new fltk_uimenu (0, 0, ww, menu_h);
788  canvas = new OpenGL_fltk (0, menu_h, ww, hh, number ());
789 
790  // The bottom toolbar is a composite of "autoscale", "togglegrid",
791  // "panzoom", "rotate", "help", and "status".
792  // Only "status" should be resized.
793 
794  int toolbar_y = menu_h + hh + 1;
795  status = new Fl_Output (5 * status_h, toolbar_y,
796  ww - 5 * status_h, status_h, "");
797 
798  status->textcolor (FL_BLACK);
799  status->color (FL_GRAY);
800  status->textfont (FL_COURIER);
801  status->textsize (10);
802  status->box (FL_ENGRAVED_BOX);
803 
804  autoscale = new Fl_Button (0, toolbar_y, status_h, status_h, "A");
805  autoscale->callback (button_callback, static_cast<void*> (this));
806  autoscale->tooltip ("Autoscale");
807 
808  togglegrid = new Fl_Button (status_h, toolbar_y, status_h, status_h, "G");
809  togglegrid->callback (button_callback, static_cast<void*> (this));
810  togglegrid->tooltip ("Toggle Grid");
811 
812  panzoom = new Fl_Button (2* status_h, toolbar_y, status_h, status_h, "P");
813  panzoom->callback (button_callback, static_cast<void*> (this));
814  panzoom->tooltip ("Mouse Pan/Zoom");
815 
816  rotate = new Fl_Button (3 * status_h, toolbar_y, status_h, status_h, "R");
817  rotate->callback (button_callback, static_cast<void*> (this));
818  rotate->tooltip ("Mouse Rotate");
819 
820  help = new Fl_Button (4 * status_h, toolbar_y, status_h, status_h, "?");
821  help->callback (button_callback, static_cast<void*> (this));
822  help->tooltip ("Help");
823 
824  end ();
825 
826  set_name ();
827  uimenu->add_to_menu (fp);
828  if (fp.menubar_is ("none") || ! uimenu->items_to_show ())
829  hide_menubar ();
830 
831  update_boundingbox (internal);
832 
833  if (fp.is_visible ())
834  {
835  // FIXME: This code should be removed when Octave drops support
836  // for FLTK 1.1. Search for default_xclass in this file to find
837  // code that should be uncommented to take its place.
838  //
839  // Set WM_CLASS which allows window managers to properly group
840  // related windows. Otherwise, the class is just "FLTK"
841  xclass ("Octave");
842 
843  show ();
844 
845 #if defined (HAVE_X_WINDOWS)
846  std::string show_gui_msgs
847  = octave::sys::env::getenv ("OCTAVE_SHOW_GUI_MESSAGES");
848 
849  // Installing our handler suppresses the messages.
850  if (show_gui_msgs.empty ())
851  XSetErrorHandler (xerror_handler);
852 #endif
853 
854  if (fp.get_currentaxes ().ok ())
855  show_canvas ();
856  else
857  hide_canvas ();
858  }
859  }
860 
861  ~plot_window (void)
862  {
863  this->hide ();
864  Fl::check ();
865  }
866 
867  double number (void) { return fp.get___myhandle__ ().value (); }
868 
869  void renumber (double new_number)
870  {
871  if (! canvas)
872  error ("unable to renumber figure");
873 
874  if (canvas->renumber (new_number))
875  mark_modified ();
876  }
877 
878  void print (const std::string& cmd, const std::string& term)
879  {
880  canvas->print (cmd, term);
881  }
882 
883  void show_menubar (void)
884  {
885  uimenu->show ();
886  update_toolbar_position ();
887  }
888 
889  void hide_menubar (void)
890  {
891  uimenu->hide ();
892  update_toolbar_position ();
893  }
894 
895  void uimenu_update (const graphics_handle& gh, int id)
896  {
897  graphics_object uimenu_obj = gh_manager::get_object (gh);
898 
899  if (uimenu_obj.valid_object () && uimenu_obj.isa ("uimenu"))
900  {
901  uimenu::properties& uimenup =
902  dynamic_cast<uimenu::properties&> (uimenu_obj.get_properties ());
903  std::string fltk_label = uimenup.get_fltk_label ();
904  graphics_object fig = uimenu_obj.get_ancestor ("figure");
905  figure::properties& figp =
906  dynamic_cast<figure::properties&> (fig.get_properties ());
907 
908  switch (id)
909  {
911  uimenu->remove_from_menu (uimenup);
912  break;
913 
915  uimenu->update_visible (uimenup);
916  break;
917 
919  uimenu->update_accelerator (uimenup);
920  break;
921 
923  uimenu->update_callback (uimenup);
924  break;
925 
927  uimenu->add_to_menu (figp);//rebuilding entire menu
928  break;
929 
931  uimenu->update_enable (uimenup);
932  break;
933 
935  uimenu->update_foregroundcolor (uimenup);
936  break;
937 
939  uimenu->add_to_menu (figp);//rebuilding entire menu
940  break;
941 
943  uimenu->add_to_menu (figp);//rebuilding entire menu
944  break;
945 
947  uimenu->update_seperator (uimenup);
948  break;
949  }
950 
951  if (uimenu->items_to_show ())
952  show_menubar ();
953  else
954  hide_menubar ();
955  }
956  }
957 
958  void show_canvas (void)
959  {
960  if (! canvas->can_do ())
961  error ("unable to plot due to insufficient OpenGL support");
962  else if (fp.is_visible ())
963  {
964  canvas->show ();
965  canvas->make_current ();
966  }
967  }
968 
969  void hide_canvas (void)
970  {
971  canvas->hide ();
972  }
973 
974  // Move the toolbar at the bottom of the plot_window.
975  // The only reason for moving the toolbar is hiding and
976  // showing the menubar. All other resizing is done by fltk.
977 
978  void update_toolbar_position ()
979  {
980  int old_canvas_h = canvas->h ();
981 
982  // keep position fix, change outerposition accordingly
983  update_boundingbox (true);
984  canvas->resize (0, menu_dy (), w (), old_canvas_h);
985 
986  int toolbar_y = canvas->h () + menu_dy () + 1;
987  autoscale->position (0, toolbar_y);
988  togglegrid->position (status_h, toolbar_y);
989  panzoom->position (2 * status_h, toolbar_y);
990  rotate->position (3 * status_h, toolbar_y);
991  help->position (4 * status_h, toolbar_y);
992  status->resize (5 * status_h, toolbar_y,
993  w () - 5 * status_h, status_h);
994  init_sizes ();
995  redraw ();
996  }
997 
998  Matrix outerposition2position (const Matrix& outerpos)
999  {
1000  Matrix pos = outerpos;
1001  pos(1) += menu_dy ();
1002  pos(3) -= menu_dy () + status_h + 2;
1003  return pos;
1004  }
1005 
1006  Matrix position2outerposition (const Matrix& pos)
1007  {
1008  Matrix outerpos = pos;
1009  outerpos(1) -= menu_dy ();
1010  outerpos(3) += menu_dy () + status_h + 2;
1011  return outerpos;
1012  }
1013 
1014  // Called from figure::properties::ID_POSITION if internal = true
1015  // or ID_OUTERPOSITION if false.
1016  // (someone has requested a position change with set (h, "position", [...])
1017  // or set (h, "outerposition", [...])
1018 
1019  void update_boundingbox (bool internal)
1020  {
1021  Matrix bb = fp.get_boundingbox (internal);
1022  if (internal)
1023  bb = position2outerposition (bb);
1024  resize (bb(0), bb(1), bb(2), bb(3));
1025  }
1026 
1027  void mark_modified (void)
1028  {
1029  canvas->redraw ();
1030  }
1031 
1032  void set_name (void)
1033  {
1034  window_label = fp.get_title ();
1035  label (window_label.c_str ());
1036  }
1037 
1038 private:
1039 
1040  // No copying!
1041 
1042  plot_window (const plot_window&);
1043 
1044  plot_window& operator = (const plot_window&);
1045 
1046  // window name -- this must exists for the duration of the window's
1047  // life
1048  std::string window_label;
1049 
1050  // Figure properties.
1051  figure::properties& fp;
1052 
1053  // Status area height.
1054  static const int status_h = 20;
1055 
1056  // Menu height
1057  static const int menu_h = 25;
1058 
1059  // Window callback.
1060  static void window_close (Fl_Widget*, void* data)
1061  {
1063  args(0) = static_cast<plot_window*> (data)->number ();
1064  feval ("close", args);
1065  }
1066 
1067  // Button callbacks.
1068  static void button_callback (Fl_Widget* ww, void* data)
1069  {
1070  static_cast<plot_window*> (data)->button_press (ww, data);
1071  }
1072 
1073  void button_press (Fl_Widget* widg, void*)
1074  {
1075  if (widg == autoscale)
1076  axis_auto ();
1077  else if (widg == togglegrid)
1078  toggle_grid ();
1079  else if (widg == panzoom)
1080  fp.set___mouse_mode__ ("pan");
1081  else if (widg == rotate)
1082  fp.set___mouse_mode__ ("rotate");
1083  else if (widg == help)
1084  fl_message ("%s", help_text);
1085  }
1086 
1087  void set_on_ax_obj (const std::string& name, const std::string& value)
1088  {
1089  // ax_obj is the last clicked axes object
1090  if (ax_obj && ax_obj.isa ("axes")
1091  && ax_obj.get_properties ().get_tag () != "legend"
1092  && ax_obj.get_properties ().get_tag () != "colorbar")
1093  {
1094  axes::properties& ap =
1095  dynamic_cast<axes::properties&>(ax_obj.get_properties ());
1096  ap.set (name, value);
1097  }
1098  else // no axes object clicked so far, take currentaxes
1099  {
1100  graphics_handle gh = fp.get_currentaxes ();
1101  if (gh.ok ())
1102  {
1104  axes::properties& ap =
1105  dynamic_cast<axes::properties&>(go.get_properties ());
1106  ap.set (name, value);
1107  }
1108  }
1109  }
1110 
1111  fltk_uimenu* uimenu;
1112  OpenGL_fltk* canvas;
1113  Fl_Button* autoscale;
1114  Fl_Button* togglegrid;
1115  Fl_Button* panzoom;
1116  Fl_Button* rotate;
1117  Fl_Button* help;
1118  Fl_Output* status;
1119  Fl_Box* resize_dummy;
1120  graphics_object ax_obj;
1121  int pos_x;
1122  int pos_y;
1123 
1124  void axis_auto (void)
1125  {
1127  if (fp.get_currentaxes ().ok ())
1128  {
1129  args(0) = fp.get_currentaxes ().as_octave_value ();
1130  args(1) = "auto";
1131  feval ("axis", args);
1132  mark_modified ();
1133  }
1134  }
1135 
1136  void toggle_grid (void)
1137  {
1139  if (fp.get_currentaxes ().ok ())
1140  args(0) = fp.get_currentaxes ().as_octave_value ();
1141 
1142  feval ("grid", args);
1143  mark_modified ();
1144  }
1145 
1146  void pixel2pos (const graphics_handle& ax, int px, int py, double& xx,
1147  double& yy) const
1148  {
1149  pixel2pos (gh_manager::get_object (ax), px, py, xx, yy);
1150  }
1151 
1152  void pixel2pos (graphics_object ax, int px, int py, double& xx,
1153  double& yy) const
1154  {
1155  if (ax && ax.isa ("axes"))
1156  {
1157  axes::properties& ap =
1158  dynamic_cast<axes::properties&> (ax.get_properties ());
1159  ColumnVector pp = ap.pixel2coord (px, py);
1160  xx = pp(0);
1161  yy = pp(1);
1162  }
1163  }
1164 
1165  graphics_handle pixel2axes_or_ca (int px, int py)
1166  {
1167  Matrix kids = fp.get_children ();
1168  int len = kids.numel ();
1169 
1170  for (int k = 0; k < len; k++)
1171  {
1172  graphics_handle hnd = gh_manager::lookup (kids(k));
1173 
1174  if (hnd.ok ())
1175  {
1177 
1178  if (kid.valid_object () && kid.isa ("axes"))
1179  {
1180  Matrix bb = kid.get_properties ().get_boundingbox (false);
1181 
1182  if (bb(0) <= px && px < (bb(0)+bb(2))
1183  && bb(1) <= py && py < (bb(1)+bb(3)))
1184  {
1185  return hnd;
1186  }
1187  }
1188  }
1189  }
1190  return fp.get_currentaxes ();
1191  }
1192 
1193  void pixel2status (const graphics_handle& ax, int px0, int py0,
1194  int px1 = -1, int py1 = -1)
1195  {
1196  pixel2status (gh_manager::get_object (ax), px0, py0, px1, py1);
1197  }
1198 
1199  void pixel2status (graphics_object ax, int px0, int py0,
1200  int px1 = -1, int py1 = -1)
1201  {
1202  double x0, y0, x1, y1;
1203  x0 = y0 = x1 = y1 = octave::numeric_limits<double>::NaN ();
1204  std::stringstream cbuf;
1205  cbuf.precision (4);
1206  cbuf.width (6);
1207  pixel2pos (ax, px0, py0, x0, y0);
1208  cbuf << "[" << x0 << ", " << y0 << "]";
1209  if (px1 >= 0)
1210  {
1211  pixel2pos (ax, px1, py1, x1, y1);
1212  cbuf << " -> ["<< x1 << ", " << y1 << "]";
1213  }
1214 
1215  status->value (cbuf.str ().c_str ());
1216  }
1217 
1218  void view2status (graphics_object ax)
1219  {
1220  if (ax && ax.isa ("axes"))
1221  {
1222  axes::properties& ap =
1223  dynamic_cast<axes::properties&> (ax.get_properties ());
1224  std::stringstream cbuf;
1225  cbuf.precision (4);
1226  cbuf.width (6);
1227  Matrix v (1,2,0);
1228  v = ap.get ("view").matrix_value ();
1229  cbuf << "[azimuth: " << v(0) << ", elevation: " << v(1) << "]";
1230 
1231  status->value (cbuf.str ().c_str ());
1232  }
1233  }
1234 
1235  void set_currentpoint (int px, int py)
1236  {
1237  if (! fp.is_beingdeleted ())
1238  {
1239  Matrix pos = fp.map_from_boundingbox (px, py);
1240  fp.set_currentpoint (pos);
1243  dynamic_cast<root_figure::properties&> (robj.get_properties ());
1245  }
1246  }
1247 
1248  void set_axes_currentpoint (graphics_object ax, int px, int py)
1249  {
1250  if (ax.valid_object () && ax.isa ("axes"))
1251  {
1252  axes::properties& ap =
1253  dynamic_cast<axes::properties&> (ax.get_properties ());
1254 
1255  Matrix x_zlim = ap.get_transform_zlim ();
1256  Matrix pos (2, 3, 0.0);
1257 
1258  // front point (nearest to the viewer)
1259  ColumnVector tmp = ap.get_transform ().untransform (px, py, x_zlim(0));
1260  pos(0,0) = tmp(0);
1261  pos(0,1) = tmp(1);
1262  pos(0,2) = tmp(2);
1263 
1264  // back point (furthest from the viewer)
1265  tmp = ap.get_transform ().untransform (px, py, x_zlim(1));
1266  pos(1,0) = tmp(0);
1267  pos(1,1) = tmp(1);
1268  pos(1,2) = tmp(2);
1269 
1270  ap.set_currentpoint (pos);
1271  if (ap.get_tag () != "legend" && ap.get_tag () != "colorbar")
1272  fp.set_currentaxes (ap.get___myhandle__ ().value ());
1273  }
1274  }
1275 
1276  int menu_dy ()
1277  {
1278  if (uimenu->is_visible ())
1279  return menu_h;
1280  else
1281  return 0;
1282  }
1283 
1284  octave_scalar_map format_key_event (int e_key, const char* e_text, int e_state)
1285  {
1286  octave_scalar_map evt;
1287 
1288  evt.assign ("Character", octave_value (e_text));
1289  evt.assign ("Modifier", octave_value (modifier2cell (e_state)));
1290 
1291  std::string key_str;
1292  std::ostringstream tmp_str;
1293 
1294  if (e_key == FL_Escape)
1295  key_str = "escape";
1296  else if (e_key == FL_Tab)
1297  key_str = "tab";
1298  else if (e_key == FL_Caps_Lock)
1299  key_str = "capslock";
1300  else if (e_key == FL_Shift_L || e_key == FL_Shift_R)
1301  key_str = "shift";
1302  else if (e_key == FL_Control_L || e_key == FL_Control_R)
1303  key_str = "control";
1304  else if (e_key == FL_Meta_L || e_key == FL_Meta_R)
1305  key_str = "windows";
1306  else if (e_key == FL_Alt_L || e_key == FL_Alt_R)
1307  key_str = "alt";
1308  else if (e_key == 32)
1309  key_str = "space";
1310  else if (e_key == FL_Enter)
1311  key_str = "return";
1312  else if (e_key == FL_BackSpace)
1313  key_str = "backspace";
1314  else if (e_key == FL_Print)
1315  key_str = "printscreen";
1316  else if (e_key == FL_Pause)
1317  key_str = "pause";
1318  else if (e_key == FL_Home)
1319  key_str = "home";
1320  else if (e_key == FL_End)
1321  key_str = "end";
1322  else if (e_key == FL_Insert)
1323  key_str = "insert";
1324  else if (e_key == FL_Page_Up)
1325  key_str = "pageup";
1326  else if (e_key == FL_Delete)
1327  key_str = "delete";
1328  else if (e_key == FL_Page_Down)
1329  key_str = "pagedown";
1330  else if (e_key == FL_Left)
1331  key_str = "leftarrow";
1332  else if (e_key == FL_Up)
1333  key_str = "uparrow";
1334  else if (e_key == FL_Right)
1335  key_str = "rightarrow";
1336  else if (e_key == FL_Down)
1337  key_str = "downarrow";
1338  else if (e_key == FL_Num_Lock)
1339  key_str = "numlock";
1340  else if (e_key == 0xffaf)
1341  key_str = "divide";
1342  else if (e_key == 0xffaa)
1343  key_str = "multiply";
1344  else if (e_key == 0xffad)
1345  key_str = "subtract";
1346  else if (e_key == 0xffab)
1347  key_str = "add";
1348  else if (e_key == 0xff8d)
1349  key_str = "return";
1350  else if (e_key == 0xffac)
1351  key_str = "separator";
1352  else if (e_key >= 0xffb0 && e_key <= 0xffb9)
1353  {
1354  tmp_str << "numpad" << (e_key - 0xffb0);
1355  key_str = tmp_str.str ();
1356  }
1357  else if (e_key >= (FL_F + 1) && e_key <= (FL_F + 12))
1358  {
1359  tmp_str << "f" << (e_key - FL_F);
1360  key_str = tmp_str.str ();
1361  }
1362  else if (e_key == ',')
1363  key_str = "comma";
1364  else if (e_key == '.')
1365  key_str = "period";
1366  else if (e_key == '-')
1367  key_str = "hyphen";
1368  else if (e_key == '^' || e_key == '+' || e_key == '#'
1369  || e_key == '<' || e_key == 0xfe03 /*AltGr*/)
1370  key_str = "0";
1371  else if (isalnum (e_key))
1372  key_str = std::tolower (e_key);
1373  else if (isprint (e_text[0]))
1374  key_str = "0";
1375 
1376  evt.assign ("Key", octave_value (key_str));
1377  return evt;
1378  }
1379 
1380  Cell modifier2cell (int e_state)
1381  {
1383 
1384  if (e_state & FL_SHIFT)
1385  mod.append (std::string ("shift"));
1386  if (e_state & FL_CTRL)
1387  mod.append (std::string ("control"));
1388  if (e_state & FL_ALT)
1389  mod.append (std::string ("alt"));
1390  if (e_state & FL_COMMAND)
1391  mod.append (std::string ("command"));
1392  return Cell (mod);
1393  }
1394 
1395  void resize (int xx, int yy, int ww, int hh)
1396  {
1397  Fl_Window::resize (xx, yy, ww, hh);
1398 
1399  Matrix bb (1, 4);
1400  bb(0) = xx;
1401  bb(1) = yy;
1402  bb(2) = ww;
1403  bb(3) = hh;
1404 
1405  // update outerposition
1406  fp.set_boundingbox (bb, false, false);
1407 
1408  // update position
1409  fp.set_boundingbox (outerposition2position (bb), true, false);
1410  }
1411 
1412  bool pan_enabled (void)
1413  {
1414  // Getting pan mode property:
1415  octave_value ov_pm = fp.get___pan_mode__ ();
1416 
1417  octave_scalar_map pm = ov_pm.scalar_map_value ();
1418 
1419  return pm.contents ("Enable").string_value () == "on";
1420  }
1421 
1422  std::string pan_mode (void)
1423  {
1424  // Getting pan mode property:
1425  octave_value ov_pm = fp.get___pan_mode__ ();
1426 
1427  octave_scalar_map pm = ov_pm.scalar_map_value ();
1428 
1429  return pm.contents ("Motion").string_value ();
1430  }
1431 
1432  bool rotate_enabled (void)
1433  {
1434  // Getting rotate mode property:
1435  octave_value ov_rm = fp.get___rotate_mode__ ();
1436 
1437  octave_scalar_map rm = ov_rm.scalar_map_value ();
1438 
1439  return rm.contents ("Enable").string_value () == "on";
1440  }
1441 
1442  int handle (int event)
1443  {
1444  if (event == FL_FOCUS)
1445  return 1;
1446 
1448 
1449  if (! fp.is_beingdeleted ())
1450  {
1451  //std::cout << "plot_window::handle event = " << fl_eventnames[event] << std::endl;
1452 
1453  // FLTK resends keyboard events with flipped case if all
1454  // widgets rejects the event.
1455  // See Event Propagation http://www.fltk.org/doc-1.3/events.html
1456  static bool key_resent_detected = false;
1457 
1458  switch (event)
1459  {
1460  case FL_SHORTCUT:
1461  {
1462  // check if it a resent event with switched case
1463  static int last_event_key = 0;
1464  static char last_event_text = 0;
1465 
1466  int e_key = Fl::event_key ();
1467  char e_text = Fl::event_text ()[0];
1468  key_resent_detected = (e_key == last_event_key
1469  && std::tolower (last_event_text) == std::tolower (e_text)
1470  && ((islower (last_event_text) && isupper (e_text))
1471  || (isupper (last_event_text) && islower (e_text))));
1472 
1473  last_event_key = e_key;
1474  last_event_text = e_text;
1475  }
1476  break;
1477 
1478  case FL_KEYDOWN:
1479  {
1480  int e_key = Fl::event_key ();
1481  const char *e_text = Fl::event_text ();
1482  int e_state = Fl::event_state ();
1483  octave_scalar_map evt = format_key_event (e_key, e_text, e_state);
1484 
1485  fp.set_currentcharacter (std::string (e_text));
1486 
1487  if (! fp.get_keypressfcn ().is_empty ()
1488  && (evt.contents ("Key").length () > 0))
1489  {
1490  // Update CurrentPoint before callback
1491  if (Fl::event_inside (canvas))
1492  {
1493  pos_x = Fl::event_x ();
1494  pos_y = Fl::event_y () - menu_dy ();
1495 
1496  set_currentpoint (pos_x, pos_y);
1497 
1498  gh = pixel2axes_or_ca (pos_x, pos_y);
1499 
1500  if (gh.ok ())
1501  {
1502  ax_obj = gh_manager::get_object (gh);
1503  set_axes_currentpoint (ax_obj, pos_x, pos_y);
1504  }
1505  }
1506 
1507  fp.execute_keypressfcn (evt);
1508  }
1509 
1510  // Handle special keys used in toolbar
1511  switch (e_key)
1512  {
1513  case 'a':
1514  case 'A':
1515  axis_auto ();
1516  return 1;
1517 
1518  case 'g':
1519  case 'G':
1520  toggle_grid ();
1521  return 1;
1522 
1523  case 'p':
1524  case 'P':
1525  fp.set___mouse_mode__ ("pan");
1526  return 1;
1527 
1528  case 'r':
1529  case 'R':
1530  fp.set___mouse_mode__ ("rotate");
1531  return 1;
1532  }
1533  }
1534  break;
1535 
1536  case FL_KEYUP:
1537  {
1538  int e_key = Fl::event_key ();
1539  int e_state = Fl::event_state ();
1540  octave_scalar_map evt;
1541  if (key_resent_detected && Fl::event_length () == 1)
1542  {
1543  // FLTK flipped the case of Fl::event_text because no
1544  // widget wanted the FL_KEYDOWN event.
1545  char tmp_e_text[2];
1546  tmp_e_text[0] = Fl::event_text ()[0];
1547  tmp_e_text[1] = 0;
1548  // Undo the case flip
1549  if (std::islower (tmp_e_text[0]))
1550  tmp_e_text[0] = std::toupper (tmp_e_text[0]);
1551  else
1552  tmp_e_text[0] = std::tolower (tmp_e_text[0]);
1553  evt = format_key_event (e_key, tmp_e_text, e_state);
1554  }
1555  else
1556  {
1557  const char *e_text = Fl::event_text ();
1558  evt = format_key_event (e_key, e_text, e_state);
1559  }
1560 
1561  if (! fp.get_keyreleasefcn ().is_empty ()
1562  && (evt.contents ("Key").length () > 0))
1563  fp.execute_keyreleasefcn (evt);
1564  return 1;
1565  }
1566  break;
1567  }
1568 
1569  // Events we only handle if they are in the canvas area.
1570  if (Fl::event_inside (canvas))
1571  switch (event)
1572  {
1573  case FL_MOVE:
1574  pixel2status (pixel2axes_or_ca (Fl::event_x (),
1575  Fl::event_y () - menu_dy ()),
1576  Fl::event_x (), Fl::event_y () - menu_dy ());
1577  return 1;
1578 
1579  case FL_PUSH:
1580  pos_x = Fl::event_x ();
1581  pos_y = Fl::event_y () - menu_dy ();
1582 
1583  set_currentpoint (pos_x, pos_y);
1584 
1585  if (Fl::event_clicks ())
1586  fp.set_selectiontype ("open");
1587  else if (Fl::event_button () == FL_MIDDLE_MOUSE
1588  || (Fl::event_button () == FL_LEFT_MOUSE
1589  && Fl::event_shift ()))
1590  fp.set_selectiontype ("extend");
1591  else if (Fl::event_button () == FL_RIGHT_MOUSE
1592  || (Fl::event_button () == FL_LEFT_MOUSE
1593  && Fl::event_ctrl ()))
1594  fp.set_selectiontype ("alt");
1595  else
1596  fp.set_selectiontype ("normal");
1597 
1598  gh = pixel2axes_or_ca (pos_x, pos_y);
1599 
1600  if (gh.ok ())
1601  {
1602  ax_obj = gh_manager::get_object (gh);
1603  set_axes_currentpoint (ax_obj, pos_x, pos_y);
1604  }
1605 
1606  // Ensure windowbuttondownfcn is called after currentpoint
1607  // is updated but before calling buttondownfcn.
1608  if (! fp.get_windowbuttondownfcn ().is_empty ())
1609  fp.execute_windowbuttondownfcn (Fl::event_button ());
1610 
1611  if (gh.ok ())
1612  {
1613  int ndim = calc_dimensions (ax_obj);
1614 
1615  if (ndim == 3)
1616  rotate->activate ();
1617  else // ndim == 2
1618  rotate->deactivate ();
1619 
1620  fp.set_currentobject (ax_obj.get_handle ().value ());
1621 
1622  base_properties& props = ax_obj.get_properties ();
1623  if (! props.get_buttondownfcn ().is_empty ())
1624  props.execute_buttondownfcn (Fl::event_button ());
1625 
1626  return 1;
1627  }
1628  else if (! fp.get_buttondownfcn ().is_empty ())
1629  fp.execute_buttondownfcn (Fl::event_button ());
1630 
1631  break;
1632 
1633  case FL_DRAG:
1634  if (! fp.get_windowbuttonmotionfcn ().is_empty ())
1635  {
1636  set_currentpoint (Fl::event_x (), Fl::event_y () - menu_dy ());
1638  }
1639 
1640  if (Fl::event_button () == 1)
1641  {
1642  if (ax_obj && ax_obj.isa ("axes"))
1643  {
1644  axes::properties& ap =
1645  dynamic_cast<axes::properties&>
1646  (ax_obj.get_properties ());
1647 
1648  // Don't pan or rotate legend
1649  if (ap.get_tag () != "legend")
1650  {
1651  if (rotate_enabled ())
1652  view2status (ax_obj);
1653  else
1654  pixel2status (ax_obj, pos_x, pos_y,
1655  Fl::event_x (),
1656  Fl::event_y () - menu_dy ());
1657 
1658  double x0, y0, x1, y1;
1659  Matrix pos = fp.get_boundingbox (true);
1660  pixel2pos (ax_obj, pos_x, pos_y, x0, y0);
1661  pixel2pos (ax_obj, Fl::event_x (),
1662  Fl::event_y () - menu_dy (),
1663  x1, y1);
1664 
1665  if (pan_enabled ())
1666  {
1667  std::string mode = pan_mode ();
1668 
1669  ap.translate_view (mode, x0, x1, y0, y1);
1670  }
1671  else if (rotate_enabled ())
1672  {
1673  double daz, del;
1674  daz = (Fl::event_x () - pos_x) / pos(2) * 360;
1675  del = (Fl::event_y () - menu_dy () - pos_y)
1676  / pos(3) * 360;
1677  ap.rotate_view (del, daz);
1678  }
1679  }
1680  else
1681  {
1682  // move the position of the legend
1683  Matrix pos = ap.get_position ().matrix_value ();
1684  pos(0) += double (Fl::event_x () - pos_x)
1685  / canvas->w ();
1686  pos(1) -= double (Fl::event_y () - menu_dy () - pos_y)
1687  / canvas->h ();
1688  ap.set_position (pos);
1689  }
1690 
1691  pos_x = Fl::event_x ();
1692  pos_y = Fl::event_y () - menu_dy ();
1693  mark_modified ();
1694  }
1695  return 1;
1696  }
1697  else if (Fl::event_button () == 3)
1698  {
1699  pixel2status (ax_obj, pos_x, pos_y,
1700  Fl::event_x (), Fl::event_y () - menu_dy ());
1701  Matrix zoom_box (1,4,0);
1702  zoom_box (0) = pos_x;
1703  zoom_box (1) = pos_y;
1704  zoom_box (2) = Fl::event_x ();
1705  zoom_box (3) = Fl::event_y () - menu_dy ();
1706  canvas->set_zoom_box (zoom_box);
1707  canvas->zoom (true);
1708  mark_modified ();
1709  return 1;
1710  }
1711 
1712  break;
1713 
1714  case FL_MOUSEWHEEL:
1715  {
1716  graphics_object ax =
1717  gh_manager::get_object (pixel2axes_or_ca (Fl::event_x (),
1718  Fl::event_y ()
1719  - menu_dy ()));
1720  if (ax && ax.isa ("axes"))
1721  {
1722  axes::properties& ap =
1723  dynamic_cast<axes::properties&> (ax.get_properties ());
1724 
1725  // Control how fast to zoom when using scroll wheel.
1726  double wheel_zoom_speed = ap.get_mousewheelzoom ();
1727 
1728  // Determine if we're zooming in or out.
1729  const double factor = (Fl::event_dy () < 0
1730  ? 1 / (1.0 - wheel_zoom_speed)
1731  : 1.0 - wheel_zoom_speed);
1732 
1733  // Get the point we're zooming about.
1734  double x1, y1;
1735  pixel2pos (ax, Fl::event_x (), Fl::event_y () - menu_dy (),
1736  x1, y1);
1737 
1738  // FIXME: should we only zoom about point for 2D plots?
1739 
1740  ap.zoom_about_point ("both", x1, y1, factor, false);
1741  mark_modified ();
1742  return 1;
1743  }
1744  }
1745 
1746  case FL_RELEASE:
1747  if (! fp.get_windowbuttonupfcn ().is_empty ())
1748  {
1749  set_currentpoint (Fl::event_x (), Fl::event_y () - menu_dy ());
1751  }
1752 
1753  if ((Fl::event_button () == 1) && Fl::event_clicks ())
1754  {
1755  // Double click
1756  set_on_ax_obj ("xlimmode", "auto");
1757  set_on_ax_obj ("ylimmode", "auto");
1758  set_on_ax_obj ("zlimmode", "auto");
1759  mark_modified ();
1760  return 1;
1761  }
1762  if (Fl::event_button () == 3)
1763  {
1764  // End of drag -- zoom.
1765  if (canvas->zoom ())
1766  {
1767  canvas->zoom (false);
1768  double x0,y0,x1,y1;
1769  if (ax_obj && ax_obj.isa ("axes"))
1770  {
1771  axes::properties& ap = dynamic_cast<axes::properties&>
1772  (ax_obj.get_properties ());
1773  pixel2pos (ax_obj, pos_x, pos_y, x0, y0);
1774  int pos_x1 = Fl::event_x ();
1775  int pos_y1 = Fl::event_y () - menu_dy ();
1776  pixel2pos (ax_obj, pos_x1, pos_y1, x1, y1);
1777  Matrix xl (1,2,0);
1778  Matrix yl (1,2,0);
1779  int dx = abs (pos_x - pos_x1);
1780  int dy = abs (pos_y - pos_y1);
1781  // Smallest zoom box must be 4 pixels square
1782  if ((dx > 4) && (dy > 4))
1783  {
1784  if (x0 < x1)
1785  {
1786  xl(0) = x0;
1787  xl(1) = x1;
1788  }
1789  else
1790  {
1791  xl(0) = x1;
1792  xl(1) = x0;
1793  }
1794  if (y0 < y1)
1795  {
1796  yl(0) = y0;
1797  yl(1) = y1;
1798  }
1799  else
1800  {
1801  yl(0) = y1;
1802  yl(1) = y0;
1803  }
1804  ap.zoom ("both", xl, yl);
1805  }
1806  mark_modified ();
1807  return 1;
1808  }
1809  }
1810  }
1811  break;
1812  }
1813  }
1814  //std::cout << "plot_window::handle wasn't interested in event " << fl_eventnames[event] << std::endl;
1815  return Fl_Window::handle (event);
1816  }
1817 };
1818 
1819 class figure_manager
1820 {
1821 public:
1822 
1823  static bool instance_ok (void)
1824  {
1825  bool retval = true;
1826 
1827  if (! instance)
1828  instance = new figure_manager ();
1829 
1830  if (! instance)
1831  error ("unable to create figure_manager object!");
1832 
1833  return retval;
1834  }
1835 
1836  ~figure_manager (void)
1837  {
1838  close_all ();
1839  }
1840 
1841  static void close_all (void)
1842  {
1843  if (instance_ok ())
1844  instance->do_close_all ();
1845  }
1846 
1847  static void new_window (figure::properties& fp)
1848  {
1849  if (instance_ok ())
1850  instance->do_new_window (fp);
1851  }
1852 
1853  static void delete_window (int idx)
1854  {
1855  if (instance_ok ())
1856  instance->do_delete_window (idx);
1857  }
1858 
1859  static void delete_window (const std::string& idx_str)
1860  {
1861  delete_window (str2idx (idx_str));
1862  }
1863 
1864  static void renumber_figure (const std::string& idx_str, double new_number)
1865  {
1866  if (instance_ok ())
1867  instance->do_renumber_figure (str2idx (idx_str), new_number);
1868  }
1869 
1870  static void toggle_window_visibility (int idx, bool is_visible)
1871  {
1872  if (instance_ok ())
1873  instance->do_toggle_window_visibility (idx, is_visible);
1874  }
1875 
1876  static void toggle_window_visibility (const std::string& idx_str,
1877  bool is_visible)
1878  {
1879  toggle_window_visibility (str2idx (idx_str), is_visible);
1880  }
1881 
1882  static void mark_modified (int idx)
1883  {
1884  if (instance_ok ())
1885  instance->do_mark_modified (idx);
1886  }
1887 
1888  static void mark_modified (const graphics_handle& gh)
1889  {
1890  mark_modified (hnd2idx (gh));
1891  }
1892 
1893  static void set_name (int idx)
1894  {
1895  if (instance_ok ())
1896  instance->do_set_name (idx);
1897  }
1898 
1899  static void set_name (const std::string& idx_str)
1900  {
1901  set_name (str2idx (idx_str));
1902  }
1903 
1904  static Matrix get_size (int idx)
1905  {
1906  return instance_ok () ? instance->do_get_size (idx) : Matrix ();
1907  }
1908 
1909  static Matrix get_size (const graphics_handle& gh)
1910  {
1911  return get_size (hnd2idx (gh));
1912  }
1913 
1914  static void print (const graphics_handle& gh, const std::string& cmd,
1915  const std::string& term)
1916  {
1917  if (instance_ok ())
1918  instance->do_print (hnd2idx (gh), cmd, term);
1919  }
1920 
1921  static void uimenu_update (const graphics_handle& figh,
1922  const graphics_handle& uimenuh, int id)
1923  {
1924  if (instance_ok ())
1925  instance->do_uimenu_update (hnd2idx (figh), uimenuh, id);
1926  }
1927 
1928  static void update_canvas (const graphics_handle& gh,
1929  const graphics_handle& ca)
1930  {
1931  if (instance_ok ())
1932  instance->do_update_canvas (hnd2idx (gh), ca);
1933  }
1934 
1935  static void update_boundingbox (const std::string& fig_idx_str,
1936  bool internal)
1937  {
1938  if (instance_ok ())
1939  instance->do_update_boundingbox (str2idx (fig_idx_str), internal);
1940  }
1941 
1942  static void toggle_menubar_visibility (const std::string& fig_idx_str,
1943  bool menubar_is_figure)
1944  {
1945  if (instance_ok ())
1946  instance->do_toggle_menubar_visibility (str2idx (fig_idx_str),
1947  menubar_is_figure);
1948  }
1949 
1950 private:
1951 
1952  static figure_manager *instance;
1953 
1954  figure_manager (void) { }
1955 
1956  // No copying!
1957  figure_manager (const figure_manager&);
1958  figure_manager& operator = (const figure_manager&);
1959 
1960  // Singelton -- hide all of the above.
1961 
1962  static int curr_index;
1963  typedef std::map<int, plot_window*> window_map;
1964  typedef window_map::iterator wm_iterator;;
1965  window_map windows;
1966 
1967  static std::string fltk_idx_header;
1968 
1969  void do_close_all (void)
1970  {
1971  wm_iterator win;
1972  for (win = windows.begin (); win != windows.end (); win++)
1973  delete win->second;
1974  windows.clear ();
1975  }
1976 
1977  void do_new_window (figure::properties& fp)
1978  {
1979  int idx = figprops2idx (fp);
1980 
1981  if (idx >= 0 && windows.find (idx) == windows.end ())
1982  {
1983  Matrix pos = fp.get_outerposition ().matrix_value ();
1984  bool internal = false;
1985  // check if figure::properties::outerposition is default -1.0
1986  if (pos(2) != -1.0 && pos(3) != -1.0)
1987  {
1988  pos = fp.get_boundingbox (internal);
1989  }
1990  else
1991  {
1992  // use position
1993  internal = true;
1994  pos = fp.get_boundingbox (internal);
1995  }
1996 
1997  idx2figprops (curr_index, fp);
1998 
1999  windows[curr_index++] = new plot_window (pos(0), pos(1), pos(2), pos(3),
2000  fp, internal);
2001  }
2002  }
2003 
2004  void do_delete_window (int idx)
2005  {
2006  wm_iterator win = windows.find (idx);
2007 
2008  if (win != windows.end ())
2009  {
2010  delete win->second;
2011  windows.erase (win);
2012  }
2013  }
2014 
2015  void do_renumber_figure (int idx, double new_number)
2016  {
2017  wm_iterator win = windows.find (idx);
2018 
2019  if (win != windows.end ())
2020  win->second->renumber (new_number);
2021  }
2022 
2023  void do_toggle_window_visibility (int idx, bool is_visible)
2024  {
2025  wm_iterator win = windows.find (idx);
2026 
2027  if (win != windows.end ())
2028  {
2029  if (is_visible)
2030  {
2031  win->second->show ();
2032  win->second->show_canvas ();
2033  }
2034  else
2035  win->second->hide ();
2036 
2037  }
2038  }
2039 
2040  void do_toggle_menubar_visibility (int fig_idx, bool menubar_is_figure)
2041  {
2042  wm_iterator win = windows.find (fig_idx);
2043 
2044  if (win != windows.end ())
2045  {
2046  if (menubar_is_figure)
2047  win->second->show_menubar ();
2048  else
2049  win->second->hide_menubar ();
2050 
2051  win->second->redraw ();
2052  }
2053  }
2054 
2055  void do_mark_modified (int idx)
2056  {
2057  wm_iterator win = windows.find (idx);
2058 
2059  if (win != windows.end ())
2060  {
2061  win->second->mark_modified ();
2062  }
2063  }
2064 
2065  void do_set_name (int idx)
2066  {
2067  wm_iterator win = windows.find (idx);
2068 
2069  if (win != windows.end ())
2070  win->second->set_name ();
2071  }
2072 
2073  Matrix do_get_size (int idx)
2074  {
2075  Matrix sz (1, 2, 0.0);
2076 
2077  wm_iterator win = windows.find (idx);
2078 
2079  if (win != windows.end ())
2080  {
2081  sz(0) = win->second->w ();
2082  sz(1) = win->second->h ();
2083  }
2084 
2085  return sz;
2086  }
2087 
2088  void do_print (int idx, const std::string& cmd, const std::string& term)
2089  {
2090  wm_iterator win = windows.find (idx);
2091 
2092  if (win != windows.end ())
2093  win->second->print (cmd, term);
2094  }
2095 
2096  void do_uimenu_update (int idx, const graphics_handle& gh, int id)
2097  {
2098  wm_iterator win = windows.find (idx);
2099 
2100  if (win != windows.end ())
2101  win->second->uimenu_update (gh, id);
2102  }
2103 
2104  void do_update_canvas (int idx, const graphics_handle& ca)
2105  {
2106  wm_iterator win = windows.find (idx);
2107 
2108  if (win != windows.end ())
2109  {
2110  if (ca.ok ())
2111  win->second->show_canvas ();
2112  else
2113  win->second->hide_canvas ();
2114  }
2115  }
2116 
2117  void do_update_boundingbox (int idx, bool internal)
2118  {
2119  wm_iterator win = windows.find (idx);
2120 
2121  if (win != windows.end ())
2122  win->second->update_boundingbox (internal);
2123  }
2124 
2125  static int str2idx (const caseless_str& clstr)
2126  {
2127  int ind;
2128  if (clstr.find (fltk_idx_header,0) == 0)
2129  {
2130  std::istringstream istr (clstr.substr (fltk_idx_header.size ()));
2131  if (istr >> ind)
2132  return ind;
2133  }
2134 
2135  error ("figure_manager: could not recognize fltk index");
2136  }
2137 
2138  void idx2figprops (int idx, figure::properties& fp)
2139  {
2140  std::ostringstream ind_str;
2141  ind_str << fltk_idx_header << idx;
2142  fp.set___plot_stream__ (ind_str.str ());
2143  }
2144 
2145  static int figprops2idx (const figure::properties& fp)
2146  {
2147  if (fp.get___graphics_toolkit__ () == FLTK_GRAPHICS_TOOLKIT_NAME)
2148  {
2149  octave_value ps = fp.get___plot_stream__ ();
2150  if (ps.is_string ())
2151  return str2idx (ps.string_value ());
2152  else
2153  return 0;
2154  }
2155 
2156  error ("figure_manager: figure is not fltk");
2157  }
2158 
2159  static int hnd2idx (double h)
2160  {
2162  if (fobj && fobj.isa ("figure"))
2163  {
2164  figure::properties& fp =
2165  dynamic_cast<figure::properties&> (fobj.get_properties ());
2166  return figprops2idx (fp);
2167  }
2168 
2169  error ("figure_manager: H (= %g) is not a figure", h);
2170  }
2171 
2172  static int hnd2idx (const graphics_handle& fh)
2173  {
2174  return hnd2idx (fh.value ());
2175  }
2176 };
2177 
2178 figure_manager *figure_manager::instance = 0;
2179 
2180 std::string figure_manager::fltk_idx_header="fltk index=";
2181 int figure_manager::curr_index = 1;
2182 
2183 static bool toolkit_loaded = false;
2184 
2185 class fltk_graphics_toolkit : public base_graphics_toolkit
2186 {
2187 public:
2188  fltk_graphics_toolkit (void)
2189  : base_graphics_toolkit (FLTK_GRAPHICS_TOOLKIT_NAME),
2190  input_event_hook_fcn_id ()
2191  {
2192  Fl::visual (FL_RGB);
2193  }
2194 
2195  ~fltk_graphics_toolkit (void) { }
2196 
2197  bool is_valid (void) const { return true; }
2198 
2199  bool initialize (const graphics_object& go)
2200  {
2201  if (go.isa ("figure")
2202  || go.isa ("uimenu"))
2203  {
2204  if (go.isa ("uimenu"))
2205  update (go, uimenu::properties::ID_LABEL);
2206 
2207  return true;
2208  }
2209 
2210  return false;
2211  }
2212 
2213  void finalize (const graphics_object& go)
2214  {
2215  if (go.isa ("figure"))
2216  {
2217  octave_value ov = go.get (caseless_str ("__plot_stream__"));
2218 
2219  if (! ov.is_empty ())
2220  figure_manager::delete_window (ov.string_value ());
2221  }
2222  }
2223 
2224  void uimenu_set_fltk_label (graphics_object uimenu_obj)
2225  {
2226  if (uimenu_obj.valid_object ())
2227  {
2228  uimenu::properties& uimenup =
2229  dynamic_cast<uimenu::properties&> (uimenu_obj.get_properties ());
2230  std::string fltk_label = uimenup.get_label ();
2231  graphics_object go = gh_manager::get_object (uimenu_obj.get_parent ());
2232  if (go.isa ("uimenu"))
2233  fltk_label = dynamic_cast<const uimenu::properties&>
2234  (go.get_properties ()).get_fltk_label ()
2235  + "/"
2236  + fltk_label;
2237  else if (go.isa ("figure") || go.isa ("uicontextmenu"))
2238  ;
2239  else
2240  error ("invalid parent object\n");
2241 
2242  uimenup.set_fltk_label (fltk_label);
2243  }
2244  }
2245 
2246  void update (const graphics_object& go, int id)
2247  {
2248  if (go.isa ("figure"))
2249  {
2250  octave_value ov = go.get (caseless_str ("__plot_stream__"));
2251 
2252  if (! ov.is_empty ())
2253  {
2254  const figure::properties& fp =
2255  dynamic_cast<const figure::properties&> (go.get_properties ());
2256 
2257  switch (id)
2258  {
2260  figure_manager::toggle_window_visibility (ov.string_value (),
2261  fp.is_visible ());
2262  break;
2263 
2265  figure_manager::toggle_menubar_visibility
2266  (ov.string_value (), fp.menubar_is ("figure"));
2267  break;
2268 
2270  figure_manager::update_canvas (go.get_handle (),
2271  fp.get_currentaxes ());
2272  break;
2273 
2276  figure_manager::set_name (ov.string_value ());
2277  break;
2278 
2280  {
2281  std::string tmp = ov.string_value ();
2282  graphics_handle gh = fp.get___myhandle__ ();
2283  figure_manager::renumber_figure (tmp, gh.value ());
2284  figure_manager::set_name (tmp);
2285  }
2286  break;
2287 
2289  figure_manager::update_boundingbox (ov.string_value (), true);
2290  break;
2291 
2293  figure_manager::update_boundingbox (ov.string_value (), false);
2294  break;
2295  }
2296  }
2297  }
2298  else if (go.isa ("uimenu"))
2299  {
2300  if (id == uimenu::properties::ID_LABEL)
2301  uimenu_set_fltk_label (go);
2302 
2303  graphics_object fig = go.get_ancestor ("figure");
2304  figure_manager::uimenu_update (fig.get_handle (), go.get_handle (), id);
2305  }
2306  }
2307 
2308  void redraw_figure (const graphics_object& go) const
2309  {
2310  // We scan all figures and add those which use FLTK.
2312  if (obj && obj.isa ("root"))
2313  {
2314  base_properties& props = obj.get_properties ();
2315  Matrix children = props.get_all_children ();
2316 
2317  for (octave_idx_type n = 0; n < children.numel (); n++)
2318  {
2319  graphics_object fobj = gh_manager::get_object (children (n));
2320  if (fobj && fobj.isa ("figure"))
2321  {
2322  figure::properties& fp =
2323  dynamic_cast<figure::properties&> (fobj.get_properties ());
2324  if (fp.get___graphics_toolkit__ ()
2325  == FLTK_GRAPHICS_TOOLKIT_NAME)
2326  figure_manager::new_window (fp);
2327  }
2328  }
2329  }
2330 
2331  figure_manager::mark_modified (go.get_handle ());
2332  Fl::check ();
2333  }
2334 
2335  void print_figure (const graphics_object& go,
2336  const std::string& term,
2337  const std::string& file_cmd,
2338  const std::string& /*debug_file*/) const
2339  {
2340  figure_manager::print (go.get_handle (), file_cmd, term);
2341  }
2342 
2343  Matrix get_canvas_size (const graphics_handle& fh) const
2344  {
2345  return figure_manager::get_size (fh);
2346  }
2347 
2348 /*
2349  double get_screen_resolution (void) const
2350  {
2351  // FLTK doesn't give this info.
2352  return 72.0;
2353 
2354  // FIXME: FLTK >= 1.3.0 could do this with Fl::screen_dpi (h, v, n)
2355  // but do we need it?
2356  }
2357 */
2358 
2359  Matrix get_screen_size (void) const
2360  {
2361  Matrix sz (1, 2, 0.0);
2362  sz(0) = Fl::w ();
2363  sz(1) = Fl::h ();
2364  return sz;
2365  }
2366 
2367  void close (void)
2368  {
2369  if (toolkit_loaded)
2370  {
2371  munlock ("__init_fltk__");
2372 
2373  octave_value_list args = input_event_hook_fcn_id;
2374  args.append (false);
2375  Fremove_input_event_hook (args, 0);
2376  input_event_hook_fcn_id = octave_value_list ();
2377 
2378  figure_manager::close_all ();
2379  }
2380  }
2381 
2382  void set_input_event_hook_id (const octave_value_list& id)
2383  {
2384  input_event_hook_fcn_id = id;
2385  }
2386 
2387 private:
2388  octave_value_list input_event_hook_fcn_id;
2389 };
2390 
2391 #endif
2392 
2393 DEFUN_DLD (__fltk_check__, , ,
2394  doc: /* -*- texinfo -*-
2395 @deftypefn {} {} __fltk_check__ ()
2396 Undocumented internal function. Calls Fl::check ()
2397 @end deftypefn */)
2398 {
2399 #if defined (HAVE_FLTK)
2400  Fl::check ();
2401 
2402  if (Vdrawnow_requested)
2403  Fdrawnow ();
2404 
2405  return ovl ();
2406 #else
2407  err_disabled_feature ("__fltk_check__", "OpenGL and FLTK");
2408 #endif
2409 }
2410 
2411 // Initialize the fltk graphics toolkit.
2412 
2413 DEFUN_DLD (__init_fltk__, , ,
2414  doc: /* -*- texinfo -*-
2415 @deftypefn {} {} __init_fltk__ ()
2416 Undocumented internal function.
2417 @end deftypefn */)
2418 {
2419 #if defined (HAVE_FLTK)
2421  error ("__init_fltk__: no graphics DISPLAY available");
2422  else if (! toolkit_loaded)
2423  {
2424  mlock ();
2425 
2426  fltk_graphics_toolkit *fltk = new fltk_graphics_toolkit ();
2427  graphics_toolkit tk (fltk);
2429  toolkit_loaded = true;
2430 
2432  octave_value fcn_handle (new octave_fcn_handle (fcn, "@__fltk_check__"));
2433  octave_value_list id = Fadd_input_event_hook (fcn_handle, 1);
2434 
2435  fltk->set_input_event_hook_id (id);
2436  }
2437 
2438  return ovl ();
2439 
2440 #else
2441  err_disabled_feature ("__init_fltk__", "OpenGL and FLTK");
2442 #endif
2443 }
2444 
2445 /*
2446 ## No test needed for internal helper function.
2447 %!assert (1)
2448 */
uint32_t id
Definition: graphics.cc:11587
graphics_handle get_currentaxes(void) const
Definition: graphics.h:4011
graphics_handle get_parent(void) const
Definition: graphics.h:3272
octave_value get_position(void) const
Definition: graphics.h:5542
Definition: Cell.h:37
virtual void print_figure(const graphics_object &, const std::string &, const std::string &, const std::string &="") const
Definition: graphics.h:2086
bool is_visible(void) const
Definition: graphics.h:2704
virtual void update(const graphics_object &, int)
Definition: graphics.h:2112
void resize(octave_idx_type nr, octave_idx_type nc, double rfv=0)
Definition: dMatrix.h:145
ind
Definition: sub2ind.cc:107
Array< octave_idx_type > sort_rows_idx(sortmode mode=ASCENDING) const
Sort by rows returns only indices.
Definition: Array.cc:2087
bool isa(const std::string &go_name) const
Definition: graphics.h:3286
OCTAVE_EXPORT octave_value_list isa nd deftypefn *return ovl(args(0).is_integer_type())
void set___mouse_mode__(const octave_value &val)
Definition: graphics.cc:1879
octave_value get_buttondownfcn(void) const
Definition: graphics.h:2668
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:363
void execute_windowbuttonmotionfcn(const octave_value &data=octave_value()) const
Definition: graphics.h:4104
identity matrix If supplied two scalar respectively For allows like xample val
Definition: data.cc:5068
octave_value get_windowbuttonupfcn(void) const
Definition: graphics.h:4108
octave_value get_callback(void) const
Definition: graphics.h:11486
const octave_value & contents(const_iterator p) const
Definition: oct-map.h:190
Return the CPU time used by your Octave session The first output is the total time spent executing your process and is equal to the sum of second and third which are the number of CPU seconds spent executing in user mode and the number of CPU seconds spent executing in system mode
Definition: data.cc:6386
virtual Matrix get_screen_size(void) const
Definition: graphics.h:2103
void set_currentaxes(const octave_value &val)
Definition: graphics.cc:3611
octave_value_list & append(const octave_value &val)
Definition: ovl.cc:85
std::string get___graphics_toolkit__(void) const
Definition: graphics.h:4130
virtual void draw(const graphics_object &go, bool toplevel=true)
Definition: gl-render.cc:652
void execute_buttondownfcn(const octave_value &data=octave_value()) const
Definition: graphics.h:3998
octave_int< T > mod(const octave_int< T > &x, const octave_int< T > &y)
Definition: oct-inttypes.h:977
bool ok(void) const
Definition: oct-handle.h:109
for large enough k
Definition: lu.cc:606
OCTAVE_EXPORT octave_value_list any number nd example oindent prints the prompt xample Pick a number
Definition: input.cc:871
OCTINTERP_API octave_value_list Fdrawnow(const octave_value_list &=octave_value_list(), int=0)
Definition: graphics.cc:11032
void error(const char *fmt,...)
Definition: error.cc:570
void zoom(const std::string &mode, double factor, bool push_to_zoom_stack=true)
Definition: graphics.cc:7646
virtual Matrix get_boundingbox(bool=false, const Matrix &=Matrix()) const
Definition: graphics.h:2499
void translate_view(const std::string &mode, double x0, double x1, double y0, double y1, bool push_to_zoom_stack=true)
Definition: graphics.cc:7764
OCTINTERP_API octave_value_list Fremove_input_event_hook(const octave_value_list &=octave_value_list(), int=0)
static void load_toolkit(const graphics_toolkit &tk)
Definition: graphics.h:2266
void execute_keypressfcn(const octave_value &data=octave_value()) const
Definition: graphics.h:4033
virtual void close(void)
Definition: graphics.h:2137
OCTAVE_EXPORT octave_value_list return the number of command line arguments passed to Octave If called with the optional argument the function t
Definition: ov-usr-fcn.cc:935
void execute_windowbuttonupfcn(const octave_value &data=octave_value()) const
Definition: graphics.h:4107
OCTINTERP_API octave_value_list Fadd_input_event_hook(const octave_value_list &=octave_value_list(), int=0)
graphics_handle gh
Definition: graphics.cc:11209
std::string get_tag(void) const
Definition: graphics.h:2696
octave_value get___plot_stream__(void) const
Definition: graphics.h:4139
OCTAVE_EXPORT octave_value_list F__fltk_check__(const octave_value_list &, int)
octave_value get(bool all=false) const
Definition: graphics.h:3211
octave_function * fcn
Definition: ov-class.cc:1743
octave_value get___rotate_mode__(void) const
Definition: graphics.h:4141
static std::string getenv(const std::string &name)
Definition: oct-env.cc:235
graphics_xform get_transform(void) const
Definition: graphics.h:4989
JNIEnv void * args
Definition: ov-java.cc:67
void set_currentfigure(const octave_value &val)
Definition: graphics.cc:3451
bool is_separator(void) const
Definition: graphics.h:11503
double h
Definition: graphics.cc:11205
OCTAVE_EXPORT octave_value_list any number nd example oindent prints the prompt xample Pick a any number!nd example oindent and waits for the user to enter a value The string entered by the user is evaluated as an so it may be a literal a variable name
Definition: input.cc:871
double value(void) const
Definition: oct-handle.h:74
void set_currentpoint(const octave_value &val)
Definition: graphics.h:5957
bool Vdrawnow_requested
Definition: input.cc:106
Matrix get_children(void) const
Definition: graphics.h:2517
bool is_beingdeleted(void) const
Definition: graphics.h:2661
property get_property(const caseless_str &pname)
std::string string_value(bool force=false) const
Definition: ov.h:908
nd deftypefn *octave_map m
Definition: ov-struct.cc:2058
bool set(const octave_value &val, bool do_run=true, bool do_notify_toolkit=true)
Definition: graphics.h:1883
double get_mousewheelzoom(void) const
Definition: graphics.h:5707
std::complex< double > w(std::complex< double > z, double relerr=0)
static bool toolkit_loaded
void gl2ps_print(const graphics_object &fig, const std::string &stream, const std::string &term)
Definition: gl2ps-print.cc:799
void execute_windowbuttondownfcn(const octave_value &data=octave_value()) const
Definition: graphics.h:4101
bool is_string(void) const
Definition: ov.h:578
void rotate_view(double delta_az, double delta_el, bool push_to_zoom_stack=true)
Definition: graphics.cc:7857
bool is_enable(void) const
Definition: graphics.h:11491
string_vector & append(const std::string &s)
Definition: str-vec.cc:107
double tmp
Definition: data.cc:6300
is false
Definition: cellfun.cc:398
virtual bool is_valid(void) const
Definition: graphics.h:2081
octave_value retval
Definition: data.cc:6294
void set_fltk_label(const octave_value &val)
Definition: graphics.h:11599
#define panic_impossible()
Definition: error.h:40
octave_value get(bool all=false) const
base_properties & get_properties(void)
Definition: graphics.h:3288
void set_position(const octave_value &val)
Definition: graphics.h:6273
virtual void redraw_figure(const graphics_object &) const
Definition: graphics.h:2083
std::string get_accelerator(void) const
Definition: graphics.h:11483
OCTINTERP_API void munlock(const std::string &)
octave_idx_type length(void) const
Definition: ov.cc:1623
std::string get_label(void) const
Definition: graphics.h:11499
idx type
Definition: ov.cc:3129
Definition: dMatrix.h:37
void zoom_about_point(const std::string &mode, double x, double y, double factor, bool push_to_zoom_stack=true)
Definition: graphics.cc:7617
sz
Definition: data.cc:5342
graphics_object get_ancestor(const std::string &type) const
Definition: graphics.cc:3404
octave_value get_keyreleasefcn(void) const
Definition: graphics.h:4037
Matrix matrix_value(bool frc_str_conv=false) const
Definition: ov.h:787
feval(ar{f}, 1) esult
Definition: oct-parse.cc:8829
void set(const caseless_str &pname, const octave_value &val)
octave_value get_windowbuttonmotionfcn(void) const
Definition: graphics.h:4105
void execute_buttondownfcn(const octave_value &data=octave_value()) const
Definition: graphics.h:2667
virtual void finalize(const graphics_object &)
Definition: graphics.h:2131
ColumnVector untransform(double x, double y, double z, bool use_scale=true) const
Definition: graphics.cc:6635
bool valid_object(void) const
Definition: graphics.h:3306
bool is_empty(void) const
Definition: ov.h:542
bool is_checked(void) const
Definition: graphics.h:11488
bool menubar_is(const std::string &v) const
Definition: graphics.h:4039
std::string get_fltk_label(void) const
Definition: graphics.h:11506
virtual Matrix get_canvas_size(const graphics_handle &) const
Definition: graphics.h:2091
void set_currentpoint(const octave_value &val)
Definition: graphics.h:4235
ColumnVector pixel2coord(double px, double py) const
Definition: graphics.h:5037
octave_scalar_map scalar_map_value(void) const
Definition: ov.cc:1699
double get_position(void) const
Definition: graphics.h:11501
virtual bool initialize(const graphics_object &)
Definition: graphics.h:2120
OCTAVE_EXPORT octave_value_list return the value of the option it must match the dimension of the state and the relative tolerance must also be a vector of the same length tem it must match the dimension of the state and the absolute tolerance must also be a vector of the same length The local error test applied at each integration step is xample roup abs(local error in x(i))<
static octave_idx_type get_size(double d, const std::string &who)
Definition: oct-stream.cc:116
void assign(const std::string &k, const octave_value &val)
Definition: oct-map.h:223
OCTAVE_EXPORT octave_value_list or N dimensional array whose elements are all equal to the IEEE symbol zero divided by nd tex zero divided by nd ifnottex and any operation involving another NaN value(5+NaN).Note that NaN always compares not equal to NaN(NaN!
static bool display_available(void)
Definition: display.h:72
static graphics_handle lookup(double val)
Definition: graphics.h:13783
octave_value get___pan_mode__(void) const
Definition: graphics.h:4137
static bool pan_enabled(const graphics_object figObj)
Definition: Canvas.cc:327
issues an error eealso double
Definition: ov-bool-mat.cc:594
Matrix map_from_boundingbox(double x, double y) const
Definition: graphics.cc:3728
Matrix get_all_children(void) const
Definition: graphics.h:2522
b
Definition: cellfun.cc:398
OCTAVE_EXPORT octave_value_list or N dimensional array whose elements are all equal to the IEEE symbol NaN(Not a Number).NaN is the result of operations which do not produce a well defined 0 result.Common operations which produce a NaN are arithmetic with infinity ex($\infty-\infty $)
static graphics_object get_object(double val)
Definition: graphics.h:13794
void set_boundingbox(const Matrix &bb, bool internal=false, bool do_notify_toolkit=true)
Definition: graphics.cc:3710
graphics_handle get_parent(void) const
Definition: graphics.h:2688
OCTINTERP_API int calc_dimensions(const graphics_object &gh)
static std::string pan_mode(const graphics_object figObj)
Definition: Canvas.cc:339
double floor(double x)
Definition: lo-mappers.cc:330
#define DEFUN_DLD(name, args_name, nargout_name, doc)
Definition: defun-dld.h:45
void set___plot_stream__(const octave_value &val)
Definition: graphics.h:4638
OCTAVE_EXPORT octave_value_list any number nd example oindent prints the prompt xample Pick a any number!nd example oindent and waits for the user to enter a value The string entered by the user is evaluated as an so it may be a literal a variable or any other valid Octave code The number of return their size
Definition: input.cc:871
graphics_handle get_handle(void) const
Definition: graphics.h:3274
octave_value get_outerposition(void) const
Definition: graphics.h:4050
void execute_keyreleasefcn(const octave_value &data=octave_value()) const
Definition: graphics.h:4036
graphics_handle get___myhandle__(void) const
Definition: graphics.h:2710
void set_currentobject(const octave_value &val)
Definition: graphics.h:4225
octave_value get_buttondownfcn(void) const
Definition: graphics.h:3999
octave_value get_keypressfcn(void) const
Definition: graphics.h:4034
Matrix get_transform_zlim(void) const
Definition: graphics.h:4996
octave_value as_octave_value(void) const
Definition: oct-handle.h:76
void err_disabled_feature(const std::string &fcn, const std::string &feature, const std::string &pkg)
Definition: errwarn.cc:50
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:854
Matrix get_boundingbox(bool internal=false, const Matrix &parent_pix_size=Matrix()) const
Definition: graphics.cc:3693
void set_selectiontype(const octave_value &val)
Definition: graphics.h:4478
octave_value get_windowbuttondownfcn(void) const
Definition: graphics.h:4102
void set_currentcharacter(const octave_value &val)
Definition: graphics.h:4215
Matrix get_foregroundcolor_rgb(void) const
Definition: graphics.h:11496
OCTINTERP_API void mlock(void)