It bothered me that the touch-part in my new Wacom Intuos Pen & Touch didn't
really work that well with MyPaint's scrolling behaviour, so I've added an
alternative scrolling option under View which changes the behaviour of scroll
events (button 4, 5, 6, 7) to panning instead of zoom and rotate. (The current
XFree86 wacom driver sends these keys on multi-finger gestures --- I'm currently
looking into making these smooth scrolling events instead, for X servers that
support it.)

It is, IMHO, also a smarter default scheme, as it is the same as for Gimp,
Inkscape, and virtually all other standard applications except Krita. The patch
also includes support for smooth scrolling events, which currently defaults to
panning for the same reason.

In general, I would like to see scroll events as mappable events similar to
mouse buttons. Currently, if you want that type of behaviour, you have to use
xmodmap, or equivalent, to remap those buttons to a key press event, which would
in turn conflict with scrolling in all other applications. For people who paint
using a mouse, I imagine this would be especially useful as well.
diff --git a/gui/document.py b/gui/document.py
index 1f6e594..2f94cbe 100644
--- a/gui/document.py
+++ b/gui/document.py
@@ -91,6 +91,7 @@ class CanvasController (object):
         """
         self.tdw.connect("scroll-event", self.scroll_cb)
         self.tdw.add_events(gdk.SCROLL_MASK)
+        self.tdw.add_events(gdk.SMOOTH_SCROLL_MASK)
 
     ## Low-level GTK event handlers: delegated to the current mode
 
@@ -220,10 +221,13 @@ class Document (CanvasController):  # TODO: rename to "DocumentController"
 
     # Constants for panning (movement) by increments
     PAN_STEP = 0.2  #: Stepwise panning amount: proportion of the canvas size
+    ALT_PAN_STEP = 0.1  #: Stepwise panning amount: proportion of the canvas size (alternative scrolling mode)
+    PAN_SMOOTH_STEP = 0.1  #: Smooth panning amount: relative to canvas size
     PAN_LEFT = 1  #: Stepwise panning direction: left
     PAN_RIGHT = 2  #: Stepwise panning direction: right
     PAN_UP = 3  #: Stepwise panning direction: up
     PAN_DOWN = 4  #: Stepwise panning direction: down
+    PAN_SMOOTH = 5  #: Smooth panning mask
 
     # Picking
     MIN_PICKING_OPACITY = 0.1
@@ -1408,14 +1412,17 @@ class Document (CanvasController):  # TODO: rename to "DocumentController"
 
     ## Viewport manipulation
 
-    def pan(self, direction):
+    def pan(self, direction, dx=0, dy=0):
         """Handles panning (scrolling) in increments.
 
         :param direction: direction of panning
         :type direction: `PAN_LEFT`, `PAN_RIGHT`, `PAN_UP`, or `PAN_DOWN`
         """
+        alt_scroll = self.app.preferences['ui.alt_scroll']
         allocation = self.tdw.get_allocation()
-        step = min((allocation.width, allocation.height)) * self.PAN_STEP
+        min_alloc = min((allocation.width, allocation.height))
+        step = min_alloc * (self.ALT_PAN_STEP if alt_scroll else self.PAN_STEP)
+        smooth_step = min_alloc * self.PAN_SMOOTH_STEP
         if direction == self.PAN_LEFT:
             self.tdw.scroll(-step, 0)
         elif direction == self.PAN_RIGHT:
@@ -1424,6 +1431,8 @@ class Document (CanvasController):  # TODO: rename to "DocumentController"
             self.tdw.scroll(0, -step)
         elif direction == self.PAN_DOWN:
             self.tdw.scroll(0, +step)
+        elif direction == self.PAN_SMOOTH:
+            self.tdw.scroll(dx * smooth_step, dy * smooth_step)
         else:
             raise TypeError('unsupported pan() direction=%s' % direction)
         self.notify_view_changed()
diff --git a/gui/mode.py b/gui/mode.py
index 5d934b6..bcfd0df 100644
--- a/gui/mode.py
+++ b/gui/mode.py
@@ -419,21 +419,38 @@ class ScrollableModeMixin (InteractionMode):
 
         """
         doc = self.doc
+        p = doc.app.preferences
         d = event.direction
+        dx, dy = event.delta_x, event.delta_y
+        print(d, dx, dy)
         if d == gdk.SCROLL_UP:
             if event.state & gdk.SHIFT_MASK:
                 doc.rotate(doc.ROTATE_CLOCKWISE)
             else:
-                doc.zoom(doc.ZOOM_INWARDS)
+                if not p['ui.alt_scroll'] or (event.state & gdk.CONTROL_MASK):
+                    doc.zoom(doc.ZOOM_INWARDS)
+                else:
+                    doc.pan(doc.PAN_UP)
         elif d == gdk.SCROLL_DOWN:
             if event.state & gdk.SHIFT_MASK:
                 doc.rotate(doc.ROTATE_ANTICLOCKWISE)
             else:
-                doc.zoom(doc.ZOOM_OUTWARDS)
+                if not p['ui.alt_scroll'] or (event.state & gdk.CONTROL_MASK):
+                    doc.zoom(doc.ZOOM_OUTWARDS)
+                else:
+                    doc.pan(doc.PAN_DOWN)
         elif d == gdk.SCROLL_RIGHT:
-            doc.rotate(doc.ROTATE_ANTICLOCKWISE)
+            if not p['ui.alt_scroll']:
+                doc.rotate(doc.ROTATE_ANTICLOCKWISE)
+            else:
+                doc.pan(doc.PAN_RIGHT)
         elif d == gdk.SCROLL_LEFT:
-            doc.rotate(doc.ROTATE_CLOCKWISE)
+            if not p['ui.alt_scroll']:
+                doc.rotate(doc.ROTATE_CLOCKWISE)
+            else:
+                doc.pan(doc.PAN_LEFT)
+        elif d == gdk.SCROLL_SMOOTH:
+            doc.pan(doc.PAN_SMOOTH, dx, dy)
         else:
             super(ScrollableModeMixin, self).scroll_cb(tdw, event)
         return True
diff --git a/gui/preferenceswindow.glade b/gui/preferenceswindow.glade
index 78e81f3..b8b895b 100644
--- a/gui/preferenceswindow.glade
+++ b/gui/preferenceswindow.glade
@@ -729,6 +729,36 @@ This may result in slow scrolling on some platforms.</property>
           </packing>
         </child>
         <child>
+          <object class="GtkLabel" id="label35">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="margin_left">12</property>
+            <property name="xalign">0</property>
+            <property name="label" translatable="yes" context="Prefs Dialog|View|Interface|">Alternative scrolling:</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">8</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkCheckButton" id="alt_scroll_checkbutton">
+            <property name="label" translatable="yes" context="Prefs Dialog|View|Interface|Alternative scrolling|">Use alternative scrolling</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="xalign">0</property>
+            <property name="draw_indicator">True</property>
+            <property name="tooltip_markup" translatable="yes" context="Prefs Dialog|View|Interface|Alternative scrolling">This option will make scrolling events (button 4, 5, 6, 7) pan the view.</property>
+            <signal name="toggled" handler="alt_scroll_toggled_cb" swapped="no"/>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">8</property>
+            <property name="width">2</property>
+          </packing>
+        </child>
+        <child>
           <object class="GtkLabel" id="label28">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
diff --git a/gui/preferenceswindow.py b/gui/preferenceswindow.py
index a837fa1..ebe3ec4 100644
--- a/gui/preferenceswindow.py
+++ b/gui/preferenceswindow.py
@@ -122,6 +122,11 @@ class PreferencesWindow (windowing.Dialog):
         dark_checkbutton = self._builder.get_object("dark_theme_checkbutton")
         dark_checkbutton.set_active(dark)
 
+        # Alternative scrolling
+        alt_scroll = bool(p.get("ui.alt_scroll"))
+        alt_scroll_checkbutton = self._builder.get_object("alt_scroll_checkbutton")
+        alt_scroll_checkbutton.set_active(alt_scroll)
+
         # High-quality zoom
         hq_zoom_checkbutton = self._builder.get_object("hq_zoom_checkbutton")
         hq_zoom_checkbutton.set_active(p['view.high_quality_zoom'])
@@ -192,6 +197,10 @@ class PreferencesWindow (windowing.Dialog):
         dark = bool(checkbut.get_active())
         self.app.preferences["ui.dark_theme_variant"] = dark
 
+    def alt_scroll_toggled_cb(self, button):
+        alt_scroll = bool(button.get_active())
+        self.app.preferences["ui.alt_scroll"] = alt_scroll
+
     def hq_zoom_checkbutton_toggled_cb(self, button):
         hq_zoom = bool(button.get_active())
         self.app.preferences['view.high_quality_zoom'] = hq_zoom
_______________________________________________
Mypaint-discuss mailing list
[email protected]
https://mail.gna.org/listinfo/mypaint-discuss

Reply via email to