summaryrefslogtreecommitdiff
path: root/src/wx
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2013-09-17 23:39:05 +0100
committerCarl Hetherington <cth@carlh.net>2013-09-17 23:39:05 +0100
commit373f010a7f04add1f49169cbaa60cb7ae5f508d4 (patch)
treea61fe014cbefc775dcf3a5c9a45d06e391e65b31 /src/wx
parent048f9b6b5569f03d1342a04f75c83a2bad340996 (diff)
parente888e92f354b9868337b0b022ff9be38b9c36c0f (diff)
Merge 1.0 in.
Diffstat (limited to 'src/wx')
-rw-r--r--src/wx/about_dialog.cc159
-rw-r--r--src/wx/about_dialog.h (renamed from src/wx/film_list.h)23
-rw-r--r--src/wx/audio_dialog.cc177
-rw-r--r--src/wx/audio_dialog.h50
-rw-r--r--src/wx/audio_mapping_view.cc207
-rw-r--r--src/wx/audio_mapping_view.h42
-rw-r--r--src/wx/audio_panel.cc288
-rw-r--r--src/wx/audio_panel.h55
-rw-r--r--src/wx/audio_plot.cc281
-rw-r--r--src/wx/audio_plot.h64
-rw-r--r--src/wx/cinema_dialog.cc4
-rw-r--r--src/wx/colour_conversion_editor.cc152
-rw-r--r--src/wx/colour_conversion_editor.h48
-rw-r--r--src/wx/config_dialog.cc487
-rw-r--r--src/wx/config_dialog.h75
-rw-r--r--src/wx/content_colour_conversion_dialog.cc121
-rw-r--r--src/wx/content_colour_conversion_dialog.h41
-rw-r--r--src/wx/content_menu.cc96
-rw-r--r--src/wx/content_menu.h48
-rw-r--r--src/wx/dci_metadata_dialog.cc106
-rw-r--r--src/wx/dci_metadata_dialog.h (renamed from src/wx/dci_name_dialog.h)19
-rw-r--r--src/wx/dci_name_dialog.cc131
-rw-r--r--src/wx/dir_picker_ctrl.cc17
-rw-r--r--src/wx/dir_picker_ctrl.h2
-rw-r--r--src/wx/editable_list.h176
-rw-r--r--src/wx/film_editor.cc1335
-rw-r--r--src/wx/film_editor.h207
-rw-r--r--src/wx/film_editor_panel.cc34
-rw-r--r--src/wx/film_editor_panel.h43
-rw-r--r--src/wx/film_list.cc65
-rw-r--r--src/wx/film_viewer.cc404
-rw-r--r--src/wx/film_viewer.h60
-rw-r--r--src/wx/filter_dialog.cc4
-rw-r--r--src/wx/filter_dialog.h5
-rw-r--r--src/wx/filter_editor.cc (renamed from src/wx/filter_view.cc)47
-rw-r--r--src/wx/filter_editor.h (renamed from src/wx/filter_view.h)10
-rw-r--r--src/wx/gain_calculator_dialog.cc10
-rw-r--r--src/wx/job_manager_view.cc198
-rw-r--r--src/wx/job_manager_view.h22
-rw-r--r--src/wx/job_wrapper.cc8
-rw-r--r--src/wx/job_wrapper.h2
-rw-r--r--src/wx/kdm_dialog.cc23
-rw-r--r--src/wx/new_film_dialog.cc37
-rw-r--r--src/wx/new_film_dialog.h7
-rw-r--r--src/wx/po/es_ES.po673
-rw-r--r--src/wx/po/fr_FR.po676
-rw-r--r--src/wx/po/it_IT.po684
-rw-r--r--src/wx/po/sv_SE.po679
-rw-r--r--src/wx/preset_colour_conversion_dialog.cc69
-rw-r--r--src/wx/preset_colour_conversion_dialog.h35
-rw-r--r--src/wx/properties_dialog.cc45
-rw-r--r--src/wx/properties_dialog.h3
-rw-r--r--src/wx/repeat_dialog.cc54
-rw-r--r--src/wx/repeat_dialog.h32
-rw-r--r--src/wx/screen_dialog.cc4
-rw-r--r--src/wx/server_dialog.cc57
-rw-r--r--src/wx/server_dialog.h9
-rw-r--r--src/wx/subtitle_panel.cc192
-rw-r--r--src/wx/subtitle_panel.h46
-rw-r--r--src/wx/timecode.cc139
-rw-r--r--src/wx/timecode.h50
-rw-r--r--src/wx/timeline.cc652
-rw-r--r--src/wx/timeline.h100
-rw-r--r--src/wx/timeline_dialog.cc42
-rw-r--r--src/wx/timeline_dialog.h34
-rw-r--r--src/wx/timing_panel.cc134
-rw-r--r--src/wx/timing_panel.h41
-rw-r--r--src/wx/video_panel.cc393
-rw-r--r--src/wx/video_panel.h60
-rw-r--r--src/wx/wscript105
-rw-r--r--src/wx/wx_ui_signaller.cc4
-rw-r--r--src/wx/wx_ui_signaller.h2
-rw-r--r--src/wx/wx_util.cc120
-rw-r--r--src/wx/wx_util.h35
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