import pygst pygst.require("0.10") # Load GTK import gtk from gtk import gdk import pygst import os, sys import time import gobject gobject.threads_init() from mediaview import MediaView import constants import gst import pygtk from treeview import TreeView from model import Model from button import RecdButton import utils from instance import Instance from tray import HTray import shutil # Load sugar libraries from sugar.activity import activity import logging COLOR_BLACK = gdk.color_parse('#000000') COLOR_WHITE = gdk.color_parse('#ffffff') class littleTrampActivity(activity.Activity): def callback(self, widget, data=None): print "Hello again" def __init__(self, handle): activity.Activity.__init__(self, handle) self._name = handle # Set title for our Activity self.set_title('Little Tramp') # Attach sugar toolbox (Share, ...) #toolbox = activity.ActivityToolbox(self) #self.set_toolbox(toolbox) #toolbox.show() Instance(self) #self.set_canvas(self._main_view) self.show_all() self.model = Model(self) self.ui_init() self._media_view.realize_video() # Changing to the first toolbar kicks off the rest of the setup if self.model.get_has_camera(): self.model.change_mode(constants.MODE_PHOTO) #else: #self.model.change_mode(constants.MODE_AUDIO) def _shutter_clicked(self, arg): self.model.do_shutter() def _remove_thumbnail(self, recdbutton): handlers = recdbutton.get_data('handler-ids') for handler in handlers: recdbutton.disconnect(handler) self._thumb_tray.remove_item(recdbutton) recdbutton.cleanup() def remove_all_thumbnails(self): for child in self._thumb_tray.get_children(): self._remove_thumbnail(child) def add_thumbnail(self, recd, scroll_to_end): button = RecdButton(recd) clicked_handler = button.connect("clicked", self._thumbnail_clicked, recd) remove_handler = button.connect("remove-requested", self._remove_recd) clipboard_handler = button.connect("copy-clipboard-requested", self._thumbnail_copy_clipboard) button.set_data('handler-ids', (clicked_handler, remove_handler, clipboard_handler)) self._thumb_tray.add_item(button) button.show() if scroll_to_end: self._thumb_tray.scroll_to_end() def ui_init(self): self._fullscreen = False self._showing_info = False # FIXME: if _thumb_tray becomes some kind of button group, we wouldn't # have to track which recd is active self._active_recd = None toolbox = activity.ActivityToolbox(self) activity_toolbar = toolbox.get_activity_toolbar() activity_toolbar.keep.props.visible = False activity_toolbar.share.props.visible = False self.set_toolbox(toolbox) toolbox.show() self.tView = TreeView() main_box = gtk.VBox() self.set_canvas(main_box) main_box.get_parent().modify_bg(gtk.STATE_NORMAL, COLOR_BLACK) main_box.show() self._media_view = MediaView() #self._media_view.connect('media-clicked', self._media_view_media_clicked) #self._media_view.connect('pip-clicked', self._media_view_pip_clicked) #self._media_view.connect('info-clicked', self._media_view_info_clicked) #self._media_view.connect('full-clicked', self._media_view_full_clicked) #self._media_view.connect('tags-changed', self._media_view_tags_changed) self._media_view.show() self._controls_hbox = gtk.HBox() self._controls_hbox.show() self._treeview_vbox = gtk.VBox() self._treeview_vbox.show() self._treeview_vbox.pack_start(self.tView) self._shutter_button = ShutterButton() self._shutter_button.connect("clicked", self._shutter_clicked) self._controls_hbox.pack_start(self._shutter_button, expand=True, fill=False) self._shutter_button.show() self._title_label = gtk.Label() self._title_label.set_markup(""+('Title:')+'') self._controls_hbox.pack_start(self._title_label, expand=False) self._title_entry = gtk.Entry() self._title_entry.modify_bg(gtk.STATE_INSENSITIVE, COLOR_BLACK) self._title_entry.connect('changed', self._title_changed) self._controls_hbox.pack_start(self._title_entry, expand=True, fill=True, padding=10) container = RecordContainer(self._media_view, self._controls_hbox) main_box.pack_start(self._treeview_vbox, expand=True) main_box.pack_start(container, expand=True, fill=True, padding=6) container.show() self._thumb_tray = HTray() self._thumb_tray.set_size_request(-1, 150) main_box.pack_end(self._thumb_tray, expand=False) self._thumb_tray.show_all() def set_glive_sink(self, sink): return self._media_view.set_video_sink(sink) # can be called from gstreamer thread, so must not do any GTK+ stuff def set_gplay_sink(self, sink): return self._media_view.set_video2_sink(sink) def _title_changed(self, widget): self._active_recd.setTitle(self._title_entry.get_text()) def _thumbnail_clicked(self, button, recd): if self.model.ui_frozen(): return self._active_recd = recd self._show_recd(recd) def _show_recd(self, recd, play=True): self._showing_info = False def _remove_recd(self, recdbutton): recd = recdbutton.get_recd() self.model.delete_recd(recd) if self._active_recd == recd: self.model.set_state(constants.STATE_READY) self._remove_thumbnail(recdbutton) def _thumbnail_copy_clipboard(self, recdbutton): self._copy_to_clipboard(recdbutton.get_recd()) def _copy_to_clipboard(self, recd): if recd == None: return if not recd.isClipboardCopyable(): return media_path = recd.getMediaFilepath() tmp_path = utils.getUniqueFilepath(media_path, 0) shutil.copyfile(media_path, tmp_path) gtk.Clipboard().set_with_data([('text/uri-list', 0, 0)], self._clipboard_get, self._clipboard_clear, tmp_path) def set_shutter_sensitive(self, value): self._shutter_button.set_sensitive(value) class ShutterButton(gtk.Button): def __init__(self): gtk.Button.__init__(self) self.set_relief(gtk.RELIEF_NONE) self.set_focus_on_click(False) self.modify_bg(gtk.STATE_ACTIVE, COLOR_BLACK) path = os.path.join(constants.GFX_PATH, 'media-record.png') self._rec_image = gtk.image_new_from_file(path) path = os.path.join(constants.GFX_PATH, 'media-record-red.png') self._rec_red_image = gtk.image_new_from_file(path) path = os.path.join(constants.GFX_PATH, 'media-insensitive.png') self._insensitive_image = gtk.image_new_from_file(path) self.set_normal() def set_sensitive(self, sensitive): if sensitive: self.set_image(self._rec_image) else: self.set_image(self._insensitive_image) super(ShutterButton, self).set_sensitive(sensitive) def set_normal(self): self.set_image(self._rec_image) def set_recording(self): self.set_image(self._rec_red_image) class RecordContainer(gtk.Container): """ A custom Container that contains a media view area, and a controls hbox. The controls hbox is given the first height that it requests, locked in for the duration of the widget. The media view is given the remainder of the space, but is constrained to a strict 4:3 ratio, therefore deducing its width. The controls hbox is given the same width, and both elements are centered horizontall.y """ __gtype_name__ = 'RecordContainer' def __init__(self, media_view, controls_hbox): self._media_view = media_view self._controls_hbox = controls_hbox self._controls_hbox_height = 0 super(RecordContainer, self).__init__() for widget in (self._media_view, self._controls_hbox): if widget.flags() & gtk.REALIZED: widget.set_parent_window(self.window) widget.set_parent(self) def do_realize(self): self.set_flags(gtk.REALIZED) self.window = gdk.Window( self.get_parent_window(), window_type=gdk.WINDOW_CHILD, x=self.allocation.x, y=self.allocation.y, width=self.allocation.width, height=self.allocation.height, wclass=gdk.INPUT_OUTPUT, colormap=self.get_colormap(), event_mask=self.get_events() | gdk.VISIBILITY_NOTIFY_MASK | gdk.EXPOSURE_MASK) self.window.set_user_data(self) self.set_style(self.style.attach(self.window)) for widget in (self._media_view, self._controls_hbox): widget.set_parent_window(self.window) self.queue_resize() # GTK+ contains on exit if remove is not implemented def do_remove(self, widget): pass def do_size_request(self, req): # always request 320x240 (as a minimum for video) req.width = 320 req.height = 240 self._media_view.size_request() w, h = self._controls_hbox.size_request() # add on height requested by controls hbox if self._controls_hbox_height == 0: self._controls_hbox_height = h req.height += self._controls_hbox_height @staticmethod def _constrain_4_3(width, height): if (width % 4 == 0) and (height % 3 == 0) and ((width / 4) * 3) == height: return width, height # nothing to do ratio = 4.0 / 3.0 if ratio * height > width: width = (width / 4) * 4 height = int(width / ratio) else: height = (height / 3) * 3 width = int(ratio * height) return width, height @staticmethod def _center_in_plane(plane_size, size): return (plane_size - size) / 2 def do_size_allocate(self, allocation): self.allocation = allocation # give the controls hbox the height that it requested remaining_height = self.allocation.height - self._controls_hbox_height # give the mediaview the rest, constrained to 4/3 and centered media_view_width, media_view_height = self._constrain_4_3(self.allocation.width, remaining_height) media_view_x = self._center_in_plane(self.allocation.width, media_view_width) media_view_y = self._center_in_plane(remaining_height, media_view_height) # send allocation to mediaview alloc = gdk.Rectangle() alloc.width = media_view_width alloc.height = media_view_height alloc.x = media_view_x alloc.y = media_view_y self._media_view.size_allocate(alloc) # position hbox at the bottom of the window, with the requested height, # and the same width as the media view alloc = gdk.Rectangle() alloc.x = media_view_x alloc.y = self.allocation.height - self._controls_hbox_height alloc.width = media_view_width alloc.height = self._controls_hbox_height self._controls_hbox.size_allocate(alloc) if self.flags() & gtk.REALIZED: self.window.move_resize(*allocation) def do_forall(self, include_internals, callback, data): for widget in (self._media_view, self._controls_hbox): callback(widget, data)