00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #ifdef HAVE_CONFIG_H
00035 #include <config.h>
00036 #endif
00037
00038 #include "defun-dld.h"
00039 #include "error.h"
00040
00041 #if defined (HAVE_FLTK)
00042
00043 #include <map>
00044 #include <set>
00045 #include <sstream>
00046 #include <iostream>
00047
00048 #ifdef WIN32
00049 #define WIN32_LEAN_AND_MEAN
00050 #endif
00051
00052 #include <FL/Fl.H>
00053 #include <FL/Fl_Box.H>
00054 #include <FL/Fl_Button.H>
00055 #include <FL/Fl_Choice.H>
00056 #include <FL/Fl_File_Chooser.H>
00057 #include <FL/Fl_Gl_Window.H>
00058 #include <FL/Fl_Menu_Bar.H>
00059 #include <FL/Fl_Menu_Button.H>
00060 #include <FL/Fl_Output.H>
00061 #include <FL/Fl_Window.H>
00062 #include <FL/fl_ask.H>
00063 #include <FL/fl_draw.H>
00064 #include <FL/gl.h>
00065
00066
00067
00068
00069
00070 #undef Complex
00071
00072 #include "cmd-edit.h"
00073 #include "lo-ieee.h"
00074
00075 #include "file-ops.h"
00076 #include "gl-render.h"
00077 #include "gl2ps-renderer.h"
00078 #include "graphics.h"
00079 #include "parse.h"
00080 #include "sysdep.h"
00081 #include "toplev.h"
00082 #include "variables.h"
00083
00084 #define FLTK_GRAPHICS_TOOLKIT_NAME "fltk"
00085
00086
00087 static double fltk_maxtime = 1e-2;
00088
00089 const char* help_text = "\
00090 Keyboard Shortcuts\n\
00091 a - autoscale\n\
00092 p - pan/zoom\n\
00093 r - rotate\n\
00094 g - toggle grid\n\
00095 \n\
00096 Mouse\n\
00097 left drag - pan\n\
00098 mouse wheel - zoom\n\
00099 right drag - rectangle zoom\n\
00100 left double click - autoscale\n\
00101 ";
00102
00103 class OpenGL_fltk : public Fl_Gl_Window
00104 {
00105 public:
00106 OpenGL_fltk (int xx, int yy, int ww, int hh, double num)
00107 : Fl_Gl_Window (xx, yy, ww, hh, 0), number (num), renderer (),
00108 in_zoom (false), zoom_box (), print_mode (false)
00109 {
00110
00111 mode (FL_DEPTH | FL_DOUBLE);
00112 }
00113
00114 ~OpenGL_fltk (void) { }
00115
00116 void zoom (bool z)
00117 {
00118 in_zoom = z;
00119 if (! in_zoom)
00120 hide_overlay ();
00121 }
00122
00123 bool zoom (void) { return in_zoom; }
00124 void set_zoom_box (const Matrix& zb) { zoom_box = zb; }
00125
00126 void print (const std::string& cmd, const std::string& term)
00127 {
00128 print_mode = true;
00129 print_cmd = cmd;
00130 print_term = term;
00131 }
00132
00133 void resize (int xx, int yy, int ww, int hh)
00134 {
00135 Fl_Gl_Window::resize (xx, yy, ww, hh);
00136 setup_viewport (ww, hh);
00137 redraw ();
00138 }
00139
00140 bool renumber (double new_number)
00141 {
00142 bool retval = false;
00143
00144 if (number != new_number)
00145 {
00146 number = new_number;
00147 retval = true;
00148 }
00149
00150 return retval;
00151 }
00152
00153 private:
00154 double number;
00155 opengl_renderer renderer;
00156 bool in_zoom;
00157
00158 Matrix zoom_box;
00159
00160 bool print_mode;
00161 std::string print_cmd;
00162 std::string print_term;
00163
00164 void setup_viewport (int ww, int hh)
00165 {
00166 glMatrixMode (GL_PROJECTION);
00167 glLoadIdentity ();
00168 glViewport (0, 0, ww, hh);
00169 }
00170
00171 void draw (void)
00172 {
00173 if (! valid ())
00174 {
00175 valid (1);
00176 setup_viewport (w (), h ());
00177 }
00178
00179 if (print_mode)
00180 {
00181 FILE *fp = octave_popen (print_cmd.c_str (), "w");
00182 glps_renderer rend (fileno (fp), print_term);
00183
00184 rend.draw (gh_manager::get_object (number));
00185
00186 octave_pclose (fp);
00187 print_mode = false;
00188 }
00189 else
00190 {
00191 renderer.draw (gh_manager::get_object (number));
00192
00193 if (zoom ())
00194 overlay ();
00195 }
00196 }
00197
00198 void zoom_box_vertex (void)
00199 {
00200 glVertex2d (zoom_box(0), h () - zoom_box(1));
00201 glVertex2d (zoom_box(0), h () - zoom_box(3));
00202 glVertex2d (zoom_box(2), h () - zoom_box(3));
00203 glVertex2d (zoom_box(2), h () - zoom_box(1));
00204 glVertex2d (zoom_box(0), h () - zoom_box(1));
00205 }
00206
00207 void overlay (void)
00208 {
00209 glPushMatrix ();
00210
00211 glMatrixMode (GL_MODELVIEW);
00212 glLoadIdentity ();
00213
00214 glMatrixMode (GL_PROJECTION);
00215 glLoadIdentity ();
00216 gluOrtho2D (0.0, w (), 0.0, h ());
00217
00218 glPushAttrib (GL_DEPTH_BUFFER_BIT | GL_CURRENT_BIT);
00219 glDisable (GL_DEPTH_TEST);
00220
00221 glBegin (GL_POLYGON);
00222 glColor4f (0.45, 0.62, 0.81, 0.1);
00223 zoom_box_vertex ();
00224 glEnd ();
00225
00226 glBegin (GL_LINE_STRIP);
00227 glLineWidth (1.5);
00228 glColor4f (0.45, 0.62, 0.81, 0.9);
00229 zoom_box_vertex ();
00230 glEnd ();
00231
00232 glPopAttrib ();
00233 glPopMatrix ();
00234 }
00235
00236 int handle (int event)
00237 {
00238 int retval = Fl_Gl_Window::handle (event);
00239
00240 switch (event)
00241 {
00242 case FL_ENTER:
00243 window ()->cursor (FL_CURSOR_CROSS);
00244 return 1;
00245
00246 case FL_LEAVE:
00247 window ()->cursor (FL_CURSOR_DEFAULT);
00248 return 1;
00249 }
00250
00251 return retval;
00252 }
00253 };
00254
00255
00256 static double wheel_zoom_speed = 0.05;
00257
00258 static enum { pan_zoom, rotate_zoom, none } gui_mode;
00259
00260 void script_cb(Fl_Widget*, void* data)
00261 {
00262 static_cast<uimenu::properties*> (data)->execute_callback ();
00263 }
00264
00265
00266 class fltk_uimenu
00267 {
00268 public:
00269 fltk_uimenu (int xx, int yy, int ww, int hh)
00270 {
00271 menubar = new
00272 Fl_Menu_Bar(xx, yy, ww, hh);
00273 }
00274
00275 int items_to_show (void)
00276 {
00277
00278 int len = menubar->size ();
00279 int n = 0;
00280 for (int t = 0; t < len; t++ )
00281 {
00282 const Fl_Menu_Item *m = static_cast<const Fl_Menu_Item*> (&(menubar->menu ()[t]));
00283 if ((m->label () != NULL) && m->visible ())
00284 n++;
00285 }
00286
00287 return n;
00288 }
00289
00290 void show (void)
00291 {
00292 menubar->show ();
00293 }
00294
00295 void hide (void)
00296 {
00297 menubar->hide ();
00298 }
00299
00300 bool is_visible (void)
00301 {
00302 return menubar->visible ();
00303 }
00304
00305 int find_index_by_name (const std::string& findname)
00306 {
00307
00308
00309
00310
00311
00312
00313 std::string menupath;
00314 for (int t = 0; t < menubar->size (); t++ )
00315 {
00316 Fl_Menu_Item *m = const_cast<Fl_Menu_Item*> (&(menubar->menu ()[t]));
00317 if (m->submenu ())
00318 {
00319
00320 if (!menupath.empty ())
00321 menupath += "/";
00322 menupath += m->label ();
00323
00324 if (menupath.compare (findname) == 0 )
00325 return (t);
00326 }
00327 else
00328 {
00329
00330 if (m->label () == NULL)
00331 {
00332 std::size_t idx = menupath.find_last_of ("/");
00333 if (idx != std::string::npos)
00334 menupath.erase (idx);
00335 else
00336 menupath.clear ();
00337 continue;
00338 }
00339
00340 std::string itempath = menupath;
00341 if (!itempath.empty ())
00342 itempath += "/";
00343 itempath += m->label ();
00344
00345 if (itempath.compare (findname) == 0)
00346 return (t);
00347 }
00348 }
00349 return (-1);
00350 }
00351
00352 Matrix find_uimenu_children (uimenu::properties& uimenup) const
00353 {
00354 Matrix uimenu_childs = uimenup.get_all_children ();
00355 Matrix retval = do_find_uimenu_children (uimenu_childs);
00356 return retval;
00357 }
00358
00359 Matrix find_uimenu_children (figure::properties& figp) const
00360 {
00361 Matrix uimenu_childs = figp.get_all_children ();
00362 Matrix retval = do_find_uimenu_children (uimenu_childs);
00363 return retval;
00364 }
00365
00366 Matrix do_find_uimenu_children (Matrix uimenu_childs) const
00367 {
00368 octave_idx_type k = 0;
00369
00370
00371 Matrix pos = Matrix (uimenu_childs.numel (), 1);
00372
00373 for (octave_idx_type ii = 0; ii < uimenu_childs.numel (); ii++)
00374 {
00375 graphics_object kidgo = gh_manager::get_object (uimenu_childs (ii));
00376
00377 if (kidgo.valid_object () && kidgo.isa ("uimenu"))
00378 {
00379 uimenu_childs(k) = uimenu_childs(ii);
00380 pos(k++) =
00381 dynamic_cast<uimenu::properties&> (kidgo.get_properties ()).get_position ();
00382 }
00383 }
00384
00385 uimenu_childs.resize (k, 1);
00386 pos.resize (k, 1);
00387 Matrix retval = Matrix (k, 1);
00388
00389
00390 Array<octave_idx_type> sidx = pos.sort_rows_idx (DESCENDING);
00391 for (octave_idx_type ii = 0; ii < k; ii++)
00392 retval(ii) = uimenu_childs (sidx(ii));
00393
00394 return retval;
00395 }
00396
00397 void delete_entry (uimenu::properties& uimenup)
00398 {
00399 std::string fltk_label = uimenup.get_fltk_label ();
00400 int idx = find_index_by_name (fltk_label.c_str ());
00401
00402 if (idx >= 0)
00403 menubar->remove (idx);
00404 }
00405
00406 void update_accelerator (uimenu::properties& uimenup)
00407 {
00408 std::string fltk_label = uimenup.get_fltk_label ();
00409 if (!fltk_label.empty ())
00410 {
00411 Fl_Menu_Item* item = const_cast<Fl_Menu_Item*> (menubar->find_item (fltk_label.c_str ()));
00412 if (item != NULL)
00413 {
00414 std::string acc = uimenup.get_accelerator ();
00415 if (acc.length () > 0)
00416 {
00417 int key = FL_CTRL + acc[0];
00418 item->shortcut (key);
00419 }
00420 }
00421 }
00422 }
00423
00424 void update_callback (uimenu::properties& uimenup)
00425 {
00426 std::string fltk_label = uimenup.get_fltk_label ();
00427 if (!fltk_label.empty ())
00428 {
00429 Fl_Menu_Item* item = const_cast<Fl_Menu_Item*> (menubar->find_item (fltk_label.c_str ()));
00430 if (item != NULL)
00431 {
00432 if (!uimenup.get_callback ().is_empty ())
00433 item->callback (static_cast<Fl_Callback*> (script_cb),
00434 static_cast<void*> (&uimenup));
00435 else
00436 item->callback (NULL, static_cast<void*> (0));
00437 }
00438 }
00439 }
00440
00441 void update_enable (uimenu::properties& uimenup)
00442 {
00443 std::string fltk_label = uimenup.get_fltk_label ();
00444 if (!fltk_label.empty ())
00445 {
00446 Fl_Menu_Item* item = const_cast<Fl_Menu_Item*> (menubar->find_item (fltk_label.c_str ()));
00447 if (item != NULL)
00448 {
00449 if (uimenup.is_enable ())
00450 item->activate ();
00451 else
00452 item->deactivate ();
00453 }
00454 }
00455 }
00456
00457 void update_foregroundcolor (uimenu::properties& uimenup)
00458 {
00459 std::string fltk_label = uimenup.get_fltk_label ();
00460 if (!fltk_label.empty ())
00461 {
00462 Fl_Menu_Item* item = const_cast<Fl_Menu_Item*> (menubar->find_item (fltk_label.c_str ()));
00463 if (item != NULL)
00464 {
00465 Matrix rgb = uimenup.get_foregroundcolor_rgb ();
00466
00467 uchar r = static_cast<uchar> (gnulib::floor (rgb (0) * 255));
00468 uchar g = static_cast<uchar> (gnulib::floor (rgb (1) * 255));
00469 uchar b = static_cast<uchar> (gnulib::floor (rgb (2) * 255));
00470
00471 item->labelcolor (fl_rgb_color (r, g, b));
00472 }
00473 }
00474 }
00475
00476 void update_seperator (const uimenu::properties& uimenup)
00477 {
00478
00479
00480
00481 std::string fltk_label = uimenup.get_fltk_label ();
00482 if (!fltk_label.empty ())
00483 {
00484 int itemflags = 0, idx;
00485 int curr_idx = find_index_by_name (fltk_label.c_str ());
00486
00487 for (idx = curr_idx - 1; idx >= 0; idx--)
00488 {
00489 Fl_Menu_Item* item = const_cast<Fl_Menu_Item*> (&menubar->menu () [idx]);
00490 itemflags = item->flags;
00491 if (item->label () != NULL)
00492 break;
00493 }
00494
00495 if (idx >= 0 && idx < menubar->size ())
00496 {
00497 if (uimenup.is_separator ())
00498 {
00499 if (idx >= 0 && !(itemflags & FL_SUBMENU))
00500 menubar->mode (idx, itemflags | FL_MENU_DIVIDER);
00501 }
00502 else
00503 menubar->mode (idx, itemflags & (~FL_MENU_DIVIDER));
00504 }
00505 }
00506 }
00507
00508 void update_visible (uimenu::properties& uimenup)
00509 {
00510 std::string fltk_label = uimenup.get_fltk_label ();
00511 if (!fltk_label.empty ())
00512 {
00513 Fl_Menu_Item* item
00514 = const_cast<Fl_Menu_Item*> (menubar->find_item (fltk_label.c_str ()));
00515 if (item != NULL)
00516 {
00517 if (uimenup.is_visible ())
00518 item->show ();
00519 else
00520 item->hide ();
00521 }
00522 }
00523 }
00524
00525 void add_entry (uimenu::properties& uimenup)
00526 {
00527
00528 std::string fltk_label = uimenup.get_fltk_label ();
00529
00530 if (!fltk_label.empty ())
00531 {
00532 bool item_added = false;
00533 do
00534 {
00535 const Fl_Menu_Item* item
00536 = menubar->find_item (fltk_label.c_str ());
00537
00538 if (item == NULL)
00539 {
00540 Matrix uimenu_ch = find_uimenu_children (uimenup);
00541 int len = uimenu_ch.numel ();
00542 int flags = 0;
00543 if (len > 0)
00544 flags = FL_SUBMENU;
00545 if (len == 0 && uimenup.is_checked ())
00546 flags += FL_MENU_TOGGLE + FL_MENU_VALUE;
00547 menubar->add (fltk_label.c_str (), 0, 0, 0, flags);
00548 item_added = true;
00549 }
00550 else
00551 {
00552
00553 std::size_t idx1 = fltk_label.find_last_of ("(");
00554 std::size_t idx2 = fltk_label.find_last_of (")");
00555 int len = idx2 - idx1;
00556 int val = 1;
00557 if (len > 0)
00558 {
00559 std::string valstr = fltk_label.substr (idx1 + 1, len - 1);
00560 fltk_label.erase (idx1, len + 1);
00561 val = atoi (valstr.c_str ());
00562 if (val > 0 && val < 99)
00563 val++;
00564 }
00565 std::ostringstream valstream;
00566 valstream << val;
00567 fltk_label += "(" + valstream.str () + ")";
00568 }
00569 }
00570 while (!item_added);
00571 uimenup.set_fltk_label (fltk_label);
00572 }
00573 }
00574
00575 void add_to_menu (uimenu::properties& uimenup)
00576 {
00577 Matrix kids = find_uimenu_children (uimenup);
00578 int len = kids.length ();
00579 std::string fltk_label = uimenup.get_fltk_label ();
00580
00581 add_entry (uimenup);
00582 update_foregroundcolor (uimenup);
00583 update_callback (uimenup);
00584 update_accelerator (uimenup);
00585 update_enable (uimenup);
00586 update_visible (uimenup);
00587 update_seperator (uimenup);
00588
00589 for (octave_idx_type ii = 0; ii < len; ii++)
00590 {
00591 graphics_object kgo = gh_manager::get_object (kids (len - (ii + 1)));
00592 if (kgo.valid_object ())
00593 {
00594 uimenu::properties& kprop = dynamic_cast<uimenu::properties&> (kgo.get_properties ());
00595 add_to_menu (kprop);
00596 }
00597 }
00598 }
00599
00600 void add_to_menu (figure::properties& figp)
00601 {
00602 Matrix kids = find_uimenu_children (figp);
00603 int len = kids.length ();
00604 menubar->clear ();
00605 for (octave_idx_type ii = 0; ii < len; ii++)
00606 {
00607 graphics_object kgo = gh_manager::get_object (kids (len - (ii + 1)));
00608
00609 if (kgo.valid_object ())
00610 {
00611 uimenu::properties& kprop = dynamic_cast<uimenu::properties&> (kgo.get_properties ());
00612 add_to_menu (kprop);
00613 }
00614 }
00615 }
00616
00617 template <class T_prop>
00618 void remove_from_menu (T_prop& prop)
00619 {
00620 Matrix kids;
00621 std::string type = prop.get_type ();
00622 kids = find_uimenu_children (prop);
00623 int len = kids.length ();
00624
00625 for (octave_idx_type ii = 0; ii < len; ii++)
00626 {
00627 graphics_object kgo = gh_manager::get_object (kids (len - (ii + 1)));
00628
00629 if (kgo.valid_object ())
00630 {
00631 uimenu::properties kprop = dynamic_cast<uimenu::properties&> (kgo.get_properties ());
00632 remove_from_menu (kprop);
00633 }
00634 }
00635
00636 if (type.compare ("uimenu") == 0)
00637 delete_entry (dynamic_cast<uimenu::properties&> (prop));
00638 else if (type.compare ("figure") == 0)
00639 menubar->clear ();
00640 }
00641
00642 ~fltk_uimenu (void)
00643 {
00644 delete menubar;
00645 }
00646
00647 private:
00648
00649
00650
00651 fltk_uimenu (const fltk_uimenu&);
00652
00653 fltk_uimenu operator = (const fltk_uimenu&);
00654
00655 Fl_Menu_Bar* menubar;
00656 };
00657
00658 class plot_window : public Fl_Window
00659 {
00660 friend class fltk_uimenu;
00661 public:
00662 plot_window (int xx, int yy, int ww, int hh, figure::properties& xfp)
00663 : Fl_Window (xx, yy, ww, hh, "octave"), window_label (), shift (0),
00664 ndim (2), fp (xfp), canvas (0), autoscale (0), togglegrid (0),
00665 panzoom (0), rotate (0), help (0), status (0),
00666 ax_obj (), pos_x (0), pos_y (0)
00667 {
00668 callback (window_close, static_cast<void*> (this));
00669 size_range (4*status_h, 2*status_h);
00670
00671 begin ();
00672 {
00673
00674 canvas = new OpenGL_fltk (0, 0, ww, hh - status_h, number ());
00675
00676 uimenu = new fltk_uimenu (0, 0, ww, menu_h);
00677 uimenu->hide ();
00678
00679 bottom = new Fl_Box (0, hh - status_h, ww, status_h);
00680 bottom->box(FL_FLAT_BOX);
00681
00682 ndim = calc_dimensions (gh_manager::get_object (fp.get___myhandle__ ()));
00683
00684 autoscale = new Fl_Button (0, hh - status_h, status_h, status_h, "A");
00685 autoscale->callback (button_callback, static_cast<void*> (this));
00686 autoscale->tooltip ("Autoscale");
00687
00688 togglegrid = new Fl_Button (status_h, hh - status_h, status_h,
00689 status_h, "G");
00690 togglegrid->callback (button_callback, static_cast<void*> (this));
00691 togglegrid->tooltip ("Toggle Grid");
00692
00693 panzoom = new Fl_Button (2 * status_h, hh - status_h, status_h,
00694 status_h, "P");
00695 panzoom->callback (button_callback, static_cast<void*> (this));
00696 panzoom->tooltip ("Mouse Pan/Zoom");
00697
00698 rotate = new Fl_Button (3 * status_h, hh - status_h, status_h,
00699 status_h, "R");
00700 rotate->callback (button_callback, static_cast<void*> (this));
00701 rotate->tooltip ("Mouse Rotate");
00702
00703 if (ndim == 2)
00704 rotate->deactivate ();
00705
00706 help = new Fl_Button (4 * status_h, hh - status_h, status_h,
00707 status_h, "?");
00708 help->callback (button_callback, static_cast<void*> (this));
00709 help->tooltip ("Help");
00710
00711 status = new Fl_Output (5 * status_h, hh - status_h,
00712 ww > 2*status_h ? ww - status_h : 0,
00713 status_h, "");
00714
00715 status->textcolor (FL_BLACK);
00716 status->color (FL_GRAY);
00717 status->textfont (FL_COURIER);
00718 status->textsize (10);
00719 status->box (FL_ENGRAVED_BOX);
00720
00721
00722 canvas->mode (FL_DEPTH | FL_DOUBLE );
00723 if (fp.is_visible ())
00724 {
00725 show ();
00726 if (fp.get_currentaxes ().ok())
00727 show_canvas ();
00728 else
00729 hide_canvas ();
00730 }
00731 }
00732 end ();
00733
00734 status->show ();
00735 autoscale->show ();
00736 togglegrid->show ();
00737 panzoom->show ();
00738 rotate->show ();
00739
00740 set_name ();
00741 resizable (canvas);
00742 gui_mode = (ndim == 3 ? rotate_zoom : pan_zoom);
00743 uimenu->add_to_menu (fp);
00744 if (uimenu->items_to_show ())
00745 show_menubar ();
00746 else
00747 hide_menubar ();
00748 }
00749
00750 ~plot_window (void)
00751 {
00752 canvas->hide ();
00753 status->hide ();
00754 uimenu->hide ();
00755 this->hide ();
00756 }
00757
00758 double number (void) { return fp.get___myhandle__ ().value (); }
00759
00760 void renumber (double new_number)
00761 {
00762 if (canvas)
00763 {
00764 if (canvas->renumber (new_number))
00765 mark_modified ();
00766 }
00767 else
00768 error ("unable to renumber figure");
00769 }
00770
00771 void print (const std::string& cmd, const std::string& term)
00772 {
00773 canvas->print (cmd, term);
00774
00775
00776
00777 mark_modified ();
00778 Fl::wait (fltk_maxtime);
00779 }
00780
00781 void show_menubar (void)
00782 {
00783 if (!uimenu->is_visible ())
00784 {
00785 canvas->resize (canvas->x (),
00786 canvas->y () + menu_h,
00787 canvas->w (),
00788 canvas->h () - menu_h);
00789 uimenu->show ();
00790 mark_modified ();
00791 }
00792 }
00793
00794 void hide_menubar (void)
00795 {
00796 if (uimenu->is_visible ())
00797 {
00798 canvas->resize (canvas->x (),
00799 canvas->y () - menu_h,
00800 canvas->w (),
00801 canvas->h () + menu_h);
00802 uimenu->hide ();
00803 mark_modified ();
00804 }
00805 }
00806
00807 void uimenu_update (const graphics_handle& gh, int id)
00808 {
00809 graphics_object uimenu_obj = gh_manager::get_object (gh);
00810
00811 if (uimenu_obj.valid_object () && uimenu_obj.isa ("uimenu"))
00812 {
00813 uimenu::properties& uimenup =
00814 dynamic_cast<uimenu::properties&> (uimenu_obj.get_properties ());
00815 std::string fltk_label = uimenup.get_fltk_label ();
00816 graphics_object fig = uimenu_obj.get_ancestor ("figure");
00817 figure::properties& figp =
00818 dynamic_cast<figure::properties&> (fig.get_properties ());
00819
00820 switch (id)
00821 {
00822 case base_properties::ID_BEINGDELETED:
00823 uimenu->remove_from_menu (uimenup);
00824 break;
00825
00826 case base_properties::ID_VISIBLE:
00827 uimenu->update_visible (uimenup);
00828 break;
00829
00830 case uimenu::properties::ID_ACCELERATOR:
00831 uimenu->update_accelerator (uimenup);
00832 break;
00833
00834 case uimenu::properties::ID_CALLBACK:
00835 uimenu->update_callback (uimenup);
00836 break;
00837
00838 case uimenu::properties::ID_CHECKED:
00839 uimenu->add_to_menu (figp);
00840 break;
00841
00842 case uimenu::properties::ID_ENABLE:
00843 uimenu->update_enable (uimenup);
00844 break;
00845
00846 case uimenu::properties::ID_FOREGROUNDCOLOR:
00847 uimenu->update_foregroundcolor (uimenup);
00848 break;
00849
00850 case uimenu::properties::ID_LABEL:
00851 uimenu->add_to_menu (figp);
00852 break;
00853
00854 case uimenu::properties::ID_POSITION:
00855 uimenu->add_to_menu (figp);
00856 break;
00857
00858 case uimenu::properties::ID_SEPARATOR:
00859 uimenu->update_seperator (uimenup);
00860 break;
00861 }
00862
00863 if (uimenu->items_to_show ())
00864 show_menubar ();
00865 else
00866 hide_menubar ();
00867
00868 mark_modified();
00869 }
00870 }
00871
00872 void show_canvas (void)
00873 {
00874 if (fp.is_visible ())
00875 {
00876 canvas->show ();
00877 canvas->make_current ();
00878 }
00879 }
00880
00881 void hide_canvas (void)
00882 {
00883 canvas->hide ();
00884 }
00885
00886 void mark_modified (void)
00887 {
00888 damage (FL_DAMAGE_ALL);
00889 canvas->damage (FL_DAMAGE_ALL);
00890 ndim = calc_dimensions (gh_manager::get_object (fp.get___myhandle__ ()));
00891
00892 if (ndim == 3)
00893 rotate->activate ();
00894 else if (ndim == 2 && gui_mode == rotate_zoom)
00895 {
00896 rotate->deactivate ();
00897 gui_mode = pan_zoom;
00898 }
00899 }
00900
00901 void set_name (void)
00902 {
00903 window_label = fp.get_title ();
00904 label (window_label.c_str ());
00905 }
00906
00907 private:
00908
00909
00910
00911 plot_window (const plot_window&);
00912
00913 plot_window& operator = (const plot_window&);
00914
00915
00916
00917 std::string window_label;
00918
00919
00920 int shift;
00921
00922
00923 int ndim;
00924
00925
00926 figure::properties& fp;
00927
00928
00929 static const int status_h = 20;
00930
00931
00932 static const int menu_h = 20;
00933
00934
00935 static void window_close (Fl_Widget*, void* data)
00936 {
00937 octave_value_list args;
00938 args(0) = static_cast<plot_window*> (data)->number ();
00939 feval ("close", args);
00940 }
00941
00942
00943 static void button_callback (Fl_Widget* ww, void* data)
00944 {
00945 static_cast<plot_window*> (data)->button_press (ww, data);
00946 }
00947
00948 void button_press (Fl_Widget* widg, void*)
00949 {
00950 if (widg == autoscale)
00951 axis_auto ();
00952
00953 if (widg == togglegrid)
00954 toggle_grid ();
00955
00956 if (widg == panzoom)
00957 gui_mode = pan_zoom;
00958
00959 if (widg == rotate && ndim == 3)
00960 gui_mode = rotate_zoom;
00961
00962 if (widg == help)
00963 fl_message ("%s", help_text);
00964 }
00965
00966 fltk_uimenu* uimenu;
00967 OpenGL_fltk* canvas;
00968 Fl_Box* bottom;
00969 Fl_Button* autoscale;
00970 Fl_Button* togglegrid;
00971 Fl_Button* panzoom;
00972 Fl_Button* rotate;
00973 Fl_Button* help;
00974 Fl_Output* status;
00975 graphics_object ax_obj;
00976 int pos_x;
00977 int pos_y;
00978
00979 void axis_auto (void)
00980 {
00981 octave_value_list args;
00982 args(0) = fp.get_currentaxes ().as_octave_value ();
00983 args(1) = "auto";
00984 feval ("axis", args);
00985 mark_modified ();
00986 }
00987
00988 void toggle_grid (void)
00989 {
00990 octave_value_list args;
00991 if (fp.get_currentaxes ().ok ())
00992 args(0) = fp.get_currentaxes ().as_octave_value ();
00993
00994 feval ("grid", args);
00995 mark_modified ();
00996 }
00997
00998 void pixel2pos (const graphics_handle& ax, int px, int py, double& xx,
00999 double& yy) const
01000 {
01001 pixel2pos ( gh_manager::get_object (ax), px, py, xx, yy);
01002 }
01003
01004 void pixel2pos (graphics_object ax, int px, int py, double& xx,
01005 double& yy) const
01006 {
01007 if (ax && ax.isa ("axes"))
01008 {
01009 axes::properties& ap =
01010 dynamic_cast<axes::properties&> (ax.get_properties ());
01011 ColumnVector pp = ap.pixel2coord (px, py);
01012 xx = pp(0);
01013 yy = pp(1);
01014 }
01015 }
01016
01017 graphics_handle pixel2axes_or_ca (int px, int py )
01018 {
01019 Matrix kids = fp.get_children ();
01020 int len = kids.length ();
01021
01022 for (int k = 0; k < len; k++)
01023 {
01024 graphics_handle hnd = gh_manager::lookup (kids(k));
01025
01026 if (hnd.ok ())
01027 {
01028 graphics_object kid = gh_manager::get_object (hnd);
01029
01030 if (kid.valid_object () && kid.isa ("axes"))
01031 {
01032 Matrix bb = kid.get_properties ().get_boundingbox (true);
01033
01034 if (bb(0) <= px && px < (bb(0)+bb(2))
01035 && bb(1) <= py && py < (bb(1)+bb(3)))
01036 {
01037 return hnd;
01038 }
01039 }
01040 }
01041 }
01042 return fp.get_currentaxes ();
01043 }
01044
01045 void pixel2status (const graphics_handle& ax, int px0, int py0,
01046 int px1 = -1, int py1 = -1)
01047 {
01048 pixel2status (gh_manager::get_object (ax), px0, py0, px1, py1);
01049 }
01050
01051 void pixel2status (graphics_object ax, int px0, int py0,
01052 int px1 = -1, int py1 = -1)
01053 {
01054 double x0, y0, x1, y1;
01055 std::stringstream cbuf;
01056 cbuf.precision (4);
01057 cbuf.width (6);
01058 pixel2pos (ax, px0, py0, x0, y0);
01059 cbuf << "[" << x0 << ", " << y0 << "]";
01060 if (px1 >= 0)
01061 {
01062 pixel2pos (ax, px1, py1, x1, y1);
01063 cbuf << " -> ["<< x1 << ", " << y1 << "]";
01064 }
01065
01066 status->value (cbuf.str ().c_str ());
01067 status->redraw ();
01068 }
01069
01070 void view2status (graphics_object ax)
01071 {
01072 if (ax && ax.isa ("axes"))
01073 {
01074 axes::properties& ap =
01075 dynamic_cast<axes::properties&> (ax.get_properties ());
01076 std::stringstream cbuf;
01077 cbuf.precision (4);
01078 cbuf.width (6);
01079 Matrix v (1,2,0);
01080 v = ap.get ("view").matrix_value ();
01081 cbuf << "[azimuth: " << v(0) << ", elevation: " << v(1) << "]";
01082
01083 status->value (cbuf.str ().c_str ());
01084 status->redraw ();
01085 }
01086 }
01087
01088 void set_currentpoint (int px, int py)
01089 {
01090 if (!fp.is_beingdeleted ())
01091 {
01092 Matrix pos (1,2,0);
01093 pos(0) = px;
01094 pos(1) = h () - status_h - menu_h - py;
01095 fp.set_currentpoint (pos);
01096 }
01097 }
01098
01099 void set_axes_currentpoint (graphics_object ax, int px, int py)
01100 {
01101 if (ax.valid_object ())
01102 {
01103 axes::properties& ap =
01104 dynamic_cast<axes::properties&> (ax.get_properties ());
01105
01106 double xx, yy;
01107 pixel2pos (ax, px, py, xx, yy);
01108
01109 Matrix pos (2,3,0);
01110 pos(0,0) = xx;
01111 pos(1,0) = yy;
01112 pos(0,1) = xx;
01113 pos(1,1) = yy;
01114
01115 ap.set_currentpoint (pos);
01116 }
01117 }
01118
01119 int key2shift (int key)
01120 {
01121 if (key == FL_Shift_L || key == FL_Shift_R)
01122 return FL_SHIFT;
01123
01124 if (key == FL_Control_L || key == FL_Control_R)
01125 return FL_CTRL;
01126
01127 if (key == FL_Alt_L || key == FL_Alt_R)
01128 return FL_ALT;
01129
01130 if (key == FL_Meta_L || key == FL_Meta_R)
01131 return FL_META;
01132
01133 return 0;
01134 }
01135
01136 int key2ascii (int key)
01137 {
01138 if (key < 256) return key;
01139 if (key == FL_Tab) return '\t';
01140 if (key == FL_Enter) return 0x0a;
01141 if (key == FL_BackSpace) return 0x08;
01142 if (key == FL_Escape) return 0x1b;
01143
01144 return 0;
01145 }
01146
01147 Cell modifier2cell ()
01148 {
01149 string_vector mod;
01150
01151 if (shift & FL_SHIFT)
01152 mod.append (std::string ("shift"));
01153 if (shift & FL_CTRL)
01154 mod.append (std::string ("control"));
01155 if (shift & FL_ALT || shift & FL_META)
01156 mod.append (std::string ("alt"));
01157
01158 return Cell (mod);
01159 }
01160
01161 void resize (int xx,int yy,int ww,int hh)
01162 {
01163 Fl_Window::resize (xx, yy, ww, hh);
01164
01165 Matrix pos (1,4,0);
01166 pos(0) = xx;
01167 pos(1) = yy;
01168 pos(2) = ww;
01169 pos(3) = hh - status_h - menu_h;
01170
01171 fp.set_position (pos);
01172 }
01173
01174 void draw (void)
01175 {
01176 Matrix pos = fp.get_position ().matrix_value ();
01177 Fl_Window::resize (pos(0), pos(1), pos(2), pos(3) + status_h + menu_h);
01178
01179 return Fl_Window::draw ();
01180 }
01181
01182 int handle (int event)
01183 {
01184 graphics_handle gh;
01185
01186 graphics_object fig = gh_manager::get_object (fp.get___myhandle__ ());
01187 int retval = Fl_Window::handle (event);
01188
01189
01190 if (!Fl::event_inside (canvas))
01191 return retval;
01192
01193 if (!fp.is_beingdeleted ())
01194 {
01195 switch (event)
01196 {
01197 case FL_KEYDOWN:
01198 {
01199 int key = Fl::event_key ();
01200
01201 shift |= key2shift (key);
01202 int key_a = key2ascii (key);
01203 if (key_a && fp.get_keypressfcn ().is_defined ())
01204 {
01205 Octave_map evt;
01206 evt.assign ("Character", octave_value (key_a));
01207 evt.assign ("Key", octave_value (std::tolower (key_a)));
01208 evt.assign ("Modifier", octave_value (modifier2cell ()));
01209 fp.execute_keypressfcn (evt);
01210 }
01211 switch (key)
01212 {
01213 case 'a':
01214 case 'A':
01215 axis_auto ();
01216 break;
01217
01218 case 'g':
01219 case 'G':
01220 toggle_grid ();
01221 break;
01222
01223 case 'p':
01224 case 'P':
01225 gui_mode = pan_zoom;
01226 break;
01227
01228 case 'r':
01229 case 'R':
01230 gui_mode = rotate_zoom;
01231 break;
01232 }
01233 }
01234 break;
01235
01236 case FL_KEYUP:
01237 {
01238 int key = Fl::event_key ();
01239
01240 shift &= (~key2shift (key));
01241 int key_a = key2ascii (key);
01242 if (key_a && fp.get_keyreleasefcn ().is_defined ())
01243 {
01244 Octave_map evt;
01245 evt.assign ("Character", octave_value (key_a));
01246 evt.assign ("Key", octave_value (std::tolower (key_a)));
01247 evt.assign ("Modifier", octave_value (modifier2cell ()));
01248 fp.execute_keyreleasefcn (evt);
01249 }
01250 }
01251 break;
01252
01253 case FL_MOVE:
01254 pixel2status (pixel2axes_or_ca (Fl::event_x (), Fl::event_y ()),
01255 Fl::event_x (), Fl::event_y ());
01256 break;
01257
01258 case FL_PUSH:
01259 pos_x = Fl::event_x ();
01260 pos_y = Fl::event_y ();
01261
01262 set_currentpoint (Fl::event_x (), Fl::event_y ());
01263
01264 gh = pixel2axes_or_ca (pos_x, pos_y);
01265
01266 if (gh.ok ())
01267 {
01268 ax_obj = gh_manager::get_object (gh);
01269 set_axes_currentpoint (ax_obj, pos_x, pos_y);
01270 }
01271
01272 fp.execute_windowbuttondownfcn ();
01273
01274 if (Fl::event_button () == 1 || Fl::event_button () == 3)
01275 return 1;
01276
01277 break;
01278
01279 case FL_DRAG:
01280 if (fp.get_windowbuttonmotionfcn ().is_defined ())
01281 {
01282 set_currentpoint (Fl::event_x (), Fl::event_y ());
01283 fp.execute_windowbuttonmotionfcn ();
01284 }
01285
01286 if (Fl::event_button () == 1)
01287 {
01288 if (ax_obj && ax_obj.isa ("axes"))
01289 {
01290 if (gui_mode == pan_zoom)
01291 pixel2status (ax_obj, pos_x, pos_y,
01292 Fl::event_x (), Fl::event_y ());
01293 else
01294 view2status (ax_obj);
01295 axes::properties& ap =
01296 dynamic_cast<axes::properties&> (ax_obj.get_properties ());
01297
01298 double x0, y0, x1, y1;
01299 Matrix pos = fp.get_position ().matrix_value ();
01300 pixel2pos (ax_obj, pos_x, pos_y, x0, y0);
01301 pixel2pos (ax_obj, Fl::event_x (), Fl::event_y (), x1, y1);
01302
01303 if (gui_mode == pan_zoom)
01304 ap.translate_view (x0 - x1, y0 - y1);
01305 else if (gui_mode == rotate_zoom)
01306 {
01307 double daz, del;
01308 daz = (Fl::event_x () - pos_x) / pos(2) * 360;
01309 del = (Fl::event_y () - pos_y) / pos(3) * 360;
01310 ap.rotate_view (del, daz);
01311 }
01312
01313 pos_x = Fl::event_x ();
01314 pos_y = Fl::event_y ();
01315 mark_modified ();
01316 }
01317 return 1;
01318 }
01319 else if (Fl::event_button () == 3)
01320 {
01321 pixel2status (ax_obj, pos_x, pos_y,
01322 Fl::event_x (), Fl::event_y ());
01323 Matrix zoom_box (1,4,0);
01324 zoom_box (0) = pos_x;
01325 zoom_box (1) = pos_y;
01326 zoom_box (2) = Fl::event_x ();
01327 zoom_box (3) = Fl::event_y ();
01328 canvas->set_zoom_box (zoom_box);
01329 canvas->zoom (true);
01330 canvas->redraw ();
01331 }
01332
01333 break;
01334
01335 case FL_MOUSEWHEEL:
01336 {
01337 graphics_object ax =
01338 gh_manager::get_object (pixel2axes_or_ca (Fl::event_x (),
01339 Fl::event_y ()));
01340 if (ax && ax.isa ("axes"))
01341 {
01342 axes::properties& ap =
01343 dynamic_cast<axes::properties&> (ax.get_properties ());
01344
01345
01346 const double factor =
01347 (Fl::event_dy () > 0) ? 1.0 + wheel_zoom_speed : 1.0 - wheel_zoom_speed;
01348
01349
01350 double x1, y1;
01351 pixel2pos (ax, Fl::event_x (), Fl::event_y (), x1, y1);
01352
01353 ap.zoom_about_point (x1, y1, factor, false);
01354 mark_modified ();
01355 }
01356 }
01357 return 1;
01358
01359 case FL_RELEASE:
01360 if (fp.get_windowbuttonupfcn ().is_defined ())
01361 {
01362 set_currentpoint (Fl::event_x (), Fl::event_y ());
01363 fp.execute_windowbuttonupfcn ();
01364 }
01365
01366 if (Fl::event_button () == 1)
01367 {
01368 if ( Fl::event_clicks () == 1)
01369 {
01370 if (ax_obj && ax_obj.isa ("axes"))
01371 {
01372 axes::properties& ap =
01373 dynamic_cast<axes::properties&> (ax_obj.get_properties ());
01374 ap.set_xlimmode ("auto");
01375 ap.set_ylimmode ("auto");
01376 ap.set_zlimmode ("auto");
01377 mark_modified ();
01378 }
01379 }
01380 }
01381 if (Fl::event_button () == 3)
01382 {
01383
01384 if (canvas->zoom ())
01385 {
01386 canvas->zoom (false);
01387 double x0,y0,x1,y1;
01388 if (ax_obj && ax_obj.isa ("axes"))
01389 {
01390 axes::properties& ap =
01391 dynamic_cast<axes::properties&> (ax_obj.get_properties ());
01392 pixel2pos (ax_obj, pos_x, pos_y, x0, y0);
01393 pixel2pos (ax_obj, Fl::event_x (), Fl::event_y (),
01394 x1, y1);
01395 Matrix xl (1,2,0);
01396 Matrix yl (1,2,0);
01397 if (x0 < x1)
01398 {
01399 xl(0) = x0;
01400 xl(1) = x1;
01401 }
01402 else
01403 {
01404 xl(0) = x1;
01405 xl(1) = x0;
01406 }
01407 if (y0 < y1)
01408 {
01409 yl(0) = y0;
01410 yl(1) = y1;
01411 }
01412 else
01413 {
01414 yl(0) = y1;
01415 yl(1) = y0;
01416 }
01417 ap.zoom (xl, yl);
01418 mark_modified ();
01419 }
01420 }
01421 }
01422 break;
01423 }
01424 }
01425
01426 return retval;
01427 }
01428 };
01429
01430 class figure_manager
01431 {
01432 public:
01433
01434 static bool instance_ok (void)
01435 {
01436 bool retval = true;
01437
01438 if (! instance)
01439 instance = new figure_manager ();
01440
01441 if (! instance)
01442 {
01443 ::error ("unable to create figure_manager object!");
01444
01445 retval = false;
01446 }
01447
01448 return retval;
01449 }
01450
01451 ~figure_manager (void)
01452 {
01453 close_all ();
01454 }
01455
01456 static void close_all (void)
01457 {
01458 if (instance_ok ())
01459 instance->do_close_all ();
01460 }
01461
01462 static void new_window (figure::properties& fp)
01463 {
01464 if (instance_ok ())
01465 instance->do_new_window (fp);
01466 }
01467
01468 static void delete_window (int idx)
01469 {
01470 if (instance_ok ())
01471 instance->do_delete_window (idx);
01472 }
01473
01474 static void delete_window (const std::string& idx_str)
01475 {
01476 delete_window (str2idx (idx_str));
01477 }
01478
01479 static void renumber_figure (const std::string& idx_str, double new_number)
01480 {
01481 if (instance_ok ())
01482 instance->do_renumber_figure (str2idx (idx_str), new_number);
01483 }
01484
01485 static void toggle_window_visibility (int idx, bool is_visible)
01486 {
01487 if (instance_ok ())
01488 instance->do_toggle_window_visibility (idx, is_visible);
01489 }
01490
01491 static void toggle_window_visibility (const std::string& idx_str,
01492 bool is_visible)
01493 {
01494 toggle_window_visibility (str2idx (idx_str), is_visible);
01495 }
01496
01497 static void mark_modified (int idx)
01498 {
01499 if (instance_ok ())
01500 instance->do_mark_modified (idx);
01501 }
01502
01503 static void mark_modified (const graphics_handle& gh)
01504 {
01505 mark_modified (hnd2idx (gh));
01506 }
01507
01508 static void set_name (int idx)
01509 {
01510 if (instance_ok ())
01511 instance->do_set_name (idx);
01512 }
01513
01514 static void set_name (const std::string& idx_str)
01515 {
01516 set_name (str2idx (idx_str));
01517 }
01518
01519 static Matrix get_size (int idx)
01520 {
01521 return instance_ok () ? instance->do_get_size (idx) : Matrix ();
01522 }
01523
01524 static Matrix get_size (const graphics_handle& gh)
01525 {
01526 return get_size (hnd2idx (gh));
01527 }
01528
01529 static void print (const graphics_handle& gh, const std::string& cmd,
01530 const std::string& term)
01531 {
01532 if (instance_ok ())
01533 instance->do_print (hnd2idx (gh), cmd, term);
01534 }
01535
01536 static void uimenu_update (const graphics_handle& figh,
01537 const graphics_handle& uimenuh, int id)
01538 {
01539 if (instance_ok ())
01540 instance->do_uimenu_update (hnd2idx (figh), uimenuh, id);
01541 }
01542
01543 static void update_canvas (const graphics_handle& gh,
01544 const graphics_handle& ca)
01545 {
01546 if (instance_ok ())
01547 instance->do_update_canvas (hnd2idx (gh), ca);
01548 }
01549
01550 static void toggle_menubar_visibility (int fig_idx, bool menubar_is_figure)
01551 {
01552 if (instance_ok ())
01553 instance->do_toggle_menubar_visibility (fig_idx, menubar_is_figure);
01554 }
01555
01556 static void toggle_menubar_visibility (const std::string& fig_idx_str,
01557 bool menubar_is_figure)
01558 {
01559 toggle_menubar_visibility (str2idx (fig_idx_str), menubar_is_figure);
01560 }
01561
01562 private:
01563
01564 static figure_manager *instance;
01565
01566 figure_manager (void) { }
01567
01568
01569 figure_manager (const figure_manager&);
01570 figure_manager& operator = (const figure_manager&);
01571
01572
01573
01574 static int curr_index;
01575 typedef std::map<int, plot_window*> window_map;
01576 typedef window_map::iterator wm_iterator;;
01577 window_map windows;
01578
01579 static std::string fltk_idx_header;
01580
01581 void do_close_all (void)
01582 {
01583 wm_iterator win;
01584 for (win = windows.begin (); win != windows.end (); win++)
01585 delete win->second;
01586 windows.clear ();
01587 }
01588
01589 void do_new_window (figure::properties& fp)
01590 {
01591 int idx = figprops2idx (fp);
01592
01593 if (idx >= 0 && windows.find (idx) == windows.end ())
01594 {
01595 Matrix pos = fp.get_boundingbox (true);
01596
01597 int x = pos(0);
01598 int y = pos(1);
01599 int w = pos(2);
01600 int h = pos(3);
01601
01602 idx2figprops (curr_index, fp);
01603
01604 windows[curr_index++] = new plot_window (x, y, w, h, fp);
01605 }
01606 }
01607
01608 void do_delete_window (int idx)
01609 {
01610 wm_iterator win = windows.find (idx);
01611
01612 if (win != windows.end ())
01613 {
01614 delete win->second;
01615 windows.erase (win);
01616 }
01617 }
01618
01619 void do_renumber_figure (int idx, double new_number)
01620 {
01621 wm_iterator win = windows.find (idx);
01622
01623 if (win != windows.end ())
01624 win->second->renumber (new_number);
01625 }
01626
01627 void do_toggle_window_visibility (int idx, bool is_visible)
01628 {
01629 wm_iterator win = windows.find (idx);
01630
01631 if (win != windows.end ())
01632 {
01633 if (is_visible)
01634 win->second->show ();
01635 else
01636 win->second->hide ();
01637
01638 win->second->redraw ();
01639 }
01640 }
01641
01642 void do_toggle_menubar_visibility (int fig_idx, bool menubar_is_figure)
01643 {
01644 wm_iterator win = windows.find (fig_idx);
01645
01646 if (win != windows.end ())
01647 {
01648 if (menubar_is_figure)
01649 win->second->show_menubar ();
01650 else
01651 win->second->hide_menubar ();
01652
01653 win->second->redraw ();
01654 }
01655 }
01656
01657 void do_mark_modified (int idx)
01658 {
01659 wm_iterator win = windows.find (idx);
01660
01661 if (win != windows.end ())
01662 win->second->mark_modified ();
01663 }
01664
01665 void do_set_name (int idx)
01666 {
01667 wm_iterator win = windows.find (idx);
01668
01669 if (win != windows.end ())
01670 win->second->set_name ();
01671 }
01672
01673 Matrix do_get_size (int idx)
01674 {
01675 Matrix sz (1, 2, 0.0);
01676
01677 wm_iterator win = windows.find (idx);
01678
01679 if (win != windows.end ())
01680 {
01681 sz(0) = win->second->w ();
01682 sz(1) = win->second->h ();
01683 }
01684
01685 return sz;
01686 }
01687
01688 void do_print (int idx, const std::string& cmd, const std::string& term)
01689 {
01690 wm_iterator win = windows.find (idx);
01691
01692 if (win != windows.end ())
01693 win->second->print (cmd, term);
01694 }
01695
01696 void do_uimenu_update (int idx, const graphics_handle& gh, int id)
01697 {
01698 wm_iterator win = windows.find (idx);
01699
01700 if (win != windows.end ())
01701 win->second->uimenu_update (gh, id);
01702 }
01703
01704 void do_update_canvas (int idx, const graphics_handle& ca)
01705 {
01706 wm_iterator win = windows.find (idx);
01707
01708 if (win != windows.end ())
01709 {
01710 if (ca.ok ())
01711 win->second->show_canvas ();
01712 else
01713 win->second->hide_canvas ();
01714 }
01715 }
01716
01717 static int str2idx (const caseless_str& clstr)
01718 {
01719 int ind;
01720 if (clstr.find (fltk_idx_header,0) == 0)
01721 {
01722 std::istringstream istr (clstr.substr (fltk_idx_header.size ()));
01723 if (istr >> ind)
01724 return ind;
01725 }
01726 error ("figure_manager: could not recognize fltk index");
01727 return -1;
01728 }
01729
01730 void idx2figprops (int idx, figure::properties& fp)
01731 {
01732 std::ostringstream ind_str;
01733 ind_str << fltk_idx_header << idx;
01734 fp.set___plot_stream__ (ind_str.str ());
01735 }
01736
01737 static int figprops2idx (const figure::properties& fp)
01738 {
01739 if (fp.get___graphics_toolkit__ () == FLTK_GRAPHICS_TOOLKIT_NAME)
01740 {
01741 octave_value ps = fp.get___plot_stream__ ();
01742 if (ps.is_string ())
01743 return str2idx (ps.string_value ());
01744 else
01745 return 0;
01746 }
01747 error ("figure_manager: figure is not fltk");
01748 return -1;
01749 }
01750
01751 static int hnd2idx (double h)
01752 {
01753 graphics_object fobj = gh_manager::get_object (h);
01754 if (fobj && fobj.isa ("figure"))
01755 {
01756 figure::properties& fp =
01757 dynamic_cast<figure::properties&> (fobj.get_properties ());
01758 return figprops2idx (fp);
01759 }
01760 error ("figure_manager: H (= %g) is not a figure", h);
01761 return -1;
01762 }
01763
01764 static int hnd2idx (const graphics_handle& fh)
01765 {
01766 return hnd2idx (fh.value ());
01767 }
01768 };
01769
01770 figure_manager *figure_manager::instance = 0;
01771
01772 std::string figure_manager::fltk_idx_header="fltk index=";
01773 int figure_manager::curr_index = 1;
01774
01775 static bool toolkit_loaded = false;
01776
01777 static int
01778 __fltk_redraw__ (void)
01779 {
01780 if (toolkit_loaded)
01781 {
01782
01783 graphics_object obj = gh_manager::get_object (0);
01784 if (obj && obj.isa ("root"))
01785 {
01786 base_properties& props = obj.get_properties ();
01787 Matrix children = props.get_all_children ();
01788
01789 for (octave_idx_type n = 0; n < children.numel (); n++)
01790 {
01791 graphics_object fobj = gh_manager::get_object (children (n));
01792 if (fobj && fobj.isa ("figure"))
01793 {
01794 figure::properties& fp =
01795 dynamic_cast<figure::properties&> (fobj.get_properties ());
01796 if (fp.get___graphics_toolkit__ ()
01797 == FLTK_GRAPHICS_TOOLKIT_NAME)
01798 figure_manager::new_window (fp);
01799 }
01800 }
01801 }
01802
01803
01804 Fl::check ();
01805 Fl::check ();
01806 }
01807
01808 return 0;
01809 }
01810
01811 class fltk_graphics_toolkit : public base_graphics_toolkit
01812 {
01813 public:
01814 fltk_graphics_toolkit (void)
01815 : base_graphics_toolkit (FLTK_GRAPHICS_TOOLKIT_NAME) { }
01816
01817 ~fltk_graphics_toolkit (void) { }
01818
01819 bool is_valid (void) const { return true; }
01820
01821 bool initialize (const graphics_object& go)
01822 { return go.isa ("figure"); }
01823
01824 void finalize (const graphics_object& go)
01825 {
01826 if (go.isa ("figure"))
01827 {
01828 octave_value ov = go.get (caseless_str ("__plot_stream__"));
01829
01830 if (! ov.is_empty ())
01831 figure_manager::delete_window (ov.string_value ());
01832 }
01833 }
01834
01835 void uimenu_set_fltk_label (graphics_object uimenu_obj)
01836 {
01837 if (uimenu_obj.valid_object ())
01838 {
01839 uimenu::properties& uimenup =
01840 dynamic_cast<uimenu::properties&> (uimenu_obj.get_properties ());
01841 std::string fltk_label = uimenup.get_label ();
01842 graphics_object go = gh_manager::get_object (uimenu_obj.get_parent ());
01843 if (go.isa ("uimenu"))
01844 fltk_label = dynamic_cast<const uimenu::properties&> (go.get_properties ()).get_fltk_label ()
01845 + "/"
01846 + fltk_label;
01847 else if (go.isa ("figure"))
01848 ;
01849 else
01850 error ("unexpected parent object\n");
01851
01852 uimenup.set_fltk_label (fltk_label);
01853 }
01854 }
01855
01856 void update (const graphics_object& go, int id)
01857 {
01858 if (go.isa ("figure"))
01859 {
01860 octave_value ov = go.get (caseless_str ("__plot_stream__"));
01861
01862 if (! ov.is_empty ())
01863 {
01864 const figure::properties& fp =
01865 dynamic_cast<const figure::properties&> (go.get_properties ());
01866
01867 switch (id)
01868 {
01869 case base_properties::ID_VISIBLE:
01870 figure_manager::toggle_window_visibility
01871 (ov.string_value (), fp.is_visible ());
01872 break;
01873
01874 case figure::properties::ID_MENUBAR:
01875 figure_manager::toggle_menubar_visibility
01876 (ov.string_value (), fp.menubar_is ("figure"));
01877 break;
01878
01879 case figure::properties::ID_CURRENTAXES:
01880 figure_manager::update_canvas
01881 (go.get_handle (), fp.get_currentaxes ());
01882 break;
01883
01884 case figure::properties::ID_NAME:
01885 case figure::properties::ID_NUMBERTITLE:
01886 figure_manager::set_name (ov.string_value ());
01887 break;
01888
01889 case figure::properties::ID_INTEGERHANDLE:
01890 {
01891 std::string tmp = ov.string_value ();
01892 graphics_handle gh = fp.get___myhandle__ ();
01893 figure_manager::renumber_figure (tmp, gh.value ());
01894 figure_manager::set_name (tmp);
01895 }
01896 break;
01897 }
01898 }
01899 }
01900 else if (go.isa ("uimenu"))
01901 {
01902 if (id == uimenu::properties::ID_LABEL)
01903 uimenu_set_fltk_label (go);
01904
01905 graphics_object fig = go.get_ancestor("figure");
01906 figure_manager::uimenu_update(fig.get_handle (), go.get_handle (), id);
01907 }
01908 }
01909
01910 void redraw_figure (const graphics_object& go) const
01911 {
01912 figure_manager::mark_modified (go.get_handle ());
01913
01914 __fltk_redraw__ ();
01915 }
01916
01917 void print_figure (const graphics_object& go,
01918 const std::string& term,
01919 const std::string& file_cmd, bool ,
01920 const std::string& ) const
01921 {
01922 figure_manager::print (go.get_handle (), file_cmd, term);
01923 redraw_figure (go);
01924 }
01925
01926 Matrix get_canvas_size (const graphics_handle& fh) const
01927 {
01928 return figure_manager::get_size (fh);
01929 }
01930
01931 double get_screen_resolution (void) const
01932 {
01933
01934 return 72.0;
01935 }
01936
01937 Matrix get_screen_size (void) const
01938 {
01939 Matrix sz (1, 2, 0.0);
01940 sz(0) = Fl::w ();
01941 sz(1) = Fl::h ();
01942 return sz;
01943 }
01944
01945 void close (void)
01946 {
01947 if (toolkit_loaded)
01948 {
01949 munlock ("__init_fltk__");
01950
01951 figure_manager::close_all ();
01952 gtk_manager::unload_toolkit (FLTK_GRAPHICS_TOOLKIT_NAME);
01953 toolkit_loaded = false;
01954
01955 octave_value_list args;
01956 args(0) = "__fltk_redraw__";
01957 feval ("remove_input_event_hook", args, 0);
01958
01959
01960 Fl::wait (fltk_maxtime);
01961 }
01962 }
01963 };
01964
01965
01966
01967 DEFUN_DLD (__init_fltk__, , , "")
01968 {
01969 if (! toolkit_loaded)
01970 {
01971 mlock ();
01972
01973 graphics_toolkit tk (new fltk_graphics_toolkit ());
01974 gtk_manager::load_toolkit (tk);
01975 toolkit_loaded = true;
01976
01977 octave_value_list args;
01978 args(0) = "__fltk_redraw__";
01979 feval ("add_input_event_hook", args, 0);
01980 }
01981
01982 octave_value retval;
01983 return retval;
01984 }
01985
01986 DEFUN_DLD (__fltk_redraw__, , , "")
01987 {
01988 __fltk_redraw__ ();
01989
01990 return octave_value ();
01991 }
01992
01993 DEFUN_DLD (__fltk_maxtime__, args, ,"")
01994 {
01995 octave_value retval = fltk_maxtime;
01996
01997 if (args.length () == 1)
01998 {
01999 if (args(0).is_real_scalar ())
02000 fltk_maxtime = args(0).double_value ();
02001 else
02002 error ("argument must be a real scalar");
02003 }
02004
02005 return retval;
02006 }
02007
02008 #endif
02009
02010
02011
02012
02013
02014
02015
02016
02017 DEFUN_DLD (mouse_wheel_zoom, args, ,
02018 "-*- texinfo -*-\n\
02019 @deftypefn {Built-in Function} {@var{speed} =} mouse_wheel_zoom ()\n\
02020 @deftypefnx {Built-in Function} {} mouse_wheel_zoom (@var{speed})\n\
02021 Query or set the mouse wheel zoom factor.\n\
02022 \n\
02023 This function is currently implemented only for the FLTK graphics toolkit.\n\
02024 @seealso{gui_mode}\n\
02025 @end deftypefn")
02026 {
02027 #if defined (HAVE_FLTK)
02028 octave_value retval = wheel_zoom_speed;
02029
02030 if (args.length () == 1)
02031 {
02032 if (args(0).is_real_scalar ())
02033 wheel_zoom_speed = args(0).double_value ();
02034 else
02035 error ("mouse_wheel_zoom: SPEED must be a real scalar");
02036 }
02037
02038 return retval;
02039 #else
02040 error ("mouse_wheel_zoom: not available without OpenGL and FLTK libraries");
02041 return octave_value ();
02042 #endif
02043 }
02044
02045 DEFUN_DLD (gui_mode, args, ,
02046 "-*- texinfo -*-\n\
02047 @deftypefn {Built-in Function} {@var{mode} =} gui_mode ()\n\
02048 @deftypefnx {Built-in Function} {} gui_mode (@var{mode})\n\
02049 Query or set the GUI mode for the current graphics toolkit.\n\
02050 The @var{mode} argument can be one of the following strings:\n\
02051 @table @asis\n\
02052 @item '2d'\n\
02053 Allows panning and zooming of current axes.\n\
02054 \n\
02055 @item '3d'\n\
02056 Allows rotating and zooming of current axes.\n\
02057 \n\
02058 @item 'none'\n\
02059 Mouse inputs have no effect.\n\
02060 @end table\n\
02061 \n\
02062 This function is currently implemented only for the FLTK graphics toolkit.\n\
02063 @seealso{mouse_wheel_zoom}\n\
02064 @end deftypefn")
02065 {
02066 #if defined (HAVE_FLTK)
02067 caseless_str mode_str;
02068
02069 if (gui_mode == pan_zoom)
02070 mode_str = "2d";
02071 else if (gui_mode == rotate_zoom)
02072 mode_str = "3d";
02073 else
02074 mode_str = "none";
02075
02076 bool failed = false;
02077
02078 if (args.length () == 1)
02079 {
02080 if (args(0).is_string ())
02081 {
02082 mode_str = args(0).string_value ();
02083
02084 if (mode_str.compare ("2d"))
02085 gui_mode = pan_zoom;
02086 else if (mode_str.compare ("3d"))
02087 gui_mode = rotate_zoom;
02088 else if (mode_str.compare ("none"))
02089 gui_mode = none;
02090 else
02091 failed = true;
02092 }
02093 else
02094 failed = true;
02095 }
02096
02097 if (failed)
02098 error ("MODE must be one of the strings: \"2D\", \"3D\", or \"none\"");
02099
02100 return octave_value (mode_str);
02101 #else
02102 error ("mouse_wheel_zoom: not available without OpenGL and FLTK libraries");
02103 return octave_value ();
02104 #endif
02105 }
02106