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 begin_reversible_selection_op (_("Clear Selection Click (track canvas)"));
183 commit_reversible_selection_op();
184 _track_canvas->grab_focus();
189 Editor::track_canvas_button_release_event (GdkEventButton *event)
191 if (_drags->active ()) {
192 _drags->end_grab ((GdkEvent*) event);
198 Editor::track_canvas_motion_notify_event (GdkEventMotion */*event*/)
201 /* keep those motion events coming */
202 _track_canvas->get_pointer (x, y);
207 Editor::typed_event (ArdourCanvas::Item* item, GdkEvent *event, ItemType type)
211 switch (event->type) {
212 case GDK_BUTTON_PRESS:
213 case GDK_2BUTTON_PRESS:
214 case GDK_3BUTTON_PRESS:
215 ret = button_press_handler (item, event, type);
217 case GDK_BUTTON_RELEASE:
218 ret = button_release_handler (item, event, type);
220 case GDK_MOTION_NOTIFY:
221 ret = motion_handler (item, event);
224 case GDK_ENTER_NOTIFY:
225 ret = enter_handler (item, event, type);
228 case GDK_LEAVE_NOTIFY:
229 ret = leave_handler (item, event, type);
233 ret = key_press_handler (item, event, type);
236 case GDK_KEY_RELEASE:
237 ret = key_release_handler (item, event, type);
247 Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView *rv)
251 if (!rv->sensitive ()) {
255 switch (event->type) {
256 case GDK_BUTTON_PRESS:
257 case GDK_2BUTTON_PRESS:
258 case GDK_3BUTTON_PRESS:
259 clicked_regionview = rv;
260 clicked_control_point = 0;
261 clicked_axisview = &rv->get_time_axis_view();
262 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
263 ret = button_press_handler (item, event, RegionItem);
266 case GDK_BUTTON_RELEASE:
267 ret = button_release_handler (item, event, RegionItem);
270 case GDK_MOTION_NOTIFY:
271 ret = motion_handler (item, event);
274 case GDK_ENTER_NOTIFY:
275 set_entered_regionview (rv);
276 ret = enter_handler (item, event, RegionItem);
279 case GDK_LEAVE_NOTIFY:
280 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) {
281 set_entered_regionview (0);
282 ret = leave_handler (item, event, RegionItem);
294 Editor::canvas_wave_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
296 /* we only care about enter events here, required for mouse/cursor
297 * tracking. there is a non-linear (non-child/non-parent) relationship
298 * between various components of a regionview and so when we leave one
299 * of them (e.g. a trim handle) and enter another (e.g. the waveview)
300 * no other items get notified. enter/leave handling does not propagate
301 * in the same way as other events, so we need to catch this because
302 * entering (and leaving) the waveview is equivalent to
303 * entering/leaving the regionview (which is why it is passed in as a
306 * And in fact, we really only care about enter events.
311 if (!rv->sensitive ()) {
315 switch (event->type) {
316 case GDK_ENTER_NOTIFY:
317 set_entered_regionview (rv);
318 ret = enter_handler (item, event, WaveItem);
330 Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, RouteTimeAxisView *tv)
334 switch (event->type) {
335 case GDK_BUTTON_PRESS:
336 case GDK_2BUTTON_PRESS:
337 case GDK_3BUTTON_PRESS:
338 clicked_regionview = 0;
339 clicked_control_point = 0;
340 clicked_axisview = tv;
341 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
342 ret = button_press_handler (item, event, StreamItem);
345 case GDK_BUTTON_RELEASE:
346 ret = button_release_handler (item, event, StreamItem);
349 case GDK_MOTION_NOTIFY:
350 ret = motion_handler (item, event);
353 case GDK_ENTER_NOTIFY:
354 set_entered_track (tv);
355 ret = enter_handler (item, event, StreamItem);
358 case GDK_LEAVE_NOTIFY:
359 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) {
360 set_entered_track (0);
362 ret = leave_handler (item, event, StreamItem);
373 Editor::canvas_automation_track_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationTimeAxisView *atv)
377 switch (event->type) {
378 case GDK_BUTTON_PRESS:
379 case GDK_2BUTTON_PRESS:
380 case GDK_3BUTTON_PRESS:
381 clicked_regionview = 0;
382 clicked_control_point = 0;
383 clicked_axisview = atv;
384 clicked_routeview = 0;
385 ret = button_press_handler (item, event, AutomationTrackItem);
388 case GDK_BUTTON_RELEASE:
389 ret = button_release_handler (item, event, AutomationTrackItem);
392 case GDK_MOTION_NOTIFY:
393 ret = motion_handler (item, event);
396 case GDK_ENTER_NOTIFY:
397 ret = enter_handler (item, event, AutomationTrackItem);
400 case GDK_LEAVE_NOTIFY:
401 ret = leave_handler (item, event, AutomationTrackItem);
412 Editor::canvas_start_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
414 if (!rv->sensitive()) {
418 switch (event->type) {
419 case GDK_BUTTON_PRESS:
420 clicked_regionview = rv;
421 clicked_control_point = 0;
422 clicked_axisview = &rv->get_time_axis_view();
423 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
424 if (event->button.button == 3) {
425 return button_press_handler (item, event, StartCrossFadeItem);
429 case GDK_BUTTON_RELEASE:
430 if (event->button.button == 3) {
431 return button_release_handler (item, event, StartCrossFadeItem);
440 /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
441 /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
442 /* if we return RegionItem here then we avoid the issue until it is resolved later */
443 return typed_event (item, event, RegionItem); // StartCrossFadeItem);
447 Editor::canvas_end_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
449 if (!rv->sensitive()) {
453 switch (event->type) {
454 case GDK_BUTTON_PRESS:
455 clicked_regionview = rv;
456 clicked_control_point = 0;
457 clicked_axisview = &rv->get_time_axis_view();
458 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
459 if (event->button.button == 3) {
460 return button_press_handler (item, event, EndCrossFadeItem);
464 case GDK_BUTTON_RELEASE:
465 if (event->button.button == 3) {
466 return button_release_handler (item, event, EndCrossFadeItem);
475 /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
476 /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
477 /* if we return RegionItem here then we avoid the issue until it is resolved later */
478 return typed_event (item, event, RegionItem); // EndCrossFadeItem);
482 Editor::canvas_fade_in_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
484 /* we handle only button 3 press/release events */
486 if (!rv->sensitive()) {
490 switch (event->type) {
491 case GDK_BUTTON_PRESS:
492 clicked_regionview = rv;
493 clicked_control_point = 0;
494 clicked_axisview = &rv->get_time_axis_view();
495 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
496 if (event->button.button == 3) {
497 return button_press_handler (item, event, FadeInItem);
501 case GDK_BUTTON_RELEASE:
502 if (event->button.button == 3) {
503 return button_release_handler (item, event, FadeInItem);
512 /* proxy for the regionview, except enter/leave events */
514 if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
517 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
522 Editor::canvas_fade_in_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv, bool trim)
526 if (!rv->sensitive()) {
530 switch (event->type) {
531 case GDK_BUTTON_PRESS:
532 case GDK_2BUTTON_PRESS:
533 case GDK_3BUTTON_PRESS:
534 clicked_regionview = rv;
535 clicked_control_point = 0;
536 clicked_axisview = &rv->get_time_axis_view();
537 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
538 ret = button_press_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
541 case GDK_BUTTON_RELEASE:
542 ret = button_release_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
543 maybe_locate_with_edit_preroll ( rv->region()->position() );
546 case GDK_MOTION_NOTIFY:
547 ret = motion_handler (item, event);
550 case GDK_ENTER_NOTIFY:
551 ret = enter_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
554 case GDK_LEAVE_NOTIFY:
555 ret = leave_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
566 Editor::canvas_fade_out_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
568 /* we handle only button 3 press/release events */
570 if (!rv->sensitive()) {
574 switch (event->type) {
575 case GDK_BUTTON_PRESS:
576 clicked_regionview = rv;
577 clicked_control_point = 0;
578 clicked_axisview = &rv->get_time_axis_view();
579 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
580 if (event->button.button == 3) {
581 return button_press_handler (item, event, FadeOutItem);
585 case GDK_BUTTON_RELEASE:
586 if (event->button.button == 3) {
587 return button_release_handler (item, event, FadeOutItem);
596 /* proxy for the regionview, except enter/leave events */
598 if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
601 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
606 Editor::canvas_fade_out_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv, bool trim)
610 if (!rv->sensitive()) {
614 switch (event->type) {
615 case GDK_BUTTON_PRESS:
616 case GDK_2BUTTON_PRESS:
617 case GDK_3BUTTON_PRESS:
618 clicked_regionview = rv;
619 clicked_control_point = 0;
620 clicked_axisview = &rv->get_time_axis_view();
621 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
622 ret = button_press_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
625 case GDK_BUTTON_RELEASE:
626 ret = button_release_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
627 maybe_locate_with_edit_preroll ( rv->region()->last_frame() - rv->get_fade_out_shape_width() );
630 case GDK_MOTION_NOTIFY:
631 ret = motion_handler (item, event);
634 case GDK_ENTER_NOTIFY:
635 ret = enter_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
638 case GDK_LEAVE_NOTIFY:
639 ret = leave_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
649 struct DescendingRegionLayerSorter {
650 bool operator()(boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
651 return a->layer() > b->layer();
656 Editor::canvas_control_point_event (GdkEvent *event, ArdourCanvas::Item* item, ControlPoint* cp)
658 switch (event->type) {
659 case GDK_BUTTON_PRESS:
660 case GDK_2BUTTON_PRESS:
661 case GDK_3BUTTON_PRESS:
662 clicked_control_point = cp;
663 clicked_axisview = &cp->line().trackview;
664 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
665 clicked_regionview = 0;
671 case GDK_SCROLL_DOWN:
678 return typed_event (item, event, ControlPointItem);
682 Editor::canvas_line_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationLine* al)
686 if (dynamic_cast<AudioRegionGainLine*> (al) != 0) {
689 type = AutomationLineItem;
692 return typed_event (item, event, type);
696 Editor::canvas_selection_rect_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
700 switch (event->type) {
701 case GDK_BUTTON_PRESS:
702 case GDK_2BUTTON_PRESS:
703 case GDK_3BUTTON_PRESS:
704 clicked_selection = rect->id;
705 ret = button_press_handler (item, event, SelectionItem);
707 case GDK_BUTTON_RELEASE:
708 ret = button_release_handler (item, event, SelectionItem);
710 case GDK_MOTION_NOTIFY:
711 ret = motion_handler (item, event);
713 /* Don't need these at the moment. */
714 case GDK_ENTER_NOTIFY:
715 ret = enter_handler (item, event, SelectionItem);
718 case GDK_LEAVE_NOTIFY:
719 ret = leave_handler (item, event, SelectionItem);
730 Editor::canvas_selection_start_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
734 switch (event->type) {
735 case GDK_BUTTON_PRESS:
736 case GDK_2BUTTON_PRESS:
737 case GDK_3BUTTON_PRESS:
738 clicked_selection = rect->id;
739 ret = button_press_handler (item, event, StartSelectionTrimItem);
741 case GDK_BUTTON_RELEASE:
742 ret = button_release_handler (item, event, StartSelectionTrimItem);
744 case GDK_MOTION_NOTIFY:
745 ret = motion_handler (item, event);
747 case GDK_ENTER_NOTIFY:
748 ret = enter_handler (item, event, StartSelectionTrimItem);
751 case GDK_LEAVE_NOTIFY:
752 ret = leave_handler (item, event, StartSelectionTrimItem);
763 Editor::canvas_selection_end_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
767 switch (event->type) {
768 case GDK_BUTTON_PRESS:
769 case GDK_2BUTTON_PRESS:
770 case GDK_3BUTTON_PRESS:
771 clicked_selection = rect->id;
772 ret = button_press_handler (item, event, EndSelectionTrimItem);
774 case GDK_BUTTON_RELEASE:
775 ret = button_release_handler (item, event, EndSelectionTrimItem);
777 case GDK_MOTION_NOTIFY:
778 ret = motion_handler (item, event);
780 case GDK_ENTER_NOTIFY:
781 ret = enter_handler (item, event, EndSelectionTrimItem);
784 case GDK_LEAVE_NOTIFY:
785 ret = leave_handler (item, event, EndSelectionTrimItem);
796 Editor::canvas_frame_handle_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
800 /* frame handles are not active when in internal edit mode, because actual notes
801 might be in the area occupied by the handle - we want them to be editable as normal.
804 if (internal_editing() || !rv->sensitive()) {
808 /* NOTE: frame handles pretend to be the colored trim bar from an event handling
809 perspective. XXX change this ??
814 if (item->get_data ("isleft")) {
815 type = LeftFrameHandle;
817 type = RightFrameHandle;
820 switch (event->type) {
821 case GDK_BUTTON_PRESS:
822 case GDK_2BUTTON_PRESS:
823 case GDK_3BUTTON_PRESS:
824 clicked_regionview = rv;
825 clicked_control_point = 0;
826 clicked_axisview = &clicked_regionview->get_time_axis_view();
827 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
828 ret = button_press_handler (item, event, type);
830 case GDK_BUTTON_RELEASE:
831 ret = button_release_handler (item, event, type);
833 case GDK_MOTION_NOTIFY:
834 ret = motion_handler (item, event);
836 case GDK_ENTER_NOTIFY:
837 ret = enter_handler (item, event, type);
840 case GDK_LEAVE_NOTIFY:
841 ret = leave_handler (item, event, type);
853 Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
857 if (!rv->sensitive()) {
861 switch (event->type) {
862 case GDK_BUTTON_PRESS:
863 case GDK_2BUTTON_PRESS:
864 case GDK_3BUTTON_PRESS:
865 clicked_regionview = rv;
866 clicked_control_point = 0;
867 clicked_axisview = &clicked_regionview->get_time_axis_view();
868 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
869 ret = button_press_handler (item, event, RegionViewNameHighlight);
871 case GDK_BUTTON_RELEASE:
872 ret = button_release_handler (item, event, RegionViewNameHighlight);
874 case GDK_MOTION_NOTIFY:
875 motion_handler (item, event);
876 ret = true; // force this to avoid progagating the event into the regionview
878 case GDK_ENTER_NOTIFY:
879 ret = enter_handler (item, event, RegionViewNameHighlight);
882 case GDK_LEAVE_NOTIFY:
883 ret = leave_handler (item, event, RegionViewNameHighlight);
894 Editor::canvas_region_view_name_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
898 if (!rv->sensitive()) {
902 switch (event->type) {
903 case GDK_BUTTON_PRESS:
904 case GDK_2BUTTON_PRESS:
905 case GDK_3BUTTON_PRESS:
906 clicked_regionview = rv;
907 clicked_control_point = 0;
908 clicked_axisview = &clicked_regionview->get_time_axis_view();
909 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
910 ret = button_press_handler (item, event, RegionViewName);
912 case GDK_BUTTON_RELEASE:
913 ret = button_release_handler (item, event, RegionViewName);
915 case GDK_MOTION_NOTIFY:
916 ret = motion_handler (item, event);
918 case GDK_ENTER_NOTIFY:
919 ret = enter_handler (item, event, RegionViewName);
922 case GDK_LEAVE_NOTIFY:
923 ret = leave_handler (item, event, RegionViewName);
934 Editor::canvas_feature_line_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView*)
938 switch (event->type) {
939 case GDK_BUTTON_PRESS:
940 case GDK_2BUTTON_PRESS:
941 case GDK_3BUTTON_PRESS:
942 clicked_regionview = 0;
943 clicked_control_point = 0;
944 clicked_axisview = 0;
945 clicked_routeview = 0; //dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
946 ret = button_press_handler (item, event, FeatureLineItem);
949 case GDK_BUTTON_RELEASE:
950 ret = button_release_handler (item, event, FeatureLineItem);
953 case GDK_MOTION_NOTIFY:
954 ret = motion_handler (item, event);
957 case GDK_ENTER_NOTIFY:
958 ret = enter_handler (item, event, FeatureLineItem);
961 case GDK_LEAVE_NOTIFY:
962 ret = leave_handler (item, event, FeatureLineItem);
973 Editor::canvas_marker_event (GdkEvent *event, ArdourCanvas::Item* item, Marker* /*marker*/)
975 return typed_event (item, event, MarkerItem);
979 Editor::canvas_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
981 return typed_event (item, event, MarkerBarItem);
985 Editor::canvas_range_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
987 return typed_event (item, event, RangeMarkerBarItem);
991 Editor::canvas_transport_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
993 return typed_event (item, event, TransportMarkerBarItem);
997 Editor::canvas_cd_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
999 return typed_event (item, event, CdMarkerBarItem);
1003 Editor::canvas_videotl_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1005 return typed_event (item, event, VideoBarItem);
1009 Editor::canvas_tempo_marker_event (GdkEvent *event, ArdourCanvas::Item* item, TempoMarker* /*marker*/)
1011 return typed_event (item, event, TempoMarkerItem);
1015 Editor::canvas_meter_marker_event (GdkEvent *event, ArdourCanvas::Item* item, MeterMarker* /*marker*/)
1017 return typed_event (item, event, MeterMarkerItem);
1021 Editor::canvas_ruler_event (GdkEvent *event, ArdourCanvas::Item* item, ItemType type)
1024 bool handled = false;
1026 if (event->type == GDK_SCROLL) {
1028 /* scroll events in the rulers are handled a little differently from
1029 scrolling elsewhere in the canvas.
1032 switch (event->scroll.direction) {
1034 temporal_zoom_step (false);
1038 case GDK_SCROLL_DOWN:
1039 temporal_zoom_step (true);
1043 case GDK_SCROLL_LEFT:
1044 xdelta = (current_page_samples() / 2);
1045 if (leftmost_frame > xdelta) {
1046 reset_x_origin (leftmost_frame - xdelta);
1053 case GDK_SCROLL_RIGHT:
1054 xdelta = (current_page_samples() / 2);
1055 if (max_framepos - xdelta > leftmost_frame) {
1056 reset_x_origin (leftmost_frame + xdelta);
1058 reset_x_origin (max_framepos - current_page_samples());
1070 return typed_event (item, event, type);
1074 Editor::canvas_tempo_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1076 return typed_event (item, event, TempoBarItem);
1080 Editor::canvas_meter_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1082 return typed_event (item, event, MeterBarItem);
1086 Editor::canvas_playhead_cursor_event (GdkEvent *event, ArdourCanvas::Item* item)
1088 return typed_event (item, event, PlayheadCursorItem);
1092 Editor::canvas_note_event (GdkEvent *event, ArdourCanvas::Item* item)
1094 if (!internal_editing()) {
1098 return typed_event (item, event, NoteItem);
1102 Editor::canvas_drop_zone_event (GdkEvent* event)
1104 GdkEventScroll scroll;
1105 ArdourCanvas::Duple winpos;
1107 switch (event->type) {
1108 case GDK_BUTTON_RELEASE:
1109 if (event->button.button == 1) {
1110 begin_reversible_selection_op (_("Nowhere Click"));
1111 selection->clear_objects ();
1112 selection->clear_tracks ();
1113 commit_reversible_selection_op ();
1118 /* convert coordinates back into window space so that
1119 we can just call canvas_scroll_event().
1121 winpos = _track_canvas->canvas_to_window (Duple (event->scroll.x, event->scroll.y));
1122 scroll = event->scroll;
1123 scroll.x = winpos.x;
1124 scroll.y = winpos.y;
1125 return canvas_scroll_event (&scroll, true);
1128 case GDK_ENTER_NOTIFY:
1129 return typed_event (_canvas_drop_zone, event, DropZoneItem);
1131 case GDK_LEAVE_NOTIFY:
1132 return typed_event (_canvas_drop_zone, event, DropZoneItem);
1142 Editor::track_canvas_drag_motion (Glib::RefPtr<Gdk::DragContext> const& context, int x, int y, guint time)
1144 boost::shared_ptr<Region> region;
1145 boost::shared_ptr<Region> region_copy;
1146 RouteTimeAxisView* rtav;
1151 string target = _track_canvas->drag_dest_find_target (context, _track_canvas->drag_dest_get_target_list());
1153 if (target.empty()) {
1157 event.type = GDK_MOTION_NOTIFY;
1160 /* assume we're dragging with button 1 */
1161 event.motion.state = Gdk::BUTTON1_MASK;
1163 (void) window_event_sample (&event, &px, &py);
1165 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py, false);
1166 bool can_drop = false;
1168 if (tv.first != 0) {
1170 /* over a time axis view of some kind */
1172 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1174 if (rtav != 0 && rtav->is_track ()) {
1175 /* over a track, not a bus */
1181 /* not over a time axis view, so drop is possible */
1186 region = _regions->get_dragged_region ();
1190 if ((boost::dynamic_pointer_cast<AudioRegion> (region) != 0 &&
1191 dynamic_cast<AudioTimeAxisView*> (tv.first) != 0) ||
1192 (boost::dynamic_pointer_cast<MidiRegion> (region) != 0 &&
1193 dynamic_cast<MidiTimeAxisView*> (tv.first) != 0)) {
1200 context->drag_status (context->get_suggested_action(), time);
1204 /* DND originating from outside ardour
1206 * TODO: check if file is audio/midi, allow drops on same track-type only,
1207 * currently: if audio is dropped on a midi-track, it is only added to the region-list
1209 if (Profile->get_sae() || ARDOUR_UI::config()->get_only_copy_imported_files()) {
1210 context->drag_status(Gdk::ACTION_COPY, time);
1212 if ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY) {
1213 context->drag_status(Gdk::ACTION_COPY, time);
1215 context->drag_status(Gdk::ACTION_LINK, time);
1223 context->drag_status (Gdk::DragAction (0), time);
1228 Editor::drop_regions (const Glib::RefPtr<Gdk::DragContext>& /*context*/,
1230 const SelectionData& /*data*/,
1231 guint /*info*/, guint /*time*/)
1233 boost::shared_ptr<Region> region;
1234 boost::shared_ptr<Region> region_copy;
1235 RouteTimeAxisView* rtav;
1240 event.type = GDK_MOTION_NOTIFY;
1243 /* assume we're dragging with button 1 */
1244 event.motion.state = Gdk::BUTTON1_MASK;
1246 framepos_t const pos = window_event_sample (&event, &px, &py);
1248 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py, false);
1250 if (tv.first != 0) {
1252 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1254 if (rtav != 0 && rtav->is_track ()) {
1256 boost::shared_ptr<Region> region = _regions->get_dragged_region ();
1260 region_copy = RegionFactory::create (region, true);
1263 if ((boost::dynamic_pointer_cast<AudioRegion> (region_copy) != 0 &&
1264 dynamic_cast<AudioTimeAxisView*> (tv.first) != 0) ||
1265 (boost::dynamic_pointer_cast<MidiRegion> (region_copy) != 0 &&
1266 dynamic_cast<MidiTimeAxisView*> (tv.first) != 0)) {
1274 _drags->set (new RegionInsertDrag (this, region_copy, rtav, pos), &event);
1275 _drags->end_grab (0);
1283 Editor::key_press_handler (ArdourCanvas::Item*, GdkEvent*, ItemType)
1289 Editor::key_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType type)
1292 bool handled = false;
1295 case TempoMarkerItem:
1296 switch (event->key.keyval) {
1298 remove_tempo_marker (item);
1306 case MeterMarkerItem:
1307 switch (event->key.keyval) {
1309 remove_meter_marker (item);