diff options
| author | Carl Hetherington <cth@carlh.net> | 2013-09-17 23:39:05 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2013-09-17 23:39:05 +0100 |
| commit | 373f010a7f04add1f49169cbaa60cb7ae5f508d4 (patch) | |
| tree | a61fe014cbefc775dcf3a5c9a45d06e391e65b31 /src/wx | |
| parent | 048f9b6b5569f03d1342a04f75c83a2bad340996 (diff) | |
| parent | e888e92f354b9868337b0b022ff9be38b9c36c0f (diff) | |
Merge 1.0 in.
Diffstat (limited to 'src/wx')
74 files changed, 8727 insertions, 1832 deletions
diff --git a/src/wx/about_dialog.cc b/src/wx/about_dialog.cc new file mode 100644 index 000000000..45f2f6c37 --- /dev/null +++ b/src/wx/about_dialog.cc @@ -0,0 +1,159 @@ +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + + 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 <wx/notebook.h> +#include <wx/hyperlink.h> +#include "lib/version.h" +#include "lib/compose.hpp" +#include "about_dialog.h" +#include "wx_util.h" + +using std::vector; + +AboutDialog::AboutDialog (wxWindow* parent) + : wxDialog (parent, wxID_ANY, _("About DCP-o-matic")) +{ + wxBoxSizer* sizer = new wxBoxSizer (wxVERTICAL); + + wxFont title_font (*wxNORMAL_FONT); + title_font.SetPointSize (title_font.GetPointSize() + 12); + title_font.SetWeight (wxFONTWEIGHT_BOLD); + + wxFont subtitle_font (*wxNORMAL_FONT); + subtitle_font.SetPointSize (subtitle_font.GetPointSize() + 2); + + wxFont version_font (*wxNORMAL_FONT); + version_font.SetWeight (wxFONTWEIGHT_BOLD); + + wxStaticText* t = new wxStaticText (this, wxID_ANY, _("DCP-o-matic")); + t->SetFont (title_font); + sizer->Add (t, wxSizerFlags().Centre().Border(wxALL, 16)); + + wxString s; + if (strcmp (dcpomatic_git_commit, "release") == 0) { + t = new wxStaticText (this, wxID_ANY, std_to_wx (String::compose ("Version %1", dcpomatic_version))); + } else { + t = new wxStaticText (this, wxID_ANY, std_to_wx (String::compose ("Version %1 git %2", dcpomatic_version, dcpomatic_git_commit))); + } + t->SetFont (version_font); + sizer->Add (t, wxSizerFlags().Centre().Border(wxALL, 2)); + sizer->AddSpacer (12); + + t = new wxStaticText ( + this, wxID_ANY, + _("Free, open-source DCP generation from almost anything."), + wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER + ); + t->SetFont (subtitle_font); + + sizer->Add (t, wxSizerFlags().Centre().Border(wxALL, 8)); + + wxHyperlinkCtrl* h = new wxHyperlinkCtrl ( + this, wxID_ANY, + wxT ("dcpomatic.com"), + wxT ("http://dcpomatic.com") + ); + + sizer->Add (h, wxSizerFlags().Centre().Border(wxALL, 8)); + + t = new wxStaticText ( + this, wxID_ANY, + _("(C) 2012-2013 Carl Hetherington, Terrence Meiczinger, Paul Davis, Ole Laursen"), + wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER + ); + + sizer->Add (t, wxSizerFlags().Centre().Border(wxLEFT | wxRIGHT, 16)); + + _notebook = new wxNotebook (this, wxID_ANY); + + wxArrayString written_by; + written_by.Add (wxT ("Carl Hetherington")); + written_by.Add (wxT ("Terrence Meiczinger")); + written_by.Add (wxT ("Paul Davis")); + written_by.Add (wxT ("Ole Laursen")); + add_section (_("Written by"), written_by); + + wxArrayString translated_by; + translated_by.Add (wxT ("Olivier Perriere")); + translated_by.Add (wxT ("Lilian Lefranc")); + translated_by.Add (wxT ("Thierry Journet")); + translated_by.Add (wxT ("Massimiliano Broggi")); + translated_by.Add (wxT ("Manuel AC")); + translated_by.Add (wxT ("Adam Klotblixt")); + add_section (_("Translated by"), translated_by); + + wxArrayString supported_by; + supported_by.Add (wxT ("Carsten Kurz")); + supported_by.Add (wxT ("Wolfgang Woehl")); + supported_by.Add (wxT ("Manual AC")); + supported_by.Add (wxT ("Theo Lipfert")); + supported_by.Add (wxT ("Olivier Lemaire")); + supported_by.Add (wxT ("Mattias Mattsson")); + supported_by.Add (wxT ("Andrä Steiner")); + supported_by.Add (wxT ("Jonathan Jensen")); + supported_by.Add (wxT ("Kjarten Michaelsen")); + supported_by.Add (wxT ("Jussi Siponen")); + supported_by.Add (wxT ("Cinema Clarici")); + supported_by.Add (wxT ("Evan Freeze")); + supported_by.Add (wxT ("Flor Guillaume")); + supported_by.Add (wxT ("Adam Klotblixt ")); + supported_by.Add (wxT ("Lilian Lefranc")); + supported_by.Add (wxT ("Gavin Lewarne")); + supported_by.Add (wxT ("Lasse Salling")); + supported_by.Add (wxT ("Andres Fink")); + supported_by.Add (wxT ("Kieran Carroll")); + supported_by.Add (wxT ("Kambiz Afshar")); + supported_by.Add (wxT ("Sean Leigh")); + supported_by.Add (wxT ("Wolfram Weber")); + add_section (_("Supported by"), supported_by); + + sizer->Add (_notebook, wxSizerFlags().Centre().Border(wxALL, 16).Expand()); + + SetSizerAndFit (sizer); +} + +void +AboutDialog::add_section (wxString name, wxArrayString credits) +{ + static bool first = true; + int const N = 3; + + wxPanel* panel = new wxPanel (_notebook, wxID_ANY); + wxSizer* overall_sizer = new wxBoxSizer (wxHORIZONTAL); + + vector<wxSizer*> sizers; + + for (int i = 0; i < N; ++i) { + sizers.push_back (new wxBoxSizer (wxVERTICAL)); + overall_sizer->Add (sizers.back (), 1, wxEXPAND | wxALL, 6); + } + + int c = 0; + for (size_t i = 0; i < credits.Count(); ++i) { + add_label_to_sizer (sizers[c], panel, credits[i], false); + ++c; + if (c == N) { + c = 0; + } + } + + panel->SetSizerAndFit (overall_sizer); + _notebook->AddPage (panel, name, first); + first = false; +} diff --git a/src/wx/film_list.h b/src/wx/about_dialog.h index 5a4ac3cc1..a78abb93e 100644 --- a/src/wx/film_list.h +++ b/src/wx/about_dialog.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2012 Carl Hetherington <cth@carlh.net> + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> 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 @@ -17,25 +17,18 @@ */ -#include <string> -#include <vector> -#include <gtkmm.h> +#include <wx/wx.h> -class Film; +class wxNotebook; -class FilmList +class AboutDialog : public wxDialog { public: - FilmList (std::string); - - Gtk::Widget& widget (); - - sigc::signal<void, Film const *> SelectionChanged; + AboutDialog (wxWindow *); private: - void selection_changed (); + void add_section (wxString, wxArrayString); - std::string _directory; - std::vector<Film const *> _films; - Gtk::ListViewText _list; + wxNotebook* _notebook; }; + diff --git a/src/wx/audio_dialog.cc b/src/wx/audio_dialog.cc new file mode 100644 index 000000000..c7a0815f8 --- /dev/null +++ b/src/wx/audio_dialog.cc @@ -0,0 +1,177 @@ +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + + 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 <boost/filesystem.hpp> +#include "lib/audio_analysis.h" +#include "lib/film.h" +#include "lib/audio_content.h" +#include "audio_dialog.h" +#include "audio_plot.h" +#include "wx_util.h" + +using boost::shared_ptr; +using boost::bind; +using boost::optional; + +AudioDialog::AudioDialog (wxWindow* parent) + : wxDialog (parent, wxID_ANY, _("Audio"), wxDefaultPosition, wxSize (640, 512), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxFULL_REPAINT_ON_RESIZE) + , _plot (0) +{ + wxBoxSizer* sizer = new wxBoxSizer (wxHORIZONTAL); + + _plot = new AudioPlot (this); + sizer->Add (_plot, 1, wxALL | wxEXPAND, 12); + + wxBoxSizer* side = new wxBoxSizer (wxVERTICAL); + + { + wxStaticText* m = new wxStaticText (this, wxID_ANY, _("Channels")); + side->Add (m, 1, wxALIGN_CENTER_VERTICAL | wxTOP, 16); + } + + for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) { + _channel_checkbox[i] = new wxCheckBox (this, wxID_ANY, std_to_wx (audio_channel_name (i))); + side->Add (_channel_checkbox[i], 1, wxEXPAND | wxALL, 3); + _channel_checkbox[i]->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AudioDialog::channel_clicked, this, _1)); + } + + { + wxStaticText* m = new wxStaticText (this, wxID_ANY, _("Type")); + side->Add (m, 1, wxALIGN_CENTER_VERTICAL | wxTOP, 16); + } + + wxString const types[] = { + _("Peak"), + _("RMS") + }; + + for (int i = 0; i < AudioPoint::COUNT; ++i) { + _type_checkbox[i] = new wxCheckBox (this, wxID_ANY, types[i]); + side->Add (_type_checkbox[i], 1, wxEXPAND | wxALL, 3); + _type_checkbox[i]->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AudioDialog::type_clicked, this, _1)); + } + + { + wxStaticText* m = new wxStaticText (this, wxID_ANY, _("Smoothing")); + side->Add (m, 1, wxALIGN_CENTER_VERTICAL | wxTOP, 16); + } + + _smoothing = new wxSlider (this, wxID_ANY, AudioPlot::max_smoothing / 2, 1, AudioPlot::max_smoothing); + _smoothing->Bind (wxEVT_SCROLL_THUMBTRACK, boost::bind (&AudioDialog::smoothing_changed, this)); + side->Add (_smoothing, 1, wxEXPAND); + + sizer->Add (side, 0, wxALL, 12); + + SetSizer (sizer); + sizer->Layout (); + sizer->SetSizeHints (this); +} + +void +AudioDialog::set_content (shared_ptr<AudioContent> c) +{ + _content_changed_connection.disconnect (); + + _content = c; + + try_to_load_analysis (); + _plot->set_gain (_content->audio_gain ()); + + _content_changed_connection = _content->Changed.connect (bind (&AudioDialog::content_changed, this, _2)); + + SetTitle (wxString::Format (_("DCP-o-matic audio - %s"), std_to_wx(_content->path().filename().string()).data())); +} + +void +AudioDialog::try_to_load_analysis () +{ + if (!boost::filesystem::exists (_content->audio_analysis_path()) && IsShown ()) { + _content->analyse_audio (bind (&AudioDialog::analysis_finished, this)); + return; + } + + shared_ptr<AudioAnalysis> a; + + a.reset (new AudioAnalysis (_content->audio_analysis_path ())); + _plot->set_analysis (a); + + if (_channel_checkbox[0]) { + _channel_checkbox[0]->SetValue (true); + } + _plot->set_channel_visible (0, true); + + for (int i = 0; i < AudioPoint::COUNT; ++i) { + _type_checkbox[i]->SetValue (true); + _plot->set_type_visible (i, true); + } +} + +void +AudioDialog::analysis_finished () +{ + if (!boost::filesystem::exists (_content->audio_analysis_path())) { + /* We analysed and still nothing showed up, so maybe it was cancelled or it failed. + Give up. + */ + _plot->set_message (_("Could not analyse audio.")); + return; + } + + try_to_load_analysis (); +} + +void +AudioDialog::channel_clicked (wxCommandEvent& ev) +{ + int c = 0; + while (c < MAX_AUDIO_CHANNELS && ev.GetEventObject() != _channel_checkbox[c]) { + ++c; + } + + assert (c < MAX_AUDIO_CHANNELS); + + _plot->set_channel_visible (c, _channel_checkbox[c]->GetValue ()); +} + +void +AudioDialog::content_changed (int p) +{ + if (p == AudioContentProperty::AUDIO_GAIN) { + _plot->set_gain (_content->audio_gain ()); + } +} + +void +AudioDialog::type_clicked (wxCommandEvent& ev) +{ + int t = 0; + while (t < AudioPoint::COUNT && ev.GetEventObject() != _type_checkbox[t]) { + ++t; + } + + assert (t < AudioPoint::COUNT); + + _plot->set_type_visible (t, _type_checkbox[t]->GetValue ()); +} + +void +AudioDialog::smoothing_changed () +{ + _plot->set_smoothing (_smoothing->GetValue ()); +} diff --git a/src/wx/audio_dialog.h b/src/wx/audio_dialog.h new file mode 100644 index 000000000..8623192c4 --- /dev/null +++ b/src/wx/audio_dialog.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + + 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 <boost/shared_ptr.hpp> +#include <boost/signals2.hpp> +#include <wx/wx.h> +#include "lib/film.h" +#include "lib/audio_analysis.h" + +class AudioPlot; +class Film; + +class AudioDialog : public wxDialog +{ +public: + AudioDialog (wxWindow *); + + void set_content (boost::shared_ptr<AudioContent>); + +private: + void content_changed (int); + void channel_clicked (wxCommandEvent &); + void type_clicked (wxCommandEvent &); + void smoothing_changed (); + void try_to_load_analysis (); + void analysis_finished (); + + boost::shared_ptr<AudioContent> _content; + AudioPlot* _plot; + wxCheckBox* _channel_checkbox[MAX_AUDIO_CHANNELS]; + wxCheckBox* _type_checkbox[AudioPoint::COUNT]; + wxSlider* _smoothing; + boost::signals2::scoped_connection _content_changed_connection; +}; diff --git a/src/wx/audio_mapping_view.cc b/src/wx/audio_mapping_view.cc new file mode 100644 index 000000000..3136b8679 --- /dev/null +++ b/src/wx/audio_mapping_view.cc @@ -0,0 +1,207 @@ +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + + 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 <wx/wx.h> +#include <wx/renderer.h> +#include <wx/grid.h> +#include <libdcp/types.h> +#include "lib/audio_mapping.h" +#include "lib/util.h" +#include "audio_mapping_view.h" +#include "wx_util.h" + +using std::cout; +using std::list; +using boost::shared_ptr; + +/* This could go away with wxWidgets 2.9, which has an API call + to find these values. +*/ + +#ifdef __WXMSW__ +#define CHECKBOX_WIDTH 16 +#define CHECKBOX_HEIGHT 16 +#else +#define CHECKBOX_WIDTH 20 +#define CHECKBOX_HEIGHT 20 +#endif + +class NoSelectionStringRenderer : public wxGridCellStringRenderer +{ +public: + void Draw (wxGrid& grid, wxGridCellAttr& attr, wxDC& dc, const wxRect& rect, int row, int col, bool) + { + wxGridCellStringRenderer::Draw (grid, attr, dc, rect, row, col, false); + } +}; + +class CheckBoxRenderer : public wxGridCellRenderer +{ +public: + + void Draw (wxGrid& grid, wxGridCellAttr &, wxDC& dc, const wxRect& rect, int row, int col, bool) + { + dc.SetPen (*wxThePenList->FindOrCreatePen (wxColour (255, 255, 255), 0, wxPENSTYLE_SOLID)); + dc.DrawRectangle (rect); + + wxRendererNative::Get().DrawCheckBox ( + &grid, + dc, rect, + grid.GetCellValue (row, col) == wxT("1") ? static_cast<int>(wxCONTROL_CHECKED) : 0 + ); + } + + wxSize GetBestSize (wxGrid &, wxGridCellAttr &, wxDC &, int, int) + { + return wxSize (CHECKBOX_WIDTH + 4, CHECKBOX_HEIGHT + 4); + } + + wxGridCellRenderer* Clone () const + { + return new CheckBoxRenderer; + } +}; + + +AudioMappingView::AudioMappingView (wxWindow* parent) + : wxPanel (parent, wxID_ANY) +{ + _grid = new wxGrid (this, wxID_ANY); + + _grid->CreateGrid (0, 7); + _grid->HideRowLabels (); + _grid->DisableDragRowSize (); + _grid->DisableDragColSize (); + _grid->EnableEditing (false); + _grid->SetCellHighlightPenWidth (0); + _grid->SetDefaultRenderer (new NoSelectionStringRenderer); + + set_column_labels (); + + _sizer = new wxBoxSizer (wxVERTICAL); + _sizer->Add (_grid, 1, wxEXPAND | wxALL); + SetSizerAndFit (_sizer); + + Bind (wxEVT_GRID_CELL_LEFT_CLICK, boost::bind (&AudioMappingView::left_click, this, _1)); +} + +void +AudioMappingView::left_click (wxGridEvent& ev) +{ + if (ev.GetCol() == 0) { + return; + } + + if (_grid->GetCellValue (ev.GetRow(), ev.GetCol()) == wxT("1")) { + _grid->SetCellValue (ev.GetRow(), ev.GetCol(), wxT("0")); + } else { + _grid->SetCellValue (ev.GetRow(), ev.GetCol(), wxT("1")); + } + + _map = AudioMapping (_map.content_channels ()); + + for (int i = 0; i < _grid->GetNumberRows(); ++i) { + for (int j = 1; j < _grid->GetNumberCols(); ++j) { + if (_grid->GetCellValue (i, j) == wxT ("1")) { + _map.add (i, static_cast<libdcp::Channel> (j - 1)); + } + } + } + + Changed (_map); +} + +void +AudioMappingView::set (AudioMapping map) +{ + _map = map; + + if (_grid->GetNumberRows ()) { + _grid->DeleteRows (0, _grid->GetNumberRows ()); + } + + _grid->InsertRows (0, _map.content_channels ()); + + for (int r = 0; r < _map.content_channels(); ++r) { + for (int c = 1; c < 7; ++c) { + _grid->SetCellRenderer (r, c, new CheckBoxRenderer); + } + } + + for (int i = 0; i < _map.content_channels(); ++i) { + _grid->SetCellValue (i, 0, wxString::Format (wxT("%d"), i + 1)); + + list<libdcp::Channel> const d = _map.content_to_dcp (i); + for (list<libdcp::Channel>::const_iterator j = d.begin(); j != d.end(); ++j) { + int const c = static_cast<int>(*j) + 1; + if (c < _grid->GetNumberCols ()) { + _grid->SetCellValue (i, c, wxT("1")); + } + } + } +} + +void +AudioMappingView::set_channels (int c) +{ + c++; + + if (c < _grid->GetNumberCols ()) { + _grid->DeleteCols (c, _grid->GetNumberCols() - c); + } else if (c > _grid->GetNumberCols ()) { + _grid->InsertCols (_grid->GetNumberCols(), c - _grid->GetNumberCols()); + set_column_labels (); + } + + set (_map); +} + +void +AudioMappingView::set_column_labels () +{ + int const c = _grid->GetNumberCols (); + + _grid->SetColLabelValue (0, _("Content channel")); + + if (c > 0) { + _grid->SetColLabelValue (1, _("L")); + } + + if (c > 1) { + _grid->SetColLabelValue (2, _("R")); + } + + if (c > 2) { + _grid->SetColLabelValue (3, _("C")); + } + + if (c > 3) { + _grid->SetColLabelValue (4, _("Lfe")); + } + + if (c > 4) { + _grid->SetColLabelValue (5, _("Ls")); + } + + if (c > 5) { + _grid->SetColLabelValue (6, _("Rs")); + } + + _grid->AutoSize (); +} diff --git a/src/wx/audio_mapping_view.h b/src/wx/audio_mapping_view.h new file mode 100644 index 000000000..80534a613 --- /dev/null +++ b/src/wx/audio_mapping_view.h @@ -0,0 +1,42 @@ +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + + 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 <boost/signals2.hpp> +#include <wx/wx.h> +#include <wx/grid.h> +#include "lib/audio_mapping.h" + +class AudioMappingView : public wxPanel +{ +public: + AudioMappingView (wxWindow *); + + void set (AudioMapping); + void set_channels (int); + + boost::signals2::signal<void (AudioMapping)> Changed; + +private: + void left_click (wxGridEvent &); + void set_column_labels (); + + wxGrid* _grid; + wxSizer* _sizer; + AudioMapping _map; +}; diff --git a/src/wx/audio_panel.cc b/src/wx/audio_panel.cc new file mode 100644 index 000000000..b4921904c --- /dev/null +++ b/src/wx/audio_panel.cc @@ -0,0 +1,288 @@ +/* + Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net> + + 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 <boost/lexical_cast.hpp> +#include <wx/spinctrl.h> +#include "lib/config.h" +#include "lib/sound_processor.h" +#include "lib/ffmpeg_content.h" +#include "audio_dialog.h" +#include "audio_panel.h" +#include "audio_mapping_view.h" +#include "wx_util.h" +#include "gain_calculator_dialog.h" +#include "film_editor.h" + +using std::vector; +using std::cout; +using std::string; +using boost::dynamic_pointer_cast; +using boost::lexical_cast; +using boost::shared_ptr; + +AudioPanel::AudioPanel (FilmEditor* e) + : FilmEditorPanel (e, _("Audio")) + , _audio_dialog (0) +{ + wxFlexGridSizer* grid = new wxFlexGridSizer (3, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + _sizer->Add (grid, 0, wxALL, 8); + + _show = new wxButton (this, wxID_ANY, _("Show Audio...")); + grid->Add (_show, 1); + grid->AddSpacer (0); + grid->AddSpacer (0); + + add_label_to_sizer (grid, this, _("Audio Gain"), true); + { + wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); + _gain = new wxSpinCtrl (this); + s->Add (_gain, 1); + add_label_to_sizer (s, this, _("dB"), false); + grid->Add (s, 1); + } + + _gain_calculate_button = new wxButton (this, wxID_ANY, _("Calculate...")); + grid->Add (_gain_calculate_button); + + add_label_to_sizer (grid, this, _("Audio Delay"), false); + { + wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); + _delay = new wxSpinCtrl (this); + s->Add (_delay, 1); + /// TRANSLATORS: this is an abbreviation for milliseconds, the unit of time + add_label_to_sizer (s, this, _("ms"), false); + grid->Add (s); + } + + grid->AddSpacer (0); + + add_label_to_sizer (grid, this, _("Audio Stream"), true); + _stream = new wxChoice (this, wxID_ANY); + grid->Add (_stream, 1, wxEXPAND); + _description = new wxStaticText (this, wxID_ANY, wxT ("")); + grid->AddSpacer (0); + + grid->Add (_description, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, 8); + grid->AddSpacer (0); + grid->AddSpacer (0); + + _mapping = new AudioMappingView (this); + _sizer->Add (_mapping, 1, wxEXPAND | wxALL, 6); + + _gain->SetRange (-60, 60); + _delay->SetRange (-1000, 1000); + + _delay->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&AudioPanel::delay_changed, this)); + _stream->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&AudioPanel::stream_changed, this)); + _show->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&AudioPanel::show_clicked, this)); + _gain->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&AudioPanel::gain_changed, this)); + _gain_calculate_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&AudioPanel::gain_calculate_button_clicked, this)); + + _mapping->Changed.connect (boost::bind (&AudioPanel::mapping_changed, this, _1)); +} + + +void +AudioPanel::film_changed (Film::Property property) +{ + switch (property) { + case Film::AUDIO_CHANNELS: + _mapping->set_channels (_editor->film()->audio_channels ()); + _sizer->Layout (); + break; + default: + break; + } +} + +void +AudioPanel::film_content_changed (shared_ptr<Content> c, int property) +{ + shared_ptr<AudioContent> ac = dynamic_pointer_cast<AudioContent> (c); + shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (c); + + if (_audio_dialog && _editor->selected_audio_content()) { + _audio_dialog->set_content (_editor->selected_audio_content ()); + } + + if (property == AudioContentProperty::AUDIO_GAIN) { + checked_set (_gain, ac ? ac->audio_gain() : 0); + } else if (property == AudioContentProperty::AUDIO_DELAY) { + checked_set (_delay, ac ? ac->audio_delay() : 0); + } else if (property == AudioContentProperty::AUDIO_MAPPING) { + _mapping->set (ac ? ac->audio_mapping () : AudioMapping ()); + _sizer->Layout (); + } else if (property == FFmpegContentProperty::AUDIO_STREAM) { + setup_stream_description (); + } else if (property == FFmpegContentProperty::AUDIO_STREAMS) { + _stream->Clear (); + if (fc) { + vector<shared_ptr<FFmpegAudioStream> > a = fc->audio_streams (); + for (vector<shared_ptr<FFmpegAudioStream> >::iterator i = a.begin(); i != a.end(); ++i) { + _stream->Append (std_to_wx ((*i)->name), new wxStringClientData (std_to_wx (lexical_cast<string> ((*i)->id)))); + } + + if (fc->audio_stream()) { + checked_set (_stream, lexical_cast<string> (fc->audio_stream()->id)); + setup_stream_description (); + } + } + } +} + +void +AudioPanel::gain_changed () +{ + shared_ptr<AudioContent> ac = _editor->selected_audio_content (); + if (!ac) { + return; + } + + ac->set_audio_gain (_gain->GetValue ()); +} + +void +AudioPanel::delay_changed () +{ + shared_ptr<AudioContent> ac = _editor->selected_audio_content (); + if (!ac) { + return; + } + + ac->set_audio_delay (_delay->GetValue ()); +} + +void +AudioPanel::gain_calculate_button_clicked () +{ + GainCalculatorDialog* d = new GainCalculatorDialog (this); + d->ShowModal (); + + if (d->wanted_fader() == 0 || d->actual_fader() == 0) { + d->Destroy (); + return; + } + + _gain->SetValue ( + Config::instance()->sound_processor()->db_for_fader_change ( + d->wanted_fader (), + d->actual_fader () + ) + ); + + /* This appears to be necessary, as the change is not signalled, + I think. + */ + gain_changed (); + + d->Destroy (); +} + +void +AudioPanel::show_clicked () +{ + if (_audio_dialog) { + _audio_dialog->Destroy (); + _audio_dialog = 0; + } + + shared_ptr<Content> c = _editor->selected_content (); + if (!c) { + return; + } + + shared_ptr<AudioContent> ac = dynamic_pointer_cast<AudioContent> (c); + if (!ac) { + return; + } + + _audio_dialog = new AudioDialog (this); + _audio_dialog->Show (); + _audio_dialog->set_content (ac); +} + +void +AudioPanel::stream_changed () +{ + shared_ptr<Content> c = _editor->selected_content (); + if (!c) { + return; + } + + shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (c); + if (!fc) { + return; + } + + if (_stream->GetSelection() == -1) { + return; + } + + vector<shared_ptr<FFmpegAudioStream> > a = fc->audio_streams (); + vector<shared_ptr<FFmpegAudioStream> >::iterator i = a.begin (); + string const s = string_client_data (_stream->GetClientObject (_stream->GetSelection ())); + while (i != a.end() && lexical_cast<string> ((*i)->id) != s) { + ++i; + } + + if (i != a.end ()) { + fc->set_audio_stream (*i); + } + + setup_stream_description (); +} + +void +AudioPanel::setup_stream_description () +{ + shared_ptr<Content> c = _editor->selected_content (); + if (!c) { + return; + } + + shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (c); + if (!fc) { + return; + } + + if (!fc->audio_stream ()) { + _description->SetLabel (wxT ("")); + } else { + wxString s; + if (fc->audio_channels() == 1) { + s << _("1 channel"); + } else { + s << fc->audio_channels() << wxT (" ") << _("channels"); + } + s << wxT (", ") << fc->content_audio_frame_rate() << _("Hz"); + _description->SetLabel (s); + } +} + +void +AudioPanel::mapping_changed (AudioMapping m) +{ + shared_ptr<AudioContent> c = _editor->selected_audio_content (); + if (!c) { + return; + } + + c->set_audio_mapping (m); +} + diff --git a/src/wx/audio_panel.h b/src/wx/audio_panel.h new file mode 100644 index 000000000..e1dc283e2 --- /dev/null +++ b/src/wx/audio_panel.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net> + + 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 "lib/audio_mapping.h" +#include "film_editor_panel.h" + +class wxSpinCtrl; +class wxButton; +class wxChoice; +class wxStaticText; +class AudioMappingView; +class AudioDialog; + +class AudioPanel : public FilmEditorPanel +{ +public: + AudioPanel (FilmEditor *); + + void film_changed (Film::Property); + void film_content_changed (boost::shared_ptr<Content>, int); + +private: + void gain_changed (); + void gain_calculate_button_clicked (); + void show_clicked (); + void delay_changed (); + void stream_changed (); + void mapping_changed (AudioMapping); + void setup_stream_description (); + + wxSpinCtrl* _gain; + wxButton* _gain_calculate_button; + wxButton* _show; + wxSpinCtrl* _delay; + wxChoice* _stream; + wxStaticText* _description; + AudioMappingView* _mapping; + AudioDialog* _audio_dialog; +}; diff --git a/src/wx/audio_plot.cc b/src/wx/audio_plot.cc new file mode 100644 index 000000000..7ed792351 --- /dev/null +++ b/src/wx/audio_plot.cc @@ -0,0 +1,281 @@ +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + + 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 <iostream> +#include <boost/bind.hpp> +#include <wx/graphics.h> +#include "audio_plot.h" +#include "lib/audio_decoder.h" +#include "lib/audio_analysis.h" +#include "wx/wx_util.h" + +using std::cout; +using std::vector; +using std::list; +using std::max; +using std::min; +using boost::bind; +using boost::shared_ptr; + +int const AudioPlot::_minimum = -70; +int const AudioPlot::max_smoothing = 128; + +AudioPlot::AudioPlot (wxWindow* parent) + : wxPanel (parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE) + , _gain (0) + , _smoothing (max_smoothing / 2) + , _message (_("Please wait; audio is being analysed...")) +{ +#ifndef __WXOSX__ + SetDoubleBuffered (true); +#endif + + for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) { + _channel_visible[i] = false; + } + + for (int i = 0; i < AudioPoint::COUNT; ++i) { + _type_visible[i] = false; + } + + _colours.push_back (wxColour ( 0, 0, 0)); + _colours.push_back (wxColour (255, 0, 0)); + _colours.push_back (wxColour ( 0, 255, 0)); + _colours.push_back (wxColour (139, 0, 204)); + _colours.push_back (wxColour ( 0, 0, 255)); + _colours.push_back (wxColour (100, 100, 100)); + + Bind (wxEVT_PAINT, boost::bind (&AudioPlot::paint, this)); + + SetMinSize (wxSize (640, 512)); +} + +void +AudioPlot::set_analysis (shared_ptr<AudioAnalysis> a) +{ + _analysis = a; + + for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) { + _channel_visible[i] = false; + } + + for (int i = 0; i < AudioPoint::COUNT; ++i) { + _type_visible[i] = false; + } + + Refresh (); +} + +void +AudioPlot::set_channel_visible (int c, bool v) +{ + _channel_visible[c] = v; + Refresh (); +} + +void +AudioPlot::set_type_visible (int t, bool v) +{ + _type_visible[t] = v; + Refresh (); +} + +void +AudioPlot::set_message (wxString s) +{ + _message = s; + Refresh (); +} + +void +AudioPlot::paint () +{ + wxPaintDC dc (this); + + wxGraphicsContext* gc = wxGraphicsContext::Create (dc); + if (!gc) { + return; + } + + if (!_analysis || _analysis->channels() == 0) { + gc->SetFont (gc->CreateFont (*wxNORMAL_FONT)); + gc->DrawText (_message, 32, 32); + return; + } + + wxGraphicsPath grid = gc->CreatePath (); + gc->SetFont (gc->CreateFont (*wxSMALL_FONT)); + wxDouble db_label_height; + wxDouble db_label_descent; + wxDouble db_label_leading; + gc->GetTextExtent (wxT ("-80dB"), &_db_label_width, &db_label_height, &db_label_descent, &db_label_leading); + + _db_label_width += 8; + + int const data_width = GetSize().GetWidth() - _db_label_width; + /* Assume all channels have the same number of points */ + _x_scale = data_width / float (_analysis->points (0)); + _height = GetSize().GetHeight (); + _y_origin = 32; + _y_scale = (_height - _y_origin) / -_minimum; + + for (int i = _minimum; i <= 0; i += 10) { + int const y = (_height - (i - _minimum) * _y_scale) - _y_origin; + grid.MoveToPoint (_db_label_width - 4, y); + grid.AddLineToPoint (_db_label_width + data_width, y); + gc->DrawText (std_to_wx (String::compose ("%1dB", i)), 0, y - (db_label_height / 2)); + } + + gc->SetPen (*wxLIGHT_GREY_PEN); + gc->StrokePath (grid); + + gc->DrawText (_("Time"), data_width, _height - _y_origin + db_label_height / 2); + + + if (_type_visible[AudioPoint::PEAK]) { + for (int c = 0; c < MAX_AUDIO_CHANNELS; ++c) { + wxGraphicsPath p = gc->CreatePath (); + if (_channel_visible[c] && c < _analysis->channels()) { + plot_peak (p, c); + } + wxColour const col = _colours[c]; + gc->SetPen (*wxThePenList->FindOrCreatePen (wxColour (col.Red(), col.Green(), col.Blue(), col.Alpha() / 2), 1, wxPENSTYLE_SOLID)); + gc->StrokePath (p); + } + } + + if (_type_visible[AudioPoint::RMS]) { + for (int c = 0; c < MAX_AUDIO_CHANNELS; ++c) { + wxGraphicsPath p = gc->CreatePath (); + if (_channel_visible[c] && c < _analysis->channels()) { + plot_rms (p, c); + } + wxColour const col = _colours[c]; + gc->SetPen (*wxThePenList->FindOrCreatePen (col, 1, wxPENSTYLE_SOLID)); + gc->StrokePath (p); + } + } + + wxGraphicsPath axes = gc->CreatePath (); + axes.MoveToPoint (_db_label_width, 0); + axes.AddLineToPoint (_db_label_width, _height - _y_origin); + axes.AddLineToPoint (_db_label_width + data_width, _height - _y_origin); + gc->SetPen (*wxBLACK_PEN); + gc->StrokePath (axes); + + delete gc; +} + +float +AudioPlot::y_for_linear (float p) const +{ + return _height - (20 * log10(p) - _minimum + _gain) * _y_scale - _y_origin; +} + +void +AudioPlot::plot_peak (wxGraphicsPath& path, int channel) const +{ + if (_analysis->points (channel) == 0) { + return; + } + + path.MoveToPoint (_db_label_width, y_for_linear (_analysis->get_point(channel, 0)[AudioPoint::PEAK])); + + float peak = 0; + int const N = _analysis->points(channel); + for (int i = 0; i < N; ++i) { + float const p = _analysis->get_point(channel, i)[AudioPoint::PEAK]; + peak -= 0.01f * (1 - log10 (_smoothing) / log10 (max_smoothing)); + if (p > peak) { + peak = p; + } else if (peak < 0) { + peak = 0; + } + + path.AddLineToPoint (_db_label_width + i * _x_scale, y_for_linear (peak)); + } +} + +void +AudioPlot::plot_rms (wxGraphicsPath& path, int channel) const +{ + if (_analysis->points (channel) == 0) { + return; + } + + path.MoveToPoint (_db_label_width, y_for_linear (_analysis->get_point(channel, 0)[AudioPoint::RMS])); + + list<float> smoothing; + + int const N = _analysis->points(channel); + + float const first = _analysis->get_point(channel, 0)[AudioPoint::RMS]; + float const last = _analysis->get_point(channel, N - 1)[AudioPoint::RMS]; + + int const before = _smoothing / 2; + int const after = _smoothing - before; + + /* Pre-load the smoothing list */ + for (int i = 0; i < before; ++i) { + smoothing.push_back (first); + } + for (int i = 0; i < after; ++i) { + if (i < N) { + smoothing.push_back (_analysis->get_point(channel, i)[AudioPoint::RMS]); + } else { + smoothing.push_back (last); + } + } + + for (int i = 0; i < N; ++i) { + + int const next_for_window = i + after; + + if (next_for_window < N) { + smoothing.push_back (_analysis->get_point(channel, i)[AudioPoint::RMS]); + } else { + smoothing.push_back (last); + } + + smoothing.pop_front (); + + float p = 0; + for (list<float>::const_iterator j = smoothing.begin(); j != smoothing.end(); ++j) { + p += pow (*j, 2); + } + + p = sqrt (p / smoothing.size ()); + + path.AddLineToPoint (_db_label_width + i * _x_scale, y_for_linear (p)); + } +} + +void +AudioPlot::set_gain (float g) +{ + _gain = g; + Refresh (); +} + +void +AudioPlot::set_smoothing (int s) +{ + _smoothing = s; + Refresh (); +} diff --git a/src/wx/audio_plot.h b/src/wx/audio_plot.h new file mode 100644 index 000000000..094f8e1b0 --- /dev/null +++ b/src/wx/audio_plot.h @@ -0,0 +1,64 @@ +/* + Copyright (C) 2012 Carl Hetherington <cth@carlh.net> + + 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 <vector> +#include <boost/shared_ptr.hpp> +#include <wx/wx.h> +#include "lib/util.h" +#include "lib/audio_analysis.h" + +class AudioPlot : public wxPanel +{ +public: + AudioPlot (wxWindow *); + + void set_analysis (boost::shared_ptr<AudioAnalysis>); + void set_channel_visible (int c, bool v); + void set_type_visible (int t, bool v); + void set_gain (float); + void set_smoothing (int); + void set_message (wxString); + + static const int max_smoothing; + +private: + void paint (); + + boost::shared_ptr<AudioAnalysis> _analysis; + bool _channel_visible[MAX_AUDIO_CHANNELS]; + bool _type_visible[AudioPoint::COUNT]; + /** gain to apply in dB */ + float _gain; + int _smoothing; + std::vector<wxColour> _colours; + + void plot_peak (wxGraphicsPath &, int) const; + void plot_rms (wxGraphicsPath &, int) const; + float y_for_linear (float) const; + + double _db_label_width; + int _height; + int _y_origin; + float _x_scale; + float _y_scale; + + wxString _message; + + static const int _minimum; +}; diff --git a/src/wx/cinema_dialog.cc b/src/wx/cinema_dialog.cc index 9e3b1507d..2c0b0b4a4 100644 --- a/src/wx/cinema_dialog.cc +++ b/src/wx/cinema_dialog.cc @@ -28,11 +28,11 @@ CinemaDialog::CinemaDialog (wxWindow* parent, string title, string name, string wxFlexGridSizer* table = new wxFlexGridSizer (2, 6, 6); table->AddGrowableCol (1, 1); - add_label_to_sizer (table, this, "Name"); + add_label_to_sizer (table, this, "Name", true); _name = new wxTextCtrl (this, wxID_ANY, std_to_wx (name), wxDefaultPosition, wxSize (256, -1)); table->Add (_name, 1, wxEXPAND); - add_label_to_sizer (table, this, "Email address for KDM delivery"); + add_label_to_sizer (table, this, "Email address for KDM delivery", true); _email = new wxTextCtrl (this, wxID_ANY, std_to_wx (email), wxDefaultPosition, wxSize (256, -1)); table->Add (_email, 1, wxEXPAND); diff --git a/src/wx/colour_conversion_editor.cc b/src/wx/colour_conversion_editor.cc new file mode 100644 index 000000000..823f5ad38 --- /dev/null +++ b/src/wx/colour_conversion_editor.cc @@ -0,0 +1,152 @@ +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + + 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 <boost/lexical_cast.hpp> +#include <wx/spinctrl.h> +#include <wx/gbsizer.h> +#include "lib/colour_conversion.h" +#include "wx_util.h" +#include "colour_conversion_editor.h" + +using std::string; +using std::cout; +using std::stringstream; +using boost::shared_ptr; +using boost::lexical_cast; + +ColourConversionEditor::ColourConversionEditor (wxWindow* parent) + : wxPanel (parent, wxID_ANY) +{ + wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); + SetSizer (overall_sizer); + + wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + overall_sizer->Add (table, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); + + int r = 0; + + add_label_to_grid_bag_sizer (table, this, _("Input gamma"), true, wxGBPosition (r, 0)); + _input_gamma = new wxSpinCtrlDouble (this); + table->Add (_input_gamma, wxGBPosition (r, 1)); + ++r; + + _input_gamma_linearised = new wxCheckBox (this, wxID_ANY, _("Linearise input gamma curve for low values")); + table->Add (_input_gamma_linearised, wxGBPosition (r, 0), wxGBSpan (1, 2)); + ++r; + + wxClientDC dc (parent); + wxSize size = dc.GetTextExtent (wxT ("-0.12345678901")); + size.SetHeight (-1); + + wxTextValidator validator (wxFILTER_INCLUDE_CHAR_LIST); + wxArrayString list; + + wxString n (wxT ("0123456789.-")); + for (size_t i = 0; i < n.Length(); ++i) { + list.Add (n[i]); + } + + validator.SetIncludes (list); + + add_label_to_grid_bag_sizer (table, this, _("Matrix"), true, wxGBPosition (r, 0)); + wxFlexGridSizer* matrix_sizer = new wxFlexGridSizer (3, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + _matrix[i][j] = new wxTextCtrl (this, wxID_ANY, wxT (""), wxDefaultPosition, size, 0, validator); + matrix_sizer->Add (_matrix[i][j]); + } + } + table->Add (matrix_sizer, wxGBPosition (r, 1)); + ++r; + + add_label_to_grid_bag_sizer (table, this, _("Output gamma"), true, wxGBPosition (r, 0)); + wxBoxSizer* output_sizer = new wxBoxSizer (wxHORIZONTAL); + /* TRANSLATORS: this means the mathematical reciprocal operation, i.e. we are dividing 1 by the control that + comes after it. + */ + add_label_to_sizer (output_sizer, this, _("1 / "), false); + _output_gamma = new wxSpinCtrlDouble (this); + output_sizer->Add (_output_gamma); + table->Add (output_sizer, wxGBPosition (r, 1)); + ++r; + + _input_gamma->SetRange(0.1, 4.0); + _input_gamma->SetDigits (1); + _input_gamma->SetIncrement (0.1); + _output_gamma->SetRange(0.1, 4.0); + _output_gamma->SetDigits (1); + _output_gamma->SetIncrement (0.1); + + _input_gamma->Bind (wxEVT_COMMAND_SPINCTRLDOUBLE_UPDATED, boost::bind (&ColourConversionEditor::changed, this)); + _input_gamma_linearised->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&ColourConversionEditor::changed, this)); + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + _matrix[i][j]->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ColourConversionEditor::changed, this)); + } + } + _output_gamma->Bind (wxEVT_COMMAND_SPINCTRLDOUBLE_UPDATED, boost::bind (&ColourConversionEditor::changed, this)); +} + +void +ColourConversionEditor::set (ColourConversion conversion) +{ + _input_gamma->SetValue (conversion.input_gamma); + _input_gamma_linearised->SetValue (conversion.input_gamma_linearised); + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + stringstream s; + s.setf (std::ios::fixed, std::ios::floatfield); + s.precision (7); + s << conversion.matrix (i, j); + _matrix[i][j]->SetValue (std_to_wx (s.str ())); + } + } + _output_gamma->SetValue (conversion.output_gamma); +} + +ColourConversion +ColourConversionEditor::get () const +{ + ColourConversion conversion; + + conversion.input_gamma = _input_gamma->GetValue (); + conversion.input_gamma_linearised = _input_gamma_linearised->GetValue (); + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + string const v = wx_to_std (_matrix[i][j]->GetValue ()); + if (v.empty ()) { + conversion.matrix (i, j) = 0; + } else { + conversion.matrix (i, j) = lexical_cast<double> (v); + } + } + } + + conversion.output_gamma = _output_gamma->GetValue (); + + return conversion; +} + +void +ColourConversionEditor::changed () +{ + Changed (); +} + diff --git a/src/wx/colour_conversion_editor.h b/src/wx/colour_conversion_editor.h new file mode 100644 index 000000000..8567cac22 --- /dev/null +++ b/src/wx/colour_conversion_editor.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + + 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. + +*/ + +#ifndef DCPOMATIC_COLOUR_CONVERSION_EDITOR_H +#define DCPOMATIC_COLOUR_CONVERSION_EDITOR_H + +#include <boost/signals2.hpp> +#include <wx/wx.h> + +class wxSpinCtrlDouble; +class ColourConversion; + +class ColourConversionEditor : public wxPanel +{ +public: + ColourConversionEditor (wxWindow *); + + void set (ColourConversion); + ColourConversion get () const; + + boost::signals2::signal<void ()> Changed; + +private: + void changed (); + + wxSpinCtrlDouble* _input_gamma; + wxCheckBox* _input_gamma_linearised; + wxTextCtrl* _matrix[3][3]; + wxSpinCtrlDouble* _output_gamma; +}; + +#endif diff --git a/src/wx/config_dialog.cc b/src/wx/config_dialog.cc index 9de8e7001..7f1efa52f 100644 --- a/src/wx/config_dialog.cc +++ b/src/wx/config_dialog.cc @@ -18,292 +18,437 @@ */ /** @file src/config_dialog.cc - * @brief A dialogue to edit DVD-o-matic configuration. + * @brief A dialogue to edit DCP-o-matic configuration. */ #include <iostream> #include <boost/lexical_cast.hpp> #include <boost/filesystem.hpp> #include <wx/stdpaths.h> +#include <wx/notebook.h> +#include <libdcp/colour_matrix.h> #include "lib/config.h" #include "lib/server.h" -#include "lib/format.h" +#include "lib/ratio.h" #include "lib/scaler.h" #include "lib/filter.h" +#include "lib/dcp_content_type.h" +#include "lib/colour_conversion.h" #include "config_dialog.h" #include "wx_util.h" #include "filter_dialog.h" #include "server_dialog.h" #include "dir_picker_ctrl.h" +#include "dci_metadata_dialog.h" +#include "preset_colour_conversion_dialog.h" -using namespace std; +using std::vector; +using std::string; +using std::list; using boost::bind; +using boost::shared_ptr; +using boost::lexical_cast; ConfigDialog::ConfigDialog (wxWindow* parent) - : wxDialog (parent, wxID_ANY, _("DVD-o-matic Preferences"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) + : wxDialog (parent, wxID_ANY, _("DCP-o-matic Preferences"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) { - wxFlexGridSizer* table = new wxFlexGridSizer (3, 6, 6); - table->AddGrowableCol (1, 1); + wxBoxSizer* s = new wxBoxSizer (wxVERTICAL); + _notebook = new wxNotebook (this, wxID_ANY); + s->Add (_notebook, 1); + + make_misc_panel (); + _notebook->AddPage (_misc_panel, _("Miscellaneous"), true); + make_servers_panel (); + _notebook->AddPage (_servers_panel, _("Encoding servers"), false); + make_colour_conversions_panel (); + _notebook->AddPage (_colour_conversions_panel, _("Colour conversions"), false); + make_metadata_panel (); + _notebook->AddPage (_metadata_panel, _("Metadata"), false); + make_tms_panel (); + _notebook->AddPage (_tms_panel, _("TMS"), false); - add_label_to_sizer (table, this, "TMS IP address"); - _tms_ip = new wxTextCtrl (this, wxID_ANY); - table->Add (_tms_ip, 1, wxEXPAND); - table->AddSpacer (0); + wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); + overall_sizer->Add (s, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); - add_label_to_sizer (table, this, "TMS target path"); - _tms_path = new wxTextCtrl (this, wxID_ANY); - table->Add (_tms_path, 1, wxEXPAND); - table->AddSpacer (0); + wxSizer* buttons = CreateSeparatedButtonSizer (wxOK); + if (buttons) { + overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); + } - add_label_to_sizer (table, this, "TMS user name"); - _tms_user = new wxTextCtrl (this, wxID_ANY); - table->Add (_tms_user, 1, wxEXPAND); - table->AddSpacer (0); + SetSizer (overall_sizer); + overall_sizer->Layout (); + overall_sizer->SetSizeHints (this); +} - add_label_to_sizer (table, this, "TMS password"); - _tms_password = new wxTextCtrl (this, wxID_ANY); - table->Add (_tms_password, 1, wxEXPAND); - table->AddSpacer (0); +void +ConfigDialog::make_misc_panel () +{ + _misc_panel = new wxPanel (_notebook); + wxBoxSizer* s = new wxBoxSizer (wxVERTICAL); + _misc_panel->SetSizer (s); - add_label_to_sizer (table, this, "Threads to use for encoding on this host"); - _num_local_encoding_threads = new wxSpinCtrl (this); - table->Add (_num_local_encoding_threads, 1, wxEXPAND); + wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + table->AddGrowableCol (1, 1); + s->Add (table, 1, wxALL | wxEXPAND, 8); + + _set_language = new wxCheckBox (_misc_panel, wxID_ANY, _("Set language")); + table->Add (_set_language, 1); + _language = new wxChoice (_misc_panel, wxID_ANY); + _language->Append (wxT ("English")); + _language->Append (wxT ("Français")); + _language->Append (wxT ("Italiano")); + _language->Append (wxT ("Español")); + _language->Append (wxT ("Svenska")); + table->Add (_language); + + wxStaticText* restart = add_label_to_sizer (table, _misc_panel, _("(restart DCP-o-matic to see language changes)"), false); + wxFont font = restart->GetFont(); + font.SetStyle (wxFONTSTYLE_ITALIC); + font.SetPointSize (font.GetPointSize() - 1); + restart->SetFont (font); table->AddSpacer (0); - add_label_to_sizer (table, this, "Default directory for new films"); -#ifdef __WXMSW__ - _default_directory = new DirPickerCtrl (this); + add_label_to_sizer (table, _misc_panel, _("Threads to use for encoding on this host"), true); + _num_local_encoding_threads = new wxSpinCtrl (_misc_panel); + table->Add (_num_local_encoding_threads, 1); + + { + add_label_to_sizer (table, _misc_panel, _("Default duration of still images"), true); + wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); + _default_still_length = new wxSpinCtrl (_misc_panel); + s->Add (_default_still_length); + add_label_to_sizer (s, _misc_panel, _("s"), false); + table->Add (s, 1); + } + + add_label_to_sizer (table, _misc_panel, _("Default directory for new films"), true); +#ifdef DCPOMATIC_USE_OWN_DIR_PICKER + _default_directory = new DirPickerCtrl (_misc_panel); #else - _default_directory = new wxDirPickerCtrl (this, wxDD_DIR_MUST_EXIST); + _default_directory = new wxDirPickerCtrl (_misc_panel, wxDD_DIR_MUST_EXIST); #endif table->Add (_default_directory, 1, wxEXPAND); - table->AddSpacer (0); - add_label_to_sizer (table, this, "Reference scaler for A/B"); - _reference_scaler = new wxComboBox (this, wxID_ANY); - vector<Scaler const *> const sc = Scaler::all (); - for (vector<Scaler const *>::const_iterator i = sc.begin(); i != sc.end(); ++i) { - _reference_scaler->Append (std_to_wx ((*i)->name ())); - } + add_label_to_sizer (table, _misc_panel, _("Default DCI name details"), true); + _default_dci_metadata_button = new wxButton (_misc_panel, wxID_ANY, _("Edit...")); + table->Add (_default_dci_metadata_button); - table->Add (_reference_scaler, 1, wxEXPAND); - table->AddSpacer (0); + add_label_to_sizer (table, _misc_panel, _("Default container"), true); + _default_container = new wxChoice (_misc_panel, wxID_ANY); + table->Add (_default_container); + + add_label_to_sizer (table, _misc_panel, _("Default content type"), true); + _default_dcp_content_type = new wxChoice (_misc_panel, wxID_ANY); + table->Add (_default_dcp_content_type); { - add_label_to_sizer (table, this, "Reference filters for A/B"); - wxSizer* s = new wxBoxSizer (wxHORIZONTAL); - _reference_filters = new wxStaticText (this, wxID_ANY, wxT ("")); - s->Add (_reference_filters, 1, wxEXPAND); - _reference_filters_button = new wxButton (this, wxID_ANY, _("Edit...")); - s->Add (_reference_filters_button, 0); - table->Add (s, 1, wxEXPAND); - table->AddSpacer (0); + add_label_to_sizer (table, _misc_panel, _("Default JPEG2000 bandwidth"), true); + wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); + _default_j2k_bandwidth = new wxSpinCtrl (_misc_panel); + s->Add (_default_j2k_bandwidth); + add_label_to_sizer (s, _misc_panel, _("MBps"), false); + table->Add (s, 1); } + + Config* config = Config::instance (); - add_label_to_sizer (table, this, "Encoding Servers"); - _servers = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxSize (220, 100), wxLC_REPORT | wxLC_SINGLE_SEL); - wxListItem ip; - ip.SetId (0); - ip.SetText (_("IP address")); - ip.SetWidth (120); - _servers->InsertColumn (0, ip); - ip.SetId (1); - ip.SetText (_("Threads")); - ip.SetWidth (80); - _servers->InsertColumn (1, ip); - table->Add (_servers, 1, wxEXPAND | wxALL); + _set_language->SetValue (config->language ()); + + if (config->language().get_value_or ("") == "fr") { + _language->SetSelection (1); + } else if (config->language().get_value_or ("") == "it") { + _language->SetSelection (2); + } else if (config->language().get_value_or ("") == "es") { + _language->SetSelection (3); + } else if (config->language().get_value_or ("") == "sv") { + _language->SetSelection (4); + } else { + _language->SetSelection (0); + } - { - wxSizer* s = new wxBoxSizer (wxVERTICAL); - _add_server = new wxButton (this, wxID_ANY, _("Add")); - s->Add (_add_server); - _edit_server = new wxButton (this, wxID_ANY, _("Edit")); - s->Add (_edit_server); - _remove_server = new wxButton (this, wxID_ANY, _("Remove")); - s->Add (_remove_server); - table->Add (s, 0); + setup_language_sensitivity (); + + _set_language->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&ConfigDialog::set_language_changed, this)); + _language->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&ConfigDialog::language_changed, this)); + + _num_local_encoding_threads->SetRange (1, 128); + _num_local_encoding_threads->SetValue (config->num_local_encoding_threads ()); + _num_local_encoding_threads->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&ConfigDialog::num_local_encoding_threads_changed, this)); + + _default_still_length->SetRange (1, 3600); + _default_still_length->SetValue (config->default_still_length ()); + _default_still_length->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&ConfigDialog::default_still_length_changed, this)); + + _default_directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())))); + _default_directory->Bind (wxEVT_COMMAND_DIRPICKER_CHANGED, boost::bind (&ConfigDialog::default_directory_changed, this)); + + _default_dci_metadata_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&ConfigDialog::edit_default_dci_metadata_clicked, this)); + + vector<Ratio const *> ratio = Ratio::all (); + int n = 0; + for (vector<Ratio const *>::iterator i = ratio.begin(); i != ratio.end(); ++i) { + _default_container->Append (std_to_wx ((*i)->nickname ())); + if (*i == config->default_container ()) { + _default_container->SetSelection (n); + } + ++n; } - - Config* config = Config::instance (); + _default_container->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&ConfigDialog::default_container_changed, this)); + + vector<DCPContentType const *> const ct = DCPContentType::all (); + n = 0; + for (vector<DCPContentType const *>::const_iterator i = ct.begin(); i != ct.end(); ++i) { + _default_dcp_content_type->Append (std_to_wx ((*i)->pretty_name ())); + if (*i == config->default_dcp_content_type ()) { + _default_dcp_content_type->SetSelection (n); + } + ++n; + } + + _default_dcp_content_type->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&ConfigDialog::default_dcp_content_type_changed, this)); + + _default_j2k_bandwidth->SetRange (50, 250); + _default_j2k_bandwidth->SetValue (config->default_j2k_bandwidth() / 1e6); + _default_j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&ConfigDialog::default_j2k_bandwidth_changed, this)); +} + +void +ConfigDialog::make_tms_panel () +{ + _tms_panel = new wxPanel (_notebook); + wxBoxSizer* s = new wxBoxSizer (wxVERTICAL); + _tms_panel->SetSizer (s); + + wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + table->AddGrowableCol (1, 1); + s->Add (table, 1, wxALL | wxEXPAND, 8); + + add_label_to_sizer (table, _tms_panel, _("IP address"), true); + _tms_ip = new wxTextCtrl (_tms_panel, wxID_ANY); + table->Add (_tms_ip, 1, wxEXPAND); + + add_label_to_sizer (table, _tms_panel, _("Target path"), true); + _tms_path = new wxTextCtrl (_tms_panel, wxID_ANY); + table->Add (_tms_path, 1, wxEXPAND); + + add_label_to_sizer (table, _tms_panel, _("User name"), true); + _tms_user = new wxTextCtrl (_tms_panel, wxID_ANY); + table->Add (_tms_user, 1, wxEXPAND); + + add_label_to_sizer (table, _tms_panel, _("Password"), true); + _tms_password = new wxTextCtrl (_tms_panel, wxID_ANY); + table->Add (_tms_password, 1, wxEXPAND); + + Config* config = Config::instance (); + _tms_ip->SetValue (std_to_wx (config->tms_ip ())); - _tms_ip->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (ConfigDialog::tms_ip_changed), 0, this); + _tms_ip->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ConfigDialog::tms_ip_changed, this)); _tms_path->SetValue (std_to_wx (config->tms_path ())); - _tms_path->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (ConfigDialog::tms_path_changed), 0, this); + _tms_path->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ConfigDialog::tms_path_changed, this)); _tms_user->SetValue (std_to_wx (config->tms_user ())); - _tms_user->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (ConfigDialog::tms_user_changed), 0, this); + _tms_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ConfigDialog::tms_user_changed, this)); _tms_password->SetValue (std_to_wx (config->tms_password ())); - _tms_password->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (ConfigDialog::tms_password_changed), 0, this); + _tms_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ConfigDialog::tms_password_changed, this)); +} - _num_local_encoding_threads->SetRange (1, 128); - _num_local_encoding_threads->SetValue (config->num_local_encoding_threads ()); - _num_local_encoding_threads->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (ConfigDialog::num_local_encoding_threads_changed), 0, this); +void +ConfigDialog::make_metadata_panel () +{ + _metadata_panel = new wxPanel (_notebook); + wxBoxSizer* s = new wxBoxSizer (wxVERTICAL); + _metadata_panel->SetSizer (s); - _default_directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())))); - _default_directory->Connect (wxID_ANY, wxEVT_COMMAND_DIRPICKER_CHANGED, wxCommandEventHandler (ConfigDialog::default_directory_changed), 0, this); + wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + table->AddGrowableCol (1, 1); + s->Add (table, 1, wxALL | wxEXPAND, 8); - _reference_scaler->SetSelection (Scaler::as_index (config->reference_scaler ())); - _reference_scaler->Connect (wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler (ConfigDialog::reference_scaler_changed), 0, this); + add_label_to_sizer (table, _metadata_panel, _("Issuer"), true); + _issuer = new wxTextCtrl (_metadata_panel, wxID_ANY); + table->Add (_issuer, 1, wxEXPAND); - pair<string, string> p = Filter::ffmpeg_strings (config->reference_filters ()); - _reference_filters->SetLabel (std_to_wx (p.first + " " + p.second)); - _reference_filters_button->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (ConfigDialog::edit_reference_filters_clicked), 0, this); + add_label_to_sizer (table, _metadata_panel, _("Creator"), true); + _creator = new wxTextCtrl (_metadata_panel, wxID_ANY); + table->Add (_creator, 1, wxEXPAND); - vector<ServerDescription*> servers = config->servers (); - for (vector<ServerDescription*>::iterator i = servers.begin(); i != servers.end(); ++i) { - add_server_to_control (*i); + Config* config = Config::instance (); + + _issuer->SetValue (std_to_wx (config->dcp_metadata().issuer)); + _issuer->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ConfigDialog::issuer_changed, this)); + _creator->SetValue (std_to_wx (config->dcp_metadata().creator)); + _creator->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ConfigDialog::creator_changed, this)); +} + +static std::string +server_column (ServerDescription s, int c) +{ + switch (c) { + case 0: + return s.host_name (); + case 1: + return lexical_cast<string> (s.threads ()); } - - _add_server->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (ConfigDialog::add_server_clicked), 0, this); - _edit_server->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (ConfigDialog::edit_server_clicked), 0, this); - _remove_server->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (ConfigDialog::remove_server_clicked), 0, this); - _servers->Connect (wxID_ANY, wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler (ConfigDialog::server_selection_changed), 0, this); - _servers->Connect (wxID_ANY, wxEVT_COMMAND_LIST_ITEM_DESELECTED, wxListEventHandler (ConfigDialog::server_selection_changed), 0, this); - wxListEvent ev; - server_selection_changed (ev); + return ""; +} - wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); - overall_sizer->Add (table, 1, wxEXPAND | wxALL, 6); +void +ConfigDialog::make_servers_panel () +{ + vector<string> columns; + columns.push_back (wx_to_std (_("IP address"))); + columns.push_back (wx_to_std (_("Threads"))); + _servers_panel = new EditableList<ServerDescription, ServerDialog> ( + _notebook, + columns, + boost::bind (&Config::servers, Config::instance()), + boost::bind (&Config::set_servers, Config::instance(), _1), + boost::bind (&server_column, _1, _2) + ); +} - wxSizer* buttons = CreateSeparatedButtonSizer (wxOK); - if (buttons) { - overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); +void +ConfigDialog::language_changed () +{ + switch (_language->GetSelection ()) { + case 0: + Config::instance()->set_language ("en"); + break; + case 1: + Config::instance()->set_language ("fr"); + break; + case 2: + Config::instance()->set_language ("it"); + break; + case 3: + Config::instance()->set_language ("es"); + break; + case 4: + Config::instance()->set_language ("sv"); + break; } - - SetSizer (overall_sizer); - overall_sizer->Layout (); - overall_sizer->SetSizeHints (this); } void -ConfigDialog::tms_ip_changed (wxCommandEvent &) +ConfigDialog::tms_ip_changed () { Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ())); } void -ConfigDialog::tms_path_changed (wxCommandEvent &) +ConfigDialog::tms_path_changed () { Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ())); } void -ConfigDialog::tms_user_changed (wxCommandEvent &) +ConfigDialog::tms_user_changed () { Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ())); } void -ConfigDialog::tms_password_changed (wxCommandEvent &) +ConfigDialog::tms_password_changed () { Config::instance()->set_tms_password (wx_to_std (_tms_password->GetValue ())); } void -ConfigDialog::num_local_encoding_threads_changed (wxCommandEvent &) +ConfigDialog::num_local_encoding_threads_changed () { Config::instance()->set_num_local_encoding_threads (_num_local_encoding_threads->GetValue ()); } void -ConfigDialog::default_directory_changed (wxCommandEvent &) +ConfigDialog::default_directory_changed () { Config::instance()->set_default_directory (wx_to_std (_default_directory->GetPath ())); } void -ConfigDialog::add_server_to_control (ServerDescription* s) -{ - wxListItem item; - int const n = _servers->GetItemCount (); - item.SetId (n); - _servers->InsertItem (item); - _servers->SetItem (n, 0, std_to_wx (s->host_name ())); - _servers->SetItem (n, 1, std_to_wx (boost::lexical_cast<string> (s->threads ()))); -} - -void -ConfigDialog::add_server_clicked (wxCommandEvent &) +ConfigDialog::edit_default_dci_metadata_clicked () { - ServerDialog* d = new ServerDialog (this, 0); + DCIMetadataDialog* d = new DCIMetadataDialog (this, Config::instance()->default_dci_metadata ()); d->ShowModal (); - ServerDescription* s = d->server (); + Config::instance()->set_default_dci_metadata (d->dci_metadata ()); d->Destroy (); - - add_server_to_control (s); - vector<ServerDescription*> o = Config::instance()->servers (); - o.push_back (s); - Config::instance()->set_servers (o); } void -ConfigDialog::edit_server_clicked (wxCommandEvent &) +ConfigDialog::set_language_changed () { - int i = _servers->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - if (i == -1) { - return; + setup_language_sensitivity (); + if (_set_language->GetValue ()) { + language_changed (); + } else { + Config::instance()->unset_language (); } +} - wxListItem item; - item.SetId (i); - item.SetColumn (0); - _servers->GetItem (item); - - vector<ServerDescription*> servers = Config::instance()->servers (); - assert (i >= 0 && i < int (servers.size ())); - - ServerDialog* d = new ServerDialog (this, servers[i]); - d->ShowModal (); - d->Destroy (); +void +ConfigDialog::setup_language_sensitivity () +{ + _language->Enable (_set_language->GetValue ()); +} - _servers->SetItem (i, 0, std_to_wx (servers[i]->host_name ())); - _servers->SetItem (i, 1, std_to_wx (boost::lexical_cast<string> (servers[i]->threads ()))); +void +ConfigDialog::default_still_length_changed () +{ + Config::instance()->set_default_still_length (_default_still_length->GetValue ()); } void -ConfigDialog::remove_server_clicked (wxCommandEvent &) +ConfigDialog::default_container_changed () { - int i = _servers->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - if (i >= 0) { - _servers->DeleteItem (i); - } + vector<Ratio const *> ratio = Ratio::all (); + Config::instance()->set_default_container (ratio[_default_container->GetSelection()]); +} - vector<ServerDescription*> o = Config::instance()->servers (); - o.erase (o.begin() + i); - Config::instance()->set_servers (o); +void +ConfigDialog::default_dcp_content_type_changed () +{ + vector<DCPContentType const *> ct = DCPContentType::all (); + Config::instance()->set_default_dcp_content_type (ct[_default_dcp_content_type->GetSelection()]); } void -ConfigDialog::server_selection_changed (wxListEvent &) +ConfigDialog::issuer_changed () { - int const i = _servers->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - _edit_server->Enable (i >= 0); - _remove_server->Enable (i >= 0); + libdcp::XMLMetadata m = Config::instance()->dcp_metadata (); + m.issuer = wx_to_std (_issuer->GetValue ()); + Config::instance()->set_dcp_metadata (m); } void -ConfigDialog::reference_scaler_changed (wxCommandEvent &) +ConfigDialog::creator_changed () { - int const n = _reference_scaler->GetSelection (); - if (n >= 0) { - Config::instance()->set_reference_scaler (Scaler::from_index (n)); - } + libdcp::XMLMetadata m = Config::instance()->dcp_metadata (); + m.creator = wx_to_std (_creator->GetValue ()); + Config::instance()->set_dcp_metadata (m); } void -ConfigDialog::edit_reference_filters_clicked (wxCommandEvent &) +ConfigDialog::default_j2k_bandwidth_changed () { - FilterDialog* d = new FilterDialog (this, Config::instance()->reference_filters ()); - d->ActiveChanged.connect (boost::bind (&ConfigDialog::reference_filters_changed, this, _1)); - d->ShowModal (); - d->Destroy (); + Config::instance()->set_default_j2k_bandwidth (_default_j2k_bandwidth->GetValue() * 1e6); +} + +static std::string +colour_conversion_column (PresetColourConversion c) +{ + return c.name; } void -ConfigDialog::reference_filters_changed (vector<Filter const *> f) +ConfigDialog::make_colour_conversions_panel () { - Config::instance()->set_reference_filters (f); - pair<string, string> p = Filter::ffmpeg_strings (Config::instance()->reference_filters ()); - _reference_filters->SetLabel (std_to_wx (p.first + " " + p.second)); + vector<string> columns; + columns.push_back (wx_to_std (_("Name"))); + _colour_conversions_panel = new EditableList<PresetColourConversion, PresetColourConversionDialog> ( + _notebook, + columns, + boost::bind (&Config::colour_conversions, Config::instance()), + boost::bind (&Config::set_colour_conversions, Config::instance(), _1), + boost::bind (&colour_conversion_column, _1) + ); } diff --git a/src/wx/config_dialog.h b/src/wx/config_dialog.h index 32123a0d7..82c4ee2a0 100644 --- a/src/wx/config_dialog.h +++ b/src/wx/config_dialog.h @@ -18,20 +18,25 @@ */ /** @file src/config_dialog.h - * @brief A dialogue to edit DVD-o-matic configuration. + * @brief A dialogue to edit DCP-o-matic configuration. */ #include <wx/wx.h> #include <wx/spinctrl.h> #include <wx/listctrl.h> #include <wx/filepicker.h> +#include "wx_util.h" +#include "editable_list.h" class DirPickerCtrl; - +class wxNotebook; class ServerDescription; +class PresetColourConversion; +class PresetColourConversionDialog; +class ServerDialog; /** @class ConfigDialog - * @brief A dialogue to edit DVD-o-matic configuration. + * @brief A dialogue to edit DCP-o-matic configuration. */ class ConfigDialog : public wxDialog { @@ -39,38 +44,54 @@ public: ConfigDialog (wxWindow *); private: - void tms_ip_changed (wxCommandEvent &); - void tms_path_changed (wxCommandEvent &); - void tms_user_changed (wxCommandEvent &); - void tms_password_changed (wxCommandEvent &); - void num_local_encoding_threads_changed (wxCommandEvent &); - void default_directory_changed (wxCommandEvent &); - void reference_scaler_changed (wxCommandEvent &); - void edit_reference_filters_clicked (wxCommandEvent &); - void reference_filters_changed (std::vector<Filter const *>); - void add_server_clicked (wxCommandEvent &); - void edit_server_clicked (wxCommandEvent &); - void remove_server_clicked (wxCommandEvent &); - void server_selection_changed (wxListEvent &); + void set_language_changed (); + void language_changed (); + void tms_ip_changed (); + void tms_path_changed (); + void tms_user_changed (); + void tms_password_changed (); + void num_local_encoding_threads_changed (); + void default_still_length_changed (); + void default_directory_changed (); + void edit_default_dci_metadata_clicked (); + void default_container_changed (); + void default_dcp_content_type_changed (); + void issuer_changed (); + void creator_changed (); + void default_j2k_bandwidth_changed (); + + void setup_language_sensitivity (); + + void make_misc_panel (); + void make_tms_panel (); + void make_metadata_panel (); + void make_servers_panel (); + void make_colour_conversions_panel (); - void add_server_to_control (ServerDescription *); - + wxNotebook* _notebook; + wxPanel* _misc_panel; + wxPanel* _tms_panel; + EditableList<PresetColourConversion, PresetColourConversionDialog>* _colour_conversions_panel; + EditableList<ServerDescription, ServerDialog>* _servers_panel; + wxPanel* _metadata_panel; + wxCheckBox* _set_language; + wxChoice* _language; + wxChoice* _default_container; + wxChoice* _default_dcp_content_type; wxTextCtrl* _tms_ip; wxTextCtrl* _tms_path; wxTextCtrl* _tms_user; wxTextCtrl* _tms_password; wxSpinCtrl* _num_local_encoding_threads; -#ifdef __WXMSW__ + wxSpinCtrl* _default_still_length; +#ifdef DCPOMATIC_USE_OWN_DIR_PICKER DirPickerCtrl* _default_directory; #else wxDirPickerCtrl* _default_directory; -#endif - wxComboBox* _reference_scaler; - wxStaticText* _reference_filters; - wxButton* _reference_filters_button; - wxListCtrl* _servers; - wxButton* _add_server; - wxButton* _edit_server; - wxButton* _remove_server; +#endif + wxButton* _default_dci_metadata_button; + wxTextCtrl* _issuer; + wxTextCtrl* _creator; + wxSpinCtrl* _default_j2k_bandwidth; }; diff --git a/src/wx/content_colour_conversion_dialog.cc b/src/wx/content_colour_conversion_dialog.cc new file mode 100644 index 000000000..d8e768bcd --- /dev/null +++ b/src/wx/content_colour_conversion_dialog.cc @@ -0,0 +1,121 @@ +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + + 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 <wx/statline.h> +#include "lib/colour_conversion.h" +#include "lib/config.h" +#include "wx_util.h" +#include "content_colour_conversion_dialog.h" +#include "colour_conversion_editor.h" + +using std::string; +using std::vector; +using std::cout; +using boost::optional; + +ContentColourConversionDialog::ContentColourConversionDialog (wxWindow* parent) + : wxDialog (parent, wxID_ANY, _("Colour conversion")) + , _editor (new ColourConversionEditor (this)) + , _setting (false) +{ + wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); + SetSizer (overall_sizer); + + wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + _preset_check = new wxCheckBox (this, wxID_ANY, _("Use preset")); + table->Add (_preset_check, 0, wxALIGN_CENTER_VERTICAL); + _preset_choice = new wxChoice (this, wxID_ANY); + table->Add (_preset_choice); + + overall_sizer->Add (table, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); + overall_sizer->Add (new wxStaticLine (this, wxID_ANY), 0, wxEXPAND); + overall_sizer->Add (_editor); + + wxSizer* buttons = CreateSeparatedButtonSizer (wxOK); + if (buttons) { + overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); + } + + overall_sizer->Layout (); + overall_sizer->SetSizeHints (this); + + _preset_check->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&ContentColourConversionDialog::preset_check_clicked, this)); + _preset_choice->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&ContentColourConversionDialog::preset_choice_changed, this)); + + _editor->Changed.connect (boost::bind (&ContentColourConversionDialog::check_for_preset, this)); + + vector<PresetColourConversion> presets = Config::instance()->colour_conversions (); + for (vector<PresetColourConversion>::const_iterator i = presets.begin(); i != presets.end(); ++i) { + _preset_choice->Append (std_to_wx (i->name)); + } +} + +ColourConversion +ContentColourConversionDialog::get () const +{ + return _editor->get (); +} + +void +ContentColourConversionDialog::set (ColourConversion c) +{ + _setting = true; + _editor->set (c); + _setting = false; + + check_for_preset (); +} + +void +ContentColourConversionDialog::check_for_preset () +{ + if (_setting) { + return; + } + + optional<size_t> preset = _editor->get().preset (); + + _preset_check->SetValue (preset); + _preset_choice->Enable (preset); + _preset_choice->SetSelection (preset.get_value_or (-1)); +} + +void +ContentColourConversionDialog::preset_check_clicked () +{ + if (_preset_check->GetValue ()) { + _preset_choice->SetSelection (0); + preset_choice_changed (); + } else { + _preset_choice->SetSelection (-1); + _preset_choice->Enable (false); + } +} + +void +ContentColourConversionDialog::preset_choice_changed () +{ + vector<PresetColourConversion> presets = Config::instance()->colour_conversions (); + int const s = _preset_choice->GetSelection(); + if (s != -1) { + set (presets[s].conversion); + } +} + + diff --git a/src/wx/content_colour_conversion_dialog.h b/src/wx/content_colour_conversion_dialog.h new file mode 100644 index 000000000..e6069f117 --- /dev/null +++ b/src/wx/content_colour_conversion_dialog.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + + 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 <wx/wx.h> + +class ColourConversionEditor; + +class ContentColourConversionDialog : public wxDialog +{ +public: + ContentColourConversionDialog (wxWindow *); + + void set (ColourConversion); + ColourConversion get () const; + +private: + void check_for_preset (); + void preset_check_clicked (); + void preset_choice_changed (); + + wxCheckBox* _preset_check; + wxChoice* _preset_choice; + ColourConversionEditor* _editor; + bool _setting; +}; diff --git a/src/wx/content_menu.cc b/src/wx/content_menu.cc new file mode 100644 index 000000000..1a409fa6c --- /dev/null +++ b/src/wx/content_menu.cc @@ -0,0 +1,96 @@ +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + + 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 <wx/wx.h> +#include "lib/playlist.h" +#include "lib/film.h" +#include "content_menu.h" +#include "repeat_dialog.h" + +using std::cout; +using boost::shared_ptr; + +enum { + ID_repeat, + ID_remove +}; + +ContentMenu::ContentMenu (shared_ptr<Film> f, wxWindow* p) + : _menu (new wxMenu) + , _film (f) + , _parent (p) +{ + _menu->Append (ID_repeat, _("Repeat...")); + _menu->AppendSeparator (); + _menu->Append (ID_remove, _("Remove")); + + _parent->Bind (wxEVT_COMMAND_MENU_SELECTED, &ContentMenu::repeat, this, ID_repeat); + _parent->Bind (wxEVT_COMMAND_MENU_SELECTED, &ContentMenu::remove, this, ID_remove); +} + +ContentMenu::~ContentMenu () +{ + delete _menu; +} + +void +ContentMenu::popup (ContentList c, wxPoint p) +{ + _content = c; + _parent->PopupMenu (_menu, p); +} + +void +ContentMenu::repeat (wxCommandEvent &) +{ + if (_content.empty ()) { + return; + } + + RepeatDialog d (_parent); + d.ShowModal (); + + shared_ptr<const Film> film = _film.lock (); + if (!film) { + return; + } + + film->playlist()->repeat (_content, d.number ()); + d.Destroy (); + + _content.clear (); +} + +void +ContentMenu::remove (wxCommandEvent &) +{ + if (_content.empty ()) { + return; + } + + shared_ptr<const Film> film = _film.lock (); + if (!film) { + return; + } + + film->playlist()->remove (_content); + + _content.clear (); +} + diff --git a/src/wx/content_menu.h b/src/wx/content_menu.h new file mode 100644 index 000000000..127fbea1a --- /dev/null +++ b/src/wx/content_menu.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + + 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. + +*/ + +#ifndef DCPOMATIC_CONTENT_MENU_H +#define DCPOMATIC_CONTENT_MENU_H + +#include <wx/wx.h> +#include <boost/shared_ptr.hpp> +#include <boost/weak_ptr.hpp> +#include "lib/types.h" + +class Film; + +class ContentMenu +{ +public: + ContentMenu (boost::shared_ptr<Film>, wxWindow *); + ~ContentMenu (); + + void popup (ContentList, wxPoint); + +private: + void repeat (wxCommandEvent &); + void remove (wxCommandEvent &); + + wxMenu* _menu; + boost::weak_ptr<Film> _film; + wxWindow* _parent; + ContentList _content; +}; + +#endif diff --git a/src/wx/dci_metadata_dialog.cc b/src/wx/dci_metadata_dialog.cc new file mode 100644 index 000000000..e28ddd855 --- /dev/null +++ b/src/wx/dci_metadata_dialog.cc @@ -0,0 +1,106 @@ +/* + Copyright (C) 2012 Carl Hetherington <cth@carlh.net> + + 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 <wx/wx.h> +#include <wx/sizer.h> +#include <wx/spinctrl.h> +#include "lib/film.h" +#include "dci_metadata_dialog.h" +#include "wx_util.h" + +using boost::shared_ptr; + +DCIMetadataDialog::DCIMetadataDialog (wxWindow* parent, DCIMetadata dm) + : wxDialog (parent, wxID_ANY, _("DCI name"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) +{ + wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + table->AddGrowableCol (1, 1); + + add_label_to_sizer (table, this, _("Content version"), true); + _content_version = new wxSpinCtrl (this, wxID_ANY); + table->Add (_content_version, 1, wxEXPAND); + + add_label_to_sizer (table, this, _("Audio Language (e.g. EN)"), true); + _audio_language = new wxTextCtrl (this, wxID_ANY); + table->Add (_audio_language, 1, wxEXPAND); + + add_label_to_sizer (table, this, _("Subtitle Language (e.g. FR)"), true); + _subtitle_language = new wxTextCtrl (this, wxID_ANY); + table->Add (_subtitle_language, 1, wxEXPAND); + + add_label_to_sizer (table, this, _("Territory (e.g. UK)"), true); + _territory = new wxTextCtrl (this, wxID_ANY); + table->Add (_territory, 1, wxEXPAND); + + add_label_to_sizer (table, this, _("Rating (e.g. 15)"), true); + _rating = new wxTextCtrl (this, wxID_ANY); + table->Add (_rating, 1, wxEXPAND); + + add_label_to_sizer (table, this, _("Studio (e.g. TCF)"), true); + _studio = new wxTextCtrl (this, wxID_ANY); + table->Add (_studio, 1, wxEXPAND); + + add_label_to_sizer (table, this, _("Facility (e.g. DLA)"), true); + _facility = new wxTextCtrl (this, wxID_ANY); + table->Add (_facility, 1, wxEXPAND); + + add_label_to_sizer (table, this, _("Package Type (e.g. OV)"), true); + _package_type = new wxTextCtrl (this, wxID_ANY); + table->Add (_package_type, 1, wxEXPAND); + + _content_version->SetRange (1, 1024); + + _content_version->SetValue (dm.content_version); + _audio_language->SetValue (std_to_wx (dm.audio_language)); + _subtitle_language->SetValue (std_to_wx (dm.subtitle_language)); + _territory->SetValue (std_to_wx (dm.territory)); + _rating->SetValue (std_to_wx (dm.rating)); + _studio->SetValue (std_to_wx (dm.studio)); + _facility->SetValue (std_to_wx (dm.facility)); + _package_type->SetValue (std_to_wx (dm.package_type)); + + wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); + overall_sizer->Add (table, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); + + wxSizer* buttons = CreateSeparatedButtonSizer (wxOK); + if (buttons) { + overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); + } + + SetSizer (overall_sizer); + overall_sizer->Layout (); + overall_sizer->SetSizeHints (this); +} + +DCIMetadata +DCIMetadataDialog::dci_metadata () const +{ + DCIMetadata dm; + + dm.content_version = _content_version->GetValue (); + dm.audio_language = wx_to_std (_audio_language->GetValue ()); + dm.subtitle_language = wx_to_std (_subtitle_language->GetValue ()); + dm.territory = wx_to_std (_territory->GetValue ()); + dm.rating = wx_to_std (_rating->GetValue ()); + dm.studio = wx_to_std (_studio->GetValue ()); + dm.facility = wx_to_std (_facility->GetValue ()); + dm.package_type = wx_to_std (_package_type->GetValue ()); + + return dm; +} diff --git a/src/wx/dci_name_dialog.h b/src/wx/dci_metadata_dialog.h index 1fd5436b8..240d5535e 100644 --- a/src/wx/dci_name_dialog.h +++ b/src/wx/dci_metadata_dialog.h @@ -20,23 +20,20 @@ #include <wx/dialog.h> #include <wx/textctrl.h> #include <boost/shared_ptr.hpp> +#include "lib/dci_metadata.h" +class wxSpinCtrl; class Film; -class DCINameDialog : public wxDialog +class DCIMetadataDialog : public wxDialog { public: - DCINameDialog (wxWindow *, boost::shared_ptr<Film>); + DCIMetadataDialog (wxWindow *, DCIMetadata); + + DCIMetadata dci_metadata () const; private: - void audio_language_changed (wxCommandEvent &); - void subtitle_language_changed (wxCommandEvent &); - void territory_changed (wxCommandEvent &); - void rating_changed (wxCommandEvent &); - void studio_changed (wxCommandEvent &); - void facility_changed (wxCommandEvent &); - void package_type_changed (wxCommandEvent &); - + wxSpinCtrl* _content_version; wxTextCtrl* _audio_language; wxTextCtrl* _subtitle_language; wxTextCtrl* _territory; @@ -44,6 +41,4 @@ private: wxTextCtrl* _studio; wxTextCtrl* _facility; wxTextCtrl* _package_type; - - boost::shared_ptr<Film> _film; }; diff --git a/src/wx/dci_name_dialog.cc b/src/wx/dci_name_dialog.cc deleted file mode 100644 index 6927d6c9e..000000000 --- a/src/wx/dci_name_dialog.cc +++ /dev/null @@ -1,131 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington <cth@carlh.net> - - 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 <wx/sizer.h> -#include "dci_name_dialog.h" -#include "wx_util.h" -#include "film.h" - -using boost::shared_ptr; - -DCINameDialog::DCINameDialog (wxWindow* parent, shared_ptr<Film> film) - : wxDialog (parent, wxID_ANY, _("DCI name"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) - , _film (film) -{ - wxFlexGridSizer* table = new wxFlexGridSizer (2, 6, 6); - table->AddGrowableCol (1, 1); - - add_label_to_sizer (table, this, "Audio Language (e.g. EN)"); - _audio_language = new wxTextCtrl (this, wxID_ANY); - table->Add (_audio_language, 1, wxEXPAND); - - add_label_to_sizer (table, this, "Subtitle Language (e.g. FR)"); - _subtitle_language = new wxTextCtrl (this, wxID_ANY); - table->Add (_subtitle_language, 1, wxEXPAND); - - add_label_to_sizer (table, this, "Territory (e.g. UK)"); - _territory = new wxTextCtrl (this, wxID_ANY); - table->Add (_territory, 1, wxEXPAND); - - add_label_to_sizer (table, this, "Rating (e.g. 15)"); - _rating = new wxTextCtrl (this, wxID_ANY); - table->Add (_rating, 1, wxEXPAND); - - add_label_to_sizer (table, this, "Studio (e.g. TCF)"); - _studio = new wxTextCtrl (this, wxID_ANY); - table->Add (_studio, 1, wxEXPAND); - - add_label_to_sizer (table, this, "Facility (e.g. DLA)"); - _facility = new wxTextCtrl (this, wxID_ANY); - table->Add (_facility, 1, wxEXPAND); - - add_label_to_sizer (table, this, "Package Type (e.g. OV)"); - _package_type = new wxTextCtrl (this, wxID_ANY); - table->Add (_package_type, 1, wxEXPAND); - - _audio_language->SetValue (std_to_wx (_film->audio_language ())); - _subtitle_language->SetValue (std_to_wx (_film->subtitle_language ())); - _territory->SetValue (std_to_wx (_film->territory ())); - _rating->SetValue (std_to_wx (_film->rating ())); - _studio->SetValue (std_to_wx (_film->studio ())); - _facility->SetValue (std_to_wx (_film->facility ())); - _package_type->SetValue (std_to_wx (_film->package_type ())); - - _audio_language->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (DCINameDialog::audio_language_changed), 0, this); - _subtitle_language->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (DCINameDialog::subtitle_language_changed), 0, this); - _territory->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (DCINameDialog::territory_changed), 0, this); - _rating->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (DCINameDialog::rating_changed), 0, this); - _studio->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (DCINameDialog::studio_changed), 0, this); - _facility->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (DCINameDialog::facility_changed), 0, this); - _package_type->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (DCINameDialog::package_type_changed), 0, this); - - wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); - overall_sizer->Add (table, 1, wxEXPAND | wxALL, 6); - - wxSizer* buttons = CreateSeparatedButtonSizer (wxOK); - if (buttons) { - overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); - } - - SetSizer (overall_sizer); - overall_sizer->Layout (); - overall_sizer->SetSizeHints (this); -} - -void -DCINameDialog::audio_language_changed (wxCommandEvent &) -{ - _film->set_audio_language (wx_to_std (_audio_language->GetValue ())); -} - -void -DCINameDialog::subtitle_language_changed (wxCommandEvent &) -{ - _film->set_subtitle_language (wx_to_std (_subtitle_language->GetValue ())); -} - -void -DCINameDialog::territory_changed (wxCommandEvent &) -{ - _film->set_territory (wx_to_std (_territory->GetValue ())); -} - -void -DCINameDialog::rating_changed (wxCommandEvent &) -{ - _film->set_rating (wx_to_std (_rating->GetValue ())); -} - -void -DCINameDialog::studio_changed (wxCommandEvent &) -{ - _film->set_studio (wx_to_std (_studio->GetValue ())); -} - -void -DCINameDialog::facility_changed (wxCommandEvent &) -{ - _film->set_facility (wx_to_std (_facility->GetValue ())); -} - -void -DCINameDialog::package_type_changed (wxCommandEvent &) -{ - _film->set_package_type (wx_to_std (_package_type->GetValue ())); -} diff --git a/src/wx/dir_picker_ctrl.cc b/src/wx/dir_picker_ctrl.cc index cb811fc10..47a546a8d 100644 --- a/src/wx/dir_picker_ctrl.cc +++ b/src/wx/dir_picker_ctrl.cc @@ -19,6 +19,7 @@ #include <wx/wx.h> #include <wx/stdpaths.h> +#include <wx/filepicker.h> #include <boost/filesystem.hpp> #include "dir_picker_ctrl.h" #include "wx_util.h" @@ -39,7 +40,7 @@ DirPickerCtrl::DirPickerCtrl (wxWindow* parent) SetSizerAndFit (_sizer); - _browse->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (DirPickerCtrl::browse_clicked), 0, this); + _browse->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&DirPickerCtrl::browse_clicked, this)); } void @@ -50,12 +51,11 @@ DirPickerCtrl::SetPath (wxString p) if (_path == wxStandardPaths::Get().GetDocumentsDir()) { _folder->SetLabel (_("My Documents")); } else { -#if BOOST_FILESYSTEM_VERSION == 3 _folder->SetLabel (std_to_wx (filesystem::path (wx_to_std (_path)).leaf().string())); -#else - _folder->SetLabel (std_to_wx (filesystem::path (wx_to_std (_path)).leaf())); -#endif } + + wxCommandEvent ev (wxEVT_COMMAND_DIRPICKER_CHANGED, wxID_ANY); + GetEventHandler()->ProcessEvent (ev); } wxString @@ -65,10 +65,11 @@ DirPickerCtrl::GetPath () const } void -DirPickerCtrl::browse_clicked (wxCommandEvent &) +DirPickerCtrl::browse_clicked () { wxDirDialog* d = new wxDirDialog (this); - d->ShowModal (); - SetPath (d->GetPath ()); + if (d->ShowModal () == wxID_OK) { + SetPath (d->GetPath ()); + } d->Destroy (); } diff --git a/src/wx/dir_picker_ctrl.h b/src/wx/dir_picker_ctrl.h index df7b25f7a..97c0d217a 100644 --- a/src/wx/dir_picker_ctrl.h +++ b/src/wx/dir_picker_ctrl.h @@ -28,7 +28,7 @@ public: void SetPath (wxString); private: - void browse_clicked (wxCommandEvent &); + void browse_clicked (); wxWindow* _parent; wxStaticText* _folder; diff --git a/src/wx/editable_list.h b/src/wx/editable_list.h new file mode 100644 index 000000000..98e7d0bfd --- /dev/null +++ b/src/wx/editable_list.h @@ -0,0 +1,176 @@ +/* + Copyright (C) 2012 Carl Hetherington <cth@carlh.net> + + 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 <wx/wx.h> + +template<class T, class S> +class EditableList : public wxPanel +{ +public: + EditableList ( + wxWindow* parent, + std::vector<std::string> columns, + boost::function<std::vector<T> ()> get, + boost::function<void (std::vector<T>)> set, + boost::function<std::string (T, int)> column + ) + : wxPanel (parent) + , _get (get) + , _set (set) + , _columns (columns.size ()) + , _column (column) + { + wxBoxSizer* s = new wxBoxSizer (wxVERTICAL); + SetSizer (s); + + wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + table->AddGrowableCol (0, 1); + s->Add (table, 1, wxALL | wxEXPAND, 8); + + _list = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxSize (columns.size() * 200, 100), wxLC_REPORT | wxLC_SINGLE_SEL); + + for (size_t i = 0; i < columns.size(); ++i) { + wxListItem ip; + ip.SetId (i); + ip.SetText (std_to_wx (columns[i])); + ip.SetWidth (200); + _list->InsertColumn (i, ip); + } + + table->Add (_list, 1, wxEXPAND | wxALL); + + { + wxSizer* s = new wxBoxSizer (wxVERTICAL); + _add = new wxButton (this, wxID_ANY, _("Add...")); + s->Add (_add, 0, wxTOP | wxBOTTOM, 2); + _edit = new wxButton (this, wxID_ANY, _("Edit...")); + s->Add (_edit, 0, wxTOP | wxBOTTOM, 2); + _remove = new wxButton (this, wxID_ANY, _("Remove")); + s->Add (_remove, 0, wxTOP | wxBOTTOM, 2); + table->Add (s, 0); + } + + std::vector<T> current = _get (); + for (typename std::vector<T>::iterator i = current.begin (); i != current.end(); ++i) { + add_to_control (*i); + } + + _add->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&EditableList::add_clicked, this)); + _edit->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&EditableList::edit_clicked, this)); + _remove->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&EditableList::remove_clicked, this)); + + _list->Bind (wxEVT_COMMAND_LIST_ITEM_SELECTED, boost::bind (&EditableList::selection_changed, this)); + _list->Bind (wxEVT_COMMAND_LIST_ITEM_DESELECTED, boost::bind (&EditableList::selection_changed, this)); + _list->Bind (wxEVT_SIZE, boost::bind (&EditableList::resized, this, _1)); + selection_changed (); + + } + +private: + + void add_to_control (T item) + { + wxListItem list_item; + int const n = _list->GetItemCount (); + list_item.SetId (n); + _list->InsertItem (list_item); + + for (int i = 0; i < _columns; ++i) { + _list->SetItem (n, i, std_to_wx (_column (item, i))); + } + } + + void selection_changed () + { + int const i = _list->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + _edit->Enable (i >= 0); + _remove->Enable (i >= 0); + } + + void add_clicked () + { + T new_item; + S* dialog = new S (this); + dialog->set (new_item); + dialog->ShowModal (); + + add_to_control (dialog->get ()); + + std::vector<T> all = _get (); + all.push_back (dialog->get ()); + _set (all); + + dialog->Destroy (); + } + + void edit_clicked () + { + int item = _list->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (item == -1) { + return; + } + + std::vector<T> all = _get (); + assert (item >= 0 && item < int (all.size ())); + + S* dialog = new S (this); + dialog->set (all[item]); + dialog->ShowModal (); + all[item] = dialog->get (); + dialog->Destroy (); + + for (int i = 0; i < _columns; ++i) { + _list->SetItem (item, i, std_to_wx (_column (all[item], i))); + } + } + + void remove_clicked () + { + int i = _list->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (i == -1) { + return; + } + + _list->DeleteItem (i); + std::vector<T> all = _get (); + all.erase (all.begin() + i); + _set (all); + + selection_changed (); + } + + void resized (wxSizeEvent& ev) + { + int const w = GetSize().GetWidth() / _columns; + for (int i = 0; i < _columns; ++i) { + _list->SetColumnWidth (i, w); + } + ev.Skip (); + } + + boost::function <std::vector<T> ()> _get; + boost::function <void (std::vector<T>)> _set; + int _columns; + boost::function<std::string (T, int)> _column; + + wxButton* _add; + wxButton* _edit; + wxButton* _remove; + wxListCtrl* _list; +}; diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index 9326227a3..56b697375 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012 Carl Hetherington <cth@carlh.net> + Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net> 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 @@ -25,26 +25,33 @@ #include <iomanip> #include <wx/wx.h> #include <wx/notebook.h> +#include <wx/listctrl.h> #include <boost/thread.hpp> #include <boost/filesystem.hpp> #include <boost/lexical_cast.hpp> -#include "lib/format.h" #include "lib/film.h" #include "lib/transcode_job.h" #include "lib/exceptions.h" -#include "lib/ab_transcode_job.h" #include "lib/job_manager.h" #include "lib/filter.h" +#include "lib/ratio.h" #include "lib/config.h" -#include "lib/ffmpeg_decoder.h" -#include "lib/external_audio_decoder.h" -#include "filter_dialog.h" +#include "lib/still_image_content.h" +#include "lib/moving_image_content.h" +#include "lib/ffmpeg_content.h" +#include "lib/sndfile_content.h" +#include "lib/dcp_content_type.h" +#include "lib/sound_processor.h" +#include "lib/scaler.h" +#include "timecode.h" #include "wx_util.h" #include "film_editor.h" -#include "gain_calculator_dialog.h" -#include "sound_processor.h" -#include "dci_name_dialog.h" -#include "scaler.h" +#include "dci_metadata_dialog.h" +#include "timeline_dialog.h" +#include "timing_panel.h" +#include "subtitle_panel.h" +#include "audio_panel.h" +#include "video_panel.h" using std::string; using std::cout; @@ -54,474 +61,257 @@ using std::fixed; using std::setprecision; using std::list; using std::vector; +using std::max; using boost::shared_ptr; +using boost::weak_ptr; using boost::dynamic_pointer_cast; +using boost::lexical_cast; /** @param f Film to edit */ FilmEditor::FilmEditor (shared_ptr<Film> f, wxWindow* parent) : wxPanel (parent) - , _film (f) + , _menu (f, this) , _generally_sensitive (true) + , _timeline_dialog (0) { wxBoxSizer* s = new wxBoxSizer (wxVERTICAL); - SetSizer (s); - _notebook = new wxNotebook (this, wxID_ANY); - s->Add (_notebook, 1); - - make_film_panel (); - _notebook->AddPage (_film_panel, _("Film"), true); - make_video_panel (); - _notebook->AddPage (_video_panel, _("Video"), false); - make_audio_panel (); - _notebook->AddPage (_audio_panel, _("Audio"), false); - make_subtitle_panel (); - _notebook->AddPage (_subtitle_panel, _("Subtitles"), false); - - set_film (_film); + + _main_notebook = new wxNotebook (this, wxID_ANY); + s->Add (_main_notebook, 1); + + make_content_panel (); + _main_notebook->AddPage (_content_panel, _("Content"), true); + make_dcp_panel (); + _main_notebook->AddPage (_dcp_panel, _("DCP"), false); + + set_film (f); connect_to_widgets (); JobManager::instance()->ActiveJobsChanged.connect ( bind (&FilmEditor::active_jobs_changed, this, _1) ); - setup_visibility (); - setup_formats (); + SetSizerAndFit (s); } void -FilmEditor::make_film_panel () +FilmEditor::make_dcp_panel () { - _film_panel = new wxPanel (_notebook); - _film_sizer = new wxFlexGridSizer (2, 4, 4); - wxBoxSizer* pad = new wxBoxSizer (wxVERTICAL); - pad->Add (_film_sizer, 0, wxALL, 8); - _film_panel->SetSizer (pad); - - add_label_to_sizer (_film_sizer, _film_panel, "Name"); - _name = new wxTextCtrl (_film_panel, wxID_ANY); - _film_sizer->Add (_name, 1, wxEXPAND); - - add_label_to_sizer (_film_sizer, _film_panel, "DCP Name"); - _dcp_name = new wxStaticText (_film_panel, wxID_ANY, wxT ("")); - _film_sizer->Add (_dcp_name, 0, wxALIGN_CENTER_VERTICAL | wxSHRINK); - - _use_dci_name = new wxCheckBox (_film_panel, wxID_ANY, wxT ("Use DCI name")); - _film_sizer->Add (_use_dci_name, 1, wxEXPAND); - _edit_dci_button = new wxButton (_film_panel, wxID_ANY, wxT ("Details...")); - _film_sizer->Add (_edit_dci_button, 0); - - add_label_to_sizer (_film_sizer, _film_panel, "Content"); - _content = new wxFilePickerCtrl (_film_panel, wxID_ANY, wxT (""), wxT ("Select Content File"), wxT("*.*")); - _film_sizer->Add (_content, 1, wxEXPAND); - - _trust_content_header = new wxCheckBox (_film_panel, wxID_ANY, wxT ("Trust content's header")); - video_control (_trust_content_header); - _film_sizer->Add (_trust_content_header, 1); - _film_sizer->AddSpacer (0); - - add_label_to_sizer (_film_sizer, _film_panel, "Content Type"); - _dcp_content_type = new wxComboBox (_film_panel, wxID_ANY, wxT (""), wxDefaultPosition, wxDefaultSize, 0, 0, wxCB_READONLY); - _film_sizer->Add (_dcp_content_type); - - video_control (add_label_to_sizer (_film_sizer, _film_panel, "Frames Per Second")); - _frames_per_second = new wxStaticText (_film_panel, wxID_ANY, wxT ("")); - _film_sizer->Add (video_control (_frames_per_second), 1, wxALIGN_CENTER_VERTICAL); + _dcp_panel = new wxPanel (_main_notebook); + _dcp_sizer = new wxBoxSizer (wxVERTICAL); + _dcp_panel->SetSizer (_dcp_sizer); + + wxGridBagSizer* grid = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + _dcp_sizer->Add (grid, 0, wxEXPAND | wxALL, 8); + + int r = 0; - video_control (add_label_to_sizer (_film_sizer, _film_panel, "Original Size")); - _original_size = new wxStaticText (_film_panel, wxID_ANY, wxT ("")); - _film_sizer->Add (video_control (_original_size), 1, wxALIGN_CENTER_VERTICAL); + add_label_to_grid_bag_sizer (grid, _dcp_panel, _("Name"), true, wxGBPosition (r, 0)); + _name = new wxTextCtrl (_dcp_panel, wxID_ANY); + grid->Add (_name, wxGBPosition(r, 1), wxDefaultSpan, wxEXPAND | wxLEFT | wxRIGHT); + ++r; - video_control (add_label_to_sizer (_film_sizer, _film_panel, "Length")); - _length = new wxStaticText (_film_panel, wxID_ANY, wxT ("")); - _film_sizer->Add (video_control (_length), 1, wxALIGN_CENTER_VERTICAL); - + add_label_to_grid_bag_sizer (grid, _dcp_panel, _("DCP Name"), true, wxGBPosition (r, 0)); + _dcp_name = new wxStaticText (_dcp_panel, wxID_ANY, wxT ("")); + grid->Add (_dcp_name, wxGBPosition(r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); + ++r; + + int flags = wxALIGN_CENTER_VERTICAL; +#ifdef __WXOSX__ + flags |= wxALIGN_RIGHT; +#endif + + _use_dci_name = new wxCheckBox (_dcp_panel, wxID_ANY, _("Use DCI name")); + grid->Add (_use_dci_name, wxGBPosition (r, 0), wxDefaultSpan, flags); + _edit_dci_button = new wxButton (_dcp_panel, wxID_ANY, _("Details...")); + grid->Add (_edit_dci_button, wxGBPosition (r, 1), wxDefaultSpan); + ++r; + + add_label_to_grid_bag_sizer (grid, _dcp_panel, _("Container"), true, wxGBPosition (r, 0)); + _container = new wxChoice (_dcp_panel, wxID_ANY); + grid->Add (_container, wxGBPosition (r, 1), wxDefaultSpan, wxEXPAND); + ++r; + + add_label_to_grid_bag_sizer (grid, _dcp_panel, _("Content Type"), true, wxGBPosition (r, 0)); + _dcp_content_type = new wxChoice (_dcp_panel, wxID_ANY); + grid->Add (_dcp_content_type, wxGBPosition (r, 1)); + ++r; { - video_control (add_label_to_sizer (_film_sizer, _film_panel, "Trim frames")); + add_label_to_grid_bag_sizer (grid, _dcp_panel, _("Frame Rate"), true, wxGBPosition (r, 0)); wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); - video_control (add_label_to_sizer (s, _film_panel, "Start")); - _dcp_trim_start = new wxSpinCtrl (_film_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)); - s->Add (video_control (_dcp_trim_start)); - video_control (add_label_to_sizer (s, _film_panel, "End")); - _dcp_trim_end = new wxSpinCtrl (_film_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)); - s->Add (video_control (_dcp_trim_end)); - - _film_sizer->Add (s); + _frame_rate = new wxChoice (_dcp_panel, wxID_ANY); + s->Add (_frame_rate, 1, wxALIGN_CENTER_VERTICAL); + _best_frame_rate = new wxButton (_dcp_panel, wxID_ANY, _("Use best")); + s->Add (_best_frame_rate, 1, wxALIGN_CENTER_VERTICAL | wxEXPAND); + grid->Add (s, wxGBPosition (r, 1)); } + ++r; - _encrypted = new wxCheckBox (_film_panel, wxID_ANY, wxT ("Encrypted")); - _film_sizer->Add (_encrypted, 1); - _film_sizer->AddSpacer (0); + _encrypted = new wxCheckBox (_dcp_panel, wxID_ANY, wxT ("Encrypted")); + grid->Add (_encrypted, wxGBPosition (r, 0), wxGBSpan (1, 2)); + ++r; - _multiple_reels = new wxCheckBox (_film_panel, wxID_ANY, wxT ("Make multiple reels")); - _film_sizer->Add (_multiple_reels); + add_label_to_grid_bag_sizer (grid, _dcp_panel, _("Audio channels"), true, wxGBPosition (r, 0)); + _audio_channels = new wxSpinCtrl (_dcp_panel, wxID_ANY); + grid->Add (_audio_channels, wxGBPosition (r, 1)); + ++r; - { - wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); - _reel_size = new wxSpinCtrl (_film_panel, wxID_ANY); - s->Add (_reel_size); - add_label_to_sizer (s, _film_panel, "Gb each"); - _film_sizer->Add (s); - } + _three_d = new wxCheckBox (_dcp_panel, wxID_ANY, _("3D")); + grid->Add (_three_d, wxGBPosition (r, 0), wxGBSpan (1, 2)); + ++r; - _dcp_ab = new wxCheckBox (_film_panel, wxID_ANY, wxT ("A/B")); - video_control (_dcp_ab); - _film_sizer->Add (_dcp_ab, 1); - _film_sizer->AddSpacer (0); + add_label_to_grid_bag_sizer (grid, _dcp_panel, _("Resolution"), true, wxGBPosition (r, 0)); + _resolution = new wxChoice (_dcp_panel, wxID_ANY); + grid->Add (_resolution, wxGBPosition (r, 1)); + ++r; - /* STILL-only stuff */ { - still_control (add_label_to_sizer (_film_sizer, _film_panel, "Duration")); + add_label_to_grid_bag_sizer (grid, _dcp_panel, _("JPEG2000 bandwidth"), true, wxGBPosition (r, 0)); wxSizer* s = new wxBoxSizer (wxHORIZONTAL); - _still_duration = new wxSpinCtrl (_film_panel); - still_control (_still_duration); - s->Add (_still_duration, 1, wxEXPAND); - still_control (add_label_to_sizer (s, _film_panel, "s")); - _film_sizer->Add (s); - } - - vector<DCPContentType const *> const ct = DCPContentType::all (); - for (vector<DCPContentType const *>::const_iterator i = ct.begin(); i != ct.end(); ++i) { - _dcp_content_type->Append (std_to_wx ((*i)->pretty_name ())); - } - - _reel_size->SetRange(1, 1000); -} - -void -FilmEditor::connect_to_widgets () -{ - _name->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (FilmEditor::name_changed), 0, this); - _use_dci_name->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::use_dci_name_toggled), 0, this); - _edit_dci_button->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::edit_dci_button_clicked), 0, this); - _format->Connect (wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler (FilmEditor::format_changed), 0, this); - _content->Connect (wxID_ANY, wxEVT_COMMAND_FILEPICKER_CHANGED, wxCommandEventHandler (FilmEditor::content_changed), 0, this); - _trust_content_header->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::trust_content_header_changed), 0, this); - _left_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::left_crop_changed), 0, this); - _right_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::right_crop_changed), 0, this); - _top_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::top_crop_changed), 0, this); - _bottom_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::bottom_crop_changed), 0, this); - _filters_button->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::edit_filters_clicked), 0, this); - _scaler->Connect (wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler (FilmEditor::scaler_changed), 0, this); - _dcp_content_type->Connect (wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler (FilmEditor::dcp_content_type_changed), 0, this); - _dcp_ab->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::dcp_ab_toggled), 0, this); - _encrypted->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::encrypted_toggled), 0, this); - _still_duration->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::still_duration_changed), 0, this); - _dcp_trim_start->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::dcp_trim_start_changed), 0, this); - _dcp_trim_end->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::dcp_trim_end_changed), 0, this); - _multiple_reels->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::multiple_reels_toggled), 0, this); - _reel_size->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::reel_size_changed), 0, this); - _with_subtitles->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::with_subtitles_toggled), 0, this); - _subtitle_offset->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::subtitle_offset_changed), 0, this); - _subtitle_scale->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::subtitle_scale_changed), 0, this); - _colour_lut->Connect (wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler (FilmEditor::colour_lut_changed), 0, this); - _j2k_bandwidth->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::j2k_bandwidth_changed), 0, this); - _subtitle_stream->Connect (wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler (FilmEditor::subtitle_stream_changed), 0, this); - _audio_stream->Connect (wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler (FilmEditor::audio_stream_changed), 0, this); - _audio_gain->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::audio_gain_changed), 0, this); - _audio_gain_calculate_button->Connect ( - wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::audio_gain_calculate_button_clicked), 0, this - ); - _audio_delay->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::audio_delay_changed), 0, this); - _use_content_audio->Connect (wxID_ANY, wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler (FilmEditor::use_audio_changed), 0, this); - _use_external_audio->Connect (wxID_ANY, wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler (FilmEditor::use_audio_changed), 0, this); - for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) { - _external_audio[i]->Connect ( - wxID_ANY, wxEVT_COMMAND_FILEPICKER_CHANGED, wxCommandEventHandler (FilmEditor::external_audio_changed), 0, this - ); - } -} - -void -FilmEditor::make_video_panel () -{ - _video_panel = new wxPanel (_notebook); - _video_sizer = new wxFlexGridSizer (2, 4, 4); - wxBoxSizer* pad = new wxBoxSizer (wxVERTICAL); - pad->Add (_video_sizer, 0, wxALL, 8); - _video_panel->SetSizer (pad); - - add_label_to_sizer (_video_sizer, _video_panel, "Format"); - _format = new wxComboBox (_video_panel, wxID_ANY, wxT (""), wxDefaultPosition, wxDefaultSize, 0, 0, wxCB_READONLY); - _video_sizer->Add (_format); - - { - add_label_to_sizer (_video_sizer, _video_panel, "Crop"); - wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); - - add_label_to_sizer (s, _video_panel, "L"); - _left_crop = new wxSpinCtrl (_video_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)); - s->Add (_left_crop, 0); - add_label_to_sizer (s, _video_panel, "R"); - _right_crop = new wxSpinCtrl (_video_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)); - s->Add (_right_crop, 0); - add_label_to_sizer (s, _video_panel, "T"); - _top_crop = new wxSpinCtrl (_video_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)); - s->Add (_top_crop, 0); - add_label_to_sizer (s, _video_panel, "B"); - _bottom_crop = new wxSpinCtrl (_video_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)); - s->Add (_bottom_crop, 0); - - _video_sizer->Add (s); + _j2k_bandwidth = new wxSpinCtrl (_dcp_panel, wxID_ANY); + s->Add (_j2k_bandwidth, 1); + add_label_to_sizer (s, _dcp_panel, _("MBps"), false); + grid->Add (s, wxGBPosition (r, 1)); } + ++r; - /* VIDEO-only stuff */ - { - video_control (add_label_to_sizer (_video_sizer, _video_panel, "Filters")); - wxSizer* s = new wxBoxSizer (wxHORIZONTAL); - _filters = new wxStaticText (_video_panel, wxID_ANY, wxT ("None")); - video_control (_filters); - s->Add (_filters, 1, wxEXPAND | wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM | wxRIGHT, 6); - _filters_button = new wxButton (_video_panel, wxID_ANY, wxT ("Edit...")); - video_control (_filters_button); - s->Add (_filters_button, 0); - _video_sizer->Add (s, 1); - } + add_label_to_grid_bag_sizer (grid, _dcp_panel, _("Standard"), true, wxGBPosition (r, 0)); + _standard = new wxChoice (_dcp_panel, wxID_ANY); + grid->Add (_standard, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); + ++r; - video_control (add_label_to_sizer (_video_sizer, _video_panel, "Scaler")); - _scaler = new wxComboBox (_video_panel, wxID_ANY, wxT (""), wxDefaultPosition, wxDefaultSize, 0, 0, wxCB_READONLY); - _video_sizer->Add (video_control (_scaler), 1); + add_label_to_grid_bag_sizer (grid, _dcp_panel, _("Scaler"), true, wxGBPosition (r, 0)); + _scaler = new wxChoice (_dcp_panel, wxID_ANY); + grid->Add (_scaler, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); + ++r; vector<Scaler const *> const sc = Scaler::all (); for (vector<Scaler const *>::const_iterator i = sc.begin(); i != sc.end(); ++i) { _scaler->Append (std_to_wx ((*i)->name())); } - add_label_to_sizer (_video_sizer, _video_panel, "Colour look-up table"); - _colour_lut = new wxComboBox (_video_panel, wxID_ANY); - for (int i = 0; i < 2; ++i) { - _colour_lut->Append (std_to_wx (colour_lut_index_to_name (i))); - } - _colour_lut->SetSelection (0); - _video_sizer->Add (_colour_lut, 1, wxEXPAND); - - { - add_label_to_sizer (_video_sizer, _video_panel, "JPEG2000 bandwidth"); - wxSizer* s = new wxBoxSizer (wxHORIZONTAL); - _j2k_bandwidth = new wxSpinCtrl (_video_panel, wxID_ANY); - s->Add (_j2k_bandwidth, 1); - add_label_to_sizer (s, _video_panel, "MBps"); - _video_sizer->Add (s, 1); + vector<Ratio const *> const ratio = Ratio::all (); + for (vector<Ratio const *>::const_iterator i = ratio.begin(); i != ratio.end(); ++i) { + _container->Append (std_to_wx ((*i)->nickname ())); } - _left_crop->SetRange (0, 1024); - _top_crop->SetRange (0, 1024); - _right_crop->SetRange (0, 1024); - _bottom_crop->SetRange (0, 1024); - _still_duration->SetRange (1, 60 * 60); - _dcp_trim_start->SetRange (0, 100); - _dcp_trim_end->SetRange (0, 100); - _j2k_bandwidth->SetRange (50, 250); -} - -void -FilmEditor::make_audio_panel () -{ - _audio_panel = new wxPanel (_notebook); - _audio_sizer = new wxFlexGridSizer (2, 4, 4); - wxBoxSizer* pad = new wxBoxSizer (wxVERTICAL); - pad->Add (_audio_sizer, 0, wxALL, 8); - _audio_panel->SetSizer (pad); - - { - video_control (add_label_to_sizer (_audio_sizer, _audio_panel, "Audio Gain")); - wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); - _audio_gain = new wxSpinCtrl (_audio_panel); - s->Add (video_control (_audio_gain), 1); - video_control (add_label_to_sizer (s, _audio_panel, "dB")); - _audio_gain_calculate_button = new wxButton (_audio_panel, wxID_ANY, _("Calculate...")); - video_control (_audio_gain_calculate_button); - s->Add (_audio_gain_calculate_button, 1, wxEXPAND); - _audio_sizer->Add (s); + vector<DCPContentType const *> const ct = DCPContentType::all (); + for (vector<DCPContentType const *>::const_iterator i = ct.begin(); i != ct.end(); ++i) { + _dcp_content_type->Append (std_to_wx ((*i)->pretty_name ())); } - { - video_control (add_label_to_sizer (_audio_sizer, _audio_panel, "Audio Delay")); - wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); - _audio_delay = new wxSpinCtrl (_audio_panel); - s->Add (video_control (_audio_delay), 1); - video_control (add_label_to_sizer (s, _audio_panel, "ms")); - _audio_sizer->Add (s); + list<int> const dfr = Config::instance()->allowed_dcp_frame_rates (); + for (list<int>::const_iterator i = dfr.begin(); i != dfr.end(); ++i) { + _frame_rate->Append (std_to_wx (boost::lexical_cast<string> (*i))); } - { - _use_content_audio = new wxRadioButton (_audio_panel, wxID_ANY, _("Use content's audio"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP); - _audio_sizer->Add (video_control (_use_content_audio)); - wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); - _audio_stream = new wxComboBox (_audio_panel, wxID_ANY, wxT (""), wxDefaultPosition, wxDefaultSize, 0, 0, wxCB_READONLY); - s->Add (video_control (_audio_stream), 1); - _audio = new wxStaticText (_audio_panel, wxID_ANY, wxT ("")); - s->Add (video_control (_audio), 1, wxALIGN_CENTER_VERTICAL | wxLEFT, 8); - _audio_sizer->Add (s, 1, wxEXPAND); - } + _audio_channels->SetRange (0, MAX_AUDIO_CHANNELS); + _j2k_bandwidth->SetRange (1, 250); - _use_external_audio = new wxRadioButton (_audio_panel, wxID_ANY, _("Use external audio")); - _audio_sizer->Add (_use_external_audio); - _audio_sizer->AddSpacer (0); - - assert (MAX_AUDIO_CHANNELS == 6); - - char const * channels[] = { - "Left", - "Right", - "Centre", - "Lfe (sub)", - "Left surround", - "Right surround" - }; - - for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) { - add_label_to_sizer (_audio_sizer, _audio_panel, channels[i]); - _external_audio[i] = new wxFilePickerCtrl (_audio_panel, wxID_ANY, wxT (""), wxT ("Select Audio File"), wxT ("*.wav")); - _audio_sizer->Add (_external_audio[i], 1, wxEXPAND); - } + _resolution->Append (_("2K")); + _resolution->Append (_("4K")); - _audio_gain->SetRange (-60, 60); - _audio_delay->SetRange (-1000, 1000); + _standard->Append (_("SMPTE")); + _standard->Append (_("Interop")); } void -FilmEditor::make_subtitle_panel () +FilmEditor::connect_to_widgets () { - _subtitle_panel = new wxPanel (_notebook); - _subtitle_sizer = new wxFlexGridSizer (2, 4, 4); - wxBoxSizer* pad = new wxBoxSizer (wxVERTICAL); - pad->Add (_subtitle_sizer, 0, wxALL, 8); - _subtitle_panel->SetSizer (pad); - - _with_subtitles = new wxCheckBox (_subtitle_panel, wxID_ANY, wxT("With Subtitles")); - video_control (_with_subtitles); - _subtitle_sizer->Add (_with_subtitles, 1); - - _subtitle_stream = new wxComboBox (_subtitle_panel, wxID_ANY, wxT (""), wxDefaultPosition, wxDefaultSize, 0, 0, wxCB_READONLY); - _subtitle_sizer->Add (video_control (_subtitle_stream)); - - video_control (add_label_to_sizer (_subtitle_sizer, _subtitle_panel, "Subtitle Offset")); - _subtitle_offset = new wxSpinCtrl (_subtitle_panel); - _subtitle_sizer->Add (video_control (_subtitle_offset), 1); + _name->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&FilmEditor::name_changed, this)); + _use_dci_name->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&FilmEditor::use_dci_name_toggled, this)); + _edit_dci_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&FilmEditor::edit_dci_button_clicked, this)); + _container->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&FilmEditor::container_changed, this)); + _content->Bind (wxEVT_COMMAND_LIST_ITEM_SELECTED, boost::bind (&FilmEditor::content_selection_changed, this)); + _content->Bind (wxEVT_COMMAND_LIST_ITEM_DESELECTED, boost::bind (&FilmEditor::content_selection_changed, this)); + _content->Bind (wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, boost::bind (&FilmEditor::content_right_click, this, _1)); + _content_add_file->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&FilmEditor::content_add_file_clicked, this)); + _content_add_folder->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&FilmEditor::content_add_folder_clicked, this)); + _content_remove->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&FilmEditor::content_remove_clicked, this)); + _content_timeline->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&FilmEditor::content_timeline_clicked, this)); + _scaler->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&FilmEditor::scaler_changed, this)); + _dcp_content_type->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&FilmEditor::dcp_content_type_changed, this)); + _frame_rate->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&FilmEditor::frame_rate_changed, this)); + _best_frame_rate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&FilmEditor::best_frame_rate_clicked, this)); + _audio_channels->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&FilmEditor::audio_channels_changed, this)); + _j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&FilmEditor::j2k_bandwidth_changed, this)); + _resolution->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&FilmEditor::resolution_changed, this)); + _sequence_video->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&FilmEditor::sequence_video_changed, this)); + _three_d->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&FilmEditor::three_d_changed, this)); + _standard->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&FilmEditor::standard_changed, this)); +} + +void +FilmEditor::make_content_panel () +{ + _content_panel = new wxPanel (_main_notebook); + _content_sizer = new wxBoxSizer (wxVERTICAL); + _content_panel->SetSizer (_content_sizer); { - video_control (add_label_to_sizer (_subtitle_sizer, _subtitle_panel, "Subtitle Scale")); wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); - _subtitle_scale = new wxSpinCtrl (_subtitle_panel); - s->Add (video_control (_subtitle_scale)); - video_control (add_label_to_sizer (s, _subtitle_panel, "%")); - _subtitle_sizer->Add (s); - } - - _subtitle_offset->SetRange (-1024, 1024); - _subtitle_scale->SetRange (1, 1000); -} - -/** Called when the left crop widget has been changed */ -void -FilmEditor::left_crop_changed (wxCommandEvent &) -{ - if (!_film) { - return; - } - - _film->set_left_crop (_left_crop->GetValue ()); -} - -/** Called when the right crop widget has been changed */ -void -FilmEditor::right_crop_changed (wxCommandEvent &) -{ - if (!_film) { - return; - } - - _film->set_right_crop (_right_crop->GetValue ()); -} - -/** Called when the top crop widget has been changed */ -void -FilmEditor::top_crop_changed (wxCommandEvent &) -{ - if (!_film) { - return; - } + + _content = new wxListCtrl (_content_panel, wxID_ANY, wxDefaultPosition, wxSize (320, 160), wxLC_REPORT | wxLC_NO_HEADER | wxLC_SINGLE_SEL); + s->Add (_content, 1, wxEXPAND | wxTOP | wxBOTTOM, 6); - _film->set_top_crop (_top_crop->GetValue ()); -} + _content->InsertColumn (0, wxT("")); + _content->SetColumnWidth (0, 512); -/** Called when the bottom crop value has been changed */ -void -FilmEditor::bottom_crop_changed (wxCommandEvent &) -{ - if (!_film) { - return; - } + wxBoxSizer* b = new wxBoxSizer (wxVERTICAL); + _content_add_file = new wxButton (_content_panel, wxID_ANY, _("Add file(s)...")); + b->Add (_content_add_file, 1, wxEXPAND | wxLEFT | wxRIGHT); + _content_add_folder = new wxButton (_content_panel, wxID_ANY, _("Add folder...")); + b->Add (_content_add_folder, 1, wxEXPAND | wxLEFT | wxRIGHT); + _content_remove = new wxButton (_content_panel, wxID_ANY, _("Remove")); + b->Add (_content_remove, 1, wxEXPAND | wxLEFT | wxRIGHT); + _content_timeline = new wxButton (_content_panel, wxID_ANY, _("Timeline...")); + b->Add (_content_timeline, 1, wxEXPAND | wxLEFT | wxRIGHT); - _film->set_bottom_crop (_bottom_crop->GetValue ()); -} + s->Add (b, 0, wxALL, 4); -/** Called when the content filename has been changed */ -void -FilmEditor::content_changed (wxCommandEvent &) -{ - if (!_film) { - return; + _content_sizer->Add (s, 0.75, wxEXPAND | wxALL, 6); } - try { - _film->set_content (wx_to_std (_content->GetPath ())); - } catch (std::exception& e) { - _content->SetPath (std_to_wx (_film->directory ())); - error_dialog (this, String::compose ("Could not set content: %1", e.what ())); - } -} + _sequence_video = new wxCheckBox (_content_panel, wxID_ANY, _("Keep video in sequence")); + _content_sizer->Add (_sequence_video); -void -FilmEditor::trust_content_header_changed (wxCommandEvent &) -{ - if (!_film) { - return; - } + _content_notebook = new wxNotebook (_content_panel, wxID_ANY); + _content_sizer->Add (_content_notebook, 1, wxEXPAND | wxTOP, 6); - _film->set_trust_content_header (_trust_content_header->GetValue ()); -} - -void -FilmEditor::multiple_reels_toggled (wxCommandEvent &) -{ - if (!_film) { - return; - } - - if (_multiple_reels->GetValue()) { - _film->set_reel_size (_reel_size->GetValue() * 1e9); - } else { - _film->unset_reel_size (); - } - - setup_reel_control_sensitivity (); + _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); } +/** Called when the name widget has been changed */ void -FilmEditor::reel_size_changed (wxCommandEvent &) +FilmEditor::name_changed () { if (!_film) { return; } - _film->set_reel_size (static_cast<uint64_t> (_reel_size->GetValue()) * 1e9); + _film->set_name (string (_name->GetValue().mb_str())); } -/** Called when the DCP A/B switch has been toggled */ void -FilmEditor::dcp_ab_toggled (wxCommandEvent &) +FilmEditor::j2k_bandwidth_changed () { if (!_film) { return; } - _film->set_dcp_ab (_dcp_ab->GetValue ()); + _film->set_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1e6); } void -FilmEditor::encrypted_toggled (wxCommandEvent &) +FilmEditor::encrypted_toggled () { if (!_film) { return; @@ -532,55 +322,48 @@ FilmEditor::encrypted_toggled (wxCommandEvent &) /** Called when the name widget has been changed */ void -FilmEditor::name_changed (wxCommandEvent &) +FilmEditor::frame_rate_changed () { if (!_film) { return; } - _film->set_name (string (_name->GetValue().mb_str())); + _film->set_video_frame_rate ( + boost::lexical_cast<int> ( + wx_to_std (_frame_rate->GetString (_frame_rate->GetSelection ())) + ) + ); } void -FilmEditor::subtitle_offset_changed (wxCommandEvent &) +FilmEditor::audio_channels_changed () { if (!_film) { return; } - _film->set_subtitle_offset (_subtitle_offset->GetValue ()); + _film->set_audio_channels (_audio_channels->GetValue ()); } void -FilmEditor::subtitle_scale_changed (wxCommandEvent &) +FilmEditor::resolution_changed () { if (!_film) { return; } - _film->set_subtitle_scale (_subtitle_scale->GetValue() / 100.0); -} - -void -FilmEditor::colour_lut_changed (wxCommandEvent &) -{ - if (!_film) { - return; - } - - _film->set_colour_lut (_colour_lut->GetSelection ()); + _film->set_resolution (_resolution->GetSelection() == 0 ? RESOLUTION_2K : RESOLUTION_4K); } void -FilmEditor::j2k_bandwidth_changed (wxCommandEvent &) +FilmEditor::standard_changed () { if (!_film) { return; } - - _film->set_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1e6); -} + _film->set_interop (_standard->GetSelection() == 1); +} /** Called when the metadata stored in the Film object has changed; * so that we can update the GUI. @@ -596,201 +379,151 @@ FilmEditor::film_changed (Film::Property p) } stringstream s; + + for (list<FilmEditorPanel*>::iterator i = _panels.begin(); i != _panels.end(); ++i) { + (*i)->film_changed (p); + } switch (p) { case Film::NONE: break; case Film::CONTENT: - checked_set (_content, _film->content ()); - setup_visibility (); - setup_formats (); - setup_subtitle_control_sensitivity (); - setup_streams (); + setup_content (); break; - case Film::TRUST_CONTENT_HEADER: - checked_set (_trust_content_header, _film->trust_content_header ()); + case Film::CONTAINER: + setup_container (); break; - case Film::SUBTITLE_STREAMS: - setup_subtitle_control_sensitivity (); - setup_streams (); - break; - case Film::CONTENT_AUDIO_STREAMS: - setup_streams (); - break; - case Film::FORMAT: - { - int n = 0; - vector<Format const *>::iterator i = _formats.begin (); - while (i != _formats.end() && *i != _film->format ()) { - ++i; - ++n; - } - if (i == _formats.end()) { - checked_set (_format, -1); - } else { - checked_set (_format, n); - } - _dcp_name->SetLabel (std_to_wx (_film->dcp_name ())); - break; - } - case Film::CROP: - checked_set (_left_crop, _film->crop().left); - checked_set (_right_crop, _film->crop().right); - checked_set (_top_crop, _film->crop().top); - checked_set (_bottom_crop, _film->crop().bottom); - break; - case Film::FILTERS: - { - pair<string, string> p = Filter::ffmpeg_strings (_film->filters ()); - if (p.first.empty () && p.second.empty ()) { - _filters->SetLabel (_("None")); - } else { - string const b = p.first + " " + p.second; - _filters->SetLabel (std_to_wx (b)); - } - _film_sizer->Layout (); - break; - } case Film::NAME: checked_set (_name, _film->name()); - _film->set_dci_date_today (); - _dcp_name->SetLabel (std_to_wx (_film->dcp_name ())); - break; - case Film::FRAMES_PER_SECOND: - s << fixed << setprecision(2) << _film->frames_per_second(); - _frames_per_second->SetLabel (std_to_wx (s.str ())); + setup_dcp_name (); break; - case Film::SIZE: - if (_film->size().width == 0 && _film->size().height == 0) { - _original_size->SetLabel (wxT ("")); - } else { - s << _film->size().width << " x " << _film->size().height; - _original_size->SetLabel (std_to_wx (s.str ())); - } - break; - case Film::LENGTH: - if (_film->frames_per_second() > 0 && _film->length()) { - s << _film->length().get() << " frames; " << seconds_to_hms (_film->length().get() / _film->frames_per_second()); - } else if (_film->length()) { - s << _film->length().get() << " frames"; - } - _length->SetLabel (std_to_wx (s.str ())); - if (_film->length()) { - _dcp_trim_start->SetRange (0, _film->length().get()); - _dcp_trim_end->SetRange (0, _film->length().get()); - } + case Film::WITH_SUBTITLES: + setup_dcp_name (); break; case Film::DCP_CONTENT_TYPE: checked_set (_dcp_content_type, DCPContentType::as_index (_film->dcp_content_type ())); - _dcp_name->SetLabel (std_to_wx (_film->dcp_name ())); - break; - case Film::DCP_AB: - checked_set (_dcp_ab, _film->dcp_ab ()); + setup_dcp_name (); break; case Film::SCALER: checked_set (_scaler, Scaler::as_index (_film->scaler ())); break; - case Film::DCP_TRIM_START: - checked_set (_dcp_trim_start, _film->dcp_trim_start()); - break; - case Film::DCP_TRIM_END: - checked_set (_dcp_trim_end, _film->dcp_trim_end()); - break; - case Film::REEL_SIZE: - if (_film->reel_size()) { - checked_set (_multiple_reels, true); - checked_set (_reel_size, _film->reel_size().get() / 1e9); - } else { - checked_set (_multiple_reels, false); - } - setup_reel_control_sensitivity (); - break; - case Film::AUDIO_GAIN: - checked_set (_audio_gain, _film->audio_gain ()); - break; - case Film::AUDIO_DELAY: - checked_set (_audio_delay, _film->audio_delay ()); - break; - case Film::STILL_DURATION: - checked_set (_still_duration, _film->still_duration ()); - break; - case Film::WITH_SUBTITLES: - checked_set (_with_subtitles, _film->with_subtitles ()); - setup_subtitle_control_sensitivity (); - _dcp_name->SetLabel (std_to_wx (_film->dcp_name ())); - break; - case Film::SUBTITLE_OFFSET: - checked_set (_subtitle_offset, _film->subtitle_offset ()); - break; - case Film::SUBTITLE_SCALE: - checked_set (_subtitle_scale, _film->subtitle_scale() * 100); - break; case Film::ENCRYPTED: checked_set (_encrypted, _film->encrypted ()); break; - case Film::COLOUR_LUT: - checked_set (_colour_lut, _film->colour_lut ()); + case Film::RESOLUTION: + checked_set (_resolution, _film->resolution() == RESOLUTION_2K ? 0 : 1); + setup_dcp_name (); break; case Film::J2K_BANDWIDTH: checked_set (_j2k_bandwidth, double (_film->j2k_bandwidth()) / 1e6); break; case Film::USE_DCI_NAME: checked_set (_use_dci_name, _film->use_dci_name ()); - _dcp_name->SetLabel (std_to_wx (_film->dcp_name ())); + setup_dcp_name (); break; case Film::DCI_METADATA: - _dcp_name->SetLabel (std_to_wx (_film->dcp_name ())); + setup_dcp_name (); break; - case Film::CONTENT_AUDIO_STREAM: - if (_film->content_audio_stream()) { - checked_set (_audio_stream, _film->content_audio_stream()->to_string()); + case Film::VIDEO_FRAME_RATE: + { + bool done = false; + for (unsigned int i = 0; i < _frame_rate->GetCount(); ++i) { + if (wx_to_std (_frame_rate->GetString(i)) == boost::lexical_cast<string> (_film->video_frame_rate())) { + checked_set (_frame_rate, i); + done = true; + break; + } + } + + if (!done) { + checked_set (_frame_rate, -1); } - _dcp_name->SetLabel (std_to_wx (_film->dcp_name ())); - setup_audio_details (); - setup_audio_control_sensitivity (); + + _best_frame_rate->Enable (_film->best_video_frame_rate () != _film->video_frame_rate ()); break; - case Film::USE_CONTENT_AUDIO: - checked_set (_use_content_audio, _film->use_content_audio()); - checked_set (_use_external_audio, !_film->use_content_audio()); - _dcp_name->SetLabel (std_to_wx (_film->dcp_name ())); - setup_audio_details (); - setup_audio_control_sensitivity (); + } + case Film::AUDIO_CHANNELS: + _audio_channels->SetValue (_film->audio_channels ()); + setup_dcp_name (); break; - case Film::SUBTITLE_STREAM: - if (_film->subtitle_stream()) { - checked_set (_subtitle_stream, _film->subtitle_stream()->to_string()); - } + case Film::SEQUENCE_VIDEO: + checked_set (_sequence_video, _film->sequence_video ()); break; - case Film::EXTERNAL_AUDIO: - { - vector<string> a = _film->external_audio (); - for (size_t i = 0; i < a.size() && i < MAX_AUDIO_CHANNELS; ++i) { - checked_set (_external_audio[i], a[i]); - } - setup_audio_details (); + case Film::THREE_D: + checked_set (_three_d, _film->three_d ()); + setup_dcp_name (); + break; + case Film::INTEROP: + checked_set (_standard, _film->interop() ? 1 : 0); break; } +} + +void +FilmEditor::film_content_changed (weak_ptr<Content> weak_content, int property) +{ + ensure_ui_thread (); + + if (!_film) { + /* We call this method ourselves (as well as using it as a signal handler) + so _film can be 0. + */ + return; + } + + shared_ptr<Content> content = weak_content.lock (); + if (!content || content != selected_content ()) { + return; + } + + for (list<FilmEditorPanel*>::iterator i = _panels.begin(); i != _panels.end(); ++i) { + (*i)->film_content_changed (content, property); + } + + if (property == FFmpegContentProperty::AUDIO_STREAM) { + setup_dcp_name (); } } -/** Called when the format widget has been changed */ void -FilmEditor::format_changed (wxCommandEvent &) +FilmEditor::setup_container () +{ + int n = 0; + vector<Ratio const *> ratios = Ratio::all (); + vector<Ratio const *>::iterator i = ratios.begin (); + while (i != ratios.end() && *i != _film->container ()) { + ++i; + ++n; + } + + if (i == ratios.end()) { + checked_set (_container, -1); + } else { + checked_set (_container, n); + } + + setup_dcp_name (); +} + +/** Called when the container widget has been changed */ +void +FilmEditor::container_changed () { if (!_film) { return; } - int const n = _format->GetSelection (); + int const n = _container->GetSelection (); if (n >= 0) { - assert (n < int (_formats.size())); - _film->set_format (_formats[n]); + vector<Ratio const *> ratios = Ratio::all (); + assert (n < int (ratios.size())); + _film->set_container (ratios[n]); } } /** Called when the DCP content type widget has been changed */ void -FilmEditor::dcp_content_type_changed (wxCommandEvent &) +FilmEditor::dcp_content_type_changed () { if (!_film) { return; @@ -806,12 +539,17 @@ FilmEditor::dcp_content_type_changed (wxCommandEvent &) void FilmEditor::set_film (shared_ptr<Film> f) { - _film = f; + set_general_sensitivity (f != 0); - set_things_sensitive (_film != 0); + if (_film == f) { + return; + } + + _film = f; if (_film) { _film->Changed.connect (bind (&FilmEditor::film_changed, this, _1)); + _film->ContentChanged.connect (bind (&FilmEditor::film_content_changed, this, _1, _2)); } if (_film) { @@ -819,93 +557,67 @@ FilmEditor::set_film (shared_ptr<Film> f) } else { FileChanged (""); } - + film_changed (Film::NAME); film_changed (Film::USE_DCI_NAME); film_changed (Film::CONTENT); - film_changed (Film::TRUST_CONTENT_HEADER); film_changed (Film::DCP_CONTENT_TYPE); - film_changed (Film::FORMAT); - film_changed (Film::CROP); - film_changed (Film::FILTERS); + film_changed (Film::CONTAINER); + film_changed (Film::RESOLUTION); film_changed (Film::SCALER); - film_changed (Film::DCP_TRIM_START); - film_changed (Film::DCP_TRIM_END); - film_changed (Film::REEL_SIZE); - film_changed (Film::DCP_AB); - film_changed (Film::CONTENT_AUDIO_STREAM); - film_changed (Film::EXTERNAL_AUDIO); - film_changed (Film::USE_CONTENT_AUDIO); - film_changed (Film::AUDIO_GAIN); - film_changed (Film::AUDIO_DELAY); - film_changed (Film::STILL_DURATION); film_changed (Film::WITH_SUBTITLES); - film_changed (Film::SUBTITLE_OFFSET); - film_changed (Film::SUBTITLE_SCALE); film_changed (Film::ENCRYPTED); - film_changed (Film::COLOUR_LUT); film_changed (Film::J2K_BANDWIDTH); film_changed (Film::DCI_METADATA); - film_changed (Film::SIZE); - film_changed (Film::LENGTH); - film_changed (Film::CONTENT_AUDIO_STREAMS); - film_changed (Film::SUBTITLE_STREAMS); - film_changed (Film::FRAMES_PER_SECOND); + film_changed (Film::VIDEO_FRAME_RATE); + film_changed (Film::AUDIO_CHANNELS); + film_changed (Film::SEQUENCE_VIDEO); + film_changed (Film::THREE_D); + film_changed (Film::INTEROP); + + if (!_film->content().empty ()) { + set_selection (_film->content().front ()); + } + + content_selection_changed (); } -/** Updates the sensitivity of lots of widgets to a given value. - * @param s true to make sensitive, false to make insensitive. - */ void -FilmEditor::set_things_sensitive (bool s) +FilmEditor::set_general_sensitivity (bool s) { _generally_sensitive = s; - + + /* Stuff in the Content / DCP tabs */ _name->Enable (s); _use_dci_name->Enable (s); _edit_dci_button->Enable (s); - _format->Enable (s); _content->Enable (s); - _trust_content_header->Enable (s); - _left_crop->Enable (s); - _right_crop->Enable (s); - _top_crop->Enable (s); - _bottom_crop->Enable (s); - _filters_button->Enable (s); - _scaler->Enable (s); - _audio_stream->Enable (s); + _content_add_file->Enable (s); + _content_add_folder->Enable (s); + _content_remove->Enable (s); + _content_timeline->Enable (s); _dcp_content_type->Enable (s); - _dcp_trim_start->Enable (s); - _dcp_trim_end->Enable (s); - _multiple_reels->Enable (s); - _reel_size->Enable (s); - _dcp_ab->Enable (s); _encrypted->Enable (s); - _colour_lut->Enable (s); + _frame_rate->Enable (s); + _audio_channels->Enable (s); _j2k_bandwidth->Enable (s); - _audio_gain->Enable (s); - _audio_gain_calculate_button->Enable (s); - _audio_delay->Enable (s); - _still_duration->Enable (s); - - setup_subtitle_control_sensitivity (); - setup_audio_control_sensitivity (); - setup_reel_control_sensitivity (); -} + _container->Enable (s); + _best_frame_rate->Enable (s && _film && _film->best_video_frame_rate () != _film->video_frame_rate ()); + _sequence_video->Enable (s); + _resolution->Enable (s); + _scaler->Enable (s); + _three_d->Enable (s); + _standard->Enable (s); -/** Called when the `Edit filters' button has been clicked */ -void -FilmEditor::edit_filters_clicked (wxCommandEvent &) -{ - FilterDialog* d = new FilterDialog (this, _film->filters()); - d->ActiveChanged.connect (bind (&Film::set_filters, _film, _1)); - d->ShowModal (); - d->Destroy (); + /* Set the panels in the content notebook */ + for (list<FilmEditorPanel*>::iterator i = _panels.begin(); i != _panels.end(); ++i) { + (*i)->Enable (s); + } } /** Called when the scaler widget has been changed */ void -FilmEditor::scaler_changed (wxCommandEvent &) +FilmEditor::scaler_changed () { if (!_film) { return; @@ -918,322 +630,289 @@ FilmEditor::scaler_changed (wxCommandEvent &) } void -FilmEditor::audio_gain_changed (wxCommandEvent &) +FilmEditor::use_dci_name_toggled () { if (!_film) { return; } - _film->set_audio_gain (_audio_gain->GetValue ()); + _film->set_use_dci_name (_use_dci_name->GetValue ()); } void -FilmEditor::audio_delay_changed (wxCommandEvent &) +FilmEditor::edit_dci_button_clicked () { if (!_film) { return; } - _film->set_audio_delay (_audio_delay->GetValue ()); -} - -wxControl * -FilmEditor::video_control (wxControl* c) -{ - _video_controls.push_back (c); - return c; -} - -wxControl * -FilmEditor::still_control (wxControl* c) -{ - _still_controls.push_back (c); - return c; + DCIMetadataDialog* d = new DCIMetadataDialog (this, _film->dci_metadata ()); + d->ShowModal (); + _film->set_dci_metadata (d->dci_metadata ()); + d->Destroy (); } void -FilmEditor::setup_visibility () +FilmEditor::active_jobs_changed (bool a) { - ContentType c = VIDEO; - - if (_film) { - c = _film->content_type (); - } - - for (list<wxControl*>::iterator i = _video_controls.begin(); i != _video_controls.end(); ++i) { - (*i)->Show (c == VIDEO); - } - - for (list<wxControl*>::iterator i = _still_controls.begin(); i != _still_controls.end(); ++i) { - (*i)->Show (c == STILL); - } - - _notebook->InvalidateBestSize (); - - _film_sizer->Layout (); - _film_sizer->SetSizeHints (_film_panel); - _video_sizer->Layout (); - _video_sizer->SetSizeHints (_video_panel); - _audio_sizer->Layout (); - _audio_sizer->SetSizeHints (_audio_panel); - _subtitle_sizer->Layout (); - _subtitle_sizer->SetSizeHints (_subtitle_panel); - - _notebook->Fit (); - Fit (); + set_general_sensitivity (!a); } void -FilmEditor::still_duration_changed (wxCommandEvent &) +FilmEditor::setup_dcp_name () { - if (!_film) { - return; + string s = _film->dcp_name (true); + if (s.length() > 28) { + _dcp_name->SetLabel (std_to_wx (s.substr (0, 28)) + N_("...")); + _dcp_name->SetToolTip (std_to_wx (s)); + } else { + _dcp_name->SetLabel (std_to_wx (s)); } - - _film->set_still_duration (_still_duration->GetValue ()); } void -FilmEditor::dcp_trim_start_changed (wxCommandEvent &) +FilmEditor::best_frame_rate_clicked () { if (!_film) { return; } - - _film->set_dcp_trim_start (_dcp_trim_start->GetValue ()); + + _film->set_video_frame_rate (_film->best_video_frame_rate ()); } void -FilmEditor::dcp_trim_end_changed (wxCommandEvent &) +FilmEditor::setup_content () { - if (!_film) { - return; + 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 (); + for (ContentList::iterator i = content.begin(); i != content.end(); ++i) { + int const t = _content->GetItemCount (); + _content->InsertItem (t, std_to_wx ((*i)->summary ())); + if ((*i)->summary() == selected_summary) { + _content->SetItemState (t, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); + } } - _film->set_dcp_trim_end (_dcp_trim_end->GetValue ()); + 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 -FilmEditor::audio_gain_calculate_button_clicked (wxCommandEvent &) +FilmEditor::content_add_file_clicked () { - GainCalculatorDialog* d = new GainCalculatorDialog (this); - d->ShowModal (); + wxFileDialog* d = new wxFileDialog (this, _("Choose a file or files"), wxT (""), wxT (""), wxT ("*.*"), wxFD_MULTIPLE); + int const r = d->ShowModal (); + d->Destroy (); - if (d->wanted_fader() == 0 || d->actual_fader() == 0) { - d->Destroy (); + if (r != wxID_OK) { return; } - - _audio_gain->SetValue ( - Config::instance()->sound_processor()->db_for_fader_change ( - d->wanted_fader (), - d->actual_fader () - ) - ); - /* This appears to be necessary, as the change is not signalled, - I think. - */ - wxCommandEvent dummy; - audio_gain_changed (dummy); - - d->Destroy (); -} + wxArrayString paths; + d->GetPaths (paths); -void -FilmEditor::setup_formats () -{ - ContentType c = VIDEO; + /* XXX: check for lots of files here and do something */ - if (_film) { - c = _film->content_type (); - } - - _formats.clear (); - - vector<Format const *> fmt = Format::all (); - for (vector<Format const *>::iterator i = fmt.begin(); i != fmt.end(); ++i) { - if (c == VIDEO && dynamic_cast<FixedFormat const *> (*i)) { - _formats.push_back (*i); - } else if (c == STILL && dynamic_cast<VariableFormat const *> (*i)) { - _formats.push_back (*i); + for (unsigned int i = 0; i < paths.GetCount(); ++i) { + boost::filesystem::path p (wx_to_std (paths[i])); + + shared_ptr<Content> c; + + if (valid_image_file (p)) { + c.reset (new StillImageContent (_film, p)); + } else if (SndfileContent::valid_file (p)) { + c.reset (new SndfileContent (_film, p)); + } else { + c.reset (new FFmpegContent (_film, p)); } - } - _format->Clear (); - for (vector<Format const *>::iterator i = _formats.begin(); i != _formats.end(); ++i) { - _format->Append (std_to_wx ((*i)->name ())); + _film->examine_and_add_content (c); } - - _film_sizer->Layout (); } void -FilmEditor::with_subtitles_toggled (wxCommandEvent &) +FilmEditor::content_add_folder_clicked () { - if (!_film) { + wxDirDialog* d = new wxDirDialog (this, _("Choose a folder"), wxT (""), wxDD_DIR_MUST_EXIST); + int const r = d->ShowModal (); + d->Destroy (); + + if (r != wxID_OK) { return; } - _film->set_with_subtitles (_with_subtitles->GetValue ()); + _film->examine_and_add_content ( + shared_ptr<MovingImageContent> ( + new MovingImageContent (_film, boost::filesystem::path (wx_to_std (d->GetPath ()))) + ) + ); } void -FilmEditor::setup_subtitle_control_sensitivity () +FilmEditor::content_remove_clicked () { - bool h = false; - if (_generally_sensitive && _film) { - h = !_film->subtitle_streams().empty(); + shared_ptr<Content> c = selected_content (); + if (c) { + _film->remove_content (c); } - - _with_subtitles->Enable (h); - bool j = false; - if (_film) { - j = _film->with_subtitles (); - } - - _subtitle_stream->Enable (j); - _subtitle_offset->Enable (j); - _subtitle_scale->Enable (j); + content_selection_changed (); } void -FilmEditor::setup_audio_control_sensitivity () +FilmEditor::content_selection_changed () { - _use_content_audio->Enable (_generally_sensitive); - _use_external_audio->Enable (_generally_sensitive); - - bool const source = _generally_sensitive && _use_content_audio->GetValue(); - bool const external = _generally_sensitive && _use_external_audio->GetValue(); + setup_content_sensitivity (); + shared_ptr<Content> s = selected_content (); - _audio_stream->Enable (source); - for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) { - _external_audio[i]->Enable (external); - } + /* All other sensitivity in content panels should be triggered by + one of these. + */ + film_content_changed (s, ContentProperty::POSITION); + film_content_changed (s, ContentProperty::LENGTH); + film_content_changed (s, ContentProperty::TRIM_START); + film_content_changed (s, ContentProperty::TRIM_END); + film_content_changed (s, VideoContentProperty::VIDEO_CROP); + film_content_changed (s, VideoContentProperty::VIDEO_RATIO); + film_content_changed (s, VideoContentProperty::VIDEO_FRAME_TYPE); + film_content_changed (s, VideoContentProperty::COLOUR_CONVERSION); + film_content_changed (s, AudioContentProperty::AUDIO_GAIN); + film_content_changed (s, AudioContentProperty::AUDIO_DELAY); + film_content_changed (s, AudioContentProperty::AUDIO_MAPPING); + film_content_changed (s, FFmpegContentProperty::AUDIO_STREAM); + film_content_changed (s, FFmpegContentProperty::AUDIO_STREAMS); + film_content_changed (s, FFmpegContentProperty::SUBTITLE_STREAM); + film_content_changed (s, FFmpegContentProperty::SUBTITLE_STREAMS); + film_content_changed (s, FFmpegContentProperty::FILTERS); + film_content_changed (s, SubtitleContentProperty::SUBTITLE_OFFSET); + film_content_changed (s, SubtitleContentProperty::SUBTITLE_SCALE); } +/** Set up broad sensitivity based on the type of content that is selected */ void -FilmEditor::use_dci_name_toggled (wxCommandEvent &) +FilmEditor::setup_content_sensitivity () { - if (!_film) { - return; - } + _content_add_file->Enable (_generally_sensitive); + _content_add_folder->Enable (_generally_sensitive); - _film->set_use_dci_name (_use_dci_name->GetValue ()); + shared_ptr<Content> selection = selected_content (); + + _content_remove->Enable (selection && _generally_sensitive); + _content_timeline->Enable (_generally_sensitive); + + _video_panel->Enable (selection && dynamic_pointer_cast<VideoContent> (selection) && _generally_sensitive); + _audio_panel->Enable (selection && dynamic_pointer_cast<AudioContent> (selection) && _generally_sensitive); + _subtitle_panel->Enable (selection && dynamic_pointer_cast<FFmpegContent> (selection) && _generally_sensitive); + _timing_panel->Enable (selection && _generally_sensitive); } -void -FilmEditor::edit_dci_button_clicked (wxCommandEvent &) +shared_ptr<Content> +FilmEditor::selected_content () { - if (!_film) { - return; + int const s = _content->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (s == -1) { + return shared_ptr<Content> (); } - DCINameDialog* d = new DCINameDialog (this, _film); - d->ShowModal (); - d->Destroy (); + ContentList c = _film->content (); + if (s < 0 || size_t (s) >= c.size ()) { + return shared_ptr<Content> (); + } + + return c[s]; } -void -FilmEditor::setup_streams () +shared_ptr<VideoContent> +FilmEditor::selected_video_content () { - _audio_stream->Clear (); - vector<shared_ptr<AudioStream> > a = _film->content_audio_streams (); - for (vector<shared_ptr<AudioStream> >::iterator i = a.begin(); i != a.end(); ++i) { - shared_ptr<FFmpegAudioStream> ffa = dynamic_pointer_cast<FFmpegAudioStream> (*i); - assert (ffa); - _audio_stream->Append (std_to_wx (ffa->name()), new wxStringClientData (std_to_wx (ffa->to_string ()))); - } - - if (_film->use_content_audio() && _film->audio_stream()) { - checked_set (_audio_stream, _film->audio_stream()->to_string()); + shared_ptr<Content> c = selected_content (); + if (!c) { + return shared_ptr<VideoContent> (); } - _subtitle_stream->Clear (); - vector<shared_ptr<SubtitleStream> > s = _film->subtitle_streams (); - for (vector<shared_ptr<SubtitleStream> >::iterator i = s.begin(); i != s.end(); ++i) { - _subtitle_stream->Append (std_to_wx ((*i)->name()), new wxStringClientData (std_to_wx ((*i)->to_string ()))); - } - if (_film->subtitle_stream()) { - checked_set (_subtitle_stream, _film->subtitle_stream()->to_string()); - } else { - _subtitle_stream->SetValue (wxT ("")); + return dynamic_pointer_cast<VideoContent> (c); +} + +shared_ptr<AudioContent> +FilmEditor::selected_audio_content () +{ + shared_ptr<Content> c = selected_content (); + if (!c) { + return shared_ptr<AudioContent> (); } + + return dynamic_pointer_cast<AudioContent> (c); } -void -FilmEditor::audio_stream_changed (wxCommandEvent &) +shared_ptr<SubtitleContent> +FilmEditor::selected_subtitle_content () { - if (!_film) { - return; + shared_ptr<Content> c = selected_content (); + if (!c) { + return shared_ptr<SubtitleContent> (); } - _film->set_content_audio_stream ( - audio_stream_factory ( - string_client_data (_audio_stream->GetClientObject (_audio_stream->GetSelection ())), - Film::state_version - ) - ); + return dynamic_pointer_cast<SubtitleContent> (c); } void -FilmEditor::subtitle_stream_changed (wxCommandEvent &) +FilmEditor::content_timeline_clicked () { - if (!_film) { - return; + if (_timeline_dialog) { + _timeline_dialog->Destroy (); + _timeline_dialog = 0; } - - _film->set_subtitle_stream ( - subtitle_stream_factory ( - string_client_data (_subtitle_stream->GetClientObject (_subtitle_stream->GetSelection ())), - Film::state_version - ) - ); + + _timeline_dialog = new TimelineDialog (this, _film); + _timeline_dialog->Show (); } void -FilmEditor::setup_audio_details () +FilmEditor::set_selection (weak_ptr<Content> wc) { - if (!_film->audio_stream()) { - _audio->SetLabel (wxT ("")); - } else { - stringstream s; - if (_film->audio_stream()->channels() == 1) { - s << "1 channel"; + 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 { - s << _film->audio_stream()->channels () << " channels"; + _content->SetItemState (i, 0, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED); } - s << ", " << _film->audio_stream()->sample_rate() << "Hz"; - _audio->SetLabel (std_to_wx (s.str ())); } } void -FilmEditor::active_jobs_changed (bool a) +FilmEditor::sequence_video_changed () { - set_things_sensitive (!a); + if (!_film) { + return; + } + + _film->set_sequence_video (_sequence_video->GetValue ()); } void -FilmEditor::use_audio_changed (wxCommandEvent &) +FilmEditor::content_right_click (wxListEvent& ev) { - _film->set_use_content_audio (_use_content_audio->GetValue()); + ContentList cl; + cl.push_back (selected_content ()); + _menu.popup (cl, ev.GetPoint ()); } void -FilmEditor::external_audio_changed (wxCommandEvent &) +FilmEditor::three_d_changed () { - vector<string> a; - for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) { - a.push_back (wx_to_std (_external_audio[i]->GetPath())); + if (!_film) { + return; } - _film->set_external_audio (a); -} - -void -FilmEditor::setup_reel_control_sensitivity () -{ - _reel_size->Enable (_multiple_reels->GetValue ()); + _film->set_three_d (_three_d->GetValue ()); } diff --git a/src/wx/film_editor.h b/src/wx/film_editor.h index b990ec40d..bb217211c 100644 --- a/src/wx/film_editor.h +++ b/src/wx/film_editor.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2012 Carl Hetherington <cth@carlh.net> + Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net> 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 @@ -16,7 +16,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - + /** @file src/film_editor.h * @brief A wx widget to edit a film's metadata, and perform various functions. */ @@ -27,10 +27,17 @@ #include <wx/collpane.h> #include <boost/signals2.hpp> #include "lib/film.h" +#include "content_menu.h" class wxNotebook; - +class wxListCtrl; +class wxListEvent; class Film; +class TimelineDialog; +class Ratio; +class Timecode; +class FilmEditorPanel; +class SubtitleContent; /** @class FilmEditor * @brief A wx widget to edit a film's metadata, and perform various functions. @@ -41,146 +48,108 @@ public: FilmEditor (boost::shared_ptr<Film>, wxWindow *); void set_film (boost::shared_ptr<Film>); - void setup_visibility (); + void set_selection (boost::weak_ptr<Content>); boost::signals2::signal<void (std::string)> FileChanged; + /* Stuff for panels */ + + wxNotebook* content_notebook () const { + return _content_notebook; + } + + boost::shared_ptr<Film> film () const { + return _film; + } + + boost::shared_ptr<Content> selected_content (); + boost::shared_ptr<VideoContent> selected_video_content (); + boost::shared_ptr<AudioContent> selected_audio_content (); + boost::shared_ptr<SubtitleContent> selected_subtitle_content (); + private: - void make_film_panel (); - void make_video_panel (); - void make_audio_panel (); - void make_subtitle_panel (); + void make_dcp_panel (); + void make_content_panel (); void connect_to_widgets (); /* Handle changes to the view */ - void name_changed (wxCommandEvent &); - void use_dci_name_toggled (wxCommandEvent &); - void edit_dci_button_clicked (wxCommandEvent &); - void left_crop_changed (wxCommandEvent &); - void right_crop_changed (wxCommandEvent &); - void top_crop_changed (wxCommandEvent &); - void bottom_crop_changed (wxCommandEvent &); - void content_changed (wxCommandEvent &); - void trust_content_header_changed (wxCommandEvent &); - void format_changed (wxCommandEvent &); - void dcp_trim_start_changed (wxCommandEvent &); - void dcp_trim_end_changed (wxCommandEvent &); - void multiple_reels_toggled (wxCommandEvent &); - void reel_size_changed (wxCommandEvent &); - void dcp_content_type_changed (wxCommandEvent &); - void encrypted_toggled (wxCommandEvent &); - void dcp_ab_toggled (wxCommandEvent &); - void scaler_changed (wxCommandEvent &); - void audio_gain_changed (wxCommandEvent &); - void audio_gain_calculate_button_clicked (wxCommandEvent &); - void audio_delay_changed (wxCommandEvent &); - void with_subtitles_toggled (wxCommandEvent &); - void subtitle_offset_changed (wxCommandEvent &); - void subtitle_scale_changed (wxCommandEvent &); - void colour_lut_changed (wxCommandEvent &); - void j2k_bandwidth_changed (wxCommandEvent &); - void still_duration_changed (wxCommandEvent &); - void audio_stream_changed (wxCommandEvent &); - void subtitle_stream_changed (wxCommandEvent &); - void use_audio_changed (wxCommandEvent &); - void external_audio_changed (wxCommandEvent &); + void name_changed (); + void use_dci_name_toggled (); + void edit_dci_button_clicked (); + void content_selection_changed (); + void content_add_file_clicked (); + void content_add_folder_clicked (); + void content_remove_clicked (); + void container_changed (); + void dcp_content_type_changed (); + void scaler_changed (); + void j2k_bandwidth_changed (); + void frame_rate_changed (); + void best_frame_rate_clicked (); + void content_timeline_clicked (); + void audio_channels_changed (); + void resolution_changed (); + void sequence_video_changed (); + void content_right_click (wxListEvent &); + void three_d_changed (); + void standard_changed (); + void encrypted_toggled (); /* Handle changes to the model */ void film_changed (Film::Property); + void film_content_changed (boost::weak_ptr<Content>, int); - /* Button clicks */ - void edit_filters_clicked (wxCommandEvent &); - - void set_things_sensitive (bool); - void setup_formats (); - void setup_subtitle_control_sensitivity (); - void setup_audio_control_sensitivity (); - void setup_reel_control_sensitivity (); - void setup_streams (); - void setup_audio_details (); + void set_general_sensitivity (bool); + void setup_dcp_name (); + void setup_content (); + void setup_container (); + void setup_content_sensitivity (); - wxControl* video_control (wxControl *); - wxControl* still_control (wxControl *); - void active_jobs_changed (bool); - wxNotebook* _notebook; - wxPanel* _film_panel; - wxSizer* _film_sizer; - wxPanel* _video_panel; - wxSizer* _video_sizer; - wxPanel* _audio_panel; - wxSizer* _audio_sizer; - wxPanel* _subtitle_panel; - wxSizer* _subtitle_sizer; + FilmEditorPanel* _video_panel; + FilmEditorPanel* _audio_panel; + FilmEditorPanel* _subtitle_panel; + FilmEditorPanel* _timing_panel; + std::list<FilmEditorPanel *> _panels; + + wxNotebook* _main_notebook; + wxNotebook* _content_notebook; + wxPanel* _dcp_panel; + wxSizer* _dcp_sizer; + wxPanel* _content_panel; + wxSizer* _content_sizer; /** The film we are editing */ boost::shared_ptr<Film> _film; - /** The Film's name */ wxTextCtrl* _name; wxStaticText* _dcp_name; wxCheckBox* _use_dci_name; + wxChoice* _container; + wxListCtrl* _content; + wxButton* _content_add_file; + wxButton* _content_add_folder; + wxButton* _content_remove; + wxButton* _content_earlier; + wxButton* _content_later; + wxButton* _content_timeline; + wxCheckBox* _sequence_video; wxButton* _edit_dci_button; - /** The Film's format */ - wxComboBox* _format; - /** The Film's content file */ - wxFilePickerCtrl* _content; - wxCheckBox* _trust_content_header; - /** The Film's left crop */ - wxSpinCtrl* _left_crop; - /** The Film's right crop */ - wxSpinCtrl* _right_crop; - /** The Film's top crop */ - wxSpinCtrl* _top_crop; - /** The Film's bottom crop */ - wxSpinCtrl* _bottom_crop; - /** Currently-applied filters */ - wxStaticText* _filters; - /** Button to open the filters dialogue */ - wxButton* _filters_button; - /** The Film's scaler */ - wxComboBox* _scaler; - wxRadioButton* _use_content_audio; - wxComboBox* _audio_stream; - wxRadioButton* _use_external_audio; - wxFilePickerCtrl* _external_audio[MAX_AUDIO_CHANNELS]; - /** The Film's audio gain */ - wxSpinCtrl* _audio_gain; - /** A button to open the gain calculation dialogue */ - wxButton* _audio_gain_calculate_button; - /** The Film's audio delay */ - wxSpinCtrl* _audio_delay; - wxCheckBox* _with_subtitles; - wxComboBox* _subtitle_stream; - wxSpinCtrl* _subtitle_offset; - wxSpinCtrl* _subtitle_scale; - wxComboBox* _colour_lut; - wxSpinCtrl* _j2k_bandwidth; - /** The Film's DCP content type */ - wxComboBox* _dcp_content_type; - /** The Film's frames per second */ - wxStaticText* _frames_per_second; - /** The Film's original size */ - wxStaticText* _original_size; - /** The Film's length */ - wxStaticText* _length; - /** The Film's audio details */ - wxStaticText* _audio; - /** The Film's duration for still sources */ - wxSpinCtrl* _still_duration; - - wxSpinCtrl* _dcp_trim_start; - wxSpinCtrl* _dcp_trim_end; + wxChoice* _scaler; + wxSpinCtrl* _j2k_bandwidth; + wxChoice* _dcp_content_type; + wxChoice* _frame_rate; + wxSpinCtrl* _audio_channels; + wxButton* _best_frame_rate; + wxCheckBox* _three_d; + wxChoice* _resolution; + wxChoice* _standard; wxCheckBox* _encrypted; - wxCheckBox* _multiple_reels; - wxSpinCtrl* _reel_size; - /** Selector to generate an A/B comparison DCP */ - wxCheckBox* _dcp_ab; - std::list<wxControl*> _video_controls; - std::list<wxControl*> _still_controls; + ContentMenu _menu; - std::vector<Format const *> _formats; + std::vector<Ratio const *> _ratios; bool _generally_sensitive; + TimelineDialog* _timeline_dialog; }; diff --git a/src/wx/film_editor_panel.cc b/src/wx/film_editor_panel.cc new file mode 100644 index 000000000..a637df1fe --- /dev/null +++ b/src/wx/film_editor_panel.cc @@ -0,0 +1,34 @@ +/* + Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net> + + 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 <wx/notebook.h> +#include "film_editor_panel.h" +#include "film_editor.h" + +using boost::shared_ptr; + +FilmEditorPanel::FilmEditorPanel (FilmEditor* e, wxString name) + : wxPanel (e->content_notebook (), wxID_ANY) + , _editor (e) + , _sizer (new wxBoxSizer (wxVERTICAL)) +{ + e->content_notebook()->AddPage (this, name, false); + SetSizer (_sizer); +} + diff --git a/src/wx/film_editor_panel.h b/src/wx/film_editor_panel.h new file mode 100644 index 000000000..8acb3efb6 --- /dev/null +++ b/src/wx/film_editor_panel.h @@ -0,0 +1,43 @@ +/* + Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net> + + 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. + +*/ + +#ifndef DCPOMATIC_FILM_EDITOR_PANEL_H +#define DCPOMATIC_FILM_EDITOR_PANEL_H + +#include <boost/shared_ptr.hpp> +#include <wx/wx.h> +#include "lib/film.h" + +class FilmEditor; +class Content; + +class FilmEditorPanel : public wxPanel +{ +public: + FilmEditorPanel (FilmEditor *, wxString); + + virtual void film_changed (Film::Property) {} + virtual void film_content_changed (boost::shared_ptr<Content>, int) = 0; + +protected: + FilmEditor* _editor; + wxSizer* _sizer; +}; + +#endif diff --git a/src/wx/film_list.cc b/src/wx/film_list.cc deleted file mode 100644 index 05d9734f6..000000000 --- a/src/wx/film_list.cc +++ /dev/null @@ -1,65 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington <cth@carlh.net> - - 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 <boost/filesystem.hpp> -#include "lib/film.h" -#include "film_list.h" - -using namespace std; -using namespace boost; - -FilmList::FilmList (string d) - : _directory (d) - , _list (1) -{ - for (filesystem::directory_iterator i = filesystem::directory_iterator (_directory); i != filesystem::directory_iterator(); ++i) { - if (is_directory (*i)) { - filesystem::path m = filesystem::path (*i) / filesystem::path ("metadata"); - if (is_regular_file (m)) { - Film* f = new Film (i->path().string()); - _films.push_back (f); - } - } - } - - for (vector<Film const *>::iterator i = _films.begin(); i != _films.end(); ++i) { - _list.append_text ((*i)->name ()); - } - - _list.set_headers_visible (false); - _list.get_selection()->signal_changed().connect (bind (&FilmList::selection_changed, this)); -} - -Gtk::Widget& -FilmList::widget () -{ - return _list; -} - -void -FilmList::selection_changed () -{ - Gtk::ListViewText::SelectionList s = _list.get_selected (); - if (s.empty ()) { - return; - } - - assert (s[0] < int (_films.size ())); - SelectionChanged (_films[s[0]]); -} diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 3d8198457..3ba7ee7ce 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -25,42 +25,50 @@ #include <iomanip> #include <wx/tglbtn.h> #include "lib/film.h" -#include "lib/format.h" +#include "lib/ratio.h" #include "lib/util.h" #include "lib/job_manager.h" -#include "lib/options.h" -#include "lib/subtitle.h" #include "lib/image.h" #include "lib/scaler.h" #include "lib/exceptions.h" #include "lib/examine_content_job.h" +#include "lib/filter.h" +#include "lib/player.h" +#include "lib/video_content.h" +#include "lib/ffmpeg_content.h" +#include "lib/still_image_content.h" +#include "lib/video_decoder.h" #include "film_viewer.h" #include "wx_util.h" -#include "video_decoder.h" using std::string; using std::pair; +using std::min; using std::max; using std::cout; using std::list; +using std::make_pair; using boost::shared_ptr; +using boost::dynamic_pointer_cast; +using boost::weak_ptr; +using libdcp::Size; FilmViewer::FilmViewer (shared_ptr<Film> f, wxWindow* p) : wxPanel (p) , _panel (new wxPanel (this)) , _slider (new wxSlider (this, wxID_ANY, 0, 0, 4096)) - , _play_button (new wxToggleButton (this, wxID_ANY, wxT ("Play"))) + , _back_button (new wxButton (this, wxID_ANY, wxT("<"))) + , _forward_button (new wxButton (this, wxID_ANY, wxT(">"))) + , _frame_number (new wxStaticText (this, wxID_ANY, wxT(""))) + , _timecode (new wxStaticText (this, wxID_ANY, wxT(""))) + , _play_button (new wxToggleButton (this, wxID_ANY, _("Play"))) , _got_frame (false) - , _out_width (0) - , _out_height (0) - , _panel_width (0) - , _panel_height (0) - , _clear_required (false) { +#ifndef __WXOSX__ _panel->SetDoubleBuffered (true); -#if wxMAJOR_VERSION == 2 && wxMINOR_VERSION >= 9 +#endif + _panel->SetBackgroundStyle (wxBG_STYLE_PAINT); -#endif _v_sizer = new wxBoxSizer (wxVERTICAL); SetSizer (_v_sizer); @@ -68,18 +76,32 @@ FilmViewer::FilmViewer (shared_ptr<Film> f, wxWindow* p) _v_sizer->Add (_panel, 1, wxEXPAND); wxBoxSizer* h_sizer = new wxBoxSizer (wxHORIZONTAL); + + wxBoxSizer* time_sizer = new wxBoxSizer (wxVERTICAL); + time_sizer->Add (_frame_number, 0, wxEXPAND); + time_sizer->Add (_timecode, 0, wxEXPAND); + + h_sizer->Add (_back_button, 0, wxALL, 2); + h_sizer->Add (time_sizer, 0, wxEXPAND); + h_sizer->Add (_forward_button, 0, wxALL, 2); h_sizer->Add (_play_button, 0, wxEXPAND); h_sizer->Add (_slider, 1, wxEXPAND); - _v_sizer->Add (h_sizer, 0, wxEXPAND); + _v_sizer->Add (h_sizer, 0, wxEXPAND | wxALL, 6); + + _frame_number->SetMinSize (wxSize (84, -1)); + _back_button->SetMinSize (wxSize (32, -1)); + _forward_button->SetMinSize (wxSize (32, -1)); - _panel->Connect (wxID_ANY, wxEVT_PAINT, wxPaintEventHandler (FilmViewer::paint_panel), 0, this); - _panel->Connect (wxID_ANY, wxEVT_SIZE, wxSizeEventHandler (FilmViewer::panel_sized), 0, this); - _slider->Connect (wxID_ANY, wxEVT_SCROLL_THUMBTRACK, wxScrollEventHandler (FilmViewer::slider_moved), 0, this); - _slider->Connect (wxID_ANY, wxEVT_SCROLL_PAGEUP, wxScrollEventHandler (FilmViewer::slider_moved), 0, this); - _slider->Connect (wxID_ANY, wxEVT_SCROLL_PAGEDOWN, wxScrollEventHandler (FilmViewer::slider_moved), 0, this); - _play_button->Connect (wxID_ANY, wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler (FilmViewer::play_clicked), 0, this); - _timer.Connect (wxID_ANY, wxEVT_TIMER, wxTimerEventHandler (FilmViewer::timer), 0, this); + _panel->Bind (wxEVT_PAINT, boost::bind (&FilmViewer::paint_panel, this)); + _panel->Bind (wxEVT_SIZE, boost::bind (&FilmViewer::panel_sized, this, _1)); + _slider->Bind (wxEVT_SCROLL_THUMBTRACK, boost::bind (&FilmViewer::slider_moved, this)); + _slider->Bind (wxEVT_SCROLL_PAGEUP, boost::bind (&FilmViewer::slider_moved, this)); + _slider->Bind (wxEVT_SCROLL_PAGEDOWN, boost::bind (&FilmViewer::slider_moved, this)); + _play_button->Bind (wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, boost::bind (&FilmViewer::play_clicked, this)); + _timer.Bind (wxEVT_TIMER, boost::bind (&FilmViewer::timer, this)); + _back_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&FilmViewer::back_clicked, this)); + _forward_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&FilmViewer::forward_clicked, this)); set_film (f); @@ -89,95 +111,66 @@ FilmViewer::FilmViewer (shared_ptr<Film> f, wxWindow* p) } void -FilmViewer::film_changed (Film::Property p) -{ - switch (p) { - case Film::FORMAT: - calculate_sizes (); - update_from_raw (); - break; - case Film::CONTENT: - { - shared_ptr<DecodeOptions> o (new DecodeOptions); - o->decode_audio = false; - o->decode_subtitles = true; - o->video_sync = false; - _decoders = decoder_factory (_film, o, 0); - _decoders.video->Video.connect (bind (&FilmViewer::process_video, this, _1, _2, _3)); - _decoders.video->OutputChanged.connect (boost::bind (&FilmViewer::decoder_changed, this)); - _decoders.video->set_subtitle_stream (_film->subtitle_stream()); - calculate_sizes (); - get_frame (); - _panel->Refresh (); - _slider->Show (_film->content_type() == VIDEO); - _play_button->Show (_film->content_type() == VIDEO); - _v_sizer->Layout (); - break; - } - case Film::WITH_SUBTITLES: - case Film::SUBTITLE_OFFSET: - case Film::SUBTITLE_SCALE: - case Film::SCALER: - update_from_raw (); - break; - case Film::SUBTITLE_STREAM: - _decoders.video->set_subtitle_stream (_film->subtitle_stream ()); - break; - default: - break; - } -} - -void FilmViewer::set_film (shared_ptr<Film> f) { if (_film == f) { return; } - + _film = f; + _frame.reset (); + _queue.clear (); + + _slider->SetValue (0); + set_position_text (0); + if (!_film) { return; } - _film->Changed.connect (boost::bind (&FilmViewer::film_changed, this, _1)); + _player = f->make_player (); + _player->disable_audio (); + _player->Video.connect (boost::bind (&FilmViewer::process_video, this, _1, _2, _5)); + _player->Changed.connect (boost::bind (&FilmViewer::player_changed, this, _1)); - film_changed (Film::CONTENT); - film_changed (Film::CROP); - film_changed (Film::FORMAT); - film_changed (Film::WITH_SUBTITLES); - film_changed (Film::SUBTITLE_OFFSET); - film_changed (Film::SUBTITLE_SCALE); - film_changed (Film::SUBTITLE_STREAM); + calculate_sizes (); + fetch_current_frame_again (); } void -FilmViewer::decoder_changed () +FilmViewer::fetch_current_frame_again () { - if (_decoders.video->seek_to_last ()) { + if (!_player) { return; } - get_frame (); - _panel->Refresh (); - _panel->Update (); + /* Player::video_position is the time after the last frame that we received. + We want to see it again, so seek back one frame. + */ + + Time p = _player->video_position() - _film->video_frames_to_time (1); + if (p < 0) { + p = 0; + } + + _player->seek (p, true); + fetch_next_frame (); } void -FilmViewer::timer (wxTimerEvent &) +FilmViewer::timer () { - if (!_film) { + if (!_player) { return; } - _panel->Refresh (); - _panel->Update (); + fetch_next_frame (); - get_frame (); + Time const len = _film->length (); - if (_film->length()) { - int const new_slider_position = 4096 * _decoders.video->last_source_time() / (_film->length().get() / _film->frames_per_second()); + if (len) { + int const new_slider_position = 4096 * _player->video_position() / len; if (new_slider_position != _slider->GetValue()) { _slider->SetValue (new_slider_position); } @@ -186,125 +179,88 @@ FilmViewer::timer (wxTimerEvent &) void -FilmViewer::paint_panel (wxPaintEvent &) +FilmViewer::paint_panel () { wxPaintDC dc (_panel); - if (_clear_required) { - dc.Clear (); - _clear_required = false; - } - - if (!_display_frame || !_film || !_out_width || !_out_height) { + if (!_frame || !_film || !_out_size.width || !_out_size.height) { dc.Clear (); return; } - wxImage frame (_out_width, _out_height, _display_frame->data()[0], true); + shared_ptr<Image> packed_frame (new Image (_frame, false)); + + wxImage frame (_out_size.width, _out_size.height, packed_frame->data()[0], true); wxBitmap frame_bitmap (frame); dc.DrawBitmap (frame_bitmap, 0, 0); - if (_film->with_subtitles() && _display_sub) { - wxImage sub (_display_sub->size().width, _display_sub->size().height, _display_sub->data()[0], _display_sub->alpha(), true); - wxBitmap sub_bitmap (sub); - dc.DrawBitmap (sub_bitmap, _display_sub_position.x, _display_sub_position.y); + if (_out_size.width < _panel_size.width) { + wxPen p (GetBackgroundColour ()); + wxBrush b (GetBackgroundColour ()); + dc.SetPen (p); + dc.SetBrush (b); + dc.DrawRectangle (_out_size.width, 0, _panel_size.width - _out_size.width, _panel_size.height); } + + if (_out_size.height < _panel_size.height) { + wxPen p (GetBackgroundColour ()); + wxBrush b (GetBackgroundColour ()); + dc.SetPen (p); + dc.SetBrush (b); + dc.DrawRectangle (0, _out_size.height, _panel_size.width, _panel_size.height - _out_size.height); + } } void -FilmViewer::slider_moved (wxScrollEvent &) +FilmViewer::slider_moved () { - if (!_film || !_film->length()) { - return; + if (_film && _player) { + _player->seek (_slider->GetValue() * _film->length() / 4096, false); + fetch_next_frame (); } - - if (_decoders.video->seek (_slider->GetValue() * _film->length().get() / (4096 * _film->frames_per_second()))) { - return; - } - - get_frame (); - _panel->Refresh (); - _panel->Update (); } void FilmViewer::panel_sized (wxSizeEvent& ev) { - _panel_width = ev.GetSize().GetWidth(); - _panel_height = ev.GetSize().GetHeight(); + _panel_size.width = ev.GetSize().GetWidth(); + _panel_size.height = ev.GetSize().GetHeight(); calculate_sizes (); - update_from_raw (); -} - -void -FilmViewer::update_from_raw () -{ - if (!_raw_frame) { - return; - } - - raw_to_display (); - - _panel->Refresh (); - _panel->Update (); + fetch_current_frame_again (); } void -FilmViewer::raw_to_display () -{ - if (!_raw_frame || _out_width < 64 || _out_height < 64 || !_film) { - return; - } - - Size old_size; - if (_display_frame) { - old_size = _display_frame->size(); - } - - /* Get a compacted image as we have to feed it to wxWidgets */ - _display_frame = _raw_frame->scale_and_convert_to_rgb (Size (_out_width, _out_height), 0, _film->scaler(), false); - - if (old_size != _display_frame->size()) { - _clear_required = true; - } - - if (_raw_sub) { - Rect tx = subtitle_transformed_area ( - float (_out_width) / _film->size().width, - float (_out_height) / _film->size().height, - _raw_sub->area(), _film->subtitle_offset(), _film->subtitle_scale() - ); - - _display_sub.reset (new RGBPlusAlphaImage (_raw_sub->image()->scale (tx.size(), _film->scaler(), false))); - _display_sub_position = tx.position(); - } else { - _display_sub.reset (); - } -} - -void FilmViewer::calculate_sizes () { - if (!_film) { + if (!_film || !_player) { return; } + + Ratio const * container = _film->container (); - float const panel_ratio = static_cast<float> (_panel_width) / _panel_height; - float const film_ratio = _film->format() ? _film->format()->ratio_as_float(_film) : 1.78; + float const panel_ratio = static_cast<float> (_panel_size.width) / _panel_size.height; + float const film_ratio = container ? container->ratio () : 1.78; + if (panel_ratio < film_ratio) { /* panel is less widscreen than the film; clamp width */ - _out_width = _panel_width; - _out_height = _out_width / film_ratio; + _out_size.width = _panel_size.width; + _out_size.height = _out_size.width / film_ratio; } else { - /* panel is more widescreen than the film; clamp heignt */ - _out_height = _panel_height; - _out_width = _out_height * film_ratio; + /* panel is more widescreen than the film; clamp height */ + _out_size.height = _panel_size.height; + _out_size.width = _out_size.height * film_ratio; } + + /* Catch silly values */ + _out_size.width = max (64, _out_size.width); + _out_size.height = max (64, _out_size.height); + + _player->set_video_container_size (_out_size); } void -FilmViewer::play_clicked (wxCommandEvent &) +FilmViewer::play_clicked () { check_play_state (); } @@ -312,48 +268,88 @@ FilmViewer::play_clicked (wxCommandEvent &) void FilmViewer::check_play_state () { - if (!_film) { + if (!_film || _film->video_frame_rate() == 0) { return; } if (_play_button->GetValue()) { - _timer.Start (1000 / _film->frames_per_second()); + _timer.Start (1000 / _film->video_frame_rate()); } else { _timer.Stop (); } } void -FilmViewer::process_video (shared_ptr<Image> image, bool, shared_ptr<Subtitle> sub) +FilmViewer::process_video (shared_ptr<const Image> image, Eyes eyes, Time t) { - _raw_frame = image; - _raw_sub = sub; + if (eyes == EYES_RIGHT) { + return; + } + + if (_got_frame) { + /* This is an additional frame emitted by a single pass. Store it. */ + _queue.push_front (make_pair (image, t)); + return; + } + + _frame = image; + _got_frame = true; - raw_to_display (); + set_position_text (t); +} - _got_frame = true; +void +FilmViewer::set_position_text (Time t) +{ + if (!_film) { + _frame_number->SetLabel ("0"); + _timecode->SetLabel ("0:0:0.0"); + return; + } + + double const fps = _film->video_frame_rate (); + /* Count frame number from 1 ... not sure if this is the best idea */ + _frame_number->SetLabel (wxString::Format (wxT("%d"), int (rint (t * fps / TIME_HZ)) + 1)); + + double w = static_cast<double>(t) / TIME_HZ; + int const h = (w / 3600); + w -= h * 3600; + int const m = (w / 60); + w -= m * 60; + int const s = floor (w); + w -= s; + int const f = rint (w * fps); + _timecode->SetLabel (wxString::Format (wxT("%02d:%02d:%02d.%02d"), h, m, s, f)); } +/** Ask the player to emit its next frame, then update our display */ void -FilmViewer::get_frame () +FilmViewer::fetch_next_frame () { - /* Clear our raw frame in case we don't get a new one */ - _raw_frame.reset (); + /* Clear our frame in case we don't get a new one */ + _frame.reset (); + + if (!_player) { + return; + } + + _got_frame = false; - try { - _got_frame = false; - while (!_got_frame) { - if (_decoders.video->pass ()) { - /* We didn't get a frame before the decoder gave up, - so clear our display frame. - */ - _display_frame.reset (); - break; - } + if (!_queue.empty ()) { + process_video (_queue.back().first, EYES_BOTH, _queue.back().second); + _queue.pop_back (); + } else { + try { + while (!_got_frame && !_player->pass ()) {} + } catch (DecodeError& e) { + _play_button->SetValue (false); + check_play_state (); + error_dialog (this, wxString::Format (_("Could not decode video for view (%s)"), std_to_wx(e.what()).data())); } - } catch (DecodeError& e) { - error_dialog (this, String::compose ("Could not decode video for view (%1)", e.what())); } + + _panel->Refresh (); + _panel->Update (); } void @@ -376,3 +372,43 @@ FilmViewer::active_jobs_changed (bool a) _play_button->Enable (!a); } +void +FilmViewer::back_clicked () +{ + if (!_player) { + return; + } + + /* Player::video_position is the time after the last frame that we received. + We want to see the one before it, so we need to go back 2. + */ + + Time p = _player->video_position() - _film->video_frames_to_time (2); + if (p < 0) { + p = 0; + } + + _player->seek (p, true); + fetch_next_frame (); +} + +void +FilmViewer::forward_clicked () +{ + if (!_player) { + return; + } + + fetch_next_frame (); +} + +void +FilmViewer::player_changed (bool frequent) +{ + if (frequent) { + return; + } + + calculate_sizes (); + fetch_current_frame_again (); +} diff --git a/src/wx/film_viewer.h b/src/wx/film_viewer.h index 6029c04f3..7bda9617e 100644 --- a/src/wx/film_viewer.h +++ b/src/wx/film_viewer.h @@ -23,16 +23,27 @@ #include <wx/wx.h> #include "lib/film.h" -#include "lib/decoder_factory.h" class wxToggleButton; class FFmpegPlayer; class Image; class RGBPlusAlphaImage; -class Subtitle; /** @class FilmViewer * @brief A wx widget to view a preview of a Film. + * + * The film takes the following path through the viewer: + * + * 1. fetch_next_frame() asks our _player to decode some data. If it does, process_video() + * will be called. + * + * 2. process_video() takes the image from the player (_frame). + * + * 3. fetch_next_frame() calls _panel->Refresh() and _panel->Update() which results in + * paint_panel() being called; this creates frame_bitmap from _frame and blits it to the display. + * + * fetch_current_frame_again() asks the player to re-emit its current frame on the next pass(), and then + * starts from step #1. */ class FilmViewer : public wxPanel { @@ -42,41 +53,42 @@ public: void set_film (boost::shared_ptr<Film>); private: - void film_changed (Film::Property); - void paint_panel (wxPaintEvent &); + void paint_panel (); void panel_sized (wxSizeEvent &); - void slider_moved (wxScrollEvent &); - void play_clicked (wxCommandEvent &); - void timer (wxTimerEvent &); - void process_video (boost::shared_ptr<Image>, bool, boost::shared_ptr<Subtitle>); + void slider_moved (); + void play_clicked (); + void timer (); + void process_video (boost::shared_ptr<const Image>, Eyes, Time); void calculate_sizes (); void check_play_state (); - void update_from_raw (); - void decoder_changed (); - void raw_to_display (); - void get_frame (); + void fetch_current_frame_again (); + void fetch_next_frame (); void active_jobs_changed (bool); + void back_clicked (); + void forward_clicked (); + void player_changed (bool); + void set_position_text (Time); boost::shared_ptr<Film> _film; + boost::shared_ptr<Player> _player; - wxBoxSizer* _v_sizer; + wxSizer* _v_sizer; wxPanel* _panel; wxSlider* _slider; + wxButton* _back_button; + wxButton* _forward_button; + wxStaticText* _frame_number; + wxStaticText* _timecode; wxToggleButton* _play_button; wxTimer _timer; - Decoders _decoders; - boost::shared_ptr<Image> _raw_frame; - boost::shared_ptr<Subtitle> _raw_sub; - boost::shared_ptr<Image> _display_frame; - boost::shared_ptr<RGBPlusAlphaImage> _display_sub; - Position _display_sub_position; + boost::shared_ptr<const Image> _frame; bool _got_frame; - int _out_width; - int _out_height; - int _panel_width; - int _panel_height; + /** Size of our output (including padding if we have any) */ + libdcp::Size _out_size; + /** Size of the panel that we have available */ + libdcp::Size _panel_size; - bool _clear_required; + std::list<std::pair<boost::shared_ptr<const Image>, Time> > _queue; }; diff --git a/src/wx/filter_dialog.cc b/src/wx/filter_dialog.cc index 2abe53026..13907ae0c 100644 --- a/src/wx/filter_dialog.cc +++ b/src/wx/filter_dialog.cc @@ -23,14 +23,14 @@ #include "lib/film.h" #include "filter_dialog.h" -#include "filter_view.h" +#include "filter_editor.h" using namespace std; using boost::bind; FilterDialog::FilterDialog (wxWindow* parent, vector<Filter const *> const & f) : wxDialog (parent, wxID_ANY, wxString (_("Filters"))) - , _filters (new FilterView (this, f)) + , _filters (new FilterEditor (this, f)) { wxBoxSizer* sizer = new wxBoxSizer (wxVERTICAL); sizer->Add (_filters, 1, wxEXPAND | wxALL, 6); diff --git a/src/wx/filter_dialog.h b/src/wx/filter_dialog.h index e76f8536b..d54e6f2e4 100644 --- a/src/wx/filter_dialog.h +++ b/src/wx/filter_dialog.h @@ -25,7 +25,8 @@ #include <boost/signals2.hpp> class Film; -class FilterView; +class FilterEditor; +class Filter; /** @class FilterDialog * @brief A dialog to select FFmpeg filters. @@ -40,5 +41,5 @@ public: private: void active_changed (); - FilterView* _filters; + FilterEditor* _filters; }; diff --git a/src/wx/filter_view.cc b/src/wx/filter_editor.cc index 8d9535d81..4dd18004b 100644 --- a/src/wx/filter_view.cc +++ b/src/wx/filter_editor.cc @@ -17,19 +17,19 @@ */ -/** @file src/filter_view.cc +/** @file src/filter_editor.cc * @brief A panel to select FFmpeg filters. */ #include <iostream> #include <algorithm> #include "lib/filter.h" -#include "filter_view.h" +#include "filter_editor.h" #include "wx_util.h" using namespace std; -FilterView::FilterView (wxWindow* parent, vector<Filter const *> const & active) +FilterEditor::FilterEditor (wxWindow* parent, vector<Filter const *> const & active) : wxPanel (parent) { wxBoxSizer* sizer = new wxBoxSizer (wxVERTICAL); @@ -37,24 +37,49 @@ FilterView::FilterView (wxWindow* parent, vector<Filter const *> const & active) vector<Filter const *> filters = Filter::all (); + typedef map<string, list<Filter const *> > CategoryMap; + CategoryMap categories; + for (vector<Filter const *>::iterator i = filters.begin(); i != filters.end(); ++i) { - wxCheckBox* b = new wxCheckBox (this, wxID_ANY, std_to_wx ((*i)->name ())); - bool const a = find (active.begin(), active.end(), *i) != active.end (); - b->SetValue (a); - _filters[*i] = b; - b->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilterView::filter_toggled), 0, this); - sizer->Add (b); + CategoryMap::iterator j = categories.find ((*i)->category ()); + if (j == categories.end ()) { + list<Filter const *> c; + c.push_back (*i); + categories[(*i)->category()] = c; + } else { + j->second.push_back (*i); + } + } + + for (CategoryMap::iterator i = categories.begin(); i != categories.end(); ++i) { + + wxStaticText* c = new wxStaticText (this, wxID_ANY, std_to_wx (i->first)); + wxFont font = c->GetFont(); + font.SetWeight(wxFONTWEIGHT_BOLD); + c->SetFont(font); + sizer->Add (c); + + for (list<Filter const *>::iterator j = i->second.begin(); j != i->second.end(); ++j) { + wxCheckBox* b = new wxCheckBox (this, wxID_ANY, std_to_wx ((*j)->name ())); + bool const a = find (active.begin(), active.end(), *j) != active.end (); + b->SetValue (a); + _filters[*j] = b; + b->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&FilterEditor::filter_toggled, this)); + sizer->Add (b); + } + + sizer->AddSpacer (6); } } void -FilterView::filter_toggled (wxCommandEvent &) +FilterEditor::filter_toggled () { ActiveChanged (); } vector<Filter const*> -FilterView::active () const +FilterEditor::active () const { vector<Filter const *> active; for (map<Filter const *, wxCheckBox*>::const_iterator i = _filters.begin(); i != _filters.end(); ++i) { diff --git a/src/wx/filter_view.h b/src/wx/filter_editor.h index b8d5f644f..4e1d682d5 100644 --- a/src/wx/filter_view.h +++ b/src/wx/filter_editor.h @@ -17,7 +17,7 @@ */ -/** @file src/filter_view.h +/** @file src/filter_editor.h * @brief A panel to select FFmpeg filters. */ @@ -28,20 +28,20 @@ class Filter; -/** @class FilterView +/** @class FilterEditor * @brief A panel to select FFmpeg filters. */ -class FilterView : public wxPanel +class FilterEditor : public wxPanel { public: - FilterView (wxWindow *, std::vector<Filter const *> const &); + FilterEditor (wxWindow *, std::vector<Filter const *> const &); std::vector<Filter const *> active () const; boost::signals2::signal<void()> ActiveChanged; private: - void filter_toggled (wxCommandEvent &); + void filter_toggled (); std::map<Filter const *, wxCheckBox *> _filters; }; diff --git a/src/wx/gain_calculator_dialog.cc b/src/wx/gain_calculator_dialog.cc index 3f07faf06..f9880c044 100644 --- a/src/wx/gain_calculator_dialog.cc +++ b/src/wx/gain_calculator_dialog.cc @@ -24,21 +24,21 @@ using namespace boost; GainCalculatorDialog::GainCalculatorDialog (wxWindow* parent) - : wxDialog (parent, wxID_ANY, wxString (_("Gain Calculator"))) + : wxDialog (parent, wxID_ANY, _("Gain Calculator")) { - wxFlexGridSizer* table = new wxFlexGridSizer (2, 6, 6); + wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); table->AddGrowableCol (1, 1); - add_label_to_sizer (table, this, "I want to play this back at fader"); + add_label_to_sizer (table, this, _("I want to play this back at fader"), true); _wanted = new wxTextCtrl (this, wxID_ANY, wxT (""), wxDefaultPosition, wxDefaultSize, 0, wxTextValidator (wxFILTER_NUMERIC)); table->Add (_wanted, 1, wxEXPAND); - add_label_to_sizer (table, this, "But I have to use fader"); + add_label_to_sizer (table, this, _("But I have to use fader"), true); _actual = new wxTextCtrl (this, wxID_ANY, wxT (""), wxDefaultPosition, wxDefaultSize, 0, wxTextValidator (wxFILTER_NUMERIC)); table->Add (_actual, 1, wxEXPAND); wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); - overall_sizer->Add (table, 1, wxEXPAND | wxALL, 6); + overall_sizer->Add (table, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); wxSizer* buttons = CreateSeparatedButtonSizer (wxOK); if (buttons) { diff --git a/src/wx/job_manager_view.cc b/src/wx/job_manager_view.cc index 9c7040584..a95087b02 100644 --- a/src/wx/job_manager_view.cc +++ b/src/wx/job_manager_view.cc @@ -30,85 +30,173 @@ using std::string; using std::list; +using std::map; +using std::cout; using boost::shared_ptr; +using boost::weak_ptr; + +class JobRecord +{ +public: + JobRecord (shared_ptr<Job> job, wxScrolledWindow* window, wxPanel* panel, wxFlexGridSizer* table, bool pause) + : _job (job) + , _window (window) + , _panel (panel) + , _table (table) + { + int n = 0; + + wxStaticText* m = new wxStaticText (panel, wxID_ANY, std_to_wx (_job->name ())); + table->Insert (n, m, 0, wxALIGN_CENTER_VERTICAL | wxALL, 6); + ++n; + + _gauge = new wxGauge (panel, wxID_ANY, 100); + /* This seems to be required to allow the gauge to shrink under OS X */ + _gauge->SetMinSize (wxSize (0, -1)); + table->Insert (n, _gauge, 1, wxEXPAND | wxLEFT | wxRIGHT); + ++n; + + _message = new wxStaticText (panel, wxID_ANY, std_to_wx ("")); + table->Insert (n, _message, 1, wxALIGN_CENTER_VERTICAL | wxALL, 6); + ++n; + + _cancel = new wxButton (panel, wxID_ANY, _("Cancel")); + _cancel->Bind (wxEVT_COMMAND_BUTTON_CLICKED, &JobRecord::cancel_clicked, this); + table->Insert (n, _cancel, 1, wxALIGN_CENTER_VERTICAL | wxALL, 6); + ++n; + + if (pause) { + _pause = new wxButton (_panel, wxID_ANY, _("Pause")); + _pause->Bind (wxEVT_COMMAND_BUTTON_CLICKED, &JobRecord::pause_clicked, this); + table->Insert (n, _pause, 1, wxALIGN_CENTER_VERTICAL | wxALL, 6); + ++n; + } + + _details = new wxButton (_panel, wxID_ANY, _("Details...")); + _details->Bind (wxEVT_COMMAND_BUTTON_CLICKED, &JobRecord::details_clicked, this); + _details->Enable (false); + table->Insert (n, _details, 1, wxALIGN_CENTER_VERTICAL | wxALL, 6); + ++n; + + job->Progress.connect (boost::bind (&JobRecord::progress, this)); + job->Finished.connect (boost::bind (&JobRecord::finished, this)); + + table->Layout (); + panel->FitInside (); + } + + void maybe_pulse () + { + if (_job->running() && _job->progress_unknown ()) { + _gauge->Pulse (); + } + } + +private: + + void progress () + { + float const p = _job->overall_progress (); + if (p >= 0) { + checked_set (_message, _job->status ()); + _gauge->SetValue (p * 100); + } + + _table->Layout (); + _window->FitInside (); + } + + void finished () + { + checked_set (_message, _job->status ()); + if (!_job->finished_cancelled ()) { + _gauge->SetValue (100); + } + + _cancel->Enable (false); + if (!_job->error_details().empty ()) { + _details->Enable (true); + } + + _table->Layout (); + _window->FitInside (); + } + + void details_clicked (wxCommandEvent &) + { + string s = _job->error_summary(); + s[0] = toupper (s[0]); + error_dialog (_window, std_to_wx (String::compose ("%1.\n\n%2", s, _job->error_details()))); + } + + void cancel_clicked (wxCommandEvent &) + { + _job->cancel (); + } + + void pause_clicked (wxCommandEvent &) + { + if (_job->paused()) { + _job->resume (); + _pause->SetLabel (_("Pause")); + } else { + _job->pause (); + _pause->SetLabel (_("Resume")); + } + } + + boost::shared_ptr<Job> _job; + wxScrolledWindow* _window; + wxPanel* _panel; + wxFlexGridSizer* _table; + wxGauge* _gauge; + wxStaticText* _message; + wxButton* _cancel; + wxButton* _pause; + wxButton* _details; +}; /** Must be called in the GUI thread */ -JobManagerView::JobManagerView (wxWindow* parent) +JobManagerView::JobManagerView (wxWindow* parent, Buttons buttons) : wxScrolledWindow (parent) + , _buttons (buttons) { _panel = new wxPanel (this); wxSizer* sizer = new wxBoxSizer (wxVERTICAL); sizer->Add (_panel, 1, wxEXPAND); SetSizer (sizer); + + int N = 5; + if (buttons & PAUSE) { + ++N; + } - _table = new wxFlexGridSizer (3, 6, 6); + _table = new wxFlexGridSizer (N, 6, 6); _table->AddGrowableCol (1, 1); _panel->SetSizer (_table); SetScrollRate (0, 32); - Connect (wxID_ANY, wxEVT_TIMER, wxTimerEventHandler (JobManagerView::periodic), 0, this); + Bind (wxEVT_TIMER, boost::bind (&JobManagerView::periodic, this)); _timer.reset (new wxTimer (this)); _timer->Start (1000); - - update (); + + JobManager::instance()->JobAdded.connect (bind (&JobManagerView::job_added, this, _1)); } void -JobManagerView::periodic (wxTimerEvent &) +JobManagerView::job_added (weak_ptr<Job> j) { - update (); + shared_ptr<Job> job = j.lock (); + if (job) { + _job_records.push_back (shared_ptr<JobRecord> (new JobRecord (job, this, _panel, _table, _buttons & PAUSE))); + } } -/** Update the view by examining the state of each job. - * Must be called in the GUI thread. - */ void -JobManagerView::update () +JobManagerView::periodic () { - list<shared_ptr<Job> > jobs = JobManager::instance()->get (); - - int index = 0; - - for (list<shared_ptr<Job> >::iterator i = jobs.begin(); i != jobs.end(); ++i) { - - if (_job_records.find (*i) == _job_records.end ()) { - wxStaticText* m = new wxStaticText (_panel, wxID_ANY, std_to_wx ((*i)->name ())); - _table->Insert (index, m, 0, wxALIGN_CENTER_VERTICAL | wxALL, 6); - - JobRecord r; - r.finalised = false; - r.gauge = new wxGauge (_panel, wxID_ANY, 100); - _table->Insert (index + 1, r.gauge, 1, wxEXPAND | wxLEFT | wxRIGHT); - - r.message = new wxStaticText (_panel, wxID_ANY, std_to_wx ("")); - _table->Insert (index + 2, r.message, 1, wxALIGN_CENTER_VERTICAL | wxALL, 6); - - _job_records[*i] = r; - } - - string const st = (*i)->status (); - - if (!(*i)->finished ()) { - float const p = (*i)->overall_progress (); - if (p >= 0) { - _job_records[*i].message->SetLabel (std_to_wx (st)); - _job_records[*i].gauge->SetValue (p * 100); - } else { - _job_records[*i].message->SetLabel (wxT ("Running")); - _job_records[*i].gauge->Pulse (); - } - } - - if ((*i)->finished() && !_job_records[*i].finalised) { - _job_records[*i].gauge->SetValue (100); - _job_records[*i].message->SetLabel (std_to_wx (st)); - _job_records[*i].finalised = true; - } - - index += 3; + for (list<shared_ptr<JobRecord> >::iterator i = _job_records.begin(); i != _job_records.end(); ++i) { + (*i)->maybe_pulse (); } - - _table->Layout (); - FitInside (); } diff --git a/src/wx/job_manager_view.h b/src/wx/job_manager_view.h index 5c10890ef..c4bb1e218 100644 --- a/src/wx/job_manager_view.h +++ b/src/wx/job_manager_view.h @@ -26,6 +26,7 @@ #include <wx/wx.h> class Job; +class JobRecord; /** @class JobManagerView * @brief Class which is a wxPanel for showing the progress of jobs. @@ -33,21 +34,20 @@ class Job; class JobManagerView : public wxScrolledWindow { public: - JobManagerView (wxWindow *); - - void update (); + enum Buttons { + PAUSE = 0x1, + }; + + JobManagerView (wxWindow *, Buttons); private: - void periodic (wxTimerEvent &); + void job_added (boost::weak_ptr<Job>); + void periodic (); - boost::shared_ptr<wxTimer> _timer; wxPanel* _panel; wxFlexGridSizer* _table; - struct JobRecord { - wxGauge* gauge; - wxStaticText* message; - bool finalised; - }; + boost::shared_ptr<wxTimer> _timer; - std::map<boost::shared_ptr<Job>, JobRecord> _job_records; + std::list<boost::shared_ptr<JobRecord> > _job_records; + Buttons _buttons; }; diff --git a/src/wx/job_wrapper.cc b/src/wx/job_wrapper.cc index f2056cf49..df4aa7d2e 100644 --- a/src/wx/job_wrapper.cc +++ b/src/wx/job_wrapper.cc @@ -26,17 +26,17 @@ using boost::shared_ptr; void -JobWrapper::make_dcp (wxWindow* parent, shared_ptr<Film> film, bool transcode) +JobWrapper::make_dcp (wxWindow* parent, shared_ptr<Film> film) { if (!film) { return; } try { - film->make_dcp (transcode); + film->make_dcp (); } catch (BadSettingError& e) { - error_dialog (parent, String::compose ("Bad setting for %1 (%2)", e.setting(), e.what ())); + error_dialog (parent, wxString::Format (_("Bad setting for %s (%s)"), std_to_wx(e.setting()).data(), std_to_wx(e.what()).data())); } catch (std::exception& e) { - error_dialog (parent, String::compose ("Could not make DCP: %1", e.what ())); + error_dialog (parent, wxString::Format (_("Could not make DCP: %s"), std_to_wx(e.what()).data())); } } diff --git a/src/wx/job_wrapper.h b/src/wx/job_wrapper.h index 7120e9f10..b0a4693dd 100644 --- a/src/wx/job_wrapper.h +++ b/src/wx/job_wrapper.h @@ -24,6 +24,6 @@ class Film; namespace JobWrapper { -void make_dcp (wxWindow *, boost::shared_ptr<Film>, bool); +void make_dcp (wxWindow *, boost::shared_ptr<Film>); } diff --git a/src/wx/kdm_dialog.cc b/src/wx/kdm_dialog.cc index d94c13057..a9f63cffc 100644 --- a/src/wx/kdm_dialog.cc +++ b/src/wx/kdm_dialog.cc @@ -43,9 +43,6 @@ KDMDialog::KDMDialog (wxWindow* parent) : wxDialog (parent, wxID_ANY, _("Make KDMs")) { wxBoxSizer* vertical = new wxBoxSizer (wxVERTICAL); - - add_label_to_sizer (vertical, this, "Make KDMs for"); - wxBoxSizer* targets = new wxBoxSizer (wxHORIZONTAL); _targets = new wxTreeCtrl (this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTR_HIDE_ROOT | wxTR_MULTIPLE | wxTR_HAS_BUTTONS); @@ -63,37 +60,37 @@ KDMDialog::KDMDialog (wxWindow* parent) wxBoxSizer* target_buttons = new wxBoxSizer (wxVERTICAL); _add_cinema = new wxButton (this, wxID_ANY, _("Add Cinema...")); - target_buttons->Add (_add_cinema, 1, 0, 6); + target_buttons->Add (_add_cinema, 1, wxEXPAND, 6); _edit_cinema = new wxButton (this, wxID_ANY, _("Edit Cinema...")); - target_buttons->Add (_edit_cinema, 1, 0, 6); + target_buttons->Add (_edit_cinema, 1, wxEXPAND, 6); _remove_cinema = new wxButton (this, wxID_ANY, _("Remove Cinema")); - target_buttons->Add (_remove_cinema, 1, 0, 6); + target_buttons->Add (_remove_cinema, 1, wxEXPAND, 6); _add_screen = new wxButton (this, wxID_ANY, _("Add Screen...")); - target_buttons->Add (_add_screen, 1, 0, 6); + target_buttons->Add (_add_screen, 1, wxEXPAND, 6); _edit_screen = new wxButton (this, wxID_ANY, _("Edit Screen...")); - target_buttons->Add (_edit_screen, 1, 0, 6); + target_buttons->Add (_edit_screen, 1, wxEXPAND, 6); _remove_screen = new wxButton (this, wxID_ANY, _("Remove Screen")); - target_buttons->Add (_remove_screen, 1, 0, 6); + target_buttons->Add (_remove_screen, 1, wxEXPAND, 6); targets->Add (target_buttons, 0, 0, 6); vertical->Add (targets, 1, wxEXPAND | wxALL, 6); wxFlexGridSizer* table = new wxFlexGridSizer (3, 2, 6); - add_label_to_sizer (table, this, "From"); + add_label_to_sizer (table, this, "From", true); _from_date = new wxDatePickerCtrl (this, wxID_ANY); table->Add (_from_date, 1, wxEXPAND); _from_time = new wxTimePickerCtrl (this, wxID_ANY); table->Add (_from_time, 1, wxEXPAND); - add_label_to_sizer (table, this, "Until"); + add_label_to_sizer (table, this, "Until", true); _until_date = new wxDatePickerCtrl (this, wxID_ANY); table->Add (_until_date, 1, wxEXPAND); _until_time = new wxTimePickerCtrl (this, wxID_ANY); table->Add (_until_time, 1, wxEXPAND); - add_label_to_sizer (table, this, "Write to"); + add_label_to_sizer (table, this, "Write to", true); #ifdef __WXMSW__ _folder = new DirPickerCtrl (this); @@ -105,7 +102,7 @@ KDMDialog::KDMDialog (wxWindow* parent) vertical->Add (table, 0, wxEXPAND | wxALL, 6); - wxSizer* buttons = CreateSeparatedButtonSizer (wxOK); + wxSizer* buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL); if (buttons) { vertical->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); } diff --git a/src/wx/new_film_dialog.cc b/src/wx/new_film_dialog.cc index eb6f2849b..6a8935232 100644 --- a/src/wx/new_film_dialog.cc +++ b/src/wx/new_film_dialog.cc @@ -21,35 +21,43 @@ #include <wx/stdpaths.h> #include "lib/config.h" #include "new_film_dialog.h" -#ifdef __WXMSW__ +#include "wx_util.h" +#ifdef DCPOMATIC_USE_OWN_DIR_PICKER #include "dir_picker_ctrl.h" #endif -#include "wx_util.h" using namespace std; using namespace boost; +boost::optional<string> NewFilmDialog::_directory; + NewFilmDialog::NewFilmDialog (wxWindow* parent) - : wxDialog (parent, wxID_ANY, wxString (_("New Film"))) + : wxDialog (parent, wxID_ANY, _("New Film")) { wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); SetSizer (overall_sizer); - wxFlexGridSizer* table = new wxFlexGridSizer (2, 6, 6); + wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); table->AddGrowableCol (1, 1); - overall_sizer->Add (table, 1, wxEXPAND | wxALL, 6); + overall_sizer->Add (table, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); - add_label_to_sizer (table, this, "Film name"); + add_label_to_sizer (table, this, _("Film name"), true); _name = new wxTextCtrl (this, wxID_ANY); - table->Add (_name, 1, wxEXPAND); + table->Add (_name, 0, wxEXPAND); - add_label_to_sizer (table, this, "Create in folder"); -#ifdef __WXMSW__ - _folder = new DirPickerCtrl (this); + add_label_to_sizer (table, this, _("Create in folder"), true); + +#ifdef DCPOMATIC_USE_OWN_DIR_PICKER + _folder = new DirPickerCtrl (this); #else - _folder = new wxDirPickerCtrl (this, wxDD_DIR_MUST_EXIST); + _folder = new wxDirPickerCtrl (this, wxID_ANY); #endif - _folder->SetPath (std_to_wx (Config::instance()->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())))); + + if (!_directory) { + _directory = Config::instance()->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())); + } + + _folder->SetPath (std_to_wx (_directory.get())); table->Add (_folder, 1, wxEXPAND); wxSizer* buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL); @@ -61,6 +69,11 @@ NewFilmDialog::NewFilmDialog (wxWindow* parent) overall_sizer->SetSizeHints (this); } +NewFilmDialog::~NewFilmDialog () +{ + _directory = wx_to_std (_folder->GetPath ()); +} + string NewFilmDialog::get_path () const { diff --git a/src/wx/new_film_dialog.h b/src/wx/new_film_dialog.h index 3d1253ecc..f8f3aa08d 100644 --- a/src/wx/new_film_dialog.h +++ b/src/wx/new_film_dialog.h @@ -19,6 +19,7 @@ #include <wx/wx.h> #include <wx/filepicker.h> +#include "wx_util.h" class DirPickerCtrl; @@ -26,14 +27,16 @@ class NewFilmDialog : public wxDialog { public: NewFilmDialog (wxWindow *); + ~NewFilmDialog (); std::string get_path () const; private: wxTextCtrl* _name; -#ifdef __WXMSW__ +#ifdef DCPOMATIC_USE_OWN_DIR_PICKER DirPickerCtrl* _folder; -#else +#else wxDirPickerCtrl* _folder; #endif + static boost::optional<std::string> _directory; }; diff --git a/src/wx/po/es_ES.po b/src/wx/po/es_ES.po new file mode 100644 index 000000000..08a1fde08 --- /dev/null +++ b/src/wx/po/es_ES.po @@ -0,0 +1,673 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: libdcpomatic-wx\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-07-15 22:07+0100\n" +"PO-Revision-Date: 2013-04-02 19:08-0500\n" +"Last-Translator: Manuel AC <manuel.acevedo@civantos.>\n" +"Language-Team: Manuel AC <manuel.acevedo@civantos.com>\n" +"Language: es-ES\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 1.5.5\n" + +#: src/wx/film_editor.cc:426 src/wx/film_editor.cc:435 +msgid "%" +msgstr "%" + +#: src/wx/about_dialog.cc:77 +msgid "" +"(C) 2012-2013 Carl Hetherington, Terrence Meiczinger, Paul Davis, Ole Laursen" +msgstr "" + +#: src/wx/config_dialog.cc:96 +msgid "(restart DCP-o-matic to see language changes)" +msgstr "" + +#: src/wx/film_editor.cc:1423 +msgid "1 channel" +msgstr "1 canal" + +#: src/wx/about_dialog.cc:30 +#, fuzzy +msgid "About DCP-o-matic" +msgstr "DCP-o-matic" + +#: src/wx/config_dialog.cc:299 +msgid "Add" +msgstr "Añadir" + +#: src/wx/film_editor.cc:317 +msgid "Add..." +msgstr "" + +#: src/wx/audio_dialog.cc:32 src/wx/film_editor.cc:343 +msgid "Audio" +msgstr "Audio" + +#: src/wx/film_editor.cc:379 +msgid "Audio Delay" +msgstr "Retardo del audio" + +#: src/wx/film_editor.cc:367 +msgid "Audio Gain" +msgstr "Ganancia del audio" + +#: src/wx/dci_metadata_dialog.cc:33 +msgid "Audio Language (e.g. EN)" +msgstr "Idioma del audio (ej. ES)" + +#: src/wx/film_editor.cc:391 +#, fuzzy +msgid "Audio Stream" +msgstr "Retardo del audio" + +#: src/wx/job_wrapper.cc:38 +#, c-format +msgid "Bad setting for %s (%s)" +msgstr "ConfiguraciĂ³n erronea para %s (%s)" + +#: src/wx/film_editor.cc:264 +msgid "Bottom crop" +msgstr "Recortar abajo" + +#: src/wx/dir_picker_ctrl.cc:38 +msgid "Browse..." +msgstr "Explorar..." + +#: src/wx/gain_calculator_dialog.cc:36 +msgid "But I have to use fader" +msgstr "pero tengo que usar el fader a" + +#: src/wx/audio_mapping_view.cc:192 +msgid "C" +msgstr "" + +#: src/wx/film_editor.cc:376 +msgid "Calculate..." +msgstr "Calcular..." + +#: src/wx/job_manager_view.cc:98 +msgid "Cancel" +msgstr "" + +#: src/wx/audio_dialog.cc:43 +msgid "Channels" +msgstr "Canales" + +#: src/wx/film_editor.cc:1163 +msgid "Choose a file or files" +msgstr "" + +#: src/wx/film_editor.cc:131 +#, fuzzy +msgid "Container" +msgstr "Contenido" + +#: src/wx/film_editor.cc:82 +msgid "Content" +msgstr "Contenido" + +#: src/wx/film_editor.cc:136 +msgid "Content Type" +msgstr "Tipo de contenido" + +#: src/wx/audio_mapping_view.cc:181 +#, fuzzy +msgid "Content channel" +msgstr "1 canal" + +#: src/wx/film_viewer.cc:326 +#, c-format +msgid "Could not decode video for view (%s)" +msgstr "No se pudo decodificar el vĂdeo para mostrarlo (%s)" + +#: src/wx/job_wrapper.cc:40 +#, c-format +msgid "Could not make DCP: %s" +msgstr "No se pudo crear el DCP: %s" + +#: src/wx/new_film_dialog.cc:48 +msgid "Create in folder" +msgstr "Crear en carpeta" + +#: src/wx/config_dialog.cc:260 +#, fuzzy +msgid "Creator" +msgstr "Crear en carpeta" + +#: src/wx/film_editor.cc:1322 +#, c-format +msgid "Cropped to %dx%d (%.2f:1)\n" +msgstr "" + +#: src/wx/dci_metadata_dialog.cc:28 +msgid "DCI name" +msgstr "Nombre DCI" + +#: src/wx/film_editor.cc:84 +msgid "DCP" +msgstr "" + +#: src/wx/film_editor.cc:142 +msgid "DCP Frame Rate" +msgstr "Velocidad DCP" + +#: src/wx/film_editor.cc:115 +msgid "DCP Name" +msgstr "Nombre DCP" + +#: src/wx/film_editor.cc:152 +#, fuzzy +msgid "DCP audio channels" +msgstr "canales" + +#: src/wx/about_dialog.cc:44 src/wx/wx_util.cc:87 src/wx/wx_util.cc:95 +msgid "DCP-o-matic" +msgstr "DCP-o-matic" + +#: src/wx/config_dialog.cc:46 +msgid "DCP-o-matic Preferences" +msgstr "Preferencias DCP-o-matic" + +#: src/wx/audio_dialog.cc:97 +#, fuzzy, c-format +msgid "DCP-o-matic audio - %s" +msgstr "Audio DCP-o-matic - %1" + +#: src/wx/config_dialog.cc:123 +msgid "Default DCI name details" +msgstr "Detalles por defecto del nombre DCI" + +#: src/wx/config_dialog.cc:138 +#, fuzzy +msgid "Default JPEG2000 bandwidth" +msgstr "Ancho de banda JPEG2000" + +#: src/wx/config_dialog.cc:128 +#, fuzzy +msgid "Default container" +msgstr "Tipo de contenido" + +#: src/wx/config_dialog.cc:133 +#, fuzzy +msgid "Default content type" +msgstr "Tipo de contenido" + +#: src/wx/config_dialog.cc:114 +msgid "Default directory for new films" +msgstr "Carpeta por defecto para nuevas pelĂculas" + +#: src/wx/config_dialog.cc:109 +#, fuzzy +msgid "Default duration of still images" +msgstr "Carpeta por defecto para nuevas pelĂculas" + +#: src/wx/film_editor.cc:127 src/wx/job_manager_view.cc:110 +msgid "Details..." +msgstr "Detalles..." + +#: src/wx/properties_dialog.cc:45 +msgid "Disk space required" +msgstr "Espacio requerido en disco" + +#: src/wx/imagemagick_content_dialog.cc:36 +msgid "Duration" +msgstr "DuraciĂ³n" + +#: src/wx/config_dialog.cc:301 +msgid "Edit" +msgstr "Editar" + +#: src/wx/config_dialog.cc:124 src/wx/film_editor.cc:288 +msgid "Edit..." +msgstr "Editar..." + +#: src/wx/config_dialog.cc:55 +#, fuzzy +msgid "Encoding servers" +msgstr "Servidores de codificaciĂ³n" + +#: src/wx/dci_metadata_dialog.cc:53 +msgid "Facility (e.g. DLA)" +msgstr "CompañĂa (ej. DLA)" + +#: src/wx/properties_dialog.cc:36 +msgid "Film Properties" +msgstr "Propiedades de la pelĂcula" + +#: src/wx/new_film_dialog.cc:44 +msgid "Film name" +msgstr "Nombre de la pelĂcula" + +#: src/wx/film_editor.cc:284 src/wx/filter_dialog.cc:32 +msgid "Filters" +msgstr "Filtros" + +#: src/wx/properties_dialog.cc:41 +msgid "Frames" +msgstr "Fotogramas" + +#: src/wx/properties_dialog.cc:49 +msgid "Frames already encoded" +msgstr "Fotogramas ya codificados" + +#: src/wx/about_dialog.cc:60 +msgid "Free, open-source DCP generation from almost anything." +msgstr "" + +#: src/wx/gain_calculator_dialog.cc:27 +msgid "Gain Calculator" +msgstr "Calculadora de ganancia" + +#: src/wx/properties_dialog.cc:56 +msgid "Gb" +msgstr "Gb" + +#: src/wx/server_dialog.cc:36 +msgid "Host name or IP address" +msgstr "Nombre o direcciĂ³n IP" + +#: src/wx/film_editor.cc:1427 +msgid "Hz" +msgstr "Hz" + +#: src/wx/gain_calculator_dialog.cc:32 +msgid "I want to play this back at fader" +msgstr "Quiero reproducir con el fader a" + +#: src/wx/config_dialog.cc:217 src/wx/config_dialog.cc:288 +msgid "IP address" +msgstr "DirecciĂ³n IP" + +#: src/wx/imagemagick_content_dialog.cc:29 +msgid "Image" +msgstr "" + +#: src/wx/config_dialog.cc:256 +msgid "Issuer" +msgstr "" + +#: src/wx/film_editor.cc:158 +msgid "JPEG2000 bandwidth" +msgstr "Ancho de banda JPEG2000" + +#: src/wx/audio_mapping_view.cc:184 +msgid "L" +msgstr "" + +#: src/wx/film_editor.cc:249 +msgid "Left crop" +msgstr "Recorte izquierda" + +#: src/wx/film_editor.cc:460 +msgid "Length" +msgstr "Longitud" + +#: src/wx/audio_mapping_view.cc:196 +msgid "Lfe" +msgstr "" + +#: src/wx/film_editor.cc:330 +msgid "Loop everything" +msgstr "" + +#: src/wx/audio_mapping_view.cc:200 +#, fuzzy +msgid "Ls" +msgstr "s" + +#: src/wx/config_dialog.cc:141 src/wx/film_editor.cc:162 +msgid "MBps" +msgstr "MBps" + +#: src/wx/config_dialog.cc:57 +msgid "Metadata" +msgstr "" + +#: src/wx/config_dialog.cc:53 +msgid "Miscellaneous" +msgstr "" + +#: src/wx/dir_picker_ctrl.cc:52 +msgid "My Documents" +msgstr "Mis documentos" + +#: src/wx/film_editor.cc:110 +msgid "Name" +msgstr "Nombre" + +#: src/wx/new_film_dialog.cc:35 +msgid "New Film" +msgstr "Nueva pelĂcula" + +#: src/wx/film_editor.cc:286 src/wx/film_editor.cc:769 +msgid "None" +msgstr "Ninguno" + +#: src/wx/film_editor.cc:1309 +#, c-format +msgid "Original video is %dx%d (%.2f:1)\n" +msgstr "" + +#: src/wx/dci_metadata_dialog.cc:57 +msgid "Package Type (e.g. OV)" +msgstr "Tipo de paquete (ej. OV)" + +#: src/wx/film_editor.cc:1343 +#, c-format +msgid "Padded with black to %dx%d (%.2f:1)\n" +msgstr "" + +#: src/wx/config_dialog.cc:229 +#, fuzzy +msgid "Password" +msgstr "Clave del TMS" + +#: src/wx/job_manager_view.cc:104 src/wx/job_manager_view.cc:206 +msgid "Pause" +msgstr "" + +#: src/wx/audio_dialog.cc:59 +msgid "Peak" +msgstr "Pico" + +#: src/wx/film_viewer.cc:64 +msgid "Play" +msgstr "Reproducir" + +#: src/wx/audio_plot.cc:110 +msgid "Please wait; audio is being analysed..." +msgstr "Por favor espere, el audio estĂ¡ siendo analizado..." + +#: src/wx/audio_mapping_view.cc:188 +msgid "R" +msgstr "" + +#: src/wx/audio_dialog.cc:60 +msgid "RMS" +msgstr "RMS" + +#: src/wx/dci_metadata_dialog.cc:45 +msgid "Rating (e.g. 15)" +msgstr "ClasificaciĂ³n (ej. 16)" + +#: src/wx/config_dialog.cc:303 src/wx/film_editor.cc:319 +msgid "Remove" +msgstr "Quitar" + +#: src/wx/job_manager_view.cc:209 +msgid "Resume" +msgstr "" + +#: src/wx/film_editor.cc:254 +msgid "Right crop" +msgstr "Recorte derecha" + +#: src/wx/audio_mapping_view.cc:204 +#, fuzzy +msgid "Rs" +msgstr "s" + +#: src/wx/job_manager_view.cc:128 +msgid "Running" +msgstr "Ejecutando" + +#: src/wx/film_editor.cc:269 +#, fuzzy +msgid "Scale to" +msgstr "Escalador" + +#: src/wx/film_editor.cc:1335 +#, c-format +msgid "Scaled to %dx%d (%.2f:1)\n" +msgstr "" + +#: src/wx/film_editor.cc:167 +msgid "Scaler" +msgstr "Escalador" + +#: src/wx/server_dialog.cc:25 +msgid "Server" +msgstr "Servidor" + +#: src/wx/config_dialog.cc:85 +msgid "Set language" +msgstr "" + +#: src/wx/film_editor.cc:362 +msgid "Show Audio..." +msgstr "Mostrar audio..." + +#: src/wx/audio_dialog.cc:70 +msgid "Smoothing" +msgstr "Suavizado" + +#: src/wx/film_editor.cc:457 +#, fuzzy +msgid "Start time" +msgstr "Inicio" + +#: src/wx/dci_metadata_dialog.cc:49 +msgid "Studio (e.g. TCF)" +msgstr "Estudio (ej. TCF)" + +#: src/wx/dci_metadata_dialog.cc:37 +msgid "Subtitle Language (e.g. FR)" +msgstr "Idioma del subtĂtulo (ej. EN)" + +#: src/wx/film_editor.cc:422 +msgid "Subtitle Offset" +msgstr "Desplazamiento del subtĂtulo" + +#: src/wx/film_editor.cc:431 +msgid "Subtitle Scale" +msgstr "Escala del subtĂtulo" + +#: src/wx/film_editor.cc:439 +#, fuzzy +msgid "Subtitle Stream" +msgstr "Escala del subtĂtulo" + +#: src/wx/film_editor.cc:345 +msgid "Subtitles" +msgstr "SubtĂtulos" + +#: src/wx/about_dialog.cc:120 +msgid "Supported by" +msgstr "" + +#: src/wx/config_dialog.cc:59 +#, fuzzy +msgid "TMS" +msgstr "RMS" + +#: src/wx/config_dialog.cc:221 +#, fuzzy +msgid "Target path" +msgstr "Ruta en el TMS" + +#: src/wx/dci_metadata_dialog.cc:41 +msgid "Territory (e.g. UK)" +msgstr "Territorio (ej. ES)" + +#: src/wx/config_dialog.cc:292 +msgid "Threads" +msgstr "Hilos" + +#: src/wx/server_dialog.cc:40 +msgid "Threads to use" +msgstr "Hilos a utilizar" + +#: src/wx/config_dialog.cc:104 +msgid "Threads to use for encoding on this host" +msgstr "Hilos a utilizar para la codificaciĂ³n en esta mĂ¡quina" + +#: src/wx/audio_plot.cc:140 +msgid "Time" +msgstr "Tiempo" + +#: src/wx/timeline_dialog.cc:32 +#, fuzzy +msgid "Timeline" +msgstr "Tiempo" + +#: src/wx/film_editor.cc:321 +msgid "Timeline..." +msgstr "" + +#: src/wx/film_editor.cc:347 +msgid "Timing" +msgstr "" + +#: src/wx/film_editor.cc:259 +msgid "Top crop" +msgstr "Recortar arriba" + +#: src/wx/about_dialog.cc:99 +msgid "Translated by" +msgstr "" + +#: src/wx/audio_dialog.cc:54 +msgid "Type" +msgstr "Tipo" + +#: src/wx/film_editor.cc:125 +msgid "Use DCI name" +msgstr "Usar el nombre DCI" + +#: src/wx/film_editor.cc:146 +msgid "Use best" +msgstr "Usar la mejor" + +#: src/wx/config_dialog.cc:225 +#, fuzzy +msgid "User name" +msgstr "Usar el nombre DCI" + +#: src/wx/film_editor.cc:341 +msgid "Video" +msgstr "VĂdeo" + +#: src/wx/film_editor.cc:417 +msgid "With Subtitles" +msgstr "Con subtĂtulos" + +#: src/wx/about_dialog.cc:90 +msgid "Written by" +msgstr "" + +#: src/wx/timeline.cc:200 +#, fuzzy +msgid "audio" +msgstr "Audio" + +#: src/wx/film_editor.cc:1425 +msgid "channels" +msgstr "canales" + +#: src/wx/properties_dialog.cc:50 +msgid "counting..." +msgstr "contando..." + +#: src/wx/film_editor.cc:372 +msgid "dB" +msgstr "dB" + +#. / TRANSLATORS: this is an abbreviation for milliseconds, the unit of time +#: src/wx/film_editor.cc:385 +msgid "ms" +msgstr "ms" + +#. / TRANSLATORS: this is an abbreviation for seconds, the unit of time +#: src/wx/config_dialog.cc:112 src/wx/imagemagick_content_dialog.cc:41 +msgid "s" +msgstr "s" + +#: src/wx/film_editor.cc:334 +msgid "times" +msgstr "" + +#: src/wx/timeline.cc:220 +#, fuzzy +msgid "video" +msgstr "VĂdeo" + +#~ msgid "A/B" +#~ msgstr "A/B" + +#~ msgid "Colour look-up table" +#~ msgstr "Tabla de referencia de colores" + +#~ msgid "Could not open content file (%s)" +#~ msgstr "No se pudo abrir el fichero (%s)" + +#~ msgid "Could not set content: %s" +#~ msgstr "No se pudo establecer el contenido: %s" + +#, fuzzy +#~ msgid "DVD-o-matic Preferences" +#~ msgstr "Preferencias DVD-o-matic" + +#~ msgid "End" +#~ msgstr "Fin" + +#~ msgid "Film" +#~ msgstr "PelĂcula" + +#~ msgid "Format" +#~ msgstr "Formato" + +#~ msgid "Original Frame Rate" +#~ msgstr "Velocidad original" + +#, fuzzy +#~ msgid "Reference filters" +#~ msgstr "Filtros de referencia para A/B" + +#, fuzzy +#~ msgid "Reference scaler" +#~ msgstr "Escalador de referencia para A/B" + +#~ msgid "Select Audio File" +#~ msgstr "Seleccionar fichero de audio" + +#~ msgid "Select Content File" +#~ msgstr "Seleccionar fichero de contenido" + +#~ msgid "Trim frames" +#~ msgstr "Recortar fotogramas" + +#, fuzzy +#~ msgid "Trim method" +#~ msgstr "Recortar fotogramas" + +#~ msgid "Trust content's header" +#~ msgstr "Confiar en la cabecera del contenido" + +#~ msgid "Use content's audio" +#~ msgstr "Usar el audio del contenido" + +#~ msgid "Use external audio" +#~ msgstr "Usar audio externo" + +#~ msgid "frames" +#~ msgstr "fotogramas" + +#~ msgid "unknown" +#~ msgstr "desconocido" + +#~ msgid "TMS IP address" +#~ msgstr "DirecciĂ³n IP del TMS" + +#~ msgid "TMS user name" +#~ msgstr "Usuario del TMS" + +#~ msgid "Original Size" +#~ msgstr "Tamaño original" diff --git a/src/wx/po/fr_FR.po b/src/wx/po/fr_FR.po new file mode 100644 index 000000000..1c0a02d4f --- /dev/null +++ b/src/wx/po/fr_FR.po @@ -0,0 +1,676 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: DCP-o-matic FRENCH\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-07-15 22:07+0100\n" +"PO-Revision-Date: 2013-07-16 23:21+0100\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/wx/film_editor.cc:426 +#: src/wx/film_editor.cc:435 +msgid "%" +msgstr "%" + +#: src/wx/about_dialog.cc:77 +msgid "(C) 2012-2013 Carl Hetherington, Terrence Meiczinger, Paul Davis, Ole Laursen" +msgstr "(C) 2012-2013 Carl Hetherington, Terrence Meiczinger, Paul Davis, Ole Laursen" + +#: src/wx/config_dialog.cc:96 +msgid "(restart DCP-o-matic to see language changes)" +msgstr "(redĂ©marrez DCP-o-matic pour que les changements de langue prennent effet)" + +#: src/wx/film_editor.cc:1423 +msgid "1 channel" +msgstr "1 canal" + +#: src/wx/about_dialog.cc:30 +msgid "About DCP-o-matic" +msgstr "Ă€ propos de DCP-o-matic" + +#: src/wx/config_dialog.cc:299 +msgid "Add" +msgstr "Ajouter" + +#: src/wx/film_editor.cc:317 +msgid "Add..." +msgstr "Ajouter..." + +#: src/wx/audio_dialog.cc:32 +#: src/wx/film_editor.cc:343 +msgid "Audio" +msgstr "Audio" + +#: src/wx/film_editor.cc:379 +msgid "Audio Delay" +msgstr "DĂ©lai audio" + +#: src/wx/film_editor.cc:367 +msgid "Audio Gain" +msgstr "Gain audio" + +#: src/wx/dci_metadata_dialog.cc:33 +msgid "Audio Language (e.g. EN)" +msgstr "Langue audio (ex. FR)" + +#: src/wx/film_editor.cc:391 +msgid "Audio Stream" +msgstr "Flux audio" + +#: src/wx/job_wrapper.cc:38 +#, c-format +msgid "Bad setting for %s (%s)" +msgstr "Mauvais paramètre pour %s (%s)" + +#: src/wx/film_editor.cc:264 +msgid "Bottom crop" +msgstr "DĂ©coupe bas" + +#: src/wx/dir_picker_ctrl.cc:38 +msgid "Browse..." +msgstr "Parcourir..." + +#: src/wx/gain_calculator_dialog.cc:36 +msgid "But I have to use fader" +msgstr "Je souhaite utiliser ce volume" + +#: src/wx/audio_mapping_view.cc:192 +msgid "C" +msgstr "C" + +#: src/wx/film_editor.cc:376 +msgid "Calculate..." +msgstr "Calcul..." + +#: src/wx/job_manager_view.cc:98 +msgid "Cancel" +msgstr "Annuler" + +#: src/wx/audio_dialog.cc:43 +msgid "Channels" +msgstr "Canaux" + +#: src/wx/film_editor.cc:1163 +msgid "Choose a file or files" +msgstr "Choisissez un ou plusieurs fichiers" + +#: src/wx/film_editor.cc:131 +msgid "Container" +msgstr "Contenu" + +#: src/wx/film_editor.cc:82 +msgid "Content" +msgstr "Contenu" + +#: src/wx/film_editor.cc:136 +msgid "Content Type" +msgstr "Type de Contenu" + +#: src/wx/audio_mapping_view.cc:181 +msgid "Content channel" +msgstr "Contenu audio" + +#: src/wx/film_viewer.cc:326 +#, c-format +msgid "Could not decode video for view (%s)" +msgstr "DĂ©codage de la vidĂ©o pour visualisation impossible (%s)" + +#: src/wx/job_wrapper.cc:40 +#, c-format +msgid "Could not make DCP: %s" +msgstr "Impossible de crĂ©er le DCP : %s" + +#: src/wx/new_film_dialog.cc:48 +msgid "Create in folder" +msgstr "CrĂ©er dans le dossier" + +#: src/wx/config_dialog.cc:260 +msgid "Creator" +msgstr "CrĂ©ateur" + +#: src/wx/film_editor.cc:1322 +#, c-format +msgid "Cropped to %dx%d (%.2f:1)\n" +msgstr "DĂ©coupe de %dx%d (%.2f:1)\n" + +#: src/wx/dci_metadata_dialog.cc:28 +msgid "DCI name" +msgstr "Nom DCI" + +#: src/wx/film_editor.cc:84 +msgid "DCP" +msgstr "DCP" + +#: src/wx/film_editor.cc:142 +msgid "DCP Frame Rate" +msgstr "Cadence image du DCP" + +#: src/wx/film_editor.cc:115 +msgid "DCP Name" +msgstr "Nom du DCP" + +#: src/wx/film_editor.cc:152 +msgid "DCP audio channels" +msgstr "canaux audios du DCP" + +#: src/wx/about_dialog.cc:44 +#: src/wx/wx_util.cc:87 +#: src/wx/wx_util.cc:95 +msgid "DCP-o-matic" +msgstr "DCP-o-matic" + +#: src/wx/config_dialog.cc:46 +msgid "DCP-o-matic Preferences" +msgstr "PrĂ©fĂ©rences DCP-o-matic" + +#: src/wx/audio_dialog.cc:97 +#, c-format +msgid "DCP-o-matic audio - %s" +msgstr "Son DCP-o-matic - %s" + +#: src/wx/config_dialog.cc:123 +msgid "Default DCI name details" +msgstr "DĂ©tails du nom DCI par dĂ©faut" + +#: src/wx/config_dialog.cc:138 +msgid "Default JPEG2000 bandwidth" +msgstr "QualitĂ© JPEG2000 par dĂ©faut" + +#: src/wx/config_dialog.cc:128 +msgid "Default container" +msgstr "Type de contenu par dĂ©faut" + +#: src/wx/config_dialog.cc:133 +msgid "Default content type" +msgstr "Type de contenu par dĂ©faut" + +#: src/wx/config_dialog.cc:114 +msgid "Default directory for new films" +msgstr "Dossier par dĂ©faut des nouveaux films" + +#: src/wx/config_dialog.cc:109 +msgid "Default duration of still images" +msgstr "DurĂ©e par dĂ©faut des images fixes" + +#: src/wx/film_editor.cc:127 +#: src/wx/job_manager_view.cc:110 +msgid "Details..." +msgstr "DĂ©tails..." + +#: src/wx/properties_dialog.cc:45 +msgid "Disk space required" +msgstr "Espace disque requis" + +#: src/wx/imagemagick_content_dialog.cc:36 +msgid "Duration" +msgstr "DurĂ©e" + +#: src/wx/config_dialog.cc:301 +msgid "Edit" +msgstr "Édition" + +#: src/wx/config_dialog.cc:124 +#: src/wx/film_editor.cc:288 +msgid "Edit..." +msgstr "Éditer..." + +#: src/wx/config_dialog.cc:55 +msgid "Encoding servers" +msgstr "Serveurs d'encodage" + +#: src/wx/dci_metadata_dialog.cc:53 +msgid "Facility (e.g. DLA)" +msgstr "Laboratoire (ex. DLA)" + +#: src/wx/properties_dialog.cc:36 +msgid "Film Properties" +msgstr "PropriĂ©tĂ©s du film" + +#: src/wx/new_film_dialog.cc:44 +msgid "Film name" +msgstr "Nom du Film" + +#: src/wx/film_editor.cc:284 +#: src/wx/filter_dialog.cc:32 +msgid "Filters" +msgstr "Filtres" + +#: src/wx/properties_dialog.cc:41 +msgid "Frames" +msgstr "Images" + +#: src/wx/properties_dialog.cc:49 +msgid "Frames already encoded" +msgstr "Images dĂ©jĂ encodĂ©es" + +#: src/wx/about_dialog.cc:60 +msgid "Free, open-source DCP generation from almost anything." +msgstr "CrĂ©ation de DCP libre et gratuit depuis presque tout." + +#: src/wx/gain_calculator_dialog.cc:27 +msgid "Gain Calculator" +msgstr "Calculateur de gain" + +#: src/wx/properties_dialog.cc:56 +msgid "Gb" +msgstr "Gb" + +#: src/wx/server_dialog.cc:36 +msgid "Host name or IP address" +msgstr "Nom de l'hĂ´te ou adresse IP" + +#: src/wx/film_editor.cc:1427 +msgid "Hz" +msgstr "Hz" + +#: src/wx/gain_calculator_dialog.cc:32 +msgid "I want to play this back at fader" +msgstr "Je veux le jouer Ă ce volume" + +#: src/wx/config_dialog.cc:217 +#: src/wx/config_dialog.cc:288 +msgid "IP address" +msgstr "Adresse IP" + +#: src/wx/imagemagick_content_dialog.cc:29 +msgid "Image" +msgstr "Image" + +#: src/wx/config_dialog.cc:256 +msgid "Issuer" +msgstr "Emetteur" + +#: src/wx/film_editor.cc:158 +msgid "JPEG2000 bandwidth" +msgstr "QualitĂ© JPEG2000" + +#: src/wx/audio_mapping_view.cc:184 +msgid "L" +msgstr "L" + +#: src/wx/film_editor.cc:249 +msgid "Left crop" +msgstr "DĂ©coupe gauche" + +#: src/wx/film_editor.cc:460 +msgid "Length" +msgstr "Longueur / durĂ©e" + +#: src/wx/audio_mapping_view.cc:196 +msgid "Lfe" +msgstr "Lfe" + +#: src/wx/film_editor.cc:330 +msgid "Loop everything" +msgstr "Tout mettre en boucle" + +#: src/wx/audio_mapping_view.cc:200 +msgid "Ls" +msgstr "Ls" + +#: src/wx/config_dialog.cc:141 +#: src/wx/film_editor.cc:162 +msgid "MBps" +msgstr "MBps" + +#: src/wx/config_dialog.cc:57 +msgid "Metadata" +msgstr "MĂ©tadonnĂ©es" + +#: src/wx/config_dialog.cc:53 +msgid "Miscellaneous" +msgstr "Divers" + +#: src/wx/dir_picker_ctrl.cc:52 +msgid "My Documents" +msgstr "Mes Documents" + +#: src/wx/film_editor.cc:110 +msgid "Name" +msgstr "Nom" + +#: src/wx/new_film_dialog.cc:35 +msgid "New Film" +msgstr "Nouveau Film" + +#: src/wx/film_editor.cc:286 +#: src/wx/film_editor.cc:769 +msgid "None" +msgstr "Aucun" + +#: src/wx/film_editor.cc:1309 +#, c-format +msgid "Original video is %dx%d (%.2f:1)\n" +msgstr "La vidĂ©o originale est %dx%d (%.2f:1)\n" + +#: src/wx/dci_metadata_dialog.cc:57 +msgid "Package Type (e.g. OV)" +msgstr "Type de paquet (ex. OV)" + +#: src/wx/film_editor.cc:1343 +#, c-format +msgid "Padded with black to %dx%d (%.2f:1)\n" +msgstr "Enveloppe noire de %dx%d (%.2f:1)\n" + +#: src/wx/config_dialog.cc:229 +msgid "Password" +msgstr "Mot de passe" + +#: src/wx/job_manager_view.cc:104 +#: src/wx/job_manager_view.cc:206 +msgid "Pause" +msgstr "Pause" + +#: src/wx/audio_dialog.cc:59 +msgid "Peak" +msgstr "CrĂªte" + +#: src/wx/film_viewer.cc:64 +msgid "Play" +msgstr "Lecture" + +#: src/wx/audio_plot.cc:110 +msgid "Please wait; audio is being analysed..." +msgstr "Merci de patienter ; analyse de la piste son..." + +#: src/wx/audio_mapping_view.cc:188 +msgid "R" +msgstr "R" + +#: src/wx/audio_dialog.cc:60 +msgid "RMS" +msgstr "RMS" + +#: src/wx/dci_metadata_dialog.cc:45 +msgid "Rating (e.g. 15)" +msgstr "Rating (ex. 15)" + +#: src/wx/config_dialog.cc:303 +#: src/wx/film_editor.cc:319 +msgid "Remove" +msgstr "Supprimer" + +#: src/wx/job_manager_view.cc:209 +msgid "Resume" +msgstr "Reprendre" + +#: src/wx/film_editor.cc:254 +msgid "Right crop" +msgstr "DĂ©coupe droite" + +#: src/wx/audio_mapping_view.cc:204 +msgid "Rs" +msgstr "Rs" + +#: src/wx/job_manager_view.cc:128 +msgid "Running" +msgstr "Progression" + +#: src/wx/film_editor.cc:269 +msgid "Scale to" +msgstr "Mise Ă l'Ă©chelle" + +#: src/wx/film_editor.cc:1335 +#, c-format +msgid "Scaled to %dx%d (%.2f:1)\n" +msgstr "Mis Ă l'Ă©chelle de %dx%d (%.2f:1)\n" + +#: src/wx/film_editor.cc:167 +msgid "Scaler" +msgstr "Mise Ă l'Ă©chelle" + +#: src/wx/server_dialog.cc:25 +msgid "Server" +msgstr "Serveur" + +#: src/wx/config_dialog.cc:85 +msgid "Set language" +msgstr "Selectionnez la langue" + +#: src/wx/film_editor.cc:362 +msgid "Show Audio..." +msgstr "Analyser le son..." + +#: src/wx/audio_dialog.cc:70 +msgid "Smoothing" +msgstr "Lissage" + +#: src/wx/film_editor.cc:457 +msgid "Start time" +msgstr "DĂ©but" + +#: src/wx/dci_metadata_dialog.cc:49 +msgid "Studio (e.g. TCF)" +msgstr "Studio (ex. TCF)" + +#: src/wx/dci_metadata_dialog.cc:37 +msgid "Subtitle Language (e.g. FR)" +msgstr "Langue de sous-titres (ex. FR)" + +#: src/wx/film_editor.cc:422 +msgid "Subtitle Offset" +msgstr "DĂ©calage du sous-titre" + +#: src/wx/film_editor.cc:431 +msgid "Subtitle Scale" +msgstr "Taille du sous-titre" + +#: src/wx/film_editor.cc:439 +msgid "Subtitle Stream" +msgstr "Flux de sous-titre" + +#: src/wx/film_editor.cc:345 +msgid "Subtitles" +msgstr "Sous-titres" + +#: src/wx/about_dialog.cc:120 +msgid "Supported by" +msgstr "Soutenu par" + +#: src/wx/config_dialog.cc:59 +msgid "TMS" +msgstr "TMS" + +#: src/wx/config_dialog.cc:221 +msgid "Target path" +msgstr "Chemin d'accès" + +#: src/wx/dci_metadata_dialog.cc:41 +msgid "Territory (e.g. UK)" +msgstr "Territoire (ex. FR)" + +#: src/wx/config_dialog.cc:292 +msgid "Threads" +msgstr "Processus" + +#: src/wx/server_dialog.cc:40 +msgid "Threads to use" +msgstr "Nombre de processus Ă utiliser" + +#: src/wx/config_dialog.cc:104 +msgid "Threads to use for encoding on this host" +msgstr "Nombre de processus Ă utiliser sur cet hĂ´te" + +#: src/wx/audio_plot.cc:140 +msgid "Time" +msgstr "DurĂ©e" + +#: src/wx/timeline_dialog.cc:32 +msgid "Timeline" +msgstr "Timeline" + +#: src/wx/film_editor.cc:321 +msgid "Timeline..." +msgstr "Timeline..." + +#: src/wx/film_editor.cc:347 +msgid "Timing" +msgstr "" + +#: src/wx/film_editor.cc:259 +msgid "Top crop" +msgstr "DĂ©coupe haut" + +#: src/wx/about_dialog.cc:99 +msgid "Translated by" +msgstr "Traduit par" + +#: src/wx/audio_dialog.cc:54 +msgid "Type" +msgstr "Type" + +#: src/wx/film_editor.cc:125 +msgid "Use DCI name" +msgstr "Utiliser le nom DCI" + +#: src/wx/film_editor.cc:146 +msgid "Use best" +msgstr "Automatique" + +#: src/wx/config_dialog.cc:225 +msgid "User name" +msgstr "Nom d'utilisateur" + +#: src/wx/film_editor.cc:341 +msgid "Video" +msgstr "VidĂ©o" + +#: src/wx/film_editor.cc:417 +msgid "With Subtitles" +msgstr "Avec sous-titres" + +#: src/wx/about_dialog.cc:90 +msgid "Written by" +msgstr "DĂ©veloppĂ© par" + +#: src/wx/timeline.cc:200 +msgid "audio" +msgstr "audio" + +#: src/wx/film_editor.cc:1425 +msgid "channels" +msgstr "canaux" + +#: src/wx/properties_dialog.cc:50 +msgid "counting..." +msgstr "calcul..." + +#: src/wx/film_editor.cc:372 +msgid "dB" +msgstr "dB" + +#. / TRANSLATORS: this is an abbreviation for milliseconds, the unit of time +#: src/wx/film_editor.cc:385 +msgid "ms" +msgstr "ms" + +#. / TRANSLATORS: this is an abbreviation for seconds, the unit of time +#: src/wx/config_dialog.cc:112 +#: src/wx/imagemagick_content_dialog.cc:41 +msgid "s" +msgstr "s" + +#: src/wx/film_editor.cc:334 +msgid "times" +msgstr "" + +#: src/wx/timeline.cc:220 +msgid "video" +msgstr "vidĂ©o" + +#~ msgid "A/B" +#~ msgstr "A/B" + +#~ msgid "A/B mode" +#~ msgstr "A/B mode" + +#~ msgid "Audio will be resampled from %dHz to %dHz\n" +#~ msgstr "L'audio sera rééchantillonnĂ© de %dHz Ă %dHz\n" + +#~ msgid "Colour look-up table" +#~ msgstr "Espace colorimĂ©trique" + +#~ msgid "Could not open content file (%s)" +#~ msgstr "Ouverture du contenu impossible (%s)" + +#~ msgid "Could not set content: %s" +#~ msgstr "SĂ©lectionner du contenu impossible : %s" + +#, fuzzy +#~ msgid "DVD-o-matic Preferences" +#~ msgstr "PrĂ©fĂ©rences de DCP-o-matic" + +#~ msgid "Default format" +#~ msgstr "Format par dĂ©faut" + +#~ msgid "End" +#~ msgstr "Fin" + +#~ msgid "Film" +#~ msgstr "Film" + +#~ msgid "Format" +#~ msgstr "Format" + +#~ msgid "Original Frame Rate" +#~ msgstr "Cadence d'images originale" + +#~ msgid "Reference filters" +#~ msgstr "Filtres de rĂ©fĂ©rence" + +#~ msgid "Reference scaler" +#~ msgstr "Échelle de rĂ©fĂ©rence" + +#~ msgid "Select Audio File" +#~ msgstr "SĂ©lectionner le fichier son" + +#~ msgid "Select Content File" +#~ msgstr "SĂ©lectionner le fichier vidĂ©o" + +#~ msgid "Trim frames" +#~ msgstr "Images coupĂ©es" + +#~ msgid "Trim method" +#~ msgstr "MĂ©thod de dĂ©coupage" + +#~ msgid "Trust content's header" +#~ msgstr "Faire confiance Ă l'en-tĂªte" + +#~ msgid "Use content's audio" +#~ msgstr "Utiliser le son intĂ©grĂ©" + +#~ msgid "Use external audio" +#~ msgstr "Utiliser une source audio externe" + +#~ msgid "encode all frames and play the subset" +#~ msgstr "encoder toutes les images mais lire seulement la sĂ©lection" + +#~ msgid "encode only the subset" +#~ msgstr "encoder seulement la sĂ©lection" + +#~ msgid "frames" +#~ msgstr "images" + +#~ msgid "pixels" +#~ msgstr "pixels" + +#~ msgid "unknown" +#~ msgstr "inconnu" + +#~ msgid "TMS IP address" +#~ msgstr "Adresse IP du TMS" + +#~ msgid "TMS user name" +#~ msgstr "Nom d'utilisateur du TMS" + +#~ msgid "Original Size" +#~ msgstr "Taille Originale" diff --git a/src/wx/po/it_IT.po b/src/wx/po/it_IT.po new file mode 100644 index 000000000..fd5b6502c --- /dev/null +++ b/src/wx/po/it_IT.po @@ -0,0 +1,684 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: IT VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-07-15 22:07+0100\n" +"PO-Revision-Date: 2013-04-28 10:27+0100\n" +"Last-Translator: Maci <macibro@gmail.com>\n" +"Language-Team: \n" +"Language: Italiano\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 1.5.5\n" + +#: src/wx/film_editor.cc:426 src/wx/film_editor.cc:435 +msgid "%" +msgstr "%" + +#: src/wx/about_dialog.cc:77 +msgid "" +"(C) 2012-2013 Carl Hetherington, Terrence Meiczinger, Paul Davis, Ole Laursen" +msgstr "" + +#: src/wx/config_dialog.cc:96 +msgid "(restart DCP-o-matic to see language changes)" +msgstr "(riavviare DCP-o-matic per vedere i cambiamenti di lingua)" + +#: src/wx/film_editor.cc:1423 +msgid "1 channel" +msgstr "1 canale" + +#: src/wx/about_dialog.cc:30 +#, fuzzy +msgid "About DCP-o-matic" +msgstr "DCP-o-matic" + +#: src/wx/config_dialog.cc:299 +msgid "Add" +msgstr "Aggiungi" + +#: src/wx/film_editor.cc:317 +msgid "Add..." +msgstr "" + +#: src/wx/audio_dialog.cc:32 src/wx/film_editor.cc:343 +msgid "Audio" +msgstr "Audio" + +#: src/wx/film_editor.cc:379 +msgid "Audio Delay" +msgstr "Ritardo dell'audio" + +#: src/wx/film_editor.cc:367 +msgid "Audio Gain" +msgstr "Guadagno dell'audio" + +#: src/wx/dci_metadata_dialog.cc:33 +msgid "Audio Language (e.g. EN)" +msgstr "Lingua dell'audio (es. EN)" + +#: src/wx/film_editor.cc:391 +#, fuzzy +msgid "Audio Stream" +msgstr "Ritardo dell'audio" + +#: src/wx/job_wrapper.cc:38 +#, c-format +msgid "Bad setting for %s (%s)" +msgstr "Valore sbagliato per %s (%s)" + +#: src/wx/film_editor.cc:264 +msgid "Bottom crop" +msgstr "Taglio in basso" + +#: src/wx/dir_picker_ctrl.cc:38 +msgid "Browse..." +msgstr "Sfoglia..." + +#: src/wx/gain_calculator_dialog.cc:36 +msgid "But I have to use fader" +msgstr "Ma dovrĂ² riprodurre con il fader a" + +#: src/wx/audio_mapping_view.cc:192 +msgid "C" +msgstr "" + +#: src/wx/film_editor.cc:376 +msgid "Calculate..." +msgstr "Calcola..." + +#: src/wx/job_manager_view.cc:98 +msgid "Cancel" +msgstr "Annulla" + +#: src/wx/audio_dialog.cc:43 +msgid "Channels" +msgstr "Canali" + +#: src/wx/film_editor.cc:1163 +msgid "Choose a file or files" +msgstr "" + +#: src/wx/film_editor.cc:131 +#, fuzzy +msgid "Container" +msgstr "Contenuto" + +#: src/wx/film_editor.cc:82 +msgid "Content" +msgstr "Contenuto" + +#: src/wx/film_editor.cc:136 +msgid "Content Type" +msgstr "Tipo di contenuto" + +#: src/wx/audio_mapping_view.cc:181 +#, fuzzy +msgid "Content channel" +msgstr "1 canale" + +#: src/wx/film_viewer.cc:326 +#, c-format +msgid "Could not decode video for view (%s)" +msgstr "Non posso decodificare il video per guardarlo (%s)" + +#: src/wx/job_wrapper.cc:40 +#, c-format +msgid "Could not make DCP: %s" +msgstr "Non posso creare il DCP: %s" + +#: src/wx/new_film_dialog.cc:48 +msgid "Create in folder" +msgstr "Crea nella cartella" + +#: src/wx/config_dialog.cc:260 +#, fuzzy +msgid "Creator" +msgstr "Crea nella cartella" + +#: src/wx/film_editor.cc:1322 +#, c-format +msgid "Cropped to %dx%d (%.2f:1)\n" +msgstr "Tagliato da %dx%d (%.2f:1)\n" + +#: src/wx/dci_metadata_dialog.cc:28 +msgid "DCI name" +msgstr "Nome del DCP" + +#: src/wx/film_editor.cc:84 +msgid "DCP" +msgstr "" + +#: src/wx/film_editor.cc:142 +msgid "DCP Frame Rate" +msgstr "Frequenza fotogrammi del DCP" + +#: src/wx/film_editor.cc:115 +msgid "DCP Name" +msgstr "Nome del DCP" + +#: src/wx/film_editor.cc:152 +#, fuzzy +msgid "DCP audio channels" +msgstr "canali" + +#: src/wx/about_dialog.cc:44 src/wx/wx_util.cc:87 src/wx/wx_util.cc:95 +msgid "DCP-o-matic" +msgstr "DCP-o-matic" + +#: src/wx/config_dialog.cc:46 +msgid "DCP-o-matic Preferences" +msgstr "Preferenze DCP-o-matic" + +#: src/wx/audio_dialog.cc:97 +#, c-format +msgid "DCP-o-matic audio - %s" +msgstr "Audio DCP-o-matic - %s" + +#: src/wx/config_dialog.cc:123 +msgid "Default DCI name details" +msgstr "Dettagli del nome di default DCI" + +#: src/wx/config_dialog.cc:138 +#, fuzzy +msgid "Default JPEG2000 bandwidth" +msgstr "Banda passante JPEG2000" + +#: src/wx/config_dialog.cc:128 +#, fuzzy +msgid "Default container" +msgstr "Tipo di contenuto" + +#: src/wx/config_dialog.cc:133 +#, fuzzy +msgid "Default content type" +msgstr "Tipo di contenuto" + +#: src/wx/config_dialog.cc:114 +msgid "Default directory for new films" +msgstr "Directory di default per i nuovi films" + +#: src/wx/config_dialog.cc:109 +#, fuzzy +msgid "Default duration of still images" +msgstr "Directory di default per i nuovi films" + +#: src/wx/film_editor.cc:127 src/wx/job_manager_view.cc:110 +msgid "Details..." +msgstr "Dettagli" + +#: src/wx/properties_dialog.cc:45 +msgid "Disk space required" +msgstr "Spazio su disco rischiesto" + +#: src/wx/imagemagick_content_dialog.cc:36 +msgid "Duration" +msgstr "Durata" + +#: src/wx/config_dialog.cc:301 +msgid "Edit" +msgstr "Modifica" + +#: src/wx/config_dialog.cc:124 src/wx/film_editor.cc:288 +msgid "Edit..." +msgstr "Modifica..." + +#: src/wx/config_dialog.cc:55 +#, fuzzy +msgid "Encoding servers" +msgstr "Servers di codifica" + +#: src/wx/dci_metadata_dialog.cc:53 +msgid "Facility (e.g. DLA)" +msgstr "Facility (es. DLA)" + +#: src/wx/properties_dialog.cc:36 +msgid "Film Properties" +msgstr "ProprietĂ del film" + +#: src/wx/new_film_dialog.cc:44 +msgid "Film name" +msgstr "Nome del film" + +#: src/wx/film_editor.cc:284 src/wx/filter_dialog.cc:32 +msgid "Filters" +msgstr "Filtri" + +#: src/wx/properties_dialog.cc:41 +msgid "Frames" +msgstr "Fotogrammi" + +#: src/wx/properties_dialog.cc:49 +msgid "Frames already encoded" +msgstr "Fotogrammi giĂ codificati" + +#: src/wx/about_dialog.cc:60 +msgid "Free, open-source DCP generation from almost anything." +msgstr "" + +#: src/wx/gain_calculator_dialog.cc:27 +msgid "Gain Calculator" +msgstr "Calcolatore del guadagno audio" + +#: src/wx/properties_dialog.cc:56 +msgid "Gb" +msgstr "Gb" + +#: src/wx/server_dialog.cc:36 +msgid "Host name or IP address" +msgstr "Nome dell'Host o indirizzo IP" + +#: src/wx/film_editor.cc:1427 +msgid "Hz" +msgstr "Hz" + +#: src/wx/gain_calculator_dialog.cc:32 +msgid "I want to play this back at fader" +msgstr "Sto usando il fader a" + +#: src/wx/config_dialog.cc:217 src/wx/config_dialog.cc:288 +msgid "IP address" +msgstr "Indirizzo IP" + +#: src/wx/imagemagick_content_dialog.cc:29 +msgid "Image" +msgstr "" + +#: src/wx/config_dialog.cc:256 +msgid "Issuer" +msgstr "" + +#: src/wx/film_editor.cc:158 +msgid "JPEG2000 bandwidth" +msgstr "Banda passante JPEG2000" + +#: src/wx/audio_mapping_view.cc:184 +msgid "L" +msgstr "" + +#: src/wx/film_editor.cc:249 +msgid "Left crop" +msgstr "Taglio a sinistra" + +#: src/wx/film_editor.cc:460 +msgid "Length" +msgstr "Lunghezza" + +#: src/wx/audio_mapping_view.cc:196 +msgid "Lfe" +msgstr "" + +#: src/wx/film_editor.cc:330 +msgid "Loop everything" +msgstr "" + +#: src/wx/audio_mapping_view.cc:200 +#, fuzzy +msgid "Ls" +msgstr "s" + +#: src/wx/config_dialog.cc:141 src/wx/film_editor.cc:162 +msgid "MBps" +msgstr "MBps" + +#: src/wx/config_dialog.cc:57 +msgid "Metadata" +msgstr "" + +#: src/wx/config_dialog.cc:53 +msgid "Miscellaneous" +msgstr "" + +#: src/wx/dir_picker_ctrl.cc:52 +msgid "My Documents" +msgstr "Documenti" + +#: src/wx/film_editor.cc:110 +msgid "Name" +msgstr "Nome" + +#: src/wx/new_film_dialog.cc:35 +msgid "New Film" +msgstr "Nuovo Film" + +#: src/wx/film_editor.cc:286 src/wx/film_editor.cc:769 +msgid "None" +msgstr "Nessuno" + +#: src/wx/film_editor.cc:1309 +#, c-format +msgid "Original video is %dx%d (%.2f:1)\n" +msgstr "Il video originale è %dx%d (%.2f:1)\n" + +#: src/wx/dci_metadata_dialog.cc:57 +msgid "Package Type (e.g. OV)" +msgstr "Tipo di Package (es. OV)" + +#: src/wx/film_editor.cc:1343 +#, c-format +msgid "Padded with black to %dx%d (%.2f:1)\n" +msgstr "Riempito con nero a %dx%d (%.2f:1)\n" + +#: src/wx/config_dialog.cc:229 +#, fuzzy +msgid "Password" +msgstr "Password del TMS" + +#: src/wx/job_manager_view.cc:104 src/wx/job_manager_view.cc:206 +msgid "Pause" +msgstr "" + +#: src/wx/audio_dialog.cc:59 +msgid "Peak" +msgstr "Picco" + +#: src/wx/film_viewer.cc:64 +msgid "Play" +msgstr "Riproduci" + +#: src/wx/audio_plot.cc:110 +msgid "Please wait; audio is being analysed..." +msgstr "Attendere prego; sto analizzando l'audio..." + +#: src/wx/audio_mapping_view.cc:188 +msgid "R" +msgstr "" + +#: src/wx/audio_dialog.cc:60 +msgid "RMS" +msgstr "RMS" + +#: src/wx/dci_metadata_dialog.cc:45 +msgid "Rating (e.g. 15)" +msgstr "Classificazione (es. 15)" + +#: src/wx/config_dialog.cc:303 src/wx/film_editor.cc:319 +msgid "Remove" +msgstr "Rimuovi" + +#: src/wx/job_manager_view.cc:209 +msgid "Resume" +msgstr "" + +#: src/wx/film_editor.cc:254 +msgid "Right crop" +msgstr "Taglio a destra" + +#: src/wx/audio_mapping_view.cc:204 +#, fuzzy +msgid "Rs" +msgstr "s" + +#: src/wx/job_manager_view.cc:128 +msgid "Running" +msgstr "In corso" + +#: src/wx/film_editor.cc:269 +#, fuzzy +msgid "Scale to" +msgstr "Scaler" + +#: src/wx/film_editor.cc:1335 +#, c-format +msgid "Scaled to %dx%d (%.2f:1)\n" +msgstr "Scalato a %dx%d (%.2f:1)\n" + +#: src/wx/film_editor.cc:167 +msgid "Scaler" +msgstr "Scaler" + +#: src/wx/server_dialog.cc:25 +msgid "Server" +msgstr "Server" + +#: src/wx/config_dialog.cc:85 +msgid "Set language" +msgstr "Seleziona la lingua" + +#: src/wx/film_editor.cc:362 +msgid "Show Audio..." +msgstr "Mostra Audio..." + +#: src/wx/audio_dialog.cc:70 +msgid "Smoothing" +msgstr "Levigatura" + +#: src/wx/film_editor.cc:457 +#, fuzzy +msgid "Start time" +msgstr "Inizio" + +#: src/wx/dci_metadata_dialog.cc:49 +msgid "Studio (e.g. TCF)" +msgstr "Studio (es. TCF)" + +#: src/wx/dci_metadata_dialog.cc:37 +msgid "Subtitle Language (e.g. FR)" +msgstr "Lingua dei Sottotitoli (es. FR)" + +#: src/wx/film_editor.cc:422 +msgid "Subtitle Offset" +msgstr "Sfalsamento dei Sottotitoli" + +#: src/wx/film_editor.cc:431 +msgid "Subtitle Scale" +msgstr "Scala dei Sottotitoli" + +#: src/wx/film_editor.cc:439 +#, fuzzy +msgid "Subtitle Stream" +msgstr "Scala dei Sottotitoli" + +#: src/wx/film_editor.cc:345 +msgid "Subtitles" +msgstr "Sottotitoli" + +#: src/wx/about_dialog.cc:120 +msgid "Supported by" +msgstr "" + +#: src/wx/config_dialog.cc:59 +#, fuzzy +msgid "TMS" +msgstr "RMS" + +#: src/wx/config_dialog.cc:221 +#, fuzzy +msgid "Target path" +msgstr "Percorso di destinazione del TMS" + +#: src/wx/dci_metadata_dialog.cc:41 +msgid "Territory (e.g. UK)" +msgstr "Nazione (es. UK)" + +#: src/wx/config_dialog.cc:292 +msgid "Threads" +msgstr "Threads" + +#: src/wx/server_dialog.cc:40 +msgid "Threads to use" +msgstr "Threads da usare" + +#: src/wx/config_dialog.cc:104 +msgid "Threads to use for encoding on this host" +msgstr "Threads da usare per codificare su questo host" + +#: src/wx/audio_plot.cc:140 +msgid "Time" +msgstr "Tempo" + +#: src/wx/timeline_dialog.cc:32 +#, fuzzy +msgid "Timeline" +msgstr "Tempo" + +#: src/wx/film_editor.cc:321 +msgid "Timeline..." +msgstr "" + +#: src/wx/film_editor.cc:347 +msgid "Timing" +msgstr "" + +#: src/wx/film_editor.cc:259 +msgid "Top crop" +msgstr "Taglio in alto" + +#: src/wx/about_dialog.cc:99 +msgid "Translated by" +msgstr "" + +#: src/wx/audio_dialog.cc:54 +msgid "Type" +msgstr "Tipo" + +#: src/wx/film_editor.cc:125 +msgid "Use DCI name" +msgstr "Usa nome DCI" + +#: src/wx/film_editor.cc:146 +msgid "Use best" +msgstr "Usa la migliore" + +#: src/wx/config_dialog.cc:225 +#, fuzzy +msgid "User name" +msgstr "Usa nome DCI" + +#: src/wx/film_editor.cc:341 +msgid "Video" +msgstr "Video" + +#: src/wx/film_editor.cc:417 +msgid "With Subtitles" +msgstr "Con sottotitoli" + +#: src/wx/about_dialog.cc:90 +msgid "Written by" +msgstr "" + +#: src/wx/timeline.cc:200 +#, fuzzy +msgid "audio" +msgstr "Audio" + +#: src/wx/film_editor.cc:1425 +msgid "channels" +msgstr "canali" + +#: src/wx/properties_dialog.cc:50 +msgid "counting..." +msgstr "conteggio..." + +#: src/wx/film_editor.cc:372 +msgid "dB" +msgstr "dB" + +#. / TRANSLATORS: this is an abbreviation for milliseconds, the unit of time +#: src/wx/film_editor.cc:385 +msgid "ms" +msgstr "ms" + +#. / TRANSLATORS: this is an abbreviation for seconds, the unit of time +#: src/wx/config_dialog.cc:112 src/wx/imagemagick_content_dialog.cc:41 +msgid "s" +msgstr "s" + +#: src/wx/film_editor.cc:334 +msgid "times" +msgstr "" + +#: src/wx/timeline.cc:220 +#, fuzzy +msgid "video" +msgstr "Video" + +#~ msgid "A/B" +#~ msgstr "A/B" + +#~ msgid "Audio will be resampled from %dHz to %dHz\n" +#~ msgstr "L'Audio sarĂ ricampionato da %dHz a %dHz\n" + +#~ msgid "Colour look-up table" +#~ msgstr "Tabella per ricerca del colore" + +#~ msgid "Could not open content file (%s)" +#~ msgstr "Non posso aprire il file del contenuto (%s)" + +#~ msgid "Could not set content: %s" +#~ msgstr "Non posso regolare il contenuto: %s" + +#, fuzzy +#~ msgid "DVD-o-matic Preferences" +#~ msgstr "Preferenze DVD-o-matic" + +#~ msgid "End" +#~ msgstr "Fine" + +#~ msgid "Film" +#~ msgstr "Film" + +#~ msgid "Format" +#~ msgstr "Formato" + +#~ msgid "Original Frame Rate" +#~ msgstr "Frequenza fotogrammi originale" + +#, fuzzy +#~ msgid "Reference filters" +#~ msgstr "Filtri di riferimento A/B" + +#, fuzzy +#~ msgid "Reference scaler" +#~ msgstr "Scalatura di riferimento A/B" + +#~ msgid "Select Audio File" +#~ msgstr "Seleziona file audio" + +#~ msgid "Select Content File" +#~ msgstr "Seleziona il file con il contenuto" + +#~ msgid "Trim frames" +#~ msgstr "Taglia fotogrammi" + +#~ msgid "Trim method" +#~ msgstr "Metodo di taglio" + +#~ msgid "Trust content's header" +#~ msgstr "Conferma l'intestazione del contenuto" + +#~ msgid "Use content's audio" +#~ msgstr "Usa l'audio del contenuto" + +#~ msgid "Use external audio" +#~ msgstr "Usa l'audio esterno" + +#~ msgid "encode all frames and play the subset" +#~ msgstr "Codifica tutti i fotogrammi e riproduci la selezione" + +#~ msgid "encode only the subset" +#~ msgstr "codifica solo la selezione" + +#~ msgid "frames" +#~ msgstr "fotogrammi" + +#~ msgid "pixels" +#~ msgstr "pizels" + +#~ msgid "unknown" +#~ msgstr "sconosciuto" + +#~ msgid "TMS IP address" +#~ msgstr "Indirizzo IP del TMS" + +#~ msgid "TMS user name" +#~ msgstr "Nome utente del TMS" + +#~ msgid "Original Size" +#~ msgstr "Dimensione Originale" diff --git a/src/wx/po/sv_SE.po b/src/wx/po/sv_SE.po new file mode 100644 index 000000000..c86fcc8f8 --- /dev/null +++ b/src/wx/po/sv_SE.po @@ -0,0 +1,679 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: DCP-o-matic\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-07-15 22:07+0100\n" +"PO-Revision-Date: 2013-04-09 10:13+0100\n" +"Last-Translator: Adam Klotblixt <adam.klotblixt@gmail.com>\n" +"Language-Team: \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 1.5.5\n" + +#: src/wx/film_editor.cc:426 src/wx/film_editor.cc:435 +msgid "%" +msgstr "%" + +#: src/wx/about_dialog.cc:77 +msgid "" +"(C) 2012-2013 Carl Hetherington, Terrence Meiczinger, Paul Davis, Ole Laursen" +msgstr "" + +#: src/wx/config_dialog.cc:96 +msgid "(restart DCP-o-matic to see language changes)" +msgstr "(starta om DCP-o-matic för att se sprĂ¥kändringar)" + +#: src/wx/film_editor.cc:1423 +msgid "1 channel" +msgstr "1 kanal" + +#: src/wx/about_dialog.cc:30 +#, fuzzy +msgid "About DCP-o-matic" +msgstr "DCP-o-matic" + +#: src/wx/config_dialog.cc:299 +msgid "Add" +msgstr "Lägg till" + +#: src/wx/film_editor.cc:317 +msgid "Add..." +msgstr "" + +#: src/wx/audio_dialog.cc:32 src/wx/film_editor.cc:343 +msgid "Audio" +msgstr "Audio" + +#: src/wx/film_editor.cc:379 +msgid "Audio Delay" +msgstr "Audio Fördröjning" + +#: src/wx/film_editor.cc:367 +msgid "Audio Gain" +msgstr "Audio Förstärkning" + +#: src/wx/dci_metadata_dialog.cc:33 +msgid "Audio Language (e.g. EN)" +msgstr "Audio SprĂ¥k (ex. SV)" + +#: src/wx/film_editor.cc:391 +#, fuzzy +msgid "Audio Stream" +msgstr "Audio Fördröjning" + +#: src/wx/job_wrapper.cc:38 +#, c-format +msgid "Bad setting for %s (%s)" +msgstr "Felaktig inställning för %s (%s)" + +#: src/wx/film_editor.cc:264 +msgid "Bottom crop" +msgstr "Nedre beskärning" + +#: src/wx/dir_picker_ctrl.cc:38 +msgid "Browse..." +msgstr "Bläddra..." + +#: src/wx/gain_calculator_dialog.cc:36 +msgid "But I have to use fader" +msgstr "Men jag mĂ¥ste använda mixervolym" + +#: src/wx/audio_mapping_view.cc:192 +msgid "C" +msgstr "" + +#: src/wx/film_editor.cc:376 +msgid "Calculate..." +msgstr "Beräkna..." + +#: src/wx/job_manager_view.cc:98 +msgid "Cancel" +msgstr "Avbryt" + +#: src/wx/audio_dialog.cc:43 +msgid "Channels" +msgstr "Kanaler" + +#: src/wx/film_editor.cc:1163 +msgid "Choose a file or files" +msgstr "" + +#: src/wx/film_editor.cc:131 +#, fuzzy +msgid "Container" +msgstr "InnehĂ¥ll" + +#: src/wx/film_editor.cc:82 +msgid "Content" +msgstr "InnehĂ¥ll" + +#: src/wx/film_editor.cc:136 +msgid "Content Type" +msgstr "InnehĂ¥llstyp" + +#: src/wx/audio_mapping_view.cc:181 +#, fuzzy +msgid "Content channel" +msgstr "1 kanal" + +#: src/wx/film_viewer.cc:326 +#, c-format +msgid "Could not decode video for view (%s)" +msgstr "Kunde inte avkoda video för visning (%s)" + +#: src/wx/job_wrapper.cc:40 +#, c-format +msgid "Could not make DCP: %s" +msgstr "Kunde inte skapa DCP: %s" + +#: src/wx/new_film_dialog.cc:48 +msgid "Create in folder" +msgstr "Skapa i katalog" + +#: src/wx/config_dialog.cc:260 +#, fuzzy +msgid "Creator" +msgstr "Skapa i katalog" + +#: src/wx/film_editor.cc:1322 +#, c-format +msgid "Cropped to %dx%d (%.2f:1)\n" +msgstr "Beskuren till %dx%d (%.2f:1)\n" + +#: src/wx/dci_metadata_dialog.cc:28 +msgid "DCI name" +msgstr "DCI namn" + +#: src/wx/film_editor.cc:84 +msgid "DCP" +msgstr "" + +#: src/wx/film_editor.cc:142 +msgid "DCP Frame Rate" +msgstr "DCP bildhastighet" + +#: src/wx/film_editor.cc:115 +msgid "DCP Name" +msgstr "DCP Namn" + +#: src/wx/film_editor.cc:152 +#, fuzzy +msgid "DCP audio channels" +msgstr "kanaler" + +#: src/wx/about_dialog.cc:44 src/wx/wx_util.cc:87 src/wx/wx_util.cc:95 +msgid "DCP-o-matic" +msgstr "DCP-o-matic" + +#: src/wx/config_dialog.cc:46 +msgid "DCP-o-matic Preferences" +msgstr "DCP-o-matic Inställningar" + +#: src/wx/audio_dialog.cc:97 +#, c-format +msgid "DCP-o-matic audio - %s" +msgstr "DCP-o-matic audio - %s" + +#: src/wx/config_dialog.cc:123 +msgid "Default DCI name details" +msgstr "Detaljer om förvalda DCI-namn" + +#: src/wx/config_dialog.cc:138 +#, fuzzy +msgid "Default JPEG2000 bandwidth" +msgstr "JPEG2000 bandbredd" + +#: src/wx/config_dialog.cc:128 +#, fuzzy +msgid "Default container" +msgstr "InnehĂ¥llstyp" + +#: src/wx/config_dialog.cc:133 +#, fuzzy +msgid "Default content type" +msgstr "InnehĂ¥llstyp" + +#: src/wx/config_dialog.cc:114 +msgid "Default directory for new films" +msgstr "Förvald katalog för nya filmer" + +#: src/wx/config_dialog.cc:109 +#, fuzzy +msgid "Default duration of still images" +msgstr "Förvald katalog för nya filmer" + +#: src/wx/film_editor.cc:127 src/wx/job_manager_view.cc:110 +msgid "Details..." +msgstr "Detaljer..." + +#: src/wx/properties_dialog.cc:45 +msgid "Disk space required" +msgstr "Diskutrymme som krävs" + +#: src/wx/imagemagick_content_dialog.cc:36 +msgid "Duration" +msgstr "Längd" + +#: src/wx/config_dialog.cc:301 +msgid "Edit" +msgstr "Redigera" + +#: src/wx/config_dialog.cc:124 src/wx/film_editor.cc:288 +msgid "Edit..." +msgstr "Redigera..." + +#: src/wx/config_dialog.cc:55 +#, fuzzy +msgid "Encoding servers" +msgstr "Kodningsservrar" + +#: src/wx/dci_metadata_dialog.cc:53 +msgid "Facility (e.g. DLA)" +msgstr "Företag (ex. DLA)" + +#: src/wx/properties_dialog.cc:36 +msgid "Film Properties" +msgstr "Film Egenskaper" + +#: src/wx/new_film_dialog.cc:44 +msgid "Film name" +msgstr "film namn" + +#: src/wx/film_editor.cc:284 src/wx/filter_dialog.cc:32 +msgid "Filters" +msgstr "Filter" + +#: src/wx/properties_dialog.cc:41 +msgid "Frames" +msgstr "Bildrutor" + +#: src/wx/properties_dialog.cc:49 +msgid "Frames already encoded" +msgstr "Bildrutor redan kodade" + +#: src/wx/about_dialog.cc:60 +msgid "Free, open-source DCP generation from almost anything." +msgstr "" + +#: src/wx/gain_calculator_dialog.cc:27 +msgid "Gain Calculator" +msgstr "Volym Kalkylator" + +#: src/wx/properties_dialog.cc:56 +msgid "Gb" +msgstr "Gb" + +#: src/wx/server_dialog.cc:36 +msgid "Host name or IP address" +msgstr "Värd-namn eller IP-adress" + +#: src/wx/film_editor.cc:1427 +msgid "Hz" +msgstr "Hz" + +#: src/wx/gain_calculator_dialog.cc:32 +msgid "I want to play this back at fader" +msgstr "Jag vill spela upp detta med mixervolym" + +#: src/wx/config_dialog.cc:217 src/wx/config_dialog.cc:288 +msgid "IP address" +msgstr "IP-adress" + +#: src/wx/imagemagick_content_dialog.cc:29 +msgid "Image" +msgstr "" + +#: src/wx/config_dialog.cc:256 +msgid "Issuer" +msgstr "" + +#: src/wx/film_editor.cc:158 +msgid "JPEG2000 bandwidth" +msgstr "JPEG2000 bandbredd" + +#: src/wx/audio_mapping_view.cc:184 +msgid "L" +msgstr "" + +#: src/wx/film_editor.cc:249 +msgid "Left crop" +msgstr "Vänster beskärning" + +#: src/wx/film_editor.cc:460 +msgid "Length" +msgstr "Längd" + +#: src/wx/audio_mapping_view.cc:196 +msgid "Lfe" +msgstr "" + +#: src/wx/film_editor.cc:330 +msgid "Loop everything" +msgstr "" + +#: src/wx/audio_mapping_view.cc:200 +#, fuzzy +msgid "Ls" +msgstr "s" + +#: src/wx/config_dialog.cc:141 src/wx/film_editor.cc:162 +msgid "MBps" +msgstr "MBps" + +#: src/wx/config_dialog.cc:57 +msgid "Metadata" +msgstr "" + +#: src/wx/config_dialog.cc:53 +msgid "Miscellaneous" +msgstr "" + +#: src/wx/dir_picker_ctrl.cc:52 +msgid "My Documents" +msgstr "Mina Dokument" + +#: src/wx/film_editor.cc:110 +msgid "Name" +msgstr "Namn" + +#: src/wx/new_film_dialog.cc:35 +msgid "New Film" +msgstr "Ny Film" + +#: src/wx/film_editor.cc:286 src/wx/film_editor.cc:769 +msgid "None" +msgstr "Inget" + +#: src/wx/film_editor.cc:1309 +#, c-format +msgid "Original video is %dx%d (%.2f:1)\n" +msgstr "Original-videon är %dx%d (%.2f:1)\n" + +#: src/wx/dci_metadata_dialog.cc:57 +msgid "Package Type (e.g. OV)" +msgstr "Förpackningstyp (ex. OV)" + +#: src/wx/film_editor.cc:1343 +#, c-format +msgid "Padded with black to %dx%d (%.2f:1)\n" +msgstr "Svarta kanter tillagda för %dx%d (%.2f:1)\n" + +#: src/wx/config_dialog.cc:229 +#, fuzzy +msgid "Password" +msgstr "TMS lösenord" + +#: src/wx/job_manager_view.cc:104 src/wx/job_manager_view.cc:206 +msgid "Pause" +msgstr "" + +#: src/wx/audio_dialog.cc:59 +msgid "Peak" +msgstr "Topp" + +#: src/wx/film_viewer.cc:64 +msgid "Play" +msgstr "Spela" + +#: src/wx/audio_plot.cc:110 +msgid "Please wait; audio is being analysed..." +msgstr "Vänligen vänta; audio analyseras..." + +#: src/wx/audio_mapping_view.cc:188 +msgid "R" +msgstr "" + +#: src/wx/audio_dialog.cc:60 +msgid "RMS" +msgstr "RMS" + +#: src/wx/dci_metadata_dialog.cc:45 +msgid "Rating (e.g. 15)" +msgstr "Klassificering (ex. 15)" + +#: src/wx/config_dialog.cc:303 src/wx/film_editor.cc:319 +msgid "Remove" +msgstr "Ta bort" + +#: src/wx/job_manager_view.cc:209 +msgid "Resume" +msgstr "" + +#: src/wx/film_editor.cc:254 +msgid "Right crop" +msgstr "Höger beskärning" + +#: src/wx/audio_mapping_view.cc:204 +#, fuzzy +msgid "Rs" +msgstr "s" + +#: src/wx/job_manager_view.cc:128 +msgid "Running" +msgstr "Körs" + +#: src/wx/film_editor.cc:269 +#, fuzzy +msgid "Scale to" +msgstr "Omskalare" + +#: src/wx/film_editor.cc:1335 +#, c-format +msgid "Scaled to %dx%d (%.2f:1)\n" +msgstr "Skalad till %dx%d (%.2f:1)\n" + +#: src/wx/film_editor.cc:167 +msgid "Scaler" +msgstr "Omskalare" + +#: src/wx/server_dialog.cc:25 +msgid "Server" +msgstr "Server" + +#: src/wx/config_dialog.cc:85 +msgid "Set language" +msgstr "Välj sprĂ¥k" + +#: src/wx/film_editor.cc:362 +msgid "Show Audio..." +msgstr "Visa Audio..." + +#: src/wx/audio_dialog.cc:70 +msgid "Smoothing" +msgstr "Utjämning" + +#: src/wx/film_editor.cc:457 +#, fuzzy +msgid "Start time" +msgstr "Start" + +#: src/wx/dci_metadata_dialog.cc:49 +msgid "Studio (e.g. TCF)" +msgstr "Studio (ex. TCF)" + +#: src/wx/dci_metadata_dialog.cc:37 +msgid "Subtitle Language (e.g. FR)" +msgstr "UndertextsprĂ¥k (ex. SV)" + +#: src/wx/film_editor.cc:422 +msgid "Subtitle Offset" +msgstr "Undertext Förskjutning" + +#: src/wx/film_editor.cc:431 +msgid "Subtitle Scale" +msgstr "Undertext Skalning" + +#: src/wx/film_editor.cc:439 +#, fuzzy +msgid "Subtitle Stream" +msgstr "Undertext Skalning" + +#: src/wx/film_editor.cc:345 +msgid "Subtitles" +msgstr "Undertexter" + +#: src/wx/about_dialog.cc:120 +msgid "Supported by" +msgstr "" + +#: src/wx/config_dialog.cc:59 +#, fuzzy +msgid "TMS" +msgstr "RMS" + +#: src/wx/config_dialog.cc:221 +#, fuzzy +msgid "Target path" +msgstr "TMS mĂ¥lsökväg" + +#: src/wx/dci_metadata_dialog.cc:41 +msgid "Territory (e.g. UK)" +msgstr "OmrĂ¥de (ex. SV)" + +#: src/wx/config_dialog.cc:292 +msgid "Threads" +msgstr "TrĂ¥dar" + +#: src/wx/server_dialog.cc:40 +msgid "Threads to use" +msgstr "Antal trĂ¥dar att använda" + +#: src/wx/config_dialog.cc:104 +msgid "Threads to use for encoding on this host" +msgstr "Antal trĂ¥dar att använda vid kodning pĂ¥ denna maskin" + +#: src/wx/audio_plot.cc:140 +msgid "Time" +msgstr "Tid" + +#: src/wx/timeline_dialog.cc:32 +#, fuzzy +msgid "Timeline" +msgstr "Tid" + +#: src/wx/film_editor.cc:321 +msgid "Timeline..." +msgstr "" + +#: src/wx/film_editor.cc:347 +msgid "Timing" +msgstr "" + +#: src/wx/film_editor.cc:259 +msgid "Top crop" +msgstr "Ă–vre beskärning" + +#: src/wx/about_dialog.cc:99 +msgid "Translated by" +msgstr "" + +#: src/wx/audio_dialog.cc:54 +msgid "Type" +msgstr "Typ" + +#: src/wx/film_editor.cc:125 +msgid "Use DCI name" +msgstr "Använd DCI-namnet" + +#: src/wx/film_editor.cc:146 +msgid "Use best" +msgstr "Använd bästa" + +#: src/wx/config_dialog.cc:225 +#, fuzzy +msgid "User name" +msgstr "Använd DCI-namnet" + +#: src/wx/film_editor.cc:341 +msgid "Video" +msgstr "Video" + +#: src/wx/film_editor.cc:417 +msgid "With Subtitles" +msgstr "Med Undertexter" + +#: src/wx/about_dialog.cc:90 +msgid "Written by" +msgstr "" + +#: src/wx/timeline.cc:200 +#, fuzzy +msgid "audio" +msgstr "Audio" + +#: src/wx/film_editor.cc:1425 +msgid "channels" +msgstr "kanaler" + +#: src/wx/properties_dialog.cc:50 +msgid "counting..." +msgstr "räknar..." + +#: src/wx/film_editor.cc:372 +msgid "dB" +msgstr "dB" + +#. / TRANSLATORS: this is an abbreviation for milliseconds, the unit of time +#: src/wx/film_editor.cc:385 +msgid "ms" +msgstr "ms" + +#. / TRANSLATORS: this is an abbreviation for seconds, the unit of time +#: src/wx/config_dialog.cc:112 src/wx/imagemagick_content_dialog.cc:41 +msgid "s" +msgstr "s" + +#: src/wx/film_editor.cc:334 +msgid "times" +msgstr "" + +#: src/wx/timeline.cc:220 +#, fuzzy +msgid "video" +msgstr "Video" + +#~ msgid "A/B" +#~ msgstr "A/B" + +#~ msgid "Audio will be resampled from %dHz to %dHz\n" +#~ msgstr "Audio kommer att samplas om frĂ¥n %dHz till %dHz\n" + +#~ msgid "Colour look-up table" +#~ msgstr "Färguppslagningstabell" + +#~ msgid "Could not open content file (%s)" +#~ msgstr "Kunde inte öppna innehĂ¥llsfilen (%s)" + +#~ msgid "Could not set content: %s" +#~ msgstr "Kunde inte fastställa innehĂ¥ll: %s" + +#, fuzzy +#~ msgid "DVD-o-matic Preferences" +#~ msgstr "DVD-o-matic Inställningar" + +#~ msgid "End" +#~ msgstr "Slut" + +#~ msgid "Film" +#~ msgstr "Film" + +#~ msgid "Format" +#~ msgstr "Format" + +#~ msgid "Original Frame Rate" +#~ msgstr "Ursprunglig bildhastighet" + +#, fuzzy +#~ msgid "Reference filters" +#~ msgstr "Referensfilter för A/B" + +#, fuzzy +#~ msgid "Reference scaler" +#~ msgstr "Referensomskalare för A/B" + +#~ msgid "Select Audio File" +#~ msgstr "Välj audiofil" + +#~ msgid "Select Content File" +#~ msgstr "Välj innehĂ¥llsfil" + +#~ msgid "Trim frames" +#~ msgstr "Skippa bilder" + +#, fuzzy +#~ msgid "Trim method" +#~ msgstr "Skippa bilder" + +#~ msgid "Trust content's header" +#~ msgstr "Lita pĂ¥ källans information" + +#~ msgid "Use content's audio" +#~ msgstr "Använd innehĂ¥llets audio" + +#~ msgid "Use external audio" +#~ msgstr "Använd extern audio" + +#~ msgid "frames" +#~ msgstr "bilder" + +#~ msgid "pixels" +#~ msgstr "pixlar" + +#~ msgid "unknown" +#~ msgstr "okänt" + +#~ msgid "TMS IP address" +#~ msgstr "TMS IP-adress" + +#~ msgid "TMS user name" +#~ msgstr "TMS användarnamn" + +#~ msgid "Original Size" +#~ msgstr "Ursprunglig Storlek" diff --git a/src/wx/preset_colour_conversion_dialog.cc b/src/wx/preset_colour_conversion_dialog.cc new file mode 100644 index 000000000..ce6897ecd --- /dev/null +++ b/src/wx/preset_colour_conversion_dialog.cc @@ -0,0 +1,69 @@ +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + + 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 <wx/statline.h> +#include "lib/colour_conversion.h" +#include "wx_util.h" +#include "preset_colour_conversion_dialog.h" +#include "colour_conversion_editor.h" + +using std::string; +using std::cout; + +PresetColourConversionDialog::PresetColourConversionDialog (wxWindow* parent) + : wxDialog (parent, wxID_ANY, _("Colour conversion")) + , _editor (new ColourConversionEditor (this)) +{ + wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); + SetSizer (overall_sizer); + + wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + table->AddGrowableCol (1, 1); + add_label_to_sizer (table, this, _("Name"), true); + _name = new wxTextCtrl (this, wxID_ANY, wxT ("")); + table->Add (_name, 1, wxEXPAND | wxALL); + + overall_sizer->Add (table, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); + overall_sizer->Add (new wxStaticLine (this, wxID_ANY), 0, wxEXPAND); + overall_sizer->Add (_editor); + + wxSizer* buttons = CreateSeparatedButtonSizer (wxOK); + if (buttons) { + overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); + } + + overall_sizer->Layout (); + overall_sizer->SetSizeHints (this); +} + +PresetColourConversion +PresetColourConversionDialog::get () const +{ + PresetColourConversion pc; + pc.name = wx_to_std (_name->GetValue ()); + pc.conversion = _editor->get (); + return pc; +} + +void +PresetColourConversionDialog::set (PresetColourConversion c) +{ + _name->SetValue (std_to_wx (c.name)); + _editor->set (c.conversion); +} diff --git a/src/wx/preset_colour_conversion_dialog.h b/src/wx/preset_colour_conversion_dialog.h new file mode 100644 index 000000000..4e612398c --- /dev/null +++ b/src/wx/preset_colour_conversion_dialog.h @@ -0,0 +1,35 @@ +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + + 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 <wx/wx.h> + +class ColourConversionEditor; + +class PresetColourConversionDialog : public wxDialog +{ +public: + PresetColourConversionDialog (wxWindow *); + + void set (PresetColourConversion); + PresetColourConversion get () const; + +private: + wxTextCtrl* _name; + ColourConversionEditor* _editor; +}; diff --git a/src/wx/properties_dialog.cc b/src/wx/properties_dialog.cc index b03c6b32c..a1ba81b3b 100644 --- a/src/wx/properties_dialog.cc +++ b/src/wx/properties_dialog.cc @@ -36,41 +36,28 @@ PropertiesDialog::PropertiesDialog (wxWindow* parent, shared_ptr<Film> film) : wxDialog (parent, wxID_ANY, _("Film Properties"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE) , _film (film) { - wxFlexGridSizer* table = new wxFlexGridSizer (2, 3, 6); + wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); - add_label_to_sizer (table, this, "Frames"); - _frames = new wxStaticText (this, wxID_ANY, std_to_wx ("")); + add_label_to_sizer (table, this, _("Frames"), true); + _frames = new wxStaticText (this, wxID_ANY, wxT ("")); table->Add (_frames, 1, wxALIGN_CENTER_VERTICAL); - add_label_to_sizer (table, this, "Disk space required for frames"); - _disk_for_frames = new wxStaticText (this, wxID_ANY, std_to_wx ("")); - table->Add (_disk_for_frames, 1, wxALIGN_CENTER_VERTICAL); - - add_label_to_sizer (table, this, "Total disk space required"); - _total_disk = new wxStaticText (this, wxID_ANY, std_to_wx ("")); - table->Add (_total_disk, 1, wxALIGN_CENTER_VERTICAL); + add_label_to_sizer (table, this, _("Disk space required"), true); + _disk = new wxStaticText (this, wxID_ANY, wxT ("")); + table->Add (_disk, 1, wxALIGN_CENTER_VERTICAL); - add_label_to_sizer (table, this, "Frames already encoded"); - _encoded = new ThreadedStaticText (this, "counting...", boost::bind (&PropertiesDialog::frames_already_encoded, this)); + add_label_to_sizer (table, this, _("Frames already encoded"), true); + _encoded = new ThreadedStaticText (this, _("counting..."), boost::bind (&PropertiesDialog::frames_already_encoded, this)); table->Add (_encoded, 1, wxALIGN_CENTER_VERTICAL); - if (_film->length()) { - _frames->SetLabel (std_to_wx (lexical_cast<string> (_film->length().get()))); - double const disk = ((double) _film->j2k_bandwidth() / 8) * _film->length().get() / (_film->frames_per_second () * 1073741824); - stringstream s; - s << fixed << setprecision (1) << disk << "Gb"; - _disk_for_frames->SetLabel (std_to_wx (s.str ())); - stringstream t; - t << fixed << setprecision (1) << (disk * 2) << "Gb"; - _total_disk->SetLabel (std_to_wx (t.str ())); - } else { - _frames->SetLabel (_("unknown")); - _disk_for_frames->SetLabel (_("unknown")); - _total_disk->SetLabel (_("unknown")); - } + _frames->SetLabel (std_to_wx (lexical_cast<string> (_film->time_to_video_frames (_film->length())))); + double const disk = ((double) _film->j2k_bandwidth() / 8) * _film->length() / (TIME_HZ * 1073741824.0f); + stringstream s; + s << fixed << setprecision (1) << disk << wx_to_std (_("Gb")); + _disk->SetLabel (std_to_wx (s.str ())); wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); - overall_sizer->Add (table, 0, wxALL, 6); + overall_sizer->Add (table, 0, wxALL, DCPOMATIC_DIALOG_BORDER); wxSizer* buttons = CreateSeparatedButtonSizer (wxOK); if (buttons) { @@ -91,9 +78,9 @@ PropertiesDialog::frames_already_encoded () const return ""; } - if (_film->dcp_length()) { + if (_film->length()) { /* XXX: encoded_frames() should check which frames have been encoded */ - u << " (" << ((_film->encoded_frames() - _film->dcp_trim_start()) * 100 / _film->dcp_length().get()) << "%)"; + u << " (" << (_film->encoded_frames() * 100 / _film->time_to_video_frames (_film->length())) << "%)"; } return u.str (); } diff --git a/src/wx/properties_dialog.h b/src/wx/properties_dialog.h index 308c0f7b3..cae929e18 100644 --- a/src/wx/properties_dialog.h +++ b/src/wx/properties_dialog.h @@ -32,8 +32,7 @@ private: boost::shared_ptr<Film> _film; wxStaticText* _frames; - wxStaticText* _disk_for_frames; - wxStaticText* _total_disk; + wxStaticText* _disk; ThreadedStaticText* _encoded; }; diff --git a/src/wx/repeat_dialog.cc b/src/wx/repeat_dialog.cc new file mode 100644 index 000000000..3721c61b9 --- /dev/null +++ b/src/wx/repeat_dialog.cc @@ -0,0 +1,54 @@ +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + + 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 "repeat_dialog.h" +#include "wx_util.h" + +RepeatDialog::RepeatDialog (wxWindow* parent) + : wxDialog (parent, wxID_ANY, _("Repeat Content")) +{ + wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); + SetSizer (overall_sizer); + + wxFlexGridSizer* table = new wxFlexGridSizer (3, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + table->AddGrowableCol (1, 1); + overall_sizer->Add (table, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); + + add_label_to_sizer (table, this, _("Repeat"), true); + _number = new wxSpinCtrl (this, wxID_ANY); + table->Add (_number, 1); + + add_label_to_sizer (table, this, _("times"), false); + + _number->SetRange (1, 1024); + + wxSizer* buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL); + if (buttons) { + overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); + } + + overall_sizer->Layout (); + overall_sizer->SetSizeHints (this); +} + +int +RepeatDialog::number () const +{ + return _number->GetValue (); +} diff --git a/src/wx/repeat_dialog.h b/src/wx/repeat_dialog.h new file mode 100644 index 000000000..cbcc6bb7a --- /dev/null +++ b/src/wx/repeat_dialog.h @@ -0,0 +1,32 @@ +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + + 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 <wx/wx.h> +#include <wx/spinctrl.h> + +class RepeatDialog : public wxDialog +{ +public: + RepeatDialog (wxWindow *); + + int number () const; + +private: + wxSpinCtrl* _number; +}; diff --git a/src/wx/screen_dialog.cc b/src/wx/screen_dialog.cc index 910dece9d..7ff519713 100644 --- a/src/wx/screen_dialog.cc +++ b/src/wx/screen_dialog.cc @@ -35,11 +35,11 @@ ScreenDialog::ScreenDialog (wxWindow* parent, string title, string name, shared_ wxFlexGridSizer* table = new wxFlexGridSizer (2, 6, 6); table->AddGrowableCol (1, 1); - add_label_to_sizer (table, this, "Name"); + add_label_to_sizer (table, this, "Name", true); _name = new wxTextCtrl (this, wxID_ANY, std_to_wx (name), wxDefaultPosition, wxSize (320, -1)); table->Add (_name, 1, wxEXPAND); - add_label_to_sizer (table, this, "Certificate"); + add_label_to_sizer (table, this, "Certificate", true); _certificate_load = new wxButton (this, wxID_ANY, wxT ("Load from file...")); table->Add (_certificate_load, 1, wxEXPAND); diff --git a/src/wx/server_dialog.cc b/src/wx/server_dialog.cc index 7b394a484..c1dbc4bca 100644 --- a/src/wx/server_dialog.cc +++ b/src/wx/server_dialog.cc @@ -21,35 +21,34 @@ #include "server_dialog.h" #include "wx_util.h" -ServerDialog::ServerDialog (wxWindow* parent, ServerDescription* server) - : wxDialog (parent, wxID_ANY, wxString (_("Server"))) +using boost::shared_ptr; + +ServerDialog::ServerDialog (wxWindow* parent) + : wxDialog (parent, wxID_ANY, _("Server")) { - if (server) { - _server = server; - } else { - _server = new ServerDescription ("localhost", 1); - } - - wxFlexGridSizer* table = new wxFlexGridSizer (2, 4, 4); + wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); table->AddGrowableCol (1, 1); - add_label_to_sizer (table, this, "Host name or IP address"); - _host = new wxTextCtrl (this, wxID_ANY); - table->Add (_host, 1, wxEXPAND); + wxClientDC dc (parent); + /* XXX: bit of a mystery why we need such a long string here */ + wxSize size = dc.GetTextExtent (wxT ("255.255.255.255.255.255.255.255")); + size.SetHeight (-1); + + wxTextValidator validator (wxFILTER_INCLUDE_CHAR_LIST); + wxArrayString list; - add_label_to_sizer (table, this, "Threads to use"); + add_label_to_sizer (table, this, _("Host name or IP address"), true); + _host = new wxTextCtrl (this, wxID_ANY, wxT (""), wxDefaultPosition, size); + table->Add (_host, 1, wxEXPAND | wxALL); + + add_label_to_sizer (table, this, _("Threads to use"), true); _threads = new wxSpinCtrl (this, wxID_ANY); table->Add (_threads, 1, wxEXPAND); - _host->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (ServerDialog::host_changed), 0, this); _threads->SetRange (0, 256); - _threads->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (ServerDialog::threads_changed), 0, this); - - _host->SetValue (std_to_wx (_server->host_name ())); - _threads->SetValue (_server->threads ()); wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); - overall_sizer->Add (table, 1, wxEXPAND | wxALL, 6); + overall_sizer->Add (table, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); wxSizer* buttons = CreateSeparatedButtonSizer (wxOK); if (buttons) { @@ -62,20 +61,18 @@ ServerDialog::ServerDialog (wxWindow* parent, ServerDescription* server) } void -ServerDialog::host_changed (wxCommandEvent &) -{ - _server->set_host_name (wx_to_std (_host->GetValue ())); -} - -void -ServerDialog::threads_changed (wxCommandEvent &) +ServerDialog::set (ServerDescription server) { - _server->set_threads (_threads->GetValue ()); + _host->SetValue (std_to_wx (server.host_name ())); + _threads->SetValue (server.threads ()); } -ServerDescription * -ServerDialog::server () const +ServerDescription +ServerDialog::get () const { - return _server; + ServerDescription server; + server.set_host_name (wx_to_std (_host->GetValue ())); + server.set_threads (_threads->GetValue ()); + return server; } diff --git a/src/wx/server_dialog.h b/src/wx/server_dialog.h index 0912fd60f..a6f48fe7b 100644 --- a/src/wx/server_dialog.h +++ b/src/wx/server_dialog.h @@ -25,15 +25,12 @@ class ServerDescription; class ServerDialog : public wxDialog { public: - ServerDialog (wxWindow *, ServerDescription *); + ServerDialog (wxWindow *); - ServerDescription* server () const; + void set (ServerDescription); + ServerDescription get () const; private: - void host_changed (wxCommandEvent &); - void threads_changed (wxCommandEvent &); - - ServerDescription* _server; wxTextCtrl* _host; wxSpinCtrl* _threads; }; diff --git a/src/wx/subtitle_panel.cc b/src/wx/subtitle_panel.cc new file mode 100644 index 000000000..8f2b08af5 --- /dev/null +++ b/src/wx/subtitle_panel.cc @@ -0,0 +1,192 @@ +/* + Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net> + + 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 <boost/lexical_cast.hpp> +#include <wx/spinctrl.h> +#include "lib/ffmpeg_content.h" +#include "subtitle_panel.h" +#include "film_editor.h" +#include "wx_util.h" + +using std::vector; +using std::string; +using boost::shared_ptr; +using boost::lexical_cast; +using boost::dynamic_pointer_cast; + +SubtitlePanel::SubtitlePanel (FilmEditor* e) + : FilmEditorPanel (e, _("Subtitles")) +{ + wxFlexGridSizer* grid = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + _sizer->Add (grid, 0, wxALL, 8); + + _with_subtitles = new wxCheckBox (this, wxID_ANY, _("With Subtitles")); + grid->Add (_with_subtitles, 1); + grid->AddSpacer (0); + + { + add_label_to_sizer (grid, this, _("Subtitle Offset"), true); + wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); + _offset = new wxSpinCtrl (this); + s->Add (_offset); + add_label_to_sizer (s, this, _("%"), false); + grid->Add (s); + } + + { + add_label_to_sizer (grid, this, _("Subtitle Scale"), true); + wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); + _scale = new wxSpinCtrl (this); + s->Add (_scale); + add_label_to_sizer (s, this, _("%"), false); + grid->Add (s); + } + + add_label_to_sizer (grid, this, _("Subtitle Stream"), true); + _stream = new wxChoice (this, wxID_ANY); + grid->Add (_stream, 1, wxEXPAND); + + _offset->SetRange (-100, 100); + _scale->SetRange (1, 1000); + _scale->SetValue (100); + + _with_subtitles->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&SubtitlePanel::with_subtitles_toggled, this)); + _offset->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&SubtitlePanel::offset_changed, this)); + _scale->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&SubtitlePanel::scale_changed, this)); + _stream->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&SubtitlePanel::stream_changed, this)); +} + +void +SubtitlePanel::film_changed (Film::Property property) +{ + switch (property) { + case Film::CONTENT: + setup_sensitivity (); + break; + case Film::WITH_SUBTITLES: + checked_set (_with_subtitles, _editor->film()->with_subtitles ()); + setup_sensitivity (); + break; + default: + break; + } +} + +void +SubtitlePanel::film_content_changed (shared_ptr<Content> c, int property) +{ + shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (c); + shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (c); + + if (property == FFmpegContentProperty::SUBTITLE_STREAMS) { + _stream->Clear (); + if (fc) { + vector<shared_ptr<FFmpegSubtitleStream> > s = fc->subtitle_streams (); + for (vector<shared_ptr<FFmpegSubtitleStream> >::iterator i = s.begin(); i != s.end(); ++i) { + _stream->Append (std_to_wx ((*i)->name), new wxStringClientData (std_to_wx (lexical_cast<string> ((*i)->id)))); + } + + if (fc->subtitle_stream()) { + checked_set (_stream, lexical_cast<string> (fc->subtitle_stream()->id)); + } else { + _stream->SetSelection (wxNOT_FOUND); + } + } + setup_sensitivity (); + } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET) { + checked_set (_offset, sc ? (sc->subtitle_offset() * 100) : 0); + } else if (property == SubtitleContentProperty::SUBTITLE_SCALE) { + checked_set (_scale, sc ? (sc->subtitle_scale() * 100) : 100); + } + +} + +void +SubtitlePanel::with_subtitles_toggled () +{ + if (!_editor->film()) { + return; + } + + _editor->film()->set_with_subtitles (_with_subtitles->GetValue ()); +} + +void +SubtitlePanel::setup_sensitivity () +{ + bool h = false; + bool j = false; + if (_editor->film()) { + h = _editor->film()->has_subtitles (); + j = _editor->film()->with_subtitles (); + } + + _with_subtitles->Enable (h); + _offset->Enable (j); + _scale->Enable (j); + _stream->Enable (j); +} + +void +SubtitlePanel::stream_changed () +{ + shared_ptr<Content> c = _editor->selected_content (); + if (!c) { + return; + } + + shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (c); + if (!fc) { + return; + } + + vector<shared_ptr<FFmpegSubtitleStream> > a = fc->subtitle_streams (); + vector<shared_ptr<FFmpegSubtitleStream> >::iterator i = a.begin (); + string const s = string_client_data (_stream->GetClientObject (_stream->GetSelection ())); + while (i != a.end() && lexical_cast<string> ((*i)->id) != s) { + ++i; + } + + if (i != a.end ()) { + fc->set_subtitle_stream (*i); + } +} + +void +SubtitlePanel::offset_changed () +{ + shared_ptr<SubtitleContent> c = _editor->selected_subtitle_content (); + if (!c) { + return; + } + + c->set_subtitle_offset (_offset->GetValue() / 100.0); +} + +void +SubtitlePanel::scale_changed () +{ + shared_ptr<SubtitleContent> c = _editor->selected_subtitle_content (); + if (!c) { + return; + } + + c->set_subtitle_scale (_scale->GetValue() / 100.0); +} + diff --git a/src/wx/subtitle_panel.h b/src/wx/subtitle_panel.h new file mode 100644 index 000000000..3f7951895 --- /dev/null +++ b/src/wx/subtitle_panel.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net> + + 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 "film_editor_panel.h" + +class wxCheckBox; +class wxSpinCtrl; + +class SubtitlePanel : public FilmEditorPanel +{ +public: + SubtitlePanel (FilmEditor *); + + void film_changed (Film::Property); + void film_content_changed (boost::shared_ptr<Content>, int); + + +private: + void with_subtitles_toggled (); + void offset_changed (); + void scale_changed (); + void stream_changed (); + + void setup_sensitivity (); + + wxCheckBox* _with_subtitles; + wxSpinCtrl* _offset; + wxSpinCtrl* _scale; + wxChoice* _stream; +}; diff --git a/src/wx/timecode.cc b/src/wx/timecode.cc new file mode 100644 index 000000000..033bd2bd0 --- /dev/null +++ b/src/wx/timecode.cc @@ -0,0 +1,139 @@ +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + + 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 <boost/lexical_cast.hpp> +#include "lib/util.h" +#include "timecode.h" +#include "wx_util.h" + +using std::string; +using std::cout; +using boost::lexical_cast; + +Timecode::Timecode (wxWindow* parent) + : wxPanel (parent) +{ + wxClientDC dc (parent); + wxSize size = dc.GetTextExtent (wxT ("9999")); + size.SetHeight (-1); + + wxTextValidator validator (wxFILTER_INCLUDE_CHAR_LIST); + wxArrayString list; + + wxString n (wxT ("0123456789")); + for (size_t i = 0; i < n.Length(); ++i) { + list.Add (n[i]); + } + + validator.SetIncludes (list); + + _sizer = new wxBoxSizer (wxHORIZONTAL); + + _editable = new wxPanel (this); + wxSizer* editable_sizer = new wxBoxSizer (wxHORIZONTAL); + _hours = new wxTextCtrl (_editable, wxID_ANY, wxT(""), wxDefaultPosition, size, 0, validator); + _hours->SetMaxLength (2); + editable_sizer->Add (_hours); + add_label_to_sizer (editable_sizer, _editable, wxT (":"), false); + _minutes = new wxTextCtrl (_editable, wxID_ANY, wxT(""), wxDefaultPosition, size, 0, validator); + _minutes->SetMaxLength (2); + editable_sizer->Add (_minutes); + add_label_to_sizer (editable_sizer, _editable, wxT (":"), false); + _seconds = new wxTextCtrl (_editable, wxID_ANY, wxT(""), wxDefaultPosition, size, 0, validator); + _seconds->SetMaxLength (2); + editable_sizer->Add (_seconds); + add_label_to_sizer (editable_sizer, _editable, wxT ("."), false); + _frames = new wxTextCtrl (_editable, wxID_ANY, wxT(""), wxDefaultPosition, size, 0, validator); + _frames->SetMaxLength (2); + editable_sizer->Add (_frames); + _set_button = new wxButton (_editable, wxID_ANY, _("Set")); + editable_sizer->Add (_set_button, 0, wxLEFT | wxRIGHT, 8); + _editable->SetSizerAndFit (editable_sizer); + _sizer->Add (_editable); + + _fixed = add_label_to_sizer (_sizer, this, wxT ("42"), false); + + _hours->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&Timecode::changed, this)); + _minutes->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&Timecode::changed, this)); + _seconds->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&Timecode::changed, this)); + _frames->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&Timecode::changed, this)); + _set_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&Timecode::set_clicked, this)); + + _set_button->Enable (false); + + set_editable (true); + + SetSizerAndFit (_sizer); +} + +void +Timecode::set (Time t, int fps) +{ + int const h = t / (3600 * TIME_HZ); + t -= h * 3600 * TIME_HZ; + int const m = t / (60 * TIME_HZ); + t -= m * 60 * TIME_HZ; + int const s = t / TIME_HZ; + t -= s * TIME_HZ; + int const f = t * fps / TIME_HZ; + + checked_set (_hours, lexical_cast<string> (h)); + checked_set (_minutes, lexical_cast<string> (m)); + checked_set (_seconds, lexical_cast<string> (s)); + checked_set (_frames, lexical_cast<string> (f)); + + _fixed->SetLabel (wxString::Format ("%02d:%02d:%02d.%02d", h, m, s, f)); +} + +Time +Timecode::get (int fps) const +{ + Time t = 0; + string const h = wx_to_std (_hours->GetValue ()); + t += lexical_cast<int> (h.empty() ? "0" : h) * 3600 * TIME_HZ; + string const m = wx_to_std (_minutes->GetValue()); + t += lexical_cast<int> (m.empty() ? "0" : m) * 60 * TIME_HZ; + string const s = wx_to_std (_seconds->GetValue()); + t += lexical_cast<int> (s.empty() ? "0" : s) * TIME_HZ; + string const f = wx_to_std (_frames->GetValue()); + t += lexical_cast<int> (f.empty() ? "0" : f) * TIME_HZ / fps; + + return t; +} + +void +Timecode::changed () +{ + _set_button->Enable (true); +} + +void +Timecode::set_clicked () +{ + Changed (); + _set_button->Enable (false); +} + +void +Timecode::set_editable (bool e) +{ + _editable->Show (e); + _fixed->Show (!e); + _sizer->Layout (); +} diff --git a/src/wx/timecode.h b/src/wx/timecode.h new file mode 100644 index 000000000..5b094e39f --- /dev/null +++ b/src/wx/timecode.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + + 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 <boost/signals2.hpp> +#include <wx/wx.h> +#include "lib/types.h" + +class Timecode : public wxPanel +{ +public: + Timecode (wxWindow *); + + void set (Time, int); + Time get (int) const; + + void set_editable (bool); + + boost::signals2::signal<void ()> Changed; + +private: + void changed (); + void set_clicked (); + + wxSizer* _sizer; + wxPanel* _editable; + wxTextCtrl* _hours; + wxStaticText* _hours_label; + wxTextCtrl* _minutes; + wxTextCtrl* _seconds; + wxTextCtrl* _frames; + wxButton* _set_button; + wxStaticText* _fixed; +}; + diff --git a/src/wx/timeline.cc b/src/wx/timeline.cc new file mode 100644 index 000000000..87070b35e --- /dev/null +++ b/src/wx/timeline.cc @@ -0,0 +1,652 @@ +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + + 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 <list> +#include <wx/graphics.h> +#include <boost/weak_ptr.hpp> +#include "lib/film.h" +#include "lib/playlist.h" +#include "film_editor.h" +#include "timeline.h" +#include "wx_util.h" + +using std::list; +using std::cout; +using std::max; +using boost::shared_ptr; +using boost::weak_ptr; +using boost::dynamic_pointer_cast; +using boost::bind; + +class View : public boost::noncopyable +{ +public: + View (Timeline& t) + : _timeline (t) + { + + } + + virtual ~View () {} + + void paint (wxGraphicsContext* g) + { + _last_paint_bbox = bbox (); + do_paint (g); + } + + void force_redraw () + { + _timeline.force_redraw (_last_paint_bbox); + _timeline.force_redraw (bbox ()); + } + + virtual dcpomatic::Rect<int> bbox () const = 0; + +protected: + virtual void do_paint (wxGraphicsContext *) = 0; + + int time_x (Time t) const + { + return _timeline.tracks_position().x + t * _timeline.pixels_per_time_unit(); + } + + Timeline& _timeline; + +private: + dcpomatic::Rect<int> _last_paint_bbox; +}; + +class ContentView : public View +{ +public: + ContentView (Timeline& tl, shared_ptr<Content> c) + : View (tl) + , _content (c) + , _track (0) + , _selected (false) + { + _content_connection = c->Changed.connect (bind (&ContentView::content_changed, this, _2, _3)); + } + + dcpomatic::Rect<int> bbox () const + { + shared_ptr<const Film> film = _timeline.film (); + shared_ptr<const Content> content = _content.lock (); + if (!film || !content) { + return dcpomatic::Rect<int> (); + } + + return dcpomatic::Rect<int> ( + time_x (content->position ()) - 8, + y_pos (_track) - 8, + content->length_after_trim () * _timeline.pixels_per_time_unit() + 16, + _timeline.track_height() + 16 + ); + } + + void set_selected (bool s) { + _selected = s; + force_redraw (); + } + + bool selected () const { + return _selected; + } + + shared_ptr<Content> content () const { + return _content.lock (); + } + + void set_track (int t) { + _track = t; + } + + int track () const { + return _track; + } + + virtual wxString type () const = 0; + virtual wxColour colour () const = 0; + +private: + + void do_paint (wxGraphicsContext* gc) + { + shared_ptr<const Film> film = _timeline.film (); + shared_ptr<const Content> cont = content (); + if (!film || !cont) { + return; + } + + Time const position = cont->position (); + Time const len = cont->length_after_trim (); + + wxColour selected (colour().Red() / 2, colour().Green() / 2, colour().Blue() / 2); + + gc->SetPen (*wxBLACK_PEN); + + gc->SetPen (*wxThePenList->FindOrCreatePen (wxColour (0, 0, 0), 4, wxPENSTYLE_SOLID)); + if (_selected) { + gc->SetBrush (*wxTheBrushList->FindOrCreateBrush (selected, wxBRUSHSTYLE_SOLID)); + } else { + gc->SetBrush (*wxTheBrushList->FindOrCreateBrush (colour(), wxBRUSHSTYLE_SOLID)); + } + + wxGraphicsPath path = gc->CreatePath (); + path.MoveToPoint (time_x (position), y_pos (_track) + 4); + path.AddLineToPoint (time_x (position + len), y_pos (_track) + 4); + path.AddLineToPoint (time_x (position + len), y_pos (_track + 1) - 4); + path.AddLineToPoint (time_x (position), y_pos (_track + 1) - 4); + path.AddLineToPoint (time_x (position), y_pos (_track) + 4); + gc->StrokePath (path); + gc->FillPath (path); + + wxString name = wxString::Format (wxT ("%s [%s]"), std_to_wx (cont->path().filename().string()).data(), type().data()); + wxDouble name_width; + wxDouble name_height; + wxDouble name_descent; + wxDouble name_leading; + gc->GetTextExtent (name, &name_width, &name_height, &name_descent, &name_leading); + + gc->Clip (wxRegion (time_x (position), y_pos (_track), len * _timeline.pixels_per_time_unit(), _timeline.track_height())); + gc->DrawText (name, time_x (position) + 12, y_pos (_track + 1) - name_height - 4); + gc->ResetClip (); + } + + int y_pos (int t) const + { + return _timeline.tracks_position().y + t * _timeline.track_height(); + } + + void content_changed (int p, bool frequent) + { + ensure_ui_thread (); + + if (p == ContentProperty::POSITION || p == ContentProperty::LENGTH) { + force_redraw (); + } + + if (!frequent) { + _timeline.setup_pixels_per_time_unit (); + _timeline.Refresh (); + } + } + + boost::weak_ptr<Content> _content; + int _track; + bool _selected; + + boost::signals2::scoped_connection _content_connection; +}; + +class AudioContentView : public ContentView +{ +public: + AudioContentView (Timeline& tl, shared_ptr<Content> c) + : ContentView (tl, c) + {} + +private: + wxString type () const + { + return _("audio"); + } + + wxColour colour () const + { + return wxColour (149, 121, 232, 255); + } +}; + +class VideoContentView : public ContentView +{ +public: + VideoContentView (Timeline& tl, shared_ptr<Content> c) + : ContentView (tl, c) + {} + +private: + + wxString type () const + { + if (dynamic_pointer_cast<FFmpegContent> (content ())) { + return _("video"); + } else { + return _("still"); + } + } + + wxColour colour () const + { + return wxColour (242, 92, 120, 255); + } +}; + +class TimeAxisView : public View +{ +public: + TimeAxisView (Timeline& tl, int y) + : View (tl) + , _y (y) + {} + + dcpomatic::Rect<int> bbox () const + { + return dcpomatic::Rect<int> (0, _y - 4, _timeline.width(), 24); + } + + void set_y (int y) + { + _y = y; + force_redraw (); + } + +private: + + void do_paint (wxGraphicsContext* gc) + { + gc->SetPen (*wxThePenList->FindOrCreatePen (wxColour (0, 0, 0), 1, wxPENSTYLE_SOLID)); + + int mark_interval = rint (128 / (TIME_HZ * _timeline.pixels_per_time_unit ())); + if (mark_interval > 5) { + mark_interval -= mark_interval % 5; + } + if (mark_interval > 10) { + mark_interval -= mark_interval % 10; + } + if (mark_interval > 60) { + mark_interval -= mark_interval % 60; + } + if (mark_interval > 3600) { + mark_interval -= mark_interval % 3600; + } + + if (mark_interval < 1) { + mark_interval = 1; + } + + wxGraphicsPath path = gc->CreatePath (); + path.MoveToPoint (_timeline.x_offset(), _y); + path.AddLineToPoint (_timeline.width(), _y); + gc->StrokePath (path); + + Time t = 0; + while ((t * _timeline.pixels_per_time_unit()) < _timeline.width()) { + wxGraphicsPath path = gc->CreatePath (); + path.MoveToPoint (time_x (t), _y - 4); + path.AddLineToPoint (time_x (t), _y + 4); + gc->StrokePath (path); + + int tc = t / TIME_HZ; + int const h = tc / 3600; + tc -= h * 3600; + int const m = tc / 60; + tc -= m * 60; + int const s = tc; + + wxString str = wxString::Format (wxT ("%02d:%02d:%02d"), h, m, s); + wxDouble str_width; + wxDouble str_height; + wxDouble str_descent; + wxDouble str_leading; + gc->GetTextExtent (str, &str_width, &str_height, &str_descent, &str_leading); + + int const tx = _timeline.x_offset() + t * _timeline.pixels_per_time_unit(); + if ((tx + str_width) < _timeline.width()) { + gc->DrawText (str, time_x (t), _y + 16); + } + + t += mark_interval * TIME_HZ; + } + } + +private: + int _y; +}; + +Timeline::Timeline (wxWindow* parent, FilmEditor* ed, shared_ptr<Film> film) + : wxPanel (parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE) + , _film_editor (ed) + , _film (film) + , _time_axis_view (new TimeAxisView (*this, 32)) + , _tracks (0) + , _pixels_per_time_unit (0) + , _left_down (false) + , _down_view_position (0) + , _first_move (false) + , _menu (film, this) +{ +#ifndef __WXOSX__ + SetDoubleBuffered (true); +#endif + + Bind (wxEVT_PAINT, boost::bind (&Timeline::paint, this)); + Bind (wxEVT_LEFT_DOWN, boost::bind (&Timeline::left_down, this, _1)); + Bind (wxEVT_LEFT_UP, boost::bind (&Timeline::left_up, this, _1)); + Bind (wxEVT_RIGHT_DOWN, boost::bind (&Timeline::right_down, this, _1)); + Bind (wxEVT_MOTION, boost::bind (&Timeline::mouse_moved, this, _1)); + Bind (wxEVT_SIZE, boost::bind (&Timeline::resized, this)); + + playlist_changed (); + + SetMinSize (wxSize (640, tracks() * track_height() + 96)); + + _playlist_connection = film->playlist()->Changed.connect (bind (&Timeline::playlist_changed, this)); +} + +void +Timeline::paint () +{ + wxPaintDC dc (this); + + wxGraphicsContext* gc = wxGraphicsContext::Create (dc); + if (!gc) { + return; + } + + gc->SetFont (gc->CreateFont (*wxNORMAL_FONT)); + + for (ViewList::iterator i = _views.begin(); i != _views.end(); ++i) { + (*i)->paint (gc); + } + + delete gc; +} + +void +Timeline::playlist_changed () +{ + ensure_ui_thread (); + + shared_ptr<const Film> fl = _film.lock (); + if (!fl) { + return; + } + + _views.clear (); + _views.push_back (_time_axis_view); + + ContentList content = fl->playlist()->content (); + + for (ContentList::iterator i = content.begin(); i != content.end(); ++i) { + if (dynamic_pointer_cast<VideoContent> (*i)) { + _views.push_back (shared_ptr<View> (new VideoContentView (*this, *i))); + } + if (dynamic_pointer_cast<AudioContent> (*i)) { + _views.push_back (shared_ptr<View> (new AudioContentView (*this, *i))); + } + } + + assign_tracks (); + setup_pixels_per_time_unit (); + Refresh (); +} + +void +Timeline::assign_tracks () +{ + for (ViewList::iterator i = _views.begin(); i != _views.end(); ++i) { + shared_ptr<ContentView> cv = dynamic_pointer_cast<ContentView> (*i); + if (cv) { + cv->set_track (0); + _tracks = 1; + } + } + + for (ViewList::iterator i = _views.begin(); i != _views.end(); ++i) { + shared_ptr<AudioContentView> acv = dynamic_pointer_cast<AudioContentView> (*i); + if (!acv) { + continue; + } + + shared_ptr<Content> acv_content = acv->content(); + + int t = 1; + while (1) { + ViewList::iterator j = _views.begin(); + while (j != _views.end()) { + shared_ptr<AudioContentView> test = dynamic_pointer_cast<AudioContentView> (*j); + if (!test) { + ++j; + continue; + } + + shared_ptr<Content> test_content = test->content(); + + if (test && test->track() == t) { + bool const no_overlap = + (acv_content->position() < test_content->position() && acv_content->end() < test_content->position()) || + (acv_content->position() > test_content->end() && acv_content->end() > test_content->end()); + + if (!no_overlap) { + /* we have an overlap on track `t' */ + ++t; + break; + } + } + + ++j; + } + + if (j == _views.end ()) { + /* no overlap on `t' */ + break; + } + } + + acv->set_track (t); + _tracks = max (_tracks, t + 1); + } + + _time_axis_view->set_y (tracks() * track_height() + 32); +} + +int +Timeline::tracks () const +{ + return _tracks; +} + +void +Timeline::setup_pixels_per_time_unit () +{ + shared_ptr<const Film> film = _film.lock (); + if (!film) { + return; + } + + _pixels_per_time_unit = static_cast<double>(width() - x_offset() * 2) / film->length (); +} + +shared_ptr<View> +Timeline::event_to_view (wxMouseEvent& ev) +{ + ViewList::iterator i = _views.begin(); + Position<int> const p (ev.GetX(), ev.GetY()); + while (i != _views.end() && !(*i)->bbox().contains (p)) { + ++i; + } + + if (i == _views.end ()) { + return shared_ptr<View> (); + } + + return *i; +} + +void +Timeline::left_down (wxMouseEvent& ev) +{ + shared_ptr<View> view = event_to_view (ev); + shared_ptr<ContentView> content_view = dynamic_pointer_cast<ContentView> (view); + + _down_view.reset (); + + if (content_view) { + _down_view = content_view; + _down_view_position = content_view->content()->position (); + } + + for (ViewList::iterator i = _views.begin(); i != _views.end(); ++i) { + shared_ptr<ContentView> cv = dynamic_pointer_cast<ContentView> (*i); + if (!cv) { + continue; + } + + if (!ev.ShiftDown ()) { + cv->set_selected (view == *i); + } + + if (view == *i) { + _film_editor->set_selection (cv->content ()); + } + } + + if (content_view && ev.ShiftDown ()) { + content_view->set_selected (!content_view->selected ()); + } + + _left_down = true; + _down_point = ev.GetPosition (); + _first_move = false; + + if (_down_view) { + _down_view->content()->set_change_signals_frequent (true); + } +} + +void +Timeline::left_up (wxMouseEvent& ev) +{ + _left_down = false; + + if (_down_view) { + _down_view->content()->set_change_signals_frequent (false); + } + + set_position_from_event (ev); +} + +void +Timeline::mouse_moved (wxMouseEvent& ev) +{ + if (!_left_down) { + return; + } + + set_position_from_event (ev); +} + +void +Timeline::right_down (wxMouseEvent& ev) +{ + shared_ptr<View> view = event_to_view (ev); + shared_ptr<ContentView> cv = dynamic_pointer_cast<ContentView> (view); + if (!cv) { + return; + } + + if (!cv->selected ()) { + clear_selection (); + cv->set_selected (true); + } + + _menu.popup (selected_content (), ev.GetPosition ()); +} + +void +Timeline::set_position_from_event (wxMouseEvent& ev) +{ + wxPoint const p = ev.GetPosition(); + + if (!_first_move) { + int const dist = sqrt (pow (p.x - _down_point.x, 2) + pow (p.y - _down_point.y, 2)); + if (dist < 8) { + return; + } + _first_move = true; + } + + Time const time_diff = (p.x - _down_point.x) / _pixels_per_time_unit; + if (_down_view) { + _down_view->content()->set_position (max (static_cast<Time> (0), _down_view_position + time_diff)); + + shared_ptr<Film> film = _film.lock (); + assert (film); + film->set_sequence_video (false); + } +} + +void +Timeline::force_redraw (dcpomatic::Rect<int> const & r) +{ + RefreshRect (wxRect (r.x, r.y, r.width, r.height), false); +} + +shared_ptr<const Film> +Timeline::film () const +{ + return _film.lock (); +} + +void +Timeline::resized () +{ + setup_pixels_per_time_unit (); +} + +void +Timeline::clear_selection () +{ + for (ViewList::iterator i = _views.begin(); i != _views.end(); ++i) { + shared_ptr<ContentView> cv = dynamic_pointer_cast<ContentView> (*i); + if (cv) { + cv->set_selected (false); + } + } +} + +Timeline::ContentViewList +Timeline::selected_views () const +{ + ContentViewList sel; + + for (ViewList::const_iterator i = _views.begin(); i != _views.end(); ++i) { + shared_ptr<ContentView> cv = dynamic_pointer_cast<ContentView> (*i); + if (cv && cv->selected()) { + sel.push_back (cv); + } + } + + return sel; +} + +ContentList +Timeline::selected_content () const +{ + ContentList sel; + ContentViewList views = selected_views (); + + for (ContentViewList::const_iterator i = views.begin(); i != views.end(); ++i) { + sel.push_back ((*i)->content ()); + } + + return sel; +} diff --git a/src/wx/timeline.h b/src/wx/timeline.h new file mode 100644 index 000000000..0217373b9 --- /dev/null +++ b/src/wx/timeline.h @@ -0,0 +1,100 @@ +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + + 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 <boost/shared_ptr.hpp> +#include <boost/weak_ptr.hpp> +#include <boost/signals2.hpp> +#include <wx/wx.h> +#include "lib/util.h" +#include "lib/rect.h" +#include "content_menu.h" + +class Film; +class View; +class ContentView; +class FilmEditor; +class TimeAxisView; + +class Timeline : public wxPanel +{ +public: + Timeline (wxWindow *, FilmEditor *, boost::shared_ptr<Film>); + + boost::shared_ptr<const Film> film () const; + + void force_redraw (dcpomatic::Rect<int> const &); + + int x_offset () const { + return 8; + } + + int width () const { + return GetSize().GetWidth (); + } + + int track_height () const { + return 48; + } + + double pixels_per_time_unit () const { + return _pixels_per_time_unit; + } + + Position<int> tracks_position () const { + return Position<int> (8, 8); + } + + int tracks () const; + + void setup_pixels_per_time_unit (); + +private: + void paint (); + void left_down (wxMouseEvent &); + void left_up (wxMouseEvent &); + void right_down (wxMouseEvent &); + void mouse_moved (wxMouseEvent &); + void playlist_changed (); + void resized (); + void assign_tracks (); + void set_position_from_event (wxMouseEvent &); + void clear_selection (); + + typedef std::vector<boost::shared_ptr<View> > ViewList; + typedef std::vector<boost::shared_ptr<ContentView> > ContentViewList; + + boost::shared_ptr<View> event_to_view (wxMouseEvent &); + ContentViewList selected_views () const; + ContentList selected_content () const; + + FilmEditor* _film_editor; + boost::weak_ptr<Film> _film; + ViewList _views; + boost::shared_ptr<TimeAxisView> _time_axis_view; + int _tracks; + double _pixels_per_time_unit; + bool _left_down; + wxPoint _down_point; + boost::shared_ptr<ContentView> _down_view; + Time _down_view_position; + bool _first_move; + ContentMenu _menu; + + boost::signals2::scoped_connection _playlist_connection; +}; diff --git a/src/wx/timeline_dialog.cc b/src/wx/timeline_dialog.cc new file mode 100644 index 000000000..9493d0acb --- /dev/null +++ b/src/wx/timeline_dialog.cc @@ -0,0 +1,42 @@ +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + + 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 <list> +#include <wx/graphics.h> +#include "lib/playlist.h" +#include "film_editor.h" +#include "timeline_dialog.h" +#include "wx_util.h" + +using std::list; +using std::cout; +using boost::shared_ptr; + +TimelineDialog::TimelineDialog (FilmEditor* ed, shared_ptr<Film> film) + : wxDialog (ed, wxID_ANY, _("Timeline"), wxDefaultPosition, wxSize (640, 512), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxFULL_REPAINT_ON_RESIZE) + , _timeline (this, ed, film) +{ + wxBoxSizer* sizer = new wxBoxSizer (wxVERTICAL); + + sizer->Add (&_timeline, 1, wxEXPAND | wxALL, 12); + + SetSizer (sizer); + sizer->Layout (); + sizer->SetSizeHints (this); +} diff --git a/src/wx/timeline_dialog.h b/src/wx/timeline_dialog.h new file mode 100644 index 000000000..17ca22c49 --- /dev/null +++ b/src/wx/timeline_dialog.h @@ -0,0 +1,34 @@ +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + + 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 <boost/shared_ptr.hpp> +#include <boost/weak_ptr.hpp> +#include <wx/wx.h> +#include "timeline.h" + +class Playlist; + +class TimelineDialog : public wxDialog +{ +public: + TimelineDialog (FilmEditor *, boost::shared_ptr<Film>); + +private: + Timeline _timeline; +}; diff --git a/src/wx/timing_panel.cc b/src/wx/timing_panel.cc new file mode 100644 index 000000000..ba645cf32 --- /dev/null +++ b/src/wx/timing_panel.cc @@ -0,0 +1,134 @@ +/* + Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net> + + 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 "lib/content.h" +#include "lib/still_image_content.h" +#include "timing_panel.h" +#include "wx_util.h" +#include "timecode.h" +#include "film_editor.h" + +using std::cout; +using boost::shared_ptr; +using boost::dynamic_pointer_cast; + +TimingPanel::TimingPanel (FilmEditor* e) + : FilmEditorPanel (e, _("Timing")) +{ + wxFlexGridSizer* grid = new wxFlexGridSizer (2, 4, 4); + _sizer->Add (grid, 0, wxALL, 8); + + add_label_to_sizer (grid, this, _("Position"), true); + _position = new Timecode (this); + grid->Add (_position); + add_label_to_sizer (grid, this, _("Length"), true); + _length = new Timecode (this); + grid->Add (_length); + add_label_to_sizer (grid, this, _("Trim from start"), true); + _trim_start = new Timecode (this); + grid->Add (_trim_start); + add_label_to_sizer (grid, this, _("Trim from end"), true); + _trim_end = new Timecode (this); + grid->Add (_trim_end); + + _position->Changed.connect (boost::bind (&TimingPanel::position_changed, this)); + _length->Changed.connect (boost::bind (&TimingPanel::length_changed, this)); + _trim_start->Changed.connect (boost::bind (&TimingPanel::trim_start_changed, this)); + _trim_end->Changed.connect (boost::bind (&TimingPanel::trim_end_changed, this)); +} + +void +TimingPanel::film_content_changed (shared_ptr<Content> content, int property) +{ + if (property == ContentProperty::POSITION) { + if (content) { + _position->set (content->position (), _editor->film()->video_frame_rate ()); + } else { + _position->set (0, 24); + } + } else if (property == ContentProperty::LENGTH) { + if (content) { + _length->set (content->full_length (), _editor->film()->video_frame_rate ()); + } else { + _length->set (0, 24); + } + } else if (property == ContentProperty::TRIM_START) { + if (content) { + _trim_start->set (content->trim_start (), _editor->film()->video_frame_rate ()); + } else { + _trim_start->set (0, 24); + } + } else if (property == ContentProperty::TRIM_END) { + if (content) { + _trim_end->set (content->trim_end (), _editor->film()->video_frame_rate ()); + } else { + _trim_end->set (0, 24); + } + } + + _length->set_editable (dynamic_pointer_cast<StillImageContent> (content)); +} + +void +TimingPanel::position_changed () +{ + shared_ptr<Content> c = _editor->selected_content (); + if (!c) { + return; + } + + c->set_position (_position->get (_editor->film()->video_frame_rate ())); +} + +void +TimingPanel::length_changed () +{ + shared_ptr<Content> c = _editor->selected_content (); + if (!c) { + return; + } + + shared_ptr<StillImageContent> ic = dynamic_pointer_cast<StillImageContent> (c); + if (ic) { + ic->set_video_length (rint (_length->get (_editor->film()->video_frame_rate()) * ic->video_frame_rate() / TIME_HZ)); + } +} + +void +TimingPanel::trim_start_changed () +{ + shared_ptr<Content> c = _editor->selected_content (); + if (!c) { + return; + } + + c->set_trim_start (_trim_start->get (_editor->film()->video_frame_rate ())); +} + + +void +TimingPanel::trim_end_changed () +{ + shared_ptr<Content> c = _editor->selected_content (); + if (!c) { + return; + } + + c->set_trim_end (_trim_end->get (_editor->film()->video_frame_rate ())); +} diff --git a/src/wx/timing_panel.h b/src/wx/timing_panel.h new file mode 100644 index 000000000..b84ea52be --- /dev/null +++ b/src/wx/timing_panel.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net> + + 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 "film_editor_panel.h" + +class Timecode; + +class TimingPanel : public FilmEditorPanel +{ +public: + TimingPanel (FilmEditor *); + + void film_content_changed (boost::shared_ptr<Content>, int); + +private: + void position_changed (); + void length_changed (); + void trim_start_changed (); + void trim_end_changed (); + + Timecode* _position; + Timecode* _length; + Timecode* _trim_start; + Timecode* _trim_end; +}; diff --git a/src/wx/video_panel.cc b/src/wx/video_panel.cc new file mode 100644 index 000000000..bb8476d63 --- /dev/null +++ b/src/wx/video_panel.cc @@ -0,0 +1,393 @@ +/* + Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net> + + 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 <wx/spinctrl.h> +#include "lib/ratio.h" +#include "lib/filter.h" +#include "lib/ffmpeg_content.h" +#include "lib/colour_conversion.h" +#include "lib/config.h" +#include "filter_dialog.h" +#include "video_panel.h" +#include "wx_util.h" +#include "film_editor.h" +#include "content_colour_conversion_dialog.h" + +using std::vector; +using std::string; +using std::pair; +using std::cout; +using std::list; +using boost::shared_ptr; +using boost::dynamic_pointer_cast; +using boost::bind; +using boost::optional; + +VideoPanel::VideoPanel (FilmEditor* e) + : FilmEditorPanel (e, _("Video")) +{ + wxGridBagSizer* grid = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + _sizer->Add (grid, 0, wxALL, 8); + + int r = 0; + + add_label_to_grid_bag_sizer (grid, this, _("Type"), true, wxGBPosition (r, 0)); + _frame_type = new wxChoice (this, wxID_ANY); + grid->Add (_frame_type, wxGBPosition (r, 1)); + ++r; + + add_label_to_grid_bag_sizer (grid, this, _("Left crop"), true, wxGBPosition (r, 0)); + _left_crop = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)); + grid->Add (_left_crop, wxGBPosition (r, 1)); + ++r; + + add_label_to_grid_bag_sizer (grid, this, _("Right crop"), true, wxGBPosition (r, 0)); + _right_crop = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)); + grid->Add (_right_crop, wxGBPosition (r, 1)); + ++r; + + add_label_to_grid_bag_sizer (grid, this, _("Top crop"), true, wxGBPosition (r, 0)); + _top_crop = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)); + grid->Add (_top_crop, wxGBPosition (r, 1)); + ++r; + + add_label_to_grid_bag_sizer (grid, this, _("Bottom crop"), true, wxGBPosition (r, 0)); + _bottom_crop = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)); + grid->Add (_bottom_crop, wxGBPosition (r, 1)); + ++r; + + add_label_to_grid_bag_sizer (grid, this, _("Scale to"), true, wxGBPosition (r, 0)); + _ratio = new wxChoice (this, wxID_ANY); + grid->Add (_ratio, wxGBPosition (r, 1)); + ++r; + + { + add_label_to_grid_bag_sizer (grid, this, _("Filters"), true, wxGBPosition (r, 0)); + wxSizer* s = new wxBoxSizer (wxHORIZONTAL); + + wxClientDC dc (this); + wxSize size = dc.GetTextExtent (wxT ("A quite long name")); + size.SetHeight (-1); + + _filters = new wxStaticText (this, wxID_ANY, _("None"), wxDefaultPosition, size); + s->Add (_filters, 1, wxEXPAND | wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM | wxRIGHT, 6); + _filters_button = new wxButton (this, wxID_ANY, _("Edit...")); + s->Add (_filters_button, 0, wxALIGN_CENTER_VERTICAL); + grid->Add (s, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); + } + ++r; + + { + add_label_to_grid_bag_sizer (grid, this, _("Colour conversion"), true, wxGBPosition (r, 0)); + wxSizer* s = new wxBoxSizer (wxHORIZONTAL); + + wxClientDC dc (this); + wxSize size = dc.GetTextExtent (wxT ("A quite long name")); + size.SetHeight (-1); + + _colour_conversion = new wxStaticText (this, wxID_ANY, wxT (""), wxDefaultPosition, size); + + s->Add (_colour_conversion, 1, wxEXPAND | wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM | wxRIGHT, 6); + _colour_conversion_button = new wxButton (this, wxID_ANY, _("Edit...")); + s->Add (_colour_conversion_button, 0, wxALIGN_CENTER_VERTICAL); + grid->Add (s, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); + } + ++r; + + _description = new wxStaticText (this, wxID_ANY, wxT ("\n \n \n \n \n"), wxDefaultPosition, wxDefaultSize); + grid->Add (_description, wxGBPosition (r, 0), wxGBSpan (1, 2), wxEXPAND | wxALIGN_CENTER_VERTICAL | wxALL, 6); + wxFont font = _description->GetFont(); + font.SetStyle(wxFONTSTYLE_ITALIC); + font.SetPointSize(font.GetPointSize() - 1); + _description->SetFont(font); + ++r; + + _left_crop->SetRange (0, 1024); + _top_crop->SetRange (0, 1024); + _right_crop->SetRange (0, 1024); + _bottom_crop->SetRange (0, 1024); + + vector<Ratio const *> ratios = Ratio::all (); + _ratio->Clear (); + for (vector<Ratio const *>::iterator i = ratios.begin(); i != ratios.end(); ++i) { + _ratio->Append (std_to_wx ((*i)->nickname ())); + } + + _frame_type->Append (_("2D")); + _frame_type->Append (_("3D left/right")); + + _frame_type->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&VideoPanel::frame_type_changed, this)); + _left_crop->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::left_crop_changed, this)); + _right_crop->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::right_crop_changed, this)); + _top_crop->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::top_crop_changed, this)); + _bottom_crop->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::bottom_crop_changed, this)); + _ratio->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&VideoPanel::ratio_changed, this)); + _filters_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&VideoPanel::edit_filters_clicked, this)); + _colour_conversion_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&VideoPanel::edit_colour_conversion_clicked, this)); +} + + +/** Called when the left crop widget has been changed */ +void +VideoPanel::left_crop_changed () +{ + shared_ptr<VideoContent> c = _editor->selected_video_content (); + if (!c) { + return; + } + + c->set_left_crop (_left_crop->GetValue ()); +} + +/** Called when the right crop widget has been changed */ +void +VideoPanel::right_crop_changed () +{ + shared_ptr<VideoContent> c = _editor->selected_video_content (); + if (!c) { + return; + } + + c->set_right_crop (_right_crop->GetValue ()); +} + +/** Called when the top crop widget has been changed */ +void +VideoPanel::top_crop_changed () +{ + shared_ptr<VideoContent> c = _editor->selected_video_content (); + if (!c) { + return; + } + + c->set_top_crop (_top_crop->GetValue ()); +} + +/** Called when the bottom crop value has been changed */ +void +VideoPanel::bottom_crop_changed () +{ + shared_ptr<VideoContent> c = _editor->selected_video_content (); + if (!c) { + return; + } + + c->set_bottom_crop (_bottom_crop->GetValue ()); +} + +void +VideoPanel::film_changed (Film::Property property) +{ + switch (property) { + case Film::CONTAINER: + case Film::VIDEO_FRAME_RATE: + setup_description (); + break; + default: + break; + } +} + +void +VideoPanel::film_content_changed (shared_ptr<Content> c, int property) +{ + shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (c); + shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (c); + + if (property == VideoContentProperty::VIDEO_FRAME_TYPE) { + checked_set (_frame_type, vc ? vc->video_frame_type () : VIDEO_FRAME_TYPE_2D); + setup_description (); + } else if (property == VideoContentProperty::VIDEO_CROP) { + checked_set (_left_crop, vc ? vc->crop().left : 0); + checked_set (_right_crop, vc ? vc->crop().right : 0); + checked_set (_top_crop, vc ? vc->crop().top : 0); + checked_set (_bottom_crop, vc ? vc->crop().bottom : 0); + setup_description (); + } else if (property == VideoContentProperty::VIDEO_RATIO) { + if (vc) { + int n = 0; + vector<Ratio const *> ratios = Ratio::all (); + vector<Ratio const *>::iterator i = ratios.begin (); + while (i != ratios.end() && *i != vc->ratio()) { + ++i; + ++n; + } + + if (i == ratios.end()) { + checked_set (_ratio, -1); + } else { + checked_set (_ratio, n); + } + } else { + checked_set (_ratio, -1); + } + setup_description (); + } else if (property == VideoContentProperty::VIDEO_FRAME_RATE) { + setup_description (); + } else if (property == VideoContentProperty::COLOUR_CONVERSION) { + optional<size_t> preset = vc ? vc->colour_conversion().preset () : optional<size_t> (); + vector<PresetColourConversion> cc = Config::instance()->colour_conversions (); + _colour_conversion->SetLabel (preset ? std_to_wx (cc[preset.get()].name) : _("Custom")); + } else if (property == FFmpegContentProperty::FILTERS) { + if (fc) { + pair<string, string> p = Filter::ffmpeg_strings (fc->filters ()); + if (p.first.empty () && p.second.empty ()) { + _filters->SetLabel (_("None")); + } else { + string const b = p.first + " " + p.second; + _filters->SetLabel (std_to_wx (b)); + } + } + } +} + +/** Called when the `Edit filters' button has been clicked */ +void +VideoPanel::edit_filters_clicked () +{ + shared_ptr<Content> c = _editor->selected_content (); + if (!c) { + return; + } + + shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (c); + if (!fc) { + return; + } + + FilterDialog* d = new FilterDialog (this, fc->filters()); + d->ActiveChanged.connect (bind (&FFmpegContent::set_filters, fc, _1)); + d->ShowModal (); + d->Destroy (); +} + +void +VideoPanel::setup_description () +{ + shared_ptr<VideoContent> vc = _editor->selected_video_content (); + if (!vc) { + _description->SetLabel (""); + return; + } + + wxString d; + + int lines = 0; + + if (vc->video_size().width && vc->video_size().height) { + d << wxString::Format ( + _("Content video is %dx%d (%.2f:1)\n"), + vc->video_size_after_3d_split().width, vc->video_size_after_3d_split().height, + float (vc->video_size_after_3d_split().width) / vc->video_size_after_3d_split().height + ); + ++lines; + } + + Crop const crop = vc->crop (); + if ((crop.left || crop.right || crop.top || crop.bottom) && vc->video_size() != libdcp::Size (0, 0)) { + libdcp::Size cropped = vc->video_size_after_3d_split (); + cropped.width -= crop.left + crop.right; + cropped.height -= crop.top + crop.bottom; + d << wxString::Format ( + _("Cropped to %dx%d (%.2f:1)\n"), + cropped.width, cropped.height, + float (cropped.width) / cropped.height + ); + ++lines; + } + + Ratio const * ratio = vc->ratio (); + if (ratio) { + libdcp::Size container_size = _editor->film()->container()->size (_editor->film()->full_frame ()); + + libdcp::Size const scaled = ratio->size (container_size); + d << wxString::Format ( + _("Scaled to %dx%d (%.2f:1)\n"), + scaled.width, scaled.height, + float (scaled.width) / scaled.height + ); + ++lines; + + if (scaled != container_size) { + d << wxString::Format ( + _("Padded with black to %dx%d (%.2f:1)\n"), + container_size.width, container_size.height, + float (container_size.width) / container_size.height + ); + ++lines; + } + } + + d << wxString::Format (_("Content frame rate %.4f\n"), vc->video_frame_rate ()); + ++lines; + FrameRateConversion frc (vc->video_frame_rate(), _editor->film()->video_frame_rate ()); + d << frc.description << "\n"; + ++lines; + + for (int i = lines; i < 6; ++i) { + d << wxT ("\n "); + } + + _description->SetLabel (d); + _sizer->Layout (); +} + + +void +VideoPanel::ratio_changed () +{ + if (!_editor->film ()) { + return; + } + + shared_ptr<VideoContent> vc = _editor->selected_video_content (); + + int const n = _ratio->GetSelection (); + if (n >= 0) { + vector<Ratio const *> ratios = Ratio::all (); + assert (n < int (ratios.size())); + vc->set_ratio (ratios[n]); + } +} + +void +VideoPanel::frame_type_changed () +{ + shared_ptr<VideoContent> vc = _editor->selected_video_content (); + if (vc) { + vc->set_video_frame_type (static_cast<VideoFrameType> (_frame_type->GetSelection ())); + } +} + +void +VideoPanel::edit_colour_conversion_clicked () +{ + shared_ptr<VideoContent> vc = _editor->selected_video_content (); + if (!vc) { + return; + } + + ColourConversion conversion = vc->colour_conversion (); + ContentColourConversionDialog* d = new ContentColourConversionDialog (this); + d->set (conversion); + d->ShowModal (); + + vc->set_colour_conversion (d->get ()); + d->Destroy (); +} diff --git a/src/wx/video_panel.h b/src/wx/video_panel.h new file mode 100644 index 000000000..2ecf3c87f --- /dev/null +++ b/src/wx/video_panel.h @@ -0,0 +1,60 @@ +/* + Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net> + + 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 "lib/film.h" +#include "film_editor_panel.h" + +class wxChoice; +class wxStaticText; +class wxSpinCtrl; +class wxButton; + +class VideoPanel : public FilmEditorPanel +{ +public: + VideoPanel (FilmEditor *); + + void film_changed (Film::Property); + void film_content_changed (boost::shared_ptr<Content>, int); + +private: + void left_crop_changed (); + void right_crop_changed (); + void top_crop_changed (); + void bottom_crop_changed (); + void edit_filters_clicked (); + void ratio_changed (); + void frame_type_changed (); + void edit_colour_conversion_clicked (); + + void setup_description (); + + wxChoice* _frame_type; + wxSpinCtrl* _left_crop; + wxSpinCtrl* _right_crop; + wxSpinCtrl* _top_crop; + wxSpinCtrl* _bottom_crop; + wxChoice* _ratio; + wxStaticText* _ratio_description; + wxStaticText* _description; + wxStaticText* _filters; + wxButton* _filters_button; + wxStaticText* _colour_conversion; + wxButton* _colour_conversion_button; +}; diff --git a/src/wx/wscript b/src/wx/wscript index 82d9d3738..8f35e2fac 100644 --- a/src/wx/wscript +++ b/src/wx/wscript @@ -1,5 +1,66 @@ +import os +import glob +from waflib import Logs +import i18n + +sources = """ + about_dialog.cc + audio_dialog.cc + audio_mapping_view.cc + audio_panel.cc + audio_plot.cc + cinema_dialog.cc + colour_conversion_editor.cc + config_dialog.cc + content_colour_conversion_dialog.cc + content_menu.cc + dci_metadata_dialog.cc + dir_picker_ctrl.cc + film_editor.cc + film_editor_panel.cc + film_viewer.cc + filter_dialog.cc + filter_editor.cc + gain_calculator_dialog.cc + job_manager_view.cc + job_wrapper.cc + kdm_dialog.cc + new_film_dialog.cc + preset_colour_conversion_dialog.cc + properties_dialog.cc + repeat_dialog.cc + screen_dialog.cc + server_dialog.cc + subtitle_panel.cc + timecode.cc + timeline.cc + timeline_dialog.cc + timing_panel.cc + video_panel.cc + wx_util.cc + wx_ui_signaller.cc + """ + def configure(conf): - conf.check_cfg(package = '', path = 'wx-config', args = '--cppflags --cxxflags --libs', uselib_store = 'WXWIDGETS', mandatory = True) + args = '--cppflags --cxxflags' + if not conf.env.STATIC: + args += ' --libs' + + conf.check_cfg(msg='Checking for wxWidgets', package='', path=conf.options.wx_config, args=args, + uselib_store='WXWIDGETS', mandatory=True) + + if conf.env.STATIC: + # wx-config returns its static libraries as full paths, without -l prefixes, which confuses + # check_cfg(), so just hard-code it all. + conf.env.STLIB_WXWIDGETS = ['wx_gtk2u_xrc-2.9', 'wx_gtk2u_qa-2.9', 'wx_baseu_net-2.9', 'wx_gtk2u_html-2.9', + 'wx_gtk2u_adv-2.9', 'wx_gtk2u_core-2.9', 'wx_baseu_xml-2.9', 'wx_baseu-2.9'] + conf.env.LIB_WXWIDGETS = ['tiff', 'SM', 'dl', 'jpeg', 'png', 'X11'] + + conf.in_msg = 1 + wx_version = conf.check_cfg(package='', path=conf.options.wx_config, args='--version').strip() + conf.im_msg = 0 + if wx_version != '2.9.4' and wx_version != '2.9.5': + conf.fatal('wxwidgets version 2.9.4 or 2.9.5 is required; %s found' % wx_version) def build(bld): if bld.env.STATIC: @@ -7,30 +68,20 @@ def build(bld): else: obj = bld(features = 'cxx cxxshlib') - obj.name = 'libdvdomatic-wx' - obj.includes = [ '..' ] - obj.export_includes = ['.'] + obj.name = 'libdcpomatic-wx' +# obj.includes = [ '..' ] + obj.export_includes = ['..'] obj.uselib = 'WXWIDGETS' - obj.use = 'libdvdomatic' - obj.source = """ - config_dialog.cc - dci_name_dialog.cc - dir_picker_ctrl.cc - film_editor.cc - film_viewer.cc - filter_dialog.cc - filter_view.cc - gain_calculator_dialog.cc - job_manager_view.cc - job_wrapper.cc - kdm_dialog.cc - cinema_dialog.cc - new_film_dialog.cc - screen_dialog.cc - properties_dialog.cc - server_dialog.cc - wx_util.cc - wx_ui_signaller.cc - """ - - obj.target = 'dvdomatic-wx' + if bld.env.TARGET_LINUX: + obj.uselib += ' GTK' + obj.use = 'libdcpomatic' + obj.source = sources + obj.target = 'dcpomatic-wx' + + i18n.po_to_mo(os.path.join('src', 'wx'), 'libdcpomatic-wx', bld) + +def pot(bld): + i18n.pot(os.path.join('src', 'wx'), sources, 'libdcpomatic-wx') + +def pot_merge(bld): + i18n.pot_merge(os.path.join('src', 'wx'), 'libdcpomatic-wx') diff --git a/src/wx/wx_ui_signaller.cc b/src/wx/wx_ui_signaller.cc index 2e926edc6..f30631960 100644 --- a/src/wx/wx_ui_signaller.cc +++ b/src/wx/wx_ui_signaller.cc @@ -29,6 +29,6 @@ wxUISignaller::wxUISignaller (wxEvtHandler* h) void wxUISignaller::wake_ui () { - wxCommandEvent event (-1, -1); - _handler->AddPendingEvent (event); + wxCommandEvent event (-1, -1); + _handler->AddPendingEvent (event); } diff --git a/src/wx/wx_ui_signaller.h b/src/wx/wx_ui_signaller.h index d134d2b6d..f7df6fca4 100644 --- a/src/wx/wx_ui_signaller.h +++ b/src/wx/wx_ui_signaller.h @@ -17,7 +17,7 @@ */ -#include "ui_signaller.h" +#include "lib/ui_signaller.h" class wxEvtHandler; diff --git a/src/wx/wx_util.cc b/src/wx/wx_util.cc index bc444e4bc..20fd2df75 100644 --- a/src/wx/wx_util.cc +++ b/src/wx/wx_util.cc @@ -24,6 +24,8 @@ #include <boost/thread.hpp> #include <wx/filepicker.h> #include <wx/spinctrl.h> +#include "lib/config.h" +#include "lib/util.h" #include "wx_util.h" using namespace std; @@ -33,13 +35,45 @@ using namespace boost; * @param s Sizer to add to. * @param p Parent window for the wxStaticText. * @param t Text for the wxStaticText. + * @param left true if this label is a `left label'; ie the sort + * of label which should be right-aligned on OS X. * @param prop Proportion to pass when calling Add() on the wxSizer. */ wxStaticText * -add_label_to_sizer (wxSizer* s, wxWindow* p, string t, int prop) +#ifdef __WXOSX__ +add_label_to_sizer (wxSizer* s, wxWindow* p, wxString t, bool left, int prop) +#else +add_label_to_sizer (wxSizer* s, wxWindow* p, wxString t, bool, int prop) +#endif { - wxStaticText* m = new wxStaticText (p, wxID_ANY, std_to_wx (t)); - s->Add (m, prop, wxALIGN_CENTER_VERTICAL | wxALL, 6); + int flags = wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT; +#ifdef __WXOSX__ + if (left) { + flags |= wxALIGN_RIGHT; + t += wxT (":"); + } +#endif + wxStaticText* m = new wxStaticText (p, wxID_ANY, t); + s->Add (m, prop, flags, 6); + return m; +} + +wxStaticText * +#ifdef __WXOSX__ +add_label_to_grid_bag_sizer (wxGridBagSizer* s, wxWindow* p, wxString t, bool left, wxGBPosition pos, wxGBSpan span) +#else +add_label_to_grid_bag_sizer (wxGridBagSizer* s, wxWindow* p, wxString t, bool, wxGBPosition pos, wxGBSpan span) +#endif +{ + int flags = wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT; +#ifdef __WXOSX__ + if (left) { + flags |= wxALIGN_RIGHT; + t += wxT (":"); + } +#endif + wxStaticText* m = new wxStaticText (p, wxID_ANY, t); + s->Add (m, pos, span, flags); return m; } @@ -48,13 +82,23 @@ add_label_to_sizer (wxSizer* s, wxWindow* p, string t, int prop) * @param m Message. */ void -error_dialog (wxWindow* parent, string m) +error_dialog (wxWindow* parent, wxString m) { - wxMessageDialog* d = new wxMessageDialog (parent, std_to_wx (m), wxT ("DVD-o-matic"), wxOK); + wxMessageDialog* d = new wxMessageDialog (parent, m, _("DCP-o-matic"), wxOK); d->ShowModal (); d->Destroy (); } +bool +confirm_dialog (wxWindow* parent, wxString m) +{ + wxMessageDialog* d = new wxMessageDialog (parent, m, _("DCP-o-matic"), wxYES_NO | wxICON_QUESTION); + int const r = d->ShowModal (); + d->Destroy (); + return r == wxID_YES; +} + + /** @param s wxWidgets string. * @return Corresponding STL string. */ @@ -79,10 +123,10 @@ int const ThreadedStaticText::_update_event_id = 10000; * @param initial Initial text for the wxStaticText while the computation is being run. * @param fn Function which works out what the wxStaticText content should be and returns it. */ -ThreadedStaticText::ThreadedStaticText (wxWindow* parent, string initial, function<string ()> fn) - : wxStaticText (parent, wxID_ANY, std_to_wx (initial)) +ThreadedStaticText::ThreadedStaticText (wxWindow* parent, wxString initial, function<string ()> fn) + : wxStaticText (parent, wxID_ANY, initial) { - Connect (_update_event_id, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (ThreadedStaticText::thread_finished), 0, this); + Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ThreadedStaticText::thread_finished, this, _1), _update_event_id); _thread = new thread (bind (&ThreadedStaticText::run, this, fn)); } @@ -138,22 +182,15 @@ checked_set (wxSpinCtrl* widget, int value) } void -checked_set (wxComboBox* widget, int value) +checked_set (wxChoice* widget, int value) { if (widget->GetSelection() != value) { - if (value == wxNOT_FOUND) { - /* Work around an apparent wxWidgets bug; SetSelection (wxNOT_FOUND) - appears not to work sometimes. - */ - widget->SetValue (wxT ("")); - } else { - widget->SetSelection (value); - } + widget->SetSelection (value); } } void -checked_set (wxComboBox* widget, string value) +checked_set (wxChoice* widget, string value) { wxClientData* o = 0; if (widget->GetSelection() != -1) { @@ -178,6 +215,14 @@ checked_set (wxTextCtrl* widget, string value) } void +checked_set (wxStaticText* widget, string value) +{ + if (widget->GetLabel() != std_to_wx (value)) { + widget->SetLabel (std_to_wx (value)); + } +} + +void checked_set (wxCheckBox* widget, bool value) { if (widget->GetValue() != value) { @@ -192,3 +237,42 @@ checked_set (wxRadioButton* widget, bool value) widget->SetValue (value); } } + +void +dcpomatic_setup_i18n () +{ + int language = wxLANGUAGE_DEFAULT; + + boost::optional<string> config_lang = Config::instance()->language (); + if (config_lang && !config_lang->empty ()) { + wxLanguageInfo const * li = wxLocale::FindLanguageInfo (std_to_wx (config_lang.get ())); + if (li) { + language = li->Language; + } + } + + wxLocale* locale = 0; + if (wxLocale::IsAvailable (language)) { + locale = new wxLocale (language, wxLOCALE_LOAD_DEFAULT); + +#ifdef DCPOMATIC_WINDOWS + locale->AddCatalogLookupPathPrefix (std_to_wx (mo_path().string())); +#endif + +#ifdef DCPOMATIC_POSIX + locale->AddCatalogLookupPathPrefix (POSIX_LOCALE_PREFIX); +#endif + + locale->AddCatalog (wxT ("libdcpomatic-wx")); + locale->AddCatalog (wxT ("dcpomatic")); + + if (!locale->IsOk()) { + delete locale; + locale = new wxLocale (wxLANGUAGE_ENGLISH); + } + } + + if (locale) { + dcpomatic_setup_gettext_i18n (wx_to_std (locale->GetCanonicalName ())); + } +} diff --git a/src/wx/wx_util.h b/src/wx/wx_util.h index 6cb7fd002..d942d8fa8 100644 --- a/src/wx/wx_util.h +++ b/src/wx/wx_util.h @@ -17,21 +17,36 @@ */ +#ifndef DCPOMATIC_WX_UTIL_H +#define DCPOMATIC_WX_UTIL_H + #include <wx/wx.h> +#include <wx/gbsizer.h> #include <boost/function.hpp> #include <boost/thread.hpp> +#ifdef __WXGTK__ +#include <gtk/gtk.h> +#endif class wxFilePickerCtrl; class wxSpinCtrl; +class wxGridBagSizer; + +#define DCPOMATIC_SIZER_X_GAP 8 +#define DCPOMATIC_SIZER_Y_GAP 8 +#define DCPOMATIC_DIALOG_BORDER 12 /** @file src/wx/wx_util.h * @brief Some utility functions and classes. */ -extern void error_dialog (wxWindow *, std::string); -extern wxStaticText* add_label_to_sizer (wxSizer *, wxWindow *, std::string, int prop = 0); +extern void error_dialog (wxWindow *, wxString); +extern bool confirm_dialog (wxWindow *, wxString); +extern wxStaticText* add_label_to_sizer (wxSizer *, wxWindow *, wxString, bool left, int prop = 0); +extern wxStaticText* add_label_to_grid_bag_sizer (wxGridBagSizer *, wxWindow *, wxString, bool, wxGBPosition, wxGBSpan span = wxDefaultSpan); extern std::string wx_to_std (wxString); extern wxString std_to_wx (std::string); +extern void dcpomatic_setup_i18n (); /** @class ThreadedStaticText * @@ -41,7 +56,7 @@ extern wxString std_to_wx (std::string); class ThreadedStaticText : public wxStaticText { public: - ThreadedStaticText (wxWindow* parent, std::string initial, boost::function<std::string ()> fn); + ThreadedStaticText (wxWindow* parent, wxString initial, boost::function<std::string ()> fn); ~ThreadedStaticText (); private: @@ -58,8 +73,18 @@ extern std::string string_client_data (wxClientData* o); extern void checked_set (wxFilePickerCtrl* widget, std::string value); extern void checked_set (wxSpinCtrl* widget, int value); -extern void checked_set (wxComboBox* widget, int value); -extern void checked_set (wxComboBox* widget, std::string value); +extern void checked_set (wxChoice* widget, int value); +extern void checked_set (wxChoice* widget, std::string value); extern void checked_set (wxTextCtrl* widget, std::string value); extern void checked_set (wxCheckBox* widget, bool value); extern void checked_set (wxRadioButton* widget, bool value); +extern void checked_set (wxStaticText* widget, std::string value); + +/* GTK 2.24.17 has a buggy GtkFileChooserButton and it was put in Ubuntu 13.04. + Use our own dir picker as this is the least bad option I can think of. +*/ +#if defined(__WXMSW__) || (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION == 24 && GTK_MICRO_VERSION == 17) +#define DCPOMATIC_USE_OWN_DIR_PICKER +#endif + +#endif |
