A little copy-editing.
[ArdourMidi.git] / gtk2_ardour / bundle_manager.cc
blob559bc7ed6c926188e711d9563230d91a5298c557
1 /*
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"
33 #include "i18n.h"
34 #include "utils.h"
36 using namespace std;
37 using namespace ARDOUR;
39 BundleEditorMatrix::BundleEditorMatrix (Gtk::Window* parent, Session* session, boost::shared_ptr<Bundle> bundle)
40 : PortMatrix (parent, session, bundle->type())
41 , _bundle (bundle)
43 _port_group = boost::shared_ptr<PortGroup> (new PortGroup (""));
44 _port_group->add_bundle (_bundle);
46 setup_all_ports ();
47 init ();
50 void
51 BundleEditorMatrix::setup_ports (int dim)
53 if (dim == OURS) {
54 _ports[OURS].clear ();
55 _ports[OURS].add_group (_port_group);
56 } else {
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 ();
69 void
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) {
74 if (s) {
75 c[OURS].bundle->add_port_to_channel (c[OURS].channel, *i);
76 } else {
77 c[OURS].bundle->remove_port_from_channel (c[OURS].channel, *i);
82 PortMatrixNode::State
83 BundleEditorMatrix::get_state (BundleChannel c[2]) const
85 Bundle::PortList const& pl = c[OTHER].bundle->channel_ports (c[OTHER].channel);
86 if (pl.empty ()) {
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;
99 bool
100 BundleEditorMatrix::can_add_channel (boost::shared_ptr<Bundle> b) const
102 if (b == _bundle) {
103 return true;
106 return PortMatrix::can_add_channel (b);
109 void
110 BundleEditorMatrix::add_channel (boost::shared_ptr<Bundle> b)
112 if (b == _bundle) {
114 NameChannelDialog d;
115 d.set_position (Gtk::WIN_POS_MOUSE);
117 if (d.run () != Gtk::RESPONSE_ACCEPT) {
118 return;
121 _bundle->add_channel (d.get_name());
122 setup_ports (OURS);
124 } else {
126 PortMatrix::add_channel (b);
131 bool
132 BundleEditorMatrix::can_remove_channels (boost::shared_ptr<Bundle> b) const
134 if (b == _bundle) {
135 return true;
138 return PortMatrix::can_remove_channels (b);
141 void
142 BundleEditorMatrix::remove_channel (BundleChannel bc)
144 bc.bundle->remove_channel (bc.channel);
145 setup_ports (OURS);
148 bool
149 BundleEditorMatrix::can_rename_channels (boost::shared_ptr<Bundle> b) const
151 if (b == _bundle) {
152 return true;
155 return PortMatrix::can_rename_channels (b);
158 void
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) {
165 return;
168 bc.bundle->set_channel_name (bc.channel, d.get_name ());
171 bool
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);
181 t->set_spacings (4);
183 /* Bundle name */
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"));
203 } else {
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);
214 a->add (_type);
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"));
223 break;
224 case DataType::MIDI:
225 _type.set_active_text (_("MIDI"));
226 break;
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);
236 show_all ();
239 void
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);
247 void
248 BundleEditor::name_changed ()
250 _bundle->set_name (_name.get_text ());
253 void
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 ();
260 } else {
261 _bundle->set_ports_are_inputs ();
264 _matrix.setup_all_ports ();
267 void
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);
279 void
280 BundleEditor::on_map ()
282 _matrix.setup_all_ports ();
283 Window::on_map ();
287 BundleManager::BundleManager (Session* session)
288 : ArdourDialog (_("Bundle Manager"))
289 , edit_button (_("Edit"))
290 , delete_button (_("Delete"))
292 set_session (session);
294 _list_model = Gtk::ListStore::create (_list_model_columns);
295 _tree_view.set_model (_list_model);
296 _tree_view.append_column (_("Name"), _list_model_columns.name);
297 _tree_view.set_headers_visible (false);
299 boost::shared_ptr<BundleList> bundles = _session->bundles ();
300 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
301 add_bundle (*i);
304 /* New / Edit / Delete buttons */
305 Gtk::VBox* buttons = new Gtk::VBox;
306 buttons->set_spacing (8);
307 Gtk::Button* b = new Gtk::Button (_("New"));
308 b->set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::NEW, Gtk::ICON_SIZE_BUTTON)));
309 b->signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::new_clicked));
310 buttons->pack_start (*Gtk::manage (b), false, false);
311 edit_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::EDIT, Gtk::ICON_SIZE_BUTTON)));
312 edit_button.signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::edit_clicked));
313 buttons->pack_start (edit_button, false, false);
314 delete_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::DELETE, Gtk::ICON_SIZE_BUTTON)));
315 delete_button.signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::delete_clicked));
316 buttons->pack_start (delete_button, false, false);
318 Gtk::HBox* h = new Gtk::HBox;
319 h->set_spacing (8);
320 h->set_border_width (8);
321 h->pack_start (_tree_view);
322 h->pack_start (*Gtk::manage (buttons), false, false);
324 get_vbox()->set_spacing (8);
325 get_vbox()->pack_start (*Gtk::manage (h));
327 set_default_size (480, 240);
329 _tree_view.get_selection()->signal_changed().connect (
330 sigc::mem_fun (*this, &BundleManager::set_button_sensitivity)
333 _tree_view.signal_row_activated().connect (
334 sigc::mem_fun (*this, &BundleManager::row_activated)
337 set_button_sensitivity ();
339 show_all ();
342 void
343 BundleManager::set_button_sensitivity ()
345 bool const sel = (_tree_view.get_selection()->get_selected() != 0);
346 edit_button.set_sensitive (sel);
347 delete_button.set_sensitive (sel);
351 void
352 BundleManager::new_clicked ()
354 boost::shared_ptr<UserBundle> b (new UserBundle (_("Bundle")));
356 /* Start off with a single channel */
357 b->add_channel ("1");
359 _session->add_bundle (b);
360 add_bundle (b);
362 BundleEditor e (_session, b);
363 e.run ();
366 void
367 BundleManager::edit_clicked ()
369 Gtk::TreeModel::iterator i = _tree_view.get_selection()->get_selected();
370 if (i) {
371 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
372 BundleEditor e (_session, b);
373 e.run ();
377 void
378 BundleManager::delete_clicked ()
380 Gtk::TreeModel::iterator i = _tree_view.get_selection()->get_selected();
381 if (i) {
382 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
383 _session->remove_bundle (b);
384 _list_model->erase (i);
388 void
389 BundleManager::add_bundle (boost::shared_ptr<Bundle> b)
391 boost::shared_ptr<UserBundle> u = boost::dynamic_pointer_cast<UserBundle> (b);
392 if (u == 0) {
393 return;
396 Gtk::TreeModel::iterator i = _list_model->append ();
397 (*i)[_list_model_columns.name] = u->name ();
398 (*i)[_list_model_columns.bundle] = u;
400 u->Changed.connect (bundle_connections, invalidator (*this), ui_bind (&BundleManager::bundle_changed, this, _1, u), gui_context());
403 void
404 BundleManager::bundle_changed (Bundle::Change c, boost::shared_ptr<UserBundle> b)
406 if ((c & Bundle::NameChanged) == 0) {
407 return;
410 Gtk::TreeModel::iterator i = _list_model->children().begin ();
411 while (i != _list_model->children().end()) {
412 boost::shared_ptr<UserBundle> t = (*i)[_list_model_columns.bundle];
413 if (t == b) {
414 break;
416 ++i;
419 if (i != _list_model->children().end()) {
420 (*i)[_list_model_columns.name] = b->name ();
424 void
425 BundleManager::row_activated (Gtk::TreeModel::Path const & p, Gtk::TreeViewColumn*)
427 Gtk::TreeModel::iterator i = _list_model->get_iter (p);
428 if (!i) {
429 return;
432 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
433 BundleEditor e (_session, b);
434 e.run ();
437 NameChannelDialog::NameChannelDialog ()
438 : ArdourDialog (_("Add Channel")),
439 _adding (true)
441 setup ();
444 NameChannelDialog::NameChannelDialog (boost::shared_ptr<Bundle> b, uint32_t c)
445 : ArdourDialog (_("Rename Channel")),
446 _bundle (b),
447 _channel (c),
448 _adding (false)
450 _name.set_text (b->channel_name (c));
452 setup ();
455 void
456 NameChannelDialog::setup ()
458 Gtk::HBox* box = Gtk::manage (new Gtk::HBox ());
460 box->pack_start (*Gtk::manage (new Gtk::Label (_("Name"))));
461 box->pack_start (_name);
462 _name.set_activates_default (true);
464 get_vbox ()->pack_end (*box);
465 box->show_all ();
467 add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
468 if (_adding) {
469 add_button (Gtk::Stock::ADD, Gtk::RESPONSE_ACCEPT);
470 } else {
471 add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_ACCEPT);
473 set_default_response (Gtk::RESPONSE_ACCEPT);
476 string
477 NameChannelDialog::get_name () const
479 return _name.get_text ();