Fix session range location by hooking into the undo system. Fixes #3654.
git-svn-id: svn://localhost/ardour2/branches/3.0@8539 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
074d58fc6f
commit
1e8586742e
@ -3069,6 +3069,14 @@ Editor::begin_reversible_command (string name)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Editor::begin_reversible_command (GQuark q)
|
||||
{
|
||||
if (_session) {
|
||||
_session->begin_reversible_command (q);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Editor::commit_reversible_command ()
|
||||
{
|
||||
|
@ -429,6 +429,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
|
||||
void snap_to (framepos_t& first, framepos_t& last, int32_t direction = 0, bool for_mark = false);
|
||||
|
||||
void begin_reversible_command (std::string cmd_name);
|
||||
void begin_reversible_command (GQuark);
|
||||
void commit_reversible_command ();
|
||||
|
||||
DragManager* drags () const {
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "ardour/source_factory.h"
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/smf_source.h"
|
||||
#include "ardour/operations.h"
|
||||
#include "pbd/memento_command.h"
|
||||
|
||||
#include "ardour_ui.h"
|
||||
@ -874,7 +875,7 @@ Editor::finish_bringing_in_material (boost::shared_ptr<Region> region, uint32_t
|
||||
|
||||
boost::shared_ptr<Playlist> playlist = existing_track->playlist();
|
||||
boost::shared_ptr<Region> copy (RegionFactory::create (region, region->properties()));
|
||||
begin_reversible_command (_("insert file"));
|
||||
begin_reversible_command (Operations::insert_file);
|
||||
playlist->clear_changes ();
|
||||
playlist->add_region (copy, pos);
|
||||
_session->add_command (new StatefulDiffCommand (playlist));
|
||||
|
@ -32,6 +32,8 @@
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/dB.h"
|
||||
#include "ardour/region_factory.h"
|
||||
#include "ardour/operations.h"
|
||||
|
||||
#include "editor.h"
|
||||
#include "i18n.h"
|
||||
#include "keyboard.h"
|
||||
@ -905,7 +907,7 @@ RegionMoveDrag::finished_no_copy (
|
||||
if (_x_constrained) {
|
||||
_editor->begin_reversible_command (_("fixed time region drag"));
|
||||
} else {
|
||||
_editor->begin_reversible_command (_("region drag"));
|
||||
_editor->begin_reversible_command (Operations::region_drag);
|
||||
}
|
||||
|
||||
for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ) {
|
||||
@ -1227,7 +1229,7 @@ RegionInsertDrag::finished (GdkEvent *, bool)
|
||||
|
||||
boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
|
||||
|
||||
_editor->begin_reversible_command (_("insert region"));
|
||||
_editor->begin_reversible_command (Operations::insert_region);
|
||||
playlist->clear_changes ();
|
||||
playlist->add_region (_primary->region (), _last_frame_position);
|
||||
_editor->session()->add_command (new StatefulDiffCommand (playlist));
|
||||
|
@ -74,6 +74,7 @@
|
||||
#include "ardour/region_factory.h"
|
||||
#include "ardour/source_factory.h"
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/operations.h"
|
||||
|
||||
#include <bitset>
|
||||
|
||||
@ -2540,7 +2541,7 @@ Editor::add_region_brush_drag (ArdourCanvas::Item* item, GdkEvent* event, Region
|
||||
RegionSelection s = get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
|
||||
_drags->add (new RegionMoveDrag (this, item, region_view, s.by_layer(), true, false));
|
||||
|
||||
begin_reversible_command (_("Drag region brush"));
|
||||
begin_reversible_command (Operations::drag_region_brush);
|
||||
}
|
||||
|
||||
/** Start a grab where a time range is selected, track(s) are selected, and the
|
||||
@ -2581,7 +2582,7 @@ Editor::start_selection_grab (ArdourCanvas::Item* /*item*/, GdkEvent* event)
|
||||
creating the new region and another for moving it.
|
||||
*/
|
||||
|
||||
begin_reversible_command (_("selection grab"));
|
||||
begin_reversible_command (Operations::selection_grab);
|
||||
|
||||
boost::shared_ptr<Playlist> playlist = clicked_axisview->playlist();
|
||||
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include "ardour/quantize.h"
|
||||
#include "ardour/strip_silence.h"
|
||||
#include "ardour/route_group.h"
|
||||
#include "ardour/operations.h"
|
||||
|
||||
#include "ardour_ui.h"
|
||||
#include "editor.h"
|
||||
@ -3032,7 +3033,7 @@ Editor::region_fill_track ()
|
||||
|
||||
framepos_t const end = _session->current_end_frame ();
|
||||
|
||||
begin_reversible_command (_("region fill"));
|
||||
begin_reversible_command (Operations::region_fill);
|
||||
|
||||
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
|
||||
|
||||
@ -3086,7 +3087,7 @@ Editor::region_fill_selection ()
|
||||
framepos_t selection_length = end - start;
|
||||
float times = (float)selection_length / region->length();
|
||||
|
||||
begin_reversible_command (_("fill selection"));
|
||||
begin_reversible_command (Operations::fill_selection);
|
||||
|
||||
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
|
||||
|
||||
@ -4155,7 +4156,7 @@ Editor::paste_internal (framepos_t position, float times)
|
||||
position = get_preferred_edit_position();
|
||||
}
|
||||
|
||||
begin_reversible_command (_("paste"));
|
||||
begin_reversible_command (Operations::paste);
|
||||
|
||||
TrackViewList ts;
|
||||
TrackViewList::iterator i;
|
||||
@ -4218,7 +4219,7 @@ Editor::duplicate_some_regions (RegionSelection& regions, float times)
|
||||
framepos_t const start_frame = regions.start ();
|
||||
framepos_t const end_frame = regions.end_frame ();
|
||||
|
||||
begin_reversible_command (_("duplicate region"));
|
||||
begin_reversible_command (Operations::duplicate_region);
|
||||
|
||||
selection->clear_regions ();
|
||||
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include "ardour/session_playlist.h"
|
||||
#include "ardour/tempo.h"
|
||||
#include "ardour/utils.h"
|
||||
#include "ardour/operations.h"
|
||||
|
||||
#include "midi++/names.h"
|
||||
|
||||
@ -1028,7 +1029,7 @@ MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
|
||||
{
|
||||
Editor* real_editor = dynamic_cast<Editor*> (&_editor);
|
||||
|
||||
real_editor->begin_reversible_command (_("create region"));
|
||||
real_editor->begin_reversible_command (Operations::create_region);
|
||||
playlist()->clear_changes ();
|
||||
|
||||
real_editor->snap_to (pos, 0);
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
@ -315,7 +314,6 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
||||
|
||||
int wipe ();
|
||||
|
||||
std::pair<framepos_t, framepos_t> get_extent () const;
|
||||
framepos_t current_end_frame () const;
|
||||
framepos_t current_start_frame () const;
|
||||
/** "actual" sample rate of session, set by current audioengine rate, pullup/down etc. */
|
||||
@ -666,6 +664,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
||||
std::string next_redo() const { return _history.next_redo(); }
|
||||
|
||||
void begin_reversible_command (const std::string& cmd_name);
|
||||
void begin_reversible_command (GQuark);
|
||||
void commit_reversible_command (Command* cmd = 0);
|
||||
|
||||
void add_command (Command *const cmd) {
|
||||
@ -673,6 +672,11 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
||||
_current_trans->add_command (cmd);
|
||||
}
|
||||
|
||||
/** @return The list of operations that are currently in progress */
|
||||
std::list<GQuark> const & current_operations () {
|
||||
return _current_trans_quarks;
|
||||
}
|
||||
|
||||
void add_commands (std::vector<Command*> const & cmds);
|
||||
|
||||
std::map<PBD::ID,PBD::StatefulDestructible*> registry;
|
||||
@ -841,6 +845,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
||||
Location* _session_range_location; ///< session range, or 0 if there is nothing in the session yet
|
||||
Slave* _slave;
|
||||
bool _silent;
|
||||
|
||||
void maybe_update_session_range (framepos_t, framepos_t);
|
||||
|
||||
// varispeed playback
|
||||
double _transport_speed;
|
||||
@ -1059,7 +1065,6 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
||||
|
||||
void first_stage_init (std::string path, std::string snapshot_name);
|
||||
int second_stage_init ();
|
||||
void update_session_range_location_marker ();
|
||||
void remove_empty_sounds ();
|
||||
|
||||
void setup_midi_control ();
|
||||
@ -1258,6 +1263,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
||||
|
||||
void remove_playlist (boost::weak_ptr<Playlist>);
|
||||
void track_playlist_changed (boost::weak_ptr<Track>);
|
||||
void playlist_region_added (boost::weak_ptr<Region>);
|
||||
void playlist_ranges_moved (std::list<Evoral::RangeMove<framepos_t> > const &);
|
||||
|
||||
/* NAMED SELECTIONS */
|
||||
|
||||
@ -1339,8 +1346,11 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
||||
UndoHistory _history;
|
||||
/** current undo transaction, or 0 */
|
||||
UndoTransaction* _current_trans;
|
||||
/** number of times that begin_reversible_command has been called without commit_reversible_command */
|
||||
int _current_trans_depth;
|
||||
/** GQuarks to describe the reversible commands that are currently in progress.
|
||||
* These may be nested, in which case more recently-started commands are toward
|
||||
* the front of the list.
|
||||
*/
|
||||
std::list<GQuark> _current_trans_quarks;
|
||||
|
||||
void jack_timebase_callback (jack_transport_state_t, pframes_t, jack_position_t*, int);
|
||||
int jack_sync_callback (jack_transport_state_t, jack_position_t*);
|
||||
|
@ -100,6 +100,7 @@
|
||||
#include "ardour/utils.h"
|
||||
#include "ardour/graph.h"
|
||||
#include "ardour/vbap_speakers.h"
|
||||
#include "ardour/operations.h"
|
||||
|
||||
#include "midi++/port.h"
|
||||
#include "midi++/mmc.h"
|
||||
@ -152,7 +153,6 @@ Session::Session (AudioEngine &eng,
|
||||
, _bundles (new BundleList)
|
||||
, _bundle_xml_node (0)
|
||||
, _current_trans (0)
|
||||
, _current_trans_depth (0)
|
||||
, _click_io ((IO*) 0)
|
||||
, click_data (0)
|
||||
, click_emphasis_data (0)
|
||||
@ -766,11 +766,9 @@ Session::track_playlist_changed (boost::weak_ptr<Track> wp)
|
||||
boost::shared_ptr<Playlist> playlist;
|
||||
|
||||
if ((playlist = track->playlist()) != 0) {
|
||||
playlist->LengthChanged.connect_same_thread (*this, boost::bind (&Session::update_session_range_location_marker, this));
|
||||
playlist->RangesMoved.connect_same_thread (*this, boost::bind (&Session::update_session_range_location_marker, this));
|
||||
playlist->RegionAdded.connect_same_thread (*this, boost::bind (&Session::playlist_region_added, this, _1));
|
||||
playlist->RangesMoved.connect_same_thread (*this, boost::bind (&Session::playlist_ranges_moved, this, _1));
|
||||
}
|
||||
|
||||
update_session_range_location_marker ();
|
||||
}
|
||||
|
||||
bool
|
||||
@ -2168,7 +2166,6 @@ Session::remove_route (boost::shared_ptr<Route> route)
|
||||
}
|
||||
|
||||
update_route_solo_state ();
|
||||
update_session_range_location_marker ();
|
||||
|
||||
// We need to disconnect the route's inputs and outputs
|
||||
|
||||
@ -2496,64 +2493,77 @@ Session::route_by_remote_id (uint32_t id)
|
||||
return boost::shared_ptr<Route> ((Route*) 0);
|
||||
}
|
||||
|
||||
/** If either end of the session range location marker lies inside the current
|
||||
* session extent, move it to the corresponding session extent.
|
||||
void
|
||||
Session::playlist_region_added (boost::weak_ptr<Region> w)
|
||||
{
|
||||
boost::shared_ptr<Region> r = w.lock ();
|
||||
if (!r) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* These are the operations that are currently in progress... */
|
||||
list<GQuark> curr = _current_trans_quarks;
|
||||
curr.sort ();
|
||||
|
||||
/* ...and these are the operations during which we want to update
|
||||
the session range location markers.
|
||||
*/
|
||||
list<GQuark> ops;
|
||||
ops.push_back (Operations::capture);
|
||||
ops.push_back (Operations::paste);
|
||||
ops.push_back (Operations::duplicate_region);
|
||||
ops.push_back (Operations::insert_file);
|
||||
ops.push_back (Operations::insert_region);
|
||||
ops.push_back (Operations::drag_region_brush);
|
||||
ops.push_back (Operations::region_drag);
|
||||
ops.push_back (Operations::selection_grab);
|
||||
ops.push_back (Operations::region_fill);
|
||||
ops.push_back (Operations::fill_selection);
|
||||
ops.push_back (Operations::create_region);
|
||||
ops.sort ();
|
||||
|
||||
/* See if any of the current operations match the ones that we want */
|
||||
list<GQuark> in;
|
||||
set_intersection (_current_trans_quarks.begin(), _current_trans_quarks.end(), ops.begin(), ops.end(), back_inserter (in));
|
||||
|
||||
/* If so, update the session range markers */
|
||||
if (!in.empty ()) {
|
||||
maybe_update_session_range (r->position (), r->last_frame ());
|
||||
}
|
||||
}
|
||||
|
||||
/** Update the session range markers if a is before the current start or
|
||||
* b is after the current end.
|
||||
*/
|
||||
void
|
||||
Session::update_session_range_location_marker ()
|
||||
Session::maybe_update_session_range (framepos_t a, framepos_t b)
|
||||
{
|
||||
if (_state_of_the_state & Loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
pair<framepos_t, framepos_t> const ext = get_extent ();
|
||||
|
||||
if (_session_range_location == 0) {
|
||||
/* we don't have a session range yet; use this one (provided it is valid) */
|
||||
if (ext.first != max_framepos) {
|
||||
add_session_range_location (ext.first, ext.second);
|
||||
}
|
||||
|
||||
add_session_range_location (a, b);
|
||||
|
||||
} else {
|
||||
/* update the existing session range */
|
||||
if (ext.first < _session_range_location->start()) {
|
||||
_session_range_location->set_start (ext.first);
|
||||
set_dirty ();
|
||||
|
||||
if (a < _session_range_location->start()) {
|
||||
_session_range_location->set_start (a);
|
||||
}
|
||||
|
||||
if (ext.second > _session_range_location->end()) {
|
||||
_session_range_location->set_end (ext.second);
|
||||
set_dirty ();
|
||||
if (b > _session_range_location->end()) {
|
||||
_session_range_location->set_end (b);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/** @return Extent of the session's contents; if the session is empty, the first value of
|
||||
* the pair will equal max_framepos.
|
||||
*/
|
||||
pair<framepos_t, framepos_t>
|
||||
Session::get_extent () const
|
||||
void
|
||||
Session::playlist_ranges_moved (list<Evoral::RangeMove<framepos_t> > const & ranges)
|
||||
{
|
||||
pair<framepos_t, framepos_t> ext (max_framepos, 0);
|
||||
|
||||
boost::shared_ptr<RouteList> rl = routes.reader ();
|
||||
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
|
||||
boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
|
||||
if (!tr || tr->destructive()) {
|
||||
// ignore tape tracks when getting extents
|
||||
continue;
|
||||
}
|
||||
|
||||
pair<framepos_t, framepos_t> e = tr->playlist()->get_extent ();
|
||||
if (e.first < ext.first) {
|
||||
ext.first = e.first;
|
||||
}
|
||||
if (e.second > ext.second) {
|
||||
ext.second = e.second;
|
||||
}
|
||||
for (list<Evoral::RangeMove<framepos_t> >::const_iterator i = ranges.begin(); i != ranges.end(); ++i) {
|
||||
maybe_update_session_range (i->to, i->to + i->length);
|
||||
}
|
||||
|
||||
return ext;
|
||||
}
|
||||
|
||||
/* Region management */
|
||||
|
@ -2363,6 +2363,16 @@ Session::add_commands (vector<Command*> const & cmds)
|
||||
|
||||
void
|
||||
Session::begin_reversible_command (const string& name)
|
||||
{
|
||||
begin_reversible_command (g_quark_from_string (name.c_str ()));
|
||||
}
|
||||
|
||||
/** Begin a reversible command using a GQuark to identify it.
|
||||
* begin_reversible_command() and commit_reversible_command() calls may be nested,
|
||||
* but there must be as many begin...()s as there are commit...()s.
|
||||
*/
|
||||
void
|
||||
Session::begin_reversible_command (GQuark q)
|
||||
{
|
||||
/* If nested begin/commit pairs are used, we create just one UndoTransaction
|
||||
to hold all the commands that are committed. This keeps the order of
|
||||
@ -2371,20 +2381,19 @@ Session::begin_reversible_command (const string& name)
|
||||
|
||||
if (_current_trans == 0) {
|
||||
/* start a new transaction */
|
||||
assert (_current_trans_depth == 0);
|
||||
assert (_current_trans_quarks.empty ());
|
||||
_current_trans = new UndoTransaction();
|
||||
_current_trans->set_name (name);
|
||||
} else {
|
||||
/* use the existing transaction */
|
||||
++_current_trans_depth;
|
||||
_current_trans->set_name (g_quark_to_string (q));
|
||||
}
|
||||
|
||||
_current_trans_quarks.push_front (q);
|
||||
}
|
||||
|
||||
void
|
||||
Session::commit_reversible_command (Command *cmd)
|
||||
{
|
||||
assert (_current_trans);
|
||||
assert (_current_trans_depth > 0);
|
||||
assert (!_current_trans_quarks.empty ());
|
||||
|
||||
struct timeval now;
|
||||
|
||||
@ -2392,9 +2401,9 @@ Session::commit_reversible_command (Command *cmd)
|
||||
_current_trans->add_command (cmd);
|
||||
}
|
||||
|
||||
--_current_trans_depth;
|
||||
_current_trans_quarks.pop_front ();
|
||||
|
||||
if (_current_trans_depth > 0) {
|
||||
if (!_current_trans_quarks.empty ()) {
|
||||
/* the transaction we're committing is not the top-level one */
|
||||
return;
|
||||
}
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "ardour/location.h"
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/slave.h"
|
||||
#include "ardour/operations.h"
|
||||
|
||||
#include "i18n.h"
|
||||
|
||||
@ -435,7 +436,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
|
||||
reset_rf_scale (0);
|
||||
|
||||
if (did_record) {
|
||||
begin_reversible_command ("capture");
|
||||
begin_reversible_command (Operations::capture);
|
||||
_have_captured = true;
|
||||
}
|
||||
|
||||
|
@ -136,6 +136,7 @@ libardour_sources = [
|
||||
'mute_master.cc',
|
||||
'named_selection.cc',
|
||||
'onset_detector.cc',
|
||||
'operations.cc',
|
||||
'panner.cc',
|
||||
'pcm_utils.cc',
|
||||
'pi_controller.cc',
|
||||
|
Loading…
Reference in New Issue
Block a user