+ gain_watching = ARDOUR_UI::RapidScreenUpdate.connect (sigc::mem_fun (*this, &GainMeterBase::effective_gain_display));
+ }
+}
+
+void
+GainMeterBase::update_meters()
+{
+ char buf[32];
+ float mpeak = level_meter->update_meters();
+
+ if (mpeak > max_peak) {
+ max_peak = mpeak;
+ if (mpeak <= -200.0f) {
+ peak_display.set_label (_("-inf"));
+ } else {
+ snprintf (buf, sizeof(buf), "%.1f", mpeak);
+ peak_display.set_label (buf);
+ }
+
+ if (mpeak >= 0.0f) {
+ peak_display.set_name ("MixerStripPeakDisplayPeak");
+ }
+ }
+}
+
+void GainMeterBase::color_handler(bool dpi)
+{
+ color_changed = true;
+ dpi_changed = (dpi) ? true : false;
+ setup_meters();
+}
+
+void
+GainMeterBase::set_width (Width w, int len)
+{
+ _width = w;
+ level_meter->setup_meters (len);
+}
+
+
+void
+GainMeterBase::on_theme_changed()
+{
+ style_changed = true;
+}
+
+GainMeter::GainMeter (Session* s, int fader_length)
+ : GainMeterBase (s, slider, false, fader_length)
+{
+ gain_display_box.set_homogeneous (true);
+ gain_display_box.set_spacing (2);
+ gain_display_box.pack_start (gain_display, true, true);
+
+ meter_metric_area.set_name ("AudioTrackMetrics");
+ set_size_request_to_display_given_text (meter_metric_area, "-127", 0, 0);
+
+ gain_automation_style_button.set_name ("MixerAutomationModeButton");
+ gain_automation_state_button.set_name ("MixerAutomationPlaybackButton");
+
+ ARDOUR_UI::instance()->set_tip (gain_automation_state_button, _("Fader automation mode"));
+ ARDOUR_UI::instance()->set_tip (gain_automation_style_button, _("Fader automation type"));
+
+ gain_automation_style_button.unset_flags (Gtk::CAN_FOCUS);
+ gain_automation_state_button.unset_flags (Gtk::CAN_FOCUS);
+
+ gain_automation_state_button.set_size_request(15, 15);
+ gain_automation_style_button.set_size_request(15, 15);
+
+ fader_vbox = manage (new Gtk::VBox());
+ fader_vbox->set_spacing (0);
+ fader_vbox->pack_start (*gain_slider, false, false, 0);
+
+ hbox.set_spacing (2);
+ hbox.pack_start (*fader_vbox, false, false, 4);
+
+ set_spacing (2);
+
+ pack_start (gain_display_box, Gtk::PACK_SHRINK);
+ pack_start (hbox, Gtk::PACK_SHRINK);
+
+ meter_metric_area.signal_expose_event().connect (sigc::mem_fun(*this, &GainMeter::meter_metrics_expose));
+}
+
+void
+GainMeter::set_controls (boost::shared_ptr<Route> r,
+ boost::shared_ptr<PeakMeter> meter,
+ boost::shared_ptr<Amp> amp)
+{
+ if (level_meter->get_parent()) {
+ hbox.remove (*level_meter);
+ }
+
+ 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), ui_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 (*level_meter, 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;
+}
+
+Glib::RefPtr<Gdk::Pixmap>
+GainMeter::render_metrics (Gtk::Widget& w, vector<DataType> types)
+{
+ Glib::RefPtr<Gdk::Window> win (w.get_window());
+ Glib::RefPtr<Gdk::GC> bg_gc (w.get_style()->get_bg_gc (Gtk::STATE_NORMAL));
+
+ gint width, height;
+ win->get_size (width, height);
+
+ Glib::RefPtr<Gdk::Pixmap> pixmap = Gdk::Pixmap::create (win, width, height);
+
+ metric_pixmaps[w.get_name()] = pixmap;
+
+ pixmap->draw_rectangle (bg_gc, true, 0, 0, width, height);
+
+ Glib::RefPtr<Pango::Layout> layout = w.create_pango_layout ("");
+
+ for (vector<DataType>::const_iterator i = types.begin(); i != types.end(); ++i) {
+
+ Glib::RefPtr<Gdk::GC> fg_gc (w.get_style()->get_fg_gc (Gtk::STATE_NORMAL));
+
+ 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.set_rgb_p (1, 1, 1);
+ break;
+ case DataType::MIDI:
+ c.set_rgb_p (0.2, 0.2, 0.5);
+ break;
+ }
+
+ fg_gc->set_rgb_fg_color (c);
+ }
+
+ 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);
+
+ snprintf (buf, sizeof (buf), "%d", abs (*j));
+
+ layout->set_text (buf);
+
+ /* we want logical extents, not ink extents here */
+
+ int tw, th;
+ layout->get_pixel_size (tw, th);
+
+ pixmap->draw_line (fg_gc, 0, pos, 4, pos);
+
+ int p = pos - (th / 2);
+ p = min (p, height - th);
+ p = max (p, 0);
+
+ pixmap->draw_layout (fg_gc, 6, p, layout);
+ }
+ }
+
+ return pixmap;
+}
+
+gint
+GainMeter::meter_metrics_expose (GdkEventExpose *ev)
+{
+ Glib::RefPtr<Gdk::Window> win (meter_metric_area.get_window());
+ Glib::RefPtr<Gdk::GC> bg_gc (meter_metric_area.get_style()->get_bg_gc (Gtk::STATE_INSENSITIVE));
+ GdkRectangle base_rect;
+ GdkRectangle draw_rect;
+ gint width, height;
+
+ win->get_size (width, height);
+
+ base_rect.width = width;
+ base_rect.height = height;
+ base_rect.x = 0;
+ base_rect.y = 0;
+
+ Glib::RefPtr<Gdk::Pixmap> pixmap;
+ std::map<string,Glib::RefPtr<Gdk::Pixmap> >::iterator i = metric_pixmaps.find (meter_metric_area.get_name());
+
+ if (i == metric_pixmaps.end() || style_changed || dpi_changed) {
+ pixmap = render_metrics (meter_metric_area, _types);
+ } else {
+ pixmap = i->second;
+ }
+
+ gdk_rectangle_intersect (&ev->area, &base_rect, &draw_rect);
+ win->draw_drawable (bg_gc, pixmap, draw_rect.x, draw_rect.y, draw_rect.x, draw_rect.y, draw_rect.width, draw_rect.height);
+ style_changed = false;
+ return true;
+}
+
+boost::shared_ptr<PBD::Controllable>
+GainMeterBase::get_controllable()
+{
+ if (_amp) {
+ return _amp->gain_control();
+ } else {
+ return boost::shared_ptr<PBD::Controllable>();