Fix zooming via ctrl+scroll in midi regions when note is selected.
[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 "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         framepos_t xdelta;
68         int direction = ev->direction;
69
70         /* this event arrives without transformation by the canvas, so we have
71          * to transform the coordinates to be able to look things up.
72          */
73
74         Duple event_coords = _track_canvas->window_to_canvas (Duple (ev->x, ev->y));
75
76   retry:
77         switch (direction) {
78         case GDK_SCROLL_UP:
79                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomHorizontalModifier)) {
80                         //for mouse-wheel zoom, force zoom-focus to mouse
81                         Editing::ZoomFocus temp_focus = zoom_focus;
82                         zoom_focus = Editing::ZoomFocusMouse;
83                         temporal_zoom_step (false);
84                         zoom_focus = temp_focus;
85                         return true;
86                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) {
87                         direction = GDK_SCROLL_LEFT;
88                         goto retry;
89                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
90                         if (!current_stepping_trackview) {
91                                 step_timeout = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Editor::track_height_step_timeout), 500);
92                                 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (event_coords.y, false);
93                                 current_stepping_trackview = p.first;
94                                 if (!current_stepping_trackview) {
95                                         return false;
96                                 }
97                         }
98                         last_track_height_step_timestamp = get_microseconds();
99                         current_stepping_trackview->step_height (false);
100                         return true;
101                 } else {
102                         scroll_up_one_track ();
103                         return true;
104                 }
105                 break;
106
107         case GDK_SCROLL_DOWN:
108                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomHorizontalModifier)) {
109                         //for mouse-wheel zoom, force zoom-focus to mouse
110                         Editing::ZoomFocus temp_focus = zoom_focus;
111                         zoom_focus = Editing::ZoomFocusMouse;
112                         temporal_zoom_step (true);
113                         zoom_focus = temp_focus;
114                         return true;
115                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) {
116                         direction = GDK_SCROLL_RIGHT;
117                         goto retry;
118                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
119                         if (!current_stepping_trackview) {
120                                 step_timeout = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Editor::track_height_step_timeout), 500);
121                                 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (event_coords.y, false);
122                                 current_stepping_trackview = p.first;
123                                 if (!current_stepping_trackview) {
124                                         return false;
125                                 }
126                         }
127                         last_track_height_step_timestamp = get_microseconds();
128                         current_stepping_trackview->step_height (true);
129                         return true;
130                 } else {
131                         scroll_down_one_track ();
132                         return true;
133                 }
134                 break;
135
136         case GDK_SCROLL_LEFT:
137                 xdelta = (current_page_samples() / 8);
138                 if (leftmost_frame > xdelta) {
139                         reset_x_origin (leftmost_frame - xdelta);
140                 } else {
141                         reset_x_origin (0);
142                 }
143                 break;
144
145         case GDK_SCROLL_RIGHT:
146                 xdelta = (current_page_samples() / 8);
147                 if (max_framepos - xdelta > leftmost_frame) {
148                         reset_x_origin (leftmost_frame + xdelta);
149                 } else {
150                         reset_x_origin (max_framepos - current_page_samples());
151                 }
152                 break;
153
154         default:
155                 /* what? */
156                 break;
157         }
158
159         return false;
160 }
161
162 bool
163 Editor::canvas_scroll_event (GdkEventScroll *event, bool from_canvas)
164 {
165         if (from_canvas) {
166                 boost::optional<ArdourCanvas::Rect> rulers = _time_markers_group->bounding_box();
167                 if (rulers && rulers->contains (Duple (event->x, event->y))) {
168                         return canvas_ruler_event ((GdkEvent*) event, timecode_ruler, TimecodeRulerItem);
169                 }
170         }
171
172         _track_canvas->grab_focus();
173         return track_canvas_scroll (event);
174 }
175
176 bool
177 Editor::track_canvas_button_press_event (GdkEventButton *event)
178 {
179         _track_canvas->grab_focus();
180         if (!Keyboard::is_context_menu_event (event)) {
181                 begin_reversible_selection_op (X_("Clear Selection Click (track canvas)"));
182                 selection->clear ();
183                 commit_reversible_selection_op();
184         }
185         return false;
186 }
187
188 bool
189 Editor::track_canvas_button_release_event (GdkEventButton *event)
190 {
191         if (!Keyboard::is_context_menu_event (event)) {
192                 if (_drags->active ()) {
193                         _drags->end_grab ((GdkEvent*) event);
194                 }
195         }
196         return false;
197 }
198
199 bool
200 Editor::track_canvas_motion_notify_event (GdkEventMotion */*event*/)
201 {
202         int x, y;
203         /* keep those motion events coming */
204         _track_canvas->get_pointer (x, y);
205         return false;
206 }
207
208 bool
209 Editor::typed_event (ArdourCanvas::Item* item, GdkEvent *event, ItemType type)
210 {
211         gint ret = FALSE;
212
213         switch (event->type) {
214         case GDK_BUTTON_PRESS:
215         case GDK_2BUTTON_PRESS:
216         case GDK_3BUTTON_PRESS:
217                 ret = button_press_handler (item, event, type);
218                 break;
219         case GDK_BUTTON_RELEASE:
220                 ret = button_release_handler (item, event, type);
221                 break;
222         case GDK_MOTION_NOTIFY:
223                 ret = motion_handler (item, event);
224                 break;
225
226         case GDK_ENTER_NOTIFY:
227                 ret = enter_handler (item, event, type);
228                 break;
229
230         case GDK_LEAVE_NOTIFY:
231                 ret = leave_handler (item, event, type);
232                 break;
233
234         case GDK_KEY_PRESS:
235                 ret = key_press_handler (item, event, type);
236                 break;
237
238         case GDK_KEY_RELEASE:
239                 ret = key_release_handler (item, event, type);
240                 break;
241
242         default:
243                 break;
244         }
245         return ret;
246 }
247
248 bool
249 Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView *rv)
250 {
251         bool ret = false;
252
253         if (!rv->sensitive ()) {
254                 return false;
255         }
256
257         switch (event->type) {
258         case GDK_BUTTON_PRESS:
259         case GDK_2BUTTON_PRESS:
260         case GDK_3BUTTON_PRESS:
261                 clicked_regionview = rv;
262                 clicked_control_point = 0;
263                 clicked_axisview = &rv->get_time_axis_view();
264                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
265                 ret = button_press_handler (item, event, RegionItem);
266                 break;
267
268         case GDK_BUTTON_RELEASE:
269                 ret = button_release_handler (item, event, RegionItem);
270                 break;
271
272         case GDK_MOTION_NOTIFY:
273                 ret = motion_handler (item, event);
274                 break;
275
276         case GDK_ENTER_NOTIFY:
277                 set_entered_regionview (rv);
278                 ret = enter_handler (item, event, RegionItem);
279                 break;
280
281         case GDK_LEAVE_NOTIFY:
282                 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) {
283                         set_entered_regionview (0);
284                         ret = leave_handler (item, event, RegionItem);
285                 }
286                 break;
287
288         default:
289                 break;
290         }
291
292         return ret;
293 }
294
295 bool
296 Editor::canvas_wave_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
297 {
298         /* we only care about enter events here, required for mouse/cursor
299          * tracking. there is a non-linear (non-child/non-parent) relationship
300          * between various components of a regionview and so when we leave one
301          * of them (e.g. a trim handle) and enter another (e.g. the waveview)
302          * no other items get notified. enter/leave handling does not propagate
303          * in the same way as other events, so we need to catch this because
304          * entering (and leaving) the waveview is equivalent to
305          * entering/leaving the regionview (which is why it is passed in as a
306          * third argument).
307          *
308          * And in fact, we really only care about enter events.
309          */
310
311         bool ret = false;
312
313         if (!rv->sensitive ()) {
314                 return false;
315         }
316
317         switch (event->type) {
318         case GDK_ENTER_NOTIFY:
319                 set_entered_regionview (rv);
320                 ret = enter_handler (item, event, WaveItem);
321                 break;
322
323         default:
324                 break;
325         }
326
327         return ret;
328 }
329
330
331 bool
332 Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, RouteTimeAxisView *tv)
333 {
334         bool ret = FALSE;
335
336         switch (event->type) {
337         case GDK_BUTTON_PRESS:
338         case GDK_2BUTTON_PRESS:
339         case GDK_3BUTTON_PRESS:
340                 clicked_regionview = 0;
341                 clicked_control_point = 0;
342                 clicked_axisview = tv;
343                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
344                 ret = button_press_handler (item, event, StreamItem);
345                 break;
346
347         case GDK_BUTTON_RELEASE:
348                 ret = button_release_handler (item, event, StreamItem);
349                 break;
350
351         case GDK_MOTION_NOTIFY:
352                 ret = motion_handler (item, event);
353                 break;
354
355         case GDK_ENTER_NOTIFY:
356                 set_entered_track (tv);
357                 ret = enter_handler (item, event, StreamItem);
358                 break;
359
360         case GDK_LEAVE_NOTIFY:
361                 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) {
362                         set_entered_track (0);
363                 }
364                 ret = leave_handler (item, event, StreamItem);
365                 break;
366
367         default:
368                 break;
369         }
370
371         return ret;
372 }
373
374 bool
375 Editor::canvas_automation_track_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationTimeAxisView *atv)
376 {
377         bool ret = false;
378
379         switch (event->type) {
380         case GDK_BUTTON_PRESS:
381         case GDK_2BUTTON_PRESS:
382         case GDK_3BUTTON_PRESS:
383                 clicked_regionview = 0;
384                 clicked_control_point = 0;
385                 clicked_axisview = atv;
386                 clicked_routeview = 0;
387                 ret = button_press_handler (item, event, AutomationTrackItem);
388                 break;
389
390         case GDK_BUTTON_RELEASE:
391                 ret = button_release_handler (item, event, AutomationTrackItem);
392                 break;
393
394         case GDK_MOTION_NOTIFY:
395                 ret = motion_handler (item, event);
396                 break;
397
398         case GDK_ENTER_NOTIFY:
399                 ret = enter_handler (item, event, AutomationTrackItem);
400                 break;
401
402         case GDK_LEAVE_NOTIFY:
403                 ret = leave_handler (item, event, AutomationTrackItem);
404                 break;
405
406         default:
407                 break;
408         }
409
410         return ret;
411 }
412
413 bool
414 Editor::canvas_start_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
415 {
416         if (!rv->sensitive()) {
417                 return false;
418         }
419
420         switch (event->type) {
421         case GDK_BUTTON_PRESS:
422                 clicked_regionview = rv;
423                 clicked_control_point = 0;
424                 clicked_axisview = &rv->get_time_axis_view();
425                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
426                 if (event->button.button == 3) {
427                         return button_press_handler (item, event, StartCrossFadeItem);
428                 }
429                 break;
430
431         case GDK_BUTTON_RELEASE:
432                 if (event->button.button == 3) {
433                         return button_release_handler (item, event, StartCrossFadeItem);
434                 }
435                 break;
436
437         default:
438                 break;
439
440         }
441
442         /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
443         /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
444         /* if we return RegionItem here then we avoid the issue until it is resolved later */
445         return typed_event (item, event, RegionItem); // StartCrossFadeItem);
446 }
447
448 bool
449 Editor::canvas_end_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
450 {
451         if (!rv->sensitive()) {
452                 return false;
453         }
454
455         switch (event->type) {
456         case GDK_BUTTON_PRESS:
457                 clicked_regionview = rv;
458                 clicked_control_point = 0;
459                 clicked_axisview = &rv->get_time_axis_view();
460                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
461                 if (event->button.button == 3) {
462                         return button_press_handler (item, event, EndCrossFadeItem);
463                 }
464                 break;
465
466         case GDK_BUTTON_RELEASE:
467                 if (event->button.button == 3) {
468                         return button_release_handler (item, event, EndCrossFadeItem);
469                 }
470                 break;
471
472         default:
473                 break;
474
475         }
476
477         /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
478         /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
479         /* if we return RegionItem here then we avoid the issue until it is resolved later */
480         return typed_event (item, event, RegionItem); // EndCrossFadeItem);
481 }
482
483 bool
484 Editor::canvas_fade_in_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
485 {
486         /* we handle only button 3 press/release events */
487
488         if (!rv->sensitive()) {
489                 return false;
490         }
491
492         switch (event->type) {
493         case GDK_BUTTON_PRESS:
494                 clicked_regionview = rv;
495                 clicked_control_point = 0;
496                 clicked_axisview = &rv->get_time_axis_view();
497                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
498                 if (event->button.button == 3) {
499                         return button_press_handler (item, event, FadeInItem);
500                 }
501                 break;
502
503         case GDK_BUTTON_RELEASE:
504                 if (event->button.button == 3) {
505                         return button_release_handler (item, event, FadeInItem);
506                 }
507                 break;
508
509         default:
510                 break;
511
512         }
513
514         /* proxy for the regionview, except enter/leave events */
515
516         if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
517                 return true;
518         } else {
519                 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
520         }
521 }
522
523 bool
524 Editor::canvas_fade_in_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv, bool trim)
525 {
526         bool ret = false;
527
528         if (!rv->sensitive()) {
529                 return false;
530         }
531
532         switch (event->type) {
533         case GDK_BUTTON_PRESS:
534         case GDK_2BUTTON_PRESS:
535         case GDK_3BUTTON_PRESS:
536                 clicked_regionview = rv;
537                 clicked_control_point = 0;
538                 clicked_axisview = &rv->get_time_axis_view();
539                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
540                 ret = button_press_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
541                 break;
542
543         case GDK_BUTTON_RELEASE:
544                 ret = button_release_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
545                 maybe_locate_with_edit_preroll ( rv->region()->position() );
546                 break;
547
548         case GDK_MOTION_NOTIFY:
549                 ret = motion_handler (item, event);
550                 break;
551
552         case GDK_ENTER_NOTIFY:
553                 ret = enter_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
554                 break;
555
556         case GDK_LEAVE_NOTIFY:
557                 ret = leave_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
558                 break;
559
560         default:
561                 break;
562         }
563
564         return ret;
565 }
566
567 bool
568 Editor::canvas_fade_out_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
569 {
570         /* we handle only button 3 press/release events */
571
572         if (!rv->sensitive()) {
573                 return false;
574         }
575
576         switch (event->type) {
577         case GDK_BUTTON_PRESS:
578                 clicked_regionview = rv;
579                 clicked_control_point = 0;
580                 clicked_axisview = &rv->get_time_axis_view();
581                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
582                 if (event->button.button == 3) {
583                         return button_press_handler (item, event, FadeOutItem);
584                 }
585                 break;
586
587         case GDK_BUTTON_RELEASE:
588                 if (event->button.button == 3) {
589                         return button_release_handler (item, event, FadeOutItem);
590                 }
591                 break;
592
593         default:
594                 break;
595
596         }
597
598         /* proxy for the regionview, except enter/leave events */
599
600         if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
601                 return true;
602         } else {
603                 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
604         }
605 }
606
607 bool
608 Editor::canvas_fade_out_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv, bool trim)
609 {
610         bool ret = false;
611
612         if (!rv->sensitive()) {
613                 return false;
614         }
615
616         switch (event->type) {
617         case GDK_BUTTON_PRESS:
618         case GDK_2BUTTON_PRESS:
619         case GDK_3BUTTON_PRESS:
620                 clicked_regionview = rv;
621                 clicked_control_point = 0;
622                 clicked_axisview = &rv->get_time_axis_view();
623                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
624                 ret = button_press_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
625                 break;
626
627         case GDK_BUTTON_RELEASE:
628                 ret = button_release_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
629                 maybe_locate_with_edit_preroll ( rv->region()->last_frame() - rv->get_fade_out_shape_width() );
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                 clicked_regionview = &gl->region_view ();
691         } else {
692                 type = AutomationLineItem;
693                 clicked_regionview = 0;
694         }
695
696         clicked_control_point = 0;
697         clicked_axisview = &al->trackview;
698         clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
699
700         return typed_event (item, event, type);
701 }
702
703 bool
704 Editor::canvas_selection_rect_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
705 {
706         bool ret = false;
707
708         switch (event->type) {
709         case GDK_BUTTON_PRESS:
710         case GDK_2BUTTON_PRESS:
711         case GDK_3BUTTON_PRESS:
712                 clicked_selection = rect->id;
713                 ret = button_press_handler (item, event, SelectionItem);
714                 break;
715         case GDK_BUTTON_RELEASE:
716                 ret = button_release_handler (item, event, SelectionItem);
717                 break;
718         case GDK_MOTION_NOTIFY:
719                 ret = motion_handler (item, event);
720                 break;
721                 /* Don't need these at the moment. */
722         case GDK_ENTER_NOTIFY:
723                 ret = enter_handler (item, event, SelectionItem);
724                 break;
725
726         case GDK_LEAVE_NOTIFY:
727                 ret = leave_handler (item, event, SelectionItem);
728                 break;
729
730         default:
731                 break;
732         }
733
734         return ret;
735 }
736
737 bool
738 Editor::canvas_selection_start_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
739 {
740         bool ret = false;
741
742         switch (event->type) {
743         case GDK_BUTTON_PRESS:
744         case GDK_2BUTTON_PRESS:
745         case GDK_3BUTTON_PRESS:
746                 clicked_selection = rect->id;
747                 ret = button_press_handler (item, event, StartSelectionTrimItem);
748                 break;
749         case GDK_BUTTON_RELEASE:
750                 ret = button_release_handler (item, event, StartSelectionTrimItem);
751                 break;
752         case GDK_MOTION_NOTIFY:
753                 ret = motion_handler (item, event);
754                 break;
755         case GDK_ENTER_NOTIFY:
756                 ret = enter_handler (item, event, StartSelectionTrimItem);
757                 break;
758
759         case GDK_LEAVE_NOTIFY:
760                 ret = leave_handler (item, event, StartSelectionTrimItem);
761                 break;
762
763         default:
764                 break;
765         }
766
767         return ret;
768 }
769
770 bool
771 Editor::canvas_selection_end_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
772 {
773         bool ret = false;
774
775         switch (event->type) {
776         case GDK_BUTTON_PRESS:
777         case GDK_2BUTTON_PRESS:
778         case GDK_3BUTTON_PRESS:
779                 clicked_selection = rect->id;
780                 ret = button_press_handler (item, event, EndSelectionTrimItem);
781                 break;
782         case GDK_BUTTON_RELEASE:
783                 ret = button_release_handler (item, event, EndSelectionTrimItem);
784                 break;
785         case GDK_MOTION_NOTIFY:
786                 ret = motion_handler (item, event);
787                 break;
788         case GDK_ENTER_NOTIFY:
789                 ret = enter_handler (item, event, EndSelectionTrimItem);
790                 break;
791
792         case GDK_LEAVE_NOTIFY:
793                 ret = leave_handler (item, event, EndSelectionTrimItem);
794                 break;
795
796         default:
797                 break;
798         }
799
800         return ret;
801 }
802
803 bool
804 Editor::canvas_frame_handle_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
805 {
806         bool ret = false;
807
808         /* frame handles are not active when in internal edit mode, because actual notes
809            might be in the area occupied by the handle - we want them to be editable as normal.
810         */
811
812         if (internal_editing() || !rv->sensitive()) {
813                 return false;
814         }
815
816         /* NOTE: frame handles pretend to be the colored trim bar from an event handling
817            perspective. XXX change this ??
818         */
819
820         ItemType type;
821
822         if (item->get_data ("isleft")) {
823                 type = LeftFrameHandle;
824         } else {
825                 type = RightFrameHandle;
826         }
827
828         switch (event->type) {
829         case GDK_BUTTON_PRESS:
830         case GDK_2BUTTON_PRESS:
831         case GDK_3BUTTON_PRESS:
832                 clicked_regionview = rv;
833                 clicked_control_point = 0;
834                 clicked_axisview = &clicked_regionview->get_time_axis_view();
835                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
836                 ret = button_press_handler (item, event, type);
837                 break;
838         case GDK_BUTTON_RELEASE:
839                 ret = button_release_handler (item, event, type);
840                 break;
841         case GDK_MOTION_NOTIFY:
842                 ret = motion_handler (item, event);
843                 break;
844         case GDK_ENTER_NOTIFY:
845                 ret = enter_handler (item, event, type);
846                 break;
847
848         case GDK_LEAVE_NOTIFY:
849                 ret = leave_handler (item, event, type);
850                 break;
851
852         default:
853                 break;
854         }
855
856         return ret;
857 }
858
859
860 bool
861 Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
862 {
863         bool ret = false;
864
865         if (!rv->sensitive()) {
866                 return false;
867         }
868
869         switch (event->type) {
870         case GDK_BUTTON_PRESS:
871         case GDK_2BUTTON_PRESS:
872         case GDK_3BUTTON_PRESS:
873                 clicked_regionview = rv;
874                 clicked_control_point = 0;
875                 clicked_axisview = &clicked_regionview->get_time_axis_view();
876                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
877                 ret = button_press_handler (item, event, RegionViewNameHighlight);
878                 break;
879         case GDK_BUTTON_RELEASE:
880                 ret = button_release_handler (item, event, RegionViewNameHighlight);
881                 break;
882         case GDK_MOTION_NOTIFY:
883                 motion_handler (item, event);
884                 ret = true; // force this to avoid progagating the event into the regionview
885                 break;
886         case GDK_ENTER_NOTIFY:
887                 ret = enter_handler (item, event, RegionViewNameHighlight);
888                 break;
889
890         case GDK_LEAVE_NOTIFY:
891                 ret = leave_handler (item, event, RegionViewNameHighlight);
892                 break;
893
894         default:
895                 break;
896         }
897
898         return ret;
899 }
900
901 bool
902 Editor::canvas_region_view_name_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
903 {
904         bool ret = false;
905
906         if (!rv->sensitive()) {
907                 return false;
908         }
909
910         switch (event->type) {
911         case GDK_BUTTON_PRESS:
912         case GDK_2BUTTON_PRESS:
913         case GDK_3BUTTON_PRESS:
914                 clicked_regionview = rv;
915                 clicked_control_point = 0;
916                 clicked_axisview = &clicked_regionview->get_time_axis_view();
917                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
918                 ret = button_press_handler (item, event, RegionViewName);
919                 break;
920         case GDK_BUTTON_RELEASE:
921                 ret = button_release_handler (item, event, RegionViewName);
922                 break;
923         case GDK_MOTION_NOTIFY:
924                 ret = motion_handler (item, event);
925                 break;
926         case GDK_ENTER_NOTIFY:
927                 ret = enter_handler (item, event, RegionViewName);
928                 break;
929
930         case GDK_LEAVE_NOTIFY:
931                 ret = leave_handler (item, event, RegionViewName);
932                 break;
933
934         default:
935                 break;
936         }
937
938         return ret;
939 }
940
941 bool
942 Editor::canvas_feature_line_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView*)
943 {
944         bool ret = false;
945
946         switch (event->type) {
947         case GDK_BUTTON_PRESS:
948         case GDK_2BUTTON_PRESS:
949         case GDK_3BUTTON_PRESS:
950                 clicked_regionview = 0;
951                 clicked_control_point = 0;
952                 clicked_axisview = 0;
953                 clicked_routeview = 0; //dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
954                 ret = button_press_handler (item, event, FeatureLineItem);
955                 break;
956
957         case GDK_BUTTON_RELEASE:
958                 ret = button_release_handler (item, event, FeatureLineItem);
959                 break;
960
961         case GDK_MOTION_NOTIFY:
962                 ret = motion_handler (item, event);
963                 break;
964
965         case GDK_ENTER_NOTIFY:
966                 ret = enter_handler (item, event, FeatureLineItem);
967                 break;
968
969         case GDK_LEAVE_NOTIFY:
970                 ret = leave_handler (item, event, FeatureLineItem);
971                 break;
972
973         default:
974                 break;
975         }
976
977         return ret;
978 }
979
980 bool
981 Editor::canvas_marker_event (GdkEvent *event, ArdourCanvas::Item* item, ArdourMarker* /*marker*/)
982 {
983         return typed_event (item, event, MarkerItem);
984 }
985
986 bool
987 Editor::canvas_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
988 {
989         return typed_event (item, event, MarkerBarItem);
990 }
991
992 bool
993 Editor::canvas_range_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
994 {
995         return typed_event (item, event, RangeMarkerBarItem);
996 }
997
998 bool
999 Editor::canvas_transport_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1000 {
1001         return typed_event (item, event, TransportMarkerBarItem);
1002 }
1003
1004 bool
1005 Editor::canvas_cd_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1006 {
1007         return typed_event (item, event, CdMarkerBarItem);
1008 }
1009
1010 bool
1011 Editor::canvas_videotl_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1012 {
1013         return typed_event (item, event, VideoBarItem);
1014 }
1015
1016 bool
1017 Editor::canvas_tempo_marker_event (GdkEvent *event, ArdourCanvas::Item* item, TempoMarker* /*marker*/)
1018 {
1019         return typed_event (item, event, TempoMarkerItem);
1020 }
1021
1022 bool
1023 Editor::canvas_meter_marker_event (GdkEvent *event, ArdourCanvas::Item* item, MeterMarker* /*marker*/)
1024 {
1025         return typed_event (item, event, MeterMarkerItem);
1026 }
1027
1028 bool
1029 Editor::canvas_ruler_event (GdkEvent *event, ArdourCanvas::Item* item, ItemType type)
1030 {
1031         framepos_t xdelta;
1032         bool handled = false;
1033
1034         if (event->type == GDK_SCROLL) {
1035
1036                 /* scroll events in the rulers are handled a little differently from
1037                    scrolling elsewhere in the canvas.
1038                 */
1039
1040                 switch (event->scroll.direction) {
1041                 case GDK_SCROLL_UP:
1042
1043                         if (Profile->get_mixbus()) {
1044                                 //for mouse-wheel zoom, force zoom-focus to mouse
1045                                 Editing::ZoomFocus temp_focus = zoom_focus;
1046                                 zoom_focus = Editing::ZoomFocusMouse;
1047                                 temporal_zoom_step (false);
1048                                 zoom_focus = temp_focus;
1049                         } else {
1050                                 temporal_zoom_step (false);
1051                         }
1052                         handled = true;
1053                         break;
1054
1055                 case GDK_SCROLL_DOWN:
1056                         if (Profile->get_mixbus()) {
1057                                 //for mouse-wheel zoom, force zoom-focus to mouse
1058                                 Editing::ZoomFocus temp_focus = zoom_focus;
1059                                 zoom_focus = Editing::ZoomFocusMouse;
1060                                 temporal_zoom_step (true);
1061                                 zoom_focus = temp_focus;
1062                         } else {
1063                                 temporal_zoom_step (true);
1064                         }
1065                         handled = true;
1066                         break;
1067
1068                 case GDK_SCROLL_LEFT:
1069                         xdelta = (current_page_samples() / 2);
1070                         if (leftmost_frame > xdelta) {
1071                                 reset_x_origin (leftmost_frame - xdelta);
1072                         } else {
1073                                 reset_x_origin (0);
1074                         }
1075                         handled = true;
1076                         break;
1077
1078                 case GDK_SCROLL_RIGHT:
1079                         xdelta = (current_page_samples() / 2);
1080                         if (max_framepos - xdelta > leftmost_frame) {
1081                                 reset_x_origin (leftmost_frame + xdelta);
1082                         } else {
1083                                 reset_x_origin (max_framepos - current_page_samples());
1084                         }
1085                         handled = true;
1086                         break;
1087
1088                 default:
1089                         /* what? */
1090                         break;
1091                 }
1092                 return handled;
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 (Profile->get_sae() || 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, ARDOUR::Normal, 0, 1, region->name());
1298                                 rtav = axis_view_from_route (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, boost::shared_ptr<ARDOUR::PluginInfo>(), ARDOUR::Normal, 0, 1, region->name());
1303                                 rtav = axis_view_from_route (midi_tracks.front());
1304                         } else {
1305                                 return;
1306                         }
1307                 } catch (...) {
1308                         error << _("Could not create new track after region placed in the drop zone") << endmsg;
1309                         return;
1310                 }
1311         }
1312
1313         if (rtav != 0 && rtav->is_track ()) {
1314                 boost::shared_ptr<Region> region_copy = RegionFactory::create (region, true);
1315
1316                 if ((boost::dynamic_pointer_cast<AudioRegion> (region_copy) != 0 && dynamic_cast<AudioTimeAxisView*> (rtav) != 0) ||
1317                     (boost::dynamic_pointer_cast<MidiRegion> (region_copy) != 0 && dynamic_cast<MidiTimeAxisView*> (rtav) != 0)) {
1318                         _drags->set (new RegionInsertDrag (this, region_copy, rtav, pos), &event);
1319                         _drags->end_grab (0);
1320                 }
1321         }
1322 }
1323
1324 bool
1325 Editor::key_press_handler (ArdourCanvas::Item*, GdkEvent*, ItemType)
1326 {
1327         return false;
1328 }
1329
1330 bool
1331 Editor::key_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType type)
1332 {
1333
1334         bool handled = false;
1335
1336         switch (type) {
1337         case TempoMarkerItem:
1338                 switch (event->key.keyval) {
1339                 case GDK_Delete:
1340                         remove_tempo_marker (item);
1341                         handled = true;
1342                         break;
1343                 default:
1344                         break;
1345                 }
1346                 break;
1347
1348         case MeterMarkerItem:
1349                 switch (event->key.keyval) {
1350                 case GDK_Delete:
1351                         remove_meter_marker (item);
1352                         handled = true;
1353                         break;
1354                 default:
1355                         break;
1356                 }
1357                 break;
1358
1359         default:
1360                 break;
1361         }
1362
1363         return handled;
1364 }
1365