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