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 if (UIConfiguration::instance().get_use_mouse_position_as_zoom_focus_on_scroll()) {
79 temporal_zoom_step_mouse_focus (false);
81 temporal_zoom_step (false);
84 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) {
87 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
88 if (!current_stepping_trackview) {
89 step_timeout = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Editor::track_height_step_timeout), 500);
90 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (event_coords.y, false);
91 current_stepping_trackview = p.first;
92 if (!current_stepping_trackview) {
96 last_track_height_step_timestamp = get_microseconds();
97 current_stepping_trackview->step_height (false);
100 scroll_up_one_track ();
105 case GDK_SCROLL_DOWN:
106 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomHorizontalModifier)) {
107 if (UIConfiguration::instance().get_use_mouse_position_as_zoom_focus_on_scroll()) {
108 temporal_zoom_step_mouse_focus (true);
110 temporal_zoom_step (true);
113 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) {
114 scroll_right_step ();
116 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
117 if (!current_stepping_trackview) {
118 step_timeout = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Editor::track_height_step_timeout), 500);
119 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (event_coords.y, false);
120 current_stepping_trackview = p.first;
121 if (!current_stepping_trackview) {
125 last_track_height_step_timestamp = get_microseconds();
126 current_stepping_trackview->step_height (true);
129 scroll_down_one_track ();
134 case GDK_SCROLL_LEFT:
139 case GDK_SCROLL_RIGHT:
140 scroll_right_step ();
153 Editor::canvas_scroll_event (GdkEventScroll *event, bool from_canvas)
156 boost::optional<ArdourCanvas::Rect> rulers = _time_markers_group->bounding_box();
157 if (rulers && rulers->contains (Duple (event->x, event->y))) {
158 return canvas_ruler_event ((GdkEvent*) event, timecode_ruler, TimecodeRulerItem);
162 _track_canvas->grab_focus();
163 return track_canvas_scroll (event);
167 Editor::track_canvas_button_press_event (GdkEventButton *event)
169 _track_canvas->grab_focus();
170 if (!Keyboard::is_context_menu_event (event)) {
171 begin_reversible_selection_op (X_("Clear Selection Click (track canvas)"));
173 commit_reversible_selection_op();
179 Editor::track_canvas_button_release_event (GdkEventButton *event)
181 if (!Keyboard::is_context_menu_event (event)) {
182 if (_drags->active ()) {
183 _drags->end_grab ((GdkEvent*) event);
190 Editor::track_canvas_motion_notify_event (GdkEventMotion */*event*/)
193 /* keep those motion events coming */
194 _track_canvas->get_pointer (x, y);
199 Editor::typed_event (ArdourCanvas::Item* item, GdkEvent *event, ItemType type)
201 if (!session () || session()->loading () || session()->deletion_in_progress ()) {
207 switch (event->type) {
208 case GDK_BUTTON_PRESS:
209 case GDK_2BUTTON_PRESS:
210 case GDK_3BUTTON_PRESS:
211 ret = button_press_handler (item, event, type);
213 case GDK_BUTTON_RELEASE:
214 ret = button_release_handler (item, event, type);
216 case GDK_MOTION_NOTIFY:
217 ret = motion_handler (item, event);
220 case GDK_ENTER_NOTIFY:
221 ret = enter_handler (item, event, type);
224 case GDK_LEAVE_NOTIFY:
225 ret = leave_handler (item, event, type);
229 ret = key_press_handler (item, event, type);
232 case GDK_KEY_RELEASE:
233 ret = key_release_handler (item, event, type);
243 Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView *rv)
247 if (!rv->sensitive ()) {
251 switch (event->type) {
252 case GDK_BUTTON_PRESS:
253 case GDK_2BUTTON_PRESS:
254 case GDK_3BUTTON_PRESS:
255 clicked_regionview = rv;
256 clicked_control_point = 0;
257 clicked_axisview = &rv->get_time_axis_view();
258 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
259 ret = button_press_handler (item, event, RegionItem);
262 case GDK_BUTTON_RELEASE:
263 ret = button_release_handler (item, event, RegionItem);
266 case GDK_MOTION_NOTIFY:
267 ret = motion_handler (item, event);
270 case GDK_ENTER_NOTIFY:
271 set_entered_regionview (rv);
272 ret = enter_handler (item, event, RegionItem);
275 case GDK_LEAVE_NOTIFY:
276 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) {
277 set_entered_regionview (0);
278 ret = leave_handler (item, event, RegionItem);
290 Editor::canvas_wave_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
292 /* we only care about enter events here, required for mouse/cursor
293 * tracking. there is a non-linear (non-child/non-parent) relationship
294 * between various components of a regionview and so when we leave one
295 * of them (e.g. a trim handle) and enter another (e.g. the waveview)
296 * no other items get notified. enter/leave handling does not propagate
297 * in the same way as other events, so we need to catch this because
298 * entering (and leaving) the waveview is equivalent to
299 * entering/leaving the regionview (which is why it is passed in as a
302 * And in fact, we really only care about enter events.
307 if (!rv->sensitive ()) {
311 switch (event->type) {
312 case GDK_ENTER_NOTIFY:
313 set_entered_regionview (rv);
314 ret = enter_handler (item, event, WaveItem);
326 Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, RouteTimeAxisView *tv)
330 switch (event->type) {
331 case GDK_BUTTON_PRESS:
332 case GDK_2BUTTON_PRESS:
333 case GDK_3BUTTON_PRESS:
334 clicked_regionview = 0;
335 clicked_control_point = 0;
336 clicked_axisview = tv;
337 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
338 ret = button_press_handler (item, event, StreamItem);
341 case GDK_BUTTON_RELEASE:
342 ret = button_release_handler (item, event, StreamItem);
345 case GDK_MOTION_NOTIFY:
346 ret = motion_handler (item, event);
349 case GDK_ENTER_NOTIFY:
350 set_entered_track (tv);
351 ret = enter_handler (item, event, StreamItem);
354 case GDK_LEAVE_NOTIFY:
355 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) {
356 set_entered_track (0);
358 ret = leave_handler (item, event, StreamItem);
369 Editor::canvas_automation_track_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationTimeAxisView *atv)
373 switch (event->type) {
374 case GDK_BUTTON_PRESS:
375 case GDK_2BUTTON_PRESS:
376 case GDK_3BUTTON_PRESS:
377 clicked_regionview = 0;
378 clicked_control_point = 0;
379 clicked_axisview = atv;
380 clicked_routeview = 0;
381 ret = button_press_handler (item, event, AutomationTrackItem);
384 case GDK_BUTTON_RELEASE:
385 ret = button_release_handler (item, event, AutomationTrackItem);
388 case GDK_MOTION_NOTIFY:
389 ret = motion_handler (item, event);
392 case GDK_ENTER_NOTIFY:
393 ret = enter_handler (item, event, AutomationTrackItem);
396 case GDK_LEAVE_NOTIFY:
397 ret = leave_handler (item, event, AutomationTrackItem);
408 Editor::canvas_start_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
410 if (!rv->sensitive()) {
414 switch (event->type) {
415 case GDK_BUTTON_PRESS:
416 clicked_regionview = rv;
417 clicked_control_point = 0;
418 clicked_axisview = &rv->get_time_axis_view();
419 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
420 if (event->button.button == 3) {
421 return button_press_handler (item, event, StartCrossFadeItem);
425 case GDK_BUTTON_RELEASE:
426 if (event->button.button == 3) {
427 return button_release_handler (item, event, StartCrossFadeItem);
436 /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
437 /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
438 /* if we return RegionItem here then we avoid the issue until it is resolved later */
439 return typed_event (item, event, RegionItem); // StartCrossFadeItem);
443 Editor::canvas_end_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
445 if (!rv->sensitive()) {
449 switch (event->type) {
450 case GDK_BUTTON_PRESS:
451 clicked_regionview = rv;
452 clicked_control_point = 0;
453 clicked_axisview = &rv->get_time_axis_view();
454 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
455 if (event->button.button == 3) {
456 return button_press_handler (item, event, EndCrossFadeItem);
460 case GDK_BUTTON_RELEASE:
461 if (event->button.button == 3) {
462 return button_release_handler (item, event, EndCrossFadeItem);
471 /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
472 /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
473 /* if we return RegionItem here then we avoid the issue until it is resolved later */
474 return typed_event (item, event, RegionItem); // EndCrossFadeItem);
478 Editor::canvas_fade_in_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
480 /* we handle only button 3 press/release events */
482 if (!rv->sensitive()) {
486 switch (event->type) {
487 case GDK_BUTTON_PRESS:
488 clicked_regionview = rv;
489 clicked_control_point = 0;
490 clicked_axisview = &rv->get_time_axis_view();
491 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
492 if (event->button.button == 3) {
493 return button_press_handler (item, event, FadeInItem);
497 case GDK_BUTTON_RELEASE:
498 if (event->button.button == 3) {
499 return button_release_handler (item, event, FadeInItem);
508 /* proxy for the regionview, except enter/leave events */
510 if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
513 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
518 Editor::canvas_fade_in_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv, bool trim)
522 if (!rv->sensitive()) {
526 switch (event->type) {
527 case GDK_BUTTON_PRESS:
528 case GDK_2BUTTON_PRESS:
529 case GDK_3BUTTON_PRESS:
530 clicked_regionview = rv;
531 clicked_control_point = 0;
532 clicked_axisview = &rv->get_time_axis_view();
533 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
534 ret = button_press_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
537 case GDK_BUTTON_RELEASE:
538 ret = button_release_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
541 case GDK_MOTION_NOTIFY:
542 ret = motion_handler (item, event);
545 case GDK_ENTER_NOTIFY:
546 ret = enter_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
549 case GDK_LEAVE_NOTIFY:
550 ret = leave_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
561 Editor::canvas_fade_out_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
563 /* we handle only button 3 press/release events */
565 if (!rv->sensitive()) {
569 switch (event->type) {
570 case GDK_BUTTON_PRESS:
571 clicked_regionview = rv;
572 clicked_control_point = 0;
573 clicked_axisview = &rv->get_time_axis_view();
574 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
575 if (event->button.button == 3) {
576 return button_press_handler (item, event, FadeOutItem);
580 case GDK_BUTTON_RELEASE:
581 if (event->button.button == 3) {
582 return button_release_handler (item, event, FadeOutItem);
591 /* proxy for the regionview, except enter/leave events */
593 if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
596 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
601 Editor::canvas_fade_out_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv, bool trim)
605 if (!rv->sensitive()) {
609 switch (event->type) {
610 case GDK_BUTTON_PRESS:
611 case GDK_2BUTTON_PRESS:
612 case GDK_3BUTTON_PRESS:
613 clicked_regionview = rv;
614 clicked_control_point = 0;
615 clicked_axisview = &rv->get_time_axis_view();
616 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
617 ret = button_press_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
620 case GDK_BUTTON_RELEASE:
621 ret = button_release_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
624 case GDK_MOTION_NOTIFY:
625 ret = motion_handler (item, event);
628 case GDK_ENTER_NOTIFY:
629 ret = enter_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
632 case GDK_LEAVE_NOTIFY:
633 ret = leave_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
643 struct DescendingRegionLayerSorter {
644 bool operator()(boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
645 return a->layer() > b->layer();
650 Editor::canvas_control_point_event (GdkEvent *event, ArdourCanvas::Item* item, ControlPoint* cp)
652 switch (event->type) {
653 case GDK_BUTTON_PRESS:
654 case GDK_2BUTTON_PRESS:
655 case GDK_3BUTTON_PRESS:
656 clicked_control_point = cp;
657 clicked_axisview = &cp->line().trackview;
658 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
659 clicked_regionview = 0;
665 case GDK_SCROLL_DOWN:
672 return typed_event (item, event, ControlPointItem);
676 Editor::canvas_line_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationLine* al)
679 AudioRegionGainLine* gl;
680 if ((gl = dynamic_cast<AudioRegionGainLine*> (al)) != 0) {
682 if (event->type == GDK_BUTTON_PRESS) {
683 clicked_regionview = &gl->region_view ();
686 type = AutomationLineItem;
687 if (event->type == GDK_BUTTON_PRESS) {
688 clicked_regionview = 0;
692 clicked_control_point = 0;
693 clicked_axisview = &al->trackview;
694 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
696 return typed_event (item, event, type);
700 Editor::canvas_selection_rect_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
704 switch (event->type) {
705 case GDK_BUTTON_PRESS:
706 case GDK_2BUTTON_PRESS:
707 case GDK_3BUTTON_PRESS:
708 clicked_selection = rect->id;
709 ret = button_press_handler (item, event, SelectionItem);
711 case GDK_BUTTON_RELEASE:
712 ret = button_release_handler (item, event, SelectionItem);
714 case GDK_MOTION_NOTIFY:
715 ret = motion_handler (item, event);
717 /* Don't need these at the moment. */
718 case GDK_ENTER_NOTIFY:
719 ret = enter_handler (item, event, SelectionItem);
722 case GDK_LEAVE_NOTIFY:
723 ret = leave_handler (item, event, SelectionItem);
734 Editor::canvas_selection_start_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
738 switch (event->type) {
739 case GDK_BUTTON_PRESS:
740 case GDK_2BUTTON_PRESS:
741 case GDK_3BUTTON_PRESS:
742 clicked_selection = rect->id;
743 ret = button_press_handler (item, event, StartSelectionTrimItem);
745 case GDK_BUTTON_RELEASE:
746 ret = button_release_handler (item, event, StartSelectionTrimItem);
748 case GDK_MOTION_NOTIFY:
749 ret = motion_handler (item, event);
751 case GDK_ENTER_NOTIFY:
752 ret = enter_handler (item, event, StartSelectionTrimItem);
755 case GDK_LEAVE_NOTIFY:
756 ret = leave_handler (item, event, StartSelectionTrimItem);
767 Editor::canvas_selection_end_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
771 switch (event->type) {
772 case GDK_BUTTON_PRESS:
773 case GDK_2BUTTON_PRESS:
774 case GDK_3BUTTON_PRESS:
775 clicked_selection = rect->id;
776 ret = button_press_handler (item, event, EndSelectionTrimItem);
778 case GDK_BUTTON_RELEASE:
779 ret = button_release_handler (item, event, EndSelectionTrimItem);
781 case GDK_MOTION_NOTIFY:
782 ret = motion_handler (item, event);
784 case GDK_ENTER_NOTIFY:
785 ret = enter_handler (item, event, EndSelectionTrimItem);
788 case GDK_LEAVE_NOTIFY:
789 ret = leave_handler (item, event, EndSelectionTrimItem);
800 Editor::canvas_sample_handle_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
804 /* sample handles are not active when in internal edit mode, because actual notes
805 might be in the area occupied by the handle - we want them to be editable as normal.
808 if (internal_editing() || !rv->sensitive()) {
812 /* NOTE: sample handles pretend to be the colored trim bar from an event handling
813 perspective. XXX change this ??
818 if (item->get_data ("isleft")) {
819 type = LeftFrameHandle;
821 type = RightFrameHandle;
824 switch (event->type) {
825 case GDK_BUTTON_PRESS:
826 case GDK_2BUTTON_PRESS:
827 case GDK_3BUTTON_PRESS:
828 clicked_regionview = rv;
829 clicked_control_point = 0;
830 clicked_axisview = &clicked_regionview->get_time_axis_view();
831 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
832 ret = button_press_handler (item, event, type);
834 case GDK_BUTTON_RELEASE:
835 ret = button_release_handler (item, event, type);
837 case GDK_MOTION_NOTIFY:
838 ret = motion_handler (item, event);
840 case GDK_ENTER_NOTIFY:
841 ret = enter_handler (item, event, type);
844 case GDK_LEAVE_NOTIFY:
845 ret = leave_handler (item, event, type);
857 Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
861 if (!rv->sensitive()) {
865 switch (event->type) {
866 case GDK_BUTTON_PRESS:
867 case GDK_2BUTTON_PRESS:
868 case GDK_3BUTTON_PRESS:
869 clicked_regionview = rv;
870 clicked_control_point = 0;
871 clicked_axisview = &clicked_regionview->get_time_axis_view();
872 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
873 ret = button_press_handler (item, event, RegionViewNameHighlight);
875 case GDK_BUTTON_RELEASE:
876 ret = button_release_handler (item, event, RegionViewNameHighlight);
878 case GDK_MOTION_NOTIFY:
879 motion_handler (item, event);
880 ret = true; // force this to avoid progagating the event into the regionview
882 case GDK_ENTER_NOTIFY:
883 ret = enter_handler (item, event, RegionViewNameHighlight);
886 case GDK_LEAVE_NOTIFY:
887 ret = leave_handler (item, event, RegionViewNameHighlight);
898 Editor::canvas_region_view_name_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
902 if (!rv->sensitive()) {
906 switch (event->type) {
907 case GDK_BUTTON_PRESS:
908 case GDK_2BUTTON_PRESS:
909 case GDK_3BUTTON_PRESS:
910 clicked_regionview = rv;
911 clicked_control_point = 0;
912 clicked_axisview = &clicked_regionview->get_time_axis_view();
913 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
914 ret = button_press_handler (item, event, RegionViewName);
916 case GDK_BUTTON_RELEASE:
917 ret = button_release_handler (item, event, RegionViewName);
919 case GDK_MOTION_NOTIFY:
920 ret = motion_handler (item, event);
922 case GDK_ENTER_NOTIFY:
923 ret = enter_handler (item, event, RegionViewName);
926 case GDK_LEAVE_NOTIFY:
927 ret = leave_handler (item, event, RegionViewName);
938 Editor::canvas_feature_line_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView*)
942 switch (event->type) {
943 case GDK_BUTTON_PRESS:
944 case GDK_2BUTTON_PRESS:
945 case GDK_3BUTTON_PRESS:
946 clicked_regionview = 0;
947 clicked_control_point = 0;
948 clicked_axisview = 0;
949 clicked_routeview = 0; //dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
950 ret = button_press_handler (item, event, FeatureLineItem);
953 case GDK_BUTTON_RELEASE:
954 ret = button_release_handler (item, event, FeatureLineItem);
957 case GDK_MOTION_NOTIFY:
958 ret = motion_handler (item, event);
961 case GDK_ENTER_NOTIFY:
962 ret = enter_handler (item, event, FeatureLineItem);
965 case GDK_LEAVE_NOTIFY:
966 ret = leave_handler (item, event, FeatureLineItem);
977 Editor::canvas_marker_event (GdkEvent *event, ArdourCanvas::Item* item, ArdourMarker* /*marker*/)
979 return typed_event (item, event, MarkerItem);
983 Editor::canvas_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
985 return typed_event (item, event, MarkerBarItem);
989 Editor::canvas_range_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
991 return typed_event (item, event, RangeMarkerBarItem);
995 Editor::canvas_transport_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
997 return typed_event (item, event, TransportMarkerBarItem);
1001 Editor::canvas_cd_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1003 return typed_event (item, event, CdMarkerBarItem);
1007 Editor::canvas_videotl_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1009 return typed_event (item, event, VideoBarItem);
1013 Editor::canvas_tempo_marker_event (GdkEvent *event, ArdourCanvas::Item* item, TempoMarker* marker)
1015 return typed_event (item, event, TempoMarkerItem);
1019 Editor::canvas_tempo_curve_event (GdkEvent *event, ArdourCanvas::Item* item, TempoCurve* /*marker*/)
1021 return typed_event (item, event, TempoCurveItem);
1025 Editor::canvas_meter_marker_event (GdkEvent *event, ArdourCanvas::Item* item, MeterMarker* /*marker*/)
1027 return typed_event (item, event, MeterMarkerItem);
1031 Editor::canvas_ruler_event (GdkEvent *event, ArdourCanvas::Item* item, ItemType type)
1033 bool handled = false;
1035 if (event->type == GDK_SCROLL) {
1037 /* scroll events in the rulers are handled a little differently from
1038 scrolling elsewhere in the canvas.
1041 switch (event->scroll.direction) {
1043 if (Keyboard::modifier_state_equals(event->scroll.state,
1044 Keyboard::ScrollHorizontalModifier)) {
1045 scroll_left_step ();
1046 } else if (UIConfiguration::instance().get_use_mouse_position_as_zoom_focus_on_scroll()) {
1047 temporal_zoom_step_mouse_focus (false);
1049 temporal_zoom_step (false);
1054 case GDK_SCROLL_DOWN:
1055 if (Keyboard::modifier_state_equals(event->scroll.state,
1056 Keyboard::ScrollHorizontalModifier)) {
1057 scroll_right_step ();
1058 } else if (UIConfiguration::instance().get_use_mouse_position_as_zoom_focus_on_scroll()) {
1059 temporal_zoom_step_mouse_focus (true);
1061 temporal_zoom_step (true);
1066 case GDK_SCROLL_LEFT:
1067 scroll_left_half_page ();
1071 case GDK_SCROLL_RIGHT:
1072 scroll_right_half_page ();
1083 return typed_event (item, event, type);
1087 Editor::canvas_tempo_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1089 return typed_event (item, event, TempoBarItem);
1093 Editor::canvas_meter_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1095 return typed_event (item, event, MeterBarItem);
1099 Editor::canvas_playhead_cursor_event (GdkEvent *event, ArdourCanvas::Item* item)
1101 return typed_event (item, event, PlayheadCursorItem);
1105 Editor::canvas_note_event (GdkEvent *event, ArdourCanvas::Item* item)
1107 if (!internal_editing()) {
1111 return typed_event (item, event, NoteItem);
1115 Editor::canvas_drop_zone_event (GdkEvent* event)
1117 GdkEventScroll scroll;
1118 ArdourCanvas::Duple winpos;
1120 switch (event->type) {
1121 case GDK_BUTTON_RELEASE:
1122 if (event->button.button == 1) {
1123 begin_reversible_selection_op (X_("Nowhere Click"));
1124 selection->clear_objects ();
1125 selection->clear_tracks ();
1126 commit_reversible_selection_op ();
1131 /* convert coordinates back into window space so that
1132 we can just call canvas_scroll_event().
1134 winpos = _track_canvas->canvas_to_window (Duple (event->scroll.x, event->scroll.y));
1135 scroll = event->scroll;
1136 scroll.x = winpos.x;
1137 scroll.y = winpos.y;
1138 return canvas_scroll_event (&scroll, true);
1141 case GDK_ENTER_NOTIFY:
1142 return typed_event (_canvas_drop_zone, event, DropZoneItem);
1144 case GDK_LEAVE_NOTIFY:
1145 return typed_event (_canvas_drop_zone, event, DropZoneItem);
1155 Editor::track_canvas_drag_motion (Glib::RefPtr<Gdk::DragContext> const& context, int x, int y, guint time)
1157 boost::shared_ptr<Region> region;
1158 boost::shared_ptr<Region> region_copy;
1159 RouteTimeAxisView* rtav;
1164 string target = _track_canvas->drag_dest_find_target (context, _track_canvas->drag_dest_get_target_list());
1166 if (target.empty()) {
1170 event.type = GDK_MOTION_NOTIFY;
1173 /* assume we're dragging with button 1 */
1174 event.motion.state = Gdk::BUTTON1_MASK;
1176 (void) window_event_sample (&event, &px, &py);
1178 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py, false);
1179 bool can_drop = false;
1181 if (tv.first != 0) {
1183 /* over a time axis view of some kind */
1185 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1187 if (rtav != 0 && rtav->is_track ()) {
1188 /* over a track, not a bus */
1194 /* not over a time axis view, so drop is possible */
1199 region = _regions->get_dragged_region ();
1205 boost::dynamic_pointer_cast<AudioRegion> (region) != 0 ||
1206 boost::dynamic_pointer_cast<MidiRegion> (region) != 0
1210 /* drop to drop-zone */
1211 context->drag_status (context->get_suggested_action(), time);
1215 if ((boost::dynamic_pointer_cast<AudioRegion> (region) != 0 &&
1216 dynamic_cast<AudioTimeAxisView*> (tv.first) != 0) ||
1217 (boost::dynamic_pointer_cast<MidiRegion> (region) != 0 &&
1218 dynamic_cast<MidiTimeAxisView*> (tv.first) != 0)) {
1225 context->drag_status (context->get_suggested_action(), time);
1229 /* DND originating from outside ardour
1231 * TODO: check if file is audio/midi, allow drops on same track-type only,
1232 * currently: if audio is dropped on a midi-track, it is only added to the region-list
1234 if (UIConfiguration::instance().get_only_copy_imported_files()) {
1235 context->drag_status(Gdk::ACTION_COPY, time);
1237 if ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY) {
1238 context->drag_status(Gdk::ACTION_COPY, time);
1240 context->drag_status(Gdk::ACTION_LINK, time);
1248 context->drag_status (Gdk::DragAction (0), time);
1253 Editor::drop_regions (const Glib::RefPtr<Gdk::DragContext>& /*context*/,
1255 const SelectionData& /*data*/,
1256 guint /*info*/, guint /*time*/)
1262 event.type = GDK_MOTION_NOTIFY;
1265 /* assume we're dragging with button 1 */
1266 event.motion.state = Gdk::BUTTON1_MASK;
1267 samplepos_t const pos = window_event_sample (&event, &px, &py);
1269 boost::shared_ptr<Region> region = _regions->get_dragged_region ();
1270 if (!region) { return; }
1272 RouteTimeAxisView* rtav = 0;
1273 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py, false);
1275 if (tv.first != 0) {
1276 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1279 if (boost::dynamic_pointer_cast<AudioRegion> (region)) {
1280 uint32_t output_chan = region->n_channels();
1281 if ((Config->get_output_auto_connect() & AutoConnectMaster) && session()->master_out()) {
1282 output_chan = session()->master_out()->n_inputs().n_audio();
1284 list<boost::shared_ptr<AudioTrack> > audio_tracks;
1285 audio_tracks = session()->new_audio_track (region->n_channels(), output_chan, 0, 1, region->name(), PresentationInfo::max_order);
1286 rtav = dynamic_cast<RouteTimeAxisView*> (time_axis_view_from_stripable (audio_tracks.front()));
1287 } else if (boost::dynamic_pointer_cast<MidiRegion> (region)) {
1288 ChanCount one_midi_port (DataType::MIDI, 1);
1289 list<boost::shared_ptr<MidiTrack> > midi_tracks;
1290 midi_tracks = session()->new_midi_track (one_midi_port, one_midi_port,
1291 Config->get_strict_io () || Profile->get_mixbus (),
1292 boost::shared_ptr<ARDOUR::PluginInfo>(),
1293 (ARDOUR::Plugin::PresetRecord*) 0,
1294 (ARDOUR::RouteGroup*) 0, 1, region->name(), PresentationInfo::max_order);
1295 rtav = dynamic_cast<RouteTimeAxisView*> (time_axis_view_from_stripable (midi_tracks.front()));
1300 error << _("Could not create new track after region placed in the drop zone") << endmsg;
1305 if (rtav != 0 && rtav->is_track ()) {
1306 boost::shared_ptr<Region> region_copy = RegionFactory::create (region, true);
1308 if ((boost::dynamic_pointer_cast<AudioRegion> (region_copy) != 0 && dynamic_cast<AudioTimeAxisView*> (rtav) != 0) ||
1309 (boost::dynamic_pointer_cast<MidiRegion> (region_copy) != 0 && dynamic_cast<MidiTimeAxisView*> (rtav) != 0)) {
1310 _drags->set (new RegionInsertDrag (this, region_copy, rtav, pos), &event);
1311 _drags->end_grab (&event);
1317 Editor::key_press_handler (ArdourCanvas::Item*, GdkEvent*, ItemType)
1323 Editor::key_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType type)
1326 bool handled = false;
1329 case TempoMarkerItem:
1330 switch (event->key.keyval) {
1332 remove_tempo_marker (item);
1340 case MeterMarkerItem:
1341 switch (event->key.keyval) {
1343 remove_meter_marker (item);