summaryrefslogtreecommitdiff
path: root/wpcreator/ui.py
diff options
context:
space:
mode:
Diffstat (limited to 'wpcreator/ui.py')
-rw-r--r--wpcreator/ui.py292
1 files changed, 292 insertions, 0 deletions
diff --git a/wpcreator/ui.py b/wpcreator/ui.py
new file mode 100644
index 0000000..b1debfa
--- /dev/null
+++ b/wpcreator/ui.py
@@ -0,0 +1,292 @@
+import pygtk
+pygtk.require ("2.0")
+import gtk
+import cairo
+import pangocairo
+
+import StringIO
+import cropper
+import generator
+
+target_width = 240
+target_height = 320
+mainWindow = None
+
+def prepare_text (cr, text):
+ '''Prepare text for drawing with Pango/Cairo'''
+ pcr = pangocairo.CairoContext (cr)
+ layout = pcr.create_layout ()
+ layout.set_markup (text)
+ return pcr, layout
+
+def pilimage_to_pixbuf (image):
+ f = StringIO.StringIO ()
+ image.save (f, 'ppm')
+ contents = f.getvalue()
+ f.close ()
+ loader = gtk.gdk.PixbufLoader ('pnm')
+ loader.write (contents, len (contents))
+ pixbuf = loader.get_pixbuf ()
+ loader.close ()
+ return pixbuf
+
+class ImagePreview (gtk.DrawingArea):
+
+ number = None
+ pixbuf = None
+ number_colors = [
+ (0.94, 0.16, 0.16),
+ (0.13, 0.29, 0.53),
+ (0.54, 0.89, 0.20),
+ (0.99, 0.69, 0.24),
+ ]
+
+ def __init__ (self, cropped):
+ super (ImagePreview, self).__init__ ()
+ self.set_cropped (cropped)
+ self.set_size_request (140, 170)
+ self.connect ("expose-event", self.on_expose)
+
+ def set_cropped (self, cropped):
+ cropped = cropped.resize ((120, 160))
+ self.pixbuf = pilimage_to_pixbuf (cropped)
+ self.queue_draw ()
+
+ def set_number (self, number):
+ self.number = number
+ self.queue_draw ()
+
+ def on_expose (self, widget, event):
+ cr = self.window.cairo_create ()
+ cr.rectangle (10, 10, 120, 160)
+ cr.clip ()
+ cr.set_source_pixbuf (self.pixbuf, 10, 10)
+ cr.paint ()
+ if self.number:
+ cr.set_source_rgba (0.6, 0.6, 0.6, 0.8)
+ cr.paint ()
+ text = '<span font_desc="Sans 42"><b>%s</b></span>' % self.number
+ pcr, layout = prepare_text (cr, text)
+ text_width, text_height = layout.get_pixel_size ()
+ _, _, width, height = self.get_allocation ()
+ cr.move_to ((width - text_width) / 2, (height - text_height) / 2)
+ colors_count = len (self.number_colors)
+ color_id = (self.number - 1) % colors_count
+ cr.set_source_rgb (*self.number_colors[color_id])
+ pcr.show_layout (layout)
+
+class ImageItem (gtk.VBox):
+
+ path = None
+ table = None
+
+ preview = None
+
+ cropped = None
+ cropper = None
+ cropperWindow = None
+
+ def __init__ (self, path, table):
+ super (ImageItem, self).__init__ ()
+ self.path = path
+ self.table = table
+ self.cropper = cropper.CropperUi (path, target_width, target_height)
+ self.cropped = self.cropper.get_cropped_image ()
+ self.preview = ImagePreview (self.cropped)
+ width, height = self.preview.get_size_request ()
+ self.set_size_request (width, height + 35)
+ self.pack_start (self.preview, False, False)
+ box = gtk.HBox (homogeneous = True)
+ self.pack_start (box, False, False)
+ use_button = gtk.CheckButton ("Use")
+ use_button.connect ("toggled", self.on_use)
+ box.pack_start (use_button, False, False)
+ crop_button = gtk.Button ("Crop")
+ crop_button.connect ("clicked", self.on_crop)
+ box.pack_start (crop_button, False, False)
+
+ def on_use (self, toggle):
+ if toggle.get_active ():
+ self.table.select_item (self)
+ else:
+ self.table.unselect_item (self)
+
+ def on_crop (self, widget):
+ self.cropperWindow = gtk.Window ()
+ self.cropperWindow.set_title ("Wallpaper Creator - Crop")
+ self.cropperWindow.set_modal (True)
+ self.cropperWindow.set_transient_for (mainWindow)
+ base_width, base_height = 800, 600
+ pixbuf_width = self.cropper.pixbuf.get_width ()
+ pixbuf_height = self.cropper.pixbuf.get_height ()
+ if pixbuf_height > pixbuf_width:
+ height = base_height
+ width = float (base_height) * pixbuf_width / pixbuf_height
+ else:
+ width = base_width
+ height = float (base_width) * pixbuf_height / pixbuf_width
+ self.cropper.set_size_request (int (width), int (height))
+ box = gtk.VBox ()
+ box.pack_start (self.cropper, True, True)
+ ok_button = gtk.Button ("Crop")
+ ok_button.connect ("clicked", self.crop)
+ box.pack_start (ok_button, False, False)
+ self.cropperWindow.add (box)
+ self.cropperWindow.show_all ()
+
+ def crop (self, button):
+ self.cropped = self.cropper.get_cropped_image ()
+ self.preview.set_cropped (self.cropped)
+ self.cropperWindow.get_child ().remove (self.cropper)
+ self.cropperWindow.destroy ()
+
+ def set_number (self, number):
+ self.preview.set_number (number)
+
+class ImageTable (gtk.Fixed):
+
+ items = None
+ selected = None
+ alloc = None
+
+ def __init__ (self):
+ super (ImageTable, self).__init__ ()
+ self.connect_after ("size-allocate", self.on_size_allocate)
+ self.items = []
+ self.selected = []
+
+ def on_size_allocate (self, widget, alloc):
+ if alloc == self.alloc:
+ return
+ self.alloc = alloc
+ for i in range (len (self.items)):
+ item = self.items[i]
+ self.move (item, *self.get_item_pos (item, i))
+
+ def get_item_pos (self, item, i):
+ width, height = item.get_size_request ()
+ alloc = self.get_allocation ()
+ per_line = alloc.width / width
+ if per_line == 0:
+ return 0, 0
+ line = i / per_line
+ pos = i - per_line * line
+ return pos * width, line * height
+
+ def add_files (self, files):
+ for f in files:
+ item = ImageItem (f, self)
+ self.put (item, *self.get_item_pos (item, len (self.items)))
+ self.items.append (item)
+ self.show_all ()
+
+ def select_item (self, item):
+ self.selected.append (item)
+ item.set_number (len (self.selected))
+
+ def unselect_item (self, item):
+ if item in self.selected:
+ self.selected.remove (item)
+ item.set_number (None)
+ for i in range (len (self.selected)):
+ self.selected[i].set_number (i + 1)
+
+ def get_selection (self):
+ return [item.cropped for item in self.selected]
+
+def add_image_filters (dialog):
+ filter = gtk.FileFilter ()
+ filter.set_name ("All files")
+ filter.add_pattern ("*")
+ dialog.add_filter (filter)
+ filter = gtk.FileFilter ()
+ filter.set_name ("Images")
+ filter.add_mime_type ("image/png")
+ filter.add_mime_type ("image/jpeg")
+ filter.add_pattern ("*.png")
+ filter.add_pattern ("*.jpg")
+ dialog.add_filter (filter)
+ dialog.set_filter (filter)
+
+class PreviewWindow (gtk.Window):
+
+ def __init__ (self, parent, image):
+ super (PreviewWindow, self).__init__ ()
+ self.set_modal (True)
+ self.set_transient_for (parent)
+ self.set_title ("Wallpaper Creator - Preview")
+ self.pixbuf = pilimage_to_pixbuf (image)
+ box = gtk.VBox ()
+ box.pack_start (gtk.image_new_from_pixbuf (self.pixbuf), True, True)
+ hbox = gtk.HBox ()
+ cancel_button = gtk.Button (stock = gtk.STOCK_CANCEL)
+ cancel_button.connect ("clicked", self.on_cancel)
+ save_button = gtk.Button (stock = gtk.STOCK_SAVE)
+ save_button.connect ("clicked", self.on_save)
+ hbox.pack_end (cancel_button, False, False)
+ hbox.pack_end (save_button, False, False)
+ box.pack_start (hbox, False, False)
+ self.add (box)
+
+ def on_save (self, widget):
+ dialog = gtk.FileChooserDialog (title = "Save to...", parent = self,
+ action = gtk.FILE_CHOOSER_ACTION_SAVE,
+ buttons = (gtk.STOCK_CANCEL,
+ gtk.RESPONSE_CANCEL,
+ gtk.STOCK_OPEN,
+ gtk.RESPONSE_OK))
+ add_image_filters (dialog)
+ response = dialog.run ()
+ if response == gtk.RESPONSE_OK:
+ path = dialog.get_filename ()
+ if path.lower ().endswith (".png"):
+ self.pixbuf.save (path, "png")
+ else:
+ self.pixbuf.save (path, "jpeg", {"quality": "95"})
+ self.destroy ()
+ dialog.destroy ()
+
+ def on_cancel (self, widget):
+ self.destroy ()
+
+def load_files (window, table):
+ dialog = gtk.FileChooserDialog (title = "Open images", parent = window,
+ action = gtk.FILE_CHOOSER_ACTION_OPEN,
+ buttons = (gtk.STOCK_CANCEL,
+ gtk.RESPONSE_CANCEL,
+ gtk.STOCK_OPEN,
+ gtk.RESPONSE_OK))
+ dialog.set_select_multiple (True)
+
+ add_image_filters (dialog)
+
+ if dialog.run () == gtk.RESPONSE_OK:
+ filenames = dialog.get_filenames ()
+ else:
+ filenames = None
+ dialog.destroy ()
+ if filenames:
+ table.add_files (filenames)
+
+def make_wallpaper (window, table):
+ image = generator.assemble (table.get_selection ())
+ preview = PreviewWindow (window, image)
+ preview.show_all ()
+
+def main ():
+ global mainWindow
+ builder = gtk.Builder ()
+ builder.add_from_file ("wpcreator.gtkbuilder")
+ builder.get_object ("targetWidthSpin").set_value (target_width)
+ builder.get_object ("targetHeightSpin").set_value (target_height)
+ table = ImageTable ()
+ builder.get_object ("scroller").add_with_viewport (table)
+ mainWindow = builder.get_object ("mainWindow")
+ mainWindow.set_default_size (800, 600)
+ mainWindow.connect ("delete-event", gtk.main_quit)
+ handlers = {"load_files": lambda widget: load_files (mainWindow, table),
+ "make_wallpaper": lambda widget: make_wallpaper (mainWindow,
+ table)}
+ builder.connect_signals (handlers)
+ mainWindow.show_all ()
+ gtk.main ()