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