summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2013-10-10 15:00:41 +0100
committerCarl Hetherington <cth@carlh.net>2013-10-10 15:00:41 +0100
commitb3d598f551a874b34ff4fb51a0a65631fc3ad070 (patch)
tree60fb477fb709e852914b185b7b9ff7f49555a3eb /src
parent895751dcac8caeb03e8af8ba286b4297f8f85e0b (diff)
Basic snapping in the timeline.
Diffstat (limited to 'src')
-rw-r--r--src/wx/timeline.cc57
-rw-r--r--src/wx/timeline.h9
-rw-r--r--src/wx/timeline_dialog.cc16
-rw-r--r--src/wx/timeline_dialog.h3
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;
};