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 "gtk2ardour-config.h"
24 #include "gtkmm2ext/utils.h"
26 #include "ardour/profile.h"
27 #include "ardour/rc_configuration.h"
28 #include "ardour/smf_source.h"
30 #include "canvas/canvas.h"
31 #include "canvas/rectangle.h"
32 #include "canvas/pixbuf.h"
33 #include "canvas/text.h"
34 #include "canvas/debug.h"
36 #include "ardour_ui.h"
38 #include "global_signals.h"
40 #include "rgb_macros.h"
42 #include "audio_time_axis.h"
43 #include "editor_drag.h"
44 #include "region_view.h"
45 #include "editor_group_tabs.h"
46 #include "editor_summary.h"
47 #include "video_timeline.h"
49 #include "editor_cursors.h"
50 #include "mouse_cursors.h"
51 #include "verbose_cursor.h"
56 using namespace ARDOUR;
60 using namespace Gtkmm2ext;
61 using namespace Editing;
64 Editor::initialize_canvas ()
66 _track_canvas_viewport = new ArdourCanvas::GtkCanvasViewport (horizontal_adjustment, vertical_adjustment);
67 _track_canvas = _track_canvas_viewport->canvas ();
68 //_track_canvas->set_global_scroll (false);
70 _verbose_cursor = new VerboseCursor (this);
72 /* on the bottom, an image */
74 if (Profile->get_sae()) {
75 Image img (::get_icon (X_("saelogo")));
76 // logo_item = new ArdourCanvas::Pixbuf (_track_canvas->root(), 0.0, 0.0, img.get_pixbuf());
77 // logo_item->property_height_in_pixels() = true;
78 // logo_item->property_width_in_pixels() = true;
79 // logo_item->property_height_set() = true;
80 // logo_item->property_width_set() = true;
81 // logo_item->show ();
84 /*a group to hold global rects like punch/loop indicators */
85 global_rect_group = new ArdourCanvas::Group (_track_canvas->root());
86 CANVAS_DEBUG_NAME (global_rect_group, "global rect group");
88 transport_loop_range_rect = new ArdourCanvas::Rectangle (global_rect_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, ArdourCanvas::COORD_MAX));
89 CANVAS_DEBUG_NAME (transport_loop_range_rect, "loop rect");
90 transport_loop_range_rect->hide();
92 transport_punch_range_rect = new ArdourCanvas::Rectangle (global_rect_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, ArdourCanvas::COORD_MAX));
93 CANVAS_DEBUG_NAME (transport_punch_range_rect, "punch rect");
94 transport_punch_range_rect->hide();
96 /*a group to hold time (measure) lines */
97 time_line_group = new ArdourCanvas::Group (_track_canvas->root());
98 CANVAS_DEBUG_NAME (time_line_group, "time line group");
100 _trackview_group = new ArdourCanvas::Group (_track_canvas->root());
101 //_trackview_group->set_scroll_sensitivity (ArdourCanvas::Group::ScrollSensitivity (ArdourCanvas::Group::ScrollsVertically|ArdourCanvas::Group::ScrollsHorizontally));
102 CANVAS_DEBUG_NAME (_trackview_group, "Canvas TrackViews");
105 /* TIME BAR CANVAS */
107 _time_bars_canvas_viewport = new ArdourCanvas::GtkCanvasViewport (horizontal_adjustment, unused_adjustment);
108 _time_bars_canvas = _time_bars_canvas_viewport->canvas ();
110 _region_motion_group = new ArdourCanvas::Group (_trackview_group);
111 CANVAS_DEBUG_NAME (_region_motion_group, "Canvas Region Motion");
113 meter_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
114 meter_bar = new ArdourCanvas::Rectangle (meter_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
115 CANVAS_DEBUG_NAME (meter_bar, "meter Bar");
116 meter_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
118 tempo_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
119 tempo_bar = new ArdourCanvas::Rectangle (tempo_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
120 CANVAS_DEBUG_NAME (tempo_bar, "Tempo Bar");
121 tempo_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
123 range_marker_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
124 range_marker_bar = new ArdourCanvas::Rectangle (range_marker_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
125 CANVAS_DEBUG_NAME (range_marker_bar, "Range Marker Bar");
126 range_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
128 transport_marker_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
129 transport_marker_bar = new ArdourCanvas::Rectangle (transport_marker_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
130 CANVAS_DEBUG_NAME (transport_marker_bar, "transport Marker Bar");
131 transport_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
133 marker_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
134 marker_bar = new ArdourCanvas::Rectangle (marker_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
135 CANVAS_DEBUG_NAME (marker_bar, "Marker Bar");
136 marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
138 cd_marker_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
139 cd_marker_bar = new ArdourCanvas::Rectangle (cd_marker_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
140 CANVAS_DEBUG_NAME (cd_marker_bar, "CD Marker Bar");
141 cd_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
143 _time_markers_group = new ArdourCanvas::Group (_time_bars_canvas->root());
145 cd_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, 0.0));
146 CANVAS_DEBUG_NAME (cd_marker_group, "cd marker group");
147 /* the vide is temporarily placed a the same location as the
148 cd_marker_group, but is moved later.
150 videotl_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple(0.0, 0.0));
151 CANVAS_DEBUG_NAME (videotl_group, "videotl group");
152 marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, timebar_height + 1.0));
153 CANVAS_DEBUG_NAME (marker_group, "marker group");
154 transport_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 2.0) + 1.0));
155 CANVAS_DEBUG_NAME (transport_marker_group, "transport marker group");
156 range_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 3.0) + 1.0));
157 CANVAS_DEBUG_NAME (range_marker_group, "range marker group");
158 tempo_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 4.0) + 1.0));
159 CANVAS_DEBUG_NAME (tempo_group, "tempo group");
160 meter_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 5.0) + 1.0));
161 CANVAS_DEBUG_NAME (meter_group, "meter group");
163 ARDOUR_UI::instance()->video_timeline = new VideoTimeLine(this, videotl_group, (timebar_height * videotl_bar_height));
165 cd_marker_bar_drag_rect = new ArdourCanvas::Rectangle (cd_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
166 CANVAS_DEBUG_NAME (cd_marker_bar_drag_rect, "cd marker drag");
167 cd_marker_bar_drag_rect->set_outline (false);
168 cd_marker_bar_drag_rect->hide ();
170 range_bar_drag_rect = new ArdourCanvas::Rectangle (range_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
171 CANVAS_DEBUG_NAME (range_bar_drag_rect, "range drag");
172 range_bar_drag_rect->set_outline (false);
173 range_bar_drag_rect->hide ();
175 transport_bar_drag_rect = new ArdourCanvas::Rectangle (transport_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
176 CANVAS_DEBUG_NAME (transport_bar_drag_rect, "transport drag");
177 transport_bar_drag_rect->set_outline (false);
178 transport_bar_drag_rect->hide ();
180 transport_punchin_line = new ArdourCanvas::Line (_track_canvas->root());
181 transport_punchin_line->set_x0 (0);
182 transport_punchin_line->set_y0 (0);
183 transport_punchin_line->set_x1 (0);
184 transport_punchin_line->set_y1 (ArdourCanvas::COORD_MAX);
185 transport_punchin_line->hide ();
187 transport_punchout_line = new ArdourCanvas::Line (_track_canvas->root());
188 transport_punchout_line->set_x0 (0);
189 transport_punchout_line->set_y0 (0);
190 transport_punchout_line->set_x1 (0);
191 transport_punchout_line->set_y1 (ArdourCanvas::COORD_MAX);
192 transport_punchout_line->hide();
194 // used to show zoom mode active zooming
195 zoom_rect = new ArdourCanvas::Rectangle (_track_canvas->root(), ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0));
197 zoom_rect->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_zoom_rect_event), (ArdourCanvas::Item*) 0));
199 // used as rubberband rect
200 rubberband_rect = new ArdourCanvas::Rectangle (_trackview_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0));
201 rubberband_rect->hide();
203 tempo_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_tempo_bar_event), tempo_bar));
204 meter_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_meter_bar_event), meter_bar));
205 marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_marker_bar_event), marker_bar));
206 cd_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_cd_marker_bar_event), cd_marker_bar));
207 videotl_group->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_videotl_bar_event), videotl_group));
208 range_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_range_marker_bar_event), range_marker_bar));
209 transport_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_transport_marker_bar_event), transport_marker_bar));
211 playhead_cursor = new EditorCursor (*this, &Editor::canvas_playhead_cursor_event);
214 logo_item->lower_to_bottom ();
218 _canvas_bottom_rect = new ArdourCanvas::Rectangle (_track_canvas->root(), ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, 20));
219 /* this thing is transparent */
220 _canvas_bottom_rect->set_fill (false);
221 _canvas_bottom_rect->set_outline (false);
222 _canvas_bottom_rect->Event.connect (sigc::mem_fun (*this, &Editor::canvas_bottom_rect_event));
224 /* these signals will initially be delivered to the canvas itself, but if they end up remaining unhandled, they are passed to Editor-level
228 _track_canvas->signal_scroll_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_scroll_event));
229 _track_canvas->signal_motion_notify_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_motion_notify_event));
230 _track_canvas->signal_button_press_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_button_press_event));
231 _track_canvas->signal_button_release_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_button_release_event));
232 _track_canvas->signal_drag_motion().connect (sigc::mem_fun (*this, &Editor::track_canvas_drag_motion));
233 _track_canvas->signal_key_press_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_key_press));
234 _track_canvas->signal_key_release_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_key_release));
236 _track_canvas->set_name ("EditorMainCanvas");
237 _track_canvas->add_events (Gdk::POINTER_MOTION_HINT_MASK | Gdk::SCROLL_MASK | Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK);
238 _track_canvas->signal_leave_notify_event().connect (sigc::mem_fun(*this, &Editor::left_track_canvas), false);
239 _track_canvas->signal_enter_notify_event().connect (sigc::mem_fun(*this, &Editor::entered_track_canvas), false);
240 _track_canvas->set_flags (CAN_FOCUS);
242 /* set up drag-n-drop */
244 vector<TargetEntry> target_table;
246 // Drag-N-Drop from the region list can generate this target
247 target_table.push_back (TargetEntry ("regions"));
249 target_table.push_back (TargetEntry ("text/plain"));
250 target_table.push_back (TargetEntry ("text/uri-list"));
251 target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
253 _track_canvas->drag_dest_set (target_table);
254 _track_canvas->signal_drag_data_received().connect (sigc::mem_fun(*this, &Editor::track_canvas_drag_data_received));
256 _track_canvas_viewport->signal_size_allocate().connect (sigc::mem_fun(*this, &Editor::track_canvas_viewport_allocate));
258 ColorsChanged.connect (sigc::mem_fun (*this, &Editor::color_handler));
264 Editor::track_canvas_viewport_allocate (Gtk::Allocation alloc)
266 _canvas_viewport_allocation = alloc;
267 track_canvas_viewport_size_allocated ();
271 Editor::track_canvas_viewport_size_allocated ()
273 bool height_changed = _visible_canvas_height != _canvas_viewport_allocation.get_height();
275 _visible_canvas_width = _canvas_viewport_allocation.get_width ();
276 _visible_canvas_height = _canvas_viewport_allocation.get_height ();
280 if (height_changed) {
282 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
283 i->second->canvas_height_set (_visible_canvas_height);
286 vertical_adjustment.set_page_size (_visible_canvas_height);
287 if ((vertical_adjustment.get_value() + _visible_canvas_height) >= vertical_adjustment.get_upper()) {
289 We're increasing the size of the canvas while the bottom is visible.
290 We scroll down to keep in step with the controls layout.
292 vertical_adjustment.set_value (_full_canvas_height - _visible_canvas_height);
295 set_visible_track_count (_visible_track_count);
298 update_fixed_rulers();
299 redisplay_tempo (false);
300 _summary->set_overlays_dirty ();
304 Editor::reset_controls_layout_width ()
309 edit_controls_vbox.size_request (req);
312 if (_group_tabs->is_mapped()) {
313 _group_tabs->size_request (req);
317 /* the controls layout has no horizontal scrolling, its visible
318 width is always equal to the total width of its contents.
321 controls_layout.property_width() = w;
322 controls_layout.property_width_request() = w;
326 Editor::reset_controls_layout_height (int32_t h)
328 /* ensure that the rect that represents the "bottom" of the canvas
329 * (the drag-n-drop zone) is, in fact, at the bottom.
332 _canvas_bottom_rect->set_position (ArdourCanvas::Duple (0, h));
334 /* track controls layout must span the full height of "h" (all tracks)
335 * plus the bottom rect.
338 h += _canvas_bottom_rect->height ();
340 /* set the height of the scrollable area (i.e. the sum of all contained widgets)
341 * for the controls layout. The size request is set elsewhere.
344 controls_layout.property_height() = h;
349 Editor::track_canvas_map_handler (GdkEventAny* /*ev*/)
351 if (current_canvas_cursor) {
352 set_canvas_cursor (current_canvas_cursor);
357 /** This is called when something is dropped onto the track canvas */
359 Editor::track_canvas_drag_data_received (const RefPtr<Gdk::DragContext>& context,
361 const SelectionData& data,
362 guint info, guint time)
364 if (data.get_target() == "regions") {
365 drop_regions (context, x, y, data, info, time);
367 drop_paths (context, x, y, data, info, time);
372 Editor::idle_drop_paths (vector<string> paths, framepos_t frame, double ypos, bool copy)
374 drop_paths_part_two (paths, frame, ypos, copy);
379 Editor::drop_paths_part_two (const vector<string>& paths, framepos_t frame, double ypos, bool copy)
381 RouteTimeAxisView* tv;
383 /* MIDI files must always be imported, because we consider them
384 * writable. So split paths into two vectors, and follow the import
385 * path on the MIDI part.
388 vector<string> midi_paths;
389 vector<string> audio_paths;
391 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
392 if (SMFSource::safe_midi_file_extension (*i)) {
393 midi_paths.push_back (*i);
395 audio_paths.push_back (*i);
400 std::pair<TimeAxisView*, int> const tvp = trackview_by_y_position (ypos);
401 if (tvp.first == 0) {
403 /* drop onto canvas background: create new tracks */
407 do_import (midi_paths, Editing::ImportDistinctFiles, ImportAsTrack, SrcBest, frame);
409 if (Profile->get_sae() || Config->get_only_copy_imported_files() || copy) {
410 do_import (audio_paths, Editing::ImportDistinctFiles, Editing::ImportAsTrack, SrcBest, frame);
412 do_embed (audio_paths, Editing::ImportDistinctFiles, ImportAsTrack, frame);
415 } else if ((tv = dynamic_cast<RouteTimeAxisView*> (tvp.first)) != 0) {
417 /* check that its a track, not a bus */
420 /* select the track, then embed/import */
423 do_import (midi_paths, Editing::ImportSerializeFiles, ImportToTrack, SrcBest, frame);
425 if (Profile->get_sae() || Config->get_only_copy_imported_files() || copy) {
426 do_import (audio_paths, Editing::ImportSerializeFiles, Editing::ImportToTrack, SrcBest, frame);
428 do_embed (audio_paths, Editing::ImportSerializeFiles, ImportToTrack, frame);
435 Editor::drop_paths (const RefPtr<Gdk::DragContext>& context,
437 const SelectionData& data,
438 guint info, guint time)
440 vector<string> paths;
445 if (convert_drop_to_paths (paths, context, x, y, data, info, time) == 0) {
447 /* D-n-D coordinates are window-relative, so convert to "world" coordinates
450 ev.type = GDK_BUTTON_RELEASE;
454 frame = window_event_sample (&ev, 0, &cy);
458 bool copy = ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY);
460 /* We are not allowed to call recursive main event loops from within
461 the main event loop with GTK/Quartz. Since import/embed wants
462 to push up a progress dialog, defer all this till we go idle.
464 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun (*this, &Editor::idle_drop_paths), paths, frame, cy, copy));
466 drop_paths_part_two (paths, frame, cy, copy);
470 context->drag_finish (true, false, time);
473 /** @param allow_horiz true to allow horizontal autoscroll, otherwise false.
475 * @param allow_vert true to allow vertical autoscroll, otherwise false.
479 Editor::maybe_autoscroll (bool allow_horiz, bool allow_vert, bool from_headers)
481 if (!Config->get_autoscroll_editor ()) {
486 ArdourCanvas::Rect scrolling_boundary;
487 Gtk::Allocation alloc;
490 alloc = controls_layout.get_allocation ();
492 alloc = _track_canvas_viewport->get_allocation ();
494 /* the effective width of the autoscroll boundary so
495 that we start scrolling before we hit the edge.
497 this helps when the window is slammed up against the
498 right edge of the screen, making it hard to scroll
502 if (alloc.get_width() > 20) {
503 alloc.set_width (alloc.get_width() - 20);
504 alloc.set_x (alloc.get_x() + 10);
508 scrolling_boundary = ArdourCanvas::Rect (alloc.get_x(), alloc.get_y(),
509 alloc.get_x() + alloc.get_width(),
510 alloc.get_y() + alloc.get_height());
513 Gdk::ModifierType mask;
515 get_window()->get_pointer (x, y, mask);
517 if ((allow_horiz && (x < scrolling_boundary.x0 || x >= scrolling_boundary.x1)) ||
518 (allow_vert && (y < scrolling_boundary.y0 || y >= scrolling_boundary.y1))) {
519 start_canvas_autoscroll (allow_horiz, allow_vert, scrolling_boundary);
524 Editor::autoscroll_active () const
526 return autoscroll_connection.connected ();
530 Editor::autoscroll_canvas ()
533 Gdk::ModifierType mask;
534 frameoffset_t dx = 0;
535 bool no_stop = false;
536 bool y_motion = false;
538 get_window()->get_pointer (x, y, mask);
542 if (autoscroll_horizontal_allowed) {
544 framepos_t new_frame = leftmost_frame;
548 if (x > autoscroll_boundary.x1) {
550 /* bring it back into view */
551 dx = x - autoscroll_boundary.x1;
552 dx += 10 + (2 * (autoscroll_cnt/2));
554 dx = pixel_to_sample (dx);
556 if (leftmost_frame < max_framepos - dx) {
557 new_frame = leftmost_frame + dx;
559 new_frame = max_framepos;
564 } else if (x < autoscroll_boundary.x0) {
566 dx = autoscroll_boundary.x0 - x;
567 dx += 10 + (2 * (autoscroll_cnt/2));
569 dx = pixel_to_sample (dx);
571 if (leftmost_frame >= dx) {
572 new_frame = leftmost_frame - dx;
580 if (new_frame != leftmost_frame) {
581 vc.time_origin = new_frame;
582 vc.add (VisualChange::TimeOrigin);
586 if (autoscroll_vertical_allowed) {
588 const double vertical_pos = vertical_adjustment.get_value();
589 double new_pixel = vertical_pos;
590 const int speed_factor = 20;
594 new_pixel = vertical_pos;
596 if (y < autoscroll_boundary.y0) {
598 /* scroll to make higher tracks visible */
600 if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
601 y_motion = scroll_up_one_track ();
604 } else if (y > autoscroll_boundary.y1) {
606 if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
607 y_motion = scroll_down_one_track ();
617 /* change horizontal first */
623 /* now send a motion event to notify anyone who cares
624 that we have moved to a new location (because we scrolled)
629 ev.type = GDK_MOTION_NOTIFY;
630 ev.state = Gdk::BUTTON1_MASK;
632 /* the motion handler expects events in canvas coordinate space */
634 /* first convert from Editor window coordinates to canvas
641 /* clamp x and y to remain within the visible area */
643 x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1);
644 y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1);
646 translate_coordinates (*_track_canvas_viewport, x, y, cx, cy);
648 ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy));
652 motion_handler (0, (GdkEvent*) &ev, true);
654 } else if (no_stop) {
656 /* not changing visual state but pointer is outside the scrolling boundary
657 * so we still need to deliver a fake motion event
662 ev.type = GDK_MOTION_NOTIFY;
663 ev.state = Gdk::BUTTON1_MASK;
665 /* the motion handler expects events in canvas coordinate space */
667 /* first convert from Editor window coordinates to canvas
674 /* clamp x and y to remain within the visible area. except
675 * .. if horizontal scrolling is allowed, always allow us to
679 if (autoscroll_horizontal_allowed) {
680 x = min (max ((ArdourCanvas::Coord) x, 0.0), autoscroll_boundary.x1);
682 x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1);
684 y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1);
686 translate_coordinates (*_track_canvas_viewport, x, y, cx, cy);
688 ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy));
692 motion_handler (0, (GdkEvent*) &ev, true);
695 stop_canvas_autoscroll ();
701 return true; /* call me again */
705 Editor::start_canvas_autoscroll (bool allow_horiz, bool allow_vert, const ArdourCanvas::Rect& boundary)
711 stop_canvas_autoscroll ();
714 autoscroll_horizontal_allowed = allow_horiz;
715 autoscroll_vertical_allowed = allow_vert;
716 autoscroll_boundary = boundary;
718 /* do the first scroll right now
721 autoscroll_canvas ();
723 /* scroll again at very very roughly 30FPS */
725 autoscroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::autoscroll_canvas), 30);
729 Editor::stop_canvas_autoscroll ()
731 autoscroll_connection.disconnect ();
735 Editor::left_track_canvas (GdkEventCrossing */*ev*/)
738 within_track_canvas = false;
739 set_entered_track (0);
740 set_entered_regionview (0);
741 reset_canvas_action_sensitivity (false);
746 Editor::entered_track_canvas (GdkEventCrossing */*ev*/)
748 within_track_canvas = true;
749 reset_canvas_action_sensitivity (true);
754 Editor::_ensure_time_axis_view_is_visible (const TimeAxisView& tav, bool at_top)
756 double begin = tav.y_position();
757 double v = vertical_adjustment.get_value ();
759 if (!at_top && (begin < v || begin + tav.current_height() > v + _visible_canvas_height)) {
760 /* try to put the TimeAxisView roughly central */
761 if (begin >= _visible_canvas_height/2.0) {
762 begin -= _visible_canvas_height/2.0;
766 /* Clamp the y pos so that we do not extend beyond the canvas full
769 if (_full_canvas_height - begin < _visible_canvas_height){
770 begin = _full_canvas_height - _visible_canvas_height;
773 vertical_adjustment.set_value (begin);
776 /** Called when the main vertical_adjustment has changed */
778 Editor::tie_vertical_scrolling ()
780 if (pending_visual_change.idle_handler_id < 0) {
781 _summary->set_overlays_dirty ();
786 Editor::set_horizontal_position (double p)
788 horizontal_adjustment.set_value (p);
790 leftmost_frame = (framepos_t) floor (p * samples_per_pixel);
792 update_fixed_rulers ();
793 redisplay_tempo (true);
795 if (pending_visual_change.idle_handler_id < 0) {
796 _summary->set_overlays_dirty ();
799 update_video_timeline();
803 Editor::color_handler()
805 playhead_cursor->set_color (ARDOUR_UI::config()->get_canvasvar_PlayHead());
806 _verbose_cursor->set_color (ARDOUR_UI::config()->get_canvasvar_VerboseCanvasCursor());
808 meter_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_MeterBar());
809 meter_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
811 tempo_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TempoBar());
812 tempo_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
814 marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_MarkerBar());
815 marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
817 cd_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CDMarkerBar());
818 cd_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
820 range_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeMarkerBar());
821 range_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
823 transport_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportMarkerBar());
824 transport_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
826 cd_marker_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
827 cd_marker_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
829 range_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
830 range_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
832 transport_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportDragRect());
833 transport_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportDragRect());
835 transport_loop_range_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportLoopRect());
836 transport_loop_range_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportLoopRect());
838 transport_punch_range_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportPunchRect());
839 transport_punch_range_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportPunchRect());
841 transport_punchin_line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_PunchLine());
842 transport_punchout_line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_PunchLine());
844 zoom_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_ZoomRect());
845 zoom_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_ZoomRect());
847 rubberband_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RubberBandRect());
848 rubberband_rect->set_fill_color ((guint32) ARDOUR_UI::config()->get_canvasvar_RubberBandRect());
850 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
851 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
852 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
853 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
854 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
856 refresh_location_display ();
858 redisplay_tempo (true);
861 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks); // redraw metric markers
866 Editor::horizontal_position () const
868 return sample_to_pixel (leftmost_frame);
872 Editor::set_canvas_cursor (Gdk::Cursor* cursor, bool save)
875 current_canvas_cursor = cursor;
878 Glib::RefPtr<Gdk::Window> win = _track_canvas->get_window();
881 _track_canvas->get_window()->set_cursor (*cursor);
886 Editor::track_canvas_key_press (GdkEventKey*)
888 /* XXX: event does not report the modifier key pressed down, AFAICS, so use the Keyboard object instead */
889 if (mouse_mode == Editing::MouseZoom && Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
890 set_canvas_cursor (_cursors->zoom_out, true);
897 Editor::track_canvas_key_release (GdkEventKey*)
899 if (mouse_mode == Editing::MouseZoom && !Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
900 set_canvas_cursor (_cursors->zoom_in, true);
907 Editor::clamp_verbose_cursor_x (double x)
912 x = min (_visible_canvas_width - 200.0, x);
918 Editor::clamp_verbose_cursor_y (double y)
921 y = min (_visible_canvas_height - 50, y);
926 Editor::get_time_bars_group () const
928 return _time_bars_canvas->root();
932 Editor::get_track_canvas_group() const
934 return _track_canvas->root();
937 ArdourCanvas::GtkCanvasViewport*
938 Editor::get_time_bars_canvas() const
940 return _time_bars_canvas_viewport;
943 ArdourCanvas::GtkCanvasViewport*
944 Editor::get_track_canvas() const
946 return _track_canvas_viewport;