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;
63 /* XXX this is a hack. it ought to be the maximum value of an framepos_t */
65 const double max_canvas_coordinate = (double) UINT32_MAX;
68 Editor::initialize_canvas ()
70 _track_canvas_viewport = new ArdourCanvas::GtkCanvasViewport (horizontal_adjustment, vertical_adjustment);
71 _track_canvas = _track_canvas_viewport->canvas ();
73 _time_bars_canvas_viewport = new ArdourCanvas::GtkCanvasViewport (horizontal_adjustment, unused_adjustment);
74 _time_bars_canvas = _time_bars_canvas_viewport->canvas ();
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 (_track_canvas->root());
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 (_track_canvas->root());
104 CANVAS_DEBUG_NAME (time_line_group, "time line group");
106 _trackview_group = new ArdourCanvas::Group (_track_canvas->root());
107 CANVAS_DEBUG_NAME (_trackview_group, "Canvas TrackViews");
108 _region_motion_group = new ArdourCanvas::Group (_trackview_group);
109 CANVAS_DEBUG_NAME (_region_motion_group, "Canvas Region Motion");
111 meter_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
112 meter_bar = new ArdourCanvas::Rectangle (meter_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
113 CANVAS_DEBUG_NAME (meter_bar, "meter Bar");
114 meter_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
116 tempo_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
117 tempo_bar = new ArdourCanvas::Rectangle (tempo_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
118 CANVAS_DEBUG_NAME (tempo_bar, "Tempo Bar");
119 tempo_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
121 range_marker_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
122 range_marker_bar = new ArdourCanvas::Rectangle (range_marker_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
123 CANVAS_DEBUG_NAME (range_marker_bar, "Range Marker Bar");
124 range_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
126 transport_marker_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
127 transport_marker_bar = new ArdourCanvas::Rectangle (transport_marker_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
128 CANVAS_DEBUG_NAME (transport_marker_bar, "transport Marker Bar");
129 transport_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
131 marker_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
132 marker_bar = new ArdourCanvas::Rectangle (marker_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
133 CANVAS_DEBUG_NAME (marker_bar, "Marker Bar");
134 marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
136 cd_marker_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
137 cd_marker_bar = new ArdourCanvas::Rectangle (cd_marker_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
138 CANVAS_DEBUG_NAME (cd_marker_bar, "CD Marker Bar");
139 cd_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
141 _time_markers_group = new ArdourCanvas::Group (_time_bars_canvas->root());
143 cd_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, 0.0));
144 CANVAS_DEBUG_NAME (cd_marker_group, "cd marker group");
145 /* the vide is temporarily placed a the same location as the
146 cd_marker_group, but is moved later.
148 videotl_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple(0.0, 0.0));
149 CANVAS_DEBUG_NAME (videotl_group, "videotl group");
150 marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, timebar_height + 1.0));
151 CANVAS_DEBUG_NAME (marker_group, "marker group");
152 transport_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 2.0) + 1.0));
153 CANVAS_DEBUG_NAME (transport_marker_group, "transport marker group");
154 range_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 3.0) + 1.0));
155 CANVAS_DEBUG_NAME (range_marker_group, "range marker group");
156 tempo_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 4.0) + 1.0));
157 CANVAS_DEBUG_NAME (tempo_group, "tempo group");
158 meter_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 5.0) + 1.0));
159 CANVAS_DEBUG_NAME (meter_group, "meter group");
161 ARDOUR_UI::instance()->video_timeline = new VideoTimeLine(this, videotl_group, (timebar_height * videotl_bar_height));
163 cd_marker_bar_drag_rect = new ArdourCanvas::Rectangle (cd_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
164 CANVAS_DEBUG_NAME (cd_marker_bar_drag_rect, "cd marker drag");
165 cd_marker_bar_drag_rect->set_outline (false);
166 cd_marker_bar_drag_rect->hide ();
168 range_bar_drag_rect = new ArdourCanvas::Rectangle (range_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
169 CANVAS_DEBUG_NAME (range_bar_drag_rect, "range drag");
170 range_bar_drag_rect->set_outline (false);
171 range_bar_drag_rect->hide ();
173 transport_bar_drag_rect = new ArdourCanvas::Rectangle (transport_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
174 CANVAS_DEBUG_NAME (transport_bar_drag_rect, "transport drag");
175 transport_bar_drag_rect->set_outline (false);
176 transport_bar_drag_rect->hide ();
178 transport_punchin_line = new ArdourCanvas::Line (_track_canvas->root());
179 transport_punchin_line->set_x0 (0);
180 transport_punchin_line->set_y0 (0);
181 transport_punchin_line->set_x1 (0);
182 transport_punchin_line->set_y1 (ArdourCanvas::COORD_MAX);
183 transport_punchin_line->hide ();
185 transport_punchout_line = new ArdourCanvas::Line (_track_canvas->root());
186 transport_punchout_line->set_x0 (0);
187 transport_punchout_line->set_y0 (0);
188 transport_punchout_line->set_x1 (0);
189 transport_punchout_line->set_y1 (ArdourCanvas::COORD_MAX);
190 transport_punchout_line->hide();
192 // used to show zoom mode active zooming
193 zoom_rect = new ArdourCanvas::Rectangle (_track_canvas->root(), ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0));
195 zoom_rect->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_zoom_rect_event), (ArdourCanvas::Item*) 0));
197 // used as rubberband rect
198 rubberband_rect = new ArdourCanvas::Rectangle (_trackview_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0));
199 rubberband_rect->hide();
201 tempo_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_tempo_bar_event), tempo_bar));
202 meter_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_meter_bar_event), meter_bar));
203 marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_marker_bar_event), marker_bar));
204 cd_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_cd_marker_bar_event), cd_marker_bar));
205 videotl_group->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_videotl_bar_event), videotl_group));
206 range_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_range_marker_bar_event), range_marker_bar));
207 transport_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_transport_marker_bar_event), transport_marker_bar));
209 playhead_cursor = new EditorCursor (*this, &Editor::canvas_playhead_cursor_event);
212 logo_item->lower_to_bottom ();
216 _canvas_bottom_rect = new ArdourCanvas::Rectangle (_track_canvas->root(), ArdourCanvas::Rect (0.0, 0.0, max_canvas_coordinate, 20));
217 /* this thing is transparent */
218 _canvas_bottom_rect->set_fill (false);
219 _canvas_bottom_rect->set_outline (false);
220 _canvas_bottom_rect->Event.connect (sigc::mem_fun (*this, &Editor::canvas_bottom_rect_event));
222 /* these signals will initially be delivered to the canvas itself, but if they end up remaining unhandled, they are passed to Editor-level
226 _track_canvas->signal_scroll_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_scroll_event));
227 _track_canvas->signal_motion_notify_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_motion_notify_event));
228 _track_canvas->signal_button_press_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_button_press_event));
229 _track_canvas->signal_button_release_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_button_release_event));
230 _track_canvas->signal_drag_motion().connect (sigc::mem_fun (*this, &Editor::track_canvas_drag_motion));
231 _track_canvas->signal_key_press_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_key_press));
232 _track_canvas->signal_key_release_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_key_release));
234 _track_canvas->set_name ("EditorMainCanvas");
235 _track_canvas->add_events (Gdk::POINTER_MOTION_HINT_MASK | Gdk::SCROLL_MASK | Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK);
236 _track_canvas->signal_leave_notify_event().connect (sigc::mem_fun(*this, &Editor::left_track_canvas), false);
237 _track_canvas->signal_enter_notify_event().connect (sigc::mem_fun(*this, &Editor::entered_track_canvas), false);
238 _track_canvas->set_flags (CAN_FOCUS);
240 /* set up drag-n-drop */
242 vector<TargetEntry> target_table;
244 // Drag-N-Drop from the region list can generate this target
245 target_table.push_back (TargetEntry ("regions"));
247 target_table.push_back (TargetEntry ("text/plain"));
248 target_table.push_back (TargetEntry ("text/uri-list"));
249 target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
251 _track_canvas->drag_dest_set (target_table);
252 _track_canvas->signal_drag_data_received().connect (sigc::mem_fun(*this, &Editor::track_canvas_drag_data_received));
254 _track_canvas_viewport->signal_size_allocate().connect (sigc::mem_fun(*this, &Editor::track_canvas_viewport_allocate));
256 ColorsChanged.connect (sigc::mem_fun (*this, &Editor::color_handler));
262 Editor::track_canvas_viewport_allocate (Gtk::Allocation alloc)
264 _canvas_viewport_allocation = alloc;
265 track_canvas_viewport_size_allocated ();
269 Editor::track_canvas_viewport_size_allocated ()
271 bool height_changed = _visible_canvas_height != _canvas_viewport_allocation.get_height();
273 _visible_canvas_width = _canvas_viewport_allocation.get_width ();
274 _visible_canvas_height = _canvas_viewport_allocation.get_height ();
278 if (height_changed) {
280 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
281 i->second->canvas_height_set (_visible_canvas_height);
284 vertical_adjustment.set_page_size (_visible_canvas_height);
285 if ((vertical_adjustment.get_value() + _visible_canvas_height) >= vertical_adjustment.get_upper()) {
287 We're increasing the size of the canvas while the bottom is visible.
288 We scroll down to keep in step with the controls layout.
290 vertical_adjustment.set_value (_full_canvas_height - _visible_canvas_height);
293 set_visible_track_count (_visible_track_count);
296 update_fixed_rulers();
297 redisplay_tempo (false);
298 _summary->set_overlays_dirty ();
302 Editor::reset_controls_layout_width ()
307 edit_controls_vbox.size_request (req);
310 if (_group_tabs->is_mapped()) {
311 _group_tabs->size_request (req);
315 /* the controls layout has no horizontal scrolling, its visible
316 width is always equal to the total width of its contents.
319 controls_layout.property_width() = w;
320 controls_layout.property_width_request() = w;
324 Editor::reset_controls_layout_height (int32_t h)
326 /* ensure that the rect that represents the "bottom" of the canvas
327 * (the drag-n-drop zone) is, in fact, at the bottom.
330 _canvas_bottom_rect->set_position (ArdourCanvas::Duple (0, h));
332 /* track controls layout must span the full height of "h" (all tracks)
333 * plus the bottom rect.
336 h += _canvas_bottom_rect->height ();
338 /* set the height of the scrollable area (i.e. the sum of all contained widgets)
339 * for the controls layout. The size request is set elsewhere.
342 controls_layout.property_height() = h;
347 Editor::track_canvas_map_handler (GdkEventAny* /*ev*/)
349 if (current_canvas_cursor) {
350 set_canvas_cursor (current_canvas_cursor);
355 /** This is called when something is dropped onto the track canvas */
357 Editor::track_canvas_drag_data_received (const RefPtr<Gdk::DragContext>& context,
359 const SelectionData& data,
360 guint info, guint time)
362 if (data.get_target() == "regions") {
363 drop_regions (context, x, y, data, info, time);
365 drop_paths (context, x, y, data, info, time);
370 Editor::idle_drop_paths (vector<string> paths, framepos_t frame, double ypos, bool copy)
372 drop_paths_part_two (paths, frame, ypos, copy);
377 Editor::drop_paths_part_two (const vector<string>& paths, framepos_t frame, double ypos, bool copy)
379 RouteTimeAxisView* tv;
381 /* MIDI files must always be imported, because we consider them
382 * writable. So split paths into two vectors, and follow the import
383 * path on the MIDI part.
386 vector<string> midi_paths;
387 vector<string> audio_paths;
389 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
390 if (SMFSource::safe_midi_file_extension (*i)) {
391 midi_paths.push_back (*i);
393 audio_paths.push_back (*i);
398 std::pair<TimeAxisView*, int> const tvp = trackview_by_y_position (ypos);
399 if (tvp.first == 0) {
401 /* drop onto canvas background: create new tracks */
405 do_import (midi_paths, Editing::ImportDistinctFiles, ImportAsTrack, SrcBest, frame);
407 if (Profile->get_sae() || Config->get_only_copy_imported_files() || copy) {
408 do_import (audio_paths, Editing::ImportDistinctFiles, Editing::ImportAsTrack, SrcBest, frame);
410 do_embed (audio_paths, Editing::ImportDistinctFiles, ImportAsTrack, frame);
413 } else if ((tv = dynamic_cast<RouteTimeAxisView*> (tvp.first)) != 0) {
415 /* check that its a track, not a bus */
418 /* select the track, then embed/import */
421 do_import (midi_paths, Editing::ImportSerializeFiles, ImportToTrack, SrcBest, frame);
423 if (Profile->get_sae() || Config->get_only_copy_imported_files() || copy) {
424 do_import (audio_paths, Editing::ImportSerializeFiles, Editing::ImportToTrack, SrcBest, frame);
426 do_embed (audio_paths, Editing::ImportSerializeFiles, ImportToTrack, frame);
433 Editor::drop_paths (const RefPtr<Gdk::DragContext>& context,
435 const SelectionData& data,
436 guint info, guint time)
438 vector<string> paths;
443 if (convert_drop_to_paths (paths, context, x, y, data, info, time) == 0) {
445 /* D-n-D coordinates are window-relative, so convert to "world" coordinates
448 ev.type = GDK_BUTTON_RELEASE;
452 frame = window_event_sample (&ev, 0, &cy);
456 bool copy = ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY);
458 /* We are not allowed to call recursive main event loops from within
459 the main event loop with GTK/Quartz. Since import/embed wants
460 to push up a progress dialog, defer all this till we go idle.
462 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun (*this, &Editor::idle_drop_paths), paths, frame, cy, copy));
464 drop_paths_part_two (paths, frame, cy, copy);
468 context->drag_finish (true, false, time);
471 /** @param allow_horiz true to allow horizontal autoscroll, otherwise false.
473 * @param allow_vert true to allow vertical autoscroll, otherwise false.
477 Editor::maybe_autoscroll (bool allow_horiz, bool allow_vert, bool from_headers)
479 if (!Config->get_autoscroll_editor ()) {
484 ArdourCanvas::Rect scrolling_boundary;
485 Gtk::Allocation alloc;
488 alloc = controls_layout.get_allocation ();
490 alloc = _track_canvas_viewport->get_allocation ();
492 /* the effective width of the autoscroll boundary so
493 that we start scrolling before we hit the edge.
495 this helps when the window is slammed up against the
496 right edge of the screen, making it hard to scroll
500 if (alloc.get_width() > 20) {
501 alloc.set_width (alloc.get_width() - 20);
502 alloc.set_x (alloc.get_x() + 10);
506 scrolling_boundary = ArdourCanvas::Rect (alloc.get_x(), alloc.get_y(),
507 alloc.get_x() + alloc.get_width(),
508 alloc.get_y() + alloc.get_height());
511 Gdk::ModifierType mask;
513 get_window()->get_pointer (x, y, mask);
515 if ((allow_horiz && (x < scrolling_boundary.x0 || x >= scrolling_boundary.x1)) ||
516 (allow_vert && (y < scrolling_boundary.y0 || y >= scrolling_boundary.y1))) {
517 start_canvas_autoscroll (allow_horiz, allow_vert, scrolling_boundary);
522 Editor::autoscroll_active () const
524 return autoscroll_connection.connected ();
528 Editor::autoscroll_canvas ()
531 Gdk::ModifierType mask;
532 frameoffset_t dx = 0;
533 bool no_stop = false;
534 bool y_motion = false;
536 get_window()->get_pointer (x, y, mask);
540 if (autoscroll_horizontal_allowed) {
542 framepos_t new_frame = leftmost_frame;
546 if (x > autoscroll_boundary.x1) {
548 /* bring it back into view */
549 dx = x - autoscroll_boundary.x1;
550 dx += 10 + (2 * (autoscroll_cnt/2));
552 dx = pixel_to_sample (dx);
554 if (leftmost_frame < max_framepos - dx) {
555 new_frame = leftmost_frame + dx;
557 new_frame = max_framepos;
562 } else if (x < autoscroll_boundary.x0) {
564 dx = autoscroll_boundary.x0 - x;
565 dx += 10 + (2 * (autoscroll_cnt/2));
567 dx = pixel_to_sample (dx);
569 if (leftmost_frame >= dx) {
570 new_frame = leftmost_frame - dx;
578 if (new_frame != leftmost_frame) {
579 vc.time_origin = new_frame;
580 vc.add (VisualChange::TimeOrigin);
584 if (autoscroll_vertical_allowed) {
586 const double vertical_pos = vertical_adjustment.get_value();
587 double new_pixel = vertical_pos;
588 const int speed_factor = 20;
592 new_pixel = vertical_pos;
594 if (y < autoscroll_boundary.y0) {
596 /* scroll to make higher tracks visible */
598 if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
599 y_motion = scroll_up_one_track ();
602 } else if (y > autoscroll_boundary.y1) {
604 if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
605 y_motion = scroll_down_one_track ();
615 /* change horizontal first */
621 /* now send a motion event to notify anyone who cares
622 that we have moved to a new location (because we scrolled)
627 ev.type = GDK_MOTION_NOTIFY;
628 ev.state = Gdk::BUTTON1_MASK;
630 /* the motion handler expects events in canvas coordinate space */
632 /* first convert from Editor window coordinates to canvas
639 /* clamp x and y to remain within the visible area */
641 x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1);
642 y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1);
644 translate_coordinates (*_track_canvas_viewport, x, y, cx, cy);
646 ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy));
650 motion_handler (0, (GdkEvent*) &ev, true);
652 } else if (no_stop) {
654 /* not changing visual state but pointer is outside the scrolling boundary
655 * so we still need to deliver a fake motion event
660 ev.type = GDK_MOTION_NOTIFY;
661 ev.state = Gdk::BUTTON1_MASK;
663 /* the motion handler expects events in canvas coordinate space */
665 /* first convert from Editor window coordinates to canvas
672 /* clamp x and y to remain within the visible area. except
673 * .. if horizontal scrolling is allowed, always allow us to
677 if (autoscroll_horizontal_allowed) {
678 x = min (max ((ArdourCanvas::Coord) x, 0.0), autoscroll_boundary.x1);
680 x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1);
682 y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1);
684 translate_coordinates (*_track_canvas_viewport, x, y, cx, cy);
686 ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy));
690 motion_handler (0, (GdkEvent*) &ev, true);
693 stop_canvas_autoscroll ();
699 return true; /* call me again */
703 Editor::start_canvas_autoscroll (bool allow_horiz, bool allow_vert, const ArdourCanvas::Rect& boundary)
709 stop_canvas_autoscroll ();
712 autoscroll_horizontal_allowed = allow_horiz;
713 autoscroll_vertical_allowed = allow_vert;
714 autoscroll_boundary = boundary;
716 /* do the first scroll right now
719 autoscroll_canvas ();
721 /* scroll again at very very roughly 30FPS */
723 autoscroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::autoscroll_canvas), 30);
727 Editor::stop_canvas_autoscroll ()
729 autoscroll_connection.disconnect ();
733 Editor::left_track_canvas (GdkEventCrossing */*ev*/)
736 within_track_canvas = false;
737 set_entered_track (0);
738 set_entered_regionview (0);
739 reset_canvas_action_sensitivity (false);
744 Editor::entered_track_canvas (GdkEventCrossing */*ev*/)
746 within_track_canvas = true;
747 reset_canvas_action_sensitivity (true);
752 Editor::_ensure_time_axis_view_is_visible (const TimeAxisView& tav, bool at_top)
754 double begin = tav.y_position();
755 double v = vertical_adjustment.get_value ();
757 if (!at_top && (begin < v || begin + tav.current_height() > v + _visible_canvas_height)) {
758 /* try to put the TimeAxisView roughly central */
759 if (begin >= _visible_canvas_height/2.0) {
760 begin -= _visible_canvas_height/2.0;
764 /* Clamp the y pos so that we do not extend beyond the canvas full
767 if (_full_canvas_height - begin < _visible_canvas_height){
768 begin = _full_canvas_height - _visible_canvas_height;
771 vertical_adjustment.set_value (begin);
774 /** Called when the main vertical_adjustment has changed */
776 Editor::tie_vertical_scrolling ()
778 if (pending_visual_change.idle_handler_id < 0) {
779 _summary->set_overlays_dirty ();
784 Editor::set_horizontal_position (double p)
786 horizontal_adjustment.set_value (p);
788 leftmost_frame = (framepos_t) floor (p * samples_per_pixel);
790 update_fixed_rulers ();
791 redisplay_tempo (true);
793 if (pending_visual_change.idle_handler_id < 0) {
794 _summary->set_overlays_dirty ();
797 update_video_timeline();
801 Editor::color_handler()
803 playhead_cursor->set_color (ARDOUR_UI::config()->get_canvasvar_PlayHead());
804 _verbose_cursor->set_color (ARDOUR_UI::config()->get_canvasvar_VerboseCanvasCursor());
806 meter_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_MeterBar());
807 meter_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
809 tempo_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TempoBar());
810 tempo_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
812 marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_MarkerBar());
813 marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
815 cd_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CDMarkerBar());
816 cd_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
818 range_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeMarkerBar());
819 range_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
821 transport_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportMarkerBar());
822 transport_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
824 cd_marker_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
825 cd_marker_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
827 range_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
828 range_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
830 transport_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportDragRect());
831 transport_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportDragRect());
833 transport_loop_range_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportLoopRect());
834 transport_loop_range_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportLoopRect());
836 transport_punch_range_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportPunchRect());
837 transport_punch_range_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportPunchRect());
839 transport_punchin_line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_PunchLine());
840 transport_punchout_line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_PunchLine());
842 zoom_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_ZoomRect());
843 zoom_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_ZoomRect());
845 rubberband_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RubberBandRect());
846 rubberband_rect->set_fill_color ((guint32) ARDOUR_UI::config()->get_canvasvar_RubberBandRect());
848 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
849 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
850 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
851 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
852 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
854 refresh_location_display ();
856 redisplay_tempo (true);
859 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks); // redraw metric markers
864 Editor::horizontal_position () const
866 return sample_to_pixel (leftmost_frame);
870 Editor::set_canvas_cursor (Gdk::Cursor* cursor, bool save)
873 current_canvas_cursor = cursor;
876 Glib::RefPtr<Gdk::Window> win = _track_canvas->get_window();
879 _track_canvas->get_window()->set_cursor (*cursor);
884 Editor::track_canvas_key_press (GdkEventKey*)
886 /* XXX: event does not report the modifier key pressed down, AFAICS, so use the Keyboard object instead */
887 if (mouse_mode == Editing::MouseZoom && Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
888 set_canvas_cursor (_cursors->zoom_out, true);
895 Editor::track_canvas_key_release (GdkEventKey*)
897 if (mouse_mode == Editing::MouseZoom && !Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
898 set_canvas_cursor (_cursors->zoom_in, true);
905 Editor::clamp_verbose_cursor_x (double x)
910 x = min (_visible_canvas_width - 200.0, x);
916 Editor::clamp_verbose_cursor_y (double y)
919 y = min (_visible_canvas_height - 50, y);
924 Editor::get_time_bars_group () const
926 return _time_bars_canvas->root();
930 Editor::get_track_canvas_group() const
932 return _track_canvas->root();
935 ArdourCanvas::GtkCanvasViewport*
936 Editor::get_time_bars_canvas() const
938 return _time_bars_canvas_viewport;
941 ArdourCanvas::GtkCanvasViewport*
942 Editor::get_track_canvas() const
944 return _track_canvas_viewport;