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