2 Copyright (C) 2000-2001 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #include <pbd/error.h>
29 #include <gtkmm2ext/utils.h>
31 #include "ardour_ui.h"
33 #include "time_axis_view.h"
34 #include "audio_time_axis.h"
35 #include "regionview.h"
37 #include "streamview.h"
38 #include "region_gain_line.h"
39 #include "automation_time_axis.h"
42 #include "selection.h"
45 #include "rgb_macros.h"
47 #include <ardour/types.h>
48 #include <ardour/route.h>
49 #include <ardour/audio_track.h>
50 #include <ardour/diskstream.h>
51 #include <ardour/playlist.h>
52 #include <ardour/audioplaylist.h>
53 #include <ardour/audioregion.h>
54 #include <ardour/dB.h>
55 #include <ardour/utils.h>
56 #include <ardour/region_factory.h>
63 using namespace ARDOUR;
66 using namespace Editing;
69 Editor::event_frame (GdkEvent* event, double* pcx, double* pcy)
83 switch (event->type) {
84 case GDK_BUTTON_RELEASE:
85 case GDK_BUTTON_PRESS:
86 case GDK_2BUTTON_PRESS:
87 case GDK_3BUTTON_PRESS:
88 track_canvas.w2c(event->button.x, event->button.y, *pcx, *pcy);
90 case GDK_MOTION_NOTIFY:
91 track_canvas.w2c(event->motion.x, event->motion.y, *pcx, *pcy);
93 case GDK_ENTER_NOTIFY:
94 case GDK_LEAVE_NOTIFY:
95 track_canvas.w2c(event->crossing.x, event->crossing.y, *pcx, *pcy);
99 // track_canvas.w2c(event->key.x, event->key.y, *pcx, *pcy);
102 warning << string_compose (_("Editor::event_frame() used on unhandled event type %1"), event->type) << endmsg;
106 /* note that pixel_to_frame() never returns less than zero, so even if the pixel
107 position is negative (as can be the case with motion events in particular),
108 the frame location is always positive.
111 return pixel_to_frame (*pcx);
115 Editor::mouse_mode_toggled (MouseMode m)
117 if (ignore_mouse_mode_toggle) {
123 if (mouse_select_button.get_active()) {
129 if (mouse_move_button.get_active()) {
135 if (mouse_gain_button.get_active()) {
141 if (mouse_zoom_button.get_active()) {
147 if (mouse_timefx_button.get_active()) {
153 if (mouse_audition_button.get_active()) {
164 Editor::set_mouse_mode (MouseMode m, bool force)
166 if (drag_info.item) {
170 if (!force && m == mouse_mode) {
178 if (mouse_mode != MouseRange) {
180 /* in all modes except range, hide the range selection,
181 show the object (region) selection.
184 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
185 (*i)->set_should_show_selection (true);
187 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
188 (*i)->hide_selection ();
194 in range mode,show the range selection.
197 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
198 if ((*i)->selected()) {
199 (*i)->show_selection (selection->time);
204 /* XXX the hack of unsetting all other buttongs should go
205 away once GTK2 allows us to use regular radio buttons drawn like
206 normal buttons, rather than my silly GroupedButton hack.
209 ignore_mouse_mode_toggle = true;
211 switch (mouse_mode) {
213 mouse_select_button.set_active (true);
214 current_canvas_cursor = selector_cursor;
218 mouse_move_button.set_active (true);
219 current_canvas_cursor = grabber_cursor;
223 mouse_gain_button.set_active (true);
224 current_canvas_cursor = cross_hair_cursor;
228 mouse_zoom_button.set_active (true);
229 current_canvas_cursor = zoom_cursor;
233 mouse_timefx_button.set_active (true);
234 current_canvas_cursor = time_fx_cursor; // just use playhead
238 mouse_audition_button.set_active (true);
239 current_canvas_cursor = speaker_cursor;
243 ignore_mouse_mode_toggle = false;
246 track_canvas.get_window()->set_cursor(*current_canvas_cursor);
251 Editor::step_mouse_mode (bool next)
253 switch (current_mouse_mode()) {
255 if (next) set_mouse_mode (MouseRange);
256 else set_mouse_mode (MouseTimeFX);
260 if (next) set_mouse_mode (MouseZoom);
261 else set_mouse_mode (MouseObject);
265 if (next) set_mouse_mode (MouseGain);
266 else set_mouse_mode (MouseRange);
270 if (next) set_mouse_mode (MouseTimeFX);
271 else set_mouse_mode (MouseZoom);
275 if (next) set_mouse_mode (MouseAudition);
276 else set_mouse_mode (MouseGain);
280 if (next) set_mouse_mode (MouseObject);
281 else set_mouse_mode (MouseTimeFX);
287 Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
293 /* in object/audition/timefx mode, any button press sets
294 the selection if the object can be selected. this is a
295 bit of hack, because we want to avoid this if the
296 mouse operation is a region alignment.
298 note: not dbl-click or triple-click
301 if (((mouse_mode != MouseObject) &&
302 (mouse_mode != MouseAudition || item_type != RegionItem) &&
303 (mouse_mode != MouseTimeFX || item_type != RegionItem)) ||
304 (event->type != GDK_BUTTON_PRESS && event->type != GDK_BUTTON_RELEASE || event->button.button > 3)) {
309 Selection::Operation op = Keyboard::selection_type (event->button.state);
310 bool press = (event->type == GDK_BUTTON_PRESS);
312 begin_reversible_command (_("select on click"));
316 c1 = set_selected_track_from_click (press, op, true, true);
317 c2 = set_selected_regionview_from_click (press, op, true);
321 case AudioRegionViewNameHighlight:
322 case AudioRegionViewName:
323 c1 = set_selected_track_from_click (press, op, true, true);
324 c2 = set_selected_regionview_from_click (press, op, true);
328 case GainAutomationControlPointItem:
329 case PanAutomationControlPointItem:
330 case RedirectAutomationControlPointItem:
331 c1 = set_selected_track_from_click (press, op, true, true);
332 c2 = set_selected_control_point_from_click (press, op, false);
337 commit = set_selected_track_from_click (press, op, true, true);
340 case AutomationTrackItem:
341 commit = set_selected_track_from_click (press, op, true, true);
348 #define SELECT_TRACK_FROM_CANVAS_IN_RANGE_MODE
349 #ifdef SELECT_TRACK_FROM_CANVAS_IN_RANGE_MODE
350 /* in range mode, button 1/2/3 press potentially selects a track */
352 if (mouse_mode == MouseRange &&
353 event->type == GDK_BUTTON_PRESS &&
354 event->button.button <= 3) {
359 case AutomationTrackItem:
360 commit = set_selected_track_from_click (press, op, true, true);
369 commit_reversible_command ();
374 Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
376 jack_nframes_t where = event_frame (event, 0, 0);
378 track_canvas.grab_focus();
380 if (session && session->actively_recording()) {
384 button_selection (item, event, item_type);
386 if (drag_info.item == 0 &&
387 (Keyboard::is_delete_event (&event->button) ||
388 Keyboard::is_context_menu_event (&event->button) ||
389 Keyboard::is_edit_event (&event->button))) {
391 /* handled by button release */
395 switch (event->button.button) {
398 if (event->type == GDK_BUTTON_PRESS) {
400 if (drag_info.item) {
401 drag_info.item->ungrab (event->button.time);
404 /* single mouse clicks on any of these item types operate
405 independent of mouse mode, mostly because they are
406 not on the main track canvas or because we want
412 case PlayheadCursorItem:
413 start_cursor_grab (item, event);
417 if (Keyboard::modifier_state_equals (event->button.state,
418 Keyboard::ModifierMask(Keyboard::Control|Keyboard::Shift))) {
419 hide_marker (item, event);
421 start_marker_grab (item, event);
425 case TempoMarkerItem:
426 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
427 start_tempo_marker_copy_grab (item, event);
429 start_tempo_marker_grab (item, event);
433 case MeterMarkerItem:
434 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
435 start_meter_marker_copy_grab (item, event);
437 start_meter_marker_grab (item, event);
447 case RangeMarkerBarItem:
448 start_range_markerbar_op (item, event, CreateRangeMarker);
452 case TransportMarkerBarItem:
453 start_range_markerbar_op (item, event, CreateTransportMarker);
462 switch (mouse_mode) {
465 case StartSelectionTrimItem:
466 start_selection_op (item, event, SelectionStartTrim);
469 case EndSelectionTrimItem:
470 start_selection_op (item, event, SelectionEndTrim);
474 if (Keyboard::modifier_state_contains
475 (event->button.state, Keyboard::ModifierMask(Keyboard::Alt))) {
476 // contains and not equals because I can't use alt as a modifier alone.
477 start_selection_grab (item, event);
478 } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
479 /* grab selection for moving */
480 start_selection_op (item, event, SelectionMove);
483 /* this was debated, but decided the more common action was to
484 make a new selection */
485 start_selection_op (item, event, CreateSelection);
490 start_selection_op (item, event, CreateSelection);
496 if (Keyboard::modifier_state_contains (event->button.state,
497 Keyboard::ModifierMask(Keyboard::Control|Keyboard::Alt))
498 && event->type == GDK_BUTTON_PRESS) {
500 start_rubberband_select (item, event);
502 } else if (event->type == GDK_BUTTON_PRESS) {
505 case FadeInHandleItem:
506 start_fade_in_grab (item, event);
509 case FadeOutHandleItem:
510 start_fade_out_grab (item, event);
514 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
515 start_region_copy_grab (item, event);
516 } else if (Keyboard::the_keyboard().key_is_down (GDK_b)) {
517 start_region_brush_grab (item, event);
519 start_region_grab (item, event);
523 case AudioRegionViewNameHighlight:
524 start_trim (item, event);
528 case AudioRegionViewName:
529 /* rename happens on edit clicks */
530 start_trim (clicked_regionview->get_name_highlight(), event);
534 case GainAutomationControlPointItem:
535 case PanAutomationControlPointItem:
536 case RedirectAutomationControlPointItem:
537 start_control_point_grab (item, event);
541 case GainAutomationLineItem:
542 case PanAutomationLineItem:
543 case RedirectAutomationLineItem:
544 start_line_grab_from_line (item, event);
549 case AutomationTrackItem:
550 start_rubberband_select (item, event);
553 /* <CMT Additions> */
554 case ImageFrameHandleStartItem:
555 imageframe_start_handle_op(item, event) ;
558 case ImageFrameHandleEndItem:
559 imageframe_end_handle_op(item, event) ;
562 case MarkerViewHandleStartItem:
563 markerview_item_start_handle_op(item, event) ;
566 case MarkerViewHandleEndItem:
567 markerview_item_end_handle_op(item, event) ;
570 /* </CMT Additions> */
572 /* <CMT Additions> */
574 start_markerview_grab(item, event) ;
577 start_imageframe_grab(item, event) ;
579 /* </CMT Additions> */
595 // start_line_grab_from_regionview (item, event);
598 case GainControlPointItem:
599 start_control_point_grab (item, event);
603 start_line_grab_from_line (item, event);
606 case GainAutomationControlPointItem:
607 case PanAutomationControlPointItem:
608 case RedirectAutomationControlPointItem:
609 start_control_point_grab (item, event);
620 case GainAutomationControlPointItem:
621 case PanAutomationControlPointItem:
622 case RedirectAutomationControlPointItem:
623 start_control_point_grab (item, event);
626 case GainAutomationLineItem:
627 case PanAutomationLineItem:
628 case RedirectAutomationLineItem:
629 start_line_grab_from_line (item, event);
633 // XXX need automation mode to identify which
635 // start_line_grab_from_regionview (item, event);
645 if (event->type == GDK_BUTTON_PRESS) {
646 start_mouse_zoom (item, event);
653 if (item_type == RegionItem) {
654 start_time_fx (item, event);
659 /* handled in release */
668 switch (mouse_mode) {
670 if (event->type == GDK_BUTTON_PRESS) {
673 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
674 start_region_copy_grab (item, event);
676 start_region_grab (item, event);
680 case GainAutomationControlPointItem:
681 case PanAutomationControlPointItem:
682 case RedirectAutomationControlPointItem:
683 start_control_point_grab (item, event);
694 case AudioRegionViewNameHighlight:
695 start_trim (item, event);
699 case AudioRegionViewName:
700 start_trim (clicked_regionview->get_name_highlight(), event);
711 if (event->type == GDK_BUTTON_PRESS) {
712 /* relax till release */
719 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
720 temporal_zoom_session();
722 temporal_zoom_to_frame (true, event_frame(event));
737 switch (mouse_mode) {
739 //temporal_zoom_to_frame (true, where);
740 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
741 temporal_zoom_to_frame (true, where);
744 temporal_zoom_step (true);
749 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::Alt))) {
750 scroll_backward (0.6f);
753 else if (Keyboard::no_modifier_keys_pressed (&event->button)) {
754 scroll_tracks_up_line ();
756 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
757 if (clicked_trackview) {
758 if (!current_stepping_trackview) {
759 step_timeout = Glib::signal_timeout().connect (mem_fun(*this, &Editor::track_height_step_timeout), 500);
760 current_stepping_trackview = clicked_trackview;
762 gettimeofday (&last_track_height_step_timestamp, 0);
763 current_stepping_trackview->step_height (true);
766 else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
767 temporal_zoom_to_frame (true, where);
774 switch (mouse_mode) {
776 // temporal_zoom_to_frame (false, where);
777 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
778 temporal_zoom_to_frame (false, where);
781 temporal_zoom_step (false);
786 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::Alt))) {
787 scroll_forward (0.6f);
790 else if (Keyboard::no_modifier_keys_pressed (&event->button)) {
791 scroll_tracks_down_line ();
793 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
794 if (clicked_trackview) {
795 if (!current_stepping_trackview) {
796 step_timeout = Glib::signal_timeout().connect (mem_fun(*this, &Editor::track_height_step_timeout), 500);
797 current_stepping_trackview = clicked_trackview;
799 gettimeofday (&last_track_height_step_timestamp, 0);
800 current_stepping_trackview->step_height (false);
802 } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
803 temporal_zoom_to_frame (false, where);
818 Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
820 jack_nframes_t where = event_frame (event, 0, 0);
822 /* no action if we're recording */
824 if (session && session->actively_recording()) {
828 /* first, see if we're finishing a drag ... */
830 if (drag_info.item) {
831 if (end_grab (item, event)) {
832 /* grab dragged, so do nothing else */
837 button_selection (item, event, item_type);
839 /* edit events get handled here */
841 if (drag_info.item == 0 && Keyboard::is_edit_event (&event->button)) {
847 case TempoMarkerItem:
848 edit_tempo_marker (item);
851 case MeterMarkerItem:
852 edit_meter_marker (item);
855 case AudioRegionViewName:
856 if (clicked_regionview->name_active()) {
857 return mouse_rename_region (item, event);
867 /* context menu events get handled here */
869 if (Keyboard::is_context_menu_event (&event->button)) {
871 if (drag_info.item == 0) {
873 /* no matter which button pops up the context menu, tell the menu
874 widget to use button 1 to drive menu selection.
879 case FadeInHandleItem:
881 case FadeOutHandleItem:
882 popup_fade_context_menu (1, event->button.time, item, item_type);
886 popup_track_context_menu (1, event->button.time, item_type, false, where);
890 case AudioRegionViewNameHighlight:
891 case AudioRegionViewName:
892 popup_track_context_menu (1, event->button.time, item_type, false, where);
896 popup_track_context_menu (1, event->button.time, item_type, true, where);
899 case AutomationTrackItem:
900 popup_track_context_menu (1, event->button.time, item_type, false, where);
904 case RangeMarkerBarItem:
905 case TransportMarkerBarItem:
908 popup_ruler_menu (pixel_to_frame(event->button.x), item_type);
912 marker_context_menu (&event->button, item);
915 case TempoMarkerItem:
916 tm_marker_context_menu (&event->button, item);
919 case MeterMarkerItem:
920 tm_marker_context_menu (&event->button, item);
923 case CrossfadeViewItem:
924 popup_track_context_menu (1, event->button.time, item_type, false, where);
927 /* <CMT Additions> */
929 popup_imageframe_edit_menu(1, event->button.time, item, true) ;
931 case ImageFrameTimeAxisItem:
932 popup_imageframe_edit_menu(1, event->button.time, item, false) ;
935 popup_marker_time_axis_edit_menu(1, event->button.time, item, true) ;
937 case MarkerTimeAxisItem:
938 popup_marker_time_axis_edit_menu(1, event->button.time, item, false) ;
940 /* <CMT Additions> */
951 /* delete events get handled here */
953 if (drag_info.item == 0 && Keyboard::is_delete_event (&event->button)) {
956 case TempoMarkerItem:
957 remove_tempo_marker (item);
960 case MeterMarkerItem:
961 remove_meter_marker (item);
965 remove_marker (*item, event);
969 if (mouse_mode == MouseObject) {
970 remove_clicked_region ();
974 case GainControlPointItem:
975 if (mouse_mode == MouseGain) {
976 remove_gain_control_point (item, event);
980 case GainAutomationControlPointItem:
981 case PanAutomationControlPointItem:
982 case RedirectAutomationControlPointItem:
983 remove_control_point (item, event);
992 switch (event->button.button) {
996 /* see comments in button_press_handler */
998 case PlayheadCursorItem:
1001 case GainAutomationLineItem:
1002 case PanAutomationLineItem:
1003 case RedirectAutomationLineItem:
1004 case StartSelectionTrimItem:
1005 case EndSelectionTrimItem:
1009 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1010 snap_to (where, 0, true);
1012 mouse_add_new_marker (where);
1016 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1019 mouse_add_new_tempo_event (where);
1023 mouse_add_new_meter_event (pixel_to_frame (event->button.x));
1031 switch (mouse_mode) {
1033 switch (item_type) {
1034 case AutomationTrackItem:
1035 dynamic_cast<AutomationTimeAxisView*>(clicked_trackview)->add_automation_event
1049 switch (item_type) {
1051 clicked_regionview->add_gain_point_event (item, event);
1055 case AutomationTrackItem:
1056 dynamic_cast<AutomationTimeAxisView*>(clicked_trackview)->
1057 add_automation_event (item, event, where, event->button.y);
1066 switch (item_type) {
1068 audition_selected_region ();
1085 switch (mouse_mode) {
1088 switch (item_type) {
1090 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
1092 } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::ModifierMask (Keyboard::Shift|Keyboard::Alt))) {
1095 // Button2 click is unused
1108 // x_style_paste (where, 1.0);
1128 Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
1134 switch (item_type) {
1135 case GainControlPointItem:
1136 if (mouse_mode == MouseGain) {
1137 cp = static_cast<ControlPoint*>(item->get_data ("control_point"));
1138 cp->set_visible (true);
1142 at_y = cp->get_y ();
1143 cp->item->i2w (at_x, at_y);
1147 fraction = 1.0 - (cp->get_y() / cp->line.height());
1149 set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y);
1150 show_verbose_canvas_cursor ();
1152 if (is_drawable()) {
1153 track_canvas.get_window()->set_cursor (*fader_cursor);
1158 case GainAutomationControlPointItem:
1159 case PanAutomationControlPointItem:
1160 case RedirectAutomationControlPointItem:
1161 cp = static_cast<ControlPoint*>(item->get_data ("control_point"));
1162 cp->set_visible (true);
1166 at_y = cp->get_y ();
1167 cp->item->i2w (at_x, at_y);
1171 fraction = 1.0 - (cp->get_y() / cp->line.height());
1173 set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y);
1174 show_verbose_canvas_cursor ();
1176 if (is_drawable()) {
1177 track_canvas.get_window()->set_cursor (*fader_cursor);
1182 if (mouse_mode == MouseGain) {
1183 ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
1185 line->property_fill_color_rgba() = color_map[cEnteredGainLine];
1186 if (is_drawable()) {
1187 track_canvas.get_window()->set_cursor (*fader_cursor);
1192 case GainAutomationLineItem:
1193 case RedirectAutomationLineItem:
1194 case PanAutomationLineItem:
1196 ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
1198 line->property_fill_color_rgba() = color_map[cEnteredAutomationLine];
1200 if (is_drawable()) {
1201 track_canvas.get_window()->set_cursor (*fader_cursor);
1205 case AudioRegionViewNameHighlight:
1206 if (is_drawable() && mouse_mode == MouseObject) {
1207 track_canvas.get_window()->set_cursor (*trimmer_cursor);
1211 case StartSelectionTrimItem:
1212 case EndSelectionTrimItem:
1213 /* <CMT Additions> */
1214 case ImageFrameHandleStartItem:
1215 case ImageFrameHandleEndItem:
1216 case MarkerViewHandleStartItem:
1217 case MarkerViewHandleEndItem:
1218 /* </CMT Additions> */
1220 if (is_drawable()) {
1221 track_canvas.get_window()->set_cursor (*trimmer_cursor);
1225 case EditCursorItem:
1226 case PlayheadCursorItem:
1227 if (is_drawable()) {
1228 track_canvas.get_window()->set_cursor (*grabber_cursor);
1232 case AudioRegionViewName:
1234 /* when the name is not an active item, the entire name highlight is for trimming */
1236 if (!reinterpret_cast<AudioRegionView *> (item->get_data ("regionview"))->name_active()) {
1237 if (mouse_mode == MouseObject && is_drawable()) {
1238 track_canvas.get_window()->set_cursor (*trimmer_cursor);
1244 case AutomationTrackItem:
1245 if (is_drawable()) {
1246 Gdk::Cursor *cursor;
1247 switch (mouse_mode) {
1249 cursor = selector_cursor;
1252 cursor = zoom_cursor;
1255 cursor = cross_hair_cursor;
1259 track_canvas.get_window()->set_cursor (*cursor);
1261 AutomationTimeAxisView* atv;
1262 if ((atv = static_cast<AutomationTimeAxisView*>(item->get_data ("trackview"))) != 0) {
1263 clear_entered_track = false;
1264 set_entered_track (atv);
1270 case RangeMarkerBarItem:
1271 case TransportMarkerBarItem:
1274 if (is_drawable()) {
1275 time_canvas.get_window()->set_cursor (*timebar_cursor);
1280 if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
1283 marker->set_color_rgba (color_map[cEnteredMarker]);
1285 case MeterMarkerItem:
1286 case TempoMarkerItem:
1287 if (is_drawable()) {
1288 time_canvas.get_window()->set_cursor (*timebar_cursor);
1291 case FadeInHandleItem:
1292 case FadeOutHandleItem:
1293 if (mouse_mode == MouseObject) {
1294 ArdourCanvas::SimpleRect *rect = dynamic_cast<ArdourCanvas::SimpleRect *> (item);
1296 rect->property_fill_color_rgba() = 0;
1297 rect->property_outline_pixels() = 1;
1306 /* second pass to handle entered track status in a comprehensible way.
1309 switch (item_type) {
1311 case GainAutomationLineItem:
1312 case RedirectAutomationLineItem:
1313 case PanAutomationLineItem:
1314 case GainControlPointItem:
1315 case GainAutomationControlPointItem:
1316 case PanAutomationControlPointItem:
1317 case RedirectAutomationControlPointItem:
1318 /* these do not affect the current entered track state */
1319 clear_entered_track = false;
1322 case AutomationTrackItem:
1323 /* handled above already */
1327 set_entered_track (0);
1335 Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
1341 AudioRegionView* rv;
1344 switch (item_type) {
1345 case GainControlPointItem:
1346 case GainAutomationControlPointItem:
1347 case PanAutomationControlPointItem:
1348 case RedirectAutomationControlPointItem:
1349 cp = reinterpret_cast<ControlPoint*>(item->get_data ("control_point"));
1350 if (cp->line.npoints() > 1) {
1351 if (!cp->selected) {
1352 cp->set_visible (false);
1356 if (is_drawable()) {
1357 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
1360 hide_verbose_canvas_cursor ();
1363 case AudioRegionViewNameHighlight:
1364 case StartSelectionTrimItem:
1365 case EndSelectionTrimItem:
1366 case EditCursorItem:
1367 case PlayheadCursorItem:
1368 /* <CMT Additions> */
1369 case ImageFrameHandleStartItem:
1370 case ImageFrameHandleEndItem:
1371 case MarkerViewHandleStartItem:
1372 case MarkerViewHandleEndItem:
1373 /* </CMT Additions> */
1374 if (is_drawable()) {
1375 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
1380 case GainAutomationLineItem:
1381 case RedirectAutomationLineItem:
1382 case PanAutomationLineItem:
1383 al = reinterpret_cast<AutomationLine*> (item->get_data ("line"));
1385 ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
1387 line->property_fill_color_rgba() = al->get_line_color();
1389 if (is_drawable()) {
1390 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
1394 case AudioRegionViewName:
1395 /* see enter_handler() for notes */
1396 if (!reinterpret_cast<AudioRegionView *> (item->get_data ("regionview"))->name_active()) {
1397 if (is_drawable() && mouse_mode == MouseObject) {
1398 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
1403 case RangeMarkerBarItem:
1404 case TransportMarkerBarItem:
1408 if (is_drawable()) {
1409 time_canvas.get_window()->set_cursor (*timebar_cursor);
1414 if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
1417 loc = find_location_from_marker (marker, is_start);
1418 if (loc) location_flags_changed (loc, this);
1420 case MeterMarkerItem:
1421 case TempoMarkerItem:
1423 if (is_drawable()) {
1424 time_canvas.get_window()->set_cursor (*timebar_cursor);
1429 case FadeInHandleItem:
1430 case FadeOutHandleItem:
1431 rv = static_cast<AudioRegionView*>(item->get_data ("regionview"));
1433 ArdourCanvas::SimpleRect *rect = dynamic_cast<ArdourCanvas::SimpleRect *> (item);
1435 rect->property_fill_color_rgba() = rv->get_fill_color();
1436 rect->property_outline_pixels() = 0;
1441 case AutomationTrackItem:
1442 if (is_drawable()) {
1443 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
1444 clear_entered_track = true;
1445 Glib::signal_idle().connect (mem_fun(*this, &Editor::left_automation_track));
1457 Editor::left_automation_track ()
1459 if (clear_entered_track) {
1460 set_entered_track (0);
1461 clear_entered_track = false;
1467 Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type, bool from_autoscroll)
1471 /* We call this so that MOTION_NOTIFY events continue to be
1472 delivered to the canvas. We need to do this because we set
1473 Gdk::POINTER_MOTION_HINT_MASK on the canvas. This reduces
1474 the density of the events, at the expense of a round-trip
1475 to the server. Given that this will mostly occur on cases
1476 where DISPLAY = :0.0, and given the cost of what the motion
1477 event might do, its a good tradeoff.
1480 track_canvas.get_pointer (x, y);
1482 if (current_stepping_trackview) {
1483 /* don't keep the persistent stepped trackview if the mouse moves */
1484 current_stepping_trackview = 0;
1485 step_timeout.disconnect ();
1488 if (session && session->actively_recording()) {
1489 /* Sorry. no dragging stuff around while we record */
1493 drag_info.item_type = item_type;
1494 drag_info.current_pointer_frame = event_frame (event, &drag_info.current_pointer_x,
1495 &drag_info.current_pointer_y);
1497 if (!from_autoscroll && drag_info.item) {
1498 /* item != 0 is the best test i can think of for dragging.
1500 if (!drag_info.move_threshold_passed) {
1502 drag_info.move_threshold_passed = (abs ((int) (drag_info.current_pointer_x - drag_info.grab_x)) > 4);
1504 // and change the initial grab loc/frame if this drag info wants us to
1506 if (drag_info.want_move_threshold && drag_info.move_threshold_passed) {
1507 drag_info.grab_frame = drag_info.current_pointer_frame;
1508 drag_info.grab_x = drag_info.current_pointer_x;
1509 drag_info.grab_y = drag_info.current_pointer_y;
1510 drag_info.last_pointer_frame = drag_info.grab_frame;
1511 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
1516 switch (item_type) {
1517 case PlayheadCursorItem:
1518 case EditCursorItem:
1520 case GainControlPointItem:
1521 case RedirectAutomationControlPointItem:
1522 case GainAutomationControlPointItem:
1523 case PanAutomationControlPointItem:
1524 case TempoMarkerItem:
1525 case MeterMarkerItem:
1526 case AudioRegionViewNameHighlight:
1527 case StartSelectionTrimItem:
1528 case EndSelectionTrimItem:
1531 case RedirectAutomationLineItem:
1532 case GainAutomationLineItem:
1533 case PanAutomationLineItem:
1534 case FadeInHandleItem:
1535 case FadeOutHandleItem:
1536 /* <CMT Additions> */
1537 case ImageFrameHandleStartItem:
1538 case ImageFrameHandleEndItem:
1539 case MarkerViewHandleStartItem:
1540 case MarkerViewHandleEndItem:
1541 /* </CMT Additions> */
1542 if (drag_info.item && (event->motion.state & Gdk::BUTTON1_MASK ||
1543 (event->motion.state & Gdk::BUTTON2_MASK))) {
1544 if (!from_autoscroll) {
1545 maybe_autoscroll (event);
1547 (this->*(drag_info.motion_callback)) (item, event);
1556 switch (mouse_mode) {
1561 if (drag_info.item && (event->motion.state & GDK_BUTTON1_MASK ||
1562 (event->motion.state & GDK_BUTTON2_MASK))) {
1563 if (!from_autoscroll) {
1564 maybe_autoscroll (event);
1566 (this->*(drag_info.motion_callback)) (item, event);
1577 track_canvas_motion (event);
1578 // drag_info.last_pointer_frame = drag_info.current_pointer_frame;
1586 Editor::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
1588 if (drag_info.item == 0) {
1589 fatal << _("programming error: start_grab called without drag item") << endmsg;
1595 cursor = grabber_cursor;
1598 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
1600 if (event->button.button == 2) {
1601 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Alt)) {
1602 drag_info.y_constrained = true;
1603 drag_info.x_constrained = false;
1605 drag_info.y_constrained = false;
1606 drag_info.x_constrained = true;
1609 drag_info.x_constrained = false;
1610 drag_info.y_constrained = false;
1613 drag_info.grab_frame = event_frame(event, &drag_info.grab_x, &drag_info.grab_y);
1614 drag_info.last_pointer_frame = drag_info.grab_frame;
1615 drag_info.current_pointer_frame = drag_info.grab_frame;
1616 drag_info.current_pointer_x = drag_info.grab_x;
1617 drag_info.current_pointer_y = drag_info.grab_y;
1618 drag_info.cumulative_x_drag = 0;
1619 drag_info.cumulative_y_drag = 0;
1620 drag_info.first_move = true;
1621 drag_info.move_threshold_passed = false;
1622 drag_info.want_move_threshold = false;
1623 drag_info.pointer_frame_offset = 0;
1624 drag_info.brushing = false;
1625 drag_info.copied_location = 0;
1627 drag_info.item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
1629 event->button.time);
1631 if (session && session->transport_rolling()) {
1632 drag_info.was_rolling = true;
1634 drag_info.was_rolling = false;
1637 switch (snap_type) {
1638 case SnapToRegionStart:
1639 case SnapToRegionEnd:
1640 case SnapToRegionSync:
1641 case SnapToRegionBoundary:
1642 build_region_boundary_cache ();
1650 Editor::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t time)
1652 drag_info.item->ungrab (0);
1653 drag_info.item = new_item;
1656 cursor = grabber_cursor;
1659 drag_info.item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK, *cursor, time);
1663 Editor::end_grab (ArdourCanvas::Item* item, GdkEvent* event)
1665 bool did_drag = false;
1667 stop_canvas_autoscroll ();
1669 if (drag_info.item == 0) {
1673 drag_info.item->ungrab (event->button.time);
1675 if (drag_info.finished_callback) {
1676 (this->*(drag_info.finished_callback)) (item, event);
1679 did_drag = !drag_info.first_move;
1681 hide_verbose_canvas_cursor();
1684 drag_info.copy = false;
1685 drag_info.motion_callback = 0;
1686 drag_info.finished_callback = 0;
1687 drag_info.last_trackview = 0;
1688 drag_info.last_frame_position = 0;
1689 drag_info.grab_frame = 0;
1690 drag_info.last_pointer_frame = 0;
1691 drag_info.current_pointer_frame = 0;
1692 drag_info.brushing = false;
1694 if (drag_info.copied_location) {
1695 delete drag_info.copied_location;
1696 drag_info.copied_location = 0;
1703 Editor::set_edit_cursor (GdkEvent* event)
1705 jack_nframes_t pointer_frame = event_frame (event);
1707 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1708 if (snap_type != SnapToEditCursor) {
1709 snap_to (pointer_frame);
1713 edit_cursor->set_position (pointer_frame);
1714 edit_cursor_clock.set (pointer_frame);
1718 Editor::set_playhead_cursor (GdkEvent* event)
1720 jack_nframes_t pointer_frame = event_frame (event);
1722 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1723 snap_to (pointer_frame);
1727 session->request_locate (pointer_frame, session->transport_rolling());
1732 Editor::start_fade_in_grab (ArdourCanvas::Item* item, GdkEvent* event)
1734 drag_info.item = item;
1735 drag_info.motion_callback = &Editor::fade_in_drag_motion_callback;
1736 drag_info.finished_callback = &Editor::fade_in_drag_finished_callback;
1740 if ((drag_info.data = (item->get_data ("regionview"))) == 0) {
1741 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1745 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1747 drag_info.pointer_frame_offset = drag_info.grab_frame - ((jack_nframes_t) arv->region.fade_in().back()->when + arv->region.position());
1751 Editor::fade_in_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
1753 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1755 jack_nframes_t fade_length;
1757 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1758 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1764 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1768 if (pos < (arv->region.position() + 64)) {
1769 fade_length = 64; // this should be a minimum defined somewhere
1770 } else if (pos > arv->region.last_frame()) {
1771 fade_length = arv->region.length();
1773 fade_length = pos - arv->region.position();
1776 arv->reset_fade_in_shape_width (fade_length);
1778 show_verbose_duration_cursor (arv->region.position(), arv->region.position() + fade_length, 10);
1780 drag_info.first_move = false;
1784 Editor::fade_in_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
1786 if (drag_info.first_move) return;
1788 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1790 jack_nframes_t fade_length;
1792 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1793 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1799 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1803 if (pos < (arv->region.position() + 64)) {
1804 fade_length = 64; // this should be a minimum defined somewhere
1806 else if (pos > arv->region.last_frame()) {
1807 fade_length = arv->region.length();
1810 fade_length = pos - arv->region.position();
1813 begin_reversible_command (_("change fade in length"));
1814 session->add_undo (arv->region.get_memento());
1815 arv->region.set_fade_in_length (fade_length);
1816 session->add_redo_no_execute (arv->region.get_memento());
1817 commit_reversible_command ();
1818 fade_in_drag_motion_callback (item, event);
1822 Editor::start_fade_out_grab (ArdourCanvas::Item* item, GdkEvent* event)
1824 drag_info.item = item;
1825 drag_info.motion_callback = &Editor::fade_out_drag_motion_callback;
1826 drag_info.finished_callback = &Editor::fade_out_drag_finished_callback;
1830 if ((drag_info.data = (item->get_data ("regionview"))) == 0) {
1831 fatal << _("programming error: fade out canvas item has no regionview data pointer!") << endmsg;
1835 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1837 drag_info.pointer_frame_offset = drag_info.grab_frame - (arv->region.length() - (jack_nframes_t) arv->region.fade_out().back()->when + arv->region.position());
1841 Editor::fade_out_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
1843 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1845 jack_nframes_t fade_length;
1847 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1848 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1854 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1858 if (pos > (arv->region.last_frame() - 64)) {
1859 fade_length = 64; // this should really be a minimum fade defined somewhere
1861 else if (pos < arv->region.position()) {
1862 fade_length = arv->region.length();
1865 fade_length = arv->region.last_frame() - pos;
1868 arv->reset_fade_out_shape_width (fade_length);
1870 show_verbose_duration_cursor (arv->region.last_frame() - fade_length, arv->region.last_frame(), 10);
1872 drag_info.first_move = false;
1876 Editor::fade_out_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
1878 if (drag_info.first_move) return;
1880 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1882 jack_nframes_t fade_length;
1884 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1885 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1891 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1895 if (pos > (arv->region.last_frame() - 64)) {
1896 fade_length = 64; // this should really be a minimum fade defined somewhere
1898 else if (pos < arv->region.position()) {
1899 fade_length = arv->region.length();
1902 fade_length = arv->region.last_frame() - pos;
1905 begin_reversible_command (_("change fade out length"));
1906 session->add_undo (arv->region.get_memento());
1907 arv->region.set_fade_out_length (fade_length);
1908 session->add_redo_no_execute (arv->region.get_memento());
1909 commit_reversible_command ();
1911 fade_out_drag_motion_callback (item, event);
1915 Editor::start_cursor_grab (ArdourCanvas::Item* item, GdkEvent* event)
1917 drag_info.item = item;
1918 drag_info.motion_callback = &Editor::cursor_drag_motion_callback;
1919 drag_info.finished_callback = &Editor::cursor_drag_finished_callback;
1923 if ((drag_info.data = (item->get_data ("cursor"))) == 0) {
1924 fatal << _("programming error: cursor canvas item has no cursor data pointer!") << endmsg;
1928 Cursor* cursor = (Cursor *) drag_info.data;
1930 if (session && cursor == playhead_cursor) {
1931 if (drag_info.was_rolling) {
1932 session->request_stop ();
1936 drag_info.pointer_frame_offset = drag_info.grab_frame - cursor->current_frame;
1938 show_verbose_time_cursor (cursor->current_frame, 10);
1942 Editor::cursor_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
1944 Cursor* cursor = (Cursor *) drag_info.data;
1945 jack_nframes_t adjusted_frame;
1947 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1948 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1954 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1955 if (cursor != edit_cursor || snap_type != SnapToEditCursor) {
1956 snap_to (adjusted_frame);
1960 if (adjusted_frame == drag_info.last_pointer_frame) return;
1962 cursor->set_position (adjusted_frame);
1964 if (cursor == edit_cursor) {
1965 edit_cursor_clock.set (cursor->current_frame);
1968 show_verbose_time_cursor (cursor->current_frame, 10);
1970 drag_info.last_pointer_frame = adjusted_frame;
1971 drag_info.first_move = false;
1975 Editor::cursor_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
1977 if (drag_info.first_move) return;
1979 cursor_drag_motion_callback (item, event);
1981 if (item == &playhead_cursor->canvas_item) {
1983 session->request_locate (playhead_cursor->current_frame, drag_info.was_rolling);
1985 } else if (item == &edit_cursor->canvas_item) {
1986 edit_cursor->set_position (edit_cursor->current_frame);
1987 edit_cursor_clock.set (edit_cursor->current_frame);
1992 Editor::update_marker_drag_item (Location *location)
1994 double x1 = frame_to_pixel (location->start());
1995 double x2 = frame_to_pixel (location->end());
1997 if (location->is_mark()) {
1998 marker_drag_line_points.front().set_x(x1);
1999 marker_drag_line_points.back().set_x(x1);
2000 marker_drag_line->property_points() = marker_drag_line_points;
2003 range_marker_drag_rect->property_x1() = x1;
2004 range_marker_drag_rect->property_x2() = x2;
2009 Editor::start_marker_grab (ArdourCanvas::Item* item, GdkEvent* event)
2013 if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
2014 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
2020 Location *location = find_location_from_marker (marker, is_start);
2022 drag_info.item = item;
2023 drag_info.data = marker;
2024 drag_info.motion_callback = &Editor::marker_drag_motion_callback;
2025 drag_info.finished_callback = &Editor::marker_drag_finished_callback;
2029 drag_info.copied_location = new Location (*location);
2030 drag_info.pointer_frame_offset = drag_info.grab_frame - (is_start ? location->start() : location->end());
2032 update_marker_drag_item (location);
2034 if (location->is_mark()) {
2035 marker_drag_line->show();
2036 marker_drag_line->raise_to_top();
2039 range_marker_drag_rect->show();
2040 range_marker_drag_rect->raise_to_top();
2043 if (is_start) show_verbose_time_cursor (location->start(), 10);
2044 else show_verbose_time_cursor (location->end(), 10);
2048 Editor::marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2050 jack_nframes_t f_delta;
2051 Marker* marker = (Marker *) drag_info.data;
2052 Location *real_location;
2053 Location *copy_location;
2055 bool move_both = false;
2058 jack_nframes_t newframe;
2059 if (drag_info.pointer_frame_offset <= (long) drag_info.current_pointer_frame) {
2060 newframe = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2066 jack_nframes_t next = newframe;
2068 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2069 snap_to (newframe, 0, true);
2072 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) {
2076 /* call this to find out if its the start or end */
2078 real_location = find_location_from_marker (marker, is_start);
2080 /* use the copy that we're "dragging" around */
2082 copy_location = drag_info.copied_location;
2084 f_delta = copy_location->end() - copy_location->start();
2086 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
2090 if (is_start) { // start marker
2093 copy_location->set_start (newframe);
2094 copy_location->set_end (newframe + f_delta);
2095 } else if (newframe < copy_location->end()) {
2096 copy_location->set_start (newframe);
2098 snap_to (next, 1, true);
2099 copy_location->set_end (next);
2100 copy_location->set_start (newframe);
2103 } else { // end marker
2106 copy_location->set_end (newframe);
2107 copy_location->set_start (newframe - f_delta);
2108 } else if (newframe > copy_location->start()) {
2109 copy_location->set_end (newframe);
2111 } else if (newframe > 0) {
2112 snap_to (next, -1, true);
2113 copy_location->set_start (next);
2114 copy_location->set_end (newframe);
2118 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
2119 drag_info.first_move = false;
2121 update_marker_drag_item (copy_location);
2123 LocationMarkers* lm = find_location_markers (real_location);
2124 lm->set_position (copy_location->start(), copy_location->end());
2126 show_verbose_time_cursor (newframe, 10);
2130 Editor::marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2132 if (drag_info.first_move) {
2133 marker_drag_motion_callback (item, event);
2137 Marker* marker = (Marker *) drag_info.data;
2141 begin_reversible_command ( _("move marker") );
2142 session->add_undo( session->locations()->get_memento() );
2144 Location * location = find_location_from_marker (marker, is_start);
2147 location->set (drag_info.copied_location->start(), drag_info.copied_location->end());
2150 session->add_redo_no_execute( session->locations()->get_memento() );
2151 commit_reversible_command ();
2153 marker_drag_line->hide();
2154 range_marker_drag_rect->hide();
2158 Editor::start_meter_marker_grab (ArdourCanvas::Item* item, GdkEvent* event)
2161 MeterMarker* meter_marker;
2163 if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
2164 fatal << _("programming error: meter marker canvas item has no marker object pointer!") << endmsg;
2168 meter_marker = dynamic_cast<MeterMarker*> (marker);
2170 MetricSection& section (meter_marker->meter());
2172 if (!section.movable()) {
2176 drag_info.item = item;
2177 drag_info.data = marker;
2178 drag_info.motion_callback = &Editor::meter_marker_drag_motion_callback;
2179 drag_info.finished_callback = &Editor::meter_marker_drag_finished_callback;
2183 drag_info.pointer_frame_offset = drag_info.grab_frame - meter_marker->meter().frame();
2185 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2189 Editor::start_meter_marker_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
2192 MeterMarker* meter_marker;
2194 if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
2195 fatal << _("programming error: meter marker canvas item has no marker object pointer!") << endmsg;
2199 meter_marker = dynamic_cast<MeterMarker*> (marker);
2201 // create a dummy marker for visual representation of moving the copy.
2202 // The actual copying is not done before we reach the finish callback.
2204 snprintf (name, sizeof(name), "%g/%g", meter_marker->meter().beats_per_bar(), meter_marker->meter().note_divisor ());
2205 MeterMarker* new_marker = new MeterMarker(*this, *meter_group, color_map[cMeterMarker], name,
2206 *new MeterSection(meter_marker->meter()));
2208 drag_info.item = &new_marker->the_item();
2209 drag_info.copy = true;
2210 drag_info.data = new_marker;
2211 drag_info.motion_callback = &Editor::meter_marker_drag_motion_callback;
2212 drag_info.finished_callback = &Editor::meter_marker_drag_finished_callback;
2216 drag_info.pointer_frame_offset = drag_info.grab_frame - meter_marker->meter().frame();
2218 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2222 Editor::meter_marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2224 MeterMarker* marker = (MeterMarker *) drag_info.data;
2225 jack_nframes_t adjusted_frame;
2227 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
2228 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2234 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2235 snap_to (adjusted_frame);
2238 if (adjusted_frame == drag_info.last_pointer_frame) return;
2240 marker->set_position (adjusted_frame);
2243 drag_info.last_pointer_frame = adjusted_frame;
2244 drag_info.first_move = false;
2246 show_verbose_time_cursor (adjusted_frame, 10);
2250 Editor::meter_marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2252 if (drag_info.first_move) return;
2254 meter_marker_drag_motion_callback (drag_info.item, event);
2256 MeterMarker* marker = (MeterMarker *) drag_info.data;
2259 TempoMap& map (session->tempo_map());
2260 map.bbt_time (drag_info.last_pointer_frame, when);
2262 if (drag_info.copy == true) {
2263 begin_reversible_command (_("copy meter mark"));
2264 session->add_undo (map.get_memento());
2265 map.add_meter (marker->meter(), when);
2266 session->add_redo_no_execute (map.get_memento());
2267 commit_reversible_command ();
2269 // delete the dummy marker we used for visual representation of copying.
2270 // a new visual marker will show up automatically.
2273 begin_reversible_command (_("move meter mark"));
2274 session->add_undo (map.get_memento());
2275 map.move_meter (marker->meter(), when);
2276 session->add_redo_no_execute (map.get_memento());
2277 commit_reversible_command ();
2282 Editor::start_tempo_marker_grab (ArdourCanvas::Item* item, GdkEvent* event)
2285 TempoMarker* tempo_marker;
2287 if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
2288 fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg;
2292 if ((tempo_marker = dynamic_cast<TempoMarker *> (marker)) == 0) {
2293 fatal << _("programming error: marker for tempo is not a tempo marker!") << endmsg;
2297 MetricSection& section (tempo_marker->tempo());
2299 if (!section.movable()) {
2303 drag_info.item = item;
2304 drag_info.data = marker;
2305 drag_info.motion_callback = &Editor::tempo_marker_drag_motion_callback;
2306 drag_info.finished_callback = &Editor::tempo_marker_drag_finished_callback;
2310 drag_info.pointer_frame_offset = drag_info.grab_frame - tempo_marker->tempo().frame();
2311 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2315 Editor::start_tempo_marker_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
2318 TempoMarker* tempo_marker;
2320 if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
2321 fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg;
2325 if ((tempo_marker = dynamic_cast<TempoMarker *> (marker)) == 0) {
2326 fatal << _("programming error: marker for tempo is not a tempo marker!") << endmsg;
2330 // create a dummy marker for visual representation of moving the copy.
2331 // The actual copying is not done before we reach the finish callback.
2333 snprintf (name, sizeof (name), "%.2f", tempo_marker->tempo().beats_per_minute());
2334 TempoMarker* new_marker = new TempoMarker(*this, *tempo_group, color_map[cTempoMarker], name,
2335 *new TempoSection(tempo_marker->tempo()));
2337 drag_info.item = &new_marker->the_item();
2338 drag_info.copy = true;
2339 drag_info.data = new_marker;
2340 drag_info.motion_callback = &Editor::tempo_marker_drag_motion_callback;
2341 drag_info.finished_callback = &Editor::tempo_marker_drag_finished_callback;
2345 drag_info.pointer_frame_offset = drag_info.grab_frame - tempo_marker->tempo().frame();
2347 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2351 Editor::tempo_marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2353 TempoMarker* marker = (TempoMarker *) drag_info.data;
2354 jack_nframes_t adjusted_frame;
2356 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
2357 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2363 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2364 snap_to (adjusted_frame);
2367 if (adjusted_frame == drag_info.last_pointer_frame) return;
2369 /* OK, we've moved far enough to make it worth actually move the thing. */
2371 marker->set_position (adjusted_frame);
2373 show_verbose_time_cursor (adjusted_frame, 10);
2375 drag_info.last_pointer_frame = adjusted_frame;
2376 drag_info.first_move = false;
2380 Editor::tempo_marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2382 if (drag_info.first_move) return;
2384 tempo_marker_drag_motion_callback (drag_info.item, event);
2386 TempoMarker* marker = (TempoMarker *) drag_info.data;
2389 TempoMap& map (session->tempo_map());
2390 map.bbt_time (drag_info.last_pointer_frame, when);
2392 if (drag_info.copy == true) {
2393 begin_reversible_command (_("copy tempo mark"));
2394 session->add_undo (map.get_memento());
2395 map.add_tempo (marker->tempo(), when);
2396 session->add_redo_no_execute (map.get_memento());
2397 commit_reversible_command ();
2399 // delete the dummy marker we used for visual representation of copying.
2400 // a new visual marker will show up automatically.
2403 begin_reversible_command (_("move tempo mark"));
2404 session->add_undo (map.get_memento());
2405 map.move_tempo (marker->tempo(), when);
2406 session->add_redo_no_execute (map.get_memento());
2407 commit_reversible_command ();
2412 Editor::remove_gain_control_point (ArdourCanvas::Item*item, GdkEvent* event)
2414 ControlPoint* control_point;
2416 if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
2417 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2421 // We shouldn't remove the first or last gain point
2422 if (control_point->line.is_last_point(*control_point) ||
2423 control_point->line.is_first_point(*control_point)) {
2427 control_point->line.remove_point (*control_point);
2431 Editor::remove_control_point (ArdourCanvas::Item*item, GdkEvent* event)
2433 ControlPoint* control_point;
2435 if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
2436 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2440 control_point->line.remove_point (*control_point);
2444 Editor::start_control_point_grab (ArdourCanvas::Item* item, GdkEvent* event)
2446 ControlPoint* control_point;
2448 if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
2449 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2453 drag_info.item = item;
2454 drag_info.data = control_point;
2455 drag_info.motion_callback = &Editor::control_point_drag_motion_callback;
2456 drag_info.finished_callback = &Editor::control_point_drag_finished_callback;
2458 start_grab (event, fader_cursor);
2460 control_point->line.start_drag (control_point, 0);
2462 float fraction = 1.0 - (control_point->get_y() / control_point->line.height());
2463 set_verbose_canvas_cursor (control_point->line.get_verbose_cursor_string (fraction),
2464 drag_info.current_pointer_x + 20, drag_info.current_pointer_y + 20);
2466 show_verbose_canvas_cursor ();
2470 Editor::control_point_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2472 ControlPoint* cp = reinterpret_cast<ControlPoint *> (drag_info.data);
2474 double cx = drag_info.current_pointer_x;
2475 double cy = drag_info.current_pointer_y;
2477 drag_info.cumulative_x_drag = cx - drag_info.grab_x ;
2478 drag_info.cumulative_y_drag = cy - drag_info.grab_y ;
2480 if (drag_info.x_constrained) {
2481 cx = drag_info.grab_x;
2483 if (drag_info.y_constrained) {
2484 cy = drag_info.grab_y;
2487 cp->line.parent_group().w2i (cx, cy);
2491 cy = min ((double) cp->line.height(), cy);
2493 //translate cx to frames
2494 jack_nframes_t cx_frames = unit_to_frame (cx);
2496 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && !drag_info.x_constrained) {
2497 snap_to (cx_frames);
2500 float fraction = 1.0 - (cy / cp->line.height());
2504 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
2510 cp->line.point_drag (*cp, cx_frames , fraction, push);
2512 set_verbose_canvas_cursor_text (cp->line.get_verbose_cursor_string (fraction));
2514 drag_info.first_move = false;
2518 Editor::control_point_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2520 ControlPoint* cp = reinterpret_cast<ControlPoint *> (drag_info.data);
2522 if (drag_info.first_move) {
2526 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
2527 reset_point_selection ();
2531 control_point_drag_motion_callback (item, event);
2533 cp->line.end_drag (cp);
2537 Editor::start_line_grab_from_regionview (ArdourCanvas::Item* item, GdkEvent* event)
2539 switch (mouse_mode) {
2541 start_line_grab (clicked_regionview->get_gain_line(), event);
2549 Editor::start_line_grab_from_line (ArdourCanvas::Item* item, GdkEvent* event)
2553 if ((al = reinterpret_cast<AutomationLine*> (item->get_data ("line"))) == 0) {
2554 fatal << _("programming error: line canvas item has no line pointer!") << endmsg;
2558 start_line_grab (al, event);
2562 Editor::start_line_grab (AutomationLine* line, GdkEvent* event)
2566 jack_nframes_t frame_within_region;
2568 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2572 cx = event->button.x;
2573 cy = event->button.y;
2574 line->parent_group().w2i (cx, cy);
2575 frame_within_region = (jack_nframes_t) floor (cx * frames_per_unit);
2577 if (!line->control_points_adjacent (frame_within_region, current_line_drag_info.before,
2578 current_line_drag_info.after)) {
2579 /* no adjacent points */
2583 drag_info.item = &line->grab_item();
2584 drag_info.data = line;
2585 drag_info.motion_callback = &Editor::line_drag_motion_callback;
2586 drag_info.finished_callback = &Editor::line_drag_finished_callback;
2588 start_grab (event, fader_cursor);
2590 double fraction = 1.0 - (cy / line->height());
2592 line->start_drag (0, fraction);
2594 set_verbose_canvas_cursor (line->get_verbose_cursor_string (fraction),
2595 drag_info.current_pointer_x + 20, drag_info.current_pointer_y + 20);
2596 show_verbose_canvas_cursor ();
2600 Editor::line_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2602 AutomationLine* line = reinterpret_cast<AutomationLine *> (drag_info.data);
2603 double cx = drag_info.current_pointer_x;
2604 double cy = drag_info.current_pointer_y;
2606 line->parent_group().w2i (cx, cy);
2609 fraction = 1.0 - (cy / line->height());
2613 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
2619 line->line_drag (current_line_drag_info.before, current_line_drag_info.after, fraction, push);
2621 set_verbose_canvas_cursor_text (line->get_verbose_cursor_string (fraction));
2625 Editor::line_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2627 AutomationLine* line = reinterpret_cast<AutomationLine *> (drag_info.data);
2628 line_drag_motion_callback (item, event);
2633 Editor::start_region_grab (ArdourCanvas::Item* item, GdkEvent* event)
2635 if (selection->audio_regions.empty() || clicked_regionview == 0) {
2639 drag_info.copy = false;
2640 drag_info.item = item;
2641 drag_info.data = clicked_regionview;
2642 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2643 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2648 TimeAxisView* tvp = clicked_trackview;
2649 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
2651 if (tv && tv->is_audio_track()) {
2652 speed = tv->get_diskstream()->speed();
2655 drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region.position() / speed);
2656 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2657 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2658 // we want a move threshold
2659 drag_info.want_move_threshold = true;
2661 show_verbose_time_cursor (drag_info.last_frame_position, 10);
2663 begin_reversible_command (_("move region(s)"));
2667 Editor::start_region_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
2669 if (selection->audio_regions.empty() || clicked_regionview == 0) {
2673 drag_info.copy = true;
2674 drag_info.item = item;
2675 drag_info.data = clicked_regionview;
2679 TimeAxisView* tv = &clicked_regionview->get_time_axis_view();
2680 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(tv);
2683 if (atv && atv->is_audio_track()) {
2684 speed = atv->get_diskstream()->speed();
2687 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2688 drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region.position() / speed);
2689 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2690 // we want a move threshold
2691 drag_info.want_move_threshold = true;
2692 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2693 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2697 Editor::start_region_brush_grab (ArdourCanvas::Item* item, GdkEvent* event)
2699 if (selection->audio_regions.empty() || clicked_regionview == 0) {
2703 drag_info.copy = false;
2704 drag_info.item = item;
2705 drag_info.data = clicked_regionview;
2706 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2707 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2712 TimeAxisView* tvp = clicked_trackview;
2713 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
2715 if (tv && tv->is_audio_track()) {
2716 speed = tv->get_diskstream()->speed();
2719 drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region.position() / speed);
2720 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2721 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2722 // we want a move threshold
2723 drag_info.want_move_threshold = true;
2724 drag_info.brushing = true;
2726 begin_reversible_command (_("Drag region brush"));
2730 Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2734 AudioRegionView *rv = reinterpret_cast<AudioRegionView*> (drag_info.data);
2735 jack_nframes_t pending_region_position = 0;
2736 int32_t pointer_y_span = 0, canvas_pointer_y_span = 0, original_pointer_order;
2737 int32_t visible_y_high = 0, visible_y_low = 512; //high meaning higher numbered.. not the height on the screen
2738 bool clamp_y_axis = false;
2739 vector<int32_t> height_list(512) ;
2740 vector<int32_t>::iterator j;
2742 show_verbose_time_cursor (drag_info.last_frame_position, 10);
2744 if (drag_info.copy && drag_info.move_threshold_passed && drag_info.want_move_threshold) {
2746 drag_info.want_move_threshold = false; // don't copy again
2748 /* this is committed in the grab finished callback. */
2750 begin_reversible_command (_("Drag region copy"));
2752 /* duplicate the region(s) */
2754 vector<AudioRegionView*> new_regionviews;
2756 set<Playlist*> affected_playlists;
2757 pair<set<Playlist*>::iterator,bool> insert_result;
2759 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
2760 AudioRegionView* rv;
2764 Playlist* to_playlist = rv->region.playlist();
2765 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&rv->get_time_axis_view());
2767 insert_result = affected_playlists.insert (to_playlist);
2768 if (insert_result.second) {
2769 session->add_undo (to_playlist->get_memento ());
2772 latest_regionview = 0;
2774 sigc::connection c = atv->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
2776 /* create a new region with the same name.
2779 AudioRegion* newregion = new AudioRegion (rv->region);
2781 /* if the original region was locked, we don't care */
2783 newregion->set_locked (false);
2785 to_playlist->add_region (*newregion, (jack_nframes_t) (rv->region.position() * atv->get_diskstream()->speed()));
2789 if (latest_regionview) {
2790 new_regionviews.push_back (latest_regionview);
2794 if (new_regionviews.empty()) {
2798 /* reset selection to new regionviews */
2800 selection->set (new_regionviews);
2802 /* reset drag_info data to reflect the fact that we are dragging the copies */
2804 drag_info.data = new_regionviews.front();
2805 swap_grab (new_regionviews.front()->get_canvas_group (), 0, event->motion.time);
2808 /* Which trackview is this ? */
2810 TimeAxisView* tvp = trackview_by_y_position (drag_info.current_pointer_y);
2811 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
2813 /* The region motion is only processed if the pointer is over
2817 if (!tv || !tv->is_audio_track()) {
2818 /* To make sure we hide the verbose canvas cursor when the mouse is
2819 not held over and audiotrack.
2821 hide_verbose_canvas_cursor ();
2825 original_pointer_order = drag_info.last_trackview->order;
2827 /************************************************************
2829 ************************************************************/
2831 if (drag_info.brushing) {
2832 clamp_y_axis = true;
2837 if ((pointer_y_span = (drag_info.last_trackview->order - tv->order)) != 0) {
2839 int32_t children = 0, numtracks = 0;
2840 // XXX hard coding track limit, oh my, so very very bad
2841 bitset <1024> tracks (0x00);
2842 /* get a bitmask representing the visible tracks */
2844 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2845 TimeAxisView *tracklist_timeview;
2846 tracklist_timeview = (*i);
2847 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tracklist_timeview);
2848 list<TimeAxisView*> children_list;
2850 /* zeroes are audio tracks. ones are other types. */
2852 if (!atv2->hidden()) {
2854 if (visible_y_high < atv2->order) {
2855 visible_y_high = atv2->order;
2857 if (visible_y_low > atv2->order) {
2858 visible_y_low = atv2->order;
2861 if (!atv2->is_audio_track()) {
2862 tracks = tracks |= (0x01 << atv2->order);
2865 height_list[atv2->order] = (*i)->height;
2867 if ((children_list = atv2->get_child_list()).size() > 0) {
2868 for (list<TimeAxisView*>::iterator j = children_list.begin(); j != children_list.end(); ++j) {
2869 tracks = tracks |= (0x01 << (atv2->order + children));
2870 height_list[atv2->order + children] = (*j)->height;
2878 /* find the actual span according to the canvas */
2880 canvas_pointer_y_span = pointer_y_span;
2881 if (drag_info.last_trackview->order >= tv->order) {
2883 for (y = tv->order; y < drag_info.last_trackview->order; y++) {
2884 if (height_list[y] == 0 ) {
2885 canvas_pointer_y_span--;
2890 for (y = drag_info.last_trackview->order;y <= tv->order; y++) {
2891 if ( height_list[y] == 0 ) {
2892 canvas_pointer_y_span++;
2897 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
2898 AudioRegionView* rv2;
2900 double ix1, ix2, iy1, iy2;
2903 rv2->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
2904 rv2->get_canvas_group()->i2w (ix1, iy1);
2905 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
2906 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2);
2908 if (atv2->order != original_pointer_order) {
2909 /* this isn't the pointer track */
2911 if (canvas_pointer_y_span > 0) {
2913 /* moving up the canvas */
2914 if ((atv2->order - canvas_pointer_y_span) >= visible_y_low) {
2916 int32_t visible_tracks = 0;
2917 while (visible_tracks < canvas_pointer_y_span ) {
2920 while (height_list[atv2->order - (visible_tracks - n)] == 0) {
2921 /* we're passing through a hidden track */
2926 if (tracks[atv2->order - (canvas_pointer_y_span - n)] != 0x00) {
2927 clamp_y_axis = true;
2931 clamp_y_axis = true;
2934 } else if (canvas_pointer_y_span < 0) {
2936 /*moving down the canvas*/
2938 if ((atv2->order - (canvas_pointer_y_span - n)) <= visible_y_high) { // we will overflow
2941 int32_t visible_tracks = 0;
2943 while (visible_tracks > canvas_pointer_y_span ) {
2946 while (height_list[atv2->order - (visible_tracks - n)] == 0) {
2950 if ( tracks[atv2->order - ( canvas_pointer_y_span - n)] != 0x00) {
2951 clamp_y_axis = true;
2956 clamp_y_axis = true;
2962 /* this is the pointer's track */
2963 if ((atv2->order - pointer_y_span) > visible_y_high) { // we will overflow
2964 clamp_y_axis = true;
2965 } else if ((atv2->order - pointer_y_span) < visible_y_low) { // we will underflow
2966 clamp_y_axis = true;
2974 } else if (drag_info.last_trackview == tv) {
2975 clamp_y_axis = true;
2979 if (!clamp_y_axis) {
2980 drag_info.last_trackview = tv;
2983 /************************************************************
2985 ************************************************************/
2987 /* compute the amount of pointer motion in frames, and where
2988 the region would be if we moved it by that much.
2991 if (drag_info.move_threshold_passed) {
2993 if ((int32_t)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
2995 jack_nframes_t sync_frame;
2996 jack_nframes_t sync_offset;
2999 pending_region_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
3001 sync_offset = rv->region.sync_offset (sync_dir);
3002 sync_frame = rv->region.adjust_to_sync (pending_region_position);
3004 /* we snap if the snap modifier is not enabled.
3007 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3008 snap_to (sync_frame);
3011 if (sync_frame - sync_offset <= sync_frame) {
3012 pending_region_position = sync_frame - (sync_dir*sync_offset);
3014 pending_region_position = 0;
3018 pending_region_position = 0;
3021 if (pending_region_position > max_frames - rv->region.length()) {
3022 pending_region_position = drag_info.last_frame_position;
3025 // printf ("3: pending_region_position= %lu %lu\n", pending_region_position, drag_info.last_frame_position );
3027 if (pending_region_position != drag_info.last_frame_position && !drag_info.x_constrained) {
3029 /* now compute the canvas unit distance we need to move the regiondrag_info.last_trackview->order
3030 to make it appear at the new location.
3033 if (pending_region_position > drag_info.last_frame_position) {
3034 x_delta = ((double) (pending_region_position - drag_info.last_frame_position) / frames_per_unit);
3036 x_delta = -((double) (drag_info.last_frame_position - pending_region_position) / frames_per_unit);
3039 drag_info.last_frame_position = pending_region_position;
3046 /* threshold not passed */
3051 /*************************************************************
3053 ************************************************************/
3055 if (x_delta == 0 && (pointer_y_span == 0)) {
3056 /* haven't reached next snap point, and we're not switching
3057 trackviews. nothing to do.
3063 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
3065 AudioRegionView* rv2;
3068 /* if any regionview is at zero, we need to know so we can
3069 stop further leftward motion.
3072 double ix1, ix2, iy1, iy2;
3073 rv2->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3074 rv2->get_canvas_group()->i2w (ix1, iy1);
3083 /*************************************************************
3085 ************************************************************/
3087 pair<set<Playlist*>::iterator,bool> insert_result;
3088 const list<AudioRegionView*>& layered_regions = selection->audio_regions.by_layer();
3090 for (list<AudioRegionView*>::const_iterator i = layered_regions.begin(); i != layered_regions.end(); ++i) {
3092 AudioRegionView* rv;
3094 double ix1, ix2, iy1, iy2;
3095 int32_t temp_pointer_y_span = pointer_y_span;
3097 /* get item BBox, which will be relative to parent. so we have
3098 to query on a child, then convert to world coordinates using
3102 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3103 rv->get_canvas_group()->i2w (ix1, iy1);
3104 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
3105 AudioTimeAxisView* canvas_atv = dynamic_cast<AudioTimeAxisView*>(tvp2);
3106 AudioTimeAxisView* temp_atv;
3108 if ((pointer_y_span != 0) && !clamp_y_axis) {
3111 for (j = height_list.begin(); j!= height_list.end(); j++) {
3112 if (x == canvas_atv->order) {
3113 /* we found the track the region is on */
3114 if (x != original_pointer_order) {
3115 /*this isn't from the same track we're dragging from */
3116 temp_pointer_y_span = canvas_pointer_y_span;
3118 while (temp_pointer_y_span > 0) {
3119 /* we're moving up canvas-wise,
3120 so we need to find the next track height
3122 if (j != height_list.begin()) {
3125 if (x != original_pointer_order) {
3126 /* we're not from the dragged track, so ignore hidden tracks. */
3128 temp_pointer_y_span++;
3132 temp_pointer_y_span--;
3134 while (temp_pointer_y_span < 0) {
3136 if (x != original_pointer_order) {
3138 temp_pointer_y_span--;
3142 if (j != height_list.end()) {
3145 temp_pointer_y_span++;
3147 /* find out where we'll be when we move and set height accordingly */
3149 tvp2 = trackview_by_y_position (iy1 + y_delta);
3150 temp_atv = dynamic_cast<AudioTimeAxisView*>(tvp2);
3151 rv->set_height (temp_atv->height);
3153 /* if you un-comment the following, the region colours will follow the track colours whilst dragging,
3154 personally, i think this can confuse things, but never mind.
3157 //const GdkColor& col (temp_atv->view->get_region_color());
3158 //rv->set_color (const_cast<GdkColor&>(col));
3165 /* prevent the regionview from being moved to before
3166 the zero position on the canvas.
3171 if (-x_delta > ix1) {
3174 } else if ((x_delta > 0) &&(rv->region.last_frame() > max_frames - x_delta)) {
3175 x_delta = max_frames - rv->region.last_frame();
3178 if (drag_info.first_move) {
3180 /* hide any dependent views */
3182 // rv->get_time_axis_view().hide_dependent_views (*rv);
3184 /* this is subtle. raising the regionview itself won't help,
3185 because raise_to_top() just puts the item on the top of
3186 its parent's stack. so, we need to put the trackview canvas_display group
3187 on the top, since its parent is the whole canvas.
3190 rv->get_canvas_group()->raise_to_top();
3191 rv->get_time_axis_view().canvas_display->raise_to_top();
3192 cursor_group->raise_to_top();
3194 /* freeze the playlists from notifying till
3198 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&rv->get_time_axis_view());
3199 if (atv && atv->is_audio_track()) {
3200 AudioPlaylist* pl = atv->get_diskstream()->playlist();
3202 /* only freeze and capture state once */
3204 insert_result = motion_frozen_playlists.insert (pl);
3205 if (insert_result.second) {
3207 session->add_undo(pl->get_memento());
3213 if (drag_info.brushing) {
3214 mouse_brush_insert_region (rv, pending_region_position);
3216 rv->move (x_delta, y_delta);
3220 if (drag_info.first_move) {
3221 cursor_group->raise_to_top();
3224 drag_info.first_move = false;
3226 if (x_delta != 0 && !drag_info.brushing) {
3227 show_verbose_time_cursor (drag_info.last_frame_position, 10);
3233 Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
3235 jack_nframes_t where;
3236 AudioRegionView* rv = reinterpret_cast<AudioRegionView *> (drag_info.data);
3237 pair<set<Playlist*>::iterator,bool> insert_result;
3238 bool nocommit = true;
3240 AudioTimeAxisView* atv;
3241 bool regionview_y_movement;
3242 bool regionview_x_movement;
3244 /* first_move is set to false if the regionview has been moved in the
3248 if (drag_info.first_move) {
3255 /* The regionview has been moved at some stage during the grab so we need
3256 to account for any mouse movement between this event and the last one.
3259 region_drag_motion_callback (item, event);
3261 if (drag_info.brushing) {
3262 /* all changes were made during motion event handlers */
3266 /* adjust for track speed */
3269 atv = dynamic_cast<AudioTimeAxisView*> (drag_info.last_trackview);
3270 if (atv && atv->get_diskstream()) {
3271 speed = atv->get_diskstream()->speed();
3274 regionview_x_movement = (drag_info.last_frame_position != (jack_nframes_t) (rv->region.position()/speed));
3275 regionview_y_movement = (drag_info.last_trackview != &rv->get_time_axis_view());
3277 //printf ("last_frame: %s position is %lu %g\n", rv->get_time_axis_view().name().c_str(), drag_info.last_frame_position, speed);
3278 //printf ("last_rackview: %s \n", drag_info.last_trackview->name().c_str());
3280 if (regionview_y_movement) {
3282 /* motion between tracks */
3284 list<AudioRegionView*> new_selection;
3286 /* moved to a different audio track. */
3288 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ) {
3290 AudioRegionView* rv2 = (*i);
3292 /* the region that used to be in the old playlist is not
3293 moved to the new one - we make a copy of it. as a result,
3294 any existing editor for the region should no longer be
3298 if (!drag_info.copy) {
3299 rv2->hide_region_editor();
3301 new_selection.push_back (rv2);
3305 /* first, freeze the target tracks */
3307 for (list<AudioRegionView*>::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) {
3309 Playlist* from_playlist;
3310 Playlist* to_playlist;
3312 double ix1, ix2, iy1, iy2;
3314 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3315 (*i)->get_canvas_group()->i2w (ix1, iy1);
3316 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
3317 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2);
3319 from_playlist = (*i)->region.playlist();
3320 to_playlist = atv2->playlist();
3322 /* the from_playlist was frozen in the "first_move" case
3323 of the motion handler. the insert can fail,
3324 but that doesn't matter. it just means
3325 we already have the playlist in the list.
3328 motion_frozen_playlists.insert (from_playlist);
3330 /* only freeze the to_playlist once */
3332 insert_result = motion_frozen_playlists.insert(to_playlist);
3333 if (insert_result.second) {
3334 to_playlist->freeze();
3335 session->add_undo(to_playlist->get_memento());
3340 /* now do it again with the actual operations */
3342 for (list<AudioRegionView*>::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) {
3344 Playlist* from_playlist;
3345 Playlist* to_playlist;
3347 double ix1, ix2, iy1, iy2;
3349 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3350 (*i)->get_canvas_group()->i2w (ix1, iy1);
3351 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
3352 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2);
3354 from_playlist = (*i)->region.playlist();
3355 to_playlist = atv2->playlist();
3357 latest_regionview = 0;
3359 where = (jack_nframes_t) (unit_to_frame (ix1) * speed);
3360 Region* new_region = createRegion ((*i)->region);
3362 from_playlist->remove_region (&((*i)->region));
3364 sigc::connection c = atv2->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3365 to_playlist->add_region (*new_region, where);
3368 if (latest_regionview) {
3369 selection->add (latest_regionview);
3375 /* motion within a single track */
3377 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
3381 if (rv->region.locked()) {
3385 if (regionview_x_movement) {
3386 double ownspeed = 1.0;
3387 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&(rv->get_time_axis_view()));
3389 if (atv && atv->get_diskstream()) {
3390 ownspeed = atv->get_diskstream()->speed();
3393 /* base the new region position on the current position of the regionview.*/
3395 double ix1, ix2, iy1, iy2;
3397 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3398 rv->get_canvas_group()->i2w (ix1, iy1);
3399 where = (jack_nframes_t) (unit_to_frame (ix1) * ownspeed);
3403 where = rv->region.position();
3406 rv->get_time_axis_view().reveal_dependent_views (*rv);
3408 /* no need to add an undo here, we did that when we added this playlist to motion_frozen playlists */
3410 rv->region.set_position (where, (void *) this);
3415 for (set<Playlist*>::iterator p = motion_frozen_playlists.begin(); p != motion_frozen_playlists.end(); ++p) {
3417 session->add_redo_no_execute ((*p)->get_memento());
3420 motion_frozen_playlists.clear ();
3423 commit_reversible_command ();
3428 Editor::region_view_item_click (AudioRegionView& rv, GdkEventButton* event)
3430 /* Either add to or set the set the region selection, unless
3431 this is an alignment click (control used)
3434 if (Keyboard::modifier_state_contains (event->state, Keyboard::Control)) {
3435 TimeAxisView* tv = &rv.get_time_axis_view();
3436 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(tv);
3438 if (atv && atv->is_audio_track()) {
3439 speed = atv->get_diskstream()->speed();
3442 if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Alt))) {
3444 align_region (rv.region, SyncPoint, (jack_nframes_t) (edit_cursor->current_frame * speed));
3446 } else if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Shift))) {
3448 align_region (rv.region, End, (jack_nframes_t) (edit_cursor->current_frame * speed));
3452 align_region (rv.region, Start, (jack_nframes_t) (edit_cursor->current_frame * speed));
3458 Editor::show_verbose_time_cursor (jack_nframes_t frame, double offset, double xpos, double ypos)
3469 switch (ARDOUR_UI::instance()->secondary_clock.mode ()) {
3470 case AudioClock::BBT:
3471 session->bbt_time (frame, bbt);
3472 snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32, bbt.bars, bbt.beats, bbt.ticks);
3475 case AudioClock::SMPTE:
3476 session->smpte_time (frame, smpte);
3477 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
3480 case AudioClock::MinSec:
3481 /* XXX fix this to compute min/sec properly */
3482 session->smpte_time (frame, smpte);
3483 secs = smpte.seconds + ((float) smpte.frames / session->smpte_frames_per_second);
3484 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%.4f", smpte.hours, smpte.minutes, secs);
3488 snprintf (buf, sizeof(buf), "%u", frame);
3492 if (xpos >= 0 && ypos >=0) {
3493 set_verbose_canvas_cursor (buf, xpos + offset, ypos + offset);
3496 set_verbose_canvas_cursor (buf, drag_info.current_pointer_x + offset, drag_info.current_pointer_y + offset);
3498 show_verbose_canvas_cursor ();
3502 Editor::show_verbose_duration_cursor (jack_nframes_t start, jack_nframes_t end, double offset, double xpos, double ypos)
3509 Meter meter_at_start(session->tempo_map().meter_at(start));
3515 switch (ARDOUR_UI::instance()->secondary_clock.mode ()) {
3516 case AudioClock::BBT:
3517 session->bbt_time (start, sbbt);
3518 session->bbt_time (end, ebbt);
3521 /* XXX this computation won't work well if the
3522 user makes a selection that spans any meter changes.
3525 ebbt.bars -= sbbt.bars;
3526 if (ebbt.beats >= sbbt.beats) {
3527 ebbt.beats -= sbbt.beats;
3530 ebbt.beats = int(meter_at_start.beats_per_bar()) + ebbt.beats - sbbt.beats;
3532 if (ebbt.ticks >= sbbt.ticks) {
3533 ebbt.ticks -= sbbt.ticks;
3536 ebbt.ticks = int(Meter::ticks_per_beat) + ebbt.ticks - sbbt.ticks;
3539 snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32, ebbt.bars, ebbt.beats, ebbt.ticks);
3542 case AudioClock::SMPTE:
3543 session->smpte_duration (end - start, smpte);
3544 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
3547 case AudioClock::MinSec:
3548 /* XXX fix this to compute min/sec properly */
3549 session->smpte_duration (end - start, smpte);
3550 secs = smpte.seconds + ((float) smpte.frames / session->smpte_frames_per_second);
3551 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%.4f", smpte.hours, smpte.minutes, secs);
3555 snprintf (buf, sizeof(buf), "%u", end - start);
3559 if (xpos >= 0 && ypos >=0) {
3560 set_verbose_canvas_cursor (buf, xpos + offset, ypos + offset);
3563 set_verbose_canvas_cursor (buf, drag_info.current_pointer_x + offset, drag_info.current_pointer_y + offset);
3565 show_verbose_canvas_cursor ();
3569 Editor::collect_new_region_view (AudioRegionView* rv)
3571 latest_regionview = rv;
3575 Editor::start_selection_grab (ArdourCanvas::Item* item, GdkEvent* event)
3577 if (clicked_regionview == 0) {
3581 /* lets try to create new Region for the selection */
3583 vector<AudioRegion*> new_regions;
3584 create_region_from_selection (new_regions);
3586 if (new_regions.empty()) {
3590 /* XXX fix me one day to use all new regions */
3592 Region* region = new_regions.front();
3594 /* add it to the current stream/playlist.
3596 tricky: the streamview for the track will add a new regionview. we will
3597 catch the signal it sends when it creates the regionview to
3598 set the regionview we want to then drag.
3601 latest_regionview = 0;
3602 sigc::connection c = clicked_audio_trackview->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3604 /* A selection grab currently creates two undo/redo operations, one for
3605 creating the new region and another for moving it.
3608 begin_reversible_command (_("selection grab"));
3610 Playlist* playlist = clicked_trackview->playlist();
3612 session->add_undo (playlist->get_memento ());
3613 clicked_trackview->playlist()->add_region (*region, selection->time[clicked_selection].start);
3614 session->add_redo_no_execute (playlist->get_memento ());
3616 commit_reversible_command ();
3620 if (latest_regionview == 0) {
3621 /* something went wrong */
3625 /* we need to deselect all other regionviews, and select this one
3626 i'm ignoring undo stuff, because the region creation will take care of it */
3627 selection->set (latest_regionview);
3629 drag_info.item = latest_regionview->get_canvas_group();
3630 drag_info.data = latest_regionview;
3631 drag_info.motion_callback = &Editor::region_drag_motion_callback;
3632 drag_info.finished_callback = &Editor::region_drag_finished_callback;
3636 drag_info.last_trackview = clicked_trackview;
3637 drag_info.last_frame_position = latest_regionview->region.position();
3638 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
3640 show_verbose_time_cursor (drag_info.last_frame_position, 10);
3644 Editor::cancel_selection ()
3646 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3647 (*i)->hide_selection ();
3649 begin_reversible_command (_("cancel selection"));
3650 selection->clear ();
3651 clicked_selection = 0;
3652 commit_reversible_command ();
3656 Editor::start_selection_op (ArdourCanvas::Item* item, GdkEvent* event, SelectionOp op)
3658 jack_nframes_t start = 0;
3659 jack_nframes_t end = 0;
3665 drag_info.item = item;
3666 drag_info.motion_callback = &Editor::drag_selection;
3667 drag_info.finished_callback = &Editor::end_selection_op;
3672 case CreateSelection:
3673 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
3674 drag_info.copy = true;
3676 drag_info.copy = false;
3678 start_grab (event, selector_cursor);
3681 case SelectionStartTrim:
3682 if (clicked_trackview) {
3683 clicked_trackview->order_selection_trims (item, true);
3685 start_grab (event, trimmer_cursor);
3686 start = selection->time[clicked_selection].start;
3687 drag_info.pointer_frame_offset = drag_info.grab_frame - start;
3690 case SelectionEndTrim:
3691 if (clicked_trackview) {
3692 clicked_trackview->order_selection_trims (item, false);
3694 start_grab (event, trimmer_cursor);
3695 end = selection->time[clicked_selection].end;
3696 drag_info.pointer_frame_offset = drag_info.grab_frame - end;
3700 start = selection->time[clicked_selection].start;
3702 drag_info.pointer_frame_offset = drag_info.grab_frame - start;
3706 if (selection_op == SelectionMove) {
3707 show_verbose_time_cursor(start, 10);
3709 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
3714 Editor::drag_selection (ArdourCanvas::Item* item, GdkEvent* event)
3716 jack_nframes_t start = 0;
3717 jack_nframes_t end = 0;
3718 jack_nframes_t length;
3719 jack_nframes_t pending_position;
3721 if ((int32_t) drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
3722 pending_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
3725 pending_position = 0;
3728 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3729 snap_to (pending_position);
3732 /* only alter selection if the current frame is
3733 different from the last frame position (adjusted)
3736 if (pending_position == drag_info.last_pointer_frame) return;
3738 switch (selection_op) {
3739 case CreateSelection:
3741 if (drag_info.first_move) {
3742 snap_to (drag_info.grab_frame);
3745 if (pending_position < drag_info.grab_frame) {
3746 start = pending_position;
3747 end = drag_info.grab_frame;
3749 end = pending_position;
3750 start = drag_info.grab_frame;
3753 /* first drag: Either add to the selection
3754 or create a new selection->
3757 if (drag_info.first_move) {
3759 begin_reversible_command (_("range selection"));
3761 if (drag_info.copy) {
3762 /* adding to the selection */
3763 clicked_selection = selection->add (start, end);
3764 drag_info.copy = false;
3766 /* new selection-> */
3767 clicked_selection = selection->set (clicked_trackview, start, end);
3772 case SelectionStartTrim:
3774 if (drag_info.first_move) {
3775 begin_reversible_command (_("trim selection start"));
3778 start = selection->time[clicked_selection].start;
3779 end = selection->time[clicked_selection].end;
3781 if (pending_position > end) {
3784 start = pending_position;
3788 case SelectionEndTrim:
3790 if (drag_info.first_move) {
3791 begin_reversible_command (_("trim selection end"));
3794 start = selection->time[clicked_selection].start;
3795 end = selection->time[clicked_selection].end;
3797 if (pending_position < start) {
3800 end = pending_position;
3807 if (drag_info.first_move) {
3808 begin_reversible_command (_("move selection"));
3811 start = selection->time[clicked_selection].start;
3812 end = selection->time[clicked_selection].end;
3814 length = end - start;
3816 start = pending_position;
3819 end = start + length;
3824 if (event->button.x >= horizontal_adjustment.get_value() + canvas_width) {
3825 start_canvas_autoscroll (1);
3829 selection->replace (clicked_selection, start, end);
3832 drag_info.last_pointer_frame = pending_position;
3833 drag_info.first_move = false;
3835 if (selection_op == SelectionMove) {
3836 show_verbose_time_cursor(start, 10);
3838 show_verbose_time_cursor(pending_position, 10);
3843 Editor::end_selection_op (ArdourCanvas::Item* item, GdkEvent* event)
3845 if (!drag_info.first_move) {
3846 drag_selection (item, event);
3847 /* XXX this is not object-oriented programming at all. ick */
3848 if (selection->time.consolidate()) {
3849 selection->TimeChanged ();
3851 commit_reversible_command ();
3853 /* just a click, no pointer movement.*/
3855 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3857 selection->clear_time();
3862 /* XXX what happens if its a music selection? */
3863 session->set_audio_range (selection->time);
3864 stop_canvas_autoscroll ();
3868 Editor::start_trim (ArdourCanvas::Item* item, GdkEvent* event)
3871 TimeAxisView* tvp = clicked_trackview;
3872 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3874 if (tv && tv->is_audio_track()) {
3875 speed = tv->get_diskstream()->speed();
3878 jack_nframes_t region_start = (jack_nframes_t) (clicked_regionview->region.position() / speed);
3879 jack_nframes_t region_end = (jack_nframes_t) (clicked_regionview->region.last_frame() / speed);
3880 jack_nframes_t region_length = (jack_nframes_t) (clicked_regionview->region.length() / speed);
3882 motion_frozen_playlists.clear();
3884 //drag_info.item = clicked_regionview->get_name_highlight();
3885 drag_info.item = item;
3886 drag_info.motion_callback = &Editor::trim_motion_callback;
3887 drag_info.finished_callback = &Editor::trim_finished_callback;
3889 start_grab (event, trimmer_cursor);
3891 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
3892 trim_op = ContentsTrim;
3894 /* These will get overridden for a point trim.*/
3895 if (drag_info.current_pointer_frame < (region_start + region_length/2)) {
3896 /* closer to start */
3897 trim_op = StartTrim;
3898 } else if (drag_info.current_pointer_frame > (region_end - region_length/2)) {
3906 show_verbose_time_cursor(region_start, 10);
3909 show_verbose_time_cursor(region_end, 10);
3912 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
3918 Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
3920 AudioRegionView* rv = clicked_regionview;
3921 jack_nframes_t frame_delta = 0;
3922 bool left_direction;
3923 bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier());
3925 /* snap modifier works differently here..
3926 its' current state has to be passed to the
3927 various trim functions in order to work properly
3931 TimeAxisView* tvp = clicked_trackview;
3932 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3933 pair<set<Playlist*>::iterator,bool> insert_result;
3935 if (tv && tv->is_audio_track()) {
3936 speed = tv->get_diskstream()->speed();
3939 if (drag_info.last_pointer_frame > drag_info.current_pointer_frame) {
3940 left_direction = true;
3942 left_direction = false;
3946 snap_to (drag_info.current_pointer_frame);
3949 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) {
3953 if (drag_info.first_move) {
3959 trim_type = "Region start trim";
3962 trim_type = "Region end trim";
3965 trim_type = "Region content trim";
3969 begin_reversible_command (trim_type);
3971 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
3972 (*i)->region.freeze ();
3973 (*i)->temporarily_hide_envelope ();
3975 Playlist * pl = (*i)->region.playlist();
3976 insert_result = motion_frozen_playlists.insert (pl);
3977 if (insert_result.second) {
3978 session->add_undo (pl->get_memento());
3983 if (left_direction) {
3984 frame_delta = (drag_info.last_pointer_frame - drag_info.current_pointer_frame);
3986 frame_delta = (drag_info.current_pointer_frame - drag_info.last_pointer_frame);
3991 if ((left_direction == false) && (drag_info.current_pointer_frame <= rv->region.first_frame()/speed)) {
3994 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
3995 single_start_trim (**i, frame_delta, left_direction, obey_snap);
4001 if ((left_direction == true) && (drag_info.current_pointer_frame > (jack_nframes_t) (rv->region.last_frame()/speed))) {
4004 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
4005 single_end_trim (**i, frame_delta, left_direction, obey_snap);
4012 bool swap_direction = false;
4014 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
4015 swap_direction = true;
4018 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin();
4019 i != selection->audio_regions.by_layer().end(); ++i)
4021 single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
4029 show_verbose_time_cursor((jack_nframes_t) (rv->region.position()/speed), 10);
4032 show_verbose_time_cursor((jack_nframes_t) (rv->region.last_frame()/speed), 10);
4035 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
4039 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4040 drag_info.first_move = false;
4044 Editor::single_contents_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool swap_direction, bool obey_snap)
4046 Region& region (rv.region);
4048 if (region.locked()) {
4052 jack_nframes_t new_bound;
4055 TimeAxisView* tvp = clicked_trackview;
4056 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
4058 if (tv && tv->is_audio_track()) {
4059 speed = tv->get_diskstream()->speed();
4062 if (left_direction) {
4063 if (swap_direction) {
4064 new_bound = (jack_nframes_t) (region.position()/speed) + frame_delta;
4066 new_bound = (jack_nframes_t) (region.position()/speed) - frame_delta;
4069 if (swap_direction) {
4070 new_bound = (jack_nframes_t) (region.position()/speed) - frame_delta;
4072 new_bound = (jack_nframes_t) (region.position()/speed) + frame_delta;
4077 snap_to (new_bound);
4079 region.trim_start ((jack_nframes_t) (new_bound * speed), this);
4080 rv.region_changed (StartChanged);
4084 Editor::single_start_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool obey_snap)
4086 Region& region (rv.region);
4088 if (region.locked()) {
4092 jack_nframes_t new_bound;
4095 TimeAxisView* tvp = clicked_trackview;
4096 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
4098 if (tv && tv->is_audio_track()) {
4099 speed = tv->get_diskstream()->speed();
4102 if (left_direction) {
4103 new_bound = (jack_nframes_t) (region.position()/speed) - frame_delta;
4105 new_bound = (jack_nframes_t) (region.position()/speed) + frame_delta;
4109 snap_to (new_bound, (left_direction ? 0 : 1));
4112 region.trim_front ((jack_nframes_t) (new_bound * speed), this);
4114 rv.region_changed (Change (LengthChanged|PositionChanged|StartChanged));
4118 Editor::single_end_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool obey_snap)
4120 Region& region (rv.region);
4122 if (region.locked()) {
4126 jack_nframes_t new_bound;
4129 TimeAxisView* tvp = clicked_trackview;
4130 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
4132 if (tv && tv->is_audio_track()) {
4133 speed = tv->get_diskstream()->speed();
4136 if (left_direction) {
4137 new_bound = (jack_nframes_t) ((region.last_frame() + 1)/speed) - frame_delta;
4139 new_bound = (jack_nframes_t) ((region.last_frame() + 1)/speed) + frame_delta;
4143 snap_to (new_bound);
4145 region.trim_end ((jack_nframes_t) (new_bound * speed), this);
4146 rv.region_changed (LengthChanged);
4150 Editor::trim_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
4152 if (!drag_info.first_move) {
4153 trim_motion_callback (item, event);
4155 if (!clicked_regionview->get_selected()) {
4156 thaw_region_after_trim (*clicked_regionview);
4159 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin();
4160 i != selection->audio_regions.by_layer().end(); ++i)
4162 thaw_region_after_trim (**i);
4166 for (set<Playlist*>::iterator p = motion_frozen_playlists.begin(); p != motion_frozen_playlists.end(); ++p) {
4168 session->add_redo_no_execute ((*p)->get_memento());
4171 motion_frozen_playlists.clear ();
4173 commit_reversible_command();
4175 /* no mouse movement */
4181 Editor::point_trim (GdkEvent* event)
4183 AudioRegionView* rv = clicked_regionview;
4184 jack_nframes_t new_bound = drag_info.current_pointer_frame;
4186 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4187 snap_to (new_bound);
4190 /* Choose action dependant on which button was pressed */
4191 switch (event->button.button) {
4193 trim_op = StartTrim;
4194 begin_reversible_command (_("Start point trim"));
4196 if (rv->get_selected()) {
4198 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin();
4199 i != selection->audio_regions.by_layer().end(); ++i)
4201 if (!(*i)->region.locked()) {
4202 session->add_undo ((*i)->region.playlist()->get_memento());
4203 (*i)->region.trim_front (new_bound, this);
4204 session->add_redo_no_execute ((*i)->region.playlist()->get_memento());
4210 if (!rv->region.locked()) {
4211 session->add_undo (rv->region.playlist()->get_memento());
4212 rv->region.trim_front (new_bound, this);
4213 session->add_redo_no_execute (rv->region.playlist()->get_memento());
4217 commit_reversible_command();
4222 begin_reversible_command (_("End point trim"));
4224 if (rv->get_selected()) {
4226 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i)
4228 if (!(*i)->region.locked()) {
4229 session->add_undo ((*i)->region.playlist()->get_memento());
4230 (*i)->region.trim_end (new_bound, this);
4231 session->add_redo_no_execute ((*i)->region.playlist()->get_memento());
4237 if (!rv->region.locked()) {
4238 session->add_undo (rv->region.playlist()->get_memento());
4239 rv->region.trim_end (new_bound, this);
4240 session->add_redo_no_execute (rv->region.playlist()->get_memento());
4244 commit_reversible_command();
4253 Editor::thaw_region_after_trim (AudioRegionView& rv)
4255 Region& region (rv.region);
4257 if (region.locked()) {
4261 region.thaw (_("trimmed region"));
4262 session->add_redo_no_execute (region.playlist()->get_memento());
4264 rv.unhide_envelope ();
4268 Editor::hide_marker (ArdourCanvas::Item* item, GdkEvent* event)
4273 if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
4274 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
4278 Location* location = find_location_from_marker (marker, is_start);
4279 location->set_hidden (true, this);
4284 Editor::start_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event, RangeMarkerOp op)
4290 drag_info.item = item;
4291 drag_info.motion_callback = &Editor::drag_range_markerbar_op;
4292 drag_info.finished_callback = &Editor::end_range_markerbar_op;
4294 range_marker_op = op;
4296 if (!temp_location) {
4297 temp_location = new Location;
4301 case CreateRangeMarker:
4302 case CreateTransportMarker:
4304 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
4305 drag_info.copy = true;
4307 drag_info.copy = false;
4309 start_grab (event, selector_cursor);
4313 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
4318 Editor::drag_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event)
4320 jack_nframes_t start = 0;
4321 jack_nframes_t end = 0;
4322 ArdourCanvas::SimpleRect *crect = (range_marker_op == CreateRangeMarker) ? range_bar_drag_rect: transport_bar_drag_rect;
4324 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4325 snap_to (drag_info.current_pointer_frame);
4328 /* only alter selection if the current frame is
4329 different from the last frame position.
4332 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) return;
4334 switch (range_marker_op) {
4335 case CreateRangeMarker:
4336 case CreateTransportMarker:
4337 if (drag_info.first_move) {
4338 snap_to (drag_info.grab_frame);
4341 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4342 start = drag_info.current_pointer_frame;
4343 end = drag_info.grab_frame;
4345 end = drag_info.current_pointer_frame;
4346 start = drag_info.grab_frame;
4349 /* first drag: Either add to the selection
4350 or create a new selection.
4353 if (drag_info.first_move) {
4355 temp_location->set (start, end);
4359 update_marker_drag_item (temp_location);
4360 range_marker_drag_rect->show();
4361 range_marker_drag_rect->raise_to_top();
4367 if (event->button.x >= horizontal_adjustment.get_value() + canvas_width) {
4368 start_canvas_autoscroll (1);
4372 temp_location->set (start, end);
4374 double x1 = frame_to_pixel (start);
4375 double x2 = frame_to_pixel (end);
4376 crect->property_x1() = x1;
4377 crect->property_x2() = x2;
4379 update_marker_drag_item (temp_location);
4382 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4383 drag_info.first_move = false;
4385 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
4390 Editor::end_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event)
4392 Location * newloc = 0;
4394 if (!drag_info.first_move) {
4395 drag_range_markerbar_op (item, event);
4397 switch (range_marker_op) {
4398 case CreateRangeMarker:
4399 begin_reversible_command (_("new range marker"));
4400 session->add_undo (session->locations()->get_memento());
4401 newloc = new Location(temp_location->start(), temp_location->end(), "unnamed", Location::IsRangeMarker);
4402 session->locations()->add (newloc, true);
4403 session->add_redo_no_execute (session->locations()->get_memento());
4404 commit_reversible_command ();
4406 range_bar_drag_rect->hide();
4407 range_marker_drag_rect->hide();
4410 case CreateTransportMarker:
4411 // popup menu to pick loop or punch
4412 new_transport_marker_context_menu (&event->button, item);
4417 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
4419 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
4421 jack_nframes_t start;
4424 start = session->locations()->first_mark_before (drag_info.grab_frame);
4425 end = session->locations()->first_mark_after (drag_info.grab_frame);
4427 if (end == max_frames) {
4428 end = session->current_end_frame ();
4432 start = session->current_start_frame ();
4435 switch (mouse_mode) {
4437 /* find the two markers on either side and then make the selection from it */
4438 cerr << "select between " << start << " .. " << end << endl;
4439 select_all_within (start, end, 0.0f, FLT_MAX, Selection::Set);
4443 /* find the two markers on either side of the click and make the range out of it */
4444 selection->set (0, start, end);
4453 stop_canvas_autoscroll ();
4459 Editor::start_mouse_zoom (ArdourCanvas::Item* item, GdkEvent* event)
4461 drag_info.item = item;
4462 drag_info.motion_callback = &Editor::drag_mouse_zoom;
4463 drag_info.finished_callback = &Editor::end_mouse_zoom;
4465 start_grab (event, zoom_cursor);
4467 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4471 Editor::drag_mouse_zoom (ArdourCanvas::Item* item, GdkEvent* event)
4473 jack_nframes_t start;
4476 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4477 snap_to (drag_info.current_pointer_frame);
4479 if (drag_info.first_move) {
4480 snap_to (drag_info.grab_frame);
4484 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) return;
4486 /* base start and end on initial click position */
4487 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4488 start = drag_info.current_pointer_frame;
4489 end = drag_info.grab_frame;
4491 end = drag_info.current_pointer_frame;
4492 start = drag_info.grab_frame;
4497 if (drag_info.first_move) {
4499 zoom_rect->raise_to_top();
4502 reposition_zoom_rect(start, end);
4504 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4505 drag_info.first_move = false;
4507 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4512 Editor::end_mouse_zoom (ArdourCanvas::Item* item, GdkEvent* event)
4514 if (!drag_info.first_move) {
4515 drag_mouse_zoom (item, event);
4517 if (drag_info.grab_frame < drag_info.last_pointer_frame) {
4518 temporal_zoom_by_frame (drag_info.grab_frame, drag_info.last_pointer_frame, "mouse zoom");
4520 temporal_zoom_by_frame (drag_info.last_pointer_frame, drag_info.grab_frame, "mouse zoom");
4523 temporal_zoom_to_frame (false, drag_info.grab_frame);
4525 temporal_zoom_step (false);
4526 center_screen (drag_info.grab_frame);
4534 Editor::reposition_zoom_rect (jack_nframes_t start, jack_nframes_t end)
4536 double x1 = frame_to_pixel (start);
4537 double x2 = frame_to_pixel (end);
4538 double y2 = canvas_height - 2;
4540 zoom_rect->property_x1() = x1;
4541 zoom_rect->property_y1() = 1.0;
4542 zoom_rect->property_x2() = x2;
4543 zoom_rect->property_y2() = y2;
4547 Editor::start_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event)
4549 drag_info.item = item;
4550 drag_info.motion_callback = &Editor::drag_rubberband_select;
4551 drag_info.finished_callback = &Editor::end_rubberband_select;
4553 start_grab (event, cross_hair_cursor);
4555 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4559 Editor::drag_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event)
4561 jack_nframes_t start;
4566 /* use a bigger drag threshold than the default */
4568 if (abs ((int) (drag_info.current_pointer_frame - drag_info.grab_frame)) < 8) {
4572 // if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4573 // snap_to (drag_info.current_pointer_frame);
4575 // if (drag_info.first_move) {
4576 // snap_to (drag_info.grab_frame);
4581 /* base start and end on initial click position */
4582 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4583 start = drag_info.current_pointer_frame;
4584 end = drag_info.grab_frame;
4586 end = drag_info.current_pointer_frame;
4587 start = drag_info.grab_frame;
4590 if (drag_info.current_pointer_y < drag_info.grab_y) {
4591 y1 = drag_info.current_pointer_y;
4592 y2 = drag_info.grab_y;
4595 y2 = drag_info.current_pointer_y;
4596 y1 = drag_info.grab_y;
4600 if (start != end || y1 != y2) {
4602 double x1 = frame_to_pixel (start);
4603 double x2 = frame_to_pixel (end);
4605 rubberband_rect->property_x1() = x1;
4606 rubberband_rect->property_y1() = y1;
4607 rubberband_rect->property_x2() = x2;
4608 rubberband_rect->property_y2() = y2;
4610 rubberband_rect->show();
4611 rubberband_rect->raise_to_top();
4613 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4614 drag_info.first_move = false;
4616 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4621 Editor::end_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event)
4623 if (!drag_info.first_move) {
4625 drag_rubberband_select (item, event);
4628 if (drag_info.current_pointer_y < drag_info.grab_y) {
4629 y1 = drag_info.current_pointer_y;
4630 y2 = drag_info.grab_y;
4633 y2 = drag_info.current_pointer_y;
4634 y1 = drag_info.grab_y;
4638 Selection::Operation op = Keyboard::selection_type (event->button.state);
4641 begin_reversible_command (_("select regions"));
4643 if (drag_info.grab_frame < drag_info.last_pointer_frame) {
4644 commit = select_all_within (drag_info.grab_frame, drag_info.last_pointer_frame, y1, y2, op);
4646 commit = select_all_within (drag_info.last_pointer_frame, drag_info.grab_frame, y1, y2, op);
4650 commit_reversible_command ();
4654 selection->clear_audio_regions();
4655 selection->clear_points ();
4656 selection->clear_lines ();
4659 rubberband_rect->hide();
4664 Editor::mouse_rename_region (ArdourCanvas::Item* item, GdkEvent* event)
4666 using namespace Gtkmm2ext;
4668 ArdourPrompter prompter (false);
4670 prompter.set_prompt (_("Name for region:"));
4671 prompter.set_initial_text (clicked_regionview->region.name());
4672 prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
4673 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
4674 prompter.show_all ();
4675 switch (prompter.run ()) {
4676 case Gtk::RESPONSE_ACCEPT:
4678 prompter.get_result(str);
4680 clicked_regionview->region.set_name (str);
4688 Editor::start_time_fx (ArdourCanvas::Item* item, GdkEvent* event)
4690 drag_info.item = item;
4691 drag_info.motion_callback = &Editor::time_fx_motion;
4692 drag_info.finished_callback = &Editor::end_time_fx;
4696 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4700 Editor::time_fx_motion (ArdourCanvas::Item *item, GdkEvent* event)
4702 AudioRegionView* rv = clicked_regionview;
4704 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4705 snap_to (drag_info.current_pointer_frame);
4708 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) {
4712 if (drag_info.current_pointer_frame > rv->region.position()) {
4713 rv->get_time_axis_view().show_timestretch (rv->region.position(), drag_info.current_pointer_frame);
4716 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4717 drag_info.first_move = false;
4719 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4723 Editor::end_time_fx (ArdourCanvas::Item* item, GdkEvent* event)
4725 clicked_regionview->get_time_axis_view().hide_timestretch ();
4727 if (drag_info.first_move) {
4731 jack_nframes_t newlen = drag_info.last_pointer_frame - clicked_regionview->region.position();
4732 float percentage = (float) ((double) newlen - (double) clicked_regionview->region.length()) / ((double) newlen) * 100.0f;
4734 begin_reversible_command (_("timestretch"));
4736 if (run_timestretch (selection->audio_regions, percentage) == 0) {
4737 session->commit_reversible_command ();
4742 Editor::mouse_brush_insert_region (AudioRegionView* rv, jack_nframes_t pos)
4744 /* no brushing without a useful snap setting */
4746 switch (snap_mode) {
4748 return; /* can't work because it allows region to be placed anywhere */
4753 switch (snap_type) {
4756 case SnapToEditCursor:
4763 /* don't brush a copy over the original */
4765 if (pos == rv->region.position()) {
4769 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&rv->get_time_axis_view());
4771 if (atv == 0 || !atv->is_audio_track()) {
4775 Playlist* playlist = atv->playlist();
4776 double speed = atv->get_diskstream()->speed();
4778 session->add_undo (playlist->get_memento());
4779 playlist->add_region (*(new AudioRegion (rv->region)), (jack_nframes_t) (pos * speed));
4780 session->add_redo_no_execute (playlist->get_memento());
4782 // playlist is frozen, so we have to update manually
4784 playlist->StateChanged (Change (~0)); /* EMIT SIGNAL */
4788 Editor::track_height_step_timeout ()
4791 struct timeval delta;
4793 gettimeofday (&now, 0);
4794 timersub (&now, &last_track_height_step_timestamp, &delta);
4796 if (delta.tv_sec * 1000000 + delta.tv_usec > 250000) { /* milliseconds */
4797 current_stepping_trackview = 0;