selection = new Selection (this);
cut_buffer = new Selection (this);
+ _selection_memento = new SelectionMemento ();
+ before.clear();
clicked_regionview = 0;
clicked_axisview = 0;
sfbrowser = 0;
- location_marker_color = ARDOUR_UI::config()->get_LocationMarker();
- location_range_color = ARDOUR_UI::config()->get_LocationRange();
- location_cd_marker_color = ARDOUR_UI::config()->get_LocationCDMarker();
- location_loop_color = ARDOUR_UI::config()->get_LocationLoop();
- location_punch_color = ARDOUR_UI::config()->get_LocationPunch();
+ location_marker_color = ARDOUR_UI::config()->color ("location marker");
+ location_range_color = ARDOUR_UI::config()->color ("location range");
+ location_cd_marker_color = ARDOUR_UI::config()->color ("location cd marker");
+ location_loop_color = ARDOUR_UI::config()->color ("location loop");
+ location_punch_color = ARDOUR_UI::config()->color ("location punch");
zoom_focus = ZoomFocusLeft;
_edit_point = EditAtMouse;
- _internal_editing = false;
current_canvas_cursor = 0;
_visible_track_count = -1;
_snap_mode = SnapOff;
set_snap_mode (_snap_mode);
set_mouse_mode (MouseObject, true);
- pre_internal_mouse_mode = MouseObject;
- pre_internal_snap_type = _snap_type;
- pre_internal_snap_mode = _snap_mode;
- internal_snap_type = _snap_type;
- internal_snap_mode = _snap_mode;
set_edit_point_preference (EditAtMouse, true);
_playlist_selector = new PlaylistSelector();
entered_regionview = rv;
if (entered_regionview != 0) {
- entered_regionview->entered (internal_editing ());
+ entered_regionview->entered ();
}
if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
/* register for undo history */
_session->register_with_memento_command_factory(id(), this);
+ _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
{
using namespace Menu_Helpers;
- AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
- assert(arv);
+ AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
+ if (!arv) {
+ return;
+ }
MenuList& items (xfade_in_context_menu.items());
items.clear ();
Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
{
using namespace Menu_Helpers;
- AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
- assert(arv);
+ AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
+ if (!arv) {
+ return;
+ }
MenuList& items (xfade_out_context_menu.items());
items.clear ();
edit_items.push_back (SeparatorElem());
edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
+ edit_items.push_back (MenuElem (_("Set Session Start/End from Range"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
edit_items.push_back (SeparatorElem());
edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
{
string str = snap_mode_strings[(int)mode];
- if (_internal_editing) {
- internal_snap_mode = mode;
- } else {
- pre_internal_snap_mode = mode;
- }
-
_snap_mode = mode;
if (str != snap_mode_selector.get_text ()) {
bool changed = (_edit_point != ep);
_edit_point = ep;
- string str = edit_point_strings[(int)ep];
-
if (Profile->get_mixbus())
if (ep == EditAtSelectedMarker)
ep = EditAtPlayhead;
-
+
+ string str = edit_point_strings[(int)ep];
if (str != edit_point_selector.get_text ()) {
edit_point_selector.set_text (str);
}
snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
}
- if ((prop = node.property ("internal-snap-to"))) {
- internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
- }
-
- if ((prop = node.property ("internal-snap-mode"))) {
- internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
- }
-
- if ((prop = node.property ("pre-internal-snap-to"))) {
- pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
- }
-
-
- if ((prop = node.property ("pre-internal-snap-mode"))) {
- pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
- }
-
if ((prop = node.property ("mouse-mode"))) {
MouseMode m = str2mousemode(prop->value());
set_mouse_mode (m, true);
reset_y_origin (atof (prop->value ()));
}
- if ((prop = node.property ("internal-edit"))) {
- bool yn = string_is_affirmative (prop->value());
- RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
- if (act) {
- RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
- tact->set_active (!yn);
- tact->set_active (yn);
- }
- }
-
if ((prop = node.property ("join-object-range"))) {
RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
bool yn = string_is_affirmative (prop->value());
node->add_property ("zoom", buf);
node->add_property ("snap-to", enum_2_string (_snap_type));
node->add_property ("snap-mode", enum_2_string (_snap_mode));
- node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
- node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
- node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
- node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
node->add_property ("edit-point", enum_2_string (_edit_point));
snprintf (buf, sizeof(buf), "%d", _visible_track_count);
node->add_property ("visible-track-count", buf);
node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
node->add_property ("mouse-mode", enum2str(mouse_mode));
- node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
switch (_snap_type) {
case SnapToTimecodeFrame:
- if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
+ if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
+ fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
+ /* start is already on a whole timecode frame, do nothing */
+ } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
} else {
start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
} else {
start -= _session->config.get_timecode_offset ();
}
- if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
+ if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
+ (start % one_timecode_second == 0)) {
+ /* start is already on a whole second, do nothing */
+ } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
} else {
start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
} else {
start -= _session->config.get_timecode_offset ();
}
- if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
+ if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
+ (start % one_timecode_minute == 0)) {
+ /* start is already on a whole minute, do nothing */
+ } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
} else {
start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
return timecode_snap_to_internal (start, direction, for_mark);
case SnapToCDFrame:
- if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
+ if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
+ start % (one_second/75) == 0) {
+ /* start is already on a whole CD frame, do nothing */
+ } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
} else {
start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
break;
case SnapToSeconds:
- if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
+ if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
+ start % one_second == 0) {
+ /* start is already on a whole second, do nothing */
+ } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
start = (framepos_t) ceil ((double) start / one_second) * one_second;
} else {
start = (framepos_t) floor ((double) start / one_second) * one_second;
break;
case SnapToMinutes:
- if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
+ if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
+ start % one_minute == 0) {
+ /* start is already on a whole minute, do nothing */
+ } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
} else {
start = (framepos_t) floor ((double) start / one_minute) * one_minute;
mouse_mode_size_group->add_widget (mouse_move_button);
mouse_mode_size_group->add_widget (mouse_cut_button);
mouse_mode_size_group->add_widget (mouse_select_button);
- mouse_mode_size_group->add_widget (mouse_gain_button);
mouse_mode_size_group->add_widget (mouse_timefx_button);
mouse_mode_size_group->add_widget (mouse_audition_button);
mouse_mode_size_group->add_widget (mouse_draw_button);
- mouse_mode_size_group->add_widget (internal_edit_button);
+ mouse_mode_size_group->add_widget (mouse_content_button);
mouse_mode_size_group->add_widget (zoom_in_button);
mouse_mode_size_group->add_widget (zoom_out_button);
}
if (!ARDOUR::Profile->get_trx()) {
- mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
- mouse_mode_hbox->pack_start (internal_edit_button, false, false, 0);
+ mouse_mode_hbox->pack_start (mouse_content_button, false, false);
}
mouse_mode_vbox->pack_start (*mouse_mode_hbox);
ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
- ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
- ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
+ ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit Gain/Notes/Automation"));
ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
- ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
+ ARDOUR_UI::instance()->set_tip (mouse_content_button, _("Select/move contents (notes and automation)"));
ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
Editor::begin_reversible_command (string name)
{
if (_session) {
+ before.push_back (&_selection_memento->get_state ());
_session->begin_reversible_command (name);
}
}
Editor::begin_reversible_command (GQuark q)
{
if (_session) {
+ before.push_back (&_selection_memento->get_state ());
_session->begin_reversible_command (q);
}
}
Editor::commit_reversible_command ()
{
if (_session) {
+ if (before.size() == 1) {
+ _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
+ }
+
+ if (!before.empty()) {
+ before.pop_back();
+ }
+
_session->commit_reversible_command ();
}
}
/* calculate basic unsnapped multi-paste offset */
framecnt_t offset = paste_count * duration;
- bool success = true;
- double snap_beats = get_grid_type_as_beats(success, pos);
- if (success) {
- /* we're snapped to something musical, round duration up */
- BeatsFramesConverter conv(_session->tempo_map(), pos);
- const Evoral::MusicalTime dur_beats = conv.from(duration);
- const framecnt_t snap_dur_beats = ceil(dur_beats / snap_beats) * snap_beats;
-
- offset = paste_count * conv.to(snap_dur_beats);
- }
+ /* snap offset so pos + offset is aligned to the grid */
+ framepos_t offset_pos = pos + offset;
+ snap_to(offset_pos, RoundUpMaybe);
+ offset = offset_pos - pos;
return offset;
}
switch (_snap_type) {
case SnapToBeat:
- return 1.0;
+ return Evoral::MusicalTime(1.0);
break;
case SnapToBeatDiv128:
- return 1.0/128.0;
+ return Evoral::MusicalTime(1.0/128.0);
break;
case SnapToBeatDiv64:
- return 1.0/64.0;
+ return Evoral::MusicalTime(1.0/64.0);
break;
case SnapToBeatDiv32:
- return 1.0/32.0;
+ return Evoral::MusicalTime(1.0/32.0);
break;
case SnapToBeatDiv28:
- return 1.0/28.0;
+ return Evoral::MusicalTime(1.0/28.0);
break;
case SnapToBeatDiv24:
- return 1.0/24.0;
+ return Evoral::MusicalTime(1.0/24.0);
break;
case SnapToBeatDiv20:
- return 1.0/20.0;
+ return Evoral::MusicalTime(1.0/20.0);
break;
case SnapToBeatDiv16:
- return 1.0/16.0;
+ return Evoral::MusicalTime(1.0/16.0);
break;
case SnapToBeatDiv14:
- return 1.0/14.0;
+ return Evoral::MusicalTime(1.0/14.0);
break;
case SnapToBeatDiv12:
- return 1.0/12.0;
+ return Evoral::MusicalTime(1.0/12.0);
break;
case SnapToBeatDiv10:
- return 1.0/10.0;
+ return Evoral::MusicalTime(1.0/10.0);
break;
case SnapToBeatDiv8:
- return 1.0/8.0;
+ return Evoral::MusicalTime(1.0/8.0);
break;
case SnapToBeatDiv7:
- return 1.0/7.0;
+ return Evoral::MusicalTime(1.0/7.0);
break;
case SnapToBeatDiv6:
- return 1.0/6.0;
+ return Evoral::MusicalTime(1.0/6.0);
break;
case SnapToBeatDiv5:
- return 1.0/5.0;
+ return Evoral::MusicalTime(1.0/5.0);
break;
case SnapToBeatDiv4:
- return 1.0/4.0;
+ return Evoral::MusicalTime(1.0/4.0);
break;
case SnapToBeatDiv3:
- return 1.0/3.0;
+ return Evoral::MusicalTime(1.0/3.0);
break;
case SnapToBeatDiv2:
- return 1.0/2.0;
+ return Evoral::MusicalTime(1.0/2.0);
break;
case SnapToBar:
if (_session) {
- return _session->tempo_map().meter_at (position).divisions_per_bar();
+ return Evoral::MusicalTime(_session->tempo_map().meter_at (position).divisions_per_bar());
}
break;
break;
}
- return 0.0;
+ return Evoral::MusicalTime();
}
framecnt_t
void
Editor::clear_playlists (TimeAxisView* v)
{
- begin_reversible_command (_("clear playlists"));
+ begin_reversible_command (_("clear playlists"));
vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
_session->playlists->get (playlists);
mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
// return key_press_focus_accelerator_handler (*this, ev);
}
+double
+Editor::get_y_origin () const
+{
+ return vertical_adjustment.get_value ();
+}
+
/** Queue up a change to the viewport x origin.
* @param frame New x origin.
*/
_session->set_auto_punch_location (loc);
XMLNode &after = _session->locations()->get_state();
_session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
- }
- else {
+ } else {
XMLNode &before = tpl->get_state();
tpl->set_hidden (false, this);
tpl->set (start, end);
return regions;
}
+void
+Editor::get_regionviews_by_id (PBD::ID const & id, RegionSelection & regions) const
+{
+ for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
+ RouteTimeAxisView* tatv;
+
+ if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
+ boost::shared_ptr<Playlist> pl;
+ std::vector<boost::shared_ptr<Region> > results;
+ boost::shared_ptr<Track> tr;
+
+ if ((tr = tatv->track()) == 0) {
+ /* bus */
+ continue;
+ }
+
+ if ((pl = (tr->playlist())) != 0) {
+ boost::shared_ptr<Region> r = pl->region_by_id (id);
+ if (r) {
+ RegionView* marv = tatv->view()->find_view (r);
+ if (marv) {
+ regions.push_back (marv);
+ }
+ }
+ }
+ }
+ }
+}
+
void
Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
{
}
void
-Editor::region_view_added (RegionView *)
+Editor::region_view_added (RegionView * rv)
{
+ for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
+ if (rv->region ()->id () == (*pr)) {
+ selection->add (rv);
+ selection->regions.pending.erase (pr);
+ break;
+ }
+ }
_summary->set_background_dirty ();
}
rtv->effective_gain_display ();
- if (internal_editing()) {
- rtv->enter_internal_edit_mode ();
- } else {
- rtv->leave_internal_edit_mode ();
- }
-
rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
}