2 Copyright (C) 2000 Paul Davis
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.
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.
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.
25 #include "pbd/stacktrace.h"
27 #include "ardour/midi_region.h"
28 #include "ardour/region_factory.h"
29 #include "ardour/profile.h"
31 #include "canvas/canvas.h"
32 #include "canvas/text.h"
33 #include "canvas/scroll_group.h"
37 #include "public_editor.h"
38 #include "audio_region_view.h"
39 #include "audio_streamview.h"
40 #include "audio_time_axis.h"
41 #include "region_gain_line.h"
42 #include "automation_line.h"
43 #include "automation_time_axis.h"
44 #include "automation_line.h"
45 #include "control_point.h"
46 #include "editor_drag.h"
47 #include "midi_time_axis.h"
48 #include "editor_regions.h"
49 #include "verbose_cursor.h"
54 using namespace ARDOUR;
57 using namespace ArdourCanvas;
59 using Gtkmm2ext::Keyboard;
62 Editor::track_canvas_scroll (GdkEventScroll* ev)
64 if (Keyboard::some_magic_widget_has_focus()) {
69 int direction = ev->direction;
71 /* this event arrives without transformation by the canvas, so we have
72 * to transform the coordinates to be able to look things up.
75 Duple event_coords = _track_canvas->window_to_canvas (Duple (ev->x, ev->y));
80 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomHorizontalModifier)) {
81 //for mouse-wheel zoom, force zoom-focus to mouse
82 Editing::ZoomFocus temp_focus = zoom_focus;
83 zoom_focus = Editing::ZoomFocusMouse;
84 temporal_zoom_step (false);
85 zoom_focus = temp_focus;
87 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) {
88 direction = GDK_SCROLL_LEFT;
90 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
91 if (!current_stepping_trackview) {
92 step_timeout = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Editor::track_height_step_timeout), 500);
93 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (event_coords.y, false);
94 current_stepping_trackview = p.first;
95 if (!current_stepping_trackview) {
99 last_track_height_step_timestamp = get_microseconds();
100 current_stepping_trackview->step_height (false);
103 scroll_up_one_track ();
108 case GDK_SCROLL_DOWN:
109 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomHorizontalModifier)) {
110 //for mouse-wheel zoom, force zoom-focus to mouse
111 Editing::ZoomFocus temp_focus = zoom_focus;
112 zoom_focus = Editing::ZoomFocusMouse;
113 temporal_zoom_step (true);
114 zoom_focus = temp_focus;
116 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) {
117 direction = GDK_SCROLL_RIGHT;
119 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
120 if (!current_stepping_trackview) {
121 step_timeout = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Editor::track_height_step_timeout), 500);
122 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (event_coords.y, false);
123 current_stepping_trackview = p.first;
124 if (!current_stepping_trackview) {
128 last_track_height_step_timestamp = get_microseconds();
129 current_stepping_trackview->step_height (true);
132 scroll_down_one_track ();
137 case GDK_SCROLL_LEFT:
138 xdelta = (current_page_samples() / 8);
139 if (leftmost_frame > xdelta) {
140 reset_x_origin (leftmost_frame - xdelta);
146 case GDK_SCROLL_RIGHT:
147 xdelta = (current_page_samples() / 8);
148 if (max_framepos - xdelta > leftmost_frame) {
149 reset_x_origin (leftmost_frame + xdelta);
151 reset_x_origin (max_framepos - current_page_samples());
164 Editor::canvas_scroll_event (GdkEventScroll *event, bool from_canvas)
167 boost::optional<ArdourCanvas::Rect> rulers = _time_markers_group->bounding_box();
168 if (rulers && rulers->contains (Duple (event->x, event->y))) {
169 return canvas_ruler_event ((GdkEvent*) event, timecode_ruler, TimecodeRulerItem);
173 _track_canvas->grab_focus();
174 return track_canvas_scroll (event);
178 Editor::track_canvas_button_press_event (GdkEventButton */*event*/)
181 _track_canvas->grab_focus();
186 Editor::track_canvas_button_release_event (GdkEventButton *event)
188 if (_drags->active ()) {
189 _drags->end_grab ((GdkEvent*) event);
195 Editor::track_canvas_motion_notify_event (GdkEventMotion */*event*/)
198 /* keep those motion events coming */
199 _track_canvas->get_pointer (x, y);
204 Editor::typed_event (ArdourCanvas::Item* item, GdkEvent *event, ItemType type)
208 switch (event->type) {
209 case GDK_BUTTON_PRESS:
210 case GDK_2BUTTON_PRESS:
211 case GDK_3BUTTON_PRESS:
212 ret = button_press_handler (item, event, type);
214 case GDK_BUTTON_RELEASE:
215 ret = button_release_handler (item, event, type);
217 case GDK_MOTION_NOTIFY:
218 ret = motion_handler (item, event);
221 case GDK_ENTER_NOTIFY:
222 ret = enter_handler (item, event, type);
225 case GDK_LEAVE_NOTIFY:
226 ret = leave_handler (item, event, type);
230 ret = key_press_handler (item, event, type);
233 case GDK_KEY_RELEASE:
234 ret = key_release_handler (item, event, type);
244 Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView *rv)
248 if (!rv->sensitive ()) {
252 switch (event->type) {
253 case GDK_BUTTON_PRESS:
254 case GDK_2BUTTON_PRESS:
255 case GDK_3BUTTON_PRESS:
256 clicked_regionview = rv;
257 clicked_control_point = 0;
258 clicked_axisview = &rv->get_time_axis_view();
259 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
260 ret = button_press_handler (item, event, RegionItem);
263 case GDK_BUTTON_RELEASE:
264 ret = button_release_handler (item, event, RegionItem);
267 case GDK_MOTION_NOTIFY:
268 ret = motion_handler (item, event);
271 case GDK_ENTER_NOTIFY:
272 set_entered_regionview (rv);
273 ret = enter_handler (item, event, RegionItem);
276 case GDK_LEAVE_NOTIFY:
277 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) {
278 set_entered_regionview (0);
279 ret = leave_handler (item, event, RegionItem);
291 Editor::canvas_wave_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
293 /* we only care about enter events here, required for mouse/cursor
294 * tracking. there is a non-linear (non-child/non-parent) relationship
295 * between various components of a regionview and so when we leave one
296 * of them (e.g. a trim handle) and enter another (e.g. the waveview)
297 * no other items get notified. enter/leave handling does not propagate
298 * in the same way as other events, so we need to catch this because
299 * entering (and leaving) the waveview is equivalent to
300 * entering/leaving the regionview (which is why it is passed in as a
303 * And in fact, we really only care about enter events.
308 if (!rv->sensitive ()) {
312 switch (event->type) {
313 case GDK_ENTER_NOTIFY:
314 set_entered_regionview (rv);
315 ret = enter_handler (item, event, WaveItem);
327 Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, RouteTimeAxisView *tv)
331 switch (event->type) {
332 case GDK_BUTTON_PRESS:
333 case GDK_2BUTTON_PRESS:
334 case GDK_3BUTTON_PRESS:
335 clicked_regionview = 0;
336 clicked_control_point = 0;
337 clicked_axisview = tv;
338 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
339 ret = button_press_handler (item, event, StreamItem);
342 case GDK_BUTTON_RELEASE:
343 ret = button_release_handler (item, event, StreamItem);
346 case GDK_MOTION_NOTIFY:
347 ret = motion_handler (item, event);
350 case GDK_ENTER_NOTIFY:
351 set_entered_track (tv);
352 ret = enter_handler (item, event, StreamItem);
355 case GDK_LEAVE_NOTIFY:
356 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) {
357 set_entered_track (0);
359 ret = leave_handler (item, event, StreamItem);
370 Editor::canvas_automation_track_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationTimeAxisView *atv)
374 switch (event->type) {
375 case GDK_BUTTON_PRESS:
376 case GDK_2BUTTON_PRESS:
377 case GDK_3BUTTON_PRESS:
378 clicked_regionview = 0;
379 clicked_control_point = 0;
380 clicked_axisview = atv;
381 clicked_routeview = 0;
382 ret = button_press_handler (item, event, AutomationTrackItem);
385 case GDK_BUTTON_RELEASE:
386 ret = button_release_handler (item, event, AutomationTrackItem);
389 case GDK_MOTION_NOTIFY:
390 ret = motion_handler (item, event);
393 case GDK_ENTER_NOTIFY:
394 ret = enter_handler (item, event, AutomationTrackItem);
397 case GDK_LEAVE_NOTIFY:
398 ret = leave_handler (item, event, AutomationTrackItem);
409 Editor::canvas_start_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
411 if (!rv->sensitive()) {
415 switch (event->type) {
416 case GDK_BUTTON_PRESS:
417 clicked_regionview = rv;
418 clicked_control_point = 0;
419 clicked_axisview = &rv->get_time_axis_view();
420 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
421 if (event->button.button == 3) {
422 return button_press_handler (item, event, StartCrossFadeItem);
426 case GDK_BUTTON_RELEASE:
427 if (event->button.button == 3) {
428 return button_release_handler (item, event, StartCrossFadeItem);
437 /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
438 /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
439 /* if we return RegionItem here then we avoid the issue until it is resolved later */
440 return typed_event (item, event, RegionItem); // StartCrossFadeItem);
444 Editor::canvas_end_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
446 if (!rv->sensitive()) {
450 switch (event->type) {
451 case GDK_BUTTON_PRESS:
452 clicked_regionview = rv;
453 clicked_control_point = 0;
454 clicked_axisview = &rv->get_time_axis_view();
455 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
456 if (event->button.button == 3) {
457 return button_press_handler (item, event, EndCrossFadeItem);
461 case GDK_BUTTON_RELEASE:
462 if (event->button.button == 3) {
463 return button_release_handler (item, event, EndCrossFadeItem);
472 /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
473 /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
474 /* if we return RegionItem here then we avoid the issue until it is resolved later */
475 return typed_event (item, event, RegionItem); // EndCrossFadeItem);
479 Editor::canvas_fade_in_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
481 /* we handle only button 3 press/release events */
483 if (!rv->sensitive()) {
487 switch (event->type) {
488 case GDK_BUTTON_PRESS:
489 clicked_regionview = rv;
490 clicked_control_point = 0;
491 clicked_axisview = &rv->get_time_axis_view();
492 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
493 if (event->button.button == 3) {
494 return button_press_handler (item, event, FadeInItem);
498 case GDK_BUTTON_RELEASE:
499 if (event->button.button == 3) {
500 return button_release_handler (item, event, FadeInItem);
509 /* proxy for the regionview, except enter/leave events */
511 if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
514 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
519 Editor::canvas_fade_in_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv, bool trim)
523 if (!rv->sensitive()) {
527 switch (event->type) {
528 case GDK_BUTTON_PRESS:
529 case GDK_2BUTTON_PRESS:
530 case GDK_3BUTTON_PRESS:
531 clicked_regionview = rv;
532 clicked_control_point = 0;
533 clicked_axisview = &rv->get_time_axis_view();
534 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
535 ret = button_press_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
538 case GDK_BUTTON_RELEASE:
539 ret = button_release_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
540 maybe_locate_with_edit_preroll ( rv->region()->position() );
543 case GDK_MOTION_NOTIFY:
544 ret = motion_handler (item, event);
547 case GDK_ENTER_NOTIFY:
548 ret = enter_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
551 case GDK_LEAVE_NOTIFY:
552 ret = leave_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
563 Editor::canvas_fade_out_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
565 /* we handle only button 3 press/release events */
567 if (!rv->sensitive()) {
571 switch (event->type) {
572 case GDK_BUTTON_PRESS:
573 clicked_regionview = rv;
574 clicked_control_point = 0;
575 clicked_axisview = &rv->get_time_axis_view();
576 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
577 if (event->button.button == 3) {
578 return button_press_handler (item, event, FadeOutItem);
582 case GDK_BUTTON_RELEASE:
583 if (event->button.button == 3) {
584 return button_release_handler (item, event, FadeOutItem);
593 /* proxy for the regionview, except enter/leave events */
595 if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
598 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
603 Editor::canvas_fade_out_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv, bool trim)
607 if (!rv->sensitive()) {
611 switch (event->type) {
612 case GDK_BUTTON_PRESS:
613 case GDK_2BUTTON_PRESS:
614 case GDK_3BUTTON_PRESS:
615 clicked_regionview = rv;
616 clicked_control_point = 0;
617 clicked_axisview = &rv->get_time_axis_view();
618 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
619 ret = button_press_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
622 case GDK_BUTTON_RELEASE:
623 ret = button_release_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
624 maybe_locate_with_edit_preroll ( rv->region()->last_frame() - rv->get_fade_out_shape_width() );
627 case GDK_MOTION_NOTIFY:
628 ret = motion_handler (item, event);
631 case GDK_ENTER_NOTIFY:
632 ret = enter_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
635 case GDK_LEAVE_NOTIFY:
636 ret = leave_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
646 struct DescendingRegionLayerSorter {
647 bool operator()(boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
648 return a->layer() > b->layer();
653 Editor::canvas_control_point_event (GdkEvent *event, ArdourCanvas::Item* item, ControlPoint* cp)
655 switch (event->type) {
656 case GDK_BUTTON_PRESS:
657 case GDK_2BUTTON_PRESS:
658 case GDK_3BUTTON_PRESS:
659 clicked_control_point = cp;
660 clicked_axisview = &cp->line().trackview;
661 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
662 clicked_regionview = 0;
668 case GDK_SCROLL_DOWN:
675 return typed_event (item, event, ControlPointItem);
679 Editor::canvas_line_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationLine* al)
683 if (dynamic_cast<AudioRegionGainLine*> (al) != 0) {
686 type = AutomationLineItem;
689 return typed_event (item, event, type);
693 Editor::canvas_selection_rect_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
697 switch (event->type) {
698 case GDK_BUTTON_PRESS:
699 case GDK_2BUTTON_PRESS:
700 case GDK_3BUTTON_PRESS:
701 clicked_selection = rect->id;
702 ret = button_press_handler (item, event, SelectionItem);
704 case GDK_BUTTON_RELEASE:
705 ret = button_release_handler (item, event, SelectionItem);
707 case GDK_MOTION_NOTIFY:
708 ret = motion_handler (item, event);
710 /* Don't need these at the moment. */
711 case GDK_ENTER_NOTIFY:
712 ret = enter_handler (item, event, SelectionItem);
715 case GDK_LEAVE_NOTIFY:
716 ret = leave_handler (item, event, SelectionItem);
727 Editor::canvas_selection_start_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
731 switch (event->type) {
732 case GDK_BUTTON_PRESS:
733 case GDK_2BUTTON_PRESS:
734 case GDK_3BUTTON_PRESS:
735 clicked_selection = rect->id;
736 ret = button_press_handler (item, event, StartSelectionTrimItem);
738 case GDK_BUTTON_RELEASE:
739 ret = button_release_handler (item, event, StartSelectionTrimItem);
741 case GDK_MOTION_NOTIFY:
742 ret = motion_handler (item, event);
744 case GDK_ENTER_NOTIFY:
745 ret = enter_handler (item, event, StartSelectionTrimItem);
748 case GDK_LEAVE_NOTIFY:
749 ret = leave_handler (item, event, StartSelectionTrimItem);
760 Editor::canvas_selection_end_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
764 switch (event->type) {
765 case GDK_BUTTON_PRESS:
766 case GDK_2BUTTON_PRESS:
767 case GDK_3BUTTON_PRESS:
768 clicked_selection = rect->id;
769 ret = button_press_handler (item, event, EndSelectionTrimItem);
771 case GDK_BUTTON_RELEASE:
772 ret = button_release_handler (item, event, EndSelectionTrimItem);
774 case GDK_MOTION_NOTIFY:
775 ret = motion_handler (item, event);
777 case GDK_ENTER_NOTIFY:
778 ret = enter_handler (item, event, EndSelectionTrimItem);
781 case GDK_LEAVE_NOTIFY:
782 ret = leave_handler (item, event, EndSelectionTrimItem);
793 Editor::canvas_frame_handle_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
797 /* frame handles are not active when in internal edit mode, because actual notes
798 might be in the area occupied by the handle - we want them to be editable as normal.
801 if (internal_editing() || !rv->sensitive()) {
805 /* NOTE: frame handles pretend to be the colored trim bar from an event handling
806 perspective. XXX change this ??
811 if (item->get_data ("isleft")) {
812 type = LeftFrameHandle;
814 type = RightFrameHandle;
817 switch (event->type) {
818 case GDK_BUTTON_PRESS:
819 case GDK_2BUTTON_PRESS:
820 case GDK_3BUTTON_PRESS:
821 clicked_regionview = rv;
822 clicked_control_point = 0;
823 clicked_axisview = &clicked_regionview->get_time_axis_view();
824 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
825 ret = button_press_handler (item, event, type);
827 case GDK_BUTTON_RELEASE:
828 ret = button_release_handler (item, event, type);
830 case GDK_MOTION_NOTIFY:
831 ret = motion_handler (item, event);
833 case GDK_ENTER_NOTIFY:
834 ret = enter_handler (item, event, type);
837 case GDK_LEAVE_NOTIFY:
838 ret = leave_handler (item, event, type);
850 Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
854 if (!rv->sensitive()) {
858 switch (event->type) {
859 case GDK_BUTTON_PRESS:
860 case GDK_2BUTTON_PRESS:
861 case GDK_3BUTTON_PRESS:
862 clicked_regionview = rv;
863 clicked_control_point = 0;
864 clicked_axisview = &clicked_regionview->get_time_axis_view();
865 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
866 ret = button_press_handler (item, event, RegionViewNameHighlight);
868 case GDK_BUTTON_RELEASE:
869 ret = button_release_handler (item, event, RegionViewNameHighlight);
871 case GDK_MOTION_NOTIFY:
872 motion_handler (item, event);
873 ret = true; // force this to avoid progagating the event into the regionview
875 case GDK_ENTER_NOTIFY:
876 ret = enter_handler (item, event, RegionViewNameHighlight);
879 case GDK_LEAVE_NOTIFY:
880 ret = leave_handler (item, event, RegionViewNameHighlight);
891 Editor::canvas_region_view_name_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
895 if (!rv->sensitive()) {
899 switch (event->type) {
900 case GDK_BUTTON_PRESS:
901 case GDK_2BUTTON_PRESS:
902 case GDK_3BUTTON_PRESS:
903 clicked_regionview = rv;
904 clicked_control_point = 0;
905 clicked_axisview = &clicked_regionview->get_time_axis_view();
906 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
907 ret = button_press_handler (item, event, RegionViewName);
909 case GDK_BUTTON_RELEASE:
910 ret = button_release_handler (item, event, RegionViewName);
912 case GDK_MOTION_NOTIFY:
913 ret = motion_handler (item, event);
915 case GDK_ENTER_NOTIFY:
916 ret = enter_handler (item, event, RegionViewName);
919 case GDK_LEAVE_NOTIFY:
920 ret = leave_handler (item, event, RegionViewName);
931 Editor::canvas_feature_line_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView*)
935 switch (event->type) {
936 case GDK_BUTTON_PRESS:
937 case GDK_2BUTTON_PRESS:
938 case GDK_3BUTTON_PRESS:
939 clicked_regionview = 0;
940 clicked_control_point = 0;
941 clicked_axisview = 0;
942 clicked_routeview = 0; //dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
943 ret = button_press_handler (item, event, FeatureLineItem);
946 case GDK_BUTTON_RELEASE:
947 ret = button_release_handler (item, event, FeatureLineItem);
950 case GDK_MOTION_NOTIFY:
951 ret = motion_handler (item, event);
954 case GDK_ENTER_NOTIFY:
955 ret = enter_handler (item, event, FeatureLineItem);
958 case GDK_LEAVE_NOTIFY:
959 ret = leave_handler (item, event, FeatureLineItem);
970 Editor::canvas_marker_event (GdkEvent *event, ArdourCanvas::Item* item, Marker* /*marker*/)
972 return typed_event (item, event, MarkerItem);
976 Editor::canvas_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
978 return typed_event (item, event, MarkerBarItem);
982 Editor::canvas_range_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
984 return typed_event (item, event, RangeMarkerBarItem);
988 Editor::canvas_transport_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
990 return typed_event (item, event, TransportMarkerBarItem);
994 Editor::canvas_cd_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
996 return typed_event (item, event, CdMarkerBarItem);
1000 Editor::canvas_videotl_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1002 return typed_event (item, event, VideoBarItem);
1006 Editor::canvas_tempo_marker_event (GdkEvent *event, ArdourCanvas::Item* item, TempoMarker* /*marker*/)
1008 return typed_event (item, event, TempoMarkerItem);
1012 Editor::canvas_meter_marker_event (GdkEvent *event, ArdourCanvas::Item* item, MeterMarker* /*marker*/)
1014 return typed_event (item, event, MeterMarkerItem);
1018 Editor::canvas_ruler_event (GdkEvent *event, ArdourCanvas::Item* item, ItemType type)
1021 bool handled = false;
1023 if (event->type == GDK_SCROLL) {
1025 /* scroll events in the rulers are handled a little differently from
1026 scrolling elsewhere in the canvas.
1029 switch (event->scroll.direction) {
1031 temporal_zoom_step (false);
1035 case GDK_SCROLL_DOWN:
1036 temporal_zoom_step (true);
1040 case GDK_SCROLL_LEFT:
1041 xdelta = (current_page_samples() / 2);
1042 if (leftmost_frame > xdelta) {
1043 reset_x_origin (leftmost_frame - xdelta);
1050 case GDK_SCROLL_RIGHT:
1051 xdelta = (current_page_samples() / 2);
1052 if (max_framepos - xdelta > leftmost_frame) {
1053 reset_x_origin (leftmost_frame + xdelta);
1055 reset_x_origin (max_framepos - current_page_samples());
1067 return typed_event (item, event, type);
1071 Editor::canvas_tempo_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1073 return typed_event (item, event, TempoBarItem);
1077 Editor::canvas_meter_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1079 return typed_event (item, event, MeterBarItem);
1083 Editor::canvas_playhead_cursor_event (GdkEvent *event, ArdourCanvas::Item* item)
1085 return typed_event (item, event, PlayheadCursorItem);
1089 Editor::canvas_zoom_rect_event (GdkEvent *event, ArdourCanvas::Item* item)
1091 return typed_event (item, event, NoItem);
1095 Editor::canvas_note_event (GdkEvent *event, ArdourCanvas::Item* item)
1097 if (!internal_editing()) {
1101 return typed_event (item, event, NoteItem);
1105 Editor::canvas_drop_zone_event (GdkEvent* event)
1107 GdkEventScroll scroll;
1108 ArdourCanvas::Duple winpos;
1110 switch (event->type) {
1111 case GDK_BUTTON_RELEASE:
1112 if (event->button.button == 1) {
1113 selection->clear_objects ();
1114 selection->clear_tracks ();
1119 /* convert coordinates back into window space so that
1120 we can just call canvas_scroll_event().
1122 winpos = _track_canvas->canvas_to_window (Duple (event->scroll.x, event->scroll.y));
1123 scroll = event->scroll;
1124 scroll.x = winpos.x;
1125 scroll.y = winpos.y;
1126 return canvas_scroll_event (&scroll, true);
1129 case GDK_ENTER_NOTIFY:
1130 return typed_event (_canvas_drop_zone, event, DropZoneItem);
1132 case GDK_LEAVE_NOTIFY:
1133 return typed_event (_canvas_drop_zone, event, DropZoneItem);
1143 Editor::track_canvas_drag_motion (Glib::RefPtr<Gdk::DragContext> const& context, int x, int y, guint time)
1145 boost::shared_ptr<Region> region;
1146 boost::shared_ptr<Region> region_copy;
1147 RouteTimeAxisView* rtav;
1152 string target = _track_canvas->drag_dest_find_target (context, _track_canvas->drag_dest_get_target_list());
1154 if (target.empty()) {
1158 event.type = GDK_MOTION_NOTIFY;
1161 /* assume we're dragging with button 1 */
1162 event.motion.state = Gdk::BUTTON1_MASK;
1164 (void) window_event_sample (&event, &px, &py);
1166 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py);
1167 bool can_drop = false;
1169 if (tv.first != 0) {
1171 /* over a time axis view of some kind */
1173 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1175 if (rtav != 0 && rtav->is_track ()) {
1176 /* over a track, not a bus */
1182 /* not over a time axis view, so drop is possible */
1187 region = _regions->get_dragged_region ();
1191 if ((boost::dynamic_pointer_cast<AudioRegion> (region) != 0 &&
1192 dynamic_cast<AudioTimeAxisView*> (tv.first) != 0) ||
1193 (boost::dynamic_pointer_cast<MidiRegion> (region) != 0 &&
1194 dynamic_cast<MidiTimeAxisView*> (tv.first) != 0)) {
1201 context->drag_status (context->get_suggested_action(), time);
1205 /* DND originating from outside ardour
1207 * TODO: check if file is audio/midi, allow drops on same track-type only,
1208 * currently: if audio is dropped on a midi-track, it is only added to the region-list
1210 if (Profile->get_sae() || Config->get_only_copy_imported_files()) {
1211 context->drag_status(Gdk::ACTION_COPY, time);
1213 if ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY) {
1214 context->drag_status(Gdk::ACTION_COPY, time);
1216 context->drag_status(Gdk::ACTION_LINK, time);
1224 context->drag_status (Gdk::DragAction (0), time);
1229 Editor::drop_regions (const Glib::RefPtr<Gdk::DragContext>& /*context*/,
1231 const SelectionData& /*data*/,
1232 guint /*info*/, guint /*time*/)
1234 boost::shared_ptr<Region> region;
1235 boost::shared_ptr<Region> region_copy;
1236 RouteTimeAxisView* rtav;
1241 event.type = GDK_MOTION_NOTIFY;
1244 /* assume we're dragging with button 1 */
1245 event.motion.state = Gdk::BUTTON1_MASK;
1247 framepos_t const pos = window_event_sample (&event, &px, &py);
1249 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py, false);
1251 if (tv.first != 0) {
1253 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1255 if (rtav != 0 && rtav->is_track ()) {
1257 boost::shared_ptr<Region> region = _regions->get_dragged_region ();
1261 region_copy = RegionFactory::create (region, true);
1264 if ((boost::dynamic_pointer_cast<AudioRegion> (region_copy) != 0 &&
1265 dynamic_cast<AudioTimeAxisView*> (tv.first) != 0) ||
1266 (boost::dynamic_pointer_cast<MidiRegion> (region_copy) != 0 &&
1267 dynamic_cast<MidiTimeAxisView*> (tv.first) != 0)) {
1275 _drags->set (new RegionInsertDrag (this, region_copy, rtav, pos), &event);
1276 _drags->end_grab (0);
1284 Editor::key_press_handler (ArdourCanvas::Item*, GdkEvent*, ItemType)
1290 Editor::key_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType type)
1293 bool handled = false;
1296 case TempoMarkerItem:
1297 switch (event->key.keyval) {
1299 remove_tempo_marker (item);
1307 case MeterMarkerItem:
1308 switch (event->key.keyval) {
1310 remove_meter_marker (item);