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
);
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);
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"));
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);
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"));
225 _type
.set_active_text (_("MIDI"));
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
);
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
);
248 BundleEditor::name_changed ()
250 _bundle
->set_name (_name
.get_text ());
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 ();
261 _bundle
->set_ports_are_inputs ();
264 _matrix
.setup_all_ports ();
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
);
280 BundleEditor::on_map ()
282 _matrix
.setup_all_ports ();
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
) {
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
;
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 ();
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
);
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
);
362 BundleEditor
e (_session
, b
);
367 BundleManager::edit_clicked ()
369 Gtk::TreeModel::iterator i
= _tree_view
.get_selection()->get_selected();
371 boost::shared_ptr
<UserBundle
> b
= (*i
)[_list_model_columns
.bundle
];
372 BundleEditor
e (_session
, b
);
378 BundleManager::delete_clicked ()
380 Gtk::TreeModel::iterator i
= _tree_view
.get_selection()->get_selected();
382 boost::shared_ptr
<UserBundle
> b
= (*i
)[_list_model_columns
.bundle
];
383 _session
->remove_bundle (b
);
384 _list_model
->erase (i
);
389 BundleManager::add_bundle (boost::shared_ptr
<Bundle
> b
)
391 boost::shared_ptr
<UserBundle
> u
= boost::dynamic_pointer_cast
<UserBundle
> (b
);
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());
404 BundleManager::bundle_changed (Bundle::Change c
, boost::shared_ptr
<UserBundle
> b
)
406 if ((c
& Bundle::NameChanged
) == 0) {
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
];
419 if (i
!= _list_model
->children().end()) {
420 (*i
)[_list_model_columns
.name
] = b
->name ();
425 BundleManager::row_activated (Gtk::TreeModel::Path
const & p
, Gtk::TreeViewColumn
*)
427 Gtk::TreeModel::iterator i
= _list_model
->get_iter (p
);
432 boost::shared_ptr
<UserBundle
> b
= (*i
)[_list_model_columns
.bundle
];
433 BundleEditor
e (_session
, b
);
437 NameChannelDialog::NameChannelDialog ()
438 : ArdourDialog (_("Add Channel")),
444 NameChannelDialog::NameChannelDialog (boost::shared_ptr
<Bundle
> b
, uint32_t c
)
445 : ArdourDialog (_("Rename Channel")),
450 _name
.set_text (b
->channel_name (c
));
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
);
467 add_button (Gtk::Stock::CANCEL
, Gtk::RESPONSE_CANCEL
);
469 add_button (Gtk::Stock::ADD
, Gtk::RESPONSE_ACCEPT
);
471 add_button (Gtk::Stock::APPLY
, Gtk::RESPONSE_ACCEPT
);
473 set_default_response (Gtk::RESPONSE_ACCEPT
);
477 NameChannelDialog::get_name () const
479 return _name
.get_text ();