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 "ardour/audioengine.h"
31 #include "bundle_manager.h"
32 #include "gui_thread.h"
37 using namespace ARDOUR;
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);
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 /* XXX: allow user to specify type */
122 _bundle->add_channel (d.get_name(), DataType::AUDIO);
127 PortMatrix::add_channel (b);
133 BundleEditorMatrix::can_remove_channels (boost::shared_ptr<Bundle> b) const
139 return PortMatrix::can_remove_channels (b);
143 BundleEditorMatrix::remove_channel (BundleChannel bc)
145 bc.bundle->remove_channel (bc.channel);
150 BundleEditorMatrix::can_rename_channels (boost::shared_ptr<Bundle> b) const
156 return PortMatrix::can_rename_channels (b);
160 BundleEditorMatrix::rename_channel (BundleChannel bc)
162 NameChannelDialog d (bc.bundle, bc.channel);
163 d.set_position (Gtk::WIN_POS_MOUSE);
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);
225 BundleEditor::on_show ()
227 Gtk::Window::on_show ();
228 pair<uint32_t, uint32_t> const pm_max = _matrix.max_size ();
229 resize_window_to_proportion_of_monitor (this, pm_max.first, pm_max.second);
233 BundleEditor::name_changed ()
235 _bundle->set_name (_name.get_text ());
239 BundleEditor::input_or_output_changed ()
241 _bundle->remove_ports_from_channels ();
243 if (_input_or_output.get_active_text() == _("Output")) {
244 _bundle->set_ports_are_outputs ();
246 _bundle->set_ports_are_inputs ();
249 _matrix.setup_all_ports ();
253 BundleEditor::on_map ()
255 _matrix.setup_all_ports ();
260 BundleManager::BundleManager (Session* session)
261 : ArdourDialog (_("Bundle Manager"))
262 , edit_button (_("Edit"))
263 , delete_button (_("Delete"))
265 set_session (session);
267 _list_model = Gtk::ListStore::create (_list_model_columns);
268 _tree_view.set_model (_list_model);
269 _tree_view.append_column (_("Name"), _list_model_columns.name);
270 _tree_view.set_headers_visible (false);
272 boost::shared_ptr<BundleList> bundles = _session->bundles ();
273 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
277 /* New / Edit / Delete buttons */
278 Gtk::VBox* buttons = new Gtk::VBox;
279 buttons->set_spacing (8);
280 Gtk::Button* b = new Gtk::Button (_("New"));
281 b->set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::NEW, Gtk::ICON_SIZE_BUTTON)));
282 b->signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::new_clicked));
283 buttons->pack_start (*Gtk::manage (b), false, false);
284 edit_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::EDIT, Gtk::ICON_SIZE_BUTTON)));
285 edit_button.signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::edit_clicked));
286 buttons->pack_start (edit_button, false, false);
287 delete_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::DELETE, Gtk::ICON_SIZE_BUTTON)));
288 delete_button.signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::delete_clicked));
289 buttons->pack_start (delete_button, false, false);
291 Gtk::HBox* h = new Gtk::HBox;
293 h->set_border_width (8);
294 h->pack_start (_tree_view);
295 h->pack_start (*Gtk::manage (buttons), false, false);
297 get_vbox()->set_spacing (8);
298 get_vbox()->pack_start (*Gtk::manage (h));
300 set_default_size (480, 240);
302 _tree_view.get_selection()->signal_changed().connect (
303 sigc::mem_fun (*this, &BundleManager::set_button_sensitivity)
306 _tree_view.signal_row_activated().connect (
307 sigc::mem_fun (*this, &BundleManager::row_activated)
310 set_button_sensitivity ();
316 BundleManager::set_button_sensitivity ()
318 bool const sel = (_tree_view.get_selection()->get_selected() != 0);
319 edit_button.set_sensitive (sel);
320 delete_button.set_sensitive (sel);
325 BundleManager::new_clicked ()
327 boost::shared_ptr<UserBundle> b (new UserBundle (_("Bundle")));
329 /* Start off with a single channel */
330 /* XXX: allow user to specify type */
331 b->add_channel ("1", DataType::AUDIO);
333 _session->add_bundle (b);
336 BundleEditor e (_session, b);
341 BundleManager::edit_clicked ()
343 Gtk::TreeModel::iterator i = _tree_view.get_selection()->get_selected();
345 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
346 BundleEditor e (_session, b);
352 BundleManager::delete_clicked ()
354 Gtk::TreeModel::iterator i = _tree_view.get_selection()->get_selected();
356 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
357 _session->remove_bundle (b);
358 _list_model->erase (i);
363 BundleManager::add_bundle (boost::shared_ptr<Bundle> b)
365 boost::shared_ptr<UserBundle> u = boost::dynamic_pointer_cast<UserBundle> (b);
370 Gtk::TreeModel::iterator i = _list_model->append ();
371 (*i)[_list_model_columns.name] = u->name ();
372 (*i)[_list_model_columns.bundle] = u;
374 u->Changed.connect (bundle_connections, invalidator (*this), ui_bind (&BundleManager::bundle_changed, this, _1, u), gui_context());
378 BundleManager::bundle_changed (Bundle::Change c, boost::shared_ptr<UserBundle> b)
380 if ((c & Bundle::NameChanged) == 0) {
384 Gtk::TreeModel::iterator i = _list_model->children().begin ();
385 while (i != _list_model->children().end()) {
386 boost::shared_ptr<UserBundle> t = (*i)[_list_model_columns.bundle];
393 if (i != _list_model->children().end()) {
394 (*i)[_list_model_columns.name] = b->name ();
399 BundleManager::row_activated (Gtk::TreeModel::Path const & p, Gtk::TreeViewColumn*)
401 Gtk::TreeModel::iterator i = _list_model->get_iter (p);
406 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
407 BundleEditor e (_session, b);
411 NameChannelDialog::NameChannelDialog ()
412 : ArdourDialog (_("Add Channel")),
418 NameChannelDialog::NameChannelDialog (boost::shared_ptr<Bundle> b, uint32_t c)
419 : ArdourDialog (_("Rename Channel")),
424 _name.set_text (b->channel_name (c));
430 NameChannelDialog::setup ()
432 Gtk::HBox* box = Gtk::manage (new Gtk::HBox ());
434 box->pack_start (*Gtk::manage (new Gtk::Label (_("Name"))));
435 box->pack_start (_name);
436 _name.set_activates_default (true);
438 get_vbox ()->pack_end (*box);
441 add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
443 add_button (Gtk::Stock::ADD, Gtk::RESPONSE_ACCEPT);
445 add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_ACCEPT);
447 set_default_response (Gtk::RESPONSE_ACCEPT);
451 NameChannelDialog::get_name () const
453 return _name.get_text ();