Some vague sort of progress.
[dcpomatic.git] / src / wx / film_editor.cc
1 /*
2     Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 /** @file src/film_editor.cc
21  *  @brief A wx widget to edit a film's metadata, and perform various functions.
22  */
23
24 #include <iostream>
25 #include <wx/wx.h>
26 #include <boost/thread.hpp>
27 #include <boost/filesystem.hpp>
28 #include "lib/format.h"
29 #include "lib/film.h"
30 #include "lib/transcode_job.h"
31 #include "lib/exceptions.h"
32 #include "lib/ab_transcode_job.h"
33 #include "lib/thumbs_job.h"
34 #include "lib/job_manager.h"
35 #include "lib/filter.h"
36 #include "lib/screen.h"
37 #include "lib/config.h"
38 //#include "filter_dialog.h"
39 #include "wx_util.h"
40 #include "film_editor.h"
41 //#include "dcp_range_dialog.h"
42
43 using namespace std;
44 using namespace boost;
45
46 /** @param f Film to edit */
47 FilmEditor::FilmEditor (Film* f, wxWindow* parent)
48         : wxPanel (parent)
49         , _film (f)
50 {
51         _name = new wxTextCtrl (this, wxID_ANY);
52         _frames_per_second = new wxSpinCtrl (this);
53         _format = new wxComboBox (this, wxID_ANY);
54 //      _content = new wxFileCtrl (this, wxID_ANY, wxT("*.*"), false);
55         _crop_panel = new wxPanel (this);
56         _left_crop = new wxSpinCtrl (_crop_panel);
57         _right_crop = new wxSpinCtrl (_crop_panel);
58         _top_crop = new wxSpinCtrl (_crop_panel);
59         _bottom_crop = new wxSpinCtrl (_crop_panel);
60         _filters = new wxStaticText (this, wxID_ANY, wxT (""));
61         _filters_button = new wxButton (this, wxID_ANY, wxT ("Edit..."));
62         _scaler = new wxComboBox (this, wxID_ANY);
63         _audio_gain = new wxSpinCtrl (this);
64         _audio_delay = new wxSpinCtrl (this);
65         _dcp_content_type = new wxComboBox (this, wxID_ANY);
66         _original_size = new wxStaticText (this, wxID_ANY, wxT (""));
67         _change_dcp_range_button = new wxButton (this, wxID_ANY, wxT ("Edit..."));
68         _dcp_ab = new wxCheckBox (this, wxID_ANY, wxT ("A/B"));
69
70 //XXX   _vbox.set_border_width (12);
71 //XXX   _vbox.set_spacing (12);
72         
73         /* Set up our editing widgets */
74         _left_crop->SetRange (0, 1024);
75 //XXX   _left_crop.set_increments (1, 16);
76         _top_crop->SetRange (0, 1024);
77 //XXX   _top_crop.set_increments (1, 16);
78         _right_crop->SetRange (0, 1024);
79 //XXX   _right_crop.set_increments (1, 16);
80         _bottom_crop->SetRange (0, 1024);
81 //XXX   _bottom_crop.set_increments (1, 16);
82 //XXX   _filters.set_alignment (0, 0.5);
83         _audio_gain->SetRange (-60, 60);
84 //XXX   _audio_gain.set_increments (1, 3);
85         _audio_delay->SetRange (-1000, 1000);
86 //XXX   _audio_delay.set_increments (1, 20);
87         _still_duration = new wxSpinCtrl (this);
88         _still_duration->SetRange (0, 60 * 60);
89 //XXX   _still_duration.set_increments (1, 5);
90         _dcp_range = new wxStaticText (this, wxID_ANY, wxT (""));
91 //      _dcp_range.set_alignment (0, 0.5);
92
93         vector<Format const *> fmt = Format::all ();
94         for (vector<Format const *>::iterator i = fmt.begin(); i != fmt.end(); ++i) {
95                 _format->Append (wxString ((*i)->name().c_str(), wxConvUTF8));
96         }
97
98 //XXX   _frames_per_second.set_increments (1, 5);
99 //XXX   _frames_per_second.set_digits (2);
100         _frames_per_second->SetRange (0, 60);
101
102         vector<DCPContentType const *> const ct = DCPContentType::all ();
103         for (vector<DCPContentType const *>::const_iterator i = ct.begin(); i != ct.end(); ++i) {
104                 _dcp_content_type->Append (wxString ((*i)->pretty_name().c_str(), wxConvUTF8));
105         }
106
107         vector<Scaler const *> const sc = Scaler::all ();
108         for (vector<Scaler const *>::const_iterator i = sc.begin(); i != sc.end(); ++i) {
109                 _scaler->Append (wxString ((*i)->name().c_str(), wxConvUTF8));
110         }
111
112 //XXX   _original_size.set_alignment (0, 0.5);
113         _length = new wxStaticText (this, wxID_ANY, wxT (""));
114 //XXX   _length.set_alignment (0, 0.5);
115         _audio = new wxStaticText (this, wxID_ANY, wxT (""));
116 //XXX   _audio.set_alignment (0, 0.5);
117
118         /* And set their values from the Film */
119         set_film (f);
120         
121         /* Now connect to them, since initial values are safely set */
122         _name->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (FilmEditor::name_changed), 0, this);
123         _frames_per_second->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::frames_per_second_changed), 0, this);
124         _format->Connect (wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler (FilmEditor::format_changed), 0, this);
125 //XXX   _content.signal_file_set().connect (sigc::mem_fun (*this, &FilmEditor::content_changed));
126         _left_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::left_crop_changed), 0, this);
127         _right_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::right_crop_changed), 0, this);
128         _top_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::top_crop_changed), 0, this);
129         _bottom_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::bottom_crop_changed), 0, this);
130         _filters_button->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::edit_filters_clicked), 0, this);
131         _scaler->Connect (wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler (FilmEditor::scaler_changed), 0, this);
132         _dcp_content_type->Connect (wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler (FilmEditor::dcp_content_type_changed), 0, this);
133         _dcp_ab->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::dcp_ab_toggled), 0, this);
134         _audio_gain->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::audio_gain_changed), 0, this);
135         _audio_delay->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::audio_delay_changed), 0, this);
136         _still_duration->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::still_duration_changed), 0, this);
137         _change_dcp_range_button->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::change_dcp_range_clicked), 0, this);
138
139
140         /* Set up the sizer */
141         _sizer = new wxFlexGridSizer (3, 6, 6);
142         this->SetSizer (_sizer);
143
144         _name_label = new wxStaticText (this, wxID_ANY, wxT ("Name"));
145         _name_label->Show (true);
146         _sizer->Add (_name_label, 0, wxALIGN_CENTER_VERTICAL);
147         _sizer->Add (_name, 1, wxEXPAND);
148         _sizer->AddSpacer (0);
149
150 #if 0   
151         _content_label = new wxStaticText (this, wxID_ANY, wxT ("Content"));
152         _sizer->Add (_content_label, 0, wxALIGN_CENTER_VERTICAL);
153         _sizer->Add (_content, 1, wxEXPAND);
154         _sizer->AddSpacer (0);
155 #endif  
156
157         _dcp_content_type_label = new wxStaticText (this, wxID_ANY, wxT ("Content Type"));
158         _sizer->Add (_dcp_content_type_label, 0, wxALIGN_CENTER_VERTICAL);
159         _sizer->Add (_dcp_content_type);
160         _sizer->AddSpacer (0);
161
162         _frames_per_second_label = new wxStaticText (this, wxID_ANY, wxT ("Frames Per Second"));
163         video_control (_frames_per_second_label);
164         _sizer->Add (_frames_per_second_label, 0, wxALIGN_CENTER_VERTICAL);
165         _sizer->Add (video_control (_frames_per_second));
166         _sizer->AddSpacer (0);
167
168         _format_label = new wxStaticText (this, wxID_ANY, wxT ("Format"));
169         _sizer->Add (_format_label, 0, wxALIGN_CENTER_VERTICAL);
170         _sizer->Add (_format);
171         _sizer->AddSpacer (0);
172
173         _crop_label = new wxStaticText (this, wxID_ANY, wxT ("Crop"));
174         _sizer->Add (_crop_label, 0, wxALIGN_CENTER_VERTICAL);
175
176         _crop_sizer = new wxBoxSizer (wxHORIZONTAL);
177         _crop_panel->SetSizer (_crop_sizer);
178
179         _left_crop_label = new wxStaticText (_crop_panel, wxID_ANY, wxT ("L"));
180         _crop_sizer->Add (_left_crop_label, 0, wxALIGN_CENTER_VERTICAL);
181         _crop_sizer->Add (_left_crop, 0);
182         _right_crop_label = new wxStaticText (_crop_panel, wxID_ANY, wxT ("R"));
183         _crop_sizer->Add (_right_crop_label, 0, wxALIGN_CENTER_VERTICAL);
184         _crop_sizer->Add (_right_crop, 0);
185         _top_crop_label = new wxStaticText (_crop_panel, wxID_ANY, wxT ("T"));
186         _crop_sizer->Add (_top_crop_label, 0, wxALIGN_CENTER_VERTICAL);
187         _crop_sizer->Add (_top_crop, 0);
188         _bottom_crop_label = new wxStaticText (_crop_panel, wxID_ANY, wxT ("B"));
189         _crop_sizer->Add (_bottom_crop_label, 0, wxALIGN_CENTER_VERTICAL);
190         _crop_sizer->Add (_bottom_crop, 0);
191
192         _sizer->Add (_crop_panel);
193         _sizer->AddSpacer (0);
194
195         /* VIDEO-only stuff */
196         _filters_label = new wxStaticText (this, wxID_ANY, wxT ("Filters"));
197         video_control (_filters_label);
198         _sizer->Add (_filters_label, 0, wxALIGN_CENTER_VERTICAL);
199         _sizer->Add (_filters, 1, wxALIGN_CENTER_VERTICAL);
200         _sizer->Add (_filters_button, 0);
201
202         video_control (add_label_to_sizer (_sizer, this, _labels, "Scaler"));
203         _sizer->Add (video_control (_scaler), 1);
204         _sizer->AddSpacer (0);
205
206         video_control (add_label_to_sizer (_sizer, this, _labels, "Audio Gain"));
207         _sizer->Add (video_control (_audio_gain), 1);
208         video_control (add_label_to_sizer (_sizer, this, _labels, "dB"));
209
210         video_control (add_label_to_sizer (_sizer, this, _labels, "Audio Delay"));
211         _sizer->Add (video_control (_audio_delay), 1);
212         video_control (add_label_to_sizer (_sizer, this, _labels, "ms"));
213
214         video_control (add_label_to_sizer (_sizer, this, _labels, "Original Size"));
215         _sizer->Add (video_control (_original_size), 1);
216         _sizer->AddSpacer (0);
217         
218         video_control (add_label_to_sizer (_sizer, this, _labels, "Length"));
219         _sizer->Add (video_control (_length), 1);
220         _sizer->AddSpacer (0);
221
222         video_control (add_label_to_sizer (_sizer, this, _labels, "Audio"));
223         _sizer->Add (video_control (_audio), 1);
224         _sizer->AddSpacer (0);
225
226         video_control (add_label_to_sizer (_sizer, this, _labels, "Range"));
227         _sizer->Add (video_control (_dcp_range));
228         _sizer->Add (video_control (_change_dcp_range_button));
229
230         _sizer->Add (_dcp_ab, 1);
231         _sizer->AddSpacer (0);
232         _sizer->AddSpacer (0);
233
234         /* STILL-only stuff */
235         still_control (add_label_to_sizer (_sizer, this, _labels, "Duration"));
236         _sizer->Add (still_control (_still_duration));
237         still_control (add_label_to_sizer (_sizer, this, _labels, "s"));
238
239         setup_visibility ();
240 }
241
242 /** Called when the left crop widget has been changed */
243 void
244 FilmEditor::left_crop_changed (wxCommandEvent &)
245 {
246         if (_film) {
247                 _film->set_left_crop (_left_crop->GetValue ());
248         }
249 }
250
251 /** Called when the right crop widget has been changed */
252 void
253 FilmEditor::right_crop_changed (wxCommandEvent &)
254 {
255         if (_film) {
256                 _film->set_right_crop (_right_crop->GetValue ());
257         }
258 }
259
260 /** Called when the top crop widget has been changed */
261 void
262 FilmEditor::top_crop_changed (wxCommandEvent &)
263 {
264         if (_film) {
265                 _film->set_top_crop (_top_crop->GetValue ());
266         }
267 }
268
269 /** Called when the bottom crop value has been changed */
270 void
271 FilmEditor::bottom_crop_changed (wxCommandEvent &)
272 {
273         if (_film) {
274                 _film->set_bottom_crop (_bottom_crop->GetValue ());
275         }
276 }
277
278 /** Called when the content filename has been changed */
279 void
280 FilmEditor::content_changed (wxCommandEvent &)
281 {
282         if (!_film) {
283                 return;
284         }
285
286         try {
287 //XXX           _film->set_content (_content.get_filename ());
288         } catch (std::exception& e) {
289 //XXX           _content.set_filename (_film->directory ());
290                 stringstream m;
291                 m << "Could not set content: " << e.what() << ".";
292 //XXX           Gtk::MessageDialog d (m.str(), false, MESSAGE_ERROR);
293 //XXX           d.set_title ("DVD-o-matic");
294 //XXX           d.run ();
295         }
296 }
297
298 /** Called when the DCP A/B switch has been toggled */
299 void
300 FilmEditor::dcp_ab_toggled (wxCommandEvent &)
301 {
302         if (_film) {
303                 _film->set_dcp_ab (_dcp_ab->GetValue ());
304         }
305 }
306
307 /** Called when the name widget has been changed */
308 void
309 FilmEditor::name_changed (wxCommandEvent &)
310 {
311         if (_film) {
312                 _film->set_name (string (_name->GetValue().mb_str()));
313         }
314 }
315
316 /** Called when the metadata stored in the Film object has changed;
317  *  so that we can update the GUI.
318  *  @param p Property of the Film that has changed.
319  */
320 void
321 FilmEditor::film_changed (Film::Property p)
322 {
323         if (!_film) {
324                 return;
325         }
326         
327         stringstream s;
328                 
329         switch (p) {
330         case Film::CONTENT:
331 //XXX           _content.set_filename (_film->content ());
332                 setup_visibility ();
333                 break;
334         case Film::FORMAT:
335                 _format->SetSelection (Format::as_index (_film->format ()));
336                 break;
337         case Film::LEFT_CROP:
338                 _left_crop->SetValue (_film->left_crop ());
339                 break;
340         case Film::RIGHT_CROP:
341                 _right_crop->SetValue (_film->right_crop ());
342                 break;
343         case Film::TOP_CROP:
344                 _top_crop->SetValue (_film->top_crop ());
345                 break;
346         case Film::BOTTOM_CROP:
347                 _bottom_crop->SetValue (_film->bottom_crop ());
348                 break;
349         case Film::FILTERS:
350         {
351                 pair<string, string> p = Filter::ffmpeg_strings (_film->filters ());
352                 string const b = p.first + " " + p.second;
353                 _filters->SetLabel (wxString (b.c_str(), wxConvUTF8));
354                 break;
355         }
356         case Film::NAME:
357                 _name->SetValue (wxString (_film->name().c_str(), wxConvUTF8));
358                 break;
359         case Film::FRAMES_PER_SECOND:
360                 _frames_per_second->SetValue (_film->frames_per_second ());
361                 break;
362         case Film::AUDIO_CHANNELS:
363         case Film::AUDIO_SAMPLE_RATE:
364                 if (_film->audio_channels() == 0 && _film->audio_sample_rate() == 0) {
365                         _audio->SetLabel (wxT (""));
366                 } else {
367                         s << _film->audio_channels () << " channels, " << _film->audio_sample_rate() << "Hz";
368                         _audio->SetLabel (wxString (s.str().c_str(), wxConvUTF8));
369                 }
370                 break;
371         case Film::SIZE:
372                 if (_film->size().width == 0 && _film->size().height == 0) {
373                         _original_size->SetLabel (wxT (""));
374                 } else {
375                         s << _film->size().width << " x " << _film->size().height;
376                         _original_size->SetLabel (wxString (s.str().c_str(), wxConvUTF8));
377                 }
378                 break;
379         case Film::LENGTH:
380                 if (_film->frames_per_second() > 0 && _film->length() > 0) {
381                         s << _film->length() << " frames; " << seconds_to_hms (_film->length() / _film->frames_per_second());
382                 } else if (_film->length() > 0) {
383                         s << _film->length() << " frames";
384                 } 
385                 _length->SetLabel (wxString (s.str().c_str(), wxConvUTF8));
386                 break;
387         case Film::DCP_CONTENT_TYPE:
388                 _dcp_content_type->SetSelection (DCPContentType::as_index (_film->dcp_content_type ()));
389                 break;
390         case Film::THUMBS:
391                 break;
392         case Film::DCP_FRAMES:
393                 if (_film->dcp_frames() == 0) {
394                         _dcp_range->SetLabel (wxT ("Whole film"));
395                 } else {
396                         stringstream s;
397                         s << "First " << _film->dcp_frames() << " frames";
398                         _dcp_range->SetLabel (wxString (s.str().c_str(), wxConvUTF8));
399                 }
400                 break;
401         case Film::DCP_TRIM_ACTION:
402                 break;
403         case Film::DCP_AB:
404                 _dcp_ab->SetValue (_film->dcp_ab ());
405                 break;
406         case Film::SCALER:
407                 _scaler->SetSelection (Scaler::as_index (_film->scaler ()));
408                 break;
409         case Film::AUDIO_GAIN:
410                 _audio_gain->SetValue (_film->audio_gain ());
411                 break;
412         case Film::AUDIO_DELAY:
413                 _audio_delay->SetValue (_film->audio_delay ());
414                 break;
415         case Film::STILL_DURATION:
416                 _still_duration->SetValue (_film->still_duration ());
417                 break;
418         }
419 }
420
421 /** Called when the format widget has been changed */
422 void
423 FilmEditor::format_changed (wxCommandEvent &)
424 {
425         if (!_film) {
426                 return;
427         }
428
429         int const n = _format->GetSelection ();
430         if (n >= 0) {
431                 _film->set_format (Format::from_index (n));
432         }
433 }
434
435 /** Called when the DCP content type widget has been changed */
436 void
437 FilmEditor::dcp_content_type_changed (wxCommandEvent &)
438 {
439         if (!_film) {
440                 return;
441         }
442         
443         int const n = _dcp_content_type->GetSelection ();
444         if (n >= 0) {
445                 _film->set_dcp_content_type (DCPContentType::from_index (n));
446         }
447 }
448
449 /** Sets the Film that we are editing */
450 void
451 FilmEditor::set_film (Film* f)
452 {
453         _film = f;
454
455         set_things_sensitive (_film != 0);
456
457         if (_film) {
458                 _film->Changed.connect (sigc::mem_fun (*this, &FilmEditor::film_changed));
459         }
460
461         if (_film) {
462 //              FileChanged (_film->directory ());
463         } else {
464 //              FileChanged ("");
465         }
466         
467         film_changed (Film::NAME);
468         film_changed (Film::CONTENT);
469         film_changed (Film::DCP_CONTENT_TYPE);
470         film_changed (Film::FORMAT);
471         film_changed (Film::LEFT_CROP);
472         film_changed (Film::RIGHT_CROP);
473         film_changed (Film::TOP_CROP);
474         film_changed (Film::BOTTOM_CROP);
475         film_changed (Film::FILTERS);
476         film_changed (Film::DCP_FRAMES);
477         film_changed (Film::DCP_TRIM_ACTION);
478         film_changed (Film::DCP_AB);
479         film_changed (Film::SIZE);
480         film_changed (Film::LENGTH);
481         film_changed (Film::FRAMES_PER_SECOND);
482         film_changed (Film::AUDIO_CHANNELS);
483         film_changed (Film::AUDIO_SAMPLE_RATE);
484         film_changed (Film::SCALER);
485         film_changed (Film::AUDIO_GAIN);
486         film_changed (Film::AUDIO_DELAY);
487         film_changed (Film::STILL_DURATION);
488 }
489
490 /** Updates the sensitivity of lots of widgets to a given value.
491  *  @param s true to make sensitive, false to make insensitive.
492  */
493 void
494 FilmEditor::set_things_sensitive (bool s)
495 {
496         _name->Enable (s);
497         _frames_per_second->Enable (s);
498         _format->Enable (s);
499 //      _content->Enable (s);
500         _left_crop->Enable (s);
501         _right_crop->Enable (s);
502         _top_crop->Enable (s);
503         _bottom_crop->Enable (s);
504         _filters_button->Enable (s);
505         _scaler->Enable (s);
506         _dcp_content_type->Enable (s);
507         _dcp_range->Enable (s);
508         _change_dcp_range_button->Enable (s);
509         _dcp_ab->Enable (s);
510         _audio_gain->Enable (s);
511         _audio_delay->Enable (s);
512         _still_duration->Enable (s);
513 }
514
515 /** Called when the `Edit filters' button has been clicked */
516 void
517 FilmEditor::edit_filters_clicked (wxCommandEvent &)
518 {
519 //      FilterDialog d (_film->filters ());
520 //      d.ActiveChanged.connect (sigc::mem_fun (*_film, &Film::set_filters));
521 //      d.run ();
522 }
523
524 /** Called when the scaler widget has been changed */
525 void
526 FilmEditor::scaler_changed (wxCommandEvent &)
527 {
528         if (!_film) {
529                 return;
530         }
531         
532         int const n = _scaler->GetSelection ();
533         if (n >= 0) {
534                 _film->set_scaler (Scaler::from_index (n));
535         }
536 }
537
538 /** Called when the frames per second widget has been changed */
539 void
540 FilmEditor::frames_per_second_changed (wxCommandEvent &)
541 {
542         if (!_film) {
543                 return;
544         }
545         
546         _film->set_frames_per_second (_frames_per_second->GetValue ());
547 }
548
549 void
550 FilmEditor::audio_gain_changed (wxCommandEvent &)
551 {
552         if (!_film) {
553                 return;
554         }
555         
556         _film->set_audio_gain (_audio_gain->GetValue ());
557 }
558
559 void
560 FilmEditor::audio_delay_changed (wxCommandEvent &)
561 {
562         if (!_film) {
563                 return;
564         }
565
566         _film->set_audio_delay (_audio_delay->GetValue ());
567 }
568
569 wxControl *
570 FilmEditor::video_control (wxControl* c)
571 {
572         _video_controls.push_back (c);
573         return c;
574 }
575
576 wxControl *
577 FilmEditor::still_control (wxControl* c)
578 {
579         _still_controls.push_back (c);
580         return c;
581 }
582
583 void
584 FilmEditor::setup_visibility ()
585 {
586         ContentType c = VIDEO;
587
588         if (_film) {
589                 c = _film->content_type ();
590         }
591
592         for (list<wxControl*>::iterator i = _video_controls.begin(); i != _video_controls.end(); ++i) {
593                 (*i)->Show (c == VIDEO);
594         }
595
596         for (list<wxControl*>::iterator i = _still_controls.begin(); i != _still_controls.end(); ++i) {
597                 (*i)->Show (c == STILL);
598         }
599 }
600
601 void
602 FilmEditor::still_duration_changed (wxCommandEvent &)
603 {
604         if (_film) {
605                 _film->set_still_duration (_still_duration->GetValue ());
606         }
607 }
608
609 void
610 FilmEditor::change_dcp_range_clicked (wxCommandEvent &)
611 {
612 //XXX   DCPRangeDialog d (_film);
613 //XXX   d.Changed.connect (sigc::mem_fun (*this, &FilmEditor::dcp_range_changed));
614 //XXX   d.run ();
615 }
616
617 void
618 FilmEditor::dcp_range_changed (int frames, TrimAction action)
619 {
620         _film->set_dcp_frames (frames);
621         _film->set_dcp_trim_action (action);
622 }