Merge branch 'master' into cairocanvas
[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/midi_region.h"
28 #include "ardour/region_factory.h"
29 #include "ardour/profile.h"
30
31 #include "canvas/canvas.h"
32 #include "canvas/text.h"
33
34 #include "editor.h"
35 #include "keyboard.h"
36 #include "public_editor.h"
37 #include "audio_region_view.h"
38 #include "audio_streamview.h"
39 #include "audio_time_axis.h"
40 #include "region_gain_line.h"
41 #include "automation_line.h"
42 #include "automation_time_axis.h"
43 #include "automation_line.h"
44 #include "control_point.h"
45 #include "editor_drag.h"
46 #include "midi_time_axis.h"
47 #include "editor_regions.h"
48 #include "verbose_cursor.h"
49
50 #include "i18n.h"
51
52 using namespace std;
53 using namespace ARDOUR;
54 using namespace PBD;
55 using namespace Gtk;
56 using namespace ArdourCanvas;
57
58 using Gtkmm2ext::Keyboard;
59
60 bool
61 Editor::track_canvas_scroll (GdkEventScroll* ev)
62 {
63         framepos_t xdelta;
64         int direction = ev->direction;
65
66   retry:
67         switch (direction) {
68         case GDK_SCROLL_UP:
69                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
70                         //for mouse-wheel zoom, force zoom-focus to mouse
71                         Editing::ZoomFocus temp_focus = zoom_focus;
72                         zoom_focus = Editing::ZoomFocusMouse;
73                         temporal_zoom_step (false);
74                         zoom_focus = temp_focus;
75                         return true;
76                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::SecondaryModifier)) {
77                         direction = GDK_SCROLL_LEFT;
78                         goto retry;
79                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
80                         if (!current_stepping_trackview) {
81                                 step_timeout = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Editor::track_height_step_timeout), 500);
82                                 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (ev->y + vertical_adjustment.get_value());
83                                 current_stepping_trackview = p.first;
84                                 if (!current_stepping_trackview) {
85                                         return false;
86                                 }
87                         }
88                         last_track_height_step_timestamp = get_microseconds();
89                         current_stepping_trackview->step_height (false);
90                         return true;
91                 } else {
92                         scroll_tracks_up_line ();
93                         return true;
94                 }
95                 break;
96
97         case GDK_SCROLL_DOWN:
98                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
99                         //for mouse-wheel zoom, force zoom-focus to mouse
100                         Editing::ZoomFocus temp_focus = zoom_focus;
101                         zoom_focus = Editing::ZoomFocusMouse;
102                         temporal_zoom_step (true);
103                         zoom_focus = temp_focus;
104                         return true;
105                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::SecondaryModifier)) {
106                         direction = GDK_SCROLL_RIGHT;
107                         goto retry;
108                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
109                         if (!current_stepping_trackview) {
110                                 step_timeout = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Editor::track_height_step_timeout), 500);
111                                 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (ev->y + vertical_adjustment.get_value());
112                                 current_stepping_trackview = p.first;
113                                 if (!current_stepping_trackview) {
114                                         return false;
115                                 }
116                         }
117                         last_track_height_step_timestamp = get_microseconds();
118                         current_stepping_trackview->step_height (true);
119                         return true;
120                 } else {
121                         scroll_tracks_down_line ();
122                         return true;
123                 }
124                 break;
125
126         case GDK_SCROLL_LEFT:
127                 xdelta = (current_page_frames() / 8);
128                 if (leftmost_frame > xdelta) {
129                         reset_x_origin (leftmost_frame - xdelta);
130                 } else {
131                         reset_x_origin (0);
132                 }
133                 break;
134
135         case GDK_SCROLL_RIGHT:
136                 xdelta = (current_page_frames() / 8);
137                 if (max_framepos - xdelta > leftmost_frame) {
138                         reset_x_origin (leftmost_frame + xdelta);
139                 } else {
140                         reset_x_origin (max_framepos - current_page_frames());
141                 }
142                 break;
143
144         default:
145                 /* what? */
146                 break;
147         }
148
149         return false;
150 }
151
152 bool
153 Editor::track_canvas_scroll_event (GdkEventScroll *event)
154 {
155         _track_canvas->grab_focus();
156         return track_canvas_scroll (event);
157 }
158
159 bool
160 Editor::track_canvas_button_press_event (GdkEventButton */*event*/)
161 {
162         selection->clear ();
163         _track_canvas->grab_focus();
164         return false;
165 }
166
167 bool
168 Editor::track_canvas_button_release_event (GdkEventButton *event)
169 {
170         if (_drags->active ()) {
171                 _drags->end_grab ((GdkEvent*) event);
172         }
173         return false;
174 }
175
176 bool
177 Editor::track_canvas_motion_notify_event (GdkEventMotion */*event*/)
178 {
179         int x, y;
180         /* keep those motion events coming */
181         _track_canvas->get_pointer (x, y);
182         return false;
183 }
184
185 bool
186 Editor::track_canvas_motion (GdkEvent *ev)
187 {
188         if (_verbose_cursor->visible ()) {
189                 _verbose_cursor->set_position (ev->motion.x + 10, ev->motion.y + 10);
190         }
191
192         return false;
193 }
194
195 bool
196 Editor::typed_event (ArdourCanvas::Item* item, GdkEvent *event, ItemType type)
197 {
198         gint ret = FALSE;
199
200         switch (event->type) {
201         case GDK_BUTTON_PRESS:
202         case GDK_2BUTTON_PRESS:
203         case GDK_3BUTTON_PRESS:
204                 ret = button_press_handler (item, event, type);
205                 break;
206         case GDK_BUTTON_RELEASE:
207                 ret = button_release_handler (item, event, type);
208                 break;
209         case GDK_MOTION_NOTIFY:
210                 ret = motion_handler (item, event);
211                 break;
212
213         case GDK_ENTER_NOTIFY:
214                 ret = enter_handler (item, event, type);
215                 break;
216
217         case GDK_LEAVE_NOTIFY:
218                 ret = leave_handler (item, event, type);
219                 break;
220
221         case GDK_KEY_PRESS:
222                 ret = key_press_handler (item, event, type);
223                 break;
224
225         case GDK_KEY_RELEASE:
226                 ret = key_release_handler (item, event, type);
227                 break;
228
229         default:
230                 break;
231         }
232         return ret;
233 }
234
235 bool
236 Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView *rv)
237 {
238         bool ret = false;
239
240         if (!rv->sensitive ()) {
241                 return false;
242         }
243
244         switch (event->type) {
245         case GDK_BUTTON_PRESS:
246         case GDK_2BUTTON_PRESS:
247         case GDK_3BUTTON_PRESS:
248                 clicked_regionview = rv;
249                 clicked_control_point = 0;
250                 clicked_axisview = &rv->get_time_axis_view();
251                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
252                 ret = button_press_handler (item, event, RegionItem);
253                 break;
254
255         case GDK_BUTTON_RELEASE:
256                 ret = button_release_handler (item, event, RegionItem);
257                 break;
258
259         case GDK_MOTION_NOTIFY:
260                 ret = motion_handler (item, event);
261                 break;
262
263         case GDK_ENTER_NOTIFY:
264                 set_entered_track (&rv->get_time_axis_view ());
265                 set_entered_regionview (rv);
266                 break;
267
268         case GDK_LEAVE_NOTIFY:
269                 set_entered_track (0);
270                 set_entered_regionview (0);
271                 break;
272
273         default:
274                 break;
275         }
276
277         return ret;
278 }
279
280 bool
281 Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, RouteTimeAxisView *tv)
282 {
283         bool ret = FALSE;
284
285         switch (event->type) {
286         case GDK_BUTTON_PRESS:
287         case GDK_2BUTTON_PRESS:
288         case GDK_3BUTTON_PRESS:
289                 clicked_regionview = 0;
290                 clicked_control_point = 0;
291                 clicked_axisview = tv;
292                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
293                 ret = button_press_handler (item, event, StreamItem);
294                 break;
295
296         case GDK_BUTTON_RELEASE:
297                 ret = button_release_handler (item, event, StreamItem);
298                 break;
299
300         case GDK_MOTION_NOTIFY:
301                 ret = motion_handler (item, event);
302                 break;
303
304         case GDK_ENTER_NOTIFY:
305                 set_entered_track (tv);
306                 break;
307
308         case GDK_LEAVE_NOTIFY:
309                 set_entered_track (0);
310                 break;
311
312         default:
313                 break;
314         }
315
316         return ret;
317 }
318
319 bool
320 Editor::canvas_automation_track_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationTimeAxisView *atv)
321 {
322         bool ret = false;
323
324         switch (event->type) {
325         case GDK_BUTTON_PRESS:
326         case GDK_2BUTTON_PRESS:
327         case GDK_3BUTTON_PRESS:
328                 clicked_regionview = 0;
329                 clicked_control_point = 0;
330                 clicked_axisview = atv;
331                 clicked_routeview = 0;
332                 ret = button_press_handler (item, event, AutomationTrackItem);
333                 break;
334
335         case GDK_BUTTON_RELEASE:
336                 ret = button_release_handler (item, event, AutomationTrackItem);
337                 break;
338
339         case GDK_MOTION_NOTIFY:
340                 ret = motion_handler (item, event);
341                 break;
342
343         case GDK_ENTER_NOTIFY:
344                 ret = enter_handler (item, event, AutomationTrackItem);
345                 break;
346
347         case GDK_LEAVE_NOTIFY:
348                 ret = leave_handler (item, event, AutomationTrackItem);
349                 break;
350
351         default:
352                 break;
353         }
354
355         return ret;
356 }
357
358 bool
359 Editor::canvas_start_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
360 {
361         if (!rv->sensitive()) {
362                 return false;
363         }
364
365         switch (event->type) {
366         case GDK_BUTTON_PRESS:
367                 clicked_regionview = rv;
368                 clicked_control_point = 0;
369                 clicked_axisview = &rv->get_time_axis_view();
370                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
371                 if (event->button.button == 3) {
372                         return button_press_handler (item, event, StartCrossFadeItem);
373                 }
374                 break;
375
376         case GDK_BUTTON_RELEASE:
377                 if (event->button.button == 3) {
378                         return button_release_handler (item, event, StartCrossFadeItem);
379                 }
380                 break;
381
382         default:
383                 break;
384
385         }
386
387         /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
388         /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
389         /* if we return RegionItem here then we avoid the issue until it is resolved later */
390         return typed_event (item, event, RegionItem); // StartCrossFadeItem);
391 }
392
393 bool
394 Editor::canvas_end_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
395 {
396         if (!rv->sensitive()) {
397                 return false;
398         }
399
400         switch (event->type) {
401         case GDK_BUTTON_PRESS:
402                 clicked_regionview = rv;
403                 clicked_control_point = 0;
404                 clicked_axisview = &rv->get_time_axis_view();
405                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
406                 if (event->button.button == 3) {
407                         return button_press_handler (item, event, EndCrossFadeItem);
408                 }
409                 break;
410
411         case GDK_BUTTON_RELEASE:
412                 if (event->button.button == 3) {
413                         return button_release_handler (item, event, EndCrossFadeItem);
414                 }
415                 break;
416
417         default:
418                 break;
419
420         }
421
422         /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
423         /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
424         /* if we return RegionItem here then we avoid the issue until it is resolved later */
425         return typed_event (item, event, RegionItem); // EndCrossFadeItem);
426 }
427
428 bool
429 Editor::canvas_fade_in_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
430 {
431         /* we handle only button 3 press/release events */
432
433         if (!rv->sensitive()) {
434                 return false;
435         }
436
437         switch (event->type) {
438         case GDK_BUTTON_PRESS:
439                 clicked_regionview = rv;
440                 clicked_control_point = 0;
441                 clicked_axisview = &rv->get_time_axis_view();
442                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
443                 if (event->button.button == 3) {
444                         return button_press_handler (item, event, FadeInItem);
445                 }
446                 break;
447
448         case GDK_BUTTON_RELEASE:
449                 if (event->button.button == 3) {
450                         return button_release_handler (item, event, FadeInItem);
451                 }
452                 break;
453
454         default:
455                 break;
456
457         }
458
459         /* proxy for the regionview */
460
461         return canvas_region_view_event (event, rv->get_canvas_group(), rv);
462 }
463
464 bool
465 Editor::canvas_fade_in_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
466 {
467         bool ret = false;
468
469         if (!rv->sensitive()) {
470                 return false;
471         }
472
473         switch (event->type) {
474         case GDK_BUTTON_PRESS:
475         case GDK_2BUTTON_PRESS:
476         case GDK_3BUTTON_PRESS:
477                 clicked_regionview = rv;
478                 clicked_control_point = 0;
479                 clicked_axisview = &rv->get_time_axis_view();
480                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
481                 ret = button_press_handler (item, event, FadeInHandleItem);
482                 break;
483
484         case GDK_BUTTON_RELEASE:
485                 ret = button_release_handler (item, event, FadeInHandleItem);
486                 maybe_locate_with_edit_preroll ( rv->region()->position() );
487                 break;
488
489         case GDK_MOTION_NOTIFY:
490                 ret = motion_handler (item, event);
491                 break;
492
493         case GDK_ENTER_NOTIFY:
494                 set_entered_regionview (rv);
495                 ret = enter_handler (item, event, FadeInHandleItem);
496                 break;
497
498         case GDK_LEAVE_NOTIFY:
499                 set_entered_regionview (0);
500                 ret = leave_handler (item, event, FadeInHandleItem);
501                 break;
502
503         default:
504                 break;
505         }
506
507         return ret;
508 }
509
510 bool
511 Editor::canvas_fade_out_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
512 {
513         /* we handle only button 3 press/release events */
514
515         if (!rv->sensitive()) {
516                 return false;
517         }
518
519         switch (event->type) {
520         case GDK_BUTTON_PRESS:
521                 clicked_regionview = rv;
522                 clicked_control_point = 0;
523                 clicked_axisview = &rv->get_time_axis_view();
524                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
525                 if (event->button.button == 3) {
526                         return button_press_handler (item, event, FadeOutItem);
527                 }
528                 break;
529
530         case GDK_BUTTON_RELEASE:
531                 if (event->button.button == 3) {
532                         return button_release_handler (item, event, FadeOutItem);
533                 }
534                 break;
535
536         default:
537                 break;
538
539         }
540
541         /* proxy for the regionview */
542
543         return canvas_region_view_event (event, rv->get_canvas_group(), rv);
544 }
545
546 bool
547 Editor::canvas_fade_out_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
548 {
549         bool ret = false;
550
551         if (!rv->sensitive()) {
552                 return false;
553         }
554
555         switch (event->type) {
556         case GDK_BUTTON_PRESS:
557         case GDK_2BUTTON_PRESS:
558         case GDK_3BUTTON_PRESS:
559                 clicked_regionview = rv;
560                 clicked_control_point = 0;
561                 clicked_axisview = &rv->get_time_axis_view();
562                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
563                 ret = button_press_handler (item, event, FadeOutHandleItem);
564                 break;
565
566         case GDK_BUTTON_RELEASE:
567                 ret = button_release_handler (item, event, FadeOutHandleItem);
568                 maybe_locate_with_edit_preroll ( rv->region()->last_frame() - rv->get_fade_out_shape_width() );
569                 break;
570
571         case GDK_MOTION_NOTIFY:
572                 ret = motion_handler (item, event);
573                 break;
574
575         case GDK_ENTER_NOTIFY:
576                 set_entered_regionview (rv);
577                 ret = enter_handler (item, event, FadeOutHandleItem);
578                 break;
579
580         case GDK_LEAVE_NOTIFY:
581                 set_entered_regionview (0);
582                 ret = leave_handler (item, event, FadeOutHandleItem);
583                 break;
584
585         default:
586                 break;
587         }
588
589         return ret;
590 }
591
592 struct DescendingRegionLayerSorter {
593     bool operator()(boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
594             return a->layer() > b->layer();
595     }
596 };
597
598 bool
599 Editor::canvas_control_point_event (GdkEvent *event, ArdourCanvas::Item* item, ControlPoint* cp)
600 {
601         switch (event->type) {
602         case GDK_BUTTON_PRESS:
603         case GDK_2BUTTON_PRESS:
604         case GDK_3BUTTON_PRESS:
605                 clicked_control_point = cp;
606                 clicked_axisview = &cp->line().trackview;
607                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
608                 clicked_regionview = 0;
609                 break;
610
611         case GDK_SCROLL_UP:
612                 break;
613
614         case GDK_SCROLL_DOWN:
615                 break;
616
617         default:
618                 break;
619         }
620
621         return typed_event (item, event, ControlPointItem);
622 }
623
624 bool
625 Editor::canvas_line_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationLine* al)
626 {
627         ItemType type;
628
629         if (dynamic_cast<AudioRegionGainLine*> (al) != 0) {
630                 type = GainLineItem;
631         } else {
632                 type = AutomationLineItem;
633         }
634
635         return typed_event (item, event, type);
636 }
637
638 bool
639 Editor::canvas_selection_rect_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
640 {
641         bool ret = false;
642
643         switch (event->type) {
644         case GDK_BUTTON_PRESS:
645         case GDK_2BUTTON_PRESS:
646         case GDK_3BUTTON_PRESS:
647                 clicked_selection = rect->id;
648                 ret = button_press_handler (item, event, SelectionItem);
649                 break;
650         case GDK_BUTTON_RELEASE:
651                 ret = button_release_handler (item, event, SelectionItem);
652                 break;
653         case GDK_MOTION_NOTIFY:
654                 ret = motion_handler (item, event);
655                 break;
656                 /* Don't need these at the moment. */
657         case GDK_ENTER_NOTIFY:
658                 ret = enter_handler (item, event, SelectionItem);
659                 break;
660
661         case GDK_LEAVE_NOTIFY:
662                 ret = leave_handler (item, event, SelectionItem);
663                 break;
664
665         default:
666                 break;
667         }
668
669         return ret;
670 }
671
672 bool
673 Editor::canvas_selection_start_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
674 {
675         bool ret = false;
676
677         switch (event->type) {
678         case GDK_BUTTON_PRESS:
679         case GDK_2BUTTON_PRESS:
680         case GDK_3BUTTON_PRESS:
681                 clicked_selection = rect->id;
682                 ret = button_press_handler (item, event, StartSelectionTrimItem);
683                 break;
684         case GDK_BUTTON_RELEASE:
685                 ret = button_release_handler (item, event, StartSelectionTrimItem);
686                 break;
687         case GDK_MOTION_NOTIFY:
688                 ret = motion_handler (item, event);
689                 break;
690         case GDK_ENTER_NOTIFY:
691                 ret = enter_handler (item, event, StartSelectionTrimItem);
692                 break;
693
694         case GDK_LEAVE_NOTIFY:
695                 ret = leave_handler (item, event, StartSelectionTrimItem);
696                 break;
697
698         default:
699                 break;
700         }
701
702         return ret;
703 }
704
705 bool
706 Editor::canvas_selection_end_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
707 {
708         bool ret = false;
709
710         switch (event->type) {
711         case GDK_BUTTON_PRESS:
712         case GDK_2BUTTON_PRESS:
713         case GDK_3BUTTON_PRESS:
714                 clicked_selection = rect->id;
715                 ret = button_press_handler (item, event, EndSelectionTrimItem);
716                 break;
717         case GDK_BUTTON_RELEASE:
718                 ret = button_release_handler (item, event, EndSelectionTrimItem);
719                 break;
720         case GDK_MOTION_NOTIFY:
721                 ret = motion_handler (item, event);
722                 break;
723         case GDK_ENTER_NOTIFY:
724                 ret = enter_handler (item, event, EndSelectionTrimItem);
725                 break;
726
727         case GDK_LEAVE_NOTIFY:
728                 ret = leave_handler (item, event, EndSelectionTrimItem);
729                 break;
730
731         default:
732                 break;
733         }
734
735         return ret;
736 }
737
738 bool
739 Editor::canvas_frame_handle_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
740 {
741         bool ret = false;
742
743         /* frame handles are not active when in internal edit mode, because actual notes
744            might be in the area occupied by the handle - we want them to be editable as normal.
745         */
746
747         if (internal_editing() || !rv->sensitive()) {
748                 return false;
749         }
750
751         /* NOTE: frame handles pretend to be the colored trim bar from an event handling
752            perspective. XXX change this ??
753         */
754
755         ItemType type;
756
757         if (item->get_data ("isleft")) {
758                 type = LeftFrameHandle;
759         } else {
760                 type = RightFrameHandle;
761         }
762
763         switch (event->type) {
764         case GDK_BUTTON_PRESS:
765         case GDK_2BUTTON_PRESS:
766         case GDK_3BUTTON_PRESS:
767                 clicked_regionview = rv;
768                 clicked_control_point = 0;
769                 clicked_axisview = &clicked_regionview->get_time_axis_view();
770                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
771                 ret = button_press_handler (item, event, type);
772                 break;
773         case GDK_BUTTON_RELEASE:
774                 ret = button_release_handler (item, event, type);
775                 break;
776         case GDK_MOTION_NOTIFY:
777                 ret = motion_handler (item, event);
778                 break;
779         case GDK_ENTER_NOTIFY:
780                 set_entered_regionview (rv);
781                 ret = enter_handler (item, event, type);
782                 break;
783
784         case GDK_LEAVE_NOTIFY:
785                 set_entered_regionview (0);
786                 ret = leave_handler (item, event, type);
787                 break;
788
789         default:
790                 break;
791         }
792
793         return ret;
794 }
795
796
797 bool
798 Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
799 {
800         bool ret = false;
801
802         if (!rv->sensitive()) {
803                 return false;
804         }
805
806         switch (event->type) {
807         case GDK_BUTTON_PRESS:
808         case GDK_2BUTTON_PRESS:
809         case GDK_3BUTTON_PRESS:
810                 clicked_regionview = rv;
811                 clicked_control_point = 0;
812                 clicked_axisview = &clicked_regionview->get_time_axis_view();
813                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
814                 ret = button_press_handler (item, event, RegionViewNameHighlight);
815                 break;
816         case GDK_BUTTON_RELEASE:
817                 ret = button_release_handler (item, event, RegionViewNameHighlight);
818                 break;
819         case GDK_MOTION_NOTIFY:
820                 motion_handler (item, event);
821                 ret = true; // force this to avoid progagating the event into the regionview
822                 break;
823         case GDK_ENTER_NOTIFY:
824                 set_entered_regionview (rv);
825                 ret = enter_handler (item, event, RegionViewNameHighlight);
826                 break;
827
828         case GDK_LEAVE_NOTIFY:
829                 set_entered_regionview (0);
830                 ret = leave_handler (item, event, RegionViewNameHighlight);
831                 break;
832
833         default:
834                 break;
835         }
836
837         return ret;
838 }
839
840 bool
841 Editor::canvas_region_view_name_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
842 {
843         bool ret = false;
844
845         if (!rv->sensitive()) {
846                 return false;
847         }
848
849         switch (event->type) {
850         case GDK_BUTTON_PRESS:
851         case GDK_2BUTTON_PRESS:
852         case GDK_3BUTTON_PRESS:
853                 clicked_regionview = rv;
854                 clicked_control_point = 0;
855                 clicked_axisview = &clicked_regionview->get_time_axis_view();
856                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
857                 ret = button_press_handler (item, event, RegionViewName);
858                 break;
859         case GDK_BUTTON_RELEASE:
860                 ret = button_release_handler (item, event, RegionViewName);
861                 break;
862         case GDK_MOTION_NOTIFY:
863                 ret = motion_handler (item, event);
864                 break;
865         case GDK_ENTER_NOTIFY:
866                 set_entered_regionview (rv);
867                 ret = enter_handler (item, event, RegionViewName);
868                 break;
869
870         case GDK_LEAVE_NOTIFY:
871                 set_entered_regionview (0);
872                 ret = leave_handler (item, event, RegionViewName);
873                 break;
874
875         default:
876                 break;
877         }
878
879         return ret;
880 }
881
882 bool
883 Editor::canvas_feature_line_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView*)
884 {
885         bool ret = false;
886
887         switch (event->type) {
888         case GDK_BUTTON_PRESS:
889         case GDK_2BUTTON_PRESS:
890         case GDK_3BUTTON_PRESS:
891                 clicked_regionview = 0;
892                 clicked_control_point = 0;
893                 clicked_axisview = 0;
894                 clicked_routeview = 0; //dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
895                 ret = button_press_handler (item, event, FeatureLineItem);
896                 break;
897
898         case GDK_BUTTON_RELEASE:
899                 ret = button_release_handler (item, event, FeatureLineItem);
900                 break;
901
902         case GDK_MOTION_NOTIFY:
903                 ret = motion_handler (item, event);
904                 break;
905
906         case GDK_ENTER_NOTIFY:
907                 ret = enter_handler (item, event, FeatureLineItem);
908                 break;
909
910         case GDK_LEAVE_NOTIFY:
911                 ret = leave_handler (item, event, FeatureLineItem);
912                 break;
913
914         default:
915                 break;
916         }
917
918         return ret;
919 }
920
921 bool
922 Editor::canvas_marker_event (GdkEvent *event, ArdourCanvas::Item* item, Marker* /*marker*/)
923 {
924         return typed_event (item, event, MarkerItem);
925 }
926
927 bool
928 Editor::canvas_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
929 {
930         return typed_event (item, event, MarkerBarItem);
931 }
932
933 bool
934 Editor::canvas_range_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
935 {
936         return typed_event (item, event, RangeMarkerBarItem);
937 }
938
939 bool
940 Editor::canvas_transport_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
941 {
942         return typed_event (item, event, TransportMarkerBarItem);
943 }
944
945 bool
946 Editor::canvas_cd_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
947 {
948         return typed_event (item, event, CdMarkerBarItem);
949 }
950
951 #ifdef WITH_VIDEOTIMELINE
952 bool
953 Editor::canvas_videotl_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
954 {
955         return typed_event (item, event, VideoBarItem);
956 }
957 #endif
958
959 bool
960 Editor::canvas_tempo_marker_event (GdkEvent *event, ArdourCanvas::Item* item, TempoMarker* /*marker*/)
961 {
962         return typed_event (item, event, TempoMarkerItem);
963 }
964
965 bool
966 Editor::canvas_meter_marker_event (GdkEvent *event, ArdourCanvas::Item* item, MeterMarker* /*marker*/)
967 {
968         return typed_event (item, event, MeterMarkerItem);
969 }
970
971 bool
972 Editor::canvas_tempo_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
973 {
974         return typed_event (item, event, TempoBarItem);
975 }
976
977 bool
978 Editor::canvas_meter_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
979 {
980         return typed_event (item, event, MeterBarItem);
981 }
982
983 bool
984 Editor::canvas_playhead_cursor_event (GdkEvent *event, ArdourCanvas::Item* item)
985 {
986         return typed_event (item, event, PlayheadCursorItem);
987 }
988
989 bool
990 Editor::canvas_zoom_rect_event (GdkEvent *event, ArdourCanvas::Item* item)
991 {
992         return typed_event (item, event, NoItem);
993 }
994
995 bool
996 Editor::canvas_note_event (GdkEvent *event, ArdourCanvas::Item* item)
997 {
998         if (!internal_editing()) {
999                 return false;
1000         }
1001
1002         return typed_event (item, event, NoteItem);
1003 }
1004
1005 bool
1006 Editor::track_canvas_drag_motion (Glib::RefPtr<Gdk::DragContext> const& context, int x, int y, guint time)
1007 {
1008         ArdourCanvas::Coord wx;
1009         ArdourCanvas::Coord wy;
1010         boost::shared_ptr<Region> region;
1011         boost::shared_ptr<Region> region_copy;
1012         RouteTimeAxisView* rtav;
1013         GdkEvent event;
1014         double px;
1015         double py;
1016
1017         string target = _track_canvas->drag_dest_find_target (context, _track_canvas->drag_dest_get_target_list());
1018
1019         if (target.empty()) {
1020                 return false;
1021         }
1022
1023         _track_canvas_viewport->window_to_canvas (x, y, wx, wy);
1024
1025         event.type = GDK_MOTION_NOTIFY;
1026         event.button.x = wx;
1027         event.button.y = wy;
1028         /* assume we're dragging with button 1 */
1029         event.motion.state = Gdk::BUTTON1_MASK;
1030
1031         (void) event_frame (&event, &px, &py);
1032
1033         std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py);
1034         bool can_drop = false;
1035         
1036         if (tv.first != 0) {
1037
1038                 /* over a time axis view of some kind */
1039
1040                 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1041                 
1042                 if (rtav != 0 && rtav->is_track ()) {
1043                         /* over a track, not a bus */
1044                         can_drop = true;
1045                 }
1046                         
1047
1048         } else {
1049                 /* not over a time axis view, so drop is possible */
1050                 can_drop = true;
1051         }
1052
1053         if (can_drop) {
1054                 region = _regions->get_dragged_region ();
1055                 
1056                 if (region) {
1057                         
1058                         if ((boost::dynamic_pointer_cast<AudioRegion> (region) != 0 &&
1059                              dynamic_cast<AudioTimeAxisView*> (tv.first) != 0) ||
1060                             (boost::dynamic_pointer_cast<MidiRegion> (region) != 0 &&
1061                              dynamic_cast<MidiTimeAxisView*> (tv.first) != 0)) {
1062                                 
1063                                 /* audio to audio 
1064                                    OR 
1065                                    midi to midi
1066                                 */
1067                                 
1068                                 context->drag_status (context->get_suggested_action(), time);
1069                                 return true;
1070                         }
1071                 } else {
1072                         /* DND originating from outside ardour
1073                          *
1074                          * TODO: check if file is audio/midi, allow drops on same track-type only,
1075                          * currently: if audio is dropped on a midi-track, it is only added to the region-list
1076                          */
1077                         if (Profile->get_sae() || Config->get_only_copy_imported_files()) {
1078                                 context->drag_status(Gdk::ACTION_COPY, time);
1079                         } else {
1080                                 if ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY) {
1081                                         context->drag_status(Gdk::ACTION_COPY, time);
1082                                 } else {
1083                                         context->drag_status(Gdk::ACTION_LINK, time);
1084                                 }
1085                         }
1086                         return true;
1087                 }
1088         }
1089
1090         /* no drop here */
1091         context->drag_status (Gdk::DragAction (0), time);
1092         return false;
1093 }
1094
1095 void
1096 Editor::drop_regions (const Glib::RefPtr<Gdk::DragContext>& /*context*/,
1097                       int x, int y,
1098                       const SelectionData& /*data*/,
1099                       guint /*info*/, guint /*time*/)
1100 {
1101         double wx;
1102         double wy;
1103         boost::shared_ptr<Region> region;
1104         boost::shared_ptr<Region> region_copy;
1105         RouteTimeAxisView* rtav;
1106         GdkEvent event;
1107         double px;
1108         double py;
1109
1110         _track_canvas_viewport->window_to_canvas (x, y, wx, wy);
1111
1112         event.type = GDK_MOTION_NOTIFY;
1113         event.button.x = wx;
1114         event.button.y = wy;
1115         /* assume we're dragging with button 1 */
1116         event.motion.state = Gdk::BUTTON1_MASK;
1117
1118         framepos_t const pos = event_frame (&event, &px, &py);
1119
1120         std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py);
1121
1122         if (tv.first != 0) {
1123
1124                 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1125                 
1126                 if (rtav != 0 && rtav->is_track ()) {
1127
1128                         boost::shared_ptr<Region> region = _regions->get_dragged_region ();
1129                         
1130                         if (region) {
1131
1132                                 region_copy = RegionFactory::create (region, true);
1133         
1134
1135                                 if ((boost::dynamic_pointer_cast<AudioRegion> (region_copy) != 0 &&
1136                                     dynamic_cast<AudioTimeAxisView*> (tv.first) != 0) ||
1137                                     (boost::dynamic_pointer_cast<MidiRegion> (region_copy) != 0 &&
1138                                      dynamic_cast<MidiTimeAxisView*> (tv.first) != 0)) {
1139
1140                                         /* audio to audio 
1141                                            OR 
1142                                            midi to midi
1143                                         */
1144
1145
1146                                         _drags->set (new RegionInsertDrag (this, region_copy, rtav, pos), &event);
1147                                         _drags->end_grab (0);
1148                                 }
1149                         }
1150                 }
1151         }
1152 }
1153
1154 bool
1155 Editor::key_press_handler (ArdourCanvas::Item*, GdkEvent*, ItemType)
1156 {
1157         return false;
1158 }
1159
1160 bool
1161 Editor::key_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType type)
1162 {
1163
1164         bool handled = false;
1165
1166         switch (type) {
1167         case TempoMarkerItem:
1168                 switch (event->key.keyval) {
1169                 case GDK_Delete:
1170                         remove_tempo_marker (item);
1171                         handled = true;
1172                         break;
1173                 default:
1174                         break;
1175                 }
1176                 break;
1177
1178         case MeterMarkerItem:
1179                 switch (event->key.keyval) {
1180                 case GDK_Delete:
1181                         remove_meter_marker (item);
1182                         handled = true;
1183                         break;
1184                 default:
1185                         break;
1186                 }
1187                 break;
1188
1189         default:
1190                 break;
1191         }
1192
1193         return handled;
1194 }