2 Copyright (C) 2007 Paul Davis
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.
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.
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.
20 #include <gtkmm/stock.h>
21 #include <gtkmm/button.h>
22 #include <gtkmm/label.h>
23 #include <gtkmm/entry.h>
24 #include <gtkmm/table.h>
25 #include <gtkmm/comboboxtext.h>
26 #include <gtkmm/alignment.h>
28 #include "ardour/session.h"
29 #include "ardour/user_bundle.h"
30 #include "ardour/audioengine.h"
31 #include "bundle_manager.h"
32 #include "gui_thread.h"
37 using namespace ARDOUR;
39 BundleEditorMatrix::BundleEditorMatrix (Gtk::Window* parent, Session* session, boost::shared_ptr<Bundle> bundle)
40 : PortMatrix (parent, session, DataType::NIL)
43 _port_group = boost::shared_ptr<PortGroup> (new PortGroup (""));
44 _port_group->add_bundle (_bundle);
51 BundleEditorMatrix::setup_ports (int dim)
54 _ports[OURS].clear ();
55 _ports[OURS].add_group (_port_group);
57 _ports[OTHER].suspend_signals ();
59 /* when we gather, allow the matrix to contain bundles with duplicate port sets,
60 otherwise in some cases the basic system IO ports may be hidden, making
61 the bundle editor useless */
63 _ports[OTHER].gather (_session, DataType::NIL, _bundle->ports_are_inputs(), true);
64 _ports[OTHER].remove_bundle (_bundle);
65 _ports[OTHER].resume_signals ();
70 BundleEditorMatrix::set_state (BundleChannel c[2], bool s)
72 Bundle::PortList const& pl = c[OTHER].bundle->channel_ports (c[OTHER].channel);
73 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
75 c[OURS].bundle->add_port_to_channel (c[OURS].channel, *i);
77 c[OURS].bundle->remove_port_from_channel (c[OURS].channel, *i);
83 BundleEditorMatrix::get_state (BundleChannel c[2]) const
85 if (c[0].bundle->nchannels() == ChanCount::ZERO || c[1].bundle->nchannels() == ChanCount::ZERO) {
86 return PortMatrixNode::NOT_ASSOCIATED;
89 Bundle::PortList const& pl = c[OTHER].bundle->channel_ports (c[OTHER].channel);
91 return PortMatrixNode::NOT_ASSOCIATED;
94 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
95 if (!c[OURS].bundle->port_attached_to_channel (c[OURS].channel, *i)) {
96 return PortMatrixNode::NOT_ASSOCIATED;
100 return PortMatrixNode::ASSOCIATED;
104 BundleEditorMatrix::can_add_channel (boost::shared_ptr<Bundle> b) const
110 return PortMatrix::can_add_channel (b);
114 BundleEditorMatrix::add_channel (boost::shared_ptr<Bundle> b, DataType t)
119 d.set_position (Gtk::WIN_POS_MOUSE);
121 if (d.run () != Gtk::RESPONSE_ACCEPT) {
125 _bundle->add_channel (d.get_name(), t);
130 PortMatrix::add_channel (b, t);
136 BundleEditorMatrix::can_remove_channels (boost::shared_ptr<Bundle> b) const
142 return PortMatrix::can_remove_channels (b);
146 BundleEditorMatrix::remove_channel (BundleChannel bc)
148 bc.bundle->remove_channel (bc.channel);
153 BundleEditorMatrix::can_rename_channels (boost::shared_ptr<Bundle> b) const
159 return PortMatrix::can_rename_channels (b);
163 BundleEditorMatrix::rename_channel (BundleChannel bc)
165 NameChannelDialog d (bc.bundle, bc.channel);
166 d.set_position (Gtk::WIN_POS_MOUSE);
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 (_("Input"));
209 _input_or_output.append_text (_("Output"));
211 if (bundle->ports_are_inputs()) {
212 _input_or_output.set_active_text (_("Input"));
214 _input_or_output.set_active_text (_("Output"));
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);
223 add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_ACCEPT);
228 BundleEditor::on_show ()
230 Gtk::Window::on_show ();
231 pair<uint32_t, uint32_t> const pm_max = _matrix.max_size ();
232 resize_window_to_proportion_of_monitor (this, pm_max.first, pm_max.second);
236 BundleEditor::name_changed ()
238 _bundle->set_name (_name.get_text ());
242 BundleEditor::input_or_output_changed ()
244 _bundle->remove_ports_from_channels ();
246 if (_input_or_output.get_active_text() == _("Output")) {
247 _bundle->set_ports_are_outputs ();
249 _bundle->set_ports_are_inputs ();
252 _matrix.setup_all_ports ();
256 BundleEditor::on_map ()
258 _matrix.setup_all_ports ();
263 BundleManager::BundleManager (Session* session)
264 : ArdourDialog (_("Bundle Manager"))
265 , edit_button (_("Edit"))
266 , delete_button (_("Delete"))
268 set_session (session);
270 _list_model = Gtk::ListStore::create (_list_model_columns);
271 _tree_view.set_model (_list_model);
272 _tree_view.append_column (_("Name"), _list_model_columns.name);
273 _tree_view.set_headers_visible (false);
275 boost::shared_ptr<BundleList> bundles = _session->bundles ();
276 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
280 /* New / Edit / Delete buttons */
281 Gtk::VBox* buttons = new Gtk::VBox;
282 buttons->set_spacing (8);
283 Gtk::Button* b = new Gtk::Button (_("New"));
284 b->set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::NEW, Gtk::ICON_SIZE_BUTTON)));
285 b->signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::new_clicked));
286 buttons->pack_start (*Gtk::manage (b), false, false);
287 edit_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::EDIT, Gtk::ICON_SIZE_BUTTON)));
288 edit_button.signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::edit_clicked));
289 buttons->pack_start (edit_button, false, false);
290 delete_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::DELETE, Gtk::ICON_SIZE_BUTTON)));
291 delete_button.signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::delete_clicked));
292 buttons->pack_start (delete_button, false, false);
294 Gtk::HBox* h = new Gtk::HBox;
296 h->set_border_width (8);
297 h->pack_start (_tree_view);
298 h->pack_start (*Gtk::manage (buttons), false, false);
300 get_vbox()->set_spacing (8);
301 get_vbox()->pack_start (*Gtk::manage (h));
303 set_default_size (480, 240);
305 _tree_view.get_selection()->signal_changed().connect (
306 sigc::mem_fun (*this, &BundleManager::set_button_sensitivity)
309 _tree_view.signal_row_activated().connect (
310 sigc::mem_fun (*this, &BundleManager::row_activated)
313 set_button_sensitivity ();
319 BundleManager::set_button_sensitivity ()
321 bool const sel = (_tree_view.get_selection()->get_selected() != 0);
322 edit_button.set_sensitive (sel);
323 delete_button.set_sensitive (sel);
328 BundleManager::new_clicked ()
330 boost::shared_ptr<UserBundle> b (new UserBundle (_("Bundle")));
332 /* Start off with a single channel */
333 /* XXX: allow user to specify type */
334 b->add_channel ("1", DataType::AUDIO);
336 _session->add_bundle (b);
339 BundleEditor e (_session, b);
344 BundleManager::edit_clicked ()
346 Gtk::TreeModel::iterator i = _tree_view.get_selection()->get_selected();
348 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
349 BundleEditor e (_session, b);
355 BundleManager::delete_clicked ()
357 Gtk::TreeModel::iterator i = _tree_view.get_selection()->get_selected();
359 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
360 _session->remove_bundle (b);
361 _list_model->erase (i);
366 BundleManager::add_bundle (boost::shared_ptr<Bundle> b)
368 boost::shared_ptr<UserBundle> u = boost::dynamic_pointer_cast<UserBundle> (b);
373 Gtk::TreeModel::iterator i = _list_model->append ();
374 (*i)[_list_model_columns.name] = u->name ();
375 (*i)[_list_model_columns.bundle] = u;
377 u->Changed.connect (bundle_connections, invalidator (*this), ui_bind (&BundleManager::bundle_changed, this, _1, u), gui_context());
381 BundleManager::bundle_changed (Bundle::Change c, boost::shared_ptr<UserBundle> b)
383 if ((c & Bundle::NameChanged) == 0) {
387 Gtk::TreeModel::iterator i = _list_model->children().begin ();
388 while (i != _list_model->children().end()) {
389 boost::shared_ptr<UserBundle> t = (*i)[_list_model_columns.bundle];
396 if (i != _list_model->children().end()) {
397 (*i)[_list_model_columns.name] = b->name ();
402 BundleManager::row_activated (Gtk::TreeModel::Path const & p, Gtk::TreeViewColumn*)
404 Gtk::TreeModel::iterator i = _list_model->get_iter (p);
409 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
410 BundleEditor e (_session, b);
414 NameChannelDialog::NameChannelDialog ()
415 : ArdourDialog (_("Add Channel")),
421 NameChannelDialog::NameChannelDialog (boost::shared_ptr<Bundle> b, uint32_t c)
422 : 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 ();