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