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 "ardour_ui.h"
39 #include "audio_region_view.h"
40 #include "audio_streamview.h"
41 #include "audio_time_axis.h"
42 #include "region_gain_line.h"
43 #include "automation_line.h"
44 #include "automation_time_axis.h"
45 #include "automation_line.h"
46 #include "control_point.h"
47 #include "editor_drag.h"
48 #include "midi_time_axis.h"
49 #include "editor_regions.h"
50 #include "verbose_cursor.h"
55 using namespace ARDOUR;
58 using namespace ArdourCanvas;
60 using Gtkmm2ext::Keyboard;
63 Editor::track_canvas_scroll (GdkEventScroll* ev)
65 if (Keyboard::some_magic_widget_has_focus()) {
70 int direction = ev->direction;
72 /* this event arrives without transformation by the canvas, so we have
73 * to transform the coordinates to be able to look things up.
76 Duple event_coords = _track_canvas->window_to_canvas (Duple (ev->x, ev->y));
81 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomHorizontalModifier)) {
82 //for mouse-wheel zoom, force zoom-focus to mouse
83 Editing::ZoomFocus temp_focus = zoom_focus;
84 zoom_focus = Editing::ZoomFocusMouse;
85 temporal_zoom_step (false);
86 zoom_focus = temp_focus;
88 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) {
89 direction = GDK_SCROLL_LEFT;
91 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
92 if (!current_stepping_trackview) {
93 step_timeout = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Editor::track_height_step_timeout), 500);
94 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (event_coords.y, false);
95 current_stepping_trackview = p.first;
96 if (!current_stepping_trackview) {
100 last_track_height_step_timestamp = get_microseconds();
101 current_stepping_trackview->step_height (false);
104 scroll_up_one_track ();
109 case GDK_SCROLL_DOWN:
110 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomHorizontalModifier)) {
111 //for mouse-wheel zoom, force zoom-focus to mouse
112 Editing::ZoomFocus temp_focus = zoom_focus;
113 zoom_focus = Editing::ZoomFocusMouse;
114 temporal_zoom_step (true);
115 zoom_focus = temp_focus;
117 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) {
118 direction = GDK_SCROLL_RIGHT;
120 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
121 if (!current_stepping_trackview) {
122 step_timeout = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Editor::track_height_step_timeout), 500);
123 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (event_coords.y, false);
124 current_stepping_trackview = p.first;
125 if (!current_stepping_trackview) {
129 last_track_height_step_timestamp = get_microseconds();
130 current_stepping_trackview->step_height (true);
133 scroll_down_one_track ();
138 case GDK_SCROLL_LEFT:
139 xdelta = (current_page_samples() / 8);
140 if (leftmost_frame > xdelta) {
141 reset_x_origin (leftmost_frame - xdelta);
147 case GDK_SCROLL_RIGHT:
148 xdelta = (current_page_samples() / 8);
149 if (max_framepos - xdelta > leftmost_frame) {
150 reset_x_origin (leftmost_frame + xdelta);
152 reset_x_origin (max_framepos - current_page_samples());
165 Editor::canvas_scroll_event (GdkEventScroll *event, bool from_canvas)
168 boost::optional<ArdourCanvas::Rect> rulers = _time_markers_group->bounding_box();
169 if (rulers && rulers->contains (Duple (event->x, event->y))) {
170 return canvas_ruler_event ((GdkEvent*) event, timecode_ruler, TimecodeRulerItem);
174 _track_canvas->grab_focus();
175 return track_canvas_scroll (event);
179 Editor::track_canvas_button_press_event (GdkEventButton */*event*/)
182 _track_canvas->grab_focus();
187 Editor::track_canvas_button_release_event (GdkEventButton *event)
189 if (_drags->active ()) {
190 _drags->end_grab ((GdkEvent*) event);
196 Editor::track_canvas_motion_notify_event (GdkEventMotion */*event*/)
199 /* keep those motion events coming */
200 _track_canvas->get_pointer (x, y);
205 Editor::typed_event (ArdourCanvas::Item* item, GdkEvent *event, ItemType type)
209 switch (event->type) {
210 case GDK_BUTTON_PRESS:
211 case GDK_2BUTTON_PRESS:
212 case GDK_3BUTTON_PRESS:
213 ret = button_press_handler (item, event, type);
215 case GDK_BUTTON_RELEASE:
216 ret = button_release_handler (item, event, type);
218 case GDK_MOTION_NOTIFY:
219 ret = motion_handler (item, event);
222 case GDK_ENTER_NOTIFY:
223 ret = enter_handler (item, event, type);
226 case GDK_LEAVE_NOTIFY:
227 ret = leave_handler (item, event, type);
231 ret = key_press_handler (item, event, type);
234 case GDK_KEY_RELEASE:
235 ret = key_release_handler (item, event, type);
245 Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView *rv)
249 if (!rv->sensitive ()) {
253 switch (event->type) {
254 case GDK_BUTTON_PRESS:
255 case GDK_2BUTTON_PRESS:
256 case GDK_3BUTTON_PRESS:
257 clicked_regionview = rv;
258 clicked_control_point = 0;
259 clicked_axisview = &rv->get_time_axis_view();
260 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
261 ret = button_press_handler (item, event, RegionItem);
264 case GDK_BUTTON_RELEASE:
265 ret = button_release_handler (item, event, RegionItem);
268 case GDK_MOTION_NOTIFY:
269 ret = motion_handler (item, event);
272 case GDK_ENTER_NOTIFY:
273 set_entered_regionview (rv);
274 ret = enter_handler (item, event, RegionItem);
277 case GDK_LEAVE_NOTIFY:
278 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) {
279 set_entered_regionview (0);
280 ret = leave_handler (item, event, RegionItem);
292 Editor::canvas_wave_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
294 /* we only care about enter events here, required for mouse/cursor
295 * tracking. there is a non-linear (non-child/non-parent) relationship
296 * between various components of a regionview and so when we leave one
297 * of them (e.g. a trim handle) and enter another (e.g. the waveview)
298 * no other items get notified. enter/leave handling does not propagate
299 * in the same way as other events, so we need to catch this because
300 * entering (and leaving) the waveview is equivalent to
301 * entering/leaving the regionview (which is why it is passed in as a
304 * And in fact, we really only care about enter events.
309 if (!rv->sensitive ()) {
313 switch (event->type) {
314 case GDK_ENTER_NOTIFY:
315 set_entered_regionview (rv);
316 ret = enter_handler (item, event, WaveItem);
328 Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, RouteTimeAxisView *tv)
332 switch (event->type) {
333 case GDK_BUTTON_PRESS:
334 case GDK_2BUTTON_PRESS:
335 case GDK_3BUTTON_PRESS:
336 clicked_regionview = 0;
337 clicked_control_point = 0;
338 clicked_axisview = tv;
339 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
340 ret = button_press_handler (item, event, StreamItem);
343 case GDK_BUTTON_RELEASE:
344 ret = button_release_handler (item, event, StreamItem);
347 case GDK_MOTION_NOTIFY:
348 ret = motion_handler (item, event);
351 case GDK_ENTER_NOTIFY:
352 set_entered_track (tv);
353 ret = enter_handler (item, event, StreamItem);
356 case GDK_LEAVE_NOTIFY:
357 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) {
358 set_entered_track (0);
360 ret = leave_handler (item, event, StreamItem);
371 Editor::canvas_automation_track_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationTimeAxisView *atv)
375 switch (event->type) {
376 case GDK_BUTTON_PRESS:
377 case GDK_2BUTTON_PRESS:
378 case GDK_3BUTTON_PRESS:
379 clicked_regionview = 0;
380 clicked_control_point = 0;
381 clicked_axisview = atv;
382 clicked_routeview = 0;
383 ret = button_press_handler (item, event, AutomationTrackItem);
386 case GDK_BUTTON_RELEASE:
387 ret = button_release_handler (item, event, AutomationTrackItem);
390 case GDK_MOTION_NOTIFY:
391 ret = motion_handler (item, event);
394 case GDK_ENTER_NOTIFY:
395 ret = enter_handler (item, event, AutomationTrackItem);
398 case GDK_LEAVE_NOTIFY:
399 ret = leave_handler (item, event, AutomationTrackItem);
410 Editor::canvas_start_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
412 if (!rv->sensitive()) {
416 switch (event->type) {
417 case GDK_BUTTON_PRESS:
418 clicked_regionview = rv;
419 clicked_control_point = 0;
420 clicked_axisview = &rv->get_time_axis_view();
421 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
422 if (event->button.button == 3) {
423 return button_press_handler (item, event, StartCrossFadeItem);
427 case GDK_BUTTON_RELEASE:
428 if (event->button.button == 3) {
429 return button_release_handler (item, event, StartCrossFadeItem);
438 /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
439 /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
440 /* if we return RegionItem here then we avoid the issue until it is resolved later */
441 return typed_event (item, event, RegionItem); // StartCrossFadeItem);
445 Editor::canvas_end_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
447 if (!rv->sensitive()) {
451 switch (event->type) {
452 case GDK_BUTTON_PRESS:
453 clicked_regionview = rv;
454 clicked_control_point = 0;
455 clicked_axisview = &rv->get_time_axis_view();
456 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
457 if (event->button.button == 3) {
458 return button_press_handler (item, event, EndCrossFadeItem);
462 case GDK_BUTTON_RELEASE:
463 if (event->button.button == 3) {
464 return button_release_handler (item, event, EndCrossFadeItem);
473 /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
474 /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
475 /* if we return RegionItem here then we avoid the issue until it is resolved later */
476 return typed_event (item, event, RegionItem); // EndCrossFadeItem);
480 Editor::canvas_fade_in_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
482 /* we handle only button 3 press/release events */
484 if (!rv->sensitive()) {
488 switch (event->type) {
489 case GDK_BUTTON_PRESS:
490 clicked_regionview = rv;
491 clicked_control_point = 0;
492 clicked_axisview = &rv->get_time_axis_view();
493 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
494 if (event->button.button == 3) {
495 return button_press_handler (item, event, FadeInItem);
499 case GDK_BUTTON_RELEASE:
500 if (event->button.button == 3) {
501 return button_release_handler (item, event, FadeInItem);
510 /* proxy for the regionview, except enter/leave events */
512 if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
515 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
520 Editor::canvas_fade_in_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv, bool trim)
524 if (!rv->sensitive()) {
528 switch (event->type) {
529 case GDK_BUTTON_PRESS:
530 case GDK_2BUTTON_PRESS:
531 case GDK_3BUTTON_PRESS:
532 clicked_regionview = rv;
533 clicked_control_point = 0;
534 clicked_axisview = &rv->get_time_axis_view();
535 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
536 ret = button_press_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
539 case GDK_BUTTON_RELEASE:
540 ret = button_release_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
541 maybe_locate_with_edit_preroll ( rv->region()->position() );
544 case GDK_MOTION_NOTIFY:
545 ret = motion_handler (item, event);
548 case GDK_ENTER_NOTIFY:
549 ret = enter_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
552 case GDK_LEAVE_NOTIFY:
553 ret = leave_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
564 Editor::canvas_fade_out_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
566 /* we handle only button 3 press/release events */
568 if (!rv->sensitive()) {
572 switch (event->type) {
573 case GDK_BUTTON_PRESS:
574 clicked_regionview = rv;
575 clicked_control_point = 0;
576 clicked_axisview = &rv->get_time_axis_view();
577 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
578 if (event->button.button == 3) {
579 return button_press_handler (item, event, FadeOutItem);
583 case GDK_BUTTON_RELEASE:
584 if (event->button.button == 3) {
585 return button_release_handler (item, event, FadeOutItem);
594 /* proxy for the regionview, except enter/leave events */
596 if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
599 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
604 Editor::canvas_fade_out_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv, bool trim)
608 if (!rv->sensitive()) {
612 switch (event->type) {
613 case GDK_BUTTON_PRESS:
614 case GDK_2BUTTON_PRESS:
615 case GDK_3BUTTON_PRESS:
616 clicked_regionview = rv;
617 clicked_control_point = 0;
618 clicked_axisview = &rv->get_time_axis_view();
619 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
620 ret = button_press_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
623 case GDK_BUTTON_RELEASE:
624 ret = button_release_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
625 maybe_locate_with_edit_preroll ( rv->region()->last_frame() - rv->get_fade_out_shape_width() );
628 case GDK_MOTION_NOTIFY:
629 ret = motion_handler (item, event);
632 case GDK_ENTER_NOTIFY:
633 ret = enter_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
636 case GDK_LEAVE_NOTIFY:
637 ret = leave_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
647 struct DescendingRegionLayerSorter {
648 bool operator()(boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
649 return a->layer() > b->layer();
654 Editor::canvas_control_point_event (GdkEvent *event, ArdourCanvas::Item* item, ControlPoint* cp)
656 switch (event->type) {
657 case GDK_BUTTON_PRESS:
658 case GDK_2BUTTON_PRESS:
659 case GDK_3BUTTON_PRESS:
660 clicked_control_point = cp;
661 clicked_axisview = &cp->line().trackview;
662 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
663 clicked_regionview = 0;
669 case GDK_SCROLL_DOWN:
676 return typed_event (item, event, ControlPointItem);
680 Editor::canvas_line_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationLine* al)
684 if (dynamic_cast<AudioRegionGainLine*> (al) != 0) {
687 type = AutomationLineItem;
690 return typed_event (item, event, type);
694 Editor::canvas_selection_rect_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
698 switch (event->type) {
699 case GDK_BUTTON_PRESS:
700 case GDK_2BUTTON_PRESS:
701 case GDK_3BUTTON_PRESS:
702 clicked_selection = rect->id;
703 ret = button_press_handler (item, event, SelectionItem);
705 case GDK_BUTTON_RELEASE:
706 ret = button_release_handler (item, event, SelectionItem);
708 case GDK_MOTION_NOTIFY:
709 ret = motion_handler (item, event);
711 /* Don't need these at the moment. */
712 case GDK_ENTER_NOTIFY:
713 ret = enter_handler (item, event, SelectionItem);
716 case GDK_LEAVE_NOTIFY:
717 ret = leave_handler (item, event, SelectionItem);
728 Editor::canvas_selection_start_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
732 switch (event->type) {
733 case GDK_BUTTON_PRESS:
734 case GDK_2BUTTON_PRESS:
735 case GDK_3BUTTON_PRESS:
736 clicked_selection = rect->id;
737 ret = button_press_handler (item, event, StartSelectionTrimItem);
739 case GDK_BUTTON_RELEASE:
740 ret = button_release_handler (item, event, StartSelectionTrimItem);
742 case GDK_MOTION_NOTIFY:
743 ret = motion_handler (item, event);
745 case GDK_ENTER_NOTIFY:
746 ret = enter_handler (item, event, StartSelectionTrimItem);
749 case GDK_LEAVE_NOTIFY:
750 ret = leave_handler (item, event, StartSelectionTrimItem);
761 Editor::canvas_selection_end_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
765 switch (event->type) {
766 case GDK_BUTTON_PRESS:
767 case GDK_2BUTTON_PRESS:
768 case GDK_3BUTTON_PRESS:
769 clicked_selection = rect->id;
770 ret = button_press_handler (item, event, EndSelectionTrimItem);
772 case GDK_BUTTON_RELEASE:
773 ret = button_release_handler (item, event, EndSelectionTrimItem);
775 case GDK_MOTION_NOTIFY:
776 ret = motion_handler (item, event);
778 case GDK_ENTER_NOTIFY:
779 ret = enter_handler (item, event, EndSelectionTrimItem);
782 case GDK_LEAVE_NOTIFY:
783 ret = leave_handler (item, event, EndSelectionTrimItem);
794 Editor::canvas_frame_handle_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
798 /* frame handles are not active when in internal edit mode, because actual notes
799 might be in the area occupied by the handle - we want them to be editable as normal.
802 if (internal_editing() || !rv->sensitive()) {
806 /* NOTE: frame handles pretend to be the colored trim bar from an event handling
807 perspective. XXX change this ??
812 if (item->get_data ("isleft")) {
813 type = LeftFrameHandle;
815 type = RightFrameHandle;
818 switch (event->type) {
819 case GDK_BUTTON_PRESS:
820 case GDK_2BUTTON_PRESS:
821 case GDK_3BUTTON_PRESS:
822 clicked_regionview = rv;
823 clicked_control_point = 0;
824 clicked_axisview = &clicked_regionview->get_time_axis_view();
825 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
826 ret = button_press_handler (item, event, type);
828 case GDK_BUTTON_RELEASE:
829 ret = button_release_handler (item, event, type);
831 case GDK_MOTION_NOTIFY:
832 ret = motion_handler (item, event);
834 case GDK_ENTER_NOTIFY:
835 ret = enter_handler (item, event, type);
838 case GDK_LEAVE_NOTIFY:
839 ret = leave_handler (item, event, type);
851 Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
855 if (!rv->sensitive()) {
859 switch (event->type) {
860 case GDK_BUTTON_PRESS:
861 case GDK_2BUTTON_PRESS:
862 case GDK_3BUTTON_PRESS:
863 clicked_regionview = rv;
864 clicked_control_point = 0;
865 clicked_axisview = &clicked_regionview->get_time_axis_view();
866 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
867 ret = button_press_handler (item, event, RegionViewNameHighlight);
869 case GDK_BUTTON_RELEASE:
870 ret = button_release_handler (item, event, RegionViewNameHighlight);
872 case GDK_MOTION_NOTIFY:
873 motion_handler (item, event);
874 ret = true; // force this to avoid progagating the event into the regionview
876 case GDK_ENTER_NOTIFY:
877 ret = enter_handler (item, event, RegionViewNameHighlight);
880 case GDK_LEAVE_NOTIFY:
881 ret = leave_handler (item, event, RegionViewNameHighlight);
892 Editor::canvas_region_view_name_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
896 if (!rv->sensitive()) {
900 switch (event->type) {
901 case GDK_BUTTON_PRESS:
902 case GDK_2BUTTON_PRESS:
903 case GDK_3BUTTON_PRESS:
904 clicked_regionview = rv;
905 clicked_control_point = 0;
906 clicked_axisview = &clicked_regionview->get_time_axis_view();
907 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
908 ret = button_press_handler (item, event, RegionViewName);
910 case GDK_BUTTON_RELEASE:
911 ret = button_release_handler (item, event, RegionViewName);
913 case GDK_MOTION_NOTIFY:
914 ret = motion_handler (item, event);
916 case GDK_ENTER_NOTIFY:
917 ret = enter_handler (item, event, RegionViewName);
920 case GDK_LEAVE_NOTIFY:
921 ret = leave_handler (item, event, RegionViewName);
932 Editor::canvas_feature_line_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView*)
936 switch (event->type) {
937 case GDK_BUTTON_PRESS:
938 case GDK_2BUTTON_PRESS:
939 case GDK_3BUTTON_PRESS:
940 clicked_regionview = 0;
941 clicked_control_point = 0;
942 clicked_axisview = 0;
943 clicked_routeview = 0; //dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
944 ret = button_press_handler (item, event, FeatureLineItem);
947 case GDK_BUTTON_RELEASE:
948 ret = button_release_handler (item, event, FeatureLineItem);
951 case GDK_MOTION_NOTIFY:
952 ret = motion_handler (item, event);
955 case GDK_ENTER_NOTIFY:
956 ret = enter_handler (item, event, FeatureLineItem);
959 case GDK_LEAVE_NOTIFY:
960 ret = leave_handler (item, event, FeatureLineItem);
971 Editor::canvas_marker_event (GdkEvent *event, ArdourCanvas::Item* item, Marker* /*marker*/)
973 return typed_event (item, event, MarkerItem);
977 Editor::canvas_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
979 return typed_event (item, event, MarkerBarItem);
983 Editor::canvas_range_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
985 return typed_event (item, event, RangeMarkerBarItem);
989 Editor::canvas_transport_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
991 return typed_event (item, event, TransportMarkerBarItem);
995 Editor::canvas_cd_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
997 return typed_event (item, event, CdMarkerBarItem);
1001 Editor::canvas_videotl_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1003 return typed_event (item, event, VideoBarItem);
1007 Editor::canvas_tempo_marker_event (GdkEvent *event, ArdourCanvas::Item* item, TempoMarker* /*marker*/)
1009 return typed_event (item, event, TempoMarkerItem);
1013 Editor::canvas_meter_marker_event (GdkEvent *event, ArdourCanvas::Item* item, MeterMarker* /*marker*/)
1015 return typed_event (item, event, MeterMarkerItem);
1019 Editor::canvas_ruler_event (GdkEvent *event, ArdourCanvas::Item* item, ItemType type)
1022 bool handled = false;
1024 if (event->type == GDK_SCROLL) {
1026 /* scroll events in the rulers are handled a little differently from
1027 scrolling elsewhere in the canvas.
1030 switch (event->scroll.direction) {
1032 temporal_zoom_step (false);
1036 case GDK_SCROLL_DOWN:
1037 temporal_zoom_step (true);
1041 case GDK_SCROLL_LEFT:
1042 xdelta = (current_page_samples() / 2);
1043 if (leftmost_frame > xdelta) {
1044 reset_x_origin (leftmost_frame - xdelta);
1051 case GDK_SCROLL_RIGHT:
1052 xdelta = (current_page_samples() / 2);
1053 if (max_framepos - xdelta > leftmost_frame) {
1054 reset_x_origin (leftmost_frame + xdelta);
1056 reset_x_origin (max_framepos - current_page_samples());
1068 return typed_event (item, event, type);
1072 Editor::canvas_tempo_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1074 return typed_event (item, event, TempoBarItem);
1078 Editor::canvas_meter_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1080 return typed_event (item, event, MeterBarItem);
1084 Editor::canvas_playhead_cursor_event (GdkEvent *event, ArdourCanvas::Item* item)
1086 return typed_event (item, event, PlayheadCursorItem);
1090 Editor::canvas_note_event (GdkEvent *event, ArdourCanvas::Item* item)
1092 if (!internal_editing()) {
1096 return typed_event (item, event, NoteItem);
1100 Editor::canvas_drop_zone_event (GdkEvent* event)
1102 GdkEventScroll scroll;
1103 ArdourCanvas::Duple winpos;
1105 switch (event->type) {
1106 case GDK_BUTTON_RELEASE:
1107 if (event->button.button == 1) {
1108 selection->clear_objects ();
1109 selection->clear_tracks ();
1114 /* convert coordinates back into window space so that
1115 we can just call canvas_scroll_event().
1117 winpos = _track_canvas->canvas_to_window (Duple (event->scroll.x, event->scroll.y));
1118 scroll = event->scroll;
1119 scroll.x = winpos.x;
1120 scroll.y = winpos.y;
1121 return canvas_scroll_event (&scroll, true);
1124 case GDK_ENTER_NOTIFY:
1125 return typed_event (_canvas_drop_zone, event, DropZoneItem);
1127 case GDK_LEAVE_NOTIFY:
1128 return typed_event (_canvas_drop_zone, event, DropZoneItem);
1138 Editor::track_canvas_drag_motion (Glib::RefPtr<Gdk::DragContext> const& context, int x, int y, guint time)
1140 boost::shared_ptr<Region> region;
1141 boost::shared_ptr<Region> region_copy;
1142 RouteTimeAxisView* rtav;
1147 string target = _track_canvas->drag_dest_find_target (context, _track_canvas->drag_dest_get_target_list());
1149 if (target.empty()) {
1153 event.type = GDK_MOTION_NOTIFY;
1156 /* assume we're dragging with button 1 */
1157 event.motion.state = Gdk::BUTTON1_MASK;
1159 (void) window_event_sample (&event, &px, &py);
1161 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py, false);
1162 bool can_drop = false;
1164 if (tv.first != 0) {
1166 /* over a time axis view of some kind */
1168 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1170 if (rtav != 0 && rtav->is_track ()) {
1171 /* over a track, not a bus */
1177 /* not over a time axis view, so drop is possible */
1182 region = _regions->get_dragged_region ();
1186 if ((boost::dynamic_pointer_cast<AudioRegion> (region) != 0 &&
1187 dynamic_cast<AudioTimeAxisView*> (tv.first) != 0) ||
1188 (boost::dynamic_pointer_cast<MidiRegion> (region) != 0 &&
1189 dynamic_cast<MidiTimeAxisView*> (tv.first) != 0)) {
1196 context->drag_status (context->get_suggested_action(), time);
1200 /* DND originating from outside ardour
1202 * TODO: check if file is audio/midi, allow drops on same track-type only,
1203 * currently: if audio is dropped on a midi-track, it is only added to the region-list
1205 if (Profile->get_sae() || ARDOUR_UI::config()->get_only_copy_imported_files()) {
1206 context->drag_status(Gdk::ACTION_COPY, time);
1208 if ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY) {
1209 context->drag_status(Gdk::ACTION_COPY, time);
1211 context->drag_status(Gdk::ACTION_LINK, time);
1219 context->drag_status (Gdk::DragAction (0), time);
1224 Editor::drop_regions (const Glib::RefPtr<Gdk::DragContext>& /*context*/,
1226 const SelectionData& /*data*/,
1227 guint /*info*/, guint /*time*/)
1229 boost::shared_ptr<Region> region;
1230 boost::shared_ptr<Region> region_copy;
1231 RouteTimeAxisView* rtav;
1236 event.type = GDK_MOTION_NOTIFY;
1239 /* assume we're dragging with button 1 */
1240 event.motion.state = Gdk::BUTTON1_MASK;
1242 framepos_t const pos = window_event_sample (&event, &px, &py);
1244 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py, false);
1246 if (tv.first != 0) {
1248 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1250 if (rtav != 0 && rtav->is_track ()) {
1252 boost::shared_ptr<Region> region = _regions->get_dragged_region ();
1256 region_copy = RegionFactory::create (region, true);
1259 if ((boost::dynamic_pointer_cast<AudioRegion> (region_copy) != 0 &&
1260 dynamic_cast<AudioTimeAxisView*> (tv.first) != 0) ||
1261 (boost::dynamic_pointer_cast<MidiRegion> (region_copy) != 0 &&
1262 dynamic_cast<MidiTimeAxisView*> (tv.first) != 0)) {
1270 _drags->set (new RegionInsertDrag (this, region_copy, rtav, pos), &event);
1271 _drags->end_grab (0);
1279 Editor::key_press_handler (ArdourCanvas::Item*, GdkEvent*, ItemType)
1285 Editor::key_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType type)
1288 bool handled = false;
1291 case TempoMarkerItem:
1292 switch (event->key.keyval) {
1294 remove_tempo_marker (item);
1302 case MeterMarkerItem:
1303 switch (event->key.keyval) {
1305 remove_meter_marker (item);