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 gdk_window_set_cursor (track_canvas_scroller.get_window()->gobj(), 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) {
728 step_timeout = t.connect (mem_fun(*this, &Editor::track_height_step_timeout), 500);
729 current_stepping_trackview = clicked_trackview;
731 gettimeofday (&last_track_height_step_timestamp, 0);
732 current_stepping_trackview->step_height (true);
735 else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
736 temporal_zoom_to_frame (true, where);
743 switch (mouse_mode) {
745 // temporal_zoom_to_frame (false, where);
746 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
747 temporal_zoom_to_frame (false, where);
750 temporal_zoom_step (false);
755 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::Alt))) {
756 scroll_forward (0.6f);
758 else if (Keyboard::no_modifier_keys_pressed (&event->button)) {
759 scroll_tracks_down_line ();
761 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
762 if (clicked_trackview) {
763 if (!current_stepping_trackview) {
765 step_timeout = t.connect (mem_fun(*this, &Editor::track_height_step_timeout), 500);
766 current_stepping_trackview = clicked_trackview;
768 gettimeofday (&last_track_height_step_timestamp, 0);
769 current_stepping_trackview->step_height (false);
771 } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
772 temporal_zoom_to_frame (false, where);
786 Editor::button_release_handler (GnomeCanvasItem* item, GdkEvent* event, ItemType item_type)
788 jack_nframes_t where = event_frame (event, 0, 0);
790 /* no action if we're recording */
792 if (session && session->actively_recording()) {
796 /* first, see if we're finishing a drag ... */
798 if (drag_info.item) {
799 if (end_grab (item, event)) {
800 /* grab dragged, so do nothing else */
805 /* edit events get handled here */
807 if (drag_info.item == 0 && Keyboard::is_edit_event (&event->button)) {
813 case TempoMarkerItem:
814 edit_tempo_marker (item);
817 case MeterMarkerItem:
818 edit_meter_marker (item);
821 case AudioRegionViewName:
822 if (clicked_regionview->name_active()) {
823 return mouse_rename_region (item, event);
833 /* context menu events get handled here */
835 if (Keyboard::is_context_menu_event (&event->button)) {
837 if (drag_info.item == 0) {
839 /* no matter which button pops up the context menu, tell the menu
840 widget to use button 1 to drive menu selection.
845 case FadeInHandleItem:
847 case FadeOutHandleItem:
848 popup_fade_context_menu (1, event->button.time, item, item_type);
852 popup_track_context_menu (1, event->button.time, item_type, false, where);
856 case AudioRegionViewNameHighlight:
857 case AudioRegionViewName:
858 popup_track_context_menu (1, event->button.time, item_type, false, where);
862 popup_track_context_menu (1, event->button.time, item_type, true, where);
865 case AutomationTrackItem:
866 popup_track_context_menu (1, event->button.time, item_type, false, where);
870 case RangeMarkerBarItem:
871 case TransportMarkerBarItem:
874 popup_ruler_menu (pixel_to_frame(event->button.x), item_type);
878 marker_context_menu (&event->button, item);
881 case TempoMarkerItem:
882 tm_marker_context_menu (&event->button, item);
885 case MeterMarkerItem:
886 tm_marker_context_menu (&event->button, item);
889 case CrossfadeViewItem:
890 popup_track_context_menu (1, event->button.time, item_type, false, where);
893 /* <CMT Additions> */
895 popup_imageframe_edit_menu(1, event->button.time, item, true) ;
897 case ImageFrameTimeAxisItem:
898 popup_imageframe_edit_menu(1, event->button.time, item, false) ;
901 popup_marker_time_axis_edit_menu(1, event->button.time, item, true) ;
903 case MarkerTimeAxisItem:
904 popup_marker_time_axis_edit_menu(1, event->button.time, item, false) ;
906 /* <CMT Additions> */
917 /* delete events get handled here */
919 if (drag_info.item == 0 && Keyboard::is_delete_event (&event->button)) {
922 case TempoMarkerItem:
923 remove_tempo_marker (item);
926 case MeterMarkerItem:
927 remove_meter_marker (item);
931 remove_marker (item, event);
935 if (mouse_mode == MouseObject) {
936 remove_clicked_region ();
940 case GainControlPointItem:
941 if (mouse_mode == MouseGain) {
942 remove_gain_control_point (item, event);
946 case GainAutomationControlPointItem:
947 case PanAutomationControlPointItem:
948 case RedirectAutomationControlPointItem:
949 remove_control_point (item, event);
958 switch (event->button.button) {
962 /* see comments in button_press_handler */
964 case PlayheadCursorItem:
967 case GainAutomationLineItem:
968 case PanAutomationLineItem:
969 case RedirectAutomationLineItem:
970 case StartSelectionTrimItem:
971 case EndSelectionTrimItem:
975 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
976 snap_to (where, 0, true);
978 mouse_add_new_marker (where);
982 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
985 mouse_add_new_tempo_event (where);
989 mouse_add_new_meter_event (pixel_to_frame (event->button.x));
997 switch (mouse_mode) {
1000 case AutomationTrackItem:
1001 dynamic_cast<AutomationTimeAxisView*>(clicked_trackview)->add_automation_event
1015 switch (item_type) {
1017 clicked_regionview->add_gain_point_event (item, event);
1021 case AutomationTrackItem:
1022 dynamic_cast<AutomationTimeAxisView*>(clicked_trackview)->
1023 add_automation_event (item, event, where, event->button.y);
1032 switch (item_type) {
1034 audition_selected_region ();
1051 switch (mouse_mode) {
1054 switch (item_type) {
1056 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
1058 } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::ModifierMask (Keyboard::Shift|Keyboard::Alt))) {
1061 // Button2 click is unused
1074 // x_style_paste (where, 1.0);
1094 Editor::maybe_autoscroll (GdkEvent* event)
1096 jack_nframes_t one_page = (jack_nframes_t) rint (canvas_width * frames_per_unit);
1097 jack_nframes_t rightmost_frame = leftmost_frame + one_page;
1099 jack_nframes_t frame = drag_info.current_pointer_frame;
1101 if (autoscroll_timeout_tag < 0) {
1102 if (frame > rightmost_frame) {
1103 if (rightmost_frame < max_frames) {
1104 start_canvas_autoscroll (1);
1106 } else if (frame < leftmost_frame) {
1107 if (leftmost_frame > 0) {
1108 start_canvas_autoscroll (-1);
1112 if (frame >= leftmost_frame && frame < rightmost_frame) {
1113 stop_canvas_autoscroll ();
1119 Editor::enter_handler (GnomeCanvasItem* item, GdkEvent* event, ItemType item_type)
1125 switch (item_type) {
1126 case GainControlPointItem:
1127 if (mouse_mode == MouseGain) {
1128 cp = reinterpret_cast<ControlPoint*>(gtk_object_get_data (GTK_OBJECT(item), "control_point"));
1129 cp->set_visible (true);
1133 at_y = cp->get_y ();
1134 gnome_canvas_item_i2w (cp->item, &at_x, &at_y);
1138 fraction = 1.0 - (cp->get_y() / cp->line.height());
1140 set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y);
1141 show_verbose_canvas_cursor ();
1143 if (is_drawable()) {
1144 gdk_window_set_cursor (track_canvas_scroller.get_window()->gobj(), fader_cursor);
1149 case GainAutomationControlPointItem:
1150 case PanAutomationControlPointItem:
1151 case RedirectAutomationControlPointItem:
1152 cp = reinterpret_cast<ControlPoint*>(gtk_object_get_data (GTK_OBJECT(item), "control_point"));
1153 cp->set_visible (true);
1157 at_y = cp->get_y ();
1158 gnome_canvas_item_i2w (cp->item, &at_x, &at_y);
1162 fraction = 1.0 - (cp->get_y() / cp->line.height());
1164 set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y);
1165 show_verbose_canvas_cursor ();
1167 if (is_drawable()) {
1168 gdk_window_set_cursor (track_canvas_scroller.get_window()->gobj(), fader_cursor);
1173 if (mouse_mode == MouseGain) {
1174 gnome_canvas_item_set (item, "fill_color_rgba", color_map[cEnteredGainLine], NULL);
1175 if (is_drawable()) {
1176 gdk_window_set_cursor (track_canvas_scroller.get_window()->gobj(), fader_cursor);
1181 case GainAutomationLineItem:
1182 case RedirectAutomationLineItem:
1183 case PanAutomationLineItem:
1184 gnome_canvas_item_set (item, "fill_color_rgba", color_map[cEnteredAutomationLine], NULL);
1185 if (is_drawable()) {
1186 gdk_window_set_cursor (track_canvas_scroller.get_window()->gobj(), fader_cursor);
1190 case AudioRegionViewNameHighlight:
1191 if (is_drawable() && mouse_mode == MouseObject) {
1192 gdk_window_set_cursor (track_canvas_scroller.get_window()->gobj(), trimmer_cursor);
1196 case StartSelectionTrimItem:
1197 case EndSelectionTrimItem:
1198 /* <CMT Additions> */
1199 case ImageFrameHandleStartItem:
1200 case ImageFrameHandleEndItem:
1201 case MarkerViewHandleStartItem:
1202 case MarkerViewHandleEndItem:
1203 /* </CMT Additions> */
1205 if (is_drawable()) {
1206 gdk_window_set_cursor (track_canvas_scroller.get_window()->gobj(), trimmer_cursor);
1210 case EditCursorItem:
1211 case PlayheadCursorItem:
1212 if (is_drawable()) {
1213 gdk_window_set_cursor (track_canvas_scroller.get_window()->gobj(), grabber_cursor);
1217 case AudioRegionViewName:
1219 /* when the name is not an active item, the entire name highlight is for trimming */
1221 if (!reinterpret_cast<AudioRegionView *> (gtk_object_get_data(GTK_OBJECT(item), "regionview"))->name_active()) {
1222 if (mouse_mode == MouseObject && is_drawable()) {
1223 gdk_window_set_cursor (track_canvas_scroller.get_window()->gobj(), trimmer_cursor);
1229 case AutomationTrackItem:
1230 if (is_drawable()) {
1232 switch (mouse_mode) {
1234 cursor = selector_cursor;
1237 cursor = zoom_cursor;
1240 cursor = cross_hair_cursor;
1244 gdk_window_set_cursor (track_canvas_scroller.get_window()->gobj(), cursor);
1246 AutomationTimeAxisView* atv;
1247 if ((atv = static_cast<AutomationTimeAxisView*>(gtk_object_get_data(GTK_OBJECT(item), "trackview"))) != 0) {
1248 clear_entered_track = false;
1249 set_entered_track (atv);
1255 case RangeMarkerBarItem:
1256 case TransportMarkerBarItem:
1259 if (is_drawable()) {
1260 gdk_window_set_cursor (time_canvas_scroller.get_window()->gobj(), timebar_cursor);
1265 if ((marker = static_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "marker"))) == 0) {
1268 marker->set_color_rgba (color_map[cEnteredMarker]);
1270 case MeterMarkerItem:
1271 case TempoMarkerItem:
1272 if (is_drawable()) {
1273 gdk_window_set_cursor (time_canvas_scroller.get_window()->gobj(), timebar_cursor);
1276 case FadeInHandleItem:
1277 case FadeOutHandleItem:
1278 if (mouse_mode == MouseObject) {
1279 gnome_canvas_item_set (item, "fill_color_rgba", 0, "outline_pixels", 1, NULL);
1287 /* second pass to handle entered track status in a comprehensible way.
1290 switch (item_type) {
1292 case GainAutomationLineItem:
1293 case RedirectAutomationLineItem:
1294 case PanAutomationLineItem:
1295 case GainControlPointItem:
1296 case GainAutomationControlPointItem:
1297 case PanAutomationControlPointItem:
1298 case RedirectAutomationControlPointItem:
1299 /* these do not affect the current entered track state */
1300 clear_entered_track = false;
1303 case AutomationTrackItem:
1304 /* handled above already */
1308 set_entered_track (0);
1316 Editor::leave_handler (GnomeCanvasItem* item, GdkEvent* event, ItemType item_type)
1322 AudioRegionView* rv;
1325 switch (item_type) {
1326 case GainControlPointItem:
1327 case GainAutomationControlPointItem:
1328 case PanAutomationControlPointItem:
1329 case RedirectAutomationControlPointItem:
1330 cp = reinterpret_cast<ControlPoint*>(gtk_object_get_data (GTK_OBJECT(item), "control_point"));
1331 if (cp->line.npoints() > 1) {
1332 if (!cp->selected) {
1333 cp->set_visible (false);
1337 if (is_drawable()) {
1338 gdk_window_set_cursor (track_canvas_scroller.get_window()->gobj(), current_canvas_cursor);
1341 hide_verbose_canvas_cursor ();
1344 case AudioRegionViewNameHighlight:
1345 case StartSelectionTrimItem:
1346 case EndSelectionTrimItem:
1347 case EditCursorItem:
1348 case PlayheadCursorItem:
1349 /* <CMT Additions> */
1350 case ImageFrameHandleStartItem:
1351 case ImageFrameHandleEndItem:
1352 case MarkerViewHandleStartItem:
1353 case MarkerViewHandleEndItem:
1354 /* </CMT Additions> */
1355 if (is_drawable()) {
1356 gdk_window_set_cursor (track_canvas_scroller.get_window()->gobj(), current_canvas_cursor);
1361 case GainAutomationLineItem:
1362 case RedirectAutomationLineItem:
1363 case PanAutomationLineItem:
1364 al = reinterpret_cast<AutomationLine*> (gtk_object_get_data (GTK_OBJECT(item),"line"));
1365 gnome_canvas_item_set (item, "fill_color_rgba", al->get_line_color(), NULL);
1366 if (is_drawable()) {
1367 gdk_window_set_cursor (track_canvas_scroller.get_window()->gobj(), current_canvas_cursor);
1371 case AudioRegionViewName:
1372 /* see enter_handler() for notes */
1373 if (!reinterpret_cast<AudioRegionView *> (gtk_object_get_data(GTK_OBJECT(item), "regionview"))->name_active()) {
1374 if (is_drawable() && mouse_mode == MouseObject) {
1375 gdk_window_set_cursor (track_canvas_scroller.get_window()->gobj(), current_canvas_cursor);
1380 case RangeMarkerBarItem:
1381 case TransportMarkerBarItem:
1385 if (is_drawable()) {
1386 gdk_window_set_cursor (time_canvas_scroller.get_window()->gobj(), timebar_cursor);
1391 if ((marker = static_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "marker"))) == 0) {
1394 loc = find_location_from_marker (marker, is_start);
1395 if (loc) location_flags_changed (loc, this);
1397 case MeterMarkerItem:
1398 case TempoMarkerItem:
1400 if (is_drawable()) {
1401 gdk_window_set_cursor (time_canvas_scroller.get_window()->gobj(), timebar_cursor);
1406 case FadeInHandleItem:
1407 case FadeOutHandleItem:
1408 rv = static_cast<AudioRegionView*>(gtk_object_get_data (GTK_OBJECT(item), "regionview"));
1409 gnome_canvas_item_set (item, "fill_color_rgba", rv->get_fill_color(), "outline_pixels", 0, NULL);
1412 case AutomationTrackItem:
1413 if (is_drawable()) {
1414 gdk_window_set_cursor (track_canvas_scroller.get_window()->gobj(), current_canvas_cursor);
1416 clear_entered_track = true;
1417 Glib::signal_idle().connect (mem_fun(*this, &Editor::left_automation_track));
1429 Editor::left_automation_track ()
1431 if (clear_entered_track) {
1432 set_entered_track (0);
1433 clear_entered_track = false;
1439 Editor::motion_handler (GnomeCanvasItem* item, GdkEvent* event, ItemType item_type)
1443 /* We call this so that MOTION_NOTIFY events continue to be
1444 delivered to the canvas. We need to do this because we set
1445 Gdk::POINTER_MOTION_HINT_MASK on the canvas. This reduces
1446 the density of the events, at the expense of a round-trip
1447 to the server. Given that this will mostly occur on cases
1448 where DISPLAY = :0.0, and given the cost of what the motion
1449 event might do, its a good tradeoff.
1452 track_canvas->get_pointer (x, y);
1454 if (current_stepping_trackview) {
1455 /* don't keep the persistent stepped trackview if the mouse moves */
1456 current_stepping_trackview = 0;
1457 step_timeout.disconnect ();
1460 if (session && session->actively_recording()) {
1461 /* Sorry. no dragging stuff around while we record */
1465 drag_info.current_pointer_frame = event_frame (event, &drag_info.current_pointer_x,
1466 &drag_info.current_pointer_y);
1467 if (drag_info.item) {
1468 /* item != 0 is the best test i can think of for
1471 if (!drag_info.move_threshold_passsed)
1473 drag_info.move_threshold_passsed = (abs ((int) (drag_info.current_pointer_x - drag_info.grab_x)) > 4);
1475 // and change the initial grab loc/frame if this drag info wants us to
1476 if (drag_info.want_move_threshold && drag_info.move_threshold_passsed) {
1477 drag_info.grab_frame = drag_info.current_pointer_frame;
1478 drag_info.grab_x = drag_info.current_pointer_x;
1479 drag_info.grab_y = drag_info.current_pointer_y;
1480 drag_info.last_pointer_frame = drag_info.grab_frame;
1481 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
1486 switch (item_type) {
1487 case PlayheadCursorItem:
1488 case EditCursorItem:
1490 case GainControlPointItem:
1491 case RedirectAutomationControlPointItem:
1492 case GainAutomationControlPointItem:
1493 case PanAutomationControlPointItem:
1494 case TempoMarkerItem:
1495 case MeterMarkerItem:
1496 case AudioRegionViewNameHighlight:
1497 case StartSelectionTrimItem:
1498 case EndSelectionTrimItem:
1501 case RedirectAutomationLineItem:
1502 case GainAutomationLineItem:
1503 case PanAutomationLineItem:
1504 case FadeInHandleItem:
1505 case FadeOutHandleItem:
1506 /* <CMT Additions> */
1507 case ImageFrameHandleStartItem:
1508 case ImageFrameHandleEndItem:
1509 case MarkerViewHandleStartItem:
1510 case MarkerViewHandleEndItem:
1511 /* </CMT Additions> */
1512 if (drag_info.item && (event->motion.state & GDK_BUTTON1_MASK ||
1513 (event->motion.state & GDK_BUTTON2_MASK))) {
1514 maybe_autoscroll (event);
1515 (this->*(drag_info.motion_callback)) (item, event);
1524 switch (mouse_mode) {
1529 if (drag_info.item && (event->motion.state & GDK_BUTTON1_MASK ||
1530 (event->motion.state & GDK_BUTTON2_MASK))) {
1531 maybe_autoscroll (event);
1532 (this->*(drag_info.motion_callback)) (item, event);
1543 track_canvas_motion (item, event);
1551 Editor::start_grab (GdkEvent* event, GdkCursor *cursor)
1553 if (drag_info.item == 0) {
1554 fatal << _("programming error: start_grab called without drag item") << endmsg;
1560 cursor = grabber_cursor;
1563 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
1565 if (event->button.button == 2) {
1566 drag_info.x_constrained = true;
1568 drag_info.x_constrained = false;
1571 drag_info.grab_frame = event_frame(event, &drag_info.grab_x, &drag_info.grab_y);
1572 drag_info.last_pointer_frame = drag_info.grab_frame;
1573 drag_info.current_pointer_frame = drag_info.grab_frame;
1574 drag_info.current_pointer_x = drag_info.grab_x;
1575 drag_info.current_pointer_y = drag_info.grab_y;
1576 drag_info.cumulative_x_drag = 0;
1577 drag_info.cumulative_y_drag = 0;
1578 drag_info.first_move = true;
1579 drag_info.move_threshold_passsed = false;
1580 drag_info.want_move_threshold = false;
1581 drag_info.pointer_frame_offset = 0;
1582 drag_info.brushing = false;
1583 drag_info.copied_location = 0;
1585 gnome_canvas_item_grab (drag_info.item,
1586 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 gnome_canvas_item_set (marker_drag_line, "points", marker_drag_line_points, NULL);
1949 gnome_canvas_item_set (range_marker_drag_rect, "x1", x1, "x2", x2, NULL);
1954 Editor::start_marker_grab (GnomeCanvasItem* item, GdkEvent* event)
1958 if ((marker = static_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "marker"))) == 0) {
1959 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
1965 Location *location = find_location_from_marker (marker, is_start);
1967 drag_info.item = item;
1968 drag_info.data = marker;
1969 drag_info.motion_callback = &Editor::marker_drag_motion_callback;
1970 drag_info.finished_callback = &Editor::marker_drag_finished_callback;
1974 drag_info.copied_location = new Location (*location);
1975 drag_info.pointer_frame_offset = drag_info.grab_frame - (is_start ? location->start() : location->end());
1977 update_marker_drag_item (location);
1979 if (location->is_mark()) {
1980 gnome_canvas_item_show (marker_drag_line);
1981 gnome_canvas_item_raise_to_top (marker_drag_line);
1984 gnome_canvas_item_show (range_marker_drag_rect);
1985 gnome_canvas_item_raise_to_top (range_marker_drag_rect);
1988 if (is_start) show_verbose_time_cursor (location->start(), 10);
1989 else show_verbose_time_cursor (location->end(), 10);
1993 Editor::marker_drag_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
1995 jack_nframes_t f_delta;
1996 Marker* marker = (Marker *) drag_info.data;
1997 Location *real_location;
1998 Location *copy_location;
2000 bool move_both = false;
2002 jack_nframes_t newframe;
2003 if (drag_info.pointer_frame_offset <= (long) drag_info.current_pointer_frame) {
2004 newframe = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2010 jack_nframes_t next = newframe;
2012 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2013 snap_to (newframe, 0, true);
2016 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) return;
2018 /* call this to find out if its the start or end */
2020 real_location = find_location_from_marker (marker, is_start);
2022 /* use the copy that we're "dragging" around */
2024 copy_location = drag_info.copied_location;
2026 f_delta = copy_location->end() - copy_location->start();
2028 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
2032 if (is_start) { // start marker
2035 copy_location->set_start (newframe);
2036 copy_location->set_end (newframe + f_delta);
2037 } else if (newframe < copy_location->end()) {
2038 copy_location->set_start (newframe);
2040 snap_to (next, 1, true);
2041 copy_location->set_end (next);
2042 copy_location->set_start (newframe);
2045 } else { // end marker
2048 copy_location->set_end (newframe);
2049 copy_location->set_start (newframe - f_delta);
2050 } else if (newframe > copy_location->start()) {
2051 copy_location->set_end (newframe);
2053 } else if (newframe > 0) {
2054 snap_to (next, -1, true);
2055 copy_location->set_start (next);
2056 copy_location->set_end (newframe);
2060 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
2061 drag_info.first_move = false;
2063 update_marker_drag_item (copy_location);
2065 LocationMarkers* lm = find_location_markers (real_location);
2066 lm->set_position (copy_location->start(), copy_location->end());
2068 show_verbose_time_cursor (newframe, 10);
2072 Editor::marker_drag_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
2074 if (drag_info.first_move) {
2075 marker_drag_motion_callback (item, event);
2079 Marker* marker = (Marker *) drag_info.data;
2081 Location * location = find_location_from_marker (marker, is_start);
2083 location->set (drag_info.copied_location->start(), drag_info.copied_location->end());
2086 gnome_canvas_item_hide (marker_drag_line);
2087 gnome_canvas_item_hide (range_marker_drag_rect);
2091 Editor::start_meter_marker_grab (GnomeCanvasItem* item, GdkEvent* event)
2094 MeterMarker* meter_marker;
2096 if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "marker"))) == 0) {
2097 fatal << _("programming error: meter marker canvas item has no marker object pointer!") << endmsg;
2101 meter_marker = dynamic_cast<MeterMarker*> (marker);
2103 MetricSection& section (meter_marker->meter());
2105 if (!section.movable()) {
2109 drag_info.item = item;
2110 drag_info.data = marker;
2111 drag_info.motion_callback = &Editor::meter_marker_drag_motion_callback;
2112 drag_info.finished_callback = &Editor::meter_marker_drag_finished_callback;
2116 drag_info.pointer_frame_offset = drag_info.grab_frame - meter_marker->meter().frame();
2118 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2122 Editor::meter_marker_drag_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
2124 MeterMarker* marker = (MeterMarker *) drag_info.data;
2125 jack_nframes_t adjusted_frame;
2127 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
2128 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2134 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2135 snap_to (adjusted_frame);
2138 if (adjusted_frame == drag_info.last_pointer_frame) return;
2140 marker->set_position (adjusted_frame);
2143 drag_info.last_pointer_frame = adjusted_frame;
2144 drag_info.first_move = false;
2146 show_verbose_time_cursor (adjusted_frame, 10);
2150 Editor::meter_marker_drag_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
2152 if (drag_info.first_move) return;
2154 meter_marker_drag_motion_callback (item, event);
2156 MeterMarker* marker = (MeterMarker *) drag_info.data;
2159 TempoMap& map (session->tempo_map());
2160 map.bbt_time (drag_info.last_pointer_frame, when);
2162 begin_reversible_command (_("move meter mark"));
2163 session->add_undo (map.get_memento());
2164 map.move_meter (marker->meter(), when);
2165 session->add_redo_no_execute (map.get_memento());
2166 commit_reversible_command ();
2170 Editor::start_tempo_marker_grab (GnomeCanvasItem* item, GdkEvent* event)
2173 TempoMarker* tempo_marker;
2175 if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "tempo_marker"))) == 0) {
2176 fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg;
2180 if ((tempo_marker = dynamic_cast<TempoMarker *> (marker)) == 0) {
2181 fatal << _("programming error: marker for tempo is not a tempo marker!") << endmsg;
2185 MetricSection& section (tempo_marker->tempo());
2187 if (!section.movable()) {
2191 drag_info.item = item;
2192 drag_info.data = marker;
2193 drag_info.motion_callback = &Editor::tempo_marker_drag_motion_callback;
2194 drag_info.finished_callback = &Editor::tempo_marker_drag_finished_callback;
2198 drag_info.pointer_frame_offset = drag_info.grab_frame - tempo_marker->tempo().frame();
2199 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2203 Editor::tempo_marker_drag_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
2205 TempoMarker* marker = (TempoMarker *) drag_info.data;
2206 jack_nframes_t adjusted_frame;
2208 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
2209 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2215 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2216 snap_to (adjusted_frame);
2219 if (adjusted_frame == drag_info.last_pointer_frame) return;
2221 /* OK, we've moved far enough to make it worth actually move the thing. */
2223 marker->set_position (adjusted_frame);
2225 show_verbose_time_cursor (adjusted_frame, 10);
2227 drag_info.last_pointer_frame = adjusted_frame;
2228 drag_info.first_move = false;
2232 Editor::tempo_marker_drag_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
2234 if (drag_info.first_move) return;
2236 tempo_marker_drag_motion_callback (item, event);
2238 TempoMarker* marker = (TempoMarker *) drag_info.data;
2241 TempoMap& map (session->tempo_map());
2242 map.bbt_time (drag_info.last_pointer_frame, when);
2244 begin_reversible_command (_("move tempo mark"));
2245 session->add_undo (map.get_memento());
2246 map.move_tempo (marker->tempo(), when);
2247 session->add_redo_no_execute (map.get_memento());
2248 commit_reversible_command ();
2252 Editor::remove_gain_control_point (GnomeCanvasItem*item, GdkEvent* event)
2254 ControlPoint* control_point;
2256 if ((control_point = reinterpret_cast<ControlPoint *> (gtk_object_get_data (GTK_OBJECT(item), "control_point"))) == 0) {
2257 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2261 // We shouldn't remove the first or last gain point
2262 if (control_point->line.is_last_point(*control_point) ||
2263 control_point->line.is_first_point(*control_point)) {
2267 control_point->line.remove_point (*control_point);
2271 Editor::remove_control_point (GnomeCanvasItem*item, GdkEvent* event)
2273 ControlPoint* control_point;
2275 if ((control_point = reinterpret_cast<ControlPoint *> (gtk_object_get_data (GTK_OBJECT(item), "control_point"))) == 0) {
2276 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2280 control_point->line.remove_point (*control_point);
2284 Editor::start_control_point_grab (GnomeCanvasItem* item, GdkEvent* event)
2286 ControlPoint* control_point;
2288 if ((control_point = reinterpret_cast<ControlPoint *> (gtk_object_get_data (GTK_OBJECT(item), "control_point"))) == 0) {
2289 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2293 drag_info.item = item;
2294 drag_info.data = control_point;
2295 drag_info.motion_callback = &Editor::control_point_drag_motion_callback;
2296 drag_info.finished_callback = &Editor::control_point_drag_finished_callback;
2298 start_grab (event, fader_cursor);
2300 control_point->line.start_drag (control_point, 0);
2302 float fraction = 1.0 - (control_point->get_y() / control_point->line.height());
2303 set_verbose_canvas_cursor (control_point->line.get_verbose_cursor_string (fraction),
2304 drag_info.current_pointer_x + 20, drag_info.current_pointer_y + 20);
2306 show_verbose_canvas_cursor ();
2310 Editor::control_point_drag_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
2312 ControlPoint* cp = reinterpret_cast<ControlPoint *> (drag_info.data);
2314 double cx = drag_info.current_pointer_x;
2315 double cy = drag_info.current_pointer_y;
2317 drag_info.cumulative_x_drag = cx - drag_info.grab_x ;
2318 drag_info.cumulative_y_drag = cy - drag_info.grab_y ;
2320 bool x_constrained = false;
2322 if (drag_info.x_constrained) {
2323 if (fabs(drag_info.cumulative_x_drag) < fabs(drag_info.cumulative_y_drag)) {
2324 cx = drag_info.grab_x;
2325 x_constrained = true;
2328 cy = drag_info.grab_y;
2333 gnome_canvas_item_w2i (cp->line.parent_group(), &cx, &cy);
2337 cy = min ((double) cp->line.height(), cy);
2339 //translate cx to frames
2340 jack_nframes_t cx_frames = (jack_nframes_t) floor (cx * frames_per_unit);
2342 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && !x_constrained) {
2343 snap_to (cx_frames);
2346 float fraction = 1.0 - (cy / cp->line.height());
2350 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
2356 cp->line.point_drag (*cp, cx_frames , fraction, push);
2358 set_verbose_canvas_cursor_text (cp->line.get_verbose_cursor_string (fraction));
2362 Editor::control_point_drag_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
2364 ControlPoint* cp = reinterpret_cast<ControlPoint *> (drag_info.data);
2365 control_point_drag_motion_callback (item, event);
2366 cp->line.end_drag (cp);
2370 Editor::start_line_grab_from_regionview (GnomeCanvasItem* item, GdkEvent* event)
2372 switch (mouse_mode) {
2374 start_line_grab (clicked_regionview->get_gain_line(), event);
2382 Editor::start_line_grab_from_line (GnomeCanvasItem* item, GdkEvent* event)
2386 if ((al = reinterpret_cast<AutomationLine*> (gtk_object_get_data (GTK_OBJECT(item), "line"))) == 0) {
2387 fatal << _("programming error: line canvas item has no line pointer!") << endmsg;
2391 start_line_grab (al, event);
2395 Editor::start_line_grab (AutomationLine* line, GdkEvent* event)
2399 jack_nframes_t frame_within_region;
2401 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2405 cx = event->button.x;
2406 cy = event->button.y;
2407 gnome_canvas_item_w2i (line->parent_group(), &cx, &cy);
2408 frame_within_region = (jack_nframes_t) floor (cx * frames_per_unit);
2410 if (!line->control_points_adjacent (frame_within_region, current_line_drag_info.before,
2411 current_line_drag_info.after)) {
2412 /* no adjacent points */
2416 drag_info.item = line->grab_item();
2417 drag_info.data = line;
2418 drag_info.motion_callback = &Editor::line_drag_motion_callback;
2419 drag_info.finished_callback = &Editor::line_drag_finished_callback;
2421 start_grab (event, fader_cursor);
2423 double fraction = 1.0 - (cy / line->height());
2425 line->start_drag (0, fraction);
2427 set_verbose_canvas_cursor (line->get_verbose_cursor_string (fraction),
2428 drag_info.current_pointer_x + 20, drag_info.current_pointer_y + 20);
2429 show_verbose_canvas_cursor ();
2433 Editor::line_drag_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
2435 AutomationLine* line = reinterpret_cast<AutomationLine *> (drag_info.data);
2436 double cx = drag_info.current_pointer_x;
2437 double cy = drag_info.current_pointer_y;
2439 gnome_canvas_item_w2i (line->parent_group(), &cx, &cy);
2442 fraction = 1.0 - (cy / line->height());
2446 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
2452 line->line_drag (current_line_drag_info.before, current_line_drag_info.after, fraction, push);
2454 set_verbose_canvas_cursor_text (line->get_verbose_cursor_string (fraction));
2458 Editor::line_drag_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
2460 AutomationLine* line = reinterpret_cast<AutomationLine *> (drag_info.data);
2461 line_drag_motion_callback (item, event);
2466 Editor::start_region_grab (GnomeCanvasItem* item, GdkEvent* event)
2468 if (selection->audio_regions.empty() || clicked_regionview == 0) {
2472 drag_info.copy = false;
2473 drag_info.item = item;
2474 drag_info.data = clicked_regionview;
2475 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2476 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2481 TimeAxisView* tvp = clicked_trackview;
2482 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
2484 if (tv && tv->is_audio_track()) {
2485 speed = tv->get_diskstream()->speed();
2488 drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region.position() / speed);
2489 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2490 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2491 // we want a move threshold
2492 drag_info.want_move_threshold = true;
2494 show_verbose_time_cursor (drag_info.last_frame_position, 10);
2496 begin_reversible_command (_("move region(s)"));
2500 Editor::start_region_copy_grab (GnomeCanvasItem* item, GdkEvent* event)
2502 if (selection->audio_regions.empty() || clicked_regionview == 0) {
2506 /* this is committed in the grab finished callback. */
2508 begin_reversible_command (_("Drag region copy"));
2510 /* duplicate the region(s) */
2512 vector<AudioRegionView*> new_regionviews;
2514 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
2515 AudioRegionView* rv;
2519 Playlist* to_playlist = rv->region.playlist();
2520 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&rv->get_time_axis_view());
2522 session->add_undo (to_playlist->get_memento ());
2523 latest_regionview = 0;
2525 sigc::connection c = atv->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
2527 /* create a new region with the same name.
2530 AudioRegion* newregion = new AudioRegion (rv->region);
2532 /* if the original region was locked, we don't care */
2534 newregion->set_locked (false);
2536 to_playlist->add_region (*newregion, (jack_nframes_t) (rv->region.position() * atv->get_diskstream()->speed()));
2540 if (latest_regionview) {
2541 new_regionviews.push_back (latest_regionview);
2546 if (new_regionviews.empty()) {
2550 /* reset selection to new regionviews */
2552 selection->set (new_regionviews);
2554 drag_info.item = new_regionviews.front()->get_canvas_group ();
2555 drag_info.copy = true;
2556 drag_info.data = new_regionviews.front();
2557 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2558 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2562 TimeAxisView* tv = &clicked_regionview->get_time_axis_view();
2563 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(tv);
2566 if (atv && atv->is_audio_track()) {
2567 speed = atv->get_diskstream()->speed();
2570 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2571 drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region.position() / speed);
2572 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2573 // we want a move threshold
2574 drag_info.want_move_threshold = true;
2576 show_verbose_time_cursor (drag_info.last_frame_position, 10);
2578 begin_reversible_command (_("copy region(s)"));
2582 Editor::start_region_brush_grab (GnomeCanvasItem* item, GdkEvent* event)
2584 if (selection->audio_regions.empty() || clicked_regionview == 0) {
2588 drag_info.copy = false;
2589 drag_info.item = item;
2590 drag_info.data = clicked_regionview;
2591 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2592 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2597 TimeAxisView* tvp = clicked_trackview;
2598 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
2600 if (tv && tv->is_audio_track()) {
2601 speed = tv->get_diskstream()->speed();
2604 drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region.position() / speed);
2605 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2606 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2607 // we want a move threshold
2608 drag_info.want_move_threshold = true;
2609 drag_info.brushing = true;
2611 begin_reversible_command (_("Drag region brush"));
2615 Editor::region_drag_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
2619 AudioRegionView *rv = reinterpret_cast<AudioRegionView*> (drag_info.data);
2620 jack_nframes_t pending_region_position = 0;
2621 int32_t pointer_y_span = 0, canvas_pointer_y_span = 0, original_pointer_order;
2622 int32_t visible_y_high = 0, visible_y_low = 512; //high meaning higher numbered.. not the height on the screen
2623 bool clamp_y_axis = false;
2624 vector<int32_t> height_list(512) ;
2625 vector<int32_t>::iterator j;
2627 /* Which trackview is this ? */
2629 TimeAxisView* tvp = trackview_by_y_position (drag_info.current_pointer_y);
2630 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
2632 /* The region motion is only processed if the pointer is over
2636 if (!tv || !tv->is_audio_track()) {
2637 /* To make sure we hide the verbose canvas cursor when the mouse is
2638 not held over and audiotrack.
2640 hide_verbose_canvas_cursor ();
2644 original_pointer_order = drag_info.last_trackview->order;
2646 /************************************************************
2648 ************************************************************/
2650 if (drag_info.brushing) {
2651 clamp_y_axis = true;
2656 if ((pointer_y_span = (drag_info.last_trackview->order - tv->order)) != 0) {
2658 int32_t children = 0, numtracks = 0;
2659 bitset <512> tracks (0x00);
2660 /* get a bitmask representing the visible tracks */
2662 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2663 TimeAxisView *tracklist_timeview;
2664 tracklist_timeview = (*i);
2665 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tracklist_timeview);
2666 list<TimeAxisView*> children_list;
2668 /* zeroes are audio tracks. ones are other types. */
2670 if (!atv2->hidden()) {
2672 if (visible_y_high < atv2->order) {
2673 visible_y_high = atv2->order;
2675 if (visible_y_low > atv2->order) {
2676 visible_y_low = atv2->order;
2679 if (!atv2->is_audio_track()) {
2680 tracks = tracks |= (0x01 << atv2->order);
2683 height_list[atv2->order] = (*i)->height;
2685 if ((children_list = atv2->get_child_list()).size() > 0) {
2686 for (list<TimeAxisView*>::iterator j = children_list.begin(); j != children_list.end(); ++j) {
2687 tracks = tracks |= (0x01 << (atv2->order + children));
2688 height_list[atv2->order + children] = (*j)->height;
2696 /* find the actual span according to the canvas */
2698 canvas_pointer_y_span = pointer_y_span;
2699 if (drag_info.last_trackview->order >= tv->order) {
2701 for (y = tv->order; y < drag_info.last_trackview->order; y++) {
2702 if (height_list[y] == 0 ) {
2703 canvas_pointer_y_span--;
2708 for (y = drag_info.last_trackview->order;y <= tv->order; y++) {
2709 if ( height_list[y] == 0 ) {
2710 canvas_pointer_y_span++;
2715 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
2716 AudioRegionView* rv2;
2718 double ix1, ix2, iy1, iy2;
2721 gnome_canvas_item_get_bounds (rv2->get_canvas_frame(), &ix1, &iy1, &ix2, &iy2);
2722 gnome_canvas_item_i2w (rv2->get_canvas_group(), &ix1, &iy1);
2723 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
2724 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2);
2726 if (atv2->order != original_pointer_order) {
2727 /* this isn't the pointer track */
2729 if (canvas_pointer_y_span > 0) {
2731 /* moving up the canvas */
2732 if ((atv2->order - canvas_pointer_y_span) >= visible_y_low) {
2734 int32_t visible_tracks = 0;
2735 while (visible_tracks < canvas_pointer_y_span ) {
2738 while (height_list[atv2->order - (visible_tracks - n)] == 0) {
2739 /* we're passing through a hidden track */
2744 if (tracks[atv2->order - (canvas_pointer_y_span - n)] != 0x00) {
2745 clamp_y_axis = true;
2749 clamp_y_axis = true;
2752 } else if (canvas_pointer_y_span < 0) {
2754 /*moving down the canvas*/
2756 if ((atv2->order - (canvas_pointer_y_span - n)) <= visible_y_high) { // we will overflow
2759 int32_t visible_tracks = 0;
2761 while (visible_tracks > canvas_pointer_y_span ) {
2764 while (height_list[atv2->order - (visible_tracks - n)] == 0) {
2768 if ( tracks[atv2->order - ( canvas_pointer_y_span - n)] != 0x00) {
2769 clamp_y_axis = true;
2774 clamp_y_axis = true;
2780 /* this is the pointer's track */
2781 if ((atv2->order - pointer_y_span) > visible_y_high) { // we will overflow
2782 clamp_y_axis = true;
2783 } else if ((atv2->order - pointer_y_span) < visible_y_low) { // we will underflow
2784 clamp_y_axis = true;
2792 } else if (drag_info.last_trackview == tv) {
2793 clamp_y_axis = true;
2797 if (!clamp_y_axis) {
2798 drag_info.last_trackview = tv;
2801 /************************************************************
2803 ************************************************************/
2805 /* compute the amount of pointer motion in frames, and where
2806 the region would be if we moved it by that much.
2809 if (drag_info.move_threshold_passsed) {
2811 if ((int32_t)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
2813 jack_nframes_t sync_frame;
2814 jack_nframes_t sync_offset;
2817 pending_region_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2819 sync_offset = rv->region.sync_offset (sync_dir);
2820 sync_frame = rv->region.adjust_to_sync (pending_region_position);
2822 /* we snap if the snap modifier is not enabled.
2825 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2826 snap_to (sync_frame);
2829 if (sync_frame - sync_offset <= sync_frame) {
2830 pending_region_position = sync_frame - (sync_dir*sync_offset);
2832 pending_region_position = 0;
2836 pending_region_position = 0;
2839 if (pending_region_position > max_frames - rv->region.length()) {
2840 pending_region_position = drag_info.last_frame_position;
2843 // printf ("3: pending_region_position= %lu %lu\n", pending_region_position, drag_info.last_frame_position );
2845 if (pending_region_position != drag_info.last_frame_position && !drag_info.x_constrained) {
2847 /* now compute the canvas unit distance we need to move the regiondrag_info.last_trackview->order
2848 to make it appear at the new location.
2851 if (pending_region_position > drag_info.last_frame_position) {
2852 x_delta = ((double) (pending_region_position - drag_info.last_frame_position) / frames_per_unit);
2854 x_delta = -((double) (drag_info.last_frame_position - pending_region_position) / frames_per_unit);
2857 drag_info.last_frame_position = pending_region_position;
2864 /* threshold not passed */
2869 /*************************************************************
2871 ************************************************************/
2873 if (x_delta == 0 && (pointer_y_span == 0)) {
2874 /* haven't reached next snap point, and we're not switching
2875 trackviews. nothing to do.
2881 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
2883 AudioRegionView* rv2;
2886 /* if any regionview is at zero, we need to know so we can
2887 stop further leftward motion.
2890 double ix1, ix2, iy1, iy2;
2891 gnome_canvas_item_get_bounds (rv2->get_canvas_frame(), &ix1, &iy1, &ix2, &iy2);
2892 gnome_canvas_item_i2w (rv2->get_canvas_group(), &ix1, &iy1);
2901 /*************************************************************
2903 ************************************************************/
2905 pair<set<Playlist*>::iterator,bool> insert_result;
2907 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
2909 AudioRegionView* rv;
2911 double ix1, ix2, iy1, iy2;
2912 int32_t temp_pointer_y_span = pointer_y_span;
2914 /* get item BBox, which will be relative to parent. so we have
2915 to query on a child, then convert to world coordinates using
2919 gnome_canvas_item_get_bounds (rv->get_canvas_frame(), &ix1, &iy1, &ix2, &iy2);
2920 gnome_canvas_item_i2w (rv->get_canvas_group(), &ix1, &iy1);
2921 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
2922 AudioTimeAxisView* canvas_atv = dynamic_cast<AudioTimeAxisView*>(tvp2);
2923 AudioTimeAxisView* temp_atv;
2925 if ((pointer_y_span != 0) && !clamp_y_axis) {
2928 for (j = height_list.begin(); j!= height_list.end(); j++) {
2929 if (x == canvas_atv->order) {
2930 /* we found the track the region is on */
2931 if (x != original_pointer_order) {
2932 /*this isn't from the same track we're dragging from */
2933 temp_pointer_y_span = canvas_pointer_y_span;
2935 while (temp_pointer_y_span > 0) {
2936 /* we're moving up canvas-wise,
2937 so we need to find the next track height
2939 if (j != height_list.begin()) {
2942 if (x != original_pointer_order) {
2943 /* we're not from the dragged track, so ignore hidden tracks. */
2945 temp_pointer_y_span++;
2949 temp_pointer_y_span--;
2951 while (temp_pointer_y_span < 0) {
2953 if (x != original_pointer_order) {
2955 temp_pointer_y_span--;
2959 if (j != height_list.end()) {
2962 temp_pointer_y_span++;
2964 /* find out where we'll be when we move and set height accordingly */
2966 tvp2 = trackview_by_y_position (iy1 + y_delta);
2967 temp_atv = dynamic_cast<AudioTimeAxisView*>(tvp2);
2968 rv->set_height (temp_atv->height);
2970 /* if you un-comment the following, the region colours will follow the track colours whilst dragging,
2971 personally, i think this can confuse things, but never mind.
2974 //const GdkColor& col (temp_atv->view->get_region_color());
2975 //rv->set_color (const_cast<GdkColor&>(col));
2982 /* prevent the regionview from being moved to before
2983 the zero position on the canvas.
2988 if (-x_delta > ix1) {
2991 } else if ((x_delta > 0) &&(rv->region.last_frame() > max_frames - x_delta)) {
2992 x_delta = max_frames - rv->region.last_frame();
2995 if (drag_info.first_move) {
2997 /* hide any dependent views */
2999 // rv->get_time_axis_view().hide_dependent_views (*rv);
3001 /* this is subtle. raising the regionview itself won't help,
3002 because raise_to_top() just puts the item on the top of
3003 its parent's stack. so, we need to put the trackview canvas_display group
3004 on the top, since its parent is the whole canvas.
3007 gnome_canvas_item_raise_to_top (rv->get_canvas_group());
3008 gnome_canvas_item_raise_to_top (rv->get_time_axis_view().canvas_display);
3009 gnome_canvas_item_raise_to_top (cursor_group);
3011 /* freeze the playlists from notifying till
3015 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&rv->get_time_axis_view());
3016 if (atv && atv->is_audio_track()) {
3017 AudioPlaylist* pl = atv->get_diskstream()->playlist();
3019 /* only freeze and capture state once */
3021 insert_result = motion_frozen_playlists.insert (pl);
3022 if (insert_result.second) {
3024 session->add_undo(pl->get_memento());
3030 if (drag_info.brushing) {
3031 mouse_brush_insert_region (rv, pending_region_position);
3033 rv->move (x_delta, y_delta);
3037 if (drag_info.first_move) {
3038 gnome_canvas_item_raise_to_top (cursor_group);
3041 drag_info.first_move = false;
3043 if (x_delta != 0 && !drag_info.brushing) {
3044 show_verbose_time_cursor (drag_info.last_frame_position, 10);
3050 Editor::region_drag_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
3052 jack_nframes_t where;
3053 AudioRegionView* rv = reinterpret_cast<AudioRegionView *> (drag_info.data);
3054 pair<set<Playlist*>::iterator,bool> insert_result;
3055 bool nocommit = true;
3057 AudioTimeAxisView* atv;
3058 bool regionview_y_movement;
3059 bool regionview_x_movement;
3061 /* first_move is set to false if the regionview has been moved in the
3065 if (drag_info.first_move) {
3072 /* The regionview has been moved at some stage during the grab so we need
3073 to account for any mouse movement between this event and the last one.
3076 region_drag_motion_callback (item, event);
3078 if (drag_info.brushing) {
3079 /* all changes were made during motion event handlers */
3083 /* adjust for track speed */
3086 atv = dynamic_cast<AudioTimeAxisView*> (drag_info.last_trackview);
3087 if (atv && atv->get_diskstream()) {
3088 speed = atv->get_diskstream()->speed();
3091 regionview_x_movement = (drag_info.last_frame_position != (jack_nframes_t) (rv->region.position()/speed));
3092 regionview_y_movement = (drag_info.last_trackview != &rv->get_time_axis_view());
3094 //printf ("last_frame: %s position is %lu %g\n", rv->get_time_axis_view().name().c_str(), drag_info.last_frame_position, speed);
3095 //printf ("last_rackview: %s \n", drag_info.last_trackview->name().c_str());
3097 if (regionview_y_movement) {
3099 /* motion between tracks */
3101 list<AudioRegionView*> new_selection;
3103 /* moved to a different audio track. */
3105 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ) {
3107 AudioRegionView* rv2 = (*i);
3109 /* the region that used to be in the old playlist is not
3110 moved to the new one - we make a copy of it. as a result,
3111 any existing editor for the region should no longer be
3115 if (!drag_info.copy) {
3116 rv2->hide_region_editor();
3118 new_selection.push_back (rv2);
3122 /* first, freeze the target tracks */
3124 for (list<AudioRegionView*>::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) {
3126 Playlist* from_playlist;
3127 Playlist* to_playlist;
3129 double ix1, ix2, iy1, iy2;
3131 gnome_canvas_item_get_bounds ((*i)->get_canvas_frame(), &ix1, &iy1, &ix2, &iy2);
3132 gnome_canvas_item_i2w ((*i)->get_canvas_group(), &ix1, &iy1);
3133 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
3134 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2);
3136 from_playlist = (*i)->region.playlist();
3137 to_playlist = atv2->playlist();
3139 /* the from_playlist was frozen in the "first_move" case
3140 of the motion handler. the insert can fail,
3141 but that doesn't matter. it just means
3142 we already have the playlist in the list.
3145 motion_frozen_playlists.insert (from_playlist);
3147 /* only freeze the to_playlist once */
3149 insert_result = motion_frozen_playlists.insert(to_playlist);
3150 if (insert_result.second) {
3151 to_playlist->freeze();
3152 session->add_undo(to_playlist->get_memento());
3157 /* now do it again with the actual operations */
3159 for (list<AudioRegionView*>::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) {
3161 Playlist* from_playlist;
3162 Playlist* to_playlist;
3164 double ix1, ix2, iy1, iy2;
3166 gnome_canvas_item_get_bounds ((*i)->get_canvas_frame(), &ix1, &iy1, &ix2, &iy2);
3167 gnome_canvas_item_i2w ((*i)->get_canvas_group(), &ix1, &iy1);
3168 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
3169 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2);
3171 from_playlist = (*i)->region.playlist();
3172 to_playlist = atv2->playlist();
3174 latest_regionview = 0;
3176 where = (jack_nframes_t) (unit_to_frame (ix1) * speed);
3177 Region* new_region = createRegion ((*i)->region);
3179 from_playlist->remove_region (&((*i)->region));
3181 sigc::connection c = atv2->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3182 to_playlist->add_region (*new_region, where);
3185 if (latest_regionview) {
3186 selection->add (latest_regionview);
3192 /* motion within a single track */
3194 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
3198 if (rv->region.locked()) {
3202 if (regionview_x_movement) {
3203 double ownspeed = 1.0;
3204 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&(rv->get_time_axis_view()));
3206 if (atv && atv->get_diskstream()) {
3207 ownspeed = atv->get_diskstream()->speed();
3210 /* base the new region position on the current position of the regionview.*/
3212 double ix1, ix2, iy1, iy2;
3214 gnome_canvas_item_get_bounds (rv->get_canvas_frame(), &ix1, &iy1, &ix2, &iy2);
3215 gnome_canvas_item_i2w (rv->get_canvas_group(), &ix1, &iy1);
3216 where = (jack_nframes_t) (unit_to_frame (ix1) * ownspeed);
3220 where = rv->region.position();
3223 rv->get_time_axis_view().reveal_dependent_views (*rv);
3225 session->add_undo (rv->region.playlist()->get_memento());
3226 rv->region.set_position (where, (void *) this);
3231 for (set<Playlist*>::iterator p = motion_frozen_playlists.begin(); p != motion_frozen_playlists.end(); ++p) {
3233 session->add_redo_no_execute ((*p)->get_memento());
3236 motion_frozen_playlists.clear ();
3239 commit_reversible_command ();
3244 Editor::region_view_item_click (AudioRegionView& rv, GdkEventButton* event)
3246 /* Either add to or set the set the region selection, unless
3247 this is an alignment click (control used)
3250 if (Keyboard::modifier_state_contains (event->state, Keyboard::Control)) {
3251 TimeAxisView* tv = &rv.get_time_axis_view();
3252 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(tv);
3254 if (atv && atv->is_audio_track()) {
3255 speed = atv->get_diskstream()->speed();
3258 if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Alt))) {
3260 align_region (rv.region, SyncPoint, (jack_nframes_t) (edit_cursor->current_frame * speed));
3262 } else if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Shift))) {
3264 align_region (rv.region, End, (jack_nframes_t) (edit_cursor->current_frame * speed));
3268 align_region (rv.region, Start, (jack_nframes_t) (edit_cursor->current_frame * speed));
3274 Editor::show_verbose_time_cursor (jack_nframes_t frame, double offset, double xpos, double ypos)
3285 switch (ARDOUR_UI::instance()->secondary_clock.mode ()) {
3286 case AudioClock::BBT:
3287 session->bbt_time (frame, bbt);
3288 snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32, bbt.bars, bbt.beats, bbt.ticks);
3291 case AudioClock::SMPTE:
3292 session->smpte_time (frame, smpte);
3293 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
3296 case AudioClock::MinSec:
3297 /* XXX fix this to compute min/sec properly */
3298 session->smpte_time (frame, smpte);
3299 secs = smpte.seconds + ((float) smpte.frames / session->smpte_frames_per_second);
3300 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%.4f", smpte.hours, smpte.minutes, secs);
3304 snprintf (buf, sizeof(buf), "%u", frame);
3308 if (xpos >= 0 && ypos >=0) {
3309 set_verbose_canvas_cursor (buf, xpos + offset, ypos + offset);
3312 set_verbose_canvas_cursor (buf, drag_info.current_pointer_x + offset, drag_info.current_pointer_y + offset);
3314 show_verbose_canvas_cursor ();
3318 Editor::show_verbose_duration_cursor (jack_nframes_t start, jack_nframes_t end, double offset, double xpos, double ypos)
3325 Meter meter_at_start(session->tempo_map().meter_at(start));
3331 switch (ARDOUR_UI::instance()->secondary_clock.mode ()) {
3332 case AudioClock::BBT:
3333 session->bbt_time (start, sbbt);
3334 session->bbt_time (end, ebbt);
3337 /* XXX this computation won't work well if the
3338 user makes a selection that spans any meter changes.
3341 ebbt.bars -= sbbt.bars;
3342 if (ebbt.beats >= sbbt.beats) {
3343 ebbt.beats -= sbbt.beats;
3346 ebbt.beats = int(meter_at_start.beats_per_bar()) + ebbt.beats - sbbt.beats;
3348 if (ebbt.ticks >= sbbt.ticks) {
3349 ebbt.ticks -= sbbt.ticks;
3352 ebbt.ticks = int(Meter::ticks_per_beat) + ebbt.ticks - sbbt.ticks;
3355 snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32, ebbt.bars, ebbt.beats, ebbt.ticks);
3358 case AudioClock::SMPTE:
3359 session->smpte_duration (end - start, smpte);
3360 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
3363 case AudioClock::MinSec:
3364 /* XXX fix this to compute min/sec properly */
3365 session->smpte_duration (end - start, smpte);
3366 secs = smpte.seconds + ((float) smpte.frames / session->smpte_frames_per_second);
3367 snprintf (buf, sizeof (buf), "%02ld:%02ld:%.4f", smpte.hours, smpte.minutes, secs);
3371 snprintf (buf, sizeof(buf), "%u", end - start);
3375 if (xpos >= 0 && ypos >=0) {
3376 set_verbose_canvas_cursor (buf, xpos + offset, ypos + offset);
3379 set_verbose_canvas_cursor (buf, drag_info.current_pointer_x + offset, drag_info.current_pointer_y + offset);
3381 show_verbose_canvas_cursor ();
3385 Editor::collect_new_region_view (AudioRegionView* rv)
3387 latest_regionview = rv;
3391 Editor::start_selection_grab (GnomeCanvasItem* item, GdkEvent* event)
3393 if (clicked_regionview == 0) {
3397 /* lets try to create new Region for the selection */
3399 vector<AudioRegion*> new_regions;
3400 create_region_from_selection (new_regions);
3402 if (new_regions.empty()) {
3406 /* XXX fix me one day to use all new regions */
3408 Region* region = new_regions.front();
3410 /* add it to the current stream/playlist.
3412 tricky: the streamview for the track will add a new regionview. we will
3413 catch the signal it sends when it creates the regionview to
3414 set the regionview we want to then drag.
3417 latest_regionview = 0;
3418 sigc::connection c = clicked_audio_trackview->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3420 /* A selection grab currently creates two undo/redo operations, one for
3421 creating the new region and another for moving it.
3424 begin_reversible_command (_("selection grab"));
3426 Playlist* playlist = clicked_trackview->playlist();
3428 session->add_undo (playlist->get_memento ());
3429 clicked_trackview->playlist()->add_region (*region, selection->time[clicked_selection].start);
3430 session->add_redo_no_execute (playlist->get_memento ());
3432 commit_reversible_command ();
3436 if (latest_regionview == 0) {
3437 /* something went wrong */
3441 /* we need to deselect all other regionviews, and select this one
3442 i'm ignoring undo stuff, because the region creation will take care of it */
3443 selection->set (latest_regionview);
3445 drag_info.item = latest_regionview->get_canvas_group();
3446 drag_info.data = latest_regionview;
3447 drag_info.motion_callback = &Editor::region_drag_motion_callback;
3448 drag_info.finished_callback = &Editor::region_drag_finished_callback;
3452 drag_info.last_trackview = clicked_trackview;
3453 drag_info.last_frame_position = latest_regionview->region.position();
3454 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
3456 show_verbose_time_cursor (drag_info.last_frame_position, 10);
3460 Editor::cancel_selection ()
3462 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3463 (*i)->hide_selection ();
3465 selection->clear ();
3466 clicked_selection = 0;
3470 Editor::start_selection_op (GnomeCanvasItem* item, GdkEvent* event, SelectionOp op)
3472 jack_nframes_t start = 0;
3473 jack_nframes_t end = 0;
3479 drag_info.item = item;
3480 drag_info.motion_callback = &Editor::drag_selection;
3481 drag_info.finished_callback = &Editor::end_selection_op;
3486 case CreateSelection:
3488 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
3489 drag_info.copy = true;
3491 drag_info.copy = false;
3493 start_grab (event, selector_cursor);
3496 case SelectionStartTrim:
3497 clicked_trackview->order_selection_trims (item, true);
3498 start_grab (event, trimmer_cursor);
3499 start = selection->time[clicked_selection].start;
3500 drag_info.pointer_frame_offset = drag_info.grab_frame - start;
3503 case SelectionEndTrim:
3504 clicked_trackview->order_selection_trims (item, false);
3505 start_grab (event, trimmer_cursor);
3506 end = selection->time[clicked_selection].end;
3507 drag_info.pointer_frame_offset = drag_info.grab_frame - end;
3511 start = selection->time[clicked_selection].start;
3513 drag_info.pointer_frame_offset = drag_info.grab_frame - start;
3517 if (selection_op == SelectionMove) {
3518 show_verbose_time_cursor(start, 10);
3520 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
3525 Editor::drag_selection (GnomeCanvasItem* item, GdkEvent* event)
3527 jack_nframes_t start = 0;
3528 jack_nframes_t end = 0;
3529 jack_nframes_t length;
3530 jack_nframes_t pending_position;
3532 if ((int32_t) drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
3533 pending_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
3536 pending_position = 0;
3539 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3540 snap_to (pending_position);
3543 /* only alter selection if the current frame is
3544 different from the last frame position (adjusted)
3547 if (pending_position == drag_info.last_pointer_frame) return;
3549 switch (selection_op) {
3550 case CreateSelection:
3552 if (drag_info.first_move) {
3553 snap_to (drag_info.grab_frame);
3556 if (pending_position < drag_info.grab_frame) {
3557 start = pending_position;
3558 end = drag_info.grab_frame;
3560 end = pending_position;
3561 start = drag_info.grab_frame;
3564 /* first drag: Either add to the selection
3565 or create a new selection->
3568 if (drag_info.first_move) {
3570 begin_reversible_command (_("range selection"));
3572 if (drag_info.copy) {
3573 /* adding to the selection */
3574 clicked_selection = selection->add (start, end);
3575 drag_info.copy = false;
3577 /* new selection-> */
3578 clicked_selection = selection->set (clicked_trackview, start, end);
3583 case SelectionStartTrim:
3585 if (drag_info.first_move) {
3586 begin_reversible_command (_("trim selection start"));
3589 start = selection->time[clicked_selection].start;
3590 end = selection->time[clicked_selection].end;
3592 if (pending_position > end) {
3595 start = pending_position;
3599 case SelectionEndTrim:
3601 if (drag_info.first_move) {
3602 begin_reversible_command (_("trim selection end"));
3605 start = selection->time[clicked_selection].start;
3606 end = selection->time[clicked_selection].end;
3608 if (pending_position < start) {
3611 end = pending_position;
3618 if (drag_info.first_move) {
3619 begin_reversible_command (_("move selection"));
3622 start = selection->time[clicked_selection].start;
3623 end = selection->time[clicked_selection].end;
3625 length = end - start;
3627 start = pending_position;
3630 end = start + length;
3636 if (event->button.x >= track_canvas_scroller.get_hadjustment()->get_value() + canvas_width) {
3637 start_canvas_autoscroll (1);
3641 selection->replace (clicked_selection, start, end);
3644 drag_info.last_pointer_frame = pending_position;
3645 drag_info.first_move = false;
3647 if (selection_op == SelectionMove) {
3648 show_verbose_time_cursor(start, 10);
3650 show_verbose_time_cursor(pending_position, 10);
3655 Editor::end_selection_op (GnomeCanvasItem* item, GdkEvent* event)
3657 if (!drag_info.first_move) {
3658 drag_selection (item, event);
3659 /* XXX this is not object-oriented programming at all. ick */
3660 if (selection->time.consolidate()) {
3661 selection->TimeChanged ();
3663 commit_reversible_command ();
3665 /* just a click, no pointer movement.*/
3667 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3669 selection->clear_time();
3674 /* XXX what happens if its a music selection? */
3675 session->set_audio_range (selection->time);
3676 stop_canvas_autoscroll ();
3680 Editor::start_trim (GnomeCanvasItem* item, GdkEvent* event)
3683 TimeAxisView* tvp = clicked_trackview;
3684 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3686 if (tv && tv->is_audio_track()) {
3687 speed = tv->get_diskstream()->speed();
3690 jack_nframes_t region_start = (jack_nframes_t) (clicked_regionview->region.position() / speed);
3691 jack_nframes_t region_end = (jack_nframes_t) (clicked_regionview->region.last_frame() / speed);
3692 jack_nframes_t region_length = (jack_nframes_t) (clicked_regionview->region.length() / speed);
3694 //drag_info.item = clicked_regionview->get_name_highlight();
3695 drag_info.item = item;
3696 drag_info.motion_callback = &Editor::trim_motion_callback;
3697 drag_info.finished_callback = &Editor::trim_finished_callback;
3699 start_grab (event, trimmer_cursor);
3701 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
3702 trim_op = ContentsTrim;
3704 /* These will get overridden for a point trim.*/
3705 if (drag_info.current_pointer_frame < (region_start + region_length/2)) {
3706 /* closer to start */
3707 trim_op = StartTrim;
3708 } else if (drag_info.current_pointer_frame > (region_end - region_length/2)) {
3716 show_verbose_time_cursor(region_start, 10);
3719 show_verbose_time_cursor(region_end, 10);
3722 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
3726 flush_track_canvas ();
3730 Editor::trim_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
3732 AudioRegionView* rv = clicked_regionview;
3733 jack_nframes_t frame_delta = 0;
3734 bool left_direction;
3735 bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier());
3737 /* snap modifier works differently here..
3738 its' current state has to be passed to the
3739 various trim functions in order to work properly
3743 TimeAxisView* tvp = clicked_trackview;
3744 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3746 if (tv && tv->is_audio_track()) {
3747 speed = tv->get_diskstream()->speed();
3750 if (drag_info.last_pointer_frame > drag_info.current_pointer_frame) {
3751 left_direction = true;
3753 left_direction = false;
3757 snap_to (drag_info.current_pointer_frame);
3760 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) {
3764 if (drag_info.first_move) {
3770 trim_type = "Region start trim";
3773 trim_type = "Region end trim";
3776 trim_type = "Region content trim";
3780 begin_reversible_command (trim_type);
3782 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
3783 (*i)->region.freeze ();
3784 (*i)->temporarily_hide_envelope ();
3785 session->add_undo ((*i)->region.playlist()->get_memento());
3789 if (left_direction) {
3790 frame_delta = (drag_info.last_pointer_frame - drag_info.current_pointer_frame);
3792 frame_delta = (drag_info.current_pointer_frame - drag_info.last_pointer_frame);
3797 if ((left_direction == false) && (drag_info.current_pointer_frame <= rv->region.first_frame()/speed)) {
3800 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
3801 single_start_trim (**i, frame_delta, left_direction, obey_snap);
3807 if ((left_direction == true) && (drag_info.current_pointer_frame > (jack_nframes_t) (rv->region.last_frame()/speed))) {
3810 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
3811 single_end_trim (**i, frame_delta, left_direction, obey_snap);
3818 bool swap_direction = false;
3820 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
3821 swap_direction = true;
3824 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin();
3825 i != selection->audio_regions.by_layer().end(); ++i)
3827 single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
3835 show_verbose_time_cursor((jack_nframes_t) (rv->region.position()/speed), 10);
3838 show_verbose_time_cursor((jack_nframes_t) (rv->region.last_frame()/speed), 10);
3841 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
3845 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
3846 drag_info.first_move = false;
3850 Editor::single_contents_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool swap_direction, bool obey_snap)
3852 Region& region (rv.region);
3854 if (region.locked()) {
3858 jack_nframes_t new_bound;
3861 TimeAxisView* tvp = clicked_trackview;
3862 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3864 if (tv && tv->is_audio_track()) {
3865 speed = tv->get_diskstream()->speed();
3868 if (left_direction) {
3869 if (swap_direction) {
3870 new_bound = (jack_nframes_t) (region.position()/speed) + frame_delta;
3872 new_bound = (jack_nframes_t) (region.position()/speed) - frame_delta;
3875 if (swap_direction) {
3876 new_bound = (jack_nframes_t) (region.position()/speed) - frame_delta;
3878 new_bound = (jack_nframes_t) (region.position()/speed) + frame_delta;
3883 snap_to (new_bound);
3885 region.trim_start ((jack_nframes_t) (new_bound * speed), this);
3886 rv.region_changed (StartChanged);
3890 Editor::single_start_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool obey_snap)
3892 Region& region (rv.region);
3894 if (region.locked()) {
3898 jack_nframes_t new_bound;
3901 TimeAxisView* tvp = clicked_trackview;
3902 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3904 if (tv && tv->is_audio_track()) {
3905 speed = tv->get_diskstream()->speed();
3908 if (left_direction) {
3909 new_bound = (jack_nframes_t) (region.position()/speed) - frame_delta;
3911 new_bound = (jack_nframes_t) (region.position()/speed) + frame_delta;
3915 snap_to (new_bound, (left_direction ? 0 : 1));
3918 region.trim_front ((jack_nframes_t) (new_bound * speed), this);
3920 rv.region_changed (Change (LengthChanged|PositionChanged|StartChanged));
3924 Editor::single_end_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool obey_snap)
3926 Region& region (rv.region);
3928 if (region.locked()) {
3932 jack_nframes_t new_bound;
3935 TimeAxisView* tvp = clicked_trackview;
3936 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3938 if (tv && tv->is_audio_track()) {
3939 speed = tv->get_diskstream()->speed();
3942 if (left_direction) {
3943 new_bound = (jack_nframes_t) ((region.last_frame() + 1)/speed) - frame_delta;
3945 new_bound = (jack_nframes_t) ((region.last_frame() + 1)/speed) + frame_delta;
3949 snap_to (new_bound);
3951 region.trim_end ((jack_nframes_t) (new_bound * speed), this);
3952 rv.region_changed (LengthChanged);
3956 Editor::trim_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
3958 if (!drag_info.first_move) {
3959 trim_motion_callback (item, event);
3961 if (!clicked_regionview->get_selected()) {
3962 thaw_region_after_trim (*clicked_regionview);
3965 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin();
3966 i != selection->audio_regions.by_layer().end(); ++i)
3968 thaw_region_after_trim (**i);
3971 commit_reversible_command();
3973 /* no mouse movement */
3977 flush_track_canvas ();
3981 Editor::point_trim (GdkEvent* event)
3983 AudioRegionView* rv = clicked_regionview;
3984 jack_nframes_t new_bound = drag_info.current_pointer_frame;
3986 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3987 snap_to (new_bound);
3990 /* Choose action dependant on which button was pressed */
3991 switch (event->button.button) {
3993 trim_op = StartTrim;
3994 begin_reversible_command (_("Start point trim"));
3996 if (rv->get_selected()) {
3998 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin();
3999 i != selection->audio_regions.by_layer().end(); ++i)
4001 if (!(*i)->region.locked()) {
4002 session->add_undo ((*i)->region.playlist()->get_memento());
4003 (*i)->region.trim_front (new_bound, this);
4004 session->add_redo_no_execute ((*i)->region.playlist()->get_memento());
4010 if (!rv->region.locked()) {
4011 session->add_undo (rv->region.playlist()->get_memento());
4012 rv->region.trim_front (new_bound, this);
4013 session->add_redo_no_execute (rv->region.playlist()->get_memento());
4017 commit_reversible_command();
4022 begin_reversible_command (_("End point trim"));
4024 if (rv->get_selected()) {
4026 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i)
4028 if (!(*i)->region.locked()) {
4029 session->add_undo ((*i)->region.playlist()->get_memento());
4030 (*i)->region.trim_end (new_bound, this);
4031 session->add_redo_no_execute ((*i)->region.playlist()->get_memento());
4037 if (!rv->region.locked()) {
4038 session->add_undo (rv->region.playlist()->get_memento());
4039 rv->region.trim_end (new_bound, this);
4040 session->add_redo_no_execute (rv->region.playlist()->get_memento());
4044 commit_reversible_command();
4053 Editor::thaw_region_after_trim (AudioRegionView& rv)
4055 Region& region (rv.region);
4057 if (region.locked()) {
4061 region.thaw (_("trimmed region"));
4062 session->add_redo_no_execute (region.playlist()->get_memento());
4064 rv.unhide_envelope ();
4068 Editor::hide_marker (GnomeCanvasItem* item, GdkEvent* event)
4073 if ((marker = static_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "marker"))) == 0) {
4074 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
4078 Location* location = find_location_from_marker (marker, is_start);
4079 location->set_hidden (true, this);
4084 Editor::start_range_markerbar_op (GnomeCanvasItem* item, GdkEvent* event, RangeMarkerOp op)
4091 drag_info.item = item;
4092 drag_info.motion_callback = &Editor::drag_range_markerbar_op;
4093 drag_info.finished_callback = &Editor::end_range_markerbar_op;
4095 range_marker_op = op;
4097 if (!temp_location) {
4098 temp_location = new Location;
4102 case CreateRangeMarker:
4103 case CreateTransportMarker:
4105 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
4106 drag_info.copy = true;
4108 drag_info.copy = false;
4110 start_grab (event, selector_cursor);
4114 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
4119 Editor::drag_range_markerbar_op (GnomeCanvasItem* item, GdkEvent* event)
4121 jack_nframes_t start = 0;
4122 jack_nframes_t end = 0;
4124 GnomeCanvasItem * crect = (range_marker_op == CreateRangeMarker) ? range_bar_drag_rect: transport_bar_drag_rect;
4126 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4127 snap_to (drag_info.current_pointer_frame);
4130 /* only alter selection if the current frame is
4131 different from the last frame position.
4134 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) return;
4136 switch (range_marker_op) {
4137 case CreateRangeMarker:
4138 case CreateTransportMarker:
4139 if (drag_info.first_move) {
4140 snap_to (drag_info.grab_frame);
4143 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4144 start = drag_info.current_pointer_frame;
4145 end = drag_info.grab_frame;
4147 end = drag_info.current_pointer_frame;
4148 start = drag_info.grab_frame;
4151 /* first drag: Either add to the selection
4152 or create a new selection->
4155 if (drag_info.first_move) {
4157 temp_location->set (start, end);
4159 gnome_canvas_item_show (crect);
4161 update_marker_drag_item (temp_location);
4162 gnome_canvas_item_show (range_marker_drag_rect);
4163 gnome_canvas_item_raise_to_top (range_marker_drag_rect);
4170 if (event->button.x >= track_canvas_scroller.get_hadjustment()->get_value() + canvas_width) {
4171 start_canvas_autoscroll (1);
4175 temp_location->set (start, end);
4177 double x1 = frame_to_pixel (start);
4178 double x2 = frame_to_pixel (end);
4179 gnome_canvas_item_set (crect, "x1", x1, "x2", x2, NULL);
4181 update_marker_drag_item (temp_location);
4184 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4185 drag_info.first_move = false;
4187 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
4192 Editor::end_range_markerbar_op (GnomeCanvasItem* item, GdkEvent* event)
4194 Location * newloc = 0;
4196 if (!drag_info.first_move) {
4197 drag_range_markerbar_op (item, event);
4199 switch (range_marker_op)
4201 case CreateRangeMarker:
4202 begin_reversible_command (_("new range marker"));
4203 session->add_undo (session->locations()->get_memento());
4204 newloc = new Location(temp_location->start(), temp_location->end(), "unnamed");
4205 session->locations()->add (newloc, true);
4206 session->add_redo_no_execute (session->locations()->get_memento());
4207 commit_reversible_command ();
4209 gnome_canvas_item_hide (range_bar_drag_rect);
4210 gnome_canvas_item_hide (range_marker_drag_rect);
4213 case CreateTransportMarker:
4214 // popup menu to pick loop or punch
4215 new_transport_marker_context_menu (&event->button, item);
4220 /* just a click, no pointer movement.*/
4222 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
4229 stop_canvas_autoscroll ();
4235 Editor::start_mouse_zoom (GnomeCanvasItem* item, GdkEvent* event)
4237 drag_info.item = item;
4238 drag_info.motion_callback = &Editor::drag_mouse_zoom;
4239 drag_info.finished_callback = &Editor::end_mouse_zoom;
4241 start_grab (event, zoom_cursor);
4243 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4247 Editor::drag_mouse_zoom (GnomeCanvasItem* item, GdkEvent* event)
4249 jack_nframes_t start;
4252 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4253 snap_to (drag_info.current_pointer_frame);
4255 if (drag_info.first_move) {
4256 snap_to (drag_info.grab_frame);
4260 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) return;
4262 /* base start and end on initial click position */
4263 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4264 start = drag_info.current_pointer_frame;
4265 end = drag_info.grab_frame;
4267 end = drag_info.current_pointer_frame;
4268 start = drag_info.grab_frame;
4273 if (drag_info.first_move) {
4274 gnome_canvas_item_show (zoom_rect);
4275 gnome_canvas_item_raise_to_top (zoom_rect);
4278 reposition_zoom_rect(start, end);
4280 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4281 drag_info.first_move = false;
4283 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4288 Editor::end_mouse_zoom (GnomeCanvasItem* item, GdkEvent* event)
4290 if (!drag_info.first_move) {
4291 drag_mouse_zoom (item, event);
4293 if (drag_info.grab_frame < drag_info.last_pointer_frame) {
4294 temporal_zoom_by_frame (drag_info.grab_frame, drag_info.last_pointer_frame, "mouse zoom");
4296 temporal_zoom_by_frame (drag_info.last_pointer_frame, drag_info.grab_frame, "mouse zoom");
4299 temporal_zoom_to_frame (false, drag_info.grab_frame);
4301 temporal_zoom_step (false);
4302 center_screen (drag_info.grab_frame);
4306 gnome_canvas_item_hide (zoom_rect);
4310 Editor::reposition_zoom_rect (jack_nframes_t start, jack_nframes_t end)
4312 double x1 = frame_to_pixel (start);
4313 double x2 = frame_to_pixel (end);
4314 double y2 = canvas_height - 2;
4316 gtk_object_set (GTK_OBJECT(zoom_rect),
4325 Editor::start_rubberband_select (GnomeCanvasItem* item, GdkEvent* event)
4327 drag_info.item = item;
4328 drag_info.motion_callback = &Editor::drag_rubberband_select;
4329 drag_info.finished_callback = &Editor::end_rubberband_select;
4331 start_grab (event, cross_hair_cursor);
4333 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4337 Editor::drag_rubberband_select (GnomeCanvasItem* item, GdkEvent* event)
4339 jack_nframes_t start;
4344 /* use a bigger drag threshold than the default */
4346 if (abs ((int) (drag_info.current_pointer_frame - drag_info.grab_frame)) < 8) {
4350 // if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4351 // snap_to (drag_info.current_pointer_frame);
4353 // if (drag_info.first_move) {
4354 // snap_to (drag_info.grab_frame);
4359 /* base start and end on initial click position */
4360 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4361 start = drag_info.current_pointer_frame;
4362 end = drag_info.grab_frame;
4364 end = drag_info.current_pointer_frame;
4365 start = drag_info.grab_frame;
4368 if (drag_info.current_pointer_y < drag_info.grab_y) {
4369 y1 = drag_info.current_pointer_y;
4370 y2 = drag_info.grab_y;
4373 y2 = drag_info.current_pointer_y;
4374 y1 = drag_info.grab_y;
4378 if (start != end || y1 != y2) {
4380 double x1 = frame_to_pixel (start);
4381 double x2 = frame_to_pixel (end);
4383 gtk_object_set (GTK_OBJECT(rubberband_rect),
4390 gnome_canvas_item_show (rubberband_rect);
4391 gnome_canvas_item_raise_to_top (rubberband_rect);
4393 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4394 drag_info.first_move = false;
4396 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4401 Editor::end_rubberband_select (GnomeCanvasItem* item, GdkEvent* event)
4403 if (!drag_info.first_move) {
4405 drag_rubberband_select (item, event);
4408 if (drag_info.current_pointer_y < drag_info.grab_y) {
4409 y1 = drag_info.current_pointer_y;
4410 y2 = drag_info.grab_y;
4413 y2 = drag_info.current_pointer_y;
4414 y1 = drag_info.grab_y;
4418 bool add = Keyboard::modifier_state_contains (event->button.state, Keyboard::Shift);
4421 begin_reversible_command (_("select regions"));
4423 if (drag_info.grab_frame < drag_info.last_pointer_frame) {
4424 commit = select_all_within (drag_info.grab_frame, drag_info.last_pointer_frame, y1, y2, add);
4426 commit = select_all_within (drag_info.last_pointer_frame, drag_info.grab_frame, y1, y2, add);
4430 commit_reversible_command ();
4434 selection->clear_audio_regions();
4435 selection->clear_points ();
4436 selection->clear_lines ();
4439 gnome_canvas_item_hide (rubberband_rect);
4444 Editor::mouse_rename_region (GnomeCanvasItem* item, GdkEvent* event)
4446 using namespace Gtkmm2ext;
4448 ArdourPrompter prompter (false);
4450 prompter.set_prompt (_("Name for region:"));
4451 prompter.set_initial_text (clicked_regionview->region.name());
4452 prompter.show_all ();
4453 prompter.done.connect (Main::quit.slot());
4457 if (prompter.status == Prompter::cancelled) {
4463 prompter.get_result(str);
4464 clicked_regionview->region.set_name (str);
4470 Editor::start_time_fx (GnomeCanvasItem* item, GdkEvent* event)
4472 drag_info.item = item;
4473 drag_info.motion_callback = &Editor::time_fx_motion;
4474 drag_info.finished_callback = &Editor::end_time_fx;
4478 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4482 Editor::time_fx_motion (GnomeCanvasItem *item, GdkEvent* event)
4484 AudioRegionView* rv = clicked_regionview;
4486 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4487 snap_to (drag_info.current_pointer_frame);
4490 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) {
4494 if (drag_info.current_pointer_frame > rv->region.position()) {
4495 rv->get_time_axis_view().show_timestretch (rv->region.position(), drag_info.current_pointer_frame);
4498 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4499 drag_info.first_move = false;
4501 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4505 Editor::end_time_fx (GnomeCanvasItem* item, GdkEvent* event)
4507 clicked_regionview->get_time_axis_view().hide_timestretch ();
4509 if (drag_info.first_move) {
4513 jack_nframes_t newlen = drag_info.last_pointer_frame - clicked_regionview->region.position();
4514 float percentage = (float) ((double) newlen - (double) clicked_regionview->region.length()) / ((double) newlen) * 100.0f;
4516 begin_reversible_command (_("timestretch"));
4518 if (run_timestretch (selection->audio_regions, percentage) == 0) {
4519 session->commit_reversible_command ();
4524 Editor::mouse_brush_insert_region (AudioRegionView* rv, jack_nframes_t pos)
4526 /* no brushing without a useful snap setting */
4528 switch (snap_mode) {
4530 return; /* can't work because it allows region to be placed anywhere */
4535 switch (snap_type) {
4538 case SnapToEditCursor:
4545 /* don't brush a copy over the original */
4547 if (pos == rv->region.position()) {
4551 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&rv->get_time_axis_view());
4553 if (atv == 0 || !atv->is_audio_track()) {
4557 Playlist* playlist = atv->playlist();
4558 double speed = atv->get_diskstream()->speed();
4560 session->add_undo (playlist->get_memento());
4561 playlist->add_region (*(new AudioRegion (rv->region)), (jack_nframes_t) (pos * speed));
4562 session->add_redo_no_execute (playlist->get_memento());
4564 // playlist is frozen, so we have to update manually
4566 playlist->StateChanged (Change (~0)); /* EMIT SIGNAL */
4570 Editor::track_height_step_timeout ()
4573 struct timeval delta;
4575 gettimeofday (&now, 0);
4576 timersub (&now, &last_track_height_step_timestamp, &delta);
4578 if (delta.tv_sec * 1000000 + delta.tv_usec > 250000) { /* milliseconds */
4579 current_stepping_trackview = 0;