Code

Phase 1 - unify/reconcile copy-n-paste edit madness of Fill and Stroke edit panes.
[inkscape.git] / src / widgets / fill-style.cpp
1 /** @file
2  * @brief  Fill style widget
3  */
4 /* Authors:
5  *   Lauris Kaplinski <lauris@kaplinski.com>
6  *   Frank Felfe <innerspace@iname.com>
7  *   bulia byak <buliabyak@users.sf.net>
8  *
9  * Copyright (C) 1999-2005 authors
10  * Copyright (C) 2001-2002 Ximian, Inc.
11  *
12  * Released under GNU GPL, read the file 'COPYING' for more information
13  */
15 #define noSP_FS_VERBOSE
17 #ifdef HAVE_CONFIG_H
18 # include "config.h"
19 #endif
21 #include <glibmm/i18n.h>
23 #include "desktop-handles.h"
24 #include "desktop-style.h"
25 #include "display/sp-canvas.h"
26 #include "document-private.h"
27 #include "gradient-chemistry.h"
28 #include "inkscape.h"
29 #include "selection.h"
30 #include "sp-linear-gradient.h"
31 #include "sp-pattern.h"
32 #include "sp-radial-gradient.h"
33 #include "style.h"
34 #include "widgets/paint-selector.h"
35 #include "widgets/sp-widget.h"
36 #include "xml/repr.h"
38 #include "fill-style.h"
39 #include "fill-n-stroke-factory.h"
42 // These can be deleted once we sort out the libart dependence.
44 #define ART_WIND_RULE_NONZERO 0
46 /* Fill */
48 static void fillnstroke_constructed(SPWidget *spw, SPPaintSelector *psel);
49 static void fillnstroke_fillrule_changed(SPPaintSelector *psel, SPPaintSelector::FillRule mode, SPWidget *spw);
51 static void fillnstroke_selection_modified(SPWidget *spw, Inkscape::Selection *selection, guint flags, SPPaintSelector *psel);
52 static void fillnstroke_selection_changed(SPWidget *spw, Inkscape::Selection *selection, SPPaintSelector *psel);
53 static void fillnstroke_subselection_changed(Inkscape::Application *inkscape, SPDesktop *desktop, SPWidget *spw);
55 static void fillnstroke_paint_mode_changed(SPPaintSelector *psel, SPPaintSelector::Mode mode, SPWidget *spw);
56 static void fillnstroke_paint_dragged(SPPaintSelector *psel, SPWidget *spw);
57 static void fillnstroke_paint_changed(SPPaintSelector *psel, SPWidget *spw);
59 static void fillnstroke_transientize_called(Inkscape::Application *inkscape, SPDesktop *desktop, SPWidget *spw);
61 static void fillnstroke_performUpdate(SPWidget *spw);
63 GtkWidget *sp_fill_style_widget_new(void)
64 {
65     return Inkscape::Widgets::createStyleWidget( FILL );
66 }
68 /**
69  * Create the fill or stroke style widget, and hook up all the signals.
70  */
71 GtkWidget *Inkscape::Widgets::createStyleWidget( FillOrStroke kind )
72 {
73     GtkWidget *spw = sp_widget_new_global(INKSCAPE);
75     // with or without fillrule selector
76     GtkWidget *psel = sp_paint_selector_new(kind == FILL);
77     gtk_widget_show(psel);
78     gtk_container_add(GTK_CONTAINER(spw), psel);
79     g_object_set_data(G_OBJECT(spw), "paint-selector", psel);
80     g_object_set_data(G_OBJECT(spw), "kind", GINT_TO_POINTER(kind));
82     if (kind == FILL) {
83         g_signal_connect( G_OBJECT(spw), "construct",
84                           G_CALLBACK(fillnstroke_constructed),
85                           psel );
86     }
88 //FIXME: switch these from spw signals to global inkscape object signals; spw just retranslates
89 //those anyway; then eliminate spw
90     g_signal_connect( G_OBJECT(spw), "modify_selection",
91                       G_CALLBACK(fillnstroke_selection_modified),
92                       psel );
94     g_signal_connect( G_OBJECT(spw), "change_selection",
95                       G_CALLBACK(fillnstroke_selection_changed),
96                       psel );
98     g_signal_connect( INKSCAPE, "change_subselection",
99                       G_CALLBACK(fillnstroke_subselection_changed),
100                       spw );
102     if (kind == STROKE) {
103         g_signal_connect( G_OBJECT(INKSCAPE), "activate_desktop",
104                           G_CALLBACK(fillnstroke_transientize_called),
105                           spw );
106     }
108     g_signal_connect( G_OBJECT(psel), "mode_changed",
109                       G_CALLBACK(fillnstroke_paint_mode_changed),
110                       spw );
112     g_signal_connect( G_OBJECT(psel), "dragged",
113                       G_CALLBACK(fillnstroke_paint_dragged),
114                       spw );
116     g_signal_connect( G_OBJECT(psel), "changed",
117                       G_CALLBACK(fillnstroke_paint_changed),
118                       spw );
120     if (kind == FILL) {
121         g_signal_connect( G_OBJECT(psel), "fillrule_changed",
122                           G_CALLBACK(fillnstroke_fillrule_changed),
123                           spw );
124     }
126     fillnstroke_performUpdate(SP_WIDGET(spw));
128     return spw;
131 static void fillnstroke_constructed( SPWidget *spw, SPPaintSelector * /*psel*/ )
133 #ifdef SP_FS_VERBOSE
134     FillOrStroke kind = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(spw), "kind")) ? FILL : STROKE;
135     g_print( "[%s] style widget constructed: inkscape %p\n",
136              (kind == FILL) ? "fill" : "style",
137               spw->inkscape );
138 #endif
139     if (spw->inkscape) {
140         fillnstroke_performUpdate(spw);
141     }
145 /**
146  * On signal modified, invokes an update of the fill or stroke style paint object.
147  */
148 static void fillnstroke_selection_modified( SPWidget *spw,
149                                     Inkscape::Selection * /*selection*/,
150                                     guint flags,
151                                     SPPaintSelector * /*psel*/ )
153     if (flags & ( SP_OBJECT_MODIFIED_FLAG |
154                   SP_OBJECT_PARENT_MODIFIED_FLAG |
155                   SP_OBJECT_STYLE_MODIFIED_FLAG) ) {
156 #ifdef SP_FS_VERBOSE
157         g_message("fillnstroke_selection_modified()");
158 #endif
159         fillnstroke_performUpdate(spw);
160     }
163 /**
164  * On signal selection changed, invokes an update of the fill or stroke style paint object.
165  */
166 static void fillnstroke_selection_changed( SPWidget *spw,
167                                    Inkscape::Selection * /*selection*/,
168                                    SPPaintSelector * /*psel*/ )
170     fillnstroke_performUpdate(spw);
173 /**
174  * On signal change subselection, invoke an update of the fill or stroke style widget.
175  */
176 static void fillnstroke_subselection_changed( Inkscape::Application * /*inkscape*/,
177                                       SPDesktop * /*desktop*/,
178                                       SPWidget *spw )
180     fillnstroke_performUpdate(spw);
183 /**
184  * Gets the active fill or stroke style property, then sets the appropriate
185  * color, alpha, gradient, pattern, etc. for the paint-selector.
186  *
187  * @param sel Selection to use, or NULL.
188  */
189 static void fillnstroke_performUpdate( SPWidget *spw )
191     if ( g_object_get_data(G_OBJECT(spw), "update") ) {
192         return;
193     }
195     FillOrStroke kind = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(spw), "kind")) ? FILL : STROKE;
197     if (kind == FILL) {
198         if ( g_object_get_data(G_OBJECT(spw), "local") ) {
199             g_object_set_data(G_OBJECT(spw), "local", GINT_TO_POINTER(FALSE)); // local change; do nothing, but reset the flag
200             return;
201         }
202     }
204     g_object_set_data(G_OBJECT(spw), "update", GINT_TO_POINTER(TRUE));
206     SPPaintSelector *psel = SP_PAINT_SELECTOR(g_object_get_data(G_OBJECT(spw), "paint-selector"));
208     // create temporary style
209     SPStyle *query = sp_style_new(SP_ACTIVE_DOCUMENT);
211     // query style from desktop into it. This returns a result flag and fills query with the style of subselection, if any, or selection
212     int result = sp_desktop_query_style(SP_ACTIVE_DESKTOP, query, (kind == FILL) ? QUERY_STYLE_PROPERTY_FILL : QUERY_STYLE_PROPERTY_STROKE);
214     SPIPaint &targPaint = (kind == FILL) ? query->fill : query->stroke;
215     SPIScale24 &targOpacity = (kind == FILL) ? query->fill_opacity : query->stroke_opacity;
217     switch (result) {
218         case QUERY_STYLE_NOTHING:
219         {
220             /* No paint at all */
221             psel->setMode(SPPaintSelector::MODE_EMPTY);
222             break;
223         }
225         case QUERY_STYLE_SINGLE:
226         case QUERY_STYLE_MULTIPLE_AVERAGED: // TODO: treat this slightly differently, e.g. display "averaged" somewhere in paint selector
227         case QUERY_STYLE_MULTIPLE_SAME:
228         {
229             SPPaintSelector::Mode pselmode = SPPaintSelector::getModeForStyle(*query, kind == FILL);
230             psel->setMode(pselmode);
232             if (kind == FILL) {
233                 psel->setFillrule(query->fill_rule.computed == ART_WIND_RULE_NONZERO?
234                                   SPPaintSelector::FILLRULE_NONZERO : SPPaintSelector::FILLRULE_EVENODD);
235             }
237             if (targPaint.set && targPaint.isColor()) {
238                 psel->setColorAlpha(targPaint.value.color, SP_SCALE24_TO_FLOAT(targOpacity.value));
239             } else if (targPaint.set && targPaint.isPaintserver()) {
241                 SPPaintServer *server = (kind == FILL) ? query->getFillPaintServer() : query->getStrokePaintServer();
243                 if (server && SP_IS_GRADIENT(server) && SP_GRADIENT(server)->getVector()->isSwatch()) {
244                     SPGradient *vector = SP_GRADIENT(server)->getVector();
245                     psel->setSwatch( vector );
246                 } else if (SP_IS_LINEARGRADIENT(server)) {
247                     SPGradient *vector = SP_GRADIENT(server)->getVector();
248                     psel->setGradientLinear( vector );
250                     SPLinearGradient *lg = SP_LINEARGRADIENT(server);
251                     psel->setGradientProperties( SP_GRADIENT_UNITS(lg),
252                                                  SP_GRADIENT_SPREAD(lg) );
253                 } else if (SP_IS_RADIALGRADIENT(server)) {
254                     SPGradient *vector = SP_GRADIENT(server)->getVector();
255                     psel->setGradientRadial( vector );
257                     SPRadialGradient *rg = SP_RADIALGRADIENT(server);
258                     psel->setGradientProperties( SP_GRADIENT_UNITS(rg),
259                                                  SP_GRADIENT_SPREAD(rg) );
260                 } else if (SP_IS_PATTERN(server)) {
261                     SPPattern *pat = pattern_getroot(SP_PATTERN(server));
262                     psel->updatePatternList( pat );
263                 }
264             }
265             break;
266         }
268         case QUERY_STYLE_MULTIPLE_DIFFERENT:
269         {
270             psel->setMode(SPPaintSelector::MODE_MULTIPLE);
271             break;
272         }
273     }
275     sp_style_unref(query);
277     g_object_set_data(G_OBJECT(spw), "update", GINT_TO_POINTER(FALSE));
280 /**
281  * When the mode is changed, invoke a regular changed handler.
282  */
283 static void fillnstroke_paint_mode_changed( SPPaintSelector *psel,
284                                     SPPaintSelector::Mode /*mode*/,
285                                     SPWidget *spw )
287     if (g_object_get_data(G_OBJECT(spw), "update")) {
288         return;
289     }
291 #ifdef SP_FS_VERBOSE
292     g_message("fillnstroke_paint_mode_changed(psel:%p, mode, spw:%p)", psel, spw);
293 #endif
295     /* TODO: Does this work?
296      * Not really, here we have to get old color back from object
297      * Instead of relying on paint widget having meaningful colors set
298      */
299     fillnstroke_paint_changed(psel, spw);
302 static void fillnstroke_fillrule_changed( SPPaintSelector * /*psel*/,
303                                   SPPaintSelector::FillRule mode,
304                                   SPWidget *spw )
306     if (g_object_get_data(G_OBJECT(spw), "update")) {
307         return;
308     }
310     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
312     SPCSSAttr *css = sp_repr_css_attr_new();
313     sp_repr_css_set_property(css, "fill-rule", mode == SPPaintSelector::FILLRULE_EVENODD? "evenodd":"nonzero");
315     sp_desktop_set_style(desktop, css);
317     sp_repr_css_attr_unref(css);
318     css = 0;
320     sp_document_done(SP_ACTIVE_DOCUMENT, SP_VERB_DIALOG_FILL_STROKE,
321                      _("Change fill rule"));
324 static gchar const *undo_F_label_1 = "fill:flatcolor:1";
325 static gchar const *undo_F_label_2 = "fill:flatcolor:2";
327 static gchar const *undo_S_label_1 = "stroke:flatcolor:1";
328 static gchar const *undo_S_label_2 = "stroke:flatcolor:2";
330 static gchar const *undo_F_label = undo_F_label_1;
331 static gchar const *undo_S_label = undo_S_label_1;
333 /**
334  * This is called repeatedly while you are dragging a color slider, only for flat color
335  * modes. Previously it set the color in style but did not update the repr for efficiency, however
336  * this was flakey and didn't buy us almost anything. So now it does the same as _changed, except
337  * lumps all its changes for undo.
338  */
339 static void fillnstroke_paint_dragged(SPPaintSelector *psel, SPWidget *spw)
341     if (!spw->inkscape) {
342         return;
343     }
345     if (g_object_get_data(G_OBJECT(spw), "update")) {
346         return;
347     }
349     FillOrStroke kind = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(spw), "kind")) ? FILL : STROKE;
351     if (kind == FILL) {
352         if (g_object_get_data(G_OBJECT(spw), "local")) {
353             // previous local flag not cleared yet;
354             // this means dragged events come too fast, so we better skip this one to speed up display
355             // (it's safe to do this in any case)
356             return;
357         }
358     }
360     g_object_set_data(G_OBJECT(spw), "update", GINT_TO_POINTER(TRUE));
362     switch (psel->mode) {
363         case SPPaintSelector::MODE_COLOR_RGB:
364         case SPPaintSelector::MODE_COLOR_CMYK:
365         {
366             psel->setFlatColor( SP_ACTIVE_DESKTOP, (kind == FILL) ? "fill" : "stroke", (kind == FILL) ? "fill-opacity" : "stroke-opacity" );
367             sp_document_maybe_done(sp_desktop_document(SP_ACTIVE_DESKTOP), (kind == FILL) ? undo_F_label : undo_S_label, SP_VERB_DIALOG_FILL_STROKE,
368                                    (kind == FILL) ? _("Set fill color") : _("Set stroke color"));
369             if (kind == FILL) {
370                 g_object_set_data(G_OBJECT(spw), "local", GINT_TO_POINTER(TRUE)); // local change, do not update from selection
371             }
372             break;
373         }
375         default:
376             g_warning( "file %s: line %d: Paint %d should not emit 'dragged'",
377                        __FILE__, __LINE__, psel->mode );
378             break;
379     }
380     g_object_set_data(G_OBJECT(spw), "update", GINT_TO_POINTER(FALSE));
383 /**
384 This is called (at least) when:
385 1  paint selector mode is switched (e.g. flat color -> gradient)
386 2  you finished dragging a gradient node and released mouse
387 3  you changed a gradient selector parameter (e.g. spread)
388 Must update repr.
389  */
390 static void fillnstroke_paint_changed( SPPaintSelector *psel, SPWidget *spw )
392 #ifdef SP_FS_VERBOSE
393     g_message("fillnstroke_paint_changed(psel:%p, spw:%p)", psel, spw);
394 #endif
395     if (g_object_get_data(G_OBJECT(spw), "update")) {
396         return;
397     }
398     g_object_set_data(G_OBJECT(spw), "update", GINT_TO_POINTER(TRUE));
400     FillOrStroke kind = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(spw), "kind")) ? FILL : STROKE;
402     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
403     if (!desktop) {
404         return;
405     }
406     SPDocument *document = sp_desktop_document(desktop);
407     Inkscape::Selection *selection = sp_desktop_selection(desktop);
409     GSList const *items = selection->itemList();
411     switch (psel->mode) {
412         case SPPaintSelector::MODE_EMPTY:
413             // This should not happen.
414             g_warning( "file %s: line %d: Paint %d should not emit 'changed'",
415                        __FILE__, __LINE__, psel->mode);
416             break;
417         case SPPaintSelector::MODE_MULTIPLE:
418             // This happens when you switch multiple objects with different gradients to flat color;
419             // nothing to do here.
420             break;
422         case SPPaintSelector::MODE_NONE:
423         {
424             SPCSSAttr *css = sp_repr_css_attr_new();
425             sp_repr_css_set_property(css, (kind == FILL) ? "fill" : "stroke", "none");
427             sp_desktop_set_style(desktop, css);
429             sp_repr_css_attr_unref(css);
430             css = 0;
432             sp_document_done(document, SP_VERB_DIALOG_FILL_STROKE,
433                              (kind == FILL) ? _("Remove fill") : _("Remove stroke"));
434             break;
435         }
437         case SPPaintSelector::MODE_COLOR_RGB:
438         case SPPaintSelector::MODE_COLOR_CMYK:
439         {
440             if (kind == FILL) {
441                 // FIXME: fix for GTK breakage, see comment in SelectedStyle::on_opacity_changed; here it results in losing release events
442                 sp_canvas_force_full_redraw_after_interruptions(sp_desktop_canvas(desktop), 0);
443             }
445             psel->setFlatColor( desktop,
446                                 (kind == FILL) ? "fill" : "stroke",
447                                 (kind == FILL) ? "fill-opacity" : "stroke-opacity" );
448             sp_document_maybe_done(sp_desktop_document(desktop), (kind == FILL) ? undo_F_label : undo_S_label, SP_VERB_DIALOG_FILL_STROKE,
449                                    (kind == FILL) ? _("Set fill color") : _("Set stroke color"));
451             if (kind == FILL) {
452                 // resume interruptibility
453                 sp_canvas_end_forced_full_redraws(sp_desktop_canvas(desktop));
454             }
456             // on release, toggle undo_label so that the next drag will not be lumped with this one
457             if (undo_F_label == undo_F_label_1) {
458                 undo_F_label = undo_F_label_2;
459                 undo_S_label = undo_S_label_2;
460             } else {
461                 undo_F_label = undo_F_label_1;
462                 undo_S_label = undo_S_label_1;
463             }
465             break;
466         }
468         case SPPaintSelector::MODE_GRADIENT_LINEAR:
469         case SPPaintSelector::MODE_GRADIENT_RADIAL:
470         case SPPaintSelector::MODE_SWATCH:
471             if (items) {
472                 SPGradientType const gradient_type = ( psel->mode != SPPaintSelector::MODE_GRADIENT_RADIAL
473                                                        ? SP_GRADIENT_TYPE_LINEAR
474                                                        : SP_GRADIENT_TYPE_RADIAL );
476                 SPCSSAttr *css = 0;
477                 if (kind == FILL) {
478                     // HACK: reset fill-opacity - that 0.75 is annoying; BUT remove this when we have an opacity slider for all tabs
479                     css = sp_repr_css_attr_new();
480                     sp_repr_css_set_property(css, "fill-opacity", "1.0");
481                 }
483                 SPGradient *vector = psel->getGradientVector();
484                 if (!vector) {
485                     /* No vector in paint selector should mean that we just changed mode */
487                     SPStyle *query = sp_style_new(SP_ACTIVE_DOCUMENT);
488                     int result = objects_query_fillstroke(const_cast<GSList *>(items), query, kind == FILL);
489                     SPIPaint &targPaint = (kind == FILL) ? query->fill : query->stroke;
490                     guint32 common_rgb = 0;
491                     if (result == QUERY_STYLE_MULTIPLE_SAME) {
492                         if (!targPaint.isColor()) {
493                             common_rgb = sp_desktop_get_color(desktop, kind == FILL);
494                         } else {
495                             common_rgb = targPaint.value.color.toRGBA32( 0xff );
496                         }
497                         vector = sp_document_default_gradient_vector(document, common_rgb);
498                     }
499                     sp_style_unref(query);
501                     for (GSList const *i = items; i != NULL; i = i->next) {
502                         //FIXME: see above
503                         if (kind == FILL) {
504                             sp_repr_css_change_recursive(SP_OBJECT_REPR(i->data), css, "style");
505                         }
507                         if (!vector) {
508                             sp_item_set_gradient(SP_ITEM(i->data),
509                                                  sp_gradient_vector_for_object(document, desktop, SP_OBJECT(i->data), kind == FILL),
510                                                  gradient_type, kind == FILL);
511                         } else {
512                             sp_item_set_gradient(SP_ITEM(i->data), vector, gradient_type, kind == FILL);
513                         }
514                     }
515                 } else {
516                     // We have changed from another gradient type, or modified spread/units within
517                     // this gradient type.
518                     vector = sp_gradient_ensure_vector_normalized(vector);
519                     for (GSList const *i = items; i != NULL; i = i->next) {
520                         //FIXME: see above
521                         if (kind == FILL) {
522                             sp_repr_css_change_recursive(SP_OBJECT_REPR(i->data), css, "style");
523                         }
525                         SPGradient *gr = sp_item_set_gradient(SP_ITEM(i->data), vector, gradient_type, kind == FILL);
526                         psel->pushAttrsToGradient( gr );
527                     }
528                 }
530                 if (css) {
531                     sp_repr_css_attr_unref(css);
532                     css = 0;
533                 }
535                 sp_document_done(document, SP_VERB_DIALOG_FILL_STROKE,
536                                  (kind == FILL) ? _("Set gradient on fill") : _("Set gradient on stroke"));
537             }
538             break;
540         case SPPaintSelector::MODE_PATTERN:
542             if (items) {
544                 SPPattern *pattern = psel->getPattern();
545                 if (!pattern) {
547                     /* No Pattern in paint selector should mean that we just
548                      * changed mode - dont do jack.
549                      */
551                 } else {
552                     Inkscape::XML::Node *patrepr = SP_OBJECT_REPR(pattern);
553                     SPCSSAttr *css = sp_repr_css_attr_new();
554                     gchar *urltext = g_strdup_printf("url(#%s)", patrepr->attribute("id"));
555                     sp_repr_css_set_property(css, (kind == FILL) ? "fill" : "stroke", urltext);
557                     // HACK: reset fill-opacity - that 0.75 is annoying; BUT remove this when we have an opacity slider for all tabs
558                     if (kind == FILL) {
559                         sp_repr_css_set_property(css, "fill-opacity", "1.0");
560                     }
562                     // cannot just call sp_desktop_set_style, because we don't want to touch those
563                     // objects who already have the same root pattern but through a different href
564                     // chain. FIXME: move this to a sp_item_set_pattern
565                     for (GSList const *i = items; i != NULL; i = i->next) {
566                         Inkscape::XML::Node *selrepr = SP_OBJECT_REPR(i->data);
567                         if ( (kind == STROKE) && !selrepr) {
568                             continue;
569                         }
570                         SPObject *selobj = SP_OBJECT(i->data);
572                         SPStyle *style = SP_OBJECT_STYLE(selobj);
573                         if (style && ((kind == FILL) ? style->fill : style->stroke).isPaintserver()) {
574                             SPObject *server = (kind == FILL) ?
575                                 SP_OBJECT_STYLE_FILL_SERVER(selobj) :
576                                 SP_OBJECT_STYLE_STROKE_SERVER(selobj);
577                             if (SP_IS_PATTERN(server) && pattern_getroot(SP_PATTERN(server)) == pattern)
578                                 // only if this object's pattern is not rooted in our selected pattern, apply
579                                 continue;
580                         }
582                         if (kind == FILL) {
583                             sp_desktop_apply_css_recursive(selobj, css, true);
584                         } else {
585                             sp_repr_css_change_recursive(selrepr, css, "style");
586                         }
587                     }
589                     sp_repr_css_attr_unref(css);
590                     css = 0;
591                     g_free(urltext);
593                 } // end if
595                 sp_document_done(document, SP_VERB_DIALOG_FILL_STROKE,
596                                  (kind == FILL) ? _("Set pattern on fill") :
597                                  _("Set pattern on stroke"));
598             } // end if
600             break;
602         case SPPaintSelector::MODE_UNSET:
603             if (items) {
604                 SPCSSAttr *css = sp_repr_css_attr_new();
605                 if (kind == FILL) {
606                     sp_repr_css_unset_property(css, "fill");
607                 } else {
608                     sp_repr_css_unset_property(css, "stroke");
609                     sp_repr_css_unset_property(css, "stroke-opacity");
610                     sp_repr_css_unset_property(css, "stroke-width");
611                     sp_repr_css_unset_property(css, "stroke-miterlimit");
612                     sp_repr_css_unset_property(css, "stroke-linejoin");
613                     sp_repr_css_unset_property(css, "stroke-linecap");
614                     sp_repr_css_unset_property(css, "stroke-dashoffset");
615                     sp_repr_css_unset_property(css, "stroke-dasharray");
616                 }
618                 sp_desktop_set_style(desktop, css);
619                 sp_repr_css_attr_unref(css);
620                 css = 0;
622                 sp_document_done(document, SP_VERB_DIALOG_FILL_STROKE,
623                                  (kind == FILL) ? _("Unset fill") : _("Unset stroke"));
624             }
625             break;
627         default:
628             g_warning( "file %s: line %d: Paint selector should not be in "
629                        "mode %d",
630                        __FILE__, __LINE__,
631                        psel->mode );
632             break;
633     }
635     g_object_set_data(G_OBJECT(spw), "update", GINT_TO_POINTER(FALSE));
639 static void fillnstroke_transientize_called(Inkscape::Application * /*inkscape*/,
640                                     SPDesktop * /*desktop*/,
641                                     SPWidget * /*spw*/ )
643 // TODO:  Either of these will cause crashes sometimes
644 //    sp_stroke_style_line_update( SP_WIDGET(spw), desktop ? sp_desktop_selection(desktop) : NULL);
645 //    ink_markers_menu_update(spw);
648 /*
649   Local Variables:
650   mode:c++
651   c-file-style:"stroustrup"
652   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
653   indent-tabs-mode:nil
654   fill-column:99
655   End:
656 */
657 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :