Use small Astate buttons for plugins with many controls
[ardour.git] / gtk2_ardour / generic_pluginui.cc
index d5b3a5f89762db41233d895bf7ddd16eff8c8c90..b1d3b8c49d105d57f4dffef1870dcf3e13894643 100644 (file)
 #include <string>
 #include <vector>
 
+#include <gtkmm/separator.h>
+
 #include "pbd/stl_delete.h"
 #include "pbd/unwind.h"
 #include "pbd/xml++.h"
 #include "pbd/failed_constructor.h"
 
-#include <gtkmm2ext/click_box.h>
-#include <gtkmm2ext/fastmeter.h>
-#include <gtkmm2ext/barcontroller.h>
-#include <gtkmm2ext/utils.h>
-#include <gtkmm2ext/doi.h>
-#include <gtkmm2ext/slider_controller.h>
-
 #include "ardour/plugin.h"
 #include "ardour/plugin_insert.h"
 #include "ardour/session.h"
 #include "ardour/value_as_string.h"
 
-#include "prompter.h"
+#include "gtkmm2ext/utils.h"
+#include "gtkmm2ext/doi.h"
+
+#include "widgets/ardour_knob.h"
+#include "widgets/click_box.h"
+#include "widgets/fastmeter.h"
+#include "widgets/slider_controller.h"
+#include "widgets/tooltips.h"
+
 #include "plugin_ui.h"
+#include "plugin_display.h"
 #include "gui_thread.h"
 #include "automation_controller.h"
-#include "ardour_knob.h"
 #include "gain_meter.h"
 #include "timers.h"
-#include "tooltips.h"
 #include "ui_config.h"
 
 #include "pbd/i18n.h"
@@ -60,6 +62,7 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 using namespace Gtkmm2ext;
+using namespace ArdourWidgets;
 using namespace Gtk;
 using namespace ARDOUR_UI_UTILS;
 
@@ -217,6 +220,7 @@ std::size_t s1pos, s2pos, n = 0;
 
 static const guint32 min_controls_per_column = 17, max_controls_per_column = 24;
 static const float default_similarity_threshold = 0.3;
+static const guint32 max_columns_for_big_autostate = 2;
 
 void
 GenericPluginUI::build ()
@@ -471,6 +475,7 @@ GenericPluginUI::automatic_layout (const std::vector<ControlUI*>& control_uis)
        // starting a new column when necessary.
 
        i = 0;
+       size_t columns = 1;
        for (vector<ControlUI*>::iterator cuip = cui_controls_list.begin(); cuip != cui_controls_list.end(); ++cuip, ++i) {
 
                ControlUI* cui = *cuip;
@@ -490,6 +495,7 @@ GenericPluginUI::automatic_layout (const std::vector<ControlUI*>& control_uis)
                                frame->add (*box);
                                hpacker.pack_start(*frame, true, true);
                                x = 0;
+                               ++columns;
                        } else {
                                HSeparator *split = new HSeparator();
                                split->set_size_request(-1, 5);
@@ -500,6 +506,14 @@ GenericPluginUI::automatic_layout (const std::vector<ControlUI*>& control_uis)
                box->pack_start (*cui, false, false);
        }
 
+       if (columns > max_columns_for_big_autostate) {
+               for (vector<ControlUI*>::iterator cuip = cui_controls_list.begin();
+                                                 cuip != cui_controls_list.end();
+                                                 ++cuip) {
+                       set_short_autostate(*cuip, true);
+               }
+       }
+
        if (is_scrollable) {
                prefheight = 30 * i;
        }
@@ -525,6 +539,11 @@ GenericPluginUI::automatic_layout (const std::vector<ControlUI*>& control_uis)
        } else {
                delete output_table;
        }
+
+       if (plugin->has_inline_display () && plugin->inline_display_in_gui ()) {
+               PluginDisplay* pd = manage (new PluginDisplay (plugin, 300));
+               hpacker.pack_end (*pd, true, true);
+       }
        show_all();
 
 }
@@ -542,6 +561,11 @@ GenericPluginUI::custom_layout (const std::vector<ControlUI*>& control_uis)
                layout->attach (*cui, cui->x0, cui->x1, cui->y0, cui->y1, FILL, SHRINK, 2, 2);
        }
        hpacker.pack_start (*layout, true, true);
+
+       if (plugin->has_inline_display () && plugin->inline_display_in_gui ()) {
+               PluginDisplay* pd = manage (new PluginDisplay (plugin, 300));
+               hpacker.pack_end (*pd, true, true);
+       }
 }
 
 GenericPluginUI::ControlUI::ControlUI (const Evoral::Parameter& p)
@@ -560,13 +584,6 @@ GenericPluginUI::ControlUI::ControlUI (const Evoral::Parameter& p)
        automate_button.set_name ("plugin automation state button");
        set_tooltip (automate_button, _("Automation control"));
 
-       /* XXX translators: use a string here that will be at least as long
-          as the longest automation label (see ::automation_state_changed()
-          below). be sure to include a descender.
-       */
-
-       automate_button.set_sizing_text(_("Mgnual"));
-
        ignore_change = false;
        update_pending = false;
        button = false;
@@ -582,6 +599,21 @@ GenericPluginUI::ControlUI::~ControlUI()
        }
 }
 
+void
+GenericPluginUI::set_short_autostate (ControlUI* cui, bool value)
+{
+       cui->short_autostate = value;
+       if (value) {
+               cui->automate_button.set_sizing_text("M");
+       } else {
+               /* XXX translators: use a string here that will be at least as long
+                  as the longest automation label (see ::automation_state_changed()
+                  below). be sure to include a descender. */
+               cui->automate_button.set_sizing_text(_("Mgnual"));
+       }
+       automation_state_changed(cui);
+}
+
 void
 GenericPluginUI::automation_state_changed (ControlUI* cui)
 {
@@ -594,7 +626,7 @@ GenericPluginUI::automation_state_changed (ControlUI* cui)
 
        cui->automate_button.set_active((state != ARDOUR::Off));
 
-       if (cui->knobtable) {
+       if (cui->short_autostate) {
                cui->automate_button.set_text (
                                GainMeterBase::astate_string (state));
                return;
@@ -665,6 +697,7 @@ GenericPluginUI::build_control_ui (const Evoral::Parameter&             param,
        control_ui->label.set_alignment (0.0, 0.5);
        control_ui->label.set_name ("PluginParameterLabel");
        control_ui->set_spacing (5);
+       set_short_autostate(control_ui, false);
 
        if (is_input) {
 
@@ -702,13 +735,6 @@ GenericPluginUI::build_control_ui (const Evoral::Parameter&             param,
                        return control_ui;
                }
 
-               if (desc.datatype != Variant::INT && desc.datatype != Variant::LONG &&
-                               desc.datatype != Variant::FLOAT && desc.datatype != Variant::DOUBLE &&
-                               desc.datatype != Variant::BOOL) {
-                       /* unsupported variant type */
-                       return control_ui;
-               }
-
                assert(mcontrol);
 
                /* See if there any named values for our input value */
@@ -737,6 +763,8 @@ GenericPluginUI::build_control_ui (const Evoral::Parameter&             param,
                                                           i->second)));
                        }
 
+                       control_ui->combo->set_controllable (mcontrol);
+
                        update_control_display(control_ui);
 
                } else {
@@ -747,7 +775,7 @@ GenericPluginUI::build_control_ui (const Evoral::Parameter&             param,
                         * destructor, and manage() reports object hierarchy
                         * ambiguity.
                         */
-                       control_ui->controller = AutomationController::create(insert, mcontrol->parameter(), desc, mcontrol, use_knob);
+                       control_ui->controller = AutomationController::create(mcontrol->parameter(), desc, mcontrol, use_knob);
 
                        /* Control UI's don't need the rapid timer workaround */
                        control_ui->controller->stop_updating ();
@@ -759,13 +787,14 @@ GenericPluginUI::build_control_ui (const Evoral::Parameter&             param,
                        Adjustment* adj = control_ui->controller->adjustment();
 
                        if (desc.integer_step && !desc.toggled) {
-                               control_ui->clickbox = new ClickBox (adj, "PluginUIClickBox", true);
+                               control_ui->clickbox = new ArdourWidgets::ClickBox (adj, "PluginUIClickBox", true);
                                Gtkmm2ext::set_size_request_to_display_given_text (*control_ui->clickbox, "g9999999", 2, 2);
                                if (desc.unit == ParameterDescriptor::MIDI_NOTE) {
                                        control_ui->clickbox->set_printer (sigc::bind (sigc::mem_fun (*this, &GenericPluginUI::midinote_printer), control_ui));
                                } else {
                                        control_ui->clickbox->set_printer (sigc::bind (sigc::mem_fun (*this, &GenericPluginUI::integer_printer), control_ui));
                                }
+                               control_ui->clickbox->set_controllable (mcontrol);
                        } else if (desc.toggled) {
                                ArdourButton* but = dynamic_cast<ArdourButton*> (control_ui->controller->widget());
                                assert(but);
@@ -780,7 +809,7 @@ GenericPluginUI::build_control_ui (const Evoral::Parameter&             param,
                        }
 
                        if (!desc.integer_step && !desc.toggled && use_knob) {
-                               control_ui->spin_box = manage (new ArdourSpinner (mcontrol, adj, insert));
+                               control_ui->spin_box = manage (new ArdourSpinner (mcontrol, adj));
                        }
 
                        adj->set_value (mcontrol->internal_to_interface(value));
@@ -788,7 +817,7 @@ GenericPluginUI::build_control_ui (const Evoral::Parameter&             param,
                }
 
                if (use_knob) {
-                       control_ui->automate_button.set_sizing_text("M");
+                       set_short_autostate(control_ui, true);
 
                        control_ui->label.set_alignment (0.5, 0.5);
                        control_ui->knobtable = manage (new Table());
@@ -804,7 +833,6 @@ GenericPluginUI::build_control_ui (const Evoral::Parameter&             param,
                        } else if (control_ui->spin_box) {
                                ArdourKnob* knob = dynamic_cast<ArdourKnob*>(control_ui->controller->widget ());
                                knob->set_tooltip_prefix (desc.label + ": ");
-                               knob->set_printer (insert);
                                Alignment *align = manage (new Alignment (.5, .5, 0, 0));
                                align->add (*control_ui->controller);
                                control_ui->knobtable->attach (*align, 0, 1, 0, 1, EXPAND, SHRINK, 1, 2);
@@ -871,13 +899,6 @@ GenericPluginUI::build_control_ui (const Evoral::Parameter&             param,
 
        } else {
 
-               if (desc.datatype != Variant::INT && desc.datatype != Variant::LONG &&
-                               desc.datatype != Variant::FLOAT && desc.datatype != Variant::DOUBLE &&
-                               desc.datatype != Variant::BOOL) {
-                       /* unsupported variant type */
-                       return control_ui;
-               }
-
                control_ui->display = manage (new EventBox);
                control_ui->display->set_name ("ParameterValueDisplay");
 
@@ -893,7 +914,10 @@ GenericPluginUI::build_control_ui (const Evoral::Parameter&             param,
                control_ui->vbox = manage (new VBox);
                control_ui->vbox->set_spacing(3);
 
-               if (desc.integer_step || desc.enumeration) {
+               if (desc.unit == ParameterDescriptor::MIDI_NOTE) {
+                       control_ui->vbox->pack_end (*control_ui->display, false, false);
+                       control_ui->vbox->pack_end (control_ui->label, false, false);
+               } else if (desc.integer_step || desc.enumeration) {
                        control_ui->vbox->pack_end (*control_ui->display, false, false);
                        control_ui->vbox->pack_end (control_ui->label, false, false);
                } else {
@@ -914,12 +938,6 @@ GenericPluginUI::build_control_ui (const Evoral::Parameter&             param,
                                        UIConfiguration::instance().color ("meter background top")
                                        );
 
-                       info->min_unbound = desc.min_unbound;
-                       info->max_unbound = desc.max_unbound;
-
-                       info->min = desc.lower;
-                       info->max = desc.upper;
-
                        control_ui->label.set_angle(90);
 
                        HBox* center =  manage (new HBox);
@@ -1100,30 +1118,14 @@ GenericPluginUI::output_update ()
        for (vector<ControlUI*>::iterator i = output_controls.begin(); i != output_controls.end(); ++i) {
                float val = plugin->get_parameter ((*i)->parameter().id());
                char buf[32];
-               snprintf (buf, sizeof(buf), "%.2f", val);
+               boost::shared_ptr<ReadOnlyControl> c = insert->control_output ((*i)->parameter().id());
+               const std::string& str = ARDOUR::value_as_string(c->desc(), Variant(val));
+               size_t len = str.copy(buf, 31);
+               buf[len] = '\0';
                (*i)->display_label->set_text (buf);
 
-               /* autoscaling for the meter */
                if ((*i)->meterinfo && (*i)->meterinfo->packed) {
-
-                       if (val < (*i)->meterinfo->min) {
-                               if ((*i)->meterinfo->min_unbound)
-                                       (*i)->meterinfo->min = val;
-                               else
-                                       val = (*i)->meterinfo->min;
-                       }
-
-                       if (val > (*i)->meterinfo->max) {
-                               if ((*i)->meterinfo->max_unbound)
-                                       (*i)->meterinfo->max = val;
-                               else
-                                       val = (*i)->meterinfo->max;
-                       }
-
-                       if ((*i)->meterinfo->max > (*i)->meterinfo->min ) {
-                               float lval = (val - (*i)->meterinfo->min) / ((*i)->meterinfo->max - (*i)->meterinfo->min) ;
-                               (*i)->meterinfo->meter->set (lval );
-                       }
+                       (*i)->meterinfo->meter->set (c->desc().to_interface (val));
                }
        }
 }