Add Version File dialog.
[dcpomatic.git] / src / wx / dcp_referencing_dialog.cc
1 /*
2     Copyright (C) 2023 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     DCP-o-matic is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21
22 #include "check_box.h"
23 #include "dcp_referencing_dialog.h"
24 #include "static_text.h"
25 #include "wx_util.h"
26 #include "lib/dcp_content.h"
27 #include "lib/film.h"
28 #include "lib/types.h"
29 #include <wx/gbsizer.h>
30 #include <wx/wx.h>
31
32
33 using std::dynamic_pointer_cast;
34 using std::shared_ptr;
35 using std::string;
36 using std::vector;
37 using std::weak_ptr;
38 #if BOOST_VERSION >= 106100
39 using namespace boost::placeholders;
40 #endif
41
42
43 DCPReferencingDialog::DCPReferencingDialog(wxWindow* parent, shared_ptr<const Film> film)
44         : wxDialog(parent, wxID_ANY, _("Version file (VF) setup"))
45         , _film(film)
46         , _dcp_grid(new wxGridBagSizer(DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP))
47         , _overall_sizer(new wxBoxSizer(wxVERTICAL))
48 {
49         _film_connection = film->Change.connect(boost::bind(&DCPReferencingDialog::film_changed, this, _1, _2));
50         _film_content_connection = film->ContentChange.connect(boost::bind(&DCPReferencingDialog::film_content_changed, this, _1, _3));
51
52         _overall_sizer->Add(_dcp_grid, 1, wxALL, DCPOMATIC_DIALOG_BORDER);
53         SetSizer(_overall_sizer);
54
55         auto buttons = CreateSeparatedButtonSizer(wxOK);
56         if (buttons) {
57                 _overall_sizer->Add(buttons, wxSizerFlags().Expand().DoubleBorder());
58         }
59
60         setup();
61 }
62
63
64 void
65 DCPReferencingDialog::film_changed(ChangeType type, FilmProperty property)
66 {
67         if (type != ChangeType::DONE) {
68                 return;
69         }
70
71         if (
72                 property == FilmProperty::INTEROP ||
73                 property == FilmProperty::RESOLUTION ||
74                 property == FilmProperty::CONTAINER ||
75                 property == FilmProperty::REEL_TYPE ||
76                 property == FilmProperty::VIDEO_FRAME_RATE ||
77                 property == FilmProperty::CONTENT) {
78                 setup();
79         }
80 }
81
82
83 void
84 DCPReferencingDialog::film_content_changed(ChangeType type, int property)
85 {
86         if (type != ChangeType::DONE) {
87                 return;
88         }
89
90         if (
91                 property != DCPContentProperty::REFERENCE_VIDEO &&
92                 property != DCPContentProperty::REFERENCE_AUDIO &&
93                 property != DCPContentProperty::REFERENCE_TEXT) {
94                 setup();
95         }
96 }
97
98
99 void
100 DCPReferencingDialog::setup()
101 {
102         _dcps.clear();
103         _dcp_grid->Clear(true);
104
105         int column = 0;
106         for (auto const& heading: { _("DCP"), _("Picture"), _("Sound"), _("Subtitles"), _("Closed captions") }) {
107                 auto text = new StaticText(this, heading);
108                 wxFont font(*wxNORMAL_FONT);
109                 font.SetWeight(wxFONTWEIGHT_BOLD);
110                 text->SetFont(font);
111                 _dcp_grid->Add(text, wxGBPosition(0, column), wxDefaultSpan, wxALL, DCPOMATIC_SIZER_GAP);
112                 ++column;
113         };
114
115         auto const all_parts = { Part::VIDEO, Part::AUDIO, Part::SUBTITLES, Part::CLOSED_CAPTIONS };
116
117         int row = 1;
118         for (auto& content: _film->content()) {
119                 auto dcp_content = dynamic_pointer_cast<DCPContent>(content);
120                 if (!dcp_content) {
121                         continue;
122                 }
123
124                 DCP record;
125                 record.content = dcp_content;
126                 _dcp_grid->Add(new StaticText(this, std_to_wx(dcp_content->name())), wxGBPosition(row, 0));
127                 column = 1;
128                 for (auto const& part: all_parts) {
129                         record.check_box[part] = new CheckBox(this, wxT(""));
130                         switch (part) {
131                         case Part::VIDEO:
132                                 record.check_box[part]->set(dcp_content->reference_video());
133                                 break;
134                         case Part::AUDIO:
135                                 record.check_box[part]->set(dcp_content->reference_audio());
136                                 break;
137                         case Part::SUBTITLES:
138                                 record.check_box[part]->set(dcp_content->reference_text(TextType::OPEN_SUBTITLE));
139                                 break;
140                         case Part::CLOSED_CAPTIONS:
141                                 record.check_box[part]->set(dcp_content->reference_text(TextType::CLOSED_CAPTION));
142                                 break;
143                         default:
144                                 DCPOMATIC_ASSERT(false);
145                         }
146                         record.check_box[part]->bind(&DCPReferencingDialog::checkbox_changed, this, weak_ptr<DCPContent>(dcp_content), record.check_box[part], part);
147                         _dcp_grid->Add(record.check_box[part], wxGBPosition(row, column++), wxDefaultSpan, wxALIGN_CENTER);
148                 }
149                 ++row;
150
151                 auto add_problem = [this, &row](wxString const& cannot, string why_not) {
152                         auto reason = new StaticText(this, cannot + wxT(": ") + std_to_wx(why_not));
153                         wxFont font(*wxNORMAL_FONT);
154                         font.SetStyle(wxFONTSTYLE_ITALIC);
155                         reason->SetFont(font);
156                         _dcp_grid->Add(reason, wxGBPosition(row, 0), wxGBSpan(1, 5), wxLEFT, DCPOMATIC_SIZER_X_GAP * 4);
157                         ++row;
158                 };
159
160                 string why_not;
161
162                 if (!dcp_content->can_reference_anything(_film, why_not)) {
163                         for (auto const& part: all_parts) {
164                                 record.check_box[part]->Enable(false);
165                         }
166                         add_problem(_("Cannot reference this DCP"), why_not);
167                 } else {
168                         if (!dcp_content->can_reference_video(_film, why_not)) {
169                                 record.check_box[Part::VIDEO]->Enable(false);
170                                 if (dcp_content->video) {
171                                         add_problem(_("Cannot reference this DCP's video"), why_not);
172                                 }
173                         }
174
175                         if (!dcp_content->can_reference_audio(_film, why_not)) {
176                                 record.check_box[Part::AUDIO]->Enable(false);
177                                 if (dcp_content->audio) {
178                                         add_problem(_("Cannot reference this DCP's audio"), why_not);
179                                 }
180                         }
181
182                         if (!dcp_content->can_reference_text(_film, TextType::OPEN_SUBTITLE, why_not)) {
183                                 record.check_box[Part::SUBTITLES]->Enable(false);
184                                 if (dcp_content->text_of_original_type(TextType::OPEN_SUBTITLE)) {
185                                         add_problem(_("Cannot reference this DCP's subtitles"), why_not);
186                                 }
187                         }
188
189                         if (!dcp_content->can_reference_text(_film, TextType::CLOSED_CAPTION, why_not)) {
190                                 record.check_box[Part::CLOSED_CAPTIONS]->Enable(false);
191                                 if (dcp_content->text_of_original_type(TextType::CLOSED_CAPTION)) {
192                                         add_problem(_("Cannot reference this DCP's closed captions"), why_not);
193                                 }
194                         }
195                 }
196
197                 _dcps.push_back(record);
198         }
199
200         _dcp_grid->Layout();
201         _overall_sizer->Layout();
202         _overall_sizer->SetSizeHints(this);
203 }
204
205
206 void
207 DCPReferencingDialog::checkbox_changed(weak_ptr<DCPContent> weak_content, CheckBox* check_box, Part part)
208 {
209         auto content = weak_content.lock();
210         if (!content) {
211                 return;
212         }
213
214         switch (part) {
215         case Part::VIDEO:
216                 content->set_reference_video(check_box->get());
217                 break;
218         case Part::AUDIO:
219                 content->set_reference_audio(check_box->get());
220                 break;
221         case Part::SUBTITLES:
222                 content->set_reference_text(TextType::OPEN_SUBTITLE, check_box->get());
223                 break;
224         case Part::CLOSED_CAPTIONS:
225                 content->set_reference_text(TextType::CLOSED_CAPTION, check_box->get());
226                 break;
227         default:
228                 DCPOMATIC_ASSERT(false);
229         }
230 }
231