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;
38 BundleEditorMatrix::BundleEditorMatrix (Gtk::Window* parent, Session* session, boost::shared_ptr<Bundle> bundle)
39 : PortMatrix (parent, session, DataType::NIL)
42 _port_group = boost::shared_ptr<PortGroup> (new PortGroup (""));
43 _port_group->add_bundle (_bundle);
50 BundleEditorMatrix::setup_ports (int dim)
53 _ports[OURS].clear ();
54 _ports[OURS].add_group (_port_group);
56 _ports[OTHER].suspend_signals ();
58 /* when we gather, allow the matrix to contain bundles with duplicate port sets,
59 otherwise in some cases the basic system IO ports may be hidden, making
60 the bundle editor useless */
62 _ports[OTHER].gather (_session, DataType::NIL, _bundle->ports_are_inputs(), true, show_only_bundles ());
63 _ports[OTHER].remove_bundle (_bundle);
64 _ports[OTHER].resume_signals ();
69 BundleEditorMatrix::set_state (BundleChannel c[2], bool s)
71 Bundle::PortList const& pl = c[OTHER].bundle->channel_ports (c[OTHER].channel);
72 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
74 c[OURS].bundle->add_port_to_channel (c[OURS].channel, *i);
76 c[OURS].bundle->remove_port_from_channel (c[OURS].channel, *i);
82 BundleEditorMatrix::get_state (BundleChannel c[2]) const
84 if (c[0].bundle->nchannels() == ChanCount::ZERO || c[1].bundle->nchannels() == ChanCount::ZERO) {
85 return PortMatrixNode::NOT_ASSOCIATED;
88 Bundle::PortList const& pl = c[OTHER].bundle->channel_ports (c[OTHER].channel);
90 return PortMatrixNode::NOT_ASSOCIATED;
93 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
94 if (!c[OURS].bundle->port_attached_to_channel (c[OURS].channel, *i)) {
95 return PortMatrixNode::NOT_ASSOCIATED;
99 return PortMatrixNode::ASSOCIATED;
103 BundleEditorMatrix::can_add_channels (boost::shared_ptr<Bundle> b) const
109 return PortMatrix::can_add_channels (b);
113 BundleEditorMatrix::add_channel (boost::shared_ptr<Bundle> b, DataType t)
118 d.set_position (Gtk::WIN_POS_MOUSE);
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);
165 d.set_position (Gtk::WIN_POS_MOUSE);
167 if (d.run () != Gtk::RESPONSE_ACCEPT) {
171 bc.bundle->set_channel_name (bc.channel, d.get_name ());
175 BundleEditorMatrix::list_is_global (int dim) const
177 return (dim == OTHER);
181 BundleEditorMatrix::disassociation_verb () const
183 return _("Disassociate");
186 BundleEditor::BundleEditor (Session* session, boost::shared_ptr<UserBundle> bundle)
187 : ArdourDialog (_("Edit Bundle")), _matrix (this, session, bundle), _bundle (bundle)
189 Gtk::Table* t = new Gtk::Table (3, 2);
193 Gtk::Alignment* a = new Gtk::Alignment (1, 0.5, 0, 1);
194 a->add (*Gtk::manage (new Gtk::Label (_("Name:"))));
195 t->attach (*Gtk::manage (a), 0, 1, 0, 1, Gtk::FILL, Gtk::FILL);
196 t->attach (_name, 1, 2, 0, 1);
197 _name.set_text (_bundle->name ());
198 _name.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::name_changed));
200 /* Direction (input or output) */
201 a = new Gtk::Alignment (1, 0.5, 0, 1);
202 a->add (*Gtk::manage (new Gtk::Label (_("Direction:"))));
203 t->attach (*Gtk::manage (a), 0, 1, 1, 2, Gtk::FILL, Gtk::FILL);
204 a = new Gtk::Alignment (0, 0.5, 0, 1);
205 a->add (_input_or_output);
206 t->attach (*Gtk::manage (a), 1, 2, 1, 2);
207 _input_or_output.append_text (_("Input"));
208 _input_or_output.append_text (_("Output"));
210 if (bundle->ports_are_inputs()) {
211 _input_or_output.set_active_text (_("Input"));
213 _input_or_output.set_active_text (_("Output"));
216 _input_or_output.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::input_or_output_changed));
218 get_vbox()->pack_start (*Gtk::manage (t), false, false);
219 get_vbox()->pack_start (_matrix);
220 get_vbox()->set_spacing (4);
222 add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_ACCEPT);
225 signal_key_press_event().connect (sigc::mem_fun (_matrix, &BundleEditorMatrix::key_press));
229 BundleEditor::on_show ()
231 Gtk::Window::on_show ();
232 pair<uint32_t, uint32_t> const pm_max = _matrix.max_size ();
233 resize_window_to_proportion_of_monitor (this, pm_max.first, pm_max.second);
237 BundleEditor::name_changed ()
239 _bundle->set_name (_name.get_text ());
243 BundleEditor::input_or_output_changed ()
245 _bundle->remove_ports_from_channels ();
247 if (_input_or_output.get_active_text() == _("Output")) {
248 _bundle->set_ports_are_outputs ();
250 _bundle->set_ports_are_inputs ();
253 _matrix.setup_all_ports ();
257 BundleEditor::on_map ()
259 _matrix.setup_all_ports ();
264 BundleManager::BundleManager (Session* session)
265 : ArdourDialog (_("Bundle Manager"))
266 , edit_button (_("Edit"))
267 , delete_button (_("Delete"))
269 set_session (session);
271 _list_model = Gtk::ListStore::create (_list_model_columns);
272 _tree_view.set_model (_list_model);
273 _tree_view.append_column (_("Name"), _list_model_columns.name);
274 _tree_view.set_headers_visible (false);
276 boost::shared_ptr<BundleList> bundles = _session->bundles ();
277 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
281 /* New / Edit / Delete buttons */
282 Gtk::VBox* buttons = new Gtk::VBox;
283 buttons->set_spacing (8);
284 Gtk::Button* b = new Gtk::Button (_("New"));
285 b->set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::NEW, Gtk::ICON_SIZE_BUTTON)));
286 b->signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::new_clicked));
287 buttons->pack_start (*Gtk::manage (b), false, false);
288 edit_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::EDIT, Gtk::ICON_SIZE_BUTTON)));
289 edit_button.signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::edit_clicked));
290 buttons->pack_start (edit_button, false, false);
291 delete_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::DELETE, Gtk::ICON_SIZE_BUTTON)));
292 delete_button.signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::delete_clicked));
293 buttons->pack_start (delete_button, false, false);
295 Gtk::HBox* h = new Gtk::HBox;
297 h->set_border_width (8);
298 h->pack_start (_tree_view);
299 h->pack_start (*Gtk::manage (buttons), false, false);
301 get_vbox()->set_spacing (8);
302 get_vbox()->pack_start (*Gtk::manage (h));
304 set_default_size (480, 240);
306 _tree_view.get_selection()->signal_changed().connect (
307 sigc::mem_fun (*this, &BundleManager::set_button_sensitivity)
310 _tree_view.signal_row_activated().connect (
311 sigc::mem_fun (*this, &BundleManager::row_activated)
314 Gtk::Button* close_but = add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_ACCEPT);
315 close_but->signal_clicked ().connect (sigc::mem_fun (*this, &Gtk::Window::hide));
317 set_button_sensitivity ();
323 BundleManager::set_button_sensitivity ()
325 bool const sel = (_tree_view.get_selection()->get_selected() != 0);
326 edit_button.set_sensitive (sel);
327 delete_button.set_sensitive (sel);
332 BundleManager::new_clicked ()
334 boost::shared_ptr<UserBundle> b (new UserBundle (_("Bundle")));
336 /* Start off with a single channel */
337 /* XXX: allow user to specify type */
338 b->add_channel ("1", DataType::AUDIO);
340 _session->add_bundle (b);
343 BundleEditor e (_session, b);
348 BundleManager::edit_clicked ()
350 Gtk::TreeModel::iterator i = _tree_view.get_selection()->get_selected();
352 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
353 BundleEditor e (_session, b);
359 BundleManager::delete_clicked ()
361 Gtk::TreeModel::iterator i = _tree_view.get_selection()->get_selected();
363 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
364 _session->remove_bundle (b);
365 _list_model->erase (i);
370 BundleManager::add_bundle (boost::shared_ptr<Bundle> b)
372 boost::shared_ptr<UserBundle> u = boost::dynamic_pointer_cast<UserBundle> (b);
377 Gtk::TreeModel::iterator i = _list_model->append ();
378 (*i)[_list_model_columns.name] = u->name ();
379 (*i)[_list_model_columns.bundle] = u;
381 u->Changed.connect (bundle_connections, invalidator (*this), boost::bind (&BundleManager::bundle_changed, this, _1, u), gui_context());
385 BundleManager::bundle_changed (Bundle::Change c, boost::shared_ptr<UserBundle> b)
387 if ((c & Bundle::NameChanged) == 0) {
391 Gtk::TreeModel::iterator i = _list_model->children().begin ();
392 while (i != _list_model->children().end()) {
393 boost::shared_ptr<UserBundle> t = (*i)[_list_model_columns.bundle];
400 if (i != _list_model->children().end()) {
401 (*i)[_list_model_columns.name] = b->name ();
406 BundleManager::row_activated (Gtk::TreeModel::Path const & p, Gtk::TreeViewColumn*)
408 Gtk::TreeModel::iterator i = _list_model->get_iter (p);
413 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
414 BundleEditor e (_session, b);
418 NameChannelDialog::NameChannelDialog ()
419 : ArdourDialog (_("Add Channel")),
425 NameChannelDialog::NameChannelDialog (boost::shared_ptr<Bundle> b, uint32_t c)
426 : ArdourDialog (_("Rename Channel")),
431 _name.set_text (b->channel_name (c));
437 NameChannelDialog::setup ()
439 Gtk::HBox* box = Gtk::manage (new Gtk::HBox ());
441 box->pack_start (*Gtk::manage (new Gtk::Label (_("Name"))));
442 box->pack_start (_name);
443 _name.set_activates_default (true);
445 get_vbox ()->pack_end (*box);
448 add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
450 add_button (Gtk::Stock::ADD, Gtk::RESPONSE_ACCEPT);
452 add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_ACCEPT);
454 set_default_response (Gtk::RESPONSE_ACCEPT);
458 NameChannelDialog::get_name () const
460 return _name.get_text ();