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 "bundle_manager.h"
31 #include "gui_thread.h"
36 using namespace ARDOUR;
37 using namespace ARDOUR_UI_UTILS;
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, show_only_bundles ());
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_channels (boost::shared_ptr<Bundle> b) const
110 return PortMatrix::can_add_channels (b);
114 BundleEditorMatrix::add_channel (boost::shared_ptr<Bundle> b, DataType t)
120 if (d.run () != Gtk::RESPONSE_ACCEPT) {
124 _bundle->add_channel (d.get_name(), t);
129 PortMatrix::add_channel (b, t);
135 BundleEditorMatrix::can_remove_channels (boost::shared_ptr<Bundle> b) const
141 return PortMatrix::can_remove_channels (b);
145 BundleEditorMatrix::remove_channel (BundleChannel bc)
147 bc.bundle->remove_channel (bc.channel);
152 BundleEditorMatrix::can_rename_channels (boost::shared_ptr<Bundle> b) const
158 return PortMatrix::can_rename_channels (b);
162 BundleEditorMatrix::rename_channel (BundleChannel bc)
164 NameChannelDialog d (bc.bundle, bc.channel);
166 if (d.run () != Gtk::RESPONSE_ACCEPT) {
170 bc.bundle->set_channel_name (bc.channel, d.get_name ());
174 BundleEditorMatrix::list_is_global (int dim) const
176 return (dim == OTHER);
180 BundleEditorMatrix::disassociation_verb () const
182 return _("Disassociate");
185 BundleEditor::BundleEditor (Session* session, boost::shared_ptr<UserBundle> bundle)
186 : ArdourDialog (_("Edit Bundle")), _matrix (this, session, bundle), _bundle (bundle)
188 Gtk::Table* t = new Gtk::Table (3, 2);
192 Gtk::Alignment* a = new Gtk::Alignment (1, 0.5, 0, 1);
193 a->add (*Gtk::manage (new Gtk::Label (_("Name:"))));
194 t->attach (*Gtk::manage (a), 0, 1, 0, 1, Gtk::FILL, Gtk::FILL);
195 t->attach (_name, 1, 2, 0, 1);
196 _name.set_text (_bundle->name ());
197 _name.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::name_changed));
199 /* Direction (input or output) */
200 a = new Gtk::Alignment (1, 0.5, 0, 1);
201 a->add (*Gtk::manage (new Gtk::Label (_("Direction:"))));
202 t->attach (*Gtk::manage (a), 0, 1, 1, 2, Gtk::FILL, Gtk::FILL);
203 a = new Gtk::Alignment (0, 0.5, 0, 1);
204 a->add (_input_or_output);
205 t->attach (*Gtk::manage (a), 1, 2, 1, 2);
206 _input_or_output.append_text (_("Input"));
207 _input_or_output.append_text (_("Output"));
209 if (bundle->ports_are_inputs()) {
210 _input_or_output.set_active_text (_("Input"));
212 _input_or_output.set_active_text (_("Output"));
215 _input_or_output.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::input_or_output_changed));
217 get_vbox()->pack_start (*Gtk::manage (t), false, false);
218 get_vbox()->pack_start (_matrix);
219 get_vbox()->set_spacing (4);
221 add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_ACCEPT);
224 signal_key_press_event().connect (sigc::mem_fun (_matrix, &BundleEditorMatrix::key_press));
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::StockID(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 Gtk::Button* close_but = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_ACCEPT);
314 close_but->signal_clicked ().connect (sigc::mem_fun (*this, &Gtk::Window::hide));
316 set_button_sensitivity ();
322 BundleManager::set_button_sensitivity ()
324 bool const sel = (_tree_view.get_selection()->get_selected() != 0);
325 edit_button.set_sensitive (sel);
326 delete_button.set_sensitive (sel);
331 BundleManager::new_clicked ()
333 boost::shared_ptr<UserBundle> b (new UserBundle (_("Bundle")));
335 /* Start off with a single channel */
336 /* XXX: allow user to specify type */
337 b->add_channel ("1", DataType::AUDIO);
339 _session->add_bundle (b);
342 BundleEditor e (_session, b);
347 BundleManager::edit_clicked ()
349 Gtk::TreeModel::iterator i = _tree_view.get_selection()->get_selected();
351 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
352 BundleEditor e (_session, b);
358 BundleManager::delete_clicked ()
360 Gtk::TreeModel::iterator i = _tree_view.get_selection()->get_selected();
362 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
363 _session->remove_bundle (b);
364 _list_model->erase (i);
369 BundleManager::add_bundle (boost::shared_ptr<Bundle> b)
371 boost::shared_ptr<UserBundle> u = boost::dynamic_pointer_cast<UserBundle> (b);
376 Gtk::TreeModel::iterator i = _list_model->append ();
377 (*i)[_list_model_columns.name] = u->name ();
378 (*i)[_list_model_columns.bundle] = u;
380 u->Changed.connect (bundle_connections, invalidator (*this), boost::bind (&BundleManager::bundle_changed, this, _1, u), gui_context());
384 BundleManager::bundle_changed (Bundle::Change c, boost::shared_ptr<UserBundle> b)
386 if ((c & Bundle::NameChanged) == 0) {
390 Gtk::TreeModel::iterator i = _list_model->children().begin ();
391 while (i != _list_model->children().end()) {
392 boost::shared_ptr<UserBundle> t = (*i)[_list_model_columns.bundle];
399 if (i != _list_model->children().end()) {
400 (*i)[_list_model_columns.name] = b->name ();
405 BundleManager::row_activated (Gtk::TreeModel::Path const & p, Gtk::TreeViewColumn*)
407 Gtk::TreeModel::iterator i = _list_model->get_iter (p);
412 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
413 BundleEditor e (_session, b);
417 NameChannelDialog::NameChannelDialog ()
418 : ArdourDialog (_("Add Channel")),
424 NameChannelDialog::NameChannelDialog (boost::shared_ptr<Bundle> b, uint32_t c)
425 : ArdourDialog (_("Rename Channel")),
429 _name.set_text (b->channel_name (c));
435 NameChannelDialog::setup ()
437 Gtk::HBox* box = Gtk::manage (new Gtk::HBox ());
439 box->pack_start (*Gtk::manage (new Gtk::Label (_("Name"))));
440 box->pack_start (_name);
441 _name.set_activates_default (true);
443 get_vbox ()->pack_end (*box);
446 add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
448 add_button (Gtk::Stock::ADD, Gtk::RESPONSE_ACCEPT);
450 add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_ACCEPT);
452 set_default_response (Gtk::RESPONSE_ACCEPT);
456 NameChannelDialog::get_name () const
458 return _name.get_text ();