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