1 #define __SP_PAINT_SELECTOR_C__
3 /** \file
4 * SPPaintSelector: Generic paint selector widget.
5 */
7 /*
8 * Copyright (C) Lauris Kaplinski 2002
9 * bulia byak <buliabyak@users.sf.net>
10 */
12 #define noSP_PS_VERBOSE
14 #ifdef HAVE_CONFIG_H
15 # include "config.h"
16 #endif
20 #include <gtk/gtkhbox.h>
21 #include <gtk/gtkradiobutton.h>
22 #include <gtk/gtkframe.h>
23 #include <gtk/gtklabel.h>
24 #include <gtk/gtkoptionmenu.h>
25 #include <gtk/gtktooltips.h>
26 #include <gtk/gtkmenuitem.h>
28 #include "../sp-pattern.h"
29 #include <glibmm/i18n.h>
30 #include "../widgets/icon.h"
31 #include "../inkscape-stock.h"
32 #include "widgets/widget-sizes.h"
33 #include "xml/repr.h"
35 #include "sp-color-notebook.h"
36 #include "sp-linear-gradient-fns.h"
37 #include "sp-radial-gradient-fns.h"
38 /* fixme: Move it from dialogs to here */
39 #include "gradient-selector.h"
40 #include <inkscape.h>
41 #include <document-private.h>
42 #include <desktop-style.h>
43 #include <style.h>
44 #include "svg/svg-color.h"
45 #include "svg/css-ostringstream.h"
47 #include "paint-selector.h"
49 enum {
50 MODE_CHANGED,
51 GRABBED,
52 DRAGGED,
53 RELEASED,
54 CHANGED,
55 FILLRULE_CHANGED,
56 LAST_SIGNAL
57 };
59 static void sp_paint_selector_class_init (SPPaintSelectorClass *klass);
60 static void sp_paint_selector_init (SPPaintSelector *slider);
61 static void sp_paint_selector_destroy (GtkObject *object);
63 static GtkWidget *sp_paint_selector_style_button_add (SPPaintSelector *psel, const gchar *px, SPPaintSelectorMode mode, GtkTooltips *tt, const gchar *tip);
64 static void sp_paint_selector_style_button_toggled (GtkToggleButton *tb, SPPaintSelector *psel);
65 static void sp_paint_selector_fillrule_toggled (GtkToggleButton *tb, SPPaintSelector *psel);
67 static void sp_paint_selector_set_mode_empty (SPPaintSelector *psel);
68 static void sp_paint_selector_set_mode_multiple (SPPaintSelector *psel);
69 static void sp_paint_selector_set_mode_none (SPPaintSelector *psel);
70 static void sp_paint_selector_set_mode_color (SPPaintSelector *psel, SPPaintSelectorMode mode);
71 static void sp_paint_selector_set_mode_gradient (SPPaintSelector *psel, SPPaintSelectorMode mode);
72 static void sp_paint_selector_set_mode_pattern (SPPaintSelector *psel, SPPaintSelectorMode mode);
73 static void sp_paint_selector_set_mode_unset (SPPaintSelector *psel);
76 static void sp_paint_selector_set_style_buttons (SPPaintSelector *psel, GtkWidget *active);
78 static GtkVBoxClass *parent_class;
79 static guint psel_signals[LAST_SIGNAL] = {0};
81 GtkType
82 sp_paint_selector_get_type (void)
83 {
84 static GtkType type = 0;
85 if (!type) {
86 GtkTypeInfo info = {
87 "SPPaintSelector",
88 sizeof (SPPaintSelector),
89 sizeof (SPPaintSelectorClass),
90 (GtkClassInitFunc) sp_paint_selector_class_init,
91 (GtkObjectInitFunc) sp_paint_selector_init,
92 NULL, NULL, NULL
93 };
94 type = gtk_type_unique (GTK_TYPE_VBOX, &info);
95 }
96 return type;
97 }
99 static void
100 sp_paint_selector_class_init (SPPaintSelectorClass *klass)
101 {
102 GtkObjectClass *object_class;
103 GtkWidgetClass *widget_class;
105 object_class = (GtkObjectClass *) klass;
106 widget_class = (GtkWidgetClass *) klass;
108 parent_class = (GtkVBoxClass*)gtk_type_class (GTK_TYPE_VBOX);
110 psel_signals[MODE_CHANGED] = gtk_signal_new ("mode_changed",
111 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
112 GTK_CLASS_TYPE(object_class),
113 GTK_SIGNAL_OFFSET (SPPaintSelectorClass, mode_changed),
114 gtk_marshal_NONE__UINT,
115 GTK_TYPE_NONE, 1, GTK_TYPE_UINT);
116 psel_signals[GRABBED] = gtk_signal_new ("grabbed",
117 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
118 GTK_CLASS_TYPE(object_class),
119 GTK_SIGNAL_OFFSET (SPPaintSelectorClass, grabbed),
120 gtk_marshal_NONE__NONE,
121 GTK_TYPE_NONE, 0);
122 psel_signals[DRAGGED] = gtk_signal_new ("dragged",
123 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
124 GTK_CLASS_TYPE(object_class),
125 GTK_SIGNAL_OFFSET (SPPaintSelectorClass, dragged),
126 gtk_marshal_NONE__NONE,
127 GTK_TYPE_NONE, 0);
128 psel_signals[RELEASED] = gtk_signal_new ("released",
129 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
130 GTK_CLASS_TYPE(object_class),
131 GTK_SIGNAL_OFFSET (SPPaintSelectorClass, released),
132 gtk_marshal_NONE__NONE,
133 GTK_TYPE_NONE, 0);
134 psel_signals[CHANGED] = gtk_signal_new ("changed",
135 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
136 GTK_CLASS_TYPE(object_class),
137 GTK_SIGNAL_OFFSET (SPPaintSelectorClass, changed),
138 gtk_marshal_NONE__NONE,
139 GTK_TYPE_NONE, 0);
140 psel_signals[FILLRULE_CHANGED] = gtk_signal_new ("fillrule_changed",
141 (GtkSignalRunType)(GTK_RUN_FIRST | GTK_RUN_NO_RECURSE),
142 GTK_CLASS_TYPE(object_class),
143 GTK_SIGNAL_OFFSET (SPPaintSelectorClass, fillrule_changed),
144 gtk_marshal_NONE__UINT,
145 GTK_TYPE_NONE, 1, GTK_TYPE_UINT);
147 object_class->destroy = sp_paint_selector_destroy;
148 }
150 #define XPAD 4
151 #define YPAD 1
153 static void
154 sp_paint_selector_init (SPPaintSelector *psel)
155 {
156 GtkTooltips *tt = gtk_tooltips_new();
158 psel->mode = (SPPaintSelectorMode)-1; // huh? do you mean 0xff? -- I think this means "not in the enum"
160 /* Paint style button box */
161 psel->style = gtk_hbox_new (FALSE, 0);
162 gtk_widget_show (psel->style);
163 gtk_container_set_border_width (GTK_CONTAINER (psel->style), 4);
164 gtk_box_pack_start (GTK_BOX (psel), psel->style, FALSE, FALSE, 0);
166 /* Buttons */
167 psel->none = sp_paint_selector_style_button_add (psel, INKSCAPE_STOCK_FILL_NONE,
168 SP_PAINT_SELECTOR_MODE_NONE, tt, _("No paint"));
169 psel->solid = sp_paint_selector_style_button_add (psel, INKSCAPE_STOCK_FILL_SOLID,
170 SP_PAINT_SELECTOR_MODE_COLOR_RGB, tt, _("Flat color"));
171 psel->gradient = sp_paint_selector_style_button_add (psel, INKSCAPE_STOCK_FILL_GRADIENT,
172 SP_PAINT_SELECTOR_MODE_GRADIENT_LINEAR, tt, _("Linear gradient"));
173 psel->radial = sp_paint_selector_style_button_add (psel, INKSCAPE_STOCK_FILL_RADIAL,
174 SP_PAINT_SELECTOR_MODE_GRADIENT_RADIAL, tt, _("Radial gradient")),
175 psel->pattern = sp_paint_selector_style_button_add (psel, INKSCAPE_STOCK_FILL_PATTERN,
176 SP_PAINT_SELECTOR_MODE_PATTERN, tt, _("Pattern"));
177 psel->unset = sp_paint_selector_style_button_add (psel, INKSCAPE_STOCK_FILL_UNSET,
178 SP_PAINT_SELECTOR_MODE_UNSET, tt, _("Unset paint (make it undefined so it can be inherited)"));
180 /* Fillrule */
181 {
182 psel->fillrulebox = gtk_hbox_new (FALSE, 0);
183 gtk_box_pack_end (GTK_BOX (psel->style), psel->fillrulebox, FALSE, FALSE, 0);
185 GtkWidget *w;
186 psel->evenodd = gtk_radio_button_new (NULL);
187 gtk_button_set_relief (GTK_BUTTON (psel->evenodd), GTK_RELIEF_NONE);
188 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON(psel->evenodd), FALSE);
189 // TRANSLATORS: for info, see http://www.w3.org/TR/2000/CR-SVG-20000802/painting.html#FillRuleProperty
190 gtk_tooltips_set_tip (tt, psel->evenodd, _("Any path self-intersections or subpaths create holes in the fill (fill-rule: evenodd)"), NULL);
191 gtk_object_set_data (GTK_OBJECT (psel->evenodd), "mode", GUINT_TO_POINTER (SP_PAINT_SELECTOR_FILLRULE_EVENODD));
192 w = sp_icon_new (GTK_ICON_SIZE_MENU, "fillrule_evenodd");
193 gtk_container_add (GTK_CONTAINER (psel->evenodd), w);
194 gtk_box_pack_start (GTK_BOX (psel->fillrulebox), psel->evenodd, FALSE, FALSE, 0);
195 gtk_signal_connect (GTK_OBJECT (psel->evenodd), "toggled", GTK_SIGNAL_FUNC (sp_paint_selector_fillrule_toggled), psel);
197 psel->nonzero = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (psel->evenodd)));
198 gtk_button_set_relief (GTK_BUTTON (psel->nonzero), GTK_RELIEF_NONE);
199 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON(psel->nonzero), FALSE);
200 // TRANSLATORS: for info, see http://www.w3.org/TR/2000/CR-SVG-20000802/painting.html#FillRuleProperty
201 gtk_tooltips_set_tip (tt, psel->nonzero, _("Fill is solid unless a subpath is counterdirectional (fill-rule: nonzero)"), NULL);
202 gtk_object_set_data (GTK_OBJECT (psel->nonzero), "mode", GUINT_TO_POINTER (SP_PAINT_SELECTOR_FILLRULE_NONZERO));
203 w = sp_icon_new (GTK_ICON_SIZE_MENU, "fillrule_nonzero");
204 gtk_container_add (GTK_CONTAINER (psel->nonzero), w);
205 gtk_box_pack_start (GTK_BOX (psel->fillrulebox), psel->nonzero, FALSE, FALSE, 0);
206 gtk_signal_connect (GTK_OBJECT (psel->nonzero), "toggled", GTK_SIGNAL_FUNC (sp_paint_selector_fillrule_toggled), psel);
207 }
209 /* Frame */
210 psel->frame = gtk_frame_new ("");
211 gtk_widget_show (psel->frame);
212 gtk_container_set_border_width (GTK_CONTAINER (psel->frame), 0);
213 gtk_box_pack_start (GTK_BOX (psel), psel->frame, TRUE, TRUE, 0);
215 /* Last used color */
216 sp_color_set_rgb_float (&psel->color, 0.0, 0.0, 0.0);
217 psel->alpha = 1.0;
218 }
220 static void
221 sp_paint_selector_destroy (GtkObject *object)
222 {
223 SPPaintSelector *psel = SP_PAINT_SELECTOR (object);
225 // clean up our long-living pattern menu
226 g_object_set_data (G_OBJECT(psel),"patternmenu",NULL);
228 if (((GtkObjectClass *) (parent_class))->destroy)
229 (* ((GtkObjectClass *) (parent_class))->destroy) (object);
230 }
232 static GtkWidget *
233 sp_paint_selector_style_button_add (SPPaintSelector *psel, const gchar *pixmap, SPPaintSelectorMode mode, GtkTooltips *tt, const gchar *tip)
234 {
235 GtkWidget *b, *w;
237 b = gtk_toggle_button_new ();
238 gtk_tooltips_set_tip (tt, b, tip, NULL);
239 gtk_widget_show (b);
241 gtk_container_set_border_width (GTK_CONTAINER (b), 0);
243 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
245 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE);
246 gtk_object_set_data (GTK_OBJECT (b), "mode", GUINT_TO_POINTER (mode));
248 w = sp_icon_new (GTK_ICON_SIZE_BUTTON, pixmap);
249 gtk_widget_show (w);
250 gtk_container_add (GTK_CONTAINER (b), w);
252 gtk_box_pack_start (GTK_BOX (psel->style), b, FALSE, FALSE, 0);
253 gtk_signal_connect (GTK_OBJECT (b), "toggled", GTK_SIGNAL_FUNC (sp_paint_selector_style_button_toggled), psel);
255 return b;
256 }
258 static void
259 sp_paint_selector_style_button_toggled (GtkToggleButton *tb, SPPaintSelector *psel)
260 {
261 if (!psel->update && gtk_toggle_button_get_active (tb)) {
262 sp_paint_selector_set_mode (psel, (SPPaintSelectorMode)GPOINTER_TO_UINT (gtk_object_get_data (GTK_OBJECT (tb), "mode")));
263 }
264 }
266 static void
267 sp_paint_selector_fillrule_toggled (GtkToggleButton *tb, SPPaintSelector *psel)
268 {
269 if (!psel->update && gtk_toggle_button_get_active (tb)) {
270 SPPaintSelectorFillRule fr = (SPPaintSelectorFillRule)GPOINTER_TO_UINT (gtk_object_get_data (GTK_OBJECT (tb), "mode"));
271 gtk_signal_emit (GTK_OBJECT (psel), psel_signals[FILLRULE_CHANGED], fr);
272 }
273 }
275 void
276 sp_paint_selector_show_fillrule (SPPaintSelector *psel, bool is_fill)
277 {
278 if (psel->fillrulebox) {
279 if (is_fill) {
280 gtk_widget_show_all (psel->fillrulebox);
281 } else {
282 gtk_widget_destroy (psel->fillrulebox);
283 psel->fillrulebox = NULL;
284 }
285 }
286 }
289 GtkWidget *
290 sp_paint_selector_new (bool is_fill)
291 {
292 SPPaintSelector *psel;
294 psel = (SPPaintSelector*)gtk_type_new (SP_TYPE_PAINT_SELECTOR);
296 sp_paint_selector_set_mode (psel, SP_PAINT_SELECTOR_MODE_MULTIPLE);
298 // This silliness is here because I don't know how to pass a parameter to the
299 // GtkObject "constructor" (sp_paint_selector_init). Remove it when paint_selector
300 // becomes a normal class.
301 sp_paint_selector_show_fillrule (psel, is_fill);
303 return GTK_WIDGET (psel);
304 }
306 void
307 sp_paint_selector_set_mode (SPPaintSelector *psel, SPPaintSelectorMode mode)
308 {
309 if (psel->mode != mode) {
310 psel->update = TRUE;
311 #ifdef SP_PS_VERBOSE
312 g_print ("Mode change %d -> %d\n", psel->mode, mode);
313 #endif
314 switch (mode) {
315 case SP_PAINT_SELECTOR_MODE_EMPTY:
316 sp_paint_selector_set_mode_empty (psel);
317 break;
318 case SP_PAINT_SELECTOR_MODE_MULTIPLE:
319 sp_paint_selector_set_mode_multiple (psel);
320 break;
321 case SP_PAINT_SELECTOR_MODE_NONE:
322 sp_paint_selector_set_mode_none (psel);
323 break;
324 case SP_PAINT_SELECTOR_MODE_COLOR_RGB:
325 case SP_PAINT_SELECTOR_MODE_COLOR_CMYK:
326 sp_paint_selector_set_mode_color (psel, mode);
327 break;
328 case SP_PAINT_SELECTOR_MODE_GRADIENT_LINEAR:
329 case SP_PAINT_SELECTOR_MODE_GRADIENT_RADIAL:
330 sp_paint_selector_set_mode_gradient (psel, mode);
331 break;
332 case SP_PAINT_SELECTOR_MODE_PATTERN:
333 sp_paint_selector_set_mode_pattern (psel, mode);
334 break;
335 case SP_PAINT_SELECTOR_MODE_UNSET:
336 sp_paint_selector_set_mode_unset (psel);
337 break;
338 default:
339 g_warning ("file %s: line %d: Unknown paint mode %d", __FILE__, __LINE__, mode);
340 break;
341 }
342 psel->mode = mode;
343 gtk_signal_emit (GTK_OBJECT (psel), psel_signals[MODE_CHANGED], psel->mode);
344 psel->update = FALSE;
345 }
346 }
348 void
349 sp_paint_selector_set_fillrule (SPPaintSelector *psel, SPPaintSelectorFillRule fillrule)
350 {
351 if (psel->fillrulebox) {
352 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (psel->evenodd), (fillrule == SP_PAINT_SELECTOR_FILLRULE_EVENODD));
353 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (psel->nonzero), (fillrule == SP_PAINT_SELECTOR_FILLRULE_NONZERO));
354 }
355 }
357 void
358 sp_paint_selector_set_color_alpha (SPPaintSelector *psel, const SPColor *color, float alpha)
359 {
360 g_return_if_fail( ( 0.0 <= alpha ) && ( alpha <= 1.0 ) );
361 SPColorSelector *csel;
362 guint32 rgba;
364 if ( sp_color_get_colorspace_type (color) == SP_COLORSPACE_TYPE_CMYK )
365 {
366 #ifdef SP_PS_VERBOSE
367 g_print ("PaintSelector set CMYKA\n");
368 #endif
369 sp_paint_selector_set_mode (psel, SP_PAINT_SELECTOR_MODE_COLOR_CMYK);
370 }
371 else
372 {
373 #ifdef SP_PS_VERBOSE
374 g_print ("PaintSelector set RGBA\n");
375 #endif
376 sp_paint_selector_set_mode (psel, SP_PAINT_SELECTOR_MODE_COLOR_RGB);
377 }
379 csel = (SPColorSelector*)gtk_object_get_data (GTK_OBJECT (psel->selector), "color-selector");
380 rgba = sp_color_get_rgba32_falpha( &*color, alpha );
381 csel->base->setColorAlpha( *color, alpha );
382 }
384 void
385 sp_paint_selector_set_gradient_linear (SPPaintSelector *psel, SPGradient *vector)
386 {
387 SPGradientSelector *gsel;
388 #ifdef SP_PS_VERBOSE
389 g_print ("PaintSelector set GRADIENT LINEAR\n");
390 #endif
391 sp_paint_selector_set_mode (psel, SP_PAINT_SELECTOR_MODE_GRADIENT_LINEAR);
393 gsel = (SPGradientSelector*)gtk_object_get_data (GTK_OBJECT (psel->selector), "gradient-selector");
395 sp_gradient_selector_set_mode (gsel, SP_GRADIENT_SELECTOR_MODE_LINEAR);
396 sp_gradient_selector_set_vector (gsel, (vector) ? SP_OBJECT_DOCUMENT (vector) : NULL, vector);
397 }
399 void
400 sp_paint_selector_set_gradient_radial (SPPaintSelector *psel, SPGradient *vector)
401 {
402 SPGradientSelector *gsel;
403 #ifdef SP_PS_VERBOSE
404 g_print ("PaintSelector set GRADIENT RADIAL\n");
405 #endif
406 sp_paint_selector_set_mode (psel, SP_PAINT_SELECTOR_MODE_GRADIENT_RADIAL);
408 gsel = (SPGradientSelector*)gtk_object_get_data (GTK_OBJECT (psel->selector), "gradient-selector");
410 sp_gradient_selector_set_mode (gsel, SP_GRADIENT_SELECTOR_MODE_RADIAL);
411 sp_gradient_selector_set_vector (gsel, (vector) ? SP_OBJECT_DOCUMENT (vector) : NULL, vector);
412 }
414 void
415 sp_paint_selector_set_gradient_properties (SPPaintSelector *psel, SPGradientUnits units, SPGradientSpread spread)
416 {
417 SPGradientSelector *gsel;
418 g_return_if_fail (SP_IS_PAINT_SELECTOR (psel));
419 g_return_if_fail ((psel->mode == SP_PAINT_SELECTOR_MODE_GRADIENT_LINEAR) ||
420 (psel->mode == SP_PAINT_SELECTOR_MODE_GRADIENT_RADIAL));
421 gsel = (SPGradientSelector*)gtk_object_get_data (GTK_OBJECT (psel->selector), "gradient-selector");
422 sp_gradient_selector_set_units (gsel, units);
423 sp_gradient_selector_set_spread (gsel, spread);
424 }
426 void
427 sp_paint_selector_get_gradient_properties (SPPaintSelector *psel, SPGradientUnits *units, SPGradientSpread *spread)
428 {
429 SPGradientSelector *gsel;
430 g_return_if_fail (SP_IS_PAINT_SELECTOR (psel));
431 g_return_if_fail ((psel->mode == SP_PAINT_SELECTOR_MODE_GRADIENT_LINEAR) ||
432 (psel->mode == SP_PAINT_SELECTOR_MODE_GRADIENT_RADIAL));
433 gsel = (SPGradientSelector*)gtk_object_get_data (GTK_OBJECT (psel->selector), "gradient-selector");
434 if (units) *units = sp_gradient_selector_get_units (gsel);
435 if (spread) *spread = sp_gradient_selector_get_spread (gsel);
436 }
438 /**
439 * \post (alpha == NULL) || (*alpha in [0.0, 1.0]).
440 */
441 void
442 sp_paint_selector_get_color_alpha (SPPaintSelector *psel, SPColor *color, gfloat *alpha)
443 {
444 SPColorSelector *csel;
446 csel = (SPColorSelector*)gtk_object_get_data (GTK_OBJECT (psel->selector), "color-selector");
448 csel->base->getColorAlpha( *color, alpha );
450 g_assert( !alpha
451 || ( ( 0.0 <= *alpha )
452 && ( *alpha <= 1.0 ) ) );
453 }
455 SPGradient *
456 sp_paint_selector_get_gradient_vector (SPPaintSelector *psel)
457 {
458 SPGradientSelector *gsel;
460 g_return_val_if_fail ((psel->mode == SP_PAINT_SELECTOR_MODE_GRADIENT_LINEAR) ||
461 (psel->mode == SP_PAINT_SELECTOR_MODE_GRADIENT_RADIAL), NULL);
463 gsel = (SPGradientSelector*)gtk_object_get_data (GTK_OBJECT (psel->selector), "gradient-selector");
465 return sp_gradient_selector_get_vector (gsel);
466 }
468 void
469 sp_gradient_selector_attrs_to_gradient (SPGradient *gr, SPPaintSelector *psel)
470 {
471 SPGradientUnits units;
472 SPGradientSpread spread;
473 sp_paint_selector_get_gradient_properties (psel, &units, &spread);
474 sp_gradient_set_units (gr, units);
475 sp_gradient_set_spread (gr, spread);
476 SP_OBJECT(gr)->updateRepr();
477 }
479 static void
480 sp_paint_selector_clear_frame(SPPaintSelector *psel)
481 {
482 g_return_if_fail ( psel != NULL);
484 if (psel->selector) {
486 /* before we destroy the frame contents, we must detach
487 * the patternmenu so that Gtk doesn't gtk_widget_destroy
488 * all the children of the menu. (We also have a g_object_ref
489 * count set on it too so that the gtk_container_remove doesn't
490 * end up destroying it.
491 */
492 GtkWidget *patterns = (GtkWidget *)g_object_get_data (G_OBJECT(psel), "patternmenu");
493 if (patterns != NULL) {
494 GtkWidget * parent = gtk_widget_get_parent ( GTK_WIDGET (patterns));
495 if ( parent != NULL ) {
496 g_assert ( GTK_IS_CONTAINER (parent) );
497 gtk_container_remove ( GTK_CONTAINER (parent), patterns );
498 }
499 }
501 gtk_widget_destroy (psel->selector);
502 psel->selector = NULL;
503 }
504 }
506 static void
507 sp_paint_selector_set_mode_empty (SPPaintSelector *psel)
508 {
509 sp_paint_selector_set_style_buttons (psel, NULL);
510 gtk_widget_set_sensitive (psel->style, FALSE);
512 sp_paint_selector_clear_frame(psel);
514 gtk_frame_set_label (GTK_FRAME (psel->frame), _("No objects"));
515 }
517 static void
518 sp_paint_selector_set_mode_multiple (SPPaintSelector *psel)
519 {
520 sp_paint_selector_set_style_buttons (psel, NULL);
521 gtk_widget_set_sensitive (psel->style, TRUE);
523 sp_paint_selector_clear_frame(psel);
525 gtk_frame_set_label (GTK_FRAME (psel->frame), _("Multiple styles"));
526 }
528 static void
529 sp_paint_selector_set_mode_unset (SPPaintSelector *psel)
530 {
531 sp_paint_selector_set_style_buttons (psel, psel->unset);
532 gtk_widget_set_sensitive (psel->style, TRUE);
534 sp_paint_selector_clear_frame(psel);
536 gtk_frame_set_label (GTK_FRAME (psel->frame), _("Paint is undefined"));
537 }
539 static void
540 sp_paint_selector_set_mode_none (SPPaintSelector *psel)
541 {
542 sp_paint_selector_set_style_buttons (psel, psel->none);
543 gtk_widget_set_sensitive (psel->style, TRUE);
545 sp_paint_selector_clear_frame(psel);
547 gtk_frame_set_label (GTK_FRAME (psel->frame), _("No paint"));
548 }
550 /* Color paint */
552 static void
553 sp_paint_selector_color_grabbed (SPColorSelector *csel, SPPaintSelector *psel)
554 {
555 gtk_signal_emit (GTK_OBJECT (psel), psel_signals[GRABBED]);
556 }
558 static void
559 sp_paint_selector_color_dragged (SPColorSelector *csel, SPPaintSelector *psel)
560 {
561 gtk_signal_emit (GTK_OBJECT (psel), psel_signals[DRAGGED]);
562 }
564 static void
565 sp_paint_selector_color_released (SPColorSelector *csel, SPPaintSelector *psel)
566 {
567 gtk_signal_emit (GTK_OBJECT (psel), psel_signals[RELEASED]);
568 }
570 static void
571 sp_paint_selector_color_changed (SPColorSelector *csel, SPPaintSelector *psel)
572 {
573 csel->base->getColorAlpha( psel->color, &psel->alpha );
575 gtk_signal_emit (GTK_OBJECT (psel), psel_signals[CHANGED]);
576 }
578 static void
579 sp_paint_selector_set_mode_color (SPPaintSelector *psel, SPPaintSelectorMode mode)
580 {
581 GtkWidget *csel;
583 sp_paint_selector_set_style_buttons (psel, psel->solid);
584 gtk_widget_set_sensitive (psel->style, TRUE);
586 if ((psel->mode == SP_PAINT_SELECTOR_MODE_COLOR_RGB) || (psel->mode == SP_PAINT_SELECTOR_MODE_COLOR_CMYK)) {
587 /* Already have color selector */
588 csel = (GtkWidget*)gtk_object_get_data (GTK_OBJECT (psel->selector), "color-selector");
589 } else {
591 sp_paint_selector_clear_frame(psel);
592 /* Create new color selector */
593 /* Create vbox */
594 GtkWidget *vb = gtk_vbox_new (FALSE, 4);
595 gtk_widget_show (vb);
597 /* Color selector */
598 csel = sp_color_selector_new (SP_TYPE_COLOR_NOTEBOOK, SP_COLORSPACE_TYPE_NONE);
599 gtk_widget_show (csel);
600 gtk_object_set_data (GTK_OBJECT (vb), "color-selector", csel);
601 gtk_box_pack_start (GTK_BOX (vb), csel, TRUE, TRUE, 0);
602 gtk_signal_connect (GTK_OBJECT (csel), "grabbed", GTK_SIGNAL_FUNC (sp_paint_selector_color_grabbed), psel);
603 gtk_signal_connect (GTK_OBJECT (csel), "dragged", GTK_SIGNAL_FUNC (sp_paint_selector_color_dragged), psel);
604 gtk_signal_connect (GTK_OBJECT (csel), "released", GTK_SIGNAL_FUNC (sp_paint_selector_color_released), psel);
605 gtk_signal_connect (GTK_OBJECT (csel), "changed", GTK_SIGNAL_FUNC (sp_paint_selector_color_changed), psel);
606 /* Pack everything to frame */
607 gtk_container_add (GTK_CONTAINER (psel->frame), vb);
608 psel->selector = vb;
610 /* Set color */
611 SP_COLOR_SELECTOR( csel )->base->setColorAlpha( psel->color, psel->alpha );
613 }
615 gtk_frame_set_label (GTK_FRAME (psel->frame), _("Flat color"));
616 #ifdef SP_PS_VERBOSE
617 g_print ("Color req\n");
618 #endif
619 }
621 /* Gradient */
623 static void
624 sp_paint_selector_gradient_grabbed (SPColorSelector *csel, SPPaintSelector *psel)
625 {
626 gtk_signal_emit (GTK_OBJECT (psel), psel_signals[GRABBED]);
627 }
629 static void
630 sp_paint_selector_gradient_dragged (SPColorSelector *csel, SPPaintSelector *psel)
631 {
632 gtk_signal_emit (GTK_OBJECT (psel), psel_signals[DRAGGED]);
633 }
635 static void
636 sp_paint_selector_gradient_released (SPColorSelector *csel, SPPaintSelector *psel)
637 {
638 gtk_signal_emit (GTK_OBJECT (psel), psel_signals[RELEASED]);
639 }
641 static void
642 sp_paint_selector_gradient_changed (SPColorSelector *csel, SPPaintSelector *psel)
643 {
644 gtk_signal_emit (GTK_OBJECT (psel), psel_signals[CHANGED]);
645 }
647 static void
648 sp_paint_selector_set_mode_gradient (SPPaintSelector *psel, SPPaintSelectorMode mode)
649 {
650 GtkWidget *gsel;
652 /* fixme: We do not need function-wide gsel at all */
654 if (mode == SP_PAINT_SELECTOR_MODE_GRADIENT_LINEAR) {
655 sp_paint_selector_set_style_buttons (psel, psel->gradient);
656 } else {
657 sp_paint_selector_set_style_buttons (psel, psel->radial);
658 }
659 gtk_widget_set_sensitive (psel->style, TRUE);
661 if ((psel->mode == SP_PAINT_SELECTOR_MODE_GRADIENT_LINEAR) || (psel->mode == SP_PAINT_SELECTOR_MODE_GRADIENT_RADIAL)) {
662 /* Already have gradient selector */
663 gsel = (GtkWidget*)gtk_object_get_data (GTK_OBJECT (psel->selector), "gradient-selector");
664 } else {
665 sp_paint_selector_clear_frame(psel);
666 /* Create new gradient selector */
667 gsel = sp_gradient_selector_new ();
668 gtk_widget_show (gsel);
669 gtk_signal_connect (GTK_OBJECT (gsel), "grabbed", GTK_SIGNAL_FUNC (sp_paint_selector_gradient_grabbed), psel);
670 gtk_signal_connect (GTK_OBJECT (gsel), "dragged", GTK_SIGNAL_FUNC (sp_paint_selector_gradient_dragged), psel);
671 gtk_signal_connect (GTK_OBJECT (gsel), "released", GTK_SIGNAL_FUNC (sp_paint_selector_gradient_released), psel);
672 gtk_signal_connect (GTK_OBJECT (gsel), "changed", GTK_SIGNAL_FUNC (sp_paint_selector_gradient_changed), psel);
673 /* Pack everything to frame */
674 gtk_container_add (GTK_CONTAINER (psel->frame), gsel);
675 psel->selector = gsel;
676 gtk_object_set_data (GTK_OBJECT (psel->selector), "gradient-selector", gsel);
677 }
679 /* Actually we have to set optiomenu history here */
680 if (mode == SP_PAINT_SELECTOR_MODE_GRADIENT_LINEAR) {
681 sp_gradient_selector_set_mode (SP_GRADIENT_SELECTOR (gsel), SP_GRADIENT_SELECTOR_MODE_LINEAR);
682 gtk_frame_set_label (GTK_FRAME (psel->frame), _("Linear gradient"));
683 } else {
684 sp_gradient_selector_set_mode (SP_GRADIENT_SELECTOR (gsel), SP_GRADIENT_SELECTOR_MODE_RADIAL);
685 gtk_frame_set_label (GTK_FRAME (psel->frame), _("Radial gradient"));
686 }
687 #ifdef SP_PS_VERBOSE
688 g_print ("Gradient req\n");
689 #endif
690 }
692 static void
693 sp_paint_selector_set_style_buttons (SPPaintSelector *psel, GtkWidget *active)
694 {
695 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (psel->none), (active == psel->none));
696 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (psel->solid), (active == psel->solid));
697 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (psel->gradient), (active == psel->gradient));
698 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (psel->radial), (active == psel->radial));
699 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (psel->pattern), (active == psel->pattern));
700 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (psel->unset), (active == psel->unset));
701 }
703 static void
704 sp_psel_pattern_destroy (GtkWidget *widget, SPPaintSelector *psel)
705 {
706 // drop our reference to the pattern menu widget
707 g_object_unref ( G_OBJECT (widget) );
708 }
710 static void
711 sp_psel_pattern_change (GtkWidget *widget, SPPaintSelector *psel)
712 {
713 gtk_signal_emit (GTK_OBJECT (psel), psel_signals[CHANGED]);
714 }
716 static GtkWidget*
717 ink_pattern_menu (GtkWidget *mnu)
718 {
719 /* Create new menu widget */
720 GtkWidget *m = gtk_menu_new ();
721 gtk_widget_show (m);
723 /* Pick up all patterns */
724 SPDocument *doc = SP_ACTIVE_DOCUMENT;
725 GSList *pl = NULL;
726 const GSList *patterns = sp_document_get_resource_list (doc, "pattern");
727 for (GSList *l = (GSList *) patterns; l != NULL; l = l->next) {
728 if (SP_PATTERN (l->data) == pattern_getroot (SP_PATTERN (l->data))) { // only if this is a root pattern
729 pl = g_slist_prepend (pl, l->data);
730 }
731 }
733 pl = g_slist_reverse (pl);
735 if (!doc) {
736 GtkWidget *i;
737 i = gtk_menu_item_new_with_label (_("No document selected"));
738 gtk_widget_show (i);
739 gtk_menu_append (GTK_MENU (m), i);
740 gtk_widget_set_sensitive (mnu, FALSE);
741 } else if (!pl) {
742 GtkWidget *i;
743 i = gtk_menu_item_new_with_label (_("No patterns in document"));
744 gtk_widget_show (i);
745 gtk_menu_append (GTK_MENU (m), i);
746 gtk_widget_set_sensitive (mnu, FALSE);
747 } else {
748 for (; pl != NULL; pl = pl->next){
749 if (SP_IS_PATTERN(pl->data)){
750 SPPattern *pat = SP_PATTERN (pl->data);
751 GtkWidget *i = gtk_menu_item_new ();
752 gtk_widget_show (i);
753 g_object_set_data (G_OBJECT (i), "pattern", pat);
754 // g_signal_connect (G_OBJECT (i), "activate", G_CALLBACK (sp_gvs_gradient_activate), gvs);
755 GtkWidget *hb = gtk_hbox_new (FALSE, 4);
756 gtk_widget_show (hb);
757 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) pl->data);
758 GtkWidget *l = gtk_label_new (repr->attribute("id"));
759 gtk_widget_show (l);
760 gtk_misc_set_alignment (GTK_MISC (l), 1.0, 0.5);
761 gtk_box_pack_start (GTK_BOX (hb), l, TRUE, TRUE, 0);
762 gtk_widget_show (hb);
763 gtk_container_add (GTK_CONTAINER (i), hb);
764 gtk_menu_append (GTK_MENU (m), i);
765 }
766 }
768 gtk_widget_set_sensitive (mnu, TRUE);
769 }
770 gtk_option_menu_set_menu (GTK_OPTION_MENU (mnu), m);
772 /* Set history */
773 //gtk_option_menu_set_history (GTK_OPTION_MENU (mnu), 0);
775 g_slist_free (pl);
776 return mnu;
777 }
780 /*update pattern list*/
781 void
782 sp_update_pattern_list ( SPPaintSelector *psel, SPPattern *pattern)
783 {
784 if (psel->update) return;
785 GtkWidget *mnu = (GtkWidget *)g_object_get_data (G_OBJECT(psel), "patternmenu");
786 g_assert ( mnu != NULL );
788 /* Clear existing menu if any */
789 gtk_option_menu_remove_menu (GTK_OPTION_MENU (mnu));
791 ink_pattern_menu (mnu);
793 /* Set history */
795 if (pattern && !gtk_object_get_data(GTK_OBJECT(mnu), "update")) {
797 gtk_object_set_data(GTK_OBJECT(mnu), "update", GINT_TO_POINTER(TRUE));
799 gchar *patname = (gchar *) SP_OBJECT_REPR(pattern)->attribute("id");
801 GtkMenu *m = GTK_MENU(gtk_option_menu_get_menu (GTK_OPTION_MENU(mnu)));
802 GList *kids = GTK_MENU_SHELL(m)->children;
804 int patpos = 0;
805 int i = 0;
807 for (; kids != NULL; kids = kids->next) {
808 gchar *men_pat = (gchar *) SP_OBJECT_REPR(g_object_get_data(G_OBJECT(kids->data), "pattern"))->attribute("id");
809 if ( strcmp(men_pat, patname) == 0 ) {
810 patpos = i;
811 }
812 i++;
813 }
815 gtk_option_menu_set_history(GTK_OPTION_MENU (mnu), patpos);
816 gtk_object_set_data(GTK_OBJECT (mnu), "update", GINT_TO_POINTER (FALSE));
817 }
818 //gtk_option_menu_set_history (GTK_OPTION_MENU (mnu), 0);
819 }
821 static void
822 sp_paint_selector_set_mode_pattern (SPPaintSelector *psel, SPPaintSelectorMode mode)
823 {
824 if (mode == SP_PAINT_SELECTOR_MODE_PATTERN)
825 sp_paint_selector_set_style_buttons (psel, psel->pattern);
827 gtk_widget_set_sensitive (psel->style, TRUE);
829 GtkWidget *tbl=NULL;
831 if (psel->mode == SP_PAINT_SELECTOR_MODE_PATTERN){
832 /* Already have pattern menu */
833 tbl = (GtkWidget*)gtk_object_get_data (GTK_OBJECT (psel->selector), "pattern-selector");
834 } else {
835 sp_paint_selector_clear_frame(psel);
837 /* Create vbox */
838 tbl = gtk_vbox_new (FALSE, 4);
839 gtk_widget_show (tbl);
841 {
842 GtkWidget *hb = gtk_hbox_new (FALSE, 1);
844 GtkWidget *mnu = gtk_option_menu_new ();
845 ink_pattern_menu (mnu);
846 gtk_signal_connect (GTK_OBJECT (mnu), "changed", GTK_SIGNAL_FUNC (sp_psel_pattern_change), psel);
847 gtk_signal_connect (GTK_OBJECT (mnu), "destroy", GTK_SIGNAL_FUNC (sp_psel_pattern_destroy), psel);
848 gtk_object_set_data (GTK_OBJECT (psel), "patternmenu", mnu);
849 g_object_ref( G_OBJECT (mnu));
851 gtk_container_add (GTK_CONTAINER (hb), mnu);
852 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
853 }
855 {
856 GtkWidget *hb = gtk_hbox_new (FALSE, 0);
857 GtkWidget *l = gtk_label_new (NULL);
858 gtk_label_set_markup(GTK_LABEL(l), _("Use <b>Edit > Object(s) to Pattern</b> to create a new pattern from selection."));
859 gtk_label_set_line_wrap (GTK_LABEL(l), true);
860 gtk_widget_set_size_request (l, 180, -1);
861 gtk_box_pack_start (GTK_BOX (hb), l, TRUE, TRUE, AUX_BETWEEN_BUTTON_GROUPS);
862 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
863 }
865 gtk_widget_show_all (tbl);
867 gtk_container_add (GTK_CONTAINER (psel->frame), tbl);
868 psel->selector = tbl;
869 gtk_object_set_data (GTK_OBJECT (psel->selector), "pattern-selector", tbl);
871 gtk_frame_set_label (GTK_FRAME (psel->frame), _("Pattern fill"));
872 }
873 #ifdef SP_PS_VERBOSE
874 g_print ("Pattern req\n");
875 #endif
876 }
878 SPPattern *
879 sp_paint_selector_get_pattern (SPPaintSelector *psel)
880 {
881 SPPattern *pat;
883 g_return_val_if_fail ((psel->mode == SP_PAINT_SELECTOR_MODE_PATTERN) , NULL);
885 GtkWidget *patmnu = (GtkWidget *) g_object_get_data (G_OBJECT(psel), "patternmenu");
886 /* no pattern menu if we were just selected */
887 if ( patmnu == NULL ) return NULL;
889 GtkMenu *m = GTK_MENU(gtk_option_menu_get_menu (GTK_OPTION_MENU(patmnu)));
891 pat = pattern_getroot (SP_PATTERN(g_object_get_data (G_OBJECT(gtk_menu_get_active (m)), "pattern")));
893 return pat;
894 }
896 void
897 sp_paint_selector_set_flat_color (SPPaintSelector *psel, SPDesktop *desktop, const gchar *color_property, const gchar *opacity_property)
898 {
899 SPCSSAttr *css = sp_repr_css_attr_new ();
901 SPColor color;
902 gfloat alpha;
903 sp_paint_selector_get_color_alpha (psel, &color, &alpha);
904 guint32 rgba = sp_color_get_rgba32_falpha (&color, alpha);
906 gchar b[64];
907 sp_svg_write_color (b, 64, rgba);
909 sp_repr_css_set_property (css, color_property, b);
910 Inkscape::CSSOStringStream osalpha;
911 osalpha << alpha;
912 sp_repr_css_set_property (css, opacity_property, osalpha.str().c_str());
914 sp_desktop_set_style (desktop, css);
916 sp_repr_css_attr_unref (css);
917 }
919 SPPaintSelectorMode
920 sp_style_determine_paint_selector_mode (SPStyle *style, bool isfill)
921 {
922 unsigned set = isfill? style->fill.set : style->stroke.set;
923 if (!set)
924 return SP_PAINT_SELECTOR_MODE_UNSET;
926 unsigned type = isfill? style->fill.type : style->stroke.type;
927 switch (type) {
929 case SP_PAINT_TYPE_NONE:
930 {
931 return SP_PAINT_SELECTOR_MODE_NONE;
932 }
934 case SP_PAINT_TYPE_COLOR:
935 {
936 return SP_PAINT_SELECTOR_MODE_COLOR_RGB; // so far only rgb can be read from svg
937 }
939 case SP_PAINT_TYPE_PAINTSERVER:
940 {
941 SPPaintServer *server = isfill? SP_STYLE_FILL_SERVER (style) : SP_STYLE_STROKE_SERVER (style);
943 if (SP_IS_LINEARGRADIENT (server)) {
944 return SP_PAINT_SELECTOR_MODE_GRADIENT_LINEAR;
945 } else if (SP_IS_RADIALGRADIENT (server)) {
946 return SP_PAINT_SELECTOR_MODE_GRADIENT_RADIAL;
947 } else if (SP_IS_PATTERN (server)) {
948 return SP_PAINT_SELECTOR_MODE_PATTERN;
949 }
951 g_warning ( "file %s: line %d: Unknown paintserver",
952 __FILE__, __LINE__ );
953 return SP_PAINT_SELECTOR_MODE_NONE;
954 }
956 default:
957 g_warning ( "file %s: line %d: Unknown paint type %d",
958 __FILE__, __LINE__, type );
959 break;
960 }
962 return SP_PAINT_SELECTOR_MODE_NONE;
963 }