1 /*
2 * Gradient vector widget
3 *
4 * Authors:
5 * Lauris Kaplinski <lauris@kaplinski.com>
6 * bulia byak <buliabyak@users.sf.net>
7 * Jon A. Cruz <jon@joncruz.org>
8 *
9 * Copyright (C) 2001-2002 Lauris Kaplinski
10 * Copyright (C) 2001 Ximian, Inc.
11 * Copyright (C) 2010 Jon A. Cruz
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 GType sp_gradient_selector_get_type(void)
59 {
60 static GType type = 0;
61 if (!type) {
62 static const GTypeInfo info = {
63 sizeof(SPGradientSelectorClass),
64 NULL, /* base_init */
65 NULL, /* base_finalize */
66 (GClassInitFunc) sp_gradient_selector_class_init,
67 NULL, /* class_finalize */
68 NULL, /* class_data */
69 sizeof(SPGradientSelector),
70 0, /* n_preallocs */
71 (GInstanceInitFunc) sp_gradient_selector_init,
72 0, /* value_table */
73 };
75 type = g_type_register_static( GTK_TYPE_VBOX,
76 "SPGradientSelector",
77 &info,
78 static_cast< GTypeFlags > (0) );
79 }
80 return type;
81 }
83 static void
84 sp_gradient_selector_class_init (SPGradientSelectorClass *klass)
85 {
86 GtkObjectClass *object_class;
88 object_class = (GtkObjectClass *) klass;
90 parent_class = (GtkVBoxClass*)gtk_type_class (GTK_TYPE_VBOX);
92 signals[GRABBED] = gtk_signal_new ("grabbed",
93 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
94 GTK_CLASS_TYPE(object_class),
95 GTK_SIGNAL_OFFSET (SPGradientSelectorClass, grabbed),
96 gtk_marshal_NONE__NONE,
97 GTK_TYPE_NONE, 0);
98 signals[DRAGGED] = gtk_signal_new ("dragged",
99 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
100 GTK_CLASS_TYPE(object_class),
101 GTK_SIGNAL_OFFSET (SPGradientSelectorClass, dragged),
102 gtk_marshal_NONE__NONE,
103 GTK_TYPE_NONE, 0);
104 signals[RELEASED] = gtk_signal_new ("released",
105 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
106 GTK_CLASS_TYPE(object_class),
107 GTK_SIGNAL_OFFSET (SPGradientSelectorClass, released),
108 gtk_marshal_NONE__NONE,
109 GTK_TYPE_NONE, 0);
110 signals[CHANGED] = gtk_signal_new ("changed",
111 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
112 GTK_CLASS_TYPE(object_class),
113 GTK_SIGNAL_OFFSET (SPGradientSelectorClass, changed),
114 gtk_marshal_NONE__NONE,
115 GTK_TYPE_NONE, 0);
117 object_class->destroy = sp_gradient_selector_destroy;
118 }
120 static void
121 sp_gradient_selector_init (SPGradientSelector *sel)
122 {
123 GtkWidget *hb, *m, *mi;
125 sel->mode = SPGradientSelector::MODE_LINEAR;
127 sel->gradientUnits = SP_GRADIENT_UNITS_USERSPACEONUSE;
128 sel->gradientSpread = SP_GRADIENT_SPREAD_PAD;
130 /* Vectors */
131 sel->vectors = sp_gradient_vector_selector_new (NULL, NULL);
132 gtk_widget_show (sel->vectors);
133 gtk_box_pack_start (GTK_BOX (sel), sel->vectors, FALSE, FALSE, 0);
134 g_signal_connect (G_OBJECT (sel->vectors), "vector_set", G_CALLBACK (sp_gradient_selector_vector_set), sel);
136 /* Create box for buttons */
137 hb = gtk_hbox_new (FALSE, 0);
138 gtk_box_pack_start (GTK_BOX (sel), hb, FALSE, FALSE, 0);
139 GtkTooltips *ttips = gtk_tooltips_new ();
141 sel->add = gtk_button_new_with_label (_("Duplicate"));
142 gtk_box_pack_start (GTK_BOX (hb), sel->add, TRUE, TRUE, 0);
143 g_signal_connect (G_OBJECT (sel->add), "clicked", G_CALLBACK (sp_gradient_selector_add_vector_clicked), sel);
144 gtk_widget_set_sensitive (sel->add, FALSE);
146 sel->edit = gtk_button_new_with_label (_("Edit..."));
147 gtk_box_pack_start (GTK_BOX (hb), sel->edit, TRUE, TRUE, 0);
148 g_signal_connect (G_OBJECT (sel->edit), "clicked", G_CALLBACK (sp_gradient_selector_edit_vector_clicked), sel);
149 gtk_widget_set_sensitive (sel->edit, FALSE);
151 gtk_widget_show_all (hb);
153 /* Spread selector */
154 hb = gtk_hbox_new (FALSE, 0);
155 gtk_widget_show (hb);
156 gtk_box_pack_start (GTK_BOX (sel), hb, FALSE, FALSE, 0);
158 sel->spread = gtk_option_menu_new ();
159 gtk_widget_show (sel->spread);
160 gtk_box_pack_end (GTK_BOX (hb), sel->spread, FALSE, FALSE, 0);
161 gtk_tooltips_set_tip (ttips, sel->spread,
162 // TRANSLATORS: for info, see http://www.w3.org/TR/2000/CR-SVG-20000802/pservers.html#LinearGradientSpreadMethodAttribute
163 _("Whether to fill with flat color beyond the ends of the gradient vector "
164 "(spreadMethod=\"pad\"), or repeat the gradient in the same direction "
165 "(spreadMethod=\"repeat\"), or repeat the gradient in alternating opposite "
166 "directions (spreadMethod=\"reflect\")"), NULL);
168 m = gtk_menu_new ();
169 mi = gtk_menu_item_new_with_label (_("none"));
170 gtk_menu_append (GTK_MENU (m), mi);
171 g_object_set_data (G_OBJECT (mi), "gradientSpread", GUINT_TO_POINTER (SP_GRADIENT_SPREAD_PAD));
172 g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (sp_gradient_selector_spread_activate), sel);
173 mi = gtk_menu_item_new_with_label (_("reflected"));
174 g_object_set_data (G_OBJECT (mi), "gradientSpread", GUINT_TO_POINTER (SP_GRADIENT_SPREAD_REFLECT));
175 g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (sp_gradient_selector_spread_activate), sel);
176 gtk_menu_append (GTK_MENU (m), mi);
177 mi = gtk_menu_item_new_with_label (_("direct"));
178 g_object_set_data (G_OBJECT (mi), "gradientSpread", GUINT_TO_POINTER (SP_GRADIENT_SPREAD_REPEAT));
179 g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (sp_gradient_selector_spread_activate), sel);
180 gtk_menu_append (GTK_MENU (m), mi);
181 gtk_widget_show_all (m);
183 gtk_option_menu_set_menu (GTK_OPTION_MENU (sel->spread), m);
185 sel->spreadLbl = gtk_label_new (_("Repeat:"));
186 gtk_widget_show(sel->spreadLbl);
187 gtk_box_pack_end(GTK_BOX(hb), sel->spreadLbl, FALSE, FALSE, 4);
188 }
190 static void
191 sp_gradient_selector_destroy (GtkObject *object)
192 {
193 SPGradientSelector *sel;
195 sel = SP_GRADIENT_SELECTOR (object);
197 if (((GtkObjectClass *) (parent_class))->destroy)
198 (* ((GtkObjectClass *) (parent_class))->destroy) (object);
199 }
201 GtkWidget *
202 sp_gradient_selector_new (void)
203 {
204 SPGradientSelector *sel;
206 sel = (SPGradientSelector*)gtk_type_new (SP_TYPE_GRADIENT_SELECTOR);
208 return (GtkWidget *) sel;
209 }
211 void SPGradientSelector::setMode(SelectorMode mode)
212 {
213 if (mode != this->mode) {
214 this->mode = mode;
215 if (mode == MODE_SWATCH) {
216 if (spread) {
217 GtkWidget *parent = gtk_widget_get_parent(spread);
218 if (parent) {
219 gtk_container_remove(GTK_CONTAINER(parent), spread);
220 spread = 0;
221 }
222 }
223 if (spreadLbl) {
224 GtkWidget *parent = gtk_widget_get_parent(spreadLbl);
225 if (parent) {
226 gtk_container_remove(GTK_CONTAINER(parent), spreadLbl);
227 spreadLbl = 0;
228 }
229 }
231 SPGradientVectorSelector* vs = SP_GRADIENT_VECTOR_SELECTOR(vectors);
232 vs->setSwatched();
233 }
234 }
235 }
237 void SPGradientSelector::setUnits(SPGradientUnits units)
238 {
239 gradientUnits = units;
240 }
242 void SPGradientSelector::setSpread(SPGradientSpread spread)
243 {
244 gradientSpread = spread;
246 gtk_option_menu_set_history(GTK_OPTION_MENU(this->spread), gradientSpread);
247 }
249 SPGradientUnits SPGradientSelector::getUnits()
250 {
251 return gradientUnits;
252 }
254 SPGradientSpread SPGradientSelector::getSpread()
255 {
256 return gradientSpread;
257 }
259 void SPGradientSelector::setVector(SPDocument *doc, SPGradient *vector)
260 {
261 g_return_if_fail(!vector || SP_IS_GRADIENT(vector));
262 g_return_if_fail(!vector || (SP_OBJECT_DOCUMENT(vector) == doc));
264 if (vector && !SP_GRADIENT_HAS_STOPS(vector)) {
265 return;
266 }
268 sp_gradient_vector_selector_set_gradient(SP_GRADIENT_VECTOR_SELECTOR(vectors), doc, vector);
270 if (vector) {
271 gtk_widget_set_sensitive(edit, TRUE);
272 gtk_widget_set_sensitive(add, TRUE);
273 } else {
274 gtk_widget_set_sensitive(edit, FALSE);
275 gtk_widget_set_sensitive(add, (doc != NULL));
276 }
277 }
279 SPGradient *SPGradientSelector::getVector()
280 {
281 /* fixme: */
282 return SP_GRADIENT_VECTOR_SELECTOR(vectors)->gr;
283 }
285 static void
286 sp_gradient_selector_vector_set (SPGradientVectorSelector */*gvs*/, SPGradient *gr, SPGradientSelector *sel)
287 {
288 static gboolean blocked = FALSE;
290 if (!blocked) {
291 blocked = TRUE;
292 gr = sp_gradient_ensure_vector_normalized (gr);
293 sel->setVector((gr) ? SP_OBJECT_DOCUMENT (gr) : 0, gr);
294 g_signal_emit (G_OBJECT (sel), signals[CHANGED], 0, gr);
295 blocked = FALSE;
296 }
297 }
299 static void
300 sp_gradient_selector_edit_vector_clicked (GtkWidget */*w*/, SPGradientSelector *sel)
301 {
302 GtkWidget *dialog;
304 /* fixme: */
305 dialog = sp_gradient_vector_editor_new (SP_GRADIENT_VECTOR_SELECTOR (sel->vectors)->gr);
307 gtk_widget_show (dialog);
308 }
310 static void
311 sp_gradient_selector_add_vector_clicked (GtkWidget */*w*/, SPGradientSelector *sel)
312 {
313 SPDocument *doc = sp_gradient_vector_selector_get_document (
314 SP_GRADIENT_VECTOR_SELECTOR (sel->vectors));
316 if (!doc)
317 return;
319 SPGradient *gr = sp_gradient_vector_selector_get_gradient(
320 SP_GRADIENT_VECTOR_SELECTOR (sel->vectors));
321 Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
323 Inkscape::XML::Node *repr = NULL;
325 if (gr)
326 repr = SP_OBJECT_REPR (gr)->duplicate(xml_doc);
327 else {
328 repr = xml_doc->createElement("svg:linearGradient");
329 Inkscape::XML::Node *stop = xml_doc->createElement("svg:stop");
330 stop->setAttribute("offset", "0");
331 stop->setAttribute("style", "stop-color:#000;stop-opacity:1;");
332 repr->appendChild(stop);
333 Inkscape::GC::release(stop);
334 stop = xml_doc->createElement("svg:stop");
335 stop->setAttribute("offset", "1");
336 stop->setAttribute("style", "stop-color:#fff;stop-opacity:1;");
337 repr->appendChild(stop);
338 Inkscape::GC::release(stop);
339 }
341 SP_OBJECT_REPR (SP_DOCUMENT_DEFS (doc))->addChild(repr, NULL);
343 gr = (SPGradient *) doc->getObjectByRepr(repr);
344 sp_gradient_vector_selector_set_gradient(
345 SP_GRADIENT_VECTOR_SELECTOR (sel->vectors), doc, gr);
347 Inkscape::GC::release(repr);
348 }
352 static void
353 sp_gradient_selector_spread_activate (GtkWidget *widget, SPGradientSelector *sel)
354 {
355 sel->gradientSpread = (SPGradientSpread)GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget), "gradientSpread"));
357 g_signal_emit (G_OBJECT (sel), signals[CHANGED], 0);
358 }
361 /*
362 Local Variables:
363 mode:c++
364 c-file-style:"stroustrup"
365 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
366 indent-tabs-mode:nil
367 fill-column:99
368 End:
369 */
370 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :