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