use CoreSelection for track selection
[ardour.git] / gtk2_ardour / editor_canvas_events.cc
1 /*
2     Copyright (C) 2000 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 #include <cstdlib>
21 #include <cmath>
22 #include <algorithm>
23 #include <typeinfo>
24
25 #include "pbd/stacktrace.h"
26
27 #include "ardour/audio_track.h"
28 #include "ardour/midi_track.h"
29 #include "ardour/midi_region.h"
30 #include "ardour/region_factory.h"
31 #include "ardour/profile.h"
32
33 #include "canvas/canvas.h"
34 #include "canvas/text.h"
35 #include "canvas/scroll_group.h"
36
37 #include "editor.h"
38 #include "keyboard.h"
39 #include "public_editor.h"
40 #include "audio_region_view.h"
41 #include "audio_streamview.h"
42 #include "audio_time_axis.h"
43 #include "region_gain_line.h"
44 #include "automation_line.h"
45 #include "automation_time_axis.h"
46 #include "automation_line.h"
47 #include "control_point.h"
48 #include "editor_drag.h"
49 #include "midi_time_axis.h"
50 #include "editor_regions.h"
51 #include "ui_config.h"
52 #include "verbose_cursor.h"
53
54 #include "pbd/i18n.h"
55
56 using namespace std;
57 using namespace ARDOUR;
58 using namespace PBD;
59 using namespace Gtk;
60 using namespace ArdourCanvas;
61
62 using Gtkmm2ext::Keyboard;
63
64 bool
65 Editor::track_canvas_scroll (GdkEventScroll* ev)
66 {
67         int direction = ev->direction;
68
69         /* this event arrives without transformation by the canvas, so we have
70          * to transform the coordinates to be able to look things up.
71          */
72
73         Duple event_coords = _track_canvas->window_to_canvas (Duple (ev->x, ev->y));
74
75         switch (direction) {
76         case GDK_SCROLL_UP:
77                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomHorizontalModifier)) {
78                         if (UIConfiguration::instance().get_use_mouse_position_as_zoom_focus_on_scroll()) {
79                                 temporal_zoom_step_mouse_focus (false);
80                         } else {
81                                 temporal_zoom_step (false);
82                         }
83                         return true;
84                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) {
85                         scroll_left_step ();
86                         return true;
87                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
88                         if (!current_stepping_trackview) {
89                                 step_timeout = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Editor::track_height_step_timeout), 500);
90                                 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (event_coords.y, false);
91                                 current_stepping_trackview = p.first;
92                                 if (!current_stepping_trackview) {
93                                         return false;
94                                 }
95                         }
96                         last_track_height_step_timestamp = get_microseconds();
97                         current_stepping_trackview->step_height (false);
98                         return true;
99                 } else {
100                         scroll_up_one_track ();
101                         return true;
102                 }
103                 break;
104
105         case GDK_SCROLL_DOWN:
106                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomHorizontalModifier)) {
107                         if (UIConfiguration::instance().get_use_mouse_position_as_zoom_focus_on_scroll()) {
108                                 temporal_zoom_step_mouse_focus (true);
109                         } else {
110                                 temporal_zoom_step (true);
111                         }
112                         return true;
113                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) {
114                         scroll_right_step ();
115                         return true;
116                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
117                         if (!current_stepping_trackview) {
118                                 step_timeout = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Editor::track_height_step_timeout), 500);
119                                 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (event_coords.y, false);
120                                 current_stepping_trackview = p.first;
121                                 if (!current_stepping_trackview) {
122                                         return false;
123                                 }
124                         }
125                         last_track_height_step_timestamp = get_microseconds();
126                         current_stepping_trackview->step_height (true);
127                         return true;
128                 } else {
129                         scroll_down_one_track ();
130                         return true;
131                 }
132                 break;
133
134         case GDK_SCROLL_LEFT:
135                 scroll_left_step ();
136                 return true;
137                 break;
138
139         case GDK_SCROLL_RIGHT:
140                 scroll_right_step ();
141                 return true;
142                 break;
143
144         default:
145                 /* what? */
146                 break;
147         }
148
149         return false;
150 }
151
152 bool
153 Editor::canvas_scroll_event (GdkEventScroll *event, bool from_canvas)
154 {
155         if (from_canvas) {
156                 boost::optional<ArdourCanvas::Rect> rulers = _time_markers_group->bounding_box();
157                 if (rulers && rulers->contains (Duple (event->x, event->y))) {
158                         return canvas_ruler_event ((GdkEvent*) event, timecode_ruler, TimecodeRulerItem);
159                 }
160         }
161
162         _track_canvas->grab_focus();
163         return track_canvas_scroll (event);
164 }
165
166 bool
167 Editor::track_canvas_button_press_event (GdkEventButton *event)
168 {
169         _track_canvas->grab_focus();
170         if (!Keyboard::is_context_menu_event (event)) {
171                 begin_reversible_selection_op (X_("Clear Selection Click (track canvas)"));
172                 selection->clear ();
173                 commit_reversible_selection_op();
174         }
175         return false;
176 }
177
178 bool
179 Editor::track_canvas_button_release_event (GdkEventButton *event)
180 {
181         if (!Keyboard::is_context_menu_event (event)) {
182                 if (_drags->active ()) {
183                         _drags->end_grab ((GdkEvent*) event);
184                 }
185         }
186         return false;
187 }
188
189 bool
190 Editor::track_canvas_motion_notify_event (GdkEventMotion */*event*/)
191 {
192         int x, y;
193         /* keep those motion events coming */
194         _track_canvas->get_pointer (x, y);
195         return false;
196 }
197
198 bool
199 Editor::typed_event (ArdourCanvas::Item* item, GdkEvent *event, ItemType type)
200 {
201         if (!session () || session()->loading () || session()->deletion_in_progress ()) {
202                 return false;
203         }
204
205         gint ret = FALSE;
206
207         switch (event->type) {
208         case GDK_BUTTON_PRESS:
209         case GDK_2BUTTON_PRESS:
210         case GDK_3BUTTON_PRESS:
211                 ret = button_press_handler (item, event, type);
212                 break;
213         case GDK_BUTTON_RELEASE:
214                 ret = button_release_handler (item, event, type);
215                 break;
216         case GDK_MOTION_NOTIFY:
217                 ret = motion_handler (item, event);
218                 break;
219
220         case GDK_ENTER_NOTIFY:
221                 ret = enter_handler (item, event, type);
222                 break;
223
224         case GDK_LEAVE_NOTIFY:
225                 ret = leave_handler (item, event, type);
226                 break;
227
228         case GDK_KEY_PRESS:
229                 ret = key_press_handler (item, event, type);
230                 break;
231
232         case GDK_KEY_RELEASE:
233                 ret = key_release_handler (item, event, type);
234                 break;
235
236         default:
237                 break;
238         }
239         return ret;
240 }
241
242 bool
243 Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView *rv)
244 {
245         bool ret = false;
246
247         if (!rv->sensitive ()) {
248                 return false;
249         }
250
251         switch (event->type) {
252         case GDK_BUTTON_PRESS:
253         case GDK_2BUTTON_PRESS:
254         case GDK_3BUTTON_PRESS:
255                 clicked_regionview = rv;
256                 clicked_control_point = 0;
257                 clicked_axisview = &rv->get_time_axis_view();
258                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
259                 ret = button_press_handler (item, event, RegionItem);
260                 break;
261
262         case GDK_BUTTON_RELEASE:
263                 ret = button_release_handler (item, event, RegionItem);
264                 break;
265
266         case GDK_MOTION_NOTIFY:
267                 ret = motion_handler (item, event);
268                 break;
269
270         case GDK_ENTER_NOTIFY:
271                 set_entered_regionview (rv);
272                 ret = enter_handler (item, event, RegionItem);
273                 break;
274
275         case GDK_LEAVE_NOTIFY:
276                 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) {
277                         set_entered_regionview (0);
278                         ret = leave_handler (item, event, RegionItem);
279                 }
280                 break;
281
282         default:
283                 break;
284         }
285
286         return ret;
287 }
288
289 bool
290 Editor::canvas_wave_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
291 {
292         /* we only care about enter events here, required for mouse/cursor
293          * tracking. there is a non-linear (non-child/non-parent) relationship
294          * between various components of a regionview and so when we leave one
295          * of them (e.g. a trim handle) and enter another (e.g. the waveview)
296          * no other items get notified. enter/leave handling does not propagate
297          * in the same way as other events, so we need to catch this because
298          * entering (and leaving) the waveview is equivalent to
299          * entering/leaving the regionview (which is why it is passed in as a
300          * third argument).
301          *
302          * And in fact, we really only care about enter events.
303          */
304
305         bool ret = false;
306
307         if (!rv->sensitive ()) {
308                 return false;
309         }
310
311         switch (event->type) {
312         case GDK_ENTER_NOTIFY:
313                 set_entered_regionview (rv);
314                 ret = enter_handler (item, event, WaveItem);
315                 break;
316
317         default:
318                 break;
319         }
320
321         return ret;
322 }
323
324
325 bool
326 Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, RouteTimeAxisView *tv)
327 {
328         bool ret = FALSE;
329
330         switch (event->type) {
331         case GDK_BUTTON_PRESS:
332         case GDK_2BUTTON_PRESS:
333         case GDK_3BUTTON_PRESS:
334                 clicked_regionview = 0;
335                 clicked_control_point = 0;
336                 clicked_axisview = tv;
337                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
338                 ret = button_press_handler (item, event, StreamItem);
339                 break;
340
341         case GDK_BUTTON_RELEASE:
342                 ret = button_release_handler (item, event, StreamItem);
343                 break;
344
345         case GDK_MOTION_NOTIFY:
346                 ret = motion_handler (item, event);
347                 break;
348
349         case GDK_ENTER_NOTIFY:
350                 set_entered_track (tv);
351                 ret = enter_handler (item, event, StreamItem);
352                 break;
353
354         case GDK_LEAVE_NOTIFY:
355                 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) {
356                         set_entered_track (0);
357                 }
358                 ret = leave_handler (item, event, StreamItem);
359                 break;
360
361         default:
362                 break;
363         }
364
365         return ret;
366 }
367
368 bool
369 Editor::canvas_automation_track_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationTimeAxisView *atv)
370 {
371         bool ret = false;
372
373         switch (event->type) {
374         case GDK_BUTTON_PRESS:
375         case GDK_2BUTTON_PRESS:
376         case GDK_3BUTTON_PRESS:
377                 clicked_regionview = 0;
378                 clicked_control_point = 0;
379                 clicked_axisview = atv;
380                 clicked_routeview = 0;
381                 ret = button_press_handler (item, event, AutomationTrackItem);
382                 break;
383
384         case GDK_BUTTON_RELEASE:
385                 ret = button_release_handler (item, event, AutomationTrackItem);
386                 break;
387
388         case GDK_MOTION_NOTIFY:
389                 ret = motion_handler (item, event);
390                 break;
391
392         case GDK_ENTER_NOTIFY:
393                 ret = enter_handler (item, event, AutomationTrackItem);
394                 break;
395
396         case GDK_LEAVE_NOTIFY:
397                 ret = leave_handler (item, event, AutomationTrackItem);
398                 break;
399
400         default:
401                 break;
402         }
403
404         return ret;
405 }
406
407 bool
408 Editor::canvas_start_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
409 {
410         if (!rv->sensitive()) {
411                 return false;
412         }
413
414         switch (event->type) {
415         case GDK_BUTTON_PRESS:
416                 clicked_regionview = rv;
417                 clicked_control_point = 0;
418                 clicked_axisview = &rv->get_time_axis_view();
419                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
420                 if (event->button.button == 3) {
421                         return button_press_handler (item, event, StartCrossFadeItem);
422                 }
423                 break;
424
425         case GDK_BUTTON_RELEASE:
426                 if (event->button.button == 3) {
427                         return button_release_handler (item, event, StartCrossFadeItem);
428                 }
429                 break;
430
431         default:
432                 break;
433
434         }
435
436         /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
437         /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
438         /* if we return RegionItem here then we avoid the issue until it is resolved later */
439         return typed_event (item, event, RegionItem); // StartCrossFadeItem);
440 }
441
442 bool
443 Editor::canvas_end_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
444 {
445         if (!rv->sensitive()) {
446                 return false;
447         }
448
449         switch (event->type) {
450         case GDK_BUTTON_PRESS:
451                 clicked_regionview = rv;
452                 clicked_control_point = 0;
453                 clicked_axisview = &rv->get_time_axis_view();
454                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
455                 if (event->button.button == 3) {
456                         return button_press_handler (item, event, EndCrossFadeItem);
457                 }
458                 break;
459
460         case GDK_BUTTON_RELEASE:
461                 if (event->button.button == 3) {
462                         return button_release_handler (item, event, EndCrossFadeItem);
463                 }
464                 break;
465
466         default:
467                 break;
468
469         }
470
471         /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
472         /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
473         /* if we return RegionItem here then we avoid the issue until it is resolved later */
474         return typed_event (item, event, RegionItem); // EndCrossFadeItem);
475 }
476
477 bool
478 Editor::canvas_fade_in_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
479 {
480         /* we handle only button 3 press/release events */
481
482         if (!rv->sensitive()) {
483                 return false;
484         }
485
486         switch (event->type) {
487         case GDK_BUTTON_PRESS:
488                 clicked_regionview = rv;
489                 clicked_control_point = 0;
490                 clicked_axisview = &rv->get_time_axis_view();
491                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
492                 if (event->button.button == 3) {
493                         return button_press_handler (item, event, FadeInItem);
494                 }
495                 break;
496
497         case GDK_BUTTON_RELEASE:
498                 if (event->button.button == 3) {
499                         return button_release_handler (item, event, FadeInItem);
500                 }
501                 break;
502
503         default:
504                 break;
505
506         }
507
508         /* proxy for the regionview, except enter/leave events */
509
510         if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
511                 return true;
512         } else {
513                 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
514         }
515 }
516
517 bool
518 Editor::canvas_fade_in_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv, bool trim)
519 {
520         bool ret = false;
521
522         if (!rv->sensitive()) {
523                 return false;
524         }
525
526         switch (event->type) {
527         case GDK_BUTTON_PRESS:
528         case GDK_2BUTTON_PRESS:
529         case GDK_3BUTTON_PRESS:
530                 clicked_regionview = rv;
531                 clicked_control_point = 0;
532                 clicked_axisview = &rv->get_time_axis_view();
533                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
534                 ret = button_press_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
535                 break;
536
537         case GDK_BUTTON_RELEASE:
538                 ret = button_release_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
539                 break;
540
541         case GDK_MOTION_NOTIFY:
542                 ret = motion_handler (item, event);
543                 break;
544
545         case GDK_ENTER_NOTIFY:
546                 ret = enter_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
547                 break;
548
549         case GDK_LEAVE_NOTIFY:
550                 ret = leave_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
551                 break;
552
553         default:
554                 break;
555         }
556
557         return ret;
558 }
559
560 bool
561 Editor::canvas_fade_out_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
562 {
563         /* we handle only button 3 press/release events */
564
565         if (!rv->sensitive()) {
566                 return false;
567         }
568
569         switch (event->type) {
570         case GDK_BUTTON_PRESS:
571                 clicked_regionview = rv;
572                 clicked_control_point = 0;
573                 clicked_axisview = &rv->get_time_axis_view();
574                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
575                 if (event->button.button == 3) {
576                         return button_press_handler (item, event, FadeOutItem);
577                 }
578                 break;
579
580         case GDK_BUTTON_RELEASE:
581                 if (event->button.button == 3) {
582                         return button_release_handler (item, event, FadeOutItem);
583                 }
584                 break;
585
586         default:
587                 break;
588
589         }
590
591         /* proxy for the regionview, except enter/leave events */
592
593         if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
594                 return true;
595         } else {
596                 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
597         }
598 }
599
600 bool
601 Editor::canvas_fade_out_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv, bool trim)
602 {
603         bool ret = false;
604
605         if (!rv->sensitive()) {
606                 return false;
607         }
608
609         switch (event->type) {
610         case GDK_BUTTON_PRESS:
611         case GDK_2BUTTON_PRESS:
612         case GDK_3BUTTON_PRESS:
613                 clicked_regionview = rv;
614                 clicked_control_point = 0;
615                 clicked_axisview = &rv->get_time_axis_view();
616                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
617                 ret = button_press_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
618                 break;
619
620         case GDK_BUTTON_RELEASE:
621                 ret = button_release_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
622                 break;
623
624         case GDK_MOTION_NOTIFY:
625                 ret = motion_handler (item, event);
626                 break;
627
628         case GDK_ENTER_NOTIFY:
629                 ret = enter_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
630                 break;
631
632         case GDK_LEAVE_NOTIFY:
633                 ret = leave_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
634                 break;
635
636         default:
637                 break;
638         }
639
640         return ret;
641 }
642
643 struct DescendingRegionLayerSorter {
644     bool operator()(boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
645             return a->layer() > b->layer();
646     }
647 };
648
649 bool
650 Editor::canvas_control_point_event (GdkEvent *event, ArdourCanvas::Item* item, ControlPoint* cp)
651 {
652         switch (event->type) {
653         case GDK_BUTTON_PRESS:
654         case GDK_2BUTTON_PRESS:
655         case GDK_3BUTTON_PRESS:
656                 clicked_control_point = cp;
657                 clicked_axisview = &cp->line().trackview;
658                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
659                 clicked_regionview = 0;
660                 break;
661
662         case GDK_SCROLL_UP:
663                 break;
664
665         case GDK_SCROLL_DOWN:
666                 break;
667
668         default:
669                 break;
670         }
671
672         return typed_event (item, event, ControlPointItem);
673 }
674
675 bool
676 Editor::canvas_line_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationLine* al)
677 {
678         ItemType type;
679         AudioRegionGainLine* gl;
680         if ((gl = dynamic_cast<AudioRegionGainLine*> (al)) != 0) {
681                 type = GainLineItem;
682                 if (event->type == GDK_BUTTON_PRESS) {
683                         clicked_regionview = &gl->region_view ();
684                 }
685         } else {
686                 type = AutomationLineItem;
687                 if (event->type == GDK_BUTTON_PRESS) {
688                         clicked_regionview = 0;
689                 }
690         }
691
692         clicked_control_point = 0;
693         clicked_axisview = &al->trackview;
694         clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
695
696         return typed_event (item, event, type);
697 }
698
699 bool
700 Editor::canvas_selection_rect_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
701 {
702         bool ret = false;
703
704         switch (event->type) {
705         case GDK_BUTTON_PRESS:
706         case GDK_2BUTTON_PRESS:
707         case GDK_3BUTTON_PRESS:
708                 clicked_selection = rect->id;
709                 ret = button_press_handler (item, event, SelectionItem);
710                 break;
711         case GDK_BUTTON_RELEASE:
712                 ret = button_release_handler (item, event, SelectionItem);
713                 break;
714         case GDK_MOTION_NOTIFY:
715                 ret = motion_handler (item, event);
716                 break;
717                 /* Don't need these at the moment. */
718         case GDK_ENTER_NOTIFY:
719                 ret = enter_handler (item, event, SelectionItem);
720                 break;
721
722         case GDK_LEAVE_NOTIFY:
723                 ret = leave_handler (item, event, SelectionItem);
724                 break;
725
726         default:
727                 break;
728         }
729
730         return ret;
731 }
732
733 bool
734 Editor::canvas_selection_start_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
735 {
736         bool ret = false;
737
738         switch (event->type) {
739         case GDK_BUTTON_PRESS:
740         case GDK_2BUTTON_PRESS:
741         case GDK_3BUTTON_PRESS:
742                 clicked_selection = rect->id;
743                 ret = button_press_handler (item, event, StartSelectionTrimItem);
744                 break;
745         case GDK_BUTTON_RELEASE:
746                 ret = button_release_handler (item, event, StartSelectionTrimItem);
747                 break;
748         case GDK_MOTION_NOTIFY:
749                 ret = motion_handler (item, event);
750                 break;
751         case GDK_ENTER_NOTIFY:
752                 ret = enter_handler (item, event, StartSelectionTrimItem);
753                 break;
754
755         case GDK_LEAVE_NOTIFY:
756                 ret = leave_handler (item, event, StartSelectionTrimItem);
757                 break;
758
759         default:
760                 break;
761         }
762
763         return ret;
764 }
765
766 bool
767 Editor::canvas_selection_end_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
768 {
769         bool ret = false;
770
771         switch (event->type) {
772         case GDK_BUTTON_PRESS:
773         case GDK_2BUTTON_PRESS:
774         case GDK_3BUTTON_PRESS:
775                 clicked_selection = rect->id;
776                 ret = button_press_handler (item, event, EndSelectionTrimItem);
777                 break;
778         case GDK_BUTTON_RELEASE:
779                 ret = button_release_handler (item, event, EndSelectionTrimItem);
780                 break;
781         case GDK_MOTION_NOTIFY:
782                 ret = motion_handler (item, event);
783                 break;
784         case GDK_ENTER_NOTIFY:
785                 ret = enter_handler (item, event, EndSelectionTrimItem);
786                 break;
787
788         case GDK_LEAVE_NOTIFY:
789                 ret = leave_handler (item, event, EndSelectionTrimItem);
790                 break;
791
792         default:
793                 break;
794         }
795
796         return ret;
797 }
798
799 bool
800 Editor::canvas_frame_handle_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
801 {
802         bool ret = false;
803
804         /* frame handles are not active when in internal edit mode, because actual notes
805            might be in the area occupied by the handle - we want them to be editable as normal.
806         */
807
808         if (internal_editing() || !rv->sensitive()) {
809                 return false;
810         }
811
812         /* NOTE: frame handles pretend to be the colored trim bar from an event handling
813            perspective. XXX change this ??
814         */
815
816         ItemType type;
817
818         if (item->get_data ("isleft")) {
819                 type = LeftFrameHandle;
820         } else {
821                 type = RightFrameHandle;
822         }
823
824         switch (event->type) {
825         case GDK_BUTTON_PRESS:
826         case GDK_2BUTTON_PRESS:
827         case GDK_3BUTTON_PRESS:
828                 clicked_regionview = rv;
829                 clicked_control_point = 0;
830                 clicked_axisview = &clicked_regionview->get_time_axis_view();
831                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
832                 ret = button_press_handler (item, event, type);
833                 break;
834         case GDK_BUTTON_RELEASE:
835                 ret = button_release_handler (item, event, type);
836                 break;
837         case GDK_MOTION_NOTIFY:
838                 ret = motion_handler (item, event);
839                 break;
840         case GDK_ENTER_NOTIFY:
841                 ret = enter_handler (item, event, type);
842                 break;
843
844         case GDK_LEAVE_NOTIFY:
845                 ret = leave_handler (item, event, type);
846                 break;
847
848         default:
849                 break;
850         }
851
852         return ret;
853 }
854
855
856 bool
857 Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
858 {
859         bool ret = false;
860
861         if (!rv->sensitive()) {
862                 return false;
863         }
864
865         switch (event->type) {
866         case GDK_BUTTON_PRESS:
867         case GDK_2BUTTON_PRESS:
868         case GDK_3BUTTON_PRESS:
869                 clicked_regionview = rv;
870                 clicked_control_point = 0;
871                 clicked_axisview = &clicked_regionview->get_time_axis_view();
872                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
873                 ret = button_press_handler (item, event, RegionViewNameHighlight);
874                 break;
875         case GDK_BUTTON_RELEASE:
876                 ret = button_release_handler (item, event, RegionViewNameHighlight);
877                 break;
878         case GDK_MOTION_NOTIFY:
879                 motion_handler (item, event);
880                 ret = true; // force this to avoid progagating the event into the regionview
881                 break;
882         case GDK_ENTER_NOTIFY:
883                 ret = enter_handler (item, event, RegionViewNameHighlight);
884                 break;
885
886         case GDK_LEAVE_NOTIFY:
887                 ret = leave_handler (item, event, RegionViewNameHighlight);
888                 break;
889
890         default:
891                 break;
892         }
893
894         return ret;
895 }
896
897 bool
898 Editor::canvas_region_view_name_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
899 {
900         bool ret = false;
901
902         if (!rv->sensitive()) {
903                 return false;
904         }
905
906         switch (event->type) {
907         case GDK_BUTTON_PRESS:
908         case GDK_2BUTTON_PRESS:
909         case GDK_3BUTTON_PRESS:
910                 clicked_regionview = rv;
911                 clicked_control_point = 0;
912                 clicked_axisview = &clicked_regionview->get_time_axis_view();
913                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
914                 ret = button_press_handler (item, event, RegionViewName);
915                 break;
916         case GDK_BUTTON_RELEASE:
917                 ret = button_release_handler (item, event, RegionViewName);
918                 break;
919         case GDK_MOTION_NOTIFY:
920                 ret = motion_handler (item, event);
921                 break;
922         case GDK_ENTER_NOTIFY:
923                 ret = enter_handler (item, event, RegionViewName);
924                 break;
925
926         case GDK_LEAVE_NOTIFY:
927                 ret = leave_handler (item, event, RegionViewName);
928                 break;
929
930         default:
931                 break;
932         }
933
934         return ret;
935 }
936
937 bool
938 Editor::canvas_feature_line_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView*)
939 {
940         bool ret = false;
941
942         switch (event->type) {
943         case GDK_BUTTON_PRESS:
944         case GDK_2BUTTON_PRESS:
945         case GDK_3BUTTON_PRESS:
946                 clicked_regionview = 0;
947                 clicked_control_point = 0;
948                 clicked_axisview = 0;
949                 clicked_routeview = 0; //dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
950                 ret = button_press_handler (item, event, FeatureLineItem);
951                 break;
952
953         case GDK_BUTTON_RELEASE:
954                 ret = button_release_handler (item, event, FeatureLineItem);
955                 break;
956
957         case GDK_MOTION_NOTIFY:
958                 ret = motion_handler (item, event);
959                 break;
960
961         case GDK_ENTER_NOTIFY:
962                 ret = enter_handler (item, event, FeatureLineItem);
963                 break;
964
965         case GDK_LEAVE_NOTIFY:
966                 ret = leave_handler (item, event, FeatureLineItem);
967                 break;
968
969         default:
970                 break;
971         }
972
973         return ret;
974 }
975
976 bool
977 Editor::canvas_marker_event (GdkEvent *event, ArdourCanvas::Item* item, ArdourMarker* /*marker*/)
978 {
979         return typed_event (item, event, MarkerItem);
980 }
981
982 bool
983 Editor::canvas_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
984 {
985         return typed_event (item, event, MarkerBarItem);
986 }
987
988 bool
989 Editor::canvas_range_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
990 {
991         return typed_event (item, event, RangeMarkerBarItem);
992 }
993
994 bool
995 Editor::canvas_transport_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
996 {
997         return typed_event (item, event, TransportMarkerBarItem);
998 }
999
1000 bool
1001 Editor::canvas_cd_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1002 {
1003         return typed_event (item, event, CdMarkerBarItem);
1004 }
1005
1006 bool
1007 Editor::canvas_videotl_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1008 {
1009         return typed_event (item, event, VideoBarItem);
1010 }
1011
1012 bool
1013 Editor::canvas_tempo_marker_event (GdkEvent *event, ArdourCanvas::Item* item, TempoMarker* marker)
1014 {
1015         return typed_event (item, event, TempoMarkerItem);
1016 }
1017
1018 bool
1019 Editor::canvas_tempo_curve_event (GdkEvent *event, ArdourCanvas::Item* item, TempoCurve* /*marker*/)
1020 {
1021         return typed_event (item, event, TempoCurveItem);
1022 }
1023
1024 bool
1025 Editor::canvas_meter_marker_event (GdkEvent *event, ArdourCanvas::Item* item, MeterMarker* /*marker*/)
1026 {
1027         return typed_event (item, event, MeterMarkerItem);
1028 }
1029
1030 bool
1031 Editor::canvas_ruler_event (GdkEvent *event, ArdourCanvas::Item* item, ItemType type)
1032 {
1033         bool handled = false;
1034
1035         if (event->type == GDK_SCROLL) {
1036
1037                 /* scroll events in the rulers are handled a little differently from
1038                    scrolling elsewhere in the canvas.
1039                 */
1040
1041                 switch (event->scroll.direction) {
1042                 case GDK_SCROLL_UP:
1043                         if (Keyboard::modifier_state_equals(event->scroll.state,
1044                                                             Keyboard::ScrollHorizontalModifier)) {
1045                                 scroll_left_step ();
1046                         } else if (UIConfiguration::instance().get_use_mouse_position_as_zoom_focus_on_scroll()) {
1047                                 temporal_zoom_step_mouse_focus (false);
1048                         } else {
1049                                 temporal_zoom_step (false);
1050                         }
1051                         handled = true;
1052                         break;
1053
1054                 case GDK_SCROLL_DOWN:
1055                         if (Keyboard::modifier_state_equals(event->scroll.state,
1056                                                             Keyboard::ScrollHorizontalModifier)) {
1057                                 scroll_right_step ();
1058                         } else if (UIConfiguration::instance().get_use_mouse_position_as_zoom_focus_on_scroll()) {
1059                                 temporal_zoom_step_mouse_focus (true);
1060                         } else {
1061                                 temporal_zoom_step (true);
1062                         }
1063                         handled = true;
1064                         break;
1065
1066                 case GDK_SCROLL_LEFT:
1067                         scroll_left_half_page ();
1068                         handled = true;
1069                         break;
1070
1071                 case GDK_SCROLL_RIGHT:
1072                         scroll_right_half_page ();
1073                         handled = true;
1074                         break;
1075
1076                 default:
1077                         /* what? */
1078                         break;
1079                 }
1080                 return handled;
1081         }
1082
1083         switch (event->type) {
1084         case GDK_BUTTON_PRESS:
1085                 if (UIConfiguration::instance ().get_use_time_rulers_to_zoom_with_vertical_drag () &&
1086                     Keyboard::no_modifier_keys_pressed (&event->button) && event->button.button == 1) {
1087                         _drags->set(new RulerZoomDrag(this, item), event);
1088                         return true;
1089                 }
1090                 break;
1091         default:
1092                 break;
1093         }
1094
1095         return typed_event (item, event, type);
1096 }
1097
1098 bool
1099 Editor::canvas_tempo_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1100 {
1101         return typed_event (item, event, TempoBarItem);
1102 }
1103
1104 bool
1105 Editor::canvas_meter_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1106 {
1107         return typed_event (item, event, MeterBarItem);
1108 }
1109
1110 bool
1111 Editor::canvas_playhead_cursor_event (GdkEvent *event, ArdourCanvas::Item* item)
1112 {
1113         return typed_event (item, event, PlayheadCursorItem);
1114 }
1115
1116 bool
1117 Editor::canvas_note_event (GdkEvent *event, ArdourCanvas::Item* item)
1118 {
1119         if (!internal_editing()) {
1120                 return false;
1121         }
1122
1123         return typed_event (item, event, NoteItem);
1124 }
1125
1126 bool
1127 Editor::canvas_drop_zone_event (GdkEvent* event)
1128 {
1129         GdkEventScroll scroll;
1130         ArdourCanvas::Duple winpos;
1131
1132         switch (event->type) {
1133         case GDK_BUTTON_RELEASE:
1134                 if (event->button.button == 1) {
1135                         begin_reversible_selection_op (X_("Nowhere Click"));
1136                         selection->clear_objects ();
1137                         selection->clear_tracks ();
1138                         commit_reversible_selection_op ();
1139                 }
1140                 break;
1141
1142         case GDK_SCROLL:
1143                 /* convert coordinates back into window space so that
1144                    we can just call canvas_scroll_event().
1145                 */
1146                 winpos = _track_canvas->canvas_to_window (Duple (event->scroll.x, event->scroll.y));
1147                 scroll = event->scroll;
1148                 scroll.x = winpos.x;
1149                 scroll.y = winpos.y;
1150                 return canvas_scroll_event (&scroll, true);
1151                 break;
1152
1153         case GDK_ENTER_NOTIFY:
1154                 return typed_event (_canvas_drop_zone, event, DropZoneItem);
1155
1156         case GDK_LEAVE_NOTIFY:
1157                 return typed_event (_canvas_drop_zone, event, DropZoneItem);
1158
1159         default:
1160                 break;
1161         }
1162
1163         return true;
1164 }
1165
1166 bool
1167 Editor::track_canvas_drag_motion (Glib::RefPtr<Gdk::DragContext> const& context, int x, int y, guint time)
1168 {
1169         boost::shared_ptr<Region> region;
1170         boost::shared_ptr<Region> region_copy;
1171         RouteTimeAxisView* rtav;
1172         GdkEvent event;
1173         double px;
1174         double py;
1175
1176         string target = _track_canvas->drag_dest_find_target (context, _track_canvas->drag_dest_get_target_list());
1177
1178         if (target.empty()) {
1179                 return false;
1180         }
1181
1182         event.type = GDK_MOTION_NOTIFY;
1183         event.button.x = x;
1184         event.button.y = y;
1185         /* assume we're dragging with button 1 */
1186         event.motion.state = Gdk::BUTTON1_MASK;
1187
1188         (void) window_event_sample (&event, &px, &py);
1189
1190         std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py, false);
1191         bool can_drop = false;
1192
1193         if (tv.first != 0) {
1194
1195                 /* over a time axis view of some kind */
1196
1197                 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1198
1199                 if (rtav != 0 && rtav->is_track ()) {
1200                         /* over a track, not a bus */
1201                         can_drop = true;
1202                 }
1203
1204
1205         } else {
1206                 /* not over a time axis view, so drop is possible */
1207                 can_drop = true;
1208         }
1209
1210         if (can_drop) {
1211                 region = _regions->get_dragged_region ();
1212
1213                 if (region) {
1214
1215                         if (tv.first == 0
1216                             && (
1217                                 boost::dynamic_pointer_cast<AudioRegion> (region) != 0 ||
1218                                 boost::dynamic_pointer_cast<MidiRegion> (region) != 0
1219                                )
1220                            )
1221                         {
1222                                 /* drop to drop-zone */
1223                                 context->drag_status (context->get_suggested_action(), time);
1224                                 return true;
1225                         }
1226
1227                         if ((boost::dynamic_pointer_cast<AudioRegion> (region) != 0 &&
1228                              dynamic_cast<AudioTimeAxisView*> (tv.first) != 0) ||
1229                             (boost::dynamic_pointer_cast<MidiRegion> (region) != 0 &&
1230                              dynamic_cast<MidiTimeAxisView*> (tv.first) != 0)) {
1231
1232                                 /* audio to audio
1233                                    OR
1234                                    midi to midi
1235                                 */
1236
1237                                 context->drag_status (context->get_suggested_action(), time);
1238                                 return true;
1239                         }
1240                 } else {
1241                         /* DND originating from outside ardour
1242                          *
1243                          * TODO: check if file is audio/midi, allow drops on same track-type only,
1244                          * currently: if audio is dropped on a midi-track, it is only added to the region-list
1245                          */
1246                         if (UIConfiguration::instance().get_only_copy_imported_files()) {
1247                                 context->drag_status(Gdk::ACTION_COPY, time);
1248                         } else {
1249                                 if ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY) {
1250                                         context->drag_status(Gdk::ACTION_COPY, time);
1251                                 } else {
1252                                         context->drag_status(Gdk::ACTION_LINK, time);
1253                                 }
1254                         }
1255                         return true;
1256                 }
1257         }
1258
1259         /* no drop here */
1260         context->drag_status (Gdk::DragAction (0), time);
1261         return false;
1262 }
1263
1264 void
1265 Editor::drop_regions (const Glib::RefPtr<Gdk::DragContext>& /*context*/,
1266                       int x, int y,
1267                       const SelectionData& /*data*/,
1268                       guint /*info*/, guint /*time*/)
1269 {
1270         GdkEvent event;
1271         double px;
1272         double py;
1273
1274         event.type = GDK_MOTION_NOTIFY;
1275         event.button.x = x;
1276         event.button.y = y;
1277         /* assume we're dragging with button 1 */
1278         event.motion.state = Gdk::BUTTON1_MASK;
1279         framepos_t const pos = window_event_sample (&event, &px, &py);
1280
1281         boost::shared_ptr<Region> region = _regions->get_dragged_region ();
1282         if (!region) { return; }
1283
1284         RouteTimeAxisView* rtav = 0;
1285         std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py, false);
1286
1287         if (tv.first != 0) {
1288                 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1289         } else {
1290                 try {
1291                         if (boost::dynamic_pointer_cast<AudioRegion> (region)) {
1292                                 uint32_t output_chan = region->n_channels();
1293                                 if ((Config->get_output_auto_connect() & AutoConnectMaster) && session()->master_out()) {
1294                                         output_chan =  session()->master_out()->n_inputs().n_audio();
1295                                 }
1296                                 list<boost::shared_ptr<AudioTrack> > audio_tracks;
1297                                 audio_tracks = session()->new_audio_track (region->n_channels(), output_chan, 0, 1, region->name(), PresentationInfo::max_order);
1298                                 rtav = dynamic_cast<RouteTimeAxisView*> (time_axis_view_from_stripable (audio_tracks.front()));
1299                         } else if (boost::dynamic_pointer_cast<MidiRegion> (region)) {
1300                                 ChanCount one_midi_port (DataType::MIDI, 1);
1301                                 list<boost::shared_ptr<MidiTrack> > midi_tracks;
1302                                 midi_tracks = session()->new_midi_track (one_midi_port, one_midi_port,
1303                                                                          Config->get_strict_io () || Profile->get_mixbus (),
1304                                                                          boost::shared_ptr<ARDOUR::PluginInfo>(),
1305                                                                          (ARDOUR::Plugin::PresetRecord*) 0,
1306                                                                          (ARDOUR::RouteGroup*) 0, 1, region->name(), PresentationInfo::max_order);
1307                                 rtav = dynamic_cast<RouteTimeAxisView*> (time_axis_view_from_stripable (midi_tracks.front()));
1308                         } else {
1309                                 return;
1310                         }
1311                 } catch (...) {
1312                         error << _("Could not create new track after region placed in the drop zone") << endmsg;
1313                         return;
1314                 }
1315         }
1316
1317         if (rtav != 0 && rtav->is_track ()) {
1318                 boost::shared_ptr<Region> region_copy = RegionFactory::create (region, true);
1319
1320                 if ((boost::dynamic_pointer_cast<AudioRegion> (region_copy) != 0 && dynamic_cast<AudioTimeAxisView*> (rtav) != 0) ||
1321                     (boost::dynamic_pointer_cast<MidiRegion> (region_copy) != 0 && dynamic_cast<MidiTimeAxisView*> (rtav) != 0)) {
1322                         _drags->set (new RegionInsertDrag (this, region_copy, rtav, pos), &event);
1323                         _drags->end_grab (&event);
1324                 }
1325         }
1326 }
1327
1328 bool
1329 Editor::key_press_handler (ArdourCanvas::Item*, GdkEvent*, ItemType)
1330 {
1331         return false;
1332 }
1333
1334 bool
1335 Editor::key_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType type)
1336 {
1337
1338         bool handled = false;
1339
1340         switch (type) {
1341         case TempoMarkerItem:
1342                 switch (event->key.keyval) {
1343                 case GDK_Delete:
1344                         remove_tempo_marker (item);
1345                         handled = true;
1346                         break;
1347                 default:
1348                         break;
1349                 }
1350                 break;
1351
1352         case MeterMarkerItem:
1353                 switch (event->key.keyval) {
1354                 case GDK_Delete:
1355                         remove_meter_marker (item);
1356                         handled = true;
1357                         break;
1358                 default:
1359                         break;
1360                 }
1361                 break;
1362
1363         default:
1364                 break;
1365         }
1366
1367         return handled;
1368 }
1369