swaroop: basic manipulation of content in playlist creator.
[dcpomatic.git] / src / wx / controls.cc
1 /*
2     Copyright (C) 2018 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     DCP-o-matic is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21 #include "controls.h"
22 #include "film_viewer.h"
23 #include "wx_util.h"
24 #include "playhead_to_timecode_dialog.h"
25 #include "playhead_to_frame_dialog.h"
26 #include "content_view.h"
27 #include "lib/job_manager.h"
28 #include "lib/player_video.h"
29 #include "lib/dcp_content.h"
30 #include "lib/job.h"
31 #include "lib/examine_content_job.h"
32 #include "lib/content_factory.h"
33 #include "lib/cross.h"
34 #include <dcp/dcp.h>
35 #include <dcp/cpl.h>
36 #include <dcp/reel.h>
37 #include <dcp/reel_picture_asset.h>
38 #include <wx/wx.h>
39 #include <wx/tglbtn.h>
40 #include <wx/listctrl.h>
41 #include <wx/progdlg.h>
42
43 using std::string;
44 using std::list;
45 using std::make_pair;
46 using std::exception;
47 using boost::optional;
48 using boost::shared_ptr;
49 using boost::weak_ptr;
50 using boost::dynamic_pointer_cast;
51
52 Controls::Controls (wxWindow* parent, shared_ptr<FilmViewer> viewer, bool editor_controls)
53         : wxPanel (parent)
54         , _viewer (viewer)
55         , _slider_being_moved (false)
56         , _was_running_before_slider (false)
57         , _outline_content (0)
58         , _eye (0)
59         , _jump_to_selected (0)
60         , _slider (new wxSlider (this, wxID_ANY, 0, 0, 4096))
61         , _rewind_button (new wxButton (this, wxID_ANY, wxT("|<")))
62         , _back_button (new wxButton (this, wxID_ANY, wxT("<")))
63         , _forward_button (new wxButton (this, wxID_ANY, wxT(">")))
64         , _frame_number (new wxStaticText (this, wxID_ANY, wxT("")))
65         , _timecode (new wxStaticText (this, wxID_ANY, wxT("")))
66 #ifdef DCPOMATIC_VARIANT_SWAROOP
67         , _play_button (new wxButton(this, wxID_ANY, _("Play")))
68         , _pause_button (new wxButton(this, wxID_ANY, _("Pause")))
69         , _stop_button (new wxButton(this, wxID_ANY, _("Stop")))
70 #else
71         , _play_button (new wxToggleButton(this, wxID_ANY, _("Play")))
72 #endif
73 {
74         _v_sizer = new wxBoxSizer (wxVERTICAL);
75         SetSizer (_v_sizer);
76
77         wxBoxSizer* view_options = new wxBoxSizer (wxHORIZONTAL);
78         if (editor_controls) {
79                 _outline_content = new wxCheckBox (this, wxID_ANY, _("Outline content"));
80                 view_options->Add (_outline_content, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_GAP);
81                 _eye = new wxChoice (this, wxID_ANY);
82                 _eye->Append (_("Left"));
83                 _eye->Append (_("Right"));
84                 _eye->SetSelection (0);
85                 view_options->Add (_eye, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_GAP);
86                 _jump_to_selected = new wxCheckBox (this, wxID_ANY, _("Jump to selected content"));
87                 view_options->Add (_jump_to_selected, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_GAP);
88         }
89
90         _v_sizer->Add (view_options, 0, wxALL, DCPOMATIC_SIZER_GAP);
91
92         wxBoxSizer* left_sizer = new wxBoxSizer (wxVERTICAL);
93
94         _spl_view = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_NO_HEADER);
95         _spl_view->AppendColumn (wxT(""), wxLIST_FORMAT_LEFT, 740);
96         left_sizer->Add (_spl_view, 1, wxALL | wxEXPAND, DCPOMATIC_SIZER_GAP);
97
98         _content_view = new ContentView (this, _film);
99         left_sizer->Add (_content_view, 1, wxALL | wxEXPAND, DCPOMATIC_SIZER_GAP);
100
101         wxBoxSizer* e_sizer = new wxBoxSizer (wxHORIZONTAL);
102         e_sizer->Add (left_sizer, 1, wxALL | wxEXPAND, DCPOMATIC_SIZER_GAP);
103
104         _current_spl_view = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_NO_HEADER);
105         _current_spl_view->AppendColumn (wxT(""), wxLIST_FORMAT_LEFT, 80);
106         _current_spl_view->AppendColumn (wxT(""), wxLIST_FORMAT_LEFT, 80);
107         _current_spl_view->AppendColumn (wxT(""), wxLIST_FORMAT_LEFT, 580);
108         e_sizer->Add (_current_spl_view, 1, wxALL | wxEXPAND, DCPOMATIC_SIZER_GAP);
109
110         wxBoxSizer* buttons_sizer = new wxBoxSizer (wxVERTICAL);
111         _add_button = new wxButton(this, wxID_ANY, _("Add"));
112         buttons_sizer->Add (_add_button);
113         _save_button = new wxButton(this, wxID_ANY, _("Save..."));
114         buttons_sizer->Add (_save_button);
115         _load_button = new wxButton(this, wxID_ANY, _("Load..."));
116         buttons_sizer->Add (_load_button);
117         e_sizer->Add (buttons_sizer, 0, wxALL | wxEXPAND, DCPOMATIC_SIZER_GAP);
118
119         _v_sizer->Add (e_sizer, 1, wxEXPAND);
120
121         _log = new wxTextCtrl (this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(-1, 200), wxTE_READONLY | wxTE_MULTILINE);
122         _v_sizer->Add (_log, 0, wxALL | wxEXPAND, DCPOMATIC_SIZER_GAP);
123
124         _content_view->Show (false);
125         _spl_view->Show (false);
126         _current_spl_view->Show (false);
127         _add_button->Show (false);
128         _save_button->Show (false);
129         _load_button->Show (false);
130         _log->Show (false);
131
132         wxBoxSizer* h_sizer = new wxBoxSizer (wxHORIZONTAL);
133
134         wxBoxSizer* time_sizer = new wxBoxSizer (wxVERTICAL);
135         time_sizer->Add (_frame_number, 0, wxEXPAND);
136         time_sizer->Add (_timecode, 0, wxEXPAND);
137
138         h_sizer->Add (_rewind_button, 0, wxALL, 2);
139         h_sizer->Add (_back_button, 0, wxALL, 2);
140         h_sizer->Add (time_sizer, 0, wxEXPAND);
141         h_sizer->Add (_forward_button, 0, wxALL, 2);
142         h_sizer->Add (_play_button, 0, wxEXPAND);
143 #ifdef DCPOMATIC_VARIANT_SWAROOP
144         h_sizer->Add (_pause_button, 0, wxEXPAND);
145         h_sizer->Add (_stop_button, 0, wxEXPAND);
146 #endif
147         h_sizer->Add (_slider, 1, wxEXPAND);
148
149         _v_sizer->Add (h_sizer, 0, wxEXPAND | wxALL, 6);
150
151         _frame_number->SetMinSize (wxSize (84, -1));
152         _rewind_button->SetMinSize (wxSize (32, -1));
153         _back_button->SetMinSize (wxSize (32, -1));
154         _forward_button->SetMinSize (wxSize (32, -1));
155
156         if (_eye) {
157                 _eye->Bind (wxEVT_CHOICE, boost::bind (&Controls::eye_changed, this));
158         }
159         if (_outline_content) {
160                 _outline_content->Bind (wxEVT_CHECKBOX, boost::bind (&Controls::outline_content_changed, this));
161         }
162
163         _slider->Bind           (wxEVT_SCROLL_THUMBTRACK,    boost::bind(&Controls::slider_moved,    this, false));
164         _slider->Bind           (wxEVT_SCROLL_PAGEUP,        boost::bind(&Controls::slider_moved,    this, true));
165         _slider->Bind           (wxEVT_SCROLL_PAGEDOWN,      boost::bind(&Controls::slider_moved,    this, true));
166         _slider->Bind           (wxEVT_SCROLL_CHANGED,       boost::bind(&Controls::slider_released, this));
167 #ifdef DCPOMATIC_VARIANT_SWAROOP
168         _play_button->Bind      (wxEVT_BUTTON,               boost::bind(&Controls::play_clicked,    this));
169         _pause_button->Bind     (wxEVT_BUTTON,               boost::bind(&Controls::pause_clicked,   this));
170         _stop_button->Bind      (wxEVT_BUTTON,               boost::bind(&Controls::stop_clicked,    this));
171 #else
172         _play_button->Bind      (wxEVT_TOGGLEBUTTON,         boost::bind(&Controls::play_clicked,    this));
173 #endif
174         _rewind_button->Bind    (wxEVT_LEFT_DOWN,            boost::bind(&Controls::rewind_clicked,  this, _1));
175         _back_button->Bind      (wxEVT_LEFT_DOWN,            boost::bind(&Controls::back_clicked,    this, _1));
176         _forward_button->Bind   (wxEVT_LEFT_DOWN,            boost::bind(&Controls::forward_clicked, this, _1));
177         _frame_number->Bind     (wxEVT_LEFT_DOWN,            boost::bind(&Controls::frame_number_clicked, this));
178         _timecode->Bind         (wxEVT_LEFT_DOWN,            boost::bind(&Controls::timecode_clicked, this));
179         _content_view->Bind     (wxEVT_LIST_ITEM_SELECTED,   boost::bind(&Controls::setup_sensitivity, this));
180         _content_view->Bind     (wxEVT_LIST_ITEM_DESELECTED, boost::bind(&Controls::setup_sensitivity, this));
181         if (_jump_to_selected) {
182                 _jump_to_selected->Bind (wxEVT_CHECKBOX, boost::bind (&Controls::jump_to_selected_clicked, this));
183                 _jump_to_selected->SetValue (Config::instance()->jump_to_selected ());
184         }
185         _add_button->Bind       (wxEVT_BUTTON,              boost::bind(&Controls::add_clicked, this));
186         _save_button->Bind      (wxEVT_BUTTON,              boost::bind(&Controls::save_clicked, this));
187         _load_button->Bind      (wxEVT_BUTTON,              boost::bind(&Controls::load_clicked, this));
188
189         _viewer->PositionChanged.connect (boost::bind(&Controls::position_changed, this));
190         _viewer->Started.connect (boost::bind(&Controls::started, this));
191         _viewer->Stopped.connect (boost::bind(&Controls::stopped, this));
192         _viewer->FilmChanged.connect (boost::bind(&Controls::film_changed, this));
193         _viewer->ImageChanged.connect (boost::bind(&Controls::image_changed, this, _1));
194
195         film_changed ();
196
197         setup_sensitivity ();
198         _content_view->update ();
199         update_playlist_directory ();
200
201         JobManager::instance()->ActiveJobsChanged.connect (
202                 bind (&Controls::active_jobs_changed, this, _2)
203                 );
204
205         _config_changed_connection = Config::instance()->Changed.connect (bind(&Controls::config_changed, this, _1));
206         config_changed (Config::OTHER);
207 }
208
209 void
210 Controls::add_clicked ()
211 {
212         shared_ptr<Content> sel = _content_view->selected()->clone();
213         DCPOMATIC_ASSERT (sel);
214         _film->examine_and_add_content (sel);
215         bool const ok = display_progress (_("DCP-o-matic"), _("Loading DCP"));
216         if (!ok || !report_errors_from_last_job(this)) {
217                 return;
218         }
219         add_content_to_list (sel, _current_spl_view);
220         setup_sensitivity ();
221 }
222
223 void
224 Controls::save_clicked ()
225 {
226         wxFileDialog* d = new wxFileDialog (
227                 this, _("Select playlist file"), wxEmptyString, wxEmptyString, wxT ("XML files (*.xml)|*.xml"),
228                 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
229                 );
230
231         if (d->ShowModal() == wxID_OK) {
232                 boost::filesystem::path p(wx_to_std(d->GetPath()));
233                 _film->set_name(p.stem().string());
234                 _film->write_metadata(p);
235         }
236
237         d->Destroy ();
238 }
239
240 void
241 Controls::load_clicked ()
242 {
243         wxFileDialog* d = new wxFileDialog (
244                 this, _("Select playlist file"), wxEmptyString, wxEmptyString, wxT ("XML files (*.xml)|*.xml")
245                 );
246
247         if (d->ShowModal() == wxID_OK) {
248                 _film->read_metadata (boost::filesystem::path(wx_to_std(d->GetPath())));
249                 _current_spl_view->DeleteAllItems ();
250                 BOOST_FOREACH (shared_ptr<Content> i, _film->content()) {
251                         shared_ptr<DCPContent> dcp = dynamic_pointer_cast<DCPContent>(i);
252                         add_content_to_list (dcp, _current_spl_view);
253                 }
254         }
255
256         d->Destroy ();
257 }
258
259 void
260 Controls::config_changed (int property)
261 {
262         if (property == Config::PLAYER_CONTENT_DIRECTORY) {
263                 _content_view->update ();
264         } else if (property == Config::PLAYER_PLAYLIST_DIRECTORY) {
265                 update_playlist_directory ();
266         } else {
267                 setup_sensitivity ();
268         }
269 }
270
271 void
272 Controls::started ()
273 {
274 #ifdef DCPOMATIC_VARIANT_SWAROOP
275         _play_button->Enable (false);
276         _pause_button->Enable (true);
277 #else
278         _play_button->SetValue (true);
279 #endif
280         setup_sensitivity ();
281 }
282
283 void
284 Controls::stopped ()
285 {
286 #ifdef DCPOMATIC_VARIANT_SWAROOP
287         _play_button->Enable (true);
288         _pause_button->Enable (false);
289 #else
290         _play_button->SetValue (false);
291 #endif
292         setup_sensitivity ();
293 }
294
295 void
296 Controls::position_changed ()
297 {
298         if (!_slider_being_moved) {
299                 update_position_label ();
300                 update_position_slider ();
301         }
302 }
303
304 void
305 Controls::eye_changed ()
306 {
307         _viewer->set_eyes (_eye->GetSelection() == 0 ? EYES_LEFT : EYES_RIGHT);
308 }
309
310 void
311 Controls::outline_content_changed ()
312 {
313         _viewer->set_outline_content (_outline_content->GetValue());
314 }
315
316 void
317 Controls::film_change (ChangeType type, Film::Property p)
318 {
319         if (type != CHANGE_TYPE_DONE) {
320                 return;
321         }
322
323         if (p == Film::CONTENT || p == Film::THREE_D) {
324                 setup_sensitivity ();
325         }
326 }
327
328 /** @param page true if this was a PAGEUP/PAGEDOWN event for which we won't receive a THUMBRELEASE */
329 void
330 Controls::slider_moved (bool page)
331 {
332         if (!_film) {
333                 return;
334         }
335
336         if (!page && !_slider_being_moved) {
337                 /* This is the first event of a drag; stop playback for the duration of the drag */
338                 _was_running_before_slider = _viewer->stop ();
339                 _slider_being_moved = true;
340         }
341
342         DCPTime t (_slider->GetValue() * _film->length().get() / 4096);
343         t = t.round (_film->video_frame_rate());
344         /* Ensure that we hit the end of the film at the end of the slider */
345         if (t >= _film->length ()) {
346                 t = _film->length() - _viewer->one_video_frame();
347         }
348         _viewer->seek (t, false);
349         update_position_label ();
350 }
351
352 void
353 Controls::slider_released ()
354 {
355         if (_was_running_before_slider) {
356                 /* Restart after a drag */
357                 _viewer->start ();
358         }
359         _slider_being_moved = false;
360 }
361
362 void
363 Controls::play_clicked ()
364 {
365 #ifdef DCPOMATIC_VARIANT_SWAROOP
366         _viewer->start ();
367 #else
368         check_play_state ();
369 #endif
370 }
371
372
373 #ifndef DCPOMATIC_VARIANT_SWAROOP
374 void
375 Controls::check_play_state ()
376 {
377         if (!_film || _film->video_frame_rate() == 0) {
378                 return;
379         }
380
381         if (_play_button->GetValue()) {
382                 _viewer->start ();
383         } else {
384                 _viewer->stop ();
385         }
386 }
387 #endif
388
389 void
390 Controls::update_position_slider ()
391 {
392         if (!_film) {
393                 _slider->SetValue (0);
394                 return;
395         }
396
397         DCPTime const len = _film->length ();
398
399         if (len.get ()) {
400                 int const new_slider_position = 4096 * _viewer->position().get() / len.get();
401                 if (new_slider_position != _slider->GetValue()) {
402                         _slider->SetValue (new_slider_position);
403                 }
404         }
405 }
406
407 void
408 Controls::update_position_label ()
409 {
410         if (!_film) {
411                 _frame_number->SetLabel ("0");
412                 _timecode->SetLabel ("0:0:0.0");
413                 return;
414         }
415
416         double const fps = _film->video_frame_rate ();
417         /* Count frame number from 1 ... not sure if this is the best idea */
418         _frame_number->SetLabel (wxString::Format (wxT("%ld"), lrint (_viewer->position().seconds() * fps) + 1));
419         _timecode->SetLabel (time_to_timecode (_viewer->position(), fps));
420 }
421
422 void
423 Controls::active_jobs_changed (optional<string> j)
424 {
425         _active_job = j;
426         setup_sensitivity ();
427 }
428
429 DCPTime
430 Controls::nudge_amount (wxKeyboardState& ev)
431 {
432         DCPTime amount = _viewer->one_video_frame ();
433
434         if (ev.ShiftDown() && !ev.ControlDown()) {
435                 amount = DCPTime::from_seconds (1);
436         } else if (!ev.ShiftDown() && ev.ControlDown()) {
437                 amount = DCPTime::from_seconds (10);
438         } else if (ev.ShiftDown() && ev.ControlDown()) {
439                 amount = DCPTime::from_seconds (60);
440         }
441
442         return amount;
443 }
444
445 void
446 Controls::rewind_clicked (wxMouseEvent& ev)
447 {
448         _viewer->seek (DCPTime(), true);
449         ev.Skip();
450 }
451
452 void
453 Controls::back_frame ()
454 {
455         _viewer->seek_by (-_viewer->one_video_frame(), true);
456 }
457
458 void
459 Controls::forward_frame ()
460 {
461         _viewer->seek_by (_viewer->one_video_frame(), true);
462 }
463
464 void
465 Controls::back_clicked (wxKeyboardState& ev)
466 {
467         _viewer->seek_by (-nudge_amount(ev), true);
468 }
469
470 void
471 Controls::forward_clicked (wxKeyboardState& ev)
472 {
473         _viewer->seek_by (nudge_amount(ev), true);
474 }
475
476 void
477 Controls::setup_sensitivity ()
478 {
479         /* examine content is the only job which stops the viewer working */
480         bool const active_job = _active_job && *_active_job != "examine_content";
481         bool const c = _film && !_film->content().empty() && !active_job;
482
483         _slider->Enable (c);
484         _rewind_button->Enable (c);
485         _back_button->Enable (c);
486         _forward_button->Enable (c);
487 #ifdef DCPOMATIC_VARIANT_SWAROOP
488         _play_button->Enable (c && !_viewer->playing());
489         _pause_button->Enable (c && (!_current_kind || _current_kind != dcp::ADVERTISEMENT) && _viewer->playing());
490         _stop_button->Enable (c && (!_current_kind || _current_kind != dcp::ADVERTISEMENT));
491         _slider->Enable (c && (!_current_kind || _current_kind != dcp::ADVERTISEMENT));
492 #else
493         _play_button->Enable (c);
494 #endif
495         if (_outline_content) {
496                 _outline_content->Enable (c);
497         }
498         _frame_number->Enable (c);
499         _timecode->Enable (c);
500         if (_jump_to_selected) {
501                 _jump_to_selected->Enable (c);
502         }
503
504         if (_eye) {
505                 _eye->Enable (c && _film->three_d ());
506         }
507
508         _add_button->Enable (Config::instance()->allow_spl_editing() && static_cast<bool>(_content_view->selected()));
509         _save_button->Enable (Config::instance()->allow_spl_editing());
510 }
511
512 void
513 Controls::timecode_clicked ()
514 {
515         PlayheadToTimecodeDialog* dialog = new PlayheadToTimecodeDialog (this, _film->video_frame_rate ());
516         if (dialog->ShowModal() == wxID_OK) {
517                 _viewer->seek (dialog->get(), true);
518         }
519         dialog->Destroy ();
520 }
521
522 void
523 Controls::frame_number_clicked ()
524 {
525         PlayheadToFrameDialog* dialog = new PlayheadToFrameDialog (this, _film->video_frame_rate ());
526         if (dialog->ShowModal() == wxID_OK) {
527                 _viewer->seek (dialog->get(), true);
528         }
529         dialog->Destroy ();
530 }
531
532 void
533 Controls::jump_to_selected_clicked ()
534 {
535         Config::instance()->set_jump_to_selected (_jump_to_selected->GetValue ());
536 }
537
538 void
539 Controls::film_changed ()
540 {
541         shared_ptr<Film> film = _viewer->film ();
542
543         if (_film == film) {
544                 return;
545         }
546
547         _film = film;
548
549         setup_sensitivity ();
550
551         update_position_slider ();
552         update_position_label ();
553
554         if (_film) {
555                 _film->Change.connect (boost::bind (&Controls::film_change, this, _1, _2));
556         }
557 }
558
559 shared_ptr<Film>
560 Controls::film () const
561 {
562         return _film;
563 }
564
565 void
566 Controls::show_extended_player_controls (bool s)
567 {
568         _content_view->Show (s);
569         _spl_view->Show (s);
570         if (s) {
571                 _content_view->update ();
572                 update_playlist_directory ();
573         }
574         _current_spl_view->Show (s);
575         _log->Show (s);
576         _add_button->Show (s);
577         _save_button->Show (s);
578         _load_button->Show (s);
579         _v_sizer->Layout ();
580 }
581
582 void
583 Controls::add_content_to_list (shared_ptr<Content> content, wxListCtrl* ctrl)
584 {
585         int const N = ctrl->GetItemCount();
586
587         wxListItem it;
588         it.SetId(N);
589         it.SetColumn(0);
590         DCPTime length = content->length_after_trim (_film);
591         int h, m, s, f;
592         length.split (24, h, m, s, f);
593         it.SetText(wxString::Format("%02d:%02d:%02d", h, m, s));
594         ctrl->InsertItem(it);
595
596         shared_ptr<DCPContent> dcp = dynamic_pointer_cast<DCPContent>(content);
597         if (dcp && dcp->content_kind()) {
598                 it.SetId(N);
599                 it.SetColumn(1);
600                 it.SetText(std_to_wx(dcp::content_kind_to_string(*dcp->content_kind())));
601                 ctrl->SetItem(it);
602         }
603
604         it.SetId(N);
605         it.SetColumn(2);
606         it.SetText(std_to_wx(content->summary()));
607         ctrl->SetItem(it);
608 }
609
610 void
611 Controls::add_playlist_to_list (shared_ptr<Film> film)
612 {
613         int const N = _spl_view->GetItemCount();
614
615         wxListItem it;
616         it.SetId(N);
617         it.SetColumn(0);
618         it.SetText (std_to_wx(film->name()));
619         _spl_view->InsertItem (it);
620 }
621
622 void
623 Controls::update_playlist_directory ()
624 {
625         if (!_spl_view->IsShown()) {
626                 return;
627         }
628
629         using namespace boost::filesystem;
630
631         _spl_view->DeleteAllItems ();
632         optional<path> dir = Config::instance()->player_playlist_directory();
633         if (!dir) {
634                 return;
635         }
636
637         for (directory_iterator i = directory_iterator(*dir); i != directory_iterator(); ++i) {
638                 try {
639                         shared_ptr<Film> film (new Film(optional<path>()));
640                         film->read_metadata (i->path());
641                         _playlists.push_back (film);
642                         add_playlist_to_list (film);
643                 } catch (exception& e) {
644                         /* Never mind */
645                 }
646         }
647 }
648
649 #ifdef DCPOMATIC_VARIANT_SWAROOP
650 void
651 Controls::pause_clicked ()
652 {
653         _viewer->stop ();
654 }
655
656 void
657 Controls::stop_clicked ()
658 {
659         _viewer->stop ();
660         _viewer->seek (DCPTime(), true);
661 }
662 #endif
663
664 void
665 Controls::log (wxString s)
666 {
667         struct timeval time;
668         gettimeofday (&time, 0);
669         char buffer[64];
670         time_t const sec = time.tv_sec;
671         struct tm* t = localtime (&sec);
672         strftime (buffer, 64, "%c", t);
673         wxString ts = std_to_wx(string(buffer)) + N_(": ");
674         _log->SetValue(_log->GetValue() + ts + s + "\n");
675 }
676
677 void
678 Controls::image_changed (boost::weak_ptr<PlayerVideo> weak_pv)
679 {
680 #ifdef DCPOMATIC_VARIANT_SWAROOP
681         shared_ptr<PlayerVideo> pv = weak_pv.lock ();
682         if (!pv) {
683                 return;
684         }
685
686         shared_ptr<Content> c = pv->content().lock();
687         if (!c) {
688                 return;
689         }
690
691         shared_ptr<DCPContent> dc = dynamic_pointer_cast<DCPContent> (c);
692         if (!dc) {
693                 return;
694         }
695
696         if (!_current_kind || *_current_kind != dc->content_kind()) {
697                 _current_kind = dc->content_kind ();
698                 setup_sensitivity ();
699         }
700 #endif
701 }