fix math bug with numthreads computation
[ardour2.git] / gtk2_ardour / bundle_manager.cc
blobba00cce9d0583b3297e5a90ba9fcf9b7631dd196
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 string
178 BundleEditorMatrix::disassociation_verb () const
180 return _("Disassociate");
183 BundleEditor::BundleEditor (Session* session, boost::shared_ptr<UserBundle> bundle)
184 : ArdourDialog (_("Edit Bundle")), _matrix (this, session, bundle), _bundle (bundle)
186 Gtk::Table* t = new Gtk::Table (3, 2);
187 t->set_spacings (4);
189 /* Bundle name */
190 Gtk::Alignment* a = new Gtk::Alignment (1, 0.5, 0, 1);
191 a->add (*Gtk::manage (new Gtk::Label (_("Name:"))));
192 t->attach (*Gtk::manage (a), 0, 1, 0, 1, Gtk::FILL, Gtk::FILL);
193 t->attach (_name, 1, 2, 0, 1);
194 _name.set_text (_bundle->name ());
195 _name.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::name_changed));
197 /* Direction (input or output) */
198 a = new Gtk::Alignment (1, 0.5, 0, 1);
199 a->add (*Gtk::manage (new Gtk::Label (_("Direction:"))));
200 t->attach (*Gtk::manage (a), 0, 1, 1, 2, Gtk::FILL, Gtk::FILL);
201 a = new Gtk::Alignment (0, 0.5, 0, 1);
202 a->add (_input_or_output);
203 t->attach (*Gtk::manage (a), 1, 2, 1, 2);
204 _input_or_output.append_text (_("Input"));
205 _input_or_output.append_text (_("Output"));
207 if (bundle->ports_are_inputs()) {
208 _input_or_output.set_active_text (_("Input"));
209 } else {
210 _input_or_output.set_active_text (_("Output"));
213 _input_or_output.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::input_or_output_changed));
215 /* Type (audio or MIDI) */
216 a = new Gtk::Alignment (1, 0.5, 0, 1);
217 a->add (*Gtk::manage (new Gtk::Label (_("Type:"))));
218 t->attach (*Gtk::manage (a), 0, 1, 2, 3, Gtk::FILL, Gtk::FILL);
219 a = new Gtk::Alignment (0, 0.5, 0, 1);
220 a->add (_type);
221 t->attach (*Gtk::manage (a), 1, 2, 2, 3);
223 _type.append_text (_("Audio"));
224 _type.append_text (_("MIDI"));
226 switch (bundle->type ()) {
227 case DataType::AUDIO:
228 _type.set_active_text (_("Audio"));
229 break;
230 case DataType::MIDI:
231 _type.set_active_text (_("MIDI"));
232 break;
235 _type.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::type_changed));
237 get_vbox()->pack_start (*Gtk::manage (t), false, false);
238 get_vbox()->pack_start (_matrix);
239 get_vbox()->set_spacing (4);
241 add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_ACCEPT);
242 show_all ();
245 void
246 BundleEditor::on_show ()
248 Gtk::Window::on_show ();
249 pair<uint32_t, uint32_t> const pm_max = _matrix.max_size ();
250 resize_window_to_proportion_of_monitor (this, pm_max.first, pm_max.second);
253 void
254 BundleEditor::name_changed ()
256 _bundle->set_name (_name.get_text ());
259 void
260 BundleEditor::input_or_output_changed ()
262 _bundle->remove_ports_from_channels ();
264 if (_input_or_output.get_active_text() == _("Output")) {
265 _bundle->set_ports_are_outputs ();
266 } else {
267 _bundle->set_ports_are_inputs ();
270 _matrix.setup_all_ports ();
273 void
274 BundleEditor::type_changed ()
276 _bundle->remove_ports_from_channels ();
278 DataType const t = _type.get_active_text() == _("Audio") ?
279 DataType::AUDIO : DataType::MIDI;
281 _bundle->set_type (t);
282 _matrix.set_type (t);
285 void
286 BundleEditor::on_map ()
288 _matrix.setup_all_ports ();
289 Window::on_map ();
293 BundleManager::BundleManager (Session* session)
294 : ArdourDialog (_("Bundle Manager"))
295 , edit_button (_("Edit"))
296 , delete_button (_("Delete"))
298 set_session (session);
300 _list_model = Gtk::ListStore::create (_list_model_columns);
301 _tree_view.set_model (_list_model);
302 _tree_view.append_column (_("Name"), _list_model_columns.name);
303 _tree_view.set_headers_visible (false);
305 boost::shared_ptr<BundleList> bundles = _session->bundles ();
306 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
307 add_bundle (*i);
310 /* New / Edit / Delete buttons */
311 Gtk::VBox* buttons = new Gtk::VBox;
312 buttons->set_spacing (8);
313 Gtk::Button* b = new Gtk::Button (_("New"));
314 b->set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::NEW, Gtk::ICON_SIZE_BUTTON)));
315 b->signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::new_clicked));
316 buttons->pack_start (*Gtk::manage (b), false, false);
317 edit_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::EDIT, Gtk::ICON_SIZE_BUTTON)));
318 edit_button.signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::edit_clicked));
319 buttons->pack_start (edit_button, false, false);
320 delete_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::DELETE, Gtk::ICON_SIZE_BUTTON)));
321 delete_button.signal_clicked().connect (sigc::mem_fun (*this, &BundleManager::delete_clicked));
322 buttons->pack_start (delete_button, false, false);
324 Gtk::HBox* h = new Gtk::HBox;
325 h->set_spacing (8);
326 h->set_border_width (8);
327 h->pack_start (_tree_view);
328 h->pack_start (*Gtk::manage (buttons), false, false);
330 get_vbox()->set_spacing (8);
331 get_vbox()->pack_start (*Gtk::manage (h));
333 set_default_size (480, 240);
335 _tree_view.get_selection()->signal_changed().connect (
336 sigc::mem_fun (*this, &BundleManager::set_button_sensitivity)
339 _tree_view.signal_row_activated().connect (
340 sigc::mem_fun (*this, &BundleManager::row_activated)
343 set_button_sensitivity ();
345 show_all ();
348 void
349 BundleManager::set_button_sensitivity ()
351 bool const sel = (_tree_view.get_selection()->get_selected() != 0);
352 edit_button.set_sensitive (sel);
353 delete_button.set_sensitive (sel);
357 void
358 BundleManager::new_clicked ()
360 boost::shared_ptr<UserBundle> b (new UserBundle (_("Bundle")));
362 /* Start off with a single channel */
363 b->add_channel ("1");
365 _session->add_bundle (b);
366 add_bundle (b);
368 BundleEditor e (_session, b);
369 e.run ();
372 void
373 BundleManager::edit_clicked ()
375 Gtk::TreeModel::iterator i = _tree_view.get_selection()->get_selected();
376 if (i) {
377 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
378 BundleEditor e (_session, b);
379 e.run ();
383 void
384 BundleManager::delete_clicked ()
386 Gtk::TreeModel::iterator i = _tree_view.get_selection()->get_selected();
387 if (i) {
388 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
389 _session->remove_bundle (b);
390 _list_model->erase (i);
394 void
395 BundleManager::add_bundle (boost::shared_ptr<Bundle> b)
397 boost::shared_ptr<UserBundle> u = boost::dynamic_pointer_cast<UserBundle> (b);
398 if (u == 0) {
399 return;
402 Gtk::TreeModel::iterator i = _list_model->append ();
403 (*i)[_list_model_columns.name] = u->name ();
404 (*i)[_list_model_columns.bundle] = u;
406 u->Changed.connect (bundle_connections, invalidator (*this), ui_bind (&BundleManager::bundle_changed, this, _1, u), gui_context());
409 void
410 BundleManager::bundle_changed (Bundle::Change c, boost::shared_ptr<UserBundle> b)
412 if ((c & Bundle::NameChanged) == 0) {
413 return;
416 Gtk::TreeModel::iterator i = _list_model->children().begin ();
417 while (i != _list_model->children().end()) {
418 boost::shared_ptr<UserBundle> t = (*i)[_list_model_columns.bundle];
419 if (t == b) {
420 break;
422 ++i;
425 if (i != _list_model->children().end()) {
426 (*i)[_list_model_columns.name] = b->name ();
430 void
431 BundleManager::row_activated (Gtk::TreeModel::Path const & p, Gtk::TreeViewColumn*)
433 Gtk::TreeModel::iterator i = _list_model->get_iter (p);
434 if (!i) {
435 return;
438 boost::shared_ptr<UserBundle> b = (*i)[_list_model_columns.bundle];
439 BundleEditor e (_session, b);
440 e.run ();
443 NameChannelDialog::NameChannelDialog ()
444 : ArdourDialog (_("Add Channel")),
445 _adding (true)
447 setup ();
450 NameChannelDialog::NameChannelDialog (boost::shared_ptr<Bundle> b, uint32_t c)
451 : ArdourDialog (_("Rename Channel")),
452 _bundle (b),
453 _channel (c),
454 _adding (false)
456 _name.set_text (b->channel_name (c));
458 setup ();
461 void
462 NameChannelDialog::setup ()
464 Gtk::HBox* box = Gtk::manage (new Gtk::HBox ());
466 box->pack_start (*Gtk::manage (new Gtk::Label (_("Name"))));
467 box->pack_start (_name);
468 _name.set_activates_default (true);
470 get_vbox ()->pack_end (*box);
471 box->show_all ();
473 add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
474 if (_adding) {
475 add_button (Gtk::Stock::ADD, Gtk::RESPONSE_ACCEPT);
476 } else {
477 add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_ACCEPT);
479 set_default_response (Gtk::RESPONSE_ACCEPT);
482 string
483 NameChannelDialog::get_name () const
485 return _name.get_text ();