1 /*
2 * Gradient vector selection widget
3 *
4 * Authors:
5 * Lauris Kaplinski <lauris@kaplinski.com>
6 * bulia byak <buliabyak@users.sf.net>
7 * MenTaLguY <mental@rydia.net>
8 * Jon A. Cruz <jon@joncruz.org>
9 *
10 * Copyright (C) 2001-2002 Lauris Kaplinski
11 * Copyright (C) 2001 Ximian, Inc.
12 * Copyright (C) 2004 Monash University
13 * Copyright (C) 2004 David Turner
14 * Copyright (C) 2006 MenTaLguY
15 * Copyright (C) 2010 Jon A. Cruz
16 *
17 * Released under GNU GPL, read the file 'COPYING' for more information
18 *
19 */
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24 #ifdef HAVE_STRING_H
25 #endif
26 #include <gtk/gtk.h>
27 #include "macros.h"
28 #include <glibmm/i18n.h>
29 #include "../widgets/gradient-image.h"
30 #include "../inkscape.h"
31 #include "../document-private.h"
32 #include "../gradient-chemistry.h"
33 #include "gradient-vector.h"
34 #include "../helper/window.h"
36 #include "xml/repr.h"
38 #include "../dialogs/dialog-events.h"
39 #include "../preferences.h"
40 #include "svg/css-ostringstream.h"
41 #include "sp-stop.h"
43 #include <sigc++/functors/ptr_fun.h>
44 #include <sigc++/adaptors/bind.h>
46 enum {
47 VECTOR_SET,
48 LAST_SIGNAL
49 };
51 static void sp_gradient_vector_selector_class_init(SPGradientVectorSelectorClass *klass);
52 static void sp_gradient_vector_selector_init(SPGradientVectorSelector *gvs);
53 static void sp_gradient_vector_selector_destroy(GtkObject *object);
55 static void sp_gvs_gradient_release(SPObject *obj, SPGradientVectorSelector *gvs);
56 static void sp_gvs_defs_release(SPObject *defs, SPGradientVectorSelector *gvs);
57 static void sp_gvs_defs_modified(SPObject *defs, guint flags, SPGradientVectorSelector *gvs);
59 static void sp_gvs_rebuild_gui_full(SPGradientVectorSelector *gvs);
60 static void sp_gvs_gradient_activate(GtkMenuItem *mi, SPGradientVectorSelector *gvs);
62 static GtkVBoxClass *parent_class;
63 static guint signals[LAST_SIGNAL] = {0};
65 // TODO FIXME kill these globals!!!
66 static GtkWidget *dlg = NULL;
67 static win_data wd;
68 static gint x = -1000, y = -1000, w = 0, h = 0; // impossible original values to make sure they are read from prefs
69 static Glib::ustring const prefs_path = "/dialogs/gradienteditor/";
71 GType sp_gradient_vector_selector_get_type(void)
72 {
73 static GType type = 0;
74 if (!type) {
75 static const GTypeInfo info = {
76 sizeof(SPGradientVectorSelectorClass),
77 NULL, /* base_init */
78 NULL, /* base_finalize */
79 reinterpret_cast<GClassInitFunc>(sp_gradient_vector_selector_class_init),
80 NULL, /* class_finalize */
81 NULL, /* class_data */
82 sizeof(SPGradientVectorSelector),
83 0, /* n_preallocs */
84 reinterpret_cast<GInstanceInitFunc>(sp_gradient_vector_selector_init),
85 0, /* value_table */
86 };
88 type = g_type_register_static( GTK_TYPE_VBOX,
89 "SPGradientVectorSelector",
90 &info,
91 static_cast< GTypeFlags >(0) );
92 }
93 return type;
94 }
96 static void sp_gradient_vector_selector_class_init(SPGradientVectorSelectorClass *klass)
97 {
98 GtkObjectClass *object_class;
100 object_class = GTK_OBJECT_CLASS(klass);
102 parent_class = static_cast<GtkVBoxClass*>(gtk_type_class(GTK_TYPE_VBOX));
104 signals[VECTOR_SET] = gtk_signal_new( "vector_set",
105 GTK_RUN_LAST,
106 GTK_CLASS_TYPE(object_class),
107 GTK_SIGNAL_OFFSET(SPGradientVectorSelectorClass, vector_set),
108 gtk_marshal_NONE__POINTER,
109 GTK_TYPE_NONE, 1,
110 GTK_TYPE_POINTER);
112 object_class->destroy = sp_gradient_vector_selector_destroy;
113 }
115 static void 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 sp_gradient_vector_selector_destroy(GtkObject *object)
132 {
133 SPGradientVectorSelector *gvs = SP_GRADIENT_VECTOR_SELECTOR(object);
135 if (gvs->gr) {
136 gvs->gradient_release_connection.disconnect();
137 gvs->gr = NULL;
138 }
140 if (gvs->doc) {
141 gvs->defs_release_connection.disconnect();
142 gvs->defs_modified_connection.disconnect();
143 gvs->doc = NULL;
144 }
146 gvs->gradient_release_connection.~connection();
147 gvs->defs_release_connection.~connection();
148 gvs->defs_modified_connection.~connection();
150 if ((reinterpret_cast<GtkObjectClass *>(parent_class))->destroy) {
151 (* (reinterpret_cast<GtkObjectClass *>(parent_class))->destroy) (object);
152 }
153 }
155 GtkWidget *sp_gradient_vector_selector_new(SPDocument *doc, SPGradient *gr)
156 {
157 GtkWidget *gvs;
159 g_return_val_if_fail(!gr || SP_IS_GRADIENT(gr), NULL);
160 g_return_val_if_fail(!gr || (SP_OBJECT_DOCUMENT(gr) == doc), NULL);
162 gvs = static_cast<GtkWidget*>(gtk_type_new(SP_TYPE_GRADIENT_VECTOR_SELECTOR));
164 if (doc) {
165 sp_gradient_vector_selector_set_gradient(SP_GRADIENT_VECTOR_SELECTOR(gvs), doc, gr);
166 } else {
167 sp_gvs_rebuild_gui_full(SP_GRADIENT_VECTOR_SELECTOR(gvs));
168 }
170 return gvs;
171 }
173 void sp_gradient_vector_selector_set_gradient(SPGradientVectorSelector *gvs, SPDocument *doc, SPGradient *gr)
174 {
175 static gboolean suppress = FALSE;
177 g_return_if_fail(gvs != NULL);
178 g_return_if_fail(SP_IS_GRADIENT_VECTOR_SELECTOR(gvs));
179 g_return_if_fail(!gr || (doc != NULL));
180 g_return_if_fail(!gr || SP_IS_GRADIENT(gr));
181 g_return_if_fail(!gr || (SP_OBJECT_DOCUMENT(gr) == doc));
182 g_return_if_fail(!gr || SP_GRADIENT_HAS_STOPS(gr));
184 if (doc != gvs->doc) {
185 /* Disconnect signals */
186 if (gvs->gr) {
187 gvs->gradient_release_connection.disconnect();
188 gvs->gr = NULL;
189 }
190 if (gvs->doc) {
191 gvs->defs_release_connection.disconnect();
192 gvs->defs_modified_connection.disconnect();
193 gvs->doc = NULL;
194 }
196 // Connect signals
197 if (doc) {
198 gvs->defs_release_connection = SP_DOCUMENT_DEFS(doc)->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gvs_defs_release), gvs));
199 gvs->defs_modified_connection = SP_DOCUMENT_DEFS(doc)->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_gvs_defs_modified), gvs));
200 }
201 if (gr) {
202 gvs->gradient_release_connection = gr->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gvs_gradient_release), gvs));
203 }
204 gvs->doc = doc;
205 gvs->gr = gr;
206 sp_gvs_rebuild_gui_full(gvs);
207 if (!suppress) g_signal_emit(G_OBJECT(gvs), signals[VECTOR_SET], 0, gr);
208 } else if (gr != gvs->gr) {
209 // Harder case - keep document, rebuild menus and stuff
210 // fixme: (Lauris)
211 suppress = TRUE;
212 sp_gradient_vector_selector_set_gradient(gvs, NULL, NULL);
213 sp_gradient_vector_selector_set_gradient(gvs, doc, gr);
214 suppress = FALSE;
215 g_signal_emit(G_OBJECT(gvs), signals[VECTOR_SET], 0, gr);
216 }
217 /* The case of setting NULL -> NULL is not very interesting */
218 }
220 SPDocument *sp_gradient_vector_selector_get_document(SPGradientVectorSelector *gvs)
221 {
222 g_return_val_if_fail(gvs != NULL, NULL);
223 g_return_val_if_fail(SP_IS_GRADIENT_VECTOR_SELECTOR(gvs), NULL);
225 return gvs->doc;
226 }
228 SPGradient *sp_gradient_vector_selector_get_gradient(SPGradientVectorSelector *gvs)
229 {
230 g_return_val_if_fail(gvs != NULL, NULL);
231 g_return_val_if_fail(SP_IS_GRADIENT_VECTOR_SELECTOR(gvs), NULL);
233 return gvs->gr;
234 }
236 static void 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 *curr = gradients; curr; curr = curr->next) {
252 SPGradient* grad = SP_GRADIENT(curr->data);
253 if (SP_GRADIENT_HAS_STOPS(grad) && !grad->isSwatch()) {
254 gl = g_slist_prepend(gl, curr->data);
255 }
256 }
257 }
258 gl = g_slist_reverse(gl);
260 gint pos = 0;
261 gint idx = 0;
263 if (!gvs->doc) {
264 GtkWidget *i;
265 i = gtk_menu_item_new_with_label(_("No document selected"));
266 gtk_widget_show(i);
267 gtk_menu_append(GTK_MENU(m), i);
268 gtk_widget_set_sensitive(gvs->menu, FALSE);
269 } else if (!gl) {
270 GtkWidget *i;
271 i = gtk_menu_item_new_with_label(_("No gradients in document"));
272 gtk_widget_show(i);
273 gtk_menu_append(GTK_MENU(m), i);
274 gtk_widget_set_sensitive(gvs->menu, FALSE);
275 } else if (!gvs->gr) {
276 GtkWidget *i;
277 i = gtk_menu_item_new_with_label(_("No gradient selected"));
278 gtk_widget_show(i);
279 gtk_menu_append(GTK_MENU(m), i);
280 gtk_widget_set_sensitive(gvs->menu, FALSE);
281 } else {
282 while (gl) {
283 SPGradient *gr;
284 GtkWidget *i, *w;
285 gr = SP_GRADIENT(gl->data);
286 gl = g_slist_remove(gl, gr);
288 /* We have to know: */
289 /* Gradient destroy */
290 /* Gradient name change */
291 i = gtk_menu_item_new();
292 gtk_widget_show(i);
293 g_object_set_data(G_OBJECT(i), "gradient", gr);
294 g_signal_connect(G_OBJECT(i), "activate", G_CALLBACK(sp_gvs_gradient_activate), gvs);
296 w = sp_gradient_image_new(gr);
297 gtk_widget_show(w);
299 if (gvs->idlabel) {
300 GtkWidget *hb, *l;
301 hb = gtk_hbox_new(FALSE, 4);
302 gtk_widget_show(hb);
303 l = gtk_label_new(gr->getId());
304 gtk_widget_show(l);
305 gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
306 gtk_box_pack_start(GTK_BOX(hb), l, TRUE, TRUE, 0);
307 gtk_box_pack_start(GTK_BOX(hb), w, FALSE, FALSE, 0);
308 w = hb;
309 }
311 gtk_container_add(GTK_CONTAINER(i), w);
313 gtk_menu_append(GTK_MENU(m), i);
315 if (gr == gvs->gr) {
316 pos = idx;
317 }
318 idx += 1;
319 }
320 gtk_widget_set_sensitive(gvs->menu, TRUE);
321 }
323 gtk_option_menu_set_menu(GTK_OPTION_MENU(gvs->menu), m);
324 /* Set history */
325 gtk_option_menu_set_history(GTK_OPTION_MENU(gvs->menu), pos);
326 }
328 static void sp_gvs_gradient_activate(GtkMenuItem *mi, SPGradientVectorSelector *gvs)
329 {
330 SPGradient *gr, *norm;
332 gr = (SPGradient*)g_object_get_data(G_OBJECT(mi), "gradient");
333 /* Hmmm... bad things may happen here, if actual gradient is something new */
334 /* Namely - menuitems etc. will be fucked up */
335 /* Hmmm - probably we can just re-set it as menuitem data (Lauris) */
337 //g_print("SPGradientVectorSelector: gradient %s activated\n", SP_OBJECT_ID(gr));
339 norm = sp_gradient_ensure_vector_normalized(gr);
340 if (norm != gr) {
341 //g_print("SPGradientVectorSelector: become %s after normalization\n", SP_OBJECT_ID(norm));
342 /* But be careful that we do not have gradient saved anywhere else */
343 g_object_set_data(G_OBJECT(mi), "gradient", norm);
344 }
346 /* fixme: Really we would want to use _set_vector */
347 /* Detach old */
348 if (gvs->gr) {
349 gvs->gradient_release_connection.disconnect();
350 gvs->gr = NULL;
351 }
352 /* Attach new */
353 if (norm) {
354 gvs->gradient_release_connection = norm->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gvs_gradient_release), gvs));
355 gvs->gr = norm;
356 }
358 g_signal_emit(G_OBJECT(gvs), signals[VECTOR_SET], 0, norm);
360 if (norm != gr) {
361 /* We do extra undo push here */
362 /* If handler has already done it, it is just NOP */
363 // FIXME: looks like this is never a valid undo step, consider removing this
364 sp_document_done(SP_OBJECT_DOCUMENT(norm), SP_VERB_CONTEXT_GRADIENT,
365 /* TODO: annotate */ "gradient-vector.cpp:350");
366 }
367 }
369 static void sp_gvs_gradient_release(SPObject */*obj*/, SPGradientVectorSelector *gvs)
370 {
371 /* Disconnect gradient */
372 if (gvs->gr) {
373 gvs->gradient_release_connection.disconnect();
374 gvs->gr = NULL;
375 }
377 /* Rebuild GUI */
378 sp_gvs_rebuild_gui_full(gvs);
379 }
381 static void 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 sp_gvs_defs_modified(SPObject */*defs*/, guint /*flags*/, SPGradientVectorSelector *gvs)
399 {
400 /* fixme: We probably have to check some flags here (Lauris) */
402 sp_gvs_rebuild_gui_full(gvs);
403 }
405 /*##################################################################
406 ### Vector Editing Widget
407 ##################################################################*/
409 #include "../widgets/sp-color-notebook.h"
410 #include "../widgets/sp-color-preview.h"
411 #include "../widgets/widget-sizes.h"
412 #include "../xml/node-event-vector.h"
413 #include "../svg/svg-color.h"
416 #define PAD 4
418 static GtkWidget *sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *stop);
420 static void sp_gradient_vector_widget_load_gradient(GtkWidget *widget, SPGradient *gradient);
421 static gint sp_gradient_vector_dialog_delete(GtkWidget *widget, GdkEvent *event, GtkWidget *dialog);
422 static void sp_gradient_vector_dialog_destroy(GtkObject *object, gpointer data);
424 static void sp_gradient_vector_widget_destroy(GtkObject *object, gpointer data);
425 static void sp_gradient_vector_gradient_release(SPObject *obj, GtkWidget *widget);
426 static void sp_gradient_vector_gradient_modified(SPObject *obj, guint flags, GtkWidget *widget);
427 static void sp_gradient_vector_color_dragged(SPColorSelector *csel, GtkObject *object);
428 static void sp_gradient_vector_color_changed(SPColorSelector *csel, GtkObject *object);
429 static void update_stop_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_stop);
431 static gboolean blocked = FALSE;
433 static void grad_edit_dia_stop_added_or_removed(Inkscape::XML::Node */*repr*/, Inkscape::XML::Node */*child*/, Inkscape::XML::Node */*ref*/, gpointer data)
434 {
435 GtkWidget *vb = GTK_WIDGET(data);
436 GtkWidget *mnu = (GtkWidget *)g_object_get_data(G_OBJECT(vb), "stopmenu");
437 SPGradient *gradient = (SPGradient *)g_object_get_data(G_OBJECT(vb), "gradient");
438 update_stop_list(mnu, gradient, NULL);
439 }
441 //FIXME!!! We must also listen to attr changes on all children (i.e. stops) too,
442 //otherwise the dialog does not reflect undoing color or offset change. This is a major
443 //hassle, unless we have a "one of the descendants changed in some way" signal.
444 static Inkscape::XML::NodeEventVector grad_edit_dia_repr_events =
445 {
446 grad_edit_dia_stop_added_or_removed, /* child_added */
447 grad_edit_dia_stop_added_or_removed, /* child_removed */
448 NULL, /* attr_changed*/
449 NULL, /* content_changed */
450 NULL /* order_changed */
451 };
453 static void verify_grad(SPGradient *gradient)
454 {
455 int i = 0;
456 SPStop *stop = NULL;
457 /* count stops */
458 for ( SPObject *ochild = sp_object_first_child(SP_OBJECT(gradient)) ; ochild != NULL ; ochild = SP_OBJECT_NEXT(ochild) ) {
459 if (SP_IS_STOP(ochild)) {
460 i++;
461 stop = SP_STOP(ochild);
462 }
463 }
465 Inkscape::XML::Document *xml_doc;
466 xml_doc = SP_OBJECT_REPR(gradient)->document();
468 if (i < 1) {
469 gchar c[64];
470 sp_svg_write_color(c, sizeof(c), 0x00000000);
472 Inkscape::CSSOStringStream os;
473 os << "stop-color:" << c << ";stop-opacity:" << 1.0 << ";";
475 Inkscape::XML::Node *child;
477 child = xml_doc->createElement("svg:stop");
478 sp_repr_set_css_double(child, "offset", 0.0);
479 child->setAttribute("style", os.str().c_str());
480 SP_OBJECT_REPR(gradient)->addChild(child, NULL);
481 Inkscape::GC::release(child);
483 child = xml_doc->createElement("svg:stop");
484 sp_repr_set_css_double(child, "offset", 1.0);
485 child->setAttribute("style", os.str().c_str());
486 SP_OBJECT_REPR(gradient)->addChild(child, NULL);
487 Inkscape::GC::release(child);
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 Inkscape::GC::release(child);
495 }
496 }
498 static void 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 update_stop_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_stop)
513 {
515 if (!SP_IS_GRADIENT(gradient)) {
516 return;
517 }
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 sp_grad_edit_select(GtkOptionMenu *mnu, GtkWidget *tbl)
585 {
586 SPGradient *gradient = (SPGradient *)g_object_get_data(G_OBJECT(tbl), "gradient");
588 GObject *item = G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu))));
589 SPStop *stop = SP_STOP(g_object_get_data(item, "stop"));
590 if (!stop) {
591 return;
592 }
594 blocked = TRUE;
596 SPColorSelector *csel = (SPColorSelector*)g_object_get_data(G_OBJECT(tbl), "cselector");
597 guint32 const c = sp_stop_get_rgba32(stop);
598 csel->base->setAlpha(SP_RGBA32_A_F(c));
599 SPColor 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 = static_cast<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 offadjustmentChanged( GtkAdjustment *adjustment, GtkWidget *vb)
647 {
648 if (blocked) {
649 return;
650 }
652 blocked = TRUE;
654 GtkOptionMenu *mnu = static_cast<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")) {
656 return;
657 }
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;
667 }
669 guint32 sp_average_color(guint32 c1, guint32 c2, gdouble p = 0.5)
670 {
671 guint32 r = (guint32) (SP_RGBA32_R_U(c1) * p + SP_RGBA32_R_U(c2) * (1 - p));
672 guint32 g = (guint32) (SP_RGBA32_G_U(c1) * p + SP_RGBA32_G_U(c2) * (1 - p));
673 guint32 b = (guint32) (SP_RGBA32_B_U(c1) * p + SP_RGBA32_B_U(c2) * (1 - p));
674 guint32 a = (guint32) (SP_RGBA32_A_U(c1) * p + SP_RGBA32_A_U(c2) * (1 - p));
676 return SP_RGBA32_U_COMPOSE(r, g, b, a);
677 }
680 static void sp_grd_ed_add_stop(GtkWidget */*widget*/, GtkWidget *vb)
681 {
682 SPGradient *gradient = static_cast<SPGradient *>(g_object_get_data(G_OBJECT(vb), "gradient"));
683 verify_grad(gradient);
684 GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(vb), "stopmenu"));
686 SPStop *stop = static_cast<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;
690 }
692 Inkscape::XML::Node *new_stop_repr = NULL;
694 SPStop *next = sp_next_stop(stop);
696 if (next == NULL) {
697 SPStop *prev = sp_prev_stop(stop, gradient);
698 if (prev != NULL) {
699 next = stop;
700 stop = prev;
701 }
702 }
704 if (next != NULL) {
705 new_stop_repr = SP_OBJECT_REPR(stop)->duplicate(SP_OBJECT_REPR(gradient)->document());
706 SP_OBJECT_REPR(gradient)->addChild(new_stop_repr, SP_OBJECT_REPR(stop));
707 } else {
708 next = stop;
709 new_stop_repr = SP_OBJECT_REPR(sp_prev_stop(stop, gradient))->duplicate(SP_OBJECT_REPR(gradient)->document());
710 SP_OBJECT_REPR(gradient)->addChild(new_stop_repr, SP_OBJECT_REPR(sp_prev_stop(stop, gradient)));
711 }
713 SPStop *newstop = (SPStop *) SP_OBJECT_DOCUMENT(gradient)->getObjectByRepr(new_stop_repr);
715 newstop->offset = (stop->offset + next->offset) * 0.5 ;
717 guint32 const c1 = sp_stop_get_rgba32(stop);
718 guint32 const c2 = sp_stop_get_rgba32(next);
719 guint32 cnew = sp_average_color(c1, c2);
721 Inkscape::CSSOStringStream os;
722 gchar c[64];
723 sp_svg_write_color(c, sizeof(c), cnew);
724 gdouble opacity = static_cast<gdouble>(SP_RGBA32_A_F(cnew));
725 os << "stop-color:" << c << ";stop-opacity:" << opacity <<";";
726 SP_OBJECT_REPR (newstop)->setAttribute("style", os.str().c_str());
727 sp_repr_set_css_double( SP_OBJECT_REPR(newstop), "offset", (double)newstop->offset);
729 sp_gradient_vector_widget_load_gradient(vb, gradient);
730 Inkscape::GC::release(new_stop_repr);
731 update_stop_list(GTK_WIDGET(mnu), gradient, newstop);
732 GtkWidget *offspin = GTK_WIDGET(g_object_get_data(G_OBJECT(vb), "offspn"));
733 GtkWidget *offslide =GTK_WIDGET(g_object_get_data(G_OBJECT(vb), "offslide"));
734 gtk_widget_set_sensitive(offslide, TRUE);
735 gtk_widget_set_sensitive(GTK_WIDGET(offspin), TRUE);
736 sp_document_done(SP_OBJECT_DOCUMENT(gradient), SP_VERB_CONTEXT_GRADIENT,
737 _("Add gradient stop"));
738 }
740 static void sp_grd_ed_del_stop(GtkWidget */*widget*/, GtkWidget *vb)
741 {
742 SPGradient *gradient = static_cast<SPGradient *>(g_object_get_data(G_OBJECT(vb), "gradient"));
744 GtkOptionMenu *mnu = static_cast<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 * sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *select_stop)
774 {
775 GtkWidget *vb, *w, *f, *csel;
777 g_return_val_if_fail(!gradient || SP_IS_GRADIENT(gradient), NULL);
779 vb = gtk_vbox_new(FALSE, PAD);
780 g_signal_connect(G_OBJECT(vb), "destroy", G_CALLBACK(sp_gradient_vector_widget_destroy), NULL);
782 w = sp_gradient_image_new(gradient);
783 g_object_set_data(G_OBJECT(vb), "preview", w);
784 gtk_widget_show(w);
785 gtk_box_pack_start(GTK_BOX(vb), w, TRUE, TRUE, PAD);
787 sp_repr_add_listener(SP_OBJECT_REPR(gradient), &grad_edit_dia_repr_events, vb);
788 GtkTooltips *tt = gtk_tooltips_new();
790 /* Stop list */
791 GtkWidget *mnu = gtk_option_menu_new();
792 /* Create new menu widget */
793 update_stop_list(GTK_WIDGET(mnu), gradient, NULL);
794 gtk_signal_connect(GTK_OBJECT(mnu), "changed", GTK_SIGNAL_FUNC(sp_grad_edit_select), vb);
795 gtk_widget_show(mnu);
796 gtk_object_set_data(GTK_OBJECT(vb), "stopmenu", mnu);
797 gtk_box_pack_start(GTK_BOX(vb), mnu, FALSE, FALSE, 0);
799 /* Add and Remove buttons */
800 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
801 // TRANSLATORS: "Stop" means: a "phase" of a gradient
802 GtkWidget *b = gtk_button_new_with_label(_("Add stop"));
803 gtk_widget_show(b);
804 gtk_container_add(GTK_CONTAINER(hb), b);
805 gtk_tooltips_set_tip(tt, b, _("Add another control stop to gradient"), NULL);
806 gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_grd_ed_add_stop), vb);
807 b = gtk_button_new_with_label(_("Delete stop"));
808 gtk_widget_show(b);
809 gtk_container_add(GTK_CONTAINER(hb), b);
810 gtk_tooltips_set_tip(tt, b, _("Delete current control stop from gradient"), NULL);
811 gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_grd_ed_del_stop), vb);
813 gtk_widget_show(hb);
814 gtk_box_pack_start(GTK_BOX(vb),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
817 /* Offset Slider and stuff */
818 hb = gtk_hbox_new(FALSE, 0);
820 /* Label */
821 GtkWidget *l = gtk_label_new(_("Offset:"));
822 gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
823 gtk_box_pack_start(GTK_BOX(hb),l, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
824 gtk_widget_show(l);
826 /* Adjustment */
827 GtkAdjustment *Offset_adj = NULL;
828 Offset_adj= (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 0.01, 0.01, 0.0);
829 gtk_object_set_data(GTK_OBJECT(vb), "offset", Offset_adj);
830 GtkMenu *m = GTK_MENU(gtk_option_menu_get_menu(GTK_OPTION_MENU(mnu)));
831 SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(m)), "stop"));
832 gtk_adjustment_set_value(Offset_adj, stop->offset);
834 /* Slider */
835 GtkWidget *slider = gtk_hscale_new(Offset_adj);
836 gtk_scale_set_draw_value( GTK_SCALE(slider), FALSE );
837 gtk_widget_show(slider);
838 gtk_box_pack_start(GTK_BOX(hb),slider, TRUE, TRUE, AUX_BETWEEN_BUTTON_GROUPS);
839 gtk_object_set_data(GTK_OBJECT(vb), "offslide", slider);
841 /* Spinbutton */
842 GtkWidget *sbtn = gtk_spin_button_new(GTK_ADJUSTMENT(Offset_adj), 0.01, 2);
843 sp_dialog_defocus_on_enter(sbtn);
844 gtk_widget_show(sbtn);
845 gtk_box_pack_start(GTK_BOX(hb),sbtn, FALSE, TRUE, AUX_BETWEEN_BUTTON_GROUPS);
846 gtk_object_set_data(GTK_OBJECT(vb), "offspn", sbtn);
848 if (stop->offset>0 && stop->offset<1) {
849 gtk_widget_set_sensitive(slider, TRUE);
850 gtk_widget_set_sensitive(GTK_WIDGET(sbtn), TRUE);
851 } else {
852 gtk_widget_set_sensitive(slider, FALSE);
853 gtk_widget_set_sensitive(GTK_WIDGET(sbtn), FALSE);
854 }
857 /* Signals */
858 gtk_signal_connect(GTK_OBJECT(Offset_adj), "value_changed",
859 GTK_SIGNAL_FUNC(offadjustmentChanged), vb);
861 // gtk_signal_connect(GTK_OBJECT(slider), "changed", GTK_SIGNAL_FUNC(offsliderChanged), vb);
862 gtk_widget_show(hb);
863 gtk_box_pack_start(GTK_BOX(vb), hb, FALSE, FALSE, PAD);
865 // TRANSLATORS: "Stop" means: a "phase" of a gradient
866 f = gtk_frame_new(_("Stop Color"));
867 gtk_widget_show(f);
868 gtk_box_pack_start(GTK_BOX(vb), f, TRUE, TRUE, PAD);
869 csel = static_cast<GtkWidget*>(sp_color_selector_new(SP_TYPE_COLOR_NOTEBOOK));
870 g_object_set_data(G_OBJECT(vb), "cselector", csel);
871 gtk_widget_show(csel);
872 gtk_container_add(GTK_CONTAINER(f), csel);
873 g_signal_connect(G_OBJECT(csel), "dragged", G_CALLBACK(sp_gradient_vector_color_dragged), vb);
874 g_signal_connect(G_OBJECT(csel), "changed", G_CALLBACK(sp_gradient_vector_color_changed), vb);
876 gtk_widget_show(vb);
878 sp_gradient_vector_widget_load_gradient(vb, gradient);
880 if (select_stop) {
881 select_stop_in_list(GTK_WIDGET(mnu), gradient, select_stop);
882 }
884 return vb;
885 }
889 GtkWidget * sp_gradient_vector_editor_new(SPGradient *gradient, SPStop *stop)
890 {
891 GtkWidget *wid;
893 if (dlg == NULL) {
894 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
896 dlg = sp_window_new(_("Gradient editor"), TRUE);
897 if (x == -1000 || y == -1000) {
898 x = prefs->getInt(prefs_path + "x", -1000);
899 y = prefs->getInt(prefs_path + "y", -1000);
900 }
901 if (w ==0 || h == 0) {
902 w = prefs->getInt(prefs_path + "w", 0);
903 h = prefs->getInt(prefs_path + "h", 0);
904 }
906 if (x<0) {
907 x=0;
908 }
909 if (y<0) {
910 y=0;
911 }
913 if (x != 0 || y != 0) {
914 gtk_window_move(reinterpret_cast<GtkWindow *>(dlg), x, y);
915 } else {
916 gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
917 }
918 if (w && h) {
919 gtk_window_resize(reinterpret_cast<GtkWindow *>(dlg), w, h);
920 }
921 sp_transientize(dlg);
922 wd.win = dlg;
923 wd.stop = 0;
924 g_signal_connect(G_OBJECT(INKSCAPE), "activate_desktop", G_CALLBACK(sp_transientize_callback), &wd);
925 gtk_signal_connect(GTK_OBJECT(dlg), "event", GTK_SIGNAL_FUNC(sp_dialog_event_handler), dlg);
926 gtk_signal_connect(GTK_OBJECT(dlg), "destroy", G_CALLBACK(sp_gradient_vector_dialog_destroy), dlg);
927 gtk_signal_connect(GTK_OBJECT(dlg), "delete_event", G_CALLBACK(sp_gradient_vector_dialog_delete), dlg);
928 g_signal_connect(G_OBJECT(INKSCAPE), "shut_down", G_CALLBACK(sp_gradient_vector_dialog_delete), dlg);
929 g_signal_connect( G_OBJECT(INKSCAPE), "dialogs_hide", G_CALLBACK(sp_dialog_hide), dlg );
930 g_signal_connect( G_OBJECT(INKSCAPE), "dialogs_unhide", G_CALLBACK(sp_dialog_unhide), dlg );
932 gtk_container_set_border_width(GTK_CONTAINER(dlg), PAD);
934 wid = static_cast<GtkWidget*>(sp_gradient_vector_widget_new(gradient, stop));
935 g_object_set_data(G_OBJECT(dlg), "gradient-vector-widget", wid);
936 /* Connect signals */
937 gtk_widget_show(wid);
938 gtk_container_add(GTK_CONTAINER(dlg), wid);
939 } else {
940 // FIXME: temp fix for 0.38
941 // Simply load_gradient into the editor does not work for multi-stop gradients,
942 // as the stop list and other widgets are in a wrong state and crash readily.
943 // Instead we just delete the window (by sending the delete signal)
944 // and call sp_gradient_vector_editor_new again, so it creates the window anew.
946 GdkEventAny event;
947 GtkWidget *widget = static_cast<GtkWidget *>(dlg);
948 event.type = GDK_DELETE;
949 event.window = widget->window;
950 event.send_event = TRUE;
951 g_object_ref(G_OBJECT(event.window));
952 gtk_main_do_event(reinterpret_cast<GdkEvent*>(&event));
953 g_object_unref(G_OBJECT(event.window));
955 g_assert(dlg == NULL);
956 sp_gradient_vector_editor_new(gradient, stop);
957 }
959 return dlg;
960 }
962 static void sp_gradient_vector_widget_load_gradient(GtkWidget *widget, SPGradient *gradient)
963 {
964 blocked = TRUE;
966 SPGradient *old;
968 old = (SPGradient*)g_object_get_data(G_OBJECT(widget), "gradient");
970 if (old != gradient) {
971 sigc::connection *release_connection;
972 sigc::connection *modified_connection;
974 release_connection = (sigc::connection *)g_object_get_data(G_OBJECT(widget), "gradient_release_connection");
975 modified_connection = (sigc::connection *)g_object_get_data(G_OBJECT(widget), "gradient_modified_connection");
977 if (old) {
978 g_assert( release_connection != NULL );
979 g_assert( modified_connection != NULL );
980 release_connection->disconnect();
981 modified_connection->disconnect();
982 sp_signal_disconnect_by_data(old, widget);
983 }
985 if (gradient) {
986 if (!release_connection) {
987 release_connection = new sigc::connection();
988 }
989 if (!modified_connection) {
990 modified_connection = new sigc::connection();
991 }
992 *release_connection = gradient->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gradient_vector_gradient_release), widget));
993 *modified_connection = gradient->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_gradient_vector_gradient_modified), widget));
994 } else {
995 if (release_connection) {
996 delete release_connection;
997 release_connection = NULL;
998 }
999 if (modified_connection) {
1000 delete modified_connection;
1001 modified_connection = NULL;
1002 }
1003 }
1005 g_object_set_data(G_OBJECT(widget), "gradient_release_connection", release_connection);
1006 g_object_set_data(G_OBJECT(widget), "gradient_modified_connection", modified_connection);
1007 }
1009 g_object_set_data(G_OBJECT(widget), "gradient", gradient);
1011 if (gradient) {
1012 gtk_widget_set_sensitive(widget, TRUE);
1014 sp_gradient_ensure_vector(gradient);
1016 GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(widget), "stopmenu"));
1017 SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop"));
1018 guint32 const c = sp_stop_get_rgba32(stop);
1020 /// get the color selector
1021 SPColorSelector *csel = SP_COLOR_SELECTOR(g_object_get_data(G_OBJECT(widget), "cselector"));
1022 // set alpha
1023 csel->base->setAlpha(SP_RGBA32_A_F(c));
1024 SPColor color( SP_RGBA32_R_F(c), SP_RGBA32_G_F(c), SP_RGBA32_B_F(c) );
1025 // set color
1026 csel->base->setColor( color );
1028 /* Fill preview */
1029 GtkWidget *w = static_cast<GtkWidget *>(g_object_get_data(G_OBJECT(widget), "preview"));
1030 sp_gradient_image_set_gradient(SP_GRADIENT_IMAGE(w), gradient);
1032 update_stop_list(GTK_WIDGET(mnu), gradient, NULL);
1034 // Once the user edits a gradient, it stops being auto-collectable
1035 if (SP_OBJECT_REPR(gradient)->attribute("inkscape:collect")) {
1036 SPDocument *document = SP_OBJECT_DOCUMENT(gradient);
1037 bool saved = sp_document_get_undo_sensitive(document);
1038 sp_document_set_undo_sensitive(document, false);
1039 SP_OBJECT_REPR(gradient)->setAttribute("inkscape:collect", NULL);
1040 sp_document_set_undo_sensitive(document, saved);
1041 }
1042 } else { // no gradient, disable everything
1043 gtk_widget_set_sensitive(widget, FALSE);
1044 }
1046 blocked = FALSE;
1047 }
1049 static void sp_gradient_vector_dialog_destroy(GtkObject */*object*/, gpointer /*data*/)
1050 {
1051 sp_signal_disconnect_by_data(INKSCAPE, dlg);
1052 wd.win = dlg = NULL;
1053 wd.stop = 0;
1054 }
1056 static gboolean sp_gradient_vector_dialog_delete(GtkWidget */*widget*/, GdkEvent */*event*/, GtkWidget */*dialog*/)
1057 {
1058 gtk_window_get_position(GTK_WINDOW(dlg), &x, &y);
1059 gtk_window_get_size(GTK_WINDOW(dlg), &w, &h);
1061 if (x<0) {
1062 x=0;
1063 }
1064 if (y<0) {
1065 y=0;
1066 }
1068 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1069 prefs->setInt(prefs_path + "x", x);
1070 prefs->setInt(prefs_path + "y", y);
1071 prefs->setInt(prefs_path + "w", w);
1072 prefs->setInt(prefs_path + "h", h);
1074 return FALSE; // which means, go ahead and destroy it
1075 }
1077 /* Widget destroy handler */
1079 static void sp_gradient_vector_widget_destroy(GtkObject *object, gpointer /*data*/)
1080 {
1081 GObject *gradient;
1083 gradient = (GObject*)g_object_get_data(G_OBJECT(object), "gradient");
1085 sigc::connection *release_connection = (sigc::connection *)g_object_get_data(G_OBJECT(object), "gradient_release_connection");
1086 sigc::connection *modified_connection = (sigc::connection *)g_object_get_data(G_OBJECT(object), "gradient_modified_connection");
1088 if (gradient) {
1089 g_assert( release_connection != NULL );
1090 g_assert( modified_connection != NULL );
1091 release_connection->disconnect();
1092 modified_connection->disconnect();
1093 sp_signal_disconnect_by_data(gradient, object);
1094 }
1096 if (gradient && SP_OBJECT_REPR(gradient)) {
1097 sp_repr_remove_listener_by_data(SP_OBJECT_REPR(gradient), object);
1098 }
1099 }
1101 static void sp_gradient_vector_gradient_release(SPObject */*object*/, GtkWidget *widget)
1102 {
1103 sp_gradient_vector_widget_load_gradient(widget, NULL);
1104 }
1106 static void sp_gradient_vector_gradient_modified(SPObject *object, guint /*flags*/, GtkWidget *widget)
1107 {
1108 SPGradient *gradient=SP_GRADIENT(object);
1109 if (!blocked) {
1110 blocked = TRUE;
1111 sp_gradient_vector_widget_load_gradient(widget, gradient);
1112 blocked = FALSE;
1113 }
1114 }
1116 static void sp_gradient_vector_color_dragged(SPColorSelector *csel, GtkObject *object)
1117 {
1118 SPGradient *gradient, *ngr;
1120 if (blocked) {
1121 return;
1122 }
1124 gradient = static_cast<SPGradient*>(g_object_get_data(G_OBJECT(object), "gradient"));
1125 if (!gradient) {
1126 return;
1127 }
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 = static_cast<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 sp_gradient_vector_color_changed(SPColorSelector *csel, GtkObject *object)
1150 {
1151 SPColor color;
1152 float alpha;
1153 guint32 rgb;
1155 if (blocked) {
1156 return;
1157 }
1159 SPGradient *gradient = static_cast<SPGradient*>(g_object_get_data(G_OBJECT(object), "gradient"));
1160 if (!gradient) {
1161 return;
1162 }
1164 blocked = TRUE;
1166 SPGradient *ngr = sp_gradient_ensure_vector_normalized(gradient);
1167 if (ngr != gradient) {
1168 /* Our master gradient has changed */
1169 sp_gradient_vector_widget_load_gradient(GTK_WIDGET(object), ngr);
1170 }
1172 sp_gradient_ensure_vector(ngr);
1174 /* Set start parameters */
1175 /* We rely on normalized vector, i.e. stops HAVE to exist */
1176 g_return_if_fail(ngr->getFirstStop() != NULL);
1178 GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(object), "stopmenu"));
1179 SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop"));
1181 csel = static_cast<SPColorSelector*>(g_object_get_data(G_OBJECT(object), "cselector"));
1182 csel->base->getColorAlpha( color, &alpha );
1183 rgb = color.toRGBA32( 0x00 );
1185 sp_repr_set_css_double(SP_OBJECT_REPR(stop), "offset", stop->offset);
1186 Inkscape::CSSOStringStream os;
1187 gchar c[64];
1188 sp_svg_write_color(c, sizeof(c), rgb);
1189 os << "stop-color:" << c << ";stop-opacity:" << static_cast<gdouble>(alpha) <<";";
1190 SP_OBJECT_REPR(stop)->setAttribute("style", os.str().c_str());
1191 // g_snprintf(c, 256, "stop-color:#%06x;stop-opacity:%g;", rgb >> 8, static_cast<gdouble>(alpha));
1192 //SP_OBJECT_REPR(stop)->setAttribute("style", c);
1194 sp_document_done(SP_OBJECT_DOCUMENT(ngr), SP_VERB_CONTEXT_GRADIENT,
1195 _("Change gradient stop color"));
1197 blocked = FALSE;
1199 SPColorPreview *cpv = static_cast<SPColorPreview *>(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "preview"));
1200 sp_color_preview_set_rgba32(cpv, sp_stop_get_rgba32(stop));
1201 }
1203 /*
1204 Local Variables:
1205 mode:c++
1206 c-file-style:"stroustrup"
1207 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1208 indent-tabs-mode:nil
1209 fill-column:99
1210 End:
1211 */
1212 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :