1 /*
2 * Copyright (C) 2010-2007 Paul Davis <paul@linuxaudiosystems.com>
3 * Copyright (C) 2017 Robin Gareus <robin@gareus.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <string>
21 #include <iostream>
22
23
24 #include <gtkmm/main.h>
25
26 #include "widgets/stateful_button.h"
27
28 using namespace Gtk;
29 using namespace Glib;
30 using namespace ArdourWidgets;
31 using namespace std;
32
StateButton()33 StateButton::StateButton ()
34 : visual_state (0)
35 , _self_managed (false)
36 , _is_realized (false)
37 , style_changing (false)
38 , state_before_prelight (Gtk::STATE_NORMAL)
39 , is_toggle (false)
40 {
41 }
42
43 void
set_visual_state(int n)44 StateButton::set_visual_state (int n)
45 {
46 if (!_is_realized) {
47 /* not yet realized */
48 visual_state = n;
49 return;
50 }
51
52 if (n == visual_state) {
53 return;
54 }
55
56 string name = get_widget_name ();
57 name = name.substr (0, name.find_last_of ('-'));
58
59 switch (n) {
60 case 0:
61 /* relax */
62 break;
63 case 1:
64 name += "-active";
65 break;
66
67 case 2:
68 name += "-alternate";
69 break;
70
71 case 3:
72 name += "-alternate2";
73 break;
74 }
75
76 set_widget_name (name);
77 visual_state = n;
78 }
79
80 void
avoid_prelight_on_style_changed(const Glib::RefPtr<Gtk::Style> &,GtkWidget * widget)81 StateButton::avoid_prelight_on_style_changed (const Glib::RefPtr<Gtk::Style>& /* old_style */, GtkWidget* widget)
82 {
83 /* don't go into an endless recursive loop if we're changing
84 the style in response to an existing style change.
85 */
86
87 if (style_changing) {
88 return;
89 }
90
91 if (gtk_widget_get_state (widget) == GTK_STATE_PRELIGHT) {
92
93 /* avoid PRELIGHT: make sure that the prelight colors in this new style match
94 the colors of the new style in whatever state we were in
95 before we switched to prelight.
96 */
97
98 GtkRcStyle* rcstyle = gtk_widget_get_modifier_style (widget);
99 GtkStyle* style = gtk_widget_get_style (widget);
100
101 rcstyle->fg[GTK_STATE_PRELIGHT] = style->fg[state_before_prelight];
102 rcstyle->bg[GTK_STATE_PRELIGHT] = style->bg[state_before_prelight];
103 rcstyle->color_flags[GTK_STATE_PRELIGHT] = (GtkRcFlags) (GTK_RC_FG|GTK_RC_BG);
104
105 style_changing = true;
106 g_object_ref (rcstyle);
107 gtk_widget_modify_style (widget, rcstyle);
108
109 Widget* child = get_child_widget();
110 if (child) {
111 gtk_widget_modify_style (GTK_WIDGET(child->gobj()), rcstyle);
112 }
113
114
115 g_object_unref (rcstyle);
116 style_changing = false;
117 }
118 }
119
120 void
avoid_prelight_on_state_changed(Gtk::StateType old_state,GtkWidget * widget)121 StateButton::avoid_prelight_on_state_changed (Gtk::StateType old_state, GtkWidget* widget)
122 {
123 GtkStateType state = gtk_widget_get_state (widget);
124
125 if (state == GTK_STATE_PRELIGHT) {
126
127 state_before_prelight = old_state;
128
129
130 /* avoid PRELIGHT when currently ACTIVE:
131 if we just went into PRELIGHT, make sure that the colors
132 match those of whatever state we were in before.
133 */
134
135 GtkRcStyle* rcstyle = gtk_widget_get_modifier_style (widget);
136 GtkStyle* style = gtk_widget_get_style (widget);
137
138 rcstyle->fg[GTK_STATE_PRELIGHT] = style->fg[old_state];
139 rcstyle->bg[GTK_STATE_PRELIGHT] = style->bg[old_state];
140 rcstyle->color_flags[GTK_STATE_PRELIGHT] = (GtkRcFlags) (GTK_RC_FG|GTK_RC_BG);
141
142 g_object_ref (rcstyle);
143 gtk_widget_modify_style (widget, rcstyle);
144
145 Widget* child = get_child_widget ();
146
147 if (child) {
148 gtk_widget_modify_style (GTK_WIDGET(child->gobj()), rcstyle);
149 }
150
151 g_object_unref (rcstyle);
152
153 }
154 }
155
156 /* ----------------------------------------------------------------- */
157
StatefulToggleButton()158 StatefulToggleButton::StatefulToggleButton ()
159 {
160 is_toggle = true;
161 }
162
StatefulToggleButton(const std::string & label)163 StatefulToggleButton::StatefulToggleButton (const std::string& label)
164 : ToggleButton (label)
165 {
166 is_toggle = true;
167 }
168
169 void
on_realize()170 StatefulToggleButton::on_realize ()
171 {
172 ToggleButton::on_realize ();
173
174 _is_realized = true;
175 visual_state++; // to force transition
176 set_visual_state (visual_state - 1);
177 }
178
179 void
on_realize()180 StatefulButton::on_realize ()
181 {
182 Button::on_realize ();
183
184 _is_realized = true;
185 visual_state++; // to force transition
186 set_visual_state (visual_state - 1);
187 }
188
189 void
on_toggled()190 StatefulToggleButton::on_toggled ()
191 {
192 if (!_self_managed) {
193 if (get_active()) {
194 set_state (Gtk::STATE_ACTIVE);
195 } else {
196 set_state (Gtk::STATE_NORMAL);
197 }
198 }
199 }
200
201
202 void
on_style_changed(const Glib::RefPtr<Gtk::Style> & style)203 StatefulToggleButton::on_style_changed (const Glib::RefPtr<Gtk::Style>& style)
204 {
205 avoid_prelight_on_style_changed (style, GTK_WIDGET(gobj()));
206 Button::on_style_changed (style);
207 }
208
209 void
on_state_changed(Gtk::StateType old_state)210 StatefulToggleButton::on_state_changed (Gtk::StateType old_state)
211 {
212 avoid_prelight_on_state_changed (old_state, GTK_WIDGET(gobj()));
213 Button::on_state_changed (old_state);
214 }
215
216 Widget*
get_child_widget()217 StatefulToggleButton::get_child_widget ()
218 {
219 return get_child();
220 }
221
222 void
set_widget_name(const std::string & name)223 StatefulToggleButton::set_widget_name (const std::string& name)
224 {
225 set_name (name);
226 Widget* w = get_child();
227
228 if (w) {
229 w->set_name (name);
230 }
231 }
232
233 /*--------------------------------------------- */
234
StatefulButton()235 StatefulButton::StatefulButton ()
236 {
237 }
238
StatefulButton(const std::string & label)239 StatefulButton::StatefulButton (const std::string& label)
240 : Button (label)
241 {
242 }
243
244 void
on_style_changed(const Glib::RefPtr<Gtk::Style> & style)245 StatefulButton::on_style_changed (const Glib::RefPtr<Gtk::Style>& style)
246 {
247 avoid_prelight_on_style_changed (style, GTK_WIDGET(gobj()));
248 Button::on_style_changed (style);
249 }
250
251 void
on_state_changed(Gtk::StateType old_state)252 StatefulButton::on_state_changed (Gtk::StateType old_state)
253 {
254 avoid_prelight_on_state_changed (old_state, GTK_WIDGET(gobj()));
255 Button::on_state_changed (old_state);
256 }
257
258 Widget*
get_child_widget()259 StatefulButton::get_child_widget ()
260 {
261 return get_child();
262 }
263
264 void
set_widget_name(const std::string & name)265 StatefulButton::set_widget_name (const std::string& name)
266 {
267 set_name (name);
268 Widget* w = get_child();
269
270 if (w) {
271 w->set_name (name);
272 }
273 }
274