X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=gtk2_ardour%2Feditor_mouse.cc;h=8f875b88e33c7c9916a31678d36de15792fcf03f;hb=56047a094cdc1f41b369c6796690cded85e2a2c6;hp=18478cdaacf2935d76cb096c14778b569eba07c4;hpb=4dc63966f0872efe768dad61eb9b8785d06b92d1;p=ardour.git diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index 18478cdaac..8f875b88e3 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -34,10 +34,10 @@ #include "gtkmm2ext/bindings.h" #include "gtkmm2ext/utils.h" -#include "gtkmm2ext/tearoff.h" #include "canvas/canvas.h" +#include "ardour/audioplaylist.h" #include "ardour/audioregion.h" #include "ardour/operations.h" #include "ardour/playlist.h" @@ -47,7 +47,10 @@ #include "ardour/session.h" #include "ardour/types.h" +#include "widgets/prompter.h" + #include "actions.h" +#include "ardour_ui.h" #include "editor.h" #include "time_axis_view.h" #include "audio_time_axis.h" @@ -56,9 +59,9 @@ #include "marker.h" #include "streamview.h" #include "region_gain_line.h" +#include "rc_option_editor.h" #include "automation_time_axis.h" #include "control_point.h" -#include "prompter.h" #include "selection.h" #include "keyboard.h" #include "editing.h" @@ -72,7 +75,7 @@ #include "verbose_cursor.h" #include "note.h" -#include "i18n.h" +#include "pbd/i18n.h" using namespace std; using namespace ARDOUR; @@ -82,21 +85,21 @@ using namespace Editing; using Gtkmm2ext::Keyboard; bool -Editor::mouse_frame (framepos_t& where, bool& in_track_canvas) const +Editor::mouse_sample (samplepos_t& where, bool& in_track_canvas) const { /* gdk_window_get_pointer() has X11's XQueryPointer semantics in that it only - pays attentions to subwindows. this means that menu windows are ignored, and - if the pointer is in a menu, the return window from the call will be the - the regular subwindow *under* the menu. - - this matters quite a lot if the pointer is moving around in a menu that overlaps - the track canvas because we will believe that we are within the track canvas - when we are not. therefore, we track enter/leave events for the track canvas - and allow that to override the result of gdk_window_get_pointer(). + pays attentions to subwindows. this means that menu windows are ignored, and + if the pointer is in a menu, the return window from the call will be the + the regular subwindow *under* the menu. + + this matters quite a lot if the pointer is moving around in a menu that overlaps + the track canvas because we will believe that we are within the track canvas + when we are not. therefore, we track enter/leave events for the track canvas + and allow that to override the result of gdk_window_get_pointer(). */ if (!within_track_canvas) { - return false; + return false; } int x, y; @@ -129,7 +132,7 @@ Editor::mouse_frame (framepos_t& where, bool& in_track_canvas) const return true; } -framepos_t +samplepos_t Editor::window_event_sample (GdkEvent const * event, double* pcx, double* pcy) const { ArdourCanvas::Duple d; @@ -154,7 +157,7 @@ Editor::window_event_sample (GdkEvent const * event, double* pcx, double* pcy) c return pixel_to_sample (d.x); } -framepos_t +samplepos_t Editor::canvas_event_sample (GdkEvent const * event, double* pcx, double* pcy) const { double x; @@ -177,7 +180,7 @@ Editor::canvas_event_sample (GdkEvent const * event, double* pcx, double* pcy) c /* note that pixel_to_sample_from_event() never returns less than zero, so even if the pixel position is negative (as can be the case with motion events in particular), - the frame location is always positive. + the sample location is always positive. */ return pixel_to_sample_from_event (x); @@ -206,18 +209,30 @@ Editor::set_current_movable (boost::shared_ptr m) void Editor::mouse_mode_object_range_toggled() { - MouseMode m = mouse_mode; - - Glib::RefPtr act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-range")); - assert (act); - Glib::RefPtr tact = Glib::RefPtr::cast_dynamic (act); - assert (tact); - - set_mouse_mode(m, true); //call this so the button styles can get updated + set_mouse_mode (mouse_mode, true); /* updates set-mouse-mode-range */ +} + +bool +Editor::snap_mode_button_clicked (GdkEventButton* ev) +{ + if (ev->button != 3) { + cycle_snap_mode(); + return true; + } + + RCOptionEditor* rc_option_editor = ARDOUR_UI::instance()->get_rc_option_editor(); + if (rc_option_editor) { + ARDOUR_UI::instance()->show_tabbable (rc_option_editor); + rc_option_editor->set_current_page (_("Editor/Snap")); + } + + return true; } -static Glib::RefPtr -get_mouse_mode_action(MouseMode m) + + +Glib::RefPtr +Editor::get_mouse_mode_action(MouseMode m) const { switch (m) { case MouseRange: @@ -250,7 +265,8 @@ Editor::set_mouse_mode (MouseMode m, bool force) } if (ARDOUR::Profile->get_mixbus()) { - if ( m == MouseCut) m = MouseObject; + if (m == MouseCut) m = MouseObject; + if (m == MouseAudition) m = MouseRange; } Glib::RefPtr act = get_mouse_mode_action(m); @@ -260,14 +276,15 @@ Editor::set_mouse_mode (MouseMode m, bool force) tact->set_active (false); tact->set_active (true); - //NOTE: this will result in a call to mouse_mode_toggled which does the heavy lifting + /* NOTE: this will result in a call to mouse_mode_toggled which does the heavy lifting */ } void Editor::mouse_mode_toggled (MouseMode m) { if (ARDOUR::Profile->get_mixbus()) { - if ( m == MouseCut) m = MouseObject; + if (m == MouseCut) m = MouseObject; + if (m == MouseAudition) m = MouseRange; } Glib::RefPtr act = get_mouse_mode_action(m); @@ -294,11 +311,14 @@ Editor::mouse_mode_toggled (MouseMode m) /* Switch snap type/mode if we're moving to/from an internal tool. Note this must toggle the actions and not call set_snap_*() directly, otherwise things get out of sync and the combo box stops working. */ - if (!was_internal && internal_editing()) { - snap_type_action(internal_snap_type)->set_active(true); + if (!UIConfiguration::instance().get_grid_follows_internal()) { + grid_type_action(pre_internal_grid_type)->set_active(true); + snap_mode_action(pre_internal_snap_mode)->set_active(true); + } else if (!was_internal && internal_editing()) { + grid_type_action(internal_grid_type)->set_active(true); snap_mode_action(internal_snap_mode)->set_active(true); } else if (was_internal && !internal_editing()) { - snap_type_action(pre_internal_snap_type)->set_active(true); + grid_type_action(pre_internal_grid_type)->set_active(true); snap_mode_action(pre_internal_snap_mode)->set_active(true); } @@ -313,7 +333,7 @@ Editor::mouse_mode_toggled (MouseMode m) } set_gain_envelope_visibility (); - + update_time_selection_display (); update_all_enter_cursors (); @@ -333,12 +353,11 @@ Editor::update_time_selection_display () switch (mouse_mode) { case MouseRange: selection->clear_objects (); - selection->ClearMidiNoteSelection (); /* EMIT SIGNAL */ + selection->clear_midi_notes (); break; case MouseObject: selection->clear_time (); - selection->clear_tracks (); - selection->ClearMidiNoteSelection (); /* EMIT SIGNAL */ + selection->clear_midi_notes (); break; case MouseDraw: /* Clear regions, but not time or tracks, since that @@ -399,8 +418,9 @@ Editor::step_mouse_mode (bool next) } void -Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemType item_type) +Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type) { + /* in object/audition/timefx/gain-automation mode, any button press sets the selection if the object can be selected. this is a bit of hack, because @@ -457,7 +477,9 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp /* almost no selection action on modified button-2 or button-3 events */ - if (item_type != RegionItem && event->button.button != 2) { + if ((item_type != RegionItem && event->button.button != 2) + /* for selection of control points prior to delete (shift-right click) */ + && !(item_type == ControlPointItem && event->button.button == 3 && event->type == GDK_BUTTON_PRESS)) { return; } } @@ -472,6 +494,9 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp switch (item_type) { case RegionItem: + if (eff_mouse_mode == MouseDraw) { + break; + } if (press) { if (eff_mouse_mode != MouseRange) { _mouse_changed_selection = set_selected_regionview_from_click (press, op); @@ -515,7 +540,99 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp /* for object/track exclusivity, we don't call set_selected_track_as_side_effect (op); */ if (eff_mouse_mode != MouseRange) { - _mouse_changed_selection |= set_selected_control_point_from_click (press, op); + if (event->button.button != 3) { + _mouse_changed_selection |= set_selected_control_point_from_click (press, op); + } else { + _mouse_changed_selection |= set_selected_control_point_from_click (press, Selection::Set); + } + } + break; + + case GainLineItem: + if (eff_mouse_mode != MouseRange) { + AutomationLine* argl = reinterpret_cast (item->get_data ("line")); + + std::list selectables; + uint32_t before, after; + samplecnt_t const where = (samplecnt_t) floor (event->button.x * samples_per_pixel) - clicked_regionview->region ()->position (); + + if (!argl || !argl->control_points_adjacent (where, before, after)) { + break; + } + + selectables.push_back (argl->nth (before)); + selectables.push_back (argl->nth (after)); + + switch (op) { + case Selection::Set: + if (press) { + selection->set (selectables); + _mouse_changed_selection = true; + } + break; + case Selection::Add: + if (press) { + selection->add (selectables); + _mouse_changed_selection = true; + } + break; + case Selection::Toggle: + if (press) { + selection->toggle (selectables); + _mouse_changed_selection = true; + } + break; + + case Selection::Extend: + /* XXX */ + break; + } + } + break; + + case AutomationLineItem: + if (eff_mouse_mode != MouseRange) { + AutomationLine* al = reinterpret_cast (item->get_data ("line")); + std::list selectables; + double mx = event->button.x; + double my = event->button.y; + + al->grab_item().canvas_to_item (mx, my); + + uint32_t before, after; + samplecnt_t const where = (samplecnt_t) floor (mx * samples_per_pixel); + + if (!al || !al->control_points_adjacent (where, before, after)) { + break; + } + + selectables.push_back (al->nth (before)); + selectables.push_back (al->nth (after)); + + switch (op) { + case Selection::Set: + if (press) { + selection->set (selectables); + _mouse_changed_selection = true; + } + break; + case Selection::Add: + if (press) { + selection->add (selectables); + _mouse_changed_selection = true; + } + break; + case Selection::Toggle: + if (press) { + selection->toggle (selectables); + _mouse_changed_selection = true; + } + break; + + case Selection::Extend: + /* XXX */ + break; + } } break; @@ -532,7 +649,23 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp break; case AutomationTrackItem: - set_selected_track_as_side_effect (op); + if (eff_mouse_mode != MouseDraw && op == Selection::Set) { + set_selected_track_as_side_effect (op); + } + break; + + case NoteItem: + if (press && event->button.button == 3) { + NoteBase* cnote = reinterpret_cast (item->get_data ("notebase")); + assert (cnote); + if (cnote->region_view().selection_size() == 0 || !cnote->selected()) { + selection->clear_points(); + cnote->region_view().unique_select (cnote); + /* we won't get the release, so store the selection change now */ + begin_reversible_selection_op (X_("Button 3 Note Selection")); + commit_reversible_selection_op (); + } + } break; default: @@ -572,14 +705,25 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT case TempoMarkerItem: { - _drags->set ( - new TempoMarkerDrag ( - this, - item, - Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier) - ), - event - ); + if (ArdourKeyboard::indicates_constraint (event->button.state)) { + _drags->set ( + new TempoEndDrag ( + this, + item + ), + event + ); + } else { + _drags->set ( + new TempoMarkerDrag ( + this, + item, + ArdourKeyboard::indicates_copy (event->button.state) + ), + event + ); + } + return true; } @@ -589,7 +733,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT new MeterMarkerDrag ( this, item, - Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier) + ArdourKeyboard::indicates_copy (event->button.state) ), event ); @@ -603,13 +747,20 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT case MarkerBarItem: case TempoBarItem: + case TempoCurveItem: case MeterBarItem: case TimecodeRulerItem: case SamplesRulerItem: case MinsecRulerItem: case BBTRulerItem: - if (!Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) { + if (!Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier) + && !ArdourKeyboard::indicates_constraint (event->button.state)) { _drags->set (new CursorDrag (this, *playhead_cursor, false), event); + } else if (ArdourKeyboard::indicates_constraint (event->button.state) + && Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) { + _drags->set (new TempoTwistDrag (this, item), event); + } else if (ArdourKeyboard::indicates_constraint (event->button.state)) { + _drags->set (new BBTRulerDrag (this, item), event); } return true; break; @@ -778,7 +929,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT break; case StreamItem: - //in the past, we created a new midi region here, but perhaps that is best left to the Draw mode + /* in the past, we created a new midi region here, but perhaps that is best left to the Draw mode */ break; case AutomationTrackItem: @@ -823,11 +974,14 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT case StartCrossFadeItem: case EndCrossFadeItem: - /* we might allow user to grab inside the fade to trim a region with preserve_fade_anchor. for not this is not fully implemented */ -// if (!clicked_regionview->region()->locked()) { -// _drags->set (new TrimDrag (this, item, clicked_regionview, selection->regions.by_layer(), true), event); -// return true; -// } + /* we might allow user to grab inside the fade to trim a region with preserve_fade_anchor. + * For not this is not fully implemented */ +#if 0 + if (!clicked_regionview->region()->locked()) { + _drags->set (new TrimDrag (this, item, clicked_regionview, selection->regions.by_layer(), true), event); + return true; + } +#endif break; case FeatureLineItem: @@ -851,7 +1005,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT } /* click on a normal region view */ - if (Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier)) { + if (ArdourKeyboard::indicates_copy (event->button.state)) { add_region_copy_drag (item, event, clicked_regionview); } else if (Keyboard::the_keyboard().key_is_down (GDK_b)) { add_region_brush_drag (item, event, clicked_regionview); @@ -920,12 +1074,12 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT _drags->set (new RegionCreateDrag (this, item, parent), event); } else { /* See if there's a region before the click that we can extend, and extend it if so */ - framepos_t const t = canvas_event_sample (event); + samplepos_t const t = canvas_event_sample (event); boost::shared_ptr prev = pl->find_next_region (t, End, -1); if (!prev) { _drags->set (new RegionCreateDrag (this, item, parent), event); } else { - prev->set_length (t - prev->position ()); + prev->set_length (t - prev->position (), get_grid_music_divisions (event->button.state)); } } } else { @@ -963,25 +1117,90 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT break; case SelectionItem: - { - if (dynamic_cast(clicked_regionview) || - dynamic_cast(clicked_regionview)) { - _drags->set (new AutomationRangeDrag (this, clicked_regionview, selection->time), - event, _cursors->up_down); - } else { - double const y = event->button.y; - pair tvp = trackview_by_y_position (y, false); - if (tvp.first) { - AutomationTimeAxisView* atv = dynamic_cast (tvp.first); - if ( atv) { - /* smart "join" mode: drag automation */ - _drags->set (new AutomationRangeDrag (this, atv, selection->time), event, _cursors->up_down); + { + if (selection->time.empty ()) { + /* nothing to do */ + return true; + } + pair tvp = trackview_by_y_position (event->button.y, false); + if (!tvp.first) { + /* clicked outside of a track */ + return true; + } + /* handle automation lanes first */ + AutomationTimeAxisView* atv = dynamic_cast (tvp.first); + if (atv) { + /* smart "join" mode: drag automation */ + _drags->set (new AutomationRangeDrag (this, atv, selection->time), event, _cursors->up_down); + return true; + } + if (dynamic_cast(clicked_regionview)) { + /* MIDI CC or similar -- TODO handle multiple? */ + list rvl; + rvl.push_back (clicked_regionview); + _drags->set (new AutomationRangeDrag (this, rvl, selection->time, + clicked_regionview->get_time_axis_view().y_position(), + clicked_regionview->get_time_axis_view().current_height()), + event, _cursors->up_down); + return true; + } + + /* shift+drag: only apply to clicked_regionview (if any) */ + if (Keyboard::modifier_state_contains (event->button.state, Keyboard::TertiaryModifier)) { + if (dynamic_cast(clicked_regionview) == 0) { + return true; + } + list rvl; + rvl.push_back (clicked_regionview); + // TODO: handle layer_display() == Stacked + _drags->set (new AutomationRangeDrag (this, rvl, selection->time, + clicked_regionview->get_time_axis_view().y_position(), + clicked_regionview->get_time_axis_view().current_height()), + event, _cursors->up_down); + return true; + } + + /* collect all audio regions-views in the given range selection */ + list rvl; + TrackViewList ts = selection->tracks.filter_to_unique_playlists (); + for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) { + RouteTimeAxisView* tatv; + boost::shared_ptr playlist; + if ((tatv = dynamic_cast (*i)) == 0) { + continue; + } + if ((playlist = (*i)->playlist()) == 0) { + continue; + } + if (boost::dynamic_pointer_cast (playlist) == 0) { + continue; + } + for (list::const_iterator j = selection->time.begin(); j != selection->time.end(); ++j) { + boost::shared_ptr rl = playlist->regions_touched (j->start, j->end); + for (RegionList::iterator ir = rl->begin(); ir != rl->end(); ++ir) { + RegionView* rv; + if ((rv = tatv->view()->find_view (*ir)) != 0) { + rvl.push_back (rv); + } + } + } + } + /* region-gain drag */ + if (!rvl.empty ()) { + double y_pos = tvp.first->y_position(); + double height = tvp.first->current_height(); + StreamView* cv = tvp.first->view (); + if (cv->layer_display() == Stacked && cv->layers() > 1) { + height /= cv->layers(); + double yy = event->button.y - _trackview_group->canvas_origin().y; + y_pos += floor ((yy - y_pos) / height) * height; } + _drags->set (new AutomationRangeDrag (this, rvl, selection->time, y_pos, height), + event, _cursors->up_down); } + return true; + break; } - return true; - break; - } case AutomationLineItem: _drags->set (new LineDrag (this, item), event); @@ -1052,7 +1271,7 @@ Editor::button_press_handler_2 (ArdourCanvas::Item* item, GdkEvent* event, ItemT case MouseObject: switch (item_type) { case RegionItem: - if (Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier)) { + if (ArdourKeyboard::indicates_copy (event->button.state)) { add_region_copy_drag (item, event, clicked_regionview); } else { add_region_drag (item, event, clicked_regionview); @@ -1137,11 +1356,23 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp return true; } - //not rolling, range mode click + join_play_range : locate the PH here - if ( !_drags->active () && _session && !_session->transport_rolling() && ( effective_mouse_mode() == MouseRange ) && UIConfiguration::instance().get_follow_edits() ) { - framepos_t where = canvas_event_sample (event); - snap_to(where); - _session->request_locate (where, false); + /* not rolling, effectively in range mode, follow edits enabled (likely + * to start range drag), not in a fade handle (since that means we are + * not starting a range drag): locate the PH here + */ + + if ((item_type != FadeInHandleItem) && + (item_type != FadeOutHandleItem) && + !_drags->active () && + _session && + !_session->transport_rolling() && + (effective_mouse_mode() == MouseRange) && + UIConfiguration::instance().get_follow_edits() && + !_session->config.get_external_sync()) { + + MusicSample where (canvas_event_sample (event), 0); + snap_to (where); + _session->request_locate (where.sample, false); } switch (event->button.button) { @@ -1157,7 +1388,7 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp break; default: - return button_press_dispatch (&event->button); + return button_press_dispatch (&event->button); break; } @@ -1188,7 +1419,7 @@ Editor::button_release_dispatch (GdkEventButton* ev) bool Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type) { - framepos_t where = canvas_event_sample (event); + MusicSample where (canvas_event_sample (event), 0); AutomationTimeAxisView* atv = 0; _press_cursor_ctx.reset(); @@ -1199,24 +1430,24 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT return true; } - bool were_dragging = false; + bool were_dragging = false; if (!Keyboard::is_context_menu_event (&event->button)) { - /* see if we're finishing a drag */ + /* see if we're finishing a drag */ - if (_drags->active ()) { - bool const r = _drags->end_grab (event); - if (r) { - /* grab dragged, so do nothing else */ - return true; - } + if (_drags->active ()) { + bool const r = _drags->end_grab (event); + if (r) { + /* grab dragged, so do nothing else */ + return true; + } - were_dragging = true; - } + were_dragging = true; + } - update_region_layering_order_editor (); - } + update_region_layering_order_editor (); + } /* edit events get handled here */ @@ -1225,21 +1456,20 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT case RegionItem: show_region_properties (); break; - case TempoMarkerItem: { ArdourMarker* marker; TempoMarker* tempo_marker; - + if ((marker = reinterpret_cast (item->get_data ("marker"))) == 0) { fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg; abort(); /*NOTREACHED*/ } - + if ((tempo_marker = dynamic_cast (marker)) == 0) { fatal << _("programming error: marker for tempo is not a tempo marker!") << endmsg; abort(); /*NOTREACHED*/ } - + edit_tempo_marker (*tempo_marker); break; } @@ -1247,12 +1477,12 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT case MeterMarkerItem: { ArdourMarker* marker; MeterMarker* meter_marker; - + if ((marker = reinterpret_cast (item->get_data ("marker"))) == 0) { fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg; abort(); /*NOTREACHED*/ } - + if ((meter_marker = dynamic_cast (marker)) == 0) { fatal << _("programming error: marker for meter is not a meter marker!") << endmsg; abort(); /*NOTREACHED*/ @@ -1320,7 +1550,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT case SelectionItem: popup_track_context_menu (1, event->button.time, item_type, true); break; - + case AutomationTrackItem: popup_track_context_menu (1, event->button.time, item_type, false); break; @@ -1330,13 +1560,14 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT case TransportMarkerBarItem: case CdMarkerBarItem: case TempoBarItem: + case TempoCurveItem: case MeterBarItem: case VideoBarItem: case TimecodeRulerItem: case SamplesRulerItem: case MinsecRulerItem: case BBTRulerItem: - popup_ruler_menu (where, item_type); + popup_ruler_menu (where.sample, item_type); break; case MarkerItem: @@ -1427,28 +1658,28 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT case MarkerBarItem: if (!_dragging_playhead) { - snap_to_with_modifier (where, event, RoundNearest, true); - mouse_add_new_marker (where); + snap_to_with_modifier (where, event, RoundNearest, SnapToGrid_Scaled); + mouse_add_new_marker (where.sample); } return true; case CdMarkerBarItem: if (!_dragging_playhead) { - // if we get here then a dragged range wasn't done - snap_to_with_modifier (where, event, RoundNearest, true); - mouse_add_new_marker (where, true); + /* if we get here then a dragged range wasn't done */ + snap_to_with_modifier (where, event, RoundNearest, SnapToGrid_Scaled); + mouse_add_new_marker (where.sample, true); } return true; - case TempoBarItem: - if (!_dragging_playhead) { + case TempoCurveItem: + if (!_dragging_playhead && Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) { snap_to_with_modifier (where, event); - mouse_add_new_tempo_event (where); + mouse_add_new_tempo_event (where.sample); } return true; case MeterBarItem: - if (!_dragging_playhead) { + if (!_dragging_playhead && Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) { mouse_add_new_meter_event (pixel_to_sample (event->button.x)); } return true; @@ -1487,7 +1718,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT bool with_guard_points = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier); atv = dynamic_cast(clicked_axisview); if (atv) { - atv->add_automation_event (event, where, event->button.y, with_guard_points); + atv->add_automation_event (event, where.sample, event->button.y, with_guard_points); } return true; break; @@ -1518,7 +1749,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT } - /* do any (de)selection operations that should occur on button release */ + /* do any (de)selection operations that should occur on button release */ button_selection (item, event, item_type); return true; @@ -1536,7 +1767,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::ModifierMask (Keyboard::TertiaryModifier|Keyboard::SecondaryModifier))) { lower_region (); } else { - // Button2 click is unused + /* Button2 click is unused */ } return true; @@ -1549,7 +1780,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT case MouseDraw: return true; - + case MouseRange: // x_style_paste (where, 1.0); return true; @@ -1576,8 +1807,10 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ { ControlPoint* cp; ArdourMarker * marker; + MeterMarker* m_marker = 0; + TempoMarker* t_marker = 0; double fraction; - bool ret = true; + bool ret = true; /* by the time we reach here, entered_regionview and entered trackview * will have already been set as appropriate. Things are done this @@ -1590,7 +1823,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ switch (item_type) { case ControlPointItem: - if (mouse_mode == MouseDraw || mouse_mode == MouseObject) { + if (mouse_mode == MouseDraw || mouse_mode == MouseObject || mouse_mode == MouseContent) { cp = static_cast(item->get_data ("control_point")); cp->show (); @@ -1633,9 +1866,30 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ } entered_marker = marker; marker->set_color_rgba (UIConfiguration::instance().color ("entered marker")); - // fall through + break; + case MeterMarkerItem: + if ((m_marker = static_cast (item->get_data ("marker"))) == 0) { + break; + } + entered_marker = m_marker; + if (m_marker->meter().position_lock_style() == MusicTime) { + m_marker->set_color_rgba (UIConfiguration::instance().color ("meter marker")); + } else { + m_marker->set_color_rgba (UIConfiguration::instance().color ("meter marker music")); + } + break; + case TempoMarkerItem: + if ((t_marker = static_cast (item->get_data ("marker"))) == 0) { + break; + } + entered_marker = t_marker; + if (t_marker->tempo().position_lock_style() == MusicTime) { + t_marker->set_color_rgba (UIConfiguration::instance().color ("tempo marker")); + } else { + t_marker->set_color_rgba (UIConfiguration::instance().color ("tempo marker music")); + } break; case FadeInHandleItem: @@ -1710,6 +1964,8 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type) { AutomationLine* al; ArdourMarker *marker; + TempoMarker *t_marker; + MeterMarker *m_marker; Location *loc; bool is_start; bool ret = true; @@ -1742,9 +1998,30 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type) if ((loc = find_location_from_marker (marker, is_start)) != 0) { location_flags_changed (loc); } - // fall through + break; + case MeterMarkerItem: + if ((m_marker = static_cast (item->get_data ("marker"))) == 0) { + break; + } + entered_marker = 0; + if (m_marker->meter().position_lock_style() == MusicTime) { + m_marker->set_color_rgba (UIConfiguration::instance().color ("meter marker music")); + } else { + m_marker->set_color_rgba (UIConfiguration::instance().color ("meter marker")); + } + break; + case TempoMarkerItem: + if ((t_marker = static_cast (item->get_data ("marker"))) == 0) { + break; + } + entered_marker = 0; + if (t_marker->tempo().position_lock_style() == MusicTime) { + t_marker->set_color_rgba (UIConfiguration::instance().color ("tempo marker music")); + } else { + t_marker->set_color_rgba (UIConfiguration::instance().color ("tempo marker")); + } break; case FadeInTrimHandleItem: @@ -1777,13 +2054,13 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type) } void -Editor::scrub (framepos_t frame, double current_x) +Editor::scrub (samplepos_t sample, double current_x) { double delta; if (scrubbing_direction == 0) { /* first move */ - _session->request_locate (frame, false); + _session->request_locate (sample, false); _session->request_transport_speed (0.1); scrubbing_direction = 1; @@ -1880,16 +2157,25 @@ Editor::motion_handler (ArdourCanvas::Item* /*item*/, GdkEvent* event, bool from current_stepping_trackview = 0; step_timeout.disconnect (); } - + if (_session && _session->actively_recording()) { /* Sorry. no dragging stuff around while we record */ return true; } - + update_join_object_range_location (event->motion.y); - + if (_drags->active ()) { + //drags change the snapped_cursor location, because we are snapping the thing being dragged, not the actual mouse cursor return _drags->motion_handler (event, from_autoscroll); + } else { + //the snapped_cursor shows where an operation (like Split) is going to occur + bool ignored; + MusicSample where (0, 0); + if (mouse_sample (where.sample, ignored)) { + snap_to_with_modifier (where, event); + set_snapped_cursor_position (where.sample); + } } return false; @@ -1974,6 +2260,16 @@ Editor::note_edit_done (int r, EditNoteDialog* d) delete d; } +void +Editor::edit_region (RegionView* rv) +{ + if (UIConfiguration::instance().get_use_double_click_to_zoom_to_selection()) { + temporal_zoom_selection (Both); + } else { + rv->show_region_editor (); + } +} + void Editor::visible_order_range (int* low, int* high) const { @@ -1984,7 +2280,7 @@ Editor::visible_order_range (int* low, int* high) const RouteTimeAxisView* rtv = dynamic_cast (*i); - if (!rtv->hidden()) { + if (rtv && !rtv->hidden()) { if (*high < rtv->order()) { *high = rtv->order (); @@ -2005,28 +2301,22 @@ Editor::region_view_item_click (AudioRegionView& rv, GdkEventButton* event) */ if (Keyboard::modifier_state_contains (event->state, Keyboard::PrimaryModifier)) { - TimeAxisView* tv = &rv.get_time_axis_view(); - RouteTimeAxisView* rtv = dynamic_cast(tv); - double speed = 1.0; - if (rtv && rtv->is_track()) { - speed = rtv->track()->speed(); - } - framepos_t where = get_preferred_edit_position(); + samplepos_t where = get_preferred_edit_position(); if (where >= 0) { if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) { - align_region (rv.region(), SyncPoint, (framepos_t) (where * speed)); + align_region (rv.region(), SyncPoint, where); } else if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) { - align_region (rv.region(), End, (framepos_t) (where * speed)); + align_region (rv.region(), End, where); } else { - align_region (rv.region(), Start, (framepos_t) (where * speed)); + align_region (rv.region(), Start, where); } } } @@ -2064,10 +2354,10 @@ Editor::cancel_time_selection () } selection->time.clear (); clicked_selection = 0; -} +} void -Editor::point_trim (GdkEvent* event, framepos_t new_bound) +Editor::point_trim (GdkEvent* event, samplepos_t new_bound) { RegionView* rv = clicked_regionview; @@ -2099,7 +2389,7 @@ Editor::point_trim (GdkEvent* event, framepos_t new_bound) break; case 2: - begin_reversible_command (_("End point trim")); + begin_reversible_command (_("end point trim")); if (selection->selected (rv)) { @@ -2149,7 +2439,7 @@ Editor::mouse_rename_region (ArdourCanvas::Item* /*item*/, GdkEvent* /*event*/) { using namespace Gtkmm2ext; - ArdourPrompter prompter (false); + ArdourWidgets::Prompter prompter (false); prompter.set_prompt (_("Name for region:")); prompter.set_initial_text (clicked_regionview->region()->name()); @@ -2170,25 +2460,12 @@ Editor::mouse_rename_region (ArdourCanvas::Item* /*item*/, GdkEvent* /*event*/) void -Editor::mouse_brush_insert_region (RegionView* rv, framepos_t pos) +Editor::mouse_brush_insert_region (RegionView* rv, samplepos_t pos) { - /* no brushing without a useful snap setting */ - - switch (_snap_mode) { - case SnapMagnetic: - return; /* can't work because it allows region to be placed anywhere */ - default: - break; /* OK */ - } - - switch (_snap_type) { - case SnapToMark: + /* no brushing without a useful quantize setting */ + if (_grid_type == GridTypeNone) return; - default: - break; - } - /* don't brush a copy over the original */ if (pos == rv->region()->position()) { @@ -2197,19 +2474,18 @@ Editor::mouse_brush_insert_region (RegionView* rv, framepos_t pos) RouteTimeAxisView* rtv = dynamic_cast(&rv->get_time_axis_view()); - if (rtv == 0 || !rtv->is_track()) { + if (!rtv || !rtv->is_track()) { return; } boost::shared_ptr playlist = rtv->playlist(); - double speed = rtv->track()->speed(); playlist->clear_changes (); boost::shared_ptr new_region (RegionFactory::create (rv->region(), true)); - playlist->add_region (new_region, (framepos_t) (pos * speed)); + playlist->add_region (new_region, pos); _session->add_command (new StatefulDiffCommand (playlist)); - // playlist is frozen, so we have to update manually XXX this is disgusting + /* playlist is frozen, so we have to update manually XXX this is disgusting */ //playlist->RegionAdded (new_region); /* EMIT SIGNAL */ } @@ -2344,11 +2620,21 @@ Editor::escape () { if (_drags->active ()) { _drags->abort (); - } else { + } else if (_session) { selection->clear (); + + /* if session is playing a range, cancel that */ + if (_session->get_play_range()) { + _session->request_cancel_play_range(); + } + + if (_session->solo_selection_active()) { + StripableList sl; + _session->solo_selection (sl, false); + } } - reset_focus (); + ARDOUR_UI::instance()->reset_focus (&contents()); } /** Update _join_object_range_state which indicate whether we are over the top @@ -2373,6 +2659,11 @@ Editor::update_join_object_range_location (double y) if (entered_regionview) { + /* TODO: there is currently a bug here(?) + * when we are inside a region fade handle, it acts as though we are in range mode because it is in the top half of the region + * can it be fixed here? + */ + ArdourCanvas::Duple const item_space = entered_regionview->get_canvas_group()->canvas_to_item (ArdourCanvas::Duple (0, y)); double const c = item_space.y / entered_regionview->height(); @@ -2386,7 +2677,7 @@ Editor::update_join_object_range_location (double y) } else if (entered_track) { RouteTimeAxisView* entered_route_view = dynamic_cast (entered_track); - + if (entered_route_view) { double cx = 0;