changeset 27099:2cd31365c84a

Implement "pointer" and related figure properties for Qt toolkit (bug #56347) * genpropdoc.m: Document "pointer", "pointershapecdata" and "pointershapehotspot" properties. * libgui/src/icons, libgui/src/module.mk, libgui/src/resource.qrc: Add new cursor png images extracted from the standard DMZ theme. Also add circle.png/svg designed to look like DMZ icons. * Canvas.[h, cc] (Canvas::setCursor): Change signature to include, pointer name, cdata and hotspot location. Use Qt standard QCursors for "arrow", "ibeam", and "watch" cursors. Use DMZ theme cursors for others. Build QCursor from Qimage for "custom" pointers. * Figure.[h,cc](m_pointer_cdata): New QImage data member. (pointer_to_qimage): New static function to convert from Matrix to QImage. (Figure::update): Call Canvas::setCursor whenever "pointer" or "pointershapehotspot" is updated. Refresh m_pointer_cdata when updating "pointershapecdata" and eventually call Canvas::setCursor. * graphics.in.h(figure::properties::pointershapecdata): Use 1 as default value for all pixels.
author Pantxo Diribarne <pantxo.diribarne@gmail.com>
date Sun, 19 May 2019 11:15:10 +0200
parents 5fa8d1459b35
children b453b586da16
files doc/interpreter/genpropdoc.m libgui/graphics/Canvas.cc libgui/graphics/Canvas.h libgui/graphics/Figure.cc libgui/graphics/Figure.h libgui/src/icons/bottom_left_corner.png libgui/src/icons/bottom_right_corner.png libgui/src/icons/bottom_side.png libgui/src/icons/circle.png libgui/src/icons/circle.svg libgui/src/icons/cross.png libgui/src/icons/fleur.png libgui/src/icons/hand2.png libgui/src/icons/icons_license libgui/src/icons/left_side.png libgui/src/icons/right_side.png libgui/src/icons/top_left_corner.png libgui/src/icons/top_right_corner.png libgui/src/icons/top_side.png libgui/src/module.mk libgui/src/resource.qrc libinterp/corefcn/graphics.in.h
diffstat 22 files changed, 264 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/doc/interpreter/genpropdoc.m	Tue May 21 10:00:52 2019 +0200
+++ b/doc/interpreter/genpropdoc.m	Sun May 19 11:15:10 2019 +0200
@@ -503,11 +503,24 @@
 @code{screenpixelsperinch} property of the root object.";
 
       case "pointer"
-        s.doc = doc_unused;
+        s.doc = "Name of the mouse pointer shape associated with the canvas \
+of the figure.  When __prop__ is \"custom\", the shape is determined by \
+the @code{pointershapecdata} property.\n\n\
+__prop__ has no effect when the figure is in zoom, pan, or rotate mode. \
+In this case, Octave automatically uses a pointer shape appropriate \
+to the mode.";
+
       case "pointershapecdata"
-        s.doc = doc_unused;
+        s.doc ="m-by-m matrix defining a custom pointer.  Each \
+element defines a pixel with the element (1,1) representing the \
+top-left pixel.  A value of 1 is colored black, a value of 2 is colored white, \
+and all other values are rendered as transparent.";
+        s.valid = "16-by-16 or 32-by-32 Matrix";
+
       case "pointershapehotspot"
-        s.doc = doc_unused;
+        s.doc ="For custom pointers only __prop__ defines the row and column \
+of the pixel in @code{pointershapecdata} that is used as the pointer location.";
+        s.valid = valid_2elvec;
 
       case "position"
         s.doc = "Specify the position and size of the figure canvas.  \
--- a/libgui/graphics/Canvas.cc	Tue May 21 10:00:52 2019 +0200
+++ b/libgui/graphics/Canvas.cc	Sun May 19 11:15:10 2019 +0200
@@ -73,7 +73,8 @@
   }
 
   void
-  Canvas::setCursor (MouseMode mode)
+  Canvas::setCursor (MouseMode mode, std::string fallback,
+                     QImage cdata, Matrix hotspot)
   {
     QWidget *w = qWidget ();
     QCursor cursor = Qt::ArrowCursor;
@@ -82,6 +83,70 @@
         switch (mode)
           {
           case NoMode:
+            {
+              cursor = Qt::ArrowCursor;
+
+              if (fallback == "arrow")
+                cursor = Qt::ArrowCursor;
+              else if (fallback == "botl")
+                cursor = QCursor (octave::resource_manager::icon
+                                  ("bottom_left_corner").pixmap (22,22),
+                                  5, 16);
+              else if (fallback == "botr")
+                cursor = QCursor (octave::resource_manager::icon
+                                  ("bottom_right_corner").pixmap (22, 22),
+                                  16, 16);
+              else if (fallback == "bottom")
+                cursor = QCursor (octave::resource_manager::icon
+                                  ("bottom_side").pixmap (22, 22),
+                                  11, 16);
+              else if (fallback == "circle")
+                cursor = QCursor (octave::resource_manager::icon
+                                  ("circle").pixmap (22, 22),
+                                  10, 10);
+              else if (fallback == "cross" || fallback == "crosshair")
+                cursor = QCursor (octave::resource_manager::icon
+                                  ("cross").pixmap (22, 22), 10, 10);
+              else if (fallback == "custom")
+                {
+                  if (hotspot(0) > cdata.width () || hotspot(0) < 1.0
+                      || hotspot(1) > cdata.height () || hotspot(1) < 1.0)
+                    hotspot = Matrix (1, 2, 1);
+
+                  cursor = QCursor (QPixmap::fromImage (cdata),
+                                    static_cast<int> (hotspot(1) - 1),
+                                    static_cast<int> (hotspot(0) - 1));
+                }
+              else if (fallback == "fleur")
+                cursor = QCursor (octave::resource_manager::icon
+                                  ("fleur").pixmap (22, 22), 10, 4);
+              else if (fallback == "hand")
+                cursor = QCursor (octave::resource_manager::icon
+                                  ("hand2").pixmap (22, 22), 7, 3);
+              else if (fallback == "ibeam")
+                cursor = Qt::IBeamCursor;
+              else if (fallback == "left")
+                cursor = QCursor (octave::resource_manager::icon
+                                  ("left_side").pixmap (22, 22), 4, 10);
+              else if (fallback == "right")
+                cursor = QCursor (octave::resource_manager::icon
+                                  ("right_side").pixmap (22, 22),
+                                  17, 10);
+              else if (fallback == "top")
+                cursor = QCursor (octave::resource_manager::icon
+                                  ("top_side").pixmap (22, 22), 11, 4);
+              else if (fallback == "topl")
+                cursor = QCursor (octave::resource_manager::icon
+                                  ("top_left_corner").pixmap (22, 22),
+                                  4, 4);
+              else if (fallback == "topr")
+                cursor = QCursor (octave::resource_manager::icon
+                                  ("top_right_corner").pixmap (22, 22),
+                                  16, 4);
+              else if (fallback == "watch")
+                cursor = Qt::BusyCursor;
+            }
+            break;
           case SelectMode:
             cursor = Qt::ArrowCursor;
             break;
--- a/libgui/graphics/Canvas.h	Tue May 21 10:00:52 2019 +0200
+++ b/libgui/graphics/Canvas.h	Sun May 19 11:15:10 2019 +0200
@@ -63,7 +63,8 @@
     void clearEventMask (int m) { m_eventMask &= (~m); }
     void setEventMask (int m) { m_eventMask = m; }
 
-    void setCursor (MouseMode mode);
+    void setCursor (MouseMode mode, std::string fallback,
+                    QImage cdata, Matrix hotspot);
 
     virtual QWidget * qWidget (void) = 0;
 
--- a/libgui/graphics/Figure.cc	Tue May 21 10:00:52 2019 +0200
+++ b/libgui/graphics/Figure.cc	Sun May 19 11:15:10 2019 +0200
@@ -81,6 +81,29 @@
     return r;
   }
 
+  static QImage
+  pointer_to_qimage (const Matrix& cdata)
+  {
+    QImage retval (cdata.rows (), cdata.columns (), QImage::Format_ARGB32);
+    QColor tmp ("White");
+    QColor black ("Black");
+    QColor white ("White");
+    for (octave_idx_type ii = 0; ii < cdata.rows (); ii++)
+      for (octave_idx_type jj = 0; jj < cdata.columns (); jj++)
+        {
+          if (cdata(ii,jj) == 1.0)
+            tmp = black;
+          else if (cdata(ii,jj) == 2.0)
+            tmp = white;
+          else
+            tmp.setAlpha (0);
+
+          retval.setPixelColor(jj, ii, tmp);
+        }
+
+    return retval;
+  }
+
   Figure*
   Figure::create (const graphics_object& go)
   {
@@ -136,6 +159,9 @@
     // Handle resizing constraints
     update (figure::properties::ID_RESIZE);
 
+    // Custom pointer data
+    update (figure::properties::ID_POINTERSHAPECDATA);
+
     // Visibility
     update (figure::properties::ID_VISIBLE);
 
@@ -426,9 +452,23 @@
 
         break;
 
+      case figure::properties::ID_POINTERSHAPECDATA:
+        m_pointer_cdata =
+          pointer_to_qimage (fp.get_pointershapecdata ().matrix_value ());
+        if (fp.get_pointer () != "custom")
+          break;
+        // Avoid warning about potential fallthrough
+        [[fallthrough]];
+
+      case figure::properties::ID_POINTER:
+      case figure::properties::ID_POINTERSHAPEHOTSPOT:
       case figure::properties::ID___MOUSE_MODE__:
       case figure::properties::ID___ZOOM_MODE__:
-        m_container->canvas (m_handle)->setCursor (mouseMode ());
+        m_container->canvas (m_handle)->setCursor (mouseMode (),
+                                                   fp.get_pointer (),
+                                                   m_pointer_cdata,
+                                                   fp.get_pointershapehotspot ()
+                                                   .matrix_value());
         break;
 
       default:
--- a/libgui/graphics/Figure.h	Tue May 21 10:00:52 2019 +0200
+++ b/libgui/graphics/Figure.h	Sun May 19 11:15:10 2019 +0200
@@ -124,6 +124,7 @@
     QStatusBar *m_statusBar;
     QRect m_innerRect;
     QRect m_outerRect;
+    QImage m_pointer_cdata;
     int m_previousHeight;
     bool m_resizable;
   };
Binary file libgui/src/icons/bottom_left_corner.png has changed
Binary file libgui/src/icons/bottom_right_corner.png has changed
Binary file libgui/src/icons/bottom_side.png has changed
Binary file libgui/src/icons/circle.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/icons/circle.svg	Sun May 19 11:15:10 2019 +0200
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="32"
+   height="32"
+   viewBox="0 0 8.4666659 8.4666659"
+   version="1.1"
+   id="svg1917"
+   sodipodi:docname="circle.svg"
+   inkscape:version="0.92.3 (2405546, 2018-03-11)"
+   inkscape:export-filename="/home/pantxo/Dev/octaveclone/libgui/src/icons/circle.png"
+   inkscape:export-xdpi="96.000008"
+   inkscape:export-ydpi="96.000008">
+  <defs
+     id="defs1911">
+    <filter
+       inkscape:collect="always"
+       style="color-interpolation-filters:sRGB"
+       id="filter2851"
+       x="-0.063633107"
+       width="1.1272662"
+       y="-0.10485"
+       height="1.2097">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="0.50308888"
+         id="feGaussianBlur2853" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="15.839192"
+     inkscape:cx="32.278892"
+     inkscape:cy="22.118004"
+     inkscape:document-units="mm"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1920"
+     inkscape:window-height="1052"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1"
+     units="px" />
+  <metadata
+     id="metadata1914">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Calque 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-288.53334)">
+    <path
+       inkscape:connector-curvature="0"
+       style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.33930296;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+       d="M 4.213445,289.32696 A 3.4506385,3.4506385 0 0 0 0.76280612,292.7776 3.4506385,3.4506385 0 0 0 4.213445,296.22825 3.4506385,3.4506385 0 0 0 7.6640826,292.7776 3.4506385,3.4506385 0 0 0 4.213445,289.32696 Z m 0,0.93147 a 2.5191778,2.5191778 0 0 1 2.5191772,2.51917 2.5191778,2.5191778 0 0 1 -2.5191772,2.51918 2.5191778,2.5191778 0 0 1 -2.5191783,-2.51918 2.5191778,2.5191778 0 0 1 2.5191783,-2.51917 z"
+       id="path1844" />
+    <path
+       inkscape:connector-curvature="0"
+       style="display:inline;opacity:0.2;vector-effect:none;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;filter:url(#filter2851)"
+       d="m 1.3070234,9.3602459 a 10.1875,10.1875 0 0 0 -0.09961,1.3281251 10.1875,10.1875 0 0 0 10.1874996,10.1875 10.1875,10.1875 0 0 0 8.78711,-5.056641 l -2.66406,-0.912109 a 7.4375,7.4375 0 0 1 -6.12305,3.21875 7.4375,7.4375 0 0 1 -7.4374996,-7.4375 7.4375,7.4375 0 0 1 0.0215,-0.414062 z"
+       id="path2462"
+       transform="matrix(0.33871298,0,0,0.32344859,0.35384012,289.47597)" />
+  </g>
+</svg>
Binary file libgui/src/icons/cross.png has changed
Binary file libgui/src/icons/fleur.png has changed
Binary file libgui/src/icons/hand2.png has changed
--- a/libgui/src/icons/icons_license	Tue May 21 10:00:52 2019 +0200
+++ b/libgui/src/icons/icons_license	Sun May 19 11:15:10 2019 +0200
@@ -96,3 +96,26 @@
 db-stop.svg
 plot-xy-curve.svg
 system-run.svg
+
+Cursors from the standard DMZ theme
+===================================
+
+https://github.com/GalliumOS/dmz-cursor-theme/tree/master/DMZ-White
+
+bottom_left_corner.png
+bottom_right_corner.png
+bottom_side.png
+cross.png
+fleur.png
+hand2.png
+left_side.png
+right_side.png
+top_left_corner.png
+top_right_corner.png
+top_side.png
+
+Cursor created by the Octave developers
+with elements from the DMZ theme:
+
+circle.png
+circle.svg
\ No newline at end of file
Binary file libgui/src/icons/left_side.png has changed
Binary file libgui/src/icons/right_side.png has changed
Binary file libgui/src/icons/top_left_corner.png has changed
Binary file libgui/src/icons/top_right_corner.png has changed
Binary file libgui/src/icons/top_side.png has changed
--- a/libgui/src/module.mk	Tue May 21 10:00:52 2019 +0200
+++ b/libgui/src/module.mk	Sun May 19 11:15:10 2019 +0200
@@ -1,9 +1,14 @@
 octave_gui_ICONS = \
   %reldir%/icons/applications-system.png \
+  %reldir%/icons/bottom_left_corner.png \
+  %reldir%/icons/bottom_right_corner.png \
+  %reldir%/icons/bottom_side.png \
   %reldir%/icons/bp-next.png \
   %reldir%/icons/bp-prev.png \
   %reldir%/icons/bp-rm-all.png \
   %reldir%/icons/bp-toggle.png \
+  %reldir%/icons/circle.png \
+  %reldir%/icons/cross.png \
   %reldir%/icons/db-cont.png \
   %reldir%/icons/db-step-in.png \
   %reldir%/icons/db-step-out.png \
@@ -24,6 +29,7 @@
   %reldir%/icons/edit-find-replace.png \
   %reldir%/icons/edit-paste.png \
   %reldir%/icons/edit-redo.png \
+  %reldir%/icons/edit-undo.png \
   %reldir%/icons/figure-axes.png \
   %reldir%/icons/figure-grid.png \
   %reldir%/icons/figure-pan.png \
@@ -32,7 +38,7 @@
   %reldir%/icons/figure-zoom-in.png \
   %reldir%/icons/figure-zoom-original.png \
   %reldir%/icons/figure-zoom-out.png \
-  %reldir%/icons/edit-undo.png \
+  %reldir%/icons/fleur.png \
   %reldir%/icons/folder.png \
   %reldir%/icons/folder-new.png \
   %reldir%/icons/go-down.png \
@@ -60,7 +66,9 @@
   %reldir%/icons/graphic_logo_WorkspaceView.svg \
   %reldir%/icons/graphic_logo_ReleaseWidget.svg \
   %reldir%/icons/graphic_logo_VariableEditor.svg \
+  %reldir%/icons/hand2.png \
   %reldir%/icons/icons_license \
+  %reldir%/icons/left_side.png \
   %reldir%/icons/letter_logo_DocumentationDockWidget.png \
   %reldir%/icons/letter_logo_FileEditor.png \
   %reldir%/icons/letter_logo_FilesDockWidget.png \
@@ -82,7 +90,11 @@
   %reldir%/icons/logo.png \
   %reldir%/icons/plot-xy-curve.png \
   %reldir%/icons/preferences-system.png \
+  %reldir%/icons/right_side.png \
   %reldir%/icons/system-run.png \
+  %reldir%/icons/top_left_corner.png \
+  %reldir%/icons/top_right_corner.png \
+  %reldir%/icons/top_side.png \
   %reldir%/icons/user-home.png \
   %reldir%/icons/view-refresh.png \
   %reldir%/icons/widget-close.png \
--- a/libgui/src/resource.qrc	Tue May 21 10:00:52 2019 +0200
+++ b/libgui/src/resource.qrc	Sun May 19 11:15:10 2019 +0200
@@ -5,6 +5,11 @@
         <file>icons/bp-rm-all.png</file>
         <file>icons/bp-prev.png</file>
         <file>icons/bp-next.png</file>
+        <file>icons/bottom_left_corner.png</file>
+        <file>icons/bottom_right_corner.png</file>
+        <file>icons/bottom_side.png</file>
+        <file>icons/circle.png</file>
+        <file>icons/cross.png</file>
         <file>icons/db-cont.png</file>
         <file>icons/db-step.png</file>
         <file>icons/db-step-in.png</file>
@@ -52,6 +57,9 @@
         <file>icons/graphic_logo_DocumentationDockWidget.png</file>
         <file>icons/graphic_logo_ReleaseWidget.png</file>
         <file>icons/graphic_logo_VariableEditor.png</file>
+        <file>icons/fleur.png</file>
+        <file>icons/hand2.png</file>
+        <file>icons/left_side.png</file>
         <file>icons/letter_logo_FilesDockWidget.png</file>
         <file>icons/letter_logo_FileEditor.png</file>
         <file>icons/letter_logo_NewsDockWidget.png</file>
@@ -64,7 +72,11 @@
         <file>icons/logo.png</file>
         <file>icons/plot-xy-curve.png</file>
         <file>icons/preferences-system.png</file>
+        <file>icons/right_side.png</file>
         <file>icons/system-run.png</file>
+        <file>icons/top_left_corner.png</file>
+        <file>icons/top_right_corner.png</file>
+        <file>icons/top_side.png</file>
         <file>icons/user-home.png</file>
         <file>icons/view-refresh.png</file>
         <file>icons/widget-close.png</file>
--- a/libinterp/corefcn/graphics.in.h	Tue May 21 10:00:52 2019 +0200
+++ b/libinterp/corefcn/graphics.in.h	Sun May 19 11:15:10 2019 +0200
@@ -3142,9 +3142,9 @@
       array_property papersize U , default_figure_papersize ()
       radio_property papertype SU , "{usletter}|uslegal|a0|a1|a2|a3|a4|a5|b0|b1|b2|b3|b4|b5|arch-a|arch-b|arch-c|arch-d|arch-e|a|b|c|d|e|tabloid|<custom>"
       radio_property paperunits Su , "{inches}|centimeters|normalized|points"
-      radio_property pointer , "crosshair|fullcrosshair|{arrow}|ibeam|watch|topl|topr|botl|botr|left|top|right|bottom|circle|cross|fleur|custom|hand"
-      array_property pointershapecdata , Matrix (16, 16, 0)
-      array_property pointershapehotspot , Matrix (1, 2, 0)
+      radio_property pointer , "crosshair|{arrow}|ibeam|watch|topl|topr|botl|botr|left|top|right|bottom|circle|cross|fleur|custom|hand"
+      array_property pointershapecdata , Matrix (16, 16, 1)
+      array_property pointershapehotspot , Matrix (1, 2, 1)
       array_property position s , default_figure_position ()
       radio_property renderer m , "{opengl}|painters"
       radio_property renderermode , "{auto}|manual"
@@ -3201,6 +3201,7 @@
       papersize.add_constraint (dim_vector (1, 2));
       papersize.add_constraint (FINITE);
       pointershapecdata.add_constraint (dim_vector (16, 16));
+      pointershapecdata.add_constraint (dim_vector (32, 32));
       pointershapehotspot.add_constraint (dim_vector (1, 2));
       position.add_constraint (dim_vector (1, 4));
       position.add_constraint (FINITE);