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