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 (cursor == playhead_cursor) {
1946 _dragging_playhead = true;
1948 if (session && drag_info.was_rolling) {
1949 session->request_stop ();
1953 drag_info.pointer_frame_offset = drag_info.grab_frame - cursor->current_frame;
1955 show_verbose_time_cursor (cursor->current_frame, 10);
1959 Editor::cursor_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
1961 Cursor* cursor = (Cursor *) drag_info.data;
1962 nframes_t adjusted_frame;
1964 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1965 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1971 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1972 if (cursor != edit_cursor || snap_type != SnapToEditCursor) {
1973 snap_to (adjusted_frame);
1977 if (adjusted_frame == drag_info.last_pointer_frame) return;
1979 cursor->set_position (adjusted_frame);
1981 if (cursor == edit_cursor) {
1982 edit_cursor_clock.set (cursor->current_frame);
1984 UpdateAllTransportClocks (cursor->current_frame);
1987 show_verbose_time_cursor (cursor->current_frame, 10);
1989 drag_info.last_pointer_frame = adjusted_frame;
1990 drag_info.first_move = false;
1994 Editor::cursor_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
1996 if (drag_info.first_move) return;
1998 cursor_drag_motion_callback (item, event);
2000 _dragging_playhead = false;
2002 if (item == &playhead_cursor->canvas_item) {
2004 session->request_locate (playhead_cursor->current_frame, drag_info.was_rolling);
2006 } else if (item == &edit_cursor->canvas_item) {
2007 edit_cursor->set_position (edit_cursor->current_frame);
2008 edit_cursor_clock.set (edit_cursor->current_frame);
2013 Editor::update_marker_drag_item (Location *location)
2015 double x1 = frame_to_pixel (location->start());
2016 double x2 = frame_to_pixel (location->end());
2018 if (location->is_mark()) {
2019 marker_drag_line_points.front().set_x(x1);
2020 marker_drag_line_points.back().set_x(x1);
2021 marker_drag_line->property_points() = marker_drag_line_points;
2024 range_marker_drag_rect->property_x1() = x1;
2025 range_marker_drag_rect->property_x2() = x2;
2030 Editor::start_marker_grab (ArdourCanvas::Item* item, GdkEvent* event)
2034 if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
2035 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
2041 Location *location = find_location_from_marker (marker, is_start);
2043 drag_info.item = item;
2044 drag_info.data = marker;
2045 drag_info.motion_callback = &Editor::marker_drag_motion_callback;
2046 drag_info.finished_callback = &Editor::marker_drag_finished_callback;
2050 drag_info.copied_location = new Location (*location);
2051 drag_info.pointer_frame_offset = drag_info.grab_frame - (is_start ? location->start() : location->end());
2053 update_marker_drag_item (location);
2055 if (location->is_mark()) {
2056 marker_drag_line->show();
2057 marker_drag_line->raise_to_top();
2060 range_marker_drag_rect->show();
2061 range_marker_drag_rect->raise_to_top();
2064 if (is_start) show_verbose_time_cursor (location->start(), 10);
2065 else show_verbose_time_cursor (location->end(), 10);
2069 Editor::marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2072 Marker* marker = (Marker *) drag_info.data;
2073 Location *real_location;
2074 Location *copy_location;
2076 bool move_both = false;
2080 if (drag_info.pointer_frame_offset <= (long) drag_info.current_pointer_frame) {
2081 newframe = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2087 nframes_t next = newframe;
2089 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2090 snap_to (newframe, 0, true);
2093 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) {
2097 /* call this to find out if its the start or end */
2099 real_location = find_location_from_marker (marker, is_start);
2101 /* use the copy that we're "dragging" around */
2103 copy_location = drag_info.copied_location;
2105 f_delta = copy_location->end() - copy_location->start();
2107 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
2111 if (copy_location->is_mark()) {
2114 copy_location->set_start (newframe);
2118 if (is_start) { // start-of-range marker
2121 copy_location->set_start (newframe);
2122 copy_location->set_end (newframe + f_delta);
2123 } else if (newframe < copy_location->end()) {
2124 copy_location->set_start (newframe);
2126 snap_to (next, 1, true);
2127 copy_location->set_end (next);
2128 copy_location->set_start (newframe);
2131 } else { // end marker
2134 copy_location->set_end (newframe);
2135 copy_location->set_start (newframe - f_delta);
2136 } else if (newframe > copy_location->start()) {
2137 copy_location->set_end (newframe);
2139 } else if (newframe > 0) {
2140 snap_to (next, -1, true);
2141 copy_location->set_start (next);
2142 copy_location->set_end (newframe);
2147 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
2148 drag_info.first_move = false;
2150 update_marker_drag_item (copy_location);
2152 LocationMarkers* lm = find_location_markers (real_location);
2153 lm->set_position (copy_location->start(), copy_location->end());
2155 show_verbose_time_cursor (newframe, 10);
2159 Editor::marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2161 if (drag_info.first_move) {
2162 marker_drag_motion_callback (item, event);
2166 Marker* marker = (Marker *) drag_info.data;
2170 begin_reversible_command ( _("move marker") );
2171 XMLNode &before = session->locations()->get_state();
2173 Location * location = find_location_from_marker (marker, is_start);
2176 if (location->is_mark()) {
2177 location->set_start (drag_info.copied_location->start());
2179 location->set (drag_info.copied_location->start(), drag_info.copied_location->end());
2183 XMLNode &after = session->locations()->get_state();
2184 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
2185 commit_reversible_command ();
2187 marker_drag_line->hide();
2188 range_marker_drag_rect->hide();
2192 Editor::start_meter_marker_grab (ArdourCanvas::Item* item, GdkEvent* event)
2195 MeterMarker* meter_marker;
2197 if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
2198 fatal << _("programming error: meter marker canvas item has no marker object pointer!") << endmsg;
2202 meter_marker = dynamic_cast<MeterMarker*> (marker);
2204 MetricSection& section (meter_marker->meter());
2206 if (!section.movable()) {
2210 drag_info.item = item;
2211 drag_info.data = marker;
2212 drag_info.motion_callback = &Editor::meter_marker_drag_motion_callback;
2213 drag_info.finished_callback = &Editor::meter_marker_drag_finished_callback;
2217 drag_info.pointer_frame_offset = drag_info.grab_frame - meter_marker->meter().frame();
2219 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2223 Editor::start_meter_marker_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
2226 MeterMarker* meter_marker;
2228 if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
2229 fatal << _("programming error: meter marker canvas item has no marker object pointer!") << endmsg;
2233 meter_marker = dynamic_cast<MeterMarker*> (marker);
2235 // create a dummy marker for visual representation of moving the copy.
2236 // The actual copying is not done before we reach the finish callback.
2238 snprintf (name, sizeof(name), "%g/%g", meter_marker->meter().beats_per_bar(), meter_marker->meter().note_divisor ());
2239 MeterMarker* new_marker = new MeterMarker(*this, *meter_group, color_map[cMeterMarker], name,
2240 *new MeterSection(meter_marker->meter()));
2242 drag_info.item = &new_marker->the_item();
2243 drag_info.copy = true;
2244 drag_info.data = new_marker;
2245 drag_info.motion_callback = &Editor::meter_marker_drag_motion_callback;
2246 drag_info.finished_callback = &Editor::meter_marker_drag_finished_callback;
2250 drag_info.pointer_frame_offset = drag_info.grab_frame - meter_marker->meter().frame();
2252 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2256 Editor::meter_marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2258 MeterMarker* marker = (MeterMarker *) drag_info.data;
2259 nframes_t adjusted_frame;
2261 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
2262 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2268 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2269 snap_to (adjusted_frame);
2272 if (adjusted_frame == drag_info.last_pointer_frame) return;
2274 marker->set_position (adjusted_frame);
2277 drag_info.last_pointer_frame = adjusted_frame;
2278 drag_info.first_move = false;
2280 show_verbose_time_cursor (adjusted_frame, 10);
2284 Editor::meter_marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2286 if (drag_info.first_move) return;
2288 meter_marker_drag_motion_callback (drag_info.item, event);
2290 MeterMarker* marker = (MeterMarker *) drag_info.data;
2293 TempoMap& map (session->tempo_map());
2294 map.bbt_time (drag_info.last_pointer_frame, when);
2296 if (drag_info.copy == true) {
2297 begin_reversible_command (_("copy meter mark"));
2298 XMLNode &before = map.get_state();
2299 map.add_meter (marker->meter(), when);
2300 XMLNode &after = map.get_state();
2301 session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
2302 commit_reversible_command ();
2304 // delete the dummy marker we used for visual representation of copying.
2305 // a new visual marker will show up automatically.
2308 begin_reversible_command (_("move meter mark"));
2309 XMLNode &before = map.get_state();
2310 map.move_meter (marker->meter(), when);
2311 XMLNode &after = map.get_state();
2312 session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
2313 commit_reversible_command ();
2318 Editor::start_tempo_marker_grab (ArdourCanvas::Item* item, GdkEvent* event)
2321 TempoMarker* tempo_marker;
2323 if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
2324 fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg;
2328 if ((tempo_marker = dynamic_cast<TempoMarker *> (marker)) == 0) {
2329 fatal << _("programming error: marker for tempo is not a tempo marker!") << endmsg;
2333 MetricSection& section (tempo_marker->tempo());
2335 if (!section.movable()) {
2339 drag_info.item = item;
2340 drag_info.data = marker;
2341 drag_info.motion_callback = &Editor::tempo_marker_drag_motion_callback;
2342 drag_info.finished_callback = &Editor::tempo_marker_drag_finished_callback;
2346 drag_info.pointer_frame_offset = drag_info.grab_frame - tempo_marker->tempo().frame();
2347 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2351 Editor::start_tempo_marker_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
2354 TempoMarker* tempo_marker;
2356 if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
2357 fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg;
2361 if ((tempo_marker = dynamic_cast<TempoMarker *> (marker)) == 0) {
2362 fatal << _("programming error: marker for tempo is not a tempo marker!") << endmsg;
2366 // create a dummy marker for visual representation of moving the copy.
2367 // The actual copying is not done before we reach the finish callback.
2369 snprintf (name, sizeof (name), "%.2f", tempo_marker->tempo().beats_per_minute());
2370 TempoMarker* new_marker = new TempoMarker(*this, *tempo_group, color_map[cTempoMarker], name,
2371 *new TempoSection(tempo_marker->tempo()));
2373 drag_info.item = &new_marker->the_item();
2374 drag_info.copy = true;
2375 drag_info.data = new_marker;
2376 drag_info.motion_callback = &Editor::tempo_marker_drag_motion_callback;
2377 drag_info.finished_callback = &Editor::tempo_marker_drag_finished_callback;
2381 drag_info.pointer_frame_offset = drag_info.grab_frame - tempo_marker->tempo().frame();
2383 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2387 Editor::tempo_marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2389 TempoMarker* marker = (TempoMarker *) drag_info.data;
2390 nframes_t adjusted_frame;
2392 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
2393 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2399 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2400 snap_to (adjusted_frame);
2403 if (adjusted_frame == drag_info.last_pointer_frame) return;
2405 /* OK, we've moved far enough to make it worth actually move the thing. */
2407 marker->set_position (adjusted_frame);
2409 show_verbose_time_cursor (adjusted_frame, 10);
2411 drag_info.last_pointer_frame = adjusted_frame;
2412 drag_info.first_move = false;
2416 Editor::tempo_marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2418 if (drag_info.first_move) return;
2420 tempo_marker_drag_motion_callback (drag_info.item, event);
2422 TempoMarker* marker = (TempoMarker *) drag_info.data;
2425 TempoMap& map (session->tempo_map());
2426 map.bbt_time (drag_info.last_pointer_frame, when);
2428 if (drag_info.copy == true) {
2429 begin_reversible_command (_("copy tempo mark"));
2430 XMLNode &before = map.get_state();
2431 map.add_tempo (marker->tempo(), when);
2432 XMLNode &after = map.get_state();
2433 session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2434 commit_reversible_command ();
2436 // delete the dummy marker we used for visual representation of copying.
2437 // a new visual marker will show up automatically.
2440 begin_reversible_command (_("move tempo mark"));
2441 XMLNode &before = map.get_state();
2442 map.move_tempo (marker->tempo(), when);
2443 XMLNode &after = map.get_state();
2444 session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2445 commit_reversible_command ();
2450 Editor::remove_gain_control_point (ArdourCanvas::Item*item, GdkEvent* event)
2452 ControlPoint* control_point;
2454 if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
2455 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2459 // We shouldn't remove the first or last gain point
2460 if (control_point->line.is_last_point(*control_point) ||
2461 control_point->line.is_first_point(*control_point)) {
2465 control_point->line.remove_point (*control_point);
2469 Editor::remove_control_point (ArdourCanvas::Item*item, GdkEvent* event)
2471 ControlPoint* control_point;
2473 if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
2474 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2478 control_point->line.remove_point (*control_point);
2482 Editor::start_control_point_grab (ArdourCanvas::Item* item, GdkEvent* event)
2484 ControlPoint* control_point;
2486 if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
2487 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2491 drag_info.item = item;
2492 drag_info.data = control_point;
2493 drag_info.motion_callback = &Editor::control_point_drag_motion_callback;
2494 drag_info.finished_callback = &Editor::control_point_drag_finished_callback;
2496 start_grab (event, fader_cursor);
2498 control_point->line.start_drag (control_point, drag_info.grab_frame, 0);
2500 float fraction = 1.0 - (control_point->get_y() / control_point->line.height());
2501 set_verbose_canvas_cursor (control_point->line.get_verbose_cursor_string (fraction),
2502 drag_info.current_pointer_x + 20, drag_info.current_pointer_y + 20);
2504 show_verbose_canvas_cursor ();
2508 Editor::control_point_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2510 ControlPoint* cp = reinterpret_cast<ControlPoint *> (drag_info.data);
2512 double cx = drag_info.current_pointer_x;
2513 double cy = drag_info.current_pointer_y;
2515 drag_info.cumulative_x_drag = cx - drag_info.grab_x ;
2516 drag_info.cumulative_y_drag = cy - drag_info.grab_y ;
2518 if (drag_info.x_constrained) {
2519 cx = drag_info.grab_x;
2521 if (drag_info.y_constrained) {
2522 cy = drag_info.grab_y;
2525 cp->line.parent_group().w2i (cx, cy);
2529 cy = min ((double) cp->line.height(), cy);
2531 //translate cx to frames
2532 nframes_t cx_frames = unit_to_frame (cx);
2534 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && !drag_info.x_constrained) {
2535 snap_to (cx_frames);
2538 float fraction = 1.0 - (cy / cp->line.height());
2542 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
2548 cp->line.point_drag (*cp, cx_frames , fraction, push);
2550 set_verbose_canvas_cursor_text (cp->line.get_verbose_cursor_string (fraction));
2552 drag_info.first_move = false;
2556 Editor::control_point_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2558 ControlPoint* cp = reinterpret_cast<ControlPoint *> (drag_info.data);
2560 if (drag_info.first_move) {
2564 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
2565 reset_point_selection ();
2569 control_point_drag_motion_callback (item, event);
2571 cp->line.end_drag (cp);
2575 Editor::start_line_grab_from_regionview (ArdourCanvas::Item* item, GdkEvent* event)
2577 switch (mouse_mode) {
2579 assert(dynamic_cast<AudioRegionView*>(clicked_regionview));
2580 start_line_grab (dynamic_cast<AudioRegionView*>(clicked_regionview)->get_gain_line(), event);
2588 Editor::start_line_grab_from_line (ArdourCanvas::Item* item, GdkEvent* event)
2592 if ((al = reinterpret_cast<AutomationLine*> (item->get_data ("line"))) == 0) {
2593 fatal << _("programming error: line canvas item has no line pointer!") << endmsg;
2597 start_line_grab (al, event);
2601 Editor::start_line_grab (AutomationLine* line, GdkEvent* event)
2605 nframes_t frame_within_region;
2607 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2611 cx = event->button.x;
2612 cy = event->button.y;
2613 line->parent_group().w2i (cx, cy);
2614 frame_within_region = (nframes_t) floor (cx * frames_per_unit);
2616 if (!line->control_points_adjacent (frame_within_region, current_line_drag_info.before,
2617 current_line_drag_info.after)) {
2618 /* no adjacent points */
2622 drag_info.item = &line->grab_item();
2623 drag_info.data = line;
2624 drag_info.motion_callback = &Editor::line_drag_motion_callback;
2625 drag_info.finished_callback = &Editor::line_drag_finished_callback;
2627 start_grab (event, fader_cursor);
2629 double fraction = 1.0 - (cy / line->height());
2631 line->start_drag (0, drag_info.grab_frame, fraction);
2633 set_verbose_canvas_cursor (line->get_verbose_cursor_string (fraction),
2634 drag_info.current_pointer_x + 20, drag_info.current_pointer_y + 20);
2635 show_verbose_canvas_cursor ();
2639 Editor::line_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2641 AutomationLine* line = reinterpret_cast<AutomationLine *> (drag_info.data);
2642 double cx = drag_info.current_pointer_x;
2643 double cy = drag_info.current_pointer_y;
2645 line->parent_group().w2i (cx, cy);
2648 fraction = 1.0 - (cy / line->height());
2652 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
2658 line->line_drag (current_line_drag_info.before, current_line_drag_info.after, fraction, push);
2660 set_verbose_canvas_cursor_text (line->get_verbose_cursor_string (fraction));
2664 Editor::line_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2666 AutomationLine* line = reinterpret_cast<AutomationLine *> (drag_info.data);
2667 line_drag_motion_callback (item, event);
2672 Editor::start_region_grab (ArdourCanvas::Item* item, GdkEvent* event)
2674 if (selection->regions.empty() || clicked_regionview == 0) {
2678 drag_info.copy = false;
2679 drag_info.item = item;
2680 drag_info.data = clicked_regionview;
2681 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2682 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2687 TimeAxisView* tvp = clicked_trackview;
2688 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
2690 if (tv && tv->is_audio_track()) {
2691 speed = tv->get_diskstream()->speed();
2694 drag_info.last_frame_position = (nframes_t) (clicked_regionview->region()->position() / speed);
2695 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2696 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2697 // we want a move threshold
2698 drag_info.want_move_threshold = true;
2700 show_verbose_time_cursor (drag_info.last_frame_position, 10);
2702 begin_reversible_command (_("move region(s)"));
2706 Editor::start_region_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
2708 if (selection->regions.empty() || clicked_regionview == 0) {
2712 drag_info.copy = true;
2713 drag_info.item = item;
2714 drag_info.data = clicked_regionview;
2718 TimeAxisView* tv = &clicked_regionview->get_time_axis_view();
2719 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*>(tv);
2722 if (atv && atv->is_audio_track()) {
2723 speed = atv->get_diskstream()->speed();
2726 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2727 drag_info.last_frame_position = (nframes_t) (clicked_regionview->region()->position() / speed);
2728 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2729 // we want a move threshold
2730 drag_info.want_move_threshold = true;
2731 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2732 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2733 show_verbose_time_cursor (drag_info.last_frame_position, 10);
2737 Editor::start_region_brush_grab (ArdourCanvas::Item* item, GdkEvent* event)
2739 if (selection->regions.empty() || clicked_regionview == 0) {
2743 drag_info.copy = false;
2744 drag_info.item = item;
2745 drag_info.data = clicked_regionview;
2746 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2747 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2752 TimeAxisView* tvp = clicked_trackview;
2753 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
2755 if (tv && tv->is_audio_track()) {
2756 speed = tv->get_diskstream()->speed();
2759 drag_info.last_frame_position = (nframes_t) (clicked_regionview->region()->position() / speed);
2760 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2761 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2762 // we want a move threshold
2763 drag_info.want_move_threshold = true;
2764 drag_info.brushing = true;
2766 begin_reversible_command (_("Drag region brush"));
2770 Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2774 RegionView* rv = reinterpret_cast<RegionView*> (drag_info.data);
2775 nframes_t pending_region_position = 0;
2776 int32_t pointer_y_span = 0, canvas_pointer_y_span = 0, original_pointer_order;
2777 int32_t visible_y_high = 0, visible_y_low = 512; //high meaning higher numbered.. not the height on the screen
2778 bool clamp_y_axis = false;
2779 vector<int32_t> height_list(512) ;
2780 vector<int32_t>::iterator j;
2782 if (drag_info.copy && drag_info.move_threshold_passed && drag_info.want_move_threshold) {
2784 drag_info.want_move_threshold = false; // don't copy again
2786 /* this is committed in the grab finished callback. */
2788 begin_reversible_command (_("Drag region copy"));
2790 /* duplicate the region(s) */
2792 vector<RegionView*> new_regionviews;
2794 set<Playlist*> affected_playlists;
2795 pair<set<Playlist*>::iterator,bool> insert_result;
2797 // TODO: Crossfades need to be copied!
2798 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
2803 Playlist* to_playlist = rv->region()->playlist();
2804 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*>(&rv->get_time_axis_view());
2806 insert_result = affected_playlists.insert (to_playlist);
2807 if (insert_result.second) {
2808 session->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
2811 latest_regionview = 0;
2813 sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
2815 /* create a new region with the same name. */
2817 // FIXME: ew. need a (virtual) Region::duplicate() or something?
2819 boost::shared_ptr<Region> newregion;
2820 boost::shared_ptr<Region> ar;
2822 if ((ar = boost::dynamic_pointer_cast<AudioRegion>(rv->region())) != 0) {
2823 newregion = RegionFactory::create (ar);
2825 assert(newregion != 0);
2827 /* if the original region was locked, we don't care */
2829 newregion->set_locked (false);
2831 to_playlist->add_region (newregion, (nframes_t) (rv->region()->position() * atv->get_diskstream()->speed()));
2835 if (latest_regionview) {
2836 new_regionviews.push_back (latest_regionview);
2842 if (new_regionviews.empty()) {
2846 /* reset selection to new regionviews */
2848 selection->set (new_regionviews);
2850 /* reset drag_info data to reflect the fact that we are dragging the copies */
2852 drag_info.data = new_regionviews.front();
2853 swap_grab (new_regionviews.front()->get_canvas_group (), 0, event->motion.time);
2856 /* Which trackview is this ? */
2858 TimeAxisView* tvp = trackview_by_y_position (drag_info.current_pointer_y);
2859 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
2861 /* The region motion is only processed if the pointer is over
2865 if (!tv || !tv->is_audio_track()) {
2866 /* To make sure we hide the verbose canvas cursor when the mouse is
2867 not held over and audiotrack.
2869 hide_verbose_canvas_cursor ();
2873 original_pointer_order = drag_info.last_trackview->order;
2875 /************************************************************
2877 ************************************************************/
2879 if (drag_info.brushing) {
2880 clamp_y_axis = true;
2885 if ((pointer_y_span = (drag_info.last_trackview->order - tv->order)) != 0) {
2887 int32_t children = 0, numtracks = 0;
2888 // XXX hard coding track limit, oh my, so very very bad
2889 bitset <1024> tracks (0x00);
2890 /* get a bitmask representing the visible tracks */
2892 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2893 TimeAxisView *tracklist_timeview;
2894 tracklist_timeview = (*i);
2895 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tracklist_timeview);
2896 list<TimeAxisView*> children_list;
2898 /* zeroes are audio tracks. ones are other types. */
2900 if (!atv2->hidden()) {
2902 if (visible_y_high < atv2->order) {
2903 visible_y_high = atv2->order;
2905 if (visible_y_low > atv2->order) {
2906 visible_y_low = atv2->order;
2909 if (!atv2->is_audio_track()) {
2910 tracks = tracks |= (0x01 << atv2->order);
2913 height_list[atv2->order] = (*i)->height;
2915 if ((children_list = atv2->get_child_list()).size() > 0) {
2916 for (list<TimeAxisView*>::iterator j = children_list.begin(); j != children_list.end(); ++j) {
2917 tracks = tracks |= (0x01 << (atv2->order + children));
2918 height_list[atv2->order + children] = (*j)->height;
2926 /* find the actual span according to the canvas */
2928 canvas_pointer_y_span = pointer_y_span;
2929 if (drag_info.last_trackview->order >= tv->order) {
2931 for (y = tv->order; y < drag_info.last_trackview->order; y++) {
2932 if (height_list[y] == 0 ) {
2933 canvas_pointer_y_span--;
2938 for (y = drag_info.last_trackview->order;y <= tv->order; y++) {
2939 if ( height_list[y] == 0 ) {
2940 canvas_pointer_y_span++;
2945 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
2946 RegionView* rv2 = (*i);
2947 double ix1, ix2, iy1, iy2;
2950 rv2->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
2951 rv2->get_canvas_group()->i2w (ix1, iy1);
2952 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
2953 RouteTimeAxisView* atv2 = dynamic_cast<RouteTimeAxisView*>(tvp2);
2955 if (atv2->order != original_pointer_order) {
2956 /* this isn't the pointer track */
2958 if (canvas_pointer_y_span > 0) {
2960 /* moving up the canvas */
2961 if ((atv2->order - canvas_pointer_y_span) >= visible_y_low) {
2963 int32_t visible_tracks = 0;
2964 while (visible_tracks < canvas_pointer_y_span ) {
2967 while (height_list[atv2->order - (visible_tracks - n)] == 0) {
2968 /* we're passing through a hidden track */
2973 if (tracks[atv2->order - (canvas_pointer_y_span - n)] != 0x00) {
2974 clamp_y_axis = true;
2978 clamp_y_axis = true;
2981 } else if (canvas_pointer_y_span < 0) {
2983 /*moving down the canvas*/
2985 if ((atv2->order - (canvas_pointer_y_span - n)) <= visible_y_high) { // we will overflow
2988 int32_t visible_tracks = 0;
2990 while (visible_tracks > canvas_pointer_y_span ) {
2993 while (height_list[atv2->order - (visible_tracks - n)] == 0) {
2997 if ( tracks[atv2->order - ( canvas_pointer_y_span - n)] != 0x00) {
2998 clamp_y_axis = true;
3003 clamp_y_axis = true;
3009 /* this is the pointer's track */
3010 if ((atv2->order - pointer_y_span) > visible_y_high) { // we will overflow
3011 clamp_y_axis = true;
3012 } else if ((atv2->order - pointer_y_span) < visible_y_low) { // we will underflow
3013 clamp_y_axis = true;
3021 } else if (drag_info.last_trackview == tv) {
3022 clamp_y_axis = true;
3026 if (!clamp_y_axis) {
3027 drag_info.last_trackview = tv;
3030 /************************************************************
3032 ************************************************************/
3034 /* compute the amount of pointer motion in frames, and where
3035 the region would be if we moved it by that much.
3038 if (drag_info.move_threshold_passed) {
3040 if ((int32_t)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
3042 nframes_t sync_frame;
3043 nframes_t sync_offset;
3046 pending_region_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
3048 sync_offset = rv->region()->sync_offset (sync_dir);
3049 sync_frame = rv->region()->adjust_to_sync (pending_region_position);
3051 /* we snap if the snap modifier is not enabled.
3054 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3055 snap_to (sync_frame);
3058 if (sync_frame - sync_offset <= sync_frame) {
3059 pending_region_position = sync_frame - (sync_dir*sync_offset);
3061 pending_region_position = 0;
3065 pending_region_position = 0;
3068 if (pending_region_position > max_frames - rv->region()->length()) {
3069 pending_region_position = drag_info.last_frame_position;
3072 // printf ("3: pending_region_position= %lu %lu\n", pending_region_position, drag_info.last_frame_position );
3074 if (pending_region_position != drag_info.last_frame_position && !drag_info.x_constrained) {
3076 /* now compute the canvas unit distance we need to move the regiondrag_info.last_trackview->order
3077 to make it appear at the new location.
3080 if (pending_region_position > drag_info.last_frame_position) {
3081 x_delta = ((double) (pending_region_position - drag_info.last_frame_position) / frames_per_unit);
3083 x_delta = -((double) (drag_info.last_frame_position - pending_region_position) / frames_per_unit);
3086 drag_info.last_frame_position = pending_region_position;
3093 /* threshold not passed */
3098 /*************************************************************
3100 ************************************************************/
3102 if (x_delta == 0 && (pointer_y_span == 0)) {
3103 /* haven't reached next snap point, and we're not switching
3104 trackviews. nothing to do.
3110 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
3112 RegionView* rv2 = (*i);
3114 // If any regionview is at zero, we need to know so we can stop further leftward motion.
3116 double ix1, ix2, iy1, iy2;
3117 rv2->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3118 rv2->get_canvas_group()->i2w (ix1, iy1);
3127 /*************************************************************
3129 ************************************************************/
3131 pair<set<Playlist*>::iterator,bool> insert_result;
3132 const list<RegionView*>& layered_regions = selection->regions.by_layer();
3134 for (list<RegionView*>::const_iterator i = layered_regions.begin(); i != layered_regions.end(); ++i) {
3136 RegionView* rv = (*i);
3137 double ix1, ix2, iy1, iy2;
3138 int32_t temp_pointer_y_span = pointer_y_span;
3140 /* get item BBox, which will be relative to parent. so we have
3141 to query on a child, then convert to world coordinates using
3145 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3146 rv->get_canvas_group()->i2w (ix1, iy1);
3147 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
3148 AudioTimeAxisView* canvas_atv = dynamic_cast<AudioTimeAxisView*>(tvp2);
3149 AudioTimeAxisView* temp_atv;
3151 if ((pointer_y_span != 0) && !clamp_y_axis) {
3154 for (j = height_list.begin(); j!= height_list.end(); j++) {
3155 if (x == canvas_atv->order) {
3156 /* we found the track the region is on */
3157 if (x != original_pointer_order) {
3158 /*this isn't from the same track we're dragging from */
3159 temp_pointer_y_span = canvas_pointer_y_span;
3161 while (temp_pointer_y_span > 0) {
3162 /* we're moving up canvas-wise,
3163 so we need to find the next track height
3165 if (j != height_list.begin()) {
3168 if (x != original_pointer_order) {
3169 /* we're not from the dragged track, so ignore hidden tracks. */
3171 temp_pointer_y_span++;
3175 temp_pointer_y_span--;
3177 while (temp_pointer_y_span < 0) {
3179 if (x != original_pointer_order) {
3181 temp_pointer_y_span--;
3185 if (j != height_list.end()) {
3188 temp_pointer_y_span++;
3190 /* find out where we'll be when we move and set height accordingly */
3192 tvp2 = trackview_by_y_position (iy1 + y_delta);
3193 temp_atv = dynamic_cast<AudioTimeAxisView*>(tvp2);
3194 rv->set_height (temp_atv->height);
3196 /* if you un-comment the following, the region colours will follow the track colours whilst dragging,
3197 personally, i think this can confuse things, but never mind.
3200 //const GdkColor& col (temp_atv->view->get_region_color());
3201 //rv->set_color (const_cast<GdkColor&>(col));
3208 /* prevent the regionview from being moved to before
3209 the zero position on the canvas.
3214 if (-x_delta > ix1) {
3217 } else if ((x_delta > 0) &&(rv->region()->last_frame() > max_frames - x_delta)) {
3218 x_delta = max_frames - rv->region()->last_frame();
3221 if (drag_info.first_move) {
3223 /* hide any dependent views */
3225 // rv->get_time_axis_view().hide_dependent_views (*rv);
3227 /* this is subtle. raising the regionview itself won't help,
3228 because raise_to_top() just puts the item on the top of
3229 its parent's stack. so, we need to put the trackview canvas_display group
3230 on the top, since its parent is the whole canvas.
3233 rv->get_canvas_group()->raise_to_top();
3234 rv->get_time_axis_view().canvas_display->raise_to_top();
3235 cursor_group->raise_to_top();
3237 /* freeze the playlists from notifying till
3241 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&rv->get_time_axis_view());
3242 if (atv && atv->is_audio_track()) {
3243 AudioPlaylist* pl = dynamic_cast<AudioPlaylist*>(atv->get_diskstream()->playlist());
3245 /* only freeze and capture state once */
3247 insert_result = motion_frozen_playlists.insert (pl);
3248 if (insert_result.second) {
3250 session->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
3254 rv->region()->set_opaque(false);
3257 if (drag_info.brushing) {
3258 mouse_brush_insert_region (rv, pending_region_position);
3260 rv->move (x_delta, y_delta);
3264 if (drag_info.first_move) {
3265 cursor_group->raise_to_top();
3268 drag_info.first_move = false;
3270 if (x_delta != 0 && !drag_info.brushing) {
3271 show_verbose_time_cursor (drag_info.last_frame_position, 10);
3277 Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
3280 RegionView* rv = reinterpret_cast<RegionView *> (drag_info.data);
3281 pair<set<Playlist*>::iterator,bool> insert_result;
3282 bool nocommit = true;
3284 RouteTimeAxisView* atv;
3285 bool regionview_y_movement;
3286 bool regionview_x_movement;
3288 /* first_move is set to false if the regionview has been moved in the
3292 if (drag_info.first_move) {
3299 /* The regionview has been moved at some stage during the grab so we need
3300 to account for any mouse movement between this event and the last one.
3303 region_drag_motion_callback (item, event);
3305 if (drag_info.brushing) {
3306 /* all changes were made during motion event handlers */
3310 /* adjust for track speed */
3313 atv = dynamic_cast<AudioTimeAxisView*> (drag_info.last_trackview);
3314 if (atv && atv->get_diskstream()) {
3315 speed = atv->get_diskstream()->speed();
3318 regionview_x_movement = (drag_info.last_frame_position != (nframes_t) (rv->region()->position()/speed));
3319 regionview_y_movement = (drag_info.last_trackview != &rv->get_time_axis_view());
3321 //printf ("last_frame: %s position is %lu %g\n", rv->get_time_axis_view().name().c_str(), drag_info.last_frame_position, speed);
3322 //printf ("last_rackview: %s \n", drag_info.last_trackview->name().c_str());
3324 if (regionview_y_movement) {
3326 /* motion between tracks */
3328 list<RegionView*> new_selection;
3330 /* moved to a different audio track. */
3332 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ) {
3334 RegionView* rv2 = (*i);
3336 /* the region that used to be in the old playlist is not
3337 moved to the new one - we make a copy of it. as a result,
3338 any existing editor for the region should no longer be
3342 if (!drag_info.copy) {
3343 rv2->hide_region_editor();
3345 new_selection.push_back (rv2);
3349 /* first, freeze the target tracks */
3351 for (list<RegionView*>::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) {
3353 Playlist* from_playlist;
3354 Playlist* to_playlist;
3356 double ix1, ix2, iy1, iy2;
3358 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3359 (*i)->get_canvas_group()->i2w (ix1, iy1);
3360 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
3361 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2);
3363 (*i)->region()->set_opaque (true);
3365 from_playlist = (*i)->region()->playlist();
3366 to_playlist = atv2->playlist();
3368 /* the from_playlist was frozen in the "first_move" case
3369 of the motion handler. the insert can fail,
3370 but that doesn't matter. it just means
3371 we already have the playlist in the list.
3374 motion_frozen_playlists.insert (from_playlist);
3376 /* only freeze the to_playlist once */
3378 insert_result = motion_frozen_playlists.insert(to_playlist);
3379 if (insert_result.second) {
3380 to_playlist->freeze();
3381 session->add_command(new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
3386 /* now do it again with the actual operations */
3388 for (list<RegionView*>::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) {
3390 Playlist* from_playlist;
3391 Playlist* to_playlist;
3393 double ix1, ix2, iy1, iy2;
3395 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3396 (*i)->get_canvas_group()->i2w (ix1, iy1);
3397 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
3398 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2);
3400 from_playlist = (*i)->region()->playlist();
3401 to_playlist = atv2->playlist();
3403 latest_regionview = 0;
3405 where = (nframes_t) (unit_to_frame (ix1) * speed);
3406 boost::shared_ptr<Region> new_region (RegionFactory::create ((*i)->region()));
3408 from_playlist->remove_region (((*i)->region()));
3410 sigc::connection c = atv2->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3411 to_playlist->add_region (new_region, where);
3414 if (latest_regionview) {
3415 selection->add (latest_regionview);
3421 /* motion within a single track */
3423 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
3427 if (rv->region()->locked()) {
3431 if (regionview_x_movement) {
3432 double ownspeed = 1.0;
3433 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&(rv->get_time_axis_view()));
3435 if (atv && atv->get_diskstream()) {
3436 ownspeed = atv->get_diskstream()->speed();
3439 /* base the new region position on the current position of the regionview.*/
3441 double ix1, ix2, iy1, iy2;
3443 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3444 rv->get_canvas_group()->i2w (ix1, iy1);
3445 where = (nframes_t) (unit_to_frame (ix1) * ownspeed);
3449 where = rv->region()->position();
3452 rv->get_time_axis_view().reveal_dependent_views (*rv);
3454 /* no need to add an undo here, we did that when we added this playlist to motion_frozen playlists */
3456 rv->region()->set_position (where, (void *) this);
3457 rv->region()->set_opaque (true);
3462 for (set<Playlist*>::iterator p = motion_frozen_playlists.begin(); p != motion_frozen_playlists.end(); ++p) {
3464 session->add_command (new MementoCommand<Playlist>(*(*p), 0, & (*p)->get_state()));
3467 motion_frozen_playlists.clear ();
3470 commit_reversible_command ();
3475 Editor::region_view_item_click (AudioRegionView& rv, GdkEventButton* event)
3477 /* Either add to or set the set the region selection, unless
3478 this is an alignment click (control used)
3481 if (Keyboard::modifier_state_contains (event->state, Keyboard::Control)) {
3482 TimeAxisView* tv = &rv.get_time_axis_view();
3483 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(tv);
3485 if (atv && atv->is_audio_track()) {
3486 speed = atv->get_diskstream()->speed();
3489 if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Alt))) {
3491 align_region (rv.region(), SyncPoint, (nframes_t) (edit_cursor->current_frame * speed));
3493 } else if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Shift))) {
3495 align_region (rv.region(), End, (nframes_t) (edit_cursor->current_frame * speed));
3499 align_region (rv.region(), Start, (nframes_t) (edit_cursor->current_frame * speed));
3505 Editor::show_verbose_time_cursor (nframes_t frame, double offset, double xpos, double ypos)
3516 switch (ARDOUR_UI::instance()->secondary_clock.mode ()) {
3517 case AudioClock::BBT:
3518 session->bbt_time (frame, bbt);
3519 snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32, bbt.bars, bbt.beats, bbt.ticks);
3522 case AudioClock::SMPTE:
3523 session->smpte_time (frame, smpte);
3524 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
3527 case AudioClock::MinSec:
3528 /* XXX fix this to compute min/sec properly */
3529 session->smpte_time (frame, smpte);
3530 secs = smpte.seconds + ((float) smpte.frames / Config->get_smpte_frames_per_second());
3531 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%.4f", smpte.hours, smpte.minutes, secs);
3535 snprintf (buf, sizeof(buf), "%u", frame);
3539 if (xpos >= 0 && ypos >=0) {
3540 set_verbose_canvas_cursor (buf, xpos + offset, ypos + offset);
3543 set_verbose_canvas_cursor (buf, drag_info.current_pointer_x + offset, drag_info.current_pointer_y + offset);
3545 show_verbose_canvas_cursor ();
3549 Editor::show_verbose_duration_cursor (nframes_t start, nframes_t end, double offset, double xpos, double ypos)
3556 Meter meter_at_start(session->tempo_map().meter_at(start));
3562 switch (ARDOUR_UI::instance()->secondary_clock.mode ()) {
3563 case AudioClock::BBT:
3564 session->bbt_time (start, sbbt);
3565 session->bbt_time (end, ebbt);
3568 /* XXX this computation won't work well if the
3569 user makes a selection that spans any meter changes.
3572 ebbt.bars -= sbbt.bars;
3573 if (ebbt.beats >= sbbt.beats) {
3574 ebbt.beats -= sbbt.beats;
3577 ebbt.beats = int(meter_at_start.beats_per_bar()) + ebbt.beats - sbbt.beats;
3579 if (ebbt.ticks >= sbbt.ticks) {
3580 ebbt.ticks -= sbbt.ticks;
3583 ebbt.ticks = int(Meter::ticks_per_beat) + ebbt.ticks - sbbt.ticks;
3586 snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32, ebbt.bars, ebbt.beats, ebbt.ticks);
3589 case AudioClock::SMPTE:
3590 session->smpte_duration (end - start, smpte);
3591 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
3594 case AudioClock::MinSec:
3595 /* XXX fix this to compute min/sec properly */
3596 session->smpte_duration (end - start, smpte);
3597 secs = smpte.seconds + ((float) smpte.frames / Config->get_smpte_frames_per_second());
3598 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%.4f", smpte.hours, smpte.minutes, secs);
3602 snprintf (buf, sizeof(buf), "%u", end - start);
3606 if (xpos >= 0 && ypos >=0) {
3607 set_verbose_canvas_cursor (buf, xpos + offset, ypos + offset);
3610 set_verbose_canvas_cursor (buf, drag_info.current_pointer_x + offset, drag_info.current_pointer_y + offset);
3612 show_verbose_canvas_cursor ();
3616 Editor::collect_new_region_view (RegionView* rv)
3618 latest_regionview = rv;
3622 Editor::start_selection_grab (ArdourCanvas::Item* item, GdkEvent* event)
3624 if (clicked_regionview == 0) {
3628 /* lets try to create new Region for the selection */
3630 vector<boost::shared_ptr<AudioRegion> > new_regions;
3631 create_region_from_selection (new_regions);
3633 if (new_regions.empty()) {
3637 /* XXX fix me one day to use all new regions */
3639 boost::shared_ptr<Region> region (new_regions.front());
3641 /* add it to the current stream/playlist.
3643 tricky: the streamview for the track will add a new regionview. we will
3644 catch the signal it sends when it creates the regionview to
3645 set the regionview we want to then drag.
3648 latest_regionview = 0;
3649 sigc::connection c = clicked_audio_trackview->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3651 /* A selection grab currently creates two undo/redo operations, one for
3652 creating the new region and another for moving it.
3655 begin_reversible_command (_("selection grab"));
3657 Playlist* playlist = clicked_trackview->playlist();
3659 XMLNode *before = &(playlist->get_state());
3660 clicked_trackview->playlist()->add_region (region, selection->time[clicked_selection].start);
3661 XMLNode *after = &(playlist->get_state());
3662 session->add_command(new MementoCommand<Playlist>(*playlist, before, after));
3664 commit_reversible_command ();
3668 if (latest_regionview == 0) {
3669 /* something went wrong */
3673 /* we need to deselect all other regionviews, and select this one
3674 i'm ignoring undo stuff, because the region creation will take care of it */
3675 selection->set (latest_regionview);
3677 drag_info.item = latest_regionview->get_canvas_group();
3678 drag_info.data = latest_regionview;
3679 drag_info.motion_callback = &Editor::region_drag_motion_callback;
3680 drag_info.finished_callback = &Editor::region_drag_finished_callback;
3684 drag_info.last_trackview = clicked_trackview;
3685 drag_info.last_frame_position = latest_regionview->region()->position();
3686 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
3688 show_verbose_time_cursor (drag_info.last_frame_position, 10);
3692 Editor::cancel_selection ()
3694 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3695 (*i)->hide_selection ();
3697 begin_reversible_command (_("cancel selection"));
3698 selection->clear ();
3699 clicked_selection = 0;
3700 commit_reversible_command ();
3704 Editor::start_selection_op (ArdourCanvas::Item* item, GdkEvent* event, SelectionOp op)
3706 nframes_t start = 0;
3713 drag_info.item = item;
3714 drag_info.motion_callback = &Editor::drag_selection;
3715 drag_info.finished_callback = &Editor::end_selection_op;
3720 case CreateSelection:
3721 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
3722 drag_info.copy = true;
3724 drag_info.copy = false;
3726 start_grab (event, selector_cursor);
3729 case SelectionStartTrim:
3730 if (clicked_trackview) {
3731 clicked_trackview->order_selection_trims (item, true);
3733 start_grab (event, trimmer_cursor);
3734 start = selection->time[clicked_selection].start;
3735 drag_info.pointer_frame_offset = drag_info.grab_frame - start;
3738 case SelectionEndTrim:
3739 if (clicked_trackview) {
3740 clicked_trackview->order_selection_trims (item, false);
3742 start_grab (event, trimmer_cursor);
3743 end = selection->time[clicked_selection].end;
3744 drag_info.pointer_frame_offset = drag_info.grab_frame - end;
3748 start = selection->time[clicked_selection].start;
3750 drag_info.pointer_frame_offset = drag_info.grab_frame - start;
3754 if (selection_op == SelectionMove) {
3755 show_verbose_time_cursor(start, 10);
3757 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
3762 Editor::drag_selection (ArdourCanvas::Item* item, GdkEvent* event)
3764 nframes_t start = 0;
3767 nframes_t pending_position;
3769 if ((int32_t) drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
3770 pending_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
3773 pending_position = 0;
3776 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3777 snap_to (pending_position);
3780 /* only alter selection if the current frame is
3781 different from the last frame position (adjusted)
3784 if (pending_position == drag_info.last_pointer_frame) return;
3786 switch (selection_op) {
3787 case CreateSelection:
3789 if (drag_info.first_move) {
3790 snap_to (drag_info.grab_frame);
3793 if (pending_position < drag_info.grab_frame) {
3794 start = pending_position;
3795 end = drag_info.grab_frame;
3797 end = pending_position;
3798 start = drag_info.grab_frame;
3801 /* first drag: Either add to the selection
3802 or create a new selection->
3805 if (drag_info.first_move) {
3807 begin_reversible_command (_("range selection"));
3809 if (drag_info.copy) {
3810 /* adding to the selection */
3811 clicked_selection = selection->add (start, end);
3812 drag_info.copy = false;
3814 /* new selection-> */
3815 clicked_selection = selection->set (clicked_trackview, start, end);
3820 case SelectionStartTrim:
3822 if (drag_info.first_move) {
3823 begin_reversible_command (_("trim selection start"));
3826 start = selection->time[clicked_selection].start;
3827 end = selection->time[clicked_selection].end;
3829 if (pending_position > end) {
3832 start = pending_position;
3836 case SelectionEndTrim:
3838 if (drag_info.first_move) {
3839 begin_reversible_command (_("trim selection end"));
3842 start = selection->time[clicked_selection].start;
3843 end = selection->time[clicked_selection].end;
3845 if (pending_position < start) {
3848 end = pending_position;
3855 if (drag_info.first_move) {
3856 begin_reversible_command (_("move selection"));
3859 start = selection->time[clicked_selection].start;
3860 end = selection->time[clicked_selection].end;
3862 length = end - start;
3864 start = pending_position;
3867 end = start + length;
3872 if (event->button.x >= horizontal_adjustment.get_value() + canvas_width) {
3873 start_canvas_autoscroll (1);
3877 selection->replace (clicked_selection, start, end);
3880 drag_info.last_pointer_frame = pending_position;
3881 drag_info.first_move = false;
3883 if (selection_op == SelectionMove) {
3884 show_verbose_time_cursor(start, 10);
3886 show_verbose_time_cursor(pending_position, 10);
3891 Editor::end_selection_op (ArdourCanvas::Item* item, GdkEvent* event)
3893 if (!drag_info.first_move) {
3894 drag_selection (item, event);
3895 /* XXX this is not object-oriented programming at all. ick */
3896 if (selection->time.consolidate()) {
3897 selection->TimeChanged ();
3899 commit_reversible_command ();
3901 /* just a click, no pointer movement.*/
3903 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3905 selection->clear_time();
3910 /* XXX what happens if its a music selection? */
3911 session->set_audio_range (selection->time);
3912 stop_canvas_autoscroll ();
3916 Editor::start_trim (ArdourCanvas::Item* item, GdkEvent* event)
3919 TimeAxisView* tvp = clicked_trackview;
3920 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3922 if (tv && tv->is_audio_track()) {
3923 speed = tv->get_diskstream()->speed();
3926 nframes_t region_start = (nframes_t) (clicked_regionview->region()->position() / speed);
3927 nframes_t region_end = (nframes_t) (clicked_regionview->region()->last_frame() / speed);
3928 nframes_t region_length = (nframes_t) (clicked_regionview->region()->length() / speed);
3930 motion_frozen_playlists.clear();
3932 //drag_info.item = clicked_regionview->get_name_highlight();
3933 drag_info.item = item;
3934 drag_info.motion_callback = &Editor::trim_motion_callback;
3935 drag_info.finished_callback = &Editor::trim_finished_callback;
3937 start_grab (event, trimmer_cursor);
3939 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
3940 trim_op = ContentsTrim;
3942 /* These will get overridden for a point trim.*/
3943 if (drag_info.current_pointer_frame < (region_start + region_length/2)) {
3944 /* closer to start */
3945 trim_op = StartTrim;
3946 } else if (drag_info.current_pointer_frame > (region_end - region_length/2)) {
3954 show_verbose_time_cursor(region_start, 10);
3957 show_verbose_time_cursor(region_end, 10);
3960 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
3966 Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
3968 RegionView* rv = clicked_regionview;
3969 nframes_t frame_delta = 0;
3970 bool left_direction;
3971 bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier());
3973 /* snap modifier works differently here..
3974 its' current state has to be passed to the
3975 various trim functions in order to work properly
3979 TimeAxisView* tvp = clicked_trackview;
3980 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
3981 pair<set<Playlist*>::iterator,bool> insert_result;
3983 if (tv && tv->is_audio_track()) {
3984 speed = tv->get_diskstream()->speed();
3987 if (drag_info.last_pointer_frame > drag_info.current_pointer_frame) {
3988 left_direction = true;
3990 left_direction = false;
3994 snap_to (drag_info.current_pointer_frame);
3997 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) {
4001 if (drag_info.first_move) {
4007 trim_type = "Region start trim";
4010 trim_type = "Region end trim";
4013 trim_type = "Region content trim";
4017 begin_reversible_command (trim_type);
4019 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
4020 (*i)->region()->set_opaque(false);
4021 (*i)->region()->freeze ();
4023 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4025 arv->temporarily_hide_envelope ();
4027 Playlist * pl = (*i)->region()->playlist();
4028 insert_result = motion_frozen_playlists.insert (pl);
4029 if (insert_result.second) {
4030 session->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
4035 if (left_direction) {
4036 frame_delta = (drag_info.last_pointer_frame - drag_info.current_pointer_frame);
4038 frame_delta = (drag_info.current_pointer_frame - drag_info.last_pointer_frame);
4043 if ((left_direction == false) && (drag_info.current_pointer_frame <= rv->region()->first_frame()/speed)) {
4046 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
4047 single_start_trim (**i, frame_delta, left_direction, obey_snap);
4053 if ((left_direction == true) && (drag_info.current_pointer_frame > (nframes_t) (rv->region()->last_frame()/speed))) {
4056 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
4057 single_end_trim (**i, frame_delta, left_direction, obey_snap);
4064 bool swap_direction = false;
4066 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
4067 swap_direction = true;
4070 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin();
4071 i != selection->regions.by_layer().end(); ++i)
4073 single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
4081 show_verbose_time_cursor((nframes_t) (rv->region()->position()/speed), 10);
4084 show_verbose_time_cursor((nframes_t) (rv->region()->last_frame()/speed), 10);
4087 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
4091 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4092 drag_info.first_move = false;
4096 Editor::single_contents_trim (RegionView& rv, nframes_t frame_delta, bool left_direction, bool swap_direction, bool obey_snap)
4098 boost::shared_ptr<Region> region (rv.region());
4100 if (region->locked()) {
4104 nframes_t new_bound;
4107 TimeAxisView* tvp = clicked_trackview;
4108 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
4110 if (tv && tv->is_audio_track()) {
4111 speed = tv->get_diskstream()->speed();
4114 if (left_direction) {
4115 if (swap_direction) {
4116 new_bound = (nframes_t) (region->position()/speed) + frame_delta;
4118 new_bound = (nframes_t) (region->position()/speed) - frame_delta;
4121 if (swap_direction) {
4122 new_bound = (nframes_t) (region->position()/speed) - frame_delta;
4124 new_bound = (nframes_t) (region->position()/speed) + frame_delta;
4129 snap_to (new_bound);
4131 region->trim_start ((nframes_t) (new_bound * speed), this);
4132 rv.region_changed (StartChanged);
4136 Editor::single_start_trim (RegionView& rv, nframes_t frame_delta, bool left_direction, bool obey_snap)
4138 boost::shared_ptr<Region> region (rv.region());
4140 if (region->locked()) {
4144 nframes_t new_bound;
4147 TimeAxisView* tvp = clicked_trackview;
4148 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
4150 if (tv && tv->is_audio_track()) {
4151 speed = tv->get_diskstream()->speed();
4154 if (left_direction) {
4155 new_bound = (nframes_t) (region->position()/speed) - frame_delta;
4157 new_bound = (nframes_t) (region->position()/speed) + frame_delta;
4161 snap_to (new_bound, (left_direction ? 0 : 1));
4164 region->trim_front ((nframes_t) (new_bound * speed), this);
4166 rv.region_changed (Change (LengthChanged|PositionChanged|StartChanged));
4170 Editor::single_end_trim (RegionView& rv, nframes_t frame_delta, bool left_direction, bool obey_snap)
4172 boost::shared_ptr<Region> region (rv.region());
4174 if (region->locked()) {
4178 nframes_t new_bound;
4181 TimeAxisView* tvp = clicked_trackview;
4182 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
4184 if (tv && tv->is_audio_track()) {
4185 speed = tv->get_diskstream()->speed();
4188 if (left_direction) {
4189 new_bound = (nframes_t) ((region->last_frame() + 1)/speed) - frame_delta;
4191 new_bound = (nframes_t) ((region->last_frame() + 1)/speed) + frame_delta;
4195 snap_to (new_bound);
4197 region->trim_end ((nframes_t) (new_bound * speed), this);
4198 rv.region_changed (LengthChanged);
4202 Editor::trim_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
4204 if (!drag_info.first_move) {
4205 trim_motion_callback (item, event);
4207 if (!clicked_regionview->get_selected()) {
4208 thaw_region_after_trim (*clicked_regionview);
4211 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin();
4212 i != selection->regions.by_layer().end(); ++i)
4214 thaw_region_after_trim (**i);
4215 (*i)->region()->set_opaque(true);
4219 for (set<Playlist*>::iterator p = motion_frozen_playlists.begin(); p != motion_frozen_playlists.end(); ++p) {
4221 session->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));
4224 motion_frozen_playlists.clear ();
4226 commit_reversible_command();
4228 /* no mouse movement */
4234 Editor::point_trim (GdkEvent* event)
4236 RegionView* rv = clicked_regionview;
4237 nframes_t new_bound = drag_info.current_pointer_frame;
4239 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4240 snap_to (new_bound);
4243 /* Choose action dependant on which button was pressed */
4244 switch (event->button.button) {
4246 trim_op = StartTrim;
4247 begin_reversible_command (_("Start point trim"));
4249 if (rv->get_selected()) {
4251 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin();
4252 i != selection->regions.by_layer().end(); ++i)
4254 if (!(*i)->region()->locked()) {
4255 Playlist *pl = (*i)->region()->playlist();
4256 XMLNode &before = pl->get_state();
4257 (*i)->region()->trim_front (new_bound, this);
4258 XMLNode &after = pl->get_state();
4259 session->add_command(new MementoCommand<Playlist>(*pl, &before, &after));
4265 if (!rv->region()->locked()) {
4266 Playlist *pl = rv->region()->playlist();
4267 XMLNode &before = pl->get_state();
4268 rv->region()->trim_front (new_bound, this);
4269 XMLNode &after = pl->get_state();
4270 session->add_command(new MementoCommand<Playlist>(*pl, &before, &after));
4274 commit_reversible_command();
4279 begin_reversible_command (_("End point trim"));
4281 if (rv->get_selected()) {
4283 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i)
4285 if (!(*i)->region()->locked()) {
4286 Playlist *pl = (*i)->region()->playlist();
4287 XMLNode &before = pl->get_state();
4288 (*i)->region()->trim_end (new_bound, this);
4289 XMLNode &after = pl->get_state();
4290 session->add_command(new MementoCommand<Playlist>(*pl, &before, &after));
4296 if (!rv->region()->locked()) {
4297 Playlist *pl = rv->region()->playlist();
4298 XMLNode &before = pl->get_state();
4299 rv->region()->trim_end (new_bound, this);
4300 XMLNode &after = pl->get_state();
4301 session->add_command (new MementoCommand<Playlist>(*pl, &before, &after));
4305 commit_reversible_command();
4314 Editor::thaw_region_after_trim (RegionView& rv)
4316 boost::shared_ptr<Region> region (rv.region());
4318 if (region->locked()) {
4322 region->thaw (_("trimmed region"));
4323 XMLNode &after = region->playlist()->get_state();
4324 session->add_command (new MementoCommand<Playlist>(*(region->playlist()), 0, &after));
4326 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(&rv);
4328 arv->unhide_envelope ();
4332 Editor::hide_marker (ArdourCanvas::Item* item, GdkEvent* event)
4337 if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
4338 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
4342 Location* location = find_location_from_marker (marker, is_start);
4343 location->set_hidden (true, this);
4348 Editor::start_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event, RangeMarkerOp op)
4354 drag_info.item = item;
4355 drag_info.motion_callback = &Editor::drag_range_markerbar_op;
4356 drag_info.finished_callback = &Editor::end_range_markerbar_op;
4358 range_marker_op = op;
4360 if (!temp_location) {
4361 temp_location = new Location;
4365 case CreateRangeMarker:
4366 case CreateTransportMarker:
4368 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
4369 drag_info.copy = true;
4371 drag_info.copy = false;
4373 start_grab (event, selector_cursor);
4377 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
4382 Editor::drag_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event)
4384 nframes_t start = 0;
4386 ArdourCanvas::SimpleRect *crect = (range_marker_op == CreateRangeMarker) ? range_bar_drag_rect: transport_bar_drag_rect;
4388 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4389 snap_to (drag_info.current_pointer_frame);
4392 /* only alter selection if the current frame is
4393 different from the last frame position.
4396 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) return;
4398 switch (range_marker_op) {
4399 case CreateRangeMarker:
4400 case CreateTransportMarker:
4401 if (drag_info.first_move) {
4402 snap_to (drag_info.grab_frame);
4405 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4406 start = drag_info.current_pointer_frame;
4407 end = drag_info.grab_frame;
4409 end = drag_info.current_pointer_frame;
4410 start = drag_info.grab_frame;
4413 /* first drag: Either add to the selection
4414 or create a new selection.
4417 if (drag_info.first_move) {
4419 temp_location->set (start, end);
4423 update_marker_drag_item (temp_location);
4424 range_marker_drag_rect->show();
4425 range_marker_drag_rect->raise_to_top();
4431 if (event->button.x >= horizontal_adjustment.get_value() + canvas_width) {
4432 start_canvas_autoscroll (1);
4436 temp_location->set (start, end);
4438 double x1 = frame_to_pixel (start);
4439 double x2 = frame_to_pixel (end);
4440 crect->property_x1() = x1;
4441 crect->property_x2() = x2;
4443 update_marker_drag_item (temp_location);
4446 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4447 drag_info.first_move = false;
4449 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
4454 Editor::end_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event)
4456 Location * newloc = 0;
4458 if (!drag_info.first_move) {
4459 drag_range_markerbar_op (item, event);
4461 switch (range_marker_op) {
4462 case CreateRangeMarker:
4464 begin_reversible_command (_("new range marker"));
4465 XMLNode &before = session->locations()->get_state();
4466 newloc = new Location(temp_location->start(), temp_location->end(), "unnamed", Location::IsRangeMarker);
4467 session->locations()->add (newloc, true);
4468 XMLNode &after = session->locations()->get_state();
4469 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
4470 commit_reversible_command ();
4472 range_bar_drag_rect->hide();
4473 range_marker_drag_rect->hide();
4477 case CreateTransportMarker:
4478 // popup menu to pick loop or punch
4479 new_transport_marker_context_menu (&event->button, item);
4484 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
4486 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
4491 start = session->locations()->first_mark_before (drag_info.grab_frame);
4492 end = session->locations()->first_mark_after (drag_info.grab_frame);
4494 if (end == max_frames) {
4495 end = session->current_end_frame ();
4499 start = session->current_start_frame ();
4502 switch (mouse_mode) {
4504 /* find the two markers on either side and then make the selection from it */
4505 cerr << "select between " << start << " .. " << end << endl;
4506 select_all_within (start, end, 0.0f, FLT_MAX, Selection::Set);
4510 /* find the two markers on either side of the click and make the range out of it */
4511 selection->set (0, start, end);
4520 stop_canvas_autoscroll ();
4526 Editor::start_mouse_zoom (ArdourCanvas::Item* item, GdkEvent* event)
4528 drag_info.item = item;
4529 drag_info.motion_callback = &Editor::drag_mouse_zoom;
4530 drag_info.finished_callback = &Editor::end_mouse_zoom;
4532 start_grab (event, zoom_cursor);
4534 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4538 Editor::drag_mouse_zoom (ArdourCanvas::Item* item, GdkEvent* event)
4543 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4544 snap_to (drag_info.current_pointer_frame);
4546 if (drag_info.first_move) {
4547 snap_to (drag_info.grab_frame);
4551 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) return;
4553 /* base start and end on initial click position */
4554 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4555 start = drag_info.current_pointer_frame;
4556 end = drag_info.grab_frame;
4558 end = drag_info.current_pointer_frame;
4559 start = drag_info.grab_frame;
4564 if (drag_info.first_move) {
4566 zoom_rect->raise_to_top();
4569 reposition_zoom_rect(start, end);
4571 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4572 drag_info.first_move = false;
4574 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4579 Editor::end_mouse_zoom (ArdourCanvas::Item* item, GdkEvent* event)
4581 if (!drag_info.first_move) {
4582 drag_mouse_zoom (item, event);
4584 if (drag_info.grab_frame < drag_info.last_pointer_frame) {
4585 temporal_zoom_by_frame (drag_info.grab_frame, drag_info.last_pointer_frame, "mouse zoom");
4587 temporal_zoom_by_frame (drag_info.last_pointer_frame, drag_info.grab_frame, "mouse zoom");
4590 temporal_zoom_to_frame (false, drag_info.grab_frame);
4592 temporal_zoom_step (false);
4593 center_screen (drag_info.grab_frame);
4601 Editor::reposition_zoom_rect (nframes_t start, nframes_t end)
4603 double x1 = frame_to_pixel (start);
4604 double x2 = frame_to_pixel (end);
4605 double y2 = full_canvas_height - 1.0;
4607 zoom_rect->property_x1() = x1;
4608 zoom_rect->property_y1() = 1.0;
4609 zoom_rect->property_x2() = x2;
4610 zoom_rect->property_y2() = y2;
4614 Editor::start_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event)
4616 drag_info.item = item;
4617 drag_info.motion_callback = &Editor::drag_rubberband_select;
4618 drag_info.finished_callback = &Editor::end_rubberband_select;
4620 start_grab (event, cross_hair_cursor);
4622 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4626 Editor::drag_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event)
4633 /* use a bigger drag threshold than the default */
4635 if (abs ((int) (drag_info.current_pointer_frame - drag_info.grab_frame)) < 8) {
4639 // if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4640 // snap_to (drag_info.current_pointer_frame);
4642 // if (drag_info.first_move) {
4643 // snap_to (drag_info.grab_frame);
4648 /* base start and end on initial click position */
4649 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4650 start = drag_info.current_pointer_frame;
4651 end = drag_info.grab_frame;
4653 end = drag_info.current_pointer_frame;
4654 start = drag_info.grab_frame;
4657 if (drag_info.current_pointer_y < drag_info.grab_y) {
4658 y1 = drag_info.current_pointer_y;
4659 y2 = drag_info.grab_y;
4662 y2 = drag_info.current_pointer_y;
4663 y1 = drag_info.grab_y;
4667 if (start != end || y1 != y2) {
4669 double x1 = frame_to_pixel (start);
4670 double x2 = frame_to_pixel (end);
4672 rubberband_rect->property_x1() = x1;
4673 rubberband_rect->property_y1() = y1;
4674 rubberband_rect->property_x2() = x2;
4675 rubberband_rect->property_y2() = y2;
4677 rubberband_rect->show();
4678 rubberband_rect->raise_to_top();
4680 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4681 drag_info.first_move = false;
4683 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4688 Editor::end_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event)
4690 if (!drag_info.first_move) {
4692 drag_rubberband_select (item, event);
4695 if (drag_info.current_pointer_y < drag_info.grab_y) {
4696 y1 = drag_info.current_pointer_y;
4697 y2 = drag_info.grab_y;
4700 y2 = drag_info.current_pointer_y;
4701 y1 = drag_info.grab_y;
4705 Selection::Operation op = Keyboard::selection_type (event->button.state);
4708 begin_reversible_command (_("select regions"));
4710 if (drag_info.grab_frame < drag_info.last_pointer_frame) {
4711 commit = select_all_within (drag_info.grab_frame, drag_info.last_pointer_frame, y1, y2, op);
4713 commit = select_all_within (drag_info.last_pointer_frame, drag_info.grab_frame, y1, y2, op);
4717 commit_reversible_command ();
4721 selection->clear_regions();
4722 selection->clear_points ();
4723 selection->clear_lines ();
4726 rubberband_rect->hide();
4731 Editor::mouse_rename_region (ArdourCanvas::Item* item, GdkEvent* event)
4733 using namespace Gtkmm2ext;
4735 ArdourPrompter prompter (false);
4737 prompter.set_prompt (_("Name for region:"));
4738 prompter.set_initial_text (clicked_regionview->region()->name());
4739 prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
4740 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
4741 prompter.show_all ();
4742 switch (prompter.run ()) {
4743 case Gtk::RESPONSE_ACCEPT:
4745 prompter.get_result(str);
4747 clicked_regionview->region()->set_name (str);
4755 Editor::start_time_fx (ArdourCanvas::Item* item, GdkEvent* event)
4757 drag_info.item = item;
4758 drag_info.motion_callback = &Editor::time_fx_motion;
4759 drag_info.finished_callback = &Editor::end_time_fx;
4763 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4767 Editor::time_fx_motion (ArdourCanvas::Item *item, GdkEvent* event)
4769 RegionView* rv = clicked_regionview;
4771 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4772 snap_to (drag_info.current_pointer_frame);
4775 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) {
4779 if (drag_info.current_pointer_frame > rv->region()->position()) {
4780 rv->get_time_axis_view().show_timestretch (rv->region()->position(), drag_info.current_pointer_frame);
4783 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4784 drag_info.first_move = false;
4786 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4790 Editor::end_time_fx (ArdourCanvas::Item* item, GdkEvent* event)
4792 clicked_regionview->get_time_axis_view().hide_timestretch ();
4794 if (drag_info.first_move) {
4798 nframes_t newlen = drag_info.last_pointer_frame - clicked_regionview->region()->position();
4799 float percentage = (float) ((double) newlen - (double) clicked_regionview->region()->length()) / ((double) newlen) * 100.0f;
4801 begin_reversible_command (_("timestretch"));
4803 if (run_timestretch (selection->regions, percentage) == 0) {
4804 session->commit_reversible_command ();
4809 Editor::mouse_brush_insert_region (RegionView* rv, nframes_t pos)
4811 /* no brushing without a useful snap setting */
4814 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
4817 switch (snap_mode) {
4819 return; /* can't work because it allows region to be placed anywhere */
4824 switch (snap_type) {
4827 case SnapToEditCursor:
4834 /* don't brush a copy over the original */
4836 if (pos == rv->region()->position()) {
4840 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*>(&arv->get_time_axis_view());
4842 if (atv == 0 || !atv->is_audio_track()) {
4846 Playlist* playlist = atv->playlist();
4847 double speed = atv->get_diskstream()->speed();
4849 XMLNode &before = playlist->get_state();
4850 playlist->add_region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (arv->audio_region())), (nframes_t) (pos * speed));
4851 XMLNode &after = playlist->get_state();
4852 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
4854 // playlist is frozen, so we have to update manually
4856 playlist->Modified(); /* EMIT SIGNAL */
4860 Editor::track_height_step_timeout ()
4863 struct timeval delta;
4865 gettimeofday (&now, 0);
4866 timersub (&now, &last_track_height_step_timestamp, &delta);
4868 if (delta.tv_sec * 1000000 + delta.tv_usec > 250000) { /* milliseconds */
4869 current_stepping_trackview = 0;