2 * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
3 * Copyright (C) 2008-2016 Paul Davis <paul@linuxaudiosystems.com>
4 * Copyright (C) 2009-2014 David Robillard <d@drobilla.net>
5 * Copyright (C) 2014-2016 Robin Gareus <robin@gareus.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include <gtkmm/stock.h>
23 #include <gtkmm/button.h>
24 #include <gtkmm/label.h>
25 #include <gtkmm/entry.h>
26 #include <gtkmm/table.h>
27 #include <gtkmm/comboboxtext.h>
28 #include <gtkmm/alignment.h>
30 #include "ardour/session.h"
31 #include "ardour/user_bundle.h"
32 #include "bundle_manager.h"
33 #include "gui_thread.h"
38 using namespace ARDOUR;
39 using namespace ARDOUR_UI_UTILS;
41 BundleEditorMatrix::BundleEditorMatrix (Gtk::Window* parent, Session* session, boost::shared_ptr<Bundle> bundle)
42 : PortMatrix (parent, session, DataType::NIL)
45 _port_group = boost::shared_ptr<PortGroup> (new PortGroup (""));
46 _port_group->add_bundle (_bundle);
53 BundleEditorMatrix::setup_ports (int dim)
56 _ports[OURS].clear ();
57 _ports[OURS].add_group (_port_group);
59 _ports[OTHER].suspend_signals ();
61 /* when we gather, allow the matrix to contain bundles with duplicate port sets,
62 otherwise in some cases the basic system IO ports may be hidden, making
63 the bundle editor useless */
65 _ports[OTHER].gather (_session, DataType::NIL, _bundle->ports_are_inputs(), true, show_only_bundles ());
66 _ports[OTHER].remove_bundle (_bundle);
67 _ports[OTHER].resume_signals ();
72 BundleEditorMatrix::set_state (BundleChannel c[2], bool s)
74 Bundle::PortList const& pl = c[OTHER].bundle->channel_ports (c[OTHER].channel);
75 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
77 c[OURS].bundle->add_port_to_channel (c[OURS].channel, *i);
79 c[OURS].bundle->remove_port_from_channel (c[OURS].channel, *i);
85 BundleEditorMatrix::get_state (BundleChannel c[2]) const
87 if (c[0].bundle->nchannels() == ChanCount::ZERO || c[1].bundle->nchannels() == ChanCount::ZERO) {
88 return PortMatrixNode::NOT_ASSOCIATED;
91 Bundle::PortList const& pl = c[OTHER].bundle->channel_ports (c[OTHER].channel);
93 return PortMatrixNode::NOT_ASSOCIATED;
96 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
97 if (!c[OURS].bundle->port_attached_to_channel (c[OURS].channel, *i)) {
98 return PortMatrixNode::NOT_ASSOCIATED;
102 return PortMatrixNode::ASSOCIATED;
106 BundleEditorMatrix::can_add_channels (boost::shared_ptr<Bundle> b) const
112 return PortMatrix::can_add_channels (b);
116 BundleEditorMatrix::add_channel (boost::shared_ptr<Bundle> b, DataType t)
122 if (d.run () != Gtk::RESPONSE_ACCEPT) {
126 _bundle->add_channel (d.get_name(), t);
131 PortMatrix::add_channel (b, t);
137 BundleEditorMatrix::can_remove_channels (boost::shared_ptr<Bundle> b) const
143 return PortMatrix::can_remove_channels (b);
147 BundleEditorMatrix::remove_channel (BundleChannel bc)
149 bc.bundle->remove_channel (bc.channel);
154 BundleEditorMatrix::can_rename_channels (boost::shared_ptr<Bundle> b) const
160 return PortMatrix::can_rename_channels (b);
164 BundleEditorMatrix::rename_channel (BundleChannel bc)
166 NameChannelDialog d (bc.bundle, bc.channel);
168 if (d.run () != Gtk::RESPONSE_ACCEPT) {
172 bc.bundle->set_channel_name (bc.channel, d.get_name ());
176 BundleEditorMatrix::list_is_global (int dim) const
178 return (dim == OTHER);
182 BundleEditorMatrix::disassociation_verb () const
184 return _("Disassociate");
187 BundleEditor::BundleEditor (Session* session, boost::shared_ptr<UserBundle> bundle)
188 : ArdourDialog (_("Edit Bundle")), _matrix (this, session, bundle), _bundle (bundle)
190 Gtk::Table* t = new Gtk::Table (3, 2);
194 Gtk::Alignment* a = new Gtk::Alignment (1, 0.5, 0, 1);
195 a->add (*Gtk::manage (new Gtk::Label (_("Name:"))));
196 t->attach (*Gtk::manage (a), 0, 1, 0, 1, Gtk::FILL, Gtk::FILL);
197 t->attach (_name, 1, 2, 0, 1);
198 _name.set_text (_bundle->name ());
199 _name.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::name_changed));
201 /* Direction (input or output) */
202 a = new Gtk::Alignment (1, 0.5, 0, 1);
203 a->add (*Gtk::manage (new Gtk::Label (_("Direction:"))));
204 t->attach (*Gtk::manage (a), 0, 1, 1, 2, Gtk::FILL, Gtk::FILL);
205 a = new Gtk::Alignment (0, 0.5, 0, 1);
206 a->add (_input_or_output);
207 t->attach (*Gtk::manage (a), 1, 2, 1, 2);
208 _input_or_output.append_text (_("Destination"));
209 _input_or_output.append_text (_("Source"));
211 if (bundle->ports_are_inputs()) {
212 _input_or_output.set_active_text (_("Source"));
214 _input_or_output.set_active_text (_("Destination"));
217 _input_or_output.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::input_or_output_changed));
219 get_vbox()->pack_start (*Gtk::manage (t), false, false);
220 get_vbox()->pack_start (_matrix);
221 get_vbox()->set_spacing (4);
225 signal_key_press_event().connect (sigc::mem_fun (_matrix, &BundleEditorMatrix::key_press));
229 BundleEditor::on_show ()
231 Gtk::Window::on_show ();
232 pair<uint32_t, uint32_t> const pm_max = _matrix.max_size ();
233 resize_window_to_proportion_of_monitor (this, pm_max.first, pm_max.second);
237 BundleEditor::name_changed ()
239 _bundle->set_name (_name.get_text ());
243 BundleEditor::input_or_output_changed ()
245 _bundle->remove_ports_from_channels ();
247 if (_input_or_output.get_active_text() == _("Source")) {
248 _bundle->set_ports_are_outputs ();
250 _bundle->set_ports_are_inputs ();
253 _matrix.setup_all_ports ();
257 BundleEditor::on_map ()
259 _matrix.setup_all_ports ();
264 BundleManager::BundleManager (Session* session)
265 : ArdourDialog (_("Bundle Manager"))
266 , edit_button (_("Edit"))
267 , delete_button (_("Delete"))
269 set_session (session);
271 _list_model = Gtk::ListStore::create (_list_model_columns);
272 _tree_view.set_model (_list_model);
273 _tree_view.append_column (_("Name"), _list_model_columns.name);
274 _tree_view.set_headers_visible (false);
276 boost::shared_ptr<BundleList> bundles = _session->bundles ();
277 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
281 /* New / Edit / Delete buttons */
282 Gtk::VBox* buttons = new Gtk::VBox;
283 buttons->set_spacing (8);
284 Gtk::Button* b = new Gtk::Button (_("New"));
285 b->set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::NEW, Gtk::ICON_SIZE_BUTTON)));
286 b->signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::new_clicked));
287 buttons->pack_start (*Gtk::manage (b), false, false);
288 edit_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::EDIT, Gtk::ICON_SIZE_BUTTON)));
289 edit_button.signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::edit_clicked));
290 buttons->pack_start (edit_button, false, false);
291 delete_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::StockID(GTK_STOCK_DELETE), Gtk::ICON_SIZE_BUTTON)));
292 delete_button.signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::delete_clicked));
293 buttons->pack_start (delete_button, false, false);
295 Gtk::HBox* h = new Gtk::HBox;
297 h->set_border_width (8);
298 h->pack_start (_tree_view);
299 h->pack_start (*Gtk::manage (buttons), false, false);
301 get_vbox()->set_spacing (8);
302 get_vbox()->pack_start (*Gtk::manage (h));
304 set_default_size (480, 240);
306 _tree_view.get_selection()->signal_changed().connect (
307 sigc::mem_fun (*this, &BundleManager::set_button_sensitivity)
310 _tree_view.signal_row_activated().connect (
311 sigc::mem_fun (*this, &BundleManager::row_activated)
314 set_button_sensitivity ();
320 BundleManager::set_button_sensitivity ()
322 bool const sel = (_tree_view.get_selection()->get_selected() != 0);
323 edit_button.set_sensitive (sel);
324 delete_button.set_sensitive (sel);
329 BundleManager::new_clicked ()
331 boost::shared_ptr<UserBundle> b (new UserBundle (_("Bundle")));
333 /* Start off with a single channel */
334 /* XXX: allow user to specify type */
335 b->add_channel ("1", DataType::AUDIO);
337 _session->add_bundle (b);
340 BundleEditor e (_session, b);
345 BundleManager::edit_clicked ()
347 Gtk::TreeModel::iterator i = _tree_view.get_selection()->get_selected();
349 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
350 BundleEditor e (_session, b);
356 BundleManager::delete_clicked ()
358 Gtk::TreeModel::iterator i = _tree_view.get_selection()->get_selected();
360 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
361 _session->remove_bundle (b);
362 _list_model->erase (i);
367 BundleManager::add_bundle (boost::shared_ptr<Bundle> b)
369 boost::shared_ptr<UserBundle> u = boost::dynamic_pointer_cast<UserBundle> (b);
374 Gtk::TreeModel::iterator i = _list_model->append ();
375 (*i)[_list_model_columns.name] = u->name ();
376 (*i)[_list_model_columns.bundle] = u;
378 u->Changed.connect (bundle_connections, invalidator (*this), boost::bind (&BundleManager::bundle_changed, this, _1, u), gui_context());
382 BundleManager::bundle_changed (Bundle::Change c, boost::shared_ptr<UserBundle> b)
384 if ((c & Bundle::NameChanged) == 0) {
388 Gtk::TreeModel::iterator i = _list_model->children().begin ();
389 while (i != _list_model->children().end()) {
390 boost::shared_ptr<UserBundle> t = (*i)[_list_model_columns.bundle];
397 if (i != _list_model->children().end()) {
398 (*i)[_list_model_columns.name] = b->name ();
403 BundleManager::row_activated (Gtk::TreeModel::Path const & p, Gtk::TreeViewColumn*)
405 Gtk::TreeModel::iterator i = _list_model->get_iter (p);
410 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
411 BundleEditor e (_session, b);
415 NameChannelDialog::NameChannelDialog ()
416 : ArdourDialog (_("Add Channel")),
422 NameChannelDialog::NameChannelDialog (boost::shared_ptr<Bundle> b, uint32_t c)
423 : ArdourDialog (_("Rename Channel")),
427 _name.set_text (b->channel_name (c));
433 NameChannelDialog::setup ()
435 Gtk::HBox* box = Gtk::manage (new Gtk::HBox ());
437 box->pack_start (*Gtk::manage (new Gtk::Label (_("Name"))));
438 box->pack_start (_name);
439 _name.set_activates_default (true);
441 get_vbox ()->pack_end (*box);
444 add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
446 add_button (Gtk::Stock::ADD, Gtk::RESPONSE_ACCEPT);
448 add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_ACCEPT);
450 set_default_response (Gtk::RESPONSE_ACCEPT);
454 NameChannelDialog::get_name () const
456 return _name.get_text ();