enough with umpteen "i18n.h" files. Consolidate on pbd/i18n.h
[ardour.git] / gtk2_ardour / meter_strip.cc
1 /*
2     Copyright (C) 2013 Paul Davis
3     Author: Robin Gareus
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <list>
21
22 #include <sigc++/bind.h>
23
24 #include "ardour/session.h"
25 #include "ardour/route.h"
26 #include "ardour/route_group.h"
27 #include "ardour/meter.h"
28
29 #include "ardour/audio_track.h"
30 #include "ardour/midi_track.h"
31
32 #include <gtkmm2ext/gtk_ui.h>
33 #include <gtkmm2ext/keyboard.h>
34 #include <gtkmm2ext/utils.h>
35 #include <gtkmm2ext/rgb_macros.h>
36
37 #include "logmeter.h"
38 #include "gui_thread.h"
39 #include "ardour_window.h"
40 #include "tooltips.h"
41 #include "ui_config.h"
42 #include "utils.h"
43
44 #include "meterbridge.h"
45 #include "meter_strip.h"
46 #include "meter_patterns.h"
47
48 #include "pbd/i18n.h"
49
50 using namespace ARDOUR;
51 using namespace ARDOUR_UI_UTILS;
52 using namespace PBD;
53 using namespace Gtk;
54 using namespace Gtkmm2ext;
55 using namespace std;
56 using namespace ArdourMeter;
57
58 PBD::Signal1<void,MeterStrip*> MeterStrip::CatchDeletion;
59 PBD::Signal0<void> MeterStrip::MetricChanged;
60 PBD::Signal0<void> MeterStrip::ConfigurationChanged;
61
62 #define PX_SCALE(pxmin, dflt) rint(std::max((double)pxmin, (double)dflt * UIConfiguration::instance().get_ui_scale()))
63
64 MeterStrip::MeterStrip (int metricmode, MeterType mt)
65         : RouteUI ((Session*) 0)
66 {
67         level_meter = 0;
68         _strip_type = 0;
69         _tick_bar = 0;
70         _metricmode = -1;
71         metric_type = MeterPeak;
72
73         mtr_vbox.set_spacing (PX_SCALE(2, 2));
74         nfo_vbox.set_spacing (PX_SCALE(2, 2));
75         peakbx.set_size_request (-1, PX_SCALE(14, 14));
76         namebx.set_size_request (PX_SCALE(16, 18), PX_SCALE(32, 52));
77         spacer.set_size_request (-1,0);
78
79         set_metric_mode(metricmode, mt);
80
81         meter_metric_area.set_size_request (PX_SCALE(25, 25), 10);
82         meter_metric_area.signal_expose_event().connect (
83                         sigc::mem_fun(*this, &MeterStrip::meter_metrics_expose));
84         RedrawMetrics.connect (sigc::mem_fun(*this, &MeterStrip::redraw_metrics));
85
86         meterbox.pack_start(meter_metric_area, true, false);
87
88         mtr_vbox.pack_start (peakbx, false, false);
89         mtr_vbox.pack_start (meterbox, true, true);
90         mtr_vbox.pack_start (spacer, false, false);
91         mtr_container.add(mtr_vbox);
92
93         mtr_hsep.set_size_request (-1, 1);
94         mtr_hsep.set_name("BlackSeparator");
95
96         nfo_vbox.pack_start (mtr_hsep, false, false);
97         nfo_vbox.pack_start (btnbox, false, false);
98         nfo_vbox.pack_start (namebx, false, false);
99
100         pack_start (mtr_container, true, true);
101         pack_start (nfo_vbox, false, false);
102
103         peakbx.show();
104         btnbox.show();
105         meter_metric_area.show();
106         meterbox.show();
107         spacer.show();
108         mtr_vbox.show();
109         mtr_container.show();
110         mtr_hsep.show();
111         nfo_vbox.show();
112
113         UI::instance()->theme_changed.connect (sigc::mem_fun(*this, &MeterStrip::on_theme_changed));
114         UIConfiguration::instance().ColorsChanged.connect (sigc::mem_fun (*this, &MeterStrip::on_theme_changed));
115         UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &MeterStrip::on_theme_changed));
116 }
117
118 MeterStrip::MeterStrip (Session* sess, boost::shared_ptr<ARDOUR::Route> rt)
119         : SessionHandlePtr (sess)
120         , RouteUI(0)
121         , _route(rt)
122         , peak_display()
123 {
124         mtr_vbox.set_spacing (PX_SCALE(2, 2));
125         nfo_vbox.set_spacing (PX_SCALE(2, 2));
126         SessionHandlePtr::set_session (sess);
127         RouteUI::init ();
128         RouteUI::set_route (rt);
129
130         _has_midi = false;
131         _tick_bar = 0;
132         _metricmode = -1;
133         metric_type = MeterPeak;
134
135         // note: level_meter->setup_meters() does the scaling
136         int meter_width = 6;
137         if (_route->shared_peak_meter()->input_streams().n_total() == 1) {
138                 meter_width = 12;
139         }
140
141         // level meter + ticks
142         level_meter = new LevelMeterHBox(sess);
143         level_meter->set_meter (_route->shared_peak_meter().get());
144         level_meter->clear_meters();
145         level_meter->set_type (_route->meter_type());
146         level_meter->setup_meters (220, meter_width, 6);
147         level_meter->ButtonPress.connect_same_thread (level_meter_connection, boost::bind (&MeterStrip::level_meter_button_press, this, _1));
148         level_meter->MeterTypeChanged.connect_same_thread (level_meter_connection, boost::bind (&MeterStrip::meter_type_changed, this, _1));
149
150         meter_align.set(0.5, 0.5, 0.0, 1.0);
151         meter_align.add(*level_meter);
152
153         meterbox.pack_start(meter_ticks1_area, true, false);
154         meterbox.pack_start(meter_align, true, true);
155         meterbox.pack_start(meter_ticks2_area, true, false);
156
157         // peak display
158         peak_display.set_name ("meterbridge peakindicator");
159         peak_display.set_elements((ArdourButton::Element) (ArdourButton::Edge|ArdourButton::Body));
160         set_tooltip (peak_display, _("Reset Peak"));
161         max_peak = minus_infinity();
162         peak_display.unset_flags (Gtk::CAN_FOCUS);
163         peak_display.set_size_request(PX_SCALE(12, 12), PX_SCALE(8, 8));
164         peak_display.set_corner_radius(2); // ardour-button scales this
165
166         peak_align.set(0.5, 1.0, 1.0, 0.8);
167         peak_align.add(peak_display);
168         peakbx.pack_start(peak_align, true, true, 2);
169         peakbx.set_size_request(-1, PX_SCALE(14, 14));
170
171         // add track-name & -number label
172         number_label.set_text("-");
173         number_label.set_size_request(PX_SCALE(18, 18), PX_SCALE(18, 18));
174
175         name_changed();
176
177         name_label.set_corner_radius(2); // ardour button scales radius
178         name_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
179         name_label.set_name("meterbridge label");
180         name_label.set_angle(-90.0);
181         name_label.set_text_ellipsize (Pango::ELLIPSIZE_END);
182         name_label.set_layout_ellipsize_width(48 * PANGO_SCALE);
183         name_label.set_size_request(PX_SCALE(18, 18), PX_SCALE(50, 50));
184         name_label.set_alignment(-1.0, .5);
185         set_tooltip (name_label, _route->name());
186         set_tooltip (*level_meter, _route->name());
187
188         number_label.set_corner_radius(2);
189         number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
190         number_label.set_name("tracknumber label");
191         number_label.set_angle(-90.0);
192         number_label.set_layout_ellipsize_width(18 * PANGO_SCALE);
193         number_label.set_alignment(.5, .5);
194
195         namebx.set_size_request(PX_SCALE(18, 18), PX_SCALE(52, 52));
196         namebx.pack_start(namenumberbx, true, false, 0);
197         namenumberbx.pack_start(name_label, true, false, 0);
198         namenumberbx.pack_start(number_label, false, false, 0);
199
200         mon_in_box.pack_start(*monitor_input_button, true, false);
201         btnbox.pack_start(mon_in_box, false, false, 1);
202         mon_disk_box.pack_start(*monitor_disk_button, true, false);
203         btnbox.pack_start(mon_disk_box, false, false, 1);
204
205         recbox.pack_start(*rec_enable_button, true, false);
206         btnbox.pack_start(recbox, false, false, 1);
207         mutebox.pack_start(*mute_button, true, false);
208         btnbox.pack_start(mutebox, false, false, 1);
209         solobox.pack_start(*solo_button, true, false);
210         btnbox.pack_start(solobox, false, false, 1);
211
212         rec_enable_button->set_corner_radius(2);
213         rec_enable_button->set_size_request (PX_SCALE(18, 18), PX_SCALE(18, 18));
214
215         mute_button->set_corner_radius(2);
216         mute_button->set_size_request (PX_SCALE(18, 18), PX_SCALE(18, 18));
217
218         solo_button->set_corner_radius(2);
219         solo_button->set_size_request (PX_SCALE(18, 18), PX_SCALE(18, 18));
220
221         monitor_input_button->set_corner_radius(2);
222         monitor_input_button->set_size_request (PX_SCALE(18, 18), PX_SCALE(18, 18));
223
224         monitor_disk_button->set_corner_radius(2);
225         monitor_disk_button->set_size_request (PX_SCALE(18, 18), PX_SCALE(18, 18));
226
227         mutebox.set_size_request (PX_SCALE(18, 18), PX_SCALE(18, 18));
228         solobox.set_size_request (PX_SCALE(18, 18), PX_SCALE(18, 18));
229         recbox.set_size_request (PX_SCALE(18, 18), PX_SCALE(18, 18));
230         mon_in_box.set_size_request (PX_SCALE(18, 18), PX_SCALE(18, 18));
231         mon_disk_box.set_size_request (PX_SCALE(18, 18), PX_SCALE(18, 18));
232         spacer.set_size_request(-1,0);
233
234         update_button_box();
235         update_name_box();
236         update_background (_route->meter_type());
237
238         mtr_vbox.pack_start (peakbx, false, false);
239         mtr_vbox.pack_start (meterbox, true, true);
240         mtr_vbox.pack_start (spacer, false, false);
241         mtr_container.add(mtr_vbox);
242
243         mtr_hsep.set_size_request(-1,1);
244         mtr_hsep.set_name("BlackSeparator");
245
246         nfo_vbox.pack_start (mtr_hsep, false, false);
247         nfo_vbox.pack_start (btnbox, false, false);
248         nfo_vbox.pack_start (namebx, false, false);
249
250         pack_start (mtr_container, true, true);
251         pack_start (nfo_vbox, false, false);
252
253         name_label.show();
254         peak_display.show();
255         peakbx.show();
256         meter_ticks1_area.show();
257         meter_ticks2_area.show();
258         meterbox.show();
259         spacer.show();
260         level_meter->show();
261         meter_align.show();
262         peak_align.show();
263         btnbox.show();
264         mtr_vbox.show();
265         mtr_container.show();
266         mtr_hsep.show();
267         nfo_vbox.show();
268         namenumberbx.show();
269
270         if (boost::dynamic_pointer_cast<Track>(_route)) {
271                 monitor_input_button->show();
272                 monitor_disk_button->show();
273         } else {
274                 monitor_input_button->hide();
275                 monitor_disk_button->hide();
276         }
277
278         _route->shared_peak_meter()->ConfigurationChanged.connect (
279                         meter_route_connections, invalidator (*this), boost::bind (&MeterStrip::meter_configuration_changed, this, _1), gui_context()
280                         );
281
282         ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &MeterStrip::reset_peak_display));
283         ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &MeterStrip::reset_route_peak_display));
284         ResetGroupPeakDisplays.connect (sigc::mem_fun(*this, &MeterStrip::reset_group_peak_display));
285         RedrawMetrics.connect (sigc::mem_fun(*this, &MeterStrip::redraw_metrics));
286         SetMeterTypeMulti.connect (sigc::mem_fun(*this, &MeterStrip::set_meter_type_multi));
287
288         meter_configuration_changed (_route->shared_peak_meter()->input_streams ());
289
290         meter_ticks1_area.set_size_request(PX_SCALE(3, 3), -1);
291         meter_ticks2_area.set_size_request(PX_SCALE(3, 3), -1);
292         meter_ticks1_area.signal_expose_event().connect (sigc::mem_fun(*this, &MeterStrip::meter_ticks1_expose));
293         meter_ticks2_area.signal_expose_event().connect (sigc::mem_fun(*this, &MeterStrip::meter_ticks2_expose));
294
295         _route->DropReferences.connect (meter_route_connections, invalidator (*this), boost::bind (&MeterStrip::self_delete, this), gui_context());
296
297         peak_display.signal_button_release_event().connect (sigc::mem_fun(*this, &MeterStrip::peak_button_release), false);
298         name_label.signal_button_release_event().connect (sigc::mem_fun(*this, &MeterStrip::name_label_button_release), false);
299
300         UI::instance()->theme_changed.connect (sigc::mem_fun(*this, &MeterStrip::on_theme_changed));
301         UIConfiguration::instance().ColorsChanged.connect (sigc::mem_fun (*this, &MeterStrip::on_theme_changed));
302         UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &MeterStrip::on_theme_changed));
303         Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&MeterStrip::parameter_changed, this, _1), gui_context());
304         sess->config.ParameterChanged.connect (*this, invalidator (*this), ui_bind (&MeterStrip::parameter_changed, this, _1), gui_context());
305
306         if (_route->is_master()) {
307                 _strip_type = 4;
308         }
309         else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
310                         && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
311                 /* non-master bus */
312                 _strip_type = 3;
313         }
314         else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
315                 _strip_type = 2;
316         }
317         else {
318                 _strip_type = 1;
319         }
320 }
321
322 MeterStrip::~MeterStrip ()
323 {
324         if (level_meter) {
325                 delete level_meter;
326                 CatchDeletion (this);
327         }
328 }
329
330 void
331 MeterStrip::self_delete ()
332 {
333         delete this;
334 }
335
336 void
337 MeterStrip::set_session (Session* s)
338 {
339         SessionHandlePtr::set_session (s);
340         if (!s) return;
341         s->config.ParameterChanged.connect (*this, invalidator (*this), ui_bind (&MeterStrip::parameter_changed, this, _1), gui_context());
342         update_button_box();
343         update_name_box();
344 }
345
346 void
347 MeterStrip::blink_rec_display (bool onoff)
348 {
349         RouteUI::blink_rec_display (onoff);
350 }
351
352 std::string
353 MeterStrip::state_id() const
354 {
355         if (_route) {
356                 return string_compose ("mtrs %1", _route->id().to_s());
357         } else {
358                 return string ();
359         }
360 }
361
362 void
363 MeterStrip::set_button_names()
364 {
365         mute_button->set_text (S_("Mute|M"));
366
367         if (_route && _route->solo_safe_control()->solo_safe()) {
368                 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
369         } else {
370                 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
371         }
372         if (!Config->get_solo_control_is_listen_control()) {
373                 solo_button->set_text (S_("Solo|S"));
374         } else {
375                 switch (Config->get_listen_position()) {
376                 case AfterFaderListen:
377                         solo_button->set_text (S_("AfterFader|A"));
378                         break;
379                 case PreFaderListen:
380                         solo_button->set_text (S_("PreFader|P"));
381                         break;
382                 }
383         }
384
385         monitor_input_button->set_text (S_("MonitorInput|I"));
386         monitor_disk_button->set_text (S_("MonitorDisk|D"));
387 }
388
389 void
390 MeterStrip::route_property_changed (const PropertyChange& what_changed)
391 {
392         if (!what_changed.contains (ARDOUR::Properties::name)) {
393                 return;
394         }
395         ENSURE_GUI_THREAD (*this, &MeterStrip::strip_name_changed, what_changed);
396         name_changed();
397         set_tooltip (name_label, _route->name());
398         if (level_meter) {
399                 set_tooltip (*level_meter, _route->name());
400         }
401 }
402
403 void
404 MeterStrip::route_color_changed ()
405 {
406         number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
407 }
408
409
410 void
411 MeterStrip::fast_update ()
412 {
413         float mpeak = level_meter->update_meters();
414         if (mpeak > max_peak) {
415                 max_peak = mpeak;
416                 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
417                         peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
418                 }
419         }
420 }
421
422 void
423 MeterStrip::on_theme_changed()
424 {
425         if (level_meter && _route) {
426                 int meter_width = 6;
427                 if (_route->shared_peak_meter()->input_streams().n_total() == 1) {
428                         meter_width = 12;
429                 }
430                 level_meter->setup_meters (220, meter_width, 6);
431         }
432 }
433
434 void
435 MeterStrip::meter_configuration_changed (ChanCount c)
436 {
437         int type = 0;
438         _types.clear ();
439         bool old_has_midi = _has_midi;
440
441         for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
442                 if (c.get (*i) > 0) {
443                         _types.push_back (*i);
444                         type |= 1 << (*i);
445                 }
446         }
447
448         if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
449                         && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0
450                         ) {
451                 meter_ticks1_area.set_name ("MyAudioBusMetricsLeft");
452                 meter_ticks2_area.set_name ("MyAudioBusMetricsRight");
453                 _has_midi = false;
454         }
455         else if (type == (1 << DataType::AUDIO)) {
456                 meter_ticks1_area.set_name ("MyAudioTrackMetricsLeft");
457                 meter_ticks2_area.set_name ("MyAudioTrackMetricsRight");
458                 _has_midi = false;
459         }
460         else if (type == (1 << DataType::MIDI)) {
461                 meter_ticks1_area.set_name ("MidiTrackMetricsLeft");
462                 meter_ticks2_area.set_name ("MidiTrackMetricsRight");
463                 _has_midi = true;
464         } else {
465                 meter_ticks1_area.set_name ("AudioMidiTrackMetricsLeft");
466                 meter_ticks2_area.set_name ("AudioMidiTrackMetricsRight");
467                 _has_midi = true;
468         }
469         set_tick_bar(_tick_bar);
470
471         on_theme_changed();
472         if (old_has_midi != _has_midi) MetricChanged();
473         else ConfigurationChanged();
474 }
475
476 void
477 MeterStrip::set_tick_bar (int m)
478 {
479         std::string n;
480         _tick_bar = m;
481         if (_tick_bar & 1) {
482                 n = meter_ticks1_area.get_name();
483                 if (n.substr(0,3) != "Bar") {
484                         meter_ticks1_area.set_name("Bar" + n);
485                 }
486         } else {
487                 n = meter_ticks1_area.get_name();
488                 if (n.substr(0,3) == "Bar") {
489                         meter_ticks1_area.set_name(n.substr(3,-1));
490                 }
491         }
492         if (_tick_bar & 2) {
493                 n = meter_ticks2_area.get_name();
494                 if (n.substr(0,3) != "Bar") {
495                         meter_ticks2_area.set_name("Bar" + n);
496                 }
497         } else {
498                 n = meter_ticks2_area.get_name();
499                 if (n.substr(0,3) == "Bar") {
500                         meter_ticks2_area.set_name(n.substr(3,-1));
501                 }
502         }
503 }
504
505 void
506 MeterStrip::on_size_request (Gtk::Requisition* r)
507 {
508         VBox::on_size_request(r);
509 }
510
511 void
512 MeterStrip::on_size_allocate (Gtk::Allocation& a)
513 {
514         const int wh = a.get_height();
515         int nh;
516         int mh = 0;
517         if (_session) {
518                 mh = _session->config.get_meterbridge_label_height();
519         }
520         switch (mh) {
521                 default:
522                 case 0:
523                         nh = ceilf(wh * .12f);
524                         if (nh < 52) nh = 52;
525                         if (nh > 148) nh = 148;
526                         break;
527                 case 1:
528                         nh = 52;
529                         break;
530                 case 2:
531                         nh = 88;
532                         break;
533                 case 3:
534                         nh = 106;
535                         break;
536                 case 4:
537                         nh = 148;
538                         break;
539         }
540         int tnh = 0;
541         if (_session && _session->config.get_track_name_number()) {
542                 // NB numbers are rotated 90deg. on the meterbridge
543                 tnh = 4 + std::max(2u, _session->track_number_decimals()) * 8; // TODO 8 = max_with_of_digit_0_to_9()
544         }
545
546         nh *= UIConfiguration::instance().get_ui_scale();
547         tnh *= UIConfiguration::instance().get_ui_scale();
548
549         int prev_height, ignored;
550         bool need_relayout = false;
551
552         namebx.get_size_request (ignored, prev_height);
553         namebx.set_size_request (PX_SCALE(18, 18), nh + tnh);
554
555         if (prev_height != nh + tnh) {
556                 need_relayout = true;
557         }
558
559         namenumberbx.get_size_request (ignored, prev_height);
560         namenumberbx.set_size_request (PX_SCALE(18, 18), nh + tnh);
561
562         if (prev_height != nh + tnh) {
563                 need_relayout = true;
564         }
565
566         if (_route) {
567                 int nlh = nh + (_route->is_master() ? tnh : -1);
568                 name_label.get_size_request(ignored, prev_height);
569                 name_label.set_size_request (PX_SCALE(18, 18), nlh);
570                 name_label.set_layout_ellipsize_width ((nh - 4 + (_route->is_master() ? tnh : 0)) * PANGO_SCALE); // XXX
571                 if (prev_height != nlh) {
572                         need_relayout = true;
573                 }
574         }
575
576         VBox::on_size_allocate(a);
577
578         if (need_relayout) {
579                 queue_resize();
580                 MetricChanged(); // force re-layout, parent on_scroll(), queue_resize()
581         }
582 }
583
584 gint
585 MeterStrip::meter_metrics_expose (GdkEventExpose *ev)
586 {
587         if (_route) {
588                 return meter_expose_metrics(ev, _route->meter_type(), _types, &meter_metric_area);
589         } else {
590                 return meter_expose_metrics(ev, metric_type, _types, &meter_metric_area);
591         }
592 }
593
594 void
595 MeterStrip::set_metric_mode (int metricmode, ARDOUR::MeterType mt)
596 {
597         if (metric_type == mt && _metricmode == metricmode) {
598                 return;
599         }
600         metric_type = mt;
601         _metricmode = metricmode;
602
603         _types.clear ();
604         switch(metricmode) {
605                 case 0:
606                         meter_metric_area.set_name ("MidiTrackMetricsLeft");
607                         _types.push_back (DataType::MIDI);
608                         break;
609                 case 1:
610                         meter_metric_area.set_name ("AudioTrackMetricsLeft");
611                         _types.push_back (DataType::AUDIO);
612                         break;
613                 case 2:
614                         meter_metric_area.set_name ("MidiTrackMetricsRight");
615                         _types.push_back (DataType::MIDI);
616                         break;
617                 case 3:
618                 default:
619                         meter_metric_area.set_name ("AudioTrackMetricsRight");
620                         _types.push_back (DataType::AUDIO);
621                         break;
622         }
623         update_background (mt);
624         meter_metric_area.queue_draw ();
625 }
626
627 void
628 MeterStrip::update_background(MeterType type)
629 {
630         switch(type) {
631                 case MeterIEC1DIN:
632                 case MeterIEC1NOR:
633                 case MeterIEC2BBC:
634                 case MeterIEC2EBU:
635                 case MeterK12:
636                 case MeterK14:
637                 case MeterK20:
638                         mtr_container.set_name ("meterstripPPM");
639                         break;
640                 case MeterVU:
641                         mtr_container.set_name ("meterstripVU");
642                         break;
643                 default:
644                         mtr_container.set_name ("meterstripDPM");
645         }
646 }
647
648 MeterType
649 MeterStrip::meter_type()
650 {
651         assert((!_route && _strip_type == 0) || (_route && _strip_type != 0));
652         if (!_route) return metric_type;
653         return _route->meter_type();
654 }
655
656 gint
657 MeterStrip::meter_ticks1_expose (GdkEventExpose *ev)
658 {
659         assert(_route);
660         return meter_expose_ticks(ev, _route->meter_type(), _types, &meter_ticks1_area);
661 }
662
663 gint
664 MeterStrip::meter_ticks2_expose (GdkEventExpose *ev)
665 {
666         assert(_route);
667         return meter_expose_ticks(ev, _route->meter_type(), _types, &meter_ticks2_area);
668 }
669
670 void
671 MeterStrip::reset_route_peak_display (Route* route)
672 {
673         if (_route && _route.get() == route) {
674                 reset_peak_display ();
675         }
676 }
677
678 void
679 MeterStrip::reset_group_peak_display (RouteGroup* group)
680 {
681         if (_route && group == _route->route_group()) {
682                 reset_peak_display ();
683         }
684 }
685
686 void
687 MeterStrip::reset_peak_display ()
688 {
689         _route->shared_peak_meter()->reset_max();
690         level_meter->clear_meters();
691         max_peak = -INFINITY;
692         peak_display.set_active_state ( Gtkmm2ext::Off );
693 }
694
695 bool
696 MeterStrip::peak_button_release (GdkEventButton* ev)
697 {
698         if (ev->button == 1 && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier|Keyboard::TertiaryModifier)) {
699                 ResetAllPeakDisplays ();
700         } else if (ev->button == 1 && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
701                 if (_route) {
702                         ResetGroupPeakDisplays (_route->route_group());
703                 }
704         } else {
705                 ResetRoutePeakDisplays (_route.get());
706         }
707         return false;
708 }
709
710 void
711 MeterStrip::redraw_metrics ()
712 {
713         meter_metric_area.queue_draw();
714         meter_ticks1_area.queue_draw();
715         meter_ticks2_area.queue_draw();
716 }
717
718 void
719 MeterStrip::update_button_box ()
720 {
721         if (!_session) return;
722         int height = 0;
723         if (_session->config.get_show_mute_on_meterbridge()) {
724                 height += PX_SCALE(18, 18) + PX_SCALE(2, 2);
725                 mutebox.show();
726         } else {
727                 mutebox.hide();
728         }
729         if (_session->config.get_show_solo_on_meterbridge()) {
730                 height += PX_SCALE(18, 18) + PX_SCALE(2, 2);
731                 solobox.show();
732         } else {
733                 solobox.hide();
734         }
735         if (_session->config.get_show_rec_on_meterbridge()) {
736                 height += PX_SCALE(18, 18) + PX_SCALE(2, 2);
737                 recbox.show();
738         } else {
739                 recbox.hide();
740         }
741         if (_session->config.get_show_monitor_on_meterbridge()) {
742                 height += PX_SCALE(18, 18) + PX_SCALE(2, 2);
743                 height += PX_SCALE(18, 18) + PX_SCALE(2, 2);
744                 mon_in_box.show();
745                 mon_disk_box.show();
746         } else {
747                 mon_in_box.hide();
748                 mon_disk_box.hide();
749         }
750         btnbox.set_size_request(PX_SCALE(18, 18), height);
751         check_resize();
752 }
753
754 void
755 MeterStrip::update_name_box ()
756 {
757         if (!_session) return;
758         if (_session->config.get_show_name_on_meterbridge()) {
759                 namebx.show();
760         } else {
761                 namebx.hide();
762         }
763 }
764
765 void
766 MeterStrip::parameter_changed (std::string const & p)
767 {
768         if (p == "meter-peak") {
769                 max_peak = -INFINITY;
770         }
771         else if (p == "show-rec-on-meterbridge") {
772                 update_button_box();
773         }
774         else if (p == "show-mute-on-meterbridge") {
775                 update_button_box();
776         }
777         else if (p == "show-solo-on-meterbridge") {
778                 update_button_box();
779         }
780         else if (p == "show-name-on-meterbridge") {
781                 update_name_box();
782         }
783         else if (p == "show-monitor-on-meterbridge") {
784                 update_button_box();
785         }
786         else if (p == "meterbridge-label-height") {
787                 queue_resize();
788         }
789         else if (p == "track-name-number") {
790                 name_changed();
791                 queue_resize();
792         }
793 }
794
795 void
796 MeterStrip::name_changed () {
797         if (!_route) {
798                 return;
799         }
800         name_label.set_text(_route->name ());
801         if (_session && _session->config.get_track_name_number()) {
802                 const uint64_t track_number = _route->track_number();
803                 if (track_number == 0) {
804                         number_label.set_text("-");
805                         number_label.hide();
806                 } else {
807                         number_label.set_text (PBD::to_string (track_number, std::dec));
808                         number_label.show();
809                 }
810                 const int tnh = 4 + std::max(2u, _session->track_number_decimals()) * 8; // TODO 8 = max_width_of_digit_0_to_9()
811                 // NB numbers are rotated 90deg. on the meterbridge -> use height
812                 number_label.set_size_request(PX_SCALE(18, 18), tnh * UIConfiguration::instance().get_ui_scale());
813         } else {
814                 number_label.hide();
815         }
816 }
817
818 bool
819 MeterStrip::level_meter_button_press (GdkEventButton* ev)
820 {
821         if (ev->button == 3) {
822                 if (_route && _route->shared_peak_meter()->input_streams ().n_audio() > 0) {
823                         popup_level_meter_menu (ev);
824                 }
825                 return true;
826         }
827
828         return false;
829 }
830
831 void
832 MeterStrip::popup_level_meter_menu (GdkEventButton* ev)
833 {
834         using namespace Gtk::Menu_Helpers;
835
836         Gtk::Menu* m = manage (new Menu);
837         MenuList& items = m->items ();
838
839         RadioMenuItem::Group group;
840
841         _suspend_menu_callbacks = true;
842         add_level_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
843         add_level_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
844         add_level_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterKrms),  MeterKrms);
845         add_level_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
846         add_level_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
847         add_level_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
848         add_level_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
849         add_level_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK20), MeterK20);
850         add_level_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK14), MeterK14);
851         add_level_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK12), MeterK12);
852         add_level_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterVU),  MeterVU);
853
854         MeterType cmt = _route->meter_type();
855         const std::string cmn = ArdourMeter::meter_type_string(cmt);
856
857         items.push_back (SeparatorElem());
858         items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
859                                 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
860         items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
861                                 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
862         items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
863                                 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
864
865         m->popup (ev->button, ev->time);
866         _suspend_menu_callbacks = false;
867 }
868
869 bool
870 MeterStrip::name_label_button_release (GdkEventButton* ev)
871 {
872         if (!_session) return true;
873         if (!_session->config.get_show_name_on_meterbridge()) return true;
874
875         if (ev->button == 3) {
876                 popup_name_label_menu (ev);
877                 return true;
878         }
879
880         return false;
881 }
882
883 void
884 MeterStrip::popup_name_label_menu (GdkEventButton* ev)
885 {
886         using namespace Gtk::Menu_Helpers;
887
888         Gtk::Menu* m = manage (new Menu);
889         MenuList& items = m->items ();
890
891         RadioMenuItem::Group group;
892
893         _suspend_menu_callbacks = true;
894         add_label_height_item (items, group, _("Variable height"), 0);
895         add_label_height_item (items, group, _("Short"), 1);
896         add_label_height_item (items, group, _("Tall"), 2);
897         add_label_height_item (items, group, _("Grande"), 3);
898         add_label_height_item (items, group, _("Venti"), 4);
899
900         m->popup (ev->button, ev->time);
901         _suspend_menu_callbacks = false;
902 }
903
904 void
905 MeterStrip::add_label_height_item (Menu_Helpers::MenuList& items, RadioMenuItem::Group& group, string const & name, uint32_t h)
906 {
907         using namespace Menu_Helpers;
908
909         items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MeterStrip::set_label_height), h)));
910         RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
911         i->set_active (_session && _session->config.get_meterbridge_label_height() == h);
912 }
913
914 void
915 MeterStrip::add_level_meter_type_item (Menu_Helpers::MenuList& items, RadioMenuItem::Group& group, string const & name, MeterType type)
916 {
917         using namespace Menu_Helpers;
918
919         items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MeterStrip::set_meter_type), type)));
920         RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
921         i->set_active (_route->meter_type() == type);
922 }
923
924 void
925 MeterStrip::set_meter_type (MeterType type)
926 {
927         if (_suspend_menu_callbacks) return;
928         if (_route->meter_type() == type) return;
929
930         level_meter->set_type (type);
931 }
932
933 void
934 MeterStrip::set_label_height (uint32_t h)
935 {
936         if (_suspend_menu_callbacks) return;
937         _session->config.set_meterbridge_label_height(h);
938 }
939
940 void
941 MeterStrip::meter_type_changed (MeterType type)
942 {
943         if (_route->meter_type() != type) {
944                 _route->set_meter_type(type);
945         }
946         update_background (type);
947         MetricChanged();
948 }
949
950 void
951 MeterStrip::set_meter_type_multi (int what, RouteGroup* group, MeterType type)
952 {
953         switch (what) {
954                 case -1:
955                         if (_route && group == _route->route_group()) {
956                                 level_meter->set_type (type);
957                         }
958                         break;
959                 case 0:
960                         level_meter->set_type (type);
961                 default:
962                         if (what == _strip_type) {
963                                 level_meter->set_type (type);
964                         }
965                         break;
966         }
967 }
968
969 string
970 MeterStrip::name () const
971 {
972         return _route->name();
973 }
974
975 Gdk::Color
976 MeterStrip::color () const
977 {
978         return RouteUI::route_color ();
979 }
980