changeset 20074:6ba3d0f7c6e8

improve mouse zooming for Qt plotting (bug #44302) * Figure.h (enum MouseMode): Split ZoomMode into ZoomInMode and ZoomOutMode. Change all uses. * Canvas.cc (Canvas::canvasMouseReleaseEvent, Canvas::canvasWheelEvent): Make meaning of zoom factor consistent with zoom function. Make direction of wheel event consistent with other programs. * __init_fltk__.cc (plot_window::handle): Make meaning of zoom factor consistent with zoom function. * MouseModeActionGroup.cc (MouseModeActionGroup::MouseModeActionGroup): Provide buttons for zooming in and out. * graphics.cc (figure::properties::set_toolkit): Handle zoom direction. (do_zoom): Make factor > 1 zoom in.
author John W. Eaton <jwe@octave.org>
date Thu, 26 Feb 2015 19:24:59 -0500
parents 726df008104d
children c7c50030e76c
files libgui/graphics/Canvas.cc libgui/graphics/Figure.cc libgui/graphics/Figure.h libgui/graphics/MouseModeActionGroup.cc libinterp/corefcn/graphics.cc libinterp/dldfcn/__init_fltk__.cc
diffstat 6 files changed, 112 insertions(+), 55 deletions(-) [+]
line wrap: on
line diff
--- a/libgui/graphics/Canvas.cc
+++ b/libgui/graphics/Canvas.cc
@@ -71,7 +71,8 @@
           w->setCursor (Qt::OpenHandCursor);
           break;
 
-        case ZoomMode:
+        case ZoomInMode:
+        case ZoomOutMode:
           // FIXME: distinguish zoom in/out.
           w->setCursor (QBitmap (":/images/zoom.png"));
           break;
@@ -206,7 +207,7 @@
 
       draw (m_handle);
 
-      if (m_mouseMode == ZoomMode && m_mouseAxes.ok ())
+      if (m_mouseMode == ZoomInMode && m_mouseAxes.ok ())
         drawZoomBox (m_mouseAnchor, m_mouseCurrent);
     }
 }
@@ -235,7 +236,8 @@
           }
           break;
 
-        case ZoomMode:
+        case ZoomInMode:
+        case ZoomOutMode:
           m_mouseCurrent = event->pos ();
           redraw (true);
           break;
@@ -546,7 +548,8 @@
 
         case PanMode:
         case RotateMode:
-        case ZoomMode:
+        case ZoomInMode:
+        case ZoomOutMode:
           if (axesObj)
             {
               bool redraw_figure = true;
@@ -609,7 +612,8 @@
 
 void Canvas::canvasMouseReleaseEvent (QMouseEvent* event)
 {
-  if (m_mouseMode == ZoomMode && m_mouseAxes.ok ())
+  if ((m_mouseMode == ZoomInMode || m_mouseMode == ZoomOutMode)
+      && m_mouseAxes.ok ())
     {
       gh_manager::auto_lock lock;
       graphics_object ax = gh_manager::get_object (m_mouseAxes);
@@ -626,9 +630,7 @@
 
           if (m_mouseAnchor == event->pos ())
             {
-              // FIXME: check direction here.
-
-              double factor = 2.0;
+              double factor = m_mouseMode == ZoomInMode ? 2.0 : 0.5;
 
               ap.zoom (zm, factor);
             }
@@ -720,7 +722,10 @@
 
               if (zoom_enabled (figObj))
                 {
-                  newMouseMode = ZoomMode;
+                  if (event->delta () > 0)
+                    newMouseMode = ZoomInMode;
+                  else
+                    newMouseMode = ZoomOutMode;
 
                   mode = zoom_mode (figObj);
                 }
@@ -736,7 +741,8 @@
 
           switch (newMouseMode)
             {
-            case ZoomMode:
+            case ZoomInMode:
+            case ZoomOutMode:
               {
                 axes::properties& ap = Utils::properties<axes> (axesObj);
 
@@ -744,21 +750,13 @@
                 double wheel_zoom_speed = ap.get_mousewheelzoom ();
 
                 // Determine if we're zooming in or out.
-                double factor = (event->delta () > 0
+                double factor = (newMouseMode == ZoomInMode
                                  ? 1 / (1.0 - wheel_zoom_speed)
                                  : 1.0 - wheel_zoom_speed);
 
-                ap.zoom (mode, factor);
+                // FIXME: should we zoom about point for 2D plots?
 
-#if 0
-                Matrix view = ap.get_view ().matrix_value ();
-                if (view(1) != 90)
-                  {
-                    Matrix zlimits = ap.get_zlim ().matrix_value ();
-                    zlimits = factor * zlimits;
-                    ap.set_zlim (zlimits);
-                  }
-#endif
+                ap.zoom (mode, factor);
               }
               break;
 
--- a/libgui/graphics/Figure.cc
+++ b/libgui/graphics/Figure.cc
@@ -179,8 +179,11 @@
     case RotateMode:
       return "rotate";
 
-    case ZoomMode:
-      return "zoom";
+    case ZoomInMode:
+      return "zoom in";
+
+    case ZoomOutMode:
+      return "zoom out";
 
     case PanMode:
       return "pan";
@@ -204,8 +207,10 @@
     return NoMode;
   else if (mode == "rotate")
     return RotateMode;
-  else if (mode == "zoom")
-    return ZoomMode;
+  else if (mode == "zoom in")
+    return ZoomInMode;
+  else if (mode == "zoom out")
+    return ZoomOutMode;
   else if (mode == "pan")
     return PanMode;
   else if (mode == "text")
@@ -244,6 +249,15 @@
 
   std::string mode = fp.get___mouse_mode__ ();
 
+  if (mode == "zoom")
+    {
+      octave_scalar_map zm = fp.get___zoom_mode__ ().scalar_map_value ();
+
+      std::string direction = zm.getfield ("Direction").string_value ();
+
+      mode += " " + direction;
+    }    
+
   return mouse_mode_from_string (mode);
 }
 
--- a/libgui/graphics/Figure.h
+++ b/libgui/graphics/Figure.h
@@ -42,10 +42,11 @@
 
   NoMode        = 0,
   RotateMode    = 1,
-  ZoomMode      = 2,
-  PanMode       = 3,
-  TextMode      = 4,
-  SelectMode    = 5
+  ZoomInMode    = 2,
+  ZoomOutMode   = 3,
+  PanMode       = 4,
+  TextMode      = 5,
+  SelectMode    = 6
 };
 
 class Container;
--- a/libgui/graphics/MouseModeActionGroup.cc
+++ b/libgui/graphics/MouseModeActionGroup.cc
@@ -38,8 +38,14 @@
 {
   m_actions.append (new QAction (QIcon (":/images/rotate.png"),
                                  tr ("Rotate"), this));
-  m_actions.append (new QAction (QIcon (":/images/zoom.png"),
-                                 tr ("Zoom"), this));
+  QAction *zoom_in = new QAction ("Z+", this);
+  zoom_in->setToolTip (tr ("Zoom In")); 
+  m_actions.append (zoom_in);
+
+  QAction *zoom_out = new QAction ("Z-", this);
+  zoom_out->setToolTip (tr ("Zoom Out")); 
+  m_actions.append (zoom_out);
+
   m_actions.append (new QAction (QIcon (":/images/pan.png"),
                                  tr ("Pan"), this));
   m_actions.append (new QAction (QIcon::fromTheme ("insert-text"),
@@ -47,8 +53,8 @@
   m_actions.append (new QAction (QIcon (":/images/select.png"),
                                  tr ("Select"), this));
 
-  m_actions[3]->setEnabled (false);
   m_actions[4]->setEnabled (false);
+  m_actions[5]->setEnabled (false);
 
   foreach (QAction* a, m_actions)
     {
--- a/libinterp/corefcn/graphics.cc
+++ b/libinterp/corefcn/graphics.cc
@@ -1810,27 +1810,62 @@
 }
 
 void
-figure::properties::set___mouse_mode__ (const octave_value& val)
+figure::properties::set___mouse_mode__ (const octave_value& val_arg)
 {
   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 ();
+      std::string direction = "in";
+
+      octave_value val = val_arg;
+
+      if (val.is_string ())
+        {
+          std::string modestr = val.string_value ();
+
+          if (modestr == "zoom in")
+            {
+              val = modestr = "zoom";
+              direction = "in";
+            }
+          else if (modestr == "zoom out")
+            {
+              val = modestr = "zoom";
+              direction = "out";
+            }
+
+          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");
+              zm.setfield ("Direction", direction);
+              set___zoom_mode__ (zm);
+
+              mark_modified ();
+            }
+          else if (modestr == "zoom")
+            {
+              octave_scalar_map zm = get___zoom_mode__ ().scalar_map_value ();
+              std::string curr_direction
+                = zm.getfield ("Direction").string_value ();
+
+              if (direction != curr_direction)
+                {
+                  zm.setfield ("Direction", direction);
+                  set___zoom_mode__ (zm);
+
+                  mark_modified ();
+                }
+            }
         }
     }
 }
@@ -7572,8 +7607,8 @@
     }
 
   // Perform the zooming
-  lo = val + factor * (lo - val);
-  hi = val + factor * (hi - val);
+  lo = val + (lo - val) / factor;
+  hi = val + (hi - val) / factor;
 
   if (is_logscale)
     {
--- a/libinterp/dldfcn/__init_fltk__.cc
+++ b/libinterp/dldfcn/__init_fltk__.cc
@@ -1588,15 +1588,18 @@
                     double wheel_zoom_speed = ap.get_mousewheelzoom ();
 
                     // Determine if we're zooming in or out.
-                    const double factor =
-                      (Fl::event_dy () > 0) ? 1 / (1.0 - wheel_zoom_speed)
-                      : 1.0 - wheel_zoom_speed;
+                    const double factor = (Fl::event_dy () < 0
+                                           ? 1 / (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 () - menu_dy (),
                                x1, y1);
 
+                    // FIXME: should we only zoom about point for 2D plots?
+
                     ap.zoom_about_point ("both", x1, y1, factor, false);
                     mark_modified ();
                     return 1;