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