Code

Revert recent refactoring changes by johnce because they break the build, which canno...
[inkscape.git] / src / widgets / gradient-vector.cpp
1 /*
2  * Gradient vector selection widget
3  *
4  * Authors:
5  *   Lauris Kaplinski <lauris@kaplinski.com>
6  *   bulia byak <buliabyak@users.sf.net>
7  *   MenTaLguY <mental@rydia.net>
8  *
9  * Copyright (C) 2001-2002 Lauris Kaplinski
10  * Copyright (C) 2001 Ximian, Inc.
11  * Copyright (C) 2004 Monash University
12  * Copyright (C) 2004 David Turner
13  * Copyright (C) 2006 MenTaLguY
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 "../preferences.h"
38 #include "svg/css-ostringstream.h"
39 #include "sp-stop.h"
41 #include <sigc++/functors/ptr_fun.h>
42 #include <sigc++/adaptors/bind.h>
44 enum {
45     VECTOR_SET,
46     LAST_SIGNAL
47 };
49 static void sp_gradient_vector_selector_class_init (SPGradientVectorSelectorClass *klass);
50 static void sp_gradient_vector_selector_init (SPGradientVectorSelector *gvs);
51 static void sp_gradient_vector_selector_destroy (GtkObject *object);
53 static void sp_gvs_gradient_release (SPObject *obj, SPGradientVectorSelector *gvs);
54 static void sp_gvs_defs_release (SPObject *defs, SPGradientVectorSelector *gvs);
55 static void sp_gvs_defs_modified (SPObject *defs, guint flags, SPGradientVectorSelector *gvs);
57 static void sp_gvs_rebuild_gui_full (SPGradientVectorSelector *gvs);
58 static void sp_gvs_gradient_activate (GtkMenuItem *mi, SPGradientVectorSelector *gvs);
60 static GtkVBoxClass *parent_class;
61 static guint signals[LAST_SIGNAL] = {0};
63 // TODO FIXME kill these globals!!!
64 static GtkWidget *dlg = NULL;
65 static win_data wd;
66 static gint x = -1000, y = -1000, w = 0, h = 0; // impossible original values to make sure they are read from prefs
67 static Glib::ustring const prefs_path = "/dialogs/gradienteditor/";
69 GType sp_gradient_vector_selector_get_type(void)
70 {
71     static GType type = 0;
72     if (!type) {
73         static const GTypeInfo info = {
74             sizeof(SPGradientVectorSelectorClass),
75             NULL, /* base_init */
76             NULL, /* base_finalize */
77             (GClassInitFunc) sp_gradient_vector_selector_class_init,
78             NULL, /* class_finalize */
79             NULL, /* class_data */
80             sizeof(SPGradientVectorSelector),
81             0,    /* n_preallocs */
82             (GInstanceInitFunc) sp_gradient_vector_selector_init,
83             0,    /* value_table */
84         };
86         type = g_type_register_static( GTK_TYPE_VBOX,
87                                        "SPGradientVectorSelector",
88                                        &info,
89                                        static_cast< GTypeFlags > (0) );
90     }
91     return type;
92 }
94 static void
95 sp_gradient_vector_selector_class_init (SPGradientVectorSelectorClass *klass)
96 {
97     GtkObjectClass *object_class;
99     object_class = GTK_OBJECT_CLASS (klass);
101     parent_class = (GtkVBoxClass*)gtk_type_class (GTK_TYPE_VBOX);
103     signals[VECTOR_SET] = gtk_signal_new ("vector_set",
104                                           GTK_RUN_LAST,
105                                           GTK_CLASS_TYPE(object_class),
106                                           GTK_SIGNAL_OFFSET (SPGradientVectorSelectorClass, vector_set),
107                                           gtk_marshal_NONE__POINTER,
108                                           GTK_TYPE_NONE, 1,
109                                           GTK_TYPE_POINTER);
111     object_class->destroy = sp_gradient_vector_selector_destroy;
114 static void
115 sp_gradient_vector_selector_init (SPGradientVectorSelector *gvs)
117     gvs->idlabel = TRUE;
119     gvs->doc = NULL;
120     gvs->gr = NULL;
122     new (&gvs->gradient_release_connection) sigc::connection();
123     new (&gvs->defs_release_connection) sigc::connection();
124     new (&gvs->defs_modified_connection) sigc::connection();
126     gvs->menu = gtk_option_menu_new ();
127     gtk_widget_show (gvs->menu);
128     gtk_box_pack_start (GTK_BOX (gvs), gvs->menu, TRUE, TRUE, 0);
131 static void
132 sp_gradient_vector_selector_destroy (GtkObject *object)
134     SPGradientVectorSelector *gvs;
136     gvs = SP_GRADIENT_VECTOR_SELECTOR (object);
138     if (gvs->gr) {
139         gvs->gradient_release_connection.disconnect();
140         gvs->gr = NULL;
141     }
143     if (gvs->doc) {
144         gvs->defs_release_connection.disconnect();
145         gvs->defs_modified_connection.disconnect();
146         gvs->doc = NULL;
147     }
149     gvs->gradient_release_connection.~connection();
150     gvs->defs_release_connection.~connection();
151     gvs->defs_modified_connection.~connection();
153     if (((GtkObjectClass *) (parent_class))->destroy)
154         (* ((GtkObjectClass *) (parent_class))->destroy) (object);
157 GtkWidget *
158 sp_gradient_vector_selector_new (SPDocument *doc, SPGradient *gr)
160     GtkWidget *gvs;
162     g_return_val_if_fail (!gr || SP_IS_GRADIENT (gr), NULL);
163     g_return_val_if_fail (!gr || (SP_OBJECT_DOCUMENT (gr) == doc), NULL);
165     gvs = (GtkWidget*)gtk_type_new (SP_TYPE_GRADIENT_VECTOR_SELECTOR);
167     if (doc) {
168         sp_gradient_vector_selector_set_gradient (SP_GRADIENT_VECTOR_SELECTOR (gvs), doc, gr);
169     } else {
170         sp_gvs_rebuild_gui_full (SP_GRADIENT_VECTOR_SELECTOR (gvs));
171     }
173     return gvs;
176 void
177 sp_gradient_vector_selector_set_gradient (SPGradientVectorSelector *gvs, SPDocument *doc, SPGradient *gr)
179     static gboolean suppress = FALSE;
181     g_return_if_fail (gvs != NULL);
182     g_return_if_fail (SP_IS_GRADIENT_VECTOR_SELECTOR (gvs));
183     g_return_if_fail (!gr || (doc != NULL));
184     g_return_if_fail (!gr || SP_IS_GRADIENT (gr));
185     g_return_if_fail (!gr || (SP_OBJECT_DOCUMENT (gr) == doc));
186     g_return_if_fail (!gr || SP_GRADIENT_HAS_STOPS (gr));
188     if (doc != gvs->doc) {
189         /* Disconnect signals */
190         if (gvs->gr) {
191             gvs->gradient_release_connection.disconnect();
192             gvs->gr = NULL;
193         }
194         if (gvs->doc) {
195             gvs->defs_release_connection.disconnect();
196             gvs->defs_modified_connection.disconnect();
197             gvs->doc = NULL;
198         }
199         /* Connect signals */
200         if (doc) {
201             gvs->defs_release_connection = SP_DOCUMENT_DEFS(doc)->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gvs_defs_release), gvs));
202             gvs->defs_modified_connection = SP_DOCUMENT_DEFS(doc)->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_gvs_defs_modified), gvs));
203         }
204         if (gr) {
205             gvs->gradient_release_connection = gr->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gvs_gradient_release), gvs));
206         }
207         gvs->doc = doc;
208         gvs->gr = gr;
209         sp_gvs_rebuild_gui_full (gvs);
210         if (!suppress) g_signal_emit (G_OBJECT (gvs), signals[VECTOR_SET], 0, gr);
211     } else if (gr != gvs->gr) {
212         /* Harder case - keep document, rebuild menus and stuff */
213         /* fixme: (Lauris) */
214         suppress = TRUE;
215         sp_gradient_vector_selector_set_gradient (gvs, NULL, NULL);
216         sp_gradient_vector_selector_set_gradient (gvs, doc, gr);
217         suppress = FALSE;
218         g_signal_emit (G_OBJECT (gvs), signals[VECTOR_SET], 0, gr);
219     }
220     /* The case of setting NULL -> NULL is not very interesting */
223 SPDocument *
224 sp_gradient_vector_selector_get_document (SPGradientVectorSelector *gvs)
226     g_return_val_if_fail (gvs != NULL, NULL);
227     g_return_val_if_fail (SP_IS_GRADIENT_VECTOR_SELECTOR (gvs), NULL);
229     return gvs->doc;
232 SPGradient *
233 sp_gradient_vector_selector_get_gradient (SPGradientVectorSelector *gvs)
235     g_return_val_if_fail (gvs != NULL, NULL);
236     g_return_val_if_fail (SP_IS_GRADIENT_VECTOR_SELECTOR (gvs), NULL);
238     return gvs->gr;
241 static void
242 sp_gvs_rebuild_gui_full (SPGradientVectorSelector *gvs)
244     /* Clear old menu, if there is any */
245     if (gtk_option_menu_get_menu (GTK_OPTION_MENU (gvs->menu))) {
246         gtk_option_menu_remove_menu (GTK_OPTION_MENU (gvs->menu));
247     }
249     /* Create new menu widget */
250     GtkWidget *m = gtk_menu_new ();
251     gtk_widget_show (m);
253     /* Pick up all gradients with vectors */
254     GSList *gl = NULL;
255     if (gvs->gr) {
256         const GSList *gradients = sp_document_get_resource_list (SP_OBJECT_DOCUMENT (gvs->gr), "gradient");
257         for (const GSList *l = gradients; l != NULL; l = l->next) {
258             if (SP_GRADIENT_HAS_STOPS (l->data)) {
259                 gl = g_slist_prepend (gl, l->data);
260             }
261         }
262     }
263     gl = g_slist_reverse (gl);
265     gint pos = 0;
266     gint idx = 0;
268     if (!gvs->doc) {
269         GtkWidget *i;
270         i = gtk_menu_item_new_with_label (_("No document selected"));
271         gtk_widget_show (i);
272         gtk_menu_append (GTK_MENU (m), i);
273         gtk_widget_set_sensitive (gvs->menu, FALSE);
274     } else if (!gl) {
275         GtkWidget *i;
276         i = gtk_menu_item_new_with_label (_("No gradients in document"));
277         gtk_widget_show (i);
278         gtk_menu_append (GTK_MENU (m), i);
279         gtk_widget_set_sensitive (gvs->menu, FALSE);
280     } else if (!gvs->gr) {
281         GtkWidget *i;
282         i = gtk_menu_item_new_with_label (_("No gradient selected"));
283         gtk_widget_show (i);
284         gtk_menu_append (GTK_MENU (m), i);
285         gtk_widget_set_sensitive (gvs->menu, FALSE);
286     } else {
287         while (gl) {
288             SPGradient *gr;
289             GtkWidget *i, *w;
290             gr = SP_GRADIENT (gl->data);
291             gl = g_slist_remove (gl, gr);
293             /* We have to know: */
294             /* Gradient destroy */
295             /* Gradient name change */
296             i = gtk_menu_item_new ();
297             gtk_widget_show (i);
298             g_object_set_data (G_OBJECT (i), "gradient", gr);
299             g_signal_connect (G_OBJECT (i), "activate", G_CALLBACK (sp_gvs_gradient_activate), gvs);
301             w = sp_gradient_image_new (gr);
302             gtk_widget_show (w);
304             if (gvs->idlabel) {
305                 GtkWidget *hb, *l;
306                 hb = gtk_hbox_new (FALSE, 4);
307                 gtk_widget_show (hb);
308                 l = gtk_label_new (SP_OBJECT_ID (gr));
309                 gtk_widget_show (l);
310                 gtk_misc_set_alignment (GTK_MISC (l), 1.0, 0.5);
311                 gtk_box_pack_start (GTK_BOX (hb), l, TRUE, TRUE, 0);
312                 gtk_box_pack_start (GTK_BOX (hb), w, FALSE, FALSE, 0);
313                 w = hb;
314             }
316             gtk_container_add (GTK_CONTAINER (i), w);
318             gtk_menu_append (GTK_MENU (m), i);
320             if (gr == gvs->gr) pos = idx;
321             idx += 1;
322         }
323         gtk_widget_set_sensitive (gvs->menu, TRUE);
324     }
326     gtk_option_menu_set_menu (GTK_OPTION_MENU (gvs->menu), m);
327     /* Set history */
328     gtk_option_menu_set_history (GTK_OPTION_MENU (gvs->menu), pos);
331 static void
332 sp_gvs_gradient_activate (GtkMenuItem *mi, SPGradientVectorSelector *gvs)
334     SPGradient *gr, *norm;
336     gr = (SPGradient*)g_object_get_data (G_OBJECT (mi), "gradient");
337     /* Hmmm... bad things may happen here, if actual gradient is something new */
338     /* Namely - menuitems etc. will be fucked up */
339     /* Hmmm - probably we can just re-set it as menuitem data (Lauris) */
341     //g_print ("SPGradientVectorSelector: gradient %s activated\n", SP_OBJECT_ID (gr));
343     norm = sp_gradient_ensure_vector_normalized (gr);
344     if (norm != gr) {
345         //g_print ("SPGradientVectorSelector: become %s after normalization\n", SP_OBJECT_ID (norm));
346         /* But be careful that we do not have gradient saved anywhere else */
347         g_object_set_data (G_OBJECT (mi), "gradient", norm);
348     }
350     /* fixme: Really we would want to use _set_vector */
351     /* Detach old */
352     if (gvs->gr) {
353         gvs->gradient_release_connection.disconnect();
354         gvs->gr = NULL;
355     }
356     /* Attach new */
357     if (norm) {
358         gvs->gradient_release_connection = norm->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gvs_gradient_release), gvs));
359         gvs->gr = norm;
360     }
362     g_signal_emit (G_OBJECT (gvs), signals[VECTOR_SET], 0, norm);
364     if (norm != gr) {
365         /* We do extra undo push here */
366         /* If handler has already done it, it is just NOP */
367         // FIXME: looks like this is never a valid undo step, consider removing this
368         sp_document_done (SP_OBJECT_DOCUMENT (norm), SP_VERB_CONTEXT_GRADIENT,
369                           /* TODO: annotate */ "gradient-vector.cpp:350");
370     }
373 static void
374 sp_gvs_gradient_release (SPObject */*obj*/, SPGradientVectorSelector *gvs)
376     /* Disconnect gradient */
377     if (gvs->gr) {
378         gvs->gradient_release_connection.disconnect();
379         gvs->gr = NULL;
380     }
382     /* Rebuild GUI */
383     sp_gvs_rebuild_gui_full (gvs);
386 static void
387 sp_gvs_defs_release (SPObject */*defs*/, SPGradientVectorSelector *gvs)
389     gvs->doc = NULL;
391     gvs->defs_release_connection.disconnect();
392     gvs->defs_modified_connection.disconnect();
394     /* Disconnect gradient as well */
395     if (gvs->gr) {
396         gvs->gradient_release_connection.disconnect();
397         gvs->gr = NULL;
398     }
400     /* Rebuild GUI */
401     sp_gvs_rebuild_gui_full (gvs);
404 static void
405 sp_gvs_defs_modified (SPObject */*defs*/, guint /*flags*/, SPGradientVectorSelector *gvs)
407     /* fixme: We probably have to check some flags here (Lauris) */
409     sp_gvs_rebuild_gui_full (gvs);
412 /*##################################################################
413   ###                 Vector Editing Widget
414   ##################################################################*/
416 #include "../widgets/sp-color-notebook.h"
417 #include "../widgets/sp-color-preview.h"
418 #include "../widgets/widget-sizes.h"
419 #include "../xml/node-event-vector.h"
420 #include "../svg/svg-color.h"
423 #define PAD 4
425 static GtkWidget *sp_gradient_vector_widget_new (SPGradient *gradient, SPStop *stop);
427 static void sp_gradient_vector_widget_load_gradient (GtkWidget *widget, SPGradient *gradient);
428 static gint sp_gradient_vector_dialog_delete (GtkWidget *widget, GdkEvent *event, GtkWidget *dialog);
429 static void sp_gradient_vector_dialog_destroy (GtkObject *object, gpointer data);
431 static void sp_gradient_vector_widget_destroy (GtkObject *object, gpointer data);
432 static void sp_gradient_vector_gradient_release (SPObject *obj, GtkWidget *widget);
433 static void sp_gradient_vector_gradient_modified (SPObject *obj, guint flags, GtkWidget *widget);
434 static void sp_gradient_vector_color_dragged (SPColorSelector *csel, GtkObject *object);
435 static void sp_gradient_vector_color_changed (SPColorSelector *csel, GtkObject *object);
436 static void update_stop_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_stop);
438 static gboolean blocked = FALSE;
440 static void grad_edit_dia_stop_added_or_removed (Inkscape::XML::Node */*repr*/, Inkscape::XML::Node */*child*/, Inkscape::XML::Node */*ref*/, gpointer data)
442     GtkWidget *vb = GTK_WIDGET(data);
443     GtkWidget *mnu = (GtkWidget *)g_object_get_data (G_OBJECT(vb), "stopmenu");
444     SPGradient *gradient = (SPGradient *)g_object_get_data (G_OBJECT(vb), "gradient");
445     update_stop_list (mnu, gradient, NULL);
448 //FIXME!!! We must also listen to attr changes on all children (i.e. stops) too,
449 //otherwise the dialog does not reflect undoing color or offset change. This is a major
450 //hassle, unless we have a "one of the descendants changed in some way" signal.
451 static Inkscape::XML::NodeEventVector grad_edit_dia_repr_events =
453     grad_edit_dia_stop_added_or_removed, /* child_added */
454     grad_edit_dia_stop_added_or_removed, /* child_removed */
455     NULL, /* attr_changed*/
456     NULL, /* content_changed */
457     NULL  /* order_changed */
458 };
460 static void
461 verify_grad(SPGradient *gradient)
463     int i = 0;
464     SPStop *stop = NULL;
465     /* count stops */
466     for ( SPObject *ochild = sp_object_first_child(SP_OBJECT(gradient)) ; ochild != NULL ; ochild = SP_OBJECT_NEXT(ochild) ) {
467         if (SP_IS_STOP (ochild)) {
468             i++;
469             stop = SP_STOP(ochild);
470         }
471     }
473     Inkscape::XML::Document *xml_doc;
474     xml_doc = SP_OBJECT_REPR(gradient)->document();
476     if (i < 1) {
477         gchar c[64];
478         sp_svg_write_color (c, sizeof(c), 0x00000000);
480         Inkscape::CSSOStringStream os;
481         os << "stop-color:" << c << ";stop-opacity:" << 1.0 << ";";
483         Inkscape::XML::Node *child;
485         child = xml_doc->createElement("svg:stop");
486         sp_repr_set_css_double(child, "offset", 0.0);
487         child->setAttribute("style", os.str().c_str());
488         SP_OBJECT_REPR (gradient)->addChild(child, NULL);
489         Inkscape::GC::release(child);
491         child = xml_doc->createElement("svg:stop");
492         sp_repr_set_css_double(child, "offset", 1.0);
493         child->setAttribute("style", os.str().c_str());
494         SP_OBJECT_REPR (gradient)->addChild(child, NULL);
495         Inkscape::GC::release(child);
496     }
497     if (i < 2) {
498         sp_repr_set_css_double(SP_OBJECT_REPR(stop), "offset", 0.0);
499         Inkscape::XML::Node *child = SP_OBJECT_REPR(stop)->duplicate(SP_OBJECT_REPR(gradient)->document());
500         sp_repr_set_css_double(child, "offset", 1.0);
501         SP_OBJECT_REPR(gradient)->addChild(child, SP_OBJECT_REPR (stop));
502         Inkscape::GC::release(child);
503     }
506 static void
507 select_stop_in_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_stop)
509     int i = 0;
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             if (SP_OBJECT (ochild) == SP_OBJECT(new_stop)) {
513                 gtk_option_menu_set_history (GTK_OPTION_MENU (mnu), i);
514                 break;
515             }
516             i++;
517         }
518     }
521 static void
522 update_stop_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_stop)
525     if (!SP_IS_GRADIENT (gradient))
526         return;
528     blocked = TRUE;
530     /* Clear old menu, if there is any */
531     if (gtk_option_menu_get_menu (GTK_OPTION_MENU (mnu))) {
532         gtk_option_menu_remove_menu (GTK_OPTION_MENU (mnu));
533     }
535     /* Create new menu widget */
536     GtkWidget *m = gtk_menu_new ();
537     gtk_widget_show (m);
538     GSList *sl = NULL;
539     if (gradient->has_stops) {
540         for ( SPObject *ochild = sp_object_first_child (SP_OBJECT(gradient)) ; ochild != NULL ; ochild = SP_OBJECT_NEXT(ochild) ) {
541             if (SP_IS_STOP (ochild)) {
542                 sl = g_slist_append (sl, ochild);
543             }
544         }
545     }
546     if (!sl) {
547         GtkWidget *i = gtk_menu_item_new_with_label (_("No stops in gradient"));
548         gtk_widget_show (i);
549         gtk_menu_append (GTK_MENU (m), i);
550         gtk_widget_set_sensitive (mnu, FALSE);
551     } else {
553         for (; sl != NULL; sl = sl->next){
554             SPStop *stop;
555             GtkWidget *i;
556             if (SP_IS_STOP(sl->data)){
557                 stop = SP_STOP (sl->data);
558                 i = gtk_menu_item_new ();
559                 gtk_widget_show (i);
560                 g_object_set_data (G_OBJECT (i), "stop", stop);
561                 GtkWidget *hb = gtk_hbox_new (FALSE, 4);
562                 GtkWidget *cpv = sp_color_preview_new(sp_stop_get_rgba32(stop));
563                 gtk_widget_show (cpv);
564                 gtk_container_add ( GTK_CONTAINER (hb), cpv );
565                 g_object_set_data ( G_OBJECT (i), "preview", cpv );
566                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) sl->data);
567                 GtkWidget *l = gtk_label_new (repr->attribute("id"));
568                 gtk_widget_show (l);
569                 gtk_misc_set_alignment (GTK_MISC (l), 1.0, 0.5);
570                 gtk_box_pack_start (GTK_BOX (hb), l, TRUE, TRUE, 0);
571                 gtk_widget_show (hb);
572                 gtk_container_add (GTK_CONTAINER (i), hb);
573                 gtk_menu_append (GTK_MENU (m), i);
574             }
575         }
577         gtk_widget_set_sensitive (mnu, TRUE);
578     }
579     gtk_option_menu_set_menu (GTK_OPTION_MENU (mnu), m);
581     /* Set history */
582     if (new_stop == NULL) {
583         gtk_option_menu_set_history (GTK_OPTION_MENU (mnu), 0);
584     } else {
585         select_stop_in_list (mnu, gradient, new_stop);
586     }
588     blocked = FALSE;
592 /*user selected existing stop from list*/
593 static void
594 sp_grad_edit_select (GtkOptionMenu *mnu,  GtkWidget *tbl)
596     SPGradient *gradient = (SPGradient *)g_object_get_data (G_OBJECT(tbl), "gradient");
598     GObject *item = G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu))));
599     SPStop *stop = SP_STOP (g_object_get_data (item, "stop"));
600     if (!stop) return;
602     blocked = TRUE;
604     SPColorSelector *csel = (SPColorSelector*)g_object_get_data (G_OBJECT (tbl), "cselector");
605     guint32 const c = sp_stop_get_rgba32(stop);
606     csel->base->setAlpha(SP_RGBA32_A_F (c));
607     SPColor color( SP_RGBA32_R_F (c), SP_RGBA32_G_F (c), SP_RGBA32_B_F (c) );
608     // set its color, from the stored array
609     csel->base->setColor( color );
610     GtkWidget *offspin = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "offspn"));
611     GtkWidget *offslide =GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "offslide"));
613     GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data (GTK_OBJECT (tbl), "offset");
615     bool isEndStop = false;
617     SPStop *prev = NULL;
618     prev = sp_prev_stop(stop, gradient);
619     if (prev != NULL )  {
620         adj->lower = prev->offset;
621     } else {
622         isEndStop = true;
623         adj->lower = 0;
624     }
626     SPStop *next = NULL;
627     next = sp_next_stop(stop);
628     if (next != NULL ) {
629         adj->upper = next->offset;
630     } else {
631         isEndStop = true;
632         adj->upper = 1.0;
633     }
635     //fixme: does this work on all possible input gradients?
636     if (!isEndStop) {
637         gtk_widget_set_sensitive (offslide, TRUE);
638         gtk_widget_set_sensitive (GTK_WIDGET (offspin), TRUE);
639     } else {
640         gtk_widget_set_sensitive (offslide, FALSE);
641         gtk_widget_set_sensitive (GTK_WIDGET (offspin), FALSE);
642     }
644     gtk_adjustment_set_value (adj, stop->offset);
646     gtk_adjustment_changed (adj);
648     blocked = FALSE;
654 static void
655 offadjustmentChanged( GtkAdjustment *adjustment, GtkWidget *vb)
657     if (blocked)
658         return;
660     blocked = TRUE;
662     GtkOptionMenu *mnu = (GtkOptionMenu *)g_object_get_data (G_OBJECT(vb), "stopmenu");
663     if (!g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop")) return;
664     SPStop *stop = SP_STOP(g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop"));
666     stop->offset = adjustment->value;
667     sp_repr_set_css_double(SP_OBJECT_REPR(stop), "offset", stop->offset);
669     sp_document_done (SP_OBJECT_DOCUMENT (stop), SP_VERB_CONTEXT_GRADIENT,
670                       _("Change gradient stop offset"));
672     blocked = FALSE;
675 guint32
676 sp_average_color (guint32 c1, guint32 c2, gdouble p = 0.5)
678     guint32 r = (guint32) (SP_RGBA32_R_U (c1) * p + SP_RGBA32_R_U (c2) * (1 - p));
679     guint32 g = (guint32) (SP_RGBA32_G_U (c1) * p + SP_RGBA32_G_U (c2) * (1 - p));
680     guint32 b = (guint32) (SP_RGBA32_B_U (c1) * p + SP_RGBA32_B_U (c2) * (1 - p));
681     guint32 a = (guint32) (SP_RGBA32_A_U (c1) * p + SP_RGBA32_A_U (c2) * (1 - p));
683     return SP_RGBA32_U_COMPOSE (r, g, b, a);
687 static void
688 sp_grd_ed_add_stop (GtkWidget */*widget*/,  GtkWidget *vb)
690     SPGradient *gradient = (SPGradient *) g_object_get_data (G_OBJECT(vb), "gradient");
691     verify_grad (gradient);
692     GtkOptionMenu *mnu = (GtkOptionMenu *)g_object_get_data (G_OBJECT(vb), "stopmenu");
694     SPStop *stop = (SPStop *) g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop");
696     if (stop == NULL)
697         return;
699     Inkscape::XML::Node *new_stop_repr = NULL;
701     SPStop *next = sp_next_stop (stop);
703     if (next == NULL) {
704         SPStop *prev = sp_prev_stop (stop, gradient);
705         if (prev != NULL) {
706             next = stop;
707             stop = prev;
708         }
709     }
711     if (next != NULL) {
712         new_stop_repr = SP_OBJECT_REPR(stop)->duplicate(SP_OBJECT_REPR(gradient)->document());
713         SP_OBJECT_REPR(gradient)->addChild(new_stop_repr, SP_OBJECT_REPR(stop));
714     } else {
715         next = stop;
716         new_stop_repr = SP_OBJECT_REPR(sp_prev_stop(stop, gradient))->duplicate(SP_OBJECT_REPR(gradient)->document());
717         SP_OBJECT_REPR(gradient)->addChild(new_stop_repr, SP_OBJECT_REPR(sp_prev_stop(stop, gradient)));
718     }
720     SPStop *newstop = (SPStop *) SP_OBJECT_DOCUMENT(gradient)->getObjectByRepr(new_stop_repr);
722     newstop->offset = (stop->offset + next->offset) * 0.5 ;
724     guint32 const c1 = sp_stop_get_rgba32(stop);
725     guint32 const c2 = sp_stop_get_rgba32(next);
726     guint32 cnew = sp_average_color (c1, c2);
728     Inkscape::CSSOStringStream os;
729     gchar c[64];
730     sp_svg_write_color (c, sizeof(c), cnew);
731     gdouble opacity = (gdouble) SP_RGBA32_A_F (cnew);
732     os << "stop-color:" << c << ";stop-opacity:" << opacity <<";";
733     SP_OBJECT_REPR (newstop)->setAttribute("style", os.str().c_str());
734     sp_repr_set_css_double( SP_OBJECT_REPR(newstop), "offset", (double)newstop->offset);
736     sp_gradient_vector_widget_load_gradient (vb, gradient);
737     Inkscape::GC::release(new_stop_repr);
738     update_stop_list(GTK_WIDGET(mnu), gradient, newstop);
739     GtkWidget *offspin = GTK_WIDGET (g_object_get_data (G_OBJECT (vb), "offspn"));
740     GtkWidget *offslide =GTK_WIDGET (g_object_get_data (G_OBJECT (vb), "offslide"));
741     gtk_widget_set_sensitive (offslide, TRUE);
742     gtk_widget_set_sensitive (GTK_WIDGET (offspin), TRUE);
743     sp_document_done (SP_OBJECT_DOCUMENT (gradient), SP_VERB_CONTEXT_GRADIENT,
744                       _("Add gradient stop"));
747 static void
748 sp_grd_ed_del_stop (GtkWidget */*widget*/,  GtkWidget *vb)
750     SPGradient *gradient = (SPGradient *)g_object_get_data (G_OBJECT(vb), "gradient");
752     GtkOptionMenu *mnu = (GtkOptionMenu *)g_object_get_data (G_OBJECT(vb), "stopmenu");
753     if (!g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop")) return;
754     SPStop *stop = SP_STOP(g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop"));
755     if (gradient->vector.stops.size() > 2) { // 2 is the minimum
757         // if we delete first or last stop, move the next/previous to the edge
758         if (stop->offset == 0) {
759             SPStop *next = sp_next_stop (stop);
760             if (next) {
761                 next->offset = 0;
762                 sp_repr_set_css_double (SP_OBJECT_REPR (next), "offset", 0);
763             }
764         } else if (stop->offset == 1) {
765             SPStop *prev = sp_prev_stop (stop, gradient);
766             if (prev) {
767                 prev->offset = 1;
768                 sp_repr_set_css_double (SP_OBJECT_REPR (prev), "offset", 1);
769             }
770         }
772         SP_OBJECT_REPR(gradient)->removeChild(SP_OBJECT_REPR(stop));
773         sp_gradient_vector_widget_load_gradient (vb, gradient);
774         update_stop_list(GTK_WIDGET(mnu), gradient, NULL);
775         sp_document_done (SP_OBJECT_DOCUMENT (gradient), SP_VERB_CONTEXT_GRADIENT,
776                           _("Delete gradient stop"));
777     }
781 static GtkWidget *
782 sp_gradient_vector_widget_new (SPGradient *gradient, SPStop *select_stop)
784     GtkWidget *vb, *w, *f, *csel;
786     g_return_val_if_fail (!gradient || SP_IS_GRADIENT (gradient), NULL);
788     vb = gtk_vbox_new (FALSE, PAD);
789     g_signal_connect (G_OBJECT (vb), "destroy", G_CALLBACK (sp_gradient_vector_widget_destroy), NULL);
791     w = sp_gradient_image_new (gradient);
792     g_object_set_data (G_OBJECT (vb), "preview", w);
793     gtk_widget_show (w);
794     gtk_box_pack_start (GTK_BOX (vb), w, TRUE, TRUE, PAD);
796     gtk_object_set_data (GTK_OBJECT (vb), "gradient", gradient);
797     sp_repr_add_listener (SP_OBJECT_REPR(gradient), &grad_edit_dia_repr_events, vb);
798     GtkTooltips *tt = gtk_tooltips_new ();
800     /* Stop list */
801     GtkWidget *mnu = gtk_option_menu_new ();
802     /* Create new menu widget */
803     update_stop_list (GTK_WIDGET(mnu), gradient, NULL);
804     gtk_signal_connect (GTK_OBJECT (mnu), "changed", GTK_SIGNAL_FUNC (sp_grad_edit_select), vb);
805     gtk_widget_show (mnu);
806     gtk_object_set_data (GTK_OBJECT (vb), "stopmenu", mnu);
807     gtk_box_pack_start (GTK_BOX (vb), mnu, FALSE, FALSE, 0);
809     /* Add and Remove buttons */
810     GtkWidget *hb = gtk_hbox_new (FALSE, 1);
811     // TRANSLATORS: "Stop" means: a "phase" of a gradient
812     GtkWidget *b = gtk_button_new_with_label (_("Add stop"));
813     gtk_widget_show (b);
814     gtk_container_add (GTK_CONTAINER (hb), b);
815     gtk_tooltips_set_tip (tt, b, _("Add another control stop to gradient"), NULL);
816     gtk_signal_connect (GTK_OBJECT (b), "clicked", GTK_SIGNAL_FUNC (sp_grd_ed_add_stop), vb);
817     b = gtk_button_new_with_label (_("Delete stop"));
818     gtk_widget_show (b);
819     gtk_container_add (GTK_CONTAINER (hb), b);
820     gtk_tooltips_set_tip (tt, b, _("Delete current control stop from gradient"), NULL);
821     gtk_signal_connect (GTK_OBJECT (b), "clicked", GTK_SIGNAL_FUNC (sp_grd_ed_del_stop), vb);
823     gtk_widget_show (hb);
824     gtk_box_pack_start (GTK_BOX (vb),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
827     /*  Offset Slider and stuff   */
828     hb = gtk_hbox_new (FALSE, 0);
830     /* Label */
831     GtkWidget *l = gtk_label_new (_("Offset:"));
832     gtk_misc_set_alignment (GTK_MISC (l), 1.0, 0.5);
833     gtk_box_pack_start (GTK_BOX (hb),l, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
834     gtk_widget_show (l);
836     /* Adjustment */
837     GtkAdjustment *Offset_adj = NULL;
838     Offset_adj= (GtkAdjustment *) gtk_adjustment_new (0.0, 0.0, 1.0, 0.01, 0.01, 0.0);
839     gtk_object_set_data (GTK_OBJECT (vb), "offset", Offset_adj);
840     GtkMenu *m = GTK_MENU(gtk_option_menu_get_menu (GTK_OPTION_MENU(mnu)));
841     SPStop *stop = SP_STOP (g_object_get_data (G_OBJECT (gtk_menu_get_active (m)), "stop"));
842     gtk_adjustment_set_value (Offset_adj, stop->offset);
844     /* Slider */
845     GtkWidget *slider = gtk_hscale_new(Offset_adj);
846     gtk_scale_set_draw_value( GTK_SCALE(slider), FALSE );
847     gtk_widget_show (slider);
848     gtk_box_pack_start (GTK_BOX (hb),slider, TRUE, TRUE, AUX_BETWEEN_BUTTON_GROUPS);
849     gtk_object_set_data (GTK_OBJECT (vb), "offslide", slider);
851     /* Spinbutton */
852     GtkWidget *sbtn = gtk_spin_button_new (GTK_ADJUSTMENT (Offset_adj), 0.01, 2);
853     sp_dialog_defocus_on_enter (sbtn);
854     gtk_widget_show (sbtn);
855     gtk_box_pack_start (GTK_BOX (hb),sbtn, FALSE, TRUE, AUX_BETWEEN_BUTTON_GROUPS);
856     gtk_object_set_data (GTK_OBJECT (vb), "offspn", sbtn);
858     if (stop->offset>0 && stop->offset<1) {
859         gtk_widget_set_sensitive (slider, TRUE);
860         gtk_widget_set_sensitive (GTK_WIDGET (sbtn), TRUE);
861     } else {
862         gtk_widget_set_sensitive (slider, FALSE);
863         gtk_widget_set_sensitive (GTK_WIDGET (sbtn), FALSE);
864     }
867     /* Signals */
868     gtk_signal_connect (GTK_OBJECT (Offset_adj), "value_changed",
869                         GTK_SIGNAL_FUNC (offadjustmentChanged), vb);
871     // gtk_signal_connect (GTK_OBJECT (slider), "changed",  GTK_SIGNAL_FUNC (offsliderChanged), vb);
872     gtk_widget_show (hb);
873     gtk_box_pack_start (GTK_BOX (vb), hb, FALSE, FALSE, PAD);
875     // TRANSLATORS: "Stop" means: a "phase" of a gradient
876     f = gtk_frame_new (_("Stop Color"));
877     gtk_widget_show (f);
878     gtk_box_pack_start (GTK_BOX (vb), f, TRUE, TRUE, PAD);
879     csel = (GtkWidget*)sp_color_selector_new (SP_TYPE_COLOR_NOTEBOOK);
880     g_object_set_data (G_OBJECT (vb), "cselector", csel);
881     gtk_widget_show (csel);
882     gtk_container_add (GTK_CONTAINER (f), csel);
883     g_signal_connect (G_OBJECT (csel), "dragged", G_CALLBACK (sp_gradient_vector_color_dragged), vb);
884     g_signal_connect (G_OBJECT (csel), "changed", G_CALLBACK (sp_gradient_vector_color_changed), vb);
886     gtk_widget_show (vb);
888     sp_gradient_vector_widget_load_gradient (vb, gradient);
890     if (select_stop)
891         select_stop_in_list (GTK_WIDGET(mnu), gradient, select_stop);
893     return vb;
898 GtkWidget *
899 sp_gradient_vector_editor_new (SPGradient *gradient, SPStop *stop)
901     GtkWidget *wid;
903     if (dlg == NULL) {
904         Inkscape::Preferences *prefs = Inkscape::Preferences::get();
906         dlg = sp_window_new (_("Gradient editor"), TRUE);
907         if (x == -1000 || y == -1000) {
908             x = prefs->getInt(prefs_path + "x", -1000);
909             y = prefs->getInt(prefs_path + "y", -1000);
910         }
911         if (w ==0 || h == 0) {
912             w = prefs->getInt(prefs_path + "w", 0);
913             h = prefs->getInt(prefs_path + "h", 0);
914         }
916         if (x<0) x=0;
917         if (y<0) y=0;
919         if (x != 0 || y != 0)
920             gtk_window_move ((GtkWindow *) dlg, x, y);
921         else
922             gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
923         if (w && h) gtk_window_resize ((GtkWindow *) dlg, w, h);
924         sp_transientize (dlg);
925         wd.win = dlg;
926         wd.stop = 0;
927         g_signal_connect (G_OBJECT (INKSCAPE), "activate_desktop", G_CALLBACK (sp_transientize_callback), &wd);
928         gtk_signal_connect (GTK_OBJECT (dlg), "event", GTK_SIGNAL_FUNC (sp_dialog_event_handler), dlg);
929         gtk_signal_connect (GTK_OBJECT (dlg), "destroy", G_CALLBACK (sp_gradient_vector_dialog_destroy), dlg);
930         gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", G_CALLBACK (sp_gradient_vector_dialog_delete), dlg);
931         g_signal_connect (G_OBJECT (INKSCAPE), "shut_down", G_CALLBACK (sp_gradient_vector_dialog_delete), dlg);
932         g_signal_connect ( G_OBJECT (INKSCAPE), "dialogs_hide", G_CALLBACK (sp_dialog_hide), dlg );
933         g_signal_connect ( G_OBJECT (INKSCAPE), "dialogs_unhide", G_CALLBACK (sp_dialog_unhide), dlg );
935         gtk_container_set_border_width (GTK_CONTAINER (dlg), PAD);
937         wid = (GtkWidget*)sp_gradient_vector_widget_new (gradient, stop);
938         g_object_set_data (G_OBJECT (dlg), "gradient-vector-widget", wid);
939         /* Connect signals */
940         gtk_widget_show (wid);
941         gtk_container_add (GTK_CONTAINER (dlg), wid);
942     } else {
943         // FIXME: temp fix for 0.38
944         // Simply load_gradient into the editor does not work for multi-stop gradients,
945         // as the stop list and other widgets are in a wrong state and crash readily.
946         // Instead we just delete the window (by sending the delete signal)
947         // and call sp_gradient_vector_editor_new again, so it creates the window anew.
949         GdkEventAny event;
950         GtkWidget *widget = (GtkWidget *) dlg;
951         event.type = GDK_DELETE;
952         event.window = widget->window;
953         event.send_event = TRUE;
954         g_object_ref (G_OBJECT (event.window));
955         gtk_main_do_event ((GdkEvent*)&event);
956         g_object_unref (G_OBJECT (event.window));
958         g_assert (dlg == NULL);
959         sp_gradient_vector_editor_new (gradient, stop);
960     }
962     return dlg;
965 static void
966 sp_gradient_vector_widget_load_gradient (GtkWidget *widget, SPGradient *gradient)
968     blocked = TRUE;
970     SPGradient *old;
972     old = (SPGradient*)g_object_get_data (G_OBJECT (widget), "gradient");
974     if (old != gradient) {
975         sigc::connection *release_connection;
976         sigc::connection *modified_connection;
978         release_connection = (sigc::connection *)g_object_get_data(G_OBJECT(widget), "gradient_release_connection");
979         modified_connection = (sigc::connection *)g_object_get_data(G_OBJECT(widget), "gradient_modified_connection");
981         if (old) {
982             g_assert( release_connection != NULL );
983             g_assert( modified_connection != NULL );
984             release_connection->disconnect();
985             modified_connection->disconnect();
986             sp_signal_disconnect_by_data (old, widget);
987         }
989         if (gradient) {
990             if (!release_connection) {
991                 release_connection = new sigc::connection();
992             }
993             if (!modified_connection) {
994                 modified_connection = new sigc::connection();
995             }
996             *release_connection = gradient->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gradient_vector_gradient_release), widget));
997             *modified_connection = gradient->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_gradient_vector_gradient_modified), widget));
998         } else {
999             if (release_connection) {
1000                 delete release_connection;
1001                 release_connection = NULL;
1002             }
1003             if (modified_connection) {
1004                 delete modified_connection;
1005                 modified_connection = NULL;
1006             }
1007         }
1009         g_object_set_data(G_OBJECT(widget), "gradient_release_connection", release_connection);
1010         g_object_set_data(G_OBJECT(widget), "gradient_modified_connection", modified_connection);
1011     }
1013     g_object_set_data (G_OBJECT (widget), "gradient", gradient);
1015     if (gradient) {
1016         sp_gradient_ensure_vector (gradient);
1018         GtkOptionMenu *mnu = (GtkOptionMenu *)g_object_get_data (G_OBJECT(widget), "stopmenu");
1019         SPStop *stop = SP_STOP(g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop"));
1020         guint32 const c = sp_stop_get_rgba32(stop);
1022         /// get the color selector
1023         SPColorSelector *csel = SP_COLOR_SELECTOR(g_object_get_data (G_OBJECT (widget), "cselector"));
1024         // set alpha
1025         csel->base->setAlpha(SP_RGBA32_A_F (c));
1026         SPColor color( SP_RGBA32_R_F (c), SP_RGBA32_G_F (c), SP_RGBA32_B_F (c) );
1027         // set color
1028         csel->base->setColor( color );
1029     }
1031     /* Fill preview */
1032     GtkWidget *w = static_cast<GtkWidget *>(g_object_get_data(G_OBJECT(widget), "preview"));
1033     sp_gradient_image_set_gradient (SP_GRADIENT_IMAGE (w), gradient);
1035     GtkWidget *mnu = static_cast<GtkWidget *>(g_object_get_data(G_OBJECT(widget), "stopmenu"));
1036     update_stop_list (GTK_WIDGET(mnu), gradient, NULL);
1038     // Once the user edits a gradient, it stops being auto-collectable
1039     if (SP_OBJECT_REPR(gradient)->attribute("inkscape:collect")) {
1040         SPDocument *document = SP_OBJECT_DOCUMENT (gradient);
1041         bool saved = sp_document_get_undo_sensitive(document);
1042         sp_document_set_undo_sensitive (document, false);
1043         SP_OBJECT_REPR(gradient)->setAttribute("inkscape:collect", NULL);
1044         sp_document_set_undo_sensitive (document, saved);
1045     }
1047     blocked = FALSE;
1050 static void
1051 sp_gradient_vector_dialog_destroy (GtkObject */*object*/, gpointer /*data*/)
1053     sp_signal_disconnect_by_data (INKSCAPE, dlg);
1054     wd.win = dlg = NULL;
1055     wd.stop = 0;
1058 static gboolean
1059 sp_gradient_vector_dialog_delete (GtkWidget */*widget*/, GdkEvent */*event*/, GtkWidget */*dialog*/)
1061     gtk_window_get_position ((GtkWindow *) dlg, &x, &y);
1062     gtk_window_get_size ((GtkWindow *) dlg, &w, &h);
1064     if (x<0) x=0;
1065     if (y<0) y=0;
1067     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1068     prefs->setInt(prefs_path + "x", x);
1069     prefs->setInt(prefs_path + "y", y);
1070     prefs->setInt(prefs_path + "w", w);
1071     prefs->setInt(prefs_path + "h", h);
1073     return FALSE; // which means, go ahead and destroy it
1076 /* Widget destroy handler */
1078 static void
1079 sp_gradient_vector_widget_destroy (GtkObject *object, gpointer /*data*/)
1081     GObject *gradient;
1083     gradient = (GObject*)g_object_get_data (G_OBJECT (object), "gradient");
1085     if (gradient && SP_OBJECT_REPR(gradient)) {
1086         /* Remove signals connected to us */
1087         /* fixme: may use _connect_while_alive as well */
1088         sp_signal_disconnect_by_data (gradient, object);
1089         sp_repr_remove_listener_by_data (SP_OBJECT_REPR(gradient), object);
1090     }
1093 static void
1094 sp_gradient_vector_gradient_release (SPObject */*object*/, GtkWidget *widget)
1096     sp_gradient_vector_widget_load_gradient (widget, NULL);
1099 static void
1100 sp_gradient_vector_gradient_modified (SPObject *object, guint /*flags*/, GtkWidget *widget)
1102     SPGradient *gradient=SP_GRADIENT(object);
1103     if (!blocked) {
1104         blocked = TRUE;
1105         sp_gradient_vector_widget_load_gradient (widget, gradient);
1106         blocked = FALSE;
1107     }
1110 static void sp_gradient_vector_color_dragged(SPColorSelector *csel, GtkObject *object)
1112     SPGradient *gradient, *ngr;
1114     if (blocked) return;
1116     gradient = (SPGradient*)g_object_get_data (G_OBJECT (object), "gradient");
1117     if (!gradient) return;
1119     blocked = TRUE;
1121     ngr = sp_gradient_ensure_vector_normalized (gradient);
1122     if (ngr != gradient) {
1123         /* Our master gradient has changed */
1124         sp_gradient_vector_widget_load_gradient (GTK_WIDGET (object), ngr);
1125     }
1127     sp_gradient_ensure_vector (ngr);
1129     GtkOptionMenu *mnu = (GtkOptionMenu *)g_object_get_data (G_OBJECT(object), "stopmenu");
1130     SPStop *stop = SP_STOP(g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop"));
1133     csel->base->getColorAlpha(stop->specified_color, &stop->opacity);
1134     stop->currentColor = false;
1136     blocked = FALSE;
1139 static void
1140 sp_gradient_vector_color_changed (SPColorSelector *csel, GtkObject *object)
1142     SPColor color;
1143     float alpha;
1144     guint32 rgb;
1146     if (blocked) return;
1148     SPGradient *gradient = (SPGradient*)g_object_get_data (G_OBJECT (object), "gradient");
1149     if (!gradient) return;
1151     blocked = TRUE;
1153     SPGradient *ngr = sp_gradient_ensure_vector_normalized (gradient);
1154     if (ngr != gradient) {
1155         /* Our master gradient has changed */
1156         sp_gradient_vector_widget_load_gradient (GTK_WIDGET (object), ngr);
1157     }
1159     sp_gradient_ensure_vector (ngr);
1161     /* Set start parameters */
1162     /* We rely on normalized vector, i.e. stops HAVE to exist */
1163     g_return_if_fail (sp_first_stop(ngr) != NULL);
1165     GtkOptionMenu *mnu = (GtkOptionMenu *)g_object_get_data (G_OBJECT(object), "stopmenu");
1166     SPStop *stop = SP_STOP(g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop"));
1168     csel = (SPColorSelector*)g_object_get_data (G_OBJECT (object), "cselector");
1169     csel->base->getColorAlpha( color, &alpha );
1170     rgb = color.toRGBA32( 0x00 );
1172     sp_repr_set_css_double (SP_OBJECT_REPR (stop), "offset", stop->offset);
1173     Inkscape::CSSOStringStream os;
1174     gchar c[64];
1175     sp_svg_write_color (c, sizeof(c), rgb);
1176     os << "stop-color:" << c << ";stop-opacity:" << (gdouble) alpha <<";";
1177     SP_OBJECT_REPR (stop)->setAttribute("style", os.str().c_str());
1178     // g_snprintf (c, 256, "stop-color:#%06x;stop-opacity:%g;", rgb >> 8, (gdouble) alpha);
1179     //SP_OBJECT_REPR (stop)->setAttribute("style", c);
1181     sp_document_done (SP_OBJECT_DOCUMENT (ngr), SP_VERB_CONTEXT_GRADIENT,
1182                       _("Change gradient stop color"));
1184     blocked = FALSE;
1186     SPColorPreview *cpv = (SPColorPreview *)g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "preview");
1187     sp_color_preview_set_rgba32(cpv, sp_stop_get_rgba32(stop));
1190 /*
1191   Local Variables:
1192   mode:c++
1193   c-file-style:"stroustrup"
1194   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1195   indent-tabs-mode:nil
1196   fill-column:99
1197   End:
1198 */
1199 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :