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