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