2 Copyright (C) 2000 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "pbd/stacktrace.h"
27 #include "ardour/midi_region.h"
28 #include "ardour/region_factory.h"
29 #include "ardour/profile.h"
31 #include "canvas/canvas.h"
32 #include "canvas/text.h"
33 #include "canvas/scroll_group.h"
37 #include "public_editor.h"
38 #include "ardour_ui.h"
39 #include "audio_region_view.h"
40 #include "audio_streamview.h"
41 #include "audio_time_axis.h"
42 #include "region_gain_line.h"
43 #include "automation_line.h"
44 #include "automation_time_axis.h"
45 #include "automation_line.h"
46 #include "control_point.h"
47 #include "editor_drag.h"
48 #include "midi_time_axis.h"
49 #include "editor_regions.h"
50 #include "verbose_cursor.h"
55 using namespace ARDOUR;
58 using namespace ArdourCanvas;
60 using Gtkmm2ext::Keyboard;
63 Editor::track_canvas_scroll (GdkEventScroll* ev)
65 if (Keyboard::some_magic_widget_has_focus()) {
70 int direction = ev->direction;
72 /* this event arrives without transformation by the canvas, so we have
73 * to transform the coordinates to be able to look things up.
76 Duple event_coords = _track_canvas->window_to_canvas (Duple (ev->x, ev->y));
81 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomHorizontalModifier)) {
82 //for mouse-wheel zoom, force zoom-focus to mouse
83 Editing::ZoomFocus temp_focus = zoom_focus;
84 zoom_focus = Editing::ZoomFocusMouse;
85 temporal_zoom_step (false);
86 zoom_focus = temp_focus;
88 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) {
89 direction = GDK_SCROLL_LEFT;
91 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
92 if (!current_stepping_trackview) {
93 step_timeout = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Editor::track_height_step_timeout), 500);
94 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (event_coords.y, false);
95 current_stepping_trackview = p.first;
96 if (!current_stepping_trackview) {
100 last_track_height_step_timestamp = get_microseconds();
101 current_stepping_trackview->step_height (false);
104 scroll_up_one_track ();
109 case GDK_SCROLL_DOWN:
110 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomHorizontalModifier)) {
111 //for mouse-wheel zoom, force zoom-focus to mouse
112 Editing::ZoomFocus temp_focus = zoom_focus;
113 zoom_focus = Editing::ZoomFocusMouse;
114 temporal_zoom_step (true);
115 zoom_focus = temp_focus;
117 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) {
118 direction = GDK_SCROLL_RIGHT;
120 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
121 if (!current_stepping_trackview) {
122 step_timeout = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Editor::track_height_step_timeout), 500);
123 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (event_coords.y, false);
124 current_stepping_trackview = p.first;
125 if (!current_stepping_trackview) {
129 last_track_height_step_timestamp = get_microseconds();
130 current_stepping_trackview->step_height (true);
133 scroll_down_one_track ();
138 case GDK_SCROLL_LEFT:
139 xdelta = (current_page_samples() / 8);
140 if (leftmost_frame > xdelta) {
141 reset_x_origin (leftmost_frame - xdelta);
147 case GDK_SCROLL_RIGHT:
148 xdelta = (current_page_samples() / 8);
149 if (max_framepos - xdelta > leftmost_frame) {
150 reset_x_origin (leftmost_frame + xdelta);
152 reset_x_origin (max_framepos - current_page_samples());
165 Editor::canvas_scroll_event (GdkEventScroll *event, bool from_canvas)
168 boost::optional<ArdourCanvas::Rect> rulers = _time_markers_group->bounding_box();
169 if (rulers && rulers->contains (Duple (event->x, event->y))) {
170 return canvas_ruler_event ((GdkEvent*) event, timecode_ruler, TimecodeRulerItem);
174 _track_canvas->grab_focus();
175 return track_canvas_scroll (event);
179 Editor::track_canvas_button_press_event (GdkEventButton *event)
181 _track_canvas->grab_focus();
182 if (!Keyboard::is_context_menu_event (event)) {
183 begin_reversible_selection_op (_("Clear Selection Click (track canvas)"));
185 commit_reversible_selection_op();
191 Editor::track_canvas_button_release_event (GdkEventButton *event)
193 if (!Keyboard::is_context_menu_event (event)) {
194 if (_drags->active ()) {
195 _drags->end_grab ((GdkEvent*) event);
202 Editor::track_canvas_motion_notify_event (GdkEventMotion */*event*/)
205 /* keep those motion events coming */
206 _track_canvas->get_pointer (x, y);
211 Editor::typed_event (ArdourCanvas::Item* item, GdkEvent *event, ItemType type)
215 switch (event->type) {
216 case GDK_BUTTON_PRESS:
217 case GDK_2BUTTON_PRESS:
218 case GDK_3BUTTON_PRESS:
219 ret = button_press_handler (item, event, type);
221 case GDK_BUTTON_RELEASE:
222 ret = button_release_handler (item, event, type);
224 case GDK_MOTION_NOTIFY:
225 ret = motion_handler (item, event);
228 case GDK_ENTER_NOTIFY:
229 ret = enter_handler (item, event, type);
232 case GDK_LEAVE_NOTIFY:
233 ret = leave_handler (item, event, type);
237 ret = key_press_handler (item, event, type);
240 case GDK_KEY_RELEASE:
241 ret = key_release_handler (item, event, type);
251 Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView *rv)
255 if (!rv->sensitive ()) {
259 switch (event->type) {
260 case GDK_BUTTON_PRESS:
261 case GDK_2BUTTON_PRESS:
262 case GDK_3BUTTON_PRESS:
263 clicked_regionview = rv;
264 clicked_control_point = 0;
265 clicked_axisview = &rv->get_time_axis_view();
266 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
267 ret = button_press_handler (item, event, RegionItem);
270 case GDK_BUTTON_RELEASE:
271 ret = button_release_handler (item, event, RegionItem);
274 case GDK_MOTION_NOTIFY:
275 ret = motion_handler (item, event);
278 case GDK_ENTER_NOTIFY:
279 set_entered_regionview (rv);
280 ret = enter_handler (item, event, RegionItem);
283 case GDK_LEAVE_NOTIFY:
284 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) {
285 set_entered_regionview (0);
286 ret = leave_handler (item, event, RegionItem);
298 Editor::canvas_wave_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
300 /* we only care about enter events here, required for mouse/cursor
301 * tracking. there is a non-linear (non-child/non-parent) relationship
302 * between various components of a regionview and so when we leave one
303 * of them (e.g. a trim handle) and enter another (e.g. the waveview)
304 * no other items get notified. enter/leave handling does not propagate
305 * in the same way as other events, so we need to catch this because
306 * entering (and leaving) the waveview is equivalent to
307 * entering/leaving the regionview (which is why it is passed in as a
310 * And in fact, we really only care about enter events.
315 if (!rv->sensitive ()) {
319 switch (event->type) {
320 case GDK_ENTER_NOTIFY:
321 set_entered_regionview (rv);
322 ret = enter_handler (item, event, WaveItem);
334 Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, RouteTimeAxisView *tv)
338 switch (event->type) {
339 case GDK_BUTTON_PRESS:
340 case GDK_2BUTTON_PRESS:
341 case GDK_3BUTTON_PRESS:
342 clicked_regionview = 0;
343 clicked_control_point = 0;
344 clicked_axisview = tv;
345 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
346 ret = button_press_handler (item, event, StreamItem);
349 case GDK_BUTTON_RELEASE:
350 ret = button_release_handler (item, event, StreamItem);
353 case GDK_MOTION_NOTIFY:
354 ret = motion_handler (item, event);
357 case GDK_ENTER_NOTIFY:
358 set_entered_track (tv);
359 ret = enter_handler (item, event, StreamItem);
362 case GDK_LEAVE_NOTIFY:
363 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) {
364 set_entered_track (0);
366 ret = leave_handler (item, event, StreamItem);
377 Editor::canvas_automation_track_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationTimeAxisView *atv)
381 switch (event->type) {
382 case GDK_BUTTON_PRESS:
383 case GDK_2BUTTON_PRESS:
384 case GDK_3BUTTON_PRESS:
385 clicked_regionview = 0;
386 clicked_control_point = 0;
387 clicked_axisview = atv;
388 clicked_routeview = 0;
389 ret = button_press_handler (item, event, AutomationTrackItem);
392 case GDK_BUTTON_RELEASE:
393 ret = button_release_handler (item, event, AutomationTrackItem);
396 case GDK_MOTION_NOTIFY:
397 ret = motion_handler (item, event);
400 case GDK_ENTER_NOTIFY:
401 ret = enter_handler (item, event, AutomationTrackItem);
404 case GDK_LEAVE_NOTIFY:
405 ret = leave_handler (item, event, AutomationTrackItem);
416 Editor::canvas_start_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
418 if (!rv->sensitive()) {
422 switch (event->type) {
423 case GDK_BUTTON_PRESS:
424 clicked_regionview = rv;
425 clicked_control_point = 0;
426 clicked_axisview = &rv->get_time_axis_view();
427 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
428 if (event->button.button == 3) {
429 return button_press_handler (item, event, StartCrossFadeItem);
433 case GDK_BUTTON_RELEASE:
434 if (event->button.button == 3) {
435 return button_release_handler (item, event, StartCrossFadeItem);
444 /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
445 /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
446 /* if we return RegionItem here then we avoid the issue until it is resolved later */
447 return typed_event (item, event, RegionItem); // StartCrossFadeItem);
451 Editor::canvas_end_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
453 if (!rv->sensitive()) {
457 switch (event->type) {
458 case GDK_BUTTON_PRESS:
459 clicked_regionview = rv;
460 clicked_control_point = 0;
461 clicked_axisview = &rv->get_time_axis_view();
462 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
463 if (event->button.button == 3) {
464 return button_press_handler (item, event, EndCrossFadeItem);
468 case GDK_BUTTON_RELEASE:
469 if (event->button.button == 3) {
470 return button_release_handler (item, event, EndCrossFadeItem);
479 /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
480 /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
481 /* if we return RegionItem here then we avoid the issue until it is resolved later */
482 return typed_event (item, event, RegionItem); // EndCrossFadeItem);
486 Editor::canvas_fade_in_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
488 /* we handle only button 3 press/release events */
490 if (!rv->sensitive()) {
494 switch (event->type) {
495 case GDK_BUTTON_PRESS:
496 clicked_regionview = rv;
497 clicked_control_point = 0;
498 clicked_axisview = &rv->get_time_axis_view();
499 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
500 if (event->button.button == 3) {
501 return button_press_handler (item, event, FadeInItem);
505 case GDK_BUTTON_RELEASE:
506 if (event->button.button == 3) {
507 return button_release_handler (item, event, FadeInItem);
516 /* proxy for the regionview, except enter/leave events */
518 if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
521 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
526 Editor::canvas_fade_in_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv, bool trim)
530 if (!rv->sensitive()) {
534 switch (event->type) {
535 case GDK_BUTTON_PRESS:
536 case GDK_2BUTTON_PRESS:
537 case GDK_3BUTTON_PRESS:
538 clicked_regionview = rv;
539 clicked_control_point = 0;
540 clicked_axisview = &rv->get_time_axis_view();
541 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
542 ret = button_press_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
545 case GDK_BUTTON_RELEASE:
546 ret = button_release_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
547 maybe_locate_with_edit_preroll ( rv->region()->position() );
550 case GDK_MOTION_NOTIFY:
551 ret = motion_handler (item, event);
554 case GDK_ENTER_NOTIFY:
555 ret = enter_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
558 case GDK_LEAVE_NOTIFY:
559 ret = leave_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
570 Editor::canvas_fade_out_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
572 /* we handle only button 3 press/release events */
574 if (!rv->sensitive()) {
578 switch (event->type) {
579 case GDK_BUTTON_PRESS:
580 clicked_regionview = rv;
581 clicked_control_point = 0;
582 clicked_axisview = &rv->get_time_axis_view();
583 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
584 if (event->button.button == 3) {
585 return button_press_handler (item, event, FadeOutItem);
589 case GDK_BUTTON_RELEASE:
590 if (event->button.button == 3) {
591 return button_release_handler (item, event, FadeOutItem);
600 /* proxy for the regionview, except enter/leave events */
602 if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
605 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
610 Editor::canvas_fade_out_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv, bool trim)
614 if (!rv->sensitive()) {
618 switch (event->type) {
619 case GDK_BUTTON_PRESS:
620 case GDK_2BUTTON_PRESS:
621 case GDK_3BUTTON_PRESS:
622 clicked_regionview = rv;
623 clicked_control_point = 0;
624 clicked_axisview = &rv->get_time_axis_view();
625 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
626 ret = button_press_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
629 case GDK_BUTTON_RELEASE:
630 ret = button_release_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
631 maybe_locate_with_edit_preroll ( rv->region()->last_frame() - rv->get_fade_out_shape_width() );
634 case GDK_MOTION_NOTIFY:
635 ret = motion_handler (item, event);
638 case GDK_ENTER_NOTIFY:
639 ret = enter_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
642 case GDK_LEAVE_NOTIFY:
643 ret = leave_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
653 struct DescendingRegionLayerSorter {
654 bool operator()(boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
655 return a->layer() > b->layer();
660 Editor::canvas_control_point_event (GdkEvent *event, ArdourCanvas::Item* item, ControlPoint* cp)
662 switch (event->type) {
663 case GDK_BUTTON_PRESS:
664 case GDK_2BUTTON_PRESS:
665 case GDK_3BUTTON_PRESS:
666 clicked_control_point = cp;
667 clicked_axisview = &cp->line().trackview;
668 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
669 clicked_regionview = 0;
675 case GDK_SCROLL_DOWN:
682 return typed_event (item, event, ControlPointItem);
686 Editor::canvas_line_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationLine* al)
690 if (dynamic_cast<AudioRegionGainLine*> (al) != 0) {
693 type = AutomationLineItem;
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_frame_handle_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
804 /* frame 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: frame 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, Marker* /*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_meter_marker_event (GdkEvent *event, ArdourCanvas::Item* item, MeterMarker* /*marker*/)
1021 return typed_event (item, event, MeterMarkerItem);
1025 Editor::canvas_ruler_event (GdkEvent *event, ArdourCanvas::Item* item, ItemType type)
1028 bool handled = false;
1030 if (event->type == GDK_SCROLL) {
1032 /* scroll events in the rulers are handled a little differently from
1033 scrolling elsewhere in the canvas.
1036 switch (event->scroll.direction) {
1039 if (Profile->get_mixbus()) {
1040 //for mouse-wheel zoom, force zoom-focus to mouse
1041 Editing::ZoomFocus temp_focus = zoom_focus;
1042 zoom_focus = Editing::ZoomFocusMouse;
1043 temporal_zoom_step (false);
1044 zoom_focus = temp_focus;
1046 temporal_zoom_step (false);
1051 case GDK_SCROLL_DOWN:
1052 if (Profile->get_mixbus()) {
1053 //for mouse-wheel zoom, force zoom-focus to mouse
1054 Editing::ZoomFocus temp_focus = zoom_focus;
1055 zoom_focus = Editing::ZoomFocusMouse;
1056 temporal_zoom_step (true);
1057 zoom_focus = temp_focus;
1059 temporal_zoom_step (true);
1064 case GDK_SCROLL_LEFT:
1065 xdelta = (current_page_samples() / 2);
1066 if (leftmost_frame > xdelta) {
1067 reset_x_origin (leftmost_frame - xdelta);
1074 case GDK_SCROLL_RIGHT:
1075 xdelta = (current_page_samples() / 2);
1076 if (max_framepos - xdelta > leftmost_frame) {
1077 reset_x_origin (leftmost_frame + xdelta);
1079 reset_x_origin (max_framepos - current_page_samples());
1091 return typed_event (item, event, type);
1095 Editor::canvas_tempo_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1097 return typed_event (item, event, TempoBarItem);
1101 Editor::canvas_meter_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1103 return typed_event (item, event, MeterBarItem);
1107 Editor::canvas_playhead_cursor_event (GdkEvent *event, ArdourCanvas::Item* item)
1109 return typed_event (item, event, PlayheadCursorItem);
1113 Editor::canvas_note_event (GdkEvent *event, ArdourCanvas::Item* item)
1115 if (!internal_editing()) {
1119 return typed_event (item, event, NoteItem);
1123 Editor::canvas_drop_zone_event (GdkEvent* event)
1125 GdkEventScroll scroll;
1126 ArdourCanvas::Duple winpos;
1128 switch (event->type) {
1129 case GDK_BUTTON_RELEASE:
1130 if (event->button.button == 1) {
1131 begin_reversible_selection_op (_("Nowhere Click"));
1132 selection->clear_objects ();
1133 selection->clear_tracks ();
1134 commit_reversible_selection_op ();
1139 /* convert coordinates back into window space so that
1140 we can just call canvas_scroll_event().
1142 winpos = _track_canvas->canvas_to_window (Duple (event->scroll.x, event->scroll.y));
1143 scroll = event->scroll;
1144 scroll.x = winpos.x;
1145 scroll.y = winpos.y;
1146 return canvas_scroll_event (&scroll, true);
1149 case GDK_ENTER_NOTIFY:
1150 return typed_event (_canvas_drop_zone, event, DropZoneItem);
1152 case GDK_LEAVE_NOTIFY:
1153 return typed_event (_canvas_drop_zone, event, DropZoneItem);
1163 Editor::track_canvas_drag_motion (Glib::RefPtr<Gdk::DragContext> const& context, int x, int y, guint time)
1165 boost::shared_ptr<Region> region;
1166 boost::shared_ptr<Region> region_copy;
1167 RouteTimeAxisView* rtav;
1172 string target = _track_canvas->drag_dest_find_target (context, _track_canvas->drag_dest_get_target_list());
1174 if (target.empty()) {
1178 event.type = GDK_MOTION_NOTIFY;
1181 /* assume we're dragging with button 1 */
1182 event.motion.state = Gdk::BUTTON1_MASK;
1184 (void) window_event_sample (&event, &px, &py);
1186 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py, false);
1187 bool can_drop = false;
1189 if (tv.first != 0) {
1191 /* over a time axis view of some kind */
1193 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1195 if (rtav != 0 && rtav->is_track ()) {
1196 /* over a track, not a bus */
1202 /* not over a time axis view, so drop is possible */
1207 region = _regions->get_dragged_region ();
1211 if ((boost::dynamic_pointer_cast<AudioRegion> (region) != 0 &&
1212 dynamic_cast<AudioTimeAxisView*> (tv.first) != 0) ||
1213 (boost::dynamic_pointer_cast<MidiRegion> (region) != 0 &&
1214 dynamic_cast<MidiTimeAxisView*> (tv.first) != 0)) {
1221 context->drag_status (context->get_suggested_action(), time);
1225 /* DND originating from outside ardour
1227 * TODO: check if file is audio/midi, allow drops on same track-type only,
1228 * currently: if audio is dropped on a midi-track, it is only added to the region-list
1230 if (Profile->get_sae() || ARDOUR_UI::config()->get_only_copy_imported_files()) {
1231 context->drag_status(Gdk::ACTION_COPY, time);
1233 if ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY) {
1234 context->drag_status(Gdk::ACTION_COPY, time);
1236 context->drag_status(Gdk::ACTION_LINK, time);
1244 context->drag_status (Gdk::DragAction (0), time);
1249 Editor::drop_regions (const Glib::RefPtr<Gdk::DragContext>& /*context*/,
1251 const SelectionData& /*data*/,
1252 guint /*info*/, guint /*time*/)
1254 boost::shared_ptr<Region> region;
1255 boost::shared_ptr<Region> region_copy;
1256 RouteTimeAxisView* rtav;
1261 event.type = GDK_MOTION_NOTIFY;
1264 /* assume we're dragging with button 1 */
1265 event.motion.state = Gdk::BUTTON1_MASK;
1267 framepos_t const pos = window_event_sample (&event, &px, &py);
1269 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py, false);
1271 if (tv.first != 0) {
1273 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1275 if (rtav != 0 && rtav->is_track ()) {
1277 boost::shared_ptr<Region> region = _regions->get_dragged_region ();
1281 region_copy = RegionFactory::create (region, true);
1284 if ((boost::dynamic_pointer_cast<AudioRegion> (region_copy) != 0 &&
1285 dynamic_cast<AudioTimeAxisView*> (tv.first) != 0) ||
1286 (boost::dynamic_pointer_cast<MidiRegion> (region_copy) != 0 &&
1287 dynamic_cast<MidiTimeAxisView*> (tv.first) != 0)) {
1295 _drags->set (new RegionInsertDrag (this, region_copy, rtav, pos), &event);
1296 _drags->end_grab (0);
1304 Editor::key_press_handler (ArdourCanvas::Item*, GdkEvent*, ItemType)
1310 Editor::key_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType type)
1313 bool handled = false;
1316 case TempoMarkerItem:
1317 switch (event->key.keyval) {
1319 remove_tempo_marker (item);
1327 case MeterMarkerItem:
1328 switch (event->key.keyval) {
1330 remove_meter_marker (item);