# HG changeset patch # User Kai Habel # Date 1287671014 -7200 # Node ID f6c09b3fbcaba0d397f7962a4a0b62433044ce92 # Parent 304b0ed4ca5674137f1e2e964b96eacaebad50fc [mq]: uimenu diff -r 304b0ed4ca56 -r f6c09b3fbcab scripts/plot/uimenu.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/plot/uimenu.m Thu Oct 21 16:23:34 2010 +0200 @@ -0,0 +1,54 @@ +## Copyright (C) 2010 Kai Habel +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or (at +## your option) any later version. +## +## Octave is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## . + +## -*- texinfo -*- +## @deftypefn {Function File} {} uimenu (@var{property}, @var{value}, @dots{}) +## @deftypefnx {Function File} {} uimenu (@var{h}, @var{property}, @var{value}, @dots{}) +## Create an uimenu object and return a handle to it. +## @end deftypefn + +## Author: Kai Habel + +function hui = uimenu (varargin) + + args = varargin; + if (nargin == 0) + h = gcf(); + elseif (nargin == 1) + if (ishandle(args{1})) + h = args{1}; + args(1) = []; + else + error("expected handle as first argument"); + endif + else + if (ishandle(args{1})) + h = args{1}; + args(1) = []; + else + h = gcf(); + endif + endif + + tmp = __go_uimenu__ (h, args{:}); + + if (nargout > 0) + hui = tmp; + endif + +endfunction diff -r 304b0ed4ca56 -r f6c09b3fbcab src/DLD-FUNCTIONS/fltk_backend.cc --- a/src/DLD-FUNCTIONS/fltk_backend.cc Thu Oct 21 00:44:32 2010 -0400 +++ b/src/DLD-FUNCTIONS/fltk_backend.cc Thu Oct 21 16:23:34 2010 +0200 @@ -41,11 +41,15 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include -#include -#include -#include #include #include #include @@ -81,6 +85,8 @@ left double click - autoscale\n\ "; +graphics_object xget_ancestor (const graphics_object& go_arg, + const std::string& type); class OpenGL_fltk : public Fl_Gl_Window { @@ -111,6 +117,13 @@ print_term = term; } + void resize (int xx, int yy, int ww, int hh) + { + Fl_Gl_Window::resize (xx, yy, ww, hh); + setup_viewport (ww, hh); + redraw (); + } + private: double number; opengl_renderer renderer; @@ -152,13 +165,6 @@ } } - void resize (int xx, int yy, int ww, int hh) - { - Fl_Gl_Window::resize (xx, yy, ww, hh); - setup_viewport (ww, hh); - redraw (); - } - void zoom_box_vertex (void) { glVertex2d (zoom_box(0), h () - zoom_box(1)); @@ -219,8 +225,396 @@ // Parameter controlling how fast we zoom when using the scrool wheel. static double wheel_zoom_speed = 0.05; +void script_cb(Fl_Widget*, void* data) + { + static_cast (data)->execute_callback (); + } + + +class fltk_uimenu +{ +public: + fltk_uimenu (int xx, int yy, int ww, int hh) + { + menubar = new + Fl_Menu_Bar(xx, yy, ww, hh); + } + + int items_to_show (void) + { + //returns the number of visible menu items + int len = menubar->size (); + int n = 0; + for (int t = 0; t < len; t++ ) + { + const Fl_Menu_Item *m = static_cast(&(menubar->menu ()[t])); + if ((m->label () != NULL) && m->visible ()) + n++; + } + + return n; + } + + void show (void) + { + menubar->show (); + } + + void hide (void) + { + menubar->hide (); + } + + bool is_visible (void) + { + return menubar->visible (); + } + + void print_menubar(void) + { + // for debugging - might be removed after things have settled + printf("menubar\n"); + printf("________________\n"); + for (int t = 0; t < menubar->size (); t++ ) + { + const Fl_Menu_Item *m = static_cast(&(menubar->menu ()[t])); + std::string sub = "submenu"; + if (!m->submenu ()) + sub.erase (); + printf("idx: %d, label: %s flags: %d %s\n",t, m->label (), m->flags, sub.c_str ()); + } + printf("________________\n"); + } + + int find_index_by_name (std::string findname) + { + // This function is derived from Greg Ercolano's function + // int GetIndexByName(...), see: + // http://seriss.com/people/erco/fltk/#Menu_ChangeLabel + // He agreed via PM that it can be included in octave using GPLv3 + // Kai Habel (14.10.2010) + + std::string menupath; + for (int t = 0; t < menubar->size (); t++ ) + { + Fl_Menu_Item *m = const_cast(&(menubar->menu ()[t])); + if (m->submenu ()) + { + // item has submenu + if (!menupath.empty ()) + menupath += "/"; + menupath += m->label (); + + if (menupath.compare (findname) == 0 ) + return (t); + } + else + { + // End of submenu? Pop back one level. + if (m->label () == NULL) + { + std::size_t idx = menupath.find_last_of ("/"); + if (idx != std::string::npos) + menupath.erase (idx); + else + menupath.clear (); + continue; + } + // Menu item? + std::string itempath = menupath; + if (!itempath.empty ()) + itempath += "/"; + itempath += m->label (); + + if (itempath.compare (findname) == 0) + return (t); + } + } + return (-1); + } + + template + Matrix find_uimenu_children (T& prop) const + { + octave_idx_type k = 0; + + Matrix uimenu_childs = prop.get_children (); + Matrix pos = Matrix (uimenu_childs.numel (), 1); + + for (octave_idx_type ii = 0; ii < uimenu_childs.numel (); ii++) + { + graphics_handle kid = uimenu_childs (ii); + + if (gh_manager::is_handle_visible (kid)) + { + graphics_object kidgo = gh_manager::get_object (kid); + if (kidgo.isa ("uimenu")) + { + uimenu_childs(k) = uimenu_childs(ii); + pos(k++) = + dynamic_cast (kidgo.get_properties ()).get_position (); + std::string lbl = + dynamic_cast (kidgo.get_properties ()).get_fltk_label (); + } + } + } + + uimenu_childs.resize (k, 1); + pos.resize (k, 1); + Matrix retval = Matrix (k, 1); + // Don't know if this is the best method to sort. + // Can we avoid the for loop? + Array sidx = pos.sort_rows_idx (DESCENDING); + for (octave_idx_type ii = 0; ii < k; ii++) + retval(ii) = uimenu_childs (sidx(ii)); + + return retval; + } + + void update_submenu (uimenu::properties& uimenup) + { + Matrix uimenu_ch = find_uimenu_children (uimenup); + + if (uimenu_ch.numel () > 0) + { + std::string fltk_label = uimenup.get_fltk_label (); + int idx = find_index_by_name (fltk_label.c_str ()); + Fl_Menu_Item* item = const_cast(&menubar->menu () [idx]); + menubar->mode(idx, item->flags|FL_SUBMENU); + } + } + + void delete_entry(uimenu::properties& uimenup) + { + std::string fltk_label = uimenup.get_fltk_label (); + int idx = find_index_by_name (fltk_label.c_str ()); + + if (idx >= 0) + menubar->remove (idx); + } + + void update_accelerator (uimenu::properties& uimenup) + { + std::string fltk_label = uimenup.get_fltk_label (); + if (!fltk_label.empty ()) + { + Fl_Menu_Item* item = const_cast(menubar->find_item (fltk_label.c_str ())); + std::string acc = uimenup.get_accelerator (); + if (acc.length () > 0) + { + int key = FL_CTRL + acc[0]; + item->shortcut (key); + } + } + } + + void update_callback (uimenu::properties& uimenup) + { + std::string fltk_label = uimenup.get_fltk_label (); + if (!fltk_label.empty ()) + { + Fl_Menu_Item* item = const_cast(menubar->find_item (fltk_label.c_str ())); + if (!uimenup.get_callback ().is_empty ()) + item->callback(static_cast(script_cb), //callback + static_cast(&uimenup)); //callback data + else + item->callback(NULL, static_cast(0)); + } + } + + void update_enable (uimenu::properties& uimenup) + { + std::string fltk_label = uimenup.get_fltk_label (); + if (!fltk_label.empty ()) + { + Fl_Menu_Item* item = const_cast(menubar->find_item (fltk_label.c_str ())); + if (uimenup.is_enable ()) + item->activate (); + else + item->deactivate (); + } + } + + void update_foregroundcolor (uimenu::properties& uimenup) + { + std::string fltk_label = uimenup.get_fltk_label (); + if (!fltk_label.empty ()) + { + Fl_Menu_Item* item = const_cast(menubar->find_item (fltk_label.c_str ())); + Matrix rgb = uimenup.get_foregroundcolor_rgb (); + item->labelcolor(fl_rgb_color(static_cast(floor (rgb(0)*255)), + static_cast(floor (rgb(1)*255)), + static_cast(floor (rgb(2)*255)))); + } + } + + void update_seperator (uimenu::properties& uimenup) + { + // Matlab places the separator before the current + // menu entry, while fltk places it after. So we need to find + // the previous item in this menu/submenu. (Kai) + std::string fltk_label = uimenup.get_fltk_label (); + if (!fltk_label.empty ()) + { + int itemflags = 0, idx; + int curr_idx = find_index_by_name(fltk_label.c_str ()); + + for (idx = curr_idx - 1; idx >= 0; idx--) + { + Fl_Menu_Item* item = const_cast(&menubar->menu () [idx]); + itemflags = item->flags; + if (item->label () != NULL) + break; + } + + if (uimenup.is_separator ()) + { + if (idx >= 0 && !(itemflags & FL_SUBMENU)) + menubar->mode (idx, itemflags | FL_MENU_DIVIDER); + } + else + menubar->mode (idx, itemflags & (~FL_MENU_DIVIDER)); + } + } + + void update_visible (uimenu::properties& uimenup) + { + std::string fltk_label = uimenup.get_fltk_label (); + if (!fltk_label.empty ()) + { + Fl_Menu_Item* item = const_cast(menubar->find_item (fltk_label.c_str ())); + if (uimenup.is_visible ()) + item->show (); + else + item->hide (); + } + } + + void add_entry (uimenu::properties& uimenup) + { + + std::string fltk_label = uimenup.get_fltk_label (); + + if (!fltk_label.empty ()) + { + bool item_added = false; + do + { + const Fl_Menu_Item* item = menubar->find_item(fltk_label.c_str ()); + + if (item == NULL) + { + Matrix uimenu_ch = find_uimenu_children (uimenup); + int len = uimenu_ch.numel (); + int flags = 0; + if (len > 0) + flags = FL_SUBMENU; + if ((len == 0) && (uimenup.is_checked ())) + flags += FL_MENU_TOGGLE + FL_MENU_VALUE; + menubar->add(fltk_label.c_str (), 0, 0, 0, flags); + item_added = true; + } + else + { + //avoid duplicate menulabels + std::size_t idx1 = fltk_label.find_last_of ("("); + std::size_t idx2 = fltk_label.find_last_of (")"); + int len = idx2 - idx1; + int val = 1; + if (len > 0) + { + std::string valstr = fltk_label.substr (idx1 + 1, len - 1); + fltk_label.erase(idx1, len + 1); + val = atoi (valstr.c_str ()); + if ((val > 0) && (val < 99)) + val++; + } + std::ostringstream valstream; + valstream << val; + fltk_label += "(" + valstream.str () + ")"; + } + } + while (!item_added); + uimenup.set_fltk_label (fltk_label); + } + } + + void add_to_menu (uimenu::properties& uimenup) + { + Matrix kids = find_uimenu_children (uimenup); + int len = kids.length (); + std::string fltk_label = uimenup.get_fltk_label (); + + add_entry (uimenup); + update_foregroundcolor (uimenup); + update_callback (uimenup); + update_accelerator (uimenup); + update_enable (uimenup); + update_visible (uimenup); + update_seperator (uimenup); + + for (octave_idx_type ii = 0; ii < len; ii++) + { + graphics_handle kid = kids (len - (ii + 1)); + graphics_object kgo = gh_manager::get_object (kid); + uimenu::properties& kprop = dynamic_cast(kgo.get_properties ()); + if (kgo.valid_object ()) + add_to_menu (kprop); + } + + + } + + void add_to_menu (figure::properties& figp) + { + Matrix kids = find_uimenu_children (figp); + int len = kids.length (); + menubar->clear (); + for (octave_idx_type ii = 0; ii < len; ii++) + { + graphics_handle kid = kids (len - (ii + 1)); + graphics_object kgo = gh_manager::get_object (kid); + uimenu::properties& kprop = dynamic_cast(kgo.get_properties ()); + if (kgo.valid_object ()) + add_to_menu (kprop); + } + } + + template + void remove_from_menu (T_prop& prop) + { + Matrix kids; + std::string type = prop.get_type (); + kids = find_uimenu_children (prop); + int len = kids.length (); + + for (octave_idx_type ii = 0; ii < len; ii++) + { + graphics_handle kid = kids (len - (ii + 1)); + graphics_object kgo = gh_manager::get_object (kid); + uimenu::properties kprop = dynamic_cast(kgo.get_properties ()); + if (kgo.valid_object ()) + remove_from_menu (kprop); + } + + if (type.compare("uimenu") == 0) + delete_entry(dynamic_cast(prop)); + else if (type.compare("figure") == 0) + menubar->clear (); + } + + ~fltk_uimenu() + { + delete menubar; + } + +private: + Fl_Menu_Bar* menubar; +}; + class plot_window : public Fl_Window { + friend class fltk_uimenu; public: plot_window (int xx, int yy, int ww, int hh, figure::properties& xfp) : Fl_Window (xx, yy, ww, hh, "octave"), window_label (), shift (0), @@ -231,6 +625,11 @@ begin (); { + + uimenu = new + fltk_uimenu(0, 0, ww, menu_h); + uimenu->hide (); + canvas = new OpenGL_fltk (0, 0, ww , hh - status_h, number ()); @@ -308,8 +707,10 @@ if (fp.is_visible ()) { show (); - canvas->show (); - canvas->make_current (); + if (fp.get_currentaxes ().ok()) + show_canvas (); + else + hide_canvas (); } } end (); @@ -324,15 +725,22 @@ resizable (canvas); size_range (4*status_h, 2*status_h); gui_mode = (ndim == 3 ? rotate_zoom : pan_zoom); + uimenu->add_to_menu (fp); + if (uimenu->items_to_show ()) + show_menubar (); + else + hide_menubar (); } ~plot_window (void) { canvas->hide (); status->hide (); + uimenu->hide (); this->hide (); delete canvas; delete status; + delete uimenu; } // FIXME -- this could change. @@ -348,6 +756,99 @@ Fl::wait (fltk_maxtime); } + void show_menubar (void) + { + int dm = menu_h; + if (uimenu->is_visible ()) + dm = 0; + canvas->resize (canvas->x (), + canvas->y () + dm, + canvas->w (), + canvas->h () - dm); + uimenu->show (); + mark_modified (); + } + + void hide_menubar (void) + { + int dm = menu_h; + if (!uimenu->is_visible ()) + dm = 0; + canvas->resize (canvas->x (), + canvas->y () - dm, + canvas->w (), + canvas->h () + dm); + uimenu->hide (); + mark_modified (); + } + + void uimenu_update(graphics_handle gh, int id) + { + graphics_object uimenu_obj = gh_manager::get_object (gh); + + if (uimenu_obj.valid_object () && uimenu_obj.isa ("uimenu")) + { + uimenu::properties& uimenup = + dynamic_cast (uimenu_obj.get_properties ()); + std::string fltk_label = uimenup.get_fltk_label(); + graphics_object fig = xget_ancestor(uimenu_obj,"figure"); + figure::properties& figp = + dynamic_cast (fig.get_properties ()); + + switch(id) + { + case base_properties::BEINGDELETED: + uimenu->remove_from_menu (uimenup); + break; + case base_properties::VISIBLE: + uimenu->update_visible (uimenup); + break; + case uimenu::properties::ACCELERATOR: + uimenu->update_accelerator (uimenup); + break; + case uimenu::properties::CALLBACK: + uimenu->update_callback (uimenup); + break; + case uimenu::properties::CHECKED: + uimenu->add_to_menu (figp);//rebuilding entire menu + break; + case uimenu::properties::ENABLE: + uimenu->update_enable (uimenup); + break; + case uimenu::properties::FOREGROUNDCOLOR: + uimenu->update_foregroundcolor (uimenup); + break; + case uimenu::properties::LABEL: + uimenu->add_to_menu (figp);//rebuilding entire menu + break; + case uimenu::properties::POSITION: + uimenu->add_to_menu (figp);//rebuilding entire menu + break; + case uimenu::properties::SEPARATOR: + uimenu->update_seperator (uimenup); + break; + } + + if (uimenu->items_to_show ()) + show_menubar (); + else + hide_menubar (); + + mark_modified(); + } + } + + void show_canvas (void) + { + canvas->show (); + canvas->make_current (); + } + + void hide_canvas (void) + { + canvas->hide (); + } + void mark_modified (void) { damage (FL_DAMAGE_ALL); @@ -382,13 +883,16 @@ // Interactive Mode enum { pan_zoom, rotate_zoom } gui_mode; - + // Figure properties. figure::properties& fp; // Status area height. static const int status_h = 20; + // Menu height + static const int menu_h = 20; + // Window callback. static void window_close (Fl_Widget*, void* data) { @@ -400,10 +904,10 @@ // Button callbacks. static void button_callback (Fl_Widget* ww, void* data) { - static_cast (data)->button_press (ww); + static_cast (data)->button_press (ww, data); } - void button_press (Fl_Widget* widg) + void button_press (Fl_Widget* widg, void*) { if (widg == autoscale) axis_auto (); @@ -421,6 +925,7 @@ fl_message ("%s", help_text); } + fltk_uimenu* uimenu; OpenGL_fltk* canvas; Fl_Box* bottom; Fl_Button* autoscale; @@ -442,7 +947,9 @@ void toggle_grid (void) { octave_value_list args; - args(0) = fp.get_currentaxes ().as_octave_value (); + if (fp.get_currentaxes ().ok ()) + args(0) = fp.get_currentaxes ().as_octave_value (); + feval ("grid", args); mark_modified (); } @@ -539,15 +1046,18 @@ void set_currentpoint (int px, int py) { - Matrix pos (1,2,0); - pos(0) = px; - pos(1) = h () - status_h - py; - fp.set_currentpoint (pos); + if (!fp.is_beingdeleted ()) + { + Matrix pos (1,2,0); + pos(0) = px; + pos(1) = h () - status_h - menu_h - py; + fp.set_currentpoint (pos); + } } void set_axes_currentpoint (graphics_object ax, int px, int py) { - if (ax) + if (ax.valid_object ()) { axes::properties& ap = dynamic_cast (ax.get_properties ()); @@ -615,7 +1125,7 @@ pos(0) = xx; pos(1) = yy; pos(2) = ww; - pos(3) = hh - status_h; + pos(3) = hh - status_h - menu_h; fp.set_position (pos); } @@ -623,7 +1133,7 @@ void draw (void) { Matrix pos = fp.get_position ().matrix_value (); - Fl_Window::resize (pos(0), pos(1) , pos(2), pos(3) + status_h); + Fl_Window::resize (pos(0), pos(1) , pos(2), pos(3) + status_h + menu_h); return Fl_Window::draw (); } @@ -633,233 +1143,243 @@ static int px0,py0; static graphics_object ax0; + graphics_handle gh; + + graphics_object fig = gh_manager::get_object (fp.get___myhandle__ ()); int retval = Fl_Window::handle (event); // We only handle events which are in the canvas area. - if (Fl::event_y () >= h() - status_h) + if (!Fl::event_inside(canvas)) return retval; - switch (event) + if (!fp.is_beingdeleted ()) { - case FL_KEYDOWN: - { - int key = Fl::event_key (); + switch (event) + { + case FL_KEYDOWN: + { + int key = Fl::event_key (); - shift |= key2shift (key); - int key_a = key2ascii (key); - if (key_a && fp.get_keypressfcn ().is_defined ()) - { - octave_scalar_map evt; - evt.assign ("Character", key_a); - evt.assign ("Key", std::tolower (key_a)); - evt.assign ("Modifier", modifier2cell ()); - fp.execute_keypressfcn (evt); + shift |= key2shift (key); + int key_a = key2ascii (key); + if (key_a && fp.get_keypressfcn ().is_defined ()) + { + Octave_map evt; + evt.assign ("Character", octave_value (key_a)); + evt.assign ("Key", octave_value (std::tolower (key_a))); + evt.assign ("Modifier", octave_value (modifier2cell ())); + fp.execute_keypressfcn (evt); + } + switch (key) + { + case 'a': + case 'A': + axis_auto (); + break; + + case 'g': + case 'G': + toggle_grid (); + break; + + case 'p': + case 'P': + gui_mode = pan_zoom; + break; + + case 'r': + case 'R': + gui_mode = rotate_zoom; + break; + } } - switch (key) - { - case 'a': - case 'A': - axis_auto (); break; - case 'g': - case 'G': - toggle_grid (); + case FL_KEYUP: + { + int key = Fl::event_key (); + + shift &= (~key2shift (key)); + int key_a = key2ascii (key); + if (key_a && fp.get_keyreleasefcn ().is_defined ()) + { + Octave_map evt; + evt.assign ("Character", octave_value (key_a)); + evt.assign ("Key", octave_value (std::tolower (key_a))); + evt.assign ("Modifier", octave_value (modifier2cell ())); + fp.execute_keyreleasefcn (evt); + } + } break; - case 'p': - case 'P': - gui_mode = pan_zoom; + case FL_MOVE: + pixel2status (pixel2axes_or_ca (Fl::event_x (), Fl::event_y ()), + Fl::event_x (), Fl::event_y ()); break; - case 'r': - case 'R': - if (ndim == 3) - gui_mode = rotate_zoom; - else - gui_mode = pan_zoom; + case FL_PUSH: + px0 = Fl::event_x (); + py0 = Fl::event_y (); + + set_currentpoint (Fl::event_x (), Fl::event_y ()); + + gh = pixel2axes_or_ca (px0, py0); + + if (gh.ok ()) + { + ax0 = gh_manager::get_object (gh); + set_axes_currentpoint (ax0, px0, py0); + } + + fp.execute_windowbuttondownfcn (); + + if (Fl::event_button () == 1 || Fl::event_button () == 3) + return 1; + break; - } - } - break; - case FL_KEYUP: - { - int key = Fl::event_key (); - - shift &= (~key2shift (key)); - int key_a = key2ascii (key); - if (key_a && fp.get_keyreleasefcn ().is_defined ()) - { - octave_scalar_map evt; - evt.assign ("Character", key_a); - evt.assign ("Key", std::tolower (key_a)); - evt.assign ("Modifier", modifier2cell ()); - fp.execute_keyreleasefcn (evt); - } - } - break; - - case FL_MOVE: - pixel2status (pixel2axes_or_ca (Fl::event_x (), Fl::event_y ()), - Fl::event_x (), Fl::event_y ()); - break; - - case FL_PUSH: - px0 = Fl::event_x (); - py0 = Fl::event_y (); - ax0 = gh_manager::get_object (pixel2axes_or_ca (px0, py0)); - - set_currentpoint (Fl::event_x (), Fl::event_y ()); - set_axes_currentpoint (ax0, px0, py0); - fp.execute_windowbuttondownfcn (); - - - if (Fl::event_button () == 1 || Fl::event_button () == 3) - return 1; - break; - - case FL_DRAG: - if (fp.get_windowbuttonmotionfcn ().is_defined ()) - { - set_currentpoint (Fl::event_x (), Fl::event_y ()); - fp.execute_windowbuttonmotionfcn (); - } - - if (Fl::event_button () == 1) - { - if (ax0 && ax0.isa ("axes")) + case FL_DRAG: + if (fp.get_windowbuttonmotionfcn ().is_defined ()) { - if (gui_mode == pan_zoom) - pixel2status (ax0, px0, py0, Fl::event_x (), Fl::event_y ()); - else - view2status (ax0); - axes::properties& ap = - dynamic_cast (ax0.get_properties ()); - - double x0, y0, x1, y1; - Matrix pos = fp.get_position ().matrix_value (); - pixel2pos (ax0, px0, py0, x0, y0); - pixel2pos (ax0, Fl::event_x (), Fl::event_y (), x1, y1); - - if (gui_mode == pan_zoom) - ap.translate_view (x0 - x1, y0 - y1); - else if (gui_mode == rotate_zoom) - { - double daz, del; - daz = (Fl::event_x () - px0) / pos(2) * 360; - del = (Fl::event_y () - py0) / pos(3) * 360; - ap.rotate_view (del, daz); - } - - px0 = Fl::event_x (); - py0 = Fl::event_y (); - mark_modified (); + set_currentpoint (Fl::event_x (), Fl::event_y ()); + fp.execute_windowbuttonmotionfcn (); } - return 1; - } - else if (Fl::event_button () == 3) - { - pixel2status (ax0, px0, py0, Fl::event_x (), Fl::event_y ()); - Matrix zoom_box (1,4,0); - zoom_box (0) = px0; - zoom_box (1) = py0; - zoom_box (2) = Fl::event_x (); - zoom_box (3) = Fl::event_y (); - canvas->set_zoom_box (zoom_box); - canvas->zoom (true); - canvas->redraw (); - } - - break; - - case FL_MOUSEWHEEL: - { - graphics_object ax = - gh_manager::get_object (pixel2axes_or_ca (Fl::event_x (), - Fl::event_y ())); - if (ax && ax.isa ("axes")) - { - axes::properties& ap = - dynamic_cast (ax.get_properties ()); - - // Determine if we're zooming in or out. - const double factor = - (Fl::event_dy () > 0) ? 1.0 + wheel_zoom_speed : 1.0 - wheel_zoom_speed; - - // Get the point we're zooming about. - double x1, y1; - pixel2pos (ax, Fl::event_x (), Fl::event_y (), x1, y1); - - ap.zoom_about_point (x1, y1, factor, false); - mark_modified (); - } - } - return 1; - - case FL_RELEASE: - if (fp.get_windowbuttonupfcn ().is_defined ()) - { - set_currentpoint (Fl::event_x (), Fl::event_y ()); - fp.execute_windowbuttonupfcn (); - } - - if (Fl::event_button () == 1) - { - if ( Fl::event_clicks () == 1) + + if (Fl::event_button () == 1) { if (ax0 && ax0.isa ("axes")) { - axes::properties& ap = + if (gui_mode == pan_zoom) + pixel2status (ax0, px0, py0, Fl::event_x (), Fl::event_y ()); + else + view2status (ax0); + axes::properties& ap = dynamic_cast (ax0.get_properties ()); - ap.set_xlimmode("auto"); - ap.set_ylimmode("auto"); - ap.set_zlimmode("auto"); + + double x0, y0, x1, y1; + Matrix pos = fp.get_position ().matrix_value (); + pixel2pos (ax0, px0, py0, x0, y0); + pixel2pos (ax0, Fl::event_x (), Fl::event_y (), x1, y1); + + if (gui_mode == pan_zoom) + ap.translate_view (x0 - x1, y0 - y1); + else if (gui_mode == rotate_zoom) + { + double daz, del; + daz = (Fl::event_x () - px0) / pos(2) * 360; + del = (Fl::event_y () - py0) / pos(3) * 360; + ap.rotate_view (del, daz); + } + + px0 = Fl::event_x (); + py0 = Fl::event_y (); mark_modified (); } + return 1; } - } - if (Fl::event_button () == 3) - { - // End of drag -- zoom. - if (canvas->zoom ()) + else if (Fl::event_button () == 3) { - canvas->zoom (false); - double x0,y0,x1,y1; - if (ax0 && ax0.isa ("axes")) + pixel2status (ax0, px0, py0, Fl::event_x (), Fl::event_y ()); + Matrix zoom_box (1,4,0); + zoom_box (0) = px0; + zoom_box (1) = py0; + zoom_box (2) = Fl::event_x (); + zoom_box (3) = Fl::event_y (); + canvas->set_zoom_box (zoom_box); + canvas->zoom (true); + canvas->redraw (); + } + + break; + + case FL_MOUSEWHEEL: + { + graphics_object ax = + gh_manager::get_object (pixel2axes_or_ca (Fl::event_x (), + Fl::event_y ())); + if (ax && ax.isa ("axes")) + { + axes::properties& ap = + dynamic_cast (ax.get_properties ()); + + // Determine if we're zooming in or out. + const double factor = + (Fl::event_dy () > 0) ? 1.0 + wheel_zoom_speed : 1.0 - wheel_zoom_speed; + + // Get the point we're zooming about. + double x1, y1; + pixel2pos (ax, Fl::event_x (), Fl::event_y (), x1, y1); + + ap.zoom_about_point (x1, y1, factor, false); + mark_modified (); + } + } + return 1; + + case FL_RELEASE: + if (fp.get_windowbuttonupfcn ().is_defined ()) + { + set_currentpoint (Fl::event_x (), Fl::event_y ()); + fp.execute_windowbuttonupfcn (); + } + + if (Fl::event_button () == 1) + { + if ( Fl::event_clicks () == 1) { - axes::properties& ap = - dynamic_cast (ax0.get_properties ()); - pixel2pos (ax0, px0, py0, x0, y0); - pixel2pos (ax0, Fl::event_x (), Fl::event_y (), x1, y1); - Matrix xl (1,2,0); - Matrix yl (1,2,0); - if (x0 < x1) + if (ax0 && ax0.isa ("axes")) { - xl(0) = x0; - xl(1) = x1; + axes::properties& ap = + dynamic_cast (ax0.get_properties ()); + ap.set_xlimmode("auto"); + ap.set_ylimmode("auto"); + ap.set_zlimmode("auto"); + mark_modified (); } - else - { - xl(0) = x1; - xl(1) = x0; - } - if (y0 < y1) - { - yl(0) = y0; - yl(1) = y1; - } - else - { - yl(0) = y1; - yl(1) = y0; - } - ap.zoom (xl, yl); - mark_modified (); } } + if (Fl::event_button () == 3) + { + // End of drag -- zoom. + if (canvas->zoom ()) + { + canvas->zoom (false); + double x0,y0,x1,y1; + if (ax0 && ax0.isa ("axes")) + { + axes::properties& ap = + dynamic_cast (ax0.get_properties ()); + pixel2pos (ax0, px0, py0, x0, y0); + pixel2pos (ax0, Fl::event_x (), Fl::event_y (), x1, y1); + Matrix xl (1,2,0); + Matrix yl (1,2,0); + if (x0 < x1) + { + xl(0) = x0; + xl(1) = x1; + } + else + { + xl(0) = x1; + xl(1) = x0; + } + if (y0 < y1) + { + yl(0) = y0; + yl(1) = y1; + } + else + { + yl(0) = y1; + yl(1) = y0; + } + ap.zoom (xl, yl); + mark_modified (); + } + } + } + break; } - break; } return retval; @@ -963,7 +1483,30 @@ if (instance_ok ()) instance->do_print (hnd2idx(gh), fid, term); } + + static void uimenu_update (const graphics_handle& figh, const graphics_handle& uimenuh, const int id) + { + if (instance_ok ()) + instance->do_uimenu_update (hnd2idx(figh), uimenuh, id); + } + + static void update_canvas (const graphics_handle& gh, const graphics_handle& ca) + { + if (instance_ok ()) + instance->do_update_canvas (hnd2idx(gh), ca); + } + + static void toggle_menubar_visibility (int fig_idx, bool menubar_is_figure) + { + if (instance_ok ()) + instance->do_toggle_menubar_visibility (fig_idx, menubar_is_figure); + } + static void toggle_menubar_visibility (std::string fig_idx_str, bool menubar_is_figure) + { + toggle_menubar_visibility (str2idx (fig_idx_str), menubar_is_figure); + } + private: static figure_manager *instance; @@ -1028,6 +1571,20 @@ } } + void do_toggle_menubar_visibility (int fig_idx, bool menubar_is_figure) + { + wm_iterator win; + if ((win = windows.find (fig_idx)) != windows.end ()) + { + if (menubar_is_figure) + win->second->show_menubar (); + else + win->second->hide_menubar (); + + win->second->redraw (); + } + } + void do_mark_modified (int idx) { wm_iterator win; @@ -1069,6 +1626,28 @@ } } + void do_uimenu_update (int idx, graphics_handle gh, int id) + { + wm_iterator win; + if ((win = windows.find (idx)) != windows.end ()) + { + win->second->uimenu_update (gh, id); + } + } + + void do_update_canvas (int idx, graphics_handle ca) + { + wm_iterator win; + if ((win = windows.find (idx)) != windows.end ()) + { + if (ca.ok ()) + win->second->show_canvas (); + else + win->second->hide_canvas (); + } + } + + // FIXME -- default size should be configurable. void default_size (int& x, int& y, int& w, int& h) { @@ -1192,6 +1771,27 @@ } } + void uimenu_set_fltk_label(graphics_object uimenu_obj) + { + if (uimenu_obj.valid_object ()) + { + uimenu::properties& uimenup = + dynamic_cast (uimenu_obj.get_properties ()); + std::string fltk_label = uimenup.get_label (); + graphics_object go = gh_manager::get_object (uimenu_obj.get_parent ()); + if (go.isa ("uimenu")) + fltk_label = dynamic_cast (go.get_properties ()).get_fltk_label () + + "/" + + fltk_label; + else if (go.isa ("figure")) + ; + else + error("unexpected parent object\n"); + + uimenup.set_fltk_label(fltk_label); + } + } + void update (const graphics_object& go, int id) { if (go.isa ("figure")) @@ -1205,17 +1805,30 @@ switch (id) { - case base_properties::VISIBLE: - figure_manager::toggle_window_visibility (ov.string_value (), fp.is_visible ()); - break; - - case figure::properties::NAME: - case figure::properties::NUMBERTITLE: - figure_manager::set_name (ov.string_value ()); - break; + case base_properties::VISIBLE: + figure_manager::toggle_window_visibility (ov.string_value (), fp.is_visible ()); + break; + case figure::properties::MENUBAR: + figure_manager::toggle_menubar_visibility (ov.string_value (), fp.menubar_is("figure")); + break; + case figure::properties::NAME: + case figure::properties::CURRENTAXES: + figure_manager::update_canvas (go.get_handle (), fp.get_currentaxes ()); + break; + case figure::properties::NUMBERTITLE: + figure_manager::set_name (ov.string_value ()); + break; } } } + else if (go.isa ("uimenu")) + { + if (id == uimenu::properties::LABEL) + uimenu_set_fltk_label (go); + + graphics_object fig = xget_ancestor(go,"figure"); + figure_manager::uimenu_update(fig.get_handle (), go.get_handle (), id); + } } void redraw_figure (const graphics_object& go) const diff -r 304b0ed4ca56 -r f6c09b3fbcab src/gl-render.cc --- a/src/gl-render.cc Thu Oct 21 00:44:32 2010 -0400 +++ b/src/gl-render.cc Thu Oct 21 16:23:34 2010 +0200 @@ -554,6 +554,8 @@ draw_text (dynamic_cast (props)); else if (go.isa ("image")) draw_image (dynamic_cast (props)); + else if (go.isa ("uimenu")) + ; else warning ("opengl_renderer: cannot render object of type `%s'", props.graphics_object_name ().c_str ()); @@ -1658,6 +1660,7 @@ if (! go.isa ("text") || go.get ("units").string_value () == "data") { set_clipping (go.get_properties ().is_clipping ()); + printf("2. pass type: %s\n",go.get_properties ().get_type ().c_str ()); draw (go); it = obj_list.erase (it); @@ -1674,6 +1677,7 @@ graphics_object go = (*it); set_clipping (go.get_properties ().is_clipping ()); + printf("3rd pass: type: %s\n",go.get_properties ().get_type ().c_str ()); draw (go); } glEnable (GL_DEPTH_TEST); @@ -3025,6 +3029,7 @@ opengl_renderer::draw_marker (double x, double y, double z, const Matrix& lc, const Matrix& fc) { + printf("draw marker\n"); ColumnVector tmp = xform.transform (x, y, z, false); glLoadIdentity (); diff -r 304b0ed4ca56 -r f6c09b3fbcab src/graphics.cc --- a/src/graphics.cc Thu Oct 21 00:44:32 2010 -0400 +++ b/src/graphics.cc Thu Oct 21 16:23:34 2010 +0200 @@ -55,7 +55,7 @@ // forward declarations static octave_value xget (const graphics_handle& h, const caseless_str& name); -static graphics_object xget_ancestor (const graphics_object& go_arg, +graphics_object xget_ancestor (const graphics_object& go_arg, const std::string& type); static void @@ -541,7 +541,7 @@ return convert_position (sz, obj.get ("units").string_value (), "pixels", sz.extract_n (0, 2, 1, 2)).extract_n (0, 2, 1, 2); } -static graphics_object +graphics_object xget_ancestor (const graphics_object& go_arg, const std::string& type) { graphics_object go = go_arg; @@ -727,7 +727,7 @@ { pfx = name.substr (0, 6); - if (pfx.compare ("figure")) + if (pfx.compare ("figure") || pfx.compare ("uimenu")) offset = 6; else if (len >= 7) { @@ -773,7 +773,8 @@ go = new surface (h, p); else if (type.compare ("hggroup")) go = new hggroup (h, p); - + else if (type.compare ("uimenu")) + go = new uimenu (h, p); return go; } @@ -1416,7 +1417,7 @@ { pfx = name.substr (0, 6); - if (pfx.compare ("figure")) + if (pfx.compare ("figure") || pfx.compare ("uimenu")) offset = 6; else if (len > 7) { @@ -1454,6 +1455,8 @@ has_property = surface::properties::has_core_property (pname); else if (pfx == "hggroup") has_property = hggroup::properties::has_core_property (pname); + else if (pfx == "uimenu") + has_property = uimenu::properties::has_core_property (pname); if (has_property) { @@ -1512,7 +1515,7 @@ { pfx = name.substr (0, 6); - if (pfx.compare ("figure")) + if (pfx.compare ("figure") || pfx.compare ("uimenu")) offset = 6; else if (len > 7) { @@ -5456,6 +5459,7 @@ plist_map["patch"] = patch::properties::factory_defaults (); plist_map["surface"] = surface::properties::factory_defaults (); plist_map["hggroup"] = hggroup::properties::factory_defaults (); + plist_map["uimenu"] = uimenu::properties::factory_defaults (); return plist_map; } @@ -6027,6 +6031,15 @@ GO_BODY (hggroup); } +DEFUN (__go_uimenu__, args, , + "-*- texinfo -*-\n\ address@hidden {Built-in Function} {} __go_uimenu__ (@var{parent})\n\ +Undocumented internal function.\n\ address@hidden deftypefn") +{ + GO_BODY (uimenu); +} + DEFUN (__go_delete__, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} __go_delete__ (@var{h})\n\ diff -r 304b0ed4ca56 -r f6c09b3fbcab src/graphics.h.in --- a/src/graphics.h.in Thu Oct 21 00:44:32 2010 -0400 +++ b/src/graphics.h.in Thu Oct 21 16:23:34 2010 +0200 @@ -3855,6 +3855,64 @@ // --------------------------------------------------------------------- +class OCTINTERP_API uimenu : public base_graphics_object +{ +public: + class OCTINTERP_API properties : public base_properties + { + public: + void remove_child (const graphics_handle& h) + { + base_properties::remove_child (h); + } + + void adopt (const graphics_handle& h) + { + base_properties::adopt (h); + } + + // See the genprops.awk script for an explanation of the + // properties declarations. + + BEGIN_PROPERTIES (uimenu) + string_property accelerator , "" + callback_property callback , Matrix() + bool_property checked , "off" + bool_property enable , "on" + color_property foregroundcolor , color_values (0, 0, 0) + string_property label , "" + double_property position , 9 + bool_property separator , "off" + string_property fltk_label h , "" + END_PROPERTIES + + protected: + void init (void) + { } + }; + +private: + properties xproperties; + +public: + uimenu (const graphics_handle& mh, const graphics_handle& p) + : base_graphics_object (), xproperties (mh, p) + { + xproperties.override_defaults (*this); + } + + ~uimenu (void) { xproperties.delete_children (); } + + base_properties& get_properties (void) { return xproperties; } + + const base_properties& get_properties (void) const { return xproperties; } + + bool valid_object (void) const { return true; } + +}; + +// --------------------------------------------------------------------- + octave_value get_property_from_handle (double handle, const std::string &property, const std::string &func);