map::clear() calls erase. Cleans up cpp check warning 'iterator used after element...
[ardour.git] / libs / gtkmm2ext / stateful_button.cc
index 074d0866511bcd0326c42574fd6f3c2f8ae193d9..3c1ad2a830e92d3c0ab77c039b54b0fa740e251d 100644 (file)
+/*
+    Copyright (C) 2000-2007 Paul Davis
+
+    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.
+
+*/
+
 #include <string>
 #include <iostream>
-#include "gtkmm2ext/stateful_button.h"
+
+
+#include <gtkmm/main.h>
+
+#include <gtkmm2ext/stateful_button.h>
 
 using namespace Gtk;
 using namespace Glib;
 using namespace Gtkmm2ext;
 using namespace std;
 
-StatefulButton::StatefulButton ()
+StateButton::StateButton ()
+        : visual_state (0)
+        , _self_managed (false)
+        , _is_realized (false)
+        , style_changing (false)
+        , state_before_prelight (Gtk::STATE_NORMAL)
+        , is_toggle (false)
+{
+}
+
+void
+StateButton::set_visual_state (int n)
+{
+       if (!_is_realized) {
+               /* not yet realized */
+               visual_state = n;
+               return;
+       }
+
+       if (n == visual_state) {
+               return;
+       }
+
+       string name = get_widget_name ();
+       name = name.substr (0, name.find_last_of ('-'));
+
+       switch (n) {
+       case 0:
+               /* relax */
+               break;
+       case 1:
+                name += "-active";
+               break;
+
+       case 2:
+               name += "-alternate";
+               break;
+
+        case 3:
+                name += "-alternate2";
+                break;
+       }
+
+       set_widget_name (name);
+       visual_state = n;
+}
+
+void
+StateButton::avoid_prelight_on_style_changed (const Glib::RefPtr<Gtk::Style>& /* old_style */,  GtkWidget* widget)
+{
+        /* don't go into an endless recursive loop if we're changing
+           the style in response to an existing style change.
+        */
+
+        if (style_changing) {
+                return;
+        }
+
+        if (gtk_widget_get_state (widget) == GTK_STATE_PRELIGHT) {
+
+                /* avoid PRELIGHT: make sure that the prelight colors in this new style match
+                   the colors of the new style in whatever state we were in
+                   before we switched to prelight.
+                */
+
+                GtkRcStyle* rcstyle = gtk_widget_get_modifier_style (widget);
+                GtkStyle* style = gtk_widget_get_style (widget);
+
+                rcstyle->fg[GTK_STATE_PRELIGHT] = style->fg[state_before_prelight];
+                rcstyle->bg[GTK_STATE_PRELIGHT] = style->bg[state_before_prelight];
+                rcstyle->color_flags[GTK_STATE_PRELIGHT] = (GtkRcFlags) (GTK_RC_FG|GTK_RC_BG);
+
+                style_changing = true;
+                g_object_ref (rcstyle);
+                gtk_widget_modify_style (widget, rcstyle);
+
+                Widget* child = get_child_widget();
+                if (child) {
+                        gtk_widget_modify_style (GTK_WIDGET(child->gobj()), rcstyle);
+                }
+
+
+                g_object_unref (rcstyle);
+                style_changing = false;
+        }
+}
+
+void
+StateButton::avoid_prelight_on_state_changed (Gtk::StateType old_state, GtkWidget* widget)
+{
+        GtkStateType state = gtk_widget_get_state (widget);
+
+        if (state == GTK_STATE_PRELIGHT) {
+
+                state_before_prelight = old_state;
+
+
+                /* avoid PRELIGHT when currently ACTIVE:
+                   if we just went into PRELIGHT, make sure that the colors
+                   match those of whatever state we were in before.
+                */
+
+                GtkRcStyle* rcstyle = gtk_widget_get_modifier_style (widget);
+                GtkStyle* style = gtk_widget_get_style (widget);
+
+                rcstyle->fg[GTK_STATE_PRELIGHT] = style->fg[old_state];
+                rcstyle->bg[GTK_STATE_PRELIGHT] = style->bg[old_state];
+                rcstyle->color_flags[GTK_STATE_PRELIGHT] = (GtkRcFlags) (GTK_RC_FG|GTK_RC_BG);
+
+                g_object_ref (rcstyle);
+                gtk_widget_modify_style (widget, rcstyle);
+
+                Widget* child = get_child_widget ();
+
+                if (child) {
+                        gtk_widget_modify_style (GTK_WIDGET(child->gobj()), rcstyle);
+                }
+
+                g_object_unref (rcstyle);
+
+        }
+}
+
+/* ----------------------------------------------------------------- */
+
+StatefulToggleButton::StatefulToggleButton ()
 {
-       current_state = 0;
-       have_saved_bg = false;
+        is_toggle = true;
 }
 
-StatefulButton::StatefulButton (const string& label)
-       Button (label)
+StatefulToggleButton::StatefulToggleButton (const std::string& label)
+        : ToggleButton (label)
 {
-       current_state = 0;
-       have_saved_bg = false;
+        is_toggle = true;
 }
 
 void
-StatefulButton::set_colors (const vector<Gdk::Color>& c)
+StatefulToggleButton::on_realize ()
 {
-       colors = c;
-       current_state++; // to force transition
-       set_state (current_state - 1);
+       ToggleButton::on_realize ();
+
+       _is_realized = true;
+       visual_state++; // to force transition
+       set_visual_state (visual_state - 1);
 }
 
 void
@@ -33,48 +181,93 @@ StatefulButton::on_realize ()
 {
        Button::on_realize ();
 
-       if (!have_saved_bg) {
-               saved_bg = get_style()->get_bg (STATE_NORMAL);
-               have_saved_bg = true;
+       _is_realized = true;
+       visual_state++; // to force transition
+       set_visual_state (visual_state - 1);
+}
+
+void
+StatefulToggleButton::on_toggled ()
+{
+       if (!_self_managed) {
+               if (get_active()) {
+                        set_state (Gtk::STATE_ACTIVE);
+               } else {
+                        set_state (Gtk::STATE_NORMAL);
+               }
        }
+}
 
-       current_state++; // to force transition
-       set_state (current_state - 1);
+
+void
+StatefulToggleButton::on_style_changed (const Glib::RefPtr<Gtk::Style>& style)
+{
+        avoid_prelight_on_style_changed (style, GTK_WIDGET(gobj()));
+        Button::on_style_changed (style);
 }
 
 void
-StatefulButton::set_state (int n)
+StatefulToggleButton::on_state_changed (Gtk::StateType old_state)
 {
-       if (is_realized()) {
+        avoid_prelight_on_state_changed (old_state, GTK_WIDGET(gobj()));
+        Button::on_state_changed (old_state);
+}
 
-               if (n == current_state) {
-                       return;
-               }
-               
-               if (n == 0) {
-                       
-                       /* back to the default color */
-                       
-                       if (have_saved_bg) {
-                               modify_bg (STATE_NORMAL, saved_bg);
-                               modify_bg (STATE_ACTIVE, saved_bg);
-                               modify_bg (STATE_SELECTED, saved_bg);
-                               modify_bg (STATE_PRELIGHT, saved_bg);
-                       }
-                       
+Widget*
+StatefulToggleButton::get_child_widget ()
+{
+        return get_child();
+}
 
-               } else {
-                       
-                       int index = (n-1) % colors.size ();
-                       
-                       modify_bg (STATE_NORMAL, colors[index]);
-                       modify_bg (STATE_ACTIVE, colors[index]);
-                       modify_bg (STATE_SELECTED, colors[index]);
-                       modify_bg (STATE_PRELIGHT, colors[index]);
-               }
-               
-               /* leave insensitive alone */
+void
+StatefulToggleButton::set_widget_name (const std::string& name)
+{
+       set_name (name);
+       Widget* w = get_child();
+
+       if (w) {
+               w->set_name (name);
        }
+}
+
+/*--------------------------------------------- */
+
+StatefulButton::StatefulButton ()
+{
+}
+
+StatefulButton::StatefulButton (const std::string& label)
+        : Button (label)
+{
+}
+
+void
+StatefulButton::on_style_changed (const Glib::RefPtr<Gtk::Style>& style)
+{
+        avoid_prelight_on_style_changed (style, GTK_WIDGET(gobj()));
+        Button::on_style_changed (style);
+}
+
+void
+StatefulButton::on_state_changed (Gtk::StateType old_state)
+{
+        avoid_prelight_on_state_changed (old_state, GTK_WIDGET(gobj()));
+        Button::on_state_changed (old_state);
+}
+
+Widget*
+StatefulButton::get_child_widget ()
+{
+        return get_child();
+}
+
+void
+StatefulButton::set_widget_name (const std::string& name)
+{
+       set_name (name);
+       Widget* w = get_child();
 
-       current_state = n;
+       if (w) {
+               w->set_name (name);
+       }
 }