Fix setup of gain envelope visible menu item.
[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/audioplaylist.h"
28 #include "ardour/audioregion.h"
29 #include "ardour/region_factory.h"
30 #include "ardour/midi_region.h"
31
32 #include "editor.h"
33 #include "keyboard.h"
34 #include "public_editor.h"
35 #include "audio_region_view.h"
36 #include "audio_streamview.h"
37 #include "canvas-noevent-text.h"
38 #include "crossfade_view.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 "canvas_impl.h"
46 #include "simplerect.h"
47 #include "editor_drag.h"
48 #include "midi_time_axis.h"
49 #include "editor_regions.h"
50 #include "verbose_cursor.h"
51
52 #include "i18n.h"
53
54 using namespace std;
55 using namespace ARDOUR;
56 using namespace PBD;
57 using namespace Gtk;
58 using namespace ArdourCanvas;
59
60 using Gtkmm2ext::Keyboard;
61
62 bool
63 Editor::track_canvas_scroll (GdkEventScroll* ev)
64 {
65         framepos_t xdelta;
66         int direction = ev->direction;
67
68   retry:
69         switch (direction) {
70         case GDK_SCROLL_UP:
71                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
72                         temporal_zoom_step (false);
73                         return true;
74                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::SecondaryModifier)) {
75                         direction = GDK_SCROLL_LEFT;
76                         goto retry;
77                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
78                         if (!current_stepping_trackview) {
79                                 step_timeout = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Editor::track_height_step_timeout), 500);
80                                 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (ev->y + vertical_adjustment.get_value() - canvas_timebars_vsize);
81                                 current_stepping_trackview = p.first;
82                                 if (!current_stepping_trackview) {
83                                         return false;
84                                 }
85                         }
86                         last_track_height_step_timestamp = get_microseconds();
87                         current_stepping_trackview->step_height (false);
88                         return true;
89                 } else {
90                         scroll_tracks_up_line ();
91                         return true;
92                 }
93                 break;
94
95         case GDK_SCROLL_DOWN:
96                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
97                         temporal_zoom_step (true);
98                         return true;
99                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::SecondaryModifier)) {
100                         direction = GDK_SCROLL_RIGHT;
101                         goto retry;
102                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
103                         if (!current_stepping_trackview) {
104                                 step_timeout = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Editor::track_height_step_timeout), 500);
105                                 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (ev->y + vertical_adjustment.get_value() - canvas_timebars_vsize);
106                                 current_stepping_trackview = p.first;
107                                 if (!current_stepping_trackview) {
108                                         return false;
109                                 }
110                         }
111                         last_track_height_step_timestamp = get_microseconds();
112                         current_stepping_trackview->step_height (true);
113                         return true;
114                 } else {
115                         scroll_tracks_down_line ();
116                         return true;
117                 }
118                 break;
119
120         case GDK_SCROLL_LEFT:
121                 xdelta = (current_page_frames() / 8);
122                 if (leftmost_frame > xdelta) {
123                         reset_x_origin (leftmost_frame - xdelta);
124                 } else {
125                         reset_x_origin (0);
126                 }
127                 break;
128
129         case GDK_SCROLL_RIGHT:
130                 xdelta = (current_page_frames() / 8);
131                 if (max_framepos - xdelta > leftmost_frame) {
132                         reset_x_origin (leftmost_frame + xdelta);
133                 } else {
134                         reset_x_origin (max_framepos - current_page_frames());
135                 }
136                 break;
137
138         default:
139                 /* what? */
140                 break;
141         }
142
143         return false;
144 }
145
146 bool
147 Editor::track_canvas_scroll_event (GdkEventScroll *event)
148 {
149         track_canvas->grab_focus();
150         return track_canvas_scroll (event);
151 }
152
153 bool
154 Editor::track_canvas_button_press_event (GdkEventButton */*event*/)
155 {
156         selection->clear ();
157         track_canvas->grab_focus();
158         return false;
159 }
160
161 bool
162 Editor::track_canvas_button_release_event (GdkEventButton *event)
163 {
164         if (_drags->active ()) {
165                 _drags->end_grab ((GdkEvent*) event);
166         }
167         return false;
168 }
169
170 bool
171 Editor::track_canvas_motion_notify_event (GdkEventMotion */*event*/)
172 {
173         int x, y;
174         /* keep those motion events coming */
175         track_canvas->get_pointer (x, y);
176         return false;
177 }
178
179 bool
180 Editor::track_canvas_motion (GdkEvent *ev)
181 {
182         if (_verbose_cursor->visible ()) {
183                 _verbose_cursor->set_position (ev->motion.x + 10, ev->motion.y + 10);
184         }
185
186         return false;
187 }
188
189 bool
190 Editor::typed_event (ArdourCanvas::Item* item, GdkEvent *event, ItemType type)
191 {
192         gint ret = FALSE;
193
194         switch (event->type) {
195         case GDK_BUTTON_PRESS:
196         case GDK_2BUTTON_PRESS:
197         case GDK_3BUTTON_PRESS:
198                 ret = button_press_handler (item, event, type);
199                 break;
200         case GDK_BUTTON_RELEASE:
201                 ret = button_release_handler (item, event, type);
202                 break;
203         case GDK_MOTION_NOTIFY:
204                 ret = motion_handler (item, event);
205                 break;
206
207         case GDK_ENTER_NOTIFY:
208                 ret = enter_handler (item, event, type);
209                 break;
210
211         case GDK_LEAVE_NOTIFY:
212                 ret = leave_handler (item, event, type);
213                 break;
214
215         case GDK_KEY_PRESS:
216                 ret = key_press_handler (item, event, type);
217                 break;
218
219         case GDK_KEY_RELEASE:
220                 ret = key_release_handler (item, event, type);
221                 break;
222
223         default:
224                 break;
225         }
226         return ret;
227 }
228
229 bool
230 Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView *rv)
231 {
232         bool ret = false;
233
234         if (!rv->sensitive ()) {
235                 return false;
236         }
237
238         switch (event->type) {
239         case GDK_BUTTON_PRESS:
240         case GDK_2BUTTON_PRESS:
241         case GDK_3BUTTON_PRESS:
242                 clicked_regionview = rv;
243                 clicked_control_point = 0;
244                 clicked_axisview = &rv->get_time_axis_view();
245                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
246                 ret = button_press_handler (item, event, RegionItem);
247                 break;
248
249         case GDK_BUTTON_RELEASE:
250                 ret = button_release_handler (item, event, RegionItem);
251                 break;
252
253         case GDK_MOTION_NOTIFY:
254                 ret = motion_handler (item, event);
255                 break;
256
257         case GDK_ENTER_NOTIFY:
258                 set_entered_track (&rv->get_time_axis_view ());
259                 set_entered_regionview (rv);
260                 break;
261
262         case GDK_LEAVE_NOTIFY:
263                 set_entered_track (0);
264                 set_entered_regionview (0);
265                 break;
266
267         default:
268                 break;
269         }
270
271         return ret;
272 }
273
274 bool
275 Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, RouteTimeAxisView *tv)
276 {
277         bool ret = FALSE;
278
279         switch (event->type) {
280         case GDK_BUTTON_PRESS:
281         case GDK_2BUTTON_PRESS:
282         case GDK_3BUTTON_PRESS:
283                 clicked_regionview = 0;
284                 clicked_control_point = 0;
285                 clicked_axisview = tv;
286                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
287                 ret = button_press_handler (item, event, StreamItem);
288                 break;
289
290         case GDK_BUTTON_RELEASE:
291                 ret = button_release_handler (item, event, StreamItem);
292                 break;
293
294         case GDK_MOTION_NOTIFY:
295                 ret = motion_handler (item, event);
296                 break;
297
298         case GDK_ENTER_NOTIFY:
299                 set_entered_track (tv);
300                 break;
301
302         case GDK_LEAVE_NOTIFY:
303                 set_entered_track (0);
304                 break;
305
306         default:
307                 break;
308         }
309
310         return ret;
311 }
312
313 bool
314 Editor::canvas_automation_track_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationTimeAxisView *atv)
315 {
316         bool ret = false;
317
318         switch (event->type) {
319         case GDK_BUTTON_PRESS:
320         case GDK_2BUTTON_PRESS:
321         case GDK_3BUTTON_PRESS:
322                 clicked_regionview = 0;
323                 clicked_control_point = 0;
324                 clicked_axisview = atv;
325                 clicked_routeview = 0;
326                 ret = button_press_handler (item, event, AutomationTrackItem);
327                 break;
328
329         case GDK_BUTTON_RELEASE:
330                 ret = button_release_handler (item, event, AutomationTrackItem);
331                 break;
332
333         case GDK_MOTION_NOTIFY:
334                 ret = motion_handler (item, event);
335                 break;
336
337         case GDK_ENTER_NOTIFY:
338                 ret = enter_handler (item, event, AutomationTrackItem);
339                 break;
340
341         case GDK_LEAVE_NOTIFY:
342                 ret = leave_handler (item, event, AutomationTrackItem);
343                 break;
344
345         default:
346                 break;
347         }
348
349         return ret;
350 }
351
352 bool
353 Editor::canvas_fade_in_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
354 {
355         /* we handle only button 3 press/release events */
356
357         if (!rv->sensitive()) {
358                 return false;
359         }
360
361         switch (event->type) {
362         case GDK_BUTTON_PRESS:
363                 clicked_regionview = rv;
364                 clicked_control_point = 0;
365                 clicked_axisview = &rv->get_time_axis_view();
366                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
367                 if (event->button.button == 3) {
368                         return button_press_handler (item, event, FadeInItem);
369                 }
370                 break;
371
372         case GDK_BUTTON_RELEASE:
373                 if (event->button.button == 3) {
374                         return button_release_handler (item, event, FadeInItem);
375                 }
376                 break;
377
378         default:
379                 break;
380
381         }
382
383         /* proxy for the regionview */
384
385         return canvas_region_view_event (event, rv->get_canvas_group(), rv);
386 }
387
388 bool
389 Editor::canvas_fade_in_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
390 {
391         bool ret = false;
392
393         if (!rv->sensitive()) {
394                 return false;
395         }
396
397         switch (event->type) {
398         case GDK_BUTTON_PRESS:
399         case GDK_2BUTTON_PRESS:
400         case GDK_3BUTTON_PRESS:
401                 clicked_regionview = rv;
402                 clicked_control_point = 0;
403                 clicked_axisview = &rv->get_time_axis_view();
404                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
405                 ret = button_press_handler (item, event, FadeInHandleItem);
406                 break;
407
408         case GDK_BUTTON_RELEASE:
409                 ret = button_release_handler (item, event, FadeInHandleItem);
410                 break;
411
412         case GDK_MOTION_NOTIFY:
413                 ret = motion_handler (item, event);
414                 break;
415
416         case GDK_ENTER_NOTIFY:
417                 set_entered_regionview (rv);
418                 ret = enter_handler (item, event, FadeInHandleItem);
419                 break;
420
421         case GDK_LEAVE_NOTIFY:
422                 set_entered_regionview (0);
423                 ret = leave_handler (item, event, FadeInHandleItem);
424                 break;
425
426         default:
427                 break;
428         }
429
430         return ret;
431 }
432
433 bool
434 Editor::canvas_fade_out_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
435 {
436         /* we handle only button 3 press/release events */
437
438         if (!rv->sensitive()) {
439                 return false;
440         }
441
442         switch (event->type) {
443         case GDK_BUTTON_PRESS:
444                 clicked_regionview = rv;
445                 clicked_control_point = 0;
446                 clicked_axisview = &rv->get_time_axis_view();
447                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
448                 if (event->button.button == 3) {
449                         return button_press_handler (item, event, FadeOutItem);
450                 }
451                 break;
452
453         case GDK_BUTTON_RELEASE:
454                 if (event->button.button == 3) {
455                         return button_release_handler (item, event, FadeOutItem);
456                 }
457                 break;
458
459         default:
460                 break;
461
462         }
463
464         /* proxy for the regionview */
465
466         return canvas_region_view_event (event, rv->get_canvas_group(), rv);
467 }
468
469 bool
470 Editor::canvas_fade_out_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
471 {
472         bool ret = false;
473
474         if (!rv->sensitive()) {
475                 return false;
476         }
477
478         switch (event->type) {
479         case GDK_BUTTON_PRESS:
480         case GDK_2BUTTON_PRESS:
481         case GDK_3BUTTON_PRESS:
482                 clicked_regionview = rv;
483                 clicked_control_point = 0;
484                 clicked_axisview = &rv->get_time_axis_view();
485                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
486                 ret = button_press_handler (item, event, FadeOutHandleItem);
487                 break;
488
489         case GDK_BUTTON_RELEASE:
490                 ret = button_release_handler (item, event, FadeOutHandleItem);
491                 break;
492
493         case GDK_MOTION_NOTIFY:
494                 ret = motion_handler (item, event);
495                 break;
496
497         case GDK_ENTER_NOTIFY:
498                 set_entered_regionview (rv);
499                 ret = enter_handler (item, event, FadeOutHandleItem);
500                 break;
501
502         case GDK_LEAVE_NOTIFY:
503                 set_entered_regionview (0);
504                 ret = leave_handler (item, event, FadeOutHandleItem);
505                 break;
506
507         default:
508                 break;
509         }
510
511         return ret;
512 }
513
514 struct DescendingRegionLayerSorter {
515     bool operator()(boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
516             return a->layer() > b->layer();
517     }
518 };
519
520 bool
521 Editor::canvas_crossfade_view_event (GdkEvent* event, ArdourCanvas::Item* item, CrossfadeView* xfv)
522 {
523         /* we handle only button 3 press/release events */
524
525         switch (event->type) {
526         case GDK_BUTTON_PRESS:
527                 clicked_crossfadeview = xfv;
528                 clicked_axisview = &clicked_crossfadeview->get_time_axis_view();
529                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
530                 if (event->button.button == 3) {
531                         return button_press_handler (item, event, CrossfadeViewItem);
532                 }
533                 break;
534
535         case GDK_BUTTON_RELEASE:
536                 if (event->button.button == 3) {
537                         bool ret = button_release_handler (item, event, CrossfadeViewItem);
538                         return ret;
539                 }
540                 break;
541
542         default:
543                 break;
544
545         }
546
547         /* XXX do not forward double clicks */
548
549         if (event->type == GDK_2BUTTON_PRESS) {
550                 return false;
551         }
552
553         /* proxy for an underlying regionview */
554
555         /* XXX really need to check if we are in the name highlight,
556            and proxy to that when required.
557         */
558
559         TimeAxisView& tv (xfv->get_time_axis_view());
560         AudioTimeAxisView* atv;
561
562         if ((atv = dynamic_cast<AudioTimeAxisView*>(&tv)) != 0) {
563
564                 if (atv->is_audio_track()) {
565
566                         boost::shared_ptr<AudioPlaylist> pl;
567                         if ((pl = boost::dynamic_pointer_cast<AudioPlaylist> (atv->track()->playlist())) != 0) {
568
569                                 Playlist::RegionList* rl = pl->regions_at (event_frame (event));
570                                 if (!rl->empty()) {
571
572                                         if (atv->layer_display() == Overlaid) {
573
574                                                 /* we're in overlaid mode; proxy to the uppermost region view */
575
576                                                 DescendingRegionLayerSorter cmp;
577                                                 rl->sort (cmp);
578
579                                                 RegionView* rv = atv->view()->find_view (rl->front());
580
581                                                 delete rl;
582
583                                                 /* proxy */
584                                                 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
585
586                                         } else {
587
588                                                 /* we're in stacked mode; proxy to the region view under the mouse */
589
590                                                 /* XXX: FIXME: this is an evil hack; it assumes that any event for which
591                                                    this proxy is being used has its GdkEvent laid out such that the y
592                                                    member is in the same place as that for a GdkEventButton */
593
594                                                 /* position of the event within the track */
595                                                 double cx = event->button.x;
596                                                 double cy = event->button.y;
597                                                 atv->view()->canvas_item()->w2i (cx, cy);
598
599                                                 /* hence layer that we're over */
600                                                 double const c = atv->view()->child_height ();
601                                                 layer_t const l = pl->top_layer () + 1 - (cy / c);
602
603                                                 /* hence region */
604                                                 Playlist::RegionList::iterator i = rl->begin();
605                                                 while (i != rl->end() && (*i)->layer() != l) {
606                                                         ++i;
607                                                 }
608
609                                                 if (i != rl->end()) {
610                                                         RegionView* rv = atv->view()->find_view (*i);
611                                                         delete rl;
612
613                                                         /* proxy */
614                                                         return canvas_region_view_event (event, rv->get_canvas_group(), rv);
615                                                 }
616                                         }
617                                 }
618
619                                 delete rl;
620                         }
621                 }
622         }
623
624         return TRUE;
625 }
626
627 bool
628 Editor::canvas_control_point_event (GdkEvent *event, ArdourCanvas::Item* item, ControlPoint* cp)
629 {
630         switch (event->type) {
631         case GDK_BUTTON_PRESS:
632         case GDK_2BUTTON_PRESS:
633         case GDK_3BUTTON_PRESS:
634                 clicked_control_point = cp;
635                 clicked_axisview = &cp->line().trackview;
636                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
637                 clicked_regionview = 0;
638                 break;
639
640         case GDK_SCROLL_UP:
641                 break;
642
643         case GDK_SCROLL_DOWN:
644                 break;
645
646         default:
647                 break;
648         }
649
650         return typed_event (item, event, ControlPointItem);
651 }
652
653 bool
654 Editor::canvas_line_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationLine* al)
655 {
656         ItemType type;
657
658         if (dynamic_cast<AudioRegionGainLine*> (al) != 0) {
659                 type = GainLineItem;
660         } else {
661                 type = AutomationLineItem;
662         }
663
664         return typed_event (item, event, type);
665 }
666
667 bool
668 Editor::canvas_selection_rect_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
669 {
670         bool ret = false;
671
672         switch (event->type) {
673         case GDK_BUTTON_PRESS:
674         case GDK_2BUTTON_PRESS:
675         case GDK_3BUTTON_PRESS:
676                 clicked_selection = rect->id;
677                 ret = button_press_handler (item, event, SelectionItem);
678                 break;
679         case GDK_BUTTON_RELEASE:
680                 ret = button_release_handler (item, event, SelectionItem);
681                 break;
682         case GDK_MOTION_NOTIFY:
683                 ret = motion_handler (item, event);
684                 break;
685                 /* Don't need these at the moment. */
686         case GDK_ENTER_NOTIFY:
687                 ret = enter_handler (item, event, SelectionItem);
688                 break;
689
690         case GDK_LEAVE_NOTIFY:
691                 ret = leave_handler (item, event, SelectionItem);
692                 break;
693
694         default:
695                 break;
696         }
697
698         return ret;
699 }
700
701 bool
702 Editor::canvas_selection_start_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
703 {
704         bool ret = false;
705
706         switch (event->type) {
707         case GDK_BUTTON_PRESS:
708         case GDK_2BUTTON_PRESS:
709         case GDK_3BUTTON_PRESS:
710                 clicked_selection = rect->id;
711                 ret = button_press_handler (item, event, StartSelectionTrimItem);
712                 break;
713         case GDK_BUTTON_RELEASE:
714                 ret = button_release_handler (item, event, StartSelectionTrimItem);
715                 break;
716         case GDK_MOTION_NOTIFY:
717                 ret = motion_handler (item, event);
718                 break;
719         case GDK_ENTER_NOTIFY:
720                 ret = enter_handler (item, event, StartSelectionTrimItem);
721                 break;
722
723         case GDK_LEAVE_NOTIFY:
724                 ret = leave_handler (item, event, StartSelectionTrimItem);
725                 break;
726
727         default:
728                 break;
729         }
730
731         return ret;
732 }
733
734 bool
735 Editor::canvas_selection_end_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
736 {
737         bool ret = false;
738
739         switch (event->type) {
740         case GDK_BUTTON_PRESS:
741         case GDK_2BUTTON_PRESS:
742         case GDK_3BUTTON_PRESS:
743                 clicked_selection = rect->id;
744                 ret = button_press_handler (item, event, EndSelectionTrimItem);
745                 break;
746         case GDK_BUTTON_RELEASE:
747                 ret = button_release_handler (item, event, EndSelectionTrimItem);
748                 break;
749         case GDK_MOTION_NOTIFY:
750                 ret = motion_handler (item, event);
751                 break;
752         case GDK_ENTER_NOTIFY:
753                 ret = enter_handler (item, event, EndSelectionTrimItem);
754                 break;
755
756         case GDK_LEAVE_NOTIFY:
757                 ret = leave_handler (item, event, EndSelectionTrimItem);
758                 break;
759
760         default:
761                 break;
762         }
763
764         return ret;
765 }
766
767 bool
768 Editor::canvas_frame_handle_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
769 {
770         bool ret = false;
771
772         /* frame handles are not active when in internal edit mode, because actual notes
773            might be in the area occupied by the handle - we want them to be editable as normal.
774         */
775
776         if (internal_editing() || !rv->sensitive()) {
777                 return false;
778         }
779
780         /* NOTE: frame handles pretend to be the colored trim bar from an event handling
781            perspective. XXX change this ??
782         */
783
784         ItemType type;
785
786         if (item->get_data ("isleft")) {
787                 type = LeftFrameHandle;
788         } else {
789                 type = RightFrameHandle;
790         }
791
792         switch (event->type) {
793         case GDK_BUTTON_PRESS:
794         case GDK_2BUTTON_PRESS:
795         case GDK_3BUTTON_PRESS:
796                 clicked_regionview = rv;
797                 clicked_control_point = 0;
798                 clicked_axisview = &clicked_regionview->get_time_axis_view();
799                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
800                 ret = button_press_handler (item, event, type);
801                 break;
802         case GDK_BUTTON_RELEASE:
803                 ret = button_release_handler (item, event, type);
804                 break;
805         case GDK_MOTION_NOTIFY:
806                 ret = motion_handler (item, event);
807                 break;
808         case GDK_ENTER_NOTIFY:
809                 set_entered_regionview (rv);
810                 ret = enter_handler (item, event, type);
811                 break;
812
813         case GDK_LEAVE_NOTIFY:
814                 set_entered_regionview (0);
815                 ret = leave_handler (item, event, type);
816                 break;
817
818         default:
819                 break;
820         }
821
822         return ret;
823 }
824
825
826 bool
827 Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
828 {
829         bool ret = false;
830
831         if (!rv->sensitive()) {
832                 return false;
833         }
834
835         switch (event->type) {
836         case GDK_BUTTON_PRESS:
837         case GDK_2BUTTON_PRESS:
838         case GDK_3BUTTON_PRESS:
839                 clicked_regionview = rv;
840                 clicked_control_point = 0;
841                 clicked_axisview = &clicked_regionview->get_time_axis_view();
842                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
843                 ret = button_press_handler (item, event, RegionViewNameHighlight);
844                 break;
845         case GDK_BUTTON_RELEASE:
846                 ret = button_release_handler (item, event, RegionViewNameHighlight);
847                 break;
848         case GDK_MOTION_NOTIFY:
849                 motion_handler (item, event);
850                 ret = true; // force this to avoid progagating the event into the regionview
851                 break;
852         case GDK_ENTER_NOTIFY:
853                 set_entered_regionview (rv);
854                 ret = enter_handler (item, event, RegionViewNameHighlight);
855                 break;
856
857         case GDK_LEAVE_NOTIFY:
858                 set_entered_regionview (0);
859                 ret = leave_handler (item, event, RegionViewNameHighlight);
860                 break;
861
862         default:
863                 break;
864         }
865
866         return ret;
867 }
868
869 bool
870 Editor::canvas_region_view_name_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
871 {
872         bool ret = false;
873
874         if (!rv->sensitive()) {
875                 return false;
876         }
877
878         switch (event->type) {
879         case GDK_BUTTON_PRESS:
880         case GDK_2BUTTON_PRESS:
881         case GDK_3BUTTON_PRESS:
882                 clicked_regionview = rv;
883                 clicked_control_point = 0;
884                 clicked_axisview = &clicked_regionview->get_time_axis_view();
885                 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
886                 ret = button_press_handler (item, event, RegionViewName);
887                 break;
888         case GDK_BUTTON_RELEASE:
889                 ret = button_release_handler (item, event, RegionViewName);
890                 break;
891         case GDK_MOTION_NOTIFY:
892                 ret = motion_handler (item, event);
893                 break;
894         case GDK_ENTER_NOTIFY:
895                 set_entered_regionview (rv);
896                 ret = enter_handler (item, event, RegionViewName);
897                 break;
898
899         case GDK_LEAVE_NOTIFY:
900                 set_entered_regionview (0);
901                 ret = leave_handler (item, event, RegionViewName);
902                 break;
903
904         default:
905                 break;
906         }
907
908         return ret;
909 }
910
911 bool
912 Editor::canvas_feature_line_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView*)
913 {
914         bool ret = false;
915
916         switch (event->type) {
917         case GDK_BUTTON_PRESS:
918         case GDK_2BUTTON_PRESS:
919         case GDK_3BUTTON_PRESS:
920                 clicked_regionview = 0;
921                 clicked_control_point = 0;
922                 clicked_axisview = 0;
923                 clicked_routeview = 0; //dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
924                 ret = button_press_handler (item, event, FeatureLineItem);
925                 break;
926
927         case GDK_BUTTON_RELEASE:
928                 ret = button_release_handler (item, event, FeatureLineItem);
929                 break;
930
931         case GDK_MOTION_NOTIFY:
932                 ret = motion_handler (item, event);
933                 break;
934
935         case GDK_ENTER_NOTIFY:
936                 ret = enter_handler (item, event, FeatureLineItem);
937                 break;
938
939         case GDK_LEAVE_NOTIFY:
940                 ret = leave_handler (item, event, FeatureLineItem);
941                 break;
942
943         default:
944                 break;
945         }
946
947         return ret;
948 }
949
950 bool
951 Editor::canvas_marker_event (GdkEvent *event, ArdourCanvas::Item* item, Marker* /*marker*/)
952 {
953         return typed_event (item, event, MarkerItem);
954 }
955
956 bool
957 Editor::canvas_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
958 {
959         return typed_event (item, event, MarkerBarItem);
960 }
961
962 bool
963 Editor::canvas_range_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
964 {
965         return typed_event (item, event, RangeMarkerBarItem);
966 }
967
968 bool
969 Editor::canvas_transport_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
970 {
971         return typed_event (item, event, TransportMarkerBarItem);
972 }
973
974 bool
975 Editor::canvas_cd_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
976 {
977         return typed_event (item, event, CdMarkerBarItem);
978 }
979
980 bool
981 Editor::canvas_tempo_marker_event (GdkEvent *event, ArdourCanvas::Item* item, TempoMarker* /*marker*/)
982 {
983         return typed_event (item, event, TempoMarkerItem);
984 }
985
986 bool
987 Editor::canvas_meter_marker_event (GdkEvent *event, ArdourCanvas::Item* item, MeterMarker* /*marker*/)
988 {
989         return typed_event (item, event, MeterMarkerItem);
990 }
991
992 bool
993 Editor::canvas_tempo_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
994 {
995         return typed_event (item, event, TempoBarItem);
996 }
997
998 bool
999 Editor::canvas_meter_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1000 {
1001         return typed_event (item, event, MeterBarItem);
1002 }
1003
1004 bool
1005 Editor::canvas_playhead_cursor_event (GdkEvent *event, ArdourCanvas::Item* item)
1006 {
1007         return typed_event (item, event, PlayheadCursorItem);
1008 }
1009
1010 bool
1011 Editor::canvas_zoom_rect_event (GdkEvent *event, ArdourCanvas::Item* item)
1012 {
1013         return typed_event (item, event, NoItem);
1014 }
1015
1016 bool
1017 Editor::canvas_note_event (GdkEvent *event, ArdourCanvas::Item* item)
1018 {
1019         if (!internal_editing()) {
1020                 return false;
1021         }
1022
1023         return typed_event (item, event, NoteItem);
1024 }
1025
1026 bool
1027 Editor::track_canvas_drag_motion (Glib::RefPtr<Gdk::DragContext> const & /*c*/, int x, int y, guint /*time*/)
1028 {
1029         double wx;
1030         double wy;
1031         track_canvas->window_to_world (x, y, wx, wy);
1032
1033         GdkEvent event;
1034         event.type = GDK_MOTION_NOTIFY;
1035         event.button.x = wx;
1036         event.button.y = wy;
1037         /* assume we're dragging with button 1 */
1038         event.motion.state = Gdk::BUTTON1_MASK;
1039
1040         if (!_drags->active ()) {
1041
1042                 double px;
1043                 double py;
1044                 framepos_t const pos = event_frame (&event, &px, &py);
1045
1046                 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py);
1047                 if (tv.first == 0) {
1048                         return true;
1049                 }
1050
1051                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1052                 if (rtav == 0 || !rtav->is_track ()) {
1053                         return true;
1054                 }
1055
1056                 boost::shared_ptr<Region> region = _regions->get_dragged_region ();
1057
1058                 if (!region) {
1059                         return true;
1060                 }
1061
1062                 boost::shared_ptr<Region> region_copy = RegionFactory::create (region);
1063
1064                 if (boost::dynamic_pointer_cast<AudioRegion> (region_copy) != 0 &&
1065                     dynamic_cast<AudioTimeAxisView*> (tv.first) == 0) {
1066
1067                         /* audio -> non-audio */
1068                         return true;
1069                 }
1070
1071                 if (boost::dynamic_pointer_cast<MidiRegion> (region_copy) == 0 &&
1072                     dynamic_cast<MidiTimeAxisView*> (tv.first) != 0) {
1073
1074                         /* MIDI -> non-MIDI */
1075                         return true;
1076                 }
1077
1078                 _drags->set (new RegionInsertDrag (this, region_copy, rtav, pos), &event);
1079         }
1080
1081         _drags->motion_handler (&event, false);
1082
1083         return true;
1084 }
1085
1086 bool
1087 Editor::key_press_handler (ArdourCanvas::Item*, GdkEvent*, ItemType)
1088 {
1089         return false;
1090 }
1091
1092 bool
1093 Editor::key_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType type)
1094 {
1095
1096         bool handled = false;
1097
1098         switch (type) {
1099         case TempoMarkerItem:
1100                 switch (event->key.keyval) {
1101                 case GDK_Delete:
1102                         remove_tempo_marker (item);
1103                         handled = true;
1104                         break;
1105                 default:
1106                         break;
1107                 }
1108                 break;
1109
1110         case MeterMarkerItem:
1111                 switch (event->key.keyval) {
1112                 case GDK_Delete:
1113                         remove_meter_marker (item);
1114                         handled = true;
1115                         break;
1116                 default:
1117                         break;
1118                 }
1119                 break;
1120
1121         default:
1122                 break;
1123         }
1124
1125         return handled;
1126 }