make inclusion/exclusion of hidden children optional in Item::add_child_bounding_boxes
[ardour.git] / gtk2_ardour / route_group_menu.cc
index 5b6c27551662b97d9e6ba83be263c3dafcfc1763..5ccafaec398c70467c9313d65c8943ccd4449126 100644 (file)
 
 #include <gtkmm/menu.h>
 #include <gtkmm/stock.h>
+
 #include "gtkmm2ext/utils.h"
+#include "gtkmm2ext/doi.h"
+
 #include "ardour/session.h"
 #include "ardour/route_group.h"
+#include "ardour/route.h"
 #include "route_group_menu.h"
 #include "route_group_dialog.h"
-#include "i18n.h"
+
+#include "pbd/i18n.h"
 
 using namespace Gtk;
 using namespace ARDOUR;
@@ -35,7 +40,6 @@ RouteGroupMenu::RouteGroupMenu (Session* s, PropertyList* plist)
        , _menu (0)
        , _default_properties (plist)
        , _inhibit_group_selected (false)
-       , _selected_route_group (0)
 {
 
 }
@@ -46,18 +50,29 @@ RouteGroupMenu::~RouteGroupMenu()
        delete _default_properties;
 }
 
-/** @param curr Current route group to mark as selected, or 0 for no group */
+/** @param s Routes to operate on */
 void
-RouteGroupMenu::build (RouteGroup* curr)
+RouteGroupMenu::build (WeakRouteList const & s)
 {
+       assert (!s.empty ());
+
        using namespace Menu_Helpers;
 
-       _selected_route_group = curr;
+       _subject = s;
+
+       /* FInd all the route groups that our subjects are members of */
+       std::set<RouteGroup*> groups;
+       for (WeakRouteList::const_iterator i = _subject.begin (); i != _subject.end(); ++i) {
+               boost::shared_ptr<Route> r = i->lock ();
+               if (r) {
+                       groups.insert (r->route_group ());
+               }
+       }
 
        _inhibit_group_selected = true;
 
        delete _menu;
-       
+
        /* Note: don't use manage() here, otherwise if our _menu object is attached as a submenu
           and its parent is then destroyed, our _menu object will be deleted and we'll have no
           way of knowing about it.  Without manage(), when the above happens our _menu's gobject
@@ -66,35 +81,49 @@ RouteGroupMenu::build (RouteGroup* curr)
        _menu = new Menu;
 
        MenuList& items = _menu->items ();
-       
-       items.push_back (MenuElem (_("New group..."), sigc::mem_fun (*this, &RouteGroupMenu::new_group)));
+
+       items.push_back (MenuElem (_("New Group..."), sigc::mem_fun (*this, &RouteGroupMenu::new_group)));
        items.push_back (SeparatorElem ());
 
        RadioMenuItem::Group group;
-       items.push_back (RadioMenuElem (group, _("No group"), sigc::bind (sigc::mem_fun (*this, &RouteGroupMenu::set_group), (RouteGroup *) 0)));
-
-       if (curr == 0) {
-               static_cast<RadioMenuItem*> (&items.back())->set_active ();
+       items.push_back (RadioMenuElem (group, _("No Group")));
+       RadioMenuItem* i = static_cast<RadioMenuItem *> (&items.back ());
+       i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteGroupMenu::set_group), (RouteGroup *) 0));
+
+       if (groups.size() == 1 && *groups.begin() == 0) {
+               i->set_active ();
+       } else if (groups.size() > 1) {
+               i->set_inconsistent ();
        }
 
        if (_session) {
-               _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &RouteGroupMenu::add_item), curr, &group));
+               _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &RouteGroupMenu::add_item), groups, &group));
        }
 
        _inhibit_group_selected = false;
 }
 
+/** @param rg Route group to add.
+ *  @param groups Active route groups (may included 0 for `no group')
+ *  @param group Radio item group to add radio items to.
+ */
 void
-RouteGroupMenu::add_item (RouteGroup* rg, RouteGroup* curr, RadioMenuItem::Group* group)
+RouteGroupMenu::add_item (RouteGroup* rg, std::set<RouteGroup*> const & groups, RadioMenuItem::Group* group)
 {
        using namespace Menu_Helpers;
 
        MenuList& items = _menu->items ();
 
-       items.push_back (RadioMenuElem (*group, rg->name(), sigc::bind (sigc::mem_fun(*this, &RouteGroupMenu::set_group), rg)));
+       items.push_back (RadioMenuElem (*group, rg->name()));
+       RadioMenuItem* i = static_cast<RadioMenuItem*> (&items.back ());
+       i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteGroupMenu::set_group), rg));
 
-       if (rg == curr) {
-               static_cast<RadioMenuItem*> (&items.back())->set_active ();
+       if (groups.size() == 1 && *groups.begin() == rg) {
+               /* there's only one active group, and it's this one */
+               i->set_active ();
+       } else if (groups.size() > 1) {
+               /* there are >1 active groups */
+               i->set_inconsistent ();
        }
 }
 
@@ -104,18 +133,25 @@ RouteGroupMenu::add_item (RouteGroup* rg, RouteGroup* curr, RadioMenuItem::Group
 void
 RouteGroupMenu::set_group (RouteGroup* g)
 {
-       if (g == _selected_route_group) {
-               /* cut off the signal_toggled that GTK emits for an option that is being un-selected
-                  when a new option is being selected instead
-               */
+       if (_inhibit_group_selected) {
                return;
        }
-       
-       if (!_inhibit_group_selected) {
-               GroupSelected (g);
-       }
 
-       _selected_route_group = g;
+       for (WeakRouteList::const_iterator i = _subject.begin(); i != _subject.end(); ++i) {
+               boost::shared_ptr<Route> r = i->lock ();
+               if (!r || r->route_group () == g) {
+                       /* lock of weak_ptr failed, or the group for this route is already right */
+                       continue;
+               }
+
+               if (g) {
+                       g->add (r);
+               } else {
+                       if (r->route_group ()) {
+                               r->route_group()->remove (r);
+                       }
+               }
+       }
 }
 
 void
@@ -126,16 +162,23 @@ RouteGroupMenu::new_group ()
        }
 
        RouteGroup* g = new RouteGroup (*_session, "");
-       g->apply_changes (*_default_properties);
+       RouteGroupDialog* d = new RouteGroupDialog (g, true);
 
-       RouteGroupDialog d (g, true);
+       d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &RouteGroupMenu::new_group_dialog_finished), d));
+       d->present ();
+}
 
-       if (d.do_run ()) {
-               delete g;
+void
+RouteGroupMenu::new_group_dialog_finished (int r, RouteGroupDialog* d)
+{
+       if (r == RESPONSE_OK) {
+               _session->add_route_group (d->group());
+               set_group (d->group());
        } else {
-               _session->add_route_group (g);
-               set_group (g);
+               delete d->group ();
        }
+
+       delete_when_idle (d);
 }
 
 Gtk::Menu *