summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2011-02-14 21:49:43 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2011-02-14 21:49:43 +0000
commit7a5b6a5031d4c573c90d2455276aa174a665239b (patch)
tree5fe53c6eb77432eeb78d4a8b46dba9112e483885
parent7ac5d03cb870acb429b7fb0c315dd5774d4e0b8c (diff)
patches from lincoln to speed up the regionlist and provide region removal (causes dangling shared ptrs to regions, fix to come
git-svn-id: svn://localhost/ardour2/branches/3.0@8845 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r--gtk2_ardour/ardour.menus.in6
-rw-r--r--gtk2_ardour/audio_region_view.cc116
-rw-r--r--gtk2_ardour/audio_region_view.h4
-rw-r--r--gtk2_ardour/editor.h3
-rw-r--r--gtk2_ardour/editor_actions.cc7
-rw-r--r--gtk2_ardour/editor_drag.cc28
-rw-r--r--gtk2_ardour/editor_drag.h4
-rw-r--r--gtk2_ardour/editor_mouse.cc12
-rw-r--r--gtk2_ardour/editor_ops.cc57
-rw-r--r--gtk2_ardour/editor_regions.cc426
-rw-r--r--gtk2_ardour/editor_regions.h40
-rw-r--r--libs/ardour/ardour/region.h36
-rw-r--r--libs/ardour/ardour/session.h1
-rw-r--r--libs/ardour/region.cc29
-rw-r--r--libs/ardour/session_state.cc28
-rw-r--r--libs/gtkmm2ext/gtk_ui.cc13
16 files changed, 458 insertions, 352 deletions
diff --git a/gtk2_ardour/ardour.menus.in b/gtk2_ardour/ardour.menus.in
index 88a07fcaac..476af838b0 100644
--- a/gtk2_ardour/ardour.menus.in
+++ b/gtk2_ardour/ardour.menus.in
@@ -540,7 +540,7 @@
<menuitem action='rlAudition'/>
<menuitem action='rlHide'/>
<menuitem action='rlShow'/>
- <separator/>
+ <separator/>
<menuitem action='rlShowAll'/>
<menuitem action='rlShowAuto'/>
<menu name='Sort' action='RegionListSort'>
@@ -559,7 +559,9 @@
<menuitem action='SortBySourceFilesystem'/>
</menu>
<separator/>
- <menuitem action='addExternalAudioToRegionList'/>
+ <menuitem action='addExternalAudioToRegionList'/>
+ <separator/>
+ <menuitem action='removeUnusedRegions'/>
</popup>
<popup name='PopupRegionMenu' action='PopupRegionMenu'>
diff --git a/gtk2_ardour/audio_region_view.cc b/gtk2_ardour/audio_region_view.cc
index b72d95ca15..4a5a477a5c 100644
--- a/gtk2_ardour/audio_region_view.cc
+++ b/gtk2_ardour/audio_region_view.cc
@@ -269,10 +269,10 @@ AudioRegionView::~AudioRegionView ()
delete *i;
}
- for (list<std::pair<framepos_t, ArdourCanvas::SimpleLine*> >::iterator i = feature_lines.begin(); i != feature_lines.end(); ++i) {
+ for (list<std::pair<framepos_t, ArdourCanvas::Line*> >::iterator i = feature_lines.begin(); i != feature_lines.end(); ++i) {
delete ((*i).second);
}
-
+
/* all waveviews etc will be destroyed when the group is destroyed */
delete gain_line;
@@ -407,8 +407,8 @@ AudioRegionView::region_resized (const PropertyChange& what_changed)
}
/* hide transient lines that extend beyond the region end */
-
- list<std::pair<framepos_t, ArdourCanvas::SimpleLine*> >::iterator l;
+
+ list<std::pair<framepos_t, ArdourCanvas::Line*> >::iterator l;
for (l = feature_lines.begin(); l != feature_lines.end(); ++l) {
if ((*l).first > _region->length()- 1){
@@ -444,11 +444,19 @@ AudioRegionView::reset_width_dependent_items (double pixel_width)
AnalysisFeatureList analysis_features = _region->transients();
AnalysisFeatureList::const_iterator i;
- list<std::pair<framepos_t, ArdourCanvas::SimpleLine*> >::iterator l;
+
+ list<std::pair<framepos_t, ArdourCanvas::Line*> >::iterator l;
for (i = analysis_features.begin(), l = feature_lines.begin(); i != analysis_features.end() && l != feature_lines.end(); ++i, ++l) {
- (*l).second->property_x1() = trackview.editor().frame_to_pixel (*i);
- (*l).second->property_x2() = trackview.editor().frame_to_pixel (*i);
+
+ float x_pos = trackview.editor().frame_to_pixel (*i);
+
+ ArdourCanvas::Points points;
+ points.push_back(Gnome::Art::Point(x_pos, 2.0)); // first x-coord needs to be a non-normal value
+ points.push_back(Gnome::Art::Point(x_pos, _height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 1));
+
+ (*l).first = *i;
+ (*l).second->property_points() = points;
}
reset_fade_shapes ();
@@ -526,13 +534,22 @@ AudioRegionView::set_height (gdouble height)
reset_fade_shapes ();
/* Update hights for any active feature lines */
- list<std::pair<framepos_t, ArdourCanvas::SimpleLine*> >::iterator l;
-
+ list<std::pair<framepos_t, ArdourCanvas::Line*> >::iterator l;
+
for (l = feature_lines.begin(); l != feature_lines.end(); ++l) {
- (*l).second->property_y2() = _height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 1;
- }
+
+ float pos_x = trackview.editor().frame_to_pixel((*l).first);
+
+ ArdourCanvas::Points points;
+
+ points.push_back(Gnome::Art::Point(pos_x, 2.0)); // first x-coord needs to be a non-normal value
+ points.push_back(Gnome::Art::Point(pos_x, _height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 1));
+
+ (*l).second->property_points() = points;
+ }
if (fade_position_line) {
+
if (height < NAME_HIGHLIGHT_THRESH) {
fade_position_line->property_y2() = _height - 1;
}
@@ -1430,31 +1447,55 @@ AudioRegionView::transients_changed ()
AnalysisFeatureList analysis_features = _region->transients();
while (feature_lines.size() < analysis_features.size()) {
- ArdourCanvas::SimpleLine* l = new ArdourCanvas::SimpleLine (*group);
- l->property_color_rgba() = (guint) ARDOUR_UI::config()->canvasvar_ZeroLine.get();
- feature_lines.push_back (make_pair(0, l));
+
+ ArdourCanvas::Line* canvas_item = new ArdourCanvas::Line(*group);
+
+ ArdourCanvas::Points points;
+
+ points.push_back(Gnome::Art::Point(-1.0, 2.0)); // first x-coord needs to be a non-normal value
+ points.push_back(Gnome::Art::Point(1.0, _height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 1));
+
+ canvas_item->property_points() = points;
+ canvas_item->property_width_pixels() = 1;
+ canvas_item->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_ZeroLine.get();
+ canvas_item->property_first_arrowhead() = TRUE;
+ canvas_item->property_last_arrowhead() = TRUE;
+ canvas_item->property_arrow_shape_a() = 11.0;
+ canvas_item->property_arrow_shape_b() = 0.0;
+ canvas_item->property_arrow_shape_c() = 4.0;
+
+ canvas_item->raise_to_top ();
+ canvas_item->show ();
+
+ canvas_item->set_data ("regionview", this);
+ canvas_item->signal_event().connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_feature_line_event), canvas_item, this));
+
+ feature_lines.push_back (make_pair(0, canvas_item));
}
while (feature_lines.size() > analysis_features.size()) {
- ArdourCanvas::SimpleLine *line = feature_lines.back().second;
+ ArdourCanvas::Line* line = feature_lines.back().second;
feature_lines.pop_back ();
delete line;
}
AnalysisFeatureList::const_iterator i;
- list<std::pair<framepos_t, ArdourCanvas::SimpleLine*> >::iterator l;
-
+ list<std::pair<framepos_t, ArdourCanvas::Line*> >::iterator l;
+
for (i = analysis_features.begin(), l = feature_lines.begin(); i != analysis_features.end() && l != feature_lines.end(); ++i, ++l) {
- (*l).first = *i;
- (*l).second->property_x1() = trackview.editor().frame_to_pixel (*i);
- (*l).second->property_x2() = trackview.editor().frame_to_pixel (*i);
- (*l).second->property_y1() = 2;
- (*l).second->property_y2() = _height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 1;
- (*l).second->set_data("regionview", this);
- (*l).second->show ();
- (*l).second->raise_to_top ();
+
+ ArdourCanvas::Points points;
+
+ float *pos = new float;
+ *pos = trackview.editor().frame_to_pixel (*i);
- (*l).second->signal_event().connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_feature_line_event), (*l).second, this));
+ points.push_back(Gnome::Art::Point(*pos, 2.0)); // first x-coord needs to be a non-normal value
+ points.push_back(Gnome::Art::Point(*pos, _height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 1));
+
+ (*l).second->property_points() = points;
+ (*l).second->set_data ("position", pos);
+
+ (*l).first = *i;
}
}
@@ -1462,12 +1503,16 @@ void
AudioRegionView::update_transient(float /*old_pos*/, float new_pos)
{
/* Find frame at old pos, calulate new frame then update region transients*/
- list<std::pair<framepos_t, ArdourCanvas::SimpleLine*> >::iterator l;
+ list<std::pair<framepos_t, ArdourCanvas::Line*> >::iterator l;
for (l = feature_lines.begin(); l != feature_lines.end(); ++l) {
- /* Simple line x1 has been updated in drag so we compare to new_pos */
- if (rint(new_pos) == rint((*l).second->property_x1())) {
-
+
+ /* Line has been updated in drag so we compare to new_pos */
+
+ float* pos = (float*) (*l).second->get_data ("position");
+
+ if (rint(new_pos) == rint(*pos)) {
+
framepos_t old_frame = (*l).first;
framepos_t new_frame = trackview.editor().pixel_to_frame (new_pos);
@@ -1482,12 +1527,15 @@ void
AudioRegionView::remove_transient(float pos)
{
/* Find frame at old pos, calulate new frame then update region transients*/
- list<std::pair<framepos_t, ArdourCanvas::SimpleLine*> >::iterator l;
+ list<std::pair<framepos_t, ArdourCanvas::Line*> >::iterator l;
for (l = feature_lines.begin(); l != feature_lines.end(); ++l) {
- /* Simple line x1 has been updated in drag so we compare to new_pos */
- if (rint(pos) == rint((*l).second->property_x1())) {
- _region->remove_transient ((*l).first);
+
+ /* Line has been updated in drag so we compare to new_pos */
+ float *line_pos = (float*) (*l).second->get_data ("position");
+
+ if (rint(pos) == rint(*line_pos)) {
+ _region->remove_transient ((*l).first);
break;
}
}
diff --git a/gtk2_ardour/audio_region_view.h b/gtk2_ardour/audio_region_view.h
index f7b8404d7b..a2ec896a16 100644
--- a/gtk2_ardour/audio_region_view.h
+++ b/gtk2_ardour/audio_region_view.h
@@ -135,9 +135,9 @@ class AudioRegionView : public RegionView
std::vector<ArdourCanvas::WaveView *> waves;
std::vector<ArdourCanvas::WaveView *> tmp_waves; ///< see ::create_waves()
+
+ std::list<std::pair<framepos_t, ArdourCanvas::Line*> > feature_lines;
- std::list<std::pair<framepos_t, ArdourCanvas::SimpleLine*> > feature_lines;
-
ArdourCanvas::Polygon* sync_mark; ///< polgyon for sync position
ArdourCanvas::SimpleLine* zero_line;
ArdourCanvas::Polygon* fade_in_shape;
diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h
index 256c8e296c..6903cd20c9 100644
--- a/gtk2_ardour/editor.h
+++ b/gtk2_ardour/editor.h
@@ -1385,6 +1385,9 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
bool canvas_markerview_item_view_event(GdkEvent* event, ArdourCanvas::Item*,MarkerView*);
bool canvas_markerview_start_handle_event(GdkEvent* event, ArdourCanvas::Item*,MarkerView*);
bool canvas_markerview_end_handle_event(GdkEvent* event, ArdourCanvas::Item*,MarkerView*);
+
+ PBD::Signal0<void> EditorFreeze;
+ PBD::Signal0<void> EditorThaw;
private:
friend class DragManager;
diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc
index 6f1579bb5a..c3a62cb63f 100644
--- a/gtk2_ardour/editor_actions.cc
+++ b/gtk2_ardour/editor_actions.cc
@@ -631,13 +631,16 @@ Editor::register_actions ()
act = ActionManager::register_action (rl_actions, X_("rlAudition"), _("Audition"), sigc::mem_fun(*this, &Editor::audition_region_from_region_list));
ActionManager::region_list_selection_sensitive_actions.push_back (act);
+
act = ActionManager::register_action (rl_actions, X_("rlHide"), _("Hide"), sigc::mem_fun(*this, &Editor::hide_region_from_region_list));
ActionManager::region_list_selection_sensitive_actions.push_back (act);
+
act = ActionManager::register_action (rl_actions, X_("rlShow"), _("Show"), sigc::mem_fun(*this, &Editor::show_region_in_region_list));
ActionManager::region_list_selection_sensitive_actions.push_back (act);
+
ActionManager::register_toggle_action (rl_actions, X_("rlShowAll"), _("Show All"), sigc::mem_fun(*_regions, &EditorRegions::toggle_full));
ActionManager::register_toggle_action (rl_actions, X_("rlShowAuto"), _("Show Automatic Regions"), sigc::mem_fun (*_regions, &EditorRegions::toggle_show_auto_regions));
-
+
ActionManager::register_radio_action (rl_actions, sort_order_group, X_("SortAscending"), _("Ascending"),
sigc::bind (sigc::mem_fun (*_regions, &EditorRegions::reset_sort_direction), true));
ActionManager::register_radio_action (rl_actions, sort_order_group, X_("SortDescending"), _("Descending"),
@@ -664,6 +667,7 @@ Editor::register_actions ()
ActionManager::register_radio_action (rl_actions, sort_type_group, X_("SortBySourceFilesystem"), _("By Source Filesystem"),
sigc::bind (sigc::mem_fun (*_regions, &EditorRegions::reset_sort_type), BySourceFileFS, false));
+ ActionManager::register_action (rl_actions, X_("removeUnusedRegions"), _("Delete Unused"), sigc::mem_fun(*_regions, &EditorRegions::delete_unused_regions));
/* the next two are duplicate items with different names for use in two different contexts */
@@ -747,6 +751,7 @@ Editor::toggle_ruler_visibility (RulerType rt)
}
Glib::RefPtr<Action> act = ActionManager::get_action (X_("Rulers"), action);
+
if (act) {
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
update_ruler_visibility ();
diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc
index b06545c32b..f0e53ab584 100644
--- a/gtk2_ardour/editor_drag.cc
+++ b/gtk2_ardour/editor_drag.cc
@@ -2900,7 +2900,7 @@ FeatureLineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
{
Drag::start_grab (event);
- _line = reinterpret_cast<SimpleLine*> (_item);
+ _line = reinterpret_cast<Line*> (_item);
assert (_line);
/* need to get x coordinate in terms of parent (AudioRegionView) origin. */
@@ -2913,10 +2913,10 @@ FeatureLineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
/* store grab start in parent frame */
_region_view_grab_x = cx;
- _before = _line->property_x1();
+ _before = *(float*) _item->get_data ("position");
_arv = reinterpret_cast<AudioRegionView*> (_item->get_data ("regionview"));
-
+
_max_x = _editor->frame_to_pixel(_arv->get_duration());
}
@@ -2938,17 +2938,30 @@ FeatureLineDrag::motion (GdkEvent*, bool)
cx = 0;
}
- _line->property_x1() = cx;
- _line->property_x2() = cx;
+ ArdourCanvas::Points points;
+
+ double x1 = 0, x2 = 0, y1 = 0, y2 = 0;
+
+ _line->get_bounds(x1, y2, x2, y2);
+
+ points.push_back(Gnome::Art::Point(cx, 2.0)); // first x-coord needs to be a non-normal value
+ points.push_back(Gnome::Art::Point(cx, y2 - y1));
- _before = _line->property_x1();
+ _line->property_points() = points;
+
+ float *pos = new float;
+ *pos = cx;
+
+ _line->set_data ("position", pos);
+
+ _before = cx;
}
void
FeatureLineDrag::finished (GdkEvent*, bool)
{
_arv = reinterpret_cast<AudioRegionView*> (_item->get_data ("regionview"));
- _arv->update_transient(_before, _line->property_x1());
+ _arv->update_transient(_before, _before);
}
void
@@ -3049,6 +3062,7 @@ RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
}
_editor->commit_reversible_command ();
+
} else {
if (!getenv("ARDOUR_SAE")) {
_editor->selection->clear_tracks();
diff --git a/gtk2_ardour/editor_drag.h b/gtk2_ardour/editor_drag.h
index ab81db5a63..ce8a1370f4 100644
--- a/gtk2_ardour/editor_drag.h
+++ b/gtk2_ardour/editor_drag.h
@@ -731,13 +731,13 @@ public:
private:
- ArdourCanvas::SimpleLine* _line;
+ ArdourCanvas::Line* _line;
AudioRegionView* _arv;
double _region_view_grab_x;
double _cumulative_x_drag;
- uint32_t _before;
+ float _before;
uint32_t _max_x;
};
diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc
index 2769a80570..6e5f8071b0 100644
--- a/gtk2_ardour/editor_mouse.cc
+++ b/gtk2_ardour/editor_mouse.cc
@@ -1462,7 +1462,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
break;
case MouseAudition:
- set_canvas_cursor (current_canvas_cursor);
+ set_canvas_cursor (current_canvas_cursor);
if (scrubbing_direction == 0) {
/* no drag, just a click */
switch (item_type) {
@@ -1714,8 +1714,8 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
break;
case FeatureLineItem:
{
- ArdourCanvas::SimpleLine *line = dynamic_cast<ArdourCanvas::SimpleLine *> (item);
- line->property_color_rgba() = 0xFF0000FF;
+ ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
+ line->property_fill_color_rgba() = 0xFF0000FF;
}
break;
case SelectionItem:
@@ -1874,8 +1874,8 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
break;
case FeatureLineItem:
{
- ArdourCanvas::SimpleLine *line = dynamic_cast<ArdourCanvas::SimpleLine *> (item);
- line->property_color_rgba() = (guint) ARDOUR_UI::config()->canvasvar_ZeroLine.get();;
+ ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
+ line->property_fill_color_rgba() = (guint) ARDOUR_UI::config()->canvasvar_ZeroLine.get();;
}
break;
@@ -2477,7 +2477,7 @@ Editor::mouse_brush_insert_region (RegionView* rv, framepos_t pos)
double speed = rtv->track()->speed();
playlist->clear_changes ();
- boost::shared_ptr<Region> new_region (RegionFactory::create (rv->region()));
+ boost::shared_ptr<Region> new_region (RegionFactory::create (rv->region(), true));
playlist->add_region (new_region, (framepos_t) (pos * speed));
_session->add_command (new StatefulDiffCommand (playlist));
diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc
index d15180fd42..ede62d8d9b 100644
--- a/gtk2_ardour/editor_ops.cc
+++ b/gtk2_ardour/editor_ops.cc
@@ -120,6 +120,8 @@ Editor::redo (uint32_t n)
void
Editor::split_regions_at (framepos_t where, RegionSelection& regions)
{
+ bool frozen = false;
+
list <boost::shared_ptr<Playlist > > used_playlists;
if (regions.empty()) {
@@ -142,6 +144,9 @@ Editor::split_regions_at (framepos_t where, RegionSelection& regions)
}
} else {
snap_to (where);
+
+ frozen = true;
+ EditorFreeze(); /* Emit Signal */
}
for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
@@ -191,6 +196,10 @@ Editor::split_regions_at (framepos_t where, RegionSelection& regions)
}
commit_reversible_command ();
+
+ if (frozen){
+ EditorThaw(); /* Emit Signal */
+ }
}
boost::shared_ptr<Region>
@@ -5851,8 +5860,9 @@ Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList
plist.add (ARDOUR::Properties::layer, 0);
boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
+
pl->add_region (nr, r->position() + pos);
-
+
if (select_new) {
new_regions.push_front(nr);
}
@@ -5924,16 +5934,18 @@ Editor::remove_transient(ArdourCanvas::Item* item)
return;
}
- ArdourCanvas::SimpleLine* _line = reinterpret_cast<ArdourCanvas::SimpleLine*> (item);
+ ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
assert (_line);
AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
- _arv->remove_transient(_line->property_x1());
+ _arv->remove_transient (*(float*) _line->get_data ("position"));
}
void
Editor::snap_regions_to_grid ()
{
+ list <boost::shared_ptr<Playlist > > used_playlists;
+
RegionSelection rs = get_regions_from_selection_and_entered ();
if (!_session || rs.empty()) {
@@ -5943,17 +5955,36 @@ Editor::snap_regions_to_grid ()
_session->begin_reversible_command (_("snap regions to grid"));
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
+
+ boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
+
+ if (!pl->frozen()) {
+ /* we haven't seen this playlist before */
+
+ /* remember used playlists so we can thaw them later */
+ used_playlists.push_back(pl);
+ pl->freeze();
+ }
+
framepos_t start_frame = (*r)->region()->first_frame ();
snap_to (start_frame);
(*r)->region()->set_position (start_frame, this);
}
+ while (used_playlists.size() > 0) {
+ list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
+ (*i)->thaw();
+ used_playlists.pop_front();
+ }
+
_session->commit_reversible_command ();
}
void
Editor::close_region_gaps ()
-{
+{
+ list <boost::shared_ptr<Playlist > > used_playlists;
+
RegionSelection rs = get_regions_from_selection_and_entered ();
if (!_session || rs.empty()) {
@@ -6007,13 +6038,23 @@ Editor::close_region_gaps ()
/* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
_session->begin_reversible_command (_("close region gaps"));
-
+
int idx = 0;
boost::shared_ptr<Region> last_region;
rs.sort_by_position_and_track();
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
+
+ boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
+
+ if (!pl->frozen()) {
+ /* we haven't seen this playlist before */
+
+ /* remember used playlists so we can thaw them later */
+ used_playlists.push_back(pl);
+ pl->freeze();
+ }
framepos_t position = (*r)->region()->position();
@@ -6031,6 +6072,12 @@ Editor::close_region_gaps ()
idx++;
}
+ while (used_playlists.size() > 0) {
+ list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
+ (*i)->thaw();
+ used_playlists.pop_front();
+ }
+
_session->commit_reversible_command ();
}
diff --git a/gtk2_ardour/editor_regions.cc b/gtk2_ardour/editor_regions.cc
index 357bb7295e..e4798650b1 100644
--- a/gtk2_ardour/editor_regions.cc
+++ b/gtk2_ardour/editor_regions.cc
@@ -34,6 +34,7 @@
#include "ardour/silentfilesource.h"
#include "ardour/profile.h"
+#include "gtkmm2ext/choice.h"
#include "gtkmm2ext/treeutils.h"
#include "editor.h"
@@ -72,6 +73,7 @@ EditorRegions::EditorRegions (Editor* e)
_display.set_size_request (100, -1);
_display.set_name ("RegionListDisplay");
_display.set_rules_hint (true);
+
/* Try to prevent single mouse presses from initiating edits.
This relies on a hack in gtktreeview.c:gtk_treeview_button_press()
*/
@@ -117,24 +119,28 @@ EditorRegions::EditorRegions (Editor* e)
CellRendererToggle* locked_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (7));
locked_cell->property_activatable() = true;
locked_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRegions::locked_changed));
+
TreeViewColumn* locked_col = _display.get_column (7);
locked_col->add_attribute (locked_cell->property_visible(), _columns.property_toggles_visible);
CellRendererToggle* glued_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (8));
glued_cell->property_activatable() = true;
glued_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRegions::glued_changed));
+
TreeViewColumn* glued_col = _display.get_column (8);
glued_col->add_attribute (glued_cell->property_visible(), _columns.property_toggles_visible);
CellRendererToggle* muted_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (9));
muted_cell->property_activatable() = true;
muted_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRegions::muted_changed));
+
TreeViewColumn* muted_col = _display.get_column (9);
muted_col->add_attribute (muted_cell->property_visible(), _columns.property_toggles_visible);
CellRendererToggle* opaque_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (10));
opaque_cell->property_activatable() = true;
opaque_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRegions::opaque_changed));
+
TreeViewColumn* opaque_col = _display.get_column (10);
opaque_col->add_attribute (opaque_cell->property_visible(), _columns.property_toggles_visible);
@@ -171,6 +177,9 @@ EditorRegions::EditorRegions (Editor* e)
ARDOUR_UI::instance()->secondary_clock.mode_changed.connect (sigc::mem_fun(*this, &EditorRegions::update_all_rows));
ARDOUR::Region::RegionPropertyChanged.connect (region_property_connection, MISSING_INVALIDATOR, ui_bind (&EditorRegions::region_changed, this, _1, _2), gui_context());
ARDOUR::RegionFactory::CheckNewRegion.connect (check_new_region_connection, MISSING_INVALIDATOR, ui_bind (&EditorRegions::add_region, this, _1), gui_context());
+
+ e->EditorFreeze.connect (editor_freeze_connection, MISSING_INVALIDATOR, ui_bind (&EditorRegions::freeze_tree_model, this), gui_context());
+ e->EditorThaw.connect (editor_thaw_connection, MISSING_INVALIDATOR, ui_bind (&EditorRegions::thaw_tree_model, this), gui_context());
}
bool
@@ -238,14 +247,6 @@ EditorRegions::set_session (ARDOUR::Session* s)
}
void
-EditorRegions::add_regions (vector<boost::shared_ptr<Region> >& regions)
-{
- for (vector<boost::shared_ptr<Region> >::iterator x = regions.begin(); x != regions.end(); ++x) {
- add_region (*x);
- }
-}
-
-void
EditorRegions::add_region (boost::shared_ptr<Region> region)
{
if (!region || !_session) {
@@ -262,6 +263,7 @@ EditorRegions::add_region (boost::shared_ptr<Region> region)
}
if (region->hidden()) {
+
TreeModel::iterator iter = _model->get_iter ("0");
TreeModel::Row parent;
TreeModel::Row child;
@@ -282,6 +284,7 @@ EditorRegions::add_region (boost::shared_ptr<Region> region)
parent = *iter;
}
}
+
row = *(_model->append (parent.children()));
} else if (region->whole_file()) {
@@ -357,31 +360,29 @@ EditorRegions::add_region (boost::shared_ptr<Region> region)
}
}
- if (region->automatic()) {
- return;
- }
-
- } else {
+ region_row_map.insert(pair<boost::shared_ptr<ARDOUR::Region>, Gtk::TreeModel::RowReference>(region, TreeRowReference(_model, TreePath (row))) );
+ parent_regions_sources_map.insert(pair<string, Gtk::TreeModel::RowReference>(region->source_string(), TreeRowReference(_model, TreePath (row))) );
- /* find parent node, add as new child */
+ return;
+ } else {
+ // find parent node, add as new child
TreeModel::iterator i;
TreeModel::Children rows = _model->children();
- bool found_parent = false;
-
- for (i = rows.begin(); i != rows.end(); ++i) {
- boost::shared_ptr<Region> r = (*i)[_columns.region];
-
- if (r && r->whole_file()) {
-
- if (region->source_equivalent (r)) {
- found_parent = true;
- }
- }
+ boost::unordered_map<string, Gtk::TreeModel::RowReference>::iterator it;
+
+ it = parent_regions_sources_map.find (region->source_string());
+
+ if (it != parent_regions_sources_map.end()){
+
+ TreeModel::iterator j = _model->get_iter ((*it).second.get_path());
+
TreeModel::iterator ii;
- TreeModel::Children subrows = (*i).children();
+ TreeModel::Children subrows = (*j).children();
+ /* XXXX: should we be accounting for all regions? */
+ /*
for (ii = subrows.begin(); ii != subrows.end(); ++ii) {
boost::shared_ptr<Region> rr = (*ii)[_columns.region];
@@ -389,15 +390,12 @@ EditorRegions::add_region (boost::shared_ptr<Region> region)
return;
}
}
-
- if (found_parent) {
- row = *(_model->append ((*i).children()));
- break;
- }
+ */
+
+ row = *(_model->insert (subrows.end()));
}
-
- if (!found_parent) {
- row = *(_model->append());
+ else {
+ row = *(_model->append());
}
row[_columns.property_toggles_visible] = true;
@@ -405,10 +403,38 @@ EditorRegions::add_region (boost::shared_ptr<Region> region)
row[_columns.region] = region;
+ region_row_map.insert(pair<boost::shared_ptr<ARDOUR::Region>, Gtk::TreeModel::RowReference>(region, TreeRowReference(_model, TreePath (row))) );
+
populate_row(region, (*row));
}
void
+EditorRegions::delete_unused_regions ()
+{
+ vector<string> choices;
+ string prompt;
+
+ if (!_session) {
+ return;
+ }
+
+ prompt = _("Do you really want to remove unused regions?"
+ "\n(This is destructive and cannot be undone)");
+
+ choices.push_back (_("No, do nothing."));
+ choices.push_back (_("Yes, remove."));
+
+ Gtkmm2ext::Choice prompter (_("Remove unused regions"), prompt, choices);
+
+ if (prompter.run () == 1) {
+ _no_redisplay = true;
+ _session->cleanup_regions ();
+ _no_redisplay = false;
+ redisplay ();
+ }
+}
+
+void
EditorRegions::region_changed (boost::shared_ptr<Region> r, const PropertyChange& what_changed)
{
PropertyChange our_interests;
@@ -424,101 +450,48 @@ EditorRegions::region_changed (boost::shared_ptr<Region> r, const PropertyChange
our_interests.add (ARDOUR::Properties::fade_in);
our_interests.add (ARDOUR::Properties::fade_out);
- if (last_row != 0) {
-
- TreeModel::iterator j = _model->get_iter (last_row.get_path());
- boost::shared_ptr<Region> c = (*j)[_columns.region];
-
- if (c == r) {
- populate_row (r, (*j));
-
- if (what_changed.contains (ARDOUR::Properties::hidden)) {
- redisplay ();
- }
-
- return;
- }
- }
-
if (what_changed.contains (our_interests)) {
- /* find the region in our model and update its row */
- TreeModel::Children rows = _model->children ();
- TreeModel::iterator i = rows.begin ();
-
- while (i != rows.end ()) {
+ if (last_row != 0) {
- TreeModel::Children children = (*i)->children ();
- TreeModel::iterator found = children.end ();
-
- boost::shared_ptr<Region> c = (*i)[_columns.region];
+ TreeModel::iterator j = _model->get_iter (last_row.get_path());
+ boost::shared_ptr<Region> c = (*j)[_columns.region];
if (c == r) {
-
- /* check this row */
- last_row = TreeRowReference (_model, TreePath (i));
- found = i;
-
- } else {
-
- /* check its children */
+ populate_row (r, (*j));
- found = children.begin ();
- while (found != children.end()) {
-
- boost::shared_ptr<Region> c = (*found)[_columns.region];
-
- if (c == r) {
- last_row = TreeRowReference(_model, TreePath (found));
- break;
- }
- ++found;
+ if (what_changed.contains (ARDOUR::Properties::hidden)) {
+ redisplay ();
}
+
+ return;
}
+ }
+
+ RegionRowMap::iterator it;
+
+ it = region_row_map.find (r);
+
+ if (it != region_row_map.end()){
- if (found != children.end()) {
-
- boost::shared_ptr<AudioRegion> audioregion = boost::dynamic_pointer_cast<AudioRegion>(r);
- uint32_t used = _editor->get_regionview_count_from_region_list (r);
+ TreeModel::iterator j = _model->get_iter ((*it).second.get_path());
+ boost::shared_ptr<Region> c = (*j)[_columns.region];
- if (what_changed.contains (ARDOUR::Properties::name)) {
- populate_row_name (r, *found);
- }
- if (what_changed.contains (ARDOUR::Properties::position)) {
- populate_row_position (r, *found, used);
- populate_row_end (r, *found, used);
- }
- if (what_changed.contains (ARDOUR::Properties::length)) {
- populate_row_end (r, *found, used);
- populate_row_length (r, *found);
- }
- if (what_changed.contains (ARDOUR::Properties::start)) {
- populate_row_length (r, *found);
- }
- if (what_changed.contains (ARDOUR::Properties::locked)) {
- populate_row_locked (r, *found, used);
- }
- if (what_changed.contains (ARDOUR::Properties::position_lock_style)) {
- populate_row_glued (r, *found, used);
- }
- if (what_changed.contains (ARDOUR::Properties::muted)) {
- populate_row_muted (r, *found, used);
- }
- if (what_changed.contains (ARDOUR::Properties::opaque)) {
- populate_row_opaque (r, *found, used);
- }
- if (what_changed.contains (ARDOUR::Properties::fade_in)) {
- populate_row_fade_in (r, *found, used, audioregion);
- }
- if (what_changed.contains (ARDOUR::Properties::fade_out)) {
- populate_row_fade_out (r, *found, used, audioregion);
+ if (c == r) {
+ populate_row (r, (*j));
+
+ if (what_changed.contains (ARDOUR::Properties::hidden)) {
+ redisplay ();
}
+
+ return;
+ }
+ }
- break;
- }
+ /* find the region in our model and update its row */
+ TreeModel::Children rows = _model->children ();
+ TreeModel::iterator i = rows.begin ();
- ++i;
- }
}
if (what_changed.contains (ARDOUR::Properties::hidden)) {
@@ -576,67 +549,19 @@ EditorRegions::selection_changed ()
void
EditorRegions::set_selected (RegionSelection& regions)
{
- TreeModel::Children rows = _model->children();
-
- for (RegionSelection::iterator iter = regions.begin(); iter != regions.end(); ++iter) {
+ for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
- TreeModel::iterator i;
+ boost::shared_ptr<Region> r ((*i)->region());
- boost::shared_ptr<Region> r ((*iter)->region());
-
- for (i = rows.begin(); i != rows.end(); ++i) {
-
- boost::shared_ptr<Region> compared_region = (*i)[_columns.region];
-
- if (r == compared_region) {
- _display.get_selection()->select(*i);
- break;
- }
-
- if (!(*i).children().empty()) {
- if (set_selected_in_subrow(r, (*i), 2)) {
- break;
- }
- }
- }
- }
-}
-
-bool
-EditorRegions::set_selected_in_subrow (boost::shared_ptr<Region> region, TreeModel::Row const &parent_row, int level)
-{
- TreeModel::iterator i;
- TreeModel::Children subrows = (*parent_row).children();
-
- for (i = subrows.begin(); i != subrows.end(); ++i) {
-
- boost::shared_ptr<Region> compared_region = (*i)[_columns.region];
-
- if (region == compared_region) {
- _display.get_selection()->select(*i);
- return true;
- }
+ RegionRowMap::iterator it;
+
+ it = region_row_map.find (r);
- if (!(*i).children().empty()) {
- if (set_selected_in_subrow (region, (*i), level + 1)) {
- return true;
- }
+ if (it != region_row_map.end()){
+ TreeModel::iterator j = _model->get_iter ((*it).second.get_path());
+ _display.get_selection()->select(*j);
}
}
-
- return false;
-}
-
-void
-EditorRegions::insert_into_tmp_regionlist(boost::shared_ptr<Region> region)
-{
- /* keep all whole files at the beginning */
-
- if (region->whole_file()) {
- tmp_region_list.push_front (region);
- } else {
- tmp_region_list.push_back (region);
- }
}
void
@@ -655,23 +580,36 @@ EditorRegions::redisplay ()
_display.set_model (Glib::RefPtr<Gtk::TreeStore>(0));
_model->clear ();
+ _model->set_sort_column (-2, SORT_ASCENDING); //Disable sorting to gain performance
+
+ region_row_map.clear();
+ parent_regions_sources_map.clear();
+
/* now add everything we have, via a temporary list used to help with sorting */
- tmp_region_list.clear();
-
const RegionFactory::RegionMap& regions (RegionFactory::regions());
+
for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
- insert_into_tmp_regionlist (i->second);
+
+ if ( i->second->whole_file()) {
+ /* add automatic regions first so that children can find their parents as we add them */
+ add_region (i->second);
+ continue;
+ }
+
+ tmp_region_list.push_front (i->second);
}
for (list<boost::shared_ptr<Region> >::iterator r = tmp_region_list.begin(); r != tmp_region_list.end(); ++r) {
add_region (*r);
}
- tmp_region_list.clear();
-
+
+ _model->set_sort_column (0, SORT_ASCENDING); // renabale sorting
_display.set_model (_model);
+ tmp_region_list.clear();
+
if (tree_expanded) {
_display.expand_all();
}
@@ -684,59 +622,15 @@ EditorRegions::update_row (boost::shared_ptr<Region> region)
return;
}
- TreeModel::iterator i;
- TreeModel::Children rows = _model->children();
+ RegionRowMap::iterator it;
- return;
+ it = region_row_map.find (region);
- for (i = rows.begin(); i != rows.end(); ++i) {
+ if (it != region_row_map.end()){
-// cerr << "Level 1: Compare " << region->name() << " with parent " << (*i)[_columns.name] << "\n";
-
- boost::shared_ptr<Region> compared_region = (*i)[_columns.region];
-
- if (region == compared_region) {
-// cerr << "Matched\n";
- populate_row(region, (*i));
- return;
- }
-
- if (!(*i).children().empty()) {
- if (update_subrows(region, (*i), 2)) {
- return;
- }
- }
+ TreeModel::iterator j = _model->get_iter ((*it).second.get_path());
+ populate_row(region, (*j));
}
-
-// cerr << "Returning - No match\n";
-}
-
-bool
-EditorRegions::update_subrows (boost::shared_ptr<Region> region, TreeModel::Row const &parent_row, int level)
-{
- TreeModel::iterator i;
- TreeModel::Children subrows = (*parent_row).children();
-
- for (i = subrows.begin(); i != subrows.end(); ++i) {
-
-// cerr << "Level " << level << ": Compare " << region->name() << " with child " << (*i)[_columns.name] << "\n";
-
- boost::shared_ptr<Region> compared_region = (*i)[_columns.region];
-
- if (region == compared_region) {
- populate_row(region, (*i));
-// cerr << "Matched\n";
- return true;
- }
-
- if (!(*i).children().empty()) {
- if (update_subrows (region, (*i), level + 1)) {
- return true;
- }
- }
- }
-
- return false;
}
void
@@ -745,40 +639,17 @@ EditorRegions::update_all_rows ()
if (!_session) {
return;
}
-
- TreeModel::iterator i;
- TreeModel::Children rows = _model->children();
-
- for (i = rows.begin(); i != rows.end(); ++i) {
-
- boost::shared_ptr<Region> region = (*i)[_columns.region];
-
- if (!region->automatic()) {
- populate_row(region, (*i));
- }
-
- if (!(*i).children().empty()) {
- update_all_subrows ((*i), 2);
- }
- }
-}
-
-void
-EditorRegions::update_all_subrows (TreeModel::Row const &parent_row, int level)
-{
- TreeModel::iterator i;
- TreeModel::Children subrows = (*parent_row).children();
- for (i = subrows.begin(); i != subrows.end(); ++i) {
+ RegionRowMap::iterator i;
- boost::shared_ptr<Region> region = (*i)[_columns.region];
+ for (i = region_row_map.begin(); i != region_row_map.end(); ++i) {
+ TreeModel::iterator j = _model->get_iter ((*i).second.get_path());
+
+ boost::shared_ptr<Region> region = (*j)[_columns.region];
+
if (!region->automatic()) {
- populate_row(region, (*i));
- }
-
- if (!(*i).children().empty()) {
- update_all_subrows ((*i), level + 1);
+ populate_row(region, (*j));
}
}
}
@@ -827,8 +698,10 @@ void
EditorRegions::populate_row (boost::shared_ptr<Region> region, TreeModel::Row const &row)
{
boost::shared_ptr<AudioRegion> audioregion = boost::dynamic_pointer_cast<AudioRegion>(region);
- uint32_t used = _session->playlists->region_use_count (region);
-
+ //uint32_t used = _session->playlists->region_use_count (region);
+ /* Presently a region is only used once so let's save on the sequential scan to determine use count */
+ uint32_t used = 1;
+
populate_row_position (region, row, used);
populate_row_end (region, row, used);
populate_row_sync (region, row, used);
@@ -1448,6 +1321,25 @@ EditorRegions::get_single_selection ()
return (*iter)[_columns.region];
}
+void
+EditorRegions::freeze_tree_model (){
+
+ _display.set_model (Glib::RefPtr<Gtk::TreeStore>(0));
+ _model->set_sort_column (-2, SORT_ASCENDING); //Disable sorting to gain performance
+
+}
+
+void
+EditorRegions::thaw_tree_model (){
+
+ _model->set_sort_column (0, SORT_ASCENDING); // renabale sorting
+ _display.set_model (_model);
+
+ if (toggle_full_action()->get_active()) {
+ _display.expand_all();
+ }
+}
+
void
EditorRegions::locked_changed (std::string const & path)
{
@@ -1515,7 +1407,7 @@ EditorRegions::get_state () const
return *node;
}
-
+
void
EditorRegions::set_state (const XMLNode & node)
{
@@ -1526,28 +1418,35 @@ EditorRegions::set_state (const XMLNode & node)
}
XMLProperty const * p = node.property (X_("sort-type"));
+
if (p) {
Editing::RegionListSortType const t = static_cast<Editing::RegionListSortType> (string_2_enum (p->value(), _sort_type));
+
if (_sort_type != t) {
changed = true;
}
+
reset_sort_type (t, true);
RefPtr<RadioAction> ract = sort_type_action (t);
ract->set_active ();
}
p = node.property (X_("sort-ascending"));
+
if (p) {
bool const yn = string_is_affirmative (p->value ());
SortType old_sort_type;
int old_sort_column;
_model->get_sort_column_id (old_sort_column, old_sort_type);
+
if (old_sort_type != (yn ? SORT_ASCENDING : SORT_DESCENDING)) {
changed = true;
}
+
reset_sort_direction (yn);
RefPtr<Action> act;
+
if (yn) {
act = ActionManager::get_action (X_("RegionList"), X_("SortAscending"));
} else {
@@ -1560,9 +1459,11 @@ EditorRegions::set_state (const XMLNode & node)
p = node.property (X_("show-all"));
if (p) {
bool const yn = string_is_affirmative (p->value ());
+
if (expanded != yn) {
changed = true;
}
+
set_full (yn);
toggle_full_action()->set_active (yn);
}
@@ -1570,6 +1471,7 @@ EditorRegions::set_state (const XMLNode & node)
p = node.property (X_("show-automatic-regions"));
if (p) {
bool const yn = string_is_affirmative (p->value ());
+
if (yn != _show_automatic_regions) {
_show_automatic_regions = yn;
toggle_show_auto_regions_action()->set_active (yn);
@@ -1642,6 +1544,12 @@ EditorRegions::show_action () const
return ActionManager::get_action (X_("RegionList"), X_("rlShow"));
}
+RefPtr<Action>
+EditorRegions::delete_unused_regions_action () const
+{
+ return ActionManager::get_action (X_("RegionList"), X_("removeUnusedRegions"));
+}
+
RefPtr<ToggleAction>
EditorRegions::toggle_full_action () const
{
diff --git a/gtk2_ardour/editor_regions.h b/gtk2_ardour/editor_regions.h
index 0643befbdf..c9d2f8714e 100644
--- a/gtk2_ardour/editor_regions.h
+++ b/gtk2_ardour/editor_regions.h
@@ -20,6 +20,7 @@
#define __gtk_ardour_editor_regions_h__
#include "editor_component.h"
+#include <boost/unordered_map.hpp>
class EditorRegions : public EditorComponent, public ARDOUR::SessionHandlePtr
{
@@ -66,6 +67,8 @@ public:
void unselect_all () {
_display.get_selection()->unselect_all ();
}
+
+ void delete_unused_regions();
XMLNode& get_state () const;
void set_state (const XMLNode &);
@@ -115,12 +118,13 @@ private:
Gtk::TreeModel::RowReference last_row;
+ void freeze_tree_model ();
+ void thaw_tree_model ();
void region_changed (boost::shared_ptr<ARDOUR::Region>, PBD::PropertyChange const &);
void selection_changed ();
sigc::connection _change_connection;
-
- bool set_selected_in_subrow (boost::shared_ptr<ARDOUR::Region>, Gtk::TreeModel::Row const &, int);
+
bool selection_filter (const Glib::RefPtr<Gtk::TreeModel>& model, const Gtk::TreeModel::Path& path, bool yn);
Gtk::Widget* old_focus;
@@ -135,10 +139,12 @@ private:
bool key_press (GdkEventKey *);
bool button_press (GdkEventButton *);
+
bool focus_in (GdkEventFocus*);
bool focus_out (GdkEventFocus*);
bool enter_notify (GdkEventCrossing*);
bool leave_notify (GdkEventCrossing*);
+
void show_context_menu (int button, int time);
int sorter (Gtk::TreeModel::iterator, Gtk::TreeModel::iterator);
@@ -146,7 +152,7 @@ private:
void format_position (ARDOUR::framepos_t pos, char* buf, size_t bufsize);
void add_region (boost::shared_ptr<ARDOUR::Region>);
- void add_regions (std::vector<boost::shared_ptr<ARDOUR::Region> > & );
+
void populate_row (boost::shared_ptr<ARDOUR::Region>, Gtk::TreeModel::Row const &);
void populate_row_used (boost::shared_ptr<ARDOUR::Region> region, Gtk::TreeModel::Row const& row, uint32_t used);
void populate_row_position (boost::shared_ptr<ARDOUR::Region> region, Gtk::TreeModel::Row const& row, uint32_t used);
@@ -162,10 +168,9 @@ private:
void populate_row_name (boost::shared_ptr<ARDOUR::Region> region, Gtk::TreeModel::Row const& row);
void populate_row_source (boost::shared_ptr<ARDOUR::Region> region, Gtk::TreeModel::Row const& row);
- void update_row (boost::shared_ptr<ARDOUR::Region>);
- bool update_subrows (boost::shared_ptr<ARDOUR::Region>, Gtk::TreeModel::Row const &, int);
+ void update_row (boost::shared_ptr<ARDOUR::Region>);
void update_all_rows ();
- void update_all_subrows (Gtk::TreeModel::Row const &, int);
+
void insert_into_tmp_regionlist (boost::shared_ptr<ARDOUR::Region>);
void drag_data_received (
@@ -177,22 +182,39 @@ private:
Glib::RefPtr<Gtk::Action> hide_action () const;
Glib::RefPtr<Gtk::Action> show_action () const;
+ Glib::RefPtr<Gtk::Action> delete_unused_regions_action() const;
Glib::RefPtr<Gtk::ToggleAction> toggle_full_action () const;
Glib::RefPtr<Gtk::ToggleAction> toggle_show_auto_regions_action () const;
Gtk::Menu* _menu;
Gtk::ScrolledWindow _scroller;
Gtk::Frame _frame;
+
Gtkmm2ext::DnDTreeView<boost::shared_ptr<ARDOUR::Region> > _display;
+
Glib::RefPtr<Gtk::TreeStore> _model;
+
bool _show_automatic_regions;
- Editing::RegionListSortType _sort_type;
+ bool ignore_region_list_selection_change;
+ bool ignore_selected_region_change;
bool _no_redisplay;
+
+ Editing::RegionListSortType _sort_type;
+
std::list<boost::shared_ptr<ARDOUR::Region> > tmp_region_list;
+
+ typedef boost::unordered_map<boost::shared_ptr<ARDOUR::Region>, Gtk::TreeModel::RowReference> RegionRowMap;
+ typedef boost::unordered_map<std::string, Gtk::TreeModel::RowReference > RegionSourceMap;
+
+ RegionRowMap region_row_map;
+ RegionSourceMap parent_regions_sources_map;
+
PBD::ScopedConnection region_property_connection;
PBD::ScopedConnection check_new_region_connection;
- bool ignore_region_list_selection_change;
- bool ignore_selected_region_change;
+
+ PBD::ScopedConnection editor_freeze_connection;
+ PBD::ScopedConnection editor_thaw_connection;
+
bool expanded;
};
diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h
index 3bb5d0aac8..2639662b2e 100644
--- a/libs/ardour/ardour/region.h
+++ b/libs/ardour/ardour/region.h
@@ -139,23 +139,24 @@ class Region
framepos_t first_frame () const { return _position; }
framepos_t last_frame () const { return _position + _length - 1; }
- bool hidden () const { return _hidden; }
- bool muted () const { return _muted; }
- bool opaque () const { return _opaque; }
- bool locked () const { return _locked; }
- bool position_locked () const { return _position_locked; }
- bool valid_transients () const { return _valid_transients; }
- bool automatic () const { return _automatic; }
- bool whole_file () const { return _whole_file; }
- bool captured () const { return !(_import || _external); }
- bool can_move () const { return !_position_locked; }
- bool sync_marked () const { return _sync_marked; }
- bool external () const { return _external; }
- bool import () const { return _import; }
-
- Trimmable::CanTrim can_trim () const;
+ bool hidden() const { return _hidden; }
+ bool muted() const { return _muted; }
+ bool opaque () const { return _opaque; }
+ bool locked() const { return _locked; }
+ bool position_locked() const { return _position_locked; }
+ bool valid_transients() const { return _valid_transients; }
+ bool automatic() const { return _automatic; }
+ bool whole_file() const { return _whole_file; }
+ bool captured() const { return !(_import || _external); }
+ bool can_move() const { return !_position_locked; }
+ bool sync_marked() const { return _sync_marked; }
+ bool external() const { return _external; }
+ bool import() const { return _import; }
+
+ Trimmable::CanTrim can_trim() const;
PositionLockStyle position_lock_style () const { return _position_lock_style; }
+
void set_position_lock_style (PositionLockStyle ps);
void recompute_position_from_lock_style ();
@@ -175,6 +176,9 @@ class Region
bool region_list_equivalent (boost::shared_ptr<const Region>) const;
bool source_equivalent (boost::shared_ptr<const Region>) const;
bool uses_source (boost::shared_ptr<const Source>) const;
+
+ std::string source_string () const;
+
/* EDITING OPERATIONS */
@@ -223,7 +227,7 @@ class Region
void source_deleted (boost::weak_ptr<Source>);
boost::shared_ptr<Source> source (uint32_t n=0) const { return _sources[ (n < _sources.size()) ? n : 0 ]; }
- uint32_t n_channels() const { return _sources.size(); }
+ uint32_t n_channels() const { return _sources.size(); }
const SourceList& sources () const { return _sources; }
const SourceList& master_sources () const { return _master_sources; }
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index 0970e01b5c..293d9d391f 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -512,6 +512,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
void add_source (boost::shared_ptr<Source>);
void remove_source (boost::weak_ptr<Source>);
+ void cleanup_regions();
int cleanup_sources (CleanupReport&);
int cleanup_trash_sources (CleanupReport&);
diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc
index 5a89707495..d711695927 100644
--- a/libs/ardour/region.cc
+++ b/libs/ardour/region.cc
@@ -423,6 +423,7 @@ Region::set_name (const std::string& str)
if (_name != str) {
SessionObject::set_name(str); // EMIT SIGNAL NameChanged()
assert(_name == str);
+
send_change (Properties::name);
}
@@ -490,6 +491,7 @@ Region::first_edit ()
_first_edit = EditChangesNothing;
send_change (Properties::name);
+
RegionFactory::CheckNewRegion (shared_from_this());
}
}
@@ -559,6 +561,7 @@ Region::set_position_lock_style (PositionLockStyle ps)
}
send_change (Properties::position_lock_style);
+
}
}
@@ -643,7 +646,6 @@ Region::set_position_on_top (framepos_t pos, void* /*src*/)
/* do this even if the position is the same. this helps out
a GUI that has moved its representation already.
*/
-
send_change (Properties::position);
}
@@ -1023,6 +1025,7 @@ Region::set_sync_position (framepos_t absolute_pos)
if (!property_changes_suspended()) {
maybe_uncopy ();
}
+
send_change (Properties::sync_position);
}
}
@@ -1035,6 +1038,7 @@ Region::clear_sync_position ()
if (!property_changes_suspended()) {
maybe_uncopy ();
}
+
send_change (Properties::sync_position);
}
}
@@ -1428,6 +1432,29 @@ Region::source_equivalent (boost::shared_ptr<const Region> other) const
return true;
}
+std::string
+Region::source_string () const
+{
+ //string res = itos(_sources.size());
+
+ char buf[64];
+
+ stringstream res;
+ res << _sources.size() << ":";
+
+ SourceList::const_iterator i;
+
+ for (i = _sources.begin(); i != _sources.end(); ++i) {
+ res << (*i)->id() << ":";
+ }
+
+ for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
+ res << (*i)->id() << ":";
+ }
+
+ return res.str();
+}
+
bool
Region::uses_source (boost::shared_ptr<const Source> source) const
{
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index cb1394740c..05fdb13bec 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -2575,6 +2575,32 @@ Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
return r.get_value_or (1);
}
+void
+Session::cleanup_regions ()
+{
+ const RegionFactory::RegionMap& regions (RegionFactory::regions());
+
+ for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
+
+ boost::shared_ptr<AudioRegion> audio_region = boost::dynamic_pointer_cast<AudioRegion>( i->second);
+
+ if (!audio_region) {
+ continue;
+ }
+
+ uint32_t used = playlists->region_use_count (audio_region);
+
+ if (used == 0 && !audio_region->automatic()){
+ RegionFactory::map_remove(i->second);
+ }
+ }
+
+ /* dump the history list */
+ _history.clear ();
+
+ save_state ("");
+}
+
int
Session::cleanup_sources (CleanupReport& rep)
{
@@ -2999,7 +3025,7 @@ Session::controllable_by_descriptor (const ControllableDescriptor& desc)
break;
case ControllableDescriptor::Solo:
- c = r->solo_control();
+ c = r->solo_control();
break;
case ControllableDescriptor::Mute:
diff --git a/libs/gtkmm2ext/gtk_ui.cc b/libs/gtkmm2ext/gtk_ui.cc
index 9736569053..035e892fba 100644
--- a/libs/gtkmm2ext/gtk_ui.cc
+++ b/libs/gtkmm2ext/gtk_ui.cc
@@ -147,7 +147,7 @@ UI::load_rcfile (string path, bool themechange)
return -1;
}
- if (access (path.c_str(), R_OK)) {
+ if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
error << "UI: couldn't find rc file \""
<< path
<< '"'
@@ -155,12 +155,11 @@ UI::load_rcfile (string path, bool themechange)
return -1;
}
- RC rc (path.c_str());
- gtk_rc_reset_styles (gtk_settings_get_default());
- //vector<string> files;
- //files.push_back(path.c_str());
- //RC::set_default_files(files);
- //RC::reparse_all (Gtk::Settings::get_default(), true);
+ RC rc (path.c_str());
+ //this is buggy in gtkmm for some reason, so use C
+ //RC::reset_styles (Gtk::Settings::get_default());
+ gtk_rc_reset_styles (gtk_settings_get_default());
+
theme_changed.emit();
if (themechange) {