#include "gtkmm2ext/bindings.h"
#include "gtkmm2ext/utils.h"
-#include "gtkmm2ext/tearoff.h"
#include "canvas/canvas.h"
#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"
#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 "utils.h"
#include "selection.h"
#include "keyboard.h"
#include "editing.h"
#include "verbose_cursor.h"
#include "note.h"
-#include "i18n.h"
+#include "pbd/i18n.h"
using namespace std;
using namespace ARDOUR;
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;
return false;
}
- if (pointer_window != canvas_window && pointer_window != _time_bars_canvas->get_window()) {
+ if (pointer_window != canvas_window) {
in_track_canvas = false;
return false;
}
return true;
}
-framepos_t
+samplepos_t
Editor::window_event_sample (GdkEvent const * event, double* pcx, double* pcy) const
{
- double x;
- double y;
+ ArdourCanvas::Duple d;
- if (!gdk_event_get_coords (event, &x, &y)) {
+ if (!gdk_event_get_coords (event, &d.x, &d.y)) {
return 0;
}
/* event coordinates are in window units, so convert to canvas
- * (i.e. account for scrolling)
*/
- ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (x, y));
+ d = _track_canvas->window_to_canvas (d);
if (pcx) {
*pcx = d.x;
return pixel_to_sample (d.x);
}
-framepos_t
+samplepos_t
Editor::canvas_event_sample (GdkEvent const * event, double* pcx, double* pcy) const
{
double x;
*pcy = y;
}
- /* note that pixel_to_sample() never returns less than zero, so even if the pixel
+ /* 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 (x);
-}
-
-Gdk::Cursor*
-Editor::which_grabber_cursor ()
-{
- Gdk::Cursor* c = _cursors->grabber;
-
- if (_internal_editing) {
- switch (mouse_mode) {
- case MouseDraw:
- c = _cursors->midi_pencil;
- break;
-
- case MouseObject:
- c = _cursors->grabber_note;
- break;
-
- case MouseTimeFX:
- c = _cursors->midi_resize;
- break;
-
- case MouseRange:
- c = _cursors->grabber_note;
- break;
-
- default:
- break;
- }
-
- } else {
-
- switch (_edit_point) {
- case EditAtMouse:
- c = _cursors->grabber_edit_point;
- break;
- default:
- boost::shared_ptr<Movable> m = _movable.lock();
- if (m && m->locked()) {
- c = _cursors->speaker;
- }
- break;
- }
- }
-
- return c;
+ return pixel_to_sample_from_event (x);
}
void
if (!st || st == t) {
_trimmable = t;
- set_canvas_cursor ();
}
}
if (!sm || sm != m) {
_movable = m;
- set_canvas_cursor ();
}
}
void
-Editor::set_canvas_cursor ()
+Editor::mouse_mode_object_range_toggled()
{
- switch (mouse_mode) {
- case MouseRange:
- current_canvas_cursor = _cursors->selector;
- if (_internal_editing) {
- current_canvas_cursor = which_grabber_cursor();
- }
- break;
-
- case MouseObject:
- current_canvas_cursor = which_grabber_cursor();
- break;
-
- case MouseDraw:
- current_canvas_cursor = _cursors->midi_pencil;
- break;
-
- case MouseGain:
- current_canvas_cursor = _cursors->cross_hair;
- break;
-
- case MouseZoom:
- if (Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
- current_canvas_cursor = _cursors->zoom_out;
- } else {
- current_canvas_cursor = _cursors->zoom_in;
- }
- break;
+ MouseMode m = mouse_mode;
- case MouseTimeFX:
- current_canvas_cursor = _cursors->time_fx; // just use playhead
- break;
+ Glib::RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-range"));
+ assert (act);
+ Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
+ assert (tact);
- case MouseAudition:
- current_canvas_cursor = _cursors->speaker;
- break;
- }
+ set_mouse_mode (m, true); // call this so the button styles can get updated
+}
- if (!_internal_editing) {
- switch (_join_object_range_state) {
- case JOIN_OBJECT_RANGE_NONE:
- break;
- case JOIN_OBJECT_RANGE_OBJECT:
- current_canvas_cursor = which_grabber_cursor ();
- break;
- case JOIN_OBJECT_RANGE_RANGE:
- current_canvas_cursor = _cursors->selector;
- break;
- }
+bool
+Editor::snap_mode_button_clicked (GdkEventButton* ev)
+{
+ if (ev->button != 3) {
+ cycle_snap_mode();
+ return true;
}
- /* up-down cursor as a cue that automation can be dragged up and down when in join object/range mode */
- if (!_internal_editing && get_smart_mode() ) {
-
- double x, y;
- get_pointer_position (x, y);
-
- if (x >= 0 && y >= 0) {
-
- vector<ArdourCanvas::Item const *> items;
-
- _track_canvas->root()->add_items_at_point (ArdourCanvas::Duple (x,y), items);
-
- // first item will be the upper most
-
- if (!items.empty()) {
- const ArdourCanvas::Item* i = items.front();
-
- if (i && i->parent() && i->parent()->get_data (X_("timeselection"))) {
- pair<TimeAxisView*, int> tvp = trackview_by_y_position (_last_motion_y);
- if (dynamic_cast<AutomationTimeAxisView*> (tvp.first)) {
- current_canvas_cursor = _cursors->up_down;
- }
- }
- }
- }
+ 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"));
}
- set_canvas_cursor (current_canvas_cursor, true);
+ return true;
}
-void
-Editor::mouse_mode_object_range_toggled()
-{
- MouseMode m = mouse_mode;
-
- Glib::RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-range"));
- assert (act);
- Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
- assert (tact);
- if (tact->get_active()) {
- m = MouseObject; //Smart mode turned to ON, force editing to Object mode
- }
- set_mouse_mode(m, true); //call this so the button styles can get updated
+Glib::RefPtr<Action>
+Editor::get_mouse_mode_action(MouseMode m) const
+{
+ switch (m) {
+ case MouseRange:
+ return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-range"));
+ case MouseObject:
+ return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object"));
+ case MouseCut:
+ return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-cut"));
+ case MouseDraw:
+ return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-draw"));
+ case MouseTimeFX:
+ return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-timefx"));
+ case MouseContent:
+ return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-content"));
+ case MouseAudition:
+ return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-audition"));
+ }
+ return Glib::RefPtr<Action>();
}
void
return;
}
- Glib::RefPtr<Action> act;
-
- switch (m) {
- case MouseRange:
- act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-range"));
- break;
-
- case MouseObject:
- act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object"));
- break;
-
- case MouseDraw:
- act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-draw"));
- break;
-
- case MouseGain:
- act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-gain"));
- break;
-
- case MouseZoom:
- act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-zoom"));
- break;
-
- case MouseTimeFX:
- act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-timefx"));
- break;
-
- case MouseAudition:
- act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-audition"));
- break;
+ if (ARDOUR::Profile->get_mixbus()) {
+ if (m == MouseCut) m = MouseObject;
+ if (m == MouseAudition) m = MouseRange;
}
- assert (act);
-
- Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
- assert (tact);
+ Glib::RefPtr<Action> act = get_mouse_mode_action(m);
+ Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
/* go there and back to ensure that the toggled handler is called to set up mouse_mode */
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)
{
- Glib::RefPtr<Action> act;
- Glib::RefPtr<ToggleAction> tact;
-
- switch (m) {
- case MouseRange:
- act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-range"));
- break;
-
- case MouseObject:
- act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object"));
- break;
-
- case MouseDraw:
- act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-draw"));
- break;
-
- case MouseGain:
- act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-gain"));
- break;
-
- case MouseZoom:
- act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-zoom"));
- break;
-
- case MouseTimeFX:
- act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-timefx"));
- break;
-
- case MouseAudition:
- act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-audition"));
- break;
+ if (ARDOUR::Profile->get_mixbus()) {
+ if (m == MouseCut) m = MouseObject;
+ if (m == MouseAudition) m = MouseRange;
}
- assert (act);
-
- tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
- assert (tact);
+ Glib::RefPtr<Action> act = get_mouse_mode_action(m);
+ Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
if (!tact->get_active()) {
/* this was just the notification that the old mode has been
return;
}
- switch (m) {
- case MouseDraw:
- act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
- tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
- tact->set_active (true);
- break;
- default:
- break;
- }
-
if (_session && mouse_mode == MouseAudition) {
/* stop transport and reset default speed to avoid oddness with
auditioning */
_session->request_transport_speed (0.0, true);
}
+ const bool was_internal = internal_editing();
+
mouse_mode = 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 (!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()) {
+ grid_type_action(pre_internal_grid_type)->set_active(true);
+ snap_mode_action(pre_internal_snap_mode)->set_active(true);
+ }
+
instant_save ();
- //TODO: set button styles for smart buttons
-/*
- if ( smart_mode_action->get_active() ) {
- if( mouse_mode == MouseObject ) { //smart active and object active
- smart_mode_button.set_active(1);
- smart_mode_button.set_name("smart mode button");
- mouse_move_button.set_name("smart mode button");
- } else { //smart active but object inactive
- smart_mode_button.set_active(0);
- smart_mode_button.set_name("smart mode button");
- mouse_move_button.set_name("mouse mode button");
- }
- } else {
- smart_mode_button.set_active(0);
- smart_mode_button.set_name("mouse mode button");
- mouse_move_button.set_name("mouse mode button");
+ /* this should generate a new enter event which will
+ trigger the appropiate cursor.
+ */
+
+ if (_track_canvas) {
+ _track_canvas->re_enter ();
}
-*/
-
- set_canvas_cursor ();
+
set_gain_envelope_visibility ();
-
+
update_time_selection_display ();
+ update_all_enter_cursors ();
+
MouseModeChanged (); /* EMIT SIGNAL */
}
-void
-Editor::update_time_selection_display ()
+bool
+Editor::internal_editing() const
{
- if (smart_mode_action->get_active()) {
- /* not sure what to do here */
- if (mouse_mode == MouseObject) {
- } else {
- }
- } else {
- switch (mouse_mode) {
- case MouseRange:
- selection->clear_objects ();
- break;
- default:
- selection->clear_time ();
- break;
- }
- }
+ return mouse_mode == Editing::MouseContent || mouse_mode == Editing::MouseDraw;
}
void
-Editor::step_mouse_mode (bool next)
+Editor::update_time_selection_display ()
{
- switch (current_mouse_mode()) {
- case MouseObject:
- if (next) {
- if (Profile->get_sae()) {
- set_mouse_mode (MouseZoom);
- } else {
- set_mouse_mode (MouseRange);
- }
- } else {
- set_mouse_mode (MouseTimeFX);
- }
- break;
-
+ switch (mouse_mode) {
case MouseRange:
- if (next) set_mouse_mode (MouseDraw);
- else set_mouse_mode (MouseObject);
+ selection->clear_objects ();
+ selection->clear_midi_notes ();
break;
-
- case MouseDraw:
- if (next) set_mouse_mode (MouseZoom);
- else set_mouse_mode (MouseRange);
- break;
-
- case MouseZoom:
- if (next) {
- if (Profile->get_sae()) {
- set_mouse_mode (MouseTimeFX);
- } else {
- set_mouse_mode (MouseGain);
- }
- } else {
- if (Profile->get_sae()) {
- set_mouse_mode (MouseObject);
- } else {
- set_mouse_mode (MouseDraw);
- }
- }
+ case MouseObject:
+ selection->clear_time ();
+ selection->clear_midi_notes ();
break;
+ case MouseDraw:
+ /* 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_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 ();
- case MouseGain:
- if (next) set_mouse_mode (MouseTimeFX);
- else set_mouse_mode (MouseZoom);
+ selection->clear_time ();
+ selection->clear_tracks ();
break;
case MouseTimeFX:
- if (next) {
- set_mouse_mode (MouseAudition);
- } else {
- if (Profile->get_sae()) {
- set_mouse_mode (MouseZoom);
- } else {
- set_mouse_mode (MouseGain);
- }
- }
+ /* 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:
- if (next) set_mouse_mode (MouseObject);
- else set_mouse_mode (MouseTimeFX);
+ /*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();
+ selection->clear_time ();
+ selection->clear_tracks ();
break;
}
}
-bool
-Editor::toggle_internal_editing_from_double_click (GdkEvent* event)
+void
+Editor::step_mouse_mode (bool next)
{
- if (_drags->active()) {
- _drags->end_grab (event);
- }
-
- ActionManager::do_action ("MouseMode", "toggle-internal-edit");
-
- /* prevent reversion of edit cursor on button release */
-
- pre_press_cursor = 0;
-
- return true;
+ const int n_mouse_modes = (int)MouseContent + 1;
+ int current = (int)current_mouse_mode();
+ if (next) {
+ set_mouse_mode((MouseMode)((current + 1) % n_mouse_modes));
+ } else {
+ set_mouse_mode((MouseMode)((current + n_mouse_modes - 1) % n_mouse_modes));
+ }
}
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
to cut notes or regions.
*/
- MouseMode eff_mouse_mode = mouse_mode;
+ MouseMode eff_mouse_mode = effective_mouse_mode ();
+
+ if (eff_mouse_mode == MouseCut) {
+ /* never change selection in cut mode */
+ return;
+ }
if (get_smart_mode() && eff_mouse_mode == MouseRange && event->button.button == 3 && item_type == RegionItem) {
/* context clicks are always about object properties, even if
eff_mouse_mode = MouseObject;
}
+ /* special case: allow drag of region fade in/out in object mode with join object/range enabled */
+ if (get_smart_mode()) {
+ switch (item_type) {
+ case FadeInHandleItem:
+ case FadeInTrimHandleItem:
+ case FadeOutHandleItem:
+ case FadeOutTrimHandleItem:
+ eff_mouse_mode = MouseObject;
+ break;
+ default:
+ break;
+ }
+ }
+
if (((mouse_mode != MouseObject) &&
(mouse_mode != MouseAudition || item_type != RegionItem) &&
(mouse_mode != MouseTimeFX || item_type != RegionItem) &&
- (mouse_mode != MouseGain) &&
- (mouse_mode != MouseDraw)) ||
- ((event->type != GDK_BUTTON_PRESS && event->type != GDK_BUTTON_RELEASE) || event->button.button > 3) ||
- (internal_editing() && mouse_mode != MouseTimeFX)) {
-
+ (mouse_mode != MouseDraw) &&
+ (mouse_mode != MouseContent || item_type == RegionItem)) ||
+ ((event->type != GDK_BUTTON_PRESS && event->type != GDK_BUTTON_RELEASE) || event->button.button > 3)) {
return;
}
/* 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;
}
}
Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
bool press = (event->type == GDK_BUTTON_PRESS);
+ if (press) {
+ _mouse_changed_selection = false;
+ }
+
switch (item_type) {
case RegionItem:
+ if (eff_mouse_mode == MouseDraw) {
+ break;
+ }
if (press) {
if (eff_mouse_mode != MouseRange) {
- set_selected_regionview_from_click (press, op);
+ _mouse_changed_selection = set_selected_regionview_from_click (press, op);
} else {
/* don't change the selection unless the
clicked track is not currently selected. if
}
} else {
if (eff_mouse_mode != MouseRange) {
- set_selected_regionview_from_click (press, op);
+ _mouse_changed_selection |= set_selected_regionview_from_click (press, op);
}
}
break;
case RegionViewName:
case LeftFrameHandle:
case RightFrameHandle:
- if (eff_mouse_mode != MouseRange) {
- set_selected_regionview_from_click (press, op);
- } else if (event->type == GDK_BUTTON_PRESS) {
- set_selected_track_as_side_effect (op);
- }
- break;
-
case FadeInHandleItem:
+ case FadeInTrimHandleItem:
case FadeInItem:
case FadeOutHandleItem:
+ case FadeOutTrimHandleItem:
case FadeOutItem:
case StartCrossFadeItem:
case EndCrossFadeItem:
- if (eff_mouse_mode != MouseRange) {
- cerr << "Should be setting selected regionview\n";
- set_selected_regionview_from_click (press, op);
+ if (get_smart_mode() || eff_mouse_mode != MouseRange) {
+ _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<AutomationLine*> (item->get_data ("line"));
+
+ std::list<Selectable*> 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) {
- set_selected_control_point_from_click (press, op);
+ AutomationLine* al = reinterpret_cast<AutomationLine*> (item->get_data ("line"));
+ std::list<Selectable*> 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;
if (event->button.button == 3) {
selection->clear_tracks ();
set_selected_track_as_side_effect (op);
+
+ /* We won't get a release.*/
+ begin_reversible_selection_op (X_("Button 3 Menu Select"));
+ commit_reversible_selection_op ();
+ }
+ break;
+
+ case AutomationTrackItem:
+ if (eff_mouse_mode != MouseDraw && op == Selection::Set) {
+ set_selected_track_as_side_effect (op);
}
break;
- case AutomationTrackItem:
- set_selected_track_as_side_effect (op);
+ case NoteItem:
+ if (press && event->button.button == 3) {
+ NoteBase* cnote = reinterpret_cast<NoteBase*> (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:
break;
}
+
+ if ((!press) && _mouse_changed_selection) {
+ begin_reversible_selection_op (X_("Button Selection"));
+ commit_reversible_selection_op ();
+ _mouse_changed_selection = false;
+ }
}
bool
them to be modeless.
*/
+ NoteBase* note = NULL;
+
switch (item_type) {
case PlayheadCursorItem:
_drags->set (new CursorDrag (this, *playhead_cursor, true), event);
case TempoMarkerItem:
{
- TempoMarker* m = reinterpret_cast<TempoMarker*> (item->get_data ("marker"));
- assert (m);
- _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;
}
case MeterMarkerItem:
{
- MeterMarker* m = reinterpret_cast<MeterMarker*> (item->get_data ("marker"));
- assert (m);
_drags->set (
new MeterMarkerDrag (
this,
item,
- Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier)
+ ArdourKeyboard::indicates_copy (event->button.state)
),
event
);
case MarkerBarItem:
case TempoBarItem:
+ case TempoCurveItem:
case MeterBarItem:
- if (!Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
+ case TimecodeRulerItem:
+ case SamplesRulerItem:
+ case MinsecRulerItem:
+ case BBTRulerItem:
+ 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;
case RangeMarkerBarItem:
- if (!Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
- _drags->set (new CursorDrag (this, *playhead_cursor, false), event);
- } else {
+ if (Keyboard::modifier_state_contains (event->button.state, Keyboard::TertiaryModifier)) {
+ _drags->set (new RangeMarkerBarDrag (this, item, RangeMarkerBarDrag::CreateSkipMarker), event);
+ } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
_drags->set (new RangeMarkerBarDrag (this, item, RangeMarkerBarDrag::CreateRangeMarker), event);
+ } else {
+ _drags->set (new CursorDrag (this, *playhead_cursor, false), event);
}
return true;
break;
Editing::MouseMode eff = effective_mouse_mode ();
/* special case: allow drag of region fade in/out in object mode with join object/range enabled */
- if (item_type == FadeInHandleItem || item_type == FadeOutHandleItem) {
- eff = MouseObject;
- }
-
- /* there is no Range mode when in internal edit mode */
- if (eff == MouseRange && internal_editing()) {
- eff = MouseObject;
+ if (get_smart_mode()) {
+ switch (item_type) {
+ case FadeInHandleItem:
+ case FadeInTrimHandleItem:
+ case FadeOutHandleItem:
+ case FadeOutTrimHandleItem:
+ eff = MouseObject;
+ break;
+ default:
+ break;
+ }
}
switch (eff) {
/* grab selection for moving */
_drags->set (new SelectionDrag (this, item, SelectionDrag::SelectionMove), event);
} else {
- double const y = event->button.y;
- pair<TimeAxisView*, int> tvp = trackview_by_y_position (y);
- if (tvp.first) {
- AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*> (tvp.first);
- if ( get_smart_mode() && atv) {
- /* smart "join" mode: drag automation */
- _drags->set (new AutomationRangeDrag (this, atv, selection->time), event, _cursors->up_down);
- } else {
- /* this was debated, but decided the more common action was to
- make a new selection */
- _drags->set (new SelectionDrag (this, item, SelectionDrag::CreateSelection), event);
- }
- }
+ /* this was debated, but decided the more common action was to
+ make a new selection */
+ _drags->set (new SelectionDrag (this, item, SelectionDrag::CreateSelection), event);
}
break;
case StreamItem:
- if (internal_editing()) {
- if (dynamic_cast<MidiTimeAxisView*> (clicked_axisview)) {
- _drags->set (new RegionCreateDrag (this, item, clicked_axisview), event);
- return true;
- }
+ if (Keyboard::modifier_state_equals (event->button.state, Keyboard::RangeSelectModifier)) {
+ _drags->set (new SelectionDrag (this, item, SelectionDrag::SelectionExtend), event);
} else {
- if (Keyboard::modifier_state_equals (event->button.state, Keyboard::RangeSelectModifier)) {
- _drags->set (new SelectionDrag (this, item, SelectionDrag::SelectionExtend), event);
- } else {
- _drags->set (new SelectionDrag (this, item, SelectionDrag::CreateSelection), event);
- }
- return true;
+ _drags->set (new SelectionDrag (this, item, SelectionDrag::CreateSelection), event);
}
+ return true;
break;
case RegionViewNameHighlight:
break;
default:
- if (!internal_editing()) {
- if (Keyboard::modifier_state_equals (event->button.state, Keyboard::RangeSelectModifier)) {
- _drags->set (new SelectionDrag (this, item, SelectionDrag::SelectionExtend), event);
- } else {
- _drags->set (new SelectionDrag (this, item, SelectionDrag::CreateSelection), event);
- }
+ if (Keyboard::modifier_state_equals (event->button.state, Keyboard::RangeSelectModifier)) {
+ _drags->set (new SelectionDrag (this, item, SelectionDrag::SelectionExtend), event);
+ } else {
+ _drags->set (new SelectionDrag (this, item, SelectionDrag::CreateSelection), event);
}
}
return true;
break;
- case MouseDraw:
+ case MouseCut:
switch (item_type) {
- case NoteItem:
- /* Existing note: allow trimming/motion */
- if (internal_editing()) {
- /* trim notes if we're in internal edit mode and near the ends of the note */
- NoteBase* cn = reinterpret_cast<NoteBase*>(item->get_data ("notebase"));
- assert (cn);
- if (cn->big_enough_to_trim() && cn->mouse_near_ends()) {
- _drags->set (new NoteResizeDrag (this, item), event, current_canvas_cursor);
- } else {
- _drags->set (new NoteDrag (this, item), event);
- }
- return true;
- }
- break;
+ case RegionItem:
+ case FadeInHandleItem:
+ case FadeOutHandleItem:
+ case LeftFrameHandle:
+ case RightFrameHandle:
+ case FeatureLineItem:
+ case RegionViewNameHighlight:
+ case RegionViewName:
case StreamItem:
- if (internal_editing()) {
- if (dynamic_cast<MidiTimeAxisView*> (clicked_axisview)) {
- _drags->set (new RegionCreateDrag (this, item, clicked_axisview), event);
- }
- return true;
- }
+ case AutomationTrackItem:
+ _drags->set (new RegionCutDrag (this, item, canvas_event_sample (event)), event, get_canvas_cursor());
+ return true;
break;
-
default:
break;
}
break;
- case MouseObject:
+ case MouseContent:
switch (item_type) {
case NoteItem:
/* Existing note: allow trimming/motion */
- if (internal_editing()) {
- NoteBase* cn = reinterpret_cast<NoteBase*> (item->get_data ("notebase"));
- assert (cn);
- if (cn->big_enough_to_trim() && cn->mouse_near_ends()) {
- _drags->set (new NoteResizeDrag (this, item), event, current_canvas_cursor);
+ if ((note = reinterpret_cast<NoteBase*> (item->get_data ("notebase")))) {
+ if (note->big_enough_to_trim() && note->mouse_near_ends()) {
+ _drags->set (new NoteResizeDrag (this, item), event, get_canvas_cursor());
} else {
_drags->set (new NoteDrag (this, item), event);
}
+ }
+ 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:
+ /* in the past, we created a new midi region here, but perhaps that is best left to the Draw mode */
+ break;
+
+ case AutomationTrackItem:
+ /* rubberband drag to select automation points */
+ _drags->set (new EditorRubberbandSelectDrag (this, item), event);
+ return true;
+ break;
+
+ case RegionItem:
+ if (dynamic_cast<AutomationRegionView*>(clicked_regionview)) {
+ /* rubberband drag to select automation points */
+ _drags->set (new EditorRubberbandSelectDrag (this, item), event);
return true;
}
break;
default:
break;
}
+ break;
+ case MouseObject:
if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)) &&
event->type == GDK_BUTTON_PRESS) {
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:
break;
}
- if (internal_editing ()) {
- break;
- }
-
/* 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);
}
-// if (!internal_editing() && (_join_object_range_state == JOIN_OBJECT_RANGE_RANGE && !selection->regions.empty())) {
-// _drags->add (new SelectionDrag (this, clicked_axisview->get_selection_rect (clicked_selection)->rect, SelectionDrag::SelectionMove));
-// }
-
_drags->start_grab (event);
return true;
break;
case RegionViewNameHighlight:
case LeftFrameHandle:
- case RightFrameHandle:
+ case RightFrameHandle:
if (!clicked_regionview->region()->locked()) {
_drags->set (new TrimDrag (this, item, clicked_regionview, selection->regions.by_layer()), event);
return true;
}
break;
+ case FadeInTrimHandleItem:
+ case FadeOutTrimHandleItem:
+ if (!clicked_regionview->region()->locked()) {
+ _drags->set (new TrimDrag (this, item, clicked_regionview, selection->regions.by_layer(), true), event);
+ return true;
+ }
+ break;
+
case RegionViewName:
{
/* rename happens on edit clicks */
- _drags->set (new TrimDrag (this, clicked_regionview->get_name_highlight(), clicked_regionview, selection->regions.by_layer()), event);
- return true;
+ if (clicked_regionview->get_name_highlight()) {
+ _drags->set (new TrimDrag (this, clicked_regionview->get_name_highlight(), clicked_regionview, selection->regions.by_layer()), event);
+ return true;
+ }
break;
}
break;
case StreamItem:
- if (internal_editing()) {
- if (dynamic_cast<MidiTimeAxisView*> (clicked_axisview)) {
- _drags->set (new RegionCreateDrag (this, item, clicked_axisview), event);
- }
- return true;
- } else {
- _drags->set (new EditorRubberbandSelectDrag (this, item), event);
- }
- break;
+ _drags->set (new EditorRubberbandSelectDrag (this, item), event);
+ return true;
case AutomationTrackItem:
{
_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<Region> 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 {
case SelectionItem:
{
- if ( get_smart_mode() ) {
- /* we're in "smart" joined mode, and we've clicked on a Selection */
- double const y = event->button.y;
- pair<TimeAxisView*, int> tvp = trackview_by_y_position (y);
- if (tvp.first) {
- /* if we're over an automation track, start a drag of its data */
- AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*> (tvp.first);
- if (atv) {
- _drags->set (new AutomationRangeDrag (this, atv, selection->time), event, _cursors->up_down);
- }
-
- /* if we're over a track and a region, and in the `object' part of a region,
- put a selection around the region and drag both
- */
-/* RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
- if (rtv && _join_object_range_state == JOIN_OBJECT_RANGE_OBJECT) {
- boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (rtv->route ());
- if (t) {
- boost::shared_ptr<Playlist> pl = t->playlist ();
- if (pl) {
-
- boost::shared_ptr<Region> r = pl->top_region_at (canvas_event_sample (event));
- if (r) {
- RegionView* rv = rtv->view()->find_view (r);
- clicked_selection = select_range (rv->region()->position(),
- rv->region()->last_frame()+1);
- _drags->add (new SelectionDrag (this, item, SelectionDrag::SelectionMove));
- list<RegionView*> rvs;
- rvs.push_back (rv);
- _drags->add (new RegionMoveDrag (this, item, rv, rvs, false, false));
- _drags->start_grab (event);
- return true;
- }
- }
- }
- }
-*/
- }
- }
break;
}
return true;
break;
- case MouseGain:
+ case MouseDraw:
switch (item_type) {
case GainLineItem:
_drags->set (new LineDrag (this, item), event);
case SelectionItem:
{
- AudioRegionView* arv = dynamic_cast<AudioRegionView *> (clicked_regionview);
- if (arv) {
- _drags->set (new AutomationRangeDrag (this, arv, selection->time), event, _cursors->up_down);
- _drags->start_grab (event);
+ if (dynamic_cast<AudioRegionView*>(clicked_regionview) ||
+ dynamic_cast<AutomationRegionView*>(clicked_regionview)) {
+ _drags->set (new AutomationRangeDrag (this, clicked_regionview, selection->time),
+ event, _cursors->up_down);
+ } else {
+ double const y = event->button.y;
+ pair<TimeAxisView*, int> tvp = trackview_by_y_position (y, false);
+ if (tvp.first) {
+ AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*> (tvp.first);
+ if (atv) {
+ /* smart "join" mode: drag automation */
+ _drags->set (new AutomationRangeDrag (this, atv, selection->time), event, _cursors->up_down);
+ }
+ }
}
return true;
break;
case AutomationLineItem:
_drags->set (new LineDrag (this, item), event);
break;
-
+
+ case NoteItem:
+ if ((note = reinterpret_cast<NoteBase*>(item->get_data ("notebase")))) {
+ if (note->big_enough_to_trim() && note->mouse_near_ends()) {
+ /* Note is big and pointer is near the end, trim */
+ _drags->set (new NoteResizeDrag (this, item), event, get_canvas_cursor());
+ } else {
+ /* Drag note */
+ _drags->set (new NoteDrag (this, item), event);
+ }
+ return true;
+ }
+ return true;
+
+ case StreamItem:
+ if (dynamic_cast<MidiTimeAxisView*> (clicked_axisview)) {
+ _drags->set (new RegionCreateDrag (this, item, clicked_axisview), event);
+ }
+ return true;
+
default:
break;
}
return true;
break;
- case MouseZoom:
- if (event->type == GDK_BUTTON_PRESS) {
- _drags->set (new MouseZoomDrag (this, item), event);
- }
-
- return true;
- break;
-
case MouseTimeFX:
- if (internal_editing() && item_type == NoteItem ) {
- /* drag notes if we're in internal edit mode */
- NoteBase* cn = reinterpret_cast<NoteBase*>(item->get_data ("notebase"));
- assert (cn);
- if (cn->big_enough_to_trim()) {
- _drags->set (new NoteResizeDrag (this, item), event, current_canvas_cursor);
+ if (item_type == NoteItem) {
+ /* resize-drag notes */
+ if ((note = reinterpret_cast<NoteBase*>(item->get_data ("notebase")))) {
+ if (note->big_enough_to_trim()) {
+ _drags->set (new NoteResizeDrag (this, item), event, get_canvas_cursor());
+ }
}
return true;
} else if (clicked_regionview) {
break;
case MouseAudition:
- _drags->set (new ScrubDrag (this, item), event);
+ _drags->set (new ScrubDrag (this, item), event, _cursors->transparent);
scrub_reversals = 0;
scrub_reverse_distance = 0;
last_scrub_x = event->button.x;
scrubbing_direction = 0;
- set_canvas_cursor (_cursors->transparent);
return true;
break;
case MouseObject:
switch (item_type) {
case RegionItem:
- if (internal_editing ()) {
- /* no region drags in internal edit mode */
- return false;
- }
-
- 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);
switch (item_type) {
case RegionViewNameHighlight:
- _drags->set (new TrimDrag (this, item, clicked_regionview, selection->regions.by_layer()), event);
- return true;
- break;
+ _drags->set (new TrimDrag (this, item, clicked_regionview, selection->regions.by_layer()), event);
+ return true;
+ break;
- case LeftFrameHandle:
- case RightFrameHandle:
- if (!internal_editing ()) {
- _drags->set (new TrimDrag (this, item, clicked_regionview, selection->regions.by_layer()), event);
- }
+ case LeftFrameHandle:
+ case RightFrameHandle:
+ _drags->set (new TrimDrag (this, item, clicked_regionview, selection->regions.by_layer()), event);
return true;
break;
return true;
break;
-
- case MouseZoom:
- if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
- temporal_zoom_to_frame (false, canvas_event_sample (event));
- } else {
- temporal_zoom_to_frame (true, canvas_event_sample(event));
- }
- return true;
- break;
-
default:
break;
}
return false;
}
-
+
bool
Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
{
return false;
}
- Glib::RefPtr<Gdk::Window> canvas_window = const_cast<Editor*>(this)->_track_canvas_viewport->get_window();
-
- if (canvas_window) {
- Glib::RefPtr<const Gdk::Window> pointer_window;
- int x, y;
- double wx, wy;
- Gdk::ModifierType mask;
-
- pointer_window = canvas_window->get_pointer (x, y, mask);
-
- if (pointer_window == _track_canvas->get_window()) {
- _track_canvas->window_to_canvas (x, y, wx, wy);
- }
- }
-
- pre_press_cursor = current_canvas_cursor;
-
_track_canvas->grab_focus();
if (_session && _session->actively_recording()) {
return true;
}
- if (internal_editing()) {
- bool leave_internal_edit_mode = false;
-
- switch (item_type) {
- case NoteItem:
- break;
-
- case RegionItem:
- if (!dynamic_cast<MidiRegionView*> (clicked_regionview) && !dynamic_cast<AutomationRegionView*> (clicked_regionview)) {
- leave_internal_edit_mode = true;
- }
- break;
-
- case PlayheadCursorItem:
- case MarkerItem:
- case TempoMarkerItem:
- case MeterMarkerItem:
- case MarkerBarItem:
- case TempoBarItem:
- case MeterBarItem:
- case RangeMarkerBarItem:
- case CdMarkerBarItem:
- case TransportMarkerBarItem:
- case StreamItem:
- /* button press on these events never does anything to
- change the editing mode.
- */
- break;
-
- default:
- break;
- }
-
- if (leave_internal_edit_mode) {
- ActionManager::do_action ("MouseMode", "toggle-internal-edit");
- }
- }
-
button_selection (item, event, item_type);
if (!_drags->active () &&
return true;
}
- //not rolling, range mode click + join_play_range : locate the PH here
- if ( !_drags->active () && !_session->transport_rolling() && ( effective_mouse_mode() == MouseRange ) && Config->get_always_play_range() ) {
- 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) {
break;
default:
- return button_press_dispatch (&event->button);
+ return button_press_dispatch (&event->button);
break;
}
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;
- if (pre_press_cursor) {
- set_canvas_cursor (pre_press_cursor);
- pre_press_cursor = 0;
- }
+ _press_cursor_ctx.reset();
/* no action if we're recording */
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)) {
case RegionItem:
show_region_properties ();
break;
-
case TempoMarkerItem: {
- Marker* marker;
+ ArdourMarker* marker;
TempoMarker* tempo_marker;
-
- if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
+
+ if ((marker = reinterpret_cast<ArdourMarker *> (item->get_data ("marker"))) == 0) {
fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg;
- /*NOTREACHED*/
+ abort(); /*NOTREACHED*/
}
-
+
if ((tempo_marker = dynamic_cast<TempoMarker*> (marker)) == 0) {
fatal << _("programming error: marker for tempo is not a tempo marker!") << endmsg;
- /*NOTREACHED*/
+ abort(); /*NOTREACHED*/
}
-
+
edit_tempo_marker (*tempo_marker);
break;
}
case MeterMarkerItem: {
- Marker* marker;
+ ArdourMarker* marker;
MeterMarker* meter_marker;
-
- if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
+
+ if ((marker = reinterpret_cast<ArdourMarker *> (item->get_data ("marker"))) == 0) {
fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg;
- /*NOTREACHED*/
+ abort(); /*NOTREACHED*/
}
-
+
if ((meter_marker = dynamic_cast<MeterMarker*> (marker)) == 0) {
fatal << _("programming error: marker for meter is not a meter marker!") << endmsg;
- /*NOTREACHED*/
+ abort(); /*NOTREACHED*/
}
edit_meter_marker (*meter_marker);
break;
switch (item_type) {
case FadeInItem:
case FadeInHandleItem:
- case FadeOutItem:
- case FadeOutHandleItem:
- popup_fade_context_menu (1, event->button.time, item, item_type);
- break;
-
+ case FadeInTrimHandleItem:
case StartCrossFadeItem:
popup_xfade_in_context_menu (1, event->button.time, item, item_type);
break;
+ case FadeOutItem:
+ case FadeOutHandleItem:
+ case FadeOutTrimHandleItem:
case EndCrossFadeItem:
popup_xfade_out_context_menu (1, event->button.time, item, item_type);
break;
+ case LeftFrameHandle:
+ case RightFrameHandle:
+ break;
+
case StreamItem:
popup_track_context_menu (1, event->button.time, item_type, false);
break;
case RegionItem:
case RegionViewNameHighlight:
- case LeftFrameHandle:
- case RightFrameHandle:
case RegionViewName:
popup_track_context_menu (1, event->button.time, item_type, false);
break;
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;
case TransportMarkerBarItem:
case CdMarkerBarItem:
case TempoBarItem:
+ case TempoCurveItem:
case MeterBarItem:
case VideoBarItem:
- popup_ruler_menu (where, item_type);
+ case TimecodeRulerItem:
+ case SamplesRulerItem:
+ case MinsecRulerItem:
+ case BBTRulerItem:
+ popup_ruler_menu (where.sample, item_type);
break;
case MarkerItem:
popup_control_point_context_menu (item, event);
break;
+ case NoteItem:
+ if (internal_editing()) {
+ popup_note_context_menu (item, event);
+ }
+ break;
+
default:
break;
}
case MarkerBarItem:
if (!_dragging_playhead) {
- snap_to_with_modifier (where, event, 0, 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, 0, 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;
break;
+ case TimecodeRulerItem:
+ case SamplesRulerItem:
+ case MinsecRulerItem:
+ case BBTRulerItem:
+ return true;
+ break;
+
default:
break;
}
switch (eff) {
- case MouseObject:
- switch (item_type) {
- case AutomationTrackItem:
- atv = dynamic_cast<AutomationTimeAxisView*>(clicked_axisview);
- if (atv) {
- bool with_guard_points = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
- atv->add_automation_event (event, where, event->button.y, with_guard_points);
- }
- return true;
- break;
- default:
- break;
- }
- break;
-
- case MouseGain:
+ case MouseDraw:
switch (item_type) {
case RegionItem:
{
case AutomationTrackItem: {
bool with_guard_points = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
- dynamic_cast<AutomationTimeAxisView*>(clicked_axisview)->
- add_automation_event (event, where, event->button.y, with_guard_points);
+ atv = dynamic_cast<AutomationTimeAxisView*>(clicked_axisview);
+ if (atv) {
+ atv->add_automation_event (event, where.sample, event->button.y, with_guard_points);
+ }
return true;
break;
}
break;
case MouseAudition:
- set_canvas_cursor (current_canvas_cursor);
if (scrubbing_direction == 0) {
/* no drag, just a click */
switch (item_type) {
default:
break;
}
- } else {
+ } else if (_session) {
/* make sure we stop */
_session->request_transport_speed (0.0);
}
}
- /* do any (de)selection operations that should occur on button release */
- button_selection (item, event, item_type);
+ /* do any (de)selection operations that should occur on button release */
+ button_selection (item, event, item_type);
+
return true;
break;
} 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;
case MouseDraw:
return true;
-
+
case MouseRange:
// x_style_paste (where, 1.0);
return true;
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
+ * 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)
+ */
+
+ choose_canvas_cursor_on_entry (item_type);
switch (item_type) {
case ControlPointItem:
- if (mouse_mode == MouseGain || mouse_mode == MouseObject) {
+ if (mouse_mode == MouseDraw || mouse_mode == MouseObject || mouse_mode == MouseContent) {
cp = static_cast<ControlPoint*>(item->get_data ("control_point"));
cp->show ();
- double at_x, at_y;
- at_x = cp->get_x();
- at_y = cp->get_y ();
- cp->i2w (at_x, at_y);
- at_x += 10.0;
- at_y += 10.0;
-
fraction = 1.0 - (cp->get_y() / cp->line().height());
- if (is_drawable() && !_drags->active ()) {
- set_canvas_cursor (_cursors->fader);
- }
-
- _verbose_cursor->set (cp->line().get_verbose_cursor_string (fraction), at_x, at_y);
+ _verbose_cursor->set (cp->line().get_verbose_cursor_string (fraction));
_verbose_cursor->show ();
}
break;
case GainLineItem:
- if (mouse_mode == MouseGain) {
+ if (mouse_mode == MouseDraw) {
ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
if (line) {
- line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_EnteredGainLine());
- }
- if (is_drawable()) {
- set_canvas_cursor (_cursors->fader);
+ line->set_outline_color (UIConfiguration::instance().color ("entered gain line"));
}
}
break;
case AutomationLineItem:
- if (mouse_mode == MouseGain || mouse_mode == MouseObject) {
+ if (mouse_mode == MouseDraw || mouse_mode == MouseObject) {
ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
if (line) {
- line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_EnteredAutomationLine());
- }
- if (is_drawable()) {
- set_canvas_cursor (_cursors->fader);
+ line->set_outline_color (UIConfiguration::instance().color ("entered automation line"));
}
}
break;
- case RegionViewNameHighlight:
- if (is_drawable() && effective_mouse_mode() == MouseObject && entered_regionview) {
- set_canvas_cursor_for_region_view (event->crossing.x, entered_regionview);
- _over_region_trim_target = true;
+ case AutomationTrackItem:
+ AutomationTimeAxisView* atv;
+ if ((atv = static_cast<AutomationTimeAxisView*>(item->get_data ("trackview"))) != 0) {
+ clear_entered_track = false;
+ set_entered_track (atv);
}
break;
- case LeftFrameHandle:
- case RightFrameHandle:
- if (is_drawable() && effective_mouse_mode() == MouseObject && !internal_editing() && entered_regionview) {
- set_canvas_cursor_for_region_view (event->crossing.x, entered_regionview);
- }
- break;
-
- case RegionItem:
- switch (effective_mouse_mode()) {
- case MouseRange:
- set_canvas_cursor (_cursors->selector);
- break;
- default:
- set_canvas_cursor (which_grabber_cursor());
+ case MarkerItem:
+ if ((marker = static_cast<ArdourMarker *> (item->get_data ("marker"))) == 0) {
break;
}
- break;
-
- case StartSelectionTrimItem:
- if (is_drawable()) {
- set_canvas_cursor (_cursors->left_side_trim);
- }
- break;
- case EndSelectionTrimItem:
- if (is_drawable()) {
- set_canvas_cursor (_cursors->right_side_trim);
- }
- break;
-
- case PlayheadCursorItem:
- if (is_drawable()) {
- switch (_edit_point) {
- case EditAtMouse:
- set_canvas_cursor (_cursors->grabber_edit_point);
- break;
- default:
- set_canvas_cursor (_cursors->grabber);
- break;
- }
- }
- break;
-
-
- case RegionViewName:
-
- /* when the name is not an active item, the entire name highlight is for trimming */
-
- if (!reinterpret_cast<RegionView *> (item->get_data ("regionview"))->name_active()) {
- if (mouse_mode == MouseObject && is_drawable()) {
- set_canvas_cursor_for_region_view (event->crossing.x, entered_regionview);
- _over_region_trim_target = true;
- }
- }
+ entered_marker = marker;
+ marker->set_color_rgba (UIConfiguration::instance().color ("entered marker"));
break;
-
- case AutomationTrackItem:
- if (is_drawable()) {
- Gdk::Cursor *cursor;
- switch (mouse_mode) {
- case MouseRange:
- cursor = _cursors->selector;
- break;
- case MouseZoom:
- cursor = _cursors->zoom_in;
- break;
- default:
- cursor = _cursors->cross_hair;
- break;
- }
-
- set_canvas_cursor (cursor);
-
- AutomationTimeAxisView* atv;
- if ((atv = static_cast<AutomationTimeAxisView*>(item->get_data ("trackview"))) != 0) {
- clear_entered_track = false;
- set_entered_track (atv);
- }
+ case MeterMarkerItem:
+ if ((m_marker = static_cast<MeterMarker *> (item->get_data ("marker"))) == 0) {
+ break;
}
- break;
-
- case MarkerBarItem:
- case RangeMarkerBarItem:
- case TransportMarkerBarItem:
- case CdMarkerBarItem:
- case MeterBarItem:
- case TempoBarItem:
- if (is_drawable()) {
- set_canvas_cursor (_cursors->timebar);
+ 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 MarkerItem:
- if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
+ case TempoMarkerItem:
+ if ((t_marker = static_cast<TempoMarker *> (item->get_data ("marker"))) == 0) {
break;
}
- entered_marker = marker;
- marker->set_color_rgba (ARDOUR_UI::config()->get_canvasvar_EnteredMarker());
- // fall through
- case MeterMarkerItem:
- case TempoMarkerItem:
- if (is_drawable()) {
- set_canvas_cursor (_cursors->timebar);
+ 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:
- if (mouse_mode == MouseObject && !internal_editing()) {
+ case FadeInTrimHandleItem:
+ if (mouse_mode == MouseObject) {
ArdourCanvas::Rectangle *rect = dynamic_cast<ArdourCanvas::Rectangle *> (item);
if (rect) {
RegionView* rv = static_cast<RegionView*>(item->get_data ("regionview"));
rect->set_fill_color (rv->get_fill_color());
- set_canvas_cursor (_cursors->fade_in);
}
}
break;
case FadeOutHandleItem:
- if (mouse_mode == MouseObject && !internal_editing()) {
+ case FadeOutTrimHandleItem:
+ if (mouse_mode == MouseObject) {
ArdourCanvas::Rectangle *rect = dynamic_cast<ArdourCanvas::Rectangle *> (item);
if (rect) {
RegionView* rv = static_cast<RegionView*>(item->get_data ("regionview"));
rect->set_fill_color (rv->get_fill_color ());
- set_canvas_cursor (_cursors->fade_out);
}
}
break;
+
case FeatureLineItem:
{
ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
break;
case SelectionItem:
- if ( get_smart_mode() ) {
- set_canvas_cursor ();
- }
break;
+ case WaveItem:
+ {
+ if (entered_regionview) {
+ entered_regionview->entered();
+ }
+ }
+ break;
+
default:
break;
}
- /* second pass to handle entered track status in a comprehensible way.
+ /* third pass to handle entered track status in a comprehensible way.
*/
switch (item_type) {
break;
default:
- set_entered_track (0);
+
break;
}
Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type)
{
AutomationLine* al;
- Marker *marker;
+ ArdourMarker *marker;
+ TempoMarker *t_marker;
+ MeterMarker *m_marker;
Location *loc;
- RegionView* rv;
bool is_start;
bool ret = true;
+ if (!_enter_stack.empty()) {
+ _enter_stack.pop_back();
+ }
+
switch (item_type) {
case ControlPointItem:
- if (is_drawable()) {
- set_canvas_cursor (current_canvas_cursor);
- }
-
_verbose_cursor->hide ();
break;
- case RegionViewNameHighlight:
- case LeftFrameHandle:
- case RightFrameHandle:
- case StartSelectionTrimItem:
- case EndSelectionTrimItem:
- case PlayheadCursorItem:
-
- _over_region_trim_target = false;
-
- if (is_drawable()) {
- set_canvas_cursor (current_canvas_cursor);
- }
- break;
-
case GainLineItem:
case AutomationLineItem:
al = reinterpret_cast<AutomationLine*> (item->get_data ("line"));
line->set_outline_color (al->get_line_color());
}
}
- if (is_drawable()) {
- set_canvas_cursor (current_canvas_cursor);
- }
break;
- case RegionViewName:
- /* see enter_handler() for notes */
- _over_region_trim_target = false;
-
- if (!reinterpret_cast<RegionView *> (item->get_data ("regionview"))->name_active()) {
- if (is_drawable() && mouse_mode == MouseObject) {
- set_canvas_cursor (current_canvas_cursor);
- }
+ case MarkerItem:
+ if ((marker = static_cast<ArdourMarker *> (item->get_data ("marker"))) == 0) {
+ break;
}
- break;
-
- case RangeMarkerBarItem:
- case TransportMarkerBarItem:
- case CdMarkerBarItem:
- case MeterBarItem:
- case TempoBarItem:
- case MarkerBarItem:
- if (is_drawable()) {
- set_canvas_cursor (current_canvas_cursor);
+ entered_marker = 0;
+ if ((loc = find_location_from_marker (marker, is_start)) != 0) {
+ location_flags_changed (loc);
}
break;
- case MarkerItem:
- if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
+ case MeterMarkerItem:
+ if ((m_marker = static_cast<MeterMarker *> (item->get_data ("marker"))) == 0) {
break;
}
entered_marker = 0;
- if ((loc = find_location_from_marker (marker, is_start)) != 0) {
- location_flags_changed (loc, this);
+ 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"));
}
- // fall through
- case MeterMarkerItem:
- case TempoMarkerItem:
+ break;
- if (is_drawable()) {
- set_canvas_cursor (current_canvas_cursor);
+ case TempoMarkerItem:
+ if ((t_marker = static_cast<TempoMarker *> (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:
+ case FadeOutTrimHandleItem:
case FadeInHandleItem:
case FadeOutHandleItem:
- rv = static_cast<RegionView*>(item->get_data ("regionview"));
- {
- ArdourCanvas::Rectangle *rect = dynamic_cast<ArdourCanvas::Rectangle *> (item);
- if (rect) {
- rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_InactiveFadeHandle());
- }
+ {
+ ArdourCanvas::Rectangle *rect = dynamic_cast<ArdourCanvas::Rectangle *> (item);
+ if (rect) {
+ rect->set_fill_color (UIConfiguration::instance().color ("inactive fade handle"));
}
- set_canvas_cursor (current_canvas_cursor);
- break;
+ }
+ break;
case AutomationTrackItem:
- if (is_drawable()) {
- set_canvas_cursor (current_canvas_cursor);
- clear_entered_track = true;
- Glib::signal_idle().connect (sigc::mem_fun(*this, &Editor::left_automation_track));
- }
break;
+
case FeatureLineItem:
- {
- ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
- line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_ZeroLine());
- }
- break;
+ {
+ ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
+ line->set_outline_color (UIConfiguration::instance().color ("zero line"));
+ }
+ break;
default:
break;
return ret;
}
-gint
-Editor::left_automation_track ()
-{
- if (clear_entered_track) {
- set_entered_track (0);
- clear_entered_track = false;
- }
- return false;
-}
-
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;
return true;
}
- JoinObjectRangeState const old = _join_object_range_state;
- update_join_object_range_location (event->motion.x, event->motion.y);
-
- if (!_internal_editing && _join_object_range_state != old) {
- set_canvas_cursor ();
- }
-
- if (!_internal_editing && _over_region_trim_target) {
- set_canvas_cursor_for_region_view (event->motion.x, entered_regionview);
- }
+ update_join_object_range_location (event->motion.y);
- bool handled = false;
if (_drags->active ()) {
- handled = _drags->motion_handler (event, from_autoscroll);
- }
-
- if (!handled) {
- return false;
+ //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);
+ }
}
- track_canvas_motion (event);
- return true;
+ return false;
}
bool
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*/
+ abort(); /*NOTREACHED*/
}
AutomationLine& line = control_point->line ();
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*/
+ abort(); /*NOTREACHED*/
}
control_point->line().remove_point (*control_point);
if (p == 0) {
fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
- /*NOTREACHED*/
+ abort(); /*NOTREACHED*/
}
ControlPointDialog d (p);
- ensure_float (d);
if (d.run () != RESPONSE_ACCEPT) {
return;
}
void
-Editor::edit_notes (TimeAxisViewItem& tavi)
+Editor::edit_notes (MidiRegionView* mrv)
{
- MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(&tavi);
-
- if (!mrv) {
- return;
- }
-
MidiRegionView::Selection const & s = mrv->selection();
if (s.empty ()) {
return;
}
-
- EditNoteDialog* d = new EditNoteDialog (&(*s.begin())->region_view(), s);
- d->show_all ();
- ensure_float (*d);
- d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &Editor::note_edit_done), d));
+ EditNoteDialog* d = new EditNoteDialog (mrv, s);
+ d->show_all ();
+
+ d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &Editor::note_edit_done), d));
}
void
Editor::note_edit_done (int r, EditNoteDialog* d)
{
- d->done (r);
- delete d;
+ d->done (r);
+ 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
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
- if (!rtv->hidden()) {
+ if (rtv && !rtv->hidden()) {
if (*high < rtv->order()) {
*high = rtv->order ();
if (Keyboard::modifier_state_contains (event->state, Keyboard::PrimaryModifier)) {
TimeAxisView* tv = &rv.get_time_axis_view();
- RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(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);
}
}
}
void
Editor::collect_and_select_new_region_view (RegionView* rv)
{
- selection->add(rv);
+ selection->add(rv);
latest_regionviews.push_back (rv);
}
void
Editor::cancel_time_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 ();
}
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;
break;
case 2:
- begin_reversible_command (_("End point trim"));
+ begin_reversible_command (_("end point trim"));
if (selection->selected (rv)) {
void
Editor::hide_marker (ArdourCanvas::Item* item, GdkEvent* /*event*/)
{
- Marker* marker;
+ ArdourMarker* marker;
bool is_start;
- if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
+ if ((marker = static_cast<ArdourMarker *> (item->get_data ("marker"))) == 0) {
fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
- /*NOTREACHED*/
+ abort(); /*NOTREACHED*/
}
Location* location = find_location_from_marker (marker, is_start);
location->set_hidden (true, this);
}
-
-void
-Editor::reposition_zoom_rect (framepos_t start, framepos_t end)
-{
- double x1 = sample_to_pixel (start);
- double x2 = sample_to_pixel (end);
- double y2 = _full_canvas_height - 1.0;
-
- zoom_rect->set (ArdourCanvas::Rect (x1, 1.0, x2, y2));
-}
-
-
gint
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());
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()) {
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&rv->get_time_axis_view());
- if (rtv == 0 || !rtv->is_track()) {
+ if (!rtv || !rtv->is_track()) {
return;
}
boost::shared_ptr<Playlist> playlist = rtv->playlist();
- double speed = rtv->track()->speed();
playlist->clear_changes ();
boost::shared_ptr<Region> 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
return;
}
- _region_motion_group->raise_to_top ();
+ switch (Config->get_edit_mode()) {
+ case Splice:
+ _drags->add (new RegionSpliceDrag (this, item, region_view, selection->regions.by_layer()));
+ break;
+ case Ripple:
+ _drags->add (new RegionRippleDrag (this, item, region_view, selection->regions.by_layer()));
+ break;
+ default:
+ _drags->add (new RegionMoveDrag (this, item, region_view, selection->regions.by_layer(), false, false));
+ break;
- if (Config->get_edit_mode() == Splice) {
- _drags->add (new RegionSpliceDrag (this, item, region_view, selection->regions.by_layer()));
- } else {
- _drags->add (new RegionMoveDrag (this, item, region_view, selection->regions.by_layer(), false, false));
}
}
return;
}
- _region_motion_group->raise_to_top ();
-
_drags->add (new RegionMoveDrag (this, item, region_view, selection->regions.by_layer(), false, true));
}
return;
}
- if (Config->get_edit_mode() == Splice) {
+ if (Config->get_edit_mode() == Splice || Config->get_edit_mode() == Ripple) {
return;
}
_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
/* 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> playlist = clicked_axisview->playlist();
clicked_routeview->playlist()->add_region (region, selection->time[clicked_selection].start);
_session->add_command(new StatefulDiffCommand (playlist));
- commit_reversible_command ();
-
c.disconnect ();
if (latest_regionviews.empty()) {
/* something went wrong */
+ abort_reversible_command ();
return;
}
/* we need to deselect all other regionviews, and select this one
i'm ignoring undo stuff, because the region creation will take care of it
*/
+
selection->set (latest_regionviews);
+ commit_reversible_command ();
+
_drags->set (new RegionMoveDrag (this, latest_regionviews.front()->get_canvas_group(), latest_regionviews.front(), latest_regionviews, false, false), event);
}
_drags->abort ();
} else {
selection->clear ();
- }
-}
-
-void
-Editor::set_internal_edit (bool yn)
-{
- if (_internal_editing == yn) {
- return;
- }
-
- _internal_editing = yn;
-
- if (yn) {
- pre_internal_mouse_mode = mouse_mode;
- pre_internal_snap_type = _snap_type;
- pre_internal_snap_mode = _snap_mode;
- for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
- (*i)->enter_internal_edit_mode ();
- }
-
- set_snap_to (internal_snap_type);
- set_snap_mode (internal_snap_mode);
-
- } else {
-
- internal_snap_mode = _snap_mode;
- internal_snap_type = _snap_type;
-
- for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
- (*i)->leave_internal_edit_mode ();
- }
-
- if (mouse_mode == MouseDraw && pre_internal_mouse_mode != MouseDraw) {
- /* we were drawing .. flip back to something sensible */
- set_mouse_mode (pre_internal_mouse_mode);
- }
+ /* if session is playing a range, cancel that */
+ if (_session->get_play_range()) {
+ _session->request_cancel_play_range();
+ }
- set_snap_to (pre_internal_snap_type);
- set_snap_mode (pre_internal_snap_mode);
+ if (_session->solo_selection_active()) {
+ StripableList sl;
+ _session->solo_selection (sl, false);
+ }
}
-
- set_canvas_cursor ();
+
+ ARDOUR_UI::instance()->reset_focus (&contents());
}
-/** Update _join_object_range_state which indicate whether we are over the top or bottom half of a region view,
- * used by the `join object/range' tool mode.
+/** Update _join_object_range_state which indicate whether we are over the top
+ * or bottom half of a route view, used by the `join object/range' tool
+ * mode. Coordinates in canvas space.
*/
void
-Editor::update_join_object_range_location (double /*x*/, double y)
+Editor::update_join_object_range_location (double y)
{
- /* XXX: actually, this decides based on whether the mouse is in the top
- or bottom half of a the waveform part RouteTimeAxisView;
-
- Note that entered_{track,regionview} is not always setup (e.g. if
- the mouse is over a TimeSelection), and to get a Region
- that we're over requires searching the playlist.
- */
-
- if ( !get_smart_mode() ) {
+ if (!get_smart_mode()) {
_join_object_range_state = JOIN_OBJECT_RANGE_NONE;
return;
}
+ JoinObjectRangeState const old = _join_object_range_state;
+
if (mouse_mode == MouseObject) {
_join_object_range_state = JOIN_OBJECT_RANGE_OBJECT;
} else if (mouse_mode == MouseRange) {
_join_object_range_state = JOIN_OBJECT_RANGE_RANGE;
}
- /* XXX: maybe we should make entered_track work in all cases, rather than resorting to this */
- pair<TimeAxisView*, int> tvp = trackview_by_y_position (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();
+
+ _join_object_range_state = c <= 0.5 ? JOIN_OBJECT_RANGE_RANGE : JOIN_OBJECT_RANGE_OBJECT;
+
+ Editor::EnterContext* ctx = get_enter_context(RegionItem);
+ if (_join_object_range_state != old && ctx) {
+ ctx->cursor_ctx->change(which_track_cursor());
+ }
+
+ } else if (entered_track) {
- if (tvp.first) {
+ RouteTimeAxisView* entered_route_view = dynamic_cast<RouteTimeAxisView*> (entered_track);
- RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
- if (rtv) {
+ if (entered_route_view) {
double cx = 0;
double cy = y;
- rtv->canvas_display()->canvas_to_item (cx, cy);
- double const c = cy / (rtv->view()->child_height() - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE);
+ entered_route_view->canvas_display()->canvas_to_item (cx, cy);
+
+ double track_height = entered_route_view->view()->child_height();
+ if (UIConfiguration::instance().get_show_name_highlight()) {
+ track_height -= TimeAxisViewItem::NAME_HIGHLIGHT_SIZE;
+ }
+ double const c = cy / track_height;
+
- _join_object_range_state = c <= 0.5 ? JOIN_OBJECT_RANGE_RANGE : JOIN_OBJECT_RANGE_OBJECT;
+ if (c <= 0.5) {
+ _join_object_range_state = JOIN_OBJECT_RANGE_RANGE;
+ } else {
+ _join_object_range_state = JOIN_OBJECT_RANGE_OBJECT;
+ }
+
+ } else {
+ /* Other kinds of tracks use object mode */
+ _join_object_range_state = JOIN_OBJECT_RANGE_OBJECT;
+ }
+
+ Editor::EnterContext* ctx = get_enter_context(StreamItem);
+ if (_join_object_range_state != old && ctx) {
+ ctx->cursor_ctx->change(which_track_cursor());
}
}
}
e->region_view().delete_note (e->note ());
}
-void
-Editor::set_canvas_cursor_for_region_view (double x, RegionView* rv)
-{
- /* XXX: this check should not be necessary */
- if (rv == 0) {
- return;
- }
-
- assert (rv);
-
- ArdourCanvas::Group* g = rv->get_canvas_group ();
- ArdourCanvas::Group* p = g->parent ();
-
- /* Compute x in region view parent coordinates */
- double dy = 0;
- p->canvas_to_item (x, dy);
-
- boost::optional<ArdourCanvas::Rect> item_bbox = g->bounding_box ();
- assert (item_bbox);
- ArdourCanvas::Rect parent_bbox = g->item_to_parent (item_bbox.get ());
-
- /* Halfway across the region */
- double const h = (parent_bbox.x0 + parent_bbox.x1) / 2;
-
- Trimmable::CanTrim ct = rv->region()->can_trim ();
- if (x <= h) {
- if (ct & Trimmable::FrontTrimEarlier) {
- set_canvas_cursor (_cursors->left_side_trim, true);
- } else {
- set_canvas_cursor (_cursors->left_side_trim_right_only, true);
- }
- } else {
- if (ct & Trimmable::EndTrimLater) {
- set_canvas_cursor (_cursors->right_side_trim, true);
- } else {
- set_canvas_cursor (_cursors->right_side_trim_left_only, true);
- }
- }
-}
-
/** Obtain the pointer position in canvas coordinates */
void
Editor::get_pointer_position (double& x, double& y) const