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
, bundle
->type())
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
, _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 _bundle
->add_channel (d
.get_name());
126 PortMatrix::add_channel (b
);
132 BundleEditorMatrix::can_remove_channels (boost::shared_ptr
<Bundle
> b
) const
138 return PortMatrix::can_remove_channels (b
);
142 BundleEditorMatrix::remove_channel (BundleChannel bc
)
144 bc
.bundle
->remove_channel (bc
.channel
);
149 BundleEditorMatrix::can_rename_channels (boost::shared_ptr
<Bundle
> b
) const
155 return PortMatrix::can_rename_channels (b
);
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
) {
168 bc
.bundle
->set_channel_name (bc
.channel
, d
.get_name ());
172 BundleEditorMatrix::list_is_global (int dim
) const
174 return (dim
== OTHER
);
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);
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"));
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);
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"));
231 _type
.set_active_text (_("MIDI"));
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
);
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
);
254 BundleEditor::name_changed ()
256 _bundle
->set_name (_name
.get_text ());
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 ();
267 _bundle
->set_ports_are_inputs ();
270 _matrix
.setup_all_ports ();
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
);
286 BundleEditor::on_map ()
288 _matrix
.setup_all_ports ();
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
) {
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
;
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 ();
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
);
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
);
368 BundleEditor
e (_session
, b
);
373 BundleManager::edit_clicked ()
375 Gtk::TreeModel::iterator i
= _tree_view
.get_selection()->get_selected();
377 boost::shared_ptr
<UserBundle
> b
= (*i
)[_list_model_columns
.bundle
];
378 BundleEditor
e (_session
, b
);
384 BundleManager::delete_clicked ()
386 Gtk::TreeModel::iterator i
= _tree_view
.get_selection()->get_selected();
388 boost::shared_ptr
<UserBundle
> b
= (*i
)[_list_model_columns
.bundle
];
389 _session
->remove_bundle (b
);
390 _list_model
->erase (i
);
395 BundleManager::add_bundle (boost::shared_ptr
<Bundle
> b
)
397 boost::shared_ptr
<UserBundle
> u
= boost::dynamic_pointer_cast
<UserBundle
> (b
);
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());
410 BundleManager::bundle_changed (Bundle::Change c
, boost::shared_ptr
<UserBundle
> b
)
412 if ((c
& Bundle::NameChanged
) == 0) {
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
];
425 if (i
!= _list_model
->children().end()) {
426 (*i
)[_list_model_columns
.name
] = b
->name ();
431 BundleManager::row_activated (Gtk::TreeModel::Path
const & p
, Gtk::TreeViewColumn
*)
433 Gtk::TreeModel::iterator i
= _list_model
->get_iter (p
);
438 boost::shared_ptr
<UserBundle
> b
= (*i
)[_list_model_columns
.bundle
];
439 BundleEditor
e (_session
, b
);
443 NameChannelDialog::NameChannelDialog ()
444 : ArdourDialog (_("Add Channel")),
450 NameChannelDialog::NameChannelDialog (boost::shared_ptr
<Bundle
> b
, uint32_t c
)
451 : ArdourDialog (_("Rename Channel")),
456 _name
.set_text (b
->channel_name (c
));
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
);
473 add_button (Gtk::Stock::CANCEL
, Gtk::RESPONSE_CANCEL
);
475 add_button (Gtk::Stock::ADD
, Gtk::RESPONSE_ACCEPT
);
477 add_button (Gtk::Stock::APPLY
, Gtk::RESPONSE_ACCEPT
);
479 set_default_response (Gtk::RESPONSE_ACCEPT
);
483 NameChannelDialog::get_name () const
485 return _name
.get_text ();