1 /*
2 * bulia byak <buliabyak@users.sf.net>
3 * Jon A. Cruz <jon@joncruz.org>
4 */
6 #ifdef HAVE_CONFIG_H
7 # include "config.h"
8 #endif
9 #include <math.h>
10 #include <gtk/gtksignal.h>
11 #include <glibmm/i18n.h>
12 #include "sp-color-selector.h"
14 enum {
15 GRABBED,
16 DRAGGED,
17 RELEASED,
18 CHANGED,
19 LAST_SIGNAL
20 };
22 #define noDUMP_CHANGE_INFO
23 #define FOO_NAME(x) g_type_name( G_TYPE_FROM_INSTANCE(x) )
25 static void sp_color_selector_class_init( SPColorSelectorClass *klass );
26 static void sp_color_selector_init( SPColorSelector *csel );
27 static void sp_color_selector_destroy( GtkObject *object );
29 static void sp_color_selector_show_all( GtkWidget *widget );
30 static void sp_color_selector_hide_all( GtkWidget *widget );
32 static GtkVBoxClass *parent_class;
33 static guint csel_signals[LAST_SIGNAL] = {0};
35 double ColorSelector::_epsilon = 1e-4;
37 GType sp_color_selector_get_type( void )
38 {
39 static GType type = 0;
40 if (!type) {
41 static const GTypeInfo info = {
42 sizeof(SPColorSelectorClass),
43 NULL, /* base_init */
44 NULL, /* base_finalize */
45 (GClassInitFunc) sp_color_selector_class_init,
46 NULL, /* class_finalize */
47 NULL, /* class_data */
48 sizeof(SPColorSelector),
49 0, /* n_preallocs */
50 (GInstanceInitFunc) sp_color_selector_init,
51 NULL
52 };
54 type = g_type_register_static( GTK_TYPE_VBOX,
55 "SPColorSelector",
56 &info,
57 static_cast<GTypeFlags>(0) );
58 }
59 return type;
60 }
62 void sp_color_selector_class_init( SPColorSelectorClass *klass )
63 {
64 static const gchar* nameset[] = {N_("Unnamed"), 0};
65 GtkObjectClass *object_class;
66 GtkWidgetClass *widget_class;
68 object_class = GTK_OBJECT_CLASS(klass);
69 widget_class = GTK_WIDGET_CLASS(klass);
71 parent_class = GTK_VBOX_CLASS( gtk_type_class(GTK_TYPE_VBOX) );
73 csel_signals[GRABBED] = gtk_signal_new( "grabbed",
74 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
75 GTK_CLASS_TYPE(object_class),
76 GTK_SIGNAL_OFFSET(SPColorSelectorClass, grabbed),
77 gtk_marshal_NONE__NONE,
78 GTK_TYPE_NONE, 0 );
79 csel_signals[DRAGGED] = gtk_signal_new( "dragged",
80 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
81 GTK_CLASS_TYPE(object_class),
82 GTK_SIGNAL_OFFSET(SPColorSelectorClass, dragged),
83 gtk_marshal_NONE__NONE,
84 GTK_TYPE_NONE, 0 );
85 csel_signals[RELEASED] = gtk_signal_new( "released",
86 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
87 GTK_CLASS_TYPE(object_class),
88 GTK_SIGNAL_OFFSET(SPColorSelectorClass, released),
89 gtk_marshal_NONE__NONE,
90 GTK_TYPE_NONE, 0 );
91 csel_signals[CHANGED] = gtk_signal_new( "changed",
92 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
93 GTK_CLASS_TYPE(object_class),
94 GTK_SIGNAL_OFFSET(SPColorSelectorClass, changed),
95 gtk_marshal_NONE__NONE,
96 GTK_TYPE_NONE, 0 );
98 klass->name = nameset;
99 klass->submode_count = 1;
101 object_class->destroy = sp_color_selector_destroy;
103 widget_class->show_all = sp_color_selector_show_all;
104 widget_class->hide_all = sp_color_selector_hide_all;
106 }
108 void sp_color_selector_init( SPColorSelector *csel )
109 {
110 if ( csel->base )
111 {
112 csel->base->init();
113 }
114 /* gtk_signal_connect(GTK_OBJECT(csel->rgbae), "changed", GTK_SIGNAL_FUNC(sp_color_selector_rgba_entry_changed), csel); */
115 }
117 void sp_color_selector_destroy( GtkObject *object )
118 {
119 SPColorSelector *csel = SP_COLOR_SELECTOR( object );
120 if ( csel->base )
121 {
122 delete csel->base;
123 csel->base = 0;
124 }
126 if ( (GTK_OBJECT_CLASS(parent_class))->destroy ) {
127 (* (GTK_OBJECT_CLASS(parent_class))->destroy)(object);
128 }
129 }
131 void sp_color_selector_show_all( GtkWidget *widget )
132 {
133 gtk_widget_show( widget );
134 }
136 void sp_color_selector_hide_all( GtkWidget *widget )
137 {
138 gtk_widget_hide( widget );
139 }
141 GtkWidget *sp_color_selector_new( GType selector_type )
142 {
143 g_return_val_if_fail( g_type_is_a( selector_type, SP_TYPE_COLOR_SELECTOR ), NULL );
145 SPColorSelector *csel = SP_COLOR_SELECTOR( g_object_new( selector_type, NULL ) );
147 return GTK_WIDGET( csel );
148 }
150 void ColorSelector::setSubmode( guint /*submode*/ )
151 {
152 }
154 guint ColorSelector::getSubmode() const
155 {
156 guint mode = 0;
157 return mode;
158 }
160 ColorSelector::ColorSelector( SPColorSelector* csel )
161 : _csel(csel),
162 _color( 0 ),
163 _alpha(1.0),
164 _held(FALSE),
165 virgin(true)
166 {
167 g_return_if_fail( SP_IS_COLOR_SELECTOR(_csel) );
168 }
170 ColorSelector::~ColorSelector()
171 {
172 }
174 void ColorSelector::init()
175 {
176 _csel->base = new ColorSelector( _csel );
177 }
179 void ColorSelector::setColor( const SPColor& color )
180 {
181 setColorAlpha( color, _alpha );
182 }
184 SPColor ColorSelector::getColor() const
185 {
186 return _color;
187 }
189 void ColorSelector::setAlpha( gfloat alpha )
190 {
191 g_return_if_fail( ( 0.0 <= alpha ) && ( alpha <= 1.0 ) );
192 setColorAlpha( _color, alpha );
193 }
195 gfloat ColorSelector::getAlpha() const
196 {
197 return _alpha;
198 }
200 #include "svg/svg-icc-color.h"
202 /**
203 Called from the outside to set the color; optionally emits signal (only when called from
204 downstream, e.g. the RGBA value field, but not from the rest of the program)
205 */
206 void ColorSelector::setColorAlpha( const SPColor& color, gfloat alpha, bool emit )
207 {
208 #ifdef DUMP_CHANGE_INFO
209 g_message("ColorSelector::setColorAlpha( this=%p, %f, %f, %f, %s, %f, %s) in %s", this, color.v.c[0], color.v.c[1], color.v.c[2], (color.icc?color.icc->colorProfile.c_str():"<null>"), alpha, (emit?"YES":"no"), FOO_NAME(_csel));
210 #endif
211 g_return_if_fail( _csel != NULL );
212 g_return_if_fail( ( 0.0 <= alpha ) && ( alpha <= 1.0 ) );
214 #ifdef DUMP_CHANGE_INFO
215 g_message("---- ColorSelector::setColorAlpha virgin:%s !close:%s alpha is:%s in %s",
216 (virgin?"YES":"no"),
217 (!color.isClose( _color, _epsilon )?"YES":"no"),
218 ((fabs((_alpha) - (alpha)) >= _epsilon )?"YES":"no"),
219 FOO_NAME(_csel)
220 );
221 #endif
223 if ( virgin || !color.isClose( _color, _epsilon ) ||
224 (fabs((_alpha) - (alpha)) >= _epsilon )) {
226 virgin = false;
228 _color = color;
229 _alpha = alpha;
230 _colorChanged();
232 if (emit) {
233 gtk_signal_emit(GTK_OBJECT(_csel), csel_signals[CHANGED]);
234 }
235 #ifdef DUMP_CHANGE_INFO
236 } else {
237 g_message("++++ ColorSelector::setColorAlpha color:%08x ==> _color:%08X isClose:%s in %s", color.toRGBA32(alpha), _color.toRGBA32(_alpha),
238 (color.isClose( _color, _epsilon )?"YES":"no"), FOO_NAME(_csel));
239 #endif
240 }
241 }
243 void ColorSelector::_grabbed()
244 {
245 _held = TRUE;
246 #ifdef DUMP_CHANGE_INFO
247 g_message("%s:%d: About to signal %s in %s", __FILE__, __LINE__,
248 "GRABBED",
249 FOO_NAME(_csel));
250 #endif
251 gtk_signal_emit(GTK_OBJECT(_csel), csel_signals[GRABBED]);
252 }
254 void ColorSelector::_released()
255 {
256 _held = false;
257 #ifdef DUMP_CHANGE_INFO
258 g_message("%s:%d: About to signal %s in %s", __FILE__, __LINE__,
259 "RELEASED",
260 FOO_NAME(_csel));
261 #endif
262 gtk_signal_emit(GTK_OBJECT(_csel), csel_signals[RELEASED]);
263 gtk_signal_emit(GTK_OBJECT(_csel), csel_signals[CHANGED]);
264 }
266 // Called from subclasses to update color and broadcast if needed
267 void ColorSelector::_updateInternals( const SPColor& color, gfloat alpha, gboolean held )
268 {
269 g_return_if_fail( ( 0.0 <= alpha ) && ( alpha <= 1.0 ) );
270 gboolean colorDifferent = ( !color.isClose( _color, _epsilon )
271 || ( fabs((_alpha) - (alpha)) >= _epsilon ) );
273 gboolean grabbed = held && !_held;
274 gboolean released = !held && _held;
276 // Store these before emmiting any signals
277 _held = held;
278 if ( colorDifferent )
279 {
280 _color = color;
281 _alpha = alpha;
282 }
284 if ( grabbed )
285 {
286 #ifdef DUMP_CHANGE_INFO
287 g_message("%s:%d: About to signal %s to color %08x::%s in %s", __FILE__, __LINE__,
288 "GRABBED",
289 color.toRGBA32( alpha ), (color.icc?color.icc->colorProfile.c_str():"<null>"), FOO_NAME(_csel));
290 #endif
291 gtk_signal_emit(GTK_OBJECT(_csel), csel_signals[GRABBED]);
292 }
293 else if ( released )
294 {
295 #ifdef DUMP_CHANGE_INFO
296 g_message("%s:%d: About to signal %s to color %08x::%s in %s", __FILE__, __LINE__,
297 "RELEASED",
298 color.toRGBA32( alpha ), (color.icc?color.icc->colorProfile.c_str():"<null>"), FOO_NAME(_csel));
299 #endif
300 gtk_signal_emit(GTK_OBJECT(_csel), csel_signals[RELEASED]);
301 }
303 if ( colorDifferent || released )
304 {
305 #ifdef DUMP_CHANGE_INFO
306 g_message("%s:%d: About to signal %s to color %08x::%s in %s", __FILE__, __LINE__,
307 (_held ? "CHANGED" : "DRAGGED" ),
308 color.toRGBA32( alpha ), (color.icc?color.icc->colorProfile.c_str():"<null>"), FOO_NAME(_csel));
309 #endif
310 gtk_signal_emit(GTK_OBJECT(_csel), csel_signals[_held ? CHANGED : DRAGGED]);
311 }
312 }
314 /**
315 * Called once the color actually changes. Allows subclasses to react to changes.
316 */
317 void ColorSelector::_colorChanged()
318 {
319 }
321 void ColorSelector::getColorAlpha( SPColor &color, gfloat &alpha ) const
322 {
323 gint i = 0;
325 color = _color;
326 alpha = _alpha;
328 // Try to catch uninitialized value usage
329 if ( color.v.c[0] )
330 {
331 i++;
332 }
333 if ( color.v.c[1] )
334 {
335 i++;
336 }
337 if ( color.v.c[2] )
338 {
339 i++;
340 }
341 if ( alpha )
342 {
343 i++;
344 }
345 }
347 /*
348 Local Variables:
349 mode:c++
350 c-file-style:"stroustrup"
351 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
352 indent-tabs-mode:nil
353 fill-column:99
354 End:
355 */
356 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :