summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2013-05-26 00:21:53 +0100
committerCarl Hetherington <cth@carlh.net>2013-05-26 00:21:53 +0100
commitc77dabbe4e6bb031edf4aa82f5e890fe605bafe1 (patch)
treed3a3f2f34b44eecedabc0240ea82c741b49385ba /src
parent996b0c06e23bcb6b300d7b8799df94993692e07d (diff)
Add unfinished timing tab; fix crash on reconstruction of timeline; fix lack of black / silence at end of films.
Diffstat (limited to 'src')
-rw-r--r--src/lib/content.cc2
-rw-r--r--src/lib/player.cc61
-rw-r--r--src/lib/player.h4
-rw-r--r--src/lib/sndfile_content.cc1
-rw-r--r--src/wx/film_editor.cc54
-rw-r--r--src/wx/film_editor.h8
-rw-r--r--src/wx/timecode.cc90
-rw-r--r--src/wx/timecode.h36
-rw-r--r--src/wx/timeline.cc20
-rw-r--r--src/wx/timeline.h5
-rw-r--r--src/wx/wscript1
11 files changed, 226 insertions, 56 deletions
diff --git a/src/lib/content.cc b/src/lib/content.cc
index ad61f4d6c..aaf2e4f9c 100644
--- a/src/lib/content.cc
+++ b/src/lib/content.cc
@@ -1,5 +1,3 @@
-/* -*- c-basic-offset: 8; default-tab-width: 8; -*- */
-
/*
Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
diff --git a/src/lib/player.cc b/src/lib/player.cc
index ff13f95db..786180a6a 100644
--- a/src/lib/player.cc
+++ b/src/lib/player.cc
@@ -1,5 +1,3 @@
-/* -*- c-basic-offset: 8; default-tab-width: 8; -*- */
-
/*
Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
@@ -103,18 +101,18 @@ Player::pass ()
shared_ptr<Piece> earliest;
for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
- cout << "check " << (*i)->content->file() << " start=" << (*i)->content->start() << ", next=" << (*i)->decoder->next() << ", end=" << (*i)->content->end() << "\n";
+// cout << "check " << (*i)->content->file() << " start=" << (*i)->content->start() << ", next=" << (*i)->decoder->next() << ", end=" << (*i)->content->end() << "\n";
if (((*i)->decoder->next() + (*i)->content->start()) >= (*i)->content->end()) {
continue;
}
- if (!_audio && dynamic_pointer_cast<SndfileContent> ((*i)->content)) {
+ if (!_audio && dynamic_pointer_cast<AudioDecoder> ((*i)->decoder) && !dynamic_pointer_cast<VideoDecoder> ((*i)->decoder)) {
continue;
}
Time const t = (*i)->content->start() + (*i)->decoder->next();
if (t < earliest_t) {
- cout << "\t candidate; " << t << " " << (t / TIME_HZ) << ".\n";
+// cout << "\t candidate; " << t << " " << (t / TIME_HZ) << ".\n";
earliest_t = t;
earliest = *i;
}
@@ -148,8 +146,6 @@ Player::pass ()
void
Player::process_video (weak_ptr<Content> weak_content, shared_ptr<const Image> image, bool same, shared_ptr<Subtitle> sub, Time time)
{
- cout << "[V]\n";
-
shared_ptr<Content> content = weak_content.lock ();
if (!content) {
return;
@@ -208,13 +204,13 @@ Player::seek (Time t)
return;
}
- cout << "seek to " << t << " " << (t / TIME_HZ) << "\n";
+// cout << "seek to " << t << " " << (t / TIME_HZ) << "\n";
for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
Time s = t - (*i)->content->start ();
s = max (static_cast<Time> (0), s);
s = min ((*i)->content->length(), s);
- cout << "seek [" << (*i)->content->file() << "," << (*i)->content->start() << "," << (*i)->content->end() << "] to " << s << "\n";
+// cout << "seek [" << (*i)->content->file() << "," << (*i)->content->start() << "," << (*i)->content->end() << "] to " << s << "\n";
(*i)->decoder->seek (s);
}
@@ -234,6 +230,27 @@ Player::seek_forward ()
}
+void
+Player::add_black_piece (Time s, Time len)
+{
+ shared_ptr<NullContent> nc (new NullContent (_film, s, len));
+ shared_ptr<BlackDecoder> bd (new BlackDecoder (_film, nc));
+ bd->Video.connect (bind (&Player::process_video, this, nc, _1, _2, _3, _4));
+ _pieces.push_back (shared_ptr<Piece> (new Piece (nc, bd)));
+ cout << "\tblack @ " << s << " -- " << (s + len) << "\n";
+}
+
+void
+Player::add_silent_piece (Time s, Time len)
+{
+ shared_ptr<NullContent> nc (new NullContent (_film, s, len));
+ shared_ptr<SilenceDecoder> sd (new SilenceDecoder (_film, nc));
+ sd->Audio.connect (bind (&Player::process_audio, this, nc, _1, _2));
+ _pieces.push_back (shared_ptr<Piece> (new Piece (nc, sd)));
+ cout << "\tsilence @ " << s << " -- " << (s + len) << "\n";
+}
+
+
struct ContentSorter
{
bool operator() (shared_ptr<Content> a, shared_ptr<Content> b)
@@ -245,7 +262,7 @@ struct ContentSorter
void
Player::setup_pieces ()
{
-// cout << "----- Player SETUP PIECES.\n";
+ cout << "----- Player SETUP PIECES.\n";
list<shared_ptr<Piece> > old_pieces = _pieces;
@@ -268,7 +285,7 @@ Player::setup_pieces ()
fd->Audio.connect (bind (&Player::process_audio, this, *i, _1, _2));
decoder = fd;
-// cout << "\tFFmpeg @ " << fc->start() << " -- " << fc->end() << "\n";
+ cout << "\tFFmpeg @ " << fc->start() << " -- " << fc->end() << "\n";
}
shared_ptr<const ImageMagickContent> ic = dynamic_pointer_cast<const ImageMagickContent> (*i);
@@ -289,7 +306,7 @@ Player::setup_pieces ()
}
decoder = id;
-// cout << "\tImageMagick @ " << ic->start() << " -- " << ic->end() << "\n";
+ cout << "\tImageMagick @ " << ic->start() << " -- " << ic->end() << "\n";
}
shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
@@ -298,7 +315,7 @@ Player::setup_pieces ()
sd->Audio.connect (bind (&Player::process_audio, this, *i, _1, _2));
decoder = sd;
-// cout << "\tSndfile @ " << sc->start() << " -- " << sc->end() << "\n";
+ cout << "\tSndfile @ " << sc->start() << " -- " << sc->end() << "\n";
}
_pieces.push_back (shared_ptr<Piece> (new Piece (*i, decoder)));
@@ -313,26 +330,24 @@ Player::setup_pieces ()
if (dynamic_pointer_cast<VideoContent> ((*i)->content)) {
Time const diff = (*i)->content->start() - video_pos;
if (diff > 0) {
- shared_ptr<NullContent> nc (new NullContent (_film, video_pos, diff));
- shared_ptr<BlackDecoder> bd (new BlackDecoder (_film, nc));
- bd->Video.connect (bind (&Player::process_video, this, nc, _1, _2, _3, _4));
- _pieces.push_back (shared_ptr<Piece> (new Piece (nc, bd)));
-// cout << "\tblack @ " << video_pos << " -- " << (video_pos + diff) << "\n";
+ add_black_piece (video_pos, diff);
}
video_pos = (*i)->content->end();
} else {
Time const diff = (*i)->content->start() - audio_pos;
if (diff > 0) {
- shared_ptr<NullContent> nc (new NullContent (_film, audio_pos, diff));
- shared_ptr<SilenceDecoder> sd (new SilenceDecoder (_film, nc));
- sd->Audio.connect (bind (&Player::process_audio, this, nc, _1, _2));
- _pieces.push_back (shared_ptr<Piece> (new Piece (nc, sd)));
-// cout << "\tsilence @ " << audio_pos << " -- " << (audio_pos + diff) << "\n";
+ add_silent_piece (video_pos, diff);
}
audio_pos = (*i)->content->end();
}
}
+
+ if (video_pos < audio_pos) {
+ add_black_piece (video_pos, audio_pos - video_pos);
+ } else if (audio_pos < video_pos) {
+ add_silent_piece (audio_pos, video_pos - audio_pos);
+ }
}
void
diff --git a/src/lib/player.h b/src/lib/player.h
index 4d23d1951..cdedf1676 100644
--- a/src/lib/player.h
+++ b/src/lib/player.h
@@ -68,6 +68,8 @@ private:
void playlist_changed ();
void content_changed (boost::weak_ptr<Content>, int);
void do_seek (Time, bool);
+ void add_black_piece (Time, Time);
+ void add_silent_piece (Time, Time);
boost::shared_ptr<const Film> _film;
boost::shared_ptr<const Playlist> _playlist;
@@ -79,8 +81,6 @@ private:
/** Our pieces are ready to go; if this is false the pieces must be (re-)created before they are used */
bool _have_valid_pieces;
std::list<boost::shared_ptr<Piece> > _pieces;
-
- /** Time of the earliest thing not yet to have been emitted */
Time _position;
AudioBuffers _audio_buffers;
Time _next_audio;
diff --git a/src/lib/sndfile_content.cc b/src/lib/sndfile_content.cc
index 0f895c95e..a80c7dbe5 100644
--- a/src/lib/sndfile_content.cc
+++ b/src/lib/sndfile_content.cc
@@ -120,6 +120,7 @@ SndfileContent::as_xml (xmlpp::Node* node) const
{
node->add_child("Type")->add_child_text ("Sndfile");
Content::as_xml (node);
+ AudioContent::as_xml (node);
node->add_child("AudioChannels")->add_child_text (lexical_cast<string> (_audio_channels));
node->add_child("AudioLength")->add_child_text (lexical_cast<string> (_audio_length));
node->add_child("AudioFrameRate")->add_child_text (lexical_cast<string> (_audio_frame_rate));
diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc
index 36d63b805..b67b47b4e 100644
--- a/src/wx/film_editor.cc
+++ b/src/wx/film_editor.cc
@@ -1,5 +1,3 @@
-/* -*- c-basic-offset: 8; default-tab-width: 8; -*- */
-
/*
Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
@@ -55,6 +53,7 @@
#include "timeline_dialog.h"
#include "audio_mapping_view.h"
#include "container.h"
+#include "timecode.h"
using std::string;
using std::cout;
@@ -230,11 +229,11 @@ void
FilmEditor::make_video_panel ()
{
_video_panel = new wxPanel (_content_notebook);
- _video_sizer = new wxBoxSizer (wxVERTICAL);
- _video_panel->SetSizer (_video_sizer);
+ wxBoxSizer* video_sizer = new wxBoxSizer (wxVERTICAL);
+ _video_panel->SetSizer (video_sizer);
wxGridBagSizer* grid = new wxGridBagSizer (4, 4);
- _video_sizer->Add (grid, 0, wxALL, 8);
+ video_sizer->Add (grid, 0, wxALL, 8);
int r = 0;
add_label_to_grid_bag_sizer (grid, _video_panel, _("Left crop"), wxGBPosition (r, 0));
@@ -336,13 +335,15 @@ FilmEditor::make_content_panel ()
_content_notebook = new wxNotebook (_content_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_LEFT);
_content_sizer->Add (_content_notebook, 1, wxEXPAND | wxTOP, 6);
-
+
make_video_panel ();
_content_notebook->AddPage (_video_panel, _("Video"), false);
make_audio_panel ();
_content_notebook->AddPage (_audio_panel, _("Audio"), false);
make_subtitle_panel ();
_content_notebook->AddPage (_subtitle_panel, _("Subtitles"), false);
+ make_timing_panel ();
+ _content_notebook->AddPage (_timing_panel, _("Timing"), false);
_loop_count->SetRange (2, 1024);
}
@@ -351,11 +352,11 @@ void
FilmEditor::make_audio_panel ()
{
_audio_panel = new wxPanel (_content_notebook);
- _audio_sizer = new wxBoxSizer (wxVERTICAL);
- _audio_panel->SetSizer (_audio_sizer);
+ wxBoxSizer* audio_sizer = new wxBoxSizer (wxVERTICAL);
+ _audio_panel->SetSizer (audio_sizer);
wxFlexGridSizer* grid = new wxFlexGridSizer (3, 4, 4);
- _audio_sizer->Add (grid, 0, wxALL, 8);
+ audio_sizer->Add (grid, 0, wxALL, 8);
_show_audio = new wxButton (_audio_panel, wxID_ANY, _("Show Audio..."));
grid->Add (_show_audio, 1);
@@ -397,7 +398,7 @@ FilmEditor::make_audio_panel ()
grid->AddSpacer (0);
_audio_mapping = new AudioMappingView (_audio_panel);
- _audio_sizer->Add (_audio_mapping, 1, wxEXPAND | wxALL, 6);
+ audio_sizer->Add (_audio_mapping, 1, wxEXPAND | wxALL, 6);
_audio_gain->SetRange (-60, 60);
_audio_delay->SetRange (-1000, 1000);
@@ -407,10 +408,10 @@ void
FilmEditor::make_subtitle_panel ()
{
_subtitle_panel = new wxPanel (_content_notebook);
- _subtitle_sizer = new wxBoxSizer (wxVERTICAL);
- _subtitle_panel->SetSizer (_subtitle_sizer);
+ wxBoxSizer* subtitle_sizer = new wxBoxSizer (wxVERTICAL);
+ _subtitle_panel->SetSizer (subtitle_sizer);
wxFlexGridSizer* grid = new wxFlexGridSizer (2, 4, 4);
- _subtitle_sizer->Add (grid, 0, wxALL, 8);
+ subtitle_sizer->Add (grid, 0, wxALL, 8);
_with_subtitles = new wxCheckBox (_subtitle_panel, wxID_ANY, _("With Subtitles"));
grid->Add (_with_subtitles, 1);
@@ -443,6 +444,24 @@ FilmEditor::make_subtitle_panel ()
_subtitle_scale->SetRange (1, 1000);
}
+void
+FilmEditor::make_timing_panel ()
+{
+ _timing_panel = new wxPanel (_content_notebook);
+ wxBoxSizer* timing_sizer = new wxBoxSizer (wxVERTICAL);
+ _timing_panel->SetSizer (timing_sizer);
+ wxFlexGridSizer* grid = new wxFlexGridSizer (2, 4, 4);
+ timing_sizer->Add (grid, 0, wxALL, 8);
+
+ add_label_to_sizer (grid, _timing_panel, _("Start time"));
+ _start = new Timecode (_timing_panel);
+ grid->Add (_start);
+ add_label_to_sizer (grid, _timing_panel, _("Length"));
+ _length = new Timecode (_timing_panel);
+ grid->Add (_length);
+}
+
+
/** Called when the left crop widget has been changed */
void
FilmEditor::left_crop_changed (wxCommandEvent &)
@@ -666,7 +685,13 @@ FilmEditor::film_content_changed (weak_ptr<Content> weak_content, int property)
ffmpeg_content = dynamic_pointer_cast<FFmpegContent> (content);
}
- if (property == VideoContentProperty::VIDEO_CROP) {
+ if (property == ContentProperty::START) {
+ if (content) {
+ _start->set (content->start (), _film->dcp_video_frame_rate ());
+ } else {
+ _start->set (0, 24);
+ }
+ } else if (property == VideoContentProperty::VIDEO_CROP) {
checked_set (_left_crop, video_content ? video_content->crop().left : 0);
checked_set (_right_crop, video_content ? video_content->crop().right : 0);
checked_set (_top_crop, video_content ? video_content->crop().top : 0);
@@ -817,6 +842,7 @@ FilmEditor::set_film (shared_ptr<Film> f)
film_changed (Film::DCI_METADATA);
film_changed (Film::DCP_VIDEO_FRAME_RATE);
+ film_content_changed (boost::shared_ptr<Content> (), ContentProperty::START);
film_content_changed (boost::shared_ptr<Content> (), VideoContentProperty::VIDEO_CROP);
film_content_changed (boost::shared_ptr<Content> (), AudioContentProperty::AUDIO_GAIN);
film_content_changed (boost::shared_ptr<Content> (), AudioContentProperty::AUDIO_DELAY);
diff --git a/src/wx/film_editor.h b/src/wx/film_editor.h
index 89065c97d..b169aee7f 100644
--- a/src/wx/film_editor.h
+++ b/src/wx/film_editor.h
@@ -36,6 +36,7 @@ class AudioDialog;
class TimelineDialog;
class AudioMappingView;
class Format;
+class Timecode;
/** @class FilmEditor
* @brief A wx widget to edit a film's metadata, and perform various functions.
@@ -55,6 +56,7 @@ private:
void make_video_panel ();
void make_audio_panel ();
void make_subtitle_panel ();
+ void make_timing_panel ();
void connect_to_widgets ();
/* Handle changes to the view */
@@ -120,11 +122,9 @@ private:
wxPanel* _content_panel;
wxSizer* _content_sizer;
wxPanel* _video_panel;
- wxSizer* _video_sizer;
wxPanel* _audio_panel;
- wxSizer* _audio_sizer;
wxPanel* _subtitle_panel;
- wxSizer* _subtitle_sizer;
+ wxPanel* _timing_panel;
/** The film we are editing */
boost::shared_ptr<Film> _film;
@@ -167,6 +167,8 @@ private:
wxStaticText* _audio_description;
wxChoice* _subtitle_stream;
AudioMappingView* _audio_mapping;
+ Timecode* _start;
+ Timecode* _length;
std::vector<Format const *> _formats;
diff --git a/src/wx/timecode.cc b/src/wx/timecode.cc
new file mode 100644
index 000000000..460f7423b
--- /dev/null
+++ b/src/wx/timecode.cc
@@ -0,0 +1,90 @@
+/*
+ Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+
+ This program 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,
+ 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.
+
+*/
+
+#include <boost/lexical_cast.hpp>
+#include "timecode.h"
+#include "wx_util.h"
+
+using std::string;
+using boost::lexical_cast;
+
+Timecode::Timecode (wxWindow* parent)
+ : wxPanel (parent)
+{
+ wxClientDC dc (parent);
+ wxSize size = dc.GetTextExtent (wxT ("9999"));
+ size.SetHeight (-1);
+
+ wxTextValidator validator (wxFILTER_INCLUDE_CHAR_LIST);
+ wxArrayString list;
+
+ string n = "0123456789";
+ for (size_t i = 0; i < n.length(); ++i) {
+ list.Add (n[i]);
+ }
+
+ validator.SetIncludes (list);
+
+ wxBoxSizer* sizer = new wxBoxSizer (wxHORIZONTAL);
+ _hours = new wxTextCtrl (this, wxID_ANY, wxT(""), wxDefaultPosition, size, 0, validator);
+ _hours->SetMaxLength (2);
+ sizer->Add (_hours);
+ add_label_to_sizer (sizer, this, ":");
+ _minutes = new wxTextCtrl (this, wxID_ANY, wxT(""), wxDefaultPosition, size);
+ _minutes->SetMaxLength (2);
+ sizer->Add (_minutes);
+ add_label_to_sizer (sizer, this, ":");
+ _seconds = new wxTextCtrl (this, wxID_ANY, wxT(""), wxDefaultPosition, size);
+ _seconds->SetMaxLength (2);
+ sizer->Add (_seconds);
+ add_label_to_sizer (sizer, this, ".");
+ _frames = new wxTextCtrl (this, wxID_ANY, wxT(""), wxDefaultPosition, size);
+ _frames->SetMaxLength (2);
+ sizer->Add (_frames);
+
+ SetSizerAndFit (sizer);
+}
+
+void
+Timecode::set (Time t, int fps)
+{
+ int const h = t / (3600 * TIME_HZ);
+ t -= h * 3600 * TIME_HZ;
+ int const m = t / (60 * TIME_HZ);
+ t -= m * 60 * TIME_HZ;
+ int const s = t / TIME_HZ;
+ t -= s * TIME_HZ;
+ int const f = t * fps / TIME_HZ;
+
+ _hours->SetValue (wxString::Format ("%02d", h));
+ _minutes->SetValue (wxString::Format ("%02d", m));
+ _seconds->SetValue (wxString::Format ("%02d", s));
+ _frames->SetValue (wxString::Format ("%02d", f));
+}
+
+Time
+Timecode::get (int fps) const
+{
+ Time t = 0;
+ t += lexical_cast<int> (wx_to_std (_hours->GetValue())) * 3600 * TIME_HZ;
+ t += lexical_cast<int> (wx_to_std (_minutes->GetValue())) * 60 * TIME_HZ;
+ t += lexical_cast<int> (wx_to_std (_seconds->GetValue())) * TIME_HZ;
+ t += lexical_cast<int> (wx_to_std (_frames->GetValue())) * TIME_HZ / fps;
+ return t;
+}
diff --git a/src/wx/timecode.h b/src/wx/timecode.h
new file mode 100644
index 000000000..f243ee0b8
--- /dev/null
+++ b/src/wx/timecode.h
@@ -0,0 +1,36 @@
+/*
+ Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+
+ This program 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,
+ 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.
+
+*/
+
+#include <wx/wx.h>
+#include "lib/types.h"
+
+class Timecode : public wxPanel
+{
+public:
+ Timecode (wxWindow *);
+
+ void set (Time, int);
+ Time get (int) const;
+
+private:
+ wxTextCtrl* _hours;
+ wxTextCtrl* _minutes;
+ wxTextCtrl* _seconds;
+ wxTextCtrl* _frames;
+};
diff --git a/src/wx/timeline.cc b/src/wx/timeline.cc
index 96bd2ccd4..8c90c3d8c 100644
--- a/src/wx/timeline.cc
+++ b/src/wx/timeline.cc
@@ -1,5 +1,3 @@
-/* -*- c-basic-offset: 8; default-tab-width: 8; -*- */
-
/*
Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
@@ -81,7 +79,7 @@ public:
, _track (t)
, _selected (false)
{
- c->Changed.connect (bind (&ContentView::content_changed, this, _2));
+ _content_connection = c->Changed.connect (bind (&ContentView::content_changed, this, _2));
}
Rect bbox () const
@@ -150,11 +148,11 @@ private:
#endif
wxGraphicsPath path = gc->CreatePath ();
- path.MoveToPoint (time_x (start), y_pos (_track));
- path.AddLineToPoint (time_x (start + len), y_pos (_track));
- path.AddLineToPoint (time_x (start + len), y_pos (_track + 1));
- path.AddLineToPoint (time_x (start), y_pos (_track + 1));
- path.AddLineToPoint (time_x (start), y_pos (_track));
+ 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);
gc->StrokePath (path);
gc->FillPath (path);
@@ -185,6 +183,8 @@ private:
boost::weak_ptr<Content> _content;
int _track;
bool _selected;
+
+ boost::signals2::scoped_connection _content_connection;
};
class AudioContentView : public ContentView
@@ -326,7 +326,7 @@ Timeline::Timeline (wxWindow* parent, shared_ptr<const Film> film)
playlist_changed ();
- film->playlist()->Changed.connect (bind (&Timeline::playlist_changed, this));
+ _playlist_connection = film->playlist()->Changed.connect (bind (&Timeline::playlist_changed, this));
}
void
@@ -452,7 +452,7 @@ Timeline::mouse_moved (wxMouseEvent& ev)
if (_down_view) {
shared_ptr<Content> c = _down_view->content().lock();
if (c) {
- c->set_start (_down_view_start + time_diff);
+ c->set_start (max (static_cast<Time> (0), _down_view_start + time_diff));
}
}
}
diff --git a/src/wx/timeline.h b/src/wx/timeline.h
index 79ceceaa0..52b29de86 100644
--- a/src/wx/timeline.h
+++ b/src/wx/timeline.h
@@ -1,5 +1,3 @@
-/* -*- c-basic-offset: 8; default-tab-width: 8; -*- */
-
/*
Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
@@ -21,6 +19,7 @@
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
+#include <boost/signals2.hpp>
#include <wx/wx.h>
#include "util.h"
@@ -76,4 +75,6 @@ private:
boost::shared_ptr<ContentView> _down_view;
Time _down_view_start;
bool _first_move;
+
+ boost::signals2::scoped_connection _playlist_connection;
};
diff --git a/src/wx/wscript b/src/wx/wscript
index 884eabc3a..d915f5899 100644
--- a/src/wx/wscript
+++ b/src/wx/wscript
@@ -21,6 +21,7 @@ sources = """
new_film_dialog.cc
properties_dialog.cc
server_dialog.cc
+ timecode.cc
timeline.cc
timeline_dialog.cc
wx_util.cc