Add a widget giving an overview of the editor, as (what I think is being) suggested...
[ardour.git] / gtk2_ardour / editor_summary.cc
1 #include "ardour/session.h"
2 #include "time_axis_view.h"
3 #include "streamview.h"
4 #include "editor_summary.h"
5 #include "gui_thread.h"
6 #include "editor.h"
7 #include "region_view.h"
8
9 using namespace std;
10 using namespace sigc;
11 using namespace ARDOUR;
12
13 EditorSummary::EditorSummary (Editor* e)
14         : _editor (e),
15           _session (0),
16           _pixmap (0),
17           _regions_dirty (true),
18           _width (512),
19           _height (64),
20           _pixels_per_frame (1)
21 {
22         
23 }
24
25 void
26 EditorSummary::set_session (Session* s)
27 {
28         _session = s;
29
30         Region::RegionPropertyChanged.connect (sigc::hide (mem_fun (*this, &EditorSummary::set_dirty)));
31
32         _session->RegionRemoved.connect (sigc::hide (mem_fun (*this, &EditorSummary::set_dirty)));
33         _session->EndTimeChanged.connect (mem_fun (*this, &EditorSummary::set_dirty));
34         _session->StartTimeChanged.connect (mem_fun (*this, &EditorSummary::set_dirty));
35
36         set_dirty ();
37 }
38
39 EditorSummary::~EditorSummary ()
40 {
41         if (_pixmap) {
42                 gdk_pixmap_unref (_pixmap);
43         }
44 }
45
46 bool
47 EditorSummary::on_expose_event (GdkEventExpose* event)
48 {
49         Gdk::Rectangle const exposure (
50                 event->area.x, event->area.y, event->area.width, event->area.height
51                 );
52
53         Gdk::Rectangle r = exposure;
54         Gdk::Rectangle content (0, 0, _width, _height);
55         bool intersects;
56         r.intersect (content, intersects);
57         
58         if (intersects) {
59
60                 GdkPixmap* p = get_pixmap (get_window()->gobj ());
61
62                 gdk_draw_drawable (
63                         get_window()->gobj(),
64                         get_style()->get_fg_gc (Gtk::STATE_NORMAL)->gobj(),
65                         p,
66                         r.get_x(),
67                         r.get_y(),
68                         r.get_x(),
69                         r.get_y(),
70                         r.get_width(),
71                         r.get_height()
72                         );
73         }
74
75         cairo_t* cr = gdk_cairo_create (get_window()->gobj());
76
77         cairo_set_source_rgb (cr, 0, 1, 0);
78         cairo_set_line_width (cr, 2);
79
80         double const s = (_editor->leftmost_position () - _session->current_start_frame ()) * _pixels_per_frame; 
81         cairo_move_to (cr, s, 0);
82         cairo_line_to (cr, s, _height);
83         cairo_stroke (cr);
84
85         double const e = s + _editor->current_page_frames() * _pixels_per_frame;
86         cairo_move_to (cr, e, 0);
87         cairo_line_to (cr, e, _height);
88         cairo_stroke (cr);
89         
90         cairo_destroy (cr);
91         
92         return true;
93 }
94
95 GdkPixmap *
96 EditorSummary::get_pixmap (GdkDrawable* drawable)
97 {
98         if (_regions_dirty) {
99
100                 if (_pixmap) {
101                         gdk_pixmap_unref (_pixmap);
102                 }
103                 _pixmap = gdk_pixmap_new (drawable, _width, _height, -1);
104
105                 cairo_t* cr = gdk_cairo_create (_pixmap);
106                 render (cr);
107                 cairo_destroy (cr);
108
109                 _regions_dirty = false;
110         }
111
112         return _pixmap;
113 }
114
115 void
116 EditorSummary::render (cairo_t* cr)
117 {
118         if (_session == 0) {
119                 return;
120         }
121
122         cairo_set_source_rgb (cr, 0, 0, 0);
123         cairo_rectangle (cr, 0, 0, _width, _height);
124         cairo_fill (cr);
125
126         int N = 0;
127         
128         for (PublicEditor::TrackViewList::const_iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
129                 if ((*i)->view()) {
130                         ++N;
131                 }
132         }
133
134         nframes_t const start = _session->current_start_frame ();
135         _pixels_per_frame = static_cast<double> (_width) / (_session->current_end_frame() - start);
136         double const track_height = static_cast<double> (_height) / N;
137
138         cairo_set_line_width (cr, track_height);
139
140         int n = 0;
141         for (PublicEditor::TrackViewList::const_iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
142                 StreamView* s = (*i)->view ();
143                 if (s) {
144
145                         double const v = ((n % 2) == 0) ? 1 : 0.5;
146                         cairo_set_source_rgb (cr, v, v, v);
147
148                         s->foreach_regionview (bind (
149                                                        mem_fun (*this, &EditorSummary::render_region),
150                                                        cr,
151                                                        start,
152                                                        track_height * (n + 0.5)
153                                                        ));
154                         ++n;
155                 }
156         }
157
158 }
159
160 void
161 EditorSummary::render_region (RegionView* r, cairo_t* cr, nframes_t start, double y) const
162 {
163         cairo_move_to (cr, (r->region()->position() - start) * _pixels_per_frame, y);
164         cairo_line_to (cr, (r->region()->position() - start + r->region()->length()) * _pixels_per_frame, y);
165         cairo_stroke (cr);
166 }
167
168 void
169 EditorSummary::set_dirty ()
170 {
171         ENSURE_GUI_THREAD (mem_fun (*this, &EditorSummary::set_dirty));
172
173         _regions_dirty = true;
174         queue_draw ();
175 }
176
177 void
178 EditorSummary::set_bounds_dirty ()
179 {
180         ENSURE_GUI_THREAD (mem_fun (*this, &EditorSummary::set_bounds_dirty));
181         queue_draw ();
182 }
183
184 void
185 EditorSummary::on_size_request (Gtk::Requisition *req)
186 {
187         req->width = 64;
188         req->height = 64;
189 }
190
191 void
192 EditorSummary::on_size_allocate (Gtk::Allocation& alloc)
193 {
194         Gtk::EventBox::on_size_allocate (alloc);
195
196         _width = alloc.get_width ();
197         _height = alloc.get_height ();
198
199         set_dirty ();
200 }
201
202 bool
203 EditorSummary::on_button_press_event (GdkEventButton* ev)
204 {
205         if (ev->button == 1) {
206
207                 nframes_t f = (ev->x / _pixels_per_frame) + _session->current_start_frame();
208
209                 nframes_t const h = _editor->current_page_frames () / 2;
210                 if (f > h) {
211                         f -= h;
212                 } else {
213                         f = 0;
214                 }
215                 
216                 _editor->reset_x_origin (f);
217         }
218
219         return true;
220 }