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