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>
27 #include "ardour/session.h"
28 #include "ardour/user_bundle.h"
29 #include "ardour/audioengine.h"
30 #include "bundle_manager.h"
35 using namespace ARDOUR;
37 BundleEditorMatrix::BundleEditorMatrix (
38 Gtk::Window* parent, Session& session, boost::shared_ptr<Bundle> bundle
40 : PortMatrix (parent, session, bundle->type()),
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, _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 Bundle::PortList const& pl = c[OTHER].bundle->channel_ports (c[OTHER].channel);
87 return PortMatrixNode::NOT_ASSOCIATED;
90 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
91 if (!c[OURS].bundle->port_attached_to_channel (c[OURS].channel, *i)) {
92 return PortMatrixNode::NOT_ASSOCIATED;
96 return PortMatrixNode::ASSOCIATED;
100 BundleEditorMatrix::can_add_channel (boost::shared_ptr<Bundle> b) const
106 return PortMatrix::can_add_channel (b);
110 BundleEditorMatrix::add_channel (boost::shared_ptr<Bundle> b)
115 d.set_position (Gtk::WIN_POS_MOUSE);
117 if (d.run () != Gtk::RESPONSE_ACCEPT) {
121 _bundle->add_channel (d.get_name());
126 PortMatrix::add_channel (b);
132 BundleEditorMatrix::can_remove_channels (boost::shared_ptr<Bundle> b) const
138 return PortMatrix::can_remove_channels (b);
142 BundleEditorMatrix::remove_channel (BundleChannel bc)
144 bc.bundle->remove_channel (bc.channel);
149 BundleEditorMatrix::can_rename_channels (boost::shared_ptr<Bundle> b) const
155 return PortMatrix::can_rename_channels (b);
159 BundleEditorMatrix::rename_channel (BundleChannel bc)
161 NameChannelDialog d (bc.bundle, bc.channel);
162 d.set_position (Gtk::WIN_POS_MOUSE);
164 if (d.run () != Gtk::RESPONSE_ACCEPT) {
168 bc.bundle->set_channel_name (bc.channel, d.get_name ());
172 BundleEditorMatrix::list_is_global (int dim) const
174 return (dim == OTHER);
177 BundleEditor::BundleEditor (Session& session, boost::shared_ptr<UserBundle> bundle)
178 : ArdourDialog (_("Edit Bundle")), _matrix (this, session, bundle), _bundle (bundle)
180 Gtk::Table* t = new Gtk::Table (3, 2);
184 Gtk::Alignment* a = new Gtk::Alignment (1, 0.5, 0, 1);
185 a->add (*Gtk::manage (new Gtk::Label (_("Name:"))));
186 t->attach (*Gtk::manage (a), 0, 1, 0, 1, Gtk::FILL, Gtk::FILL);
187 t->attach (_name, 1, 2, 0, 1);
188 _name.set_text (_bundle->name ());
189 _name.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::name_changed));
191 /* Direction (input or output) */
192 a = new Gtk::Alignment (1, 0.5, 0, 1);
193 a->add (*Gtk::manage (new Gtk::Label (_("Direction:"))));
194 t->attach (*Gtk::manage (a), 0, 1, 1, 2, Gtk::FILL, Gtk::FILL);
195 a = new Gtk::Alignment (0, 0.5, 0, 1);
196 a->add (_input_or_output);
197 t->attach (*Gtk::manage (a), 1, 2, 1, 2);
198 _input_or_output.append_text (_("Input"));
199 _input_or_output.append_text (_("Output"));
201 if (bundle->ports_are_inputs()) {
202 _input_or_output.set_active_text (_("Input"));
204 _input_or_output.set_active_text (_("Output"));
207 _input_or_output.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::input_or_output_changed));
209 /* Type (audio or MIDI) */
210 a = new Gtk::Alignment (1, 0.5, 0, 1);
211 a->add (*Gtk::manage (new Gtk::Label (_("Type:"))));
212 t->attach (*Gtk::manage (a), 0, 1, 2, 3, Gtk::FILL, Gtk::FILL);
213 a = new Gtk::Alignment (0, 0.5, 0, 1);
215 t->attach (*Gtk::manage (a), 1, 2, 2, 3);
217 _type.append_text (_("Audio"));
218 _type.append_text (_("MIDI"));
220 switch (bundle->type ()) {
221 case DataType::AUDIO:
222 _type.set_active_text (_("Audio"));
225 _type.set_active_text (_("MIDI"));
229 _type.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::type_changed));
231 get_vbox()->pack_start (*Gtk::manage (t), false, false);
232 get_vbox()->pack_start (_matrix);
233 get_vbox()->set_spacing (4);
235 add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_ACCEPT);
240 BundleEditor::on_show ()
242 Gtk::Window::on_show ();
243 pair<uint32_t, uint32_t> const pm_max = _matrix.max_size ();
244 resize_window_to_proportion_of_monitor (this, pm_max.first, pm_max.second);
248 BundleEditor::name_changed ()
250 _bundle->set_name (_name.get_text ());
254 BundleEditor::input_or_output_changed ()
256 _bundle->remove_ports_from_channels ();
258 if (_input_or_output.get_active_text() == _("Output")) {
259 _bundle->set_ports_are_outputs ();
261 _bundle->set_ports_are_inputs ();
264 _matrix.setup_all_ports ();
268 BundleEditor::type_changed ()
270 _bundle->remove_ports_from_channels ();
272 DataType const t = _type.get_active_text() == _("Audio") ?
273 DataType::AUDIO : DataType::MIDI;
275 _bundle->set_type (t);
276 _matrix.set_type (t);
280 BundleEditor::on_map ()
282 _matrix.setup_all_ports ();
287 BundleManager::BundleManager (Session& session)
288 : ArdourDialog (_("Bundle Manager")), _session (session), edit_button (_("Edit")), delete_button (_("Delete"))
290 _list_model = Gtk::ListStore::create (_list_model_columns);
291 _tree_view.set_model (_list_model);
292 _tree_view.append_column (_("Name"), _list_model_columns.name);
293 _tree_view.set_headers_visible (false);
295 boost::shared_ptr<BundleList> bundles = _session.bundles ();
296 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
300 /* New / Edit / Delete buttons */
301 Gtk::VBox* buttons = new Gtk::VBox;
302 buttons->set_spacing (8);
303 Gtk::Button* b = new Gtk::Button (_("New"));
304 b->set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::NEW, Gtk::ICON_SIZE_BUTTON)));
305 b->signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::new_clicked));
306 buttons->pack_start (*Gtk::manage (b), false, false);
307 edit_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::EDIT, Gtk::ICON_SIZE_BUTTON)));
308 edit_button.signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::edit_clicked));
309 buttons->pack_start (edit_button, false, false);
310 delete_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::DELETE, Gtk::ICON_SIZE_BUTTON)));
311 delete_button.signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::delete_clicked));
312 buttons->pack_start (delete_button, false, false);
314 Gtk::HBox* h = new Gtk::HBox;
316 h->set_border_width (8);
317 h->pack_start (_tree_view);
318 h->pack_start (*Gtk::manage (buttons), false, false);
320 get_vbox()->set_spacing (8);
321 get_vbox()->pack_start (*Gtk::manage (h));
323 set_default_size (480, 240);
325 _tree_view.get_selection()->signal_changed().connect (
326 sigc::mem_fun (*this, &BundleManager::set_button_sensitivity)
329 _tree_view.signal_row_activated().connect (
330 sigc::mem_fun (*this, &BundleManager::row_activated)
333 set_button_sensitivity ();
339 BundleManager::set_button_sensitivity ()
341 bool const sel = (_tree_view.get_selection()->get_selected() != 0);
342 edit_button.set_sensitive (sel);
343 delete_button.set_sensitive (sel);
348 BundleManager::new_clicked ()
350 boost::shared_ptr<UserBundle> b (new UserBundle (_("Bundle")));
352 /* Start off with a single channel */
353 b->add_channel ("1");
355 _session.add_bundle (b);
358 BundleEditor e (_session, b);
363 BundleManager::edit_clicked ()
365 Gtk::TreeModel::iterator i = _tree_view.get_selection()->get_selected();
367 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
368 BundleEditor e (_session, b);
374 BundleManager::delete_clicked ()
376 Gtk::TreeModel::iterator i = _tree_view.get_selection()->get_selected();
378 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
379 _session.remove_bundle (b);
380 _list_model->erase (i);
385 BundleManager::add_bundle (boost::shared_ptr<Bundle> b)
387 boost::shared_ptr<UserBundle> u = boost::dynamic_pointer_cast<UserBundle> (b);
392 Gtk::TreeModel::iterator i = _list_model->append ();
393 (*i)[_list_model_columns.name] = u->name ();
394 (*i)[_list_model_columns.bundle] = u;
396 u->Changed.connect (sigc::bind (sigc::mem_fun (*this, &BundleManager::bundle_changed), u));
400 BundleManager::bundle_changed (Bundle::Change c, boost::shared_ptr<UserBundle> b)
402 if ((c & Bundle::NameChanged) == 0) {
406 Gtk::TreeModel::iterator i = _list_model->children().begin ();
407 while (i != _list_model->children().end()) {
408 boost::shared_ptr<UserBundle> t = (*i)[_list_model_columns.bundle];
415 if (i != _list_model->children().end()) {
416 (*i)[_list_model_columns.name] = b->name ();
421 BundleManager::row_activated (Gtk::TreeModel::Path const & p, Gtk::TreeViewColumn* c)
423 Gtk::TreeModel::iterator i = _list_model->get_iter (p);
428 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
429 BundleEditor e (_session, b);
433 NameChannelDialog::NameChannelDialog ()
434 : ArdourDialog (_("Add channel")),
440 NameChannelDialog::NameChannelDialog (boost::shared_ptr<Bundle> b, uint32_t c)
441 : ArdourDialog (_("Rename channel")),
446 _name.set_text (b->channel_name (c));
452 NameChannelDialog::setup ()
454 Gtk::HBox* box = Gtk::manage (new Gtk::HBox ());
456 box->pack_start (*Gtk::manage (new Gtk::Label (_("Name"))));
457 box->pack_start (_name);
458 _name.set_activates_default (true);
460 get_vbox ()->pack_end (*box);
463 add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
465 add_button (Gtk::Stock::ADD, Gtk::RESPONSE_ACCEPT);
467 add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_ACCEPT);
469 set_default_response (Gtk::RESPONSE_ACCEPT);
473 NameChannelDialog::get_name () const
475 return _name.get_text ();