fix ordering of cut/copied regions when pasting; ctrl-click now does the right thing...
authorPaul Davis <paul@linuxaudiosystems.com>
Wed, 17 Jan 2007 01:42:44 +0000 (01:42 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Wed, 17 Jan 2007 01:42:44 +0000 (01:42 +0000)
git-svn-id: svn://localhost/ardour2/trunk@1331 d708f5d6-7413-0410-9779-e7cbd77b26cf

13 files changed:
gtk2_ardour/actions.cc
gtk2_ardour/ardour_ui_options.cc
gtk2_ardour/editor.cc
gtk2_ardour/editor.h
gtk2_ardour/editor_keyboard.cc
gtk2_ardour/editor_mixer.cc
gtk2_ardour/editor_ops.cc
gtk2_ardour/region_selection.cc
gtk2_ardour/region_selection.h
gtk2_ardour/time_axis_view_item.h
libs/ardour/ardour/configuration_variable.h
libs/ardour/configuration.cc
libs/ardour/session.cc

index 2fe305cf84b8e07e52fe641f75fcd6d0e1e29fd7..d38287858248d8c707c1626bce5f082cbad9d063 100644 (file)
@@ -266,7 +266,7 @@ ActionManager::toggle_config_state (const char* group, const char* action, bool
                
                if (tact) {
                        bool x = (Config->*get)();
-
+                       
                        if (x != tact->get_active()) {
                                (Config->*set) (!x);
                        }
index d0f523481f24485ffd8cc87414dee302c8aeda58..7b8557f18b6fefafb89056f5c1188062608c83e1 100644 (file)
@@ -19,6 +19,7 @@
 */
 
 #include <pbd/convert.h>
+#include <pbd/stacktrace.h>
 
 #include <gtkmm2ext/utils.h>
 
index cd1e9f3f6125402b20ca4da7637c0f8ed6421285..e447603100e6c08ae7431c88dc66da3c3f51cd9f 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <pbd/convert.h>
 #include <pbd/error.h>
+#include <pbd/stacktrace.h>
 #include <pbd/memento_command.h>
 
 #include <gtkmm/image.h>
@@ -3030,7 +3031,6 @@ Editor::mapped_set_selected_regionview_from_click (RouteTimeAxisView& tv, uint32
                return;
        }
 
-       
        if ((pl = ds->playlist()) != 0) {
                pl->get_equivalent_regions (basis->region(), results);
        }
@@ -3052,6 +3052,10 @@ Editor::set_selected_regionview_from_click (bool press, Selection::Operation op,
                return false;
        }
 
+       if (press) {
+               button_release_can_deselect = false;
+       }
+
        if (op == Selection::Toggle || op == Selection::Set) {
                
                mapover_audio_tracks (bind (mem_fun (*this, &Editor::mapped_set_selected_regionview_from_click), 
@@ -4292,3 +4296,17 @@ Editor::idle_visual_changer ()
 
        return 0;
 }
+
+struct EditorOrderTimeAxisSorter {
+    bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
+           return a->order < b->order;
+    }
+};
+       
+void
+Editor::sort_track_selection ()
+{
+       EditorOrderTimeAxisSorter cmp;
+       selection->tracks.sort (cmp);
+}
+
index 241ce808ff7828e321145dfd2b5ab7232edfbcc7..b09f76c9d97d8830d127c9f2b0b87fc30ace7677 100644 (file)
@@ -419,6 +419,8 @@ class Editor : public PublicEditor
        CrossfadeView*     clicked_crossfadeview;
        ControlPoint*      clicked_control_point;
 
+       void sort_track_selection ();
+
        void get_relevant_audio_tracks (std::set<AudioTimeAxisView*>& relevant_tracks);
        void mapover_audio_tracks (sigc::slot<void,AudioTimeAxisView&,uint32_t> sl);
 
index cdea9d22720706b33c5f1a710450950a8a8dd058..bfe61eae5cc165577bee12fd3d585297b57c61e0 100644 (file)
@@ -82,7 +82,7 @@ Editor::kbd_do_split (GdkEvent* ev)
        nframes_t where = event_frame (ev);
 
        if (entered_regionview) {
-               if (selection->regions.find (entered_regionview) != selection->regions.end()) {
+               if (selection->regions.contains (entered_regionview)) {
                        split_regions_at (where, selection->regions);
                } else {
                        RegionSelection s;
index 2d8d04e94a4e066797b0c103c81764a1dd885099..13eafe1602976caadc2c179fc4839ab53c5f4e40 100644 (file)
@@ -77,6 +77,9 @@ Editor::show_editor_mixer (bool yn)
                                }
 
                        } else {
+
+                               sort_track_selection ();
+
                                for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
                                        AudioTimeAxisView* atv;
 
index 2e271d7671faa31ac4892314bf244c12aca354c0..5ab343392a14658e374377efeffc52d6fa9e24c2 100644 (file)
@@ -1351,27 +1351,20 @@ Editor::select_all_within (nframes_t start, nframes_t end, double top, double bo
                (*iter)->get_selectables (start, end, top, bot, touched);
        }
 
-       cerr << "select all within found " << touched.size() << endl;
-
        begin_reversible_command (_("select all within"));
        switch (op) {
        case Selection::Add:
        case Selection::Toggle:
-               cerr << "toggle\n";
                selection->add (touched);
                break;
        case Selection::Set:
-               cerr << "set\n";
                selection->set (touched);
                break;
        case Selection::Extend:
-               cerr << "extend\n";
                /* not defined yet */
                break;
        }
 
-       cerr << "selection now has " << selection->points.size() << endl;
-
        commit_reversible_command ();
        return !touched.empty();
 }
@@ -2166,6 +2159,8 @@ Editor::create_region_from_selection (vector<boost::shared_ptr<AudioRegion> >& n
        nframes_t start = selection->time[clicked_selection].start;
        nframes_t end = selection->time[clicked_selection].end;
        
+       sort_track_selection ();
+
        for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
 
                boost::shared_ptr<AudioRegion> current;
@@ -2227,6 +2222,8 @@ Editor::separate_region_from_selection ()
 
        boost::shared_ptr<Playlist> playlist;
                
+       sort_track_selection ();
+
        for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
 
                AudioTimeAxisView* atv;
@@ -2333,6 +2330,8 @@ Editor::crop_region_to_selection ()
 
        } else {
                
+               sort_track_selection ();
+
                for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
 
                        AudioTimeAxisView* atv;
@@ -2949,17 +2948,33 @@ struct lt_playlist {
     }
 };
        
+struct PlaylistMapping { 
+    TimeAxisView* tv;
+    boost::shared_ptr<AudioPlaylist> pl;
+
+    PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
+};
+
 void
 Editor::cut_copy_regions (CutCopyOp op)
 {
-        typedef std::map<boost::shared_ptr<AudioPlaylist>,boost::shared_ptr<AudioPlaylist> > PlaylistMapping;
-       PlaylistMapping pmap;
-       nframes_t first_position = max_frames;
+       /* we can't use a std::map here because the ordering is important, and we can't trivially sort
+          a map when we want ordered access to both elements. i think.
+       */
+
+       vector<PlaylistMapping> pmap;
 
+       nframes_t first_position = max_frames;
+       
        set<PlaylistState, lt_playlist> freezelist;
        pair<set<PlaylistState, lt_playlist>::iterator,bool> insert_result;
+       
+       /* get ordering correct before we cut/copy */
+       
+       selection->regions.sort_by_position_and_track ();
 
        for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
+
                first_position = min ((*x)->region()->position(), first_position);
 
                if (op == Cut || op == Clear) {
@@ -2972,66 +2987,94 @@ Editor::cut_copy_regions (CutCopyOp op)
                                before.before = &pl->get_state();
                                
                                insert_result = freezelist.insert (before);
-
+                               
                                if (insert_result.second) {
                                        pl->freeze ();
                                }
                        }
                }
+
+               TimeAxisView* tv = &(*x)->get_trackview();
+               vector<PlaylistMapping>::iterator z;
+
+               for (z = pmap.begin(); z != pmap.end(); ++z) {
+                       if ((*z).tv == tv) {
+                               break;
+                       }
+               }
+               
+               if (z == pmap.end()) {
+                       pmap.push_back (PlaylistMapping (tv));
+               }
        }
 
        for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ) {
 
                boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>((*x)->region()->playlist());
+               
+               if (!pl) {
+                       /* impossible, but this handles it for the future */
+                       continue;
+               }
+
+               TimeAxisView& tv = (*x)->get_trackview();
                boost::shared_ptr<AudioPlaylist> npl;
                RegionSelection::iterator tmp;
                
                tmp = x;
                ++tmp;
 
-               if (pl) {
-
-                       PlaylistMapping::iterator pi = pmap.find (pl);
-                       
-                       if (pi == pmap.end()) {
-                               npl = boost::dynamic_pointer_cast<AudioPlaylist> (PlaylistFactory::create (*session, "cutlist", true));
-                               npl->freeze();
-                               pmap[pl] = npl;
-                       } else {
-                               npl = pi->second;
-                       }
-
-                       // FIXME
-                       boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>((*x)->region());
-                       switch (op) {
-                       case Cut:
-                               if (!ar) break;
-
-                               npl->add_region (RegionFactory::create (ar), (*x)->region()->position() - first_position);
-                               pl->remove_region (((*x)->region()));
-                               break;
-
-                       case Copy:
-                               if (!ar) break;
-
-                               npl->add_region (RegionFactory::create (ar), (*x)->region()->position() - first_position);
-                               break;
-
-                       case Clear:
-                               pl->remove_region (((*x)->region()));
+               vector<PlaylistMapping>::iterator z;
+               
+               for (z = pmap.begin(); z != pmap.end(); ++z) {
+                       if ((*z).tv == &tv) {
                                break;
                        }
                }
+               
+               assert (z != pmap.end());
+               
+               if (!(*z).pl) {
+                       npl = boost::dynamic_pointer_cast<AudioPlaylist> (PlaylistFactory::create (*session, "cutlist", true));
+                       npl->freeze();
+                       (*z).pl = npl;
+               } else {
+                       npl = (*z).pl;
+               }
+               
+               boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>((*x)->region());
+               
+               switch (op) {
+               case Cut:
+                       if (!ar) break;
+                       
+                       npl->add_region (RegionFactory::create (ar), (*x)->region()->position() - first_position);
+                       pl->remove_region (((*x)->region()));
+                       break;
+                       
+               case Copy:
+                       if (!ar) break;
+                       
+                       npl->add_region (RegionFactory::create (ar), (*x)->region()->position() - first_position);
+                       break;
+                       
+               case Clear:
+                       pl->remove_region (((*x)->region()));
+                       break;
+               }
 
                x = tmp;
        }
-
+       
        list<boost::shared_ptr<Playlist> > foo;
-
-       for (PlaylistMapping::iterator i = pmap.begin(); i != pmap.end(); ++i) {
-               foo.push_back (i->second);
+       
+       /* the pmap is in the same order as the tracks in which selected regions occured */
+       
+       for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
+               (*i).pl->thaw();
+               foo.push_back ((*i).pl);
        }
-
+       
        if (!foo.empty()) {
                cut_buffer->set (foo);
        }
@@ -3095,15 +3138,19 @@ Editor::paste_internal (nframes_t position, float times)
        TrackSelection::iterator i;
        size_t nth;
 
+       /* get everything in the correct order */
+
+       sort_track_selection ();
+
        for (nth = 0, i = selection->tracks.begin(); i != selection->tracks.end(); ++i, ++nth) {
-               
+
                /* undo/redo is handled by individual tracks */
 
                if ((*i)->paste (position, times, *cut_buffer, nth)) {
                        commit = true;
                }
        }
-
+       
        if (commit) {
                commit_reversible_command ();
        }
@@ -3129,6 +3176,8 @@ Editor::paste_named_selection (float times)
        chunk = ns->playlists.begin();
                
        begin_reversible_command (_("paste chunk"));
+       
+       sort_track_selection ();
 
        for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
                
@@ -3241,8 +3290,6 @@ Editor::reset_point_selection ()
 {
        /* reset all selected points to the relevant default value */
 
-       cerr << "point selection has " << selection->points.size() << " entries\n";
-       
        for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
                
                AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
index a418b1de23623944edcdc4f08fa74c7bcc9f645e..430e1d372881d899a7c0cf26ce46dedb373a8adc 100644 (file)
 
 #include "region_view.h"
 #include "region_selection.h"
+#include "time_axis_view.h"
 
 using namespace ARDOUR;
 using namespace PBD;
 using namespace sigc;
 
 
-bool 
-RegionComparator::operator() (const RegionView* a, const RegionView* b) const
-{
-       if (a == b) {
-               return false;
-       } else {
-               return a < b;
-       }
-}
-
 RegionSelection::RegionSelection ()
 {
        _current_start = 0;
@@ -46,9 +37,8 @@ RegionSelection::RegionSelection ()
 
 RegionSelection::RegionSelection (const RegionSelection& other)
 {
-
        for (RegionSelection::const_iterator i = other.begin(); i != other.end(); ++i) {
-               add (*i, false);
+               add (*i);
        }
        _current_start = other._current_start;
        _current_end = other._current_end;
@@ -64,7 +54,7 @@ RegionSelection::operator= (const RegionSelection& other)
                clear_all();
                
                for (RegionSelection::const_iterator i = other.begin(); i != other.end(); ++i) {
-                       add (*i, false);
+                       add (*i);
                }
 
                _current_start = other._current_start;
@@ -85,11 +75,11 @@ RegionSelection::clear_all()
 
 bool RegionSelection::contains (RegionView* rv)
 {
-       return this->find (rv) != end();
+       return find (begin(), end(), rv) != end();
 }
 
 void
-RegionSelection::add (RegionView* rv, bool dosort)
+RegionSelection::add (RegionView* rv)
 {
        if (contains (rv)) {
                /* we already have it */
@@ -106,11 +96,11 @@ RegionSelection::add (RegionView* rv, bool dosort)
                _current_end = rv->region()->last_frame();
        }
        
-       insert (rv);
+       push_back (rv);
 
        // add to layer sorted list
+
        add_to_layer (rv);
-       
 }
 
 void
@@ -124,7 +114,7 @@ RegionSelection::remove (RegionView* rv)
 {
        RegionSelection::iterator i;
 
-       if ((i = this->find (rv)) != end()) {
+       if ((i = find (begin(), end(), rv)) != end()) {
 
                erase (i);
 
@@ -198,7 +188,7 @@ RegionSelection::add_to_layer (RegionView * rv)
 }
 
 struct RegionSortByTime {
-    bool operator() (const RegionView* a, const RegionView* b) {
+    bool operator() (const RegionView* a, const RegionView* b) const {
            return a->region()->position() < b->region()->position();
     }
 };
@@ -217,3 +207,37 @@ RegionSelection::by_position (list<RegionView*>& foo) const
        foo.sort (sorter);
        return;
 }
+
+struct RegionSortByTrack {
+    bool operator() (const RegionView* a, const RegionView* b) const {
+           
+           /* really, track and position */
+
+           if (a->get_trackview().order == b->get_trackview().order) {
+                   return a->region()->position() < b->region()->position();
+           } else {
+                   return a->get_trackview().order < b->get_trackview().order;
+           }
+    }
+};
+       
+void
+RegionSelection::by_track (list<RegionView*>& foo) const
+{
+       list<RegionView*>::const_iterator i;
+       RegionSortByTrack sorter;
+
+       for (i = _bylayer.begin(); i != _bylayer.end(); ++i) {
+               foo.push_back (*i);
+       }
+
+       foo.sort (sorter);
+       return;
+}
+
+void
+RegionSelection::sort_by_position_and_track ()
+{
+       RegionSortByTrack sorter;
+       sort (sorter);
+}
index 7e1d3b0835fb621a7d8e33aa2bb274842d97bc62..5c05a813f9464127ad7ee5560a21fb4cb2c867d2 100644 (file)
@@ -29,11 +29,7 @@ using std::set;
 
 class RegionView;
 
-struct RegionComparator {
-    bool operator() (const RegionView* a, const RegionView* b) const;
-};
-
-class RegionSelection : public set<RegionView*, RegionComparator>, public sigc::trackable
+class RegionSelection : public std::list<RegionView*>, public sigc::trackable
 {
   public:
        RegionSelection();
@@ -41,9 +37,10 @@ class RegionSelection : public set<RegionView*, RegionComparator>, public sigc::
 
        RegionSelection& operator= (const RegionSelection&);
 
-       void add (RegionView*, bool dosort = true);
+       void add (RegionView*);
        bool remove (RegionView*);
        bool contains (RegionView*);
+       void sort_by_position_and_track ();
 
        void clear_all();
        
@@ -51,14 +48,15 @@ class RegionSelection : public set<RegionView*, RegionComparator>, public sigc::
                return _current_start;
        }
 
-       /* collides with list<>::end */
+       /* "end" collides with list<>::end */
 
        nframes_t end_frame () const { 
                return _current_end;
        }
 
-       const list<RegionView *> & by_layer() const { return _bylayer; }
-       void  by_position (list<RegionView*>&) const;
+       const std::list<RegionView *>& by_layer() const { return _bylayer; }
+       void  by_position (std::list<RegionView*>&) const;
+       void  by_track (std::list<RegionView*>&) const;
        
   private:
        void remove_it (RegionView*);
index e27b944e2a6c59597301c1b50ea183ef96edbd1f..80d917704187a75cdc7ba9ad2d670d712c36d6d9 100644 (file)
@@ -232,6 +232,11 @@ class TimeAxisViewItem : public Selectable
     ArdourCanvas::Text* get_name_text();
 
 
+    /**
+     * Returns the time axis that this item is upon
+     */
+    TimeAxisView& get_trackview() const { return trackview; }
+
     /**
      * Sets the samples per unit of this item.
      * this item is used to determine the relative visual size and position of this item
index 6f0a8a35718ff80a3002a98b488ffba8369316fc..4327fa69b1df9b195a24c708e4c958cf179d828d 100644 (file)
@@ -27,9 +27,13 @@ class ConfigVariableBase {
        virtual void add_to_node (XMLNode& node) = 0;
        virtual bool set_from_node (const XMLNode& node, Owner owner) = 0;
 
+
   protected:
        std::string _name;
        Owner _owner;
+
+       void notify ();
+       void miss ();
 };
 
 template<class T>
@@ -41,10 +45,12 @@ class ConfigVariable : public ConfigVariableBase
 
        virtual bool set (T val, Owner owner) {
                if (val == value) {
+                       miss ();
                        return false;
                }
                value = val;
                _owner = (ConfigVariableBase::Owner)(_owner |owner);
+               notify ();
                return true;
        }
 
index eb3d8794472932bb0f195ddefb89027c4d4d3838..a0f2b5e036139ea7a1452c54d02b334e916b2768 100644 (file)
@@ -317,3 +317,16 @@ Configuration::map_parameters (sigc::slot<void,const char*> theSlot)
 #undef  CONFIG_VARIABLE
 #undef  CONFIG_VARIABLE_SPECIAL        
 }
+
+void
+ConfigVariableBase::notify ()
+{
+       // placeholder for any debugging desired when a config variable is modified
+}
+
+void
+ConfigVariableBase::miss ()
+{
+       // placeholder for any debugging desired when a config variable 
+       // is set but to the same value as it already has
+}
index d49fb2c1164c1f4efac3e5d32bedf434525b0127..eba090665a173559c4a672cac964e0e160e170f7 100644 (file)
@@ -368,7 +368,6 @@ Session::Session (AudioEngine &eng,
                if (master_out_channels) {
                        shared_ptr<Route> r (new Route (*this, _("master"), -1, master_out_channels, -1, master_out_channels, Route::MasterOut));
                        r->set_remote_control_id (control_id);
-                       cerr << "master bus has remote control ID " << r->remote_control_id() << endl;
                         
                        rl.push_back (r);
                } else {
@@ -396,6 +395,8 @@ Session::Session (AudioEngine &eng,
 
        _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
 
+       Config->ParameterChanged.connect (mem_fun (*this, &Session::config_changed));
+
        if (was_dirty) {
                DirtyChanged (); /* EMIT SIGNAL */
        }