Code

A simple layout document as to what, why and how is cppification.
[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  *   Jon A. Cruz <jon@joncruz.org>
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  * Copyright (C) 2006 MenTaLguY
15  * Copyright (C) 2010 Jon A. Cruz
16  *
17  * Released under GNU GPL, read the file 'COPYING' for more information
18  *
19  */
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24 #ifdef HAVE_STRING_H
25 #endif
26 #include <gtk/gtk.h>
27 #include "macros.h"
28 #include <glibmm/i18n.h>
29 #include "../widgets/gradient-image.h"
30 #include "../inkscape.h"
31 #include "../document-private.h"
32 #include "../gradient-chemistry.h"
33 #include "gradient-vector.h"
34 #include "../helper/window.h"
36 #include "xml/repr.h"
38 #include "../dialogs/dialog-events.h"
39 #include "../preferences.h"
40 #include "svg/css-ostringstream.h"
41 #include "sp-stop.h"
43 #include <sigc++/functors/ptr_fun.h>
44 #include <sigc++/adaptors/bind.h>
46 enum {
47     VECTOR_SET,
48     LAST_SIGNAL
49 };
51 static void sp_gradient_vector_selector_class_init(SPGradientVectorSelectorClass *klass);
52 static void sp_gradient_vector_selector_init(SPGradientVectorSelector *gvs);
53 static void sp_gradient_vector_selector_destroy(GtkObject *object);
55 static void sp_gvs_gradient_release(SPObject *obj, SPGradientVectorSelector *gvs);
56 static void sp_gvs_defs_release(SPObject *defs, SPGradientVectorSelector *gvs);
57 static void sp_gvs_defs_modified(SPObject *defs, guint flags, SPGradientVectorSelector *gvs);
59 static void sp_gvs_rebuild_gui_full(SPGradientVectorSelector *gvs);
60 static void sp_gvs_gradient_activate(GtkMenuItem *mi, SPGradientVectorSelector *gvs);
62 static GtkVBoxClass *parent_class;
63 static guint signals[LAST_SIGNAL] = {0};
65 // TODO FIXME kill these globals!!!
66 static GtkWidget *dlg = NULL;
67 static win_data wd;
68 static gint x = -1000, y = -1000, w = 0, h = 0; // impossible original values to make sure they are read from prefs
69 static Glib::ustring const prefs_path = "/dialogs/gradienteditor/";
71 GType sp_gradient_vector_selector_get_type(void)
72 {
73     static GType type = 0;
74     if (!type) {
75         static const GTypeInfo info = {
76             sizeof(SPGradientVectorSelectorClass),
77             NULL, /* base_init */
78             NULL, /* base_finalize */
79             reinterpret_cast<GClassInitFunc>(sp_gradient_vector_selector_class_init),
80             NULL, /* class_finalize */
81             NULL, /* class_data */
82             sizeof(SPGradientVectorSelector),
83             0,    /* n_preallocs */
84             reinterpret_cast<GInstanceInitFunc>(sp_gradient_vector_selector_init),
85             0,    /* value_table */
86         };
88         type = g_type_register_static( GTK_TYPE_VBOX,
89                                        "SPGradientVectorSelector",
90                                        &info,
91                                        static_cast< GTypeFlags >(0) );
92     }
93     return type;
94 }
96 static void sp_gradient_vector_selector_class_init(SPGradientVectorSelectorClass *klass)
97 {
98     GtkObjectClass *object_class;
100     object_class = GTK_OBJECT_CLASS(klass);
102     parent_class = static_cast<GtkVBoxClass*>(gtk_type_class(GTK_TYPE_VBOX));
104     signals[VECTOR_SET] = gtk_signal_new( "vector_set",
105                                           GTK_RUN_LAST,
106                                           GTK_CLASS_TYPE(object_class),
107                                           GTK_SIGNAL_OFFSET(SPGradientVectorSelectorClass, vector_set),
108                                           gtk_marshal_NONE__POINTER,
109                                           GTK_TYPE_NONE, 1,
110                                           GTK_TYPE_POINTER);
112     object_class->destroy = sp_gradient_vector_selector_destroy;
115 static void sp_gradient_vector_selector_init(SPGradientVectorSelector *gvs)
117     gvs->idlabel = TRUE;
119     gvs->swatched = false;
121     gvs->doc = NULL;
122     gvs->gr = NULL;
124     new (&gvs->gradient_release_connection) sigc::connection();
125     new (&gvs->defs_release_connection) sigc::connection();
126     new (&gvs->defs_modified_connection) sigc::connection();
128     gvs->menu = gtk_option_menu_new();
129     gtk_widget_show(gvs->menu);
130     gtk_box_pack_start(GTK_BOX(gvs), gvs->menu, TRUE, TRUE, 0);
133 static void sp_gradient_vector_selector_destroy(GtkObject *object)
135     SPGradientVectorSelector *gvs = SP_GRADIENT_VECTOR_SELECTOR(object);
137     if (gvs->gr) {
138         gvs->gradient_release_connection.disconnect();
139         gvs->gr = NULL;
140     }
142     if (gvs->doc) {
143         gvs->defs_release_connection.disconnect();
144         gvs->defs_modified_connection.disconnect();
145         gvs->doc = NULL;
146     }
148     gvs->gradient_release_connection.~connection();
149     gvs->defs_release_connection.~connection();
150     gvs->defs_modified_connection.~connection();
152     if ((reinterpret_cast<GtkObjectClass *>(parent_class))->destroy) {
153         (* (reinterpret_cast<GtkObjectClass *>(parent_class))->destroy) (object);
154     }
157 GtkWidget *sp_gradient_vector_selector_new(SPDocument *doc, SPGradient *gr)
159     GtkWidget *gvs;
161     g_return_val_if_fail(!gr || SP_IS_GRADIENT(gr), NULL);
162     g_return_val_if_fail(!gr || (SP_OBJECT_DOCUMENT(gr) == doc), NULL);
164     gvs = static_cast<GtkWidget*>(gtk_type_new(SP_TYPE_GRADIENT_VECTOR_SELECTOR));
166     if (doc) {
167         sp_gradient_vector_selector_set_gradient(SP_GRADIENT_VECTOR_SELECTOR(gvs), doc, gr);
168     } else {
169         sp_gvs_rebuild_gui_full(SP_GRADIENT_VECTOR_SELECTOR(gvs));
170     }
172     return gvs;
175 void sp_gradient_vector_selector_set_gradient(SPGradientVectorSelector *gvs, SPDocument *doc, SPGradient *gr)
177     static gboolean suppress = FALSE;
179     g_return_if_fail(gvs != NULL);
180     g_return_if_fail(SP_IS_GRADIENT_VECTOR_SELECTOR(gvs));
181     g_return_if_fail(!gr || (doc != NULL));
182     g_return_if_fail(!gr || SP_IS_GRADIENT(gr));
183     g_return_if_fail(!gr || (SP_OBJECT_DOCUMENT(gr) == doc));
184     g_return_if_fail(!gr || gr->hasStops());
186     if (doc != gvs->doc) {
187         /* Disconnect signals */
188         if (gvs->gr) {
189             gvs->gradient_release_connection.disconnect();
190             gvs->gr = NULL;
191         }
192         if (gvs->doc) {
193             gvs->defs_release_connection.disconnect();
194             gvs->defs_modified_connection.disconnect();
195             gvs->doc = NULL;
196         }
198         // Connect signals
199         if (doc) {
200             gvs->defs_release_connection = SP_DOCUMENT_DEFS(doc)->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gvs_defs_release), gvs));
201             gvs->defs_modified_connection = SP_DOCUMENT_DEFS(doc)->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_gvs_defs_modified), gvs));
202         }
203         if (gr) {
204             gvs->gradient_release_connection = gr->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gvs_gradient_release), gvs));
205         }
206         gvs->doc = doc;
207         gvs->gr = gr;
208         sp_gvs_rebuild_gui_full(gvs);
209         if (!suppress) g_signal_emit(G_OBJECT(gvs), signals[VECTOR_SET], 0, gr);
210     } else if (gr != gvs->gr) {
211         // Harder case - keep document, rebuild menus and stuff
212         // fixme: (Lauris)
213         suppress = TRUE;
214         sp_gradient_vector_selector_set_gradient(gvs, NULL, NULL);
215         sp_gradient_vector_selector_set_gradient(gvs, doc, gr);
216         suppress = FALSE;
217         g_signal_emit(G_OBJECT(gvs), signals[VECTOR_SET], 0, gr);
218     }
219     /* The case of setting NULL -> NULL is not very interesting */
222 SPDocument *sp_gradient_vector_selector_get_document(SPGradientVectorSelector *gvs)
224     g_return_val_if_fail(gvs != NULL, NULL);
225     g_return_val_if_fail(SP_IS_GRADIENT_VECTOR_SELECTOR(gvs), NULL);
227     return gvs->doc;
230 SPGradient *sp_gradient_vector_selector_get_gradient(SPGradientVectorSelector *gvs)
232     g_return_val_if_fail(gvs != NULL, NULL);
233     g_return_val_if_fail(SP_IS_GRADIENT_VECTOR_SELECTOR(gvs), NULL);
235     return gvs->gr;
238 static void sp_gvs_rebuild_gui_full(SPGradientVectorSelector *gvs)
240     /* Clear old menu, if there is any */
241     if (gtk_option_menu_get_menu(GTK_OPTION_MENU(gvs->menu))) {
242         gtk_option_menu_remove_menu(GTK_OPTION_MENU(gvs->menu));
243     }
245     /* Create new menu widget */
246     GtkWidget *m = gtk_menu_new();
247     gtk_widget_show(m);
249     /* Pick up all gradients with vectors */
250     GSList *gl = NULL;
251     if (gvs->gr) {
252         const GSList *gradients = SP_OBJECT_DOCUMENT(gvs->gr)->get_resource_list("gradient");
253         for (const GSList *curr = gradients; curr; curr = curr->next) {
254             SPGradient* grad = SP_GRADIENT(curr->data);
255             if ( grad->hasStops() && (grad->isSwatch() == gvs->swatched) ) {
256                 gl = g_slist_prepend(gl, curr->data);
257             }
258         }
259     }
260     gl = g_slist_reverse(gl);
262     gint pos = 0;
263     gint idx = 0;
265     if (!gvs->doc) {
266         GtkWidget *i;
267         i = gtk_menu_item_new_with_label(_("No document selected"));
268         gtk_widget_show(i);
269         gtk_menu_append(GTK_MENU(m), i);
270         gtk_widget_set_sensitive(gvs->menu, FALSE);
271     } else if (!gl) {
272         GtkWidget *i;
273         i = gtk_menu_item_new_with_label(_("No gradients in document"));
274         gtk_widget_show(i);
275         gtk_menu_append(GTK_MENU(m), i);
276         gtk_widget_set_sensitive(gvs->menu, FALSE);
277     } else if (!gvs->gr) {
278         GtkWidget *i;
279         i = gtk_menu_item_new_with_label(_("No gradient selected"));
280         gtk_widget_show(i);
281         gtk_menu_append(GTK_MENU(m), i);
282         gtk_widget_set_sensitive(gvs->menu, FALSE);
283     } else {
284         while (gl) {
285             SPGradient *gr;
286             GtkWidget *i, *w;
287             gr = SP_GRADIENT(gl->data);
288             gl = g_slist_remove(gl, gr);
290             /* We have to know: */
291             /* Gradient destroy */
292             /* Gradient name change */
293             i = gtk_menu_item_new();
294             gtk_widget_show(i);
295             g_object_set_data(G_OBJECT(i), "gradient", gr);
296             g_signal_connect(G_OBJECT(i), "activate", G_CALLBACK(sp_gvs_gradient_activate), gvs);
298             w = sp_gradient_image_new(gr);
299             gtk_widget_show(w);
301             if (gvs->idlabel) {
302                 GtkWidget *hb, *l;
303                 hb = gtk_hbox_new(FALSE, 4);
304                 gtk_widget_show(hb);
305                 l = gtk_label_new(gr->getId());
306                 gtk_widget_show(l);
307                 gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
308                 gtk_box_pack_start(GTK_BOX(hb), l, TRUE, TRUE, 0);
309                 gtk_box_pack_start(GTK_BOX(hb), w, FALSE, FALSE, 0);
310                 w = hb;
311             }
313             gtk_container_add(GTK_CONTAINER(i), w);
315             gtk_menu_append(GTK_MENU(m), i);
317             if (gr == gvs->gr) {
318                 pos = idx;
319             }
320             idx += 1;
321         }
322         gtk_widget_set_sensitive(gvs->menu, TRUE);
323     }
325     gtk_option_menu_set_menu(GTK_OPTION_MENU(gvs->menu), m);
326     /* Set history */
327     gtk_option_menu_set_history(GTK_OPTION_MENU(gvs->menu), pos);
330 static void sp_gvs_gradient_activate(GtkMenuItem *mi, SPGradientVectorSelector *gvs)
332     SPGradient *gr, *norm;
334     gr = (SPGradient*)g_object_get_data(G_OBJECT(mi), "gradient");
335     /* Hmmm... bad things may happen here, if actual gradient is something new */
336     /* Namely - menuitems etc. will be fucked up */
337     /* Hmmm - probably we can just re-set it as menuitem data (Lauris) */
339     //g_print("SPGradientVectorSelector: gradient %s activated\n", SP_OBJECT_ID(gr));
341     norm = sp_gradient_ensure_vector_normalized(gr);
342     if (norm != gr) {
343         //g_print("SPGradientVectorSelector: become %s after normalization\n", SP_OBJECT_ID(norm));
344         /* But be careful that we do not have gradient saved anywhere else */
345         g_object_set_data(G_OBJECT(mi), "gradient", norm);
346     }
348     /* fixme: Really we would want to use _set_vector */
349     /* Detach old */
350     if (gvs->gr) {
351         gvs->gradient_release_connection.disconnect();
352         gvs->gr = NULL;
353     }
354     /* Attach new */
355     if (norm) {
356         gvs->gradient_release_connection = norm->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gvs_gradient_release), gvs));
357         gvs->gr = norm;
358     }
360     g_signal_emit(G_OBJECT(gvs), signals[VECTOR_SET], 0, norm);
362     if (norm != gr) {
363         /* We do extra undo push here */
364         /* If handler has already done it, it is just NOP */
365         // FIXME: looks like this is never a valid undo step, consider removing this
366         SPDocumentUndo::done(SP_OBJECT_DOCUMENT(norm), SP_VERB_CONTEXT_GRADIENT,
367                           /* TODO: annotate */ "gradient-vector.cpp:350");
368     }
371 static void sp_gvs_gradient_release(SPObject */*obj*/, SPGradientVectorSelector *gvs)
373     /* Disconnect gradient */
374     if (gvs->gr) {
375         gvs->gradient_release_connection.disconnect();
376         gvs->gr = NULL;
377     }
379     /* Rebuild GUI */
380     sp_gvs_rebuild_gui_full(gvs);
383 static void sp_gvs_defs_release(SPObject */*defs*/, SPGradientVectorSelector *gvs)
385     gvs->doc = NULL;
387     gvs->defs_release_connection.disconnect();
388     gvs->defs_modified_connection.disconnect();
390     /* Disconnect gradient as well */
391     if (gvs->gr) {
392         gvs->gradient_release_connection.disconnect();
393         gvs->gr = NULL;
394     }
396     /* Rebuild GUI */
397     sp_gvs_rebuild_gui_full(gvs);
400 static void sp_gvs_defs_modified(SPObject */*defs*/, guint /*flags*/, SPGradientVectorSelector *gvs)
402     /* fixme: We probably have to check some flags here (Lauris) */
404     sp_gvs_rebuild_gui_full(gvs);
407 void SPGradientVectorSelector::setSwatched()
409     swatched = true;
410     sp_gvs_rebuild_gui_full(this);
413 /*##################################################################
414   ###                 Vector Editing Widget
415   ##################################################################*/
417 #include "../widgets/sp-color-notebook.h"
418 #include "../widgets/sp-color-preview.h"
419 #include "../widgets/widget-sizes.h"
420 #include "../xml/node-event-vector.h"
421 #include "../svg/svg-color.h"
424 #define PAD 4
426 static GtkWidget *sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *stop);
428 static void sp_gradient_vector_widget_load_gradient(GtkWidget *widget, SPGradient *gradient);
429 static gint sp_gradient_vector_dialog_delete(GtkWidget *widget, GdkEvent *event, GtkWidget *dialog);
430 static void sp_gradient_vector_dialog_destroy(GtkObject *object, gpointer data);
432 static void sp_gradient_vector_widget_destroy(GtkObject *object, gpointer data);
433 static void sp_gradient_vector_gradient_release(SPObject *obj, GtkWidget *widget);
434 static void sp_gradient_vector_gradient_modified(SPObject *obj, guint flags, GtkWidget *widget);
435 static void sp_gradient_vector_color_dragged(SPColorSelector *csel, GtkObject *object);
436 static void sp_gradient_vector_color_changed(SPColorSelector *csel, GtkObject *object);
437 static void update_stop_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_stop);
439 static gboolean blocked = FALSE;
441 static void grad_edit_dia_stop_added_or_removed(Inkscape::XML::Node */*repr*/, Inkscape::XML::Node */*child*/, Inkscape::XML::Node */*ref*/, gpointer data)
443     GtkWidget *vb = GTK_WIDGET(data);
444     GtkWidget *mnu = (GtkWidget *)g_object_get_data(G_OBJECT(vb), "stopmenu");
445     SPGradient *gradient = (SPGradient *)g_object_get_data(G_OBJECT(vb), "gradient");
446     update_stop_list(mnu, gradient, NULL);
449 //FIXME!!! We must also listen to attr changes on all children (i.e. stops) too,
450 //otherwise the dialog does not reflect undoing color or offset change. This is a major
451 //hassle, unless we have a "one of the descendants changed in some way" signal.
452 static Inkscape::XML::NodeEventVector grad_edit_dia_repr_events =
454     grad_edit_dia_stop_added_or_removed, /* child_added */
455     grad_edit_dia_stop_added_or_removed, /* child_removed */
456     NULL, /* attr_changed*/
457     NULL, /* content_changed */
458     NULL  /* order_changed */
459 };
461 static void verify_grad(SPGradient *gradient)
463     int i = 0;
464     SPStop *stop = NULL;
465     /* count stops */
466     for ( SPObject *ochild = SP_OBJECT(gradient)->first_child() ; 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 select_stop_in_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_stop)
508     int i = 0;
509     for ( SPObject *ochild = SP_OBJECT(gradient)->first_child() ; ochild != NULL ; ochild = SP_OBJECT_NEXT(ochild) ) {
510         if (SP_IS_STOP(ochild)) {
511             if (SP_OBJECT(ochild) == SP_OBJECT(new_stop)) {
512                 gtk_option_menu_set_history(GTK_OPTION_MENU(mnu), i);
513                 break;
514             }
515             i++;
516         }
517     }
520 static void update_stop_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_stop)
523     if (!SP_IS_GRADIENT(gradient)) {
524         return;
525     }
527     blocked = TRUE;
529     /* Clear old menu, if there is any */
530     if (gtk_option_menu_get_menu(GTK_OPTION_MENU(mnu))) {
531         gtk_option_menu_remove_menu(GTK_OPTION_MENU(mnu));
532     }
534     /* Create new menu widget */
535     GtkWidget *m = gtk_menu_new();
536     gtk_widget_show(m);
537     GSList *sl = NULL;
538     if ( gradient->hasStops() ) {
539         for ( SPObject *ochild = SP_OBJECT(gradient)->first_child() ; ochild != NULL ; ochild = SP_OBJECT_NEXT(ochild) ) {
540             if (SP_IS_STOP(ochild)) {
541                 sl = g_slist_append(sl, ochild);
542             }
543         }
544     }
545     if (!sl) {
546         GtkWidget *i = gtk_menu_item_new_with_label(_("No stops in gradient"));
547         gtk_widget_show(i);
548         gtk_menu_append(GTK_MENU(m), i);
549         gtk_widget_set_sensitive(mnu, FALSE);
550     } else {
552         for (; sl != NULL; sl = sl->next){
553             SPStop *stop;
554             GtkWidget *i;
555             if (SP_IS_STOP(sl->data)){
556                 stop = SP_STOP(sl->data);
557                 i = gtk_menu_item_new();
558                 gtk_widget_show(i);
559                 g_object_set_data(G_OBJECT(i), "stop", stop);
560                 GtkWidget *hb = gtk_hbox_new(FALSE, 4);
561                 GtkWidget *cpv = sp_color_preview_new(sp_stop_get_rgba32(stop));
562                 gtk_widget_show(cpv);
563                 gtk_container_add( GTK_CONTAINER(hb), cpv );
564                 g_object_set_data( G_OBJECT(i), "preview", cpv );
565                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) sl->data);
566                 GtkWidget *l = gtk_label_new(repr->attribute("id"));
567                 gtk_widget_show(l);
568                 gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
569                 gtk_box_pack_start(GTK_BOX(hb), l, TRUE, TRUE, 0);
570                 gtk_widget_show(hb);
571                 gtk_container_add(GTK_CONTAINER(i), hb);
572                 gtk_menu_append(GTK_MENU(m), i);
573             }
574         }
576         gtk_widget_set_sensitive(mnu, TRUE);
577     }
578     gtk_option_menu_set_menu(GTK_OPTION_MENU(mnu), m);
580     /* Set history */
581     if (new_stop == NULL) {
582         gtk_option_menu_set_history(GTK_OPTION_MENU(mnu), 0);
583     } else {
584         select_stop_in_list(mnu, gradient, new_stop);
585     }
587     blocked = FALSE;
591 // user selected existing stop from list
592 static void sp_grad_edit_select(GtkOptionMenu *mnu, GtkWidget *tbl)
594     GObject *item = G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu))));
595     SPStop *stop = SP_STOP(g_object_get_data(item, "stop"));
596     if (!stop) {
597         return;
598     }
600     blocked = TRUE;
602     SPColorSelector *csel = (SPColorSelector*)g_object_get_data(G_OBJECT(tbl), "cselector");
603     guint32 const c = sp_stop_get_rgba32(stop);
604     csel->base->setAlpha(SP_RGBA32_A_F(c));
605     SPColor color( SP_RGBA32_R_F(c), SP_RGBA32_G_F(c), SP_RGBA32_B_F(c) );
606     // set its color, from the stored array
607     csel->base->setColor( color );
608     GtkWidget *offspin = GTK_WIDGET(g_object_get_data(G_OBJECT(tbl), "offspn"));
609     GtkWidget *offslide =GTK_WIDGET(g_object_get_data(G_OBJECT(tbl), "offslide"));
611     GtkAdjustment *adj = static_cast<GtkAdjustment*>(gtk_object_get_data(GTK_OBJECT(tbl), "offset"));
613     bool isEndStop = false;
615     SPStop *prev = NULL;
616     prev = stop->getPrevStop();
617     if (prev != NULL )  {
618         adj->lower = prev->offset;
619     } else {
620         isEndStop = true;
621         adj->lower = 0;
622     }
624     SPStop *next = NULL;
625     next = stop->getNextStop();
626     if (next != NULL ) {
627         adj->upper = next->offset;
628     } else {
629         isEndStop = true;
630         adj->upper = 1.0;
631     }
633     //fixme: does this work on all possible input gradients?
634     if (!isEndStop) {
635         gtk_widget_set_sensitive(offslide, TRUE);
636         gtk_widget_set_sensitive(GTK_WIDGET(offspin), TRUE);
637     } else {
638         gtk_widget_set_sensitive(offslide, FALSE);
639         gtk_widget_set_sensitive(GTK_WIDGET(offspin), FALSE);
640     }
642     gtk_adjustment_set_value(adj, stop->offset);
644     gtk_adjustment_changed(adj);
646     blocked = FALSE;
652 static void offadjustmentChanged( GtkAdjustment *adjustment, GtkWidget *vb)
654     if (blocked) {
655         return;
656     }
658     blocked = TRUE;
660     GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(vb), "stopmenu"));
661     if (!g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop")) {
662         return;
663     }
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     SPDocumentUndo::done(SP_OBJECT_DOCUMENT(stop), SP_VERB_CONTEXT_GRADIENT,
670                       _("Change gradient stop offset"));
672     blocked = FALSE;
675 guint32 sp_average_color(guint32 c1, guint32 c2, gdouble p = 0.5)
677     guint32 r = (guint32) (SP_RGBA32_R_U(c1) * p + SP_RGBA32_R_U(c2) * (1 - p));
678     guint32 g = (guint32) (SP_RGBA32_G_U(c1) * p + SP_RGBA32_G_U(c2) * (1 - p));
679     guint32 b = (guint32) (SP_RGBA32_B_U(c1) * p + SP_RGBA32_B_U(c2) * (1 - p));
680     guint32 a = (guint32) (SP_RGBA32_A_U(c1) * p + SP_RGBA32_A_U(c2) * (1 - p));
682     return SP_RGBA32_U_COMPOSE(r, g, b, a);
686 static void sp_grd_ed_add_stop(GtkWidget */*widget*/,  GtkWidget *vb)
688     SPGradient *gradient = static_cast<SPGradient *>(g_object_get_data(G_OBJECT(vb), "gradient"));
689     verify_grad(gradient);
690     GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(vb), "stopmenu"));
692     SPStop *stop = static_cast<SPStop *>(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop"));
694     if (stop == NULL) {
695         return;
696     }
698     Inkscape::XML::Node *new_stop_repr = NULL;
700     SPStop *next = stop->getNextStop();
702     if (next == NULL) {
703         SPStop *prev = stop->getPrevStop();
704         if (prev != NULL) {
705             next = stop;
706             stop = prev;
707         }
708     }
710     if (next != NULL) {
711         new_stop_repr = SP_OBJECT_REPR(stop)->duplicate(SP_OBJECT_REPR(gradient)->document());
712         SP_OBJECT_REPR(gradient)->addChild(new_stop_repr, SP_OBJECT_REPR(stop));
713     } else {
714         next = stop;
715         new_stop_repr = SP_OBJECT_REPR(stop->getPrevStop())->duplicate(SP_OBJECT_REPR(gradient)->document());
716         SP_OBJECT_REPR(gradient)->addChild(new_stop_repr, SP_OBJECT_REPR(stop->getPrevStop()));
717     }
719     SPStop *newstop = (SPStop *) SP_OBJECT_DOCUMENT(gradient)->getObjectByRepr(new_stop_repr);
721     newstop->offset = (stop->offset + next->offset) * 0.5 ;
723     guint32 const c1 = sp_stop_get_rgba32(stop);
724     guint32 const c2 = sp_stop_get_rgba32(next);
725     guint32 cnew = sp_average_color(c1, c2);
727     Inkscape::CSSOStringStream os;
728     gchar c[64];
729     sp_svg_write_color(c, sizeof(c), cnew);
730     gdouble opacity = static_cast<gdouble>(SP_RGBA32_A_F(cnew));
731     os << "stop-color:" << c << ";stop-opacity:" << opacity <<";";
732     SP_OBJECT_REPR (newstop)->setAttribute("style", os.str().c_str());
733     sp_repr_set_css_double( SP_OBJECT_REPR(newstop), "offset", (double)newstop->offset);
735     sp_gradient_vector_widget_load_gradient(vb, gradient);
736     Inkscape::GC::release(new_stop_repr);
737     update_stop_list(GTK_WIDGET(mnu), gradient, newstop);
738     GtkWidget *offspin = GTK_WIDGET(g_object_get_data(G_OBJECT(vb), "offspn"));
739     GtkWidget *offslide =GTK_WIDGET(g_object_get_data(G_OBJECT(vb), "offslide"));
740     gtk_widget_set_sensitive(offslide, TRUE);
741     gtk_widget_set_sensitive(GTK_WIDGET(offspin), TRUE);
742     SPDocumentUndo::done(SP_OBJECT_DOCUMENT(gradient), SP_VERB_CONTEXT_GRADIENT,
743                       _("Add gradient stop"));
746 static void sp_grd_ed_del_stop(GtkWidget */*widget*/,  GtkWidget *vb)
748     SPGradient *gradient = static_cast<SPGradient *>(g_object_get_data(G_OBJECT(vb), "gradient"));
750     GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(vb), "stopmenu"));
751     if (!g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop")) return;
752     SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop"));
753     if (gradient->vector.stops.size() > 2) { // 2 is the minimum
755         // if we delete first or last stop, move the next/previous to the edge
756         if (stop->offset == 0) {
757             SPStop *next = stop->getNextStop();
758             if (next) {
759                 next->offset = 0;
760                 sp_repr_set_css_double(SP_OBJECT_REPR(next), "offset", 0);
761             }
762         } else if (stop->offset == 1) {
763             SPStop *prev = stop->getPrevStop();
764             if (prev) {
765                 prev->offset = 1;
766                 sp_repr_set_css_double(SP_OBJECT_REPR(prev), "offset", 1);
767             }
768         }
770         SP_OBJECT_REPR(gradient)->removeChild(SP_OBJECT_REPR(stop));
771         sp_gradient_vector_widget_load_gradient(vb, gradient);
772         update_stop_list(GTK_WIDGET(mnu), gradient, NULL);
773         SPDocumentUndo::done(SP_OBJECT_DOCUMENT(gradient), SP_VERB_CONTEXT_GRADIENT,
774                           _("Delete gradient stop"));
775     }
779 static GtkWidget * sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *select_stop)
781     GtkWidget *vb, *w, *f, *csel;
783     g_return_val_if_fail(!gradient || SP_IS_GRADIENT(gradient), NULL);
785     vb = gtk_vbox_new(FALSE, PAD);
786     g_signal_connect(G_OBJECT(vb), "destroy", G_CALLBACK(sp_gradient_vector_widget_destroy), NULL);
788     w = sp_gradient_image_new(gradient);
789     g_object_set_data(G_OBJECT(vb), "preview", w);
790     gtk_widget_show(w);
791     gtk_box_pack_start(GTK_BOX(vb), w, TRUE, TRUE, PAD);
793     sp_repr_add_listener(SP_OBJECT_REPR(gradient), &grad_edit_dia_repr_events, vb);
794     GtkTooltips *tt = gtk_tooltips_new();
796     /* Stop list */
797     GtkWidget *mnu = gtk_option_menu_new();
798     /* Create new menu widget */
799     update_stop_list(GTK_WIDGET(mnu), gradient, NULL);
800     gtk_signal_connect(GTK_OBJECT(mnu), "changed", GTK_SIGNAL_FUNC(sp_grad_edit_select), vb);
801     gtk_widget_show(mnu);
802     gtk_object_set_data(GTK_OBJECT(vb), "stopmenu", mnu);
803     gtk_box_pack_start(GTK_BOX(vb), mnu, FALSE, FALSE, 0);
805     /* Add and Remove buttons */
806     GtkWidget *hb = gtk_hbox_new(FALSE, 1);
807     // TRANSLATORS: "Stop" means: a "phase" of a gradient
808     GtkWidget *b = gtk_button_new_with_label(_("Add stop"));
809     gtk_widget_show(b);
810     gtk_container_add(GTK_CONTAINER(hb), b);
811     gtk_tooltips_set_tip(tt, b, _("Add another control stop to gradient"), NULL);
812     gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_grd_ed_add_stop), vb);
813     b = gtk_button_new_with_label(_("Delete stop"));
814     gtk_widget_show(b);
815     gtk_container_add(GTK_CONTAINER(hb), b);
816     gtk_tooltips_set_tip(tt, b, _("Delete current control stop from gradient"), NULL);
817     gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_grd_ed_del_stop), vb);
819     gtk_widget_show(hb);
820     gtk_box_pack_start(GTK_BOX(vb),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
823     /*  Offset Slider and stuff   */
824     hb = gtk_hbox_new(FALSE, 0);
826     /* Label */
827     GtkWidget *l = gtk_label_new(_("Offset:"));
828     gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
829     gtk_box_pack_start(GTK_BOX(hb),l, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
830     gtk_widget_show(l);
832     /* Adjustment */
833     GtkAdjustment *Offset_adj = NULL;
834     Offset_adj= (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 0.01, 0.01, 0.0);
835     gtk_object_set_data(GTK_OBJECT(vb), "offset", Offset_adj);
836     GtkMenu *m = GTK_MENU(gtk_option_menu_get_menu(GTK_OPTION_MENU(mnu)));
837     SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(m)), "stop"));
838     gtk_adjustment_set_value(Offset_adj, stop->offset);
840     /* Slider */
841     GtkWidget *slider = gtk_hscale_new(Offset_adj);
842     gtk_scale_set_draw_value( GTK_SCALE(slider), FALSE );
843     gtk_widget_show(slider);
844     gtk_box_pack_start(GTK_BOX(hb),slider, TRUE, TRUE, AUX_BETWEEN_BUTTON_GROUPS);
845     gtk_object_set_data(GTK_OBJECT(vb), "offslide", slider);
847     /* Spinbutton */
848     GtkWidget *sbtn = gtk_spin_button_new(GTK_ADJUSTMENT(Offset_adj), 0.01, 2);
849     sp_dialog_defocus_on_enter(sbtn);
850     gtk_widget_show(sbtn);
851     gtk_box_pack_start(GTK_BOX(hb),sbtn, FALSE, TRUE, AUX_BETWEEN_BUTTON_GROUPS);
852     gtk_object_set_data(GTK_OBJECT(vb), "offspn", sbtn);
854     if (stop->offset>0 && stop->offset<1) {
855         gtk_widget_set_sensitive(slider, TRUE);
856         gtk_widget_set_sensitive(GTK_WIDGET(sbtn), TRUE);
857     } else {
858         gtk_widget_set_sensitive(slider, FALSE);
859         gtk_widget_set_sensitive(GTK_WIDGET(sbtn), FALSE);
860     }
863     /* Signals */
864     gtk_signal_connect(GTK_OBJECT(Offset_adj), "value_changed",
865                         GTK_SIGNAL_FUNC(offadjustmentChanged), vb);
867     // gtk_signal_connect(GTK_OBJECT(slider), "changed",  GTK_SIGNAL_FUNC(offsliderChanged), vb);
868     gtk_widget_show(hb);
869     gtk_box_pack_start(GTK_BOX(vb), hb, FALSE, FALSE, PAD);
871     // TRANSLATORS: "Stop" means: a "phase" of a gradient
872     f = gtk_frame_new(_("Stop Color"));
873     gtk_widget_show(f);
874     gtk_box_pack_start(GTK_BOX(vb), f, TRUE, TRUE, PAD);
875     csel = static_cast<GtkWidget*>(sp_color_selector_new(SP_TYPE_COLOR_NOTEBOOK));
876     g_object_set_data(G_OBJECT(vb), "cselector", csel);
877     gtk_widget_show(csel);
878     gtk_container_add(GTK_CONTAINER(f), csel);
879     g_signal_connect(G_OBJECT(csel), "dragged", G_CALLBACK(sp_gradient_vector_color_dragged), vb);
880     g_signal_connect(G_OBJECT(csel), "changed", G_CALLBACK(sp_gradient_vector_color_changed), vb);
882     gtk_widget_show(vb);
884     sp_gradient_vector_widget_load_gradient(vb, gradient);
886     if (select_stop) {
887         select_stop_in_list(GTK_WIDGET(mnu), gradient, select_stop);
888     }
890     return vb;
895 GtkWidget * sp_gradient_vector_editor_new(SPGradient *gradient, SPStop *stop)
897     GtkWidget *wid;
899     if (dlg == NULL) {
900         Inkscape::Preferences *prefs = Inkscape::Preferences::get();
902         dlg = sp_window_new(_("Gradient editor"), TRUE);
903         if (x == -1000 || y == -1000) {
904             x = prefs->getInt(prefs_path + "x", -1000);
905             y = prefs->getInt(prefs_path + "y", -1000);
906         }
907         if (w ==0 || h == 0) {
908             w = prefs->getInt(prefs_path + "w", 0);
909             h = prefs->getInt(prefs_path + "h", 0);
910         }
912         if (x<0) {
913             x=0;
914         }
915         if (y<0) {
916             y=0;
917         }
919         if (x != 0 || y != 0) {
920             gtk_window_move(reinterpret_cast<GtkWindow *>(dlg), x, y);
921         } else {
922             gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
923         }
924         if (w && h) {
925             gtk_window_resize(reinterpret_cast<GtkWindow *>(dlg), w, h);
926         }
927         sp_transientize(dlg);
928         wd.win = dlg;
929         wd.stop = 0;
930         g_signal_connect(G_OBJECT(INKSCAPE), "activate_desktop", G_CALLBACK(sp_transientize_callback), &wd);
931         gtk_signal_connect(GTK_OBJECT(dlg), "event", GTK_SIGNAL_FUNC(sp_dialog_event_handler), dlg);
932         gtk_signal_connect(GTK_OBJECT(dlg), "destroy", G_CALLBACK(sp_gradient_vector_dialog_destroy), dlg);
933         gtk_signal_connect(GTK_OBJECT(dlg), "delete_event", G_CALLBACK(sp_gradient_vector_dialog_delete), dlg);
934         g_signal_connect(G_OBJECT(INKSCAPE), "shut_down", G_CALLBACK(sp_gradient_vector_dialog_delete), dlg);
935         g_signal_connect( G_OBJECT(INKSCAPE), "dialogs_hide", G_CALLBACK(sp_dialog_hide), dlg );
936         g_signal_connect( G_OBJECT(INKSCAPE), "dialogs_unhide", G_CALLBACK(sp_dialog_unhide), dlg );
938         gtk_container_set_border_width(GTK_CONTAINER(dlg), PAD);
940         wid = static_cast<GtkWidget*>(sp_gradient_vector_widget_new(gradient, stop));
941         g_object_set_data(G_OBJECT(dlg), "gradient-vector-widget", wid);
942         /* Connect signals */
943         gtk_widget_show(wid);
944         gtk_container_add(GTK_CONTAINER(dlg), wid);
945     } else {
946         // FIXME: temp fix for 0.38
947         // Simply load_gradient into the editor does not work for multi-stop gradients,
948         // as the stop list and other widgets are in a wrong state and crash readily.
949         // Instead we just delete the window (by sending the delete signal)
950         // and call sp_gradient_vector_editor_new again, so it creates the window anew.
952         GdkEventAny event;
953         GtkWidget *widget = static_cast<GtkWidget *>(dlg);
954         event.type = GDK_DELETE;
955         event.window = widget->window;
956         event.send_event = TRUE;
957         g_object_ref(G_OBJECT(event.window));
958         gtk_main_do_event(reinterpret_cast<GdkEvent*>(&event));
959         g_object_unref(G_OBJECT(event.window));
961         g_assert(dlg == NULL);
962         sp_gradient_vector_editor_new(gradient, stop);
963     }
965     return dlg;
968 static void sp_gradient_vector_widget_load_gradient(GtkWidget *widget, SPGradient *gradient)
970     blocked = TRUE;
972     SPGradient *old;
974     old = (SPGradient*)g_object_get_data(G_OBJECT(widget), "gradient");
976     if (old != gradient) {
977         sigc::connection *release_connection;
978         sigc::connection *modified_connection;
980         release_connection = (sigc::connection *)g_object_get_data(G_OBJECT(widget), "gradient_release_connection");
981         modified_connection = (sigc::connection *)g_object_get_data(G_OBJECT(widget), "gradient_modified_connection");
983         if (old) {
984             g_assert( release_connection != NULL );
985             g_assert( modified_connection != NULL );
986             release_connection->disconnect();
987             modified_connection->disconnect();
988             sp_signal_disconnect_by_data(old, widget);
989         }
991         if (gradient) {
992             if (!release_connection) {
993                 release_connection = new sigc::connection();
994             }
995             if (!modified_connection) {
996                 modified_connection = new sigc::connection();
997             }
998             *release_connection = gradient->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gradient_vector_gradient_release), widget));
999             *modified_connection = gradient->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_gradient_vector_gradient_modified), widget));
1000         } else {
1001             if (release_connection) {
1002                 delete release_connection;
1003                 release_connection = NULL;
1004             }
1005             if (modified_connection) {
1006                 delete modified_connection;
1007                 modified_connection = NULL;
1008             }
1009         }
1011         g_object_set_data(G_OBJECT(widget), "gradient_release_connection", release_connection);
1012         g_object_set_data(G_OBJECT(widget), "gradient_modified_connection", modified_connection);
1013     }
1015     g_object_set_data(G_OBJECT(widget), "gradient", gradient);
1017     if (gradient) {
1018         gtk_widget_set_sensitive(widget, TRUE);
1020         gradient->ensureVector();
1022         GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(widget), "stopmenu"));
1023         SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop"));
1024         guint32 const c = sp_stop_get_rgba32(stop);
1026         /// get the color selector
1027         SPColorSelector *csel = SP_COLOR_SELECTOR(g_object_get_data(G_OBJECT(widget), "cselector"));
1028         // set alpha
1029         csel->base->setAlpha(SP_RGBA32_A_F(c));
1030         SPColor color( SP_RGBA32_R_F(c), SP_RGBA32_G_F(c), SP_RGBA32_B_F(c) );
1031         // set color
1032         csel->base->setColor( color );
1034         /* Fill preview */
1035         GtkWidget *w = static_cast<GtkWidget *>(g_object_get_data(G_OBJECT(widget), "preview"));
1036         sp_gradient_image_set_gradient(SP_GRADIENT_IMAGE(w), gradient);
1038         update_stop_list(GTK_WIDGET(mnu), gradient, NULL);
1040         // Once the user edits a gradient, it stops being auto-collectable
1041         if (SP_OBJECT_REPR(gradient)->attribute("inkscape:collect")) {
1042             SPDocument *document = SP_OBJECT_DOCUMENT(gradient);
1043             bool saved = SPDocumentUndo::get_undo_sensitive(document);
1044                         SPDocumentUndo::set_undo_sensitive(document, false);
1045             SP_OBJECT_REPR(gradient)->setAttribute("inkscape:collect", NULL);
1046                         SPDocumentUndo::set_undo_sensitive(document, saved);
1047         }
1048     } else { // no gradient, disable everything
1049         gtk_widget_set_sensitive(widget, FALSE);
1050     }
1052     blocked = FALSE;
1055 static void sp_gradient_vector_dialog_destroy(GtkObject */*object*/, gpointer /*data*/)
1057     sp_signal_disconnect_by_data(INKSCAPE, dlg);
1058     wd.win = dlg = NULL;
1059     wd.stop = 0;
1062 static gboolean sp_gradient_vector_dialog_delete(GtkWidget */*widget*/, GdkEvent */*event*/, GtkWidget */*dialog*/)
1064     gtk_window_get_position(GTK_WINDOW(dlg), &x, &y);
1065     gtk_window_get_size(GTK_WINDOW(dlg), &w, &h);
1067     if (x<0) {
1068         x=0;
1069     }
1070     if (y<0) {
1071         y=0;
1072     }
1074     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1075     prefs->setInt(prefs_path + "x", x);
1076     prefs->setInt(prefs_path + "y", y);
1077     prefs->setInt(prefs_path + "w", w);
1078     prefs->setInt(prefs_path + "h", h);
1080     return FALSE; // which means, go ahead and destroy it
1083 /* Widget destroy handler */
1085 static void sp_gradient_vector_widget_destroy(GtkObject *object, gpointer /*data*/)
1087     GObject *gradient;
1089     gradient = (GObject*)g_object_get_data(G_OBJECT(object), "gradient");
1091     sigc::connection *release_connection = (sigc::connection *)g_object_get_data(G_OBJECT(object), "gradient_release_connection");
1092     sigc::connection *modified_connection = (sigc::connection *)g_object_get_data(G_OBJECT(object), "gradient_modified_connection");
1094     if (gradient) {
1095         g_assert( release_connection != NULL );
1096         g_assert( modified_connection != NULL );
1097         release_connection->disconnect();
1098         modified_connection->disconnect();
1099         sp_signal_disconnect_by_data(gradient, object);
1100     }
1102     if (gradient && SP_OBJECT_REPR(gradient)) {
1103         sp_repr_remove_listener_by_data(SP_OBJECT_REPR(gradient), object);
1104     }
1107 static void sp_gradient_vector_gradient_release(SPObject */*object*/, GtkWidget *widget)
1109     sp_gradient_vector_widget_load_gradient(widget, NULL);
1112 static void sp_gradient_vector_gradient_modified(SPObject *object, guint /*flags*/, GtkWidget *widget)
1114     SPGradient *gradient=SP_GRADIENT(object);
1115     if (!blocked) {
1116         blocked = TRUE;
1117         sp_gradient_vector_widget_load_gradient(widget, gradient);
1118         blocked = FALSE;
1119     }
1122 static void sp_gradient_vector_color_dragged(SPColorSelector *csel, GtkObject *object)
1124     SPGradient *gradient, *ngr;
1126     if (blocked) {
1127         return;
1128     }
1130     gradient = static_cast<SPGradient*>(g_object_get_data(G_OBJECT(object), "gradient"));
1131     if (!gradient) {
1132         return;
1133     }
1135     blocked = TRUE;
1137     ngr = sp_gradient_ensure_vector_normalized(gradient);
1138     if (ngr != gradient) {
1139         /* Our master gradient has changed */
1140         sp_gradient_vector_widget_load_gradient(GTK_WIDGET(object), ngr);
1141     }
1143     ngr->ensureVector();
1145     GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(object), "stopmenu"));
1146     SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop"));
1149     csel->base->getColorAlpha(stop->specified_color, stop->opacity);
1150     stop->currentColor = false;
1152     blocked = FALSE;
1155 static void sp_gradient_vector_color_changed(SPColorSelector *csel, GtkObject *object)
1157     SPColor color;
1158     float alpha;
1159     guint32 rgb;
1161     if (blocked) {
1162         return;
1163     }
1165     SPGradient *gradient = static_cast<SPGradient*>(g_object_get_data(G_OBJECT(object), "gradient"));
1166     if (!gradient) {
1167         return;
1168     }
1170     blocked = TRUE;
1172     SPGradient *ngr = sp_gradient_ensure_vector_normalized(gradient);
1173     if (ngr != gradient) {
1174         /* Our master gradient has changed */
1175         sp_gradient_vector_widget_load_gradient(GTK_WIDGET(object), ngr);
1176     }
1178     ngr->ensureVector();
1180     /* Set start parameters */
1181     /* We rely on normalized vector, i.e. stops HAVE to exist */
1182     g_return_if_fail(ngr->getFirstStop() != NULL);
1184     GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(object), "stopmenu"));
1185     SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop"));
1187     csel = static_cast<SPColorSelector*>(g_object_get_data(G_OBJECT(object), "cselector"));
1188     csel->base->getColorAlpha( color, alpha );
1189     rgb = color.toRGBA32( 0x00 );
1191     sp_repr_set_css_double(SP_OBJECT_REPR(stop), "offset", stop->offset);
1192     Inkscape::CSSOStringStream os;
1193     gchar c[64];
1194     sp_svg_write_color(c, sizeof(c), rgb);
1195     os << "stop-color:" << c << ";stop-opacity:" << static_cast<gdouble>(alpha) <<";";
1196     SP_OBJECT_REPR(stop)->setAttribute("style", os.str().c_str());
1197     // g_snprintf(c, 256, "stop-color:#%06x;stop-opacity:%g;", rgb >> 8, static_cast<gdouble>(alpha));
1198     //SP_OBJECT_REPR(stop)->setAttribute("style", c);
1200     SPDocumentUndo::done(SP_OBJECT_DOCUMENT(ngr), SP_VERB_CONTEXT_GRADIENT,
1201                       _("Change gradient stop color"));
1203     blocked = FALSE;
1205     SPColorPreview *cpv = static_cast<SPColorPreview *>(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "preview"));
1206     sp_color_preview_set_rgba32(cpv, sp_stop_get_rgba32(stop));
1209 /*
1210   Local Variables:
1211   mode:c++
1212   c-file-style:"stroustrup"
1213   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1214   indent-tabs-mode:nil
1215   fill-column:99
1216   End:
1217 */
1218 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :