-/** 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)
- : _timeline (t)
- {
-
- }
-
- virtual ~View () {}
-
- void paint (wxGraphicsContext* g)
- {
- _last_paint_bbox = bbox ();
- do_paint (g);
- }
-
- void force_redraw ()
- {
- _timeline.force_redraw (_last_paint_bbox);
- _timeline.force_redraw (bbox ());
- }
-
- virtual dcpomatic::Rect<int> bbox () const = 0;
-
-protected:
- virtual void do_paint (wxGraphicsContext *) = 0;
-
- int time_x (DCPTime t) const
- {
- return _timeline.tracks_position().x + t.seconds() * _timeline.pixels_per_second ();
- }
-
- Timeline& _timeline;
-
-private:
- dcpomatic::Rect<int> _last_paint_bbox;
-};
-
-
-/** Parent class for views of pieces of content */
-class ContentView : public View
-{
-public:
- ContentView (Timeline& tl, shared_ptr<Content> c)
- : View (tl)
- , _content (c)
- , _track (0)
- , _selected (false)
- {
- _content_connection = c->Changed.connect (bind (&ContentView::content_changed, this, _2, _3));
- }
-
- dcpomatic::Rect<int> bbox () const
- {
- shared_ptr<const Film> film = _timeline.film ();
- shared_ptr<const Content> content = _content.lock ();
- if (!film || !content) {
- return dcpomatic::Rect<int> ();
- }
-
- return dcpomatic::Rect<int> (
- time_x (content->position ()) - 8,
- y_pos (_track) - 8,
- content->length_after_trim().seconds() * _timeline.pixels_per_second() + 16,
- _timeline.track_height() + 16
- );
- }
-
- void set_selected (bool s) {
- _selected = s;
- force_redraw ();
- }
-
- bool selected () const {
- return _selected;
- }
-
- shared_ptr<Content> content () const {
- return _content.lock ();
- }
-
- void set_track (int t) {
- _track = t;
- }
-
- int track () const {
- return _track;
- }
-
- virtual wxString type () const = 0;
- virtual wxColour colour () const = 0;
-
-private:
-
- void do_paint (wxGraphicsContext* gc)
- {
- shared_ptr<const Film> film = _timeline.film ();
- shared_ptr<const Content> cont = content ();
- if (!film || !cont) {
- return;
- }
-
- DCPTime const position = cont->position ();
- DCPTime const len = cont->length_after_trim ();
-
- wxColour selected (colour().Red() / 2, colour().Green() / 2, colour().Blue() / 2);
-
- gc->SetPen (*wxBLACK_PEN);
-
- gc->SetPen (*wxThePenList->FindOrCreatePen (wxColour (0, 0, 0), 4, wxPENSTYLE_SOLID));
- if (_selected) {
- gc->SetBrush (*wxTheBrushList->FindOrCreateBrush (selected, wxBRUSHSTYLE_SOLID));
- } else {
- gc->SetBrush (*wxTheBrushList->FindOrCreateBrush (colour(), wxBRUSHSTYLE_SOLID));
- }
-
- wxGraphicsPath path = gc->CreatePath ();
- 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_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 (position), y_pos (_track), len.seconds() * _timeline.pixels_per_second(), _timeline.track_height()));
- gc->DrawText (name, time_x (position) + 12, y_pos (_track + 1) - name_height - 4);
- gc->ResetClip ();
- }
-
- int y_pos (int t) const
- {
- return _timeline.tracks_position().y + t * _timeline.track_height();
- }
-
- void content_changed (int p, bool frequent)
- {
- ensure_ui_thread ();
-
- if (p == ContentProperty::POSITION || p == ContentProperty::LENGTH) {
- force_redraw ();
- }
-
- if (!frequent) {
- _timeline.setup_pixels_per_second ();
- _timeline.Refresh ();
- }
- }
-
- boost::weak_ptr<Content> _content;
- int _track;
- bool _selected;
-
- boost::signals2::scoped_connection _content_connection;
-};
-
-class AudioContentView : public ContentView
-{
-public:
- AudioContentView (Timeline& tl, shared_ptr<Content> c)
- : ContentView (tl, c)
- {}
-
-private:
- wxString type () const
- {
- return _("audio");
- }
-
- wxColour colour () const
- {
- return wxColour (149, 121, 232, 255);
- }
-};
-
-class VideoContentView : public ContentView
-{
-public:
- VideoContentView (Timeline& tl, shared_ptr<Content> c)
- : ContentView (tl, c)
- {}
-
-private:
-
- wxString type () const
- {
- if (dynamic_pointer_cast<FFmpegContent> (content ())) {
- return _("video");
- } else {
- return _("still");
- }
- }
-
- wxColour colour () const
- {
- return wxColour (242, 92, 120, 255);
- }
-};
-
-class TimeAxisView : public View
-{
-public:
- TimeAxisView (Timeline& tl, int y)
- : View (tl)
- , _y (y)
- {}
-
- dcpomatic::Rect<int> bbox () const
- {
- return dcpomatic::Rect<int> (0, _y - 4, _timeline.width(), 24);
- }
-
- void set_y (int y)
- {
- _y = y;
- force_redraw ();
- }
-
-private:
-
- void do_paint (wxGraphicsContext* gc)
- {
- gc->SetPen (*wxThePenList->FindOrCreatePen (wxColour (0, 0, 0), 1, wxPENSTYLE_SOLID));
-
- double mark_interval = rint (128 / _timeline.pixels_per_second ());
- if (mark_interval > 5) {
- mark_interval -= int (rint (mark_interval)) % 5;
- }
- if (mark_interval > 10) {
- mark_interval -= int (rint (mark_interval)) % 10;
- }
- if (mark_interval > 60) {
- mark_interval -= int (rint (mark_interval)) % 60;
- }
- if (mark_interval > 3600) {
- mark_interval -= int (rint (mark_interval)) % 3600;
- }
-
- if (mark_interval < 1) {
- mark_interval = 1;
- }
-
- wxGraphicsPath path = gc->CreatePath ();
- path.MoveToPoint (_timeline.x_offset(), _y);
- path.AddLineToPoint (_timeline.width(), _y);
- gc->StrokePath (path);
-
- /* Time in seconds */
- DCPTime t;
- while ((t.seconds() * _timeline.pixels_per_second()) < _timeline.width()) {
- wxGraphicsPath path = gc->CreatePath ();
- path.MoveToPoint (time_x (t), _y - 4);
- path.AddLineToPoint (time_x (t), _y + 4);
- gc->StrokePath (path);
-
- double tc = t.seconds ();
- int const h = tc / 3600;
- tc -= h * 3600;
- int const m = tc / 60;
- tc -= m * 60;
- int const s = tc;
-
- wxString str = wxString::Format (wxT ("%02d:%02d:%02d"), h, m, s);
- wxDouble str_width;
- wxDouble str_height;
- wxDouble str_descent;
- wxDouble str_leading;
- gc->GetTextExtent (str, &str_width, &str_height, &str_descent, &str_leading);
-
- int const tx = _timeline.x_offset() + t.seconds() * _timeline.pixels_per_second();
- if ((tx + str_width) < _timeline.width()) {
- gc->DrawText (str, time_x (t), _y + 16);
- }
-
- t += DCPTime::from_seconds (mark_interval);
- }
- }
-
-private:
- int _y;
-};
-
-
-Timeline::Timeline (wxWindow* parent, FilmEditor* ed, shared_ptr<Film> film)