X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fgeneric_pluginui.cc;h=30be93c1406857a73ffaba3760c59b298ddf8292;hb=11e907770a0a7bceea240de30517f2237e5fe128;hp=a44b54c9b00bf4d0472b22bd3b5032418cf323bb;hpb=ed626628b54e67dd9621c08d82a42afaed00c7ac;p=ardour.git diff --git a/gtk2_ardour/generic_pluginui.cc b/gtk2_ardour/generic_pluginui.cc index a44b54c9b0..30be93c140 100644 --- a/gtk2_ardour/generic_pluginui.cc +++ b/gtk2_ardour/generic_pluginui.cc @@ -126,8 +126,13 @@ GenericPluginUI::GenericPluginUI (boost::shared_ptr pi, bool scrol pi->ActiveChanged.connect (active_connection, invalidator (*this), boost::bind (&GenericPluginUI::processor_active_changed, this, boost::weak_ptr(pi)), gui_context()); - bypass_button.set_active (!pi->active()); + if (!pi->active()) { + bypass_button.set_active_state (Gtkmm2ext::Active); + } else { + bypass_button.unset_active_state (); + } + prefheight = 0; build (); } @@ -138,6 +143,55 @@ GenericPluginUI::~GenericPluginUI () } } +// Some functions for calculating the 'similarity' of two plugin +// control labels. + +static int get_number(string label) { +static const char *digits = "0123456789"; +int value = -1; + + std::size_t first_digit_pos = label.find_first_of(digits); + if (first_digit_pos != string::npos) { + // found some digits: there's a number in there somewhere + stringstream s; + s << label.substr(first_digit_pos); + s >> value; + } + return value; +} + +static int match_or_digit(char c1, char c2) { + return c1 == c2 || (isdigit(c1) && isdigit(c2)); +} + +static std::size_t matching_chars_at_head(const string s1, const string s2) { +std::size_t length, n = 0; + + length = min(s1.length(), s2.length()); + while (n < length) { + if (!match_or_digit(s1[n], s2[n])) + break; + n++; + } + return n; +} + +static std::size_t matching_chars_at_tail(const string s1, const string s2) { +std::size_t s1pos, s2pos, n = 0; + + s1pos = s1.length(); + s2pos = s2.length(); + while (s1pos-- > 0 && s2pos-- > 0) { + if (!match_or_digit(s1[s1pos], s2[s2pos]) ) + break; + n++; + } + return n; +} + +static const guint32 min_controls_per_column = 17, max_controls_per_column = 24; +static const float default_similarity_threshold = 0.3; + void GenericPluginUI::build () { @@ -151,7 +205,6 @@ GenericPluginUI::build () int output_rows, output_cols; int button_rows, button_cols; - prefheight = 30; hpacker.set_spacing (10); output_rows = initial_output_rows; @@ -176,6 +229,7 @@ GenericPluginUI::build () bt_frame = manage (new Frame); bt_frame->set_name ("BaseFrame"); + bt_frame->set_label (_("Switches")); bt_frame->add (button_table); hpacker.pack_start(*bt_frame, true, true); @@ -190,6 +244,7 @@ GenericPluginUI::build () hpacker.pack_start(*frame, true, true); /* find all ports. build control elements for all appropriate control ports */ + std::vector cui_controls_list; for (i = 0; i < plugin->parameter_count(); ++i) { @@ -203,24 +258,6 @@ GenericPluginUI::build () ControlUI* cui; - /* if we are scrollable, just use one long column */ - - if (!is_scrollable) { - if (x++ > 20){ - frame = manage (new Frame); - frame->set_name ("BaseFrame"); - box = manage (new VBox); - - box->set_border_width (5); - box->set_spacing (1); - - frame->add (*box); - hpacker.pack_start(*frame, true, true); - - x = 1; - } - } - boost::shared_ptr c = boost::dynamic_pointer_cast( insert->control(Evoral::Parameter(PluginAutomation, 0, i))); @@ -231,12 +268,12 @@ GenericPluginUI::build () } if (cui->controller || cui->clickbox || cui->combo) { - - box->pack_start (*cui, false, false); - + // Get all of the controls into a list, so that + // we can lay them out a bit more nicely later. + cui_controls_list.push_back(cui); } else if (cui->button) { - if (button_row == button_rows) { + if (!is_scrollable && button_row == button_rows) { button_row = 0; if (++button_col == button_cols) { button_cols += 2; @@ -259,33 +296,93 @@ GenericPluginUI::build () output_cols ++; output_table.resize (output_rows, output_cols); } + } + } + } - /* old code, which divides meters into - * columns first, rows later. New code divides into one row - - if (output_row == output_rows) { - output_row = 0; - if (++output_col == output_cols) { - output_cols += 2; - output_table.resize (output_rows, output_cols); - } - } - - output_table.attach (*cui, output_col, output_col + 1, output_row, output_row+1, - FILL|EXPAND, FILL); - - output_row++; - */ + // Iterate over the list of controls to find which adjacent controls + // are similar enough to be grouped together. + + string label, previous_label = ""; + int numbers_in_labels[cui_controls_list.size()]; + + float similarity_scores[cui_controls_list.size()]; + float most_similar = 0.0, least_similar = 1.0; + + i = 0; + for (vector::iterator cuip = cui_controls_list.begin(); cuip != cui_controls_list.end(); ++cuip, ++i) { + label = (*cuip)->label.get_text(); + numbers_in_labels[i] = get_number(label); + + if (i > 0) { + // A hand-wavy calculation of how similar this control's + // label is to the previous. + similarity_scores[i] = + (float) ( + ( matching_chars_at_head(label, previous_label) + + matching_chars_at_tail(label, previous_label) + + 1 + ) + ) / (label.length() + previous_label.length()); + if (numbers_in_labels[i] >= 0) { + similarity_scores[i] += (numbers_in_labels[i] == numbers_in_labels[i-1]); } + least_similar = min(least_similar, similarity_scores[i]); + most_similar = max(most_similar, similarity_scores[i]); + } else { + similarity_scores[0] = 1.0; + } - /* HACK: ideally the preferred height would be queried from - the complete hpacker, but I can't seem to get that - information in time, so this is an estimation - */ + // cerr << "label: " << label << " sim: " << fixed << setprecision(3) << similarity_scores[i] << " num: " << numbers_in_labels[i] << endl; + previous_label = label; + } - prefheight += 30; + + // cerr << "most similar: " << most_similar << ", least similar: " << least_similar << endl; + float similarity_threshold; + + if (most_similar > 1.0) { + similarity_threshold = default_similarity_threshold; + } else { + similarity_threshold = most_similar - (1 - default_similarity_threshold); + } + + // Now iterate over the list of controls to display them, placing an + // HSeparator between controls of less than a certain similarity, and + // starting a new column when necessary. + + i = 0; + for (vector::iterator cuip = cui_controls_list.begin(); cuip != cui_controls_list.end(); ++cuip, ++i) { + + ControlUI* cui = *cuip; + + if (!is_scrollable) { + x++; + } + + if (x > max_controls_per_column || similarity_scores[i] <= similarity_threshold) { + if (x > min_controls_per_column) { + frame = manage (new Frame); + frame->set_name ("BaseFrame"); + frame->set_label (_("Controls")); + box = manage (new VBox); + box->set_border_width (5); + box->set_spacing (1); + frame->add (*box); + hpacker.pack_start(*frame, true, true); + x = 0; + } else { + HSeparator *split = new HSeparator(); + split->set_size_request(-1, 5); + box->pack_start(*split, false, false, 0); + } } + box->pack_start (*cui, false, false); + } + + if (is_scrollable) { + prefheight = 30 * i; } if (box->children().empty()) { @@ -299,6 +396,7 @@ GenericPluginUI::build () if (!output_table.children().empty()) { frame = manage (new Frame); frame->set_name ("BaseFrame"); + frame->set_label(_("Meters")); frame->add (output_table); hpacker.pack_end (*frame, true, true); } @@ -387,7 +485,6 @@ GenericPluginUI::build_control_ui (guint32 port_index, boost::shared_ptrcombo = 0; - control_ui->combo_map = 0; control_ui->control = mcontrol; control_ui->update_pending = false; control_ui->label.set_text (desc.label); @@ -403,13 +500,15 @@ GenericPluginUI::build_control_ui (guint32 port_index, boost::shared_ptr points - = plugin->get_scale_points(port_index); + control_ui->combo_map = plugin->get_scale_points (port_index); - if (points) { + if (control_ui->combo_map) { std::vector labels; - for (ARDOUR::Plugin::ScalePoints::const_iterator i = points->begin(); - i != points->end(); ++i) { + for ( + ARDOUR::Plugin::ScalePoints::const_iterator i = control_ui->combo_map->begin(); + i != control_ui->combo_map->end(); + ++i) { + labels.push_back(i->first); } @@ -650,8 +749,7 @@ GenericPluginUI::update_control_display (ControlUI* cui) cui->ignore_change++; if (cui->combo && cui->combo_map) { - std::map::iterator it; - for (it = cui->combo_map->begin(); it != cui->combo_map->end(); ++it) { + for (ARDOUR::Plugin::ScalePoints::iterator it = cui->combo_map->begin(); it != cui->combo_map->end(); ++it) { if (it->second == val) { cui->combo->set_active_text(it->first); break; @@ -695,21 +793,10 @@ GenericPluginUI::control_combo_changed (ControlUI* cui) { if (!cui->ignore_change && cui->combo_map) { string value = cui->combo->get_active_text(); - std::map mapping = *cui->combo_map; - insert->automation_control(cui->parameter())->set_value(mapping[value]); + insert->automation_control (cui->parameter())->set_value ((*cui->combo_map)[value]); } } -void -GenericPluginUI::processor_active_changed (boost::weak_ptr weak_processor) -{ - ENSURE_GUI_THREAD (*this, &GenericPluginUI::processor_active_changed, weak_processor) - - boost::shared_ptr processor = weak_processor.lock(); - - bypass_button.set_active (!processor || !processor->active()); -} - bool GenericPluginUI::start_updating (GdkEventAny*) {