X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fmeterbridge.cc;h=02350c92bf114345012bfc95a092c4b30a1b5219;hb=fdf63ace6a655f772a46e73719de14f9dd6fb940;hp=dbed1a42ec6ff2c1b9f3f6a8eaffd709a81fb430;hpb=c72702883bf68477fd1a26974064afdc9709895f;p=ardour.git diff --git a/gtk2_ardour/meterbridge.cc b/gtk2_ardour/meterbridge.cc index dbed1a42ec..02350c92bf 100644 --- a/gtk2_ardour/meterbridge.cc +++ b/gtk2_ardour/meterbridge.cc @@ -43,6 +43,7 @@ #include "meterbridge.h" +#include "keyboard.h" #include "monitor_section.h" #include "public_editor.h" #include "ardour_ui.h" @@ -50,15 +51,19 @@ #include "route_sorter.h" #include "actions.h" #include "gui_thread.h" +#include "meter_patterns.h" +#include "timers.h" -#include "i18n.h" +#include "pbd/i18n.h" using namespace ARDOUR; +using namespace ARDOUR_UI_UTILS; using namespace PBD; using namespace Gtk; using namespace Glib; using namespace Gtkmm2ext; using namespace std; +using namespace ArdourMeter; using PBD::atoi; @@ -74,52 +79,14 @@ Meterbridge::instance () return _instance; } -/* copy from gtk2_ardour/mixer_ui.cc -- TODO consolidate - * used by Meterbridge::set_session() below - */ -struct SignalOrderRouteSorter { - bool operator() (boost::shared_ptr a, boost::shared_ptr b) { - if (a->is_master() || a->is_monitor()) { - /* "a" is a special route (master, monitor, etc), and comes - * last in the mixer ordering - */ - return false; - } else if (b->is_master() || b->is_monitor()) { - /* everything comes before b */ - return true; - } - return a->order_key (MixerSort) < b->order_key (MixerSort); - } -}; - -/* modified version of above - * used in Meterbridge::sync_order_keys() - */ -struct MeterOrderRouteSorter { - bool operator() (MeterStrip *ma, MeterStrip *mb) { - boost::shared_ptr a = ma->route(); - boost::shared_ptr b = mb->route(); - if (a->is_master() || a->is_monitor()) { - /* "a" is a special route (master, monitor, etc), and comes - * last in the mixer ordering - */ - return false; - } else if (b->is_master() || b->is_monitor()) { - /* everything comes before b */ - return true; - } - return a->order_key (MixerSort) < b->order_key (MixerSort); - } -}; - - Meterbridge::Meterbridge () : Window (Gtk::WINDOW_TOPLEVEL) , VisibilityTracker (*((Gtk::Window*) this)) , _visible (false) , _show_busses (false) - , metrics_left (2) - , metrics_right (3) + , metrics_left (1, MeterPeak) + , metrics_right (2, MeterPeak) + , cur_max_width (-1) { set_name ("Meter Bridge"); @@ -134,10 +101,14 @@ Meterbridge::Meterbridge () Gdk::Geometry geom; geom.max_width = 1<<16; - geom.max_height = 1024 + 148 + 16 + 12 ; // see FastMeter::max_pattern_metric_size + meter-strip widgets - set_geometry_hints(*((Gtk::Window*) this), geom, Gdk::HINT_MAX_SIZE); + geom.max_height = max_height; + geom.min_width = 40; + geom.min_height = -1; + geom.height_inc = 16; + geom.width_inc = 1; + assert(max_height % 16 == 0); + set_geometry_hints(*((Gtk::Window*) this), geom, Gdk::HINT_MIN_SIZE | Gdk::HINT_MAX_SIZE | Gdk::HINT_RESIZE_INC); - set_keep_above (true); set_border_width (0); metrics_vpacker_left.pack_start (metrics_left, true, true); @@ -152,11 +123,9 @@ Meterbridge::Meterbridge () signal_delete_event().connect (sigc::mem_fun (*this, &Meterbridge::hide_window)); signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler)); - Route::SyncOrderKeys.connect (*this, invalidator (*this), boost::bind (&Meterbridge::sync_order_keys, this, _1), gui_context()); MeterStrip::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Meterbridge::remove_strip, this, _1), gui_context()); - MeterStrip::ResetAllPeakDisplays.connect_same_thread (*this, boost::bind(&Meterbridge::reset_all_peaks, this)); - MeterStrip::ResetGroupPeakDisplays.connect_same_thread (*this, boost::bind (&Meterbridge::reset_group_peaks, this, _1)); - MeterStrip::MetricChanged.connect_same_thread (*this, boost::bind(&Meterbridge::update_metrics, this)); + MeterStrip::MetricChanged.connect (*this, invalidator (*this), boost::bind(&Meterbridge::resync_order, this), gui_context()); + MeterStrip::ConfigurationChanged.connect (*this, invalidator (*this), boost::bind(&Meterbridge::queue_resize, this), gui_context()); /* work around ScrolledWindowViewport alignment mess Part one */ Gtk::HBox * yspc = manage (new Gtk::HBox()); @@ -200,10 +169,18 @@ Meterbridge::Meterbridge () Gtk::Viewport* viewport = (Gtk::Viewport*) scroller.get_child(); viewport->set_shadow_type(Gtk::SHADOW_NONE); viewport->set_border_width(0); + + UI::instance()->theme_changed.connect (sigc::mem_fun(*this, &Meterbridge::on_theme_changed)); + UIConfiguration::instance().ColorsChanged.connect (sigc::mem_fun (*this, &Meterbridge::on_theme_changed)); + UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &Meterbridge::on_theme_changed)); } Meterbridge::~Meterbridge () { + while (_metrics.size() > 0) { + delete (_metrics.back()); + _metrics.pop_back(); + } } void @@ -265,6 +242,7 @@ Meterbridge::get_window_pos_and_size () bool Meterbridge::hide_window (GdkEventAny *ev) { + if (!_visible) return 0; get_window_pos_and_size(); _visible = false; return just_hide_it(ev, static_cast(this)); @@ -276,7 +254,7 @@ Meterbridge::on_key_press_event (GdkEventKey* ev) if (gtk_window_propagate_key_event (GTK_WINDOW(gobj()), ev)) { return true; } - return forward_key_press (ev); + return relay_key_press (ev, this); } bool @@ -289,10 +267,76 @@ Meterbridge::on_key_release_event (GdkEventKey* ev) return true; } +bool +Meterbridge::on_scroll_event (GdkEventScroll* ev) +{ + switch (ev->direction) { + case GDK_SCROLL_LEFT: + scroll_left (); + return true; + case GDK_SCROLL_UP: + if (ev->state & Keyboard::TertiaryModifier) { + scroll_left (); + return true; + } + return false; + + case GDK_SCROLL_RIGHT: + scroll_right (); + return true; + + case GDK_SCROLL_DOWN: + if (ev->state & Keyboard::TertiaryModifier) { + scroll_right (); + return true; + } + return false; + } + + return false; +} + +void +Meterbridge::scroll_left () +{ + if (!scroller.get_hscrollbar()) return; + Adjustment* adj = scroller.get_hscrollbar()->get_adjustment(); + /* stupid GTK: can't rely on clamping across versions */ + scroller.get_hscrollbar()->set_value (max (adj->get_lower(), adj->get_value() - adj->get_step_increment())); +} + +void +Meterbridge::scroll_right () +{ + if (!scroller.get_hscrollbar()) return; + Adjustment* adj = scroller.get_hscrollbar()->get_adjustment(); + /* stupid GTK: can't rely on clamping across versions */ + scroller.get_hscrollbar()->set_value (min (adj->get_upper(), adj->get_value() + adj->get_step_increment())); +} + void Meterbridge::on_size_request (Gtk::Requisition* r) { + meter_clear_pattern_cache(3); Gtk::Window::on_size_request(r); + + Gdk::Geometry geom; + Gtk::Requisition mr = meterarea.size_request(); + + geom.max_width = mr.width + metrics_left.get_width() + metrics_right.get_width(); + geom.max_width = std::max(50, geom.max_width); + geom.max_height = max_height; + + if (cur_max_width != geom.max_width) { + cur_max_width = geom.max_width; + /* height resizes are 'heavy' since the metric areas and meter-patterns + * are re-generated. limit to 16px steps. */ + geom.height_inc = 16; + geom.width_inc = 1; + geom.min_width = 40; + geom.min_height = -1; + set_geometry_hints(*((Gtk::Window*) this), geom, Gdk::HINT_MIN_SIZE | Gdk::HINT_MAX_SIZE | Gdk::HINT_RESIZE_INC); + } } void @@ -300,18 +344,16 @@ Meterbridge::on_size_allocate (Gtk::Allocation& a) { const Gtk::Scrollbar * hsc = scroller.get_hscrollbar(); + /* switch left/right edge patterns depending on horizontal scroll-position */ if (scroller.get_hscrollbar_visible() && hsc) { + if (!scroll_connection.connected()) { + scroll_connection = scroller.get_hscrollbar()->get_adjustment()->signal_value_changed().connect(sigc::mem_fun (*this, &Meterbridge::on_scroll)); + scroller.get_hscrollbar()->get_adjustment()->signal_changed().connect(sigc::mem_fun (*this, &Meterbridge::on_scroll)); + } gint scrollbar_spacing; gtk_widget_style_get (GTK_WIDGET (scroller.gobj()), "scrollbar-spacing", &scrollbar_spacing, NULL); const int h = hsc->get_height() + scrollbar_spacing + 1; -#if 1 // debug - Gtk::Viewport* viewport = (Gtk::Viewport*) scroller.get_child(); - if (get_height() - viewport->get_height() != h) { - printf("scrollbar height vs win-view height: %d vs %d\n", - h, get_height() - viewport->get_height()); - } -#endif metrics_spacer_left.set_size_request(-1, h); metrics_spacer_right.set_size_request(-1, h); } else { @@ -321,6 +363,57 @@ Meterbridge::on_size_allocate (Gtk::Allocation& a) Gtk::Window::on_size_allocate(a); } +void +Meterbridge::on_scroll() +{ + if (!scroller.get_hscrollbar()) return; + + Adjustment* adj = scroller.get_hscrollbar()->get_adjustment(); + int leftend = adj->get_value(); + int rightend = scroller.get_width() + leftend; + + int mm_left = _mm_left; + int mm_right = _mm_right; + ARDOUR::MeterType mt_left = _mt_left; + ARDOUR::MeterType mt_right = _mt_right; + + for (unsigned int i = 0; i < _metrics.size(); ++i) { + int sx, dx = 0, dy = 0; + int mm = _metrics[i]->get_metric_mode(); + sx = (mm & 2) ? _metrics[i]->get_width() : 0; + + _metrics[i]->translate_coordinates(meterarea, sx, 0, dx, dy); + + if (dx < leftend && !(mm&2)) { + mm_left = mm; + mt_left = _metrics[i]->meter_type(); + } + if (dx > rightend && (mm&2)) { + mm_right = mm; + mt_right = _metrics[i]->meter_type(); + break; + } + } + metrics_left.set_metric_mode(mm_left, mt_left); + metrics_right.set_metric_mode(mm_right, mt_right); +} + +struct PresentationInfoRouteSorter +{ + bool operator() (boost::shared_ptr a, boost::shared_ptr b) { + if (a->is_master() || a->is_monitor()) { + /* "a" is a special route (master, monitor, etc), and comes + * last in the mixer ordering + */ + return false; + } else if (b->is_master() || b->is_monitor()) { + /* everything comes before b */ + return true; + } + return a->presentation_info().order() < b->presentation_info().order(); + } +}; + void Meterbridge::set_session (Session* s) { @@ -330,29 +423,34 @@ Meterbridge::set_session (Session* s) return; } + metrics_left.set_session(s); + metrics_right.set_session(s); + XMLNode* node = _session->instant_xml(X_("Meterbridge")); if (node) { set_state (*node); } update_title (); - _show_busses = _session->config.get_show_busses_in_meterbridge(); + _show_busses = _session->config.get_show_busses_on_meterbridge(); + _show_master = _session->config.get_show_master_on_meterbridge(); + _show_midi = _session->config.get_show_midi_on_meterbridge(); - SignalOrderRouteSorter sorter; boost::shared_ptr routes = _session->get_routes(); - RouteList copy(*routes); - copy.sort(sorter); - add_strips(copy); + RouteList copy (*routes); + copy.sort (PresentationInfoRouteSorter()); + add_strips (copy); _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Meterbridge::add_strips, this, _1), gui_context()); _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Meterbridge::update_title, this), gui_context()); _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Meterbridge::update_title, this), gui_context()); _session->config.ParameterChanged.connect (*this, invalidator (*this), ui_bind (&Meterbridge::parameter_changed, this, _1), gui_context()); + Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&Meterbridge::parameter_changed, this, _1), gui_context()); if (_visible) { show_window(); - ActionManager::check_toggleaction ("/Common/toggle-meterbridge"); + present (); } start_updating (); } @@ -362,8 +460,8 @@ Meterbridge::session_going_away () { ENSURE_GUI_THREAD (*this, &Meterbridge::session_going_away); - for (list::iterator i = strips.begin(); i != strips.end(); ++i) { - delete (*i); + for (list::iterator i = strips.begin(); i != strips.end(); ++i) { + delete ((*i).s); } strips.clear (); @@ -378,7 +476,7 @@ Meterbridge::session_going_away () int Meterbridge::set_state (const XMLNode& node) { - const XMLProperty* prop; + XMLProperty const * prop; XMLNode* geometry; m_width = default_width; @@ -388,7 +486,7 @@ Meterbridge::set_state (const XMLNode& node) if ((geometry = find_named_node (node, "geometry")) != 0) { - XMLProperty* prop; + XMLProperty const * prop; if ((prop = geometry->property("x_size")) == 0) { prop = geometry->property ("x-size"); @@ -432,26 +530,24 @@ Meterbridge::set_state (const XMLNode& node) XMLNode& Meterbridge::get_state (void) { + char buf[32]; XMLNode* node = new XMLNode ("Meterbridge"); - if (is_realized()) { - Glib::RefPtr win = get_window(); - + if (is_realized() && _visible) { get_window_pos_and_size (); - - XMLNode* geometry = new XMLNode ("geometry"); - char buf[32]; - snprintf(buf, sizeof(buf), "%d", m_width); - geometry->add_property(X_("x_size"), string(buf)); - snprintf(buf, sizeof(buf), "%d", m_height); - geometry->add_property(X_("y_size"), string(buf)); - snprintf(buf, sizeof(buf), "%d", m_root_x); - geometry->add_property(X_("x_pos"), string(buf)); - snprintf(buf, sizeof(buf), "%d", m_root_y); - geometry->add_property(X_("y_pos"), string(buf)); - node->add_child_nocopy (*geometry); } + XMLNode* geometry = new XMLNode ("geometry"); + snprintf(buf, sizeof(buf), "%d", m_width); + geometry->add_property(X_("x_size"), string(buf)); + snprintf(buf, sizeof(buf), "%d", m_height); + geometry->add_property(X_("y_size"), string(buf)); + snprintf(buf, sizeof(buf), "%d", m_root_x); + geometry->add_property(X_("x_pos"), string(buf)); + snprintf(buf, sizeof(buf), "%d", m_root_y); + geometry->add_property(X_("y_pos"), string(buf)); + node->add_child_nocopy (*geometry); + node->add_property ("show-meterbridge", _visible ? "yes" : "no"); return *node; } @@ -460,7 +556,7 @@ Meterbridge::get_state (void) gint Meterbridge::start_updating () { - fast_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &Meterbridge::fast_update_strips)); + fast_screen_update_connection = Timers::super_rapid_connect (sigc::mem_fun(*this, &Meterbridge::fast_update_strips)); return 0; } @@ -477,8 +573,9 @@ Meterbridge::fast_update_strips () if (!is_mapped () || !_session) { return; } - for (list::iterator i = strips.begin(); i != strips.end(); ++i) { - (*i)->fast_update (); + for (list::iterator i = strips.begin(); i != strips.end(); ++i) { + if (!(*i).visible) continue; + (*i).s->fast_update (); } } @@ -496,14 +593,14 @@ Meterbridge::add_strips (RouteList& routes) } strip = new MeterStrip (_session, route); - strips.push_back (strip); + strips.push_back (MeterBridgeStrip(strip)); + route->active_changed.connect (*this, invalidator (*this), boost::bind (&Meterbridge::resync_order, this), gui_context ()); meterarea.pack_start (*strip, false, false); strip->show(); } - sync_order_keys(MixerSort); - update_metrics(); + resync_order(); } void @@ -513,93 +610,203 @@ Meterbridge::remove_strip (MeterStrip* strip) return; } - list::iterator i; - if ((i = find (strips.begin(), strips.end(), strip)) != strips.end()) { - strips.erase (i); - } - update_metrics(); -} - -void -Meterbridge::update_metrics () -{ - bool have_midi = false; - for (list::iterator i = strips.begin(); i != strips.end(); ++i) { - if ( (*i)->has_midi ()) { - have_midi = true; + list::iterator i; + for (list::iterator i = strips.begin(); i != strips.end(); ++i) { + if ( (*i).s == strip) { + strips.erase (i); break; } } - if (have_midi) { - metrics_right.set_metric_mode(3); - } else { - metrics_right.set_metric_mode(4); - } -} -void -Meterbridge::reset_all_peaks () -{ - for (list::iterator i = strips.begin(); i != strips.end(); ++i) { - (*i)->reset_peak_display (); - } + resync_order(); } void -Meterbridge::reset_group_peaks (RouteGroup* rg) +Meterbridge::sync_order_keys () { - for (list::iterator i = strips.begin(); i != strips.end(); ++i) { - (*i)->reset_group_peak_display (rg); - } -} + Glib::Threads::Mutex::Lock lm (_resync_mutex); -void -Meterbridge::sync_order_keys (RouteSortOrderKey src) -{ MeterOrderRouteSorter sorter; - std::list copy (strips); - copy.sort(sorter); + strips.sort(sorter); int pos = 0; + int vis = 0; + MeterStrip * last = 0; - for (list::iterator i = copy.begin(); i != copy.end(); ++i) { + unsigned int metrics = 0; + MeterType lmt = MeterPeak; + bool have_midi = false; + metrics_left.set_metric_mode(1, lmt); -#if 0 // TODO subscribe to route active,inactive changes, merge w/ bus - if (! (*i)->route()->active()) { - (*i)->hide(); - } else { - (*i)->show(); - } -#endif + for (list::iterator i = strips.begin(); i != strips.end(); ++i) { - // TODO simplyfy, abstract ->is_bus() - if ((*i)->route()->is_master()) { - /* always show master */ - (*i)->show(); + if (! (*i).s->route()->active()) { + (*i).s->hide(); + (*i).visible = false; } - else if (boost::dynamic_pointer_cast((*i)->route()) == 0 - && boost::dynamic_pointer_cast((*i)->route()) == 0 + else if ((*i).s->route()->is_master()) { + if (_show_master) { + (*i).s->show(); + (*i).visible = true; + vis++; + } else { + (*i).s->hide(); + (*i).visible = false; + } + } + else if (boost::dynamic_pointer_cast((*i).s->route()) == 0 + && boost::dynamic_pointer_cast((*i).s->route()) == 0 ) { /* non-master bus */ if (_show_busses) { - (*i)->show(); + (*i).s->show(); + (*i).visible = true; + vis++; + } else { + (*i).s->hide(); + (*i).visible = false; + } + } + else if (boost::dynamic_pointer_cast((*i).s->route())) { + if (_show_midi) { + (*i).s->show(); + (*i).visible = true; + vis++; } else { - (*i)->hide(); + (*i).s->hide(); + (*i).visible = false; } } else { - (*i)->show(); + (*i).s->show(); + (*i).visible = true; + vis++; + } + + (*i).s->set_tick_bar(0); + + MeterType nmt = (*i).s->meter_type(); + if (nmt == MeterKrms) nmt = MeterPeak; // identical metrics + if (vis == 1) { + (*i).s->set_tick_bar(1); + } + + if ((*i).visible && nmt != lmt && vis == 1) { + lmt = nmt; + metrics_left.set_metric_mode(1, lmt); + } else if ((*i).visible && nmt != lmt) { + + if (last) { + last->set_tick_bar(last->get_tick_bar() | 2); + } + (*i).s->set_tick_bar((*i).s->get_tick_bar() | 1); + + if (_metrics.size() <= metrics) { + _metrics.push_back(new MeterStrip(have_midi ? 2 : 3, lmt)); + meterarea.pack_start (*_metrics[metrics], false, false); + _metrics[metrics]->set_session(_session); + _metrics[metrics]->show(); + } else { + _metrics[metrics]->set_metric_mode(have_midi ? 2 : 3, lmt); + } + meterarea.reorder_child(*_metrics[metrics], pos++); + metrics++; + + lmt = nmt; + + if (_metrics.size() <= metrics) { + _metrics.push_back(new MeterStrip(1, lmt)); + meterarea.pack_start (*_metrics[metrics], false, false); + _metrics[metrics]->set_session(_session); + _metrics[metrics]->show(); + } else { + _metrics[metrics]->set_metric_mode(1, lmt); + } + meterarea.reorder_child(*_metrics[metrics], pos++); + metrics++; + have_midi = false; } - meterarea.reorder_child(*(*i), pos++); + if ((*i).visible && (*i).s->has_midi()) { + have_midi = true; + } + + meterarea.reorder_child(*((*i).s), pos++); + if ((*i).visible) { + last = (*i).s; + } + } + + if (last) { + last->set_tick_bar(last->get_tick_bar() | 2); } + + metrics_right.set_metric_mode(have_midi ? 2 : 3, lmt); + + while (_metrics.size() > metrics) { + meterarea.remove(*_metrics.back()); + delete (_metrics.back()); + _metrics.pop_back(); + } + + _mm_left = metrics_left.get_metric_mode(); + _mt_left = metrics_left.meter_type(); + _mm_right = metrics_right.get_metric_mode(); + _mt_right = metrics_right.meter_type(); + + on_scroll(); + queue_resize(); +} + +void +Meterbridge::resync_order() +{ + sync_order_keys(); } void Meterbridge::parameter_changed (std::string const & p) { - if (p == "show-busses-in-meterbridge") { - _show_busses = _session->config.get_show_busses_in_meterbridge(); - sync_order_keys(MixerSort); + if (p == "show-busses-on-meterbridge") { + _show_busses = _session->config.get_show_busses_on_meterbridge(); + resync_order(); + } + else if (p == "show-master-on-meterbridge") { + _show_master = _session->config.get_show_master_on_meterbridge(); + resync_order(); + } + else if (p == "show-midi-on-meterbridge") { + _show_midi = _session->config.get_show_midi_on_meterbridge(); + resync_order(); + } + else if (p == "meter-line-up-level") { + meter_clear_pattern_cache(); + } + else if (p == "show-rec-on-meterbridge") { + scroller.queue_resize(); + } + else if (p == "show-mute-on-meterbridge") { + scroller.queue_resize(); } + else if (p == "show-solo-on-meterbridge") { + scroller.queue_resize(); + } + else if (p == "show-name-on-meterbridge") { + scroller.queue_resize(); + } + else if (p == "meterbridge-label-height") { + scroller.queue_resize(); + } + else if (p == "show-monitor-on-meterbridge") { + scroller.queue_resize(); + } + else if (p == "track-name-number") { + scroller.queue_resize(); + } +} + +void +Meterbridge::on_theme_changed () +{ + meter_clear_pattern_cache(); }