diff options
| author | Carl Hetherington <cth@carlh.net> | 2013-10-10 15:00:41 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2013-10-10 15:00:41 +0100 |
| commit | b3d598f551a874b34ff4fb51a0a65631fc3ad070 (patch) | |
| tree | 60fb477fb709e852914b185b7b9ff7f49555a3eb /src | |
| parent | 895751dcac8caeb03e8af8ba286b4297f8f85e0b (diff) | |
Basic snapping in the timeline.
Diffstat (limited to 'src')
| -rw-r--r-- | src/wx/timeline.cc | 57 | ||||
| -rw-r--r-- | src/wx/timeline.h | 9 | ||||
| -rw-r--r-- | src/wx/timeline_dialog.cc | 16 | ||||
| -rw-r--r-- | src/wx/timeline_dialog.h | 3 |
4 files changed, 82 insertions, 3 deletions
diff --git a/src/wx/timeline.cc b/src/wx/timeline.cc index 87070b35e..1f0aee4e8 100644 --- a/src/wx/timeline.cc +++ b/src/wx/timeline.cc @@ -33,7 +33,9 @@ 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: @@ -332,6 +334,7 @@ Timeline::Timeline (wxWindow* parent, FilmEditor* ed, shared_ptr<Film> film) , _down_view_position (0) , _first_move (false) , _menu (film, this) + , _snap (true) { #ifndef __WXOSX__ SetDoubleBuffered (true); @@ -577,6 +580,9 @@ Timeline::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; @@ -584,9 +590,56 @@ Timeline::set_position_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_position (max (static_cast<Time> (0), _down_view_position + time_diff)); + Time new_position = _down_view_position + (p.x - _down_point.x) / _pixels_per_time_unit; + + if (_snap) { + + bool first = true; + Time nearest_distance = TIME_MAX; + Time nearest_new_position = TIME_MAX; + + /* Find the nearest content edge; this is inefficient */ + for (ViewList::iterator i = _views.begin(); i != _views.end(); ++i) { + shared_ptr<ContentView> cv = dynamic_pointer_cast<ContentView> (*i); + if (!cv || cv == _down_view) { + continue; + } + + { + /* Snap starts to ends */ + Time const d = abs (cv->content()->end() - new_position); + if (first || d < nearest_distance) { + nearest_distance = d; + nearest_new_position = cv->content()->end(); + } + } + + { + /* Snap ends to starts */ + Time const d = abs (cv->content()->position() - (new_position + _down_view->content()->length_after_trim())); + if (d < nearest_distance) { + nearest_distance = d; + nearest_new_position = cv->content()->position() - _down_view->content()->length_after_trim (); + } + } + + first = false; + } + + if (!first) { + /* Snap if it's close; `close' means within a proportion of the time on the timeline */ + if (nearest_distance < (width() / pixels_per_time_unit()) / 32) { + new_position = nearest_new_position; + } + } + } + + if (new_position < 0) { + new_position = 0; + } + + _down_view->content()->set_position (new_position); shared_ptr<Film> film = _film.lock (); assert (film); diff --git a/src/wx/timeline.h b/src/wx/timeline.h index 0217373b9..ef1d10797 100644 --- a/src/wx/timeline.h +++ b/src/wx/timeline.h @@ -64,6 +64,14 @@ public: void setup_pixels_per_time_unit (); + void set_snap (bool s) { + _snap = s; + } + + bool snap () const { + return _snap; + } + private: void paint (); void left_down (wxMouseEvent &); @@ -95,6 +103,7 @@ private: Time _down_view_position; bool _first_move; ContentMenu _menu; + bool _snap; boost::signals2::scoped_connection _playlist_connection; }; diff --git a/src/wx/timeline_dialog.cc b/src/wx/timeline_dialog.cc index 9493d0acb..dbf7ae232 100644 --- a/src/wx/timeline_dialog.cc +++ b/src/wx/timeline_dialog.cc @@ -33,10 +33,24 @@ TimelineDialog::TimelineDialog (FilmEditor* ed, shared_ptr<Film> film) , _timeline (this, ed, film) { wxBoxSizer* sizer = new wxBoxSizer (wxVERTICAL); - + + wxBoxSizer* controls = new wxBoxSizer (wxHORIZONTAL); + _snap = new wxCheckBox (this, wxID_ANY, _("Snap")); + controls->Add (_snap); + + sizer->Add (controls, 0, wxALL, 12); sizer->Add (&_timeline, 1, wxEXPAND | wxALL, 12); SetSizer (sizer); sizer->Layout (); sizer->SetSizeHints (this); + + _snap->SetValue (_timeline.snap ()); + _snap->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&TimelineDialog::snap_toggled, this)); +} + +void +TimelineDialog::snap_toggled () +{ + _timeline.set_snap (_snap->GetValue ()); } diff --git a/src/wx/timeline_dialog.h b/src/wx/timeline_dialog.h index 17ca22c49..1e5955003 100644 --- a/src/wx/timeline_dialog.h +++ b/src/wx/timeline_dialog.h @@ -30,5 +30,8 @@ public: TimelineDialog (FilmEditor *, boost::shared_ptr<Film>); private: + void snap_toggled (); + Timeline _timeline; + wxCheckBox* _snap; }; |
