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 if (Keyboard::some_magic_widget_has_focus()) {
72 int direction = ev->direction;
74 /* this event arrives without transformation by the canvas, so we have
75 * to transform the coordinates to be able to look things up.
78 Duple event_coords = _track_canvas->window_to_canvas (Duple (ev->x, ev->y));
83 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomHorizontalModifier)) {
84 //for mouse-wheel zoom, force zoom-focus to mouse
85 Editing::ZoomFocus temp_focus = zoom_focus;
86 zoom_focus = Editing::ZoomFocusMouse;
87 temporal_zoom_step (false);
88 zoom_focus = temp_focus;
90 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) {
91 direction = GDK_SCROLL_LEFT;
93 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
94 if (!current_stepping_trackview) {
95 step_timeout = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Editor::track_height_step_timeout), 500);
96 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (event_coords.y, false);
97 current_stepping_trackview = p.first;
98 if (!current_stepping_trackview) {
102 last_track_height_step_timestamp = get_microseconds();
103 current_stepping_trackview->step_height (false);
106 scroll_up_one_track ();
111 case GDK_SCROLL_DOWN:
112 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomHorizontalModifier)) {
113 //for mouse-wheel zoom, force zoom-focus to mouse
114 Editing::ZoomFocus temp_focus = zoom_focus;
115 zoom_focus = Editing::ZoomFocusMouse;
116 temporal_zoom_step (true);
117 zoom_focus = temp_focus;
119 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) {
120 direction = GDK_SCROLL_RIGHT;
122 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
123 if (!current_stepping_trackview) {
124 step_timeout = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Editor::track_height_step_timeout), 500);
125 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (event_coords.y, false);
126 current_stepping_trackview = p.first;
127 if (!current_stepping_trackview) {
131 last_track_height_step_timestamp = get_microseconds();
132 current_stepping_trackview->step_height (true);
135 scroll_down_one_track ();
140 case GDK_SCROLL_LEFT:
141 xdelta = (current_page_samples() / 8);
142 if (leftmost_frame > xdelta) {
143 reset_x_origin (leftmost_frame - xdelta);
149 case GDK_SCROLL_RIGHT:
150 xdelta = (current_page_samples() / 8);
151 if (max_framepos - xdelta > leftmost_frame) {
152 reset_x_origin (leftmost_frame + xdelta);
154 reset_x_origin (max_framepos - current_page_samples());
167 Editor::canvas_scroll_event (GdkEventScroll *event, bool from_canvas)
170 boost::optional<ArdourCanvas::Rect> rulers = _time_markers_group->bounding_box();
171 if (rulers && rulers->contains (Duple (event->x, event->y))) {
172 return canvas_ruler_event ((GdkEvent*) event, timecode_ruler, TimecodeRulerItem);
176 _track_canvas->grab_focus();
177 return track_canvas_scroll (event);
181 Editor::track_canvas_button_press_event (GdkEventButton *event)
183 _track_canvas->grab_focus();
184 if (!Keyboard::is_context_menu_event (event)) {
185 begin_reversible_selection_op (X_("Clear Selection Click (track canvas)"));
187 commit_reversible_selection_op();
193 Editor::track_canvas_button_release_event (GdkEventButton *event)
195 if (!Keyboard::is_context_menu_event (event)) {
196 if (_drags->active ()) {
197 _drags->end_grab ((GdkEvent*) event);
204 Editor::track_canvas_motion_notify_event (GdkEventMotion */*event*/)
207 /* keep those motion events coming */
208 _track_canvas->get_pointer (x, y);
213 Editor::typed_event (ArdourCanvas::Item* item, GdkEvent *event, ItemType type)
217 switch (event->type) {
218 case GDK_BUTTON_PRESS:
219 case GDK_2BUTTON_PRESS:
220 case GDK_3BUTTON_PRESS:
221 ret = button_press_handler (item, event, type);
223 case GDK_BUTTON_RELEASE:
224 ret = button_release_handler (item, event, type);
226 case GDK_MOTION_NOTIFY:
227 ret = motion_handler (item, event);
230 case GDK_ENTER_NOTIFY:
231 ret = enter_handler (item, event, type);
234 case GDK_LEAVE_NOTIFY:
235 ret = leave_handler (item, event, type);
239 ret = key_press_handler (item, event, type);
242 case GDK_KEY_RELEASE:
243 ret = key_release_handler (item, event, type);
253 Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView *rv)
257 if (!rv->sensitive ()) {
261 switch (event->type) {
262 case GDK_BUTTON_PRESS:
263 case GDK_2BUTTON_PRESS:
264 case GDK_3BUTTON_PRESS:
265 clicked_regionview = rv;
266 clicked_control_point = 0;
267 clicked_axisview = &rv->get_time_axis_view();
268 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
269 ret = button_press_handler (item, event, RegionItem);
272 case GDK_BUTTON_RELEASE:
273 ret = button_release_handler (item, event, RegionItem);
276 case GDK_MOTION_NOTIFY:
277 ret = motion_handler (item, event);
280 case GDK_ENTER_NOTIFY:
281 set_entered_regionview (rv);
282 ret = enter_handler (item, event, RegionItem);
285 case GDK_LEAVE_NOTIFY:
286 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) {
287 set_entered_regionview (0);
288 ret = leave_handler (item, event, RegionItem);
300 Editor::canvas_wave_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
302 /* we only care about enter events here, required for mouse/cursor
303 * tracking. there is a non-linear (non-child/non-parent) relationship
304 * between various components of a regionview and so when we leave one
305 * of them (e.g. a trim handle) and enter another (e.g. the waveview)
306 * no other items get notified. enter/leave handling does not propagate
307 * in the same way as other events, so we need to catch this because
308 * entering (and leaving) the waveview is equivalent to
309 * entering/leaving the regionview (which is why it is passed in as a
312 * And in fact, we really only care about enter events.
317 if (!rv->sensitive ()) {
321 switch (event->type) {
322 case GDK_ENTER_NOTIFY:
323 set_entered_regionview (rv);
324 ret = enter_handler (item, event, WaveItem);
336 Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, RouteTimeAxisView *tv)
340 switch (event->type) {
341 case GDK_BUTTON_PRESS:
342 case GDK_2BUTTON_PRESS:
343 case GDK_3BUTTON_PRESS:
344 clicked_regionview = 0;
345 clicked_control_point = 0;
346 clicked_axisview = tv;
347 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
348 ret = button_press_handler (item, event, StreamItem);
351 case GDK_BUTTON_RELEASE:
352 ret = button_release_handler (item, event, StreamItem);
355 case GDK_MOTION_NOTIFY:
356 ret = motion_handler (item, event);
359 case GDK_ENTER_NOTIFY:
360 set_entered_track (tv);
361 ret = enter_handler (item, event, StreamItem);
364 case GDK_LEAVE_NOTIFY:
365 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) {
366 set_entered_track (0);
368 ret = leave_handler (item, event, StreamItem);
379 Editor::canvas_automation_track_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationTimeAxisView *atv)
383 switch (event->type) {
384 case GDK_BUTTON_PRESS:
385 case GDK_2BUTTON_PRESS:
386 case GDK_3BUTTON_PRESS:
387 clicked_regionview = 0;
388 clicked_control_point = 0;
389 clicked_axisview = atv;
390 clicked_routeview = 0;
391 ret = button_press_handler (item, event, AutomationTrackItem);
394 case GDK_BUTTON_RELEASE:
395 ret = button_release_handler (item, event, AutomationTrackItem);
398 case GDK_MOTION_NOTIFY:
399 ret = motion_handler (item, event);
402 case GDK_ENTER_NOTIFY:
403 ret = enter_handler (item, event, AutomationTrackItem);
406 case GDK_LEAVE_NOTIFY:
407 ret = leave_handler (item, event, AutomationTrackItem);
418 Editor::canvas_start_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
420 if (!rv->sensitive()) {
424 switch (event->type) {
425 case GDK_BUTTON_PRESS:
426 clicked_regionview = rv;
427 clicked_control_point = 0;
428 clicked_axisview = &rv->get_time_axis_view();
429 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
430 if (event->button.button == 3) {
431 return button_press_handler (item, event, StartCrossFadeItem);
435 case GDK_BUTTON_RELEASE:
436 if (event->button.button == 3) {
437 return button_release_handler (item, event, StartCrossFadeItem);
446 /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
447 /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
448 /* if we return RegionItem here then we avoid the issue until it is resolved later */
449 return typed_event (item, event, RegionItem); // StartCrossFadeItem);
453 Editor::canvas_end_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
455 if (!rv->sensitive()) {
459 switch (event->type) {
460 case GDK_BUTTON_PRESS:
461 clicked_regionview = rv;
462 clicked_control_point = 0;
463 clicked_axisview = &rv->get_time_axis_view();
464 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
465 if (event->button.button == 3) {
466 return button_press_handler (item, event, EndCrossFadeItem);
470 case GDK_BUTTON_RELEASE:
471 if (event->button.button == 3) {
472 return button_release_handler (item, event, EndCrossFadeItem);
481 /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
482 /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
483 /* if we return RegionItem here then we avoid the issue until it is resolved later */
484 return typed_event (item, event, RegionItem); // EndCrossFadeItem);
488 Editor::canvas_fade_in_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
490 /* we handle only button 3 press/release events */
492 if (!rv->sensitive()) {
496 switch (event->type) {
497 case GDK_BUTTON_PRESS:
498 clicked_regionview = rv;
499 clicked_control_point = 0;
500 clicked_axisview = &rv->get_time_axis_view();
501 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
502 if (event->button.button == 3) {
503 return button_press_handler (item, event, FadeInItem);
507 case GDK_BUTTON_RELEASE:
508 if (event->button.button == 3) {
509 return button_release_handler (item, event, FadeInItem);
518 /* proxy for the regionview, except enter/leave events */
520 if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
523 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
528 Editor::canvas_fade_in_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv, bool trim)
532 if (!rv->sensitive()) {
536 switch (event->type) {
537 case GDK_BUTTON_PRESS:
538 case GDK_2BUTTON_PRESS:
539 case GDK_3BUTTON_PRESS:
540 clicked_regionview = rv;
541 clicked_control_point = 0;
542 clicked_axisview = &rv->get_time_axis_view();
543 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
544 ret = button_press_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
547 case GDK_BUTTON_RELEASE:
548 ret = button_release_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
549 maybe_locate_with_edit_preroll ( rv->region()->position() );
552 case GDK_MOTION_NOTIFY:
553 ret = motion_handler (item, event);
556 case GDK_ENTER_NOTIFY:
557 ret = enter_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
560 case GDK_LEAVE_NOTIFY:
561 ret = leave_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
572 Editor::canvas_fade_out_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
574 /* we handle only button 3 press/release events */
576 if (!rv->sensitive()) {
580 switch (event->type) {
581 case GDK_BUTTON_PRESS:
582 clicked_regionview = rv;
583 clicked_control_point = 0;
584 clicked_axisview = &rv->get_time_axis_view();
585 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
586 if (event->button.button == 3) {
587 return button_press_handler (item, event, FadeOutItem);
591 case GDK_BUTTON_RELEASE:
592 if (event->button.button == 3) {
593 return button_release_handler (item, event, FadeOutItem);
602 /* proxy for the regionview, except enter/leave events */
604 if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
607 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
612 Editor::canvas_fade_out_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv, bool trim)
616 if (!rv->sensitive()) {
620 switch (event->type) {
621 case GDK_BUTTON_PRESS:
622 case GDK_2BUTTON_PRESS:
623 case GDK_3BUTTON_PRESS:
624 clicked_regionview = rv;
625 clicked_control_point = 0;
626 clicked_axisview = &rv->get_time_axis_view();
627 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
628 ret = button_press_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
631 case GDK_BUTTON_RELEASE:
632 ret = button_release_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
633 maybe_locate_with_edit_preroll ( rv->region()->last_frame() - rv->get_fade_out_shape_width() );
636 case GDK_MOTION_NOTIFY:
637 ret = motion_handler (item, event);
640 case GDK_ENTER_NOTIFY:
641 ret = enter_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
644 case GDK_LEAVE_NOTIFY:
645 ret = leave_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
655 struct DescendingRegionLayerSorter {
656 bool operator()(boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
657 return a->layer() > b->layer();
662 Editor::canvas_control_point_event (GdkEvent *event, ArdourCanvas::Item* item, ControlPoint* cp)
664 switch (event->type) {
665 case GDK_BUTTON_PRESS:
666 case GDK_2BUTTON_PRESS:
667 case GDK_3BUTTON_PRESS:
668 clicked_control_point = cp;
669 clicked_axisview = &cp->line().trackview;
670 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
671 clicked_regionview = 0;
677 case GDK_SCROLL_DOWN:
684 return typed_event (item, event, ControlPointItem);
688 Editor::canvas_line_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationLine* al)
691 AudioRegionGainLine* gl;
692 if ((gl = dynamic_cast<AudioRegionGainLine*> (al)) != 0) {
694 clicked_regionview = &gl->region_view ();
696 type = AutomationLineItem;
697 clicked_regionview = 0;
700 clicked_control_point = 0;
701 clicked_axisview = &al->trackview;
702 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
704 return typed_event (item, event, type);
708 Editor::canvas_selection_rect_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
712 switch (event->type) {
713 case GDK_BUTTON_PRESS:
714 case GDK_2BUTTON_PRESS:
715 case GDK_3BUTTON_PRESS:
716 clicked_selection = rect->id;
717 ret = button_press_handler (item, event, SelectionItem);
719 case GDK_BUTTON_RELEASE:
720 ret = button_release_handler (item, event, SelectionItem);
722 case GDK_MOTION_NOTIFY:
723 ret = motion_handler (item, event);
725 /* Don't need these at the moment. */
726 case GDK_ENTER_NOTIFY:
727 ret = enter_handler (item, event, SelectionItem);
730 case GDK_LEAVE_NOTIFY:
731 ret = leave_handler (item, event, SelectionItem);
742 Editor::canvas_selection_start_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
746 switch (event->type) {
747 case GDK_BUTTON_PRESS:
748 case GDK_2BUTTON_PRESS:
749 case GDK_3BUTTON_PRESS:
750 clicked_selection = rect->id;
751 ret = button_press_handler (item, event, StartSelectionTrimItem);
753 case GDK_BUTTON_RELEASE:
754 ret = button_release_handler (item, event, StartSelectionTrimItem);
756 case GDK_MOTION_NOTIFY:
757 ret = motion_handler (item, event);
759 case GDK_ENTER_NOTIFY:
760 ret = enter_handler (item, event, StartSelectionTrimItem);
763 case GDK_LEAVE_NOTIFY:
764 ret = leave_handler (item, event, StartSelectionTrimItem);
775 Editor::canvas_selection_end_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
779 switch (event->type) {
780 case GDK_BUTTON_PRESS:
781 case GDK_2BUTTON_PRESS:
782 case GDK_3BUTTON_PRESS:
783 clicked_selection = rect->id;
784 ret = button_press_handler (item, event, EndSelectionTrimItem);
786 case GDK_BUTTON_RELEASE:
787 ret = button_release_handler (item, event, EndSelectionTrimItem);
789 case GDK_MOTION_NOTIFY:
790 ret = motion_handler (item, event);
792 case GDK_ENTER_NOTIFY:
793 ret = enter_handler (item, event, EndSelectionTrimItem);
796 case GDK_LEAVE_NOTIFY:
797 ret = leave_handler (item, event, EndSelectionTrimItem);
808 Editor::canvas_frame_handle_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
812 /* frame handles are not active when in internal edit mode, because actual notes
813 might be in the area occupied by the handle - we want them to be editable as normal.
816 if (internal_editing() || !rv->sensitive()) {
820 /* NOTE: frame handles pretend to be the colored trim bar from an event handling
821 perspective. XXX change this ??
826 if (item->get_data ("isleft")) {
827 type = LeftFrameHandle;
829 type = RightFrameHandle;
832 switch (event->type) {
833 case GDK_BUTTON_PRESS:
834 case GDK_2BUTTON_PRESS:
835 case GDK_3BUTTON_PRESS:
836 clicked_regionview = rv;
837 clicked_control_point = 0;
838 clicked_axisview = &clicked_regionview->get_time_axis_view();
839 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
840 ret = button_press_handler (item, event, type);
842 case GDK_BUTTON_RELEASE:
843 ret = button_release_handler (item, event, type);
845 case GDK_MOTION_NOTIFY:
846 ret = motion_handler (item, event);
848 case GDK_ENTER_NOTIFY:
849 ret = enter_handler (item, event, type);
852 case GDK_LEAVE_NOTIFY:
853 ret = leave_handler (item, event, type);
865 Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
869 if (!rv->sensitive()) {
873 switch (event->type) {
874 case GDK_BUTTON_PRESS:
875 case GDK_2BUTTON_PRESS:
876 case GDK_3BUTTON_PRESS:
877 clicked_regionview = rv;
878 clicked_control_point = 0;
879 clicked_axisview = &clicked_regionview->get_time_axis_view();
880 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
881 ret = button_press_handler (item, event, RegionViewNameHighlight);
883 case GDK_BUTTON_RELEASE:
884 ret = button_release_handler (item, event, RegionViewNameHighlight);
886 case GDK_MOTION_NOTIFY:
887 motion_handler (item, event);
888 ret = true; // force this to avoid progagating the event into the regionview
890 case GDK_ENTER_NOTIFY:
891 ret = enter_handler (item, event, RegionViewNameHighlight);
894 case GDK_LEAVE_NOTIFY:
895 ret = leave_handler (item, event, RegionViewNameHighlight);
906 Editor::canvas_region_view_name_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
910 if (!rv->sensitive()) {
914 switch (event->type) {
915 case GDK_BUTTON_PRESS:
916 case GDK_2BUTTON_PRESS:
917 case GDK_3BUTTON_PRESS:
918 clicked_regionview = rv;
919 clicked_control_point = 0;
920 clicked_axisview = &clicked_regionview->get_time_axis_view();
921 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
922 ret = button_press_handler (item, event, RegionViewName);
924 case GDK_BUTTON_RELEASE:
925 ret = button_release_handler (item, event, RegionViewName);
927 case GDK_MOTION_NOTIFY:
928 ret = motion_handler (item, event);
930 case GDK_ENTER_NOTIFY:
931 ret = enter_handler (item, event, RegionViewName);
934 case GDK_LEAVE_NOTIFY:
935 ret = leave_handler (item, event, RegionViewName);
946 Editor::canvas_feature_line_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView*)
950 switch (event->type) {
951 case GDK_BUTTON_PRESS:
952 case GDK_2BUTTON_PRESS:
953 case GDK_3BUTTON_PRESS:
954 clicked_regionview = 0;
955 clicked_control_point = 0;
956 clicked_axisview = 0;
957 clicked_routeview = 0; //dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
958 ret = button_press_handler (item, event, FeatureLineItem);
961 case GDK_BUTTON_RELEASE:
962 ret = button_release_handler (item, event, FeatureLineItem);
965 case GDK_MOTION_NOTIFY:
966 ret = motion_handler (item, event);
969 case GDK_ENTER_NOTIFY:
970 ret = enter_handler (item, event, FeatureLineItem);
973 case GDK_LEAVE_NOTIFY:
974 ret = leave_handler (item, event, FeatureLineItem);
985 Editor::canvas_marker_event (GdkEvent *event, ArdourCanvas::Item* item, ArdourMarker* /*marker*/)
987 return typed_event (item, event, MarkerItem);
991 Editor::canvas_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
993 return typed_event (item, event, MarkerBarItem);
997 Editor::canvas_range_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
999 return typed_event (item, event, RangeMarkerBarItem);
1003 Editor::canvas_transport_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1005 return typed_event (item, event, TransportMarkerBarItem);
1009 Editor::canvas_cd_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1011 return typed_event (item, event, CdMarkerBarItem);
1015 Editor::canvas_videotl_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1017 return typed_event (item, event, VideoBarItem);
1021 Editor::canvas_tempo_marker_event (GdkEvent *event, ArdourCanvas::Item* item, TempoMarker* /*marker*/)
1023 return typed_event (item, event, TempoMarkerItem);
1027 Editor::canvas_meter_marker_event (GdkEvent *event, ArdourCanvas::Item* item, MeterMarker* /*marker*/)
1029 return typed_event (item, event, MeterMarkerItem);
1033 Editor::canvas_ruler_event (GdkEvent *event, ArdourCanvas::Item* item, ItemType type)
1036 bool handled = false;
1038 if (event->type == GDK_SCROLL) {
1040 /* scroll events in the rulers are handled a little differently from
1041 scrolling elsewhere in the canvas.
1044 switch (event->scroll.direction) {
1047 if (Profile->get_mixbus()) {
1048 //for mouse-wheel zoom, force zoom-focus to mouse
1049 Editing::ZoomFocus temp_focus = zoom_focus;
1050 zoom_focus = Editing::ZoomFocusMouse;
1051 temporal_zoom_step (false);
1052 zoom_focus = temp_focus;
1054 temporal_zoom_step (false);
1059 case GDK_SCROLL_DOWN:
1060 if (Profile->get_mixbus()) {
1061 //for mouse-wheel zoom, force zoom-focus to mouse
1062 Editing::ZoomFocus temp_focus = zoom_focus;
1063 zoom_focus = Editing::ZoomFocusMouse;
1064 temporal_zoom_step (true);
1065 zoom_focus = temp_focus;
1067 temporal_zoom_step (true);
1072 case GDK_SCROLL_LEFT:
1073 xdelta = (current_page_samples() / 2);
1074 if (leftmost_frame > xdelta) {
1075 reset_x_origin (leftmost_frame - xdelta);
1082 case GDK_SCROLL_RIGHT:
1083 xdelta = (current_page_samples() / 2);
1084 if (max_framepos - xdelta > leftmost_frame) {
1085 reset_x_origin (leftmost_frame + xdelta);
1087 reset_x_origin (max_framepos - current_page_samples());
1099 return typed_event (item, event, type);
1103 Editor::canvas_tempo_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1105 return typed_event (item, event, TempoBarItem);
1109 Editor::canvas_meter_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1111 return typed_event (item, event, MeterBarItem);
1115 Editor::canvas_playhead_cursor_event (GdkEvent *event, ArdourCanvas::Item* item)
1117 return typed_event (item, event, PlayheadCursorItem);
1121 Editor::canvas_note_event (GdkEvent *event, ArdourCanvas::Item* item)
1123 if (!internal_editing()) {
1127 return typed_event (item, event, NoteItem);
1131 Editor::canvas_drop_zone_event (GdkEvent* event)
1133 GdkEventScroll scroll;
1134 ArdourCanvas::Duple winpos;
1136 switch (event->type) {
1137 case GDK_BUTTON_RELEASE:
1138 if (event->button.button == 1) {
1139 begin_reversible_selection_op (X_("Nowhere Click"));
1140 selection->clear_objects ();
1141 selection->clear_tracks ();
1142 commit_reversible_selection_op ();
1147 /* convert coordinates back into window space so that
1148 we can just call canvas_scroll_event().
1150 winpos = _track_canvas->canvas_to_window (Duple (event->scroll.x, event->scroll.y));
1151 scroll = event->scroll;
1152 scroll.x = winpos.x;
1153 scroll.y = winpos.y;
1154 return canvas_scroll_event (&scroll, true);
1157 case GDK_ENTER_NOTIFY:
1158 return typed_event (_canvas_drop_zone, event, DropZoneItem);
1160 case GDK_LEAVE_NOTIFY:
1161 return typed_event (_canvas_drop_zone, event, DropZoneItem);
1171 Editor::track_canvas_drag_motion (Glib::RefPtr<Gdk::DragContext> const& context, int x, int y, guint time)
1173 boost::shared_ptr<Region> region;
1174 boost::shared_ptr<Region> region_copy;
1175 RouteTimeAxisView* rtav;
1180 string target = _track_canvas->drag_dest_find_target (context, _track_canvas->drag_dest_get_target_list());
1182 if (target.empty()) {
1186 event.type = GDK_MOTION_NOTIFY;
1189 /* assume we're dragging with button 1 */
1190 event.motion.state = Gdk::BUTTON1_MASK;
1192 (void) window_event_sample (&event, &px, &py);
1194 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py, false);
1195 bool can_drop = false;
1197 if (tv.first != 0) {
1199 /* over a time axis view of some kind */
1201 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1203 if (rtav != 0 && rtav->is_track ()) {
1204 /* over a track, not a bus */
1210 /* not over a time axis view, so drop is possible */
1215 region = _regions->get_dragged_region ();
1221 boost::dynamic_pointer_cast<AudioRegion> (region) != 0 ||
1222 boost::dynamic_pointer_cast<MidiRegion> (region) != 0
1226 /* drop to drop-zone */
1227 context->drag_status (context->get_suggested_action(), time);
1231 if ((boost::dynamic_pointer_cast<AudioRegion> (region) != 0 &&
1232 dynamic_cast<AudioTimeAxisView*> (tv.first) != 0) ||
1233 (boost::dynamic_pointer_cast<MidiRegion> (region) != 0 &&
1234 dynamic_cast<MidiTimeAxisView*> (tv.first) != 0)) {
1241 context->drag_status (context->get_suggested_action(), time);
1245 /* DND originating from outside ardour
1247 * TODO: check if file is audio/midi, allow drops on same track-type only,
1248 * currently: if audio is dropped on a midi-track, it is only added to the region-list
1250 if (Profile->get_sae() || UIConfiguration::instance().get_only_copy_imported_files()) {
1251 context->drag_status(Gdk::ACTION_COPY, time);
1253 if ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY) {
1254 context->drag_status(Gdk::ACTION_COPY, time);
1256 context->drag_status(Gdk::ACTION_LINK, time);
1264 context->drag_status (Gdk::DragAction (0), time);
1269 Editor::drop_regions (const Glib::RefPtr<Gdk::DragContext>& /*context*/,
1271 const SelectionData& /*data*/,
1272 guint /*info*/, guint /*time*/)
1278 event.type = GDK_MOTION_NOTIFY;
1281 /* assume we're dragging with button 1 */
1282 event.motion.state = Gdk::BUTTON1_MASK;
1283 framepos_t const pos = window_event_sample (&event, &px, &py);
1285 boost::shared_ptr<Region> region = _regions->get_dragged_region ();
1286 if (!region) { return; }
1288 RouteTimeAxisView* rtav = 0;
1289 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py, false);
1291 if (tv.first != 0) {
1292 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1295 if (boost::dynamic_pointer_cast<AudioRegion> (region)) {
1296 uint32_t output_chan = region->n_channels();
1297 if ((Config->get_output_auto_connect() & AutoConnectMaster) && session()->master_out()) {
1298 output_chan = session()->master_out()->n_inputs().n_audio();
1300 list<boost::shared_ptr<AudioTrack> > audio_tracks;
1301 audio_tracks = session()->new_audio_track (region->n_channels(), output_chan, ARDOUR::Normal, 0, 1, region->name());
1302 rtav = axis_view_from_route (audio_tracks.front());
1303 } else if (boost::dynamic_pointer_cast<MidiRegion> (region)) {
1304 ChanCount one_midi_port (DataType::MIDI, 1);
1305 list<boost::shared_ptr<MidiTrack> > midi_tracks;
1306 midi_tracks = session()->new_midi_track (one_midi_port, one_midi_port, boost::shared_ptr<ARDOUR::PluginInfo>(), ARDOUR::Normal, 0, 1, region->name());
1307 rtav = axis_view_from_route (midi_tracks.front());
1312 error << _("Could not create new track after region placed in the drop zone") << endmsg;
1317 if (rtav != 0 && rtav->is_track ()) {
1318 boost::shared_ptr<Region> region_copy = RegionFactory::create (region, true);
1320 if ((boost::dynamic_pointer_cast<AudioRegion> (region_copy) != 0 && dynamic_cast<AudioTimeAxisView*> (rtav) != 0) ||
1321 (boost::dynamic_pointer_cast<MidiRegion> (region_copy) != 0 && dynamic_cast<MidiTimeAxisView*> (rtav) != 0)) {
1322 _drags->set (new RegionInsertDrag (this, region_copy, rtav, pos), &event);
1323 _drags->end_grab (0);
1329 Editor::key_press_handler (ArdourCanvas::Item*, GdkEvent*, ItemType)
1335 Editor::key_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType type)
1338 bool handled = false;
1341 case TempoMarkerItem:
1342 switch (event->key.keyval) {
1344 remove_tempo_marker (item);
1352 case MeterMarkerItem:
1353 switch (event->key.keyval) {
1355 remove_meter_marker (item);