notable changes to try to improve most of enter/leave handling for canvas items
[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                 set_entered_regionview (rv);
271                 ret = true;
272                 break;
273
274         case GDK_LEAVE_NOTIFY:
275                 set_entered_regionview (0);
276                 break;
277
278         default:
279                 break;
280         }
281
282         return ret;
283 }
284
285 bool
286 Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, RouteTimeAxisView *tv)
287 {
288         bool ret = FALSE;
289
290         switch (event->type) {
291         case GDK_BUTTON_PRESS:
292         case GDK_2BUTTON_PRESS:
293         case GDK_3BUTTON_PRESS:
294                 clicked_regionview = 0;
295                 clicked_control_point = 0;
296                 clicked_axisview = tv;
297                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
298                 ret = button_press_handler (item, event, StreamItem);
299                 break;
300
301         case GDK_BUTTON_RELEASE:
302                 ret = button_release_handler (item, event, StreamItem);
303                 break;
304
305         case GDK_MOTION_NOTIFY:
306                 ret = motion_handler (item, event);
307                 break;
308
309         case GDK_ENTER_NOTIFY:
310                 set_entered_track (tv);
311                 ret = true;
312                 break;
313
314         case GDK_LEAVE_NOTIFY:
315                 set_entered_track (0);
316                 break;
317
318         default:
319                 break;
320         }
321
322         return ret;
323 }
324
325 bool
326 Editor::canvas_automation_track_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationTimeAxisView *atv)
327 {
328         bool ret = false;
329
330         switch (event->type) {
331         case GDK_BUTTON_PRESS:
332         case GDK_2BUTTON_PRESS:
333         case GDK_3BUTTON_PRESS:
334                 clicked_regionview = 0;
335                 clicked_control_point = 0;
336                 clicked_axisview = atv;
337                 clicked_routeview = 0;
338                 ret = button_press_handler (item, event, AutomationTrackItem);
339                 break;
340
341         case GDK_BUTTON_RELEASE:
342                 ret = button_release_handler (item, event, AutomationTrackItem);
343                 break;
344
345         case GDK_MOTION_NOTIFY:
346                 ret = motion_handler (item, event);
347                 break;
348
349         case GDK_ENTER_NOTIFY:
350                 ret = enter_handler (item, event, AutomationTrackItem);
351                 break;
352
353         case GDK_LEAVE_NOTIFY:
354                 ret = leave_handler (item, event, AutomationTrackItem);
355                 break;
356
357         default:
358                 break;
359         }
360
361         return ret;
362 }
363
364 bool
365 Editor::canvas_start_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
366 {
367         if (!rv->sensitive()) {
368                 return false;
369         }
370
371         switch (event->type) {
372         case GDK_BUTTON_PRESS:
373                 clicked_regionview = rv;
374                 clicked_control_point = 0;
375                 clicked_axisview = &rv->get_time_axis_view();
376                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
377                 if (event->button.button == 3) {
378                         return button_press_handler (item, event, StartCrossFadeItem);
379                 }
380                 break;
381
382         case GDK_BUTTON_RELEASE:
383                 if (event->button.button == 3) {
384                         return button_release_handler (item, event, StartCrossFadeItem);
385                 }
386                 break;
387
388         default:
389                 break;
390
391         }
392
393         /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
394         /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
395         /* if we return RegionItem here then we avoid the issue until it is resolved later */
396         return typed_event (item, event, RegionItem); // StartCrossFadeItem);
397 }
398
399 bool
400 Editor::canvas_end_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
401 {
402         if (!rv->sensitive()) {
403                 return false;
404         }
405
406         switch (event->type) {
407         case GDK_BUTTON_PRESS:
408                 clicked_regionview = rv;
409                 clicked_control_point = 0;
410                 clicked_axisview = &rv->get_time_axis_view();
411                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
412                 if (event->button.button == 3) {
413                         return button_press_handler (item, event, EndCrossFadeItem);
414                 }
415                 break;
416
417         case GDK_BUTTON_RELEASE:
418                 if (event->button.button == 3) {
419                         return button_release_handler (item, event, EndCrossFadeItem);
420                 }
421                 break;
422
423         default:
424                 break;
425
426         }
427
428         /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
429         /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
430         /* if we return RegionItem here then we avoid the issue until it is resolved later */
431         return typed_event (item, event, RegionItem); // EndCrossFadeItem);
432 }
433
434 bool
435 Editor::canvas_fade_in_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
436 {
437         /* we handle only button 3 press/release events */
438
439         if (!rv->sensitive()) {
440                 return false;
441         }
442
443         switch (event->type) {
444         case GDK_BUTTON_PRESS:
445                 clicked_regionview = rv;
446                 clicked_control_point = 0;
447                 clicked_axisview = &rv->get_time_axis_view();
448                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
449                 if (event->button.button == 3) {
450                         return button_press_handler (item, event, FadeInItem);
451                 }
452                 break;
453
454         case GDK_BUTTON_RELEASE:
455                 if (event->button.button == 3) {
456                         return button_release_handler (item, event, FadeInItem);
457                 }
458                 break;
459
460         default:
461                 break;
462
463         }
464
465         /* proxy for the regionview, except enter/leave events */
466
467         if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
468                 return true;
469         } else {
470                 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
471         }
472 }
473
474 bool
475 Editor::canvas_fade_in_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
476 {
477         bool ret = false;
478
479         if (!rv->sensitive()) {
480                 return false;
481         }
482
483         switch (event->type) {
484         case GDK_BUTTON_PRESS:
485         case GDK_2BUTTON_PRESS:
486         case GDK_3BUTTON_PRESS:
487                 clicked_regionview = rv;
488                 clicked_control_point = 0;
489                 clicked_axisview = &rv->get_time_axis_view();
490                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
491                 ret = button_press_handler (item, event, FadeInHandleItem);
492                 break;
493
494         case GDK_BUTTON_RELEASE:
495                 ret = button_release_handler (item, event, FadeInHandleItem);
496                 maybe_locate_with_edit_preroll ( rv->region()->position() );
497                 break;
498
499         case GDK_MOTION_NOTIFY:
500                 ret = motion_handler (item, event);
501                 break;
502
503         case GDK_ENTER_NOTIFY:
504                 ret = enter_handler (item, event, FadeInHandleItem);
505                 break;
506
507         case GDK_LEAVE_NOTIFY:
508                 ret = leave_handler (item, event, FadeInHandleItem);
509                 break;
510
511         default:
512                 break;
513         }
514
515         return ret;
516 }
517
518 bool
519 Editor::canvas_fade_out_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
520 {
521         /* we handle only button 3 press/release events */
522
523         if (!rv->sensitive()) {
524                 return false;
525         }
526
527         switch (event->type) {
528         case GDK_BUTTON_PRESS:
529                 clicked_regionview = rv;
530                 clicked_control_point = 0;
531                 clicked_axisview = &rv->get_time_axis_view();
532                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
533                 if (event->button.button == 3) {
534                         return button_press_handler (item, event, FadeOutItem);
535                 }
536                 break;
537
538         case GDK_BUTTON_RELEASE:
539                 if (event->button.button == 3) {
540                         return button_release_handler (item, event, FadeOutItem);
541                 }
542                 break;
543
544         default:
545                 break;
546
547         }
548
549         /* proxy for the regionview, except enter/leave events */
550
551         if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
552                 return true;
553         } else {
554                 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
555         }
556 }
557
558 bool
559 Editor::canvas_fade_out_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
560 {
561         bool ret = false;
562
563         if (!rv->sensitive()) {
564                 return false;
565         }
566
567         switch (event->type) {
568         case GDK_BUTTON_PRESS:
569         case GDK_2BUTTON_PRESS:
570         case GDK_3BUTTON_PRESS:
571                 clicked_regionview = rv;
572                 clicked_control_point = 0;
573                 clicked_axisview = &rv->get_time_axis_view();
574                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
575                 ret = button_press_handler (item, event, FadeOutHandleItem);
576                 break;
577
578         case GDK_BUTTON_RELEASE:
579                 ret = button_release_handler (item, event, FadeOutHandleItem);
580                 maybe_locate_with_edit_preroll ( rv->region()->last_frame() - rv->get_fade_out_shape_width() );
581                 break;
582
583         case GDK_MOTION_NOTIFY:
584                 ret = motion_handler (item, event);
585                 break;
586
587         case GDK_ENTER_NOTIFY:
588                 ret = enter_handler (item, event, FadeOutHandleItem);
589                 break;
590
591         case GDK_LEAVE_NOTIFY:
592                 ret = leave_handler (item, event, FadeOutHandleItem);
593                 break;
594
595         default:
596                 break;
597         }
598
599         return ret;
600 }
601
602 struct DescendingRegionLayerSorter {
603     bool operator()(boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
604             return a->layer() > b->layer();
605     }
606 };
607
608 bool
609 Editor::canvas_control_point_event (GdkEvent *event, ArdourCanvas::Item* item, ControlPoint* cp)
610 {
611         switch (event->type) {
612         case GDK_BUTTON_PRESS:
613         case GDK_2BUTTON_PRESS:
614         case GDK_3BUTTON_PRESS:
615                 clicked_control_point = cp;
616                 clicked_axisview = &cp->line().trackview;
617                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
618                 clicked_regionview = 0;
619                 break;
620
621         case GDK_SCROLL_UP:
622                 break;
623
624         case GDK_SCROLL_DOWN:
625                 break;
626
627         default:
628                 break;
629         }
630
631         return typed_event (item, event, ControlPointItem);
632 }
633
634 bool
635 Editor::canvas_line_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationLine* al)
636 {
637         ItemType type;
638
639         if (dynamic_cast<AudioRegionGainLine*> (al) != 0) {
640                 type = GainLineItem;
641         } else {
642                 type = AutomationLineItem;
643         }
644
645         return typed_event (item, event, type);
646 }
647
648 bool
649 Editor::canvas_selection_rect_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
650 {
651         bool ret = false;
652
653         switch (event->type) {
654         case GDK_BUTTON_PRESS:
655         case GDK_2BUTTON_PRESS:
656         case GDK_3BUTTON_PRESS:
657                 clicked_selection = rect->id;
658                 ret = button_press_handler (item, event, SelectionItem);
659                 break;
660         case GDK_BUTTON_RELEASE:
661                 ret = button_release_handler (item, event, SelectionItem);
662                 break;
663         case GDK_MOTION_NOTIFY:
664                 ret = motion_handler (item, event);
665                 break;
666                 /* Don't need these at the moment. */
667         case GDK_ENTER_NOTIFY:
668                 ret = enter_handler (item, event, SelectionItem);
669                 break;
670
671         case GDK_LEAVE_NOTIFY:
672                 ret = leave_handler (item, event, SelectionItem);
673                 break;
674
675         default:
676                 break;
677         }
678
679         return ret;
680 }
681
682 bool
683 Editor::canvas_selection_start_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
684 {
685         bool ret = false;
686
687         switch (event->type) {
688         case GDK_BUTTON_PRESS:
689         case GDK_2BUTTON_PRESS:
690         case GDK_3BUTTON_PRESS:
691                 clicked_selection = rect->id;
692                 ret = button_press_handler (item, event, StartSelectionTrimItem);
693                 break;
694         case GDK_BUTTON_RELEASE:
695                 ret = button_release_handler (item, event, StartSelectionTrimItem);
696                 break;
697         case GDK_MOTION_NOTIFY:
698                 ret = motion_handler (item, event);
699                 break;
700         case GDK_ENTER_NOTIFY:
701                 ret = enter_handler (item, event, StartSelectionTrimItem);
702                 break;
703
704         case GDK_LEAVE_NOTIFY:
705                 ret = leave_handler (item, event, StartSelectionTrimItem);
706                 break;
707
708         default:
709                 break;
710         }
711
712         return ret;
713 }
714
715 bool
716 Editor::canvas_selection_end_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
717 {
718         bool ret = false;
719
720         switch (event->type) {
721         case GDK_BUTTON_PRESS:
722         case GDK_2BUTTON_PRESS:
723         case GDK_3BUTTON_PRESS:
724                 clicked_selection = rect->id;
725                 ret = button_press_handler (item, event, EndSelectionTrimItem);
726                 break;
727         case GDK_BUTTON_RELEASE:
728                 ret = button_release_handler (item, event, EndSelectionTrimItem);
729                 break;
730         case GDK_MOTION_NOTIFY:
731                 ret = motion_handler (item, event);
732                 break;
733         case GDK_ENTER_NOTIFY:
734                 ret = enter_handler (item, event, EndSelectionTrimItem);
735                 break;
736
737         case GDK_LEAVE_NOTIFY:
738                 ret = leave_handler (item, event, EndSelectionTrimItem);
739                 break;
740
741         default:
742                 break;
743         }
744
745         return ret;
746 }
747
748 bool
749 Editor::canvas_frame_handle_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
750 {
751         bool ret = false;
752
753         /* frame handles are not active when in internal edit mode, because actual notes
754            might be in the area occupied by the handle - we want them to be editable as normal.
755         */
756
757         if (internal_editing() || !rv->sensitive()) {
758                 return false;
759         }
760
761         /* NOTE: frame handles pretend to be the colored trim bar from an event handling
762            perspective. XXX change this ??
763         */
764
765         ItemType type;
766
767         if (item->get_data ("isleft")) {
768                 type = LeftFrameHandle;
769         } else {
770                 type = RightFrameHandle;
771         }
772
773         switch (event->type) {
774         case GDK_BUTTON_PRESS:
775         case GDK_2BUTTON_PRESS:
776         case GDK_3BUTTON_PRESS:
777                 clicked_regionview = rv;
778                 clicked_control_point = 0;
779                 clicked_axisview = &clicked_regionview->get_time_axis_view();
780                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
781                 ret = button_press_handler (item, event, type);
782                 break;
783         case GDK_BUTTON_RELEASE:
784                 ret = button_release_handler (item, event, type);
785                 break;
786         case GDK_MOTION_NOTIFY:
787                 ret = motion_handler (item, event);
788                 break;
789         case GDK_ENTER_NOTIFY:
790                 ret = enter_handler (item, event, type);
791                 break;
792
793         case GDK_LEAVE_NOTIFY:
794                 ret = leave_handler (item, event, type);
795                 break;
796
797         default:
798                 break;
799         }
800
801         return ret;
802 }
803
804
805 bool
806 Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
807 {
808         bool ret = false;
809
810         if (!rv->sensitive()) {
811                 return false;
812         }
813
814         switch (event->type) {
815         case GDK_BUTTON_PRESS:
816         case GDK_2BUTTON_PRESS:
817         case GDK_3BUTTON_PRESS:
818                 clicked_regionview = rv;
819                 clicked_control_point = 0;
820                 clicked_axisview = &clicked_regionview->get_time_axis_view();
821                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
822                 ret = button_press_handler (item, event, RegionViewNameHighlight);
823                 break;
824         case GDK_BUTTON_RELEASE:
825                 ret = button_release_handler (item, event, RegionViewNameHighlight);
826                 break;
827         case GDK_MOTION_NOTIFY:
828                 motion_handler (item, event);
829                 ret = true; // force this to avoid progagating the event into the regionview
830                 break;
831         case GDK_ENTER_NOTIFY:
832                 ret = enter_handler (item, event, RegionViewNameHighlight);
833                 break;
834
835         case GDK_LEAVE_NOTIFY:
836                 ret = leave_handler (item, event, RegionViewNameHighlight);
837                 break;
838
839         default:
840                 break;
841         }
842
843         return ret;
844 }
845
846 bool
847 Editor::canvas_region_view_name_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
848 {
849         bool ret = false;
850
851         if (!rv->sensitive()) {
852                 return false;
853         }
854
855         switch (event->type) {
856         case GDK_BUTTON_PRESS:
857         case GDK_2BUTTON_PRESS:
858         case GDK_3BUTTON_PRESS:
859                 clicked_regionview = rv;
860                 clicked_control_point = 0;
861                 clicked_axisview = &clicked_regionview->get_time_axis_view();
862                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
863                 ret = button_press_handler (item, event, RegionViewName);
864                 break;
865         case GDK_BUTTON_RELEASE:
866                 ret = button_release_handler (item, event, RegionViewName);
867                 break;
868         case GDK_MOTION_NOTIFY:
869                 ret = motion_handler (item, event);
870                 break;
871         case GDK_ENTER_NOTIFY:
872                 ret = enter_handler (item, event, RegionViewName);
873                 break;
874
875         case GDK_LEAVE_NOTIFY:
876                 ret = leave_handler (item, event, RegionViewName);
877                 break;
878
879         default:
880                 break;
881         }
882
883         return ret;
884 }
885
886 bool
887 Editor::canvas_feature_line_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView*)
888 {
889         bool ret = false;
890
891         switch (event->type) {
892         case GDK_BUTTON_PRESS:
893         case GDK_2BUTTON_PRESS:
894         case GDK_3BUTTON_PRESS:
895                 clicked_regionview = 0;
896                 clicked_control_point = 0;
897                 clicked_axisview = 0;
898                 clicked_routeview = 0; //dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
899                 ret = button_press_handler (item, event, FeatureLineItem);
900                 break;
901
902         case GDK_BUTTON_RELEASE:
903                 ret = button_release_handler (item, event, FeatureLineItem);
904                 break;
905
906         case GDK_MOTION_NOTIFY:
907                 ret = motion_handler (item, event);
908                 break;
909
910         case GDK_ENTER_NOTIFY:
911                 ret = enter_handler (item, event, FeatureLineItem);
912                 break;
913
914         case GDK_LEAVE_NOTIFY:
915                 ret = leave_handler (item, event, FeatureLineItem);
916                 break;
917
918         default:
919                 break;
920         }
921
922         return ret;
923 }
924
925 bool
926 Editor::canvas_marker_event (GdkEvent *event, ArdourCanvas::Item* item, Marker* /*marker*/)
927 {
928         return typed_event (item, event, MarkerItem);
929 }
930
931 bool
932 Editor::canvas_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
933 {
934         return typed_event (item, event, MarkerBarItem);
935 }
936
937 bool
938 Editor::canvas_range_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
939 {
940         return typed_event (item, event, RangeMarkerBarItem);
941 }
942
943 bool
944 Editor::canvas_transport_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
945 {
946         return typed_event (item, event, TransportMarkerBarItem);
947 }
948
949 bool
950 Editor::canvas_cd_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
951 {
952         return typed_event (item, event, CdMarkerBarItem);
953 }
954
955 bool
956 Editor::canvas_videotl_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
957 {
958         return typed_event (item, event, VideoBarItem);
959 }
960
961 bool
962 Editor::canvas_tempo_marker_event (GdkEvent *event, ArdourCanvas::Item* item, TempoMarker* /*marker*/)
963 {
964         return typed_event (item, event, TempoMarkerItem);
965 }
966
967 bool
968 Editor::canvas_meter_marker_event (GdkEvent *event, ArdourCanvas::Item* item, MeterMarker* /*marker*/)
969 {
970         return typed_event (item, event, MeterMarkerItem);
971 }
972
973 bool
974 Editor::canvas_tempo_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
975 {
976         return typed_event (item, event, TempoBarItem);
977 }
978
979 bool
980 Editor::canvas_meter_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
981 {
982         return typed_event (item, event, MeterBarItem);
983 }
984
985 bool
986 Editor::canvas_playhead_cursor_event (GdkEvent *event, ArdourCanvas::Item* item)
987 {
988         return typed_event (item, event, PlayheadCursorItem);
989 }
990
991 bool
992 Editor::canvas_zoom_rect_event (GdkEvent *event, ArdourCanvas::Item* item)
993 {
994         return typed_event (item, event, NoItem);
995 }
996
997 bool
998 Editor::canvas_note_event (GdkEvent *event, ArdourCanvas::Item* item)
999 {
1000         if (!internal_editing()) {
1001                 return false;
1002         }
1003
1004         return typed_event (item, event, NoteItem);
1005 }
1006
1007 bool
1008 Editor::track_canvas_drag_motion (Glib::RefPtr<Gdk::DragContext> const& context, int x, int y, guint time)
1009 {
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         event.type = GDK_MOTION_NOTIFY;
1024         event.button.x = x;
1025         event.button.y = y;
1026         /* assume we're dragging with button 1 */
1027         event.motion.state = Gdk::BUTTON1_MASK;
1028
1029         (void) window_event_frame (&event, &px, &py);
1030
1031         std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py);
1032         bool can_drop = false;
1033         
1034         if (tv.first != 0) {
1035
1036                 /* over a time axis view of some kind */
1037
1038                 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1039                 
1040                 if (rtav != 0 && rtav->is_track ()) {
1041                         /* over a track, not a bus */
1042                         can_drop = true;
1043                 }
1044                         
1045
1046         } else {
1047                 /* not over a time axis view, so drop is possible */
1048                 can_drop = true;
1049         }
1050
1051         if (can_drop) {
1052                 region = _regions->get_dragged_region ();
1053                 
1054                 if (region) {
1055                         
1056                         if ((boost::dynamic_pointer_cast<AudioRegion> (region) != 0 &&
1057                              dynamic_cast<AudioTimeAxisView*> (tv.first) != 0) ||
1058                             (boost::dynamic_pointer_cast<MidiRegion> (region) != 0 &&
1059                              dynamic_cast<MidiTimeAxisView*> (tv.first) != 0)) {
1060                                 
1061                                 /* audio to audio 
1062                                    OR 
1063                                    midi to midi
1064                                 */
1065                                 
1066                                 context->drag_status (context->get_suggested_action(), time);
1067                                 return true;
1068                         }
1069                 } else {
1070                         /* DND originating from outside ardour
1071                          *
1072                          * TODO: check if file is audio/midi, allow drops on same track-type only,
1073                          * currently: if audio is dropped on a midi-track, it is only added to the region-list
1074                          */
1075                         if (Profile->get_sae() || Config->get_only_copy_imported_files()) {
1076                                 context->drag_status(Gdk::ACTION_COPY, time);
1077                         } else {
1078                                 if ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY) {
1079                                         context->drag_status(Gdk::ACTION_COPY, time);
1080                                 } else {
1081                                         context->drag_status(Gdk::ACTION_LINK, time);
1082                                 }
1083                         }
1084                         return true;
1085                 }
1086         }
1087
1088         /* no drop here */
1089         context->drag_status (Gdk::DragAction (0), time);
1090         return false;
1091 }
1092
1093 void
1094 Editor::drop_regions (const Glib::RefPtr<Gdk::DragContext>& /*context*/,
1095                       int x, int y,
1096                       const SelectionData& /*data*/,
1097                       guint /*info*/, guint /*time*/)
1098 {
1099         boost::shared_ptr<Region> region;
1100         boost::shared_ptr<Region> region_copy;
1101         RouteTimeAxisView* rtav;
1102         GdkEvent event;
1103         double px;
1104         double py;
1105
1106         event.type = GDK_MOTION_NOTIFY;
1107         event.button.x = x;
1108         event.button.y = y;
1109         /* assume we're dragging with button 1 */
1110         event.motion.state = Gdk::BUTTON1_MASK;
1111
1112         framepos_t const pos = window_event_frame (&event, &px, &py);
1113
1114         std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py);
1115
1116         if (tv.first != 0) {
1117
1118                 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1119                 
1120                 if (rtav != 0 && rtav->is_track ()) {
1121
1122                         boost::shared_ptr<Region> region = _regions->get_dragged_region ();
1123                         
1124                         if (region) {
1125
1126                                 region_copy = RegionFactory::create (region, true);
1127         
1128
1129                                 if ((boost::dynamic_pointer_cast<AudioRegion> (region_copy) != 0 &&
1130                                     dynamic_cast<AudioTimeAxisView*> (tv.first) != 0) ||
1131                                     (boost::dynamic_pointer_cast<MidiRegion> (region_copy) != 0 &&
1132                                      dynamic_cast<MidiTimeAxisView*> (tv.first) != 0)) {
1133
1134                                         /* audio to audio 
1135                                            OR 
1136                                            midi to midi
1137                                         */
1138
1139
1140                                         _drags->set (new RegionInsertDrag (this, region_copy, rtav, pos), &event);
1141                                         _drags->end_grab (0);
1142                                 }
1143                         }
1144                 }
1145         }
1146 }
1147
1148 bool
1149 Editor::key_press_handler (ArdourCanvas::Item*, GdkEvent*, ItemType)
1150 {
1151         return false;
1152 }
1153
1154 bool
1155 Editor::key_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType type)
1156 {
1157
1158         bool handled = false;
1159
1160         switch (type) {
1161         case TempoMarkerItem:
1162                 switch (event->key.keyval) {
1163                 case GDK_Delete:
1164                         remove_tempo_marker (item);
1165                         handled = true;
1166                         break;
1167                 default:
1168                         break;
1169                 }
1170                 break;
1171
1172         case MeterMarkerItem:
1173                 switch (event->key.keyval) {
1174                 case GDK_Delete:
1175                         remove_meter_marker (item);
1176                         handled = true;
1177                         break;
1178                 default:
1179                         break;
1180                 }
1181                 break;
1182
1183         default:
1184                 break;
1185         }
1186
1187         return handled;
1188 }