X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor_mouse.cc;h=5fc952481046e382743c3c20cc3dc8d8ea3d1cdd;hb=6c19a776f43b4a9869780e3312764d039a16cd39;hp=de71c4a77f21bb316a4f10250a0a383e75ff652e;hpb=e1f8112f81c655684ec18b881528df9208c00af0;p=ardour.git diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index de71c4a77f..5fc9524810 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -34,7 +34,6 @@ #include "gtkmm2ext/bindings.h" #include "gtkmm2ext/utils.h" -#include "gtkmm2ext/tearoff.h" #include "canvas/canvas.h" @@ -47,8 +46,10 @@ #include "ardour/session.h" #include "ardour/types.h" -#include "ardour_ui.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" @@ -57,9 +58,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" @@ -73,7 +74,7 @@ #include "verbose_cursor.h" #include "note.h" -#include "i18n.h" +#include "pbd/i18n.h" using namespace std; using namespace ARDOUR; @@ -83,21 +84,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; @@ -130,7 +131,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; @@ -155,7 +156,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; @@ -178,7 +179,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); @@ -208,15 +209,34 @@ 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 (m, true); // call this so the button styles can get updated } +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) { @@ -251,7 +271,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); @@ -261,14 +282,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); @@ -295,11 +317,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); } @@ -314,7 +339,7 @@ Editor::mouse_mode_toggled (MouseMode m) } set_gain_envelope_visibility (); - + update_time_selection_display (); update_all_enter_cursors (); @@ -334,22 +359,52 @@ 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 top level objects, but not time or tracks, since that - woulddestroy the range selection rectangle, which we need to stick + /* Clear regions, but not time or tracks, since that + would destroy the range selection rectangle, which we need to stick around for AutomationRangeDrag. */ - selection->clear_objects (); + selection->clear_regions (); + selection->clear_playlists (); + break; + case MouseContent: + /* This handles internal edit. + Clear everything except points and notes. + */ + selection->clear_regions(); + selection->clear_lines(); + selection->clear_playlists (); + + selection->clear_time (); + selection->clear_tracks (); break; + + case MouseTimeFX: + /* We probably want to keep region selection */ + selection->clear_points (); + selection->clear_lines(); + selection->clear_playlists (); + + selection->clear_time (); + selection->clear_tracks (); + break; + + case MouseAudition: + /*Don't lose lines or points if no action in this mode */ + selection->clear_regions (); + selection->clear_playlists (); + selection->clear_time (); + selection->clear_tracks (); + break; + default: - /* Clear everything. */ - selection->clear_objects (); + /*Clear everything */ + selection->clear_objects(); selection->clear_time (); selection->clear_tracks (); break; @@ -369,8 +424,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 @@ -415,7 +471,8 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp if (((mouse_mode != MouseObject) && (mouse_mode != MouseAudition || item_type != RegionItem) && (mouse_mode != MouseTimeFX || item_type != RegionItem) && - (mouse_mode != MouseDraw)) || + (mouse_mode != MouseDraw) && + (mouse_mode != MouseContent || item_type == RegionItem)) || ((event->type != GDK_BUTTON_PRESS && event->type != GDK_BUTTON_RELEASE) || event->button.button > 3)) { return; } @@ -426,7 +483,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; } } @@ -441,6 +500,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); @@ -456,7 +518,7 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp } } else { if (eff_mouse_mode != MouseRange) { - _mouse_changed_selection = set_selected_regionview_from_click (press, op); + _mouse_changed_selection |= set_selected_regionview_from_click (press, op); } } break; @@ -474,16 +536,109 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp case StartCrossFadeItem: case EndCrossFadeItem: if (get_smart_mode() || eff_mouse_mode != MouseRange) { - _mouse_changed_selection = set_selected_regionview_from_click (press, op); + _mouse_changed_selection |= set_selected_regionview_from_click (press, op); } else if (event->type == GDK_BUTTON_PRESS) { set_selected_track_as_side_effect (op); } break; case ControlPointItem: - set_selected_track_as_side_effect (op); + /* for object/track exclusivity, we don't call set_selected_track_as_side_effect (op); */ + + if (eff_mouse_mode != MouseRange) { + 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) { - _mouse_changed_selection = set_selected_control_point_from_click (press, op); + 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; @@ -492,12 +647,31 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp if (event->button.button == 3) { selection->clear_tracks (); set_selected_track_as_side_effect (op); - _mouse_changed_selection = true; + + /* We won't get a release.*/ + begin_reversible_selection_op (X_("Button 3 Menu Select")); + commit_reversible_selection_op (); } 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: @@ -505,7 +679,7 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp } if ((!press) && _mouse_changed_selection) { - begin_reversible_selection_op (_("Button Selection")); + begin_reversible_selection_op (X_("Button Selection")); commit_reversible_selection_op (); _mouse_changed_selection = false; } @@ -537,14 +711,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; } @@ -554,7 +739,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 ); @@ -568,13 +753,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; @@ -630,7 +822,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT Editing::MouseMode eff = effective_mouse_mode (); /* special case: allow drag of region fade in/out in object mode with join object/range enabled */ - if (get_smart_mode()) { + if (get_smart_mode()) { switch (item_type) { case FadeInHandleItem: case FadeInTrimHandleItem: @@ -727,16 +919,23 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT } return true; + case GainLineItem: + _drags->set (new LineDrag (this, item), event); + return true; + break; + case ControlPointItem: _drags->set (new ControlPointDrag (this, item), event); return true; break; + case AutomationLineItem: + _drags->set (new LineDrag (this, item), event); + return true; + break; + case StreamItem: - if (dynamic_cast (clicked_axisview)) { - _drags->set (new RegionCreateDrag (this, item, clicked_axisview), event); - return true; - } + /* in the past, we created a new midi region here, but perhaps that is best left to the Draw mode */ break; case AutomationTrackItem: @@ -781,11 +980,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: @@ -809,7 +1011,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); @@ -878,12 +1080,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 { @@ -931,7 +1133,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT pair tvp = trackview_by_y_position (y, false); if (tvp.first) { AutomationTimeAxisView* atv = dynamic_cast (tvp.first); - if ( atv) { + if (atv) { /* smart "join" mode: drag automation */ _drags->set (new AutomationRangeDrag (this, atv, selection->time), event, _cursors->up_down); } @@ -1010,7 +1212,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); @@ -1064,7 +1266,7 @@ Editor::button_press_handler_2 (ArdourCanvas::Item* item, GdkEvent* event, ItemT return false; } - + bool Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type) { @@ -1095,11 +1297,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->transport_rolling() && ( effective_mouse_mode() == MouseRange ) && ARDOUR_UI::config()->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) { @@ -1115,7 +1329,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; } @@ -1146,7 +1360,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(); @@ -1157,21 +1371,25 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT return true; } - /* see if we're finishing a drag */ - bool were_dragging = false; - if (_drags->active ()) { - bool const r = _drags->end_grab (event); - if (r) { - /* grab dragged, so do nothing else */ - return true; + + if (!Keyboard::is_context_menu_event (&event->button)) { + + /* 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; + } + + were_dragging = true; } - were_dragging = true; + update_region_layering_order_editor (); } - update_region_layering_order_editor (); - /* edit events get handled here */ if (!_drags->active () && Keyboard::is_edit_event (&event->button)) { @@ -1179,34 +1397,33 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT case RegionItem: show_region_properties (); break; - case TempoMarkerItem: { - Marker* marker; + ArdourMarker* marker; TempoMarker* tempo_marker; - - if ((marker = reinterpret_cast (item->get_data ("marker"))) == 0) { + + 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; } case MeterMarkerItem: { - Marker* marker; + ArdourMarker* marker; MeterMarker* meter_marker; - - if ((marker = reinterpret_cast (item->get_data ("marker"))) == 0) { + + 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*/ @@ -1274,7 +1491,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; @@ -1284,13 +1501,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: @@ -1381,28 +1599,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; @@ -1441,7 +1659,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; @@ -1461,7 +1679,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT default: break; } - } else { + } else if (_session) { /* make sure we stop */ _session->request_transport_speed (0.0); } @@ -1472,7 +1690,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; @@ -1490,7 +1708,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; @@ -1503,7 +1721,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; @@ -1529,12 +1747,14 @@ bool Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type) { ControlPoint* cp; - Marker * marker; + 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 + * will have already been set as appropriate. Things are done this * way because this method isn't passed a pointer to a variable type of * thing that is entered (which may or may not be canvas item). * (e.g. the actual entered regionview) @@ -1544,7 +1764,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 (); @@ -1559,7 +1779,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ if (mouse_mode == MouseDraw) { ArdourCanvas::Line *line = dynamic_cast (item); if (line) { - line->set_outline_color (ARDOUR_UI::config()->color ("entered gain line")); + line->set_outline_color (UIConfiguration::instance().color ("entered gain line")); } } break; @@ -1568,7 +1788,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ if (mouse_mode == MouseDraw || mouse_mode == MouseObject) { ArdourCanvas::Line *line = dynamic_cast (item); if (line) { - line->set_outline_color (ARDOUR_UI::config()->color ("entered automation line")); + line->set_outline_color (UIConfiguration::instance().color ("entered automation line")); } } break; @@ -1582,14 +1802,35 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ break; case MarkerItem: - if ((marker = static_cast (item->get_data ("marker"))) == 0) { + if ((marker = static_cast (item->get_data ("marker"))) == 0) { break; } entered_marker = marker; - marker->set_color_rgba (ARDOUR_UI::config()->color ("entered marker")); - // fall through + marker->set_color_rgba (UIConfiguration::instance().color ("entered marker")); + 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: @@ -1624,6 +1865,14 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ case SelectionItem: break; + case WaveItem: + { + if (entered_regionview) { + entered_regionview->entered(); + } + } + break; + default: break; } @@ -1655,7 +1904,9 @@ bool Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type) { AutomationLine* al; - Marker *marker; + ArdourMarker *marker; + TempoMarker *t_marker; + MeterMarker *m_marker; Location *loc; bool is_start; bool ret = true; @@ -1666,7 +1917,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type) switch (item_type) { case ControlPointItem: - _verbose_cursor->hide (); + _verbose_cursor->hide (); break; case GainLineItem: @@ -1681,16 +1932,37 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type) break; case MarkerItem: - if ((marker = static_cast (item->get_data ("marker"))) == 0) { + if ((marker = static_cast (item->get_data ("marker"))) == 0) { break; } entered_marker = 0; 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: @@ -1700,7 +1972,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type) { ArdourCanvas::Rectangle *rect = dynamic_cast (item); if (rect) { - rect->set_fill_color (ARDOUR_UI::config()->color ("inactive fade handle")); + rect->set_fill_color (UIConfiguration::instance().color ("inactive fade handle")); } } break; @@ -1711,7 +1983,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type) case FeatureLineItem: { ArdourCanvas::Line *line = dynamic_cast (item); - line->set_outline_color (ARDOUR_UI::config()->color ("zero line")); + line->set_outline_color (UIConfiguration::instance().color ("zero line")); } break; @@ -1723,13 +1995,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; @@ -1826,16 +2098,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; @@ -1890,7 +2171,6 @@ Editor::edit_control_point (ArdourCanvas::Item* item) } ControlPointDialog d (p); - ensure_float (d); if (d.run () != RESPONSE_ACCEPT) { return; @@ -1910,7 +2190,6 @@ Editor::edit_notes (MidiRegionView* mrv) EditNoteDialog* d = new EditNoteDialog (mrv, s); d->show_all (); - ensure_float (*d); d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &Editor::note_edit_done), d)); } @@ -1922,6 +2201,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 { @@ -1932,7 +2221,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 (); @@ -1954,27 +2243,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); } } } @@ -2012,10 +2296,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; @@ -2047,7 +2331,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)) { @@ -2080,10 +2364,10 @@ Editor::point_trim (GdkEvent* event, framepos_t new_bound) void Editor::hide_marker (ArdourCanvas::Item* item, GdkEvent* /*event*/) { - Marker* marker; + ArdourMarker* marker; bool is_start; - if ((marker = static_cast (item->get_data ("marker"))) == 0) { + if ((marker = static_cast (item->get_data ("marker"))) == 0) { fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg; abort(); /*NOTREACHED*/ } @@ -2097,7 +2381,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()); @@ -2118,25 +2402,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()) { @@ -2145,21 +2416,20 @@ 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 */ + //playlist->RegionAdded (new_region); /* EMIT SIGNAL */ } gint @@ -2221,8 +2491,6 @@ Editor::add_region_brush_drag (ArdourCanvas::Item* item, GdkEvent*, RegionView* } _drags->add (new RegionMoveDrag (this, item, region_view, selection->regions.by_layer(), true, false)); - - begin_reversible_command (Operations::drag_region_brush); } /** Start a grab where a time range is selected, track(s) are selected, and the @@ -2262,7 +2530,6 @@ Editor::start_selection_grab (ArdourCanvas::Item* /*item*/, GdkEvent* event) /* A selection grab currently creates two undo/redo operations, one for creating the new region and another for moving it. */ - begin_reversible_command (Operations::selection_grab); boost::shared_ptr playlist = clicked_axisview->playlist(); @@ -2275,6 +2542,7 @@ Editor::start_selection_grab (ArdourCanvas::Item* /*item*/, GdkEvent* event) if (latest_regionviews.empty()) { /* something went wrong */ + abort_reversible_command (); return; } @@ -2296,9 +2564,19 @@ Editor::escape () _drags->abort (); } else { 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 @@ -2323,6 +2601,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(); @@ -2336,7 +2619,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; @@ -2345,7 +2628,7 @@ Editor::update_join_object_range_location (double y) entered_route_view->canvas_display()->canvas_to_item (cx, cy); double track_height = entered_route_view->view()->child_height(); - if (ARDOUR_UI::config()->get_show_name_highlight()) { + if (UIConfiguration::instance().get_show_name_highlight()) { track_height -= TimeAxisViewItem::NAME_HIGHLIGHT_SIZE; } double const c = cy / track_height;