Fix thinko with dragging one of >1 tabs in the same
[ardour.git] / gtk2_ardour / group_tabs.cc
index 297698e85c9d27e14d27bc1e4f8ab6b19de9ef41..4f194235e286251bad682b40220cabd0f79fb9f9 100644 (file)
 #include "group_tabs.h"
 #include "keyboard.h"
 #include "i18n.h"
+#include "ardour_ui.h"
+#include "utils.h"
 
 using namespace std;
 using namespace Gtk;
 using namespace ARDOUR;
 using Gtkmm2ext::Keyboard;
 
+list<Gdk::Color> GroupTabs::_used_colors;
+
 GroupTabs::GroupTabs ()
        : _menu (0)
        , _dragging (0)
@@ -97,7 +101,7 @@ GroupTabs::on_button_press_event (GdkEventButton* ev)
                                list<Tab>::iterator j = _tabs.insert (next, n);
                                t = &(*j);
                        }
-                       
+
                } else {
                        _dragging_new_tab = false;
                }
@@ -169,18 +173,18 @@ GroupTabs::on_button_release_event (GdkEventButton* ev)
        if (!_drag_moved) {
 
                if (_dragging->group) {
-                       
+
                        if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
-                               
+
                                /* edit */
                                RouteGroupDialog d (_dragging->group, false);
                                d.do_run ();
-                               
+
                        } else {
-                               
+
                                /* toggle active state */
                                _dragging->group->set_active (!_dragging->group->is_active (), this);
-                               
+
                        }
                }
 
@@ -201,8 +205,9 @@ GroupTabs::on_button_release_event (GdkEventButton* ev)
                                for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
 
                                        if (find (routes.begin(), routes.end(), *i) == routes.end()) {
-                                               /* this route is not on the list of those that should be in _dragging's group */
-                                               if ((*i)->route_group() == _dragging->group) {
+                                               /* this route is not contained in the tab we are dragging ... */
+                                               if ((*i)->route_group() != _dragging->group) {
+                                                       /* and it's not in the dragged tab's group either */
                                                        _dragging->group->remove (*i);
                                                }
                                        } else {
@@ -244,8 +249,8 @@ GroupTabs::render (cairo_t* cr)
 
 /** Convert a click position to a tab.
  *  @param c Click position.
- *  @param prev Filled in with the previous tab to the click, or 0.
- *  @param next Filled in with the next tab after the click, or 0.
+ *  @param prev Filled in with the previous tab to the click, or _tabs.end().
+ *  @param next Filled in with the next tab after the click, or _tabs.end().
  *  @return Tab under the click, or 0.
  */
 
@@ -259,6 +264,7 @@ GroupTabs::click_to_tab (double c, list<Tab>::iterator* prev, list<Tab>::iterato
        while (i != _tabs.end()) {
 
                if (i->from > c) {
+                       *next = i;
                        break;
                }
 
@@ -275,14 +281,6 @@ GroupTabs::click_to_tab (double c, list<Tab>::iterator* prev, list<Tab>::iterato
                ++i;
        }
 
-       if (i != _tabs.end()) {
-               *next = i;
-
-               if (under) {
-                       (*next)++;
-               }
-       }
-
        return under;
 }
 
@@ -305,7 +303,7 @@ GroupTabs::get_menu (RouteGroup* g)
 
        items.push_back (MenuElem (_("New..."), hide_return (sigc::mem_fun(*this, &GroupTabs::create_and_add_group))));
        items.push_back (MenuElem (_("New From"), *new_from));
-       
+
        if (g) {
                items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &GroupTabs::edit_group), g)));
                items.push_back (MenuElem (_("Add New Subgroup Bus"), sigc::bind (sigc::mem_fun (*this, &GroupTabs::subgroup), g, false, PreFader)));
@@ -316,13 +314,13 @@ GroupTabs::get_menu (RouteGroup* g)
        }
 
        add_menu_items (_menu, g);
-       
+
        items.push_back (SeparatorElem());
        items.push_back (MenuElem (_("Activate All"), sigc::mem_fun(*this, &GroupTabs::activate_all)));
        items.push_back (MenuElem (_("Disable All"), sigc::mem_fun(*this, &GroupTabs::disable_all)));
 
        return _menu;
-       
+
 }
 
 void
@@ -407,7 +405,7 @@ GroupTabs::create_and_add_group () const
                delete g;
                return 0;
        }
-       
+
        _session->add_route_group (g);
        return g;
 }
@@ -427,7 +425,7 @@ GroupTabs::subgroup (RouteGroup* g, bool aux, Placement placement)
 
 struct CollectSorter {
        CollectSorter (std::string const & key) : _key (key) {}
-       
+
        bool operator () (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
                return a->order_key (_key) < b->order_key (_key);
        }
@@ -470,9 +468,9 @@ GroupTabs::collect (RouteGroup* g)
                        ++i;
 
                } else {
-                       
+
                        (*j)->set_order_key (order_key (), k + diff);
-                       
+
                }
 
                ++j;
@@ -502,9 +500,76 @@ GroupTabs::set_activation (RouteGroup* g, bool a)
 {
        g->set_active (a, this);
 }
-       
+
 void
 GroupTabs::remove_group (RouteGroup* g)
 {
        _session->remove_route_group (*g);
 }
+
+/** Set the color of the tab of a route group */
+void
+GroupTabs::set_group_color (RouteGroup* group, Gdk::Color color)
+{
+       assert (group);
+       
+       GUIObjectState& gui_state = *ARDOUR_UI::instance()->gui_object_state;
+
+       char buf[64];
+       snprintf (buf, sizeof (buf), "%d:%d:%d", color.get_red(), color.get_green(), color.get_blue());
+       gui_state.set (group_gui_id (group), "color", buf);
+
+       /* This is a bit of a hack, but this might change
+          our route's effective color, so emit gui_changed
+          for our routes.
+       */
+
+       for (RouteList::iterator i = group->route_list()->begin(); i != group->route_list()->end(); ++i) {
+               (*i)->gui_changed (X_("color"), 0);
+       }
+}
+
+/** @return the ID string to use for the GUI state of a route group */
+string
+GroupTabs::group_gui_id (RouteGroup* group)
+{
+       assert (group);
+
+       char buf[64];
+       snprintf (buf, sizeof (buf), "route_group %s", group->id().to_s().c_str ());
+
+       return buf;
+}
+
+/** @return the color to use for a route group tab */
+Gdk::Color
+GroupTabs::group_color (RouteGroup* group)
+{
+       assert (group);
+       
+       GUIObjectState& gui_state = *ARDOUR_UI::instance()->gui_object_state;
+
+       string const gui_id = group_gui_id (group);
+
+       bool empty;
+       string const color = gui_state.get_string (gui_id, "color", &empty);
+       if (empty) {
+               /* no color has yet been set, so use a random one */
+               Gdk::Color const color = unique_random_color (_used_colors);
+               set_group_color (group, color);
+               return color;
+       }
+
+       Gdk::Color c;
+
+       int r, g, b;
+
+       sscanf (color.c_str(), "%d:%d:%d", &r, &g, &b);
+
+       c.set_red (r);
+       c.set_green (g);
+       c.set_blue (b);
+       
+       return c;
+}
+