Enable Menu > Quit to work again after startup on macOS
[ardour.git] / gtk2_ardour / visibility_group.cc
index c817ff3fcb1dba86429d0c98ea075bc8d24fdcc9..bd4f2cda8b68208c50086b3992950bfdb1a5c982 100644 (file)
@@ -1,30 +1,34 @@
 /*
-    Copyright (C) 2011 Paul Davis
   Author: Carl Hetherington <cth@carlh.net>
-
-    This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
+ * Copyright (C) 2011 Carl Hetherington <carl@carlh.net>
* Copyright (C) 2015-2019 Robin Gareus <robin@gareus.org>
+ * Copyright (C) 2016 Paul Davis <paul@linuxaudiosystems.com>
+ *
* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
 
 #include <gtkmm/menu.h>
 #include <gtkmm/menushell.h>
 #include <gtkmm/treeview.h>
+
+#include "pbd/strsplit.h"
 #include "pbd/xml++.h"
+
+#include "context_menu_helper.h"
 #include "visibility_group.h"
 
-#include "i18n.h"
+#include "pbd/i18n.h"
 
 using namespace std;
 
@@ -40,17 +44,21 @@ VisibilityGroup::VisibilityGroup (std::string const & name)
  *  @param id Some single-word ID to be used for the state of this member in XML.
  *  @param name User-visible name for the widget.
  *  @param visible true to default to visible, otherwise false.
+ *  @param override A functor to decide whether the visibility specified by the member should be
+ *  overridden by some external factor; if the returned optional value is given, it will be used
+ *  to override whatever visibility setting the member has.
  */
 
 void
-VisibilityGroup::add (Gtk::Widget* widget, string const & id, string const & name, bool visible)
+VisibilityGroup::add (Gtk::Widget* widget, string const & id, string const & name, bool visible, boost::function<boost::optional<bool> ()> override)
 {
        Member m;
        m.widget = widget;
        m.id = id;
        m.name = name;
        m.visible = visible;
-       
+       m.override = override;
+
        _members.push_back (m);
 }
 
@@ -62,16 +70,9 @@ VisibilityGroup::button_press_event (GdkEventButton* ev)
                return false;
        }
 
-       menu()->popup (1, ev->time);
-       return true;
-}
-
-Gtk::Menu*
-VisibilityGroup::menu ()
-{
        using namespace Gtk::Menu_Helpers;
 
-       Gtk::Menu* m = Gtk::manage (new Gtk::Menu);
+       Gtk::Menu* m = ARDOUR_UI_UTILS::shared_popup_menu ();
        MenuList& items = m->items ();
 
        for (vector<Member>::iterator i = _members.begin(); i != _members.end(); ++i) {
@@ -81,7 +82,23 @@ VisibilityGroup::menu ()
                j->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &VisibilityGroup::toggle), i));
        }
 
-       return m;
+       m->popup (1, ev->time);
+       return true;
+}
+
+
+/** @return true if the member should be visible, even taking into account any override functor */
+bool
+VisibilityGroup::should_actually_be_visible (Member const & m) const
+{
+       if (m.override) {
+               boost::optional<bool> o = m.override ();
+               if (o) {
+                       return o.get ();
+               }
+       }
+
+       return m.visible;
 }
 
 /** Update visible consequences of any changes to our _members vector */
@@ -90,7 +107,7 @@ VisibilityGroup::update ()
 {
        for (vector<Member>::iterator i = _members.begin(); i != _members.end(); ++i) {
                if (i->widget) {
-                       if (i->visible) {
+                       if (should_actually_be_visible (*i)) {
                                i->widget->show ();
                        } else {
                                i->widget->hide ();
@@ -143,12 +160,58 @@ VisibilityGroup::set_state (string v)
                }
 
                v = v.substr (comma + 1);
-               
+
        } while (1);
 
        update ();
 }
 
+string
+VisibilityGroup::remove_element (std::string const& from, std::string const& element)
+{
+       std::vector<string> s;
+       std::string ret;
+
+       split (from, s, ',');
+       for (std::vector<string>::const_iterator i = s.begin(); i != s.end(); ++i) {
+               if ((*i) == element) {
+                       continue;
+               }
+               if (!ret.empty()) {
+                       ret += ',';
+               }
+               ret += *i;
+       }
+
+       return ret;
+}
+
+string
+VisibilityGroup::add_element (std::string const& from, std::string const& element)
+{
+       std::vector<string> s;
+       std::string ret;
+       
+       split (from, s, ',');
+
+       for (std::vector<string>::const_iterator i = s.begin(); i != s.end(); ++i) {
+               if ((*i) == element) {
+                       /* already present, just return the original */
+                       return from;
+               }
+       }
+
+       ret = from;
+
+       if (!ret.empty()) {
+               ret += ',';
+       }
+
+       ret += element;
+
+       return ret;
+}
+
 string
 VisibilityGroup::get_state_name () const
 {
@@ -177,11 +240,11 @@ VisibilityGroup::update_list_view ()
        if (!_model) {
                return;
        }
-       
+
        _ignore_list_view_change = true;
 
        _model->clear ();
-       
+
        for (vector<Member>::iterator i = _members.begin(); i != _members.end(); ++i) {
                Gtk::TreeModel::iterator j = _model->append ();
                Gtk::TreeModel::Row row = *j;
@@ -202,8 +265,8 @@ VisibilityGroup::list_view ()
 
        Gtk::TreeView* v = Gtk::manage (new Gtk::TreeView (_model));
        v->set_headers_visible (false);
-       v->append_column (_(""), _model_columns._visible);
-       v->append_column (_(""), _model_columns._name);
+       v->append_column ("", _model_columns._visible);
+       v->append_column ("", _model_columns._name);
 
        Gtk::CellRendererToggle* visible_cell = dynamic_cast<Gtk::CellRendererToggle*> (v->get_column_cell_renderer (0));
        visible_cell->property_activatable() = true;
@@ -217,7 +280,7 @@ VisibilityGroup::list_view_visible_changed (string const & path)
        if (_ignore_list_view_change) {
                return;
        }
-       
+
        Gtk::TreeModel::iterator i = _model->get_iter (path);
        if (!i) {
                return;