import gtk import cairo import sys import os from fringwalker import FringWalker from fringrenderer import FringRenderer from fringutil import * GPL = """ fring is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. fring is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with fring; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. """ ui = """ """ class UI( gtk.Window ): def __init__(self, path): self.busy_cursor = 0 self.backgroundColour = (1,1,1) self.data = None self.zoomfactor = 1.0 self.renderer = FringRenderer() self.walker = FringWalker(); # create gui gtk.Window.__init__(self) self.set_title("fring"); self.__init_gui(path) # walk directory self.walker.connect("list-changed",self.__list_changed) self.walker.connect("finished", self.__walker_finished) self.open_folder(path) def __init_gui(self, path): # create menubar uimanager = gtk.UIManager() accelgroup = uimanager.get_accel_group() self.add_accel_group(accelgroup) ag_global = gtk.ActionGroup('ag_global') ag_global.add_actions([ ('FRing', None, "_Folder"), ('View', None, "_View"), ('Help', None, "_Help"), ('OpenParent', gtk.STOCK_GO_UP, "Open _Parent", "Up", "Open the parent folder", self.open_parent), ('SelectFolder', gtk.STOCK_OPEN, "_Open Folder...", None, "Open Folder...", self.__selectfolder), ('Quit', gtk.STOCK_QUIT, "_Quit", None, "Quit", self.close), ('Zoom In', gtk.STOCK_ZOOM_IN, "Zoom _In", "Up", "Zoom In", lambda w: self.zoom(w,0.2)), ('Zoom Out', gtk.STOCK_ZOOM_OUT, "Zoom _Out", "Down", "Zoom Out", lambda w: self.zoom(w,-0.2)), ('Save Image...', gtk.STOCK_SAVE_AS, "_Save Image...", None, "Save Image...", self.save_image), ('Refresh', gtk.STOCK_REFRESH, "_Refresh Tree", "R", "Refresh Tree", lambda w: self.__set_path(self.path)), ('About', gtk.STOCK_ABOUT, "_About", None, "About", self.about_dialog), ]) action = gtk.ToggleAction("Show Hidden Files", "Show Hidden Files", None, None) action.connect("toggled",self.__hidden_files_toggled) ag_global.add_action(action) uimanager.insert_action_group(ag_global, 0) uimanager.add_ui_from_string(ui) menubar = uimanager.get_widget('/MenuBar') menubar.show() # create toolbar toolbar = gtk.HBox() b = gtk.Button() img = gtk.image_new_from_stock(gtk.STOCK_GO_UP, gtk.ICON_SIZE_BUTTON) b.set_property("image", img) uimanager.get_action("/MenuBar/FRing/OpenParent").connect_proxy(b) toolbar.pack_start( b, False ) b = gtk.FileChooserButton('Select a Folder') b.set_action(gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER) b.connect("current-folder-changed", lambda w: self.__set_path(w.get_current_folder())) toolbar.pack_start( b, True ) self.filechooserbutton = b # create canvas self.eventbox = gtk.EventBox() self.image = gtk.Image() self.eventbox.add(self.image) self.eventbox.add_events( gtk.gdk.EXPOSURE_MASK | gtk.gdk.LEAVE_NOTIFY_MASK | gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.POINTER_MOTION_MASK ) self.eventbox.connect("scroll_event", self.__scroll_event) self.eventbox.connect("button-press-event",self.__click_event) self.eventbox.connect("motion-notify-event",self.__move_event) # Create label self.label = gtk.Label() self.label.set_alignment(0, .5) self.label.set_padding(6, 0) self.label.set_text("Initializing") # aligh menubar, toolbar and canvas vertically vbox = gtk.VBox(); vbox.pack_start(menubar,False,False) vbox.pack_start(toolbar,False,False) f = gtk.Frame() f.set_shadow_type(gtk.SHADOW_IN) f.add(self.eventbox) vbox.pack_start(f) vbox.pack_start(self.label,False,False,6) self.add(vbox) # show everything # Note: With set_default_size, the image can't be downsized. self.set_size_request(100,100) # minimum size, needed! self.resize(500,350) self.show_all() self.__create_canvas() self.eventbox.connect("size-allocate",self.__on_resize) self.connect("delete_event", self.close) def open_folder(self,path): print "open",path # change folder by changing the chooser button self.filechooserbutton.set_current_folder(path) def about_dialog(self,widget): d = gtk.AboutDialog() d.set_name("fring"); d.set_license(GPL); d.set_copyright("copyright 2006 Lennart Poettering, Frederic Back") d.run() d.destroy() def close(self,w=None,e=None): self.walker.stop() self.destroy() gtk.main_quit() def open_parent(self,widget): p = os.path.split(self.path) p = os.path.join(p[:-1]) self.open_folder(p[0]) def zoom(self,widget,factor): self.zoomfactor += factor if self.zoomfactor < 0: self.zoomfactor = 0 self.redraw() def redraw(self,widget=None): # clear the canvas self.__show_busy_cursor(1) self.ctx.rectangle(0,0,self.width,self.height) self.ctx.set_source_rgb(*self.backgroundColour) self.ctx.fill() # draw segments if not self.data: return self.renderer.WIDTH = self.width self.renderer.HEIGHT = self.height self.renderer.INNER_RADIUS = self.height/12 self.renderer.RING_RADIUS = self.height/10 #self.renderer.INNER_RADIUS *= self.zoomfactor self.renderer.RING_RADIUS *= self.zoomfactor self.renderer.RINGS_MAX = 3 self.renderer.LABEL_UNTIL_RING = int(self.zoomfactor - 0.4) if self.zoomfactor < 0.8: self.renderer.LABEL_UNTIL_RING = -1 self.renderer.draw_segment(self.ctx, 0, 0, 1, 0, 1, self.data, self.path) self.image.queue_draw() self.__show_busy_cursor(-1) def save_image(self, widget=None): d = gtk.FileChooserDialog("Save As...", self.get_toplevel(), gtk.FILE_CHOOSER_ACTION_SAVE, (gtk.STOCK_CANCEL,0,gtk.STOCK_OK,1), None) d.set_current_name( self.data.name.replace(" ","_") + ".png" ) r = d.run() if r == 1: #print d.get_uri() self.__show_busy_cursor(1) pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB,True,8,self.width,self.height) pixmap, mask = self.image.get_pixmap() pixbuf.get_from_drawable(pixmap,pixmap.get_colormap(),0,0,0,0,-1,-1) #pixbuf.save(d.get_filename(), "jpeg", {"quality":"100"}) pixbuf.save(d.get_filename(), "png", {}) self.__show_busy_cursor(-1) d.destroy() #----------------------------------------------------------- private methods def __set_path(self,path): """ Set a path and start parsing. Also used to refresh or reset. """ self.path = path self.walker.stop() if path is None: return self.walker.walk(path); self.__show_busy_cursor(1) def __selectfolder(self,widget): """ Open a dialog to select a folder """ d = gtk.FileChooserDialog(None, self, gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, (gtk.STOCK_CANCEL,0,gtk.STOCK_OK,1)) if d.run() == 1: self.open_folder(d.get_current_folder()) d.destroy() def __hidden_files_toggled(self,widget): if self.walker.showhidden == widget.get_active(): return self.walker.showhidden = widget.get_active() self.__set_path(self.path) def __move_event(self, widget, event): f = self.renderer.get_hotspot_at(event.x, event.y) if f is None: self.label.set_text("Ready.") else: self.label.set_markup("Path %s, %s, %0.1f%%" % (f.path, pretty_size(f.size), f.value*100)) if f is None or not f.is_dir: if self.busy_cursor > 0: cursor = gtk.gdk.Cursor(gtk.gdk.WATCH) else: cursor = None self.eventbox.window.set_cursor(cursor) else: # always display a hand when hovering a link self.eventbox.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND1)) def __click_event(self, widget, event): f = self.renderer.get_hotspot_at(event.x, event.y) if f is not None: if f.is_dir: self.open_folder(f.path) def __scroll_event(self, widget, event): if event.direction is gtk.gdk.SCROLL_UP: self.zoom(widget, 0.2) elif event.direction is gtk.gdk.SCROLL_DOWN: self.zoom(widget, -0.2) def __create_canvas(self): # create a new pixmap and cairo context r = self.eventbox.get_allocation() self.width, self.height = r.width, r.height self.pixmap = gtk.gdk.Pixmap(self.window,r.width,r.height) self.image.set_from_pixmap(self.pixmap,None) self.ctx = self.pixmap.cairo_create() self.renderer.prepare_layouts(self.ctx) self.ctx.rectangle(0,0,self.width,self.height) self.ctx.set_source_rgb(*self.backgroundColour) self.ctx.fill() def __list_changed(self,widget,data): self.data = data self.redraw() #print data.name def __walker_finished(self, widget, data): self.__list_changed(widget, data) self.__show_busy_cursor(-1) def __on_resize(self, widget, event): r = self.eventbox.get_allocation() if (r.width,r.height) != (self.width,self.height): self.__create_canvas() self.redraw() def __show_busy_cursor(self, value): if self.busy_cursor <= 0 and self.busy_cursor+value >= 0: if self.window: self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH)) self.label.set_markup("Busy...") elif self.busy_cursor > 0 and self.busy_cursor+value <= 0: if self.window: self.window.set_cursor(None) self.label.set_text("Ready.") self.busy_cursor += value #print "busy state:",self.busy_cursor