#include <gtkmm/menu.h>
#include <gtkmm/stock.h>
+#include "gtkmm2ext/utils.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"
using namespace Gtk;
using namespace ARDOUR;
+using namespace PBD;
-RouteGroupMenu::RouteGroupMenu (Session& s, RouteGroup::Property p)
- : _session (s),
- _default_properties (p)
+RouteGroupMenu::RouteGroupMenu (Session* s, PropertyList* plist)
+ : SessionHandlePtr (s)
+ , _menu (0)
+ , _default_properties (plist)
+ , _inhibit_group_selected (false)
{
- rebuild (0);
+
}
+RouteGroupMenu::~RouteGroupMenu()
+{
+ delete _menu;
+ delete _default_properties;
+}
+
+/** @param s Routes to operate on */
void
-RouteGroupMenu::rebuild (RouteGroup* curr)
+RouteGroupMenu::build (WeakRouteList const & s)
{
+ assert (!s.empty ());
+
using namespace Menu_Helpers;
-
- items().clear ();
- items().push_back (MenuElem (_("New group..."), mem_fun (*this, &RouteGroupMenu::new_group)));
- items().push_back (SeparatorElem ());
+ _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
+ will be destroyed and its value set to 0, so we know.
+ */
+ _menu = new Menu;
+
+ MenuList& items = _menu->items ();
+
+ 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"), bind (mem_fun (*this, &RouteGroupMenu::set_group), (RouteGroup *) 0)));
+ 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 (curr == 0) {
- static_cast<RadioMenuItem*> (&items().back())->set_active ();
+ if (_session) {
+ _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &RouteGroupMenu::add_item), groups, &group));
}
-
- _session.foreach_route_group (bind (mem_fun (*this, &RouteGroupMenu::add_item), curr, &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;
- items().push_back (RadioMenuElem (*group, rg->name(), bind (mem_fun(*this, &RouteGroupMenu::set_group), rg)));
-
- if (rg == curr) {
- static_cast<RadioMenuItem*> (&items().back())->set_active ();
- }
+ MenuList& items = _menu->items ();
+
+ 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 (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 ();
+ }
}
+/** Called when a group is selected from the menu.
+ * @param Group, or 0 for none.
+ */
void
RouteGroupMenu::set_group (RouteGroup* g)
{
- GroupSelected (g);
-}
+ if (_inhibit_group_selected) {
+ return;
+ }
+ 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
RouteGroupMenu::new_group ()
{
- RouteGroup* g = new RouteGroup (_session, "", RouteGroup::Active, _default_properties);
+ if (!_session) {
+ return;
+ }
- RouteGroupDialog d (g, Gtk::Stock::NEW);
- int const r = d.do_run ();
+ RouteGroup* g = new RouteGroup (*_session, "");
+ g->apply_changes (*_default_properties);
- if (r == Gtk::RESPONSE_OK) {
- _session.add_route_group (g);
- set_group (g);
- } else {
+ RouteGroupDialog d (g, true);
+
+ if (d.do_run ()) {
delete g;
+ } else {
+ _session->add_route_group (g);
+ set_group (g);
+ }
+}
+
+Gtk::Menu *
+RouteGroupMenu::menu ()
+{
+ /* Our menu's gobject can be 0 if it was attached as a submenu whose
+ parent was subsequently deleted.
+ */
+ assert (_menu && _menu->gobj());
+ return _menu;
+}
+
+void
+RouteGroupMenu::detach ()
+{
+ if (_menu && _menu->gobj ()) {
+ Gtkmm2ext::detach_menu (*_menu);
}
}