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 ();
69 _time_bars_canvas_viewport = new ArdourCanvas::GtkCanvasViewport (horizontal_adjustment, unused_adjustment);
70 _time_bars_canvas = _time_bars_canvas_viewport->canvas ();
72 _verbose_cursor = new VerboseCursor (this);
74 /* on the bottom, an image */
76 if (Profile->get_sae()) {
77 Image img (::get_icon (X_("saelogo")));
78 // logo_item = new ArdourCanvas::Pixbuf (_track_canvas->root(), 0.0, 0.0, img.get_pixbuf());
79 // logo_item->property_height_in_pixels() = true;
80 // logo_item->property_width_in_pixels() = true;
81 // logo_item->property_height_set() = true;
82 // logo_item->property_width_set() = true;
83 // logo_item->show ();
86 /*a group to hold global rects like punch/loop indicators */
87 global_rect_group = new ArdourCanvas::Group (_track_canvas->root());
88 CANVAS_DEBUG_NAME (global_rect_group, "global rect group");
90 transport_loop_range_rect = new ArdourCanvas::Rectangle (global_rect_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, ArdourCanvas::COORD_MAX));
91 CANVAS_DEBUG_NAME (transport_loop_range_rect, "loop rect");
92 transport_loop_range_rect->hide();
94 transport_punch_range_rect = new ArdourCanvas::Rectangle (global_rect_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, ArdourCanvas::COORD_MAX));
95 CANVAS_DEBUG_NAME (transport_punch_range_rect, "punch rect");
96 transport_punch_range_rect->hide();
98 /*a group to hold time (measure) lines */
99 time_line_group = new ArdourCanvas::Group (_track_canvas->root());
100 CANVAS_DEBUG_NAME (time_line_group, "time line group");
102 _trackview_group = new ArdourCanvas::Group (_track_canvas->root());
103 CANVAS_DEBUG_NAME (_trackview_group, "Canvas TrackViews");
104 _region_motion_group = new ArdourCanvas::Group (_trackview_group);
105 CANVAS_DEBUG_NAME (_region_motion_group, "Canvas Region Motion");
107 meter_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
108 meter_bar = new ArdourCanvas::Rectangle (meter_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
109 CANVAS_DEBUG_NAME (meter_bar, "meter Bar");
110 meter_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
112 tempo_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
113 tempo_bar = new ArdourCanvas::Rectangle (tempo_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
114 CANVAS_DEBUG_NAME (tempo_bar, "Tempo Bar");
115 tempo_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
117 range_marker_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
118 range_marker_bar = new ArdourCanvas::Rectangle (range_marker_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
119 CANVAS_DEBUG_NAME (range_marker_bar, "Range Marker Bar");
120 range_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
122 transport_marker_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
123 transport_marker_bar = new ArdourCanvas::Rectangle (transport_marker_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
124 CANVAS_DEBUG_NAME (transport_marker_bar, "transport Marker Bar");
125 transport_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
127 marker_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
128 marker_bar = new ArdourCanvas::Rectangle (marker_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
129 CANVAS_DEBUG_NAME (marker_bar, "Marker Bar");
130 marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
132 cd_marker_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
133 cd_marker_bar = new ArdourCanvas::Rectangle (cd_marker_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
134 CANVAS_DEBUG_NAME (cd_marker_bar, "CD Marker Bar");
135 cd_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
137 _time_markers_group = new ArdourCanvas::Group (_time_bars_canvas->root());
139 cd_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, 0.0));
140 CANVAS_DEBUG_NAME (cd_marker_group, "cd marker group");
141 /* the vide is temporarily placed a the same location as the
142 cd_marker_group, but is moved later.
144 videotl_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple(0.0, 0.0));
145 CANVAS_DEBUG_NAME (videotl_group, "videotl group");
146 marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, timebar_height + 1.0));
147 CANVAS_DEBUG_NAME (marker_group, "marker group");
148 transport_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 2.0) + 1.0));
149 CANVAS_DEBUG_NAME (transport_marker_group, "transport marker group");
150 range_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 3.0) + 1.0));
151 CANVAS_DEBUG_NAME (range_marker_group, "range marker group");
152 tempo_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 4.0) + 1.0));
153 CANVAS_DEBUG_NAME (tempo_group, "tempo group");
154 meter_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 5.0) + 1.0));
155 CANVAS_DEBUG_NAME (meter_group, "meter group");
157 ARDOUR_UI::instance()->video_timeline = new VideoTimeLine(this, videotl_group, (timebar_height * videotl_bar_height));
159 cd_marker_bar_drag_rect = new ArdourCanvas::Rectangle (cd_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
160 CANVAS_DEBUG_NAME (cd_marker_bar_drag_rect, "cd marker drag");
161 cd_marker_bar_drag_rect->set_outline (false);
162 cd_marker_bar_drag_rect->hide ();
164 range_bar_drag_rect = new ArdourCanvas::Rectangle (range_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
165 CANVAS_DEBUG_NAME (range_bar_drag_rect, "range drag");
166 range_bar_drag_rect->set_outline (false);
167 range_bar_drag_rect->hide ();
169 transport_bar_drag_rect = new ArdourCanvas::Rectangle (transport_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
170 CANVAS_DEBUG_NAME (transport_bar_drag_rect, "transport drag");
171 transport_bar_drag_rect->set_outline (false);
172 transport_bar_drag_rect->hide ();
174 transport_punchin_line = new ArdourCanvas::Line (_track_canvas->root());
175 transport_punchin_line->set_x0 (0);
176 transport_punchin_line->set_y0 (0);
177 transport_punchin_line->set_x1 (0);
178 transport_punchin_line->set_y1 (ArdourCanvas::COORD_MAX);
179 transport_punchin_line->hide ();
181 transport_punchout_line = new ArdourCanvas::Line (_track_canvas->root());
182 transport_punchout_line->set_x0 (0);
183 transport_punchout_line->set_y0 (0);
184 transport_punchout_line->set_x1 (0);
185 transport_punchout_line->set_y1 (ArdourCanvas::COORD_MAX);
186 transport_punchout_line->hide();
188 // used to show zoom mode active zooming
189 zoom_rect = new ArdourCanvas::Rectangle (_track_canvas->root(), ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0));
191 zoom_rect->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_zoom_rect_event), (ArdourCanvas::Item*) 0));
193 // used as rubberband rect
194 rubberband_rect = new ArdourCanvas::Rectangle (_trackview_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0));
195 rubberband_rect->hide();
197 tempo_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_tempo_bar_event), tempo_bar));
198 meter_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_meter_bar_event), meter_bar));
199 marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_marker_bar_event), marker_bar));
200 cd_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_cd_marker_bar_event), cd_marker_bar));
201 videotl_group->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_videotl_bar_event), videotl_group));
202 range_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_range_marker_bar_event), range_marker_bar));
203 transport_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_transport_marker_bar_event), transport_marker_bar));
205 playhead_cursor = new EditorCursor (*this, &Editor::canvas_playhead_cursor_event);
208 logo_item->lower_to_bottom ();
212 _canvas_bottom_rect = new ArdourCanvas::Rectangle (_track_canvas->root(), ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, 20));
213 /* this thing is transparent */
214 _canvas_bottom_rect->set_fill (false);
215 _canvas_bottom_rect->set_outline (false);
216 _canvas_bottom_rect->Event.connect (sigc::mem_fun (*this, &Editor::canvas_bottom_rect_event));
218 /* these signals will initially be delivered to the canvas itself, but if they end up remaining unhandled, they are passed to Editor-level
222 _track_canvas->signal_scroll_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_scroll_event));
223 _track_canvas->signal_motion_notify_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_motion_notify_event));
224 _track_canvas->signal_button_press_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_button_press_event));
225 _track_canvas->signal_button_release_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_button_release_event));
226 _track_canvas->signal_drag_motion().connect (sigc::mem_fun (*this, &Editor::track_canvas_drag_motion));
227 _track_canvas->signal_key_press_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_key_press));
228 _track_canvas->signal_key_release_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_key_release));
230 _track_canvas->set_name ("EditorMainCanvas");
231 _track_canvas->add_events (Gdk::POINTER_MOTION_HINT_MASK | Gdk::SCROLL_MASK | Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK);
232 _track_canvas->signal_leave_notify_event().connect (sigc::mem_fun(*this, &Editor::left_track_canvas), false);
233 _track_canvas->signal_enter_notify_event().connect (sigc::mem_fun(*this, &Editor::entered_track_canvas), false);
234 _track_canvas->set_flags (CAN_FOCUS);
236 /* set up drag-n-drop */
238 vector<TargetEntry> target_table;
240 // Drag-N-Drop from the region list can generate this target
241 target_table.push_back (TargetEntry ("regions"));
243 target_table.push_back (TargetEntry ("text/plain"));
244 target_table.push_back (TargetEntry ("text/uri-list"));
245 target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
247 _track_canvas->drag_dest_set (target_table);
248 _track_canvas->signal_drag_data_received().connect (sigc::mem_fun(*this, &Editor::track_canvas_drag_data_received));
250 _track_canvas_viewport->signal_size_allocate().connect (sigc::mem_fun(*this, &Editor::track_canvas_viewport_allocate));
252 ColorsChanged.connect (sigc::mem_fun (*this, &Editor::color_handler));
258 Editor::track_canvas_viewport_allocate (Gtk::Allocation alloc)
260 _canvas_viewport_allocation = alloc;
261 track_canvas_viewport_size_allocated ();
265 Editor::track_canvas_viewport_size_allocated ()
267 bool height_changed = _visible_canvas_height != _canvas_viewport_allocation.get_height();
269 _visible_canvas_width = _canvas_viewport_allocation.get_width ();
270 _visible_canvas_height = _canvas_viewport_allocation.get_height ();
274 if (height_changed) {
276 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
277 i->second->canvas_height_set (_visible_canvas_height);
280 vertical_adjustment.set_page_size (_visible_canvas_height);
281 if ((vertical_adjustment.get_value() + _visible_canvas_height) >= vertical_adjustment.get_upper()) {
283 We're increasing the size of the canvas while the bottom is visible.
284 We scroll down to keep in step with the controls layout.
286 vertical_adjustment.set_value (_full_canvas_height - _visible_canvas_height);
289 set_visible_track_count (_visible_track_count);
292 update_fixed_rulers();
293 redisplay_tempo (false);
294 _summary->set_overlays_dirty ();
298 Editor::reset_controls_layout_width ()
303 edit_controls_vbox.size_request (req);
306 if (_group_tabs->is_mapped()) {
307 _group_tabs->size_request (req);
311 /* the controls layout has no horizontal scrolling, its visible
312 width is always equal to the total width of its contents.
315 controls_layout.property_width() = w;
316 controls_layout.property_width_request() = w;
320 Editor::reset_controls_layout_height (int32_t h)
322 /* ensure that the rect that represents the "bottom" of the canvas
323 * (the drag-n-drop zone) is, in fact, at the bottom.
326 _canvas_bottom_rect->set_position (ArdourCanvas::Duple (0, h));
328 /* track controls layout must span the full height of "h" (all tracks)
329 * plus the bottom rect.
332 h += _canvas_bottom_rect->height ();
334 /* set the height of the scrollable area (i.e. the sum of all contained widgets)
335 * for the controls layout. The size request is set elsewhere.
338 controls_layout.property_height() = h;
343 Editor::track_canvas_map_handler (GdkEventAny* /*ev*/)
345 if (current_canvas_cursor) {
346 set_canvas_cursor (current_canvas_cursor);
351 /** This is called when something is dropped onto the track canvas */
353 Editor::track_canvas_drag_data_received (const RefPtr<Gdk::DragContext>& context,
355 const SelectionData& data,
356 guint info, guint time)
358 if (data.get_target() == "regions") {
359 drop_regions (context, x, y, data, info, time);
361 drop_paths (context, x, y, data, info, time);
366 Editor::idle_drop_paths (vector<string> paths, framepos_t frame, double ypos, bool copy)
368 drop_paths_part_two (paths, frame, ypos, copy);
373 Editor::drop_paths_part_two (const vector<string>& paths, framepos_t frame, double ypos, bool copy)
375 RouteTimeAxisView* tv;
377 /* MIDI files must always be imported, because we consider them
378 * writable. So split paths into two vectors, and follow the import
379 * path on the MIDI part.
382 vector<string> midi_paths;
383 vector<string> audio_paths;
385 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
386 if (SMFSource::safe_midi_file_extension (*i)) {
387 midi_paths.push_back (*i);
389 audio_paths.push_back (*i);
394 std::pair<TimeAxisView*, int> const tvp = trackview_by_y_position (ypos);
395 if (tvp.first == 0) {
397 /* drop onto canvas background: create new tracks */
401 do_import (midi_paths, Editing::ImportDistinctFiles, ImportAsTrack, SrcBest, frame);
403 if (Profile->get_sae() || Config->get_only_copy_imported_files() || copy) {
404 do_import (audio_paths, Editing::ImportDistinctFiles, Editing::ImportAsTrack, SrcBest, frame);
406 do_embed (audio_paths, Editing::ImportDistinctFiles, ImportAsTrack, frame);
409 } else if ((tv = dynamic_cast<RouteTimeAxisView*> (tvp.first)) != 0) {
411 /* check that its a track, not a bus */
414 /* select the track, then embed/import */
417 do_import (midi_paths, Editing::ImportSerializeFiles, ImportToTrack, SrcBest, frame);
419 if (Profile->get_sae() || Config->get_only_copy_imported_files() || copy) {
420 do_import (audio_paths, Editing::ImportSerializeFiles, Editing::ImportToTrack, SrcBest, frame);
422 do_embed (audio_paths, Editing::ImportSerializeFiles, ImportToTrack, frame);
429 Editor::drop_paths (const RefPtr<Gdk::DragContext>& context,
431 const SelectionData& data,
432 guint info, guint time)
434 vector<string> paths;
439 if (convert_drop_to_paths (paths, context, x, y, data, info, time) == 0) {
441 /* D-n-D coordinates are window-relative, so convert to "world" coordinates
444 ev.type = GDK_BUTTON_RELEASE;
448 frame = window_event_sample (&ev, 0, &cy);
452 bool copy = ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY);
454 /* We are not allowed to call recursive main event loops from within
455 the main event loop with GTK/Quartz. Since import/embed wants
456 to push up a progress dialog, defer all this till we go idle.
458 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun (*this, &Editor::idle_drop_paths), paths, frame, cy, copy));
460 drop_paths_part_two (paths, frame, cy, copy);
464 context->drag_finish (true, false, time);
467 /** @param allow_horiz true to allow horizontal autoscroll, otherwise false.
469 * @param allow_vert true to allow vertical autoscroll, otherwise false.
473 Editor::maybe_autoscroll (bool allow_horiz, bool allow_vert, bool from_headers)
475 if (!Config->get_autoscroll_editor ()) {
480 ArdourCanvas::Rect scrolling_boundary;
481 Gtk::Allocation alloc;
484 alloc = controls_layout.get_allocation ();
486 alloc = _track_canvas_viewport->get_allocation ();
488 /* the effective width of the autoscroll boundary so
489 that we start scrolling before we hit the edge.
491 this helps when the window is slammed up against the
492 right edge of the screen, making it hard to scroll
496 if (alloc.get_width() > 20) {
497 alloc.set_width (alloc.get_width() - 20);
498 alloc.set_x (alloc.get_x() + 10);
502 scrolling_boundary = ArdourCanvas::Rect (alloc.get_x(), alloc.get_y(),
503 alloc.get_x() + alloc.get_width(),
504 alloc.get_y() + alloc.get_height());
507 Gdk::ModifierType mask;
509 get_window()->get_pointer (x, y, mask);
511 if ((allow_horiz && (x < scrolling_boundary.x0 || x >= scrolling_boundary.x1)) ||
512 (allow_vert && (y < scrolling_boundary.y0 || y >= scrolling_boundary.y1))) {
513 start_canvas_autoscroll (allow_horiz, allow_vert, scrolling_boundary);
518 Editor::autoscroll_active () const
520 return autoscroll_connection.connected ();
524 Editor::autoscroll_canvas ()
527 Gdk::ModifierType mask;
528 frameoffset_t dx = 0;
529 bool no_stop = false;
530 bool y_motion = false;
532 get_window()->get_pointer (x, y, mask);
536 if (autoscroll_horizontal_allowed) {
538 framepos_t new_frame = leftmost_frame;
542 if (x > autoscroll_boundary.x1) {
544 /* bring it back into view */
545 dx = x - autoscroll_boundary.x1;
546 dx += 10 + (2 * (autoscroll_cnt/2));
548 dx = pixel_to_sample (dx);
550 if (leftmost_frame < max_framepos - dx) {
551 new_frame = leftmost_frame + dx;
553 new_frame = max_framepos;
558 } else if (x < autoscroll_boundary.x0) {
560 dx = autoscroll_boundary.x0 - x;
561 dx += 10 + (2 * (autoscroll_cnt/2));
563 dx = pixel_to_sample (dx);
565 if (leftmost_frame >= dx) {
566 new_frame = leftmost_frame - dx;
574 if (new_frame != leftmost_frame) {
575 vc.time_origin = new_frame;
576 vc.add (VisualChange::TimeOrigin);
580 if (autoscroll_vertical_allowed) {
582 const double vertical_pos = vertical_adjustment.get_value();
583 double new_pixel = vertical_pos;
584 const int speed_factor = 20;
588 new_pixel = vertical_pos;
590 if (y < autoscroll_boundary.y0) {
592 /* scroll to make higher tracks visible */
594 if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
595 y_motion = scroll_up_one_track ();
598 } else if (y > autoscroll_boundary.y1) {
600 if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
601 y_motion = scroll_down_one_track ();
611 /* change horizontal first */
617 /* now send a motion event to notify anyone who cares
618 that we have moved to a new location (because we scrolled)
623 ev.type = GDK_MOTION_NOTIFY;
624 ev.state = Gdk::BUTTON1_MASK;
626 /* the motion handler expects events in canvas coordinate space */
628 /* first convert from Editor window coordinates to canvas
635 /* clamp x and y to remain within the visible area */
637 x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1);
638 y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1);
640 translate_coordinates (*_track_canvas_viewport, x, y, cx, cy);
642 ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy));
646 motion_handler (0, (GdkEvent*) &ev, true);
648 } else if (no_stop) {
650 /* not changing visual state but pointer is outside the scrolling boundary
651 * so we still need to deliver a fake motion event
656 ev.type = GDK_MOTION_NOTIFY;
657 ev.state = Gdk::BUTTON1_MASK;
659 /* the motion handler expects events in canvas coordinate space */
661 /* first convert from Editor window coordinates to canvas
668 /* clamp x and y to remain within the visible area. except
669 * .. if horizontal scrolling is allowed, always allow us to
673 if (autoscroll_horizontal_allowed) {
674 x = min (max ((ArdourCanvas::Coord) x, 0.0), autoscroll_boundary.x1);
676 x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1);
678 y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1);
680 translate_coordinates (*_track_canvas_viewport, x, y, cx, cy);
682 ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy));
686 motion_handler (0, (GdkEvent*) &ev, true);
689 stop_canvas_autoscroll ();
695 return true; /* call me again */
699 Editor::start_canvas_autoscroll (bool allow_horiz, bool allow_vert, const ArdourCanvas::Rect& boundary)
705 stop_canvas_autoscroll ();
708 autoscroll_horizontal_allowed = allow_horiz;
709 autoscroll_vertical_allowed = allow_vert;
710 autoscroll_boundary = boundary;
712 /* do the first scroll right now
715 autoscroll_canvas ();
717 /* scroll again at very very roughly 30FPS */
719 autoscroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::autoscroll_canvas), 30);
723 Editor::stop_canvas_autoscroll ()
725 autoscroll_connection.disconnect ();
729 Editor::left_track_canvas (GdkEventCrossing */*ev*/)
732 within_track_canvas = false;
733 set_entered_track (0);
734 set_entered_regionview (0);
735 reset_canvas_action_sensitivity (false);
740 Editor::entered_track_canvas (GdkEventCrossing */*ev*/)
742 within_track_canvas = true;
743 reset_canvas_action_sensitivity (true);
748 Editor::_ensure_time_axis_view_is_visible (const TimeAxisView& tav, bool at_top)
750 double begin = tav.y_position();
751 double v = vertical_adjustment.get_value ();
753 if (!at_top && (begin < v || begin + tav.current_height() > v + _visible_canvas_height)) {
754 /* try to put the TimeAxisView roughly central */
755 if (begin >= _visible_canvas_height/2.0) {
756 begin -= _visible_canvas_height/2.0;
760 /* Clamp the y pos so that we do not extend beyond the canvas full
763 if (_full_canvas_height - begin < _visible_canvas_height){
764 begin = _full_canvas_height - _visible_canvas_height;
767 vertical_adjustment.set_value (begin);
770 /** Called when the main vertical_adjustment has changed */
772 Editor::tie_vertical_scrolling ()
774 if (pending_visual_change.idle_handler_id < 0) {
775 _summary->set_overlays_dirty ();
780 Editor::set_horizontal_position (double p)
782 horizontal_adjustment.set_value (p);
784 leftmost_frame = (framepos_t) floor (p * samples_per_pixel);
786 update_fixed_rulers ();
787 redisplay_tempo (true);
789 if (pending_visual_change.idle_handler_id < 0) {
790 _summary->set_overlays_dirty ();
793 update_video_timeline();
797 Editor::color_handler()
799 playhead_cursor->set_color (ARDOUR_UI::config()->get_canvasvar_PlayHead());
800 _verbose_cursor->set_color (ARDOUR_UI::config()->get_canvasvar_VerboseCanvasCursor());
802 meter_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_MeterBar());
803 meter_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
805 tempo_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TempoBar());
806 tempo_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
808 marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_MarkerBar());
809 marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
811 cd_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CDMarkerBar());
812 cd_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
814 range_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeMarkerBar());
815 range_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
817 transport_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportMarkerBar());
818 transport_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
820 cd_marker_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
821 cd_marker_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
823 range_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
824 range_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
826 transport_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportDragRect());
827 transport_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportDragRect());
829 transport_loop_range_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportLoopRect());
830 transport_loop_range_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportLoopRect());
832 transport_punch_range_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportPunchRect());
833 transport_punch_range_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportPunchRect());
835 transport_punchin_line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_PunchLine());
836 transport_punchout_line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_PunchLine());
838 zoom_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_ZoomRect());
839 zoom_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_ZoomRect());
841 rubberband_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RubberBandRect());
842 rubberband_rect->set_fill_color ((guint32) ARDOUR_UI::config()->get_canvasvar_RubberBandRect());
844 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
845 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
846 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
847 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
848 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
850 refresh_location_display ();
852 redisplay_tempo (true);
855 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks); // redraw metric markers
860 Editor::horizontal_position () const
862 return sample_to_pixel (leftmost_frame);
866 Editor::set_canvas_cursor (Gdk::Cursor* cursor, bool save)
869 current_canvas_cursor = cursor;
872 Glib::RefPtr<Gdk::Window> win = _track_canvas->get_window();
875 _track_canvas->get_window()->set_cursor (*cursor);
880 Editor::track_canvas_key_press (GdkEventKey*)
882 /* XXX: event does not report the modifier key pressed down, AFAICS, so use the Keyboard object instead */
883 if (mouse_mode == Editing::MouseZoom && Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
884 set_canvas_cursor (_cursors->zoom_out, true);
891 Editor::track_canvas_key_release (GdkEventKey*)
893 if (mouse_mode == Editing::MouseZoom && !Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
894 set_canvas_cursor (_cursors->zoom_in, true);
901 Editor::clamp_verbose_cursor_x (double x)
906 x = min (_visible_canvas_width - 200.0, x);
912 Editor::clamp_verbose_cursor_y (double y)
915 y = min (_visible_canvas_height - 50, y);
920 Editor::get_time_bars_group () const
922 return _time_bars_canvas->root();
926 Editor::get_track_canvas_group() const
928 return _track_canvas->root();
931 ArdourCanvas::GtkCanvasViewport*
932 Editor::get_time_bars_canvas() const
934 return _time_bars_canvas_viewport;
937 ArdourCanvas::GtkCanvasViewport*
938 Editor::get_track_canvas() const
940 return _track_canvas_viewport;