1 #define __SP_GRADIENT_SELECTOR_C__
3 /*
4 * Gradient vector widget
5 *
6 * Authors:
7 * Lauris Kaplinski <lauris@kaplinski.com>
8 * bulia byak <buliabyak@users.sf.net>
9 *
10 * Copyright (C) 2001-2002 Lauris Kaplinski
11 * Copyright (C) 2001 Ximian, Inc.
12 *
13 * Released under GNU GPL, read the file 'COPYING' for more information
14 */
16 #ifdef HAVE_CONFIG_H
17 # include "config.h"
18 #endif
19 #include <gtk/gtkhbox.h>
20 #include <gtk/gtklabel.h>
21 #include <gtk/gtkoptionmenu.h>
22 #include <gtk/gtkmenuitem.h>
23 #include <gtk/gtktooltips.h>
25 #include "document.h"
26 #include "../document-private.h"
27 #include "../gradient-chemistry.h"
29 #include <glibmm/i18n.h>
30 #include <xml/repr.h>
32 #include "gradient-vector.h"
34 #include "gradient-selector.h"
36 enum {
37 GRABBED,
38 DRAGGED,
39 RELEASED,
40 CHANGED,
41 LAST_SIGNAL
42 };
44 static void sp_gradient_selector_class_init (SPGradientSelectorClass *klass);
45 static void sp_gradient_selector_init (SPGradientSelector *selector);
46 static void sp_gradient_selector_destroy (GtkObject *object);
48 /* Signal handlers */
49 static void sp_gradient_selector_vector_set (SPGradientVectorSelector *gvs, SPGradient *gr, SPGradientSelector *sel);
50 static void sp_gradient_selector_edit_vector_clicked (GtkWidget *w, SPGradientSelector *sel);
51 static void sp_gradient_selector_add_vector_clicked (GtkWidget *w, SPGradientSelector *sel);
53 static void sp_gradient_selector_spread_activate (GtkWidget *widget, SPGradientSelector *sel);
55 static GtkVBoxClass *parent_class;
56 static guint signals[LAST_SIGNAL] = {0};
58 GtkType
59 sp_gradient_selector_get_type (void)
60 {
61 static GtkType type = 0;
62 if (!type) {
63 GtkTypeInfo info = {
64 "SPGradientSelector",
65 sizeof (SPGradientSelector),
66 sizeof (SPGradientSelectorClass),
67 (GtkClassInitFunc) sp_gradient_selector_class_init,
68 (GtkObjectInitFunc) sp_gradient_selector_init,
69 NULL, NULL, NULL
70 };
71 type = gtk_type_unique (GTK_TYPE_VBOX, &info);
72 }
73 return type;
74 }
76 static void
77 sp_gradient_selector_class_init (SPGradientSelectorClass *klass)
78 {
79 GtkObjectClass *object_class;
81 object_class = (GtkObjectClass *) klass;
83 parent_class = (GtkVBoxClass*)gtk_type_class (GTK_TYPE_VBOX);
85 signals[GRABBED] = gtk_signal_new ("grabbed",
86 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
87 GTK_CLASS_TYPE(object_class),
88 GTK_SIGNAL_OFFSET (SPGradientSelectorClass, grabbed),
89 gtk_marshal_NONE__NONE,
90 GTK_TYPE_NONE, 0);
91 signals[DRAGGED] = gtk_signal_new ("dragged",
92 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
93 GTK_CLASS_TYPE(object_class),
94 GTK_SIGNAL_OFFSET (SPGradientSelectorClass, dragged),
95 gtk_marshal_NONE__NONE,
96 GTK_TYPE_NONE, 0);
97 signals[RELEASED] = gtk_signal_new ("released",
98 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
99 GTK_CLASS_TYPE(object_class),
100 GTK_SIGNAL_OFFSET (SPGradientSelectorClass, released),
101 gtk_marshal_NONE__NONE,
102 GTK_TYPE_NONE, 0);
103 signals[CHANGED] = gtk_signal_new ("changed",
104 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
105 GTK_CLASS_TYPE(object_class),
106 GTK_SIGNAL_OFFSET (SPGradientSelectorClass, changed),
107 gtk_marshal_NONE__NONE,
108 GTK_TYPE_NONE, 0);
110 object_class->destroy = sp_gradient_selector_destroy;
111 }
113 static void
114 sp_gradient_selector_init (SPGradientSelector *sel)
115 {
116 GtkWidget *hb, *l, *m, *mi;
118 sel->mode = SP_GRADIENT_SELECTOR_MODE_LINEAR;
120 sel->gradientUnits = SP_GRADIENT_UNITS_USERSPACEONUSE;
121 sel->gradientSpread = SP_GRADIENT_SPREAD_PAD;
123 /* Vectors */
124 sel->vectors = sp_gradient_vector_selector_new (NULL, NULL);
125 gtk_widget_show (sel->vectors);
126 gtk_box_pack_start (GTK_BOX (sel), sel->vectors, FALSE, FALSE, 0);
127 g_signal_connect (G_OBJECT (sel->vectors), "vector_set", G_CALLBACK (sp_gradient_selector_vector_set), sel);
129 /* Create box for buttons */
130 hb = gtk_hbox_new (FALSE, 0);
131 gtk_box_pack_start (GTK_BOX (sel), hb, FALSE, FALSE, 0);
132 GtkTooltips *ttips = gtk_tooltips_new ();
134 sel->add = gtk_button_new_with_label (_("Duplicate"));
135 gtk_box_pack_start (GTK_BOX (hb), sel->add, TRUE, TRUE, 0);
136 g_signal_connect (G_OBJECT (sel->add), "clicked", G_CALLBACK (sp_gradient_selector_add_vector_clicked), sel);
137 gtk_widget_set_sensitive (sel->add, FALSE);
139 sel->edit = gtk_button_new_with_label (_("Edit..."));
140 gtk_box_pack_start (GTK_BOX (hb), sel->edit, TRUE, TRUE, 0);
141 g_signal_connect (G_OBJECT (sel->edit), "clicked", G_CALLBACK (sp_gradient_selector_edit_vector_clicked), sel);
142 gtk_widget_set_sensitive (sel->edit, FALSE);
144 gtk_widget_show_all (hb);
146 /* Spread selector */
147 hb = gtk_hbox_new (FALSE, 0);
148 gtk_widget_show (hb);
149 gtk_box_pack_start (GTK_BOX (sel), hb, FALSE, FALSE, 0);
151 sel->spread = gtk_option_menu_new ();
152 gtk_widget_show (sel->spread);
153 gtk_box_pack_end (GTK_BOX (hb), sel->spread, FALSE, FALSE, 0);
154 gtk_tooltips_set_tip (ttips, sel->spread,
155 // TRANSLATORS: for info, see http://www.w3.org/TR/2000/CR-SVG-20000802/pservers.html#LinearGradientSpreadMethodAttribute
156 _("Whether to fill with flat color beyond the ends of the gradient vector "
157 "(spreadMethod=\"pad\"), or repeat the gradient in the same direction "
158 "(spreadMethod=\"repeat\"), or repeat the gradient in alternating opposite "
159 "directions (spreadMethod=\"reflect\")"), NULL);
161 m = gtk_menu_new ();
162 mi = gtk_menu_item_new_with_label (_("none"));
163 gtk_menu_append (GTK_MENU (m), mi);
164 g_object_set_data (G_OBJECT (mi), "gradientSpread", GUINT_TO_POINTER (SP_GRADIENT_SPREAD_PAD));
165 g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (sp_gradient_selector_spread_activate), sel);
166 mi = gtk_menu_item_new_with_label (_("reflected"));
167 g_object_set_data (G_OBJECT (mi), "gradientSpread", GUINT_TO_POINTER (SP_GRADIENT_SPREAD_REFLECT));
168 g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (sp_gradient_selector_spread_activate), sel);
169 gtk_menu_append (GTK_MENU (m), mi);
170 mi = gtk_menu_item_new_with_label (_("direct"));
171 g_object_set_data (G_OBJECT (mi), "gradientSpread", GUINT_TO_POINTER (SP_GRADIENT_SPREAD_REPEAT));
172 g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (sp_gradient_selector_spread_activate), sel);
173 gtk_menu_append (GTK_MENU (m), mi);
174 gtk_widget_show_all (m);
176 gtk_option_menu_set_menu (GTK_OPTION_MENU (sel->spread), m);
178 l = gtk_label_new (_("Repeat:"));
179 gtk_widget_show (l);
180 gtk_box_pack_end (GTK_BOX (hb), l, FALSE, FALSE, 4);
181 }
183 static void
184 sp_gradient_selector_destroy (GtkObject *object)
185 {
186 SPGradientSelector *sel;
188 sel = SP_GRADIENT_SELECTOR (object);
190 if (((GtkObjectClass *) (parent_class))->destroy)
191 (* ((GtkObjectClass *) (parent_class))->destroy) (object);
192 }
194 GtkWidget *
195 sp_gradient_selector_new (void)
196 {
197 SPGradientSelector *sel;
199 sel = (SPGradientSelector*)gtk_type_new (SP_TYPE_GRADIENT_SELECTOR);
201 return (GtkWidget *) sel;
202 }
204 void
205 sp_gradient_selector_set_mode (SPGradientSelector *sel, guint mode)
206 {
207 g_return_if_fail (sel != NULL);
208 g_return_if_fail (SP_IS_GRADIENT_SELECTOR (sel));
210 sel->mode = mode;
211 }
213 void
214 sp_gradient_selector_set_units (SPGradientSelector *sel, guint units)
215 {
216 g_return_if_fail (sel != NULL);
217 g_return_if_fail (SP_IS_GRADIENT_SELECTOR (sel));
219 sel->gradientUnits = (SPGradientUnits)units;
220 }
222 void
223 sp_gradient_selector_set_spread (SPGradientSelector *sel, guint spread)
224 {
225 g_return_if_fail (sel != NULL);
226 g_return_if_fail (SP_IS_GRADIENT_SELECTOR (sel));
228 sel->gradientSpread = (SPGradientSpread)spread;
230 gtk_option_menu_set_history (GTK_OPTION_MENU (sel->spread), sel->gradientSpread);
231 }
233 SPGradientUnits
234 sp_gradient_selector_get_units (SPGradientSelector *sel)
235 {
236 return (SPGradientUnits) sel->gradientUnits;
237 }
239 SPGradientSpread
240 sp_gradient_selector_get_spread (SPGradientSelector *sel)
241 {
242 return (SPGradientSpread) sel->gradientSpread;
243 }
245 void
246 sp_gradient_selector_set_vector (SPGradientSelector *sel, SPDocument *doc, SPGradient *vector)
247 {
248 g_return_if_fail (sel != NULL);
249 g_return_if_fail (SP_IS_GRADIENT_SELECTOR (sel));
250 g_return_if_fail (!vector || SP_IS_GRADIENT (vector));
251 g_return_if_fail (!vector || (SP_OBJECT_DOCUMENT (vector) == doc));
253 if (vector && !SP_GRADIENT_HAS_STOPS (vector))
254 return;
256 sp_gradient_vector_selector_set_gradient (SP_GRADIENT_VECTOR_SELECTOR (sel->vectors), doc, vector);
258 if (vector) {
259 gtk_widget_set_sensitive (sel->edit, TRUE);
260 gtk_widget_set_sensitive (sel->add, TRUE);
261 } else {
262 gtk_widget_set_sensitive (sel->edit, FALSE);
263 gtk_widget_set_sensitive (sel->add, (doc != NULL));
264 }
265 }
267 SPGradient *
268 sp_gradient_selector_get_vector (SPGradientSelector *sel)
269 {
270 if (sel == NULL || !SP_IS_GRADIENT_SELECTOR (sel))
271 return NULL;
273 /* fixme: */
274 return SP_GRADIENT_VECTOR_SELECTOR (sel->vectors)->gr;
275 }
277 static void
278 sp_gradient_selector_vector_set (SPGradientVectorSelector *gvs, SPGradient *gr, SPGradientSelector *sel)
279 {
280 static gboolean blocked = FALSE;
282 if (!blocked) {
283 blocked = TRUE;
284 gr = sp_gradient_ensure_vector_normalized (gr);
285 sp_gradient_selector_set_vector (sel, (gr) ? SP_OBJECT_DOCUMENT (gr) : NULL, gr);
286 g_signal_emit (G_OBJECT (sel), signals[CHANGED], 0, gr);
287 blocked = FALSE;
288 }
289 }
291 static void
292 sp_gradient_selector_edit_vector_clicked (GtkWidget *w, SPGradientSelector *sel)
293 {
294 GtkWidget *dialog;
296 /* fixme: */
297 dialog = sp_gradient_vector_editor_new (SP_GRADIENT_VECTOR_SELECTOR (sel->vectors)->gr);
299 gtk_widget_show (dialog);
300 }
302 static void
303 sp_gradient_selector_add_vector_clicked (GtkWidget *w, SPGradientSelector *sel)
304 {
305 SPDocument *doc = sp_gradient_vector_selector_get_document (
306 SP_GRADIENT_VECTOR_SELECTOR (sel->vectors));
308 if (!doc)
309 return;
311 SPGradient *gr = sp_gradient_vector_selector_get_gradient(
312 SP_GRADIENT_VECTOR_SELECTOR (sel->vectors));
313 Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
315 Inkscape::XML::Node *repr = NULL;
317 if (gr)
318 repr = SP_OBJECT_REPR (gr)->duplicate(xml_doc);
319 else {
320 repr = xml_doc->createElement("svg:linearGradient");
321 Inkscape::XML::Node *stop = xml_doc->createElement("svg:stop");
322 stop->setAttribute("offset", "0");
323 stop->setAttribute("style", "stop-color:#000;stop-opacity:1;");
324 repr->appendChild(stop);
325 Inkscape::GC::release(stop);
326 stop = xml_doc->createElement("svg:stop");
327 stop->setAttribute("offset", "1");
328 stop->setAttribute("style", "stop-color:#fff;stop-opacity:1;");
329 repr->appendChild(stop);
330 Inkscape::GC::release(stop);
331 }
333 SP_OBJECT_REPR (SP_DOCUMENT_DEFS (doc))->addChild(repr, NULL);
335 gr = (SPGradient *) doc->getObjectByRepr(repr);
336 sp_gradient_vector_selector_set_gradient(
337 SP_GRADIENT_VECTOR_SELECTOR (sel->vectors), doc, gr);
339 Inkscape::GC::release(repr);
340 }
344 static void
345 sp_gradient_selector_spread_activate (GtkWidget *widget, SPGradientSelector *sel)
346 {
347 sel->gradientSpread = (SPGradientSpread)GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget), "gradientSpread"));
349 g_signal_emit (G_OBJECT (sel), signals[CHANGED], 0);
350 }