70
71
(_("Anamorphic (2.4)"), gst.Fraction(24, 10)),
73
class ProjectSettingsDialog(GladeWindow):
74
glade_file = "projectsettings.glade"
75
class ProjectSettingsDialog():
76
77
def __init__(self, parent, project):
77
GladeWindow.__init__(self, parent)
78
78
self.project = project
80
79
self.settings = project.getSettings()
81
self.project = project
81
self.builder = gtk.Builder()
82
self.builder.add_from_file(os.path.join(get_ui_dir(),
83
"projectsettings.ui"))
85
self.builder.connect_signals(self)
87
# add custom display aspect ratio widget
84
88
self.dar_fraction_widget = FractionWidget()
85
89
self.video_properties_table.attach(self.dar_fraction_widget,
86
90
0, 1, 6, 7, xoptions=gtk.EXPAND | gtk.FILL, yoptions=0)
87
91
self.dar_fraction_widget.show()
93
# add custom pixel aspect ratio widget
90
94
self.par_fraction_widget = FractionWidget()
91
95
self.video_properties_table.attach(self.par_fraction_widget,
92
96
1, 2, 6, 7, xoptions=gtk.EXPAND | gtk.FILL, yoptions=0)
93
97
self.par_fraction_widget.show()
99
# add custom framerate widget
95
100
self.frame_rate_fraction_widget = FractionWidget()
96
101
self.video_properties_table.attach(self.frame_rate_fraction_widget,
97
102
1, 2, 2, 3, xoptions=gtk.EXPAND | gtk.FILL, yoptions=0)
119
self.wg = RippleUpdateGroup(
120
(self.frame_rate_combo, self._updateCombo, "changed",
121
self.frame_rate_fraction_widget),
122
(self.frame_rate_fraction_widget, self._updateFraction,
123
"value-changed", self.frame_rate_combo),
124
(self.dar_combo, None, "changed"),
125
(self.dar_fraction_widget, None, "value-changed"),
126
(self.par_combo, None, "changed"),
127
(self.par_fraction_widget, None, "value-changed"),
128
(self.width_spinbutton, None, "value-changed"),
129
(self.height_spinbutton, None, "value-changed"),
130
(self.save_audio_preset_button, self._updateAudioSaveButton),
131
(self.save_video_preset_button, self._updateVideoSaveButton),
132
(self.channels_combo,),
133
(self.sample_rate_combo,),
134
(self.sample_depth_combo,),
124
self.wg = RippleUpdateGroup()
125
self.wg.addVertex(self.frame_rate_combo,
127
update_func=self._updateCombo,
128
update_func_args=(self.frame_rate_fraction_widget,))
129
self.wg.addVertex(self.frame_rate_fraction_widget,
130
signal="value-changed",
131
update_func=self._updateFraction,
132
update_func_args=(self.frame_rate_combo,))
133
self.wg.addVertex(self.dar_combo, signal="changed")
134
self.wg.addVertex(self.dar_fraction_widget, signal="value-changed")
135
self.wg.addVertex(self.par_combo, signal="changed")
136
self.wg.addVertex(self.par_fraction_widget, signal="value-changed")
137
self.wg.addVertex(self.width_spinbutton, signal="value-changed")
138
self.wg.addVertex(self.height_spinbutton, signal="value-changed")
139
self.wg.addVertex(self.save_audio_preset_button,
140
update_func=self._updateAudioSaveButton)
141
self.wg.addVertex(self.save_video_preset_button,
142
update_func=self._updateVideoSaveButton)
143
self.wg.addVertex(self.channels_combo, signal="changed")
144
self.wg.addVertex(self.sample_rate_combo, signal="changed")
145
self.wg.addVertex(self.sample_depth_combo, signal="changed")
137
147
# constrain width and height IFF constrain_sar_button is active
138
self.wg.add_edge(self.width_spinbutton, self.height_spinbutton,
139
self.constrained, self.updateHeight)
140
self.wg.add_edge(self.height_spinbutton, self.width_spinbutton,
141
self.constrained, self.updateWidth)
148
self.wg.addEdge(self.width_spinbutton, self.height_spinbutton,
149
predicate=self.constrained, edge_func=self.updateHeight)
150
self.wg.addEdge(self.height_spinbutton, self.width_spinbutton,
151
predicate=self.constrained, edge_func=self.updateWidth)
143
153
# keep framereate text field and combo in sync
144
self.wg.add_bi_edge(self.frame_rate_combo,
154
self.wg.addBiEdge(self.frame_rate_combo,
145
155
self.frame_rate_fraction_widget)
147
157
# keep dar text field and combo in sync
148
self.wg.add_edge(self.dar_combo, self.dar_fraction_widget,
158
self.wg.addEdge(self.dar_combo, self.dar_fraction_widget,
149
159
edge_func=self.updateDarFromCombo)
150
self.wg.add_edge(self.dar_fraction_widget, self.dar_combo,
160
self.wg.addEdge(self.dar_fraction_widget, self.dar_combo,
151
161
edge_func=self.updateDarFromFractionWidget)
153
163
# keep par text field and combo in sync
154
self.wg.add_edge(self.par_combo, self.par_fraction_widget,
164
self.wg.addEdge(self.par_combo, self.par_fraction_widget,
155
165
edge_func=self.updateParFromCombo)
156
self.wg.add_edge(self.par_fraction_widget, self.par_combo,
166
self.wg.addEdge(self.par_fraction_widget, self.par_combo,
157
167
edge_func=self.updateParFromFractionWidget)
159
169
# constrain DAR and PAR values. because the combo boxes are already
160
170
# linked, we only have to link the fraction widgets together.
161
self.wg.add_edge(self.par_fraction_widget, self.dar_fraction_widget,
171
self.wg.addEdge(self.par_fraction_widget, self.dar_fraction_widget,
162
172
edge_func=self.updateDarFromPar)
163
self.wg.add_edge(self.dar_fraction_widget, self.par_fraction_widget,
173
self.wg.addEdge(self.dar_fraction_widget, self.par_fraction_widget,
164
174
edge_func=self.updateParFromDar)
166
176
# update PAR when width/height change and the DAR checkbutton is
168
self.wg.add_edge(self.width_spinbutton, self.par_fraction_widget,
178
self.wg.addEdge(self.width_spinbutton, self.par_fraction_widget,
169
179
predicate=self.darSelected, edge_func=self.updateParFromDar)
170
self.wg.add_edge(self.height_spinbutton, self.par_fraction_widget,
180
self.wg.addEdge(self.height_spinbutton, self.par_fraction_widget,
171
181
predicate=self.darSelected, edge_func=self.updateParFromDar)
173
183
# update DAR when width/height change and the PAR checkbutton is
175
self.wg.add_edge(self.width_spinbutton, self.dar_fraction_widget,
185
self.wg.addEdge(self.width_spinbutton, self.dar_fraction_widget,
176
186
predicate=self.parSelected, edge_func=self.updateDarFromPar)
177
self.wg.add_edge(self.height_spinbutton, self.dar_fraction_widget,
187
self.wg.addEdge(self.height_spinbutton, self.dar_fraction_widget,
178
188
predicate=self.parSelected, edge_func=self.updateDarFromPar)
183
193
self.video_presets = VideoPresetManager()
184
194
self.video_presets.load()
186
self.fillTreeview(self.audio_preset_treeview, self.audio_presets)
187
self.fillTreeview(self.video_preset_treeview, self.video_presets)
196
self._fillPresetsTreeview(
197
self.audio_preset_treeview, self.audio_presets,
198
self._updateAudioPresetButtons)
199
self._fillPresetsTreeview(
200
self.video_preset_treeview, self.video_presets,
201
self._updateVideoPresetButtons)
203
# A map which tells which infobar should be used when displaying
204
# an error for a preset manager.
205
self._infobarForPresetManager = {
206
self.audio_presets: self.audio_preset_infobar,
207
self.video_presets: self.video_preset_infobar}
209
# Bind the widgets in the Video tab to the Video Presets Manager.
189
210
self.bindSpinbutton(self.video_presets, "width", self.width_spinbutton)
190
211
self.bindSpinbutton(self.video_presets, "height",
191
212
self.height_spinbutton)
192
213
self.bindFractionWidget(self.video_presets, "frame-rate",
193
214
self.frame_rate_fraction_widget)
194
215
self.bindPar(self.video_presets)
217
# Bind the widgets in the Audio tab to the Audio Presets Manager.
195
218
self.bindCombo(self.audio_presets, "channels",
196
219
self.channels_combo)
197
220
self.bindCombo(self.audio_presets, "sample-rate",
199
222
self.bindCombo(self.audio_presets, "depth",
200
223
self.sample_depth_combo)
202
self.wg.add_edge(self.par_fraction_widget,
203
self.save_video_preset_button)
204
self.wg.add_edge(self.frame_rate_fraction_widget,
205
self.save_video_preset_button)
206
self.wg.add_edge(self.width_spinbutton,
207
self.save_video_preset_button)
208
self.wg.add_edge(self.height_spinbutton,
225
self.wg.addEdge(self.par_fraction_widget,
226
self.save_video_preset_button)
227
self.wg.addEdge(self.frame_rate_fraction_widget,
228
self.save_video_preset_button)
229
self.wg.addEdge(self.width_spinbutton,
230
self.save_video_preset_button)
231
self.wg.addEdge(self.height_spinbutton,
209
232
self.save_video_preset_button)
211
self.wg.add_edge(self.channels_combo,
212
self.save_audio_preset_button)
213
self.wg.add_edge(self.sample_rate_combo,
214
self.save_audio_preset_button)
215
self.wg.add_edge(self.sample_depth_combo,
234
self.wg.addEdge(self.channels_combo,
235
self.save_audio_preset_button)
236
self.wg.addEdge(self.sample_rate_combo,
237
self.save_audio_preset_button)
238
self.wg.addEdge(self.sample_depth_combo,
216
239
self.save_audio_preset_button)
234
257
def bindCombo(self, mgr, name, widget):
235
258
mgr.bindWidget(name,
236
259
lambda x: set_combo_value(widget, x),
237
lambda : get_combo_value(widget))
260
lambda: get_combo_value(widget))
239
262
def bindSpinbutton(self, mgr, name, widget):
240
263
mgr.bindWidget(name,
241
264
lambda x: widget.set_value(float(x)),
242
lambda : int(widget.get_value()))
244
def presetNameEditedCb(self, renderer, path, new_text, mgr):
245
mgr.renamePreset(path, new_text)
246
mgr.cur_preset = new_text
248
def fillTreeview(self, treeview, mgr):
265
lambda: int(widget.get_value()))
267
def _fillPresetsTreeview(self, treeview, mgr, update_buttons_func):
268
"""Set up the specified treeview to display the specified presets.
270
@param treeview: The treeview for displaying the presets.
271
@type treeview: TreeView
272
@param mgr: The preset manager.
273
@type mgr: PresetManager
274
@param update_buttons_func: A function which updates the buttons for
275
removing and saving a preset, enabling or disabling them accordingly.
276
@type update_buttons_func: function
249
278
renderer = gtk.CellRendererText()
250
279
renderer.props.editable = True
251
280
column = gtk.TreeViewColumn("Preset", renderer, text=0)
255
284
treeview.set_model(model)
256
285
model.connect("row-inserted", self._newPresetCb,
257
286
column, renderer, treeview)
258
renderer.connect("edited", self.presetNameEditedCb, mgr)
287
renderer.connect("edited", self._presetNameEditedCb, mgr)
288
renderer.connect("editing-started", self._presetNameEditingStartedCb,
259
290
treeview.get_selection().connect("changed", self._presetChangedCb,
291
mgr, update_buttons_func)
292
treeview.connect("focus-out-event", self._treeviewDefocusedCb, mgr)
262
294
def _newPresetCb(self, model, path, iter_, column, renderer, treeview):
295
"""Handle the addition of a preset to the model of the preset manager.
263
297
treeview.set_cursor_on_cell(path, column, renderer, start_editing=True)
264
298
treeview.grab_focus()
266
def _presetChangedCb(self, selection, mgr):
300
def _presetNameEditedCb(self, renderer, path, new_text, mgr):
301
"""Handle the renaming of a preset."""
303
mgr.renamePreset(path, new_text)
304
except DuplicatePresetNameException:
305
error_markup = _('"%s" already exists.') % new_text
306
self._showPresetManagerError(mgr, error_markup)
308
def _presetNameEditingStartedCb(self, renderer, editable, path, mgr):
309
"""Handle the start of a preset renaming."""
310
self._hidePresetManagerError(mgr)
312
def _presetChangedCb(self, selection, mgr, update_preset_buttons_func):
313
"""Handle the selection of a preset."""
267
314
model, iter_ = selection.get_selected()
269
316
preset = model[iter_][0]
272
319
mgr.restorePreset(preset)
273
if mgr == self.audio_presets:
274
self._updateAudioSaveButton(None, self.save_audio_preset_button)
275
self.remove_audio_preset_button.set_sensitive(bool(preset))
277
self._updateVideoSaveButton(None, self.save_video_preset_button)
278
self.remove_video_preset_button.set_sensitive(bool(preset))
320
update_preset_buttons_func()
321
self._hidePresetManagerError(mgr)
323
def _treeviewDefocusedCb(self, widget, event, mgr):
324
"""Handle the treeview loosing the focus."""
325
self._hidePresetManagerError(mgr)
327
def _showPresetManagerError(self, mgr, error_markup):
328
"""Show the specified error on the infobar associated with the manager.
330
@param mgr: The preset manager for which to show the error.
331
@type mgr: PresetManager
333
infobar = self._infobarForPresetManager[mgr]
334
# The infobar must contain exactly one object in the content area:
335
# a label for displaying the error.
336
label = infobar.get_content_area().children()[0]
337
label.set_markup(error_markup)
340
def _hidePresetManagerError(self, mgr):
341
"""Hide the error infobar associated with the manager.
343
@param mgr: The preset manager for which to hide the error infobar.
344
@type mgr: PresetManager
346
infobar = self._infobarForPresetManager[mgr]
280
349
def constrained(self):
281
350
return self.constrain_sar_button.props.active
291
360
height = int(self.height_spinbutton.get_value())
292
361
return gst.Fraction(width, height)
363
def _setProperties(self):
364
self.window = self.builder.get_object("project-settings-dialog")
365
self.video_properties_table = self.builder.get_object(
366
"video_properties_table")
367
self.video_properties_table = self.builder.get_object(
368
"video_properties_table")
369
self.frame_rate_combo = self.builder.get_object("frame_rate_combo")
370
self.dar_combo = self.builder.get_object("dar_combo")
371
self.par_combo = self.builder.get_object("par_combo")
372
self.channels_combo = self.builder.get_object("channels_combo")
373
self.sample_rate_combo = self.builder.get_object("sample_rate_combo")
374
self.sample_depth_combo = self.builder.get_object("sample_depth_combo")
375
self.year_spinbutton = self.builder.get_object("year_spinbutton")
376
self.author_entry = self.builder.get_object("author_entry")
377
self.width_spinbutton = self.builder.get_object("width_spinbutton")
378
self.height_spinbutton = self.builder.get_object("height_spinbutton")
379
self.save_audio_preset_button = self.builder.get_object(
380
"save_audio_preset_button")
381
self.save_video_preset_button = self.builder.get_object(
382
"save_video_preset_button")
383
self.audio_preset_treeview = self.builder.get_object(
384
"audio_preset_treeview")
385
self.video_preset_treeview = self.builder.get_object(
386
"video_preset_treeview")
387
self.select_par_radiobutton = self.builder.get_object(
388
"select_par_radiobutton")
389
self.remove_audio_preset_button = self.builder.get_object(
390
"remove_audio_preset_button")
391
self.remove_video_preset_button = self.builder.get_object(
392
"remove_video_preset_button")
393
self.constrain_sar_button = self.builder.get_object(
394
"constrain_sar_button")
395
self.select_dar_radiobutton = self.builder.get_object(
396
"select_dar_radiobutton")
397
self.video_preset_infobar = self.builder.get_object(
398
"video-preset-infobar")
399
self.audio_preset_infobar = self.builder.get_object(
400
"audio-preset-infobar")
294
402
def _constrainSarButtonToggledCb(self, button):
295
403
if button.props.active:
296
404
self.sar = self.getSAR()
302
410
self.par_fraction_widget.set_sensitive(not state)
303
411
self.par_combo.set_sensitive(not state)
414
def _getUniquePresetName(mgr):
415
"""Get a unique name for a new preset for the specified PresetManager.
417
existing_preset_names = list(mgr.getPresetNames())
418
preset_name = _("New Preset")
420
while preset_name in existing_preset_names:
421
preset_name = _("New Preset %d") % i
305
425
def _addAudioPresetButtonClickedCb(self, button):
306
self.audio_presets.addPreset(_("New Preset"), {
307
"channels" : get_combo_value(self.channels_combo),
308
"sample-rate" : get_combo_value(self.sample_rate_combo),
309
"depth" : get_combo_value(self.sample_depth_combo)
426
preset_name = self._getUniquePresetName(self.audio_presets)
427
self.audio_presets.addPreset(preset_name, {
428
"channels": get_combo_value(self.channels_combo),
429
"sample-rate": get_combo_value(self.sample_rate_combo),
430
"depth": get_combo_value(self.sample_depth_combo)
432
self.audio_presets.restorePreset(preset_name)
433
self._updateAudioPresetButtons()
312
435
def _removeAudioPresetButtonClickedCb(self, button):
313
436
selection = self.audio_preset_treeview.get_selection()
334
460
self.video_presets.removePreset(model[iter_][0])
336
def _saveVideoPresetClickedCb(self, button):
462
def _saveVideoPresetButtonClickedCb(self, button):
337
463
self.video_presets.savePreset()
338
464
self.save_video_preset_button.set_sensitive(False)
466
def _updateAudioPresetButtons(self):
467
preset_changed = self.audio_presets.isCurrentPresetChanged()
468
self.save_audio_preset_button.set_sensitive(preset_changed)
469
preset_selected = bool(self.audio_presets.cur_preset)
470
self.remove_audio_preset_button.set_sensitive(preset_selected)
472
def _updateVideoPresetButtons(self):
473
preset_changed = self.video_presets.isCurrentPresetChanged()
474
self.save_video_preset_button.set_sensitive(preset_changed)
475
preset_selected = bool(self.video_presets.cur_preset)
476
self.remove_video_preset_button.set_sensitive(preset_selected)
340
478
def _updateAudioSaveButton(self, unused_in, button):
341
button.set_sensitive(self.audio_presets.changed())
479
button.set_sensitive(self.audio_presets.isCurrentPresetChanged())
343
481
def _updateVideoSaveButton(self, unused_in, button):
344
button.set_sensitive(self.video_presets.changed())
482
button.set_sensitive(self.video_presets.isCurrentPresetChanged())
346
484
def darSelected(self):
347
485
return self.select_dar_radiobutton.props.active