Refactor PC Dialog/Window -- non-modal tabbed dialog

This commit is contained in:
Robin Gareus 2022-02-09 18:59:15 +01:00
parent eb674d3b58
commit a4fd29fa7d
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
2 changed files with 127 additions and 86 deletions

View File

@ -46,12 +46,10 @@
using namespace Gtk;
using namespace ARDOUR;
PatchBankList::PatchBankList (boost::shared_ptr<ARDOUR::Route> r)
: _route (r)
, _bank_msb_spin (*manage (new Adjustment (0, 0, 127, 1, 16)))
PatchBankList::PatchBankList ()
: _bank_msb_spin (*manage (new Adjustment (0, 0, 127, 1, 16)))
, _bank_lsb_spin (*manage (new Adjustment (0, 0, 127, 1, 16)))
, _program_table (/*rows*/ 16, /*cols*/ 8, true)
, _info (r->instrument_info ())
, _ignore_spin_btn_signals (false)
{
_program_table.set_spacings (1);
@ -67,14 +65,6 @@ PatchBankList::PatchBankList (boost::shared_ptr<ARDOUR::Route> r)
_bank_msb_spin.signal_changed ().connect (sigc::mem_fun (*this, &PatchBankList::select_bank_spin));
_bank_lsb_spin.signal_changed ().connect (sigc::mem_fun (*this, &PatchBankList::select_bank_spin));
_info.Changed.connect (_info_changed_connection, invalidator (*this),
boost::bind (&PatchBankList::instrument_info_changed, this), gui_context ());
if (!boost::dynamic_pointer_cast<MidiTrack> (_route)) {
_route->processors_changed.connect (_route_connection, invalidator (*this),
boost::bind (&PatchBankList::processors_changed, this), gui_context ());
}
}
PatchBankList::~PatchBankList ()
@ -96,7 +86,7 @@ flip_map (std::map<A, B> const& src)
}
void
PatchBankList::refill (const uint8_t channel)
PatchBankList::refill (boost::shared_ptr<MIDI::Name::ChannelNameSet> cns, int const b)
{
using namespace Menu_Helpers;
using namespace Gtkmm2ext;
@ -105,8 +95,6 @@ PatchBankList::refill (const uint8_t channel)
_current_patch_bank.reset ();
_bank_select.clear_items ();
const int b = bank (channel);
{
PBD::Unwinder<bool> uw (_ignore_spin_btn_signals, true);
_bank_msb_spin.set_value (b >> 7);
@ -122,7 +110,6 @@ PatchBankList::refill (const uint8_t channel)
unset_notes.set ();
boost::shared_ptr<ChannelNameSet> cns = _info.get_patches (channel);
if (cns) {
const ChannelNameSet::PatchBanks& patch_banks = cns->patch_banks ();
for (ChannelNameSet::PatchBanks::const_iterator bank = patch_banks.begin (); bank != patch_banks.end (); ++bank) {
@ -251,21 +238,12 @@ PatchBankList::set_active_pgm (uint8_t p)
/* ****************************************************************************/
PatchChangeTab::PatchChangeTab (boost::shared_ptr<Route> r, boost::shared_ptr<MIDITrigger> t, int channel)
: PatchBankList (r)
, _enable_btn (_("Override Patch Changes"), ArdourWidgets::ArdourButton::led_default_elements)
PatchChangeTab::PatchChangeTab (int channel)
: _enable_btn (_("Override Patch Changes"), ArdourWidgets::ArdourButton::led_default_elements)
, _channel (channel)
, _bank (0)
, _ignore_callback (false)
, _trigger (t)
{
if (_trigger->patch_change_set (_channel)) {
_bank = _trigger->patch_change (_channel).bank ();
_enable_btn.set_active (true);
} else {
_enable_btn.set_active (false);
}
Box* box;
box = manage (new HBox ());
box->set_border_width (2);
@ -288,18 +266,39 @@ PatchChangeTab::PatchChangeTab (boost::shared_ptr<Route> r, boost::shared_ptr<MI
_enable_btn.signal_clicked.connect (sigc::mem_fun (*this, &PatchChangeTab::enable_toggle));
_trigger->PropertyChanged.connect (_trigger_connection, invalidator (*this), boost::bind (&PatchChangeTab::trigger_property_changed, this, _1), gui_context ());
if (!boost::dynamic_pointer_cast<MidiTrack> (_route)) {
processors_changed ();
reset (boost::shared_ptr<ARDOUR::Route> (), boost::shared_ptr<ARDOUR::MIDITrigger>());
}
void
PatchChangeTab::reset (boost::shared_ptr<ARDOUR::Route> r, boost::shared_ptr<MIDITrigger> t)
{
_route = r;
_trigger = t;
_connections.drop_connections ();
if (!r || !t) {
_enable_btn.set_active (false);
refill_banks ();
return;
}
if (_trigger->patch_change_set (_channel)) {
_bank = _trigger->patch_change (_channel).bank ();
_enable_btn.set_active (true);
} else {
_enable_btn.set_active (false);
}
_route->instrument_info().Changed.connect (_connections, invalidator (*this), boost::bind (&PatchChangeTab::instrument_info_changed, this), gui_context ());
_trigger->PropertyChanged.connect (_connections, invalidator (*this), boost::bind (&PatchChangeTab::trigger_property_changed, this, _1), gui_context ());
refill_banks ();
update_sensitivity ();
}
void
PatchChangeTab::enable_toggle ()
{
if (_ignore_callback) {
if (_ignore_callback || !_trigger) {
return;
}
if (_enable_btn.get_active ()) {
@ -313,7 +312,8 @@ PatchChangeTab::enable_toggle ()
void
PatchChangeTab::update_sensitivity ()
{
bool en = _trigger->patch_change_set (_channel);
bool en = _trigger ? _trigger->patch_change_set (_channel) : false;
_enable_btn.set_sensitive (_trigger ? true : false /* _trigger->region () ? true : false) : false */);
_program_table.set_sensitive (en);
_bank_select.set_sensitive (en);
_bank_msb_spin.set_sensitive (en);
@ -340,7 +340,7 @@ PatchChangeTab::select_bank (uint32_t bank)
void
PatchChangeTab::select_program (uint8_t pgm)
{
if (pgm > 127) {
if (pgm > 127 || !_trigger) {
return;
}
@ -357,15 +357,19 @@ PatchChangeTab::refresh ()
void
PatchChangeTab::refill_banks ()
{
refill (_channel);
boost::shared_ptr<MIDI::Name::ChannelNameSet> cns;
if (_route) {
cns = _route->instrument_info ().get_patches (_channel);
}
update_sensitivity ();
refill (cns, bank ());
set_active_pgm (program ());
}
int
PatchChangeTab::bank (uint8_t c) const
PatchChangeTab::bank () const
{
assert (c == _channel);
if (_trigger->patch_change_set (_channel)) {
if (_trigger && _trigger->patch_change_set (_channel)) {
return _trigger->patch_change (_channel).bank ();
}
return _bank;
@ -374,7 +378,7 @@ PatchChangeTab::bank (uint8_t c) const
uint8_t
PatchChangeTab::program () const
{
if (_trigger->patch_change_set (_channel)) {
if (_trigger && _trigger->patch_change_set (_channel)) {
return _trigger->patch_change (_channel).program ();
}
return 0;
@ -386,15 +390,11 @@ PatchChangeTab::instrument_info_changed ()
refill_banks ();
}
void
PatchChangeTab::processors_changed ()
{
}
/* ****************************************************************************/
PatchChangeWidget::PatchChangeWidget (boost::shared_ptr<ARDOUR::Route> r)
: PatchBankList (r)
: _route (r)
, _info (r->instrument_info ())
, _channel (-1)
, _no_notifications (false)
, _audition_enable (_("Audition on Change"), ArdourWidgets::ArdourButton::led_default_elements)
@ -467,7 +467,12 @@ PatchChangeWidget::PatchChangeWidget (boost::shared_ptr<ARDOUR::Route> r)
if (!boost::dynamic_pointer_cast<MidiTrack> (_route)) {
processors_changed ();
_route->processors_changed.connect (_route_connections, invalidator (*this),
boost::bind (&PatchChangeWidget::processors_changed, this), gui_context ());
}
_info.Changed.connect (_route_connections, invalidator (*this),
boost::bind (&PatchChangeWidget::instrument_info_changed, this), gui_context ());
}
PatchChangeWidget::~PatchChangeWidget ()
@ -546,7 +551,9 @@ void
PatchChangeWidget::refill_banks ()
{
cancel_audition ();
refill (_channel);
boost::shared_ptr<MIDI::Name::ChannelNameSet> cns = _info.get_patches (_channel);
refill (cns, bank (_channel));
program_changed ();
}
@ -804,23 +811,53 @@ PatchChangeWidget::program (uint8_t chn) const
/* ***************************************************************************/
PatchChangeTriggerDialog::PatchChangeTriggerDialog (boost::shared_ptr<Route> r, boost::shared_ptr<MIDITrigger> t)
: ArdourDialog (string_compose (_("Select Patch for \"%1\""), t->name ()), false, false)
PatchChangeTriggerWindow::PatchChangeTriggerWindow ()
: ArdourWindow (_("Trigger Patch Select"))
{
for (uint32_t chn = 0; chn < 16; ++chn) {
_w[chn] = manage (new PatchChangeTab (r, t, chn));
_w[chn] = manage (new PatchChangeTab (chn));
_notebook.append_page (*_w[chn], string_compose (_("Chn %1"), chn + 1));
}
_notebook.signal_switch_page ().connect (sigc::mem_fun (*this, &PatchChangeTriggerDialog::on_switch_page));
_notebook.set_current_page (0);
get_vbox ()->add (_notebook);
_notebook.show_all ();
add (_notebook);
_notebook.signal_switch_page ().connect (sigc::mem_fun (*this, &PatchChangeTriggerWindow::on_switch_page));
_notebook.set_current_page (0);
}
void
PatchChangeTriggerDialog::on_switch_page (GtkNotebookPage*, guint page_num)
PatchChangeTriggerWindow::clear ()
{
_route_connection.disconnect ();
set_title (_("Trigger Patch Select"));
for (uint32_t chn = 0; chn < 16; ++chn) {
_w[chn]->reset (boost::shared_ptr<ARDOUR::Route> (), boost::shared_ptr<ARDOUR::MIDITrigger>());
}
}
void
PatchChangeTriggerWindow::reset (boost::shared_ptr<Route> r, boost::shared_ptr<MIDITrigger> t)
{
if (!r || !t) {
clear ();
return;
}
set_title (string_compose (_("Select Patch for \"%1\" - \"%2\""), r->name (), t->name ()));
r->DropReferences.connect (_route_connection, invalidator(*this), boost::bind (&PatchChangeTriggerWindow::clear, this), gui_context());
for (uint32_t chn = 0; chn < 16; ++chn) {
_w[chn]->reset (r, t);
}
_notebook.set_current_page (0);
}
void
PatchChangeTriggerWindow::on_switch_page (GtkNotebookPage*, guint page_num)
{
_w[page_num]->refresh ();
}

View File

@ -33,29 +33,26 @@
#include "widgets/ardour_dropdown.h"
#include "ardour_dialog.h"
#include "ardour_window.h"
#include "pianokeyboard.h"
namespace ARDOUR {
class MIDITrigger;
};
class PatchBankList : virtual public sigc::trackable
class PatchBankList
{
public:
PatchBankList (boost::shared_ptr<ARDOUR::Route>);
PatchBankList ();
virtual ~PatchBankList ();
protected:
void refill (uint8_t const channel);
void refill (boost::shared_ptr<MIDI::Name::ChannelNameSet>, int const bank);
void set_active_pgm (uint8_t);
virtual int bank (uint8_t chn) const = 0;
virtual void select_bank (uint32_t) = 0;
virtual void select_program (uint8_t) = 0;
virtual void instrument_info_changed () = 0;
virtual void processors_changed () = 0;
boost::shared_ptr<ARDOUR::Route> _route;
ArdourWidgets::ArdourDropdown _bank_select;
Gtk::SpinButton _bank_msb_spin;
@ -65,37 +62,34 @@ protected:
private:
void select_bank_spin ();
ARDOUR::InstrumentInfo& _info;
ArdourWidgets::ArdourButton _program_btn[128];
boost::shared_ptr<MIDI::Name::PatchBank> _current_patch_bank;
bool _ignore_spin_btn_signals;
PBD::ScopedConnection _info_changed_connection;
PBD::ScopedConnection _route_connection;
};
class PatchChangeTab : public Gtk::VBox, public PatchBankList
{
public:
PatchChangeTab (boost::shared_ptr<ARDOUR::Route>, boost::shared_ptr<ARDOUR::MIDITrigger>, int channel);
PatchChangeTab (int channel);
void refresh ();
void reset (boost::shared_ptr<ARDOUR::Route>, boost::shared_ptr<ARDOUR::MIDITrigger>);
protected:
int bank (uint8_t) const;
int bank () const;
uint8_t program () const;
/* Implement PatchBankList */
void select_bank (uint32_t);
void select_program (uint8_t);
void instrument_info_changed ();
void processors_changed ();
private:
void refill_banks ();
void trigger_property_changed (PBD::PropertyChange const&);
void enable_toggle ();
void update_sensitivity ();
void instrument_info_changed ();
ArdourWidgets::ArdourButton _enable_btn;
@ -103,8 +97,9 @@ private:
int _bank;
bool _ignore_callback;
boost::shared_ptr<ARDOUR::Route> _route;
boost::shared_ptr<ARDOUR::MIDITrigger> _trigger;
PBD::ScopedConnection _trigger_connection;
PBD::ScopedConnectionList _connections;
};
class PatchChangeWidget : public Gtk::VBox, public PatchBankList
@ -125,16 +120,13 @@ protected:
private:
void refill_banks ();
ArdourWidgets::ArdourDropdown _channel_select;
uint8_t _channel;
bool _no_notifications;
void select_channel (uint8_t);
/* Implement PatchBankList */
void select_bank (uint32_t);
void select_program (uint8_t);
/* Route Callbacks */
void instrument_info_changed ();
void processors_changed ();
@ -143,8 +135,6 @@ private:
void program_changed ();
void bankpatch_changed (uint8_t);
PBD::ScopedConnectionList _ac_connections;
/* Audition */
void audition_toggle ();
void check_note_range (bool);
@ -152,32 +142,46 @@ private:
void cancel_audition ();
bool audition_next ();
sigc::connection _note_queue_connection;
boost::shared_ptr<ARDOUR::Route> _route;
ARDOUR::InstrumentInfo& _info;
ArdourWidgets::ArdourButton _audition_enable;
Gtk::SpinButton _audition_start_spin; // Consider a click-box w/note-names
Gtk::SpinButton _audition_end_spin;
Gtk::SpinButton _audition_velocity;
uint8_t _audition_note_num;
bool _audition_note_on;
uint8_t _channel;
bool _no_notifications;
ArdourWidgets::ArdourDropdown _channel_select;
ArdourWidgets::ArdourButton _audition_enable;
Gtk::SpinButton _audition_start_spin; // Consider a click-box w/note-names
Gtk::SpinButton _audition_end_spin;
Gtk::SpinButton _audition_velocity;
uint8_t _audition_note_num;
bool _audition_note_on;
APianoKeyboard _piano;
void _note_on_event_handler (int, int);
void note_on_event_handler (int, bool for_audition);
void note_off_event_handler (int);
sigc::connection _note_queue_connection;
PBD::ScopedConnectionList _ac_connections;
PBD::ScopedConnectionList _route_connections;
};
class PatchChangeTriggerDialog : public ArdourDialog
class PatchChangeTriggerWindow : public ArdourWindow
{
public:
PatchChangeTriggerDialog (boost::shared_ptr<ARDOUR::Route>, boost::shared_ptr<ARDOUR::MIDITrigger>);
PatchChangeTriggerWindow ();
void reset (boost::shared_ptr<ARDOUR::Route>, boost::shared_ptr<ARDOUR::MIDITrigger>);
void clear ();
private:
void on_switch_page (GtkNotebookPage*, guint page_num);
Gtk::Notebook _notebook;
PatchChangeTab* _w[16];
PBD::ScopedConnection _route_connection;
};
class PatchChangeGridDialog : public ArdourDialog