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