X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fwx%2Ftimeline.cc;h=ac26c77a9125d7ab31c2a34620831d980b5d6bc4;hb=8aeb741ccbe2edb528e98a431bf55459a6836a9b;hp=8b0e4762a6ac9f6b888bb9190b23c9da686cb4ef;hpb=e875c2935a4031fd5d50864b20a432c343f48248;p=dcpomatic.git diff --git a/src/wx/timeline.cc b/src/wx/timeline.cc index 8b0e4762a..ac26c77a9 100644 --- a/src/wx/timeline.cc +++ b/src/wx/timeline.cc @@ -33,15 +33,19 @@ using boost::shared_ptr; using boost::weak_ptr; using boost::dynamic_pointer_cast; using boost::bind; +using boost::optional; +/** Parent class for components of the timeline (e.g. a piece of content or an axis) */ class View : public boost::noncopyable { public: - View (Timeline& t) + View (DCPTimeline& t) : _timeline (t) { } + + virtual ~View () {} void paint (wxGraphicsContext* g) { @@ -60,21 +64,23 @@ public: protected: virtual void do_paint (wxGraphicsContext *) = 0; - int time_x (Time t) const + int time_x (DCPTime t) const { return _timeline.tracks_position().x + t * _timeline.pixels_per_time_unit(); } - Timeline& _timeline; + DCPTimeline& _timeline; private: dcpomatic::Rect _last_paint_bbox; }; + +/** Parent class for views of pieces of content */ class ContentView : public View { public: - ContentView (Timeline& tl, shared_ptr c) + ContentView (DCPTimeline& tl, shared_ptr c) : View (tl) , _content (c) , _track (0) @@ -92,9 +98,9 @@ public: } return dcpomatic::Rect ( - time_x (content->start ()) - 8, + time_x (content->position ()) - 8, y_pos (_track) - 8, - content->length () * _timeline.pixels_per_time_unit() + 16, + content->length_after_trim () * _timeline.pixels_per_time_unit() + 16, _timeline.track_height() + 16 ); } @@ -133,8 +139,8 @@ private: return; } - Time const start = cont->start (); - Time const len = cont->length (); + DCPTime const position = cont->position (); + DCPTime const len = cont->length_after_trim (); wxColour selected (colour().Red() / 2, colour().Green() / 2, colour().Blue() / 2); @@ -148,23 +154,23 @@ private: } wxGraphicsPath path = gc->CreatePath (); - path.MoveToPoint (time_x (start), y_pos (_track) + 4); - path.AddLineToPoint (time_x (start + len), y_pos (_track) + 4); - path.AddLineToPoint (time_x (start + len), y_pos (_track + 1) - 4); - path.AddLineToPoint (time_x (start), y_pos (_track + 1) - 4); - path.AddLineToPoint (time_x (start), y_pos (_track) + 4); + path.MoveToPoint (time_x (position), y_pos (_track) + 4); + path.AddLineToPoint (time_x (position + len), y_pos (_track) + 4); + path.AddLineToPoint (time_x (position + len), y_pos (_track + 1) - 4); + path.AddLineToPoint (time_x (position), y_pos (_track + 1) - 4); + path.AddLineToPoint (time_x (position), y_pos (_track) + 4); gc->StrokePath (path); gc->FillPath (path); - wxString name = wxString::Format (wxT ("%s [%s]"), std_to_wx (cont->path().filename().string()).data(), type().data()); + wxString name = wxString::Format (wxT ("%s [%s]"), std_to_wx (cont->path_summary()).data(), type().data()); wxDouble name_width; wxDouble name_height; wxDouble name_descent; wxDouble name_leading; gc->GetTextExtent (name, &name_width, &name_height, &name_descent, &name_leading); - gc->Clip (wxRegion (time_x (start), y_pos (_track), len * _timeline.pixels_per_time_unit(), _timeline.track_height())); - gc->DrawText (name, time_x (start) + 12, y_pos (_track + 1) - name_height - 4); + gc->Clip (wxRegion (time_x (position), y_pos (_track), len * _timeline.pixels_per_time_unit(), _timeline.track_height())); + gc->DrawText (name, time_x (position) + 12, y_pos (_track + 1) - name_height - 4); gc->ResetClip (); } @@ -177,7 +183,7 @@ private: { ensure_ui_thread (); - if (p == ContentProperty::START || p == ContentProperty::LENGTH) { + if (p == ContentProperty::POSITION || p == ContentProperty::LENGTH) { force_redraw (); } @@ -197,7 +203,7 @@ private: class AudioContentView : public ContentView { public: - AudioContentView (Timeline& tl, shared_ptr c) + AudioContentView (DCPTimeline& tl, shared_ptr c) : ContentView (tl, c) {} @@ -216,7 +222,7 @@ private: class VideoContentView : public ContentView { public: - VideoContentView (Timeline& tl, shared_ptr c) + VideoContentView (DCPTimeline& tl, shared_ptr c) : ContentView (tl, c) {} @@ -237,10 +243,10 @@ private: } }; -class TimeAxisView : public View +class DCPTimeAxisView : public View { public: - TimeAxisView (Timeline& tl, int y) + DCPTimeAxisView (DCPTimeline& tl, int y) : View (tl) , _y (y) {} @@ -285,7 +291,7 @@ private: path.AddLineToPoint (_timeline.width(), _y); gc->StrokePath (path); - Time t = 0; + DCPTime t = 0; while ((t * _timeline.pixels_per_time_unit()) < _timeline.width()) { wxGraphicsPath path = gc->CreatePath (); path.MoveToPoint (time_x (t), _y - 4); @@ -319,38 +325,40 @@ private: int _y; }; -Timeline::Timeline (wxWindow* parent, FilmEditor* ed, shared_ptr film) + +DCPTimeline::DCPTimeline (wxWindow* parent, FilmEditor* ed, shared_ptr film) : wxPanel (parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE) , _film_editor (ed) , _film (film) - , _time_axis_view (new TimeAxisView (*this, 32)) + , _time_axis_view (new DCPTimeAxisView (*this, 32)) , _tracks (0) , _pixels_per_time_unit (0) , _left_down (false) - , _down_view_start (0) + , _down_view_position (0) , _first_move (false) - , _menu (film, this) + , _menu (this) + , _snap (true) { #ifndef __WXOSX__ SetDoubleBuffered (true); #endif - Connect (wxID_ANY, wxEVT_PAINT, wxPaintEventHandler (Timeline::paint), 0, this); - Connect (wxID_ANY, wxEVT_LEFT_DOWN, wxMouseEventHandler (Timeline::left_down), 0, this); - Connect (wxID_ANY, wxEVT_LEFT_UP, wxMouseEventHandler (Timeline::left_up), 0, this); - Connect (wxID_ANY, wxEVT_RIGHT_DOWN, wxMouseEventHandler (Timeline::right_down), 0, this); - Connect (wxID_ANY, wxEVT_MOTION, wxMouseEventHandler (Timeline::mouse_moved), 0, this); - Connect (wxID_ANY, wxEVT_SIZE, wxSizeEventHandler (Timeline::resized), 0, this); + Bind (wxEVT_PAINT, boost::bind (&DCPTimeline::paint, this)); + Bind (wxEVT_LEFT_DOWN, boost::bind (&DCPTimeline::left_down, this, _1)); + Bind (wxEVT_LEFT_UP, boost::bind (&DCPTimeline::left_up, this, _1)); + Bind (wxEVT_RIGHT_DOWN, boost::bind (&DCPTimeline::right_down, this, _1)); + Bind (wxEVT_MOTION, boost::bind (&DCPTimeline::mouse_moved, this, _1)); + Bind (wxEVT_SIZE, boost::bind (&DCPTimeline::resized, this)); playlist_changed (); SetMinSize (wxSize (640, tracks() * track_height() + 96)); - _playlist_connection = film->playlist()->Changed.connect (bind (&Timeline::playlist_changed, this)); + _playlist_connection = film->playlist()->Changed.connect (bind (&DCPTimeline::playlist_changed, this)); } void -Timeline::paint (wxPaintEvent &) +DCPTimeline::paint () { wxPaintDC dc (this); @@ -369,7 +377,7 @@ Timeline::paint (wxPaintEvent &) } void -Timeline::playlist_changed () +DCPTimeline::playlist_changed () { ensure_ui_thread (); @@ -398,7 +406,7 @@ Timeline::playlist_changed () } void -Timeline::assign_tracks () +DCPTimeline::assign_tracks () { for (ViewList::iterator i = _views.begin(); i != _views.end(); ++i) { shared_ptr cv = dynamic_pointer_cast (*i); @@ -430,8 +438,8 @@ Timeline::assign_tracks () if (test && test->track() == t) { bool const no_overlap = - (acv_content->start() < test_content->start() && acv_content->end() < test_content->start()) || - (acv_content->start() > test_content->end() && acv_content->end() > test_content->end()); + (acv_content->position() < test_content->position() && acv_content->end() < test_content->position()) || + (acv_content->position() > test_content->end() && acv_content->end() > test_content->end()); if (!no_overlap) { /* we have an overlap on track `t' */ @@ -457,16 +465,16 @@ Timeline::assign_tracks () } int -Timeline::tracks () const +DCPTimeline::tracks () const { return _tracks; } void -Timeline::setup_pixels_per_time_unit () +DCPTimeline::setup_pixels_per_time_unit () { shared_ptr film = _film.lock (); - if (!film) { + if (!film || film->length() == 0) { return; } @@ -474,7 +482,7 @@ Timeline::setup_pixels_per_time_unit () } shared_ptr -Timeline::event_to_view (wxMouseEvent& ev) +DCPTimeline::event_to_view (wxMouseEvent& ev) { ViewList::iterator i = _views.begin(); Position const p (ev.GetX(), ev.GetY()); @@ -490,7 +498,7 @@ Timeline::event_to_view (wxMouseEvent& ev) } void -Timeline::left_down (wxMouseEvent& ev) +DCPTimeline::left_down (wxMouseEvent& ev) { shared_ptr view = event_to_view (ev); shared_ptr content_view = dynamic_pointer_cast (view); @@ -499,7 +507,7 @@ Timeline::left_down (wxMouseEvent& ev) if (content_view) { _down_view = content_view; - _down_view_start = content_view->content()->start (); + _down_view_position = content_view->content()->position (); } for (ViewList::iterator i = _views.begin(); i != _views.end(); ++i) { @@ -531,7 +539,7 @@ Timeline::left_down (wxMouseEvent& ev) } void -Timeline::left_up (wxMouseEvent& ev) +DCPTimeline::left_up (wxMouseEvent& ev) { _left_down = false; @@ -539,21 +547,21 @@ Timeline::left_up (wxMouseEvent& ev) _down_view->content()->set_change_signals_frequent (false); } - set_start_from_event (ev); + set_position_from_event (ev); } void -Timeline::mouse_moved (wxMouseEvent& ev) +DCPTimeline::mouse_moved (wxMouseEvent& ev) { if (!_left_down) { return; } - set_start_from_event (ev); + set_position_from_event (ev); } void -Timeline::right_down (wxMouseEvent& ev) +DCPTimeline::right_down (wxMouseEvent& ev) { shared_ptr view = event_to_view (ev); shared_ptr cv = dynamic_pointer_cast (view); @@ -566,15 +574,18 @@ Timeline::right_down (wxMouseEvent& ev) cv->set_selected (true); } - _menu.popup (selected_content (), ev.GetPosition ()); + _menu.popup (_film, selected_content (), ev.GetPosition ()); } void -Timeline::set_start_from_event (wxMouseEvent& ev) +DCPTimeline::set_position_from_event (wxMouseEvent& ev) { wxPoint const p = ev.GetPosition(); if (!_first_move) { + /* We haven't moved yet; in that case, we must move the mouse some reasonable distance + before the drag is considered to have started. + */ int const dist = sqrt (pow (p.x - _down_point.x, 2) + pow (p.y - _down_point.y, 2)); if (dist < 8) { return; @@ -582,36 +593,85 @@ Timeline::set_start_from_event (wxMouseEvent& ev) _first_move = true; } - Time const time_diff = (p.x - _down_point.x) / _pixels_per_time_unit; - if (_down_view) { - _down_view->content()->set_start (max (static_cast