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         /* 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_track (&rv->get_time_axis_view ());
271                 set_entered_regionview (rv);
272                 break;
273
274         case GDK_LEAVE_NOTIFY:
275                 set_entered_track (0);
276                 set_entered_regionview (0);
277                 break;
278
279         default:
280                 break;
281         }
282
283         return ret;
284 }
285
286 bool
287 Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, RouteTimeAxisView *tv)
288 {
289         bool ret = FALSE;
290
291         switch (event->type) {
292         case GDK_BUTTON_PRESS:
293         case GDK_2BUTTON_PRESS:
294         case GDK_3BUTTON_PRESS:
295                 clicked_regionview = 0;
296                 clicked_control_point = 0;
297                 clicked_axisview = tv;
298                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
299                 ret = button_press_handler (item, event, StreamItem);
300                 break;
301
302         case GDK_BUTTON_RELEASE:
303                 ret = button_release_handler (item, event, StreamItem);
304                 break;
305
306         case GDK_MOTION_NOTIFY:
307                 ret = motion_handler (item, event);
308                 break;
309
310         case GDK_ENTER_NOTIFY:
311                 set_entered_track (tv);
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 */
466
467         return canvas_region_view_event (event, rv->get_canvas_group(), rv);
468 }
469
470 bool
471 Editor::canvas_fade_in_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
472 {
473         bool ret = false;
474
475         if (!rv->sensitive()) {
476                 return false;
477         }
478
479         switch (event->type) {
480         case GDK_BUTTON_PRESS:
481         case GDK_2BUTTON_PRESS:
482         case GDK_3BUTTON_PRESS:
483                 clicked_regionview = rv;
484                 clicked_control_point = 0;
485                 clicked_axisview = &rv->get_time_axis_view();
486                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
487                 ret = button_press_handler (item, event, FadeInHandleItem);
488                 break;
489
490         case GDK_BUTTON_RELEASE:
491                 ret = button_release_handler (item, event, FadeInHandleItem);
492                 maybe_locate_with_edit_preroll ( rv->region()->position() );
493                 break;
494
495         case GDK_MOTION_NOTIFY:
496                 ret = motion_handler (item, event);
497                 break;
498
499         case GDK_ENTER_NOTIFY:
500                 set_entered_regionview (rv);
501                 ret = enter_handler (item, event, FadeInHandleItem);
502                 break;
503
504         case GDK_LEAVE_NOTIFY:
505                 set_entered_regionview (0);
506                 ret = leave_handler (item, event, FadeInHandleItem);
507                 break;
508
509         default:
510                 break;
511         }
512
513         return ret;
514 }
515
516 bool
517 Editor::canvas_fade_out_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
518 {
519         /* we handle only button 3 press/release events */
520
521         if (!rv->sensitive()) {
522                 return false;
523         }
524
525         switch (event->type) {
526         case GDK_BUTTON_PRESS:
527                 clicked_regionview = rv;
528                 clicked_control_point = 0;
529                 clicked_axisview = &rv->get_time_axis_view();
530                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
531                 if (event->button.button == 3) {
532                         return button_press_handler (item, event, FadeOutItem);
533                 }
534                 break;
535
536         case GDK_BUTTON_RELEASE:
537                 if (event->button.button == 3) {
538                         return button_release_handler (item, event, FadeOutItem);
539                 }
540                 break;
541
542         default:
543                 break;
544
545         }
546
547         /* proxy for the regionview */
548
549         return canvas_region_view_event (event, rv->get_canvas_group(), rv);
550 }
551
552 bool
553 Editor::canvas_fade_out_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
554 {
555         bool ret = false;
556
557         if (!rv->sensitive()) {
558                 return false;
559         }
560
561         switch (event->type) {
562         case GDK_BUTTON_PRESS:
563         case GDK_2BUTTON_PRESS:
564         case GDK_3BUTTON_PRESS:
565                 clicked_regionview = rv;
566                 clicked_control_point = 0;
567                 clicked_axisview = &rv->get_time_axis_view();
568                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
569                 ret = button_press_handler (item, event, FadeOutHandleItem);
570                 break;
571
572         case GDK_BUTTON_RELEASE:
573                 ret = button_release_handler (item, event, FadeOutHandleItem);
574                 maybe_locate_with_edit_preroll ( rv->region()->last_frame() - rv->get_fade_out_shape_width() );
575                 break;
576
577         case GDK_MOTION_NOTIFY:
578                 ret = motion_handler (item, event);
579                 break;
580
581         case GDK_ENTER_NOTIFY:
582                 set_entered_regionview (rv);
583                 ret = enter_handler (item, event, FadeOutHandleItem);
584                 break;
585
586         case GDK_LEAVE_NOTIFY:
587                 set_entered_regionview (0);
588                 ret = leave_handler (item, event, FadeOutHandleItem);
589                 break;
590
591         default:
592                 break;
593         }
594
595         return ret;
596 }
597
598 struct DescendingRegionLayerSorter {
599     bool operator()(boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
600             return a->layer() > b->layer();
601     }
602 };
603
604 bool
605 Editor::canvas_control_point_event (GdkEvent *event, ArdourCanvas::Item* item, ControlPoint* cp)
606 {
607         switch (event->type) {
608         case GDK_BUTTON_PRESS:
609         case GDK_2BUTTON_PRESS:
610         case GDK_3BUTTON_PRESS:
611                 clicked_control_point = cp;
612                 clicked_axisview = &cp->line().trackview;
613                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
614                 clicked_regionview = 0;
615                 break;
616
617         case GDK_SCROLL_UP:
618                 break;
619
620         case GDK_SCROLL_DOWN:
621                 break;
622
623         default:
624                 break;
625         }
626
627         return typed_event (item, event, ControlPointItem);
628 }
629
630 bool
631 Editor::canvas_line_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationLine* al)
632 {
633         ItemType type;
634
635         if (dynamic_cast<AudioRegionGainLine*> (al) != 0) {
636                 type = GainLineItem;
637         } else {
638                 type = AutomationLineItem;
639         }
640
641         return typed_event (item, event, type);
642 }
643
644 bool
645 Editor::canvas_selection_rect_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
646 {
647         bool ret = false;
648
649         switch (event->type) {
650         case GDK_BUTTON_PRESS:
651         case GDK_2BUTTON_PRESS:
652         case GDK_3BUTTON_PRESS:
653                 clicked_selection = rect->id;
654                 ret = button_press_handler (item, event, SelectionItem);
655                 break;
656         case GDK_BUTTON_RELEASE:
657                 ret = button_release_handler (item, event, SelectionItem);
658                 break;
659         case GDK_MOTION_NOTIFY:
660                 ret = motion_handler (item, event);
661                 break;
662                 /* Don't need these at the moment. */
663         case GDK_ENTER_NOTIFY:
664                 ret = enter_handler (item, event, SelectionItem);
665                 break;
666
667         case GDK_LEAVE_NOTIFY:
668                 ret = leave_handler (item, event, SelectionItem);
669                 break;
670
671         default:
672                 break;
673         }
674
675         return ret;
676 }
677
678 bool
679 Editor::canvas_selection_start_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
680 {
681         bool ret = false;
682
683         switch (event->type) {
684         case GDK_BUTTON_PRESS:
685         case GDK_2BUTTON_PRESS:
686         case GDK_3BUTTON_PRESS:
687                 clicked_selection = rect->id;
688                 ret = button_press_handler (item, event, StartSelectionTrimItem);
689                 break;
690         case GDK_BUTTON_RELEASE:
691                 ret = button_release_handler (item, event, StartSelectionTrimItem);
692                 break;
693         case GDK_MOTION_NOTIFY:
694                 ret = motion_handler (item, event);
695                 break;
696         case GDK_ENTER_NOTIFY:
697                 ret = enter_handler (item, event, StartSelectionTrimItem);
698                 break;
699
700         case GDK_LEAVE_NOTIFY:
701                 ret = leave_handler (item, event, StartSelectionTrimItem);
702                 break;
703
704         default:
705                 break;
706         }
707
708         return ret;
709 }
710
711 bool
712 Editor::canvas_selection_end_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
713 {
714         bool ret = false;
715
716         switch (event->type) {
717         case GDK_BUTTON_PRESS:
718         case GDK_2BUTTON_PRESS:
719         case GDK_3BUTTON_PRESS:
720                 clicked_selection = rect->id;
721                 ret = button_press_handler (item, event, EndSelectionTrimItem);
722                 break;
723         case GDK_BUTTON_RELEASE:
724                 ret = button_release_handler (item, event, EndSelectionTrimItem);
725                 break;
726         case GDK_MOTION_NOTIFY:
727                 ret = motion_handler (item, event);
728                 break;
729         case GDK_ENTER_NOTIFY:
730                 ret = enter_handler (item, event, EndSelectionTrimItem);
731                 break;
732
733         case GDK_LEAVE_NOTIFY:
734                 ret = leave_handler (item, event, EndSelectionTrimItem);
735                 break;
736
737         default:
738                 break;
739         }
740
741         return ret;
742 }
743
744 bool
745 Editor::canvas_frame_handle_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
746 {
747         bool ret = false;
748
749         /* frame handles are not active when in internal edit mode, because actual notes
750            might be in the area occupied by the handle - we want them to be editable as normal.
751         */
752
753         if (internal_editing() || !rv->sensitive()) {
754                 return false;
755         }
756
757         /* NOTE: frame handles pretend to be the colored trim bar from an event handling
758            perspective. XXX change this ??
759         */
760
761         ItemType type;
762
763         if (item->get_data ("isleft")) {
764                 type = LeftFrameHandle;
765         } else {
766                 type = RightFrameHandle;
767         }
768
769         switch (event->type) {
770         case GDK_BUTTON_PRESS:
771         case GDK_2BUTTON_PRESS:
772         case GDK_3BUTTON_PRESS:
773                 clicked_regionview = rv;
774                 clicked_control_point = 0;
775                 clicked_axisview = &clicked_regionview->get_time_axis_view();
776                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
777                 ret = button_press_handler (item, event, type);
778                 break;
779         case GDK_BUTTON_RELEASE:
780                 ret = button_release_handler (item, event, type);
781                 break;
782         case GDK_MOTION_NOTIFY:
783                 ret = motion_handler (item, event);
784                 break;
785         case GDK_ENTER_NOTIFY:
786                 set_entered_regionview (rv);
787                 ret = enter_handler (item, event, type);
788                 break;
789
790         case GDK_LEAVE_NOTIFY:
791                 set_entered_regionview (0);
792                 ret = leave_handler (item, event, type);
793                 break;
794
795         default:
796                 break;
797         }
798
799         return ret;
800 }
801
802
803 bool
804 Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
805 {
806         bool ret = false;
807
808         if (!rv->sensitive()) {
809                 return false;
810         }
811
812         switch (event->type) {
813         case GDK_BUTTON_PRESS:
814         case GDK_2BUTTON_PRESS:
815         case GDK_3BUTTON_PRESS:
816                 clicked_regionview = rv;
817                 clicked_control_point = 0;
818                 clicked_axisview = &clicked_regionview->get_time_axis_view();
819                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
820                 ret = button_press_handler (item, event, RegionViewNameHighlight);
821                 break;
822         case GDK_BUTTON_RELEASE:
823                 ret = button_release_handler (item, event, RegionViewNameHighlight);
824                 break;
825         case GDK_MOTION_NOTIFY:
826                 motion_handler (item, event);
827                 ret = true; // force this to avoid progagating the event into the regionview
828                 break;
829         case GDK_ENTER_NOTIFY:
830                 set_entered_regionview (rv);
831                 ret = enter_handler (item, event, RegionViewNameHighlight);
832                 break;
833
834         case GDK_LEAVE_NOTIFY:
835                 set_entered_regionview (0);
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                 set_entered_regionview (rv);
873                 ret = enter_handler (item, event, RegionViewName);
874                 break;
875
876         case GDK_LEAVE_NOTIFY:
877                 set_entered_regionview (0);
878                 ret = leave_handler (item, event, RegionViewName);
879                 break;
880
881         default:
882                 break;
883         }
884
885         return ret;
886 }
887
888 bool
889 Editor::canvas_feature_line_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView*)
890 {
891         bool ret = false;
892
893         switch (event->type) {
894         case GDK_BUTTON_PRESS:
895         case GDK_2BUTTON_PRESS:
896         case GDK_3BUTTON_PRESS:
897                 clicked_regionview = 0;
898                 clicked_control_point = 0;
899                 clicked_axisview = 0;
900                 clicked_routeview = 0; //dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
901                 ret = button_press_handler (item, event, FeatureLineItem);
902                 break;
903
904         case GDK_BUTTON_RELEASE:
905                 ret = button_release_handler (item, event, FeatureLineItem);
906                 break;
907
908         case GDK_MOTION_NOTIFY:
909                 ret = motion_handler (item, event);
910                 break;
911
912         case GDK_ENTER_NOTIFY:
913                 ret = enter_handler (item, event, FeatureLineItem);
914                 break;
915
916         case GDK_LEAVE_NOTIFY:
917                 ret = leave_handler (item, event, FeatureLineItem);
918                 break;
919
920         default:
921                 break;
922         }
923
924         return ret;
925 }
926
927 bool
928 Editor::canvas_marker_event (GdkEvent *event, ArdourCanvas::Item* item, Marker* /*marker*/)
929 {
930         return typed_event (item, event, MarkerItem);
931 }
932
933 bool
934 Editor::canvas_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
935 {
936         return typed_event (item, event, MarkerBarItem);
937 }
938
939 bool
940 Editor::canvas_range_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
941 {
942         return typed_event (item, event, RangeMarkerBarItem);
943 }
944
945 bool
946 Editor::canvas_transport_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
947 {
948         return typed_event (item, event, TransportMarkerBarItem);
949 }
950
951 bool
952 Editor::canvas_cd_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
953 {
954         return typed_event (item, event, CdMarkerBarItem);
955 }
956
957 bool
958 Editor::canvas_videotl_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
959 {
960         return typed_event (item, event, VideoBarItem);
961 }
962
963 bool
964 Editor::canvas_tempo_marker_event (GdkEvent *event, ArdourCanvas::Item* item, TempoMarker* /*marker*/)
965 {
966         return typed_event (item, event, TempoMarkerItem);
967 }
968
969 bool
970 Editor::canvas_meter_marker_event (GdkEvent *event, ArdourCanvas::Item* item, MeterMarker* /*marker*/)
971 {
972         return typed_event (item, event, MeterMarkerItem);
973 }
974
975 bool
976 Editor::canvas_tempo_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
977 {
978         return typed_event (item, event, TempoBarItem);
979 }
980
981 bool
982 Editor::canvas_meter_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
983 {
984         return typed_event (item, event, MeterBarItem);
985 }
986
987 bool
988 Editor::canvas_playhead_cursor_event (GdkEvent *event, ArdourCanvas::Item* item)
989 {
990         return typed_event (item, event, PlayheadCursorItem);
991 }
992
993 bool
994 Editor::canvas_zoom_rect_event (GdkEvent *event, ArdourCanvas::Item* item)
995 {
996         return typed_event (item, event, NoItem);
997 }
998
999 bool
1000 Editor::canvas_note_event (GdkEvent *event, ArdourCanvas::Item* item)
1001 {
1002         if (!internal_editing()) {
1003                 return false;
1004         }
1005
1006         return typed_event (item, event, NoteItem);
1007 }
1008
1009 bool
1010 Editor::track_canvas_drag_motion (Glib::RefPtr<Gdk::DragContext> const& context, int x, int y, guint time)
1011 {
1012         boost::shared_ptr<Region> region;
1013         boost::shared_ptr<Region> region_copy;
1014         RouteTimeAxisView* rtav;
1015         GdkEvent event;
1016         double px;
1017         double py;
1018
1019         string target = _track_canvas->drag_dest_find_target (context, _track_canvas->drag_dest_get_target_list());
1020
1021         if (target.empty()) {
1022                 return false;
1023         }
1024
1025         event.type = GDK_MOTION_NOTIFY;
1026         event.button.x = x;
1027         event.button.y = y;
1028         /* assume we're dragging with button 1 */
1029         event.motion.state = Gdk::BUTTON1_MASK;
1030
1031         (void) window_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         boost::shared_ptr<Region> region;
1102         boost::shared_ptr<Region> region_copy;
1103         RouteTimeAxisView* rtav;
1104         GdkEvent event;
1105         double px;
1106         double py;
1107
1108         event.type = GDK_MOTION_NOTIFY;
1109         event.button.x = x;
1110         event.button.y = y;
1111         /* assume we're dragging with button 1 */
1112         event.motion.state = Gdk::BUTTON1_MASK;
1113
1114         framepos_t const pos = window_event_frame (&event, &px, &py);
1115
1116         std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py);
1117
1118         if (tv.first != 0) {
1119
1120                 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1121                 
1122                 if (rtav != 0 && rtav->is_track ()) {
1123
1124                         boost::shared_ptr<Region> region = _regions->get_dragged_region ();
1125                         
1126                         if (region) {
1127
1128                                 region_copy = RegionFactory::create (region, true);
1129         
1130
1131                                 if ((boost::dynamic_pointer_cast<AudioRegion> (region_copy) != 0 &&
1132                                     dynamic_cast<AudioTimeAxisView*> (tv.first) != 0) ||
1133                                     (boost::dynamic_pointer_cast<MidiRegion> (region_copy) != 0 &&
1134                                      dynamic_cast<MidiTimeAxisView*> (tv.first) != 0)) {
1135
1136                                         /* audio to audio 
1137                                            OR 
1138                                            midi to midi
1139                                         */
1140
1141
1142                                         _drags->set (new RegionInsertDrag (this, region_copy, rtav, pos), &event);
1143                                         _drags->end_grab (0);
1144                                 }
1145                         }
1146                 }
1147         }
1148 }
1149
1150 bool
1151 Editor::key_press_handler (ArdourCanvas::Item*, GdkEvent*, ItemType)
1152 {
1153         return false;
1154 }
1155
1156 bool
1157 Editor::key_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType type)
1158 {
1159
1160         bool handled = false;
1161
1162         switch (type) {
1163         case TempoMarkerItem:
1164                 switch (event->key.keyval) {
1165                 case GDK_Delete:
1166                         remove_tempo_marker (item);
1167                         handled = true;
1168                         break;
1169                 default:
1170                         break;
1171                 }
1172                 break;
1173
1174         case MeterMarkerItem:
1175                 switch (event->key.keyval) {
1176                 case GDK_Delete:
1177                         remove_meter_marker (item);
1178                         handled = true;
1179                         break;
1180                 default:
1181                         break;
1182                 }
1183                 break;
1184
1185         default:
1186                 break;
1187         }
1188
1189         return handled;
1190 }