return boost::optional<int> ();
}
- return libdcp::raw_convert<int> (number);
+ return dcp::raw_convert<int> (number);
}
};
#define DCPOMATIC_RECT_H
#include "position.h"
+#include <algorithm>
/* Put this inside a namespace as Apple put a Rect in the global namespace */
#include "lib/image_content.h"
#include "film_editor.h"
#include "timeline.h"
+#include "timeline_time_axis_view.h"
+#include "timeline_video_content_view.h"
+#include "timeline_audio_content_view.h"
+#include "timeline_subtitle_content_view.h"
#include "content_panel.h"
#include "wx_util.h"
using boost::bind;
using boost::optional;
-/** @class View
- * @brief 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().get_value_or (0);
- }
-
- Timeline& _timeline;
-
-private:
- dcpomatic::Rect<int> _last_paint_bbox;
-};
-
-
-/** @class ContentView
- * @brief Parent class for views of pieces of content.
- */
-class ContentView : public View
-{
-public:
- ContentView (Timeline& tl, shared_ptr<Content> c)
- : View (tl)
- , _content (c)
- , _selected (false)
- {
- _content_connection = c->Changed.connect (bind (&ContentView::content_changed, this, _2, _3));
- }
-
- dcpomatic::Rect<int> bbox () const
- {
- DCPOMATIC_ASSERT (_track);
-
- 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.get()) - 8,
- content->length_after_trim().seconds() * _timeline.pixels_per_second().get_value_or(0) + 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;
- }
-
- void unset_track () {
- _track = boost::optional<int> ();
- }
-
- optional<int> track () const {
- return _track;
- }
-
- virtual wxString type () const = 0;
- virtual wxColour background_colour () const = 0;
- virtual wxColour foreground_colour () const = 0;
-
-private:
-
- void do_paint (wxGraphicsContext* gc)
- {
- DCPOMATIC_ASSERT (_track);
-
- 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 (background_colour().Red() / 2, background_colour().Green() / 2, background_colour().Blue() / 2);
-
- gc->SetPen (*wxThePenList->FindOrCreatePen (foreground_colour(), 4, wxPENSTYLE_SOLID));
- if (_selected) {
- gc->SetBrush (*wxTheBrushList->FindOrCreateBrush (selected, wxBRUSHSTYLE_SOLID));
- } else {
- gc->SetBrush (*wxTheBrushList->FindOrCreateBrush (background_colour(), wxBRUSHSTYLE_SOLID));
- }
-
- wxGraphicsPath path = gc->CreatePath ();
- path.MoveToPoint (time_x (position), y_pos (_track.get()) + 4);
- path.AddLineToPoint (time_x (position + len), y_pos (_track.get()) + 4);
- path.AddLineToPoint (time_x (position + len), y_pos (_track.get() + 1) - 4);
- path.AddLineToPoint (time_x (position), y_pos (_track.get() + 1) - 4);
- path.AddLineToPoint (time_x (position), y_pos (_track.get()) + 4);
- gc->StrokePath (path);
- gc->FillPath (path);
-
- wxString name = wxString::Format (wxT ("%s [%s]"), std_to_wx (cont->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.get()), len.seconds() * _timeline.pixels_per_second().get_value_or(0), _timeline.track_height()));
- gc->SetFont (gc->CreateFont (*wxNORMAL_FONT, foreground_colour ()));
- gc->DrawText (name, time_x (position) + 12, y_pos (_track.get() + 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;
- optional<int> _track;
- bool _selected;
-
- boost::signals2::scoped_connection _content_connection;
-};
-
-/** @class AudioContentView
- * @brief Timeline view for AudioContent.
- */
-class AudioContentView : public ContentView
-{
-public:
- AudioContentView (Timeline& tl, shared_ptr<Content> c)
- : ContentView (tl, c)
- {}
-
-private:
- wxString type () const
- {
- return _("audio");
- }
-
- wxColour background_colour () const
- {
- return wxColour (149, 121, 232, 255);
- }
-
- wxColour foreground_colour () const
- {
- return wxColour (0, 0, 0, 255);
- }
-};
-
-/** @class AudioContentView
- * @brief Timeline view for VideoContent.
- */
-class VideoContentView : public ContentView
-{
-public:
- VideoContentView (Timeline& tl, shared_ptr<Content> c)
- : ContentView (tl, c)
- {}
-
-private:
-
- wxString type () const
- {
- if (dynamic_pointer_cast<ImageContent> (content ()) && content()->number_of_paths() == 1) {
- return _("still");
- } else {
- return _("video");
- }
- }
-
- wxColour background_colour () const
- {
- return wxColour (242, 92, 120, 255);
- }
-
- wxColour foreground_colour () const
- {
- return wxColour (0, 0, 0, 255);
- }
-};
-
-/** @class AudioContentView
- * @brief Timeline view for SubtitleContent.
- */
-class SubtitleContentView : public ContentView
-{
-public:
- SubtitleContentView (Timeline& tl, shared_ptr<SubtitleContent> c)
- : ContentView (tl, c)
- , _subtitle_content (c)
- {}
-
-private:
- wxString type () const
- {
- return _("subtitles");
- }
-
- wxColour background_colour () const
- {
- shared_ptr<SubtitleContent> sc = _subtitle_content.lock ();
- if (!sc || !sc->use_subtitles ()) {
- return wxColour (210, 210, 210, 128);
- }
-
- return wxColour (163, 255, 154, 255);
- }
-
- wxColour foreground_colour () const
- {
- shared_ptr<SubtitleContent> sc = _subtitle_content.lock ();
- if (!sc || !sc->use_subtitles ()) {
- return wxColour (180, 180, 180, 128);
- }
-
- return wxColour (0, 0, 0, 255);
- }
-
- boost::weak_ptr<SubtitleContent> _subtitle_content;
-};
-
-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)
- {
- if (!_timeline.pixels_per_second()) {
- return;
- }
-
- double const pps = _timeline.pixels_per_second().get ();
-
- gc->SetPen (*wxThePenList->FindOrCreatePen (wxColour (0, 0, 0), 1, wxPENSTYLE_SOLID));
-
- double mark_interval = rint (128 / pps);
- 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);
-
- gc->SetFont (gc->CreateFont (*wxNORMAL_FONT));
-
- /* Time in seconds */
- DCPTime t;
- while ((t.seconds() * pps) < _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() * pps;
- 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, ContentPanel* cp, shared_ptr<Film> film)
: wxPanel (parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE)
, _content_panel (cp)
, _film (film)
- , _time_axis_view (new TimeAxisView (*this, 32))
+ , _time_axis_view (new TimelineTimeAxisView (*this, 32))
, _tracks (0)
, _left_down (false)
, _down_view_position (0)
return;
}
- for (ViewList::iterator i = _views.begin(); i != _views.end(); ++i) {
+ for (TimelineViewList::iterator i = _views.begin(); i != _views.end(); ++i) {
(*i)->paint (gc);
}
for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
if (dynamic_pointer_cast<VideoContent> (*i)) {
- _views.push_back (shared_ptr<View> (new VideoContentView (*this, *i)));
+ _views.push_back (shared_ptr<TimelineView> (new TimelineVideoContentView (*this, *i)));
}
if (dynamic_pointer_cast<AudioContent> (*i)) {
- _views.push_back (shared_ptr<View> (new AudioContentView (*this, *i)));
+ _views.push_back (shared_ptr<TimelineView> (new TimelineAudioContentView (*this, *i)));
}
shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (*i);
if (sc && sc->has_subtitles ()) {
- _views.push_back (shared_ptr<View> (new SubtitleContentView (*this, sc)));
+ _views.push_back (shared_ptr<TimelineView> (new TimelineSubtitleContentView (*this, sc)));
}
}
void
Timeline::assign_tracks ()
{
- for (ViewList::iterator i = _views.begin(); i != _views.end(); ++i) {
- shared_ptr<ContentView> c = dynamic_pointer_cast<ContentView> (*i);
+ for (TimelineViewList::iterator i = _views.begin(); i != _views.end(); ++i) {
+ shared_ptr<TimelineContentView> c = dynamic_pointer_cast<TimelineContentView> (*i);
if (c) {
c->unset_track ();
}
}
- for (ViewList::iterator i = _views.begin(); i != _views.end(); ++i) {
- shared_ptr<ContentView> cv = dynamic_pointer_cast<ContentView> (*i);
+ for (TimelineViewList::iterator i = _views.begin(); i != _views.end(); ++i) {
+ shared_ptr<TimelineContentView> cv = dynamic_pointer_cast<TimelineContentView> (*i);
if (!cv) {
continue;
}
int t = 0;
while (true) {
- ViewList::iterator j = _views.begin();
+ TimelineViewList::iterator j = _views.begin();
while (j != _views.end()) {
- shared_ptr<ContentView> test = dynamic_pointer_cast<ContentView> (*j);
+ shared_ptr<TimelineContentView> test = dynamic_pointer_cast<TimelineContentView> (*j);
if (!test) {
++j;
continue;
_pixels_per_second = static_cast<double>(width() - x_offset() * 2) / film->length().seconds ();
}
-shared_ptr<View>
+shared_ptr<TimelineView>
Timeline::event_to_view (wxMouseEvent& ev)
{
- ViewList::iterator i = _views.begin();
+ TimelineViewList::iterator i = _views.begin();
Position<int> const p (ev.GetX(), ev.GetY());
while (i != _views.end() && !(*i)->bbox().contains (p)) {
++i;
}
if (i == _views.end ()) {
- return shared_ptr<View> ();
+ return shared_ptr<TimelineView> ();
}
return *i;
void
Timeline::left_down (wxMouseEvent& ev)
{
- shared_ptr<View> view = event_to_view (ev);
- shared_ptr<ContentView> content_view = dynamic_pointer_cast<ContentView> (view);
+ shared_ptr<TimelineView> view = event_to_view (ev);
+ shared_ptr<TimelineContentView> content_view = dynamic_pointer_cast<TimelineContentView> (view);
_down_view.reset ();
_down_view_position = content_view->content()->position ();
}
- for (ViewList::iterator i = _views.begin(); i != _views.end(); ++i) {
- shared_ptr<ContentView> cv = dynamic_pointer_cast<ContentView> (*i);
+ for (TimelineViewList::iterator i = _views.begin(); i != _views.end(); ++i) {
+ shared_ptr<TimelineContentView> cv = dynamic_pointer_cast<TimelineContentView> (*i);
if (!cv) {
continue;
}
void
Timeline::right_down (wxMouseEvent& ev)
{
- shared_ptr<View> view = event_to_view (ev);
- shared_ptr<ContentView> cv = dynamic_pointer_cast<ContentView> (view);
+ shared_ptr<TimelineView> view = event_to_view (ev);
+ shared_ptr<TimelineContentView> cv = dynamic_pointer_cast<TimelineContentView> (view);
if (!cv) {
return;
}
optional<DCPTime> nearest_distance;
/* 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);
+ for (TimelineViewList::iterator i = _views.begin(); i != _views.end(); ++i) {
+ shared_ptr<TimelineContentView> cv = dynamic_pointer_cast<TimelineContentView> (*i);
if (!cv || cv == _down_view) {
continue;
}
void
Timeline::clear_selection ()
{
- for (ViewList::iterator i = _views.begin(); i != _views.end(); ++i) {
- shared_ptr<ContentView> cv = dynamic_pointer_cast<ContentView> (*i);
+ for (TimelineViewList::iterator i = _views.begin(); i != _views.end(); ++i) {
+ shared_ptr<TimelineContentView> cv = dynamic_pointer_cast<TimelineContentView> (*i);
if (cv) {
cv->set_selected (false);
}
}
}
-Timeline::ContentViewList
+TimelineContentViewList
Timeline::selected_views () const
{
- ContentViewList sel;
+ TimelineContentViewList sel;
- for (ViewList::const_iterator i = _views.begin(); i != _views.end(); ++i) {
- shared_ptr<ContentView> cv = dynamic_pointer_cast<ContentView> (*i);
+ for (TimelineViewList::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+ shared_ptr<TimelineContentView> cv = dynamic_pointer_cast<TimelineContentView> (*i);
if (cv && cv->selected()) {
sel.push_back (cv);
}
Timeline::selected_content () const
{
ContentList sel;
- ContentViewList views = selected_views ();
+ TimelineContentViewList views = selected_views ();
- for (ContentViewList::const_iterator i = views.begin(); i != views.end(); ++i) {
+ for (TimelineContentViewList::const_iterator i = views.begin(); i != views.end(); ++i) {
sel.push_back ((*i)->content ());
}
#include "lib/util.h"
#include "lib/rect.h"
#include "content_menu.h"
+#include "timeline_content_view.h"
class Film;
-class View;
-class ContentView;
class ContentPanel;
-class TimeAxisView;
+class TimelineView;
+class TimelineTimeAxisView;
class Timeline : public wxPanel
{
void set_position_from_event (wxMouseEvent &);
void clear_selection ();
- typedef std::vector<boost::shared_ptr<View> > ViewList;
- typedef std::vector<boost::shared_ptr<ContentView> > ContentViewList;
-
- boost::shared_ptr<View> event_to_view (wxMouseEvent &);
- ContentViewList selected_views () const;
+ boost::shared_ptr<TimelineView> event_to_view (wxMouseEvent &);
+ TimelineContentViewList selected_views () const;
ContentList selected_content () const;
void maybe_snap (DCPTime a, DCPTime b, boost::optional<DCPTime>& nearest_distance) const;
ContentPanel* _content_panel;
boost::weak_ptr<Film> _film;
- ViewList _views;
- boost::shared_ptr<TimeAxisView> _time_axis_view;
+ TimelineViewList _views;
+ boost::shared_ptr<TimelineTimeAxisView> _time_axis_view;
int _tracks;
boost::optional<double> _pixels_per_second;
bool _left_down;
wxPoint _down_point;
- boost::shared_ptr<ContentView> _down_view;
+ boost::shared_ptr<TimelineContentView> _down_view;
DCPTime _down_view_position;
bool _first_move;
ContentMenu _menu;
--- /dev/null
+/*
+ Copyright (C) 2013-2015 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 "timeline_audio_content_view.h"
+
+using boost::shared_ptr;
+
+/** @class TimelineAudioContentView
+ * @brief Timeline view for AudioContent.
+ */
+
+TimelineAudioContentView::TimelineAudioContentView (Timeline& tl, shared_ptr<Content> c)
+ : TimelineContentView (tl, c)
+{
+
+}
+
+wxString
+TimelineAudioContentView::type () const
+{
+ return _("audio");
+}
+
+wxColour
+TimelineAudioContentView::background_colour () const
+{
+ return wxColour (149, 121, 232, 255);
+}
+
+wxColour
+TimelineAudioContentView::foreground_colour () const
+{
+ return wxColour (0, 0, 0, 255);
+}
--- /dev/null
+/*
+ Copyright (C) 2013-2015 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 "timeline_content_view.h"
+
+/** @class TimelineAudioContentView
+ * @brief Timeline view for AudioContent.
+ */
+class TimelineAudioContentView : public TimelineContentView
+{
+public:
+ TimelineAudioContentView (Timeline& tl, boost::shared_ptr<Content> c);
+
+private:
+ wxString type () const;
+ wxColour background_colour () const;
+ wxColour foreground_colour () const;
+};
--- /dev/null
+/*
+ Copyright (C) 2013-2015 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 "timeline_content_view.h"
+#include "timeline.h"
+#include "wx_util.h"
+#include "lib/content.h"
+#include <wx/graphics.h>
+
+using boost::shared_ptr;
+
+TimelineContentView::TimelineContentView (Timeline& tl, shared_ptr<Content> c)
+ : TimelineView (tl)
+ , _content (c)
+ , _selected (false)
+{
+ _content_connection = c->Changed.connect (bind (&TimelineContentView::content_changed, this, _2, _3));
+}
+
+dcpomatic::Rect<int>
+TimelineContentView::bbox () const
+{
+ DCPOMATIC_ASSERT (_track);
+
+ 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.get()) - 8,
+ content->length_after_trim().seconds() * _timeline.pixels_per_second().get_value_or(0) + 16,
+ _timeline.track_height() + 16
+ );
+}
+
+void
+TimelineContentView::set_selected (bool s)
+{
+ _selected = s;
+ force_redraw ();
+}
+
+bool
+TimelineContentView::selected () const
+{
+ return _selected;
+}
+
+shared_ptr<Content>
+TimelineContentView::content () const
+{
+ return _content.lock ();
+}
+
+void
+TimelineContentView::set_track (int t)
+{
+ _track = t;
+}
+
+void
+TimelineContentView::unset_track ()
+{
+ _track = boost::optional<int> ();
+}
+
+boost::optional<int>
+TimelineContentView::track () const
+{
+ return _track;
+}
+
+void
+TimelineContentView::do_paint (wxGraphicsContext* gc)
+{
+ DCPOMATIC_ASSERT (_track);
+
+ 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 (background_colour().Red() / 2, background_colour().Green() / 2, background_colour().Blue() / 2);
+
+ gc->SetPen (*wxThePenList->FindOrCreatePen (foreground_colour(), 4, wxPENSTYLE_SOLID));
+ if (_selected) {
+ gc->SetBrush (*wxTheBrushList->FindOrCreateBrush (selected, wxBRUSHSTYLE_SOLID));
+ } else {
+ gc->SetBrush (*wxTheBrushList->FindOrCreateBrush (background_colour(), wxBRUSHSTYLE_SOLID));
+ }
+
+ wxGraphicsPath path = gc->CreatePath ();
+ path.MoveToPoint (time_x (position), y_pos (_track.get()) + 4);
+ path.AddLineToPoint (time_x (position + len), y_pos (_track.get()) + 4);
+ path.AddLineToPoint (time_x (position + len), y_pos (_track.get() + 1) - 4);
+ path.AddLineToPoint (time_x (position), y_pos (_track.get() + 1) - 4);
+ path.AddLineToPoint (time_x (position), y_pos (_track.get()) + 4);
+ gc->StrokePath (path);
+ gc->FillPath (path);
+
+ wxString name = wxString::Format (wxT ("%s [%s]"), std_to_wx (cont->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.get()), len.seconds() * _timeline.pixels_per_second().get_value_or(0), _timeline.track_height()));
+ gc->SetFont (gc->CreateFont (*wxNORMAL_FONT, foreground_colour ()));
+ gc->DrawText (name, time_x (position) + 12, y_pos (_track.get() + 1) - name_height - 4);
+ gc->ResetClip ();
+}
+
+int
+TimelineContentView::y_pos (int t) const
+{
+ return _timeline.tracks_position().y + t * _timeline.track_height();
+}
+
+void
+TimelineContentView::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 ();
+ }
+}
+
--- /dev/null
+/*
+ Copyright (C) 2013-2015 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.
+
+*/
+
+#ifndef DCPOMATIC_TIMELINE_CONTENT_VIEW_H
+#define DCPOMATIC_TIMELINE_CONTENT_VIEW_H
+
+#include "timeline_view.h"
+#include <wx/wx.h>
+#include <boost/signals2.hpp>
+
+class Content;
+
+/** @class TimelineContentView
+ * @brief Parent class for views of pieces of content.
+ */
+class TimelineContentView : public TimelineView
+{
+public:
+ TimelineContentView (Timeline& tl, boost::shared_ptr<Content> c);
+
+ dcpomatic::Rect<int> bbox () const;
+
+ void set_selected (bool s);
+ bool selected () const;
+ boost::shared_ptr<Content> content () const;
+ void set_track (int t);
+ void unset_track ();
+ boost::optional<int> track () const;
+
+ virtual wxString type () const = 0;
+ virtual wxColour background_colour () const = 0;
+ virtual wxColour foreground_colour () const = 0;
+
+private:
+
+ void do_paint (wxGraphicsContext* gc);
+ int y_pos (int t) const;
+ void content_changed (int p, bool frequent);
+
+ boost::weak_ptr<Content> _content;
+ boost::optional<int> _track;
+ bool _selected;
+
+ boost::signals2::scoped_connection _content_connection;
+};
+
+typedef std::vector<boost::shared_ptr<TimelineContentView> > TimelineContentViewList;
+
+#endif
--- /dev/null
+/*
+ Copyright (C) 2013-2015 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 "timeline_subtitle_content_view.h"
+#include "lib/subtitle_content.h"
+
+using boost::shared_ptr;
+
+TimelineSubtitleContentView::TimelineSubtitleContentView (Timeline& tl, shared_ptr<SubtitleContent> c)
+ : TimelineContentView (tl, c)
+ , _subtitle_content (c)
+{
+
+}
+
+wxString
+TimelineSubtitleContentView::type () const
+{
+ return _("subtitles");
+}
+
+wxColour
+TimelineSubtitleContentView::background_colour () const
+{
+ shared_ptr<SubtitleContent> sc = _subtitle_content.lock ();
+ if (!sc || !sc->use_subtitles ()) {
+ return wxColour (210, 210, 210, 128);
+ }
+
+ return wxColour (163, 255, 154, 255);
+}
+
+wxColour
+TimelineSubtitleContentView::foreground_colour () const
+{
+ shared_ptr<SubtitleContent> sc = _subtitle_content.lock ();
+ if (!sc || !sc->use_subtitles ()) {
+ return wxColour (180, 180, 180, 128);
+ }
+
+ return wxColour (0, 0, 0, 255);
+}
--- /dev/null
+/*
+ Copyright (C) 2013-2015 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 "timeline_content_view.h"
+
+class SubtitleContent;
+
+/** @class TimelineSubtitleContentView
+ * @brief Timeline view for SubtitleContent.
+ */
+class TimelineSubtitleContentView : public TimelineContentView
+{
+public:
+ TimelineSubtitleContentView (Timeline& tl, boost::shared_ptr<SubtitleContent> c);
+
+private:
+ wxString type () const;
+ wxColour background_colour () const;
+ wxColour foreground_colour () const;
+
+ boost::weak_ptr<SubtitleContent> _subtitle_content;
+};
+
--- /dev/null
+/*
+ Copyright (C) 2013-2015 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 "timeline_time_axis_view.h"
+#include "timeline.h"
+#include <wx/wx.h>
+#include <wx/graphics.h>
+
+TimelineTimeAxisView::TimelineTimeAxisView (Timeline& tl, int y)
+ : TimelineView (tl)
+ , _y (y)
+{
+
+}
+
+dcpomatic::Rect<int>
+TimelineTimeAxisView::bbox () const
+{
+ return dcpomatic::Rect<int> (0, _y - 4, _timeline.width(), 24);
+}
+
+void
+TimelineTimeAxisView::set_y (int y)
+{
+ _y = y;
+ force_redraw ();
+}
+
+void
+TimelineTimeAxisView::do_paint (wxGraphicsContext* gc)
+{
+ if (!_timeline.pixels_per_second()) {
+ return;
+ }
+
+ double const pps = _timeline.pixels_per_second().get ();
+
+ gc->SetPen (*wxThePenList->FindOrCreatePen (wxColour (0, 0, 0), 1, wxPENSTYLE_SOLID));
+
+ double mark_interval = rint (128 / pps);
+ 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);
+
+ gc->SetFont (gc->CreateFont (*wxNORMAL_FONT));
+
+ /* Time in seconds */
+ DCPTime t;
+ while ((t.seconds() * pps) < _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() * pps;
+ if ((tx + str_width) < _timeline.width()) {
+ gc->DrawText (str, time_x (t), _y + 16);
+ }
+
+ t += DCPTime::from_seconds (mark_interval);
+ }
+}
--- /dev/null
+/*
+ Copyright (C) 2013-2015 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 "timeline_view.h"
+
+class TimelineTimeAxisView : public TimelineView
+{
+public:
+ TimelineTimeAxisView (Timeline& tl, int y);
+
+ dcpomatic::Rect<int> bbox () const;
+ void set_y (int y);
+
+private:
+ void do_paint (wxGraphicsContext* gc);
+
+private:
+ int _y;
+};
+
--- /dev/null
+/*
+ Copyright (C) 2013-2015 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 "timeline_video_content_view.h"
+#include "lib/image_content.h"
+
+using boost::dynamic_pointer_cast;
+using boost::shared_ptr;
+
+TimelineVideoContentView::TimelineVideoContentView (Timeline& tl, shared_ptr<Content> c)
+ : TimelineContentView (tl, c)
+{
+
+}
+
+wxString
+TimelineVideoContentView::type () const
+{
+ if (dynamic_pointer_cast<ImageContent> (content ()) && content()->number_of_paths() == 1) {
+ return _("still");
+ } else {
+ return _("video");
+ }
+}
+
+wxColour
+TimelineVideoContentView::background_colour () const
+{
+ return wxColour (242, 92, 120, 255);
+}
+
+wxColour
+TimelineVideoContentView::foreground_colour () const
+{
+ return wxColour (0, 0, 0, 255);
+}
+
--- /dev/null
+/*
+ Copyright (C) 2013-2015 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 "timeline_content_view.h"
+
+/** @class TimelineVideoContentView
+ * @brief Timeline view for VideoContent.
+ */
+class TimelineVideoContentView : public TimelineContentView
+{
+public:
+ TimelineVideoContentView (Timeline& tl, boost::shared_ptr<Content> c);
+
+private:
+ wxString type () const;
+ wxColour background_colour () const;
+ wxColour foreground_colour () const;
+};
--- /dev/null
+/*
+ Copyright (C) 2013-2015 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 "timeline_view.h"
+#include "timeline.h"
+
+/** @class TimelineView
+ * @brief Parent class for components of the timeline (e.g. a piece of content or an axis).
+ */
+TimelineView::TimelineView (Timeline& t)
+ : _timeline (t)
+{
+
+}
+
+void
+TimelineView::paint (wxGraphicsContext* g)
+{
+ _last_paint_bbox = bbox ();
+ do_paint (g);
+}
+
+void
+TimelineView::force_redraw ()
+{
+ _timeline.force_redraw (_last_paint_bbox);
+ _timeline.force_redraw (bbox ());
+}
+
+int
+TimelineView::time_x (DCPTime t) const
+{
+ return _timeline.tracks_position().x + t.seconds() * _timeline.pixels_per_second().get_value_or (0);
+}
+
--- /dev/null
+/*
+ Copyright (C) 2013-2015 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.
+
+*/
+
+#ifndef DCPOMATIC_TIMELINE_VIEW_H
+#define DCPOMATIC_TIMELINE_VIEW_H
+
+#include "lib/rect.h"
+#include "lib/dcpomatic_time.h"
+#include <boost/noncopyable.hpp>
+
+class wxGraphicsContext;
+class Timeline;
+
+/** @class TimelineView
+ * @brief Parent class for components of the timeline (e.g. a piece of content or an axis).
+ */
+class TimelineView : public boost::noncopyable
+{
+public:
+ TimelineView (Timeline& t);
+ virtual ~TimelineView () {}
+
+ void paint (wxGraphicsContext* g);
+ void force_redraw ();
+
+ virtual dcpomatic::Rect<int> bbox () const = 0;
+
+protected:
+ virtual void do_paint (wxGraphicsContext *) = 0;
+
+ int time_x (DCPTime t) const;
+
+ Timeline& _timeline;
+
+private:
+ dcpomatic::Rect<int> _last_paint_bbox;
+};
+
+typedef std::vector<boost::shared_ptr<TimelineView> > TimelineViewList;
+
+#endif
table_dialog.cc
timecode.cc
timeline.cc
+ timeline_content_view.cc
timeline_dialog.cc
+ timeline_audio_content_view.cc
+ timeline_subtitle_content_view.cc
+ timeline_time_axis_view.cc
+ timeline_video_content_view.cc
+ timeline_view.cc
timing_panel.cc
update_dialog.cc
video_panel.cc