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 "../prefs-utils.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 gchar 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;
106 }
108 static void
109 sp_gradient_vector_selector_init (SPGradientVectorSelector *gvs)
110 {
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);
123 }
125 static void
126 sp_gradient_vector_selector_destroy (GtkObject *object)
127 {
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);
149 }
151 GtkWidget *
152 sp_gradient_vector_selector_new (SPDocument *doc, SPGradient *gr)
153 {
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;
168 }
170 void
171 sp_gradient_vector_selector_set_gradient (SPGradientVectorSelector *gvs, SPDocument *doc, SPGradient *gr)
172 {
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 */
215 }
217 SPDocument *
218 sp_gradient_vector_selector_get_document (SPGradientVectorSelector *gvs)
219 {
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;
224 }
226 SPGradient *
227 sp_gradient_vector_selector_get_gradient (SPGradientVectorSelector *gvs)
228 {
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;
233 }
235 static void
236 sp_gvs_rebuild_gui_full (SPGradientVectorSelector *gvs)
237 {
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);
323 }
325 static void
326 sp_gvs_gradient_activate (GtkMenuItem *mi, SPGradientVectorSelector *gvs)
327 {
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 }
365 }
367 static void
368 sp_gvs_gradient_release (SPObject *obj, SPGradientVectorSelector *gvs)
369 {
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);
378 }
380 static void
381 sp_gvs_defs_release (SPObject *defs, SPGradientVectorSelector *gvs)
382 {
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);
396 }
398 static void
399 sp_gvs_defs_modified (SPObject *defs, guint flags, SPGradientVectorSelector *gvs)
400 {
401 /* fixme: We probably have to check some flags here (Lauris) */
403 sp_gvs_rebuild_gui_full (gvs);
404 }
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)
435 {
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);
440 }
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 =
446 {
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)
456 {
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, 64, 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);
484 child = xml_doc->createElement("svg:stop");
485 sp_repr_set_css_double(child, "offset", 1.0);
486 child->setAttribute("style", os.str().c_str());
487 SP_OBJECT_REPR (gradient)->addChild(child, NULL);
488 }
489 if (i < 2) {
490 sp_repr_set_css_double(SP_OBJECT_REPR(stop), "offset", 0.0);
491 Inkscape::XML::Node *child = SP_OBJECT_REPR(stop)->duplicate(SP_OBJECT_REPR(gradient)->document());
492 sp_repr_set_css_double(child, "offset", 1.0);
493 SP_OBJECT_REPR(gradient)->addChild(child, SP_OBJECT_REPR (stop));
494 }
495 }
497 static void
498 select_stop_in_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_stop)
499 {
500 int i = 0;
501 for ( SPObject *ochild = sp_object_first_child(SP_OBJECT(gradient)) ; ochild != NULL ; ochild = SP_OBJECT_NEXT(ochild) ) {
502 if (SP_IS_STOP (ochild)) {
503 if (SP_OBJECT (ochild) == SP_OBJECT(new_stop)) {
504 gtk_option_menu_set_history (GTK_OPTION_MENU (mnu), i);
505 break;
506 }
507 i++;
508 }
509 }
510 }
512 static void
513 update_stop_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_stop)
514 {
516 if (!SP_IS_GRADIENT (gradient))
517 return;
519 blocked = TRUE;
521 /* Clear old menu, if there is any */
522 if (gtk_option_menu_get_menu (GTK_OPTION_MENU (mnu))) {
523 gtk_option_menu_remove_menu (GTK_OPTION_MENU (mnu));
524 }
526 /* Create new menu widget */
527 GtkWidget *m = gtk_menu_new ();
528 gtk_widget_show (m);
529 GSList *sl = NULL;
530 if (gradient->has_stops) {
531 for ( SPObject *ochild = sp_object_first_child (SP_OBJECT(gradient)) ; ochild != NULL ; ochild = SP_OBJECT_NEXT(ochild) ) {
532 if (SP_IS_STOP (ochild)) {
533 sl = g_slist_append (sl, ochild);
534 }
535 }
536 }
537 if (!sl) {
538 GtkWidget *i = gtk_menu_item_new_with_label (_("No stops in gradient"));
539 gtk_widget_show (i);
540 gtk_menu_append (GTK_MENU (m), i);
541 gtk_widget_set_sensitive (mnu, FALSE);
542 } else {
544 for (; sl != NULL; sl = sl->next){
545 SPStop *stop;
546 GtkWidget *i;
547 if (SP_IS_STOP(sl->data)){
548 stop = SP_STOP (sl->data);
549 i = gtk_menu_item_new ();
550 gtk_widget_show (i);
551 g_object_set_data (G_OBJECT (i), "stop", stop);
552 GtkWidget *hb = gtk_hbox_new (FALSE, 4);
553 GtkWidget *cpv = sp_color_preview_new(sp_stop_get_rgba32(stop));
554 gtk_widget_show (cpv);
555 gtk_container_add ( GTK_CONTAINER (hb), cpv );
556 g_object_set_data ( G_OBJECT (i), "preview", cpv );
557 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) sl->data);
558 GtkWidget *l = gtk_label_new (repr->attribute("id"));
559 gtk_widget_show (l);
560 gtk_misc_set_alignment (GTK_MISC (l), 1.0, 0.5);
561 gtk_box_pack_start (GTK_BOX (hb), l, TRUE, TRUE, 0);
562 gtk_widget_show (hb);
563 gtk_container_add (GTK_CONTAINER (i), hb);
564 gtk_menu_append (GTK_MENU (m), i);
565 }
566 }
568 gtk_widget_set_sensitive (mnu, TRUE);
569 }
570 gtk_option_menu_set_menu (GTK_OPTION_MENU (mnu), m);
572 /* Set history */
573 if (new_stop == NULL) {
574 gtk_option_menu_set_history (GTK_OPTION_MENU (mnu), 0);
575 } else {
576 select_stop_in_list (mnu, gradient, new_stop);
577 }
579 blocked = FALSE;
580 }
583 /*user selected existing stop from list*/
584 static void
585 sp_grad_edit_select (GtkOptionMenu *mnu, GtkWidget *tbl)
586 {
587 SPGradient *gradient = (SPGradient *)g_object_get_data (G_OBJECT(tbl), "gradient");
589 GObject *item = G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu))));
590 SPStop *stop = SP_STOP (g_object_get_data (item, "stop"));
591 if (!stop) return;
593 blocked = TRUE;
595 SPColorSelector *csel = (SPColorSelector*)g_object_get_data (G_OBJECT (tbl), "cselector");
596 guint32 const c = sp_stop_get_rgba32(stop);
597 csel->base->setAlpha(SP_RGBA32_A_F (c));
598 SPColor color;
599 sp_color_set_rgb_float (&color, SP_RGBA32_R_F (c), SP_RGBA32_G_F (c), SP_RGBA32_B_F (c));
600 // set its color, from the stored array
601 csel->base->setColor( color );
602 GtkWidget *offspin = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "offspn"));
603 GtkWidget *offslide =GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "offslide"));
605 GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data (GTK_OBJECT (tbl), "offset");
607 bool isEndStop = false;
609 SPStop *prev = NULL;
610 prev = sp_prev_stop(stop, gradient);
611 if (prev != NULL ) {
612 adj->lower = prev->offset;
613 } else {
614 isEndStop = true;
615 adj->lower = 0;
616 }
618 SPStop *next = NULL;
619 next = sp_next_stop(stop);
620 if (next != NULL ) {
621 adj->upper = next->offset;
622 } else {
623 isEndStop = true;
624 adj->upper = 1.0;
625 }
627 //fixme: does this work on all possible input gradients?
628 if (!isEndStop) {
629 gtk_widget_set_sensitive (offslide, TRUE);
630 gtk_widget_set_sensitive (GTK_WIDGET (offspin), TRUE);
631 } else {
632 gtk_widget_set_sensitive (offslide, FALSE);
633 gtk_widget_set_sensitive (GTK_WIDGET (offspin), FALSE);
634 }
636 gtk_adjustment_set_value (adj, stop->offset);
638 gtk_adjustment_changed (adj);
640 blocked = FALSE;
641 }
646 static void
647 offadjustmentChanged( GtkAdjustment *adjustment, GtkWidget *vb)
648 {
649 if (blocked)
650 return;
652 blocked = TRUE;
654 GtkOptionMenu *mnu = (GtkOptionMenu *)g_object_get_data (G_OBJECT(vb), "stopmenu");
655 if (!g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop")) return;
656 SPStop *stop = SP_STOP(g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop"));
658 stop->offset = adjustment->value;
659 sp_repr_set_css_double(SP_OBJECT_REPR(stop), "offset", stop->offset);
661 sp_document_done (SP_OBJECT_DOCUMENT (stop), SP_VERB_CONTEXT_GRADIENT,
662 _("Change gradient stop offset"));
664 blocked = FALSE;
665 }
667 guint32
668 sp_average_color (guint32 c1, guint32 c2, gdouble p = 0.5)
669 {
670 guint32 r = (guint32) (SP_RGBA32_R_U (c1) * p + SP_RGBA32_R_U (c2) * (1 - p));
671 guint32 g = (guint32) (SP_RGBA32_G_U (c1) * p + SP_RGBA32_G_U (c2) * (1 - p));
672 guint32 b = (guint32) (SP_RGBA32_B_U (c1) * p + SP_RGBA32_B_U (c2) * (1 - p));
673 guint32 a = (guint32) (SP_RGBA32_A_U (c1) * p + SP_RGBA32_A_U (c2) * (1 - p));
675 return SP_RGBA32_U_COMPOSE (r, g, b, a);
676 }
679 static void
680 sp_grd_ed_add_stop (GtkWidget *widget, GtkWidget *vb)
681 {
682 SPGradient *gradient = (SPGradient *) g_object_get_data (G_OBJECT(vb), "gradient");
683 verify_grad (gradient);
684 GtkOptionMenu *mnu = (GtkOptionMenu *)g_object_get_data (G_OBJECT(vb), "stopmenu");
686 SPStop *stop = (SPStop *) g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop");
688 if (stop == NULL)
689 return;
691 Inkscape::XML::Node *new_stop_repr = NULL;
693 SPStop *next = sp_next_stop (stop);
695 if (next == NULL) {
696 SPStop *prev = sp_prev_stop (stop, gradient);
697 if (prev != NULL) {
698 next = stop;
699 stop = prev;
700 }
701 }
703 if (next != NULL) {
704 new_stop_repr = SP_OBJECT_REPR(stop)->duplicate(SP_OBJECT_REPR(gradient)->document());
705 SP_OBJECT_REPR(gradient)->addChild(new_stop_repr, SP_OBJECT_REPR(stop));
706 } else {
707 next = stop;
708 new_stop_repr = SP_OBJECT_REPR(sp_prev_stop(stop, gradient))->duplicate(SP_OBJECT_REPR(gradient)->document());
709 SP_OBJECT_REPR(gradient)->addChild(new_stop_repr, SP_OBJECT_REPR(sp_prev_stop(stop, gradient)));
710 }
712 SPStop *newstop = (SPStop *) SP_OBJECT_DOCUMENT(gradient)->getObjectByRepr(new_stop_repr);
714 newstop->offset = (stop->offset + next->offset) * 0.5 ;
716 guint32 const c1 = sp_stop_get_rgba32(stop);
717 guint32 const c2 = sp_stop_get_rgba32(next);
718 guint32 cnew = sp_average_color (c1, c2);
720 Inkscape::CSSOStringStream os;
721 gchar c[64];
722 sp_svg_write_color (c, 64, cnew);
723 gdouble opacity = (gdouble) SP_RGBA32_A_F (cnew);
724 os << "stop-color:" << c << ";stop-opacity:" << opacity <<";";
725 SP_OBJECT_REPR (newstop)->setAttribute("style", os.str().c_str());
726 sp_repr_set_css_double( SP_OBJECT_REPR(newstop), "offset", (double)newstop->offset);
728 sp_gradient_vector_widget_load_gradient (vb, gradient);
729 Inkscape::GC::release(new_stop_repr);
730 update_stop_list(GTK_WIDGET(mnu), gradient, newstop);
731 GtkWidget *offspin = GTK_WIDGET (g_object_get_data (G_OBJECT (vb), "offspn"));
732 GtkWidget *offslide =GTK_WIDGET (g_object_get_data (G_OBJECT (vb), "offslide"));
733 gtk_widget_set_sensitive (offslide, TRUE);
734 gtk_widget_set_sensitive (GTK_WIDGET (offspin), TRUE);
735 sp_document_done (SP_OBJECT_DOCUMENT (gradient), SP_VERB_CONTEXT_GRADIENT,
736 _("Add gradient stop"));
737 }
739 static void
740 sp_grd_ed_del_stop (GtkWidget *widget, GtkWidget *vb)
741 {
742 SPGradient *gradient = (SPGradient *)g_object_get_data (G_OBJECT(vb), "gradient");
744 GtkOptionMenu *mnu = (GtkOptionMenu *)g_object_get_data (G_OBJECT(vb), "stopmenu");
745 if (!g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop")) return;
746 SPStop *stop = SP_STOP(g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop"));
747 if (gradient->vector.stops.size() > 2) { // 2 is the minimum
749 // if we delete first or last stop, move the next/previous to the edge
750 if (stop->offset == 0) {
751 SPStop *next = sp_next_stop (stop);
752 if (next) {
753 next->offset = 0;
754 sp_repr_set_css_double (SP_OBJECT_REPR (next), "offset", 0);
755 }
756 } else if (stop->offset == 1) {
757 SPStop *prev = sp_prev_stop (stop, gradient);
758 if (prev) {
759 prev->offset = 1;
760 sp_repr_set_css_double (SP_OBJECT_REPR (prev), "offset", 1);
761 }
762 }
764 SP_OBJECT_REPR(gradient)->removeChild(SP_OBJECT_REPR(stop));
765 sp_gradient_vector_widget_load_gradient (vb, gradient);
766 update_stop_list(GTK_WIDGET(mnu), gradient, NULL);
767 sp_document_done (SP_OBJECT_DOCUMENT (gradient), SP_VERB_CONTEXT_GRADIENT,
768 _("Delete gradient stop"));
769 }
771 }
773 static GtkWidget *
774 sp_gradient_vector_widget_new (SPGradient *gradient, SPStop *select_stop)
775 {
776 GtkWidget *vb, *w, *f, *csel;
778 g_return_val_if_fail (!gradient || SP_IS_GRADIENT (gradient), NULL);
780 vb = gtk_vbox_new (FALSE, PAD);
781 g_signal_connect (G_OBJECT (vb), "destroy", G_CALLBACK (sp_gradient_vector_widget_destroy), NULL);
783 w = sp_gradient_image_new (gradient);
784 g_object_set_data (G_OBJECT (vb), "preview", w);
785 gtk_widget_show (w);
786 gtk_box_pack_start (GTK_BOX (vb), w, TRUE, TRUE, PAD);
788 gtk_object_set_data (GTK_OBJECT (vb), "gradient", gradient);
789 sp_repr_add_listener (SP_OBJECT_REPR(gradient), &grad_edit_dia_repr_events, vb);
790 GtkTooltips *tt = gtk_tooltips_new ();
792 /* Stop list */
793 GtkWidget *mnu = gtk_option_menu_new ();
794 /* Create new menu widget */
795 update_stop_list (GTK_WIDGET(mnu), gradient, NULL);
796 gtk_signal_connect (GTK_OBJECT (mnu), "changed", GTK_SIGNAL_FUNC (sp_grad_edit_select), vb);
797 gtk_widget_show (mnu);
798 gtk_object_set_data (GTK_OBJECT (vb), "stopmenu", mnu);
799 gtk_box_pack_start (GTK_BOX (vb), mnu, FALSE, FALSE, 0);
801 /* Add and Remove buttons */
802 GtkWidget *hb = gtk_hbox_new (FALSE, 1);
803 // TRANSLATORS: "Stop" means: a "phase" of a gradient
804 GtkWidget *b = gtk_button_new_with_label (_("Add stop"));
805 gtk_widget_show (b);
806 gtk_container_add (GTK_CONTAINER (hb), b);
807 gtk_tooltips_set_tip (tt, b, _("Add another control stop to gradient"), NULL);
808 gtk_signal_connect (GTK_OBJECT (b), "clicked", GTK_SIGNAL_FUNC (sp_grd_ed_add_stop), vb);
809 b = gtk_button_new_with_label (_("Delete stop"));
810 gtk_widget_show (b);
811 gtk_container_add (GTK_CONTAINER (hb), b);
812 gtk_tooltips_set_tip (tt, b, _("Delete current control stop from gradient"), NULL);
813 gtk_signal_connect (GTK_OBJECT (b), "clicked", GTK_SIGNAL_FUNC (sp_grd_ed_del_stop), vb);
815 gtk_widget_show (hb);
816 gtk_box_pack_start (GTK_BOX (vb),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
819 /* Offset Slider and stuff */
820 hb = gtk_hbox_new (FALSE, 0);
822 /* Label */
823 GtkWidget *l = gtk_label_new (_("Offset:"));
824 gtk_misc_set_alignment (GTK_MISC (l), 1.0, 0.5);
825 gtk_box_pack_start (GTK_BOX (hb),l, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
826 gtk_widget_show (l);
828 /* Adjustment */
829 GtkAdjustment *Offset_adj = NULL;
830 Offset_adj= (GtkAdjustment *) gtk_adjustment_new (0.0, 0.0, 1.0, 0.01, 0.01, 0.0);
831 gtk_object_set_data (GTK_OBJECT (vb), "offset", Offset_adj);
832 GtkMenu *m = GTK_MENU(gtk_option_menu_get_menu (GTK_OPTION_MENU(mnu)));
833 SPStop *stop = SP_STOP (g_object_get_data (G_OBJECT (gtk_menu_get_active (m)), "stop"));
834 gtk_adjustment_set_value (Offset_adj, stop->offset);
836 /* Slider */
837 GtkWidget *slider = gtk_hscale_new(Offset_adj);
838 gtk_scale_set_draw_value( GTK_SCALE(slider), FALSE );
839 gtk_widget_show (slider);
840 gtk_box_pack_start (GTK_BOX (hb),slider, TRUE, TRUE, AUX_BETWEEN_BUTTON_GROUPS);
841 gtk_object_set_data (GTK_OBJECT (vb), "offslide", slider);
843 /* Spinbutton */
844 GtkWidget *sbtn = gtk_spin_button_new (GTK_ADJUSTMENT (Offset_adj), 0.01, 2);
845 sp_dialog_defocus_on_enter (sbtn);
846 gtk_widget_show (sbtn);
847 gtk_box_pack_start (GTK_BOX (hb),sbtn, FALSE, TRUE, AUX_BETWEEN_BUTTON_GROUPS);
848 gtk_object_set_data (GTK_OBJECT (vb), "offspn", sbtn);
850 if (stop->offset>0 && stop->offset<1) {
851 gtk_widget_set_sensitive (slider, TRUE);
852 gtk_widget_set_sensitive (GTK_WIDGET (sbtn), TRUE);
853 } else {
854 gtk_widget_set_sensitive (slider, FALSE);
855 gtk_widget_set_sensitive (GTK_WIDGET (sbtn), FALSE);
856 }
859 /* Signals */
860 gtk_signal_connect (GTK_OBJECT (Offset_adj), "value_changed",
861 GTK_SIGNAL_FUNC (offadjustmentChanged), vb);
863 // gtk_signal_connect (GTK_OBJECT (slider), "changed", GTK_SIGNAL_FUNC (offsliderChanged), vb);
864 gtk_widget_show (hb);
865 gtk_box_pack_start (GTK_BOX (vb), hb, FALSE, FALSE, PAD);
867 // TRANSLATORS: "Stop" means: a "phase" of a gradient
868 f = gtk_frame_new (_("Stop Color"));
869 gtk_widget_show (f);
870 gtk_box_pack_start (GTK_BOX (vb), f, TRUE, TRUE, PAD);
871 csel = (GtkWidget*)sp_color_selector_new (SP_TYPE_COLOR_NOTEBOOK, SP_COLORSPACE_TYPE_NONE);
872 g_object_set_data (G_OBJECT (vb), "cselector", csel);
873 gtk_widget_show (csel);
874 gtk_container_add (GTK_CONTAINER (f), csel);
875 g_signal_connect (G_OBJECT (csel), "dragged", G_CALLBACK (sp_gradient_vector_color_dragged), vb);
876 g_signal_connect (G_OBJECT (csel), "changed", G_CALLBACK (sp_gradient_vector_color_changed), vb);
878 gtk_widget_show (vb);
880 sp_gradient_vector_widget_load_gradient (vb, gradient);
882 if (select_stop)
883 select_stop_in_list (GTK_WIDGET(mnu), gradient, select_stop);
885 return vb;
886 }
890 GtkWidget *
891 sp_gradient_vector_editor_new (SPGradient *gradient, SPStop *stop)
892 {
893 GtkWidget *wid;
895 if (dlg == NULL) {
897 dlg = sp_window_new (_("Gradient editor"), TRUE);
898 if (x == -1000 || y == -1000) {
899 x = prefs_get_int_attribute (prefs_path, "x", 0);
900 y = prefs_get_int_attribute (prefs_path, "y", 0);
901 }
902 if (w ==0 || h == 0) {
903 w = prefs_get_int_attribute (prefs_path, "w", 0);
904 h = prefs_get_int_attribute (prefs_path, "h", 0);
905 }
907 if (x<0) x=0;
908 if (y<0) y=0;
910 if (x != 0 || y != 0)
911 gtk_window_move ((GtkWindow *) dlg, x, y);
912 else
913 gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
914 if (w && h) gtk_window_resize ((GtkWindow *) dlg, w, h);
915 sp_transientize (dlg);
916 wd.win = dlg;
917 wd.stop = 0;
918 g_signal_connect (G_OBJECT (INKSCAPE), "activate_desktop", G_CALLBACK (sp_transientize_callback), &wd);
919 gtk_signal_connect (GTK_OBJECT (dlg), "event", GTK_SIGNAL_FUNC (sp_dialog_event_handler), dlg);
920 gtk_signal_connect (GTK_OBJECT (dlg), "destroy", G_CALLBACK (sp_gradient_vector_dialog_destroy), dlg);
921 gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", G_CALLBACK (sp_gradient_vector_dialog_delete), dlg);
922 g_signal_connect (G_OBJECT (INKSCAPE), "shut_down", G_CALLBACK (sp_gradient_vector_dialog_delete), dlg);
923 g_signal_connect ( G_OBJECT (INKSCAPE), "dialogs_hide", G_CALLBACK (sp_dialog_hide), dlg );
924 g_signal_connect ( G_OBJECT (INKSCAPE), "dialogs_unhide", G_CALLBACK (sp_dialog_unhide), dlg );
926 gtk_container_set_border_width (GTK_CONTAINER (dlg), PAD);
928 wid = (GtkWidget*)sp_gradient_vector_widget_new (gradient, stop);
929 g_object_set_data (G_OBJECT (dlg), "gradient-vector-widget", wid);
930 /* Connect signals */
931 gtk_widget_show (wid);
932 gtk_container_add (GTK_CONTAINER (dlg), wid);
933 } else {
934 // FIXME: temp fix for 0.38
935 // Simply load_gradient into the editor does not work for multi-stop gradients,
936 // as the stop list and other widgets are in a wrong state and crash readily.
937 // Instead we just delete the window (by sending the delete signal)
938 // and call sp_gradient_vector_editor_new again, so it creates the window anew.
940 GdkEventAny event;
941 GtkWidget *widget = (GtkWidget *) dlg;
942 event.type = GDK_DELETE;
943 event.window = widget->window;
944 event.send_event = TRUE;
945 g_object_ref (G_OBJECT (event.window));
946 gtk_main_do_event ((GdkEvent*)&event);
947 g_object_unref (G_OBJECT (event.window));
949 g_assert (dlg == NULL);
950 sp_gradient_vector_editor_new (gradient, stop);
951 }
953 return dlg;
954 }
956 static void
957 sp_gradient_vector_widget_load_gradient (GtkWidget *widget, SPGradient *gradient)
958 {
959 blocked = TRUE;
961 SPGradient *old;
963 old = (SPGradient*)g_object_get_data (G_OBJECT (widget), "gradient");
965 if (old != gradient) {
966 sigc::connection *release_connection;
967 sigc::connection *modified_connection;
969 release_connection = (sigc::connection *)g_object_get_data(G_OBJECT(widget), "gradient_release_connection");
970 modified_connection = (sigc::connection *)g_object_get_data(G_OBJECT(widget), "gradient_modified_connection");
972 if (old) {
973 g_assert( release_connection != NULL );
974 g_assert( modified_connection != NULL );
975 release_connection->disconnect();
976 modified_connection->disconnect();
977 sp_signal_disconnect_by_data (old, widget);
978 }
980 if (gradient) {
981 if (!release_connection) {
982 release_connection = new sigc::connection();
983 }
984 if (!modified_connection) {
985 modified_connection = new sigc::connection();
986 }
987 *release_connection = gradient->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gradient_vector_gradient_release), widget));
988 *modified_connection = gradient->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_gradient_vector_gradient_modified), widget));
989 } else {
990 if (release_connection) {
991 delete release_connection;
992 release_connection = NULL;
993 }
994 if (modified_connection) {
995 delete modified_connection;
996 modified_connection = NULL;
997 }
998 }
1000 g_object_set_data(G_OBJECT(widget), "gradient_release_connection", release_connection);
1001 g_object_set_data(G_OBJECT(widget), "gradient_modified_connection", modified_connection);
1002 }
1004 g_object_set_data (G_OBJECT (widget), "gradient", gradient);
1006 if (gradient) {
1007 sp_gradient_ensure_vector (gradient);
1009 GtkOptionMenu *mnu = (GtkOptionMenu *)g_object_get_data (G_OBJECT(widget), "stopmenu");
1010 SPStop *stop = SP_STOP(g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop"));
1011 guint32 const c = sp_stop_get_rgba32(stop);
1013 /// get the color selector
1014 SPColorSelector *csel = SP_COLOR_SELECTOR(g_object_get_data (G_OBJECT (widget), "cselector"));
1015 // set alpha
1016 csel->base->setAlpha(SP_RGBA32_A_F (c));
1017 SPColor color;
1018 sp_color_set_rgb_float (&color, SP_RGBA32_R_F (c), SP_RGBA32_G_F (c), SP_RGBA32_B_F (c));
1019 // set color
1020 csel->base->setColor( color );
1021 }
1023 /* Fill preview */
1024 GtkWidget *w = static_cast<GtkWidget *>(g_object_get_data(G_OBJECT(widget), "preview"));
1025 sp_gradient_image_set_gradient (SP_GRADIENT_IMAGE (w), gradient);
1027 GtkWidget *mnu = static_cast<GtkWidget *>(g_object_get_data(G_OBJECT(widget), "stopmenu"));
1028 update_stop_list (GTK_WIDGET(mnu), gradient, NULL);
1030 // Once the user edits a gradient, it stops being auto-collectable
1031 if (SP_OBJECT_REPR(gradient)->attribute("inkscape:collect")) {
1032 SPDocument *document = SP_OBJECT_DOCUMENT (gradient);
1033 bool saved = sp_document_get_undo_sensitive(document);
1034 sp_document_set_undo_sensitive (document, false);
1035 SP_OBJECT_REPR(gradient)->setAttribute("inkscape:collect", NULL);
1036 sp_document_set_undo_sensitive (document, saved);
1037 }
1039 blocked = FALSE;
1040 }
1042 static void
1043 sp_gradient_vector_dialog_destroy (GtkObject *object, gpointer data)
1044 {
1045 sp_signal_disconnect_by_data (INKSCAPE, dlg);
1046 wd.win = dlg = NULL;
1047 wd.stop = 0;
1048 }
1050 static gboolean
1051 sp_gradient_vector_dialog_delete (GtkWidget *widget, GdkEvent *event, GtkWidget *dialog)
1052 {
1053 gtk_window_get_position ((GtkWindow *) dlg, &x, &y);
1054 gtk_window_get_size ((GtkWindow *) dlg, &w, &h);
1056 if (x<0) x=0;
1057 if (y<0) y=0;
1059 prefs_set_int_attribute (prefs_path, "x", x);
1060 prefs_set_int_attribute (prefs_path, "y", y);
1061 prefs_set_int_attribute (prefs_path, "w", w);
1062 prefs_set_int_attribute (prefs_path, "h", h);
1064 return FALSE; // which means, go ahead and destroy it
1065 }
1067 /* Widget destroy handler */
1069 static void
1070 sp_gradient_vector_widget_destroy (GtkObject *object, gpointer data)
1071 {
1072 GObject *gradient;
1074 gradient = (GObject*)g_object_get_data (G_OBJECT (object), "gradient");
1076 if (gradient && SP_OBJECT_REPR(gradient)) {
1077 /* Remove signals connected to us */
1078 /* fixme: may use _connect_while_alive as well */
1079 sp_signal_disconnect_by_data (gradient, object);
1080 sp_repr_remove_listener_by_data (SP_OBJECT_REPR(gradient), object);
1081 }
1082 }
1084 static void
1085 sp_gradient_vector_gradient_release (SPObject *object, GtkWidget *widget)
1086 {
1087 sp_gradient_vector_widget_load_gradient (widget, NULL);
1088 }
1090 static void
1091 sp_gradient_vector_gradient_modified (SPObject *object, guint flags, GtkWidget *widget)
1092 {
1093 SPGradient *gradient=SP_GRADIENT(object);
1094 if (!blocked) {
1095 blocked = TRUE;
1096 sp_gradient_vector_widget_load_gradient (widget, gradient);
1097 blocked = FALSE;
1098 }
1099 }
1101 static void sp_gradient_vector_color_dragged(SPColorSelector *csel, GtkObject *object)
1102 {
1103 SPGradient *gradient, *ngr;
1105 if (blocked) return;
1107 gradient = (SPGradient*)g_object_get_data (G_OBJECT (object), "gradient");
1108 if (!gradient) return;
1110 blocked = TRUE;
1112 ngr = sp_gradient_ensure_vector_normalized (gradient);
1113 if (ngr != gradient) {
1114 /* Our master gradient has changed */
1115 sp_gradient_vector_widget_load_gradient (GTK_WIDGET (object), ngr);
1116 }
1118 sp_gradient_ensure_vector (ngr);
1120 GtkOptionMenu *mnu = (GtkOptionMenu *)g_object_get_data (G_OBJECT(object), "stopmenu");
1121 SPStop *stop = SP_STOP(g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop"));
1124 csel->base->getColorAlpha(stop->specified_color, &stop->opacity);
1125 stop->currentColor = false;
1127 blocked = FALSE;
1128 }
1130 static void
1131 sp_gradient_vector_color_changed (SPColorSelector *csel, GtkObject *object)
1132 {
1133 SPColor color;
1134 float alpha;
1135 guint32 rgb;
1137 if (blocked) return;
1139 SPGradient *gradient = (SPGradient*)g_object_get_data (G_OBJECT (object), "gradient");
1140 if (!gradient) return;
1142 blocked = TRUE;
1144 SPGradient *ngr = sp_gradient_ensure_vector_normalized (gradient);
1145 if (ngr != gradient) {
1146 /* Our master gradient has changed */
1147 sp_gradient_vector_widget_load_gradient (GTK_WIDGET (object), ngr);
1148 }
1150 sp_gradient_ensure_vector (ngr);
1152 /* Set start parameters */
1153 /* We rely on normalized vector, i.e. stops HAVE to exist */
1154 g_return_if_fail (sp_first_stop(ngr) != NULL);
1156 GtkOptionMenu *mnu = (GtkOptionMenu *)g_object_get_data (G_OBJECT(object), "stopmenu");
1157 SPStop *stop = SP_STOP(g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "stop"));
1159 csel = (SPColorSelector*)g_object_get_data (G_OBJECT (object), "cselector");
1160 csel->base->getColorAlpha( color, &alpha );
1161 rgb = sp_color_get_rgba32_ualpha (&color, 0x00);
1163 sp_repr_set_css_double (SP_OBJECT_REPR (stop), "offset", stop->offset);
1164 Inkscape::CSSOStringStream os;
1165 gchar c[64];
1166 sp_svg_write_color (c, 64, rgb);
1167 os << "stop-color:" << c << ";stop-opacity:" << (gdouble) alpha <<";";
1168 SP_OBJECT_REPR (stop)->setAttribute("style", os.str().c_str());
1169 // g_snprintf (c, 256, "stop-color:#%06x;stop-opacity:%g;", rgb >> 8, (gdouble) alpha);
1170 //SP_OBJECT_REPR (stop)->setAttribute("style", c);
1172 sp_document_done (SP_OBJECT_DOCUMENT (ngr), SP_VERB_CONTEXT_GRADIENT,
1173 _("Change gradient stop color"));
1175 blocked = FALSE;
1177 SPColorPreview *cpv = (SPColorPreview *)g_object_get_data (G_OBJECT(gtk_menu_get_active (GTK_MENU(gtk_option_menu_get_menu (mnu)))), "preview");
1178 sp_color_preview_set_rgba32(cpv, sp_stop_get_rgba32(stop));
1179 }
1181 /*
1182 Local Variables:
1183 mode:c++
1184 c-file-style:"stroustrup"
1185 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1186 indent-tabs-mode:nil
1187 fill-column:99
1188 End:
1189 */
1190 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :