X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fmeter_strip.cc;h=1f22222293c7e2c59151e1db9e1dd8f92d6406b0;hb=184fd983d013c7c2eb73b0521212b576a6ee1147;hp=956a89c4703db7bd04da621e4e5e62b0457b1775;hpb=2d0309c09289ec014bd4fa847da4eee3dc92babd;p=ardour.git diff --git a/gtk2_ardour/meter_strip.cc b/gtk2_ardour/meter_strip.cc index 956a89c470..1f22222293 100644 --- a/gtk2_ardour/meter_strip.cc +++ b/gtk2_ardour/meter_strip.cc @@ -30,16 +30,20 @@ #include "ardour/midi_track.h" #include +#include #include +#include #include "ardour_ui.h" #include "global_signals.h" #include "logmeter.h" #include "gui_thread.h" #include "ardour_window.h" +#include "utils.h" #include "meterbridge.h" #include "meter_strip.h" +#include "meter_patterns.h" #include "i18n.h" @@ -48,65 +52,58 @@ using namespace PBD; using namespace Gtk; using namespace Gtkmm2ext; using namespace std; +using namespace ArdourMeter; PBD::Signal1 MeterStrip::CatchDeletion; +PBD::Signal0 MeterStrip::MetricChanged; +PBD::Signal0 MeterStrip::ConfigurationChanged; -MeterStrip::MetricPatterns MeterStrip::metric_patterns; -MeterStrip::TickPatterns MeterStrip::ticks_patterns; - -MeterStrip::MeterStrip (int metricmode) +MeterStrip::MeterStrip (int metricmode, MeterType mt) : AxisView(0) , RouteUI(0) { level_meter = 0; - set_spacing(2); - peakbx.set_size_request(-1, 16); - btnbox.set_size_request(-1, 16); + _strip_type = 0; + _tick_bar = 0; + mtr_vbox.set_spacing(2); + nfo_vbox.set_spacing(2); + peakbx.set_size_request(-1, 14); + namebx.set_size_request(18, 52); + spacer.set_size_request(-1,0); - _types.clear (); - switch(metricmode) { - case 1: - meter_metric_area.set_name ("AudioBusMetrics"); - _types.push_back (DataType::AUDIO); - break; - case 2: - meter_metric_area.set_name ("AudioTrackMetrics"); - _types.push_back (DataType::AUDIO); - break; - case 3: - meter_metric_area.set_name ("MidiTrackMetrics"); - _types.push_back (DataType::MIDI); - break; - default: - meter_metric_area.set_name ("AudioMidiTrackMetrics"); - _types.push_back (DataType::AUDIO); - _types.push_back (DataType::MIDI); - break; - } - //meter_metric_area.queue_draw (); + set_metric_mode(metricmode, mt); - set_size_request_to_display_given_text (meter_metric_area, "8888", 1, 0); + meter_metric_area.set_size_request(25, 10); meter_metric_area.signal_expose_event().connect ( sigc::mem_fun(*this, &MeterStrip::meter_metrics_expose)); + RedrawMetrics.connect (sigc::mem_fun(*this, &MeterStrip::redraw_metrics)); meterbox.pack_start(meter_metric_area, true, false); - label.set_text(""); - label.set_name("MeterbridgeLabel"); - label.set_angle(90.0); - label.set_alignment(0.5, 1.0); - label.set_size_request(12, 52); + mtr_vbox.pack_start (peakbx, false, false); + mtr_vbox.pack_start (meterbox, true, true); + mtr_vbox.pack_start (spacer, false, false); + mtr_container.add(mtr_vbox); + + mtr_hsep.set_size_request(-1,1); + mtr_hsep.set_name("BlackSeparator"); + + nfo_vbox.pack_start (mtr_hsep, false, false); + nfo_vbox.pack_start (btnbox, false, false); + nfo_vbox.pack_start (namebx, false, false); - pack_start (peakbx, false, false); - pack_start (meterbox, true, true); - pack_start (btnbox, false, false); - pack_start (label, false, false, 2); + pack_start (mtr_container, true, true); + pack_start (nfo_vbox, false, false); peakbx.show(); btnbox.show(); - label.show(); meter_metric_area.show(); meterbox.show(); + spacer.show(); + mtr_vbox.show(); + mtr_container.show(); + mtr_hsep.show(); + nfo_vbox.show(); UI::instance()->theme_changed.connect (sigc::mem_fun(*this, &MeterStrip::on_theme_changed)); ColorsChanged.connect (sigc::mem_fun (*this, &MeterStrip::on_theme_changed)); @@ -117,9 +114,15 @@ MeterStrip::MeterStrip (Session* sess, boost::shared_ptr rt) : AxisView(sess) , RouteUI(sess) , _route(rt) + , peak_display() { - set_spacing(2); + mtr_vbox.set_spacing(2); + nfo_vbox.set_spacing(2); RouteUI::set_route (rt); + SessionHandlePtr::set_session (sess); + + _has_midi = false; + _tick_bar = 0; int meter_width = 6; if (_route->shared_peak_meter()->input_streams().n_total() == 1) { @@ -127,62 +130,118 @@ MeterStrip::MeterStrip (Session* sess, boost::shared_ptr rt) } // level meter + ticks - level_meter = new LevelMeter(sess); + level_meter = new LevelMeterHBox(sess); level_meter->set_meter (_route->shared_peak_meter().get()); level_meter->clear_meters(); - level_meter->setup_meters (400, meter_width, 6); + level_meter->set_type (_route->meter_type()); + level_meter->setup_meters (220, meter_width, 6); + level_meter->ButtonPress.connect_same_thread (level_meter_connection, boost::bind (&MeterStrip::level_meter_button_press, this, _1)); + level_meter->MeterTypeChanged.connect_same_thread (level_meter_connection, boost::bind (&MeterStrip::meter_type_changed, this, _1)); - Gtk::Alignment *meter_align = Gtk::manage (new Gtk::Alignment()); - meter_align->set(0.5, 0.5, 0.0, 1.0); - meter_align->add(*level_meter); + meter_align.set(0.5, 0.5, 0.0, 1.0); + meter_align.add(*level_meter); meterbox.pack_start(meter_ticks1_area, true, false); - meterbox.pack_start(*meter_align, true, true); + meterbox.pack_start(meter_align, true, true); meterbox.pack_start(meter_ticks2_area, true, false); // peak display - peak_display.set_name ("MixerStripPeakDisplay"); - set_size_request_to_display_given_text (peak_display, "-80.g", 2, 6); + peak_display.set_name ("meterbridge peakindicator"); + peak_display.set_elements((ArdourButton::Element) (ArdourButton::Edge|ArdourButton::Body)); max_peak = minus_infinity(); - peak_display.set_label (_("-inf")); peak_display.unset_flags (Gtk::CAN_FOCUS); - - peakbx.pack_start(peak_display, true, true); - peakbx.set_size_request(-1, 16); - - // add track-name label -- TODO ellipsize - label.set_text(_route->name().c_str()); - label.set_name("MeterbridgeLabel"); - label.set_angle(90.0); - label.set_alignment(0.5, 1.0); - label.set_size_request(12, 52); - - // rec-enable button - btnbox.pack_start(*rec_enable_button, true, false); - btnbox.set_size_request(-1, 16); - - pack_start (peakbx, false, false); - pack_start (meterbox, true, true); - pack_start (btnbox, false, false); - pack_start (label, false, false, 2); - + peak_display.set_size_request(12, 8); + peak_display.set_corner_radius(2); + + peak_align.set(0.5, 1.0, 1.0, 0.8); + peak_align.add(peak_display); + peakbx.pack_start(peak_align, true, true, 3); + peakbx.set_size_request(-1, 14); + + // add track-name label + name_label.set_text(_route->name()); + name_label.set_corner_radius(2); + name_label.set_name("meterbridge label"); + name_label.set_angle(-90.0); + name_label.layout()->set_ellipsize (Pango::ELLIPSIZE_END); + name_label.layout()->set_width(48 * PANGO_SCALE); + name_label.set_size_request(18, 50); + name_label.set_alignment(-1.0, .5); + ARDOUR_UI::instance()->set_tip (name_label, _route->name()); + + namebx.set_size_request(18, 52); + namebx.pack_start(name_label, true, false, 3); + + recbox.pack_start(*rec_enable_button, true, false); + btnbox.pack_start(recbox, false, false, 1); + mutebox.pack_start(*mute_button, true, false); + btnbox.pack_start(mutebox, false, false, 1); + solobox.pack_start(*solo_button, true, false); + btnbox.pack_start(solobox, false, false, 1); + + rec_enable_button->set_corner_radius(2); + rec_enable_button->set_size_request(16, 16); + + mute_button->set_corner_radius(2); + mute_button->set_size_request(16, 16); + + solo_button->set_corner_radius(2); + solo_button->set_size_request(16, 16); + + mutebox.set_size_request(16, 16); + solobox.set_size_request(16, 16); + recbox.set_size_request(16, 16); + spacer.set_size_request(-1,0); + + update_button_box(); + update_name_box(); + update_background (_route->meter_type()); + + mtr_vbox.pack_start (peakbx, false, false); + mtr_vbox.pack_start (meterbox, true, true); + mtr_vbox.pack_start (spacer, false, false); + mtr_container.add(mtr_vbox); + + mtr_hsep.set_size_request(-1,1); + mtr_hsep.set_name("BlackSeparator"); + + nfo_vbox.pack_start (mtr_hsep, false, false); + nfo_vbox.pack_start (btnbox, false, false); + nfo_vbox.pack_start (namebx, false, false); + + pack_start (mtr_container, true, true); + pack_start (nfo_vbox, false, false); + + name_label.show(); peak_display.show(); peakbx.show(); meter_ticks1_area.show(); meter_ticks2_area.show(); meterbox.show(); + spacer.show(); level_meter->show(); - meter_align->show(); + meter_align.show(); + peak_align.show(); btnbox.show(); - label.show(); + mtr_vbox.show(); + mtr_container.show(); + mtr_hsep.show(); + nfo_vbox.show(); _route->shared_peak_meter()->ConfigurationChanged.connect ( route_connections, invalidator (*this), boost::bind (&MeterStrip::meter_configuration_changed, this, _1), gui_context() ); + + ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &MeterStrip::reset_peak_display)); + ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &MeterStrip::reset_route_peak_display)); + ResetGroupPeakDisplays.connect (sigc::mem_fun(*this, &MeterStrip::reset_group_peak_display)); + RedrawMetrics.connect (sigc::mem_fun(*this, &MeterStrip::redraw_metrics)); + SetMeterTypeMulti.connect (sigc::mem_fun(*this, &MeterStrip::set_meter_type_multi)); + meter_configuration_changed (_route->shared_peak_meter()->input_streams ()); - meter_ticks1_area.set_size_request(4,-1); - meter_ticks2_area.set_size_request(4,-1); + meter_ticks1_area.set_size_request(3,-1); + meter_ticks2_area.set_size_request(3,-1); meter_ticks1_area.signal_expose_event().connect (sigc::mem_fun(*this, &MeterStrip::meter_ticks1_expose)); meter_ticks2_area.signal_expose_event().connect (sigc::mem_fun(*this, &MeterStrip::meter_ticks2_expose)); @@ -194,6 +253,23 @@ MeterStrip::MeterStrip (Session* sess, boost::shared_ptr rt) UI::instance()->theme_changed.connect (sigc::mem_fun(*this, &MeterStrip::on_theme_changed)); ColorsChanged.connect (sigc::mem_fun (*this, &MeterStrip::on_theme_changed)); DPIReset.connect (sigc::mem_fun (*this, &MeterStrip::on_theme_changed)); + Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&MeterStrip::parameter_changed, this, _1), gui_context()); + sess->config.ParameterChanged.connect (*this, invalidator (*this), ui_bind (&MeterStrip::parameter_changed, this, _1), gui_context()); + + if (_route->is_master()) { + _strip_type = 4; + } + else if (boost::dynamic_pointer_cast(_route) == 0 + && boost::dynamic_pointer_cast(_route) == 0) { + /* non-master bus */ + _strip_type = 3; + } + else if (boost::dynamic_pointer_cast(_route)) { + _strip_type = 2; + } + else { + _strip_type = 1; + } } MeterStrip::~MeterStrip () @@ -208,6 +284,16 @@ MeterStrip::self_delete () delete this; } +void +MeterStrip::set_session (Session* s) +{ + SessionHandlePtr::set_session (s); + if (!s) return; + s->config.ParameterChanged.connect (*this, invalidator (*this), ui_bind (&MeterStrip::parameter_changed, this, _1), gui_context()); + update_button_box(); + update_name_box(); +} + void MeterStrip::update_rec_display () { @@ -223,7 +309,28 @@ MeterStrip::state_id() const void MeterStrip::set_button_names() { - rec_enable_button->set_text (_("R")); + mute_button->set_text (_("M")); + rec_enable_button->set_text (""); + rec_enable_button->set_image (::get_icon (X_("record_normal_red"))); + + if (_route && _route->solo_safe()) { + solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive)); + } else { + solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive)); + } + if (!Config->get_solo_control_is_listen_control()) { + solo_button->set_text (_("S")); + } else { + switch (Config->get_listen_position()) { + case AfterFaderListen: + solo_button->set_text (_("A")); + break; + case PreFaderListen: + solo_button->set_text (_("P")); + break; + } + } + } void @@ -233,53 +340,32 @@ MeterStrip::strip_property_changed (const PropertyChange& what_changed) return; } ENSURE_GUI_THREAD (*this, &MeterStrip::strip_name_changed, what_changed) - label.set_text(_route->name()); + name_label.set_text(_route->name()); + ARDOUR_UI::instance()->set_tip (name_label, _route->name()); } void MeterStrip::fast_update () { - 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 >= Config->get_meter_peak()) { + peak_display.set_name ("meterbridge peakindicator on"); + peak_display.set_elements((ArdourButton::Element) (ArdourButton::Edge|ArdourButton::Body)); } - - if (mpeak >= 0.0f) { - peak_display.set_name ("MixerStripPeakDisplayPeak"); - } - } -} - -void -MeterStrip::display_metrics (bool show) -{ -#if 0 - if (show) { - meter_metric_area.show(); - } else { - meter_metric_area.hide(); } -#endif } void MeterStrip::on_theme_changed() { - metric_patterns.clear(); - ticks_patterns.clear(); - if (level_meter && _route) { int meter_width = 6; if (_route->shared_peak_meter()->input_streams().n_total() == 1) { meter_width = 12; } - level_meter->setup_meters (400, meter_width, 6); + level_meter->setup_meters (220, meter_width, 6); } } @@ -288,6 +374,7 @@ MeterStrip::meter_configuration_changed (ChanCount c) { int type = 0; _types.clear (); + bool old_has_midi = _has_midi; for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) { if (c.get (*i) > 0) { @@ -296,465 +383,175 @@ MeterStrip::meter_configuration_changed (ChanCount c) } } - // TODO draw Inactive routes or busses with different styles if (boost::dynamic_pointer_cast(_route) == 0 && boost::dynamic_pointer_cast(_route) == 0 ) { - meter_ticks1_area.set_name ("AudioBusMetrics"); - meter_ticks2_area.set_name ("AudioBusMetrics"); + meter_ticks1_area.set_name ("MyAudioBusMetricsLeft"); + meter_ticks2_area.set_name ("MyAudioBusMetricsRight"); + _has_midi = false; } else if (type == (1 << DataType::AUDIO)) { - meter_ticks1_area.set_name ("AudioTrackMetrics"); - meter_ticks2_area.set_name ("AudioTrackMetrics"); + meter_ticks1_area.set_name ("MyAudioTrackMetricsLeft"); + meter_ticks2_area.set_name ("MyAudioTrackMetricsRight"); + _has_midi = false; } else if (type == (1 << DataType::MIDI)) { - meter_ticks1_area.set_name ("MidiTrackMetrics"); - meter_ticks2_area.set_name ("MidiTrackMetrics"); + meter_ticks1_area.set_name ("MidiTrackMetricsLeft"); + meter_ticks2_area.set_name ("MidiTrackMetricsRight"); + _has_midi = true; } else { - meter_ticks1_area.set_name ("AudioMidiTrackMetrics"); - meter_ticks2_area.set_name ("AudioMidiTrackMetrics"); + meter_ticks1_area.set_name ("AudioMidiTrackMetricsLeft"); + meter_ticks2_area.set_name ("AudioMidiTrackMetricsRight"); + _has_midi = true; } - meter_ticks1_area.queue_draw(); - meter_ticks2_area.queue_draw(); - metric_patterns.clear(); - ticks_patterns.clear(); -} + set_tick_bar(_tick_bar); -void -MeterStrip::on_size_request (Gtk::Requisition* r) -{ - metric_patterns.clear(); - ticks_patterns.clear(); - VBox::on_size_request(r); + on_theme_changed(); + if (old_has_midi != _has_midi) MetricChanged(); + else ConfigurationChanged(); } void -MeterStrip::on_size_allocate (Gtk::Allocation& a) +MeterStrip::set_tick_bar (int m) { - metric_patterns.clear(); - ticks_patterns.clear(); - VBox::on_size_allocate(a); -} - -/* XXX code-copy from gain_meter.cc -- TODO consolidate - * - * slightly different: - * - ticks & label positions are swapped - * - more ticks for audio (longer meter by default) - * - right-aligned lables, unit-legend - * - height limitation of FastMeter::max_pattern_metric_size is included here - */ -cairo_pattern_t* -MeterStrip::render_metrics (Gtk::Widget& w, vector types) -{ - Glib::RefPtr 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); - Glib::RefPtr layout = Pango::Layout::create(w.get_pango_context()); - - - Pango::AttrList audio_font_attributes; - Pango::AttrList midi_font_attributes; - Pango::AttrList unit_font_attributes; - - Pango::AttrFontDesc* font_attr; - Pango::FontDescription font; - - font = Pango::FontDescription (""); // use defaults - //font = get_font_for_style("gain-fader"); - //font = w.get_style()->get_font(); - - font.set_weight (Pango::WEIGHT_NORMAL); - font.set_size (9.0 * PANGO_SCALE); - font_attr = new Pango::AttrFontDesc (Pango::Attribute::create_attr_font_desc (font)); - audio_font_attributes.change (*font_attr); - delete font_attr; - - font.set_weight (Pango::WEIGHT_ULTRALIGHT); - font.set_stretch (Pango::STRETCH_ULTRA_CONDENSED); - font.set_size (7.5 * PANGO_SCALE); - font_attr = new Pango::AttrFontDesc (Pango::Attribute::create_attr_font_desc (font)); - midi_font_attributes.change (*font_attr); - delete font_attr; - - font.set_size (7.0 * PANGO_SCALE); - font_attr = new Pango::AttrFontDesc (Pango::Attribute::create_attr_font_desc (font)); - unit_font_attributes.change (*font_attr); - delete font_attr; - - 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); - - height = min(1024, height); // XXX see FastMeter::max_pattern_metric_size - - for (vector::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()); + std::string n; + _tick_bar = m; + if (_tick_bar & 1) { + n = meter_ticks1_area.get_name(); + if (n.substr(0,3) != "Bar") { + meter_ticks1_area.set_name("Bar" + n); } - - vector points; - - switch (*i) { - case DataType::AUDIO: - layout->set_attributes (audio_font_attributes); - points.push_back (-50); - points.push_back (-40); - points.push_back (-30); - points.push_back (-25); - points.push_back (-20); - points.push_back (-18); - points.push_back (-15); - points.push_back (-10); - points.push_back (-5); - points.push_back (-3); - points.push_back (0); - points.push_back (3); - break; - - case DataType::MIDI: - layout->set_attributes (midi_font_attributes); - 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); - } - if (types.size() == 1) { - points.push_back (64); // very close to -18dB - points.push_back (96); // overlays with -6dB mark - } else { - points.push_back (72); - points.push_back (88); - } - points.push_back (127); - break; - } - - char buf[32]; - - for (vector::const_iterator j = points.begin(); j != points.end(); ++j) { - - float fraction = 0; - switch (*i) { - case DataType::AUDIO: - fraction = log_meter (*j); - snprintf (buf, sizeof (buf), "%+2d", *j); - break; - case DataType::MIDI: - fraction = *j / 127.0; - snprintf (buf, sizeof (buf), "%3d", *j); - break; - } - - gint const pos = height - (gint) floor (height * fraction); - layout->set_text(buf); - - /* we want logical extents, not ink extents here */ - - int tw, th; - layout->get_pixel_size(tw, th); - - int p = pos - (th / 2); - p = min (p, height - th); - p = max (p, 0); - - cairo_move_to (cr, width-1-tw, p + .5); - pango_cairo_show_layout (cr, layout->gobj()); + } else { + n = meter_ticks1_area.get_name(); + if (n.substr(0,3) == "Bar") { + meter_ticks1_area.set_name(n.substr(3,-1)); } } - - if (types.size() == 1) { - int tw, th; - layout->set_attributes (unit_font_attributes); - switch (types.at(0)) { - case DataType::AUDIO: - layout->set_text("dBFS"); - layout->get_pixel_size(tw, th); - break; - case DataType::MIDI: - layout->set_text("vel"); - layout->get_pixel_size(tw, th); - break; + if (_tick_bar & 2) { + n = meter_ticks2_area.get_name(); + if (n.substr(0,3) != "Bar") { + meter_ticks2_area.set_name("Bar" + n); + } + } else { + n = meter_ticks2_area.get_name(); + if (n.substr(0,3) == "Bar") { + meter_ticks2_area.set_name(n.substr(3,-1)); } - Gdk::Color 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()); - cairo_move_to (cr, 1, height - th); - pango_cairo_show_layout (cr, layout->gobj()); } +} - cairo_pattern_t* pattern = cairo_pattern_create_for_surface (surface); - MetricPatterns::iterator p; +void +MeterStrip::on_size_request (Gtk::Requisition* r) +{ + VBox::on_size_request(r); +} - if ((p = metric_patterns.find (w.get_name())) != metric_patterns.end()) { - cairo_pattern_destroy (p->second); +void +MeterStrip::on_size_allocate (Gtk::Allocation& a) +{ + const int wh = a.get_height(); + int nh = ceilf(wh * .11f); + if (nh < 52) nh = 52; + if (nh > 148) nh = 148; + namebx.set_size_request(18, nh); + if (_route) { + name_label.set_size_request(18, nh-2); + name_label.layout()->set_width((nh-4) * PANGO_SCALE); } - - metric_patterns[w.get_name()] = pattern; - - cairo_destroy (cr); - cairo_surface_destroy (surface); - - return pattern; + VBox::on_size_allocate(a); } -/* XXX code-copy from gain_meter.cc -- TODO consolidate */ gint MeterStrip::meter_metrics_expose (GdkEventExpose *ev) { - Glib::RefPtr win (meter_metric_area.get_window()); - cairo_t* cr; - - cr = gdk_cairo_create (win->gobj()); - - /* clip to expose area */ - - gdk_cairo_rectangle (cr, &ev->area); - cairo_clip (cr); - - cairo_pattern_t* pattern; - MetricPatterns::iterator i = metric_patterns.find (meter_metric_area.get_name()); - - if (i == metric_patterns.end()) { - pattern = render_metrics (meter_metric_area, _types); + if (_route) { + return meter_expose_metrics(ev, _route->meter_type(), _types, &meter_metric_area); } else { - pattern = i->second; + return meter_expose_metrics(ev, metric_type, _types, &meter_metric_area); } - - cairo_move_to (cr, 0, 0); - cairo_set_source (cr, pattern); - - gint width, height; - win->get_size (width, height); - - cairo_rectangle (cr, 0, 0, width, height); - cairo_fill (cr); - - cairo_destroy (cr); - - return true; } -cairo_pattern_t* -MeterStrip::render_ticks (Gtk::Widget& w, vector types) +void +MeterStrip::set_metric_mode (int metricmode, ARDOUR::MeterType mt) { - Glib::RefPtr 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); - - 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); - - height = min(1024, height); // XXX see FastMeter::max_pattern_metric_size - - for (vector::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()); - } - - std::map points; - - switch (*i) { - case DataType::AUDIO: - points.insert (std::pair(-60, 0.5)); - points.insert (std::pair(-50, 0.5)); - points.insert (std::pair(-40, 0.5)); - points.insert (std::pair(-30, 0.5)); - points.insert (std::pair(-25, 0.5)); - points.insert (std::pair(-20, 1.0)); - - points.insert (std::pair(-19, 0.5)); - points.insert (std::pair(-18, 1.0)); - points.insert (std::pair(-17, 0.5)); - points.insert (std::pair(-16, 0.5)); - points.insert (std::pair(-15, 1.0)); - - points.insert (std::pair(-14, 0.5)); - points.insert (std::pair(-13, 0.5)); - points.insert (std::pair(-12, 0.5)); - points.insert (std::pair(-11, 0.5)); - points.insert (std::pair(-10, 1.0)); - - points.insert (std::pair( -9, 0.5)); - points.insert (std::pair( -8, 0.5)); - points.insert (std::pair( -7, 0.5)); - points.insert (std::pair( -6, 0.5)); - points.insert (std::pair( -5, 1.0)); - points.insert (std::pair( -4, 0.5)); - points.insert (std::pair( -3, 0.5)); - points.insert (std::pair( -2, 0.5)); - points.insert (std::pair( -1, 0.5)); - - points.insert (std::pair( 0, 1.0)); - points.insert (std::pair( 1, 0.5)); - points.insert (std::pair( 2, 0.5)); - points.insert (std::pair( 3, 0.5)); - points.insert (std::pair( 4, 0.5)); - points.insert (std::pair( 5, 0.5)); - points.insert (std::pair( 6, 0.5)); + metric_type = mt; + _types.clear (); + switch(metricmode) { + case 0: + meter_metric_area.set_name ("MidiTrackMetricsLeft"); + _types.push_back (DataType::MIDI); break; - - case DataType::MIDI: - points.insert (std::pair( 0, 1.0)); - points.insert (std::pair( 16, 0.5)); - points.insert (std::pair( 32, 0.5)); - points.insert (std::pair( 48, 0.5)); - points.insert (std::pair( 64, 1.0)); - points.insert (std::pair( 72, 0.5)); - points.insert (std::pair( 96, 0.5)); - points.insert (std::pair(100, 1.0)); - points.insert (std::pair(112, 0.5)); - points.insert (std::pair(127, 1.0)); + case 1: + meter_metric_area.set_name ("AudioTrackMetricsLeft"); + _types.push_back (DataType::AUDIO); + break; + case 2: + meter_metric_area.set_name ("MidiTrackMetricsRight"); + _types.push_back (DataType::MIDI); + break; + case 3: + default: + meter_metric_area.set_name ("AudioTrackMetricsRight"); + _types.push_back (DataType::AUDIO); break; - } - - for (std::map::const_iterator j = points.begin(); j != points.end(); ++j) { - cairo_set_line_width (cr, (j->second)); - - float fraction = 0; - gint pos; - - switch (*i) { - case DataType::AUDIO: - if (j->first >= 0) { - cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); - } - fraction = log_meter (j->first); - pos = height - (gint) floor (height * fraction); - cairo_move_to(cr, 0, pos + .5); - cairo_line_to(cr, 4, pos + .5); - cairo_stroke (cr); - break; - case DataType::MIDI: - fraction = (j->first) / 127.0; - pos = height - (gint) floor (height * fraction); - cairo_arc(cr, 2, pos, (j->second), 0, 2 * M_PI); - cairo_fill_preserve(cr); - cairo_stroke (cr); - break; - } - } } + update_background (mt); + meter_metric_area.queue_draw (); +} - cairo_pattern_t* pattern = cairo_pattern_create_for_surface (surface); - TickPatterns::iterator p; - - if ((p = ticks_patterns.find (w.get_name())) != metric_patterns.end()) { - cairo_pattern_destroy (p->second); +void +MeterStrip::update_background(MeterType type) +{ + switch(type) { + case MeterIEC1DIN: + case MeterIEC1NOR: + case MeterIEC2BBC: + case MeterIEC2EBU: + case MeterK14: + case MeterK20: + mtr_container.set_name ("meterstripPPM"); + break; + case MeterVU: + mtr_container.set_name ("meterstripVU"); + break; + default: + mtr_container.set_name ("meterstripDPM"); } +} - ticks_patterns[w.get_name()] = pattern; - - cairo_destroy (cr); - cairo_surface_destroy (surface); - - return pattern; +MeterType +MeterStrip::meter_type() +{ + assert((!_route && _strip_type == 0) || (_route && _strip_type != 0)); + if (!_route) return metric_type; + return _route->meter_type(); } gint MeterStrip::meter_ticks1_expose (GdkEventExpose *ev) { - return meter_ticks_expose(ev, &meter_ticks1_area); + assert(_route); + return meter_expose_ticks(ev, _route->meter_type(), _types, &meter_ticks1_area); } gint MeterStrip::meter_ticks2_expose (GdkEventExpose *ev) { - return meter_ticks_expose(ev, &meter_ticks2_area); + assert(_route); + return meter_expose_ticks(ev, _route->meter_type(), _types, &meter_ticks2_area); } -gint -MeterStrip::meter_ticks_expose (GdkEventExpose *ev, Gtk::DrawingArea *mta) +void +MeterStrip::reset_route_peak_display (Route* route) { - Glib::RefPtr win (mta->get_window()); - cairo_t* cr; - - cr = gdk_cairo_create (win->gobj()); - - /* clip to expose area */ - - gdk_cairo_rectangle (cr, &ev->area); - cairo_clip (cr); - - cairo_pattern_t* pattern; - TickPatterns::iterator i = ticks_patterns.find (mta->get_name()); - - if (i == ticks_patterns.end()) { - pattern = render_ticks (*mta, _types); - } else { - pattern = i->second; + if (_route && _route.get() == route) { + reset_peak_display (); } - - cairo_move_to (cr, 0, 0); - cairo_set_source (cr, pattern); - - gint width, height; - win->get_size (width, height); - - cairo_rectangle (cr, 0, 0, width, height); - cairo_fill (cr); - - cairo_destroy (cr); - - return true; } void MeterStrip::reset_group_peak_display (RouteGroup* group) { - /* UNUSED -- need connection w/mixer || other meters */ if (_route && group == _route->route_group()) { reset_peak_display (); } @@ -766,13 +563,181 @@ MeterStrip::reset_peak_display () _route->shared_peak_meter()->reset_max(); level_meter->clear_meters(); max_peak = -INFINITY; - peak_display.set_label (_("-inf")); - peak_display.set_name ("MixerStripPeakDisplay"); + peak_display.set_name ("meterbridge peakindicator"); + peak_display.set_elements((ArdourButton::Element) (ArdourButton::Edge|ArdourButton::Body)); } bool MeterStrip::peak_button_release (GdkEventButton* ev) { - reset_peak_display (); + if (ev->button == 1 && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier|Keyboard::TertiaryModifier)) { + ResetAllPeakDisplays (); + } else if (ev->button == 1 && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) { + if (_route) { + ResetGroupPeakDisplays (_route->route_group()); + } + } else { + ResetRoutePeakDisplays (_route.get()); + } return true; } + +void +MeterStrip::redraw_metrics () +{ + meter_metric_area.queue_draw(); + meter_ticks1_area.queue_draw(); + meter_ticks2_area.queue_draw(); +} + +void +MeterStrip::update_button_box () +{ + if (!_session) return; + int height = 0; + if (_session->config.get_show_mute_on_meterbridge()) { + height += 18; + mutebox.show(); + } else { + mutebox.hide(); + } + if (_session->config.get_show_solo_on_meterbridge()) { + height += 18; + solobox.show(); + } else { + solobox.hide(); + } + if (_session->config.get_show_rec_on_meterbridge()) { + height += 18; + recbox.show(); + } else { + recbox.hide(); + } + btnbox.set_size_request(16, height); + check_resize(); +} + +void +MeterStrip::update_name_box () +{ + if (!_session) return; + if (_session->config.get_show_name_on_meterbridge()) { + namebx.show(); + } else { + namebx.hide(); + } +} + +void +MeterStrip::parameter_changed (std::string const & p) +{ + if (p == "meter-peak") { + max_peak = -INFINITY; + } + else if (p == "show-rec-on-meterbridge") { + update_button_box(); + } + else if (p == "show-mute-on-meterbridge") { + update_button_box(); + } + else if (p == "show-solo-on-meterbridge") { + update_button_box(); + } + else if (p == "show-name-on-meterbridge") { + update_name_box(); + } +} + + +bool +MeterStrip::level_meter_button_press (GdkEventButton* ev) +{ + if (ev->button == 3) { + popup_level_meter_menu (ev); + return true; + } + + return false; +} + +void +MeterStrip::popup_level_meter_menu (GdkEventButton* ev) +{ + using namespace Gtk::Menu_Helpers; + + Gtk::Menu* m = manage (new Menu); + MenuList& items = m->items (); + + RadioMenuItem::Group group; + + _suspend_menu_callbacks = true; + add_level_meter_item (items, group, ArdourMeter::meter_type_string(MeterPeak), MeterPeak); + add_level_meter_item (items, group, ArdourMeter::meter_type_string(MeterKrms), MeterKrms); + add_level_meter_item (items, group, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN); + add_level_meter_item (items, group, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR); + add_level_meter_item (items, group, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC); + add_level_meter_item (items, group, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU); + add_level_meter_item (items, group, ArdourMeter::meter_type_string(MeterK20), MeterK20); + add_level_meter_item (items, group, ArdourMeter::meter_type_string(MeterK14), MeterK14); + add_level_meter_item (items, group, ArdourMeter::meter_type_string(MeterVU), MeterVU); + + MeterType cmt = _route->meter_type(); + const std::string cmn = ArdourMeter::meter_type_string(cmt); + + items.push_back (SeparatorElem()); + items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn), + sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt))); + items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn), + sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt))); + items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn), + sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt))); + + m->popup (ev->button, ev->time); + _suspend_menu_callbacks = false; +} + +void +MeterStrip::add_level_meter_item (Menu_Helpers::MenuList& items, RadioMenuItem::Group& group, string const & name, MeterType type) +{ + using namespace Menu_Helpers; + + items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MeterStrip::set_meter_type), type))); + RadioMenuItem* i = dynamic_cast (&items.back ()); + i->set_active (_route->meter_type() == type); +} + +void +MeterStrip::set_meter_type (MeterType type) +{ + if (_suspend_menu_callbacks) return; + level_meter->set_type (type); +} + +void +MeterStrip::meter_type_changed (MeterType type) +{ + if (_route->meter_type() != type) { + _route->set_meter_type(type); + } + update_background (type); + MetricChanged(); +} + +void +MeterStrip::set_meter_type_multi (int what, RouteGroup* group, MeterType type) +{ + switch (what) { + case -1: + if (_route && group == _route->route_group()) { + level_meter->set_type (type); + } + break; + case 0: + level_meter->set_type (type); + default: + if (what == _strip_type) { + level_meter->set_type (type); + } + break; + } +}