Code

From trunk
[inkscape.git] / src / widgets / gradient-vector.cpp
1 #define __SP_GRADIENT_VECTOR_C__
3 /*
4  * Gradient vector selection widget
5  *
6  * Authors:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *   bulia byak <buliabyak@users.sf.net>
9  *   MenTaLguY <mental@rydia.net>
10  *
11  * Copyright (C) 2001-2002 Lauris Kaplinski
12  * Copyright (C) 2001 Ximian, Inc.
13  * Copyright (C) 2004 Monash University
14  * Copyright (C) 2004 David Turner
15  * Copyright (C) 2006 MenTaLguY
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 static GtkWidget *dlg = NULL;
66 static win_data wd;
67 static gint x = -1000, y = -1000, w = 0, h = 0; // impossible original values to make sure they are read from prefs
68 static Glib::ustring const prefs_path = "/dialogs/gradienteditor/";
70 GtkType
71 sp_gradient_vector_selector_get_type (void)
72 {
73         static GtkType type = 0;
74         if (!type) {
75                 GtkTypeInfo info = {
76                         "SPGradientVectorSelector",
77                         sizeof (SPGradientVectorSelector),
78                         sizeof (SPGradientVectorSelectorClass),
79                         (GtkClassInitFunc) sp_gradient_vector_selector_class_init,
80                         (GtkObjectInitFunc) sp_gradient_vector_selector_init,
81                         NULL, NULL, NULL
82                 };
83                 type = gtk_type_unique (GTK_TYPE_VBOX, &info);
84         }
85         return type;
86 }
88 static void
89 sp_gradient_vector_selector_class_init (SPGradientVectorSelectorClass *klass)
90 {
91         GtkObjectClass *object_class;
93         object_class = GTK_OBJECT_CLASS (klass);
95         parent_class = (GtkVBoxClass*)gtk_type_class (GTK_TYPE_VBOX);
97         signals[VECTOR_SET] = gtk_signal_new ("vector_set",
98                                               GTK_RUN_LAST,
99                                               GTK_CLASS_TYPE(object_class),
100                                               GTK_SIGNAL_OFFSET (SPGradientVectorSelectorClass, vector_set),
101                                               gtk_marshal_NONE__POINTER,
102                                               GTK_TYPE_NONE, 1,
103                                               GTK_TYPE_POINTER);
105         object_class->destroy = sp_gradient_vector_selector_destroy;
108 static void
109 sp_gradient_vector_selector_init (SPGradientVectorSelector *gvs)
111         gvs->idlabel = TRUE;
113         gvs->doc = NULL;
114         gvs->gr = NULL;
116         new (&gvs->gradient_release_connection) sigc::connection();
117         new (&gvs->defs_release_connection) sigc::connection();
118         new (&gvs->defs_modified_connection) sigc::connection();
120         gvs->menu = gtk_option_menu_new ();
121         gtk_widget_show (gvs->menu);
122         gtk_box_pack_start (GTK_BOX (gvs), gvs->menu, TRUE, TRUE, 0);
125 static void
126 sp_gradient_vector_selector_destroy (GtkObject *object)
128         SPGradientVectorSelector *gvs;
130         gvs = SP_GRADIENT_VECTOR_SELECTOR (object);
132         if (gvs->gr) {
133                 gvs->gradient_release_connection.disconnect();
134                 gvs->gr = NULL;
135         }
137         if (gvs->doc) {
138                 gvs->defs_release_connection.disconnect();
139                 gvs->defs_modified_connection.disconnect();
140                 gvs->doc = NULL;
141         }
143         gvs->gradient_release_connection.~connection();
144         gvs->defs_release_connection.~connection();
145         gvs->defs_modified_connection.~connection();
147         if (((GtkObjectClass *) (parent_class))->destroy)
148                 (* ((GtkObjectClass *) (parent_class))->destroy) (object);
151 GtkWidget *
152 sp_gradient_vector_selector_new (SPDocument *doc, SPGradient *gr)
154         GtkWidget *gvs;
156         g_return_val_if_fail (!gr || SP_IS_GRADIENT (gr), NULL);
157         g_return_val_if_fail (!gr || (SP_OBJECT_DOCUMENT (gr) == doc), NULL);
159         gvs = (GtkWidget*)gtk_type_new (SP_TYPE_GRADIENT_VECTOR_SELECTOR);
161         if (doc) {
162                 sp_gradient_vector_selector_set_gradient (SP_GRADIENT_VECTOR_SELECTOR (gvs), doc, gr);
163         } else {
164                 sp_gvs_rebuild_gui_full (SP_GRADIENT_VECTOR_SELECTOR (gvs));
165         }
167         return gvs;
170 void
171 sp_gradient_vector_selector_set_gradient (SPGradientVectorSelector *gvs, SPDocument *doc, SPGradient *gr)
173         static gboolean suppress = FALSE;
175         g_return_if_fail (gvs != NULL);
176         g_return_if_fail (SP_IS_GRADIENT_VECTOR_SELECTOR (gvs));
177         g_return_if_fail (!gr || (doc != NULL));
178         g_return_if_fail (!gr || SP_IS_GRADIENT (gr));
179         g_return_if_fail (!gr || (SP_OBJECT_DOCUMENT (gr) == doc));
180         g_return_if_fail (!gr || SP_GRADIENT_HAS_STOPS (gr));
182         if (doc != gvs->doc) {
183                 /* Disconnect signals */
184                 if (gvs->gr) {
185                         gvs->gradient_release_connection.disconnect();
186                         gvs->gr = NULL;
187                 }
188                 if (gvs->doc) {
189                         gvs->defs_release_connection.disconnect();
190                         gvs->defs_modified_connection.disconnect();
191                         gvs->doc = NULL;
192                 }
193                 /* Connect signals */
194                 if (doc) {
195                         gvs->defs_release_connection = SP_DOCUMENT_DEFS(doc)->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gvs_defs_release), gvs));
196                         gvs->defs_modified_connection = SP_DOCUMENT_DEFS(doc)->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_gvs_defs_modified), gvs));
197                 }
198                 if (gr) {
199                         gvs->gradient_release_connection = gr->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gvs_gradient_release), gvs));
200                 }
201                 gvs->doc = doc;
202                 gvs->gr = gr;
203                 sp_gvs_rebuild_gui_full (gvs);
204                 if (!suppress) g_signal_emit (G_OBJECT (gvs), signals[VECTOR_SET], 0, gr);
205         } else if (gr != gvs->gr) {
206                 /* Harder case - keep document, rebuild menus and stuff */
207                 /* fixme: (Lauris) */
208                 suppress = TRUE;
209                 sp_gradient_vector_selector_set_gradient (gvs, NULL, NULL);
210                 sp_gradient_vector_selector_set_gradient (gvs, doc, gr);
211                 suppress = FALSE;
212                 g_signal_emit (G_OBJECT (gvs), signals[VECTOR_SET], 0, gr);
213         }
214         /* The case of setting NULL -> NULL is not very interesting */
217 SPDocument *
218 sp_gradient_vector_selector_get_document (SPGradientVectorSelector *gvs)
220         g_return_val_if_fail (gvs != NULL, NULL);
221         g_return_val_if_fail (SP_IS_GRADIENT_VECTOR_SELECTOR (gvs), NULL);
223         return gvs->doc;
226 SPGradient *
227 sp_gradient_vector_selector_get_gradient (SPGradientVectorSelector *gvs)
229         g_return_val_if_fail (gvs != NULL, NULL);
230         g_return_val_if_fail (SP_IS_GRADIENT_VECTOR_SELECTOR (gvs), NULL);
232         return gvs->gr;
235 static void
236 sp_gvs_rebuild_gui_full (SPGradientVectorSelector *gvs)
238         /* Clear old menu, if there is any */
239         if (gtk_option_menu_get_menu (GTK_OPTION_MENU (gvs->menu))) {
240                 gtk_option_menu_remove_menu (GTK_OPTION_MENU (gvs->menu));
241         }
243         /* Create new menu widget */
244         GtkWidget *m = gtk_menu_new ();
245         gtk_widget_show (m);
247         /* Pick up all gradients with vectors */
248         GSList *gl = NULL;
249         if (gvs->gr) {
250                 const GSList *gradients = sp_document_get_resource_list (SP_OBJECT_DOCUMENT (gvs->gr), "gradient");
251                 for (const GSList *l = gradients; l != NULL; l = l->next) {
252                         if (SP_GRADIENT_HAS_STOPS (l->data)) {
253                                 gl = g_slist_prepend (gl, l->data);
254                         }
255                 }
256         }
257         gl = g_slist_reverse (gl);
259         gint pos = 0;
260         gint idx = 0;
262         if (!gvs->doc) {
263                 GtkWidget *i;
264                 i = gtk_menu_item_new_with_label (_("No document selected"));
265                 gtk_widget_show (i);
266                 gtk_menu_append (GTK_MENU (m), i);
267                 gtk_widget_set_sensitive (gvs->menu, FALSE);
268         } else if (!gl) {
269                 GtkWidget *i;
270                 i = gtk_menu_item_new_with_label (_("No gradients in document"));
271                 gtk_widget_show (i);
272                 gtk_menu_append (GTK_MENU (m), i);
273                 gtk_widget_set_sensitive (gvs->menu, FALSE);
274         } else if (!gvs->gr) {
275                 GtkWidget *i;
276                 i = gtk_menu_item_new_with_label (_("No gradient selected"));
277                 gtk_widget_show (i);
278                 gtk_menu_append (GTK_MENU (m), i);
279                 gtk_widget_set_sensitive (gvs->menu, FALSE);
280         } else {
281                 while (gl) {
282                         SPGradient *gr;
283                         GtkWidget *i, *w;
284                         gr = SP_GRADIENT (gl->data);
285                         gl = g_slist_remove (gl, gr);
287                         /* We have to know: */
288                         /* Gradient destroy */
289                         /* Gradient name change */
290                         i = gtk_menu_item_new ();
291                         gtk_widget_show (i);
292                         g_object_set_data (G_OBJECT (i), "gradient", gr);
293                         g_signal_connect (G_OBJECT (i), "activate", G_CALLBACK (sp_gvs_gradient_activate), gvs);
295                         w = sp_gradient_image_new (gr);
296                         gtk_widget_show (w);
298                         if (gvs->idlabel) {
299                                 GtkWidget *hb, *l;
300                                 hb = gtk_hbox_new (FALSE, 4);
301                                 gtk_widget_show (hb);
302                                 l = gtk_label_new (SP_OBJECT_ID (gr));
303                                 gtk_widget_show (l);
304                                 gtk_misc_set_alignment (GTK_MISC (l), 1.0, 0.5);
305                                 gtk_box_pack_start (GTK_BOX (hb), l, TRUE, TRUE, 0);
306                                 gtk_box_pack_start (GTK_BOX (hb), w, FALSE, FALSE, 0);
307                                 w = hb;
308                         }
310                         gtk_container_add (GTK_CONTAINER (i), w);
312                         gtk_menu_append (GTK_MENU (m), i);
314                         if (gr == gvs->gr) pos = idx;
315                         idx += 1;
316                 }
317                 gtk_widget_set_sensitive (gvs->menu, TRUE);
318         }
320         gtk_option_menu_set_menu (GTK_OPTION_MENU (gvs->menu), m);
321         /* Set history */
322         gtk_option_menu_set_history (GTK_OPTION_MENU (gvs->menu), pos);
325 static void
326 sp_gvs_gradient_activate (GtkMenuItem *mi, SPGradientVectorSelector *gvs)
328         SPGradient *gr, *norm;
330         gr = (SPGradient*)g_object_get_data (G_OBJECT (mi), "gradient");
331         /* Hmmm... bad things may happen here, if actual gradient is something new */
332         /* Namely - menuitems etc. will be fucked up */
333         /* Hmmm - probably we can just re-set it as menuitem data (Lauris) */
335         //g_print ("SPGradientVectorSelector: gradient %s activated\n", SP_OBJECT_ID (gr));
337         norm = sp_gradient_ensure_vector_normalized (gr);
338         if (norm != gr) {
339                 //g_print ("SPGradientVectorSelector: become %s after normalization\n", SP_OBJECT_ID (norm));
340                 /* But be careful that we do not have gradient saved anywhere else */
341                 g_object_set_data (G_OBJECT (mi), "gradient", norm);
342         }
344         /* fixme: Really we would want to use _set_vector */
345         /* Detach old */
346         if (gvs->gr) {
347                 gvs->gradient_release_connection.disconnect();
348                 gvs->gr = NULL;
349         }
350         /* Attach new */
351         if (norm) {
352                 gvs->gradient_release_connection = norm->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gvs_gradient_release), gvs));
353                 gvs->gr = norm;
354         }
356         g_signal_emit (G_OBJECT (gvs), signals[VECTOR_SET], 0, norm);
358         if (norm != gr) {
359                 /* We do extra undo push here */
360                 /* If handler has already done it, it is just NOP */
361                 // FIXME: looks like this is never a valid undo step, consider removing this
362             sp_document_done (SP_OBJECT_DOCUMENT (norm), SP_VERB_CONTEXT_GRADIENT,
363                               /* TODO: annotate */ "gradient-vector.cpp:350");
364         }
367 static void
368 sp_gvs_gradient_release (SPObject *obj, SPGradientVectorSelector *gvs)
370         /* Disconnect gradient */
371         if (gvs->gr) {
372                 gvs->gradient_release_connection.disconnect();
373                 gvs->gr = NULL;
374         }
376         /* Rebuild GUI */
377         sp_gvs_rebuild_gui_full (gvs);
380 static void
381 sp_gvs_defs_release (SPObject *defs, SPGradientVectorSelector *gvs)
383         gvs->doc = NULL;
385         gvs->defs_release_connection.disconnect();
386         gvs->defs_modified_connection.disconnect();
388         /* Disconnect gradient as well */
389         if (gvs->gr) {
390                 gvs->gradient_release_connection.disconnect();
391                 gvs->gr = NULL;
392         }
394         /* Rebuild GUI */
395         sp_gvs_rebuild_gui_full (gvs);
398 static void
399 sp_gvs_defs_modified (SPObject *defs, guint flags, SPGradientVectorSelector *gvs)
401         /* fixme: We probably have to check some flags here (Lauris) */
403         sp_gvs_rebuild_gui_full (gvs);
406 /*##################################################################
407 ###                 Vector Editing Widget
408 ##################################################################*/
410 #include "../widgets/sp-color-notebook.h"
411 #include "../widgets/sp-color-preview.h"
412 #include "../widgets/widget-sizes.h"
413 #include "../xml/node-event-vector.h"
414 #include "../svg/svg-color.h"
417 #define PAD 4
419 static GtkWidget *sp_gradient_vector_widget_new (SPGradient *gradient, SPStop *stop);
421 static void sp_gradient_vector_widget_load_gradient (GtkWidget *widget, SPGradient *gradient);
422 static gint sp_gradient_vector_dialog_delete (GtkWidget *widget, GdkEvent *event, GtkWidget *dialog);
423 static void sp_gradient_vector_dialog_destroy (GtkObject *object, gpointer data);
425 static void sp_gradient_vector_widget_destroy (GtkObject *object, gpointer data);
426 static void sp_gradient_vector_gradient_release (SPObject *obj, GtkWidget *widget);
427 static void sp_gradient_vector_gradient_modified (SPObject *obj, guint flags, GtkWidget *widget);
428 static void sp_gradient_vector_color_dragged (SPColorSelector *csel, GtkObject *object);
429 static void sp_gradient_vector_color_changed (SPColorSelector *csel, GtkObject *object);
430 static void update_stop_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_stop);
432 static gboolean blocked = FALSE;
434 static void grad_edit_dia_stop_added_or_removed (Inkscape::XML::Node *repr, Inkscape::XML::Node *child, Inkscape::XML::Node *ref, gpointer data)
436    GtkWidget *vb = GTK_WIDGET(data);
437    GtkWidget *mnu = (GtkWidget *)g_object_get_data (G_OBJECT(vb), "stopmenu");
438    SPGradient *gradient = (SPGradient *)g_object_get_data (G_OBJECT(vb), "gradient");
439    update_stop_list (mnu, gradient, NULL);
442 //FIXME!!! We must also listen to attr changes on all children (i.e. stops) too,
443 //otherwise the dialog does not reflect undoing color or offset change. This is a major
444 //hassle, unless we have a "one of the descendants changed in some way" signal.
445 static Inkscape::XML::NodeEventVector grad_edit_dia_repr_events =
447     grad_edit_dia_stop_added_or_removed, /* child_added */
448     grad_edit_dia_stop_added_or_removed, /* child_removed */
449     NULL, /* attr_changed*/
450     NULL, /* content_changed */
451     NULL  /* order_changed */
452 };
454 static void
455 verify_grad(SPGradient *gradient)
457         int i = 0;
458         SPStop *stop = NULL;
459         /* count stops */
460         for ( SPObject *ochild = sp_object_first_child(SP_OBJECT(gradient)) ; ochild != NULL ; ochild = SP_OBJECT_NEXT(ochild) ) {
461                 if (SP_IS_STOP (ochild)) {
462                         i++;
463                         stop = SP_STOP(ochild);
464                 }
465         }
467         Inkscape::XML::Document *xml_doc;
468         xml_doc = SP_OBJECT_REPR(gradient)->document();
470         if (i < 1) {
471                 gchar c[64];
472                 sp_svg_write_color (c, sizeof(c), 0x00000000);
474                 Inkscape::CSSOStringStream os;
475                 os << "stop-color:" << c << ";stop-opacity:" << 1.0 << ";";
477                 Inkscape::XML::Node *child;
479                 child = xml_doc->createElement("svg:stop");
480                 sp_repr_set_css_double(child, "offset", 0.0);
481                 child->setAttribute("style", os.str().c_str());
482                 SP_OBJECT_REPR (gradient)->addChild(child, NULL);
483                 Inkscape::GC::release(child);
485                 child = xml_doc->createElement("svg:stop");
486                 sp_repr_set_css_double(child, "offset", 1.0);
487                 child->setAttribute("style", os.str().c_str());
488                 SP_OBJECT_REPR (gradient)->addChild(child, NULL);
489                 Inkscape::GC::release(child);
490         }
491         if (i < 2) {
492                 sp_repr_set_css_double(SP_OBJECT_REPR(stop), "offset", 0.0);
493                 Inkscape::XML::Node *child = SP_OBJECT_REPR(stop)->duplicate(SP_OBJECT_REPR(gradient)->document());
494                 sp_repr_set_css_double(child, "offset", 1.0);
495                 SP_OBJECT_REPR(gradient)->addChild(child, SP_OBJECT_REPR (stop));
496                 Inkscape::GC::release(child);
497         }
500 static void
501 select_stop_in_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_stop)
503         int i = 0;
504         for ( SPObject *ochild = sp_object_first_child(SP_OBJECT(gradient)) ; ochild != NULL ; ochild = SP_OBJECT_NEXT(ochild) ) {
505                 if (SP_IS_STOP (ochild)) {
506                         if (SP_OBJECT (ochild) == SP_OBJECT(new_stop)) {
507                                 gtk_option_menu_set_history (GTK_OPTION_MENU (mnu), i);
508                                 break;
509                         }
510                         i++;
511                 }
512         }
515 static void
516 update_stop_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_stop)
519         if (!SP_IS_GRADIENT (gradient))
520                 return;
522         blocked = TRUE;
524         /* Clear old menu, if there is any */
525         if (gtk_option_menu_get_menu (GTK_OPTION_MENU (mnu))) {
526                 gtk_option_menu_remove_menu (GTK_OPTION_MENU (mnu));
527         }
529         /* Create new menu widget */
530         GtkWidget *m = gtk_menu_new ();
531         gtk_widget_show (m);
532         GSList *sl = NULL;
533         if (gradient->has_stops) {
534                 for ( SPObject *ochild = sp_object_first_child (SP_OBJECT(gradient)) ; ochild != NULL ; ochild = SP_OBJECT_NEXT(ochild) ) {
535                         if (SP_IS_STOP (ochild)) {
536                                 sl = g_slist_append (sl, ochild);
537                         }
538                 }
539         }
540         if (!sl) {
541                 GtkWidget *i = gtk_menu_item_new_with_label (_("No stops in gradient"));
542                 gtk_widget_show (i);
543                 gtk_menu_append (GTK_MENU (m), i);
544                 gtk_widget_set_sensitive (mnu, FALSE);
545         } else {
547                 for (; sl != NULL; sl = sl->next){
548                         SPStop *stop;
549                         GtkWidget *i;
550                         if (SP_IS_STOP(sl->data)){
551                                 stop = SP_STOP (sl->data);
552                                 i = gtk_menu_item_new ();
553                                 gtk_widget_show (i);
554                                 g_object_set_data (G_OBJECT (i), "stop", stop);
555                                 GtkWidget *hb = gtk_hbox_new (FALSE, 4);
556                                 GtkWidget *cpv = sp_color_preview_new(sp_stop_get_rgba32(stop));
557                                 gtk_widget_show (cpv);
558                                 gtk_container_add ( GTK_CONTAINER (hb), cpv );
559                                 g_object_set_data ( G_OBJECT (i), "preview", cpv );
560                                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) sl->data);
561                                 GtkWidget *l = gtk_label_new (repr->attribute("id"));
562                                 gtk_widget_show (l);
563                                 gtk_misc_set_alignment (GTK_MISC (l), 1.0, 0.5);
564                                 gtk_box_pack_start (GTK_BOX (hb), l, TRUE, TRUE, 0);
565                                 gtk_widget_show (hb);
566                                 gtk_container_add (GTK_CONTAINER (i), hb);
567                                 gtk_menu_append (GTK_MENU (m), i);
568                         }
569                 }
571                 gtk_widget_set_sensitive (mnu, TRUE);
572         }
573         gtk_option_menu_set_menu (GTK_OPTION_MENU (mnu), m);
575         /* Set history */
576         if (new_stop == NULL) {
577                 gtk_option_menu_set_history (GTK_OPTION_MENU (mnu), 0);
578         } else {
579                 select_stop_in_list (mnu, gradient, new_stop);
580         }
582         blocked = FALSE;
586 /*user selected existing stop from list*/
587 static void
588 sp_grad_edit_select (GtkOptionMenu *mnu,  GtkWidget *tbl)
590         SPGradient *gradient = (SPGradient *)g_object_get_data (G_OBJECT(tbl), "gradient");
592         GObject *item = G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu))));
593         SPStop *stop = SP_STOP (g_object_get_data (item, "stop"));
594         if (!stop) return;
596         blocked = TRUE;
598         SPColorSelector *csel = (SPColorSelector*)g_object_get_data (G_OBJECT (tbl), "cselector");
599         guint32 const c = sp_stop_get_rgba32(stop);
600         csel->base->setAlpha(SP_RGBA32_A_F (c));
601         SPColor color( SP_RGBA32_R_F (c), SP_RGBA32_G_F (c), SP_RGBA32_B_F (c) );
602         // set its color, from the stored array
603         csel->base->setColor( color );
604         GtkWidget *offspin = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "offspn"));
605         GtkWidget *offslide =GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "offslide"));
607         GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data (GTK_OBJECT (tbl), "offset");
609         bool isEndStop = false;
611         SPStop *prev = NULL;
612         prev = sp_prev_stop(stop, gradient);
613         if (prev != NULL )  {
614           adj->lower = prev->offset;
615         } else {
616           isEndStop = true;
617           adj->lower = 0;
618         }
620         SPStop *next = NULL;
621         next = sp_next_stop(stop);
622         if (next != NULL ) {
623           adj->upper = next->offset;
624         } else {
625           isEndStop = true;
626           adj->upper = 1.0;
627         }
629         //fixme: does this work on all possible input gradients?
630         if (!isEndStop) {
631                 gtk_widget_set_sensitive (offslide, TRUE);
632                 gtk_widget_set_sensitive (GTK_WIDGET (offspin), TRUE);
633         } else {
634                 gtk_widget_set_sensitive (offslide, FALSE);
635                 gtk_widget_set_sensitive (GTK_WIDGET (offspin), FALSE);
636         }
638         gtk_adjustment_set_value (adj, stop->offset);
640         gtk_adjustment_changed (adj);
642         blocked = FALSE;
648 static void
649 offadjustmentChanged( GtkAdjustment *adjustment, GtkWidget *vb)
651         if (blocked)
652                 return;
654         blocked = TRUE;
656     GtkOptionMenu *mnu = (GtkOptionMenu *)g_object_get_data (G_OBJECT(vb), "stopmenu");
657     if (!g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop")) return;
658     SPStop *stop = SP_STOP(g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop"));
660     stop->offset = adjustment->value;
661     sp_repr_set_css_double(SP_OBJECT_REPR(stop), "offset", stop->offset);
663     sp_document_done (SP_OBJECT_DOCUMENT (stop), SP_VERB_CONTEXT_GRADIENT,
664                                                         _("Change gradient stop offset"));
666         blocked = FALSE;
669 guint32
670 sp_average_color (guint32 c1, guint32 c2, gdouble p = 0.5)
672         guint32 r = (guint32) (SP_RGBA32_R_U (c1) * p + SP_RGBA32_R_U (c2) * (1 - p));
673         guint32 g = (guint32) (SP_RGBA32_G_U (c1) * p + SP_RGBA32_G_U (c2) * (1 - p));
674         guint32 b = (guint32) (SP_RGBA32_B_U (c1) * p + SP_RGBA32_B_U (c2) * (1 - p));
675         guint32 a = (guint32) (SP_RGBA32_A_U (c1) * p + SP_RGBA32_A_U (c2) * (1 - p));
677         return SP_RGBA32_U_COMPOSE (r, g, b, a);
681 static void
682 sp_grd_ed_add_stop (GtkWidget *widget,  GtkWidget *vb)
684         SPGradient *gradient = (SPGradient *) g_object_get_data (G_OBJECT(vb), "gradient");
685         verify_grad (gradient);
686         GtkOptionMenu *mnu = (GtkOptionMenu *)g_object_get_data (G_OBJECT(vb), "stopmenu");
688         SPStop *stop = (SPStop *) g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop");
690         if (stop == NULL)
691                 return;
693         Inkscape::XML::Node *new_stop_repr = NULL;
695         SPStop *next = sp_next_stop (stop);
697         if (next == NULL) {
698                 SPStop *prev = sp_prev_stop (stop, gradient);
699                 if (prev != NULL) {
700                         next = stop;
701                         stop = prev;
702                 }
703         }
705         if (next != NULL) {
706                 new_stop_repr = SP_OBJECT_REPR(stop)->duplicate(SP_OBJECT_REPR(gradient)->document());
707                 SP_OBJECT_REPR(gradient)->addChild(new_stop_repr, SP_OBJECT_REPR(stop));
708         } else {
709                 next = stop;
710                 new_stop_repr = SP_OBJECT_REPR(sp_prev_stop(stop, gradient))->duplicate(SP_OBJECT_REPR(gradient)->document());
711                 SP_OBJECT_REPR(gradient)->addChild(new_stop_repr, SP_OBJECT_REPR(sp_prev_stop(stop, gradient)));
712         }
714         SPStop *newstop = (SPStop *) SP_OBJECT_DOCUMENT(gradient)->getObjectByRepr(new_stop_repr);
716         newstop->offset = (stop->offset + next->offset) * 0.5 ;
718         guint32 const c1 = sp_stop_get_rgba32(stop);
719         guint32 const c2 = sp_stop_get_rgba32(next);
720         guint32 cnew = sp_average_color (c1, c2);
722         Inkscape::CSSOStringStream os;
723         gchar c[64];
724         sp_svg_write_color (c, sizeof(c), cnew);
725         gdouble opacity = (gdouble) SP_RGBA32_A_F (cnew);
726         os << "stop-color:" << c << ";stop-opacity:" << opacity <<";";
727         SP_OBJECT_REPR (newstop)->setAttribute("style", os.str().c_str());
728     sp_repr_set_css_double( SP_OBJECT_REPR(newstop), "offset", (double)newstop->offset);
730         sp_gradient_vector_widget_load_gradient (vb, gradient);
731         Inkscape::GC::release(new_stop_repr);
732         update_stop_list(GTK_WIDGET(mnu), gradient, newstop);
733         GtkWidget *offspin = GTK_WIDGET (g_object_get_data (G_OBJECT (vb), "offspn"));
734         GtkWidget *offslide =GTK_WIDGET (g_object_get_data (G_OBJECT (vb), "offslide"));
735         gtk_widget_set_sensitive (offslide, TRUE);
736         gtk_widget_set_sensitive (GTK_WIDGET (offspin), TRUE);
737         sp_document_done (SP_OBJECT_DOCUMENT (gradient), SP_VERB_CONTEXT_GRADIENT, 
738                           _("Add gradient stop"));
741 static void
742 sp_grd_ed_del_stop (GtkWidget *widget,  GtkWidget *vb)
744         SPGradient *gradient = (SPGradient *)g_object_get_data (G_OBJECT(vb), "gradient");
746         GtkOptionMenu *mnu = (GtkOptionMenu *)g_object_get_data (G_OBJECT(vb), "stopmenu");
747         if (!g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop")) return;
748         SPStop *stop = SP_STOP(g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop"));
749         if (gradient->vector.stops.size() > 2) { // 2 is the minimum
751                 // if we delete first or last stop, move the next/previous to the edge
752                 if (stop->offset == 0) {
753                         SPStop *next = sp_next_stop (stop);
754                         if (next) {
755                                 next->offset = 0;
756                                 sp_repr_set_css_double (SP_OBJECT_REPR (next), "offset", 0);
757                         }
758                 } else if (stop->offset == 1) {
759                         SPStop *prev = sp_prev_stop (stop, gradient);
760                         if (prev) {
761                                 prev->offset = 1;
762                                 sp_repr_set_css_double (SP_OBJECT_REPR (prev), "offset", 1);
763                         }
764                 }
766                 SP_OBJECT_REPR(gradient)->removeChild(SP_OBJECT_REPR(stop));
767                 sp_gradient_vector_widget_load_gradient (vb, gradient);
768                 update_stop_list(GTK_WIDGET(mnu), gradient, NULL);
769                 sp_document_done (SP_OBJECT_DOCUMENT (gradient), SP_VERB_CONTEXT_GRADIENT, 
770                                   _("Delete gradient stop"));
771         }
775 static GtkWidget *
776 sp_gradient_vector_widget_new (SPGradient *gradient, SPStop *select_stop)
778         GtkWidget *vb, *w, *f, *csel;
780         g_return_val_if_fail (!gradient || SP_IS_GRADIENT (gradient), NULL);
782         vb = gtk_vbox_new (FALSE, PAD);
783         g_signal_connect (G_OBJECT (vb), "destroy", G_CALLBACK (sp_gradient_vector_widget_destroy), NULL);
785         w = sp_gradient_image_new (gradient);
786         g_object_set_data (G_OBJECT (vb), "preview", w);
787         gtk_widget_show (w);
788         gtk_box_pack_start (GTK_BOX (vb), w, TRUE, TRUE, PAD);
790         gtk_object_set_data (GTK_OBJECT (vb), "gradient", gradient);
791         sp_repr_add_listener (SP_OBJECT_REPR(gradient), &grad_edit_dia_repr_events, vb);
792         GtkTooltips *tt = gtk_tooltips_new ();
794         /* Stop list */
795         GtkWidget *mnu = gtk_option_menu_new ();
796         /* Create new menu widget */
797         update_stop_list (GTK_WIDGET(mnu), gradient, NULL);
798         gtk_signal_connect (GTK_OBJECT (mnu), "changed", GTK_SIGNAL_FUNC (sp_grad_edit_select), vb);
799         gtk_widget_show (mnu);
800         gtk_object_set_data (GTK_OBJECT (vb), "stopmenu", mnu);
801         gtk_box_pack_start (GTK_BOX (vb), mnu, FALSE, FALSE, 0);
803         /* Add and Remove buttons */
804         GtkWidget *hb = gtk_hbox_new (FALSE, 1);
805         // TRANSLATORS: "Stop" means: a "phase" of a gradient
806         GtkWidget *b = gtk_button_new_with_label (_("Add stop"));
807         gtk_widget_show (b);
808         gtk_container_add (GTK_CONTAINER (hb), b);
809         gtk_tooltips_set_tip (tt, b, _("Add another control stop to gradient"), NULL);
810         gtk_signal_connect (GTK_OBJECT (b), "clicked", GTK_SIGNAL_FUNC (sp_grd_ed_add_stop), vb);
811         b = gtk_button_new_with_label (_("Delete stop"));
812         gtk_widget_show (b);
813         gtk_container_add (GTK_CONTAINER (hb), b);
814         gtk_tooltips_set_tip (tt, b, _("Delete current control stop from gradient"), NULL);
815         gtk_signal_connect (GTK_OBJECT (b), "clicked", GTK_SIGNAL_FUNC (sp_grd_ed_del_stop), vb);
817         gtk_widget_show (hb);
818         gtk_box_pack_start (GTK_BOX (vb),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
821         /*  Offset Slider and stuff   */
822         hb = gtk_hbox_new (FALSE, 0);
824         /* Label */
825         GtkWidget *l = gtk_label_new (_("Offset:"));
826         gtk_misc_set_alignment (GTK_MISC (l), 1.0, 0.5);
827         gtk_box_pack_start (GTK_BOX (hb),l, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
828         gtk_widget_show (l);
830         /* Adjustment */
831         GtkAdjustment *Offset_adj = NULL;
832         Offset_adj= (GtkAdjustment *) gtk_adjustment_new (0.0, 0.0, 1.0, 0.01, 0.01, 0.0);
833         gtk_object_set_data (GTK_OBJECT (vb), "offset", Offset_adj);
834         GtkMenu *m = GTK_MENU(gtk_option_menu_get_menu (GTK_OPTION_MENU(mnu)));
835         SPStop *stop = SP_STOP (g_object_get_data (G_OBJECT (gtk_menu_get_active (m)), "stop"));
836         gtk_adjustment_set_value (Offset_adj, stop->offset);
838         /* Slider */
839         GtkWidget *slider = gtk_hscale_new(Offset_adj);
840         gtk_scale_set_draw_value( GTK_SCALE(slider), FALSE );
841         gtk_widget_show (slider);
842         gtk_box_pack_start (GTK_BOX (hb),slider, TRUE, TRUE, AUX_BETWEEN_BUTTON_GROUPS);
843         gtk_object_set_data (GTK_OBJECT (vb), "offslide", slider);
845         /* Spinbutton */
846         GtkWidget *sbtn = gtk_spin_button_new (GTK_ADJUSTMENT (Offset_adj), 0.01, 2);
847         sp_dialog_defocus_on_enter (sbtn);
848         gtk_widget_show (sbtn);
849         gtk_box_pack_start (GTK_BOX (hb),sbtn, FALSE, TRUE, AUX_BETWEEN_BUTTON_GROUPS);
850         gtk_object_set_data (GTK_OBJECT (vb), "offspn", sbtn);
852         if (stop->offset>0 && stop->offset<1) {
853                 gtk_widget_set_sensitive (slider, TRUE);
854                 gtk_widget_set_sensitive (GTK_WIDGET (sbtn), TRUE);
855         } else {
856                 gtk_widget_set_sensitive (slider, FALSE);
857                 gtk_widget_set_sensitive (GTK_WIDGET (sbtn), FALSE);
858         }
861         /* Signals */
862         gtk_signal_connect (GTK_OBJECT (Offset_adj), "value_changed", 
863                             GTK_SIGNAL_FUNC (offadjustmentChanged), vb);
865         // gtk_signal_connect (GTK_OBJECT (slider), "changed",  GTK_SIGNAL_FUNC (offsliderChanged), vb);
866         gtk_widget_show (hb);
867         gtk_box_pack_start (GTK_BOX (vb), hb, FALSE, FALSE, PAD);
869         // TRANSLATORS: "Stop" means: a "phase" of a gradient
870         f = gtk_frame_new (_("Stop Color"));
871         gtk_widget_show (f);
872         gtk_box_pack_start (GTK_BOX (vb), f, TRUE, TRUE, PAD);
873         csel = (GtkWidget*)sp_color_selector_new (SP_TYPE_COLOR_NOTEBOOK);
874         g_object_set_data (G_OBJECT (vb), "cselector", csel);
875         gtk_widget_show (csel);
876         gtk_container_add (GTK_CONTAINER (f), csel);
877         g_signal_connect (G_OBJECT (csel), "dragged", G_CALLBACK (sp_gradient_vector_color_dragged), vb);
878         g_signal_connect (G_OBJECT (csel), "changed", G_CALLBACK (sp_gradient_vector_color_changed), vb);
880         gtk_widget_show (vb);
882         sp_gradient_vector_widget_load_gradient (vb, gradient);
884         if (select_stop)
885                 select_stop_in_list (GTK_WIDGET(mnu), gradient, select_stop);
887         return vb;
892 GtkWidget *
893 sp_gradient_vector_editor_new (SPGradient *gradient, SPStop *stop)
895     GtkWidget *wid;
897     if (dlg == NULL) {
898         Inkscape::Preferences *prefs = Inkscape::Preferences::get();
900         dlg = sp_window_new (_("Gradient editor"), TRUE);
901         if (x == -1000 || y == -1000) {
902             x = prefs->getInt(prefs_path + "x", -1000);
903             y = prefs->getInt(prefs_path + "y", -1000);
904         }
905         if (w ==0 || h == 0) {
906             w = prefs->getInt(prefs_path + "w", 0);
907             h = prefs->getInt(prefs_path + "h", 0);
908         }
910         if (x<0) x=0;
911         if (y<0) y=0;
913         if (x != 0 || y != 0)
914                 gtk_window_move ((GtkWindow *) dlg, x, y);
915         else
916                 gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
917         if (w && h) gtk_window_resize ((GtkWindow *) dlg, w, h);
918         sp_transientize (dlg);
919         wd.win = dlg;
920         wd.stop = 0;
921         g_signal_connect (G_OBJECT (INKSCAPE), "activate_desktop", G_CALLBACK (sp_transientize_callback), &wd);
922         gtk_signal_connect (GTK_OBJECT (dlg), "event", GTK_SIGNAL_FUNC (sp_dialog_event_handler), dlg);
923         gtk_signal_connect (GTK_OBJECT (dlg), "destroy", G_CALLBACK (sp_gradient_vector_dialog_destroy), dlg);
924         gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", G_CALLBACK (sp_gradient_vector_dialog_delete), dlg);
925         g_signal_connect (G_OBJECT (INKSCAPE), "shut_down", G_CALLBACK (sp_gradient_vector_dialog_delete), dlg);
926         g_signal_connect ( G_OBJECT (INKSCAPE), "dialogs_hide", G_CALLBACK (sp_dialog_hide), dlg );
927         g_signal_connect ( G_OBJECT (INKSCAPE), "dialogs_unhide", G_CALLBACK (sp_dialog_unhide), dlg );
929         gtk_container_set_border_width (GTK_CONTAINER (dlg), PAD);
931         wid = (GtkWidget*)sp_gradient_vector_widget_new (gradient, stop);
932         g_object_set_data (G_OBJECT (dlg), "gradient-vector-widget", wid);
933         /* Connect signals */
934         gtk_widget_show (wid);
935         gtk_container_add (GTK_CONTAINER (dlg), wid);
936     } else {
937         // FIXME: temp fix for 0.38
938         // Simply load_gradient into the editor does not work for multi-stop gradients,
939         // as the stop list and other widgets are in a wrong state and crash readily.
940         // Instead we just delete the window (by sending the delete signal)
941         // and call sp_gradient_vector_editor_new again, so it creates the window anew.
943         GdkEventAny event;
944         GtkWidget *widget = (GtkWidget *) dlg;
945         event.type = GDK_DELETE;
946         event.window = widget->window;
947         event.send_event = TRUE;
948         g_object_ref (G_OBJECT (event.window));
949         gtk_main_do_event ((GdkEvent*)&event);
950         g_object_unref (G_OBJECT (event.window));
952         g_assert (dlg == NULL);
953         sp_gradient_vector_editor_new (gradient, stop);
954     }
956     return dlg;
959 static void
960 sp_gradient_vector_widget_load_gradient (GtkWidget *widget, SPGradient *gradient)
962         blocked = TRUE;
964         SPGradient *old;
966         old = (SPGradient*)g_object_get_data (G_OBJECT (widget), "gradient");
968         if (old != gradient) {
969                 sigc::connection *release_connection;
970                 sigc::connection *modified_connection;
972                 release_connection = (sigc::connection *)g_object_get_data(G_OBJECT(widget), "gradient_release_connection");
973                 modified_connection = (sigc::connection *)g_object_get_data(G_OBJECT(widget), "gradient_modified_connection");
975                 if (old) {
976                         g_assert( release_connection != NULL );
977                         g_assert( modified_connection != NULL );
978                         release_connection->disconnect();
979                         modified_connection->disconnect();
980                         sp_signal_disconnect_by_data (old, widget);
981                 }
983                 if (gradient) {
984                         if (!release_connection) {
985                                 release_connection = new sigc::connection();
986                         }
987                         if (!modified_connection) {
988                                 modified_connection = new sigc::connection();
989                         }
990                         *release_connection = gradient->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gradient_vector_gradient_release), widget));
991                         *modified_connection = gradient->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_gradient_vector_gradient_modified), widget));
992                 } else {
993                         if (release_connection) {
994                                 delete release_connection;
995                                 release_connection = NULL;
996                         }
997                         if (modified_connection) {
998                                 delete modified_connection;
999                                 modified_connection = NULL;
1000                         }
1001                 }
1003                 g_object_set_data(G_OBJECT(widget), "gradient_release_connection", release_connection);
1004                 g_object_set_data(G_OBJECT(widget), "gradient_modified_connection", modified_connection);
1005         }
1007         g_object_set_data (G_OBJECT (widget), "gradient", gradient);
1009         if (gradient) {
1010                 sp_gradient_ensure_vector (gradient);
1012                 GtkOptionMenu *mnu = (GtkOptionMenu *)g_object_get_data (G_OBJECT(widget), "stopmenu");
1013                 SPStop *stop = SP_STOP(g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop"));
1014                 guint32 const c = sp_stop_get_rgba32(stop);
1016                 /// get the color selector
1017                 SPColorSelector *csel = SP_COLOR_SELECTOR(g_object_get_data (G_OBJECT (widget), "cselector"));
1018                 // set alpha
1019                 csel->base->setAlpha(SP_RGBA32_A_F (c));
1020                 SPColor color( SP_RGBA32_R_F (c), SP_RGBA32_G_F (c), SP_RGBA32_B_F (c) );
1021                 // set color
1022                 csel->base->setColor( color );
1023         }
1025         /* Fill preview */
1026         GtkWidget *w = static_cast<GtkWidget *>(g_object_get_data(G_OBJECT(widget), "preview"));
1027         sp_gradient_image_set_gradient (SP_GRADIENT_IMAGE (w), gradient);
1029         GtkWidget *mnu = static_cast<GtkWidget *>(g_object_get_data(G_OBJECT(widget), "stopmenu"));
1030         update_stop_list (GTK_WIDGET(mnu), gradient, NULL);
1032         // Once the user edits a gradient, it stops being auto-collectable
1033         if (SP_OBJECT_REPR(gradient)->attribute("inkscape:collect")) {
1034                 SPDocument *document = SP_OBJECT_DOCUMENT (gradient);
1035                 bool saved = sp_document_get_undo_sensitive(document);
1036                 sp_document_set_undo_sensitive (document, false);
1037                 SP_OBJECT_REPR(gradient)->setAttribute("inkscape:collect", NULL);
1038                 sp_document_set_undo_sensitive (document, saved);
1039         }
1041         blocked = FALSE;
1044 static void
1045 sp_gradient_vector_dialog_destroy (GtkObject *object, gpointer data)
1047         sp_signal_disconnect_by_data (INKSCAPE, dlg);
1048         wd.win = dlg = NULL;
1049         wd.stop = 0;
1052 static gboolean
1053 sp_gradient_vector_dialog_delete (GtkWidget *widget, GdkEvent *event, GtkWidget *dialog)
1055     gtk_window_get_position ((GtkWindow *) dlg, &x, &y);
1056     gtk_window_get_size ((GtkWindow *) dlg, &w, &h);
1058     if (x<0) x=0;
1059     if (y<0) y=0;
1061     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1062     prefs->setInt(prefs_path + "x", x);
1063     prefs->setInt(prefs_path + "y", y);
1064     prefs->setInt(prefs_path + "w", w);
1065     prefs->setInt(prefs_path + "h", h);
1067     return FALSE; // which means, go ahead and destroy it
1070 /* Widget destroy handler */
1072 static void
1073 sp_gradient_vector_widget_destroy (GtkObject *object, gpointer data)
1075         GObject *gradient;
1077         gradient = (GObject*)g_object_get_data (G_OBJECT (object), "gradient");
1079         if (gradient && SP_OBJECT_REPR(gradient)) {
1080                 /* Remove signals connected to us */
1081                 /* fixme: may use _connect_while_alive as well */
1082                 sp_signal_disconnect_by_data (gradient, object);
1083                 sp_repr_remove_listener_by_data (SP_OBJECT_REPR(gradient), object);
1084         }
1087 static void
1088 sp_gradient_vector_gradient_release (SPObject *object, GtkWidget *widget)
1090         sp_gradient_vector_widget_load_gradient (widget, NULL);
1093 static void
1094 sp_gradient_vector_gradient_modified (SPObject *object, guint flags, GtkWidget *widget)
1096         SPGradient *gradient=SP_GRADIENT(object);
1097         if (!blocked) {
1098                 blocked = TRUE;
1099                 sp_gradient_vector_widget_load_gradient (widget, gradient);
1100                 blocked = FALSE;
1101         }
1104 static void sp_gradient_vector_color_dragged(SPColorSelector *csel, GtkObject *object)
1106         SPGradient *gradient, *ngr;
1108         if (blocked) return;
1110         gradient = (SPGradient*)g_object_get_data (G_OBJECT (object), "gradient");
1111         if (!gradient) return;
1113         blocked = TRUE;
1115         ngr = sp_gradient_ensure_vector_normalized (gradient);
1116         if (ngr != gradient) {
1117                 /* Our master gradient has changed */
1118                 sp_gradient_vector_widget_load_gradient (GTK_WIDGET (object), ngr);
1119         }
1121         sp_gradient_ensure_vector (ngr);
1123     GtkOptionMenu *mnu = (GtkOptionMenu *)g_object_get_data (G_OBJECT(object), "stopmenu");
1124     SPStop *stop = SP_STOP(g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop"));
1127     csel->base->getColorAlpha(stop->specified_color, &stop->opacity);
1128     stop->currentColor = false;
1130     blocked = FALSE;
1133 static void
1134 sp_gradient_vector_color_changed (SPColorSelector *csel, GtkObject *object)
1136         SPColor color;
1137         float alpha;
1138         guint32 rgb;
1140         if (blocked) return;
1142         SPGradient *gradient = (SPGradient*)g_object_get_data (G_OBJECT (object), "gradient");
1143         if (!gradient) return;
1145         blocked = TRUE;
1147         SPGradient *ngr = sp_gradient_ensure_vector_normalized (gradient);
1148         if (ngr != gradient) {
1149                 /* Our master gradient has changed */
1150                 sp_gradient_vector_widget_load_gradient (GTK_WIDGET (object), ngr);
1151         }
1153         sp_gradient_ensure_vector (ngr);
1155         /* Set start parameters */
1156         /* We rely on normalized vector, i.e. stops HAVE to exist */
1157         g_return_if_fail (sp_first_stop(ngr) != NULL);
1159         GtkOptionMenu *mnu = (GtkOptionMenu *)g_object_get_data (G_OBJECT(object), "stopmenu");
1160         SPStop *stop = SP_STOP(g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop"));
1162         csel = (SPColorSelector*)g_object_get_data (G_OBJECT (object), "cselector");
1163         csel->base->getColorAlpha( color, &alpha );
1164         rgb = color.toRGBA32( 0x00 );
1166         sp_repr_set_css_double (SP_OBJECT_REPR (stop), "offset", stop->offset);
1167         Inkscape::CSSOStringStream os;
1168         gchar c[64];
1169         sp_svg_write_color (c, sizeof(c), rgb);
1170         os << "stop-color:" << c << ";stop-opacity:" << (gdouble) alpha <<";";
1171         SP_OBJECT_REPR (stop)->setAttribute("style", os.str().c_str());
1172                 //      g_snprintf (c, 256, "stop-color:#%06x;stop-opacity:%g;", rgb >> 8, (gdouble) alpha);
1173                 //SP_OBJECT_REPR (stop)->setAttribute("style", c);
1175         sp_document_done (SP_OBJECT_DOCUMENT (ngr), SP_VERB_CONTEXT_GRADIENT,
1176                           _("Change gradient stop color"));
1178         blocked = FALSE;
1180         SPColorPreview *cpv = (SPColorPreview *)g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "preview");
1181         sp_color_preview_set_rgba32(cpv, sp_stop_get_rgba32(stop));
1184 /*
1185   Local Variables:
1186   mode:c++
1187   c-file-style:"stroustrup"
1188   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1189   indent-tabs-mode:nil
1190   fill-column:99
1191   End:
1192 */
1193 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :