summaryrefslogtreecommitdiff
path: root/gtk2_ardour/luadialog.cc
diff options
context:
space:
mode:
authorRobin Gareus <robin@gareus.org>2017-04-24 22:12:09 +0200
committerRobin Gareus <robin@gareus.org>2017-04-25 14:01:22 +0200
commitf5995661d0b652a1907ca440dce6e1fcc2bf3855 (patch)
treef9f77298ce4dffbb3f4856c6ef49a9524ac15dfc /gtk2_ardour/luadialog.cc
parent7652f4edf204ae87c9d4475a603695d96c9bb1d5 (diff)
Lua: Action Script Dialog & MessageBox
Diffstat (limited to 'gtk2_ardour/luadialog.cc')
-rw-r--r--gtk2_ardour/luadialog.cc563
1 files changed, 563 insertions, 0 deletions
diff --git a/gtk2_ardour/luadialog.cc b/gtk2_ardour/luadialog.cc
new file mode 100644
index 0000000000..62a1e4d682
--- /dev/null
+++ b/gtk2_ardour/luadialog.cc
@@ -0,0 +1,563 @@
+/*
+ * Copyright (C) 2017 Robin Gareus <robin@gareus.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <gtkmm.h>
+
+#include "ardour/dB.h"
+#include "ardour/rc_configuration.h"
+
+#include "gtkmm2ext/slider_controller.h"
+#include "gtkmm2ext/utils.h"
+
+#include "ardour_dialog.h"
+#include "ardour_dropdown.h"
+#include "luadialog.h"
+#include "utils.h"
+
+using namespace LuaDialog;
+
+/*******************************************************************************
+ * Simple Message Dialog
+ */
+Message::Message (std::string const& title, std::string const& msg, Message::MessageType mt, Message::ButtonType bt)
+ : _message_dialog (msg, false, to_gtk_mt (mt), to_gtk_bt (bt), true)
+{
+ _message_dialog.set_title (title);
+}
+
+int
+Message::run ()
+{
+ int rv = _message_dialog.run ();
+ _message_dialog.hide ();
+ switch (rv) {
+ case Gtk::RESPONSE_OK:
+ return 0;
+ case Gtk::RESPONSE_CANCEL:
+ return 1;
+ case Gtk::RESPONSE_CLOSE:
+ return 2;
+ case Gtk::RESPONSE_YES:
+ return 3;
+ case Gtk::RESPONSE_NO:
+ return 4;
+ default:
+ break;
+ }
+ return -1;
+}
+
+Gtk::ButtonsType
+Message::to_gtk_bt (ButtonType bt)
+{
+ switch (bt) {
+ case OK:
+ return Gtk::BUTTONS_OK;
+ case Close:
+ return Gtk::BUTTONS_CLOSE;
+ case Cancel:
+ return Gtk::BUTTONS_CANCEL;
+ case Yes_No:
+ return Gtk::BUTTONS_YES_NO;
+ case OK_Cancel:
+ return Gtk::BUTTONS_OK_CANCEL;
+ }
+ assert (0);
+ return Gtk::BUTTONS_OK;
+}
+
+Gtk::MessageType
+Message::to_gtk_mt (MessageType mt)
+{
+ switch (mt) {
+ case Info:
+ return Gtk::MESSAGE_INFO;
+ case Warning:
+ return Gtk::MESSAGE_WARNING;
+ case Question:
+ return Gtk::MESSAGE_QUESTION;
+ case Error:
+ return Gtk::MESSAGE_ERROR;
+ }
+ assert (0);
+ return Gtk::MESSAGE_INFO;
+}
+
+
+/* *****************************************************************************
+ * Lua Dialog Widgets
+ */
+
+class LuaDialogCheckbox : public LuaDialogWidget
+{
+public:
+ LuaDialogCheckbox (std::string const& key, std::string const& title, bool on)
+ : LuaDialogWidget (key, "")
+ , _cb (title)
+ {
+ _cb.set_active (on);
+ }
+
+ Gtk::Widget* widget ()
+ {
+ return &_cb;
+ }
+
+ void assign (luabridge::LuaRef* rv) const
+ {
+ (*rv)[_key] = _cb.get_active ();
+ }
+
+protected:
+ Gtk::CheckButton _cb;
+};
+
+class LuaDialogEntry : public LuaDialogWidget
+{
+public:
+ LuaDialogEntry (std::string const& key, std::string const& title, std::string const& dflt)
+ : LuaDialogWidget (key, title)
+ {
+ _entry.set_text (dflt);
+ }
+
+ Gtk::Widget* widget ()
+ {
+ return &_entry;
+ }
+
+ void assign (luabridge::LuaRef* rv) const
+ {
+ (*rv)[_key] = std::string (_entry.get_text ());
+ }
+
+protected:
+ Gtk::Entry _entry;
+};
+
+class LuaDialogFader : public LuaDialogWidget
+{
+public:
+ LuaDialogFader (std::string const& key, std::string const& title, double dflt)
+ : LuaDialogWidget (key, title)
+ , _db_adjustment (ARDOUR::gain_to_slider_position_with_max (1.0, ARDOUR::Config->get_max_gain()), 0, 1, 0.01, 0.1)
+ {
+ _db_slider = Gtk::manage (new Gtkmm2ext::HSliderController (&_db_adjustment, boost::shared_ptr<PBD::Controllable>(), 220, 18));
+
+ _fader_centering_box.pack_start (*_db_slider, true, false);
+
+ _box.set_spacing (4);
+ _box.set_homogeneous (false);
+ _box.pack_start (_fader_centering_box, false, false);
+ _box.pack_start (_db_display, false, false);
+ _box.pack_start (*Gtk::manage (new Gtk::Label ("dB")), false, false);
+
+ Gtkmm2ext::set_size_request_to_display_given_text (_db_display, "-99.00", 12, 0);
+
+ _db_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &LuaDialogFader::db_changed));
+ _db_display.signal_activate().connect (sigc::mem_fun (*this, &LuaDialogFader::on_activate));
+ _db_display.signal_key_press_event().connect (sigc::mem_fun (*this, &LuaDialogFader::on_key_press), false);
+
+ double coeff_val = dB_to_coefficient (dflt);
+ _db_adjustment.set_value (ARDOUR::gain_to_slider_position_with_max (coeff_val, ARDOUR::Config->get_max_gain ()));
+ db_changed ();
+ }
+
+ Gtk::Widget* widget ()
+ {
+ return &_box;
+ }
+
+ void assign (luabridge::LuaRef* rv) const
+ {
+ double const val = ARDOUR::slider_position_to_gain_with_max (_db_adjustment.get_value (), ARDOUR::Config->get_max_gain());
+ (*rv)[_key] = accurate_coefficient_to_dB (val);
+ }
+
+protected:
+ void db_changed ()
+ {
+ double const val = ARDOUR::slider_position_to_gain_with_max (_db_adjustment.get_value (), ARDOUR::Config->get_max_gain());
+ char buf[16];
+ if (val == 0.0) {
+ snprintf (buf, sizeof (buf), "-inf");
+ } else {
+ snprintf (buf, sizeof (buf), "%.2f", accurate_coefficient_to_dB (val));
+ }
+ _db_display.set_text (buf);
+ }
+
+ void on_activate ()
+ {
+ float db_val = atof (_db_display.get_text ().c_str ());
+ double coeff_val = dB_to_coefficient (db_val);
+ _db_adjustment.set_value (ARDOUR::gain_to_slider_position_with_max (coeff_val, ARDOUR::Config->get_max_gain ()));
+ }
+
+ bool on_key_press (GdkEventKey* ev)
+ {
+ if (ARDOUR_UI_UTILS::key_is_legal_for_numeric_entry (ev->keyval)) {
+ return false;
+ }
+ return true;
+ }
+
+ Gtk::Adjustment _db_adjustment;
+ Gtkmm2ext::HSliderController* _db_slider;
+ Gtk::Entry _db_display;
+ Gtk::HBox _box;
+ Gtk::VBox _fader_centering_box;
+};
+
+class LuaDialogSlider : public LuaDialogWidget
+{
+public:
+ LuaDialogSlider (std::string const& key, std::string const& title, double lower, double upper, double dflt, int digits, luabridge::LuaRef scalepoints)
+ : LuaDialogWidget (key, title)
+ , _adj (dflt, lower, upper, 1, (upper - lower) / 20, 0)
+ , _hscale (_adj)
+ {
+ _hscale.set_digits (digits);
+ _hscale.set_draw_value (true);
+ _hscale.set_value_pos (Gtk::POS_TOP);
+
+ if (!scalepoints.isTable ()) {
+ return;
+ }
+
+ for (luabridge::Iterator i (scalepoints); !i.isNil (); ++i) {
+ if (!i.key ().isNumber ()) { continue; }
+ if (!i.value ().isString ()) { continue; }
+ _hscale.add_mark (i.key ().cast<double> (), Gtk::POS_BOTTOM, i.value ().cast<std::string> ());
+ }
+ }
+
+ Gtk::Widget* widget ()
+ {
+ return &_hscale;
+ }
+
+ void assign (luabridge::LuaRef* rv) const
+ {
+ (*rv)[_key] = _adj.get_value ();
+ }
+
+protected:
+ Gtk::Adjustment _adj;
+ Gtk::HScale _hscale;
+};
+
+class LuaDialogSpinBox : public LuaDialogWidget
+{
+public:
+ LuaDialogSpinBox (std::string const& key, std::string const& title, double lower, double upper, double dflt, double step, int digits)
+ : LuaDialogWidget (key, title)
+ , _adj (dflt, lower, upper, step, step, 0)
+ , _spin (_adj)
+ {
+ _spin.set_digits(digits);
+ }
+
+ Gtk::Widget* widget ()
+ {
+ return &_spin;
+ }
+
+ void assign (luabridge::LuaRef* rv) const
+ {
+ (*rv)[_key] = _adj.get_value ();
+ }
+
+protected:
+ Gtk::Adjustment _adj;
+ Gtk::SpinButton _spin;
+};
+
+class LuaDialogRadio : public LuaDialogWidget
+{
+public:
+ LuaDialogRadio (std::string const& key, std::string const& title, luabridge::LuaRef values, std::string const& dflt)
+ : LuaDialogWidget (key, title)
+ , _rv (0)
+ {
+ for (luabridge::Iterator i (values); !i.isNil (); ++i) {
+ if (!i.key ().isString ()) { continue; }
+ std::string key = i.key ().cast<std::string> ();
+ Gtk::RadioButton* rb = Gtk::manage (new Gtk::RadioButton (_group, key));
+ _hbox.pack_start (*rb);
+ luabridge::LuaRef* ref = new luabridge::LuaRef (i.value ());
+ _refs.push_back (ref);
+ if (!_rv) { _rv = ref; }
+ rb->signal_toggled ().connect (sigc::bind (
+ sigc::mem_fun (*this, &LuaDialogRadio::rb_toggled), rb, ref
+ ) , false);
+
+ if (key == dflt) {
+ rb->set_active ();
+ }
+ }
+ }
+
+ ~LuaDialogRadio ()
+ {
+ for (std::vector<luabridge::LuaRef*>::const_iterator i = _refs.begin (); i != _refs.end (); ++i) {
+ delete *i;
+ }
+ _refs.clear ();
+ }
+
+ Gtk::Widget* widget ()
+ {
+ return &_hbox;
+ }
+
+ void assign (luabridge::LuaRef* rv) const
+ {
+ if (_rv) {
+ (*rv)[_key] = *_rv;
+ } else {
+ (*rv)[_key] = luabridge::Nil ();
+ }
+ }
+
+protected:
+ LuaDialogRadio (LuaDialogRadio const&); // prevent cc
+ void rb_toggled (Gtk::RadioButton* b, luabridge::LuaRef* rv) {
+ if (b->get_active ()) {
+ _rv = rv;
+ }
+ }
+
+ Gtk::HBox _hbox;
+ Gtk::RadioButtonGroup _group;
+ std::vector<luabridge::LuaRef*> _refs;
+ luabridge::LuaRef* _rv;
+};
+
+class LuaDialogDropDown : public LuaDialogWidget
+{
+public:
+ LuaDialogDropDown (std::string const& key, std::string const& title, luabridge::LuaRef values, std::string const& dflt)
+ : LuaDialogWidget (key, title)
+ , _rv (0)
+ {
+ populate (_dd.items(), values, dflt);
+ }
+
+ ~LuaDialogDropDown ()
+ {
+ for (std::vector<luabridge::LuaRef*>::const_iterator i = _refs.begin (); i != _refs.end (); ++i) {
+ delete *i;
+ }
+ _refs.clear ();
+ }
+
+ Gtk::Widget* widget ()
+ {
+ return &_dd;
+ }
+
+ void assign (luabridge::LuaRef* rv) const
+ {
+ if (_rv) {
+ (*rv)[_key] = *_rv;
+ } else {
+ (*rv)[_key] = luabridge::Nil ();
+ }
+ }
+
+protected:
+ void populate (Gtk::Menu_Helpers::MenuList& items, luabridge::LuaRef values, std::string const& dflt)
+ {
+ using namespace Gtk::Menu_Helpers;
+ for (luabridge::Iterator i (values); !i.isNil (); ++i) {
+ if (!i.key ().isString ()) { continue; }
+ std::string key = i.key ().cast<std::string> ();
+ if (i.value ().isTable ()) {
+ Gtk::Menu* menu = Gtk::manage (new Gtk::Menu);
+ items.push_back (MenuElem (key, *menu));
+ populate (menu->items(), i.value (), dflt);
+ continue;
+ }
+ luabridge::LuaRef* ref = new luabridge::LuaRef (i.value ());
+ _refs.push_back (ref);
+ items.push_back (MenuElem (i.key ().cast<std::string> (),
+ sigc::bind (sigc::mem_fun(*this, &LuaDialogDropDown::dd_select), key, ref)));
+
+ if (!_rv || key == dflt) {
+ _rv = ref;
+ _dd.set_text (key);
+ }
+ }
+ }
+
+ void dd_select (std::string const& key, luabridge::LuaRef* rv) {
+ _dd.set_text (key);
+ _rv = rv;
+ }
+
+ ArdourDropdown _dd;
+ std::vector<luabridge::LuaRef*> _refs;
+ luabridge::LuaRef* _rv;
+};
+
+
+/*******************************************************************************
+ * Lua Parameter Dialog
+ */
+Dialog::Dialog (std::string const& title, luabridge::LuaRef lr)
+ :_ad (title, true, false)
+ , _title (title)
+{
+ if (!lr.isTable ()) {
+ return;
+ }
+ for (luabridge::Iterator i (lr); !i.isNil (); ++i) {
+ if (!i.key ().isNumber ()) { continue; }
+ if (!i.value ().isTable ()) { continue; }
+ if (!i.value ()["key"].isString ()) { continue; }
+ if (!i.value ()["title"].isString ()) { continue; }
+ if (!i.value ()["type"].isString ()) { continue; }
+
+ std::string key = i.value ()["key"].cast<std::string> ();
+ std::string title = i.value ()["title"].cast<std::string> ();
+ std::string type = i.value ()["type"].cast<std::string> ();
+
+ if (type == "checkbox") {
+ bool dflt = false;
+ if (i.value ()["default"].isBoolean ()) {
+ dflt = i.value ()["default"].cast<bool> ();
+ }
+ _widgets.push_back (new LuaDialogCheckbox (key, title, dflt));
+ } else if (type == "entry") {
+ std::string dflt;
+ if (i.value ()["default"].isString ()) {
+ dflt = i.value ()["default"].cast<std::string> ();
+ }
+ _widgets.push_back (new LuaDialogEntry (key, title, dflt));
+ } else if (type == "radio") {
+ std::string dflt;
+ if (!i.value ()["values"].isTable ()) {
+ continue;
+ }
+ if (i.value ()["default"].isString ()) {
+ dflt = i.value ()["default"].cast<std::string> ();
+ }
+ _widgets.push_back (new LuaDialogRadio (key, title, i.value ()["values"], dflt));
+ } else if (type == "fader") {
+ double dflt = 0;
+ if (i.value ()["default"].isNumber ()) {
+ dflt = i.value ()["default"].cast<double> ();
+ }
+ _widgets.push_back (new LuaDialogFader (key, title, dflt));
+ } else if (type == "slider") {
+ double lower, upper, dflt;
+ int digits = 0;
+ if (!i.value ()["min"].isNumber ()) { continue; }
+ if (!i.value ()["max"].isNumber ()) { continue; }
+ lower = i.value ()["min"].cast<double> ();
+ upper = i.value ()["max"].cast<double> ();
+ if (i.value ()["default"].isNumber ()) {
+ dflt = i.value ()["default"].cast<double> ();
+ } else {
+ dflt = lower;
+ }
+ if (i.value ()["digits"].isNumber ()) {
+ digits = i.value ()["digits"].cast<int> ();
+ }
+ _widgets.push_back (new LuaDialogSlider (key, title, lower, upper, dflt, digits, i.value ()["scalepoints"]));
+ } else if (type == "number") {
+ double lower, upper, dflt, step;
+ int digits = 0;
+ if (!i.value ()["min"].isNumber ()) { continue; }
+ if (!i.value ()["max"].isNumber ()) { continue; }
+ lower = i.value ()["min"].cast<double> ();
+ upper = i.value ()["max"].cast<double> ();
+ if (i.value ()["default"].isNumber ()) {
+ dflt = i.value ()["default"].cast<double> ();
+ } else {
+ dflt = lower;
+ }
+ if (i.value ()["step"].isNumber ()) {
+ step = i.value ()["step"].cast<double> ();
+ } else {
+ step = 1.0;
+ }
+ if (i.value ()["digits"].isNumber ()) {
+ digits = i.value ()["digits"].cast<int> ();
+ }
+ _widgets.push_back (new LuaDialogSpinBox (key, title, lower, upper, dflt, step, digits));
+ } else if (type == "dropdown") {
+ std::string dflt;
+ if (!i.value ()["values"].isTable ()) {
+ continue;
+ }
+ if (i.value ()["default"].isString ()) {
+ dflt = i.value ()["default"].cast<std::string> ();
+ }
+ _widgets.push_back (new LuaDialogDropDown (key, title, i.value ()["values"], dflt));
+ }
+ }
+
+ _ad.add_button (Gtk::Stock::OK, Gtk::RESPONSE_ACCEPT);
+ _ad.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
+
+ Gtk::Table* table = Gtk::manage (new Gtk::Table());
+ table->set_spacings (6);
+ _ad.get_vbox ()->pack_start (*table);
+ int row = 0;
+
+ for (DialogWidgets::const_iterator i = _widgets.begin (); i != _widgets.end () ; ++i) {
+ std::string const& label = (*i)->label ();
+ if (!label.empty ()) {
+ Gtk::Label* lbl = Gtk::manage (new Gtk::Label ("<b>" + label + ":</b>", Gtk::ALIGN_END, Gtk::ALIGN_CENTER, false));
+ lbl->set_use_markup ();
+ table->attach (*lbl, 0, 1, row, row + 1, Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);
+ }
+ table->attach (*((*i)->widget ()), 1, 2, row, row + 1, Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);
+ ++row;
+ }
+}
+
+Dialog::~Dialog ()
+{
+ for (DialogWidgets::const_iterator i = _widgets.begin (); i != _widgets.end () ; ++i) {
+ delete *i;
+ }
+ _widgets.clear ();
+}
+
+int
+Dialog::run (lua_State *L)
+{
+ _ad.get_vbox ()->show_all ();
+ switch (_ad.run ()) {
+ case Gtk::RESPONSE_ACCEPT:
+ break;
+ default:
+ lua_pushnil (L);
+ return 1;
+ }
+
+ luabridge::LuaRef rv (luabridge::newTable (L));
+ for (DialogWidgets::const_iterator i = _widgets.begin (); i != _widgets.end () ; ++i) {
+ (*i)->assign (&rv);
+ }
+ luabridge::push (L, rv);
+ return 1;
+}