2 Copyright (C) 2000-2001 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.
28 #include <pbd/error.h>
29 #include <gtkmm2ext/utils.h>
31 #include "ardour_ui.h"
33 #include "time_axis_view.h"
34 #include "audio_time_axis.h"
35 #include "regionview.h"
37 #include "streamview.h"
38 #include "region_gain_line.h"
39 #include "automation_time_axis.h"
42 #include "selection.h"
45 #include "rgb_macros.h"
47 #include <ardour/types.h>
48 #include <ardour/route.h>
49 #include <ardour/audio_track.h>
50 #include <ardour/diskstream.h>
51 #include <ardour/playlist.h>
52 #include <ardour/audioplaylist.h>
53 #include <ardour/audioregion.h>
54 #include <ardour/dB.h>
55 #include <ardour/utils.h>
56 #include <ardour/region_factory.h>
63 using namespace ARDOUR;
66 using namespace Editing;
69 Editor::event_frame (GdkEvent* event, double* pcx, double* pcy)
83 switch (event->type) {
84 case GDK_BUTTON_RELEASE:
85 case GDK_BUTTON_PRESS:
86 case GDK_2BUTTON_PRESS:
87 case GDK_3BUTTON_PRESS:
88 track_canvas.w2c(event->button.x, event->button.y, *pcx, *pcy);
90 case GDK_MOTION_NOTIFY:
91 track_canvas.w2c(event->motion.x, event->motion.y, *pcx, *pcy);
93 case GDK_ENTER_NOTIFY:
94 case GDK_LEAVE_NOTIFY:
95 track_canvas.w2c(event->crossing.x, event->crossing.y, *pcx, *pcy);
98 warning << string_compose (_("Editor::event_frame() used on unhandled event type %1"), event->type) << endmsg;
102 /* note that pixel_to_frame() never returns less than zero, so even if the pixel
103 position is negative (as can be the case with motion events in particular),
104 the frame location is always positive.
107 return pixel_to_frame (*pcx);
111 Editor::mouse_mode_toggled (MouseMode m)
113 if (ignore_mouse_mode_toggle) {
119 if (mouse_select_button.get_active()) {
125 if (mouse_move_button.get_active()) {
131 if (mouse_gain_button.get_active()) {
137 if (mouse_zoom_button.get_active()) {
143 if (mouse_timefx_button.get_active()) {
149 if (mouse_audition_button.get_active()) {
160 Editor::set_mouse_mode (MouseMode m, bool force)
162 if (drag_info.item) {
166 if (m == mouse_mode && !force) {
174 if (mouse_mode != MouseRange) {
176 /* in all modes except range, hide the range selection,
177 show the object (region) selection.
180 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
181 (*i)->set_should_show_selection (true);
183 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
184 (*i)->hide_selection ();
189 /* in range mode, hide object (region) selection, and show the
193 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
194 (*i)->set_should_show_selection (false);
196 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
197 if ((*i)->selected()) {
198 (*i)->show_selection (selection->time);
203 /* XXX the hack of unsetting all other buttongs should go
204 away once GTK2 allows us to use regular radio buttons drawn like
205 normal buttons, rather than my silly GroupedButton hack.
208 ignore_mouse_mode_toggle = true;
210 switch (mouse_mode) {
212 mouse_select_button.set_active (true);
213 current_canvas_cursor = selector_cursor;
217 mouse_move_button.set_active (true);
218 current_canvas_cursor = grabber_cursor;
222 mouse_gain_button.set_active (true);
223 current_canvas_cursor = cross_hair_cursor;
227 mouse_zoom_button.set_active (true);
228 current_canvas_cursor = zoom_cursor;
232 mouse_timefx_button.set_active (true);
233 current_canvas_cursor = time_fx_cursor; // just use playhead
237 mouse_audition_button.set_active (true);
238 current_canvas_cursor = speaker_cursor;
242 ignore_mouse_mode_toggle = false;
245 track_canvas.get_window()->set_cursor(*current_canvas_cursor);
250 Editor::step_mouse_mode (bool next)
252 switch (current_mouse_mode()) {
254 if (next) set_mouse_mode (MouseRange);
255 else set_mouse_mode (MouseTimeFX);
259 if (next) set_mouse_mode (MouseZoom);
260 else set_mouse_mode (MouseObject);
264 if (next) set_mouse_mode (MouseGain);
265 else set_mouse_mode (MouseRange);
269 if (next) set_mouse_mode (MouseTimeFX);
270 else set_mouse_mode (MouseZoom);
274 if (next) set_mouse_mode (MouseAudition);
275 else set_mouse_mode (MouseGain);
279 if (next) set_mouse_mode (MouseObject);
280 else set_mouse_mode (MouseTimeFX);
286 Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
288 jack_nframes_t where = event_frame (event, 0, 0);
290 if (session && session->actively_recording()) {
294 /* in object/audition/timefx mode, any button press sets
295 the selection if the object can be selected. this is a
296 bit of hack, because we want to avoid this if the
297 mouse operation is a region alignment.
300 if (((mouse_mode == MouseObject) ||
301 (mouse_mode == MouseAudition && item_type == RegionItem) ||
302 (mouse_mode == MouseTimeFX && item_type == RegionItem)) &&
303 event->type == GDK_BUTTON_PRESS &&
304 event->button.button <= 3) {
309 /* not dbl-click or triple-click */
313 set_selected_regionview_from_click (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift), true);
316 case AudioRegionViewNameHighlight:
317 case AudioRegionViewName:
318 if ((rv = reinterpret_cast<AudioRegionView *> (item->get_data ("regionview"))) != 0) {
319 set_selected_regionview_from_click (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift), true);
323 case GainAutomationControlPointItem:
324 case PanAutomationControlPointItem:
325 case RedirectAutomationControlPointItem:
326 if ((cp = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) != 0) {
327 set_selected_control_point_from_click (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift), true);
334 case AutomationTrackItem:
342 #define SELECT_TRACK_FROM_CANVAS_IN_RANGE_MODE
343 #ifdef SELECT_TRACK_FROM_CANVAS_IN_RANGE_MODE
344 /* in range mode, button 1/2/3 press potentially selects a track */
346 if (mouse_mode == MouseRange &&
347 event->type == GDK_BUTTON_PRESS &&
348 event->button.button <= 3) {
355 case AutomationTrackItem:
356 set_selected_track_from_click (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift), true, true);
359 case AudioRegionViewNameHighlight:
360 case AudioRegionViewName:
361 rv = reinterpret_cast<AudioRegionView *> (item->get_data ("regionview"));
368 if (drag_info.item == 0 &&
369 (Keyboard::is_delete_event (&event->button) ||
370 Keyboard::is_context_menu_event (&event->button) ||
371 Keyboard::is_edit_event (&event->button))) {
373 /* handled by button release */
377 switch (event->button.button) {
380 if (event->type == GDK_BUTTON_PRESS) {
382 if (drag_info.item) {
383 drag_info.item->ungrab (event->button.time);
386 /* single mouse clicks on any of these item types operate
387 independent of mouse mode, mostly because they are
388 not on the main track canvas or because we want
394 case PlayheadCursorItem:
395 start_cursor_grab (item, event);
399 if (Keyboard::modifier_state_equals (event->button.state,
400 Keyboard::ModifierMask(Keyboard::Control|Keyboard::Shift))) {
401 hide_marker (item, event);
403 start_marker_grab (item, event);
407 case TempoMarkerItem:
408 start_tempo_marker_grab (item, event);
411 case MeterMarkerItem:
412 start_meter_marker_grab (item, event);
421 case RangeMarkerBarItem:
422 start_range_markerbar_op (item, event, CreateRangeMarker);
425 case TransportMarkerBarItem:
426 start_range_markerbar_op (item, event, CreateTransportMarker);
435 switch (mouse_mode) {
438 case StartSelectionTrimItem:
439 start_selection_op (item, event, SelectionStartTrim);
442 case EndSelectionTrimItem:
443 start_selection_op (item, event, SelectionEndTrim);
447 if (Keyboard::modifier_state_contains
448 (event->button.state, Keyboard::ModifierMask(Keyboard::Alt))) {
449 // contains and not equals because I can't use alt as a modifier alone.
450 start_selection_grab (item, event);
451 } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
452 /* grab selection for moving */
453 start_selection_op (item, event, SelectionMove);
456 /* this was debated, but decided the more common action was to
457 make a new selection */
458 start_selection_op (item, event, CreateSelection);
463 start_selection_op (item, event, CreateSelection);
469 if (Keyboard::modifier_state_contains (event->button.state,
470 Keyboard::ModifierMask(Keyboard::Control|Keyboard::Alt))
471 && event->type == GDK_BUTTON_PRESS) {
473 start_rubberband_select (item, event);
475 } else if (event->type == GDK_BUTTON_PRESS) {
478 case FadeInHandleItem:
479 start_fade_in_grab (item, event);
482 case FadeOutHandleItem:
483 start_fade_out_grab (item, event);
487 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
488 start_region_copy_grab (item, event);
489 } else if (Keyboard::the_keyboard().key_is_down (GDK_b)) {
490 start_region_brush_grab (item, event);
492 start_region_grab (item, event);
496 case AudioRegionViewNameHighlight:
497 start_trim (item, event);
501 case AudioRegionViewName:
502 /* rename happens on edit clicks */
503 start_trim (clicked_regionview->get_name_highlight(), event);
507 case GainAutomationControlPointItem:
508 case PanAutomationControlPointItem:
509 case RedirectAutomationControlPointItem:
510 start_control_point_grab (item, event);
514 case GainAutomationLineItem:
515 case PanAutomationLineItem:
516 case RedirectAutomationLineItem:
517 start_line_grab_from_line (item, event);
522 case AutomationTrackItem:
523 start_rubberband_select (item, event);
526 /* <CMT Additions> */
527 case ImageFrameHandleStartItem:
528 imageframe_start_handle_op(item, event) ;
531 case ImageFrameHandleEndItem:
532 imageframe_end_handle_op(item, event) ;
535 case MarkerViewHandleStartItem:
536 markerview_item_start_handle_op(item, event) ;
539 case MarkerViewHandleEndItem:
540 markerview_item_end_handle_op(item, event) ;
543 /* </CMT Additions> */
545 /* <CMT Additions> */
547 start_markerview_grab(item, event) ;
550 start_imageframe_grab(item, event) ;
552 /* </CMT Additions> */
564 // start_line_grab_from_regionview (item, event);
567 case GainControlPointItem:
568 start_control_point_grab (item, event);
572 start_line_grab_from_line (item, event);
575 case GainAutomationControlPointItem:
576 case PanAutomationControlPointItem:
577 case RedirectAutomationControlPointItem:
578 start_control_point_grab (item, event);
589 case GainAutomationControlPointItem:
590 case PanAutomationControlPointItem:
591 case RedirectAutomationControlPointItem:
592 start_control_point_grab (item, event);
595 case GainAutomationLineItem:
596 case PanAutomationLineItem:
597 case RedirectAutomationLineItem:
598 start_line_grab_from_line (item, event);
602 // XXX need automation mode to identify which
604 // start_line_grab_from_regionview (item, event);
614 if (event->type == GDK_BUTTON_PRESS) {
615 start_mouse_zoom (item, event);
622 if (item_type == RegionItem) {
623 start_time_fx (item, event);
628 /* handled in release */
637 switch (mouse_mode) {
639 if (event->type == GDK_BUTTON_PRESS) {
642 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
643 start_region_copy_grab (item, event);
645 start_region_grab (item, event);
649 case GainAutomationControlPointItem:
650 case PanAutomationControlPointItem:
651 case RedirectAutomationControlPointItem:
652 start_control_point_grab (item, event);
663 case AudioRegionViewNameHighlight:
664 start_trim (item, event);
668 case AudioRegionViewName:
669 start_trim (clicked_regionview->get_name_highlight(), event);
680 if (event->type == GDK_BUTTON_PRESS) {
681 /* relax till release */
688 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
689 temporal_zoom_session();
691 temporal_zoom_to_frame (true, event_frame(event));
706 switch (mouse_mode) {
708 //temporal_zoom_to_frame (true, where);
709 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
710 temporal_zoom_to_frame (true, where);
713 temporal_zoom_step (true);
718 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::Alt))) {
719 scroll_backward (0.6f);
721 else if (Keyboard::no_modifier_keys_pressed (&event->button)) {
722 scroll_tracks_up_line ();
724 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
725 if (clicked_trackview) {
726 if (!current_stepping_trackview) {
727 step_timeout = Glib::signal_timeout().connect (mem_fun(*this, &Editor::track_height_step_timeout), 500);
728 current_stepping_trackview = clicked_trackview;
730 gettimeofday (&last_track_height_step_timestamp, 0);
731 current_stepping_trackview->step_height (true);
734 else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
735 temporal_zoom_to_frame (true, where);
742 switch (mouse_mode) {
744 // temporal_zoom_to_frame (false, where);
745 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
746 temporal_zoom_to_frame (false, where);
749 temporal_zoom_step (false);
754 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::Alt))) {
755 scroll_forward (0.6f);
757 else if (Keyboard::no_modifier_keys_pressed (&event->button)) {
758 scroll_tracks_down_line ();
760 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
761 if (clicked_trackview) {
762 if (!current_stepping_trackview) {
763 step_timeout = Glib::signal_timeout().connect (mem_fun(*this, &Editor::track_height_step_timeout), 500);
764 current_stepping_trackview = clicked_trackview;
766 gettimeofday (&last_track_height_step_timestamp, 0);
767 current_stepping_trackview->step_height (false);
769 } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
770 temporal_zoom_to_frame (false, where);
784 Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
786 jack_nframes_t where = event_frame (event, 0, 0);
788 /* no action if we're recording */
790 if (session && session->actively_recording()) {
794 /* first, see if we're finishing a drag ... */
796 if (drag_info.item) {
797 if (end_grab (item, event)) {
798 /* grab dragged, so do nothing else */
803 /* edit events get handled here */
805 if (drag_info.item == 0 && Keyboard::is_edit_event (&event->button)) {
811 case TempoMarkerItem:
812 edit_tempo_marker (item);
815 case MeterMarkerItem:
816 edit_meter_marker (item);
819 case AudioRegionViewName:
820 if (clicked_regionview->name_active()) {
821 return mouse_rename_region (item, event);
831 /* context menu events get handled here */
833 if (Keyboard::is_context_menu_event (&event->button)) {
835 if (drag_info.item == 0) {
837 /* no matter which button pops up the context menu, tell the menu
838 widget to use button 1 to drive menu selection.
843 case FadeInHandleItem:
845 case FadeOutHandleItem:
846 popup_fade_context_menu (1, event->button.time, item, item_type);
850 popup_track_context_menu (1, event->button.time, item_type, false, where);
854 case AudioRegionViewNameHighlight:
855 case AudioRegionViewName:
856 popup_track_context_menu (1, event->button.time, item_type, false, where);
860 popup_track_context_menu (1, event->button.time, item_type, true, where);
863 case AutomationTrackItem:
864 popup_track_context_menu (1, event->button.time, item_type, false, where);
868 case RangeMarkerBarItem:
869 case TransportMarkerBarItem:
872 popup_ruler_menu (pixel_to_frame(event->button.x), item_type);
876 marker_context_menu (&event->button, item);
879 case TempoMarkerItem:
880 tm_marker_context_menu (&event->button, item);
883 case MeterMarkerItem:
884 tm_marker_context_menu (&event->button, item);
887 case CrossfadeViewItem:
888 popup_track_context_menu (1, event->button.time, item_type, false, where);
891 /* <CMT Additions> */
893 popup_imageframe_edit_menu(1, event->button.time, item, true) ;
895 case ImageFrameTimeAxisItem:
896 popup_imageframe_edit_menu(1, event->button.time, item, false) ;
899 popup_marker_time_axis_edit_menu(1, event->button.time, item, true) ;
901 case MarkerTimeAxisItem:
902 popup_marker_time_axis_edit_menu(1, event->button.time, item, false) ;
904 /* <CMT Additions> */
915 /* delete events get handled here */
917 if (drag_info.item == 0 && Keyboard::is_delete_event (&event->button)) {
920 case TempoMarkerItem:
921 remove_tempo_marker (item);
924 case MeterMarkerItem:
925 remove_meter_marker (item);
930 remove_marker (*item, event);
935 if (mouse_mode == MouseObject) {
936 remove_clicked_region ();
940 case GainControlPointItem:
941 if (mouse_mode == MouseGain) {
942 remove_gain_control_point (item, event);
946 case GainAutomationControlPointItem:
947 case PanAutomationControlPointItem:
948 case RedirectAutomationControlPointItem:
949 remove_control_point (item, event);
958 switch (event->button.button) {
962 /* see comments in button_press_handler */
964 case PlayheadCursorItem:
967 case GainAutomationLineItem:
968 case PanAutomationLineItem:
969 case RedirectAutomationLineItem:
970 case StartSelectionTrimItem:
971 case EndSelectionTrimItem:
975 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
976 snap_to (where, 0, true);
978 mouse_add_new_marker (where);
982 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
985 mouse_add_new_tempo_event (where);
989 mouse_add_new_meter_event (pixel_to_frame (event->button.x));
997 switch (mouse_mode) {
1000 case AutomationTrackItem:
1001 dynamic_cast<AutomationTimeAxisView*>(clicked_trackview)->add_automation_event
1015 switch (item_type) {
1017 clicked_regionview->add_gain_point_event (item, event);
1021 case AutomationTrackItem:
1022 dynamic_cast<AutomationTimeAxisView*>(clicked_trackview)->
1023 add_automation_event (item, event, where, event->button.y);
1032 switch (item_type) {
1034 audition_selected_region ();
1051 switch (mouse_mode) {
1054 switch (item_type) {
1056 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
1058 } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::ModifierMask (Keyboard::Shift|Keyboard::Alt))) {
1061 // Button2 click is unused
1074 // x_style_paste (where, 1.0);
1094 Editor::maybe_autoscroll (GdkEvent* event)
1096 jack_nframes_t one_page = (jack_nframes_t) rint (canvas_width * frames_per_unit);
1097 jack_nframes_t rightmost_frame = leftmost_frame + one_page;
1099 jack_nframes_t frame = drag_info.current_pointer_frame;
1101 if (autoscroll_timeout_tag < 0) {
1102 if (frame > rightmost_frame) {
1103 if (rightmost_frame < max_frames) {
1104 start_canvas_autoscroll (1);
1106 } else if (frame < leftmost_frame) {
1107 if (leftmost_frame > 0) {
1108 start_canvas_autoscroll (-1);
1112 if (frame >= leftmost_frame && frame < rightmost_frame) {
1113 stop_canvas_autoscroll ();
1119 Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
1125 switch (item_type) {
1126 case GainControlPointItem:
1127 if (mouse_mode == MouseGain) {
1128 cp = reinterpret_cast<ControlPoint*>(item->get_data ("control_point"));
1129 cp->set_visible (true);
1133 at_y = cp->get_y ();
1134 cp->item->i2w (at_x, at_y);
1138 fraction = 1.0 - (cp->get_y() / cp->line.height());
1140 set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y);
1141 show_verbose_canvas_cursor ();
1143 if (is_drawable()) {
1144 track_canvas.get_window()->set_cursor (*fader_cursor);
1149 case GainAutomationControlPointItem:
1150 case PanAutomationControlPointItem:
1151 case RedirectAutomationControlPointItem:
1152 cp = reinterpret_cast<ControlPoint*>(item->get_data ("control_point"));
1153 cp->set_visible (true);
1157 at_y = cp->get_y ();
1158 cp->item->i2w (at_x, at_y);
1162 fraction = 1.0 - (cp->get_y() / cp->line.height());
1164 set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y);
1165 show_verbose_canvas_cursor ();
1167 if (is_drawable()) {
1168 track_canvas.get_window()->set_cursor (*fader_cursor);
1173 if (mouse_mode == MouseGain) {
1174 ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
1176 line->property_fill_color_rgba() = color_map[cEnteredGainLine];
1177 if (is_drawable()) {
1178 track_canvas.get_window()->set_cursor (*fader_cursor);
1183 case GainAutomationLineItem:
1184 case RedirectAutomationLineItem:
1185 case PanAutomationLineItem:
1187 ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
1189 line->property_fill_color_rgba() = color_map[cEnteredAutomationLine];
1191 if (is_drawable()) {
1192 track_canvas.get_window()->set_cursor (*fader_cursor);
1196 case AudioRegionViewNameHighlight:
1197 if (is_drawable() && mouse_mode == MouseObject) {
1198 track_canvas.get_window()->set_cursor (*trimmer_cursor);
1202 case StartSelectionTrimItem:
1203 case EndSelectionTrimItem:
1204 /* <CMT Additions> */
1205 case ImageFrameHandleStartItem:
1206 case ImageFrameHandleEndItem:
1207 case MarkerViewHandleStartItem:
1208 case MarkerViewHandleEndItem:
1209 /* </CMT Additions> */
1211 if (is_drawable()) {
1212 track_canvas.get_window()->set_cursor (*trimmer_cursor);
1216 case EditCursorItem:
1217 case PlayheadCursorItem:
1218 if (is_drawable()) {
1219 track_canvas.get_window()->set_cursor (*grabber_cursor);
1223 case AudioRegionViewName:
1225 /* when the name is not an active item, the entire name highlight is for trimming */
1227 if (!reinterpret_cast<AudioRegionView *> (item->get_data ("regionview"))->name_active()) {
1228 if (mouse_mode == MouseObject && is_drawable()) {
1229 track_canvas.get_window()->set_cursor (*trimmer_cursor);
1235 case AutomationTrackItem:
1236 if (is_drawable()) {
1237 Gdk::Cursor *cursor;
1238 switch (mouse_mode) {
1240 cursor = selector_cursor;
1243 cursor = zoom_cursor;
1246 cursor = cross_hair_cursor;
1250 track_canvas.get_window()->set_cursor (*cursor);
1252 AutomationTimeAxisView* atv;
1253 if ((atv = static_cast<AutomationTimeAxisView*>(item->get_data ("trackview"))) != 0) {
1254 clear_entered_track = false;
1255 set_entered_track (atv);
1261 case RangeMarkerBarItem:
1262 case TransportMarkerBarItem:
1265 if (is_drawable()) {
1266 time_canvas.get_window()->set_cursor (*timebar_cursor);
1271 if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
1274 marker->set_color_rgba (color_map[cEnteredMarker]);
1276 case MeterMarkerItem:
1277 case TempoMarkerItem:
1278 if (is_drawable()) {
1279 time_canvas.get_window()->set_cursor (*timebar_cursor);
1282 case FadeInHandleItem:
1283 case FadeOutHandleItem:
1284 if (mouse_mode == MouseObject) {
1285 ArdourCanvas::SimpleRect *rect = dynamic_cast<ArdourCanvas::SimpleRect *> (item);
1287 rect->property_fill_color_rgba() = 0;
1288 rect->property_outline_pixels() = 1;
1297 /* second pass to handle entered track status in a comprehensible way.
1300 switch (item_type) {
1302 case GainAutomationLineItem:
1303 case RedirectAutomationLineItem:
1304 case PanAutomationLineItem:
1305 case GainControlPointItem:
1306 case GainAutomationControlPointItem:
1307 case PanAutomationControlPointItem:
1308 case RedirectAutomationControlPointItem:
1309 /* these do not affect the current entered track state */
1310 clear_entered_track = false;
1313 case AutomationTrackItem:
1314 /* handled above already */
1318 set_entered_track (0);
1326 Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
1332 AudioRegionView* rv;
1335 switch (item_type) {
1336 case GainControlPointItem:
1337 case GainAutomationControlPointItem:
1338 case PanAutomationControlPointItem:
1339 case RedirectAutomationControlPointItem:
1340 cp = reinterpret_cast<ControlPoint*>(item->get_data ("control_point"));
1341 if (cp->line.npoints() > 1) {
1342 if (!cp->selected) {
1343 cp->set_visible (false);
1347 if (is_drawable()) {
1348 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
1351 hide_verbose_canvas_cursor ();
1354 case AudioRegionViewNameHighlight:
1355 case StartSelectionTrimItem:
1356 case EndSelectionTrimItem:
1357 case EditCursorItem:
1358 case PlayheadCursorItem:
1359 /* <CMT Additions> */
1360 case ImageFrameHandleStartItem:
1361 case ImageFrameHandleEndItem:
1362 case MarkerViewHandleStartItem:
1363 case MarkerViewHandleEndItem:
1364 /* </CMT Additions> */
1365 if (is_drawable()) {
1366 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
1371 case GainAutomationLineItem:
1372 case RedirectAutomationLineItem:
1373 case PanAutomationLineItem:
1374 al = reinterpret_cast<AutomationLine*> (item->get_data ("line"));
1376 ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
1378 line->property_fill_color_rgba() = al->get_line_color();
1380 if (is_drawable()) {
1381 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
1385 case AudioRegionViewName:
1386 /* see enter_handler() for notes */
1387 if (!reinterpret_cast<AudioRegionView *> (item->get_data ("regionview"))->name_active()) {
1388 if (is_drawable() && mouse_mode == MouseObject) {
1389 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
1394 case RangeMarkerBarItem:
1395 case TransportMarkerBarItem:
1399 if (is_drawable()) {
1400 time_canvas.get_window()->set_cursor (*timebar_cursor);
1405 if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
1408 loc = find_location_from_marker (marker, is_start);
1409 if (loc) location_flags_changed (loc, this);
1411 case MeterMarkerItem:
1412 case TempoMarkerItem:
1414 if (is_drawable()) {
1415 time_canvas.get_window()->set_cursor (*timebar_cursor);
1420 case FadeInHandleItem:
1421 case FadeOutHandleItem:
1422 rv = static_cast<AudioRegionView*>(item->get_data ("regionview"));
1424 ArdourCanvas::SimpleRect *rect = dynamic_cast<ArdourCanvas::SimpleRect *> (item);
1426 rect->property_fill_color_rgba() = rv->get_fill_color();
1427 rect->property_outline_pixels() = 0;
1432 case AutomationTrackItem:
1433 if (is_drawable()) {
1434 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
1435 clear_entered_track = true;
1436 Glib::signal_idle().connect (mem_fun(*this, &Editor::left_automation_track));
1448 Editor::left_automation_track ()
1450 if (clear_entered_track) {
1451 set_entered_track (0);
1452 clear_entered_track = false;
1458 Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
1462 /* We call this so that MOTION_NOTIFY events continue to be
1463 delivered to the canvas. We need to do this because we set
1464 Gdk::POINTER_MOTION_HINT_MASK on the canvas. This reduces
1465 the density of the events, at the expense of a round-trip
1466 to the server. Given that this will mostly occur on cases
1467 where DISPLAY = :0.0, and given the cost of what the motion
1468 event might do, its a good tradeoff.
1471 track_canvas.get_pointer (x, y);
1473 if (current_stepping_trackview) {
1474 /* don't keep the persistent stepped trackview if the mouse moves */
1475 current_stepping_trackview = 0;
1476 step_timeout.disconnect ();
1479 if (session && session->actively_recording()) {
1480 /* Sorry. no dragging stuff around while we record */
1484 drag_info.current_pointer_frame = event_frame (event, &drag_info.current_pointer_x,
1485 &drag_info.current_pointer_y);
1486 if (drag_info.item) {
1487 /* item != 0 is the best test i can think of for
1490 if (!drag_info.move_threshold_passsed)
1492 drag_info.move_threshold_passsed = (abs ((int) (drag_info.current_pointer_x - drag_info.grab_x)) > 4);
1494 // and change the initial grab loc/frame if this drag info wants us to
1495 if (drag_info.want_move_threshold && drag_info.move_threshold_passsed) {
1496 drag_info.grab_frame = drag_info.current_pointer_frame;
1497 drag_info.grab_x = drag_info.current_pointer_x;
1498 drag_info.grab_y = drag_info.current_pointer_y;
1499 drag_info.last_pointer_frame = drag_info.grab_frame;
1500 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
1505 switch (item_type) {
1506 case PlayheadCursorItem:
1507 case EditCursorItem:
1509 case GainControlPointItem:
1510 case RedirectAutomationControlPointItem:
1511 case GainAutomationControlPointItem:
1512 case PanAutomationControlPointItem:
1513 case TempoMarkerItem:
1514 case MeterMarkerItem:
1515 case AudioRegionViewNameHighlight:
1516 case StartSelectionTrimItem:
1517 case EndSelectionTrimItem:
1520 case RedirectAutomationLineItem:
1521 case GainAutomationLineItem:
1522 case PanAutomationLineItem:
1523 case FadeInHandleItem:
1524 case FadeOutHandleItem:
1525 /* <CMT Additions> */
1526 case ImageFrameHandleStartItem:
1527 case ImageFrameHandleEndItem:
1528 case MarkerViewHandleStartItem:
1529 case MarkerViewHandleEndItem:
1530 /* </CMT Additions> */
1531 if (drag_info.item && (event->motion.state & Gdk::BUTTON1_MASK ||
1532 (event->motion.state & Gdk::BUTTON2_MASK))) {
1533 maybe_autoscroll (event);
1534 (this->*(drag_info.motion_callback)) (item, event);
1543 switch (mouse_mode) {
1548 if (drag_info.item && (event->motion.state & GDK_BUTTON1_MASK ||
1549 (event->motion.state & GDK_BUTTON2_MASK))) {
1550 maybe_autoscroll (event);
1551 (this->*(drag_info.motion_callback)) (item, event);
1562 track_canvas_motion (event);
1570 Editor::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
1572 if (drag_info.item == 0) {
1573 fatal << _("programming error: start_grab called without drag item") << endmsg;
1579 cursor = grabber_cursor;
1582 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
1584 if (event->button.button == 2) {
1585 drag_info.x_constrained = true;
1587 drag_info.x_constrained = false;
1590 drag_info.grab_frame = event_frame(event, &drag_info.grab_x, &drag_info.grab_y);
1591 drag_info.last_pointer_frame = drag_info.grab_frame;
1592 drag_info.current_pointer_frame = drag_info.grab_frame;
1593 drag_info.current_pointer_x = drag_info.grab_x;
1594 drag_info.current_pointer_y = drag_info.grab_y;
1595 drag_info.cumulative_x_drag = 0;
1596 drag_info.cumulative_y_drag = 0;
1597 drag_info.first_move = true;
1598 drag_info.move_threshold_passsed = false;
1599 drag_info.want_move_threshold = false;
1600 drag_info.pointer_frame_offset = 0;
1601 drag_info.brushing = false;
1602 drag_info.copied_location = 0;
1604 drag_info.item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
1606 event->button.time);
1608 if (session && session->transport_rolling()) {
1609 drag_info.was_rolling = true;
1611 drag_info.was_rolling = false;
1614 switch (snap_type) {
1615 case SnapToRegionStart:
1616 case SnapToRegionEnd:
1617 case SnapToRegionSync:
1618 case SnapToRegionBoundary:
1619 build_region_boundary_cache ();
1627 Editor::end_grab (ArdourCanvas::Item* item, GdkEvent* event)
1629 bool did_drag = false;
1631 stop_canvas_autoscroll ();
1633 if (drag_info.item == 0) {
1637 drag_info.item->ungrab (event->button.time);
1639 if (drag_info.finished_callback) {
1640 (this->*(drag_info.finished_callback)) (item, event);
1643 did_drag = !drag_info.first_move;
1645 hide_verbose_canvas_cursor();
1648 drag_info.copy = false;
1649 drag_info.motion_callback = 0;
1650 drag_info.finished_callback = 0;
1651 drag_info.last_trackview = 0;
1652 drag_info.last_frame_position = 0;
1653 drag_info.grab_frame = 0;
1654 drag_info.last_pointer_frame = 0;
1655 drag_info.current_pointer_frame = 0;
1656 drag_info.brushing = false;
1658 if (drag_info.copied_location) {
1659 delete drag_info.copied_location;
1660 drag_info.copied_location = 0;
1667 Editor::set_edit_cursor (GdkEvent* event)
1669 jack_nframes_t pointer_frame = event_frame (event);
1671 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1672 if (snap_type != SnapToEditCursor) {
1673 snap_to (pointer_frame);
1677 edit_cursor->set_position (pointer_frame);
1678 edit_cursor_clock.set (pointer_frame);
1682 Editor::set_playhead_cursor (GdkEvent* event)
1684 jack_nframes_t pointer_frame = event_frame (event);
1686 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1687 snap_to (pointer_frame);
1691 session->request_locate (pointer_frame, session->transport_rolling());
1696 Editor::start_fade_in_grab (ArdourCanvas::Item* item, GdkEvent* event)
1698 drag_info.item = item;
1699 drag_info.motion_callback = &Editor::fade_in_drag_motion_callback;
1700 drag_info.finished_callback = &Editor::fade_in_drag_finished_callback;
1704 if ((drag_info.data = (item->get_data ("regionview"))) == 0) {
1705 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1709 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1711 drag_info.pointer_frame_offset = drag_info.grab_frame - ((jack_nframes_t) arv->region.fade_in().back()->when + arv->region.position());
1715 Editor::fade_in_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
1717 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1719 jack_nframes_t fade_length;
1721 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1722 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1728 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1732 if (pos < (arv->region.position() + 64)) {
1733 fade_length = 64; // this should be a minimum defined somewhere
1734 } else if (pos > arv->region.last_frame()) {
1735 fade_length = arv->region.length();
1737 fade_length = pos - arv->region.position();
1740 arv->reset_fade_in_shape_width (fade_length);
1742 show_verbose_duration_cursor (arv->region.position(), arv->region.position() + fade_length, 10);
1744 drag_info.first_move = false;
1748 Editor::fade_in_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
1750 if (drag_info.first_move) return;
1752 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1754 jack_nframes_t fade_length;
1756 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1757 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1763 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1767 if (pos < (arv->region.position() + 64)) {
1768 fade_length = 64; // this should be a minimum defined somewhere
1770 else if (pos > arv->region.last_frame()) {
1771 fade_length = arv->region.length();
1774 fade_length = pos - arv->region.position();
1777 begin_reversible_command (_("change fade in length"));
1778 session->add_undo (arv->region.get_memento());
1779 arv->region.set_fade_in_length (fade_length);
1780 session->add_redo_no_execute (arv->region.get_memento());
1781 commit_reversible_command ();
1782 fade_in_drag_motion_callback (item, event);
1786 Editor::start_fade_out_grab (ArdourCanvas::Item* item, GdkEvent* event)
1788 drag_info.item = item;
1789 drag_info.motion_callback = &Editor::fade_out_drag_motion_callback;
1790 drag_info.finished_callback = &Editor::fade_out_drag_finished_callback;
1794 if ((drag_info.data = (item->get_data ("regionview"))) == 0) {
1795 fatal << _("programming error: fade out canvas item has no regionview data pointer!") << endmsg;
1799 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1801 drag_info.pointer_frame_offset = drag_info.grab_frame - (arv->region.length() - (jack_nframes_t) arv->region.fade_out().back()->when + arv->region.position());
1805 Editor::fade_out_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
1807 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1809 jack_nframes_t fade_length;
1811 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1812 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1818 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1822 if (pos > (arv->region.last_frame() - 64)) {
1823 fade_length = 64; // this should really be a minimum fade defined somewhere
1825 else if (pos < arv->region.position()) {
1826 fade_length = arv->region.length();
1829 fade_length = arv->region.last_frame() - pos;
1832 arv->reset_fade_out_shape_width (fade_length);
1834 show_verbose_duration_cursor (arv->region.last_frame() - fade_length, arv->region.last_frame(), 10);
1836 drag_info.first_move = false;
1840 Editor::fade_out_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
1842 if (drag_info.first_move) return;
1844 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1846 jack_nframes_t fade_length;
1848 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1849 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1855 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1859 if (pos > (arv->region.last_frame() - 64)) {
1860 fade_length = 64; // this should really be a minimum fade defined somewhere
1862 else if (pos < arv->region.position()) {
1863 fade_length = arv->region.length();
1866 fade_length = arv->region.last_frame() - pos;
1869 begin_reversible_command (_("change fade out length"));
1870 session->add_undo (arv->region.get_memento());
1871 arv->region.set_fade_out_length (fade_length);
1872 session->add_redo_no_execute (arv->region.get_memento());
1873 commit_reversible_command ();
1875 fade_out_drag_motion_callback (item, event);
1879 Editor::start_cursor_grab (ArdourCanvas::Item* item, GdkEvent* event)
1881 drag_info.item = item;
1882 drag_info.motion_callback = &Editor::cursor_drag_motion_callback;
1883 drag_info.finished_callback = &Editor::cursor_drag_finished_callback;
1887 if ((drag_info.data = (item->get_data ("cursor"))) == 0) {
1888 fatal << _("programming error: cursor canvas item has no cursor data pointer!") << endmsg;
1892 Cursor* cursor = (Cursor *) drag_info.data;
1894 if (session && cursor == playhead_cursor) {
1895 if (drag_info.was_rolling) {
1896 session->request_stop ();
1900 drag_info.pointer_frame_offset = drag_info.grab_frame - cursor->current_frame;
1902 show_verbose_time_cursor (cursor->current_frame, 10);
1906 Editor::cursor_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
1908 Cursor* cursor = (Cursor *) drag_info.data;
1909 jack_nframes_t adjusted_frame;
1911 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1912 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1918 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1919 if (cursor != edit_cursor || snap_type != SnapToEditCursor) {
1920 snap_to (adjusted_frame);
1924 if (adjusted_frame == drag_info.last_pointer_frame) return;
1926 cursor->set_position (adjusted_frame);
1928 if (cursor == edit_cursor) {
1929 edit_cursor_clock.set (cursor->current_frame);
1932 show_verbose_time_cursor (cursor->current_frame, 10);
1934 drag_info.last_pointer_frame = adjusted_frame;
1935 drag_info.first_move = false;
1939 Editor::cursor_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
1941 if (drag_info.first_move) return;
1943 cursor_drag_motion_callback (item, event);
1945 if (item == &playhead_cursor->canvas_item) {
1947 session->request_locate (playhead_cursor->current_frame, drag_info.was_rolling);
1949 } else if (item == &edit_cursor->canvas_item) {
1950 edit_cursor->set_position (edit_cursor->current_frame);
1951 edit_cursor_clock.set (edit_cursor->current_frame);
1956 Editor::update_marker_drag_item (Location *location)
1958 double x1 = frame_to_pixel (location->start());
1959 double x2 = frame_to_pixel (location->end());
1961 if (location->is_mark()) {
1962 marker_drag_line_points.front().set_x(x1);
1963 marker_drag_line_points.back().set_x(x1);
1964 marker_drag_line->property_points() = marker_drag_line_points;
1967 range_marker_drag_rect->property_x1() = x1;
1968 range_marker_drag_rect->property_x2() = x2;
1973 Editor::start_marker_grab (ArdourCanvas::Item* item, GdkEvent* event)
1977 if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
1978 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
1984 Location *location = find_location_from_marker (marker, is_start);
1986 drag_info.item = item;
1987 drag_info.data = marker;
1988 drag_info.motion_callback = &Editor::marker_drag_motion_callback;
1989 drag_info.finished_callback = &Editor::marker_drag_finished_callback;
1993 drag_info.copied_location = new Location (*location);
1994 drag_info.pointer_frame_offset = drag_info.grab_frame - (is_start ? location->start() : location->end());
1996 update_marker_drag_item (location);
1998 if (location->is_mark()) {
1999 marker_drag_line->show();
2000 marker_drag_line->raise_to_top();
2003 range_marker_drag_rect->show();
2004 range_marker_drag_rect->raise_to_top();
2007 if (is_start) show_verbose_time_cursor (location->start(), 10);
2008 else show_verbose_time_cursor (location->end(), 10);
2012 Editor::marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2014 jack_nframes_t f_delta;
2015 Marker* marker = (Marker *) drag_info.data;
2016 Location *real_location;
2017 Location *copy_location;
2019 bool move_both = false;
2021 jack_nframes_t newframe;
2022 if (drag_info.pointer_frame_offset <= (long) drag_info.current_pointer_frame) {
2023 newframe = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2029 jack_nframes_t next = newframe;
2031 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2032 snap_to (newframe, 0, true);
2035 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) return;
2037 /* call this to find out if its the start or end */
2039 real_location = find_location_from_marker (marker, is_start);
2041 /* use the copy that we're "dragging" around */
2043 copy_location = drag_info.copied_location;
2045 f_delta = copy_location->end() - copy_location->start();
2047 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
2051 if (is_start) { // start marker
2054 copy_location->set_start (newframe);
2055 copy_location->set_end (newframe + f_delta);
2056 } else if (newframe < copy_location->end()) {
2057 copy_location->set_start (newframe);
2059 snap_to (next, 1, true);
2060 copy_location->set_end (next);
2061 copy_location->set_start (newframe);
2064 } else { // end marker
2067 copy_location->set_end (newframe);
2068 copy_location->set_start (newframe - f_delta);
2069 } else if (newframe > copy_location->start()) {
2070 copy_location->set_end (newframe);
2072 } else if (newframe > 0) {
2073 snap_to (next, -1, true);
2074 copy_location->set_start (next);
2075 copy_location->set_end (newframe);
2079 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
2080 drag_info.first_move = false;
2082 update_marker_drag_item (copy_location);
2084 LocationMarkers* lm = find_location_markers (real_location);
2085 lm->set_position (copy_location->start(), copy_location->end());
2087 show_verbose_time_cursor (newframe, 10);
2091 Editor::marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2093 if (drag_info.first_move) {
2094 marker_drag_motion_callback (item, event);
2098 Marker* marker = (Marker *) drag_info.data;
2100 Location * location = find_location_from_marker (marker, is_start);
2102 location->set (drag_info.copied_location->start(), drag_info.copied_location->end());
2105 marker_drag_line->hide();
2106 range_marker_drag_rect->hide();
2110 Editor::start_meter_marker_grab (ArdourCanvas::Item* item, GdkEvent* event)
2113 MeterMarker* meter_marker;
2115 if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
2116 fatal << _("programming error: meter marker canvas item has no marker object pointer!") << endmsg;
2120 meter_marker = dynamic_cast<MeterMarker*> (marker);
2122 MetricSection& section (meter_marker->meter());
2124 if (!section.movable()) {
2128 drag_info.item = item;
2129 drag_info.data = marker;
2130 drag_info.motion_callback = &Editor::meter_marker_drag_motion_callback;
2131 drag_info.finished_callback = &Editor::meter_marker_drag_finished_callback;
2135 drag_info.pointer_frame_offset = drag_info.grab_frame - meter_marker->meter().frame();
2137 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2141 Editor::meter_marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2143 MeterMarker* marker = (MeterMarker *) drag_info.data;
2144 jack_nframes_t adjusted_frame;
2146 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
2147 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2153 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2154 snap_to (adjusted_frame);
2157 if (adjusted_frame == drag_info.last_pointer_frame) return;
2159 marker->set_position (adjusted_frame);
2162 drag_info.last_pointer_frame = adjusted_frame;
2163 drag_info.first_move = false;
2165 show_verbose_time_cursor (adjusted_frame, 10);
2169 Editor::meter_marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2171 if (drag_info.first_move) return;
2173 meter_marker_drag_motion_callback (item, event);
2175 MeterMarker* marker = (MeterMarker *) drag_info.data;
2178 TempoMap& map (session->tempo_map());
2179 map.bbt_time (drag_info.last_pointer_frame, when);
2181 begin_reversible_command (_("move meter mark"));
2182 session->add_undo (map.get_memento());
2183 map.move_meter (marker->meter(), when);
2184 session->add_redo_no_execute (map.get_memento());
2185 commit_reversible_command ();
2189 Editor::start_tempo_marker_grab (ArdourCanvas::Item* item, GdkEvent* event)
2192 TempoMarker* tempo_marker;
2194 if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
2195 fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg;
2199 if ((tempo_marker = dynamic_cast<TempoMarker *> (marker)) == 0) {
2200 fatal << _("programming error: marker for tempo is not a tempo marker!") << endmsg;
2204 MetricSection& section (tempo_marker->tempo());
2206 if (!section.movable()) {
2210 drag_info.item = item;
2211 drag_info.data = marker;
2212 drag_info.motion_callback = &Editor::tempo_marker_drag_motion_callback;
2213 drag_info.finished_callback = &Editor::tempo_marker_drag_finished_callback;
2217 drag_info.pointer_frame_offset = drag_info.grab_frame - tempo_marker->tempo().frame();
2218 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2222 Editor::tempo_marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2224 TempoMarker* marker = (TempoMarker *) drag_info.data;
2225 jack_nframes_t adjusted_frame;
2227 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
2228 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2234 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2235 snap_to (adjusted_frame);
2238 if (adjusted_frame == drag_info.last_pointer_frame) return;
2240 /* OK, we've moved far enough to make it worth actually move the thing. */
2242 marker->set_position (adjusted_frame);
2244 show_verbose_time_cursor (adjusted_frame, 10);
2246 drag_info.last_pointer_frame = adjusted_frame;
2247 drag_info.first_move = false;
2251 Editor::tempo_marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2253 if (drag_info.first_move) return;
2255 tempo_marker_drag_motion_callback (item, event);
2257 TempoMarker* marker = (TempoMarker *) drag_info.data;
2260 TempoMap& map (session->tempo_map());
2261 map.bbt_time (drag_info.last_pointer_frame, when);
2263 begin_reversible_command (_("move tempo mark"));
2264 session->add_undo (map.get_memento());
2265 map.move_tempo (marker->tempo(), when);
2266 session->add_redo_no_execute (map.get_memento());
2267 commit_reversible_command ();
2271 Editor::remove_gain_control_point (ArdourCanvas::Item*item, GdkEvent* event)
2273 ControlPoint* control_point;
2275 if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
2276 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2280 // We shouldn't remove the first or last gain point
2281 if (control_point->line.is_last_point(*control_point) ||
2282 control_point->line.is_first_point(*control_point)) {
2286 control_point->line.remove_point (*control_point);
2290 Editor::remove_control_point (ArdourCanvas::Item*item, GdkEvent* event)
2292 ControlPoint* control_point;
2294 if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
2295 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2299 control_point->line.remove_point (*control_point);
2303 Editor::start_control_point_grab (ArdourCanvas::Item* item, GdkEvent* event)
2305 ControlPoint* control_point;
2307 if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
2308 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2312 drag_info.item = item;
2313 drag_info.data = control_point;
2314 drag_info.motion_callback = &Editor::control_point_drag_motion_callback;
2315 drag_info.finished_callback = &Editor::control_point_drag_finished_callback;
2317 start_grab (event, fader_cursor);
2319 control_point->line.start_drag (control_point, 0);
2321 float fraction = 1.0 - (control_point->get_y() / control_point->line.height());
2322 set_verbose_canvas_cursor (control_point->line.get_verbose_cursor_string (fraction),
2323 drag_info.current_pointer_x + 20, drag_info.current_pointer_y + 20);
2325 show_verbose_canvas_cursor ();
2329 Editor::control_point_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2331 ControlPoint* cp = reinterpret_cast<ControlPoint *> (drag_info.data);
2333 double cx = drag_info.current_pointer_x;
2334 double cy = drag_info.current_pointer_y;
2336 drag_info.cumulative_x_drag = cx - drag_info.grab_x ;
2337 drag_info.cumulative_y_drag = cy - drag_info.grab_y ;
2339 bool x_constrained = false;
2341 if (drag_info.x_constrained) {
2342 if (fabs(drag_info.cumulative_x_drag) < fabs(drag_info.cumulative_y_drag)) {
2343 cx = drag_info.grab_x;
2344 x_constrained = true;
2347 cy = drag_info.grab_y;
2352 cp->line.parent_group().w2i (cx, cy);
2356 cy = min ((double) cp->line.height(), cy);
2358 //translate cx to frames
2359 jack_nframes_t cx_frames = (jack_nframes_t) floor (cx * frames_per_unit);
2361 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && !x_constrained) {
2362 snap_to (cx_frames);
2365 float fraction = 1.0 - (cy / cp->line.height());
2369 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
2375 cp->line.point_drag (*cp, cx_frames , fraction, push);
2377 set_verbose_canvas_cursor_text (cp->line.get_verbose_cursor_string (fraction));
2381 Editor::control_point_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2383 ControlPoint* cp = reinterpret_cast<ControlPoint *> (drag_info.data);
2384 control_point_drag_motion_callback (item, event);
2385 cp->line.end_drag (cp);
2389 Editor::start_line_grab_from_regionview (ArdourCanvas::Item* item, GdkEvent* event)
2391 switch (mouse_mode) {
2393 start_line_grab (clicked_regionview->get_gain_line(), event);
2401 Editor::start_line_grab_from_line (ArdourCanvas::Item* item, GdkEvent* event)
2405 if ((al = reinterpret_cast<AutomationLine*> (item->get_data ("line"))) == 0) {
2406 fatal << _("programming error: line canvas item has no line pointer!") << endmsg;
2410 start_line_grab (al, event);
2414 Editor::start_line_grab (AutomationLine* line, GdkEvent* event)
2418 jack_nframes_t frame_within_region;
2420 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2424 cx = event->button.x;
2425 cy = event->button.y;
2426 line->parent_group().w2i (cx, cy);
2427 frame_within_region = (jack_nframes_t) floor (cx * frames_per_unit);
2429 if (!line->control_points_adjacent (frame_within_region, current_line_drag_info.before,
2430 current_line_drag_info.after)) {
2431 /* no adjacent points */
2435 drag_info.item = &line->grab_item();
2436 drag_info.data = line;
2437 drag_info.motion_callback = &Editor::line_drag_motion_callback;
2438 drag_info.finished_callback = &Editor::line_drag_finished_callback;
2440 start_grab (event, fader_cursor);
2442 double fraction = 1.0 - (cy / line->height());
2444 line->start_drag (0, fraction);
2446 set_verbose_canvas_cursor (line->get_verbose_cursor_string (fraction),
2447 drag_info.current_pointer_x + 20, drag_info.current_pointer_y + 20);
2448 show_verbose_canvas_cursor ();
2452 Editor::line_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2454 AutomationLine* line = reinterpret_cast<AutomationLine *> (drag_info.data);
2455 double cx = drag_info.current_pointer_x;
2456 double cy = drag_info.current_pointer_y;
2458 line->parent_group().w2i (cx, cy);
2461 fraction = 1.0 - (cy / line->height());
2465 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
2471 line->line_drag (current_line_drag_info.before, current_line_drag_info.after, fraction, push);
2473 set_verbose_canvas_cursor_text (line->get_verbose_cursor_string (fraction));
2477 Editor::line_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2479 AutomationLine* line = reinterpret_cast<AutomationLine *> (drag_info.data);
2480 line_drag_motion_callback (item, event);
2485 Editor::start_region_grab (ArdourCanvas::Item* item, GdkEvent* event)
2487 if (selection->audio_regions.empty() || clicked_regionview == 0) {
2491 drag_info.copy = false;
2492 drag_info.item = item;
2493 drag_info.data = clicked_regionview;
2494 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2495 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2500 TimeAxisView* tvp = clicked_trackview;
2501 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
2503 if (tv && tv->is_audio_track()) {
2504 speed = tv->get_diskstream()->speed();
2507 drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region.position() / speed);
2508 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2509 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2510 // we want a move threshold
2511 drag_info.want_move_threshold = true;
2513 show_verbose_time_cursor (drag_info.last_frame_position, 10);
2515 begin_reversible_command (_("move region(s)"));
2519 Editor::start_region_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
2521 if (selection->audio_regions.empty() || clicked_regionview == 0) {
2525 /* this is committed in the grab finished callback. */
2527 begin_reversible_command (_("Drag region copy"));
2529 /* duplicate the region(s) */
2531 vector<AudioRegionView*> new_regionviews;
2533 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
2534 AudioRegionView* rv;
2538 Playlist* to_playlist = rv->region.playlist();
2539 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&rv->get_time_axis_view());
2541 session->add_undo (to_playlist->get_memento ());
2542 latest_regionview = 0;
2544 sigc::connection c = atv->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
2546 /* create a new region with the same name.
2549 AudioRegion* newregion = new AudioRegion (rv->region);
2551 /* if the original region was locked, we don't care */
2553 newregion->set_locked (false);
2555 to_playlist->add_region (*newregion, (jack_nframes_t) (rv->region.position() * atv->get_diskstream()->speed()));
2559 if (latest_regionview) {
2560 new_regionviews.push_back (latest_regionview);
2565 if (new_regionviews.empty()) {
2569 /* reset selection to new regionviews */
2571 selection->set (new_regionviews);
2573 drag_info.item = new_regionviews.front()->get_canvas_group ();
2574 drag_info.copy = true;
2575 drag_info.data = new_regionviews.front();
2576 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2577 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2581 TimeAxisView* tv = &clicked_regionview->get_time_axis_view();
2582 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(tv);
2585 if (atv && atv->is_audio_track()) {
2586 speed = atv->get_diskstream()->speed();
2589 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2590 drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region.position() / speed);
2591 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2592 // we want a move threshold
2593 drag_info.want_move_threshold = true;
2595 show_verbose_time_cursor (drag_info.last_frame_position, 10);
2597 begin_reversible_command (_("copy region(s)"));
2601 Editor::start_region_brush_grab (ArdourCanvas::Item* item, GdkEvent* event)
2603 if (selection->audio_regions.empty() || clicked_regionview == 0) {
2607 drag_info.copy = false;
2608 drag_info.item = item;
2609 drag_info.data = clicked_regionview;
2610 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2611 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2616 TimeAxisView* tvp = clicked_trackview;
2617 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
2619 if (tv && tv->is_audio_track()) {
2620 speed = tv->get_diskstream()->speed();
2623 drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region.position() / speed);
2624 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2625 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2626 // we want a move threshold
2627 drag_info.want_move_threshold = true;
2628 drag_info.brushing = true;
2630 begin_reversible_command (_("Drag region brush"));
2634 Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2638 AudioRegionView *rv = reinterpret_cast<AudioRegionView*> (drag_info.data);
2639 jack_nframes_t pending_region_position = 0;
2640 int32_t pointer_y_span = 0, canvas_pointer_y_span = 0, original_pointer_order;
2641 int32_t visible_y_high = 0, visible_y_low = 512; //high meaning higher numbered.. not the height on the screen
2642 bool clamp_y_axis = false;
2643 vector<int32_t> height_list(512) ;
2644 vector<int32_t>::iterator j;
2646 /* Which trackview is this ? */
2648 TimeAxisView* tvp = trackview_by_y_position (drag_info.current_pointer_y);
2649 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
2651 /* The region motion is only processed if the pointer is over
2655 if (!tv || !tv->is_audio_track()) {
2656 /* To make sure we hide the verbose canvas cursor when the mouse is
2657 not held over and audiotrack.
2659 hide_verbose_canvas_cursor ();
2663 original_pointer_order = drag_info.last_trackview->order;
2665 /************************************************************
2667 ************************************************************/
2669 if (drag_info.brushing) {
2670 clamp_y_axis = true;
2675 if ((pointer_y_span = (drag_info.last_trackview->order - tv->order)) != 0) {
2677 int32_t children = 0, numtracks = 0;
2678 bitset <512> tracks (0x00);
2679 /* get a bitmask representing the visible tracks */
2681 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2682 TimeAxisView *tracklist_timeview;
2683 tracklist_timeview = (*i);
2684 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tracklist_timeview);
2685 list<TimeAxisView*> children_list;
2687 /* zeroes are audio tracks. ones are other types. */
2689 if (!atv2->hidden()) {
2691 if (visible_y_high < atv2->order) {
2692 visible_y_high = atv2->order;
2694 if (visible_y_low > atv2->order) {
2695 visible_y_low = atv2->order;
2698 if (!atv2->is_audio_track()) {
2699 tracks = tracks |= (0x01 << atv2->order);
2702 height_list[atv2->order] = (*i)->height;
2704 if ((children_list = atv2->get_child_list()).size() > 0) {
2705 for (list<TimeAxisView*>::iterator j = children_list.begin(); j != children_list.end(); ++j) {
2706 tracks = tracks |= (0x01 << (atv2->order + children));
2707 height_list[atv2->order + children] = (*j)->height;
2715 /* find the actual span according to the canvas */
2717 canvas_pointer_y_span = pointer_y_span;
2718 if (drag_info.last_trackview->order >= tv->order) {
2720 for (y = tv->order; y < drag_info.last_trackview->order; y++) {
2721 if (height_list[y] == 0 ) {
2722 canvas_pointer_y_span--;
2727 for (y = drag_info.last_trackview->order;y <= tv->order; y++) {
2728 if ( height_list[y] == 0 ) {
2729 canvas_pointer_y_span++;
2734 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
2735 AudioRegionView* rv2;
2737 double ix1, ix2, iy1, iy2;
2740 rv2->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
2741 rv2->get_canvas_group()->i2w (ix1, iy1);
2742 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
2743 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2);
2745 if (atv2->order != original_pointer_order) {
2746 /* this isn't the pointer track */
2748 if (canvas_pointer_y_span > 0) {
2750 /* moving up the canvas */
2751 if ((atv2->order - canvas_pointer_y_span) >= visible_y_low) {
2753 int32_t visible_tracks = 0;
2754 while (visible_tracks < canvas_pointer_y_span ) {
2757 while (height_list[atv2->order - (visible_tracks - n)] == 0) {
2758 /* we're passing through a hidden track */
2763 if (tracks[atv2->order - (canvas_pointer_y_span - n)] != 0x00) {
2764 clamp_y_axis = true;
2768 clamp_y_axis = true;
2771 } else if (canvas_pointer_y_span < 0) {
2773 /*moving down the canvas*/
2775 if ((atv2->order - (canvas_pointer_y_span - n)) <= visible_y_high) { // we will overflow
2778 int32_t visible_tracks = 0;
2780 while (visible_tracks > canvas_pointer_y_span ) {
2783 while (height_list[atv2->order - (visible_tracks - n)] == 0) {
2787 if ( tracks[atv2->order - ( canvas_pointer_y_span - n)] != 0x00) {
2788 clamp_y_axis = true;
2793 clamp_y_axis = true;
2799 /* this is the pointer's track */
2800 if ((atv2->order - pointer_y_span) > visible_y_high) { // we will overflow
2801 clamp_y_axis = true;
2802 } else if ((atv2->order - pointer_y_span) < visible_y_low) { // we will underflow
2803 clamp_y_axis = true;
2811 } else if (drag_info.last_trackview == tv) {
2812 clamp_y_axis = true;
2816 if (!clamp_y_axis) {
2817 drag_info.last_trackview = tv;
2820 /************************************************************
2822 ************************************************************/
2824 /* compute the amount of pointer motion in frames, and where
2825 the region would be if we moved it by that much.
2828 if (drag_info.move_threshold_passsed) {
2830 if ((int32_t)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
2832 jack_nframes_t sync_frame;
2833 jack_nframes_t sync_offset;
2836 pending_region_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2838 sync_offset = rv->region.sync_offset (sync_dir);
2839 sync_frame = rv->region.adjust_to_sync (pending_region_position);
2841 /* we snap if the snap modifier is not enabled.
2844 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2845 snap_to (sync_frame);
2848 if (sync_frame - sync_offset <= sync_frame) {
2849 pending_region_position = sync_frame - (sync_dir*sync_offset);
2851 pending_region_position = 0;
2855 pending_region_position = 0;
2858 if (pending_region_position > max_frames - rv->region.length()) {
2859 pending_region_position = drag_info.last_frame_position;
2862 // printf ("3: pending_region_position= %lu %lu\n", pending_region_position, drag_info.last_frame_position );
2864 if (pending_region_position != drag_info.last_frame_position && !drag_info.x_constrained) {
2866 /* now compute the canvas unit distance we need to move the regiondrag_info.last_trackview->order
2867 to make it appear at the new location.
2870 if (pending_region_position > drag_info.last_frame_position) {
2871 x_delta = ((double) (pending_region_position - drag_info.last_frame_position) / frames_per_unit);
2873 x_delta = -((double) (drag_info.last_frame_position - pending_region_position) / frames_per_unit);
2876 drag_info.last_frame_position = pending_region_position;
2883 /* threshold not passed */
2888 /*************************************************************
2890 ************************************************************/
2892 if (x_delta == 0 && (pointer_y_span == 0)) {
2893 /* haven't reached next snap point, and we're not switching
2894 trackviews. nothing to do.
2900 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
2902 AudioRegionView* rv2;
2905 /* if any regionview is at zero, we need to know so we can
2906 stop further leftward motion.
2909 double ix1, ix2, iy1, iy2;
2910 rv2->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
2911 rv2->get_canvas_group()->i2w (ix1, iy1);
2920 /*************************************************************
2922 ************************************************************/
2924 pair<set<Playlist*>::iterator,bool> insert_result;
2926 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
2928 AudioRegionView* rv;
2930 double ix1, ix2, iy1, iy2;
2931 int32_t temp_pointer_y_span = pointer_y_span;
2933 /* get item BBox, which will be relative to parent. so we have
2934 to query on a child, then convert to world coordinates using
2938 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
2939 rv->get_canvas_group()->i2w (ix1, iy1);
2940 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
2941 AudioTimeAxisView* canvas_atv = dynamic_cast<AudioTimeAxisView*>(tvp2);
2942 AudioTimeAxisView* temp_atv;
2944 if ((pointer_y_span != 0) && !clamp_y_axis) {
2947 for (j = height_list.begin(); j!= height_list.end(); j++) {
2948 if (x == canvas_atv->order) {
2949 /* we found the track the region is on */
2950 if (x != original_pointer_order) {
2951 /*this isn't from the same track we're dragging from */
2952 temp_pointer_y_span = canvas_pointer_y_span;
2954 while (temp_pointer_y_span > 0) {
2955 /* we're moving up canvas-wise,
2956 so we need to find the next track height
2958 if (j != height_list.begin()) {
2961 if (x != original_pointer_order) {
2962 /* we're not from the dragged track, so ignore hidden tracks. */
2964 temp_pointer_y_span++;
2968 temp_pointer_y_span--;
2970 while (temp_pointer_y_span < 0) {
2972 if (x != original_pointer_order) {
2974 temp_pointer_y_span--;
2978 if (j != height_list.end()) {
2981 temp_pointer_y_span++;
2983 /* find out where we'll be when we move and set height accordingly */
2985 tvp2 = trackview_by_y_position (iy1 + y_delta);
2986 temp_atv = dynamic_cast<AudioTimeAxisView*>(tvp2);
2987 rv->set_height (temp_atv->height);
2989 /* if you un-comment the following, the region colours will follow the track colours whilst dragging,
2990 personally, i think this can confuse things, but never mind.
2993 //const GdkColor& col (temp_atv->view->get_region_color());
2994 //rv->set_color (const_cast<GdkColor&>(col));
3001 /* prevent the regionview from being moved to before
3002 the zero position on the canvas.
3007 if (-x_delta > ix1) {
3010 } else if ((x_delta > 0) &&(rv->region.last_frame() > max_frames - x_delta)) {
3011 x_delta = max_frames - rv->region.last_frame();
3014 if (drag_info.first_move) {
3016 /* hide any dependent views */
3018 // rv->get_time_axis_view().hide_dependent_views (*rv);
3020 /* this is subtle. raising the regionview itself won't help,
3021 because raise_to_top() just puts the item on the top of
3022 its parent's stack. so, we need to put the trackview canvas_display group
3023 on the top, since its parent is the whole canvas.
3026 rv->get_canvas_group()->raise_to_top();
3027 rv->get_time_axis_view().canvas_display->raise_to_top();
3028 cursor_group->raise_to_top();
3030 /* freeze the playlists from notifying till
3034 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&rv->get_time_axis_view());
3035 if (atv && atv->is_audio_track()) {
3036 AudioPlaylist* pl = atv->get_diskstream()->playlist();
3038 /* only freeze and capture state once */
3040 insert_result = motion_frozen_playlists.insert (pl);
3041 if (insert_result.second) {
3043 session->add_undo(pl->get_memento());
3049 if (drag_info.brushing) {
3050 mouse_brush_insert_region (rv, pending_region_position);
3052 rv->move (x_delta, y_delta);
3056 if (drag_info.first_move) {
3057 cursor_group->raise_to_top();
3060 drag_info.first_move = false;
3062 if (x_delta != 0 && !drag_info.brushing) {
3063 show_verbose_time_cursor (drag_info.last_frame_position, 10);
3069 Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
3071 jack_nframes_t where;
3072 AudioRegionView* rv = reinterpret_cast<AudioRegionView *> (drag_info.data);
3073 pair<set<Playlist*>::iterator,bool> insert_result;
3074 bool nocommit = true;
3076 AudioTimeAxisView* atv;
3077 bool regionview_y_movement;
3078 bool regionview_x_movement;
3080 /* first_move is set to false if the regionview has been moved in the
3084 if (drag_info.first_move) {
3091 /* The regionview has been moved at some stage during the grab so we need
3092 to account for any mouse movement between this event and the last one.
3095 region_drag_motion_callback (item, event);
3097 if (drag_info.brushing) {
3098 /* all changes were made during motion event handlers */
3102 /* adjust for track speed */
3105 atv = dynamic_cast<AudioTimeAxisView*> (drag_info.last_trackview);
3106 if (atv && atv->get_diskstream()) {
3107 speed = atv->get_diskstream()->speed();
3110 regionview_x_movement = (drag_info.last_frame_position != (jack_nframes_t) (rv->region.position()/speed));
3111 regionview_y_movement = (drag_info.last_trackview != &rv->get_time_axis_view());
3113 //printf ("last_frame: %s position is %lu %g\n", rv->get_time_axis_view().name().c_str(), drag_info.last_frame_position, speed);
3114 //printf ("last_rackview: %s \n", drag_info.last_trackview->name().c_str());
3116 if (regionview_y_movement) {
3118 /* motion between tracks */
3120 list<AudioRegionView*> new_selection;
3122 /* moved to a different audio track. */
3124 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ) {
3126 AudioRegionView* rv2 = (*i);
3128 /* the region that used to be in the old playlist is not
3129 moved to the new one - we make a copy of it. as a result,
3130 any existing editor for the region should no longer be
3134 if (!drag_info.copy) {
3135 rv2->hide_region_editor();
3137 new_selection.push_back (rv2);
3141 /* first, freeze the target tracks */
3143 for (list<AudioRegionView*>::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) {
3145 Playlist* from_playlist;
3146 Playlist* to_playlist;
3148 double ix1, ix2, iy1, iy2;
3150 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3151 (*i)->get_canvas_group()->i2w (ix1, iy1);
3152 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
3153 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2);
3155 from_playlist = (*i)->region.playlist();
3156 to_playlist = atv2->playlist();
3158 /* the from_playlist was frozen in the "first_move" case
3159 of the motion handler. the insert can fail,
3160 but that doesn't matter. it just means
3161 we already have the playlist in the list.
3164 motion_frozen_playlists.insert (from_playlist);
3166 /* only freeze the to_playlist once */
3168 insert_result = motion_frozen_playlists.insert(to_playlist);
3169 if (insert_result.second) {
3170 to_playlist->freeze();
3171 session->add_undo(to_playlist->get_memento());
3176 /* now do it again with the actual operations */
3178 for (list<AudioRegionView*>::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) {
3180 Playlist* from_playlist;
3181 Playlist* to_playlist;
3183 double ix1, ix2, iy1, iy2;
3185 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3186 (*i)->get_canvas_group()->i2w (ix1, iy1);
3187 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
3188 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2);
3190 from_playlist = (*i)->region.playlist();
3191 to_playlist = atv2->playlist();
3193 latest_regionview = 0;
3195 where = (jack_nframes_t) (unit_to_frame (ix1) * speed);
3196 Region* new_region = createRegion ((*i)->region);
3198 from_playlist->remove_region (&((*i)->region));
3200 sigc::connection c = atv2->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3201 to_playlist->add_region (*new_region, where);
3204 if (latest_regionview) {
3205 selection->add (latest_regionview);
3211 /* motion within a single track */
3213 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
3217 if (rv->region.locked()) {
3221 if (regionview_x_movement) {
3222 double ownspeed = 1.0;
3223 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&(rv->get_time_axis_view()));
3225 if (atv && atv->get_diskstream()) {
3226 ownspeed = atv->get_diskstream()->speed();
3229 /* base the new region position on the current position of the regionview.*/
3231 double ix1, ix2, iy1, iy2;
3233 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3234 rv->get_canvas_group()->i2w (ix1, iy1);
3235 where = (jack_nframes_t) (unit_to_frame (ix1) * ownspeed);
3239 where = rv->region.position();
3242 rv->get_time_axis_view().reveal_dependent_views (*rv);
3244 session->add_undo (rv->region.playlist()->get_memento());
3245 rv->region.set_position (where, (void *) this);
3250 for (set<Playlist*>::iterator p = motion_frozen_playlists.begin(); p != motion_frozen_playlists.end(); ++p) {
3252 session->add_redo_no_execute ((*p)->get_memento());
3255 motion_frozen_playlists.clear ();
3258 commit_reversible_command ();
3263 Editor::region_view_item_click (AudioRegionView& rv, GdkEventButton* event)
3265 /* Either add to or set the set the region selection, unless
3266 this is an alignment click (control used)
3269 if (Keyboard::modifier_state_contains (event->state, Keyboard::Control)) {
3270 TimeAxisView* tv = &rv.get_time_axis_view();
3271 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(tv);
3273 if (atv && atv->is_audio_track()) {
3274 speed = atv->get_diskstream()->speed();
3277 if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Alt))) {
3279 align_region (rv.region, SyncPoint, (jack_nframes_t) (edit_cursor->current_frame * speed));
3281 } else if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Shift))) {
3283 align_region (rv.region, End, (jack_nframes_t) (edit_cursor->current_frame * speed));
3287 align_region (rv.region, Start, (jack_nframes_t) (edit_cursor->current_frame * speed));
3293 Editor::show_verbose_time_cursor (jack_nframes_t frame, double offset, double xpos, double ypos)
3304 switch (ARDOUR_UI::instance()->secondary_clock.mode ()) {
3305 case AudioClock::BBT:
3306 session->bbt_time (frame, bbt);
3307 snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32, bbt.bars, bbt.beats, bbt.ticks);
3310 case AudioClock::SMPTE:
3311 session->smpte_time (frame, smpte);
3312 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
3315 case AudioClock::MinSec:
3316 /* XXX fix this to compute min/sec properly */
3317 session->smpte_time (frame, smpte);
3318 secs = smpte.seconds + ((float) smpte.frames / session->smpte_frames_per_second);
3319 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%.4f", smpte.hours, smpte.minutes, secs);
3323 snprintf (buf, sizeof(buf), "%u", frame);
3327 if (xpos >= 0 && ypos >=0) {
3328 set_verbose_canvas_cursor (buf, xpos + offset, ypos + offset);
3331 set_verbose_canvas_cursor (buf, drag_info.current_pointer_x + offset, drag_info.current_pointer_y + offset);
3333 show_verbose_canvas_cursor ();
3337 Editor::show_verbose_duration_cursor (jack_nframes_t start, jack_nframes_t end, double offset, double xpos, double ypos)
3344 Meter meter_at_start(session->tempo_map().meter_at(start));
3350 switch (ARDOUR_UI::instance()->secondary_clock.mode ()) {
3351 case AudioClock::BBT:
3352 session->bbt_time (start, sbbt);
3353 session->bbt_time (end, ebbt);
3356 /* XXX this computation won't work well if the
3357 user makes a selection that spans any meter changes.
3360 ebbt.bars -= sbbt.bars;
3361 if (ebbt.beats >= sbbt.beats) {
3362 ebbt.beats -= sbbt.beats;
3365 ebbt.beats = int(meter_at_start.beats_per_bar()) + ebbt.beats - sbbt.beats;
3367 if (ebbt.ticks >= sbbt.ticks) {
3368 ebbt.ticks -= sbbt.ticks;
3371 ebbt.ticks = int(Meter::ticks_per_beat) + ebbt.ticks - sbbt.ticks;
3374 snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32, ebbt.bars, ebbt.beats, ebbt.ticks);
3377 case AudioClock::SMPTE:
3378 session->smpte_duration (end - start, smpte);
3379 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
3382 case AudioClock::MinSec:
3383 /* XXX fix this to compute min/sec properly */
3384 session->smpte_duration (end - start, smpte);
3385 secs = smpte.seconds + ((float) smpte.frames / session->smpte_frames_per_second);
3386 snprintf (buf, sizeof (buf), "%02ld:%02ld:%.4f", smpte.hours, smpte.minutes, secs);
3390 snprintf (buf, sizeof(buf), "%u", end - start);
3394 if (xpos >= 0 && ypos >=0) {
3395 set_verbose_canvas_cursor (buf, xpos + offset, ypos + offset);
3398 set_verbose_canvas_cursor (buf, drag_info.current_pointer_x + offset, drag_info.current_pointer_y + offset);
3400 show_verbose_canvas_cursor ();
3404 Editor::collect_new_region_view (AudioRegionView* rv)
3406 latest_regionview = rv;
3410 Editor::start_selection_grab (ArdourCanvas::Item* item, GdkEvent* event)
3412 if (clicked_regionview == 0) {
3416 /* lets try to create new Region for the selection */
3418 vector<AudioRegion*> new_regions;
3419 create_region_from_selection (new_regions);
3421 if (new_regions.empty()) {
3425 /* XXX fix me one day to use all new regions */
3427 Region* region = new_regions.front();
3429 /* add it to the current stream/playlist.
3431 tricky: the streamview for the track will add a new regionview. we will
3432 catch the signal it sends when it creates the regionview to
3433 set the regionview we want to then drag.
3436 latest_regionview = 0;
3437 sigc::connection c = clicked_audio_trackview->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3439 /* A selection grab currently creates two undo/redo operations, one for
3440 creating the new region and another for moving it.
3443 begin_reversible_command (_("selection grab"));
3445 Playlist* playlist = clicked_trackview->playlist();
3447 session->add_undo (playlist->get_memento ());
3448 clicked_trackview->playlist()->add_region (*region, selection->time[clicked_selection].start);
3449 session->add_redo_no_execute (playlist->get_memento ());
3451 commit_reversible_command ();
3455 if (latest_regionview == 0) {
3456 /* something went wrong */
3460 /* we need to deselect all other regionviews, and select this one
3461 i'm ignoring undo stuff, because the region creation will take care of it */
3462 selection->set (latest_regionview);
3464 drag_info.item = latest_regionview->get_canvas_group();
3465 drag_info.data = latest_regionview;
3466 drag_info.motion_callback = &Editor::region_drag_motion_callback;
3467 drag_info.finished_callback = &Editor::region_drag_finished_callback;
3471 drag_info.last_trackview = clicked_trackview;
3472 drag_info.last_frame_position = latest_regionview->region.position();
3473 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
3475 show_verbose_time_cursor (drag_info.last_frame_position, 10);
3479 Editor::cancel_selection ()
3481 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3482 (*i)->hide_selection ();
3484 selection->clear ();
3485 clicked_selection = 0;
3489 Editor::start_selection_op (ArdourCanvas::Item* item, GdkEvent* event, SelectionOp op)
3491 jack_nframes_t start = 0;
3492 jack_nframes_t end = 0;
3498 drag_info.item = item;
3499 drag_info.motion_callback = &Editor::drag_selection;
3500 drag_info.finished_callback = &Editor::end_selection_op;
3505 case CreateSelection:
3507 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
3508 drag_info.copy = true;
3510 drag_info.copy = false;
3512 start_grab (event, selector_cursor);
3515 case SelectionStartTrim:
3516 clicked_trackview->order_selection_trims (item, true);
3517 start_grab (event, trimmer_cursor);
3518 start = selection->time[clicked_selection].start;
3519 drag_info.pointer_frame_offset = drag_info.grab_frame - start;
3522 case SelectionEndTrim:
3523 clicked_trackview->order_selection_trims (item, false);
3524 start_grab (event, trimmer_cursor);
3525 end = selection->time[clicked_selection].end;
3526 drag_info.pointer_frame_offset = drag_info.grab_frame - end;
3530 start = selection->time[clicked_selection].start;
3532 drag_info.pointer_frame_offset = drag_info.grab_frame - start;
3536 if (selection_op == SelectionMove) {
3537 show_verbose_time_cursor(start, 10);
3539 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
3544 Editor::drag_selection (ArdourCanvas::Item* item, GdkEvent* event)
3546 jack_nframes_t start = 0;
3547 jack_nframes_t end = 0;
3548 jack_nframes_t length;
3549 jack_nframes_t pending_position;
3551 if ((int32_t) drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
3552 pending_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
3555 pending_position = 0;
3558 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3559 snap_to (pending_position);
3562 /* only alter selection if the current frame is
3563 different from the last frame position (adjusted)
3566 if (pending_position == drag_info.last_pointer_frame) return;
3568 switch (selection_op) {
3569 case CreateSelection:
3571 if (drag_info.first_move) {
3572 snap_to (drag_info.grab_frame);
3575 if (pending_position < drag_info.grab_frame) {
3576 start = pending_position;
3577 end = drag_info.grab_frame;
3579 end = pending_position;
3580 start = drag_info.grab_frame;
3583 /* first drag: Either add to the selection
3584 or create a new selection->
3587 if (drag_info.first_move) {
3589 begin_reversible_command (_("range selection"));
3591 if (drag_info.copy) {
3592 /* adding to the selection */
3593 clicked_selection = selection->add (start, end);
3594 drag_info.copy = false;
3596 /* new selection-> */
3597 clicked_selection = selection->set (clicked_trackview, start, end);
3602 case SelectionStartTrim:
3604 if (drag_info.first_move) {
3605 begin_reversible_command (_("trim selection start"));
3608 start = selection->time[clicked_selection].start;
3609 end = selection->time[clicked_selection].end;
3611 if (pending_position > end) {
3614 start = pending_position;
3618 case SelectionEndTrim:
3620 if (drag_info.first_move) {
3621 begin_reversible_command (_("trim selection end"));
3624 start = selection->time[clicked_selection].start;
3625 end = selection->time[clicked_selection].end;
3627 if (pending_position < start) {
3630 end = pending_position;
3637 if (drag_info.first_move) {
3638 begin_reversible_command (_("move selection"));
3641 start = selection->time[clicked_selection].start;
3642 end = selection->time[clicked_selection].end;
3644 length = end - start;
3646 start = pending_position;
3649 end = start + length;
3654 if (event->button.x >= horizontal_adjustment.get_value() + canvas_width) {
3655 start_canvas_autoscroll (1);
3659 selection->replace (clicked_selection, start, end);
3662 drag_info.last_pointer_frame = pending_position;
3663 drag_info.first_move = false;
3665 if (selection_op == SelectionMove) {
3666 show_verbose_time_cursor(start, 10);
3668 show_verbose_time_cursor(pending_position, 10);
3673 Editor::end_selection_op (ArdourCanvas::Item* item, GdkEvent* event)
3675 if (!drag_info.first_move) {
3676 drag_selection (item, event);
3677 /* XXX this is not object-oriented programming at all. ick */
3678 if (selection->time.consolidate()) {
3679 selection->TimeChanged ();
3681 commit_reversible_command ();
3683 /* just a click, no pointer movement.*/
3685 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3687 selection->clear_time();
3692 /* XXX what happens if its a music selection? */
3693 session->set_audio_range (selection->time);
3694 stop_canvas_autoscroll ();
3698 Editor::start_trim (ArdourCanvas::Item* item, GdkEvent* event)
3701 TimeAxisView* tvp = clicked_trackview;
3702 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3704 if (tv && tv->is_audio_track()) {
3705 speed = tv->get_diskstream()->speed();
3708 jack_nframes_t region_start = (jack_nframes_t) (clicked_regionview->region.position() / speed);
3709 jack_nframes_t region_end = (jack_nframes_t) (clicked_regionview->region.last_frame() / speed);
3710 jack_nframes_t region_length = (jack_nframes_t) (clicked_regionview->region.length() / speed);
3712 //drag_info.item = clicked_regionview->get_name_highlight();
3713 drag_info.item = item;
3714 drag_info.motion_callback = &Editor::trim_motion_callback;
3715 drag_info.finished_callback = &Editor::trim_finished_callback;
3717 start_grab (event, trimmer_cursor);
3719 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
3720 trim_op = ContentsTrim;
3722 /* These will get overridden for a point trim.*/
3723 if (drag_info.current_pointer_frame < (region_start + region_length/2)) {
3724 /* closer to start */
3725 trim_op = StartTrim;
3726 } else if (drag_info.current_pointer_frame > (region_end - region_length/2)) {
3734 show_verbose_time_cursor(region_start, 10);
3737 show_verbose_time_cursor(region_end, 10);
3740 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
3746 Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
3748 AudioRegionView* rv = clicked_regionview;
3749 jack_nframes_t frame_delta = 0;
3750 bool left_direction;
3751 bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier());
3753 /* snap modifier works differently here..
3754 its' current state has to be passed to the
3755 various trim functions in order to work properly
3759 TimeAxisView* tvp = clicked_trackview;
3760 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3762 if (tv && tv->is_audio_track()) {
3763 speed = tv->get_diskstream()->speed();
3766 if (drag_info.last_pointer_frame > drag_info.current_pointer_frame) {
3767 left_direction = true;
3769 left_direction = false;
3773 snap_to (drag_info.current_pointer_frame);
3776 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) {
3780 if (drag_info.first_move) {
3786 trim_type = "Region start trim";
3789 trim_type = "Region end trim";
3792 trim_type = "Region content trim";
3796 begin_reversible_command (trim_type);
3798 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
3799 (*i)->region.freeze ();
3800 (*i)->temporarily_hide_envelope ();
3801 session->add_undo ((*i)->region.playlist()->get_memento());
3805 if (left_direction) {
3806 frame_delta = (drag_info.last_pointer_frame - drag_info.current_pointer_frame);
3808 frame_delta = (drag_info.current_pointer_frame - drag_info.last_pointer_frame);
3813 if ((left_direction == false) && (drag_info.current_pointer_frame <= rv->region.first_frame()/speed)) {
3816 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
3817 single_start_trim (**i, frame_delta, left_direction, obey_snap);
3823 if ((left_direction == true) && (drag_info.current_pointer_frame > (jack_nframes_t) (rv->region.last_frame()/speed))) {
3826 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
3827 single_end_trim (**i, frame_delta, left_direction, obey_snap);
3834 bool swap_direction = false;
3836 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
3837 swap_direction = true;
3840 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin();
3841 i != selection->audio_regions.by_layer().end(); ++i)
3843 single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
3851 show_verbose_time_cursor((jack_nframes_t) (rv->region.position()/speed), 10);
3854 show_verbose_time_cursor((jack_nframes_t) (rv->region.last_frame()/speed), 10);
3857 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
3861 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
3862 drag_info.first_move = false;
3866 Editor::single_contents_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool swap_direction, bool obey_snap)
3868 Region& region (rv.region);
3870 if (region.locked()) {
3874 jack_nframes_t new_bound;
3877 TimeAxisView* tvp = clicked_trackview;
3878 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3880 if (tv && tv->is_audio_track()) {
3881 speed = tv->get_diskstream()->speed();
3884 if (left_direction) {
3885 if (swap_direction) {
3886 new_bound = (jack_nframes_t) (region.position()/speed) + frame_delta;
3888 new_bound = (jack_nframes_t) (region.position()/speed) - frame_delta;
3891 if (swap_direction) {
3892 new_bound = (jack_nframes_t) (region.position()/speed) - frame_delta;
3894 new_bound = (jack_nframes_t) (region.position()/speed) + frame_delta;
3899 snap_to (new_bound);
3901 region.trim_start ((jack_nframes_t) (new_bound * speed), this);
3902 rv.region_changed (StartChanged);
3906 Editor::single_start_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool obey_snap)
3908 Region& region (rv.region);
3910 if (region.locked()) {
3914 jack_nframes_t new_bound;
3917 TimeAxisView* tvp = clicked_trackview;
3918 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3920 if (tv && tv->is_audio_track()) {
3921 speed = tv->get_diskstream()->speed();
3924 if (left_direction) {
3925 new_bound = (jack_nframes_t) (region.position()/speed) - frame_delta;
3927 new_bound = (jack_nframes_t) (region.position()/speed) + frame_delta;
3931 snap_to (new_bound, (left_direction ? 0 : 1));
3934 region.trim_front ((jack_nframes_t) (new_bound * speed), this);
3936 rv.region_changed (Change (LengthChanged|PositionChanged|StartChanged));
3940 Editor::single_end_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool obey_snap)
3942 Region& region (rv.region);
3944 if (region.locked()) {
3948 jack_nframes_t new_bound;
3951 TimeAxisView* tvp = clicked_trackview;
3952 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3954 if (tv && tv->is_audio_track()) {
3955 speed = tv->get_diskstream()->speed();
3958 if (left_direction) {
3959 new_bound = (jack_nframes_t) ((region.last_frame() + 1)/speed) - frame_delta;
3961 new_bound = (jack_nframes_t) ((region.last_frame() + 1)/speed) + frame_delta;
3965 snap_to (new_bound);
3967 region.trim_end ((jack_nframes_t) (new_bound * speed), this);
3968 rv.region_changed (LengthChanged);
3972 Editor::trim_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
3974 if (!drag_info.first_move) {
3975 trim_motion_callback (item, event);
3977 if (!clicked_regionview->get_selected()) {
3978 thaw_region_after_trim (*clicked_regionview);
3981 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin();
3982 i != selection->audio_regions.by_layer().end(); ++i)
3984 thaw_region_after_trim (**i);
3987 commit_reversible_command();
3989 /* no mouse movement */
3995 Editor::point_trim (GdkEvent* event)
3997 AudioRegionView* rv = clicked_regionview;
3998 jack_nframes_t new_bound = drag_info.current_pointer_frame;
4000 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4001 snap_to (new_bound);
4004 /* Choose action dependant on which button was pressed */
4005 switch (event->button.button) {
4007 trim_op = StartTrim;
4008 begin_reversible_command (_("Start point trim"));
4010 if (rv->get_selected()) {
4012 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin();
4013 i != selection->audio_regions.by_layer().end(); ++i)
4015 if (!(*i)->region.locked()) {
4016 session->add_undo ((*i)->region.playlist()->get_memento());
4017 (*i)->region.trim_front (new_bound, this);
4018 session->add_redo_no_execute ((*i)->region.playlist()->get_memento());
4024 if (!rv->region.locked()) {
4025 session->add_undo (rv->region.playlist()->get_memento());
4026 rv->region.trim_front (new_bound, this);
4027 session->add_redo_no_execute (rv->region.playlist()->get_memento());
4031 commit_reversible_command();
4036 begin_reversible_command (_("End point trim"));
4038 if (rv->get_selected()) {
4040 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i)
4042 if (!(*i)->region.locked()) {
4043 session->add_undo ((*i)->region.playlist()->get_memento());
4044 (*i)->region.trim_end (new_bound, this);
4045 session->add_redo_no_execute ((*i)->region.playlist()->get_memento());
4051 if (!rv->region.locked()) {
4052 session->add_undo (rv->region.playlist()->get_memento());
4053 rv->region.trim_end (new_bound, this);
4054 session->add_redo_no_execute (rv->region.playlist()->get_memento());
4058 commit_reversible_command();
4067 Editor::thaw_region_after_trim (AudioRegionView& rv)
4069 Region& region (rv.region);
4071 if (region.locked()) {
4075 region.thaw (_("trimmed region"));
4076 session->add_redo_no_execute (region.playlist()->get_memento());
4078 rv.unhide_envelope ();
4082 Editor::hide_marker (ArdourCanvas::Item* item, GdkEvent* event)
4087 if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
4088 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
4092 Location* location = find_location_from_marker (marker, is_start);
4093 location->set_hidden (true, this);
4098 Editor::start_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event, RangeMarkerOp op)
4105 drag_info.item = item;
4106 drag_info.motion_callback = &Editor::drag_range_markerbar_op;
4107 drag_info.finished_callback = &Editor::end_range_markerbar_op;
4109 range_marker_op = op;
4111 if (!temp_location) {
4112 temp_location = new Location;
4116 case CreateRangeMarker:
4117 case CreateTransportMarker:
4119 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
4120 drag_info.copy = true;
4122 drag_info.copy = false;
4124 start_grab (event, selector_cursor);
4128 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
4133 Editor::drag_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event)
4135 jack_nframes_t start = 0;
4136 jack_nframes_t end = 0;
4137 ArdourCanvas::SimpleRect *crect = (range_marker_op == CreateRangeMarker) ? range_bar_drag_rect: transport_bar_drag_rect;
4139 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4140 snap_to (drag_info.current_pointer_frame);
4143 /* only alter selection if the current frame is
4144 different from the last frame position.
4147 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) return;
4149 switch (range_marker_op) {
4150 case CreateRangeMarker:
4151 case CreateTransportMarker:
4152 if (drag_info.first_move) {
4153 snap_to (drag_info.grab_frame);
4156 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4157 start = drag_info.current_pointer_frame;
4158 end = drag_info.grab_frame;
4160 end = drag_info.current_pointer_frame;
4161 start = drag_info.grab_frame;
4164 /* first drag: Either add to the selection
4165 or create a new selection->
4168 if (drag_info.first_move) {
4170 temp_location->set (start, end);
4174 update_marker_drag_item (temp_location);
4175 range_marker_drag_rect->show();
4176 range_marker_drag_rect->raise_to_top();
4182 if (event->button.x >= horizontal_adjustment.get_value() + canvas_width) {
4183 start_canvas_autoscroll (1);
4187 temp_location->set (start, end);
4189 double x1 = frame_to_pixel (start);
4190 double x2 = frame_to_pixel (end);
4191 crect->property_x1() = x1;
4192 crect->property_x2() = x2;
4194 update_marker_drag_item (temp_location);
4197 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4198 drag_info.first_move = false;
4200 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
4205 Editor::end_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event)
4207 Location * newloc = 0;
4209 if (!drag_info.first_move) {
4210 drag_range_markerbar_op (item, event);
4212 switch (range_marker_op) {
4213 case CreateRangeMarker:
4214 begin_reversible_command (_("new range marker"));
4215 session->add_undo (session->locations()->get_memento());
4216 newloc = new Location(temp_location->start(), temp_location->end(), "unnamed");
4217 session->locations()->add (newloc, true);
4218 session->add_redo_no_execute (session->locations()->get_memento());
4219 commit_reversible_command ();
4221 range_bar_drag_rect->hide();
4222 range_marker_drag_rect->hide();
4225 case CreateTransportMarker:
4226 // popup menu to pick loop or punch
4227 new_transport_marker_context_menu (&event->button, item);
4232 /* just a click, no pointer movement.*/
4234 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
4241 stop_canvas_autoscroll ();
4247 Editor::start_mouse_zoom (ArdourCanvas::Item* item, GdkEvent* event)
4249 drag_info.item = item;
4250 drag_info.motion_callback = &Editor::drag_mouse_zoom;
4251 drag_info.finished_callback = &Editor::end_mouse_zoom;
4253 start_grab (event, zoom_cursor);
4255 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4259 Editor::drag_mouse_zoom (ArdourCanvas::Item* item, GdkEvent* event)
4261 jack_nframes_t start;
4264 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4265 snap_to (drag_info.current_pointer_frame);
4267 if (drag_info.first_move) {
4268 snap_to (drag_info.grab_frame);
4272 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) return;
4274 /* base start and end on initial click position */
4275 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4276 start = drag_info.current_pointer_frame;
4277 end = drag_info.grab_frame;
4279 end = drag_info.current_pointer_frame;
4280 start = drag_info.grab_frame;
4285 if (drag_info.first_move) {
4287 zoom_rect->raise_to_top();
4290 reposition_zoom_rect(start, end);
4292 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4293 drag_info.first_move = false;
4295 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4300 Editor::end_mouse_zoom (ArdourCanvas::Item* item, GdkEvent* event)
4302 if (!drag_info.first_move) {
4303 drag_mouse_zoom (item, event);
4305 if (drag_info.grab_frame < drag_info.last_pointer_frame) {
4306 temporal_zoom_by_frame (drag_info.grab_frame, drag_info.last_pointer_frame, "mouse zoom");
4308 temporal_zoom_by_frame (drag_info.last_pointer_frame, drag_info.grab_frame, "mouse zoom");
4311 temporal_zoom_to_frame (false, drag_info.grab_frame);
4313 temporal_zoom_step (false);
4314 center_screen (drag_info.grab_frame);
4322 Editor::reposition_zoom_rect (jack_nframes_t start, jack_nframes_t end)
4324 double x1 = frame_to_pixel (start);
4325 double x2 = frame_to_pixel (end);
4326 double y2 = canvas_height - 2;
4328 zoom_rect->property_x1() = x1;
4329 zoom_rect->property_y1() = 1.0;
4330 zoom_rect->property_x2() = x2;
4331 zoom_rect->property_y2() = y2;
4335 Editor::start_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event)
4337 drag_info.item = item;
4338 drag_info.motion_callback = &Editor::drag_rubberband_select;
4339 drag_info.finished_callback = &Editor::end_rubberband_select;
4341 start_grab (event, cross_hair_cursor);
4343 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4347 Editor::drag_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event)
4349 jack_nframes_t start;
4354 /* use a bigger drag threshold than the default */
4356 if (abs ((int) (drag_info.current_pointer_frame - drag_info.grab_frame)) < 8) {
4360 // if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4361 // snap_to (drag_info.current_pointer_frame);
4363 // if (drag_info.first_move) {
4364 // snap_to (drag_info.grab_frame);
4369 /* base start and end on initial click position */
4370 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4371 start = drag_info.current_pointer_frame;
4372 end = drag_info.grab_frame;
4374 end = drag_info.current_pointer_frame;
4375 start = drag_info.grab_frame;
4378 if (drag_info.current_pointer_y < drag_info.grab_y) {
4379 y1 = drag_info.current_pointer_y;
4380 y2 = drag_info.grab_y;
4383 y2 = drag_info.current_pointer_y;
4384 y1 = drag_info.grab_y;
4388 if (start != end || y1 != y2) {
4390 double x1 = frame_to_pixel (start);
4391 double x2 = frame_to_pixel (end);
4393 rubberband_rect->property_x1() = x1;
4394 rubberband_rect->property_y1() = y1;
4395 rubberband_rect->property_x2() = x2;
4396 rubberband_rect->property_y2() = y2;
4398 rubberband_rect->show();
4399 rubberband_rect->raise_to_top();
4401 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4402 drag_info.first_move = false;
4404 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4409 Editor::end_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event)
4411 if (!drag_info.first_move) {
4413 drag_rubberband_select (item, event);
4416 if (drag_info.current_pointer_y < drag_info.grab_y) {
4417 y1 = drag_info.current_pointer_y;
4418 y2 = drag_info.grab_y;
4421 y2 = drag_info.current_pointer_y;
4422 y1 = drag_info.grab_y;
4426 bool add = Keyboard::modifier_state_contains (event->button.state, Keyboard::Shift);
4429 begin_reversible_command (_("select regions"));
4431 if (drag_info.grab_frame < drag_info.last_pointer_frame) {
4432 commit = select_all_within (drag_info.grab_frame, drag_info.last_pointer_frame, y1, y2, add);
4434 commit = select_all_within (drag_info.last_pointer_frame, drag_info.grab_frame, y1, y2, add);
4438 commit_reversible_command ();
4442 selection->clear_audio_regions();
4443 selection->clear_points ();
4444 selection->clear_lines ();
4447 rubberband_rect->hide();
4452 Editor::mouse_rename_region (ArdourCanvas::Item* item, GdkEvent* event)
4454 using namespace Gtkmm2ext;
4456 ArdourPrompter prompter (false);
4458 prompter.set_prompt (_("Name for region:"));
4459 prompter.set_initial_text (clicked_regionview->region.name());
4460 prompter.show_all ();
4461 switch (prompter.run ()) {
4462 case GTK_RESPONSE_ACCEPT:
4464 prompter.get_result(str);
4467 clicked_regionview->region.set_name (str);
4475 Editor::start_time_fx (ArdourCanvas::Item* item, GdkEvent* event)
4477 drag_info.item = item;
4478 drag_info.motion_callback = &Editor::time_fx_motion;
4479 drag_info.finished_callback = &Editor::end_time_fx;
4483 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4487 Editor::time_fx_motion (ArdourCanvas::Item *item, GdkEvent* event)
4489 AudioRegionView* rv = clicked_regionview;
4491 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4492 snap_to (drag_info.current_pointer_frame);
4495 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) {
4499 if (drag_info.current_pointer_frame > rv->region.position()) {
4500 rv->get_time_axis_view().show_timestretch (rv->region.position(), drag_info.current_pointer_frame);
4503 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4504 drag_info.first_move = false;
4506 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4510 Editor::end_time_fx (ArdourCanvas::Item* item, GdkEvent* event)
4512 clicked_regionview->get_time_axis_view().hide_timestretch ();
4514 if (drag_info.first_move) {
4518 jack_nframes_t newlen = drag_info.last_pointer_frame - clicked_regionview->region.position();
4519 float percentage = (float) ((double) newlen - (double) clicked_regionview->region.length()) / ((double) newlen) * 100.0f;
4521 begin_reversible_command (_("timestretch"));
4523 if (run_timestretch (selection->audio_regions, percentage) == 0) {
4524 session->commit_reversible_command ();
4529 Editor::mouse_brush_insert_region (AudioRegionView* rv, jack_nframes_t pos)
4531 /* no brushing without a useful snap setting */
4533 switch (snap_mode) {
4535 return; /* can't work because it allows region to be placed anywhere */
4540 switch (snap_type) {
4543 case SnapToEditCursor:
4550 /* don't brush a copy over the original */
4552 if (pos == rv->region.position()) {
4556 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&rv->get_time_axis_view());
4558 if (atv == 0 || !atv->is_audio_track()) {
4562 Playlist* playlist = atv->playlist();
4563 double speed = atv->get_diskstream()->speed();
4565 session->add_undo (playlist->get_memento());
4566 playlist->add_region (*(new AudioRegion (rv->region)), (jack_nframes_t) (pos * speed));
4567 session->add_redo_no_execute (playlist->get_memento());
4569 // playlist is frozen, so we have to update manually
4571 playlist->StateChanged (Change (~0)); /* EMIT SIGNAL */
4575 Editor::track_height_step_timeout ()
4578 struct timeval delta;
4580 gettimeofday (&now, 0);
4581 timersub (&now, &last_track_height_step_timestamp, &delta);
4583 if (delta.tv_sec * 1000000 + delta.tv_usec > 250000) { /* milliseconds */
4584 current_stepping_trackview = 0;