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/scroll_group.h"
34 #include "canvas/text.h"
35 #include "canvas/debug.h"
37 #include "ardour_ui.h"
39 #include "global_signals.h"
41 #include "rgb_macros.h"
43 #include "audio_time_axis.h"
44 #include "editor_drag.h"
45 #include "region_view.h"
46 #include "editor_group_tabs.h"
47 #include "editor_summary.h"
48 #include "video_timeline.h"
50 #include "editor_cursors.h"
51 #include "mouse_cursors.h"
52 #include "verbose_cursor.h"
57 using namespace ARDOUR;
61 using namespace Gtkmm2ext;
62 using namespace Editing;
65 Editor::initialize_canvas ()
67 _track_canvas_viewport = new ArdourCanvas::GtkCanvasViewport (horizontal_adjustment, vertical_adjustment);
68 _track_canvas = _track_canvas_viewport->canvas ();
70 ArdourCanvas::ScrollGroup* hsg;
71 ArdourCanvas::ScrollGroup* hg;
72 ArdourCanvas::ScrollGroup* vg;
74 hv_scroll_group = hsg = new ArdourCanvas::ScrollGroup (_track_canvas->root(),
75 ArdourCanvas::ScrollGroup::ScrollSensitivity (ArdourCanvas::ScrollGroup::ScrollsVertically|
76 ArdourCanvas::ScrollGroup::ScrollsHorizontally));
77 CANVAS_DEBUG_NAME (hv_scroll_group, "canvas hv scroll");
78 _track_canvas->add_scroller (*hsg);
80 v_scroll_group = vg = new ArdourCanvas::ScrollGroup (_track_canvas->root(), ArdourCanvas::ScrollGroup::ScrollsVertically);
81 CANVAS_DEBUG_NAME (v_scroll_group, "canvas v scroll");
82 _track_canvas->add_scroller (*vg);
84 h_scroll_group = hg = new ArdourCanvas::ScrollGroup (_track_canvas->root(), ArdourCanvas::ScrollGroup::ScrollsHorizontally);
85 CANVAS_DEBUG_NAME (h_scroll_group, "canvas h scroll");
86 _track_canvas->add_scroller (*hg);
88 _verbose_cursor = new VerboseCursor (this);
90 /* on the bottom, an image */
92 if (Profile->get_sae()) {
93 Image img (::get_icon (X_("saelogo")));
94 // logo_item = new ArdourCanvas::Pixbuf (_track_canvas->root(), 0.0, 0.0, img.get_pixbuf());
95 // logo_item->property_height_in_pixels() = true;
96 // logo_item->property_width_in_pixels() = true;
97 // logo_item->property_height_set() = true;
98 // logo_item->property_width_set() = true;
99 // logo_item->show ();
102 /*a group to hold global rects like punch/loop indicators */
103 global_rect_group = new ArdourCanvas::Group (hv_scroll_group);
104 CANVAS_DEBUG_NAME (global_rect_group, "global rect group");
106 transport_loop_range_rect = new ArdourCanvas::Rectangle (global_rect_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, ArdourCanvas::COORD_MAX));
107 CANVAS_DEBUG_NAME (transport_loop_range_rect, "loop rect");
108 transport_loop_range_rect->hide();
110 transport_punch_range_rect = new ArdourCanvas::Rectangle (global_rect_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, ArdourCanvas::COORD_MAX));
111 CANVAS_DEBUG_NAME (transport_punch_range_rect, "punch rect");
112 transport_punch_range_rect->hide();
114 /*a group to hold time (measure) lines */
115 time_line_group = new ArdourCanvas::Group (hv_scroll_group);
116 CANVAS_DEBUG_NAME (time_line_group, "time line group");
118 _trackview_group = new ArdourCanvas::Group (hv_scroll_group);
119 CANVAS_DEBUG_NAME (_trackview_group, "Canvas TrackViews");
121 // used to show zoom mode active zooming
122 zoom_rect = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0));
124 zoom_rect->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_zoom_rect_event), (ArdourCanvas::Item*) 0));
126 // used as rubberband rect
127 rubberband_rect = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0));
128 rubberband_rect->hide();
130 /* a group to hold stuff while it gets dragged around. Must be the
131 * uppermost (last) group with hv_scroll_group as a parent
133 _drag_motion_group = new ArdourCanvas::Group (hv_scroll_group);
134 CANVAS_DEBUG_NAME (_drag_motion_group, "Canvas Drag Motion");
136 /* TIME BAR CANVAS */
138 _time_markers_group = new ArdourCanvas::Group (h_scroll_group);
139 CANVAS_DEBUG_NAME (_time_markers_group, "time bars");
141 cd_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, 0.0));
142 CANVAS_DEBUG_NAME (cd_marker_group, "cd marker group");
143 /* the vide is temporarily placed a the same location as the
144 cd_marker_group, but is moved later.
146 videotl_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple(0.0, 0.0));
147 CANVAS_DEBUG_NAME (videotl_group, "videotl group");
148 marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, timebar_height + 1.0));
149 CANVAS_DEBUG_NAME (marker_group, "marker group");
150 transport_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 2.0) + 1.0));
151 CANVAS_DEBUG_NAME (transport_marker_group, "transport marker group");
152 range_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 3.0) + 1.0));
153 CANVAS_DEBUG_NAME (range_marker_group, "range marker group");
154 tempo_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 4.0) + 1.0));
155 CANVAS_DEBUG_NAME (tempo_group, "tempo group");
156 meter_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 5.0) + 1.0));
157 CANVAS_DEBUG_NAME (meter_group, "meter group");
159 meter_bar = new ArdourCanvas::Rectangle (meter_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
160 CANVAS_DEBUG_NAME (meter_bar, "meter Bar");
161 meter_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
163 tempo_bar = new ArdourCanvas::Rectangle (tempo_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
164 CANVAS_DEBUG_NAME (tempo_bar, "Tempo Bar");
165 tempo_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
167 range_marker_bar = new ArdourCanvas::Rectangle (range_marker_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
168 CANVAS_DEBUG_NAME (range_marker_bar, "Range Marker Bar");
169 range_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
171 transport_marker_bar = new ArdourCanvas::Rectangle (transport_marker_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
172 CANVAS_DEBUG_NAME (transport_marker_bar, "transport Marker Bar");
173 transport_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
175 marker_bar = new ArdourCanvas::Rectangle (marker_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
176 CANVAS_DEBUG_NAME (marker_bar, "Marker Bar");
177 marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
179 cd_marker_bar = new ArdourCanvas::Rectangle (cd_marker_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
180 CANVAS_DEBUG_NAME (cd_marker_bar, "CD Marker Bar");
181 cd_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
183 ARDOUR_UI::instance()->video_timeline = new VideoTimeLine(this, videotl_group, (timebar_height * videotl_bar_height));
185 cd_marker_bar_drag_rect = new ArdourCanvas::Rectangle (cd_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
186 CANVAS_DEBUG_NAME (cd_marker_bar_drag_rect, "cd marker drag");
187 cd_marker_bar_drag_rect->set_outline (false);
188 cd_marker_bar_drag_rect->hide ();
190 range_bar_drag_rect = new ArdourCanvas::Rectangle (range_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
191 CANVAS_DEBUG_NAME (range_bar_drag_rect, "range drag");
192 range_bar_drag_rect->set_outline (false);
193 range_bar_drag_rect->hide ();
195 transport_bar_drag_rect = new ArdourCanvas::Rectangle (transport_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
196 CANVAS_DEBUG_NAME (transport_bar_drag_rect, "transport drag");
197 transport_bar_drag_rect->set_outline (false);
198 transport_bar_drag_rect->hide ();
200 transport_punchin_line = new ArdourCanvas::Line (hv_scroll_group);
201 transport_punchin_line->set_x0 (0);
202 transport_punchin_line->set_y0 (0);
203 transport_punchin_line->set_x1 (0);
204 transport_punchin_line->set_y1 (ArdourCanvas::COORD_MAX);
205 transport_punchin_line->hide ();
207 transport_punchout_line = new ArdourCanvas::Line (hv_scroll_group);
208 transport_punchout_line->set_x0 (0);
209 transport_punchout_line->set_y0 (0);
210 transport_punchout_line->set_x1 (0);
211 transport_punchout_line->set_y1 (ArdourCanvas::COORD_MAX);
212 transport_punchout_line->hide();
214 tempo_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_tempo_bar_event), tempo_bar));
215 meter_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_meter_bar_event), meter_bar));
216 marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_marker_bar_event), marker_bar));
217 cd_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_cd_marker_bar_event), cd_marker_bar));
218 videotl_group->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_videotl_bar_event), videotl_group));
219 range_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_range_marker_bar_event), range_marker_bar));
220 transport_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_transport_marker_bar_event), transport_marker_bar));
222 playhead_cursor = new EditorCursor (*this, &Editor::canvas_playhead_cursor_event);
225 logo_item->lower_to_bottom ();
229 _canvas_drop_zone = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, 0.0));
230 /* this thing is transparent */
231 _canvas_drop_zone->set_fill (false);
232 _canvas_drop_zone->set_outline (false);
233 _canvas_drop_zone->Event.connect (sigc::mem_fun (*this, &Editor::canvas_drop_zone_event));
235 /* these signals will initially be delivered to the canvas itself, but if they end up remaining unhandled, they are passed to Editor-level
239 _track_canvas->signal_scroll_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_scroll_event));
240 _track_canvas->signal_motion_notify_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_motion_notify_event));
241 _track_canvas->signal_button_press_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_button_press_event));
242 _track_canvas->signal_button_release_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_button_release_event));
243 _track_canvas->signal_drag_motion().connect (sigc::mem_fun (*this, &Editor::track_canvas_drag_motion));
244 _track_canvas->signal_key_press_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_key_press));
245 _track_canvas->signal_key_release_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_key_release));
247 _track_canvas->set_name ("EditorMainCanvas");
248 _track_canvas->add_events (Gdk::POINTER_MOTION_HINT_MASK | Gdk::SCROLL_MASK | Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK);
249 _track_canvas->signal_leave_notify_event().connect (sigc::mem_fun(*this, &Editor::left_track_canvas), false);
250 _track_canvas->signal_enter_notify_event().connect (sigc::mem_fun(*this, &Editor::entered_track_canvas), false);
251 _track_canvas->set_flags (CAN_FOCUS);
253 /* set up drag-n-drop */
255 vector<TargetEntry> target_table;
257 // Drag-N-Drop from the region list can generate this target
258 target_table.push_back (TargetEntry ("regions"));
260 target_table.push_back (TargetEntry ("text/plain"));
261 target_table.push_back (TargetEntry ("text/uri-list"));
262 target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
264 _track_canvas->drag_dest_set (target_table);
265 _track_canvas->signal_drag_data_received().connect (sigc::mem_fun(*this, &Editor::track_canvas_drag_data_received));
267 _track_canvas_viewport->signal_size_allocate().connect (sigc::mem_fun(*this, &Editor::track_canvas_viewport_allocate));
269 ColorsChanged.connect (sigc::mem_fun (*this, &Editor::color_handler));
275 Editor::track_canvas_viewport_allocate (Gtk::Allocation alloc)
277 _canvas_viewport_allocation = alloc;
278 track_canvas_viewport_size_allocated ();
282 Editor::track_canvas_viewport_size_allocated ()
284 bool height_changed = _visible_canvas_height != _canvas_viewport_allocation.get_height();
286 _visible_canvas_width = _canvas_viewport_allocation.get_width ();
287 _visible_canvas_height = _canvas_viewport_allocation.get_height ();
289 _canvas_drop_zone->set_y1 (_canvas_drop_zone->y0() + (_visible_canvas_height - 20.0));
293 if (height_changed) {
295 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
296 i->second->canvas_height_set (_visible_canvas_height);
299 vertical_adjustment.set_page_size (_visible_canvas_height);
300 if ((vertical_adjustment.get_value() + _visible_canvas_height) >= vertical_adjustment.get_upper()) {
302 We're increasing the size of the canvas while the bottom is visible.
303 We scroll down to keep in step with the controls layout.
305 vertical_adjustment.set_value (_full_canvas_height - _visible_canvas_height);
308 set_visible_track_count (_visible_track_count);
311 update_fixed_rulers();
312 redisplay_tempo (false);
313 _summary->set_overlays_dirty ();
317 Editor::reset_controls_layout_width ()
322 edit_controls_vbox.size_request (req);
325 if (_group_tabs->is_mapped()) {
326 _group_tabs->size_request (req);
330 /* the controls layout has no horizontal scrolling, its visible
331 width is always equal to the total width of its contents.
334 controls_layout.property_width() = w;
335 controls_layout.property_width_request() = w;
339 Editor::reset_controls_layout_height (int32_t h)
341 /* ensure that the rect that represents the "bottom" of the canvas
342 * (the drag-n-drop zone) is, in fact, at the bottom.
345 _canvas_drop_zone->set_position (ArdourCanvas::Duple (0, h));
347 /* track controls layout must span the full height of "h" (all tracks)
348 * plus the bottom rect.
351 h += _canvas_drop_zone->height ();
353 /* set the height of the scrollable area (i.e. the sum of all contained widgets)
354 * for the controls layout. The size request is set elsewhere.
357 controls_layout.property_height() = h;
362 Editor::track_canvas_map_handler (GdkEventAny* /*ev*/)
364 if (current_canvas_cursor) {
365 set_canvas_cursor (current_canvas_cursor);
370 /** This is called when something is dropped onto the track canvas */
372 Editor::track_canvas_drag_data_received (const RefPtr<Gdk::DragContext>& context,
374 const SelectionData& data,
375 guint info, guint time)
377 if (data.get_target() == "regions") {
378 drop_regions (context, x, y, data, info, time);
380 drop_paths (context, x, y, data, info, time);
385 Editor::idle_drop_paths (vector<string> paths, framepos_t frame, double ypos, bool copy)
387 drop_paths_part_two (paths, frame, ypos, copy);
392 Editor::drop_paths_part_two (const vector<string>& paths, framepos_t frame, double ypos, bool copy)
394 RouteTimeAxisView* tv;
396 /* MIDI files must always be imported, because we consider them
397 * writable. So split paths into two vectors, and follow the import
398 * path on the MIDI part.
401 vector<string> midi_paths;
402 vector<string> audio_paths;
404 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
405 if (SMFSource::safe_midi_file_extension (*i)) {
406 midi_paths.push_back (*i);
408 audio_paths.push_back (*i);
413 std::pair<TimeAxisView*, int> const tvp = trackview_by_y_position (ypos);
414 if (tvp.first == 0) {
416 /* drop onto canvas background: create new tracks */
420 do_import (midi_paths, Editing::ImportDistinctFiles, ImportAsTrack, SrcBest, frame);
422 if (Profile->get_sae() || Config->get_only_copy_imported_files() || copy) {
423 do_import (audio_paths, Editing::ImportDistinctFiles, Editing::ImportAsTrack, SrcBest, frame);
425 do_embed (audio_paths, Editing::ImportDistinctFiles, ImportAsTrack, frame);
428 } else if ((tv = dynamic_cast<RouteTimeAxisView*> (tvp.first)) != 0) {
430 /* check that its a track, not a bus */
433 /* select the track, then embed/import */
436 do_import (midi_paths, Editing::ImportSerializeFiles, ImportToTrack, SrcBest, frame);
438 if (Profile->get_sae() || Config->get_only_copy_imported_files() || copy) {
439 do_import (audio_paths, Editing::ImportSerializeFiles, Editing::ImportToTrack, SrcBest, frame);
441 do_embed (audio_paths, Editing::ImportSerializeFiles, ImportToTrack, frame);
448 Editor::drop_paths (const RefPtr<Gdk::DragContext>& context,
450 const SelectionData& data,
451 guint info, guint time)
453 vector<string> paths;
458 if (convert_drop_to_paths (paths, context, x, y, data, info, time) == 0) {
460 /* D-n-D coordinates are window-relative, so convert to canvas coordinates
463 ev.type = GDK_BUTTON_RELEASE;
467 frame = window_event_sample (&ev, 0, &cy);
471 bool copy = ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY);
473 /* We are not allowed to call recursive main event loops from within
474 the main event loop with GTK/Quartz. Since import/embed wants
475 to push up a progress dialog, defer all this till we go idle.
477 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun (*this, &Editor::idle_drop_paths), paths, frame, cy, copy));
479 drop_paths_part_two (paths, frame, cy, copy);
483 context->drag_finish (true, false, time);
486 /** @param allow_horiz true to allow horizontal autoscroll, otherwise false.
488 * @param allow_vert true to allow vertical autoscroll, otherwise false.
492 Editor::maybe_autoscroll (bool allow_horiz, bool allow_vert, bool from_headers)
494 if (!Config->get_autoscroll_editor ()) {
498 ArdourCanvas::Rect scrolling_boundary;
499 Gtk::Allocation alloc;
502 alloc = controls_layout.get_allocation ();
504 alloc = _track_canvas_viewport->get_allocation ();
506 /* the effective width of the autoscroll boundary so
507 that we start scrolling before we hit the edge.
509 this helps when the window is slammed up against the
510 right edge of the screen, making it hard to scroll
514 if (alloc.get_width() > 20) {
515 alloc.set_width (alloc.get_width() - 20);
516 alloc.set_x (alloc.get_x() + 10);
520 scrolling_boundary = ArdourCanvas::Rect (alloc.get_x(), alloc.get_y(),
521 alloc.get_x() + alloc.get_width(),
522 alloc.get_y() + alloc.get_height());
525 Gdk::ModifierType mask;
527 get_window()->get_pointer (x, y, mask);
529 if ((allow_horiz && (x < scrolling_boundary.x0 || x >= scrolling_boundary.x1)) ||
530 (allow_vert && (y < scrolling_boundary.y0 || y >= scrolling_boundary.y1))) {
531 start_canvas_autoscroll (allow_horiz, allow_vert, scrolling_boundary);
536 Editor::autoscroll_active () const
538 return autoscroll_connection.connected ();
542 Editor::autoscroll_canvas ()
545 Gdk::ModifierType mask;
546 frameoffset_t dx = 0;
547 bool no_stop = false;
548 bool y_motion = false;
550 get_window()->get_pointer (x, y, mask);
554 if (autoscroll_horizontal_allowed) {
556 framepos_t new_frame = leftmost_frame;
560 if (x > autoscroll_boundary.x1) {
562 /* bring it back into view */
563 dx = x - autoscroll_boundary.x1;
564 dx += 10 + (2 * (autoscroll_cnt/2));
566 dx = pixel_to_sample (dx);
568 if (leftmost_frame < max_framepos - dx) {
569 new_frame = leftmost_frame + dx;
571 new_frame = max_framepos;
576 } else if (x < autoscroll_boundary.x0) {
578 dx = autoscroll_boundary.x0 - x;
579 dx += 10 + (2 * (autoscroll_cnt/2));
581 dx = pixel_to_sample (dx);
583 if (leftmost_frame >= dx) {
584 new_frame = leftmost_frame - dx;
592 if (new_frame != leftmost_frame) {
593 vc.time_origin = new_frame;
594 vc.add (VisualChange::TimeOrigin);
598 if (autoscroll_vertical_allowed) {
600 const double vertical_pos = vertical_adjustment.get_value();
601 const int speed_factor = 20;
605 if (y < autoscroll_boundary.y0) {
607 /* scroll to make higher tracks visible */
609 if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
610 y_motion = scroll_up_one_track ();
613 } else if (y > autoscroll_boundary.y1) {
615 if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
616 y_motion = scroll_down_one_track ();
626 /* change horizontal first */
632 /* now send a motion event to notify anyone who cares
633 that we have moved to a new location (because we scrolled)
638 ev.type = GDK_MOTION_NOTIFY;
639 ev.state = Gdk::BUTTON1_MASK;
641 /* the motion handler expects events in canvas coordinate space */
643 /* first convert from Editor window coordinates to canvas
650 /* clamp x and y to remain within the visible area */
652 x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1);
653 y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1);
655 translate_coordinates (*_track_canvas_viewport, x, y, cx, cy);
657 ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy));
661 motion_handler (0, (GdkEvent*) &ev, true);
663 } else if (no_stop) {
665 /* not changing visual state but pointer is outside the scrolling boundary
666 * so we still need to deliver a fake motion event
671 ev.type = GDK_MOTION_NOTIFY;
672 ev.state = Gdk::BUTTON1_MASK;
674 /* the motion handler expects events in canvas coordinate space */
676 /* first convert from Editor window coordinates to canvas
683 /* clamp x and y to remain within the visible area. except
684 * .. if horizontal scrolling is allowed, always allow us to
688 if (autoscroll_horizontal_allowed) {
689 x = min (max ((ArdourCanvas::Coord) x, 0.0), autoscroll_boundary.x1);
691 x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1);
693 y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1);
695 translate_coordinates (*_track_canvas_viewport, x, y, cx, cy);
697 ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy));
701 motion_handler (0, (GdkEvent*) &ev, true);
704 stop_canvas_autoscroll ();
710 return true; /* call me again */
714 Editor::start_canvas_autoscroll (bool allow_horiz, bool allow_vert, const ArdourCanvas::Rect& boundary)
720 stop_canvas_autoscroll ();
723 autoscroll_horizontal_allowed = allow_horiz;
724 autoscroll_vertical_allowed = allow_vert;
725 autoscroll_boundary = boundary;
727 /* do the first scroll right now
730 autoscroll_canvas ();
732 /* scroll again at very very roughly 30FPS */
734 autoscroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::autoscroll_canvas), 30);
738 Editor::stop_canvas_autoscroll ()
740 autoscroll_connection.disconnect ();
744 Editor::left_track_canvas (GdkEventCrossing */*ev*/)
747 within_track_canvas = false;
748 set_entered_track (0);
749 set_entered_regionview (0);
750 reset_canvas_action_sensitivity (false);
755 Editor::entered_track_canvas (GdkEventCrossing */*ev*/)
757 within_track_canvas = true;
758 reset_canvas_action_sensitivity (true);
763 Editor::_ensure_time_axis_view_is_visible (const TimeAxisView& tav, bool at_top)
765 double begin = tav.y_position();
766 double v = vertical_adjustment.get_value ();
768 if (!at_top && (begin < v || begin + tav.current_height() > v + _visible_canvas_height)) {
769 /* try to put the TimeAxisView roughly central */
770 if (begin >= _visible_canvas_height/2.0) {
771 begin -= _visible_canvas_height/2.0;
775 /* Clamp the y pos so that we do not extend beyond the canvas full
778 if (_full_canvas_height - begin < _visible_canvas_height){
779 begin = _full_canvas_height - _visible_canvas_height;
782 vertical_adjustment.set_value (begin);
785 /** Called when the main vertical_adjustment has changed */
787 Editor::tie_vertical_scrolling ()
789 if (pending_visual_change.idle_handler_id < 0) {
790 _summary->set_overlays_dirty ();
795 Editor::set_horizontal_position (double p)
797 horizontal_adjustment.set_value (p);
799 leftmost_frame = (framepos_t) floor (p * samples_per_pixel);
801 update_fixed_rulers ();
802 redisplay_tempo (true);
804 if (pending_visual_change.idle_handler_id < 0) {
805 _summary->set_overlays_dirty ();
808 update_video_timeline();
812 Editor::color_handler()
814 playhead_cursor->set_color (ARDOUR_UI::config()->get_canvasvar_PlayHead());
815 _verbose_cursor->set_color (ARDOUR_UI::config()->get_canvasvar_VerboseCanvasCursor());
817 meter_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_MeterBar());
818 meter_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
820 tempo_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TempoBar());
821 tempo_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
823 marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_MarkerBar());
824 marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
826 cd_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CDMarkerBar());
827 cd_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
829 range_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeMarkerBar());
830 range_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
832 transport_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportMarkerBar());
833 transport_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
835 cd_marker_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
836 cd_marker_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
838 range_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
839 range_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
841 transport_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportDragRect());
842 transport_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportDragRect());
844 transport_loop_range_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportLoopRect());
845 transport_loop_range_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportLoopRect());
847 transport_punch_range_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportPunchRect());
848 transport_punch_range_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportPunchRect());
850 transport_punchin_line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_PunchLine());
851 transport_punchout_line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_PunchLine());
853 zoom_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_ZoomRect());
854 zoom_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_ZoomRect());
856 rubberband_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RubberBandRect());
857 rubberband_rect->set_fill_color ((guint32) ARDOUR_UI::config()->get_canvasvar_RubberBandRect());
859 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
860 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
861 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
862 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
863 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
865 refresh_location_display ();
867 redisplay_tempo (true);
870 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks); // redraw metric markers
875 Editor::horizontal_position () const
877 return sample_to_pixel (leftmost_frame);
881 Editor::set_canvas_cursor (Gdk::Cursor* cursor, bool save)
884 current_canvas_cursor = cursor;
887 Glib::RefPtr<Gdk::Window> win = _track_canvas->get_window();
890 _track_canvas->get_window()->set_cursor (*cursor);
895 Editor::track_canvas_key_press (GdkEventKey*)
897 /* XXX: event does not report the modifier key pressed down, AFAICS, so use the Keyboard object instead */
898 if (mouse_mode == Editing::MouseZoom && Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
899 set_canvas_cursor (_cursors->zoom_out, true);
906 Editor::track_canvas_key_release (GdkEventKey*)
908 if (mouse_mode == Editing::MouseZoom && !Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
909 set_canvas_cursor (_cursors->zoom_in, true);
916 Editor::clamp_verbose_cursor_x (double x)
921 x = min (_visible_canvas_width - 200.0, x);
927 Editor::clamp_verbose_cursor_y (double y)
930 y = min (_visible_canvas_height - 50, y);
934 ArdourCanvas::GtkCanvasViewport*
935 Editor::get_track_canvas() const
937 return _track_canvas_viewport;