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"
46 #include "extra_bind.h"
48 #include <ardour/types.h>
49 #include <ardour/route.h>
50 #include <ardour/audio_track.h>
51 #include <ardour/diskstream.h>
52 #include <ardour/playlist.h>
53 #include <ardour/audioplaylist.h>
54 #include <ardour/audioregion.h>
55 #include <ardour/dB.h>
56 #include <ardour/utils.h>
57 #include <ardour/region_factory.h>
64 using namespace ARDOUR;
67 using namespace Editing;
70 Editor::event_frame (GdkEvent* event, double* pcx, double* pcy)
84 switch (event->type) {
85 case GDK_BUTTON_RELEASE:
86 case GDK_BUTTON_PRESS:
87 case GDK_2BUTTON_PRESS:
88 case GDK_3BUTTON_PRESS:
89 gnome_canvas_w2c_d (GNOME_CANVAS(track_gnome_canvas), event->button.x, event->button.y, pcx, pcy);
91 case GDK_MOTION_NOTIFY:
92 gnome_canvas_w2c_d (GNOME_CANVAS(track_gnome_canvas), event->motion.x, event->motion.y, pcx, pcy);
94 case GDK_ENTER_NOTIFY:
95 case GDK_LEAVE_NOTIFY:
96 gnome_canvas_w2c_d (GNOME_CANVAS(track_gnome_canvas), event->crossing.x, event->crossing.y, pcx, pcy);
99 warning << string_compose (_("Editor::event_frame() used on unhandled event type %1"), event->type) << endmsg;
103 /* note that pixel_to_frame() never returns less than zero, so even if the pixel
104 position is negative (as can be the case with motion events in particular),
105 the frame location is always positive.
108 return pixel_to_frame (*pcx);
112 Editor::mouse_mode_toggled (MouseMode m)
114 if (ignore_mouse_mode_toggle) {
120 if (mouse_select_button.get_active()) {
126 if (mouse_move_button.get_active()) {
132 if (mouse_gain_button.get_active()) {
138 if (mouse_zoom_button.get_active()) {
144 if (mouse_timefx_button.get_active()) {
150 if (mouse_audition_button.get_active()) {
161 Editor::set_mouse_mode (MouseMode m, bool force)
163 if (drag_info.item) {
167 if (m == mouse_mode && !force) {
175 if (mouse_mode != MouseRange) {
177 /* in all modes except range, hide the range selection,
178 show the object (region) selection.
181 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
182 (*i)->set_should_show_selection (true);
184 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
185 (*i)->hide_selection ();
190 /* in range mode, hide object (region) selection, and show the
194 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
195 (*i)->set_should_show_selection (false);
197 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
198 if ((*i)->selected()) {
199 (*i)->show_selection (selection->time);
204 /* XXX the hack of unsetting all other buttongs should go
205 away once GTK2 allows us to use regular radio buttons drawn like
206 normal buttons, rather than my silly GroupedButton hack.
209 ignore_mouse_mode_toggle = true;
211 switch (mouse_mode) {
213 mouse_select_button.set_active (true);
214 current_canvas_cursor = selector_cursor;
218 mouse_move_button.set_active (true);
219 current_canvas_cursor = grabber_cursor;
223 mouse_gain_button.set_active (true);
224 current_canvas_cursor = cross_hair_cursor;
228 mouse_zoom_button.set_active (true);
229 current_canvas_cursor = zoom_cursor;
233 mouse_timefx_button.set_active (true);
234 current_canvas_cursor = time_fx_cursor; // just use playhead
238 mouse_audition_button.set_active (true);
239 current_canvas_cursor = speaker_cursor;
243 ignore_mouse_mode_toggle = false;
246 gdk_window_set_cursor (track_canvas_scroller.get_window(), current_canvas_cursor);
251 Editor::step_mouse_mode (bool next)
253 switch (current_mouse_mode()) {
255 if (next) set_mouse_mode (MouseRange);
256 else set_mouse_mode (MouseTimeFX);
260 if (next) set_mouse_mode (MouseZoom);
261 else set_mouse_mode (MouseObject);
265 if (next) set_mouse_mode (MouseGain);
266 else set_mouse_mode (MouseRange);
270 if (next) set_mouse_mode (MouseTimeFX);
271 else set_mouse_mode (MouseZoom);
275 if (next) set_mouse_mode (MouseAudition);
276 else set_mouse_mode (MouseGain);
280 if (next) set_mouse_mode (MouseObject);
281 else set_mouse_mode (MouseTimeFX);
287 Editor::button_press_handler (GnomeCanvasItem* item, GdkEvent* event, ItemType item_type)
289 jack_nframes_t where = event_frame (event, 0, 0);
291 if (session && session->actively_recording()) {
295 /* in object/audition/timefx mode, any button press sets
296 the selection if the object can be selected. this is a
297 bit of hack, because we want to avoid this if the
298 mouse operation is a region alignment.
301 if (((mouse_mode == MouseObject) ||
302 (mouse_mode == MouseAudition && item_type == RegionItem) ||
303 (mouse_mode == MouseTimeFX && item_type == RegionItem)) &&
304 event->type == GDK_BUTTON_PRESS &&
305 event->button.button <= 3) {
310 /* not dbl-click or triple-click */
314 set_selected_regionview_from_click (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift), true);
317 case AudioRegionViewNameHighlight:
318 case AudioRegionViewName:
319 if ((rv = reinterpret_cast<AudioRegionView *> (gtk_object_get_data(GTK_OBJECT(item), "regionview"))) != 0) {
320 set_selected_regionview_from_click (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift), true);
324 case GainAutomationControlPointItem:
325 case PanAutomationControlPointItem:
326 case RedirectAutomationControlPointItem:
327 if ((cp = reinterpret_cast<ControlPoint *> (gtk_object_get_data(GTK_OBJECT(item), "control_point"))) != 0) {
328 set_selected_control_point_from_click (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift), true);
335 case AutomationTrackItem:
343 #define SELECT_TRACK_FROM_CANVAS_IN_RANGE_MODE
344 #ifdef SELECT_TRACK_FROM_CANVAS_IN_RANGE_MODE
345 /* in range mode, button 1/2/3 press potentially selects a track */
347 if (mouse_mode == MouseRange &&
348 event->type == GDK_BUTTON_PRESS &&
349 event->button.button <= 3) {
356 case AutomationTrackItem:
357 set_selected_track_from_click (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift), true, true);
360 case AudioRegionViewNameHighlight:
361 case AudioRegionViewName:
362 rv = reinterpret_cast<AudioRegionView *> (gtk_object_get_data(GTK_OBJECT(item), "regionview"));
369 if (drag_info.item == 0 &&
370 (Keyboard::is_delete_event (&event->button) ||
371 Keyboard::is_context_menu_event (&event->button) ||
372 Keyboard::is_edit_event (&event->button))) {
374 /* handled by button release */
378 switch (event->button.button) {
381 if (event->type == GDK_BUTTON_PRESS) {
383 if (drag_info.item) {
384 gnome_canvas_item_ungrab (drag_info.item, event->button.time);
387 /* single mouse clicks on any of these item types operate
388 independent of mouse mode, mostly because they are
389 not on the main track canvas or because we want
395 case PlayheadCursorItem:
396 start_cursor_grab (item, event);
400 if (Keyboard::modifier_state_equals (event->button.state,
401 Keyboard::ModifierMask(Keyboard::Control|Keyboard::Shift))) {
402 hide_marker (item, event);
404 start_marker_grab (item, event);
408 case TempoMarkerItem:
409 start_tempo_marker_grab (item, event);
412 case MeterMarkerItem:
413 start_meter_marker_grab (item, event);
422 case RangeMarkerBarItem:
423 start_range_markerbar_op (item, event, CreateRangeMarker);
426 case TransportMarkerBarItem:
427 start_range_markerbar_op (item, event, CreateTransportMarker);
436 switch (mouse_mode) {
439 case StartSelectionTrimItem:
440 start_selection_op (item, event, SelectionStartTrim);
443 case EndSelectionTrimItem:
444 start_selection_op (item, event, SelectionEndTrim);
448 if (Keyboard::modifier_state_contains
449 (event->button.state, Keyboard::ModifierMask(Keyboard::Alt))) {
450 // contains and not equals because I can't use alt as a modifier alone.
451 start_selection_grab (item, event);
452 } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
453 /* grab selection for moving */
454 start_selection_op (item, event, SelectionMove);
457 /* this was debated, but decided the more common action was to
458 make a new selection */
459 start_selection_op (item, event, CreateSelection);
464 start_selection_op (item, event, CreateSelection);
470 if (Keyboard::modifier_state_contains (event->button.state,
471 Keyboard::ModifierMask(Keyboard::Control|Keyboard::Alt))
472 && event->type == GDK_BUTTON_PRESS) {
474 start_rubberband_select (item, event);
476 } else if (event->type == GDK_BUTTON_PRESS) {
479 case FadeInHandleItem:
480 start_fade_in_grab (item, event);
483 case FadeOutHandleItem:
484 start_fade_out_grab (item, event);
488 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
489 start_region_copy_grab (item, event);
490 } else if (Keyboard::the_keyboard().key_is_down (GDK_b)) {
491 start_region_brush_grab (item, event);
493 start_region_grab (item, event);
497 case AudioRegionViewNameHighlight:
498 start_trim (item, event);
502 case AudioRegionViewName:
503 /* rename happens on edit clicks */
504 start_trim (clicked_regionview->get_name_highlight(), event);
508 case GainAutomationControlPointItem:
509 case PanAutomationControlPointItem:
510 case RedirectAutomationControlPointItem:
511 start_control_point_grab (item, event);
515 case GainAutomationLineItem:
516 case PanAutomationLineItem:
517 case RedirectAutomationLineItem:
518 start_line_grab_from_line (item, event);
523 case AutomationTrackItem:
524 start_rubberband_select (item, event);
527 /* <CMT Additions> */
528 case ImageFrameHandleStartItem:
529 imageframe_start_handle_op(item, event) ;
532 case ImageFrameHandleEndItem:
533 imageframe_end_handle_op(item, event) ;
536 case MarkerViewHandleStartItem:
537 markerview_item_start_handle_op(item, event) ;
540 case MarkerViewHandleEndItem:
541 markerview_item_end_handle_op(item, event) ;
544 /* </CMT Additions> */
546 /* <CMT Additions> */
548 start_markerview_grab(item, event) ;
551 start_imageframe_grab(item, event) ;
553 /* </CMT Additions> */
565 // start_line_grab_from_regionview (item, event);
568 case GainControlPointItem:
569 start_control_point_grab (item, event);
573 start_line_grab_from_line (item, event);
576 case GainAutomationControlPointItem:
577 case PanAutomationControlPointItem:
578 case RedirectAutomationControlPointItem:
579 start_control_point_grab (item, event);
590 case GainAutomationControlPointItem:
591 case PanAutomationControlPointItem:
592 case RedirectAutomationControlPointItem:
593 start_control_point_grab (item, event);
596 case GainAutomationLineItem:
597 case PanAutomationLineItem:
598 case RedirectAutomationLineItem:
599 start_line_grab_from_line (item, event);
603 // XXX need automation mode to identify which
605 // start_line_grab_from_regionview (item, event);
615 if (event->type == GDK_BUTTON_PRESS) {
616 start_mouse_zoom (item, event);
623 if (item_type == RegionItem) {
624 start_time_fx (item, event);
629 /* handled in release */
638 switch (mouse_mode) {
640 if (event->type == GDK_BUTTON_PRESS) {
643 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
644 start_region_copy_grab (item, event);
646 start_region_grab (item, event);
650 case GainAutomationControlPointItem:
651 case PanAutomationControlPointItem:
652 case RedirectAutomationControlPointItem:
653 start_control_point_grab (item, event);
664 case AudioRegionViewNameHighlight:
665 start_trim (item, event);
669 case AudioRegionViewName:
670 start_trim (clicked_regionview->get_name_highlight(), event);
681 if (event->type == GDK_BUTTON_PRESS) {
682 /* relax till release */
689 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
690 temporal_zoom_session();
692 temporal_zoom_to_frame (true, event_frame(event));
707 switch (mouse_mode) {
709 //temporal_zoom_to_frame (true, where);
710 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
711 temporal_zoom_to_frame (true, where);
714 temporal_zoom_step (true);
719 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::Alt))) {
720 scroll_backward (0.6f);
722 else if (Keyboard::no_modifier_keys_pressed (&event->button)) {
723 scroll_tracks_up_line ();
725 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
726 if (clicked_trackview) {
727 if (!current_stepping_trackview) {
729 step_timeout = t.connect (mem_fun(*this, &Editor::track_height_step_timeout), 500);
730 current_stepping_trackview = clicked_trackview;
732 gettimeofday (&last_track_height_step_timestamp, 0);
733 current_stepping_trackview->step_height (true);
736 else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
737 temporal_zoom_to_frame (true, where);
744 switch (mouse_mode) {
746 // temporal_zoom_to_frame (false, where);
747 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
748 temporal_zoom_to_frame (false, where);
751 temporal_zoom_step (false);
756 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::Alt))) {
757 scroll_forward (0.6f);
759 else if (Keyboard::no_modifier_keys_pressed (&event->button)) {
760 scroll_tracks_down_line ();
762 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
763 if (clicked_trackview) {
764 if (!current_stepping_trackview) {
766 step_timeout = t.connect (mem_fun(*this, &Editor::track_height_step_timeout), 500);
767 current_stepping_trackview = clicked_trackview;
769 gettimeofday (&last_track_height_step_timestamp, 0);
770 current_stepping_trackview->step_height (false);
772 } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
773 temporal_zoom_to_frame (false, where);
787 Editor::button_release_handler (GnomeCanvasItem* item, GdkEvent* event, ItemType item_type)
789 jack_nframes_t where = event_frame (event, 0, 0);
791 /* no action if we're recording */
793 if (session && session->actively_recording()) {
797 /* first, see if we're finishing a drag ... */
799 if (drag_info.item) {
800 if (end_grab (item, event)) {
801 /* grab dragged, so do nothing else */
806 /* edit events get handled here */
808 if (drag_info.item == 0 && Keyboard::is_edit_event (&event->button)) {
814 case TempoMarkerItem:
815 edit_tempo_marker (item);
818 case MeterMarkerItem:
819 edit_meter_marker (item);
822 case AudioRegionViewName:
823 if (clicked_regionview->name_active()) {
824 return mouse_rename_region (item, event);
834 /* context menu events get handled here */
836 if (Keyboard::is_context_menu_event (&event->button)) {
838 if (drag_info.item == 0) {
840 /* no matter which button pops up the context menu, tell the menu
841 widget to use button 1 to drive menu selection.
846 case FadeInHandleItem:
848 case FadeOutHandleItem:
849 popup_fade_context_menu (1, event->button.time, item, item_type);
853 popup_track_context_menu (1, event->button.time, item_type, false, where);
857 case AudioRegionViewNameHighlight:
858 case AudioRegionViewName:
859 popup_track_context_menu (1, event->button.time, item_type, false, where);
863 popup_track_context_menu (1, event->button.time, item_type, true, where);
866 case AutomationTrackItem:
867 popup_track_context_menu (1, event->button.time, item_type, false, where);
871 case RangeMarkerBarItem:
872 case TransportMarkerBarItem:
875 popup_ruler_menu (pixel_to_frame(event->button.x), item_type);
879 marker_context_menu (&event->button, item);
882 case TempoMarkerItem:
883 tm_marker_context_menu (&event->button, item);
886 case MeterMarkerItem:
887 tm_marker_context_menu (&event->button, item);
890 case CrossfadeViewItem:
891 popup_track_context_menu (1, event->button.time, item_type, false, where);
894 /* <CMT Additions> */
896 popup_imageframe_edit_menu(1, event->button.time, item, true) ;
898 case ImageFrameTimeAxisItem:
899 popup_imageframe_edit_menu(1, event->button.time, item, false) ;
902 popup_marker_time_axis_edit_menu(1, event->button.time, item, true) ;
904 case MarkerTimeAxisItem:
905 popup_marker_time_axis_edit_menu(1, event->button.time, item, false) ;
907 /* <CMT Additions> */
918 /* delete events get handled here */
920 if (drag_info.item == 0 && Keyboard::is_delete_event (&event->button)) {
923 case TempoMarkerItem:
924 remove_tempo_marker (item);
927 case MeterMarkerItem:
928 remove_meter_marker (item);
932 remove_marker (item, event);
936 if (mouse_mode == MouseObject) {
937 remove_clicked_region ();
941 case GainControlPointItem:
942 if (mouse_mode == MouseGain) {
943 remove_gain_control_point (item, event);
947 case GainAutomationControlPointItem:
948 case PanAutomationControlPointItem:
949 case RedirectAutomationControlPointItem:
950 remove_control_point (item, event);
959 switch (event->button.button) {
963 /* see comments in button_press_handler */
965 case PlayheadCursorItem:
968 case GainAutomationLineItem:
969 case PanAutomationLineItem:
970 case RedirectAutomationLineItem:
971 case StartSelectionTrimItem:
972 case EndSelectionTrimItem:
976 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
977 snap_to (where, 0, true);
979 mouse_add_new_marker (where);
983 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
986 mouse_add_new_tempo_event (where);
990 mouse_add_new_meter_event (pixel_to_frame (event->button.x));
998 switch (mouse_mode) {
1000 switch (item_type) {
1001 case AutomationTrackItem:
1002 dynamic_cast<AutomationTimeAxisView*>(clicked_trackview)->signal_add_automation_event()
1016 switch (item_type) {
1018 clicked_regionview->signal_add_gain_point_event() (item, event);
1022 case AutomationTrackItem:
1023 dynamic_cast<AutomationTimeAxisView*>(clicked_trackview)->
1024 add_automation_event (item, event, where, event->button.y);
1033 switch (item_type) {
1035 audition_selected_region ();
1052 switch (mouse_mode) {
1055 switch (item_type) {
1057 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
1059 } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::ModifierMask (Keyboard::Shift|Keyboard::Alt))) {
1062 // Button2 click is unused
1075 // x_style_paste (where, 1.0);
1095 Editor::maybe_autoscroll (GdkEvent* event)
1097 jack_nframes_t one_page = (jack_nframes_t) rint (canvas_width * frames_per_unit);
1098 jack_nframes_t rightmost_frame = leftmost_frame + one_page;
1100 jack_nframes_t frame = drag_info.current_pointer_frame;
1102 if (autoscroll_timeout_tag < 0) {
1103 if (frame > rightmost_frame) {
1104 if (rightmost_frame < max_frames) {
1105 start_canvas_autoscroll (1);
1107 } else if (frame < leftmost_frame) {
1108 if (leftmost_frame > 0) {
1109 start_canvas_autoscroll (-1);
1113 if (frame >= leftmost_frame && frame < rightmost_frame) {
1114 stop_canvas_autoscroll ();
1120 Editor::enter_handler (GnomeCanvasItem* item, GdkEvent* event, ItemType item_type)
1126 switch (item_type) {
1127 case GainControlPointItem:
1128 if (mouse_mode == MouseGain) {
1129 cp = reinterpret_cast<ControlPoint*>(gtk_object_get_data (GTK_OBJECT(item), "control_point"));
1130 cp->set_visible (true);
1134 at_y = cp->get_y ();
1135 gnome_canvas_item_i2w (cp->item, &at_x, &at_y);
1139 fraction = 1.0 - (cp->get_y() / cp->line.height());
1141 set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y);
1142 show_verbose_canvas_cursor ();
1144 if (is_drawable()) {
1145 gdk_window_set_cursor (track_canvas_scroller.get_window(), fader_cursor);
1150 case GainAutomationControlPointItem:
1151 case PanAutomationControlPointItem:
1152 case RedirectAutomationControlPointItem:
1153 cp = reinterpret_cast<ControlPoint*>(gtk_object_get_data (GTK_OBJECT(item), "control_point"));
1154 cp->set_visible (true);
1158 at_y = cp->get_y ();
1159 gnome_canvas_item_i2w (cp->item, &at_x, &at_y);
1163 fraction = 1.0 - (cp->get_y() / cp->line.height());
1165 set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y);
1166 show_verbose_canvas_cursor ();
1168 if (is_drawable()) {
1169 gdk_window_set_cursor (track_canvas_scroller.get_window(), fader_cursor);
1174 if (mouse_mode == MouseGain) {
1175 gnome_canvas_item_set (item, "fill_color_rgba", color_map[cEnteredGainLine], NULL);
1176 if (is_drawable()) {
1177 gdk_window_set_cursor (track_canvas_scroller.get_window(), fader_cursor);
1182 case GainAutomationLineItem:
1183 case RedirectAutomationLineItem:
1184 case PanAutomationLineItem:
1185 gnome_canvas_item_set (item, "fill_color_rgba", color_map[cEnteredAutomationLine], NULL);
1186 if (is_drawable()) {
1187 gdk_window_set_cursor (track_canvas_scroller.get_window(), fader_cursor);
1191 case AudioRegionViewNameHighlight:
1192 if (is_drawable() && mouse_mode == MouseObject) {
1193 gdk_window_set_cursor (track_canvas_scroller.get_window(), trimmer_cursor);
1197 case StartSelectionTrimItem:
1198 case EndSelectionTrimItem:
1199 /* <CMT Additions> */
1200 case ImageFrameHandleStartItem:
1201 case ImageFrameHandleEndItem:
1202 case MarkerViewHandleStartItem:
1203 case MarkerViewHandleEndItem:
1204 /* </CMT Additions> */
1206 if (is_drawable()) {
1207 gdk_window_set_cursor (track_canvas_scroller.get_window(), trimmer_cursor);
1211 case EditCursorItem:
1212 case PlayheadCursorItem:
1213 if (is_drawable()) {
1214 gdk_window_set_cursor (track_canvas_scroller.get_window(), grabber_cursor);
1218 case AudioRegionViewName:
1220 /* when the name is not an active item, the entire name highlight is for trimming */
1222 if (!reinterpret_cast<AudioRegionView *> (gtk_object_get_data(GTK_OBJECT(item), "regionview"))->name_active()) {
1223 if (mouse_mode == MouseObject && is_drawable()) {
1224 gdk_window_set_cursor (track_canvas_scroller.get_window(), trimmer_cursor);
1230 case AutomationTrackItem:
1231 if (is_drawable()) {
1233 switch (mouse_mode) {
1235 cursor = selector_cursor;
1238 cursor = zoom_cursor;
1241 cursor = cross_hair_cursor;
1245 gdk_window_set_cursor (track_canvas_scroller.get_window(), cursor);
1247 AutomationTimeAxisView* atv;
1248 if ((atv = static_cast<AutomationTimeAxisView*>(gtk_object_get_data(GTK_OBJECT(item), "trackview"))) != 0) {
1249 clear_entered_track = false;
1250 set_entered_track (atv);
1256 case RangeMarkerBarItem:
1257 case TransportMarkerBarItem:
1260 if (is_drawable()) {
1261 gdk_window_set_cursor (time_canvas_scroller.get_window(), timebar_cursor);
1266 if ((marker = static_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "marker"))) == 0) {
1269 marker->set_color_rgba (color_map[cEnteredMarker]);
1271 case MeterMarkerItem:
1272 case TempoMarkerItem:
1273 if (is_drawable()) {
1274 gdk_window_set_cursor (time_canvas_scroller.get_window(), timebar_cursor);
1277 case FadeInHandleItem:
1278 case FadeOutHandleItem:
1279 if (mouse_mode == MouseObject) {
1280 gnome_canvas_item_set (item, "fill_color_rgba", 0, "outline_pixels", 1, NULL);
1288 /* second pass to handle entered track status in a comprehensible way.
1291 switch (item_type) {
1293 case GainAutomationLineItem:
1294 case RedirectAutomationLineItem:
1295 case PanAutomationLineItem:
1296 case GainControlPointItem:
1297 case GainAutomationControlPointItem:
1298 case PanAutomationControlPointItem:
1299 case RedirectAutomationControlPointItem:
1300 /* these do not affect the current entered track state */
1301 clear_entered_track = false;
1304 case AutomationTrackItem:
1305 /* handled above already */
1309 set_entered_track (0);
1317 Editor::leave_handler (GnomeCanvasItem* item, GdkEvent* event, ItemType item_type)
1323 AudioRegionView* rv;
1326 switch (item_type) {
1327 case GainControlPointItem:
1328 case GainAutomationControlPointItem:
1329 case PanAutomationControlPointItem:
1330 case RedirectAutomationControlPointItem:
1331 cp = reinterpret_cast<ControlPoint*>(gtk_object_get_data (GTK_OBJECT(item), "control_point"));
1332 if (cp->line.npoints() > 1) {
1333 if (!cp->selected) {
1334 cp->set_visible (false);
1338 if (is_drawable()) {
1339 gdk_window_set_cursor (track_canvas_scroller.get_window(), current_canvas_cursor);
1342 hide_verbose_canvas_cursor ();
1345 case AudioRegionViewNameHighlight:
1346 case StartSelectionTrimItem:
1347 case EndSelectionTrimItem:
1348 case EditCursorItem:
1349 case PlayheadCursorItem:
1350 /* <CMT Additions> */
1351 case ImageFrameHandleStartItem:
1352 case ImageFrameHandleEndItem:
1353 case MarkerViewHandleStartItem:
1354 case MarkerViewHandleEndItem:
1355 /* </CMT Additions> */
1356 if (is_drawable()) {
1357 gdk_window_set_cursor (track_canvas_scroller.get_window(), current_canvas_cursor);
1362 case GainAutomationLineItem:
1363 case RedirectAutomationLineItem:
1364 case PanAutomationLineItem:
1365 al = reinterpret_cast<AutomationLine*> (gtk_object_get_data (GTK_OBJECT(item),"line"));
1366 gnome_canvas_item_set (item, "fill_color_rgba", al->get_line_color(), NULL);
1367 if (is_drawable()) {
1368 gdk_window_set_cursor (track_canvas_scroller.get_window(), current_canvas_cursor);
1372 case AudioRegionViewName:
1373 /* see enter_handler() for notes */
1374 if (!reinterpret_cast<AudioRegionView *> (gtk_object_get_data(GTK_OBJECT(item), "regionview"))->name_active()) {
1375 if (is_drawable() && mouse_mode == MouseObject) {
1376 gdk_window_set_cursor (track_canvas_scroller.get_window(), current_canvas_cursor);
1381 case RangeMarkerBarItem:
1382 case TransportMarkerBarItem:
1386 if (is_drawable()) {
1387 gdk_window_set_cursor (time_canvas_scroller.get_window(), timebar_cursor);
1392 if ((marker = static_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "marker"))) == 0) {
1395 loc = find_location_from_marker (marker, is_start);
1396 if (loc) location_flags_changed (loc, this);
1398 case MeterMarkerItem:
1399 case TempoMarkerItem:
1401 if (is_drawable()) {
1402 gdk_window_set_cursor (time_canvas_scroller.get_window(), timebar_cursor);
1407 case FadeInHandleItem:
1408 case FadeOutHandleItem:
1409 rv = static_cast<AudioRegionView*>(gtk_object_get_data (GTK_OBJECT(item), "regionview"));
1410 gnome_canvas_item_set (item, "fill_color_rgba", rv->get_fill_color(), "outline_pixels", 0, NULL);
1413 case AutomationTrackItem:
1414 if (is_drawable()) {
1415 gdk_window_set_cursor (track_canvas_scroller.get_window(), current_canvas_cursor);
1417 clear_entered_track = true;
1418 Main::idle.connect (mem_fun(*this, &Editor::left_automation_track));
1430 Editor::left_automation_track ()
1432 if (clear_entered_track) {
1433 set_entered_track (0);
1434 clear_entered_track = false;
1440 Editor::motion_handler (GnomeCanvasItem* item, GdkEvent* event, ItemType item_type)
1444 /* We call this so that MOTION_NOTIFY events continue to be
1445 delivered to the canvas. We need to do this because we set
1446 Gdk::POINTER_MOTION_HINT_MASK on the canvas. This reduces
1447 the density of the events, at the expense of a round-trip
1448 to the server. Given that this will mostly occur on cases
1449 where DISPLAY = :0.0, and given the cost of what the motion
1450 event might do, its a good tradeoff.
1453 track_canvas->get_pointer (x, y);
1455 if (current_stepping_trackview) {
1456 /* don't keep the persistent stepped trackview if the mouse moves */
1457 current_stepping_trackview = 0;
1458 step_timeout.disconnect ();
1461 if (session && session->actively_recording()) {
1462 /* Sorry. no dragging stuff around while we record */
1466 drag_info.current_pointer_frame = event_frame (event, &drag_info.current_pointer_x,
1467 &drag_info.current_pointer_y);
1468 if (drag_info.item) {
1469 /* item != 0 is the best test i can think of for
1472 if (!drag_info.move_threshold_passsed)
1474 drag_info.move_threshold_passsed = (abs ((int) (drag_info.current_pointer_x - drag_info.grab_x)) > 4);
1476 // and change the initial grab loc/frame if this drag info wants us to
1477 if (drag_info.want_move_threshold && drag_info.move_threshold_passsed) {
1478 drag_info.grab_frame = drag_info.current_pointer_frame;
1479 drag_info.grab_x = drag_info.current_pointer_x;
1480 drag_info.grab_y = drag_info.current_pointer_y;
1481 drag_info.last_pointer_frame = drag_info.grab_frame;
1482 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
1487 switch (item_type) {
1488 case PlayheadCursorItem:
1489 case EditCursorItem:
1491 case GainControlPointItem:
1492 case RedirectAutomationControlPointItem:
1493 case GainAutomationControlPointItem:
1494 case PanAutomationControlPointItem:
1495 case TempoMarkerItem:
1496 case MeterMarkerItem:
1497 case AudioRegionViewNameHighlight:
1498 case StartSelectionTrimItem:
1499 case EndSelectionTrimItem:
1502 case RedirectAutomationLineItem:
1503 case GainAutomationLineItem:
1504 case PanAutomationLineItem:
1505 case FadeInHandleItem:
1506 case FadeOutHandleItem:
1507 /* <CMT Additions> */
1508 case ImageFrameHandleStartItem:
1509 case ImageFrameHandleEndItem:
1510 case MarkerViewHandleStartItem:
1511 case MarkerViewHandleEndItem:
1512 /* </CMT Additions> */
1513 if (drag_info.item && (event->motion.state & GDK_BUTTON1_MASK ||
1514 (event->motion.state & GDK_BUTTON2_MASK))) {
1515 maybe_autoscroll (event);
1516 (this->*(drag_info.motion_callback)) (item, event);
1525 switch (mouse_mode) {
1530 if (drag_info.item && (event->motion.state & GDK_BUTTON1_MASK ||
1531 (event->motion.state & GDK_BUTTON2_MASK))) {
1532 maybe_autoscroll (event);
1533 (this->*(drag_info.motion_callback)) (item, event);
1544 track_canvas_motion (item, event);
1552 Editor::start_grab (GdkEvent* event, GdkCursor *cursor)
1554 if (drag_info.item == 0) {
1555 fatal << _("programming error: start_grab called without drag item") << endmsg;
1561 cursor = grabber_cursor;
1564 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
1566 if (event->button.button == 2) {
1567 drag_info.x_constrained = true;
1569 drag_info.x_constrained = false;
1572 drag_info.grab_frame = event_frame(event, &drag_info.grab_x, &drag_info.grab_y);
1573 drag_info.last_pointer_frame = drag_info.grab_frame;
1574 drag_info.current_pointer_frame = drag_info.grab_frame;
1575 drag_info.current_pointer_x = drag_info.grab_x;
1576 drag_info.current_pointer_y = drag_info.grab_y;
1577 drag_info.cumulative_x_drag = 0;
1578 drag_info.cumulative_y_drag = 0;
1579 drag_info.first_move = true;
1580 drag_info.move_threshold_passsed = false;
1581 drag_info.want_move_threshold = false;
1582 drag_info.pointer_frame_offset = 0;
1583 drag_info.brushing = false;
1584 drag_info.copied_location = 0;
1586 gnome_canvas_item_grab (drag_info.item,
1587 Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
1589 event->button.time);
1591 if (session && session->transport_rolling()) {
1592 drag_info.was_rolling = true;
1594 drag_info.was_rolling = false;
1597 switch (snap_type) {
1598 case SnapToRegionStart:
1599 case SnapToRegionEnd:
1600 case SnapToRegionSync:
1601 case SnapToRegionBoundary:
1602 build_region_boundary_cache ();
1610 Editor::end_grab (GnomeCanvasItem* item, GdkEvent* event)
1612 bool did_drag = false;
1614 stop_canvas_autoscroll ();
1616 if (drag_info.item == 0) {
1620 gnome_canvas_item_ungrab (drag_info.item, event->button.time);
1622 if (drag_info.finished_callback) {
1623 (this->*(drag_info.finished_callback)) (item, event);
1626 did_drag = !drag_info.first_move;
1628 hide_verbose_canvas_cursor();
1631 drag_info.copy = false;
1632 drag_info.motion_callback = 0;
1633 drag_info.finished_callback = 0;
1634 drag_info.last_trackview = 0;
1635 drag_info.last_frame_position = 0;
1636 drag_info.grab_frame = 0;
1637 drag_info.last_pointer_frame = 0;
1638 drag_info.current_pointer_frame = 0;
1639 drag_info.brushing = false;
1641 if (drag_info.copied_location) {
1642 delete drag_info.copied_location;
1643 drag_info.copied_location = 0;
1650 Editor::set_edit_cursor (GdkEvent* event)
1652 jack_nframes_t pointer_frame = event_frame (event);
1654 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1655 if (snap_type != SnapToEditCursor) {
1656 snap_to (pointer_frame);
1660 edit_cursor->set_position (pointer_frame);
1661 edit_cursor_clock.set (pointer_frame);
1665 Editor::set_playhead_cursor (GdkEvent* event)
1667 jack_nframes_t pointer_frame = event_frame (event);
1669 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1670 snap_to (pointer_frame);
1674 session->request_locate (pointer_frame, session->transport_rolling());
1679 Editor::start_fade_in_grab (GnomeCanvasItem* item, GdkEvent* event)
1681 drag_info.item = item;
1682 drag_info.motion_callback = &Editor::fade_in_drag_motion_callback;
1683 drag_info.finished_callback = &Editor::fade_in_drag_finished_callback;
1687 if ((drag_info.data = (gtk_object_get_data (GTK_OBJECT(item), "regionview"))) == 0) {
1688 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1692 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1694 drag_info.pointer_frame_offset = drag_info.grab_frame - ((jack_nframes_t) arv->region.fade_in().back()->when + arv->region.position());
1698 Editor::fade_in_drag_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
1700 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1702 jack_nframes_t fade_length;
1704 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1705 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1711 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1715 if (pos < (arv->region.position() + 64)) {
1716 fade_length = 64; // this should be a minimum defined somewhere
1717 } else if (pos > arv->region.last_frame()) {
1718 fade_length = arv->region.length();
1720 fade_length = pos - arv->region.position();
1723 arv->reset_fade_in_shape_width (fade_length);
1725 show_verbose_duration_cursor (arv->region.position(), arv->region.position() + fade_length, 10);
1727 drag_info.first_move = false;
1731 Editor::fade_in_drag_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
1733 if (drag_info.first_move) return;
1735 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1737 jack_nframes_t fade_length;
1739 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1740 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1746 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1750 if (pos < (arv->region.position() + 64)) {
1751 fade_length = 64; // this should be a minimum defined somewhere
1753 else if (pos > arv->region.last_frame()) {
1754 fade_length = arv->region.length();
1757 fade_length = pos - arv->region.position();
1760 begin_reversible_command (_("change fade in length"));
1761 session->add_undo (arv->region.get_memento());
1762 arv->region.set_fade_in_length (fade_length);
1763 session->add_redo_no_execute (arv->region.get_memento());
1764 commit_reversible_command ();
1765 fade_in_drag_motion_callback (item, event);
1769 Editor::start_fade_out_grab (GnomeCanvasItem* item, GdkEvent* event)
1771 drag_info.item = item;
1772 drag_info.motion_callback = &Editor::fade_out_drag_motion_callback;
1773 drag_info.finished_callback = &Editor::fade_out_drag_finished_callback;
1777 if ((drag_info.data = (gtk_object_get_data (GTK_OBJECT(item), "regionview"))) == 0) {
1778 fatal << _("programming error: fade out canvas item has no regionview data pointer!") << endmsg;
1782 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1784 drag_info.pointer_frame_offset = drag_info.grab_frame - (arv->region.length() - (jack_nframes_t) arv->region.fade_out().back()->when + arv->region.position());
1788 Editor::fade_out_drag_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
1790 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1792 jack_nframes_t fade_length;
1794 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1795 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1801 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1805 if (pos > (arv->region.last_frame() - 64)) {
1806 fade_length = 64; // this should really be a minimum fade defined somewhere
1808 else if (pos < arv->region.position()) {
1809 fade_length = arv->region.length();
1812 fade_length = arv->region.last_frame() - pos;
1815 arv->reset_fade_out_shape_width (fade_length);
1817 show_verbose_duration_cursor (arv->region.last_frame() - fade_length, arv->region.last_frame(), 10);
1819 drag_info.first_move = false;
1823 Editor::fade_out_drag_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
1825 if (drag_info.first_move) return;
1827 AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
1829 jack_nframes_t fade_length;
1831 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1832 pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1838 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1842 if (pos > (arv->region.last_frame() - 64)) {
1843 fade_length = 64; // this should really be a minimum fade defined somewhere
1845 else if (pos < arv->region.position()) {
1846 fade_length = arv->region.length();
1849 fade_length = arv->region.last_frame() - pos;
1852 begin_reversible_command (_("change fade out length"));
1853 session->add_undo (arv->region.get_memento());
1854 arv->region.set_fade_out_length (fade_length);
1855 session->add_redo_no_execute (arv->region.get_memento());
1856 commit_reversible_command ();
1858 fade_out_drag_motion_callback (item, event);
1862 Editor::start_cursor_grab (GnomeCanvasItem* item, GdkEvent* event)
1864 drag_info.item = item;
1865 drag_info.motion_callback = &Editor::cursor_drag_motion_callback;
1866 drag_info.finished_callback = &Editor::cursor_drag_finished_callback;
1870 if ((drag_info.data = (gtk_object_get_data (GTK_OBJECT(item), "cursor"))) == 0) {
1871 fatal << _("programming error: cursor canvas item has no cursor data pointer!") << endmsg;
1875 Cursor* cursor = (Cursor *) drag_info.data;
1877 if (session && cursor == playhead_cursor) {
1878 if (drag_info.was_rolling) {
1879 session->request_stop ();
1883 drag_info.pointer_frame_offset = drag_info.grab_frame - cursor->current_frame;
1885 show_verbose_time_cursor (cursor->current_frame, 10);
1889 Editor::cursor_drag_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
1891 Cursor* cursor = (Cursor *) drag_info.data;
1892 jack_nframes_t adjusted_frame;
1894 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
1895 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
1901 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
1902 if (cursor != edit_cursor || snap_type != SnapToEditCursor) {
1903 snap_to (adjusted_frame);
1907 if (adjusted_frame == drag_info.last_pointer_frame) return;
1909 cursor->set_position (adjusted_frame);
1911 if (cursor == edit_cursor) {
1912 edit_cursor_clock.set (cursor->current_frame);
1915 show_verbose_time_cursor (cursor->current_frame, 10);
1917 drag_info.last_pointer_frame = adjusted_frame;
1918 drag_info.first_move = false;
1922 Editor::cursor_drag_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
1924 if (drag_info.first_move) return;
1926 cursor_drag_motion_callback (item, event);
1928 if (item == playhead_cursor->canvas_item) {
1930 session->request_locate (playhead_cursor->current_frame, drag_info.was_rolling);
1932 } else if (item == edit_cursor->canvas_item) {
1933 edit_cursor->set_position (edit_cursor->current_frame);
1934 edit_cursor_clock.set (edit_cursor->current_frame);
1939 Editor::update_marker_drag_item (Location *location)
1941 double x1 = frame_to_pixel (location->start());
1942 double x2 = frame_to_pixel (location->end());
1944 if (location->is_mark()) {
1945 marker_drag_line_points->coords[0] = x1;
1946 marker_drag_line_points->coords[2] = x1;
1947 gnome_canvas_item_set (marker_drag_line, "points", marker_drag_line_points, NULL);
1950 gnome_canvas_item_set (range_marker_drag_rect, "x1", x1, "x2", x2, NULL);
1955 Editor::start_marker_grab (GnomeCanvasItem* item, GdkEvent* event)
1959 if ((marker = static_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "marker"))) == 0) {
1960 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
1966 Location *location = find_location_from_marker (marker, is_start);
1968 drag_info.item = item;
1969 drag_info.data = marker;
1970 drag_info.motion_callback = &Editor::marker_drag_motion_callback;
1971 drag_info.finished_callback = &Editor::marker_drag_finished_callback;
1975 drag_info.copied_location = new Location (*location);
1976 drag_info.pointer_frame_offset = drag_info.grab_frame - (is_start ? location->start() : location->end());
1978 update_marker_drag_item (location);
1980 if (location->is_mark()) {
1981 gnome_canvas_item_show (marker_drag_line);
1982 gnome_canvas_item_raise_to_top (marker_drag_line);
1985 gnome_canvas_item_show (range_marker_drag_rect);
1986 gnome_canvas_item_raise_to_top (range_marker_drag_rect);
1989 if (is_start) show_verbose_time_cursor (location->start(), 10);
1990 else show_verbose_time_cursor (location->end(), 10);
1994 Editor::marker_drag_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
1996 jack_nframes_t f_delta;
1997 Marker* marker = (Marker *) drag_info.data;
1998 Location *real_location;
1999 Location *copy_location;
2001 bool move_both = false;
2003 jack_nframes_t newframe;
2004 if (drag_info.pointer_frame_offset <= (long) drag_info.current_pointer_frame) {
2005 newframe = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2011 jack_nframes_t next = newframe;
2013 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2014 snap_to (newframe, 0, true);
2017 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) return;
2019 /* call this to find out if its the start or end */
2021 real_location = find_location_from_marker (marker, is_start);
2023 /* use the copy that we're "dragging" around */
2025 copy_location = drag_info.copied_location;
2027 f_delta = copy_location->end() - copy_location->start();
2029 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
2033 if (is_start) { // start marker
2036 copy_location->set_start (newframe);
2037 copy_location->set_end (newframe + f_delta);
2038 } else if (newframe < copy_location->end()) {
2039 copy_location->set_start (newframe);
2041 snap_to (next, 1, true);
2042 copy_location->set_end (next);
2043 copy_location->set_start (newframe);
2046 } else { // end marker
2049 copy_location->set_end (newframe);
2050 copy_location->set_start (newframe - f_delta);
2051 } else if (newframe > copy_location->start()) {
2052 copy_location->set_end (newframe);
2054 } else if (newframe > 0) {
2055 snap_to (next, -1, true);
2056 copy_location->set_start (next);
2057 copy_location->set_end (newframe);
2061 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
2062 drag_info.first_move = false;
2064 update_marker_drag_item (copy_location);
2066 LocationMarkers* lm = find_location_markers (real_location);
2067 lm->set_position (copy_location->start(), copy_location->end());
2069 show_verbose_time_cursor (newframe, 10);
2073 Editor::marker_drag_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
2075 if (drag_info.first_move) {
2076 marker_drag_motion_callback (item, event);
2080 Marker* marker = (Marker *) drag_info.data;
2082 Location * location = find_location_from_marker (marker, is_start);
2084 location->set (drag_info.copied_location->start(), drag_info.copied_location->end());
2087 gnome_canvas_item_hide (marker_drag_line);
2088 gnome_canvas_item_hide (range_marker_drag_rect);
2092 Editor::start_meter_marker_grab (GnomeCanvasItem* item, GdkEvent* event)
2095 MeterMarker* meter_marker;
2097 if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "marker"))) == 0) {
2098 fatal << _("programming error: meter marker canvas item has no marker object pointer!") << endmsg;
2102 meter_marker = dynamic_cast<MeterMarker*> (marker);
2104 MetricSection& section (meter_marker->meter());
2106 if (!section.movable()) {
2110 drag_info.item = item;
2111 drag_info.data = marker;
2112 drag_info.motion_callback = &Editor::meter_marker_drag_motion_callback;
2113 drag_info.finished_callback = &Editor::meter_marker_drag_finished_callback;
2117 drag_info.pointer_frame_offset = drag_info.grab_frame - meter_marker->meter().frame();
2119 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2123 Editor::meter_marker_drag_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
2125 MeterMarker* marker = (MeterMarker *) drag_info.data;
2126 jack_nframes_t adjusted_frame;
2128 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
2129 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2135 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2136 snap_to (adjusted_frame);
2139 if (adjusted_frame == drag_info.last_pointer_frame) return;
2141 marker->set_position (adjusted_frame);
2144 drag_info.last_pointer_frame = adjusted_frame;
2145 drag_info.first_move = false;
2147 show_verbose_time_cursor (adjusted_frame, 10);
2151 Editor::meter_marker_drag_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
2153 if (drag_info.first_move) return;
2155 meter_marker_drag_motion_callback (item, event);
2157 MeterMarker* marker = (MeterMarker *) drag_info.data;
2160 TempoMap& map (session->tempo_map());
2161 map.bbt_time (drag_info.last_pointer_frame, when);
2163 begin_reversible_command (_("move meter mark"));
2164 session->add_undo (map.get_memento());
2165 map.move_meter (marker->meter(), when);
2166 session->add_redo_no_execute (map.get_memento());
2167 commit_reversible_command ();
2171 Editor::start_tempo_marker_grab (GnomeCanvasItem* item, GdkEvent* event)
2174 TempoMarker* tempo_marker;
2176 if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "tempo_marker"))) == 0) {
2177 fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg;
2181 if ((tempo_marker = dynamic_cast<TempoMarker *> (marker)) == 0) {
2182 fatal << _("programming error: marker for tempo is not a tempo marker!") << endmsg;
2186 MetricSection& section (tempo_marker->tempo());
2188 if (!section.movable()) {
2192 drag_info.item = item;
2193 drag_info.data = marker;
2194 drag_info.motion_callback = &Editor::tempo_marker_drag_motion_callback;
2195 drag_info.finished_callback = &Editor::tempo_marker_drag_finished_callback;
2199 drag_info.pointer_frame_offset = drag_info.grab_frame - tempo_marker->tempo().frame();
2200 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
2204 Editor::tempo_marker_drag_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
2206 TempoMarker* marker = (TempoMarker *) drag_info.data;
2207 jack_nframes_t adjusted_frame;
2209 if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
2210 adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2216 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2217 snap_to (adjusted_frame);
2220 if (adjusted_frame == drag_info.last_pointer_frame) return;
2222 /* OK, we've moved far enough to make it worth actually move the thing. */
2224 marker->set_position (adjusted_frame);
2226 show_verbose_time_cursor (adjusted_frame, 10);
2228 drag_info.last_pointer_frame = adjusted_frame;
2229 drag_info.first_move = false;
2233 Editor::tempo_marker_drag_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
2235 if (drag_info.first_move) return;
2237 tempo_marker_drag_motion_callback (item, event);
2239 TempoMarker* marker = (TempoMarker *) drag_info.data;
2242 TempoMap& map (session->tempo_map());
2243 map.bbt_time (drag_info.last_pointer_frame, when);
2245 begin_reversible_command (_("move tempo mark"));
2246 session->add_undo (map.get_memento());
2247 map.move_tempo (marker->tempo(), when);
2248 session->add_redo_no_execute (map.get_memento());
2249 commit_reversible_command ();
2253 Editor::remove_gain_control_point (GnomeCanvasItem*item, GdkEvent* event)
2255 ControlPoint* control_point;
2257 if ((control_point = reinterpret_cast<ControlPoint *> (gtk_object_get_data (GTK_OBJECT(item), "control_point"))) == 0) {
2258 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2262 // We shouldn't remove the first or last gain point
2263 if (control_point->line.is_last_point(*control_point) ||
2264 control_point->line.is_first_point(*control_point)) {
2268 control_point->line.remove_point (*control_point);
2272 Editor::remove_control_point (GnomeCanvasItem*item, GdkEvent* event)
2274 ControlPoint* control_point;
2276 if ((control_point = reinterpret_cast<ControlPoint *> (gtk_object_get_data (GTK_OBJECT(item), "control_point"))) == 0) {
2277 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2281 control_point->line.remove_point (*control_point);
2285 Editor::start_control_point_grab (GnomeCanvasItem* item, GdkEvent* event)
2287 ControlPoint* control_point;
2289 if ((control_point = reinterpret_cast<ControlPoint *> (gtk_object_get_data (GTK_OBJECT(item), "control_point"))) == 0) {
2290 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
2294 drag_info.item = item;
2295 drag_info.data = control_point;
2296 drag_info.motion_callback = &Editor::control_point_drag_motion_callback;
2297 drag_info.finished_callback = &Editor::control_point_drag_finished_callback;
2299 start_grab (event, fader_cursor);
2301 control_point->line.start_drag (control_point, 0);
2303 float fraction = 1.0 - (control_point->get_y() / control_point->line.height());
2304 set_verbose_canvas_cursor (control_point->line.get_verbose_cursor_string (fraction),
2305 drag_info.current_pointer_x + 20, drag_info.current_pointer_y + 20);
2307 show_verbose_canvas_cursor ();
2311 Editor::control_point_drag_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
2313 ControlPoint* cp = reinterpret_cast<ControlPoint *> (drag_info.data);
2315 double cx = drag_info.current_pointer_x;
2316 double cy = drag_info.current_pointer_y;
2318 drag_info.cumulative_x_drag = cx - drag_info.grab_x ;
2319 drag_info.cumulative_y_drag = cy - drag_info.grab_y ;
2321 bool x_constrained = false;
2323 if (drag_info.x_constrained) {
2324 if (fabs(drag_info.cumulative_x_drag) < fabs(drag_info.cumulative_y_drag)) {
2325 cx = drag_info.grab_x;
2326 x_constrained = true;
2329 cy = drag_info.grab_y;
2334 gnome_canvas_item_w2i (cp->line.parent_group(), &cx, &cy);
2338 cy = min ((double) cp->line.height(), cy);
2340 //translate cx to frames
2341 jack_nframes_t cx_frames = (jack_nframes_t) floor (cx * frames_per_unit);
2343 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && !x_constrained) {
2344 snap_to (cx_frames);
2347 float fraction = 1.0 - (cy / cp->line.height());
2351 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
2357 cp->line.point_drag (*cp, cx_frames , fraction, push);
2359 set_verbose_canvas_cursor_text (cp->line.get_verbose_cursor_string (fraction));
2363 Editor::control_point_drag_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
2365 ControlPoint* cp = reinterpret_cast<ControlPoint *> (drag_info.data);
2366 control_point_drag_motion_callback (item, event);
2367 cp->line.end_drag (cp);
2371 Editor::start_line_grab_from_regionview (GnomeCanvasItem* item, GdkEvent* event)
2373 switch (mouse_mode) {
2375 start_line_grab (clicked_regionview->get_gain_line(), event);
2383 Editor::start_line_grab_from_line (GnomeCanvasItem* item, GdkEvent* event)
2387 if ((al = reinterpret_cast<AutomationLine*> (gtk_object_get_data (GTK_OBJECT(item), "line"))) == 0) {
2388 fatal << _("programming error: line canvas item has no line pointer!") << endmsg;
2392 start_line_grab (al, event);
2396 Editor::start_line_grab (AutomationLine* line, GdkEvent* event)
2400 jack_nframes_t frame_within_region;
2402 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2406 cx = event->button.x;
2407 cy = event->button.y;
2408 gnome_canvas_item_w2i (line->parent_group(), &cx, &cy);
2409 frame_within_region = (jack_nframes_t) floor (cx * frames_per_unit);
2411 if (!line->control_points_adjacent (frame_within_region, current_line_drag_info.before,
2412 current_line_drag_info.after)) {
2413 /* no adjacent points */
2417 drag_info.item = line->grab_item();
2418 drag_info.data = line;
2419 drag_info.motion_callback = &Editor::line_drag_motion_callback;
2420 drag_info.finished_callback = &Editor::line_drag_finished_callback;
2422 start_grab (event, fader_cursor);
2424 double fraction = 1.0 - (cy / line->height());
2426 line->start_drag (0, fraction);
2428 set_verbose_canvas_cursor (line->get_verbose_cursor_string (fraction),
2429 drag_info.current_pointer_x + 20, drag_info.current_pointer_y + 20);
2430 show_verbose_canvas_cursor ();
2434 Editor::line_drag_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
2436 AutomationLine* line = reinterpret_cast<AutomationLine *> (drag_info.data);
2437 double cx = drag_info.current_pointer_x;
2438 double cy = drag_info.current_pointer_y;
2440 gnome_canvas_item_w2i (line->parent_group(), &cx, &cy);
2443 fraction = 1.0 - (cy / line->height());
2447 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
2453 line->line_drag (current_line_drag_info.before, current_line_drag_info.after, fraction, push);
2455 set_verbose_canvas_cursor_text (line->get_verbose_cursor_string (fraction));
2459 Editor::line_drag_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
2461 AutomationLine* line = reinterpret_cast<AutomationLine *> (drag_info.data);
2462 line_drag_motion_callback (item, event);
2467 Editor::start_region_grab (GnomeCanvasItem* item, GdkEvent* event)
2469 if (selection->audio_regions.empty() || clicked_regionview == 0) {
2473 drag_info.copy = false;
2474 drag_info.item = item;
2475 drag_info.data = clicked_regionview;
2476 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2477 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2482 TimeAxisView* tvp = clicked_trackview;
2483 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
2485 if (tv && tv->is_audio_track()) {
2486 speed = tv->get_diskstream()->speed();
2489 drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region.position() / speed);
2490 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2491 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2492 // we want a move threshold
2493 drag_info.want_move_threshold = true;
2495 show_verbose_time_cursor (drag_info.last_frame_position, 10);
2497 begin_reversible_command (_("move region(s)"));
2501 Editor::start_region_copy_grab (GnomeCanvasItem* item, GdkEvent* event)
2503 if (selection->audio_regions.empty() || clicked_regionview == 0) {
2507 /* this is committed in the grab finished callback. */
2509 begin_reversible_command (_("Drag region copy"));
2511 /* duplicate the region(s) */
2513 vector<AudioRegionView*> new_regionviews;
2515 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
2516 AudioRegionView* rv;
2520 Playlist* to_playlist = rv->region.playlist();
2521 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&rv->get_time_axis_view());
2523 session->add_undo (to_playlist->get_memento ());
2524 latest_regionview = 0;
2526 sigc::connection c = atv->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
2528 /* create a new region with the same name.
2531 AudioRegion* newregion = new AudioRegion (rv->region);
2533 /* if the original region was locked, we don't care */
2535 newregion->set_locked (false);
2537 to_playlist->add_region (*newregion, (jack_nframes_t) (rv->region.position() * atv->get_diskstream()->speed()));
2541 if (latest_regionview) {
2542 new_regionviews.push_back (latest_regionview);
2547 if (new_regionviews.empty()) {
2551 /* reset selection to new regionviews */
2553 selection->set (new_regionviews);
2555 drag_info.item = new_regionviews.front()->get_canvas_group ();
2556 drag_info.copy = true;
2557 drag_info.data = new_regionviews.front();
2558 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2559 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2563 TimeAxisView* tv = &clicked_regionview->get_time_axis_view();
2564 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(tv);
2567 if (atv && atv->is_audio_track()) {
2568 speed = atv->get_diskstream()->speed();
2571 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2572 drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region.position() / speed);
2573 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2574 // we want a move threshold
2575 drag_info.want_move_threshold = true;
2577 show_verbose_time_cursor (drag_info.last_frame_position, 10);
2579 begin_reversible_command (_("copy region(s)"));
2583 Editor::start_region_brush_grab (GnomeCanvasItem* item, GdkEvent* event)
2585 if (selection->audio_regions.empty() || clicked_regionview == 0) {
2589 drag_info.copy = false;
2590 drag_info.item = item;
2591 drag_info.data = clicked_regionview;
2592 drag_info.motion_callback = &Editor::region_drag_motion_callback;
2593 drag_info.finished_callback = &Editor::region_drag_finished_callback;
2598 TimeAxisView* tvp = clicked_trackview;
2599 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
2601 if (tv && tv->is_audio_track()) {
2602 speed = tv->get_diskstream()->speed();
2605 drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region.position() / speed);
2606 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
2607 drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
2608 // we want a move threshold
2609 drag_info.want_move_threshold = true;
2610 drag_info.brushing = true;
2612 begin_reversible_command (_("Drag region brush"));
2616 Editor::region_drag_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
2620 AudioRegionView *rv = reinterpret_cast<AudioRegionView*> (drag_info.data);
2621 jack_nframes_t pending_region_position = 0;
2622 int32_t pointer_y_span = 0, canvas_pointer_y_span = 0, original_pointer_order;
2623 int32_t visible_y_high = 0, visible_y_low = 512; //high meaning higher numbered.. not the height on the screen
2624 bool clamp_y_axis = false;
2625 vector<int32_t> height_list(512) ;
2626 vector<int32_t>::iterator j;
2628 /* Which trackview is this ? */
2630 TimeAxisView* tvp = trackview_by_y_position (drag_info.current_pointer_y);
2631 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
2633 /* The region motion is only processed if the pointer is over
2637 if (!tv || !tv->is_audio_track()) {
2638 /* To make sure we hide the verbose canvas cursor when the mouse is
2639 not held over and audiotrack.
2641 hide_verbose_canvas_cursor ();
2645 original_pointer_order = drag_info.last_trackview->order;
2647 /************************************************************
2649 ************************************************************/
2651 if (drag_info.brushing) {
2652 clamp_y_axis = true;
2657 if ((pointer_y_span = (drag_info.last_trackview->order - tv->order)) != 0) {
2659 int32_t children = 0, numtracks = 0;
2660 bitset <512> tracks (0x00);
2661 /* get a bitmask representing the visible tracks */
2663 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2664 TimeAxisView *tracklist_timeview;
2665 tracklist_timeview = (*i);
2666 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tracklist_timeview);
2667 list<TimeAxisView*> children_list;
2669 /* zeroes are audio tracks. ones are other types. */
2671 if (!atv2->hidden()) {
2673 if (visible_y_high < atv2->order) {
2674 visible_y_high = atv2->order;
2676 if (visible_y_low > atv2->order) {
2677 visible_y_low = atv2->order;
2680 if (!atv2->is_audio_track()) {
2681 tracks = tracks |= (0x01 << atv2->order);
2684 height_list[atv2->order] = (*i)->height;
2686 if ((children_list = atv2->get_child_list()).size() > 0) {
2687 for (list<TimeAxisView*>::iterator j = children_list.begin(); j != children_list.end(); ++j) {
2688 tracks = tracks |= (0x01 << (atv2->order + children));
2689 height_list[atv2->order + children] = (*j)->height;
2697 /* find the actual span according to the canvas */
2699 canvas_pointer_y_span = pointer_y_span;
2700 if (drag_info.last_trackview->order >= tv->order) {
2702 for (y = tv->order; y < drag_info.last_trackview->order; y++) {
2703 if (height_list[y] == 0 ) {
2704 canvas_pointer_y_span--;
2709 for (y = drag_info.last_trackview->order;y <= tv->order; y++) {
2710 if ( height_list[y] == 0 ) {
2711 canvas_pointer_y_span++;
2716 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
2717 AudioRegionView* rv2;
2719 double ix1, ix2, iy1, iy2;
2722 gnome_canvas_item_get_bounds (rv2->get_canvas_frame(), &ix1, &iy1, &ix2, &iy2);
2723 gnome_canvas_item_i2w (rv2->get_canvas_group(), &ix1, &iy1);
2724 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
2725 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2);
2727 if (atv2->order != original_pointer_order) {
2728 /* this isn't the pointer track */
2730 if (canvas_pointer_y_span > 0) {
2732 /* moving up the canvas */
2733 if ((atv2->order - canvas_pointer_y_span) >= visible_y_low) {
2735 int32_t visible_tracks = 0;
2736 while (visible_tracks < canvas_pointer_y_span ) {
2739 while (height_list[atv2->order - (visible_tracks - n)] == 0) {
2740 /* we're passing through a hidden track */
2745 if (tracks[atv2->order - (canvas_pointer_y_span - n)] != 0x00) {
2746 clamp_y_axis = true;
2750 clamp_y_axis = true;
2753 } else if (canvas_pointer_y_span < 0) {
2755 /*moving down the canvas*/
2757 if ((atv2->order - (canvas_pointer_y_span - n)) <= visible_y_high) { // we will overflow
2760 int32_t visible_tracks = 0;
2762 while (visible_tracks > canvas_pointer_y_span ) {
2765 while (height_list[atv2->order - (visible_tracks - n)] == 0) {
2769 if ( tracks[atv2->order - ( canvas_pointer_y_span - n)] != 0x00) {
2770 clamp_y_axis = true;
2775 clamp_y_axis = true;
2781 /* this is the pointer's track */
2782 if ((atv2->order - pointer_y_span) > visible_y_high) { // we will overflow
2783 clamp_y_axis = true;
2784 } else if ((atv2->order - pointer_y_span) < visible_y_low) { // we will underflow
2785 clamp_y_axis = true;
2793 } else if (drag_info.last_trackview == tv) {
2794 clamp_y_axis = true;
2798 if (!clamp_y_axis) {
2799 drag_info.last_trackview = tv;
2802 /************************************************************
2804 ************************************************************/
2806 /* compute the amount of pointer motion in frames, and where
2807 the region would be if we moved it by that much.
2810 if (drag_info.move_threshold_passsed) {
2812 if ((int32_t)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
2814 jack_nframes_t sync_frame;
2815 jack_nframes_t sync_offset;
2818 pending_region_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
2820 sync_offset = rv->region.sync_offset (sync_dir);
2821 sync_frame = rv->region.adjust_to_sync (pending_region_position);
2823 /* we snap if the snap modifier is not enabled.
2826 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2827 snap_to (sync_frame);
2830 if (sync_frame - sync_offset <= sync_frame) {
2831 pending_region_position = sync_frame - (sync_dir*sync_offset);
2833 pending_region_position = 0;
2837 pending_region_position = 0;
2840 if (pending_region_position > max_frames - rv->region.length()) {
2841 pending_region_position = drag_info.last_frame_position;
2844 // printf ("3: pending_region_position= %lu %lu\n", pending_region_position, drag_info.last_frame_position );
2846 if (pending_region_position != drag_info.last_frame_position && !drag_info.x_constrained) {
2848 /* now compute the canvas unit distance we need to move the regiondrag_info.last_trackview->order
2849 to make it appear at the new location.
2852 if (pending_region_position > drag_info.last_frame_position) {
2853 x_delta = ((double) (pending_region_position - drag_info.last_frame_position) / frames_per_unit);
2855 x_delta = -((double) (drag_info.last_frame_position - pending_region_position) / frames_per_unit);
2858 drag_info.last_frame_position = pending_region_position;
2865 /* threshold not passed */
2870 /*************************************************************
2872 ************************************************************/
2874 if (x_delta == 0 && (pointer_y_span == 0)) {
2875 /* haven't reached next snap point, and we're not switching
2876 trackviews. nothing to do.
2882 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
2884 AudioRegionView* rv2;
2887 /* if any regionview is at zero, we need to know so we can
2888 stop further leftward motion.
2891 double ix1, ix2, iy1, iy2;
2892 gnome_canvas_item_get_bounds (rv2->get_canvas_frame(), &ix1, &iy1, &ix2, &iy2);
2893 gnome_canvas_item_i2w (rv2->get_canvas_group(), &ix1, &iy1);
2902 /*************************************************************
2904 ************************************************************/
2906 pair<set<Playlist*>::iterator,bool> insert_result;
2908 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
2910 AudioRegionView* rv;
2912 double ix1, ix2, iy1, iy2;
2913 int32_t temp_pointer_y_span = pointer_y_span;
2915 /* get item BBox, which will be relative to parent. so we have
2916 to query on a child, then convert to world coordinates using
2920 gnome_canvas_item_get_bounds (rv->get_canvas_frame(), &ix1, &iy1, &ix2, &iy2);
2921 gnome_canvas_item_i2w (rv->get_canvas_group(), &ix1, &iy1);
2922 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
2923 AudioTimeAxisView* canvas_atv = dynamic_cast<AudioTimeAxisView*>(tvp2);
2924 AudioTimeAxisView* temp_atv;
2926 if ((pointer_y_span != 0) && !clamp_y_axis) {
2929 for (j = height_list.begin(); j!= height_list.end(); j++) {
2930 if (x == canvas_atv->order) {
2931 /* we found the track the region is on */
2932 if (x != original_pointer_order) {
2933 /*this isn't from the same track we're dragging from */
2934 temp_pointer_y_span = canvas_pointer_y_span;
2936 while (temp_pointer_y_span > 0) {
2937 /* we're moving up canvas-wise,
2938 so we need to find the next track height
2940 if (j != height_list.begin()) {
2943 if (x != original_pointer_order) {
2944 /* we're not from the dragged track, so ignore hidden tracks. */
2946 temp_pointer_y_span++;
2950 temp_pointer_y_span--;
2952 while (temp_pointer_y_span < 0) {
2954 if (x != original_pointer_order) {
2956 temp_pointer_y_span--;
2960 if (j != height_list.end()) {
2963 temp_pointer_y_span++;
2965 /* find out where we'll be when we move and set height accordingly */
2967 tvp2 = trackview_by_y_position (iy1 + y_delta);
2968 temp_atv = dynamic_cast<AudioTimeAxisView*>(tvp2);
2969 rv->set_height (temp_atv->height);
2971 /* if you un-comment the following, the region colours will follow the track colours whilst dragging,
2972 personally, i think this can confuse things, but never mind.
2975 //const GdkColor& col (temp_atv->view->get_region_color());
2976 //rv->set_color (const_cast<GdkColor&>(col));
2983 /* prevent the regionview from being moved to before
2984 the zero position on the canvas.
2989 if (-x_delta > ix1) {
2992 } else if ((x_delta > 0) &&(rv->region.last_frame() > max_frames - x_delta)) {
2993 x_delta = max_frames - rv->region.last_frame();
2996 if (drag_info.first_move) {
2998 /* hide any dependent views */
3000 // rv->get_time_axis_view().hide_dependent_views (*rv);
3002 /* this is subtle. raising the regionview itself won't help,
3003 because raise_to_top() just puts the item on the top of
3004 its parent's stack. so, we need to put the trackview canvas_display group
3005 on the top, since its parent is the whole canvas.
3008 gnome_canvas_item_raise_to_top (rv->get_canvas_group());
3009 gnome_canvas_item_raise_to_top (rv->get_time_axis_view().canvas_display);
3010 gnome_canvas_item_raise_to_top (cursor_group);
3012 /* freeze the playlists from notifying till
3016 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&rv->get_time_axis_view());
3017 if (atv && atv->is_audio_track()) {
3018 AudioPlaylist* pl = atv->get_diskstream()->playlist();
3020 /* only freeze and capture state once */
3022 insert_result = motion_frozen_playlists.insert (pl);
3023 if (insert_result.second) {
3025 session->add_undo(pl->get_memento());
3031 if (drag_info.brushing) {
3032 mouse_brush_insert_region (rv, pending_region_position);
3034 rv->move (x_delta, y_delta);
3038 if (drag_info.first_move) {
3039 gnome_canvas_item_raise_to_top (cursor_group);
3042 drag_info.first_move = false;
3044 if (x_delta != 0 && !drag_info.brushing) {
3045 show_verbose_time_cursor (drag_info.last_frame_position, 10);
3051 Editor::region_drag_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
3053 jack_nframes_t where;
3054 AudioRegionView* rv = reinterpret_cast<AudioRegionView *> (drag_info.data);
3055 pair<set<Playlist*>::iterator,bool> insert_result;
3056 bool nocommit = true;
3058 AudioTimeAxisView* atv;
3059 bool regionview_y_movement;
3060 bool regionview_x_movement;
3062 /* first_move is set to false if the regionview has been moved in the
3066 if (drag_info.first_move) {
3073 /* The regionview has been moved at some stage during the grab so we need
3074 to account for any mouse movement between this event and the last one.
3077 region_drag_motion_callback (item, event);
3079 if (drag_info.brushing) {
3080 /* all changes were made during motion event handlers */
3084 /* adjust for track speed */
3087 atv = dynamic_cast<AudioTimeAxisView*> (drag_info.last_trackview);
3088 if (atv && atv->get_diskstream()) {
3089 speed = atv->get_diskstream()->speed();
3092 regionview_x_movement = (drag_info.last_frame_position != (jack_nframes_t) (rv->region.position()/speed));
3093 regionview_y_movement = (drag_info.last_trackview != &rv->get_time_axis_view());
3095 //printf ("last_frame: %s position is %lu %g\n", rv->get_time_axis_view().name().c_str(), drag_info.last_frame_position, speed);
3096 //printf ("last_rackview: %s \n", drag_info.last_trackview->name().c_str());
3098 if (regionview_y_movement) {
3100 /* motion between tracks */
3102 list<AudioRegionView*> new_selection;
3104 /* moved to a different audio track. */
3106 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ) {
3108 AudioRegionView* rv2 = (*i);
3110 /* the region that used to be in the old playlist is not
3111 moved to the new one - we make a copy of it. as a result,
3112 any existing editor for the region should no longer be
3116 if (!drag_info.copy) {
3117 rv2->hide_region_editor();
3119 new_selection.push_back (rv2);
3123 /* first, freeze the target tracks */
3125 for (list<AudioRegionView*>::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) {
3127 Playlist* from_playlist;
3128 Playlist* to_playlist;
3130 double ix1, ix2, iy1, iy2;
3132 gnome_canvas_item_get_bounds ((*i)->get_canvas_frame(), &ix1, &iy1, &ix2, &iy2);
3133 gnome_canvas_item_i2w ((*i)->get_canvas_group(), &ix1, &iy1);
3134 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
3135 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2);
3137 from_playlist = (*i)->region.playlist();
3138 to_playlist = atv2->playlist();
3140 /* the from_playlist was frozen in the "first_move" case
3141 of the motion handler. the insert can fail,
3142 but that doesn't matter. it just means
3143 we already have the playlist in the list.
3146 motion_frozen_playlists.insert (from_playlist);
3148 /* only freeze the to_playlist once */
3150 insert_result = motion_frozen_playlists.insert(to_playlist);
3151 if (insert_result.second) {
3152 to_playlist->freeze();
3153 session->add_undo(to_playlist->get_memento());
3158 /* now do it again with the actual operations */
3160 for (list<AudioRegionView*>::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) {
3162 Playlist* from_playlist;
3163 Playlist* to_playlist;
3165 double ix1, ix2, iy1, iy2;
3167 gnome_canvas_item_get_bounds ((*i)->get_canvas_frame(), &ix1, &iy1, &ix2, &iy2);
3168 gnome_canvas_item_i2w ((*i)->get_canvas_group(), &ix1, &iy1);
3169 TimeAxisView* tvp2 = trackview_by_y_position (iy1);
3170 AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2);
3172 from_playlist = (*i)->region.playlist();
3173 to_playlist = atv2->playlist();
3175 latest_regionview = 0;
3177 where = (jack_nframes_t) (unit_to_frame (ix1) * speed);
3178 Region* new_region = createRegion ((*i)->region);
3180 from_playlist->remove_region (&((*i)->region));
3182 sigc::connection c = atv2->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3183 to_playlist->add_region (*new_region, where);
3186 if (latest_regionview) {
3187 selection->add (latest_regionview);
3193 /* motion within a single track */
3195 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
3199 if (rv->region.locked()) {
3203 if (regionview_x_movement) {
3204 double ownspeed = 1.0;
3205 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&(rv->get_time_axis_view()));
3207 if (atv && atv->get_diskstream()) {
3208 ownspeed = atv->get_diskstream()->speed();
3211 /* base the new region position on the current position of the regionview.*/
3213 double ix1, ix2, iy1, iy2;
3215 gnome_canvas_item_get_bounds (rv->get_canvas_frame(), &ix1, &iy1, &ix2, &iy2);
3216 gnome_canvas_item_i2w (rv->get_canvas_group(), &ix1, &iy1);
3217 where = (jack_nframes_t) (unit_to_frame (ix1) * ownspeed);
3221 where = rv->region.position();
3224 rv->get_time_axis_view().reveal_dependent_views (*rv);
3226 session->add_undo (rv->region.playlist()->get_memento());
3227 rv->region.set_position (where, (void *) this);
3232 for (set<Playlist*>::iterator p = motion_frozen_playlists.begin(); p != motion_frozen_playlists.end(); ++p) {
3234 session->add_redo_no_execute ((*p)->get_memento());
3237 motion_frozen_playlists.clear ();
3240 commit_reversible_command ();
3245 Editor::region_view_item_click (AudioRegionView& rv, GdkEventButton* event)
3247 /* Either add to or set the set the region selection, unless
3248 this is an alignment click (control used)
3251 if (Keyboard::modifier_state_contains (event->state, Keyboard::Control)) {
3252 TimeAxisView* tv = &rv.get_time_axis_view();
3253 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(tv);
3255 if (atv && atv->is_audio_track()) {
3256 speed = atv->get_diskstream()->speed();
3259 if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Alt))) {
3261 align_region (rv.region, SyncPoint, (jack_nframes_t) (edit_cursor->current_frame * speed));
3263 } else if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Shift))) {
3265 align_region (rv.region, End, (jack_nframes_t) (edit_cursor->current_frame * speed));
3269 align_region (rv.region, Start, (jack_nframes_t) (edit_cursor->current_frame * speed));
3275 Editor::show_verbose_time_cursor (jack_nframes_t frame, double offset, double xpos, double ypos)
3286 switch (ARDOUR_UI::instance()->secondary_clock.mode ()) {
3287 case AudioClock::BBT:
3288 session->bbt_time (frame, bbt);
3289 snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32, bbt.bars, bbt.beats, bbt.ticks);
3292 case AudioClock::SMPTE:
3293 session->smpte_time (frame, smpte);
3294 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
3297 case AudioClock::MinSec:
3298 /* XXX fix this to compute min/sec properly */
3299 session->smpte_time (frame, smpte);
3300 secs = smpte.seconds + ((float) smpte.frames / session->smpte_frames_per_second);
3301 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%.4f", smpte.hours, smpte.minutes, secs);
3305 snprintf (buf, sizeof(buf), "%u", frame);
3309 if (xpos >= 0 && ypos >=0) {
3310 set_verbose_canvas_cursor (buf, xpos + offset, ypos + offset);
3313 set_verbose_canvas_cursor (buf, drag_info.current_pointer_x + offset, drag_info.current_pointer_y + offset);
3315 show_verbose_canvas_cursor ();
3319 Editor::show_verbose_duration_cursor (jack_nframes_t start, jack_nframes_t end, double offset, double xpos, double ypos)
3326 Meter meter_at_start(session->tempo_map().meter_at(start));
3332 switch (ARDOUR_UI::instance()->secondary_clock.mode ()) {
3333 case AudioClock::BBT:
3334 session->bbt_time (start, sbbt);
3335 session->bbt_time (end, ebbt);
3338 /* XXX this computation won't work well if the
3339 user makes a selection that spans any meter changes.
3342 ebbt.bars -= sbbt.bars;
3343 if (ebbt.beats >= sbbt.beats) {
3344 ebbt.beats -= sbbt.beats;
3347 ebbt.beats = int(meter_at_start.beats_per_bar()) + ebbt.beats - sbbt.beats;
3349 if (ebbt.ticks >= sbbt.ticks) {
3350 ebbt.ticks -= sbbt.ticks;
3353 ebbt.ticks = int(Meter::ticks_per_beat) + ebbt.ticks - sbbt.ticks;
3356 snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32, ebbt.bars, ebbt.beats, ebbt.ticks);
3359 case AudioClock::SMPTE:
3360 session->smpte_duration (end - start, smpte);
3361 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
3364 case AudioClock::MinSec:
3365 /* XXX fix this to compute min/sec properly */
3366 session->smpte_duration (end - start, smpte);
3367 secs = smpte.seconds + ((float) smpte.frames / session->smpte_frames_per_second);
3368 snprintf (buf, sizeof (buf), "%02ld:%02ld:%.4f", smpte.hours, smpte.minutes, secs);
3372 snprintf (buf, sizeof(buf), "%u", end - start);
3376 if (xpos >= 0 && ypos >=0) {
3377 set_verbose_canvas_cursor (buf, xpos + offset, ypos + offset);
3380 set_verbose_canvas_cursor (buf, drag_info.current_pointer_x + offset, drag_info.current_pointer_y + offset);
3382 show_verbose_canvas_cursor ();
3386 Editor::collect_new_region_view (AudioRegionView* rv)
3388 latest_regionview = rv;
3392 Editor::start_selection_grab (GnomeCanvasItem* item, GdkEvent* event)
3394 if (clicked_regionview == 0) {
3398 /* lets try to create new Region for the selection */
3400 vector<AudioRegion*> new_regions;
3401 create_region_from_selection (new_regions);
3403 if (new_regions.empty()) {
3407 /* XXX fix me one day to use all new regions */
3409 Region* region = new_regions.front();
3411 /* add it to the current stream/playlist.
3413 tricky: the streamview for the track will add a new regionview. we will
3414 catch the signal it sends when it creates the regionview to
3415 set the regionview we want to then drag.
3418 latest_regionview = 0;
3419 sigc::connection c = clicked_audio_trackview->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3421 /* A selection grab currently creates two undo/redo operations, one for
3422 creating the new region and another for moving it.
3425 begin_reversible_command (_("selection grab"));
3427 Playlist* playlist = clicked_trackview->playlist();
3429 session->add_undo (playlist->get_memento ());
3430 clicked_trackview->playlist()->add_region (*region, selection->time[clicked_selection].start);
3431 session->add_redo_no_execute (playlist->get_memento ());
3433 commit_reversible_command ();
3437 if (latest_regionview == 0) {
3438 /* something went wrong */
3442 /* we need to deselect all other regionviews, and select this one
3443 i'm ignoring undo stuff, because the region creation will take care of it */
3444 selection->set (latest_regionview);
3446 drag_info.item = latest_regionview->get_canvas_group();
3447 drag_info.data = latest_regionview;
3448 drag_info.motion_callback = &Editor::region_drag_motion_callback;
3449 drag_info.finished_callback = &Editor::region_drag_finished_callback;
3453 drag_info.last_trackview = clicked_trackview;
3454 drag_info.last_frame_position = latest_regionview->region.position();
3455 drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
3457 show_verbose_time_cursor (drag_info.last_frame_position, 10);
3461 Editor::cancel_selection ()
3463 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3464 (*i)->hide_selection ();
3466 selection->clear ();
3467 clicked_selection = 0;
3471 Editor::start_selection_op (GnomeCanvasItem* item, GdkEvent* event, SelectionOp op)
3473 jack_nframes_t start = 0;
3474 jack_nframes_t end = 0;
3480 drag_info.item = item;
3481 drag_info.motion_callback = &Editor::drag_selection;
3482 drag_info.finished_callback = &Editor::end_selection_op;
3487 case CreateSelection:
3489 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
3490 drag_info.copy = true;
3492 drag_info.copy = false;
3494 start_grab (event, selector_cursor);
3497 case SelectionStartTrim:
3498 clicked_trackview->order_selection_trims (item, true);
3499 start_grab (event, trimmer_cursor);
3500 start = selection->time[clicked_selection].start;
3501 drag_info.pointer_frame_offset = drag_info.grab_frame - start;
3504 case SelectionEndTrim:
3505 clicked_trackview->order_selection_trims (item, false);
3506 start_grab (event, trimmer_cursor);
3507 end = selection->time[clicked_selection].end;
3508 drag_info.pointer_frame_offset = drag_info.grab_frame - end;
3512 start = selection->time[clicked_selection].start;
3514 drag_info.pointer_frame_offset = drag_info.grab_frame - start;
3518 if (selection_op == SelectionMove) {
3519 show_verbose_time_cursor(start, 10);
3521 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
3526 Editor::drag_selection (GnomeCanvasItem* item, GdkEvent* event)
3528 jack_nframes_t start = 0;
3529 jack_nframes_t end = 0;
3530 jack_nframes_t length;
3531 jack_nframes_t pending_position;
3533 if ((int32_t) drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
3534 pending_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
3537 pending_position = 0;
3540 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3541 snap_to (pending_position);
3544 /* only alter selection if the current frame is
3545 different from the last frame position (adjusted)
3548 if (pending_position == drag_info.last_pointer_frame) return;
3550 switch (selection_op) {
3551 case CreateSelection:
3553 if (drag_info.first_move) {
3554 snap_to (drag_info.grab_frame);
3557 if (pending_position < drag_info.grab_frame) {
3558 start = pending_position;
3559 end = drag_info.grab_frame;
3561 end = pending_position;
3562 start = drag_info.grab_frame;
3565 /* first drag: Either add to the selection
3566 or create a new selection->
3569 if (drag_info.first_move) {
3571 begin_reversible_command (_("range selection"));
3573 if (drag_info.copy) {
3574 /* adding to the selection */
3575 clicked_selection = selection->add (start, end);
3576 drag_info.copy = false;
3578 /* new selection-> */
3579 clicked_selection = selection->set (clicked_trackview, start, end);
3584 case SelectionStartTrim:
3586 if (drag_info.first_move) {
3587 begin_reversible_command (_("trim selection start"));
3590 start = selection->time[clicked_selection].start;
3591 end = selection->time[clicked_selection].end;
3593 if (pending_position > end) {
3596 start = pending_position;
3600 case SelectionEndTrim:
3602 if (drag_info.first_move) {
3603 begin_reversible_command (_("trim selection end"));
3606 start = selection->time[clicked_selection].start;
3607 end = selection->time[clicked_selection].end;
3609 if (pending_position < start) {
3612 end = pending_position;
3619 if (drag_info.first_move) {
3620 begin_reversible_command (_("move selection"));
3623 start = selection->time[clicked_selection].start;
3624 end = selection->time[clicked_selection].end;
3626 length = end - start;
3628 start = pending_position;
3631 end = start + length;
3637 if (event->button.x >= track_canvas_scroller.get_hadjustment()->get_value() + canvas_width) {
3638 start_canvas_autoscroll (1);
3642 selection->replace (clicked_selection, start, end);
3645 drag_info.last_pointer_frame = pending_position;
3646 drag_info.first_move = false;
3648 if (selection_op == SelectionMove) {
3649 show_verbose_time_cursor(start, 10);
3651 show_verbose_time_cursor(pending_position, 10);
3656 Editor::end_selection_op (GnomeCanvasItem* item, GdkEvent* event)
3658 if (!drag_info.first_move) {
3659 drag_selection (item, event);
3660 /* XXX this is not object-oriented programming at all. ick */
3661 if (selection->time.consolidate()) {
3662 selection->TimeChanged ();
3664 commit_reversible_command ();
3666 /* just a click, no pointer movement.*/
3668 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3670 selection->clear_time();
3675 /* XXX what happens if its a music selection? */
3676 session->set_audio_range (selection->time);
3677 stop_canvas_autoscroll ();
3681 Editor::start_trim (GnomeCanvasItem* item, GdkEvent* event)
3684 TimeAxisView* tvp = clicked_trackview;
3685 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3687 if (tv && tv->is_audio_track()) {
3688 speed = tv->get_diskstream()->speed();
3691 jack_nframes_t region_start = (jack_nframes_t) (clicked_regionview->region.position() / speed);
3692 jack_nframes_t region_end = (jack_nframes_t) (clicked_regionview->region.last_frame() / speed);
3693 jack_nframes_t region_length = (jack_nframes_t) (clicked_regionview->region.length() / speed);
3695 //drag_info.item = clicked_regionview->get_name_highlight();
3696 drag_info.item = item;
3697 drag_info.motion_callback = &Editor::trim_motion_callback;
3698 drag_info.finished_callback = &Editor::trim_finished_callback;
3700 start_grab (event, trimmer_cursor);
3702 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
3703 trim_op = ContentsTrim;
3705 /* These will get overridden for a point trim.*/
3706 if (drag_info.current_pointer_frame < (region_start + region_length/2)) {
3707 /* closer to start */
3708 trim_op = StartTrim;
3709 } else if (drag_info.current_pointer_frame > (region_end - region_length/2)) {
3717 show_verbose_time_cursor(region_start, 10);
3720 show_verbose_time_cursor(region_end, 10);
3723 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
3727 flush_track_canvas ();
3731 Editor::trim_motion_callback (GnomeCanvasItem* item, GdkEvent* event)
3733 AudioRegionView* rv = clicked_regionview;
3734 jack_nframes_t frame_delta = 0;
3735 bool left_direction;
3736 bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier());
3738 /* snap modifier works differently here..
3739 its' current state has to be passed to the
3740 various trim functions in order to work properly
3744 TimeAxisView* tvp = clicked_trackview;
3745 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3747 if (tv && tv->is_audio_track()) {
3748 speed = tv->get_diskstream()->speed();
3751 if (drag_info.last_pointer_frame > drag_info.current_pointer_frame) {
3752 left_direction = true;
3754 left_direction = false;
3758 snap_to (drag_info.current_pointer_frame);
3761 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) {
3765 if (drag_info.first_move) {
3771 trim_type = "Region start trim";
3774 trim_type = "Region end trim";
3777 trim_type = "Region content trim";
3781 begin_reversible_command (trim_type);
3783 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
3784 (*i)->region.freeze ();
3785 (*i)->temporarily_hide_envelope ();
3786 session->add_undo ((*i)->region.playlist()->get_memento());
3790 if (left_direction) {
3791 frame_delta = (drag_info.last_pointer_frame - drag_info.current_pointer_frame);
3793 frame_delta = (drag_info.current_pointer_frame - drag_info.last_pointer_frame);
3798 if ((left_direction == false) && (drag_info.current_pointer_frame <= rv->region.first_frame()/speed)) {
3801 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
3802 single_start_trim (**i, frame_delta, left_direction, obey_snap);
3808 if ((left_direction == true) && (drag_info.current_pointer_frame > (jack_nframes_t) (rv->region.last_frame()/speed))) {
3811 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
3812 single_end_trim (**i, frame_delta, left_direction, obey_snap);
3819 bool swap_direction = false;
3821 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
3822 swap_direction = true;
3825 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin();
3826 i != selection->audio_regions.by_layer().end(); ++i)
3828 single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
3836 show_verbose_time_cursor((jack_nframes_t) (rv->region.position()/speed), 10);
3839 show_verbose_time_cursor((jack_nframes_t) (rv->region.last_frame()/speed), 10);
3842 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
3846 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
3847 drag_info.first_move = false;
3851 Editor::single_contents_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool swap_direction, bool obey_snap)
3853 Region& region (rv.region);
3855 if (region.locked()) {
3859 jack_nframes_t new_bound;
3862 TimeAxisView* tvp = clicked_trackview;
3863 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3865 if (tv && tv->is_audio_track()) {
3866 speed = tv->get_diskstream()->speed();
3869 if (left_direction) {
3870 if (swap_direction) {
3871 new_bound = (jack_nframes_t) (region.position()/speed) + frame_delta;
3873 new_bound = (jack_nframes_t) (region.position()/speed) - frame_delta;
3876 if (swap_direction) {
3877 new_bound = (jack_nframes_t) (region.position()/speed) - frame_delta;
3879 new_bound = (jack_nframes_t) (region.position()/speed) + frame_delta;
3884 snap_to (new_bound);
3886 region.trim_start ((jack_nframes_t) (new_bound * speed), this);
3887 rv.region_changed (StartChanged);
3891 Editor::single_start_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool obey_snap)
3893 Region& region (rv.region);
3895 if (region.locked()) {
3899 jack_nframes_t new_bound;
3902 TimeAxisView* tvp = clicked_trackview;
3903 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3905 if (tv && tv->is_audio_track()) {
3906 speed = tv->get_diskstream()->speed();
3909 if (left_direction) {
3910 new_bound = (jack_nframes_t) (region.position()/speed) - frame_delta;
3912 new_bound = (jack_nframes_t) (region.position()/speed) + frame_delta;
3916 snap_to (new_bound, (left_direction ? 0 : 1));
3919 region.trim_front ((jack_nframes_t) (new_bound * speed), this);
3921 rv.region_changed (Change (LengthChanged|PositionChanged|StartChanged));
3925 Editor::single_end_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool obey_snap)
3927 Region& region (rv.region);
3929 if (region.locked()) {
3933 jack_nframes_t new_bound;
3936 TimeAxisView* tvp = clicked_trackview;
3937 AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
3939 if (tv && tv->is_audio_track()) {
3940 speed = tv->get_diskstream()->speed();
3943 if (left_direction) {
3944 new_bound = (jack_nframes_t) ((region.last_frame() + 1)/speed) - frame_delta;
3946 new_bound = (jack_nframes_t) ((region.last_frame() + 1)/speed) + frame_delta;
3950 snap_to (new_bound);
3952 region.trim_end ((jack_nframes_t) (new_bound * speed), this);
3953 rv.region_changed (LengthChanged);
3957 Editor::trim_finished_callback (GnomeCanvasItem* item, GdkEvent* event)
3959 if (!drag_info.first_move) {
3960 trim_motion_callback (item, event);
3962 if (!clicked_regionview->get_selected()) {
3963 thaw_region_after_trim (*clicked_regionview);
3966 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin();
3967 i != selection->audio_regions.by_layer().end(); ++i)
3969 thaw_region_after_trim (**i);
3972 commit_reversible_command();
3974 /* no mouse movement */
3978 flush_track_canvas ();
3982 Editor::point_trim (GdkEvent* event)
3984 AudioRegionView* rv = clicked_regionview;
3985 jack_nframes_t new_bound = drag_info.current_pointer_frame;
3987 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
3988 snap_to (new_bound);
3991 /* Choose action dependant on which button was pressed */
3992 switch (event->button.button) {
3994 trim_op = StartTrim;
3995 begin_reversible_command (_("Start point trim"));
3997 if (rv->get_selected()) {
3999 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin();
4000 i != selection->audio_regions.by_layer().end(); ++i)
4002 if (!(*i)->region.locked()) {
4003 session->add_undo ((*i)->region.playlist()->get_memento());
4004 (*i)->region.trim_front (new_bound, this);
4005 session->add_redo_no_execute ((*i)->region.playlist()->get_memento());
4011 if (!rv->region.locked()) {
4012 session->add_undo (rv->region.playlist()->get_memento());
4013 rv->region.trim_front (new_bound, this);
4014 session->add_redo_no_execute (rv->region.playlist()->get_memento());
4018 commit_reversible_command();
4023 begin_reversible_command (_("End point trim"));
4025 if (rv->get_selected()) {
4027 for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i)
4029 if (!(*i)->region.locked()) {
4030 session->add_undo ((*i)->region.playlist()->get_memento());
4031 (*i)->region.trim_end (new_bound, this);
4032 session->add_redo_no_execute ((*i)->region.playlist()->get_memento());
4038 if (!rv->region.locked()) {
4039 session->add_undo (rv->region.playlist()->get_memento());
4040 rv->region.trim_end (new_bound, this);
4041 session->add_redo_no_execute (rv->region.playlist()->get_memento());
4045 commit_reversible_command();
4054 Editor::thaw_region_after_trim (AudioRegionView& rv)
4056 Region& region (rv.region);
4058 if (region.locked()) {
4062 region.thaw (_("trimmed region"));
4063 session->add_redo_no_execute (region.playlist()->get_memento());
4065 rv.unhide_envelope ();
4069 Editor::hide_marker (GnomeCanvasItem* item, GdkEvent* event)
4074 if ((marker = static_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "marker"))) == 0) {
4075 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
4079 Location* location = find_location_from_marker (marker, is_start);
4080 location->set_hidden (true, this);
4085 Editor::start_range_markerbar_op (GnomeCanvasItem* item, GdkEvent* event, RangeMarkerOp op)
4092 drag_info.item = item;
4093 drag_info.motion_callback = &Editor::drag_range_markerbar_op;
4094 drag_info.finished_callback = &Editor::end_range_markerbar_op;
4096 range_marker_op = op;
4098 if (!temp_location) {
4099 temp_location = new Location;
4103 case CreateRangeMarker:
4104 case CreateTransportMarker:
4106 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
4107 drag_info.copy = true;
4109 drag_info.copy = false;
4111 start_grab (event, selector_cursor);
4115 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
4120 Editor::drag_range_markerbar_op (GnomeCanvasItem* item, GdkEvent* event)
4122 jack_nframes_t start = 0;
4123 jack_nframes_t end = 0;
4125 GnomeCanvasItem * crect = (range_marker_op == CreateRangeMarker) ? range_bar_drag_rect: transport_bar_drag_rect;
4127 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4128 snap_to (drag_info.current_pointer_frame);
4131 /* only alter selection if the current frame is
4132 different from the last frame position.
4135 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) return;
4137 switch (range_marker_op) {
4138 case CreateRangeMarker:
4139 case CreateTransportMarker:
4140 if (drag_info.first_move) {
4141 snap_to (drag_info.grab_frame);
4144 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4145 start = drag_info.current_pointer_frame;
4146 end = drag_info.grab_frame;
4148 end = drag_info.current_pointer_frame;
4149 start = drag_info.grab_frame;
4152 /* first drag: Either add to the selection
4153 or create a new selection->
4156 if (drag_info.first_move) {
4158 temp_location->set (start, end);
4160 gnome_canvas_item_show (crect);
4162 update_marker_drag_item (temp_location);
4163 gnome_canvas_item_show (range_marker_drag_rect);
4164 gnome_canvas_item_raise_to_top (range_marker_drag_rect);
4171 if (event->button.x >= track_canvas_scroller.get_hadjustment()->get_value() + canvas_width) {
4172 start_canvas_autoscroll (1);
4176 temp_location->set (start, end);
4178 double x1 = frame_to_pixel (start);
4179 double x2 = frame_to_pixel (end);
4180 gnome_canvas_item_set (crect, "x1", x1, "x2", x2, NULL);
4182 update_marker_drag_item (temp_location);
4185 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4186 drag_info.first_move = false;
4188 show_verbose_time_cursor(drag_info.current_pointer_frame, 10);
4193 Editor::end_range_markerbar_op (GnomeCanvasItem* item, GdkEvent* event)
4195 Location * newloc = 0;
4197 if (!drag_info.first_move) {
4198 drag_range_markerbar_op (item, event);
4200 switch (range_marker_op)
4202 case CreateRangeMarker:
4203 begin_reversible_command (_("new range marker"));
4204 session->add_undo (session->locations()->get_memento());
4205 newloc = new Location(temp_location->start(), temp_location->end(), "unnamed");
4206 session->locations()->add (newloc, true);
4207 session->add_redo_no_execute (session->locations()->get_memento());
4208 commit_reversible_command ();
4210 gnome_canvas_item_hide (range_bar_drag_rect);
4211 gnome_canvas_item_hide (range_marker_drag_rect);
4214 case CreateTransportMarker:
4215 // popup menu to pick loop or punch
4216 new_transport_marker_context_menu (&event->button, item);
4221 /* just a click, no pointer movement.*/
4223 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
4230 stop_canvas_autoscroll ();
4236 Editor::start_mouse_zoom (GnomeCanvasItem* item, GdkEvent* event)
4238 drag_info.item = item;
4239 drag_info.motion_callback = &Editor::drag_mouse_zoom;
4240 drag_info.finished_callback = &Editor::end_mouse_zoom;
4242 start_grab (event, zoom_cursor);
4244 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4248 Editor::drag_mouse_zoom (GnomeCanvasItem* item, GdkEvent* event)
4250 jack_nframes_t start;
4253 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4254 snap_to (drag_info.current_pointer_frame);
4256 if (drag_info.first_move) {
4257 snap_to (drag_info.grab_frame);
4261 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) return;
4263 /* base start and end on initial click position */
4264 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4265 start = drag_info.current_pointer_frame;
4266 end = drag_info.grab_frame;
4268 end = drag_info.current_pointer_frame;
4269 start = drag_info.grab_frame;
4274 if (drag_info.first_move) {
4275 gnome_canvas_item_show (zoom_rect);
4276 gnome_canvas_item_raise_to_top (zoom_rect);
4279 reposition_zoom_rect(start, end);
4281 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4282 drag_info.first_move = false;
4284 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4289 Editor::end_mouse_zoom (GnomeCanvasItem* item, GdkEvent* event)
4291 if (!drag_info.first_move) {
4292 drag_mouse_zoom (item, event);
4294 if (drag_info.grab_frame < drag_info.last_pointer_frame) {
4295 temporal_zoom_by_frame (drag_info.grab_frame, drag_info.last_pointer_frame, "mouse zoom");
4297 temporal_zoom_by_frame (drag_info.last_pointer_frame, drag_info.grab_frame, "mouse zoom");
4300 temporal_zoom_to_frame (false, drag_info.grab_frame);
4302 temporal_zoom_step (false);
4303 center_screen (drag_info.grab_frame);
4307 gnome_canvas_item_hide (zoom_rect);
4311 Editor::reposition_zoom_rect (jack_nframes_t start, jack_nframes_t end)
4313 double x1 = frame_to_pixel (start);
4314 double x2 = frame_to_pixel (end);
4315 double y2 = canvas_height - 2;
4317 gtk_object_set (GTK_OBJECT(zoom_rect),
4326 Editor::start_rubberband_select (GnomeCanvasItem* item, GdkEvent* event)
4328 drag_info.item = item;
4329 drag_info.motion_callback = &Editor::drag_rubberband_select;
4330 drag_info.finished_callback = &Editor::end_rubberband_select;
4332 start_grab (event, cross_hair_cursor);
4334 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4338 Editor::drag_rubberband_select (GnomeCanvasItem* item, GdkEvent* event)
4340 jack_nframes_t start;
4345 /* use a bigger drag threshold than the default */
4347 if (abs ((int) (drag_info.current_pointer_frame - drag_info.grab_frame)) < 8) {
4351 // if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4352 // snap_to (drag_info.current_pointer_frame);
4354 // if (drag_info.first_move) {
4355 // snap_to (drag_info.grab_frame);
4360 /* base start and end on initial click position */
4361 if (drag_info.current_pointer_frame < drag_info.grab_frame) {
4362 start = drag_info.current_pointer_frame;
4363 end = drag_info.grab_frame;
4365 end = drag_info.current_pointer_frame;
4366 start = drag_info.grab_frame;
4369 if (drag_info.current_pointer_y < drag_info.grab_y) {
4370 y1 = drag_info.current_pointer_y;
4371 y2 = drag_info.grab_y;
4374 y2 = drag_info.current_pointer_y;
4375 y1 = drag_info.grab_y;
4379 if (start != end || y1 != y2) {
4381 double x1 = frame_to_pixel (start);
4382 double x2 = frame_to_pixel (end);
4384 gtk_object_set (GTK_OBJECT(rubberband_rect),
4391 gnome_canvas_item_show (rubberband_rect);
4392 gnome_canvas_item_raise_to_top (rubberband_rect);
4394 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4395 drag_info.first_move = false;
4397 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4402 Editor::end_rubberband_select (GnomeCanvasItem* item, GdkEvent* event)
4404 if (!drag_info.first_move) {
4406 drag_rubberband_select (item, event);
4409 if (drag_info.current_pointer_y < drag_info.grab_y) {
4410 y1 = drag_info.current_pointer_y;
4411 y2 = drag_info.grab_y;
4414 y2 = drag_info.current_pointer_y;
4415 y1 = drag_info.grab_y;
4419 bool add = Keyboard::modifier_state_contains (event->button.state, Keyboard::Shift);
4422 begin_reversible_command (_("select regions"));
4424 if (drag_info.grab_frame < drag_info.last_pointer_frame) {
4425 commit = select_all_within (drag_info.grab_frame, drag_info.last_pointer_frame, y1, y2, add);
4427 commit = select_all_within (drag_info.last_pointer_frame, drag_info.grab_frame, y1, y2, add);
4431 commit_reversible_command ();
4435 selection->clear_audio_regions();
4436 selection->clear_points ();
4437 selection->clear_lines ();
4440 gnome_canvas_item_hide (rubberband_rect);
4445 Editor::mouse_rename_region (GnomeCanvasItem* item, GdkEvent* event)
4447 using namespace Gtkmm2ext;
4449 ArdourPrompter prompter (false);
4451 prompter.set_prompt (_("Name for region:"));
4452 prompter.set_initial_text (clicked_regionview->region.name());
4453 prompter.show_all ();
4454 prompter.done.connect (Main::quit.slot());
4458 if (prompter.status == Prompter::cancelled) {
4464 prompter.get_result(str);
4465 clicked_regionview->region.set_name (str);
4471 Editor::start_time_fx (GnomeCanvasItem* item, GdkEvent* event)
4473 drag_info.item = item;
4474 drag_info.motion_callback = &Editor::time_fx_motion;
4475 drag_info.finished_callback = &Editor::end_time_fx;
4479 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4483 Editor::time_fx_motion (GnomeCanvasItem *item, GdkEvent* event)
4485 AudioRegionView* rv = clicked_regionview;
4487 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
4488 snap_to (drag_info.current_pointer_frame);
4491 if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) {
4495 if (drag_info.current_pointer_frame > rv->region.position()) {
4496 rv->get_time_axis_view().show_timestretch (rv->region.position(), drag_info.current_pointer_frame);
4499 drag_info.last_pointer_frame = drag_info.current_pointer_frame;
4500 drag_info.first_move = false;
4502 show_verbose_time_cursor (drag_info.current_pointer_frame, 10);
4506 Editor::end_time_fx (GnomeCanvasItem* item, GdkEvent* event)
4508 clicked_regionview->get_time_axis_view().hide_timestretch ();
4510 if (drag_info.first_move) {
4514 jack_nframes_t newlen = drag_info.last_pointer_frame - clicked_regionview->region.position();
4515 float percentage = (float) ((double) newlen - (double) clicked_regionview->region.length()) / ((double) newlen) * 100.0f;
4517 begin_reversible_command (_("timestretch"));
4519 if (run_timestretch (selection->audio_regions, percentage) == 0) {
4520 session->commit_reversible_command ();
4525 Editor::mouse_brush_insert_region (AudioRegionView* rv, jack_nframes_t pos)
4527 /* no brushing without a useful snap setting */
4529 switch (snap_mode) {
4531 return; /* can't work because it allows region to be placed anywhere */
4536 switch (snap_type) {
4539 case SnapToEditCursor:
4546 /* don't brush a copy over the original */
4548 if (pos == rv->region.position()) {
4552 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&rv->get_time_axis_view());
4554 if (atv == 0 || !atv->is_audio_track()) {
4558 Playlist* playlist = atv->playlist();
4559 double speed = atv->get_diskstream()->speed();
4561 session->add_undo (playlist->get_memento());
4562 playlist->add_region (*(new AudioRegion (rv->region)), (jack_nframes_t) (pos * speed));
4563 session->add_redo_no_execute (playlist->get_memento());
4565 // playlist is frozen, so we have to update manually
4567 playlist->StateChanged (Change (~0)); /* EMIT SIGNAL */
4571 Editor::track_height_step_timeout ()
4574 struct timeval delta;
4576 gettimeofday (&now, 0);
4577 timersub (&now, &last_track_height_step_timestamp, &delta);
4579 if (delta.tv_sec * 1000000 + delta.tv_usec > 250000) { /* milliseconds */
4580 current_stepping_trackview = 0;