def scroll_smartly(self, max_scroll, backwards, axis_map, index=None): """ Applies a "smart scrolling" step to the current viewport position. If there are not enough Boxes to scroll to, the viewport is not moved and an appropriate value is returned. @param max_scroll: The maximum numbers of pixels to scroll in one step. @param backwards: True for backwards scrolling, False otherwise. @param axis_map: The index of the dimension to modify. @param index: The index of the Box the scrolling step is related to, or None to use the index of the current Box. @return: The index of the current Box after scrolling, or -1 if there were not enough Boxes to scroll backwards, or the number of Boxes if there were not enough Boxes to scroll forwards. """ # TODO reconsider interface if (index == None) or (not self.wrap_individually): index = self.get_current_index() if not self.wrap_individually: wrapper_index = 0 else: wrapper_index = index o = tools.vector_opposite(self.orientation) if backwards \ else self.orientation new_pos = self.scroller.scroll_smartly(self.wrapper_boxes[wrapper_index], self.viewport_box, o, max_scroll, axis_map) if new_pos == []: if self.wrap_individually: index += -1 if backwards else 1 n = len(self.get_content_boxes()) if (index < n) and (index >= 0): self.scroll_to_predefined(tools.vector_opposite(o), index) return index else: index = -1 if backwards else len(self.get_content_boxes()) return index self.set_viewport_position(new_pos) return index
def _draw_image(self, scroll_to): self._update_toggles_visibility() self.osd.clear() if not self.filehandler.file_loaded: self._clear_main_area() self._waiting_for_redraw = False return False if self.imagehandler.page_is_available(): distribution_axis = constants.DISTRIBUTION_AXIS alignment_axis = constants.ALIGNMENT_AXIS pixbuf_count = 2 if self.displayed_double( ) else 1 # XXX limited to at most 2 pages pixbuf_list = list(self.imagehandler.get_pixbufs(pixbuf_count)) do_not_transform = [ image_tools.disable_transform(x) for x in pixbuf_list ] size_list = [[pixbuf.get_width(), pixbuf.get_height()] for pixbuf in pixbuf_list] if self.is_manga_mode: orientation = constants.MANGA_ORIENTATION else: orientation = constants.WESTERN_ORIENTATION # Rotation handling: # - apply Exif rotation on individual images # - apply automatic rotation (size based) on whole page # - apply manual rotation on whole page if prefs['auto rotate from exif']: rotation_list = [ image_tools.get_implied_rotation(pixbuf) for pixbuf in pixbuf_list ] else: rotation_list = [0] * len(pixbuf_list) virtual_size = [0, 0] for i in range(pixbuf_count): if rotation_list[i] in (90, 270): size_list[i].reverse() size = size_list[i] virtual_size[distribution_axis] += size[distribution_axis] virtual_size[alignment_axis] = max( virtual_size[alignment_axis], size[alignment_axis]) rotation = self._get_size_rotation(*virtual_size) rotation = (rotation + prefs['rotation']) % 360 if rotation in (90, 270): distribution_axis, alignment_axis = alignment_axis, distribution_axis orientation = list(orientation) orientation.reverse() for i in range(pixbuf_count): size_list[i].reverse() if rotation in (180, 270): orientation = tools.vector_opposite(orientation) for i in range(pixbuf_count): rotation_list[i] = (rotation_list[i] + rotation) % 360 if prefs['vertical flip'] and rotation in (90, 270): orientation = tools.vector_opposite(orientation) if prefs['horizontal flip'] and rotation in (0, 180): orientation = tools.vector_opposite(orientation) viewport_size = () # dummy expand_area = False scrollbar_requests = [False] * len(self._scroll) # Visible area size is recomputed depending on scrollbar visibility while True: self._show_scrollbars(scrollbar_requests) new_viewport_size = self.get_visible_area_size() if new_viewport_size == viewport_size: break viewport_size = new_viewport_size zoom_dummy_size = list(viewport_size) dasize = zoom_dummy_size[distribution_axis] - \ self._spacing * (pixbuf_count - 1) if dasize <= 0: dasize = 1 zoom_dummy_size[distribution_axis] = dasize scaled_sizes = self.zoom.get_zoomed_size( size_list, zoom_dummy_size, distribution_axis, do_not_transform) self.layout = layout.FiniteLayout(scaled_sizes, viewport_size, orientation, self._spacing, expand_area, distribution_axis, alignment_axis) union_scaled_size = self.layout.get_union_box().get_size() scrollbar_requests = [(old or new) for old, new in zip( scrollbar_requests, tools.smaller(viewport_size, union_scaled_size))] if len(tuple(filter( None, scrollbar_requests))) > 1 and not expand_area: expand_area = True viewport_size = () # start anew for i in range(pixbuf_count): pixbuf_list[i] = image_tools.fit_pixbuf_to_rectangle( pixbuf_list[i], scaled_sizes[i], rotation_list[i]) for i in range(pixbuf_count): pixbuf_list[i] = image_tools.trans_pixbuf( pixbuf_list[i], flip=prefs['vertical flip'], flop=prefs['horizontal flip']) pixbuf_list[i] = self.enhancer.enhance(pixbuf_list[i]) for i in range(pixbuf_count): image_tools.set_from_pixbuf(self.images[i], pixbuf_list[i]) resolutions = [ (*size, scaled_size[0] / size[0]) for scaled_size, size in zip(scaled_sizes, size_list) ] if self.is_manga_mode: resolutions.reverse() self.statusbar.set_resolution(resolutions) self.statusbar.update() smartbg = prefs['smart bg'] smartthumbbg = prefs['show thumbnails'] and prefs['smart thumb bg'] if smartbg or smartthumbbg: bg_color = self.imagehandler.get_pixbuf_auto_background( pixbuf_count) if smartbg: self.set_bg_color(bg_color) if smartthumbbg: self.thumbnailsidebar.change_thumbnail_background_color( bg_color) self._main_layout.get_bin_window().freeze_updates() self._main_layout.set_size(*union_scaled_size) content_boxes = self.layout.get_content_boxes() for i in range(pixbuf_count): self._main_layout.move(self.images[i], *content_boxes[i].get_position()) for i in range(pixbuf_count): self.images[i].show() for i in range(pixbuf_count, len(self.images)): self.images[i].hide() # Reset orientation so scrolling behaviour is sane. if self.is_manga_mode: self.layout.set_orientation(constants.MANGA_ORIENTATION) else: self.layout.set_orientation(constants.WESTERN_ORIENTATION) if scroll_to is not None: destination = (scroll_to, ) * 2 if constants.SCROLL_TO_START == scroll_to: index = constants.FIRST_INDEX elif constants.SCROLL_TO_END == scroll_to: index = constants.LAST_INDEX else: index = None self.scroll_to_predefined(destination, index) self._main_layout.get_bin_window().thaw_updates() else: # Save scroll destination for when the page becomes available. self._last_scroll_destination = scroll_to # If the pixbuf for the current page(s) isn't available, # hide all images to clear any old pixbufs. # XXX How about calling self._clear_main_area? for i in range(len(self.images)): self.images[i].hide() self._show_scrollbars([False] * len(self._scroll)) self._waiting_for_redraw = False return False
def _draw_image(self, scroll_to): self._update_toggles_visibility() if not self.filehandler.file_loaded: self._clear_main_area() self._waiting_for_redraw = False return False if self.imagehandler.page_is_available(): distribution_axis = constants.DISTRIBUTION_AXIS alignment_axis = constants.ALIGNMENT_AXIS pixbuf_count = 2 if self.displayed_double() else 1 # XXX limited to at most 2 pages pixbuf_list = list(self.imagehandler.get_pixbufs(pixbuf_count)) size_list = [[pixbuf.get_width(), pixbuf.get_height()] for pixbuf in pixbuf_list] if self.is_manga_mode: orientation = constants.MANGA_ORIENTATION else: orientation = constants.WESTERN_ORIENTATION # Rotation handling: # - apply Exif rotation on individual images # - apply automatic rotation (size based) on whole page # - apply manual rotation on whole page if prefs['auto rotate from exif']: rotation_list = [image_tools.get_implied_rotation(pixbuf) for pixbuf in pixbuf_list] else: rotation_list = [0] * len(pixbuf_list) virtual_size = [0, 0] for i in range(pixbuf_count): if rotation_list[i] in (90, 270): size_list[i].reverse() size = size_list[i] virtual_size[distribution_axis] += size[distribution_axis] virtual_size[alignment_axis] = max(virtual_size[alignment_axis], size[alignment_axis]) rotation = self._get_size_rotation(*virtual_size) rotation = (rotation + prefs['rotation']) % 360 if rotation in (90, 270): distribution_axis, alignment_axis = alignment_axis, distribution_axis orientation = list(orientation) orientation.reverse() for i in range(pixbuf_count): size_list[i].reverse() if rotation in (180, 270): orientation = tools.vector_opposite(orientation) for i in range(pixbuf_count): rotation_list[i] = (rotation_list[i] + rotation) % 360 if prefs['vertical flip'] and rotation in (90, 270): orientation = tools.vector_opposite(orientation) if prefs['horizontal flip'] and rotation in (0, 180): orientation = tools.vector_opposite(orientation) viewport_size = () # dummy expand_area = False scrollbar_requests = [False] * len(self._scroll) # Visible area size is recomputed depending on scrollbar visibility while True: self._show_scrollbars(scrollbar_requests) new_viewport_size = self.get_visible_area_size() if new_viewport_size == viewport_size: break viewport_size = new_viewport_size zoom_dummy_size = list(viewport_size) dasize = zoom_dummy_size[distribution_axis] - \ self._spacing * (pixbuf_count - 1) if dasize <= 0: dasize = 1 zoom_dummy_size[distribution_axis] = dasize scaled_sizes = self.zoom.get_zoomed_size(size_list, zoom_dummy_size, distribution_axis) self.layout = layout.FiniteLayout(scaled_sizes, viewport_size, orientation, self._spacing, expand_area, distribution_axis, alignment_axis) union_scaled_size = self.layout.get_union_box().get_size() scrollbar_requests = map(operator.or_, scrollbar_requests, tools.smaller(viewport_size, union_scaled_size)) if len(filter(None, scrollbar_requests)) > 1 and not expand_area: expand_area = True viewport_size = () # start anew for i in range(pixbuf_count): pixbuf_list[i] = image_tools.fit_pixbuf_to_rectangle( pixbuf_list[i], scaled_sizes[i], rotation_list[i]) for i in range(pixbuf_count): if prefs['horizontal flip']: pixbuf_list[i] = pixbuf_list[i].flip(horizontal=True) if prefs['vertical flip']: pixbuf_list[i] = pixbuf_list[i].flip(horizontal=False) pixbuf_list[i] = self.enhancer.enhance(pixbuf_list[i]) for i in range(pixbuf_count): image_tools.set_from_pixbuf(self.images[i], pixbuf_list[i]) scales = tuple(map(lambda x, y: math.sqrt(tools.div( tools.volume(x), tools.volume(y))), scaled_sizes, size_list)) resolutions = tuple(map(lambda x, y: x + [y,], size_list, scales)) if self.is_manga_mode: resolutions = tuple(reversed(resolutions)) self.statusbar.set_resolution(resolutions) self.statusbar.update() smartbg = prefs['smart bg'] smartthumbbg = prefs['smart thumb bg'] and prefs['show thumbnails'] if smartbg or smartthumbbg: bg_colour = self.imagehandler.get_pixbuf_auto_background(pixbuf_count) if smartbg: self.set_bg_colour(bg_colour) if smartthumbbg: self.thumbnailsidebar.change_thumbnail_background_color(bg_colour) self._main_layout.window.freeze_updates() self._main_layout.set_size(*union_scaled_size) content_boxes = self.layout.get_content_boxes() for i in range(pixbuf_count): self._main_layout.move(self.images[i], *content_boxes[i].get_position()) for i in range(pixbuf_count): self.images[i].show() for i in range(pixbuf_count, len(self.images)): self.images[i].hide() # Reset orientation so scrolling behaviour is sane. if self.is_manga_mode: self.layout.set_orientation(constants.MANGA_ORIENTATION) else: self.layout.set_orientation(constants.WESTERN_ORIENTATION) if scroll_to is not None: destination = (scroll_to,) * 2 if constants.SCROLL_TO_START == scroll_to: index = constants.FIRST_INDEX elif constants.SCROLL_TO_END == scroll_to: index = constants.LAST_INDEX else: index = None self.scroll_to_predefined(destination, index) self._main_layout.window.thaw_updates() else: # Save scroll destination for when the page becomes available. self._last_scroll_destination = scroll_to # If the pixbuf for the current page(s) isn't available, # hide all images to clear any old pixbufs. # XXX How about calling self._clear_main_area? for i in range(len(self.images)): self.images[i].hide() self._show_scrollbars([False] * len(self._scroll)) self._waiting_for_redraw = False return False