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