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);
48 BundleEditorMatrix::setup_ports (int dim)
51 _ports[OURS].clear ();
52 _ports[OURS].add_group (_port_group);
54 _ports[OTHER].suspend_signals ();
56 /* when we gather, allow the matrix to contain bundles with duplicate port sets,
57 otherwise in some cases the basic system IO ports may be hidden, making
58 the bundle editor useless */
60 _ports[OTHER].gather (_session, _bundle->ports_are_inputs(), true);
61 _ports[OTHER].remove_bundle (_bundle);
62 _ports[OTHER].resume_signals ();
67 BundleEditorMatrix::set_state (BundleChannel c[2], bool s)
69 Bundle::PortList const& pl = c[OTHER].bundle->channel_ports (c[OTHER].channel);
70 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
72 c[OURS].bundle->add_port_to_channel (c[OURS].channel, *i);
74 c[OURS].bundle->remove_port_from_channel (c[OURS].channel, *i);
80 BundleEditorMatrix::get_state (BundleChannel c[2]) const
82 Bundle::PortList const& pl = c[OTHER].bundle->channel_ports (c[OTHER].channel);
84 return PortMatrixNode::NOT_ASSOCIATED;
87 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
88 if (!c[OURS].bundle->port_attached_to_channel (c[OURS].channel, *i)) {
89 return PortMatrixNode::NOT_ASSOCIATED;
93 return PortMatrixNode::ASSOCIATED;
97 BundleEditorMatrix::can_add_channel (boost::shared_ptr<Bundle> b) const
103 return PortMatrix::can_add_channel (b);
107 BundleEditorMatrix::add_channel (boost::shared_ptr<Bundle> b)
112 d.set_position (Gtk::WIN_POS_MOUSE);
114 if (d.run () != Gtk::RESPONSE_ACCEPT) {
118 _bundle->add_channel (d.get_name());
123 PortMatrix::add_channel (b);
129 BundleEditorMatrix::can_remove_channels (boost::shared_ptr<Bundle> b) const
135 return PortMatrix::can_remove_channels (b);
139 BundleEditorMatrix::remove_channel (BundleChannel bc)
141 bc.bundle->remove_channel (bc.channel);
146 BundleEditorMatrix::can_rename_channels (boost::shared_ptr<Bundle> b) const
152 return PortMatrix::can_rename_channels (b);
156 BundleEditorMatrix::rename_channel (BundleChannel bc)
158 NameChannelDialog d (bc.bundle, bc.channel);
159 d.set_position (Gtk::WIN_POS_MOUSE);
161 if (d.run () != Gtk::RESPONSE_ACCEPT) {
165 bc.bundle->set_channel_name (bc.channel, d.get_name ());
169 BundleEditorMatrix::list_is_global (int dim) const
171 return (dim == OTHER);
174 BundleEditor::BundleEditor (Session& session, boost::shared_ptr<UserBundle> bundle)
175 : ArdourDialog (_("Edit Bundle")), _matrix (this, session, bundle), _bundle (bundle)
177 Gtk::Table* t = new Gtk::Table (3, 2);
181 Gtk::Alignment* a = new Gtk::Alignment (1, 0.5, 0, 1);
182 a->add (*Gtk::manage (new Gtk::Label (_("Name:"))));
183 t->attach (*Gtk::manage (a), 0, 1, 0, 1, Gtk::FILL, Gtk::FILL);
184 t->attach (_name, 1, 2, 0, 1);
185 _name.set_text (_bundle->name ());
186 _name.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::name_changed));
188 /* Direction (input or output) */
189 a = new Gtk::Alignment (1, 0.5, 0, 1);
190 a->add (*Gtk::manage (new Gtk::Label (_("Direction:"))));
191 t->attach (*Gtk::manage (a), 0, 1, 1, 2, Gtk::FILL, Gtk::FILL);
192 a = new Gtk::Alignment (0, 0.5, 0, 1);
193 a->add (_input_or_output);
194 t->attach (*Gtk::manage (a), 1, 2, 1, 2);
195 _input_or_output.append_text (_("Input"));
196 _input_or_output.append_text (_("Output"));
198 if (bundle->ports_are_inputs()) {
199 _input_or_output.set_active_text (_("Input"));
201 _input_or_output.set_active_text (_("Output"));
204 _input_or_output.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::input_or_output_changed));
206 /* Type (audio or MIDI) */
207 a = new Gtk::Alignment (1, 0.5, 0, 1);
208 a->add (*Gtk::manage (new Gtk::Label (_("Type:"))));
209 t->attach (*Gtk::manage (a), 0, 1, 2, 3, Gtk::FILL, Gtk::FILL);
210 a = new Gtk::Alignment (0, 0.5, 0, 1);
212 t->attach (*Gtk::manage (a), 1, 2, 2, 3);
214 _type.append_text (_("Audio"));
215 _type.append_text (_("MIDI"));
217 switch (bundle->type ()) {
218 case DataType::AUDIO:
219 _type.set_active_text (_("Audio"));
222 _type.set_active_text (_("MIDI"));
226 _type.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::type_changed));
228 get_vbox()->pack_start (*Gtk::manage (t), false, false);
229 get_vbox()->pack_start (_matrix);
230 get_vbox()->set_spacing (4);
232 add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_ACCEPT);
237 BundleEditor::on_show ()
239 Gtk::Window::on_show ();
240 pair<uint32_t, uint32_t> const pm_max = _matrix.max_size ();
241 resize_window_to_proportion_of_monitor (this, pm_max.first, pm_max.second);
245 BundleEditor::name_changed ()
247 _bundle->set_name (_name.get_text ());
251 BundleEditor::input_or_output_changed ()
253 _bundle->remove_ports_from_channels ();
255 if (_input_or_output.get_active_text() == _("Output")) {
256 _bundle->set_ports_are_outputs ();
258 _bundle->set_ports_are_inputs ();
261 _matrix.setup_all_ports ();
265 BundleEditor::type_changed ()
267 _bundle->remove_ports_from_channels ();
269 DataType const t = _type.get_active_text() == _("Audio") ?
270 DataType::AUDIO : DataType::MIDI;
272 _bundle->set_type (t);
273 _matrix.set_type (t);
277 BundleEditor::on_map ()
279 _matrix.setup_all_ports ();
284 BundleManager::BundleManager (Session& session)
285 : ArdourDialog (_("Bundle Manager")), _session (session), edit_button (_("Edit")), delete_button (_("Delete"))
287 _list_model = Gtk::ListStore::create (_list_model_columns);
288 _tree_view.set_model (_list_model);
289 _tree_view.append_column (_("Name"), _list_model_columns.name);
290 _tree_view.set_headers_visible (false);
292 boost::shared_ptr<BundleList> bundles = _session.bundles ();
293 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
297 /* New / Edit / Delete buttons */
298 Gtk::VBox* buttons = new Gtk::VBox;
299 buttons->set_spacing (8);
300 Gtk::Button* b = new Gtk::Button (_("New"));
301 b->set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::NEW, Gtk::ICON_SIZE_BUTTON)));
302 b->signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::new_clicked));
303 buttons->pack_start (*Gtk::manage (b), false, false);
304 edit_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::EDIT, Gtk::ICON_SIZE_BUTTON)));
305 edit_button.signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::edit_clicked));
306 buttons->pack_start (edit_button, false, false);
307 delete_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::DELETE, Gtk::ICON_SIZE_BUTTON)));
308 delete_button.signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::delete_clicked));
309 buttons->pack_start (delete_button, false, false);
311 Gtk::HBox* h = new Gtk::HBox;
313 h->set_border_width (8);
314 h->pack_start (_tree_view);
315 h->pack_start (*Gtk::manage (buttons), false, false);
317 get_vbox()->set_spacing (8);
318 get_vbox()->pack_start (*Gtk::manage (h));
320 set_default_size (480, 240);
322 _tree_view.get_selection()->signal_changed().connect (
323 sigc::mem_fun (*this, &BundleManager::set_button_sensitivity)
326 _tree_view.signal_row_activated().connect (
327 sigc::mem_fun (*this, &BundleManager::row_activated)
330 set_button_sensitivity ();
336 BundleManager::set_button_sensitivity ()
338 bool const sel = (_tree_view.get_selection()->get_selected() != 0);
339 edit_button.set_sensitive (sel);
340 delete_button.set_sensitive (sel);
345 BundleManager::new_clicked ()
347 boost::shared_ptr<UserBundle> b (new UserBundle (_("Bundle")));
349 /* Start off with a single channel */
350 b->add_channel ("1");
352 _session.add_bundle (b);
355 BundleEditor e (_session, b);
360 BundleManager::edit_clicked ()
362 Gtk::TreeModel::iterator i = _tree_view.get_selection()->get_selected();
364 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
365 BundleEditor e (_session, b);
371 BundleManager::delete_clicked ()
373 Gtk::TreeModel::iterator i = _tree_view.get_selection()->get_selected();
375 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
376 _session.remove_bundle (b);
377 _list_model->erase (i);
382 BundleManager::add_bundle (boost::shared_ptr<Bundle> b)
384 boost::shared_ptr<UserBundle> u = boost::dynamic_pointer_cast<UserBundle> (b);
389 Gtk::TreeModel::iterator i = _list_model->append ();
390 (*i)[_list_model_columns.name] = u->name ();
391 (*i)[_list_model_columns.bundle] = u;
393 u->Changed.connect (sigc::bind (sigc::mem_fun (*this, &BundleManager::bundle_changed), u));
397 BundleManager::bundle_changed (Bundle::Change c, boost::shared_ptr<UserBundle> b)
399 if ((c & Bundle::NameChanged) == 0) {
403 Gtk::TreeModel::iterator i = _list_model->children().begin ();
404 while (i != _list_model->children().end()) {
405 boost::shared_ptr<UserBundle> t = (*i)[_list_model_columns.bundle];
412 if (i != _list_model->children().end()) {
413 (*i)[_list_model_columns.name] = b->name ();
418 BundleManager::row_activated (Gtk::TreeModel::Path const & p, Gtk::TreeViewColumn* c)
420 Gtk::TreeModel::iterator i = _list_model->get_iter (p);
425 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
426 BundleEditor e (_session, b);
430 NameChannelDialog::NameChannelDialog ()
431 : ArdourDialog (_("Add channel")),
437 NameChannelDialog::NameChannelDialog (boost::shared_ptr<Bundle> b, uint32_t c)
438 : ArdourDialog (_("Rename channel")),
443 _name.set_text (b->channel_name (c));
449 NameChannelDialog::setup ()
451 Gtk::HBox* box = Gtk::manage (new Gtk::HBox ());
453 box->pack_start (*Gtk::manage (new Gtk::Label (_("Name"))));
454 box->pack_start (_name);
455 _name.set_activates_default (true);
457 get_vbox ()->pack_end (*box);
460 add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
462 add_button (Gtk::Stock::ADD, Gtk::RESPONSE_ACCEPT);
464 add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_ACCEPT);
466 set_default_response (Gtk::RESPONSE_ACCEPT);
470 NameChannelDialog::get_name () const
472 return _name.get_text ();