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.
29 #include <pbd/error.h>
30 #include <gtkmm2ext/utils.h>
31 #include <pbd/memento_command.h>
33 #include "ardour_ui.h"
35 #include "time_axis_view.h"
36 #include "audio_time_axis.h"
37 #include "audio_region_view.h"
39 #include "streamview.h"
40 #include "region_gain_line.h"
41 #include "automation_time_axis.h"
44 #include "selection.h"
47 #include "rgb_macros.h"
49 #include <ardour/types.h>
50 #include <ardour/route.h>
51 #include <ardour/audio_track.h>
52 #include <ardour/audio_diskstream.h>
53 #include <ardour/playlist.h>
54 #include <ardour/audioplaylist.h>
55 #include <ardour/audioregion.h>
56 #include <ardour/dB.h>
57 #include <ardour/utils.h>
58 #include <ardour/region_factory.h>
65 using namespace ARDOUR;
69 using namespace Editing;
72 Editor::event_frame (GdkEvent* event, double* pcx, double* pcy)
86 switch (event->type) {
87 case GDK_BUTTON_RELEASE:
88 case GDK_BUTTON_PRESS:
89 case GDK_2BUTTON_PRESS:
90 case GDK_3BUTTON_PRESS:
91 track_canvas.w2c(event->button.x, event->button.y, *pcx, *pcy);
93 case GDK_MOTION_NOTIFY:
94 track_canvas.w2c(event->motion.x, event->motion.y, *pcx, *pcy);
96 case GDK_ENTER_NOTIFY:
97 case GDK_LEAVE_NOTIFY:
98 track_canvas.w2c(event->crossing.x, event->crossing.y, *pcx, *pcy);
101 case GDK_KEY_RELEASE:
102 // track_canvas.w2c(event->key.x, event->key.y, *pcx, *pcy);
105 warning << string_compose (_("Editor::event_frame() used on unhandled event type %1"), event->type) << endmsg;
109 /* note that pixel_to_frame() never returns less than zero, so even if the pixel
110 position is negative (as can be the case with motion events in particular),
111 the frame location is always positive.
114 return pixel_to_frame (*pcx);
118 Editor::mouse_mode_toggled (MouseMode m)
120 if (ignore_mouse_mode_toggle) {
126 if (mouse_select_button.get_active()) {
132 if (mouse_move_button.get_active()) {
138 if (mouse_gain_button.get_active()) {
144 if (mouse_zoom_button.get_active()) {
150 if (mouse_timefx_button.get_active()) {
156 if (mouse_audition_button.get_active()) {
167 Editor::set_mouse_mode (MouseMode m, bool force)
169 if (drag_info.item) {
173 if (!force && m == mouse_mode) {
181 if (mouse_mode != MouseRange) {
183 /* in all modes except range, hide the range selection,
184 show the object (region) selection.
187 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
188 (*i)->set_should_show_selection (true);
190 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
191 (*i)->hide_selection ();
197 in range mode,show the range selection.
200 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
201 if ((*i)->get_selected()) {
202 (*i)->show_selection (selection->time);
207 /* XXX the hack of unsetting all other buttongs should go
208 away once GTK2 allows us to use regular radio buttons drawn like
209 normal buttons, rather than my silly GroupedButton hack.
212 ignore_mouse_mode_toggle = true;
214 switch (mouse_mode) {
216 mouse_select_button.set_active (true);
217 current_canvas_cursor = selector_cursor;
221 mouse_move_button.set_active (true);
222 current_canvas_cursor = grabber_cursor;
226 mouse_gain_button.set_active (true);
227 current_canvas_cursor = cross_hair_cursor;
231 mouse_zoom_button.set_active (true);
232 current_canvas_cursor = zoom_cursor;
236 mouse_timefx_button.set_active (true);
237 current_canvas_cursor = time_fx_cursor; // just use playhead
241 mouse_audition_button.set_active (true);
242 current_canvas_cursor = speaker_cursor;
246 ignore_mouse_mode_toggle = false;
249 track_canvas.get_window()->set_cursor(*current_canvas_cursor);
254 Editor::step_mouse_mode (bool next)
256 switch (current_mouse_mode()) {
258 if (next) set_mouse_mode (MouseRange);
259 else set_mouse_mode (MouseTimeFX);
263 if (next) set_mouse_mode (MouseZoom);
264 else set_mouse_mode (MouseObject);
268 if (next) set_mouse_mode (MouseGain);
269 else set_mouse_mode (MouseRange);
273 if (next) set_mouse_mode (MouseTimeFX);
274 else set_mouse_mode (MouseZoom);
278 if (next) set_mouse_mode (MouseAudition);
279 else set_mouse_mode (MouseGain);
283 if (next) set_mouse_mode (MouseObject);
284 else set_mouse_mode (MouseTimeFX);
290 Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
296 /* in object/audition/timefx mode, any button press sets
297 the selection if the object can be selected. this is a
298 bit of hack, because we want to avoid this if the
299 mouse operation is a region alignment.
301 note: not dbl-click or triple-click
304 if (((mouse_mode != MouseObject) &&
305 (mouse_mode != MouseAudition || item_type != RegionItem) &&
306 (mouse_mode != MouseTimeFX || item_type != RegionItem)) ||
307 (event->type != GDK_BUTTON_PRESS && event->type != GDK_BUTTON_RELEASE || event->button.button > 3)) {
312 Selection::Operation op = Keyboard::selection_type (event->button.state);
313 bool press = (event->type == GDK_BUTTON_PRESS);
315 begin_reversible_command (_("select on click"));
319 c1 = set_selected_track_from_click (op, true);
320 c2 = set_selected_regionview_from_click (press, op, true);
324 case RegionViewNameHighlight:
326 c1 = set_selected_track_from_click (op, true);
327 c2 = set_selected_regionview_from_click (press, op, true);
331 case GainAutomationControlPointItem:
332 case PanAutomationControlPointItem:
333 case RedirectAutomationControlPointItem:
334 c1 = set_selected_track_from_click (op, true);
335 c2 = set_selected_control_point_from_click (op, false);
340 commit = set_selected_track_from_click (op, true);
343 case AutomationTrackItem:
344 commit = set_selected_track_from_click (op, true);
351 #define SELECT_TRACK_FROM_CANVAS_IN_RANGE_MODE
352 #ifdef SELECT_TRACK_FROM_CANVAS_IN_RANGE_MODE
353 /* in range mode, button 1/2/3 press potentially selects a track */
355 if (mouse_mode == MouseRange &&
356 event->type == GDK_BUTTON_PRESS &&
357 event->button.button <= 3) {
362 case AutomationTrackItem:
363 commit = set_selected_track_from_click (op, true);
372 commit_reversible_command ();
377 Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
379 nframes_t where = event_frame (event, 0, 0);
381 track_canvas.grab_focus();
383 if (session && session->actively_recording()) {
387 button_selection (item, event, item_type);
389 if (drag_info.item == 0 &&
390 (Keyboard::is_delete_event (&event->button) ||
391 Keyboard::is_context_menu_event (&event->button) ||
392 Keyboard::is_edit_event (&event->button))) {
394 /* handled by button release */
398 switch (event->button.button) {
401 if (event->type == GDK_BUTTON_PRESS) {
403 if (drag_info.item) {
404 drag_info.item->ungrab (event->button.time);
407 /* single mouse clicks on any of these item types operate
408 independent of mouse mode, mostly because they are
409 not on the main track canvas or because we want
415 case PlayheadCursorItem:
416 start_cursor_grab (item, event);
420 if (Keyboard::modifier_state_equals (event->button.state,
421 Keyboard::ModifierMask(Keyboard::Control|Keyboard::Shift))) {
422 hide_marker (item, event);
424 start_marker_grab (item, event);
428 case TempoMarkerItem:
429 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
430 start_tempo_marker_copy_grab (item, event);
432 start_tempo_marker_grab (item, event);
436 case MeterMarkerItem:
437 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
438 start_meter_marker_copy_grab (item, event);
440 start_meter_marker_grab (item, event);
450 case RangeMarkerBarItem:
451 start_range_markerbar_op (item, event, CreateRangeMarker);
455 case TransportMarkerBarItem:
456 start_range_markerbar_op (item, event, CreateTransportMarker);
465 switch (mouse_mode) {
468 case StartSelectionTrimItem:
469 start_selection_op (item, event, SelectionStartTrim);
472 case EndSelectionTrimItem:
473 start_selection_op (item, event, SelectionEndTrim);
477 if (Keyboard::modifier_state_contains
478 (event->button.state, Keyboard::ModifierMask(Keyboard::Alt))) {
479 // contains and not equals because I can't use alt as a modifier alone.
480 start_selection_grab (item, event);
481 } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
482 /* grab selection for moving */
483 start_selection_op (item, event, SelectionMove);
486 /* this was debated, but decided the more common action was to
487 make a new selection */
488 start_selection_op (item, event, CreateSelection);
493 start_selection_op (item, event, CreateSelection);
499 if (Keyboard::modifier_state_contains (event->button.state,
500 Keyboard::ModifierMask(Keyboard::Control|Keyboard::Alt))
501 && event->type == GDK_BUTTON_PRESS) {
503 start_rubberband_select (item, event);
505 } else if (event->type == GDK_BUTTON_PRESS) {
508 case FadeInHandleItem:
509 start_fade_in_grab (item, event);
512 case FadeOutHandleItem:
513 start_fade_out_grab (item, event);
517 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
518 start_region_copy_grab (item, event);
519 } else if (Keyboard::the_keyboard().key_is_down (GDK_b)) {
520 start_region_brush_grab (item, event);
522 start_region_grab (item, event);
526 case RegionViewNameHighlight:
527 start_trim (item, event);
532 /* rename happens on edit clicks */
533 start_trim (clicked_regionview->get_name_highlight(), event);
537 case GainAutomationControlPointItem:
538 case PanAutomationControlPointItem:
539 case RedirectAutomationControlPointItem:
540 start_control_point_grab (item, event);
544 case GainAutomationLineItem:
545 case PanAutomationLineItem:
546 case RedirectAutomationLineItem:
547 start_line_grab_from_line (item, event);
552 case AutomationTrackItem:
553 start_rubberband_select (item, event);
556 /* <CMT Additions> */
557 case ImageFrameHandleStartItem:
558 imageframe_start_handle_op(item, event) ;
561 case ImageFrameHandleEndItem:
562 imageframe_end_handle_op(item, event) ;
565 case MarkerViewHandleStartItem:
566 markerview_item_start_handle_op(item, event) ;
569 case MarkerViewHandleEndItem:
570 markerview_item_end_handle_op(item, event) ;
573 /* </CMT Additions> */
575 /* <CMT Additions> */
577 start_markerview_grab(item, event) ;
580 start_imageframe_grab(item, event) ;
582 /* </CMT Additions> */
598 // start_line_grab_from_regionview (item, event);
601 case GainControlPointItem:
602 start_control_point_grab (item, event);
606 start_line_grab_from_line (item, event);
609 case GainAutomationControlPointItem:
610 case PanAutomationControlPointItem:
611 case RedirectAutomationControlPointItem:
612 start_control_point_grab (item, event);
623 case GainAutomationControlPointItem:
624 case PanAutomationControlPointItem:
625 case RedirectAutomationControlPointItem:
626 start_control_point_grab (item, event);
629 case GainAutomationLineItem:
630 case PanAutomationLineItem:
631 case RedirectAutomationLineItem:
632 start_line_grab_from_line (item, event);
636 // XXX need automation mode to identify which
638 // start_line_grab_from_regionview (item, event);
648 if (event->type == GDK_BUTTON_PRESS) {
649 start_mouse_zoom (item, event);
656 if (item_type == RegionItem) {
657 start_time_fx (item, event);
662 /* handled in release */
671 switch (mouse_mode) {
673 if (event->type == GDK_BUTTON_PRESS) {
676 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
677 start_region_copy_grab (item, event);
679 start_region_grab (item, event);
683 case GainAutomationControlPointItem:
684 case PanAutomationControlPointItem:
685 case RedirectAutomationControlPointItem:
686 start_control_point_grab (item, event);
697 case RegionViewNameHighlight:
698 start_trim (item, event);
703 start_trim (clicked_regionview->get_name_highlight(), event);
714 if (event->type == GDK_BUTTON_PRESS) {
715 /* relax till release */
722 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
723 temporal_zoom_session();
725 temporal_zoom_to_frame (true, event_frame(event));
740 switch (mouse_mode) {
742 //temporal_zoom_to_frame (true, where);
743 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
744 temporal_zoom_to_frame (true, where);
747 temporal_zoom_step (true);
752 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::Alt))) {
753 scroll_backward (0.6f);
756 else if (Keyboard::no_modifier_keys_pressed (&event->button)) {
757 scroll_tracks_up_line ();
759 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
760 if (clicked_trackview) {
761 if (!current_stepping_trackview) {
762 step_timeout = Glib::signal_timeout().connect (mem_fun(*this, &Editor::track_height_step_timeout), 500);
763 current_stepping_trackview = clicked_trackview;
765 gettimeofday (&last_track_height_step_timestamp, 0);
766 current_stepping_trackview->step_height (true);
769 else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
770 temporal_zoom_to_frame (true, where);
777 switch (mouse_mode) {
779 // temporal_zoom_to_frame (false, where);
780 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
781 temporal_zoom_to_frame (false, where);
784 temporal_zoom_step (false);
789 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::Alt))) {
790 scroll_forward (0.6f);
793 else if (Keyboard::no_modifier_keys_pressed (&event->button)) {
794 scroll_tracks_down_line ();
796 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
797 if (clicked_trackview) {
798 if (!current_stepping_trackview) {
799 step_timeout = Glib::signal_timeout().connect (mem_fun(*this, &Editor::track_height_step_timeout), 500);
800 current_stepping_trackview = clicked_trackview;
802 gettimeofday (&last_track_height_step_timestamp, 0);
803 current_stepping_trackview->step_height (false);
805 } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
806 temporal_zoom_to_frame (false, where);
821 Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
823 nframes_t where = event_frame (event, 0, 0);
825 /* no action if we're recording */
827 if (session && session->actively_recording()) {
831 /* first, see if we're finishing a drag ... */
833 if (drag_info.item) {
834 if (end_grab (item, event)) {
835 /* grab dragged, so do nothing else */
840 button_selection (item, event, item_type);
842 /* edit events get handled here */
844 if (drag_info.item == 0 && Keyboard::is_edit_event (&event->button)) {
850 case TempoMarkerItem:
851 edit_tempo_marker (item);
854 case MeterMarkerItem:
855 edit_meter_marker (item);
859 if (clicked_regionview->name_active()) {
860 return mouse_rename_region (item, event);
870 /* context menu events get handled here */
872 if (Keyboard::is_context_menu_event (&event->button)) {
874 if (drag_info.item == 0) {
876 /* no matter which button pops up the context menu, tell the menu
877 widget to use button 1 to drive menu selection.
882 case FadeInHandleItem:
884 case FadeOutHandleItem:
885 popup_fade_context_menu (1, event->button.time, item, item_type);
889 popup_track_context_menu (1, event->button.time, item_type, false, where);
893 case RegionViewNameHighlight:
895 popup_track_context_menu (1, event->button.time, item_type, false, where);
899 popup_track_context_menu (1, event->button.time, item_type, true, where);
902 case AutomationTrackItem:
903 popup_track_context_menu (1, event->button.time, item_type, false, where);
907 case RangeMarkerBarItem:
908 case TransportMarkerBarItem:
911 popup_ruler_menu (pixel_to_frame(event->button.x), item_type);
915 marker_context_menu (&event->button, item);
918 case TempoMarkerItem:
919 tm_marker_context_menu (&event->button, item);
922 case MeterMarkerItem:
923 tm_marker_context_menu (&event->button, item);
926 case CrossfadeViewItem:
927 popup_track_context_menu (1, event->button.time, item_type, false, where);
930 /* <CMT Additions> */
932 popup_imageframe_edit_menu(1, event->button.time, item, true) ;
934 case ImageFrameTimeAxisItem:
935 popup_imageframe_edit_menu(1, event->button.time, item, false) ;
938 popup_marker_time_axis_edit_menu(1, event->button.time, item, true) ;
940 case MarkerTimeAxisItem:
941 popup_marker_time_axis_edit_menu(1, event->button.time, item, false) ;
943 /* <CMT Additions> */
954 /* delete events get handled here */
956 if (drag_info.item == 0 && Keyboard::is_delete_event (&event->button)) {
959 case TempoMarkerItem:
960 remove_tempo_marker (item);
963 case MeterMarkerItem:
964 remove_meter_marker (item);
968 remove_marker (*item, event);
972 if (mouse_mode == MouseObject) {
973 remove_clicked_region ();
977 case GainControlPointItem:
978 if (mouse_mode == MouseGain) {
979 remove_gain_control_point (item, event);
983 case GainAutomationControlPointItem:
984 case PanAutomationControlPointItem:
985 case RedirectAutomationControlPointItem:
986 remove_control_point (item, event);
995 switch (event->button.button) {
999 /* see comments in button_press_handler */
1000 case EditCursorItem:
1001 case PlayheadCursorItem:
1004 case GainAutomationLineItem:
1005 case PanAutomationLineItem:
1006 case RedirectAutomationLineItem:
1007 case StartSelectionTrimItem:
1008 case EndSelectionTrimItem:
1012 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1013 snap_to (where, 0, true);
1015 mouse_add_new_marker (where);
1019 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1022 mouse_add_new_tempo_event (where);
1026 mouse_add_new_meter_event (pixel_to_frame (event->button.x));
1034 switch (mouse_mode) {
1036 switch (item_type) {
1037 case AutomationTrackItem:
1038 dynamic_cast<AutomationTimeAxisView*>(clicked_trackview)->add_automation_event
1052 // Gain only makes sense for audio regions
1053 if ( ! dynamic_cast<AudioRegionView*>(clicked_regionview))
1056 switch (item_type) {
1058 dynamic_cast<AudioRegionView*>(clicked_regionview)->add_gain_point_event (item, event);
1062 case AutomationTrackItem:
1063 dynamic_cast<AutomationTimeAxisView*>(clicked_trackview)->
1064 add_automation_event (item, event, where, event->button.y);
1073 switch (item_type) {
1075 audition_selected_region ();
1092 switch (mouse_mode) {
1095 switch (item_type) {
1097 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
1099 } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::ModifierMask (Keyboard::Shift|Keyboard::Alt))) {
1102 // Button2 click is unused
1115 // x_style_paste (where, 1.0);
1135 Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
1141 switch (item_type) {
1142 case GainControlPointItem:
1143 if (mouse_mode == MouseGain) {
1144 cp = static_cast<ControlPoint*>(item->get_data ("control_point"));
1145 cp->set_visible (true);
1149 at_y = cp->get_y ();
1150 cp->item->i2w (at_x, at_y);
1154 fraction = 1.0 - (cp->get_y() / cp->line.height());
1156 set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y);
1157 show_verbose_canvas_cursor ();
1159 if (is_drawable()) {
1160 track_canvas.get_window()->set_cursor (*fader_cursor);
1165 case GainAutomationControlPointItem:
1166 case PanAutomationControlPointItem:
1167 case RedirectAutomationControlPointItem:
1168 cp = static_cast<ControlPoint*>(item->get_data ("control_point"));
1169 cp->set_visible (true);
1173 at_y = cp->get_y ();
1174 cp->item->i2w (at_x, at_y);
1178 fraction = 1.0 - (cp->get_y() / cp->line.height());
1180 set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y);
1181 show_verbose_canvas_cursor ();
1183 if (is_drawable()) {
1184 track_canvas.get_window()->set_cursor (*fader_cursor);
1189 if (mouse_mode == MouseGain) {
1190 ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
1192 line->property_fill_color_rgba() = color_map[cEnteredGainLine];
1193 if (is_drawable()) {
1194 track_canvas.get_window()->set_cursor (*fader_cursor);
1199 case GainAutomationLineItem:
1200 case RedirectAutomationLineItem:
1201 case PanAutomationLineItem:
1203 ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
1205 line->property_fill_color_rgba() = color_map[cEnteredAutomationLine];
1207 if (is_drawable()) {
1208 track_canvas.get_window()->set_cursor (*fader_cursor);
1212 case RegionViewNameHighlight:
1213 if (is_drawable() && mouse_mode == MouseObject) {
1214 track_canvas.get_window()->set_cursor (*trimmer_cursor);
1218 case StartSelectionTrimItem:
1219 case EndSelectionTrimItem:
1220 /* <CMT Additions> */
1221 case ImageFrameHandleStartItem:
1222 case ImageFrameHandleEndItem:
1223 case MarkerViewHandleStartItem:
1224 case MarkerViewHandleEndItem:
1225 /* </CMT Additions> */
1227 if (is_drawable()) {
1228 track_canvas.get_window()->set_cursor (*trimmer_cursor);
1232 case EditCursorItem:
1233 case PlayheadCursorItem:
1234 if (is_drawable()) {
1235 track_canvas.get_window()->set_cursor (*grabber_cursor);
1239 case RegionViewName:
1241 /* when the name is not an active item, the entire name highlight is for trimming */
1243 if (!reinterpret_cast<RegionView *> (item->get_data ("regionview"))->name_active()) {
1244 if (mouse_mode == MouseObject && is_drawable()) {
1245 track_canvas.get_window()->set_cursor (*trimmer_cursor);
1251 case AutomationTrackItem:
1252 if (is_drawable()) {
1253 Gdk::Cursor *cursor;
1254 switch (mouse_mode) {
1256 cursor = selector_cursor;
1259 cursor = zoom_cursor;
1262 cursor = cross_hair_cursor;
1266 track_canvas.get_window()->set_cursor (*cursor);
1268 AutomationTimeAxisView* atv;
1269 if ((atv = static_cast<AutomationTimeAxisView*>(item->get_data ("trackview"))) != 0) {
1270 clear_entered_track = false;
1271 set_entered_track (atv);
1277 case RangeMarkerBarItem:
1278 case TransportMarkerBarItem:
1281 if (is_drawable()) {
1282 time_canvas.get_window()->set_cursor (*timebar_cursor);
1287 if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
1290 marker->set_color_rgba (color_map[cEnteredMarker]);
1292 case MeterMarkerItem:
1293 case TempoMarkerItem:
1294 if (is_drawable()) {
1295 time_canvas.get_window()->set_cursor (*timebar_cursor);
1298 case FadeInHandleItem:
1299 case FadeOutHandleItem:
1300 if (mouse_mode == MouseObject) {
1301 ArdourCanvas::SimpleRect *rect = dynamic_cast<ArdourCanvas::SimpleRect *> (item);
1303 rect->property_fill_color_rgba() = 0;
1304 rect->property_outline_pixels() = 1;
1313 /* second pass to handle entered track status in a comprehensible way.
1316 switch (item_type) {
1318 case GainAutomationLineItem:
1319 case RedirectAutomationLineItem:
1320 case PanAutomationLineItem:
1321 case GainControlPointItem:
1322 case GainAutomationControlPointItem:
1323 case PanAutomationControlPointItem:
1324 case RedirectAutomationControlPointItem:
1325 /* these do not affect the current entered track state */
1326 clear_entered_track = false;
1329 case AutomationTrackItem:
1330 /* handled above already */
1334 set_entered_track (0);
1342 Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
1351 switch (item_type) {
1352 case GainControlPointItem:
1353 case GainAutomationControlPointItem:
1354 case PanAutomationControlPointItem:
1355 case RedirectAutomationControlPointItem:
1356 cp = reinterpret_cast<ControlPoint*>(item->get_data ("control_point"));
1357 if (cp->line.npoints() > 1) {
1358 if (!cp->selected) {
1359 cp->set_visible (false);
1363 if (is_drawable()) {
1364 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
1367 hide_verbose_canvas_cursor ();
1370 case RegionViewNameHighlight:
1371 case StartSelectionTrimItem:
1372 case EndSelectionTrimItem:
1373 case EditCursorItem:
1374 case PlayheadCursorItem:
1375 /* <CMT Additions> */
1376 case ImageFrameHandleStartItem:
1377 case ImageFrameHandleEndItem:
1378 case MarkerViewHandleStartItem:
1379 case MarkerViewHandleEndItem:
1380 /* </CMT Additions> */
1381 if (is_drawable()) {
1382 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
1387 case GainAutomationLineItem:
1388 case RedirectAutomationLineItem:
1389 case PanAutomationLineItem:
1390 al = reinterpret_cast<AutomationLine*> (item->get_data ("line"));
1392 ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
1394 line->property_fill_color_rgba() = al->get_line_color();
1396 if (is_drawable()) {
1397 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
1401 case RegionViewName:
1402 /* see enter_handler() for notes */
1403 if (!reinterpret_cast<RegionView *> (item->get_data ("regionview"))->name_active()) {
1404 if (is_drawable() && mouse_mode == MouseObject) {
1405 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
1410 case RangeMarkerBarItem:
1411 case TransportMarkerBarItem:
1415 if (is_drawable()) {
1416 time_canvas.get_window()->set_cursor (*timebar_cursor);
1421 if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
1424 loc = find_location_from_marker (marker, is_start);
1425 if (loc) location_flags_changed (loc, this);
1427 case MeterMarkerItem:
1428 case TempoMarkerItem:
1430 if (is_drawable()) {
1431 time_canvas.get_window()->set_cursor (*timebar_cursor);
1436 case FadeInHandleItem:
1437 case FadeOutHandleItem:
1438 rv = static_cast<RegionView*>(item->get_data ("regionview"));
1440 ArdourCanvas::SimpleRect *rect = dynamic_cast<ArdourCanvas::SimpleRect *> (item);
1442 rect->property_fill_color_rgba() = rv->get_fill_color();
1443 rect->property_outline_pixels() = 0;
1448 case AutomationTrackItem:
1449 if (is_drawable()) {
1450 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
1451 clear_entered_track = true;
1452 Glib::signal_idle().connect (mem_fun(*this, &Editor::left_automation_track));
1464 Editor::left_automation_track ()
1466 if (clear_entered_track) {
1467 set_entered_track (0);
1468 clear_entered_track = false;
1474 Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type, bool from_autoscroll)
1478 /* We call this so that MOTION_NOTIFY events continue to be
1479 delivered to the canvas. We need to do this because we set
1480 Gdk::POINTER_MOTION_HINT_MASK on the canvas. This reduces
1481 the density of the events, at the expense of a round-trip
1482 to the server. Given that this will mostly occur on cases
1483 where DISPLAY = :0.0, and given the cost of what the motion
1484 event might do, its a good tradeoff.
1487 track_canvas.get_pointer (x, y);
1489 if (current_stepping_trackview) {
1490 /* don't keep the persistent stepped trackview if the mouse moves */
1491 current_stepping_trackview = 0;
1492 step_timeout.disconnect ();
1495 if (session && session->actively_recording()) {
1496 /* Sorry. no dragging stuff around while we record */
1500 drag_info.item_type = item_type;
1501 drag_info.current_pointer_frame = event_frame (event, &drag_info.current_pointer_x,
1502 &drag_info.current_pointer_y);
1504 if (!from_autoscroll && drag_info.item) {
1505 /* item != 0 is the best test i can think of for dragging.
1507 if (!drag_info.move_threshold_passed) {
1509 drag_info.move_threshold_passed = (abs ((int) (drag_info.current_pointer_x - drag_info.grab_x)) > 4);
1511 // and change the initial grab loc/frame if this drag info wants us to
1513 if (drag_info.want_move_threshold && drag_info.move_threshold_passed) {
1514 drag_info.grab_frame = drag_info.current_pointer_frame;
1515 drag_info.grab_x = drag_info.current_pointer_x;
1516 drag_info.grab_y = drag_info.current_pointer_y;
1517 drag_info.last_pointer_frame = drag_info.grab_frame;
1518 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
1523 switch (item_type) {
1524 case PlayheadCursorItem:
1525 case EditCursorItem:
1527 case GainControlPointItem:
1528 case RedirectAutomationControlPointItem:
1529 case GainAutomationControlPointItem:
1530 case PanAutomationControlPointItem:
1531 case TempoMarkerItem:
1532 case MeterMarkerItem:
1533 case RegionViewNameHighlight:
1534 case StartSelectionTrimItem:
1535 case EndSelectionTrimItem:
1538 case RedirectAutomationLineItem:
1539 case GainAutomationLineItem:
1540 case PanAutomationLineItem:
1541 case FadeInHandleItem:
1542 case FadeOutHandleItem:
1543 /* <CMT Additions> */
1544 case ImageFrameHandleStartItem:
1545 case ImageFrameHandleEndItem:
1546 case MarkerViewHandleStartItem:
1547 case MarkerViewHandleEndItem:
1548 /* </CMT Additions> */
1549 if (drag_info.item && (event->motion.state & Gdk::BUTTON1_MASK ||
1550 (event->motion.state & Gdk::BUTTON2_MASK))) {
1551 if (!from_autoscroll) {
1552 maybe_autoscroll (event);
1554 (this->*(drag_info.motion_callback)) (item, event);
1563 switch (mouse_mode) {
1568 if (drag_info.item && (event->motion.state & GDK_BUTTON1_MASK ||
1569 (event->motion.state & GDK_BUTTON2_MASK))) {
1570 if (!from_autoscroll) {
1571 maybe_autoscroll (event);
1573 (this->*(drag_info.motion_callback)) (item, event);
1584 track_canvas_motion (event);
1585 // drag_info.last_pointer_frame = drag_info.current_pointer_frame;
1593 Editor::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
1595 if (drag_info.item == 0) {
1596 fatal << _("programming error: start_grab called without drag item") << endmsg;
1602 cursor = grabber_cursor;
1605 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
1607 if (event->button.button == 2) {
1608 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Alt)) {
1609 drag_info.y_constrained = true;
1610 drag_info.x_constrained = false;
1612 drag_info.y_constrained = false;
1613 drag_info.x_constrained = true;
1616 drag_info.x_constrained = false;
1617 drag_info.y_constrained = false;
1620 drag_info.grab_frame = event_frame(event, &drag_info.grab_x, &drag_info.grab_y);
1621 drag_info.last_pointer_frame = drag_info.grab_frame;
1622 drag_info.current_pointer_frame = drag_info.grab_frame;
1623 drag_info.current_pointer_x = drag_info.grab_x;
1624 drag_info.current_pointer_y = drag_info.grab_y;
1625 drag_info.cumulative_x_drag = 0;
1626 drag_info.cumulative_y_drag = 0;
1627 drag_info.first_move = true;
1628 drag_info.move_threshold_passed = false;
1629 drag_info.want_move_threshold = false;
1630 drag_info.pointer_frame_offset = 0;
1631 drag_info.brushing = false;
1632 drag_info.copied_location = 0;
1634 drag_info.item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
1636 event->button.time);
1638 if (session && session->transport_rolling()) {
1639 drag_info.was_rolling = true;
1641 drag_info.was_rolling = false;
1644 switch (snap_type) {
1645 case SnapToRegionStart:
1646 case SnapToRegionEnd:
1647 case SnapToRegionSync:
1648 case SnapToRegionBoundary:
1649 build_region_boundary_cache ();
1657 Editor::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t time)
1659 drag_info.item->ungrab (0);
1660 drag_info.item = new_item;
1663 cursor = grabber_cursor;
1666 drag_info.item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK, *cursor, time);
1670 Editor::end_grab (ArdourCanvas::Item* item, GdkEvent* event)
1672 bool did_drag = false;
1674 stop_canvas_autoscroll ();
1676 if (drag_info.item == 0) {
1680 drag_info.item->ungrab (event->button.time);
1682 if (drag_info.finished_callback) {
1683 (this->*(drag_info.finished_callback)) (item, event);
1686 did_drag = !drag_info.first_move;
1688 hide_verbose_canvas_cursor();
1691 drag_info.copy = false;
1692 drag_info.motion_callback = 0;
1693 drag_info.finished_callback = 0;
1694 drag_info.last_trackview = 0;
1695 drag_info.last_frame_position = 0;
1696 drag_info.grab_frame = 0;
1697 drag_info.last_pointer_frame = 0;
1698 drag_info.current_pointer_frame = 0;
1699 drag_info.brushing = false;
1701 if (drag_info.copied_location) {
1702 delete drag_info.copied_location;
1703 drag_info.copied_location = 0;
1710 Editor::set_edit_cursor (GdkEvent* event)
1712 nframes_t pointer_frame = event_frame (event);
1714 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1715 if (snap_type != SnapToEditCursor) {
1716 snap_to (pointer_frame);
1720 edit_cursor->set_position (pointer_frame);
1721 edit_cursor_clock.set (pointer_frame);
1725 Editor::set_playhead_cursor (GdkEvent* event)
1727 nframes_t pointer_frame = event_frame (event);
1729 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1730 snap_to (pointer_frame);
1734 session->request_locate (pointer_frame, session->transport_rolling());
1739 Editor::start_fade_in_grab (ArdourCanvas::Item* item, GdkEvent* event)
1741 drag_info.item = item;
1742 drag_info.motion_callback = &Editor::fade_in_drag_motion_callback;
1743 drag_info.finished_callback = &Editor::fade_in_drag_finished_callback;
1747 if ((drag_info.data = (item->get_data ("regionview"))) == 0) {
1748 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1752 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1754 drag_info.pointer_frame_offset = drag_info.grab_frame - ((nframes_t) arv->audio_region()->fade_in().back()->when + arv->region()->position());
1758 Editor::fade_in_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
1760 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1762 nframes_t fade_length;
1764 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1765 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1771 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1775 if (pos < (arv->region()->position() + 64)) {
1776 fade_length = 64; // this should be a minimum defined somewhere
1777 } else if (pos > arv->region()->last_frame()) {
1778 fade_length = arv->region()->length();
1780 fade_length = pos - arv->region()->position();
1783 arv->reset_fade_in_shape_width (fade_length);
1785 show_verbose_duration_cursor (arv->region()->position(), arv->region()->position() + fade_length, 10);
1787 drag_info.first_move = false;
1791 Editor::fade_in_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
1793 if (drag_info.first_move) return;
1795 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1797 nframes_t fade_length;
1799 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1800 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1806 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1810 if (pos < (arv->region()->position() + 64)) {
1811 fade_length = 64; // this should be a minimum defined somewhere
1813 else if (pos > arv->region()->last_frame()) {
1814 fade_length = arv->region()->length();
1817 fade_length = pos - arv->region()->position();
1820 begin_reversible_command (_("change fade in length"));
1821 AutomationList& alist = arv->audio_region()->fade_in();
1822 XMLNode &before = alist.get_state();
1824 arv->audio_region()->set_fade_in_length (fade_length);
1826 XMLNode &after = alist.get_state();
1827 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
1828 commit_reversible_command ();
1829 fade_in_drag_motion_callback (item, event);
1833 Editor::start_fade_out_grab (ArdourCanvas::Item* item, GdkEvent* event)
1835 drag_info.item = item;
1836 drag_info.motion_callback = &Editor::fade_out_drag_motion_callback;
1837 drag_info.finished_callback = &Editor::fade_out_drag_finished_callback;
1841 if ((drag_info.data = (item->get_data ("regionview"))) == 0) {
1842 fatal << _("programming error: fade out canvas item has no regionview data pointer!") << endmsg;
1846 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1848 drag_info.pointer_frame_offset = drag_info.grab_frame - (arv->region()->length() - (nframes_t) arv->audio_region()->fade_out().back()->when + arv->region()->position());
1852 Editor::fade_out_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
1854 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1856 nframes_t fade_length;
1858 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1859 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1865 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1869 if (pos > (arv->region()->last_frame() - 64)) {
1870 fade_length = 64; // this should really be a minimum fade defined somewhere
1872 else if (pos < arv->region()->position()) {
1873 fade_length = arv->region()->length();
1876 fade_length = arv->region()->last_frame() - pos;
1879 arv->reset_fade_out_shape_width (fade_length);
1881 show_verbose_duration_cursor (arv->region()->last_frame() - fade_length, arv->region()->last_frame(), 10);
1883 drag_info.first_move = false;
1887 Editor::fade_out_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
1889 if (drag_info.first_move) return;
1891 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1893 nframes_t fade_length;
1895 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1896 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1902 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1906 if (pos > (arv->region()->last_frame() - 64)) {
1907 fade_length = 64; // this should really be a minimum fade defined somewhere
1909 else if (pos < arv->region()->position()) {
1910 fade_length = arv->region()->length();
1913 fade_length = arv->region()->last_frame() - pos;
1916 begin_reversible_command (_("change fade out length"));
1917 AutomationList& alist = arv->audio_region()->fade_out();
1918 XMLNode &before = alist.get_state();
1920 arv->audio_region()->set_fade_out_length (fade_length);
1922 XMLNode &after = alist.get_state();
1923 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
1924 commit_reversible_command ();
1926 fade_out_drag_motion_callback (item, event);
1930 Editor::start_cursor_grab (ArdourCanvas::Item* item, GdkEvent* event)
1932 drag_info.item = item;
1933 drag_info.motion_callback = &Editor::cursor_drag_motion_callback;
1934 drag_info.finished_callback = &Editor::cursor_drag_finished_callback;
1938 if ((drag_info.data = (item->get_data ("cursor"))) == 0) {
1939 fatal << _("programming error: cursor canvas item has no cursor data pointer!") << endmsg;
1943 Cursor* cursor = (Cursor *) drag_info.data;
1945 if (session && cursor == playhead_cursor) {
1946 if (drag_info.was_rolling) {
1947 session->request_stop ();
1951 drag_info.pointer_frame_offset = drag_info.grab_frame - cursor->current_frame;
1953 show_verbose_time_cursor (cursor->current_frame, 10);
1957 Editor::cursor_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
1959 Cursor* cursor = (Cursor *) drag_info.data;
1960 nframes_t adjusted_frame;
1962 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1963 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1969 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1970 if (cursor != edit_cursor || snap_type != SnapToEditCursor) {
1971 snap_to (adjusted_frame);
1975 if (adjusted_frame == drag_info.last_pointer_frame) return;
1977 cursor->set_position (adjusted_frame);
1979 if (cursor == edit_cursor) {
1980 edit_cursor_clock.set (cursor->current_frame);
1982 UpdateAllTransportClocks (cursor->current_frame);
1985 show_verbose_time_cursor (cursor->current_frame, 10);
1987 drag_info.last_pointer_frame = adjusted_frame;
1988 drag_info.first_move = false;
1992 Editor::cursor_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
1994 if (drag_info.first_move) return;
1996 cursor_drag_motion_callback (item, event);
1998 if (item == &playhead_cursor->canvas_item) {
2000 session->request_locate (playhead_cursor->current_frame, drag_info.was_rolling);
2002 } else if (item == &edit_cursor->canvas_item) {
2003 edit_cursor->set_position (edit_cursor->current_frame);
2004 edit_cursor_clock.set (edit_cursor->current_frame);
2009 Editor::update_marker_drag_item (Location *location)
2011 double x1 = frame_to_pixel (location->start());
2012 double x2 = frame_to_pixel (location->end());
2014 if (location->is_mark()) {
2015 marker_drag_line_points.front().set_x(x1);
2016 marker_drag_line_points.back().set_x(x1);
2017 marker_drag_line->property_points() = marker_drag_line_points;
2020 range_marker_drag_rect->property_x1() = x1;
2021 range_marker_drag_rect->property_x2() = x2;
2026 Editor::start_marker_grab (ArdourCanvas::Item* item, GdkEvent* event)
2030 if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
2031 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
2037 Location *location = find_location_from_marker (marker, is_start);
2039 drag_info.item = item;
2040 drag_info.data = marker;
2041 drag_info.motion_callback = &Editor::marker_drag_motion_callback;
2042 drag_info.finished_callback = &Editor::marker_drag_finished_callback;
2046 drag_info.copied_location = new Location (*location);
2047 drag_info.pointer_frame_offset = drag_info.grab_frame - (is_start ? location->start() : location->end());
2049 update_marker_drag_item (location);
2051 if (location->is_mark()) {
2052 marker_drag_line->show();
2053 marker_drag_line->raise_to_top();
2056 range_marker_drag_rect->show();
2057 range_marker_drag_rect->raise_to_top();
2060 if (is_start) show_verbose_time_cursor (location->start(), 10);
2061 else show_verbose_time_cursor (location->end(), 10);
2065 Editor::marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2068 Marker* marker = (Marker *) drag_info.data;
2069 Location *real_location;
2070 Location *copy_location;
2072 bool move_both = false;
2076 if (drag_info.pointer_frame_offset <= (long) drag_info.current_pointer_frame) {
2077 newframe = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2083 nframes_t next = newframe;
2085 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2086 snap_to (newframe, 0, true);
2089 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) {
2093 /* call this to find out if its the start or end */
2095 real_location = find_location_from_marker (marker, is_start);
2097 /* use the copy that we're "dragging" around */
2099 copy_location = drag_info.copied_location;
2101 f_delta = copy_location->end() - copy_location->start();
2103 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
2107 if (copy_location->is_mark()) {
2110 copy_location->set_start (newframe);
2114 if (is_start) { // start-of-range marker
2117 copy_location->set_start (newframe);
2118 copy_location->set_end (newframe + f_delta);
2119 } else if (newframe < copy_location->end()) {
2120 copy_location->set_start (newframe);
2122 snap_to (next, 1, true);
2123 copy_location->set_end (next);
2124 copy_location->set_start (newframe);
2127 } else { // end marker
2130 copy_location->set_end (newframe);
2131 copy_location->set_start (newframe - f_delta);
2132 } else if (newframe > copy_location->start()) {
2133 copy_location->set_end (newframe);
2135 } else if (newframe > 0) {
2136 snap_to (next, -1, true);
2137 copy_location->set_start (next);
2138 copy_location->set_end (newframe);
2143 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
2144 drag_info.first_move = false;
2146 update_marker_drag_item (copy_location);
2148 LocationMarkers* lm = find_location_markers (real_location);
2149 lm->set_position (copy_location->start(), copy_location->end());
2151 show_verbose_time_cursor (newframe, 10);
2155 Editor::marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2157 if (drag_info.first_move) {
2158 marker_drag_motion_callback (item, event);
2162 Marker* marker = (Marker *) drag_info.data;
2166 begin_reversible_command ( _("move marker") );
2167 XMLNode &before = session->locations()->get_state();
2169 Location * location = find_location_from_marker (marker, is_start);
2172 if (location->is_mark()) {
2173 location->set_start (drag_info.copied_location->start());
2175 location->set (drag_info.copied_location->start(), drag_info.copied_location->end());
2179 XMLNode &after = session->locations()->get_state();
2180 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
2181 commit_reversible_command ();
2183 marker_drag_line->hide();
2184 range_marker_drag_rect->hide();
2188 Editor::start_meter_marker_grab (ArdourCanvas::Item* item, GdkEvent* event)
2191 MeterMarker* meter_marker;
2193 if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
2194 fatal << _("programming error: meter marker canvas item has no marker object pointer!") << endmsg;
2198 meter_marker = dynamic_cast<MeterMarker*> (marker);
2200 MetricSection& section (meter_marker->meter());
2202 if (!section.movable()) {
2206 drag_info.item = item;
2207 drag_info.data = marker;
2208 drag_info.motion_callback = &Editor::meter_marker_drag_motion_callback;
2209 drag_info.finished_callback = &Editor::meter_marker_drag_finished_callback;
2213 drag_info.pointer_frame_offset = drag_info.grab_frame - meter_marker->meter().frame();
2215 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2219 Editor::start_meter_marker_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
2222 MeterMarker* meter_marker;
2224 if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
2225 fatal << _("programming error: meter marker canvas item has no marker object pointer!") << endmsg;
2229 meter_marker = dynamic_cast<MeterMarker*> (marker);
2231 // create a dummy marker for visual representation of moving the copy.
2232 // The actual copying is not done before we reach the finish callback.
2234 snprintf (name, sizeof(name), "%g/%g", meter_marker->meter().beats_per_bar(), meter_marker->meter().note_divisor ());
2235 MeterMarker* new_marker = new MeterMarker(*this, *meter_group, color_map[cMeterMarker], name,
2236 *new MeterSection(meter_marker->meter()));
2238 drag_info.item = &new_marker->the_item();
2239 drag_info.copy = true;
2240 drag_info.data = new_marker;
2241 drag_info.motion_callback = &Editor::meter_marker_drag_motion_callback;
2242 drag_info.finished_callback = &Editor::meter_marker_drag_finished_callback;
2246 drag_info.pointer_frame_offset = drag_info.grab_frame - meter_marker->meter().frame();
2248 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2252 Editor::meter_marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2254 MeterMarker* marker = (MeterMarker *) drag_info.data;
2255 nframes_t adjusted_frame;
2257 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
2258 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2264 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2265 snap_to (adjusted_frame);
2268 if (adjusted_frame == drag_info.last_pointer_frame) return;
2270 marker->set_position (adjusted_frame);
2273 drag_info.last_pointer_frame = adjusted_frame;
2274 drag_info.first_move = false;
2276 show_verbose_time_cursor (adjusted_frame, 10);
2280 Editor::meter_marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2282 if (drag_info.first_move) return;
2284 meter_marker_drag_motion_callback (drag_info.item, event);
2286 MeterMarker* marker = (MeterMarker *) drag_info.data;
2289 TempoMap& map (session->tempo_map());
2290 map.bbt_time (drag_info.last_pointer_frame, when);
2292 if (drag_info.copy == true) {
2293 begin_reversible_command (_("copy meter mark"));
2294 XMLNode &before = map.get_state();
2295 map.add_meter (marker->meter(), when);
2296 XMLNode &after = map.get_state();
2297 session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
2298 commit_reversible_command ();
2300 // delete the dummy marker we used for visual representation of copying.
2301 // a new visual marker will show up automatically.
2304 begin_reversible_command (_("move meter mark"));
2305 XMLNode &before = map.get_state();
2306 map.move_meter (marker->meter(), when);
2307 XMLNode &after = map.get_state();
2308 session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
2309 commit_reversible_command ();
2314 Editor::start_tempo_marker_grab (ArdourCanvas::Item* item, GdkEvent* event)
2317 TempoMarker* tempo_marker;
2319 if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
2320 fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg;
2324 if ((tempo_marker = dynamic_cast<TempoMarker *> (marker)) == 0) {
2325 fatal << _("programming error: marker for tempo is not a tempo marker!") << endmsg;
2329 MetricSection& section (tempo_marker->tempo());
2331 if (!section.movable()) {
2335 drag_info.item = item;
2336 drag_info.data = marker;
2337 drag_info.motion_callback = &Editor::tempo_marker_drag_motion_callback;
2338 drag_info.finished_callback = &Editor::tempo_marker_drag_finished_callback;
2342 drag_info.pointer_frame_offset = drag_info.grab_frame - tempo_marker->tempo().frame();
2343 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2347 Editor::start_tempo_marker_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
2350 TempoMarker* tempo_marker;
2352 if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
2353 fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg;
2357 if ((tempo_marker = dynamic_cast<TempoMarker *> (marker)) == 0) {
2358 fatal << _("programming error: marker for tempo is not a tempo marker!") << endmsg;
2362 // create a dummy marker for visual representation of moving the copy.
2363 // The actual copying is not done before we reach the finish callback.
2365 snprintf (name, sizeof (name), "%.2f", tempo_marker->tempo().beats_per_minute());
2366 TempoMarker* new_marker = new TempoMarker(*this, *tempo_group, color_map[cTempoMarker], name,
2367 *new TempoSection(tempo_marker->tempo()));
2369 drag_info.item = &new_marker->the_item();
2370 drag_info.copy = true;
2371 drag_info.data = new_marker;
2372 drag_info.motion_callback = &Editor::tempo_marker_drag_motion_callback;
2373 drag_info.finished_callback = &Editor::tempo_marker_drag_finished_callback;
2377 drag_info.pointer_frame_offset = drag_info.grab_frame - tempo_marker->tempo().frame();
2379 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2383 Editor::tempo_marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2385 TempoMarker* marker = (TempoMarker *) drag_info.data;
2386 nframes_t adjusted_frame;
2388 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
2389 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2395 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2396 snap_to (adjusted_frame);
2399 if (adjusted_frame == drag_info.last_pointer_frame) return;
2401 /* OK, we've moved far enough to make it worth actually move the thing. */
2403 marker->set_position (adjusted_frame);
2405 show_verbose_time_cursor (adjusted_frame, 10);
2407 drag_info.last_pointer_frame = adjusted_frame;
2408 drag_info.first_move = false;
2412 Editor::tempo_marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2414 if (drag_info.first_move) return;
2416 tempo_marker_drag_motion_callback (drag_info.item, event);
2418 TempoMarker* marker = (TempoMarker *) drag_info.data;
2421 TempoMap& map (session->tempo_map());
2422 map.bbt_time (drag_info.last_pointer_frame, when);
2424 if (drag_info.copy == true) {
2425 begin_reversible_command (_("copy tempo mark"));
2426 XMLNode &before = map.get_state();
2427 map.add_tempo (marker->tempo(), when);
2428 XMLNode &after = map.get_state();
2429 session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2430 commit_reversible_command ();
2432 // delete the dummy marker we used for visual representation of copying.
2433 // a new visual marker will show up automatically.
2436 begin_reversible_command (_("move tempo mark"));
2437 XMLNode &before = map.get_state();
2438 map.move_tempo (marker->tempo(), when);
2439 XMLNode &after = map.get_state();
2440 session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2441 commit_reversible_command ();
2446 Editor::remove_gain_control_point (ArdourCanvas::Item*item, GdkEvent* event)
2448 ControlPoint* control_point;
2450 if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
2451 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2455 // We shouldn't remove the first or last gain point
2456 if (control_point->line.is_last_point(*control_point) ||
2457 control_point->line.is_first_point(*control_point)) {
2461 control_point->line.remove_point (*control_point);
2465 Editor::remove_control_point (ArdourCanvas::Item*item, GdkEvent* event)
2467 ControlPoint* control_point;
2469 if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
2470 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2474 control_point->line.remove_point (*control_point);
2478 Editor::start_control_point_grab (ArdourCanvas::Item* item, GdkEvent* event)
2480 ControlPoint* control_point;
2482 if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
2483 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2487 drag_info.item = item;
2488 drag_info.data = control_point;
2489 drag_info.motion_callback = &Editor::control_point_drag_motion_callback;
2490 drag_info.finished_callback = &Editor::control_point_drag_finished_callback;
2492 start_grab (event, fader_cursor);
2494 control_point->line.start_drag (control_point, drag_info.grab_frame, 0);
2496 float fraction = 1.0 - (control_point->get_y() / control_point->line.height());
2497 set_verbose_canvas_cursor (control_point->line.get_verbose_cursor_string (fraction),
2498 drag_info.current_pointer_x + 20, drag_info.current_pointer_y + 20);
2500 show_verbose_canvas_cursor ();
2504 Editor::control_point_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2506 ControlPoint* cp = reinterpret_cast<ControlPoint *> (drag_info.data);
2508 double cx = drag_info.current_pointer_x;
2509 double cy = drag_info.current_pointer_y;
2511 drag_info.cumulative_x_drag = cx - drag_info.grab_x ;
2512 drag_info.cumulative_y_drag = cy - drag_info.grab_y ;
2514 if (drag_info.x_constrained) {
2515 cx = drag_info.grab_x;
2517 if (drag_info.y_constrained) {
2518 cy = drag_info.grab_y;
2521 cp->line.parent_group().w2i (cx, cy);
2525 cy = min ((double) cp->line.height(), cy);
2527 //translate cx to frames
2528 nframes_t cx_frames = unit_to_frame (cx);
2530 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && !drag_info.x_constrained) {
2531 snap_to (cx_frames);
2534 float fraction = 1.0 - (cy / cp->line.height());
2538 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
2544 cp->line.point_drag (*cp, cx_frames , fraction, push);
2546 set_verbose_canvas_cursor_text (cp->line.get_verbose_cursor_string (fraction));
2548 drag_info.first_move = false;
2552 Editor::control_point_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2554 ControlPoint* cp = reinterpret_cast<ControlPoint *> (drag_info.data);
2556 if (drag_info.first_move) {
2560 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
2561 reset_point_selection ();
2565 control_point_drag_motion_callback (item, event);
2567 cp->line.end_drag (cp);
2571 Editor::start_line_grab_from_regionview (ArdourCanvas::Item* item, GdkEvent* event)
2573 switch (mouse_mode) {
2575 assert(dynamic_cast<AudioRegionView*>(clicked_regionview));
2576 start_line_grab (dynamic_cast<AudioRegionView*>(clicked_regionview)->get_gain_line(), event);
2584 Editor::start_line_grab_from_line (ArdourCanvas::Item* item, GdkEvent* event)
2588 if ((al = reinterpret_cast<AutomationLine*> (item->get_data ("line"))) == 0) {
2589 fatal << _("programming error: line canvas item has no line pointer!") << endmsg;
2593 start_line_grab (al, event);
2597 Editor::start_line_grab (AutomationLine* line, GdkEvent* event)
2601 nframes_t frame_within_region;
2603 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2607 cx = event->button.x;
2608 cy = event->button.y;
2609 line->parent_group().w2i (cx, cy);
2610 frame_within_region = (nframes_t) floor (cx * frames_per_unit);
2612 if (!line->control_points_adjacent (frame_within_region, current_line_drag_info.before,
2613 current_line_drag_info.after)) {
2614 /* no adjacent points */
2618 drag_info.item = &line->grab_item();
2619 drag_info.data = line;
2620 drag_info.motion_callback = &Editor::line_drag_motion_callback;
2621 drag_info.finished_callback = &Editor::line_drag_finished_callback;
2623 start_grab (event, fader_cursor);
2625 double fraction = 1.0 - (cy / line->height());
2627 line->start_drag (0, drag_info.grab_frame, fraction);
2629 set_verbose_canvas_cursor (line->get_verbose_cursor_string (fraction),
2630 drag_info.current_pointer_x + 20, drag_info.current_pointer_y + 20);
2631 show_verbose_canvas_cursor ();
2635 Editor::line_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2637 AutomationLine* line = reinterpret_cast<AutomationLine *> (drag_info.data);
2638 double cx = drag_info.current_pointer_x;
2639 double cy = drag_info.current_pointer_y;
2641 line->parent_group().w2i (cx, cy);
2644 fraction = 1.0 - (cy / line->height());
2648 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
2654 line->line_drag (current_line_drag_info.before, current_line_drag_info.after, fraction, push);
2656 set_verbose_canvas_cursor_text (line->get_verbose_cursor_string (fraction));
2660 Editor::line_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2662 AutomationLine* line = reinterpret_cast<AutomationLine *> (drag_info.data);
2663 line_drag_motion_callback (item, event);
2668 Editor::start_region_grab (ArdourCanvas::Item* item, GdkEvent* event)
2670 if (selection->regions.empty() || clicked_regionview == 0) {
2674 drag_info.copy = false;
2675 drag_info.item = item;
2676 drag_info.data = clicked_regionview;
2677 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2678 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2683 TimeAxisView* tvp = clicked_trackview;
2684 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
2686 if (tv && tv->is_audio_track()) {
2687 speed = tv->get_diskstream()->speed();
2690 drag_info.last_frame_position = (nframes_t) (clicked_regionview->region()->position() / speed);
2691 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2692 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2693 // we want a move threshold
2694 drag_info.want_move_threshold = true;
2696 show_verbose_time_cursor (drag_info.last_frame_position, 10);
2698 begin_reversible_command (_("move region(s)"));
2702 Editor::start_region_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
2704 if (selection->regions.empty() || clicked_regionview == 0) {
2708 drag_info.copy = true;
2709 drag_info.item = item;
2710 drag_info.data = clicked_regionview;
2714 TimeAxisView* tv = &clicked_regionview->get_time_axis_view();
2715 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*>(tv);
2718 if (atv && atv->is_audio_track()) {
2719 speed = atv->get_diskstream()->speed();
2722 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2723 drag_info.last_frame_position = (nframes_t) (clicked_regionview->region()->position() / speed);
2724 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2725 // we want a move threshold
2726 drag_info.want_move_threshold = true;
2727 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2728 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2729 show_verbose_time_cursor (drag_info.last_frame_position, 10);
2733 Editor::start_region_brush_grab (ArdourCanvas::Item* item, GdkEvent* event)
2735 if (selection->regions.empty() || clicked_regionview == 0) {
2739 drag_info.copy = false;
2740 drag_info.item = item;
2741 drag_info.data = clicked_regionview;
2742 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2743 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2748 TimeAxisView* tvp = clicked_trackview;
2749 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
2751 if (tv && tv->is_audio_track()) {
2752 speed = tv->get_diskstream()->speed();
2755 drag_info.last_frame_position = (nframes_t) (clicked_regionview->region()->position() / speed);
2756 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2757 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2758 // we want a move threshold
2759 drag_info.want_move_threshold = true;
2760 drag_info.brushing = true;
2762 begin_reversible_command (_("Drag region brush"));
2766 Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2770 RegionView* rv = reinterpret_cast<RegionView*> (drag_info.data);
2771 nframes_t pending_region_position = 0;
2772 int32_t pointer_y_span = 0, canvas_pointer_y_span = 0, original_pointer_order;
2773 int32_t visible_y_high = 0, visible_y_low = 512; //high meaning higher numbered.. not the height on the screen
2774 bool clamp_y_axis = false;
2775 vector<int32_t> height_list(512) ;
2776 vector<int32_t>::iterator j;
2778 if (drag_info.copy && drag_info.move_threshold_passed && drag_info.want_move_threshold) {
2780 drag_info.want_move_threshold = false; // don't copy again
2782 /* this is committed in the grab finished callback. */
2784 begin_reversible_command (_("Drag region copy"));
2786 /* duplicate the region(s) */
2788 vector<RegionView*> new_regionviews;
2790 set<Playlist*> affected_playlists;
2791 pair<set<Playlist*>::iterator,bool> insert_result;
2793 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
2798 Playlist* to_playlist = rv->region()->playlist();
2799 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*>(&rv->get_time_axis_view());
2801 insert_result = affected_playlists.insert (to_playlist);
2802 if (insert_result.second) {
2803 session->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
2806 latest_regionview = 0;
2808 sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
2810 /* create a new region with the same name. */
2812 // FIXME: ew. need a (virtual) Region::duplicate() or something?
2814 boost::shared_ptr<Region> newregion;
2815 boost::shared_ptr<Region> ar;
2817 if ((ar = boost::dynamic_pointer_cast<AudioRegion>(rv->region())) != 0) {
2818 newregion = RegionFactory::create (ar);
2820 assert(newregion != 0);
2822 /* if the original region was locked, we don't care */
2824 newregion->set_locked (false);
2826 to_playlist->add_region (newregion, (nframes_t) (rv->region()->position() * atv->get_diskstream()->speed()));
2830 if (latest_regionview) {
2831 new_regionviews.push_back (latest_regionview);
2835 if (new_regionviews.empty()) {
2839 /* reset selection to new regionviews */
2841 selection->set (new_regionviews);
2843 /* reset drag_info data to reflect the fact that we are dragging the copies */
2845 drag_info.data = new_regionviews.front();
2846 swap_grab (new_regionviews.front()->get_canvas_group (), 0, event->motion.time);
2849 /* Which trackview is this ? */
2851 TimeAxisView* tvp = trackview_by_y_position (drag_info.current_pointer_y);
2852 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
2854 /* The region motion is only processed if the pointer is over
2858 if (!tv || !tv->is_audio_track()) {
2859 /* To make sure we hide the verbose canvas cursor when the mouse is
2860 not held over and audiotrack.
2862 hide_verbose_canvas_cursor ();
2866 original_pointer_order = drag_info.last_trackview->order;
2868 /************************************************************
2870 ************************************************************/
2872 if (drag_info.brushing) {
2873 clamp_y_axis = true;
2878 if ((pointer_y_span = (drag_info.last_trackview->order - tv->order)) != 0) {
2880 int32_t children = 0, numtracks = 0;
2881 // XXX hard coding track limit, oh my, so very very bad
2882 bitset <1024> tracks (0x00);
2883 /* get a bitmask representing the visible tracks */
2885 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2886 TimeAxisView *tracklist_timeview;
2887 tracklist_timeview = (*i);
2888 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tracklist_timeview);
2889 list<TimeAxisView*> children_list;
2891 /* zeroes are audio tracks. ones are other types. */
2893 if (!atv2->hidden()) {
2895 if (visible_y_high < atv2->order) {
2896 visible_y_high = atv2->order;
2898 if (visible_y_low > atv2->order) {
2899 visible_y_low = atv2->order;
2902 if (!atv2->is_audio_track()) {
2903 tracks = tracks |= (0x01 << atv2->order);
2906 height_list[atv2->order] = (*i)->height;
2908 if ((children_list = atv2->get_child_list()).size() > 0) {
2909 for (list<TimeAxisView*>::iterator j = children_list.begin(); j != children_list.end(); ++j) {
2910 tracks = tracks |= (0x01 << (atv2->order + children));
2911 height_list[atv2->order + children] = (*j)->height;
2919 /* find the actual span according to the canvas */
2921 canvas_pointer_y_span = pointer_y_span;
2922 if (drag_info.last_trackview->order >= tv->order) {
2924 for (y = tv->order; y < drag_info.last_trackview->order; y++) {
2925 if (height_list[y] == 0 ) {
2926 canvas_pointer_y_span--;
2931 for (y = drag_info.last_trackview->order;y <= tv->order; y++) {
2932 if ( height_list[y] == 0 ) {
2933 canvas_pointer_y_span++;
2938 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
2939 RegionView* rv2 = (*i);
2940 double ix1, ix2, iy1, iy2;
2943 rv2->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
2944 rv2->get_canvas_group()->i2w (ix1, iy1);
2945 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
2946 RouteTimeAxisView* atv2 = dynamic_cast<RouteTimeAxisView*>(tvp2);
2948 if (atv2->order != original_pointer_order) {
2949 /* this isn't the pointer track */
2951 if (canvas_pointer_y_span > 0) {
2953 /* moving up the canvas */
2954 if ((atv2->order - canvas_pointer_y_span) >= visible_y_low) {
2956 int32_t visible_tracks = 0;
2957 while (visible_tracks < canvas_pointer_y_span ) {
2960 while (height_list[atv2->order - (visible_tracks - n)] == 0) {
2961 /* we're passing through a hidden track */
2966 if (tracks[atv2->order - (canvas_pointer_y_span - n)] != 0x00) {
2967 clamp_y_axis = true;
2971 clamp_y_axis = true;
2974 } else if (canvas_pointer_y_span < 0) {
2976 /*moving down the canvas*/
2978 if ((atv2->order - (canvas_pointer_y_span - n)) <= visible_y_high) { // we will overflow
2981 int32_t visible_tracks = 0;
2983 while (visible_tracks > canvas_pointer_y_span ) {
2986 while (height_list[atv2->order - (visible_tracks - n)] == 0) {
2990 if ( tracks[atv2->order - ( canvas_pointer_y_span - n)] != 0x00) {
2991 clamp_y_axis = true;
2996 clamp_y_axis = true;
3002 /* this is the pointer's track */
3003 if ((atv2->order - pointer_y_span) > visible_y_high) { // we will overflow
3004 clamp_y_axis = true;
3005 } else if ((atv2->order - pointer_y_span) < visible_y_low) { // we will underflow
3006 clamp_y_axis = true;
3014 } else if (drag_info.last_trackview == tv) {
3015 clamp_y_axis = true;
3019 if (!clamp_y_axis) {
3020 drag_info.last_trackview = tv;
3023 /************************************************************
3025 ************************************************************/
3027 /* compute the amount of pointer motion in frames, and where
3028 the region would be if we moved it by that much.
3031 if (drag_info.move_threshold_passed) {
3033 if ((int32_t)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
3035 nframes_t sync_frame;
3036 nframes_t sync_offset;
3039 pending_region_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
3041 sync_offset = rv->region()->sync_offset (sync_dir);
3042 sync_frame = rv->region()->adjust_to_sync (pending_region_position);
3044 /* we snap if the snap modifier is not enabled.
3047 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3048 snap_to (sync_frame);
3051 if (sync_frame - sync_offset <= sync_frame) {
3052 pending_region_position = sync_frame - (sync_dir*sync_offset);
3054 pending_region_position = 0;
3058 pending_region_position = 0;
3061 if (pending_region_position > max_frames - rv->region()->length()) {
3062 pending_region_position = drag_info.last_frame_position;
3065 // printf ("3: pending_region_position= %lu %lu\n", pending_region_position, drag_info.last_frame_position );
3067 if (pending_region_position != drag_info.last_frame_position && !drag_info.x_constrained) {
3069 /* now compute the canvas unit distance we need to move the regiondrag_info.last_trackview->order
3070 to make it appear at the new location.
3073 if (pending_region_position > drag_info.last_frame_position) {
3074 x_delta = ((double) (pending_region_position - drag_info.last_frame_position) / frames_per_unit);
3076 x_delta = -((double) (drag_info.last_frame_position - pending_region_position) / frames_per_unit);
3079 drag_info.last_frame_position = pending_region_position;
3086 /* threshold not passed */
3091 /*************************************************************
3093 ************************************************************/
3095 if (x_delta == 0 && (pointer_y_span == 0)) {
3096 /* haven't reached next snap point, and we're not switching
3097 trackviews. nothing to do.
3103 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
3105 RegionView* rv2 = (*i);
3107 // If any regionview is at zero, we need to know so we can stop further leftward motion.
3109 double ix1, ix2, iy1, iy2;
3110 rv2->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3111 rv2->get_canvas_group()->i2w (ix1, iy1);
3120 /*************************************************************
3122 ************************************************************/
3124 pair<set<Playlist*>::iterator,bool> insert_result;
3125 const list<RegionView*>& layered_regions = selection->regions.by_layer();
3127 for (list<RegionView*>::const_iterator i = layered_regions.begin(); i != layered_regions.end(); ++i) {
3129 RegionView* rv = (*i);
3130 double ix1, ix2, iy1, iy2;
3131 int32_t temp_pointer_y_span = pointer_y_span;
3133 /* get item BBox, which will be relative to parent. so we have
3134 to query on a child, then convert to world coordinates using
3138 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3139 rv->get_canvas_group()->i2w (ix1, iy1);
3140 rv->region()->set_opaque(false);
3141 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
3142 AudioTimeAxisView* canvas_atv = dynamic_cast<AudioTimeAxisView*>(tvp2);
3143 AudioTimeAxisView* temp_atv;
3145 if ((pointer_y_span != 0) && !clamp_y_axis) {
3148 for (j = height_list.begin(); j!= height_list.end(); j++) {
3149 if (x == canvas_atv->order) {
3150 /* we found the track the region is on */
3151 if (x != original_pointer_order) {
3152 /*this isn't from the same track we're dragging from */
3153 temp_pointer_y_span = canvas_pointer_y_span;
3155 while (temp_pointer_y_span > 0) {
3156 /* we're moving up canvas-wise,
3157 so we need to find the next track height
3159 if (j != height_list.begin()) {
3162 if (x != original_pointer_order) {
3163 /* we're not from the dragged track, so ignore hidden tracks. */
3165 temp_pointer_y_span++;
3169 temp_pointer_y_span--;
3171 while (temp_pointer_y_span < 0) {
3173 if (x != original_pointer_order) {
3175 temp_pointer_y_span--;
3179 if (j != height_list.end()) {
3182 temp_pointer_y_span++;
3184 /* find out where we'll be when we move and set height accordingly */
3186 tvp2 = trackview_by_y_position (iy1 + y_delta);
3187 temp_atv = dynamic_cast<AudioTimeAxisView*>(tvp2);
3188 rv->set_height (temp_atv->height);
3190 /* if you un-comment the following, the region colours will follow the track colours whilst dragging,
3191 personally, i think this can confuse things, but never mind.
3194 //const GdkColor& col (temp_atv->view->get_region_color());
3195 //rv->set_color (const_cast<GdkColor&>(col));
3202 /* prevent the regionview from being moved to before
3203 the zero position on the canvas.
3208 if (-x_delta > ix1) {
3211 } else if ((x_delta > 0) &&(rv->region()->last_frame() > max_frames - x_delta)) {
3212 x_delta = max_frames - rv->region()->last_frame();
3215 if (drag_info.first_move) {
3217 /* hide any dependent views */
3219 // rv->get_time_axis_view().hide_dependent_views (*rv);
3221 /* this is subtle. raising the regionview itself won't help,
3222 because raise_to_top() just puts the item on the top of
3223 its parent's stack. so, we need to put the trackview canvas_display group
3224 on the top, since its parent is the whole canvas.
3227 rv->get_canvas_group()->raise_to_top();
3228 rv->get_time_axis_view().canvas_display->raise_to_top();
3229 cursor_group->raise_to_top();
3231 /* freeze the playlists from notifying till
3235 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&rv->get_time_axis_view());
3236 if (atv && atv->is_audio_track()) {
3237 AudioPlaylist* pl = dynamic_cast<AudioPlaylist*>(atv->get_diskstream()->playlist());
3239 /* only freeze and capture state once */
3241 insert_result = motion_frozen_playlists.insert (pl);
3242 if (insert_result.second) {
3244 session->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
3250 if (drag_info.brushing) {
3251 mouse_brush_insert_region (rv, pending_region_position);
3253 rv->move (x_delta, y_delta);
3257 if (drag_info.first_move) {
3258 cursor_group->raise_to_top();
3261 drag_info.first_move = false;
3263 if (x_delta != 0 && !drag_info.brushing) {
3264 show_verbose_time_cursor (drag_info.last_frame_position, 10);
3270 Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
3273 RegionView* rv = reinterpret_cast<RegionView *> (drag_info.data);
3274 pair<set<Playlist*>::iterator,bool> insert_result;
3275 bool nocommit = true;
3277 RouteTimeAxisView* atv;
3278 bool regionview_y_movement;
3279 bool regionview_x_movement;
3281 /* first_move is set to false if the regionview has been moved in the
3285 if (drag_info.first_move) {
3292 /* The regionview has been moved at some stage during the grab so we need
3293 to account for any mouse movement between this event and the last one.
3296 region_drag_motion_callback (item, event);
3298 if (drag_info.brushing) {
3299 /* all changes were made during motion event handlers */
3303 /* adjust for track speed */
3306 atv = dynamic_cast<AudioTimeAxisView*> (drag_info.last_trackview);
3307 if (atv && atv->get_diskstream()) {
3308 speed = atv->get_diskstream()->speed();
3311 regionview_x_movement = (drag_info.last_frame_position != (nframes_t) (rv->region()->position()/speed));
3312 regionview_y_movement = (drag_info.last_trackview != &rv->get_time_axis_view());
3314 //printf ("last_frame: %s position is %lu %g\n", rv->get_time_axis_view().name().c_str(), drag_info.last_frame_position, speed);
3315 //printf ("last_rackview: %s \n", drag_info.last_trackview->name().c_str());
3317 if (regionview_y_movement) {
3319 /* motion between tracks */
3321 list<RegionView*> new_selection;
3323 /* moved to a different audio track. */
3325 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ) {
3327 RegionView* rv2 = (*i);
3329 /* the region that used to be in the old playlist is not
3330 moved to the new one - we make a copy of it. as a result,
3331 any existing editor for the region should no longer be
3335 if (!drag_info.copy) {
3336 rv2->hide_region_editor();
3338 new_selection.push_back (rv2);
3342 /* first, freeze the target tracks */
3344 for (list<RegionView*>::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) {
3346 Playlist* from_playlist;
3347 Playlist* to_playlist;
3349 double ix1, ix2, iy1, iy2;
3351 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3352 (*i)->get_canvas_group()->i2w (ix1, iy1);
3353 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
3354 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2);
3356 (*i)->region()->set_opaque (true);
3358 from_playlist = (*i)->region()->playlist();
3359 to_playlist = atv2->playlist();
3361 /* the from_playlist was frozen in the "first_move" case
3362 of the motion handler. the insert can fail,
3363 but that doesn't matter. it just means
3364 we already have the playlist in the list.
3367 motion_frozen_playlists.insert (from_playlist);
3369 /* only freeze the to_playlist once */
3371 insert_result = motion_frozen_playlists.insert(to_playlist);
3372 if (insert_result.second) {
3373 to_playlist->freeze();
3374 session->add_command(new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
3379 /* now do it again with the actual operations */
3381 for (list<RegionView*>::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) {
3383 Playlist* from_playlist;
3384 Playlist* to_playlist;
3386 double ix1, ix2, iy1, iy2;
3388 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3389 (*i)->get_canvas_group()->i2w (ix1, iy1);
3390 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
3391 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2);
3393 from_playlist = (*i)->region()->playlist();
3394 to_playlist = atv2->playlist();
3396 latest_regionview = 0;
3398 where = (nframes_t) (unit_to_frame (ix1) * speed);
3399 boost::shared_ptr<Region> new_region (RegionFactory::create ((*i)->region()));
3401 from_playlist->remove_region (((*i)->region()));
3403 sigc::connection c = atv2->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3404 to_playlist->add_region (new_region, where);
3407 if (latest_regionview) {
3408 selection->add (latest_regionview);
3414 /* motion within a single track */
3416 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
3420 if (rv->region()->locked()) {
3424 if (regionview_x_movement) {
3425 double ownspeed = 1.0;
3426 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&(rv->get_time_axis_view()));
3428 if (atv && atv->get_diskstream()) {
3429 ownspeed = atv->get_diskstream()->speed();
3432 /* base the new region position on the current position of the regionview.*/
3434 double ix1, ix2, iy1, iy2;
3436 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3437 rv->get_canvas_group()->i2w (ix1, iy1);
3438 where = (nframes_t) (unit_to_frame (ix1) * ownspeed);
3442 where = rv->region()->position();
3445 rv->get_time_axis_view().reveal_dependent_views (*rv);
3447 /* no need to add an undo here, we did that when we added this playlist to motion_frozen playlists */
3449 rv->region()->set_position (where, (void *) this);
3450 rv->region()->set_opaque (true);
3455 for (set<Playlist*>::iterator p = motion_frozen_playlists.begin(); p != motion_frozen_playlists.end(); ++p) {
3457 session->add_command (new MementoCommand<Playlist>(*(*p), 0, & (*p)->get_state()));
3460 motion_frozen_playlists.clear ();
3463 commit_reversible_command ();
3468 Editor::region_view_item_click (AudioRegionView& rv, GdkEventButton* event)
3470 /* Either add to or set the set the region selection, unless
3471 this is an alignment click (control used)
3474 if (Keyboard::modifier_state_contains (event->state, Keyboard::Control)) {
3475 TimeAxisView* tv = &rv.get_time_axis_view();
3476 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(tv);
3478 if (atv && atv->is_audio_track()) {
3479 speed = atv->get_diskstream()->speed();
3482 if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Alt))) {
3484 align_region (rv.region(), SyncPoint, (nframes_t) (edit_cursor->current_frame * speed));
3486 } else if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Shift))) {
3488 align_region (rv.region(), End, (nframes_t) (edit_cursor->current_frame * speed));
3492 align_region (rv.region(), Start, (nframes_t) (edit_cursor->current_frame * speed));
3498 Editor::show_verbose_time_cursor (nframes_t frame, double offset, double xpos, double ypos)
3509 switch (ARDOUR_UI::instance()->secondary_clock.mode ()) {
3510 case AudioClock::BBT:
3511 session->bbt_time (frame, bbt);
3512 snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32, bbt.bars, bbt.beats, bbt.ticks);
3515 case AudioClock::SMPTE:
3516 session->smpte_time (frame, smpte);
3517 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
3520 case AudioClock::MinSec:
3521 /* XXX fix this to compute min/sec properly */
3522 session->smpte_time (frame, smpte);
3523 secs = smpte.seconds + ((float) smpte.frames / Config->get_smpte_frames_per_second());
3524 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%.4f", smpte.hours, smpte.minutes, secs);
3528 snprintf (buf, sizeof(buf), "%u", frame);
3532 if (xpos >= 0 && ypos >=0) {
3533 set_verbose_canvas_cursor (buf, xpos + offset, ypos + offset);
3536 set_verbose_canvas_cursor (buf, drag_info.current_pointer_x + offset, drag_info.current_pointer_y + offset);
3538 show_verbose_canvas_cursor ();
3542 Editor::show_verbose_duration_cursor (nframes_t start, nframes_t end, double offset, double xpos, double ypos)
3549 Meter meter_at_start(session->tempo_map().meter_at(start));
3555 switch (ARDOUR_UI::instance()->secondary_clock.mode ()) {
3556 case AudioClock::BBT:
3557 session->bbt_time (start, sbbt);
3558 session->bbt_time (end, ebbt);
3561 /* XXX this computation won't work well if the
3562 user makes a selection that spans any meter changes.
3565 ebbt.bars -= sbbt.bars;
3566 if (ebbt.beats >= sbbt.beats) {
3567 ebbt.beats -= sbbt.beats;
3570 ebbt.beats = int(meter_at_start.beats_per_bar()) + ebbt.beats - sbbt.beats;
3572 if (ebbt.ticks >= sbbt.ticks) {
3573 ebbt.ticks -= sbbt.ticks;
3576 ebbt.ticks = int(Meter::ticks_per_beat) + ebbt.ticks - sbbt.ticks;
3579 snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32, ebbt.bars, ebbt.beats, ebbt.ticks);
3582 case AudioClock::SMPTE:
3583 session->smpte_duration (end - start, smpte);
3584 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
3587 case AudioClock::MinSec:
3588 /* XXX fix this to compute min/sec properly */
3589 session->smpte_duration (end - start, smpte);
3590 secs = smpte.seconds + ((float) smpte.frames / Config->get_smpte_frames_per_second());
3591 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%.4f", smpte.hours, smpte.minutes, secs);
3595 snprintf (buf, sizeof(buf), "%u", end - start);
3599 if (xpos >= 0 && ypos >=0) {
3600 set_verbose_canvas_cursor (buf, xpos + offset, ypos + offset);
3603 set_verbose_canvas_cursor (buf, drag_info.current_pointer_x + offset, drag_info.current_pointer_y + offset);
3605 show_verbose_canvas_cursor ();
3609 Editor::collect_new_region_view (RegionView* rv)
3611 latest_regionview = rv;
3615 Editor::start_selection_grab (ArdourCanvas::Item* item, GdkEvent* event)
3617 if (clicked_regionview == 0) {
3621 /* lets try to create new Region for the selection */
3623 vector<boost::shared_ptr<AudioRegion> > new_regions;
3624 create_region_from_selection (new_regions);
3626 if (new_regions.empty()) {
3630 /* XXX fix me one day to use all new regions */
3632 boost::shared_ptr<Region> region (new_regions.front());
3634 /* add it to the current stream/playlist.
3636 tricky: the streamview for the track will add a new regionview. we will
3637 catch the signal it sends when it creates the regionview to
3638 set the regionview we want to then drag.
3641 latest_regionview = 0;
3642 sigc::connection c = clicked_audio_trackview->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3644 /* A selection grab currently creates two undo/redo operations, one for
3645 creating the new region and another for moving it.
3648 begin_reversible_command (_("selection grab"));
3650 Playlist* playlist = clicked_trackview->playlist();
3652 XMLNode *before = &(playlist->get_state());
3653 clicked_trackview->playlist()->add_region (region, selection->time[clicked_selection].start);
3654 XMLNode *after = &(playlist->get_state());
3655 session->add_command(new MementoCommand<Playlist>(*playlist, before, after));
3657 commit_reversible_command ();
3661 if (latest_regionview == 0) {
3662 /* something went wrong */
3666 /* we need to deselect all other regionviews, and select this one
3667 i'm ignoring undo stuff, because the region creation will take care of it */
3668 selection->set (latest_regionview);
3670 drag_info.item = latest_regionview->get_canvas_group();
3671 drag_info.data = latest_regionview;
3672 drag_info.motion_callback = &Editor::region_drag_motion_callback;
3673 drag_info.finished_callback = &Editor::region_drag_finished_callback;
3677 drag_info.last_trackview = clicked_trackview;
3678 drag_info.last_frame_position = latest_regionview->region()->position();
3679 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
3681 show_verbose_time_cursor (drag_info.last_frame_position, 10);
3685 Editor::cancel_selection ()
3687 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3688 (*i)->hide_selection ();
3690 begin_reversible_command (_("cancel selection"));
3691 selection->clear ();
3692 clicked_selection = 0;
3693 commit_reversible_command ();
3697 Editor::start_selection_op (ArdourCanvas::Item* item, GdkEvent* event, SelectionOp op)
3699 nframes_t start = 0;
3706 drag_info.item = item;
3707 drag_info.motion_callback = &Editor::drag_selection;
3708 drag_info.finished_callback = &Editor::end_selection_op;
3713 case CreateSelection:
3714 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
3715 drag_info.copy = true;
3717 drag_info.copy = false;
3719 start_grab (event, selector_cursor);
3722 case SelectionStartTrim:
3723 if (clicked_trackview) {
3724 clicked_trackview->order_selection_trims (item, true);
3726 start_grab (event, trimmer_cursor);
3727 start = selection->time[clicked_selection].start;
3728 drag_info.pointer_frame_offset = drag_info.grab_frame - start;
3731 case SelectionEndTrim:
3732 if (clicked_trackview) {
3733 clicked_trackview->order_selection_trims (item, false);
3735 start_grab (event, trimmer_cursor);
3736 end = selection->time[clicked_selection].end;
3737 drag_info.pointer_frame_offset = drag_info.grab_frame - end;
3741 start = selection->time[clicked_selection].start;
3743 drag_info.pointer_frame_offset = drag_info.grab_frame - start;
3747 if (selection_op == SelectionMove) {
3748 show_verbose_time_cursor(start, 10);
3750 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
3755 Editor::drag_selection (ArdourCanvas::Item* item, GdkEvent* event)
3757 nframes_t start = 0;
3760 nframes_t pending_position;
3762 if ((int32_t) drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
3763 pending_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
3766 pending_position = 0;
3769 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3770 snap_to (pending_position);
3773 /* only alter selection if the current frame is
3774 different from the last frame position (adjusted)
3777 if (pending_position == drag_info.last_pointer_frame) return;
3779 switch (selection_op) {
3780 case CreateSelection:
3782 if (drag_info.first_move) {
3783 snap_to (drag_info.grab_frame);
3786 if (pending_position < drag_info.grab_frame) {
3787 start = pending_position;
3788 end = drag_info.grab_frame;
3790 end = pending_position;
3791 start = drag_info.grab_frame;
3794 /* first drag: Either add to the selection
3795 or create a new selection->
3798 if (drag_info.first_move) {
3800 begin_reversible_command (_("range selection"));
3802 if (drag_info.copy) {
3803 /* adding to the selection */
3804 clicked_selection = selection->add (start, end);
3805 drag_info.copy = false;
3807 /* new selection-> */
3808 clicked_selection = selection->set (clicked_trackview, start, end);
3813 case SelectionStartTrim:
3815 if (drag_info.first_move) {
3816 begin_reversible_command (_("trim selection start"));
3819 start = selection->time[clicked_selection].start;
3820 end = selection->time[clicked_selection].end;
3822 if (pending_position > end) {
3825 start = pending_position;
3829 case SelectionEndTrim:
3831 if (drag_info.first_move) {
3832 begin_reversible_command (_("trim selection end"));
3835 start = selection->time[clicked_selection].start;
3836 end = selection->time[clicked_selection].end;
3838 if (pending_position < start) {
3841 end = pending_position;
3848 if (drag_info.first_move) {
3849 begin_reversible_command (_("move selection"));
3852 start = selection->time[clicked_selection].start;
3853 end = selection->time[clicked_selection].end;
3855 length = end - start;
3857 start = pending_position;
3860 end = start + length;
3865 if (event->button.x >= horizontal_adjustment.get_value() + canvas_width) {
3866 start_canvas_autoscroll (1);
3870 selection->replace (clicked_selection, start, end);
3873 drag_info.last_pointer_frame = pending_position;
3874 drag_info.first_move = false;
3876 if (selection_op == SelectionMove) {
3877 show_verbose_time_cursor(start, 10);
3879 show_verbose_time_cursor(pending_position, 10);
3884 Editor::end_selection_op (ArdourCanvas::Item* item, GdkEvent* event)
3886 if (!drag_info.first_move) {
3887 drag_selection (item, event);
3888 /* XXX this is not object-oriented programming at all. ick */
3889 if (selection->time.consolidate()) {
3890 selection->TimeChanged ();
3892 commit_reversible_command ();
3894 /* just a click, no pointer movement.*/
3896 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3898 selection->clear_time();
3903 /* XXX what happens if its a music selection? */
3904 session->set_audio_range (selection->time);
3905 stop_canvas_autoscroll ();
3909 Editor::start_trim (ArdourCanvas::Item* item, GdkEvent* event)
3912 TimeAxisView* tvp = clicked_trackview;
3913 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3915 if (tv && tv->is_audio_track()) {
3916 speed = tv->get_diskstream()->speed();
3919 nframes_t region_start = (nframes_t) (clicked_regionview->region()->position() / speed);
3920 nframes_t region_end = (nframes_t) (clicked_regionview->region()->last_frame() / speed);
3921 nframes_t region_length = (nframes_t) (clicked_regionview->region()->length() / speed);
3923 motion_frozen_playlists.clear();
3925 //drag_info.item = clicked_regionview->get_name_highlight();
3926 drag_info.item = item;
3927 drag_info.motion_callback = &Editor::trim_motion_callback;
3928 drag_info.finished_callback = &Editor::trim_finished_callback;
3930 start_grab (event, trimmer_cursor);
3932 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
3933 trim_op = ContentsTrim;
3935 /* These will get overridden for a point trim.*/
3936 if (drag_info.current_pointer_frame < (region_start + region_length/2)) {
3937 /* closer to start */
3938 trim_op = StartTrim;
3939 } else if (drag_info.current_pointer_frame > (region_end - region_length/2)) {
3947 show_verbose_time_cursor(region_start, 10);
3950 show_verbose_time_cursor(region_end, 10);
3953 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
3959 Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
3961 RegionView* rv = clicked_regionview;
3962 nframes_t frame_delta = 0;
3963 bool left_direction;
3964 bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier());
3966 /* snap modifier works differently here..
3967 its' current state has to be passed to the
3968 various trim functions in order to work properly
3972 TimeAxisView* tvp = clicked_trackview;
3973 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
3974 pair<set<Playlist*>::iterator,bool> insert_result;
3976 if (tv && tv->is_audio_track()) {
3977 speed = tv->get_diskstream()->speed();
3980 if (drag_info.last_pointer_frame > drag_info.current_pointer_frame) {
3981 left_direction = true;
3983 left_direction = false;
3987 snap_to (drag_info.current_pointer_frame);
3990 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) {
3994 if (drag_info.first_move) {
4000 trim_type = "Region start trim";
4003 trim_type = "Region end trim";
4006 trim_type = "Region content trim";
4010 begin_reversible_command (trim_type);
4012 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
4013 (*i)->region()->set_opaque(false);
4014 (*i)->region()->freeze ();
4016 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4018 arv->temporarily_hide_envelope ();
4020 Playlist * pl = (*i)->region()->playlist();
4021 insert_result = motion_frozen_playlists.insert (pl);
4022 if (insert_result.second) {
4023 session->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
4028 if (left_direction) {
4029 frame_delta = (drag_info.last_pointer_frame - drag_info.current_pointer_frame);
4031 frame_delta = (drag_info.current_pointer_frame - drag_info.last_pointer_frame);
4036 if ((left_direction == false) && (drag_info.current_pointer_frame <= rv->region()->first_frame()/speed)) {
4039 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
4040 single_start_trim (**i, frame_delta, left_direction, obey_snap);
4046 if ((left_direction == true) && (drag_info.current_pointer_frame > (nframes_t) (rv->region()->last_frame()/speed))) {
4049 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
4050 single_end_trim (**i, frame_delta, left_direction, obey_snap);
4057 bool swap_direction = false;
4059 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
4060 swap_direction = true;
4063 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin();
4064 i != selection->regions.by_layer().end(); ++i)
4066 single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
4074 show_verbose_time_cursor((nframes_t) (rv->region()->position()/speed), 10);
4077 show_verbose_time_cursor((nframes_t) (rv->region()->last_frame()/speed), 10);
4080 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
4084 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4085 drag_info.first_move = false;
4089 Editor::single_contents_trim (RegionView& rv, nframes_t frame_delta, bool left_direction, bool swap_direction, bool obey_snap)
4091 boost::shared_ptr<Region> region (rv.region());
4093 if (region->locked()) {
4097 nframes_t new_bound;
4100 TimeAxisView* tvp = clicked_trackview;
4101 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
4103 if (tv && tv->is_audio_track()) {
4104 speed = tv->get_diskstream()->speed();
4107 if (left_direction) {
4108 if (swap_direction) {
4109 new_bound = (nframes_t) (region->position()/speed) + frame_delta;
4111 new_bound = (nframes_t) (region->position()/speed) - frame_delta;
4114 if (swap_direction) {
4115 new_bound = (nframes_t) (region->position()/speed) - frame_delta;
4117 new_bound = (nframes_t) (region->position()/speed) + frame_delta;
4122 snap_to (new_bound);
4124 region->trim_start ((nframes_t) (new_bound * speed), this);
4125 rv.region_changed (StartChanged);
4129 Editor::single_start_trim (RegionView& rv, nframes_t frame_delta, bool left_direction, bool obey_snap)
4131 boost::shared_ptr<Region> region (rv.region());
4133 if (region->locked()) {
4137 nframes_t new_bound;
4140 TimeAxisView* tvp = clicked_trackview;
4141 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
4143 if (tv && tv->is_audio_track()) {
4144 speed = tv->get_diskstream()->speed();
4147 if (left_direction) {
4148 new_bound = (nframes_t) (region->position()/speed) - frame_delta;
4150 new_bound = (nframes_t) (region->position()/speed) + frame_delta;
4154 snap_to (new_bound, (left_direction ? 0 : 1));
4157 region->trim_front ((nframes_t) (new_bound * speed), this);
4159 rv.region_changed (Change (LengthChanged|PositionChanged|StartChanged));
4163 Editor::single_end_trim (RegionView& rv, nframes_t frame_delta, bool left_direction, bool obey_snap)
4165 boost::shared_ptr<Region> region (rv.region());
4167 if (region->locked()) {
4171 nframes_t new_bound;
4174 TimeAxisView* tvp = clicked_trackview;
4175 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
4177 if (tv && tv->is_audio_track()) {
4178 speed = tv->get_diskstream()->speed();
4181 if (left_direction) {
4182 new_bound = (nframes_t) ((region->last_frame() + 1)/speed) - frame_delta;
4184 new_bound = (nframes_t) ((region->last_frame() + 1)/speed) + frame_delta;
4188 snap_to (new_bound);
4190 region->trim_end ((nframes_t) (new_bound * speed), this);
4191 rv.region_changed (LengthChanged);
4195 Editor::trim_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
4197 if (!drag_info.first_move) {
4198 trim_motion_callback (item, event);
4200 if (!clicked_regionview->get_selected()) {
4201 thaw_region_after_trim (*clicked_regionview);
4204 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin();
4205 i != selection->regions.by_layer().end(); ++i)
4207 thaw_region_after_trim (**i);
4208 (*i)->region()->set_opaque(true);
4212 for (set<Playlist*>::iterator p = motion_frozen_playlists.begin(); p != motion_frozen_playlists.end(); ++p) {
4214 session->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));
4217 motion_frozen_playlists.clear ();
4219 commit_reversible_command();
4221 /* no mouse movement */
4227 Editor::point_trim (GdkEvent* event)
4229 RegionView* rv = clicked_regionview;
4230 nframes_t new_bound = drag_info.current_pointer_frame;
4232 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4233 snap_to (new_bound);
4236 /* Choose action dependant on which button was pressed */
4237 switch (event->button.button) {
4239 trim_op = StartTrim;
4240 begin_reversible_command (_("Start point trim"));
4242 if (rv->get_selected()) {
4244 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin();
4245 i != selection->regions.by_layer().end(); ++i)
4247 if (!(*i)->region()->locked()) {
4248 Playlist *pl = (*i)->region()->playlist();
4249 XMLNode &before = pl->get_state();
4250 (*i)->region()->trim_front (new_bound, this);
4251 XMLNode &after = pl->get_state();
4252 session->add_command(new MementoCommand<Playlist>(*pl, &before, &after));
4258 if (!rv->region()->locked()) {
4259 Playlist *pl = rv->region()->playlist();
4260 XMLNode &before = pl->get_state();
4261 rv->region()->trim_front (new_bound, this);
4262 XMLNode &after = pl->get_state();
4263 session->add_command(new MementoCommand<Playlist>(*pl, &before, &after));
4267 commit_reversible_command();
4272 begin_reversible_command (_("End point trim"));
4274 if (rv->get_selected()) {
4276 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i)
4278 if (!(*i)->region()->locked()) {
4279 Playlist *pl = (*i)->region()->playlist();
4280 XMLNode &before = pl->get_state();
4281 (*i)->region()->trim_end (new_bound, this);
4282 XMLNode &after = pl->get_state();
4283 session->add_command(new MementoCommand<Playlist>(*pl, &before, &after));
4289 if (!rv->region()->locked()) {
4290 Playlist *pl = rv->region()->playlist();
4291 XMLNode &before = pl->get_state();
4292 rv->region()->trim_end (new_bound, this);
4293 XMLNode &after = pl->get_state();
4294 session->add_command (new MementoCommand<Playlist>(*pl, &before, &after));
4298 commit_reversible_command();
4307 Editor::thaw_region_after_trim (RegionView& rv)
4309 boost::shared_ptr<Region> region (rv.region());
4311 if (region->locked()) {
4315 region->thaw (_("trimmed region"));
4316 XMLNode &after = region->playlist()->get_state();
4317 session->add_command (new MementoCommand<Playlist>(*(region->playlist()), 0, &after));
4319 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(&rv);
4321 arv->unhide_envelope ();
4325 Editor::hide_marker (ArdourCanvas::Item* item, GdkEvent* event)
4330 if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
4331 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
4335 Location* location = find_location_from_marker (marker, is_start);
4336 location->set_hidden (true, this);
4341 Editor::start_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event, RangeMarkerOp op)
4347 drag_info.item = item;
4348 drag_info.motion_callback = &Editor::drag_range_markerbar_op;
4349 drag_info.finished_callback = &Editor::end_range_markerbar_op;
4351 range_marker_op = op;
4353 if (!temp_location) {
4354 temp_location = new Location;
4358 case CreateRangeMarker:
4359 case CreateTransportMarker:
4361 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
4362 drag_info.copy = true;
4364 drag_info.copy = false;
4366 start_grab (event, selector_cursor);
4370 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
4375 Editor::drag_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event)
4377 nframes_t start = 0;
4379 ArdourCanvas::SimpleRect *crect = (range_marker_op == CreateRangeMarker) ? range_bar_drag_rect: transport_bar_drag_rect;
4381 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4382 snap_to (drag_info.current_pointer_frame);
4385 /* only alter selection if the current frame is
4386 different from the last frame position.
4389 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) return;
4391 switch (range_marker_op) {
4392 case CreateRangeMarker:
4393 case CreateTransportMarker:
4394 if (drag_info.first_move) {
4395 snap_to (drag_info.grab_frame);
4398 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4399 start = drag_info.current_pointer_frame;
4400 end = drag_info.grab_frame;
4402 end = drag_info.current_pointer_frame;
4403 start = drag_info.grab_frame;
4406 /* first drag: Either add to the selection
4407 or create a new selection.
4410 if (drag_info.first_move) {
4412 temp_location->set (start, end);
4416 update_marker_drag_item (temp_location);
4417 range_marker_drag_rect->show();
4418 range_marker_drag_rect->raise_to_top();
4424 if (event->button.x >= horizontal_adjustment.get_value() + canvas_width) {
4425 start_canvas_autoscroll (1);
4429 temp_location->set (start, end);
4431 double x1 = frame_to_pixel (start);
4432 double x2 = frame_to_pixel (end);
4433 crect->property_x1() = x1;
4434 crect->property_x2() = x2;
4436 update_marker_drag_item (temp_location);
4439 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4440 drag_info.first_move = false;
4442 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
4447 Editor::end_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event)
4449 Location * newloc = 0;
4451 if (!drag_info.first_move) {
4452 drag_range_markerbar_op (item, event);
4454 switch (range_marker_op) {
4455 case CreateRangeMarker:
4457 begin_reversible_command (_("new range marker"));
4458 XMLNode &before = session->locations()->get_state();
4459 newloc = new Location(temp_location->start(), temp_location->end(), "unnamed", Location::IsRangeMarker);
4460 session->locations()->add (newloc, true);
4461 XMLNode &after = session->locations()->get_state();
4462 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
4463 commit_reversible_command ();
4465 range_bar_drag_rect->hide();
4466 range_marker_drag_rect->hide();
4470 case CreateTransportMarker:
4471 // popup menu to pick loop or punch
4472 new_transport_marker_context_menu (&event->button, item);
4477 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
4479 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
4484 start = session->locations()->first_mark_before (drag_info.grab_frame);
4485 end = session->locations()->first_mark_after (drag_info.grab_frame);
4487 if (end == max_frames) {
4488 end = session->current_end_frame ();
4492 start = session->current_start_frame ();
4495 switch (mouse_mode) {
4497 /* find the two markers on either side and then make the selection from it */
4498 cerr << "select between " << start << " .. " << end << endl;
4499 select_all_within (start, end, 0.0f, FLT_MAX, Selection::Set);
4503 /* find the two markers on either side of the click and make the range out of it */
4504 selection->set (0, start, end);
4513 stop_canvas_autoscroll ();
4519 Editor::start_mouse_zoom (ArdourCanvas::Item* item, GdkEvent* event)
4521 drag_info.item = item;
4522 drag_info.motion_callback = &Editor::drag_mouse_zoom;
4523 drag_info.finished_callback = &Editor::end_mouse_zoom;
4525 start_grab (event, zoom_cursor);
4527 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4531 Editor::drag_mouse_zoom (ArdourCanvas::Item* item, GdkEvent* event)
4536 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4537 snap_to (drag_info.current_pointer_frame);
4539 if (drag_info.first_move) {
4540 snap_to (drag_info.grab_frame);
4544 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) return;
4546 /* base start and end on initial click position */
4547 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4548 start = drag_info.current_pointer_frame;
4549 end = drag_info.grab_frame;
4551 end = drag_info.current_pointer_frame;
4552 start = drag_info.grab_frame;
4557 if (drag_info.first_move) {
4559 zoom_rect->raise_to_top();
4562 reposition_zoom_rect(start, end);
4564 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4565 drag_info.first_move = false;
4567 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4572 Editor::end_mouse_zoom (ArdourCanvas::Item* item, GdkEvent* event)
4574 if (!drag_info.first_move) {
4575 drag_mouse_zoom (item, event);
4577 if (drag_info.grab_frame < drag_info.last_pointer_frame) {
4578 temporal_zoom_by_frame (drag_info.grab_frame, drag_info.last_pointer_frame, "mouse zoom");
4580 temporal_zoom_by_frame (drag_info.last_pointer_frame, drag_info.grab_frame, "mouse zoom");
4583 temporal_zoom_to_frame (false, drag_info.grab_frame);
4585 temporal_zoom_step (false);
4586 center_screen (drag_info.grab_frame);
4594 Editor::reposition_zoom_rect (nframes_t start, nframes_t end)
4596 double x1 = frame_to_pixel (start);
4597 double x2 = frame_to_pixel (end);
4598 double y2 = canvas_height - 2;
4600 zoom_rect->property_x1() = x1;
4601 zoom_rect->property_y1() = 1.0;
4602 zoom_rect->property_x2() = x2;
4603 zoom_rect->property_y2() = y2;
4607 Editor::start_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event)
4609 drag_info.item = item;
4610 drag_info.motion_callback = &Editor::drag_rubberband_select;
4611 drag_info.finished_callback = &Editor::end_rubberband_select;
4613 start_grab (event, cross_hair_cursor);
4615 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4619 Editor::drag_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event)
4626 /* use a bigger drag threshold than the default */
4628 if (abs ((int) (drag_info.current_pointer_frame - drag_info.grab_frame)) < 8) {
4632 // if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4633 // snap_to (drag_info.current_pointer_frame);
4635 // if (drag_info.first_move) {
4636 // snap_to (drag_info.grab_frame);
4641 /* base start and end on initial click position */
4642 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4643 start = drag_info.current_pointer_frame;
4644 end = drag_info.grab_frame;
4646 end = drag_info.current_pointer_frame;
4647 start = drag_info.grab_frame;
4650 if (drag_info.current_pointer_y < drag_info.grab_y) {
4651 y1 = drag_info.current_pointer_y;
4652 y2 = drag_info.grab_y;
4655 y2 = drag_info.current_pointer_y;
4656 y1 = drag_info.grab_y;
4660 if (start != end || y1 != y2) {
4662 double x1 = frame_to_pixel (start);
4663 double x2 = frame_to_pixel (end);
4665 rubberband_rect->property_x1() = x1;
4666 rubberband_rect->property_y1() = y1;
4667 rubberband_rect->property_x2() = x2;
4668 rubberband_rect->property_y2() = y2;
4670 rubberband_rect->show();
4671 rubberband_rect->raise_to_top();
4673 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4674 drag_info.first_move = false;
4676 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4681 Editor::end_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event)
4683 if (!drag_info.first_move) {
4685 drag_rubberband_select (item, event);
4688 if (drag_info.current_pointer_y < drag_info.grab_y) {
4689 y1 = drag_info.current_pointer_y;
4690 y2 = drag_info.grab_y;
4693 y2 = drag_info.current_pointer_y;
4694 y1 = drag_info.grab_y;
4698 Selection::Operation op = Keyboard::selection_type (event->button.state);
4701 begin_reversible_command (_("select regions"));
4703 if (drag_info.grab_frame < drag_info.last_pointer_frame) {
4704 commit = select_all_within (drag_info.grab_frame, drag_info.last_pointer_frame, y1, y2, op);
4706 commit = select_all_within (drag_info.last_pointer_frame, drag_info.grab_frame, y1, y2, op);
4710 commit_reversible_command ();
4714 selection->clear_regions();
4715 selection->clear_points ();
4716 selection->clear_lines ();
4719 rubberband_rect->hide();
4724 Editor::mouse_rename_region (ArdourCanvas::Item* item, GdkEvent* event)
4726 using namespace Gtkmm2ext;
4728 ArdourPrompter prompter (false);
4730 prompter.set_prompt (_("Name for region:"));
4731 prompter.set_initial_text (clicked_regionview->region()->name());
4732 prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
4733 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
4734 prompter.show_all ();
4735 switch (prompter.run ()) {
4736 case Gtk::RESPONSE_ACCEPT:
4738 prompter.get_result(str);
4740 clicked_regionview->region()->set_name (str);
4748 Editor::start_time_fx (ArdourCanvas::Item* item, GdkEvent* event)
4750 drag_info.item = item;
4751 drag_info.motion_callback = &Editor::time_fx_motion;
4752 drag_info.finished_callback = &Editor::end_time_fx;
4756 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4760 Editor::time_fx_motion (ArdourCanvas::Item *item, GdkEvent* event)
4762 RegionView* rv = clicked_regionview;
4764 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4765 snap_to (drag_info.current_pointer_frame);
4768 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) {
4772 if (drag_info.current_pointer_frame > rv->region()->position()) {
4773 rv->get_time_axis_view().show_timestretch (rv->region()->position(), drag_info.current_pointer_frame);
4776 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4777 drag_info.first_move = false;
4779 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4783 Editor::end_time_fx (ArdourCanvas::Item* item, GdkEvent* event)
4785 clicked_regionview->get_time_axis_view().hide_timestretch ();
4787 if (drag_info.first_move) {
4791 nframes_t newlen = drag_info.last_pointer_frame - clicked_regionview->region()->position();
4792 float percentage = (float) ((double) newlen - (double) clicked_regionview->region()->length()) / ((double) newlen) * 100.0f;
4794 begin_reversible_command (_("timestretch"));
4796 if (run_timestretch (selection->regions, percentage) == 0) {
4797 session->commit_reversible_command ();
4802 Editor::mouse_brush_insert_region (RegionView* rv, nframes_t pos)
4804 /* no brushing without a useful snap setting */
4807 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
4810 switch (snap_mode) {
4812 return; /* can't work because it allows region to be placed anywhere */
4817 switch (snap_type) {
4820 case SnapToEditCursor:
4827 /* don't brush a copy over the original */
4829 if (pos == rv->region()->position()) {
4833 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*>(&arv->get_time_axis_view());
4835 if (atv == 0 || !atv->is_audio_track()) {
4839 Playlist* playlist = atv->playlist();
4840 double speed = atv->get_diskstream()->speed();
4842 XMLNode &before = playlist->get_state();
4843 playlist->add_region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (arv->audio_region())), (nframes_t) (pos * speed));
4844 XMLNode &after = playlist->get_state();
4845 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
4847 // playlist is frozen, so we have to update manually
4849 playlist->Modified(); /* EMIT SIGNAL */
4853 Editor::track_height_step_timeout ()
4856 struct timeval delta;
4858 gettimeofday (&now, 0);
4859 timersub (&now, &last_track_height_step_timestamp, &delta);
4861 if (delta.tv_sec * 1000000 + delta.tv_usec > 250000) { /* milliseconds */
4862 current_stepping_trackview = 0;