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/midi_region.h>
57 #include <ardour/dB.h>
58 #include <ardour/utils.h>
59 #include <ardour/region_factory.h>
66 using namespace ARDOUR;
70 using namespace Editing;
73 Editor::event_frame (GdkEvent* event, double* pcx, double* pcy)
87 switch (event->type) {
88 case GDK_BUTTON_RELEASE:
89 case GDK_BUTTON_PRESS:
90 case GDK_2BUTTON_PRESS:
91 case GDK_3BUTTON_PRESS:
92 track_canvas.w2c(event->button.x, event->button.y, *pcx, *pcy);
94 case GDK_MOTION_NOTIFY:
95 track_canvas.w2c(event->motion.x, event->motion.y, *pcx, *pcy);
97 case GDK_ENTER_NOTIFY:
98 case GDK_LEAVE_NOTIFY:
99 track_canvas.w2c(event->crossing.x, event->crossing.y, *pcx, *pcy);
102 case GDK_KEY_RELEASE:
103 // track_canvas.w2c(event->key.x, event->key.y, *pcx, *pcy);
106 warning << string_compose (_("Editor::event_frame() used on unhandled event type %1"), event->type) << endmsg;
110 /* note that pixel_to_frame() never returns less than zero, so even if the pixel
111 position is negative (as can be the case with motion events in particular),
112 the frame location is always positive.
115 return pixel_to_frame (*pcx);
119 Editor::mouse_mode_toggled (MouseMode m)
121 if (ignore_mouse_mode_toggle) {
127 if (mouse_select_button.get_active()) {
133 if (mouse_move_button.get_active()) {
139 if (mouse_gain_button.get_active()) {
145 if (mouse_zoom_button.get_active()) {
151 if (mouse_timefx_button.get_active()) {
157 if (mouse_audition_button.get_active()) {
168 Editor::set_mouse_mode (MouseMode m, bool force)
170 if (drag_info.item) {
174 if (!force && m == mouse_mode) {
182 if (mouse_mode != MouseRange) {
184 /* in all modes except range, hide the range selection,
185 show the object (region) selection.
188 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
189 (*i)->set_should_show_selection (true);
191 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
192 (*i)->hide_selection ();
198 in range mode,show the range selection.
201 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
202 if ((*i)->get_selected()) {
203 (*i)->show_selection (selection->time);
208 /* XXX the hack of unsetting all other buttongs should go
209 away once GTK2 allows us to use regular radio buttons drawn like
210 normal buttons, rather than my silly GroupedButton hack.
213 ignore_mouse_mode_toggle = true;
215 switch (mouse_mode) {
217 mouse_select_button.set_active (true);
218 current_canvas_cursor = selector_cursor;
222 mouse_move_button.set_active (true);
223 current_canvas_cursor = grabber_cursor;
227 mouse_gain_button.set_active (true);
228 current_canvas_cursor = cross_hair_cursor;
232 mouse_zoom_button.set_active (true);
233 current_canvas_cursor = zoom_cursor;
237 mouse_timefx_button.set_active (true);
238 current_canvas_cursor = time_fx_cursor; // just use playhead
242 mouse_audition_button.set_active (true);
243 current_canvas_cursor = speaker_cursor;
247 ignore_mouse_mode_toggle = false;
250 track_canvas.get_window()->set_cursor(*current_canvas_cursor);
255 Editor::step_mouse_mode (bool next)
257 switch (current_mouse_mode()) {
259 if (next) set_mouse_mode (MouseRange);
260 else set_mouse_mode (MouseTimeFX);
264 if (next) set_mouse_mode (MouseZoom);
265 else set_mouse_mode (MouseObject);
269 if (next) set_mouse_mode (MouseGain);
270 else set_mouse_mode (MouseRange);
274 if (next) set_mouse_mode (MouseTimeFX);
275 else set_mouse_mode (MouseZoom);
279 if (next) set_mouse_mode (MouseAudition);
280 else set_mouse_mode (MouseGain);
284 if (next) set_mouse_mode (MouseObject);
285 else set_mouse_mode (MouseTimeFX);
291 Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
297 /* in object/audition/timefx mode, any button press sets
298 the selection if the object can be selected. this is a
299 bit of hack, because we want to avoid this if the
300 mouse operation is a region alignment.
302 note: not dbl-click or triple-click
305 if (((mouse_mode != MouseObject) &&
306 (mouse_mode != MouseAudition || item_type != RegionItem) &&
307 (mouse_mode != MouseTimeFX || item_type != RegionItem)) ||
308 (event->type != GDK_BUTTON_PRESS && event->type != GDK_BUTTON_RELEASE || event->button.button > 3)) {
313 Selection::Operation op = Keyboard::selection_type (event->button.state);
314 bool press = (event->type == GDK_BUTTON_PRESS);
316 begin_reversible_command (_("select on click"));
320 c1 = set_selected_track_from_click (press, op, true, true);
321 c2 = set_selected_regionview_from_click (press, op, true);
325 case RegionViewNameHighlight:
327 c1 = set_selected_track_from_click (press, op, true, true);
328 c2 = set_selected_regionview_from_click (press, op, true);
332 case GainAutomationControlPointItem:
333 case PanAutomationControlPointItem:
334 case RedirectAutomationControlPointItem:
335 c1 = set_selected_track_from_click (press, op, true, true);
336 c2 = set_selected_control_point_from_click (press, op, false);
341 commit = set_selected_track_from_click (press, op, true, true);
344 case AutomationTrackItem:
345 commit = set_selected_track_from_click (press, op, true, true);
352 #define SELECT_TRACK_FROM_CANVAS_IN_RANGE_MODE
353 #ifdef SELECT_TRACK_FROM_CANVAS_IN_RANGE_MODE
354 /* in range mode, button 1/2/3 press potentially selects a track */
356 if (mouse_mode == MouseRange &&
357 event->type == GDK_BUTTON_PRESS &&
358 event->button.button <= 3) {
363 case AutomationTrackItem:
364 commit = set_selected_track_from_click (press, op, true, true);
373 commit_reversible_command ();
378 Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
380 jack_nframes_t where = event_frame (event, 0, 0);
382 track_canvas.grab_focus();
384 if (session && session->actively_recording()) {
388 button_selection (item, event, item_type);
390 if (drag_info.item == 0 &&
391 (Keyboard::is_delete_event (&event->button) ||
392 Keyboard::is_context_menu_event (&event->button) ||
393 Keyboard::is_edit_event (&event->button))) {
395 /* handled by button release */
399 switch (event->button.button) {
402 if (event->type == GDK_BUTTON_PRESS) {
404 if (drag_info.item) {
405 drag_info.item->ungrab (event->button.time);
408 /* single mouse clicks on any of these item types operate
409 independent of mouse mode, mostly because they are
410 not on the main track canvas or because we want
416 case PlayheadCursorItem:
417 start_cursor_grab (item, event);
421 if (Keyboard::modifier_state_equals (event->button.state,
422 Keyboard::ModifierMask(Keyboard::Control|Keyboard::Shift))) {
423 hide_marker (item, event);
425 start_marker_grab (item, event);
429 case TempoMarkerItem:
430 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
431 start_tempo_marker_copy_grab (item, event);
433 start_tempo_marker_grab (item, event);
437 case MeterMarkerItem:
438 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
439 start_meter_marker_copy_grab (item, event);
441 start_meter_marker_grab (item, event);
451 case RangeMarkerBarItem:
452 start_range_markerbar_op (item, event, CreateRangeMarker);
456 case TransportMarkerBarItem:
457 start_range_markerbar_op (item, event, CreateTransportMarker);
466 switch (mouse_mode) {
469 case StartSelectionTrimItem:
470 start_selection_op (item, event, SelectionStartTrim);
473 case EndSelectionTrimItem:
474 start_selection_op (item, event, SelectionEndTrim);
478 if (Keyboard::modifier_state_contains
479 (event->button.state, Keyboard::ModifierMask(Keyboard::Alt))) {
480 // contains and not equals because I can't use alt as a modifier alone.
481 start_selection_grab (item, event);
482 } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
483 /* grab selection for moving */
484 start_selection_op (item, event, SelectionMove);
487 /* this was debated, but decided the more common action was to
488 make a new selection */
489 start_selection_op (item, event, CreateSelection);
494 start_selection_op (item, event, CreateSelection);
500 if (Keyboard::modifier_state_contains (event->button.state,
501 Keyboard::ModifierMask(Keyboard::Control|Keyboard::Alt))
502 && event->type == GDK_BUTTON_PRESS) {
504 start_rubberband_select (item, event);
506 } else if (event->type == GDK_BUTTON_PRESS) {
509 case FadeInHandleItem:
510 start_fade_in_grab (item, event);
513 case FadeOutHandleItem:
514 start_fade_out_grab (item, event);
518 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
519 start_region_copy_grab (item, event);
520 } else if (Keyboard::the_keyboard().key_is_down (GDK_b)) {
521 start_region_brush_grab (item, event);
523 start_region_grab (item, event);
527 case RegionViewNameHighlight:
528 start_trim (item, event);
533 /* rename happens on edit clicks */
534 start_trim (clicked_regionview->get_name_highlight(), event);
538 case GainAutomationControlPointItem:
539 case PanAutomationControlPointItem:
540 case RedirectAutomationControlPointItem:
541 start_control_point_grab (item, event);
545 case GainAutomationLineItem:
546 case PanAutomationLineItem:
547 case RedirectAutomationLineItem:
548 start_line_grab_from_line (item, event);
553 case AutomationTrackItem:
554 start_rubberband_select (item, event);
557 /* <CMT Additions> */
558 case ImageFrameHandleStartItem:
559 imageframe_start_handle_op(item, event) ;
562 case ImageFrameHandleEndItem:
563 imageframe_end_handle_op(item, event) ;
566 case MarkerViewHandleStartItem:
567 markerview_item_start_handle_op(item, event) ;
570 case MarkerViewHandleEndItem:
571 markerview_item_end_handle_op(item, event) ;
574 /* </CMT Additions> */
576 /* <CMT Additions> */
578 start_markerview_grab(item, event) ;
581 start_imageframe_grab(item, event) ;
583 /* </CMT Additions> */
599 // start_line_grab_from_regionview (item, event);
602 case GainControlPointItem:
603 start_control_point_grab (item, event);
607 start_line_grab_from_line (item, event);
610 case GainAutomationControlPointItem:
611 case PanAutomationControlPointItem:
612 case RedirectAutomationControlPointItem:
613 start_control_point_grab (item, event);
624 case GainAutomationControlPointItem:
625 case PanAutomationControlPointItem:
626 case RedirectAutomationControlPointItem:
627 start_control_point_grab (item, event);
630 case GainAutomationLineItem:
631 case PanAutomationLineItem:
632 case RedirectAutomationLineItem:
633 start_line_grab_from_line (item, event);
637 // XXX need automation mode to identify which
639 // start_line_grab_from_regionview (item, event);
649 if (event->type == GDK_BUTTON_PRESS) {
650 start_mouse_zoom (item, event);
657 if (item_type == RegionItem) {
658 start_time_fx (item, event);
663 /* handled in release */
672 switch (mouse_mode) {
674 if (event->type == GDK_BUTTON_PRESS) {
677 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
678 start_region_copy_grab (item, event);
680 start_region_grab (item, event);
684 case GainAutomationControlPointItem:
685 case PanAutomationControlPointItem:
686 case RedirectAutomationControlPointItem:
687 start_control_point_grab (item, event);
698 case RegionViewNameHighlight:
699 start_trim (item, event);
704 start_trim (clicked_regionview->get_name_highlight(), event);
715 if (event->type == GDK_BUTTON_PRESS) {
716 /* relax till release */
723 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
724 temporal_zoom_session();
726 temporal_zoom_to_frame (true, event_frame(event));
741 switch (mouse_mode) {
743 //temporal_zoom_to_frame (true, where);
744 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
745 temporal_zoom_to_frame (true, where);
748 temporal_zoom_step (true);
753 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::Alt))) {
754 scroll_backward (0.6f);
757 else if (Keyboard::no_modifier_keys_pressed (&event->button)) {
758 scroll_tracks_up_line ();
760 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
761 if (clicked_axisview) {
762 if (!current_stepping_trackview) {
763 step_timeout = Glib::signal_timeout().connect (mem_fun(*this, &Editor::track_height_step_timeout), 500);
764 current_stepping_trackview = clicked_axisview;
766 gettimeofday (&last_track_height_step_timestamp, 0);
767 current_stepping_trackview->step_height (true);
770 else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
771 temporal_zoom_to_frame (true, where);
778 switch (mouse_mode) {
780 // temporal_zoom_to_frame (false, where);
781 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
782 temporal_zoom_to_frame (false, where);
785 temporal_zoom_step (false);
790 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::Alt))) {
791 scroll_forward (0.6f);
794 else if (Keyboard::no_modifier_keys_pressed (&event->button)) {
795 scroll_tracks_down_line ();
797 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
798 if (clicked_axisview) {
799 if (!current_stepping_trackview) {
800 step_timeout = Glib::signal_timeout().connect (mem_fun(*this, &Editor::track_height_step_timeout), 500);
801 current_stepping_trackview = clicked_axisview;
803 gettimeofday (&last_track_height_step_timestamp, 0);
804 current_stepping_trackview->step_height (false);
806 } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
807 temporal_zoom_to_frame (false, where);
822 Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
824 jack_nframes_t where = event_frame (event, 0, 0);
826 /* no action if we're recording */
828 if (session && session->actively_recording()) {
832 /* first, see if we're finishing a drag ... */
834 if (drag_info.item) {
835 if (end_grab (item, event)) {
836 /* grab dragged, so do nothing else */
841 button_selection (item, event, item_type);
843 /* edit events get handled here */
845 if (drag_info.item == 0 && Keyboard::is_edit_event (&event->button)) {
851 case TempoMarkerItem:
852 edit_tempo_marker (item);
855 case MeterMarkerItem:
856 edit_meter_marker (item);
860 if (clicked_regionview->name_active()) {
861 return mouse_rename_region (item, event);
871 /* context menu events get handled here */
873 if (Keyboard::is_context_menu_event (&event->button)) {
875 if (drag_info.item == 0) {
877 /* no matter which button pops up the context menu, tell the menu
878 widget to use button 1 to drive menu selection.
883 case FadeInHandleItem:
885 case FadeOutHandleItem:
886 popup_fade_context_menu (1, event->button.time, item, item_type);
890 popup_track_context_menu (1, event->button.time, item_type, false, where);
894 case RegionViewNameHighlight:
896 popup_track_context_menu (1, event->button.time, item_type, false, where);
900 popup_track_context_menu (1, event->button.time, item_type, true, where);
903 case AutomationTrackItem:
904 popup_track_context_menu (1, event->button.time, item_type, false, where);
908 case RangeMarkerBarItem:
909 case TransportMarkerBarItem:
912 popup_ruler_menu (pixel_to_frame(event->button.x), item_type);
916 marker_context_menu (&event->button, item);
919 case TempoMarkerItem:
920 tm_marker_context_menu (&event->button, item);
923 case MeterMarkerItem:
924 tm_marker_context_menu (&event->button, item);
927 case CrossfadeViewItem:
928 popup_track_context_menu (1, event->button.time, item_type, false, where);
931 /* <CMT Additions> */
933 popup_imageframe_edit_menu(1, event->button.time, item, true) ;
935 case ImageFrameTimeAxisItem:
936 popup_imageframe_edit_menu(1, event->button.time, item, false) ;
939 popup_marker_time_axis_edit_menu(1, event->button.time, item, true) ;
941 case MarkerTimeAxisItem:
942 popup_marker_time_axis_edit_menu(1, event->button.time, item, false) ;
944 /* <CMT Additions> */
955 /* delete events get handled here */
957 if (drag_info.item == 0 && Keyboard::is_delete_event (&event->button)) {
960 case TempoMarkerItem:
961 remove_tempo_marker (item);
964 case MeterMarkerItem:
965 remove_meter_marker (item);
969 remove_marker (*item, event);
973 if (mouse_mode == MouseObject) {
974 remove_clicked_region ();
978 case GainControlPointItem:
979 if (mouse_mode == MouseGain) {
980 remove_gain_control_point (item, event);
984 case GainAutomationControlPointItem:
985 case PanAutomationControlPointItem:
986 case RedirectAutomationControlPointItem:
987 remove_control_point (item, event);
996 switch (event->button.button) {
1000 /* see comments in button_press_handler */
1001 case EditCursorItem:
1002 case PlayheadCursorItem:
1005 case GainAutomationLineItem:
1006 case PanAutomationLineItem:
1007 case RedirectAutomationLineItem:
1008 case StartSelectionTrimItem:
1009 case EndSelectionTrimItem:
1013 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1014 snap_to (where, 0, true);
1016 mouse_add_new_marker (where);
1020 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1023 mouse_add_new_tempo_event (where);
1027 mouse_add_new_meter_event (pixel_to_frame (event->button.x));
1035 switch (mouse_mode) {
1037 switch (item_type) {
1038 case AutomationTrackItem:
1039 dynamic_cast<AutomationTimeAxisView*>(clicked_axisview)->add_automation_event
1053 // Gain only makes sense for audio regions
1054 if ( ! dynamic_cast<AudioRegionView*>(clicked_regionview))
1057 switch (item_type) {
1059 dynamic_cast<AudioRegionView*>(clicked_regionview)->add_gain_point_event (item, event);
1063 case AutomationTrackItem:
1064 dynamic_cast<AutomationTimeAxisView*>(clicked_axisview)->
1065 add_automation_event (item, event, where, event->button.y);
1074 switch (item_type) {
1076 audition_selected_region ();
1093 switch (mouse_mode) {
1096 switch (item_type) {
1098 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
1100 } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::ModifierMask (Keyboard::Shift|Keyboard::Alt))) {
1103 // Button2 click is unused
1116 // x_style_paste (where, 1.0);
1136 Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
1142 switch (item_type) {
1143 case GainControlPointItem:
1144 if (mouse_mode == MouseGain) {
1145 cp = static_cast<ControlPoint*>(item->get_data ("control_point"));
1146 cp->set_visible (true);
1150 at_y = cp->get_y ();
1151 cp->item->i2w (at_x, at_y);
1155 fraction = 1.0 - (cp->get_y() / cp->line.height());
1157 set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y);
1158 show_verbose_canvas_cursor ();
1160 if (is_drawable()) {
1161 track_canvas.get_window()->set_cursor (*fader_cursor);
1166 case GainAutomationControlPointItem:
1167 case PanAutomationControlPointItem:
1168 case RedirectAutomationControlPointItem:
1169 cp = static_cast<ControlPoint*>(item->get_data ("control_point"));
1170 cp->set_visible (true);
1174 at_y = cp->get_y ();
1175 cp->item->i2w (at_x, at_y);
1179 fraction = 1.0 - (cp->get_y() / cp->line.height());
1181 set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y);
1182 show_verbose_canvas_cursor ();
1184 if (is_drawable()) {
1185 track_canvas.get_window()->set_cursor (*fader_cursor);
1190 if (mouse_mode == MouseGain) {
1191 ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
1193 line->property_fill_color_rgba() = color_map[cEnteredGainLine];
1194 if (is_drawable()) {
1195 track_canvas.get_window()->set_cursor (*fader_cursor);
1200 case GainAutomationLineItem:
1201 case RedirectAutomationLineItem:
1202 case PanAutomationLineItem:
1204 ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
1206 line->property_fill_color_rgba() = color_map[cEnteredAutomationLine];
1208 if (is_drawable()) {
1209 track_canvas.get_window()->set_cursor (*fader_cursor);
1213 case RegionViewNameHighlight:
1214 if (is_drawable() && mouse_mode == MouseObject) {
1215 track_canvas.get_window()->set_cursor (*trimmer_cursor);
1219 case StartSelectionTrimItem:
1220 case EndSelectionTrimItem:
1221 /* <CMT Additions> */
1222 case ImageFrameHandleStartItem:
1223 case ImageFrameHandleEndItem:
1224 case MarkerViewHandleStartItem:
1225 case MarkerViewHandleEndItem:
1226 /* </CMT Additions> */
1228 if (is_drawable()) {
1229 track_canvas.get_window()->set_cursor (*trimmer_cursor);
1233 case EditCursorItem:
1234 case PlayheadCursorItem:
1235 if (is_drawable()) {
1236 track_canvas.get_window()->set_cursor (*grabber_cursor);
1240 case RegionViewName:
1242 /* when the name is not an active item, the entire name highlight is for trimming */
1244 if (!reinterpret_cast<RegionView *> (item->get_data ("regionview"))->name_active()) {
1245 if (mouse_mode == MouseObject && is_drawable()) {
1246 track_canvas.get_window()->set_cursor (*trimmer_cursor);
1252 case AutomationTrackItem:
1253 if (is_drawable()) {
1254 Gdk::Cursor *cursor;
1255 switch (mouse_mode) {
1257 cursor = selector_cursor;
1260 cursor = zoom_cursor;
1263 cursor = cross_hair_cursor;
1267 track_canvas.get_window()->set_cursor (*cursor);
1269 AutomationTimeAxisView* atv;
1270 if ((atv = static_cast<AutomationTimeAxisView*>(item->get_data ("trackview"))) != 0) {
1271 clear_entered_track = false;
1272 set_entered_track (atv);
1278 case RangeMarkerBarItem:
1279 case TransportMarkerBarItem:
1282 if (is_drawable()) {
1283 time_canvas.get_window()->set_cursor (*timebar_cursor);
1288 if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
1291 marker->set_color_rgba (color_map[cEnteredMarker]);
1293 case MeterMarkerItem:
1294 case TempoMarkerItem:
1295 if (is_drawable()) {
1296 time_canvas.get_window()->set_cursor (*timebar_cursor);
1299 case FadeInHandleItem:
1300 case FadeOutHandleItem:
1301 if (mouse_mode == MouseObject) {
1302 ArdourCanvas::SimpleRect *rect = dynamic_cast<ArdourCanvas::SimpleRect *> (item);
1304 rect->property_fill_color_rgba() = 0;
1305 rect->property_outline_pixels() = 1;
1314 /* second pass to handle entered track status in a comprehensible way.
1317 switch (item_type) {
1319 case GainAutomationLineItem:
1320 case RedirectAutomationLineItem:
1321 case PanAutomationLineItem:
1322 case GainControlPointItem:
1323 case GainAutomationControlPointItem:
1324 case PanAutomationControlPointItem:
1325 case RedirectAutomationControlPointItem:
1326 /* these do not affect the current entered track state */
1327 clear_entered_track = false;
1330 case AutomationTrackItem:
1331 /* handled above already */
1335 set_entered_track (0);
1343 Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
1352 switch (item_type) {
1353 case GainControlPointItem:
1354 case GainAutomationControlPointItem:
1355 case PanAutomationControlPointItem:
1356 case RedirectAutomationControlPointItem:
1357 cp = reinterpret_cast<ControlPoint*>(item->get_data ("control_point"));
1358 if (cp->line.npoints() > 1) {
1359 if (!cp->selected) {
1360 cp->set_visible (false);
1364 if (is_drawable()) {
1365 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
1368 hide_verbose_canvas_cursor ();
1371 case RegionViewNameHighlight:
1372 case StartSelectionTrimItem:
1373 case EndSelectionTrimItem:
1374 case EditCursorItem:
1375 case PlayheadCursorItem:
1376 /* <CMT Additions> */
1377 case ImageFrameHandleStartItem:
1378 case ImageFrameHandleEndItem:
1379 case MarkerViewHandleStartItem:
1380 case MarkerViewHandleEndItem:
1381 /* </CMT Additions> */
1382 if (is_drawable()) {
1383 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
1388 case GainAutomationLineItem:
1389 case RedirectAutomationLineItem:
1390 case PanAutomationLineItem:
1391 al = reinterpret_cast<AutomationLine*> (item->get_data ("line"));
1393 ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
1395 line->property_fill_color_rgba() = al->get_line_color();
1397 if (is_drawable()) {
1398 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
1402 case RegionViewName:
1403 /* see enter_handler() for notes */
1404 if (!reinterpret_cast<RegionView *> (item->get_data ("regionview"))->name_active()) {
1405 if (is_drawable() && mouse_mode == MouseObject) {
1406 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
1411 case RangeMarkerBarItem:
1412 case TransportMarkerBarItem:
1416 if (is_drawable()) {
1417 time_canvas.get_window()->set_cursor (*timebar_cursor);
1422 if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
1425 loc = find_location_from_marker (marker, is_start);
1426 if (loc) location_flags_changed (loc, this);
1428 case MeterMarkerItem:
1429 case TempoMarkerItem:
1431 if (is_drawable()) {
1432 time_canvas.get_window()->set_cursor (*timebar_cursor);
1437 case FadeInHandleItem:
1438 case FadeOutHandleItem:
1439 rv = static_cast<RegionView*>(item->get_data ("regionview"));
1441 ArdourCanvas::SimpleRect *rect = dynamic_cast<ArdourCanvas::SimpleRect *> (item);
1443 rect->property_fill_color_rgba() = rv->get_fill_color();
1444 rect->property_outline_pixels() = 0;
1449 case AutomationTrackItem:
1450 if (is_drawable()) {
1451 track_canvas.get_window()->set_cursor (*current_canvas_cursor);
1452 clear_entered_track = true;
1453 Glib::signal_idle().connect (mem_fun(*this, &Editor::left_automation_track));
1465 Editor::left_automation_track ()
1467 if (clear_entered_track) {
1468 set_entered_track (0);
1469 clear_entered_track = false;
1475 Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type, bool from_autoscroll)
1479 /* We call this so that MOTION_NOTIFY events continue to be
1480 delivered to the canvas. We need to do this because we set
1481 Gdk::POINTER_MOTION_HINT_MASK on the canvas. This reduces
1482 the density of the events, at the expense of a round-trip
1483 to the server. Given that this will mostly occur on cases
1484 where DISPLAY = :0.0, and given the cost of what the motion
1485 event might do, its a good tradeoff.
1488 track_canvas.get_pointer (x, y);
1490 if (current_stepping_trackview) {
1491 /* don't keep the persistent stepped trackview if the mouse moves */
1492 current_stepping_trackview = 0;
1493 step_timeout.disconnect ();
1496 if (session && session->actively_recording()) {
1497 /* Sorry. no dragging stuff around while we record */
1501 drag_info.item_type = item_type;
1502 drag_info.current_pointer_frame = event_frame (event, &drag_info.current_pointer_x,
1503 &drag_info.current_pointer_y);
1505 if (!from_autoscroll && drag_info.item) {
1506 /* item != 0 is the best test i can think of for dragging.
1508 if (!drag_info.move_threshold_passed) {
1510 drag_info.move_threshold_passed = (abs ((int) (drag_info.current_pointer_x - drag_info.grab_x)) > 4);
1512 // and change the initial grab loc/frame if this drag info wants us to
1514 if (drag_info.want_move_threshold && drag_info.move_threshold_passed) {
1515 drag_info.grab_frame = drag_info.current_pointer_frame;
1516 drag_info.grab_x = drag_info.current_pointer_x;
1517 drag_info.grab_y = drag_info.current_pointer_y;
1518 drag_info.last_pointer_frame = drag_info.grab_frame;
1519 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
1524 switch (item_type) {
1525 case PlayheadCursorItem:
1526 case EditCursorItem:
1528 case GainControlPointItem:
1529 case RedirectAutomationControlPointItem:
1530 case GainAutomationControlPointItem:
1531 case PanAutomationControlPointItem:
1532 case TempoMarkerItem:
1533 case MeterMarkerItem:
1534 case RegionViewNameHighlight:
1535 case StartSelectionTrimItem:
1536 case EndSelectionTrimItem:
1539 case RedirectAutomationLineItem:
1540 case GainAutomationLineItem:
1541 case PanAutomationLineItem:
1542 case FadeInHandleItem:
1543 case FadeOutHandleItem:
1544 /* <CMT Additions> */
1545 case ImageFrameHandleStartItem:
1546 case ImageFrameHandleEndItem:
1547 case MarkerViewHandleStartItem:
1548 case MarkerViewHandleEndItem:
1549 /* </CMT Additions> */
1550 if (drag_info.item && (event->motion.state & Gdk::BUTTON1_MASK ||
1551 (event->motion.state & Gdk::BUTTON2_MASK))) {
1552 if (!from_autoscroll) {
1553 maybe_autoscroll (event);
1555 (this->*(drag_info.motion_callback)) (item, event);
1564 switch (mouse_mode) {
1569 if (drag_info.item && (event->motion.state & GDK_BUTTON1_MASK ||
1570 (event->motion.state & GDK_BUTTON2_MASK))) {
1571 if (!from_autoscroll) {
1572 maybe_autoscroll (event);
1574 (this->*(drag_info.motion_callback)) (item, event);
1585 track_canvas_motion (event);
1586 // drag_info.last_pointer_frame = drag_info.current_pointer_frame;
1594 Editor::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
1596 if (drag_info.item == 0) {
1597 fatal << _("programming error: start_grab called without drag item") << endmsg;
1603 cursor = grabber_cursor;
1606 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
1608 if (event->button.button == 2) {
1609 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Alt)) {
1610 drag_info.y_constrained = true;
1611 drag_info.x_constrained = false;
1613 drag_info.y_constrained = false;
1614 drag_info.x_constrained = true;
1617 drag_info.x_constrained = false;
1618 drag_info.y_constrained = false;
1621 drag_info.grab_frame = event_frame(event, &drag_info.grab_x, &drag_info.grab_y);
1622 drag_info.last_pointer_frame = drag_info.grab_frame;
1623 drag_info.current_pointer_frame = drag_info.grab_frame;
1624 drag_info.current_pointer_x = drag_info.grab_x;
1625 drag_info.current_pointer_y = drag_info.grab_y;
1626 drag_info.cumulative_x_drag = 0;
1627 drag_info.cumulative_y_drag = 0;
1628 drag_info.first_move = true;
1629 drag_info.move_threshold_passed = false;
1630 drag_info.want_move_threshold = false;
1631 drag_info.pointer_frame_offset = 0;
1632 drag_info.brushing = false;
1633 drag_info.copied_location = 0;
1635 drag_info.item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
1637 event->button.time);
1639 if (session && session->transport_rolling()) {
1640 drag_info.was_rolling = true;
1642 drag_info.was_rolling = false;
1645 switch (snap_type) {
1646 case SnapToRegionStart:
1647 case SnapToRegionEnd:
1648 case SnapToRegionSync:
1649 case SnapToRegionBoundary:
1650 build_region_boundary_cache ();
1658 Editor::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t time)
1660 drag_info.item->ungrab (0);
1661 drag_info.item = new_item;
1664 cursor = grabber_cursor;
1667 drag_info.item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK, *cursor, time);
1671 Editor::end_grab (ArdourCanvas::Item* item, GdkEvent* event)
1673 bool did_drag = false;
1675 stop_canvas_autoscroll ();
1677 if (drag_info.item == 0) {
1681 drag_info.item->ungrab (event->button.time);
1683 if (drag_info.finished_callback) {
1684 (this->*(drag_info.finished_callback)) (item, event);
1687 did_drag = !drag_info.first_move;
1689 hide_verbose_canvas_cursor();
1692 drag_info.copy = false;
1693 drag_info.motion_callback = 0;
1694 drag_info.finished_callback = 0;
1695 drag_info.last_trackview = 0;
1696 drag_info.last_frame_position = 0;
1697 drag_info.grab_frame = 0;
1698 drag_info.last_pointer_frame = 0;
1699 drag_info.current_pointer_frame = 0;
1700 drag_info.brushing = false;
1702 if (drag_info.copied_location) {
1703 delete drag_info.copied_location;
1704 drag_info.copied_location = 0;
1711 Editor::set_edit_cursor (GdkEvent* event)
1713 jack_nframes_t pointer_frame = event_frame (event);
1715 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1716 if (snap_type != SnapToEditCursor) {
1717 snap_to (pointer_frame);
1721 edit_cursor->set_position (pointer_frame);
1722 edit_cursor_clock.set (pointer_frame);
1726 Editor::set_playhead_cursor (GdkEvent* event)
1728 jack_nframes_t pointer_frame = event_frame (event);
1730 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1731 snap_to (pointer_frame);
1735 session->request_locate (pointer_frame, session->transport_rolling());
1740 Editor::start_fade_in_grab (ArdourCanvas::Item* item, GdkEvent* event)
1742 drag_info.item = item;
1743 drag_info.motion_callback = &Editor::fade_in_drag_motion_callback;
1744 drag_info.finished_callback = &Editor::fade_in_drag_finished_callback;
1748 if ((drag_info.data = (item->get_data ("regionview"))) == 0) {
1749 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1753 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1755 drag_info.pointer_frame_offset = drag_info.grab_frame - ((jack_nframes_t) arv->audio_region().fade_in().back()->when + arv->region().position());
1759 Editor::fade_in_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
1761 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1763 jack_nframes_t fade_length;
1765 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1766 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1772 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1776 if (pos < (arv->region().position() + 64)) {
1777 fade_length = 64; // this should be a minimum defined somewhere
1778 } else if (pos > arv->region().last_frame()) {
1779 fade_length = arv->region().length();
1781 fade_length = pos - arv->region().position();
1784 arv->reset_fade_in_shape_width (fade_length);
1786 show_verbose_duration_cursor (arv->region().position(), arv->region().position() + fade_length, 10);
1788 drag_info.first_move = false;
1792 Editor::fade_in_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
1794 if (drag_info.first_move) return;
1796 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1798 jack_nframes_t fade_length;
1800 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1801 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1807 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1811 if (pos < (arv->region().position() + 64)) {
1812 fade_length = 64; // this should be a minimum defined somewhere
1814 else if (pos > arv->region().last_frame()) {
1815 fade_length = arv->region().length();
1818 fade_length = pos - arv->region().position();
1821 begin_reversible_command (_("change fade in length"));
1822 XMLNode &before = arv->audio_region().get_state();
1824 arv->audio_region().set_fade_in_length (fade_length);
1826 XMLNode &after = arv->audio_region().get_state();
1827 session->add_command(new MementoCommand<ARDOUR::AudioRegion>(arv->audio_region(),
1830 commit_reversible_command ();
1831 fade_in_drag_motion_callback (item, event);
1835 Editor::start_fade_out_grab (ArdourCanvas::Item* item, GdkEvent* event)
1837 drag_info.item = item;
1838 drag_info.motion_callback = &Editor::fade_out_drag_motion_callback;
1839 drag_info.finished_callback = &Editor::fade_out_drag_finished_callback;
1843 if ((drag_info.data = (item->get_data ("regionview"))) == 0) {
1844 fatal << _("programming error: fade out canvas item has no regionview data pointer!") << endmsg;
1848 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1850 drag_info.pointer_frame_offset = drag_info.grab_frame - (arv->region().length() - (jack_nframes_t) arv->audio_region().fade_out().back()->when + arv->region().position());
1854 Editor::fade_out_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
1856 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1858 jack_nframes_t fade_length;
1860 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1861 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1867 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1871 if (pos > (arv->region().last_frame() - 64)) {
1872 fade_length = 64; // this should really be a minimum fade defined somewhere
1874 else if (pos < arv->region().position()) {
1875 fade_length = arv->region().length();
1878 fade_length = arv->region().last_frame() - pos;
1881 arv->reset_fade_out_shape_width (fade_length);
1883 show_verbose_duration_cursor (arv->region().last_frame() - fade_length, arv->region().last_frame(), 10);
1885 drag_info.first_move = false;
1889 Editor::fade_out_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
1891 if (drag_info.first_move) return;
1893 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1895 jack_nframes_t fade_length;
1897 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1898 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1904 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1908 if (pos > (arv->region().last_frame() - 64)) {
1909 fade_length = 64; // this should really be a minimum fade defined somewhere
1911 else if (pos < arv->region().position()) {
1912 fade_length = arv->region().length();
1915 fade_length = arv->region().last_frame() - pos;
1918 begin_reversible_command (_("change fade out length"));
1919 XMLNode &before = arv->region().get_state();
1921 arv->audio_region().set_fade_out_length (fade_length);
1923 XMLNode &after = arv->region().get_state();
1924 session->add_command(new MementoCommand<ARDOUR::Region>(arv->region(), before, after));
1925 commit_reversible_command ();
1927 fade_out_drag_motion_callback (item, event);
1931 Editor::start_cursor_grab (ArdourCanvas::Item* item, GdkEvent* event)
1933 drag_info.item = item;
1934 drag_info.motion_callback = &Editor::cursor_drag_motion_callback;
1935 drag_info.finished_callback = &Editor::cursor_drag_finished_callback;
1939 if ((drag_info.data = (item->get_data ("cursor"))) == 0) {
1940 fatal << _("programming error: cursor canvas item has no cursor data pointer!") << endmsg;
1944 Cursor* cursor = (Cursor *) drag_info.data;
1946 if (session && cursor == playhead_cursor) {
1947 if (drag_info.was_rolling) {
1948 session->request_stop ();
1952 drag_info.pointer_frame_offset = drag_info.grab_frame - cursor->current_frame;
1954 show_verbose_time_cursor (cursor->current_frame, 10);
1958 Editor::cursor_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
1960 Cursor* cursor = (Cursor *) drag_info.data;
1961 jack_nframes_t adjusted_frame;
1963 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1964 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1970 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1971 if (cursor != edit_cursor || snap_type != SnapToEditCursor) {
1972 snap_to (adjusted_frame);
1976 if (adjusted_frame == drag_info.last_pointer_frame) return;
1978 cursor->set_position (adjusted_frame);
1980 if (cursor == edit_cursor) {
1981 edit_cursor_clock.set (cursor->current_frame);
1984 show_verbose_time_cursor (cursor->current_frame, 10);
1986 drag_info.last_pointer_frame = adjusted_frame;
1987 drag_info.first_move = false;
1991 Editor::cursor_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
1993 if (drag_info.first_move) return;
1995 cursor_drag_motion_callback (item, event);
1997 if (item == &playhead_cursor->canvas_item) {
1999 session->request_locate (playhead_cursor->current_frame, drag_info.was_rolling);
2001 } else if (item == &edit_cursor->canvas_item) {
2002 edit_cursor->set_position (edit_cursor->current_frame);
2003 edit_cursor_clock.set (edit_cursor->current_frame);
2008 Editor::update_marker_drag_item (Location *location)
2010 double x1 = frame_to_pixel (location->start());
2011 double x2 = frame_to_pixel (location->end());
2013 if (location->is_mark()) {
2014 marker_drag_line_points.front().set_x(x1);
2015 marker_drag_line_points.back().set_x(x1);
2016 marker_drag_line->property_points() = marker_drag_line_points;
2019 range_marker_drag_rect->property_x1() = x1;
2020 range_marker_drag_rect->property_x2() = x2;
2025 Editor::start_marker_grab (ArdourCanvas::Item* item, GdkEvent* event)
2029 if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
2030 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
2036 Location *location = find_location_from_marker (marker, is_start);
2038 drag_info.item = item;
2039 drag_info.data = marker;
2040 drag_info.motion_callback = &Editor::marker_drag_motion_callback;
2041 drag_info.finished_callback = &Editor::marker_drag_finished_callback;
2045 drag_info.copied_location = new Location (*location);
2046 drag_info.pointer_frame_offset = drag_info.grab_frame - (is_start ? location->start() : location->end());
2048 update_marker_drag_item (location);
2050 if (location->is_mark()) {
2051 marker_drag_line->show();
2052 marker_drag_line->raise_to_top();
2055 range_marker_drag_rect->show();
2056 range_marker_drag_rect->raise_to_top();
2059 if (is_start) show_verbose_time_cursor (location->start(), 10);
2060 else show_verbose_time_cursor (location->end(), 10);
2064 Editor::marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2066 jack_nframes_t f_delta;
2067 Marker* marker = (Marker *) drag_info.data;
2068 Location *real_location;
2069 Location *copy_location;
2071 bool move_both = false;
2074 jack_nframes_t newframe;
2075 if (drag_info.pointer_frame_offset <= (long) drag_info.current_pointer_frame) {
2076 newframe = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2082 jack_nframes_t next = newframe;
2084 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2085 snap_to (newframe, 0, true);
2088 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) {
2092 /* call this to find out if its the start or end */
2094 real_location = find_location_from_marker (marker, is_start);
2096 /* use the copy that we're "dragging" around */
2098 copy_location = drag_info.copied_location;
2100 f_delta = copy_location->end() - copy_location->start();
2102 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
2106 if (copy_location->is_mark()) {
2109 copy_location->set_start (newframe);
2113 if (is_start) { // start-of-range marker
2116 copy_location->set_start (newframe);
2117 copy_location->set_end (newframe + f_delta);
2118 } else if (newframe < copy_location->end()) {
2119 copy_location->set_start (newframe);
2121 snap_to (next, 1, true);
2122 copy_location->set_end (next);
2123 copy_location->set_start (newframe);
2126 } else { // end marker
2129 copy_location->set_end (newframe);
2130 copy_location->set_start (newframe - f_delta);
2131 } else if (newframe > copy_location->start()) {
2132 copy_location->set_end (newframe);
2134 } else if (newframe > 0) {
2135 snap_to (next, -1, true);
2136 copy_location->set_start (next);
2137 copy_location->set_end (newframe);
2142 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
2143 drag_info.first_move = false;
2145 update_marker_drag_item (copy_location);
2147 LocationMarkers* lm = find_location_markers (real_location);
2148 lm->set_position (copy_location->start(), copy_location->end());
2150 show_verbose_time_cursor (newframe, 10);
2154 Editor::marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2156 if (drag_info.first_move) {
2157 marker_drag_motion_callback (item, event);
2161 Marker* marker = (Marker *) drag_info.data;
2165 begin_reversible_command ( _("move marker") );
2166 XMLNode &before = session->locations()->get_state();
2168 Location * location = find_location_from_marker (marker, is_start);
2171 if (location->is_mark()) {
2172 location->set_start (drag_info.copied_location->start());
2174 location->set (drag_info.copied_location->start(), drag_info.copied_location->end());
2178 XMLNode &after = session->locations()->get_state();
2179 session->add_command(new MementoCommand<Locations>(*(session->locations()), before, after));
2180 commit_reversible_command ();
2182 marker_drag_line->hide();
2183 range_marker_drag_rect->hide();
2187 Editor::start_meter_marker_grab (ArdourCanvas::Item* item, GdkEvent* event)
2190 MeterMarker* meter_marker;
2192 if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
2193 fatal << _("programming error: meter marker canvas item has no marker object pointer!") << endmsg;
2197 meter_marker = dynamic_cast<MeterMarker*> (marker);
2199 MetricSection& section (meter_marker->meter());
2201 if (!section.movable()) {
2205 drag_info.item = item;
2206 drag_info.data = marker;
2207 drag_info.motion_callback = &Editor::meter_marker_drag_motion_callback;
2208 drag_info.finished_callback = &Editor::meter_marker_drag_finished_callback;
2212 drag_info.pointer_frame_offset = drag_info.grab_frame - meter_marker->meter().frame();
2214 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2218 Editor::start_meter_marker_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
2221 MeterMarker* meter_marker;
2223 if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
2224 fatal << _("programming error: meter marker canvas item has no marker object pointer!") << endmsg;
2228 meter_marker = dynamic_cast<MeterMarker*> (marker);
2230 // create a dummy marker for visual representation of moving the copy.
2231 // The actual copying is not done before we reach the finish callback.
2233 snprintf (name, sizeof(name), "%g/%g", meter_marker->meter().beats_per_bar(), meter_marker->meter().note_divisor ());
2234 MeterMarker* new_marker = new MeterMarker(*this, *meter_group, color_map[cMeterMarker], name,
2235 *new MeterSection(meter_marker->meter()));
2237 drag_info.item = &new_marker->the_item();
2238 drag_info.copy = true;
2239 drag_info.data = new_marker;
2240 drag_info.motion_callback = &Editor::meter_marker_drag_motion_callback;
2241 drag_info.finished_callback = &Editor::meter_marker_drag_finished_callback;
2245 drag_info.pointer_frame_offset = drag_info.grab_frame - meter_marker->meter().frame();
2247 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2251 Editor::meter_marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2253 MeterMarker* marker = (MeterMarker *) drag_info.data;
2254 jack_nframes_t adjusted_frame;
2256 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
2257 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2263 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2264 snap_to (adjusted_frame);
2267 if (adjusted_frame == drag_info.last_pointer_frame) return;
2269 marker->set_position (adjusted_frame);
2272 drag_info.last_pointer_frame = adjusted_frame;
2273 drag_info.first_move = false;
2275 show_verbose_time_cursor (adjusted_frame, 10);
2279 Editor::meter_marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2281 if (drag_info.first_move) return;
2283 meter_marker_drag_motion_callback (drag_info.item, event);
2285 MeterMarker* marker = (MeterMarker *) drag_info.data;
2288 TempoMap& map (session->tempo_map());
2289 map.bbt_time (drag_info.last_pointer_frame, when);
2291 if (drag_info.copy == true) {
2292 begin_reversible_command (_("copy meter mark"));
2293 XMLNode &before = map.get_state();
2294 map.add_meter (marker->meter(), when);
2295 XMLNode &after = map.get_state();
2296 session->add_command(new MementoCommand<TempoMap>(map, before, after));
2297 commit_reversible_command ();
2299 // delete the dummy marker we used for visual representation of copying.
2300 // a new visual marker will show up automatically.
2303 begin_reversible_command (_("move meter mark"));
2304 XMLNode &before = map.get_state();
2305 map.move_meter (marker->meter(), when);
2306 XMLNode &after = map.get_state();
2307 session->add_command(new MementoCommand<TempoMap>(map, before, after));
2308 commit_reversible_command ();
2313 Editor::start_tempo_marker_grab (ArdourCanvas::Item* item, GdkEvent* event)
2316 TempoMarker* tempo_marker;
2318 if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
2319 fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg;
2323 if ((tempo_marker = dynamic_cast<TempoMarker *> (marker)) == 0) {
2324 fatal << _("programming error: marker for tempo is not a tempo marker!") << endmsg;
2328 MetricSection& section (tempo_marker->tempo());
2330 if (!section.movable()) {
2334 drag_info.item = item;
2335 drag_info.data = marker;
2336 drag_info.motion_callback = &Editor::tempo_marker_drag_motion_callback;
2337 drag_info.finished_callback = &Editor::tempo_marker_drag_finished_callback;
2341 drag_info.pointer_frame_offset = drag_info.grab_frame - tempo_marker->tempo().frame();
2342 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2346 Editor::start_tempo_marker_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
2349 TempoMarker* tempo_marker;
2351 if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
2352 fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg;
2356 if ((tempo_marker = dynamic_cast<TempoMarker *> (marker)) == 0) {
2357 fatal << _("programming error: marker for tempo is not a tempo marker!") << endmsg;
2361 // create a dummy marker for visual representation of moving the copy.
2362 // The actual copying is not done before we reach the finish callback.
2364 snprintf (name, sizeof (name), "%.2f", tempo_marker->tempo().beats_per_minute());
2365 TempoMarker* new_marker = new TempoMarker(*this, *tempo_group, color_map[cTempoMarker], name,
2366 *new TempoSection(tempo_marker->tempo()));
2368 drag_info.item = &new_marker->the_item();
2369 drag_info.copy = true;
2370 drag_info.data = new_marker;
2371 drag_info.motion_callback = &Editor::tempo_marker_drag_motion_callback;
2372 drag_info.finished_callback = &Editor::tempo_marker_drag_finished_callback;
2376 drag_info.pointer_frame_offset = drag_info.grab_frame - tempo_marker->tempo().frame();
2378 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2382 Editor::tempo_marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2384 TempoMarker* marker = (TempoMarker *) drag_info.data;
2385 jack_nframes_t adjusted_frame;
2387 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
2388 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2394 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2395 snap_to (adjusted_frame);
2398 if (adjusted_frame == drag_info.last_pointer_frame) return;
2400 /* OK, we've moved far enough to make it worth actually move the thing. */
2402 marker->set_position (adjusted_frame);
2404 show_verbose_time_cursor (adjusted_frame, 10);
2406 drag_info.last_pointer_frame = adjusted_frame;
2407 drag_info.first_move = false;
2411 Editor::tempo_marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2413 if (drag_info.first_move) return;
2415 tempo_marker_drag_motion_callback (drag_info.item, event);
2417 TempoMarker* marker = (TempoMarker *) drag_info.data;
2420 TempoMap& map (session->tempo_map());
2421 map.bbt_time (drag_info.last_pointer_frame, when);
2423 if (drag_info.copy == true) {
2424 begin_reversible_command (_("copy tempo mark"));
2425 XMLNode &before = map.get_state();
2426 map.add_tempo (marker->tempo(), when);
2427 XMLNode &after = map.get_state();
2428 session->add_command (new MementoCommand<TempoMap>(map, before, after));
2429 commit_reversible_command ();
2431 // delete the dummy marker we used for visual representation of copying.
2432 // a new visual marker will show up automatically.
2435 begin_reversible_command (_("move tempo mark"));
2436 XMLNode &before = map.get_state();
2437 map.move_tempo (marker->tempo(), when);
2438 XMLNode &after = map.get_state();
2439 session->add_command (new MementoCommand<TempoMap>(map, before, after));
2440 commit_reversible_command ();
2445 Editor::remove_gain_control_point (ArdourCanvas::Item*item, GdkEvent* event)
2447 ControlPoint* control_point;
2449 if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
2450 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2454 // We shouldn't remove the first or last gain point
2455 if (control_point->line.is_last_point(*control_point) ||
2456 control_point->line.is_first_point(*control_point)) {
2460 control_point->line.remove_point (*control_point);
2464 Editor::remove_control_point (ArdourCanvas::Item*item, GdkEvent* event)
2466 ControlPoint* control_point;
2468 if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
2469 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2473 control_point->line.remove_point (*control_point);
2477 Editor::start_control_point_grab (ArdourCanvas::Item* item, GdkEvent* event)
2479 ControlPoint* control_point;
2481 if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
2482 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2486 drag_info.item = item;
2487 drag_info.data = control_point;
2488 drag_info.motion_callback = &Editor::control_point_drag_motion_callback;
2489 drag_info.finished_callback = &Editor::control_point_drag_finished_callback;
2491 start_grab (event, fader_cursor);
2493 control_point->line.start_drag (control_point, 0);
2495 float fraction = 1.0 - (control_point->get_y() / control_point->line.height());
2496 set_verbose_canvas_cursor (control_point->line.get_verbose_cursor_string (fraction),
2497 drag_info.current_pointer_x + 20, drag_info.current_pointer_y + 20);
2499 show_verbose_canvas_cursor ();
2503 Editor::control_point_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2505 ControlPoint* cp = reinterpret_cast<ControlPoint *> (drag_info.data);
2507 double cx = drag_info.current_pointer_x;
2508 double cy = drag_info.current_pointer_y;
2510 drag_info.cumulative_x_drag = cx - drag_info.grab_x ;
2511 drag_info.cumulative_y_drag = cy - drag_info.grab_y ;
2513 if (drag_info.x_constrained) {
2514 cx = drag_info.grab_x;
2516 if (drag_info.y_constrained) {
2517 cy = drag_info.grab_y;
2520 cp->line.parent_group().w2i (cx, cy);
2524 cy = min ((double) cp->line.height(), cy);
2526 //translate cx to frames
2527 jack_nframes_t cx_frames = unit_to_frame (cx);
2529 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && !drag_info.x_constrained) {
2530 snap_to (cx_frames);
2533 float fraction = 1.0 - (cy / cp->line.height());
2537 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
2543 cp->line.point_drag (*cp, cx_frames , fraction, push);
2545 set_verbose_canvas_cursor_text (cp->line.get_verbose_cursor_string (fraction));
2547 drag_info.first_move = false;
2551 Editor::control_point_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2553 ControlPoint* cp = reinterpret_cast<ControlPoint *> (drag_info.data);
2555 if (drag_info.first_move) {
2559 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
2560 reset_point_selection ();
2564 control_point_drag_motion_callback (item, event);
2566 cp->line.end_drag (cp);
2570 Editor::start_line_grab_from_regionview (ArdourCanvas::Item* item, GdkEvent* event)
2572 switch (mouse_mode) {
2574 assert(dynamic_cast<AudioRegionView*>(clicked_regionview));
2575 start_line_grab (dynamic_cast<AudioRegionView*>(clicked_regionview)->get_gain_line(), event);
2583 Editor::start_line_grab_from_line (ArdourCanvas::Item* item, GdkEvent* event)
2587 if ((al = reinterpret_cast<AutomationLine*> (item->get_data ("line"))) == 0) {
2588 fatal << _("programming error: line canvas item has no line pointer!") << endmsg;
2592 start_line_grab (al, event);
2596 Editor::start_line_grab (AutomationLine* line, GdkEvent* event)
2600 jack_nframes_t frame_within_region;
2602 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2606 cx = event->button.x;
2607 cy = event->button.y;
2608 line->parent_group().w2i (cx, cy);
2609 frame_within_region = (jack_nframes_t) floor (cx * frames_per_unit);
2611 if (!line->control_points_adjacent (frame_within_region, current_line_drag_info.before,
2612 current_line_drag_info.after)) {
2613 /* no adjacent points */
2617 drag_info.item = &line->grab_item();
2618 drag_info.data = line;
2619 drag_info.motion_callback = &Editor::line_drag_motion_callback;
2620 drag_info.finished_callback = &Editor::line_drag_finished_callback;
2622 start_grab (event, fader_cursor);
2624 double fraction = 1.0 - (cy / line->height());
2626 line->start_drag (0, fraction);
2628 set_verbose_canvas_cursor (line->get_verbose_cursor_string (fraction),
2629 drag_info.current_pointer_x + 20, drag_info.current_pointer_y + 20);
2630 show_verbose_canvas_cursor ();
2634 Editor::line_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2636 AutomationLine* line = reinterpret_cast<AutomationLine *> (drag_info.data);
2637 double cx = drag_info.current_pointer_x;
2638 double cy = drag_info.current_pointer_y;
2640 line->parent_group().w2i (cx, cy);
2643 fraction = 1.0 - (cy / line->height());
2647 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
2653 line->line_drag (current_line_drag_info.before, current_line_drag_info.after, fraction, push);
2655 set_verbose_canvas_cursor_text (line->get_verbose_cursor_string (fraction));
2659 Editor::line_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
2661 AutomationLine* line = reinterpret_cast<AutomationLine *> (drag_info.data);
2662 line_drag_motion_callback (item, event);
2667 Editor::start_region_grab (ArdourCanvas::Item* item, GdkEvent* event)
2669 if (selection->regions.empty() || clicked_regionview == 0) {
2673 drag_info.copy = false;
2674 drag_info.item = item;
2675 drag_info.data = clicked_regionview;
2676 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2677 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2682 TimeAxisView* tvp = clicked_axisview;
2683 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
2685 if (tv && tv->is_track()) {
2686 speed = tv->get_diskstream()->speed();
2689 drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region().position() / speed);
2690 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2691 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2692 // we want a move threshold
2693 drag_info.want_move_threshold = true;
2695 show_verbose_time_cursor (drag_info.last_frame_position, 10);
2697 begin_reversible_command (_("move region(s)"));
2701 Editor::start_region_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
2703 if (selection->regions.empty() || clicked_regionview == 0) {
2707 drag_info.copy = true;
2708 drag_info.item = item;
2709 drag_info.data = clicked_regionview;
2713 TimeAxisView* tv = &clicked_regionview->get_time_axis_view();
2714 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(tv);
2717 if (rtv && rtv->is_track()) {
2718 speed = rtv->get_diskstream()->speed();
2721 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2722 drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region().position() / speed);
2723 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2724 // we want a move threshold
2725 drag_info.want_move_threshold = true;
2726 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2727 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2731 Editor::start_region_brush_grab (ArdourCanvas::Item* item, GdkEvent* event)
2733 if (selection->regions.empty() || clicked_regionview == 0) {
2737 drag_info.copy = false;
2738 drag_info.item = item;
2739 drag_info.data = clicked_regionview;
2740 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2741 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2746 TimeAxisView* tvp = clicked_axisview;
2747 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
2749 if (tv && tv->is_track()) {
2750 speed = tv->get_diskstream()->speed();
2753 drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region().position() / speed);
2754 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2755 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2756 // we want a move threshold
2757 drag_info.want_move_threshold = true;
2758 drag_info.brushing = true;
2760 begin_reversible_command (_("Drag region brush"));
2764 Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
2768 RegionView* rv = reinterpret_cast<RegionView*> (drag_info.data);
2769 jack_nframes_t pending_region_position = 0;
2770 int32_t pointer_y_span = 0, canvas_pointer_y_span = 0, original_pointer_order;
2771 int32_t visible_y_high = 0, visible_y_low = 512; //high meaning higher numbered.. not the height on the screen
2772 bool clamp_y_axis = false;
2773 vector<int32_t> height_list(512) ;
2774 vector<int32_t>::iterator j;
2776 show_verbose_time_cursor (drag_info.last_frame_position, 10);
2778 if (drag_info.copy && drag_info.move_threshold_passed && drag_info.want_move_threshold) {
2780 drag_info.want_move_threshold = false; // don't copy again
2782 /* this is committed in the grab finished callback. */
2784 begin_reversible_command (_("Drag region copy"));
2786 /* duplicate the region(s) */
2788 vector<RegionView*> new_regionviews;
2790 set<Playlist*> affected_playlists;
2791 pair<set<Playlist*>::iterator,bool> insert_result;
2793 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
2798 Playlist* to_playlist = rv->region().playlist();
2799 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&rv->get_time_axis_view());
2801 insert_result = affected_playlists.insert (to_playlist);
2802 if (insert_result.second) {
2803 session->add_command (new MementoUndoCommand<Playlist>(*to_playlist, to_playlist->get_state()));
2806 latest_regionview = 0;
2808 sigc::connection c = rtv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
2810 /* create a new region with the same name. */
2812 // FIXME: ew. need a (virtual) Region::duplicate() or something?
2813 Region* newregion = NULL;
2814 if (dynamic_cast<AudioRegion*>(&rv->region()))
2815 newregion = new AudioRegion (dynamic_cast<AudioRegion&>(rv->region()));
2816 else if (dynamic_cast<MidiRegion*>(&rv->region()))
2817 newregion = new MidiRegion (dynamic_cast<MidiRegion&>(rv->region()));
2820 /* if the original region was locked, we don't care */
2822 newregion->set_locked (false);
2824 to_playlist->add_region (*newregion, (jack_nframes_t) (rv->region().position() * rtv->get_diskstream()->speed()));
2828 if (latest_regionview) {
2829 new_regionviews.push_back (latest_regionview);
2833 if (new_regionviews.empty()) {
2837 /* reset selection to new regionviews */
2839 selection->set (new_regionviews);
2841 /* reset drag_info data to reflect the fact that we are dragging the copies */
2843 drag_info.data = new_regionviews.front();
2844 swap_grab (new_regionviews.front()->get_canvas_group (), 0, event->motion.time);
2847 /* Which trackview is this ? */
2849 TimeAxisView* tvp = trackview_by_y_position (drag_info.current_pointer_y);
2850 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
2852 /* The region motion is only processed if the pointer is over
2856 if (!tv || !tv->is_track()) {
2857 /* To make sure we hide the verbose canvas cursor when the mouse is
2858 not held over a track.
2860 hide_verbose_canvas_cursor ();
2864 original_pointer_order = drag_info.last_trackview->order;
2866 /************************************************************
2868 ************************************************************/
2870 if (drag_info.brushing) {
2871 clamp_y_axis = true;
2876 if ((pointer_y_span = (drag_info.last_trackview->order - tv->order)) != 0) {
2878 int32_t children = 0, numtracks = 0;
2879 // XXX hard coding track limit, oh my, so very very bad
2880 bitset <1024> tracks (0x00);
2881 /* get a bitmask representing the visible tracks */
2883 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2884 TimeAxisView *tracklist_timeview;
2885 tracklist_timeview = (*i);
2886 RouteTimeAxisView* rtv2 = dynamic_cast<RouteTimeAxisView*>(tracklist_timeview);
2887 list<TimeAxisView*> children_list;
2889 /* zeroes are audio tracks. ones are other types. */
2891 if (!rtv2->hidden()) {
2893 if (visible_y_high < rtv2->order) {
2894 visible_y_high = rtv2->order;
2896 if (visible_y_low > rtv2->order) {
2897 visible_y_low = rtv2->order;
2900 if (!rtv2->is_track()) {
2901 tracks = tracks |= (0x01 << rtv2->order);
2904 height_list[rtv2->order] = (*i)->height;
2906 if ((children_list = rtv2->get_child_list()).size() > 0) {
2907 for (list<TimeAxisView*>::iterator j = children_list.begin(); j != children_list.end(); ++j) {
2908 tracks = tracks |= (0x01 << (rtv2->order + children));
2909 height_list[rtv2->order + children] = (*j)->height;
2917 /* find the actual span according to the canvas */
2919 canvas_pointer_y_span = pointer_y_span;
2920 if (drag_info.last_trackview->order >= tv->order) {
2922 for (y = tv->order; y < drag_info.last_trackview->order; y++) {
2923 if (height_list[y] == 0 ) {
2924 canvas_pointer_y_span--;
2929 for (y = drag_info.last_trackview->order;y <= tv->order; y++) {
2930 if ( height_list[y] == 0 ) {
2931 canvas_pointer_y_span++;
2936 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
2937 RegionView* rv2 = (*i);
2938 double ix1, ix2, iy1, iy2;
2941 rv2->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
2942 rv2->get_canvas_group()->i2w (ix1, iy1);
2943 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
2944 RouteTimeAxisView* rtv2 = dynamic_cast<RouteTimeAxisView*>(tvp2);
2946 if (rtv2->order != original_pointer_order) {
2947 /* this isn't the pointer track */
2949 if (canvas_pointer_y_span > 0) {
2951 /* moving up the canvas */
2952 if ((rtv2->order - canvas_pointer_y_span) >= visible_y_low) {
2954 int32_t visible_tracks = 0;
2955 while (visible_tracks < canvas_pointer_y_span ) {
2958 while (height_list[rtv2->order - (visible_tracks - n)] == 0) {
2959 /* we're passing through a hidden track */
2964 if (tracks[rtv2->order - (canvas_pointer_y_span - n)] != 0x00) {
2965 clamp_y_axis = true;
2969 clamp_y_axis = true;
2972 } else if (canvas_pointer_y_span < 0) {
2974 /*moving down the canvas*/
2976 if ((rtv2->order - (canvas_pointer_y_span - n)) <= visible_y_high) { // we will overflow
2979 int32_t visible_tracks = 0;
2981 while (visible_tracks > canvas_pointer_y_span ) {
2984 while (height_list[rtv2->order - (visible_tracks - n)] == 0) {
2988 if ( tracks[rtv2->order - ( canvas_pointer_y_span - n)] != 0x00) {
2989 clamp_y_axis = true;
2994 clamp_y_axis = true;
3000 /* this is the pointer's track */
3001 if ((rtv2->order - pointer_y_span) > visible_y_high) { // we will overflow
3002 clamp_y_axis = true;
3003 } else if ((rtv2->order - pointer_y_span) < visible_y_low) { // we will underflow
3004 clamp_y_axis = true;
3012 } else if (drag_info.last_trackview == tv) {
3013 clamp_y_axis = true;
3017 if (!clamp_y_axis) {
3018 drag_info.last_trackview = tv;
3021 /************************************************************
3023 ************************************************************/
3025 /* compute the amount of pointer motion in frames, and where
3026 the region would be if we moved it by that much.
3029 if (drag_info.move_threshold_passed) {
3031 if ((int32_t)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
3033 jack_nframes_t sync_frame;
3034 jack_nframes_t sync_offset;
3037 pending_region_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
3039 sync_offset = rv->region().sync_offset (sync_dir);
3040 sync_frame = rv->region().adjust_to_sync (pending_region_position);
3042 /* we snap if the snap modifier is not enabled.
3045 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3046 snap_to (sync_frame);
3049 if (sync_frame - sync_offset <= sync_frame) {
3050 pending_region_position = sync_frame - (sync_dir*sync_offset);
3052 pending_region_position = 0;
3056 pending_region_position = 0;
3059 if (pending_region_position > max_frames - rv->region().length()) {
3060 pending_region_position = drag_info.last_frame_position;
3063 // printf ("3: pending_region_position= %lu %lu\n", pending_region_position, drag_info.last_frame_position );
3065 if (pending_region_position != drag_info.last_frame_position && !drag_info.x_constrained) {
3067 /* now compute the canvas unit distance we need to move the regiondrag_info.last_trackview->order
3068 to make it appear at the new location.
3071 if (pending_region_position > drag_info.last_frame_position) {
3072 x_delta = ((double) (pending_region_position - drag_info.last_frame_position) / frames_per_unit);
3074 x_delta = -((double) (drag_info.last_frame_position - pending_region_position) / frames_per_unit);
3077 drag_info.last_frame_position = pending_region_position;
3084 /* threshold not passed */
3089 /*************************************************************
3091 ************************************************************/
3093 if (x_delta == 0 && (pointer_y_span == 0)) {
3094 /* haven't reached next snap point, and we're not switching
3095 trackviews. nothing to do.
3101 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
3103 RegionView* rv2 = (*i);
3105 // If any regionview is at zero, we need to know so we can stop further leftward motion.
3107 double ix1, ix2, iy1, iy2;
3108 rv2->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3109 rv2->get_canvas_group()->i2w (ix1, iy1);
3118 /*************************************************************
3120 ************************************************************/
3122 pair<set<Playlist*>::iterator,bool> insert_result;
3123 const list<RegionView*>& layered_regions = selection->regions.by_layer();
3125 for (list<RegionView*>::const_iterator i = layered_regions.begin(); i != layered_regions.end(); ++i) {
3127 RegionView* rv = (*i);
3128 double ix1, ix2, iy1, iy2;
3129 int32_t temp_pointer_y_span = pointer_y_span;
3131 /* get item BBox, which will be relative to parent. so we have
3132 to query on a child, then convert to world coordinates using
3136 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3137 rv->get_canvas_group()->i2w (ix1, iy1);
3138 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
3139 RouteTimeAxisView* canvas_rtv = dynamic_cast<RouteTimeAxisView*>(tvp2);
3140 RouteTimeAxisView* temp_rtv;
3142 if ((pointer_y_span != 0) && !clamp_y_axis) {
3145 for (j = height_list.begin(); j!= height_list.end(); j++) {
3146 if (x == canvas_rtv->order) {
3147 /* we found the track the region is on */
3148 if (x != original_pointer_order) {
3149 /*this isn't from the same track we're dragging from */
3150 temp_pointer_y_span = canvas_pointer_y_span;
3152 while (temp_pointer_y_span > 0) {
3153 /* we're moving up canvas-wise,
3154 so we need to find the next track height
3156 if (j != height_list.begin()) {
3159 if (x != original_pointer_order) {
3160 /* we're not from the dragged track, so ignore hidden tracks. */
3162 temp_pointer_y_span++;
3166 temp_pointer_y_span--;
3168 while (temp_pointer_y_span < 0) {
3170 if (x != original_pointer_order) {
3172 temp_pointer_y_span--;
3176 if (j != height_list.end()) {
3179 temp_pointer_y_span++;
3181 /* find out where we'll be when we move and set height accordingly */
3183 tvp2 = trackview_by_y_position (iy1 + y_delta);
3184 temp_rtv = dynamic_cast<RouteTimeAxisView*>(tvp2);
3185 rv->set_height (temp_rtv->height);
3187 /* if you un-comment the following, the region colours will follow the track colours whilst dragging,
3188 personally, i think this can confuse things, but never mind.
3191 //const GdkColor& col (temp_rtv->view->get_region_color());
3192 //rv->set_color (const_cast<GdkColor&>(col));
3199 /* prevent the regionview from being moved to before
3200 the zero position on the canvas.
3205 if (-x_delta > ix1) {
3208 } else if ((x_delta > 0) &&(rv->region().last_frame() > max_frames - x_delta)) {
3209 x_delta = max_frames - rv->region().last_frame();
3212 if (drag_info.first_move) {
3214 /* hide any dependent views */
3216 // rv->get_time_axis_view().hide_dependent_views (*rv);
3218 /* this is subtle. raising the regionview itself won't help,
3219 because raise_to_top() just puts the item on the top of
3220 its parent's stack. so, we need to put the trackview canvas_display group
3221 on the top, since its parent is the whole canvas.
3224 rv->get_canvas_group()->raise_to_top();
3225 rv->get_time_axis_view().canvas_display->raise_to_top();
3226 cursor_group->raise_to_top();
3228 /* freeze the playlists from notifying till
3232 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3233 if (rtv && rtv->is_track()) {
3234 Playlist* pl = dynamic_cast<Playlist*>(rtv->get_diskstream()->playlist());
3236 /* only freeze and capture state once */
3238 insert_result = motion_frozen_playlists.insert (pl);
3239 if (insert_result.second) {
3241 session->add_command(new MementoUndoCommand<Playlist>(*pl, pl->get_state()));
3247 if (drag_info.brushing) {
3248 mouse_brush_insert_region (rv, pending_region_position);
3250 rv->move (x_delta, y_delta);
3254 if (drag_info.first_move) {
3255 cursor_group->raise_to_top();
3258 drag_info.first_move = false;
3260 if (x_delta != 0 && !drag_info.brushing) {
3261 show_verbose_time_cursor (drag_info.last_frame_position, 10);
3267 Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
3269 jack_nframes_t where;
3270 RegionView* rv = reinterpret_cast<RegionView *> (drag_info.data);
3271 pair<set<Playlist*>::iterator,bool> insert_result;
3272 bool nocommit = true;
3274 RouteTimeAxisView* atv;
3275 bool regionview_y_movement;
3276 bool regionview_x_movement;
3278 /* first_move is set to false if the regionview has been moved in the
3282 if (drag_info.first_move) {
3289 /* The regionview has been moved at some stage during the grab so we need
3290 to account for any mouse movement between this event and the last one.
3293 region_drag_motion_callback (item, event);
3295 if (drag_info.brushing) {
3296 /* all changes were made during motion event handlers */
3300 /* adjust for track speed */
3303 atv = dynamic_cast<RouteTimeAxisView*> (drag_info.last_trackview);
3304 if (atv && atv->get_diskstream()) {
3305 speed = atv->get_diskstream()->speed();
3308 regionview_x_movement = (drag_info.last_frame_position != (jack_nframes_t) (rv->region().position()/speed));
3309 regionview_y_movement = (drag_info.last_trackview != &rv->get_time_axis_view());
3311 //printf ("last_frame: %s position is %lu %g\n", rv->get_time_axis_view().name().c_str(), drag_info.last_frame_position, speed);
3312 //printf ("last_rackview: %s \n", drag_info.last_trackview->name().c_str());
3314 if (regionview_y_movement) {
3316 /* motion between tracks */
3318 list<RegionView*> new_selection;
3320 /* moved to a different audio track. */
3322 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ) {
3324 RegionView* rv2 = (*i);
3326 /* the region that used to be in the old playlist is not
3327 moved to the new one - we make a copy of it. as a result,
3328 any existing editor for the region should no longer be
3332 if (!drag_info.copy) {
3333 rv2->hide_region_editor();
3335 new_selection.push_back (rv2);
3339 /* first, freeze the target tracks */
3341 for (list<RegionView*>::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) {
3343 Playlist* from_playlist;
3344 Playlist* to_playlist;
3346 double ix1, ix2, iy1, iy2;
3348 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3349 (*i)->get_canvas_group()->i2w (ix1, iy1);
3350 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
3351 RouteTimeAxisView* atv2 = dynamic_cast<RouteTimeAxisView*>(tvp2);
3353 from_playlist = (*i)->region().playlist();
3354 to_playlist = atv2->playlist();
3356 /* the from_playlist was frozen in the "first_move" case
3357 of the motion handler. the insert can fail,
3358 but that doesn't matter. it just means
3359 we already have the playlist in the list.
3362 motion_frozen_playlists.insert (from_playlist);
3364 /* only freeze the to_playlist once */
3366 insert_result = motion_frozen_playlists.insert(to_playlist);
3367 if (insert_result.second) {
3368 to_playlist->freeze();
3369 session->add_command(new MementoUndoCommand<Playlist>(*to_playlist, to_playlist->get_state()));
3374 /* now do it again with the actual operations */
3376 for (list<RegionView*>::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) {
3378 Playlist* from_playlist;
3379 Playlist* to_playlist;
3381 double ix1, ix2, iy1, iy2;
3383 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3384 (*i)->get_canvas_group()->i2w (ix1, iy1);
3385 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
3386 RouteTimeAxisView* atv2 = dynamic_cast<RouteTimeAxisView*>(tvp2);
3388 from_playlist = (*i)->region().playlist();
3389 to_playlist = atv2->playlist();
3391 latest_regionview = 0;
3393 where = (jack_nframes_t) (unit_to_frame (ix1) * speed);
3394 Region* new_region = createRegion ((*i)->region());
3396 from_playlist->remove_region (&((*i)->region()));
3398 sigc::connection c = atv2->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3399 to_playlist->add_region (*new_region, where);
3402 if (latest_regionview) {
3403 selection->add (latest_regionview);
3409 /* motion within a single track */
3411 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
3415 if (rv->region().locked()) {
3419 if (regionview_x_movement) {
3420 double ownspeed = 1.0;
3421 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(rv->get_time_axis_view()));
3423 if (atv && atv->get_diskstream()) {
3424 ownspeed = atv->get_diskstream()->speed();
3427 /* base the new region position on the current position of the regionview.*/
3429 double ix1, ix2, iy1, iy2;
3431 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
3432 rv->get_canvas_group()->i2w (ix1, iy1);
3433 where = (jack_nframes_t) (unit_to_frame (ix1) * ownspeed);
3437 where = rv->region().position();
3440 rv->get_time_axis_view().reveal_dependent_views (*rv);
3442 /* no need to add an undo here, we did that when we added this playlist to motion_frozen playlists */
3444 rv->region().set_position (where, (void *) this);
3449 for (set<Playlist*>::iterator p = motion_frozen_playlists.begin(); p != motion_frozen_playlists.end(); ++p) {
3451 session->add_command (new MementoRedoCommand<Playlist>(*(*p), (*p)->get_state()));
3454 motion_frozen_playlists.clear ();
3457 commit_reversible_command ();
3462 Editor::region_view_item_click (AudioRegionView& rv, GdkEventButton* event)
3464 /* Either add to or set the set the region selection, unless
3465 this is an alignment click (control used)
3468 if (Keyboard::modifier_state_contains (event->state, Keyboard::Control)) {
3469 TimeAxisView* tv = &rv.get_time_axis_view();
3470 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*>(tv);
3472 if (atv && atv->is_track()) {
3473 speed = atv->get_diskstream()->speed();
3476 if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Alt))) {
3478 align_region (rv.region(), SyncPoint, (jack_nframes_t) (edit_cursor->current_frame * speed));
3480 } else if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Shift))) {
3482 align_region (rv.region(), End, (jack_nframes_t) (edit_cursor->current_frame * speed));
3486 align_region (rv.region(), Start, (jack_nframes_t) (edit_cursor->current_frame * speed));
3492 Editor::show_verbose_time_cursor (jack_nframes_t frame, double offset, double xpos, double ypos)
3503 switch (ARDOUR_UI::instance()->secondary_clock.mode ()) {
3504 case AudioClock::BBT:
3505 session->bbt_time (frame, bbt);
3506 snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32, bbt.bars, bbt.beats, bbt.ticks);
3509 case AudioClock::SMPTE:
3510 session->smpte_time (frame, smpte);
3511 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
3514 case AudioClock::MinSec:
3515 /* XXX fix this to compute min/sec properly */
3516 session->smpte_time (frame, smpte);
3517 secs = smpte.seconds + ((float) smpte.frames / session->smpte_frames_per_second);
3518 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%.4f", smpte.hours, smpte.minutes, secs);
3522 snprintf (buf, sizeof(buf), "%u", frame);
3526 if (xpos >= 0 && ypos >=0) {
3527 set_verbose_canvas_cursor (buf, xpos + offset, ypos + offset);
3530 set_verbose_canvas_cursor (buf, drag_info.current_pointer_x + offset, drag_info.current_pointer_y + offset);
3532 show_verbose_canvas_cursor ();
3536 Editor::show_verbose_duration_cursor (jack_nframes_t start, jack_nframes_t end, double offset, double xpos, double ypos)
3543 Meter meter_at_start(session->tempo_map().meter_at(start));
3549 switch (ARDOUR_UI::instance()->secondary_clock.mode ()) {
3550 case AudioClock::BBT:
3551 session->bbt_time (start, sbbt);
3552 session->bbt_time (end, ebbt);
3555 /* XXX this computation won't work well if the
3556 user makes a selection that spans any meter changes.
3559 ebbt.bars -= sbbt.bars;
3560 if (ebbt.beats >= sbbt.beats) {
3561 ebbt.beats -= sbbt.beats;
3564 ebbt.beats = int(meter_at_start.beats_per_bar()) + ebbt.beats - sbbt.beats;
3566 if (ebbt.ticks >= sbbt.ticks) {
3567 ebbt.ticks -= sbbt.ticks;
3570 ebbt.ticks = int(Meter::ticks_per_beat) + ebbt.ticks - sbbt.ticks;
3573 snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32, ebbt.bars, ebbt.beats, ebbt.ticks);
3576 case AudioClock::SMPTE:
3577 session->smpte_duration (end - start, smpte);
3578 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
3581 case AudioClock::MinSec:
3582 /* XXX fix this to compute min/sec properly */
3583 session->smpte_duration (end - start, smpte);
3584 secs = smpte.seconds + ((float) smpte.frames / session->smpte_frames_per_second);
3585 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%.4f", smpte.hours, smpte.minutes, secs);
3589 snprintf (buf, sizeof(buf), "%u", end - start);
3593 if (xpos >= 0 && ypos >=0) {
3594 set_verbose_canvas_cursor (buf, xpos + offset, ypos + offset);
3597 set_verbose_canvas_cursor (buf, drag_info.current_pointer_x + offset, drag_info.current_pointer_y + offset);
3599 show_verbose_canvas_cursor ();
3603 Editor::collect_new_region_view (RegionView* rv)
3605 latest_regionview = rv;
3609 Editor::start_selection_grab (ArdourCanvas::Item* item, GdkEvent* event)
3611 if (clicked_regionview == 0) {
3615 /* lets try to create new Region for the selection */
3617 vector<AudioRegion*> new_regions;
3618 create_region_from_selection (new_regions);
3620 if (new_regions.empty()) {
3624 /* XXX fix me one day to use all new regions */
3626 Region* region = new_regions.front();
3628 /* add it to the current stream/playlist.
3630 tricky: the streamview for the track will add a new regionview. we will
3631 catch the signal it sends when it creates the regionview to
3632 set the regionview we want to then drag.
3635 latest_regionview = 0;
3636 sigc::connection c = clicked_routeview->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3638 /* A selection grab currently creates two undo/redo operations, one for
3639 creating the new region and another for moving it.
3642 begin_reversible_command (_("selection grab"));
3644 Playlist* playlist = clicked_axisview->playlist();
3646 before = &(playlist->get_state());
3647 clicked_axisview->playlist()->add_region (*region, selection->time[clicked_selection].start);
3648 XMLNode &after = playlist->get_state();
3649 session->add_command(new MementoCommand<Playlist>(*playlist, *before, after));
3651 commit_reversible_command ();
3655 if (latest_regionview == 0) {
3656 /* something went wrong */
3660 /* we need to deselect all other regionviews, and select this one
3661 i'm ignoring undo stuff, because the region creation will take care of it */
3662 selection->set (latest_regionview);
3664 drag_info.item = latest_regionview->get_canvas_group();
3665 drag_info.data = latest_regionview;
3666 drag_info.motion_callback = &Editor::region_drag_motion_callback;
3667 drag_info.finished_callback = &Editor::region_drag_finished_callback;
3671 drag_info.last_trackview = clicked_axisview;
3672 drag_info.last_frame_position = latest_regionview->region().position();
3673 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
3675 show_verbose_time_cursor (drag_info.last_frame_position, 10);
3679 Editor::cancel_selection ()
3681 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3682 (*i)->hide_selection ();
3684 begin_reversible_command (_("cancel selection"));
3685 selection->clear ();
3686 clicked_selection = 0;
3687 commit_reversible_command ();
3691 Editor::start_selection_op (ArdourCanvas::Item* item, GdkEvent* event, SelectionOp op)
3693 jack_nframes_t start = 0;
3694 jack_nframes_t end = 0;
3700 drag_info.item = item;
3701 drag_info.motion_callback = &Editor::drag_selection;
3702 drag_info.finished_callback = &Editor::end_selection_op;
3707 case CreateSelection:
3708 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
3709 drag_info.copy = true;
3711 drag_info.copy = false;
3713 start_grab (event, selector_cursor);
3716 case SelectionStartTrim:
3717 if (clicked_axisview) {
3718 clicked_axisview->order_selection_trims (item, true);
3720 start_grab (event, trimmer_cursor);
3721 start = selection->time[clicked_selection].start;
3722 drag_info.pointer_frame_offset = drag_info.grab_frame - start;
3725 case SelectionEndTrim:
3726 if (clicked_axisview) {
3727 clicked_axisview->order_selection_trims (item, false);
3729 start_grab (event, trimmer_cursor);
3730 end = selection->time[clicked_selection].end;
3731 drag_info.pointer_frame_offset = drag_info.grab_frame - end;
3735 start = selection->time[clicked_selection].start;
3737 drag_info.pointer_frame_offset = drag_info.grab_frame - start;
3741 if (selection_op == SelectionMove) {
3742 show_verbose_time_cursor(start, 10);
3744 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
3749 Editor::drag_selection (ArdourCanvas::Item* item, GdkEvent* event)
3751 jack_nframes_t start = 0;
3752 jack_nframes_t end = 0;
3753 jack_nframes_t length;
3754 jack_nframes_t pending_position;
3756 if ((int32_t) drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
3757 pending_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
3760 pending_position = 0;
3763 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3764 snap_to (pending_position);
3767 /* only alter selection if the current frame is
3768 different from the last frame position (adjusted)
3771 if (pending_position == drag_info.last_pointer_frame) return;
3773 switch (selection_op) {
3774 case CreateSelection:
3776 if (drag_info.first_move) {
3777 snap_to (drag_info.grab_frame);
3780 if (pending_position < drag_info.grab_frame) {
3781 start = pending_position;
3782 end = drag_info.grab_frame;
3784 end = pending_position;
3785 start = drag_info.grab_frame;
3788 /* first drag: Either add to the selection
3789 or create a new selection->
3792 if (drag_info.first_move) {
3794 begin_reversible_command (_("range selection"));
3796 if (drag_info.copy) {
3797 /* adding to the selection */
3798 clicked_selection = selection->add (start, end);
3799 drag_info.copy = false;
3801 /* new selection-> */
3802 clicked_selection = selection->set (clicked_axisview, start, end);
3807 case SelectionStartTrim:
3809 if (drag_info.first_move) {
3810 begin_reversible_command (_("trim selection start"));
3813 start = selection->time[clicked_selection].start;
3814 end = selection->time[clicked_selection].end;
3816 if (pending_position > end) {
3819 start = pending_position;
3823 case SelectionEndTrim:
3825 if (drag_info.first_move) {
3826 begin_reversible_command (_("trim selection end"));
3829 start = selection->time[clicked_selection].start;
3830 end = selection->time[clicked_selection].end;
3832 if (pending_position < start) {
3835 end = pending_position;
3842 if (drag_info.first_move) {
3843 begin_reversible_command (_("move selection"));
3846 start = selection->time[clicked_selection].start;
3847 end = selection->time[clicked_selection].end;
3849 length = end - start;
3851 start = pending_position;
3854 end = start + length;
3859 if (event->button.x >= horizontal_adjustment.get_value() + canvas_width) {
3860 start_canvas_autoscroll (1);
3864 selection->replace (clicked_selection, start, end);
3867 drag_info.last_pointer_frame = pending_position;
3868 drag_info.first_move = false;
3870 if (selection_op == SelectionMove) {
3871 show_verbose_time_cursor(start, 10);
3873 show_verbose_time_cursor(pending_position, 10);
3878 Editor::end_selection_op (ArdourCanvas::Item* item, GdkEvent* event)
3880 if (!drag_info.first_move) {
3881 drag_selection (item, event);
3882 /* XXX this is not object-oriented programming at all. ick */
3883 if (selection->time.consolidate()) {
3884 selection->TimeChanged ();
3886 commit_reversible_command ();
3888 /* just a click, no pointer movement.*/
3890 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3892 selection->clear_time();
3897 /* XXX what happens if its a music selection? */
3898 session->set_audio_range (selection->time);
3899 stop_canvas_autoscroll ();
3903 Editor::start_trim (ArdourCanvas::Item* item, GdkEvent* event)
3906 TimeAxisView* tvp = clicked_axisview;
3907 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
3909 if (tv && tv->is_track()) {
3910 speed = tv->get_diskstream()->speed();
3913 jack_nframes_t region_start = (jack_nframes_t) (clicked_regionview->region().position() / speed);
3914 jack_nframes_t region_end = (jack_nframes_t) (clicked_regionview->region().last_frame() / speed);
3915 jack_nframes_t region_length = (jack_nframes_t) (clicked_regionview->region().length() / speed);
3917 motion_frozen_playlists.clear();
3919 //drag_info.item = clicked_regionview->get_name_highlight();
3920 drag_info.item = item;
3921 drag_info.motion_callback = &Editor::trim_motion_callback;
3922 drag_info.finished_callback = &Editor::trim_finished_callback;
3924 start_grab (event, trimmer_cursor);
3926 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
3927 trim_op = ContentsTrim;
3929 /* These will get overridden for a point trim.*/
3930 if (drag_info.current_pointer_frame < (region_start + region_length/2)) {
3931 /* closer to start */
3932 trim_op = StartTrim;
3933 } else if (drag_info.current_pointer_frame > (region_end - region_length/2)) {
3941 show_verbose_time_cursor(region_start, 10);
3944 show_verbose_time_cursor(region_end, 10);
3947 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
3953 Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
3955 RegionView* rv = clicked_regionview;
3956 jack_nframes_t frame_delta = 0;
3957 bool left_direction;
3958 bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier());
3960 /* snap modifier works differently here..
3961 its' current state has to be passed to the
3962 various trim functions in order to work properly
3966 TimeAxisView* tvp = clicked_axisview;
3967 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
3968 pair<set<Playlist*>::iterator,bool> insert_result;
3970 if (tv && tv->is_track()) {
3971 speed = tv->get_diskstream()->speed();
3974 if (drag_info.last_pointer_frame > drag_info.current_pointer_frame) {
3975 left_direction = true;
3977 left_direction = false;
3981 snap_to (drag_info.current_pointer_frame);
3984 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) {
3988 if (drag_info.first_move) {
3994 trim_type = "Region start trim";
3997 trim_type = "Region end trim";
4000 trim_type = "Region content trim";
4004 begin_reversible_command (trim_type);
4006 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
4007 (*i)->region().freeze ();
4009 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4011 arv->temporarily_hide_envelope ();
4013 Playlist * pl = (*i)->region().playlist();
4014 insert_result = motion_frozen_playlists.insert (pl);
4015 if (insert_result.second) {
4016 session->add_command(new MementoUndoCommand<Playlist>(*pl, pl->get_state()));
4021 if (left_direction) {
4022 frame_delta = (drag_info.last_pointer_frame - drag_info.current_pointer_frame);
4024 frame_delta = (drag_info.current_pointer_frame - drag_info.last_pointer_frame);
4029 if ((left_direction == false) && (drag_info.current_pointer_frame <= rv->region().first_frame()/speed)) {
4032 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
4033 single_start_trim (**i, frame_delta, left_direction, obey_snap);
4039 if ((left_direction == true) && (drag_info.current_pointer_frame > (jack_nframes_t) (rv->region().last_frame()/speed))) {
4042 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
4043 single_end_trim (**i, frame_delta, left_direction, obey_snap);
4050 bool swap_direction = false;
4052 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
4053 swap_direction = true;
4056 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin();
4057 i != selection->regions.by_layer().end(); ++i)
4059 single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
4067 show_verbose_time_cursor((jack_nframes_t) (rv->region().position()/speed), 10);
4070 show_verbose_time_cursor((jack_nframes_t) (rv->region().last_frame()/speed), 10);
4073 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
4077 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4078 drag_info.first_move = false;
4082 Editor::single_contents_trim (RegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool swap_direction, bool obey_snap)
4084 Region& region (rv.region());
4086 if (region.locked()) {
4090 jack_nframes_t new_bound;
4093 TimeAxisView* tvp = clicked_axisview;
4094 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
4096 if (tv && tv->is_track()) {
4097 speed = tv->get_diskstream()->speed();
4100 if (left_direction) {
4101 if (swap_direction) {
4102 new_bound = (jack_nframes_t) (region.position()/speed) + frame_delta;
4104 new_bound = (jack_nframes_t) (region.position()/speed) - frame_delta;
4107 if (swap_direction) {
4108 new_bound = (jack_nframes_t) (region.position()/speed) - frame_delta;
4110 new_bound = (jack_nframes_t) (region.position()/speed) + frame_delta;
4115 snap_to (new_bound);
4117 region.trim_start ((jack_nframes_t) (new_bound * speed), this);
4118 rv.region_changed (StartChanged);
4122 Editor::single_start_trim (RegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool obey_snap)
4124 Region& region (rv.region());
4126 if (region.locked()) {
4130 jack_nframes_t new_bound;
4133 TimeAxisView* tvp = clicked_axisview;
4134 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
4136 if (tv && tv->is_track()) {
4137 speed = tv->get_diskstream()->speed();
4140 if (left_direction) {
4141 new_bound = (jack_nframes_t) (region.position()/speed) - frame_delta;
4143 new_bound = (jack_nframes_t) (region.position()/speed) + frame_delta;
4147 snap_to (new_bound, (left_direction ? 0 : 1));
4150 region.trim_front ((jack_nframes_t) (new_bound * speed), this);
4152 rv.region_changed (Change (LengthChanged|PositionChanged|StartChanged));
4156 Editor::single_end_trim (RegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool obey_snap)
4158 Region& region (rv.region());
4160 if (region.locked()) {
4164 jack_nframes_t new_bound;
4167 TimeAxisView* tvp = clicked_axisview;
4168 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
4170 if (tv && tv->is_track()) {
4171 speed = tv->get_diskstream()->speed();
4174 if (left_direction) {
4175 new_bound = (jack_nframes_t) ((region.last_frame() + 1)/speed) - frame_delta;
4177 new_bound = (jack_nframes_t) ((region.last_frame() + 1)/speed) + frame_delta;
4181 snap_to (new_bound);
4183 region.trim_end ((jack_nframes_t) (new_bound * speed), this);
4184 rv.region_changed (LengthChanged);
4188 Editor::trim_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
4190 if (!drag_info.first_move) {
4191 trim_motion_callback (item, event);
4193 if (!clicked_regionview->get_selected()) {
4194 thaw_region_after_trim (*clicked_regionview);
4197 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin();
4198 i != selection->regions.by_layer().end(); ++i)
4200 thaw_region_after_trim (**i);
4204 for (set<Playlist*>::iterator p = motion_frozen_playlists.begin(); p != motion_frozen_playlists.end(); ++p) {
4206 session->add_command (new MementoRedoCommand<Playlist>(*(*p), (*p)->get_state()));
4209 motion_frozen_playlists.clear ();
4211 commit_reversible_command();
4213 /* no mouse movement */
4219 Editor::point_trim (GdkEvent* event)
4221 RegionView* rv = clicked_regionview;
4222 jack_nframes_t new_bound = drag_info.current_pointer_frame;
4224 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4225 snap_to (new_bound);
4228 /* Choose action dependant on which button was pressed */
4229 switch (event->button.button) {
4231 trim_op = StartTrim;
4232 begin_reversible_command (_("Start point trim"));
4234 if (rv->get_selected()) {
4236 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin();
4237 i != selection->regions.by_layer().end(); ++i)
4239 if (!(*i)->region().locked()) {
4240 Playlist *pl = (*i)->region().playlist();
4241 XMLNode &before = pl->get_state();
4242 (*i)->region().trim_front (new_bound, this);
4243 XMLNode &after = pl->get_state();
4244 session->add_command(new MementoCommand<Playlist>(*pl, before, after));
4250 if (!rv->region().locked()) {
4251 Playlist *pl = rv->region().playlist();
4252 XMLNode &before = pl->get_state();
4253 rv->region().trim_front (new_bound, this);
4254 XMLNode &after = pl->get_state();
4255 session->add_command(new MementoCommand<Playlist>(*pl, before, after));
4259 commit_reversible_command();
4264 begin_reversible_command (_("End point trim"));
4266 if (rv->get_selected()) {
4268 for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i)
4270 if (!(*i)->region().locked()) {
4271 Playlist *pl = (*i)->region().playlist();
4272 XMLNode &before = pl->get_state();
4273 (*i)->region().trim_end (new_bound, this);
4274 XMLNode &after = pl->get_state();
4275 session->add_command(new MementoCommand<Playlist>(*pl, before, after));
4281 if (!rv->region().locked()) {
4282 Playlist *pl = rv->region().playlist();
4283 XMLNode &before = pl->get_state();
4284 rv->region().trim_end (new_bound, this);
4285 XMLNode &after = pl->get_state();
4286 session->add_command (new MementoCommand<Playlist>(*pl, before, after));
4290 commit_reversible_command();
4299 Editor::thaw_region_after_trim (RegionView& rv)
4301 Region& region (rv.region());
4303 if (region.locked()) {
4307 region.thaw (_("trimmed region"));
4308 XMLNode &after = region.playlist()->get_state();
4309 session->add_command (new MementoRedoCommand<Playlist>(*(region.playlist()), after));
4311 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(&rv);
4313 arv->unhide_envelope ();
4317 Editor::hide_marker (ArdourCanvas::Item* item, GdkEvent* event)
4322 if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
4323 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
4327 Location* location = find_location_from_marker (marker, is_start);
4328 location->set_hidden (true, this);
4333 Editor::start_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event, RangeMarkerOp op)
4339 drag_info.item = item;
4340 drag_info.motion_callback = &Editor::drag_range_markerbar_op;
4341 drag_info.finished_callback = &Editor::end_range_markerbar_op;
4343 range_marker_op = op;
4345 if (!temp_location) {
4346 temp_location = new Location;
4350 case CreateRangeMarker:
4351 case CreateTransportMarker:
4353 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
4354 drag_info.copy = true;
4356 drag_info.copy = false;
4358 start_grab (event, selector_cursor);
4362 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
4367 Editor::drag_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event)
4369 jack_nframes_t start = 0;
4370 jack_nframes_t end = 0;
4371 ArdourCanvas::SimpleRect *crect = (range_marker_op == CreateRangeMarker) ? range_bar_drag_rect: transport_bar_drag_rect;
4373 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4374 snap_to (drag_info.current_pointer_frame);
4377 /* only alter selection if the current frame is
4378 different from the last frame position.
4381 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) return;
4383 switch (range_marker_op) {
4384 case CreateRangeMarker:
4385 case CreateTransportMarker:
4386 if (drag_info.first_move) {
4387 snap_to (drag_info.grab_frame);
4390 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4391 start = drag_info.current_pointer_frame;
4392 end = drag_info.grab_frame;
4394 end = drag_info.current_pointer_frame;
4395 start = drag_info.grab_frame;
4398 /* first drag: Either add to the selection
4399 or create a new selection.
4402 if (drag_info.first_move) {
4404 temp_location->set (start, end);
4408 update_marker_drag_item (temp_location);
4409 range_marker_drag_rect->show();
4410 range_marker_drag_rect->raise_to_top();
4416 if (event->button.x >= horizontal_adjustment.get_value() + canvas_width) {
4417 start_canvas_autoscroll (1);
4421 temp_location->set (start, end);
4423 double x1 = frame_to_pixel (start);
4424 double x2 = frame_to_pixel (end);
4425 crect->property_x1() = x1;
4426 crect->property_x2() = x2;
4428 update_marker_drag_item (temp_location);
4431 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4432 drag_info.first_move = false;
4434 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
4439 Editor::end_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event)
4441 Location * newloc = 0;
4443 if (!drag_info.first_move) {
4444 drag_range_markerbar_op (item, event);
4446 switch (range_marker_op) {
4447 case CreateRangeMarker:
4449 begin_reversible_command (_("new range marker"));
4450 XMLNode &before = session->locations()->get_state();
4451 newloc = new Location(temp_location->start(), temp_location->end(), "unnamed", Location::IsRangeMarker);
4452 session->locations()->add (newloc, true);
4453 XMLNode &after = session->locations()->get_state();
4454 session->add_command(new MementoCommand<Locations>(*(session->locations()), before, after));
4455 commit_reversible_command ();
4457 range_bar_drag_rect->hide();
4458 range_marker_drag_rect->hide();
4462 case CreateTransportMarker:
4463 // popup menu to pick loop or punch
4464 new_transport_marker_context_menu (&event->button, item);
4469 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
4471 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
4473 jack_nframes_t start;
4476 start = session->locations()->first_mark_before (drag_info.grab_frame);
4477 end = session->locations()->first_mark_after (drag_info.grab_frame);
4479 if (end == max_frames) {
4480 end = session->current_end_frame ();
4484 start = session->current_start_frame ();
4487 switch (mouse_mode) {
4489 /* find the two markers on either side and then make the selection from it */
4490 cerr << "select between " << start << " .. " << end << endl;
4491 select_all_within (start, end, 0.0f, FLT_MAX, Selection::Set);
4495 /* find the two markers on either side of the click and make the range out of it */
4496 selection->set (0, start, end);
4505 stop_canvas_autoscroll ();
4511 Editor::start_mouse_zoom (ArdourCanvas::Item* item, GdkEvent* event)
4513 drag_info.item = item;
4514 drag_info.motion_callback = &Editor::drag_mouse_zoom;
4515 drag_info.finished_callback = &Editor::end_mouse_zoom;
4517 start_grab (event, zoom_cursor);
4519 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4523 Editor::drag_mouse_zoom (ArdourCanvas::Item* item, GdkEvent* event)
4525 jack_nframes_t start;
4528 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4529 snap_to (drag_info.current_pointer_frame);
4531 if (drag_info.first_move) {
4532 snap_to (drag_info.grab_frame);
4536 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) return;
4538 /* base start and end on initial click position */
4539 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4540 start = drag_info.current_pointer_frame;
4541 end = drag_info.grab_frame;
4543 end = drag_info.current_pointer_frame;
4544 start = drag_info.grab_frame;
4549 if (drag_info.first_move) {
4551 zoom_rect->raise_to_top();
4554 reposition_zoom_rect(start, end);
4556 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4557 drag_info.first_move = false;
4559 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4564 Editor::end_mouse_zoom (ArdourCanvas::Item* item, GdkEvent* event)
4566 if (!drag_info.first_move) {
4567 drag_mouse_zoom (item, event);
4569 if (drag_info.grab_frame < drag_info.last_pointer_frame) {
4570 temporal_zoom_by_frame (drag_info.grab_frame, drag_info.last_pointer_frame, "mouse zoom");
4572 temporal_zoom_by_frame (drag_info.last_pointer_frame, drag_info.grab_frame, "mouse zoom");
4575 temporal_zoom_to_frame (false, drag_info.grab_frame);
4577 temporal_zoom_step (false);
4578 center_screen (drag_info.grab_frame);
4586 Editor::reposition_zoom_rect (jack_nframes_t start, jack_nframes_t end)
4588 double x1 = frame_to_pixel (start);
4589 double x2 = frame_to_pixel (end);
4590 double y2 = canvas_height - 2;
4592 zoom_rect->property_x1() = x1;
4593 zoom_rect->property_y1() = 1.0;
4594 zoom_rect->property_x2() = x2;
4595 zoom_rect->property_y2() = y2;
4599 Editor::start_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event)
4601 drag_info.item = item;
4602 drag_info.motion_callback = &Editor::drag_rubberband_select;
4603 drag_info.finished_callback = &Editor::end_rubberband_select;
4605 start_grab (event, cross_hair_cursor);
4607 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4611 Editor::drag_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event)
4613 jack_nframes_t start;
4618 /* use a bigger drag threshold than the default */
4620 if (abs ((int) (drag_info.current_pointer_frame - drag_info.grab_frame)) < 8) {
4624 // if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4625 // snap_to (drag_info.current_pointer_frame);
4627 // if (drag_info.first_move) {
4628 // snap_to (drag_info.grab_frame);
4633 /* base start and end on initial click position */
4634 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4635 start = drag_info.current_pointer_frame;
4636 end = drag_info.grab_frame;
4638 end = drag_info.current_pointer_frame;
4639 start = drag_info.grab_frame;
4642 if (drag_info.current_pointer_y < drag_info.grab_y) {
4643 y1 = drag_info.current_pointer_y;
4644 y2 = drag_info.grab_y;
4647 y2 = drag_info.current_pointer_y;
4648 y1 = drag_info.grab_y;
4652 if (start != end || y1 != y2) {
4654 double x1 = frame_to_pixel (start);
4655 double x2 = frame_to_pixel (end);
4657 rubberband_rect->property_x1() = x1;
4658 rubberband_rect->property_y1() = y1;
4659 rubberband_rect->property_x2() = x2;
4660 rubberband_rect->property_y2() = y2;
4662 rubberband_rect->show();
4663 rubberband_rect->raise_to_top();
4665 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4666 drag_info.first_move = false;
4668 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4673 Editor::end_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event)
4675 if (!drag_info.first_move) {
4677 drag_rubberband_select (item, event);
4680 if (drag_info.current_pointer_y < drag_info.grab_y) {
4681 y1 = drag_info.current_pointer_y;
4682 y2 = drag_info.grab_y;
4685 y2 = drag_info.current_pointer_y;
4686 y1 = drag_info.grab_y;
4690 Selection::Operation op = Keyboard::selection_type (event->button.state);
4693 begin_reversible_command (_("select regions"));
4695 if (drag_info.grab_frame < drag_info.last_pointer_frame) {
4696 commit = select_all_within (drag_info.grab_frame, drag_info.last_pointer_frame, y1, y2, op);
4698 commit = select_all_within (drag_info.last_pointer_frame, drag_info.grab_frame, y1, y2, op);
4702 commit_reversible_command ();
4706 selection->clear_regions();
4707 selection->clear_points ();
4708 selection->clear_lines ();
4711 rubberband_rect->hide();
4716 Editor::mouse_rename_region (ArdourCanvas::Item* item, GdkEvent* event)
4718 using namespace Gtkmm2ext;
4720 ArdourPrompter prompter (false);
4722 prompter.set_prompt (_("Name for region:"));
4723 prompter.set_initial_text (clicked_regionview->region().name());
4724 prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
4725 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
4726 prompter.show_all ();
4727 switch (prompter.run ()) {
4728 case Gtk::RESPONSE_ACCEPT:
4730 prompter.get_result(str);
4732 clicked_regionview->region().set_name (str);
4740 Editor::start_time_fx (ArdourCanvas::Item* item, GdkEvent* event)
4742 drag_info.item = item;
4743 drag_info.motion_callback = &Editor::time_fx_motion;
4744 drag_info.finished_callback = &Editor::end_time_fx;
4748 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4752 Editor::time_fx_motion (ArdourCanvas::Item *item, GdkEvent* event)
4754 RegionView* rv = clicked_regionview;
4756 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4757 snap_to (drag_info.current_pointer_frame);
4760 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) {
4764 if (drag_info.current_pointer_frame > rv->region().position()) {
4765 rv->get_time_axis_view().show_timestretch (rv->region().position(), drag_info.current_pointer_frame);
4768 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4769 drag_info.first_move = false;
4771 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4775 Editor::end_time_fx (ArdourCanvas::Item* item, GdkEvent* event)
4777 clicked_regionview->get_time_axis_view().hide_timestretch ();
4779 if (drag_info.first_move) {
4783 jack_nframes_t newlen = drag_info.last_pointer_frame - clicked_regionview->region().position();
4784 float percentage = (float) ((double) newlen - (double) clicked_regionview->region().length()) / ((double) newlen) * 100.0f;
4786 begin_reversible_command (_("timestretch"));
4788 if (run_timestretch (selection->regions, percentage) == 0) {
4789 session->commit_reversible_command ();
4794 Editor::mouse_brush_insert_region (RegionView* rv, jack_nframes_t pos)
4796 /* no brushing without a useful snap setting */
4799 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
4802 switch (snap_mode) {
4804 return; /* can't work because it allows region to be placed anywhere */
4809 switch (snap_type) {
4812 case SnapToEditCursor:
4819 /* don't brush a copy over the original */
4821 if (pos == rv->region().position()) {
4825 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*>(&arv->get_time_axis_view());
4827 if (atv == 0 || !atv->is_track()) {
4831 Playlist* playlist = atv->playlist();
4832 double speed = atv->get_diskstream()->speed();
4834 XMLNode &before = playlist->get_state();
4835 playlist->add_region (*(new AudioRegion (arv->audio_region())), (jack_nframes_t) (pos * speed));
4836 XMLNode &after = playlist->get_state();
4837 session->add_command(new MementoCommand<Playlist>(*playlist, before, after));
4839 // playlist is frozen, so we have to update manually
4841 playlist->StateChanged (Change (~0)); /* EMIT SIGNAL */
4845 Editor::track_height_step_timeout ()
4848 struct timeval delta;
4850 gettimeofday (&now, 0);
4851 timersub (&now, &last_track_height_step_timestamp, &delta);
4853 if (delta.tv_sec * 1000000 + delta.tv_usec > 250000) { /* milliseconds */
4854 current_stepping_trackview = 0;