Viewer kind of works.
[dcpomatic.git] / src / wx / film_viewer.cc
1 /*
2     Copyright (C) 2012 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 /** @file  src/film_viewer.cc
21  *  @brief A wx widget to view `thumbnails' of a Film.
22  */
23
24 #include <iostream>
25 #include <iomanip>
26 #include "lib/film.h"
27 #include "lib/format.h"
28 #include "lib/util.h"
29 #include "lib/thumbs_job.h"
30 #include "lib/job_manager.h"
31 #include "lib/film_state.h"
32 #include "lib/options.h"
33 #include "film_viewer.h"
34
35 using namespace std;
36 using namespace boost;
37
38 class ThumbPanel : public wxPanel
39 {
40 public:
41         ThumbPanel (wxPanel* parent, Film* film)
42                 : wxPanel (parent)
43                 , _film (film)
44                 , _image (0)
45                 , _bitmap (0)
46         {
47         }
48
49         void paint_event (wxPaintEvent& ev)
50         {
51                 if (!_bitmap) {
52                         return;
53                 }
54
55                 wxPaintDC dc (this);
56                 dc.DrawBitmap (*_bitmap, 0, 0, false);
57         }
58
59         void size_event (wxSizeEvent &)
60         {
61                 if (!_image) {
62                         return;
63                 }
64
65                 resize ();
66         }
67
68         void resize ()
69         {
70                 int vw, vh;
71                 GetSize (&vw, &vh);
72
73                 float const target = _film->format()->ratio_as_float ();
74
75                 delete _bitmap;
76                 if ((float (vw) / vh) > target) {
77                         /* view is longer (horizontally) than the ratio; fit height */
78                         _bitmap = new wxBitmap (_image->Scale (vh * target, vh));
79                 } else {
80                         /* view is shorter (horizontally) than the ratio; fit width */
81                         _bitmap = new wxBitmap (_image->Scale (vw, vw / target));
82                 }
83
84                 Refresh ();
85         }
86
87         void load (string f)
88         {
89                 delete _image;
90                 _image = new wxImage (wxString (f.c_str(), wxConvUTF8));
91                 resize ();
92         }
93
94         void clear ()
95         {
96                 delete _bitmap;
97                 _bitmap = 0;
98                 delete _image;
99                 _image = 0;
100         }
101
102         DECLARE_EVENT_TABLE ();
103
104 private:
105         Film* _film;
106         wxImage* _image;
107         wxBitmap* _bitmap;
108 };
109
110 BEGIN_EVENT_TABLE (ThumbPanel, wxPanel)
111 EVT_PAINT (ThumbPanel::paint_event)
112 EVT_SIZE (ThumbPanel::size_event)
113 END_EVENT_TABLE ()
114
115 FilmViewer::FilmViewer (Film* f, wxWindow* p)
116         : wxPanel (p)
117         , _film (f)
118 {
119         _sizer = new wxBoxSizer (wxVERTICAL);
120         SetSizer (_sizer);
121         
122         _thumb_panel = new ThumbPanel (this, f);
123         _sizer->Add (_thumb_panel, 1, wxEXPAND);
124
125         int const max = f ? f->num_thumbs() : 0;
126         _slider = new wxSlider (this, wxID_ANY, 0, 0, max);
127         _sizer->Add (_slider, 0, wxEXPAND | wxLEFT | wxRIGHT);
128         load_thumbnail (0);
129
130         _slider->Connect (wxID_ANY, wxEVT_COMMAND_SLIDER_UPDATED, wxCommandEventHandler (FilmViewer::slider_changed), 0, this);
131
132         set_film (_film);
133 }
134
135 void
136 FilmViewer::load_thumbnail (int n)
137 {
138         if (_film == 0 || _film->num_thumbs() <= n) {
139                 return;
140         }
141
142         int const left = _film->left_crop ();
143         int const right = _film->right_crop ();
144         int const top = _film->top_crop ();
145         int const bottom = _film->bottom_crop ();
146
147         _thumb_panel->load (_film->thumb_file(n));
148 }
149
150 void
151 FilmViewer::reload_current_thumbnail ()
152 {
153         load_thumbnail (_slider->GetValue ());
154 }
155
156 void
157 FilmViewer::slider_changed (wxCommandEvent &)
158 {
159         reload_current_thumbnail ();
160 }
161
162 string
163 FilmViewer::format_position_slider_value (double v) const
164 {
165 #if 0   
166         stringstream s;
167
168         if (_film && int (v) < _film->num_thumbs ()) {
169                 int const f = _film->thumb_frame (int (v));
170                 s << f << " " << seconds_to_hms (f / _film->frames_per_second ());
171         } else {
172                 s << "-";
173         }
174         
175         return s.str ();
176 #endif  
177 }
178
179 void
180 FilmViewer::film_changed (Film::Property p)
181 {
182 #if 0   
183         if (p == Film::LEFT_CROP || p == Film::RIGHT_CROP || p == Film::TOP_CROP || p == Film::BOTTOM_CROP) {
184                 reload_current_thumbnail ();
185         } else if (p == Film::THUMBS) {
186                 if (_film && _film->num_thumbs() > 1) {
187                         _position_slider.set_range (0, _film->num_thumbs () - 1);
188                 } else {
189                         _image.clear ();
190                         _position_slider.set_range (0, 1);
191                 }
192                 
193                 _position_slider.set_value (0);
194                 reload_current_thumbnail ();
195         } else if (p == Film::FORMAT) {
196                 reload_current_thumbnail ();
197         } else if (p == Film::CONTENT) {
198                 setup_visibility ();
199                 _film->examine_content ();
200                 update_thumbs ();
201         }
202 #endif  
203 }
204
205 void
206 FilmViewer::set_film (Film* f)
207 {
208         _film = f;
209
210         if (!_film) {
211                 _thumb_panel->clear ();
212                 return;
213         }
214
215 //      _film->Changed.connect (sigc::mem_fun (*this, &FilmViewer::film_changed));
216
217         film_changed (Film::THUMBS);
218 }
219
220 pair<int, int>
221 FilmViewer::scaled_pixbuf_size () const
222 {
223 #if 0   
224         if (_film == 0) {
225                 return make_pair (0, 0);
226         }
227         
228         int const cw = _film->size().width - _film->left_crop() - _film->right_crop(); 
229         int const ch = _film->size().height - _film->top_crop() - _film->bottom_crop();
230
231         float ratio = 1;
232         if (_film->format()) {
233                 ratio = _film->format()->ratio_as_float() * ch / cw;
234         }
235
236         Gtk::Allocation const a = _scroller.get_allocation ();
237         float const zoom = min (float (a.get_width()) / (cw * ratio), float (a.get_height()) / cw);
238         return make_pair (cw * zoom * ratio, ch * zoom);
239 #endif  
240 }
241         
242 void
243 FilmViewer::update_scaled_pixbuf ()
244 {
245 #if 0   
246         pair<int, int> const s = scaled_pixbuf_size ();
247
248         if (s.first > 0 && s.second > 0 && _cropped_pixbuf) {
249                 _scaled_pixbuf = _cropped_pixbuf->scale_simple (s.first, s.second, Gdk::INTERP_HYPER);
250                 _image.set (_scaled_pixbuf);
251         }
252 #endif  
253 }
254
255 void
256 FilmViewer::update_thumbs ()
257 {
258 #if 0   
259         if (!_film) {
260                 return;
261         }
262
263         _film->update_thumbs_pre_gui ();
264
265         shared_ptr<const FilmState> s = _film->state_copy ();
266         shared_ptr<Options> o (new Options (s->dir ("thumbs"), ".tiff", ""));
267         o->out_size = _film->size ();
268         o->apply_crop = false;
269         o->decode_audio = false;
270         o->decode_video_frequency = 128;
271         
272         shared_ptr<Job> j (new ThumbsJob (s, o, _film->log ()));
273         j->Finished.connect (sigc::mem_fun (_film, &Film::update_thumbs_post_gui));
274         JobManager::instance()->add (j);
275 #endif  
276 }
277
278 void
279 FilmViewer::setup_visibility ()
280 {
281 #if 0   
282         if (!_film) {
283                 return;
284         }
285
286         ContentType const c = _film->content_type ();
287         _position_slider.property_visible() = (c == VIDEO);
288 #endif  
289 }