Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManuel QuiƱones <manuq@laptop.org>2013-05-15 18:13:10 (GMT)
committer Agustin Zubiaga <aguz@localhost.localdomain>2013-06-03 19:07:00 (GMT)
commit38245d9f4c51fc1af29a326392939138ef137f08 (patch)
tree0933624306447a7de1935d4c7d8e77fa9e0a55ff
parentb0e066894ab52d4dc7a8e7273b04d885953b870b (diff)
Improve pinch to zoom, add rotation
Center the image between the touch points.
-rw-r--r--ImageView.py78
-rw-r--r--ImageViewerActivity.py6
2 files changed, 68 insertions, 16 deletions
diff --git a/ImageView.py b/ImageView.py
index 7bc9095..2dae6b4 100644
--- a/ImageView.py
+++ b/ImageView.py
@@ -17,6 +17,7 @@
import logging
import cairo
+import math
from gi.repository import Gtk
from gi.repository import Gdk
@@ -47,8 +48,10 @@ class ImageViewer(Gtk.DrawingArea):
self._file_location = None
self._surface = None
self._zoom = None
+ self._angle = 0
+ self._target_point = None
+ self._anchor_point = None
- self._in_zoomtouch = False
self._zoomtouch_scale = 1
self.connect('draw', self.__draw_cb)
@@ -57,6 +60,11 @@ class ImageViewer(Gtk.DrawingArea):
self._file_location = file_location
self.queue_draw()
+ def _center_surface(self):
+ # Setting target point to None, the draw callback will center
+ # the image surface.
+ self._target_point = None
+
def set_zoom(self, zoom):
if zoom < ZOOM_MIN or zoom > ZOOM_MAX:
return
@@ -100,6 +108,8 @@ class ImageViewer(Gtk.DrawingArea):
alloc.height * 1.0 / surface_height)
else:
self._zoom = 1.0
+
+ self._center_surface()
self.queue_draw()
def zoom_original(self):
@@ -107,27 +117,58 @@ class ImageViewer(Gtk.DrawingArea):
self.queue_draw()
def start_zoomtouch(self, center):
- logging.debug("start_zoomtouch %r", center)
- self._in_zoomtouch = True
self._zoomtouch_scale = 1
+
+ # Set target point to the relative coordinates of this view.
+ alloc = self.get_allocation()
+ self._target_point = (center[1] - alloc.x, center[2] - alloc.y)
+
self.queue_draw()
def update_zoomtouch(self, center, scale):
- logging.debug("update_zoomtouch %r", (center, scale))
self._zoomtouch_scale = scale
+
+ # Set target point to the relative coordinates of this view.
+ alloc = self.get_allocation()
+ self._target_point = (center[1] - alloc.x, center[2] - alloc.y)
+
self.queue_draw()
def finish_zoomtouch(self):
- logging.debug("finish_zoomtouch")
- # apply zoom
+ # Apply zoom
self._zoom = self._zoom * self._zoomtouch_scale
-
- self._in_zoomtouch = False
self._zoomtouch_scale = 1
+
+ # Restrict zoom values
+ if self._zoom < ZOOM_MIN:
+ self._zoom = ZOOM_MIN
+ elif self._zoom > ZOOM_MAX:
+ self._zoom = ZOOM_MAX
+
+ # If at the current size the image surface is smaller than the
+ # available space, center it on the canvas.
+
+ alloc = self.get_allocation()
+
+ scaled_width = self._surface.get_width() * self._zoom
+ scaled_height = self._surface.get_height() * self._zoom
+
+ if alloc.width >= scaled_width and alloc.height >= scaled_height:
+ self._center_surface()
+
+ self.queue_draw()
+
+ def rotate_anticlockwise(self):
+ self._angle = self._angle - math.pi / 2
+ self.queue_draw()
+
+ def rotate_clockwise(self):
+ self._angle = self._angle + math.pi / 2
self.queue_draw()
def __draw_cb(self, widget, ctx):
+ alloc = self.get_allocation()
# If the image surface is not set, it reads it from the file
# location. If the file location is not set yet, it just
@@ -143,6 +184,11 @@ class ImageViewer(Gtk.DrawingArea):
# FIXME investigate
ctx.set_antialias(cairo.ANTIALIAS_NONE)
+ # If no target point was set via pinch-to-zoom, default to the
+ # center of the screen.
+ if self._target_point is None:
+ self._target_point = (alloc.width / 2, alloc.height / 2)
+
# Scale and center the image according to the current zoom.
zoom_absolute = self._zoom * self._zoomtouch_scale
@@ -150,13 +196,21 @@ class ImageViewer(Gtk.DrawingArea):
scaled_width = int(self._surface.get_width() * zoom_absolute)
scaled_height = int(self._surface.get_height() * zoom_absolute)
+ # If no anchor point was set via pinch-to-zoom, default to the
+ # center of the surface.
+ if self._anchor_point is None:
+ self._anchor_point = (self._surface.get_width() / 2,
+ self._surface.get_height() / 2)
- alloc = self.get_allocation()
- x_offset = (alloc.width * 1.0 - scaled_width) / 2
- y_offset = (alloc.height * 1.0 - scaled_height) / 2
+ ctx.translate(*self._target_point)
- ctx.translate(x_offset, y_offset)
ctx.scale(zoom_absolute, zoom_absolute)
+
+ if self._angle != 0:
+ ctx.rotate(self._angle)
+
+ ctx.translate(self._anchor_point[0] * -1, self._anchor_point[1] * -1)
+
ctx.set_source_surface(self._surface, 0, 0)
# FIXME investigate
diff --git a/ImageViewerActivity.py b/ImageViewerActivity.py
index ab1424c..1d222d7 100644
--- a/ImageViewerActivity.py
+++ b/ImageViewerActivity.py
@@ -289,12 +289,10 @@ class ImageViewerActivity(activity.Activity):
self._update_zoom_buttons()
def __rotate_anticlockwise_cb(self, button):
- angle = self.view.angle - math.pi / 2
- self.view.set_angle(angle)
+ self.view.rotate_anticlockwise()
def __rotate_clockwise_cb(self, button):
- angle = self.view.angle + math.pi / 2
- self.view.set_angle(angle)
+ self.view.rotate_clockwise()
def __fullscreen_cb(self, button):
self.fullscreen()