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