Merge branch '2.0' of ssh://main.carlh.net/home/carl/git/dcpomatic into 2.0
[dcpomatic.git] / src / wx / timeline_content_view.cc
1 /*
2     Copyright (C) 2013-2015 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include "timeline_content_view.h"
21 #include "timeline.h"
22 #include "wx_util.h"
23 #include "lib/content.h"
24 #include <wx/graphics.h>
25
26 using boost::shared_ptr;
27
28 TimelineContentView::TimelineContentView (Timeline& tl, shared_ptr<Content> c)
29         : TimelineView (tl)
30         , _content (c)
31         , _selected (false)
32 {
33         _content_connection = c->Changed.connect (bind (&TimelineContentView::content_changed, this, _2, _3));
34 }
35
36 dcpomatic::Rect<int>
37 TimelineContentView::bbox () const
38 {
39         DCPOMATIC_ASSERT (_track);
40         
41         shared_ptr<const Film> film = _timeline.film ();
42         shared_ptr<const Content> content = _content.lock ();
43         if (!film || !content) {
44                 return dcpomatic::Rect<int> ();
45         }
46         
47         return dcpomatic::Rect<int> (
48                 time_x (content->position ()) - 8,
49                 y_pos (_track.get()) - 8,
50                 content->length_after_trim().seconds() * _timeline.pixels_per_second().get_value_or(0) + 16,
51                 _timeline.track_height() + 16
52                 );
53 }
54
55 void
56 TimelineContentView::set_selected (bool s)
57 {
58         _selected = s;
59         force_redraw ();
60 }
61
62 bool
63 TimelineContentView::selected () const
64 {
65         return _selected;
66 }
67
68 shared_ptr<Content>
69 TimelineContentView::content () const
70 {
71         return _content.lock ();
72 }
73
74 void
75 TimelineContentView::set_track (int t)
76 {
77         _track = t;
78 }
79
80 void
81 TimelineContentView::unset_track ()
82 {
83         _track = boost::optional<int> ();
84 }
85
86 boost::optional<int>
87 TimelineContentView::track () const
88 {
89         return _track;
90 }
91
92 void
93 TimelineContentView::do_paint (wxGraphicsContext* gc)
94 {
95         DCPOMATIC_ASSERT (_track);
96         
97         shared_ptr<const Film> film = _timeline.film ();
98         shared_ptr<const Content> cont = content ();
99         if (!film || !cont) {
100                 return;
101         }
102         
103         DCPTime const position = cont->position ();
104         DCPTime const len = cont->length_after_trim ();
105         
106         wxColour selected (background_colour().Red() / 2, background_colour().Green() / 2, background_colour().Blue() / 2);
107         
108         gc->SetPen (*wxThePenList->FindOrCreatePen (foreground_colour(), 4, wxPENSTYLE_SOLID));
109         if (_selected) {
110                 gc->SetBrush (*wxTheBrushList->FindOrCreateBrush (selected, wxBRUSHSTYLE_SOLID));
111         } else {
112                 gc->SetBrush (*wxTheBrushList->FindOrCreateBrush (background_colour(), wxBRUSHSTYLE_SOLID));
113         }
114
115         wxGraphicsPath path = gc->CreatePath ();
116         path.MoveToPoint    (time_x (position),       y_pos (_track.get()) + 4);
117         path.AddLineToPoint (time_x (position + len), y_pos (_track.get()) + 4);
118         path.AddLineToPoint (time_x (position + len), y_pos (_track.get() + 1) - 4);
119         path.AddLineToPoint (time_x (position),       y_pos (_track.get() + 1) - 4);
120         path.AddLineToPoint (time_x (position),       y_pos (_track.get()) + 4);
121         gc->StrokePath (path);
122         gc->FillPath (path);
123         
124         wxString name = wxString::Format (wxT ("%s [%s]"), std_to_wx (cont->summary()).data(), type().data());
125         wxDouble name_width;
126         wxDouble name_height;
127         wxDouble name_descent;
128         wxDouble name_leading;
129         gc->GetTextExtent (name, &name_width, &name_height, &name_descent, &name_leading);
130         
131         gc->Clip (wxRegion (time_x (position), y_pos (_track.get()), len.seconds() * _timeline.pixels_per_second().get_value_or(0), _timeline.track_height()));
132         gc->SetFont (gc->CreateFont (*wxNORMAL_FONT, foreground_colour ()));
133         gc->DrawText (name, time_x (position) + 12, y_pos (_track.get() + 1) - name_height - 4);
134         gc->ResetClip ();
135 }
136
137 int
138 TimelineContentView::y_pos (int t) const
139 {
140         return _timeline.tracks_position().y + t * _timeline.track_height();
141 }
142
143 void
144 TimelineContentView::content_changed (int p, bool frequent)
145 {
146         ensure_ui_thread ();
147         
148         if (p == ContentProperty::POSITION || p == ContentProperty::LENGTH) {
149                 force_redraw ();
150         }
151         
152         if (!frequent) {
153                 _timeline.setup_pixels_per_second ();
154                 _timeline.Refresh ();
155         }
156 }
157