def __init__(self, parent, project): self.project = project self.settings = project.getSettings() self.builder = gtk.Builder() self.builder.add_from_file(os.path.join(get_ui_dir(), "projectsettings.ui")) self._setProperties() self.builder.connect_signals(self) # add custom display aspect ratio widget self.dar_fraction_widget = FractionWidget() self.video_properties_table.attach(self.dar_fraction_widget, 0, 1, 6, 7, xoptions=gtk.EXPAND | gtk.FILL, yoptions=0) self.dar_fraction_widget.show() # add custom pixel aspect ratio widget self.par_fraction_widget = FractionWidget() self.video_properties_table.attach(self.par_fraction_widget, 1, 2, 6, 7, xoptions=gtk.EXPAND | gtk.FILL, yoptions=0) self.par_fraction_widget.show() # add custom framerate widget self.frame_rate_fraction_widget = FractionWidget() self.video_properties_table.attach(self.frame_rate_fraction_widget, 1, 2, 2, 3, xoptions=gtk.EXPAND | gtk.FILL, yoptions=0) self.frame_rate_fraction_widget.show() # populate coboboxes with appropriate data self.frame_rate_combo.set_model(frame_rates) self.dar_combo.set_model(display_aspect_ratios) self.par_combo.set_model(pixel_aspect_ratios) self.channels_combo.set_model(audio_channels) self.sample_rate_combo.set_model(audio_rates) self.sample_depth_combo.set_model(audio_depths) # set the project metadata # FIXME: not saved in the project file if self.year_spinbutton.get_value_as_int() == 1900: self.year_spinbutton.set_value(datetime.now().year) if self.author_entry.get_text() == "": self.full_user_name = getpwuid(os.getuid()).pw_gecos.split(",")[0] self.author_entry.set_text(self.full_user_name) # behavior self.wg = RippleUpdateGroup() self.wg.addVertex(self.frame_rate_combo, signal="changed", update_func=self._updateCombo, update_func_args=(self.frame_rate_fraction_widget,)) self.wg.addVertex(self.frame_rate_fraction_widget, signal="value-changed", update_func=self._updateFraction, update_func_args=(self.frame_rate_combo,)) self.wg.addVertex(self.dar_combo, signal="changed") self.wg.addVertex(self.dar_fraction_widget, signal="value-changed") self.wg.addVertex(self.par_combo, signal="changed") self.wg.addVertex(self.par_fraction_widget, signal="value-changed") self.wg.addVertex(self.width_spinbutton, signal="value-changed") self.wg.addVertex(self.height_spinbutton, signal="value-changed") self.wg.addVertex(self.save_audio_preset_button, update_func=self._updateAudioSaveButton) self.wg.addVertex(self.save_video_preset_button, update_func=self._updateVideoSaveButton) self.wg.addVertex(self.channels_combo, signal="changed") self.wg.addVertex(self.sample_rate_combo, signal="changed") self.wg.addVertex(self.sample_depth_combo, signal="changed") # constrain width and height IFF constrain_sar_button is active self.wg.addEdge(self.width_spinbutton, self.height_spinbutton, predicate=self.constrained, edge_func=self.updateHeight) self.wg.addEdge(self.height_spinbutton, self.width_spinbutton, predicate=self.constrained, edge_func=self.updateWidth) # keep framereate text field and combo in sync self.wg.addBiEdge(self.frame_rate_combo, self.frame_rate_fraction_widget) # keep dar text field and combo in sync self.wg.addEdge(self.dar_combo, self.dar_fraction_widget, edge_func=self.updateDarFromCombo) self.wg.addEdge(self.dar_fraction_widget, self.dar_combo, edge_func=self.updateDarFromFractionWidget) # keep par text field and combo in sync self.wg.addEdge(self.par_combo, self.par_fraction_widget, edge_func=self.updateParFromCombo) self.wg.addEdge(self.par_fraction_widget, self.par_combo, edge_func=self.updateParFromFractionWidget) # constrain DAR and PAR values. because the combo boxes are already # linked, we only have to link the fraction widgets together. self.wg.addEdge(self.par_fraction_widget, self.dar_fraction_widget, edge_func=self.updateDarFromPar) self.wg.addEdge(self.dar_fraction_widget, self.par_fraction_widget, edge_func=self.updateParFromDar) # update PAR when width/height change and the DAR checkbutton is # selected self.wg.addEdge(self.width_spinbutton, self.par_fraction_widget, predicate=self.darSelected, edge_func=self.updateParFromDar) self.wg.addEdge(self.height_spinbutton, self.par_fraction_widget, predicate=self.darSelected, edge_func=self.updateParFromDar) # update DAR when width/height change and the PAR checkbutton is # selected self.wg.addEdge(self.width_spinbutton, self.dar_fraction_widget, predicate=self.parSelected, edge_func=self.updateDarFromPar) self.wg.addEdge(self.height_spinbutton, self.dar_fraction_widget, predicate=self.parSelected, edge_func=self.updateDarFromPar) # presets self.audio_presets = AudioPresetManager() self.audio_presets.load() self.video_presets = VideoPresetManager() self.video_presets.load() self._fillPresetsTreeview( self.audio_preset_treeview, self.audio_presets, self._updateAudioPresetButtons) self._fillPresetsTreeview( self.video_preset_treeview, self.video_presets, self._updateVideoPresetButtons) # A map which tells which infobar should be used when displaying # an error for a preset manager. self._infobarForPresetManager = { self.audio_presets: self.audio_preset_infobar, self.video_presets: self.video_preset_infobar} # Bind the widgets in the Video tab to the Video Presets Manager. self.bindSpinbutton(self.video_presets, "width", self.width_spinbutton) self.bindSpinbutton(self.video_presets, "height", self.height_spinbutton) self.bindFractionWidget(self.video_presets, "frame-rate", self.frame_rate_fraction_widget) self.bindPar(self.video_presets) # Bind the widgets in the Audio tab to the Audio Presets Manager. self.bindCombo(self.audio_presets, "channels", self.channels_combo) self.bindCombo(self.audio_presets, "sample-rate", self.sample_rate_combo) self.bindCombo(self.audio_presets, "depth", self.sample_depth_combo) self.wg.addEdge(self.par_fraction_widget, self.save_video_preset_button) self.wg.addEdge(self.frame_rate_fraction_widget, self.save_video_preset_button) self.wg.addEdge(self.width_spinbutton, self.save_video_preset_button) self.wg.addEdge(self.height_spinbutton, self.save_video_preset_button) self.wg.addEdge(self.channels_combo, self.save_audio_preset_button) self.wg.addEdge(self.sample_rate_combo, self.save_audio_preset_button) self.wg.addEdge(self.sample_depth_combo, self.save_audio_preset_button) self.updateUI()
class ProjectSettingsDialog(): def __init__(self, parent, project): self.project = project self.settings = project.getSettings() self.builder = gtk.Builder() self.builder.add_from_file(os.path.join(get_ui_dir(), "projectsettings.ui")) self._setProperties() self.builder.connect_signals(self) # add custom display aspect ratio widget self.dar_fraction_widget = FractionWidget() self.video_properties_table.attach(self.dar_fraction_widget, 0, 1, 6, 7, xoptions=gtk.EXPAND | gtk.FILL, yoptions=0) self.dar_fraction_widget.show() # add custom pixel aspect ratio widget self.par_fraction_widget = FractionWidget() self.video_properties_table.attach(self.par_fraction_widget, 1, 2, 6, 7, xoptions=gtk.EXPAND | gtk.FILL, yoptions=0) self.par_fraction_widget.show() # add custom framerate widget self.frame_rate_fraction_widget = FractionWidget() self.video_properties_table.attach(self.frame_rate_fraction_widget, 1, 2, 2, 3, xoptions=gtk.EXPAND | gtk.FILL, yoptions=0) self.frame_rate_fraction_widget.show() # populate coboboxes with appropriate data self.frame_rate_combo.set_model(frame_rates) self.dar_combo.set_model(display_aspect_ratios) self.par_combo.set_model(pixel_aspect_ratios) self.channels_combo.set_model(audio_channels) self.sample_rate_combo.set_model(audio_rates) self.sample_depth_combo.set_model(audio_depths) # set the project metadata # FIXME: not saved in the project file if self.year_spinbutton.get_value_as_int() == 1900: self.year_spinbutton.set_value(datetime.now().year) if self.author_entry.get_text() == "": self.full_user_name = getpwuid(os.getuid()).pw_gecos.split(",")[0] self.author_entry.set_text(self.full_user_name) # behavior self.wg = RippleUpdateGroup( (self.frame_rate_combo, self._updateCombo, "changed", self.frame_rate_fraction_widget), (self.frame_rate_fraction_widget, self._updateFraction, "value-changed", self.frame_rate_combo), (self.dar_combo, None, "changed"), (self.dar_fraction_widget, None, "value-changed"), (self.par_combo, None, "changed"), (self.par_fraction_widget, None, "value-changed"), (self.width_spinbutton, None, "value-changed"), (self.height_spinbutton, None, "value-changed"), (self.save_audio_preset_button, self._updateAudioSaveButton), (self.save_video_preset_button, self._updateVideoSaveButton), (self.channels_combo,), (self.sample_rate_combo,), (self.sample_depth_combo,), ) # constrain width and height IFF constrain_sar_button is active self.wg.add_edge(self.width_spinbutton, self.height_spinbutton, self.constrained, self.updateHeight) self.wg.add_edge(self.height_spinbutton, self.width_spinbutton, self.constrained, self.updateWidth) # keep framereate text field and combo in sync self.wg.add_bi_edge(self.frame_rate_combo, self.frame_rate_fraction_widget) # keep dar text field and combo in sync self.wg.add_edge(self.dar_combo, self.dar_fraction_widget, edge_func=self.updateDarFromCombo) self.wg.add_edge(self.dar_fraction_widget, self.dar_combo, edge_func=self.updateDarFromFractionWidget) # keep par text field and combo in sync self.wg.add_edge(self.par_combo, self.par_fraction_widget, edge_func=self.updateParFromCombo) self.wg.add_edge(self.par_fraction_widget, self.par_combo, edge_func=self.updateParFromFractionWidget) # constrain DAR and PAR values. because the combo boxes are already # linked, we only have to link the fraction widgets together. self.wg.add_edge(self.par_fraction_widget, self.dar_fraction_widget, edge_func=self.updateDarFromPar) self.wg.add_edge(self.dar_fraction_widget, self.par_fraction_widget, edge_func=self.updateParFromDar) # update PAR when width/height change and the DAR checkbutton is # selected self.wg.add_edge(self.width_spinbutton, self.par_fraction_widget, predicate=self.darSelected, edge_func=self.updateParFromDar) self.wg.add_edge(self.height_spinbutton, self.par_fraction_widget, predicate=self.darSelected, edge_func=self.updateParFromDar) # update DAR when width/height change and the PAR checkbutton is # selected self.wg.add_edge(self.width_spinbutton, self.dar_fraction_widget, predicate=self.parSelected, edge_func=self.updateDarFromPar) self.wg.add_edge(self.height_spinbutton, self.dar_fraction_widget, predicate=self.parSelected, edge_func=self.updateDarFromPar) # presets self.audio_presets = AudioPresetManager() self.audio_presets.load() self.video_presets = VideoPresetManager() self.video_presets.load() self.fillTreeview(self.audio_preset_treeview, self.audio_presets) self.fillTreeview(self.video_preset_treeview, self.video_presets) self.bindSpinbutton(self.video_presets, "width", self.width_spinbutton) self.bindSpinbutton(self.video_presets, "height", self.height_spinbutton) self.bindFractionWidget(self.video_presets, "frame-rate", self.frame_rate_fraction_widget) self.bindPar(self.video_presets) self.bindCombo(self.audio_presets, "channels", self.channels_combo) self.bindCombo(self.audio_presets, "sample-rate", self.sample_rate_combo) self.bindCombo(self.audio_presets, "depth", self.sample_depth_combo) self.wg.add_edge(self.par_fraction_widget, self.save_video_preset_button) self.wg.add_edge(self.frame_rate_fraction_widget, self.save_video_preset_button) self.wg.add_edge(self.width_spinbutton, self.save_video_preset_button) self.wg.add_edge(self.height_spinbutton, self.save_video_preset_button) self.wg.add_edge(self.channels_combo, self.save_audio_preset_button) self.wg.add_edge(self.sample_rate_combo, self.save_audio_preset_button) self.wg.add_edge(self.sample_depth_combo, self.save_audio_preset_button) self.updateUI() def bindPar(self, mgr): def updatePar(value): # activate par so we can set the value self.select_par_radiobutton.props.active = True self.par_fraction_widget.setWidgetValue(value) mgr.bindWidget("par", updatePar, self.par_fraction_widget.getWidgetValue) def bindFractionWidget(self, mgr, name, widget): mgr.bindWidget(name, widget.setWidgetValue, widget.getWidgetValue) def bindCombo(self, mgr, name, widget): mgr.bindWidget(name, lambda x: set_combo_value(widget, x), lambda : get_combo_value(widget)) def bindSpinbutton(self, mgr, name, widget): mgr.bindWidget(name, lambda x: widget.set_value(float(x)), lambda : int(widget.get_value())) def presetNameEditedCb(self, renderer, path, new_text, mgr): mgr.renamePreset(path, new_text) mgr.cur_preset = new_text def fillTreeview(self, treeview, mgr): renderer = gtk.CellRendererText() renderer.props.editable = True column = gtk.TreeViewColumn("Preset", renderer, text=0) treeview.append_column(column) treeview.props.headers_visible = False model = mgr.getModel() treeview.set_model(model) model.connect("row-inserted", self._newPresetCb, column, renderer, treeview) renderer.connect("edited", self.presetNameEditedCb, mgr) treeview.get_selection().connect("changed", self._presetChangedCb, mgr) def _newPresetCb(self, model, path, iter_, column, renderer, treeview): treeview.set_cursor_on_cell(path, column, renderer, start_editing=True) treeview.grab_focus() def _presetChangedCb(self, selection, mgr): model, iter_ = selection.get_selected() if iter_: preset = model[iter_][0] else: preset = None mgr.restorePreset(preset) if mgr == self.audio_presets: self._updateAudioSaveButton(None, self.save_audio_preset_button) self.remove_audio_preset_button.set_sensitive(bool(preset)) else: self._updateVideoSaveButton(None, self.save_video_preset_button) self.remove_video_preset_button.set_sensitive(bool(preset)) def constrained(self): return self.constrain_sar_button.props.active def _updateFraction(self, unused, fraction, combo): fraction.setWidgetValue(get_combo_value(combo)) def _updateCombo(self, unused, combo, fraction): set_combo_value(combo, fraction.getWidgetValue()) def getSAR(self): width = int(self.width_spinbutton.get_value()) height = int(self.height_spinbutton.get_value()) return gst.Fraction(width, height) def _setProperties(self): self.window = self.builder.get_object("project-settings-dialog") self.video_properties_table = self.builder.get_object( "video_properties_table") self.video_properties_table = self.builder.get_object( "video_properties_table") self.frame_rate_combo = self.builder.get_object("frame_rate_combo") self.dar_combo = self.builder.get_object("dar_combo") self.par_combo = self.builder.get_object("par_combo") self.channels_combo = self.builder.get_object("channels_combo") self.sample_rate_combo = self.builder.get_object("sample_rate_combo") self.sample_depth_combo = self.builder.get_object("sample_depth_combo") self.year_spinbutton = self.builder.get_object("year_spinbutton") self.author_entry = self.builder.get_object("author_entry") self.width_spinbutton = self.builder.get_object("width_spinbutton") self.height_spinbutton = self.builder.get_object("height_spinbutton") self.save_audio_preset_button = self.builder.get_object( "save_audio_preset_button") self.save_video_preset_button = self.builder.get_object( "save_video_preset_button") self.audio_preset_treeview = self.builder.get_object( "audio_preset_treeview") self.video_preset_treeview = self.builder.get_object( "video_preset_treeview") self.select_par_radiobutton = self.builder.get_object( "select_par_radiobutton") self.remove_audio_preset_button = self.builder.get_object( "remove_audio_preset_button") self.remove_video_preset_button = self.builder.get_object( "remove_video_preset_button") self.constrain_sar_button = self.builder.get_object( "constrain_sar_button") self.select_dar_radiobutton = self.builder.get_object( "select_dar_radiobutton") def _constrainSarButtonToggledCb(self, button): if button.props.active: self.sar = self.getSAR() def _selectDarRadiobuttonToggledCb(self, button): state = button.props.active self.dar_fraction_widget.set_sensitive(state) self.dar_combo.set_sensitive(state) self.par_fraction_widget.set_sensitive(not state) self.par_combo.set_sensitive(not state) def _addAudioPresetButtonClickedCb(self, button): self.audio_presets.addPreset(_("New Preset"), { "channels" : get_combo_value(self.channels_combo), "sample-rate" : get_combo_value(self.sample_rate_combo), "depth" : get_combo_value(self.sample_depth_combo) }) def _removeAudioPresetButtonClickedCb(self, button): selection = self.audio_preset_treeview.get_selection() model, iter_ = selection.get_selected() if iter_: self.audio_presets.removePreset(model[iter_][0]) def _saveAudioPresetButtonClickedCb(self, button): self.audio_presets.savePreset() self.save_audio_preset_button.set_sensitive(False) def _addVideoPresetButtonClickedCb(self, button): self.video_presets.addPreset(_("New Preset"), { "width": int(self.width_spinbutton.get_value()), "height": int(self.height_spinbutton.get_value()), "frame-rate": self.frame_rate_fraction_widget.getWidgetValue(), "par": self.par_fraction_widget.getWidgetValue(), }) def _removeVideoPresetButtonClickedCb(self, button): selection = self.video_preset_treeview.get_selection() model, iter_ = selection.get_selected() if iter_: self.video_presets.removePreset(model[iter_][0]) def _saveVideoPresetClickedCb(self, button): self.video_presets.savePreset() self.save_video_preset_button.set_sensitive(False) def _updateAudioSaveButton(self, unused_in, button): button.set_sensitive(self.audio_presets.changed()) def _updateVideoSaveButton(self, unused_in, button): button.set_sensitive(self.video_presets.changed()) def darSelected(self): return self.select_dar_radiobutton.props.active def parSelected(self): return not self.darSelected() def updateWidth(self): height = int(self.height_spinbutton.get_value()) self.width_spinbutton.set_value(height * self.sar) def updateHeight(self): width = int(self.width_spinbutton.get_value()) self.height_spinbutton.set_value(width * (1 / self.sar)) def updateDarFromPar(self): par = self.par_fraction_widget.getWidgetValue() sar = self.getSAR() self.dar_fraction_widget.setWidgetValue(sar * par) def updateParFromDar(self): dar = self.dar_fraction_widget.getWidgetValue() sar = self.getSAR() self.par_fraction_widget.setWidgetValue(dar * (1 / sar)) def updateDarFromCombo(self): self.dar_fraction_widget.setWidgetValue(get_combo_value( self.dar_combo)) def updateDarFromFractionWidget(self): set_combo_value(self.dar_combo, self.dar_fraction_widget.getWidgetValue()) def updateParFromCombo(self): self.par_fraction_widget.setWidgetValue(get_combo_value( self.par_combo)) def updateParFromFractionWidget(self): set_combo_value(self.par_combo, self.par_fraction_widget.getWidgetValue()) def updateUI(self): self.width_spinbutton.set_value(self.settings.videowidth) self.height_spinbutton.set_value(self.settings.videoheight) # video self.frame_rate_fraction_widget.setWidgetValue(self.settings.videorate) self.par_fraction_widget.setWidgetValue(self.settings.videopar) # audio set_combo_value(self.channels_combo, self.settings.audiochannels) set_combo_value(self.sample_rate_combo, self.settings.audiorate) set_combo_value(self.sample_depth_combo, self.settings.audiodepth) self._selectDarRadiobuttonToggledCb(self.select_dar_radiobutton) def updateSettings(self): width = int(self.width_spinbutton.get_value()) height = int(self.height_spinbutton.get_value()) par = self.par_fraction_widget.getWidgetValue() frame_rate = self.frame_rate_fraction_widget.getWidgetValue() channels = get_combo_value(self.channels_combo) sample_rate = get_combo_value(self.sample_rate_combo) sample_depth = get_combo_value(self.sample_depth_combo) self.settings.setVideoProperties(width, height, frame_rate, par) self.settings.setAudioProperties(channels, sample_rate, sample_depth) self.project.setSettings(self.settings) def _responseCb(self, unused_widget, response): if response == gtk.RESPONSE_OK: self.updateSettings() self.audio_presets.save() self.video_presets.save() self.window.destroy()
class ProjectSettingsDialog(): def __init__(self, parent, project): self.project = project self.settings = project.getSettings() self.builder = gtk.Builder() self.builder.add_from_file(os.path.join(get_ui_dir(), "projectsettings.ui")) self._setProperties() self.builder.connect_signals(self) # add custom display aspect ratio widget self.dar_fraction_widget = FractionWidget() self.video_properties_table.attach(self.dar_fraction_widget, 0, 1, 6, 7, xoptions=gtk.EXPAND | gtk.FILL, yoptions=0) self.dar_fraction_widget.show() # add custom pixel aspect ratio widget self.par_fraction_widget = FractionWidget() self.video_properties_table.attach(self.par_fraction_widget, 1, 2, 6, 7, xoptions=gtk.EXPAND | gtk.FILL, yoptions=0) self.par_fraction_widget.show() # add custom framerate widget self.frame_rate_fraction_widget = FractionWidget() self.video_properties_table.attach(self.frame_rate_fraction_widget, 1, 2, 2, 3, xoptions=gtk.EXPAND | gtk.FILL, yoptions=0) self.frame_rate_fraction_widget.show() # populate coboboxes with appropriate data self.frame_rate_combo.set_model(frame_rates) self.dar_combo.set_model(display_aspect_ratios) self.par_combo.set_model(pixel_aspect_ratios) self.channels_combo.set_model(audio_channels) self.sample_rate_combo.set_model(audio_rates) self.sample_depth_combo.set_model(audio_depths) # set the project metadata # FIXME: not saved in the project file if self.year_spinbutton.get_value_as_int() == 1900: self.year_spinbutton.set_value(datetime.now().year) if self.author_entry.get_text() == "": self.full_user_name = getpwuid(os.getuid()).pw_gecos.split(",")[0] self.author_entry.set_text(self.full_user_name) # behavior self.wg = RippleUpdateGroup() self.wg.addVertex(self.frame_rate_combo, signal="changed", update_func=self._updateCombo, update_func_args=(self.frame_rate_fraction_widget,)) self.wg.addVertex(self.frame_rate_fraction_widget, signal="value-changed", update_func=self._updateFraction, update_func_args=(self.frame_rate_combo,)) self.wg.addVertex(self.dar_combo, signal="changed") self.wg.addVertex(self.dar_fraction_widget, signal="value-changed") self.wg.addVertex(self.par_combo, signal="changed") self.wg.addVertex(self.par_fraction_widget, signal="value-changed") self.wg.addVertex(self.width_spinbutton, signal="value-changed") self.wg.addVertex(self.height_spinbutton, signal="value-changed") self.wg.addVertex(self.save_audio_preset_button, update_func=self._updateAudioSaveButton) self.wg.addVertex(self.save_video_preset_button, update_func=self._updateVideoSaveButton) self.wg.addVertex(self.channels_combo, signal="changed") self.wg.addVertex(self.sample_rate_combo, signal="changed") self.wg.addVertex(self.sample_depth_combo, signal="changed") # constrain width and height IFF constrain_sar_button is active self.wg.addEdge(self.width_spinbutton, self.height_spinbutton, predicate=self.constrained, edge_func=self.updateHeight) self.wg.addEdge(self.height_spinbutton, self.width_spinbutton, predicate=self.constrained, edge_func=self.updateWidth) # keep framereate text field and combo in sync self.wg.addBiEdge(self.frame_rate_combo, self.frame_rate_fraction_widget) # keep dar text field and combo in sync self.wg.addEdge(self.dar_combo, self.dar_fraction_widget, edge_func=self.updateDarFromCombo) self.wg.addEdge(self.dar_fraction_widget, self.dar_combo, edge_func=self.updateDarFromFractionWidget) # keep par text field and combo in sync self.wg.addEdge(self.par_combo, self.par_fraction_widget, edge_func=self.updateParFromCombo) self.wg.addEdge(self.par_fraction_widget, self.par_combo, edge_func=self.updateParFromFractionWidget) # constrain DAR and PAR values. because the combo boxes are already # linked, we only have to link the fraction widgets together. self.wg.addEdge(self.par_fraction_widget, self.dar_fraction_widget, edge_func=self.updateDarFromPar) self.wg.addEdge(self.dar_fraction_widget, self.par_fraction_widget, edge_func=self.updateParFromDar) # update PAR when width/height change and the DAR checkbutton is # selected self.wg.addEdge(self.width_spinbutton, self.par_fraction_widget, predicate=self.darSelected, edge_func=self.updateParFromDar) self.wg.addEdge(self.height_spinbutton, self.par_fraction_widget, predicate=self.darSelected, edge_func=self.updateParFromDar) # update DAR when width/height change and the PAR checkbutton is # selected self.wg.addEdge(self.width_spinbutton, self.dar_fraction_widget, predicate=self.parSelected, edge_func=self.updateDarFromPar) self.wg.addEdge(self.height_spinbutton, self.dar_fraction_widget, predicate=self.parSelected, edge_func=self.updateDarFromPar) # presets self.audio_presets = AudioPresetManager() self.audio_presets.load() self.video_presets = VideoPresetManager() self.video_presets.load() self._fillPresetsTreeview( self.audio_preset_treeview, self.audio_presets, self._updateAudioPresetButtons) self._fillPresetsTreeview( self.video_preset_treeview, self.video_presets, self._updateVideoPresetButtons) # A map which tells which infobar should be used when displaying # an error for a preset manager. self._infobarForPresetManager = { self.audio_presets: self.audio_preset_infobar, self.video_presets: self.video_preset_infobar} # Bind the widgets in the Video tab to the Video Presets Manager. self.bindSpinbutton(self.video_presets, "width", self.width_spinbutton) self.bindSpinbutton(self.video_presets, "height", self.height_spinbutton) self.bindFractionWidget(self.video_presets, "frame-rate", self.frame_rate_fraction_widget) self.bindPar(self.video_presets) # Bind the widgets in the Audio tab to the Audio Presets Manager. self.bindCombo(self.audio_presets, "channels", self.channels_combo) self.bindCombo(self.audio_presets, "sample-rate", self.sample_rate_combo) self.bindCombo(self.audio_presets, "depth", self.sample_depth_combo) self.wg.addEdge(self.par_fraction_widget, self.save_video_preset_button) self.wg.addEdge(self.frame_rate_fraction_widget, self.save_video_preset_button) self.wg.addEdge(self.width_spinbutton, self.save_video_preset_button) self.wg.addEdge(self.height_spinbutton, self.save_video_preset_button) self.wg.addEdge(self.channels_combo, self.save_audio_preset_button) self.wg.addEdge(self.sample_rate_combo, self.save_audio_preset_button) self.wg.addEdge(self.sample_depth_combo, self.save_audio_preset_button) self.updateUI() def bindPar(self, mgr): def updatePar(value): # activate par so we can set the value self.select_par_radiobutton.props.active = True self.par_fraction_widget.setWidgetValue(value) mgr.bindWidget("par", updatePar, self.par_fraction_widget.getWidgetValue) def bindFractionWidget(self, mgr, name, widget): mgr.bindWidget(name, widget.setWidgetValue, widget.getWidgetValue) def bindCombo(self, mgr, name, widget): mgr.bindWidget(name, lambda x: set_combo_value(widget, x), lambda: get_combo_value(widget)) def bindSpinbutton(self, mgr, name, widget): mgr.bindWidget(name, lambda x: widget.set_value(float(x)), lambda: int(widget.get_value())) def _fillPresetsTreeview(self, treeview, mgr, update_buttons_func): """Set up the specified treeview to display the specified presets. @param treeview: The treeview for displaying the presets. @type treeview: TreeView @param mgr: The preset manager. @type mgr: PresetManager @param update_buttons_func: A function which updates the buttons for removing and saving a preset, enabling or disabling them accordingly. @type update_buttons_func: function """ renderer = gtk.CellRendererText() renderer.props.editable = True column = gtk.TreeViewColumn("Preset", renderer, text=0) treeview.append_column(column) treeview.props.headers_visible = False model = mgr.getModel() treeview.set_model(model) model.connect("row-inserted", self._newPresetCb, column, renderer, treeview) renderer.connect("edited", self._presetNameEditedCb, mgr) renderer.connect("editing-started", self._presetNameEditingStartedCb, mgr) treeview.get_selection().connect("changed", self._presetChangedCb, mgr, update_buttons_func) treeview.connect("focus-out-event", self._treeviewDefocusedCb, mgr) def _newPresetCb(self, model, path, iter_, column, renderer, treeview): """Handle the addition of a preset to the model of the preset manager. """ treeview.set_cursor_on_cell(path, column, renderer, start_editing=True) treeview.grab_focus() def _presetNameEditedCb(self, renderer, path, new_text, mgr): """Handle the renaming of a preset.""" try: mgr.renamePreset(path, new_text) except DuplicatePresetNameException: error_markup = _('"%s" already exists.') % new_text self._showPresetManagerError(mgr, error_markup) def _presetNameEditingStartedCb(self, renderer, editable, path, mgr): """Handle the start of a preset renaming.""" self._hidePresetManagerError(mgr) def _presetChangedCb(self, selection, mgr, update_preset_buttons_func): """Handle the selection of a preset.""" model, iter_ = selection.get_selected() if iter_: preset = model[iter_][0] else: preset = None mgr.restorePreset(preset) update_preset_buttons_func() self._hidePresetManagerError(mgr) def _treeviewDefocusedCb(self, widget, event, mgr): """Handle the treeview loosing the focus.""" self._hidePresetManagerError(mgr) def _showPresetManagerError(self, mgr, error_markup): """Show the specified error on the infobar associated with the manager. @param mgr: The preset manager for which to show the error. @type mgr: PresetManager """ infobar = self._infobarForPresetManager[mgr] # The infobar must contain exactly one object in the content area: # a label for displaying the error. label = infobar.get_content_area().children()[0] label.set_markup(error_markup) infobar.show() def _hidePresetManagerError(self, mgr): """Hide the error infobar associated with the manager. @param mgr: The preset manager for which to hide the error infobar. @type mgr: PresetManager """ infobar = self._infobarForPresetManager[mgr] infobar.hide() def constrained(self): return self.constrain_sar_button.props.active def _updateFraction(self, unused, fraction, combo): fraction.setWidgetValue(get_combo_value(combo)) def _updateCombo(self, unused, combo, fraction): set_combo_value(combo, fraction.getWidgetValue()) def getSAR(self): width = int(self.width_spinbutton.get_value()) height = int(self.height_spinbutton.get_value()) return gst.Fraction(width, height) def _setProperties(self): self.window = self.builder.get_object("project-settings-dialog") self.video_properties_table = self.builder.get_object( "video_properties_table") self.video_properties_table = self.builder.get_object( "video_properties_table") self.frame_rate_combo = self.builder.get_object("frame_rate_combo") self.dar_combo = self.builder.get_object("dar_combo") self.par_combo = self.builder.get_object("par_combo") self.channels_combo = self.builder.get_object("channels_combo") self.sample_rate_combo = self.builder.get_object("sample_rate_combo") self.sample_depth_combo = self.builder.get_object("sample_depth_combo") self.year_spinbutton = self.builder.get_object("year_spinbutton") self.author_entry = self.builder.get_object("author_entry") self.width_spinbutton = self.builder.get_object("width_spinbutton") self.height_spinbutton = self.builder.get_object("height_spinbutton") self.save_audio_preset_button = self.builder.get_object( "save_audio_preset_button") self.save_video_preset_button = self.builder.get_object( "save_video_preset_button") self.audio_preset_treeview = self.builder.get_object( "audio_preset_treeview") self.video_preset_treeview = self.builder.get_object( "video_preset_treeview") self.select_par_radiobutton = self.builder.get_object( "select_par_radiobutton") self.remove_audio_preset_button = self.builder.get_object( "remove_audio_preset_button") self.remove_video_preset_button = self.builder.get_object( "remove_video_preset_button") self.constrain_sar_button = self.builder.get_object( "constrain_sar_button") self.select_dar_radiobutton = self.builder.get_object( "select_dar_radiobutton") self.video_preset_infobar = self.builder.get_object( "video-preset-infobar") self.audio_preset_infobar = self.builder.get_object( "audio-preset-infobar") def _constrainSarButtonToggledCb(self, button): if button.props.active: self.sar = self.getSAR() def _selectDarRadiobuttonToggledCb(self, button): state = button.props.active self.dar_fraction_widget.set_sensitive(state) self.dar_combo.set_sensitive(state) self.par_fraction_widget.set_sensitive(not state) self.par_combo.set_sensitive(not state) @staticmethod def _getUniquePresetName(mgr): """Get a unique name for a new preset for the specified PresetManager. """ existing_preset_names = list(mgr.getPresetNames()) preset_name = _("New Preset") i = 1 while preset_name in existing_preset_names: preset_name = _("New Preset %d") % i i += 1 return preset_name def _addAudioPresetButtonClickedCb(self, button): preset_name = self._getUniquePresetName(self.audio_presets) self.audio_presets.addPreset(preset_name, { "channels": get_combo_value(self.channels_combo), "sample-rate": get_combo_value(self.sample_rate_combo), "depth": get_combo_value(self.sample_depth_combo) }) self.audio_presets.restorePreset(preset_name) self._updateAudioPresetButtons() def _removeAudioPresetButtonClickedCb(self, button): selection = self.audio_preset_treeview.get_selection() model, iter_ = selection.get_selected() if iter_: self.audio_presets.removePreset(model[iter_][0]) def _saveAudioPresetButtonClickedCb(self, button): self.audio_presets.savePreset() self.save_audio_preset_button.set_sensitive(False) def _addVideoPresetButtonClickedCb(self, button): preset_name = self._getUniquePresetName(self.video_presets) self.video_presets.addPreset(preset_name, { "width": int(self.width_spinbutton.get_value()), "height": int(self.height_spinbutton.get_value()), "frame-rate": self.frame_rate_fraction_widget.getWidgetValue(), "par": self.par_fraction_widget.getWidgetValue(), }) self.video_presets.restorePreset(preset_name) self._updateVideoPresetButtons() def _removeVideoPresetButtonClickedCb(self, button): selection = self.video_preset_treeview.get_selection() model, iter_ = selection.get_selected() if iter_: self.video_presets.removePreset(model[iter_][0]) def _saveVideoPresetButtonClickedCb(self, button): self.video_presets.savePreset() self.save_video_preset_button.set_sensitive(False) def _updateAudioPresetButtons(self): preset_changed = self.audio_presets.isCurrentPresetChanged() self.save_audio_preset_button.set_sensitive(preset_changed) preset_selected = bool(self.audio_presets.cur_preset) self.remove_audio_preset_button.set_sensitive(preset_selected) def _updateVideoPresetButtons(self): preset_changed = self.video_presets.isCurrentPresetChanged() self.save_video_preset_button.set_sensitive(preset_changed) preset_selected = bool(self.video_presets.cur_preset) self.remove_video_preset_button.set_sensitive(preset_selected) def _updateAudioSaveButton(self, unused_in, button): button.set_sensitive(self.audio_presets.isCurrentPresetChanged()) def _updateVideoSaveButton(self, unused_in, button): button.set_sensitive(self.video_presets.isCurrentPresetChanged()) def darSelected(self): return self.select_dar_radiobutton.props.active def parSelected(self): return not self.darSelected() def updateWidth(self): height = int(self.height_spinbutton.get_value()) self.width_spinbutton.set_value(height * self.sar) def updateHeight(self): width = int(self.width_spinbutton.get_value()) self.height_spinbutton.set_value(width * (1 / self.sar)) def updateDarFromPar(self): par = self.par_fraction_widget.getWidgetValue() sar = self.getSAR() self.dar_fraction_widget.setWidgetValue(sar * par) def updateParFromDar(self): dar = self.dar_fraction_widget.getWidgetValue() sar = self.getSAR() self.par_fraction_widget.setWidgetValue(dar * (1 / sar)) def updateDarFromCombo(self): self.dar_fraction_widget.setWidgetValue(get_combo_value( self.dar_combo)) def updateDarFromFractionWidget(self): set_combo_value(self.dar_combo, self.dar_fraction_widget.getWidgetValue()) def updateParFromCombo(self): self.par_fraction_widget.setWidgetValue(get_combo_value( self.par_combo)) def updateParFromFractionWidget(self): set_combo_value(self.par_combo, self.par_fraction_widget.getWidgetValue()) def updateUI(self): self.width_spinbutton.set_value(self.settings.videowidth) self.height_spinbutton.set_value(self.settings.videoheight) # video self.frame_rate_fraction_widget.setWidgetValue(self.settings.videorate) self.par_fraction_widget.setWidgetValue(self.settings.videopar) # audio set_combo_value(self.channels_combo, self.settings.audiochannels) set_combo_value(self.sample_rate_combo, self.settings.audiorate) set_combo_value(self.sample_depth_combo, self.settings.audiodepth) self._selectDarRadiobuttonToggledCb(self.select_dar_radiobutton) def updateSettings(self): width = int(self.width_spinbutton.get_value()) height = int(self.height_spinbutton.get_value()) par = self.par_fraction_widget.getWidgetValue() frame_rate = self.frame_rate_fraction_widget.getWidgetValue() channels = get_combo_value(self.channels_combo) sample_rate = get_combo_value(self.sample_rate_combo) sample_depth = get_combo_value(self.sample_depth_combo) self.settings.setVideoProperties(width, height, frame_rate, par) self.settings.setAudioProperties(channels, sample_rate, sample_depth) self.project.setSettings(self.settings) def _responseCb(self, unused_widget, response): if response == gtk.RESPONSE_OK: self.updateSettings() self.audio_presets.save() self.video_presets.save() self.window.destroy()
def __init__(self, parent, project): self.project = project self.settings = project.getSettings() self.builder = gtk.Builder() self.builder.add_from_file( os.path.join(get_ui_dir(), "projectsettings.ui")) self._setProperties() self.builder.connect_signals(self) # add custom display aspect ratio widget self.dar_fraction_widget = FractionWidget() self.video_properties_table.attach(self.dar_fraction_widget, 0, 1, 6, 7, xoptions=gtk.EXPAND | gtk.FILL, yoptions=0) self.dar_fraction_widget.show() # add custom pixel aspect ratio widget self.par_fraction_widget = FractionWidget() self.video_properties_table.attach(self.par_fraction_widget, 1, 2, 6, 7, xoptions=gtk.EXPAND | gtk.FILL, yoptions=0) self.par_fraction_widget.show() # add custom framerate widget self.frame_rate_fraction_widget = FractionWidget() self.video_properties_table.attach(self.frame_rate_fraction_widget, 1, 2, 2, 3, xoptions=gtk.EXPAND | gtk.FILL, yoptions=0) self.frame_rate_fraction_widget.show() # populate coboboxes with appropriate data self.frame_rate_combo.set_model(frame_rates) self.dar_combo.set_model(display_aspect_ratios) self.par_combo.set_model(pixel_aspect_ratios) self.channels_combo.set_model(audio_channels) self.sample_rate_combo.set_model(audio_rates) self.sample_depth_combo.set_model(audio_depths) # set the project metadata # FIXME: not saved in the project file if self.year_spinbutton.get_value_as_int() == 1900: self.year_spinbutton.set_value(datetime.now().year) if self.author_entry.get_text() == "": self.full_user_name = getpwuid(os.getuid()).pw_gecos.split(",")[0] self.author_entry.set_text(self.full_user_name) # behavior self.wg = RippleUpdateGroup() self.wg.addVertex(self.frame_rate_combo, signal="changed", update_func=self._updateCombo, update_func_args=(self.frame_rate_fraction_widget, )) self.wg.addVertex(self.frame_rate_fraction_widget, signal="value-changed", update_func=self._updateFraction, update_func_args=(self.frame_rate_combo, )) self.wg.addVertex(self.dar_combo, signal="changed") self.wg.addVertex(self.dar_fraction_widget, signal="value-changed") self.wg.addVertex(self.par_combo, signal="changed") self.wg.addVertex(self.par_fraction_widget, signal="value-changed") self.wg.addVertex(self.width_spinbutton, signal="value-changed") self.wg.addVertex(self.height_spinbutton, signal="value-changed") self.wg.addVertex(self.save_audio_preset_button, update_func=self._updateAudioSaveButton) self.wg.addVertex(self.save_video_preset_button, update_func=self._updateVideoSaveButton) self.wg.addVertex(self.channels_combo, signal="changed") self.wg.addVertex(self.sample_rate_combo, signal="changed") self.wg.addVertex(self.sample_depth_combo, signal="changed") # constrain width and height IFF constrain_sar_button is active self.wg.addEdge(self.width_spinbutton, self.height_spinbutton, predicate=self.constrained, edge_func=self.updateHeight) self.wg.addEdge(self.height_spinbutton, self.width_spinbutton, predicate=self.constrained, edge_func=self.updateWidth) # keep framereate text field and combo in sync self.wg.addBiEdge(self.frame_rate_combo, self.frame_rate_fraction_widget) # keep dar text field and combo in sync self.wg.addEdge(self.dar_combo, self.dar_fraction_widget, edge_func=self.updateDarFromCombo) self.wg.addEdge(self.dar_fraction_widget, self.dar_combo, edge_func=self.updateDarFromFractionWidget) # keep par text field and combo in sync self.wg.addEdge(self.par_combo, self.par_fraction_widget, edge_func=self.updateParFromCombo) self.wg.addEdge(self.par_fraction_widget, self.par_combo, edge_func=self.updateParFromFractionWidget) # constrain DAR and PAR values. because the combo boxes are already # linked, we only have to link the fraction widgets together. self.wg.addEdge(self.par_fraction_widget, self.dar_fraction_widget, edge_func=self.updateDarFromPar) self.wg.addEdge(self.dar_fraction_widget, self.par_fraction_widget, edge_func=self.updateParFromDar) # update PAR when width/height change and the DAR checkbutton is # selected self.wg.addEdge(self.width_spinbutton, self.par_fraction_widget, predicate=self.darSelected, edge_func=self.updateParFromDar) self.wg.addEdge(self.height_spinbutton, self.par_fraction_widget, predicate=self.darSelected, edge_func=self.updateParFromDar) # update DAR when width/height change and the PAR checkbutton is # selected self.wg.addEdge(self.width_spinbutton, self.dar_fraction_widget, predicate=self.parSelected, edge_func=self.updateDarFromPar) self.wg.addEdge(self.height_spinbutton, self.dar_fraction_widget, predicate=self.parSelected, edge_func=self.updateDarFromPar) # presets self.audio_presets = AudioPresetManager() self.audio_presets.load() self.video_presets = VideoPresetManager() self.video_presets.load() self._fillPresetsTreeview(self.audio_preset_treeview, self.audio_presets, self._updateAudioPresetButtons) self._fillPresetsTreeview(self.video_preset_treeview, self.video_presets, self._updateVideoPresetButtons) # A map which tells which infobar should be used when displaying # an error for a preset manager. self._infobarForPresetManager = { self.audio_presets: self.audio_preset_infobar, self.video_presets: self.video_preset_infobar } # Bind the widgets in the Video tab to the Video Presets Manager. self.bindSpinbutton(self.video_presets, "width", self.width_spinbutton) self.bindSpinbutton(self.video_presets, "height", self.height_spinbutton) self.bindFractionWidget(self.video_presets, "frame-rate", self.frame_rate_fraction_widget) self.bindPar(self.video_presets) # Bind the widgets in the Audio tab to the Audio Presets Manager. self.bindCombo(self.audio_presets, "channels", self.channels_combo) self.bindCombo(self.audio_presets, "sample-rate", self.sample_rate_combo) self.bindCombo(self.audio_presets, "depth", self.sample_depth_combo) self.wg.addEdge(self.par_fraction_widget, self.save_video_preset_button) self.wg.addEdge(self.frame_rate_fraction_widget, self.save_video_preset_button) self.wg.addEdge(self.width_spinbutton, self.save_video_preset_button) self.wg.addEdge(self.height_spinbutton, self.save_video_preset_button) self.wg.addEdge(self.channels_combo, self.save_audio_preset_button) self.wg.addEdge(self.sample_rate_combo, self.save_audio_preset_button) self.wg.addEdge(self.sample_depth_combo, self.save_audio_preset_button) self.updateUI()
class ProjectSettingsDialog(): def __init__(self, parent, project): self.project = project self.settings = project.getSettings() self.builder = gtk.Builder() self.builder.add_from_file( os.path.join(get_ui_dir(), "projectsettings.ui")) self._setProperties() self.builder.connect_signals(self) # add custom display aspect ratio widget self.dar_fraction_widget = FractionWidget() self.video_properties_table.attach(self.dar_fraction_widget, 0, 1, 6, 7, xoptions=gtk.EXPAND | gtk.FILL, yoptions=0) self.dar_fraction_widget.show() # add custom pixel aspect ratio widget self.par_fraction_widget = FractionWidget() self.video_properties_table.attach(self.par_fraction_widget, 1, 2, 6, 7, xoptions=gtk.EXPAND | gtk.FILL, yoptions=0) self.par_fraction_widget.show() # add custom framerate widget self.frame_rate_fraction_widget = FractionWidget() self.video_properties_table.attach(self.frame_rate_fraction_widget, 1, 2, 2, 3, xoptions=gtk.EXPAND | gtk.FILL, yoptions=0) self.frame_rate_fraction_widget.show() # populate coboboxes with appropriate data self.frame_rate_combo.set_model(frame_rates) self.dar_combo.set_model(display_aspect_ratios) self.par_combo.set_model(pixel_aspect_ratios) self.channels_combo.set_model(audio_channels) self.sample_rate_combo.set_model(audio_rates) self.sample_depth_combo.set_model(audio_depths) # set the project metadata # FIXME: not saved in the project file if self.year_spinbutton.get_value_as_int() == 1900: self.year_spinbutton.set_value(datetime.now().year) if self.author_entry.get_text() == "": self.full_user_name = getpwuid(os.getuid()).pw_gecos.split(",")[0] self.author_entry.set_text(self.full_user_name) # behavior self.wg = RippleUpdateGroup() self.wg.addVertex(self.frame_rate_combo, signal="changed", update_func=self._updateCombo, update_func_args=(self.frame_rate_fraction_widget, )) self.wg.addVertex(self.frame_rate_fraction_widget, signal="value-changed", update_func=self._updateFraction, update_func_args=(self.frame_rate_combo, )) self.wg.addVertex(self.dar_combo, signal="changed") self.wg.addVertex(self.dar_fraction_widget, signal="value-changed") self.wg.addVertex(self.par_combo, signal="changed") self.wg.addVertex(self.par_fraction_widget, signal="value-changed") self.wg.addVertex(self.width_spinbutton, signal="value-changed") self.wg.addVertex(self.height_spinbutton, signal="value-changed") self.wg.addVertex(self.save_audio_preset_button, update_func=self._updateAudioSaveButton) self.wg.addVertex(self.save_video_preset_button, update_func=self._updateVideoSaveButton) self.wg.addVertex(self.channels_combo, signal="changed") self.wg.addVertex(self.sample_rate_combo, signal="changed") self.wg.addVertex(self.sample_depth_combo, signal="changed") # constrain width and height IFF constrain_sar_button is active self.wg.addEdge(self.width_spinbutton, self.height_spinbutton, predicate=self.constrained, edge_func=self.updateHeight) self.wg.addEdge(self.height_spinbutton, self.width_spinbutton, predicate=self.constrained, edge_func=self.updateWidth) # keep framereate text field and combo in sync self.wg.addBiEdge(self.frame_rate_combo, self.frame_rate_fraction_widget) # keep dar text field and combo in sync self.wg.addEdge(self.dar_combo, self.dar_fraction_widget, edge_func=self.updateDarFromCombo) self.wg.addEdge(self.dar_fraction_widget, self.dar_combo, edge_func=self.updateDarFromFractionWidget) # keep par text field and combo in sync self.wg.addEdge(self.par_combo, self.par_fraction_widget, edge_func=self.updateParFromCombo) self.wg.addEdge(self.par_fraction_widget, self.par_combo, edge_func=self.updateParFromFractionWidget) # constrain DAR and PAR values. because the combo boxes are already # linked, we only have to link the fraction widgets together. self.wg.addEdge(self.par_fraction_widget, self.dar_fraction_widget, edge_func=self.updateDarFromPar) self.wg.addEdge(self.dar_fraction_widget, self.par_fraction_widget, edge_func=self.updateParFromDar) # update PAR when width/height change and the DAR checkbutton is # selected self.wg.addEdge(self.width_spinbutton, self.par_fraction_widget, predicate=self.darSelected, edge_func=self.updateParFromDar) self.wg.addEdge(self.height_spinbutton, self.par_fraction_widget, predicate=self.darSelected, edge_func=self.updateParFromDar) # update DAR when width/height change and the PAR checkbutton is # selected self.wg.addEdge(self.width_spinbutton, self.dar_fraction_widget, predicate=self.parSelected, edge_func=self.updateDarFromPar) self.wg.addEdge(self.height_spinbutton, self.dar_fraction_widget, predicate=self.parSelected, edge_func=self.updateDarFromPar) # presets self.audio_presets = AudioPresetManager() self.audio_presets.load() self.video_presets = VideoPresetManager() self.video_presets.load() self._fillPresetsTreeview(self.audio_preset_treeview, self.audio_presets, self._updateAudioPresetButtons) self._fillPresetsTreeview(self.video_preset_treeview, self.video_presets, self._updateVideoPresetButtons) # A map which tells which infobar should be used when displaying # an error for a preset manager. self._infobarForPresetManager = { self.audio_presets: self.audio_preset_infobar, self.video_presets: self.video_preset_infobar } # Bind the widgets in the Video tab to the Video Presets Manager. self.bindSpinbutton(self.video_presets, "width", self.width_spinbutton) self.bindSpinbutton(self.video_presets, "height", self.height_spinbutton) self.bindFractionWidget(self.video_presets, "frame-rate", self.frame_rate_fraction_widget) self.bindPar(self.video_presets) # Bind the widgets in the Audio tab to the Audio Presets Manager. self.bindCombo(self.audio_presets, "channels", self.channels_combo) self.bindCombo(self.audio_presets, "sample-rate", self.sample_rate_combo) self.bindCombo(self.audio_presets, "depth", self.sample_depth_combo) self.wg.addEdge(self.par_fraction_widget, self.save_video_preset_button) self.wg.addEdge(self.frame_rate_fraction_widget, self.save_video_preset_button) self.wg.addEdge(self.width_spinbutton, self.save_video_preset_button) self.wg.addEdge(self.height_spinbutton, self.save_video_preset_button) self.wg.addEdge(self.channels_combo, self.save_audio_preset_button) self.wg.addEdge(self.sample_rate_combo, self.save_audio_preset_button) self.wg.addEdge(self.sample_depth_combo, self.save_audio_preset_button) self.updateUI() def bindPar(self, mgr): def updatePar(value): # activate par so we can set the value self.select_par_radiobutton.props.active = True self.par_fraction_widget.setWidgetValue(value) mgr.bindWidget("par", updatePar, self.par_fraction_widget.getWidgetValue) def bindFractionWidget(self, mgr, name, widget): mgr.bindWidget(name, widget.setWidgetValue, widget.getWidgetValue) def bindCombo(self, mgr, name, widget): mgr.bindWidget(name, lambda x: set_combo_value(widget, x), lambda: get_combo_value(widget)) def bindSpinbutton(self, mgr, name, widget): mgr.bindWidget(name, lambda x: widget.set_value(float(x)), lambda: int(widget.get_value())) def _fillPresetsTreeview(self, treeview, mgr, update_buttons_func): """Set up the specified treeview to display the specified presets. @param treeview: The treeview for displaying the presets. @type treeview: TreeView @param mgr: The preset manager. @type mgr: PresetManager @param update_buttons_func: A function which updates the buttons for removing and saving a preset, enabling or disabling them accordingly. @type update_buttons_func: function """ renderer = gtk.CellRendererText() renderer.props.editable = True column = gtk.TreeViewColumn("Preset", renderer, text=0) treeview.append_column(column) treeview.props.headers_visible = False model = mgr.getModel() treeview.set_model(model) model.connect("row-inserted", self._newPresetCb, column, renderer, treeview) renderer.connect("edited", self._presetNameEditedCb, mgr) renderer.connect("editing-started", self._presetNameEditingStartedCb, mgr) treeview.get_selection().connect("changed", self._presetChangedCb, mgr, update_buttons_func) treeview.connect("focus-out-event", self._treeviewDefocusedCb, mgr) def _newPresetCb(self, model, path, iter_, column, renderer, treeview): """Handle the addition of a preset to the model of the preset manager. """ treeview.set_cursor_on_cell(path, column, renderer, start_editing=True) treeview.grab_focus() def _presetNameEditedCb(self, renderer, path, new_text, mgr): """Handle the renaming of a preset.""" try: mgr.renamePreset(path, new_text) except DuplicatePresetNameException: error_markup = _('"%s" already exists.') % new_text self._showPresetManagerError(mgr, error_markup) def _presetNameEditingStartedCb(self, renderer, editable, path, mgr): """Handle the start of a preset renaming.""" self._hidePresetManagerError(mgr) def _presetChangedCb(self, selection, mgr, update_preset_buttons_func): """Handle the selection of a preset.""" model, iter_ = selection.get_selected() if iter_: preset = model[iter_][0] else: preset = None mgr.restorePreset(preset) update_preset_buttons_func() self._hidePresetManagerError(mgr) def _treeviewDefocusedCb(self, widget, event, mgr): """Handle the treeview loosing the focus.""" self._hidePresetManagerError(mgr) def _showPresetManagerError(self, mgr, error_markup): """Show the specified error on the infobar associated with the manager. @param mgr: The preset manager for which to show the error. @type mgr: PresetManager """ infobar = self._infobarForPresetManager[mgr] # The infobar must contain exactly one object in the content area: # a label for displaying the error. label = infobar.get_content_area().children()[0] label.set_markup(error_markup) infobar.show() def _hidePresetManagerError(self, mgr): """Hide the error infobar associated with the manager. @param mgr: The preset manager for which to hide the error infobar. @type mgr: PresetManager """ infobar = self._infobarForPresetManager[mgr] infobar.hide() def constrained(self): return self.constrain_sar_button.props.active def _updateFraction(self, unused, fraction, combo): fraction.setWidgetValue(get_combo_value(combo)) def _updateCombo(self, unused, combo, fraction): set_combo_value(combo, fraction.getWidgetValue()) def getSAR(self): width = int(self.width_spinbutton.get_value()) height = int(self.height_spinbutton.get_value()) return gst.Fraction(width, height) def _setProperties(self): self.window = self.builder.get_object("project-settings-dialog") self.video_properties_table = self.builder.get_object( "video_properties_table") self.video_properties_table = self.builder.get_object( "video_properties_table") self.frame_rate_combo = self.builder.get_object("frame_rate_combo") self.dar_combo = self.builder.get_object("dar_combo") self.par_combo = self.builder.get_object("par_combo") self.channels_combo = self.builder.get_object("channels_combo") self.sample_rate_combo = self.builder.get_object("sample_rate_combo") self.sample_depth_combo = self.builder.get_object("sample_depth_combo") self.year_spinbutton = self.builder.get_object("year_spinbutton") self.author_entry = self.builder.get_object("author_entry") self.width_spinbutton = self.builder.get_object("width_spinbutton") self.height_spinbutton = self.builder.get_object("height_spinbutton") self.save_audio_preset_button = self.builder.get_object( "save_audio_preset_button") self.save_video_preset_button = self.builder.get_object( "save_video_preset_button") self.audio_preset_treeview = self.builder.get_object( "audio_preset_treeview") self.video_preset_treeview = self.builder.get_object( "video_preset_treeview") self.select_par_radiobutton = self.builder.get_object( "select_par_radiobutton") self.remove_audio_preset_button = self.builder.get_object( "remove_audio_preset_button") self.remove_video_preset_button = self.builder.get_object( "remove_video_preset_button") self.constrain_sar_button = self.builder.get_object( "constrain_sar_button") self.select_dar_radiobutton = self.builder.get_object( "select_dar_radiobutton") self.video_preset_infobar = self.builder.get_object( "video-preset-infobar") self.audio_preset_infobar = self.builder.get_object( "audio-preset-infobar") def _constrainSarButtonToggledCb(self, button): if button.props.active: self.sar = self.getSAR() def _selectDarRadiobuttonToggledCb(self, button): state = button.props.active self.dar_fraction_widget.set_sensitive(state) self.dar_combo.set_sensitive(state) self.par_fraction_widget.set_sensitive(not state) self.par_combo.set_sensitive(not state) @staticmethod def _getUniquePresetName(mgr): """Get a unique name for a new preset for the specified PresetManager. """ existing_preset_names = list(mgr.getPresetNames()) preset_name = _("New Preset") i = 1 while preset_name in existing_preset_names: preset_name = _("New Preset %d") % i i += 1 return preset_name def _addAudioPresetButtonClickedCb(self, button): preset_name = self._getUniquePresetName(self.audio_presets) self.audio_presets.addPreset( preset_name, { "channels": get_combo_value(self.channels_combo), "sample-rate": get_combo_value(self.sample_rate_combo), "depth": get_combo_value(self.sample_depth_combo) }) self.audio_presets.restorePreset(preset_name) self._updateAudioPresetButtons() def _removeAudioPresetButtonClickedCb(self, button): selection = self.audio_preset_treeview.get_selection() model, iter_ = selection.get_selected() if iter_: self.audio_presets.removePreset(model[iter_][0]) def _saveAudioPresetButtonClickedCb(self, button): self.audio_presets.savePreset() self.save_audio_preset_button.set_sensitive(False) def _addVideoPresetButtonClickedCb(self, button): preset_name = self._getUniquePresetName(self.video_presets) self.video_presets.addPreset( preset_name, { "width": int(self.width_spinbutton.get_value()), "height": int(self.height_spinbutton.get_value()), "frame-rate": self.frame_rate_fraction_widget.getWidgetValue(), "par": self.par_fraction_widget.getWidgetValue(), }) self.video_presets.restorePreset(preset_name) self._updateVideoPresetButtons() def _removeVideoPresetButtonClickedCb(self, button): selection = self.video_preset_treeview.get_selection() model, iter_ = selection.get_selected() if iter_: self.video_presets.removePreset(model[iter_][0]) def _saveVideoPresetButtonClickedCb(self, button): self.video_presets.savePreset() self.save_video_preset_button.set_sensitive(False) def _updateAudioPresetButtons(self): preset_changed = self.audio_presets.isCurrentPresetChanged() self.save_audio_preset_button.set_sensitive(preset_changed) preset_selected = bool(self.audio_presets.cur_preset) self.remove_audio_preset_button.set_sensitive(preset_selected) def _updateVideoPresetButtons(self): preset_changed = self.video_presets.isCurrentPresetChanged() self.save_video_preset_button.set_sensitive(preset_changed) preset_selected = bool(self.video_presets.cur_preset) self.remove_video_preset_button.set_sensitive(preset_selected) def _updateAudioSaveButton(self, unused_in, button): button.set_sensitive(self.audio_presets.isCurrentPresetChanged()) def _updateVideoSaveButton(self, unused_in, button): button.set_sensitive(self.video_presets.isCurrentPresetChanged()) def darSelected(self): return self.select_dar_radiobutton.props.active def parSelected(self): return not self.darSelected() def updateWidth(self): height = int(self.height_spinbutton.get_value()) self.width_spinbutton.set_value(height * self.sar) def updateHeight(self): width = int(self.width_spinbutton.get_value()) self.height_spinbutton.set_value(width * (1 / self.sar)) def updateDarFromPar(self): par = self.par_fraction_widget.getWidgetValue() sar = self.getSAR() self.dar_fraction_widget.setWidgetValue(sar * par) def updateParFromDar(self): dar = self.dar_fraction_widget.getWidgetValue() sar = self.getSAR() self.par_fraction_widget.setWidgetValue(dar * (1 / sar)) def updateDarFromCombo(self): self.dar_fraction_widget.setWidgetValue(get_combo_value( self.dar_combo)) def updateDarFromFractionWidget(self): set_combo_value(self.dar_combo, self.dar_fraction_widget.getWidgetValue()) def updateParFromCombo(self): self.par_fraction_widget.setWidgetValue(get_combo_value( self.par_combo)) def updateParFromFractionWidget(self): set_combo_value(self.par_combo, self.par_fraction_widget.getWidgetValue()) def updateUI(self): self.width_spinbutton.set_value(self.settings.videowidth) self.height_spinbutton.set_value(self.settings.videoheight) # video self.frame_rate_fraction_widget.setWidgetValue(self.settings.videorate) self.par_fraction_widget.setWidgetValue(self.settings.videopar) # audio set_combo_value(self.channels_combo, self.settings.audiochannels) set_combo_value(self.sample_rate_combo, self.settings.audiorate) set_combo_value(self.sample_depth_combo, self.settings.audiodepth) self._selectDarRadiobuttonToggledCb(self.select_dar_radiobutton) def updateSettings(self): width = int(self.width_spinbutton.get_value()) height = int(self.height_spinbutton.get_value()) par = self.par_fraction_widget.getWidgetValue() frame_rate = self.frame_rate_fraction_widget.getWidgetValue() channels = get_combo_value(self.channels_combo) sample_rate = get_combo_value(self.sample_rate_combo) sample_depth = get_combo_value(self.sample_depth_combo) self.settings.setVideoProperties(width, height, frame_rate, par) self.settings.setAudioProperties(channels, sample_rate, sample_depth) self.project.setSettings(self.settings) def _responseCb(self, unused_widget, response): if response == gtk.RESPONSE_OK: self.updateSettings() self.audio_presets.save() self.video_presets.save() self.window.destroy()
def __init__(self, parent, project): GladeWindow.__init__(self, parent) self.project = project self.settings = project.getSettings() self.project = project # add custom widgets self.dar_fraction_widget = FractionWidget() self.video_properties_table.attach(self.dar_fraction_widget, 0, 1, 6, 7, xoptions=gtk.EXPAND | gtk.FILL, yoptions=0) self.dar_fraction_widget.show() # add custom widgets self.par_fraction_widget = FractionWidget() self.video_properties_table.attach(self.par_fraction_widget, 1, 2, 6, 7, xoptions=gtk.EXPAND | gtk.FILL, yoptions=0) self.par_fraction_widget.show() self.frame_rate_fraction_widget = FractionWidget() self.video_properties_table.attach(self.frame_rate_fraction_widget, 1, 2, 2, 3, xoptions=gtk.EXPAND | gtk.FILL, yoptions=0) self.frame_rate_fraction_widget.show() # populate coboboxes with appropriate data self.frame_rate_combo.set_model(frame_rates) self.dar_combo.set_model(display_aspect_ratios) self.par_combo.set_model(pixel_aspect_ratios) self.channels_combo.set_model(audio_channels) self.sample_rate_combo.set_model(audio_rates) self.sample_depth_combo.set_model(audio_depths) # set the project metadata # FIXME: not saved in the project file if self.year_spinbutton.get_value_as_int() == 1900: self.year_spinbutton.set_value(datetime.now().year) if self.author_entry.get_text() == "": self.full_user_name = getpwuid(os.getuid()).pw_gecos.split(",")[0] self.author_entry.set_text(self.full_user_name) # behavior self.wg = RippleUpdateGroup( (self.frame_rate_combo, self._updateCombo, "changed", self.frame_rate_fraction_widget), (self.frame_rate_fraction_widget, self._updateFraction, "value-changed", self.frame_rate_combo), (self.dar_combo, None, "changed"), (self.dar_fraction_widget, None, "value-changed"), (self.par_combo, None, "changed"), (self.par_fraction_widget, None, "value-changed"), (self.width_spinbutton, None, "value-changed"), (self.height_spinbutton, None, "value-changed"), (self.save_audio_preset_button, self._updateAudioSaveButton), (self.save_video_preset_button, self._updateVideoSaveButton), (self.channels_combo,), (self.sample_rate_combo,), (self.sample_depth_combo,), ) # constrain width and height IFF constrain_sar_button is active self.wg.add_edge(self.width_spinbutton, self.height_spinbutton, self.constrained, self.updateHeight) self.wg.add_edge(self.height_spinbutton, self.width_spinbutton, self.constrained, self.updateWidth) # keep framereate text field and combo in sync self.wg.add_bi_edge(self.frame_rate_combo, self.frame_rate_fraction_widget) # keep dar text field and combo in sync self.wg.add_edge(self.dar_combo, self.dar_fraction_widget, edge_func=self.updateDarFromCombo) self.wg.add_edge(self.dar_fraction_widget, self.dar_combo, edge_func=self.updateDarFromFractionWidget) # keep par text field and combo in sync self.wg.add_edge(self.par_combo, self.par_fraction_widget, edge_func=self.updateParFromCombo) self.wg.add_edge(self.par_fraction_widget, self.par_combo, edge_func=self.updateParFromFractionWidget) # constrain DAR and PAR values. because the combo boxes are already # linked, we only have to link the fraction widgets together. self.wg.add_edge(self.par_fraction_widget, self.dar_fraction_widget, edge_func=self.updateDarFromPar) self.wg.add_edge(self.dar_fraction_widget, self.par_fraction_widget, edge_func=self.updateParFromDar) # update PAR when width/height change and the DAR checkbutton is # selected self.wg.add_edge(self.width_spinbutton, self.par_fraction_widget, predicate=self.darSelected, edge_func=self.updateParFromDar) self.wg.add_edge(self.height_spinbutton, self.par_fraction_widget, predicate=self.darSelected, edge_func=self.updateParFromDar) # update DAR when width/height change and the PAR checkbutton is # selected self.wg.add_edge(self.width_spinbutton, self.dar_fraction_widget, predicate=self.parSelected, edge_func=self.updateDarFromPar) self.wg.add_edge(self.height_spinbutton, self.dar_fraction_widget, predicate=self.parSelected, edge_func=self.updateDarFromPar) # presets self.audio_presets = AudioPresetManager() self.audio_presets.load() self.video_presets = VideoPresetManager() self.video_presets.load() self.fillTreeview(self.audio_preset_treeview, self.audio_presets) self.fillTreeview(self.video_preset_treeview, self.video_presets) self.bindSpinbutton(self.video_presets, "width", self.width_spinbutton) self.bindSpinbutton(self.video_presets, "height", self.height_spinbutton) self.bindFractionWidget(self.video_presets, "frame-rate", self.frame_rate_fraction_widget) self.bindPar(self.video_presets) self.bindCombo(self.audio_presets, "channels", self.channels_combo) self.bindCombo(self.audio_presets, "sample-rate", self.sample_rate_combo) self.bindCombo(self.audio_presets, "depth", self.sample_depth_combo) self.wg.add_edge(self.par_fraction_widget, self.save_video_preset_button) self.wg.add_edge(self.frame_rate_fraction_widget, self.save_video_preset_button) self.wg.add_edge(self.width_spinbutton, self.save_video_preset_button) self.wg.add_edge(self.height_spinbutton, self.save_video_preset_button) self.wg.add_edge(self.channels_combo, self.save_audio_preset_button) self.wg.add_edge(self.sample_rate_combo, self.save_audio_preset_button) self.wg.add_edge(self.sample_depth_combo, self.save_audio_preset_button) self.updateUI()
def __init__(self, app, project, pipeline=None): Loggable.__init__(self) self.app = app self.builder = gtk.Builder() self.builder.add_from_file(os.path.join(configure.get_ui_dir(), "encodingdialog.ui")) self._setProperties() self.builder.connect_signals(self) # UI widgets icon = os.path.join(configure.get_pixmap_dir(), "pitivi-render-16.png") self.window.set_icon_from_file(icon) # FIXME: re-enable this widget when bug #637078 is implemented self.selected_only_button.destroy() # The Render dialog and the Project Settings dialog have some # common settings, for example the audio sample rate. # When these common settings are changed in the Render dialog, # we don't want them to be saved, so we create a copy of the project's # settings to be used by the Render dialog for rendering. render_settings = project.getSettings().copy() # Note: render_settings will end up as self.settings. Renderer.__init__(self, project, pipeline=pipeline, settings=render_settings) # Directory and Filename self.filebutton.set_current_folder(self.app.settings.lastExportFolder) self.updateFilename(self.project.name) # We store these so that when the user tries various container formats, # (AKA muxers) we select these a/v encoders, if they are compatible with # the current container format. self.preferred_vencoder = self.settings.vencoder self.preferred_aencoder = self.settings.aencoder self._initializeComboboxModels() self._displaySettings() self._displayRenderSettings() self.window.connect("delete-event", self._deleteEventCb) self.settings.connect("settings-changed", self._settingsChanged) # Monitor changes self.wg = RippleUpdateGroup() self.wg.addVertex(self.frame_rate_combo, signal="changed") self.wg.addVertex(self.save_render_preset_button, update_func=self._updateRenderSaveButton) self.wg.addVertex(self.channels_combo, signal="changed") self.wg.addVertex(self.sample_rate_combo, signal="changed") self.wg.addVertex(self.sample_depth_combo, signal="changed") self.wg.addVertex(self.muxercombobox, signal="changed") self.wg.addVertex(self.audio_encoder_combo, signal="changed") self.wg.addVertex(self.video_encoder_combo, signal="changed") self.render_presets = RenderPresetManager() self.render_presets.loadAll() self._fillPresetsTreeview( self.render_preset_treeview, self.render_presets, self._updateRenderPresetButtons) self.wg.addEdge(self.frame_rate_combo, self.save_render_preset_button) self.wg.addEdge(self.audio_encoder_combo, self.save_render_preset_button) self.wg.addEdge(self.video_encoder_combo, self.save_render_preset_button) self.wg.addEdge(self.muxercombobox, self.save_render_preset_button) self.wg.addEdge(self.channels_combo, self.save_render_preset_button) self.wg.addEdge(self.sample_rate_combo, self.save_render_preset_button) self.wg.addEdge(self.sample_depth_combo, self.save_render_preset_button) self._infobarForPresetManager = { self.render_presets: self.render_preset_infobar} # Bind widgets to RenderPresetsManager self.bindCombo(self.render_presets, "channels", self.channels_combo) self.bindCombo(self.render_presets, "sample-rate", self.sample_rate_combo) self.bindCombo(self.render_presets, "depth", self.sample_depth_combo) self.bindCombo(self.render_presets, "acodec", self.audio_encoder_combo) self.bindCombo(self.render_presets, "vcodec", self.video_encoder_combo) self.bindCombo(self.render_presets, "container", self.muxercombobox) self.bindCombo(self.render_presets, "frame-rate", self.frame_rate_combo) self.bindHeight(self.render_presets) self.bindWidth(self.render_presets) self.createNoPreset(self.render_presets)
class EncodingDialog(Renderer, Loggable): """Render dialog box. @ivar preferred_aencoder: The last audio encoder selected by the user. @type preferred_aencoder: str @ivar preferred_vencoder: The last video encoder selected by the user. @type preferred_vencoder: str @ivar settings: The settings used for rendering. @type settings: ExportSettings """ def __init__(self, app, project, pipeline=None): Loggable.__init__(self) self.app = app self.builder = gtk.Builder() self.builder.add_from_file(os.path.join(configure.get_ui_dir(), "encodingdialog.ui")) self._setProperties() self.builder.connect_signals(self) # UI widgets icon = os.path.join(configure.get_pixmap_dir(), "pitivi-render-16.png") self.window.set_icon_from_file(icon) # FIXME: re-enable this widget when bug #637078 is implemented self.selected_only_button.destroy() # The Render dialog and the Project Settings dialog have some # common settings, for example the audio sample rate. # When these common settings are changed in the Render dialog, # we don't want them to be saved, so we create a copy of the project's # settings to be used by the Render dialog for rendering. render_settings = project.getSettings().copy() # Note: render_settings will end up as self.settings. Renderer.__init__(self, project, pipeline=pipeline, settings=render_settings) # Directory and Filename self.filebutton.set_current_folder(self.app.settings.lastExportFolder) self.updateFilename(self.project.name) # We store these so that when the user tries various container formats, # (AKA muxers) we select these a/v encoders, if they are compatible with # the current container format. self.preferred_vencoder = self.settings.vencoder self.preferred_aencoder = self.settings.aencoder self._initializeComboboxModels() self._displaySettings() self._displayRenderSettings() self.window.connect("delete-event", self._deleteEventCb) self.settings.connect("settings-changed", self._settingsChanged) # Monitor changes self.wg = RippleUpdateGroup() self.wg.addVertex(self.frame_rate_combo, signal="changed") self.wg.addVertex(self.save_render_preset_button, update_func=self._updateRenderSaveButton) self.wg.addVertex(self.channels_combo, signal="changed") self.wg.addVertex(self.sample_rate_combo, signal="changed") self.wg.addVertex(self.sample_depth_combo, signal="changed") self.wg.addVertex(self.muxercombobox, signal="changed") self.wg.addVertex(self.audio_encoder_combo, signal="changed") self.wg.addVertex(self.video_encoder_combo, signal="changed") self.render_presets = RenderPresetManager() self.render_presets.loadAll() self._fillPresetsTreeview( self.render_preset_treeview, self.render_presets, self._updateRenderPresetButtons) self.wg.addEdge(self.frame_rate_combo, self.save_render_preset_button) self.wg.addEdge(self.audio_encoder_combo, self.save_render_preset_button) self.wg.addEdge(self.video_encoder_combo, self.save_render_preset_button) self.wg.addEdge(self.muxercombobox, self.save_render_preset_button) self.wg.addEdge(self.channels_combo, self.save_render_preset_button) self.wg.addEdge(self.sample_rate_combo, self.save_render_preset_button) self.wg.addEdge(self.sample_depth_combo, self.save_render_preset_button) self._infobarForPresetManager = { self.render_presets: self.render_preset_infobar} # Bind widgets to RenderPresetsManager self.bindCombo(self.render_presets, "channels", self.channels_combo) self.bindCombo(self.render_presets, "sample-rate", self.sample_rate_combo) self.bindCombo(self.render_presets, "depth", self.sample_depth_combo) self.bindCombo(self.render_presets, "acodec", self.audio_encoder_combo) self.bindCombo(self.render_presets, "vcodec", self.video_encoder_combo) self.bindCombo(self.render_presets, "container", self.muxercombobox) self.bindCombo(self.render_presets, "frame-rate", self.frame_rate_combo) self.bindHeight(self.render_presets) self.bindWidth(self.render_presets) self.createNoPreset(self.render_presets) def createNoPreset(self, mgr): mgr.prependPreset(_("No preset"), { "depth": int(get_combo_value(self.sample_depth_combo)), "channels": int(get_combo_value(self.channels_combo)), "sample-rate": int(get_combo_value(self.sample_rate_combo)), "acodec": get_combo_value(self.audio_encoder_combo).get_name(), "vcodec": get_combo_value(self.video_encoder_combo).get_name(), "container": get_combo_value(self.muxercombobox).get_name(), "frame-rate": gst.Fraction(int(get_combo_value(self.frame_rate_combo).num), int(get_combo_value(self.frame_rate_combo).denom)), "height": self.getDimension("height"), "width": self.getDimension("width")}) def bindCombo(self, mgr, name, widget): if name == "container": mgr.bindWidget(name, lambda x: self.muxer_setter(widget, x), lambda: get_combo_value(widget).get_name()) elif name == "acodec": mgr.bindWidget(name, lambda x: self.acodec_setter(widget, x), lambda: get_combo_value(widget).get_name()) elif name == "vcodec": mgr.bindWidget(name, lambda x: self.vcodec_setter(widget, x), lambda: get_combo_value(widget).get_name()) elif name == "depth": mgr.bindWidget(name, lambda x: self.sample_depth_setter(widget, x), lambda: get_combo_value(widget)) elif name == "sample-rate": mgr.bindWidget(name, lambda x: self.sample_rate_setter(widget, x), lambda: get_combo_value(widget)) elif name == "channels": mgr.bindWidget(name, lambda x: self.channels_setter(widget, x), lambda: get_combo_value(widget)) elif name == "frame-rate": mgr.bindWidget(name, lambda x: self.framerate_setter(widget, x), lambda: get_combo_value(widget)) def muxer_setter(self, widget, value): set_combo_value(widget, gst.element_factory_find(value)) self.settings.setEncoders(muxer=value) # Update the extension of the filename. basename = os.path.splitext(self.fileentry.get_text())[0] self.updateFilename(basename) # Update muxer-dependent widgets. self.muxer_combo_changing = True try: self.updateAvailableEncoders() finally: self.muxer_combo_changing = False def acodec_setter(self, widget, value): set_combo_value(widget, gst.element_factory_find(value)) self.settings.setEncoders(aencoder=value) if not self.muxer_combo_changing: # The user directly changed the audio encoder combo. self.preferred_aencoder = value def vcodec_setter(self, widget, value): set_combo_value(widget, gst.element_factory_find(value)) self.settings.setEncoders(vencoder=value) if not self.muxer_combo_changing: # The user directly changed the video encoder combo. self.preferred_vencoder = value def sample_depth_setter(self, widget, value): set_combo_value(widget, value) self.settings.setAudioProperties(depth=value) def sample_rate_setter(self, widget, value): set_combo_value(widget, value) self.settings.setAudioProperties(rate=value) def channels_setter(self, widget, value): set_combo_value(widget, value) self.settings.setAudioProperties(nbchanns=value) def framerate_setter(self, widget, value): set_combo_value(widget, value) self.settings.setVideoProperties(framerate=value) def bindHeight(self, mgr): mgr.bindWidget("height", lambda x: self.settings.setVideoProperties(height=x), lambda: 0) def bindWidth(self, mgr): mgr.bindWidget("width", lambda x: self.settings.setVideoProperties(width=x), lambda: 0) def getDimension(self, dimension): value = self.settings.getVideoWidthAndHeight() if dimension == "height": return value[1] elif dimension == "width": return value[0] def _fillPresetsTreeview(self, treeview, mgr, update_buttons_func): """Set up the specified treeview to display the specified presets. @param treeview: The treeview for displaying the presets. @type treeview: TreeView @param mgr: The preset manager. @type mgr: PresetManager @param update_buttons_func: A function which updates the buttons for removing and saving a preset, enabling or disabling them accordingly. @type update_buttons_func: function """ renderer = gtk.CellRendererText() renderer.props.editable = True column = gtk.TreeViewColumn("Preset", renderer, text=0) treeview.append_column(column) treeview.props.headers_visible = False model = mgr.getModel() treeview.set_model(model) model.connect("row-inserted", self._newPresetCb, column, renderer, treeview) renderer.connect("edited", self._presetNameEditedCb, mgr) renderer.connect("editing-started", self._presetNameEditingStartedCb, mgr) treeview.get_selection().connect("changed", self._presetChangedCb, mgr, update_buttons_func) treeview.connect("focus-out-event", self._treeviewDefocusedCb, mgr) def _newPresetCb(self, model, path, iter_, column, renderer, treeview): """Handle the addition of a preset to the model of the preset manager. """ treeview.set_cursor_on_cell(path, column, renderer, start_editing=True) treeview.grab_focus() def _presetNameEditedCb(self, renderer, path, new_text, mgr): """Handle the renaming of a preset.""" try: mgr.renamePreset(path, new_text) self._updateRenderPresetButtons() except DuplicatePresetNameException: error_markup = _('"%s" already exists.') % new_text self._showPresetManagerError(mgr, error_markup) def _presetNameEditingStartedCb(self, renderer, editable, path, mgr): """Handle the start of a preset renaming.""" self._hidePresetManagerError(mgr) def _treeviewDefocusedCb(self, widget, event, mgr): """Handle the treeview loosing the focus.""" self._hidePresetManagerError(mgr) def _showPresetManagerError(self, mgr, error_markup): """Show the specified error on the infobar associated with the manager. @param mgr: The preset manager for which to show the error. @type mgr: PresetManager """ infobar = self._infobarForPresetManager[mgr] # The infobar must contain exactly one object in the content area: # a label for displaying the error. label = infobar.get_content_area().children()[0] label.set_markup(error_markup) infobar.show() def _hidePresetManagerError(self, mgr): """Hide the error infobar associated with the manager. @param mgr: The preset manager for which to hide the error infobar. @type mgr: PresetManager """ infobar = self._infobarForPresetManager[mgr] infobar.hide() def _updateRenderSaveButton(self, unused_in, button): button.set_sensitive(self.render_presets.isSaveButtonSensitive()) @staticmethod def _getUniquePresetName(mgr): """Get a unique name for a new preset for the specified PresetManager. """ existing_preset_names = list(mgr.getPresetNames()) preset_name = _("New preset") i = 1 while preset_name in existing_preset_names: preset_name = _("New preset %d") % i i += 1 return preset_name def _addRenderPresetButtonClickedCb(self, button): preset_name = self._getUniquePresetName(self.render_presets) self.render_presets.addPreset(preset_name, { "depth": int(get_combo_value(self.sample_depth_combo)), "channels": int(get_combo_value(self.channels_combo)), "sample-rate": int(get_combo_value(self.sample_rate_combo)), "acodec": get_combo_value(self.audio_encoder_combo).get_name(), "vcodec": get_combo_value(self.video_encoder_combo).get_name(), "container": get_combo_value(self.muxercombobox).get_name(), "frame-rate": gst.Fraction(int(get_combo_value(self.frame_rate_combo).num), int(get_combo_value(self.frame_rate_combo).denom)), "height": 0, "width": 0}) self.render_presets.restorePreset(preset_name) self._updateRenderPresetButtons() def _saveRenderPresetButtonClickedCb(self, button): self.render_presets.savePreset() self.save_render_preset_button.set_sensitive(False) self.remove_render_preset_button.set_sensitive(True) def _updateRenderPresetButtons(self): can_save = self.render_presets.isSaveButtonSensitive() self.save_render_preset_button.set_sensitive(can_save) can_remove = self.render_presets.isRemoveButtonSensitive() self.remove_render_preset_button.set_sensitive(can_remove) def _removeRenderPresetButtonClickedCb(self, button): selection = self.render_preset_treeview.get_selection() model, iter_ = selection.get_selected() if iter_: self.render_presets.removePreset(model[iter_][0]) def _presetChangedCb(self, selection, mgr, update_preset_buttons_func): """Handle the selection of a preset.""" model, iter_ = selection.get_selected() if iter_: self.selected_preset = model[iter_][0] else: self.selected_preset = None mgr.restorePreset(self.selected_preset) self._displaySettings() update_preset_buttons_func() self._hidePresetManagerError(mgr) def _setProperties(self): self.window = self.builder.get_object("render-dialog") self.selected_only_button = self.builder.get_object( "selected_only_button") self.frame_rate_combo = self.builder.get_object("frame_rate_combo") self.scale_spinbutton = self.builder.get_object("scale_spinbutton") self.channels_combo = self.builder.get_object("channels_combo") self.sample_rate_combo = self.builder.get_object( "sample_rate_combo") self.sample_depth_combo = self.builder.get_object( "sample_depth_combo") self.muxercombobox = self.builder.get_object("muxercombobox") self.audio_encoder_combo = self.builder.get_object( "audio_encoder_combo") self.video_encoder_combo = self.builder.get_object( "video_encoder_combo") self.filebutton = self.builder.get_object("filebutton") self.fileentry = self.builder.get_object("fileentry") self.resolution_label = self.builder.get_object("resolution_label") self.render_preset_treeview = self.builder.get_object( "render_preset_treeview") self.save_render_preset_button = self.builder.get_object( "save_render_preset_button") self.remove_render_preset_button = self.builder.get_object( "remove_render_preset_button") self.render_preset_infobar = self.builder.get_object( "render-preset-infobar") def _settingsChanged(self, settings): self.updateResolution() def _initializeComboboxModels(self): self.frame_rate_combo.set_model(frame_rates) self.channels_combo.set_model(audio_channels) self.sample_rate_combo.set_model(audio_rates) self.sample_depth_combo.set_model(audio_depths) self.muxercombobox.set_model(factorylist(ExportSettings.muxers)) def _displaySettings(self): """Display the settings that also change in the ProjectSettingsDialog. """ # Video settings set_combo_value(self.frame_rate_combo, self.settings.videorate) # Audio settings set_combo_value(self.channels_combo, self.settings.audiochannels) set_combo_value(self.sample_rate_combo, self.settings.audiorate) set_combo_value(self.sample_depth_combo, self.settings.audiodepth) def _displayRenderSettings(self): """Display the settings which can be changed only in the EncodingDialog. """ # Video settings # note: this will trigger an update of the video resolution label self.scale_spinbutton.set_value(self.settings.render_scale) # Muxer settings # note: this will trigger an update of the codec comboboxes set_combo_value(self.muxercombobox, gst.element_factory_find(self.settings.muxer)) # File self.filebutton.set_current_folder(self.app.settings.lastExportFolder) self.updateFilename(self.project.name) def _checkForExistingFile(self, *args): """ Display a warning icon and tooltip if the file path already exists. """ path = self.filebutton.get_current_folder() if not path: # This happens when the window is initialized. return warning_icon = gtk.STOCK_DIALOG_WARNING filename = self.fileentry.get_text() if not filename: tooltip_text = _("A file name is required.") elif filename and os.path.exists(os.path.join(path, filename)): tooltip_text = _("This file already exists.\n" "If you don't want to overwrite it, choose a " "different file name or folder.") else: warning_icon = None tooltip_text = None self.fileentry.set_icon_from_stock(1, warning_icon) self.fileentry.set_icon_tooltip_text(1, tooltip_text) def updateFilename(self, basename): """Updates the filename UI element to show the specified file name.""" extension = extension_for_muxer(self.settings.muxer) if extension: name = "%s%s%s" % (basename, os.path.extsep, extension) else: name = basename self.fileentry.set_text(name) def _muxerComboChangedCb(self, muxer_combo): """Handle the changing of the container format combobox.""" muxer = get_combo_value(muxer_combo).get_name() self.settings.setEncoders(muxer=muxer) # Update the extension of the filename. basename = os.path.splitext(self.fileentry.get_text())[0] self.updateFilename(basename) # Update muxer-dependent widgets. self.muxer_combo_changing = True try: self.updateAvailableEncoders() finally: self.muxer_combo_changing = False def updateAvailableEncoders(self): """Update the encoder comboboxes to show the available encoders.""" video_encoders = self.settings.getVideoEncoders() video_encoder_model = factorylist(video_encoders) self.video_encoder_combo.set_model(video_encoder_model) audio_encoders = self.settings.getAudioEncoders() audio_encoder_model = factorylist(audio_encoders) self.audio_encoder_combo.set_model(audio_encoder_model) self._updateEncoderCombo( self.video_encoder_combo, self.preferred_vencoder) self._updateEncoderCombo( self.audio_encoder_combo, self.preferred_aencoder) def _updateEncoderCombo(self, encoder_combo, preferred_encoder): """Select the specified encoder for the specified encoder combo.""" if preferred_encoder: # A preferrence exists, pick it if it can be found in # the current model of the combobox. vencoder = gst.element_factory_find(preferred_encoder) set_combo_value(encoder_combo, vencoder, default_index=0) else: # No preferrence exists, pick the first encoder from # the current model of the combobox. encoder_combo.set_active(0) def _scaleSpinbuttonChangedCb(self, button): render_scale = self.scale_spinbutton.get_value() self.settings.setVideoProperties(render_scale=render_scale) self.updateResolution() def updateResolution(self): width, height = self.settings.getVideoWidthAndHeight(render=True) self.resolution_label.set_text(u"%d×%d" % (width, height)) def _projectSettingsButtonClickedCb(self, button): from pitivi.ui.projectsettings import ProjectSettingsDialog dialog = ProjectSettingsDialog(self.window, self.project) dialog.window.connect("destroy", self._projectSettingsDestroyCb) dialog.window.run() def _projectSettingsDestroyCb(self, dialog): """Handle the destruction of the ProjectSettingsDialog.""" settings = self.project.getSettings() self.settings.setVideoProperties(width=settings.videowidth, height=settings.videoheight, framerate=settings.videorate) self.settings.setAudioProperties(nbchanns=settings.audiochannels, rate=settings.audiorate, depth=settings.audiodepth) self._displaySettings() def _frameRateComboChangedCb(self, combo): framerate = get_combo_value(combo) self.settings.setVideoProperties(framerate=framerate) def _videoEncoderComboChangedCb(self, combo): vencoder = get_combo_value(combo).get_name() self.settings.setEncoders(vencoder=vencoder) if not self.muxer_combo_changing: # The user directly changed the video encoder combo. self.preferred_vencoder = vencoder def _videoSettingsButtonClickedCb(self, button): factory = get_combo_value(self.video_encoder_combo) self._elementSettingsDialog(factory, 'vcodecsettings') def _channelsComboChangedCb(self, combo): self.settings.setAudioProperties(nbchanns=get_combo_value(combo)) def _sampleDepthComboChangedCb(self, combo): self.settings.setAudioProperties(depth=get_combo_value(combo)) def _sampleRateComboChangedCb(self, combo): self.settings.setAudioProperties(rate=get_combo_value(combo)) def _audioEncoderChangedComboCb(self, combo): aencoder = get_combo_value(combo).get_name() self.settings.setEncoders(aencoder=aencoder) if not self.muxer_combo_changing: # The user directly changed the audio encoder combo. self.preferred_aencoder = aencoder def _audioSettingsButtonClickedCb(self, button): factory = get_combo_value(self.audio_encoder_combo) self._elementSettingsDialog(factory, 'acodecsettings') def _elementSettingsDialog(self, factory, settings_attr): """Open a dialog to edit the properties for the specified factory. @param factory: An element factory whose properties the user will edit. @type factory: gst.ElementFactory @param settings_attr: The ExportSettings attribute holding the properties. @type settings_attr: str """ properties = getattr(self.settings, settings_attr) self.dialog = GstElementSettingsDialog(factory, properties=properties) self.dialog.window.set_transient_for(self.window) self.dialog.ok_btn.connect("clicked", self._okButtonClickedCb, settings_attr) self.dialog.window.run() def _okButtonClickedCb(self, unused_button, settings_attr): setattr(self.settings, settings_attr, self.dialog.getSettings()) self.dialog.window.destroy() def _renderButtonClickedCb(self, unused_button): self.outfile = os.path.join(self.filebutton.get_uri(), self.fileentry.get_text()) self.progress = EncodingProgressDialog(self.app, self) self.window.hide() # Hide the rendering settings dialog while rendering self.progress.window.show() self.startAction() self.progress.connect("cancel", self._cancelRender) self.progress.connect("pause", self._pauseRender) self.pipeline.connect("state-changed", self._stateChanged) def _cancelRender(self, progress): self.debug("aborting render") self.shutdown() def _pauseRender(self, progress): self.pipeline.togglePlayback() def _stateChanged(self, pipeline, state): self.progress.setState(state) def updatePosition(self, fraction, text): if self.progress: self.progress.updatePosition(fraction, text) def updateUIOnEOS(self): """Handle the ending or the cancellation of the render process.""" self.progress.window.destroy() self.progress = None self.window.show() # Show the encoding dialog again self.pipeline.disconnect_by_function(self._stateChanged) def _closeButtonClickedCb(self, unused_button): self.debug("Render Close button clicked") self.destroy() def _deleteEventCb(self, window, event): self.debug("Render window is being deleted") self.destroy() def _updateProjectSettings(self): """Updates the settings of the project if the render settings changed. """ settings = self.project.getSettings() if (settings.muxer == self.settings.muxer and settings.aencoder == self.settings.aencoder and settings.vencoder == self.settings.vencoder and settings.containersettings == self.settings.containersettings and settings.acodecsettings == self.settings.acodecsettings and settings.vcodecsettings == self.settings.vcodecsettings and settings.render_scale == self.settings.render_scale): # No setting which can be changed in the Render dialog # and which we want to save have been changed. return settings.setEncoders(muxer=self.settings.muxer, aencoder=self.settings.aencoder, vencoder=self.settings.vencoder) settings.containersettings = self.settings.containersettings settings.acodecsettings = self.settings.acodecsettings settings.vcodecsettings = self.settings.vcodecsettings settings.setVideoProperties(render_scale=self.settings.render_scale) # Signal that the project settings have been changed. self.project.setSettings(settings) def destroy(self): self._updateProjectSettings() self.window.destroy()