Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorolpc user <olpc@xo-1e-88-ab.localdomain>2013-05-15 02:43:59 (GMT)
committer Agustin Zubiaga <aguz@localhost.localdomain>2013-06-03 19:06:59 (GMT)
commitd06d767f69b8d2fd58b4f273d7733b7769f059e1 (patch)
tree350b69863ab9a1b384c98a4292e1b710ce27eed8
parentcc2b1ba12d1d7b68f015d7908a2d329ee73d4116 (diff)
Go back to a clean, basic view
This commit breaks a lot of things.
-rw-r--r--ImageView.py410
-rw-r--r--ImageViewerActivity.py22
2 files changed, 86 insertions, 346 deletions
diff --git a/ImageView.py b/ImageView.py
index f20910c..f335e92 100644
--- a/ImageView.py
+++ b/ImageView.py
@@ -15,378 +15,130 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-from __future__ import division
+import cairo
from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import GdkPixbuf
from gi.repository import GObject
-import sys
-import logging
-import cairo
-import random
-import time
-import math
+ZOOM_STEP = 0.05
+ZOOM_MAX = 4
+ZOOM_MIN = 0.05
-ZOOM_IN_OUT = 0.1
+def _surface_from_file(file_location, ctx):
+ pixbuf = GdkPixbuf.Pixbuf.new_from_file(file_location)
+ surface = ctx.get_target().create_similar(
+ cairo.CONTENT_COLOR_ALPHA, pixbuf.get_width(),
+ pixbuf.get_height())
-class ImageViewer(Gtk.DrawingArea):
- __gsignals__ = {
- #'expose-event': (
- # 'override'),
- 'zoom-changed': (
- GObject.SignalFlags.RUN_FIRST, None, []),
- 'angle-changed': (
- GObject.SignalFlags.RUN_FIRST, None, []),
- }
-
- __gproperties__ = {
- 'zoom': (
- GObject.TYPE_FLOAT, 'Zoom Factor', 'Factor of zoom',
- 0, 4, 1, GObject.PARAM_READWRITE),
- 'angle': (
- GObject.TYPE_INT, 'Angle', 'Angle of rotation',
- 0, 360, 0, GObject.PARAM_READWRITE),
- 'file_location': (
- GObject.TYPE_STRING, 'File Location', 'Location of the image file',
- '', GObject.PARAM_READWRITE),
- }
+ ctx_surface = cairo.Context(surface)
+ Gdk.cairo_set_source_pixbuf(ctx_surface, pixbuf, 0, 0)
+ ctx_surface.paint()
+ return surface
+
+class ImageViewer(Gtk.DrawingArea):
def __init__(self):
- GObject.GObject.__init__(self)
- self.set_app_paintable(True)
+ Gtk.DrawingArea.__init__(self)
- self.surface = None
- self.zoom = None
- self.parent = None
- self.file_location = None
- self._optimal_zoom_flag = True
+ self._file_location = None
+ self._surface = None
+ self._zoom = None
self.connect('draw', self.__draw_cb)
- self.angle = 0
- self._zoom_ori = 1.0
- self._angle_ori = 0.0
- self._fast = True
- self._redraw_id = None
- self._switched = False
-
- # zoom with fixed point
- self._is_touching = False
- self._touch_center = False
- self._old_zoom = None
- self._xofs = 0
- self._yofs = 0
-
- def do_get_property(self, pspec):
- if pspec.name == 'zoom':
- return self.zoom
- elif pspec.name == 'angle':
- return self.angle
- elif pspec.name == 'file_location':
- return self.file_location
- else:
- raise AttributeError('unknown property %s' % pspec.name)
-
- def do_set_property(self, pspec, value):
- if pspec.name == 'zoom':
- self.set_zoom(value)
- elif pspec.name == 'angle':
- self.set_angle(value)
- elif pspec.name == 'file_location':
- self.set_file_location(value)
- else:
- raise AttributeError('unknown property %s' % pspec.name)
-
- def set_optimal_zoom(self):
- self._optimal_zoom_flag = True
- self._set_zoom(self._calc_optimal_zoom())
-
- def update_optimal_zoom(self):
- if self._optimal_zoom_flag:
- self._set_zoom(self._calc_optimal_zoom())
-
- def __draw_cb(self, widget, ctx):
- timeini = time.time()
- logging.error('ImageViewer.draw start')
-
- if self.surface is None:
- if self.file_location is None:
- return
- logging.error('init surface with image')
- # http://cairographics.org/gdkpixbufpycairo/
- pixbuf = GdkPixbuf.Pixbuf.new_from_file(self.file_location)
- self.surface = ctx.get_target().create_similar(
- cairo.CONTENT_COLOR_ALPHA, pixbuf.get_width(),
- pixbuf.get_height())
- ctx_surface = cairo.Context(self.surface)
- self._pixbuf_to_context(pixbuf, ctx_surface)
-
- if self.zoom is None:
- self.zoom = self._calc_optimal_zoom()
-
- w = int(self.surface.get_width() * self.zoom)
- h = int(self.surface.get_height() * self.zoom)
- logging.error('W: %s, H: %s', w, h)
-
- if self._fast:
- ctx.set_antialias(cairo.ANTIALIAS_NONE)
-
- scrolled_window = self.get_parent()
- rect = scrolled_window.get_allocation()
- x = y = 0
- if self.angle != 0:
- logging.error('Rotating: %s', self.angle)
- ctx.rotate(self.angle)
-
- if self.angle == math.pi:
- ctx.translate(-w, -h)
-
- if rect.width > w:
- x = -(rect.width - w) / 2
- if rect.height > h:
- y = -(rect.height - h) / 2
-
- elif self.angle == math.pi / 2:
- ctx.translate(0, -h)
-
- # center the image
- if rect.height > w:
- x = (rect.height - w) / 2
- if rect.width > h:
- y = -(rect.width - h) / 2
-
- elif self.angle == math.pi * 3 / 2:
- ctx.translate(-w, 0)
-
- if rect.height > w:
- x = -(rect.height - w) / 2
- if rect.width > h:
- y = (rect.width - h) / 2
-
- else:
- if rect.width > w:
- x = int((rect.width - w) / 2)
- if rect.height > h:
- y = int((rect.height - h) / 2)
- ctx.translate(x, y)
-
- if self.zoom != 1:
- logging.error('Scaling: %s', self.zoom)
- ctx.scale(self.zoom, self.zoom)
-
- ctx.set_source_surface(self.surface, 0, 0)
- if self._fast:
- ctx.get_source().set_filter(cairo.FILTER_NEAREST)
- ctx.paint()
- logging.error('ImageViewer.draw end %f', (time.time() - timeini))
-
- if not self._fast:
- if self._redraw_id is not None:
- GObject.source_remove(self._redraw_id)
- self._redraw_id = GObject.timeout_add(200,
- self._redraw_high_quality)
-
- self._is_touching = False
-
- def _redraw_high_quality(self):
- self._fast = False
- self._redraw_id = None
- self._redraw()
- return False
-
- def _redraw(self):
- # README: this is a hack to not raise the 'draw' event (again)
- # when we request more space to show the scroll bars
- w = int(self.surface.get_width() * self.zoom)
- h = int(self.surface.get_height() * self.zoom)
-
- self._switched = False
- if (self.angle / (math.pi / 2)) % 2 == 1:
- # change image dimensions if it's rotated
- w, h = h, w
- self._switched = True
-
- self.set_size_request(w, h)
- self._scroll_image()
-
- def _scroll_image(self):
- # based on Eye Of GNOME code
-
- w = int(self.surface.get_width() * self.zoom)
- h = int(self.surface.get_height() * self.zoom)
-
- old_width = int(self.surface.get_width() * self._old_zoom)
- old_height = int(self.surface.get_height() * self._old_zoom)
-
- scrolled_window = self.get_parent()
- rect = scrolled_window.get_allocation()
+ def set_file_location(self, file_location):
+ self._file_location = file_location
+ self.queue_draw()
- if self._switched:
- # TODO: zoom with fixed point does not work properly when
- # the image is rotated
+ def zoom_in(self):
+ if self._zoom + ZOOM_STEP > ZOOM_MAX:
return
+ self._zoom += ZOOM_STEP
+ self.queue_draw()
- if self._is_touching:
- zoom_x_anchor = self._touch_center[1] / rect.width
- zoom_y_anchor = self._touch_center[2] / rect.height
- else:
- zoom_x_anchor = 0.5
- zoom_y_anchor = 0.5
-
- vadjustment = scrolled_window.get_vadjustment()
- step_inc = vadjustment.get_step_increment()
- page_inc = vadjustment.get_page_increment()
-
- if old_height < rect.height:
- cy = zoom_y_anchor * old_height / self._old_zoom
- else:
- cy = (self._yofs + zoom_y_anchor * rect.height) / self._old_zoom
-
- if h < rect.height:
- self._yofs = 0
- else:
- self._yofs = math.floor(cy * self.zoom - \
- zoom_y_anchor * rect.height + 0.5)
-
- vadj = max(0, min(self._yofs, h - rect.height))
- vadjustment.configure(vadj, 0, h, step_inc, page_inc,
- rect.height)
-
- hadjustment = scrolled_window.get_hadjustment()
- step_inc = hadjustment.get_step_increment()
- page_inc = hadjustment.get_page_increment()
-
- if old_width < rect.width:
- cx = zoom_x_anchor * old_width / self._old_zoom
- else:
- cx = (self._xofs + zoom_x_anchor * rect.width) / self._old_zoom
-
- if w < rect.width:
- self._xofs = 0
- else:
- self._xofs = math.floor(cx * self.zoom - \
- zoom_x_anchor * rect.width + 0.5)
-
- hadj = max(0, min(self._xofs, w - rect.width))
- hadjustment.configure(hadj, 0, w, step_inc, page_inc,
- rect.width)
-
- def set_zoom(self, zoom):
- self._optimal_zoom_flag = False
- self._set_zoom(zoom)
-
- def set_zoom_relative(self, scale):
- if scale == 1.0:
- self._zoom_ori = self.zoom
- self._set_zoom(self._zoom_ori * scale)
-
- def set_angle_relative(self, diff):
- if diff == 0.0:
- self._angle_ori = self.angle
- self.set_angle(self._angle_ori + diff)
+ def zoom_out(self):
+ if self._zoom - ZOOM_STEP < ZOOM_MIN:
+ return
+ self._zoom -= ZOOM_MIN
+ self.queue_draw()
- def set_angle(self, angle):
- self._optimal_zoom_flag = True
+ def zoom_to_fit(self):
+ # This tries to figure out a best fit model
+ # If the image can fit in, we show it in 1:1,
+ # in any other case we show it in a fit to screen way
- self.angle = angle % (2 * math.pi)
- self._redraw()
- self.emit('angle-changed')
+ parent_allocation = self.get_parent().get_allocation()
+ parent_width = parent_allocation.width
+ parent_height = parent_allocation.height
- def zoom_in(self):
- self.set_zoom(self.zoom + ZOOM_IN_OUT)
- # TODO: this value is not valid
- if self.zoom > (4):
- return False
- else:
- return True
+ surface_width = self._surface.get_width()
+ surface_height = self._surface.get_height()
- def zoom_out(self):
- self.set_zoom(self.zoom - ZOOM_IN_OUT)
- # TODO: this value is not valid
- if self.zoom <= 0.2:
- return False
+ if parent_width < surface_width or parent_height < surface_height:
+ # Image is larger than allocated size
+ self._zoom = min(parent_width * 1.0 / surface_width,
+ parent_height * 1.0 / surface_height)
else:
- return True
-
- def _pixbuf_to_context(self, pixbuf, context, x=0, y=0):
- # copy from the pixbuf to the drawing context
- context.save()
- context.translate(x, y)
- Gdk.cairo_set_source_pixbuf(context, pixbuf, 0, 0)
- context.paint()
- context.restore()
-
- def set_file_location(self, file_location):
- logging.debug('Loading image from: %s', file_location)
+ self._zoom = 1.0
+ self.queue_draw()
- self.file_location = file_location
- self.zoom = None
+ def zoom_equal(self):
+ self._zoom = 1
self.queue_draw()
- def _calc_optimal_zoom(self):
- # This tries to figure out a best fit model
- # If the image can fit in, we show it in 1:1,
- # in any other case we show it in a fit to screen way
+ def __draw_cb(self, widget, ctx):
- if isinstance(self.parent, Gtk.Viewport):
- rect = self.parent.parent.get_allocation()
- else:
- rect = self.parent.get_allocation()
- width = rect.width
- height = rect.height
+ # If the image surface is not set, it reads it from the file
+ # location. If the file location is not set yet, it just
+ # returns.
+ if self._surface is None:
+ if self._file_location is None:
+ return
+ self._surface = _surface_from_file(self._file_location, ctx)
- surface_width = self.surface.get_width()
- surface_height = self.surface.get_height()
+ if self._zoom is None:
+ self.zoom_to_fit()
- if self._switched:
- surface_width, surface_height = \
- surface_height, surface_width
+ # FIXME investigate
+ ctx.set_antialias(cairo.ANTIALIAS_NONE)
- if width < surface_width or \
- height < surface_height:
- # Image is larger than allocated size
- zoom = min(width / surface_width,
- height / surface_height)
- else:
- zoom = 1
+ # Scale and center the image according to the current zoom.
- logging.debug('Optimal zoom: %s', zoom)
- return zoom
+ scaled_width = int(self._surface.get_width() * self._zoom)
+ scaled_height = int(self._surface.get_height() * self._zoom)
- def _set_zoom(self, zoom):
- self._old_zoom = self.zoom
- self.zoom = zoom
- self._redraw()
- self.emit('zoom-changed')
+ parent_allocation = self.get_parent().get_allocation()
+ parent_width = parent_allocation.width
+ parent_height = parent_allocation.height
+ x_offset = (parent_width * 1.0 - scaled_width) / 2
+ y_offset = (parent_height * 1.0 - scaled_height) / 2
-def update(view_object):
- #return view_object.zoom_out()
- angle = 90 * random.randint(0, 4)
- view_object.set_angle(angle)
+ ctx.translate(x_offset, y_offset)
+ ctx.scale(self._zoom, self._zoom)
+ ctx.set_source_surface(self._surface, 0, 0)
- return True
+ # FIXME investigate
+ ctx.get_source().set_filter(cairo.FILTER_NEAREST)
+
+ ctx.paint()
if __name__ == '__main__':
- window = Gtk.Window()
+ import sys
- vadj = Gtk.Adjustment()
- hadj = Gtk.Adjustment()
- sw = Gtk.ScrolledWindow(hadj, vadj)
+ window = Gtk.Window()
+ window.connect("destroy", Gtk.main_quit)
view = ImageViewer()
view.set_file_location(sys.argv[1])
-
- sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
- sw.add_with_viewport(view)
- window.add(sw)
+ window.add(view)
+ view.show()
window.set_size_request(800, 600)
- window.show_all()
+ window.show()
- GObject.timeout_add(1000, update, view)
Gtk.main()
diff --git a/ImageViewerActivity.py b/ImageViewerActivity.py
index 4850116..3085675 100644
--- a/ImageViewerActivity.py
+++ b/ImageViewerActivity.py
@@ -107,7 +107,6 @@ IMAGEVIEWER_STREAM_SERVICE = 'imageviewer-activity-http'
class ImageViewerActivity(activity.Activity):
def __init__(self, handle):
- logging.error('start activity')
activity.Activity.__init__(self, handle)
self.zoom = None
self._object_id = handle.object_id
@@ -135,16 +134,6 @@ class ImageViewerActivity(activity.Activity):
self.set_toolbar_box(toolbar_box)
toolbar_box.show()
- vadj = Gtk.Adjustment()
- hadj = Gtk.Adjustment()
- self.sw = Gtk.ScrolledWindow(hadj, vadj)
- self.view.parent = self.sw
- # Avoid needless spacing
- self.view.parent.props.shadow_type = Gtk.ShadowType.NONE
- self.sw.set_policy(Gtk.PolicyType.AUTOMATIC,
- Gtk.PolicyType.AUTOMATIC)
- self.sw.add_with_viewport(self.view)
- self.sw.show_all()
self._last_angle = 0.0
self._last_scale = 1.0
@@ -183,10 +172,10 @@ class ImageViewerActivity(activity.Activity):
empty_widgets.add(vbox)
empty_widgets.show_all()
- logging.error('show empty widgets')
self.set_canvas(empty_widgets)
else:
- self.set_canvas(self.sw)
+ self.set_canvas(self.view)
+ self.view.show()
self.unused_download_tubes = set()
self._want_document = True
@@ -216,7 +205,6 @@ class ImageViewerActivity(activity.Activity):
def __scale_changed_cb(self, controller, scale):
if scale != self._last_scale:
self._last_scale = scale
- logging.error('Scale changed %f', scale)
self.view._is_touching = True
self.view._touch_center = controller.get_center()
@@ -308,10 +296,10 @@ class ImageViewerActivity(activity.Activity):
self._zoom_in_button.set_sensitive(True)
def __zoom_tofit_cb(self, button):
- self.view.set_optimal_zoom()
+ self.view.zoom_to_fit()
def __zoom_original_cb(self, button):
- self.view.set_zoom(1)
+ self.view.zoom_equal()
def __rotate_anticlockwise_cb(self, button):
angle = self.view.angle - math.pi / 2
@@ -337,7 +325,7 @@ class ImageViewerActivity(activity.Activity):
jobject = chooser.get_selected_object()
if jobject and jobject.file_path:
self.read_file(jobject.file_path)
- self.set_canvas(self.sw)
+ self.set_canvas(self.view)
finally:
chooser.destroy()
del chooser