Make the route group submenu of the RouteTimeAxisView menu apply to the selection.
[ardour.git] / gtk2_ardour / route_group_menu.cc
1 /*
2     Copyright (C) 2009 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <gtkmm/menu.h>
21 #include <gtkmm/stock.h>
22 #include "gtkmm2ext/utils.h"
23 #include "ardour/session.h"
24 #include "ardour/route_group.h"
25 #include "ardour/route.h"
26 #include "route_group_menu.h"
27 #include "route_group_dialog.h"
28 #include "i18n.h"
29
30 using namespace Gtk;
31 using namespace ARDOUR;
32 using namespace PBD;
33
34 RouteGroupMenu::RouteGroupMenu (Session* s, PropertyList* plist)
35         : SessionHandlePtr (s)
36         , _menu (0)
37         , _default_properties (plist)
38         , _inhibit_group_selected (false)
39 {
40
41 }
42
43 RouteGroupMenu::~RouteGroupMenu()
44 {
45         delete _menu;
46         delete _default_properties;
47 }
48
49 /** @param s Routes to operate on */
50 void
51 RouteGroupMenu::build (WeakRouteList const & s)
52 {
53         assert (!s.empty ());
54         
55         using namespace Menu_Helpers;
56
57         _subject = s;
58
59         /* FInd all the route groups that our subjects are members of */
60         std::set<RouteGroup*> groups;
61         for (WeakRouteList::const_iterator i = _subject.begin (); i != _subject.end(); ++i) {
62                 boost::shared_ptr<Route> r = i->lock ();
63                 if (r) {
64                         groups.insert (r->route_group ());
65                 }
66         }
67
68         _inhibit_group_selected = true;
69
70         delete _menu;
71         
72         /* Note: don't use manage() here, otherwise if our _menu object is attached as a submenu
73            and its parent is then destroyed, our _menu object will be deleted and we'll have no
74            way of knowing about it.  Without manage(), when the above happens our _menu's gobject
75            will be destroyed and its value set to 0, so we know.
76         */
77         _menu = new Menu;
78
79         MenuList& items = _menu->items ();
80         
81         items.push_back (MenuElem (_("New group..."), sigc::mem_fun (*this, &RouteGroupMenu::new_group)));
82         items.push_back (SeparatorElem ());
83
84         RadioMenuItem::Group group;
85         items.push_back (RadioMenuElem (group, _("No group")));
86         RadioMenuItem* i = static_cast<RadioMenuItem *> (&items.back ());
87         i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteGroupMenu::set_group), (RouteGroup *) 0));
88
89         if (groups.size() == 1 && *groups.begin() == 0) {
90                 i->set_active ();
91         } else if (groups.size() > 1) {
92                 i->set_inconsistent ();
93         }
94
95         if (_session) {
96                 _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &RouteGroupMenu::add_item), groups, &group));
97         }
98
99         _inhibit_group_selected = false;
100 }
101
102 /** @param rg Route group to add.
103  *  @param groups Active route groups (may included 0 for `no group')
104  *  @param group Radio item group to add radio items to.
105  */
106 void
107 RouteGroupMenu::add_item (RouteGroup* rg, std::set<RouteGroup*> const & groups, RadioMenuItem::Group* group)
108 {
109         using namespace Menu_Helpers;
110
111         MenuList& items = _menu->items ();
112
113         items.push_back (RadioMenuElem (*group, rg->name()));
114         RadioMenuItem* i = static_cast<RadioMenuItem*> (&items.back ());
115         i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteGroupMenu::set_group), rg));
116
117         if (groups.size() == 1 && *groups.begin() == rg) {
118                 /* there's only one active group, and it's this one */
119                 i->set_active ();
120         } else if (groups.size() > 1) {
121                 /* there are >1 active groups */
122                 i->set_inconsistent ();
123         }
124 }
125
126 /** Called when a group is selected from the menu.
127  *  @param Group, or 0 for none.
128  */
129 void
130 RouteGroupMenu::set_group (RouteGroup* g)
131 {
132         if (_inhibit_group_selected) {
133                 return;
134         }
135
136         for (WeakRouteList::const_iterator i = _subject.begin(); i != _subject.end(); ++i) {
137                 boost::shared_ptr<Route> r = i->lock ();
138                 if (!r || r->route_group () == g) {
139                         /* lock of weak_ptr failed, or the group for this route is already right */
140                         continue;
141                 }
142
143                 if (g) {
144                         g->add (r);
145                 } else {
146                         if (r->route_group ()) {
147                                 r->route_group()->remove (r);
148                         }
149                 }
150         }
151 }
152
153 void
154 RouteGroupMenu::new_group ()
155 {
156         if (!_session) {
157                 return;
158         }
159
160         RouteGroup* g = new RouteGroup (*_session, "");
161         g->apply_changes (*_default_properties);
162
163         RouteGroupDialog d (g, true);
164
165         if (d.do_run ()) {
166                 delete g;
167         } else {
168                 _session->add_route_group (g);
169                 set_group (g);
170         }
171 }
172
173 Gtk::Menu *
174 RouteGroupMenu::menu ()
175 {
176         /* Our menu's gobject can be 0 if it was attached as a submenu whose
177            parent was subsequently deleted.
178         */
179         assert (_menu && _menu->gobj());
180         return _menu;
181 }
182
183 void
184 RouteGroupMenu::detach ()
185 {
186         if (_menu && _menu->gobj ()) {
187                 Gtkmm2ext::detach_menu (*_menu);
188         }
189 }