Code

make sure positive xy widget pos is written
[inkscape.git] / src / widgets / gradient-vector.cpp
1 #define __SP_GRADIENT_VECTOR_C__
3 /*
4  * Gradient vector selection widget
5  *
6  * Authors:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *   bulia byak <buliabyak@users.sf.net>
9  *
10  * Copyright (C) 2001-2002 Lauris Kaplinski
11  * Copyright (C) 2001 Ximian, Inc.
12  * Copyright (C) 2004 Monash University
13  * Copyright (C) 2004 David Turner
14  *
15  * Released under GNU GPL, read the file 'COPYING' for more information
16  *
17  */
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22 #ifdef HAVE_STRING_H
23 #endif
24 #include <gtk/gtk.h>
25 #include "macros.h"
26 #include <glibmm/i18n.h>
27 #include "../widgets/gradient-image.h"
28 #include "../inkscape.h"
29 #include "../document-private.h"
30 #include "../gradient-chemistry.h"
31 #include "gradient-vector.h"
32 #include "../helper/window.h"
34 #include "xml/repr.h"
36 #include "../dialogs/dialog-events.h"
37 #include "../prefs-utils.h"
38 #include "svg/css-ostringstream.h"
39 #include "sp-stop.h"
41 enum {
42         VECTOR_SET,
43         LAST_SIGNAL
44 };
46 static void sp_gradient_vector_selector_class_init (SPGradientVectorSelectorClass *klass);
47 static void sp_gradient_vector_selector_init (SPGradientVectorSelector *gvs);
48 static void sp_gradient_vector_selector_destroy (GtkObject *object);
50 static void sp_gvs_gradient_release (SPGradient *gr, SPGradientVectorSelector *gvs);
51 static void sp_gvs_defs_release (SPObject *defs, SPGradientVectorSelector *gvs);
52 static void sp_gvs_defs_modified (SPObject *defs, guint flags, SPGradientVectorSelector *gvs);
54 static void sp_gvs_rebuild_gui_full (SPGradientVectorSelector *gvs);
55 static void sp_gvs_gradient_activate (GtkMenuItem *mi, SPGradientVectorSelector *gvs);
57 static GtkVBoxClass *parent_class;
58 static guint signals[LAST_SIGNAL] = {0};
60 static GtkWidget *dlg = NULL;
61 static win_data wd;
62 static gint x = -1000, y = -1000, w = 0, h = 0; // impossible original values to make sure they are read from prefs
63 static gchar const *prefs_path = "dialogs.gradienteditor";
65 GtkType
66 sp_gradient_vector_selector_get_type (void)
67 {
68         static GtkType type = 0;
69         if (!type) {
70                 GtkTypeInfo info = {
71                         "SPGradientVectorSelector",
72                         sizeof (SPGradientVectorSelector),
73                         sizeof (SPGradientVectorSelectorClass),
74                         (GtkClassInitFunc) sp_gradient_vector_selector_class_init,
75                         (GtkObjectInitFunc) sp_gradient_vector_selector_init,
76                         NULL, NULL, NULL
77                 };
78                 type = gtk_type_unique (GTK_TYPE_VBOX, &info);
79         }
80         return type;
81 }
83 static void
84 sp_gradient_vector_selector_class_init (SPGradientVectorSelectorClass *klass)
85 {
86         GtkObjectClass *object_class;
88         object_class = GTK_OBJECT_CLASS (klass);
90         parent_class = (GtkVBoxClass*)gtk_type_class (GTK_TYPE_VBOX);
92         signals[VECTOR_SET] = gtk_signal_new ("vector_set",
93                                               GTK_RUN_LAST,
94                                               GTK_CLASS_TYPE(object_class),
95                                               GTK_SIGNAL_OFFSET (SPGradientVectorSelectorClass, vector_set),
96                                               gtk_marshal_NONE__POINTER,
97                                               GTK_TYPE_NONE, 1,
98                                               GTK_TYPE_POINTER);
100         object_class->destroy = sp_gradient_vector_selector_destroy;
103 static void
104 sp_gradient_vector_selector_init (SPGradientVectorSelector *gvs)
106         gvs->idlabel = TRUE;
108         gvs->doc = NULL;
109         gvs->gr = NULL;
111         gvs->menu = gtk_option_menu_new ();
112         gtk_widget_show (gvs->menu);
113         gtk_box_pack_start (GTK_BOX (gvs), gvs->menu, TRUE, TRUE, 0);
116 static void
117 sp_gradient_vector_selector_destroy (GtkObject *object)
119         SPGradientVectorSelector *gvs;
121         gvs = SP_GRADIENT_VECTOR_SELECTOR (object);
123         if (gvs->gr) {
124                 sp_signal_disconnect_by_data (gvs->gr, gvs);
125                 gvs->gr = NULL;
126         }
128         if (gvs->doc) {
129                 sp_signal_disconnect_by_data (SP_DOCUMENT_DEFS (gvs->doc), gvs);
130                 gvs->doc = NULL;
131         }
133         if (((GtkObjectClass *) (parent_class))->destroy)
134                 (* ((GtkObjectClass *) (parent_class))->destroy) (object);
137 GtkWidget *
138 sp_gradient_vector_selector_new (SPDocument *doc, SPGradient *gr)
140         GtkWidget *gvs;
142         g_return_val_if_fail (!gr || SP_IS_GRADIENT (gr), NULL);
143         g_return_val_if_fail (!gr || (SP_OBJECT_DOCUMENT (gr) == doc), NULL);
145         gvs = (GtkWidget*)gtk_type_new (SP_TYPE_GRADIENT_VECTOR_SELECTOR);
147         if (doc) {
148                 sp_gradient_vector_selector_set_gradient (SP_GRADIENT_VECTOR_SELECTOR (gvs), doc, gr);
149         } else {
150                 sp_gvs_rebuild_gui_full (SP_GRADIENT_VECTOR_SELECTOR (gvs));
151         }
153         return gvs;
156 void
157 sp_gradient_vector_selector_set_gradient (SPGradientVectorSelector *gvs, SPDocument *doc, SPGradient *gr)
159         static gboolean suppress = FALSE;
161         g_return_if_fail (gvs != NULL);
162         g_return_if_fail (SP_IS_GRADIENT_VECTOR_SELECTOR (gvs));
163         g_return_if_fail (!gr || (doc != NULL));
164         g_return_if_fail (!gr || SP_IS_GRADIENT (gr));
165         g_return_if_fail (!gr || (SP_OBJECT_DOCUMENT (gr) == doc));
166         g_return_if_fail (!gr || SP_GRADIENT_HAS_STOPS (gr));
168         if (doc != gvs->doc) {
169                 /* Disconnect signals */
170                 if (gvs->gr) {
171                         sp_signal_disconnect_by_data (gvs->gr, gvs);
172                         g_signal_handlers_disconnect_matched (G_OBJECT(gvs->gr), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, gvs);
173                         gvs->gr = NULL;
174                 }
175                 if (gvs->doc) {
176                         sp_signal_disconnect_by_data (SP_DOCUMENT_DEFS (gvs->doc), gvs);
177                         gvs->doc = NULL;
178                 }
179                 /* Connect signals */
180                 if (doc) {
181                         g_signal_connect (G_OBJECT (SP_DOCUMENT_DEFS (doc)), "release", G_CALLBACK (sp_gvs_defs_release), gvs);
182                         g_signal_connect (G_OBJECT (SP_DOCUMENT_DEFS (doc)), "modified", G_CALLBACK (sp_gvs_defs_modified), gvs);
183                 }
184                 if (gr) {
185                         g_signal_connect (G_OBJECT (gr), "release", G_CALLBACK (sp_gvs_gradient_release), gvs);
186                 }
187                 gvs->doc = doc;
188                 gvs->gr = gr;
189                 sp_gvs_rebuild_gui_full (gvs);
190                 if (!suppress) g_signal_emit (G_OBJECT (gvs), signals[VECTOR_SET], 0, gr);
191         } else if (gr != gvs->gr) {
192                 /* Harder case - keep document, rebuild menus and stuff */
193                 /* fixme: (Lauris) */
194                 suppress = TRUE;
195                 sp_gradient_vector_selector_set_gradient (gvs, NULL, NULL);
196                 sp_gradient_vector_selector_set_gradient (gvs, doc, gr);
197                 suppress = FALSE;
198                 g_signal_emit (G_OBJECT (gvs), signals[VECTOR_SET], 0, gr);
199         }
200         /* The case of setting NULL -> NULL is not very interesting */
203 SPDocument *
204 sp_gradient_vector_selector_get_document (SPGradientVectorSelector *gvs)
206         g_return_val_if_fail (gvs != NULL, NULL);
207         g_return_val_if_fail (SP_IS_GRADIENT_VECTOR_SELECTOR (gvs), NULL);
209         return gvs->doc;
212 SPGradient *
213 sp_gradient_vector_selector_get_gradient (SPGradientVectorSelector *gvs)
215         g_return_val_if_fail (gvs != NULL, NULL);
216         g_return_val_if_fail (SP_IS_GRADIENT_VECTOR_SELECTOR (gvs), NULL);
218         return gvs->gr;
221 static void
222 sp_gvs_rebuild_gui_full (SPGradientVectorSelector *gvs)
224         /* Clear old menu, if there is any */
225         if (gtk_option_menu_get_menu (GTK_OPTION_MENU (gvs->menu))) {
226                 gtk_option_menu_remove_menu (GTK_OPTION_MENU (gvs->menu));
227         }
229         /* Create new menu widget */
230         GtkWidget *m = gtk_menu_new ();
231         gtk_widget_show (m);
233         /* Pick up all gradients with vectors */
234         GSList *gl = NULL;
235         if (gvs->gr) {
236                 const GSList *gradients = sp_document_get_resource_list (SP_OBJECT_DOCUMENT (gvs->gr), "gradient");
237                 for (const GSList *l = gradients; l != NULL; l = l->next) {
238                         if (SP_GRADIENT_HAS_STOPS (l->data)) {
239                                 gl = g_slist_prepend (gl, l->data);
240                         }
241                 }
242         }
243         gl = g_slist_reverse (gl);
245         gint pos = 0;
246         gint idx = 0;
248         if (!gvs->doc) {
249                 GtkWidget *i;
250                 i = gtk_menu_item_new_with_label (_("No document selected"));
251                 gtk_widget_show (i);
252                 gtk_menu_append (GTK_MENU (m), i);
253                 gtk_widget_set_sensitive (gvs->menu, FALSE);
254         } else if (!gl) {
255                 GtkWidget *i;
256                 i = gtk_menu_item_new_with_label (_("No gradients in document"));
257                 gtk_widget_show (i);
258                 gtk_menu_append (GTK_MENU (m), i);
259                 gtk_widget_set_sensitive (gvs->menu, FALSE);
260         } else if (!gvs->gr) {
261                 GtkWidget *i;
262                 i = gtk_menu_item_new_with_label (_("No gradient selected"));
263                 gtk_widget_show (i);
264                 gtk_menu_append (GTK_MENU (m), i);
265                 gtk_widget_set_sensitive (gvs->menu, FALSE);
266         } else {
267                 while (gl) {
268                         SPGradient *gr;
269                         GtkWidget *i, *w;
270                         gr = SP_GRADIENT (gl->data);
271                         gl = g_slist_remove (gl, gr);
273                         /* We have to know: */
274                         /* Gradient destroy */
275                         /* Gradient name change */
276                         i = gtk_menu_item_new ();
277                         gtk_widget_show (i);
278                         g_object_set_data (G_OBJECT (i), "gradient", gr);
279                         g_signal_connect (G_OBJECT (i), "activate", G_CALLBACK (sp_gvs_gradient_activate), gvs);
281                         w = sp_gradient_image_new (gr);
282                         gtk_widget_show (w);
284                         if (gvs->idlabel) {
285                                 GtkWidget *hb, *l;
286                                 hb = gtk_hbox_new (FALSE, 4);
287                                 gtk_widget_show (hb);
288                                 l = gtk_label_new (SP_OBJECT_ID (gr));
289                                 gtk_widget_show (l);
290                                 gtk_misc_set_alignment (GTK_MISC (l), 1.0, 0.5);
291                                 gtk_box_pack_start (GTK_BOX (hb), l, TRUE, TRUE, 0);
292                                 gtk_box_pack_start (GTK_BOX (hb), w, FALSE, FALSE, 0);
293                                 w = hb;
294                         }
296                         gtk_container_add (GTK_CONTAINER (i), w);
298                         gtk_menu_append (GTK_MENU (m), i);
300                         if (gr == gvs->gr) pos = idx;
301                         idx += 1;
302                 }
303                 gtk_widget_set_sensitive (gvs->menu, TRUE);
304         }
306         gtk_option_menu_set_menu (GTK_OPTION_MENU (gvs->menu), m);
307         /* Set history */
308         gtk_option_menu_set_history (GTK_OPTION_MENU (gvs->menu), pos);
311 static void
312 sp_gvs_gradient_activate (GtkMenuItem *mi, SPGradientVectorSelector *gvs)
314         SPGradient *gr, *norm;
316         gr = (SPGradient*)g_object_get_data (G_OBJECT (mi), "gradient");
317         /* Hmmm... bad things may happen here, if actual gradient is something new */
318         /* Namely - menuitems etc. will be fucked up */
319         /* Hmmm - probably we can just re-set it as menuitem data (Lauris) */
321         //g_print ("SPGradientVectorSelector: gradient %s activated\n", SP_OBJECT_ID (gr));
323         norm = sp_gradient_ensure_vector_normalized (gr);
324         if (norm != gr) {
325                 //g_print ("SPGradientVectorSelector: become %s after normalization\n", SP_OBJECT_ID (norm));
326                 /* But be careful that we do not have gradient saved anywhere else */
327                 g_object_set_data (G_OBJECT (mi), "gradient", norm);
328         }
330         /* fixme: Really we would want to use _set_vector */
331         /* Detach old */
332         if (gvs->gr) {
333                 sp_signal_disconnect_by_data (gvs->gr, gvs);
334                 gvs->gr = NULL;
335         }
336         /* Attach new */
337         if (norm) {
338                 g_signal_connect (G_OBJECT (norm), "release", G_CALLBACK (sp_gvs_gradient_release), gvs);
339                 /* fixme: Connect 'modified'? (Lauris) */
340                 /* fixme: I think we do not need it (Lauris) */
341                 gvs->gr = norm;
342         }
344         g_signal_emit (G_OBJECT (gvs), signals[VECTOR_SET], 0, norm);
346         if (norm != gr) {
347                 /* We do extra undo push here */
348                 /* If handler has already done it, it is just NOP */
349                 sp_document_done (SP_OBJECT_DOCUMENT (norm));
350         }
353 static void
354 sp_gvs_gradient_release (SPGradient *gr, SPGradientVectorSelector *gvs)
356         /* Disconnect gradient */
357         if (gvs->gr) {
358                 sp_signal_disconnect_by_data (gvs->gr, gvs);
359                 gvs->gr = NULL;
360         }
362         /* Rebuild GUI */
363         sp_gvs_rebuild_gui_full (gvs);
366 static void
367 sp_gvs_defs_release (SPObject *defs, SPGradientVectorSelector *gvs)
369         gvs->doc = NULL;
370         /* Disconnect gradient as well */
371         if (gvs->gr) {
372                 sp_signal_disconnect_by_data (gvs->gr, gvs);
373                 gvs->gr = NULL;
374         }
376         /* Rebuild GUI */
377         sp_gvs_rebuild_gui_full (gvs);
380 static void
381 sp_gvs_defs_modified (SPObject *defs, guint flags, SPGradientVectorSelector *gvs)
383         /* fixme: We probably have to check some flags here (Lauris) */
385         sp_gvs_rebuild_gui_full (gvs);
388 /*##################################################################
389 ###                 Vector Editing Widget
390 ##################################################################*/
392 #include "../widgets/sp-color-notebook.h"
393 #include "../widgets/sp-color-preview.h"
394 #include "../widgets/widget-sizes.h"
395 #include "../xml/node-event-vector.h"
396 #include "../svg/svg.h"
399 #define PAD 4
401 static GtkWidget *sp_gradient_vector_widget_new (SPGradient *gradient, SPStop *stop);
403 static void sp_gradient_vector_widget_load_gradient (GtkWidget *widget, SPGradient *gradient);
404 static gint sp_gradient_vector_dialog_delete (GtkWidget *widget, GdkEvent *event, GtkWidget *dialog);
405 static void sp_gradient_vector_dialog_destroy (GtkObject *object, gpointer data);
407 static void sp_gradient_vector_widget_destroy (GtkObject *object, gpointer data);
408 static void sp_gradient_vector_gradient_release (SPGradient *gradient, GtkWidget *widget);
409 static void sp_gradient_vector_gradient_modified (SPGradient *gradient, guint flags, GtkWidget *widget);
410 static void sp_gradient_vector_color_dragged (SPColorSelector *csel, GtkObject *object);
411 static void sp_gradient_vector_color_changed (SPColorSelector *csel, GtkObject *object);
412 static void update_stop_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_stop);
414 static gboolean blocked = FALSE;
416 static void grad_edit_dia_stop_added_or_removed (Inkscape::XML::Node *repr, Inkscape::XML::Node *child, Inkscape::XML::Node *ref, gpointer data)
418    GtkWidget *vb = GTK_WIDGET(data);
419    GtkWidget *mnu = (GtkWidget *)g_object_get_data (G_OBJECT(vb), "stopmenu");
420    SPGradient *gradient = (SPGradient *)g_object_get_data (G_OBJECT(vb), "gradient");
421    update_stop_list (mnu, gradient, NULL);
424 //FIXME!!! We must also listen to attr changes on all children (i.e. stops) too,
425 //otherwise the dialog does not reflect undoing color or offset change. This is a major
426 //hassle, unless we have a "one of the descendants changed in some way" signal.
427 static Inkscape::XML::NodeEventVector grad_edit_dia_repr_events =
429     grad_edit_dia_stop_added_or_removed, /* child_added */
430     grad_edit_dia_stop_added_or_removed, /* child_removed */
431     NULL, /* attr_changed*/
432     NULL, /* content_changed */
433     NULL  /* order_changed */
434 };
436 static void
437 verify_grad(SPGradient *gradient)
439         int i = 0;
440         SPStop *stop = NULL;
441         /* count stops */
442         for ( SPObject *ochild = sp_object_first_child(SP_OBJECT(gradient)) ; ochild != NULL ; ochild = SP_OBJECT_NEXT(ochild) ) {
443                 if (SP_IS_STOP (ochild)) {
444                         i++;
445                         stop = SP_STOP(ochild);
446                 }
447         }
449         if (i < 1) {
450                 gchar c[64];
451                 sp_svg_write_color (c, 64, 0x00000000);
453                 Inkscape::CSSOStringStream os;
454                 os << "stop-color:" << c << ";stop-opacity:" << 1.0 << ";";
456                 Inkscape::XML::Node *child;
458                 child = sp_repr_new ("svg:stop");
459                 sp_repr_set_css_double(child, "offset", 0.0);
460                 child->setAttribute("style", os.str().c_str());
461                 SP_OBJECT_REPR (gradient)->addChild(child, NULL);
463                 child = sp_repr_new ("svg:stop");
464                 sp_repr_set_css_double(child, "offset", 1.0);
465                 child->setAttribute("style", os.str().c_str());
466                 SP_OBJECT_REPR (gradient)->addChild(child, NULL);
467         }
468         if (i < 2) {
469                 sp_repr_set_css_double(SP_OBJECT_REPR(stop), "offset", 0.0);
470                 Inkscape::XML::Node *child = SP_OBJECT_REPR(stop)->duplicate();
471                 sp_repr_set_css_double(child, "offset", 1.0);
472                 SP_OBJECT_REPR(gradient)->addChild(child, SP_OBJECT_REPR (stop));
473         }
476 static void
477 select_stop_in_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_stop)
479         int i = 0;
480         for ( SPObject *ochild = sp_object_first_child(SP_OBJECT(gradient)) ; ochild != NULL ; ochild = SP_OBJECT_NEXT(ochild) ) {
481                 if (SP_IS_STOP (ochild)) {
482                         if (SP_OBJECT (ochild) == SP_OBJECT(new_stop)) {
483                                 gtk_option_menu_set_history (GTK_OPTION_MENU (mnu), i);
484                                 break;
485                         }
486                         i++;
487                 }
488         }
491 static void
492 update_stop_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_stop)
495         if (!SP_IS_GRADIENT (gradient))
496                 return;
498         blocked = TRUE;
500         /* Clear old menu, if there is any */
501         if (gtk_option_menu_get_menu (GTK_OPTION_MENU (mnu))) {
502                 gtk_option_menu_remove_menu (GTK_OPTION_MENU (mnu));
503         }
505         /* Create new menu widget */
506         GtkWidget *m = gtk_menu_new ();
507         gtk_widget_show (m);
508         GSList *sl = NULL;
509         if (gradient->has_stops) {
510                 for ( SPObject *ochild = sp_object_first_child (SP_OBJECT(gradient)) ; ochild != NULL ; ochild = SP_OBJECT_NEXT(ochild) ) {
511                         if (SP_IS_STOP (ochild)) {
512                                 sl = g_slist_append (sl, ochild);
513                         }
514                 }
515         }
516         if (!sl) {
517                 GtkWidget *i = gtk_menu_item_new_with_label (_("No stops in gradient"));
518                 gtk_widget_show (i);
519                 gtk_menu_append (GTK_MENU (m), i);
520                 gtk_widget_set_sensitive (mnu, FALSE);
521         } else {
523                 for (; sl != NULL; sl = sl->next){
524                         SPStop *stop;
525                         GtkWidget *i;
526                         if (SP_IS_STOP(sl->data)){
527                                 stop = SP_STOP (sl->data);
528                                 i = gtk_menu_item_new ();
529                                 gtk_widget_show (i);
530                                 g_object_set_data (G_OBJECT (i), "stop", stop);
531                                 GtkWidget *hb = gtk_hbox_new (FALSE, 4);
532                                 GtkWidget *cpv = sp_color_preview_new(sp_stop_get_rgba32(stop));
533                                 gtk_widget_show (cpv);
534                                 gtk_container_add ( GTK_CONTAINER (hb), cpv );
535                                 g_object_set_data ( G_OBJECT (i), "preview", cpv );
536                                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) sl->data);
537                                 GtkWidget *l = gtk_label_new (repr->attribute("id"));
538                                 gtk_widget_show (l);
539                                 gtk_misc_set_alignment (GTK_MISC (l), 1.0, 0.5);
540                                 gtk_box_pack_start (GTK_BOX (hb), l, TRUE, TRUE, 0);
541                                 gtk_widget_show (hb);
542                                 gtk_container_add (GTK_CONTAINER (i), hb);
543                                 gtk_menu_append (GTK_MENU (m), i);
544                         }
545                 }
547                 gtk_widget_set_sensitive (mnu, TRUE);
548         }
549         gtk_option_menu_set_menu (GTK_OPTION_MENU (mnu), m);
551         /* Set history */
552         if (new_stop == NULL) {
553                 gtk_option_menu_set_history (GTK_OPTION_MENU (mnu), 0);
554         } else {
555                 select_stop_in_list (mnu, gradient, new_stop);
556         }
558         blocked = FALSE;
562 /*user selected existing stop from list*/
563 static void
564 sp_grad_edit_select (GtkOptionMenu *mnu,  GtkWidget *tbl)
566         SPGradient *gradient = (SPGradient *)g_object_get_data (G_OBJECT(tbl), "gradient");
568         GObject *item = G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu))));
569         SPStop *stop = SP_STOP (g_object_get_data (item, "stop"));
570         if (!stop) return;
572         blocked = TRUE;
574         SPColorSelector *csel = (SPColorSelector*)g_object_get_data (G_OBJECT (tbl), "cselector");
575         guint32 const c = sp_stop_get_rgba32(stop);
576         csel->base->setAlpha(SP_RGBA32_A_F (c));
577         SPColor color;
578         sp_color_set_rgb_float (&color, SP_RGBA32_R_F (c), SP_RGBA32_G_F (c), SP_RGBA32_B_F (c));
579         // set its color, from the stored array
580         csel->base->setColor( color );
581         GtkWidget *offspin = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "offspn"));
582         GtkWidget *offslide =GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "offslide"));
584         GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data (GTK_OBJECT (tbl), "offset");
586         bool isEndStop = false;
588         SPStop *prev = NULL;
589         prev = sp_prev_stop(stop, gradient);
590         if (prev != NULL )  {
591           adj->lower = prev->offset;
592         } else {
593           isEndStop = true;
594           adj->lower = 0;
595         }
597         SPStop *next = NULL;
598         next = sp_next_stop(stop);
599         if (next != NULL ) {
600           adj->upper = next->offset;
601         } else {
602           isEndStop = true;
603           adj->upper = 1.0;
604         }
606         //fixme: does this work on all possible input gradients?
607         if (!isEndStop) {
608                 gtk_widget_set_sensitive (offslide, TRUE);
609                 gtk_widget_set_sensitive (GTK_WIDGET (offspin), TRUE);
610         } else {
611                 gtk_widget_set_sensitive (offslide, FALSE);
612                 gtk_widget_set_sensitive (GTK_WIDGET (offspin), FALSE);
613         }
615         gtk_adjustment_set_value (adj, stop->offset);
617         gtk_adjustment_changed (adj);
619         blocked = FALSE;
625 static void
626 offadjustmentChanged( GtkAdjustment *adjustment, GtkWidget *vb)
628         if (blocked)
629                 return;
631         blocked = TRUE;
633     GtkOptionMenu *mnu = (GtkOptionMenu *)g_object_get_data (G_OBJECT(vb), "stopmenu");
634     if (!g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop")) return;
635     SPStop *stop = SP_STOP(g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop"));
637     stop->offset = adjustment->value;
638     sp_repr_set_css_double(SP_OBJECT_REPR(stop), "offset", stop->offset);
640     sp_document_done (SP_OBJECT_DOCUMENT (stop));
642         blocked = FALSE;
645 guint32
646 sp_average_color (guint32 c1, guint32 c2, gdouble p = 0.5)
648         guint32 r = (guint32) (SP_RGBA32_R_U (c1) * p + SP_RGBA32_R_U (c2) * (1 - p));
649         guint32 g = (guint32) (SP_RGBA32_G_U (c1) * p + SP_RGBA32_G_U (c2) * (1 - p));
650         guint32 b = (guint32) (SP_RGBA32_B_U (c1) * p + SP_RGBA32_B_U (c2) * (1 - p));
651         guint32 a = (guint32) (SP_RGBA32_A_U (c1) * p + SP_RGBA32_A_U (c2) * (1 - p));
653         return SP_RGBA32_U_COMPOSE (r, g, b, a);
657 static void
658 sp_grd_ed_add_stop (GtkWidget *widget,  GtkWidget *vb)
660         SPGradient *gradient = (SPGradient *) g_object_get_data (G_OBJECT(vb), "gradient");
661         verify_grad (gradient);
662         GtkOptionMenu *mnu = (GtkOptionMenu *)g_object_get_data (G_OBJECT(vb), "stopmenu");
664         SPStop *stop = (SPStop *) g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop");
666         if (stop == NULL)
667                 return;
669         Inkscape::XML::Node *new_stop_repr = NULL;
671         SPStop *next = sp_next_stop (stop);
673         if (next == NULL) {
674                 SPStop *prev = sp_prev_stop (stop, gradient);
675                 if (prev != NULL) {
676                         next = stop;
677                         stop = prev;
678                 }
679         }
681         if (next != NULL) {
682                 new_stop_repr = SP_OBJECT_REPR(stop)->duplicate();
683                 SP_OBJECT_REPR(gradient)->addChild(new_stop_repr, SP_OBJECT_REPR(stop));
684         } else {
685                 next = stop;
686                 new_stop_repr = SP_OBJECT_REPR(sp_prev_stop(stop, gradient))->duplicate();
687                 SP_OBJECT_REPR(gradient)->addChild(new_stop_repr, SP_OBJECT_REPR(sp_prev_stop(stop, gradient)));
688         }
690         SPStop *newstop = (SPStop *) SP_OBJECT_DOCUMENT(gradient)->getObjectByRepr(new_stop_repr);
692         newstop->offset = (stop->offset + next->offset) * 0.5 ;
694         guint32 const c1 = sp_stop_get_rgba32(stop);
695         guint32 const c2 = sp_stop_get_rgba32(next);
696         guint32 cnew = sp_average_color (c1, c2);
698         Inkscape::CSSOStringStream os;
699         gchar c[64];
700         sp_svg_write_color (c, 64, cnew);
701         gdouble opacity = (gdouble) SP_RGBA32_A_F (cnew);
702         os << "stop-color:" << c << ";stop-opacity:" << opacity <<";";
703         SP_OBJECT_REPR (newstop)->setAttribute("style", os.str().c_str());
705         sp_gradient_vector_widget_load_gradient (vb, gradient);
706         Inkscape::GC::release(new_stop_repr);
707         update_stop_list(GTK_WIDGET(mnu), gradient, newstop);
708         GtkWidget *offspin = GTK_WIDGET (g_object_get_data (G_OBJECT (vb), "offspn"));
709         GtkWidget *offslide =GTK_WIDGET (g_object_get_data (G_OBJECT (vb), "offslide"));
710         gtk_widget_set_sensitive (offslide, TRUE);
711         gtk_widget_set_sensitive (GTK_WIDGET (offspin), TRUE);
712         sp_document_done (SP_OBJECT_DOCUMENT (gradient));
715 static void
716 sp_grd_ed_del_stop (GtkWidget *widget,  GtkWidget *vb)
718         SPGradient *gradient = (SPGradient *)g_object_get_data (G_OBJECT(vb), "gradient");
720         GtkOptionMenu *mnu = (GtkOptionMenu *)g_object_get_data (G_OBJECT(vb), "stopmenu");
721         if (!g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop")) return;
722         SPStop *stop = SP_STOP(g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop"));
723         if (gradient->vector.stops.size() > 2) { // 2 is the minimum
725                 // if we delete first or last stop, move the next/previous to the edge
726                 if (stop->offset == 0) {
727                         SPStop *next = sp_next_stop (stop);
728                         if (next) {
729                                 next->offset = 0;
730                                 sp_repr_set_css_double (SP_OBJECT_REPR (next), "offset", 0);
731                         }
732                 } else if (stop->offset == 1) {
733                         SPStop *prev = sp_prev_stop (stop, gradient);
734                         if (prev) {
735                                 prev->offset = 1;
736                                 sp_repr_set_css_double (SP_OBJECT_REPR (prev), "offset", 1);
737                         }
738                 }
740                 SP_OBJECT_REPR(gradient)->removeChild(SP_OBJECT_REPR(stop));
741                 sp_gradient_vector_widget_load_gradient (vb, gradient);
742                 update_stop_list(GTK_WIDGET(mnu), gradient, NULL);
743                 sp_document_done (SP_OBJECT_DOCUMENT (gradient));
744         }
748 static GtkWidget *
749 sp_gradient_vector_widget_new (SPGradient *gradient, SPStop *select_stop)
751         GtkWidget *vb, *w, *f, *csel;
753         g_return_val_if_fail (!gradient || SP_IS_GRADIENT (gradient), NULL);
755         vb = gtk_vbox_new (FALSE, PAD);
756         g_signal_connect (G_OBJECT (vb), "destroy", G_CALLBACK (sp_gradient_vector_widget_destroy), NULL);
758         w = sp_gradient_image_new (gradient);
759         g_object_set_data (G_OBJECT (vb), "preview", w);
760         gtk_widget_show (w);
761         gtk_box_pack_start (GTK_BOX (vb), w, TRUE, TRUE, PAD);
763         gtk_object_set_data (GTK_OBJECT (vb), "gradient", gradient);
764         sp_repr_add_listener (SP_OBJECT_REPR(gradient), &grad_edit_dia_repr_events, vb);
765         GtkTooltips *tt = gtk_tooltips_new ();
767         /* Stop list */
768         GtkWidget *mnu = gtk_option_menu_new ();
769         /* Create new menu widget */
770         update_stop_list (GTK_WIDGET(mnu), gradient, NULL);
771         gtk_signal_connect (GTK_OBJECT (mnu), "changed", GTK_SIGNAL_FUNC (sp_grad_edit_select), vb);
772         gtk_widget_show (mnu);
773         gtk_object_set_data (GTK_OBJECT (vb), "stopmenu", mnu);
774         gtk_box_pack_start (GTK_BOX (vb), mnu, FALSE, FALSE, 0);
776         /* Add and Remove buttons */
777         GtkWidget *hb = gtk_hbox_new (FALSE, 1);
778         // TRANSLATORS: "Stop" means: a "phase" of a gradient
779         GtkWidget *b = gtk_button_new_with_label (_("Add stop"));
780         gtk_widget_show (b);
781         gtk_container_add (GTK_CONTAINER (hb), b);
782         gtk_tooltips_set_tip (tt, b, _("Add another control stop to gradient"), NULL);
783         gtk_signal_connect (GTK_OBJECT (b), "clicked", GTK_SIGNAL_FUNC (sp_grd_ed_add_stop), vb);
784         b = gtk_button_new_with_label (_("Delete stop"));
785         gtk_widget_show (b);
786         gtk_container_add (GTK_CONTAINER (hb), b);
787         gtk_tooltips_set_tip (tt, b, _("Delete current control stop from gradient"), NULL);
788         gtk_signal_connect (GTK_OBJECT (b), "clicked", GTK_SIGNAL_FUNC (sp_grd_ed_del_stop), vb);
790         gtk_widget_show (hb);
791         gtk_box_pack_start (GTK_BOX (vb),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
794         /*  Offset Slider and stuff   */
795         hb = gtk_hbox_new (FALSE, 0);
797         /* Label */
798         GtkWidget *l = gtk_label_new (_("Offset:"));
799         gtk_misc_set_alignment (GTK_MISC (l), 1.0, 0.5);
800         gtk_box_pack_start (GTK_BOX (hb),l, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
801         gtk_widget_show (l);
803         /* Adjustment */
804         GtkAdjustment *Offset_adj = NULL;
805         Offset_adj= (GtkAdjustment *) gtk_adjustment_new (0.0, 0.0, 1.0, 0.01, 0.01, 0.0);
806         gtk_object_set_data (GTK_OBJECT (vb), "offset", Offset_adj);
807         GtkMenu *m = GTK_MENU(gtk_option_menu_get_menu (GTK_OPTION_MENU(mnu)));
808         SPStop *stop = SP_STOP (g_object_get_data (G_OBJECT (gtk_menu_get_active (m)), "stop"));
809         gtk_adjustment_set_value (Offset_adj, stop->offset);
811         /* Slider */
812         GtkWidget *slider = gtk_hscale_new(Offset_adj);
813         gtk_scale_set_draw_value( GTK_SCALE(slider), FALSE );
814         gtk_widget_show (slider);
815         gtk_box_pack_start (GTK_BOX (hb),slider, TRUE, TRUE, AUX_BETWEEN_BUTTON_GROUPS);
816         gtk_object_set_data (GTK_OBJECT (vb), "offslide", slider);
818         /* Spinbutton */
819         GtkWidget *sbtn = gtk_spin_button_new (GTK_ADJUSTMENT (Offset_adj), 0.01, 2);
820         sp_dialog_defocus_on_enter (sbtn);
821         gtk_widget_show (sbtn);
822         gtk_box_pack_start (GTK_BOX (hb),sbtn, FALSE, TRUE, AUX_BETWEEN_BUTTON_GROUPS);
823         gtk_object_set_data (GTK_OBJECT (vb), "offspn", sbtn);
825         if (stop->offset>0 && stop->offset<1) {
826                 gtk_widget_set_sensitive (slider, TRUE);
827                 gtk_widget_set_sensitive (GTK_WIDGET (sbtn), TRUE);
828         } else {
829                 gtk_widget_set_sensitive (slider, FALSE);
830                 gtk_widget_set_sensitive (GTK_WIDGET (sbtn), FALSE);
831         }
834         /* Signals */
835         gtk_signal_connect (GTK_OBJECT (Offset_adj), "value_changed",
836                                                                                         GTK_SIGNAL_FUNC (offadjustmentChanged), vb);
838         // gtk_signal_connect (GTK_OBJECT (slider), "changed",  GTK_SIGNAL_FUNC (offsliderChanged), vb);
839         gtk_widget_show (hb);
840         gtk_box_pack_start (GTK_BOX (vb), hb, FALSE, FALSE, PAD);
842         // TRANSLATORS: "Stop" means: a "phase" of a gradient
843         f = gtk_frame_new (_("Stop Color"));
844         gtk_widget_show (f);
845         gtk_box_pack_start (GTK_BOX (vb), f, TRUE, TRUE, PAD);
846         csel = (GtkWidget*)sp_color_selector_new (SP_TYPE_COLOR_NOTEBOOK, SP_COLORSPACE_TYPE_NONE);
847         g_object_set_data (G_OBJECT (vb), "cselector", csel);
848         gtk_widget_show (csel);
849         gtk_container_add (GTK_CONTAINER (f), csel);
850         g_signal_connect (G_OBJECT (csel), "dragged", G_CALLBACK (sp_gradient_vector_color_dragged), vb);
851         g_signal_connect (G_OBJECT (csel), "changed", G_CALLBACK (sp_gradient_vector_color_changed), vb);
853         gtk_widget_show (vb);
855         sp_gradient_vector_widget_load_gradient (vb, gradient);
857         if (select_stop)
858                 select_stop_in_list (GTK_WIDGET(mnu), gradient, select_stop);
860         return vb;
865 GtkWidget *
866 sp_gradient_vector_editor_new (SPGradient *gradient, SPStop *stop)
868         GtkWidget *wid;
870         if (dlg == NULL) {
872                 dlg = sp_window_new (_("Gradient editor"), TRUE);
873                 if (x == -1000 || y == -1000) {
874                         x = prefs_get_int_attribute (prefs_path, "x", 0);
875                         y = prefs_get_int_attribute (prefs_path, "y", 0);
876                 }
877                 if (w ==0 || h == 0) {
878                         w = prefs_get_int_attribute (prefs_path, "w", 0);
879                         h = prefs_get_int_attribute (prefs_path, "h", 0);
880                 }
881                 if (x != 0 || y != 0)
882                         gtk_window_move ((GtkWindow *) dlg, x, y);
883                 else
884                         gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
885                 if (w && h) gtk_window_resize ((GtkWindow *) dlg, w, h);
886                 sp_transientize (dlg);
887                 wd.win = dlg;
888                 wd.stop = 0;
889                 g_signal_connect (G_OBJECT (INKSCAPE), "activate_desktop", G_CALLBACK (sp_transientize_callback), &wd);
890                 gtk_signal_connect (GTK_OBJECT (dlg), "event", GTK_SIGNAL_FUNC (sp_dialog_event_handler), dlg);
891                 gtk_signal_connect (GTK_OBJECT (dlg), "destroy", G_CALLBACK (sp_gradient_vector_dialog_destroy), dlg);
892                 gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", G_CALLBACK (sp_gradient_vector_dialog_delete), dlg);
893                 g_signal_connect (G_OBJECT (INKSCAPE), "shut_down", G_CALLBACK (sp_gradient_vector_dialog_delete), dlg);
894                 g_signal_connect ( G_OBJECT (INKSCAPE), "dialogs_hide", G_CALLBACK (sp_dialog_hide), dlg );
895                 g_signal_connect ( G_OBJECT (INKSCAPE), "dialogs_unhide", G_CALLBACK (sp_dialog_unhide), dlg );
897                 gtk_container_set_border_width (GTK_CONTAINER (dlg), PAD);
899                 wid = (GtkWidget*)sp_gradient_vector_widget_new (gradient, stop);
900                 g_object_set_data (G_OBJECT (dlg), "gradient-vector-widget", wid);
901                 /* Connect signals */
902                 gtk_widget_show (wid);
903                 gtk_container_add (GTK_CONTAINER (dlg), wid);
904         } else {
905                 // FIXME: temp fix for 0.38
906                 // Simply load_gradient into the editor does not work for multi-stop gradients,
907                 // as the stop list and other widgets are in a wrong state and crash readily.
908                 // Instead we just delete the window (by sending the delete signal)
909                 // and call sp_gradient_vector_editor_new again, so it creates the window anew.
911                 GdkEventAny event;
912                 GtkWidget *widget = (GtkWidget *) dlg;
913                 event.type = GDK_DELETE;
914                 event.window = widget->window;
915                 event.send_event = TRUE;
916                 g_object_ref (G_OBJECT (event.window));
917                 gtk_main_do_event ((GdkEvent*)&event);
918                 g_object_unref (G_OBJECT (event.window));
920                 g_assert (dlg == NULL);
921                 sp_gradient_vector_editor_new (gradient, stop);
922         }
924         return dlg;
927 static void
928 sp_gradient_vector_widget_load_gradient (GtkWidget *widget, SPGradient *gradient)
930         blocked = TRUE;
932         SPGradient *old;
934         old = (SPGradient*)g_object_get_data (G_OBJECT (widget), "gradient");
935         if (old != gradient) {
936                 if (old) {
937                         sp_signal_disconnect_by_data (old, widget);
938                 }
939                 if (gradient) {
940                         g_signal_connect (G_OBJECT (gradient), "release", G_CALLBACK (sp_gradient_vector_gradient_release), widget);
941                         g_signal_connect (G_OBJECT (gradient), "modified", G_CALLBACK (sp_gradient_vector_gradient_modified), widget);
942                 }
943         }
945         g_object_set_data (G_OBJECT (widget), "gradient", gradient);
947         if (gradient) {
948                 sp_gradient_ensure_vector (gradient);
950                 GtkOptionMenu *mnu = (GtkOptionMenu *)g_object_get_data (G_OBJECT(widget), "stopmenu");
951                 SPStop *stop = SP_STOP(g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop"));
952                 guint32 const c = sp_stop_get_rgba32(stop);
954                 /// get the color selector
955                 SPColorSelector *csel = SP_COLOR_SELECTOR(g_object_get_data (G_OBJECT (widget), "cselector"));
956                 // set alpha
957                 csel->base->setAlpha(SP_RGBA32_A_F (c));
958                 SPColor color;
959                 sp_color_set_rgb_float (&color, SP_RGBA32_R_F (c), SP_RGBA32_G_F (c), SP_RGBA32_B_F (c));
960                 // set color
961                 csel->base->setColor( color );
962         }
964         /* Fill preview */
965         GtkWidget *w = static_cast<GtkWidget *>(g_object_get_data(G_OBJECT(widget), "preview"));
966         sp_gradient_image_set_gradient (SP_GRADIENT_IMAGE (w), gradient);
968         GtkWidget *mnu = static_cast<GtkWidget *>(g_object_get_data(G_OBJECT(widget), "stopmenu"));
969         update_stop_list (GTK_WIDGET(mnu), gradient, NULL);
971         // Once the user edits a gradient, it stops being auto-collectable
972         if (SP_OBJECT_REPR(gradient)->attribute("inkscape:collect")) {
973                 SPDocument *document = SP_OBJECT_DOCUMENT (gradient);
974                 gboolean saved = sp_document_get_undo_sensitive(document);
975                 sp_document_set_undo_sensitive (document, FALSE);
976                 SP_OBJECT_REPR(gradient)->setAttribute("inkscape:collect", NULL);
977                 sp_document_set_undo_sensitive (document, saved);
978         }
980         blocked = FALSE;
983 static void
984 sp_gradient_vector_dialog_destroy (GtkObject *object, gpointer data)
986         sp_signal_disconnect_by_data (INKSCAPE, dlg);
987         wd.win = dlg = NULL;
988         wd.stop = 0;
991 static gboolean
992 sp_gradient_vector_dialog_delete (GtkWidget *widget, GdkEvent *event, GtkWidget *dialog)
994         gtk_window_get_position ((GtkWindow *) dlg, &x, &y);
995         gtk_window_get_size ((GtkWindow *) dlg, &w, &h);
997     if (x<0) x=0;
998     if (y<0) y=0;
1000         prefs_set_int_attribute (prefs_path, "x", x);
1001         prefs_set_int_attribute (prefs_path, "y", y);
1002         prefs_set_int_attribute (prefs_path, "w", w);
1003         prefs_set_int_attribute (prefs_path, "h", h);
1005         return FALSE; // which means, go ahead and destroy it
1008 /* Widget destroy handler */
1010 static void
1011 sp_gradient_vector_widget_destroy (GtkObject *object, gpointer data)
1013         GObject *gradient;
1015         gradient = (GObject*)g_object_get_data (G_OBJECT (object), "gradient");
1017         if (gradient && SP_OBJECT_REPR(gradient)) {
1018                 /* Remove signals connected to us */
1019                 /* fixme: may use _connect_while_alive as well */
1020                 sp_signal_disconnect_by_data (gradient, object);
1021                 sp_repr_remove_listener_by_data (SP_OBJECT_REPR(gradient), object);
1022         }
1025 static void
1026 sp_gradient_vector_gradient_release (SPGradient *gradient, GtkWidget *widget)
1028         sp_gradient_vector_widget_load_gradient (widget, NULL);
1031 static void
1032 sp_gradient_vector_gradient_modified (SPGradient *gradient, guint flags, GtkWidget *widget)
1034         if (!blocked) {
1035                 blocked = TRUE;
1036                 sp_gradient_vector_widget_load_gradient (widget, gradient);
1037                 blocked = FALSE;
1038         }
1041 static void sp_gradient_vector_color_dragged(SPColorSelector *csel, GtkObject *object)
1043         SPGradient *gradient, *ngr;
1045         if (blocked) return;
1047         gradient = (SPGradient*)g_object_get_data (G_OBJECT (object), "gradient");
1048         if (!gradient) return;
1050         blocked = TRUE;
1052         ngr = sp_gradient_ensure_vector_normalized (gradient);
1053         if (ngr != gradient) {
1054                 /* Our master gradient has changed */
1055                 sp_gradient_vector_widget_load_gradient (GTK_WIDGET (object), ngr);
1056         }
1058         sp_gradient_ensure_vector (ngr);
1060     GtkOptionMenu *mnu = (GtkOptionMenu *)g_object_get_data (G_OBJECT(object), "stopmenu");
1061     SPStop *stop = SP_STOP(g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop"));
1064     csel->base->getColorAlpha(stop->specified_color, &stop->opacity);
1065     stop->currentColor = false;
1067         blocked = FALSE;
1068     SPColorPreview *cpv = (SPColorPreview *)g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "preview");
1069     sp_color_preview_set_rgba32(cpv, sp_stop_get_rgba32(stop));
1073 static void
1074 sp_gradient_vector_color_changed (SPColorSelector *csel, GtkObject *object)
1076         SPColor color;
1077         float alpha;
1078         guint32 rgb;
1080         if (blocked) return;
1082         SPGradient *gradient = (SPGradient*)g_object_get_data (G_OBJECT (object), "gradient");
1083         if (!gradient) return;
1085         blocked = TRUE;
1087         SPGradient *ngr = sp_gradient_ensure_vector_normalized (gradient);
1088         if (ngr != gradient) {
1089                 /* Our master gradient has changed */
1090                 sp_gradient_vector_widget_load_gradient (GTK_WIDGET (object), ngr);
1091         }
1093         sp_gradient_ensure_vector (ngr);
1095         /* Set start parameters */
1096         /* We rely on normalized vector, i.e. stops HAVE to exist */
1097         g_return_if_fail (sp_first_stop(ngr) != NULL);
1099         GtkOptionMenu *mnu = (GtkOptionMenu *)g_object_get_data (G_OBJECT(object), "stopmenu");
1100         SPStop *stop = SP_STOP(g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop"));
1102         csel = (SPColorSelector*)g_object_get_data (G_OBJECT (object), "cselector");
1103         csel->base->getColorAlpha( color, &alpha );
1104         rgb = sp_color_get_rgba32_ualpha (&color, 0x00);
1106         sp_repr_set_css_double (SP_OBJECT_REPR (stop), "offset", stop->offset);
1107         Inkscape::CSSOStringStream os;
1108         gchar c[64];
1109         sp_svg_write_color (c, 64, rgb);
1110         os << "stop-color:" << c << ";stop-opacity:" << (gdouble) alpha <<";";
1111         SP_OBJECT_REPR (stop)->setAttribute("style", os.str().c_str());
1112                 //      g_snprintf (c, 256, "stop-color:#%06x;stop-opacity:%g;", rgb >> 8, (gdouble) alpha);
1113                 //SP_OBJECT_REPR (stop)->setAttribute("style", c);
1115         sp_document_done (SP_OBJECT_DOCUMENT (ngr));
1117         blocked = FALSE;