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/audio_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;
67 using namespace Editing;
70 Editor::event_frame (GdkEvent* event, double* pcx, double* pcy)
84 switch (event->type) {
85 case GDK_BUTTON_RELEASE:
86 case GDK_BUTTON_PRESS:
87 case GDK_2BUTTON_PRESS:
88 case GDK_3BUTTON_PRESS:
89 track_canvas.w2c(event->button.x, event->button.y, *pcx, *pcy);
91 case GDK_MOTION_NOTIFY:
92 track_canvas.w2c(event->motion.x, event->motion.y, *pcx, *pcy);
94 case GDK_ENTER_NOTIFY:
95 case GDK_LEAVE_NOTIFY:
96 track_canvas.w2c(event->crossing.x, event->crossing.y, *pcx, *pcy);
100 // track_canvas.w2c(event->key.x, event->key.y, *pcx, *pcy);
103 warning << string_compose (_("Editor::event_frame() used on unhandled event type %1"), event->type) << endmsg;
107 /* note that pixel_to_frame() never returns less than zero, so even if the pixel
108 position is negative (as can be the case with motion events in particular),
109 the frame location is always positive.
112 return pixel_to_frame (*pcx);
116 Editor::mouse_mode_toggled (MouseMode m)
118 if (ignore_mouse_mode_toggle) {
124 if (mouse_select_button.get_active()) {
130 if (mouse_move_button.get_active()) {
136 if (mouse_gain_button.get_active()) {
142 if (mouse_zoom_button.get_active()) {
148 if (mouse_timefx_button.get_active()) {
154 if (mouse_audition_button.get_active()) {
165 Editor::set_mouse_mode (MouseMode m, bool force)
167 if (drag_info.item) {
171 if (!force && m == mouse_mode) {
179 if (mouse_mode != MouseRange) {
181 /* in all modes except range, hide the range selection,
182 show the object (region) selection.
185 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
186 (*i)->set_should_show_selection (true);
188 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
189 (*i)->hide_selection ();
195 in range mode,show the range selection.
198 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
199 if ((*i)->get_selected()) {
200 (*i)->show_selection (selection->time);
205 /* XXX the hack of unsetting all other buttongs should go
206 away once GTK2 allows us to use regular radio buttons drawn like
207 normal buttons, rather than my silly GroupedButton hack.
210 ignore_mouse_mode_toggle = true;
212 switch (mouse_mode) {
214 mouse_select_button.set_active (true);
215 current_canvas_cursor = selector_cursor;
219 mouse_move_button.set_active (true);
220 current_canvas_cursor = grabber_cursor;
224 mouse_gain_button.set_active (true);
225 current_canvas_cursor = cross_hair_cursor;
229 mouse_zoom_button.set_active (true);
230 current_canvas_cursor = zoom_cursor;
234 mouse_timefx_button.set_active (true);
235 current_canvas_cursor = time_fx_cursor; // just use playhead
239 mouse_audition_button.set_active (true);
240 current_canvas_cursor = speaker_cursor;
244 ignore_mouse_mode_toggle = false;
247 track_canvas.get_window()->set_cursor(*current_canvas_cursor);
252 Editor::step_mouse_mode (bool next)
254 switch (current_mouse_mode()) {
256 if (next) set_mouse_mode (MouseRange);
257 else set_mouse_mode (MouseTimeFX);
261 if (next) set_mouse_mode (MouseZoom);
262 else set_mouse_mode (MouseObject);
266 if (next) set_mouse_mode (MouseGain);
267 else set_mouse_mode (MouseRange);
271 if (next) set_mouse_mode (MouseTimeFX);
272 else set_mouse_mode (MouseZoom);
276 if (next) set_mouse_mode (MouseAudition);
277 else set_mouse_mode (MouseGain);
281 if (next) set_mouse_mode (MouseObject);
282 else set_mouse_mode (MouseTimeFX);
288 Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
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.
299 note: not dbl-click or triple-click
302 if (((mouse_mode != MouseObject) &&
303 (mouse_mode != MouseAudition || item_type != RegionItem) &&
304 (mouse_mode != MouseTimeFX || item_type != RegionItem)) ||
305 (event->type != GDK_BUTTON_PRESS && event->type != GDK_BUTTON_RELEASE || event->button.button > 3)) {
310 Selection::Operation op = Keyboard::selection_type (event->button.state);
311 bool press = (event->type == GDK_BUTTON_PRESS);
313 begin_reversible_command (_("select on click"));
317 c1 = set_selected_track_from_click (press, op, true, true);
318 c2 = set_selected_regionview_from_click (press, op, true);
322 case AudioRegionViewNameHighlight:
323 case AudioRegionViewName:
324 c1 = set_selected_track_from_click (press, op, true, true);
325 c2 = set_selected_regionview_from_click (press, op, true);
329 case GainAutomationControlPointItem:
330 case PanAutomationControlPointItem:
331 case RedirectAutomationControlPointItem:
332 c1 = set_selected_track_from_click (press, op, true, true);
333 c2 = set_selected_control_point_from_click (press, op, false);
338 commit = set_selected_track_from_click (press, op, true, true);
341 case AutomationTrackItem:
342 commit = set_selected_track_from_click (press, op, true, true);
349 #define SELECT_TRACK_FROM_CANVAS_IN_RANGE_MODE
350 #ifdef SELECT_TRACK_FROM_CANVAS_IN_RANGE_MODE
351 /* in range mode, button 1/2/3 press potentially selects a track */
353 if (mouse_mode == MouseRange &&
354 event->type == GDK_BUTTON_PRESS &&
355 event->button.button <= 3) {
360 case AutomationTrackItem:
361 commit = set_selected_track_from_click (press, op, true, true);
370 commit_reversible_command ();
375 Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
377 jack_nframes_t where = event_frame (event, 0, 0);
379 track_canvas.grab_focus();
381 if (session && session->actively_recording()) {
385 button_selection (item, event, item_type);
387 if (drag_info.item == 0 &&
388 (Keyboard::is_delete_event (&event->button) ||
389 Keyboard::is_context_menu_event (&event->button) ||
390 Keyboard::is_edit_event (&event->button))) {
392 /* handled by button release */
396 switch (event->button.button) {
399 if (event->type == GDK_BUTTON_PRESS) {
401 if (drag_info.item) {
402 drag_info.item->ungrab (event->button.time);
405 /* single mouse clicks on any of these item types operate
406 independent of mouse mode, mostly because they are
407 not on the main track canvas or because we want
413 case PlayheadCursorItem:
414 start_cursor_grab (item, event);
418 if (Keyboard::modifier_state_equals (event->button.state,
419 Keyboard::ModifierMask(Keyboard::Control|Keyboard::Shift))) {
420 hide_marker (item, event);
422 start_marker_grab (item, event);
426 case TempoMarkerItem:
427 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
428 start_tempo_marker_copy_grab (item, event);
430 start_tempo_marker_grab (item, event);
434 case MeterMarkerItem:
435 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
436 start_meter_marker_copy_grab (item, event);
438 start_meter_marker_grab (item, event);
448 case RangeMarkerBarItem:
449 start_range_markerbar_op (item, event, CreateRangeMarker);
453 case TransportMarkerBarItem:
454 start_range_markerbar_op (item, event, CreateTransportMarker);
463 switch (mouse_mode) {
466 case StartSelectionTrimItem:
467 start_selection_op (item, event, SelectionStartTrim);
470 case EndSelectionTrimItem:
471 start_selection_op (item, event, SelectionEndTrim);
475 if (Keyboard::modifier_state_contains
476 (event->button.state, Keyboard::ModifierMask(Keyboard::Alt))) {
477 // contains and not equals because I can't use alt as a modifier alone.
478 start_selection_grab (item, event);
479 } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
480 /* grab selection for moving */
481 start_selection_op (item, event, SelectionMove);
484 /* this was debated, but decided the more common action was to
485 make a new selection */
486 start_selection_op (item, event, CreateSelection);
491 start_selection_op (item, event, CreateSelection);
497 if (Keyboard::modifier_state_contains (event->button.state,
498 Keyboard::ModifierMask(Keyboard::Control|Keyboard::Alt))
499 && event->type == GDK_BUTTON_PRESS) {
501 start_rubberband_select (item, event);
503 } else if (event->type == GDK_BUTTON_PRESS) {
506 case FadeInHandleItem:
507 start_fade_in_grab (item, event);
510 case FadeOutHandleItem:
511 start_fade_out_grab (item, event);
515 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
516 start_region_copy_grab (item, event);
517 } else if (Keyboard::the_keyboard().key_is_down (GDK_b)) {
518 start_region_brush_grab (item, event);
520 start_region_grab (item, event);
524 case AudioRegionViewNameHighlight:
525 start_trim (item, event);
529 case AudioRegionViewName:
530 /* rename happens on edit clicks */
531 start_trim (clicked_regionview->get_name_highlight(), event);
535 case GainAutomationControlPointItem:
536 case PanAutomationControlPointItem:
537 case RedirectAutomationControlPointItem:
538 start_control_point_grab (item, event);
542 case GainAutomationLineItem:
543 case PanAutomationLineItem:
544 case RedirectAutomationLineItem:
545 start_line_grab_from_line (item, event);
550 case AutomationTrackItem:
551 start_rubberband_select (item, event);
554 /* <CMT Additions> */
555 case ImageFrameHandleStartItem:
556 imageframe_start_handle_op(item, event) ;
559 case ImageFrameHandleEndItem:
560 imageframe_end_handle_op(item, event) ;
563 case MarkerViewHandleStartItem:
564 markerview_item_start_handle_op(item, event) ;
567 case MarkerViewHandleEndItem:
568 markerview_item_end_handle_op(item, event) ;
571 /* </CMT Additions> */
573 /* <CMT Additions> */
575 start_markerview_grab(item, event) ;
578 start_imageframe_grab(item, event) ;
580 /* </CMT Additions> */
596 // start_line_grab_from_regionview (item, event);
599 case GainControlPointItem:
600 start_control_point_grab (item, event);
604 start_line_grab_from_line (item, event);
607 case GainAutomationControlPointItem:
608 case PanAutomationControlPointItem:
609 case RedirectAutomationControlPointItem:
610 start_control_point_grab (item, event);
621 case GainAutomationControlPointItem:
622 case PanAutomationControlPointItem:
623 case RedirectAutomationControlPointItem:
624 start_control_point_grab (item, event);
627 case GainAutomationLineItem:
628 case PanAutomationLineItem:
629 case RedirectAutomationLineItem:
630 start_line_grab_from_line (item, event);
634 // XXX need automation mode to identify which
636 // start_line_grab_from_regionview (item, event);
646 if (event->type == GDK_BUTTON_PRESS) {
647 start_mouse_zoom (item, event);
654 if (item_type == RegionItem) {
655 start_time_fx (item, event);
660 /* handled in release */
669 switch (mouse_mode) {
671 if (event->type == GDK_BUTTON_PRESS) {
674 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
675 start_region_copy_grab (item, event);
677 start_region_grab (item, event);
681 case GainAutomationControlPointItem:
682 case PanAutomationControlPointItem:
683 case RedirectAutomationControlPointItem:
684 start_control_point_grab (item, event);
695 case AudioRegionViewNameHighlight:
696 start_trim (item, event);
700 case AudioRegionViewName:
701 start_trim (clicked_regionview->get_name_highlight(), event);
712 if (event->type == GDK_BUTTON_PRESS) {
713 /* relax till release */
720 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
721 temporal_zoom_session();
723 temporal_zoom_to_frame (true, event_frame(event));
738 switch (mouse_mode) {
740 //temporal_zoom_to_frame (true, where);
741 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
742 temporal_zoom_to_frame (true, where);
745 temporal_zoom_step (true);
750 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::Alt))) {
751 scroll_backward (0.6f);
754 else if (Keyboard::no_modifier_keys_pressed (&event->button)) {
755 scroll_tracks_up_line ();
757 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
758 if (clicked_trackview) {
759 if (!current_stepping_trackview) {
760 step_timeout = Glib::signal_timeout().connect (mem_fun(*this, &Editor::track_height_step_timeout), 500);
761 current_stepping_trackview = clicked_trackview;
763 gettimeofday (&last_track_height_step_timestamp, 0);
764 current_stepping_trackview->step_height (true);
767 else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
768 temporal_zoom_to_frame (true, where);
775 switch (mouse_mode) {
777 // temporal_zoom_to_frame (false, where);
778 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
779 temporal_zoom_to_frame (false, where);
782 temporal_zoom_step (false);
787 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::Alt))) {
788 scroll_forward (0.6f);
791 else if (Keyboard::no_modifier_keys_pressed (&event->button)) {
792 scroll_tracks_down_line ();
794 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
795 if (clicked_trackview) {
796 if (!current_stepping_trackview) {
797 step_timeout = Glib::signal_timeout().connect (mem_fun(*this, &Editor::track_height_step_timeout), 500);
798 current_stepping_trackview = clicked_trackview;
800 gettimeofday (&last_track_height_step_timestamp, 0);
801 current_stepping_trackview->step_height (false);
803 } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
804 temporal_zoom_to_frame (false, where);
819 Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
821 jack_nframes_t where = event_frame (event, 0, 0);
823 /* no action if we're recording */
825 if (session && session->actively_recording()) {
829 /* first, see if we're finishing a drag ... */
831 if (drag_info.item) {
832 if (end_grab (item, event)) {
833 /* grab dragged, so do nothing else */
838 button_selection (item, event, item_type);
840 /* edit events get handled here */
842 if (drag_info.item == 0 && Keyboard::is_edit_event (&event->button)) {
848 case TempoMarkerItem:
849 edit_tempo_marker (item);
852 case MeterMarkerItem:
853 edit_meter_marker (item);
856 case AudioRegionViewName:
857 if (clicked_regionview->name_active()) {
858 return mouse_rename_region (item, event);
868 /* context menu events get handled here */
870 if (Keyboard::is_context_menu_event (&event->button)) {
872 if (drag_info.item == 0) {
874 /* no matter which button pops up the context menu, tell the menu
875 widget to use button 1 to drive menu selection.
880 case FadeInHandleItem:
882 case FadeOutHandleItem:
883 popup_fade_context_menu (1, event->button.time, item, item_type);
887 popup_track_context_menu (1, event->button.time, item_type, false, where);
891 case AudioRegionViewNameHighlight:
892 case AudioRegionViewName:
893 popup_track_context_menu (1, event->button.time, item_type, false, where);
897 popup_track_context_menu (1, event->button.time, item_type, true, where);
900 case AutomationTrackItem:
901 popup_track_context_menu (1, event->button.time, item_type, false, where);
905 case RangeMarkerBarItem:
906 case TransportMarkerBarItem:
909 popup_ruler_menu (pixel_to_frame(event->button.x), item_type);
913 marker_context_menu (&event->button, item);
916 case TempoMarkerItem:
917 tm_marker_context_menu (&event->button, item);
920 case MeterMarkerItem:
921 tm_marker_context_menu (&event->button, item);
924 case CrossfadeViewItem:
925 popup_track_context_menu (1, event->button.time, item_type, false, where);
928 /* <CMT Additions> */
930 popup_imageframe_edit_menu(1, event->button.time, item, true) ;
932 case ImageFrameTimeAxisItem:
933 popup_imageframe_edit_menu(1, event->button.time, item, false) ;
936 popup_marker_time_axis_edit_menu(1, event->button.time, item, true) ;
938 case MarkerTimeAxisItem:
939 popup_marker_time_axis_edit_menu(1, event->button.time, item, false) ;
941 /* <CMT Additions> */
952 /* delete events get handled here */
954 if (drag_info.item == 0 && Keyboard::is_delete_event (&event->button)) {
957 case TempoMarkerItem:
958 remove_tempo_marker (item);
961 case MeterMarkerItem:
962 remove_meter_marker (item);
966 remove_marker (*item, event);
970 if (mouse_mode == MouseObject) {
971 remove_clicked_region ();
975 case GainControlPointItem:
976 if (mouse_mode == MouseGain) {
977 remove_gain_control_point (item, event);
981 case GainAutomationControlPointItem:
982 case PanAutomationControlPointItem:
983 case RedirectAutomationControlPointItem:
984 remove_control_point (item, event);
993 switch (event->button.button) {
997 /* see comments in button_press_handler */
999 case PlayheadCursorItem:
1002 case GainAutomationLineItem:
1003 case PanAutomationLineItem:
1004 case RedirectAutomationLineItem:
1005 case StartSelectionTrimItem:
1006 case EndSelectionTrimItem:
1010 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1011 snap_to (where, 0, true);
1013 mouse_add_new_marker (where);
1017 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1020 mouse_add_new_tempo_event (where);
1024 mouse_add_new_meter_event (pixel_to_frame (event->button.x));
1032 switch (mouse_mode) {
1034 switch (item_type) {
1035 case AutomationTrackItem:
1036 dynamic_cast<AutomationTimeAxisView*>(clicked_trackview)->add_automation_event
1050 switch (item_type) {
1052 clicked_regionview->add_gain_point_event (item, event);
1056 case AutomationTrackItem:
1057 dynamic_cast<AutomationTimeAxisView*>(clicked_trackview)->
1058 add_automation_event (item, event, where, event->button.y);
1067 switch (item_type) {
1069 audition_selected_region ();
1086 switch (mouse_mode) {
1089 switch (item_type) {
1091 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
1093 } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::ModifierMask (Keyboard::Shift|Keyboard::Alt))) {
1096 // Button2 click is unused
1109 // x_style_paste (where, 1.0);
1129 Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
1135 switch (item_type) {
1136 case GainControlPointItem:
1137 if (mouse_mode == MouseGain) {
1138 cp = static_cast<ControlPoint*>(item->get_data ("control_point"));
1139 cp->set_visible (true);
1143 at_y = cp->get_y ();
1144 cp->item->i2w (at_x, at_y);
1148 fraction = 1.0 - (cp->get_y() / cp->line.height());
1150 set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y);
1151 show_verbose_canvas_cursor ();
1153 if (is_drawable()) {
1154 track_canvas.get_window()->set_cursor (*fader_cursor);
1159 case GainAutomationControlPointItem:
1160 case PanAutomationControlPointItem:
1161 case RedirectAutomationControlPointItem:
1162 cp = static_cast<ControlPoint*>(item->get_data ("control_point"));
1163 cp->set_visible (true);
1167 at_y = cp->get_y ();
1168 cp->item->i2w (at_x, at_y);
1172 fraction = 1.0 - (cp->get_y() / cp->line.height());
1174 set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y);
1175 show_verbose_canvas_cursor ();
1177 if (is_drawable()) {
1178 track_canvas.get_window()->set_cursor (*fader_cursor);
1183 if (mouse_mode == MouseGain) {
1184 ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
1186 line->property_fill_color_rgba() = color_map[cEnteredGainLine];
1187 if (is_drawable()) {
1188 track_canvas.get_window()->set_cursor (*fader_cursor);
1193 case GainAutomationLineItem:
1194 case RedirectAutomationLineItem:
1195 case PanAutomationLineItem:
1197 ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
1199 line->property_fill_color_rgba() = color_map[cEnteredAutomationLine];
1201 if (is_drawable()) {
1202 track_canvas.get_window()->set_cursor (*fader_cursor);
1206 case AudioRegionViewNameHighlight:
1207 if (is_drawable() && mouse_mode == MouseObject) {
1208 track_canvas.get_window()->set_cursor (*trimmer_cursor);
1212 case StartSelectionTrimItem:
1213 case EndSelectionTrimItem:
1214 /* <CMT Additions> */
1215 case ImageFrameHandleStartItem:
1216 case ImageFrameHandleEndItem:
1217 case MarkerViewHandleStartItem:
1218 case MarkerViewHandleEndItem:
1219 /* </CMT Additions> */
1221 if (is_drawable()) {
1222 track_canvas.get_window()->set_cursor (*trimmer_cursor);
1226 case EditCursorItem:
1227 case PlayheadCursorItem:
1228 if (is_drawable()) {
1229 track_canvas.get_window()->set_cursor (*grabber_cursor);
1233 case AudioRegionViewName:
1235 /* when the name is not an active item, the entire name highlight is for trimming */
1237 if (!reinterpret_cast<AudioRegionView *> (item->get_data ("regionview"))->name_active()) {
1238 if (mouse_mode == MouseObject && is_drawable()) {
1239 track_canvas.get_window()->set_cursor (*trimmer_cursor);
1245 case AutomationTrackItem:
1246 if (is_drawable()) {
1247 Gdk::Cursor *cursor;
1248 switch (mouse_mode) {
1250 cursor = selector_cursor;
1253 cursor = zoom_cursor;
1256 cursor = cross_hair_cursor;
1260 track_canvas.get_window()->set_cursor (*cursor);
1262 AutomationTimeAxisView* atv;
1263 if ((atv = static_cast<AutomationTimeAxisView*>(item->get_data ("trackview"))) != 0) {
1264 clear_entered_track = false;
1265 set_entered_track (atv);
1271 case RangeMarkerBarItem:
1272 case TransportMarkerBarItem:
1275 if (is_drawable()) {
1276 time_canvas.get_window()->set_cursor (*timebar_cursor);
1281 if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
1284 marker->set_color_rgba (color_map[cEnteredMarker]);
1286 case MeterMarkerItem:
1287 case TempoMarkerItem:
1288 if (is_drawable()) {
1289 time_canvas.get_window()->set_cursor (*timebar_cursor);
1292 case FadeInHandleItem:
1293 case FadeOutHandleItem:
1294 if (mouse_mode == MouseObject) {
1295 ArdourCanvas::SimpleRect *rect = dynamic_cast<ArdourCanvas::SimpleRect *> (item);
1297 rect->property_fill_color_rgba() = 0;
1298 rect->property_outline_pixels() = 1;
1307 /* second pass to handle entered track status in a comprehensible way.
1310 switch (item_type) {
1312 case GainAutomationLineItem:
1313 case RedirectAutomationLineItem:
1314 case PanAutomationLineItem:
1315 case GainControlPointItem:
1316 case GainAutomationControlPointItem:
1317 case PanAutomationControlPointItem:
1318 case RedirectAutomationControlPointItem:
1319 /* these do not affect the current entered track state */
1320 clear_entered_track = false;
1323 case AutomationTrackItem:
1324 /* handled above already */
1328 set_entered_track (0);
1336 Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
1342 AudioRegionView* rv;
1345 switch (item_type) {
1346 case GainControlPointItem:
1347 case GainAutomationControlPointItem:
1348 case PanAutomationControlPointItem:
1349 case RedirectAutomationControlPointItem:
1350 cp = reinterpret_cast<ControlPoint*>(item->get_data ("control_point"));
1351 if (cp->line.npoints() > 1) {
1352 if (!cp->selected) {
1353 cp->set_visible (false);
1357 if (is_drawable()) {
1358 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
1361 hide_verbose_canvas_cursor ();
1364 case AudioRegionViewNameHighlight:
1365 case StartSelectionTrimItem:
1366 case EndSelectionTrimItem:
1367 case EditCursorItem:
1368 case PlayheadCursorItem:
1369 /* <CMT Additions> */
1370 case ImageFrameHandleStartItem:
1371 case ImageFrameHandleEndItem:
1372 case MarkerViewHandleStartItem:
1373 case MarkerViewHandleEndItem:
1374 /* </CMT Additions> */
1375 if (is_drawable()) {
1376 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
1381 case GainAutomationLineItem:
1382 case RedirectAutomationLineItem:
1383 case PanAutomationLineItem:
1384 al = reinterpret_cast<AutomationLine*> (item->get_data ("line"));
1386 ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
1388 line->property_fill_color_rgba() = al->get_line_color();
1390 if (is_drawable()) {
1391 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
1395 case AudioRegionViewName:
1396 /* see enter_handler() for notes */
1397 if (!reinterpret_cast<AudioRegionView *> (item->get_data ("regionview"))->name_active()) {
1398 if (is_drawable() && mouse_mode == MouseObject) {
1399 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
1404 case RangeMarkerBarItem:
1405 case TransportMarkerBarItem:
1409 if (is_drawable()) {
1410 time_canvas.get_window()->set_cursor (*timebar_cursor);
1415 if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
1418 loc = find_location_from_marker (marker, is_start);
1419 if (loc) location_flags_changed (loc, this);
1421 case MeterMarkerItem:
1422 case TempoMarkerItem:
1424 if (is_drawable()) {
1425 time_canvas.get_window()->set_cursor (*timebar_cursor);
1430 case FadeInHandleItem:
1431 case FadeOutHandleItem:
1432 rv = static_cast<AudioRegionView*>(item->get_data ("regionview"));
1434 ArdourCanvas::SimpleRect *rect = dynamic_cast<ArdourCanvas::SimpleRect *> (item);
1436 rect->property_fill_color_rgba() = rv->get_fill_color();
1437 rect->property_outline_pixels() = 0;
1442 case AutomationTrackItem:
1443 if (is_drawable()) {
1444 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
1445 clear_entered_track = true;
1446 Glib::signal_idle().connect (mem_fun(*this, &Editor::left_automation_track));
1458 Editor::left_automation_track ()
1460 if (clear_entered_track) {
1461 set_entered_track (0);
1462 clear_entered_track = false;
1468 Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type, bool from_autoscroll)
1472 /* We call this so that MOTION_NOTIFY events continue to be
1473 delivered to the canvas. We need to do this because we set
1474 Gdk::POINTER_MOTION_HINT_MASK on the canvas. This reduces
1475 the density of the events, at the expense of a round-trip
1476 to the server. Given that this will mostly occur on cases
1477 where DISPLAY = :0.0, and given the cost of what the motion
1478 event might do, its a good tradeoff.
1481 track_canvas.get_pointer (x, y);
1483 if (current_stepping_trackview) {
1484 /* don't keep the persistent stepped trackview if the mouse moves */
1485 current_stepping_trackview = 0;
1486 step_timeout.disconnect ();
1489 if (session && session->actively_recording()) {
1490 /* Sorry. no dragging stuff around while we record */
1494 drag_info.item_type = item_type;
1495 drag_info.current_pointer_frame = event_frame (event, &drag_info.current_pointer_x,
1496 &drag_info.current_pointer_y);
1498 if (!from_autoscroll && drag_info.item) {
1499 /* item != 0 is the best test i can think of for dragging.
1501 if (!drag_info.move_threshold_passed) {
1503 drag_info.move_threshold_passed = (abs ((int) (drag_info.current_pointer_x - drag_info.grab_x)) > 4);
1505 // and change the initial grab loc/frame if this drag info wants us to
1507 if (drag_info.want_move_threshold && drag_info.move_threshold_passed) {
1508 drag_info.grab_frame = drag_info.current_pointer_frame;
1509 drag_info.grab_x = drag_info.current_pointer_x;
1510 drag_info.grab_y = drag_info.current_pointer_y;
1511 drag_info.last_pointer_frame = drag_info.grab_frame;
1512 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
1517 switch (item_type) {
1518 case PlayheadCursorItem:
1519 case EditCursorItem:
1521 case GainControlPointItem:
1522 case RedirectAutomationControlPointItem:
1523 case GainAutomationControlPointItem:
1524 case PanAutomationControlPointItem:
1525 case TempoMarkerItem:
1526 case MeterMarkerItem:
1527 case AudioRegionViewNameHighlight:
1528 case StartSelectionTrimItem:
1529 case EndSelectionTrimItem:
1532 case RedirectAutomationLineItem:
1533 case GainAutomationLineItem:
1534 case PanAutomationLineItem:
1535 case FadeInHandleItem:
1536 case FadeOutHandleItem:
1537 /* <CMT Additions> */
1538 case ImageFrameHandleStartItem:
1539 case ImageFrameHandleEndItem:
1540 case MarkerViewHandleStartItem:
1541 case MarkerViewHandleEndItem:
1542 /* </CMT Additions> */
1543 if (drag_info.item && (event->motion.state & Gdk::BUTTON1_MASK ||
1544 (event->motion.state & Gdk::BUTTON2_MASK))) {
1545 if (!from_autoscroll) {
1546 maybe_autoscroll (event);
1548 (this->*(drag_info.motion_callback)) (item, event);
1557 switch (mouse_mode) {
1562 if (drag_info.item && (event->motion.state & GDK_BUTTON1_MASK ||
1563 (event->motion.state & GDK_BUTTON2_MASK))) {
1564 if (!from_autoscroll) {
1565 maybe_autoscroll (event);
1567 (this->*(drag_info.motion_callback)) (item, event);
1578 track_canvas_motion (event);
1579 // drag_info.last_pointer_frame = drag_info.current_pointer_frame;
1587 Editor::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
1589 if (drag_info.item == 0) {
1590 fatal << _("programming error: start_grab called without drag item") << endmsg;
1596 cursor = grabber_cursor;
1599 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
1601 if (event->button.button == 2) {
1602 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Alt)) {
1603 drag_info.y_constrained = true;
1604 drag_info.x_constrained = false;
1606 drag_info.y_constrained = false;
1607 drag_info.x_constrained = true;
1610 drag_info.x_constrained = false;
1611 drag_info.y_constrained = false;
1614 drag_info.grab_frame = event_frame(event, &drag_info.grab_x, &drag_info.grab_y);
1615 drag_info.last_pointer_frame = drag_info.grab_frame;
1616 drag_info.current_pointer_frame = drag_info.grab_frame;
1617 drag_info.current_pointer_x = drag_info.grab_x;
1618 drag_info.current_pointer_y = drag_info.grab_y;
1619 drag_info.cumulative_x_drag = 0;
1620 drag_info.cumulative_y_drag = 0;
1621 drag_info.first_move = true;
1622 drag_info.move_threshold_passed = false;
1623 drag_info.want_move_threshold = false;
1624 drag_info.pointer_frame_offset = 0;
1625 drag_info.brushing = false;
1626 drag_info.copied_location = 0;
1628 drag_info.item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
1630 event->button.time);
1632 if (session && session->transport_rolling()) {
1633 drag_info.was_rolling = true;
1635 drag_info.was_rolling = false;
1638 switch (snap_type) {
1639 case SnapToRegionStart:
1640 case SnapToRegionEnd:
1641 case SnapToRegionSync:
1642 case SnapToRegionBoundary:
1643 build_region_boundary_cache ();
1651 Editor::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t time)
1653 drag_info.item->ungrab (0);
1654 drag_info.item = new_item;
1657 cursor = grabber_cursor;
1660 drag_info.item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK, *cursor, time);
1664 Editor::end_grab (ArdourCanvas::Item* item, GdkEvent* event)
1666 bool did_drag = false;
1668 stop_canvas_autoscroll ();
1670 if (drag_info.item == 0) {
1674 drag_info.item->ungrab (event->button.time);
1676 if (drag_info.finished_callback) {
1677 (this->*(drag_info.finished_callback)) (item, event);
1680 did_drag = !drag_info.first_move;
1682 hide_verbose_canvas_cursor();
1685 drag_info.copy = false;
1686 drag_info.motion_callback = 0;
1687 drag_info.finished_callback = 0;
1688 drag_info.last_trackview = 0;
1689 drag_info.last_frame_position = 0;
1690 drag_info.grab_frame = 0;
1691 drag_info.last_pointer_frame = 0;
1692 drag_info.current_pointer_frame = 0;
1693 drag_info.brushing = false;
1695 if (drag_info.copied_location) {
1696 delete drag_info.copied_location;
1697 drag_info.copied_location = 0;
1704 Editor::set_edit_cursor (GdkEvent* event)
1706 jack_nframes_t pointer_frame = event_frame (event);
1708 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1709 if (snap_type != SnapToEditCursor) {
1710 snap_to (pointer_frame);
1714 edit_cursor->set_position (pointer_frame);
1715 edit_cursor_clock.set (pointer_frame);
1719 Editor::set_playhead_cursor (GdkEvent* event)
1721 jack_nframes_t pointer_frame = event_frame (event);
1723 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1724 snap_to (pointer_frame);
1728 session->request_locate (pointer_frame, session->transport_rolling());
1733 Editor::start_fade_in_grab (ArdourCanvas::Item* item, GdkEvent* event)
1735 drag_info.item = item;
1736 drag_info.motion_callback = &Editor::fade_in_drag_motion_callback;
1737 drag_info.finished_callback = &Editor::fade_in_drag_finished_callback;
1741 if ((drag_info.data = (item->get_data ("regionview"))) == 0) {
1742 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1746 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1748 drag_info.pointer_frame_offset = drag_info.grab_frame - ((jack_nframes_t) arv->region.fade_in().back()->when + arv->region.position());
1752 Editor::fade_in_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
1754 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1756 jack_nframes_t fade_length;
1758 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1759 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1765 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1769 if (pos < (arv->region.position() + 64)) {
1770 fade_length = 64; // this should be a minimum defined somewhere
1771 } else if (pos > arv->region.last_frame()) {
1772 fade_length = arv->region.length();
1774 fade_length = pos - arv->region.position();
1777 arv->reset_fade_in_shape_width (fade_length);
1779 show_verbose_duration_cursor (arv->region.position(), arv->region.position() + fade_length, 10);
1781 drag_info.first_move = false;
1785 Editor::fade_in_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
1787 if (drag_info.first_move) return;
1789 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1791 jack_nframes_t fade_length;
1793 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1794 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1800 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1804 if (pos < (arv->region.position() + 64)) {
1805 fade_length = 64; // this should be a minimum defined somewhere
1807 else if (pos > arv->region.last_frame()) {
1808 fade_length = arv->region.length();
1811 fade_length = pos - arv->region.position();
1814 begin_reversible_command (_("change fade in length"));
1815 session->add_undo (arv->region.get_memento());
1816 arv->region.set_fade_in_length (fade_length);
1817 session->add_redo_no_execute (arv->region.get_memento());
1818 commit_reversible_command ();
1819 fade_in_drag_motion_callback (item, event);
1823 Editor::start_fade_out_grab (ArdourCanvas::Item* item, GdkEvent* event)
1825 drag_info.item = item;
1826 drag_info.motion_callback = &Editor::fade_out_drag_motion_callback;
1827 drag_info.finished_callback = &Editor::fade_out_drag_finished_callback;
1831 if ((drag_info.data = (item->get_data ("regionview"))) == 0) {
1832 fatal << _("programming error: fade out canvas item has no regionview data pointer!") << endmsg;
1836 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1838 drag_info.pointer_frame_offset = drag_info.grab_frame - (arv->region.length() - (jack_nframes_t) arv->region.fade_out().back()->when + arv->region.position());
1842 Editor::fade_out_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
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 arv->reset_fade_out_shape_width (fade_length);
1871 show_verbose_duration_cursor (arv->region.last_frame() - fade_length, arv->region.last_frame(), 10);
1873 drag_info.first_move = false;
1877 Editor::fade_out_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
1879 if (drag_info.first_move) return;
1881 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1883 jack_nframes_t fade_length;
1885 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1886 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1892 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1896 if (pos > (arv->region.last_frame() - 64)) {
1897 fade_length = 64; // this should really be a minimum fade defined somewhere
1899 else if (pos < arv->region.position()) {
1900 fade_length = arv->region.length();
1903 fade_length = arv->region.last_frame() - pos;
1906 begin_reversible_command (_("change fade out length"));
1907 session->add_undo (arv->region.get_memento());
1908 arv->region.set_fade_out_length (fade_length);
1909 session->add_redo_no_execute (arv->region.get_memento());
1910 commit_reversible_command ();
1912 fade_out_drag_motion_callback (item, event);
1916 Editor::start_cursor_grab (ArdourCanvas::Item* item, GdkEvent* event)
1918 drag_info.item = item;
1919 drag_info.motion_callback = &Editor::cursor_drag_motion_callback;
1920 drag_info.finished_callback = &Editor::cursor_drag_finished_callback;
1924 if ((drag_info.data = (item->get_data ("cursor"))) == 0) {
1925 fatal << _("programming error: cursor canvas item has no cursor data pointer!") << endmsg;
1929 Cursor* cursor = (Cursor *) drag_info.data;
1931 if (session && cursor == playhead_cursor) {
1932 if (drag_info.was_rolling) {
1933 session->request_stop ();
1937 drag_info.pointer_frame_offset = drag_info.grab_frame - cursor->current_frame;
1939 show_verbose_time_cursor (cursor->current_frame, 10);
1943 Editor::cursor_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
1945 Cursor* cursor = (Cursor *) drag_info.data;
1946 jack_nframes_t adjusted_frame;
1948 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1949 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1955 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1956 if (cursor != edit_cursor || snap_type != SnapToEditCursor) {
1957 snap_to (adjusted_frame);
1961 if (adjusted_frame == drag_info.last_pointer_frame) return;
1963 cursor->set_position (adjusted_frame);
1965 if (cursor == edit_cursor) {
1966 edit_cursor_clock.set (cursor->current_frame);
1969 show_verbose_time_cursor (cursor->current_frame, 10);
1971 drag_info.last_pointer_frame = adjusted_frame;
1972 drag_info.first_move = false;
1976 Editor::cursor_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
1978 if (drag_info.first_move) return;
1980 cursor_drag_motion_callback (item, event);
1982 if (item == &playhead_cursor->canvas_item) {
1984 session->request_locate (playhead_cursor->current_frame, drag_info.was_rolling);
1986 } else if (item == &edit_cursor->canvas_item) {
1987 edit_cursor->set_position (edit_cursor->current_frame);
1988 edit_cursor_clock.set (edit_cursor->current_frame);
1993 Editor::update_marker_drag_item (Location *location)
1995 double x1 = frame_to_pixel (location->start());
1996 double x2 = frame_to_pixel (location->end());
1998 if (location->is_mark()) {
1999 marker_drag_line_points.front().set_x(x1);
2000 marker_drag_line_points.back().set_x(x1);
2001 marker_drag_line->property_points() = marker_drag_line_points;
2004 range_marker_drag_rect->property_x1() = x1;
2005 range_marker_drag_rect->property_x2() = x2;
2010 Editor::start_marker_grab (ArdourCanvas::Item* item, GdkEvent* event)
2014 if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
2015 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
2021 Location *location = find_location_from_marker (marker, is_start);
2023 drag_info.item = item;
2024 drag_info.data = marker;
2025 drag_info.motion_callback = &Editor::marker_drag_motion_callback;
2026 drag_info.finished_callback = &Editor::marker_drag_finished_callback;
2030 drag_info.copied_location = new Location (*location);
2031 drag_info.pointer_frame_offset = drag_info.grab_frame - (is_start ? location->start() : location->end());
2033 update_marker_drag_item (location);
2035 if (location->is_mark()) {
2036 marker_drag_line->show();
2037 marker_drag_line->raise_to_top();
2040 range_marker_drag_rect->show();
2041 range_marker_drag_rect->raise_to_top();
2044 if (is_start) show_verbose_time_cursor (location->start(), 10);
2045 else show_verbose_time_cursor (location->end(), 10);
2049 Editor::marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2051 jack_nframes_t f_delta;
2052 Marker* marker = (Marker *) drag_info.data;
2053 Location *real_location;
2054 Location *copy_location;
2056 bool move_both = false;
2059 jack_nframes_t newframe;
2060 if (drag_info.pointer_frame_offset <= (long) drag_info.current_pointer_frame) {
2061 newframe = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2067 jack_nframes_t next = newframe;
2069 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2070 snap_to (newframe, 0, true);
2073 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) {
2077 /* call this to find out if its the start or end */
2079 real_location = find_location_from_marker (marker, is_start);
2081 /* use the copy that we're "dragging" around */
2083 copy_location = drag_info.copied_location;
2085 f_delta = copy_location->end() - copy_location->start();
2087 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
2091 if (is_start) { // start marker
2094 copy_location->set_start (newframe);
2095 copy_location->set_end (newframe + f_delta);
2096 } else if (newframe < copy_location->end()) {
2097 copy_location->set_start (newframe);
2099 snap_to (next, 1, true);
2100 copy_location->set_end (next);
2101 copy_location->set_start (newframe);
2104 } else { // end marker
2107 copy_location->set_end (newframe);
2108 copy_location->set_start (newframe - f_delta);
2109 } else if (newframe > copy_location->start()) {
2110 copy_location->set_end (newframe);
2112 } else if (newframe > 0) {
2113 snap_to (next, -1, true);
2114 copy_location->set_start (next);
2115 copy_location->set_end (newframe);
2119 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
2120 drag_info.first_move = false;
2122 update_marker_drag_item (copy_location);
2124 LocationMarkers* lm = find_location_markers (real_location);
2125 lm->set_position (copy_location->start(), copy_location->end());
2127 show_verbose_time_cursor (newframe, 10);
2131 Editor::marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2133 if (drag_info.first_move) {
2134 marker_drag_motion_callback (item, event);
2138 Marker* marker = (Marker *) drag_info.data;
2142 begin_reversible_command ( _("move marker") );
2143 session->add_undo( session->locations()->get_memento() );
2145 Location * location = find_location_from_marker (marker, is_start);
2148 location->set (drag_info.copied_location->start(), drag_info.copied_location->end());
2151 session->add_redo_no_execute( session->locations()->get_memento() );
2152 commit_reversible_command ();
2154 marker_drag_line->hide();
2155 range_marker_drag_rect->hide();
2159 Editor::start_meter_marker_grab (ArdourCanvas::Item* item, GdkEvent* event)
2162 MeterMarker* meter_marker;
2164 if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
2165 fatal << _("programming error: meter marker canvas item has no marker object pointer!") << endmsg;
2169 meter_marker = dynamic_cast<MeterMarker*> (marker);
2171 MetricSection& section (meter_marker->meter());
2173 if (!section.movable()) {
2177 drag_info.item = item;
2178 drag_info.data = marker;
2179 drag_info.motion_callback = &Editor::meter_marker_drag_motion_callback;
2180 drag_info.finished_callback = &Editor::meter_marker_drag_finished_callback;
2184 drag_info.pointer_frame_offset = drag_info.grab_frame - meter_marker->meter().frame();
2186 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2190 Editor::start_meter_marker_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
2193 MeterMarker* meter_marker;
2195 if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
2196 fatal << _("programming error: meter marker canvas item has no marker object pointer!") << endmsg;
2200 meter_marker = dynamic_cast<MeterMarker*> (marker);
2202 // create a dummy marker for visual representation of moving the copy.
2203 // The actual copying is not done before we reach the finish callback.
2205 snprintf (name, sizeof(name), "%g/%g", meter_marker->meter().beats_per_bar(), meter_marker->meter().note_divisor ());
2206 MeterMarker* new_marker = new MeterMarker(*this, *meter_group, color_map[cMeterMarker], name,
2207 *new MeterSection(meter_marker->meter()));
2209 drag_info.item = &new_marker->the_item();
2210 drag_info.copy = true;
2211 drag_info.data = new_marker;
2212 drag_info.motion_callback = &Editor::meter_marker_drag_motion_callback;
2213 drag_info.finished_callback = &Editor::meter_marker_drag_finished_callback;
2217 drag_info.pointer_frame_offset = drag_info.grab_frame - meter_marker->meter().frame();
2219 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2223 Editor::meter_marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2225 MeterMarker* marker = (MeterMarker *) drag_info.data;
2226 jack_nframes_t adjusted_frame;
2228 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
2229 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2235 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2236 snap_to (adjusted_frame);
2239 if (adjusted_frame == drag_info.last_pointer_frame) return;
2241 marker->set_position (adjusted_frame);
2244 drag_info.last_pointer_frame = adjusted_frame;
2245 drag_info.first_move = false;
2247 show_verbose_time_cursor (adjusted_frame, 10);
2251 Editor::meter_marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2253 if (drag_info.first_move) return;
2255 meter_marker_drag_motion_callback (drag_info.item, event);
2257 MeterMarker* marker = (MeterMarker *) drag_info.data;
2260 TempoMap& map (session->tempo_map());
2261 map.bbt_time (drag_info.last_pointer_frame, when);
2263 if (drag_info.copy == true) {
2264 begin_reversible_command (_("copy meter mark"));
2265 session->add_undo (map.get_memento());
2266 map.add_meter (marker->meter(), when);
2267 session->add_redo_no_execute (map.get_memento());
2268 commit_reversible_command ();
2270 // delete the dummy marker we used for visual representation of copying.
2271 // a new visual marker will show up automatically.
2274 begin_reversible_command (_("move meter mark"));
2275 session->add_undo (map.get_memento());
2276 map.move_meter (marker->meter(), when);
2277 session->add_redo_no_execute (map.get_memento());
2278 commit_reversible_command ();
2283 Editor::start_tempo_marker_grab (ArdourCanvas::Item* item, GdkEvent* event)
2286 TempoMarker* tempo_marker;
2288 if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
2289 fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg;
2293 if ((tempo_marker = dynamic_cast<TempoMarker *> (marker)) == 0) {
2294 fatal << _("programming error: marker for tempo is not a tempo marker!") << endmsg;
2298 MetricSection& section (tempo_marker->tempo());
2300 if (!section.movable()) {
2304 drag_info.item = item;
2305 drag_info.data = marker;
2306 drag_info.motion_callback = &Editor::tempo_marker_drag_motion_callback;
2307 drag_info.finished_callback = &Editor::tempo_marker_drag_finished_callback;
2311 drag_info.pointer_frame_offset = drag_info.grab_frame - tempo_marker->tempo().frame();
2312 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2316 Editor::start_tempo_marker_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
2319 TempoMarker* tempo_marker;
2321 if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
2322 fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg;
2326 if ((tempo_marker = dynamic_cast<TempoMarker *> (marker)) == 0) {
2327 fatal << _("programming error: marker for tempo is not a tempo marker!") << endmsg;
2331 // create a dummy marker for visual representation of moving the copy.
2332 // The actual copying is not done before we reach the finish callback.
2334 snprintf (name, sizeof (name), "%.2f", tempo_marker->tempo().beats_per_minute());
2335 TempoMarker* new_marker = new TempoMarker(*this, *tempo_group, color_map[cTempoMarker], name,
2336 *new TempoSection(tempo_marker->tempo()));
2338 drag_info.item = &new_marker->the_item();
2339 drag_info.copy = true;
2340 drag_info.data = new_marker;
2341 drag_info.motion_callback = &Editor::tempo_marker_drag_motion_callback;
2342 drag_info.finished_callback = &Editor::tempo_marker_drag_finished_callback;
2346 drag_info.pointer_frame_offset = drag_info.grab_frame - tempo_marker->tempo().frame();
2348 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2352 Editor::tempo_marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2354 TempoMarker* marker = (TempoMarker *) drag_info.data;
2355 jack_nframes_t adjusted_frame;
2357 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
2358 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2364 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2365 snap_to (adjusted_frame);
2368 if (adjusted_frame == drag_info.last_pointer_frame) return;
2370 /* OK, we've moved far enough to make it worth actually move the thing. */
2372 marker->set_position (adjusted_frame);
2374 show_verbose_time_cursor (adjusted_frame, 10);
2376 drag_info.last_pointer_frame = adjusted_frame;
2377 drag_info.first_move = false;
2381 Editor::tempo_marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2383 if (drag_info.first_move) return;
2385 tempo_marker_drag_motion_callback (drag_info.item, event);
2387 TempoMarker* marker = (TempoMarker *) drag_info.data;
2390 TempoMap& map (session->tempo_map());
2391 map.bbt_time (drag_info.last_pointer_frame, when);
2393 if (drag_info.copy == true) {
2394 begin_reversible_command (_("copy tempo mark"));
2395 session->add_undo (map.get_memento());
2396 map.add_tempo (marker->tempo(), when);
2397 session->add_redo_no_execute (map.get_memento());
2398 commit_reversible_command ();
2400 // delete the dummy marker we used for visual representation of copying.
2401 // a new visual marker will show up automatically.
2404 begin_reversible_command (_("move tempo mark"));
2405 session->add_undo (map.get_memento());
2406 map.move_tempo (marker->tempo(), when);
2407 session->add_redo_no_execute (map.get_memento());
2408 commit_reversible_command ();
2413 Editor::remove_gain_control_point (ArdourCanvas::Item*item, GdkEvent* event)
2415 ControlPoint* control_point;
2417 if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
2418 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2422 // We shouldn't remove the first or last gain point
2423 if (control_point->line.is_last_point(*control_point) ||
2424 control_point->line.is_first_point(*control_point)) {
2428 control_point->line.remove_point (*control_point);
2432 Editor::remove_control_point (ArdourCanvas::Item*item, GdkEvent* event)
2434 ControlPoint* control_point;
2436 if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
2437 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2441 control_point->line.remove_point (*control_point);
2445 Editor::start_control_point_grab (ArdourCanvas::Item* item, GdkEvent* event)
2447 ControlPoint* control_point;
2449 if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
2450 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2454 drag_info.item = item;
2455 drag_info.data = control_point;
2456 drag_info.motion_callback = &Editor::control_point_drag_motion_callback;
2457 drag_info.finished_callback = &Editor::control_point_drag_finished_callback;
2459 start_grab (event, fader_cursor);
2461 control_point->line.start_drag (control_point, 0);
2463 float fraction = 1.0 - (control_point->get_y() / control_point->line.height());
2464 set_verbose_canvas_cursor (control_point->line.get_verbose_cursor_string (fraction),
2465 drag_info.current_pointer_x + 20, drag_info.current_pointer_y + 20);
2467 show_verbose_canvas_cursor ();
2471 Editor::control_point_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2473 ControlPoint* cp = reinterpret_cast<ControlPoint *> (drag_info.data);
2475 double cx = drag_info.current_pointer_x;
2476 double cy = drag_info.current_pointer_y;
2478 drag_info.cumulative_x_drag = cx - drag_info.grab_x ;
2479 drag_info.cumulative_y_drag = cy - drag_info.grab_y ;
2481 if (drag_info.x_constrained) {
2482 cx = drag_info.grab_x;
2484 if (drag_info.y_constrained) {
2485 cy = drag_info.grab_y;
2488 cp->line.parent_group().w2i (cx, cy);
2492 cy = min ((double) cp->line.height(), cy);
2494 //translate cx to frames
2495 jack_nframes_t cx_frames = unit_to_frame (cx);
2497 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && !drag_info.x_constrained) {
2498 snap_to (cx_frames);
2501 float fraction = 1.0 - (cy / cp->line.height());
2505 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
2511 cp->line.point_drag (*cp, cx_frames , fraction, push);
2513 set_verbose_canvas_cursor_text (cp->line.get_verbose_cursor_string (fraction));
2515 drag_info.first_move = false;
2519 Editor::control_point_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2521 ControlPoint* cp = reinterpret_cast<ControlPoint *> (drag_info.data);
2523 if (drag_info.first_move) {
2527 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
2528 reset_point_selection ();
2532 control_point_drag_motion_callback (item, event);
2534 cp->line.end_drag (cp);
2538 Editor::start_line_grab_from_regionview (ArdourCanvas::Item* item, GdkEvent* event)
2540 switch (mouse_mode) {
2542 start_line_grab (clicked_regionview->get_gain_line(), event);
2550 Editor::start_line_grab_from_line (ArdourCanvas::Item* item, GdkEvent* event)
2554 if ((al = reinterpret_cast<AutomationLine*> (item->get_data ("line"))) == 0) {
2555 fatal << _("programming error: line canvas item has no line pointer!") << endmsg;
2559 start_line_grab (al, event);
2563 Editor::start_line_grab (AutomationLine* line, GdkEvent* event)
2567 jack_nframes_t frame_within_region;
2569 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2573 cx = event->button.x;
2574 cy = event->button.y;
2575 line->parent_group().w2i (cx, cy);
2576 frame_within_region = (jack_nframes_t) floor (cx * frames_per_unit);
2578 if (!line->control_points_adjacent (frame_within_region, current_line_drag_info.before,
2579 current_line_drag_info.after)) {
2580 /* no adjacent points */
2584 drag_info.item = &line->grab_item();
2585 drag_info.data = line;
2586 drag_info.motion_callback = &Editor::line_drag_motion_callback;
2587 drag_info.finished_callback = &Editor::line_drag_finished_callback;
2589 start_grab (event, fader_cursor);
2591 double fraction = 1.0 - (cy / line->height());
2593 line->start_drag (0, fraction);
2595 set_verbose_canvas_cursor (line->get_verbose_cursor_string (fraction),
2596 drag_info.current_pointer_x + 20, drag_info.current_pointer_y + 20);
2597 show_verbose_canvas_cursor ();
2601 Editor::line_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2603 AutomationLine* line = reinterpret_cast<AutomationLine *> (drag_info.data);
2604 double cx = drag_info.current_pointer_x;
2605 double cy = drag_info.current_pointer_y;
2607 line->parent_group().w2i (cx, cy);
2610 fraction = 1.0 - (cy / line->height());
2614 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
2620 line->line_drag (current_line_drag_info.before, current_line_drag_info.after, fraction, push);
2622 set_verbose_canvas_cursor_text (line->get_verbose_cursor_string (fraction));
2626 Editor::line_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2628 AutomationLine* line = reinterpret_cast<AutomationLine *> (drag_info.data);
2629 line_drag_motion_callback (item, event);
2634 Editor::start_region_grab (ArdourCanvas::Item* item, GdkEvent* event)
2636 if (selection->audio_regions.empty() || clicked_regionview == 0) {
2640 drag_info.copy = false;
2641 drag_info.item = item;
2642 drag_info.data = clicked_regionview;
2643 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2644 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2649 TimeAxisView* tvp = clicked_trackview;
2650 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
2652 if (tv && tv->is_audio_track()) {
2653 speed = tv->get_diskstream()->speed();
2656 drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region.position() / speed);
2657 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2658 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2659 // we want a move threshold
2660 drag_info.want_move_threshold = true;
2662 show_verbose_time_cursor (drag_info.last_frame_position, 10);
2664 begin_reversible_command (_("move region(s)"));
2668 Editor::start_region_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
2670 if (selection->audio_regions.empty() || clicked_regionview == 0) {
2674 drag_info.copy = true;
2675 drag_info.item = item;
2676 drag_info.data = clicked_regionview;
2680 TimeAxisView* tv = &clicked_regionview->get_time_axis_view();
2681 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(tv);
2684 if (atv && atv->is_audio_track()) {
2685 speed = atv->get_diskstream()->speed();
2688 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2689 drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region.position() / speed);
2690 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2691 // we want a move threshold
2692 drag_info.want_move_threshold = true;
2693 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2694 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2698 Editor::start_region_brush_grab (ArdourCanvas::Item* item, GdkEvent* event)
2700 if (selection->audio_regions.empty() || clicked_regionview == 0) {
2704 drag_info.copy = false;
2705 drag_info.item = item;
2706 drag_info.data = clicked_regionview;
2707 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2708 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2713 TimeAxisView* tvp = clicked_trackview;
2714 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
2716 if (tv && tv->is_audio_track()) {
2717 speed = tv->get_diskstream()->speed();
2720 drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region.position() / speed);
2721 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2722 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2723 // we want a move threshold
2724 drag_info.want_move_threshold = true;
2725 drag_info.brushing = true;
2727 begin_reversible_command (_("Drag region brush"));
2731 Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2735 AudioRegionView *rv = reinterpret_cast<AudioRegionView*> (drag_info.data);
2736 jack_nframes_t pending_region_position = 0;
2737 int32_t pointer_y_span = 0, canvas_pointer_y_span = 0, original_pointer_order;
2738 int32_t visible_y_high = 0, visible_y_low = 512; //high meaning higher numbered.. not the height on the screen
2739 bool clamp_y_axis = false;
2740 vector<int32_t> height_list(512) ;
2741 vector<int32_t>::iterator j;
2743 show_verbose_time_cursor (drag_info.last_frame_position, 10);
2745 if (drag_info.copy && drag_info.move_threshold_passed && drag_info.want_move_threshold) {
2747 drag_info.want_move_threshold = false; // don't copy again
2749 /* this is committed in the grab finished callback. */
2751 begin_reversible_command (_("Drag region copy"));
2753 /* duplicate the region(s) */
2755 vector<AudioRegionView*> new_regionviews;
2757 set<Playlist*> affected_playlists;
2758 pair<set<Playlist*>::iterator,bool> insert_result;
2760 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
2761 AudioRegionView* rv;
2765 Playlist* to_playlist = rv->region.playlist();
2766 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&rv->get_time_axis_view());
2768 insert_result = affected_playlists.insert (to_playlist);
2769 if (insert_result.second) {
2770 session->add_undo (to_playlist->get_memento ());
2773 latest_regionview = 0;
2775 sigc::connection c = atv->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
2777 /* create a new region with the same name.
2780 AudioRegion* newregion = new AudioRegion (rv->region);
2782 /* if the original region was locked, we don't care */
2784 newregion->set_locked (false);
2786 to_playlist->add_region (*newregion, (jack_nframes_t) (rv->region.position() * atv->get_diskstream()->speed()));
2790 if (latest_regionview) {
2791 new_regionviews.push_back (latest_regionview);
2795 if (new_regionviews.empty()) {
2799 /* reset selection to new regionviews */
2801 selection->set (new_regionviews);
2803 /* reset drag_info data to reflect the fact that we are dragging the copies */
2805 drag_info.data = new_regionviews.front();
2806 swap_grab (new_regionviews.front()->get_canvas_group (), 0, event->motion.time);
2809 /* Which trackview is this ? */
2811 TimeAxisView* tvp = trackview_by_y_position (drag_info.current_pointer_y);
2812 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
2814 /* The region motion is only processed if the pointer is over
2818 if (!tv || !tv->is_audio_track()) {
2819 /* To make sure we hide the verbose canvas cursor when the mouse is
2820 not held over and audiotrack.
2822 hide_verbose_canvas_cursor ();
2826 original_pointer_order = drag_info.last_trackview->order;
2828 /************************************************************
2830 ************************************************************/
2832 if (drag_info.brushing) {
2833 clamp_y_axis = true;
2838 if ((pointer_y_span = (drag_info.last_trackview->order - tv->order)) != 0) {
2840 int32_t children = 0, numtracks = 0;
2841 // XXX hard coding track limit, oh my, so very very bad
2842 bitset <1024> tracks (0x00);
2843 /* get a bitmask representing the visible tracks */
2845 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2846 TimeAxisView *tracklist_timeview;
2847 tracklist_timeview = (*i);
2848 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tracklist_timeview);
2849 list<TimeAxisView*> children_list;
2851 /* zeroes are audio tracks. ones are other types. */
2853 if (!atv2->hidden()) {
2855 if (visible_y_high < atv2->order) {
2856 visible_y_high = atv2->order;
2858 if (visible_y_low > atv2->order) {
2859 visible_y_low = atv2->order;
2862 if (!atv2->is_audio_track()) {
2863 tracks = tracks |= (0x01 << atv2->order);
2866 height_list[atv2->order] = (*i)->height;
2868 if ((children_list = atv2->get_child_list()).size() > 0) {
2869 for (list<TimeAxisView*>::iterator j = children_list.begin(); j != children_list.end(); ++j) {
2870 tracks = tracks |= (0x01 << (atv2->order + children));
2871 height_list[atv2->order + children] = (*j)->height;
2879 /* find the actual span according to the canvas */
2881 canvas_pointer_y_span = pointer_y_span;
2882 if (drag_info.last_trackview->order >= tv->order) {
2884 for (y = tv->order; y < drag_info.last_trackview->order; y++) {
2885 if (height_list[y] == 0 ) {
2886 canvas_pointer_y_span--;
2891 for (y = drag_info.last_trackview->order;y <= tv->order; y++) {
2892 if ( height_list[y] == 0 ) {
2893 canvas_pointer_y_span++;
2898 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
2899 AudioRegionView* rv2;
2901 double ix1, ix2, iy1, iy2;
2904 rv2->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
2905 rv2->get_canvas_group()->i2w (ix1, iy1);
2906 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
2907 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2);
2909 if (atv2->order != original_pointer_order) {
2910 /* this isn't the pointer track */
2912 if (canvas_pointer_y_span > 0) {
2914 /* moving up the canvas */
2915 if ((atv2->order - canvas_pointer_y_span) >= visible_y_low) {
2917 int32_t visible_tracks = 0;
2918 while (visible_tracks < canvas_pointer_y_span ) {
2921 while (height_list[atv2->order - (visible_tracks - n)] == 0) {
2922 /* we're passing through a hidden track */
2927 if (tracks[atv2->order - (canvas_pointer_y_span - n)] != 0x00) {
2928 clamp_y_axis = true;
2932 clamp_y_axis = true;
2935 } else if (canvas_pointer_y_span < 0) {
2937 /*moving down the canvas*/
2939 if ((atv2->order - (canvas_pointer_y_span - n)) <= visible_y_high) { // we will overflow
2942 int32_t visible_tracks = 0;
2944 while (visible_tracks > canvas_pointer_y_span ) {
2947 while (height_list[atv2->order - (visible_tracks - n)] == 0) {
2951 if ( tracks[atv2->order - ( canvas_pointer_y_span - n)] != 0x00) {
2952 clamp_y_axis = true;
2957 clamp_y_axis = true;
2963 /* this is the pointer's track */
2964 if ((atv2->order - pointer_y_span) > visible_y_high) { // we will overflow
2965 clamp_y_axis = true;
2966 } else if ((atv2->order - pointer_y_span) < visible_y_low) { // we will underflow
2967 clamp_y_axis = true;
2975 } else if (drag_info.last_trackview == tv) {
2976 clamp_y_axis = true;
2980 if (!clamp_y_axis) {
2981 drag_info.last_trackview = tv;
2984 /************************************************************
2986 ************************************************************/
2988 /* compute the amount of pointer motion in frames, and where
2989 the region would be if we moved it by that much.
2992 if (drag_info.move_threshold_passed) {
2994 if ((int32_t)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
2996 jack_nframes_t sync_frame;
2997 jack_nframes_t sync_offset;
3000 pending_region_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
3002 sync_offset = rv->region.sync_offset (sync_dir);
3003 sync_frame = rv->region.adjust_to_sync (pending_region_position);
3005 /* we snap if the snap modifier is not enabled.
3008 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3009 snap_to (sync_frame);
3012 if (sync_frame - sync_offset <= sync_frame) {
3013 pending_region_position = sync_frame - (sync_dir*sync_offset);
3015 pending_region_position = 0;
3019 pending_region_position = 0;
3022 if (pending_region_position > max_frames - rv->region.length()) {
3023 pending_region_position = drag_info.last_frame_position;
3026 // printf ("3: pending_region_position= %lu %lu\n", pending_region_position, drag_info.last_frame_position );
3028 if (pending_region_position != drag_info.last_frame_position && !drag_info.x_constrained) {
3030 /* now compute the canvas unit distance we need to move the regiondrag_info.last_trackview->order
3031 to make it appear at the new location.
3034 if (pending_region_position > drag_info.last_frame_position) {
3035 x_delta = ((double) (pending_region_position - drag_info.last_frame_position) / frames_per_unit);
3037 x_delta = -((double) (drag_info.last_frame_position - pending_region_position) / frames_per_unit);
3040 drag_info.last_frame_position = pending_region_position;
3047 /* threshold not passed */
3052 /*************************************************************
3054 ************************************************************/
3056 if (x_delta == 0 && (pointer_y_span == 0)) {
3057 /* haven't reached next snap point, and we're not switching
3058 trackviews. nothing to do.
3064 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
3066 AudioRegionView* rv2;
3069 /* if any regionview is at zero, we need to know so we can
3070 stop further leftward motion.
3073 double ix1, ix2, iy1, iy2;
3074 rv2->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3075 rv2->get_canvas_group()->i2w (ix1, iy1);
3084 /*************************************************************
3086 ************************************************************/
3088 pair<set<Playlist*>::iterator,bool> insert_result;
3089 const list<AudioRegionView*>& layered_regions = selection->audio_regions.by_layer();
3091 for (list<AudioRegionView*>::const_iterator i = layered_regions.begin(); i != layered_regions.end(); ++i) {
3093 AudioRegionView* rv;
3095 double ix1, ix2, iy1, iy2;
3096 int32_t temp_pointer_y_span = pointer_y_span;
3098 /* get item BBox, which will be relative to parent. so we have
3099 to query on a child, then convert to world coordinates using
3103 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3104 rv->get_canvas_group()->i2w (ix1, iy1);
3105 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
3106 AudioTimeAxisView* canvas_atv = dynamic_cast<AudioTimeAxisView*>(tvp2);
3107 AudioTimeAxisView* temp_atv;
3109 if ((pointer_y_span != 0) && !clamp_y_axis) {
3112 for (j = height_list.begin(); j!= height_list.end(); j++) {
3113 if (x == canvas_atv->order) {
3114 /* we found the track the region is on */
3115 if (x != original_pointer_order) {
3116 /*this isn't from the same track we're dragging from */
3117 temp_pointer_y_span = canvas_pointer_y_span;
3119 while (temp_pointer_y_span > 0) {
3120 /* we're moving up canvas-wise,
3121 so we need to find the next track height
3123 if (j != height_list.begin()) {
3126 if (x != original_pointer_order) {
3127 /* we're not from the dragged track, so ignore hidden tracks. */
3129 temp_pointer_y_span++;
3133 temp_pointer_y_span--;
3135 while (temp_pointer_y_span < 0) {
3137 if (x != original_pointer_order) {
3139 temp_pointer_y_span--;
3143 if (j != height_list.end()) {
3146 temp_pointer_y_span++;
3148 /* find out where we'll be when we move and set height accordingly */
3150 tvp2 = trackview_by_y_position (iy1 + y_delta);
3151 temp_atv = dynamic_cast<AudioTimeAxisView*>(tvp2);
3152 rv->set_height (temp_atv->height);
3154 /* if you un-comment the following, the region colours will follow the track colours whilst dragging,
3155 personally, i think this can confuse things, but never mind.
3158 //const GdkColor& col (temp_atv->view->get_region_color());
3159 //rv->set_color (const_cast<GdkColor&>(col));
3166 /* prevent the regionview from being moved to before
3167 the zero position on the canvas.
3172 if (-x_delta > ix1) {
3175 } else if ((x_delta > 0) &&(rv->region.last_frame() > max_frames - x_delta)) {
3176 x_delta = max_frames - rv->region.last_frame();
3179 if (drag_info.first_move) {
3181 /* hide any dependent views */
3183 // rv->get_time_axis_view().hide_dependent_views (*rv);
3185 /* this is subtle. raising the regionview itself won't help,
3186 because raise_to_top() just puts the item on the top of
3187 its parent's stack. so, we need to put the trackview canvas_display group
3188 on the top, since its parent is the whole canvas.
3191 rv->get_canvas_group()->raise_to_top();
3192 rv->get_time_axis_view().canvas_display->raise_to_top();
3193 cursor_group->raise_to_top();
3195 /* freeze the playlists from notifying till
3199 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&rv->get_time_axis_view());
3200 if (atv && atv->is_audio_track()) {
3201 AudioPlaylist* pl = atv->get_diskstream()->playlist();
3203 /* only freeze and capture state once */
3205 insert_result = motion_frozen_playlists.insert (pl);
3206 if (insert_result.second) {
3208 session->add_undo(pl->get_memento());
3214 if (drag_info.brushing) {
3215 mouse_brush_insert_region (rv, pending_region_position);
3217 rv->move (x_delta, y_delta);
3221 if (drag_info.first_move) {
3222 cursor_group->raise_to_top();
3225 drag_info.first_move = false;
3227 if (x_delta != 0 && !drag_info.brushing) {
3228 show_verbose_time_cursor (drag_info.last_frame_position, 10);
3234 Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
3236 jack_nframes_t where;
3237 AudioRegionView* rv = reinterpret_cast<AudioRegionView *> (drag_info.data);
3238 pair<set<Playlist*>::iterator,bool> insert_result;
3239 bool nocommit = true;
3241 AudioTimeAxisView* atv;
3242 bool regionview_y_movement;
3243 bool regionview_x_movement;
3245 /* first_move is set to false if the regionview has been moved in the
3249 if (drag_info.first_move) {
3256 /* The regionview has been moved at some stage during the grab so we need
3257 to account for any mouse movement between this event and the last one.
3260 region_drag_motion_callback (item, event);
3262 if (drag_info.brushing) {
3263 /* all changes were made during motion event handlers */
3267 /* adjust for track speed */
3270 atv = dynamic_cast<AudioTimeAxisView*> (drag_info.last_trackview);
3271 if (atv && atv->get_diskstream()) {
3272 speed = atv->get_diskstream()->speed();
3275 regionview_x_movement = (drag_info.last_frame_position != (jack_nframes_t) (rv->region.position()/speed));
3276 regionview_y_movement = (drag_info.last_trackview != &rv->get_time_axis_view());
3278 //printf ("last_frame: %s position is %lu %g\n", rv->get_time_axis_view().name().c_str(), drag_info.last_frame_position, speed);
3279 //printf ("last_rackview: %s \n", drag_info.last_trackview->name().c_str());
3281 if (regionview_y_movement) {
3283 /* motion between tracks */
3285 list<AudioRegionView*> new_selection;
3287 /* moved to a different audio track. */
3289 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ) {
3291 AudioRegionView* rv2 = (*i);
3293 /* the region that used to be in the old playlist is not
3294 moved to the new one - we make a copy of it. as a result,
3295 any existing editor for the region should no longer be
3299 if (!drag_info.copy) {
3300 rv2->hide_region_editor();
3302 new_selection.push_back (rv2);
3306 /* first, freeze the target tracks */
3308 for (list<AudioRegionView*>::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) {
3310 Playlist* from_playlist;
3311 Playlist* to_playlist;
3313 double ix1, ix2, iy1, iy2;
3315 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3316 (*i)->get_canvas_group()->i2w (ix1, iy1);
3317 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
3318 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2);
3320 from_playlist = (*i)->region.playlist();
3321 to_playlist = atv2->playlist();
3323 /* the from_playlist was frozen in the "first_move" case
3324 of the motion handler. the insert can fail,
3325 but that doesn't matter. it just means
3326 we already have the playlist in the list.
3329 motion_frozen_playlists.insert (from_playlist);
3331 /* only freeze the to_playlist once */
3333 insert_result = motion_frozen_playlists.insert(to_playlist);
3334 if (insert_result.second) {
3335 to_playlist->freeze();
3336 session->add_undo(to_playlist->get_memento());
3341 /* now do it again with the actual operations */
3343 for (list<AudioRegionView*>::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) {
3345 Playlist* from_playlist;
3346 Playlist* to_playlist;
3348 double ix1, ix2, iy1, iy2;
3350 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3351 (*i)->get_canvas_group()->i2w (ix1, iy1);
3352 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
3353 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2);
3355 from_playlist = (*i)->region.playlist();
3356 to_playlist = atv2->playlist();
3358 latest_regionview = 0;
3360 where = (jack_nframes_t) (unit_to_frame (ix1) * speed);
3361 Region* new_region = createRegion ((*i)->region);
3363 from_playlist->remove_region (&((*i)->region));
3365 sigc::connection c = atv2->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3366 to_playlist->add_region (*new_region, where);
3369 if (latest_regionview) {
3370 selection->add (latest_regionview);
3376 /* motion within a single track */
3378 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
3382 if (rv->region.locked()) {
3386 if (regionview_x_movement) {
3387 double ownspeed = 1.0;
3388 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&(rv->get_time_axis_view()));
3390 if (atv && atv->get_diskstream()) {
3391 ownspeed = atv->get_diskstream()->speed();
3394 /* base the new region position on the current position of the regionview.*/
3396 double ix1, ix2, iy1, iy2;
3398 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3399 rv->get_canvas_group()->i2w (ix1, iy1);
3400 where = (jack_nframes_t) (unit_to_frame (ix1) * ownspeed);
3404 where = rv->region.position();
3407 rv->get_time_axis_view().reveal_dependent_views (*rv);
3409 /* no need to add an undo here, we did that when we added this playlist to motion_frozen playlists */
3411 rv->region.set_position (where, (void *) this);
3416 for (set<Playlist*>::iterator p = motion_frozen_playlists.begin(); p != motion_frozen_playlists.end(); ++p) {
3418 session->add_redo_no_execute ((*p)->get_memento());
3421 motion_frozen_playlists.clear ();
3424 commit_reversible_command ();
3429 Editor::region_view_item_click (AudioRegionView& rv, GdkEventButton* event)
3431 /* Either add to or set the set the region selection, unless
3432 this is an alignment click (control used)
3435 if (Keyboard::modifier_state_contains (event->state, Keyboard::Control)) {
3436 TimeAxisView* tv = &rv.get_time_axis_view();
3437 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(tv);
3439 if (atv && atv->is_audio_track()) {
3440 speed = atv->get_diskstream()->speed();
3443 if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Alt))) {
3445 align_region (rv.region, SyncPoint, (jack_nframes_t) (edit_cursor->current_frame * speed));
3447 } else if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Shift))) {
3449 align_region (rv.region, End, (jack_nframes_t) (edit_cursor->current_frame * speed));
3453 align_region (rv.region, Start, (jack_nframes_t) (edit_cursor->current_frame * speed));
3459 Editor::show_verbose_time_cursor (jack_nframes_t frame, double offset, double xpos, double ypos)
3470 switch (ARDOUR_UI::instance()->secondary_clock.mode ()) {
3471 case AudioClock::BBT:
3472 session->bbt_time (frame, bbt);
3473 snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32, bbt.bars, bbt.beats, bbt.ticks);
3476 case AudioClock::SMPTE:
3477 session->smpte_time (frame, smpte);
3478 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
3481 case AudioClock::MinSec:
3482 /* XXX fix this to compute min/sec properly */
3483 session->smpte_time (frame, smpte);
3484 secs = smpte.seconds + ((float) smpte.frames / session->smpte_frames_per_second);
3485 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%.4f", smpte.hours, smpte.minutes, secs);
3489 snprintf (buf, sizeof(buf), "%u", frame);
3493 if (xpos >= 0 && ypos >=0) {
3494 set_verbose_canvas_cursor (buf, xpos + offset, ypos + offset);
3497 set_verbose_canvas_cursor (buf, drag_info.current_pointer_x + offset, drag_info.current_pointer_y + offset);
3499 show_verbose_canvas_cursor ();
3503 Editor::show_verbose_duration_cursor (jack_nframes_t start, jack_nframes_t end, double offset, double xpos, double ypos)
3510 Meter meter_at_start(session->tempo_map().meter_at(start));
3516 switch (ARDOUR_UI::instance()->secondary_clock.mode ()) {
3517 case AudioClock::BBT:
3518 session->bbt_time (start, sbbt);
3519 session->bbt_time (end, ebbt);
3522 /* XXX this computation won't work well if the
3523 user makes a selection that spans any meter changes.
3526 ebbt.bars -= sbbt.bars;
3527 if (ebbt.beats >= sbbt.beats) {
3528 ebbt.beats -= sbbt.beats;
3531 ebbt.beats = int(meter_at_start.beats_per_bar()) + ebbt.beats - sbbt.beats;
3533 if (ebbt.ticks >= sbbt.ticks) {
3534 ebbt.ticks -= sbbt.ticks;
3537 ebbt.ticks = int(Meter::ticks_per_beat) + ebbt.ticks - sbbt.ticks;
3540 snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32, ebbt.bars, ebbt.beats, ebbt.ticks);
3543 case AudioClock::SMPTE:
3544 session->smpte_duration (end - start, smpte);
3545 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
3548 case AudioClock::MinSec:
3549 /* XXX fix this to compute min/sec properly */
3550 session->smpte_duration (end - start, smpte);
3551 secs = smpte.seconds + ((float) smpte.frames / session->smpte_frames_per_second);
3552 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%.4f", smpte.hours, smpte.minutes, secs);
3556 snprintf (buf, sizeof(buf), "%u", end - start);
3560 if (xpos >= 0 && ypos >=0) {
3561 set_verbose_canvas_cursor (buf, xpos + offset, ypos + offset);
3564 set_verbose_canvas_cursor (buf, drag_info.current_pointer_x + offset, drag_info.current_pointer_y + offset);
3566 show_verbose_canvas_cursor ();
3570 Editor::collect_new_region_view (AudioRegionView* rv)
3572 latest_regionview = rv;
3576 Editor::start_selection_grab (ArdourCanvas::Item* item, GdkEvent* event)
3578 if (clicked_regionview == 0) {
3582 /* lets try to create new Region for the selection */
3584 vector<AudioRegion*> new_regions;
3585 create_region_from_selection (new_regions);
3587 if (new_regions.empty()) {
3591 /* XXX fix me one day to use all new regions */
3593 Region* region = new_regions.front();
3595 /* add it to the current stream/playlist.
3597 tricky: the streamview for the track will add a new regionview. we will
3598 catch the signal it sends when it creates the regionview to
3599 set the regionview we want to then drag.
3602 latest_regionview = 0;
3603 sigc::connection c = clicked_audio_trackview->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3605 /* A selection grab currently creates two undo/redo operations, one for
3606 creating the new region and another for moving it.
3609 begin_reversible_command (_("selection grab"));
3611 Playlist* playlist = clicked_trackview->playlist();
3613 session->add_undo (playlist->get_memento ());
3614 clicked_trackview->playlist()->add_region (*region, selection->time[clicked_selection].start);
3615 session->add_redo_no_execute (playlist->get_memento ());
3617 commit_reversible_command ();
3621 if (latest_regionview == 0) {
3622 /* something went wrong */
3626 /* we need to deselect all other regionviews, and select this one
3627 i'm ignoring undo stuff, because the region creation will take care of it */
3628 selection->set (latest_regionview);
3630 drag_info.item = latest_regionview->get_canvas_group();
3631 drag_info.data = latest_regionview;
3632 drag_info.motion_callback = &Editor::region_drag_motion_callback;
3633 drag_info.finished_callback = &Editor::region_drag_finished_callback;
3637 drag_info.last_trackview = clicked_trackview;
3638 drag_info.last_frame_position = latest_regionview->region.position();
3639 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
3641 show_verbose_time_cursor (drag_info.last_frame_position, 10);
3645 Editor::cancel_selection ()
3647 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3648 (*i)->hide_selection ();
3650 begin_reversible_command (_("cancel selection"));
3651 selection->clear ();
3652 clicked_selection = 0;
3653 commit_reversible_command ();
3657 Editor::start_selection_op (ArdourCanvas::Item* item, GdkEvent* event, SelectionOp op)
3659 jack_nframes_t start = 0;
3660 jack_nframes_t end = 0;
3666 drag_info.item = item;
3667 drag_info.motion_callback = &Editor::drag_selection;
3668 drag_info.finished_callback = &Editor::end_selection_op;
3673 case CreateSelection:
3674 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
3675 drag_info.copy = true;
3677 drag_info.copy = false;
3679 start_grab (event, selector_cursor);
3682 case SelectionStartTrim:
3683 if (clicked_trackview) {
3684 clicked_trackview->order_selection_trims (item, true);
3686 start_grab (event, trimmer_cursor);
3687 start = selection->time[clicked_selection].start;
3688 drag_info.pointer_frame_offset = drag_info.grab_frame - start;
3691 case SelectionEndTrim:
3692 if (clicked_trackview) {
3693 clicked_trackview->order_selection_trims (item, false);
3695 start_grab (event, trimmer_cursor);
3696 end = selection->time[clicked_selection].end;
3697 drag_info.pointer_frame_offset = drag_info.grab_frame - end;
3701 start = selection->time[clicked_selection].start;
3703 drag_info.pointer_frame_offset = drag_info.grab_frame - start;
3707 if (selection_op == SelectionMove) {
3708 show_verbose_time_cursor(start, 10);
3710 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
3715 Editor::drag_selection (ArdourCanvas::Item* item, GdkEvent* event)
3717 jack_nframes_t start = 0;
3718 jack_nframes_t end = 0;
3719 jack_nframes_t length;
3720 jack_nframes_t pending_position;
3722 if ((int32_t) drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
3723 pending_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
3726 pending_position = 0;
3729 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3730 snap_to (pending_position);
3733 /* only alter selection if the current frame is
3734 different from the last frame position (adjusted)
3737 if (pending_position == drag_info.last_pointer_frame) return;
3739 switch (selection_op) {
3740 case CreateSelection:
3742 if (drag_info.first_move) {
3743 snap_to (drag_info.grab_frame);
3746 if (pending_position < drag_info.grab_frame) {
3747 start = pending_position;
3748 end = drag_info.grab_frame;
3750 end = pending_position;
3751 start = drag_info.grab_frame;
3754 /* first drag: Either add to the selection
3755 or create a new selection->
3758 if (drag_info.first_move) {
3760 begin_reversible_command (_("range selection"));
3762 if (drag_info.copy) {
3763 /* adding to the selection */
3764 clicked_selection = selection->add (start, end);
3765 drag_info.copy = false;
3767 /* new selection-> */
3768 clicked_selection = selection->set (clicked_trackview, start, end);
3773 case SelectionStartTrim:
3775 if (drag_info.first_move) {
3776 begin_reversible_command (_("trim selection start"));
3779 start = selection->time[clicked_selection].start;
3780 end = selection->time[clicked_selection].end;
3782 if (pending_position > end) {
3785 start = pending_position;
3789 case SelectionEndTrim:
3791 if (drag_info.first_move) {
3792 begin_reversible_command (_("trim selection end"));
3795 start = selection->time[clicked_selection].start;
3796 end = selection->time[clicked_selection].end;
3798 if (pending_position < start) {
3801 end = pending_position;
3808 if (drag_info.first_move) {
3809 begin_reversible_command (_("move selection"));
3812 start = selection->time[clicked_selection].start;
3813 end = selection->time[clicked_selection].end;
3815 length = end - start;
3817 start = pending_position;
3820 end = start + length;
3825 if (event->button.x >= horizontal_adjustment.get_value() + canvas_width) {
3826 start_canvas_autoscroll (1);
3830 selection->replace (clicked_selection, start, end);
3833 drag_info.last_pointer_frame = pending_position;
3834 drag_info.first_move = false;
3836 if (selection_op == SelectionMove) {
3837 show_verbose_time_cursor(start, 10);
3839 show_verbose_time_cursor(pending_position, 10);
3844 Editor::end_selection_op (ArdourCanvas::Item* item, GdkEvent* event)
3846 if (!drag_info.first_move) {
3847 drag_selection (item, event);
3848 /* XXX this is not object-oriented programming at all. ick */
3849 if (selection->time.consolidate()) {
3850 selection->TimeChanged ();
3852 commit_reversible_command ();
3854 /* just a click, no pointer movement.*/
3856 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3858 selection->clear_time();
3863 /* XXX what happens if its a music selection? */
3864 session->set_audio_range (selection->time);
3865 stop_canvas_autoscroll ();
3869 Editor::start_trim (ArdourCanvas::Item* item, GdkEvent* event)
3872 TimeAxisView* tvp = clicked_trackview;
3873 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3875 if (tv && tv->is_audio_track()) {
3876 speed = tv->get_diskstream()->speed();
3879 jack_nframes_t region_start = (jack_nframes_t) (clicked_regionview->region.position() / speed);
3880 jack_nframes_t region_end = (jack_nframes_t) (clicked_regionview->region.last_frame() / speed);
3881 jack_nframes_t region_length = (jack_nframes_t) (clicked_regionview->region.length() / speed);
3883 motion_frozen_playlists.clear();
3885 //drag_info.item = clicked_regionview->get_name_highlight();
3886 drag_info.item = item;
3887 drag_info.motion_callback = &Editor::trim_motion_callback;
3888 drag_info.finished_callback = &Editor::trim_finished_callback;
3890 start_grab (event, trimmer_cursor);
3892 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
3893 trim_op = ContentsTrim;
3895 /* These will get overridden for a point trim.*/
3896 if (drag_info.current_pointer_frame < (region_start + region_length/2)) {
3897 /* closer to start */
3898 trim_op = StartTrim;
3899 } else if (drag_info.current_pointer_frame > (region_end - region_length/2)) {
3907 show_verbose_time_cursor(region_start, 10);
3910 show_verbose_time_cursor(region_end, 10);
3913 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
3919 Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
3921 AudioRegionView* rv = clicked_regionview;
3922 jack_nframes_t frame_delta = 0;
3923 bool left_direction;
3924 bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier());
3926 /* snap modifier works differently here..
3927 its' current state has to be passed to the
3928 various trim functions in order to work properly
3932 TimeAxisView* tvp = clicked_trackview;
3933 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3934 pair<set<Playlist*>::iterator,bool> insert_result;
3936 if (tv && tv->is_audio_track()) {
3937 speed = tv->get_diskstream()->speed();
3940 if (drag_info.last_pointer_frame > drag_info.current_pointer_frame) {
3941 left_direction = true;
3943 left_direction = false;
3947 snap_to (drag_info.current_pointer_frame);
3950 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) {
3954 if (drag_info.first_move) {
3960 trim_type = "Region start trim";
3963 trim_type = "Region end trim";
3966 trim_type = "Region content trim";
3970 begin_reversible_command (trim_type);
3972 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
3973 (*i)->region.freeze ();
3974 (*i)->temporarily_hide_envelope ();
3976 Playlist * pl = (*i)->region.playlist();
3977 insert_result = motion_frozen_playlists.insert (pl);
3978 if (insert_result.second) {
3979 session->add_undo (pl->get_memento());
3984 if (left_direction) {
3985 frame_delta = (drag_info.last_pointer_frame - drag_info.current_pointer_frame);
3987 frame_delta = (drag_info.current_pointer_frame - drag_info.last_pointer_frame);
3992 if ((left_direction == false) && (drag_info.current_pointer_frame <= rv->region.first_frame()/speed)) {
3995 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
3996 single_start_trim (**i, frame_delta, left_direction, obey_snap);
4002 if ((left_direction == true) && (drag_info.current_pointer_frame > (jack_nframes_t) (rv->region.last_frame()/speed))) {
4005 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
4006 single_end_trim (**i, frame_delta, left_direction, obey_snap);
4013 bool swap_direction = false;
4015 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
4016 swap_direction = true;
4019 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin();
4020 i != selection->audio_regions.by_layer().end(); ++i)
4022 single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
4030 show_verbose_time_cursor((jack_nframes_t) (rv->region.position()/speed), 10);
4033 show_verbose_time_cursor((jack_nframes_t) (rv->region.last_frame()/speed), 10);
4036 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
4040 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4041 drag_info.first_move = false;
4045 Editor::single_contents_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool swap_direction, bool obey_snap)
4047 Region& region (rv.region);
4049 if (region.locked()) {
4053 jack_nframes_t new_bound;
4056 TimeAxisView* tvp = clicked_trackview;
4057 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
4059 if (tv && tv->is_audio_track()) {
4060 speed = tv->get_diskstream()->speed();
4063 if (left_direction) {
4064 if (swap_direction) {
4065 new_bound = (jack_nframes_t) (region.position()/speed) + frame_delta;
4067 new_bound = (jack_nframes_t) (region.position()/speed) - frame_delta;
4070 if (swap_direction) {
4071 new_bound = (jack_nframes_t) (region.position()/speed) - frame_delta;
4073 new_bound = (jack_nframes_t) (region.position()/speed) + frame_delta;
4078 snap_to (new_bound);
4080 region.trim_start ((jack_nframes_t) (new_bound * speed), this);
4081 rv.region_changed (StartChanged);
4085 Editor::single_start_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool obey_snap)
4087 Region& region (rv.region);
4089 if (region.locked()) {
4093 jack_nframes_t new_bound;
4096 TimeAxisView* tvp = clicked_trackview;
4097 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
4099 if (tv && tv->is_audio_track()) {
4100 speed = tv->get_diskstream()->speed();
4103 if (left_direction) {
4104 new_bound = (jack_nframes_t) (region.position()/speed) - frame_delta;
4106 new_bound = (jack_nframes_t) (region.position()/speed) + frame_delta;
4110 snap_to (new_bound, (left_direction ? 0 : 1));
4113 region.trim_front ((jack_nframes_t) (new_bound * speed), this);
4115 rv.region_changed (Change (LengthChanged|PositionChanged|StartChanged));
4119 Editor::single_end_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool obey_snap)
4121 Region& region (rv.region);
4123 if (region.locked()) {
4127 jack_nframes_t new_bound;
4130 TimeAxisView* tvp = clicked_trackview;
4131 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
4133 if (tv && tv->is_audio_track()) {
4134 speed = tv->get_diskstream()->speed();
4137 if (left_direction) {
4138 new_bound = (jack_nframes_t) ((region.last_frame() + 1)/speed) - frame_delta;
4140 new_bound = (jack_nframes_t) ((region.last_frame() + 1)/speed) + frame_delta;
4144 snap_to (new_bound);
4146 region.trim_end ((jack_nframes_t) (new_bound * speed), this);
4147 rv.region_changed (LengthChanged);
4151 Editor::trim_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
4153 if (!drag_info.first_move) {
4154 trim_motion_callback (item, event);
4156 if (!clicked_regionview->get_selected()) {
4157 thaw_region_after_trim (*clicked_regionview);
4160 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin();
4161 i != selection->audio_regions.by_layer().end(); ++i)
4163 thaw_region_after_trim (**i);
4167 for (set<Playlist*>::iterator p = motion_frozen_playlists.begin(); p != motion_frozen_playlists.end(); ++p) {
4169 session->add_redo_no_execute ((*p)->get_memento());
4172 motion_frozen_playlists.clear ();
4174 commit_reversible_command();
4176 /* no mouse movement */
4182 Editor::point_trim (GdkEvent* event)
4184 AudioRegionView* rv = clicked_regionview;
4185 jack_nframes_t new_bound = drag_info.current_pointer_frame;
4187 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4188 snap_to (new_bound);
4191 /* Choose action dependant on which button was pressed */
4192 switch (event->button.button) {
4194 trim_op = StartTrim;
4195 begin_reversible_command (_("Start point trim"));
4197 if (rv->get_selected()) {
4199 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin();
4200 i != selection->audio_regions.by_layer().end(); ++i)
4202 if (!(*i)->region.locked()) {
4203 session->add_undo ((*i)->region.playlist()->get_memento());
4204 (*i)->region.trim_front (new_bound, this);
4205 session->add_redo_no_execute ((*i)->region.playlist()->get_memento());
4211 if (!rv->region.locked()) {
4212 session->add_undo (rv->region.playlist()->get_memento());
4213 rv->region.trim_front (new_bound, this);
4214 session->add_redo_no_execute (rv->region.playlist()->get_memento());
4218 commit_reversible_command();
4223 begin_reversible_command (_("End point trim"));
4225 if (rv->get_selected()) {
4227 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i)
4229 if (!(*i)->region.locked()) {
4230 session->add_undo ((*i)->region.playlist()->get_memento());
4231 (*i)->region.trim_end (new_bound, this);
4232 session->add_redo_no_execute ((*i)->region.playlist()->get_memento());
4238 if (!rv->region.locked()) {
4239 session->add_undo (rv->region.playlist()->get_memento());
4240 rv->region.trim_end (new_bound, this);
4241 session->add_redo_no_execute (rv->region.playlist()->get_memento());
4245 commit_reversible_command();
4254 Editor::thaw_region_after_trim (AudioRegionView& rv)
4256 Region& region (rv.region);
4258 if (region.locked()) {
4262 region.thaw (_("trimmed region"));
4263 session->add_redo_no_execute (region.playlist()->get_memento());
4265 rv.unhide_envelope ();
4269 Editor::hide_marker (ArdourCanvas::Item* item, GdkEvent* event)
4274 if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
4275 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
4279 Location* location = find_location_from_marker (marker, is_start);
4280 location->set_hidden (true, this);
4285 Editor::start_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event, RangeMarkerOp op)
4291 drag_info.item = item;
4292 drag_info.motion_callback = &Editor::drag_range_markerbar_op;
4293 drag_info.finished_callback = &Editor::end_range_markerbar_op;
4295 range_marker_op = op;
4297 if (!temp_location) {
4298 temp_location = new Location;
4302 case CreateRangeMarker:
4303 case CreateTransportMarker:
4305 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
4306 drag_info.copy = true;
4308 drag_info.copy = false;
4310 start_grab (event, selector_cursor);
4314 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
4319 Editor::drag_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event)
4321 jack_nframes_t start = 0;
4322 jack_nframes_t end = 0;
4323 ArdourCanvas::SimpleRect *crect = (range_marker_op == CreateRangeMarker) ? range_bar_drag_rect: transport_bar_drag_rect;
4325 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4326 snap_to (drag_info.current_pointer_frame);
4329 /* only alter selection if the current frame is
4330 different from the last frame position.
4333 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) return;
4335 switch (range_marker_op) {
4336 case CreateRangeMarker:
4337 case CreateTransportMarker:
4338 if (drag_info.first_move) {
4339 snap_to (drag_info.grab_frame);
4342 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4343 start = drag_info.current_pointer_frame;
4344 end = drag_info.grab_frame;
4346 end = drag_info.current_pointer_frame;
4347 start = drag_info.grab_frame;
4350 /* first drag: Either add to the selection
4351 or create a new selection.
4354 if (drag_info.first_move) {
4356 temp_location->set (start, end);
4360 update_marker_drag_item (temp_location);
4361 range_marker_drag_rect->show();
4362 range_marker_drag_rect->raise_to_top();
4368 if (event->button.x >= horizontal_adjustment.get_value() + canvas_width) {
4369 start_canvas_autoscroll (1);
4373 temp_location->set (start, end);
4375 double x1 = frame_to_pixel (start);
4376 double x2 = frame_to_pixel (end);
4377 crect->property_x1() = x1;
4378 crect->property_x2() = x2;
4380 update_marker_drag_item (temp_location);
4383 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4384 drag_info.first_move = false;
4386 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
4391 Editor::end_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event)
4393 Location * newloc = 0;
4395 if (!drag_info.first_move) {
4396 drag_range_markerbar_op (item, event);
4398 switch (range_marker_op) {
4399 case CreateRangeMarker:
4400 begin_reversible_command (_("new range marker"));
4401 session->add_undo (session->locations()->get_memento());
4402 newloc = new Location(temp_location->start(), temp_location->end(), "unnamed", Location::IsRangeMarker);
4403 session->locations()->add (newloc, true);
4404 session->add_redo_no_execute (session->locations()->get_memento());
4405 commit_reversible_command ();
4407 range_bar_drag_rect->hide();
4408 range_marker_drag_rect->hide();
4411 case CreateTransportMarker:
4412 // popup menu to pick loop or punch
4413 new_transport_marker_context_menu (&event->button, item);
4418 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
4420 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
4422 jack_nframes_t start;
4425 start = session->locations()->first_mark_before (drag_info.grab_frame);
4426 end = session->locations()->first_mark_after (drag_info.grab_frame);
4428 if (end == max_frames) {
4429 end = session->current_end_frame ();
4433 start = session->current_start_frame ();
4436 switch (mouse_mode) {
4438 /* find the two markers on either side and then make the selection from it */
4439 cerr << "select between " << start << " .. " << end << endl;
4440 select_all_within (start, end, 0.0f, FLT_MAX, Selection::Set);
4444 /* find the two markers on either side of the click and make the range out of it */
4445 selection->set (0, start, end);
4454 stop_canvas_autoscroll ();
4460 Editor::start_mouse_zoom (ArdourCanvas::Item* item, GdkEvent* event)
4462 drag_info.item = item;
4463 drag_info.motion_callback = &Editor::drag_mouse_zoom;
4464 drag_info.finished_callback = &Editor::end_mouse_zoom;
4466 start_grab (event, zoom_cursor);
4468 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4472 Editor::drag_mouse_zoom (ArdourCanvas::Item* item, GdkEvent* event)
4474 jack_nframes_t start;
4477 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4478 snap_to (drag_info.current_pointer_frame);
4480 if (drag_info.first_move) {
4481 snap_to (drag_info.grab_frame);
4485 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) return;
4487 /* base start and end on initial click position */
4488 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4489 start = drag_info.current_pointer_frame;
4490 end = drag_info.grab_frame;
4492 end = drag_info.current_pointer_frame;
4493 start = drag_info.grab_frame;
4498 if (drag_info.first_move) {
4500 zoom_rect->raise_to_top();
4503 reposition_zoom_rect(start, end);
4505 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4506 drag_info.first_move = false;
4508 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4513 Editor::end_mouse_zoom (ArdourCanvas::Item* item, GdkEvent* event)
4515 if (!drag_info.first_move) {
4516 drag_mouse_zoom (item, event);
4518 if (drag_info.grab_frame < drag_info.last_pointer_frame) {
4519 temporal_zoom_by_frame (drag_info.grab_frame, drag_info.last_pointer_frame, "mouse zoom");
4521 temporal_zoom_by_frame (drag_info.last_pointer_frame, drag_info.grab_frame, "mouse zoom");
4524 temporal_zoom_to_frame (false, drag_info.grab_frame);
4526 temporal_zoom_step (false);
4527 center_screen (drag_info.grab_frame);
4535 Editor::reposition_zoom_rect (jack_nframes_t start, jack_nframes_t end)
4537 double x1 = frame_to_pixel (start);
4538 double x2 = frame_to_pixel (end);
4539 double y2 = canvas_height - 2;
4541 zoom_rect->property_x1() = x1;
4542 zoom_rect->property_y1() = 1.0;
4543 zoom_rect->property_x2() = x2;
4544 zoom_rect->property_y2() = y2;
4548 Editor::start_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event)
4550 drag_info.item = item;
4551 drag_info.motion_callback = &Editor::drag_rubberband_select;
4552 drag_info.finished_callback = &Editor::end_rubberband_select;
4554 start_grab (event, cross_hair_cursor);
4556 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4560 Editor::drag_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event)
4562 jack_nframes_t start;
4567 /* use a bigger drag threshold than the default */
4569 if (abs ((int) (drag_info.current_pointer_frame - drag_info.grab_frame)) < 8) {
4573 // if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4574 // snap_to (drag_info.current_pointer_frame);
4576 // if (drag_info.first_move) {
4577 // snap_to (drag_info.grab_frame);
4582 /* base start and end on initial click position */
4583 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4584 start = drag_info.current_pointer_frame;
4585 end = drag_info.grab_frame;
4587 end = drag_info.current_pointer_frame;
4588 start = drag_info.grab_frame;
4591 if (drag_info.current_pointer_y < drag_info.grab_y) {
4592 y1 = drag_info.current_pointer_y;
4593 y2 = drag_info.grab_y;
4596 y2 = drag_info.current_pointer_y;
4597 y1 = drag_info.grab_y;
4601 if (start != end || y1 != y2) {
4603 double x1 = frame_to_pixel (start);
4604 double x2 = frame_to_pixel (end);
4606 rubberband_rect->property_x1() = x1;
4607 rubberband_rect->property_y1() = y1;
4608 rubberband_rect->property_x2() = x2;
4609 rubberband_rect->property_y2() = y2;
4611 rubberband_rect->show();
4612 rubberband_rect->raise_to_top();
4614 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4615 drag_info.first_move = false;
4617 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4622 Editor::end_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event)
4624 if (!drag_info.first_move) {
4626 drag_rubberband_select (item, event);
4629 if (drag_info.current_pointer_y < drag_info.grab_y) {
4630 y1 = drag_info.current_pointer_y;
4631 y2 = drag_info.grab_y;
4634 y2 = drag_info.current_pointer_y;
4635 y1 = drag_info.grab_y;
4639 Selection::Operation op = Keyboard::selection_type (event->button.state);
4642 begin_reversible_command (_("select regions"));
4644 if (drag_info.grab_frame < drag_info.last_pointer_frame) {
4645 commit = select_all_within (drag_info.grab_frame, drag_info.last_pointer_frame, y1, y2, op);
4647 commit = select_all_within (drag_info.last_pointer_frame, drag_info.grab_frame, y1, y2, op);
4651 commit_reversible_command ();
4655 selection->clear_audio_regions();
4656 selection->clear_points ();
4657 selection->clear_lines ();
4660 rubberband_rect->hide();
4665 Editor::mouse_rename_region (ArdourCanvas::Item* item, GdkEvent* event)
4667 using namespace Gtkmm2ext;
4669 ArdourPrompter prompter (false);
4671 prompter.set_prompt (_("Name for region:"));
4672 prompter.set_initial_text (clicked_regionview->region.name());
4673 prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
4674 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
4675 prompter.show_all ();
4676 switch (prompter.run ()) {
4677 case Gtk::RESPONSE_ACCEPT:
4679 prompter.get_result(str);
4681 clicked_regionview->region.set_name (str);
4689 Editor::start_time_fx (ArdourCanvas::Item* item, GdkEvent* event)
4691 drag_info.item = item;
4692 drag_info.motion_callback = &Editor::time_fx_motion;
4693 drag_info.finished_callback = &Editor::end_time_fx;
4697 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4701 Editor::time_fx_motion (ArdourCanvas::Item *item, GdkEvent* event)
4703 AudioRegionView* rv = clicked_regionview;
4705 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4706 snap_to (drag_info.current_pointer_frame);
4709 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) {
4713 if (drag_info.current_pointer_frame > rv->region.position()) {
4714 rv->get_time_axis_view().show_timestretch (rv->region.position(), drag_info.current_pointer_frame);
4717 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4718 drag_info.first_move = false;
4720 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4724 Editor::end_time_fx (ArdourCanvas::Item* item, GdkEvent* event)
4726 clicked_regionview->get_time_axis_view().hide_timestretch ();
4728 if (drag_info.first_move) {
4732 jack_nframes_t newlen = drag_info.last_pointer_frame - clicked_regionview->region.position();
4733 float percentage = (float) ((double) newlen - (double) clicked_regionview->region.length()) / ((double) newlen) * 100.0f;
4735 begin_reversible_command (_("timestretch"));
4737 if (run_timestretch (selection->audio_regions, percentage) == 0) {
4738 session->commit_reversible_command ();
4743 Editor::mouse_brush_insert_region (AudioRegionView* rv, jack_nframes_t pos)
4745 /* no brushing without a useful snap setting */
4747 switch (snap_mode) {
4749 return; /* can't work because it allows region to be placed anywhere */
4754 switch (snap_type) {
4757 case SnapToEditCursor:
4764 /* don't brush a copy over the original */
4766 if (pos == rv->region.position()) {
4770 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&rv->get_time_axis_view());
4772 if (atv == 0 || !atv->is_audio_track()) {
4776 Playlist* playlist = atv->playlist();
4777 double speed = atv->get_diskstream()->speed();
4779 session->add_undo (playlist->get_memento());
4780 playlist->add_region (*(new AudioRegion (rv->region)), (jack_nframes_t) (pos * speed));
4781 session->add_redo_no_execute (playlist->get_memento());
4783 // playlist is frozen, so we have to update manually
4785 playlist->StateChanged (Change (~0)); /* EMIT SIGNAL */
4789 Editor::track_height_step_timeout ()
4792 struct timeval delta;
4794 gettimeofday (&now, 0);
4795 timersub (&now, &last_track_height_step_timestamp, &delta);
4797 if (delta.tv_sec * 1000000 + delta.tv_usec > 250000) { /* milliseconds */
4798 current_stepping_trackview = 0;