Monitor new signal to rebuild sendlist
[ardour.git] / gtk2_ardour / editor_canvas.cc
1 /*
2  * Copyright (C) 2005-2017 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2006-2015 David Robillard <d@drobilla.net>
4  * Copyright (C) 2007-2017 Tim Mayberry <mojofunk@gmail.com>
5  * Copyright (C) 2007 Doug McLain <doug@nostar.net>
6  * Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
7  * Copyright (C) 2013-2019 Robin Gareus <robin@gareus.org>
8  * Copyright (C) 2014-2019 Ben Loftis <ben@harrisonconsoles.com>
9  * Copyright (C) 2015-2017 Nick Mainsbridge <mainsbridge@gmail.com>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License along
22  * with this program; if not, write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 #ifdef WAF_BUILD
27 #include "gtk2ardour-config.h"
28 #endif
29
30 #include "gtkmm2ext/utils.h"
31
32 #include "ardour/profile.h"
33 #include "ardour/rc_configuration.h"
34 #include "ardour/smf_source.h"
35
36 #include "pbd/error.h"
37
38 #include "canvas/canvas.h"
39 #include "canvas/rectangle.h"
40 #include "canvas/pixbuf.h"
41 #include "canvas/scroll_group.h"
42 #include "canvas/text.h"
43 #include "canvas/debug.h"
44
45 #include "ardour_ui.h"
46 #include "automation_time_axis.h"
47 #include "editor.h"
48 #include "editing.h"
49 #include "rgb_macros.h"
50 #include "utils.h"
51 #include "audio_time_axis.h"
52 #include "editor_drag.h"
53 #include "region_view.h"
54 #include "editor_group_tabs.h"
55 #include "editor_summary.h"
56 #include "video_timeline.h"
57 #include "keyboard.h"
58 #include "editor_cursors.h"
59 #include "mouse_cursors.h"
60 #include "note_base.h"
61 #include "ui_config.h"
62 #include "verbose_cursor.h"
63
64 #include "pbd/i18n.h"
65
66 using namespace std;
67 using namespace ARDOUR;
68 using namespace ARDOUR_UI_UTILS;
69 using namespace PBD;
70 using namespace Gtk;
71 using namespace Glib;
72 using namespace Gtkmm2ext;
73 using namespace Editing;
74
75 void
76 Editor::initialize_canvas ()
77 {
78         _track_canvas_viewport = new ArdourCanvas::GtkCanvasViewport (horizontal_adjustment, vertical_adjustment);
79         _track_canvas = _track_canvas_viewport->canvas ();
80
81         _track_canvas->set_background_color (UIConfiguration::instance().color ("arrange base"));
82         _track_canvas->use_nsglview ();
83
84         /* scroll group for items that should not automatically scroll
85          *  (e.g verbose cursor). It shares the canvas coordinate space.
86         */
87         no_scroll_group = new ArdourCanvas::Container (_track_canvas->root());
88
89         ArdourCanvas::ScrollGroup* hsg;
90         ArdourCanvas::ScrollGroup* hg;
91         ArdourCanvas::ScrollGroup* cg;
92
93         h_scroll_group = hg = new ArdourCanvas::ScrollGroup (_track_canvas->root(), ArdourCanvas::ScrollGroup::ScrollsHorizontally);
94         CANVAS_DEBUG_NAME (h_scroll_group, "canvas h scroll");
95         _track_canvas->add_scroller (*hg);
96
97         hv_scroll_group = hsg = new ArdourCanvas::ScrollGroup (_track_canvas->root(),
98                                                                ArdourCanvas::ScrollGroup::ScrollSensitivity (ArdourCanvas::ScrollGroup::ScrollsVertically|
99                                                                                                              ArdourCanvas::ScrollGroup::ScrollsHorizontally));
100         CANVAS_DEBUG_NAME (hv_scroll_group, "canvas hv scroll");
101         _track_canvas->add_scroller (*hsg);
102
103         cursor_scroll_group = cg = new ArdourCanvas::ScrollGroup (_track_canvas->root(), ArdourCanvas::ScrollGroup::ScrollsHorizontally);
104         CANVAS_DEBUG_NAME (cursor_scroll_group, "canvas cursor scroll");
105         _track_canvas->add_scroller (*cg);
106
107         _verbose_cursor = new VerboseCursor (this);
108
109         /*a group to hold global rects like punch/loop indicators */
110         global_rect_group = new ArdourCanvas::Container (hv_scroll_group);
111         CANVAS_DEBUG_NAME (global_rect_group, "global rect group");
112
113         transport_loop_range_rect = new ArdourCanvas::Rectangle (global_rect_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, ArdourCanvas::COORD_MAX));
114         CANVAS_DEBUG_NAME (transport_loop_range_rect, "loop rect");
115         transport_loop_range_rect->hide();
116
117         transport_punch_range_rect = new ArdourCanvas::Rectangle (global_rect_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, ArdourCanvas::COORD_MAX));
118         CANVAS_DEBUG_NAME (transport_punch_range_rect, "punch rect");
119         transport_punch_range_rect->hide();
120
121         /*a group to hold time (measure) lines */
122         time_line_group = new ArdourCanvas::Container (h_scroll_group);
123         CANVAS_DEBUG_NAME (time_line_group, "time line group");
124
125         _trackview_group = new ArdourCanvas::Container (hv_scroll_group);
126         CANVAS_DEBUG_NAME (_trackview_group, "Canvas TrackViews");
127
128         // used as rubberband rect
129         rubberband_rect = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0));
130         rubberband_rect->hide();
131
132         /* a group to hold stuff while it gets dragged around. Must be the
133          * uppermost (last) group with hv_scroll_group as a parent
134          */
135         _drag_motion_group = new ArdourCanvas::Container (hv_scroll_group);
136         CANVAS_DEBUG_NAME (_drag_motion_group, "Canvas Drag Motion");
137
138         /* TIME BAR CANVAS */
139
140         _time_markers_group = new ArdourCanvas::Container (h_scroll_group);
141         CANVAS_DEBUG_NAME (_time_markers_group, "time bars");
142
143         cd_marker_group = new ArdourCanvas::Container (_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.
147         */
148         videotl_group = new ArdourCanvas::Container (_time_markers_group, ArdourCanvas::Duple(0.0, 0.0));
149         CANVAS_DEBUG_NAME (videotl_group, "videotl group");
150         marker_group = new ArdourCanvas::Container (_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::Container (_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::Container (_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::Container (_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::Container (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 5.0) + 1.0));
159         CANVAS_DEBUG_NAME (meter_group, "meter group");
160
161         meter_bar = new ArdourCanvas::Rectangle (meter_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
162         CANVAS_DEBUG_NAME (meter_bar, "meter Bar");
163         meter_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
164
165         tempo_bar = new ArdourCanvas::Rectangle (tempo_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
166         CANVAS_DEBUG_NAME (tempo_bar, "Tempo  Bar");
167         tempo_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
168
169         range_marker_bar = new ArdourCanvas::Rectangle (range_marker_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
170         CANVAS_DEBUG_NAME (range_marker_bar, "Range Marker Bar");
171         range_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
172
173         transport_marker_bar = new ArdourCanvas::Rectangle (transport_marker_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
174         CANVAS_DEBUG_NAME (transport_marker_bar, "transport Marker Bar");
175         transport_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
176
177         marker_bar = new ArdourCanvas::Rectangle (marker_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
178         CANVAS_DEBUG_NAME (marker_bar, "Marker Bar");
179         marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
180
181         cd_marker_bar = new ArdourCanvas::Rectangle (cd_marker_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
182         CANVAS_DEBUG_NAME (cd_marker_bar, "CD Marker Bar");
183         cd_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
184
185         ARDOUR_UI::instance()->video_timeline = new VideoTimeLine(this, videotl_group, (timebar_height * videotl_bar_height));
186
187         cd_marker_bar_drag_rect = new ArdourCanvas::Rectangle (cd_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
188         CANVAS_DEBUG_NAME (cd_marker_bar_drag_rect, "cd marker drag");
189         cd_marker_bar_drag_rect->set_outline (false);
190         cd_marker_bar_drag_rect->hide ();
191
192         range_bar_drag_rect = new ArdourCanvas::Rectangle (range_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
193         CANVAS_DEBUG_NAME (range_bar_drag_rect, "range drag");
194         range_bar_drag_rect->set_outline (false);
195         range_bar_drag_rect->hide ();
196
197         transport_bar_drag_rect = new ArdourCanvas::Rectangle (transport_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
198         CANVAS_DEBUG_NAME (transport_bar_drag_rect, "transport drag");
199         transport_bar_drag_rect->set_outline (false);
200         transport_bar_drag_rect->hide ();
201
202         transport_punchin_line = new ArdourCanvas::Line (hv_scroll_group);
203         transport_punchin_line->set_x0 (0);
204         transport_punchin_line->set_y0 (0);
205         transport_punchin_line->set_x1 (0);
206         transport_punchin_line->set_y1 (ArdourCanvas::COORD_MAX);
207         transport_punchin_line->hide ();
208
209         transport_punchout_line  = new ArdourCanvas::Line (hv_scroll_group);
210         transport_punchout_line->set_x0 (0);
211         transport_punchout_line->set_y0 (0);
212         transport_punchout_line->set_x1 (0);
213         transport_punchout_line->set_y1 (ArdourCanvas::COORD_MAX);
214         transport_punchout_line->hide();
215
216         tempo_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_tempo_bar_event), tempo_bar));
217         meter_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_meter_bar_event), meter_bar));
218         marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_marker_bar_event), marker_bar));
219         cd_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_cd_marker_bar_event), cd_marker_bar));
220         videotl_group->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_videotl_bar_event), videotl_group));
221         range_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_range_marker_bar_event), range_marker_bar));
222         transport_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_transport_marker_bar_event), transport_marker_bar));
223
224         playhead_cursor = new EditorCursor (*this, &Editor::canvas_playhead_cursor_event);
225
226         snapped_cursor = new EditorCursor (*this);
227
228         _canvas_drop_zone = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, 0.0));
229         /* this thing is transparent */
230         _canvas_drop_zone->set_fill (false);
231         _canvas_drop_zone->set_outline (false);
232         _canvas_drop_zone->Event.connect (sigc::mem_fun (*this, &Editor::canvas_drop_zone_event));
233
234         /* these signals will initially be delivered to the canvas itself, but if they end up remaining unhandled, they are passed to Editor-level
235            handlers.
236         */
237
238         _track_canvas->signal_scroll_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_scroll_event), true));
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));
245
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);
251
252         _track_canvas->PreRender.connect (sigc::mem_fun(*this, &Editor::pre_render));
253
254         /* set up drag-n-drop */
255
256         vector<TargetEntry> target_table;
257
258         target_table.push_back (TargetEntry ("regions")); // DnD from the region list will generate this target
259         target_table.push_back (TargetEntry ("sources")); // DnD from the source list will generate this target
260         target_table.push_back (TargetEntry ("text/uri-list"));
261         target_table.push_back (TargetEntry ("text/plain"));
262         target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
263
264         _track_canvas->drag_dest_set (target_table);
265         _track_canvas->signal_drag_data_received().connect (sigc::mem_fun(*this, &Editor::track_canvas_drag_data_received));
266
267         _track_canvas_viewport->signal_size_allocate().connect (sigc::mem_fun(*this, &Editor::track_canvas_viewport_allocate));
268
269         initialize_rulers ();
270
271         UIConfiguration::instance().ColorsChanged.connect (sigc::mem_fun (*this, &Editor::color_handler));
272         color_handler();
273
274 }
275
276 void
277 Editor::track_canvas_viewport_allocate (Gtk::Allocation alloc)
278 {
279         _canvas_viewport_allocation = alloc;
280         track_canvas_viewport_size_allocated ();
281 }
282
283 void
284 Editor::track_canvas_viewport_size_allocated ()
285 {
286         bool height_changed = _visible_canvas_height != _canvas_viewport_allocation.get_height();
287
288         _visible_canvas_width  = _canvas_viewport_allocation.get_width ();
289         _visible_canvas_height = _canvas_viewport_allocation.get_height ();
290
291         _canvas_drop_zone->set_y1 (_canvas_drop_zone->y0() + (_visible_canvas_height - 20.0));
292
293         // SHOWTRACKS
294
295         if (height_changed) {
296
297                 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
298                         i->second->canvas_height_set (_visible_canvas_height);
299                 }
300
301                 vertical_adjustment.set_page_size (_visible_canvas_height);
302                 if ((vertical_adjustment.get_value() + _visible_canvas_height) >= vertical_adjustment.get_upper()) {
303                         /*
304                            We're increasing the size of the canvas while the bottom is visible.
305                            We scroll down to keep in step with the controls layout.
306                         */
307                         vertical_adjustment.set_value (_full_canvas_height - _visible_canvas_height);
308                 }
309
310                 set_visible_track_count (_visible_track_count);
311         }
312
313         update_fixed_rulers();
314         redisplay_grid (false);
315         _summary->set_overlays_dirty ();
316 }
317
318 void
319 Editor::reset_controls_layout_width ()
320 {
321         GtkRequisition req = { 0, 0 };
322         gint w;
323
324         edit_controls_vbox.size_request (req);
325         w = req.width;
326
327         if (_group_tabs->is_visible()) {
328                 _group_tabs->size_request (req);
329                 w += req.width;
330         }
331
332         /* the controls layout has no horizontal scrolling, its visible
333            width is always equal to the total width of its contents.
334         */
335
336         controls_layout.property_width() = w;
337         controls_layout.property_width_request() = w;
338 }
339
340 void
341 Editor::reset_controls_layout_height (int32_t h)
342 {
343         /* ensure that the rect that represents the "bottom" of the canvas
344          * (the drag-n-drop zone) is, in fact, at the bottom.
345          */
346
347         _canvas_drop_zone->set_position (ArdourCanvas::Duple (0, h));
348
349         /* track controls layout must span the full height of "h" (all tracks)
350          * plus the bottom rect.
351          */
352
353         h += _canvas_drop_zone->height ();
354
355         /* set the height of the scrollable area (i.e. the sum of all contained widgets)
356          * for the controls layout. The size request is set elsewhere.
357          */
358
359         controls_layout.property_height() = h;
360
361 }
362
363 bool
364 Editor::track_canvas_map_handler (GdkEventAny* /*ev*/)
365 {
366         if (!_cursor_stack.empty()) {
367                 set_canvas_cursor (get_canvas_cursor());
368         } else {
369                 PBD::error << "cursor stack is empty" << endmsg;
370         }
371         return false;
372 }
373
374 /** This is called when something is dropped onto the track canvas */
375 void
376 Editor::track_canvas_drag_data_received (const RefPtr<Gdk::DragContext>& context,
377                                          int x, int y,
378                                          const SelectionData& data,
379                                          guint info, guint time)
380 {
381         if (!ARDOUR_UI_UTILS::engine_is_running ()) {
382                 return;
383         }
384         if (data.get_target() == X_("regions")) {
385                 drop_regions (context, x, y, data, info, time, true);
386         } else if (data.get_target() == X_("sources")) {
387                 drop_regions (context, x, y, data, info, time, false);
388         } else {
389                 drop_paths (context, x, y, data, info, time);
390         }
391 }
392
393 bool
394 Editor::idle_drop_paths (vector<string> paths, samplepos_t sample, double ypos, bool copy)
395 {
396         drop_paths_part_two (paths, sample, ypos, copy);
397         return false;
398 }
399
400 void
401 Editor::drop_paths_part_two (const vector<string>& paths, samplepos_t sample, double ypos, bool copy)
402 {
403         RouteTimeAxisView* tv;
404
405         /* MIDI files must always be imported, because we consider them
406          * writable. So split paths into two vectors, and follow the import
407          * path on the MIDI part.
408          */
409
410         vector<string> midi_paths;
411         vector<string> audio_paths;
412
413         for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
414                 if (SMFSource::safe_midi_file_extension (*i)) {
415                         midi_paths.push_back (*i);
416                 } else {
417                         audio_paths.push_back (*i);
418                 }
419         }
420
421
422         std::pair<TimeAxisView*, int> const tvp = trackview_by_y_position (ypos, false);
423         if (tvp.first == 0) {
424
425                 /* drop onto canvas background: create new tracks */
426
427                 sample = 0;
428                 InstrumentSelector is; // instantiation builds instrument-list and sets default.
429                 do_import (midi_paths, Editing::ImportDistinctFiles, ImportAsTrack, SrcBest, SMFTrackName, SMFTempoIgnore, sample, is.selected_instrument());
430
431                 if (UIConfiguration::instance().get_only_copy_imported_files() || copy) {
432                         do_import (audio_paths, Editing::ImportDistinctFiles, Editing::ImportAsTrack,
433                                    SrcBest, SMFTrackName, SMFTempoIgnore, sample);
434                 } else {
435                         do_embed (audio_paths, Editing::ImportDistinctFiles, ImportAsTrack, sample);
436                 }
437
438         } else if ((tv = dynamic_cast<RouteTimeAxisView*> (tvp.first)) != 0) {
439
440                 /* check that its a track, not a bus */
441
442                 if (tv->track()) {
443                         /* select the track, then embed/import */
444                         selection->set (tv);
445
446                         do_import (midi_paths, Editing::ImportSerializeFiles, ImportToTrack,
447                                    SrcBest, SMFTrackName, SMFTempoIgnore, sample);
448
449                         if (UIConfiguration::instance().get_only_copy_imported_files() || copy) {
450                                 do_import (audio_paths, Editing::ImportSerializeFiles, Editing::ImportToTrack,
451                                            SrcBest, SMFTrackName, SMFTempoIgnore, sample);
452                         } else {
453                                 do_embed (audio_paths, Editing::ImportSerializeFiles, ImportToTrack, sample);
454                         }
455                 }
456         }
457 }
458
459 void
460 Editor::drop_paths (const RefPtr<Gdk::DragContext>& context,
461                     int x, int y,
462                     const SelectionData& data,
463                     guint info, guint time)
464 {
465         vector<string> paths;
466         GdkEvent ev;
467         double cy;
468
469         if (convert_drop_to_paths (paths, context, x, y, data, info, time) == 0) {
470
471                 /* D-n-D coordinates are window-relative, so convert to canvas coordinates
472                  */
473
474                 ev.type = GDK_BUTTON_RELEASE;
475                 ev.button.x = x;
476                 ev.button.y = y;
477
478                 MusicSample when (window_event_sample (&ev, 0, &cy), 0);
479                 snap_to (when);
480
481                 bool copy = ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY);
482 #ifdef __APPLE__
483                 /* We are not allowed to call recursive main event loops from within
484                    the main event loop with GTK/Quartz. Since import/embed wants
485                    to push up a progress dialog, defer all this till we go idle.
486                 */
487                 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun (*this, &Editor::idle_drop_paths), paths, when.sample, cy, copy));
488 #else
489                 drop_paths_part_two (paths, when.sample, cy, copy);
490 #endif
491         }
492
493         context->drag_finish (true, false, time);
494 }
495
496 /** @param allow_horiz true to allow horizontal autoscroll, otherwise false.
497  *
498  *  @param allow_vert true to allow vertical autoscroll, otherwise false.
499  *
500  */
501 void
502 Editor::maybe_autoscroll (bool allow_horiz, bool allow_vert, bool from_headers)
503 {
504         Gtk::Window* toplevel = dynamic_cast<Gtk::Window*>(contents().get_toplevel());
505
506         if (!toplevel) {
507                 return;
508         }
509
510         if (!UIConfiguration::instance().get_autoscroll_editor () || autoscroll_active ()) {
511                 return;
512         }
513
514         /* define a rectangular boundary for scrolling. If the mouse moves
515          * outside of this area and/or continue to be outside of this area,
516          * then we will continuously auto-scroll the canvas in the appropriate
517          * direction(s)
518          *
519          * the boundary is defined in coordinates relative to the toplevel
520          * window since that is what we're going to call ::get_pointer() on
521          * during autoscrolling to determine if we're still outside the
522          * boundary or not.
523          */
524
525         ArdourCanvas::Rect scrolling_boundary;
526         Gtk::Allocation alloc;
527
528         if (from_headers) {
529                 alloc = controls_layout.get_allocation ();
530
531                 int wx, wy;
532
533                 controls_layout.get_parent()->translate_coordinates (*toplevel,
534                                                                      alloc.get_x(), alloc.get_y(),
535                                                                      wx, wy);
536
537                 scrolling_boundary = ArdourCanvas::Rect (wx, wy, wx + alloc.get_width(), wy + alloc.get_height());
538
539
540         } else {
541                 alloc = _track_canvas_viewport->get_allocation ();
542
543                 /* reduce height by the height of the timebars, which happens
544                    to correspond to the position of the hv_scroll_group.
545                 */
546
547                 alloc.set_height (alloc.get_height() - hv_scroll_group->position().y);
548                 alloc.set_y (alloc.get_y() + hv_scroll_group->position().y);
549
550                 /* now reduce it again so that we start autoscrolling before we
551                  * move off the top or bottom of the canvas
552                  */
553
554                 alloc.set_height (alloc.get_height() - 20);
555                 alloc.set_y (alloc.get_y() + 10);
556
557                 /* the effective width of the autoscroll boundary so
558                    that we start scrolling before we hit the edge.
559
560                    this helps when the window is slammed up against the
561                    right edge of the screen, making it hard to scroll
562                    effectively.
563                 */
564
565                 if (alloc.get_width() > 20) {
566                         alloc.set_width (alloc.get_width() - 20);
567                         alloc.set_x (alloc.get_x() + 10);
568                 }
569
570                 int wx, wy;
571
572                 _track_canvas_viewport->get_parent()->translate_coordinates (*toplevel,
573                                                                              alloc.get_x(), alloc.get_y(),
574                                                                              wx, wy);
575
576                 scrolling_boundary = ArdourCanvas::Rect (wx, wy, wx + alloc.get_width(), wy + alloc.get_height());
577         }
578
579         int x, y;
580         Gdk::ModifierType mask;
581
582         toplevel->get_window()->get_pointer (x, y, mask);
583
584         if ((allow_horiz && ((x < scrolling_boundary.x0 && _leftmost_sample > 0) || x >= scrolling_boundary.x1)) ||
585             (allow_vert && ((y < scrolling_boundary.y0 && vertical_adjustment.get_value() > 0)|| y >= scrolling_boundary.y1))) {
586                 start_canvas_autoscroll (allow_horiz, allow_vert, scrolling_boundary);
587         }
588 }
589
590 bool
591 Editor::autoscroll_active () const
592 {
593         return autoscroll_connection.connected ();
594 }
595
596 std::pair <samplepos_t,samplepos_t>
597 Editor::session_gui_extents (bool use_extra) const
598 {
599         if (!_session) {
600                 return std::pair <samplepos_t,samplepos_t>(max_samplepos,0);
601         }
602
603         samplecnt_t session_extent_start = _session->current_start_sample();
604         samplecnt_t session_extent_end = _session->current_end_sample();
605
606         /* calculate the extents of all regions in every playlist
607          * NOTE: we should listen to playlists, and cache these values so we don't calculate them every time.
608          */
609         {
610                 boost::shared_ptr<RouteList> rl = _session->get_routes();
611                 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
612                         boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*r);
613                         if (tr) {
614                                 boost::shared_ptr<Playlist> pl = tr->playlist();
615                                 if (pl && !pl->all_regions_empty()) {
616                                         pair<samplepos_t, samplepos_t> e;
617                                         e = pl->get_extent();
618                                         if (e.first < session_extent_start) {
619                                                 session_extent_start = e.first;
620                                         }
621                                         if (e.second > session_extent_end) {
622                                                 session_extent_end = e.second;
623                                         }
624                                 }
625                         }
626                 }
627         }
628
629         /* ToDo: also incorporate automation regions (in case the session has no audio/midi but is just used for automating plugins or the like) */
630
631         /* add additional time to the ui extents (user-defined in config) */
632         if (use_extra) {
633                 samplecnt_t const extra = UIConfiguration::instance().get_extra_ui_extents_time() * 60 * _session->nominal_sample_rate();
634                 session_extent_end += extra;
635                 session_extent_start -= extra;
636         }
637
638         /* range-check */
639         if (session_extent_end > max_samplepos) {
640                 session_extent_end = max_samplepos;
641         }
642         if (session_extent_start < 0) {
643                 session_extent_start = 0;
644         }
645
646         std::pair <samplepos_t,samplepos_t> ret (session_extent_start, session_extent_end);
647         return ret;
648 }
649
650 bool
651 Editor::autoscroll_canvas ()
652 {
653         int x, y;
654         Gdk::ModifierType mask;
655         sampleoffset_t dx = 0;
656         bool no_stop = false;
657         Gtk::Window* toplevel = dynamic_cast<Gtk::Window*>(contents().get_toplevel());
658
659         if (!toplevel) {
660                 return false;
661         }
662
663         toplevel->get_window()->get_pointer (x, y, mask);
664
665         VisualChange vc;
666         bool vertical_motion = false;
667
668         if (autoscroll_horizontal_allowed) {
669
670                 samplepos_t new_sample = _leftmost_sample;
671
672                 /* horizontal */
673
674                 if (x > autoscroll_boundary.x1) {
675
676                         /* bring it back into view */
677                         dx = x - autoscroll_boundary.x1;
678                         dx += 10 + (2 * (autoscroll_cnt/2));
679
680                         dx = pixel_to_sample (dx);
681
682                         dx *= UIConfiguration::instance().get_draggable_playhead_speed();
683
684                         if (_leftmost_sample < max_samplepos - dx) {
685                                 new_sample = _leftmost_sample + dx;
686                         } else {
687                                 new_sample = max_samplepos;
688                         }
689
690                         no_stop = true;
691
692                 } else if (x < autoscroll_boundary.x0) {
693
694                         dx = autoscroll_boundary.x0 - x;
695                         dx += 10 + (2 * (autoscroll_cnt/2));
696
697                         dx = pixel_to_sample (dx);
698
699                         dx *= UIConfiguration::instance().get_draggable_playhead_speed();
700
701                         if (_leftmost_sample >= dx) {
702                                 new_sample = _leftmost_sample - dx;
703                         } else {
704                                 new_sample = 0;
705                         }
706
707                         no_stop = true;
708                 }
709
710                 if (new_sample != _leftmost_sample) {
711                         vc.time_origin = new_sample;
712                         vc.add (VisualChange::TimeOrigin);
713                 }
714         }
715
716         if (autoscroll_vertical_allowed) {
717
718                 // const double vertical_pos = vertical_adjustment.get_value();
719                 const int speed_factor = 10;
720
721                 /* vertical */
722
723                 if (y < autoscroll_boundary.y0) {
724
725                         /* scroll to make higher tracks visible */
726
727                         if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
728                                 scroll_up_one_track ();
729                                 vertical_motion = true;
730                         }
731                         no_stop = true;
732
733                 } else if (y > autoscroll_boundary.y1) {
734
735                         if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
736                                 scroll_down_one_track ();
737                                 vertical_motion = true;
738                         }
739                         no_stop = true;
740                 }
741
742         }
743
744         if (vc.pending || vertical_motion) {
745
746                 /* change horizontal first */
747
748                 if (vc.pending) {
749                         visual_changer (vc);
750                 }
751
752                 /* now send a motion event to notify anyone who cares
753                    that we have moved to a new location (because we scrolled)
754                 */
755
756                 GdkEventMotion ev;
757
758                 ev.type = GDK_MOTION_NOTIFY;
759                 ev.state = Gdk::BUTTON1_MASK;
760
761                 /* the motion handler expects events in canvas coordinate space */
762
763                 /* we asked for the mouse position above (::get_pointer()) via
764                  * our own top level window (we being the Editor). Convert into
765                  * coordinates within the canvas window.
766                  */
767
768                 int cx;
769                 int cy;
770
771                 toplevel->translate_coordinates (*_track_canvas, x, y, cx, cy);
772
773                 /* clamp x and y to remain within the autoscroll boundary,
774                  * which is defined in window coordinates
775                  */
776
777                 x = min (max ((ArdourCanvas::Coord) cx, autoscroll_boundary.x0), autoscroll_boundary.x1);
778                 y = min (max ((ArdourCanvas::Coord) cy, autoscroll_boundary.y0), autoscroll_boundary.y1);
779
780                 /* now convert from Editor window coordinates to canvas
781                  * window coordinates
782                  */
783
784                 ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy));
785                 ev.x = d.x;
786                 ev.y = d.y;
787                 ev.state = mask;
788
789                 motion_handler (0, (GdkEvent*) &ev, true);
790
791         } else if (no_stop) {
792
793                 /* not changing visual state but pointer is outside the scrolling boundary
794                  * so we still need to deliver a fake motion event
795                  */
796
797                 GdkEventMotion ev;
798
799                 ev.type = GDK_MOTION_NOTIFY;
800                 ev.state = Gdk::BUTTON1_MASK;
801
802                 /* the motion handler expects events in canvas coordinate space */
803
804                 /* first convert from Editor window coordinates to canvas
805                  * window coordinates
806                  */
807
808                 int cx;
809                 int cy;
810
811                 /* clamp x and y to remain within the visible area. except
812                  * .. if horizontal scrolling is allowed, always allow us to
813                  * move back to zero
814                  */
815
816                 if (autoscroll_horizontal_allowed) {
817                         x = min (max ((ArdourCanvas::Coord) x, 0.0), autoscroll_boundary.x1);
818                 } else {
819                         x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1);
820                 }
821                 y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1);
822
823                 toplevel->translate_coordinates (*_track_canvas_viewport, x, y, cx, cy);
824
825                 ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy));
826                 ev.x = d.x;
827                 ev.y = d.y;
828                 ev.state = mask;
829
830                 motion_handler (0, (GdkEvent*) &ev, true);
831
832         } else {
833                 stop_canvas_autoscroll ();
834                 return false;
835         }
836
837         autoscroll_cnt++;
838
839         return true; /* call me again */
840 }
841
842 void
843 Editor::start_canvas_autoscroll (bool allow_horiz, bool allow_vert, const ArdourCanvas::Rect& boundary)
844 {
845         if (!_session) {
846                 return;
847         }
848
849         stop_canvas_autoscroll ();
850
851         autoscroll_horizontal_allowed = allow_horiz;
852         autoscroll_vertical_allowed = allow_vert;
853         autoscroll_boundary = boundary;
854
855         /* do the first scroll right now
856         */
857
858         autoscroll_canvas ();
859
860         /* scroll again at very very roughly 30FPS */
861
862         autoscroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::autoscroll_canvas), 30);
863 }
864
865 void
866 Editor::stop_canvas_autoscroll ()
867 {
868         autoscroll_connection.disconnect ();
869         autoscroll_cnt = 0;
870 }
871
872 Editor::EnterContext*
873 Editor::get_enter_context(ItemType type)
874 {
875         for (ssize_t i = _enter_stack.size() - 1; i >= 0; --i) {
876                 if (_enter_stack[i].item_type == type) {
877                         return &_enter_stack[i];
878                 }
879         }
880         return NULL;
881 }
882
883 bool
884 Editor::left_track_canvas (GdkEventCrossing* ev)
885 {
886         const bool was_within = within_track_canvas;
887         DropDownKeys ();
888         within_track_canvas = false;
889         set_entered_track (0);
890         set_entered_regionview (0);
891         reset_canvas_action_sensitivity (false);
892
893         if (was_within) {
894                 if (ev->detail == GDK_NOTIFY_NONLINEAR ||
895                     ev->detail == GDK_NOTIFY_NONLINEAR_VIRTUAL) {
896                         /* context menu or something similar */
897                         sensitize_the_right_region_actions (false);
898                 } else {
899                         sensitize_the_right_region_actions (true);
900                 }
901         }
902
903         return false;
904 }
905
906 bool
907 Editor::entered_track_canvas (GdkEventCrossing* ev)
908 {
909         const bool was_within = within_track_canvas;
910         within_track_canvas = true;
911         reset_canvas_action_sensitivity (true);
912
913         if (!was_within) {
914                 if (ev->detail == GDK_NOTIFY_NONLINEAR ||
915                     ev->detail == GDK_NOTIFY_NONLINEAR_VIRTUAL) {
916                         /* context menu or something similar */
917                         sensitize_the_right_region_actions (false);
918                 } else {
919                         sensitize_the_right_region_actions (true);
920                 }
921         }
922
923         return false;
924 }
925
926 void
927 Editor::ensure_time_axis_view_is_visible (TimeAxisView const & track, bool at_top)
928 {
929         if (track.hidden()) {
930                 return;
931         }
932
933         /* compute visible area of trackview group, as offsets from top of
934          * trackview group.
935          */
936
937         double const current_view_min_y = vertical_adjustment.get_value();
938         double const current_view_max_y = current_view_min_y + vertical_adjustment.get_page_size();
939
940         double const track_min_y = track.y_position ();
941         double const track_max_y = track.y_position () + track.effective_height ();
942
943         if (!at_top &&
944             (track_min_y >= current_view_min_y &&
945              track_max_y < current_view_max_y)) {
946                 /* already visible, and caller did not ask to place it at the
947                  * top of the track canvas
948                  */
949                 return;
950         }
951
952         double new_value;
953
954         if (at_top) {
955                 new_value = track_min_y;
956         } else {
957                 if (track_min_y < current_view_min_y) {
958                         // Track is above the current view
959                         new_value = track_min_y;
960                 } else if (track_max_y > current_view_max_y) {
961                         // Track is below the current view
962                         new_value = track.y_position () + track.effective_height() - vertical_adjustment.get_page_size();
963                 } else {
964                         new_value = track_min_y;
965                 }
966         }
967
968         vertical_adjustment.set_value(new_value);
969 }
970
971 /** Called when the main vertical_adjustment has changed */
972 void
973 Editor::tie_vertical_scrolling ()
974 {
975         if (pending_visual_change.idle_handler_id < 0) {
976                 _summary->set_overlays_dirty ();
977         }
978 }
979
980 void
981 Editor::set_horizontal_position (double p)
982 {
983         horizontal_adjustment.set_value (p);
984
985         _leftmost_sample = (samplepos_t) floor (p * samples_per_pixel);
986 }
987
988 void
989 Editor::color_handler()
990 {
991         Gtkmm2ext::Color base = UIConfiguration::instance().color ("ruler base");
992         Gtkmm2ext::Color text = UIConfiguration::instance().color ("ruler text");
993         timecode_ruler->set_fill_color (base);
994         timecode_ruler->set_outline_color (text);
995         minsec_ruler->set_fill_color (base);
996         minsec_ruler->set_outline_color (text);
997         samples_ruler->set_fill_color (base);
998         samples_ruler->set_outline_color (text);
999         bbt_ruler->set_fill_color (base);
1000         bbt_ruler->set_outline_color (text);
1001
1002         playhead_cursor->set_color (UIConfiguration::instance().color ("play head"));
1003
1004         meter_bar->set_fill_color (UIConfiguration::instance().color_mod ("meter bar", "marker bar"));
1005         meter_bar->set_outline_color (UIConfiguration::instance().color ("marker bar separator"));
1006
1007         tempo_bar->set_fill_color (UIConfiguration::instance().color_mod ("tempo bar", "marker bar"));
1008         tempo_bar->set_outline_color (UIConfiguration::instance().color ("marker bar separator"));
1009
1010         marker_bar->set_fill_color (UIConfiguration::instance().color_mod ("marker bar", "marker bar"));
1011         marker_bar->set_outline_color (UIConfiguration::instance().color ("marker bar separator"));
1012
1013         cd_marker_bar->set_fill_color (UIConfiguration::instance().color_mod ("cd marker bar", "marker bar"));
1014         cd_marker_bar->set_outline_color (UIConfiguration::instance().color ("marker bar separator"));
1015
1016         range_marker_bar->set_fill_color (UIConfiguration::instance().color_mod ("range marker bar", "marker bar"));
1017         range_marker_bar->set_outline_color (UIConfiguration::instance().color ("marker bar separator"));
1018
1019         transport_marker_bar->set_fill_color (UIConfiguration::instance().color_mod ("transport marker bar", "marker bar"));
1020         transport_marker_bar->set_outline_color (UIConfiguration::instance().color ("marker bar separator"));
1021
1022         cd_marker_bar_drag_rect->set_fill_color (UIConfiguration::instance().color ("range drag bar rect"));
1023         cd_marker_bar_drag_rect->set_outline_color (UIConfiguration::instance().color ("range drag bar rect"));
1024
1025         range_bar_drag_rect->set_fill_color (UIConfiguration::instance().color ("range drag bar rect"));
1026         range_bar_drag_rect->set_outline_color (UIConfiguration::instance().color ("range drag bar rect"));
1027
1028         transport_bar_drag_rect->set_fill_color (UIConfiguration::instance().color ("transport drag rect"));
1029         transport_bar_drag_rect->set_outline_color (UIConfiguration::instance().color ("transport drag rect"));
1030
1031         transport_loop_range_rect->set_fill_color (UIConfiguration::instance().color_mod ("transport loop rect", "loop rectangle"));
1032         transport_loop_range_rect->set_outline_color (UIConfiguration::instance().color ("transport loop rect"));
1033
1034         transport_punch_range_rect->set_fill_color (UIConfiguration::instance().color ("transport punch rect"));
1035         transport_punch_range_rect->set_outline_color (UIConfiguration::instance().color ("transport punch rect"));
1036
1037         transport_punchin_line->set_outline_color (UIConfiguration::instance().color ("punch line"));
1038         transport_punchout_line->set_outline_color (UIConfiguration::instance().color ("punch line"));
1039
1040         rubberband_rect->set_outline_color (UIConfiguration::instance().color ("rubber band rect"));
1041         rubberband_rect->set_fill_color (UIConfiguration::instance().color_mod ("rubber band rect", "selection rect"));
1042
1043         location_marker_color = UIConfiguration::instance().color ("location marker");
1044         location_range_color = UIConfiguration::instance().color ("location range");
1045         location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
1046         location_loop_color = UIConfiguration::instance().color ("location loop");
1047         location_punch_color = UIConfiguration::instance().color ("location punch");
1048
1049         refresh_location_display ();
1050
1051         NoteBase::set_colors ();
1052
1053         /* redraw the whole thing */
1054         _track_canvas->set_background_color (UIConfiguration::instance().color ("arrange base"));
1055         _track_canvas->queue_draw ();
1056
1057 /*
1058         redisplay_grid (true);
1059
1060         if (_session)
1061               _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks); // redraw metric markers
1062 */
1063 }
1064
1065 double
1066 Editor::horizontal_position () const
1067 {
1068         return sample_to_pixel (_leftmost_sample);
1069 }
1070
1071 bool
1072 Editor::track_canvas_key_press (GdkEventKey*)
1073 {
1074         return false;
1075 }
1076
1077 bool
1078 Editor::track_canvas_key_release (GdkEventKey*)
1079 {
1080         return false;
1081 }
1082
1083 double
1084 Editor::clamp_verbose_cursor_x (double x)
1085 {
1086         if (x < 0) {
1087                 x = 0;
1088         } else {
1089                 x = min (_visible_canvas_width - 200.0, x);
1090         }
1091         return x;
1092 }
1093
1094 double
1095 Editor::clamp_verbose_cursor_y (double y)
1096 {
1097         y = max (0.0, y);
1098         y = min (_visible_canvas_height - 50, y);
1099         return y;
1100 }
1101
1102 ArdourCanvas::GtkCanvasViewport*
1103 Editor::get_track_canvas() const
1104 {
1105         return _track_canvas_viewport;
1106 }
1107
1108 Gdk::Cursor*
1109 Editor::get_canvas_cursor () const
1110 {
1111         /* The top of the cursor stack is always the currently visible cursor. */
1112         return _cursor_stack.back();
1113 }
1114
1115 void
1116 Editor::set_canvas_cursor (Gdk::Cursor* cursor)
1117 {
1118         Glib::RefPtr<Gdk::Window> win = _track_canvas->get_window();
1119
1120         if (win && !_cursors->is_invalid (cursor)) {
1121                 /* glibmm 2.4 doesn't allow null cursor pointer because it uses
1122                    a Gdk::Cursor& as the argument to Gdk::Window::set_cursor().
1123                    But a null pointer just means "use parent window cursor",
1124                    and so should be allowed. Gtkmm 3.x has fixed this API.
1125
1126                    For now, drop down and use C API
1127                 */
1128                 gdk_window_set_cursor (win->gobj(), cursor ? cursor->gobj() : 0);
1129         }
1130 }
1131
1132 size_t
1133 Editor::push_canvas_cursor (Gdk::Cursor* cursor)
1134 {
1135         if (!_cursors->is_invalid (cursor)) {
1136                 _cursor_stack.push_back (cursor);
1137                 set_canvas_cursor (cursor);
1138         }
1139         return _cursor_stack.size() - 1;
1140 }
1141
1142 void
1143 Editor::pop_canvas_cursor ()
1144 {
1145         while (true) {
1146                 if (_cursor_stack.size() <= 1) {
1147                         PBD::error << "attempt to pop default cursor" << endmsg;
1148                         return;
1149                 }
1150
1151                 _cursor_stack.pop_back();
1152                 if (_cursor_stack.back()) {
1153                         /* Popped to an existing cursor, we're done.  Otherwise, the
1154                            context that created this cursor has been destroyed, so we need
1155                            to skip to the next down the stack. */
1156                         set_canvas_cursor (_cursor_stack.back());
1157                         return;
1158                 }
1159         }
1160 }
1161
1162 Gdk::Cursor*
1163 Editor::which_trim_cursor (bool left) const
1164 {
1165         if (!entered_regionview) {
1166                 return 0;
1167         }
1168
1169         Trimmable::CanTrim ct = entered_regionview->region()->can_trim ();
1170
1171         if (left) {
1172
1173                 if (ct & Trimmable::FrontTrimEarlier) {
1174                         return _cursors->left_side_trim;
1175                 } else {
1176                         return _cursors->left_side_trim_right_only;
1177                 }
1178         } else {
1179                 if (ct & Trimmable::EndTrimLater) {
1180                         return _cursors->right_side_trim;
1181                 } else {
1182                         return _cursors->right_side_trim_left_only;
1183                 }
1184         }
1185 }
1186
1187 Gdk::Cursor*
1188 Editor::which_mode_cursor () const
1189 {
1190         Gdk::Cursor* mode_cursor = MouseCursors::invalid_cursor ();
1191
1192         switch (mouse_mode) {
1193         case MouseRange:
1194                 mode_cursor = _cursors->selector;
1195                 break;
1196
1197         case MouseCut:
1198                 mode_cursor = _cursors->scissors;
1199                 break;
1200
1201         case MouseObject:
1202         case MouseContent:
1203                 /* don't use mode cursor, pick a grabber cursor based on the item */
1204                 break;
1205
1206         case MouseDraw:
1207                 mode_cursor = _cursors->midi_pencil;
1208                 break;
1209
1210         case MouseTimeFX:
1211                 mode_cursor = _cursors->time_fx; // just use playhead
1212                 break;
1213
1214         case MouseAudition:
1215                 mode_cursor = _cursors->speaker;
1216                 break;
1217         }
1218
1219         /* up-down cursor as a cue that automation can be dragged up and down when in join object/range mode */
1220         if (get_smart_mode()) {
1221
1222                 double x, y;
1223                 get_pointer_position (x, y);
1224
1225                 if (x >= 0 && y >= 0) {
1226
1227                         vector<ArdourCanvas::Item const *> items;
1228
1229                         /* Note how we choose a specific scroll group to get
1230                          * items from. This could be problematic.
1231                          */
1232
1233                         hv_scroll_group->add_items_at_point (ArdourCanvas::Duple (x,y), items);
1234
1235                         // first item will be the upper most
1236
1237                         if (!items.empty()) {
1238                                 const ArdourCanvas::Item* i = items.front();
1239
1240                                 if (i && i->parent() && i->parent()->get_data (X_("timeselection"))) {
1241                                         pair<TimeAxisView*, int> tvp = trackview_by_y_position (_last_motion_y);
1242                                         if (dynamic_cast<AutomationTimeAxisView*> (tvp.first)) {
1243                                                 mode_cursor = _cursors->up_down;
1244                                         }
1245                                 }
1246                         }
1247                 }
1248         }
1249
1250         return mode_cursor;
1251 }
1252
1253 Gdk::Cursor*
1254 Editor::which_track_cursor () const
1255 {
1256         Gdk::Cursor* cursor = MouseCursors::invalid_cursor();
1257
1258         switch (_join_object_range_state) {
1259         case JOIN_OBJECT_RANGE_NONE:
1260         case JOIN_OBJECT_RANGE_OBJECT:
1261                 cursor = _cursors->grabber;
1262                 break;
1263         case JOIN_OBJECT_RANGE_RANGE:
1264                 cursor = _cursors->selector;
1265                 break;
1266         }
1267
1268         return cursor;
1269 }
1270
1271 Gdk::Cursor*
1272 Editor::which_canvas_cursor(ItemType type) const
1273 {
1274         Gdk::Cursor* cursor = which_mode_cursor ();
1275
1276         if (mouse_mode == MouseRange) {
1277                 switch (type) {
1278                 case StartSelectionTrimItem:
1279                         cursor = _cursors->left_side_trim;
1280                         break;
1281                 case EndSelectionTrimItem:
1282                         cursor = _cursors->right_side_trim;
1283                         break;
1284                 default:
1285                         break;
1286                 }
1287         }
1288
1289         if ((mouse_mode == MouseObject || get_smart_mode ()) ||
1290             mouse_mode == MouseContent) {
1291
1292                 /* find correct cursor to use in object/smart mode */
1293
1294                 switch (type) {
1295                 case RegionItem:
1296                 /* We don't choose a cursor for these items on top of a region view,
1297                    because this would push a new context on the enter stack which
1298                    means switching the region context for things like smart mode
1299                    won't actualy change the cursor. */
1300                 // case RegionViewNameHighlight:
1301                 // case RegionViewName:
1302                 // case WaveItem:
1303                 case StreamItem:
1304                 case AutomationTrackItem:
1305                         cursor = which_track_cursor ();
1306                         break;
1307                 case PlayheadCursorItem:
1308                         cursor = _cursors->grabber;
1309                         break;
1310                 case SelectionItem:
1311                         cursor = _cursors->selector;
1312                         break;
1313                 case ControlPointItem:
1314                         cursor = _cursors->fader;
1315                         break;
1316                 case GainLineItem:
1317                         cursor = _cursors->cross_hair;
1318                         break;
1319                 case AutomationLineItem:
1320                         cursor = _cursors->cross_hair;
1321                         break;
1322                 case StartSelectionTrimItem:
1323                         cursor = _cursors->left_side_trim;
1324                         break;
1325                 case EndSelectionTrimItem:
1326                         cursor = _cursors->right_side_trim;
1327                         break;
1328                 case FadeInItem:
1329                         cursor = _cursors->fade_in;
1330                         break;
1331                 case FadeInHandleItem:
1332                         cursor = _cursors->fade_in;
1333                         break;
1334                 case FadeInTrimHandleItem:
1335                         cursor = _cursors->fade_in;
1336                         break;
1337                 case FadeOutItem:
1338                         cursor = _cursors->fade_out;
1339                         break;
1340                 case FadeOutHandleItem:
1341                         cursor = _cursors->fade_out;
1342                         break;
1343                 case FadeOutTrimHandleItem:
1344                         cursor = _cursors->fade_out;
1345                         break;
1346                 case FeatureLineItem:
1347                         cursor = _cursors->cross_hair;
1348                         break;
1349                 case LeftFrameHandle:
1350                         if (effective_mouse_mode() == MouseObject) // (smart mode): if the user is in the btm half, show the trim cursor
1351                                 cursor = which_trim_cursor (true);
1352                         else
1353                                 cursor = _cursors->selector; // (smart mode): in the top half, just show the selection (range) cursor
1354                         break;
1355                 case RightFrameHandle:
1356                         if (effective_mouse_mode() == MouseObject) // see above
1357                                 cursor = which_trim_cursor (false);
1358                         else
1359                                 cursor = _cursors->selector;
1360                         break;
1361                 case StartCrossFadeItem:
1362                         cursor = _cursors->fade_in;
1363                         break;
1364                 case EndCrossFadeItem:
1365                         cursor = _cursors->fade_out;
1366                         break;
1367                 case CrossfadeViewItem:
1368                         cursor = _cursors->cross_hair;
1369                         break;
1370                 case NoteItem:
1371                         cursor = _cursors->grabber_note;
1372                 default:
1373                         break;
1374                 }
1375
1376         } else if (mouse_mode == MouseDraw) {
1377
1378                 /* ControlPointItem is not really specific to region gain mode
1379                    but it is the same cursor so don't worry about this for now.
1380                    The result is that we'll see the fader cursor if we enter
1381                    non-region-gain-line control points while in MouseDraw
1382                    mode, even though we can't edit them in this mode.
1383                 */
1384
1385                 switch (type) {
1386                 case GainLineItem:
1387                 case ControlPointItem:
1388                         cursor = _cursors->fader;
1389                         break;
1390                 case NoteItem:
1391                         cursor = _cursors->grabber_note;
1392                 default:
1393                         break;
1394                 }
1395         }
1396
1397         switch (type) {
1398                 /* These items use the timebar cursor at all times */
1399         case TimecodeRulerItem:
1400         case MinsecRulerItem:
1401         case BBTRulerItem:
1402         case SamplesRulerItem:
1403                 cursor = _cursors->timebar;
1404                 break;
1405
1406                 /* These items use the grabber cursor at all times */
1407         case MeterMarkerItem:
1408         case TempoMarkerItem:
1409         case MeterBarItem:
1410         case TempoBarItem:
1411         case MarkerItem:
1412         case MarkerBarItem:
1413         case RangeMarkerBarItem:
1414         case CdMarkerBarItem:
1415         case VideoBarItem:
1416         case TransportMarkerBarItem:
1417         case DropZoneItem:
1418                 cursor = _cursors->grabber;
1419                 break;
1420
1421         default:
1422                 break;
1423         }
1424
1425         return cursor;
1426 }
1427
1428 void
1429 Editor::choose_canvas_cursor_on_entry (ItemType type)
1430 {
1431         if (_drags->active()) {
1432                 return;
1433         }
1434
1435         Gdk::Cursor* cursor = which_canvas_cursor(type);
1436
1437         if (!_cursors->is_invalid (cursor)) {
1438                 // Push a new enter context
1439                 const EnterContext ctx = { type, CursorContext::create(*this, cursor) };
1440                 _enter_stack.push_back(ctx);
1441         }
1442 }
1443
1444 void
1445 Editor::update_all_enter_cursors ()
1446 {
1447         for (std::vector<EnterContext>::iterator i = _enter_stack.begin(); i != _enter_stack.end(); ++i) {
1448                 i->cursor_ctx->change(which_canvas_cursor(i->item_type));
1449         }
1450 }
1451
1452 double
1453 Editor::trackviews_height() const
1454 {
1455         if (!_trackview_group) {
1456                 return 0;
1457         }
1458
1459         return _visible_canvas_height - _trackview_group->canvas_origin().y;
1460 }