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 (_("Destination"));
207 _input_or_output.append_text (_("Source"));
209 if (bundle->ports_are_inputs()) {
210 _input_or_output.set_active_text (_("Source"));
212 _input_or_output.set_active_text (_("Destination"));
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);
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() == _("Source")) {
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 set_button_sensitivity ();
318 BundleManager::set_button_sensitivity ()
320 bool const sel = (_tree_view.get_selection()->get_selected() != 0);
321 edit_button.set_sensitive (sel);
322 delete_button.set_sensitive (sel);
327 BundleManager::new_clicked ()
329 boost::shared_ptr<UserBundle> b (new UserBundle (_("Bundle")));
331 /* Start off with a single channel */
332 /* XXX: allow user to specify type */
333 b->add_channel ("1", DataType::AUDIO);
335 _session->add_bundle (b);
338 BundleEditor e (_session, b);
343 BundleManager::edit_clicked ()
345 Gtk::TreeModel::iterator i = _tree_view.get_selection()->get_selected();
347 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
348 BundleEditor e (_session, b);
354 BundleManager::delete_clicked ()
356 Gtk::TreeModel::iterator i = _tree_view.get_selection()->get_selected();
358 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
359 _session->remove_bundle (b);
360 _list_model->erase (i);
365 BundleManager::add_bundle (boost::shared_ptr<Bundle> b)
367 boost::shared_ptr<UserBundle> u = boost::dynamic_pointer_cast<UserBundle> (b);
372 Gtk::TreeModel::iterator i = _list_model->append ();
373 (*i)[_list_model_columns.name] = u->name ();
374 (*i)[_list_model_columns.bundle] = u;
376 u->Changed.connect (bundle_connections, invalidator (*this), boost::bind (&BundleManager::bundle_changed, this, _1, u), gui_context());
380 BundleManager::bundle_changed (Bundle::Change c, boost::shared_ptr<UserBundle> b)
382 if ((c & Bundle::NameChanged) == 0) {
386 Gtk::TreeModel::iterator i = _list_model->children().begin ();
387 while (i != _list_model->children().end()) {
388 boost::shared_ptr<UserBundle> t = (*i)[_list_model_columns.bundle];
395 if (i != _list_model->children().end()) {
396 (*i)[_list_model_columns.name] = b->name ();
401 BundleManager::row_activated (Gtk::TreeModel::Path const & p, Gtk::TreeViewColumn*)
403 Gtk::TreeModel::iterator i = _list_model->get_iter (p);
408 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
409 BundleEditor e (_session, b);
413 NameChannelDialog::NameChannelDialog ()
414 : ArdourDialog (_("Add Channel")),
420 NameChannelDialog::NameChannelDialog (boost::shared_ptr<Bundle> b, uint32_t c)
421 : ArdourDialog (_("Rename Channel")),
425 _name.set_text (b->channel_name (c));
431 NameChannelDialog::setup ()
433 Gtk::HBox* box = Gtk::manage (new Gtk::HBox ());
435 box->pack_start (*Gtk::manage (new Gtk::Label (_("Name"))));
436 box->pack_start (_name);
437 _name.set_activates_default (true);
439 get_vbox ()->pack_end (*box);
442 add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
444 add_button (Gtk::Stock::ADD, Gtk::RESPONSE_ACCEPT);
446 add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_ACCEPT);
448 set_default_response (Gtk::RESPONSE_ACCEPT);
452 NameChannelDialog::get_name () const
454 return _name.get_text ();