+
+ if (peak_display.get_parent()) {
+ gain_display_box.remove (peak_display);
+ }
+
+ if (gain_automation_state_button.get_parent()) {
+ fader_vbox->remove (gain_automation_state_button);
+ }
+
+ GainMeterBase::set_controls (r, meter, amp);
+
+ if (_meter) {
+ _meter->ConfigurationChanged.connect (
+ model_connections, invalidator (*this), boost::bind (&GainMeter::meter_configuration_changed, this, _1), gui_context()
+ );
+
+ meter_configuration_changed (_meter->input_streams ());
+ }
+
+
+ /*
+ if we have a non-hidden route (ie. we're not the click or the auditioner),
+ pack some route-dependent stuff.
+ */
+
+ gain_display_box.pack_end (peak_display, true, true);
+ hbox.pack_start (meter_alignment, true, true);
+
+ if (r && !r->is_hidden()) {
+ fader_vbox->pack_start (gain_automation_state_button, false, false, 0);
+ }
+
+ setup_meters ();
+ hbox.show_all ();
+}
+
+int
+GainMeter::get_gm_width ()
+{
+ Gtk::Requisition sz;
+ hbox.size_request (sz);
+ return sz.width;
+}
+
+cairo_pattern_t*
+GainMeter::render_metrics (Gtk::Widget& w, vector<DataType> types)
+{
+ Glib::RefPtr<Gdk::Window> win (w.get_window());
+
+ gint width, height;
+ win->get_size (width, height);
+
+ cairo_surface_t* surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
+ cairo_t* cr = cairo_create (surface);
+ PangoLayout* layout = gtk_widget_create_pango_layout (w.gobj(), "");
+
+ cairo_move_to (cr, 0, 0);
+ cairo_rectangle (cr, 0, 0, width, height);
+ {
+ Gdk::Color c = w.get_style()->get_bg (Gtk::STATE_NORMAL);
+ cairo_set_source_rgb (cr, c.get_red_p(), c.get_green_p(), c.get_blue_p());
+ }
+ cairo_fill (cr);
+
+ for (vector<DataType>::const_iterator i = types.begin(); i != types.end(); ++i) {
+
+ Gdk::Color c;
+
+ if (types.size() > 1) {
+ /* we're overlaying more than 1 set of marks, so use different colours */
+ Gdk::Color c;
+ switch (*i) {
+ case DataType::AUDIO:
+ c = w.get_style()->get_fg (Gtk::STATE_NORMAL);
+ cairo_set_source_rgb (cr, c.get_red_p(), c.get_green_p(), c.get_blue_p());
+ break;
+ case DataType::MIDI:
+ c = w.get_style()->get_fg (Gtk::STATE_ACTIVE);
+ cairo_set_source_rgb (cr, c.get_red_p(), c.get_green_p(), c.get_blue_p());
+ break;
+ }
+ } else {
+ c = w.get_style()->get_fg (Gtk::STATE_NORMAL);
+ cairo_set_source_rgb (cr, c.get_red_p(), c.get_green_p(), c.get_blue_p());
+ }
+
+ vector<int> points;
+
+ switch (*i) {
+ case DataType::AUDIO:
+ points.push_back (-50);
+ points.push_back (-40);
+ points.push_back (-30);
+ points.push_back (-20);
+ points.push_back (-10);
+ points.push_back (-3);
+ points.push_back (0);
+ points.push_back (4);
+ break;
+
+ case DataType::MIDI:
+ points.push_back (0);
+ if (types.size() == 1) {
+ points.push_back (32);
+ } else {
+ /* tweak so as not to overlay the -30dB mark */
+ points.push_back (48);
+ }
+ points.push_back (64);
+ points.push_back (96);
+ points.push_back (127);
+ break;
+ }
+
+ char buf[32];
+
+ for (vector<int>::const_iterator j = points.begin(); j != points.end(); ++j) {
+
+ float fraction = 0;
+ switch (*i) {
+ case DataType::AUDIO:
+ fraction = log_meter (*j);
+ break;
+ case DataType::MIDI:
+ fraction = *j / 127.0;
+ break;
+ }
+
+ gint const pos = height - (gint) floor (height * fraction);
+
+ cairo_set_line_width (cr, 1.0);
+ cairo_move_to (cr, 0, pos);
+ cairo_line_to (cr, 4, pos);
+ cairo_stroke (cr);
+
+ snprintf (buf, sizeof (buf), "%d", abs (*j));
+ pango_layout_set_text (layout, buf, strlen (buf));
+
+ /* we want logical extents, not ink extents here */
+
+ int tw, th;
+ pango_layout_get_pixel_size (layout, &tw, &th);
+
+ int p = pos - (th / 2);
+ p = min (p, height - th);
+ p = max (p, 0);
+
+ cairo_move_to (cr, 6, p);
+ pango_cairo_show_layout (cr, layout);
+ }
+ }
+
+ cairo_pattern_t* pattern = cairo_pattern_create_for_surface (surface);
+ MetricPatterns::iterator p;
+
+ if ((p = metric_patterns.find (w.get_name())) != metric_patterns.end()) {
+ cairo_pattern_destroy (p->second);
+ }
+
+ metric_patterns[w.get_name()] = pattern;
+
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+ g_object_unref (layout);
+
+ return pattern;