2 Copyright (C) 2000-2001 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #include <pbd/error.h>
29 #include <gtkmm2ext/utils.h>
31 #include "ardour_ui.h"
33 #include "time_axis_view.h"
34 #include "audio_time_axis.h"
35 #include "regionview.h"
37 #include "streamview.h"
38 #include "region_gain_line.h"
39 #include "automation_time_axis.h"
42 #include "selection.h"
45 #include "rgb_macros.h"
47 #include <ardour/types.h>
48 #include <ardour/route.h>
49 #include <ardour/audio_track.h>
50 #include <ardour/diskstream.h>
51 #include <ardour/playlist.h>
52 #include <ardour/audioplaylist.h>
53 #include <ardour/audioregion.h>
54 #include <ardour/dB.h>
55 #include <ardour/utils.h>
56 #include <ardour/region_factory.h>
63 using namespace ARDOUR;
66 using namespace Editing;
69 Editor::event_frame (GdkEvent* event, double* pcx, double* pcy)
83 switch (event->type) {
84 case GDK_BUTTON_RELEASE:
85 case GDK_BUTTON_PRESS:
86 case GDK_2BUTTON_PRESS:
87 case GDK_3BUTTON_PRESS:
88 gnome_canvas_w2c_d (GNOME_CANVAS(&track_canvas), event->button.x, event->button.y, pcx, pcy);
90 case GDK_MOTION_NOTIFY:
91 gnome_canvas_w2c_d (GNOME_CANVAS(&track_canvas), event->motion.x, event->motion.y, pcx, pcy);
93 case GDK_ENTER_NOTIFY:
94 case GDK_LEAVE_NOTIFY:
95 gnome_canvas_w2c_d (GNOME_CANVAS(&track_canvas), event->crossing.x, event->crossing.y, pcx, pcy);
98 warning << string_compose (_("Editor::event_frame() used on unhandled event type %1"), event->type) << endmsg;
102 /* note that pixel_to_frame() never returns less than zero, so even if the pixel
103 position is negative (as can be the case with motion events in particular),
104 the frame location is always positive.
107 return pixel_to_frame (*pcx);
111 Editor::mouse_mode_toggled (MouseMode m)
113 if (ignore_mouse_mode_toggle) {
119 if (mouse_select_button.get_active()) {
125 if (mouse_move_button.get_active()) {
131 if (mouse_gain_button.get_active()) {
137 if (mouse_zoom_button.get_active()) {
143 if (mouse_timefx_button.get_active()) {
149 if (mouse_audition_button.get_active()) {
160 Editor::set_mouse_mode (MouseMode m, bool force)
162 if (drag_info.item) {
166 if (m == mouse_mode && !force) {
174 if (mouse_mode != MouseRange) {
176 /* in all modes except range, hide the range selection,
177 show the object (region) selection.
180 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
181 (*i)->set_should_show_selection (true);
183 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
184 (*i)->hide_selection ();
189 /* in range mode, hide object (region) selection, and show the
193 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
194 (*i)->set_should_show_selection (false);
196 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
197 if ((*i)->selected()) {
198 (*i)->show_selection (selection->time);
203 /* XXX the hack of unsetting all other buttongs should go
204 away once GTK2 allows us to use regular radio buttons drawn like
205 normal buttons, rather than my silly GroupedButton hack.
208 ignore_mouse_mode_toggle = true;
210 switch (mouse_mode) {
212 mouse_select_button.set_active (true);
213 current_canvas_cursor = selector_cursor;
217 mouse_move_button.set_active (true);
218 current_canvas_cursor = grabber_cursor;
222 mouse_gain_button.set_active (true);
223 current_canvas_cursor = cross_hair_cursor;
227 mouse_zoom_button.set_active (true);
228 current_canvas_cursor = zoom_cursor;
232 mouse_timefx_button.set_active (true);
233 current_canvas_cursor = time_fx_cursor; // just use playhead
237 mouse_audition_button.set_active (true);
238 current_canvas_cursor = speaker_cursor;
242 ignore_mouse_mode_toggle = false;
245 track_canvas_scroller.get_window()->set_cursor(*current_canvas_cursor);
250 Editor::step_mouse_mode (bool next)
252 switch (current_mouse_mode()) {
254 if (next) set_mouse_mode (MouseRange);
255 else set_mouse_mode (MouseTimeFX);
259 if (next) set_mouse_mode (MouseZoom);
260 else set_mouse_mode (MouseObject);
264 if (next) set_mouse_mode (MouseGain);
265 else set_mouse_mode (MouseRange);
269 if (next) set_mouse_mode (MouseTimeFX);
270 else set_mouse_mode (MouseZoom);
274 if (next) set_mouse_mode (MouseAudition);
275 else set_mouse_mode (MouseGain);
279 if (next) set_mouse_mode (MouseObject);
280 else set_mouse_mode (MouseTimeFX);
286 Editor::button_press_handler (GnomeCanvasItem* item, GdkEvent* event, ItemType item_type)
288 jack_nframes_t where = event_frame (event, 0, 0);
290 if (session && session->actively_recording()) {
294 /* in object/audition/timefx mode, any button press sets
295 the selection if the object can be selected. this is a
296 bit of hack, because we want to avoid this if the
297 mouse operation is a region alignment.
300 if (((mouse_mode == MouseObject) ||
301 (mouse_mode == MouseAudition && item_type == RegionItem) ||
302 (mouse_mode == MouseTimeFX && item_type == RegionItem)) &&
303 event->type == GDK_BUTTON_PRESS &&
304 event->button.button <= 3) {
309 /* not dbl-click or triple-click */
313 set_selected_regionview_from_click (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift), true);
316 case AudioRegionViewNameHighlight:
317 case AudioRegionViewName:
318 if ((rv = reinterpret_cast<AudioRegionView *> (gtk_object_get_data(GTK_OBJECT(item), "regionview"))) != 0) {
319 set_selected_regionview_from_click (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift), true);
323 case GainAutomationControlPointItem:
324 case PanAutomationControlPointItem:
325 case RedirectAutomationControlPointItem:
326 if ((cp = reinterpret_cast<ControlPoint *> (gtk_object_get_data(GTK_OBJECT(item), "control_point"))) != 0) {
327 set_selected_control_point_from_click (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift), true);
334 case AutomationTrackItem:
342 #define SELECT_TRACK_FROM_CANVAS_IN_RANGE_MODE
343 #ifdef SELECT_TRACK_FROM_CANVAS_IN_RANGE_MODE
344 /* in range mode, button 1/2/3 press potentially selects a track */
346 if (mouse_mode == MouseRange &&
347 event->type == GDK_BUTTON_PRESS &&
348 event->button.button <= 3) {
355 case AutomationTrackItem:
356 set_selected_track_from_click (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift), true, true);
359 case AudioRegionViewNameHighlight:
360 case AudioRegionViewName:
361 rv = reinterpret_cast<AudioRegionView *> (gtk_object_get_data(GTK_OBJECT(item), "regionview"));
368 if (drag_info.item == 0 &&
369 (Keyboard::is_delete_event (&event->button) ||
370 Keyboard::is_context_menu_event (&event->button) ||
371 Keyboard::is_edit_event (&event->button))) {
373 /* handled by button release */
377 switch (event->button.button) {
380 if (event->type == GDK_BUTTON_PRESS) {
382 if (drag_info.item) {
383 gnome_canvas_item_ungrab (drag_info.item, event->button.time);
386 /* single mouse clicks on any of these item types operate
387 independent of mouse mode, mostly because they are
388 not on the main track canvas or because we want
394 case PlayheadCursorItem:
395 start_cursor_grab (item, event);
399 if (Keyboard::modifier_state_equals (event->button.state,
400 Keyboard::ModifierMask(Keyboard::Control|Keyboard::Shift))) {
401 hide_marker (item, event);
403 start_marker_grab (item, event);
407 case TempoMarkerItem:
408 start_tempo_marker_grab (item, event);
411 case MeterMarkerItem:
412 start_meter_marker_grab (item, event);
421 case RangeMarkerBarItem:
422 start_range_markerbar_op (item, event, CreateRangeMarker);
425 case TransportMarkerBarItem:
426 start_range_markerbar_op (item, event, CreateTransportMarker);
435 switch (mouse_mode) {
438 case StartSelectionTrimItem:
439 start_selection_op (item, event, SelectionStartTrim);
442 case EndSelectionTrimItem:
443 start_selection_op (item, event, SelectionEndTrim);
447 if (Keyboard::modifier_state_contains
448 (event->button.state, Keyboard::ModifierMask(Keyboard::Alt))) {
449 // contains and not equals because I can't use alt as a modifier alone.
450 start_selection_grab (item, event);
451 } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
452 /* grab selection for moving */
453 start_selection_op (item, event, SelectionMove);
456 /* this was debated, but decided the more common action was to
457 make a new selection */
458 start_selection_op (item, event, CreateSelection);
463 start_selection_op (item, event, CreateSelection);
469 if (Keyboard::modifier_state_contains (event->button.state,
470 Keyboard::ModifierMask(Keyboard::Control|Keyboard::Alt))
471 && event->type == GDK_BUTTON_PRESS) {
473 start_rubberband_select (item, event);
475 } else if (event->type == GDK_BUTTON_PRESS) {
478 case FadeInHandleItem:
479 start_fade_in_grab (item, event);
482 case FadeOutHandleItem:
483 start_fade_out_grab (item, event);
487 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
488 start_region_copy_grab (item, event);
489 } else if (Keyboard::the_keyboard().key_is_down (GDK_b)) {
490 start_region_brush_grab (item, event);
492 start_region_grab (item, event);
496 case AudioRegionViewNameHighlight:
497 start_trim (item, event);
501 case AudioRegionViewName:
502 /* rename happens on edit clicks */
503 start_trim (clicked_regionview->get_name_highlight(), event);
507 case GainAutomationControlPointItem:
508 case PanAutomationControlPointItem:
509 case RedirectAutomationControlPointItem:
510 start_control_point_grab (item, event);
514 case GainAutomationLineItem:
515 case PanAutomationLineItem:
516 case RedirectAutomationLineItem:
517 start_line_grab_from_line (item, event);
522 case AutomationTrackItem:
523 start_rubberband_select (item, event);
526 /* <CMT Additions> */
527 case ImageFrameHandleStartItem:
528 imageframe_start_handle_op(item, event) ;
531 case ImageFrameHandleEndItem:
532 imageframe_end_handle_op(item, event) ;
535 case MarkerViewHandleStartItem:
536 markerview_item_start_handle_op(item, event) ;
539 case MarkerViewHandleEndItem:
540 markerview_item_end_handle_op(item, event) ;
543 /* </CMT Additions> */
545 /* <CMT Additions> */
547 start_markerview_grab(item, event) ;
550 start_imageframe_grab(item, event) ;
552 /* </CMT Additions> */
564 // start_line_grab_from_regionview (item, event);
567 case GainControlPointItem:
568 start_control_point_grab (item, event);
572 start_line_grab_from_line (item, event);
575 case GainAutomationControlPointItem:
576 case PanAutomationControlPointItem:
577 case RedirectAutomationControlPointItem:
578 start_control_point_grab (item, event);
589 case GainAutomationControlPointItem:
590 case PanAutomationControlPointItem:
591 case RedirectAutomationControlPointItem:
592 start_control_point_grab (item, event);
595 case GainAutomationLineItem:
596 case PanAutomationLineItem:
597 case RedirectAutomationLineItem:
598 start_line_grab_from_line (item, event);
602 // XXX need automation mode to identify which
604 // start_line_grab_from_regionview (item, event);
614 if (event->type == GDK_BUTTON_PRESS) {
615 start_mouse_zoom (item, event);
622 if (item_type == RegionItem) {
623 start_time_fx (item, event);
628 /* handled in release */
637 switch (mouse_mode) {
639 if (event->type == GDK_BUTTON_PRESS) {
642 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
643 start_region_copy_grab (item, event);
645 start_region_grab (item, event);
649 case GainAutomationControlPointItem:
650 case PanAutomationControlPointItem:
651 case RedirectAutomationControlPointItem:
652 start_control_point_grab (item, event);
663 case AudioRegionViewNameHighlight:
664 start_trim (item, event);
668 case AudioRegionViewName:
669 start_trim (clicked_regionview->get_name_highlight(), event);
680 if (event->type == GDK_BUTTON_PRESS) {
681 /* relax till release */
688 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
689 temporal_zoom_session();
691 temporal_zoom_to_frame (true, event_frame(event));
706 switch (mouse_mode) {
708 //temporal_zoom_to_frame (true, where);
709 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
710 temporal_zoom_to_frame (true, where);
713 temporal_zoom_step (true);
718 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::Alt))) {
719 scroll_backward (0.6f);
721 else if (Keyboard::no_modifier_keys_pressed (&event->button)) {
722 scroll_tracks_up_line ();
724 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
725 if (clicked_trackview) {
726 if (!current_stepping_trackview) {
727 step_timeout = Glib::signal_timeout().connect (mem_fun(*this, &Editor::track_height_step_timeout), 500);
728 current_stepping_trackview = clicked_trackview;
730 gettimeofday (&last_track_height_step_timestamp, 0);
731 current_stepping_trackview->step_height (true);
734 else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
735 temporal_zoom_to_frame (true, where);
742 switch (mouse_mode) {
744 // temporal_zoom_to_frame (false, where);
745 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
746 temporal_zoom_to_frame (false, where);
749 temporal_zoom_step (false);
754 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::Alt))) {
755 scroll_forward (0.6f);
757 else if (Keyboard::no_modifier_keys_pressed (&event->button)) {
758 scroll_tracks_down_line ();
760 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
761 if (clicked_trackview) {
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_trackview;
766 gettimeofday (&last_track_height_step_timestamp, 0);
767 current_stepping_trackview->step_height (false);
769 } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
770 temporal_zoom_to_frame (false, where);
784 Editor::button_release_handler (GnomeCanvasItem* item, GdkEvent* event, ItemType item_type)
786 jack_nframes_t where = event_frame (event, 0, 0);
788 /* no action if we're recording */
790 if (session && session->actively_recording()) {
794 /* first, see if we're finishing a drag ... */
796 if (drag_info.item) {
797 if (end_grab (item, event)) {
798 /* grab dragged, so do nothing else */
803 /* edit events get handled here */
805 if (drag_info.item == 0 && Keyboard::is_edit_event (&event->button)) {
811 case TempoMarkerItem:
812 edit_tempo_marker (item);
815 case MeterMarkerItem:
816 edit_meter_marker (item);
819 case AudioRegionViewName:
820 if (clicked_regionview->name_active()) {
821 return mouse_rename_region (item, event);
831 /* context menu events get handled here */
833 if (Keyboard::is_context_menu_event (&event->button)) {
835 if (drag_info.item == 0) {
837 /* no matter which button pops up the context menu, tell the menu
838 widget to use button 1 to drive menu selection.
843 case FadeInHandleItem:
845 case FadeOutHandleItem:
846 popup_fade_context_menu (1, event->button.time, item, item_type);
850 popup_track_context_menu (1, event->button.time, item_type, false, where);
854 case AudioRegionViewNameHighlight:
855 case AudioRegionViewName:
856 popup_track_context_menu (1, event->button.time, item_type, false, where);
860 popup_track_context_menu (1, event->button.time, item_type, true, where);
863 case AutomationTrackItem:
864 popup_track_context_menu (1, event->button.time, item_type, false, where);
868 case RangeMarkerBarItem:
869 case TransportMarkerBarItem:
872 popup_ruler_menu (pixel_to_frame(event->button.x), item_type);
876 marker_context_menu (&event->button, item);
879 case TempoMarkerItem:
880 tm_marker_context_menu (&event->button, item);
883 case MeterMarkerItem:
884 tm_marker_context_menu (&event->button, item);
887 case CrossfadeViewItem:
888 popup_track_context_menu (1, event->button.time, item_type, false, where);
891 /* <CMT Additions> */
893 popup_imageframe_edit_menu(1, event->button.time, item, true) ;
895 case ImageFrameTimeAxisItem:
896 popup_imageframe_edit_menu(1, event->button.time, item, false) ;
899 popup_marker_time_axis_edit_menu(1, event->button.time, item, true) ;
901 case MarkerTimeAxisItem:
902 popup_marker_time_axis_edit_menu(1, event->button.time, item, false) ;
904 /* <CMT Additions> */
915 /* delete events get handled here */
917 if (drag_info.item == 0 && Keyboard::is_delete_event (&event->button)) {
920 case TempoMarkerItem:
921 remove_tempo_marker (item);
924 case MeterMarkerItem:
925 remove_meter_marker (item);
929 remove_marker (item, &event);
933 if (mouse_mode == MouseObject) {
934 remove_clicked_region ();
938 case GainControlPointItem:
939 if (mouse_mode == MouseGain) {
940 remove_gain_control_point (item, event);
944 case GainAutomationControlPointItem:
945 case PanAutomationControlPointItem:
946 case RedirectAutomationControlPointItem:
947 remove_control_point (item, event);
956 switch (event->button.button) {
960 /* see comments in button_press_handler */
962 case PlayheadCursorItem:
965 case GainAutomationLineItem:
966 case PanAutomationLineItem:
967 case RedirectAutomationLineItem:
968 case StartSelectionTrimItem:
969 case EndSelectionTrimItem:
973 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
974 snap_to (where, 0, true);
976 mouse_add_new_marker (where);
980 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
983 mouse_add_new_tempo_event (where);
987 mouse_add_new_meter_event (pixel_to_frame (event->button.x));
995 switch (mouse_mode) {
998 case AutomationTrackItem:
999 dynamic_cast<AutomationTimeAxisView*>(clicked_trackview)->add_automation_event
1013 switch (item_type) {
1015 clicked_regionview->add_gain_point_event (item, event);
1019 case AutomationTrackItem:
1020 dynamic_cast<AutomationTimeAxisView*>(clicked_trackview)->
1021 add_automation_event (item, event, where, event->button.y);
1030 switch (item_type) {
1032 audition_selected_region ();
1049 switch (mouse_mode) {
1052 switch (item_type) {
1054 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
1056 } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::ModifierMask (Keyboard::Shift|Keyboard::Alt))) {
1059 // Button2 click is unused
1072 // x_style_paste (where, 1.0);
1092 Editor::maybe_autoscroll (GdkEvent* event)
1094 jack_nframes_t one_page = (jack_nframes_t) rint (canvas_width * frames_per_unit);
1095 jack_nframes_t rightmost_frame = leftmost_frame + one_page;
1097 jack_nframes_t frame = drag_info.current_pointer_frame;
1099 if (autoscroll_timeout_tag < 0) {
1100 if (frame > rightmost_frame) {
1101 if (rightmost_frame < max_frames) {
1102 start_canvas_autoscroll (1);
1104 } else if (frame < leftmost_frame) {
1105 if (leftmost_frame > 0) {
1106 start_canvas_autoscroll (-1);
1110 if (frame >= leftmost_frame && frame < rightmost_frame) {
1111 stop_canvas_autoscroll ();
1117 Editor::enter_handler (GnomeCanvasItem* item, GdkEvent* event, ItemType item_type)
1123 switch (item_type) {
1124 case GainControlPointItem:
1125 if (mouse_mode == MouseGain) {
1126 cp = reinterpret_cast<ControlPoint*>(gtk_object_get_data (GTK_OBJECT(item), "control_point"));
1127 cp->set_visible (true);
1131 at_y = cp->get_y ();
1132 gnome_canvas_item_i2w (cp->item, &at_x, &at_y);
1136 fraction = 1.0 - (cp->get_y() / cp->line.height());
1138 set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y);
1139 show_verbose_canvas_cursor ();
1141 if (is_drawable()) {
1142 track_canvas_scroller.get_window()->set_cursor (*fader_cursor);
1147 case GainAutomationControlPointItem:
1148 case PanAutomationControlPointItem:
1149 case RedirectAutomationControlPointItem:
1150 cp = reinterpret_cast<ControlPoint*>(gtk_object_get_data (GTK_OBJECT(item), "control_point"));
1151 cp->set_visible (true);
1155 at_y = cp->get_y ();
1156 gnome_canvas_item_i2w (cp->item, &at_x, &at_y);
1160 fraction = 1.0 - (cp->get_y() / cp->line.height());
1162 set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y);
1163 show_verbose_canvas_cursor ();
1165 if (is_drawable()) {
1166 track_canvas_scroller.get_window()->set_cursor (*fader_cursor);
1171 if (mouse_mode == MouseGain) {
1172 gnome_canvas_item_set (item, "fill_color_rgba", color_map[cEnteredGainLine], NULL);
1173 if (is_drawable()) {
1174 track_canvas_scroller.get_window()->set_cursor (*fader_cursor);
1179 case GainAutomationLineItem:
1180 case RedirectAutomationLineItem:
1181 case PanAutomationLineItem:
1182 gnome_canvas_item_set (item, "fill_color_rgba", color_map[cEnteredAutomationLine], NULL);
1183 if (is_drawable()) {
1184 track_canvas_scroller.get_window()->set_cursor (*fader_cursor);
1188 case AudioRegionViewNameHighlight:
1189 if (is_drawable() && mouse_mode == MouseObject) {
1190 track_canvas_scroller.get_window()->set_cursor (*trimmer_cursor);
1194 case StartSelectionTrimItem:
1195 case EndSelectionTrimItem:
1196 /* <CMT Additions> */
1197 case ImageFrameHandleStartItem:
1198 case ImageFrameHandleEndItem:
1199 case MarkerViewHandleStartItem:
1200 case MarkerViewHandleEndItem:
1201 /* </CMT Additions> */
1203 if (is_drawable()) {
1204 track_canvas_scroller.get_window()->set_cursor (*trimmer_cursor);
1208 case EditCursorItem:
1209 case PlayheadCursorItem:
1210 if (is_drawable()) {
1211 track_canvas_scroller.get_window()->set_cursor (*grabber_cursor);
1215 case AudioRegionViewName:
1217 /* when the name is not an active item, the entire name highlight is for trimming */
1219 if (!reinterpret_cast<AudioRegionView *> (gtk_object_get_data(GTK_OBJECT(item), "regionview"))->name_active()) {
1220 if (mouse_mode == MouseObject && is_drawable()) {
1221 track_canvas_scroller.get_window()->set_cursor (*trimmer_cursor);
1227 case AutomationTrackItem:
1228 if (is_drawable()) {
1229 Gdk::Cursor *cursor;
1230 switch (mouse_mode) {
1232 cursor = selector_cursor;
1235 cursor = zoom_cursor;
1238 cursor = cross_hair_cursor;
1242 track_canvas_scroller.get_window()->set_cursor (*cursor);
1244 AutomationTimeAxisView* atv;
1245 if ((atv = static_cast<AutomationTimeAxisView*>(gtk_object_get_data(GTK_OBJECT(item), "trackview"))) != 0) {
1246 clear_entered_track = false;
1247 set_entered_track (atv);
1253 case RangeMarkerBarItem:
1254 case TransportMarkerBarItem:
1257 if (is_drawable()) {
1258 time_canvas_scroller.get_window()->set_cursor (*timebar_cursor);
1263 if ((marker = static_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "marker"))) == 0) {
1266 marker->set_color_rgba (color_map[cEnteredMarker]);
1268 case MeterMarkerItem:
1269 case TempoMarkerItem:
1270 if (is_drawable()) {
1271 time_canvas_scroller.get_window()->set_cursor (*timebar_cursor);
1274 case FadeInHandleItem:
1275 case FadeOutHandleItem:
1276 if (mouse_mode == MouseObject) {
1277 gnome_canvas_item_set (item, "fill_color_rgba", 0, "outline_pixels", 1, NULL);
1285 /* second pass to handle entered track status in a comprehensible way.
1288 switch (item_type) {
1290 case GainAutomationLineItem:
1291 case RedirectAutomationLineItem:
1292 case PanAutomationLineItem:
1293 case GainControlPointItem:
1294 case GainAutomationControlPointItem:
1295 case PanAutomationControlPointItem:
1296 case RedirectAutomationControlPointItem:
1297 /* these do not affect the current entered track state */
1298 clear_entered_track = false;
1301 case AutomationTrackItem:
1302 /* handled above already */
1306 set_entered_track (0);
1314 Editor::leave_handler (GnomeCanvasItem* item, GdkEvent* event, ItemType item_type)
1320 AudioRegionView* rv;
1323 switch (item_type) {
1324 case GainControlPointItem:
1325 case GainAutomationControlPointItem:
1326 case PanAutomationControlPointItem:
1327 case RedirectAutomationControlPointItem:
1328 cp = reinterpret_cast<ControlPoint*>(gtk_object_get_data (GTK_OBJECT(item), "control_point"));
1329 if (cp->line.npoints() > 1) {
1330 if (!cp->selected) {
1331 cp->set_visible (false);
1335 if (is_drawable()) {
1336 track_canvas_scroller.get_window()->set_cursor (*current_canvas_cursor);
1339 hide_verbose_canvas_cursor ();
1342 case AudioRegionViewNameHighlight:
1343 case StartSelectionTrimItem:
1344 case EndSelectionTrimItem:
1345 case EditCursorItem:
1346 case PlayheadCursorItem:
1347 /* <CMT Additions> */
1348 case ImageFrameHandleStartItem:
1349 case ImageFrameHandleEndItem:
1350 case MarkerViewHandleStartItem:
1351 case MarkerViewHandleEndItem:
1352 /* </CMT Additions> */
1353 if (is_drawable()) {
1354 track_canvas_scroller.get_window()->set_cursor (*current_canvas_cursor);
1359 case GainAutomationLineItem:
1360 case RedirectAutomationLineItem:
1361 case PanAutomationLineItem:
1362 al = reinterpret_cast<AutomationLine*> (gtk_object_get_data (GTK_OBJECT(item),"line"));
1363 gnome_canvas_item_set (item, "fill_color_rgba", al->get_line_color(), NULL);
1364 if (is_drawable()) {
1365 track_canvas_scroller.get_window()->set_cursor (*current_canvas_cursor);
1369 case AudioRegionViewName:
1370 /* see enter_handler() for notes */
1371 if (!reinterpret_cast<AudioRegionView *> (gtk_object_get_data(GTK_OBJECT(item), "regionview"))->name_active()) {
1372 if (is_drawable() && mouse_mode == MouseObject) {
1373 track_canvas_scroller.get_window()->set_cursor (*current_canvas_cursor);
1378 case RangeMarkerBarItem:
1379 case TransportMarkerBarItem:
1383 if (is_drawable()) {
1384 time_canvas_scroller.get_window()->set_cursor (*timebar_cursor);
1389 if ((marker = static_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "marker"))) == 0) {
1392 loc = find_location_from_marker (marker, is_start);
1393 if (loc) location_flags_changed (loc, this);
1395 case MeterMarkerItem:
1396 case TempoMarkerItem:
1398 if (is_drawable()) {
1399 time_canvas_scroller.get_window()->set_cursor (*timebar_cursor);
1404 case FadeInHandleItem:
1405 case FadeOutHandleItem:
1406 rv = static_cast<AudioRegionView*>(gtk_object_get_data (GTK_OBJECT(item), "regionview"));
1407 gnome_canvas_item_set (item, "fill_color_rgba", rv->get_fill_color(), "outline_pixels", 0, NULL);
1410 case AutomationTrackItem:
1411 if (is_drawable()) {
1412 track_canvas_scroller.get_window()->set_cursor (*current_canvas_cursor);
1413 clear_entered_track = true;
1414 Glib::signal_idle().connect (mem_fun(*this, &Editor::left_automation_track));
1426 Editor::left_automation_track ()
1428 if (clear_entered_track) {
1429 set_entered_track (0);
1430 clear_entered_track = false;
1436 Editor::motion_handler (GnomeCanvasItem* item, GdkEvent* event, ItemType item_type)
1440 /* We call this so that MOTION_NOTIFY events continue to be
1441 delivered to the canvas. We need to do this because we set
1442 Gdk::POINTER_MOTION_HINT_MASK on the canvas. This reduces
1443 the density of the events, at the expense of a round-trip
1444 to the server. Given that this will mostly occur on cases
1445 where DISPLAY = :0.0, and given the cost of what the motion
1446 event might do, its a good tradeoff.
1449 track_canvas.get_pointer (x, y);
1451 if (current_stepping_trackview) {
1452 /* don't keep the persistent stepped trackview if the mouse moves */
1453 current_stepping_trackview = 0;
1454 step_timeout.disconnect ();
1457 if (session && session->actively_recording()) {
1458 /* Sorry. no dragging stuff around while we record */
1462 drag_info.current_pointer_frame = event_frame (event, &drag_info.current_pointer_x,
1463 &drag_info.current_pointer_y);
1464 if (drag_info.item) {
1465 /* item != 0 is the best test i can think of for
1468 if (!drag_info.move_threshold_passsed)
1470 drag_info.move_threshold_passsed = (abs ((int) (drag_info.current_pointer_x - drag_info.grab_x)) > 4);
1472 // and change the initial grab loc/frame if this drag info wants us to
1473 if (drag_info.want_move_threshold && drag_info.move_threshold_passsed) {
1474 drag_info.grab_frame = drag_info.current_pointer_frame;
1475 drag_info.grab_x = drag_info.current_pointer_x;
1476 drag_info.grab_y = drag_info.current_pointer_y;
1477 drag_info.last_pointer_frame = drag_info.grab_frame;
1478 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
1483 switch (item_type) {
1484 case PlayheadCursorItem:
1485 case EditCursorItem:
1487 case GainControlPointItem:
1488 case RedirectAutomationControlPointItem:
1489 case GainAutomationControlPointItem:
1490 case PanAutomationControlPointItem:
1491 case TempoMarkerItem:
1492 case MeterMarkerItem:
1493 case AudioRegionViewNameHighlight:
1494 case StartSelectionTrimItem:
1495 case EndSelectionTrimItem:
1498 case RedirectAutomationLineItem:
1499 case GainAutomationLineItem:
1500 case PanAutomationLineItem:
1501 case FadeInHandleItem:
1502 case FadeOutHandleItem:
1503 /* <CMT Additions> */
1504 case ImageFrameHandleStartItem:
1505 case ImageFrameHandleEndItem:
1506 case MarkerViewHandleStartItem:
1507 case MarkerViewHandleEndItem:
1508 /* </CMT Additions> */
1509 if (drag_info.item && (event->motion.state & GDK_BUTTON1_MASK ||
1510 (event->motion.state & GDK_BUTTON2_MASK))) {
1511 maybe_autoscroll (event);
1512 (this->*(drag_info.motion_callback)) (item, event);
1521 switch (mouse_mode) {
1526 if (drag_info.item && (event->motion.state & GDK_BUTTON1_MASK ||
1527 (event->motion.state & GDK_BUTTON2_MASK))) {
1528 maybe_autoscroll (event);
1529 (this->*(drag_info.motion_callback)) (item, event);
1540 track_canvas_motion (event);
1548 Editor::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
1550 if (drag_info.item == 0) {
1551 fatal << _("programming error: start_grab called without drag item") << endmsg;
1557 cursor = grabber_cursor;
1560 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
1562 if (event->button.button == 2) {
1563 drag_info.x_constrained = true;
1565 drag_info.x_constrained = false;
1568 drag_info.grab_frame = event_frame(event, &drag_info.grab_x, &drag_info.grab_y);
1569 drag_info.last_pointer_frame = drag_info.grab_frame;
1570 drag_info.current_pointer_frame = drag_info.grab_frame;
1571 drag_info.current_pointer_x = drag_info.grab_x;
1572 drag_info.current_pointer_y = drag_info.grab_y;
1573 drag_info.cumulative_x_drag = 0;
1574 drag_info.cumulative_y_drag = 0;
1575 drag_info.first_move = true;
1576 drag_info.move_threshold_passsed = false;
1577 drag_info.want_move_threshold = false;
1578 drag_info.pointer_frame_offset = 0;
1579 drag_info.brushing = false;
1580 drag_info.copied_location = 0;
1582 gnome_canvas_item_grab (drag_info.item,
1583 Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
1585 event->button.time);
1586 //drag_info.item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
1588 // event->button.time);
1590 if (session && session->transport_rolling()) {
1591 drag_info.was_rolling = true;
1593 drag_info.was_rolling = false;
1596 switch (snap_type) {
1597 case SnapToRegionStart:
1598 case SnapToRegionEnd:
1599 case SnapToRegionSync:
1600 case SnapToRegionBoundary:
1601 build_region_boundary_cache ();
1609 Editor::end_grab (GnomeCanvasItem* item, GdkEvent* event)
1611 bool did_drag = false;
1613 stop_canvas_autoscroll ();
1615 if (drag_info.item == 0) {
1619 gnome_canvas_item_ungrab (drag_info.item, event->button.time);
1621 if (drag_info.finished_callback) {
1622 (this->*(drag_info.finished_callback)) (item, event);
1625 did_drag = !drag_info.first_move;
1627 hide_verbose_canvas_cursor();
1630 drag_info.copy = false;
1631 drag_info.motion_callback = 0;
1632 drag_info.finished_callback = 0;
1633 drag_info.last_trackview = 0;
1634 drag_info.last_frame_position = 0;
1635 drag_info.grab_frame = 0;
1636 drag_info.last_pointer_frame = 0;
1637 drag_info.current_pointer_frame = 0;
1638 drag_info.brushing = false;
1640 if (drag_info.copied_location) {
1641 delete drag_info.copied_location;
1642 drag_info.copied_location = 0;
1649 Editor::set_edit_cursor (GdkEvent* event)
1651 jack_nframes_t pointer_frame = event_frame (event);
1653 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1654 if (snap_type != SnapToEditCursor) {
1655 snap_to (pointer_frame);
1659 edit_cursor->set_position (pointer_frame);
1660 edit_cursor_clock.set (pointer_frame);
1664 Editor::set_playhead_cursor (GdkEvent* event)
1666 jack_nframes_t pointer_frame = event_frame (event);
1668 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1669 snap_to (pointer_frame);
1673 session->request_locate (pointer_frame, session->transport_rolling());
1678 Editor::start_fade_in_grab (GnomeCanvasItem* item, GdkEvent* event)
1680 drag_info.item = item;
1681 drag_info.motion_callback = &Editor::fade_in_drag_motion_callback;
1682 drag_info.finished_callback = &Editor::fade_in_drag_finished_callback;
1686 if ((drag_info.data = (gtk_object_get_data (GTK_OBJECT(item), "regionview"))) == 0) {
1687 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1691 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1693 drag_info.pointer_frame_offset = drag_info.grab_frame - ((jack_nframes_t) arv->region.fade_in().back()->when + arv->region.position());
1697 Editor::fade_in_drag_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
1699 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1701 jack_nframes_t fade_length;
1703 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1704 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1710 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1714 if (pos < (arv->region.position() + 64)) {
1715 fade_length = 64; // this should be a minimum defined somewhere
1716 } else if (pos > arv->region.last_frame()) {
1717 fade_length = arv->region.length();
1719 fade_length = pos - arv->region.position();
1722 arv->reset_fade_in_shape_width (fade_length);
1724 show_verbose_duration_cursor (arv->region.position(), arv->region.position() + fade_length, 10);
1726 drag_info.first_move = false;
1730 Editor::fade_in_drag_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
1732 if (drag_info.first_move) return;
1734 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1736 jack_nframes_t fade_length;
1738 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1739 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1745 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1749 if (pos < (arv->region.position() + 64)) {
1750 fade_length = 64; // this should be a minimum defined somewhere
1752 else if (pos > arv->region.last_frame()) {
1753 fade_length = arv->region.length();
1756 fade_length = pos - arv->region.position();
1759 begin_reversible_command (_("change fade in length"));
1760 session->add_undo (arv->region.get_memento());
1761 arv->region.set_fade_in_length (fade_length);
1762 session->add_redo_no_execute (arv->region.get_memento());
1763 commit_reversible_command ();
1764 fade_in_drag_motion_callback (item, event);
1768 Editor::start_fade_out_grab (GnomeCanvasItem* item, GdkEvent* event)
1770 drag_info.item = item;
1771 drag_info.motion_callback = &Editor::fade_out_drag_motion_callback;
1772 drag_info.finished_callback = &Editor::fade_out_drag_finished_callback;
1776 if ((drag_info.data = (gtk_object_get_data (GTK_OBJECT(item), "regionview"))) == 0) {
1777 fatal << _("programming error: fade out canvas item has no regionview data pointer!") << endmsg;
1781 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1783 drag_info.pointer_frame_offset = drag_info.grab_frame - (arv->region.length() - (jack_nframes_t) arv->region.fade_out().back()->when + arv->region.position());
1787 Editor::fade_out_drag_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
1789 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1791 jack_nframes_t fade_length;
1793 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1794 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1800 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1804 if (pos > (arv->region.last_frame() - 64)) {
1805 fade_length = 64; // this should really be a minimum fade defined somewhere
1807 else if (pos < arv->region.position()) {
1808 fade_length = arv->region.length();
1811 fade_length = arv->region.last_frame() - pos;
1814 arv->reset_fade_out_shape_width (fade_length);
1816 show_verbose_duration_cursor (arv->region.last_frame() - fade_length, arv->region.last_frame(), 10);
1818 drag_info.first_move = false;
1822 Editor::fade_out_drag_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
1824 if (drag_info.first_move) return;
1826 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1828 jack_nframes_t fade_length;
1830 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1831 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1837 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1841 if (pos > (arv->region.last_frame() - 64)) {
1842 fade_length = 64; // this should really be a minimum fade defined somewhere
1844 else if (pos < arv->region.position()) {
1845 fade_length = arv->region.length();
1848 fade_length = arv->region.last_frame() - pos;
1851 begin_reversible_command (_("change fade out length"));
1852 session->add_undo (arv->region.get_memento());
1853 arv->region.set_fade_out_length (fade_length);
1854 session->add_redo_no_execute (arv->region.get_memento());
1855 commit_reversible_command ();
1857 fade_out_drag_motion_callback (item, event);
1861 Editor::start_cursor_grab (GnomeCanvasItem* item, GdkEvent* event)
1863 drag_info.item = item;
1864 drag_info.motion_callback = &Editor::cursor_drag_motion_callback;
1865 drag_info.finished_callback = &Editor::cursor_drag_finished_callback;
1869 if ((drag_info.data = (gtk_object_get_data (GTK_OBJECT(item), "cursor"))) == 0) {
1870 fatal << _("programming error: cursor canvas item has no cursor data pointer!") << endmsg;
1874 Cursor* cursor = (Cursor *) drag_info.data;
1876 if (session && cursor == playhead_cursor) {
1877 if (drag_info.was_rolling) {
1878 session->request_stop ();
1882 drag_info.pointer_frame_offset = drag_info.grab_frame - cursor->current_frame;
1884 show_verbose_time_cursor (cursor->current_frame, 10);
1888 Editor::cursor_drag_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
1890 Cursor* cursor = (Cursor *) drag_info.data;
1891 jack_nframes_t adjusted_frame;
1893 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1894 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1900 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1901 if (cursor != edit_cursor || snap_type != SnapToEditCursor) {
1902 snap_to (adjusted_frame);
1906 if (adjusted_frame == drag_info.last_pointer_frame) return;
1908 cursor->set_position (adjusted_frame);
1910 if (cursor == edit_cursor) {
1911 edit_cursor_clock.set (cursor->current_frame);
1914 show_verbose_time_cursor (cursor->current_frame, 10);
1916 drag_info.last_pointer_frame = adjusted_frame;
1917 drag_info.first_move = false;
1921 Editor::cursor_drag_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
1923 if (drag_info.first_move) return;
1925 cursor_drag_motion_callback (item, event);
1927 if (item == playhead_cursor->canvas_item) {
1929 session->request_locate (playhead_cursor->current_frame, drag_info.was_rolling);
1931 } else if (item == edit_cursor->canvas_item) {
1932 edit_cursor->set_position (edit_cursor->current_frame);
1933 edit_cursor_clock.set (edit_cursor->current_frame);
1938 Editor::update_marker_drag_item (Location *location)
1940 double x1 = frame_to_pixel (location->start());
1941 double x2 = frame_to_pixel (location->end());
1943 if (location->is_mark()) {
1944 marker_drag_line_points->coords[0] = x1;
1945 marker_drag_line_points->coords[2] = x1;
1946 marker_drag_line->set_property ("points", marker_drag_line_points);
1949 range_marker_drag_rect->set_property ("x1", x1);
1950 range_marker_drag_rect->set_property ("x2", x2);
1955 Editor::start_marker_grab (GnomeCanvasItem* item, GdkEvent* event)
1959 if ((marker = static_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "marker"))) == 0) {
1960 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
1966 Location *location = find_location_from_marker (marker, is_start);
1968 drag_info.item = item;
1969 drag_info.data = marker;
1970 drag_info.motion_callback = &Editor::marker_drag_motion_callback;
1971 drag_info.finished_callback = &Editor::marker_drag_finished_callback;
1975 drag_info.copied_location = new Location (*location);
1976 drag_info.pointer_frame_offset = drag_info.grab_frame - (is_start ? location->start() : location->end());
1978 update_marker_drag_item (location);
1980 if (location->is_mark()) {
1981 marker_drag_line->show();
1982 marker_drag_line->raise_to_top();
1985 range_marker_drag_rect->show();
1986 range_marker_drag_rect->raise_to_top();
1989 if (is_start) show_verbose_time_cursor (location->start(), 10);
1990 else show_verbose_time_cursor (location->end(), 10);
1994 Editor::marker_drag_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
1996 jack_nframes_t f_delta;
1997 Marker* marker = (Marker *) drag_info.data;
1998 Location *real_location;
1999 Location *copy_location;
2001 bool move_both = false;
2003 jack_nframes_t newframe;
2004 if (drag_info.pointer_frame_offset <= (long) drag_info.current_pointer_frame) {
2005 newframe = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2011 jack_nframes_t next = newframe;
2013 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2014 snap_to (newframe, 0, true);
2017 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) return;
2019 /* call this to find out if its the start or end */
2021 real_location = find_location_from_marker (marker, is_start);
2023 /* use the copy that we're "dragging" around */
2025 copy_location = drag_info.copied_location;
2027 f_delta = copy_location->end() - copy_location->start();
2029 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
2033 if (is_start) { // start marker
2036 copy_location->set_start (newframe);
2037 copy_location->set_end (newframe + f_delta);
2038 } else if (newframe < copy_location->end()) {
2039 copy_location->set_start (newframe);
2041 snap_to (next, 1, true);
2042 copy_location->set_end (next);
2043 copy_location->set_start (newframe);
2046 } else { // end marker
2049 copy_location->set_end (newframe);
2050 copy_location->set_start (newframe - f_delta);
2051 } else if (newframe > copy_location->start()) {
2052 copy_location->set_end (newframe);
2054 } else if (newframe > 0) {
2055 snap_to (next, -1, true);
2056 copy_location->set_start (next);
2057 copy_location->set_end (newframe);
2061 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
2062 drag_info.first_move = false;
2064 update_marker_drag_item (copy_location);
2066 LocationMarkers* lm = find_location_markers (real_location);
2067 lm->set_position (copy_location->start(), copy_location->end());
2069 show_verbose_time_cursor (newframe, 10);
2073 Editor::marker_drag_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
2075 if (drag_info.first_move) {
2076 marker_drag_motion_callback (item, event);
2080 Marker* marker = (Marker *) drag_info.data;
2082 Location * location = find_location_from_marker (marker, is_start);
2084 location->set (drag_info.copied_location->start(), drag_info.copied_location->end());
2087 marker_drag_line->hide();
2088 range_marker_drag_rect->hide();
2092 Editor::start_meter_marker_grab (GnomeCanvasItem* item, GdkEvent* event)
2095 MeterMarker* meter_marker;
2097 if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "marker"))) == 0) {
2098 fatal << _("programming error: meter marker canvas item has no marker object pointer!") << endmsg;
2102 meter_marker = dynamic_cast<MeterMarker*> (marker);
2104 MetricSection& section (meter_marker->meter());
2106 if (!section.movable()) {
2110 drag_info.item = item;
2111 drag_info.data = marker;
2112 drag_info.motion_callback = &Editor::meter_marker_drag_motion_callback;
2113 drag_info.finished_callback = &Editor::meter_marker_drag_finished_callback;
2117 drag_info.pointer_frame_offset = drag_info.grab_frame - meter_marker->meter().frame();
2119 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2123 Editor::meter_marker_drag_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
2125 MeterMarker* marker = (MeterMarker *) drag_info.data;
2126 jack_nframes_t adjusted_frame;
2128 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
2129 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2135 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2136 snap_to (adjusted_frame);
2139 if (adjusted_frame == drag_info.last_pointer_frame) return;
2141 marker->set_position (adjusted_frame);
2144 drag_info.last_pointer_frame = adjusted_frame;
2145 drag_info.first_move = false;
2147 show_verbose_time_cursor (adjusted_frame, 10);
2151 Editor::meter_marker_drag_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
2153 if (drag_info.first_move) return;
2155 meter_marker_drag_motion_callback (item, event);
2157 MeterMarker* marker = (MeterMarker *) drag_info.data;
2160 TempoMap& map (session->tempo_map());
2161 map.bbt_time (drag_info.last_pointer_frame, when);
2163 begin_reversible_command (_("move meter mark"));
2164 session->add_undo (map.get_memento());
2165 map.move_meter (marker->meter(), when);
2166 session->add_redo_no_execute (map.get_memento());
2167 commit_reversible_command ();
2171 Editor::start_tempo_marker_grab (GnomeCanvasItem* item, GdkEvent* event)
2174 TempoMarker* tempo_marker;
2176 if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "tempo_marker"))) == 0) {
2177 fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg;
2181 if ((tempo_marker = dynamic_cast<TempoMarker *> (marker)) == 0) {
2182 fatal << _("programming error: marker for tempo is not a tempo marker!") << endmsg;
2186 MetricSection& section (tempo_marker->tempo());
2188 if (!section.movable()) {
2192 drag_info.item = item;
2193 drag_info.data = marker;
2194 drag_info.motion_callback = &Editor::tempo_marker_drag_motion_callback;
2195 drag_info.finished_callback = &Editor::tempo_marker_drag_finished_callback;
2199 drag_info.pointer_frame_offset = drag_info.grab_frame - tempo_marker->tempo().frame();
2200 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2204 Editor::tempo_marker_drag_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
2206 TempoMarker* marker = (TempoMarker *) drag_info.data;
2207 jack_nframes_t adjusted_frame;
2209 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
2210 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2216 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2217 snap_to (adjusted_frame);
2220 if (adjusted_frame == drag_info.last_pointer_frame) return;
2222 /* OK, we've moved far enough to make it worth actually move the thing. */
2224 marker->set_position (adjusted_frame);
2226 show_verbose_time_cursor (adjusted_frame, 10);
2228 drag_info.last_pointer_frame = adjusted_frame;
2229 drag_info.first_move = false;
2233 Editor::tempo_marker_drag_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
2235 if (drag_info.first_move) return;
2237 tempo_marker_drag_motion_callback (item, event);
2239 TempoMarker* marker = (TempoMarker *) drag_info.data;
2242 TempoMap& map (session->tempo_map());
2243 map.bbt_time (drag_info.last_pointer_frame, when);
2245 begin_reversible_command (_("move tempo mark"));
2246 session->add_undo (map.get_memento());
2247 map.move_tempo (marker->tempo(), when);
2248 session->add_redo_no_execute (map.get_memento());
2249 commit_reversible_command ();
2253 Editor::remove_gain_control_point (GnomeCanvasItem*item, GdkEvent* event)
2255 ControlPoint* control_point;
2257 if ((control_point = reinterpret_cast<ControlPoint *> (gtk_object_get_data (GTK_OBJECT(item), "control_point"))) == 0) {
2258 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2262 // We shouldn't remove the first or last gain point
2263 if (control_point->line.is_last_point(*control_point) ||
2264 control_point->line.is_first_point(*control_point)) {
2268 control_point->line.remove_point (*control_point);
2272 Editor::remove_control_point (GnomeCanvasItem*item, GdkEvent* event)
2274 ControlPoint* control_point;
2276 if ((control_point = reinterpret_cast<ControlPoint *> (gtk_object_get_data (GTK_OBJECT(item), "control_point"))) == 0) {
2277 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2281 control_point->line.remove_point (*control_point);
2285 Editor::start_control_point_grab (GnomeCanvasItem* item, GdkEvent* event)
2287 ControlPoint* control_point;
2289 if ((control_point = reinterpret_cast<ControlPoint *> (gtk_object_get_data (GTK_OBJECT(item), "control_point"))) == 0) {
2290 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2294 drag_info.item = item;
2295 drag_info.data = control_point;
2296 drag_info.motion_callback = &Editor::control_point_drag_motion_callback;
2297 drag_info.finished_callback = &Editor::control_point_drag_finished_callback;
2299 start_grab (event, fader_cursor);
2301 control_point->line.start_drag (control_point, 0);
2303 float fraction = 1.0 - (control_point->get_y() / control_point->line.height());
2304 set_verbose_canvas_cursor (control_point->line.get_verbose_cursor_string (fraction),
2305 drag_info.current_pointer_x + 20, drag_info.current_pointer_y + 20);
2307 show_verbose_canvas_cursor ();
2311 Editor::control_point_drag_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
2313 ControlPoint* cp = reinterpret_cast<ControlPoint *> (drag_info.data);
2315 double cx = drag_info.current_pointer_x;
2316 double cy = drag_info.current_pointer_y;
2318 drag_info.cumulative_x_drag = cx - drag_info.grab_x ;
2319 drag_info.cumulative_y_drag = cy - drag_info.grab_y ;
2321 bool x_constrained = false;
2323 if (drag_info.x_constrained) {
2324 if (fabs(drag_info.cumulative_x_drag) < fabs(drag_info.cumulative_y_drag)) {
2325 cx = drag_info.grab_x;
2326 x_constrained = true;
2329 cy = drag_info.grab_y;
2334 gnome_canvas_item_w2i (cp->line.parent_group(), &cx, &cy);
2338 cy = min ((double) cp->line.height(), cy);
2340 //translate cx to frames
2341 jack_nframes_t cx_frames = (jack_nframes_t) floor (cx * frames_per_unit);
2343 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && !x_constrained) {
2344 snap_to (cx_frames);
2347 float fraction = 1.0 - (cy / cp->line.height());
2351 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
2357 cp->line.point_drag (*cp, cx_frames , fraction, push);
2359 set_verbose_canvas_cursor_text (cp->line.get_verbose_cursor_string (fraction));
2363 Editor::control_point_drag_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
2365 ControlPoint* cp = reinterpret_cast<ControlPoint *> (drag_info.data);
2366 control_point_drag_motion_callback (item, event);
2367 cp->line.end_drag (cp);
2371 Editor::start_line_grab_from_regionview (GnomeCanvasItem* item, GdkEvent* event)
2373 switch (mouse_mode) {
2375 start_line_grab (clicked_regionview->get_gain_line(), event);
2383 Editor::start_line_grab_from_line (GnomeCanvasItem* item, GdkEvent* event)
2387 if ((al = reinterpret_cast<AutomationLine*> (gtk_object_get_data (GTK_OBJECT(item), "line"))) == 0) {
2388 fatal << _("programming error: line canvas item has no line pointer!") << endmsg;
2392 start_line_grab (al, event);
2396 Editor::start_line_grab (AutomationLine* line, GdkEvent* event)
2400 jack_nframes_t frame_within_region;
2402 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2406 cx = event->button.x;
2407 cy = event->button.y;
2408 gnome_canvas_item_w2i (line->parent_group(), &cx, &cy);
2409 frame_within_region = (jack_nframes_t) floor (cx * frames_per_unit);
2411 if (!line->control_points_adjacent (frame_within_region, current_line_drag_info.before,
2412 current_line_drag_info.after)) {
2413 /* no adjacent points */
2417 drag_info.item = line->grab_item();
2418 drag_info.data = line;
2419 drag_info.motion_callback = &Editor::line_drag_motion_callback;
2420 drag_info.finished_callback = &Editor::line_drag_finished_callback;
2422 start_grab (event, fader_cursor);
2424 double fraction = 1.0 - (cy / line->height());
2426 line->start_drag (0, fraction);
2428 set_verbose_canvas_cursor (line->get_verbose_cursor_string (fraction),
2429 drag_info.current_pointer_x + 20, drag_info.current_pointer_y + 20);
2430 show_verbose_canvas_cursor ();
2434 Editor::line_drag_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
2436 AutomationLine* line = reinterpret_cast<AutomationLine *> (drag_info.data);
2437 double cx = drag_info.current_pointer_x;
2438 double cy = drag_info.current_pointer_y;
2440 gnome_canvas_item_w2i (line->parent_group(), &cx, &cy);
2443 fraction = 1.0 - (cy / line->height());
2447 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
2453 line->line_drag (current_line_drag_info.before, current_line_drag_info.after, fraction, push);
2455 set_verbose_canvas_cursor_text (line->get_verbose_cursor_string (fraction));
2459 Editor::line_drag_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
2461 AutomationLine* line = reinterpret_cast<AutomationLine *> (drag_info.data);
2462 line_drag_motion_callback (item, event);
2467 Editor::start_region_grab (GnomeCanvasItem* item, GdkEvent* event)
2469 if (selection->audio_regions.empty() || clicked_regionview == 0) {
2473 drag_info.copy = false;
2474 drag_info.item = item;
2475 drag_info.data = clicked_regionview;
2476 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2477 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2482 TimeAxisView* tvp = clicked_trackview;
2483 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
2485 if (tv && tv->is_audio_track()) {
2486 speed = tv->get_diskstream()->speed();
2489 drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region.position() / speed);
2490 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2491 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2492 // we want a move threshold
2493 drag_info.want_move_threshold = true;
2495 show_verbose_time_cursor (drag_info.last_frame_position, 10);
2497 begin_reversible_command (_("move region(s)"));
2501 Editor::start_region_copy_grab (GnomeCanvasItem* item, GdkEvent* event)
2503 if (selection->audio_regions.empty() || clicked_regionview == 0) {
2507 /* this is committed in the grab finished callback. */
2509 begin_reversible_command (_("Drag region copy"));
2511 /* duplicate the region(s) */
2513 vector<AudioRegionView*> new_regionviews;
2515 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
2516 AudioRegionView* rv;
2520 Playlist* to_playlist = rv->region.playlist();
2521 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&rv->get_time_axis_view());
2523 session->add_undo (to_playlist->get_memento ());
2524 latest_regionview = 0;
2526 sigc::connection c = atv->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
2528 /* create a new region with the same name.
2531 AudioRegion* newregion = new AudioRegion (rv->region);
2533 /* if the original region was locked, we don't care */
2535 newregion->set_locked (false);
2537 to_playlist->add_region (*newregion, (jack_nframes_t) (rv->region.position() * atv->get_diskstream()->speed()));
2541 if (latest_regionview) {
2542 new_regionviews.push_back (latest_regionview);
2547 if (new_regionviews.empty()) {
2551 /* reset selection to new regionviews */
2553 selection->set (new_regionviews);
2555 drag_info.item = new_regionviews.front()->get_canvas_group ();
2556 drag_info.copy = true;
2557 drag_info.data = new_regionviews.front();
2558 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2559 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2563 TimeAxisView* tv = &clicked_regionview->get_time_axis_view();
2564 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(tv);
2567 if (atv && atv->is_audio_track()) {
2568 speed = atv->get_diskstream()->speed();
2571 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2572 drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region.position() / speed);
2573 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2574 // we want a move threshold
2575 drag_info.want_move_threshold = true;
2577 show_verbose_time_cursor (drag_info.last_frame_position, 10);
2579 begin_reversible_command (_("copy region(s)"));
2583 Editor::start_region_brush_grab (GnomeCanvasItem* item, GdkEvent* event)
2585 if (selection->audio_regions.empty() || clicked_regionview == 0) {
2589 drag_info.copy = false;
2590 drag_info.item = item;
2591 drag_info.data = clicked_regionview;
2592 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2593 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2598 TimeAxisView* tvp = clicked_trackview;
2599 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
2601 if (tv && tv->is_audio_track()) {
2602 speed = tv->get_diskstream()->speed();
2605 drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region.position() / speed);
2606 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2607 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2608 // we want a move threshold
2609 drag_info.want_move_threshold = true;
2610 drag_info.brushing = true;
2612 begin_reversible_command (_("Drag region brush"));
2616 Editor::region_drag_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
2620 AudioRegionView *rv = reinterpret_cast<AudioRegionView*> (drag_info.data);
2621 jack_nframes_t pending_region_position = 0;
2622 int32_t pointer_y_span = 0, canvas_pointer_y_span = 0, original_pointer_order;
2623 int32_t visible_y_high = 0, visible_y_low = 512; //high meaning higher numbered.. not the height on the screen
2624 bool clamp_y_axis = false;
2625 vector<int32_t> height_list(512) ;
2626 vector<int32_t>::iterator j;
2628 /* Which trackview is this ? */
2630 TimeAxisView* tvp = trackview_by_y_position (drag_info.current_pointer_y);
2631 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
2633 /* The region motion is only processed if the pointer is over
2637 if (!tv || !tv->is_audio_track()) {
2638 /* To make sure we hide the verbose canvas cursor when the mouse is
2639 not held over and audiotrack.
2641 hide_verbose_canvas_cursor ();
2645 original_pointer_order = drag_info.last_trackview->order;
2647 /************************************************************
2649 ************************************************************/
2651 if (drag_info.brushing) {
2652 clamp_y_axis = true;
2657 if ((pointer_y_span = (drag_info.last_trackview->order - tv->order)) != 0) {
2659 int32_t children = 0, numtracks = 0;
2660 bitset <512> tracks (0x00);
2661 /* get a bitmask representing the visible tracks */
2663 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2664 TimeAxisView *tracklist_timeview;
2665 tracklist_timeview = (*i);
2666 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tracklist_timeview);
2667 list<TimeAxisView*> children_list;
2669 /* zeroes are audio tracks. ones are other types. */
2671 if (!atv2->hidden()) {
2673 if (visible_y_high < atv2->order) {
2674 visible_y_high = atv2->order;
2676 if (visible_y_low > atv2->order) {
2677 visible_y_low = atv2->order;
2680 if (!atv2->is_audio_track()) {
2681 tracks = tracks |= (0x01 << atv2->order);
2684 height_list[atv2->order] = (*i)->height;
2686 if ((children_list = atv2->get_child_list()).size() > 0) {
2687 for (list<TimeAxisView*>::iterator j = children_list.begin(); j != children_list.end(); ++j) {
2688 tracks = tracks |= (0x01 << (atv2->order + children));
2689 height_list[atv2->order + children] = (*j)->height;
2697 /* find the actual span according to the canvas */
2699 canvas_pointer_y_span = pointer_y_span;
2700 if (drag_info.last_trackview->order >= tv->order) {
2702 for (y = tv->order; y < drag_info.last_trackview->order; y++) {
2703 if (height_list[y] == 0 ) {
2704 canvas_pointer_y_span--;
2709 for (y = drag_info.last_trackview->order;y <= tv->order; y++) {
2710 if ( height_list[y] == 0 ) {
2711 canvas_pointer_y_span++;
2716 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
2717 AudioRegionView* rv2;
2719 double ix1, ix2, iy1, iy2;
2722 gnome_canvas_item_get_bounds (rv2->get_canvas_frame(), &ix1, &iy1, &ix2, &iy2);
2723 gnome_canvas_item_i2w (rv2->get_canvas_group(), &ix1, &iy1);
2724 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
2725 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2);
2727 if (atv2->order != original_pointer_order) {
2728 /* this isn't the pointer track */
2730 if (canvas_pointer_y_span > 0) {
2732 /* moving up the canvas */
2733 if ((atv2->order - canvas_pointer_y_span) >= visible_y_low) {
2735 int32_t visible_tracks = 0;
2736 while (visible_tracks < canvas_pointer_y_span ) {
2739 while (height_list[atv2->order - (visible_tracks - n)] == 0) {
2740 /* we're passing through a hidden track */
2745 if (tracks[atv2->order - (canvas_pointer_y_span - n)] != 0x00) {
2746 clamp_y_axis = true;
2750 clamp_y_axis = true;
2753 } else if (canvas_pointer_y_span < 0) {
2755 /*moving down the canvas*/
2757 if ((atv2->order - (canvas_pointer_y_span - n)) <= visible_y_high) { // we will overflow
2760 int32_t visible_tracks = 0;
2762 while (visible_tracks > canvas_pointer_y_span ) {
2765 while (height_list[atv2->order - (visible_tracks - n)] == 0) {
2769 if ( tracks[atv2->order - ( canvas_pointer_y_span - n)] != 0x00) {
2770 clamp_y_axis = true;
2775 clamp_y_axis = true;
2781 /* this is the pointer's track */
2782 if ((atv2->order - pointer_y_span) > visible_y_high) { // we will overflow
2783 clamp_y_axis = true;
2784 } else if ((atv2->order - pointer_y_span) < visible_y_low) { // we will underflow
2785 clamp_y_axis = true;
2793 } else if (drag_info.last_trackview == tv) {
2794 clamp_y_axis = true;
2798 if (!clamp_y_axis) {
2799 drag_info.last_trackview = tv;
2802 /************************************************************
2804 ************************************************************/
2806 /* compute the amount of pointer motion in frames, and where
2807 the region would be if we moved it by that much.
2810 if (drag_info.move_threshold_passsed) {
2812 if ((int32_t)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
2814 jack_nframes_t sync_frame;
2815 jack_nframes_t sync_offset;
2818 pending_region_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2820 sync_offset = rv->region.sync_offset (sync_dir);
2821 sync_frame = rv->region.adjust_to_sync (pending_region_position);
2823 /* we snap if the snap modifier is not enabled.
2826 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2827 snap_to (sync_frame);
2830 if (sync_frame - sync_offset <= sync_frame) {
2831 pending_region_position = sync_frame - (sync_dir*sync_offset);
2833 pending_region_position = 0;
2837 pending_region_position = 0;
2840 if (pending_region_position > max_frames - rv->region.length()) {
2841 pending_region_position = drag_info.last_frame_position;
2844 // printf ("3: pending_region_position= %lu %lu\n", pending_region_position, drag_info.last_frame_position );
2846 if (pending_region_position != drag_info.last_frame_position && !drag_info.x_constrained) {
2848 /* now compute the canvas unit distance we need to move the regiondrag_info.last_trackview->order
2849 to make it appear at the new location.
2852 if (pending_region_position > drag_info.last_frame_position) {
2853 x_delta = ((double) (pending_region_position - drag_info.last_frame_position) / frames_per_unit);
2855 x_delta = -((double) (drag_info.last_frame_position - pending_region_position) / frames_per_unit);
2858 drag_info.last_frame_position = pending_region_position;
2865 /* threshold not passed */
2870 /*************************************************************
2872 ************************************************************/
2874 if (x_delta == 0 && (pointer_y_span == 0)) {
2875 /* haven't reached next snap point, and we're not switching
2876 trackviews. nothing to do.
2882 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
2884 AudioRegionView* rv2;
2887 /* if any regionview is at zero, we need to know so we can
2888 stop further leftward motion.
2891 double ix1, ix2, iy1, iy2;
2892 gnome_canvas_item_get_bounds (rv2->get_canvas_frame(), &ix1, &iy1, &ix2, &iy2);
2893 gnome_canvas_item_i2w (rv2->get_canvas_group(), &ix1, &iy1);
2902 /*************************************************************
2904 ************************************************************/
2906 pair<set<Playlist*>::iterator,bool> insert_result;
2908 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
2910 AudioRegionView* rv;
2912 double ix1, ix2, iy1, iy2;
2913 int32_t temp_pointer_y_span = pointer_y_span;
2915 /* get item BBox, which will be relative to parent. so we have
2916 to query on a child, then convert to world coordinates using
2920 gnome_canvas_item_get_bounds (rv->get_canvas_frame(), &ix1, &iy1, &ix2, &iy2);
2921 gnome_canvas_item_i2w (rv->get_canvas_group(), &ix1, &iy1);
2922 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
2923 AudioTimeAxisView* canvas_atv = dynamic_cast<AudioTimeAxisView*>(tvp2);
2924 AudioTimeAxisView* temp_atv;
2926 if ((pointer_y_span != 0) && !clamp_y_axis) {
2929 for (j = height_list.begin(); j!= height_list.end(); j++) {
2930 if (x == canvas_atv->order) {
2931 /* we found the track the region is on */
2932 if (x != original_pointer_order) {
2933 /*this isn't from the same track we're dragging from */
2934 temp_pointer_y_span = canvas_pointer_y_span;
2936 while (temp_pointer_y_span > 0) {
2937 /* we're moving up canvas-wise,
2938 so we need to find the next track height
2940 if (j != height_list.begin()) {
2943 if (x != original_pointer_order) {
2944 /* we're not from the dragged track, so ignore hidden tracks. */
2946 temp_pointer_y_span++;
2950 temp_pointer_y_span--;
2952 while (temp_pointer_y_span < 0) {
2954 if (x != original_pointer_order) {
2956 temp_pointer_y_span--;
2960 if (j != height_list.end()) {
2963 temp_pointer_y_span++;
2965 /* find out where we'll be when we move and set height accordingly */
2967 tvp2 = trackview_by_y_position (iy1 + y_delta);
2968 temp_atv = dynamic_cast<AudioTimeAxisView*>(tvp2);
2969 rv->set_height (temp_atv->height);
2971 /* if you un-comment the following, the region colours will follow the track colours whilst dragging,
2972 personally, i think this can confuse things, but never mind.
2975 //const GdkColor& col (temp_atv->view->get_region_color());
2976 //rv->set_color (const_cast<GdkColor&>(col));
2983 /* prevent the regionview from being moved to before
2984 the zero position on the canvas.
2989 if (-x_delta > ix1) {
2992 } else if ((x_delta > 0) &&(rv->region.last_frame() > max_frames - x_delta)) {
2993 x_delta = max_frames - rv->region.last_frame();
2996 if (drag_info.first_move) {
2998 /* hide any dependent views */
3000 // rv->get_time_axis_view().hide_dependent_views (*rv);
3002 /* this is subtle. raising the regionview itself won't help,
3003 because raise_to_top() just puts the item on the top of
3004 its parent's stack. so, we need to put the trackview canvas_display group
3005 on the top, since its parent is the whole canvas.
3008 gnome_canvas_item_raise_to_top (rv->get_canvas_group());
3009 gnome_canvas_item_raise_to_top (rv->get_time_axis_view().canvas_display);
3010 cursor_group->raise_to_top();
3012 /* freeze the playlists from notifying till
3016 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&rv->get_time_axis_view());
3017 if (atv && atv->is_audio_track()) {
3018 AudioPlaylist* pl = atv->get_diskstream()->playlist();
3020 /* only freeze and capture state once */
3022 insert_result = motion_frozen_playlists.insert (pl);
3023 if (insert_result.second) {
3025 session->add_undo(pl->get_memento());
3031 if (drag_info.brushing) {
3032 mouse_brush_insert_region (rv, pending_region_position);
3034 rv->move (x_delta, y_delta);
3038 if (drag_info.first_move) {
3039 cursor_group->raise_to_top();
3042 drag_info.first_move = false;
3044 if (x_delta != 0 && !drag_info.brushing) {
3045 show_verbose_time_cursor (drag_info.last_frame_position, 10);
3051 Editor::region_drag_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
3053 jack_nframes_t where;
3054 AudioRegionView* rv = reinterpret_cast<AudioRegionView *> (drag_info.data);
3055 pair<set<Playlist*>::iterator,bool> insert_result;
3056 bool nocommit = true;
3058 AudioTimeAxisView* atv;
3059 bool regionview_y_movement;
3060 bool regionview_x_movement;
3062 /* first_move is set to false if the regionview has been moved in the
3066 if (drag_info.first_move) {
3073 /* The regionview has been moved at some stage during the grab so we need
3074 to account for any mouse movement between this event and the last one.
3077 region_drag_motion_callback (item, event);
3079 if (drag_info.brushing) {
3080 /* all changes were made during motion event handlers */
3084 /* adjust for track speed */
3087 atv = dynamic_cast<AudioTimeAxisView*> (drag_info.last_trackview);
3088 if (atv && atv->get_diskstream()) {
3089 speed = atv->get_diskstream()->speed();
3092 regionview_x_movement = (drag_info.last_frame_position != (jack_nframes_t) (rv->region.position()/speed));
3093 regionview_y_movement = (drag_info.last_trackview != &rv->get_time_axis_view());
3095 //printf ("last_frame: %s position is %lu %g\n", rv->get_time_axis_view().name().c_str(), drag_info.last_frame_position, speed);
3096 //printf ("last_rackview: %s \n", drag_info.last_trackview->name().c_str());
3098 if (regionview_y_movement) {
3100 /* motion between tracks */
3102 list<AudioRegionView*> new_selection;
3104 /* moved to a different audio track. */
3106 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ) {
3108 AudioRegionView* rv2 = (*i);
3110 /* the region that used to be in the old playlist is not
3111 moved to the new one - we make a copy of it. as a result,
3112 any existing editor for the region should no longer be
3116 if (!drag_info.copy) {
3117 rv2->hide_region_editor();
3119 new_selection.push_back (rv2);
3123 /* first, freeze the target tracks */
3125 for (list<AudioRegionView*>::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) {
3127 Playlist* from_playlist;
3128 Playlist* to_playlist;
3130 double ix1, ix2, iy1, iy2;
3132 gnome_canvas_item_get_bounds ((*i)->get_canvas_frame(), &ix1, &iy1, &ix2, &iy2);
3133 gnome_canvas_item_i2w ((*i)->get_canvas_group(), &ix1, &iy1);
3134 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
3135 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2);
3137 from_playlist = (*i)->region.playlist();
3138 to_playlist = atv2->playlist();
3140 /* the from_playlist was frozen in the "first_move" case
3141 of the motion handler. the insert can fail,
3142 but that doesn't matter. it just means
3143 we already have the playlist in the list.
3146 motion_frozen_playlists.insert (from_playlist);
3148 /* only freeze the to_playlist once */
3150 insert_result = motion_frozen_playlists.insert(to_playlist);
3151 if (insert_result.second) {
3152 to_playlist->freeze();
3153 session->add_undo(to_playlist->get_memento());
3158 /* now do it again with the actual operations */
3160 for (list<AudioRegionView*>::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) {
3162 Playlist* from_playlist;
3163 Playlist* to_playlist;
3165 double ix1, ix2, iy1, iy2;
3167 gnome_canvas_item_get_bounds ((*i)->get_canvas_frame(), &ix1, &iy1, &ix2, &iy2);
3168 gnome_canvas_item_i2w ((*i)->get_canvas_group(), &ix1, &iy1);
3169 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
3170 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2);
3172 from_playlist = (*i)->region.playlist();
3173 to_playlist = atv2->playlist();
3175 latest_regionview = 0;
3177 where = (jack_nframes_t) (unit_to_frame (ix1) * speed);
3178 Region* new_region = createRegion ((*i)->region);
3180 from_playlist->remove_region (&((*i)->region));
3182 sigc::connection c = atv2->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3183 to_playlist->add_region (*new_region, where);
3186 if (latest_regionview) {
3187 selection->add (latest_regionview);
3193 /* motion within a single track */
3195 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
3199 if (rv->region.locked()) {
3203 if (regionview_x_movement) {
3204 double ownspeed = 1.0;
3205 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&(rv->get_time_axis_view()));
3207 if (atv && atv->get_diskstream()) {
3208 ownspeed = atv->get_diskstream()->speed();
3211 /* base the new region position on the current position of the regionview.*/
3213 double ix1, ix2, iy1, iy2;
3215 gnome_canvas_item_get_bounds (rv->get_canvas_frame(), &ix1, &iy1, &ix2, &iy2);
3216 gnome_canvas_item_i2w (rv->get_canvas_group(), &ix1, &iy1);
3217 where = (jack_nframes_t) (unit_to_frame (ix1) * ownspeed);
3221 where = rv->region.position();
3224 rv->get_time_axis_view().reveal_dependent_views (*rv);
3226 session->add_undo (rv->region.playlist()->get_memento());
3227 rv->region.set_position (where, (void *) this);
3232 for (set<Playlist*>::iterator p = motion_frozen_playlists.begin(); p != motion_frozen_playlists.end(); ++p) {
3234 session->add_redo_no_execute ((*p)->get_memento());
3237 motion_frozen_playlists.clear ();
3240 commit_reversible_command ();
3245 Editor::region_view_item_click (AudioRegionView& rv, GdkEventButton* event)
3247 /* Either add to or set the set the region selection, unless
3248 this is an alignment click (control used)
3251 if (Keyboard::modifier_state_contains (event->state, Keyboard::Control)) {
3252 TimeAxisView* tv = &rv.get_time_axis_view();
3253 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(tv);
3255 if (atv && atv->is_audio_track()) {
3256 speed = atv->get_diskstream()->speed();
3259 if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Alt))) {
3261 align_region (rv.region, SyncPoint, (jack_nframes_t) (edit_cursor->current_frame * speed));
3263 } else if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Shift))) {
3265 align_region (rv.region, End, (jack_nframes_t) (edit_cursor->current_frame * speed));
3269 align_region (rv.region, Start, (jack_nframes_t) (edit_cursor->current_frame * speed));
3275 Editor::show_verbose_time_cursor (jack_nframes_t frame, double offset, double xpos, double ypos)
3286 switch (ARDOUR_UI::instance()->secondary_clock.mode ()) {
3287 case AudioClock::BBT:
3288 session->bbt_time (frame, bbt);
3289 snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32, bbt.bars, bbt.beats, bbt.ticks);
3292 case AudioClock::SMPTE:
3293 session->smpte_time (frame, smpte);
3294 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
3297 case AudioClock::MinSec:
3298 /* XXX fix this to compute min/sec properly */
3299 session->smpte_time (frame, smpte);
3300 secs = smpte.seconds + ((float) smpte.frames / session->smpte_frames_per_second);
3301 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%.4f", smpte.hours, smpte.minutes, secs);
3305 snprintf (buf, sizeof(buf), "%u", frame);
3309 if (xpos >= 0 && ypos >=0) {
3310 set_verbose_canvas_cursor (buf, xpos + offset, ypos + offset);
3313 set_verbose_canvas_cursor (buf, drag_info.current_pointer_x + offset, drag_info.current_pointer_y + offset);
3315 show_verbose_canvas_cursor ();
3319 Editor::show_verbose_duration_cursor (jack_nframes_t start, jack_nframes_t end, double offset, double xpos, double ypos)
3326 Meter meter_at_start(session->tempo_map().meter_at(start));
3332 switch (ARDOUR_UI::instance()->secondary_clock.mode ()) {
3333 case AudioClock::BBT:
3334 session->bbt_time (start, sbbt);
3335 session->bbt_time (end, ebbt);
3338 /* XXX this computation won't work well if the
3339 user makes a selection that spans any meter changes.
3342 ebbt.bars -= sbbt.bars;
3343 if (ebbt.beats >= sbbt.beats) {
3344 ebbt.beats -= sbbt.beats;
3347 ebbt.beats = int(meter_at_start.beats_per_bar()) + ebbt.beats - sbbt.beats;
3349 if (ebbt.ticks >= sbbt.ticks) {
3350 ebbt.ticks -= sbbt.ticks;
3353 ebbt.ticks = int(Meter::ticks_per_beat) + ebbt.ticks - sbbt.ticks;
3356 snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32, ebbt.bars, ebbt.beats, ebbt.ticks);
3359 case AudioClock::SMPTE:
3360 session->smpte_duration (end - start, smpte);
3361 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
3364 case AudioClock::MinSec:
3365 /* XXX fix this to compute min/sec properly */
3366 session->smpte_duration (end - start, smpte);
3367 secs = smpte.seconds + ((float) smpte.frames / session->smpte_frames_per_second);
3368 snprintf (buf, sizeof (buf), "%02ld:%02ld:%.4f", smpte.hours, smpte.minutes, secs);
3372 snprintf (buf, sizeof(buf), "%u", end - start);
3376 if (xpos >= 0 && ypos >=0) {
3377 set_verbose_canvas_cursor (buf, xpos + offset, ypos + offset);
3380 set_verbose_canvas_cursor (buf, drag_info.current_pointer_x + offset, drag_info.current_pointer_y + offset);
3382 show_verbose_canvas_cursor ();
3386 Editor::collect_new_region_view (AudioRegionView* rv)
3388 latest_regionview = rv;
3392 Editor::start_selection_grab (GnomeCanvasItem* item, GdkEvent* event)
3394 if (clicked_regionview == 0) {
3398 /* lets try to create new Region for the selection */
3400 vector<AudioRegion*> new_regions;
3401 create_region_from_selection (new_regions);
3403 if (new_regions.empty()) {
3407 /* XXX fix me one day to use all new regions */
3409 Region* region = new_regions.front();
3411 /* add it to the current stream/playlist.
3413 tricky: the streamview for the track will add a new regionview. we will
3414 catch the signal it sends when it creates the regionview to
3415 set the regionview we want to then drag.
3418 latest_regionview = 0;
3419 sigc::connection c = clicked_audio_trackview->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3421 /* A selection grab currently creates two undo/redo operations, one for
3422 creating the new region and another for moving it.
3425 begin_reversible_command (_("selection grab"));
3427 Playlist* playlist = clicked_trackview->playlist();
3429 session->add_undo (playlist->get_memento ());
3430 clicked_trackview->playlist()->add_region (*region, selection->time[clicked_selection].start);
3431 session->add_redo_no_execute (playlist->get_memento ());
3433 commit_reversible_command ();
3437 if (latest_regionview == 0) {
3438 /* something went wrong */
3442 /* we need to deselect all other regionviews, and select this one
3443 i'm ignoring undo stuff, because the region creation will take care of it */
3444 selection->set (latest_regionview);
3446 drag_info.item = latest_regionview->get_canvas_group();
3447 drag_info.data = latest_regionview;
3448 drag_info.motion_callback = &Editor::region_drag_motion_callback;
3449 drag_info.finished_callback = &Editor::region_drag_finished_callback;
3453 drag_info.last_trackview = clicked_trackview;
3454 drag_info.last_frame_position = latest_regionview->region.position();
3455 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
3457 show_verbose_time_cursor (drag_info.last_frame_position, 10);
3461 Editor::cancel_selection ()
3463 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3464 (*i)->hide_selection ();
3466 selection->clear ();
3467 clicked_selection = 0;
3471 Editor::start_selection_op (GnomeCanvasItem* item, GdkEvent* event, SelectionOp op)
3473 jack_nframes_t start = 0;
3474 jack_nframes_t end = 0;
3480 drag_info.item = item;
3481 drag_info.motion_callback = &Editor::drag_selection;
3482 drag_info.finished_callback = &Editor::end_selection_op;
3487 case CreateSelection:
3489 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
3490 drag_info.copy = true;
3492 drag_info.copy = false;
3494 start_grab (event, selector_cursor);
3497 case SelectionStartTrim:
3498 clicked_trackview->order_selection_trims (item, true);
3499 start_grab (event, trimmer_cursor);
3500 start = selection->time[clicked_selection].start;
3501 drag_info.pointer_frame_offset = drag_info.grab_frame - start;
3504 case SelectionEndTrim:
3505 clicked_trackview->order_selection_trims (item, false);
3506 start_grab (event, trimmer_cursor);
3507 end = selection->time[clicked_selection].end;
3508 drag_info.pointer_frame_offset = drag_info.grab_frame - end;
3512 start = selection->time[clicked_selection].start;
3514 drag_info.pointer_frame_offset = drag_info.grab_frame - start;
3518 if (selection_op == SelectionMove) {
3519 show_verbose_time_cursor(start, 10);
3521 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
3526 Editor::drag_selection (GnomeCanvasItem* item, GdkEvent* event)
3528 jack_nframes_t start = 0;
3529 jack_nframes_t end = 0;
3530 jack_nframes_t length;
3531 jack_nframes_t pending_position;
3533 if ((int32_t) drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
3534 pending_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
3537 pending_position = 0;
3540 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3541 snap_to (pending_position);
3544 /* only alter selection if the current frame is
3545 different from the last frame position (adjusted)
3548 if (pending_position == drag_info.last_pointer_frame) return;
3550 switch (selection_op) {
3551 case CreateSelection:
3553 if (drag_info.first_move) {
3554 snap_to (drag_info.grab_frame);
3557 if (pending_position < drag_info.grab_frame) {
3558 start = pending_position;
3559 end = drag_info.grab_frame;
3561 end = pending_position;
3562 start = drag_info.grab_frame;
3565 /* first drag: Either add to the selection
3566 or create a new selection->
3569 if (drag_info.first_move) {
3571 begin_reversible_command (_("range selection"));
3573 if (drag_info.copy) {
3574 /* adding to the selection */
3575 clicked_selection = selection->add (start, end);
3576 drag_info.copy = false;
3578 /* new selection-> */
3579 clicked_selection = selection->set (clicked_trackview, start, end);
3584 case SelectionStartTrim:
3586 if (drag_info.first_move) {
3587 begin_reversible_command (_("trim selection start"));
3590 start = selection->time[clicked_selection].start;
3591 end = selection->time[clicked_selection].end;
3593 if (pending_position > end) {
3596 start = pending_position;
3600 case SelectionEndTrim:
3602 if (drag_info.first_move) {
3603 begin_reversible_command (_("trim selection end"));
3606 start = selection->time[clicked_selection].start;
3607 end = selection->time[clicked_selection].end;
3609 if (pending_position < start) {
3612 end = pending_position;
3619 if (drag_info.first_move) {
3620 begin_reversible_command (_("move selection"));
3623 start = selection->time[clicked_selection].start;
3624 end = selection->time[clicked_selection].end;
3626 length = end - start;
3628 start = pending_position;
3631 end = start + length;
3637 if (event->button.x >= track_canvas_scroller.get_hadjustment()->get_value() + canvas_width) {
3638 start_canvas_autoscroll (1);
3642 selection->replace (clicked_selection, start, end);
3645 drag_info.last_pointer_frame = pending_position;
3646 drag_info.first_move = false;
3648 if (selection_op == SelectionMove) {
3649 show_verbose_time_cursor(start, 10);
3651 show_verbose_time_cursor(pending_position, 10);
3656 Editor::end_selection_op (GnomeCanvasItem* item, GdkEvent* event)
3658 if (!drag_info.first_move) {
3659 drag_selection (item, event);
3660 /* XXX this is not object-oriented programming at all. ick */
3661 if (selection->time.consolidate()) {
3662 selection->TimeChanged ();
3664 commit_reversible_command ();
3666 /* just a click, no pointer movement.*/
3668 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3670 selection->clear_time();
3675 /* XXX what happens if its a music selection? */
3676 session->set_audio_range (selection->time);
3677 stop_canvas_autoscroll ();
3681 Editor::start_trim (GnomeCanvasItem* item, GdkEvent* event)
3684 TimeAxisView* tvp = clicked_trackview;
3685 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3687 if (tv && tv->is_audio_track()) {
3688 speed = tv->get_diskstream()->speed();
3691 jack_nframes_t region_start = (jack_nframes_t) (clicked_regionview->region.position() / speed);
3692 jack_nframes_t region_end = (jack_nframes_t) (clicked_regionview->region.last_frame() / speed);
3693 jack_nframes_t region_length = (jack_nframes_t) (clicked_regionview->region.length() / speed);
3695 //drag_info.item = clicked_regionview->get_name_highlight();
3696 drag_info.item = item;
3697 drag_info.motion_callback = &Editor::trim_motion_callback;
3698 drag_info.finished_callback = &Editor::trim_finished_callback;
3700 start_grab (event, trimmer_cursor);
3702 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
3703 trim_op = ContentsTrim;
3705 /* These will get overridden for a point trim.*/
3706 if (drag_info.current_pointer_frame < (region_start + region_length/2)) {
3707 /* closer to start */
3708 trim_op = StartTrim;
3709 } else if (drag_info.current_pointer_frame > (region_end - region_length/2)) {
3717 show_verbose_time_cursor(region_start, 10);
3720 show_verbose_time_cursor(region_end, 10);
3723 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
3727 flush_track_canvas ();
3731 Editor::trim_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
3733 AudioRegionView* rv = clicked_regionview;
3734 jack_nframes_t frame_delta = 0;
3735 bool left_direction;
3736 bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier());
3738 /* snap modifier works differently here..
3739 its' current state has to be passed to the
3740 various trim functions in order to work properly
3744 TimeAxisView* tvp = clicked_trackview;
3745 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3747 if (tv && tv->is_audio_track()) {
3748 speed = tv->get_diskstream()->speed();
3751 if (drag_info.last_pointer_frame > drag_info.current_pointer_frame) {
3752 left_direction = true;
3754 left_direction = false;
3758 snap_to (drag_info.current_pointer_frame);
3761 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) {
3765 if (drag_info.first_move) {
3771 trim_type = "Region start trim";
3774 trim_type = "Region end trim";
3777 trim_type = "Region content trim";
3781 begin_reversible_command (trim_type);
3783 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
3784 (*i)->region.freeze ();
3785 (*i)->temporarily_hide_envelope ();
3786 session->add_undo ((*i)->region.playlist()->get_memento());
3790 if (left_direction) {
3791 frame_delta = (drag_info.last_pointer_frame - drag_info.current_pointer_frame);
3793 frame_delta = (drag_info.current_pointer_frame - drag_info.last_pointer_frame);
3798 if ((left_direction == false) && (drag_info.current_pointer_frame <= rv->region.first_frame()/speed)) {
3801 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
3802 single_start_trim (**i, frame_delta, left_direction, obey_snap);
3808 if ((left_direction == true) && (drag_info.current_pointer_frame > (jack_nframes_t) (rv->region.last_frame()/speed))) {
3811 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
3812 single_end_trim (**i, frame_delta, left_direction, obey_snap);
3819 bool swap_direction = false;
3821 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
3822 swap_direction = true;
3825 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin();
3826 i != selection->audio_regions.by_layer().end(); ++i)
3828 single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
3836 show_verbose_time_cursor((jack_nframes_t) (rv->region.position()/speed), 10);
3839 show_verbose_time_cursor((jack_nframes_t) (rv->region.last_frame()/speed), 10);
3842 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
3846 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
3847 drag_info.first_move = false;
3851 Editor::single_contents_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool swap_direction, bool obey_snap)
3853 Region& region (rv.region);
3855 if (region.locked()) {
3859 jack_nframes_t new_bound;
3862 TimeAxisView* tvp = clicked_trackview;
3863 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3865 if (tv && tv->is_audio_track()) {
3866 speed = tv->get_diskstream()->speed();
3869 if (left_direction) {
3870 if (swap_direction) {
3871 new_bound = (jack_nframes_t) (region.position()/speed) + frame_delta;
3873 new_bound = (jack_nframes_t) (region.position()/speed) - frame_delta;
3876 if (swap_direction) {
3877 new_bound = (jack_nframes_t) (region.position()/speed) - frame_delta;
3879 new_bound = (jack_nframes_t) (region.position()/speed) + frame_delta;
3884 snap_to (new_bound);
3886 region.trim_start ((jack_nframes_t) (new_bound * speed), this);
3887 rv.region_changed (StartChanged);
3891 Editor::single_start_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool obey_snap)
3893 Region& region (rv.region);
3895 if (region.locked()) {
3899 jack_nframes_t new_bound;
3902 TimeAxisView* tvp = clicked_trackview;
3903 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3905 if (tv && tv->is_audio_track()) {
3906 speed = tv->get_diskstream()->speed();
3909 if (left_direction) {
3910 new_bound = (jack_nframes_t) (region.position()/speed) - frame_delta;
3912 new_bound = (jack_nframes_t) (region.position()/speed) + frame_delta;
3916 snap_to (new_bound, (left_direction ? 0 : 1));
3919 region.trim_front ((jack_nframes_t) (new_bound * speed), this);
3921 rv.region_changed (Change (LengthChanged|PositionChanged|StartChanged));
3925 Editor::single_end_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool obey_snap)
3927 Region& region (rv.region);
3929 if (region.locked()) {
3933 jack_nframes_t new_bound;
3936 TimeAxisView* tvp = clicked_trackview;
3937 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3939 if (tv && tv->is_audio_track()) {
3940 speed = tv->get_diskstream()->speed();
3943 if (left_direction) {
3944 new_bound = (jack_nframes_t) ((region.last_frame() + 1)/speed) - frame_delta;
3946 new_bound = (jack_nframes_t) ((region.last_frame() + 1)/speed) + frame_delta;
3950 snap_to (new_bound);
3952 region.trim_end ((jack_nframes_t) (new_bound * speed), this);
3953 rv.region_changed (LengthChanged);
3957 Editor::trim_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
3959 if (!drag_info.first_move) {
3960 trim_motion_callback (item, event);
3962 if (!clicked_regionview->get_selected()) {
3963 thaw_region_after_trim (*clicked_regionview);
3966 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin();
3967 i != selection->audio_regions.by_layer().end(); ++i)
3969 thaw_region_after_trim (**i);
3972 commit_reversible_command();
3974 /* no mouse movement */
3978 flush_track_canvas ();
3982 Editor::point_trim (GdkEvent* event)
3984 AudioRegionView* rv = clicked_regionview;
3985 jack_nframes_t new_bound = drag_info.current_pointer_frame;
3987 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3988 snap_to (new_bound);
3991 /* Choose action dependant on which button was pressed */
3992 switch (event->button.button) {
3994 trim_op = StartTrim;
3995 begin_reversible_command (_("Start point trim"));
3997 if (rv->get_selected()) {
3999 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin();
4000 i != selection->audio_regions.by_layer().end(); ++i)
4002 if (!(*i)->region.locked()) {
4003 session->add_undo ((*i)->region.playlist()->get_memento());
4004 (*i)->region.trim_front (new_bound, this);
4005 session->add_redo_no_execute ((*i)->region.playlist()->get_memento());
4011 if (!rv->region.locked()) {
4012 session->add_undo (rv->region.playlist()->get_memento());
4013 rv->region.trim_front (new_bound, this);
4014 session->add_redo_no_execute (rv->region.playlist()->get_memento());
4018 commit_reversible_command();
4023 begin_reversible_command (_("End point trim"));
4025 if (rv->get_selected()) {
4027 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i)
4029 if (!(*i)->region.locked()) {
4030 session->add_undo ((*i)->region.playlist()->get_memento());
4031 (*i)->region.trim_end (new_bound, this);
4032 session->add_redo_no_execute ((*i)->region.playlist()->get_memento());
4038 if (!rv->region.locked()) {
4039 session->add_undo (rv->region.playlist()->get_memento());
4040 rv->region.trim_end (new_bound, this);
4041 session->add_redo_no_execute (rv->region.playlist()->get_memento());
4045 commit_reversible_command();
4054 Editor::thaw_region_after_trim (AudioRegionView& rv)
4056 Region& region (rv.region);
4058 if (region.locked()) {
4062 region.thaw (_("trimmed region"));
4063 session->add_redo_no_execute (region.playlist()->get_memento());
4065 rv.unhide_envelope ();
4069 Editor::hide_marker (GnomeCanvasItem* item, GdkEvent* event)
4074 if ((marker = static_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "marker"))) == 0) {
4075 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
4079 Location* location = find_location_from_marker (marker, is_start);
4080 location->set_hidden (true, this);
4085 Editor::start_range_markerbar_op (GnomeCanvasItem* item, GdkEvent* event, RangeMarkerOp op)
4092 drag_info.item = item;
4093 drag_info.motion_callback = &Editor::drag_range_markerbar_op;
4094 drag_info.finished_callback = &Editor::end_range_markerbar_op;
4096 range_marker_op = op;
4098 if (!temp_location) {
4099 temp_location = new Location;
4103 case CreateRangeMarker:
4104 case CreateTransportMarker:
4106 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
4107 drag_info.copy = true;
4109 drag_info.copy = false;
4111 start_grab (event, selector_cursor);
4115 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
4120 Editor::drag_range_markerbar_op (GnomeCanvasItem* item, GdkEvent* event)
4122 jack_nframes_t start = 0;
4123 jack_nframes_t end = 0;
4125 GnomeCanvasItem * crect = (range_marker_op == CreateRangeMarker) ? range_bar_drag_rect: transport_bar_drag_rect;
4127 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4128 snap_to (drag_info.current_pointer_frame);
4131 /* only alter selection if the current frame is
4132 different from the last frame position.
4135 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) return;
4137 switch (range_marker_op) {
4138 case CreateRangeMarker:
4139 case CreateTransportMarker:
4140 if (drag_info.first_move) {
4141 snap_to (drag_info.grab_frame);
4144 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4145 start = drag_info.current_pointer_frame;
4146 end = drag_info.grab_frame;
4148 end = drag_info.current_pointer_frame;
4149 start = drag_info.grab_frame;
4152 /* first drag: Either add to the selection
4153 or create a new selection->
4156 if (drag_info.first_move) {
4158 temp_location->set (start, end);
4160 gnome_canvas_item_show (crect);
4162 update_marker_drag_item (temp_location);
4163 range_marker_drag_rect->show();
4164 range_marker_drag_rect->raise_to_top();
4171 if (event->button.x >= track_canvas_scroller.get_hadjustment()->get_value() + canvas_width) {
4172 start_canvas_autoscroll (1);
4176 temp_location->set (start, end);
4178 double x1 = frame_to_pixel (start);
4179 double x2 = frame_to_pixel (end);
4180 gnome_canvas_item_set (crect, "x1", x1, "x2", x2, NULL);
4182 update_marker_drag_item (temp_location);
4185 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4186 drag_info.first_move = false;
4188 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
4193 Editor::end_range_markerbar_op (GnomeCanvasItem* item, GdkEvent* event)
4195 Location * newloc = 0;
4197 if (!drag_info.first_move) {
4198 drag_range_markerbar_op (item, event);
4200 switch (range_marker_op)
4202 case CreateRangeMarker:
4203 begin_reversible_command (_("new range marker"));
4204 session->add_undo (session->locations()->get_memento());
4205 newloc = new Location(temp_location->start(), temp_location->end(), "unnamed");
4206 session->locations()->add (newloc, true);
4207 session->add_redo_no_execute (session->locations()->get_memento());
4208 commit_reversible_command ();
4210 range_bar_drag_rect->hide();
4211 range_marker_drag_rect->hide();
4214 case CreateTransportMarker:
4215 // popup menu to pick loop or punch
4216 new_transport_marker_context_menu (&event->button, item);
4221 /* just a click, no pointer movement.*/
4223 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
4230 stop_canvas_autoscroll ();
4236 Editor::start_mouse_zoom (GnomeCanvasItem* item, GdkEvent* event)
4238 drag_info.item = item;
4239 drag_info.motion_callback = &Editor::drag_mouse_zoom;
4240 drag_info.finished_callback = &Editor::end_mouse_zoom;
4242 start_grab (event, zoom_cursor);
4244 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4248 Editor::drag_mouse_zoom (GnomeCanvasItem* item, GdkEvent* event)
4250 jack_nframes_t start;
4253 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4254 snap_to (drag_info.current_pointer_frame);
4256 if (drag_info.first_move) {
4257 snap_to (drag_info.grab_frame);
4261 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) return;
4263 /* base start and end on initial click position */
4264 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4265 start = drag_info.current_pointer_frame;
4266 end = drag_info.grab_frame;
4268 end = drag_info.current_pointer_frame;
4269 start = drag_info.grab_frame;
4274 if (drag_info.first_move) {
4276 zoom_rect->raise_to_top();
4279 reposition_zoom_rect(start, end);
4281 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4282 drag_info.first_move = false;
4284 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4289 Editor::end_mouse_zoom (GnomeCanvasItem* item, GdkEvent* event)
4291 if (!drag_info.first_move) {
4292 drag_mouse_zoom (item, event);
4294 if (drag_info.grab_frame < drag_info.last_pointer_frame) {
4295 temporal_zoom_by_frame (drag_info.grab_frame, drag_info.last_pointer_frame, "mouse zoom");
4297 temporal_zoom_by_frame (drag_info.last_pointer_frame, drag_info.grab_frame, "mouse zoom");
4300 temporal_zoom_to_frame (false, drag_info.grab_frame);
4302 temporal_zoom_step (false);
4303 center_screen (drag_info.grab_frame);
4311 Editor::reposition_zoom_rect (jack_nframes_t start, jack_nframes_t end)
4313 double x1 = frame_to_pixel (start);
4314 double x2 = frame_to_pixel (end);
4315 double y2 = canvas_height - 2;
4317 gtk_object_set (GTK_OBJECT(zoom_rect),
4326 Editor::start_rubberband_select (GnomeCanvasItem* item, GdkEvent* event)
4328 drag_info.item = item;
4329 drag_info.motion_callback = &Editor::drag_rubberband_select;
4330 drag_info.finished_callback = &Editor::end_rubberband_select;
4332 start_grab (event, cross_hair_cursor);
4334 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4338 Editor::drag_rubberband_select (GnomeCanvasItem* item, GdkEvent* event)
4340 jack_nframes_t start;
4345 /* use a bigger drag threshold than the default */
4347 if (abs ((int) (drag_info.current_pointer_frame - drag_info.grab_frame)) < 8) {
4351 // if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4352 // snap_to (drag_info.current_pointer_frame);
4354 // if (drag_info.first_move) {
4355 // snap_to (drag_info.grab_frame);
4360 /* base start and end on initial click position */
4361 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4362 start = drag_info.current_pointer_frame;
4363 end = drag_info.grab_frame;
4365 end = drag_info.current_pointer_frame;
4366 start = drag_info.grab_frame;
4369 if (drag_info.current_pointer_y < drag_info.grab_y) {
4370 y1 = drag_info.current_pointer_y;
4371 y2 = drag_info.grab_y;
4374 y2 = drag_info.current_pointer_y;
4375 y1 = drag_info.grab_y;
4379 if (start != end || y1 != y2) {
4381 double x1 = frame_to_pixel (start);
4382 double x2 = frame_to_pixel (end);
4384 gtk_object_set (GTK_OBJECT(rubberband_rect),
4391 rubberband_rect->show();
4392 rubberband_rect->raise_to_top();
4394 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4395 drag_info.first_move = false;
4397 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4402 Editor::end_rubberband_select (GnomeCanvasItem* item, GdkEvent* event)
4404 if (!drag_info.first_move) {
4406 drag_rubberband_select (item, event);
4409 if (drag_info.current_pointer_y < drag_info.grab_y) {
4410 y1 = drag_info.current_pointer_y;
4411 y2 = drag_info.grab_y;
4414 y2 = drag_info.current_pointer_y;
4415 y1 = drag_info.grab_y;
4419 bool add = Keyboard::modifier_state_contains (event->button.state, Keyboard::Shift);
4422 begin_reversible_command (_("select regions"));
4424 if (drag_info.grab_frame < drag_info.last_pointer_frame) {
4425 commit = select_all_within (drag_info.grab_frame, drag_info.last_pointer_frame, y1, y2, add);
4427 commit = select_all_within (drag_info.last_pointer_frame, drag_info.grab_frame, y1, y2, add);
4431 commit_reversible_command ();
4435 selection->clear_audio_regions();
4436 selection->clear_points ();
4437 selection->clear_lines ();
4440 rubberband_rect->hide();
4445 Editor::mouse_rename_region (GnomeCanvasItem* item, GdkEvent* event)
4447 using namespace Gtkmm2ext;
4449 ArdourPrompter prompter (false);
4451 prompter.set_prompt (_("Name for region:"));
4452 prompter.set_initial_text (clicked_regionview->region.name());
4453 prompter.show_all ();
4454 prompter.chosen.connect(sigc::ptr_fun(Gtk::Main::quit));
4455 switch (prompter.run ()) {
4456 case GTK_RESPONSE_ACCEPT:
4458 prompter.get_result(str);
4461 clicked_regionview->region.set_name (str);
4469 Editor::start_time_fx (GnomeCanvasItem* item, GdkEvent* event)
4471 drag_info.item = item;
4472 drag_info.motion_callback = &Editor::time_fx_motion;
4473 drag_info.finished_callback = &Editor::end_time_fx;
4477 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4481 Editor::time_fx_motion (GnomeCanvasItem *item, GdkEvent* event)
4483 AudioRegionView* rv = clicked_regionview;
4485 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4486 snap_to (drag_info.current_pointer_frame);
4489 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) {
4493 if (drag_info.current_pointer_frame > rv->region.position()) {
4494 rv->get_time_axis_view().show_timestretch (rv->region.position(), drag_info.current_pointer_frame);
4497 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4498 drag_info.first_move = false;
4500 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4504 Editor::end_time_fx (GnomeCanvasItem* item, GdkEvent* event)
4506 clicked_regionview->get_time_axis_view().hide_timestretch ();
4508 if (drag_info.first_move) {
4512 jack_nframes_t newlen = drag_info.last_pointer_frame - clicked_regionview->region.position();
4513 float percentage = (float) ((double) newlen - (double) clicked_regionview->region.length()) / ((double) newlen) * 100.0f;
4515 begin_reversible_command (_("timestretch"));
4517 if (run_timestretch (selection->audio_regions, percentage) == 0) {
4518 session->commit_reversible_command ();
4523 Editor::mouse_brush_insert_region (AudioRegionView* rv, jack_nframes_t pos)
4525 /* no brushing without a useful snap setting */
4527 switch (snap_mode) {
4529 return; /* can't work because it allows region to be placed anywhere */
4534 switch (snap_type) {
4537 case SnapToEditCursor:
4544 /* don't brush a copy over the original */
4546 if (pos == rv->region.position()) {
4550 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&rv->get_time_axis_view());
4552 if (atv == 0 || !atv->is_audio_track()) {
4556 Playlist* playlist = atv->playlist();
4557 double speed = atv->get_diskstream()->speed();
4559 session->add_undo (playlist->get_memento());
4560 playlist->add_region (*(new AudioRegion (rv->region)), (jack_nframes_t) (pos * speed));
4561 session->add_redo_no_execute (playlist->get_memento());
4563 // playlist is frozen, so we have to update manually
4565 playlist->StateChanged (Change (~0)); /* EMIT SIGNAL */
4569 Editor::track_height_step_timeout ()
4572 struct timeval delta;
4574 gettimeofday (&now, 0);
4575 timersub (&now, &last_track_height_step_timestamp, &delta);
4577 if (delta.tv_sec * 1000000 + delta.tv_usec > 250000) { /* milliseconds */
4578 current_stepping_trackview = 0;