Codebase list sugar-read-activity / 2b8256e
Merge branch 'cbz-try3' of https://github.com/SAMdroid-apps/read-activity into SAMdroid-apps-cbz-try3 Gonzalo Odiard 9 years ago
4 changed file(s) with 779 addition(s) and 2 deletion(s). Raw diff Collapse all Expand all
33 icon = activity-read
44 exec = sugar-activity readactivity.ReadActivity
55 activity_version = 114
6 mime_types = application/pdf;image/vnd.djvu;image/x.djvu;image/tiff;application/epub+zip;text/plain;application/zip
6 mime_types = application/pdf;image/vnd.djvu;image/x.djvu;image/tiff;application/epub+zip;text/plain;application/zip;application/x-cbz
77 license = GPLv2+
88 summary = Use this activity when you are ready to read! Remember to flip your computer around to feel like you are really holding a book!
9 categories = language documents media tools system
9 categories = language documents media tools system
0 # Copyright (C) 2014, Sam Parkinson
1 #
2 # This program is free software; you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation; either version 2 of the License, or
5 # (at your option) any later version.
6 #
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
11 #
12 # You should have received a copy of the GNU General Public License
13 # along with this program; if not, write to the Free Software
14 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
15
16 import zipfile
17 import logging
18 from gettext import gettext as _
19 from gi.repository import GObject
20 from gi.repository import Gtk
21
22 from sugar3.graphics.alert import Alert
23
24 from imageview import ImageViewer, pixbuf_from_data
25
26 IMAGE_ENDINGS = ('.png', '.jpg', '.jpeg', '.gif', '.bmp', '.tiff', '.tif')
27
28
29 class ComicViewer(GObject.GObject):
30
31 __gsignals__ = {
32 'zoom-changed': (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE,
33 ([int])),
34 'page-changed': (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE,
35 ([int, int]))
36 }
37
38 def setup(self, activity):
39 self._activity = activity
40 self._zip = None
41 self._images = []
42 self._index = 0
43 self._rotate = 0
44 self._old_zoom = 1.0
45
46 self._sw = Gtk.ScrolledWindow()
47 self._sw.set_policy(Gtk.PolicyType.ALWAYS, Gtk.PolicyType.ALWAYS)
48 self._activity._hbox.pack_start(self._sw, True, True, 0)
49 self._sw.show()
50
51 self._view = ImageViewer()
52 self._view.set_zoom(1.0)
53 self._view.connect('setup-new-surface', self.__new_surface_cb)
54 self._sw.add(self._view)
55 self._view.show()
56
57 def load_document(self, file_path):
58 try:
59 self._zip = zipfile.ZipFile(file_path.replace('file://', ''))
60 except zipfile.BadZipfile, IOError:
61 pass
62
63 files = self._zip.namelist()
64 files.sort()
65 self._images = [i for i in files if i.endswith(IMAGE_ENDINGS)]
66
67 if len(self._images) == 0:
68 alert = Alert()
69 alert.props.title = _('Can not read Comic Book Archive')
70 alert.props.msg = _('No readable images were found')
71 self._activity.add_alert(alert)
72 return
73
74 self.set_current_page(0)
75
76 def load_metadata(self, activity):
77 if activity.metadata.get('view-zoom'):
78 self.set_zoom(activity.metadata.get('view-zoom'))
79
80 def update_metadata(self, activity):
81 activity.metadata['view-zoom'] = self.get_zoom()
82
83 def get_current_page(self):
84 return self._index
85
86 def set_current_page(self, page):
87 if len(self._images) == 0:
88 return
89
90 from_ = self._index
91 self._index = page
92
93 filename = self._images[page]
94 data = self._zip.read(filename)
95 self._view.set_data(data)
96
97 self.emit('page-changed', from_, self._index)
98
99 def __new_surface_cb(self, view):
100 self._view.set_rotate(self._rotate)
101 self._view.update_adjustments()
102
103 self._sw.get_hadjustment().set_value(0)
104 self._sw.get_vadjustment().set_value(0)
105
106 self._view.update_adjustments()
107 self._view.queue_draw()
108
109 def next_page(self):
110 if self._index + 1 < self.get_pagecount():
111 self.set_current_page(self._index + 1)
112
113 def previous_page(self):
114 if self._index - 1 >= 0:
115 self.set_current_page(self._index - 1)
116
117 def can_rotate(self):
118 return True
119
120 def rotate_left(self):
121 self._view.rotate_anticlockwise()
122 self._rotate -= 1
123 if self._rotate == -4:
124 self._rotate = 0
125
126 def rotate_right(self):
127 self._view.rotate_clockwise()
128 self._rotate += 1
129 if self._rotate == 4:
130 self._rotate = 0
131
132 def get_pagecount(self):
133 return len(self._images)
134
135 def connect_zoom_handler(self, handler):
136 self.connect('zoom-changed', handler)
137
138 def _zoom_changed(self):
139 self.emit('zoom-changed', self.get_zoom())
140
141 def get_zoom(self):
142 return self._view.get_zoom()
143
144 def set_zoom(self, value):
145 self._view.set_zoom(value)
146 self._zoom_changed()
147
148 def zoom_in(self):
149 self._view.zoom_in()
150 self._zoom_changed()
151
152 def can_zoom_in(self):
153 return self._view.can_zoom_in()
154
155 def zoom_out(self):
156 self._view.zoom_out()
157 self._zoom_changed()
158
159 def can_zoom_out(self):
160 return self._view.can_zoom_out()
161
162 def can_zoom_to_width(self):
163 return True
164
165 def zoom_to_width(self):
166 self._view.zoom_to_width()
167 self._zoom_changed()
168
169 def zoom_to_best_fit(self):
170 self._view.zoom_to_fit()
171 self._zoom_changed()
172
173 def can_zoom_to_actual_size(self):
174 return True
175
176 def zoom_to_actual_size(self):
177 self._view.zoom_original()
178 self._zoom_changed()
179
180 def connect_page_changed_handler(self, handler):
181 self.connect('page-changed', handler)
182
183 def scroll(self, scrolltype, horizontal):
184 if scrolltype == Gtk.ScrollType.PAGE_BACKWARD:
185 self.previous_page()
186 elif scrolltype == Gtk.ScrollType.PAGE_FORWARD:
187 self.next_page()
188 elif scrolltype == Gtk.ScrollType.STEP_BACKWARD:
189 self._scroll_step(False, horizontal)
190 elif scrolltype == Gtk.ScrollType.STEP_FORWARD:
191 self._scroll_step(True, horizontal)
192 elif scrolltype == Gtk.ScrollType.START:
193 self.set_current_page(1)
194 elif scrolltype == Gtk.ScrollType.END:
195 self.set_current_page(self._document.get_n_pages())
196 else:
197 pass
198
199 def _scroll_step(self, forward, horizontal):
200 if horizontal:
201 adj = self._sw.get_hadjustment()
202 else:
203 adj = self._sw.get_vadjustment()
204
205 value = adj.get_value()
206 step = adj.get_step_increment()
207
208 if forward:
209 adj.set_value(value + step)
210 else:
211 adj.set_value(value - step)
212
213 # Not relevant for non-text documents
214
215 def can_highlight(self):
216 return False
217
218 def can_do_text_to_speech(self):
219 return False
220
221 def find_set_highlight_search(self, set_highlight_search):
222 pass
223
224 def find_next(self):
225 pass
226
227 def find_previous(self):
228 pass
229
230 def update_toc(self, activity):
231 pass
232
233 def handle_link(self, link):
234 pass
235
236 def get_current_link(self):
237 return ''
238
239 def get_link_iter(self, link):
240 return None
241
242 def copy(self):
243 # Copy is for the selected text
244 pass
0 # Copyright (C) 2008, One Laptop per Child
1 # Author: Sayamindu Dasgupta <sayamindu@laptop.org>
2 #
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 #
17 # From ImageViewer Activity - file ImageView.py
18
19 import logging
20 import cairo
21 import math
22
23 from gi.repository import Gtk
24 from gi.repository import Gdk
25 from gi.repository import GdkPixbuf
26 from gi.repository import GObject
27 from gi.repository import Gio
28
29 ZOOM_STEP = 0.05
30 ZOOM_MAX = 10
31 ZOOM_MIN = 0.05
32
33
34 def pixbuf_from_data(data):
35 stream = Gio.MemoryInputStream.new_from_data(data, None)
36 pixbuf = GdkPixbuf.Pixbuf.new_from_stream(stream, None)
37 return pixbuf
38
39
40 def _surface_from_data(data, ctx):
41 pixbuf = pixbuf_from_data(data)
42 surface = ctx.get_target().create_similar(
43 cairo.CONTENT_COLOR_ALPHA, pixbuf.get_width(),
44 pixbuf.get_height())
45
46 ctx_surface = cairo.Context(surface)
47 Gdk.cairo_set_source_pixbuf(ctx_surface, pixbuf, 0, 0)
48 ctx_surface.paint()
49 return surface
50
51
52 def _rotate_surface(surface, direction):
53 ctx = cairo.Context(surface)
54 new_surface = ctx.get_target().create_similar(
55 cairo.CONTENT_COLOR_ALPHA, surface.get_height(),
56 surface.get_width())
57
58 ctx_surface = cairo.Context(new_surface)
59
60 if direction == 1:
61 ctx_surface.translate(surface.get_height(), 0)
62 else:
63 ctx_surface.translate(0, surface.get_width())
64
65 ctx_surface.rotate(math.pi / 2 * direction)
66
67 ctx_surface.set_source_surface(surface, 0, 0)
68 ctx_surface.paint()
69
70 return new_surface
71
72
73 def _flip_surface(surface):
74 ctx = cairo.Context(surface)
75 new_surface = ctx.get_target().create_similar(
76 cairo.CONTENT_COLOR_ALPHA, surface.get_width(),
77 surface.get_height())
78
79 ctx_surface = cairo.Context(new_surface)
80 ctx_surface.rotate(math.pi)
81 ctx_surface.translate(-surface.get_width(), -surface.get_height())
82
83 ctx_surface.set_source_surface(surface, 0, 0)
84 ctx_surface.paint()
85
86 return new_surface
87
88
89 class ImageViewer(Gtk.DrawingArea, Gtk.Scrollable):
90 __gtype_name__ = 'ImageViewer'
91
92 __gproperties__ = {
93 "hscroll-policy": (Gtk.ScrollablePolicy, "hscroll-policy",
94 "hscroll-policy", Gtk.ScrollablePolicy.MINIMUM,
95 GObject.PARAM_READWRITE),
96 "hadjustment": (Gtk.Adjustment, "hadjustment", "hadjustment",
97 GObject.PARAM_READWRITE),
98 "vscroll-policy": (Gtk.ScrollablePolicy, "hscroll-policy",
99 "hscroll-policy", Gtk.ScrollablePolicy.MINIMUM,
100 GObject.PARAM_READWRITE),
101 "vadjustment": (Gtk.Adjustment, "hadjustment", "hadjustment",
102 GObject.PARAM_READWRITE),
103 }
104
105 __gsignals__ = {
106 'setup-new-surface': (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE,
107 ([])),
108 }
109
110 def __init__(self):
111 Gtk.DrawingArea.__init__(self)
112
113 self._data = None
114 self._data_changed = False
115 self._surface = None
116 self._zoom = None
117 self._target_point = None
118 self._anchor_point = None
119
120 self._in_dragtouch = False
121 self._in_zoomtouch = False
122 self._zoomtouch_scale = 1
123
124 self._in_scrolling = False
125 self._scrolling_hid = None
126 self._hadj = None
127 self._vadj = None
128 self._hadj_value_changed_hid = None
129 self._vadj_value_changed_hid = None
130
131 self.connect('draw', self.__draw_cb)
132
133 def set_data(self, data):
134 self._data = data
135 self._data_changed = True
136 self.queue_draw()
137
138 def do_get_property(self, prop):
139 # We don't use the getter but GTK wants it defined as we are
140 # implementing Gtk.Scrollable interface.
141 pass
142
143 def do_set_property(self, prop, value):
144 # The scrolled window will give us the adjustments. Make a
145 # reference to them and also connect to their value-changed
146 # signal.
147 if prop.name == 'hadjustment':
148 if value is not None:
149 hadj = value
150 self._hadj_value_changed_hid = \
151 hadj.connect('value-changed', self.__hadj_value_changed_cb)
152 self._hadj = hadj
153
154 elif prop.name == 'vadjustment':
155 if value is not None:
156 vadj = value
157 self._vadj_value_changed_hid = \
158 vadj.connect('value-changed', self.__vadj_value_changed_cb)
159 self._vadj = vadj
160
161 def update_adjustments(self):
162 alloc = self.get_allocation()
163 scaled_width = self._surface.get_width() * self._zoom
164 scaled_height = self._surface.get_height() * self._zoom
165
166 page_size_x = alloc.width * 1.0 / scaled_width
167 self._hadj.set_lower(0)
168 self._hadj.set_page_size(page_size_x)
169 self._hadj.set_upper(1.0)
170 self._hadj.set_step_increment(0.1)
171 self._hadj.set_page_increment(0.5)
172
173 page_size_y = alloc.height * 1.0 / scaled_height
174 self._vadj.set_lower(0)
175 self._vadj.set_page_size(page_size_y)
176 self._vadj.set_upper(1.0)
177 self._vadj.set_step_increment(0.1)
178 self._vadj.set_page_increment(0.5)
179
180 anchor_scaled = (self._anchor_point[0] * self._zoom,
181 self._anchor_point[1] * self._zoom)
182
183 # This vector is the top left coordinate of the scaled image.
184 scaled_image_topleft = (self._target_point[0] - anchor_scaled[0],
185 self._target_point[1] - anchor_scaled[1])
186
187 max_topleft = (scaled_width - alloc.width,
188 scaled_height - alloc.height)
189
190 max_value = (1.0 - page_size_x,
191 1.0 - page_size_y)
192
193 # This two linear functions map the topleft corner of the
194 # image to the value each adjustment.
195
196 if max_topleft[0] != 0:
197 self._hadj.disconnect(self._hadj_value_changed_hid)
198 self._hadj.set_value(-1 * max_value[0] *
199 scaled_image_topleft[0] / max_topleft[0])
200 self._hadj_value_changed_hid = \
201 self._hadj.connect('value-changed',
202 self.__hadj_value_changed_cb)
203
204 if max_topleft[1] != 0:
205 self._vadj.disconnect(self._vadj_value_changed_hid)
206 self._vadj.set_value(-1 * max_value[1] *
207 scaled_image_topleft[1] / max_topleft[1])
208 self._vadj_value_changed_hid = \
209 self._vadj.connect('value-changed',
210 self.__vadj_value_changed_cb)
211
212 def _stop_scrolling(self):
213 self._in_scrolling = False
214 self.queue_draw()
215 return False
216
217 def _start_scrolling(self):
218 if not self._in_scrolling:
219 self._in_scrolling = True
220
221 # Add or update a timer after which the in_scrolling flag will
222 # be set to False. This is to perform a faster drawing while
223 # scrolling.
224 if self._scrolling_hid is not None:
225 GObject.source_remove(self._scrolling_hid)
226 self._scrolling_hid = GObject.timeout_add(200,
227 self._stop_scrolling)
228
229 def __hadj_value_changed_cb(self, adj):
230 alloc = self.get_allocation()
231 scaled_width = self._surface.get_width() * self._zoom
232 anchor_scaled_x = self._anchor_point[0] * self._zoom
233 scaled_image_left = self._target_point[0] - anchor_scaled_x
234
235 max_left = scaled_width - alloc.width
236 max_value = 1.0 - adj.get_page_size()
237 new_left = -1 * max_left * adj.get_value() / max_value
238
239 delta_x = scaled_image_left - new_left
240 self._anchor_point = (self._anchor_point[0] + delta_x,
241 self._anchor_point[1])
242
243 self._start_scrolling()
244 self.queue_draw()
245
246 def __vadj_value_changed_cb(self, adj):
247 alloc = self.get_allocation()
248 scaled_height = self._surface.get_height() * self._zoom
249 anchor_scaled_y = self._anchor_point[1] * self._zoom
250 scaled_image_top = self._target_point[1] - anchor_scaled_y
251
252 max_top = scaled_height - alloc.height
253 max_value = 1.0 - adj.get_page_size()
254 new_top = -1 * max_top * adj.get_value() / max_value
255
256 delta_y = scaled_image_top - new_top
257 self._anchor_point = (self._anchor_point[0],
258 self._anchor_point[1] + delta_y)
259
260 self._start_scrolling()
261 self.queue_draw()
262
263 def _center_target_point(self):
264 alloc = self.get_allocation()
265 self._target_point = (alloc.width / 2, alloc.height / 2)
266
267 def _center_anchor_point(self):
268 self._anchor_point = (self._surface.get_width() / 2,
269 self._surface.get_height() / 2)
270
271 def _center_if_small(self):
272 # If at the current size the image surface is smaller than the
273 # available space, center it on the canvas.
274
275 alloc = self.get_allocation()
276
277 scaled_width = self._surface.get_width() * self._zoom
278 scaled_height = self._surface.get_height() * self._zoom
279
280 if alloc.width >= scaled_width and alloc.height >= scaled_height:
281 self._center_target_point()
282 self._center_anchor_point()
283 self.queue_draw()
284
285 def set_zoom(self, zoom):
286 if zoom < ZOOM_MIN or zoom > ZOOM_MAX:
287 return
288 self._zoom = zoom
289 self.queue_draw()
290
291 def get_zoom(self):
292 return self._zoom
293
294 def can_zoom_in(self):
295 return self._zoom + ZOOM_STEP < ZOOM_MAX
296 self.update_adjustments()
297
298 def can_zoom_out(self):
299 return self._zoom - ZOOM_STEP > ZOOM_MIN
300 self.update_adjustments()
301
302 def zoom_in(self):
303 if not self.can_zoom_in():
304 return
305 self._zoom += ZOOM_STEP
306 self.update_adjustments()
307 self.queue_draw()
308
309 def zoom_out(self):
310 if not self.can_zoom_out():
311 return
312 self._zoom -= ZOOM_MIN
313
314 self._center_if_small()
315 self.update_adjustments()
316 self.queue_draw()
317
318 def zoom_to_fit(self):
319 # This tries to figure out a best fit model
320 # We show it in a fit to screen way
321
322 alloc = self.get_allocation()
323
324 surface_width = self._surface.get_width()
325 surface_height = self._surface.get_height()
326
327 self._zoom = min(alloc.width * 1.0 / surface_width,
328 alloc.height * 1.0 / surface_height)
329
330 self._center_target_point()
331 self._center_anchor_point()
332 self.update_adjustments()
333 self.queue_draw()
334
335 def zoom_to_width(self):
336 alloc = self.get_allocation()
337 surface_width = self._surface.get_width()
338 self._zoom = alloc.width * 1.0 / surface_width
339
340 self._center_target_point()
341 self._center_anchor_point()
342 self.update_adjustments()
343 self.queue_draw()
344
345 def zoom_original(self):
346 self._zoom = 1
347 self._center_if_small()
348 self.update_adjustments()
349 self.queue_draw()
350
351 def _move_anchor_to_target(self, prev_target_point):
352 # Calculate the new anchor point, move it from the previous
353 # target to the new one.
354
355 prev_anchor_scaled = (self._anchor_point[0] * self._zoom,
356 self._anchor_point[1] * self._zoom)
357
358 # This vector is the top left coordinate of the scaled image.
359 scaled_image_topleft = (prev_target_point[0] - prev_anchor_scaled[0],
360 prev_target_point[1] - prev_anchor_scaled[1])
361
362 anchor_scaled = (self._target_point[0] - scaled_image_topleft[0],
363 self._target_point[1] - scaled_image_topleft[1])
364
365 self._anchor_point = (int(anchor_scaled[0] * 1.0 / self._zoom),
366 int(anchor_scaled[1] * 1.0 / self._zoom))
367
368 def start_dragtouch(self, coords):
369 self._in_dragtouch = True
370
371 prev_target_point = self._target_point
372
373 # Set target point to the relative coordinates of this view.
374 alloc = self.get_allocation()
375 self._target_point = (coords[1], coords[2])
376
377 self._move_anchor_to_target(prev_target_point)
378 self.queue_draw()
379
380 def update_dragtouch(self, coords):
381 # Drag touch will be replaced by zoom touch if another finger
382 # is placed over the display. When the user finishes zoom
383 # touch, it will probably remove one finger after the other,
384 # and this method will be called. In that probable case, we
385 # need to start drag touch again.
386 if not self._in_dragtouch:
387 self.start_dragtouch(coords)
388 return
389
390 self._target_point = (coords[1], coords[2])
391 self.update_adjustments()
392 self.queue_draw()
393
394 def finish_dragtouch(self, coords):
395 self._in_dragtouch = False
396 self._center_if_small()
397 self.update_adjustments()
398
399 def start_zoomtouch(self, center):
400 self._in_zoomtouch = True
401 self._zoomtouch_scale = 1
402
403 # Zoom touch replaces drag touch.
404 self._in_dragtouch = False
405
406 prev_target_point = self._target_point
407
408 # Set target point to the relative coordinates of this view.
409 alloc = self.get_allocation()
410 self._target_point = (center[1] - alloc.x, center[2] - alloc.y)
411
412 self._move_anchor_to_target(prev_target_point)
413 self.queue_draw()
414
415 def update_zoomtouch(self, center, scale):
416 self._zoomtouch_scale = scale
417
418 # Set target point to the relative coordinates of this view.
419 alloc = self.get_allocation()
420 self._target_point = (center[1] - alloc.x, center[2] - alloc.y)
421
422 self.queue_draw()
423
424 def finish_zoomtouch(self):
425 self._in_zoomtouch = False
426
427 # Apply zoom
428 self._zoom = self._zoom * self._zoomtouch_scale
429 self._zoomtouch_scale = 1
430
431 # Restrict zoom values
432 if self._zoom < ZOOM_MIN:
433 self._zoom = ZOOM_MIN
434 elif self._zoom > ZOOM_MAX:
435 self._zoom = ZOOM_MAX
436
437 self._center_if_small()
438 self.update_adjustments()
439 self.queue_draw()
440
441 def set_rotate(self, rotate):
442 if rotate == 0:
443 return
444 elif rotate in [1, -3]:
445 self._surface = _rotate_surface(self._surface, 1)
446 elif rotate in [-1, 3]:
447 self._surface = _rotate_surface(self._surface, -1)
448 else:
449 self._surface = _flip_surface(self._surface)
450
451 if rotate > 0:
452 for i in range(rotate):
453 self._anchor_point = (
454 self._surface.get_width() - self._anchor_point[1],
455 self._anchor_point[0])
456
457 if rotate < 0:
458 for i in range(-rotate):
459 self._anchor_point = (
460 self._anchor_point[1],
461 self._surface.get_height() - self._anchor_point[0])
462
463 self.update_adjustments()
464 self.queue_draw()
465
466 def rotate_anticlockwise(self):
467 self._surface = _rotate_surface(self._surface, -1)
468
469 # Recalculate the anchor point to make it relative to the new
470 # top left corner.
471 self._anchor_point = (
472 self._anchor_point[1],
473 self._surface.get_height() - self._anchor_point[0])
474
475 self.update_adjustments()
476 self.queue_draw()
477
478 def rotate_clockwise(self):
479 self._surface = _rotate_surface(self._surface, 1)
480
481 # Recalculate the anchor point to make it relative to the new
482 # top left corner.
483 self._anchor_point = (
484 self._surface.get_width() - self._anchor_point[1],
485 self._anchor_point[0])
486
487 self.update_adjustments()
488 self.queue_draw()
489
490 def __draw_cb(self, widget, ctx):
491
492 # If the image surface is not set, it reads it from the data If the
493 # data is not set yet, it just returns.
494 if self._surface is None or self._data_changed:
495 if self._data is None:
496 return
497 self._surface = _surface_from_data(self._data, ctx)
498 self._data_changed = False
499 self.emit('setup-new-surface')
500
501 if self._zoom is None:
502 self.zoom_to_width()
503
504 # If no target point was set via pinch-to-zoom, default to the
505 # center of the screen.
506 if self._target_point is None:
507 self._center_target_point()
508
509 # If no anchor point was set via pinch-to-zoom, default to the
510 # center of the surface.
511 if self._anchor_point is None:
512 self._center_anchor_point()
513 self.update_adjustments()
514
515 ctx.translate(*self._target_point)
516 zoom_absolute = self._zoom * self._zoomtouch_scale
517 ctx.scale(zoom_absolute, zoom_absolute)
518
519 ctx.translate(self._anchor_point[0] * -1, self._anchor_point[1] * -1)
520
521 ctx.set_source_surface(self._surface, 0, 0)
522
523 # Perform faster draw if the view is zooming or scrolling via
524 # mouse or touch.
525 if self._in_zoomtouch or self._in_dragtouch or self._in_scrolling:
526 ctx.get_source().set_filter(cairo.FILTER_NEAREST)
527
528 ctx.paint()
940940 elif mimetype == 'text/plain' or mimetype == 'application/zip':
941941 import textadapter
942942 self._view = textadapter.TextViewer()
943 elif mimetype == 'application/x-cbz':
944 import comicadapter
945 self._view = comicadapter.ComicViewer()
943946 else:
944947 import evinceadapter
945948 self._view = evinceadapter.EvinceViewer()