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-private.h"
26 #include "../gradient-chemistry.h"
28 #include <glibmm/i18n.h>
29 #include <xml/repr.h>
31 #include "gradient-vector.h"
33 #include "gradient-selector.h"
35 enum {
36 GRABBED,
37 DRAGGED,
38 RELEASED,
39 CHANGED,
40 LAST_SIGNAL
41 };
43 static void sp_gradient_selector_class_init (SPGradientSelectorClass *klass);
44 static void sp_gradient_selector_init (SPGradientSelector *selector);
45 static void sp_gradient_selector_destroy (GtkObject *object);
47 /* Signal handlers */
48 static void sp_gradient_selector_vector_set (SPGradientVectorSelector *gvs, SPGradient *gr, SPGradientSelector *sel);
49 static void sp_gradient_selector_edit_vector_clicked (GtkWidget *w, SPGradientSelector *sel);
50 static void sp_gradient_selector_add_vector_clicked (GtkWidget *w, SPGradientSelector *sel);
52 static void sp_gradient_selector_spread_activate (GtkWidget *widget, SPGradientSelector *sel);
54 static GtkVBoxClass *parent_class;
55 static guint signals[LAST_SIGNAL] = {0};
57 GtkType
58 sp_gradient_selector_get_type (void)
59 {
60 static GtkType type = 0;
61 if (!type) {
62 GtkTypeInfo info = {
63 "SPGradientSelector",
64 sizeof (SPGradientSelector),
65 sizeof (SPGradientSelectorClass),
66 (GtkClassInitFunc) sp_gradient_selector_class_init,
67 (GtkObjectInitFunc) sp_gradient_selector_init,
68 NULL, NULL, NULL
69 };
70 type = gtk_type_unique (GTK_TYPE_VBOX, &info);
71 }
72 return type;
73 }
75 static void
76 sp_gradient_selector_class_init (SPGradientSelectorClass *klass)
77 {
78 GtkObjectClass *object_class;
80 object_class = (GtkObjectClass *) klass;
82 parent_class = (GtkVBoxClass*)gtk_type_class (GTK_TYPE_VBOX);
84 signals[GRABBED] = gtk_signal_new ("grabbed",
85 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
86 GTK_CLASS_TYPE(object_class),
87 GTK_SIGNAL_OFFSET (SPGradientSelectorClass, grabbed),
88 gtk_marshal_NONE__NONE,
89 GTK_TYPE_NONE, 0);
90 signals[DRAGGED] = gtk_signal_new ("dragged",
91 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
92 GTK_CLASS_TYPE(object_class),
93 GTK_SIGNAL_OFFSET (SPGradientSelectorClass, dragged),
94 gtk_marshal_NONE__NONE,
95 GTK_TYPE_NONE, 0);
96 signals[RELEASED] = gtk_signal_new ("released",
97 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
98 GTK_CLASS_TYPE(object_class),
99 GTK_SIGNAL_OFFSET (SPGradientSelectorClass, released),
100 gtk_marshal_NONE__NONE,
101 GTK_TYPE_NONE, 0);
102 signals[CHANGED] = gtk_signal_new ("changed",
103 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
104 GTK_CLASS_TYPE(object_class),
105 GTK_SIGNAL_OFFSET (SPGradientSelectorClass, changed),
106 gtk_marshal_NONE__NONE,
107 GTK_TYPE_NONE, 0);
109 object_class->destroy = sp_gradient_selector_destroy;
110 }
112 static void
113 sp_gradient_selector_init (SPGradientSelector *sel)
114 {
115 GtkWidget *hb, *l, *m, *mi;
117 sel->mode = SP_GRADIENT_SELECTOR_MODE_LINEAR;
119 sel->gradientUnits = SP_GRADIENT_UNITS_USERSPACEONUSE;
120 sel->gradientSpread = SP_GRADIENT_SPREAD_PAD;
122 /* Vectors */
123 sel->vectors = sp_gradient_vector_selector_new (NULL, NULL);
124 gtk_widget_show (sel->vectors);
125 gtk_box_pack_start (GTK_BOX (sel), sel->vectors, FALSE, FALSE, 0);
126 g_signal_connect (G_OBJECT (sel->vectors), "vector_set", G_CALLBACK (sp_gradient_selector_vector_set), sel);
128 /* Create box for buttons */
129 hb = gtk_hbox_new (FALSE, 0);
130 gtk_box_pack_start (GTK_BOX (sel), hb, FALSE, FALSE, 0);
131 GtkTooltips *ttips = gtk_tooltips_new ();
133 sel->add = gtk_button_new_with_label (_("Duplicate"));
134 gtk_box_pack_start (GTK_BOX (hb), sel->add, TRUE, TRUE, 0);
135 g_signal_connect (G_OBJECT (sel->add), "clicked", G_CALLBACK (sp_gradient_selector_add_vector_clicked), sel);
136 gtk_widget_set_sensitive (sel->add, FALSE);
138 sel->edit = gtk_button_new_with_label (_("Edit..."));
139 gtk_box_pack_start (GTK_BOX (hb), sel->edit, TRUE, TRUE, 0);
140 g_signal_connect (G_OBJECT (sel->edit), "clicked", G_CALLBACK (sp_gradient_selector_edit_vector_clicked), sel);
141 gtk_widget_set_sensitive (sel->edit, FALSE);
143 gtk_widget_show_all (hb);
145 /* Spread selector */
146 hb = gtk_hbox_new (FALSE, 0);
147 gtk_widget_show (hb);
148 gtk_box_pack_start (GTK_BOX (sel), hb, FALSE, FALSE, 0);
150 sel->spread = gtk_option_menu_new ();
151 gtk_widget_show (sel->spread);
152 gtk_box_pack_end (GTK_BOX (hb), sel->spread, FALSE, FALSE, 0);
153 gtk_tooltips_set_tip (ttips, sel->spread,
154 // TRANSLATORS: for info, see http://www.w3.org/TR/2000/CR-SVG-20000802/pservers.html#LinearGradientSpreadMethodAttribute
155 _("Whether to fill with flat color beyond the ends of the gradient vector "
156 "(spreadMethod=\"pad\"), or repeat the gradient in the same direction "
157 "(spreadMethod=\"repeat\"), or repeat the gradient in alternating opposite "
158 "directions (spreadMethod=\"reflect\")"), NULL);
160 m = gtk_menu_new ();
161 mi = gtk_menu_item_new_with_label (_("none"));
162 gtk_menu_append (GTK_MENU (m), mi);
163 g_object_set_data (G_OBJECT (mi), "gradientSpread", GUINT_TO_POINTER (SP_GRADIENT_SPREAD_PAD));
164 g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (sp_gradient_selector_spread_activate), sel);
165 mi = gtk_menu_item_new_with_label (_("reflected"));
166 g_object_set_data (G_OBJECT (mi), "gradientSpread", GUINT_TO_POINTER (SP_GRADIENT_SPREAD_REFLECT));
167 g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (sp_gradient_selector_spread_activate), sel);
168 gtk_menu_append (GTK_MENU (m), mi);
169 mi = gtk_menu_item_new_with_label (_("direct"));
170 g_object_set_data (G_OBJECT (mi), "gradientSpread", GUINT_TO_POINTER (SP_GRADIENT_SPREAD_REPEAT));
171 g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (sp_gradient_selector_spread_activate), sel);
172 gtk_menu_append (GTK_MENU (m), mi);
173 gtk_widget_show_all (m);
175 gtk_option_menu_set_menu (GTK_OPTION_MENU (sel->spread), m);
177 l = gtk_label_new (_("Repeat:"));
178 gtk_widget_show (l);
179 gtk_box_pack_end (GTK_BOX (hb), l, FALSE, FALSE, 4);
180 }
182 static void
183 sp_gradient_selector_destroy (GtkObject *object)
184 {
185 SPGradientSelector *sel;
187 sel = SP_GRADIENT_SELECTOR (object);
189 if (((GtkObjectClass *) (parent_class))->destroy)
190 (* ((GtkObjectClass *) (parent_class))->destroy) (object);
191 }
193 GtkWidget *
194 sp_gradient_selector_new (void)
195 {
196 SPGradientSelector *sel;
198 sel = (SPGradientSelector*)gtk_type_new (SP_TYPE_GRADIENT_SELECTOR);
200 return (GtkWidget *) sel;
201 }
203 void
204 sp_gradient_selector_set_mode (SPGradientSelector *sel, guint mode)
205 {
206 g_return_if_fail (sel != NULL);
207 g_return_if_fail (SP_IS_GRADIENT_SELECTOR (sel));
209 sel->mode = mode;
210 }
212 void
213 sp_gradient_selector_set_units (SPGradientSelector *sel, guint units)
214 {
215 g_return_if_fail (sel != NULL);
216 g_return_if_fail (SP_IS_GRADIENT_SELECTOR (sel));
218 sel->gradientUnits = (SPGradientUnits)units;
219 }
221 void
222 sp_gradient_selector_set_spread (SPGradientSelector *sel, guint spread)
223 {
224 g_return_if_fail (sel != NULL);
225 g_return_if_fail (SP_IS_GRADIENT_SELECTOR (sel));
227 sel->gradientSpread = (SPGradientSpread)spread;
229 gtk_option_menu_set_history (GTK_OPTION_MENU (sel->spread), sel->gradientSpread);
230 }
232 SPGradientUnits
233 sp_gradient_selector_get_units (SPGradientSelector *sel)
234 {
235 return (SPGradientUnits) sel->gradientUnits;
236 }
238 SPGradientSpread
239 sp_gradient_selector_get_spread (SPGradientSelector *sel)
240 {
241 return (SPGradientSpread) sel->gradientSpread;
242 }
244 void
245 sp_gradient_selector_set_vector (SPGradientSelector *sel, SPDocument *doc, SPGradient *vector)
246 {
247 g_return_if_fail (sel != NULL);
248 g_return_if_fail (SP_IS_GRADIENT_SELECTOR (sel));
249 g_return_if_fail (!vector || SP_IS_GRADIENT (vector));
250 g_return_if_fail (!vector || (SP_OBJECT_DOCUMENT (vector) == doc));
252 if (vector && !SP_GRADIENT_HAS_STOPS (vector))
253 return;
255 sp_gradient_vector_selector_set_gradient (SP_GRADIENT_VECTOR_SELECTOR (sel->vectors), doc, vector);
257 if (vector) {
258 gtk_widget_set_sensitive (sel->edit, TRUE);
259 gtk_widget_set_sensitive (sel->add, TRUE);
260 } else {
261 gtk_widget_set_sensitive (sel->edit, FALSE);
262 gtk_widget_set_sensitive (sel->add, (doc != NULL));
263 }
264 }
266 SPGradient *
267 sp_gradient_selector_get_vector (SPGradientSelector *sel)
268 {
269 if (sel == NULL || !SP_IS_GRADIENT_SELECTOR (sel))
270 return NULL;
272 /* fixme: */
273 return SP_GRADIENT_VECTOR_SELECTOR (sel->vectors)->gr;
274 }
276 static void
277 sp_gradient_selector_vector_set (SPGradientVectorSelector *gvs, SPGradient *gr, SPGradientSelector *sel)
278 {
279 static gboolean blocked = FALSE;
281 if (!blocked) {
282 blocked = TRUE;
283 gr = sp_gradient_ensure_vector_normalized (gr);
284 sp_gradient_selector_set_vector (sel, (gr) ? SP_OBJECT_DOCUMENT (gr) : NULL, gr);
285 g_signal_emit (G_OBJECT (sel), signals[CHANGED], 0, gr);
286 blocked = FALSE;
287 }
288 }
290 static void
291 sp_gradient_selector_edit_vector_clicked (GtkWidget *w, SPGradientSelector *sel)
292 {
293 GtkWidget *dialog;
295 /* fixme: */
296 dialog = sp_gradient_vector_editor_new (SP_GRADIENT_VECTOR_SELECTOR (sel->vectors)->gr);
298 gtk_widget_show (dialog);
299 }
301 static void
302 sp_gradient_selector_add_vector_clicked (GtkWidget *w, SPGradientSelector *sel)
303 {
304 SPDocument *doc;
305 SPGradient *gr;
306 Inkscape::XML::Node *repr;
308 doc = sp_gradient_vector_selector_get_document (SP_GRADIENT_VECTOR_SELECTOR (sel->vectors));
309 if (!doc) return;
310 gr = sp_gradient_vector_selector_get_gradient (SP_GRADIENT_VECTOR_SELECTOR (sel->vectors));
312 if (gr) {
313 repr = SP_OBJECT_REPR (gr)->duplicate();
314 } else {
315 Inkscape::XML::Node *stop;
316 repr = sp_repr_new ("svg:linearGradient");
317 stop = sp_repr_new ("svg:stop");
318 stop->setAttribute("offset", "0");
319 stop->setAttribute("style", "stop-color:#000;stop-opacity:1;");
320 repr->appendChild(stop);
321 Inkscape::GC::release(stop);
322 stop = sp_repr_new ("svg:stop");
323 stop->setAttribute("offset", "1");
324 stop->setAttribute("style", "stop-color:#fff;stop-opacity:1;");
325 repr->appendChild(stop);
326 Inkscape::GC::release(stop);
327 }
329 SP_OBJECT_REPR (SP_DOCUMENT_DEFS (doc))->addChild(repr, NULL);
330 Inkscape::GC::release(repr);
332 gr = (SPGradient *) doc->getObjectByRepr(repr);
333 sp_gradient_vector_selector_set_gradient (SP_GRADIENT_VECTOR_SELECTOR (sel->vectors), doc, gr);
334 }
336 static void
337 sp_gradient_selector_spread_activate (GtkWidget *widget, SPGradientSelector *sel)
338 {
339 sel->gradientSpread = (SPGradientSpread)GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget), "gradientSpread"));
341 g_signal_emit (G_OBJECT (sel), signals[CHANGED], 0);
342 }