summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cscript4
-rwxr-xr-xrun/tests2
-rw-r--r--src/lib/create_cli.cc32
-rw-r--r--src/lib/create_cli.h1
-rw-r--r--src/lib/dcp_subtitle_content.cc13
-rw-r--r--src/lib/dcpomatic_socket.cc8
-rw-r--r--src/lib/hints.cc107
-rw-r--r--src/lib/util.cc22
-rw-r--r--src/lib/util.h1
-rw-r--r--src/tools/dcpomatic_verifier.cc2
-rw-r--r--src/wx/controls.cc2
-rw-r--r--src/wx/standard_controls.cc1
-rw-r--r--src/wx/supporters.cc1
-rw-r--r--src/wx/verify_dcp_result_panel.cc8
-rw-r--r--src/wx/wx_util.cc212
-rw-r--r--src/wx/wx_util.h76
-rw-r--r--test/create_cli_test.cc16
m---------test/data0
-rw-r--r--test/hints_test.cc33
-rw-r--r--test/render_subtitles_test.cc7
-rw-r--r--test/test.cc7
-rw-r--r--test/test.h1
-rw-r--r--test/util_test.cc18
23 files changed, 333 insertions, 241 deletions
diff --git a/cscript b/cscript
index 87a090b9d..193db2213 100644
--- a/cscript
+++ b/cscript
@@ -506,7 +506,7 @@ def build_with_cpp17(target):
def dependencies(target, options):
- deps = [('libdcp', 'v1.10.55', {'c++17': build_with_cpp17(target)})]
+ deps = [('libdcp', 'b47f0559041040495a08eb0b5cc2d62068d83952', {'c++17': build_with_cpp17(target)})]
deps.append(('libsub', 'v1.6.59'))
deps.append(('leqm-nrt', 'd75d0af984d9c14bfefca8f1bdbc215c3bf3a388'))
if target.platform != 'linux' or target.distro != 'arch':
@@ -529,7 +529,7 @@ option_defaults = { "gui": True, "variant": None }
def build_tests(target):
# Currently we only build tests on macOS, Windows, some Ubuntu versions and Arch
return (
- (target.platform == 'linux' and target.distro == 'ubuntu' and target.version in ['18.04', '22.04', '24.04', '25.10']) or
+ (target.platform == 'linux' and target.distro == 'ubuntu' and target.version in ['18.04', '22.04', '24.04', '26.04']) or
(target.platform == 'linux' and target.distro == 'arch') or
(target.platform == 'osx') or
(target.platform == 'windows')
diff --git a/run/tests b/run/tests
index 8ae093aaf..40bbdcdf0 100755
--- a/run/tests
+++ b/run/tests
@@ -3,7 +3,7 @@
# e.g. --run_tests=foo
set -e
-PRIVATE_GIT="805027eb2f6d4b1cbacedd77272cf66b1c06ac98"
+PRIVATE_GIT="d64f166137a3f2ee5c950f112e48e52fd982f781"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
source $DIR/environment
diff --git a/src/lib/create_cli.cc b/src/lib/create_cli.cc
index 32834be23..3ef61fe11 100644
--- a/src/lib/create_cli.cc
+++ b/src/lib/create_cli.cc
@@ -85,6 +85,8 @@ help()
" --left-eye next piece of content is for the left eye\n"
" --right-eye next piece of content is for the right eye\n"
" --auto-crop next piece of content should be auto-cropped\n"
+ " --fill-crop next piece of content should be cropped to fit the container\n"
+ " (e.g. to crop the letterboxing from a scope-in-flat image)\n"
" --colourspace next piece of content is in the given colourspace: " + colour_conversions + "\n"
" --colorspace same as --colourspace\n"
" --channel <channel> next piece of content should be mapped to audio channel L, R, C, Lfe, Ls, Rs, BsL, BsR, HI, VI\n"
@@ -184,6 +186,7 @@ CreateCLI::CreateCLI(int argc, char* argv[])
optional<string> next_colour_conversion;
auto next_frame_type = VideoFrameType::TWO_D;
auto next_auto_crop = false;
+ auto next_fill_crop = false;
optional<dcp::Channel> channel;
optional<float> gain;
optional<float> fade_in;
@@ -225,6 +228,9 @@ CreateCLI::CreateCLI(int argc, char* argv[])
} else if (a == "--auto-crop") {
next_auto_crop = true;
claimed = true;
+ } else if (a == "--fill-crop") {
+ next_fill_crop = true;
+ claimed = true;
} else if (a == "--twok") {
_twok = true;
claimed = true;
@@ -331,6 +337,7 @@ CreateCLI::CreateCLI(int argc, char* argv[])
c.path = a;
c.frame_type = next_frame_type;
c.auto_crop = next_auto_crop;
+ c.fill_crop = next_fill_crop;
c.colour_conversion = next_colour_conversion;
c.channel = channel;
c.gain = gain;
@@ -341,6 +348,7 @@ CreateCLI::CreateCLI(int argc, char* argv[])
content.push_back(c);
next_frame_type = VideoFrameType::TWO_D;
next_auto_crop = false;
+ next_fill_crop = false;
next_colour_conversion = {};
channel = {};
gain = {};
@@ -555,6 +563,30 @@ CreateCLI::make_film(function<void (string)> error) const
video->set_crop(crop);
}
+ if (cli_content.fill_crop && video->size()) {
+ auto const source_ratio = video->size()->ratio();
+ Crop crop;
+ if (source_ratio < film->container().ratio()) {
+ /* Part to extract is wider than the source */
+ auto const height = video->size()->width / film->container().ratio();
+ crop.top = crop.bottom = (video->size()->height - height) / 2;
+ } else {
+ /* Container is wider than the source */
+ auto const width = video->size()->height * film->container().ratio();
+ crop.left = crop.right = (video->size()->width - width) / 2;
+ }
+
+ error(fmt::format(
+ "Cropped {} to {} left, {} right, {} top and {} bottom",
+ film_content->path(0).string(),
+ crop.left,
+ crop.right,
+ crop.top,
+ crop.bottom
+ ));
+
+ video->set_crop(crop);
+ }
if (cli_content.colour_conversion) {
video->set_colour_conversion(PresetColourConversion::from_id(*cli_content.colour_conversion).conversion);
}
diff --git a/src/lib/create_cli.h b/src/lib/create_cli.h
index 00abf85e5..cde8598cd 100644
--- a/src/lib/create_cli.h
+++ b/src/lib/create_cli.h
@@ -42,6 +42,7 @@ public:
boost::filesystem::path path;
VideoFrameType frame_type = VideoFrameType::TWO_D;
bool auto_crop = false;
+ bool fill_crop = false;
boost::optional<std::string> colour_conversion;
boost::optional<dcp::Channel> channel;
boost::optional<float> gain;
diff --git a/src/lib/dcp_subtitle_content.cc b/src/lib/dcp_subtitle_content.cc
index b285a78fe..ac8c4245b 100644
--- a/src/lib/dcp_subtitle_content.cc
+++ b/src/lib/dcp_subtitle_content.cc
@@ -38,6 +38,7 @@ using std::list;
using std::make_shared;
using std::shared_ptr;
using std::string;
+using std::vector;
using boost::optional;
using namespace dcpomatic;
@@ -45,7 +46,9 @@ using namespace dcpomatic;
DCPSubtitleContent::DCPSubtitleContent(boost::filesystem::path path)
: Content(path)
{
- text.push_back(make_shared<TextContent>(this, TextType::OPEN_SUBTITLE, TextType::OPEN_SUBTITLE));
+ text = vector<shared_ptr<TextContent>>{make_shared<TextContent>(this, TextType::OPEN_SUBTITLE, TextType::OPEN_SUBTITLE)};
+ /* Default to turning these subtitles on */
+ only_text()->set_use(true);
}
DCPSubtitleContent::DCPSubtitleContent(cxml::ConstNodePtr node, boost::optional<boost::filesystem::path> film_directory, int version)
@@ -63,20 +66,16 @@ DCPSubtitleContent::examine(shared_ptr<const Film> film, shared_ptr<Job> job, bo
auto subtitle_asset = load(path(0));
- auto iop = dynamic_pointer_cast<dcp::InteropTextAsset>(subtitle_asset);
- auto smpte = dynamic_pointer_cast<dcp::SMPTETextAsset>(subtitle_asset);
- if (smpte) {
+ if (auto smpte = dynamic_pointer_cast<dcp::SMPTETextAsset>(subtitle_asset)) {
set_video_frame_rate(film, smpte->edit_rate().numerator);
}
boost::mutex::scoped_lock lm(_mutex);
- /* Default to turning these subtitles on */
- only_text()->set_use(true);
-
_length = ContentTime::from_seconds(subtitle_asset->latest_text_out().as_seconds());
subtitle_asset->fix_empty_font_ids();
+ only_text()->clear_fonts();
add_fonts(only_text(), subtitle_asset);
}
diff --git a/src/lib/dcpomatic_socket.cc b/src/lib/dcpomatic_socket.cc
index d3bfbc309..876fa47d3 100644
--- a/src/lib/dcpomatic_socket.cc
+++ b/src/lib/dcpomatic_socket.cc
@@ -50,7 +50,11 @@ Socket::Socket (int timeout)
void
Socket::check ()
{
+#if BOOST_VERSION >= 108700
if (_deadline.expiry() <= std::chrono::system_clock::now()) {
+#else
+ if (_deadline.expires_at() <= std::chrono::system_clock::now()) {
+#endif
_socket.close();
_deadline.expires_at(std::chrono::time_point<std::chrono::system_clock>::max());
}
@@ -321,7 +325,11 @@ Socket::set_send_buffer_size (int size)
void
Socket::set_deadline_from_now(int seconds)
{
+#if BOOST_VERSION >= 108700
_deadline.expires_after(std::chrono::seconds(seconds));
+#else
+ _deadline.expires_from_now(std::chrono::seconds(seconds));
+#endif
}
void
diff --git a/src/lib/hints.cc b/src/lib/hints.cc
index 35eb640d4..879c8a5dd 100644
--- a/src/lib/hints.cc
+++ b/src/lib/hints.cc
@@ -44,16 +44,19 @@
#include <fmt/format.h>
#include <boost/algorithm/string.hpp>
#include <iostream>
+#include <numeric>
#include "i18n.h"
using std::cout;
using std::make_shared;
+using std::map;
using std::max;
using std::shared_ptr;
using std::string;
using std::weak_ptr;
+using std::vector;
using boost::optional;
using namespace dcpomatic;
#if BOOST_VERSION >= 106100
@@ -367,14 +370,6 @@ Hints::check_loudness()
}
-static
-bool
-subtitle_mxf_too_big(shared_ptr<dcp::TextAsset> asset)
-{
- return asset && asset->file() && dcp::filesystem::file_size(*asset->file()) >= (MAX_TEXT_MXF_SIZE - SIZE_SLACK);
-}
-
-
void
Hints::check_out_of_range_markers()
{
@@ -497,10 +492,6 @@ try
hint(_("At least one of your subtitle lines has more than 79 characters. You should make each line 79 characters at most in length."));
}
- bool ccap_xml_too_big = false;
- bool ccap_mxf_too_big = false;
- bool subs_mxf_too_big = false;
-
auto dcp_dir = film->dir("hints") / dcpomatic::get_process_id();
dcp::filesystem::remove_all(dcp_dir);
@@ -509,31 +500,39 @@ try
dcp::DCP dcp(dcp_dir);
dcp.read();
DCPOMATIC_ASSERT(dcp.cpls().size() == 1);
+ optional<size_t> largest_ccap_xml;
+ optional<size_t> largest_ccap_mxf;
+ optional<size_t> largest_sub_mxf;
for (auto reel: dcp.cpls()[0]->reels()) {
for (auto ccap: reel->closed_captions()) {
- if (ccap->asset() && ccap->asset()->xml_as_string().length() > static_cast<size_t>(MAX_CLOSED_CAPTION_XML_SIZE - SIZE_SLACK) && !ccap_xml_too_big) {
- hint(_(
- "At least one of your closed caption files' XML part is larger than " MAX_CLOSED_CAPTION_XML_SIZE_TEXT
- ". You should divide the DCP into shorter reels."
- ));
- ccap_xml_too_big = true;
- }
- if (subtitle_mxf_too_big(ccap->asset()) && !ccap_mxf_too_big) {
- hint(_(
- "At least one of your closed caption files is larger than " MAX_TEXT_MXF_SIZE_TEXT
- " in total. You should divide the DCP into shorter reels."
- ));
- ccap_mxf_too_big = true;
+ largest_ccap_xml = std::max(ccap->asset()->xml_as_string().length(), largest_ccap_xml.get_value_or(0));
+ if (ccap->asset() && ccap->asset()->file()) {
+ largest_ccap_mxf = std::max(dcp::filesystem::file_size(*ccap->asset()->file()), largest_ccap_mxf.get_value_or(0));
}
}
- if (reel->main_subtitle() && subtitle_mxf_too_big(reel->main_subtitle()->asset()) && !subs_mxf_too_big) {
- hint(_(
- "At least one of your subtitle files is larger than " MAX_TEXT_MXF_SIZE_TEXT " in total. "
- "You should divide the DCP into shorter reels."
- ));
- subs_mxf_too_big = true;
+ if (reel->main_subtitle() && reel->main_subtitle()->asset() && reel->main_subtitle()->asset()->file()) {
+ largest_sub_mxf = std::max(dcp::filesystem::file_size(*reel->main_subtitle()->asset()->file()), largest_sub_mxf.get_value_or(0));
}
}
+
+ if (largest_ccap_xml && *largest_ccap_xml > static_cast<size_t>(MAX_CLOSED_CAPTION_XML_SIZE - SIZE_SLACK)) {
+ hint(fmt::format(_(
+ "At least one of your closed caption files' XML part is larger than " MAX_CLOSED_CAPTION_XML_SIZE_TEXT
+ ". The largest XML part is {}KB. You should divide the DCP into shorter reels."
+ ), *largest_ccap_xml / 1000));
+ }
+ if (largest_ccap_mxf && *largest_ccap_mxf >= (MAX_TEXT_MXF_SIZE - SIZE_SLACK)) {
+ hint(fmt::format(_(
+ "At least one of your closed caption files is larger than " MAX_TEXT_MXF_SIZE_TEXT
+ " in total. The largest file is {}MB. You should divide the DCP into shorter reels."
+ ), *largest_ccap_mxf / 1000000));
+ }
+ if (largest_sub_mxf && *largest_sub_mxf >= (MAX_TEXT_MXF_SIZE - SIZE_SLACK)) {
+ hint(fmt::format(_(
+ "At least one of your subtitle files is larger than " MAX_TEXT_MXF_SIZE_TEXT " in total. "
+ "The largest file is {}MB. You should divide the DCP into shorter reels."
+ ), *largest_sub_mxf / 1000000));
+ }
dcp::filesystem::remove_all(dcp_dir);
emit(boost::bind(boost::ref(Finished)));
@@ -584,24 +583,42 @@ Hints::text(PlayerText text, TextType type, optional<DCPTextTrack> track, DCPTim
void
Hints::closed_caption(PlayerText text, DCPTimePeriod period)
{
- int lines = text.string.size();
- for (auto i: text.string) {
- if (utf8_strlen(i.text()) > MAX_CLOSED_CAPTION_LENGTH) {
- ++lines;
- if (!_long_ccap) {
- _long_ccap = true;
- hint(
- fmt::format(
- "At least one of your closed caption lines has more than {} characters. "
- "It is advisable to make each line {} characters at most in length.",
- MAX_CLOSED_CAPTION_LENGTH,
- MAX_CLOSED_CAPTION_LENGTH)
- );
+ map<float, vector<StringText>> lines;
+ for (auto const& line: text.string) {
+ bool added = false;
+ for (auto& existing: lines) {
+ if (std::abs(existing.first - line.v_position()) < dcp::ALIGN_EPSILON) {
+ existing.second.push_back(line);
+ added = true;
}
}
+ if (!added) {
+ lines[line.v_position()] = { line };
+ }
+ }
+
+ for (auto const& line: lines) {
+ int const length = std::accumulate(
+ line.second.begin(),
+ line.second.end(),
+ 0,
+ [](int acc, StringText const& text) {
+ return acc + dcp::utf8_strlen(text.text());
+ });
+
+ if (length > MAX_CLOSED_CAPTION_LENGTH && !_long_ccap) {
+ _long_ccap = true;
+ hint(
+ fmt::format(
+ "At least one of your closed caption lines has more than {} characters. "
+ "It is advisable to make each line {} characters at most in length.",
+ MAX_CLOSED_CAPTION_LENGTH,
+ MAX_CLOSED_CAPTION_LENGTH)
+ );
+ }
}
- if (!_too_many_ccap_lines && lines > MAX_CLOSED_CAPTION_LINES) {
+ if (!_too_many_ccap_lines && lines.size() > MAX_CLOSED_CAPTION_LINES) {
hint(fmt::format(_("Some of your closed captions span more than {} lines, so they will be truncated."), MAX_CLOSED_CAPTION_LINES));
_too_many_ccap_lines = true;
}
diff --git a/src/lib/util.cc b/src/lib/util.cc
index adc347ab1..60b93a0c4 100644
--- a/src/lib/util.cc
+++ b/src/lib/util.cc
@@ -171,7 +171,7 @@ time_to_hmsf(DCPTime time, Frame rate)
m -= h * 60;
char buffer[64];
- snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d.%02d", h, m, s, static_cast<int>(f));
+ snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d:%02d", h, m, s, static_cast<int>(f));
return buffer;
}
@@ -842,26 +842,6 @@ remap(shared_ptr<const AudioBuffers> input, int output_channels, AudioMapping ma
}
-size_t
-utf8_strlen(string s)
-{
- size_t const len = s.length();
- int N = 0;
- for (size_t i = 0; i < len; ++i) {
- unsigned char c = s[i];
- if ((c & 0xe0) == 0xc0) {
- ++i;
- } else if ((c & 0xf0) == 0xe0) {
- i += 2;
- } else if ((c & 0xf8) == 0xf0) {
- i += 3;
- }
- ++N;
- }
- return N;
-}
-
-
/** @param size Size of picture that the subtitle will be overlaid onto */
void
emit_subtitle_image(ContentTimePeriod period, dcp::TextImage sub, dcp::Size size, shared_ptr<TextDecoder> decoder)
diff --git a/src/lib/util.h b/src/lib/util.h
index aa003ff00..9863e5d94 100644
--- a/src/lib/util.h
+++ b/src/lib/util.h
@@ -84,7 +84,6 @@ extern std::string atmos_asset_filename(std::shared_ptr<dcp::AtmosAsset> asset,
extern std::string careful_string_filter(std::string s, std::wstring allowed = L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_.+");
extern std::pair<int, int> audio_channel_types(std::list<int> mapped, int channels);
extern std::shared_ptr<AudioBuffers> remap(std::shared_ptr<const AudioBuffers> input, int output_channels, AudioMapping map);
-extern size_t utf8_strlen(std::string s);
extern void emit_subtitle_image(dcpomatic::ContentTimePeriod period, dcp::TextImage sub, dcp::Size size, std::shared_ptr<TextDecoder> decoder);
extern void copy_in_bits(boost::filesystem::path from, boost::filesystem::path to, std::function<void (float)>);
extern dcp::Size scale_for_display(dcp::Size s, dcp::Size display_container, dcp::Size film_container, PixelQuanta quanta);
diff --git a/src/tools/dcpomatic_verifier.cc b/src/tools/dcpomatic_verifier.cc
index c2d6cd22c..c881019d8 100644
--- a/src/tools/dcpomatic_verifier.cc
+++ b/src/tools/dcpomatic_verifier.cc
@@ -160,7 +160,7 @@ public:
return dcp_paths;
};
- auto add = [this, &load_dcps](wxWindow* parent) {
+ auto add = [&load_dcps](wxWindow* parent) {
#if wxCHECK_VERSION(3, 1, 4)
DirDialog dialog(parent, _("Select DCP(s)"), wxDD_MULTIPLE, "AddVerifierInputPath");
#else
diff --git a/src/wx/controls.cc b/src/wx/controls.cc
index fce3fd7eb..708cc9a5d 100644
--- a/src/wx/controls.cc
+++ b/src/wx/controls.cc
@@ -279,7 +279,7 @@ Controls::update_position_label()
{
if (!_film) {
checked_set(_frame_number, char_to_wx("0"));
- checked_set(_timecode, char_to_wx("0:0:0.0"));
+ checked_set(_timecode, char_to_wx("0:0:0:0"));
return;
}
diff --git a/src/wx/standard_controls.cc b/src/wx/standard_controls.cc
index 942c49fc4..d9b8c998b 100644
--- a/src/wx/standard_controls.cc
+++ b/src/wx/standard_controls.cc
@@ -38,6 +38,7 @@ StandardControls::StandardControls(wxWindow* parent, FilmViewer& viewer, bool ed
{
_button_sizer->Add (_play_button, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
_play_button->Bind (wxEVT_TOGGLEBUTTON, boost::bind(&StandardControls::play_clicked, this));
+ setup_sensitivity();
}
diff --git a/src/wx/supporters.cc b/src/wx/supporters.cc
index 18951fa4f..dff4f9a7c 100644
--- a/src/wx/supporters.cc
+++ b/src/wx/supporters.cc
@@ -1491,6 +1491,7 @@ supported_by.Add (wxT ("Tilman Vatteroth"));
supported_by.Add (wxT ("Jos Vecht"));
supported_by.Add (wxT ("Christian Vennefrohne"));
supported_by.Add (wxT ("Jaap Verseput"));
+supported_by.Add (wxT ("Dan Viafore"));
supported_by.Add (wxT ("Videoworld"));
supported_by.Add (wxT ("Robert Vidić"));
supported_by.Add (wxT ("Burg Kino Vienna"));
diff --git a/src/wx/verify_dcp_result_panel.cc b/src/wx/verify_dcp_result_panel.cc
index 425a3eb00..aa5da95c6 100644
--- a/src/wx/verify_dcp_result_panel.cc
+++ b/src/wx/verify_dcp_result_panel.cc
@@ -230,6 +230,12 @@ VerifyDCPResultPanel::add(shared_ptr<const VerifyDCPJob> job, bool many)
if (auto const error = note.error()) {
message.Replace(char_to_wx("%error"), std_to_wx(*error));
}
+ if (auto const bit_depth = note.bit_depth()) {
+ message.Replace(char_to_wx("%bit_depth"), std_to_wx(fmt::to_string(*bit_depth)));
+ }
+ if (auto const issue_date = note.issue_date()) {
+ message.Replace(char_to_wx("%issue_date"), std_to_wx(*issue_date));
+ }
if (auto const size_in_pixels = note.size_in_pixels()) {
message.Replace(char_to_wx("%size_in_pixels"), wxString::Format(char_to_wx("%dx%d"), size_in_pixels->width, size_in_pixels->height));
}
@@ -339,7 +345,7 @@ VerifyDCPResultPanel::add(shared_ptr<const VerifyDCPJob> job, bool many)
);
break;
case dcp::VerificationNote::Code::EXTERNAL_ASSET:
- add(i.second, _("This DCP refers to at the asset %asset_id in another DCP (and perhaps others), so it is a \"version file\" (VF)"));
+ add(i.second, _("This DCP refers to the asset %asset_id in another DCP (and perhaps others), so it is a \"version file\" (VF)"));
break;
case dcp::VerificationNote::Code::THREED_ASSET_MARKED_AS_TWOD:
add(i.second, _("The asset %f is 3D but its MXF is marked as 2D."));
diff --git a/src/wx/wx_util.cc b/src/wx/wx_util.cc
index 8d21a3e63..8e86a5408 100644
--- a/src/wx/wx_util.cc
+++ b/src/wx/wx_util.cc
@@ -65,9 +65,9 @@ using namespace dcpomatic;
wxStaticText *
#ifdef __WXOSX__
-create_label (wxWindow* p, wxString t, bool left)
+create_label(wxWindow* p, wxString t, bool left)
#else
-create_label (wxWindow* p, wxString t, bool)
+create_label(wxWindow* p, wxString t, bool)
#endif
{
#ifdef __WXOSX__
@@ -75,14 +75,14 @@ create_label (wxWindow* p, wxString t, bool)
t += char_to_wx(":");
}
#endif
- return new StaticText (p, t);
+ return new StaticText(p, t);
}
#ifdef __WXOSX__
static
void
-setup_osx_flags (wxSizer* s, bool left, int& flags)
+setup_osx_flags(wxSizer* s, bool left, int& flags)
{
if (left) {
auto box = dynamic_cast<wxBoxSizer*>(s);
@@ -103,28 +103,28 @@ setup_osx_flags (wxSizer* s, bool left, int& flags)
* @param prop Proportion to pass when calling Add() on the wxSizer.
*/
wxStaticText *
-add_label_to_sizer (wxSizer* s, wxWindow* p, wxString t, bool left, int prop, int flags)
+add_label_to_sizer(wxSizer* s, wxWindow* p, wxString t, bool left, int prop, int flags)
{
#ifdef __WXOSX__
- setup_osx_flags (s, left, flags);
+ setup_osx_flags(s, left, flags);
#endif
- auto m = create_label (p, t, left);
- s->Add (m, prop, flags, DCPOMATIC_SIZER_GAP);
+ auto m = create_label(p, t, left);
+ s->Add(m, prop, flags, DCPOMATIC_SIZER_GAP);
return m;
}
wxStaticText *
#ifdef __WXOSX__
-add_label_to_sizer (wxSizer* s, wxStaticText* t, bool left, int prop, int flags)
+add_label_to_sizer(wxSizer* s, wxStaticText* t, bool left, int prop, int flags)
#else
-add_label_to_sizer (wxSizer* s, wxStaticText* t, bool, int prop, int flags)
+add_label_to_sizer(wxSizer* s, wxStaticText* t, bool, int prop, int flags)
#endif
{
#ifdef __WXOSX__
- setup_osx_flags (s, left, flags);
+ setup_osx_flags(s, left, flags);
#endif
- s->Add (t, prop, flags, DCPOMATIC_SIZER_GAP);
+ s->Add(t, prop, flags, DCPOMATIC_SIZER_GAP);
return t;
}
@@ -134,9 +134,9 @@ add_label_to_sizer(wxGridBagSizer* s, wxWindow* p, wxString t, bool left, wxGBPo
{
int flags = wxALIGN_CENTER_VERTICAL | wxLEFT;
#ifdef __WXOSX__
- setup_osx_flags (s, left, flags);
+ setup_osx_flags(s, left, flags);
#endif
- auto m = create_label (p, t, left);
+ auto m = create_label(p, t, left);
s->Add(m, pos, span, flags, indent ? DCPOMATIC_SIZER_X_GAP : 0);
return m;
}
@@ -144,16 +144,16 @@ add_label_to_sizer(wxGridBagSizer* s, wxWindow* p, wxString t, bool left, wxGBPo
wxStaticText *
#ifdef __WXOSX__
-add_label_to_sizer (wxGridBagSizer* s, wxStaticText* t, bool left, wxGBPosition pos, wxGBSpan span)
+add_label_to_sizer(wxGridBagSizer* s, wxStaticText* t, bool left, wxGBPosition pos, wxGBSpan span)
#else
-add_label_to_sizer (wxGridBagSizer* s, wxStaticText* t, bool, wxGBPosition pos, wxGBSpan span)
+add_label_to_sizer(wxGridBagSizer* s, wxStaticText* t, bool, wxGBPosition pos, wxGBSpan span)
#endif
{
int flags = wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT;
#ifdef __WXOSX__
- setup_osx_flags (s, left, flags);
+ setup_osx_flags(s, left, flags);
#endif
- s->Add (t, pos, span, flags);
+ s->Add(t, pos, span, flags);
return t;
}
@@ -164,12 +164,12 @@ add_label_to_sizer (wxGridBagSizer* s, wxStaticText* t, bool, wxGBPosition pos,
* @param e Extended message.
*/
void
-error_dialog (wxWindow* parent, wxString m, optional<wxString> e)
+error_dialog(wxWindow* parent, wxString m, optional<wxString> e)
{
wxMessageDialog dialog(parent, m, variant::wx::dcpomatic(), wxOK | wxICON_ERROR);
if (e) {
wxString em = *e;
- em[0] = wxToupper (em[0]);
+ em[0] = wxToupper(em[0]);
dialog.SetExtendedMessage(em);
}
dialog.ShowModal();
@@ -181,7 +181,7 @@ error_dialog (wxWindow* parent, wxString m, optional<wxString> e)
* @param m Message.
*/
void
-message_dialog (wxWindow* parent, wxString m)
+message_dialog(wxWindow* parent, wxString m)
{
wxMessageDialog dialog(parent, m, variant::wx::dcpomatic(), wxOK | wxICON_INFORMATION);
dialog.ShowModal();
@@ -190,7 +190,7 @@ message_dialog (wxWindow* parent, wxString m)
/** @return true if the user answered "yes" */
bool
-confirm_dialog (wxWindow* parent, wxString m)
+confirm_dialog(wxWindow* parent, wxString m)
{
wxMessageDialog dialog(parent, m, variant::wx::dcpomatic(), wxYES_NO | wxICON_QUESTION);
return dialog.ShowModal() == wxID_YES;
@@ -201,9 +201,9 @@ confirm_dialog (wxWindow* parent, wxString m)
* @return Corresponding STL string.
*/
string
-wx_to_std (wxString s)
+wx_to_std(wxString s)
{
- return string (s.ToUTF8());
+ return string(s.ToUTF8());
}
@@ -211,9 +211,9 @@ wx_to_std (wxString s)
* @return Corresponding wxWidgets string.
*/
wxString
-std_to_wx (string s)
+std_to_wx(string s)
{
- return wxString (s.c_str(), wxConvUTF8);
+ return wxString(s.c_str(), wxConvUTF8);
}
@@ -225,14 +225,14 @@ char_to_wx(char const* s)
string
-string_client_data (wxClientData* o)
+string_client_data(wxClientData* o)
{
- return wx_to_std (dynamic_cast<wxStringClientData*>(o)->GetData());
+ return wx_to_std(dynamic_cast<wxStringClientData*>(o)->GetData());
}
void
-checked_set (FilePickerCtrl* widget, boost::filesystem::path value)
+checked_set(FilePickerCtrl* widget, boost::filesystem::path value)
{
if (widget->path() != value) {
if (value.empty()) {
@@ -247,60 +247,60 @@ checked_set (FilePickerCtrl* widget, boost::filesystem::path value)
void
-checked_set (wxDirPickerCtrl* widget, boost::filesystem::path value)
+checked_set(wxDirPickerCtrl* widget, boost::filesystem::path value)
{
- if (widget->GetPath() != std_to_wx (value.string())) {
+ if (widget->GetPath() != std_to_wx(value.string())) {
if (value.empty()) {
/* Hack to make wxWidgets clear the control when we are passed
an empty value.
*/
value = " ";
}
- widget->SetPath (std_to_wx (value.string()));
+ widget->SetPath(std_to_wx(value.string()));
}
}
void
-checked_set (wxSpinCtrl* widget, int value)
+checked_set(wxSpinCtrl* widget, int value)
{
if (widget->GetValue() != value) {
- widget->SetValue (value);
+ widget->SetValue(value);
}
}
void
-checked_set (wxSpinCtrlDouble* widget, double value)
+checked_set(wxSpinCtrlDouble* widget, double value)
{
/* XXX: completely arbitrary epsilon */
- if (fabs (widget->GetValue() - value) > 1e-16) {
- widget->SetValue (value);
+ if (fabs(widget->GetValue() - value) > 1e-16) {
+ widget->SetValue(value);
}
}
void
-checked_set (wxChoice* widget, int value)
+checked_set(wxChoice* widget, int value)
{
if (widget->GetSelection() != value) {
- widget->SetSelection (value);
+ widget->SetSelection(value);
}
}
void
-checked_set (wxChoice* widget, string value)
+checked_set(wxChoice* widget, string value)
{
wxClientData* o = nullptr;
if (widget->GetSelection() != -1) {
- o = widget->GetClientObject (widget->GetSelection ());
+ o = widget->GetClientObject(widget->GetSelection());
}
if (!o || string_client_data(o) != value) {
for (unsigned int i = 0; i < widget->GetCount(); ++i) {
- if (string_client_data (widget->GetClientObject (i)) == value) {
- widget->SetSelection (i);
+ if (string_client_data(widget->GetClientObject(i)) == value) {
+ widget->SetSelection(i);
}
}
}
@@ -308,11 +308,11 @@ checked_set (wxChoice* widget, string value)
void
-checked_set (wxChoice* widget, vector<pair<string, string>> items)
+checked_set(wxChoice* widget, vector<pair<string, string>> items)
{
vector<pair<string, string>> current;
for (unsigned int i = 0; i < widget->GetCount(); ++i) {
- current.push_back (
+ current.push_back(
make_pair(
wx_to_std(widget->GetString(i)),
widget->GetClientData() ? string_client_data(widget->GetClientObject(i)) : ""
@@ -324,24 +324,24 @@ checked_set (wxChoice* widget, vector<pair<string, string>> items)
return;
}
- widget->Clear ();
+ widget->Clear();
for (auto i: items) {
- widget->Append (std_to_wx(i.first), new wxStringClientData(std_to_wx(i.second)));
+ widget->Append(std_to_wx(i.first), new wxStringClientData(std_to_wx(i.second)));
}
}
void
-checked_set (wxTextCtrl* widget, string value)
+checked_set(wxTextCtrl* widget, string value)
{
- if (widget->GetValue() != std_to_wx (value)) {
- widget->ChangeValue (std_to_wx (value));
+ if (widget->GetValue() != std_to_wx(value)) {
+ widget->ChangeValue(std_to_wx(value));
}
}
void
-checked_set (PasswordEntry* entry, string value)
+checked_set(PasswordEntry* entry, string value)
{
if (entry->get() != value) {
entry->set(value);
@@ -350,46 +350,46 @@ checked_set (PasswordEntry* entry, string value)
void
-checked_set (wxTextCtrl* widget, wxString value)
+checked_set(wxTextCtrl* widget, wxString value)
{
if (widget->GetValue() != value) {
- widget->ChangeValue (value);
+ widget->ChangeValue(value);
}
}
void
-checked_set (wxStaticText* widget, string value)
+checked_set(wxStaticText* widget, string value)
{
- if (widget->GetLabel() != std_to_wx (value)) {
- widget->SetLabel (std_to_wx (value));
+ if (widget->GetLabel() != std_to_wx(value)) {
+ widget->SetLabel(std_to_wx(value));
}
}
void
-checked_set (wxStaticText* widget, wxString value)
+checked_set(wxStaticText* widget, wxString value)
{
if (widget->GetLabel() != value) {
- widget->SetLabel (value);
+ widget->SetLabel(value);
}
}
void
-checked_set (wxCheckBox* widget, bool value)
+checked_set(wxCheckBox* widget, bool value)
{
if (widget->GetValue() != value) {
- widget->SetValue (value);
+ widget->SetValue(value);
}
}
void
-checked_set (wxRadioButton* widget, bool value)
+checked_set(wxRadioButton* widget, bool value)
{
if (widget->GetValue() != value) {
- widget->SetValue (value);
+ widget->SetValue(value);
}
}
@@ -422,23 +422,23 @@ checked_set(RegionSubtagWidget* widget, optional<dcp::LanguageTag::RegionSubtag>
int
-wx_get (wxSpinCtrl* w)
+wx_get(wxSpinCtrl* w)
{
- return w->GetValue ();
+ return w->GetValue();
}
int
-wx_get (wxChoice* w)
+wx_get(wxChoice* w)
{
- return w->GetSelection ();
+ return w->GetSelection();
}
double
-wx_get (wxSpinCtrlDouble* w)
+wx_get(wxSpinCtrlDouble* w)
{
- return w->GetValue ();
+ return w->GetValue();
}
@@ -454,7 +454,7 @@ context_translation(char const* s)
/* No translation; strip the context */
int c = t.Find(char_to_wx("|"));
if (c != wxNOT_FOUND) {
- t = t.Mid (c + 1);
+ t = t.Mid(c + 1);
}
}
@@ -463,46 +463,46 @@ context_translation(char const* s)
wxString
-time_to_timecode (DCPTime t, double fps)
+time_to_timecode(DCPTime t, double fps)
{
- auto w = t.seconds ();
+ auto w = t.seconds();
int const h = (w / 3600);
w -= h * 3600;
int const m = (w / 60);
w -= m * 60;
- int const s = floor (w);
+ int const s = floor(w);
w -= s;
- int const f = lrint (w * fps);
- return wxString::Format(char_to_wx("%02d:%02d:%02d.%02d"), h, m, s, f);
+ int const f = lrint(w * fps);
+ return wxString::Format(char_to_wx("%02d:%02d:%02d:%02d"), h, m, s, f);
}
void
-setup_audio_channels_choice (wxChoice* choice, int minimum)
+setup_audio_channels_choice(wxChoice* choice, int minimum)
{
vector<pair<string, string>> items;
for (int i = minimum; i <= 16; i += 2) {
if (i == 2) {
- items.push_back (make_pair(wx_to_std(_("2 - stereo")), locale_convert<string>(i)));
+ items.push_back(make_pair(wx_to_std(_("2 - stereo")), locale_convert<string>(i)));
} else if (i == 4) {
- items.push_back (make_pair(wx_to_std(_("4 - L/C/R/Lfe")), locale_convert<string>(i)));
+ items.push_back(make_pair(wx_to_std(_("4 - L/C/R/Lfe")), locale_convert<string>(i)));
} else if (i == 6) {
- items.push_back (make_pair(wx_to_std(_("6 - 5.1")), locale_convert<string>(i)));
+ items.push_back(make_pair(wx_to_std(_("6 - 5.1")), locale_convert<string>(i)));
} else if (i == 8) {
- items.push_back (make_pair(wx_to_std(_("8 - 5.1/HI/VI")), locale_convert<string>(i)));
+ items.push_back(make_pair(wx_to_std(_("8 - 5.1/HI/VI")), locale_convert<string>(i)));
} else if (i == 12) {
- items.push_back (make_pair(wx_to_std(_("12 - 7.1/HI/VI")), locale_convert<string>(i)));
+ items.push_back(make_pair(wx_to_std(_("12 - 7.1/HI/VI")), locale_convert<string>(i)));
} else {
- items.push_back (make_pair(locale_convert<string> (i), locale_convert<string>(i)));
+ items.push_back(make_pair(locale_convert<string>(i), locale_convert<string>(i)));
}
}
- checked_set (choice, items);
+ checked_set(choice, items);
}
wxSplashScreen*
-maybe_show_splash ()
+maybe_show_splash()
{
wxSplashScreen* splash = nullptr;
@@ -523,7 +523,7 @@ maybe_show_splash ()
#else
splash = new wxSplashScreen(bitmap, wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_NO_TIMEOUT, 0, nullptr, -1);
#endif
- wxYield ();
+ wxYield();
}
} catch (boost::filesystem::filesystem_error& e) {
/* Maybe we couldn't find the splash image; never mind */
@@ -534,19 +534,19 @@ maybe_show_splash ()
double
-calculate_mark_interval (double mark_interval)
+calculate_mark_interval(double mark_interval)
{
if (mark_interval > 5) {
- mark_interval -= lrint (mark_interval) % 5;
+ mark_interval -= lrint(mark_interval) % 5;
}
if (mark_interval > 10) {
- mark_interval -= lrint (mark_interval) % 10;
+ mark_interval -= lrint(mark_interval) % 10;
}
if (mark_interval > 60) {
- mark_interval -= lrint (mark_interval) % 60;
+ mark_interval -= lrint(mark_interval) % 60;
}
if (mark_interval > 3600) {
- mark_interval -= lrint (mark_interval) % 3600;
+ mark_interval -= lrint(mark_interval) % 3600;
}
if (mark_interval < 1) {
@@ -559,16 +559,16 @@ calculate_mark_interval (double mark_interval)
/** @return false if the task was cancelled */
bool
-display_progress (wxString title, wxString task)
+display_progress(wxString title, wxString task)
{
- auto jm = JobManager::instance ();
+ auto jm = JobManager::instance();
- wxProgressDialog progress (title, task, 100, 0, wxPD_CAN_ABORT);
+ wxProgressDialog progress(title, task, 100, 0, wxPD_CAN_ABORT);
bool ok = true;
while (jm->work_to_do()) {
- dcpomatic_sleep_seconds (1);
+ dcpomatic_sleep_seconds(1);
if (!progress.Pulse()) {
/* user pressed cancel */
for (auto i: jm->get()) {
@@ -584,7 +584,7 @@ display_progress (wxString title, wxString task)
int
-get_offsets (vector<Offset>& offsets)
+get_offsets(vector<Offset>& offsets)
{
offsets.push_back({_("UTC-11"), dcp::UTCOffset(-11, 0)});
offsets.push_back({_("UTC-10"), dcp::UTCOffset(-10, 0)});
@@ -623,13 +623,13 @@ get_offsets (vector<Offset>& offsets)
wxString
-bitmap_path (string name)
+bitmap_path(string name)
{
boost::filesystem::path base;
#ifdef DCPOMATIC_DEBUG
/* Hack to allow Linux and OS X to find icons when running from the source tree */
- char* path = getenv ("DCPOMATIC_GRAPHICS");
+ char* path = getenv("DCPOMATIC_GRAPHICS");
if (path) {
base = path;
} else {
@@ -644,7 +644,7 @@ bitmap_path (string name)
#endif
auto p = base / name;
- return std_to_wx (p.string());
+ return std_to_wx(p.string());
}
@@ -656,18 +656,18 @@ icon_path(string name)
wxSize
-small_button_size (wxWindow* parent, wxString text)
+small_button_size(wxWindow* parent, wxString text)
{
- wxClientDC dc (parent);
- auto size = dc.GetTextExtent (text);
- size.SetHeight (-1);
- size.IncBy (32, 0);
+ wxClientDC dc(parent);
+ auto size = dc.GetTextExtent(text);
+ size.SetHeight(-1);
+ size.IncBy(32, 0);
return size;
}
bool
-gui_is_dark ()
+gui_is_dark()
{
#ifdef DCPOMATIC_WINDOWS
/* Dark mode doesn't really work at all on Windows at the moment, so just don't use it */
@@ -684,13 +684,13 @@ gui_is_dark ()
#if wxCHECK_VERSION(3,1,0)
double
-dpi_scale_factor (wxWindow* window)
+dpi_scale_factor(wxWindow* window)
{
return window->GetDPIScaleFactor();
}
#else
double
-dpi_scale_factor (wxWindow*)
+dpi_scale_factor(wxWindow*)
{
return 1;
}
@@ -699,7 +699,7 @@ dpi_scale_factor (wxWindow*)
int
-search_ctrl_height ()
+search_ctrl_height()
{
#ifdef __WXGTK3__
return 30;
diff --git a/src/wx/wx_util.h b/src/wx/wx_util.h
index 6f84705fb..957957589 100644
--- a/src/wx/wx_util.h
+++ b/src/wx/wx_util.h
@@ -94,34 +94,34 @@ class PasswordEntry;
#define S_(x) context_translation(x)
-extern void error_dialog (wxWindow *, wxString, boost::optional<wxString> e = boost::optional<wxString>());
-extern void message_dialog (wxWindow *, wxString);
-extern bool confirm_dialog (wxWindow *, wxString);
-extern wxStaticText* create_label (wxWindow* p, wxString t, bool left);
-extern wxStaticText* add_label_to_sizer (wxSizer *, wxWindow *, wxString, bool left, int prop = 0, int flags = wxLEFT | wxRIGHT);
-extern wxStaticText* add_label_to_sizer (wxSizer *, wxStaticText *, bool left, int prop = 0, int flags = wxLEFT | wxRIGHT);
+extern void error_dialog(wxWindow *, wxString, boost::optional<wxString> e = boost::optional<wxString>());
+extern void message_dialog(wxWindow *, wxString);
+extern bool confirm_dialog(wxWindow *, wxString);
+extern wxStaticText* create_label(wxWindow* p, wxString t, bool left);
+extern wxStaticText* add_label_to_sizer(wxSizer *, wxWindow *, wxString, bool left, int prop = 0, int flags = wxLEFT | wxRIGHT);
+extern wxStaticText* add_label_to_sizer(wxSizer *, wxStaticText *, bool left, int prop = 0, int flags = wxLEFT | wxRIGHT);
extern wxStaticText* add_label_to_sizer(wxGridBagSizer *, wxWindow *, wxString, bool, wxGBPosition, wxGBSpan span = wxDefaultSpan, bool indent = false);
-extern wxStaticText* add_label_to_sizer (wxGridBagSizer *, wxStaticText *, bool, wxGBPosition, wxGBSpan span = wxDefaultSpan);
-extern std::string wx_to_std (wxString);
-extern wxString std_to_wx (std::string);
+extern wxStaticText* add_label_to_sizer(wxGridBagSizer *, wxStaticText *, bool, wxGBPosition, wxGBSpan span = wxDefaultSpan);
+extern std::string wx_to_std(wxString);
+extern wxString std_to_wx(std::string);
/** Convert UTF8-encoded char array to wxString */
extern wxString char_to_wx(char const* s);
extern wxString context_translation(char const* s);
-extern std::string string_client_data (wxClientData* o);
-extern wxString time_to_timecode (dcpomatic::DCPTime t, double fps);
-extern void setup_audio_channels_choice (wxChoice* choice, int minimum);
+extern std::string string_client_data(wxClientData* o);
+extern wxString time_to_timecode(dcpomatic::DCPTime t, double fps);
+extern void setup_audio_channels_choice(wxChoice* choice, int minimum);
extern wxSplashScreen* maybe_show_splash();
-extern double calculate_mark_interval (double start);
-extern bool display_progress (wxString title, wxString task);
-extern bool report_errors_from_last_job (wxWindow* parent);
-extern wxString bitmap_path (std::string name);
+extern double calculate_mark_interval(double start);
+extern bool display_progress(wxString title, wxString task);
+extern bool report_errors_from_last_job(wxWindow* parent);
+extern wxString bitmap_path(std::string name);
extern wxString icon_path(std::string name);
-extern wxSize small_button_size (wxWindow* parent, wxString text);
-extern bool gui_is_dark ();
-extern double dpi_scale_factor (wxWindow* window);
-extern int search_ctrl_height ();
+extern wxSize small_button_size(wxWindow* parent, wxString text);
+extern bool gui_is_dark();
+extern double dpi_scale_factor(wxWindow* window);
+extern int search_ctrl_height();
extern void report_config_load_failure(wxWindow* parent, Config::LoadFailure what);
extern bool layout_for_short_screen(wxWindow* reference);
@@ -137,7 +137,7 @@ struct Offset
dcp::UTCOffset offset;
};
-extern int get_offsets (std::vector<Offset>& offsets);
+extern int get_offsets(std::vector<Offset>& offsets);
namespace dcpomatic {
namespace wx {
@@ -149,27 +149,27 @@ namespace wx {
}
-extern void checked_set (FilePickerCtrl* widget, boost::filesystem::path value);
-extern void checked_set (wxDirPickerCtrl* widget, boost::filesystem::path value);
-extern void checked_set (wxSpinCtrl* widget, int value);
-extern void checked_set (wxSpinCtrlDouble* widget, double value);
-extern void checked_set (wxChoice* widget, int value);
-extern void checked_set (wxChoice* widget, std::string value);
-extern void checked_set (wxChoice* widget, std::vector<std::pair<std::string, std::string> > items);
-extern void checked_set (wxTextCtrl* widget, std::string value);
-extern void checked_set (wxTextCtrl* widget, wxString value);
-extern void checked_set (PasswordEntry* 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);
-extern void checked_set (wxStaticText* widget, wxString value);
+extern void checked_set(FilePickerCtrl* widget, boost::filesystem::path value);
+extern void checked_set(wxDirPickerCtrl* widget, boost::filesystem::path value);
+extern void checked_set(wxSpinCtrl* widget, int value);
+extern void checked_set(wxSpinCtrlDouble* widget, double value);
+extern void checked_set(wxChoice* widget, int value);
+extern void checked_set(wxChoice* widget, std::string value);
+extern void checked_set(wxChoice* widget, std::vector<std::pair<std::string, std::string> > items);
+extern void checked_set(wxTextCtrl* widget, std::string value);
+extern void checked_set(wxTextCtrl* widget, wxString value);
+extern void checked_set(PasswordEntry* 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);
+extern void checked_set(wxStaticText* widget, wxString value);
extern void checked_set(LanguageTagWidget* widget, dcp::LanguageTag value);
extern void checked_set(LanguageTagWidget* widget, boost::optional<dcp::LanguageTag> value);
extern void checked_set(RegionSubtagWidget* widget, boost::optional<dcp::LanguageTag::RegionSubtag> value);
-extern int wx_get (wxChoice* widget);
-extern int wx_get (wxSpinCtrl* widget);
-extern double wx_get (wxSpinCtrlDouble* widget);
+extern int wx_get(wxChoice* widget);
+extern int wx_get(wxSpinCtrl* widget);
+extern double wx_get(wxSpinCtrlDouble* widget);
#ifdef DCPOMATIC_WINDOWS
#define DCPOMATIC_USE_OWN_PICKER
diff --git a/test/create_cli_test.cc b/test/create_cli_test.cc
index c71031fbc..0f127c018 100644
--- a/test/create_cli_test.cc
+++ b/test/create_cli_test.cc
@@ -322,6 +322,22 @@ BOOST_AUTO_TEST_CASE (create_cli_test)
BOOST_CHECK(film->content()[0]->video->fade_in() == 24);
BOOST_CHECK(film->content()[0]->video->fade_out() == 0);
BOOST_CHECK(collected_error.empty());
+
+ /* Extract a 1.85 frame from a 320x240 source */
+ cc = run("dcpomatic2_create --container-ratio 185 --fill-crop test/data/red_24.mp4");
+ BOOST_CHECK(!cc.error);
+ film = cc.make_film(error);
+ BOOST_REQUIRE_EQUAL(film->content().size(), 1U);
+ BOOST_REQUIRE(film->content()[0]->video);
+ BOOST_CHECK(film->content()[0]->video->requested_crop() == Crop(0, 0, 33, 33));
+
+ /* Extract a 1.85 frame from a 2048x858 source */
+ cc = run("dcpomatic2_create --container-ratio 185 --fill-crop test/data/scope_dcp");
+ BOOST_CHECK(!cc.error);
+ film = cc.make_film(error);
+ BOOST_REQUIRE_EQUAL(film->content().size(), 1U);
+ BOOST_REQUIRE(film->content()[0]->video);
+ BOOST_CHECK(film->content()[0]->video->requested_crop() == Crop(230, 230, 0, 0));
}
diff --git a/test/data b/test/data
-Subproject fe6973d73602cff710f5ea2396a47074b21686d
+Subproject cec02cb60028b76800357604f8331b903388d77
diff --git a/test/hints_test.cc b/test/hints_test.cc
index 073415018..7cb9d676b 100644
--- a/test/hints_test.cc
+++ b/test/hints_test.cc
@@ -211,7 +211,7 @@ BOOST_AUTO_TEST_CASE (hint_subtitle_mxf_too_big)
BOOST_CHECK_EQUAL (
hints[0],
"At least one of your subtitle files is larger than " MAX_TEXT_MXF_SIZE_TEXT " in total. "
- "You should divide the DCP into shorter reels."
+ "The largest file is 134MB. You should divide the DCP into shorter reels."
);
}
@@ -245,7 +245,7 @@ BOOST_AUTO_TEST_CASE (hint_closed_caption_xml_too_big)
BOOST_CHECK_EQUAL (
hints[0],
"At least one of your closed caption files' XML part is larger than " MAX_CLOSED_CAPTION_XML_SIZE_TEXT ". "
- "You should divide the DCP into shorter reels."
+ "The largest XML part is 482KB. You should divide the DCP into shorter reels."
);
}
@@ -326,3 +326,32 @@ BOOST_AUTO_TEST_CASE(hints_120fps)
BOOST_CHECK(hint.find("There is a large difference between the frame rate of your DCP and that of some of your content.") == std::string::npos);
}
}
+
+
+BOOST_AUTO_TEST_CASE(hints_ccap_not_too_many_lines_xml)
+{
+ auto content = content_factory(TestPaths::private_data() / "ccap_not_too_many_lines.xml")[0];
+ auto film = new_test_film("hints_ccap_not_too_many_lines", { content });
+ content->text[0]->set_type(TextType::CLOSED_CAPTION);
+ auto hints = get_hints(film);
+
+ BOOST_CHECK(
+ std::none_of(hints.begin(), hints.end(), [](string const& hint) {
+ return hint.find("Some of your closed captions span more than 3 lines") != std::string::npos;
+ })
+ );
+}
+
+
+BOOST_AUTO_TEST_CASE(hints_ccap_too_many_lines_xml)
+{
+ auto content = content_factory(TestPaths::private_data() / "ccap_too_many_lines.xml")[0];
+ auto film = new_test_film("hints_ccap_too_many_lines", { content });
+ content->text[0]->set_type(TextType::CLOSED_CAPTION);
+ auto hints = get_hints(film);
+ BOOST_CHECK(
+ std::any_of(hints.begin(), hints.end(), [](string const& hint) {
+ return hint.find("Some of your closed captions span more than 3 lines") != std::string::npos;
+ })
+ );
+}
diff --git a/test/render_subtitles_test.cc b/test/render_subtitles_test.cc
index 4e87abde0..4fc98cb56 100644
--- a/test/render_subtitles_test.cc
+++ b/test/render_subtitles_test.cc
@@ -176,8 +176,11 @@ BOOST_AUTO_TEST_CASE(render_text_with_newline_test)
#elif defined(DCPOMATIC_WINDOWS)
check_image("test/data/windows/render_text_with_newline_test.png", "build/test/render_text_with_newline_test.png");
#elif PANGO_VERSION_CHECK(1, 57, 0)
- /* This pango version is the one on Arch, which renders slightly differently */
- check_image("test/data/arch/render_text_with_newline_test.png", "build/test/render_text_with_newline_test.png");
+ /* This pango version is the one on Arch and Ubuntu 26.04, both of which render slightly differently */
+ BOOST_REQUIRE(
+ check_image_and_report("test/data/arch/render_text_with_newline_test.png", "build/test/render_text_with_newline_test.png")
+ || check_image_and_report("test/data/ubuntu-26.04/render_text_with_newline_test.png", "build/test/render_text_with_newline_test.png")
+ );
#elif PANGO_VERSION_CHECK(1, 52, 1)
/* This pango version is the one on Ubuntu 24.04, which renders slightly differently */
check_image("test/data/ubuntu-24.04/render_text_with_newline_test.png", "build/test/render_text_with_newline_test.png");
diff --git a/test/test.cc b/test/test.cc
index 641ee4085..27b00b9d3 100644
--- a/test/test.cc
+++ b/test/test.cc
@@ -473,6 +473,13 @@ check_image (boost::filesystem::path ref, boost::filesystem::path check, double
}
+bool
+check_image_and_report(boost::filesystem::path ref, boost::filesystem::path check, double threshold)
+{
+ return rms_error(ref, check) < threshold;
+}
+
+
void
check_file (boost::filesystem::path ref, boost::filesystem::path check)
{
diff --git a/test/test.h b/test/test.h
index 172edcf71..cd40c7872 100644
--- a/test/test.h
+++ b/test/test.h
@@ -69,6 +69,7 @@ extern bool mxf_atmos_files_same (boost::filesystem::path ref, boost::filesystem
extern void check_xml(boost::filesystem::path, boost::filesystem::path, std::list<Glib::ustring>);
extern void check_ffmpeg(boost::filesystem::path, boost::filesystem::path, float audio_tolerance);
extern void check_image(boost::filesystem::path ref, boost::filesystem::path check, double threshold = 4);
+extern bool check_image_and_report(boost::filesystem::path ref, boost::filesystem::path check, double threshold = 4);
extern boost::filesystem::path test_film_dir (std::string);
extern void write_image (std::shared_ptr<const Image> image, boost::filesystem::path file);
boost::filesystem::path dcp_file (std::shared_ptr<const Film> film, std::string prefix);
diff --git a/test/util_test.cc b/test/util_test.cc
index defc7f907..ee26cc18c 100644
--- a/test/util_test.cc
+++ b/test/util_test.cc
@@ -93,11 +93,11 @@ BOOST_AUTO_TEST_CASE(seconds_to_approximate_hms_test)
BOOST_AUTO_TEST_CASE(time_to_hmsf_test)
{
- BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_frames(12, 24), 24), "00:00:00.12");
- BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_frames(24, 24), 24), "00:00:01.00");
- BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_frames(32, 24), 24), "00:00:01.08");
- BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_seconds(92), 24), "00:01:32.00");
- BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_seconds(2 * 60 * 60 + 92), 24), "02:01:32.00");
+ BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_frames(12, 24), 24), "00:00:00:12");
+ BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_frames(24, 24), 24), "00:00:01:00");
+ BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_frames(32, 24), 24), "00:00:01:08");
+ BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_seconds(92), 24), "00:01:32:00");
+ BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_seconds(2 * 60 * 60 + 92), 24), "02:01:32:00");
}
@@ -110,14 +110,6 @@ BOOST_AUTO_TEST_CASE(tidy_for_filename_test)
}
-BOOST_AUTO_TEST_CASE(utf8_strlen_test)
-{
- BOOST_CHECK_EQUAL(utf8_strlen("hello world"), 11U);
- BOOST_CHECK_EQUAL(utf8_strlen("hëllo world"), 11U);
- BOOST_CHECK_EQUAL(utf8_strlen("hëłlo wørld"), 11U);
-}
-
-
BOOST_AUTO_TEST_CASE(careful_string_filter_test)
{
BOOST_CHECK_EQUAL("hello_world", careful_string_filter("hello_world"));