class TimeAdjustment: """TimeAdjustment widget. Note: time values are integers in milliseconds. """ def __init__(self, value=0, controller=None, videosync=False, editable=True, compact=False, callback=None): self.value=value self.controller=controller self.sync_video=videosync # Small increment self.small_increment=config.data.preferences['scroll-increment'] # Large increment self.large_increment=config.data.preferences['second-scroll-increment'] self.image=None self.editable=editable self.compact=compact # Callback is a method which will be called *before* setting # the new value. If it returns False, then the new value will # not be used. self.callback=callback self.widget=self.make_widget() self.update_display() def make_widget(self): def refresh_snapshot(item): self.image.refresh_snapshot() return True def image_button_clicked(button): event=gtk.get_current_event() if event.state & gtk.gdk.CONTROL_MASK: self.use_current_position(button) return True else: self.play_from_here(button) return True def image_button_press(button, event): if event.button == 3 and event.type == gtk.gdk.BUTTON_PRESS: # Display the popup menu menu = gtk.Menu() item = gtk.MenuItem(_("Refresh snapshot")) item.connect('activate', refresh_snapshot) menu.append(item) menu.show_all() menu.popup(None, None, None, 0, gtk.get_current_event_time()) return True return False def make_button(incr_value, pixmap): """Helper function to build the buttons.""" b=gtk.Button() i=gtk.Image() i.set_from_file(config.data.advenefile( ( 'pixmaps', pixmap) )) # FIXME: to re-enable # The proper way is to do #b.set_image(i) # but it works only on linux, gtk 2.10 # and is broken on windows and mac al=gtk.Alignment() al.set_padding(0, 0, 0, 0) al.add(i) b.add(al) b.connect('clicked', self.update_value_cb, incr_value) if incr_value < 0: tip=_("Decrement value by %.2f s") % (incr_value / 1000.0) else: tip=_("Increment value by %.2f s") % (incr_value / 1000.0) b.set_tooltip_text(tip) return b vbox=gtk.VBox() hbox=gtk.HBox() hbox.set_homogeneous(False) if self.editable: vb=gtk.VBox() b=make_button(-self.large_increment, "2leftarrow.png") vb.pack_start(b, expand=False) b=make_button(-self.small_increment, "1leftarrow.png") vb.pack_start(b, expand=False) hbox.pack_start(vb, expand=False) if self.compact: width=50 else: width=100 self.image=TimestampRepresentation(self.value, self.controller, width, epsilon=1000/25, visible_label=False) self.image.connect('button-press-event', image_button_press) self.image.connect('clicked', image_button_clicked) self.image.set_tooltip_text(_("Click to play\nControl+click to set to current time\Scroll to modify value (with control/shift)\nRight-click to invalidate screenshot")) hbox.pack_start(self.image, expand=False) if self.editable: vb=gtk.VBox() b=make_button(self.large_increment, "2rightarrow.png") vb.pack_start(b, expand=False) b=make_button(self.small_increment, "1rightarrow.png") vb.pack_start(b, expand=False) hbox.pack_start(vb, expand=False) hb = gtk.HBox() if self.editable: self.entry=gtk.Entry() # Default width of the entry field self.entry.set_width_chars(len(helper.format_time(0.0))) self.entry.connect('activate', self.convert_entered_value) self.entry.connect('focus-out-event', self.convert_entered_value) self.entry.set_editable(self.editable) hb.pack_start(self.entry, expand=False) else: self.entry=None if self.editable: current_pos=gtk.Button() i=gtk.Image() i.set_from_file(config.data.advenefile( ( 'pixmaps', 'set-to-now.png') )) current_pos.set_tooltip_text(_("Set to current player position")) current_pos.add(i) current_pos.connect('clicked', self.use_current_position) hb.pack_start(current_pos, expand=False) vbox.pack_start(hbox, expand=False) vbox.pack_start(hb, expand=False) hb.set_style(self.image.box.get_style()) #self.entry.set_style(self.image.box.get_style()) vbox.set_style(self.image.box.get_style()) vbox.show_all() hb.set_no_show_all(True) hbox.set_no_show_all(True) self.image.label.hide() hb.show() def handle_scroll_event(button, event): if event.state & gtk.gdk.CONTROL_MASK: i=config.data.preferences['scroll-increment'] elif event.state & gtk.gdk.SHIFT_MASK: i=config.data.preferences['second-scroll-increment'] else: # 1 frame i=1000/25 if event.direction == gtk.gdk.SCROLL_DOWN or event.direction == gtk.gdk.SCROLL_LEFT: incr=-i elif event.direction == gtk.gdk.SCROLL_UP or event.direction == gtk.gdk.SCROLL_RIGHT: incr=i v=self.value v += incr if self.callback and not self.callback(v): return True self.value=v self.update_display() return True if self.editable: # The widget can receive drops from annotations vbox.connect('drag-data-received', self.drag_received) vbox.drag_dest_set(gtk.DEST_DEFAULT_MOTION | gtk.DEST_DEFAULT_HIGHLIGHT | gtk.DEST_DEFAULT_ALL, config.data.drag_type['annotation'] + config.data.drag_type['timestamp'], gtk.gdk.ACTION_LINK) vbox.connect('scroll-event', handle_scroll_event) vbox.show_all() return vbox def drag_received(self, widget, context, x, y, selection, targetType, time): if targetType == config.data.target_type['annotation']: source_uri=unicode(selection.data, 'utf8').split('\n')[0] source=self.controller.package.get(source_uri) if self.callback and not self.callback(source.begin): return True self.value = source.begin self.update_display() elif targetType == config.data.target_type['timestamp']: data=decode_drop_parameters(selection.data) v=long(float(data['timestamp'])) if self.callback and not self.callback(v): return True self.value=v self.update_display() else: print "Unknown target type for drop: %d" % targetType return True def drag_sent(self, widget, context, selection, targetType, eventTime): """Handle the drag-sent event. """ if targetType == config.data.target_type['timestamp']: selection.set(selection.target, 8, encode_drop_parameters(timestamp=self.value)) return True elif targetType in ( config.data.target_type['text-plain'], config.data.target_type['TEXT'], config.data.target_type['STRING'] ): selection.set(selection.target, 8, helper.format_time(self.value)) return True return False def play_from_here(self, button): if self.controller.player.status == self.controller.player.PauseStatus: self.controller.update_status("set", self.value) elif self.controller.player.status != self.controller.player.PlayingStatus: self.controller.update_status("start", self.value) self.controller.update_status("set", self.value) return True def use_current_position(self, button): v=self.controller.player.current_position_value if self.callback and not self.callback(v): return True self.value=v self.update_display() return True def update_snapshot(self, button): # FIXME: to implement print "Not implemented yet." pass # Static values used in numericTime _hour = r'(?P<hour>\d+)' _minute = r'(?P<minute>\d+)' _second = r'(?P<second>\d+(\.\d+))' _time = _hour + r':' + _minute + r'(:' + _second + r')?' _timeRE = re.compile(_time, re.I) def numericTime(self, s): """Converts a time string into a long value. This function is inspired from the numdate.py example script from the egenix mxDateTime package. If the input string s is a valid time expression of the form hh:mm:ss.sss or hh:mm:ss or hh:mm, return the corresponding value in milliseconds (float), else None """ if s is None: return None dt = None match = TimeAdjustment._timeRE.search(s) if match is not None: hh = int(match.group('hour')) mm = int(match.group('minute')) second = match.group('second') if second: ss = float(second) else: ss = 0.0 dt=int(1000 * (ss + (60 * mm) + (3600 * hh))) return dt def convert_entered_value(self, *p): t=self.entry.get_text() v=self.numericTime(t) if v is not None and v != self.value: v=self.check_bound_value(v) if self.callback and not self.callback(v): return False self.value = v if self.sync_video: self.controller.move_position(self.value, relative=False) self.update_display() return False def check_bound_value(self, value): if value < 0: value = 0 elif (self.controller.cached_duration > 0 and value > self.controller.cached_duration): value = self.controller.cached_duration return value def update(self): self.update_display() def update_display(self): """Updates the value displayed in the entry according to the current value.""" self.entry.set_text(helper.format_time(self.value)) self.image.value=self.value def update_value_cb(self, widget, increment): if not self.editable: return True v=self.check_bound_value(self.value + increment) if self.callback and not self.callback(v): return True self.value=v if self.sync_video: self.controller.move_position(self.value, relative=False) self.update_display() return True def get_widget(self): return self.widget def get_value(self): return self.value
class TimeAdjustment: """TimeAdjustment widget. Note: time values are integers in milliseconds. """ def __init__(self, value=0, controller=None, videosync=False, editable=True, compact=False, callback=None): self.value = value self.controller = controller self.sync_video = videosync # Small increment self.small_increment = config.data.preferences['scroll-increment'] # Large increment self.large_increment = config.data.preferences[ 'second-scroll-increment'] self.image = None self.editable = editable self.compact = compact # Callback is a method which will be called *before* setting # the new value. If it returns False, then the new value will # not be used. self.callback = callback self.widget = self.make_widget() self.update_display() def make_widget(self): def refresh_snapshot(item): self.image.refresh_snapshot() return True def image_button_clicked(button): event = Gtk.get_current_event() if event.get_state().state & Gdk.ModifierType.CONTROL_MASK: self.use_current_position(button) return True else: self.play_from_here(button) return True def image_button_press(button, event): if event.button == 3 and event.type == Gdk.EventType.BUTTON_PRESS: # Display the popup menu menu = Gtk.Menu() item = Gtk.MenuItem(_("Refresh snapshot")) item.connect('activate', refresh_snapshot) menu.append(item) menu.show_all() menu.popup_at_pointer(None) return True return False def make_button(incr_value, pixmap): """Helper function to build the buttons.""" b = Gtk.Button() i = Gtk.Image() i.set_from_file(config.data.advenefile(('pixmaps', pixmap))) b.set_image(i) def increment_value_cb(widget, increment): self.set_value(self.value + increment) return True b.connect('clicked', increment_value_cb, incr_value) if incr_value < 0: tip = _("Decrement value by %.2f s") % (incr_value / 1000.0) else: tip = _("Increment value by %.2f s") % (incr_value / 1000.0) b.set_tooltip_text(tip) return b vbox = Gtk.VBox() hbox = Gtk.HBox() hbox.set_homogeneous(False) if self.editable: vb = Gtk.VBox() b = make_button(-self.large_increment, "2leftarrow.png") vb.pack_start(b, False, True, 0) b = make_button(-self.small_increment, "1leftarrow.png") vb.pack_start(b, False, True, 0) hbox.pack_start(vb, False, True, 0) if self.compact: width = 50 else: width = 100 self.image = TimestampRepresentation(self.value, None, self.controller, width, visible_label=False, callback=self.set_value) self.image.connect('button-press-event', image_button_press) self.image.connect('clicked', image_button_clicked) self.image.set_tooltip_text( _("Click to play\nControl+click to set to current time\nScroll to modify value (with control/shift)\nRight-click to invalidate screenshot" )) hbox.pack_start(self.image, False, True, 0) if self.editable: vb = Gtk.VBox() b = make_button(self.large_increment, "2rightarrow.png") vb.pack_start(b, False, True, 0) b = make_button(self.small_increment, "1rightarrow.png") vb.pack_start(b, False, True, 0) hbox.pack_start(vb, False, True, 0) hb = Gtk.HBox() if self.editable: self.entry = Gtk.Entry() self.entry.set_tooltip_text( _("Enter a timecode.\nAn integer value will be considered as milliseconds.\nA float value (12.2) will be considered as seconds.\nHH:MM:SS.sss values are possible." )) # Default width of the entry field self.entry.set_width_chars(len(helper.format_time(0.0))) self.entry.connect('activate', self.convert_entered_value) self.entry.connect('focus-out-event', self.convert_entered_value) self.entry.set_editable(self.editable) hb.pack_start(self.entry, False, True, 0) else: self.entry = None if self.editable: current_pos = Gtk.Button() i = Gtk.Image() i.set_from_file( config.data.advenefile(('pixmaps', 'set-to-now.png'))) current_pos.set_tooltip_text(_("Set to current player position")) current_pos.add(i) current_pos.connect('clicked', self.use_current_position) hb.pack_start(current_pos, False, True, 0) vbox.pack_start(hbox, False, True, 0) vbox.pack_start(hb, False, True, 0) hb.set_style(self.image.box.get_style()) #self.entry.set_style(self.image.box.get_style()) vbox.set_style(self.image.box.get_style()) vbox.show_all() hb.set_no_show_all(True) hbox.set_no_show_all(True) self.image.label.hide() hb.show() def handle_scroll_event(button, event): if event.get_state() & Gdk.ModifierType.CONTROL_MASK: i = config.data.preferences['scroll-increment'] elif event.get_state() & Gdk.ModifierType.SHIFT_MASK: i = config.data.preferences['second-scroll-increment'] else: # 1 frame i = self.controller.frame2time(1) if event.direction == Gdk.ScrollDirection.DOWN or event.direction == Gdk.ScrollDirection.LEFT: incr = -i elif event.direction == Gdk.ScrollDirection.UP or event.direction == Gdk.ScrollDirection.RIGHT: incr = i if not self.set_value(self.value + incr): return True return True if self.editable: # The widget can receive drops from annotations vbox.connect('drag-data-received', self.drag_received) vbox.drag_dest_set( Gtk.DestDefaults.MOTION | Gtk.DestDefaults.HIGHLIGHT | Gtk.DestDefaults.ALL, config.data.get_target_types('annotation', 'timestamp'), Gdk.DragAction.LINK) vbox.connect('scroll-event', handle_scroll_event) vbox.show_all() return vbox def drag_received(self, widget, context, x, y, selection, targetType, time): if targetType == config.data.target_type['annotation']: source_uri = str(selection.get_data(), 'utf8').split('\n')[0] source = self.controller.package.annotations.get(source_uri) self.set_value(source.fragment.begin) elif targetType == config.data.target_type['timestamp']: data = decode_drop_parameters(selection.get_data().decode('utf-8')) v = int(float(data['timestamp'])) self.set_value(v) else: logger.warning("Unknown target type for drop: %d", targetType) return True def drag_sent(self, widget, context, selection, targetType, eventTime): """Handle the drag-sent event. """ if targetType == config.data.target_type['timestamp']: selection.set(selection.get_target(), 8, encode_drop_parameters(timestamp=self.value)) return True elif targetType in (config.data.target_type['text-plain'], config.data.target_type['TEXT'], config.data.target_type['STRING']): selection.set(selection.get_target(), 8, helper.format_time(self.value)) return True return False def play_from_here(self, button): self.controller.update_status("seek", self.value) return True def use_current_position(self, button): self.set_value(self.controller.player.current_position_value) return True def update_snapshot(self, button): # FIXME: to implement logger.warning("Not implemented yet.") pass def convert_entered_value(self, *p): t = self.entry.get_text() v = helper.parse_time(t) if v is not None and v != self.value: if not self.set_value(v): return False return False def check_bound_value(self, value): if value < 0 or value is None: value = 0 elif (self.controller.cached_duration > 0 and value > self.controller.cached_duration): value = self.controller.cached_duration return value def update(self): self.update_display() def update_display(self): """Updates the value displayed in the entry according to the current value.""" self.entry.set_text(helper.format_time(self.value)) self.image.value = self.value def get_widget(self): return self.widget def get_value(self): return self.value def set_value(self, v): """Set the new value. The method does various consistency checks, and can leave the value unset if a callback is defined and returns False. """ if self.value == v: return True v = self.check_bound_value(v) if self.callback and not self.callback(v): return False self.value = v self.update_display() if self.sync_video: self.controller.update_status("seek", self.value) return True
def create_timestamp_mark(self, timestamp, it): def popup_goto (b): self.controller.update_status(status="seek", position=b.value) return True b=self.textview.get_buffer() b.begin_user_action() anchor=b.create_child_anchor(it) # Create the mark representation child=TimestampRepresentation(timestamp, None, self.controller, width=self.options['snapshot-size'], visible_label=False) child.anchor=anchor child.connect('clicked', popup_goto) child.popup_menu=None child.connect('button-press-event', self.mark_button_press_cb, anchor, child) b.end_user_action() def handle_scroll_event(button, event): if not (event.get_state() & Gdk.ModifierType.CONTROL_MASK): return False if event.get_state() & Gdk.ModifierType.SHIFT_MASK: i='second-scroll-increment' else: i='scroll-increment' if event.direction == Gdk.ScrollDirection.DOWN or event.direction == Gdk.ScrollDirection.RIGHT: button.value -= config.data.preferences[i] elif event.direction == Gdk.ScrollDirection.UP or event.direction == Gdk.ScrollDirection.LEFT: button.value += config.data.preferences[i] button.set_tooltip_text("%s" % helper.format_time(button.value)) # FIXME: find a way to do this in the new Gtk.Tooltip API? #if self.tooltips.active_tips_data is None: # button.emit('show-help', Gtk.WIDGET_HELP_TOOLTIP) self.timestamp_play = button.value button.grab_focus() return True def mark_key_release_cb(button, event, anchor=None, child=None): """Handler for key release on timestamp mark. """ # Control key released. Goto the position if we were scrolling a mark if self.timestamp_play is not None and (event.get_state() & Gdk.ModifierType.CONTROL_MASK): # self.timestamp_play contains the new value, but child.timestamp # as well. So we can use popup_goto self.timestamp_play = None popup_goto(child) return True return False child.connect('scroll-event', handle_scroll_event) child.connect('key-release-event', mark_key_release_cb, anchor, child) child.set_tooltip_text("%s" % helper.format_time(timestamp)) child.value=timestamp child.ignore=False self.update_mark(child) child.show_all() child.label.set_no_show_all(True) child.label.hide() self.textview.add_child_at_anchor(child, anchor) self.marks.append(child) self.marks.sort(key=lambda a: a.value) return child
class TimeAdjustment: """TimeAdjustment widget. Note: time values are integers in milliseconds. """ def __init__(self, value=0, controller=None, videosync=False, editable=True, compact=False, callback=None): self.value=value self.controller=controller self.sync_video=videosync # Small increment self.small_increment=config.data.preferences['scroll-increment'] # Large increment self.large_increment=config.data.preferences['second-scroll-increment'] self.image=None self.editable=editable self.compact=compact # Callback is a method which will be called *before* setting # the new value. If it returns False, then the new value will # not be used. self.callback=callback self.widget=self.make_widget() self.update_display() def make_widget(self): def refresh_snapshot(item): self.image.refresh_snapshot() return True def image_button_clicked(button): event=gtk.get_current_event() if event.state & gtk.gdk.CONTROL_MASK: self.use_current_position(button) return True else: self.play_from_here(button) return True def image_button_press(button, event): if event.button == 3 and event.type == gtk.gdk.BUTTON_PRESS: # Display the popup menu menu = gtk.Menu() item = gtk.MenuItem(_("Refresh snapshot")) item.connect('activate', refresh_snapshot) menu.append(item) menu.show_all() menu.popup(None, None, None, 0, gtk.get_current_event_time()) return True return False def make_button(incr_value, pixmap): """Helper function to build the buttons.""" b=gtk.Button() i=gtk.Image() i.set_from_file(config.data.advenefile( ( 'pixmaps', pixmap) )) # FIXME: to re-enable # The proper way is to do #b.set_image(i) # but it works only on linux, gtk 2.10 # and is broken on windows and mac al=gtk.Alignment() al.set_padding(0, 0, 0, 0) al.add(i) b.add(al) def increment_value_cb(widget, increment): self.set_value(self.value + increment) return True b.connect('clicked', increment_value_cb, incr_value) if incr_value < 0: tip=_("Decrement value by %.2f s") % (incr_value / 1000.0) else: tip=_("Increment value by %.2f s") % (incr_value / 1000.0) b.set_tooltip_text(tip) return b vbox=gtk.VBox() hbox=gtk.HBox() hbox.set_homogeneous(False) if self.editable: vb=gtk.VBox() b=make_button(-self.large_increment, "2leftarrow.png") vb.pack_start(b, expand=False) b=make_button(-self.small_increment, "1leftarrow.png") vb.pack_start(b, expand=False) hbox.pack_start(vb, expand=False) if self.compact: width=50 else: width=100 self.image=TimestampRepresentation(self.value, self.controller, width, epsilon=1000/config.data.preferences['default-fps'], visible_label=False, callback=self.set_value) self.image.connect('button-press-event', image_button_press) self.image.connect('clicked', image_button_clicked) self.image.set_tooltip_text(_("Click to play\nControl+click to set to current time\nScroll to modify value (with control/shift)\nRight-click to invalidate screenshot")) hbox.pack_start(self.image, expand=False) if self.editable: vb=gtk.VBox() b=make_button(self.large_increment, "2rightarrow.png") vb.pack_start(b, expand=False) b=make_button(self.small_increment, "1rightarrow.png") vb.pack_start(b, expand=False) hbox.pack_start(vb, expand=False) hb = gtk.HBox() if self.editable: self.entry=gtk.Entry() self.entry.set_tooltip_text(_("Enter a timecode.\nAn integer value will be considered as milliseconds.\nA float value (12.2) will be considered as seconds.\nHH:MM:SS.sss values are possible.")) # Default width of the entry field self.entry.set_width_chars(len(helper.format_time(0.0))) self.entry.connect('activate', self.convert_entered_value) self.entry.connect('focus-out-event', self.convert_entered_value) self.entry.set_editable(self.editable) hb.pack_start(self.entry, expand=False) else: self.entry=None if self.editable: current_pos=gtk.Button() i=gtk.Image() i.set_from_file(config.data.advenefile( ( 'pixmaps', 'set-to-now.png') )) current_pos.set_tooltip_text(_("Set to current player position")) current_pos.add(i) current_pos.connect('clicked', self.use_current_position) hb.pack_start(current_pos, expand=False) vbox.pack_start(hbox, expand=False) vbox.pack_start(hb, expand=False) hb.set_style(self.image.box.get_style()) #self.entry.set_style(self.image.box.get_style()) vbox.set_style(self.image.box.get_style()) vbox.show_all() hb.set_no_show_all(True) hbox.set_no_show_all(True) self.image.label.hide() hb.show() def handle_scroll_event(button, event): if event.state & gtk.gdk.CONTROL_MASK: i=config.data.preferences['scroll-increment'] elif event.state & gtk.gdk.SHIFT_MASK: i=config.data.preferences['second-scroll-increment'] else: # 1 frame i=1000 / config.data.preferences['default-fps'] if event.direction == gtk.gdk.SCROLL_DOWN or event.direction == gtk.gdk.SCROLL_LEFT: incr=-i elif event.direction == gtk.gdk.SCROLL_UP or event.direction == gtk.gdk.SCROLL_RIGHT: incr=i if not self.set_value(self.value + incr): return True return True if self.editable: # The widget can receive drops from annotations vbox.connect('drag-data-received', self.drag_received) vbox.drag_dest_set(gtk.DEST_DEFAULT_MOTION | gtk.DEST_DEFAULT_HIGHLIGHT | gtk.DEST_DEFAULT_ALL, config.data.drag_type['annotation'] + config.data.drag_type['timestamp'], gtk.gdk.ACTION_LINK) vbox.connect('scroll-event', handle_scroll_event) vbox.show_all() return vbox def drag_received(self, widget, context, x, y, selection, targetType, time): if targetType == config.data.target_type['annotation']: source_uri=unicode(selection.data, 'utf8').split('\n')[0] source=self.controller.package.annotations.get(source_uri) self.set_value(source.fragment.begin) elif targetType == config.data.target_type['timestamp']: data=decode_drop_parameters(selection.data) v=long(float(data['timestamp'])) self.set_value(v) else: print "Unknown target type for drop: %d" % targetType return True def drag_sent(self, widget, context, selection, targetType, eventTime): """Handle the drag-sent event. """ if targetType == config.data.target_type['timestamp']: selection.set(selection.target, 8, encode_drop_parameters(timestamp=self.value)) return True elif targetType in ( config.data.target_type['text-plain'], config.data.target_type['TEXT'], config.data.target_type['STRING'] ): selection.set(selection.target, 8, helper.format_time(self.value)) return True return False def play_from_here(self, button): self.controller.update_status("set", self.value) return True def use_current_position(self, button): self.set_value(self.controller.player.current_position_value) return True def update_snapshot(self, button): # FIXME: to implement print "Not implemented yet." pass def convert_entered_value(self, *p): t=unicode(self.entry.get_text()) v=helper.parse_time(t) if v is not None and v != self.value: if not self.set_value(v): return False return False def check_bound_value(self, value): if value < 0 or value is None: value = 0 elif (self.controller.cached_duration > 0 and value > self.controller.cached_duration): value = self.controller.cached_duration return value def update(self): self.update_display() def update_display(self): """Updates the value displayed in the entry according to the current value.""" self.entry.set_text(helper.format_time(self.value)) self.image.value=self.value def get_widget(self): return self.widget def get_value(self): return self.value def set_value(self, v): """Set the new value. The method does various consistency checks, and can leave the value unset if a callback is defined and returns False. """ if self.value == v: return True v = self.check_bound_value(v) if self.callback and not self.callback(v): return False self.value=v self.update_display() if self.sync_video: self.controller.move_position(self.value, relative=False) return True
def create_timestamp_mark(self, timestamp, it): def popup_goto (b): self.controller.update_status(status="seek", position=b.value) return True b=self.textview.get_buffer() b.begin_user_action() if self.options['mark-prefix']: b.insert(it, unescape_string(self.options['mark-prefix'])) anchor=b.create_child_anchor(it) if self.options['mark-suffix']: b.insert(it, unescape_string(self.options['mark-suffix'])) # Create the mark representation child=TimestampRepresentation(timestamp, None, self.controller, width=self.options['snapshot-size'], visible_label=False) child.anchor=anchor child.connect('clicked', popup_goto) child.popup_menu=None child.connect('button-press-event', self.mark_button_press_cb, anchor, child) b.end_user_action() def handle_scroll_event(button, event): if not (event.get_state() & Gdk.ModifierType.CONTROL_MASK): return False if event.get_state() & Gdk.ModifierType.SHIFT_MASK: i='second-scroll-increment' else: i='scroll-increment' if event.direction == Gdk.ScrollDirection.DOWN or event.direction == Gdk.ScrollDirection.RIGHT: button.value -= config.data.preferences[i] elif event.direction == Gdk.ScrollDirection.UP or event.direction == Gdk.ScrollDirection.LEFT: button.value += config.data.preferences[i] button.set_tooltip_text("%s" % helper.format_time(button.value)) # FIXME: find a way to do this in the new Gtk.Tooltip API? #if self.tooltips.active_tips_data is None: # button.emit('show-help', Gtk.WIDGET_HELP_TOOLTIP) self.timestamp_play = button.value button.grab_focus() return True def mark_key_release_cb(button, event, anchor=None, child=None): """Handler for key release on timestamp mark. """ # Control key released. Goto the position if we were scrolling a mark if self.timestamp_play is not None and (event.get_state() & Gdk.ModifierType.CONTROL_MASK): # self.timestamp_play contains the new value, but child.timestamp # as well. So we can use popup_goto self.timestamp_play = None popup_goto(child) return True return False child.connect('scroll-event', handle_scroll_event) child.connect('key-release-event', mark_key_release_cb, anchor, child) child.set_tooltip_text("%s" % helper.format_time(timestamp)) child.value=timestamp child.ignore=False self.update_mark(child) child.show_all() child.label.set_no_show_all(True) child.label.hide() self.textview.add_child_at_anchor(child, anchor) self.marks.append(child) self.marks.sort(key=lambda a: a.value) return child