No-op; rename a whole load of wx constants to their shorter equivalents.
[dcpomatic.git] / src / wx / film_viewer.cc
index 9564c0fc944595a31520c588e271ef385b77e286..40155b18c398ed7b5040cdc3095dedb561a623e6 100644 (file)
@@ -1,19 +1,20 @@
 /*
     Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
 
-    This program is free software; you can redistribute it and/or modify
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2 of the License, or
     (at your option) any later version.
 
-    This program is distributed in the hope that it will be useful,
+    DCP-o-matic is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.
 
     You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+    along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
 
 */
 
  *  @brief A wx widget to view a preview of a Film.
  */
 
+#include "film_viewer.h"
+#include "playhead_to_timecode_dialog.h"
+#include "playhead_to_frame_dialog.h"
+#include "wx_util.h"
 #include "lib/film.h"
 #include "lib/ratio.h"
 #include "lib/util.h"
@@ -35,8 +40,6 @@
 #include "lib/video_decoder.h"
 #include "lib/timer.h"
 #include "lib/log.h"
-#include "film_viewer.h"
-#include "wx_util.h"
 extern "C" {
 #include <libavutil/pixfmt.h>
 }
@@ -111,18 +114,20 @@ FilmViewer::FilmViewer (wxWindow* p)
        _back_button->SetMinSize (wxSize (32, -1));
        _forward_button->SetMinSize (wxSize (32, -1));
 
-       _panel->Bind          (wxEVT_PAINT,                        boost::bind (&FilmViewer::paint_panel,     this));
-       _panel->Bind          (wxEVT_SIZE,                         boost::bind (&FilmViewer::panel_sized,     this, _1));
-       _outline_content->Bind(wxEVT_COMMAND_CHECKBOX_CLICKED,     boost::bind (&FilmViewer::refresh_panel,   this));
-       _left_eye->Bind       (wxEVT_COMMAND_RADIOBUTTON_SELECTED, boost::bind (&FilmViewer::refresh,         this));
-       _right_eye->Bind      (wxEVT_COMMAND_RADIOBUTTON_SELECTED, boost::bind (&FilmViewer::refresh,         this));
-       _slider->Bind         (wxEVT_SCROLL_THUMBTRACK,            boost::bind (&FilmViewer::slider_moved,    this));
-       _slider->Bind         (wxEVT_SCROLL_PAGEUP,                boost::bind (&FilmViewer::slider_moved,    this));
-       _slider->Bind         (wxEVT_SCROLL_PAGEDOWN,              boost::bind (&FilmViewer::slider_moved,    this));
-       _play_button->Bind    (wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, boost::bind (&FilmViewer::play_clicked,    this));
-       _timer.Bind           (wxEVT_TIMER,                        boost::bind (&FilmViewer::timer,           this));
-       _back_button->Bind    (wxEVT_COMMAND_BUTTON_CLICKED,       boost::bind (&FilmViewer::back_clicked,    this));
-       _forward_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED,       boost::bind (&FilmViewer::forward_clicked, this));
+       _panel->Bind          (wxEVT_PAINT,             boost::bind (&FilmViewer::paint_panel,     this));
+       _panel->Bind          (wxEVT_SIZE,              boost::bind (&FilmViewer::panel_sized,     this, _1));
+       _outline_content->Bind(wxEVT_CHECKBOX,          boost::bind (&FilmViewer::refresh_panel,   this));
+       _left_eye->Bind       (wxEVT_RADIOBUTTON,       boost::bind (&FilmViewer::refresh,         this));
+       _right_eye->Bind      (wxEVT_RADIOBUTTON,       boost::bind (&FilmViewer::refresh,         this));
+       _slider->Bind         (wxEVT_SCROLL_THUMBTRACK, boost::bind (&FilmViewer::slider_moved,    this));
+       _slider->Bind         (wxEVT_SCROLL_PAGEUP,     boost::bind (&FilmViewer::slider_moved,    this));
+       _slider->Bind         (wxEVT_SCROLL_PAGEDOWN,   boost::bind (&FilmViewer::slider_moved,    this));
+       _play_button->Bind    (wxEVT_TOGGLEBUTTON,      boost::bind (&FilmViewer::play_clicked,    this));
+       _timer.Bind           (wxEVT_TIMER,             boost::bind (&FilmViewer::timer,           this));
+       _back_button->Bind    (wxEVT_LEFT_DOWN,         boost::bind (&FilmViewer::back_clicked,    this, _1));
+       _forward_button->Bind (wxEVT_LEFT_DOWN,         boost::bind (&FilmViewer::forward_clicked, this, _1));
+       _frame_number->Bind   (wxEVT_LEFT_DOWN,         boost::bind (&FilmViewer::frame_number_clicked, this));
+       _timecode->Bind       (wxEVT_LEFT_DOWN,         boost::bind (&FilmViewer::timecode_clicked, this));
 
        set_film (shared_ptr<Film> ());
 
@@ -153,6 +158,7 @@ FilmViewer::set_film (shared_ptr<Film> film)
 
        try {
                _player.reset (new Player (_film, _film->playlist ()));
+               _player->set_fast ();
        } catch (bad_alloc) {
                error_dialog (this, _("There is not enough free memory to do that."));
                _film.reset ();
@@ -220,19 +226,32 @@ FilmViewer::get (DCPTime p, bool accurate)
                                pv = all_pv.front ();
                        }
 
-                       /* XXX: this could now give us a 48-bit image, which is a bit wasteful,
-                          or a XYZ image, which the code below will currently rely on FFmpeg
-                          to colourspace-convert.
-                       */
-                       _frame = pv->image (boost::bind (&Log::dcp_log, _film->log().get(), _1, _2));
-                       ImageChanged (pv);
+                       /* In an ideal world, what we would do here is:
+                        *
+                        * 1. convert to XYZ exactly as we do in the DCP creation path.
+                        * 2. convert back to RGB for the preview display, compensating
+                        *    for the monitor etc. etc.
+                        *
+                        * but this is inefficient if the source is RGB.  Since we don't
+                        * (currently) care too much about the precise accuracy of the preview's
+                        * colour mapping (and we care more about its speed) we try to short-
+                        * circuit this "ideal" situation in some cases.
+                        *
+                        * The content's specified colour conversion indicates the colourspace
+                        * which the content is in (according to the user).
+                        *
+                        * PlayerVideo::image (bound to PlayerVideo::always_rgb) will take the source
+                        * image and convert it (from whatever the user has said it is) to RGB.
+                        */
 
-                       dcp::YUVToRGB yuv_to_rgb = dcp::YUV_TO_RGB_REC601;
-                       if (pv->colour_conversion()) {
-                               yuv_to_rgb = pv->colour_conversion().get().yuv_to_rgb();
-                       }
+                       _frame = pv->image (
+                               bind (&Log::dcp_log, _film->log().get(), _1, _2),
+                               bind (&PlayerVideo::always_rgb, _1),
+                               false, true
+                               );
+
+                       ImageChanged (pv);
 
-                       _frame = _frame->scale (_frame->size(), yuv_to_rgb, AV_PIX_FMT_RGB24, false);
                        _position = pv->time ();
                        _inter_position = pv->inter_position ();
                        _inter_size = pv->inter_size ();
@@ -433,32 +452,52 @@ FilmViewer::active_jobs_changed (optional<string> j)
        _play_button->Enable (a);
 }
 
-void
-FilmViewer::back_clicked ()
+DCPTime
+FilmViewer::nudge_amount (wxMouseEvent& ev)
 {
-       DCPTime p = _position - DCPTime::from_frames (1, _film->video_frame_rate ());
-       if (p < DCPTime ()) {
-               p = DCPTime ();
+       DCPTime amount = DCPTime::from_frames (1, _film->video_frame_rate ());
+
+       if (ev.ShiftDown() && !ev.ControlDown()) {
+               amount = DCPTime::from_seconds (1);
+       } else if (!ev.ShiftDown() && ev.ControlDown()) {
+               amount = DCPTime::from_seconds (10);
+       } else if (ev.ShiftDown() && ev.ControlDown()) {
+               amount = DCPTime::from_seconds (60);
        }
 
-       get (p, true);
-       update_position_label ();
-       update_position_slider ();
+       return amount;
 }
 
 void
-FilmViewer::forward_clicked ()
+FilmViewer::go_to (DCPTime t)
 {
-       DCPTime p = _position + DCPTime::from_frames (1, _film->video_frame_rate ());
-       if (p >= _film->length ()) {
-               p = _position;
+       if (t < DCPTime ()) {
+               t = DCPTime ();
+       }
+
+       if (t >= _film->length ()) {
+               t = _film->length ();
        }
 
-       get (p, true);
+       get (t, true);
        update_position_label ();
        update_position_slider ();
 }
 
+void
+FilmViewer::back_clicked (wxMouseEvent& ev)
+{
+       go_to (_position - nudge_amount (ev));
+       ev.Skip ();
+}
+
+void
+FilmViewer::forward_clicked (wxMouseEvent& ev)
+{
+       go_to (_position + nudge_amount (ev));
+       ev.Skip ();
+}
+
 void
 FilmViewer::player_changed (bool frequent)
 {
@@ -531,3 +570,23 @@ FilmViewer::set_coalesce_player_changes (bool c)
                }
        }
 }
+
+void
+FilmViewer::timecode_clicked ()
+{
+       PlayheadToTimecodeDialog* dialog = new PlayheadToTimecodeDialog (this, _film->video_frame_rate ());
+       if (dialog->ShowModal() == wxID_OK) {
+               go_to (dialog->get ());
+       }
+       dialog->Destroy ();
+}
+
+void
+FilmViewer::frame_number_clicked ()
+{
+       PlayheadToFrameDialog* dialog = new PlayheadToFrameDialog (this, _film->video_frame_rate ());
+       if (dialog->ShowModal() == wxID_OK) {
+               go_to (dialog->get ());
+       }
+       dialog->Destroy ();
+}