2 Copyright (C) 2005 Paul Davis
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.
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.
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.
21 #include <libgnomecanvasmm/init.h>
22 #include <jack/types.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"
35 #include "rgb_macros.h"
37 #include "time_axis_view.h"
43 using namespace ARDOUR;
46 using namespace Gtkmm2ext;
47 using namespace Editing;
49 /* XXX this is a hack. it ought to be the maximum value of an jack_nframes_t */
51 const double max_canvas_coordinate = (double) JACK_MAX_FRAMES;
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);
63 static void ardour_canvas_type_init()
65 // Map gtypes to gtkmm wrapper-creation functions:
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);
72 // Register the gtkmm gtypes:
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();
81 Editor::initialize_canvas ()
83 ArdourCanvas::init ();
84 ardour_canvas_type_init ();
86 /* adjust sensitivity for "picking" items */
88 // GNOME_CANVAS(track_canvas)->close_enough = 2;
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));
95 /* set up drag-n-drop */
96 vector<Gtk::TargetEntry> target_table;
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"));
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));
107 /* stuff for the verbose canvas cursor */
109 Pango::FontDescription font = get_font_for_style (N_("VerboseCanvasCursor"));
111 verbose_canvas_cursor = new ArdourCanvas::Text (*track_canvas.root());
112 verbose_canvas_cursor->property_font_desc() = font;
114 // verbose_canvas_cursor->property_anchor() = GTK_ANCHOR_NW;
115 verbose_canvas_cursor->property_fill_color_rgba() = color_map[cVerboseCanvasCursor];
117 verbose_cursor_visible = false;
119 /* a group to hold time (measure) lines */
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);
124 time_canvas.set_name ("EditorTimeCanvas");
125 time_canvas.add_events (Gdk::POINTER_MOTION_HINT_MASK);
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);
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;
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;
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;
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;
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;
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 ();
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 ();
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));
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();
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 ();
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();
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();
191 transport_loop_range_rect->lower_to_bottom (); // loop on the bottom
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 ();
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();
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;
216 zoom_rect->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_zoom_rect_event), (ArdourCanvas::Item*) 0));
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();
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));
231 /* separator lines */
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);
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);
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);
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);
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);
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));
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);
255 edit_cursor = new Cursor (*this, "blue", &Editor::canvas_edit_cursor_event);
256 playhead_cursor = new Cursor (*this, "red", &Editor::canvas_playhead_cursor_event);
258 track_canvas.signal_size_allocate().connect (mem_fun(*this, &Editor::track_canvas_allocate));
262 Editor::reset_scrolling_region (Gtk::Allocation* alloc)
264 guint32 last_canvas_unit;
266 guint32 canvas_alloc_height, canvas_alloc_width;
267 TrackViewList::iterator i;
268 static bool first_time = true;
270 /* We need to make sure that the canvas always has its
271 scrolling region set to larger of:
273 - the size allocated for it (within the container its packed in)
274 - the size required to see the entire session
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
281 XXX GnomeCanvas has fixed this, and has an option to
282 control the centering behaviour.
285 last_canvas_unit = (guint32) ceil ((float) max_frames / frames_per_unit);
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;
298 height -= track_spacing;
302 canvas_height = (guint32) height;
305 canvas_alloc_height = alloc->get_height();
306 canvas_alloc_width = alloc->get_width();
308 canvas_alloc_height = track_canvas.get_height();
309 canvas_alloc_width = track_canvas.get_width();
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);
315 if (edit_cursor) edit_cursor->set_length (canvas_alloc_height);
316 if (playhead_cursor) playhead_cursor->set_length (canvas_alloc_height);
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;
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;
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;
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;
338 if (transport_punchin_line) {
339 transport_punchin_line->property_y1() = 0.0;
340 transport_punchin_line->property_y2() = (double) canvas_height;
343 if (transport_punchout_line) {
344 transport_punchout_line->property_y1() = 0.0;
345 transport_punchout_line->property_y2() = (double) canvas_height;
348 update_fixed_rulers ();
350 if (is_visible() && first_time) {
351 tempo_map_changed (Change (0));
359 Editor::track_canvas_map_handler (GdkEventAny* ev)
361 track_canvas_scroller.get_window()->set_cursor (*current_canvas_cursor);
366 Editor::time_canvas_map_handler (GdkEventAny* ev)
368 time_canvas_scroller.get_window()->set_cursor (*timebar_cursor);