def _draw_image(self, at_bottom, scroll): self._display_active_widgets() if not self.filehandler.file_loaded: self._waiting_for_redraw = False return False self.is_virtual_double_page = self.imagehandler.get_virtual_double_page() if self.imagehandler.page_is_available(): distribution_axis = constants.DISTRIBUTION_AXIS alignment_axis = constants.ALIGNMENT_AXIS n = 2 if self.displayed_double() else 1 # XXX limited to at most 2 pages pixbufs = list(self.imagehandler.get_pixbufs(n)) rotations = [self._get_pixbuf_rotation(x, True) for x in pixbufs] sizes = map(lambda y: tuple(reversed(y[1])) \ if rotations[y[0]] in (90, 270) else y[1], # 2D only enumerate([(x.get_width(), x.get_height()) for x in pixbufs])) 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 * (n - 1) if dasize <= 0: dasize = 1 zoom_dummy_size[distribution_axis] = dasize scaled_sizes = self.zoom.get_zoomed_size(sizes, zoom_dummy_size, distribution_axis) self.layout = scrolling.FiniteLayout(scaled_sizes, viewport_size, scrolling.MANGA_ORIENTATION if self.is_manga_mode else scrolling.WESTERN_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(n): pixbufs[i] = image_tools.fit_pixbuf_to_rectangle( pixbufs[i], scaled_sizes[i], rotations[i]) for i in range(n): if prefs['horizontal flip']: # 2D only pixbufs[i] = pixbufs[i].flip(horizontal=True) if prefs['vertical flip']: # 2D only pixbufs[i] = pixbufs[i].flip(horizontal=False) pixbufs[i] = self.enhancer.enhance(pixbufs[i]) for i in range(n): self.images[i].set_from_pixbuf(pixbufs[i]) scales = tuple(map(lambda x, y: math.sqrt(tools.div( tools.volume(x), tools.volume(y))), scaled_sizes, sizes)) resolutions = tuple(map(lambda x, y: x + (y,), sizes, scales)) if self.is_manga_mode: resolutions = tuple(reversed(resolutions)) self.statusbar.set_resolution(resolutions) 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(n) if smartbg: self.set_bg_colour(bg_colour) if smartthumbbg: self.thumbnailsidebar.change_thumbnail_background_color(bg_colour) #self._image_box.window.freeze_updates() # XXX replacement necessary? self._main_layout.set_size(*union_scaled_size) content_boxes = self.layout.get_content_boxes() for i in range(n): self._main_layout.move(self.images[i], *content_boxes[i].get_position()) for i in range(n): self.images[i].show() for i in range(n, len(self.images)): self.images[i].hide() if scroll: if at_bottom: self.scroll_to_fixed(horiz='endsecond', vert='bottom') else: self.scroll_to_fixed(horiz='startfirst', vert='top') #self._image_box.window.thaw_updates() # XXX replacement necessary? else: # 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._update_page_information() self._waiting_for_redraw = False return False
def _scale_distributed(sizes, axis, max_size, allow_upscaling, do_not_transform): ''' Calculates scales for a list of boxes that are distributed along a given axis (without any gaps). If the resulting scales are applied to their respective boxes, their new total size along axis will be as close as possible to max_size. The current implementation ensures that equal box sizes are mapped to equal scales. @param sizes: A list of box sizes. @param axis: The axis along which those boxes are distributed. @param max_size: The maximum size the scaled boxes may have along axis. @param allow_upscaling: True if upscaling is allowed, False otherwise. @param do_not_transform: True if the resulting scale must be 1, False otherwise. @return: A list of scales where the i-th scale belongs to the i-th box size. If sizes is empty, the empty list is returned. If there are more boxes than max_size, an approximation is returned where all resulting scales will shrink their respective boxes to 1 along axis. In this case, the scaled total size might be greater than max_size. ''' n = len(sizes) # trivial cases first if n == 0: return [] if n >= max_size: # In this case, only one solution or only an approximation is available. # if n > max_size, the result won't fit into max_size. return map(lambda x: tools.div(1, x[axis]), sizes) # FIXME ignores do_not_transform total_axis_size = sum(map(lambda x: x[axis], sizes)) if (total_axis_size <= max_size) and not allow_upscaling: # identity return [IDENTITY_ZOOM] * n # non-trival case scale = tools.div( max_size, total_axis_size ) # FIXME initial guess should take unscalable images into account scaling_data = [None] * n total_axis_size = 0 # This loop collects some data we need for the actual computations later. for i in range(n): this_size = sizes[i] # Shortcut: If the size cannot be changed, accept the original size. if do_not_transform[i]: total_axis_size += this_size[axis] scaling_data[i] = [ IDENTITY_ZOOM, IDENTITY_ZOOM, False, IDENTITY_ZOOM, 0.0 ] continue # Initial guess: The current scale works for all tuples. ideal = tools.scale(this_size, scale) ideal_vol = tools.volume(ideal) # Let's use a dummy to compute the actual (rounded) size along axis # so we can rescale the rounded tuple with a better local_scale # later. This rescaling is necessary to ensure that the sizes in ALL # dimensions are monotonically scaled (with respect to local_scale). # A nice side effect of this is that it keeps the aspect ratio better. dummy_approx = _round_nonempty((ideal[axis], ))[0] local_scale = tools.div(dummy_approx, this_size[axis]) total_axis_size += dummy_approx can_be_downscaled = dummy_approx > 1 if can_be_downscaled: forced_size = dummy_approx - 1 forced_scale = tools.div(forced_size, this_size[axis]) forced_approx = _scale_image_size(this_size, forced_scale) forced_vol_err = tools.relerr(tools.volume(forced_approx), ideal_vol) else: forced_scale = None forced_vol_err = None scaling_data[i] = [ local_scale, ideal, can_be_downscaled, forced_scale, forced_vol_err ] # Now we need to find at most total_axis_size - max_size occasions to # scale down some tuples so the whole thing would fit into max_size. If # we are lucky, there will be no gaps at the end (or at least fewer gaps # than we would have if we always rounded down). dirty = True # This flag prevents infinite loops if nothing can be made any smaller. while dirty and (total_axis_size > max_size): # This algorithm needs O(n*n) time. Let's hope that n is small enough. dirty = False current_index = 0 current_min = None for i in range(n): d = scaling_data[i] if not d[2]: # Ignore elements that cannot be made any smaller. continue if (current_min is None) or (d[4] < current_min[4]): # We are searching for the tuple where downscaling results # in the smallest relative volume error (compared to the # respective ideal volume). current_min = d current_index = i for i in range(current_index, n): # We must scale down ALL equal tuples. Otherwise, images that # are of equal size might appear to be of different size # afterwards. The downside of this approach is that it might # introduce more gaps than necessary. d = scaling_data[i] if (not d[2]) or (d[1] != current_min[1]): continue d[0] = d[3] d[2] = False # only once per tuple total_axis_size -= 1 dirty = True else: # If we are here and total_axis_size < max_size, we could try to # upscale some tuples similarily to the other loop (i.e. smallest # relative volume error first, equal boxes in conjunction with each # other). However, this is not as useful as the other loop, slightly # more complicated and it won't do anything if all tuples are equal. pass return map(lambda d: d[0], scaling_data)
def _scale_distributed(sizes, axis, max_size, allow_upscaling, do_not_transform): """ Calculates scales for a list of boxes that are distributed along a given axis (without any gaps). If the resulting scales are applied to their respective boxes, their new total size along axis will be as close as possible to max_size. The current implementation ensures that equal box sizes are mapped to equal scales. @param sizes: A list of box sizes. @param axis: The axis along which those boxes are distributed. @param max_size: The maximum size the scaled boxes may have along axis. @param allow_upscaling: True if upscaling is allowed, False otherwise. @param do_not_transform: True if the resulting scale must be 1, False otherwise. @return: A list of scales where the i-th scale belongs to the i-th box size. If sizes is empty, the empty list is returned. If there are more boxes than max_size, an approximation is returned where all resulting scales will shrink their respective boxes to 1 along axis. In this case, the scaled total size might be greater than max_size. """ n = len(sizes) # trivial cases first if n == 0: return [] if n >= max_size: # In this case, only one solution or only an approximation is available. # if n > max_size, the result won't fit into max_size. return map(lambda x: tools.div(1, x[axis]), sizes) # FIXME ignores do_not_transform total_axis_size = sum(map(lambda x: x[axis], sizes)) if (total_axis_size <= max_size) and not allow_upscaling: # identity return [IDENTITY_ZOOM] * n # non-trival case scale = tools.div(max_size, total_axis_size) # FIXME initial guess should take unscalable images into account scaling_data = [None] * n total_axis_size = 0 # This loop collects some data we need for the actual computations later. for i in range(n): this_size = sizes[i] # Shortcut: If the size cannot be changed, accept the original size. if do_not_transform[i]: total_axis_size += this_size[axis] scaling_data[i] = [IDENTITY_ZOOM, IDENTITY_ZOOM, False, IDENTITY_ZOOM, 0.0] continue # Initial guess: The current scale works for all tuples. ideal = tools.scale(this_size, scale) ideal_vol = tools.volume(ideal) # Let's use a dummy to compute the actual (rounded) size along axis # so we can rescale the rounded tuple with a better local_scale # later. This rescaling is necessary to ensure that the sizes in ALL # dimensions are monotonically scaled (with respect to local_scale). # A nice side effect of this is that it keeps the aspect ratio better. dummy_approx = _round_nonempty((ideal[axis],))[0] local_scale = tools.div(dummy_approx, this_size[axis]) total_axis_size += dummy_approx can_be_downscaled = dummy_approx > 1 if can_be_downscaled: forced_size = dummy_approx - 1 forced_scale = tools.div(forced_size, this_size[axis]) forced_approx = _scale_image_size(this_size, forced_scale) forced_vol_err = tools.relerr(tools.volume(forced_approx), ideal_vol) else: forced_scale = None forced_vol_err = None scaling_data[i] = [local_scale, ideal, can_be_downscaled, forced_scale, forced_vol_err] # Now we need to find at most total_axis_size - max_size occasions to # scale down some tuples so the whole thing would fit into max_size. If # we are lucky, there will be no gaps at the end (or at least fewer gaps # than we would have if we always rounded down). dirty=True # This flag prevents infinite loops if nothing can be made any smaller. while dirty and (total_axis_size > max_size): # This algorithm needs O(n*n) time. Let's hope that n is small enough. dirty=False current_index = 0 current_min = None for i in range(n): d = scaling_data[i] if not d[2]: # Ignore elements that cannot be made any smaller. continue if (current_min is None) or (d[4] < current_min[4]): # We are searching for the tuple where downscaling results # in the smallest relative volume error (compared to the # respective ideal volume). current_min = d current_index = i for i in range(current_index, n): # We must scale down ALL equal tuples. Otherwise, images that # are of equal size might appear to be of different size # afterwards. The downside of this approach is that it might # introduce more gaps than necessary. d = scaling_data[i] if (not d[2]) or (d[1] != current_min[1]): continue d[0] = d[3] d[2] = False # only once per tuple total_axis_size -= 1 dirty=True else: # If we are here and total_axis_size < max_size, we could try to # upscale some tuples similarly to the other loop (i.e. smallest # relative volume error first, equal boxes in conjunction with each # other). However, this is not as useful as the other loop, slightly # more complicated and it won't do anything if all tuples are equal. pass return map(lambda d: d[0], scaling_data)
def _draw_image(self, at_bottom, scroll): self._display_active_widgets() if not self.filehandler.file_loaded: self._waiting_for_redraw = False return False self.is_virtual_double_page = self.imagehandler.get_virtual_double_page( ) if self.imagehandler.page_is_available(): distribution_axis = constants.DISTRIBUTION_AXIS alignment_axis = constants.ALIGNMENT_AXIS n = 2 if self.displayed_double( ) else 1 # XXX limited to at most 2 pages pixbufs = list(self.imagehandler.get_pixbufs(n)) rotations = [self._get_pixbuf_rotation(x, True) for x in pixbufs] sizes = map(lambda y: tuple(reversed(y[1])) \ if rotations[y[0]] in (90, 270) else y[1], # 2D only enumerate([(x.get_width(), x.get_height()) for x in pixbufs])) 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 * (n - 1) if dasize <= 0: dasize = 1 zoom_dummy_size[distribution_axis] = dasize scaled_sizes = self.zoom.get_zoomed_size( sizes, zoom_dummy_size, distribution_axis) self.layout = layout.FiniteLayout( scaled_sizes, viewport_size, constants.MANGA_ORIENTATION if self.is_manga_mode else constants.WESTERN_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(n): pixbufs[i] = image_tools.fit_pixbuf_to_rectangle( pixbufs[i], scaled_sizes[i], rotations[i]) for i in range(n): if prefs['horizontal flip']: # 2D only pixbufs[i] = pixbufs[i].flip(horizontal=True) if prefs['vertical flip']: # 2D only pixbufs[i] = pixbufs[i].flip(horizontal=False) pixbufs[i] = self.enhancer.enhance(pixbufs[i]) for i in range(n): image_tools.set_from_pixbuf(self.images[i], pixbufs[i]) scales = tuple( map( lambda x, y: math.sqrt( tools.div(tools.volume(x), tools.volume(y))), scaled_sizes, sizes)) resolutions = tuple(map(lambda x, y: x + (y, ), sizes, scales)) if self.is_manga_mode: resolutions = tuple(reversed(resolutions)) self.statusbar.set_resolution(resolutions) 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(n) if smartbg: self.set_bg_colour(bg_colour) if smartthumbbg: self.thumbnailsidebar.change_thumbnail_background_color( bg_colour) #self._image_box.window.freeze_updates() # XXX replacement necessary? self._main_layout.set_size(*union_scaled_size) content_boxes = self.layout.get_content_boxes() for i in range(n): self._main_layout.move(self.images[i], *content_boxes[i].get_position()) for i in range(n): self.images[i].show() for i in range(n, len(self.images)): self.images[i].hide() if scroll: if at_bottom: self.scroll_to_predefined((constants.SCROLL_TO_END, ) * 2, constants.LAST_INDEX) else: self.scroll_to_predefined( (constants.SCROLL_TO_START, ) * 2, constants.FIRST_INDEX) #self._image_box.window.thaw_updates() # XXX replacement necessary? else: # 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._update_page_information() 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)) do_not_transform = [ image_tools.is_animation(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): if do_not_transform[i]: continue 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 = 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): if do_not_transform[i]: continue 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 do_not_transform[i]: continue 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
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