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/audio_track.h"
28 #include "ardour/midi_track.h"
29 #include "ardour/midi_region.h"
30 #include "ardour/region_factory.h"
31 #include "ardour/profile.h"
33 #include "canvas/canvas.h"
34 #include "canvas/text.h"
35 #include "canvas/scroll_group.h"
39 #include "public_editor.h"
40 #include "audio_region_view.h"
41 #include "audio_streamview.h"
42 #include "audio_time_axis.h"
43 #include "region_gain_line.h"
44 #include "automation_line.h"
45 #include "automation_time_axis.h"
46 #include "automation_line.h"
47 #include "control_point.h"
48 #include "editor_drag.h"
49 #include "midi_time_axis.h"
50 #include "editor_regions.h"
51 #include "ui_config.h"
52 #include "verbose_cursor.h"
57 using namespace ARDOUR;
60 using namespace ArdourCanvas;
62 using Gtkmm2ext::Keyboard;
65 Editor::track_canvas_scroll (GdkEventScroll* ev)
67 int direction = ev->direction;
69 /* this event arrives without transformation by the canvas, so we have
70 * to transform the coordinates to be able to look things up.
73 Duple event_coords = _track_canvas->window_to_canvas (Duple (ev->x, ev->y));
77 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomHorizontalModifier)) {
78 //for mouse-wheel zoom, force zoom-focus to mouse
79 temporal_zoom_step_mouse_focus (false);
81 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) {
84 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
85 if (!current_stepping_trackview) {
86 step_timeout = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Editor::track_height_step_timeout), 500);
87 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (event_coords.y, false);
88 current_stepping_trackview = p.first;
89 if (!current_stepping_trackview) {
93 last_track_height_step_timestamp = get_microseconds();
94 current_stepping_trackview->step_height (false);
97 scroll_up_one_track ();
102 case GDK_SCROLL_DOWN:
103 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomHorizontalModifier)) {
104 //for mouse-wheel zoom, force zoom-focus to mouse
105 temporal_zoom_step_mouse_focus (true);
107 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) {
108 scroll_right_step ();
110 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
111 if (!current_stepping_trackview) {
112 step_timeout = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Editor::track_height_step_timeout), 500);
113 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (event_coords.y, false);
114 current_stepping_trackview = p.first;
115 if (!current_stepping_trackview) {
119 last_track_height_step_timestamp = get_microseconds();
120 current_stepping_trackview->step_height (true);
123 scroll_down_one_track ();
128 case GDK_SCROLL_LEFT:
133 case GDK_SCROLL_RIGHT:
134 scroll_right_step ();
147 Editor::canvas_scroll_event (GdkEventScroll *event, bool from_canvas)
150 boost::optional<ArdourCanvas::Rect> rulers = _time_markers_group->bounding_box();
151 if (rulers && rulers->contains (Duple (event->x, event->y))) {
152 return canvas_ruler_event ((GdkEvent*) event, timecode_ruler, TimecodeRulerItem);
156 _track_canvas->grab_focus();
157 return track_canvas_scroll (event);
161 Editor::track_canvas_button_press_event (GdkEventButton *event)
163 _track_canvas->grab_focus();
164 if (!Keyboard::is_context_menu_event (event)) {
165 begin_reversible_selection_op (X_("Clear Selection Click (track canvas)"));
167 commit_reversible_selection_op();
173 Editor::track_canvas_button_release_event (GdkEventButton *event)
175 if (!Keyboard::is_context_menu_event (event)) {
176 if (_drags->active ()) {
177 _drags->end_grab ((GdkEvent*) event);
184 Editor::track_canvas_motion_notify_event (GdkEventMotion */*event*/)
187 /* keep those motion events coming */
188 _track_canvas->get_pointer (x, y);
193 Editor::typed_event (ArdourCanvas::Item* item, GdkEvent *event, ItemType type)
197 switch (event->type) {
198 case GDK_BUTTON_PRESS:
199 case GDK_2BUTTON_PRESS:
200 case GDK_3BUTTON_PRESS:
201 ret = button_press_handler (item, event, type);
203 case GDK_BUTTON_RELEASE:
204 ret = button_release_handler (item, event, type);
206 case GDK_MOTION_NOTIFY:
207 ret = motion_handler (item, event);
210 case GDK_ENTER_NOTIFY:
211 ret = enter_handler (item, event, type);
214 case GDK_LEAVE_NOTIFY:
215 ret = leave_handler (item, event, type);
219 ret = key_press_handler (item, event, type);
222 case GDK_KEY_RELEASE:
223 ret = key_release_handler (item, event, type);
233 Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView *rv)
237 if (!rv->sensitive ()) {
241 switch (event->type) {
242 case GDK_BUTTON_PRESS:
243 case GDK_2BUTTON_PRESS:
244 case GDK_3BUTTON_PRESS:
245 clicked_regionview = rv;
246 clicked_control_point = 0;
247 clicked_axisview = &rv->get_time_axis_view();
248 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
249 ret = button_press_handler (item, event, RegionItem);
252 case GDK_BUTTON_RELEASE:
253 ret = button_release_handler (item, event, RegionItem);
256 case GDK_MOTION_NOTIFY:
257 ret = motion_handler (item, event);
260 case GDK_ENTER_NOTIFY:
261 set_entered_regionview (rv);
262 ret = enter_handler (item, event, RegionItem);
265 case GDK_LEAVE_NOTIFY:
266 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) {
267 set_entered_regionview (0);
268 ret = leave_handler (item, event, RegionItem);
280 Editor::canvas_wave_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
282 /* we only care about enter events here, required for mouse/cursor
283 * tracking. there is a non-linear (non-child/non-parent) relationship
284 * between various components of a regionview and so when we leave one
285 * of them (e.g. a trim handle) and enter another (e.g. the waveview)
286 * no other items get notified. enter/leave handling does not propagate
287 * in the same way as other events, so we need to catch this because
288 * entering (and leaving) the waveview is equivalent to
289 * entering/leaving the regionview (which is why it is passed in as a
292 * And in fact, we really only care about enter events.
297 if (!rv->sensitive ()) {
301 switch (event->type) {
302 case GDK_ENTER_NOTIFY:
303 set_entered_regionview (rv);
304 ret = enter_handler (item, event, WaveItem);
316 Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, RouteTimeAxisView *tv)
320 switch (event->type) {
321 case GDK_BUTTON_PRESS:
322 case GDK_2BUTTON_PRESS:
323 case GDK_3BUTTON_PRESS:
324 clicked_regionview = 0;
325 clicked_control_point = 0;
326 clicked_axisview = tv;
327 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
328 ret = button_press_handler (item, event, StreamItem);
331 case GDK_BUTTON_RELEASE:
332 ret = button_release_handler (item, event, StreamItem);
335 case GDK_MOTION_NOTIFY:
336 ret = motion_handler (item, event);
339 case GDK_ENTER_NOTIFY:
340 set_entered_track (tv);
341 ret = enter_handler (item, event, StreamItem);
344 case GDK_LEAVE_NOTIFY:
345 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) {
346 set_entered_track (0);
348 ret = leave_handler (item, event, StreamItem);
359 Editor::canvas_automation_track_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationTimeAxisView *atv)
363 switch (event->type) {
364 case GDK_BUTTON_PRESS:
365 case GDK_2BUTTON_PRESS:
366 case GDK_3BUTTON_PRESS:
367 clicked_regionview = 0;
368 clicked_control_point = 0;
369 clicked_axisview = atv;
370 clicked_routeview = 0;
371 ret = button_press_handler (item, event, AutomationTrackItem);
374 case GDK_BUTTON_RELEASE:
375 ret = button_release_handler (item, event, AutomationTrackItem);
378 case GDK_MOTION_NOTIFY:
379 ret = motion_handler (item, event);
382 case GDK_ENTER_NOTIFY:
383 ret = enter_handler (item, event, AutomationTrackItem);
386 case GDK_LEAVE_NOTIFY:
387 ret = leave_handler (item, event, AutomationTrackItem);
398 Editor::canvas_start_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
400 if (!rv->sensitive()) {
404 switch (event->type) {
405 case GDK_BUTTON_PRESS:
406 clicked_regionview = rv;
407 clicked_control_point = 0;
408 clicked_axisview = &rv->get_time_axis_view();
409 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
410 if (event->button.button == 3) {
411 return button_press_handler (item, event, StartCrossFadeItem);
415 case GDK_BUTTON_RELEASE:
416 if (event->button.button == 3) {
417 return button_release_handler (item, event, StartCrossFadeItem);
426 /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
427 /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
428 /* if we return RegionItem here then we avoid the issue until it is resolved later */
429 return typed_event (item, event, RegionItem); // StartCrossFadeItem);
433 Editor::canvas_end_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
435 if (!rv->sensitive()) {
439 switch (event->type) {
440 case GDK_BUTTON_PRESS:
441 clicked_regionview = rv;
442 clicked_control_point = 0;
443 clicked_axisview = &rv->get_time_axis_view();
444 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
445 if (event->button.button == 3) {
446 return button_press_handler (item, event, EndCrossFadeItem);
450 case GDK_BUTTON_RELEASE:
451 if (event->button.button == 3) {
452 return button_release_handler (item, event, EndCrossFadeItem);
461 /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
462 /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
463 /* if we return RegionItem here then we avoid the issue until it is resolved later */
464 return typed_event (item, event, RegionItem); // EndCrossFadeItem);
468 Editor::canvas_fade_in_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
470 /* we handle only button 3 press/release events */
472 if (!rv->sensitive()) {
476 switch (event->type) {
477 case GDK_BUTTON_PRESS:
478 clicked_regionview = rv;
479 clicked_control_point = 0;
480 clicked_axisview = &rv->get_time_axis_view();
481 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
482 if (event->button.button == 3) {
483 return button_press_handler (item, event, FadeInItem);
487 case GDK_BUTTON_RELEASE:
488 if (event->button.button == 3) {
489 return button_release_handler (item, event, FadeInItem);
498 /* proxy for the regionview, except enter/leave events */
500 if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
503 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
508 Editor::canvas_fade_in_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv, bool trim)
512 if (!rv->sensitive()) {
516 switch (event->type) {
517 case GDK_BUTTON_PRESS:
518 case GDK_2BUTTON_PRESS:
519 case GDK_3BUTTON_PRESS:
520 clicked_regionview = rv;
521 clicked_control_point = 0;
522 clicked_axisview = &rv->get_time_axis_view();
523 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
524 ret = button_press_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
527 case GDK_BUTTON_RELEASE:
528 ret = button_release_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
529 maybe_locate_with_edit_preroll ( rv->region()->position() );
532 case GDK_MOTION_NOTIFY:
533 ret = motion_handler (item, event);
536 case GDK_ENTER_NOTIFY:
537 ret = enter_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
540 case GDK_LEAVE_NOTIFY:
541 ret = leave_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
552 Editor::canvas_fade_out_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
554 /* we handle only button 3 press/release events */
556 if (!rv->sensitive()) {
560 switch (event->type) {
561 case GDK_BUTTON_PRESS:
562 clicked_regionview = rv;
563 clicked_control_point = 0;
564 clicked_axisview = &rv->get_time_axis_view();
565 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
566 if (event->button.button == 3) {
567 return button_press_handler (item, event, FadeOutItem);
571 case GDK_BUTTON_RELEASE:
572 if (event->button.button == 3) {
573 return button_release_handler (item, event, FadeOutItem);
582 /* proxy for the regionview, except enter/leave events */
584 if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
587 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
592 Editor::canvas_fade_out_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv, bool trim)
596 if (!rv->sensitive()) {
600 switch (event->type) {
601 case GDK_BUTTON_PRESS:
602 case GDK_2BUTTON_PRESS:
603 case GDK_3BUTTON_PRESS:
604 clicked_regionview = rv;
605 clicked_control_point = 0;
606 clicked_axisview = &rv->get_time_axis_view();
607 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
608 ret = button_press_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
611 case GDK_BUTTON_RELEASE:
612 ret = button_release_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
613 maybe_locate_with_edit_preroll ( rv->region()->last_frame() - rv->get_fade_out_shape_width() );
616 case GDK_MOTION_NOTIFY:
617 ret = motion_handler (item, event);
620 case GDK_ENTER_NOTIFY:
621 ret = enter_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
624 case GDK_LEAVE_NOTIFY:
625 ret = leave_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
635 struct DescendingRegionLayerSorter {
636 bool operator()(boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
637 return a->layer() > b->layer();
642 Editor::canvas_control_point_event (GdkEvent *event, ArdourCanvas::Item* item, ControlPoint* cp)
644 switch (event->type) {
645 case GDK_BUTTON_PRESS:
646 case GDK_2BUTTON_PRESS:
647 case GDK_3BUTTON_PRESS:
648 clicked_control_point = cp;
649 clicked_axisview = &cp->line().trackview;
650 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
651 clicked_regionview = 0;
657 case GDK_SCROLL_DOWN:
664 return typed_event (item, event, ControlPointItem);
668 Editor::canvas_line_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationLine* al)
671 AudioRegionGainLine* gl;
672 if ((gl = dynamic_cast<AudioRegionGainLine*> (al)) != 0) {
674 clicked_regionview = &gl->region_view ();
676 type = AutomationLineItem;
677 clicked_regionview = 0;
680 clicked_control_point = 0;
681 clicked_axisview = &al->trackview;
682 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
684 return typed_event (item, event, type);
688 Editor::canvas_selection_rect_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
692 switch (event->type) {
693 case GDK_BUTTON_PRESS:
694 case GDK_2BUTTON_PRESS:
695 case GDK_3BUTTON_PRESS:
696 clicked_selection = rect->id;
697 ret = button_press_handler (item, event, SelectionItem);
699 case GDK_BUTTON_RELEASE:
700 ret = button_release_handler (item, event, SelectionItem);
702 case GDK_MOTION_NOTIFY:
703 ret = motion_handler (item, event);
705 /* Don't need these at the moment. */
706 case GDK_ENTER_NOTIFY:
707 ret = enter_handler (item, event, SelectionItem);
710 case GDK_LEAVE_NOTIFY:
711 ret = leave_handler (item, event, SelectionItem);
722 Editor::canvas_selection_start_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
726 switch (event->type) {
727 case GDK_BUTTON_PRESS:
728 case GDK_2BUTTON_PRESS:
729 case GDK_3BUTTON_PRESS:
730 clicked_selection = rect->id;
731 ret = button_press_handler (item, event, StartSelectionTrimItem);
733 case GDK_BUTTON_RELEASE:
734 ret = button_release_handler (item, event, StartSelectionTrimItem);
736 case GDK_MOTION_NOTIFY:
737 ret = motion_handler (item, event);
739 case GDK_ENTER_NOTIFY:
740 ret = enter_handler (item, event, StartSelectionTrimItem);
743 case GDK_LEAVE_NOTIFY:
744 ret = leave_handler (item, event, StartSelectionTrimItem);
755 Editor::canvas_selection_end_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
759 switch (event->type) {
760 case GDK_BUTTON_PRESS:
761 case GDK_2BUTTON_PRESS:
762 case GDK_3BUTTON_PRESS:
763 clicked_selection = rect->id;
764 ret = button_press_handler (item, event, EndSelectionTrimItem);
766 case GDK_BUTTON_RELEASE:
767 ret = button_release_handler (item, event, EndSelectionTrimItem);
769 case GDK_MOTION_NOTIFY:
770 ret = motion_handler (item, event);
772 case GDK_ENTER_NOTIFY:
773 ret = enter_handler (item, event, EndSelectionTrimItem);
776 case GDK_LEAVE_NOTIFY:
777 ret = leave_handler (item, event, EndSelectionTrimItem);
788 Editor::canvas_frame_handle_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
792 /* frame handles are not active when in internal edit mode, because actual notes
793 might be in the area occupied by the handle - we want them to be editable as normal.
796 if (internal_editing() || !rv->sensitive()) {
800 /* NOTE: frame handles pretend to be the colored trim bar from an event handling
801 perspective. XXX change this ??
806 if (item->get_data ("isleft")) {
807 type = LeftFrameHandle;
809 type = RightFrameHandle;
812 switch (event->type) {
813 case GDK_BUTTON_PRESS:
814 case GDK_2BUTTON_PRESS:
815 case GDK_3BUTTON_PRESS:
816 clicked_regionview = rv;
817 clicked_control_point = 0;
818 clicked_axisview = &clicked_regionview->get_time_axis_view();
819 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
820 ret = button_press_handler (item, event, type);
822 case GDK_BUTTON_RELEASE:
823 ret = button_release_handler (item, event, type);
825 case GDK_MOTION_NOTIFY:
826 ret = motion_handler (item, event);
828 case GDK_ENTER_NOTIFY:
829 ret = enter_handler (item, event, type);
832 case GDK_LEAVE_NOTIFY:
833 ret = leave_handler (item, event, type);
845 Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
849 if (!rv->sensitive()) {
853 switch (event->type) {
854 case GDK_BUTTON_PRESS:
855 case GDK_2BUTTON_PRESS:
856 case GDK_3BUTTON_PRESS:
857 clicked_regionview = rv;
858 clicked_control_point = 0;
859 clicked_axisview = &clicked_regionview->get_time_axis_view();
860 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
861 ret = button_press_handler (item, event, RegionViewNameHighlight);
863 case GDK_BUTTON_RELEASE:
864 ret = button_release_handler (item, event, RegionViewNameHighlight);
866 case GDK_MOTION_NOTIFY:
867 motion_handler (item, event);
868 ret = true; // force this to avoid progagating the event into the regionview
870 case GDK_ENTER_NOTIFY:
871 ret = enter_handler (item, event, RegionViewNameHighlight);
874 case GDK_LEAVE_NOTIFY:
875 ret = leave_handler (item, event, RegionViewNameHighlight);
886 Editor::canvas_region_view_name_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
890 if (!rv->sensitive()) {
894 switch (event->type) {
895 case GDK_BUTTON_PRESS:
896 case GDK_2BUTTON_PRESS:
897 case GDK_3BUTTON_PRESS:
898 clicked_regionview = rv;
899 clicked_control_point = 0;
900 clicked_axisview = &clicked_regionview->get_time_axis_view();
901 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
902 ret = button_press_handler (item, event, RegionViewName);
904 case GDK_BUTTON_RELEASE:
905 ret = button_release_handler (item, event, RegionViewName);
907 case GDK_MOTION_NOTIFY:
908 ret = motion_handler (item, event);
910 case GDK_ENTER_NOTIFY:
911 ret = enter_handler (item, event, RegionViewName);
914 case GDK_LEAVE_NOTIFY:
915 ret = leave_handler (item, event, RegionViewName);
926 Editor::canvas_feature_line_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView*)
930 switch (event->type) {
931 case GDK_BUTTON_PRESS:
932 case GDK_2BUTTON_PRESS:
933 case GDK_3BUTTON_PRESS:
934 clicked_regionview = 0;
935 clicked_control_point = 0;
936 clicked_axisview = 0;
937 clicked_routeview = 0; //dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
938 ret = button_press_handler (item, event, FeatureLineItem);
941 case GDK_BUTTON_RELEASE:
942 ret = button_release_handler (item, event, FeatureLineItem);
945 case GDK_MOTION_NOTIFY:
946 ret = motion_handler (item, event);
949 case GDK_ENTER_NOTIFY:
950 ret = enter_handler (item, event, FeatureLineItem);
953 case GDK_LEAVE_NOTIFY:
954 ret = leave_handler (item, event, FeatureLineItem);
965 Editor::canvas_marker_event (GdkEvent *event, ArdourCanvas::Item* item, ArdourMarker* /*marker*/)
967 return typed_event (item, event, MarkerItem);
971 Editor::canvas_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
973 return typed_event (item, event, MarkerBarItem);
977 Editor::canvas_range_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
979 return typed_event (item, event, RangeMarkerBarItem);
983 Editor::canvas_transport_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
985 return typed_event (item, event, TransportMarkerBarItem);
989 Editor::canvas_cd_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
991 return typed_event (item, event, CdMarkerBarItem);
995 Editor::canvas_videotl_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
997 return typed_event (item, event, VideoBarItem);
1001 Editor::canvas_tempo_marker_event (GdkEvent *event, ArdourCanvas::Item* item, TempoMarker* /*marker*/)
1003 return typed_event (item, event, TempoMarkerItem);
1007 Editor::canvas_meter_marker_event (GdkEvent *event, ArdourCanvas::Item* item, MeterMarker* /*marker*/)
1009 return typed_event (item, event, MeterMarkerItem);
1013 Editor::canvas_ruler_event (GdkEvent *event, ArdourCanvas::Item* item, ItemType type)
1015 bool handled = false;
1017 if (event->type == GDK_SCROLL) {
1019 /* scroll events in the rulers are handled a little differently from
1020 scrolling elsewhere in the canvas.
1023 switch (event->scroll.direction) {
1025 if (Keyboard::modifier_state_equals(event->scroll.state,
1026 Keyboard::ScrollHorizontalModifier)) {
1027 scroll_left_half_page ();
1028 } else if (Profile->get_mixbus()) {
1029 //for mouse-wheel zoom, force zoom-focus to mouse
1030 temporal_zoom_step_mouse_focus (false);
1032 temporal_zoom_step (false);
1037 case GDK_SCROLL_DOWN:
1038 if (Keyboard::modifier_state_equals(event->scroll.state,
1039 Keyboard::ScrollHorizontalModifier)) {
1040 scroll_right_half_page ();
1041 } else if (Profile->get_mixbus()) {
1042 //for mouse-wheel zoom, force zoom-focus to mouse
1043 temporal_zoom_step_mouse_focus (true);
1045 temporal_zoom_step (true);
1050 case GDK_SCROLL_LEFT:
1051 scroll_left_half_page ();
1055 case GDK_SCROLL_RIGHT:
1056 scroll_right_half_page ();
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_note_event (GdkEvent *event, ArdourCanvas::Item* item)
1091 if (!internal_editing()) {
1095 return typed_event (item, event, NoteItem);
1099 Editor::canvas_drop_zone_event (GdkEvent* event)
1101 GdkEventScroll scroll;
1102 ArdourCanvas::Duple winpos;
1104 switch (event->type) {
1105 case GDK_BUTTON_RELEASE:
1106 if (event->button.button == 1) {
1107 begin_reversible_selection_op (X_("Nowhere Click"));
1108 selection->clear_objects ();
1109 selection->clear_tracks ();
1110 commit_reversible_selection_op ();
1115 /* convert coordinates back into window space so that
1116 we can just call canvas_scroll_event().
1118 winpos = _track_canvas->canvas_to_window (Duple (event->scroll.x, event->scroll.y));
1119 scroll = event->scroll;
1120 scroll.x = winpos.x;
1121 scroll.y = winpos.y;
1122 return canvas_scroll_event (&scroll, true);
1125 case GDK_ENTER_NOTIFY:
1126 return typed_event (_canvas_drop_zone, event, DropZoneItem);
1128 case GDK_LEAVE_NOTIFY:
1129 return typed_event (_canvas_drop_zone, event, DropZoneItem);
1139 Editor::track_canvas_drag_motion (Glib::RefPtr<Gdk::DragContext> const& context, int x, int y, guint time)
1141 boost::shared_ptr<Region> region;
1142 boost::shared_ptr<Region> region_copy;
1143 RouteTimeAxisView* rtav;
1148 string target = _track_canvas->drag_dest_find_target (context, _track_canvas->drag_dest_get_target_list());
1150 if (target.empty()) {
1154 event.type = GDK_MOTION_NOTIFY;
1157 /* assume we're dragging with button 1 */
1158 event.motion.state = Gdk::BUTTON1_MASK;
1160 (void) window_event_sample (&event, &px, &py);
1162 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py, false);
1163 bool can_drop = false;
1165 if (tv.first != 0) {
1167 /* over a time axis view of some kind */
1169 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1171 if (rtav != 0 && rtav->is_track ()) {
1172 /* over a track, not a bus */
1178 /* not over a time axis view, so drop is possible */
1183 region = _regions->get_dragged_region ();
1189 boost::dynamic_pointer_cast<AudioRegion> (region) != 0 ||
1190 boost::dynamic_pointer_cast<MidiRegion> (region) != 0
1194 /* drop to drop-zone */
1195 context->drag_status (context->get_suggested_action(), time);
1199 if ((boost::dynamic_pointer_cast<AudioRegion> (region) != 0 &&
1200 dynamic_cast<AudioTimeAxisView*> (tv.first) != 0) ||
1201 (boost::dynamic_pointer_cast<MidiRegion> (region) != 0 &&
1202 dynamic_cast<MidiTimeAxisView*> (tv.first) != 0)) {
1209 context->drag_status (context->get_suggested_action(), time);
1213 /* DND originating from outside ardour
1215 * TODO: check if file is audio/midi, allow drops on same track-type only,
1216 * currently: if audio is dropped on a midi-track, it is only added to the region-list
1218 if (Profile->get_sae() || UIConfiguration::instance().get_only_copy_imported_files()) {
1219 context->drag_status(Gdk::ACTION_COPY, time);
1221 if ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY) {
1222 context->drag_status(Gdk::ACTION_COPY, time);
1224 context->drag_status(Gdk::ACTION_LINK, time);
1232 context->drag_status (Gdk::DragAction (0), time);
1237 Editor::drop_regions (const Glib::RefPtr<Gdk::DragContext>& /*context*/,
1239 const SelectionData& /*data*/,
1240 guint /*info*/, guint /*time*/)
1246 event.type = GDK_MOTION_NOTIFY;
1249 /* assume we're dragging with button 1 */
1250 event.motion.state = Gdk::BUTTON1_MASK;
1251 framepos_t const pos = window_event_sample (&event, &px, &py);
1253 boost::shared_ptr<Region> region = _regions->get_dragged_region ();
1254 if (!region) { return; }
1256 RouteTimeAxisView* rtav = 0;
1257 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py, false);
1259 if (tv.first != 0) {
1260 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1263 if (boost::dynamic_pointer_cast<AudioRegion> (region)) {
1264 uint32_t output_chan = region->n_channels();
1265 if ((Config->get_output_auto_connect() & AutoConnectMaster) && session()->master_out()) {
1266 output_chan = session()->master_out()->n_inputs().n_audio();
1268 list<boost::shared_ptr<AudioTrack> > audio_tracks;
1269 audio_tracks = session()->new_audio_track (region->n_channels(), output_chan, ARDOUR::Normal, 0, 1, region->name());
1270 rtav = axis_view_from_route (audio_tracks.front());
1271 } else if (boost::dynamic_pointer_cast<MidiRegion> (region)) {
1272 ChanCount one_midi_port (DataType::MIDI, 1);
1273 list<boost::shared_ptr<MidiTrack> > midi_tracks;
1274 midi_tracks = session()->new_midi_track (one_midi_port, one_midi_port, boost::shared_ptr<ARDOUR::PluginInfo>(), ARDOUR::Normal, 0, 1, region->name());
1275 rtav = axis_view_from_route (midi_tracks.front());
1280 error << _("Could not create new track after region placed in the drop zone") << endmsg;
1285 if (rtav != 0 && rtav->is_track ()) {
1286 boost::shared_ptr<Region> region_copy = RegionFactory::create (region, true);
1288 if ((boost::dynamic_pointer_cast<AudioRegion> (region_copy) != 0 && dynamic_cast<AudioTimeAxisView*> (rtav) != 0) ||
1289 (boost::dynamic_pointer_cast<MidiRegion> (region_copy) != 0 && dynamic_cast<MidiTimeAxisView*> (rtav) != 0)) {
1290 _drags->set (new RegionInsertDrag (this, region_copy, rtav, pos), &event);
1291 _drags->end_grab (0);
1297 Editor::key_press_handler (ArdourCanvas::Item*, GdkEvent*, ItemType)
1303 Editor::key_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType type)
1306 bool handled = false;
1309 case TempoMarkerItem:
1310 switch (event->key.keyval) {
1312 remove_tempo_marker (item);
1320 case MeterMarkerItem:
1321 switch (event->key.keyval) {
1323 remove_meter_marker (item);