#include <cstdlib>
#include "pbd/stacktrace.h"
+#include "pbd/unwind.h"
#include "ardour/midi_region.h"
#include "ardour/playlist.h"
sorted.sort (cmp);
- if (!selection->selected (&view)) {
- to_be_added.push_back (&view);
- }
-
/* figure out if we should go forward or backwards */
for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
}
}
+ if (!selection->selected (&view)) {
+ to_be_added.push_back (&view);
+ }
+
if (!to_be_added.empty()) {
selection->add (to_be_added);
return true;
visible_views.push_back (*i);
}
}
+ PBD::Unwinder<bool> uw (_track_selection_change_without_scroll, true);
selection->set (visible_views);
}
return commit;
}
+void
+Editor::set_selection (std::list<Selectable*> s, Selection::Operation op)
+{
+ if (s.empty()) {
+ return;
+ }
+ begin_reversible_selection_op (X_("set selection"));
+ switch (op) {
+ case Selection::Toggle:
+ selection->toggle (s);
+ break;
+ case Selection::Set:
+ selection->set (s);
+ break;
+ case Selection::Extend:
+ selection->add (s);
+ break;
+ case Selection::Add:
+ selection->add (s);
+ break;
+ }
+
+ commit_reversible_selection_op () ;
+}
void
Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> region, Selection::Operation op)
return true;
}
+struct SelectionOrderSorter {
+ bool operator() (TimeAxisView const * const a, TimeAxisView const * const b) const {
+ boost::shared_ptr<Stripable> sa = a->stripable ();
+ boost::shared_ptr<Stripable> sb = b->stripable ();
+ if (!sa && !sb) {
+ return a < b;
+ }
+ if (!sa) {
+ return false;
+ }
+ if (!sb) {
+ return true;
+ }
+ return sa->presentation_info().selection_cnt() < sb->presentation_info().selection_cnt();
+ }
+};
+
void
Editor::track_selection_changed ()
{
+ SelectionOrderSorter cmp;
+ selection->tracks.sort (cmp);
+
switch (selection->tracks.size()) {
case 0:
break;
default:
- /* last element in selection list is the most recently
- * selected, because we always append to that list.
- */
set_selected_mixer_strip (*(selection->tracks.back()));
- ensure_time_axis_view_is_visible (*(selection->tracks.back()), false);
+ if (!_track_selection_change_without_scroll) {
+ ensure_time_axis_view_is_visible (*(selection->tracks.back()), false);
+ }
break;
}
ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, !selection->tracks.empty());
+ sensitize_the_right_region_actions (false);
+
/* notify control protocols */
ControlProtocol::StripableSelectionChanged (stripables);
_all_region_actions_sensitized = s;
}
-/** Sensitize region-based actions based on the selection ONLY, ignoring the entered_regionview.
- * This method is called from three places:
- *
- * 1. just before the top level Region menu is shown
- * 2. whenever the region selection changes
- * 3. just before popping up a track context menu
+/** Sensitize region-based actions.
*
- * This method also sets up toggle action state as appropriate.
+ * This method is called from whenever we leave the canvas, either by moving
+ * the pointer out of it, or by popping up a context menu. See
+ * Editor::{entered,left}_track_canvas() for details there.
*/
void
-Editor::sensitize_the_right_region_actions (bool from_context_menu, bool from_outside_canvas)
+Editor::sensitize_the_right_region_actions (bool because_canvas_crossing)
{
- PBD::stacktrace (cerr, 20);
- RegionSelection rs = get_regions_from_selection_and_edit_point (Editing::EDIT_IGNORE_NONE, from_context_menu, from_outside_canvas);
+ bool have_selection = false;
+ bool have_entered = false;
+ bool have_edit_point = false;
+ RegionSelection rs;
+
+ // std::cerr << "STRRA: crossing ? " << because_canvas_crossing << " within ? " << within_track_canvas
+ // << std::endl;
+
+ if (!selection->regions.empty()) {
+ have_selection = true;
+ rs = selection->regions;
+ }
+
+ if (entered_regionview) {
+ have_entered = true;
+ rs.add (entered_regionview);
+ }
- sensitize_all_region_actions (!rs.empty ());
+ if (rs.empty() && !selection->tracks.empty()) {
+
+ /* no selected regions, but some selected tracks.
+ */
+
+ if (_edit_point == EditAtMouse) {
+ if (!within_track_canvas) {
+ /* pointer is not in canvas, so edit point is meaningless */
+ have_edit_point = false;
+ } else {
+ /* inside canvas. we don't know where the edit
+ point will be when an action is invoked, but
+ assume it could intersect with a region.
+ */
+ have_edit_point = true;
+ }
+ } else {
+ RegionSelection at_edit_point;
+ framepos_t const where = get_preferred_edit_position (Editing::EDIT_IGNORE_NONE, false, !within_track_canvas);
+ get_regions_at (at_edit_point, where, selection->tracks);
+ if (!at_edit_point.empty()) {
+ have_edit_point = true;
+ }
+ if (rs.empty()) {
+ rs.insert (rs.end(), at_edit_point.begin(), at_edit_point.end());
+ }
+ }
+ }
+
+ //std::cerr << "\tfinal have selection: " << have_selection
+ // << " have entered " << have_entered
+ // << " have edit point " << have_edit_point
+ // << " EP = " << enum_2_string (_edit_point)
+ // << std::endl;
+
+ typedef std::map<std::string,RegionAction> RegionActionMap;
_ignore_region_action = true;
+ for (RegionActionMap::iterator x = region_action_map.begin(); x != region_action_map.end(); ++x) {
+ RegionActionTarget tgt = x->second.target;
+ bool sensitive = false;
+
+ if ((tgt & SelectedRegions) && have_selection) {
+ sensitive = true;
+ } else if ((tgt & EnteredRegions) && have_entered) {
+ sensitive = true;
+ } else if ((tgt & EditPointRegions) && have_edit_point) {
+ sensitive = true;
+ }
+
+ x->second.action->set_sensitive (sensitive);
+ }
+
/* Look through the regions that are selected and make notes about what we have got */
bool have_audio = false;
/* others were already marked sensitive */
}
- /* these actions all require a single location, taken from the edit
- * point.
- */
-
- vector<string> edit_point_actions;
- edit_point_actions.push_back ("set-region-sync-position");
- edit_point_actions.push_back ("trim-front");
- edit_point_actions.push_back ("trim-back");
- edit_point_actions.push_back ("place-transient");
- edit_point_actions.push_back ("align-regions-start");
- edit_point_actions.push_back ("align-regions-start-relative");
- edit_point_actions.push_back ("align-regions-end");
- edit_point_actions.push_back ("align-regions-end-relative");
- edit_point_actions.push_back ("align-regions-sync");
- edit_point_actions.push_back ("align-regions-sync-relative");
-
- /* They all use Editor::get_regions_from_selection_and_edit_point(),
- * which is the same method used at the start of this to determine if
- * any regions are eligible/valid for editing.
- *
- * there are two possible reasons why these actions should still
- * be sensitive.
- *
- * 1. regions are selected
- * 2. the edit point is inside some regions on selected tracks
- *
- * the first condition is satisfied if selection->regions is not empty.
- * the second condition is satisfied if selection->regions is empty,
- * but @param rs (set above by the call to get_regions_from_selection_and_edit_point()
- * is not empty.
- *
- * if the mouse is the edit point, then whether get_regions_from_selection_and_edit_point()
- * will have identified any regions will depend on the edit point setting.
- *
- * Editing::EditIgnoreOption that we passed to it, which in turn will
- * depend on whether or not the pointer is still inside the track
- * canvas. If it was, then the pointer position will determine whether
- * or not any non-selected regions are considered eligible. If it
- * wasn't, then we will ignore the pointer position and fallback on a
- * secondary edit point (at this writing, that will likely be the
- * playhead but see get_regions_from_selection_and_edit_point() to see
- * how this works).
- *
- * if the edit point is not the mouse, then
- * get_regions_from_selection_and_edit_point() will just do the right
- * thing.
- *
- * However, the implementation of the actions will still use the edit
- * point, ...
- *
- */
-
- bool sensitivity;
-
- if (!selection->regions.empty() || !rs.empty()) { /* conditions 1 and 2 above */
- sensitivity = true;
- } else {
- sensitivity = false;
- }
-
- for (vector<string>::const_iterator a = edit_point_actions.begin(); a != edit_point_actions.end(); ++a) {
- _region_actions->get_action (*a)->set_sensitive (sensitivity);
- }
-
/* ok, moving along... */
if (have_compound_regions) {
_regions->block_change_connection (false);
editor_regions_selection_changed_connection.block(false);
- sensitize_the_right_region_actions (false, false);
+ sensitize_the_right_region_actions (false);
/* propagate into backend */