06608339754b11f33275969ebff94b7311651a03
[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                 int vw, vh;
66                 GetSize (&vw, &vh);
67
68                 float const target = _film->format()->ratio_as_float ();
69
70                 delete _bitmap;
71                 if ((float (vw) / vh) > target) {
72                         /* view is longer (horizontally) than the ratio; fit height */
73                         _bitmap = new wxBitmap (_image->Scale (vh * target, vh));
74                 } else {
75                         /* view is shorter (horizontally) than the ratio; fit width */
76                         _bitmap = new wxBitmap (_image->Scale (vw, vw / target));
77                 }
78         }
79
80         void load (string f)
81         {
82                 clear ();
83                 _image = new wxImage (wxString (f.c_str(), wxConvUTF8));
84                 _bitmap = new wxBitmap (_image->Scale (512, 512));
85         }
86
87         void clear ()
88         {
89                 delete _bitmap;
90                 _bitmap = 0;
91                 delete _image;
92                 _image = 0;
93         }
94
95         DECLARE_EVENT_TABLE ();
96
97 private:
98         Film* _film;
99         wxImage* _image;
100         wxBitmap* _bitmap;
101 };
102
103 BEGIN_EVENT_TABLE (ThumbPanel, wxPanel)
104 EVT_PAINT (ThumbPanel::paint_event)
105 EVT_SIZE (ThumbPanel::size_event)
106 END_EVENT_TABLE ()
107
108 FilmViewer::FilmViewer (Film* f, wxWindow* p)
109         : wxPanel (p)
110         , _film (f)
111 {
112         _sizer = new wxBoxSizer (wxVERTICAL);
113         SetSizer (_sizer);
114         
115         _thumb_panel = new ThumbPanel (this, f);
116         _thumb_panel->Show (true);
117         _sizer->Add (_thumb_panel, 1, wxEXPAND);
118
119 #if 0   
120         _scroller.add (_image);
121         
122         Gtk::HBox* controls = manage (new Gtk::HBox);
123         controls->set_spacing (6);
124         controls->pack_start (_position_slider);
125         
126         _vbox.pack_start (_scroller, true, true);
127         _vbox.pack_start (*controls, false, false);
128         _vbox.set_border_width (12);
129
130         _position_slider.set_digits (0);
131         _position_slider.signal_format_value().connect (sigc::mem_fun (*this, &FilmViewer::format_position_slider_value));
132         _position_slider.signal_value_changed().connect (sigc::mem_fun (*this, &FilmViewer::position_slider_changed));
133
134         _scroller.signal_size_allocate().connect (sigc::mem_fun (*this, &FilmViewer::scroller_size_allocate));
135 #endif  
136
137         set_film (_film);
138
139         load_thumbnail (42);//XXX
140 }
141
142 void
143 FilmViewer::load_thumbnail (int n)
144 {
145         if (_film == 0 || _film->num_thumbs() <= n) {
146                 return;
147         }
148
149         int const left = _film->left_crop ();
150         int const right = _film->right_crop ();
151         int const top = _film->top_crop ();
152         int const bottom = _film->bottom_crop ();
153
154         _thumb_panel->load (_film->thumb_file(n));
155
156 //      _pixbuf = Gdk::Pixbuf::create_from_file (_film->thumb_file (n));
157
158 //      int const cw = _film->size().width - left - right;
159 //      int const ch = _film->size().height - top - bottom;
160 //      _cropped_pixbuf = Gdk::Pixbuf::create_subpixbuf (_pixbuf, left, top, cw, ch);
161 //      update_scaled_pixbuf ();
162 //      _image.set (_scaled_pixbuf);
163 }
164
165 void
166 FilmViewer::reload_current_thumbnail ()
167 {
168         load_thumbnail (42);//_position_slider.get_value ());
169 }
170
171 void
172 FilmViewer::position_slider_changed ()
173 {
174         reload_current_thumbnail ();
175 }
176
177 string
178 FilmViewer::format_position_slider_value (double v) const
179 {
180 #if 0   
181         stringstream s;
182
183         if (_film && int (v) < _film->num_thumbs ()) {
184                 int const f = _film->thumb_frame (int (v));
185                 s << f << " " << seconds_to_hms (f / _film->frames_per_second ());
186         } else {
187                 s << "-";
188         }
189         
190         return s.str ();
191 #endif  
192 }
193
194 void
195 FilmViewer::film_changed (Film::Property p)
196 {
197 #if 0   
198         if (p == Film::LEFT_CROP || p == Film::RIGHT_CROP || p == Film::TOP_CROP || p == Film::BOTTOM_CROP) {
199                 reload_current_thumbnail ();
200         } else if (p == Film::THUMBS) {
201                 if (_film && _film->num_thumbs() > 1) {
202                         _position_slider.set_range (0, _film->num_thumbs () - 1);
203                 } else {
204                         _image.clear ();
205                         _position_slider.set_range (0, 1);
206                 }
207                 
208                 _position_slider.set_value (0);
209                 reload_current_thumbnail ();
210         } else if (p == Film::FORMAT) {
211                 reload_current_thumbnail ();
212         } else if (p == Film::CONTENT) {
213                 setup_visibility ();
214                 _film->examine_content ();
215                 update_thumbs ();
216         }
217 #endif  
218 }
219
220 void
221 FilmViewer::set_film (Film* f)
222 {
223         _film = f;
224
225         if (!_film) {
226                 _thumb_panel->clear ();
227                 return;
228         }
229
230 //      _film->Changed.connect (sigc::mem_fun (*this, &FilmViewer::film_changed));
231
232         film_changed (Film::THUMBS);
233 }
234
235 pair<int, int>
236 FilmViewer::scaled_pixbuf_size () const
237 {
238 #if 0   
239         if (_film == 0) {
240                 return make_pair (0, 0);
241         }
242         
243         int const cw = _film->size().width - _film->left_crop() - _film->right_crop(); 
244         int const ch = _film->size().height - _film->top_crop() - _film->bottom_crop();
245
246         float ratio = 1;
247         if (_film->format()) {
248                 ratio = _film->format()->ratio_as_float() * ch / cw;
249         }
250
251         Gtk::Allocation const a = _scroller.get_allocation ();
252         float const zoom = min (float (a.get_width()) / (cw * ratio), float (a.get_height()) / cw);
253         return make_pair (cw * zoom * ratio, ch * zoom);
254 #endif  
255 }
256         
257 void
258 FilmViewer::update_scaled_pixbuf ()
259 {
260 #if 0   
261         pair<int, int> const s = scaled_pixbuf_size ();
262
263         if (s.first > 0 && s.second > 0 && _cropped_pixbuf) {
264                 _scaled_pixbuf = _cropped_pixbuf->scale_simple (s.first, s.second, Gdk::INTERP_HYPER);
265                 _image.set (_scaled_pixbuf);
266         }
267 #endif  
268 }
269
270 void
271 FilmViewer::update_thumbs ()
272 {
273 #if 0   
274         if (!_film) {
275                 return;
276         }
277
278         _film->update_thumbs_pre_gui ();
279
280         shared_ptr<const FilmState> s = _film->state_copy ();
281         shared_ptr<Options> o (new Options (s->dir ("thumbs"), ".tiff", ""));
282         o->out_size = _film->size ();
283         o->apply_crop = false;
284         o->decode_audio = false;
285         o->decode_video_frequency = 128;
286         
287         shared_ptr<Job> j (new ThumbsJob (s, o, _film->log ()));
288         j->Finished.connect (sigc::mem_fun (_film, &Film::update_thumbs_post_gui));
289         JobManager::instance()->add (j);
290 #endif  
291 }
292
293 void
294 FilmViewer::setup_visibility ()
295 {
296 #if 0   
297         if (!_film) {
298                 return;
299         }
300
301         ContentType const c = _film->content_type ();
302         _position_slider.property_visible() = (c == VIDEO);
303 #endif  
304 }