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