Fix insertion of processors at the point at which the processor menu was opened; give a visual cue to indicate where a processor will be inserted. Kind of experimental.

git-svn-id: svn://localhost/ardour2/branches/3.0@10236 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Carl Hetherington 2011-10-19 16:53:36 +00:00
parent a9ebb3576e
commit 153ee4e441
5 changed files with 135 additions and 87 deletions

View File

@ -497,7 +497,7 @@ ProcessorBox::ProcessorBox (ARDOUR::Session* sess, boost::function<PluginSelecto
, _owner_is_mixer (owner_is_mixer)
, ab_direction (true)
, _get_plugin_selector (get_plugin_selector)
, _placement(PreFader)
, _placement (-1)
, _rr_selection(rsel)
{
set_session (sess);
@ -684,10 +684,11 @@ ProcessorBox::new_send ()
}
void
ProcessorBox::show_processor_menu (gint arg)
ProcessorBox::show_processor_menu (int arg)
{
if (processor_menu == 0) {
processor_menu = build_processor_menu ();
processor_menu->signal_unmap().connect (sigc::mem_fun (*this, &ProcessorBox::processor_menu_unmapped));
}
Gtk::MenuItem* plugin_menu_item = dynamic_cast<Gtk::MenuItem*>(ActionManager::get_widget("/ProcessorMenu/newplugin"));
@ -714,6 +715,13 @@ ProcessorBox::show_processor_menu (gint arg)
paste_action->set_sensitive (!_rr_selection.processors.empty());
processor_menu->popup (1, arg);
/* Add a placeholder gap to the processor list to indicate where a processor would be
inserted were one chosen from the menu.
*/
int x, y;
processor_display.get_pointer (x, y);
_placement = processor_display.add_placeholder (y);
}
bool
@ -884,20 +892,6 @@ ProcessorBox::processor_button_release_event (GdkEventButton *ev, ProcessorEntry
} else if (Keyboard::is_context_menu_event (ev)) {
/* figure out if we are above or below the fader/amp processor,
and set the next insert position appropriately.
*/
if (processor) {
if (_route->processor_is_prefader (processor)) {
_placement = PreFader;
} else {
_placement = PostFader;
}
} else {
_placement = PostFader;
}
show_processor_menu (ev->time);
} else if (processor && Keyboard::is_button2_event (ev)
@ -977,7 +971,7 @@ ProcessorBox::use_plugins (const SelectedPlugins& plugins)
Route::ProcessorStreams err_streams;
if (_route->add_processor (processor, _placement, &err_streams, Config->get_new_plugins_active ())) {
if (_route->add_processor_by_index (processor, _placement, &err_streams, Config->get_new_plugins_active ())) {
weird_plugin_dialog (**p, err_streams);
return true;
// XXX SHAREDPTR delete plugin here .. do we even need to care?
@ -1042,7 +1036,7 @@ void
ProcessorBox::choose_insert ()
{
boost::shared_ptr<Processor> processor (new PortInsert (*_session, _route->pannable(), _route->mute_master()));
_route->add_processor (processor, _placement);
_route->add_processor_by_index (processor, _placement);
}
/* Caller must not hold process lock */
@ -1104,7 +1098,7 @@ ProcessorBox::send_io_finished (IOSelector::Result r, boost::weak_ptr<Processor>
break;
case IOSelector::Accepted:
_route->add_processor (processor, _placement);
_route->add_processor_by_index (processor, _placement);
if (Profile->get_sae()) {
processor->activate ();
}
@ -1132,7 +1126,7 @@ ProcessorBox::return_io_finished (IOSelector::Result r, boost::weak_ptr<Processo
break;
case IOSelector::Accepted:
_route->add_processor (processor, _placement);
_route->add_processor_by_index (processor, _placement);
if (Profile->get_sae()) {
processor->activate ();
}
@ -2401,6 +2395,12 @@ ProcessorBox::hide_things ()
}
}
void
ProcessorBox::processor_menu_unmapped ()
{
processor_display.remove_placeholder ();
}
ProcessorWindowProxy::ProcessorWindowProxy (
string const & name,
XMLNode const * node,

View File

@ -240,7 +240,10 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject, public ARD
boost::shared_ptr<ARDOUR::Processor> _processor_being_created;
ARDOUR::Placement _placement;
/** Index at which to place a new plugin (based on where the menu was opened), or -1 to
* put at the end of the plugin list.
*/
int _placement;
RouteRedirectSelection& _rr_selection;
@ -265,7 +268,7 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject, public ARD
gint processor_menu_map_handler (GdkEventAny *ev);
Gtk::Menu * build_processor_menu ();
void build_processor_tooltip (Gtk::EventBox&, std::string);
void show_processor_menu (gint arg);
void show_processor_menu (int);
Gtk::Menu* build_possible_aux_menu();
void choose_aux (boost::weak_ptr<ARDOUR::Route>);
@ -289,6 +292,7 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject, public ARD
void reordered ();
void report_failed_reorder ();
void route_processors_changed (ARDOUR::RouteProcessorChange);
void processor_menu_unmapped ();
void processors_reordered (const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator&, int*);
void compute_processor_sort_keys ();

View File

@ -237,6 +237,7 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
};
int add_processor (boost::shared_ptr<Processor>, Placement placement, ProcessorStreams* err = 0, bool activation_allowed = true);
int add_processor_by_index (boost::shared_ptr<Processor>, int, ProcessorStreams* err = 0, bool activation_allowed = true);
int add_processor (boost::shared_ptr<Processor>, ProcessorList::iterator iter, ProcessorStreams* err = 0, bool activation_allowed = true);
int add_processors (const ProcessorList&, boost::shared_ptr<Processor> before, ProcessorStreams* err = 0);
int remove_processor (boost::shared_ptr<Processor>, ProcessorStreams* err = 0);

View File

@ -853,6 +853,34 @@ Route::add_processor (boost::shared_ptr<Processor> processor, Placement placemen
}
/** Add a processor to a route such that it ends up with a given index into the visible processors.
* @param index Index to add the processor at, or -1 to add at the end of the list.
*/
int
Route::add_processor_by_index (boost::shared_ptr<Processor> processor, int index, ProcessorStreams* err, bool activation_allowed)
{
/* XXX this is not thread safe - we don't hold the lock across determining the iter
to add before and actually doing the insertion. dammit.
*/
if (index == -1) {
return add_processor (processor, _processors.end(), err, activation_allowed);
}
ProcessorList::iterator i = _processors.begin ();
int j = 0;
while (i != _processors.end() && j < index) {
if ((*i)->display_to_user()) {
++j;
}
++i;
}
return add_processor (processor, i, err, activation_allowed);
}
/** Add a processor to the route.
* @param iter an iterator in _processors; the new processor will be inserted immediately before this location.
*/

View File

@ -45,7 +45,7 @@ template <class T>
class DnDVBox : public Gtk::EventBox
{
public:
DnDVBox () : _active (0), _drag_icon (0), _expecting_unwanted_button_event (false), _drag_placeholder (0)
DnDVBox () : _active (0), _drag_icon (0), _expecting_unwanted_button_event (false), _placeholder (0)
{
_targets.push_back (Gtk::TargetEntry ("processor"));
@ -165,6 +165,59 @@ public:
SelectionChanged (); /* EMIT SIGNAL */
}
/** @param y y coordinate.
* @return Pair consisting of the child under y (or 0) and the (fractional) index of the child under y (or -1)
*/
std::pair<T*, double> get_child_at_position (int y) const
{
T* before;
T* after;
std::pair<T*, double> r;
r.second = get_children_around_position (y, &before, &r.first, &after);
return r;
}
void set_spacing (int s) {
_internal_vbox.set_spacing (s);
}
void remove_placeholder ()
{
if (_placeholder) {
_internal_vbox.remove (*_placeholder);
_placeholder = 0;
}
}
/** Add a placeholder where a child would be put if it were added at the given y position.
* @param y y position within the DnDVBox.
* @return index of child that the placeholder represents, or -1 if it is at the end of all children.
*/
int add_placeholder (double y)
{
return create_or_update_placeholder (get_child_at_position (y).second);
}
/** Children have been reordered by a drag */
sigc::signal<void> Reordered;
/** A button has been pressed over the widget */
sigc::signal<bool, GdkEventButton*, T*> ButtonPress;
/** A button has been release over the widget */
sigc::signal<bool, GdkEventButton*, T*> ButtonRelease;
/** A child has been dropped onto this DnDVBox from another one;
* Parameters are the source DnDVBox, our child which the other one was dropped on (or 0) and the DragContext.
*/
sigc::signal<void, DnDVBox*, T*, Glib::RefPtr<Gdk::DragContext> const & > DropFromAnotherBox;
sigc::signal<void> SelectionChanged;
private:
/** Look at a y coordinate and find the children below y, and the ones either side.
* @param y y position.
* @param before Filled in with the child before, or 0.
@ -188,7 +241,8 @@ public:
/* top of current child */
double top = 0;
/* bottom of current child */
double bottom = (*j)->widget().get_allocation().get_height ();
Gtk::Allocation const a = (*j)->widget().get_allocation();
double bottom = a.get_y() + a.get_height();
while (y >= bottom && j != _children.end()) {
@ -199,7 +253,8 @@ public:
++j;
if (j != _children.end()) {
bottom += (*j)->widget().get_allocation().get_height ();
Gtk::Allocation const a = (*j)->widget().get_allocation();
bottom = a.get_y() + a.get_height();
}
}
@ -217,41 +272,6 @@ public:
return i + ((y - top) / (*at)->widget().get_allocation().get_height());
}
/** @param y y coordinate.
* @return Pair consisting of the child under y (or 0) and the (fractional) index of the child under y (or -1)
*/
std::pair<T*, double> get_child_at_position (int y) const
{
T* before;
T* after;
std::pair<T*, double> r;
r.second = get_children_around_position (y, &before, &r.first, &after);
return r;
}
void set_spacing (int s) {
_internal_vbox.set_spacing (s);
}
/** Children have been reordered by a drag */
sigc::signal<void> Reordered;
/** A button has been pressed over the widget */
sigc::signal<bool, GdkEventButton*, T*> ButtonPress;
/** A button has been release over the widget */
sigc::signal<bool, GdkEventButton*, T*> ButtonRelease;
/** A child has been dropped onto this DnDVBox from another one;
* Parameters are the source DnDVBox, our child which the other one was dropped on (or 0) and the DragContext.
*/
sigc::signal<void, DnDVBox*, T*, Glib::RefPtr<Gdk::DragContext> const & > DropFromAnotherBox;
sigc::signal<void> SelectionChanged;
private:
void drag_begin (Glib::RefPtr<Gdk::DragContext> const & context, T* child)
{
_drag_child = child;
@ -356,17 +376,27 @@ private:
_drag_icon = 0;
_drag_child = 0;
remove_drag_placeholder ();
remove_placeholder ();
Reordered (); /* EMIT SIGNAL */
}
void remove_drag_placeholder ()
/** Insert a placeholder at a given fractional child position, creating it if necessary.
* @param c Fractional child position.
* @return index of child that the placeholder represents, or -1 if it is at the end of all children.
*/
int create_or_update_placeholder (double c)
{
if (_drag_placeholder) {
_internal_vbox.remove (*_drag_placeholder);
_drag_placeholder = 0;
if (_placeholder == 0) {
_placeholder = manage (new Gtk::Label (""));
_internal_vbox.pack_start (*_placeholder, false, false);
_placeholder->show ();
}
/* round up the index, unless we're off the end of the children */
int const n = c < 0 ? -1 : int (c + 0.5);
_internal_vbox.reorder_child (*_placeholder, n);
return n;
}
bool drag_motion (Glib::RefPtr<Gdk::DragContext> const &, int /*x*/, int y, guint)
@ -387,37 +417,23 @@ private:
if (top_half && (before == _drag_child || at == _drag_child)) {
/* dropping here would have no effect, so remove the visual cue */
remove_drag_placeholder ();
remove_placeholder ();
return false;
}
if (!top_half && (at == _drag_child || after == _drag_child)) {
/* dropping here would have no effect, so remove the visual cue */
remove_drag_placeholder ();
remove_placeholder ();
return false;
}
/* the index that the placeholder should be put at */
int const n = int (c + 0.5);
if (_drag_placeholder == 0) {
_drag_placeholder = manage (new Gtk::Label (""));
_internal_vbox.pack_start (*_drag_placeholder, false, false);
_drag_placeholder->show ();
}
if (c < 0) {
_internal_vbox.reorder_child (*_drag_placeholder, -1);
} else {
_internal_vbox.reorder_child (*_drag_placeholder, n);
}
create_or_update_placeholder (c);
return false;
}
void drag_leave (Glib::RefPtr<Gdk::DragContext> const &, guint)
{
remove_drag_placeholder ();
remove_placeholder ();
}
bool button_press (GdkEventButton* ev, T* child)
@ -489,7 +505,6 @@ private:
}
}
return ButtonPress (ev, child); /* EMIT SIGNAL */
}
@ -566,10 +581,10 @@ private:
T* _active;
Gtk::Window* _drag_icon;
bool _expecting_unwanted_button_event;
/** A blank label used as a placeholder to indicate where a dragged item would
* go if it were dropped now.
/** A blank label used as a placeholder to indicate where an item would
* go if it were dropped or inserted "now".
*/
Gtk::Label* _drag_placeholder;
Gtk::Label* _placeholder;
/** Our child being dragged, or 0 */
T* _drag_child;