From: Carl Hetherington Date: Sun, 31 Aug 2014 16:31:38 +0000 (+0100) Subject: Merge master. X-Git-Tag: v2.0.48~631 X-Git-Url: https://git.carlh.net/gitweb/?p=dcpomatic.git;a=commitdiff_plain;h=22b9f3b2090d8bdfe52cda1e69d3acbe874f1ce5 Merge master. --- 22b9f3b2090d8bdfe52cda1e69d3acbe874f1ce5 diff --cc ChangeLog index b584a6c7c,e66822597..36a282919 --- a/ChangeLog +++ b/ChangeLog @@@ -1,32 -1,14 +1,41 @@@ + 2014-08-31 Carl Hetherington + + * Give a hint when content and container aspect ratios are not + the same (#392). + + * Add "copy" button to colour conversion presets editor (#399). + + * Allow drag-and-drop of files onto the content list (#395). + 2014-08-29 Carl Hetherington + * Version 2.0.4 released. + +2014-08-24 Carl Hetherington + + * Version 2.0.3 released. + +2014-08-24 Carl Hetherington + + * Version 2.0.2 released. + +2014-08-06 Carl Hetherington + + * Version 2.0.1 released. + +2014-07-15 Carl Hetherington + + * A variety of changes were made on the 2.0 branch + but not documented in the ChangeLog. Most sigificantly: + + - DCP import + - Creation of DCPs with proper XML subtitles + - Import of .srt and .xml subtitles + - Audio processing framework (with some basic processors). + +2014-03-07 Carl Hetherington + + * Add subtitle view. * Some improvements to the manual. 2014-08-26 Carl Hetherington diff --cc src/wx/content_panel.cc index b752a0e5f,000000000..991080e59 mode 100644,000000..100644 --- a/src/wx/content_panel.cc +++ b/src/wx/content_panel.cc @@@ -1,458 -1,0 +1,471 @@@ +/* + Copyright (C) 2012-2014 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include "lib/audio_content.h" +#include "lib/subtitle_content.h" +#include "lib/video_content.h" +#include "lib/ffmpeg_content.h" +#include "lib/content_factory.h" +#include "lib/image_content.h" +#include "lib/dcp_content.h" +#include "lib/playlist.h" +#include "content_panel.h" +#include "wx_util.h" +#include "video_panel.h" +#include "audio_panel.h" +#include "subtitle_panel.h" +#include "timing_panel.h" +#include "timeline_dialog.h" + +using std::list; +using std::string; +using std::cout; +using boost::shared_ptr; +using boost::weak_ptr; +using boost::dynamic_pointer_cast; + +ContentPanel::ContentPanel (wxNotebook* n, boost::shared_ptr f) + : _timeline_dialog (0) + , _film (f) + , _generally_sensitive (true) +{ + _panel = new wxPanel (n); + _sizer = new wxBoxSizer (wxVERTICAL); + _panel->SetSizer (_sizer); + + _menu = new ContentMenu (_panel); + + { + wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); + + _content = new wxListCtrl (_panel, wxID_ANY, wxDefaultPosition, wxSize (320, 160), wxLC_REPORT | wxLC_NO_HEADER); + s->Add (_content, 1, wxEXPAND | wxTOP | wxBOTTOM, 6); + + _content->InsertColumn (0, wxT("")); + _content->SetColumnWidth (0, 512); + + wxBoxSizer* b = new wxBoxSizer (wxVERTICAL); + _add_file = new wxButton (_panel, wxID_ANY, _("Add file(s)...")); + b->Add (_add_file, 1, wxEXPAND | wxALL, DCPOMATIC_BUTTON_STACK_GAP); + _add_folder = new wxButton (_panel, wxID_ANY, _("Add folder...")); + b->Add (_add_folder, 1, wxEXPAND | wxALL, DCPOMATIC_BUTTON_STACK_GAP); + _remove = new wxButton (_panel, wxID_ANY, _("Remove")); + b->Add (_remove, 1, wxEXPAND | wxALL, DCPOMATIC_BUTTON_STACK_GAP); + _earlier = new wxButton (_panel, wxID_ANY, _("Up")); + b->Add (_earlier, 1, wxEXPAND | wxALL, DCPOMATIC_BUTTON_STACK_GAP); + _later = new wxButton (_panel, wxID_ANY, _("Down")); + b->Add (_later, 1, wxEXPAND | wxALL, DCPOMATIC_BUTTON_STACK_GAP); + _timeline = new wxButton (_panel, wxID_ANY, _("Timeline...")); + b->Add (_timeline, 1, wxEXPAND | wxALL, DCPOMATIC_BUTTON_STACK_GAP); + + s->Add (b, 0, wxALL, 4); + + _sizer->Add (s, 0, wxEXPAND | wxALL, 6); + } + + _sequence_video = new wxCheckBox (_panel, wxID_ANY, _("Keep video in sequence")); + _sizer->Add (_sequence_video); + + _notebook = new wxNotebook (_panel, wxID_ANY); + _sizer->Add (_notebook, 1, wxEXPAND | wxTOP, 6); + + _video_panel = new VideoPanel (this); + _panels.push_back (_video_panel); + _audio_panel = new AudioPanel (this); + _panels.push_back (_audio_panel); + _subtitle_panel = new SubtitlePanel (this); + _panels.push_back (_subtitle_panel); + _timing_panel = new TimingPanel (this); + _panels.push_back (_timing_panel); + + _content->Bind (wxEVT_COMMAND_LIST_ITEM_SELECTED, boost::bind (&ContentPanel::selection_changed, this)); + _content->Bind (wxEVT_COMMAND_LIST_ITEM_DESELECTED, boost::bind (&ContentPanel::selection_changed, this)); + _content->Bind (wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, boost::bind (&ContentPanel::right_click, this, _1)); ++ _content->Bind (wxEVT_DROP_FILES, boost::bind (&ContentPanel::files_dropped, this, _1)); + _add_file->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&ContentPanel::add_file_clicked, this)); + _add_folder->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&ContentPanel::add_folder_clicked, this)); + _remove->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&ContentPanel::remove_clicked, this)); + _earlier->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&ContentPanel::earlier_clicked, this)); + _later->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&ContentPanel::later_clicked, this)); + _timeline->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&ContentPanel::timeline_clicked, this)); + _sequence_video->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&ContentPanel::sequence_video_changed, this)); +} + +ContentList +ContentPanel::selected () +{ + ContentList sel; + long int s = -1; + while (true) { + s = _content->GetNextItem (s, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (s == -1) { + break; + } + + if (s < int (_film->content().size ())) { + sel.push_back (_film->content()[s]); + } + } + + return sel; +} + +VideoContentList +ContentPanel::selected_video () +{ + ContentList c = selected (); + VideoContentList vc; + + for (ContentList::iterator i = c.begin(); i != c.end(); ++i) { + shared_ptr t = dynamic_pointer_cast (*i); + if (t) { + vc.push_back (t); + } + } + + return vc; +} + +AudioContentList +ContentPanel::selected_audio () +{ + ContentList c = selected (); + AudioContentList ac; + + for (ContentList::iterator i = c.begin(); i != c.end(); ++i) { + shared_ptr t = dynamic_pointer_cast (*i); + if (t) { + ac.push_back (t); + } + } + + return ac; +} + +SubtitleContentList +ContentPanel::selected_subtitle () +{ + ContentList c = selected (); + SubtitleContentList sc; + + for (ContentList::iterator i = c.begin(); i != c.end(); ++i) { + shared_ptr t = dynamic_pointer_cast (*i); + if (t) { + sc.push_back (t); + } + } + + return sc; +} + +FFmpegContentList +ContentPanel::selected_ffmpeg () +{ + ContentList c = selected (); + FFmpegContentList sc; + + for (ContentList::iterator i = c.begin(); i != c.end(); ++i) { + shared_ptr t = dynamic_pointer_cast (*i); + if (t) { + sc.push_back (t); + } + } + + return sc; +} + +void +ContentPanel::sequence_video_changed () +{ + if (!_film) { + return; + } + + _film->set_sequence_video (_sequence_video->GetValue ()); +} + +void +ContentPanel::film_changed (Film::Property p) +{ + switch (p) { + case Film::CONTENT: + setup (); + break; + case Film::SEQUENCE_VIDEO: + checked_set (_sequence_video, _film->sequence_video ()); + break; + default: + break; + } + + for (list::iterator i = _panels.begin(); i != _panels.end(); ++i) { + (*i)->film_changed (p); + } +} + +void +ContentPanel::selection_changed () +{ + setup_sensitivity (); + + for (list::iterator i = _panels.begin(); i != _panels.end(); ++i) { + (*i)->content_selection_changed (); + } +} + +void +ContentPanel::add_file_clicked () +{ + /* The wxFD_CHANGE_DIR here prevents a `could not set working directory' error 123 on Windows when using + non-Latin filenames or paths. + */ + wxFileDialog* d = new wxFileDialog (_panel, _("Choose a file or files"), wxT (""), wxT (""), wxT ("*.*"), wxFD_MULTIPLE | wxFD_CHANGE_DIR); + int const r = d->ShowModal (); + + if (r != wxID_OK) { + d->Destroy (); + return; + } + + wxArrayString paths; + d->GetPaths (paths); + + /* XXX: check for lots of files here and do something */ + + for (unsigned int i = 0; i < paths.GetCount(); ++i) { + _film->examine_and_add_content (content_factory (_film, wx_to_std (paths[i]))); + } + + d->Destroy (); +} + +void +ContentPanel::add_folder_clicked () +{ + wxDirDialog* d = new wxDirDialog (_panel, _("Choose a folder"), wxT (""), wxDD_DIR_MUST_EXIST); + int const r = d->ShowModal (); + d->Destroy (); + + if (r != wxID_OK) { + return; + } + + shared_ptr content; + + try { + content.reset (new ImageContent (_film, boost::filesystem::path (wx_to_std (d->GetPath ())))); + } catch (...) { + try { + content.reset (new DCPContent (_film, boost::filesystem::path (wx_to_std (d->GetPath ())))); + } catch (...) { + error_dialog (_panel, _("Could not find any images nor a DCP in that folder")); + return; + } + } + + if (content) { + _film->examine_and_add_content (content); + } +} + +void +ContentPanel::remove_clicked () +{ + ContentList c = selected (); + if (c.size() == 1) { + _film->remove_content (c.front ()); + } + + selection_changed (); +} + +void +ContentPanel::timeline_clicked () +{ + if (_timeline_dialog) { + _timeline_dialog->Destroy (); + _timeline_dialog = 0; + } + + _timeline_dialog = new TimelineDialog (this, _film); + _timeline_dialog->Show (); +} + +void +ContentPanel::right_click (wxListEvent& ev) +{ + _menu->popup (_film, selected (), ev.GetPoint ()); +} + +/** Set up broad sensitivity based on the type of content that is selected */ +void +ContentPanel::setup_sensitivity () +{ + _add_file->Enable (_generally_sensitive); + _add_folder->Enable (_generally_sensitive); + + ContentList selection = selected (); + VideoContentList video_selection = selected_video (); + AudioContentList audio_selection = selected_audio (); + + _remove->Enable (selection.size() == 1 && _generally_sensitive); + _earlier->Enable (selection.size() == 1 && _generally_sensitive); + _later->Enable (selection.size() == 1 && _generally_sensitive); + _timeline->Enable (!_film->content().empty() && _generally_sensitive); + + _video_panel->Enable (video_selection.size() > 0 && _generally_sensitive); + _audio_panel->Enable (audio_selection.size() > 0 && _generally_sensitive); + _subtitle_panel->Enable (selection.size() == 1 && dynamic_pointer_cast (selection.front()) && _generally_sensitive); + _timing_panel->Enable (selection.size() == 1 && _generally_sensitive); +} + +void +ContentPanel::set_film (shared_ptr f) +{ + _film = f; + selection_changed (); +} + +void +ContentPanel::set_general_sensitivity (bool s) +{ + _generally_sensitive = s; + + _content->Enable (s); + _add_file->Enable (s); + _add_folder->Enable (s); + _remove->Enable (s); + _earlier->Enable (s); + _later->Enable (s); + _timeline->Enable (s); + _sequence_video->Enable (s); + + /* Set the panels in the content notebook */ + for (list::iterator i = _panels.begin(); i != _panels.end(); ++i) { + (*i)->Enable (s); + } +} + +void +ContentPanel::earlier_clicked () +{ + ContentList sel = selected (); + if (sel.size() == 1) { + _film->move_content_earlier (sel.front ()); + selection_changed (); + } +} + +void +ContentPanel::later_clicked () +{ + ContentList sel = selected (); + if (sel.size() == 1) { + _film->move_content_later (sel.front ()); + selection_changed (); + } +} + +void +ContentPanel::set_selection (weak_ptr wc) +{ + ContentList content = _film->content (); + for (size_t i = 0; i < content.size(); ++i) { + if (content[i] == wc.lock ()) { + _content->SetItemState (i, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); + } else { + _content->SetItemState (i, 0, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED); + } + } +} + +void +ContentPanel::film_content_changed (int property) +{ + if (property == ContentProperty::PATH || property == ContentProperty::POSITION || property == DCPContentProperty::CAN_BE_PLAYED) { + setup (); + } + + for (list::iterator i = _panels.begin(); i != _panels.end(); ++i) { + (*i)->film_content_changed (property); + } +} + +void +ContentPanel::setup () +{ + string selected_summary; + int const s = _content->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (s != -1) { + selected_summary = wx_to_std (_content->GetItemText (s)); + } + + _content->DeleteAllItems (); + + ContentList content = _film->content (); + sort (content.begin(), content.end(), ContentSorter ()); + + for (ContentList::iterator i = content.begin(); i != content.end(); ++i) { + int const t = _content->GetItemCount (); + bool const valid = (*i)->paths_valid (); + shared_ptr dcp = dynamic_pointer_cast (*i); + bool const needs_kdm = dcp && !dcp->can_be_played (); + + string s = (*i)->summary (); + + if (!valid) { + s = _("MISSING: ") + s; + } + + if (needs_kdm) { + s = _("NEEDS KDM: ") + s; + } + + _content->InsertItem (t, std_to_wx (s)); + + if ((*i)->summary() == selected_summary) { + _content->SetItemState (t, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); + } + + if (!valid || needs_kdm) { + _content->SetItemTextColour (t, *wxRED); + } + } + + if (selected_summary.empty () && !content.empty ()) { + /* Select the item of content if none was selected before */ + _content->SetItemState (0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); + } +} + ++void ++ContentPanel::files_dropped (wxDropFilesEvent& event) ++{ ++ if (!_film) { ++ return; ++ } ++ ++ wxString* paths = event.GetFiles (); ++ for (int i = 0; i < event.GetNumberOfFiles(); i++) { ++ _film->examine_and_add_content (content_factory (_film, wx_to_std (paths[i]))); ++ } ++} diff --cc src/wx/content_panel.h index 5701696e5,000000000..1f64d51c6 mode 100644,000000..100644 --- a/src/wx/content_panel.h +++ b/src/wx/content_panel.h @@@ -1,101 -1,0 +1,102 @@@ +/* + Copyright (C) 2012-2014 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include "lib/types.h" +#include "lib/film.h" +#include "content_menu.h" + +class wxNotebook; +class wxPanel; +class wxSizer; +class wxListCtrl; +class wxListEvent; +class TimelineDialog; +class FilmEditor; +class ContentSubPanel; +class Film; + +class ContentPanel +{ +public: + ContentPanel (wxNotebook *, boost::shared_ptr); + + boost::shared_ptr film () const { + return _film; + } + + void set_film (boost::shared_ptr f); + void set_general_sensitivity (bool s); + void set_selection (boost::weak_ptr); + + void film_changed (Film::Property p); + void film_content_changed (int p); + + wxPanel* panel () const { + return _panel; + } + + wxNotebook* notebook () const { + return _notebook; + } + + ContentList selected (); + VideoContentList selected_video (); + AudioContentList selected_audio (); + SubtitleContentList selected_subtitle (); + FFmpegContentList selected_ffmpeg (); + +private: + void sequence_video_changed (); + void selection_changed (); + void add_file_clicked (); + void add_folder_clicked (); + void remove_clicked (); + void earlier_clicked (); + void later_clicked (); + void right_click (wxListEvent &); ++ void files_dropped (wxDropFilesEvent &); + void timeline_clicked (); + + void setup (); + void setup_sensitivity (); + + wxPanel* _panel; + wxSizer* _sizer; + wxNotebook* _notebook; + wxListCtrl* _content; + wxButton* _add_file; + wxButton* _add_folder; + wxButton* _remove; + wxButton* _earlier; + wxButton* _later; + wxButton* _timeline; + wxCheckBox* _sequence_video; + ContentSubPanel* _video_panel; + ContentSubPanel* _audio_panel; + ContentSubPanel* _subtitle_panel; + ContentSubPanel* _timing_panel; + std::list _panels; + ContentMenu* _menu; + TimelineDialog* _timeline_dialog; + + boost::shared_ptr _film; + bool _generally_sensitive; +};