Mercurial > hg > octave-nkf
diff libinterp/corefcn/graphics.cc @ 19864:dfea01b3425f
more mouse interaction features for Qt plotting widget
* graphics.in.h, graphics.cc (figure::properties::__mouse_mode__,
figure::properties::__pan_mode__, figure::properties::__rotate_mode__,
figure::properties::__zoom_mode__): New properties.
(figure::properties::set___mouse_mode__): New function.
(axes::properties::pan, axes::properties::rotate3d,
axes::properties::zoom): New functions. Handle zoom, and pan modes.
(axes::properties::clear_zoom_stack): New arg, do_unzoom.
Conditionally call unzoom.
(axes::properties::unzoom): Also restore view property.
(axes::properties::rotate_view): Conditionall save state to zoom stack.
(axes::properties::push_zoom_stack): New function.
(axes::properties::pan, axes::properties::rotate3d):
Delete properties.
(axes::properties::update_xlim, axes::properties::update_ylim,
axes::properties::update_zlim): Don't clear zoom stack. Delete
do_clr_zoom argument.
(axes::properties::set_pan, axes::properties::set_rotate3d): Delete.
(F__zoom__): New function.
* Canvas.h, Canvas.cc (Canvas::toggleAxes, Canvas::toggleGrid):
New pure virtual functions.
(Canvas::setCursor, Canvas::canvasToggleAxes,
Canvas::canvasToggleGrid, Canvas::canvasMouseDoubleClickEvent,
Canvas::canvasWheelEvent): New functions.
(zoom_enabled, pan_enabled, pan_mode, rotate_enabled, rotate_mode):
New static functions.
(Canvas::canvasMouseMoveEvent): Call axes::properties::rotate3d to do
rotation. Handle panning.
(Canvas::canvasMousePressEvent): Also handle "unzoom" action when in
pan and rotate modes.
(Canvas::canvasMouseReleaseEvent): Zoom by factor if mouse has not
moved from mouse press event.
* Figure.h, Figure.cc (MouseMode): New enum value, TextMode.
(Figure::m_mouseMode, Figure::m_lastMouseMode): Delete member
variables.
(Figure::mouseMode, Figure::setMouseMode): Get info from and save info
to figure properties.
(Figure::updateFigureToolBarAndMenuBar, Figure::toggleAxes,
Figure::toggleGrid): New functions.
(Figure::m_mouseModeGroup): New member variable.
(Figure::createFigureToolBarAndMenuBar): Add actions for toggling Axes
and Grid. Maintain pointer to MouseModeActionGroup.
(mouse_mode_to_string, mouse_mode_from_string): New functions.
* GLCanvas.h, GLCanvas.cc (GLCanvas::toggleAxes, GLCanvas::ToggleGrid,
GLCanvas::mouseDoubleClickEvent, GLCanvas::wheelEvent): New functions.
* MouseModeActionGroup.h, MouseModeActionGroup.cc
(MouseModeActionGroup::mouseMode): Delete.
(MouseModeActionGroup::setMode): New function.
(MouseModeActionGroup::MouseModeActionGroup): Also include action to
insert text in the list.
* figure.m: Set default pan, rotate, and zoom mode properties for the
figure object.
* pan.m, rotate3d.m, zoom.m: Improve compatibility with Matlab. Set
mode properties for figure.
* __init_fltk__.cc: Cope with changes to graphics properties.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Fri, 06 Feb 2015 13:06:54 -0500 |
parents | a9516bc4c55c |
children | e7df12f37f71 |
line wrap: on
line diff
--- a/libinterp/corefcn/graphics.cc +++ b/libinterp/corefcn/graphics.cc @@ -1809,6 +1809,32 @@ mark_modified (); } +void +figure::properties::set___mouse_mode__ (const octave_value& val) +{ + if (! error_state) + { + if (__mouse_mode__.set (val, true)) + { + std::string mode = __mouse_mode__.current_value (); + + octave_scalar_map pm = get___pan_mode__ ().scalar_map_value (); + pm.setfield ("Enable", mode == "pan" ? "on" : "off"); + set___pan_mode__ (pm); + + octave_scalar_map rm = get___rotate_mode__ ().scalar_map_value (); + rm.setfield ("Enable", mode == "rotate" ? "on" : "off"); + set___rotate_mode__ (rm); + + octave_scalar_map zm = get___zoom_mode__ ().scalar_map_value (); + zm.setfield ("Enable", mode == "zoom" ? "on" : "off"); + set___zoom_mode__ (zm); + + mark_modified (); + } + } +} + // --------------------------------------------------------------------- void @@ -5041,8 +5067,6 @@ update_transform (); sync_positions (); override_defaults (obj); - // Disable rotate3d and select pan for 2D axes - set_rotate3d (get_rotate3d ()); } void @@ -6488,27 +6512,6 @@ } void -axes::properties::set_rotate3d (const octave_value& v) -{ - graphics_object parent_obj = - gh_manager::get_object (get_parent ()); - - int ndim = calc_dimensions (parent_obj); - rotate3d.set (v, false, false); - if (rotate3d_is ("on")) - { - // Disable rotate3d for 2D plots - if (ndim == 2) - { - rotate3d.set ("off", false, false); - pan.set ("on", false, false); - } - else - pan.set ("off", false, false); - } -} - -void axes::properties::set_units (const octave_value& v) { if (! error_state) @@ -7564,7 +7567,8 @@ } void -axes::properties::zoom_about_point (double x, double y, double factor, +axes::properties::zoom_about_point (const std::string& mode, + double x, double y, double factor, bool push_to_zoom_stack) { // FIXME: Do we need error checking here? @@ -7588,29 +7592,70 @@ xlims = do_zoom (x, factor, xlims, xscale_is ("log")); ylims = do_zoom (y, factor, ylims, yscale_is ("log")); - zoom (xlims, ylims, push_to_zoom_stack); -} - -void -axes::properties::zoom (const Matrix& xl, const Matrix& yl, + zoom (mode, xlims, ylims, push_to_zoom_stack); +} + +void +axes::properties::zoom (const std::string& mode, double factor, + bool push_to_zoom_stack) +{ + // FIXME: Do we need error checking here? + Matrix xlims = get_xlim ().matrix_value (); + Matrix ylims = get_ylim ().matrix_value (); + + double x = (xlims(0) + xlims(1)) / 2; + double y = (ylims(0) + ylims(1)) / 2; + + zoom_about_point (mode, x, y, factor, push_to_zoom_stack); +} + +void +axes::properties::push_zoom_stack (void) +{ + // FIXME: Maybe make the size of the undo stack configurable. A limit + // of 500 elements means 100 pan, rotate, or zoom actions are stored + // and may be undone. + + if (zoom_stack.size () >= 500) + { + for (int i = 0; i < 5; i++) + zoom_stack.pop_back (); + } + + zoom_stack.push_front (xlimmode.get ()); + zoom_stack.push_front (xlim.get ()); + zoom_stack.push_front (ylimmode.get ()); + zoom_stack.push_front (ylim.get ()); + zoom_stack.push_front (view.get ()); +} + +void +axes::properties::zoom (const std::string& mode, + const Matrix& xl, const Matrix& yl, bool push_to_zoom_stack) { if (push_to_zoom_stack) - { - zoom_stack.push_front (xlimmode.get ()); - zoom_stack.push_front (xlim.get ()); - zoom_stack.push_front (ylimmode.get ()); - zoom_stack.push_front (ylim.get ()); - } - - xlim = xl; - xlimmode = "manual"; - ylim = yl; - ylimmode = "manual"; + push_zoom_stack (); + + if (mode == "horizontal" || mode == "both") + { + xlim = xl; + xlimmode = "manual"; + } + + if (mode == "vertical" || mode == "both") + { + ylim = yl; + ylimmode = "manual"; + } update_transform (); - update_xlim (false); - update_ylim (false); + + if (mode == "horizontal" || mode == "both") + update_xlim (); + + if (mode == "vertical" || mode == "both") + update_ylim (); } static Matrix @@ -7674,7 +7719,9 @@ } void -axes::properties::translate_view (double x0, double x1, double y0, double y1) +axes::properties::translate_view (const std::string& mode, + double x0, double x1, double y0, double y1, + bool push_to_zoom_stack) { // FIXME: Do we need error checking here? Matrix xlims = get_xlim ().matrix_value (); @@ -7697,12 +7744,82 @@ xlims = do_translate (x0, x1, xlims, xscale_is ("log")); ylims = do_translate (y0, y1, ylims, yscale_is ("log")); - zoom (xlims, ylims, false); -} - -void -axes::properties::rotate_view (double delta_el, double delta_az) -{ + zoom (mode, xlims, ylims, push_to_zoom_stack); +} + +void +axes::properties::pan (const std::string& mode, double factor, + bool push_to_zoom_stack) +{ + // FIXME: Do we need error checking here? + Matrix xlims = get_xlim ().matrix_value (); + Matrix ylims = get_ylim ().matrix_value (); + + double x0 = (xlims(0) + xlims(1)) / 2; + double y0 = (ylims(0) + ylims(1)) / 2; + + double x1 = x0 + (xlims(1) - xlims(0)) * factor; + double y1 = y0 + (ylims(1) - ylims(0)) * factor; + + translate_view (mode, x0, x1, y0, y1, push_to_zoom_stack); +} + +void +axes::properties::rotate3d (double x0, double x1, double y0, double y1, + bool push_to_zoom_stack) +{ + if (push_to_zoom_stack) + push_zoom_stack (); + + Matrix bb = get_boundingbox (true); + Matrix new_view = get_view ().matrix_value (); + + // Compute new view angles + new_view(0) += ((x0 - x1) * (180.0 / bb(2))); + new_view(1) += ((y1 - y0) * (180.0 / bb(3))); + + // Clipping + new_view(1) = std::min (new_view(1), 90.0); + new_view(1) = std::max (new_view(1), -90.0); + if (new_view(0) > 180.0) + new_view(0) -= 360.0; + else if (new_view(0) < -180.0) + new_view(0) += 360.0; + + // Snapping + double snapMargin = 1.0; + for (int a = -90; a <= 90; a += 90) + { + if ((a - snapMargin) < new_view(1) + && new_view(1) < (a + snapMargin)) + { + new_view(1) = a; + break; + } + } + + for (int a = -180; a <= 180; a += 180) + if ((a - snapMargin) < new_view(0) + && new_view(0) < (a + snapMargin)) + { + if (a == 180) + new_view(0) = -180; + else + new_view(0) = a; + break; + } + + // Update axes properties + set_view (new_view); +} + +void +axes::properties::rotate_view (double delta_el, double delta_az, + bool push_to_zoom_stack) +{ + if (push_to_zoom_stack) + push_zoom_stack (); + Matrix v = get_view ().matrix_value (); v(1) += delta_el; @@ -7715,36 +7832,49 @@ v(0) = fmod (v(0) - delta_az + 720,360); set_view (v); + update_transform (); } void axes::properties::unzoom (void) { - if (zoom_stack.size () >= 4) - { + if (zoom_stack.size () >= 5) + { + view = zoom_stack.front (); + zoom_stack.pop_front (); + ylim = zoom_stack.front (); zoom_stack.pop_front (); + ylimmode = zoom_stack.front (); zoom_stack.pop_front (); + xlim = zoom_stack.front (); zoom_stack.pop_front (); + xlimmode = zoom_stack.front (); zoom_stack.pop_front (); update_transform (); - update_xlim (false); - update_ylim (false); - } -} - -void -axes::properties::clear_zoom_stack (void) -{ - while (zoom_stack.size () > 4) + + update_xlim (); + update_ylim (); + + update_view (); + } +} + +void +axes::properties::clear_zoom_stack (bool do_unzoom) +{ + size_t items_to_leave_on_stack = do_unzoom ? 5 : 0; + + while (zoom_stack.size () > items_to_leave_on_stack) zoom_stack.pop_front (); - unzoom (); + if (do_unzoom) + unzoom (); } void @@ -11658,3 +11788,74 @@ return octave_value (); } + +DEFUN (__zoom__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} __zoom__ (@var{axes}, @var{mode}, @var{factor})\n\ +@deftypefnx {Built-in Function} {} __zoom__ (@var{axes}, \"out\")\n\ +@deftypefnx {Built-in Function} {} __zoom__ (@var{axes}, \"reset\")\n\ +Undocumented internal function.\n\ +@end deftypefn") +{ + octave_value retval; + + int nargin = args.length (); + + if (nargin != 2 && nargin != 3) + { + print_usage (); + return retval; + } + + double h = args(0).double_value (); + + if (error_state) + return retval; + + gh_manager::auto_lock guard; + + graphics_handle handle = gh_manager::lookup (h); + + if (! handle.ok ()) + { + error ("__zoom__: invalid handle"); + return retval; + } + + graphics_object ax = gh_manager::get_object (handle); + + axes::properties& ax_props = + dynamic_cast<axes::properties&> (ax.get_properties ()); + + if (nargin == 2) + { + std::string opt = args(1).string_value (); + + if (error_state) + return retval; + + if (opt == "out" || opt == "reset") + { + if (opt == "out") + { + ax_props.clear_zoom_stack (); + Vdrawnow_requested = true; + } + else + ax_props.clear_zoom_stack (false); + + } + } + else + { + std::string mode = args(1).string_value (); + double factor = args(2).scalar_value (); + + if (error_state) + return retval; + + ax_props.zoom (mode, factor); + } + + return retval; +}