Code

Merge and cleanup of GSoC C++-ification project.
[inkscape.git] / src / widgets / gradient-selector.cpp
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;
120 static void sp_gradient_selector_init(SPGradientSelector *sel)
122     sel->safelyInit = true;
123     new (&sel->nonsolid) std::vector<GtkWidget*>();
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     GtkWidget *hb = gtk_hbox_new( FALSE, 0 );
138     sel->nonsolid.push_back(hb);
139     gtk_box_pack_start( GTK_BOX(sel), hb, FALSE, FALSE, 0 );
140     GtkTooltips *ttips = gtk_tooltips_new ();
142     sel->add = gtk_button_new_with_label (_("Duplicate"));
143     sel->nonsolid.push_back(sel->add);
144     gtk_box_pack_start (GTK_BOX (hb), sel->add, TRUE, TRUE, 0);
145     g_signal_connect (G_OBJECT (sel->add), "clicked", G_CALLBACK (sp_gradient_selector_add_vector_clicked), sel);
146     gtk_widget_set_sensitive (sel->add, FALSE);
148     sel->edit = gtk_button_new_with_label (_("Edit..."));
149     sel->nonsolid.push_back(sel->edit);
150     gtk_box_pack_start (GTK_BOX (hb), sel->edit, TRUE, TRUE, 0);
151     g_signal_connect (G_OBJECT (sel->edit), "clicked", G_CALLBACK (sp_gradient_selector_edit_vector_clicked), sel);
152     gtk_widget_set_sensitive (sel->edit, FALSE);
154     gtk_widget_show_all(hb);
156     /* Spread selector */
157     hb = gtk_hbox_new( FALSE, 0 );
158     sel->nonsolid.push_back(hb);
159     gtk_widget_show(hb);
160     gtk_box_pack_start( GTK_BOX(sel), hb, FALSE, FALSE, 0 );
162     sel->spread = gtk_option_menu_new();
163     sel->nonsolid.push_back(sel->spread);
164     gtk_widget_show(sel->spread);
165     gtk_box_pack_end( GTK_BOX(hb), sel->spread, FALSE, FALSE, 0 );
166     gtk_tooltips_set_tip( ttips, sel->spread,
167                           // TRANSLATORS: for info, see http://www.w3.org/TR/2000/CR-SVG-20000802/pservers.html#LinearGradientSpreadMethodAttribute
168                           _("Whether to fill with flat color beyond the ends of the gradient vector "
169                             "(spreadMethod=\"pad\"), or repeat the gradient in the same direction "
170                             "(spreadMethod=\"repeat\"), or repeat the gradient in alternating opposite "
171                             "directions (spreadMethod=\"reflect\")"), NULL);
173     GtkWidget *m = gtk_menu_new();
174     GtkWidget *mi = gtk_menu_item_new_with_label(_("none"));
175     gtk_menu_append (GTK_MENU (m), mi);
176     g_object_set_data (G_OBJECT (mi), "gradientSpread", GUINT_TO_POINTER (SP_GRADIENT_SPREAD_PAD));
177     g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (sp_gradient_selector_spread_activate), sel);
178     mi = gtk_menu_item_new_with_label (_("reflected"));
179     g_object_set_data (G_OBJECT (mi), "gradientSpread", GUINT_TO_POINTER (SP_GRADIENT_SPREAD_REFLECT));
180     g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (sp_gradient_selector_spread_activate), sel);
181     gtk_menu_append (GTK_MENU (m), mi);
182     mi = gtk_menu_item_new_with_label (_("direct"));
183     g_object_set_data (G_OBJECT (mi), "gradientSpread", GUINT_TO_POINTER (SP_GRADIENT_SPREAD_REPEAT));
184     g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (sp_gradient_selector_spread_activate), sel);
185     gtk_menu_append (GTK_MENU (m), mi);
186     gtk_widget_show_all (m);
188     gtk_option_menu_set_menu( GTK_OPTION_MENU(sel->spread), m );
190     sel->spreadLbl = gtk_label_new( _("Repeat:") );
191     sel->nonsolid.push_back(sel->spreadLbl);
192     gtk_widget_show( sel->spreadLbl );
193     gtk_box_pack_end( GTK_BOX(hb), sel->spreadLbl, FALSE, FALSE, 4 );
196 static void sp_gradient_selector_destroy(GtkObject *object)
198     SPGradientSelector *sel = SP_GRADIENT_SELECTOR( object );
200     if ( sel->safelyInit ) {
201         sel->safelyInit = false;
202         using std::vector;
203         sel->nonsolid.~vector<GtkWidget*>();
204     }
206     if (((GtkObjectClass *) (parent_class))->destroy) {
207         (* ((GtkObjectClass *) (parent_class))->destroy) (object);
208     }
211 GtkWidget *
212 sp_gradient_selector_new (void)
214     SPGradientSelector *sel;
216     sel = (SPGradientSelector*)gtk_type_new (SP_TYPE_GRADIENT_SELECTOR);
218     return (GtkWidget *) sel;
221 void SPGradientSelector::setMode(SelectorMode mode)
223     if (mode != this->mode) {
224         this->mode = mode;
225         if (mode == MODE_SWATCH) {
226             for (std::vector<GtkWidget*>::iterator it = nonsolid.begin(); it != nonsolid.end(); ++it)
227             {
228                 gtk_widget_hide(*it);
229             }
231             SPGradientVectorSelector* vs = SP_GRADIENT_VECTOR_SELECTOR(vectors);
232             vs->setSwatched();
233         }
234     }
237 void SPGradientSelector::setUnits(SPGradientUnits units)
239     gradientUnits = units;
242 void SPGradientSelector::setSpread(SPGradientSpread spread)
244     gradientSpread = spread;
246     gtk_option_menu_set_history(GTK_OPTION_MENU(this->spread), gradientSpread);
249 SPGradientUnits SPGradientSelector::getUnits()
251     return gradientUnits;
254 SPGradientSpread SPGradientSelector::getSpread()
256     return gradientSpread;
259 void SPGradientSelector::setVector(SPDocument *doc, SPGradient *vector)
261     g_return_if_fail(!vector || SP_IS_GRADIENT(vector));
262     g_return_if_fail(!vector || (SP_OBJECT_DOCUMENT(vector) == doc));
264     if (vector && !vector->hasStops()) {
265         return;
266     }
268     sp_gradient_vector_selector_set_gradient(SP_GRADIENT_VECTOR_SELECTOR(vectors), doc, vector);
270     if (vector) {
271         if ( (mode == MODE_SWATCH) && vector->isSwatch() ) {
272             if ( vector->isSolid() ) {
273                 for (std::vector<GtkWidget*>::iterator it = nonsolid.begin(); it != nonsolid.end(); ++it)
274                 {
275                     gtk_widget_hide(*it);
276                 }
277             } else {
278                 for (std::vector<GtkWidget*>::iterator it = nonsolid.begin(); it != nonsolid.end(); ++it)
279                 {
280                     gtk_widget_show_all(*it);
281                 }
282             }
283         }
285         if (edit) {
286             gtk_widget_set_sensitive(edit, TRUE);
287         }
288         if (add) {
289             gtk_widget_set_sensitive(add, TRUE);
290         }
291     } else {
292         if (edit) {
293             gtk_widget_set_sensitive(edit, FALSE);
294         }
295         if (add) {
296             gtk_widget_set_sensitive(add, (doc != NULL));
297         }
298     }
301 SPGradient *SPGradientSelector::getVector()
303     /* fixme: */
304     return SP_GRADIENT_VECTOR_SELECTOR(vectors)->gr;
307 static void
308 sp_gradient_selector_vector_set (SPGradientVectorSelector */*gvs*/, SPGradient *gr, SPGradientSelector *sel)
310     static gboolean blocked = FALSE;
312     if (!blocked) {
313         blocked = TRUE;
314         gr = sp_gradient_ensure_vector_normalized (gr);
315         sel->setVector((gr) ? SP_OBJECT_DOCUMENT (gr) : 0, gr);
316         g_signal_emit (G_OBJECT (sel), signals[CHANGED], 0, gr);
317         blocked = FALSE;
318     }
321 static void
322 sp_gradient_selector_edit_vector_clicked (GtkWidget */*w*/, SPGradientSelector *sel)
324     GtkWidget *dialog;
326     /* fixme: */
327     dialog = sp_gradient_vector_editor_new (SP_GRADIENT_VECTOR_SELECTOR (sel->vectors)->gr);
329     gtk_widget_show (dialog);
332 static void
333 sp_gradient_selector_add_vector_clicked (GtkWidget */*w*/, SPGradientSelector *sel)
335     SPDocument *doc = sp_gradient_vector_selector_get_document (
336                                                                 SP_GRADIENT_VECTOR_SELECTOR (sel->vectors));
338     if (!doc)
339         return;
341     SPGradient *gr = sp_gradient_vector_selector_get_gradient(
342                                                               SP_GRADIENT_VECTOR_SELECTOR (sel->vectors));
343     Inkscape::XML::Document *xml_doc = doc->getReprDoc();
345     Inkscape::XML::Node *repr = NULL;
347     if (gr)
348         repr = SP_OBJECT_REPR (gr)->duplicate(xml_doc);
349     else {
350         repr = xml_doc->createElement("svg:linearGradient");
351         Inkscape::XML::Node *stop = xml_doc->createElement("svg:stop");
352         stop->setAttribute("offset", "0");
353         stop->setAttribute("style", "stop-color:#000;stop-opacity:1;");
354         repr->appendChild(stop);
355         Inkscape::GC::release(stop);
356         stop = xml_doc->createElement("svg:stop");
357         stop->setAttribute("offset", "1");
358         stop->setAttribute("style", "stop-color:#fff;stop-opacity:1;");
359         repr->appendChild(stop);
360         Inkscape::GC::release(stop);
361     }
363     SP_OBJECT_REPR (SP_DOCUMENT_DEFS (doc))->addChild(repr, NULL);
365     gr = (SPGradient *) doc->getObjectByRepr(repr);
366     sp_gradient_vector_selector_set_gradient(
367                                              SP_GRADIENT_VECTOR_SELECTOR (sel->vectors), doc, gr);
369     Inkscape::GC::release(repr);
374 static void
375 sp_gradient_selector_spread_activate (GtkWidget *widget, SPGradientSelector *sel)
377     sel->gradientSpread = (SPGradientSpread)GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget), "gradientSpread"));
379     g_signal_emit (G_OBJECT (sel), signals[CHANGED], 0);
383 /*
384   Local Variables:
385   mode:c++
386   c-file-style:"stroustrup"
387   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
388   indent-tabs-mode:nil
389   fill-column:99
390   End:
391 */
392 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :