46b625407a6bbaaf931498b8ae62bcfee50b3eb3
[ardour.git] / gtk2_ardour / editor_canvas.cc
1 /*
2     Copyright (C) 2005 Paul Davis 
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     $Id$
19 */
20
21 #include <libgnomecanvasmm/init.h>
22 #include <jack/types.h>
23
24 #include "editor.h"
25 #include "waveview.h"
26 #include "simplerect.h"
27 #include "simpleline.h"
28 #include "imageframe.h"
29 #include "waveview_p.h"
30 #include "simplerect_p.h"
31 #include "simpleline_p.h"
32 #include "imageframe_p.h"
33 #include "canvas_impl.h"
34 #include "editing.h"
35 #include "rgb_macros.h"
36 #include "utils.h"
37 #include "time_axis_view.h"
38
39 #include "i18n.h"
40
41 using namespace std;
42 using namespace sigc;
43 using namespace ARDOUR;
44 using namespace Gtk;
45 using namespace Glib;
46 using namespace Gtkmm2ext;
47 using namespace Editing;
48
49 /* XXX this is a hack. it ought to be the maximum value of an jack_nframes_t */
50
51 const double max_canvas_coordinate = (double) JACK_MAX_FRAMES;
52
53 extern "C"
54 {
55
56 GType gnome_canvas_simpleline_get_type(void);
57 GType gnome_canvas_simplerect_get_type(void);
58 GType gnome_canvas_waveview_get_type(void);
59 GType gnome_canvas_imageframe_get_type(void);
60
61 }
62
63 static void ardour_canvas_type_init() 
64 {
65         // Map gtypes to gtkmm wrapper-creation functions:
66         
67         Glib::wrap_register(gnome_canvas_simpleline_get_type(), &Gnome::Canvas::SimpleLine_Class::wrap_new);
68         Glib::wrap_register(gnome_canvas_simplerect_get_type(), &Gnome::Canvas::SimpleRect_Class::wrap_new);
69         Glib::wrap_register(gnome_canvas_waveview_get_type(), &Gnome::Canvas::WaveView_Class::wrap_new);
70         Glib::wrap_register(gnome_canvas_imageframe_get_type(), &Gnome::Canvas::ImageFrame_Class::wrap_new);
71         
72         // Register the gtkmm gtypes:
73
74         (void) Gnome::Canvas::WaveView::get_type();
75         (void) Gnome::Canvas::SimpleLine::get_type();
76         (void) Gnome::Canvas::SimpleRect::get_type();
77         (void) Gnome::Canvas::ImageFrame::get_type();
78
79
80 void
81 Editor::initialize_canvas ()
82 {
83         ArdourCanvas::init ();
84         ardour_canvas_type_init ();
85
86         /* adjust sensitivity for "picking" items */
87
88         // GNOME_CANVAS(track_canvas)->close_enough = 2;
89
90         track_canvas.signal_event().connect (bind (mem_fun (*this, &Editor::track_canvas_event), (ArdourCanvas::Item*) 0));
91         track_canvas.set_name ("EditorMainCanvas");
92         track_canvas.add_events (Gdk::POINTER_MOTION_HINT_MASK);
93         track_canvas.signal_leave_notify_event().connect (mem_fun(*this, &Editor::left_track_canvas));
94         
95         /* set up drag-n-drop */
96         vector<Gtk::TargetEntry> target_table;
97         
98         target_table.push_back (TargetEntry ("STRING"));
99         target_table.push_back (TargetEntry ("text/plain"));
100         target_table.push_back (TargetEntry ("text/uri-list"));
101         target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
102
103         // GTK2FIX
104         // track_canvas.drag_dest_set (target_table, DEST_DEFAULT_ALL, GdkDragAction (Gdk::ACTION_COPY|Gdk::ACTION_MOVE));
105         // track_canvas.signal_drag_data_received().connect (mem_fun(*this, &Editor::track_canvas_drag_data_received));
106
107         /* stuff for the verbose canvas cursor */
108
109         Pango::FontDescription font = get_font_for_style (N_("VerboseCanvasCursor"));
110
111         verbose_canvas_cursor = new ArdourCanvas::Text (*track_canvas.root());
112         verbose_canvas_cursor->property_font_desc() = font;
113         // GTK2FIX
114         // verbose_canvas_cursor->property_anchor() = GTK_ANCHOR_NW;
115         verbose_canvas_cursor->property_fill_color_rgba() = color_map[cVerboseCanvasCursor];
116         
117         verbose_cursor_visible = false;
118         
119         /* a group to hold time (measure) lines */
120         
121         time_line_group = new ArdourCanvas::Group (*track_canvas.root(), 0.0, 0.0);
122         cursor_group = new ArdourCanvas::Group (*track_canvas.root(), 0.0, 0.0);
123         
124         time_canvas.set_name ("EditorTimeCanvas");
125         time_canvas.add_events (Gdk::POINTER_MOTION_HINT_MASK);
126         
127         meter_group = new ArdourCanvas::Group (*time_canvas.root(), 0.0, 0.0);
128         tempo_group = new ArdourCanvas::Group (*time_canvas.root(), 0.0, 0.0);
129         marker_group = new ArdourCanvas::Group (*time_canvas.root(), 0.0, timebar_height * 2.0);
130         range_marker_group = new ArdourCanvas::Group (*time_canvas.root(), 0.0, timebar_height * 3.0);
131         transport_marker_group = new ArdourCanvas::Group (*time_canvas.root(), 0.0, timebar_height * 4.0);
132         
133         tempo_bar = new ArdourCanvas::SimpleRect (*tempo_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
134         tempo_bar->property_fill_color_rgba() = color_map[cTempoBar];
135         tempo_bar->property_outline_pixels() = 0;
136         
137         meter_bar = new ArdourCanvas::SimpleRect (*meter_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
138         meter_bar->property_fill_color_rgba() = color_map[cMeterBar];
139         meter_bar->property_outline_pixels() = 0;
140         
141         marker_bar = new ArdourCanvas::SimpleRect (*marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
142         marker_bar->property_fill_color_rgba() = color_map[cMarkerBar];
143         marker_bar->property_outline_pixels() = 0;
144         
145         range_marker_bar = new ArdourCanvas::SimpleRect (*range_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
146         range_marker_bar->property_fill_color_rgba() = color_map[cRangeMarkerBar];
147         range_marker_bar->property_outline_pixels() = 0;
148         
149         transport_marker_bar = new ArdourCanvas::SimpleRect (*transport_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
150         transport_marker_bar->property_fill_color_rgba() = color_map[cTransportMarkerBar];
151         transport_marker_bar->property_outline_pixels() = 0;
152         
153         range_bar_drag_rect = new ArdourCanvas::SimpleRect (*range_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
154         range_bar_drag_rect->property_fill_color_rgba() = color_map[cRangeDragBarRectFill];
155         range_bar_drag_rect->property_outline_color_rgba() = color_map[cRangeDragBarRect];
156         range_bar_drag_rect->property_outline_pixels() = 0;
157         range_bar_drag_rect->hide ();
158         
159         transport_bar_drag_rect = new ArdourCanvas::SimpleRect (*transport_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
160         transport_bar_drag_rect ->property_fill_color_rgba() = color_map[cTransportDragRectFill];
161         transport_bar_drag_rect->property_outline_color_rgba() = color_map[cTransportDragRect];
162         transport_bar_drag_rect->property_outline_pixels() = 0;
163         transport_bar_drag_rect->hide ();
164         
165         marker_drag_line_points.push_back(Gnome::Art::Point(0.0, 0.0));
166         marker_drag_line_points.push_back(Gnome::Art::Point(0.0, 0.0));
167
168         marker_drag_line = new ArdourCanvas::Line (*track_canvas.root());
169         marker_drag_line->property_width_pixels() = 1;
170         marker_drag_line->property_fill_color_rgba() = color_map[cMarkerDragLine];
171         marker_drag_line->property_points() = marker_drag_line_points;
172         marker_drag_line->hide();
173
174         range_marker_drag_rect = new ArdourCanvas::SimpleRect (*track_canvas.root(), 0.0, 0.0, 0.0, 0.0);
175         range_marker_drag_rect->property_fill_color_rgba() = color_map[cRangeDragRectFill];
176         range_marker_drag_rect->property_outline_color_rgba() = color_map[cRangeDragRect];
177         range_marker_drag_rect->hide ();
178         
179         transport_loop_range_rect = new ArdourCanvas::SimpleRect (*time_line_group, 0.0, 0.0, 0.0, 0.0);
180         transport_loop_range_rect->property_fill_color_rgba() = color_map[cTransportLoopRectFill];
181         transport_loop_range_rect->property_outline_color_rgba() = color_map[cTransportLoopRect];
182         transport_loop_range_rect->property_outline_pixels() = 1;
183         transport_loop_range_rect->hide();
184
185         transport_punch_range_rect = new ArdourCanvas::SimpleRect (*time_line_group, 0.0, 0.0, 0.0, 0.0);
186         transport_punch_range_rect->property_fill_color_rgba() = color_map[cTransportPunchRectFill];
187         transport_punch_range_rect->property_outline_color_rgba() = color_map[cTransportPunchRect];
188         transport_punch_range_rect->property_outline_pixels() = 0;
189         transport_punch_range_rect->hide();
190         
191         transport_loop_range_rect->lower_to_bottom (); // loop on the bottom
192
193         transport_punchin_line = new ArdourCanvas::SimpleLine (*time_line_group);
194         transport_punchin_line->property_x1() = 0.0;
195         transport_punchin_line->property_y1() = 0.0;
196         transport_punchin_line->property_x2() = 0.0;
197         transport_punchin_line->property_y2() = 0.0;
198         transport_punchin_line->property_color_rgba() = color_map[cPunchInLine];
199         transport_punchin_line->hide ();
200         
201         transport_punchout_line  = new ArdourCanvas::SimpleLine (*time_line_group);
202         transport_punchout_line->property_x1() = 0.0;
203         transport_punchout_line->property_y1() = 0.0;
204         transport_punchout_line->property_x2() = 0.0;
205         transport_punchout_line->property_y2() = 0.0;
206         transport_punchout_line->property_color_rgba() = color_map[cPunchOutLine];
207         transport_punchout_line->hide();
208         
209         // used to show zoom mode active zooming
210         zoom_rect = new ArdourCanvas::SimpleRect (*track_canvas.root(), 0.0, 0.0, 0.0, 0.0);
211         zoom_rect->property_fill_color_rgba() = color_map[cZoomRectFill];
212         zoom_rect->property_outline_color_rgba() = color_map[cZoomRect];
213         zoom_rect->property_outline_pixels() = 1;
214         zoom_rect->hide();
215         
216         zoom_rect->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_zoom_rect_event), (ArdourCanvas::Item*) 0));
217         
218         // used as rubberband rect
219         rubberband_rect = new ArdourCanvas::SimpleRect (*track_canvas.root(), 0.0, 0.0, 0.0, 0.0);
220         rubberband_rect->property_outline_color_rgba() = color_map[cRubberBandRect];
221         rubberband_rect->property_fill_color_rgba() = (guint32) color_map[cRubberBandRectFill];
222         rubberband_rect->property_outline_pixels() = 1;
223         rubberband_rect->hide();
224         
225         tempo_bar->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_tempo_bar_event), tempo_bar));
226         meter_bar->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_meter_bar_event), meter_bar));
227         marker_bar->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_marker_bar_event), marker_bar));
228         range_marker_bar->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_range_marker_bar_event), range_marker_bar));
229         transport_marker_bar->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_transport_marker_bar_event), transport_marker_bar));
230         
231         /* separator lines */
232         
233         tempo_line = new ArdourCanvas::SimpleLine (*tempo_group, 0, timebar_height, max_canvas_coordinate, timebar_height);
234         tempo_line->property_color_rgba() = RGBA_TO_UINT (0,0,0,255);
235
236         meter_line = new ArdourCanvas::SimpleLine (*meter_group, 0, timebar_height, max_canvas_coordinate, timebar_height);
237         meter_line->property_color_rgba() = RGBA_TO_UINT (0,0,0,255);
238
239         marker_line = new ArdourCanvas::SimpleLine (*marker_group, 0, timebar_height, max_canvas_coordinate, timebar_height);
240         marker_line->property_color_rgba() = RGBA_TO_UINT (0,0,0,255);
241         
242         range_marker_line = new ArdourCanvas::SimpleLine (*range_marker_group, 0, timebar_height, max_canvas_coordinate, timebar_height);
243         range_marker_line->property_color_rgba() = RGBA_TO_UINT (0,0,0,255);
244
245         transport_marker_line = new ArdourCanvas::SimpleLine (*transport_marker_group, 0, timebar_height, max_canvas_coordinate, timebar_height);
246         transport_marker_line->property_color_rgba() = RGBA_TO_UINT (0,0,0,255);
247
248         ZoomChanged.connect (bind (mem_fun(*this, &Editor::update_loop_range_view), false));
249         ZoomChanged.connect (bind (mem_fun(*this, &Editor::update_punch_range_view), false));
250         
251         double time_height = timebar_height * 5;
252         double time_width = FLT_MAX/frames_per_unit;
253         time_canvas.set_scroll_region(0.0, 0.0, time_width, time_height);
254         
255         edit_cursor = new Cursor (*this, "blue", &Editor::canvas_edit_cursor_event);
256         playhead_cursor = new Cursor (*this, "red", &Editor::canvas_playhead_cursor_event);
257         
258         track_canvas.signal_size_allocate().connect (mem_fun(*this, &Editor::track_canvas_allocate));
259 }
260
261 void
262 Editor::reset_scrolling_region (Gtk::Allocation* alloc)
263 {
264         guint32 last_canvas_unit;
265         double height;
266         guint32 canvas_alloc_height, canvas_alloc_width;
267         TrackViewList::iterator i;
268         static bool first_time = true;
269
270         /* We need to make sure that the canvas always has its
271            scrolling region set to larger of:
272
273            - the size allocated for it (within the container its packed in)
274            - the size required to see the entire session
275
276            If we don't ensure at least the first of these, the canvas
277            does some wierd and in my view unnecessary stuff to center
278            itself within the allocated area, which causes bad, bad
279            results.
280            
281            XXX GnomeCanvas has fixed this, and has an option to
282            control the centering behaviour.
283         */
284
285         last_canvas_unit = (guint32) ceil ((float) max_frames / frames_per_unit);
286
287         height = 0;
288
289         if (session) {
290                 for (i = track_views.begin(); i != track_views.end(); ++i) {
291                         if ((*i)->control_parent) {
292                                 height += (*i)->effective_height;
293                                 height += track_spacing;
294                         }
295                 }
296                 
297                 if (height) {
298                         height -= track_spacing;
299                 }
300         }
301
302         canvas_height = (guint32) height;
303         
304         if (alloc) {
305                 canvas_alloc_height = alloc->get_height();
306                 canvas_alloc_width = alloc->get_width();
307         } else {
308                 canvas_alloc_height = track_canvas.get_height();
309                 canvas_alloc_width = track_canvas.get_width();
310         }
311
312         canvas_height = max (canvas_height, canvas_alloc_height);
313         track_canvas.set_scroll_region ( 0.0, 0.0, max (last_canvas_unit, canvas_alloc_width), canvas_height);
314
315         if (edit_cursor) edit_cursor->set_length (canvas_alloc_height);
316         if (playhead_cursor) playhead_cursor->set_length (canvas_alloc_height);
317
318         if (marker_drag_line) {
319                 marker_drag_line_points.back().set_x(canvas_height);
320                 // cerr << "set mlA points, nc = " << marker_drag_line_points.num_points << endl;
321                 marker_drag_line->property_points() = marker_drag_line_points;
322         }
323         if (range_marker_drag_rect) {
324                 range_marker_drag_rect->property_y1() = 0.0;
325                 range_marker_drag_rect->property_y2() = (double) canvas_height;
326         }
327
328         if (transport_loop_range_rect) {
329                 transport_loop_range_rect->property_y1() = 0.0;
330                 transport_loop_range_rect->property_y2() = (double) canvas_height;
331         }
332
333         if (transport_punch_range_rect) {
334                 transport_punch_range_rect->property_y1() = 0.0;
335                 transport_punch_range_rect->property_y2() = (double) canvas_height;
336         }
337
338         if (transport_punchin_line) {
339                 transport_punchin_line->property_y1() = 0.0;
340                 transport_punchin_line->property_y2() = (double) canvas_height;
341         }
342
343         if (transport_punchout_line) {
344                 transport_punchout_line->property_y1() = 0.0;
345                 transport_punchout_line->property_y2() = (double) canvas_height;
346         }
347                 
348         update_fixed_rulers ();
349
350         if (is_visible() && first_time) {
351                 tempo_map_changed (Change (0));
352                 first_time = false;
353         } else {
354                 redisplay_tempo ();
355         }
356 }
357
358 bool
359 Editor::track_canvas_map_handler (GdkEventAny* ev)
360 {
361         track_canvas_scroller.get_window()->set_cursor (*current_canvas_cursor);
362         return false;
363 }
364
365 bool
366 Editor::time_canvas_map_handler (GdkEventAny* ev)
367 {
368         time_canvas_scroller.get_window()->set_cursor (*timebar_cursor);
369         return false;
370 }
371