diff options
| author | Carl Hetherington <cth@carlh.net> | 2013-07-09 20:35:39 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2013-07-09 20:35:39 +0100 |
| commit | 89115db77729a2c99f1a09ff6a461720e16f889e (patch) | |
| tree | e528ec014b820d4e0efa28893dcee91cd76ee618 /src | |
| parent | f8ad440cf187c517b7800f3efdfc0954025c4422 (diff) | |
| parent | d2ff6a6b0256e256b6df416f280c846072f7682f (diff) | |
Merge master.
Diffstat (limited to 'src')
35 files changed, 597 insertions, 131 deletions
diff --git a/src/lib/combiner.cc b/src/lib/combiner.cc new file mode 100644 index 000000000..f7d634832 --- /dev/null +++ b/src/lib/combiner.cc @@ -0,0 +1,74 @@ +/* + 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 "combiner.h" +#include "image.h" + +using boost::shared_ptr; + +Combiner::Combiner (shared_ptr<Log> log) + : TimedVideoProcessor (log) +{ + +} + +/** Process video for the left half of the frame. + * Subtitle parameter will be ignored. + * @param image Frame image. + */ +void +Combiner::process_video (shared_ptr<const Image> image, bool, shared_ptr<Subtitle>, double) +{ + _image.reset (new SimpleImage (image)); +} + +/** Process video for the right half of the frame. + * @param image Frame image. + * @param sub Subtitle (which will be put onto the whole frame) + */ +void +Combiner::process_video_b (shared_ptr<const Image> image, bool, shared_ptr<Subtitle> sub, double t) +{ + if (!_image) { + /* It's possible for filters in the A-side to mean that we get a B frame + before any A; just skip the B frame in that case. This at least prevents + a crash, but may not be right. + */ + return; + } + + /* Copy the right half of this image into our _image */ + /* XXX: this should probably be in the Image class */ + for (int i = 0; i < image->components(); ++i) { + int const line_size = image->line_size()[i]; + int const half_line_size = line_size / 2; + + uint8_t* p = _image->data()[i]; + uint8_t* q = image->data()[i]; + + for (int j = 0; j < image->lines (i); ++j) { + memcpy (p + half_line_size, q + half_line_size, half_line_size); + p += _image->stride()[i]; + q += image->stride()[i]; + } + } + + Video (_image, false, sub, t); + _image.reset (); +} diff --git a/src/lib/config.cc b/src/lib/config.cc index c9ec730f2..e0fbcc703 100644 --- a/src/lib/config.cc +++ b/src/lib/config.cc @@ -38,6 +38,7 @@ using std::ifstream; using std::string; using std::ofstream; using std::list; +using std::max; using boost::shared_ptr; using boost::lexical_cast; using boost::optional; @@ -46,7 +47,7 @@ Config* Config::_instance = 0; /** Construct default configuration */ Config::Config () - : _num_local_encoding_threads (2) + : _num_local_encoding_threads (max (2U, boost::thread::hardware_concurrency())) , _server_port (6192) , _tms_path (N_(".")) , _sound_processor (SoundProcessor::from_id (N_("dolby_cp750"))) diff --git a/src/lib/cross.cc b/src/lib/cross.cc index ffd44eb02..ee0ef89b2 100644 --- a/src/lib/cross.cc +++ b/src/lib/cross.cc @@ -20,19 +20,27 @@ #include <fstream> #include <boost/algorithm/string.hpp> #include "cross.h" -#ifdef DCPOMATIC_POSIX +#include "compose.hpp" +#include "log.h" +#ifdef DCPOMATIC_LINUX #include <unistd.h> +#include <mntent.h> #endif #ifdef DCPOMATIC_WINDOWS -#include "windows.h" +#include <windows.h> +#undef DATADIR +#include <shlwapi.h> #endif #ifdef DCPOMATIC_OSX #include <sys/sysctl.h> #endif using std::pair; +using std::list; using std::ifstream; using std::string; +using std::make_pair; +using boost::shared_ptr; void dcpomatic_sleep (int s) @@ -81,3 +89,101 @@ cpu_info () return info; } +void +run_ffprobe (boost::filesystem::path content, boost::filesystem::path out, shared_ptr<Log> log) +{ +#ifdef DCPOMATIC_WINDOWS + SECURITY_ATTRIBUTES security; + security.nLength = sizeof (security); + security.bInheritHandle = TRUE; + security.lpSecurityDescriptor = 0; + + HANDLE child_stderr_read; + HANDLE child_stderr_write; + if (!CreatePipe (&child_stderr_read, &child_stderr_write, &security, 0)) { + log->log ("ffprobe call failed (could not CreatePipe)"); + return; + } + + wchar_t dir[512]; + GetModuleFileName (GetModuleHandle (0), dir, sizeof (dir)); + PathRemoveFileSpec (dir); + SetCurrentDirectory (dir); + + STARTUPINFO startup_info; + ZeroMemory (&startup_info, sizeof (startup_info)); + startup_info.cb = sizeof (startup_info); + startup_info.hStdError = child_stderr_write; + startup_info.dwFlags |= STARTF_USESTDHANDLES; + + wchar_t command[512]; + wcscpy (command, L"ffprobe.exe \""); + + wchar_t file[512]; + MultiByteToWideChar (CP_UTF8, 0, content.string().c_str(), -1, file, sizeof(file)); + wcscat (command, file); + + wcscat (command, L"\""); + + PROCESS_INFORMATION process_info; + ZeroMemory (&process_info, sizeof (process_info)); + if (!CreateProcess (0, command, 0, 0, TRUE, CREATE_NO_WINDOW, 0, 0, &startup_info, &process_info)) { + log->log ("ffprobe call failed (could not CreateProcess)"); + return; + } + + FILE* o = fopen (out.string().c_str(), "w"); + if (!o) { + log->log ("ffprobe call failed (could not create output file)"); + return; + } + + CloseHandle (child_stderr_write); + + while (1) { + char buffer[512]; + DWORD read; + if (!ReadFile(child_stderr_read, buffer, sizeof(buffer), &read, 0) || read == 0) { + break; + } + fwrite (buffer, read, 1, o); + } + + fclose (o); + + WaitForSingleObject (process_info.hProcess, INFINITE); + CloseHandle (process_info.hProcess); + CloseHandle (process_info.hThread); + CloseHandle (child_stderr_read); +#else + string ffprobe = "ffprobe \"" + content.string() + "\" 2> \"" + out.string() + "\""; + log->log (String::compose ("Probing with %1", ffprobe)); + system (ffprobe.c_str ()); +#endif +} + +list<pair<string, string> > +mount_info () +{ + list<pair<string, string> > m; + +#ifdef DCPOMATIC_LINUX + FILE* f = setmntent ("/etc/mtab", "r"); + if (!f) { + return m; + } + + while (1) { + struct mntent* mnt = getmntent (f); + if (!mnt) { + break; + } + + m.push_back (make_pair (mnt->mnt_dir, mnt->mnt_type)); + } + + endmntent (f); +#endif + + return m; +} diff --git a/src/lib/cross.h b/src/lib/cross.h index d185286b1..a00fee679 100644 --- a/src/lib/cross.h +++ b/src/lib/cross.h @@ -17,9 +17,15 @@ */ +#include <boost/filesystem.hpp> + #ifdef DCPOMATIC_WINDOWS #define WEXITSTATUS(w) (w) #endif +class Log; + void dcpomatic_sleep (int); extern std::pair<std::string, int> cpu_info (); +extern void run_ffprobe (boost::filesystem::path, boost::filesystem::path, boost::shared_ptr<Log>); +extern std::list<std::pair<std::string, std::string> > mount_info (); diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index c3865d2c1..d3181acd9 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -40,6 +40,7 @@ using std::stringstream; using std::vector; using std::list; using std::cout; +using std::min; using std::make_pair; using boost::shared_ptr; using boost::optional; diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index a3fdaf9b1..bf0949130 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -78,9 +78,6 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> f, shared_ptr<const FFmpegC double FFmpegDecoder::compute_pts_offset (double first_video, double first_audio, float video_frame_rate) { - assert (first_video >= 0); - assert (first_audio >= 0); - double const old_first_video = first_video; /* Round the first video to a frame boundary */ @@ -94,6 +91,8 @@ FFmpegDecoder::compute_pts_offset (double first_video, double first_audio, float FFmpegDecoder::~FFmpegDecoder () { + boost::mutex::scoped_lock lm (_mutex); + if (_subtitle_codec_context) { avcodec_close (_subtitle_codec_context); } @@ -370,17 +369,9 @@ FFmpegDecoder::decode_audio_packet () } } - - int const data_size = av_samples_get_buffer_size ( - 0, audio_codec_context()->channels, _frame->nb_samples, audio_sample_format (), 1 - ); - - assert (audio_codec_context()->channels == _ffmpeg_content->audio_channels()); - audio (deinterleave_audio (_frame->data, data_size), _audio_position); + copy_packet.data += decode_result; + copy_packet.size -= decode_result; } - - copy_packet.data += decode_result; - copy_packet.size -= decode_result; } } } diff --git a/src/lib/film.cc b/src/lib/film.cc index ad565aca0..fa75ab1f1 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -101,6 +101,7 @@ Film::Film (string d) , _dci_metadata (Config::instance()->default_dci_metadata ()) , _dcp_video_frame_rate (24) , _dcp_audio_channels (MAX_AUDIO_CHANNELS) + , _minimum_audio_channels (0) , _dirty (false) { set_dci_date_today (); @@ -127,7 +128,6 @@ Film::Film (string d) } set_directory (result.string ()); - _log.reset (new FileLog (file ("log"))); } Film::Film (Film const & o) @@ -149,6 +149,7 @@ Film::Film (Film const & o) , _dci_metadata (o._dci_metadata) , _dcp_video_frame_rate (o._dcp_video_frame_rate) , _dci_date (o._dci_date) + , _minimum_audio_channels (o._minimum_audio_channels) , _dirty (o._dirty) { _playlist->ContentChanged.connect (bind (&Film::playlist_content_changed, this, _1, _2)); @@ -184,7 +185,6 @@ Film::info_dir () const string Film::internal_video_mxf_dir () const { - boost::filesystem::path p; return dir ("video"); } @@ -268,6 +268,10 @@ Film::make_dcp () #endif pair<string, int> const c = cpu_info (); log()->log (String::compose ("CPU: %1, %2 processors", c.first, c.second)); + list<pair<string, string> > const m = mount_info (); + for (list<pair<string, string> >::const_iterator i = m.begin(); i != m.end(); ++i) { + log()->log (String::compose ("Mount: %1 %2", i->first, i->second)); + } if (container() == 0) { throw MissingSettingError (_("container")); @@ -353,6 +357,7 @@ Film::write_metadata () const root->add_child("DCPVideoFrameRate")->add_child_text (lexical_cast<string> (_dcp_video_frame_rate)); root->add_child("DCIDate")->add_child_text (boost::gregorian::to_iso_string (_dci_date)); root->add_child("DCPAudioChannels")->add_child_text (lexical_cast<string> (_dcp_audio_channels)); + root->add_child("MinimumAudioChannels")->add_child_text (lexical_cast<string> (_minimum_audio_channels)); _playlist->as_xml (root->add_child ("Playlist")); doc.write_to_file_formatted (file ("metadata.xml")); @@ -400,6 +405,7 @@ Film::read_metadata () _dcp_video_frame_rate = f.number_child<int> ("DCPVideoFrameRate"); _dci_date = boost::gregorian::from_undelimited_string (f.string_child ("DCIDate")); _dcp_audio_channels = f.number_child<int> ("DCPAudioChannels"); + _minimum_audio_channels = f.number_child<int> ("MinimumAudioChannels"); _playlist->set_from_xml (shared_from_this(), f.node_child ("Playlist")); @@ -642,6 +648,16 @@ Film::set_dci_metadata (DCIMetadata m) void +Film::set_minimum_audio_channels (int c) +{ + { + boost::mutex::scoped_lock lm (_state_mutex); + _minimum_audio_channels = c; + } + signal_changed (MINIMUM_AUDIO_CHANNELS); +} + +void Film::set_dcp_video_frame_rate (int f) { { diff --git a/src/lib/film.h b/src/lib/film.h index 5bb9acf29..f5a7c1246 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -141,6 +141,7 @@ public: J2K_BANDWIDTH, DCI_METADATA, DCP_VIDEO_FRAME_RATE, + MINIMUM_AUDIO_CHANNELS }; @@ -217,6 +218,11 @@ public: return _dcp_audio_channels; } + int minimum_audio_channels () const { + boost::mutex::scoped_lock lm (_state_mutex); + return _minimum_audio_channels; + } + /* SET */ void set_directory (std::string); @@ -236,6 +242,7 @@ public: void set_dci_metadata (DCIMetadata); void set_dcp_video_frame_rate (int); void set_dci_date_today (); + void set_minimum_audio_channels (int); /** Emitted when some property has of the Film has changed */ mutable boost::signals2::signal<void (Property)> Changed; @@ -298,6 +305,7 @@ private: /** The date that we should use in a DCI name */ boost::gregorian::date _dci_date; int _dcp_audio_channels; + int _minimum_audio_channels; /** true if our state has changed since we last saved it */ mutable bool _dirty; diff --git a/src/lib/ratio.h b/src/lib/ratio.h index 6916a7491..5480eee12 100644 --- a/src/lib/ratio.h +++ b/src/lib/ratio.h @@ -17,6 +17,9 @@ */ +#ifndef DCPOMATIC_RATIO_H +#define DCPOMATIC_RATIO_H + #include <vector> #include <libdcp/util.h> @@ -64,3 +67,5 @@ private: static std::vector<Ratio const *> _ratios; }; + +#endif diff --git a/src/lib/trimmer.cc b/src/lib/trimmer.cc new file mode 100644 index 000000000..99f04793f --- /dev/null +++ b/src/lib/trimmer.cc @@ -0,0 +1,123 @@ +/* + 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 <stdint.h> +#include "trimmer.h" + +using std::cout; +using std::max; +using boost::shared_ptr; + +/** @param audio_sample_rate Audio sampling rate, or 0 if there is no audio */ +Trimmer::Trimmer ( + shared_ptr<Log> log, + int video_trim_start, + int video_trim_end, + int video_length, + int audio_sample_rate, + float frames_per_second, + int dcp_frames_per_second + ) + : AudioVideoProcessor (log) + , _video_start (video_trim_start) + , _video_end (video_length - video_trim_end) + , _video_in (0) + , _audio_in (0) +{ + FrameRateConversion frc (frames_per_second, dcp_frames_per_second); + + if (frc.skip) { + _video_start /= 2; + _video_end /= 2; + } else if (frc.repeat) { + _video_start *= 2; + _video_end *= 2; + } + + if (audio_sample_rate) { + _audio_start = video_frames_to_audio_frames (_video_start, audio_sample_rate, frames_per_second); + _audio_end = video_frames_to_audio_frames (_video_end, audio_sample_rate, frames_per_second); + } + + /* XXX: this is a hack; if there is no trim at the end, set + the audio end point to infinity so that + shorter-video-than-audio does not trim audio (which breaks + the current set of regression tests). This could be + removed if a) the regression tests are regenerated and b) I + can work out what DCP length should be. + + There is also a problem whereby black video frames inserted + at the start of the output by the matcher are not taken into account, + so if black frames are inserted it means more gets trimmed off the + end than should be. Hack around this in similar fashion with the + _video_end = INT_MAX line. + */ + if (video_trim_end == 0) { + _video_end = INT_MAX; + _audio_end = INT64_MAX; + } +} + +void +Trimmer::process_video (shared_ptr<const Image> image, bool same, shared_ptr<Subtitle> sub) +{ + if (_video_in >= _video_start && _video_in < _video_end) { + Video (image, same, sub); + } + + ++_video_in; +} + +void +Trimmer::process_audio (shared_ptr<const AudioBuffers> audio) +{ + int64_t offset = _audio_start - _audio_in; + if (offset > audio->frames()) { + /* we haven't reached the start of the untrimmed section yet */ + _audio_in += audio->frames (); + return; + } + + if (offset < 0) { + offset = 0; + } + + int64_t length = _audio_end - max (_audio_in, _audio_start); + if (length < 0) { + _audio_in += audio->frames (); + return; + } + + if (length > (audio->frames() - offset)) { + length = audio->frames () - offset; + } + + _audio_in += audio->frames (); + + if (offset != 0 || length != audio->frames ()) { + shared_ptr<AudioBuffers> copy (new AudioBuffers (audio)); + copy->move (offset, 0, length); + copy->set_frames (length); + audio = copy; + } + + Audio (audio); +} + diff --git a/src/lib/util.h b/src/lib/util.h index c68bb4f16..7af8ffedf 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -52,6 +52,7 @@ extern "C" { #define MAX_AUDIO_CHANNELS 6 class Scaler; +class Film; extern std::string seconds_to_hms (int); extern std::string time_to_hms (Time); diff --git a/src/lib/version.h b/src/lib/version.h index 518862fc4..b70be8343 100644 --- a/src/lib/version.h +++ b/src/lib/version.h @@ -1,3 +1,4 @@ extern char const * dcpomatic_version; extern char const * dcpomatic_git_commit; +extern char const * dcpomatic_cxx_flags; diff --git a/src/lib/writer.cc b/src/lib/writer.cc index cf81d5b70..cbb84a940 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -18,6 +18,7 @@ */ #include <fstream> +#include <cerrno> #include <libdcp/picture_asset.h> #include <libdcp/sound_asset.h> #include <libdcp/picture_frame.h> @@ -342,8 +343,9 @@ Writer::check_existing_picture_mxf () boost::filesystem::path p; p /= _film->internal_video_mxf_dir (); p /= _film->internal_video_mxf_filename (); - FILE* mxf = fopen (p.string().c_str(), N_("rb")); + FILE* mxf = fopen (p.string().c_str(), "rb"); if (!mxf) { + _film->log()->log (String::compose ("Could not open existing MXF at %1 (errno=%2)", p.string(), errno)); return; } diff --git a/src/lib/wscript b/src/lib/wscript index 3e7f2e33b..2f8653984 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -73,7 +73,7 @@ def build(bld): obj.source = sources + ' version.cc' if bld.env.TARGET_WINDOWS: - obj.uselib += ' WINSOCK2 BFD DBGHELP IBERTY' + obj.uselib += ' WINSOCK2 BFD DBGHELP IBERTY SHLWAPI' obj.source += ' stack.cpp' if bld.env.STATIC: obj.uselib += ' XML++' diff --git a/src/tools/dcpomatic.cc b/src/tools/dcpomatic.cc index 683e60ceb..ac39d4fed 100644 --- a/src/tools/dcpomatic.cc +++ b/src/tools/dcpomatic.cc @@ -163,7 +163,7 @@ setup_menu (wxMenuBar* m) add_item (file, _("&Properties..."), ID_file_properties, NEEDS_FILM); #ifndef __WXOSX__ file->AppendSeparator (); -#endif +#endif add_item (file, _("&Exit"), wxID_EXIT, ALWAYS); #ifdef __WXOSX__ diff --git a/src/tools/dcpomatic_cli.cc b/src/tools/dcpomatic_cli.cc index 8623d9194..ee9e2cdc0 100644 --- a/src/tools/dcpomatic_cli.cc +++ b/src/tools/dcpomatic_cli.cc @@ -47,6 +47,7 @@ help (string n) << " -v, --version show DCP-o-matic version\n" << " -h, --help show this help\n" << " -d, --deps list DCP-o-matic dependency details and quit\n" + << " -f, --flags show flags passed to C++ compiler on build\n" << " -n, --no-progress do not print progress to stdout\n" << " -r, --no-remote do not use any remote servers\n" << "\n" @@ -67,13 +68,14 @@ main (int argc, char* argv[]) { "version", no_argument, 0, 'v'}, { "help", no_argument, 0, 'h'}, { "deps", no_argument, 0, 'd'}, + { "flags", no_argument, 0, 'f'}, { "no-progress", no_argument, 0, 'n'}, { "no-remote", no_argument, 0, 'r'}, { "log-level", required_argument, 0, 'l' }, { 0, 0, 0, 0 } }; - int c = getopt_long (argc, argv, "vhdnrl:", long_options, &option_index); + int c = getopt_long (argc, argv, "vhdfnrl:", long_options, &option_index); if (c == -1) { break; @@ -89,6 +91,9 @@ main (int argc, char* argv[]) case 'd': cout << dependency_version_summary () << "\n"; exit (EXIT_SUCCESS); + case 'f': + cout << dcpomatic_cxx_flags << "\n"; + exit (EXIT_SUCCESS); case 'n': progress = false; break; diff --git a/src/tools/wscript b/src/tools/wscript index 38d986f25..c7ab44604 100644 --- a/src/tools/wscript +++ b/src/tools/wscript @@ -6,7 +6,7 @@ import i18n def build(bld): for t in ['dcpomatic_cli', 'dcpomatic_server_cli']: obj = bld(features = 'cxx cxxprogram') - obj.uselib = 'BOOST_THREAD OPENJPEG DCP CXML AVFORMAT AVFILTER AVCODEC AVUTIL SWSCALE POSTPROC' + obj.uselib = 'BOOST_THREAD OPENJPEG DCP CXML AVFORMAT AVFILTER AVCODEC AVUTIL SWSCALE POSTPROC WXWIDGETS' obj.includes = ['..'] obj.use = ['libdcpomatic'] obj.source = '%s.cc' % t @@ -15,7 +15,9 @@ def build(bld): if not bld.env.DISABLE_GUI: for t in ['dcpomatic', 'dcpomatic_batch', 'dcpomatic_server']: obj = bld(features = 'cxx cxxprogram') - obj.uselib = 'DCP CXML OPENJPEG AVFORMAT AVFILTER AVCODEC AVUTIL SWSCALE POSTPROC' + obj.uselib = 'DCP OPENJPEG AVFORMAT AVFILTER AVCODEC AVUTIL SWSCALE POSTPROC CXML WXWIDGETS' + if bld.env.STATIC: + obj.uselib += ' GTK' obj.includes = ['..'] obj.use = ['libdcpomatic', 'libdcpomatic-wx'] obj.source = '%s.cc' % t diff --git a/src/wx/about_dialog.cc b/src/wx/about_dialog.cc index 0c56cf1be..ca19326a1 100644 --- a/src/wx/about_dialog.cc +++ b/src/wx/about_dialog.cc @@ -138,7 +138,7 @@ AboutDialog::add_section (wxString name, wxArrayString credits) int c = 0; for (size_t i = 0; i < credits.Count(); ++i) { - add_label_to_sizer (sizers[c], panel, credits[i]); + add_label_to_sizer (sizers[c], panel, credits[i], false); ++c; if (c == N) { c = 0; diff --git a/src/wx/audio_dialog.cc b/src/wx/audio_dialog.cc index ea7cc60dd..22e09cc7a 100644 --- a/src/wx/audio_dialog.cc +++ b/src/wx/audio_dialog.cc @@ -97,7 +97,6 @@ AudioDialog::set_content (shared_ptr<AudioContent> c) SetTitle (wxString::Format (_("DCP-o-matic audio - %s"), std_to_wx(_content->file().filename().string()).data())); } - void AudioDialog::try_to_load_analysis () { diff --git a/src/wx/config_dialog.cc b/src/wx/config_dialog.cc index 844b03ad7..e66be174d 100644 --- a/src/wx/config_dialog.cc +++ b/src/wx/config_dialog.cc @@ -78,7 +78,7 @@ ConfigDialog::make_misc_panel () wxBoxSizer* s = new wxBoxSizer (wxVERTICAL); _misc_panel->SetSizer (s); - wxFlexGridSizer* table = new wxFlexGridSizer (3, 6, 6); + wxFlexGridSizer* table = new wxFlexGridSizer (3, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); table->AddGrowableCol (1, 1); s->Add (table, 1, wxALL | wxEXPAND, 8); @@ -93,7 +93,7 @@ ConfigDialog::make_misc_panel () table->Add (_language, 1, wxEXPAND); table->AddSpacer (0); - wxStaticText* restart = add_label_to_sizer (table, _misc_panel, _("(restart DVD-o-matic to see language changes)")); + wxStaticText* restart = add_label_to_sizer (table, _misc_panel, _("(restart DVD-o-matic to see language changes)"), false); wxFont font = restart->GetFont(); font.SetStyle (wxFONTSTYLE_ITALIC); font.SetPointSize (font.GetPointSize() - 1); @@ -101,18 +101,18 @@ ConfigDialog::make_misc_panel () table->AddSpacer (0); table->AddSpacer (0); - add_label_to_sizer (table, _misc_panel, _("Threads to use for encoding on this host")); + 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, wxEXPAND); + table->Add (_num_local_encoding_threads, 1); table->AddSpacer (0); - add_label_to_sizer (table, _misc_panel, _("Default duration of still images")); + add_label_to_sizer (table, _misc_panel, _("Default duration of still images"), true); _default_still_length = new wxSpinCtrl (_misc_panel); table->Add (_default_still_length, 1, wxEXPAND); - add_label_to_sizer (table, _misc_panel, _("s")); + add_label_to_sizer (table, _misc_panel, _("s"), false); - add_label_to_sizer (table, _misc_panel, _("Default directory for new films")); -#ifdef __WXMSW__ + 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 (_misc_panel, wxDD_DIR_MUST_EXIST); @@ -120,17 +120,17 @@ ConfigDialog::make_misc_panel () table->Add (_default_directory, 1, wxEXPAND); table->AddSpacer (0); - add_label_to_sizer (table, _misc_panel, _("Default DCI name details")); + 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->AddSpacer (1); - add_label_to_sizer (table, _misc_panel, _("Default container")); + add_label_to_sizer (table, _misc_panel, _("Default container"), true); _default_container = new wxChoice (_misc_panel, wxID_ANY); table->Add (_default_container); table->AddSpacer (1); - add_label_to_sizer (table, _misc_panel, _("Default content type")); + 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); table->AddSpacer (1); @@ -201,23 +201,23 @@ ConfigDialog::make_tms_panel () wxBoxSizer* s = new wxBoxSizer (wxVERTICAL); _tms_panel->SetSizer (s); - wxFlexGridSizer* table = new wxFlexGridSizer (2, 6, 6); + 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")); + 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")); + 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")); + 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")); + add_label_to_sizer (table, _tms_panel, _("Password"), true); _tms_password = new wxTextCtrl (_tms_panel, wxID_ANY); table->Add (_tms_password, 1, wxEXPAND); @@ -240,15 +240,15 @@ ConfigDialog::make_metadata_panel () wxBoxSizer* s = new wxBoxSizer (wxVERTICAL); _metadata_panel->SetSizer (s); - wxFlexGridSizer* table = new wxFlexGridSizer (2, 6, 6); + 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, _metadata_panel, _("Issuer")); + add_label_to_sizer (table, _metadata_panel, _("Issuer"), true); _issuer = new wxTextCtrl (_metadata_panel, wxID_ANY); table->Add (_issuer, 1, wxEXPAND); - add_label_to_sizer (table, _metadata_panel, _("Creator")); + add_label_to_sizer (table, _metadata_panel, _("Creator"), true); _creator = new wxTextCtrl (_metadata_panel, wxID_ANY); table->Add (_creator, 1, wxEXPAND); @@ -267,7 +267,7 @@ ConfigDialog::make_servers_panel () wxBoxSizer* s = new wxBoxSizer (wxVERTICAL); _servers_panel->SetSizer (s); - wxFlexGridSizer* table = new wxFlexGridSizer (2, 6, 6); + wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); table->AddGrowableCol (0, 1); s->Add (table, 1, wxALL | wxEXPAND, 8); @@ -288,11 +288,11 @@ ConfigDialog::make_servers_panel () { wxSizer* s = new wxBoxSizer (wxVERTICAL); _add_server = new wxButton (_servers_panel, wxID_ANY, _("Add")); - s->Add (_add_server); + s->Add (_add_server, 0, wxTOP | wxBOTTOM, 2); _edit_server = new wxButton (_servers_panel, wxID_ANY, _("Edit")); - s->Add (_edit_server); + s->Add (_edit_server, 0, wxTOP | wxBOTTOM, 2); _remove_server = new wxButton (_servers_panel, wxID_ANY, _("Remove")); - s->Add (_remove_server); + s->Add (_remove_server, 0, wxTOP | wxBOTTOM, 2); table->Add (s, 0); } diff --git a/src/wx/config_dialog.h b/src/wx/config_dialog.h index 3da48fd08..459d64dd7 100644 --- a/src/wx/config_dialog.h +++ b/src/wx/config_dialog.h @@ -25,6 +25,7 @@ #include <wx/spinctrl.h> #include <wx/listctrl.h> #include <wx/filepicker.h> +#include "wx_util.h" class DirPickerCtrl; class wxNotebook; @@ -82,7 +83,7 @@ private: wxTextCtrl* _tms_password; wxSpinCtrl* _num_local_encoding_threads; wxSpinCtrl* _default_still_length; -#ifdef __WXMSW__ +#ifdef DCPOMATIC_USE_OWN_DIR_PICKER DirPickerCtrl* _default_directory; #else wxDirPickerCtrl* _default_directory; diff --git a/src/wx/dci_metadata_dialog.cc b/src/wx/dci_metadata_dialog.cc index c08c58ed4..df3a24f62 100644 --- a/src/wx/dci_metadata_dialog.cc +++ b/src/wx/dci_metadata_dialog.cc @@ -27,34 +27,34 @@ 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, 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, _("Audio Language (e.g. EN)")); + 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)")); + 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)")); + 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)")); + 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)")); + 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)")); + 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)")); + 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); diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index 27803fb9a..2d8c752a1 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -102,39 +102,44 @@ FilmEditor::make_dcp_panel () _dcp_sizer = new wxBoxSizer (wxVERTICAL); _dcp_panel->SetSizer (_dcp_sizer); - wxGridBagSizer* grid = new wxGridBagSizer (4, 4); + wxGridBagSizer* grid = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); _dcp_sizer->Add (grid, 0, wxEXPAND | wxALL, 8); int r = 0; - add_label_to_grid_bag_sizer (grid, _dcp_panel, _("Name"), wxGBPosition (r, 0)); + 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); + grid->Add (_name, wxGBPosition(r, 1), wxDefaultSpan, wxEXPAND | wxLEFT | wxRIGHT); ++r; - add_label_to_grid_bag_sizer (grid, _dcp_panel, _("DCP Name"), wxGBPosition (r, 0)); + 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, wxALIGN_CENTER_VERTICAL); + 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"), wxGBPosition (r, 0)); + 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)); + grid->Add (_container, wxGBPosition (r, 1), wxDefaultSpan, wxEXPAND); ++r; - add_label_to_grid_bag_sizer (grid, _dcp_panel, _("Content Type"), wxGBPosition (r, 0)); + 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; { - add_label_to_grid_bag_sizer (grid, _dcp_panel, _("DCP Frame Rate"), wxGBPosition (r, 0)); + add_label_to_grid_bag_sizer (grid, _dcp_panel, _("DCP Frame Rate"), true, wxGBPosition (r, 0)); wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); _dcp_frame_rate = new wxChoice (_dcp_panel, wxID_ANY); s->Add (_dcp_frame_rate, 1, wxALIGN_CENTER_VERTICAL); @@ -145,18 +150,18 @@ FilmEditor::make_dcp_panel () ++r; { - add_label_to_grid_bag_sizer (grid, _dcp_panel, _("JPEG2000 bandwidth"), wxGBPosition (r, 0)); + add_label_to_grid_bag_sizer (grid, _dcp_panel, _("JPEG2000 bandwidth"), true, wxGBPosition (r, 0)); wxSizer* s = new wxBoxSizer (wxHORIZONTAL); _j2k_bandwidth = new wxSpinCtrl (_dcp_panel, wxID_ANY); s->Add (_j2k_bandwidth, 1); - add_label_to_sizer (s, _dcp_panel, _("MBps")); + add_label_to_sizer (s, _dcp_panel, _("MBps"), false); grid->Add (s, wxGBPosition (r, 1)); } ++r; - add_label_to_grid_bag_sizer (grid, _dcp_panel, _("Scaler"), wxGBPosition (r, 0)); + 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)); + grid->Add (_scaler, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); ++r; vector<Scaler const *> const sc = Scaler::all (); @@ -206,6 +211,8 @@ FilmEditor::connect_to_widgets () _dcp_content_type->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::dcp_content_type_changed), 0, this); _dcp_frame_rate->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::dcp_frame_rate_changed), 0, this); _best_dcp_frame_rate->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::best_dcp_frame_rate_clicked), 0, this); +// _pad_with_silence->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::pad_with_silence_toggled), 0, this); +// _minimum_audio_channels->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::minimum_audio_channels_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); @@ -231,31 +238,31 @@ FilmEditor::make_video_panel () wxBoxSizer* video_sizer = new wxBoxSizer (wxVERTICAL); _video_panel->SetSizer (video_sizer); - wxGridBagSizer* grid = new wxGridBagSizer (4, 4); + wxGridBagSizer* grid = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); video_sizer->Add (grid, 0, wxALL, 8); int r = 0; - add_label_to_grid_bag_sizer (grid, _video_panel, _("Left crop"), wxGBPosition (r, 0)); + add_label_to_grid_bag_sizer (grid, _video_panel, _("Left crop"), true, wxGBPosition (r, 0)); _left_crop = new wxSpinCtrl (_video_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)); grid->Add (_left_crop, wxGBPosition (r, 1)); ++r; - add_label_to_grid_bag_sizer (grid, _video_panel, _("Right crop"), wxGBPosition (r, 0)); + add_label_to_grid_bag_sizer (grid, _video_panel, _("Right crop"), true, wxGBPosition (r, 0)); _right_crop = new wxSpinCtrl (_video_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)); grid->Add (_right_crop, wxGBPosition (r, 1)); ++r; - add_label_to_grid_bag_sizer (grid, _video_panel, _("Top crop"), wxGBPosition (r, 0)); + add_label_to_grid_bag_sizer (grid, _video_panel, _("Top crop"), true, wxGBPosition (r, 0)); _top_crop = new wxSpinCtrl (_video_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)); grid->Add (_top_crop, wxGBPosition (r, 1)); ++r; - add_label_to_grid_bag_sizer (grid, _video_panel, _("Bottom crop"), wxGBPosition (r, 0)); + add_label_to_grid_bag_sizer (grid, _video_panel, _("Bottom crop"), true, wxGBPosition (r, 0)); _bottom_crop = new wxSpinCtrl (_video_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)); grid->Add (_bottom_crop, wxGBPosition (r, 1)); ++r; - add_label_to_grid_bag_sizer (grid, _video_panel, _("Scale to"), wxGBPosition (r, 0)); + add_label_to_grid_bag_sizer (grid, _video_panel, _("Scale to"), true, wxGBPosition (r, 0)); _ratio = new wxChoice (_video_panel, wxID_ANY); grid->Add (_ratio, wxGBPosition (r, 1)); ++r; @@ -270,17 +277,17 @@ FilmEditor::make_video_panel () /* VIDEO-only stuff */ { - add_label_to_grid_bag_sizer (grid, _video_panel, _("Filters"), wxGBPosition (r, 0)); + add_label_to_grid_bag_sizer (grid, _video_panel, _("Filters"), true, wxGBPosition (r, 0)); wxSizer* s = new wxBoxSizer (wxHORIZONTAL); _filters = new wxStaticText (_video_panel, wxID_ANY, _("None")); s->Add (_filters, 1, wxEXPAND | wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM | wxRIGHT, 6); _filters_button = new wxButton (_video_panel, wxID_ANY, _("Edit...")); - s->Add (_filters_button, 0); + 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, _video_panel, _("Colour look-up table"), wxGBPosition (r, 0)); + add_label_to_grid_bag_sizer (grid, _video_panel, _("Colour look-up table"), true, wxGBPosition (r, 0)); _colour_lut = new wxChoice (_video_panel, wxID_ANY); for (int i = 0; i < 2; ++i) { _colour_lut->Append (std_to_wx (colour_lut_index_to_name (i))); @@ -329,7 +336,7 @@ FilmEditor::make_content_panel () h->Add (_loop_content, 0, wxALL, 6); _loop_count = new wxSpinCtrl (_content_panel, wxID_ANY); h->Add (_loop_count, 0, wxALL, 6); - add_label_to_sizer (h, _content_panel, _("times")); + add_label_to_sizer (h, _content_panel, _("times"), false); _content_sizer->Add (h, 0, wxALL, 6); _content_notebook = new wxNotebook (_content_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_LEFT); @@ -354,7 +361,7 @@ FilmEditor::make_audio_panel () wxBoxSizer* audio_sizer = new wxBoxSizer (wxVERTICAL); _audio_panel->SetSizer (audio_sizer); - wxFlexGridSizer* grid = new wxFlexGridSizer (3, 4, 4); + wxFlexGridSizer* grid = new wxFlexGridSizer (3, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); audio_sizer->Add (grid, 0, wxALL, 8); _show_audio = new wxButton (_audio_panel, wxID_ANY, _("Show Audio...")); @@ -362,31 +369,31 @@ FilmEditor::make_audio_panel () grid->AddSpacer (0); grid->AddSpacer (0); - add_label_to_sizer (grid, _audio_panel, _("Audio Gain")); + add_label_to_sizer (grid, _audio_panel, _("Audio Gain"), true); { wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); _audio_gain = new wxSpinCtrl (_audio_panel); s->Add (_audio_gain, 1); - add_label_to_sizer (s, _audio_panel, _("dB")); + add_label_to_sizer (s, _audio_panel, _("dB"), false); grid->Add (s, 1); } _audio_gain_calculate_button = new wxButton (_audio_panel, wxID_ANY, _("Calculate...")); grid->Add (_audio_gain_calculate_button); - add_label_to_sizer (grid, _audio_panel, _("Audio Delay")); + add_label_to_sizer (grid, _audio_panel, _("Audio Delay"), false); { wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); _audio_delay = new wxSpinCtrl (_audio_panel); s->Add (_audio_delay, 1); /// TRANSLATORS: this is an abbreviation for milliseconds, the unit of time - add_label_to_sizer (s, _audio_panel, _("ms")); + add_label_to_sizer (s, _audio_panel, _("ms"), false); grid->Add (s); } grid->AddSpacer (0); - add_label_to_sizer (grid, _audio_panel, _("Audio Stream")); + add_label_to_sizer (grid, _audio_panel, _("Audio Stream"), true); _audio_stream = new wxChoice (_audio_panel, wxID_ANY); grid->Add (_audio_stream, 1); _audio_description = new wxStaticText (_audio_panel, wxID_ANY, wxT ("")); @@ -399,8 +406,32 @@ FilmEditor::make_audio_panel () _audio_mapping = new AudioMappingView (_audio_panel); audio_sizer->Add (_audio_mapping, 1, wxEXPAND | wxALL, 6); +#if 0 + { + _pad_with_silence = new wxCheckBox (_audio_panel, wxID_ANY, _("Pad with silence to")); + grid->Add (_pad_with_silence); + wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); + _minimum_audio_channels = new wxSpinCtrl (_audio_panel); + s->Add (_minimum_audio_channels, 1); + add_label_to_sizer (s, _audio_panel, _("channels"), false); + grid->Add (s); + } + + { + _use_content_audio = new wxRadioButton (_audio_panel, wxID_ANY, _("Use content's audio"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP); + grid->Add (video_control (_use_content_audio)); + wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); + _audio_stream = new wxChoice (_audio_panel, wxID_ANY); + 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); + grid->Add (s); + } +#endif + _audio_gain->SetRange (-60, 60); _audio_delay->SetRange (-1000, 1000); +// _minimum_audio_channels->SetRange (0, MAX_AUDIO_CHANNELS); } void @@ -409,7 +440,7 @@ FilmEditor::make_subtitle_panel () _subtitle_panel = new wxPanel (_content_notebook); wxBoxSizer* subtitle_sizer = new wxBoxSizer (wxVERTICAL); _subtitle_panel->SetSizer (subtitle_sizer); - wxFlexGridSizer* grid = new wxFlexGridSizer (2, 4, 4); + wxFlexGridSizer* grid = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); subtitle_sizer->Add (grid, 0, wxALL, 8); _with_subtitles = new wxCheckBox (_subtitle_panel, wxID_ANY, _("With Subtitles")); @@ -417,24 +448,24 @@ FilmEditor::make_subtitle_panel () grid->AddSpacer (0); { - add_label_to_sizer (grid, _subtitle_panel, _("Subtitle Offset")); + add_label_to_sizer (grid, _subtitle_panel, _("Subtitle Offset"), true); wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); _subtitle_offset = new wxSpinCtrl (_subtitle_panel); s->Add (_subtitle_offset); - add_label_to_sizer (s, _subtitle_panel, _("pixels")); + add_label_to_sizer (s, _subtitle_panel, _("pixels"), false); grid->Add (s); } { - add_label_to_sizer (grid, _subtitle_panel, _("Subtitle Scale")); + add_label_to_sizer (grid, _subtitle_panel, _("Subtitle Scale"), true); wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); _subtitle_scale = new wxSpinCtrl (_subtitle_panel); s->Add (_subtitle_scale); - add_label_to_sizer (s, _subtitle_panel, _("%")); + add_label_to_sizer (s, _subtitle_panel, _("%"), false); grid->Add (s); } - add_label_to_sizer (grid, _subtitle_panel, _("Subtitle Stream")); + add_label_to_sizer (grid, _subtitle_panel, _("Subtitle Stream"), true); _subtitle_stream = new wxChoice (_subtitle_panel, wxID_ANY); grid->Add (_subtitle_stream, 1, wxEXPAND | wxALL, 6); grid->AddSpacer (0); @@ -452,10 +483,10 @@ FilmEditor::make_timing_panel () wxFlexGridSizer* grid = new wxFlexGridSizer (2, 4, 4); timing_sizer->Add (grid, 0, wxALL, 8); - add_label_to_sizer (grid, _timing_panel, _("Start time")); + add_label_to_sizer (grid, _timing_panel, _("Start time"), true); _start = new Timecode (_timing_panel); grid->Add (_start); - add_label_to_sizer (grid, _timing_panel, _("Length")); + add_label_to_sizer (grid, _timing_panel, _("Length"), true); _length = new Timecode (_timing_panel); grid->Add (_length); } @@ -597,6 +628,7 @@ FilmEditor::film_changed (Film::Property p) setup_content (); setup_subtitle_control_sensitivity (); setup_show_audio_sensitivity (); + setup_minimum_audio_channels (); break; case Film::LOOP: checked_set (_loop_content, _film->loop() > 1); @@ -659,6 +691,10 @@ FilmEditor::film_changed (Film::Property p) _best_dcp_frame_rate->Enable (_film->best_dcp_video_frame_rate () != _film->dcp_video_frame_rate ()); break; } + case Film::MINIMUM_AUDIO_CHANNELS: +// checked_set (_minimum_audio_channels, _film->minimum_audio_channels ()); + setup_minimum_audio_channels (); + break; } } @@ -1284,8 +1320,8 @@ XXX } Crop const crop = _film->crop (); - if (crop.left || crop.right || crop.top || crop.bottom) { - libdcp::Size const cropped = _film->cropped_size (_film->video_size ()); + if ((crop.left || crop.right || crop.top || crop.bottom) && _film->size() != libdcp::Size (0, 0)) { + libdcp::Size const cropped = _film->cropped_size (_film->size ()); d << wxString::Format ( _("Cropped to %dx%d (%.2f:1)\n"), cropped.width, cropped.height, @@ -1503,3 +1539,35 @@ FilmEditor::ratio_changed (wxCommandEvent &) vc->set_ratio (ratios[n]); } } + +void +FilmEditor::setup_minimum_audio_channels () +{ +#if 0 + if (!_film || !_film->audio_stream ()) { + _pad_with_silence->SetValue (false); + return; + } + + _pad_with_silence->SetValue (_film->audio_stream()->channels() < _film->minimum_audio_channels()); + + AudioMapping m (_film); + _minimum_audio_channels->SetRange (m.minimum_dcp_channels() + 1, MAX_AUDIO_CHANNELS); +#endif +} + +void +FilmEditor::pad_with_silence_toggled (wxCommandEvent &) +{ + +} + +void +FilmEditor::minimum_audio_channels_changed (wxCommandEvent &) +{ + if (!_film) { + return; + } + +// _film->set_minimum_audio_channels (_minimum_audio_channels->GetValue ()); +} diff --git a/src/wx/film_editor.h b/src/wx/film_editor.h index 4b096a2e1..705eb16af 100644 --- a/src/wx/film_editor.h +++ b/src/wx/film_editor.h @@ -97,6 +97,8 @@ private: void start_changed (); void length_changed (); void ratio_changed (wxCommandEvent &); + void pad_with_silence_toggled (wxCommandEvent &); + void minimum_audio_channels_changed (wxCommandEvent &); /* Handle changes to the model */ void film_changed (Film::Property); @@ -113,6 +115,7 @@ private: void setup_container (); void setup_content_sensitivity (); void setup_loop_sensitivity (); + void setup_minimum_audio_channels (); void active_jobs_changed (bool); boost::shared_ptr<Content> selected_content (); @@ -167,6 +170,8 @@ private: wxChoice* _dcp_content_type; wxChoice* _dcp_frame_rate; wxButton* _best_dcp_frame_rate; + wxCheckBox* _pad_with_silence; + wxSpinCtrl* _minimum_audio_channels; wxChoice* _audio_stream; wxStaticText* _audio_description; wxChoice* _subtitle_stream; diff --git a/src/wx/gain_calculator_dialog.cc b/src/wx/gain_calculator_dialog.cc index 22e6b447a..17ebbb983 100644 --- a/src/wx/gain_calculator_dialog.cc +++ b/src/wx/gain_calculator_dialog.cc @@ -26,14 +26,14 @@ using namespace boost; GainCalculatorDialog::GainCalculatorDialog (wxWindow* parent) : 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); diff --git a/src/wx/imagemagick_content_dialog.cc b/src/wx/imagemagick_content_dialog.cc index dfe4df2e7..6aa756260 100644 --- a/src/wx/imagemagick_content_dialog.cc +++ b/src/wx/imagemagick_content_dialog.cc @@ -33,12 +33,12 @@ ImageMagickContentDialog::ImageMagickContentDialog (wxWindow* parent, shared_ptr grid->AddGrowableCol (1, 1); { - add_label_to_sizer (grid, this, (_("Duration"))); + add_label_to_sizer (grid, this, _("Duration"), true); wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); _video_length = new wxSpinCtrl (this); s->Add (_video_length); /// TRANSLATORS: this is an abbreviation for seconds, the unit of time - add_label_to_sizer (s, this, _("s")); + add_label_to_sizer (s, this, _("s"), false); grid->Add (s); } diff --git a/src/wx/job_manager_view.cc b/src/wx/job_manager_view.cc index 1594dfc91..b5c66bd3e 100644 --- a/src/wx/job_manager_view.cc +++ b/src/wx/job_manager_view.cc @@ -152,7 +152,6 @@ JobManagerView::update () if (!(*i)->finished_cancelled()) { _job_records[*i].gauge->SetValue (100); } - (*i)->Finished (); _job_records[*i].finalised = true; _job_records[*i].cancel->Enable (false); if (!(*i)->error_details().empty ()) { diff --git a/src/wx/new_film_dialog.cc b/src/wx/new_film_dialog.cc index 191482a7c..d4b78d5bf 100644 --- a/src/wx/new_film_dialog.cc +++ b/src/wx/new_film_dialog.cc @@ -21,10 +21,10 @@ #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; @@ -37,17 +37,18 @@ NewFilmDialog::NewFilmDialog (wxWindow* parent) 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); - 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"), true); - add_label_to_sizer (table, this, _("Create in folder")); -#ifdef __WXMSW__ - _folder = new DirPickerCtrl (this); +#ifdef DCPOMATIC_USE_OWN_DIR_PICKER + _folder = new DirPickerCtrl (this); #else _folder = new wxDirPickerCtrl (this, wxDD_DIR_MUST_EXIST); #endif diff --git a/src/wx/new_film_dialog.h b/src/wx/new_film_dialog.h index bfcbd423c..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; @@ -32,10 +33,10 @@ public: private: wxTextCtrl* _name; -#ifdef __WXMSW__ +#ifdef DCPOMATIC_USE_OWN_DIR_PICKER DirPickerCtrl* _folder; -#else +#else wxDirPickerCtrl* _folder; -#endif +#endif static boost::optional<std::string> _directory; }; diff --git a/src/wx/properties_dialog.cc b/src/wx/properties_dialog.cc index 40527ded7..d525fe38b 100644 --- a/src/wx/properties_dialog.cc +++ b/src/wx/properties_dialog.cc @@ -36,17 +36,17 @@ 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")); + 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")); + 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")); + 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); diff --git a/src/wx/server_dialog.cc b/src/wx/server_dialog.cc index 7a9cf95c7..33cb392bf 100644 --- a/src/wx/server_dialog.cc +++ b/src/wx/server_dialog.cc @@ -30,14 +30,14 @@ ServerDialog::ServerDialog (wxWindow* parent, ServerDescription* server) _server = new ServerDescription (wx_to_std (N_("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")); + add_label_to_sizer (table, this, _("Host name or IP address"), true); _host = new wxTextCtrl (this, wxID_ANY); table->Add (_host, 1, wxEXPAND); - add_label_to_sizer (table, this, _("Threads to use")); + add_label_to_sizer (table, this, _("Threads to use"), true); _threads = new wxSpinCtrl (this, wxID_ANY); table->Add (_threads, 1, wxEXPAND); diff --git a/src/wx/timecode.cc b/src/wx/timecode.cc index 9072fb99e..6ce1c1cb8 100644 --- a/src/wx/timecode.cc +++ b/src/wx/timecode.cc @@ -47,15 +47,15 @@ Timecode::Timecode (wxWindow* parent) _hours = new wxTextCtrl (this, wxID_ANY, wxT(""), wxDefaultPosition, size, 0, validator); _hours->SetMaxLength (2); sizer->Add (_hours); - add_label_to_sizer (sizer, this, wxT (":")); + add_label_to_sizer (sizer, this, wxT (":"), false); _minutes = new wxTextCtrl (this, wxID_ANY, wxT(""), wxDefaultPosition, size); _minutes->SetMaxLength (2); sizer->Add (_minutes); - add_label_to_sizer (sizer, this, wxT (":")); + add_label_to_sizer (sizer, this, wxT (":"), false); _seconds = new wxTextCtrl (this, wxID_ANY, wxT(""), wxDefaultPosition, size); _seconds->SetMaxLength (2); sizer->Add (_seconds); - add_label_to_sizer (sizer, this, wxT (".")); + add_label_to_sizer (sizer, this, wxT ("."), false); _frames = new wxTextCtrl (this, wxID_ANY, wxT(""), wxDefaultPosition, size); _frames->SetMaxLength (2); sizer->Add (_frames); diff --git a/src/wx/wscript b/src/wx/wscript index 992f31175..1205fb21b 100644 --- a/src/wx/wscript +++ b/src/wx/wscript @@ -30,7 +30,21 @@ sources = """ """ def configure(conf): - conf.check_cfg(package = '', path = conf.options.wx_config, args = '--cppflags --cxxflags --libs', uselib_store = 'WXWIDGETS', mandatory = True) + conf.check_cfg(msg='Checking for wxWidgets', package='', path=conf.options.wx_config, args='--cppflags --cxxflags --libs', + 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'] + + 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': + conf.fatal('wxwidgets version 2.9.4 is required; %s found' % wx_version) def build(bld): if bld.env.STATIC: @@ -42,6 +56,8 @@ def build(bld): obj.includes = [ '..' ] obj.export_includes = ['.'] obj.uselib = 'WXWIDGETS' + if bld.env.TARGET_LINUX: + obj.uselib += ' GTK' obj.use = 'libdcpomatic' obj.source = sources obj.target = 'dcpomatic-wx' diff --git a/src/wx/wx_util.cc b/src/wx/wx_util.cc index 5691d341a..c5887e17d 100644 --- a/src/wx/wx_util.cc +++ b/src/wx/wx_util.cc @@ -35,21 +35,37 @@ 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, wxString t, int prop) +add_label_to_sizer (wxSizer* s, wxWindow* p, wxString t, bool left, int prop) { + 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, wxALIGN_CENTER_VERTICAL | wxALL, 6); + s->Add (m, prop, flags, 6); return m; } wxStaticText * -add_label_to_grid_bag_sizer (wxGridBagSizer* s, wxWindow* p, wxString t, wxGBPosition pos, wxGBSpan span) +add_label_to_grid_bag_sizer (wxGridBagSizer* s, wxWindow* p, wxString t, bool left, wxGBPosition pos, wxGBSpan span) { + 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, wxALIGN_CENTER_VERTICAL | wxALL, 6); + s->Add (m, pos, span, flags); return m; } diff --git a/src/wx/wx_util.h b/src/wx/wx_util.h index bff11647e..de6a09c35 100644 --- a/src/wx/wx_util.h +++ b/src/wx/wx_util.h @@ -17,23 +17,32 @@ */ +#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 + /** @file src/wx/wx_util.h * @brief Some utility functions and classes. */ extern void error_dialog (wxWindow *, wxString); extern bool confirm_dialog (wxWindow *, wxString); -extern wxStaticText* add_label_to_sizer (wxSizer *, wxWindow *, wxString, int prop = 0); -extern wxStaticText* add_label_to_grid_bag_sizer (wxGridBagSizer *, wxWindow *, wxString, wxGBPosition, wxGBSpan span = wxDefaultSpan); +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 (); @@ -69,3 +78,12 @@ 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 |
