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)
68 int direction = ev->direction;
70 /* this event arrives without transformation by the canvas, so we have
71 * to transform the coordinates to be able to look things up.
74 Duple event_coords = _track_canvas->window_to_canvas (Duple (ev->x, ev->y));
79 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomHorizontalModifier)) {
80 //for mouse-wheel zoom, force zoom-focus to mouse
81 Editing::ZoomFocus temp_focus = zoom_focus;
82 zoom_focus = Editing::ZoomFocusMouse;
83 temporal_zoom_step (false);
84 zoom_focus = temp_focus;
86 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) {
87 direction = GDK_SCROLL_LEFT;
89 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
90 if (!current_stepping_trackview) {
91 step_timeout = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Editor::track_height_step_timeout), 500);
92 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (event_coords.y, false);
93 current_stepping_trackview = p.first;
94 if (!current_stepping_trackview) {
98 last_track_height_step_timestamp = get_microseconds();
99 current_stepping_trackview->step_height (false);
102 scroll_up_one_track ();
107 case GDK_SCROLL_DOWN:
108 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomHorizontalModifier)) {
109 //for mouse-wheel zoom, force zoom-focus to mouse
110 Editing::ZoomFocus temp_focus = zoom_focus;
111 zoom_focus = Editing::ZoomFocusMouse;
112 temporal_zoom_step (true);
113 zoom_focus = temp_focus;
115 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) {
116 direction = GDK_SCROLL_RIGHT;
118 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
119 if (!current_stepping_trackview) {
120 step_timeout = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Editor::track_height_step_timeout), 500);
121 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (event_coords.y, false);
122 current_stepping_trackview = p.first;
123 if (!current_stepping_trackview) {
127 last_track_height_step_timestamp = get_microseconds();
128 current_stepping_trackview->step_height (true);
131 scroll_down_one_track ();
136 case GDK_SCROLL_LEFT:
137 xdelta = (current_page_samples() / 8);
138 if (leftmost_frame > xdelta) {
139 reset_x_origin (leftmost_frame - xdelta);
145 case GDK_SCROLL_RIGHT:
146 xdelta = (current_page_samples() / 8);
147 if (max_framepos - xdelta > leftmost_frame) {
148 reset_x_origin (leftmost_frame + xdelta);
150 reset_x_origin (max_framepos - current_page_samples());
163 Editor::canvas_scroll_event (GdkEventScroll *event, bool from_canvas)
166 boost::optional<ArdourCanvas::Rect> rulers = _time_markers_group->bounding_box();
167 if (rulers && rulers->contains (Duple (event->x, event->y))) {
168 return canvas_ruler_event ((GdkEvent*) event, timecode_ruler, TimecodeRulerItem);
172 _track_canvas->grab_focus();
173 return track_canvas_scroll (event);
177 Editor::track_canvas_button_press_event (GdkEventButton *event)
179 _track_canvas->grab_focus();
180 if (!Keyboard::is_context_menu_event (event)) {
181 begin_reversible_selection_op (X_("Clear Selection Click (track canvas)"));
183 commit_reversible_selection_op();
189 Editor::track_canvas_button_release_event (GdkEventButton *event)
191 if (!Keyboard::is_context_menu_event (event)) {
192 if (_drags->active ()) {
193 _drags->end_grab ((GdkEvent*) event);
200 Editor::track_canvas_motion_notify_event (GdkEventMotion */*event*/)
203 /* keep those motion events coming */
204 _track_canvas->get_pointer (x, y);
209 Editor::typed_event (ArdourCanvas::Item* item, GdkEvent *event, ItemType type)
213 switch (event->type) {
214 case GDK_BUTTON_PRESS:
215 case GDK_2BUTTON_PRESS:
216 case GDK_3BUTTON_PRESS:
217 ret = button_press_handler (item, event, type);
219 case GDK_BUTTON_RELEASE:
220 ret = button_release_handler (item, event, type);
222 case GDK_MOTION_NOTIFY:
223 ret = motion_handler (item, event);
226 case GDK_ENTER_NOTIFY:
227 ret = enter_handler (item, event, type);
230 case GDK_LEAVE_NOTIFY:
231 ret = leave_handler (item, event, type);
235 ret = key_press_handler (item, event, type);
238 case GDK_KEY_RELEASE:
239 ret = key_release_handler (item, event, type);
249 Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView *rv)
253 if (!rv->sensitive ()) {
257 switch (event->type) {
258 case GDK_BUTTON_PRESS:
259 case GDK_2BUTTON_PRESS:
260 case GDK_3BUTTON_PRESS:
261 clicked_regionview = rv;
262 clicked_control_point = 0;
263 clicked_axisview = &rv->get_time_axis_view();
264 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
265 ret = button_press_handler (item, event, RegionItem);
268 case GDK_BUTTON_RELEASE:
269 ret = button_release_handler (item, event, RegionItem);
272 case GDK_MOTION_NOTIFY:
273 ret = motion_handler (item, event);
276 case GDK_ENTER_NOTIFY:
277 set_entered_regionview (rv);
278 ret = enter_handler (item, event, RegionItem);
281 case GDK_LEAVE_NOTIFY:
282 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) {
283 set_entered_regionview (0);
284 ret = leave_handler (item, event, RegionItem);
296 Editor::canvas_wave_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
298 /* we only care about enter events here, required for mouse/cursor
299 * tracking. there is a non-linear (non-child/non-parent) relationship
300 * between various components of a regionview and so when we leave one
301 * of them (e.g. a trim handle) and enter another (e.g. the waveview)
302 * no other items get notified. enter/leave handling does not propagate
303 * in the same way as other events, so we need to catch this because
304 * entering (and leaving) the waveview is equivalent to
305 * entering/leaving the regionview (which is why it is passed in as a
308 * And in fact, we really only care about enter events.
313 if (!rv->sensitive ()) {
317 switch (event->type) {
318 case GDK_ENTER_NOTIFY:
319 set_entered_regionview (rv);
320 ret = enter_handler (item, event, WaveItem);
332 Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, RouteTimeAxisView *tv)
336 switch (event->type) {
337 case GDK_BUTTON_PRESS:
338 case GDK_2BUTTON_PRESS:
339 case GDK_3BUTTON_PRESS:
340 clicked_regionview = 0;
341 clicked_control_point = 0;
342 clicked_axisview = tv;
343 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
344 ret = button_press_handler (item, event, StreamItem);
347 case GDK_BUTTON_RELEASE:
348 ret = button_release_handler (item, event, StreamItem);
351 case GDK_MOTION_NOTIFY:
352 ret = motion_handler (item, event);
355 case GDK_ENTER_NOTIFY:
356 set_entered_track (tv);
357 ret = enter_handler (item, event, StreamItem);
360 case GDK_LEAVE_NOTIFY:
361 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) {
362 set_entered_track (0);
364 ret = leave_handler (item, event, StreamItem);
375 Editor::canvas_automation_track_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationTimeAxisView *atv)
379 switch (event->type) {
380 case GDK_BUTTON_PRESS:
381 case GDK_2BUTTON_PRESS:
382 case GDK_3BUTTON_PRESS:
383 clicked_regionview = 0;
384 clicked_control_point = 0;
385 clicked_axisview = atv;
386 clicked_routeview = 0;
387 ret = button_press_handler (item, event, AutomationTrackItem);
390 case GDK_BUTTON_RELEASE:
391 ret = button_release_handler (item, event, AutomationTrackItem);
394 case GDK_MOTION_NOTIFY:
395 ret = motion_handler (item, event);
398 case GDK_ENTER_NOTIFY:
399 ret = enter_handler (item, event, AutomationTrackItem);
402 case GDK_LEAVE_NOTIFY:
403 ret = leave_handler (item, event, AutomationTrackItem);
414 Editor::canvas_start_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
416 if (!rv->sensitive()) {
420 switch (event->type) {
421 case GDK_BUTTON_PRESS:
422 clicked_regionview = rv;
423 clicked_control_point = 0;
424 clicked_axisview = &rv->get_time_axis_view();
425 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
426 if (event->button.button == 3) {
427 return button_press_handler (item, event, StartCrossFadeItem);
431 case GDK_BUTTON_RELEASE:
432 if (event->button.button == 3) {
433 return button_release_handler (item, event, StartCrossFadeItem);
442 /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
443 /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
444 /* if we return RegionItem here then we avoid the issue until it is resolved later */
445 return typed_event (item, event, RegionItem); // StartCrossFadeItem);
449 Editor::canvas_end_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
451 if (!rv->sensitive()) {
455 switch (event->type) {
456 case GDK_BUTTON_PRESS:
457 clicked_regionview = rv;
458 clicked_control_point = 0;
459 clicked_axisview = &rv->get_time_axis_view();
460 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
461 if (event->button.button == 3) {
462 return button_press_handler (item, event, EndCrossFadeItem);
466 case GDK_BUTTON_RELEASE:
467 if (event->button.button == 3) {
468 return button_release_handler (item, event, EndCrossFadeItem);
477 /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
478 /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
479 /* if we return RegionItem here then we avoid the issue until it is resolved later */
480 return typed_event (item, event, RegionItem); // EndCrossFadeItem);
484 Editor::canvas_fade_in_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
486 /* we handle only button 3 press/release events */
488 if (!rv->sensitive()) {
492 switch (event->type) {
493 case GDK_BUTTON_PRESS:
494 clicked_regionview = rv;
495 clicked_control_point = 0;
496 clicked_axisview = &rv->get_time_axis_view();
497 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
498 if (event->button.button == 3) {
499 return button_press_handler (item, event, FadeInItem);
503 case GDK_BUTTON_RELEASE:
504 if (event->button.button == 3) {
505 return button_release_handler (item, event, FadeInItem);
514 /* proxy for the regionview, except enter/leave events */
516 if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
519 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
524 Editor::canvas_fade_in_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv, bool trim)
528 if (!rv->sensitive()) {
532 switch (event->type) {
533 case GDK_BUTTON_PRESS:
534 case GDK_2BUTTON_PRESS:
535 case GDK_3BUTTON_PRESS:
536 clicked_regionview = rv;
537 clicked_control_point = 0;
538 clicked_axisview = &rv->get_time_axis_view();
539 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
540 ret = button_press_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
543 case GDK_BUTTON_RELEASE:
544 ret = button_release_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
545 maybe_locate_with_edit_preroll ( rv->region()->position() );
548 case GDK_MOTION_NOTIFY:
549 ret = motion_handler (item, event);
552 case GDK_ENTER_NOTIFY:
553 ret = enter_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
556 case GDK_LEAVE_NOTIFY:
557 ret = leave_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
568 Editor::canvas_fade_out_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
570 /* we handle only button 3 press/release events */
572 if (!rv->sensitive()) {
576 switch (event->type) {
577 case GDK_BUTTON_PRESS:
578 clicked_regionview = rv;
579 clicked_control_point = 0;
580 clicked_axisview = &rv->get_time_axis_view();
581 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
582 if (event->button.button == 3) {
583 return button_press_handler (item, event, FadeOutItem);
587 case GDK_BUTTON_RELEASE:
588 if (event->button.button == 3) {
589 return button_release_handler (item, event, FadeOutItem);
598 /* proxy for the regionview, except enter/leave events */
600 if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
603 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
608 Editor::canvas_fade_out_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv, bool trim)
612 if (!rv->sensitive()) {
616 switch (event->type) {
617 case GDK_BUTTON_PRESS:
618 case GDK_2BUTTON_PRESS:
619 case GDK_3BUTTON_PRESS:
620 clicked_regionview = rv;
621 clicked_control_point = 0;
622 clicked_axisview = &rv->get_time_axis_view();
623 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
624 ret = button_press_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
627 case GDK_BUTTON_RELEASE:
628 ret = button_release_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
629 maybe_locate_with_edit_preroll ( rv->region()->last_frame() - rv->get_fade_out_shape_width() );
632 case GDK_MOTION_NOTIFY:
633 ret = motion_handler (item, event);
636 case GDK_ENTER_NOTIFY:
637 ret = enter_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
640 case GDK_LEAVE_NOTIFY:
641 ret = leave_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
651 struct DescendingRegionLayerSorter {
652 bool operator()(boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
653 return a->layer() > b->layer();
658 Editor::canvas_control_point_event (GdkEvent *event, ArdourCanvas::Item* item, ControlPoint* cp)
660 switch (event->type) {
661 case GDK_BUTTON_PRESS:
662 case GDK_2BUTTON_PRESS:
663 case GDK_3BUTTON_PRESS:
664 clicked_control_point = cp;
665 clicked_axisview = &cp->line().trackview;
666 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
667 clicked_regionview = 0;
673 case GDK_SCROLL_DOWN:
680 return typed_event (item, event, ControlPointItem);
684 Editor::canvas_line_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationLine* al)
687 AudioRegionGainLine* gl;
688 if ((gl = dynamic_cast<AudioRegionGainLine*> (al)) != 0) {
690 clicked_regionview = &gl->region_view ();
692 type = AutomationLineItem;
693 clicked_regionview = 0;
696 clicked_control_point = 0;
697 clicked_axisview = &al->trackview;
698 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
700 return typed_event (item, event, type);
704 Editor::canvas_selection_rect_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
708 switch (event->type) {
709 case GDK_BUTTON_PRESS:
710 case GDK_2BUTTON_PRESS:
711 case GDK_3BUTTON_PRESS:
712 clicked_selection = rect->id;
713 ret = button_press_handler (item, event, SelectionItem);
715 case GDK_BUTTON_RELEASE:
716 ret = button_release_handler (item, event, SelectionItem);
718 case GDK_MOTION_NOTIFY:
719 ret = motion_handler (item, event);
721 /* Don't need these at the moment. */
722 case GDK_ENTER_NOTIFY:
723 ret = enter_handler (item, event, SelectionItem);
726 case GDK_LEAVE_NOTIFY:
727 ret = leave_handler (item, event, SelectionItem);
738 Editor::canvas_selection_start_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
742 switch (event->type) {
743 case GDK_BUTTON_PRESS:
744 case GDK_2BUTTON_PRESS:
745 case GDK_3BUTTON_PRESS:
746 clicked_selection = rect->id;
747 ret = button_press_handler (item, event, StartSelectionTrimItem);
749 case GDK_BUTTON_RELEASE:
750 ret = button_release_handler (item, event, StartSelectionTrimItem);
752 case GDK_MOTION_NOTIFY:
753 ret = motion_handler (item, event);
755 case GDK_ENTER_NOTIFY:
756 ret = enter_handler (item, event, StartSelectionTrimItem);
759 case GDK_LEAVE_NOTIFY:
760 ret = leave_handler (item, event, StartSelectionTrimItem);
771 Editor::canvas_selection_end_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
775 switch (event->type) {
776 case GDK_BUTTON_PRESS:
777 case GDK_2BUTTON_PRESS:
778 case GDK_3BUTTON_PRESS:
779 clicked_selection = rect->id;
780 ret = button_press_handler (item, event, EndSelectionTrimItem);
782 case GDK_BUTTON_RELEASE:
783 ret = button_release_handler (item, event, EndSelectionTrimItem);
785 case GDK_MOTION_NOTIFY:
786 ret = motion_handler (item, event);
788 case GDK_ENTER_NOTIFY:
789 ret = enter_handler (item, event, EndSelectionTrimItem);
792 case GDK_LEAVE_NOTIFY:
793 ret = leave_handler (item, event, EndSelectionTrimItem);
804 Editor::canvas_frame_handle_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
808 /* frame handles are not active when in internal edit mode, because actual notes
809 might be in the area occupied by the handle - we want them to be editable as normal.
812 if (internal_editing() || !rv->sensitive()) {
816 /* NOTE: frame handles pretend to be the colored trim bar from an event handling
817 perspective. XXX change this ??
822 if (item->get_data ("isleft")) {
823 type = LeftFrameHandle;
825 type = RightFrameHandle;
828 switch (event->type) {
829 case GDK_BUTTON_PRESS:
830 case GDK_2BUTTON_PRESS:
831 case GDK_3BUTTON_PRESS:
832 clicked_regionview = rv;
833 clicked_control_point = 0;
834 clicked_axisview = &clicked_regionview->get_time_axis_view();
835 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
836 ret = button_press_handler (item, event, type);
838 case GDK_BUTTON_RELEASE:
839 ret = button_release_handler (item, event, type);
841 case GDK_MOTION_NOTIFY:
842 ret = motion_handler (item, event);
844 case GDK_ENTER_NOTIFY:
845 ret = enter_handler (item, event, type);
848 case GDK_LEAVE_NOTIFY:
849 ret = leave_handler (item, event, type);
861 Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
865 if (!rv->sensitive()) {
869 switch (event->type) {
870 case GDK_BUTTON_PRESS:
871 case GDK_2BUTTON_PRESS:
872 case GDK_3BUTTON_PRESS:
873 clicked_regionview = rv;
874 clicked_control_point = 0;
875 clicked_axisview = &clicked_regionview->get_time_axis_view();
876 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
877 ret = button_press_handler (item, event, RegionViewNameHighlight);
879 case GDK_BUTTON_RELEASE:
880 ret = button_release_handler (item, event, RegionViewNameHighlight);
882 case GDK_MOTION_NOTIFY:
883 motion_handler (item, event);
884 ret = true; // force this to avoid progagating the event into the regionview
886 case GDK_ENTER_NOTIFY:
887 ret = enter_handler (item, event, RegionViewNameHighlight);
890 case GDK_LEAVE_NOTIFY:
891 ret = leave_handler (item, event, RegionViewNameHighlight);
902 Editor::canvas_region_view_name_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
906 if (!rv->sensitive()) {
910 switch (event->type) {
911 case GDK_BUTTON_PRESS:
912 case GDK_2BUTTON_PRESS:
913 case GDK_3BUTTON_PRESS:
914 clicked_regionview = rv;
915 clicked_control_point = 0;
916 clicked_axisview = &clicked_regionview->get_time_axis_view();
917 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
918 ret = button_press_handler (item, event, RegionViewName);
920 case GDK_BUTTON_RELEASE:
921 ret = button_release_handler (item, event, RegionViewName);
923 case GDK_MOTION_NOTIFY:
924 ret = motion_handler (item, event);
926 case GDK_ENTER_NOTIFY:
927 ret = enter_handler (item, event, RegionViewName);
930 case GDK_LEAVE_NOTIFY:
931 ret = leave_handler (item, event, RegionViewName);
942 Editor::canvas_feature_line_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView*)
946 switch (event->type) {
947 case GDK_BUTTON_PRESS:
948 case GDK_2BUTTON_PRESS:
949 case GDK_3BUTTON_PRESS:
950 clicked_regionview = 0;
951 clicked_control_point = 0;
952 clicked_axisview = 0;
953 clicked_routeview = 0; //dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
954 ret = button_press_handler (item, event, FeatureLineItem);
957 case GDK_BUTTON_RELEASE:
958 ret = button_release_handler (item, event, FeatureLineItem);
961 case GDK_MOTION_NOTIFY:
962 ret = motion_handler (item, event);
965 case GDK_ENTER_NOTIFY:
966 ret = enter_handler (item, event, FeatureLineItem);
969 case GDK_LEAVE_NOTIFY:
970 ret = leave_handler (item, event, FeatureLineItem);
981 Editor::canvas_marker_event (GdkEvent *event, ArdourCanvas::Item* item, ArdourMarker* /*marker*/)
983 return typed_event (item, event, MarkerItem);
987 Editor::canvas_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
989 return typed_event (item, event, MarkerBarItem);
993 Editor::canvas_range_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
995 return typed_event (item, event, RangeMarkerBarItem);
999 Editor::canvas_transport_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1001 return typed_event (item, event, TransportMarkerBarItem);
1005 Editor::canvas_cd_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1007 return typed_event (item, event, CdMarkerBarItem);
1011 Editor::canvas_videotl_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1013 return typed_event (item, event, VideoBarItem);
1017 Editor::canvas_tempo_marker_event (GdkEvent *event, ArdourCanvas::Item* item, TempoMarker* /*marker*/)
1019 return typed_event (item, event, TempoMarkerItem);
1023 Editor::canvas_meter_marker_event (GdkEvent *event, ArdourCanvas::Item* item, MeterMarker* /*marker*/)
1025 return typed_event (item, event, MeterMarkerItem);
1029 Editor::canvas_ruler_event (GdkEvent *event, ArdourCanvas::Item* item, ItemType type)
1032 bool handled = false;
1034 if (event->type == GDK_SCROLL) {
1036 /* scroll events in the rulers are handled a little differently from
1037 scrolling elsewhere in the canvas.
1040 switch (event->scroll.direction) {
1043 if (Profile->get_mixbus()) {
1044 //for mouse-wheel zoom, force zoom-focus to mouse
1045 Editing::ZoomFocus temp_focus = zoom_focus;
1046 zoom_focus = Editing::ZoomFocusMouse;
1047 temporal_zoom_step (false);
1048 zoom_focus = temp_focus;
1050 temporal_zoom_step (false);
1055 case GDK_SCROLL_DOWN:
1056 if (Profile->get_mixbus()) {
1057 //for mouse-wheel zoom, force zoom-focus to mouse
1058 Editing::ZoomFocus temp_focus = zoom_focus;
1059 zoom_focus = Editing::ZoomFocusMouse;
1060 temporal_zoom_step (true);
1061 zoom_focus = temp_focus;
1063 temporal_zoom_step (true);
1068 case GDK_SCROLL_LEFT:
1069 xdelta = (current_page_samples() / 2);
1070 if (leftmost_frame > xdelta) {
1071 reset_x_origin (leftmost_frame - xdelta);
1078 case GDK_SCROLL_RIGHT:
1079 xdelta = (current_page_samples() / 2);
1080 if (max_framepos - xdelta > leftmost_frame) {
1081 reset_x_origin (leftmost_frame + xdelta);
1083 reset_x_origin (max_framepos - current_page_samples());
1095 return typed_event (item, event, type);
1099 Editor::canvas_tempo_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1101 return typed_event (item, event, TempoBarItem);
1105 Editor::canvas_meter_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1107 return typed_event (item, event, MeterBarItem);
1111 Editor::canvas_playhead_cursor_event (GdkEvent *event, ArdourCanvas::Item* item)
1113 return typed_event (item, event, PlayheadCursorItem);
1117 Editor::canvas_note_event (GdkEvent *event, ArdourCanvas::Item* item)
1119 if (!internal_editing()) {
1123 return typed_event (item, event, NoteItem);
1127 Editor::canvas_drop_zone_event (GdkEvent* event)
1129 GdkEventScroll scroll;
1130 ArdourCanvas::Duple winpos;
1132 switch (event->type) {
1133 case GDK_BUTTON_RELEASE:
1134 if (event->button.button == 1) {
1135 begin_reversible_selection_op (X_("Nowhere Click"));
1136 selection->clear_objects ();
1137 selection->clear_tracks ();
1138 commit_reversible_selection_op ();
1143 /* convert coordinates back into window space so that
1144 we can just call canvas_scroll_event().
1146 winpos = _track_canvas->canvas_to_window (Duple (event->scroll.x, event->scroll.y));
1147 scroll = event->scroll;
1148 scroll.x = winpos.x;
1149 scroll.y = winpos.y;
1150 return canvas_scroll_event (&scroll, true);
1153 case GDK_ENTER_NOTIFY:
1154 return typed_event (_canvas_drop_zone, event, DropZoneItem);
1156 case GDK_LEAVE_NOTIFY:
1157 return typed_event (_canvas_drop_zone, event, DropZoneItem);
1167 Editor::track_canvas_drag_motion (Glib::RefPtr<Gdk::DragContext> const& context, int x, int y, guint time)
1169 boost::shared_ptr<Region> region;
1170 boost::shared_ptr<Region> region_copy;
1171 RouteTimeAxisView* rtav;
1176 string target = _track_canvas->drag_dest_find_target (context, _track_canvas->drag_dest_get_target_list());
1178 if (target.empty()) {
1182 event.type = GDK_MOTION_NOTIFY;
1185 /* assume we're dragging with button 1 */
1186 event.motion.state = Gdk::BUTTON1_MASK;
1188 (void) window_event_sample (&event, &px, &py);
1190 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py, false);
1191 bool can_drop = false;
1193 if (tv.first != 0) {
1195 /* over a time axis view of some kind */
1197 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1199 if (rtav != 0 && rtav->is_track ()) {
1200 /* over a track, not a bus */
1206 /* not over a time axis view, so drop is possible */
1211 region = _regions->get_dragged_region ();
1217 boost::dynamic_pointer_cast<AudioRegion> (region) != 0 ||
1218 boost::dynamic_pointer_cast<MidiRegion> (region) != 0
1222 /* drop to drop-zone */
1223 context->drag_status (context->get_suggested_action(), time);
1227 if ((boost::dynamic_pointer_cast<AudioRegion> (region) != 0 &&
1228 dynamic_cast<AudioTimeAxisView*> (tv.first) != 0) ||
1229 (boost::dynamic_pointer_cast<MidiRegion> (region) != 0 &&
1230 dynamic_cast<MidiTimeAxisView*> (tv.first) != 0)) {
1237 context->drag_status (context->get_suggested_action(), time);
1241 /* DND originating from outside ardour
1243 * TODO: check if file is audio/midi, allow drops on same track-type only,
1244 * currently: if audio is dropped on a midi-track, it is only added to the region-list
1246 if (Profile->get_sae() || UIConfiguration::instance().get_only_copy_imported_files()) {
1247 context->drag_status(Gdk::ACTION_COPY, time);
1249 if ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY) {
1250 context->drag_status(Gdk::ACTION_COPY, time);
1252 context->drag_status(Gdk::ACTION_LINK, time);
1260 context->drag_status (Gdk::DragAction (0), time);
1265 Editor::drop_regions (const Glib::RefPtr<Gdk::DragContext>& /*context*/,
1267 const SelectionData& /*data*/,
1268 guint /*info*/, guint /*time*/)
1274 event.type = GDK_MOTION_NOTIFY;
1277 /* assume we're dragging with button 1 */
1278 event.motion.state = Gdk::BUTTON1_MASK;
1279 framepos_t const pos = window_event_sample (&event, &px, &py);
1281 boost::shared_ptr<Region> region = _regions->get_dragged_region ();
1282 if (!region) { return; }
1284 RouteTimeAxisView* rtav = 0;
1285 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py, false);
1287 if (tv.first != 0) {
1288 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1291 if (boost::dynamic_pointer_cast<AudioRegion> (region)) {
1292 uint32_t output_chan = region->n_channels();
1293 if ((Config->get_output_auto_connect() & AutoConnectMaster) && session()->master_out()) {
1294 output_chan = session()->master_out()->n_inputs().n_audio();
1296 list<boost::shared_ptr<AudioTrack> > audio_tracks;
1297 audio_tracks = session()->new_audio_track (region->n_channels(), output_chan, ARDOUR::Normal, 0, 1, region->name());
1298 rtav = axis_view_from_route (audio_tracks.front());
1299 } else if (boost::dynamic_pointer_cast<MidiRegion> (region)) {
1300 ChanCount one_midi_port (DataType::MIDI, 1);
1301 list<boost::shared_ptr<MidiTrack> > midi_tracks;
1302 midi_tracks = session()->new_midi_track (one_midi_port, one_midi_port, boost::shared_ptr<ARDOUR::PluginInfo>(), ARDOUR::Normal, 0, 1, region->name());
1303 rtav = axis_view_from_route (midi_tracks.front());
1308 error << _("Could not create new track after region placed in the drop zone") << endmsg;
1313 if (rtav != 0 && rtav->is_track ()) {
1314 boost::shared_ptr<Region> region_copy = RegionFactory::create (region, true);
1316 if ((boost::dynamic_pointer_cast<AudioRegion> (region_copy) != 0 && dynamic_cast<AudioTimeAxisView*> (rtav) != 0) ||
1317 (boost::dynamic_pointer_cast<MidiRegion> (region_copy) != 0 && dynamic_cast<MidiTimeAxisView*> (rtav) != 0)) {
1318 _drags->set (new RegionInsertDrag (this, region_copy, rtav, pos), &event);
1319 _drags->end_grab (0);
1325 Editor::key_press_handler (ArdourCanvas::Item*, GdkEvent*, ItemType)
1331 Editor::key_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType type)
1334 bool handled = false;
1337 case TempoMarkerItem:
1338 switch (event->key.keyval) {
1340 remove_tempo_marker (item);
1348 case MeterMarkerItem:
1349 switch (event->key.keyval) {
1351 remove_meter_marker (item);