X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fwx%2Ffilm_viewer.cc;h=5262338332e7073884b37bbc398c9d007eb057ca;hb=c0e04acd1e9875fa67800a7861bd8a370157b49f;hp=06608339754b11f33275969ebff94b7311651a03;hpb=424fb25e9b084ee1cc8d2552f8b22a0a4d3d5f46;p=dcpomatic.git diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 066083397..526233833 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -26,11 +26,12 @@ #include "lib/film.h" #include "lib/format.h" #include "lib/util.h" -#include "lib/thumbs_job.h" #include "lib/job_manager.h" #include "lib/film_state.h" #include "lib/options.h" +#include "lib/subtitle.h" #include "film_viewer.h" +#include "wx_util.h" using namespace std; using namespace boost; @@ -41,63 +42,180 @@ public: ThumbPanel (wxPanel* parent, Film* film) : wxPanel (parent) , _film (film) - , _image (0) - , _bitmap (0) - { - } + , _frame_rebuild_needed (false) + , _composition_needed (false) + {} + /** Handle a paint event */ void paint_event (wxPaintEvent& ev) { - if (!_bitmap) { + if (!_film || _film->thumbs().size() == 0) { + wxPaintDC dc (this); return; } + if (_frame_rebuild_needed) { + _image.reset (new wxImage (std_to_wx (_film->thumb_file (_index)))); + + _subtitle.reset (); + pair s = _film->thumb_subtitle (_index); + if (!s.second.empty ()) { + _subtitle.reset (new SubtitleView (s.first, std_to_wx (s.second))); + } + + _frame_rebuild_needed = false; + compose (); + } + + if (_composition_needed) { + compose (); + } + wxPaintDC dc (this); - dc.DrawBitmap (*_bitmap, 0, 0, false); + if (_bitmap) { + dc.DrawBitmap (*_bitmap, 0, 0, false); + } + + if (_film->with_subtitles() && _subtitle) { + dc.DrawBitmap (*_subtitle->bitmap, _subtitle->transformed_area.x, _subtitle->transformed_area.y, true); + } } + /** Handle a size event */ void size_event (wxSizeEvent &) { if (!_image) { return; } - int vw, vh; - GetSize (&vw, &vh); + recompose (); + } - float const target = _film->format()->ratio_as_float (); + /** @param n Thumbnail index */ + void set (int n) + { + _index = n; + _frame_rebuild_needed = true; + Refresh (); + } - delete _bitmap; - if ((float (vw) / vh) > target) { - /* view is longer (horizontally) than the ratio; fit height */ - _bitmap = new wxBitmap (_image->Scale (vh * target, vh)); + void set_film (Film* f) + { + _film = f; + if (!_film) { + clear (); + _frame_rebuild_needed = true; + Refresh (); } else { - /* view is shorter (horizontally) than the ratio; fit width */ - _bitmap = new wxBitmap (_image->Scale (vw, vw / target)); + _frame_rebuild_needed = true; + Refresh (); } } - void load (string f) + /** Clear our thumbnail image */ + void clear () { - clear (); - _image = new wxImage (wxString (f.c_str(), wxConvUTF8)); - _bitmap = new wxBitmap (_image->Scale (512, 512)); + _bitmap.reset (); + _image.reset (); + _subtitle.reset (); } - void clear () + void recompose () { - delete _bitmap; - _bitmap = 0; - delete _image; - _image = 0; + _composition_needed = true; + Refresh (); } DECLARE_EVENT_TABLE (); private: + + void compose () + { + _composition_needed = false; + + if (!_film || !_image) { + return; + } + + /* Size of the view */ + int vw, vh; + GetSize (&vw, &vh); + + Crop const fc = _film->crop (); + + /* Cropped rectangle */ + Rect cropped_area ( + fc.left, + fc.top, + _image->GetWidth() - (fc.left + fc.right), + _image->GetHeight() - (fc.top + fc.bottom) + ); + + /* Target ratio */ + float const target = _film->format() ? _film->format()->ratio_as_float (_film) : 1.78; + + _transformed_image = _image->GetSubImage (wxRect (cropped_area.x, cropped_area.y, cropped_area.width, cropped_area.height)); + + float x_scale = 1; + float y_scale = 1; + + if ((float (vw) / vh) > target) { + /* view is longer (horizontally) than the ratio; fit height */ + _transformed_image.Rescale (vh * target, vh, wxIMAGE_QUALITY_HIGH); + x_scale = vh * target / cropped_area.width; + y_scale = float (vh) / cropped_area.height; + } else { + /* view is shorter (horizontally) than the ratio; fit width */ + _transformed_image.Rescale (vw, vw / target, wxIMAGE_QUALITY_HIGH); + x_scale = float (vw) / cropped_area.width; + y_scale = (vw / target) / cropped_area.height; + } + + _bitmap.reset (new wxBitmap (_transformed_image)); + + if (_subtitle) { + + _subtitle->transformed_area = subtitle_transformed_area ( + x_scale, y_scale, _subtitle->base_area, _film->subtitle_offset(), _film->subtitle_scale() + ); + + _subtitle->transformed_image = _subtitle->base_image; + _subtitle->transformed_image.Rescale (_subtitle->transformed_area.width, _subtitle->transformed_area.height, wxIMAGE_QUALITY_HIGH); + _subtitle->transformed_area.x -= rint (_film->crop().left * x_scale); + _subtitle->transformed_area.y -= rint (_film->crop().top * y_scale); + _subtitle->bitmap.reset (new wxBitmap (_subtitle->transformed_image)); + } + } + Film* _film; - wxImage* _image; - wxBitmap* _bitmap; + shared_ptr _image; + wxImage _transformed_image; + /** currently-displayed thumbnail index */ + int _index; + shared_ptr _bitmap; + bool _frame_rebuild_needed; + bool _composition_needed; + + struct SubtitleView + { + SubtitleView (Position p, wxString const & i) + : base_image (i) + { + base_area.x = p.x; + base_area.y = p.y; + base_area.width = base_image.GetWidth (); + base_area.height = base_image.GetHeight (); + } + + Rect base_area; + Rect transformed_area; + wxImage base_image; + wxImage transformed_image; + shared_ptr bitmap; + }; + + shared_ptr _subtitle; }; BEGIN_EVENT_TABLE (ThumbPanel, wxPanel) @@ -107,198 +225,99 @@ END_EVENT_TABLE () FilmViewer::FilmViewer (Film* f, wxWindow* p) : wxPanel (p) - , _film (f) + , _film (0) { _sizer = new wxBoxSizer (wxVERTICAL); SetSizer (_sizer); _thumb_panel = new ThumbPanel (this, f); - _thumb_panel->Show (true); _sizer->Add (_thumb_panel, 1, wxEXPAND); -#if 0 - _scroller.add (_image); - - Gtk::HBox* controls = manage (new Gtk::HBox); - controls->set_spacing (6); - controls->pack_start (_position_slider); - - _vbox.pack_start (_scroller, true, true); - _vbox.pack_start (*controls, false, false); - _vbox.set_border_width (12); - - _position_slider.set_digits (0); - _position_slider.signal_format_value().connect (sigc::mem_fun (*this, &FilmViewer::format_position_slider_value)); - _position_slider.signal_value_changed().connect (sigc::mem_fun (*this, &FilmViewer::position_slider_changed)); + int const m = max ((size_t) 1, f ? f->thumbs().size() - 1 : 0); + _slider = new wxSlider (this, wxID_ANY, 0, 0, m); + _sizer->Add (_slider, 0, wxEXPAND | wxLEFT | wxRIGHT); + set_thumbnail (0); - _scroller.signal_size_allocate().connect (sigc::mem_fun (*this, &FilmViewer::scroller_size_allocate)); -#endif + _slider->Connect (wxID_ANY, wxEVT_COMMAND_SLIDER_UPDATED, wxCommandEventHandler (FilmViewer::slider_changed), 0, this); set_film (_film); - - load_thumbnail (42);//XXX } void -FilmViewer::load_thumbnail (int n) +FilmViewer::set_thumbnail (int n) { - if (_film == 0 || _film->num_thumbs() <= n) { + if (_film == 0 || int (_film->thumbs().size()) <= n) { return; } - int const left = _film->left_crop (); - int const right = _film->right_crop (); - int const top = _film->top_crop (); - int const bottom = _film->bottom_crop (); - - _thumb_panel->load (_film->thumb_file(n)); - -// _pixbuf = Gdk::Pixbuf::create_from_file (_film->thumb_file (n)); - -// int const cw = _film->size().width - left - right; -// int const ch = _film->size().height - top - bottom; -// _cropped_pixbuf = Gdk::Pixbuf::create_subpixbuf (_pixbuf, left, top, cw, ch); -// update_scaled_pixbuf (); -// _image.set (_scaled_pixbuf); + _thumb_panel->set (n); } void -FilmViewer::reload_current_thumbnail () +FilmViewer::slider_changed (wxCommandEvent &) { - load_thumbnail (42);//_position_slider.get_value ()); + set_thumbnail (_slider->GetValue ()); } void -FilmViewer::position_slider_changed () +FilmViewer::film_changed (FilmState::Property p) { - reload_current_thumbnail (); -} - -string -FilmViewer::format_position_slider_value (double v) const -{ -#if 0 - stringstream s; - - if (_film && int (v) < _film->num_thumbs ()) { - int const f = _film->thumb_frame (int (v)); - s << f << " " << seconds_to_hms (f / _film->frames_per_second ()); - } else { - s << "-"; - } + ensure_ui_thread (); - return s.str (); -#endif -} - -void -FilmViewer::film_changed (Film::Property p) -{ -#if 0 - if (p == Film::LEFT_CROP || p == Film::RIGHT_CROP || p == Film::TOP_CROP || p == Film::BOTTOM_CROP) { - reload_current_thumbnail (); - } else if (p == Film::THUMBS) { - if (_film && _film->num_thumbs() > 1) { - _position_slider.set_range (0, _film->num_thumbs () - 1); + switch (p) { + case FilmState::THUMBS: + if (_film && _film->thumbs().size() > 1) { + _slider->SetRange (0, _film->thumbs().size() - 1); } else { - _image.clear (); - _position_slider.set_range (0, 1); + _thumb_panel->clear (); + _slider->SetRange (0, 1); } - _position_slider.set_value (0); - reload_current_thumbnail (); - } else if (p == Film::FORMAT) { - reload_current_thumbnail (); - } else if (p == Film::CONTENT) { + _slider->SetValue (0); + set_thumbnail (0); + break; + case FilmState::CONTENT: setup_visibility (); - _film->examine_content (); - update_thumbs (); + break; + case FilmState::CROP: + case FilmState::FORMAT: + case FilmState::WITH_SUBTITLES: + case FilmState::SUBTITLE_OFFSET: + case FilmState::SUBTITLE_SCALE: + _thumb_panel->recompose (); + break; + default: + break; } -#endif } void FilmViewer::set_film (Film* f) { - _film = f; - - if (!_film) { - _thumb_panel->clear (); + if (_film == f) { return; } - -// _film->Changed.connect (sigc::mem_fun (*this, &FilmViewer::film_changed)); - - film_changed (Film::THUMBS); -} - -pair -FilmViewer::scaled_pixbuf_size () const -{ -#if 0 - if (_film == 0) { - return make_pair (0, 0); - } - - int const cw = _film->size().width - _film->left_crop() - _film->right_crop(); - int const ch = _film->size().height - _film->top_crop() - _film->bottom_crop(); - - float ratio = 1; - if (_film->format()) { - ratio = _film->format()->ratio_as_float() * ch / cw; - } - - Gtk::Allocation const a = _scroller.get_allocation (); - float const zoom = min (float (a.get_width()) / (cw * ratio), float (a.get_height()) / cw); - return make_pair (cw * zoom * ratio, ch * zoom); -#endif -} -void -FilmViewer::update_scaled_pixbuf () -{ -#if 0 - pair const s = scaled_pixbuf_size (); - - if (s.first > 0 && s.second > 0 && _cropped_pixbuf) { - _scaled_pixbuf = _cropped_pixbuf->scale_simple (s.first, s.second, Gdk::INTERP_HYPER); - _image.set (_scaled_pixbuf); - } -#endif -} + _film = f; + _thumb_panel->set_film (_film); -void -FilmViewer::update_thumbs () -{ -#if 0 if (!_film) { return; } - _film->update_thumbs_pre_gui (); - - shared_ptr s = _film->state_copy (); - shared_ptr o (new Options (s->dir ("thumbs"), ".tiff", "")); - o->out_size = _film->size (); - o->apply_crop = false; - o->decode_audio = false; - o->decode_video_frequency = 128; - - shared_ptr j (new ThumbsJob (s, o, _film->log ())); - j->Finished.connect (sigc::mem_fun (_film, &Film::update_thumbs_post_gui)); - JobManager::instance()->add (j); -#endif + _film->Changed.connect (sigc::mem_fun (*this, &FilmViewer::film_changed)); + film_changed (Film::CROP); + film_changed (Film::THUMBS); + setup_visibility (); } void FilmViewer::setup_visibility () { -#if 0 if (!_film) { return; } ContentType const c = _film->content_type (); - _position_slider.property_visible() = (c == VIDEO); -#endif + _slider->Show (c == VIDEO); }