#include "streamview.h"
#include "region_gain_line.h"
#include "automation_time_axis.h"
+#include "control_point.h"
#include "prompter.h"
#include "utils.h"
#include "selection.h"
set_mouse_mode (m);
}
break;
+
+ case MouseNote:
+ if (mouse_note_button.get_active()) {
+ set_mouse_mode (m);
+ }
+ break;
default:
break;
}
}
- /* XXX the hack of unsetting all other buttongs should go
+ /* XXX the hack of unsetting all other buttons should go
away once GTK2 allows us to use regular radio buttons drawn like
normal buttons, rather than my silly GroupedButton hack.
*/
mouse_audition_button.set_active (true);
current_canvas_cursor = speaker_cursor;
break;
+
+ case MouseNote:
+ mouse_note_button.set_active (true);
+ set_midi_edit_cursor (current_midi_edit_mode());
+ break;
}
+ if (mouse_mode == MouseNote)
+ midi_toolbar_frame.show();
+ else
+ midi_toolbar_frame.hide();
+
ignore_mouse_mode_toggle = false;
if (is_drawable()) {
- track_canvas.get_window()->set_cursor(*current_canvas_cursor);
+ track_canvas.get_window()->set_cursor(*current_canvas_cursor);
}
}
if (next) set_mouse_mode (MouseObject);
else set_mouse_mode (MouseTimeFX);
break;
+
+ case MouseNote:
+ if (next) set_mouse_mode (MouseObject);
+ else set_mouse_mode (MouseAudition);
+ break;
+ }
+}
+
+void
+Editor::midi_edit_mode_toggled (MidiEditMode m)
+{
+ if (ignore_midi_edit_mode_toggle) {
+ return;
+ }
+
+ switch (m) {
+ case MidiEditSelect:
+ if (midi_tool_select_button.get_active()) {
+ set_midi_edit_mode (m);
+ }
+ break;
+
+ case MidiEditPencil:
+ if (midi_tool_pencil_button.get_active()) {
+ set_midi_edit_mode (m);
+ }
+ break;
+
+ case MidiEditErase:
+ if (midi_tool_erase_button.get_active()) {
+ set_midi_edit_mode (m);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ set_midi_edit_cursor(m);
+}
+
+
+void
+Editor::set_midi_edit_mode (MidiEditMode m, bool force)
+{
+ if (drag_info.item) {
+ return;
+ }
+
+ if (!force && m == midi_edit_mode) {
+ return;
+ }
+
+ midi_edit_mode = m;
+
+ instant_save ();
+
+ ignore_midi_edit_mode_toggle = true;
+
+ switch (midi_edit_mode) {
+ case MidiEditSelect:
+ midi_tool_select_button.set_active (true);
+ break;
+
+ case MidiEditPencil:
+ midi_tool_pencil_button.set_active (true);
+ break;
+
+ case MidiEditErase:
+ midi_tool_erase_button.set_active (true);
+ break;
+ }
+
+ ignore_midi_edit_mode_toggle = false;
+
+ set_midi_edit_cursor (current_midi_edit_mode());
+
+ if (is_drawable()) {
+ track_canvas.get_window()->set_cursor(*current_canvas_cursor);
+ }
+}
+
+void
+Editor::set_midi_edit_cursor (MidiEditMode m)
+{
+ switch (midi_edit_mode) {
+ case MidiEditSelect:
+ current_canvas_cursor = midi_select_cursor;
+ break;
+ case MidiEditPencil:
+ current_canvas_cursor = midi_pencil_cursor;
+ break;
+ case MidiEditErase:
+ current_canvas_cursor = midi_erase_cursor;
+ break;
}
}
}
break;
- case RegionViewNameHighlight:
- case RegionViewName:
+ case RegionViewNameHighlight:
+ case RegionViewName:
if (mouse_mode != MouseRange) {
commit = set_selected_regionview_from_click (press, op, true);
} else if (event->type == GDK_BUTTON_PRESS) {
}
break;
+
case FadeInHandleItem:
case FadeInItem:
case FadeOutHandleItem:
commit = set_selected_track_from_click (press, op, false);
}
break;
-
- case GainAutomationControlPointItem:
- case PanAutomationControlPointItem:
- case RedirectAutomationControlPointItem:
+
+ case CrossfadeViewItem:
+ commit = set_selected_track_from_click (press, op, false);
+ break;
+
+ case ControlPointItem:
commit = set_selected_track_from_click (press, op, true);
if (mouse_mode != MouseRange) {
commit |= set_selected_control_point_from_click (op, false);
return true;
break;
- case GainAutomationControlPointItem:
- case PanAutomationControlPointItem:
- case RedirectAutomationControlPointItem:
+ case ControlPointItem:
start_control_point_grab (item, event);
return true;
break;
- case GainAutomationLineItem:
- case PanAutomationLineItem:
- case RedirectAutomationLineItem:
+ case AutomationLineItem:
start_line_grab_from_line (item, event);
return true;
break;
start_rubberband_select (item, event);
break;
- /* <CMT Additions> */
+#ifdef WITH_CMT
case ImageFrameHandleStartItem:
imageframe_start_handle_op(item, event) ;
return(true) ;
markerview_item_end_handle_op(item, event) ;
return(true) ;
break ;
- /* </CMT Additions> */
-
- /* <CMT Additions> */
case MarkerViewItem:
start_markerview_grab(item, event) ;
break ;
case ImageFrameItem:
start_imageframe_grab(item, event) ;
break ;
- /* </CMT Additions> */
+#endif
case MarkerBarItem:
// start_line_grab_from_regionview (item, event);
break;
- case GainControlPointItem:
- start_control_point_grab (item, event);
- return true;
-
case GainLineItem:
start_line_grab_from_line (item, event);
return true;
- case GainAutomationControlPointItem:
- case PanAutomationControlPointItem:
- case RedirectAutomationControlPointItem:
+ case ControlPointItem:
start_control_point_grab (item, event);
return true;
break;
break;
switch (item_type) {
- case GainAutomationControlPointItem:
- case PanAutomationControlPointItem:
- case RedirectAutomationControlPointItem:
+ case ControlPointItem:
start_control_point_grab (item, event);
break;
- case GainAutomationLineItem:
- case PanAutomationLineItem:
- case RedirectAutomationLineItem:
+ case AutomationLineItem:
start_line_grab_from_line (item, event);
break;
break;
case MouseAudition:
- /* handled in release */
+ _scrubbing = true;
+ last_scrub_frame = 0;
+ last_scrub_time = 0;
+ have_full_mouse_speed = false;
+ memset (mouse_speed, 0, sizeof (double) * mouse_speed_size);
+ /* rest handled in motion & release */
break;
default:
}
break;
- case GainAutomationControlPointItem:
- case PanAutomationControlPointItem:
- case RedirectAutomationControlPointItem:
+ case ControlPointItem:
start_control_point_grab (item, event);
return true;
break;
break;
case StreamItem:
- popup_track_context_menu (1, event->button.time, item_type, false, where);
+ popup_track_context_menu (1, event->button.time, where);
break;
case RegionItem:
case RegionViewNameHighlight:
case RegionViewName:
- popup_track_context_menu (1, event->button.time, item_type, false, where);
+ popup_track_context_menu (1, event->button.time, where);
break;
case SelectionItem:
- popup_track_context_menu (1, event->button.time, item_type, true, where);
+ popup_track_context_menu (1, event->button.time, where);
break;
case AutomationTrackItem:
- popup_track_context_menu (1, event->button.time, item_type, false, where);
+ case CrossfadeViewItem:
+ popup_track_context_menu (1, event->button.time, where);
break;
case MarkerBarItem:
tm_marker_context_menu (&event->button, item);
break;
- case CrossfadeViewItem:
- popup_track_context_menu (1, event->button.time, item_type, false, where);
- break;
-
- /* <CMT Additions> */
+#ifdef WITH_CMT
case ImageFrameItem:
popup_imageframe_edit_menu(1, event->button.time, item, true) ;
break ;
case MarkerTimeAxisItem:
popup_marker_time_axis_edit_menu(1, event->button.time, item, false) ;
break ;
- /* <CMT Additions> */
-
+#endif
default:
break;
}
break;
- case GainControlPointItem:
+ case ControlPointItem:
if (mouse_mode == MouseGain) {
remove_gain_control_point (item, event);
+ } else {
+ remove_control_point (item, event);
}
break;
- case GainAutomationControlPointItem:
- case PanAutomationControlPointItem:
- case RedirectAutomationControlPointItem:
- remove_control_point (item, event);
- break;
-
default:
break;
}
case PlayheadCursorItem:
case MarkerItem:
case GainLineItem:
- case GainAutomationLineItem:
- case PanAutomationLineItem:
- case RedirectAutomationLineItem:
+ case AutomationLineItem:
case StartSelectionTrimItem:
case EndSelectionTrimItem:
return true;
break;
case MouseAudition:
- switch (item_type) {
- case RegionItem:
- audition_selected_region ();
- break;
- default:
- break;
- }
+ _scrubbing = false;
+ if (last_scrub_frame == 0) {
+ /* no drag, just a click */
+ switch (item_type) {
+ case RegionItem:
+ audition_selected_region ();
+ break;
+ default:
+ break;
+ }
+ } else {
+ /* make sure we stop */
+ session->request_transport_speed (0.0);
+ }
break;
default:
case 2:
switch (mouse_mode) {
- case MouseObject:
- switch (item_type) {
- case RegionItem:
- if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
- raise_region ();
- } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::ModifierMask (Keyboard::Shift|Keyboard::Alt))) {
- lower_region ();
- } else {
- // Button2 click is unused
- }
- return true;
-
- break;
-
- default:
- break;
- }
- break;
-
case MouseRange:
// x_style_paste (where, 1.0);
double fraction;
switch (item_type) {
- case GainControlPointItem:
- if (mouse_mode == MouseGain) {
- cp = static_cast<ControlPoint*>(item->get_data ("control_point"));
- cp->set_visible (true);
-
- double at_x, at_y;
- at_x = cp->get_x();
- at_y = cp->get_y ();
- cp->item->i2w (at_x, at_y);
- at_x += 20.0;
- at_y += 20.0;
-
- fraction = 1.0 - (cp->get_y() / cp->line.height());
-
- set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y);
- show_verbose_canvas_cursor ();
-
- if (is_drawable()) {
- track_canvas.get_window()->set_cursor (*fader_cursor);
- }
- }
- break;
-
- case GainAutomationControlPointItem:
- case PanAutomationControlPointItem:
- case RedirectAutomationControlPointItem:
+ case ControlPointItem:
if (mouse_mode == MouseGain || mouse_mode == MouseObject) {
cp = static_cast<ControlPoint*>(item->get_data ("control_point"));
cp->set_visible (true);
double at_x, at_y;
at_x = cp->get_x();
at_y = cp->get_y ();
- cp->item->i2w (at_x, at_y);
+ cp->item()->i2w (at_x, at_y);
at_x += 20.0;
at_y += 20.0;
- fraction = 1.0 - (cp->get_y() / cp->line.height());
+ fraction = 1.0 - (cp->get_y() / cp->line().height());
- set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y);
+ set_verbose_canvas_cursor (cp->line().get_verbose_cursor_string (fraction), at_x, at_y);
show_verbose_canvas_cursor ();
if (is_drawable()) {
if (mouse_mode == MouseGain) {
ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
if (line)
- line->property_fill_color_rgba() = color_map[cEnteredGainLine];
+ line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_EnteredGainLine.get();
if (is_drawable()) {
track_canvas.get_window()->set_cursor (*fader_cursor);
}
}
break;
- case GainAutomationLineItem:
- case RedirectAutomationLineItem:
- case PanAutomationLineItem:
+ case AutomationLineItem:
if (mouse_mode == MouseGain || mouse_mode == MouseObject) {
{
ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
if (line)
- line->property_fill_color_rgba() = color_map[cEnteredAutomationLine];
+ line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_EnteredAutomationLine.get();
}
if (is_drawable()) {
track_canvas.get_window()->set_cursor (*fader_cursor);
case StartSelectionTrimItem:
case EndSelectionTrimItem:
- /* <CMT Additions> */
+
+#ifdef WITH_CMT
case ImageFrameHandleStartItem:
case ImageFrameHandleEndItem:
case MarkerViewHandleStartItem:
case MarkerViewHandleEndItem:
- /* </CMT Additions> */
+#endif
if (is_drawable()) {
track_canvas.get_window()->set_cursor (*trimmer_cursor);
case AutomationTrackItem:
if (is_drawable()) {
- Gdk::Cursor *cursor;
+ Gdk::Cursor *cursor;
switch (mouse_mode) {
case MouseRange:
cursor = selector_cursor;
if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
break;
}
- marker->set_color_rgba (color_map[cEnteredMarker]);
+ marker->set_color_rgba (ARDOUR_UI::config()->canvasvar_EnteredMarker.get());
// fall through
case MeterMarkerItem:
case TempoMarkerItem:
switch (item_type) {
case GainLineItem:
- case GainAutomationLineItem:
- case RedirectAutomationLineItem:
- case PanAutomationLineItem:
- case GainControlPointItem:
- case GainAutomationControlPointItem:
- case PanAutomationControlPointItem:
- case RedirectAutomationControlPointItem:
+ case AutomationLineItem:
+ case ControlPointItem:
/* these do not affect the current entered track state */
clear_entered_track = false;
break;
bool is_start;
switch (item_type) {
- case GainControlPointItem:
- case GainAutomationControlPointItem:
- case PanAutomationControlPointItem:
- case RedirectAutomationControlPointItem:
+ case ControlPointItem:
cp = reinterpret_cast<ControlPoint*>(item->get_data ("control_point"));
- if (cp->line.npoints() > 1) {
- if (!cp->selected) {
+ if (cp->line().the_list()->interpolation() != AutomationList::Discrete) {
+ if (cp->line().npoints() > 1 && !cp->selected()) {
cp->set_visible (false);
}
}
case EndSelectionTrimItem:
case EditCursorItem:
case PlayheadCursorItem:
- /* <CMT Additions> */
+
+#ifdef WITH_CMT
case ImageFrameHandleStartItem:
case ImageFrameHandleEndItem:
case MarkerViewHandleStartItem:
case MarkerViewHandleEndItem:
- /* </CMT Additions> */
+#endif
+
if (is_drawable()) {
track_canvas.get_window()->set_cursor (*current_canvas_cursor);
}
break;
case GainLineItem:
- case GainAutomationLineItem:
- case RedirectAutomationLineItem:
- case PanAutomationLineItem:
+ case AutomationLineItem:
al = reinterpret_cast<AutomationLine*> (item->get_data ("line"));
{
ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
return false;
}
+static gboolean
+_update_mouse_speed (void *arg)
+{
+ return static_cast<Editor*>(arg)->update_mouse_speed ();
+}
+
bool
Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type, bool from_autoscroll)
{
drag_info.current_pointer_frame = event_frame (event, &drag_info.current_pointer_x,
&drag_info.current_pointer_y);
+ switch (mouse_mode) {
+ case MouseAudition:
+ if (_scrubbing) {
+ struct timeval tmnow;
+
+ if (last_scrub_frame == 0) {
+
+ /* first motion, just set up the variables */
+
+ last_scrub_frame = (nframes64_t) drag_info.current_pointer_frame;
+ gettimeofday (&tmnow, 0);
+ last_scrub_time = tmnow.tv_sec * 1000000.0 + tmnow.tv_usec;
+ session->request_locate (last_scrub_frame, true);
+
+ } else {
+ /* how fast is the mouse moving ? */
+
+ double speed;
+ nframes_t distance;
+ double time;
+ double dir;
+
+#if 1
+ if (last_scrub_frame < (nframes64_t) drag_info.current_pointer_frame) {
+ distance = (nframes64_t) drag_info.current_pointer_frame - last_scrub_frame;
+ dir = 1.0;
+ } else {
+ distance = last_scrub_frame - (nframes64_t) drag_info.current_pointer_frame;
+ dir = -1.0;
+ }
+#else
+ if (drag_info.grab_x < drag_info.current_pointer_x) {
+ distance = drag_info.current_pointer_x - drag_info.grab_x;
+ dir = -1.0;
+ } else {
+ distance = drag_info.grab_x - drag_info.current_pointer_x;
+ dir = 1.0;
+ }
+#endif
+
+ gettimeofday (&tmnow, 0);
+ time = (tmnow.tv_sec * 1000000.0 + tmnow.tv_usec) - last_scrub_time;
+ last_scrub_frame = drag_info.current_pointer_frame;
+ last_scrub_time = (tmnow.tv_sec * 1000000.0) + tmnow.tv_usec;
+ speed = ((double)distance/session->frame_rate()) / (time/1000000.0); // frames/sec
+
+ add_mouse_speed (speed, dir);
+
+ if (mouse_speed_update < 0) {
+ mouse_speed_update = g_timeout_add (10, _update_mouse_speed, this);
+ update_mouse_speed ();
+ }
+ }
+ }
+
+ default:
+ break;
+ }
+
+
if (!from_autoscroll && drag_info.item) {
/* item != 0 is the best test i can think of for dragging.
*/
if (!drag_info.move_threshold_passed) {
- bool x_threshold_passed = (abs ((int) (drag_info.current_pointer_x - drag_info.grab_x)) > 4);
- bool y_threshold_passed = (abs ((int) (drag_info.current_pointer_y - drag_info.grab_y)) > 4);
-
+ bool x_threshold_passed = (abs ((nframes64_t) (drag_info.current_pointer_x - drag_info.grab_x)) > 4LL);
+ bool y_threshold_passed = (abs ((nframes64_t) (drag_info.current_pointer_y - drag_info.grab_y)) > 4LL);
+
drag_info.move_threshold_passed = (x_threshold_passed || y_threshold_passed);
// and change the initial grab loc/frame if this drag info wants us to
case PlayheadCursorItem:
case EditCursorItem:
case MarkerItem:
- case GainControlPointItem:
- case RedirectAutomationControlPointItem:
- case GainAutomationControlPointItem:
- case PanAutomationControlPointItem:
+ case ControlPointItem:
case TempoMarkerItem:
case MeterMarkerItem:
case RegionViewNameHighlight:
case EndSelectionTrimItem:
case SelectionItem:
case GainLineItem:
- case RedirectAutomationLineItem:
- case GainAutomationLineItem:
- case PanAutomationLineItem:
+ case AutomationLineItem:
case FadeInHandleItem:
case FadeOutHandleItem:
- /* <CMT Additions> */
+
+#ifdef WITH_CMT
case ImageFrameHandleStartItem:
case ImageFrameHandleEndItem:
case MarkerViewHandleStartItem:
case MarkerViewHandleEndItem:
- /* </CMT Additions> */
+#endif
+
if (drag_info.item && (event->motion.state & Gdk::BUTTON1_MASK ||
(event->motion.state & Gdk::BUTTON2_MASK))) {
if (!from_autoscroll) {
cursor = grabber_cursor;
}
- // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
+ // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
if (event->button.button == 2) {
if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Alt)) {
drag_info.y_constrained = false;
}
- drag_info.grab_frame = event_frame(event, &drag_info.grab_x, &drag_info.grab_y);
+ drag_info.grab_frame = event_frame (event, &drag_info.grab_x, &drag_info.grab_y);
drag_info.last_pointer_frame = drag_info.grab_frame;
drag_info.current_pointer_frame = drag_info.grab_frame;
drag_info.current_pointer_x = drag_info.grab_x;
AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
- drag_info.pointer_frame_offset = drag_info.grab_frame - ((nframes_t) arv->audio_region()->fade_in().back()->when + arv->region()->position());
+ drag_info.pointer_frame_offset = drag_info.grab_frame - ((nframes_t) arv->audio_region()->fade_in()->back()->when + arv->region()->position());
}
void
nframes_t pos;
nframes_t fade_length;
- if ((int32_t)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+ if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
}
else {
if (drag_info.first_move) return;
- if ((int32_t)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+ if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
} else {
pos = 0;
continue;
}
- AutomationList& alist = tmp->audio_region()->fade_in();
- XMLNode &before = alist.get_state();
+ boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
+ XMLNode &before = alist->get_state();
tmp->audio_region()->set_fade_in_length (fade_length);
- XMLNode &after = alist.get_state();
- session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
+ XMLNode &after = alist->get_state();
+ session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
}
commit_reversible_command ();
AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
- drag_info.pointer_frame_offset = drag_info.grab_frame - (arv->region()->length() - (nframes_t) arv->audio_region()->fade_out().back()->when + arv->region()->position());
+ drag_info.pointer_frame_offset = drag_info.grab_frame - (arv->region()->length() - (nframes_t) arv->audio_region()->fade_out()->back()->when + arv->region()->position());
}
void
nframes_t pos;
nframes_t fade_length;
- if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+ if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
- }
- else {
+ } else {
pos = 0;
}
nframes_t pos;
nframes_t fade_length;
- if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+ if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
}
else {
continue;
}
- AutomationList& alist = tmp->audio_region()->fade_out();
- XMLNode &before = alist.get_state();
+ boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
+ XMLNode &before = alist->get_state();
tmp->audio_region()->set_fade_out_length (fade_length);
- XMLNode &after = alist.get_state();
- session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
+ XMLNode &after = alist->get_state();
+ session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
}
commit_reversible_command ();
Cursor* cursor = (Cursor *) drag_info.data;
nframes_t adjusted_frame;
- if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+ if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
}
else {
double x2 = frame_to_pixel (location->end());
if (location->is_mark()) {
- marker_drag_line_points.front().set_x(x1);
+ marker_drag_line_points.front().set_x(x1);
marker_drag_line_points.back().set_x(x1);
marker_drag_line->property_points() = marker_drag_line_points;
}
nframes_t newframe;
- if (drag_info.pointer_frame_offset <= (long) drag_info.current_pointer_frame) {
+ if (drag_info.pointer_frame_offset <= drag_info.current_pointer_frame) {
newframe = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
- }
- else {
+ } else {
newframe = 0;
}
// The actual copying is not done before we reach the finish callback.
char name[64];
snprintf (name, sizeof(name), "%g/%g", meter_marker->meter().beats_per_bar(), meter_marker->meter().note_divisor ());
- MeterMarker* new_marker = new MeterMarker(*this, *meter_group, color_map[cMeterMarker], name,
+ MeterMarker* new_marker = new MeterMarker(*this, *meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
*new MeterSection(meter_marker->meter()));
drag_info.item = &new_marker->the_item();
MeterMarker* marker = (MeterMarker *) drag_info.data;
nframes_t adjusted_frame;
- if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+ if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
}
else {
if (drag_info.copy == true) {
begin_reversible_command (_("copy meter mark"));
- XMLNode &before = map.get_state();
+ XMLNode &before = map.get_state();
map.add_meter (marker->meter(), when);
XMLNode &after = map.get_state();
- session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
+ session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
commit_reversible_command ();
-
+
// delete the dummy marker we used for visual representation of copying.
// a new visual marker will show up automatically.
delete marker;
XMLNode &before = map.get_state();
map.move_meter (marker->meter(), when);
XMLNode &after = map.get_state();
- session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
+ session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
commit_reversible_command ();
}
}
// The actual copying is not done before we reach the finish callback.
char name[64];
snprintf (name, sizeof (name), "%.2f", tempo_marker->tempo().beats_per_minute());
- TempoMarker* new_marker = new TempoMarker(*this, *tempo_group, color_map[cTempoMarker], name,
+ TempoMarker* new_marker = new TempoMarker(*this, *tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
*new TempoSection(tempo_marker->tempo()));
drag_info.item = &new_marker->the_item();
TempoMarker* marker = (TempoMarker *) drag_info.data;
nframes_t adjusted_frame;
- if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+ if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
}
else {
delete marker;
} else {
begin_reversible_command (_("move tempo mark"));
- XMLNode &before = map.get_state();
+ XMLNode &before = map.get_state();
map.move_tempo (marker->tempo(), when);
- XMLNode &after = map.get_state();
- session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
+ XMLNode &after = map.get_state();
+ session->add_command (new MementoCommand<TempoMap>(map, &before, &after));
commit_reversible_command ();
}
}
}
// We shouldn't remove the first or last gain point
- if (control_point->line.is_last_point(*control_point) ||
- control_point->line.is_first_point(*control_point)) {
+ if (control_point->line().is_last_point(*control_point) ||
+ control_point->line().is_first_point(*control_point)) {
return;
}
- control_point->line.remove_point (*control_point);
+ control_point->line().remove_point (*control_point);
}
void
-Editor::remove_control_point (ArdourCanvas::Item*item, GdkEvent* event)
+Editor::remove_control_point (ArdourCanvas::Item* item, GdkEvent* event)
{
ControlPoint* control_point;
/*NOTREACHED*/
}
- control_point->line.remove_point (*control_point);
+ control_point->line().remove_point (*control_point);
}
void
Editor::start_control_point_grab (ArdourCanvas::Item* item, GdkEvent* event)
{
ControlPoint* control_point;
-
+
if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
/*NOTREACHED*/
start_grab (event, fader_cursor);
- control_point->line.start_drag (control_point, drag_info.grab_frame, 0);
+ control_point->line().start_drag (control_point, drag_info.grab_frame, 0);
- float fraction = 1.0 - (control_point->get_y() / control_point->line.height());
- set_verbose_canvas_cursor (control_point->line.get_verbose_cursor_string (fraction),
+ double fraction = 1.0 - ((control_point->get_y() - control_point->line().y_position()) / (double)control_point->line().height());
+ set_verbose_canvas_cursor (control_point->line().get_verbose_cursor_string (fraction),
drag_info.current_pointer_x + 20, drag_info.current_pointer_y + 20);
show_verbose_canvas_cursor ();
cy = drag_info.grab_y;
}
- cp->line.parent_group().w2i (cx, cy);
+ cp->line().parent_group().w2i (cx, cy);
cx = max (0.0, cx);
cy = max (0.0, cy);
- cy = min ((double) cp->line.height(), cy);
+ cy = min ((double) (cp->line().y_position() + cp->line().height()), cy);
//translate cx to frames
nframes_t cx_frames = unit_to_frame (cx);
snap_to (cx_frames);
}
- float fraction = 1.0 - (cy / cp->line.height());
-
+ const double fraction = 1.0 - ((cy - cp->line().y_position()) / (double)cp->line().height());
+
bool push;
if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
push = false;
}
- cp->line.point_drag (*cp, cx_frames , fraction, push);
+ cp->line().point_drag (*cp, cx_frames , fraction, push);
- set_verbose_canvas_cursor_text (cp->line.get_verbose_cursor_string (fraction));
+ set_verbose_canvas_cursor_text (cp->line().get_verbose_cursor_string (fraction));
drag_info.first_move = false;
}
} else {
control_point_drag_motion_callback (item, event);
}
- cp->line.end_drag (cp);
+ cp->line().end_drag (cp);
}
void
start_grab (event, fader_cursor);
- double fraction = 1.0 - (cy / line->height());
+ const double fraction = 1.0 - ((cy - line->y_position()) / (double)line->height());
line->start_drag (0, drag_info.grab_frame, fraction);
line->parent_group().w2i (cx, cy);
- double fraction;
- fraction = 1.0 - (cy / line->height());
+ const double fraction = 1.0 - ((cy - line->y_position()) / (double)line->height());
bool push;
original_pointer_order = drag_info.last_trackview->order;
/************************************************************
- Y-Delta Computation
+ Y-Delta Computation
************************************************************/
if (drag_info.brushing) {
TimeAxisView *tracklist_timeview;
tracklist_timeview = (*i);
RouteTimeAxisView* rtv2 = dynamic_cast<RouteTimeAxisView*>(tracklist_timeview);
- list<TimeAxisView*> children_list;
+ TimeAxisView::Children children_list;
/* zeroes are audio tracks. ones are other types. */
height_list[rtv2->order] = (*i)->height;
children = 1;
if ((children_list = rtv2->get_child_list()).size() > 0) {
- for (list<TimeAxisView*>::iterator j = children_list.begin(); j != children_list.end(); ++j) {
+ for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
tracks = tracks |= (0x01 << (rtv2->order + children));
height_list[rtv2->order + children] = (*j)->height;
numtracks++;
}
/************************************************************
- X DELTA COMPUTATION
+ X DELTA COMPUTATION
************************************************************/
/* compute the amount of pointer motion in frames, and where
if (drag_info.move_threshold_passed) {
- if ((int32_t)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+ if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
nframes_t sync_frame;
nframes_t sync_offset;
int32_t sync_dir;
pending_region_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
-
+
sync_offset = rv->region()->sync_offset (sync_dir);
sync_frame = rv->region()->adjust_to_sync (pending_region_position);
/* now compute the canvas unit distance we need to move the regiondrag_info.last_trackview->order
to make it appear at the new location.
*/
-
+
if (pending_region_position > drag_info.last_frame_position) {
x_delta = ((double) (pending_region_position - drag_info.last_frame_position) / frames_per_unit);
} else {
x_delta = -((double) (drag_info.last_frame_position - pending_region_position) / frames_per_unit);
}
-
+
drag_info.last_frame_position = pending_region_position;
} else {
}
/*************************************************************
- PREPARE TO MOVE
+ PREPARE TO MOVE
************************************************************/
if (x_delta == 0 && (pointer_y_span == 0)) {
return;
}
+
if (x_delta < 0) {
for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
}
/*************************************************************
- MOTION
+ MOTION
************************************************************/
bool do_move;
tvp2 = trackview_by_y_position (iy1 + y_delta);
temp_rtv = dynamic_cast<RouteTimeAxisView*>(tvp2);
- rv->set_height (temp_rtv->height);
+ rv->set_y_position_and_height (0, temp_rtv->height);
/* if you un-comment the following, the region colours will follow the track colours whilst dragging,
personally, i think this can confuse things, but never mind.
if (-x_delta > ix1) {
x_delta = -ix1;
}
- } else if ((x_delta > 0) &&(rv->region()->last_frame() > max_frames - x_delta)) {
+ } else if ((x_delta > 0) && (rv->region()->last_frame() > max_frames - x_delta)) {
x_delta = max_frames - rv->region()->last_frame();
}
+
if (drag_info.first_move) {
/* hide any dependent views */
boost::shared_ptr<Playlist> from_playlist = rv->region()->playlist();
boost::shared_ptr<Playlist> to_playlist = rtv2->playlist();
-
+
where = (nframes_t) (unit_to_frame (ix1) * speed);
boost::shared_ptr<Region> new_region (RegionFactory::create (rv->region()));
rv = (*i);
- if (rv->region()->locked()) {
+ if (!rv->region()->can_move()) {
continue;
}
-
if (regionview_x_movement) {
double ownspeed = 1.0;
boost::shared_ptr<Region> newregion;
boost::shared_ptr<Region> ar;
+ boost::shared_ptr<Region> mr;
if ((ar = boost::dynamic_pointer_cast<AudioRegion>(rv->region())) != 0) {
newregion = RegionFactory::create (ar);
- } else {
- /* XXX MIDI HERE drobilla */
- continue;
+ } else if ((mr = boost::dynamic_pointer_cast<MidiRegion>(rv->region())) != 0) {
+ newregion = RegionFactory::create (mr);
}
/* add it */
-
+
latest_regionview = 0;
sigc::connection c = rtv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
to_playlist->add_region (newregion, (nframes_t) (where * rtv->get_diskstream()->speed()));
rtv->reveal_dependent_views (*latest_regionview);
selection->add (latest_regionview);
}
-
+
/* if the original region was locked, we don't care for the new one */
newregion->set_locked (false);
-
+
} else {
/* just change the model */
void
Editor::cancel_selection ()
{
- for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
+ for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
(*i)->hide_selection ();
}
begin_reversible_command (_("cancel selection"));
nframes_t length;
nframes_t pending_position;
- if ((int32_t) drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+ if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
pending_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
- }
- else {
+ } else {
pending_position = 0;
}
boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
insert_result = motion_frozen_playlists.insert (pl);
if (insert_result.second) {
- session->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
+ session->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
}
}
}
case StartTrim:
if ((left_direction == false) && (drag_info.current_pointer_frame <= rv->region()->first_frame()/speed)) {
break;
- } else {
+ } else {
for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
single_start_trim (**i, frame_delta, left_direction, obey_snap);
}
for (set<boost::shared_ptr<Playlist> >::iterator p = motion_frozen_playlists.begin(); p != motion_frozen_playlists.end(); ++p) {
//(*p)->thaw ();
- session->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
- }
+ session->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
+ }
motion_frozen_playlists.clear ();
{
if (!(*i)->region()->locked()) {
boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
- XMLNode &before = pl->get_state();
+ XMLNode &before = pl->get_state();
(*i)->region()->trim_front (new_bound, this);
- XMLNode &after = pl->get_state();
- session->add_command(new MementoCommand<Playlist>(*pl.get(), &before, &after));
+ XMLNode &after = pl->get_state();
+ session->add_command(new MementoCommand<Playlist>(*pl.get(), &before, &after));
}
}
boost::shared_ptr<Playlist> pl = rv->region()->playlist();
XMLNode &before = pl->get_state();
rv->region()->trim_front (new_bound, this);
- XMLNode &after = pl->get_state();
+ XMLNode &after = pl->get_state();
session->add_command(new MementoCommand<Playlist>(*pl.get(), &before, &after));
}
}
boost::shared_ptr<Playlist> pl = rv->region()->playlist();
XMLNode &before = pl->get_state();
rv->region()->trim_end (new_bound, this);
- XMLNode &after = pl->get_state();
+ XMLNode &after = pl->get_state();
session->add_command (new MementoCommand<Playlist>(*pl.get(), &before, &after));
}
}
}
region->thaw (_("trimmed region"));
- XMLNode &after = region->playlist()->get_state();
+ XMLNode &after = region->playlist()->get_state();
session->add_command (new MementoCommand<Playlist>(*(region->playlist()), 0, &after));
AudioRegionView* arv = dynamic_cast<AudioRegionView*>(&rv);
case CreateRangeMarker:
{
begin_reversible_command (_("new range marker"));
- XMLNode &before = session->locations()->get_state();
+ XMLNode &before = session->locations()->get_state();
session->locations()->next_available_name(rangename,"unnamed");
newloc = new Location(temp_location->start(), temp_location->end(), rangename, Location::IsRangeMarker);
session->locations()->add (newloc, true);
- XMLNode &after = session->locations()->get_state();
+ XMLNode &after = session->locations()->get_state();
session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
commit_reversible_command ();
prompter.show_all ();
switch (prompter.run ()) {
case Gtk::RESPONSE_ACCEPT:
- string str;
+ string str;
prompter.get_result(str);
if (str.length()) {
clicked_regionview->region()->set_name (str);
if (drag_info.first_move) {
return;
}
+
+ if (drag_info.last_pointer_frame < clicked_regionview->region()->position()) {
+ /* backwards drag of the left edge - not usable */
+ return;
+ }
nframes_t newlen = drag_info.last_pointer_frame - clicked_regionview->region()->position();
float percentage = (float) ((double) newlen - (double) clicked_regionview->region()->length()) / ((double) newlen) * 100.0f;
boost::shared_ptr<Playlist> playlist = rtv->playlist();
double speed = rtv->get_diskstream()->speed();
- XMLNode &before = playlist->get_state();
+ XMLNode &before = playlist->get_state();
playlist->add_region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (arv->audio_region())), (nframes_t) (pos * speed));
- XMLNode &after = playlist->get_state();
+ XMLNode &after = playlist->get_state();
session->add_command(new MementoCommand<Playlist>(*playlist.get(), &before, &after));
// playlist is frozen, so we have to update manually
}
return true;
}
+
+
+void
+Editor::add_mouse_speed (double speed, double dir)
+{
+ size_t index;
+
+ mouse_direction = dir;
+
+ index = mouse_speed_entries;
+
+ if (++index >= mouse_speed_size) {
+ index = 0;
+ have_full_mouse_speed = true;
+ }
+
+ mouse_speed[index] = speed;
+ mouse_speed_entries = index;
+}
+
+double
+Editor::compute_mouse_speed ()
+{
+ double total = 0;
+
+ if (!have_full_mouse_speed) {
+
+ /* partial speed buffer, just use whatever we have so far */
+
+ if (mouse_speed_entries == 0 ) {
+ return 0.0;
+ }
+
+ for (size_t n = 0; n < mouse_speed_entries; ++n) {
+ total += mouse_speed[n];
+ }
+
+ return mouse_direction * total/mouse_speed_entries;
+ }
+
+ /* compute the average (effectively low-pass filtering) mouse speed
+ across the entire buffer.
+ */
+
+ for (size_t n = 0; n < mouse_speed_size; ++n) {
+ total += mouse_speed[n];
+ }
+
+
+ return mouse_direction * total/mouse_speed_size;
+}
+
+bool
+Editor::update_mouse_speed ()
+{
+ double speed;
+
+ if (!_scrubbing) {
+ session->request_transport_speed (0.0);
+ mouse_speed_update = -1;
+ return false;
+ }
+
+ speed = compute_mouse_speed ();
+
+ struct timeval tmnow;
+
+ gettimeofday (&tmnow, 0);
+ double now = (tmnow.tv_sec * 1000000.0) + tmnow.tv_usec;
+
+ if (now - last_scrub_time > 250000) {
+
+ // 0.25 seconds since last mouse motion, start to brake
+
+ if (fabs (speed) < 0.1) {
+ /* don't asymptotically approach zero */
+ memset (mouse_speed, 0, sizeof (double) * mouse_speed_size);
+ speed = 0.0;
+ } else if (fabs (speed) < 0.25) {
+ add_mouse_speed (fabs (speed * 0.2), mouse_direction);
+ } else {
+ add_mouse_speed (fabs (speed * 0.6), mouse_direction);
+ }
+ }
+
+ session->request_transport_speed (speed);
+ return _scrubbing;
+}