More include fixes.
[dcpomatic.git] / src / wx / timing_panel.cc
1 /*
2     Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include "lib/content.h"
21 #include "lib/image_content.h"
22 #include "timing_panel.h"
23 #include "wx_util.h"
24 #include "timecode.h"
25 #include "content_panel.h"
26 #include <dcp/raw_convert.h>
27 #include <set>
28
29 using std::cout;
30 using std::string;
31 using std::set;
32 using boost::shared_ptr;
33 using boost::dynamic_pointer_cast;
34 using dcp::raw_convert;
35
36 TimingPanel::TimingPanel (ContentPanel* p)
37         /* horrid hack for apparent lack of context support with wxWidgets i18n code */
38         : ContentSubPanel (p, S_("Timing|Timing"))
39 {
40         wxFlexGridSizer* grid = new wxFlexGridSizer (2, 4, 4);
41         _sizer->Add (grid, 0, wxALL, 8);
42
43         add_label_to_sizer (grid, this, _("Position"), true);
44         _position = new Timecode<DCPTime> (this);
45         grid->Add (_position);
46         add_label_to_sizer (grid, this, _("Full length"), true);
47         _full_length = new Timecode<DCPTime> (this);
48         grid->Add (_full_length);
49         add_label_to_sizer (grid, this, _("Trim from start"), true);
50         _trim_start = new Timecode<DCPTime> (this);
51         grid->Add (_trim_start);
52         add_label_to_sizer (grid, this, _("Trim from end"), true);
53         _trim_end = new Timecode<DCPTime> (this);
54         grid->Add (_trim_end);
55         add_label_to_sizer (grid, this, _("Play length"), true);
56         _play_length = new Timecode<DCPTime> (this);
57         grid->Add (_play_length);
58
59         {
60                 add_label_to_sizer (grid, this, _("Video frame rate"), true);
61                 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
62                 _video_frame_rate = new wxTextCtrl (this, wxID_ANY);
63                 s->Add (_video_frame_rate, 1, wxEXPAND);
64                 _set_video_frame_rate = new wxButton (this, wxID_ANY, _("Set"));
65                 _set_video_frame_rate->Enable (false);
66                 s->Add (_set_video_frame_rate, 0, wxLEFT | wxRIGHT, 8);
67                 grid->Add (s, 1, wxEXPAND);
68         }
69
70         _position->Changed.connect    (boost::bind (&TimingPanel::position_changed, this));
71         _full_length->Changed.connect (boost::bind (&TimingPanel::full_length_changed, this));
72         _trim_start->Changed.connect  (boost::bind (&TimingPanel::trim_start_changed, this));
73         _trim_end->Changed.connect    (boost::bind (&TimingPanel::trim_end_changed, this));
74         _play_length->Changed.connect (boost::bind (&TimingPanel::play_length_changed, this));
75         _video_frame_rate->Bind       (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TimingPanel::video_frame_rate_changed, this));
76         _set_video_frame_rate->Bind   (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&TimingPanel::set_video_frame_rate, this));
77 }
78
79 void
80 TimingPanel::film_content_changed (int property)
81 {
82         ContentList cl = _parent->selected ();
83         int const film_video_frame_rate = _parent->film()->video_frame_rate ();
84
85         /* Here we check to see if we have exactly one different value of various
86            properties, and fill the controls with that value if so.
87         */
88         
89         if (property == ContentProperty::POSITION) {
90
91                 set<DCPTime> check;
92                 for (ContentList::const_iterator i = cl.begin (); i != cl.end(); ++i) {
93                         check.insert ((*i)->position ());
94                 }
95
96                 if (check.size() == 1) {
97                         _position->set (cl.front()->position(), film_video_frame_rate);
98                 } else {
99                         _position->clear ();
100                 }
101                 
102         } else if (
103                 property == ContentProperty::LENGTH ||
104                 property == VideoContentProperty::VIDEO_FRAME_RATE ||
105                 property == VideoContentProperty::VIDEO_FRAME_TYPE
106                 ) {
107
108                 set<DCPTime> check;
109                 for (ContentList::const_iterator i = cl.begin (); i != cl.end(); ++i) {
110                         check.insert ((*i)->full_length ());
111                 }
112                 
113                 if (check.size() == 1) {
114                         _full_length->set (cl.front()->full_length (), film_video_frame_rate);
115                 } else {
116                         _full_length->clear ();
117                 }
118
119         } else if (property == ContentProperty::TRIM_START) {
120
121                 set<DCPTime> check;
122                 for (ContentList::const_iterator i = cl.begin (); i != cl.end(); ++i) {
123                         check.insert ((*i)->trim_start ());
124                 }
125                 
126                 if (check.size() == 1) {
127                         _trim_start->set (cl.front()->trim_start (), film_video_frame_rate);
128                 } else {
129                         _trim_start->clear ();
130                 }
131                 
132         } else if (property == ContentProperty::TRIM_END) {
133
134                 set<DCPTime> check;
135                 for (ContentList::const_iterator i = cl.begin (); i != cl.end(); ++i) {
136                         check.insert ((*i)->trim_end ());
137                 }
138                 
139                 if (check.size() == 1) {
140                         _trim_end->set (cl.front()->trim_end (), film_video_frame_rate);
141                 } else {
142                         _trim_end->clear ();
143                 }
144         }
145
146         if (
147                 property == ContentProperty::LENGTH ||
148                 property == ContentProperty::TRIM_START ||
149                 property == ContentProperty::TRIM_END ||
150                 property == VideoContentProperty::VIDEO_FRAME_RATE ||
151                 property == VideoContentProperty::VIDEO_FRAME_TYPE
152                 ) {
153
154                 set<DCPTime> check;
155                 for (ContentList::const_iterator i = cl.begin (); i != cl.end(); ++i) {
156                         check.insert ((*i)->length_after_trim ());
157                 }
158                 
159                 if (check.size() == 1) {
160                         _play_length->set (cl.front()->length_after_trim (), film_video_frame_rate);
161                 } else {
162                         _play_length->clear ();
163                 }
164         }
165
166         if (property == VideoContentProperty::VIDEO_FRAME_RATE) {
167                 set<float> check;
168                 shared_ptr<VideoContent> vc;
169                 for (ContentList::const_iterator i = cl.begin (); i != cl.end(); ++i) {
170                         shared_ptr<VideoContent> t = dynamic_pointer_cast<VideoContent> (*i);
171                         if (t) {
172                                 check.insert (t->video_frame_rate ());
173                                 vc = t;
174                         }
175                 }
176                 if (check.size() == 1) {
177                         _video_frame_rate->SetValue (std_to_wx (raw_convert<string> (vc->video_frame_rate (), 5)));
178                         _video_frame_rate->Enable (true);
179                 } else {
180                         _video_frame_rate->SetValue ("");
181                         _video_frame_rate->Enable (false);
182                 }
183         }
184
185         bool have_still = false;
186         for (ContentList::const_iterator i = cl.begin (); i != cl.end(); ++i) {
187                 shared_ptr<ImageContent> ic = dynamic_pointer_cast<ImageContent> (*i);
188                 if (ic && ic->still ()) {
189                         have_still = true;
190                 }
191         }
192
193         _full_length->set_editable (have_still);
194         _play_length->set_editable (!have_still);
195         _set_video_frame_rate->Enable (false);
196 }
197
198 void
199 TimingPanel::position_changed ()
200 {
201         ContentList c = _parent->selected ();
202         for (ContentList::iterator i = c.begin(); i != c.end(); ++i) {
203                 (*i)->set_position (_position->get (_parent->film()->video_frame_rate ()));
204         }
205 }
206
207 void
208 TimingPanel::full_length_changed ()
209 {
210         ContentList c = _parent->selected ();
211         for (ContentList::iterator i = c.begin(); i != c.end(); ++i) {
212                 shared_ptr<ImageContent> ic = dynamic_pointer_cast<ImageContent> (*i);
213                 if (ic && ic->still ()) {
214                         /* XXX: No effective FRC here... is this right? */
215                         ic->set_video_length (ContentTime (_full_length->get (_parent->film()->video_frame_rate()), FrameRateChange (1, 1)));
216                 }
217         }
218 }
219
220 void
221 TimingPanel::trim_start_changed ()
222 {
223         ContentList c = _parent->selected ();
224         for (ContentList::iterator i = c.begin(); i != c.end(); ++i) {
225                 (*i)->set_trim_start (_trim_start->get (_parent->film()->video_frame_rate ()));
226         }
227 }
228
229
230 void
231 TimingPanel::trim_end_changed ()
232 {
233         ContentList c = _parent->selected ();
234         for (ContentList::iterator i = c.begin(); i != c.end(); ++i) {
235                 (*i)->set_trim_end (_trim_end->get (_parent->film()->video_frame_rate ()));
236         }
237 }
238
239 void
240 TimingPanel::play_length_changed ()
241 {
242         ContentList c = _parent->selected ();
243         for (ContentList::iterator i = c.begin(); i != c.end(); ++i) {
244                 (*i)->set_trim_end ((*i)->full_length() - _play_length->get (_parent->film()->video_frame_rate()) - (*i)->trim_start());
245         }
246 }
247
248 void
249 TimingPanel::video_frame_rate_changed ()
250 {
251         _set_video_frame_rate->Enable (true);
252 }
253
254 void
255 TimingPanel::set_video_frame_rate ()
256 {
257         ContentList c = _parent->selected ();
258         for (ContentList::iterator i = c.begin(); i != c.end(); ++i) {
259                 shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (*i);
260                 if (vc) {
261                         vc->set_video_frame_rate (raw_convert<float> (wx_to_std (_video_frame_rate->GetValue ())));
262                 }
263                 _set_video_frame_rate->Enable (false);
264         }
265 }
266
267 void
268 TimingPanel::content_selection_changed ()
269 {
270         bool const e = !_parent->selected().empty ();
271
272         _position->Enable (e);
273         _full_length->Enable (e);
274         _trim_start->Enable (e);
275         _trim_end->Enable (e);
276         _play_length->Enable (e);
277         _video_frame_rate->Enable (e);
278         
279         film_content_changed (ContentProperty::POSITION);
280         film_content_changed (ContentProperty::LENGTH);
281         film_content_changed (ContentProperty::TRIM_START);
282         film_content_changed (ContentProperty::TRIM_END);
283         film_content_changed (VideoContentProperty::VIDEO_FRAME_RATE);
284 }