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;
72 hv_scroll_group = hsg = new ArdourCanvas::ScrollGroup (_track_canvas->root(),
73 ArdourCanvas::ScrollGroup::ScrollSensitivity (ArdourCanvas::ScrollGroup::ScrollsVertically|
74 ArdourCanvas::ScrollGroup::ScrollsHorizontally));
75 CANVAS_DEBUG_NAME (hv_scroll_group, "canvas hv scroll");
76 _track_canvas->add_scroller (*hsg);
78 _verbose_cursor = new VerboseCursor (this);
80 /* on the bottom, an image */
82 if (Profile->get_sae()) {
83 Image img (::get_icon (X_("saelogo")));
84 // logo_item = new ArdourCanvas::Pixbuf (_track_canvas->root(), 0.0, 0.0, img.get_pixbuf());
85 // logo_item->property_height_in_pixels() = true;
86 // logo_item->property_width_in_pixels() = true;
87 // logo_item->property_height_set() = true;
88 // logo_item->property_width_set() = true;
89 // logo_item->show ();
92 /*a group to hold global rects like punch/loop indicators */
93 global_rect_group = new ArdourCanvas::Group (hv_scroll_group);
94 CANVAS_DEBUG_NAME (global_rect_group, "global rect group");
96 transport_loop_range_rect = new ArdourCanvas::Rectangle (global_rect_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, ArdourCanvas::COORD_MAX));
97 CANVAS_DEBUG_NAME (transport_loop_range_rect, "loop rect");
98 transport_loop_range_rect->hide();
100 transport_punch_range_rect = new ArdourCanvas::Rectangle (global_rect_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, ArdourCanvas::COORD_MAX));
101 CANVAS_DEBUG_NAME (transport_punch_range_rect, "punch rect");
102 transport_punch_range_rect->hide();
104 /*a group to hold time (measure) lines */
105 time_line_group = new ArdourCanvas::Group (hv_scroll_group);
106 CANVAS_DEBUG_NAME (time_line_group, "time line group");
108 _trackview_group = new ArdourCanvas::Group (hv_scroll_group);
109 //_trackview_group->set_scroll_sensitivity (ArdourCanvas::Group::ScrollSensitivity (ArdourCanvas::Group::ScrollsVertically|ArdourCanvas::Group::ScrollsHorizontally));
110 CANVAS_DEBUG_NAME (_trackview_group, "Canvas TrackViews");
112 _region_motion_group = new ArdourCanvas::Group (_trackview_group);
113 CANVAS_DEBUG_NAME (_region_motion_group, "Canvas Region Motion");
115 /* TIME BAR CANVAS */
117 ArdourCanvas::ScrollGroup* hg;
119 h_scroll_group = hg = new ArdourCanvas::ScrollGroup (_track_canvas->root(), ArdourCanvas::ScrollGroup::ScrollsHorizontally);
120 CANVAS_DEBUG_NAME (h_scroll_group, "canvas h scroll");
121 _track_canvas->add_scroller (*hg);
123 meter_bar_group = new ArdourCanvas::Group (h_scroll_group);
124 meter_bar = new ArdourCanvas::Rectangle (meter_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
125 CANVAS_DEBUG_NAME (meter_bar, "meter Bar");
126 meter_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
128 tempo_bar_group = new ArdourCanvas::Group (h_scroll_group);
129 tempo_bar = new ArdourCanvas::Rectangle (tempo_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
130 CANVAS_DEBUG_NAME (tempo_bar, "Tempo Bar");
131 tempo_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
133 range_marker_bar_group = new ArdourCanvas::Group (h_scroll_group);
134 range_marker_bar = new ArdourCanvas::Rectangle (range_marker_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
135 CANVAS_DEBUG_NAME (range_marker_bar, "Range Marker Bar");
136 range_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
138 transport_marker_bar_group = new ArdourCanvas::Group (h_scroll_group);
139 transport_marker_bar = new ArdourCanvas::Rectangle (transport_marker_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
140 CANVAS_DEBUG_NAME (transport_marker_bar, "transport Marker Bar");
141 transport_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
143 marker_bar_group = new ArdourCanvas::Group (h_scroll_group);
144 marker_bar = new ArdourCanvas::Rectangle (marker_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
145 CANVAS_DEBUG_NAME (marker_bar, "Marker Bar");
146 marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
148 cd_marker_bar_group = new ArdourCanvas::Group (h_scroll_group);
149 cd_marker_bar = new ArdourCanvas::Rectangle (cd_marker_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
150 CANVAS_DEBUG_NAME (cd_marker_bar, "CD Marker Bar");
151 cd_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
153 _time_markers_group = new ArdourCanvas::Group (h_scroll_group);
155 cd_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, 0.0));
156 CANVAS_DEBUG_NAME (cd_marker_group, "cd marker group");
157 /* the vide is temporarily placed a the same location as the
158 cd_marker_group, but is moved later.
160 videotl_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple(0.0, 0.0));
161 CANVAS_DEBUG_NAME (videotl_group, "videotl group");
162 marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, timebar_height + 1.0));
163 CANVAS_DEBUG_NAME (marker_group, "marker group");
164 transport_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 2.0) + 1.0));
165 CANVAS_DEBUG_NAME (transport_marker_group, "transport marker group");
166 range_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 3.0) + 1.0));
167 CANVAS_DEBUG_NAME (range_marker_group, "range marker group");
168 tempo_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 4.0) + 1.0));
169 CANVAS_DEBUG_NAME (tempo_group, "tempo group");
170 meter_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 5.0) + 1.0));
171 CANVAS_DEBUG_NAME (meter_group, "meter group");
173 ARDOUR_UI::instance()->video_timeline = new VideoTimeLine(this, videotl_group, (timebar_height * videotl_bar_height));
175 cd_marker_bar_drag_rect = new ArdourCanvas::Rectangle (cd_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
176 CANVAS_DEBUG_NAME (cd_marker_bar_drag_rect, "cd marker drag");
177 cd_marker_bar_drag_rect->set_outline (false);
178 cd_marker_bar_drag_rect->hide ();
180 range_bar_drag_rect = new ArdourCanvas::Rectangle (range_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
181 CANVAS_DEBUG_NAME (range_bar_drag_rect, "range drag");
182 range_bar_drag_rect->set_outline (false);
183 range_bar_drag_rect->hide ();
185 transport_bar_drag_rect = new ArdourCanvas::Rectangle (transport_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
186 CANVAS_DEBUG_NAME (transport_bar_drag_rect, "transport drag");
187 transport_bar_drag_rect->set_outline (false);
188 transport_bar_drag_rect->hide ();
190 transport_punchin_line = new ArdourCanvas::Line (hv_scroll_group);
191 transport_punchin_line->set_x0 (0);
192 transport_punchin_line->set_y0 (0);
193 transport_punchin_line->set_x1 (0);
194 transport_punchin_line->set_y1 (ArdourCanvas::COORD_MAX);
195 transport_punchin_line->hide ();
197 transport_punchout_line = new ArdourCanvas::Line (hv_scroll_group);
198 transport_punchout_line->set_x0 (0);
199 transport_punchout_line->set_y0 (0);
200 transport_punchout_line->set_x1 (0);
201 transport_punchout_line->set_y1 (ArdourCanvas::COORD_MAX);
202 transport_punchout_line->hide();
204 // used to show zoom mode active zooming
205 zoom_rect = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0));
207 zoom_rect->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_zoom_rect_event), (ArdourCanvas::Item*) 0));
209 // used as rubberband rect
210 rubberband_rect = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0));
211 rubberband_rect->hide();
213 tempo_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_tempo_bar_event), tempo_bar));
214 meter_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_meter_bar_event), meter_bar));
215 marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_marker_bar_event), marker_bar));
216 cd_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_cd_marker_bar_event), cd_marker_bar));
217 videotl_group->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_videotl_bar_event), videotl_group));
218 range_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_range_marker_bar_event), range_marker_bar));
219 transport_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_transport_marker_bar_event), transport_marker_bar));
221 playhead_cursor = new EditorCursor (*this, &Editor::canvas_playhead_cursor_event);
224 logo_item->lower_to_bottom ();
228 _canvas_bottom_rect = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, 20));
229 /* this thing is transparent */
230 _canvas_bottom_rect->set_fill (false);
231 _canvas_bottom_rect->set_outline (false);
232 _canvas_bottom_rect->Event.connect (sigc::mem_fun (*this, &Editor::canvas_bottom_rect_event));
234 /* these signals will initially be delivered to the canvas itself, but if they end up remaining unhandled, they are passed to Editor-level
238 _track_canvas->signal_scroll_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_scroll_event));
239 _track_canvas->signal_motion_notify_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_motion_notify_event));
240 _track_canvas->signal_button_press_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_button_press_event));
241 _track_canvas->signal_button_release_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_button_release_event));
242 _track_canvas->signal_drag_motion().connect (sigc::mem_fun (*this, &Editor::track_canvas_drag_motion));
243 _track_canvas->signal_key_press_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_key_press));
244 _track_canvas->signal_key_release_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_key_release));
246 _track_canvas->set_name ("EditorMainCanvas");
247 _track_canvas->add_events (Gdk::POINTER_MOTION_HINT_MASK | Gdk::SCROLL_MASK | Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK);
248 _track_canvas->signal_leave_notify_event().connect (sigc::mem_fun(*this, &Editor::left_track_canvas), false);
249 _track_canvas->signal_enter_notify_event().connect (sigc::mem_fun(*this, &Editor::entered_track_canvas), false);
250 _track_canvas->set_flags (CAN_FOCUS);
252 /* set up drag-n-drop */
254 vector<TargetEntry> target_table;
256 // Drag-N-Drop from the region list can generate this target
257 target_table.push_back (TargetEntry ("regions"));
259 target_table.push_back (TargetEntry ("text/plain"));
260 target_table.push_back (TargetEntry ("text/uri-list"));
261 target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
263 _track_canvas->drag_dest_set (target_table);
264 _track_canvas->signal_drag_data_received().connect (sigc::mem_fun(*this, &Editor::track_canvas_drag_data_received));
266 _track_canvas_viewport->signal_size_allocate().connect (sigc::mem_fun(*this, &Editor::track_canvas_viewport_allocate));
268 ColorsChanged.connect (sigc::mem_fun (*this, &Editor::color_handler));
274 Editor::track_canvas_viewport_allocate (Gtk::Allocation alloc)
276 _canvas_viewport_allocation = alloc;
277 track_canvas_viewport_size_allocated ();
281 Editor::track_canvas_viewport_size_allocated ()
283 bool height_changed = _visible_canvas_height != _canvas_viewport_allocation.get_height();
285 _visible_canvas_width = _canvas_viewport_allocation.get_width ();
286 _visible_canvas_height = _canvas_viewport_allocation.get_height ();
290 if (height_changed) {
292 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
293 i->second->canvas_height_set (_visible_canvas_height);
296 vertical_adjustment.set_page_size (_visible_canvas_height);
297 if ((vertical_adjustment.get_value() + _visible_canvas_height) >= vertical_adjustment.get_upper()) {
299 We're increasing the size of the canvas while the bottom is visible.
300 We scroll down to keep in step with the controls layout.
302 vertical_adjustment.set_value (_full_canvas_height - _visible_canvas_height);
305 set_visible_track_count (_visible_track_count);
308 update_fixed_rulers();
309 redisplay_tempo (false);
310 _summary->set_overlays_dirty ();
314 Editor::reset_controls_layout_width ()
319 edit_controls_vbox.size_request (req);
322 if (_group_tabs->is_mapped()) {
323 _group_tabs->size_request (req);
327 /* the controls layout has no horizontal scrolling, its visible
328 width is always equal to the total width of its contents.
331 controls_layout.property_width() = w;
332 controls_layout.property_width_request() = w;
336 Editor::reset_controls_layout_height (int32_t h)
338 /* ensure that the rect that represents the "bottom" of the canvas
339 * (the drag-n-drop zone) is, in fact, at the bottom.
342 _canvas_bottom_rect->set_position (ArdourCanvas::Duple (0, h));
344 /* track controls layout must span the full height of "h" (all tracks)
345 * plus the bottom rect.
348 h += _canvas_bottom_rect->height ();
350 /* set the height of the scrollable area (i.e. the sum of all contained widgets)
351 * for the controls layout. The size request is set elsewhere.
354 controls_layout.property_height() = h;
359 Editor::track_canvas_map_handler (GdkEventAny* /*ev*/)
361 if (current_canvas_cursor) {
362 set_canvas_cursor (current_canvas_cursor);
367 /** This is called when something is dropped onto the track canvas */
369 Editor::track_canvas_drag_data_received (const RefPtr<Gdk::DragContext>& context,
371 const SelectionData& data,
372 guint info, guint time)
374 if (data.get_target() == "regions") {
375 drop_regions (context, x, y, data, info, time);
377 drop_paths (context, x, y, data, info, time);
382 Editor::idle_drop_paths (vector<string> paths, framepos_t frame, double ypos, bool copy)
384 drop_paths_part_two (paths, frame, ypos, copy);
389 Editor::drop_paths_part_two (const vector<string>& paths, framepos_t frame, double ypos, bool copy)
391 RouteTimeAxisView* tv;
393 /* MIDI files must always be imported, because we consider them
394 * writable. So split paths into two vectors, and follow the import
395 * path on the MIDI part.
398 vector<string> midi_paths;
399 vector<string> audio_paths;
401 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
402 if (SMFSource::safe_midi_file_extension (*i)) {
403 midi_paths.push_back (*i);
405 audio_paths.push_back (*i);
410 std::pair<TimeAxisView*, int> const tvp = trackview_by_y_position (ypos);
411 if (tvp.first == 0) {
413 /* drop onto canvas background: create new tracks */
417 do_import (midi_paths, Editing::ImportDistinctFiles, ImportAsTrack, SrcBest, frame);
419 if (Profile->get_sae() || Config->get_only_copy_imported_files() || copy) {
420 do_import (audio_paths, Editing::ImportDistinctFiles, Editing::ImportAsTrack, SrcBest, frame);
422 do_embed (audio_paths, Editing::ImportDistinctFiles, ImportAsTrack, frame);
425 } else if ((tv = dynamic_cast<RouteTimeAxisView*> (tvp.first)) != 0) {
427 /* check that its a track, not a bus */
430 /* select the track, then embed/import */
433 do_import (midi_paths, Editing::ImportSerializeFiles, ImportToTrack, SrcBest, frame);
435 if (Profile->get_sae() || Config->get_only_copy_imported_files() || copy) {
436 do_import (audio_paths, Editing::ImportSerializeFiles, Editing::ImportToTrack, SrcBest, frame);
438 do_embed (audio_paths, Editing::ImportSerializeFiles, ImportToTrack, frame);
445 Editor::drop_paths (const RefPtr<Gdk::DragContext>& context,
447 const SelectionData& data,
448 guint info, guint time)
450 vector<string> paths;
455 if (convert_drop_to_paths (paths, context, x, y, data, info, time) == 0) {
457 /* D-n-D coordinates are window-relative, so convert to "world" coordinates
460 ev.type = GDK_BUTTON_RELEASE;
464 frame = window_event_sample (&ev, 0, &cy);
468 bool copy = ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY);
470 /* We are not allowed to call recursive main event loops from within
471 the main event loop with GTK/Quartz. Since import/embed wants
472 to push up a progress dialog, defer all this till we go idle.
474 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun (*this, &Editor::idle_drop_paths), paths, frame, cy, copy));
476 drop_paths_part_two (paths, frame, cy, copy);
480 context->drag_finish (true, false, time);
483 /** @param allow_horiz true to allow horizontal autoscroll, otherwise false.
485 * @param allow_vert true to allow vertical autoscroll, otherwise false.
489 Editor::maybe_autoscroll (bool allow_horiz, bool allow_vert, bool from_headers)
491 if (!Config->get_autoscroll_editor ()) {
495 ArdourCanvas::Rect scrolling_boundary;
496 Gtk::Allocation alloc;
499 alloc = controls_layout.get_allocation ();
501 alloc = _track_canvas_viewport->get_allocation ();
503 /* the effective width of the autoscroll boundary so
504 that we start scrolling before we hit the edge.
506 this helps when the window is slammed up against the
507 right edge of the screen, making it hard to scroll
511 if (alloc.get_width() > 20) {
512 alloc.set_width (alloc.get_width() - 20);
513 alloc.set_x (alloc.get_x() + 10);
517 scrolling_boundary = ArdourCanvas::Rect (alloc.get_x(), alloc.get_y(),
518 alloc.get_x() + alloc.get_width(),
519 alloc.get_y() + alloc.get_height());
522 Gdk::ModifierType mask;
524 get_window()->get_pointer (x, y, mask);
526 if ((allow_horiz && (x < scrolling_boundary.x0 || x >= scrolling_boundary.x1)) ||
527 (allow_vert && (y < scrolling_boundary.y0 || y >= scrolling_boundary.y1))) {
528 start_canvas_autoscroll (allow_horiz, allow_vert, scrolling_boundary);
533 Editor::autoscroll_active () const
535 return autoscroll_connection.connected ();
539 Editor::autoscroll_canvas ()
542 Gdk::ModifierType mask;
543 frameoffset_t dx = 0;
544 bool no_stop = false;
545 bool y_motion = false;
547 get_window()->get_pointer (x, y, mask);
551 if (autoscroll_horizontal_allowed) {
553 framepos_t new_frame = leftmost_frame;
557 if (x > autoscroll_boundary.x1) {
559 /* bring it back into view */
560 dx = x - autoscroll_boundary.x1;
561 dx += 10 + (2 * (autoscroll_cnt/2));
563 dx = pixel_to_sample (dx);
565 if (leftmost_frame < max_framepos - dx) {
566 new_frame = leftmost_frame + dx;
568 new_frame = max_framepos;
573 } else if (x < autoscroll_boundary.x0) {
575 dx = autoscroll_boundary.x0 - x;
576 dx += 10 + (2 * (autoscroll_cnt/2));
578 dx = pixel_to_sample (dx);
580 if (leftmost_frame >= dx) {
581 new_frame = leftmost_frame - dx;
589 if (new_frame != leftmost_frame) {
590 vc.time_origin = new_frame;
591 vc.add (VisualChange::TimeOrigin);
595 if (autoscroll_vertical_allowed) {
597 const double vertical_pos = vertical_adjustment.get_value();
598 double new_pixel = vertical_pos;
599 const int speed_factor = 20;
603 if (y < autoscroll_boundary.y0) {
605 /* scroll to make higher tracks visible */
607 if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
608 y_motion = scroll_up_one_track ();
611 } else if (y > autoscroll_boundary.y1) {
613 if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
614 y_motion = scroll_down_one_track ();
624 /* change horizontal first */
630 /* now send a motion event to notify anyone who cares
631 that we have moved to a new location (because we scrolled)
636 ev.type = GDK_MOTION_NOTIFY;
637 ev.state = Gdk::BUTTON1_MASK;
639 /* the motion handler expects events in canvas coordinate space */
641 /* first convert from Editor window coordinates to canvas
648 /* clamp x and y to remain within the visible area */
650 x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1);
651 y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1);
653 translate_coordinates (*_track_canvas_viewport, x, y, cx, cy);
655 ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy));
659 motion_handler (0, (GdkEvent*) &ev, true);
661 } else if (no_stop) {
663 /* not changing visual state but pointer is outside the scrolling boundary
664 * so we still need to deliver a fake motion event
669 ev.type = GDK_MOTION_NOTIFY;
670 ev.state = Gdk::BUTTON1_MASK;
672 /* the motion handler expects events in canvas coordinate space */
674 /* first convert from Editor window coordinates to canvas
681 /* clamp x and y to remain within the visible area. except
682 * .. if horizontal scrolling is allowed, always allow us to
686 if (autoscroll_horizontal_allowed) {
687 x = min (max ((ArdourCanvas::Coord) x, 0.0), autoscroll_boundary.x1);
689 x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1);
691 y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1);
693 translate_coordinates (*_track_canvas_viewport, x, y, cx, cy);
695 ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy));
699 motion_handler (0, (GdkEvent*) &ev, true);
702 stop_canvas_autoscroll ();
708 return true; /* call me again */
712 Editor::start_canvas_autoscroll (bool allow_horiz, bool allow_vert, const ArdourCanvas::Rect& boundary)
718 stop_canvas_autoscroll ();
721 autoscroll_horizontal_allowed = allow_horiz;
722 autoscroll_vertical_allowed = allow_vert;
723 autoscroll_boundary = boundary;
725 /* do the first scroll right now
728 autoscroll_canvas ();
730 /* scroll again at very very roughly 30FPS */
732 autoscroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::autoscroll_canvas), 30);
736 Editor::stop_canvas_autoscroll ()
738 autoscroll_connection.disconnect ();
742 Editor::left_track_canvas (GdkEventCrossing */*ev*/)
745 within_track_canvas = false;
746 set_entered_track (0);
747 set_entered_regionview (0);
748 reset_canvas_action_sensitivity (false);
753 Editor::entered_track_canvas (GdkEventCrossing */*ev*/)
755 within_track_canvas = true;
756 reset_canvas_action_sensitivity (true);
761 Editor::_ensure_time_axis_view_is_visible (const TimeAxisView& tav, bool at_top)
763 double begin = tav.y_position();
764 double v = vertical_adjustment.get_value ();
766 if (!at_top && (begin < v || begin + tav.current_height() > v + _visible_canvas_height)) {
767 /* try to put the TimeAxisView roughly central */
768 if (begin >= _visible_canvas_height/2.0) {
769 begin -= _visible_canvas_height/2.0;
773 /* Clamp the y pos so that we do not extend beyond the canvas full
776 if (_full_canvas_height - begin < _visible_canvas_height){
777 begin = _full_canvas_height - _visible_canvas_height;
780 vertical_adjustment.set_value (begin);
783 /** Called when the main vertical_adjustment has changed */
785 Editor::tie_vertical_scrolling ()
787 if (pending_visual_change.idle_handler_id < 0) {
788 _summary->set_overlays_dirty ();
793 Editor::set_horizontal_position (double p)
795 horizontal_adjustment.set_value (p);
797 leftmost_frame = (framepos_t) floor (p * samples_per_pixel);
799 update_fixed_rulers ();
800 redisplay_tempo (true);
802 if (pending_visual_change.idle_handler_id < 0) {
803 _summary->set_overlays_dirty ();
806 update_video_timeline();
810 Editor::color_handler()
812 playhead_cursor->set_color (ARDOUR_UI::config()->get_canvasvar_PlayHead());
813 _verbose_cursor->set_color (ARDOUR_UI::config()->get_canvasvar_VerboseCanvasCursor());
815 meter_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_MeterBar());
816 meter_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
818 tempo_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TempoBar());
819 tempo_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
821 marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_MarkerBar());
822 marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
824 cd_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CDMarkerBar());
825 cd_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
827 range_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeMarkerBar());
828 range_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
830 transport_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportMarkerBar());
831 transport_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
833 cd_marker_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
834 cd_marker_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
836 range_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
837 range_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
839 transport_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportDragRect());
840 transport_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportDragRect());
842 transport_loop_range_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportLoopRect());
843 transport_loop_range_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportLoopRect());
845 transport_punch_range_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportPunchRect());
846 transport_punch_range_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportPunchRect());
848 transport_punchin_line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_PunchLine());
849 transport_punchout_line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_PunchLine());
851 zoom_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_ZoomRect());
852 zoom_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_ZoomRect());
854 rubberband_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RubberBandRect());
855 rubberband_rect->set_fill_color ((guint32) ARDOUR_UI::config()->get_canvasvar_RubberBandRect());
857 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
858 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
859 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
860 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
861 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
863 refresh_location_display ();
865 redisplay_tempo (true);
868 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks); // redraw metric markers
873 Editor::horizontal_position () const
875 return sample_to_pixel (leftmost_frame);
879 Editor::set_canvas_cursor (Gdk::Cursor* cursor, bool save)
882 current_canvas_cursor = cursor;
885 Glib::RefPtr<Gdk::Window> win = _track_canvas->get_window();
888 _track_canvas->get_window()->set_cursor (*cursor);
893 Editor::track_canvas_key_press (GdkEventKey*)
895 /* XXX: event does not report the modifier key pressed down, AFAICS, so use the Keyboard object instead */
896 if (mouse_mode == Editing::MouseZoom && Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
897 set_canvas_cursor (_cursors->zoom_out, true);
904 Editor::track_canvas_key_release (GdkEventKey*)
906 if (mouse_mode == Editing::MouseZoom && !Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
907 set_canvas_cursor (_cursors->zoom_in, true);
914 Editor::clamp_verbose_cursor_x (double x)
919 x = min (_visible_canvas_width - 200.0, x);
925 Editor::clamp_verbose_cursor_y (double y)
928 y = min (_visible_canvas_height - 50, y);
933 Editor::get_time_bars_group () const
935 return h_scroll_group;
939 Editor::get_track_canvas_group() const
941 return hv_scroll_group;
944 ArdourCanvas::GtkCanvasViewport*
945 Editor::get_track_canvas() const
947 return _track_canvas_viewport;