fix meter bridge window size issues
[ardour.git] / gtk2_ardour / meterbridge.cc
1 /*
2     Copyright (C) 2012 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
21 #ifdef WAF_BUILD
22 #include "gtk2ardour-config.h"
23 #endif
24
25 #include <map>
26 #include <sigc++/bind.h>
27
28 #include <gtkmm/accelmap.h>
29
30 #include <glibmm/threads.h>
31
32 #include <gtkmm2ext/gtk_ui.h>
33 #include <gtkmm2ext/utils.h>
34 #include <gtkmm2ext/window_title.h>
35
36 #include "ardour/debug.h"
37 #include "ardour/midi_track.h"
38 #include "ardour/route_group.h"
39 #include "ardour/session.h"
40
41 #include "ardour/audio_track.h"
42 #include "ardour/midi_track.h"
43 #include "ardour/route_sorters.h"
44
45 #include "meterbridge.h"
46
47 #include "keyboard.h"
48 #include "monitor_section.h"
49 #include "public_editor.h"
50 #include "ardour_ui.h"
51 #include "utils.h"
52 #include "route_sorter.h"
53 #include "actions.h"
54 #include "gui_thread.h"
55 #include "global_signals.h"
56 #include "meter_patterns.h"
57 #include "timers.h"
58
59 #include "i18n.h"
60
61 using namespace ARDOUR;
62 using namespace ARDOUR_UI_UTILS;
63 using namespace PBD;
64 using namespace Gtk;
65 using namespace Glib;
66 using namespace Gtkmm2ext;
67 using namespace std;
68 using namespace ArdourMeter;
69
70 using PBD::atoi;
71
72 Meterbridge* Meterbridge::_instance = 0;
73
74 Meterbridge*
75 Meterbridge::instance ()
76 {
77         if (!_instance) {
78                 _instance  = new Meterbridge;
79         }
80
81         return _instance;
82 }
83
84 Meterbridge::Meterbridge ()
85         : Window (Gtk::WINDOW_TOPLEVEL)
86         , VisibilityTracker (*((Gtk::Window*) this))
87         , _visible (false)
88         , _show_busses (false)
89         , metrics_left (1, MeterPeak)
90         , metrics_right (2, MeterPeak)
91         , cur_max_width (-1)
92 {
93         set_name ("Meter Bridge");
94
95         m_width = default_width;
96         m_height = default_height;
97         m_root_x = 1;
98         m_root_y = 1;
99
100         update_title ();
101
102         set_wmclass (X_("ardour_mixer"), PROGRAM_NAME);
103
104         Gdk::Geometry geom;
105         geom.max_width = 1<<16;
106         geom.max_height = max_height;
107         geom.min_width = 40;
108         geom.min_height = -1;
109         geom.height_inc = 16;
110         geom.width_inc = 1;
111         assert(max_height % 16 == 0);
112         set_geometry_hints(*((Gtk::Window*) this), geom, Gdk::HINT_MIN_SIZE | Gdk::HINT_MAX_SIZE | Gdk::HINT_RESIZE_INC);
113
114         set_keep_above (true);
115         set_border_width (0);
116
117         metrics_vpacker_left.pack_start (metrics_left, true, true);
118         metrics_vpacker_left.pack_start (metrics_spacer_left, false, false);
119         metrics_spacer_left.set_size_request(-1, 0);
120         metrics_spacer_left.set_spacing(0);
121
122         metrics_vpacker_right.pack_start (metrics_right, true, true);
123         metrics_vpacker_right.pack_start (metrics_spacer_right, false, false);
124         metrics_spacer_right.set_size_request(-1, 0);
125         metrics_spacer_right.set_spacing(0);
126
127         signal_delete_event().connect (sigc::mem_fun (*this, &Meterbridge::hide_window));
128         signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
129         Route::SyncOrderKeys.connect (*this, invalidator (*this), boost::bind (&Meterbridge::sync_order_keys, this), gui_context());
130         MeterStrip::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Meterbridge::remove_strip, this, _1), gui_context());
131         MeterStrip::MetricChanged.connect (*this, invalidator (*this), boost::bind(&Meterbridge::resync_order, this), gui_context());
132         MeterStrip::ConfigurationChanged.connect (*this, invalidator (*this), boost::bind(&Meterbridge::queue_resize, this), gui_context());
133
134         /* work around ScrolledWindowViewport alignment mess Part one */
135         Gtk::HBox * yspc = manage (new Gtk::HBox());
136         yspc->set_size_request(-1, 1);
137         Gtk::VBox * xspc = manage (new Gtk::VBox());
138         xspc->pack_start(meterarea, true, true);
139         xspc->pack_start(*yspc, false, false);
140         yspc->show();
141         xspc->show();
142
143         meterarea.set_spacing(0);
144         scroller.set_shadow_type(Gtk::SHADOW_NONE);
145         scroller.set_border_width(0);
146         scroller.add (*xspc);
147         scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_NEVER);
148
149         global_hpacker.pack_start (metrics_vpacker_left, false, false);
150         global_hpacker.pack_start (scroller, true, true);
151         global_hpacker.pack_start (metrics_vpacker_right, false, false);
152
153         global_vpacker.pack_start (global_hpacker, true, true);
154         add (global_vpacker);
155
156         metrics_left.show();
157         metrics_right.show();
158
159         metrics_vpacker_left.show();
160         metrics_spacer_left.show();
161         metrics_vpacker_right.show();
162         metrics_spacer_right.show();
163
164         meterarea.show();
165         global_vpacker.show();
166         global_hpacker.show();
167         scroller.show();
168
169         /* the return of the ScrolledWindowViewport mess:
170          * remove shadow from scrollWindow's viewport
171          * see http://www.mail-archive.com/gtkmm-list@gnome.org/msg03509.html
172          */
173         Gtk::Viewport* viewport = (Gtk::Viewport*) scroller.get_child();
174         viewport->set_shadow_type(Gtk::SHADOW_NONE);
175         viewport->set_border_width(0);
176
177         UI::instance()->theme_changed.connect (sigc::mem_fun(*this, &Meterbridge::on_theme_changed));
178         ColorsChanged.connect (sigc::mem_fun (*this, &Meterbridge::on_theme_changed));
179         DPIReset.connect (sigc::mem_fun (*this, &Meterbridge::on_theme_changed));
180 }
181
182 Meterbridge::~Meterbridge ()
183 {
184         while (_metrics.size() > 0) {
185                 delete (_metrics.back());
186                 _metrics.pop_back();
187         }
188 }
189
190 void
191 Meterbridge::show_window ()
192 {
193         present();
194         if (!_visible) {
195                 set_window_pos_and_size ();
196         }
197         _visible = true;
198 }
199
200 /* code duplicated from gtk2_ardour/mixer_ui.cc  Mixer_UI::update_title() */
201 void
202 Meterbridge::update_title ()
203 {
204         if (_session) {
205                 string n;
206
207                 if (_session->snap_name() != _session->name()) {
208                         n = _session->snap_name ();
209                 } else {
210                         n = _session->name ();
211                 }
212
213                 if (_session->dirty ()) {
214                         n = "*" + n;
215                 }
216
217                 WindowTitle title (n);
218                 title += S_("Window|Meterbridge");
219                 title += Glib::get_application_name ();
220                 set_title (title.get_string());
221
222         } else {
223
224                 WindowTitle title (S_("Window|Meterbridge"));
225                 title += Glib::get_application_name ();
226                 set_title (title.get_string());
227         }
228 }
229
230 void
231 Meterbridge::set_window_pos_and_size ()
232 {
233         resize (m_width, m_height);
234         if (m_root_x >= 0 && m_root_y >= 0) {
235                 move (m_root_x, m_root_y);
236         }
237 }
238
239 void
240 Meterbridge::get_window_pos_and_size ()
241 {
242         get_position(m_root_x, m_root_y);
243         get_size(m_width, m_height);
244 }
245
246 bool
247 Meterbridge::hide_window (GdkEventAny *ev)
248 {
249         if (!_visible) return 0;
250         get_window_pos_and_size();
251         _visible = false;
252         return just_hide_it(ev, static_cast<Gtk::Window *>(this));
253 }
254
255 bool
256 Meterbridge::on_key_press_event (GdkEventKey* ev)
257 {
258         if (gtk_window_propagate_key_event (GTK_WINDOW(gobj()), ev)) {
259                 return true;
260         }
261         return forward_key_press (ev);
262 }
263
264 bool
265 Meterbridge::on_key_release_event (GdkEventKey* ev)
266 {
267         if (gtk_window_propagate_key_event (GTK_WINDOW(gobj()), ev)) {
268                 return true;
269         }
270         /* don't forward releases */
271         return true;
272 }
273
274 bool
275 Meterbridge::on_scroll_event (GdkEventScroll* ev)
276 {
277         switch (ev->direction) {
278         case GDK_SCROLL_LEFT:
279                 scroll_left ();
280                 return true;
281         case GDK_SCROLL_UP:
282                 if (ev->state & Keyboard::TertiaryModifier) {
283                         scroll_left ();
284                         return true;
285                 }
286                 return false;
287
288         case GDK_SCROLL_RIGHT:
289                 scroll_right ();
290                 return true;
291
292         case GDK_SCROLL_DOWN:
293                 if (ev->state & Keyboard::TertiaryModifier) {
294                         scroll_right ();
295                         return true;
296                 }
297                 return false;
298         }
299
300         return false;
301 }
302
303 void
304 Meterbridge::scroll_left ()
305 {
306         if (!scroller.get_hscrollbar()) return;
307         Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
308         /* stupid GTK: can't rely on clamping across versions */
309         scroller.get_hscrollbar()->set_value (max (adj->get_lower(), adj->get_value() - adj->get_step_increment()));
310 }
311
312 void
313 Meterbridge::scroll_right ()
314 {
315         if (!scroller.get_hscrollbar()) return;
316         Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
317         /* stupid GTK: can't rely on clamping across versions */
318         scroller.get_hscrollbar()->set_value (min (adj->get_upper(), adj->get_value() + adj->get_step_increment()));
319 }
320
321 void
322 Meterbridge::on_size_request (Gtk::Requisition* r)
323 {
324         meter_clear_pattern_cache(3);
325         Gtk::Window::on_size_request(r);
326
327         Gdk::Geometry geom;
328         Gtk::Requisition mr = meterarea.size_request();
329
330         geom.max_width = mr.width + metrics_left.get_width() + metrics_right.get_width();
331         geom.max_width = std::max(50, geom.max_width);
332         geom.max_height = max_height;
333
334         if (cur_max_width != geom.max_width) {
335                 cur_max_width = geom.max_width;
336                 /* height resizes are 'heavy' since the metric areas and meter-patterns
337                  * are re-generated. limit to 16px steps. */
338                 geom.height_inc = 16;
339                 geom.width_inc = 1;
340                 geom.min_width = 40;
341                 geom.min_height = -1;
342                 set_geometry_hints(*((Gtk::Window*) this), geom, Gdk::HINT_MIN_SIZE | Gdk::HINT_MAX_SIZE | Gdk::HINT_RESIZE_INC);
343         }
344 }
345
346 void
347 Meterbridge::on_size_allocate (Gtk::Allocation& a)
348 {
349         const Gtk::Scrollbar * hsc = scroller.get_hscrollbar();
350
351         /* switch left/right edge patterns depending on horizontal scroll-position */
352         if (scroller.get_hscrollbar_visible() && hsc) {
353                 if (!scroll_connection.connected()) {
354                         scroll_connection = scroller.get_hscrollbar()->get_adjustment()->signal_value_changed().connect(sigc::mem_fun (*this, &Meterbridge::on_scroll));
355                         scroller.get_hscrollbar()->get_adjustment()->signal_changed().connect(sigc::mem_fun (*this, &Meterbridge::on_scroll));
356                 }
357                 gint scrollbar_spacing;
358                 gtk_widget_style_get (GTK_WIDGET (scroller.gobj()),
359                                 "scrollbar-spacing", &scrollbar_spacing, NULL);
360                 const int h = hsc->get_height() + scrollbar_spacing + 1;
361                 metrics_spacer_left.set_size_request(-1, h);
362                 metrics_spacer_right.set_size_request(-1, h);
363         } else {
364                 metrics_spacer_left.set_size_request(-1, 0);
365                 metrics_spacer_right.set_size_request(-1, 0);
366         }
367         Gtk::Window::on_size_allocate(a);
368 }
369
370 void
371 Meterbridge::on_scroll()
372 {
373         if (!scroller.get_hscrollbar()) return;
374
375         Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
376         int leftend = adj->get_value();
377         int rightend = scroller.get_width() + leftend;
378
379         int mm_left = _mm_left;
380         int mm_right = _mm_right;
381         ARDOUR::MeterType mt_left = _mt_left;
382         ARDOUR::MeterType mt_right = _mt_right;
383
384         for (unsigned int i = 0; i < _metrics.size(); ++i) {
385                 int sx, dx = 0, dy = 0;
386                 int mm = _metrics[i]->get_metric_mode();
387                 sx = (mm & 2) ? _metrics[i]->get_width() : 0;
388
389                 _metrics[i]->translate_coordinates(meterarea, sx, 0, dx, dy);
390
391                 if (dx < leftend && !(mm&2)) {
392                         mm_left = mm;
393                         mt_left = _metrics[i]->meter_type();
394                 }
395                 if (dx > rightend && (mm&2)) {
396                         mm_right = mm;
397                         mt_right = _metrics[i]->meter_type();
398                         break;
399                 }
400         }
401         metrics_left.set_metric_mode(mm_left, mt_left);
402         metrics_right.set_metric_mode(mm_right, mt_right);
403 }
404
405 void
406 Meterbridge::set_session (Session* s)
407 {
408         SessionHandlePtr::set_session (s);
409
410         if (!_session) {
411                 return;
412         }
413
414         metrics_left.set_session(s);
415         metrics_right.set_session(s);
416
417         XMLNode* node = _session->instant_xml(X_("Meterbridge"));
418         if (node) {
419                 set_state (*node);
420         }
421
422         update_title ();
423         _show_busses = _session->config.get_show_busses_on_meterbridge();
424         _show_master = _session->config.get_show_master_on_meterbridge();
425         _show_midi = _session->config.get_show_midi_on_meterbridge();
426
427         ARDOUR::SignalOrderRouteSorter sorter;
428         boost::shared_ptr<RouteList> routes = _session->get_routes();
429
430         RouteList copy(*routes);
431         copy.sort(sorter);
432         add_strips(copy);
433
434         _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Meterbridge::add_strips, this, _1), gui_context());
435         _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Meterbridge::update_title, this), gui_context());
436         _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Meterbridge::update_title, this), gui_context());
437         _session->config.ParameterChanged.connect (*this, invalidator (*this), ui_bind (&Meterbridge::parameter_changed, this, _1), gui_context());
438         Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&Meterbridge::parameter_changed, this, _1), gui_context());
439
440         if (_visible) {
441                 show_window();
442                 ActionManager::check_toggleaction ("<Actions>/Common/toggle-meterbridge");
443         }
444         start_updating ();
445 }
446
447 void
448 Meterbridge::session_going_away ()
449 {
450         ENSURE_GUI_THREAD (*this, &Meterbridge::session_going_away);
451
452         for (list<MeterBridgeStrip>::iterator i = strips.begin(); i != strips.end(); ++i) {
453                 delete ((*i).s);
454         }
455
456         strips.clear ();
457         stop_updating ();
458
459         SessionHandlePtr::session_going_away ();
460
461         _session = 0;
462         update_title ();
463 }
464
465 int
466 Meterbridge::set_state (const XMLNode& node)
467 {
468         const XMLProperty* prop;
469         XMLNode* geometry;
470
471         m_width = default_width;
472         m_height = default_height;
473         m_root_x = 1;
474         m_root_y = 1;
475
476         if ((geometry = find_named_node (node, "geometry")) != 0) {
477
478                 XMLProperty* prop;
479
480                 if ((prop = geometry->property("x_size")) == 0) {
481                         prop = geometry->property ("x-size");
482                 }
483                 if (prop) {
484                         m_width = atoi(prop->value());
485                 }
486                 if ((prop = geometry->property("y_size")) == 0) {
487                         prop = geometry->property ("y-size");
488                 }
489                 if (prop) {
490                         m_height = atoi(prop->value());
491                 }
492
493                 if ((prop = geometry->property ("x_pos")) == 0) {
494                         prop = geometry->property ("x-pos");
495                 }
496                 if (prop) {
497                         m_root_x = atoi (prop->value());
498
499                 }
500                 if ((prop = geometry->property ("y_pos")) == 0) {
501                         prop = geometry->property ("y-pos");
502                 }
503                 if (prop) {
504                         m_root_y = atoi (prop->value());
505                 }
506         }
507
508         set_window_pos_and_size ();
509
510         if ((prop = node.property ("show-meterbridge"))) {
511                 if (string_is_affirmative (prop->value())) {
512                        _visible = true;
513                 }
514         }
515
516         return 0;
517 }
518
519 XMLNode&
520 Meterbridge::get_state (void)
521 {
522         char buf[32];
523         XMLNode* node = new XMLNode ("Meterbridge");
524
525         if (is_realized() && _visible) {
526                 get_window_pos_and_size ();
527         }
528
529         XMLNode* geometry = new XMLNode ("geometry");
530         snprintf(buf, sizeof(buf), "%d", m_width);
531         geometry->add_property(X_("x_size"), string(buf));
532         snprintf(buf, sizeof(buf), "%d", m_height);
533         geometry->add_property(X_("y_size"), string(buf));
534         snprintf(buf, sizeof(buf), "%d", m_root_x);
535         geometry->add_property(X_("x_pos"), string(buf));
536         snprintf(buf, sizeof(buf), "%d", m_root_y);
537         geometry->add_property(X_("y_pos"), string(buf));
538         node->add_child_nocopy (*geometry);
539
540         node->add_property ("show-meterbridge", _visible ? "yes" : "no");
541         return *node;
542 }
543
544
545 gint
546 Meterbridge::start_updating ()
547 {
548         fast_screen_update_connection = Timers::super_rapid_connect (sigc::mem_fun(*this, &Meterbridge::fast_update_strips));
549         return 0;
550 }
551
552 gint
553 Meterbridge::stop_updating ()
554 {
555         fast_screen_update_connection.disconnect();
556         return 0;
557 }
558
559 void
560 Meterbridge::fast_update_strips ()
561 {
562         if (!is_mapped () || !_session) {
563                 return;
564         }
565         for (list<MeterBridgeStrip>::iterator i = strips.begin(); i != strips.end(); ++i) {
566                 if (!(*i).visible) continue;
567                 (*i).s->fast_update ();
568         }
569 }
570
571 void
572 Meterbridge::add_strips (RouteList& routes)
573 {
574         MeterStrip* strip;
575         for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
576                 boost::shared_ptr<Route> route = (*x);
577                 if (route->is_auditioner()) {
578                         continue;
579                 }
580                 if (route->is_monitor()) {
581                         continue;
582                 }
583
584                 strip = new MeterStrip (_session, route);
585                 strips.push_back (MeterBridgeStrip(strip));
586                 route->active_changed.connect (*this, invalidator (*this), boost::bind (&Meterbridge::resync_order, this), gui_context ());
587
588                 meterarea.pack_start (*strip, false, false);
589                 strip->show();
590         }
591
592         resync_order();
593 }
594
595 void
596 Meterbridge::remove_strip (MeterStrip* strip)
597 {
598         if (_session && _session->deletion_in_progress()) {
599                 return;
600         }
601
602         list<MeterBridgeStrip>::iterator i;
603         for (list<MeterBridgeStrip>::iterator i = strips.begin(); i != strips.end(); ++i) {
604                 if ( (*i).s == strip) {
605                         strips.erase (i);
606                         break;
607                 }
608         }
609
610         resync_order();
611 }
612
613 void
614 Meterbridge::sync_order_keys ()
615 {
616         Glib::Threads::Mutex::Lock lm (_resync_mutex);
617
618         MeterOrderRouteSorter sorter;
619         strips.sort(sorter);
620
621         int pos = 0;
622         int vis = 0;
623         MeterStrip * last = 0;
624
625         unsigned int metrics = 0;
626         MeterType lmt = MeterPeak;
627         bool have_midi = false;
628         metrics_left.set_metric_mode(1, lmt);
629
630         for (list<MeterBridgeStrip>::iterator i = strips.begin(); i != strips.end(); ++i) {
631
632                 if (! (*i).s->route()->active()) {
633                         (*i).s->hide();
634                         (*i).visible = false;
635                 }
636                 else if ((*i).s->route()->is_master()) {
637                         if (_show_master) {
638                                 (*i).s->show();
639                                 (*i).visible = true;
640                                 vis++;
641                         } else {
642                                 (*i).s->hide();
643                                 (*i).visible = false;
644                         }
645                 }
646                 else if (boost::dynamic_pointer_cast<AudioTrack>((*i).s->route()) == 0
647                                 && boost::dynamic_pointer_cast<MidiTrack>((*i).s->route()) == 0
648                                 ) {
649                         /* non-master bus */
650                         if (_show_busses) {
651                                 (*i).s->show();
652                                 (*i).visible = true;
653                                 vis++;
654                         } else {
655                                 (*i).s->hide();
656                                 (*i).visible = false;
657                         }
658                 }
659                 else if (boost::dynamic_pointer_cast<MidiTrack>((*i).s->route())) {
660                         if (_show_midi) {
661                                 (*i).s->show();
662                                 (*i).visible = true;
663                                 vis++;
664                         } else {
665                                 (*i).s->hide();
666                                 (*i).visible = false;
667                         }
668                 }
669                 else {
670                         (*i).s->show();
671                         (*i).visible = true;
672                                 vis++;
673                 }
674
675                 (*i).s->set_tick_bar(0);
676
677                 MeterType nmt = (*i).s->meter_type();
678                 if (nmt == MeterKrms) nmt = MeterPeak; // identical metrics
679                 if (vis == 1) {
680                         (*i).s->set_tick_bar(1);
681                 }
682
683                 if ((*i).visible && nmt != lmt && vis == 1) {
684                         lmt = nmt;
685                         metrics_left.set_metric_mode(1, lmt);
686                 } else if ((*i).visible && nmt != lmt) {
687
688                         if (last) {
689                                 last->set_tick_bar(last->get_tick_bar() | 2);
690                         }
691                         (*i).s->set_tick_bar((*i).s->get_tick_bar() | 1);
692
693                         if (_metrics.size() <= metrics) {
694                                 _metrics.push_back(new MeterStrip(have_midi ? 2 : 3, lmt));
695                                 meterarea.pack_start (*_metrics[metrics], false, false);
696                                 _metrics[metrics]->set_session(_session);
697                                 _metrics[metrics]->show();
698                         } else {
699                                 _metrics[metrics]->set_metric_mode(have_midi ? 2 : 3, lmt);
700                         }
701                         meterarea.reorder_child(*_metrics[metrics], pos++);
702                         metrics++;
703
704                         lmt = nmt;
705
706                         if (_metrics.size() <= metrics) {
707                                 _metrics.push_back(new MeterStrip(1, lmt));
708                                 meterarea.pack_start (*_metrics[metrics], false, false);
709                                 _metrics[metrics]->set_session(_session);
710                                 _metrics[metrics]->show();
711                         } else {
712                                 _metrics[metrics]->set_metric_mode(1, lmt);
713                         }
714                         meterarea.reorder_child(*_metrics[metrics], pos++);
715                         metrics++;
716                         have_midi = false;
717                 }
718
719                 if ((*i).visible && (*i).s->has_midi()) {
720                         have_midi = true;
721                 }
722
723                 meterarea.reorder_child(*((*i).s), pos++);
724                 if ((*i).visible) {
725                         last = (*i).s;
726                 }
727         }
728
729         if (last) {
730                 last->set_tick_bar(last->get_tick_bar() | 2);
731         }
732
733         metrics_right.set_metric_mode(have_midi ? 2 : 3, lmt);
734
735         while (_metrics.size() > metrics) {
736                 meterarea.remove(*_metrics.back());
737                 delete (_metrics.back());
738                 _metrics.pop_back();
739         }
740
741         _mm_left = metrics_left.get_metric_mode();
742         _mt_left = metrics_left.meter_type();
743         _mm_right = metrics_right.get_metric_mode();
744         _mt_right = metrics_right.meter_type();
745
746         on_scroll();
747         queue_resize();
748 }
749
750 void
751 Meterbridge::resync_order()
752 {
753         sync_order_keys();
754 }
755
756 void
757 Meterbridge::parameter_changed (std::string const & p)
758 {
759         if (p == "show-busses-on-meterbridge") {
760                 _show_busses = _session->config.get_show_busses_on_meterbridge();
761                 resync_order();
762         }
763         else if (p == "show-master-on-meterbridge") {
764                 _show_master = _session->config.get_show_master_on_meterbridge();
765                 resync_order();
766         }
767         else if (p == "show-midi-on-meterbridge") {
768                 _show_midi = _session->config.get_show_midi_on_meterbridge();
769                 resync_order();
770         }
771         else if (p == "meter-line-up-level") {
772                 meter_clear_pattern_cache();
773         }
774         else if (p == "show-rec-on-meterbridge") {
775                 scroller.queue_resize();
776         }
777         else if (p == "show-mute-on-meterbridge") {
778                 scroller.queue_resize();
779         }
780         else if (p == "show-solo-on-meterbridge") {
781                 scroller.queue_resize();
782         }
783         else if (p == "show-name-on-meterbridge") {
784                 scroller.queue_resize();
785         }
786         else if (p == "meterbridge-label-height") {
787                 scroller.queue_resize();
788         }
789         else if (p == "show-monitor-on-meterbridge") {
790                 scroller.queue_resize();
791         }
792         else if (p == "track-name-number") {
793                 scroller.queue_resize();
794         }
795 }
796
797 void
798 Meterbridge::on_theme_changed ()
799 {
800         meter_clear_pattern_cache();
801 }