c49d9e06f0685427023ec6d585f5927c7d65a8a0
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->swatched = false;
121 gvs->doc = NULL;
122 gvs->gr = NULL;
124 new (&gvs->gradient_release_connection) sigc::connection();
125 new (&gvs->defs_release_connection) sigc::connection();
126 new (&gvs->defs_modified_connection) sigc::connection();
128 gvs->menu = gtk_option_menu_new();
129 gtk_widget_show(gvs->menu);
130 gtk_box_pack_start(GTK_BOX(gvs), gvs->menu, TRUE, TRUE, 0);
131 }
133 static void sp_gradient_vector_selector_destroy(GtkObject *object)
134 {
135 SPGradientVectorSelector *gvs = SP_GRADIENT_VECTOR_SELECTOR(object);
137 if (gvs->gr) {
138 gvs->gradient_release_connection.disconnect();
139 gvs->gr = NULL;
140 }
142 if (gvs->doc) {
143 gvs->defs_release_connection.disconnect();
144 gvs->defs_modified_connection.disconnect();
145 gvs->doc = NULL;
146 }
148 gvs->gradient_release_connection.~connection();
149 gvs->defs_release_connection.~connection();
150 gvs->defs_modified_connection.~connection();
152 if ((reinterpret_cast<GtkObjectClass *>(parent_class))->destroy) {
153 (* (reinterpret_cast<GtkObjectClass *>(parent_class))->destroy) (object);
154 }
155 }
157 GtkWidget *sp_gradient_vector_selector_new(SPDocument *doc, SPGradient *gr)
158 {
159 GtkWidget *gvs;
161 g_return_val_if_fail(!gr || SP_IS_GRADIENT(gr), NULL);
162 g_return_val_if_fail(!gr || (SP_OBJECT_DOCUMENT(gr) == doc), NULL);
164 gvs = static_cast<GtkWidget*>(gtk_type_new(SP_TYPE_GRADIENT_VECTOR_SELECTOR));
166 if (doc) {
167 sp_gradient_vector_selector_set_gradient(SP_GRADIENT_VECTOR_SELECTOR(gvs), doc, gr);
168 } else {
169 sp_gvs_rebuild_gui_full(SP_GRADIENT_VECTOR_SELECTOR(gvs));
170 }
172 return gvs;
173 }
175 void sp_gradient_vector_selector_set_gradient(SPGradientVectorSelector *gvs, SPDocument *doc, SPGradient *gr)
176 {
177 // g_message("sp_gradient_vector_selector_set_gradient(%p, %p, %p) [%s] %d %d", gvs, doc, gr,
178 // (gr ? gr->getId():"N/A"),
179 // (gr ? gr->isSwatch() : -1),
180 // (gr ? gr->isSolid() : -1));
181 static gboolean suppress = FALSE;
183 g_return_if_fail(gvs != NULL);
184 g_return_if_fail(SP_IS_GRADIENT_VECTOR_SELECTOR(gvs));
185 g_return_if_fail(!gr || (doc != NULL));
186 g_return_if_fail(!gr || SP_IS_GRADIENT(gr));
187 g_return_if_fail(!gr || (SP_OBJECT_DOCUMENT(gr) == doc));
188 g_return_if_fail(!gr || gr->hasStops());
190 if (doc != gvs->doc) {
191 /* Disconnect signals */
192 if (gvs->gr) {
193 gvs->gradient_release_connection.disconnect();
194 gvs->gr = NULL;
195 }
196 if (gvs->doc) {
197 gvs->defs_release_connection.disconnect();
198 gvs->defs_modified_connection.disconnect();
199 gvs->doc = NULL;
200 }
202 // Connect signals
203 if (doc) {
204 gvs->defs_release_connection = SP_DOCUMENT_DEFS(doc)->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gvs_defs_release), gvs));
205 gvs->defs_modified_connection = SP_DOCUMENT_DEFS(doc)->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_gvs_defs_modified), gvs));
206 }
207 if (gr) {
208 gvs->gradient_release_connection = gr->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gvs_gradient_release), gvs));
209 }
210 gvs->doc = doc;
211 gvs->gr = gr;
212 sp_gvs_rebuild_gui_full(gvs);
213 if (!suppress) g_signal_emit(G_OBJECT(gvs), signals[VECTOR_SET], 0, gr);
214 } else if (gr != gvs->gr) {
215 // Harder case - keep document, rebuild menus and stuff
216 // fixme: (Lauris)
217 suppress = TRUE;
218 sp_gradient_vector_selector_set_gradient(gvs, NULL, NULL);
219 sp_gradient_vector_selector_set_gradient(gvs, doc, gr);
220 suppress = FALSE;
221 g_signal_emit(G_OBJECT(gvs), signals[VECTOR_SET], 0, gr);
222 }
223 /* The case of setting NULL -> NULL is not very interesting */
224 }
226 SPDocument *sp_gradient_vector_selector_get_document(SPGradientVectorSelector *gvs)
227 {
228 g_return_val_if_fail(gvs != NULL, NULL);
229 g_return_val_if_fail(SP_IS_GRADIENT_VECTOR_SELECTOR(gvs), NULL);
231 return gvs->doc;
232 }
234 SPGradient *sp_gradient_vector_selector_get_gradient(SPGradientVectorSelector *gvs)
235 {
236 g_return_val_if_fail(gvs != NULL, NULL);
237 g_return_val_if_fail(SP_IS_GRADIENT_VECTOR_SELECTOR(gvs), NULL);
239 return gvs->gr;
240 }
242 static void 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 *curr = gradients; curr; curr = curr->next) {
258 SPGradient* grad = SP_GRADIENT(curr->data);
259 if ( grad->hasStops() && (grad->isSwatch() == gvs->swatched) ) {
260 gl = g_slist_prepend(gl, curr->data);
261 }
262 }
263 }
264 gl = g_slist_reverse(gl);
266 gint pos = 0;
267 gint idx = 0;
269 if (!gvs->doc) {
270 GtkWidget *i;
271 i = gtk_menu_item_new_with_label(_("No document selected"));
272 gtk_widget_show(i);
273 gtk_menu_append(GTK_MENU(m), i);
274 gtk_widget_set_sensitive(gvs->menu, FALSE);
275 } else if (!gl) {
276 GtkWidget *i;
277 i = gtk_menu_item_new_with_label(_("No gradients in document"));
278 gtk_widget_show(i);
279 gtk_menu_append(GTK_MENU(m), i);
280 gtk_widget_set_sensitive(gvs->menu, FALSE);
281 } else if (!gvs->gr) {
282 GtkWidget *i;
283 i = gtk_menu_item_new_with_label(_("No gradient selected"));
284 gtk_widget_show(i);
285 gtk_menu_append(GTK_MENU(m), i);
286 gtk_widget_set_sensitive(gvs->menu, FALSE);
287 } else {
288 while (gl) {
289 SPGradient *gr;
290 GtkWidget *i, *w;
291 gr = SP_GRADIENT(gl->data);
292 gl = g_slist_remove(gl, gr);
294 /* We have to know: */
295 /* Gradient destroy */
296 /* Gradient name change */
297 i = gtk_menu_item_new();
298 gtk_widget_show(i);
299 g_object_set_data(G_OBJECT(i), "gradient", gr);
300 g_signal_connect(G_OBJECT(i), "activate", G_CALLBACK(sp_gvs_gradient_activate), gvs);
302 w = sp_gradient_image_new(gr);
303 gtk_widget_show(w);
305 if (gvs->idlabel) {
306 GtkWidget *hb, *l;
307 hb = gtk_hbox_new(FALSE, 4);
308 gtk_widget_show(hb);
309 l = gtk_label_new(gr->getId());
310 gtk_widget_show(l);
311 gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
312 gtk_box_pack_start(GTK_BOX(hb), l, TRUE, TRUE, 0);
313 gtk_box_pack_start(GTK_BOX(hb), w, FALSE, FALSE, 0);
314 w = hb;
315 }
317 gtk_container_add(GTK_CONTAINER(i), w);
319 gtk_menu_append(GTK_MENU(m), i);
321 if (gr == gvs->gr) {
322 pos = idx;
323 }
324 idx += 1;
325 }
326 gtk_widget_set_sensitive(gvs->menu, TRUE);
327 }
329 gtk_option_menu_set_menu(GTK_OPTION_MENU(gvs->menu), m);
330 /* Set history */
331 gtk_option_menu_set_history(GTK_OPTION_MENU(gvs->menu), pos);
332 }
334 static void sp_gvs_gradient_activate(GtkMenuItem *mi, SPGradientVectorSelector *gvs)
335 {
336 SPGradient *gr, *norm;
338 gr = (SPGradient*)g_object_get_data(G_OBJECT(mi), "gradient");
339 /* Hmmm... bad things may happen here, if actual gradient is something new */
340 /* Namely - menuitems etc. will be fucked up */
341 /* Hmmm - probably we can just re-set it as menuitem data (Lauris) */
343 //g_print("SPGradientVectorSelector: gradient %s activated\n", SP_OBJECT_ID(gr));
344 //g_message("Setting to gradient %p swatch:%d solid:%d", gr, gr->isSwatch(), gr->isSolid());
346 norm = sp_gradient_ensure_vector_normalized(gr);
347 if (norm != gr) {
348 //g_print("SPGradientVectorSelector: become %s after normalization\n", SP_OBJECT_ID(norm));
349 /* But be careful that we do not have gradient saved anywhere else */
350 g_object_set_data(G_OBJECT(mi), "gradient", norm);
351 }
353 /* fixme: Really we would want to use _set_vector */
354 /* Detach old */
355 if (gvs->gr) {
356 gvs->gradient_release_connection.disconnect();
357 gvs->gr = NULL;
358 }
359 /* Attach new */
360 if (norm) {
361 gvs->gradient_release_connection = norm->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gvs_gradient_release), gvs));
362 gvs->gr = norm;
363 }
365 g_signal_emit(G_OBJECT(gvs), signals[VECTOR_SET], 0, norm);
367 if (norm != gr) {
368 /* We do extra undo push here */
369 /* If handler has already done it, it is just NOP */
370 // FIXME: looks like this is never a valid undo step, consider removing this
371 sp_document_done(SP_OBJECT_DOCUMENT(norm), SP_VERB_CONTEXT_GRADIENT,
372 /* TODO: annotate */ "gradient-vector.cpp:350");
373 }
374 }
376 static void sp_gvs_gradient_release(SPObject */*obj*/, SPGradientVectorSelector *gvs)
377 {
378 /* Disconnect gradient */
379 if (gvs->gr) {
380 gvs->gradient_release_connection.disconnect();
381 gvs->gr = NULL;
382 }
384 /* Rebuild GUI */
385 sp_gvs_rebuild_gui_full(gvs);
386 }
388 static void sp_gvs_defs_release(SPObject */*defs*/, SPGradientVectorSelector *gvs)
389 {
390 gvs->doc = NULL;
392 gvs->defs_release_connection.disconnect();
393 gvs->defs_modified_connection.disconnect();
395 /* Disconnect gradient as well */
396 if (gvs->gr) {
397 gvs->gradient_release_connection.disconnect();
398 gvs->gr = NULL;
399 }
401 /* Rebuild GUI */
402 sp_gvs_rebuild_gui_full(gvs);
403 }
405 static void 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 void SPGradientVectorSelector::setSwatched()
413 {
414 swatched = true;
415 sp_gvs_rebuild_gui_full(this);
416 }
418 /*##################################################################
419 ### Vector Editing Widget
420 ##################################################################*/
422 #include "../widgets/sp-color-notebook.h"
423 #include "../widgets/sp-color-preview.h"
424 #include "../widgets/widget-sizes.h"
425 #include "../xml/node-event-vector.h"
426 #include "../svg/svg-color.h"
429 #define PAD 4
431 static GtkWidget *sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *stop);
433 static void sp_gradient_vector_widget_load_gradient(GtkWidget *widget, SPGradient *gradient);
434 static gint sp_gradient_vector_dialog_delete(GtkWidget *widget, GdkEvent *event, GtkWidget *dialog);
435 static void sp_gradient_vector_dialog_destroy(GtkObject *object, gpointer data);
437 static void sp_gradient_vector_widget_destroy(GtkObject *object, gpointer data);
438 static void sp_gradient_vector_gradient_release(SPObject *obj, GtkWidget *widget);
439 static void sp_gradient_vector_gradient_modified(SPObject *obj, guint flags, GtkWidget *widget);
440 static void sp_gradient_vector_color_dragged(SPColorSelector *csel, GtkObject *object);
441 static void sp_gradient_vector_color_changed(SPColorSelector *csel, GtkObject *object);
442 static void update_stop_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_stop);
444 static gboolean blocked = FALSE;
446 static void grad_edit_dia_stop_added_or_removed(Inkscape::XML::Node */*repr*/, Inkscape::XML::Node */*child*/, Inkscape::XML::Node */*ref*/, gpointer data)
447 {
448 GtkWidget *vb = GTK_WIDGET(data);
449 GtkWidget *mnu = (GtkWidget *)g_object_get_data(G_OBJECT(vb), "stopmenu");
450 SPGradient *gradient = (SPGradient *)g_object_get_data(G_OBJECT(vb), "gradient");
451 update_stop_list(mnu, gradient, NULL);
452 }
454 //FIXME!!! We must also listen to attr changes on all children (i.e. stops) too,
455 //otherwise the dialog does not reflect undoing color or offset change. This is a major
456 //hassle, unless we have a "one of the descendants changed in some way" signal.
457 static Inkscape::XML::NodeEventVector grad_edit_dia_repr_events =
458 {
459 grad_edit_dia_stop_added_or_removed, /* child_added */
460 grad_edit_dia_stop_added_or_removed, /* child_removed */
461 NULL, /* attr_changed*/
462 NULL, /* content_changed */
463 NULL /* order_changed */
464 };
466 static void verify_grad(SPGradient *gradient)
467 {
468 int i = 0;
469 SPStop *stop = NULL;
470 /* count stops */
471 for ( SPObject *ochild = sp_object_first_child(SP_OBJECT(gradient)) ; ochild != NULL ; ochild = SP_OBJECT_NEXT(ochild) ) {
472 if (SP_IS_STOP(ochild)) {
473 i++;
474 stop = SP_STOP(ochild);
475 }
476 }
478 Inkscape::XML::Document *xml_doc;
479 xml_doc = SP_OBJECT_REPR(gradient)->document();
481 if (i < 1) {
482 gchar c[64];
483 sp_svg_write_color(c, sizeof(c), 0x00000000);
485 Inkscape::CSSOStringStream os;
486 os << "stop-color:" << c << ";stop-opacity:" << 1.0 << ";";
488 Inkscape::XML::Node *child;
490 child = xml_doc->createElement("svg:stop");
491 sp_repr_set_css_double(child, "offset", 0.0);
492 child->setAttribute("style", os.str().c_str());
493 SP_OBJECT_REPR(gradient)->addChild(child, NULL);
494 Inkscape::GC::release(child);
496 child = xml_doc->createElement("svg:stop");
497 sp_repr_set_css_double(child, "offset", 1.0);
498 child->setAttribute("style", os.str().c_str());
499 SP_OBJECT_REPR(gradient)->addChild(child, NULL);
500 Inkscape::GC::release(child);
501 }
502 if (i < 2) {
503 sp_repr_set_css_double(SP_OBJECT_REPR(stop), "offset", 0.0);
504 Inkscape::XML::Node *child = SP_OBJECT_REPR(stop)->duplicate(SP_OBJECT_REPR(gradient)->document());
505 sp_repr_set_css_double(child, "offset", 1.0);
506 SP_OBJECT_REPR(gradient)->addChild(child, SP_OBJECT_REPR(stop));
507 Inkscape::GC::release(child);
508 }
509 }
511 static void select_stop_in_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_stop)
512 {
513 int i = 0;
514 for ( SPObject *ochild = sp_object_first_child(SP_OBJECT(gradient)) ; ochild != NULL ; ochild = SP_OBJECT_NEXT(ochild) ) {
515 if (SP_IS_STOP(ochild)) {
516 if (SP_OBJECT(ochild) == SP_OBJECT(new_stop)) {
517 gtk_option_menu_set_history(GTK_OPTION_MENU(mnu), i);
518 break;
519 }
520 i++;
521 }
522 }
523 }
525 static void update_stop_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_stop)
526 {
528 if (!SP_IS_GRADIENT(gradient)) {
529 return;
530 }
532 blocked = TRUE;
534 /* Clear old menu, if there is any */
535 if (gtk_option_menu_get_menu(GTK_OPTION_MENU(mnu))) {
536 gtk_option_menu_remove_menu(GTK_OPTION_MENU(mnu));
537 }
539 /* Create new menu widget */
540 GtkWidget *m = gtk_menu_new();
541 gtk_widget_show(m);
542 GSList *sl = NULL;
543 if ( gradient->hasStops() ) {
544 for ( SPObject *ochild = sp_object_first_child(SP_OBJECT(gradient)) ; ochild != NULL ; ochild = SP_OBJECT_NEXT(ochild) ) {
545 if (SP_IS_STOP(ochild)) {
546 sl = g_slist_append(sl, ochild);
547 }
548 }
549 }
550 if (!sl) {
551 GtkWidget *i = gtk_menu_item_new_with_label(_("No stops in gradient"));
552 gtk_widget_show(i);
553 gtk_menu_append(GTK_MENU(m), i);
554 gtk_widget_set_sensitive(mnu, FALSE);
555 } else {
557 for (; sl != NULL; sl = sl->next){
558 SPStop *stop;
559 GtkWidget *i;
560 if (SP_IS_STOP(sl->data)){
561 stop = SP_STOP(sl->data);
562 i = gtk_menu_item_new();
563 gtk_widget_show(i);
564 g_object_set_data(G_OBJECT(i), "stop", stop);
565 GtkWidget *hb = gtk_hbox_new(FALSE, 4);
566 GtkWidget *cpv = sp_color_preview_new(sp_stop_get_rgba32(stop));
567 gtk_widget_show(cpv);
568 gtk_container_add( GTK_CONTAINER(hb), cpv );
569 g_object_set_data( G_OBJECT(i), "preview", cpv );
570 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) sl->data);
571 GtkWidget *l = gtk_label_new(repr->attribute("id"));
572 gtk_widget_show(l);
573 gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
574 gtk_box_pack_start(GTK_BOX(hb), l, TRUE, TRUE, 0);
575 gtk_widget_show(hb);
576 gtk_container_add(GTK_CONTAINER(i), hb);
577 gtk_menu_append(GTK_MENU(m), i);
578 }
579 }
581 gtk_widget_set_sensitive(mnu, TRUE);
582 }
583 gtk_option_menu_set_menu(GTK_OPTION_MENU(mnu), m);
585 /* Set history */
586 if (new_stop == NULL) {
587 gtk_option_menu_set_history(GTK_OPTION_MENU(mnu), 0);
588 } else {
589 select_stop_in_list(mnu, gradient, new_stop);
590 }
592 blocked = FALSE;
593 }
596 // user selected existing stop from list
597 static void sp_grad_edit_select(GtkOptionMenu *mnu, GtkWidget *tbl)
598 {
599 GObject *item = G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu))));
600 SPStop *stop = SP_STOP(g_object_get_data(item, "stop"));
601 if (!stop) {
602 return;
603 }
605 blocked = TRUE;
607 SPColorSelector *csel = (SPColorSelector*)g_object_get_data(G_OBJECT(tbl), "cselector");
608 guint32 const c = sp_stop_get_rgba32(stop);
609 csel->base->setAlpha(SP_RGBA32_A_F(c));
610 SPColor color( SP_RGBA32_R_F(c), SP_RGBA32_G_F(c), SP_RGBA32_B_F(c) );
611 // set its color, from the stored array
612 csel->base->setColor( color );
613 GtkWidget *offspin = GTK_WIDGET(g_object_get_data(G_OBJECT(tbl), "offspn"));
614 GtkWidget *offslide =GTK_WIDGET(g_object_get_data(G_OBJECT(tbl), "offslide"));
616 GtkAdjustment *adj = static_cast<GtkAdjustment*>(gtk_object_get_data(GTK_OBJECT(tbl), "offset"));
618 bool isEndStop = false;
620 SPStop *prev = NULL;
621 prev = stop->getPrevStop();
622 if (prev != NULL ) {
623 adj->lower = prev->offset;
624 } else {
625 isEndStop = true;
626 adj->lower = 0;
627 }
629 SPStop *next = NULL;
630 next = stop->getNextStop();
631 if (next != NULL ) {
632 adj->upper = next->offset;
633 } else {
634 isEndStop = true;
635 adj->upper = 1.0;
636 }
638 //fixme: does this work on all possible input gradients?
639 if (!isEndStop) {
640 gtk_widget_set_sensitive(offslide, TRUE);
641 gtk_widget_set_sensitive(GTK_WIDGET(offspin), TRUE);
642 } else {
643 gtk_widget_set_sensitive(offslide, FALSE);
644 gtk_widget_set_sensitive(GTK_WIDGET(offspin), FALSE);
645 }
647 gtk_adjustment_set_value(adj, stop->offset);
649 gtk_adjustment_changed(adj);
651 blocked = FALSE;
652 }
657 static void offadjustmentChanged( GtkAdjustment *adjustment, GtkWidget *vb)
658 {
659 if (blocked) {
660 return;
661 }
663 blocked = TRUE;
665 GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(vb), "stopmenu"));
666 if (!g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop")) {
667 return;
668 }
669 SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop"));
671 stop->offset = adjustment->value;
672 sp_repr_set_css_double(SP_OBJECT_REPR(stop), "offset", stop->offset);
674 sp_document_done(SP_OBJECT_DOCUMENT(stop), SP_VERB_CONTEXT_GRADIENT,
675 _("Change gradient stop offset"));
677 blocked = FALSE;
678 }
680 guint32 sp_average_color(guint32 c1, guint32 c2, gdouble p = 0.5)
681 {
682 guint32 r = (guint32) (SP_RGBA32_R_U(c1) * p + SP_RGBA32_R_U(c2) * (1 - p));
683 guint32 g = (guint32) (SP_RGBA32_G_U(c1) * p + SP_RGBA32_G_U(c2) * (1 - p));
684 guint32 b = (guint32) (SP_RGBA32_B_U(c1) * p + SP_RGBA32_B_U(c2) * (1 - p));
685 guint32 a = (guint32) (SP_RGBA32_A_U(c1) * p + SP_RGBA32_A_U(c2) * (1 - p));
687 return SP_RGBA32_U_COMPOSE(r, g, b, a);
688 }
691 static void sp_grd_ed_add_stop(GtkWidget */*widget*/, GtkWidget *vb)
692 {
693 SPGradient *gradient = static_cast<SPGradient *>(g_object_get_data(G_OBJECT(vb), "gradient"));
694 verify_grad(gradient);
695 GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(vb), "stopmenu"));
697 SPStop *stop = static_cast<SPStop *>(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop"));
699 if (stop == NULL) {
700 return;
701 }
703 Inkscape::XML::Node *new_stop_repr = NULL;
705 SPStop *next = stop->getNextStop();
707 if (next == NULL) {
708 SPStop *prev = stop->getPrevStop();
709 if (prev != NULL) {
710 next = stop;
711 stop = prev;
712 }
713 }
715 if (next != NULL) {
716 new_stop_repr = SP_OBJECT_REPR(stop)->duplicate(SP_OBJECT_REPR(gradient)->document());
717 SP_OBJECT_REPR(gradient)->addChild(new_stop_repr, SP_OBJECT_REPR(stop));
718 } else {
719 next = stop;
720 new_stop_repr = SP_OBJECT_REPR(stop->getPrevStop())->duplicate(SP_OBJECT_REPR(gradient)->document());
721 SP_OBJECT_REPR(gradient)->addChild(new_stop_repr, SP_OBJECT_REPR(stop->getPrevStop()));
722 }
724 SPStop *newstop = (SPStop *) SP_OBJECT_DOCUMENT(gradient)->getObjectByRepr(new_stop_repr);
726 newstop->offset = (stop->offset + next->offset) * 0.5 ;
728 guint32 const c1 = sp_stop_get_rgba32(stop);
729 guint32 const c2 = sp_stop_get_rgba32(next);
730 guint32 cnew = sp_average_color(c1, c2);
732 Inkscape::CSSOStringStream os;
733 gchar c[64];
734 sp_svg_write_color(c, sizeof(c), cnew);
735 gdouble opacity = static_cast<gdouble>(SP_RGBA32_A_F(cnew));
736 os << "stop-color:" << c << ";stop-opacity:" << opacity <<";";
737 SP_OBJECT_REPR (newstop)->setAttribute("style", os.str().c_str());
738 sp_repr_set_css_double( SP_OBJECT_REPR(newstop), "offset", (double)newstop->offset);
740 sp_gradient_vector_widget_load_gradient(vb, gradient);
741 Inkscape::GC::release(new_stop_repr);
742 update_stop_list(GTK_WIDGET(mnu), gradient, newstop);
743 GtkWidget *offspin = GTK_WIDGET(g_object_get_data(G_OBJECT(vb), "offspn"));
744 GtkWidget *offslide =GTK_WIDGET(g_object_get_data(G_OBJECT(vb), "offslide"));
745 gtk_widget_set_sensitive(offslide, TRUE);
746 gtk_widget_set_sensitive(GTK_WIDGET(offspin), TRUE);
747 sp_document_done(SP_OBJECT_DOCUMENT(gradient), SP_VERB_CONTEXT_GRADIENT,
748 _("Add gradient stop"));
749 }
751 static void sp_grd_ed_del_stop(GtkWidget */*widget*/, GtkWidget *vb)
752 {
753 SPGradient *gradient = static_cast<SPGradient *>(g_object_get_data(G_OBJECT(vb), "gradient"));
755 GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(vb), "stopmenu"));
756 if (!g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop")) return;
757 SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop"));
758 if (gradient->vector.stops.size() > 2) { // 2 is the minimum
760 // if we delete first or last stop, move the next/previous to the edge
761 if (stop->offset == 0) {
762 SPStop *next = stop->getNextStop();
763 if (next) {
764 next->offset = 0;
765 sp_repr_set_css_double(SP_OBJECT_REPR(next), "offset", 0);
766 }
767 } else if (stop->offset == 1) {
768 SPStop *prev = stop->getPrevStop();
769 if (prev) {
770 prev->offset = 1;
771 sp_repr_set_css_double(SP_OBJECT_REPR(prev), "offset", 1);
772 }
773 }
775 SP_OBJECT_REPR(gradient)->removeChild(SP_OBJECT_REPR(stop));
776 sp_gradient_vector_widget_load_gradient(vb, gradient);
777 update_stop_list(GTK_WIDGET(mnu), gradient, NULL);
778 sp_document_done(SP_OBJECT_DOCUMENT(gradient), SP_VERB_CONTEXT_GRADIENT,
779 _("Delete gradient stop"));
780 }
782 }
784 static GtkWidget * sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *select_stop)
785 {
786 GtkWidget *vb, *w, *f, *csel;
788 g_return_val_if_fail(!gradient || SP_IS_GRADIENT(gradient), NULL);
790 vb = gtk_vbox_new(FALSE, PAD);
791 g_signal_connect(G_OBJECT(vb), "destroy", G_CALLBACK(sp_gradient_vector_widget_destroy), NULL);
793 w = sp_gradient_image_new(gradient);
794 g_object_set_data(G_OBJECT(vb), "preview", w);
795 gtk_widget_show(w);
796 gtk_box_pack_start(GTK_BOX(vb), w, TRUE, TRUE, PAD);
798 sp_repr_add_listener(SP_OBJECT_REPR(gradient), &grad_edit_dia_repr_events, vb);
799 GtkTooltips *tt = gtk_tooltips_new();
801 /* Stop list */
802 GtkWidget *mnu = gtk_option_menu_new();
803 /* Create new menu widget */
804 update_stop_list(GTK_WIDGET(mnu), gradient, NULL);
805 gtk_signal_connect(GTK_OBJECT(mnu), "changed", GTK_SIGNAL_FUNC(sp_grad_edit_select), vb);
806 gtk_widget_show(mnu);
807 gtk_object_set_data(GTK_OBJECT(vb), "stopmenu", mnu);
808 gtk_box_pack_start(GTK_BOX(vb), mnu, FALSE, FALSE, 0);
810 /* Add and Remove buttons */
811 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
812 // TRANSLATORS: "Stop" means: a "phase" of a gradient
813 GtkWidget *b = gtk_button_new_with_label(_("Add stop"));
814 gtk_widget_show(b);
815 gtk_container_add(GTK_CONTAINER(hb), b);
816 gtk_tooltips_set_tip(tt, b, _("Add another control stop to gradient"), NULL);
817 gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_grd_ed_add_stop), vb);
818 b = gtk_button_new_with_label(_("Delete stop"));
819 gtk_widget_show(b);
820 gtk_container_add(GTK_CONTAINER(hb), b);
821 gtk_tooltips_set_tip(tt, b, _("Delete current control stop from gradient"), NULL);
822 gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_grd_ed_del_stop), vb);
824 gtk_widget_show(hb);
825 gtk_box_pack_start(GTK_BOX(vb),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
828 /* Offset Slider and stuff */
829 hb = gtk_hbox_new(FALSE, 0);
831 /* Label */
832 GtkWidget *l = gtk_label_new(_("Offset:"));
833 gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
834 gtk_box_pack_start(GTK_BOX(hb),l, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
835 gtk_widget_show(l);
837 /* Adjustment */
838 GtkAdjustment *Offset_adj = NULL;
839 Offset_adj= (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 0.01, 0.01, 0.0);
840 gtk_object_set_data(GTK_OBJECT(vb), "offset", Offset_adj);
841 GtkMenu *m = GTK_MENU(gtk_option_menu_get_menu(GTK_OPTION_MENU(mnu)));
842 SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(m)), "stop"));
843 gtk_adjustment_set_value(Offset_adj, stop->offset);
845 /* Slider */
846 GtkWidget *slider = gtk_hscale_new(Offset_adj);
847 gtk_scale_set_draw_value( GTK_SCALE(slider), FALSE );
848 gtk_widget_show(slider);
849 gtk_box_pack_start(GTK_BOX(hb),slider, TRUE, TRUE, AUX_BETWEEN_BUTTON_GROUPS);
850 gtk_object_set_data(GTK_OBJECT(vb), "offslide", slider);
852 /* Spinbutton */
853 GtkWidget *sbtn = gtk_spin_button_new(GTK_ADJUSTMENT(Offset_adj), 0.01, 2);
854 sp_dialog_defocus_on_enter(sbtn);
855 gtk_widget_show(sbtn);
856 gtk_box_pack_start(GTK_BOX(hb),sbtn, FALSE, TRUE, AUX_BETWEEN_BUTTON_GROUPS);
857 gtk_object_set_data(GTK_OBJECT(vb), "offspn", sbtn);
859 if (stop->offset>0 && stop->offset<1) {
860 gtk_widget_set_sensitive(slider, TRUE);
861 gtk_widget_set_sensitive(GTK_WIDGET(sbtn), TRUE);
862 } else {
863 gtk_widget_set_sensitive(slider, FALSE);
864 gtk_widget_set_sensitive(GTK_WIDGET(sbtn), FALSE);
865 }
868 /* Signals */
869 gtk_signal_connect(GTK_OBJECT(Offset_adj), "value_changed",
870 GTK_SIGNAL_FUNC(offadjustmentChanged), vb);
872 // gtk_signal_connect(GTK_OBJECT(slider), "changed", GTK_SIGNAL_FUNC(offsliderChanged), vb);
873 gtk_widget_show(hb);
874 gtk_box_pack_start(GTK_BOX(vb), hb, FALSE, FALSE, PAD);
876 // TRANSLATORS: "Stop" means: a "phase" of a gradient
877 f = gtk_frame_new(_("Stop Color"));
878 gtk_widget_show(f);
879 gtk_box_pack_start(GTK_BOX(vb), f, TRUE, TRUE, PAD);
880 csel = static_cast<GtkWidget*>(sp_color_selector_new(SP_TYPE_COLOR_NOTEBOOK));
881 g_object_set_data(G_OBJECT(vb), "cselector", csel);
882 gtk_widget_show(csel);
883 gtk_container_add(GTK_CONTAINER(f), csel);
884 g_signal_connect(G_OBJECT(csel), "dragged", G_CALLBACK(sp_gradient_vector_color_dragged), vb);
885 g_signal_connect(G_OBJECT(csel), "changed", G_CALLBACK(sp_gradient_vector_color_changed), vb);
887 gtk_widget_show(vb);
889 sp_gradient_vector_widget_load_gradient(vb, gradient);
891 if (select_stop) {
892 select_stop_in_list(GTK_WIDGET(mnu), gradient, select_stop);
893 }
895 return vb;
896 }
900 GtkWidget * sp_gradient_vector_editor_new(SPGradient *gradient, SPStop *stop)
901 {
902 GtkWidget *wid;
904 if (dlg == NULL) {
905 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
907 dlg = sp_window_new(_("Gradient editor"), TRUE);
908 if (x == -1000 || y == -1000) {
909 x = prefs->getInt(prefs_path + "x", -1000);
910 y = prefs->getInt(prefs_path + "y", -1000);
911 }
912 if (w ==0 || h == 0) {
913 w = prefs->getInt(prefs_path + "w", 0);
914 h = prefs->getInt(prefs_path + "h", 0);
915 }
917 if (x<0) {
918 x=0;
919 }
920 if (y<0) {
921 y=0;
922 }
924 if (x != 0 || y != 0) {
925 gtk_window_move(reinterpret_cast<GtkWindow *>(dlg), x, y);
926 } else {
927 gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
928 }
929 if (w && h) {
930 gtk_window_resize(reinterpret_cast<GtkWindow *>(dlg), w, h);
931 }
932 sp_transientize(dlg);
933 wd.win = dlg;
934 wd.stop = 0;
935 g_signal_connect(G_OBJECT(INKSCAPE), "activate_desktop", G_CALLBACK(sp_transientize_callback), &wd);
936 gtk_signal_connect(GTK_OBJECT(dlg), "event", GTK_SIGNAL_FUNC(sp_dialog_event_handler), dlg);
937 gtk_signal_connect(GTK_OBJECT(dlg), "destroy", G_CALLBACK(sp_gradient_vector_dialog_destroy), dlg);
938 gtk_signal_connect(GTK_OBJECT(dlg), "delete_event", G_CALLBACK(sp_gradient_vector_dialog_delete), dlg);
939 g_signal_connect(G_OBJECT(INKSCAPE), "shut_down", G_CALLBACK(sp_gradient_vector_dialog_delete), dlg);
940 g_signal_connect( G_OBJECT(INKSCAPE), "dialogs_hide", G_CALLBACK(sp_dialog_hide), dlg );
941 g_signal_connect( G_OBJECT(INKSCAPE), "dialogs_unhide", G_CALLBACK(sp_dialog_unhide), dlg );
943 gtk_container_set_border_width(GTK_CONTAINER(dlg), PAD);
945 wid = static_cast<GtkWidget*>(sp_gradient_vector_widget_new(gradient, stop));
946 g_object_set_data(G_OBJECT(dlg), "gradient-vector-widget", wid);
947 /* Connect signals */
948 gtk_widget_show(wid);
949 gtk_container_add(GTK_CONTAINER(dlg), wid);
950 } else {
951 // FIXME: temp fix for 0.38
952 // Simply load_gradient into the editor does not work for multi-stop gradients,
953 // as the stop list and other widgets are in a wrong state and crash readily.
954 // Instead we just delete the window (by sending the delete signal)
955 // and call sp_gradient_vector_editor_new again, so it creates the window anew.
957 GdkEventAny event;
958 GtkWidget *widget = static_cast<GtkWidget *>(dlg);
959 event.type = GDK_DELETE;
960 event.window = widget->window;
961 event.send_event = TRUE;
962 g_object_ref(G_OBJECT(event.window));
963 gtk_main_do_event(reinterpret_cast<GdkEvent*>(&event));
964 g_object_unref(G_OBJECT(event.window));
966 g_assert(dlg == NULL);
967 sp_gradient_vector_editor_new(gradient, stop);
968 }
970 return dlg;
971 }
973 static void sp_gradient_vector_widget_load_gradient(GtkWidget *widget, SPGradient *gradient)
974 {
975 blocked = TRUE;
977 SPGradient *old;
979 old = (SPGradient*)g_object_get_data(G_OBJECT(widget), "gradient");
981 if (old != gradient) {
982 sigc::connection *release_connection;
983 sigc::connection *modified_connection;
985 release_connection = (sigc::connection *)g_object_get_data(G_OBJECT(widget), "gradient_release_connection");
986 modified_connection = (sigc::connection *)g_object_get_data(G_OBJECT(widget), "gradient_modified_connection");
988 if (old) {
989 g_assert( release_connection != NULL );
990 g_assert( modified_connection != NULL );
991 release_connection->disconnect();
992 modified_connection->disconnect();
993 sp_signal_disconnect_by_data(old, widget);
994 }
996 if (gradient) {
997 if (!release_connection) {
998 release_connection = new sigc::connection();
999 }
1000 if (!modified_connection) {
1001 modified_connection = new sigc::connection();
1002 }
1003 *release_connection = gradient->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gradient_vector_gradient_release), widget));
1004 *modified_connection = gradient->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_gradient_vector_gradient_modified), widget));
1005 } else {
1006 if (release_connection) {
1007 delete release_connection;
1008 release_connection = NULL;
1009 }
1010 if (modified_connection) {
1011 delete modified_connection;
1012 modified_connection = NULL;
1013 }
1014 }
1016 g_object_set_data(G_OBJECT(widget), "gradient_release_connection", release_connection);
1017 g_object_set_data(G_OBJECT(widget), "gradient_modified_connection", modified_connection);
1018 }
1020 g_object_set_data(G_OBJECT(widget), "gradient", gradient);
1022 if (gradient) {
1023 gtk_widget_set_sensitive(widget, TRUE);
1025 gradient->ensureVector();
1027 GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(widget), "stopmenu"));
1028 SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop"));
1029 guint32 const c = sp_stop_get_rgba32(stop);
1031 /// get the color selector
1032 SPColorSelector *csel = SP_COLOR_SELECTOR(g_object_get_data(G_OBJECT(widget), "cselector"));
1033 // set alpha
1034 csel->base->setAlpha(SP_RGBA32_A_F(c));
1035 SPColor color( SP_RGBA32_R_F(c), SP_RGBA32_G_F(c), SP_RGBA32_B_F(c) );
1036 // set color
1037 csel->base->setColor( color );
1039 /* Fill preview */
1040 GtkWidget *w = static_cast<GtkWidget *>(g_object_get_data(G_OBJECT(widget), "preview"));
1041 sp_gradient_image_set_gradient(SP_GRADIENT_IMAGE(w), gradient);
1043 update_stop_list(GTK_WIDGET(mnu), gradient, NULL);
1045 // Once the user edits a gradient, it stops being auto-collectable
1046 if (SP_OBJECT_REPR(gradient)->attribute("inkscape:collect")) {
1047 SPDocument *document = SP_OBJECT_DOCUMENT(gradient);
1048 bool saved = sp_document_get_undo_sensitive(document);
1049 sp_document_set_undo_sensitive(document, false);
1050 SP_OBJECT_REPR(gradient)->setAttribute("inkscape:collect", NULL);
1051 sp_document_set_undo_sensitive(document, saved);
1052 }
1053 } else { // no gradient, disable everything
1054 gtk_widget_set_sensitive(widget, FALSE);
1055 }
1057 blocked = FALSE;
1058 }
1060 static void sp_gradient_vector_dialog_destroy(GtkObject */*object*/, gpointer /*data*/)
1061 {
1062 sp_signal_disconnect_by_data(INKSCAPE, dlg);
1063 wd.win = dlg = NULL;
1064 wd.stop = 0;
1065 }
1067 static gboolean sp_gradient_vector_dialog_delete(GtkWidget */*widget*/, GdkEvent */*event*/, GtkWidget */*dialog*/)
1068 {
1069 gtk_window_get_position(GTK_WINDOW(dlg), &x, &y);
1070 gtk_window_get_size(GTK_WINDOW(dlg), &w, &h);
1072 if (x<0) {
1073 x=0;
1074 }
1075 if (y<0) {
1076 y=0;
1077 }
1079 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1080 prefs->setInt(prefs_path + "x", x);
1081 prefs->setInt(prefs_path + "y", y);
1082 prefs->setInt(prefs_path + "w", w);
1083 prefs->setInt(prefs_path + "h", h);
1085 return FALSE; // which means, go ahead and destroy it
1086 }
1088 /* Widget destroy handler */
1090 static void sp_gradient_vector_widget_destroy(GtkObject *object, gpointer /*data*/)
1091 {
1092 GObject *gradient;
1094 gradient = (GObject*)g_object_get_data(G_OBJECT(object), "gradient");
1096 sigc::connection *release_connection = (sigc::connection *)g_object_get_data(G_OBJECT(object), "gradient_release_connection");
1097 sigc::connection *modified_connection = (sigc::connection *)g_object_get_data(G_OBJECT(object), "gradient_modified_connection");
1099 if (gradient) {
1100 g_assert( release_connection != NULL );
1101 g_assert( modified_connection != NULL );
1102 release_connection->disconnect();
1103 modified_connection->disconnect();
1104 sp_signal_disconnect_by_data(gradient, object);
1105 }
1107 if (gradient && SP_OBJECT_REPR(gradient)) {
1108 sp_repr_remove_listener_by_data(SP_OBJECT_REPR(gradient), object);
1109 }
1110 }
1112 static void sp_gradient_vector_gradient_release(SPObject */*object*/, GtkWidget *widget)
1113 {
1114 sp_gradient_vector_widget_load_gradient(widget, NULL);
1115 }
1117 static void sp_gradient_vector_gradient_modified(SPObject *object, guint /*flags*/, GtkWidget *widget)
1118 {
1119 SPGradient *gradient=SP_GRADIENT(object);
1120 if (!blocked) {
1121 blocked = TRUE;
1122 sp_gradient_vector_widget_load_gradient(widget, gradient);
1123 blocked = FALSE;
1124 }
1125 }
1127 static void sp_gradient_vector_color_dragged(SPColorSelector *csel, GtkObject *object)
1128 {
1129 SPGradient *gradient, *ngr;
1131 if (blocked) {
1132 return;
1133 }
1135 gradient = static_cast<SPGradient*>(g_object_get_data(G_OBJECT(object), "gradient"));
1136 if (!gradient) {
1137 return;
1138 }
1140 blocked = TRUE;
1142 ngr = sp_gradient_ensure_vector_normalized(gradient);
1143 if (ngr != gradient) {
1144 /* Our master gradient has changed */
1145 sp_gradient_vector_widget_load_gradient(GTK_WIDGET(object), ngr);
1146 }
1148 ngr->ensureVector();
1150 GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(object), "stopmenu"));
1151 SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop"));
1154 csel->base->getColorAlpha(stop->specified_color, stop->opacity);
1155 stop->currentColor = false;
1157 blocked = FALSE;
1158 }
1160 static void sp_gradient_vector_color_changed(SPColorSelector *csel, GtkObject *object)
1161 {
1162 SPColor color;
1163 float alpha;
1164 guint32 rgb;
1166 if (blocked) {
1167 return;
1168 }
1170 SPGradient *gradient = static_cast<SPGradient*>(g_object_get_data(G_OBJECT(object), "gradient"));
1171 if (!gradient) {
1172 return;
1173 }
1175 blocked = TRUE;
1177 SPGradient *ngr = sp_gradient_ensure_vector_normalized(gradient);
1178 if (ngr != gradient) {
1179 /* Our master gradient has changed */
1180 sp_gradient_vector_widget_load_gradient(GTK_WIDGET(object), ngr);
1181 }
1183 ngr->ensureVector();
1185 /* Set start parameters */
1186 /* We rely on normalized vector, i.e. stops HAVE to exist */
1187 g_return_if_fail(ngr->getFirstStop() != NULL);
1189 GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(object), "stopmenu"));
1190 SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop"));
1192 csel = static_cast<SPColorSelector*>(g_object_get_data(G_OBJECT(object), "cselector"));
1193 csel->base->getColorAlpha( color, alpha );
1194 rgb = color.toRGBA32( 0x00 );
1196 sp_repr_set_css_double(SP_OBJECT_REPR(stop), "offset", stop->offset);
1197 Inkscape::CSSOStringStream os;
1198 gchar c[64];
1199 sp_svg_write_color(c, sizeof(c), rgb);
1200 os << "stop-color:" << c << ";stop-opacity:" << static_cast<gdouble>(alpha) <<";";
1201 SP_OBJECT_REPR(stop)->setAttribute("style", os.str().c_str());
1202 // g_snprintf(c, 256, "stop-color:#%06x;stop-opacity:%g;", rgb >> 8, static_cast<gdouble>(alpha));
1203 //SP_OBJECT_REPR(stop)->setAttribute("style", c);
1205 sp_document_done(SP_OBJECT_DOCUMENT(ngr), SP_VERB_CONTEXT_GRADIENT,
1206 _("Change gradient stop color"));
1208 blocked = FALSE;
1210 SPColorPreview *cpv = static_cast<SPColorPreview *>(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "preview"));
1211 sp_color_preview_set_rgba32(cpv, sp_stop_get_rgba32(stop));
1212 }
1214 /*
1215 Local Variables:
1216 mode:c++
1217 c-file-style:"stroustrup"
1218 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1219 indent-tabs-mode:nil
1220 fill-column:99
1221 End:
1222 */
1223 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :