1 /*
2 * Gradient vector widget
3 *
4 * Authors:
5 * Lauris Kaplinski <lauris@kaplinski.com>
6 * bulia byak <buliabyak@users.sf.net>
7 *
8 * Copyright (C) 2001-2002 Lauris Kaplinski
9 * Copyright (C) 2001 Ximian, Inc.
10 *
11 * Released under GNU GPL, read the file 'COPYING' for more information
12 */
14 #ifdef HAVE_CONFIG_H
15 # include "config.h"
16 #endif
17 #include <gtk/gtkhbox.h>
18 #include <gtk/gtklabel.h>
19 #include <gtk/gtkoptionmenu.h>
20 #include <gtk/gtkmenuitem.h>
21 #include <gtk/gtktooltips.h>
23 #include "document.h"
24 #include "../document-private.h"
25 #include "../gradient-chemistry.h"
27 #include <glibmm/i18n.h>
28 #include <xml/repr.h>
30 #include "gradient-vector.h"
32 #include "gradient-selector.h"
34 enum {
35 GRABBED,
36 DRAGGED,
37 RELEASED,
38 CHANGED,
39 LAST_SIGNAL
40 };
42 static void sp_gradient_selector_class_init (SPGradientSelectorClass *klass);
43 static void sp_gradient_selector_init (SPGradientSelector *selector);
44 static void sp_gradient_selector_destroy (GtkObject *object);
46 /* Signal handlers */
47 static void sp_gradient_selector_vector_set (SPGradientVectorSelector *gvs, SPGradient *gr, SPGradientSelector *sel);
48 static void sp_gradient_selector_edit_vector_clicked (GtkWidget *w, SPGradientSelector *sel);
49 static void sp_gradient_selector_add_vector_clicked (GtkWidget *w, SPGradientSelector *sel);
51 static void sp_gradient_selector_spread_activate (GtkWidget *widget, SPGradientSelector *sel);
53 static GtkVBoxClass *parent_class;
54 static guint signals[LAST_SIGNAL] = {0};
56 GType sp_gradient_selector_get_type(void)
57 {
58 static GType type = 0;
59 if (!type) {
60 static const GTypeInfo info = {
61 sizeof(SPGradientSelectorClass),
62 NULL, /* base_init */
63 NULL, /* base_finalize */
64 (GClassInitFunc) sp_gradient_selector_class_init,
65 NULL, /* class_finalize */
66 NULL, /* class_data */
67 sizeof(SPGradientSelector),
68 0, /* n_preallocs */
69 (GInstanceInitFunc) sp_gradient_selector_init,
70 0, /* value_table */
71 };
73 type = g_type_register_static( GTK_TYPE_VBOX,
74 "SPGradientSelector",
75 &info,
76 static_cast< GTypeFlags > (0) );
77 }
78 return type;
79 }
81 static void
82 sp_gradient_selector_class_init (SPGradientSelectorClass *klass)
83 {
84 GtkObjectClass *object_class;
86 object_class = (GtkObjectClass *) klass;
88 parent_class = (GtkVBoxClass*)gtk_type_class (GTK_TYPE_VBOX);
90 signals[GRABBED] = gtk_signal_new ("grabbed",
91 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
92 GTK_CLASS_TYPE(object_class),
93 GTK_SIGNAL_OFFSET (SPGradientSelectorClass, grabbed),
94 gtk_marshal_NONE__NONE,
95 GTK_TYPE_NONE, 0);
96 signals[DRAGGED] = gtk_signal_new ("dragged",
97 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
98 GTK_CLASS_TYPE(object_class),
99 GTK_SIGNAL_OFFSET (SPGradientSelectorClass, dragged),
100 gtk_marshal_NONE__NONE,
101 GTK_TYPE_NONE, 0);
102 signals[RELEASED] = gtk_signal_new ("released",
103 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
104 GTK_CLASS_TYPE(object_class),
105 GTK_SIGNAL_OFFSET (SPGradientSelectorClass, released),
106 gtk_marshal_NONE__NONE,
107 GTK_TYPE_NONE, 0);
108 signals[CHANGED] = gtk_signal_new ("changed",
109 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
110 GTK_CLASS_TYPE(object_class),
111 GTK_SIGNAL_OFFSET (SPGradientSelectorClass, changed),
112 gtk_marshal_NONE__NONE,
113 GTK_TYPE_NONE, 0);
115 object_class->destroy = sp_gradient_selector_destroy;
116 }
118 static void
119 sp_gradient_selector_init (SPGradientSelector *sel)
120 {
121 GtkWidget *hb, *l, *m, *mi;
123 sel->mode = SP_GRADIENT_SELECTOR_MODE_LINEAR;
125 sel->gradientUnits = SP_GRADIENT_UNITS_USERSPACEONUSE;
126 sel->gradientSpread = SP_GRADIENT_SPREAD_PAD;
128 /* Vectors */
129 sel->vectors = sp_gradient_vector_selector_new (NULL, NULL);
130 gtk_widget_show (sel->vectors);
131 gtk_box_pack_start (GTK_BOX (sel), sel->vectors, FALSE, FALSE, 0);
132 g_signal_connect (G_OBJECT (sel->vectors), "vector_set", G_CALLBACK (sp_gradient_selector_vector_set), sel);
134 /* Create box for buttons */
135 hb = gtk_hbox_new (FALSE, 0);
136 gtk_box_pack_start (GTK_BOX (sel), hb, FALSE, FALSE, 0);
137 GtkTooltips *ttips = gtk_tooltips_new ();
139 sel->add = gtk_button_new_with_label (_("Duplicate"));
140 gtk_box_pack_start (GTK_BOX (hb), sel->add, TRUE, TRUE, 0);
141 g_signal_connect (G_OBJECT (sel->add), "clicked", G_CALLBACK (sp_gradient_selector_add_vector_clicked), sel);
142 gtk_widget_set_sensitive (sel->add, FALSE);
144 sel->edit = gtk_button_new_with_label (_("Edit..."));
145 gtk_box_pack_start (GTK_BOX (hb), sel->edit, TRUE, TRUE, 0);
146 g_signal_connect (G_OBJECT (sel->edit), "clicked", G_CALLBACK (sp_gradient_selector_edit_vector_clicked), sel);
147 gtk_widget_set_sensitive (sel->edit, FALSE);
149 gtk_widget_show_all (hb);
151 /* Spread selector */
152 hb = gtk_hbox_new (FALSE, 0);
153 gtk_widget_show (hb);
154 gtk_box_pack_start (GTK_BOX (sel), hb, FALSE, FALSE, 0);
156 sel->spread = gtk_option_menu_new ();
157 gtk_widget_show (sel->spread);
158 gtk_box_pack_end (GTK_BOX (hb), sel->spread, FALSE, FALSE, 0);
159 gtk_tooltips_set_tip (ttips, sel->spread,
160 // TRANSLATORS: for info, see http://www.w3.org/TR/2000/CR-SVG-20000802/pservers.html#LinearGradientSpreadMethodAttribute
161 _("Whether to fill with flat color beyond the ends of the gradient vector "
162 "(spreadMethod=\"pad\"), or repeat the gradient in the same direction "
163 "(spreadMethod=\"repeat\"), or repeat the gradient in alternating opposite "
164 "directions (spreadMethod=\"reflect\")"), NULL);
166 m = gtk_menu_new ();
167 mi = gtk_menu_item_new_with_label (_("none"));
168 gtk_menu_append (GTK_MENU (m), mi);
169 g_object_set_data (G_OBJECT (mi), "gradientSpread", GUINT_TO_POINTER (SP_GRADIENT_SPREAD_PAD));
170 g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (sp_gradient_selector_spread_activate), sel);
171 mi = gtk_menu_item_new_with_label (_("reflected"));
172 g_object_set_data (G_OBJECT (mi), "gradientSpread", GUINT_TO_POINTER (SP_GRADIENT_SPREAD_REFLECT));
173 g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (sp_gradient_selector_spread_activate), sel);
174 gtk_menu_append (GTK_MENU (m), mi);
175 mi = gtk_menu_item_new_with_label (_("direct"));
176 g_object_set_data (G_OBJECT (mi), "gradientSpread", GUINT_TO_POINTER (SP_GRADIENT_SPREAD_REPEAT));
177 g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (sp_gradient_selector_spread_activate), sel);
178 gtk_menu_append (GTK_MENU (m), mi);
179 gtk_widget_show_all (m);
181 gtk_option_menu_set_menu (GTK_OPTION_MENU (sel->spread), m);
183 l = gtk_label_new (_("Repeat:"));
184 gtk_widget_show (l);
185 gtk_box_pack_end (GTK_BOX (hb), l, FALSE, FALSE, 4);
186 }
188 static void
189 sp_gradient_selector_destroy (GtkObject *object)
190 {
191 SPGradientSelector *sel;
193 sel = SP_GRADIENT_SELECTOR (object);
195 if (((GtkObjectClass *) (parent_class))->destroy)
196 (* ((GtkObjectClass *) (parent_class))->destroy) (object);
197 }
199 GtkWidget *
200 sp_gradient_selector_new (void)
201 {
202 SPGradientSelector *sel;
204 sel = (SPGradientSelector*)gtk_type_new (SP_TYPE_GRADIENT_SELECTOR);
206 return (GtkWidget *) sel;
207 }
209 void
210 sp_gradient_selector_set_mode (SPGradientSelector *sel, guint mode)
211 {
212 g_return_if_fail (sel != NULL);
213 g_return_if_fail (SP_IS_GRADIENT_SELECTOR (sel));
215 sel->mode = mode;
216 }
218 void
219 sp_gradient_selector_set_units (SPGradientSelector *sel, guint units)
220 {
221 g_return_if_fail (sel != NULL);
222 g_return_if_fail (SP_IS_GRADIENT_SELECTOR (sel));
224 sel->gradientUnits = (SPGradientUnits)units;
225 }
227 void
228 sp_gradient_selector_set_spread (SPGradientSelector *sel, guint spread)
229 {
230 g_return_if_fail (sel != NULL);
231 g_return_if_fail (SP_IS_GRADIENT_SELECTOR (sel));
233 sel->gradientSpread = (SPGradientSpread)spread;
235 gtk_option_menu_set_history (GTK_OPTION_MENU (sel->spread), sel->gradientSpread);
236 }
238 SPGradientUnits
239 sp_gradient_selector_get_units (SPGradientSelector *sel)
240 {
241 return (SPGradientUnits) sel->gradientUnits;
242 }
244 SPGradientSpread
245 sp_gradient_selector_get_spread (SPGradientSelector *sel)
246 {
247 return (SPGradientSpread) sel->gradientSpread;
248 }
250 void
251 sp_gradient_selector_set_vector (SPGradientSelector *sel, SPDocument *doc, SPGradient *vector)
252 {
253 g_return_if_fail (sel != NULL);
254 g_return_if_fail (SP_IS_GRADIENT_SELECTOR (sel));
255 g_return_if_fail (!vector || SP_IS_GRADIENT (vector));
256 g_return_if_fail (!vector || (SP_OBJECT_DOCUMENT (vector) == doc));
258 if (vector && !SP_GRADIENT_HAS_STOPS (vector))
259 return;
261 sp_gradient_vector_selector_set_gradient (SP_GRADIENT_VECTOR_SELECTOR (sel->vectors), doc, vector);
263 if (vector) {
264 gtk_widget_set_sensitive (sel->edit, TRUE);
265 gtk_widget_set_sensitive (sel->add, TRUE);
266 } else {
267 gtk_widget_set_sensitive (sel->edit, FALSE);
268 gtk_widget_set_sensitive (sel->add, (doc != NULL));
269 }
270 }
272 SPGradient *
273 sp_gradient_selector_get_vector (SPGradientSelector *sel)
274 {
275 if (sel == NULL || !SP_IS_GRADIENT_SELECTOR (sel))
276 return NULL;
278 /* fixme: */
279 return SP_GRADIENT_VECTOR_SELECTOR (sel->vectors)->gr;
280 }
282 static void
283 sp_gradient_selector_vector_set (SPGradientVectorSelector */*gvs*/, SPGradient *gr, SPGradientSelector *sel)
284 {
285 static gboolean blocked = FALSE;
287 if (!blocked) {
288 blocked = TRUE;
289 gr = sp_gradient_ensure_vector_normalized (gr);
290 sp_gradient_selector_set_vector (sel, (gr) ? SP_OBJECT_DOCUMENT (gr) : NULL, gr);
291 g_signal_emit (G_OBJECT (sel), signals[CHANGED], 0, gr);
292 blocked = FALSE;
293 }
294 }
296 static void
297 sp_gradient_selector_edit_vector_clicked (GtkWidget */*w*/, SPGradientSelector *sel)
298 {
299 GtkWidget *dialog;
301 /* fixme: */
302 dialog = sp_gradient_vector_editor_new (SP_GRADIENT_VECTOR_SELECTOR (sel->vectors)->gr);
304 gtk_widget_show (dialog);
305 }
307 static void
308 sp_gradient_selector_add_vector_clicked (GtkWidget */*w*/, SPGradientSelector *sel)
309 {
310 SPDocument *doc = sp_gradient_vector_selector_get_document (
311 SP_GRADIENT_VECTOR_SELECTOR (sel->vectors));
313 if (!doc)
314 return;
316 SPGradient *gr = sp_gradient_vector_selector_get_gradient(
317 SP_GRADIENT_VECTOR_SELECTOR (sel->vectors));
318 Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
320 Inkscape::XML::Node *repr = NULL;
322 if (gr)
323 repr = SP_OBJECT_REPR (gr)->duplicate(xml_doc);
324 else {
325 repr = xml_doc->createElement("svg:linearGradient");
326 Inkscape::XML::Node *stop = xml_doc->createElement("svg:stop");
327 stop->setAttribute("offset", "0");
328 stop->setAttribute("style", "stop-color:#000;stop-opacity:1;");
329 repr->appendChild(stop);
330 Inkscape::GC::release(stop);
331 stop = xml_doc->createElement("svg:stop");
332 stop->setAttribute("offset", "1");
333 stop->setAttribute("style", "stop-color:#fff;stop-opacity:1;");
334 repr->appendChild(stop);
335 Inkscape::GC::release(stop);
336 }
338 SP_OBJECT_REPR (SP_DOCUMENT_DEFS (doc))->addChild(repr, NULL);
340 gr = (SPGradient *) doc->getObjectByRepr(repr);
341 sp_gradient_vector_selector_set_gradient(
342 SP_GRADIENT_VECTOR_SELECTOR (sel->vectors), doc, gr);
344 Inkscape::GC::release(repr);
345 }
349 static void
350 sp_gradient_selector_spread_activate (GtkWidget *widget, SPGradientSelector *sel)
351 {
352 sel->gradientSpread = (SPGradientSpread)GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget), "gradientSpread"));
354 g_signal_emit (G_OBJECT (sel), signals[CHANGED], 0);
355 }
358 /*
359 Local Variables:
360 mode:c++
361 c-file-style:"stroustrup"
362 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
363 indent-tabs-mode:nil
364 fill-column:99
365 End:
366 */
367 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :