class ShotValidation(AdhocView): view_name = _("Shot validation view") view_id = 'shotvalidation' tooltip=_("Display shot validation interface") def __init__(self, controller=None, parameters=None, annotationtype=None): super(ShotValidation, self).__init__(controller=controller) self.close_on_package_load = True self.contextual_actions = () self.controller=controller self._annotationtype=None self.current_index = Gtk.Adjustment.new(10, 1, 1000, 1, 1, 1) self.options={} # Load options opt, arg = self.load_parameters(parameters) self.options.update(opt) self.annotationtype=annotationtype self.widget = self.build_widget() def set_annotationtype(self, at): self._annotationtype=at if self._annotationtype is not None: self.annotations = sorted(at.annotations, key=lambda a: a.fragment.begin) else: self.annotations = [] self.current_index.set_upper(len(self.annotations) + 2) def get_annotationtype(self): return self._annotationtype annotationtype=property(get_annotationtype, set_annotationtype) def set_title(self, s): self.title_widget.set_markup(s) def set_index(self, i): self.current_index.set_value(i + 1) def get_index(self): return int(self.current_index.get_value()) - 1 index = property(get_index, set_index) def update_annotationtype(self, annotationtype=None, event=None): if annotationtype == self.annotationtype and event == 'AnnotationTypeDelete': self.close() return True def update_annotation(self, annotation=None, event=None): if annotation.type == self.annotationtype and event in ('AnnotationCreate', 'AnnotationDelete'): # Update annotation type, which will trigger an update of self.annotations self.annotationtype = annotation.type self.current_index.emit('value-changed') def goto_current(self, *p): """Select annotation containing current player time. """ l=[ a for a in self.annotations if self.controller.player.current_position_value in a.fragment ] if l: self.set_index(self.annotations.index(l[0])) return True def merge(self, *p): """Merge the annotation with the previous one. """ i = self.index if i == 0: return True annotation = self.annotations[i] previous = self.annotations[i - 1] batch=object() self.controller.notify('EditSessionStart', element=previous, immediate=True) previous.fragment.end = annotation.fragment.end self.controller.notify('AnnotationEditEnd', annotation=previous, batch=batch) self.controller.notify('EditSessionEnd', element=previous) self.annotations.remove(annotation) self.controller.delete_element(annotation, immediate_notify=True, batch=batch) self.message(_("Merged #%(first)d-#%(second)d into #%(first)d" % { 'first': i + 1, 'second': i + 2 })) self.undo_button.set_sensitive(True) # We want to display the next annotation, i.e. at i. But we # were already at i, so the handle_index_change would not be # triggered. Force value-changed emission self.set_index(i) self.current_index.emit('value-changed') return True def handle_scroll_event(self, widget, event): return self.selector.handle_scroll_event(widget, event) def handle_keypress(self, widget, event): if self.selector.handle_key_press(widget, event): return True elif event.keyval == Gdk.KEY_Page_Up or event.keyval == Gdk.KEY_Up: # Next annotation self.set_index(self.index + 1) return True elif event.keyval == Gdk.KEY_Page_Down or event.keyval == Gdk.KEY_Down: # Previous annotation self.set_index(self.index - 1) return True return False def undo(self, *p): """Undo the last modification. """ self.message(_("Last action undone")) self.controller.gui.undo() if self.index > 0: self.index = self.index - 1 return True def validate_and_next(self, new): """Validate the current annotation and display the next one. """ i = self.index annotation = self.annotations[i] batch=object() event = Gtk.get_current_event() if event.get_state().state & Gdk.ModifierType.CONTROL_MASK: # Control-key is held. Split the annotation. if new > annotation.fragment.begin and new < annotation.fragment.end: self.controller.split_annotation(annotation, new) self.message(_("Split annotation #%(current)d into #%(current)d and #%(next)d") % { 'current': i + 1, 'next': i + 2 }) else: self.message(_("Cannot split annotation #%(current)d: out of bounds.") % { 'current': i + 1, }) return True if new != annotation.fragment.begin: logger.debug("Updating annotation begin from %s to %s", helper.format_time(annotation.fragment.begin), helper.format_time_reference(new)) self.controller.notify('EditSessionStart', element=annotation, immediate=True) annotation.fragment.begin = new self.controller.notify('AnnotationEditEnd', annotation=annotation, batch=batch) self.controller.notify('EditSessionEnd', element=annotation) self.undo_button.set_sensitive(True) # Update previous annotation end. if i > 0: annotation = self.annotations[i - 1] if new != annotation.fragment.end: self.controller.notify('EditSessionStart', element=annotation, immediate=True) annotation.fragment.end = new self.controller.notify('AnnotationEditEnd', annotation=annotation, batch=batch) self.controller.notify('EditSessionEnd', element=annotation) self.message(_("Changed cut between #%(first)d and %(second)d") % { 'first': i + 1, 'second': i + 2 }) else: self.message(_("Changed begin time for first annotation")) self.set_index(i + 1) return True def build_widget(self): if not self.annotations: return Gtk.Label(label=(_("No annotations to adjust"))) vbox = Gtk.VBox() self.title_widget = Gtk.Label() vbox.pack_start(self.title_widget, True, True, 0) self.selector = FrameSelector(self.controller, self.annotations[0].fragment.begin, label=_("Click on the frame just after the cut to adjust the cut time.\nControl-click on a frame to indicate a missing cut.")) self.selector.callback = self.validate_and_next def handle_index_change(adj): i = int(adj.get_value()) - 1 if i >= 0 and i <= len(self.annotations) - 1: a=self.annotations[i] self.selector.set_timestamp(a.fragment.begin) self.set_title(_("Begin of #%(index)d (title: %(content)s)") % { 'index': i + 1, 'content': self.controller.get_title(a, max_size=60).replace('&', '&').replace('<', '<') }) self.prev_button.set_sensitive(i > 0) self.next_button.set_sensitive(i < len(self.annotations) - 1) else: # End: display a message ? pass self.current_index.connect('value-changed', handle_index_change) vbox.add(self.selector.widget) # Button bar hb=Gtk.HBox() self.prev_button = Gtk.Button(_("< Previous cut")) self.prev_button.set_tooltip_text(_("Display previous cut")) self.prev_button.connect("clicked", lambda b: self.set_index(self.index - 1)) hb.add(self.prev_button) l = Gtk.Label(label="#") hb.pack_start(l, False, True, 0) self.next_button = Gtk.Button(_("Next cut >")) self.next_button.set_tooltip_text(_("Display next cut")) self.next_button.connect("clicked", lambda b: self.set_index(self.index + 1)) s=Gtk.SpinButton.new(self.current_index, 1, 0) s.set_increments(1, 10) #s.set_update_policy(Gtk.UPDATE_IF_VALID) s.set_numeric(True) hb.add(s) hb.add(self.next_button) vbox.pack_start(hb, False, True, 0) hb = Gtk.HButtonBox() b=Gtk.Button(_("Current time")) b.set_tooltip_text(_("Go to annotation containing current player time.")) b.connect("clicked", self.goto_current) hb.add(b) b=Gtk.Button(_("Refresh")) b.set_tooltip_text(_("Refresh missing snapshots")) b.connect("clicked", lambda b: self.selector.refresh_snapshots()) hb.add(b) b=Gtk.Button(_("Undo")) b.set_tooltip_text(_("Undo last modification")) b.connect("clicked", self.undo) hb.add(b) b.set_sensitive(False) self.undo_button = b b=Gtk.Button(_("Merge")) b.set_tooltip_text(_("Merge with previous annotation, i.e. remove this bound.")) b.connect("clicked", self.merge) hb.add(b) b=Gtk.Button(stock=Gtk.STOCK_CLOSE) b.set_tooltip_text(_("Close view.")) b.connect("clicked", self.close) hb.add(b) vbox.pack_start(hb, False, True, 0) self.statusbar = Gtk.Statusbar() vbox.pack_start(self.statusbar, False, True, 0) self.set_index(0) vbox.connect('key-press-event', self.handle_keypress) vbox.connect('scroll-event', self.handle_scroll_event) vbox.show_all() # Hack: since the view if often launched from the timeline # view, moving the mouse in timeline steals the focus from the # window. Let's only grab focus after a small timeout, so that # the user has time to get the mouse out of the timeline # window GObject.timeout_add(2000, lambda: self.next_button.grab_focus()) return vbox
def build_widget(self): if not self.annotations: return Gtk.Label(label=(_("No annotations to adjust"))) vbox = Gtk.VBox() self.title_widget = Gtk.Label() vbox.pack_start(self.title_widget, True, True, 0) self.selector = FrameSelector(self.controller, self.annotations[0].fragment.begin, label=_("Click on the frame just after the cut to adjust the cut time.\nControl-click on a frame to indicate a missing cut.")) self.selector.callback = self.validate_and_next def handle_index_change(adj): i = int(adj.get_value()) - 1 if i >= 0 and i <= len(self.annotations) - 1: a=self.annotations[i] self.selector.set_timestamp(a.fragment.begin) self.set_title(_("Begin of #%(index)d (title: %(content)s)") % { 'index': i + 1, 'content': self.controller.get_title(a, max_size=60).replace('&', '&').replace('<', '<') }) self.prev_button.set_sensitive(i > 0) self.next_button.set_sensitive(i < len(self.annotations) - 1) else: # End: display a message ? pass self.current_index.connect('value-changed', handle_index_change) vbox.add(self.selector.widget) # Button bar hb=Gtk.HBox() self.prev_button = Gtk.Button(_("< Previous cut")) self.prev_button.set_tooltip_text(_("Display previous cut")) self.prev_button.connect("clicked", lambda b: self.set_index(self.index - 1)) hb.add(self.prev_button) l = Gtk.Label(label="#") hb.pack_start(l, False, True, 0) self.next_button = Gtk.Button(_("Next cut >")) self.next_button.set_tooltip_text(_("Display next cut")) self.next_button.connect("clicked", lambda b: self.set_index(self.index + 1)) s=Gtk.SpinButton.new(self.current_index, 1, 0) s.set_increments(1, 10) #s.set_update_policy(Gtk.UPDATE_IF_VALID) s.set_numeric(True) hb.add(s) hb.add(self.next_button) vbox.pack_start(hb, False, True, 0) hb = Gtk.HButtonBox() b=Gtk.Button(_("Current time")) b.set_tooltip_text(_("Go to annotation containing current player time.")) b.connect("clicked", self.goto_current) hb.add(b) b=Gtk.Button(_("Refresh")) b.set_tooltip_text(_("Refresh missing snapshots")) b.connect("clicked", lambda b: self.selector.refresh_snapshots()) hb.add(b) b=Gtk.Button(_("Undo")) b.set_tooltip_text(_("Undo last modification")) b.connect("clicked", self.undo) hb.add(b) b.set_sensitive(False) self.undo_button = b b=Gtk.Button(_("Merge")) b.set_tooltip_text(_("Merge with previous annotation, i.e. remove this bound.")) b.connect("clicked", self.merge) hb.add(b) b=Gtk.Button(stock=Gtk.STOCK_CLOSE) b.set_tooltip_text(_("Close view.")) b.connect("clicked", self.close) hb.add(b) vbox.pack_start(hb, False, True, 0) self.statusbar = Gtk.Statusbar() vbox.pack_start(self.statusbar, False, True, 0) self.set_index(0) vbox.connect('key-press-event', self.handle_keypress) vbox.connect('scroll-event', self.handle_scroll_event) vbox.show_all() # Hack: since the view if often launched from the timeline # view, moving the mouse in timeline steals the focus from the # window. Let's only grab focus after a small timeout, so that # the user has time to get the mouse out of the timeline # window GObject.timeout_add(2000, lambda: self.next_button.grab_focus()) return vbox
class ShotValidation(AdhocView): view_name = _("Shot validation view") view_id = 'shotvalidation' tooltip = _("Display shot validation interface") def __init__(self, controller=None, parameters=None, annotationtype=None): super(ShotValidation, self).__init__(controller=controller) self.close_on_package_load = True self.contextual_actions = () self.controller = controller self._annotationtype = None self.current_index = Gtk.Adjustment.new(10, 1, 1000, 1, 1, 1) self.options = {} # Load options opt, arg = self.load_parameters(parameters) self.options.update(opt) self.annotationtype = annotationtype self.widget = self.build_widget() def set_annotationtype(self, at): self._annotationtype = at if self._annotationtype is not None: self.annotations = sorted(at.annotations, key=lambda a: a.fragment.begin) else: self.annotations = [] self.current_index.set_upper(len(self.annotations) + 2) def get_annotationtype(self): return self._annotationtype annotationtype = property(get_annotationtype, set_annotationtype) def set_title(self, s): self.title_widget.set_markup(s) def set_index(self, i): self.current_index.set_value(i + 1) def get_index(self): return int(self.current_index.get_value()) - 1 index = property(get_index, set_index) def update_annotationtype(self, annotationtype=None, event=None): if annotationtype == self.annotationtype and event == 'AnnotationTypeDelete': self.close() return True def update_annotation(self, annotation=None, event=None): if annotation.type == self.annotationtype and event in ( 'AnnotationCreate', 'AnnotationDelete'): # Update annotation type, which will trigger an update of self.annotations self.annotationtype = annotation.type self.current_index.emit('value-changed') def goto_current(self, *p): """Select annotation containing current player time. """ l = [ a for a in self.annotations if self.controller.player.current_position_value in a.fragment ] if l: self.set_index(self.annotations.index(l[0])) return True def merge(self, *p): """Merge the annotation with the previous one. """ i = self.index if i == 0: return True annotation = self.annotations[i] previous = self.annotations[i - 1] batch = object() self.controller.notify('EditSessionStart', element=previous, immediate=True) previous.fragment.end = annotation.fragment.end self.controller.notify('AnnotationEditEnd', annotation=previous, batch=batch) self.controller.notify('EditSessionEnd', element=previous) self.annotations.remove(annotation) self.controller.delete_element(annotation, immediate_notify=True, batch=batch) self.message( _("Merged #%(first)d-#%(second)d into #%(first)d" % { 'first': i + 1, 'second': i + 2 })) self.undo_button.set_sensitive(True) # We want to display the next annotation, i.e. at i. But we # were already at i, so the handle_index_change would not be # triggered. Force value-changed emission self.set_index(i) self.current_index.emit('value-changed') return True def handle_scroll_event(self, widget, event): return self.selector.handle_scroll_event(widget, event) def handle_keypress(self, widget, event): if self.selector.handle_key_press(widget, event): return True elif event.keyval == Gdk.KEY_Page_Up or event.keyval == Gdk.KEY_Up: # Next annotation self.set_index(self.index + 1) return True elif event.keyval == Gdk.KEY_Page_Down or event.keyval == Gdk.KEY_Down: # Previous annotation self.set_index(self.index - 1) return True return False def undo(self, *p): """Undo the last modification. """ self.message(_("Last action undone")) self.controller.gui.undo() if self.index > 0: self.index = self.index - 1 return True def validate_and_next(self, new): """Validate the current annotation and display the next one. """ i = self.index annotation = self.annotations[i] batch = object() event = Gtk.get_current_event() if event.get_state().state & Gdk.ModifierType.CONTROL_MASK: # Control-key is held. Split the annotation. if new > annotation.fragment.begin and new < annotation.fragment.end: self.controller.split_annotation(annotation, new) self.message( _("Split annotation #%(current)d into #%(current)d and #%(next)d" ) % { 'current': i + 1, 'next': i + 2 }) else: self.message( _("Cannot split annotation #%(current)d: out of bounds.") % { 'current': i + 1, }) return True if new != annotation.fragment.begin: logger.debug("Updating annotation begin from %s to %s", helper.format_time(annotation.fragment.begin), helper.format_time_reference(new)) self.controller.notify('EditSessionStart', element=annotation, immediate=True) annotation.fragment.begin = new self.controller.notify('AnnotationEditEnd', annotation=annotation, batch=batch) self.controller.notify('EditSessionEnd', element=annotation) self.undo_button.set_sensitive(True) # Update previous annotation end. if i > 0: annotation = self.annotations[i - 1] if new != annotation.fragment.end: self.controller.notify('EditSessionStart', element=annotation, immediate=True) annotation.fragment.end = new self.controller.notify('AnnotationEditEnd', annotation=annotation, batch=batch) self.controller.notify('EditSessionEnd', element=annotation) self.message( _("Changed cut between #%(first)d and %(second)d") % { 'first': i + 1, 'second': i + 2 }) else: self.message(_("Changed begin time for first annotation")) self.set_index(i + 1) return True def build_widget(self): if not self.annotations: return Gtk.Label(label=(_("No annotations to adjust"))) vbox = Gtk.VBox() self.title_widget = Gtk.Label() vbox.pack_start(self.title_widget, True, True, 0) self.selector = FrameSelector( self.controller, self.annotations[0].fragment.begin, label= _("Click on the frame just after the cut to adjust the cut time.\nControl-click on a frame to indicate a missing cut." )) self.selector.callback = self.validate_and_next def handle_index_change(adj): i = int(adj.get_value()) - 1 if i >= 0 and i <= len(self.annotations) - 1: a = self.annotations[i] self.selector.set_timestamp(a.fragment.begin) self.set_title( _("Begin of #%(index)d (title: %(content)s)") % { 'index': i + 1, 'content': self.controller.get_title(a, max_size=60).replace( '&', '&').replace('<', '<') }) self.prev_button.set_sensitive(i > 0) self.next_button.set_sensitive(i < len(self.annotations) - 1) else: # End: display a message ? pass self.current_index.connect('value-changed', handle_index_change) vbox.add(self.selector.widget) # Button bar hb = Gtk.HBox() self.prev_button = Gtk.Button(_("< Previous cut")) self.prev_button.set_tooltip_text(_("Display previous cut")) self.prev_button.connect("clicked", lambda b: self.set_index(self.index - 1)) hb.add(self.prev_button) l = Gtk.Label(label="#") hb.pack_start(l, False, True, 0) self.next_button = Gtk.Button(_("Next cut >")) self.next_button.set_tooltip_text(_("Display next cut")) self.next_button.connect("clicked", lambda b: self.set_index(self.index + 1)) s = Gtk.SpinButton.new(self.current_index, 1, 0) s.set_increments(1, 10) #s.set_update_policy(Gtk.UPDATE_IF_VALID) s.set_numeric(True) hb.add(s) hb.add(self.next_button) vbox.pack_start(hb, False, True, 0) hb = Gtk.HButtonBox() b = Gtk.Button(_("Current time")) b.set_tooltip_text( _("Go to annotation containing current player time.")) b.connect("clicked", self.goto_current) hb.add(b) b = Gtk.Button(_("Refresh")) b.set_tooltip_text(_("Refresh missing snapshots")) b.connect("clicked", lambda b: self.selector.refresh_snapshots()) hb.add(b) b = Gtk.Button(_("Undo")) b.set_tooltip_text(_("Undo last modification")) b.connect("clicked", self.undo) hb.add(b) b.set_sensitive(False) self.undo_button = b b = Gtk.Button(_("Merge")) b.set_tooltip_text( _("Merge with previous annotation, i.e. remove this bound.")) b.connect("clicked", self.merge) hb.add(b) b = Gtk.Button(stock=Gtk.STOCK_CLOSE) b.set_tooltip_text(_("Close view.")) b.connect("clicked", self.close) hb.add(b) vbox.pack_start(hb, False, True, 0) self.statusbar = Gtk.Statusbar() vbox.pack_start(self.statusbar, False, True, 0) self.set_index(0) vbox.connect('key-press-event', self.handle_keypress) vbox.connect('scroll-event', self.handle_scroll_event) vbox.show_all() # Hack: since the view if often launched from the timeline # view, moving the mouse in timeline steals the focus from the # window. Let's only grab focus after a small timeout, so that # the user has time to get the mouse out of the timeline # window GObject.timeout_add(2000, lambda: self.next_button.grab_focus()) return vbox
def build_widget(self): if not self.annotations: return Gtk.Label(label=(_("No annotations to adjust"))) vbox = Gtk.VBox() self.title_widget = Gtk.Label() vbox.pack_start(self.title_widget, True, True, 0) self.selector = FrameSelector( self.controller, self.annotations[0].fragment.begin, label= _("Click on the frame just after the cut to adjust the cut time.\nControl-click on a frame to indicate a missing cut." )) self.selector.callback = self.validate_and_next def handle_index_change(adj): i = int(adj.get_value()) - 1 if i >= 0 and i <= len(self.annotations) - 1: a = self.annotations[i] self.selector.set_timestamp(a.fragment.begin) self.set_title( _("Begin of #%(index)d (title: %(content)s)") % { 'index': i + 1, 'content': self.controller.get_title(a, max_size=60).replace( '&', '&').replace('<', '<') }) self.prev_button.set_sensitive(i > 0) self.next_button.set_sensitive(i < len(self.annotations) - 1) else: # End: display a message ? pass self.current_index.connect('value-changed', handle_index_change) vbox.add(self.selector.widget) # Button bar hb = Gtk.HBox() self.prev_button = Gtk.Button(_("< Previous cut")) self.prev_button.set_tooltip_text(_("Display previous cut")) self.prev_button.connect("clicked", lambda b: self.set_index(self.index - 1)) hb.add(self.prev_button) l = Gtk.Label(label="#") hb.pack_start(l, False, True, 0) self.next_button = Gtk.Button(_("Next cut >")) self.next_button.set_tooltip_text(_("Display next cut")) self.next_button.connect("clicked", lambda b: self.set_index(self.index + 1)) s = Gtk.SpinButton.new(self.current_index, 1, 0) s.set_increments(1, 10) #s.set_update_policy(Gtk.UPDATE_IF_VALID) s.set_numeric(True) hb.add(s) hb.add(self.next_button) vbox.pack_start(hb, False, True, 0) hb = Gtk.HButtonBox() b = Gtk.Button(_("Current time")) b.set_tooltip_text( _("Go to annotation containing current player time.")) b.connect("clicked", self.goto_current) hb.add(b) b = Gtk.Button(_("Refresh")) b.set_tooltip_text(_("Refresh missing snapshots")) b.connect("clicked", lambda b: self.selector.refresh_snapshots()) hb.add(b) b = Gtk.Button(_("Undo")) b.set_tooltip_text(_("Undo last modification")) b.connect("clicked", self.undo) hb.add(b) b.set_sensitive(False) self.undo_button = b b = Gtk.Button(_("Merge")) b.set_tooltip_text( _("Merge with previous annotation, i.e. remove this bound.")) b.connect("clicked", self.merge) hb.add(b) b = Gtk.Button(stock=Gtk.STOCK_CLOSE) b.set_tooltip_text(_("Close view.")) b.connect("clicked", self.close) hb.add(b) vbox.pack_start(hb, False, True, 0) self.statusbar = Gtk.Statusbar() vbox.pack_start(self.statusbar, False, True, 0) self.set_index(0) vbox.connect('key-press-event', self.handle_keypress) vbox.connect('scroll-event', self.handle_scroll_event) vbox.show_all() # Hack: since the view if often launched from the timeline # view, moving the mouse in timeline steals the focus from the # window. Let's only grab focus after a small timeout, so that # the user has time to get the mouse out of the timeline # window GObject.timeout_add(2000, lambda: self.next_button.grab_focus()) return vbox
def build_widget(self): if not self.annotations: return gtk.Label((_("No annotations to adjust"))) vbox = gtk.VBox() self.title_widget = gtk.Label() vbox.pack_start(self.title_widget) self.selector = FrameSelector(self.controller, self.annotations[0].fragment.begin, label=_("Click on the frame just after the cut to adjust the cut time.\nControl-click on a frame to indicate a missing cut.")) self.selector.callback = self.validate_and_next def handle_index_change(adj): i = int(adj.get_value()) - 1 if i >= 0 and i <= len(self.annotations) - 1: a=self.annotations[i] self.selector.set_timestamp(a.fragment.begin) self.set_title(_("Begin of #%(index)d (title: %(content)s)") % { 'index': i + 1, 'content': self.controller.get_title(a, max_size=60).replace('&', '&').replace('<', '<') }) self.prev_button.set_sensitive(i > 0) self.next_button.set_sensitive(i < len(self.annotations) - 1) else: # End: display a message ? pass self.current_index.connect('value-changed', handle_index_change) vbox.add(self.selector.widget) # Button bar hb=gtk.HBox() self.prev_button = gtk.Button(_("< Previous cut")) self.prev_button.set_tooltip_text(_("Display previous cut")) self.prev_button.connect("clicked", lambda b: self.set_index(self.index - 1)) hb.add(self.prev_button) l = gtk.Label("#") hb.pack_start(l, expand=False) self.next_button = gtk.Button(_("Next cut >")) self.next_button.set_tooltip_text(_("Display next cut")) self.next_button.connect("clicked", lambda b: self.set_index(self.index + 1)) s=gtk.SpinButton(self.current_index, 1, 0) s.set_increments(1, 10) s.set_update_policy(gtk.UPDATE_IF_VALID) s.set_numeric(True) # For an unknown reason, the default behaviour of updating # SpinButton through scroll does not work. Emulate it. def handle_spin_scroll(widget, event): if event.direction == gtk.gdk.SCROLL_UP: offset=+1 elif event.direction == gtk.gdk.SCROLL_DOWN: offset=-1 self.set_index(self.index + offset) return True s.connect('scroll-event', handle_spin_scroll) hb.add(s) hb.add(self.next_button) vbox.pack_start(hb, expand=False) hb = gtk.HButtonBox() b=gtk.Button(_("Current time")) b.set_tooltip_text(_("Go to annotation containing current player time.")) b.connect("clicked", self.goto_current) hb.add(b) b=gtk.Button(_("Refresh snapshots")) b.set_tooltip_text(_("Refresh missing snapshots")) b.connect("clicked", lambda b: self.selector.refresh_snapshots()) hb.add(b) b=gtk.Button(_("Undo")) b.set_tooltip_text(_("Undo last modification")) b.connect("clicked", self.undo) hb.add(b) b.set_sensitive(False) self.undo_button = b b=gtk.Button(_("Merge with previous")) b.set_tooltip_text(_("Merge with previous annotation, i.e. remove this bound.")) b.connect("clicked", self.merge) hb.add(b) b=gtk.Button(stock=gtk.STOCK_CLOSE) b.set_tooltip_text(_("Close view.")) b.connect("clicked", self.close) hb.add(b) vbox.pack_start(hb, expand=False) self.statusbar = gtk.Statusbar() vbox.pack_start(self.statusbar, expand=False) self.set_index(0) vbox.show_all() vbox.connect('key-press-event', self.handle_keypress) return vbox
class ShotValidation(AdhocView): view_name = _("Shot validation view") view_id = 'shotvalidation' tooltip=_("Display shot validation interface") def __init__(self, controller=None, parameters=None, annotationtype=None): super(ShotValidation, self).__init__(controller=controller) self.close_on_package_load = True self.contextual_actions = ( ) self.controller=controller self._annotationtype=None self.current_index = gtk.Adjustment(10, 1, 10, 1, 10) self.options={} # Load options opt, arg = self.load_parameters(parameters) self.options.update(opt) self.annotationtype=annotationtype self.widget = self.build_widget() def set_annotationtype(self, at): self._annotationtype=at self.annotations = list(at.annotations) self.current_index.set_upper(len(self.annotations)) def get_annotationtype(self): return self._annotationtype annotationtype=property(get_annotationtype, set_annotationtype) def set_title(self, s): self.title_widget.set_markup(s) def set_index(self, i): self.current_index.set_value(i + 1) def get_index(self): return int(self.current_index.get_value()) - 1 index = property(get_index, set_index) def update_annotationtype(self, annotationtype=None, event=None): if annotationtype == self.annotationtype and event == 'AnnotationTypeDelete': self.close() return True def update_annotation(self, annotation=None, event=None): if annotation.type == self.annotationtype and event in ('AnnotationCreate', 'AnnotationDelete'): # Update annotation type, which will trigger an update of self.annotations self.annotationtype = annotation.type self.current_index.emit('value-changed') def goto_current(self, *p): """Select annotation containing current player time. """ p = self.controller.player.current_position_value l=[ a for a in self.annotations if p >= a.begin and p <= a.end ] if l: self.set_index(self.annotations.index(l[0])) return True def merge(self, *p): """Merge the annotation with the previous one. """ i = self.index if i == 0: return True annotation = self.annotations[i] previous = self.annotations[i - 1] batch=object() self.controller.notify('EditSessionStart', element=previous, immediate=True) previous.end = annotation.end self.controller.notify('AnnotationEditEnd', annotation=previous, batch=batch) self.controller.notify('EditSessionEnd', element=previous) self.controller.delete_element(annotation, immediate_notify=True, batch=batch) self.message(_("Merged #%(first)d-#%(second)d into #%(first)d" % { 'first': i + 1, 'second': i + 2 })) self.undo_button.set_sensitive(True) # We want to display the next annotation, i.e. at i. But we # were already at i, so the handle_index_change would not be # triggered. Force value-changed emission self.set_index(i) self.current_index.emit('value-changed') return True def handle_keypress(self, widget, event): if event.keyval == gtk.keysyms.Page_Down: # Next annotation self.set_index(self.index + 1) return True elif event.keyval == gtk.keysyms.Page_Up: # Previous annotation self.set_index(self.index - 1) return True return False def undo(self, *p): """Undo the last modification. """ self.controller.gui.undo() if self.index > 0: self.index = self.index - 1 return True def validate_and_next(self, new): """Validate the current annotation and display the next one. """ i = self.index annotation = self.annotations[i] batch=object() if new != annotation.fragment.begin: self.controller.notify('EditSessionStart', element=annotation, immediate=True) annotation.begin = new self.controller.notify('AnnotationEditEnd', annotation=annotation, batch=batch) self.controller.notify('EditSessionEnd', element=annotation) self.undo_button.set_sensitive(True) # Update previous annotation end. if i > 0: annotation = self.annotations[i - 1] if new != annotation.end: self.controller.notify('EditSessionStart', element=annotation, immediate=True) annotation.end = new self.controller.notify('AnnotationEditEnd', annotation=annotation, batch=batch) self.controller.notify('EditSessionEnd', element=annotation) self.message(_("Validated cut between #%(first)d and %(second)d") % { 'first': i + 1, 'second': i + 2 }) else: self.message(_("Validated begin time for first annotation")) self.set_index(i + 1) return True def build_widget(self): if not self.annotations: return gtk.Label((_("No annotations to adjust"))) vbox = gtk.VBox() self.title_widget = gtk.Label() vbox.pack_start(self.title_widget) self.selector = FrameSelector(self.controller, self.annotations[0].begin) self.selector.callback = self.validate_and_next def handle_index_change(adj): i = int(adj.get_value()) - 1 if i >= 0 and i <= len(self.annotations) - 1: a=self.annotations[i] self.selector.set_timestamp(a.begin) self.set_title(_("Begin of #%(index)d (title: %(content)s)") % { 'index': i + 1, 'content': self.controller.get_title(a) }) self.prev_button.set_sensitive(i > 0) self.next_button.set_sensitive(i < len(self.annotations) - 1) else: # End: display a message ? pass self.current_index.connect('value-changed', handle_index_change) vbox.add(self.selector.widget) # Button bar hb=gtk.HBox() self.prev_button = gtk.Button(_("Previous cut")) self.prev_button.set_tooltip_text(_("Display previous cut")) self.prev_button.connect("clicked", lambda b: self.set_index(self.index - 1)) hb.add(self.prev_button) l = gtk.Label("#") hb.pack_start(l, expand=False) self.next_button = gtk.Button(_("Next cut")) self.next_button.set_tooltip_text(_("Display next cut")) self.next_button.connect("clicked", lambda b: self.set_index(self.index + 1)) s=gtk.SpinButton(self.current_index, 1, 0) s.set_increments(1, 10) s.set_update_policy(gtk.UPDATE_IF_VALID) s.set_numeric(True) # For an unknown reason, the default behaviour of updating # SpinButton through scroll does not work. Emulate it. def handle_spin_scroll(widget, event): if event.direction == gtk.gdk.SCROLL_UP: offset=+1 elif event.direction == gtk.gdk.SCROLL_DOWN: offset=-1 self.set_index(self.index + offset) return True s.connect('scroll-event', handle_spin_scroll) hb.add(s) hb.add(self.next_button) vbox.pack_start(hb, expand=False) hb = gtk.HBox() b=gtk.Button(_("Current time")) b.set_tooltip_text(_("Go to annotation containing current player time.")) b.connect("clicked", self.goto_current) hb.add(b) b=gtk.Button(_("Undo")) b.set_tooltip_text(_("Undo last modification")) b.connect("clicked", self.undo) hb.add(b) b.set_sensitive(False) self.undo_button = b b=gtk.Button(_("Merge with previous")) b.set_tooltip_text(_("Merge with previous annotation, i.e. remove this bound.")) b.connect("clicked", self.merge) hb.add(b) vbox.pack_start(hb, expand=False) self.statusbar = gtk.Statusbar() vbox.pack_start(self.statusbar, expand=False) self.set_index(0) vbox.show_all() vbox.connect('key-press-event', self.handle_keypress) return vbox