diff --git a/gtk2_ardour/axis_view.cc b/gtk2_ardour/axis_view.cc index 6aec4c62eb..1144fb1e68 100644 --- a/gtk2_ardour/axis_view.cc +++ b/gtk2_ardour/axis_view.cc @@ -38,6 +38,7 @@ #include "ardour_ui.h" #include "gui_object.h" #include "axis_view.h" +#include "utils.h" #include "i18n.h" using namespace std; @@ -60,41 +61,7 @@ AxisView::~AxisView() Gdk::Color AxisView::unique_random_color() { - Gdk::Color newcolor; - - while (1) { - - /* avoid neon/glowing tones by limiting them to the - "inner section" (paler) of a color wheel/circle. - */ - - const int32_t max_saturation = 48000; // 65535 would open up the whole color wheel - - newcolor.set_red (random() % max_saturation); - newcolor.set_blue (random() % max_saturation); - newcolor.set_green (random() % max_saturation); - - if (used_colors.size() == 0) { - used_colors.push_back (newcolor); - return newcolor; - } - - for (list::iterator i = used_colors.begin(); i != used_colors.end(); ++i) { - Gdk::Color c = *i; - float rdelta, bdelta, gdelta; - - rdelta = newcolor.get_red() - c.get_red(); - bdelta = newcolor.get_blue() - c.get_blue(); - gdelta = newcolor.get_green() - c.get_green(); - - if (sqrt (rdelta*rdelta + bdelta*bdelta + gdelta*gdelta) > 25.0) { - used_colors.push_back (newcolor); - return newcolor; - } - } - - /* XXX need throttle here to make sure we don't spin for ever */ - } + return ::unique_random_color (used_colors); } string diff --git a/gtk2_ardour/editor_group_tabs.cc b/gtk2_ardour/editor_group_tabs.cc index d98c064bff..9b21432fef 100644 --- a/gtk2_ardour/editor_group_tabs.cc +++ b/gtk2_ardour/editor_group_tabs.cc @@ -61,7 +61,9 @@ EditorGroupTabs::compute_tabs () const tab.from = y; tab.group = g; - tab.colour = (*i)->color (); + if (g) { + tab.color = group_color (g); + } } y += (*i)->effective_height (); @@ -81,7 +83,7 @@ EditorGroupTabs::draw_tab (cairo_t* cr, Tab const & tab) const double const arc_radius = _width; if (tab.group && tab.group->is_active()) { - cairo_set_source_rgba (cr, tab.colour.get_red_p (), tab.colour.get_green_p (), tab.colour.get_blue_p (), 1); + cairo_set_source_rgba (cr, tab.color.get_red_p (), tab.color.get_green_p (), tab.color.get_blue_p (), 1); } else { cairo_set_source_rgba (cr, 1, 1, 1, 0.2); } diff --git a/gtk2_ardour/group_tabs.cc b/gtk2_ardour/group_tabs.cc index ab4dcd1923..ec80bc4291 100644 --- a/gtk2_ardour/group_tabs.cc +++ b/gtk2_ardour/group_tabs.cc @@ -27,12 +27,16 @@ #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 GroupTabs::_used_colors; + GroupTabs::GroupTabs () : _menu (0) , _dragging (0) @@ -501,3 +505,61 @@ 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); +} + +/** @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; +} + diff --git a/gtk2_ardour/group_tabs.h b/gtk2_ardour/group_tabs.h index 7362067251..ed4a24709f 100644 --- a/gtk2_ardour/group_tabs.h +++ b/gtk2_ardour/group_tabs.h @@ -28,7 +28,7 @@ namespace ARDOUR { class Editor; -/** Parent class for tabs which represent route groups as coloured tabs; +/** Parent class for tabs which represent route groups as colored tabs; * Currently used on the left-hand side of the editor and at the top of the mixer. */ class GroupTabs : public CairoWidget, public ARDOUR::SessionHandlePtr @@ -46,6 +46,10 @@ public: void run_new_group_dialog (ARDOUR::RouteList const &); + static void set_group_color (ARDOUR::RouteGroup *, Gdk::Color); + static std::string group_gui_id (ARDOUR::RouteGroup *); + static Gdk::Color group_color (ARDOUR::RouteGroup *); + protected: struct Tab { @@ -53,7 +57,7 @@ protected: double from; double to; - Gdk::Color colour; ///< colour + Gdk::Color color; ///< color ARDOUR::RouteGroup* group; ///< route group }; @@ -117,4 +121,7 @@ private: double _drag_min; ///< minimum position for drag double _drag_max; ///< maximum position for drag double _drag_first; ///< first mouse pointer position during drag + + /** colors that have been used for new route group tabs */ + static std::list _used_colors; }; diff --git a/gtk2_ardour/mixer_group_tabs.cc b/gtk2_ardour/mixer_group_tabs.cc index 6c97a8f043..b74455b28d 100644 --- a/gtk2_ardour/mixer_group_tabs.cc +++ b/gtk2_ardour/mixer_group_tabs.cc @@ -67,7 +67,10 @@ MixerGroupTabs::compute_tabs () const tab.from = x; tab.group = g; - tab.colour = s->color (); + + if (g) { + tab.color = group_color (g); + } } x += s->get_width (); @@ -87,7 +90,7 @@ MixerGroupTabs::draw_tab (cairo_t* cr, Tab const & tab) const double const arc_radius = _height; if (tab.group && tab.group->is_active()) { - cairo_set_source_rgba (cr, tab.colour.get_red_p (), tab.colour.get_green_p (), tab.colour.get_blue_p (), 1); + cairo_set_source_rgba (cr, tab.color.get_red_p (), tab.color.get_green_p (), tab.color.get_blue_p (), 1); } else { cairo_set_source_rgba (cr, 1, 1, 1, 0.2); } diff --git a/gtk2_ardour/route_group_dialog.cc b/gtk2_ardour/route_group_dialog.cc index 9d58ea816c..acc4eefbcc 100644 --- a/gtk2_ardour/route_group_dialog.cc +++ b/gtk2_ardour/route_group_dialog.cc @@ -23,6 +23,7 @@ #include "ardour/route_group.h" #include "ardour/session.h" #include "route_group_dialog.h" +#include "group_tabs.h" #include "i18n.h" #include @@ -94,6 +95,7 @@ RouteGroupDialog::RouteGroupDialog (RouteGroup* g, bool creating_new) _select.set_active (_group->is_select()); _edit.set_active (_group->is_edit()); _route_active.set_active (_group->is_route_active()); + _color.set_color (GroupTabs::group_color (_group)); _name.signal_changed().connect (sigc::mem_fun (*this, &RouteGroupDialog::update)); _active.signal_toggled().connect (sigc::mem_fun (*this, &RouteGroupDialog::update)); @@ -105,10 +107,11 @@ RouteGroupDialog::RouteGroupDialog (RouteGroup* g, bool creating_new) _select.signal_toggled().connect (sigc::mem_fun (*this, &RouteGroupDialog::update)); _edit.signal_toggled().connect (sigc::mem_fun (*this, &RouteGroupDialog::update)); _route_active.signal_toggled().connect (sigc::mem_fun (*this, &RouteGroupDialog::update)); + _color.signal_color_set().connect (sigc::mem_fun (*this, &RouteGroupDialog::update)); gain_toggled (); - Table* table = manage (new Table (8, 3, false)); + Table* table = manage (new Table (11, 4, false)); table->set_row_spacings (6); l = manage (new Label ("", Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); @@ -129,6 +132,12 @@ RouteGroupDialog::RouteGroupDialog (RouteGroup* g, bool creating_new) table->attach (_edit, 1, 3, 7, 8, Gtk::FILL, Gtk::FILL, 0, 0); table->attach (_route_active, 1, 3, 8, 9, Gtk::FILL, Gtk::FILL, 0, 0); + HBox* b = manage (new HBox); + l = manage (new Label (_("Color"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); + b->pack_start (*l, Gtk::SHRINK, Gtk::SHRINK); + b->pack_start (_color, Gtk::FILL, Gtk::FILL); + table->attach (*b, 1, 3, 10, 11, Gtk::FILL, Gtk::FILL, 0, 0); + options_box->pack_start (*table, false, true); main_vbox->pack_start (*options_box, false, true); @@ -196,6 +205,8 @@ RouteGroupDialog::update () plist.add (Properties::active, _active.get_active()); plist.add (Properties::name, string (_name.get_text())); + GroupTabs::set_group_color (_group, _color.get_color ()); + _group->apply_changes (plist); } diff --git a/gtk2_ardour/route_group_dialog.h b/gtk2_ardour/route_group_dialog.h index 712f463a87..9fa242f7e0 100644 --- a/gtk2_ardour/route_group_dialog.h +++ b/gtk2_ardour/route_group_dialog.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "ardour_dialog.h" @@ -48,6 +49,7 @@ private: Gtk::CheckButton _edit; Gtk::CheckButton _route_active; Gtk::Button* _ok; + Gtk::ColorButton _color; void gain_toggled (); void update (); diff --git a/gtk2_ardour/utils.cc b/gtk2_ardour/utils.cc index add148d0b0..7c71170307 100644 --- a/gtk2_ardour/utils.cc +++ b/gtk2_ardour/utils.cc @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -938,4 +939,42 @@ escape_underscores (string const & s) return o; } +Gdk::Color +unique_random_color (list& used_colors) +{ + Gdk::Color newcolor; + while (1) { + + /* avoid neon/glowing tones by limiting them to the + "inner section" (paler) of a color wheel/circle. + */ + + const int32_t max_saturation = 48000; // 65535 would open up the whole color wheel + + newcolor.set_red (random() % max_saturation); + newcolor.set_blue (random() % max_saturation); + newcolor.set_green (random() % max_saturation); + + if (used_colors.size() == 0) { + used_colors.push_back (newcolor); + return newcolor; + } + + for (list::iterator i = used_colors.begin(); i != used_colors.end(); ++i) { + Gdk::Color c = *i; + float rdelta, bdelta, gdelta; + + rdelta = newcolor.get_red() - c.get_red(); + bdelta = newcolor.get_blue() - c.get_blue(); + gdelta = newcolor.get_green() - c.get_green(); + + if (sqrt (rdelta*rdelta + bdelta*bdelta + gdelta*gdelta) > 25.0) { + used_colors.push_back (newcolor); + return newcolor; + } + } + + /* XXX need throttle here to make sure we don't spin for ever */ + } +} diff --git a/gtk2_ardour/utils.h b/gtk2_ardour/utils.h index c019989d94..d511b0e718 100644 --- a/gtk2_ardour/utils.h +++ b/gtk2_ardour/utils.h @@ -91,4 +91,6 @@ void resize_window_to_proportion_of_monitor (Gtk::Window*, int, int); std::string escape_underscores (std::string const &); +Gdk::Color unique_random_color (std::list &); + #endif /* __ardour_gtk_utils_h__ */ diff --git a/libs/ardour/route_group.cc b/libs/ardour/route_group.cc index 7352112217..ef7e218d67 100644 --- a/libs/ardour/route_group.cc +++ b/libs/ardour/route_group.cc @@ -213,10 +213,14 @@ RouteGroup::get_max_factor(gain_t factor) } XMLNode& -RouteGroup::get_state (void) +RouteGroup::get_state () { XMLNode *node = new XMLNode ("RouteGroup"); + char buf[64]; + id().print (buf, sizeof (buf)); + node->add_property ("id", buf); + add_properties (*node); if (!routes->empty()) { @@ -239,10 +243,14 @@ RouteGroup::set_state (const XMLNode& node, int version) return set_state_2X (node, version); } - set_values (node); - const XMLProperty *prop; + if ((prop = node.property ("id")) != 0) { + _id = prop->value(); + } + + set_values (node); + if ((prop = node.property ("routes")) != 0) { stringstream str (prop->value()); vector ids;