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 (Gtk::Window* parent, Session* session, boost::shared_ptr<Bundle> bundle)
38 : PortMatrix (parent, session, bundle->type())
41 _port_group = boost::shared_ptr<PortGroup> (new PortGroup (""));
42 _port_group->add_bundle (_bundle);
49 BundleEditorMatrix::setup_ports (int dim)
52 _ports[OURS].clear ();
53 _ports[OURS].add_group (_port_group);
55 _ports[OTHER].suspend_signals ();
57 /* when we gather, allow the matrix to contain bundles with duplicate port sets,
58 otherwise in some cases the basic system IO ports may be hidden, making
59 the bundle editor useless */
61 _ports[OTHER].gather (_session, _bundle->ports_are_inputs(), true);
62 _ports[OTHER].remove_bundle (_bundle);
63 _ports[OTHER].resume_signals ();
68 BundleEditorMatrix::set_state (BundleChannel c[2], bool s)
70 Bundle::PortList const& pl = c[OTHER].bundle->channel_ports (c[OTHER].channel);
71 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
73 c[OURS].bundle->add_port_to_channel (c[OURS].channel, *i);
75 c[OURS].bundle->remove_port_from_channel (c[OURS].channel, *i);
81 BundleEditorMatrix::get_state (BundleChannel c[2]) const
83 Bundle::PortList const& pl = c[OTHER].bundle->channel_ports (c[OTHER].channel);
85 return PortMatrixNode::NOT_ASSOCIATED;
88 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
89 if (!c[OURS].bundle->port_attached_to_channel (c[OURS].channel, *i)) {
90 return PortMatrixNode::NOT_ASSOCIATED;
94 return PortMatrixNode::ASSOCIATED;
98 BundleEditorMatrix::can_add_channel (boost::shared_ptr<Bundle> b) const
104 return PortMatrix::can_add_channel (b);
108 BundleEditorMatrix::add_channel (boost::shared_ptr<Bundle> b)
113 d.set_position (Gtk::WIN_POS_MOUSE);
115 if (d.run () != Gtk::RESPONSE_ACCEPT) {
119 _bundle->add_channel (d.get_name());
124 PortMatrix::add_channel (b);
130 BundleEditorMatrix::can_remove_channels (boost::shared_ptr<Bundle> b) const
136 return PortMatrix::can_remove_channels (b);
140 BundleEditorMatrix::remove_channel (BundleChannel bc)
142 bc.bundle->remove_channel (bc.channel);
147 BundleEditorMatrix::can_rename_channels (boost::shared_ptr<Bundle> b) const
153 return PortMatrix::can_rename_channels (b);
157 BundleEditorMatrix::rename_channel (BundleChannel bc)
159 NameChannelDialog d (bc.bundle, bc.channel);
160 d.set_position (Gtk::WIN_POS_MOUSE);
162 if (d.run () != Gtk::RESPONSE_ACCEPT) {
166 bc.bundle->set_channel_name (bc.channel, d.get_name ());
170 BundleEditorMatrix::list_is_global (int dim) const
172 return (dim == OTHER);
175 BundleEditor::BundleEditor (Session* session, boost::shared_ptr<UserBundle> bundle)
176 : ArdourDialog (_("Edit Bundle")), _matrix (this, session, bundle), _bundle (bundle)
178 Gtk::Table* t = new Gtk::Table (3, 2);
182 Gtk::Alignment* a = new Gtk::Alignment (1, 0.5, 0, 1);
183 a->add (*Gtk::manage (new Gtk::Label (_("Name:"))));
184 t->attach (*Gtk::manage (a), 0, 1, 0, 1, Gtk::FILL, Gtk::FILL);
185 t->attach (_name, 1, 2, 0, 1);
186 _name.set_text (_bundle->name ());
187 _name.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::name_changed));
189 /* Direction (input or output) */
190 a = new Gtk::Alignment (1, 0.5, 0, 1);
191 a->add (*Gtk::manage (new Gtk::Label (_("Direction:"))));
192 t->attach (*Gtk::manage (a), 0, 1, 1, 2, Gtk::FILL, Gtk::FILL);
193 a = new Gtk::Alignment (0, 0.5, 0, 1);
194 a->add (_input_or_output);
195 t->attach (*Gtk::manage (a), 1, 2, 1, 2);
196 _input_or_output.append_text (_("Input"));
197 _input_or_output.append_text (_("Output"));
199 if (bundle->ports_are_inputs()) {
200 _input_or_output.set_active_text (_("Input"));
202 _input_or_output.set_active_text (_("Output"));
205 _input_or_output.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::input_or_output_changed));
207 /* Type (audio or MIDI) */
208 a = new Gtk::Alignment (1, 0.5, 0, 1);
209 a->add (*Gtk::manage (new Gtk::Label (_("Type:"))));
210 t->attach (*Gtk::manage (a), 0, 1, 2, 3, Gtk::FILL, Gtk::FILL);
211 a = new Gtk::Alignment (0, 0.5, 0, 1);
213 t->attach (*Gtk::manage (a), 1, 2, 2, 3);
215 _type.append_text (_("Audio"));
216 _type.append_text (_("MIDI"));
218 switch (bundle->type ()) {
219 case DataType::AUDIO:
220 _type.set_active_text (_("Audio"));
223 _type.set_active_text (_("MIDI"));
227 _type.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::type_changed));
229 get_vbox()->pack_start (*Gtk::manage (t), false, false);
230 get_vbox()->pack_start (_matrix);
231 get_vbox()->set_spacing (4);
233 add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_ACCEPT);
238 BundleEditor::on_show ()
240 Gtk::Window::on_show ();
241 pair<uint32_t, uint32_t> const pm_max = _matrix.max_size ();
242 resize_window_to_proportion_of_monitor (this, pm_max.first, pm_max.second);
246 BundleEditor::name_changed ()
248 _bundle->set_name (_name.get_text ());
252 BundleEditor::input_or_output_changed ()
254 _bundle->remove_ports_from_channels ();
256 if (_input_or_output.get_active_text() == _("Output")) {
257 _bundle->set_ports_are_outputs ();
259 _bundle->set_ports_are_inputs ();
262 _matrix.setup_all_ports ();
266 BundleEditor::type_changed ()
268 _bundle->remove_ports_from_channels ();
270 DataType const t = _type.get_active_text() == _("Audio") ?
271 DataType::AUDIO : DataType::MIDI;
273 _bundle->set_type (t);
274 _matrix.set_type (t);
278 BundleEditor::on_map ()
280 _matrix.setup_all_ports ();
285 BundleManager::BundleManager (Session* session)
286 : ArdourDialog (_("Bundle Manager"))
287 , edit_button (_("Edit"))
288 , delete_button (_("Delete"))
290 set_session (session);
292 _list_model = Gtk::ListStore::create (_list_model_columns);
293 _tree_view.set_model (_list_model);
294 _tree_view.append_column (_("Name"), _list_model_columns.name);
295 _tree_view.set_headers_visible (false);
297 boost::shared_ptr<BundleList> bundles = _session->bundles ();
298 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
302 /* New / Edit / Delete buttons */
303 Gtk::VBox* buttons = new Gtk::VBox;
304 buttons->set_spacing (8);
305 Gtk::Button* b = new Gtk::Button (_("New"));
306 b->set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::NEW, Gtk::ICON_SIZE_BUTTON)));
307 b->signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::new_clicked));
308 buttons->pack_start (*Gtk::manage (b), false, false);
309 edit_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::EDIT, Gtk::ICON_SIZE_BUTTON)));
310 edit_button.signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::edit_clicked));
311 buttons->pack_start (edit_button, false, false);
312 delete_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::DELETE, Gtk::ICON_SIZE_BUTTON)));
313 delete_button.signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::delete_clicked));
314 buttons->pack_start (delete_button, false, false);
316 Gtk::HBox* h = new Gtk::HBox;
318 h->set_border_width (8);
319 h->pack_start (_tree_view);
320 h->pack_start (*Gtk::manage (buttons), false, false);
322 get_vbox()->set_spacing (8);
323 get_vbox()->pack_start (*Gtk::manage (h));
325 set_default_size (480, 240);
327 _tree_view.get_selection()->signal_changed().connect (
328 sigc::mem_fun (*this, &BundleManager::set_button_sensitivity)
331 _tree_view.signal_row_activated().connect (
332 sigc::mem_fun (*this, &BundleManager::row_activated)
335 set_button_sensitivity ();
341 BundleManager::set_button_sensitivity ()
343 bool const sel = (_tree_view.get_selection()->get_selected() != 0);
344 edit_button.set_sensitive (sel);
345 delete_button.set_sensitive (sel);
350 BundleManager::new_clicked ()
352 boost::shared_ptr<UserBundle> b (new UserBundle (_("Bundle")));
354 /* Start off with a single channel */
355 b->add_channel ("1");
357 _session->add_bundle (b);
360 BundleEditor e (_session, b);
365 BundleManager::edit_clicked ()
367 Gtk::TreeModel::iterator i = _tree_view.get_selection()->get_selected();
369 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
370 BundleEditor e (_session, b);
376 BundleManager::delete_clicked ()
378 Gtk::TreeModel::iterator i = _tree_view.get_selection()->get_selected();
380 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
381 _session->remove_bundle (b);
382 _list_model->erase (i);
387 BundleManager::add_bundle (boost::shared_ptr<Bundle> b)
389 boost::shared_ptr<UserBundle> u = boost::dynamic_pointer_cast<UserBundle> (b);
394 Gtk::TreeModel::iterator i = _list_model->append ();
395 (*i)[_list_model_columns.name] = u->name ();
396 (*i)[_list_model_columns.bundle] = u;
398 u->Changed.connect (bundle_connections, boost::bind (&BundleManager::bundle_changed, this, _1, u));
402 BundleManager::bundle_changed (Bundle::Change c, boost::shared_ptr<UserBundle> b)
404 if ((c & Bundle::NameChanged) == 0) {
408 Gtk::TreeModel::iterator i = _list_model->children().begin ();
409 while (i != _list_model->children().end()) {
410 boost::shared_ptr<UserBundle> t = (*i)[_list_model_columns.bundle];
417 if (i != _list_model->children().end()) {
418 (*i)[_list_model_columns.name] = b->name ();
423 BundleManager::row_activated (Gtk::TreeModel::Path const & p, Gtk::TreeViewColumn* c)
425 Gtk::TreeModel::iterator i = _list_model->get_iter (p);
430 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
431 BundleEditor e (_session, b);
435 NameChannelDialog::NameChannelDialog ()
436 : ArdourDialog (_("Add channel")),
442 NameChannelDialog::NameChannelDialog (boost::shared_ptr<Bundle> b, uint32_t c)
443 : ArdourDialog (_("Rename channel")),
448 _name.set_text (b->channel_name (c));
454 NameChannelDialog::setup ()
456 Gtk::HBox* box = Gtk::manage (new Gtk::HBox ());
458 box->pack_start (*Gtk::manage (new Gtk::Label (_("Name"))));
459 box->pack_start (_name);
460 _name.set_activates_default (true);
462 get_vbox ()->pack_end (*box);
465 add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
467 add_button (Gtk::Stock::ADD, Gtk::RESPONSE_ACCEPT);
469 add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_ACCEPT);
471 set_default_response (Gtk::RESPONSE_ACCEPT);
475 NameChannelDialog::get_name () const
477 return _name.get_text ();