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>
24 #include "ardour_ui.h"
27 #include "simplerect.h"
28 #include "simpleline.h"
29 #include "imageframe.h"
30 #include "waveview_p.h"
31 #include "simplerect_p.h"
32 #include "simpleline_p.h"
33 #include "imageframe_p.h"
34 #include "canvas_impl.h"
36 #include "rgb_macros.h"
38 #include "time_axis_view.h"
44 using namespace ARDOUR;
47 using namespace Gtkmm2ext;
48 using namespace Editing;
50 /* XXX this is a hack. it ought to be the maximum value of an jack_nframes_t */
52 const double max_canvas_coordinate = (double) JACK_MAX_FRAMES;
57 GType gnome_canvas_simpleline_get_type(void);
58 GType gnome_canvas_simplerect_get_type(void);
59 GType gnome_canvas_waveview_get_type(void);
60 GType gnome_canvas_imageframe_get_type(void);
64 static void ardour_canvas_type_init()
66 // Map gtypes to gtkmm wrapper-creation functions:
68 Glib::wrap_register(gnome_canvas_simpleline_get_type(), &Gnome::Canvas::SimpleLine_Class::wrap_new);
69 Glib::wrap_register(gnome_canvas_simplerect_get_type(), &Gnome::Canvas::SimpleRect_Class::wrap_new);
70 Glib::wrap_register(gnome_canvas_waveview_get_type(), &Gnome::Canvas::WaveView_Class::wrap_new);
71 Glib::wrap_register(gnome_canvas_imageframe_get_type(), &Gnome::Canvas::ImageFrame_Class::wrap_new);
73 // Register the gtkmm gtypes:
75 (void) Gnome::Canvas::WaveView::get_type();
76 (void) Gnome::Canvas::SimpleLine::get_type();
77 (void) Gnome::Canvas::SimpleRect::get_type();
78 (void) Gnome::Canvas::ImageFrame::get_type();
82 Editor::initialize_canvas ()
84 ArdourCanvas::init ();
85 ardour_canvas_type_init ();
87 /* don't try to center the canvas */
89 track_canvas.set_center_scroll_region (false);
91 track_canvas.signal_event().connect (bind (mem_fun (*this, &Editor::track_canvas_event), (ArdourCanvas::Item*) 0));
92 track_canvas.set_name ("EditorMainCanvas");
93 track_canvas.add_events (Gdk::POINTER_MOTION_HINT_MASK);
94 track_canvas.signal_leave_notify_event().connect (mem_fun(*this, &Editor::left_track_canvas));
96 /* set up drag-n-drop */
97 vector<Gtk::TargetEntry> target_table;
99 target_table.push_back (TargetEntry ("STRING"));
100 target_table.push_back (TargetEntry ("text/plain"));
101 target_table.push_back (TargetEntry ("text/uri-list"));
102 target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
105 // track_canvas.drag_dest_set (target_table, DEST_DEFAULT_ALL, GdkDragAction (Gdk::ACTION_COPY|Gdk::ACTION_MOVE));
106 // track_canvas.signal_drag_data_received().connect (mem_fun(*this, &Editor::track_canvas_drag_data_received));
108 /* stuff for the verbose canvas cursor */
110 Pango::FontDescription font = get_font_for_style (N_("VerboseCanvasCursor"));
112 verbose_canvas_cursor = new ArdourCanvas::Text (*track_canvas.root());
113 verbose_canvas_cursor->property_font_desc() = font;
115 // verbose_canvas_cursor->property_anchor() = GTK_ANCHOR_NW;
116 verbose_canvas_cursor->property_fill_color_rgba() = color_map[cVerboseCanvasCursor];
118 verbose_cursor_visible = false;
120 /* a group to hold time (measure) lines */
122 time_line_group = new ArdourCanvas::Group (*track_canvas.root(), 0.0, 0.0);
123 cursor_group = new ArdourCanvas::Group (*track_canvas.root(), 0.0, 0.0);
125 time_canvas.set_name ("EditorTimeCanvas");
126 time_canvas.add_events (Gdk::POINTER_MOTION_HINT_MASK);
128 meter_group = new ArdourCanvas::Group (*time_canvas.root(), 0.0, 0.0);
129 tempo_group = new ArdourCanvas::Group (*time_canvas.root(), 0.0, 0.0);
130 marker_group = new ArdourCanvas::Group (*time_canvas.root(), 0.0, timebar_height * 2.0);
131 range_marker_group = new ArdourCanvas::Group (*time_canvas.root(), 0.0, timebar_height * 3.0);
132 transport_marker_group = new ArdourCanvas::Group (*time_canvas.root(), 0.0, timebar_height * 4.0);
134 tempo_bar = new ArdourCanvas::SimpleRect (*tempo_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
135 tempo_bar->property_fill_color_rgba() = color_map[cTempoBar];
136 tempo_bar->property_outline_pixels() = 0;
138 meter_bar = new ArdourCanvas::SimpleRect (*meter_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
139 meter_bar->property_fill_color_rgba() = color_map[cMeterBar];
140 meter_bar->property_outline_pixels() = 0;
142 marker_bar = new ArdourCanvas::SimpleRect (*marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
143 marker_bar->property_fill_color_rgba() = color_map[cMarkerBar];
144 marker_bar->property_outline_pixels() = 0;
146 range_marker_bar = new ArdourCanvas::SimpleRect (*range_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
147 range_marker_bar->property_fill_color_rgba() = color_map[cRangeMarkerBar];
148 range_marker_bar->property_outline_pixels() = 0;
150 transport_marker_bar = new ArdourCanvas::SimpleRect (*transport_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
151 transport_marker_bar->property_fill_color_rgba() = color_map[cTransportMarkerBar];
152 transport_marker_bar->property_outline_pixels() = 0;
154 range_bar_drag_rect = new ArdourCanvas::SimpleRect (*range_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
155 range_bar_drag_rect->property_fill_color_rgba() = color_map[cRangeDragBarRectFill];
156 range_bar_drag_rect->property_outline_color_rgba() = color_map[cRangeDragBarRect];
157 range_bar_drag_rect->property_outline_pixels() = 0;
158 range_bar_drag_rect->hide ();
160 transport_bar_drag_rect = new ArdourCanvas::SimpleRect (*transport_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
161 transport_bar_drag_rect ->property_fill_color_rgba() = color_map[cTransportDragRectFill];
162 transport_bar_drag_rect->property_outline_color_rgba() = color_map[cTransportDragRect];
163 transport_bar_drag_rect->property_outline_pixels() = 0;
164 transport_bar_drag_rect->hide ();
166 marker_drag_line_points.push_back(Gnome::Art::Point(0.0, 0.0));
167 marker_drag_line_points.push_back(Gnome::Art::Point(0.0, 0.0));
169 marker_drag_line = new ArdourCanvas::Line (*track_canvas.root());
170 marker_drag_line->property_width_pixels() = 1;
171 marker_drag_line->property_fill_color_rgba() = color_map[cMarkerDragLine];
172 marker_drag_line->property_points() = marker_drag_line_points;
173 marker_drag_line->hide();
175 range_marker_drag_rect = new ArdourCanvas::SimpleRect (*track_canvas.root(), 0.0, 0.0, 0.0, 0.0);
176 range_marker_drag_rect->property_fill_color_rgba() = color_map[cRangeDragRectFill];
177 range_marker_drag_rect->property_outline_color_rgba() = color_map[cRangeDragRect];
178 range_marker_drag_rect->hide ();
180 transport_loop_range_rect = new ArdourCanvas::SimpleRect (*time_line_group, 0.0, 0.0, 0.0, 0.0);
181 transport_loop_range_rect->property_fill_color_rgba() = color_map[cTransportLoopRectFill];
182 transport_loop_range_rect->property_outline_color_rgba() = color_map[cTransportLoopRect];
183 transport_loop_range_rect->property_outline_pixels() = 1;
184 transport_loop_range_rect->hide();
186 transport_punch_range_rect = new ArdourCanvas::SimpleRect (*time_line_group, 0.0, 0.0, 0.0, 0.0);
187 transport_punch_range_rect->property_fill_color_rgba() = color_map[cTransportPunchRectFill];
188 transport_punch_range_rect->property_outline_color_rgba() = color_map[cTransportPunchRect];
189 transport_punch_range_rect->property_outline_pixels() = 0;
190 transport_punch_range_rect->hide();
192 transport_loop_range_rect->lower_to_bottom (); // loop on the bottom
194 transport_punchin_line = new ArdourCanvas::SimpleLine (*time_line_group);
195 transport_punchin_line->property_x1() = 0.0;
196 transport_punchin_line->property_y1() = 0.0;
197 transport_punchin_line->property_x2() = 0.0;
198 transport_punchin_line->property_y2() = 0.0;
199 transport_punchin_line->property_color_rgba() = color_map[cPunchInLine];
200 transport_punchin_line->hide ();
202 transport_punchout_line = new ArdourCanvas::SimpleLine (*time_line_group);
203 transport_punchout_line->property_x1() = 0.0;
204 transport_punchout_line->property_y1() = 0.0;
205 transport_punchout_line->property_x2() = 0.0;
206 transport_punchout_line->property_y2() = 0.0;
207 transport_punchout_line->property_color_rgba() = color_map[cPunchOutLine];
208 transport_punchout_line->hide();
210 // used to show zoom mode active zooming
211 zoom_rect = new ArdourCanvas::SimpleRect (*track_canvas.root(), 0.0, 0.0, 0.0, 0.0);
212 zoom_rect->property_fill_color_rgba() = color_map[cZoomRectFill];
213 zoom_rect->property_outline_color_rgba() = color_map[cZoomRect];
214 zoom_rect->property_outline_pixels() = 1;
217 zoom_rect->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_zoom_rect_event), (ArdourCanvas::Item*) 0));
219 // used as rubberband rect
220 rubberband_rect = new ArdourCanvas::SimpleRect (*track_canvas.root(), 0.0, 0.0, 0.0, 0.0);
221 rubberband_rect->property_outline_color_rgba() = color_map[cRubberBandRect];
222 rubberband_rect->property_fill_color_rgba() = (guint32) color_map[cRubberBandRectFill];
223 rubberband_rect->property_outline_pixels() = 1;
224 rubberband_rect->hide();
226 tempo_bar->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_tempo_bar_event), tempo_bar));
227 meter_bar->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_meter_bar_event), meter_bar));
228 marker_bar->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_marker_bar_event), marker_bar));
229 range_marker_bar->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_range_marker_bar_event), range_marker_bar));
230 transport_marker_bar->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_transport_marker_bar_event), transport_marker_bar));
232 /* separator lines */
234 tempo_line = new ArdourCanvas::SimpleLine (*tempo_group, 0, timebar_height, max_canvas_coordinate, timebar_height);
235 tempo_line->property_color_rgba() = RGBA_TO_UINT (0,0,0,255);
237 meter_line = new ArdourCanvas::SimpleLine (*meter_group, 0, timebar_height, max_canvas_coordinate, timebar_height);
238 meter_line->property_color_rgba() = RGBA_TO_UINT (0,0,0,255);
240 marker_line = new ArdourCanvas::SimpleLine (*marker_group, 0, timebar_height, max_canvas_coordinate, timebar_height);
241 marker_line->property_color_rgba() = RGBA_TO_UINT (0,0,0,255);
243 range_marker_line = new ArdourCanvas::SimpleLine (*range_marker_group, 0, timebar_height, max_canvas_coordinate, timebar_height);
244 range_marker_line->property_color_rgba() = RGBA_TO_UINT (0,0,0,255);
246 transport_marker_line = new ArdourCanvas::SimpleLine (*transport_marker_group, 0, timebar_height, max_canvas_coordinate, timebar_height);
247 transport_marker_line->property_color_rgba() = RGBA_TO_UINT (0,0,0,255);
249 ZoomChanged.connect (bind (mem_fun(*this, &Editor::update_loop_range_view), false));
250 ZoomChanged.connect (bind (mem_fun(*this, &Editor::update_punch_range_view), false));
252 double time_height = timebar_height * 5;
253 double time_width = FLT_MAX/frames_per_unit;
254 time_canvas.set_scroll_region(0.0, 0.0, time_width, time_height);
256 edit_cursor = new Cursor (*this, "blue", &Editor::canvas_edit_cursor_event);
257 playhead_cursor = new Cursor (*this, "red", &Editor::canvas_playhead_cursor_event);
259 track_canvas.signal_size_allocate().connect (mem_fun(*this, &Editor::track_canvas_allocate));
263 Editor::track_canvas_allocate (Gtk::Allocation alloc)
265 static bool first_time = true;
267 canvas_width = alloc.get_width();
268 canvas_height = alloc.get_height();
270 if (session == 0 && !ARDOUR_UI::instance()->will_create_new_session_automatically()) {
272 Pango::FontDescription font = get_font_for_style (N_("FirstActionMessage"));
274 cerr << "font for style = "
275 << font.get_family() << ' '
276 << font.get_size() << ' '
277 << font.get_weight() << ' '
278 << font.get_variant() << ' '
281 const char *txt1 = _("Start a new session\n");
282 const char *txt2 = _("via Session menu");
284 /* this mess of code is here to find out how wide this text is and
285 position the message in the center of the editor window. there
286 are two lines, so we use the longer of the the lines to
287 compute width, and multiply the height by 2.
293 /* this is a dummy widget that exists so that we can get the
294 style from the RC file.
298 Glib::RefPtr<Pango::Layout> layout;
300 top_hbox.pack_start (foo);
301 foo.set_name ("FirstActionMessage");
304 layout = foo.create_pango_layout (_(txt2));
305 layout->set_font_description (font);
306 layout->set_font_description (font);
307 layout->get_pixel_size (pixel_width, pixel_height);
309 top_hbox.remove (foo);
311 if (first_action_message == 0) {
313 char txt[strlen(txt1)+strlen(txt2)+1];
315 /* merge both lines */
317 strcpy (txt, _(txt1));
318 strcat (txt, _(txt2));
320 first_action_message = new ArdourCanvas::Text (*track_canvas.root());
321 first_action_message->property_font_desc() = font;
322 first_action_message->property_fill_color_rgba() = color_map[cFirstActionMessage];
323 first_action_message->property_x() = (gdouble) (canvas_width - pixel_width) / 2.0;
324 first_action_message->property_y() = (gdouble) (canvas_height/2.0) - (2.0 * (pixel_height));
325 first_action_message->property_anchor() = ANCHOR_NORTH_WEST;
326 first_action_message->property_text() = ustring (txt);
331 first_action_message->property_x() = (gdouble) (canvas_width - pixel_width) / 2.0;
332 first_action_message->property_y() = (gdouble) (canvas_height/2.0) - (2.0 * (pixel_height));
336 zoom_range_clock.set ((jack_nframes_t) (canvas_width * frames_per_unit));
337 edit_cursor->set_position (edit_cursor->current_frame);
338 playhead_cursor->set_position (playhead_cursor->current_frame);
339 reset_scrolling_region (&alloc);
341 if (edit_cursor) edit_cursor->set_length (canvas_height);
342 if (playhead_cursor) playhead_cursor->set_length (canvas_height);
344 if (marker_drag_line) {
345 marker_drag_line_points.back().set_x(canvas_height);
346 marker_drag_line->property_points() = marker_drag_line_points;
349 if (range_marker_drag_rect) {
350 range_marker_drag_rect->property_y1() = 0.0;
351 range_marker_drag_rect->property_y2() = (double) canvas_height;
354 if (transport_loop_range_rect) {
355 transport_loop_range_rect->property_y1() = 0.0;
356 transport_loop_range_rect->property_y2() = (double) canvas_height;
359 if (transport_punch_range_rect) {
360 transport_punch_range_rect->property_y1() = 0.0;
361 transport_punch_range_rect->property_y2() = (double) canvas_height;
364 if (transport_punchin_line) {
365 transport_punchin_line->property_y1() = 0.0;
366 transport_punchin_line->property_y2() = (double) canvas_height;
369 if (transport_punchout_line) {
370 transport_punchout_line->property_y1() = 0.0;
371 transport_punchout_line->property_y2() = (double) canvas_height;
374 update_fixed_rulers ();
376 if (is_visible() && first_time) {
377 tempo_map_changed (Change (0));
383 Resized (); /* EMIT_SIGNAL */
387 Editor::reset_scrolling_region (Gtk::Allocation* alloc)
389 guint32 last_canvas_unit;
391 guint32 canvas_alloc_height, canvas_alloc_width;
392 TrackViewList::iterator i;
394 /* We need to make sure that the canvas always has its
395 scrolling region set to larger of:
397 - the size allocated for it (within the container its packed in)
398 - the size required to see the entire session
400 If we don't ensure at least the first of these, the canvas
401 does some wierd and in my view unnecessary stuff to center
402 itself within the allocated area, which causes bad, bad
405 XXX GnomeCanvas has fixed this, and has an option to
406 control the centering behaviour.
410 last_canvas_unit = (guint32) ceil ((float) max_frames / frames_per_unit);
415 for (i = track_views.begin(); i != track_views.end(); ++i) {
416 if ((*i)->control_parent) {
417 height += (*i)->effective_height;
418 height += track_spacing;
423 height -= track_spacing;
427 canvas_height = (guint32) height;
431 canvas_alloc_height = alloc->get_height();
432 canvas_alloc_width = alloc->get_width();
434 canvas_alloc_height = track_canvas.get_height();
435 canvas_alloc_width = track_canvas.get_width();
439 canvas_height = max (canvas_height, canvas_alloc_height);
440 track_canvas.set_scroll_region ( 0.0, 0.0, max (last_canvas_unit, canvas_alloc_width), canvas_height);
444 Editor::track_canvas_map_handler (GdkEventAny* ev)
446 track_canvas_scroller.get_window()->set_cursor (*current_canvas_cursor);
451 Editor::time_canvas_map_handler (GdkEventAny* ev)
453 time_canvas_scroller.get_window()->set_cursor (*timebar_cursor);