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 ();
69 _track_canvas->set_global_scroll (false);
71 hv_scroll_group = new ArdourCanvas::ScrollGroup (_track_canvas->root(),
72 ArdourCanvas::ScrollGroup::ScrollSensitivity (ArdourCanvas::ScrollGroup::ScrollsVertically|
73 ArdourCanvas::ScrollGroup::ScrollsHorizontally));
74 CANVAS_DEBUG_NAME (hv_scroll_group, "canvas hv scroll");
76 _verbose_cursor = new VerboseCursor (this);
78 /* on the bottom, an image */
80 if (Profile->get_sae()) {
81 Image img (::get_icon (X_("saelogo")));
82 // logo_item = new ArdourCanvas::Pixbuf (_track_canvas->root(), 0.0, 0.0, img.get_pixbuf());
83 // logo_item->property_height_in_pixels() = true;
84 // logo_item->property_width_in_pixels() = true;
85 // logo_item->property_height_set() = true;
86 // logo_item->property_width_set() = true;
87 // logo_item->show ();
90 /*a group to hold global rects like punch/loop indicators */
91 global_rect_group = new ArdourCanvas::Group (hv_scroll_group);
92 CANVAS_DEBUG_NAME (global_rect_group, "global rect group");
94 transport_loop_range_rect = new ArdourCanvas::Rectangle (global_rect_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, ArdourCanvas::COORD_MAX));
95 CANVAS_DEBUG_NAME (transport_loop_range_rect, "loop rect");
96 transport_loop_range_rect->hide();
98 transport_punch_range_rect = new ArdourCanvas::Rectangle (global_rect_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, ArdourCanvas::COORD_MAX));
99 CANVAS_DEBUG_NAME (transport_punch_range_rect, "punch rect");
100 transport_punch_range_rect->hide();
102 /*a group to hold time (measure) lines */
103 time_line_group = new ArdourCanvas::Group (hv_scroll_group);
104 CANVAS_DEBUG_NAME (time_line_group, "time line group");
106 _trackview_group = new ArdourCanvas::Group (hv_scroll_group);
107 //_trackview_group->set_scroll_sensitivity (ArdourCanvas::Group::ScrollSensitivity (ArdourCanvas::Group::ScrollsVertically|ArdourCanvas::Group::ScrollsHorizontally));
108 CANVAS_DEBUG_NAME (_trackview_group, "Canvas TrackViews");
110 _region_motion_group = new ArdourCanvas::Group (_trackview_group);
111 CANVAS_DEBUG_NAME (_region_motion_group, "Canvas Region Motion");
113 /* TIME BAR CANVAS */
115 _time_bars_canvas_viewport = new ArdourCanvas::GtkCanvasViewport (horizontal_adjustment, unused_adjustment);
116 _time_bars_canvas = _time_bars_canvas_viewport->canvas ();
118 meter_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
119 meter_bar = new ArdourCanvas::Rectangle (meter_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
120 CANVAS_DEBUG_NAME (meter_bar, "meter Bar");
121 meter_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
123 tempo_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
124 tempo_bar = new ArdourCanvas::Rectangle (tempo_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
125 CANVAS_DEBUG_NAME (tempo_bar, "Tempo Bar");
126 tempo_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
128 range_marker_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
129 range_marker_bar = new ArdourCanvas::Rectangle (range_marker_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
130 CANVAS_DEBUG_NAME (range_marker_bar, "Range Marker Bar");
131 range_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
133 transport_marker_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
134 transport_marker_bar = new ArdourCanvas::Rectangle (transport_marker_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
135 CANVAS_DEBUG_NAME (transport_marker_bar, "transport Marker Bar");
136 transport_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
138 marker_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
139 marker_bar = new ArdourCanvas::Rectangle (marker_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
140 CANVAS_DEBUG_NAME (marker_bar, "Marker Bar");
141 marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
143 cd_marker_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
144 cd_marker_bar = new ArdourCanvas::Rectangle (cd_marker_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
145 CANVAS_DEBUG_NAME (cd_marker_bar, "CD Marker Bar");
146 cd_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
148 _time_markers_group = new ArdourCanvas::Group (_time_bars_canvas->root());
150 cd_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, 0.0));
151 CANVAS_DEBUG_NAME (cd_marker_group, "cd marker group");
152 /* the vide is temporarily placed a the same location as the
153 cd_marker_group, but is moved later.
155 videotl_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple(0.0, 0.0));
156 CANVAS_DEBUG_NAME (videotl_group, "videotl group");
157 marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, timebar_height + 1.0));
158 CANVAS_DEBUG_NAME (marker_group, "marker group");
159 transport_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 2.0) + 1.0));
160 CANVAS_DEBUG_NAME (transport_marker_group, "transport marker group");
161 range_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 3.0) + 1.0));
162 CANVAS_DEBUG_NAME (range_marker_group, "range marker group");
163 tempo_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 4.0) + 1.0));
164 CANVAS_DEBUG_NAME (tempo_group, "tempo group");
165 meter_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 5.0) + 1.0));
166 CANVAS_DEBUG_NAME (meter_group, "meter group");
168 ARDOUR_UI::instance()->video_timeline = new VideoTimeLine(this, videotl_group, (timebar_height * videotl_bar_height));
170 cd_marker_bar_drag_rect = new ArdourCanvas::Rectangle (cd_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
171 CANVAS_DEBUG_NAME (cd_marker_bar_drag_rect, "cd marker drag");
172 cd_marker_bar_drag_rect->set_outline (false);
173 cd_marker_bar_drag_rect->hide ();
175 range_bar_drag_rect = new ArdourCanvas::Rectangle (range_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
176 CANVAS_DEBUG_NAME (range_bar_drag_rect, "range drag");
177 range_bar_drag_rect->set_outline (false);
178 range_bar_drag_rect->hide ();
180 transport_bar_drag_rect = new ArdourCanvas::Rectangle (transport_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
181 CANVAS_DEBUG_NAME (transport_bar_drag_rect, "transport drag");
182 transport_bar_drag_rect->set_outline (false);
183 transport_bar_drag_rect->hide ();
185 transport_punchin_line = new ArdourCanvas::Line (hv_scroll_group);
186 transport_punchin_line->set_x0 (0);
187 transport_punchin_line->set_y0 (0);
188 transport_punchin_line->set_x1 (0);
189 transport_punchin_line->set_y1 (ArdourCanvas::COORD_MAX);
190 transport_punchin_line->hide ();
192 transport_punchout_line = new ArdourCanvas::Line (hv_scroll_group);
193 transport_punchout_line->set_x0 (0);
194 transport_punchout_line->set_y0 (0);
195 transport_punchout_line->set_x1 (0);
196 transport_punchout_line->set_y1 (ArdourCanvas::COORD_MAX);
197 transport_punchout_line->hide();
199 // used to show zoom mode active zooming
200 zoom_rect = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0));
202 zoom_rect->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_zoom_rect_event), (ArdourCanvas::Item*) 0));
204 // used as rubberband rect
205 rubberband_rect = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0));
206 rubberband_rect->hide();
208 tempo_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_tempo_bar_event), tempo_bar));
209 meter_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_meter_bar_event), meter_bar));
210 marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_marker_bar_event), marker_bar));
211 cd_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_cd_marker_bar_event), cd_marker_bar));
212 videotl_group->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_videotl_bar_event), videotl_group));
213 range_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_range_marker_bar_event), range_marker_bar));
214 transport_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_transport_marker_bar_event), transport_marker_bar));
216 playhead_cursor = new EditorCursor (*this, &Editor::canvas_playhead_cursor_event);
219 logo_item->lower_to_bottom ();
223 _canvas_bottom_rect = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, 20));
224 /* this thing is transparent */
225 _canvas_bottom_rect->set_fill (false);
226 _canvas_bottom_rect->set_outline (false);
227 _canvas_bottom_rect->Event.connect (sigc::mem_fun (*this, &Editor::canvas_bottom_rect_event));
229 /* these signals will initially be delivered to the canvas itself, but if they end up remaining unhandled, they are passed to Editor-level
233 _track_canvas->signal_scroll_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_scroll_event));
234 _track_canvas->signal_motion_notify_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_motion_notify_event));
235 _track_canvas->signal_button_press_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_button_press_event));
236 _track_canvas->signal_button_release_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_button_release_event));
237 _track_canvas->signal_drag_motion().connect (sigc::mem_fun (*this, &Editor::track_canvas_drag_motion));
238 _track_canvas->signal_key_press_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_key_press));
239 _track_canvas->signal_key_release_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_key_release));
241 _track_canvas->set_name ("EditorMainCanvas");
242 _track_canvas->add_events (Gdk::POINTER_MOTION_HINT_MASK | Gdk::SCROLL_MASK | Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK);
243 _track_canvas->signal_leave_notify_event().connect (sigc::mem_fun(*this, &Editor::left_track_canvas), false);
244 _track_canvas->signal_enter_notify_event().connect (sigc::mem_fun(*this, &Editor::entered_track_canvas), false);
245 _track_canvas->set_flags (CAN_FOCUS);
247 /* set up drag-n-drop */
249 vector<TargetEntry> target_table;
251 // Drag-N-Drop from the region list can generate this target
252 target_table.push_back (TargetEntry ("regions"));
254 target_table.push_back (TargetEntry ("text/plain"));
255 target_table.push_back (TargetEntry ("text/uri-list"));
256 target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
258 _track_canvas->drag_dest_set (target_table);
259 _track_canvas->signal_drag_data_received().connect (sigc::mem_fun(*this, &Editor::track_canvas_drag_data_received));
261 _track_canvas_viewport->signal_size_allocate().connect (sigc::mem_fun(*this, &Editor::track_canvas_viewport_allocate));
263 ColorsChanged.connect (sigc::mem_fun (*this, &Editor::color_handler));
269 Editor::track_canvas_viewport_allocate (Gtk::Allocation alloc)
271 _canvas_viewport_allocation = alloc;
272 track_canvas_viewport_size_allocated ();
276 Editor::track_canvas_viewport_size_allocated ()
278 bool height_changed = _visible_canvas_height != _canvas_viewport_allocation.get_height();
280 _visible_canvas_width = _canvas_viewport_allocation.get_width ();
281 _visible_canvas_height = _canvas_viewport_allocation.get_height ();
285 if (height_changed) {
287 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
288 i->second->canvas_height_set (_visible_canvas_height);
291 vertical_adjustment.set_page_size (_visible_canvas_height);
292 if ((vertical_adjustment.get_value() + _visible_canvas_height) >= vertical_adjustment.get_upper()) {
294 We're increasing the size of the canvas while the bottom is visible.
295 We scroll down to keep in step with the controls layout.
297 vertical_adjustment.set_value (_full_canvas_height - _visible_canvas_height);
300 set_visible_track_count (_visible_track_count);
303 update_fixed_rulers();
304 redisplay_tempo (false);
305 _summary->set_overlays_dirty ();
309 Editor::reset_controls_layout_width ()
314 edit_controls_vbox.size_request (req);
317 if (_group_tabs->is_mapped()) {
318 _group_tabs->size_request (req);
322 /* the controls layout has no horizontal scrolling, its visible
323 width is always equal to the total width of its contents.
326 controls_layout.property_width() = w;
327 controls_layout.property_width_request() = w;
331 Editor::reset_controls_layout_height (int32_t h)
333 /* ensure that the rect that represents the "bottom" of the canvas
334 * (the drag-n-drop zone) is, in fact, at the bottom.
337 _canvas_bottom_rect->set_position (ArdourCanvas::Duple (0, h));
339 /* track controls layout must span the full height of "h" (all tracks)
340 * plus the bottom rect.
343 h += _canvas_bottom_rect->height ();
345 /* set the height of the scrollable area (i.e. the sum of all contained widgets)
346 * for the controls layout. The size request is set elsewhere.
349 controls_layout.property_height() = h;
354 Editor::track_canvas_map_handler (GdkEventAny* /*ev*/)
356 if (current_canvas_cursor) {
357 set_canvas_cursor (current_canvas_cursor);
362 /** This is called when something is dropped onto the track canvas */
364 Editor::track_canvas_drag_data_received (const RefPtr<Gdk::DragContext>& context,
366 const SelectionData& data,
367 guint info, guint time)
369 if (data.get_target() == "regions") {
370 drop_regions (context, x, y, data, info, time);
372 drop_paths (context, x, y, data, info, time);
377 Editor::idle_drop_paths (vector<string> paths, framepos_t frame, double ypos, bool copy)
379 drop_paths_part_two (paths, frame, ypos, copy);
384 Editor::drop_paths_part_two (const vector<string>& paths, framepos_t frame, double ypos, bool copy)
386 RouteTimeAxisView* tv;
388 /* MIDI files must always be imported, because we consider them
389 * writable. So split paths into two vectors, and follow the import
390 * path on the MIDI part.
393 vector<string> midi_paths;
394 vector<string> audio_paths;
396 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
397 if (SMFSource::safe_midi_file_extension (*i)) {
398 midi_paths.push_back (*i);
400 audio_paths.push_back (*i);
405 std::pair<TimeAxisView*, int> const tvp = trackview_by_y_position (ypos);
406 if (tvp.first == 0) {
408 /* drop onto canvas background: create new tracks */
412 do_import (midi_paths, Editing::ImportDistinctFiles, ImportAsTrack, SrcBest, frame);
414 if (Profile->get_sae() || Config->get_only_copy_imported_files() || copy) {
415 do_import (audio_paths, Editing::ImportDistinctFiles, Editing::ImportAsTrack, SrcBest, frame);
417 do_embed (audio_paths, Editing::ImportDistinctFiles, ImportAsTrack, frame);
420 } else if ((tv = dynamic_cast<RouteTimeAxisView*> (tvp.first)) != 0) {
422 /* check that its a track, not a bus */
425 /* select the track, then embed/import */
428 do_import (midi_paths, Editing::ImportSerializeFiles, ImportToTrack, SrcBest, frame);
430 if (Profile->get_sae() || Config->get_only_copy_imported_files() || copy) {
431 do_import (audio_paths, Editing::ImportSerializeFiles, Editing::ImportToTrack, SrcBest, frame);
433 do_embed (audio_paths, Editing::ImportSerializeFiles, ImportToTrack, frame);
440 Editor::drop_paths (const RefPtr<Gdk::DragContext>& context,
442 const SelectionData& data,
443 guint info, guint time)
445 vector<string> paths;
450 if (convert_drop_to_paths (paths, context, x, y, data, info, time) == 0) {
452 /* D-n-D coordinates are window-relative, so convert to "world" coordinates
455 ev.type = GDK_BUTTON_RELEASE;
459 frame = window_event_sample (&ev, 0, &cy);
463 bool copy = ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY);
465 /* We are not allowed to call recursive main event loops from within
466 the main event loop with GTK/Quartz. Since import/embed wants
467 to push up a progress dialog, defer all this till we go idle.
469 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun (*this, &Editor::idle_drop_paths), paths, frame, cy, copy));
471 drop_paths_part_two (paths, frame, cy, copy);
475 context->drag_finish (true, false, time);
478 /** @param allow_horiz true to allow horizontal autoscroll, otherwise false.
480 * @param allow_vert true to allow vertical autoscroll, otherwise false.
484 Editor::maybe_autoscroll (bool allow_horiz, bool allow_vert, bool from_headers)
486 if (!Config->get_autoscroll_editor ()) {
491 ArdourCanvas::Rect scrolling_boundary;
492 Gtk::Allocation alloc;
495 alloc = controls_layout.get_allocation ();
497 alloc = _track_canvas_viewport->get_allocation ();
499 /* the effective width of the autoscroll boundary so
500 that we start scrolling before we hit the edge.
502 this helps when the window is slammed up against the
503 right edge of the screen, making it hard to scroll
507 if (alloc.get_width() > 20) {
508 alloc.set_width (alloc.get_width() - 20);
509 alloc.set_x (alloc.get_x() + 10);
513 scrolling_boundary = ArdourCanvas::Rect (alloc.get_x(), alloc.get_y(),
514 alloc.get_x() + alloc.get_width(),
515 alloc.get_y() + alloc.get_height());
518 Gdk::ModifierType mask;
520 get_window()->get_pointer (x, y, mask);
522 if ((allow_horiz && (x < scrolling_boundary.x0 || x >= scrolling_boundary.x1)) ||
523 (allow_vert && (y < scrolling_boundary.y0 || y >= scrolling_boundary.y1))) {
524 start_canvas_autoscroll (allow_horiz, allow_vert, scrolling_boundary);
529 Editor::autoscroll_active () const
531 return autoscroll_connection.connected ();
535 Editor::autoscroll_canvas ()
538 Gdk::ModifierType mask;
539 frameoffset_t dx = 0;
540 bool no_stop = false;
541 bool y_motion = false;
543 get_window()->get_pointer (x, y, mask);
547 if (autoscroll_horizontal_allowed) {
549 framepos_t new_frame = leftmost_frame;
553 if (x > autoscroll_boundary.x1) {
555 /* bring it back into view */
556 dx = x - autoscroll_boundary.x1;
557 dx += 10 + (2 * (autoscroll_cnt/2));
559 dx = pixel_to_sample (dx);
561 if (leftmost_frame < max_framepos - dx) {
562 new_frame = leftmost_frame + dx;
564 new_frame = max_framepos;
569 } else if (x < autoscroll_boundary.x0) {
571 dx = autoscroll_boundary.x0 - x;
572 dx += 10 + (2 * (autoscroll_cnt/2));
574 dx = pixel_to_sample (dx);
576 if (leftmost_frame >= dx) {
577 new_frame = leftmost_frame - dx;
585 if (new_frame != leftmost_frame) {
586 vc.time_origin = new_frame;
587 vc.add (VisualChange::TimeOrigin);
591 if (autoscroll_vertical_allowed) {
593 const double vertical_pos = vertical_adjustment.get_value();
594 double new_pixel = vertical_pos;
595 const int speed_factor = 20;
599 if (y < autoscroll_boundary.y0) {
601 /* scroll to make higher tracks visible */
603 if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
604 y_motion = scroll_up_one_track ();
607 } else if (y > autoscroll_boundary.y1) {
609 if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
610 y_motion = scroll_down_one_track ();
620 /* change horizontal first */
626 /* now send a motion event to notify anyone who cares
627 that we have moved to a new location (because we scrolled)
632 ev.type = GDK_MOTION_NOTIFY;
633 ev.state = Gdk::BUTTON1_MASK;
635 /* the motion handler expects events in canvas coordinate space */
637 /* first convert from Editor window coordinates to canvas
644 /* clamp x and y to remain within the visible area */
646 x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1);
647 y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1);
649 translate_coordinates (*_track_canvas_viewport, x, y, cx, cy);
651 ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy));
655 motion_handler (0, (GdkEvent*) &ev, true);
657 } else if (no_stop) {
659 /* not changing visual state but pointer is outside the scrolling boundary
660 * so we still need to deliver a fake motion event
665 ev.type = GDK_MOTION_NOTIFY;
666 ev.state = Gdk::BUTTON1_MASK;
668 /* the motion handler expects events in canvas coordinate space */
670 /* first convert from Editor window coordinates to canvas
677 /* clamp x and y to remain within the visible area. except
678 * .. if horizontal scrolling is allowed, always allow us to
682 if (autoscroll_horizontal_allowed) {
683 x = min (max ((ArdourCanvas::Coord) x, 0.0), autoscroll_boundary.x1);
685 x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1);
687 y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1);
689 translate_coordinates (*_track_canvas_viewport, x, y, cx, cy);
691 ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy));
695 motion_handler (0, (GdkEvent*) &ev, true);
698 stop_canvas_autoscroll ();
704 return true; /* call me again */
708 Editor::start_canvas_autoscroll (bool allow_horiz, bool allow_vert, const ArdourCanvas::Rect& boundary)
714 stop_canvas_autoscroll ();
717 autoscroll_horizontal_allowed = allow_horiz;
718 autoscroll_vertical_allowed = allow_vert;
719 autoscroll_boundary = boundary;
721 /* do the first scroll right now
724 autoscroll_canvas ();
726 /* scroll again at very very roughly 30FPS */
728 autoscroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::autoscroll_canvas), 30);
732 Editor::stop_canvas_autoscroll ()
734 autoscroll_connection.disconnect ();
738 Editor::left_track_canvas (GdkEventCrossing */*ev*/)
741 within_track_canvas = false;
742 set_entered_track (0);
743 set_entered_regionview (0);
744 reset_canvas_action_sensitivity (false);
749 Editor::entered_track_canvas (GdkEventCrossing */*ev*/)
751 within_track_canvas = true;
752 reset_canvas_action_sensitivity (true);
757 Editor::_ensure_time_axis_view_is_visible (const TimeAxisView& tav, bool at_top)
759 double begin = tav.y_position();
760 double v = vertical_adjustment.get_value ();
762 if (!at_top && (begin < v || begin + tav.current_height() > v + _visible_canvas_height)) {
763 /* try to put the TimeAxisView roughly central */
764 if (begin >= _visible_canvas_height/2.0) {
765 begin -= _visible_canvas_height/2.0;
769 /* Clamp the y pos so that we do not extend beyond the canvas full
772 if (_full_canvas_height - begin < _visible_canvas_height){
773 begin = _full_canvas_height - _visible_canvas_height;
776 vertical_adjustment.set_value (begin);
779 /** Called when the main vertical_adjustment has changed */
781 Editor::tie_vertical_scrolling ()
783 if (pending_visual_change.idle_handler_id < 0) {
784 _summary->set_overlays_dirty ();
789 Editor::set_horizontal_position (double p)
791 horizontal_adjustment.set_value (p);
793 leftmost_frame = (framepos_t) floor (p * samples_per_pixel);
795 update_fixed_rulers ();
796 redisplay_tempo (true);
798 if (pending_visual_change.idle_handler_id < 0) {
799 _summary->set_overlays_dirty ();
802 update_video_timeline();
806 Editor::color_handler()
808 playhead_cursor->set_color (ARDOUR_UI::config()->get_canvasvar_PlayHead());
809 _verbose_cursor->set_color (ARDOUR_UI::config()->get_canvasvar_VerboseCanvasCursor());
811 meter_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_MeterBar());
812 meter_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
814 tempo_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TempoBar());
815 tempo_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
817 marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_MarkerBar());
818 marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
820 cd_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CDMarkerBar());
821 cd_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
823 range_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeMarkerBar());
824 range_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
826 transport_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportMarkerBar());
827 transport_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
829 cd_marker_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
830 cd_marker_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
832 range_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
833 range_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
835 transport_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportDragRect());
836 transport_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportDragRect());
838 transport_loop_range_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportLoopRect());
839 transport_loop_range_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportLoopRect());
841 transport_punch_range_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportPunchRect());
842 transport_punch_range_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportPunchRect());
844 transport_punchin_line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_PunchLine());
845 transport_punchout_line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_PunchLine());
847 zoom_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_ZoomRect());
848 zoom_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_ZoomRect());
850 rubberband_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RubberBandRect());
851 rubberband_rect->set_fill_color ((guint32) ARDOUR_UI::config()->get_canvasvar_RubberBandRect());
853 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
854 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
855 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
856 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
857 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
859 refresh_location_display ();
861 redisplay_tempo (true);
864 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks); // redraw metric markers
869 Editor::horizontal_position () const
871 return sample_to_pixel (leftmost_frame);
875 Editor::set_canvas_cursor (Gdk::Cursor* cursor, bool save)
878 current_canvas_cursor = cursor;
881 Glib::RefPtr<Gdk::Window> win = _track_canvas->get_window();
884 _track_canvas->get_window()->set_cursor (*cursor);
889 Editor::track_canvas_key_press (GdkEventKey*)
891 /* XXX: event does not report the modifier key pressed down, AFAICS, so use the Keyboard object instead */
892 if (mouse_mode == Editing::MouseZoom && Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
893 set_canvas_cursor (_cursors->zoom_out, true);
900 Editor::track_canvas_key_release (GdkEventKey*)
902 if (mouse_mode == Editing::MouseZoom && !Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
903 set_canvas_cursor (_cursors->zoom_in, true);
910 Editor::clamp_verbose_cursor_x (double x)
915 x = min (_visible_canvas_width - 200.0, x);
921 Editor::clamp_verbose_cursor_y (double y)
924 y = min (_visible_canvas_height - 50, y);
929 Editor::get_time_bars_group () const
931 return _time_bars_canvas->root();
935 Editor::get_track_canvas_group() const
937 return hv_scroll_group;
940 ArdourCanvas::GtkCanvasViewport*
941 Editor::get_time_bars_canvas() const
943 return _time_bars_canvas_viewport;
946 ArdourCanvas::GtkCanvasViewport*
947 Editor::get_track_canvas() const
949 return _track_canvas_viewport;