def init(self, parent, params = {}): #connect buttons with icons self.zoom_fit_button.add(Utils.create_stock_button(gtk.STOCK_ZOOM_FIT)) self.zoom_100_button.add(Utils.create_stock_button(gtk.STOCK_ZOOM_100)) self.library_back_button.add(Utils.create_stock_button(gtk.STOCK_GO_BACK, "Back to Library")) self.play_slideshow_button.add(Utils.create_stock_button(gtk.STOCK_MEDIA_PLAY, "Play")) self.prev_button.add(Utils.create_stock_button(gtk.STOCK_MEDIA_PREVIOUS)) self.next_button.add(Utils.create_stock_button(gtk.STOCK_MEDIA_NEXT)) self.selection_add_button.add(Utils.create_stock_button(gtk.STOCK_ADD, icon_size=gtk.ICON_SIZE_MENU)) self.selection_remove_button.add(Utils.create_stock_button(gtk.STOCK_REMOVE, icon_size=gtk.ICON_SIZE_MENU)) self.selection_clear_button.add(Utils.create_stock_button(gtk.STOCK_CLEAR, icon_size=gtk.ICON_SIZE_MENU)) #self.star_button.remove(self.star_button.get_child()) #self.star_button.add(Utils.create_stock_button("unstarred")) #self.star_button.set_property('orientation', gtk.ORIENTATION_HORIZONTAL) self.rotate_left_button.add(Utils.create_stock_button("object-rotate-left")) self.rotate_right_button.add(Utils.create_stock_button("object-rotate-right")) self.add_tag_button.add(Utils.create_stock_button("tag")) self.image_viewport = GtkImageView() self.vbox2.pack_start(self.image_viewport, True, True, 0) self.vbox2.reorder_child(self.image_viewport, 0) self.image_viewport.show() self.thumbnails = [self.thumbnail1, self.thumbnail2, self.thumbnail3, self.thumbnail4, self.thumbnail5, self.thumbnail6, self.thumbnail7 ] self.image_viewport.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#888A85')) #connect eventboxes to thumbnails dx = -3 for eventbox in [self.thumbnail1event, self.thumbnail2event, self.thumbnail3event, self.thumbnail5event, self.thumbnail6event, self.thumbnail7event]: eventbox.set_events(gtk.gdk.BUTTON1_MASK) eventbox.connect("button_press_event", self.move_to_thumbnail, dx) dx+=1 if dx==0: dx+=1 #colorize status_line self.statusline.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#eeeeec')) self.statusline_eventbox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#5590ba')) self.parent = parent #connect change-value signals to scrollbars of main image #self.scrolled_viewport.get_vscrollbar().connect('change-value', self.change_zoom_origin_x) label = gtk.Label("Hello World\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nHello") x = Utils.create_expander("QuickFix", label, False) self.plugins_box.pack_start(x, False, False) #self.image_viewport.connect("button_release_event", self.on_image_viewport_button_release_event) self.caption_text.get_buffer().connect_after('changed', self.on_caption_text_changed_event) self.caption_text.get_buffer().connect('insert-text', self.on_caption_text_insert_text_event) #ValueButton for rating self.star_value_button = ValueButton([ (0, 'star-0of5', '0/5'), (1, 'star-1of5', '1/5'), (2, 'star-2of5', '2/5'), (3, 'star-3of5', '3/5'), (4, 'star-4of5', '4/5'), (5, 'star-5of5', '5/5')], initial_value = 0, icon_size = gtk.ICON_SIZE_MENU, show_values = True) self.star_value_button.show() self.star_value_button.connect('value-changed', self._set_image_rating) self.hbox8.pack_start(self.star_value_button, False, False) self.hbox8.reorder_child(self.star_value_button, 0) self.star_value_button.set_border_width(4)
class PhotoView(GladeApp, object): class Size(): def __init__(self, width, height): self.width = width self.height = height glade = os.path.join('..', os.path.dirname(os.path.dirname(__file__)), 'data', 'photoview.glade') window = "vbox1" _zoom = 0.0 _zoom_min = log(0.01) _zoom_max = log(8.00) _zoom_fit = log(0.1) _zoom_origin_x = 0.5 _zoom_origin_y = 0.5 zoom_step = 0.1 images_list = [] _thumbnails_cache = {} parent = None thumbnails = [] selected = [] _allocation = None #image zoom def _get_zoom(self): return self._zoom def _set_zoom_with_callback(self, value, callback = True): if value == 'fit': value = self._zoom_fit if value < self._zoom_min: value = self._zoom_min if value > self._zoom_max: value = self._zoom_max if value != self._zoom: old = self._zoom self._zoom = value if value < self._zoom_fit: self._zoom_origin_x = 0.5 self._zoom_origin_y = 0.5 if callback: self.zoom_scale.set_value(value) self._apply_zoom_on_image(exp(-old+value)) def _set_zoom(self, value): self._set_zoom_with_callback(value) zoom = property(_get_zoom, _set_zoom) #currently displayed image _image = None def _get_image(self): return self._image def _set_image(self, value): self._image = value self._compute_fit_zoom() self.zoom = 'fit' self.image_viewport.set_image(value) self.image_viewport.set_property('zoom', self.image_viewport.get_property('fit-zoom')) #self._apply_zoom_on_image() #show new image in widget image = property(_get_image, _set_image) #image index (now displayed) in images_list _index = 0 def _get_index(self): return self._index def _set_index(self, value): if type(value) == int: if 0 <= value < len(self.images_list):# and self._index != value: self._index = value self.image = self.current.getImage() self._update_view() index = property(_get_index, _set_index) #current image node def _get_current(self): return self.images_list[self.index] current = property(_get_current) def init(self, parent, params = {}): #connect buttons with icons self.zoom_fit_button.add(Utils.create_stock_button(gtk.STOCK_ZOOM_FIT)) self.zoom_100_button.add(Utils.create_stock_button(gtk.STOCK_ZOOM_100)) self.library_back_button.add(Utils.create_stock_button(gtk.STOCK_GO_BACK, "Back to Library")) self.play_slideshow_button.add(Utils.create_stock_button(gtk.STOCK_MEDIA_PLAY, "Play")) self.prev_button.add(Utils.create_stock_button(gtk.STOCK_MEDIA_PREVIOUS)) self.next_button.add(Utils.create_stock_button(gtk.STOCK_MEDIA_NEXT)) self.selection_add_button.add(Utils.create_stock_button(gtk.STOCK_ADD, icon_size=gtk.ICON_SIZE_MENU)) self.selection_remove_button.add(Utils.create_stock_button(gtk.STOCK_REMOVE, icon_size=gtk.ICON_SIZE_MENU)) self.selection_clear_button.add(Utils.create_stock_button(gtk.STOCK_CLEAR, icon_size=gtk.ICON_SIZE_MENU)) #self.star_button.remove(self.star_button.get_child()) #self.star_button.add(Utils.create_stock_button("unstarred")) #self.star_button.set_property('orientation', gtk.ORIENTATION_HORIZONTAL) self.rotate_left_button.add(Utils.create_stock_button("object-rotate-left")) self.rotate_right_button.add(Utils.create_stock_button("object-rotate-right")) self.add_tag_button.add(Utils.create_stock_button("tag")) self.image_viewport = GtkImageView() self.vbox2.pack_start(self.image_viewport, True, True, 0) self.vbox2.reorder_child(self.image_viewport, 0) self.image_viewport.show() self.thumbnails = [self.thumbnail1, self.thumbnail2, self.thumbnail3, self.thumbnail4, self.thumbnail5, self.thumbnail6, self.thumbnail7 ] self.image_viewport.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#888A85')) #connect eventboxes to thumbnails dx = -3 for eventbox in [self.thumbnail1event, self.thumbnail2event, self.thumbnail3event, self.thumbnail5event, self.thumbnail6event, self.thumbnail7event]: eventbox.set_events(gtk.gdk.BUTTON1_MASK) eventbox.connect("button_press_event", self.move_to_thumbnail, dx) dx+=1 if dx==0: dx+=1 #colorize status_line self.statusline.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#eeeeec')) self.statusline_eventbox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#5590ba')) self.parent = parent #connect change-value signals to scrollbars of main image #self.scrolled_viewport.get_vscrollbar().connect('change-value', self.change_zoom_origin_x) label = gtk.Label("Hello World\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nHello") x = Utils.create_expander("QuickFix", label, False) self.plugins_box.pack_start(x, False, False) #self.image_viewport.connect("button_release_event", self.on_image_viewport_button_release_event) self.caption_text.get_buffer().connect_after('changed', self.on_caption_text_changed_event) self.caption_text.get_buffer().connect('insert-text', self.on_caption_text_insert_text_event) #ValueButton for rating self.star_value_button = ValueButton([ (0, 'star-0of5', '0/5'), (1, 'star-1of5', '1/5'), (2, 'star-2of5', '2/5'), (3, 'star-3of5', '3/5'), (4, 'star-4of5', '4/5'), (5, 'star-5of5', '5/5')], initial_value = 0, icon_size = gtk.ICON_SIZE_MENU, show_values = True) self.star_value_button.show() self.star_value_button.connect('value-changed', self._set_image_rating) self.hbox8.pack_start(self.star_value_button, False, False) self.hbox8.reorder_child(self.star_value_button, 0) self.star_value_button.set_border_width(4) def _set_image_rating(self, widget, value): if self.current != None: self.current.setRating(value) def move_to_thumbnail(self, widget, event, number): self.index += number def _get_thumbnail_from_node(self, node, refresh = False, size = 32): """ Return square miniature of image (e.g. for thumbnail bar or for @param node: @return: """ if not node.file in self._thumbnails_cache or refresh == True: pb = node.getOriginalThumbnail() w,h = (pb.get_width(), pb.get_height()) if w > h: pb = pb.scale_simple(w*size/h, size, gtk.gdk.INTERP_HYPER) else: pb = pb.scale_simple(size, h*size/w, gtk.gdk.INTERP_HYPER) pb = pb.subpixbuf(0,0,size, size) #print pb.get_width(), pb.get_height() self._thumbnails_cache[node.file] = pb return self._thumbnails_cache[node.file] def _update_thumbnails_bar(self): if self.index is not None: for i in xrange(-3,4): if 0<= self.index+i < len(self.images_list): self.thumbnails[i+3].set_from_pixbuf(self._get_thumbnail_from_node(self.images_list[self.index+i])) else: self.thumbnails[i+3].set_from_stock(gtk.STOCK_NO, gtk.ICON_SIZE_BUTTON) def _init_selection_view(self): model = gtk.ListStore(gtk.gdk.Pixbuf) for i in self.images_list: model.append((self._get_thumbnail_from_node(i, True, size = 16), )) self.selection_icons.set_model(model) self.selection_icons.set_pixbuf_column(0) self.selection_icons.set_item_padding(1) self.selection_icons.set_spacing(0) self.selection_icons.set_row_spacing(0) self.selection_icons.set_column_spacing(0) #self.selection_icons.set_item_width(32) def init_data(self, images_list, index, selected=[]): self.images_list = images_list self.selected = selected self.index = index self._update_view() self._init_selection_view() def unload(self): self.images_list = None self.index = None self.selected = None def _update_status_line(self): d = self.current.getInfo() t = [ os.path.split(self.current.file)[1], Utils.get_human_readable_date(d['exifdate']), str(d['resolution'])+' pixels', Utils.get_human_readable_byte_count(d['filesize'], False), ] #if photo has tags display it if len(self.current.tags)>0: t.append('tags: '+', '.join(self.current.tags)) #add position of current photo (e.g 5/12) t.append('('+str(self.index+1)+'/'+str(len(self.images_list))+')') self.statusline.set_text(' '.join(t)) def _update_main_image(self): self.image = self.current.getImage() if self.image is not None: self._apply_zoom_on_image(0.0) def _update_comment(self): if self.current != None: x = self.current.comment if x == '': x = 'Make a Caption!' self.caption_text.get_buffer().set_text(x) def _update_rating(self): if self.current != None: self.star_value_button.set_value(self.current.rating, True) def _update_view(self): self._update_thumbnails_bar() self._update_main_image() self._update_status_line() self._update_zoom_scale() self._update_comment() self._update_rating() def _update_zoom_scale(self): """ Refresh zoom_scale (HScale) widget according to zoom properties """ if self.image is not None: self.zoom_scale.clear_marks() self.zoom_scale.set_range(self._zoom_min, self._zoom_max) self.zoom_scale.add_mark(self._zoom_fit, gtk.POS_BOTTOM, "fit") self.zoom_scale.add_mark(0.0, gtk.POS_BOTTOM, "100%") self.zoom_scale.set_value(self.zoom) def _compute_fit_zoom(self): """ Set _zoom_fit according to viewport size """ """if self.image is None: return #TODO: change to _get_allocation_size() bounds = self._get_allocation_size() width, height = bounds.width, bounds.height #add some margin width-=16 height-=16 set_zoom_fit = True if self._zoom_fit == self._zoom else False x = width*self.image.get_height()/height if x >= self.image.get_width(): self._zoom_fit = log(float(height)/float(self.image.get_height())) #fill height else: self._zoom_fit = log(float(width)/float(self.image.get_width())) #fill width #TODO: add better values self._zoom_min = min( 0.0, self._zoom_fit-2.0) self._zoom_max = max(self._zoom_fit+2.0, 0.0) #If zoom was fitted, then restore them to 'fit' if set_zoom_fit: self.zoom = 'fit' self._update_zoom_scale()""" def _get_zoomed_size(self): if self.image is not None: return PhotoView.Size(self.image.get_width()*exp(self.zoom), self.image.get_height()*exp(self.zoom)) return PhotoView.Size(0,0) def _get_allocation_size(self): if self._allocation is None: self._allocation = self.image_viewport.get_allocation() bounds = self._allocation#self.image_viewport.get_allocation() return PhotoView.Size(bounds.width, bounds.height) def _update_adjustments(self): zoomed = self._get_zoomed_size() alloc = self._get_allocation_size() self.image_viewport.get_vadjustment().set_value(max(0.0, self._zoom_origin_y*zoomed.height-0.5*alloc.height)) self.image_viewport.get_hadjustment().set_value(max(0.0, self._zoom_origin_x*zoomed.width-0.5*alloc.width)) #self.scrolled_viewport.set_hadjustment(hadj) def _apply_zoom_on_image(self, ratio): """ Set display_image with applying current zoom property """ """if self.image is not None and ratio != 1.0: zoomed = self._get_zoomed_size() alloc = self._get_allocation_size() off_x = -self.image_viewport.get_bin_window().get_position()[0] x = alloc.width*self._zoom_origin_x dx = off_x+x off_y = -self.image_viewport.get_bin_window().get_position()[1] y = alloc.height*self._zoom_origin_y dy = off_y+y #print (dx, dy, ratio, self._zoom_origin_x, self._zoom_origin_y) self.image_viewport.get_bin_window().freeze_updates() self.display_image.set_from_pixbuf( self.image.scale_simple( int(zoomed.width), int(zoomed.height), gtk.gdk.INTERP_NEAREST #gtk.gdk.INTERP_HYPER ) ) alloc = self._get_allocation_size() #print (dx*ratio-x, dy*ratio-y) self.image_viewport.get_hadjustment().set_value(dx*ratio-x) self.image_viewport.get_vadjustment().set_value(dy*ratio-y) self.image_viewport.get_bin_window().thaw_updates() """ def on_prev_button_clicked(self, event): self.index -= 1 def on_next_button_clicked(self, event): self.index += 1 def on_library_back_button_clicked(self, event): #TODO self.parent.notebook2.set_current_page(0) self.unload() """def on_image_viewport_size_allocate(self, widget, allocation): alloc = self._get_allocation_size() if alloc.width != allocation.width or alloc.height != allocation.height: self._allocation = allocation if self.image is not None: self._compute_fit_zoom() return False""" def on_zoom_fit_button_clicked(self, event): self.image_viewport.set_property('horizontal-center', 0.5) self.image_viewport.set_property('vertical-center', 0.5) self.image_viewport.set_property('zoom', self.image_viewport.get_property('fit-zoom')) def on_zoom_100_button_clicked(self, event): self.image_viewport.set_property('horizontal-center', 0.5) self.image_viewport.set_property('vertical-center', 0.5) self.image_viewport.set_property('zoom', 1.0) def on_zoom_out_eventbox_button_press_event(self, widget, event): self._zoom_origin_x = self._zoom_origin_y = 0.5 self.zoom -= self.zoom_step def on_zoom_in_eventbox_button_press_event(self, widget, event): self._zoom_origin_x = self._zoom_origin_y = 0.5 self.zoom += self.zoom_step def on_zoom_scale_change_value(self, widget, scroll, value): self._zoom_origin_x = self._zoom_origin_y = 0.5 self._set_zoom_with_callback(value, False) """def on_scrolled_viewport_scroll_event(self, widget, event): alloc = self._get_allocation_size() #zoomed = self._get_zoomed_size() orig_x = float(event.x)/float(alloc.width) orig_y = float(event.y)/float(alloc.height) #orig_x = float(event.x)/float(zoomed.width) #orig_y = float(event.y)/float(zoomed.height) # print (orig_x, orig_y) if event.direction == gtk.gdk.SCROLL_UP: self._zoom_origin_x = orig_x self._zoom_origin_y = orig_y self.zoom += self.zoom_step elif event.direction == gtk.gdk.SCROLL_DOWN: self._zoom_origin_x = orig_x self._zoom_origin_y = orig_y self.zoom -= self.zoom_step return True""" """def on_scrolled_viewport_motion_notify_event(self, widget, event): return False""" """def on_image_viewport_button_press_event(self, widget, event): #print (event.x, event.y, event.button, ) return False def on_image_viewport_button_release_event(self, widget, event): #print (event.x, event.y, event.button, ) return False""" def _save_comment(self, comment): if type(comment) == str: comment = unicode(comment) #print 'Setting comment: '+comment+' '+str(type(comment)) self.current.setComment(comment) def on_caption_text_focus_in_event(self, widget, event): """ On focus-in update caption @param widget: @param event: @return: """ widget.get_buffer().set_text(self.current.comment) return False def on_caption_text_focus_out_event(self, widget, event): """ On focus-out save caption as jpeg comment @param widget: @param event: @return: """ buffer = widget.get_buffer() caption = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter()).strip() self._save_comment(caption) if caption == '': buffer.set_text('Make a caption!') return False def on_caption_text_insert_text_event(self, buffer, iter, text, length): """ If user pressed enter, leave focus @param buffer: @param iter: @param text: @param length: """ if text == '\n': #print 'Entered: '+buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter()) self.caption_text.get_toplevel().child_focus(gtk.DIR_TAB_FORWARD) def on_caption_text_changed_event(self, buffer):#, iter, text, length): """ Remove new lines "\n" and multiple spaces from caption text @param buffer: @return: """ old_text = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter()) #get caption text if old_text.find('\n') != -1 or old_text.find(' ') != -1: #is something to update? old_text = old_text.replace('\n', '') #replace newline import re old_text = re.compile('[ ]{2,}').subn(' ', old_text)[0] #replace multiple spaces #print old_text buffer.set_text(old_text) #update caption text return True def on_caption_remove_eventbox_button_press_event(self, widget, event): if event.button == 1: #detect left button press if self.current.comment != "": ans = InputQuestion(self.parent.main_widget, "Do you want to remove comment?", buttons = (gtk.STOCK_NO, gtk.RESPONSE_CANCEL, gtk.STOCK_YES, gtk.RESPONSE_OK)) if ans: self.current.setComment(u"") self._update_comment() def on_add_tag_button_clicked(self, widget): tag_editor = TagEditorDialog(self.current) if tag_editor.run(): self._update_status_line() def on_rotate_right_button_clicked(self, widget): self.current.rotate('R') self._get_thumbnail_from_node(self.current, True) self._update_view() def on_rotate_left_button_clicked(self, widget): self.current.rotate('L') self._get_thumbnail_from_node(self.current, True) self._update_view()