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