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;
38 BundleEditorMatrix::BundleEditorMatrix (Gtk::Window* parent, Session* session, boost::shared_ptr<Bundle> bundle)
39 : PortMatrix (parent, session, DataType::NIL)
42 _port_group = boost::shared_ptr<PortGroup> (new PortGroup (""));
43 _port_group->add_bundle (_bundle);
50 BundleEditorMatrix::setup_ports (int dim)
53 _ports[OURS].clear ();
54 _ports[OURS].add_group (_port_group);
56 _ports[OTHER].suspend_signals ();
58 /* when we gather, allow the matrix to contain bundles with duplicate port sets,
59 otherwise in some cases the basic system IO ports may be hidden, making
60 the bundle editor useless */
62 _ports[OTHER].gather (_session, DataType::NIL, _bundle->ports_are_inputs(), true, show_only_bundles ());
63 _ports[OTHER].remove_bundle (_bundle);
64 _ports[OTHER].resume_signals ();
69 BundleEditorMatrix::set_state (BundleChannel c[2], bool s)
71 Bundle::PortList const& pl = c[OTHER].bundle->channel_ports (c[OTHER].channel);
72 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
74 c[OURS].bundle->add_port_to_channel (c[OURS].channel, *i);
76 c[OURS].bundle->remove_port_from_channel (c[OURS].channel, *i);
82 BundleEditorMatrix::get_state (BundleChannel c[2]) const
84 if (c[0].bundle->nchannels() == ChanCount::ZERO || c[1].bundle->nchannels() == ChanCount::ZERO) {
85 return PortMatrixNode::NOT_ASSOCIATED;
88 Bundle::PortList const& pl = c[OTHER].bundle->channel_ports (c[OTHER].channel);
90 return PortMatrixNode::NOT_ASSOCIATED;
93 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
94 if (!c[OURS].bundle->port_attached_to_channel (c[OURS].channel, *i)) {
95 return PortMatrixNode::NOT_ASSOCIATED;
99 return PortMatrixNode::ASSOCIATED;
103 BundleEditorMatrix::can_add_channels (boost::shared_ptr<Bundle> b) const
109 return PortMatrix::can_add_channels (b);
113 BundleEditorMatrix::add_channel (boost::shared_ptr<Bundle> b, DataType t)
119 if (d.run () != Gtk::RESPONSE_ACCEPT) {
123 _bundle->add_channel (d.get_name(), t);
128 PortMatrix::add_channel (b, t);
134 BundleEditorMatrix::can_remove_channels (boost::shared_ptr<Bundle> b) const
140 return PortMatrix::can_remove_channels (b);
144 BundleEditorMatrix::remove_channel (BundleChannel bc)
146 bc.bundle->remove_channel (bc.channel);
151 BundleEditorMatrix::can_rename_channels (boost::shared_ptr<Bundle> b) const
157 return PortMatrix::can_rename_channels (b);
161 BundleEditorMatrix::rename_channel (BundleChannel bc)
163 NameChannelDialog d (bc.bundle, bc.channel);
165 if (d.run () != Gtk::RESPONSE_ACCEPT) {
169 bc.bundle->set_channel_name (bc.channel, d.get_name ());
173 BundleEditorMatrix::list_is_global (int dim) const
175 return (dim == OTHER);
179 BundleEditorMatrix::disassociation_verb () const
181 return _("Disassociate");
184 BundleEditor::BundleEditor (Session* session, boost::shared_ptr<UserBundle> bundle)
185 : ArdourDialog (_("Edit Bundle")), _matrix (this, session, bundle), _bundle (bundle)
187 Gtk::Table* t = new Gtk::Table (3, 2);
191 Gtk::Alignment* a = new Gtk::Alignment (1, 0.5, 0, 1);
192 a->add (*Gtk::manage (new Gtk::Label (_("Name:"))));
193 t->attach (*Gtk::manage (a), 0, 1, 0, 1, Gtk::FILL, Gtk::FILL);
194 t->attach (_name, 1, 2, 0, 1);
195 _name.set_text (_bundle->name ());
196 _name.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::name_changed));
198 /* Direction (input or output) */
199 a = new Gtk::Alignment (1, 0.5, 0, 1);
200 a->add (*Gtk::manage (new Gtk::Label (_("Direction:"))));
201 t->attach (*Gtk::manage (a), 0, 1, 1, 2, Gtk::FILL, Gtk::FILL);
202 a = new Gtk::Alignment (0, 0.5, 0, 1);
203 a->add (_input_or_output);
204 t->attach (*Gtk::manage (a), 1, 2, 1, 2);
205 _input_or_output.append_text (_("Input"));
206 _input_or_output.append_text (_("Output"));
208 if (bundle->ports_are_inputs()) {
209 _input_or_output.set_active_text (_("Input"));
211 _input_or_output.set_active_text (_("Output"));
214 _input_or_output.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::input_or_output_changed));
216 get_vbox()->pack_start (*Gtk::manage (t), false, false);
217 get_vbox()->pack_start (_matrix);
218 get_vbox()->set_spacing (4);
220 add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_ACCEPT);
223 signal_key_press_event().connect (sigc::mem_fun (_matrix, &BundleEditorMatrix::key_press));
227 BundleEditor::on_show ()
229 Gtk::Window::on_show ();
230 pair<uint32_t, uint32_t> const pm_max = _matrix.max_size ();
231 resize_window_to_proportion_of_monitor (this, pm_max.first, pm_max.second);
235 BundleEditor::name_changed ()
237 _bundle->set_name (_name.get_text ());
241 BundleEditor::input_or_output_changed ()
243 _bundle->remove_ports_from_channels ();
245 if (_input_or_output.get_active_text() == _("Output")) {
246 _bundle->set_ports_are_outputs ();
248 _bundle->set_ports_are_inputs ();
251 _matrix.setup_all_ports ();
255 BundleEditor::on_map ()
257 _matrix.setup_all_ports ();
262 BundleManager::BundleManager (Session* session)
263 : ArdourDialog (_("Bundle Manager"))
264 , edit_button (_("Edit"))
265 , delete_button (_("Delete"))
267 set_session (session);
269 _list_model = Gtk::ListStore::create (_list_model_columns);
270 _tree_view.set_model (_list_model);
271 _tree_view.append_column (_("Name"), _list_model_columns.name);
272 _tree_view.set_headers_visible (false);
274 boost::shared_ptr<BundleList> bundles = _session->bundles ();
275 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
279 /* New / Edit / Delete buttons */
280 Gtk::VBox* buttons = new Gtk::VBox;
281 buttons->set_spacing (8);
282 Gtk::Button* b = new Gtk::Button (_("New"));
283 b->set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::NEW, Gtk::ICON_SIZE_BUTTON)));
284 b->signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::new_clicked));
285 buttons->pack_start (*Gtk::manage (b), false, false);
286 edit_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::EDIT, Gtk::ICON_SIZE_BUTTON)));
287 edit_button.signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::edit_clicked));
288 buttons->pack_start (edit_button, false, false);
289 delete_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::StockID(GTK_STOCK_DELETE), Gtk::ICON_SIZE_BUTTON)));
290 delete_button.signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::delete_clicked));
291 buttons->pack_start (delete_button, false, false);
293 Gtk::HBox* h = new Gtk::HBox;
295 h->set_border_width (8);
296 h->pack_start (_tree_view);
297 h->pack_start (*Gtk::manage (buttons), false, false);
299 get_vbox()->set_spacing (8);
300 get_vbox()->pack_start (*Gtk::manage (h));
302 set_default_size (480, 240);
304 _tree_view.get_selection()->signal_changed().connect (
305 sigc::mem_fun (*this, &BundleManager::set_button_sensitivity)
308 _tree_view.signal_row_activated().connect (
309 sigc::mem_fun (*this, &BundleManager::row_activated)
312 Gtk::Button* close_but = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_ACCEPT);
313 close_but->signal_clicked ().connect (sigc::mem_fun (*this, &Gtk::Window::hide));
315 set_button_sensitivity ();
321 BundleManager::set_button_sensitivity ()
323 bool const sel = (_tree_view.get_selection()->get_selected() != 0);
324 edit_button.set_sensitive (sel);
325 delete_button.set_sensitive (sel);
330 BundleManager::new_clicked ()
332 boost::shared_ptr<UserBundle> b (new UserBundle (_("Bundle")));
334 /* Start off with a single channel */
335 /* XXX: allow user to specify type */
336 b->add_channel ("1", DataType::AUDIO);
338 _session->add_bundle (b);
341 BundleEditor e (_session, b);
346 BundleManager::edit_clicked ()
348 Gtk::TreeModel::iterator i = _tree_view.get_selection()->get_selected();
350 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
351 BundleEditor e (_session, b);
357 BundleManager::delete_clicked ()
359 Gtk::TreeModel::iterator i = _tree_view.get_selection()->get_selected();
361 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
362 _session->remove_bundle (b);
363 _list_model->erase (i);
368 BundleManager::add_bundle (boost::shared_ptr<Bundle> b)
370 boost::shared_ptr<UserBundle> u = boost::dynamic_pointer_cast<UserBundle> (b);
375 Gtk::TreeModel::iterator i = _list_model->append ();
376 (*i)[_list_model_columns.name] = u->name ();
377 (*i)[_list_model_columns.bundle] = u;
379 u->Changed.connect (bundle_connections, invalidator (*this), boost::bind (&BundleManager::bundle_changed, this, _1, u), gui_context());
383 BundleManager::bundle_changed (Bundle::Change c, boost::shared_ptr<UserBundle> b)
385 if ((c & Bundle::NameChanged) == 0) {
389 Gtk::TreeModel::iterator i = _list_model->children().begin ();
390 while (i != _list_model->children().end()) {
391 boost::shared_ptr<UserBundle> t = (*i)[_list_model_columns.bundle];
398 if (i != _list_model->children().end()) {
399 (*i)[_list_model_columns.name] = b->name ();
404 BundleManager::row_activated (Gtk::TreeModel::Path const & p, Gtk::TreeViewColumn*)
406 Gtk::TreeModel::iterator i = _list_model->get_iter (p);
411 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
412 BundleEditor e (_session, b);
416 NameChannelDialog::NameChannelDialog ()
417 : ArdourDialog (_("Add Channel")),
423 NameChannelDialog::NameChannelDialog (boost::shared_ptr<Bundle> b, uint32_t c)
424 : 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 ();