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::bind (sigc::mem_fun (*this, &Editor::canvas_scroll_event), true));
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 initialize_rulers ();
271 ColorsChanged.connect (sigc::mem_fun (*this, &Editor::color_handler));
277 Editor::track_canvas_viewport_allocate (Gtk::Allocation alloc)
279 _canvas_viewport_allocation = alloc;
280 track_canvas_viewport_size_allocated ();
284 Editor::track_canvas_viewport_size_allocated ()
286 bool height_changed = _visible_canvas_height != _canvas_viewport_allocation.get_height();
288 _visible_canvas_width = _canvas_viewport_allocation.get_width ();
289 _visible_canvas_height = _canvas_viewport_allocation.get_height ();
291 _canvas_drop_zone->set_y1 (_canvas_drop_zone->y0() + (_visible_canvas_height - 20.0));
295 if (height_changed) {
297 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
298 i->second->canvas_height_set (_visible_canvas_height);
301 vertical_adjustment.set_page_size (_visible_canvas_height);
302 if ((vertical_adjustment.get_value() + _visible_canvas_height) >= vertical_adjustment.get_upper()) {
304 We're increasing the size of the canvas while the bottom is visible.
305 We scroll down to keep in step with the controls layout.
307 vertical_adjustment.set_value (_full_canvas_height - _visible_canvas_height);
310 set_visible_track_count (_visible_track_count);
313 update_fixed_rulers();
314 redisplay_tempo (false);
315 _summary->set_overlays_dirty ();
319 Editor::reset_controls_layout_width ()
324 edit_controls_vbox.size_request (req);
327 if (_group_tabs->is_mapped()) {
328 _group_tabs->size_request (req);
332 /* the controls layout has no horizontal scrolling, its visible
333 width is always equal to the total width of its contents.
336 controls_layout.property_width() = w;
337 controls_layout.property_width_request() = w;
341 Editor::reset_controls_layout_height (int32_t h)
343 /* ensure that the rect that represents the "bottom" of the canvas
344 * (the drag-n-drop zone) is, in fact, at the bottom.
347 _canvas_drop_zone->set_position (ArdourCanvas::Duple (0, h));
349 /* track controls layout must span the full height of "h" (all tracks)
350 * plus the bottom rect.
353 h += _canvas_drop_zone->height ();
355 /* set the height of the scrollable area (i.e. the sum of all contained widgets)
356 * for the controls layout. The size request is set elsewhere.
359 controls_layout.property_height() = h;
364 Editor::track_canvas_map_handler (GdkEventAny* /*ev*/)
366 if (current_canvas_cursor) {
367 set_canvas_cursor (current_canvas_cursor);
372 /** This is called when something is dropped onto the track canvas */
374 Editor::track_canvas_drag_data_received (const RefPtr<Gdk::DragContext>& context,
376 const SelectionData& data,
377 guint info, guint time)
379 if (data.get_target() == "regions") {
380 drop_regions (context, x, y, data, info, time);
382 drop_paths (context, x, y, data, info, time);
387 Editor::idle_drop_paths (vector<string> paths, framepos_t frame, double ypos, bool copy)
389 drop_paths_part_two (paths, frame, ypos, copy);
394 Editor::drop_paths_part_two (const vector<string>& paths, framepos_t frame, double ypos, bool copy)
396 RouteTimeAxisView* tv;
398 /* MIDI files must always be imported, because we consider them
399 * writable. So split paths into two vectors, and follow the import
400 * path on the MIDI part.
403 vector<string> midi_paths;
404 vector<string> audio_paths;
406 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
407 if (SMFSource::safe_midi_file_extension (*i)) {
408 midi_paths.push_back (*i);
410 audio_paths.push_back (*i);
415 std::pair<TimeAxisView*, int> const tvp = trackview_by_y_position (ypos);
416 if (tvp.first == 0) {
418 /* drop onto canvas background: create new tracks */
422 do_import (midi_paths, Editing::ImportDistinctFiles, ImportAsTrack, SrcBest, frame);
424 if (Profile->get_sae() || Config->get_only_copy_imported_files() || copy) {
425 do_import (audio_paths, Editing::ImportDistinctFiles, Editing::ImportAsTrack, SrcBest, frame);
427 do_embed (audio_paths, Editing::ImportDistinctFiles, ImportAsTrack, frame);
430 } else if ((tv = dynamic_cast<RouteTimeAxisView*> (tvp.first)) != 0) {
432 /* check that its a track, not a bus */
435 /* select the track, then embed/import */
438 do_import (midi_paths, Editing::ImportSerializeFiles, ImportToTrack, SrcBest, frame);
440 if (Profile->get_sae() || Config->get_only_copy_imported_files() || copy) {
441 do_import (audio_paths, Editing::ImportSerializeFiles, Editing::ImportToTrack, SrcBest, frame);
443 do_embed (audio_paths, Editing::ImportSerializeFiles, ImportToTrack, frame);
450 Editor::drop_paths (const RefPtr<Gdk::DragContext>& context,
452 const SelectionData& data,
453 guint info, guint time)
455 vector<string> paths;
460 if (convert_drop_to_paths (paths, context, x, y, data, info, time) == 0) {
462 /* D-n-D coordinates are window-relative, so convert to canvas coordinates
465 ev.type = GDK_BUTTON_RELEASE;
469 frame = window_event_sample (&ev, 0, &cy);
473 bool copy = ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY);
475 /* We are not allowed to call recursive main event loops from within
476 the main event loop with GTK/Quartz. Since import/embed wants
477 to push up a progress dialog, defer all this till we go idle.
479 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun (*this, &Editor::idle_drop_paths), paths, frame, cy, copy));
481 drop_paths_part_two (paths, frame, cy, copy);
485 context->drag_finish (true, false, time);
488 /** @param allow_horiz true to allow horizontal autoscroll, otherwise false.
490 * @param allow_vert true to allow vertical autoscroll, otherwise false.
494 Editor::maybe_autoscroll (bool allow_horiz, bool allow_vert, bool from_headers)
496 if (!Config->get_autoscroll_editor ()) {
500 ArdourCanvas::Rect scrolling_boundary;
501 Gtk::Allocation alloc;
504 alloc = controls_layout.get_allocation ();
506 alloc = _track_canvas_viewport->get_allocation ();
508 /* the effective width of the autoscroll boundary so
509 that we start scrolling before we hit the edge.
511 this helps when the window is slammed up against the
512 right edge of the screen, making it hard to scroll
516 if (alloc.get_width() > 20) {
517 alloc.set_width (alloc.get_width() - 20);
518 alloc.set_x (alloc.get_x() + 10);
522 scrolling_boundary = ArdourCanvas::Rect (alloc.get_x(), alloc.get_y(),
523 alloc.get_x() + alloc.get_width(),
524 alloc.get_y() + alloc.get_height());
527 Gdk::ModifierType mask;
529 get_window()->get_pointer (x, y, mask);
531 if ((allow_horiz && ((x < scrolling_boundary.x0 && leftmost_frame > 0) || x >= scrolling_boundary.x1)) ||
532 (allow_vert && ((y < scrolling_boundary.y0 && vertical_adjustment.get_value() > 0)|| y >= scrolling_boundary.y1))) {
533 start_canvas_autoscroll (allow_horiz, allow_vert, scrolling_boundary);
538 Editor::autoscroll_active () const
540 return autoscroll_connection.connected ();
544 Editor::autoscroll_canvas ()
547 Gdk::ModifierType mask;
548 frameoffset_t dx = 0;
549 bool no_stop = false;
550 bool y_motion = false;
552 get_window()->get_pointer (x, y, mask);
556 if (autoscroll_horizontal_allowed) {
558 framepos_t new_frame = leftmost_frame;
562 if (x > autoscroll_boundary.x1) {
564 /* bring it back into view */
565 dx = x - autoscroll_boundary.x1;
566 dx += 10 + (2 * (autoscroll_cnt/2));
568 dx = pixel_to_sample (dx);
570 if (leftmost_frame < max_framepos - dx) {
571 new_frame = leftmost_frame + dx;
573 new_frame = max_framepos;
578 } else if (x < autoscroll_boundary.x0) {
580 dx = autoscroll_boundary.x0 - x;
581 dx += 10 + (2 * (autoscroll_cnt/2));
583 dx = pixel_to_sample (dx);
585 if (leftmost_frame >= dx) {
586 new_frame = leftmost_frame - dx;
594 if (new_frame != leftmost_frame) {
595 vc.time_origin = new_frame;
596 vc.add (VisualChange::TimeOrigin);
600 if (autoscroll_vertical_allowed) {
602 // const double vertical_pos = vertical_adjustment.get_value();
603 const int speed_factor = 20;
607 if (y < autoscroll_boundary.y0) {
609 /* scroll to make higher tracks visible */
611 if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
612 y_motion = scroll_up_one_track ();
615 } else if (y > autoscroll_boundary.y1) {
617 if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
618 y_motion = scroll_down_one_track ();
628 /* change horizontal first */
634 /* now send a motion event to notify anyone who cares
635 that we have moved to a new location (because we scrolled)
640 ev.type = GDK_MOTION_NOTIFY;
641 ev.state = Gdk::BUTTON1_MASK;
643 /* the motion handler expects events in canvas coordinate space */
645 /* first convert from Editor window coordinates to canvas
652 /* clamp x and y to remain within the visible area */
654 x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1);
655 y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1);
657 translate_coordinates (*_track_canvas_viewport, x, y, cx, cy);
659 ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy));
663 motion_handler (0, (GdkEvent*) &ev, true);
665 } else if (no_stop) {
667 /* not changing visual state but pointer is outside the scrolling boundary
668 * so we still need to deliver a fake motion event
673 ev.type = GDK_MOTION_NOTIFY;
674 ev.state = Gdk::BUTTON1_MASK;
676 /* the motion handler expects events in canvas coordinate space */
678 /* first convert from Editor window coordinates to canvas
685 /* clamp x and y to remain within the visible area. except
686 * .. if horizontal scrolling is allowed, always allow us to
690 if (autoscroll_horizontal_allowed) {
691 x = min (max ((ArdourCanvas::Coord) x, 0.0), autoscroll_boundary.x1);
693 x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1);
695 y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1);
697 translate_coordinates (*_track_canvas_viewport, x, y, cx, cy);
699 ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy));
703 motion_handler (0, (GdkEvent*) &ev, true);
706 stop_canvas_autoscroll ();
712 return true; /* call me again */
716 Editor::start_canvas_autoscroll (bool allow_horiz, bool allow_vert, const ArdourCanvas::Rect& boundary)
722 stop_canvas_autoscroll ();
725 autoscroll_horizontal_allowed = allow_horiz;
726 autoscroll_vertical_allowed = allow_vert;
727 autoscroll_boundary = boundary;
729 /* do the first scroll right now
732 autoscroll_canvas ();
734 /* scroll again at very very roughly 30FPS */
736 autoscroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::autoscroll_canvas), 30);
740 Editor::stop_canvas_autoscroll ()
742 autoscroll_connection.disconnect ();
746 Editor::left_track_canvas (GdkEventCrossing */*ev*/)
749 within_track_canvas = false;
750 set_entered_track (0);
751 set_entered_regionview (0);
752 reset_canvas_action_sensitivity (false);
757 Editor::entered_track_canvas (GdkEventCrossing */*ev*/)
759 within_track_canvas = true;
760 reset_canvas_action_sensitivity (true);
765 Editor::_ensure_time_axis_view_is_visible (const TimeAxisView& tav, bool at_top)
767 double begin = tav.y_position();
768 double v = vertical_adjustment.get_value ();
770 if (!at_top && (begin < v || begin + tav.current_height() > v + _visible_canvas_height)) {
771 /* try to put the TimeAxisView roughly central */
772 if (begin >= _visible_canvas_height/2.0) {
773 begin -= _visible_canvas_height/2.0;
777 /* Clamp the y pos so that we do not extend beyond the canvas full
780 if (_full_canvas_height - begin < _visible_canvas_height){
781 begin = _full_canvas_height - _visible_canvas_height;
784 vertical_adjustment.set_value (begin);
787 /** Called when the main vertical_adjustment has changed */
789 Editor::tie_vertical_scrolling ()
791 if (pending_visual_change.idle_handler_id < 0) {
792 _summary->set_overlays_dirty ();
797 Editor::set_horizontal_position (double p)
799 horizontal_adjustment.set_value (p);
801 leftmost_frame = (framepos_t) floor (p * samples_per_pixel);
803 update_fixed_rulers ();
804 redisplay_tempo (true);
806 if (pending_visual_change.idle_handler_id < 0) {
807 _summary->set_overlays_dirty ();
810 update_video_timeline();
814 Editor::color_handler()
816 ArdourCanvas::Color base = ARDOUR_UI::config()->get_canvasvar_RulerBase();
817 ArdourCanvas::Color text = ARDOUR_UI::config()->get_canvasvar_RulerText();
818 timecode_ruler->set_fill_color (base);
819 timecode_ruler->set_outline_color (text);
820 minsec_ruler->set_fill_color (base);
821 minsec_ruler->set_outline_color (text);
822 samples_ruler->set_fill_color (base);
823 samples_ruler->set_outline_color (text);
824 bbt_ruler->set_fill_color (base);
825 bbt_ruler->set_outline_color (text);
827 playhead_cursor->set_color (ARDOUR_UI::config()->get_canvasvar_PlayHead());
828 _verbose_cursor->set_color (ARDOUR_UI::config()->get_canvasvar_VerboseCanvasCursor());
830 meter_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_MeterBar());
831 meter_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
833 tempo_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TempoBar());
834 tempo_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
836 marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_MarkerBar());
837 marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
839 cd_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CDMarkerBar());
840 cd_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
842 range_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeMarkerBar());
843 range_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
845 transport_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportMarkerBar());
846 transport_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
848 cd_marker_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
849 cd_marker_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
851 range_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
852 range_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
854 transport_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportDragRect());
855 transport_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportDragRect());
857 transport_loop_range_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportLoopRect());
858 transport_loop_range_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportLoopRect());
860 transport_punch_range_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportPunchRect());
861 transport_punch_range_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportPunchRect());
863 transport_punchin_line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_PunchLine());
864 transport_punchout_line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_PunchLine());
866 zoom_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_ZoomRect());
867 zoom_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_ZoomRect());
869 rubberband_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RubberBandRect());
870 rubberband_rect->set_fill_color ((guint32) ARDOUR_UI::config()->get_canvasvar_RubberBandRect());
872 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
873 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
874 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
875 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
876 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
878 refresh_location_display ();
880 redisplay_tempo (true);
883 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks); // redraw metric markers
888 Editor::horizontal_position () const
890 return sample_to_pixel (leftmost_frame);
894 Editor::set_canvas_cursor (Gdk::Cursor* cursor, bool save)
897 current_canvas_cursor = cursor;
900 Glib::RefPtr<Gdk::Window> win = _track_canvas->get_window();
903 _track_canvas->get_window()->set_cursor (*cursor);
908 Editor::push_canvas_cursor (Gdk::Cursor* cursor)
911 _cursor_stack.push (cursor);
912 set_canvas_cursor (cursor, false);
917 Editor::pop_canvas_cursor ()
919 if (!_cursor_stack.empty()) {
920 Gdk::Cursor* cursor = _cursor_stack.top ();
921 _cursor_stack.pop ();
922 set_canvas_cursor (cursor, false);
927 Editor::track_canvas_key_press (GdkEventKey*)
929 /* XXX: event does not report the modifier key pressed down, AFAICS, so use the Keyboard object instead */
930 if (mouse_mode == Editing::MouseZoom && Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
931 set_canvas_cursor (_cursors->zoom_out, true);
938 Editor::track_canvas_key_release (GdkEventKey*)
940 if (mouse_mode == Editing::MouseZoom && !Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
941 set_canvas_cursor (_cursors->zoom_in, true);
948 Editor::clamp_verbose_cursor_x (double x)
953 x = min (_visible_canvas_width - 200.0, x);
959 Editor::clamp_verbose_cursor_y (double y)
962 y = min (_visible_canvas_height - 50, y);
966 ArdourCanvas::GtkCanvasViewport*
967 Editor::get_track_canvas() const
969 return _track_canvas_viewport;