first vaguely working version using PresentationInfo
[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         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                 maybe_locate_with_edit_preroll ( rv->region()->position() );
536                 break;
537
538         case GDK_MOTION_NOTIFY:
539                 ret = motion_handler (item, event);
540                 break;
541
542         case GDK_ENTER_NOTIFY:
543                 ret = enter_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
544                 break;
545
546         case GDK_LEAVE_NOTIFY:
547                 ret = leave_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
548                 break;
549
550         default:
551                 break;
552         }
553
554         return ret;
555 }
556
557 bool
558 Editor::canvas_fade_out_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
559 {
560         /* we handle only button 3 press/release events */
561
562         if (!rv->sensitive()) {
563                 return false;
564         }
565
566         switch (event->type) {
567         case GDK_BUTTON_PRESS:
568                 clicked_regionview = rv;
569                 clicked_control_point = 0;
570                 clicked_axisview = &rv->get_time_axis_view();
571                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
572                 if (event->button.button == 3) {
573                         return button_press_handler (item, event, FadeOutItem);
574                 }
575                 break;
576
577         case GDK_BUTTON_RELEASE:
578                 if (event->button.button == 3) {
579                         return button_release_handler (item, event, FadeOutItem);
580                 }
581                 break;
582
583         default:
584                 break;
585
586         }
587
588         /* proxy for the regionview, except enter/leave events */
589
590         if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
591                 return true;
592         } else {
593                 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
594         }
595 }
596
597 bool
598 Editor::canvas_fade_out_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv, bool trim)
599 {
600         bool ret = false;
601
602         if (!rv->sensitive()) {
603                 return false;
604         }
605
606         switch (event->type) {
607         case GDK_BUTTON_PRESS:
608         case GDK_2BUTTON_PRESS:
609         case GDK_3BUTTON_PRESS:
610                 clicked_regionview = rv;
611                 clicked_control_point = 0;
612                 clicked_axisview = &rv->get_time_axis_view();
613                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
614                 ret = button_press_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
615                 break;
616
617         case GDK_BUTTON_RELEASE:
618                 ret = button_release_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
619                 maybe_locate_with_edit_preroll ( rv->region()->last_frame() - rv->get_fade_out_shape_width() );
620                 break;
621
622         case GDK_MOTION_NOTIFY:
623                 ret = motion_handler (item, event);
624                 break;
625
626         case GDK_ENTER_NOTIFY:
627                 ret = enter_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
628                 break;
629
630         case GDK_LEAVE_NOTIFY:
631                 ret = leave_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
632                 break;
633
634         default:
635                 break;
636         }
637
638         return ret;
639 }
640
641 struct DescendingRegionLayerSorter {
642     bool operator()(boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
643             return a->layer() > b->layer();
644     }
645 };
646
647 bool
648 Editor::canvas_control_point_event (GdkEvent *event, ArdourCanvas::Item* item, ControlPoint* cp)
649 {
650         switch (event->type) {
651         case GDK_BUTTON_PRESS:
652         case GDK_2BUTTON_PRESS:
653         case GDK_3BUTTON_PRESS:
654                 clicked_control_point = cp;
655                 clicked_axisview = &cp->line().trackview;
656                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
657                 clicked_regionview = 0;
658                 break;
659
660         case GDK_SCROLL_UP:
661                 break;
662
663         case GDK_SCROLL_DOWN:
664                 break;
665
666         default:
667                 break;
668         }
669
670         return typed_event (item, event, ControlPointItem);
671 }
672
673 bool
674 Editor::canvas_line_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationLine* al)
675 {
676         ItemType type;
677         AudioRegionGainLine* gl;
678         if ((gl = dynamic_cast<AudioRegionGainLine*> (al)) != 0) {
679                 type = GainLineItem;
680                 if (event->type == GDK_BUTTON_PRESS) {
681                         clicked_regionview = &gl->region_view ();
682                 }
683         } else {
684                 type = AutomationLineItem;
685                 if (event->type == GDK_BUTTON_PRESS) {
686                         clicked_regionview = 0;
687                 }
688         }
689
690         clicked_control_point = 0;
691         clicked_axisview = &al->trackview;
692         clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
693
694         return typed_event (item, event, type);
695 }
696
697 bool
698 Editor::canvas_selection_rect_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
699 {
700         bool ret = false;
701
702         switch (event->type) {
703         case GDK_BUTTON_PRESS:
704         case GDK_2BUTTON_PRESS:
705         case GDK_3BUTTON_PRESS:
706                 clicked_selection = rect->id;
707                 ret = button_press_handler (item, event, SelectionItem);
708                 break;
709         case GDK_BUTTON_RELEASE:
710                 ret = button_release_handler (item, event, SelectionItem);
711                 break;
712         case GDK_MOTION_NOTIFY:
713                 ret = motion_handler (item, event);
714                 break;
715                 /* Don't need these at the moment. */
716         case GDK_ENTER_NOTIFY:
717                 ret = enter_handler (item, event, SelectionItem);
718                 break;
719
720         case GDK_LEAVE_NOTIFY:
721                 ret = leave_handler (item, event, SelectionItem);
722                 break;
723
724         default:
725                 break;
726         }
727
728         return ret;
729 }
730
731 bool
732 Editor::canvas_selection_start_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
733 {
734         bool ret = false;
735
736         switch (event->type) {
737         case GDK_BUTTON_PRESS:
738         case GDK_2BUTTON_PRESS:
739         case GDK_3BUTTON_PRESS:
740                 clicked_selection = rect->id;
741                 ret = button_press_handler (item, event, StartSelectionTrimItem);
742                 break;
743         case GDK_BUTTON_RELEASE:
744                 ret = button_release_handler (item, event, StartSelectionTrimItem);
745                 break;
746         case GDK_MOTION_NOTIFY:
747                 ret = motion_handler (item, event);
748                 break;
749         case GDK_ENTER_NOTIFY:
750                 ret = enter_handler (item, event, StartSelectionTrimItem);
751                 break;
752
753         case GDK_LEAVE_NOTIFY:
754                 ret = leave_handler (item, event, StartSelectionTrimItem);
755                 break;
756
757         default:
758                 break;
759         }
760
761         return ret;
762 }
763
764 bool
765 Editor::canvas_selection_end_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
766 {
767         bool ret = false;
768
769         switch (event->type) {
770         case GDK_BUTTON_PRESS:
771         case GDK_2BUTTON_PRESS:
772         case GDK_3BUTTON_PRESS:
773                 clicked_selection = rect->id;
774                 ret = button_press_handler (item, event, EndSelectionTrimItem);
775                 break;
776         case GDK_BUTTON_RELEASE:
777                 ret = button_release_handler (item, event, EndSelectionTrimItem);
778                 break;
779         case GDK_MOTION_NOTIFY:
780                 ret = motion_handler (item, event);
781                 break;
782         case GDK_ENTER_NOTIFY:
783                 ret = enter_handler (item, event, EndSelectionTrimItem);
784                 break;
785
786         case GDK_LEAVE_NOTIFY:
787                 ret = leave_handler (item, event, EndSelectionTrimItem);
788                 break;
789
790         default:
791                 break;
792         }
793
794         return ret;
795 }
796
797 bool
798 Editor::canvas_frame_handle_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
799 {
800         bool ret = false;
801
802         /* frame handles are not active when in internal edit mode, because actual notes
803            might be in the area occupied by the handle - we want them to be editable as normal.
804         */
805
806         if (internal_editing() || !rv->sensitive()) {
807                 return false;
808         }
809
810         /* NOTE: frame handles pretend to be the colored trim bar from an event handling
811            perspective. XXX change this ??
812         */
813
814         ItemType type;
815
816         if (item->get_data ("isleft")) {
817                 type = LeftFrameHandle;
818         } else {
819                 type = RightFrameHandle;
820         }
821
822         switch (event->type) {
823         case GDK_BUTTON_PRESS:
824         case GDK_2BUTTON_PRESS:
825         case GDK_3BUTTON_PRESS:
826                 clicked_regionview = rv;
827                 clicked_control_point = 0;
828                 clicked_axisview = &clicked_regionview->get_time_axis_view();
829                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
830                 ret = button_press_handler (item, event, type);
831                 break;
832         case GDK_BUTTON_RELEASE:
833                 ret = button_release_handler (item, event, type);
834                 break;
835         case GDK_MOTION_NOTIFY:
836                 ret = motion_handler (item, event);
837                 break;
838         case GDK_ENTER_NOTIFY:
839                 ret = enter_handler (item, event, type);
840                 break;
841
842         case GDK_LEAVE_NOTIFY:
843                 ret = leave_handler (item, event, type);
844                 break;
845
846         default:
847                 break;
848         }
849
850         return ret;
851 }
852
853
854 bool
855 Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
856 {
857         bool ret = false;
858
859         if (!rv->sensitive()) {
860                 return false;
861         }
862
863         switch (event->type) {
864         case GDK_BUTTON_PRESS:
865         case GDK_2BUTTON_PRESS:
866         case GDK_3BUTTON_PRESS:
867                 clicked_regionview = rv;
868                 clicked_control_point = 0;
869                 clicked_axisview = &clicked_regionview->get_time_axis_view();
870                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
871                 ret = button_press_handler (item, event, RegionViewNameHighlight);
872                 break;
873         case GDK_BUTTON_RELEASE:
874                 ret = button_release_handler (item, event, RegionViewNameHighlight);
875                 break;
876         case GDK_MOTION_NOTIFY:
877                 motion_handler (item, event);
878                 ret = true; // force this to avoid progagating the event into the regionview
879                 break;
880         case GDK_ENTER_NOTIFY:
881                 ret = enter_handler (item, event, RegionViewNameHighlight);
882                 break;
883
884         case GDK_LEAVE_NOTIFY:
885                 ret = leave_handler (item, event, RegionViewNameHighlight);
886                 break;
887
888         default:
889                 break;
890         }
891
892         return ret;
893 }
894
895 bool
896 Editor::canvas_region_view_name_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
897 {
898         bool ret = false;
899
900         if (!rv->sensitive()) {
901                 return false;
902         }
903
904         switch (event->type) {
905         case GDK_BUTTON_PRESS:
906         case GDK_2BUTTON_PRESS:
907         case GDK_3BUTTON_PRESS:
908                 clicked_regionview = rv;
909                 clicked_control_point = 0;
910                 clicked_axisview = &clicked_regionview->get_time_axis_view();
911                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
912                 ret = button_press_handler (item, event, RegionViewName);
913                 break;
914         case GDK_BUTTON_RELEASE:
915                 ret = button_release_handler (item, event, RegionViewName);
916                 break;
917         case GDK_MOTION_NOTIFY:
918                 ret = motion_handler (item, event);
919                 break;
920         case GDK_ENTER_NOTIFY:
921                 ret = enter_handler (item, event, RegionViewName);
922                 break;
923
924         case GDK_LEAVE_NOTIFY:
925                 ret = leave_handler (item, event, RegionViewName);
926                 break;
927
928         default:
929                 break;
930         }
931
932         return ret;
933 }
934
935 bool
936 Editor::canvas_feature_line_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView*)
937 {
938         bool ret = false;
939
940         switch (event->type) {
941         case GDK_BUTTON_PRESS:
942         case GDK_2BUTTON_PRESS:
943         case GDK_3BUTTON_PRESS:
944                 clicked_regionview = 0;
945                 clicked_control_point = 0;
946                 clicked_axisview = 0;
947                 clicked_routeview = 0; //dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
948                 ret = button_press_handler (item, event, FeatureLineItem);
949                 break;
950
951         case GDK_BUTTON_RELEASE:
952                 ret = button_release_handler (item, event, FeatureLineItem);
953                 break;
954
955         case GDK_MOTION_NOTIFY:
956                 ret = motion_handler (item, event);
957                 break;
958
959         case GDK_ENTER_NOTIFY:
960                 ret = enter_handler (item, event, FeatureLineItem);
961                 break;
962
963         case GDK_LEAVE_NOTIFY:
964                 ret = leave_handler (item, event, FeatureLineItem);
965                 break;
966
967         default:
968                 break;
969         }
970
971         return ret;
972 }
973
974 bool
975 Editor::canvas_marker_event (GdkEvent *event, ArdourCanvas::Item* item, ArdourMarker* /*marker*/)
976 {
977         return typed_event (item, event, MarkerItem);
978 }
979
980 bool
981 Editor::canvas_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
982 {
983         return typed_event (item, event, MarkerBarItem);
984 }
985
986 bool
987 Editor::canvas_range_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
988 {
989         return typed_event (item, event, RangeMarkerBarItem);
990 }
991
992 bool
993 Editor::canvas_transport_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
994 {
995         return typed_event (item, event, TransportMarkerBarItem);
996 }
997
998 bool
999 Editor::canvas_cd_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1000 {
1001         return typed_event (item, event, CdMarkerBarItem);
1002 }
1003
1004 bool
1005 Editor::canvas_videotl_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1006 {
1007         return typed_event (item, event, VideoBarItem);
1008 }
1009
1010 bool
1011 Editor::canvas_tempo_marker_event (GdkEvent *event, ArdourCanvas::Item* item, TempoMarker* /*marker*/)
1012 {
1013         return typed_event (item, event, TempoMarkerItem);
1014 }
1015
1016 bool
1017 Editor::canvas_tempo_curve_event (GdkEvent *event, ArdourCanvas::Item* item, TempoCurve* /*marker*/)
1018 {
1019         return typed_event (item, event, TempoCurveItem);
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         bool handled = false;
1032
1033         if (event->type == GDK_SCROLL) {
1034
1035                 /* scroll events in the rulers are handled a little differently from
1036                    scrolling elsewhere in the canvas.
1037                 */
1038
1039                 switch (event->scroll.direction) {
1040                 case GDK_SCROLL_UP:
1041                         if (Keyboard::modifier_state_equals(event->scroll.state,
1042                                                             Keyboard::ScrollHorizontalModifier)) {
1043                                 scroll_left_step ();
1044                         } else if (UIConfiguration::instance().get_use_mouse_position_as_zoom_focus_on_scroll()) {
1045                                 temporal_zoom_step_mouse_focus (false);
1046                         } else {
1047                                 temporal_zoom_step (false);
1048                         }
1049                         handled = true;
1050                         break;
1051
1052                 case GDK_SCROLL_DOWN:
1053                         if (Keyboard::modifier_state_equals(event->scroll.state,
1054                                                             Keyboard::ScrollHorizontalModifier)) {
1055                                 scroll_right_step ();
1056                         } else if (UIConfiguration::instance().get_use_mouse_position_as_zoom_focus_on_scroll()) {
1057                                 temporal_zoom_step_mouse_focus (true);
1058                         } else {
1059                                 temporal_zoom_step (true);
1060                         }
1061                         handled = true;
1062                         break;
1063
1064                 case GDK_SCROLL_LEFT:
1065                         scroll_left_half_page ();
1066                         handled = true;
1067                         break;
1068
1069                 case GDK_SCROLL_RIGHT:
1070                         scroll_right_half_page ();
1071                         handled = true;
1072                         break;
1073
1074                 default:
1075                         /* what? */
1076                         break;
1077                 }
1078                 return handled;
1079         }
1080
1081         return typed_event (item, event, type);
1082 }
1083
1084 bool
1085 Editor::canvas_tempo_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1086 {
1087         return typed_event (item, event, TempoBarItem);
1088 }
1089
1090 bool
1091 Editor::canvas_meter_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1092 {
1093         return typed_event (item, event, MeterBarItem);
1094 }
1095
1096 bool
1097 Editor::canvas_playhead_cursor_event (GdkEvent *event, ArdourCanvas::Item* item)
1098 {
1099         return typed_event (item, event, PlayheadCursorItem);
1100 }
1101
1102 bool
1103 Editor::canvas_note_event (GdkEvent *event, ArdourCanvas::Item* item)
1104 {
1105         if (!internal_editing()) {
1106                 return false;
1107         }
1108
1109         return typed_event (item, event, NoteItem);
1110 }
1111
1112 bool
1113 Editor::canvas_drop_zone_event (GdkEvent* event)
1114 {
1115         GdkEventScroll scroll;
1116         ArdourCanvas::Duple winpos;
1117
1118         switch (event->type) {
1119         case GDK_BUTTON_RELEASE:
1120                 if (event->button.button == 1) {
1121                         begin_reversible_selection_op (X_("Nowhere Click"));
1122                         selection->clear_objects ();
1123                         selection->clear_tracks ();
1124                         commit_reversible_selection_op ();
1125                 }
1126                 break;
1127
1128         case GDK_SCROLL:
1129                 /* convert coordinates back into window space so that
1130                    we can just call canvas_scroll_event().
1131                 */
1132                 winpos = _track_canvas->canvas_to_window (Duple (event->scroll.x, event->scroll.y));
1133                 scroll = event->scroll;
1134                 scroll.x = winpos.x;
1135                 scroll.y = winpos.y;
1136                 return canvas_scroll_event (&scroll, true);
1137                 break;
1138
1139         case GDK_ENTER_NOTIFY:
1140                 return typed_event (_canvas_drop_zone, event, DropZoneItem);
1141
1142         case GDK_LEAVE_NOTIFY:
1143                 return typed_event (_canvas_drop_zone, event, DropZoneItem);
1144
1145         default:
1146                 break;
1147         }
1148
1149         return true;
1150 }
1151
1152 bool
1153 Editor::track_canvas_drag_motion (Glib::RefPtr<Gdk::DragContext> const& context, int x, int y, guint time)
1154 {
1155         boost::shared_ptr<Region> region;
1156         boost::shared_ptr<Region> region_copy;
1157         RouteTimeAxisView* rtav;
1158         GdkEvent event;
1159         double px;
1160         double py;
1161
1162         string target = _track_canvas->drag_dest_find_target (context, _track_canvas->drag_dest_get_target_list());
1163
1164         if (target.empty()) {
1165                 return false;
1166         }
1167
1168         event.type = GDK_MOTION_NOTIFY;
1169         event.button.x = x;
1170         event.button.y = y;
1171         /* assume we're dragging with button 1 */
1172         event.motion.state = Gdk::BUTTON1_MASK;
1173
1174         (void) window_event_sample (&event, &px, &py);
1175
1176         std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py, false);
1177         bool can_drop = false;
1178
1179         if (tv.first != 0) {
1180
1181                 /* over a time axis view of some kind */
1182
1183                 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1184
1185                 if (rtav != 0 && rtav->is_track ()) {
1186                         /* over a track, not a bus */
1187                         can_drop = true;
1188                 }
1189
1190
1191         } else {
1192                 /* not over a time axis view, so drop is possible */
1193                 can_drop = true;
1194         }
1195
1196         if (can_drop) {
1197                 region = _regions->get_dragged_region ();
1198
1199                 if (region) {
1200
1201                         if (tv.first == 0
1202                             && (
1203                                 boost::dynamic_pointer_cast<AudioRegion> (region) != 0 ||
1204                                 boost::dynamic_pointer_cast<MidiRegion> (region) != 0
1205                                )
1206                            )
1207                         {
1208                                 /* drop to drop-zone */
1209                                 context->drag_status (context->get_suggested_action(), time);
1210                                 return true;
1211                         }
1212
1213                         if ((boost::dynamic_pointer_cast<AudioRegion> (region) != 0 &&
1214                              dynamic_cast<AudioTimeAxisView*> (tv.first) != 0) ||
1215                             (boost::dynamic_pointer_cast<MidiRegion> (region) != 0 &&
1216                              dynamic_cast<MidiTimeAxisView*> (tv.first) != 0)) {
1217
1218                                 /* audio to audio
1219                                    OR
1220                                    midi to midi
1221                                 */
1222
1223                                 context->drag_status (context->get_suggested_action(), time);
1224                                 return true;
1225                         }
1226                 } else {
1227                         /* DND originating from outside ardour
1228                          *
1229                          * TODO: check if file is audio/midi, allow drops on same track-type only,
1230                          * currently: if audio is dropped on a midi-track, it is only added to the region-list
1231                          */
1232                         if (UIConfiguration::instance().get_only_copy_imported_files()) {
1233                                 context->drag_status(Gdk::ACTION_COPY, time);
1234                         } else {
1235                                 if ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY) {
1236                                         context->drag_status(Gdk::ACTION_COPY, time);
1237                                 } else {
1238                                         context->drag_status(Gdk::ACTION_LINK, time);
1239                                 }
1240                         }
1241                         return true;
1242                 }
1243         }
1244
1245         /* no drop here */
1246         context->drag_status (Gdk::DragAction (0), time);
1247         return false;
1248 }
1249
1250 void
1251 Editor::drop_regions (const Glib::RefPtr<Gdk::DragContext>& /*context*/,
1252                       int x, int y,
1253                       const SelectionData& /*data*/,
1254                       guint /*info*/, guint /*time*/)
1255 {
1256         GdkEvent event;
1257         double px;
1258         double py;
1259
1260         event.type = GDK_MOTION_NOTIFY;
1261         event.button.x = x;
1262         event.button.y = y;
1263         /* assume we're dragging with button 1 */
1264         event.motion.state = Gdk::BUTTON1_MASK;
1265         framepos_t const pos = window_event_sample (&event, &px, &py);
1266
1267         boost::shared_ptr<Region> region = _regions->get_dragged_region ();
1268         if (!region) { return; }
1269
1270         RouteTimeAxisView* rtav = 0;
1271         std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py, false);
1272
1273         if (tv.first != 0) {
1274                 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1275         } else {
1276                 try {
1277                         if (boost::dynamic_pointer_cast<AudioRegion> (region)) {
1278                                 uint32_t output_chan = region->n_channels();
1279                                 if ((Config->get_output_auto_connect() & AutoConnectMaster) && session()->master_out()) {
1280                                         output_chan =  session()->master_out()->n_inputs().n_audio();
1281                                 }
1282                                 list<boost::shared_ptr<AudioTrack> > audio_tracks;
1283                                 audio_tracks = session()->new_audio_track (region->n_channels(), output_chan, 0, 1, region->name(), PresentationInfo::max_order, ARDOUR::Normal);
1284                                 rtav = axis_view_from_route (audio_tracks.front());
1285                         } else if (boost::dynamic_pointer_cast<MidiRegion> (region)) {
1286                                 ChanCount one_midi_port (DataType::MIDI, 1);
1287                                 list<boost::shared_ptr<MidiTrack> > midi_tracks;
1288                                 midi_tracks = session()->new_midi_track (one_midi_port, one_midi_port, boost::shared_ptr<ARDOUR::PluginInfo>(), 0, 1, region->name(), PresentationInfo::max_order, ARDOUR::Normal);
1289                                 rtav = axis_view_from_route (midi_tracks.front());
1290                         } else {
1291                                 return;
1292                         }
1293                 } catch (...) {
1294                         error << _("Could not create new track after region placed in the drop zone") << endmsg;
1295                         return;
1296                 }
1297         }
1298
1299         if (rtav != 0 && rtav->is_track ()) {
1300                 boost::shared_ptr<Region> region_copy = RegionFactory::create (region, true);
1301
1302                 if ((boost::dynamic_pointer_cast<AudioRegion> (region_copy) != 0 && dynamic_cast<AudioTimeAxisView*> (rtav) != 0) ||
1303                     (boost::dynamic_pointer_cast<MidiRegion> (region_copy) != 0 && dynamic_cast<MidiTimeAxisView*> (rtav) != 0)) {
1304                         _drags->set (new RegionInsertDrag (this, region_copy, rtav, pos), &event);
1305                         _drags->end_grab (0);
1306                 }
1307         }
1308 }
1309
1310 bool
1311 Editor::key_press_handler (ArdourCanvas::Item*, GdkEvent*, ItemType)
1312 {
1313         return false;
1314 }
1315
1316 bool
1317 Editor::key_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType type)
1318 {
1319
1320         bool handled = false;
1321
1322         switch (type) {
1323         case TempoMarkerItem:
1324                 switch (event->key.keyval) {
1325                 case GDK_Delete:
1326                         remove_tempo_marker (item);
1327                         handled = true;
1328                         break;
1329                 default:
1330                         break;
1331                 }
1332                 break;
1333
1334         case MeterMarkerItem:
1335                 switch (event->key.keyval) {
1336                 case GDK_Delete:
1337                         remove_meter_marker (item);
1338                         handled = true;
1339                         break;
1340                 default:
1341                         break;
1342                 }
1343                 break;
1344
1345         default:
1346                 break;
1347         }
1348
1349         return handled;
1350 }
1351