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_diskstream.h"
28 #include "ardour/audioplaylist.h"
32 #include "public_editor.h"
33 #include "audio_region_view.h"
34 #include "audio_streamview.h"
35 #include "crossfade_view.h"
36 #include "audio_time_axis.h"
37 #include "region_gain_line.h"
38 #include "automation_line.h"
39 #include "automation_time_axis.h"
40 #include "automation_line.h"
41 #include "control_point.h"
42 #include "canvas_impl.h"
43 #include "simplerect.h"
44 #include "interactive-item.h"
45 #include "editor_drag.h"
51 using namespace ARDOUR;
54 using namespace ArdourCanvas;
57 Editor::track_canvas_scroll (GdkEventScroll* ev)
62 int direction = ev->direction;
64 Gnome::Canvas::Item* item = track_canvas->get_item_at(ev->x, ev->y);
65 InteractiveItem* interactive_item = dynamic_cast<InteractiveItem*>(item);
66 if (interactive_item) {
67 return interactive_item->on_event(reinterpret_cast<GdkEvent*>(ev));
73 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
74 //if (ev->state == GDK_CONTROL_MASK) {
76 the ev->x will be out of step with the canvas
77 if we're in mid zoom, so we have to get the damn mouse
80 track_canvas->get_pointer (x, y);
81 track_canvas->window_to_world (x, y, wx, wy);
84 event.type = GDK_BUTTON_RELEASE;
88 nframes64_t where = event_frame (&event, 0, 0);
89 temporal_zoom_to_frame (false, where);
91 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::SecondaryModifier)) {
92 direction = GDK_SCROLL_LEFT;
94 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
95 if (!current_stepping_trackview) {
96 step_timeout = Glib::signal_timeout().connect (mem_fun(*this, &Editor::track_height_step_timeout), 500);
97 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (ev->y + vertical_adjustment.get_value() - canvas_timebars_vsize);
98 current_stepping_trackview = p.first;
99 if (!current_stepping_trackview) {
103 last_track_height_step_timestamp = get_microseconds();
104 current_stepping_trackview->step_height (true);
107 scroll_tracks_up_line ();
112 case GDK_SCROLL_DOWN:
113 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
114 //if (ev->state == GDK_CONTROL_MASK) {
115 track_canvas->get_pointer (x, y);
116 track_canvas->window_to_world (x, y, wx, wy);
119 event.type = GDK_BUTTON_RELEASE;
123 nframes64_t where = event_frame (&event, 0, 0);
124 temporal_zoom_to_frame (true, where);
126 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::SecondaryModifier)) {
127 direction = GDK_SCROLL_RIGHT;
129 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
130 if (!current_stepping_trackview) {
131 step_timeout = Glib::signal_timeout().connect (mem_fun(*this, &Editor::track_height_step_timeout), 500);
132 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (ev->y + vertical_adjustment.get_value() - canvas_timebars_vsize);
133 current_stepping_trackview = p.first;
134 if (!current_stepping_trackview) {
138 last_track_height_step_timestamp = get_microseconds();
139 current_stepping_trackview->step_height (false);
142 scroll_tracks_down_line ();
147 case GDK_SCROLL_LEFT:
148 xdelta = (current_page_frames() / 8);
149 if (leftmost_frame > xdelta) {
150 reset_x_origin (leftmost_frame - xdelta);
156 case GDK_SCROLL_RIGHT:
157 xdelta = (current_page_frames() / 8);
158 if (max_frames - xdelta > leftmost_frame) {
159 reset_x_origin (leftmost_frame + xdelta);
161 reset_x_origin (max_frames - current_page_frames());
174 Editor::track_canvas_scroll_event (GdkEventScroll *event)
176 track_canvas->grab_focus();
177 track_canvas_scroll (event);
182 Editor::track_canvas_button_press_event (GdkEventButton *event)
185 track_canvas->grab_focus();
190 Editor::track_canvas_button_release_event (GdkEventButton *event)
193 _drag->end_grab ((GdkEvent*) event);
201 Editor::track_canvas_motion_notify_event (GdkEventMotion *event)
204 /* keep those motion events coming */
205 track_canvas->get_pointer (x, y);
210 Editor::track_canvas_motion (GdkEvent *ev)
212 if (verbose_cursor_visible) {
213 verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (ev->motion.x + 10);
214 verbose_canvas_cursor->property_y() = clamp_verbose_cursor_y (ev->motion.y + 10);
221 Editor::typed_event (ArdourCanvas::Item* item, GdkEvent *event, ItemType type)
225 switch (event->type) {
226 case GDK_BUTTON_PRESS:
227 case GDK_2BUTTON_PRESS:
228 case GDK_3BUTTON_PRESS:
229 ret = button_press_handler (item, event, type);
231 case GDK_BUTTON_RELEASE:
232 ret = button_release_handler (item, event, type);
234 case GDK_MOTION_NOTIFY:
235 ret = motion_handler (item, event);
238 case GDK_ENTER_NOTIFY:
239 ret = enter_handler (item, event, type);
242 case GDK_LEAVE_NOTIFY:
243 ret = leave_handler (item, event, type);
253 Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView *rv)
257 if (!rv->sensitive ()) {
262 switch (event->type) {
263 case GDK_BUTTON_PRESS:
264 case GDK_2BUTTON_PRESS:
265 case GDK_3BUTTON_PRESS:
266 clicked_regionview = rv;
267 clicked_control_point = 0;
268 clicked_axisview = &rv->get_time_axis_view();
269 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
270 ret = button_press_handler (item, event, RegionItem);
273 case GDK_BUTTON_RELEASE:
274 ret = button_release_handler (item, event, RegionItem);
277 case GDK_MOTION_NOTIFY:
278 ret = motion_handler (item, event);
281 case GDK_ENTER_NOTIFY:
282 set_entered_track (&rv->get_time_axis_view ());
283 set_entered_regionview (rv);
286 case GDK_LEAVE_NOTIFY:
287 set_entered_track (0);
288 set_entered_regionview (0);
299 Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, RouteTimeAxisView *tv)
303 switch (event->type) {
304 case GDK_BUTTON_PRESS:
305 case GDK_2BUTTON_PRESS:
306 case GDK_3BUTTON_PRESS:
307 clicked_regionview = 0;
308 clicked_control_point = 0;
309 clicked_axisview = tv;
310 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(tv);
311 ret = button_press_handler (item, event, StreamItem);
314 case GDK_BUTTON_RELEASE:
315 ret = button_release_handler (item, event, StreamItem);
318 case GDK_MOTION_NOTIFY:
319 ret = motion_handler (item, event, StreamItem);
322 case GDK_ENTER_NOTIFY:
323 set_entered_track (tv);
326 case GDK_LEAVE_NOTIFY:
327 set_entered_track (0);
338 Editor::canvas_automation_track_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationTimeAxisView *atv)
343 switch (event->type) {
344 case GDK_BUTTON_PRESS:
345 case GDK_2BUTTON_PRESS:
346 case GDK_3BUTTON_PRESS:
347 clicked_regionview = 0;
348 clicked_control_point = 0;
349 clicked_axisview = atv;
350 clicked_routeview = 0;
351 ret = button_press_handler (item, event, AutomationTrackItem);
354 case GDK_BUTTON_RELEASE:
355 ret = button_release_handler (item, event, AutomationTrackItem);
358 case GDK_MOTION_NOTIFY:
359 ret = motion_handler (item, event);
362 case GDK_ENTER_NOTIFY:
363 ret = enter_handler (item, event, AutomationTrackItem);
366 case GDK_LEAVE_NOTIFY:
367 ret = leave_handler (item, event, AutomationTrackItem);
378 Editor::canvas_fade_in_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
380 /* we handle only button 3 press/release events */
382 if (!rv->sensitive()) {
386 switch (event->type) {
387 case GDK_BUTTON_PRESS:
388 clicked_regionview = rv;
389 clicked_control_point = 0;
390 clicked_axisview = &rv->get_time_axis_view();
391 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
392 if (event->button.button == 3) {
393 return button_press_handler (item, event, FadeInItem);
397 case GDK_BUTTON_RELEASE:
398 if (event->button.button == 3) {
399 return button_release_handler (item, event, FadeInItem);
408 /* proxy for the regionview */
410 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
414 Editor::canvas_fade_in_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
418 if (!rv->sensitive()) {
422 switch (event->type) {
423 case GDK_BUTTON_PRESS:
424 case GDK_2BUTTON_PRESS:
425 case GDK_3BUTTON_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 ret = button_press_handler (item, event, FadeInHandleItem);
433 case GDK_BUTTON_RELEASE:
434 ret = button_release_handler (item, event, FadeInHandleItem);
437 case GDK_MOTION_NOTIFY:
438 ret = motion_handler (item, event);
441 case GDK_ENTER_NOTIFY:
442 ret = enter_handler (item, event, FadeInHandleItem);
445 case GDK_LEAVE_NOTIFY:
446 ret = leave_handler (item, event, FadeInHandleItem);
457 Editor::canvas_fade_out_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
459 /* we handle only button 3 press/release events */
461 if (!rv->sensitive()) {
465 switch (event->type) {
466 case GDK_BUTTON_PRESS:
467 clicked_regionview = rv;
468 clicked_control_point = 0;
469 clicked_axisview = &rv->get_time_axis_view();
470 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
471 if (event->button.button == 3) {
472 return button_press_handler (item, event, FadeOutItem);
476 case GDK_BUTTON_RELEASE:
477 if (event->button.button == 3) {
478 return button_release_handler (item, event, FadeOutItem);
487 /* proxy for the regionview */
489 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
493 Editor::canvas_fade_out_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
497 if (!rv->sensitive()) {
501 switch (event->type) {
502 case GDK_BUTTON_PRESS:
503 case GDK_2BUTTON_PRESS:
504 case GDK_3BUTTON_PRESS:
505 clicked_regionview = rv;
506 clicked_control_point = 0;
507 clicked_axisview = &rv->get_time_axis_view();
508 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
509 ret = button_press_handler (item, event, FadeOutHandleItem);
512 case GDK_BUTTON_RELEASE:
513 ret = button_release_handler (item, event, FadeOutHandleItem);
516 case GDK_MOTION_NOTIFY:
517 ret = motion_handler (item, event);
520 case GDK_ENTER_NOTIFY:
521 ret = enter_handler (item, event, FadeOutHandleItem);
524 case GDK_LEAVE_NOTIFY:
525 ret = leave_handler (item, event, FadeOutHandleItem);
535 struct DescendingRegionLayerSorter {
536 bool operator()(boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
537 return a->layer() > b->layer();
542 Editor::canvas_crossfade_view_event (GdkEvent* event, ArdourCanvas::Item* item, CrossfadeView* xfv)
544 /* we handle only button 3 press/release events */
546 switch (event->type) {
547 case GDK_BUTTON_PRESS:
548 clicked_crossfadeview = xfv;
549 clicked_axisview = &clicked_crossfadeview->get_time_axis_view();
550 if (event->button.button == 3) {
551 return button_press_handler (item, event, CrossfadeViewItem);
555 case GDK_BUTTON_RELEASE:
556 if (event->button.button == 3) {
557 bool ret = button_release_handler (item, event, CrossfadeViewItem);
567 /* XXX do not forward double clicks */
569 if (event->type == GDK_2BUTTON_PRESS) {
573 /* proxy for the upper most regionview */
575 /* XXX really need to check if we are in the name highlight,
576 and proxy to that when required.
579 TimeAxisView& tv (xfv->get_time_axis_view());
580 AudioTimeAxisView* atv;
582 if ((atv = dynamic_cast<AudioTimeAxisView*>(&tv)) != 0) {
584 if (atv->is_audio_track()) {
586 boost::shared_ptr<AudioPlaylist> pl;
587 if ((pl = boost::dynamic_pointer_cast<AudioPlaylist> (atv->get_diskstream()->playlist())) != 0) {
589 Playlist::RegionList* rl = pl->regions_at (event_frame (event));
592 DescendingRegionLayerSorter cmp;
595 RegionView* rv = atv->view()->find_view (rl->front());
601 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
613 Editor::canvas_control_point_event (GdkEvent *event, ArdourCanvas::Item* item, ControlPoint* cp)
615 switch (event->type) {
616 case GDK_BUTTON_PRESS:
617 case GDK_2BUTTON_PRESS:
618 case GDK_3BUTTON_PRESS:
619 clicked_control_point = cp;
620 clicked_axisview = &cp->line().trackview;
621 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
622 clicked_regionview = 0;
628 case GDK_SCROLL_DOWN:
635 return typed_event (item, event, ControlPointItem);
639 Editor::canvas_line_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationLine* al)
643 if (dynamic_cast<AudioRegionGainLine*> (al) != 0) {
646 type = AutomationLineItem;
649 return typed_event (item, event, type);
653 Editor::canvas_selection_rect_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
657 switch (event->type) {
658 case GDK_BUTTON_PRESS:
659 case GDK_2BUTTON_PRESS:
660 case GDK_3BUTTON_PRESS:
661 clicked_selection = rect->id;
662 ret = button_press_handler (item, event, SelectionItem);
664 case GDK_BUTTON_RELEASE:
665 ret = button_release_handler (item, event, SelectionItem);
667 case GDK_MOTION_NOTIFY:
668 ret = motion_handler (item, event);
670 /* Don't need these at the moment. */
671 case GDK_ENTER_NOTIFY:
672 ret = enter_handler (item, event, SelectionItem);
675 case GDK_LEAVE_NOTIFY:
676 ret = leave_handler (item, event, SelectionItem);
687 Editor::canvas_selection_start_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
691 switch (event->type) {
692 case GDK_BUTTON_PRESS:
693 case GDK_2BUTTON_PRESS:
694 case GDK_3BUTTON_PRESS:
695 clicked_selection = rect->id;
696 ret = button_press_handler (item, event, StartSelectionTrimItem);
698 case GDK_BUTTON_RELEASE:
699 ret = button_release_handler (item, event, StartSelectionTrimItem);
701 case GDK_MOTION_NOTIFY:
702 ret = motion_handler (item, event);
704 case GDK_ENTER_NOTIFY:
705 ret = enter_handler (item, event, StartSelectionTrimItem);
708 case GDK_LEAVE_NOTIFY:
709 ret = leave_handler (item, event, StartSelectionTrimItem);
720 Editor::canvas_selection_end_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
724 switch (event->type) {
725 case GDK_BUTTON_PRESS:
726 case GDK_2BUTTON_PRESS:
727 case GDK_3BUTTON_PRESS:
728 clicked_selection = rect->id;
729 ret = button_press_handler (item, event, EndSelectionTrimItem);
731 case GDK_BUTTON_RELEASE:
732 ret = button_release_handler (item, event, EndSelectionTrimItem);
734 case GDK_MOTION_NOTIFY:
735 ret = motion_handler (item, event);
737 case GDK_ENTER_NOTIFY:
738 ret = enter_handler (item, event, EndSelectionTrimItem);
741 case GDK_LEAVE_NOTIFY:
742 ret = leave_handler (item, event, EndSelectionTrimItem);
754 Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
758 if (!rv->sensitive()) {
762 switch (event->type) {
763 case GDK_BUTTON_PRESS:
764 case GDK_2BUTTON_PRESS:
765 case GDK_3BUTTON_PRESS:
766 clicked_regionview = rv;
767 clicked_control_point = 0;
768 clicked_axisview = &clicked_regionview->get_time_axis_view();
769 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
770 ret = button_press_handler (item, event, RegionViewNameHighlight);
772 case GDK_BUTTON_RELEASE:
773 ret = button_release_handler (item, event, RegionViewNameHighlight);
775 case GDK_MOTION_NOTIFY:
776 ret = motion_handler (item, event);
778 case GDK_ENTER_NOTIFY:
779 ret = enter_handler (item, event, RegionViewNameHighlight);
782 case GDK_LEAVE_NOTIFY:
783 ret = leave_handler (item, event, RegionViewNameHighlight);
794 Editor::canvas_region_view_name_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
798 if (!rv->sensitive()) {
802 switch (event->type) {
803 case GDK_BUTTON_PRESS:
804 case GDK_2BUTTON_PRESS:
805 case GDK_3BUTTON_PRESS:
806 clicked_regionview = rv;
807 clicked_control_point = 0;
808 clicked_axisview = &clicked_regionview->get_time_axis_view();
809 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
810 ret = button_press_handler (item, event, RegionViewName);
812 case GDK_BUTTON_RELEASE:
813 ret = button_release_handler (item, event, RegionViewName);
815 case GDK_MOTION_NOTIFY:
816 ret = motion_handler (item, event);
818 case GDK_ENTER_NOTIFY:
819 ret = enter_handler (item, event, RegionViewName);
822 case GDK_LEAVE_NOTIFY:
823 ret = leave_handler (item, event, RegionViewName);
834 Editor::canvas_marker_event (GdkEvent *event, ArdourCanvas::Item* item, Marker* marker)
836 return typed_event (item, event, MarkerItem);
840 Editor::canvas_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
842 return typed_event (item, event, MarkerBarItem);
846 Editor::canvas_range_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
848 return typed_event (item, event, RangeMarkerBarItem);
852 Editor::canvas_transport_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
854 return typed_event (item, event, TransportMarkerBarItem);
858 Editor::canvas_cd_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
860 return typed_event (item, event, CdMarkerBarItem);
864 Editor::canvas_tempo_marker_event (GdkEvent *event, ArdourCanvas::Item* item, TempoMarker* marker)
866 return typed_event (item, event, TempoMarkerItem);
870 Editor::canvas_meter_marker_event (GdkEvent *event, ArdourCanvas::Item* item, MeterMarker* marker)
872 return typed_event (item, event, MeterMarkerItem);
876 Editor::canvas_tempo_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
878 return typed_event (item, event, TempoBarItem);
882 Editor::canvas_meter_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
884 return typed_event (item, event, MeterBarItem);
888 Editor::canvas_playhead_cursor_event (GdkEvent *event, ArdourCanvas::Item* item)
890 return typed_event (item, event, PlayheadCursorItem);
894 Editor::canvas_zoom_rect_event (GdkEvent *event, ArdourCanvas::Item* item)
896 return typed_event (item, event, NoItem);