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