Code

Merge and cleanup of GSoC C++-ification project.
[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  *   Jon A. Cruz <jon@joncruz.org>
9  *   Abhishek Sharma
10  *
11  * Copyright (C) 1999-2005 authors
12  * Copyright (C) 2001-2002 Ximian, Inc.
13  * Copyright (C) 2010 Jon A. Cruz
14  *
15  * Released under GNU GPL, read the file 'COPYING' for more information
16  */
18 #define noSP_FS_VERBOSE
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
24 #include <glibmm/i18n.h>
25 #include <gtkmm/box.h>
26 #include <gtk/gtkvbox.h>
28 #include "desktop.h"
29 #include "selection.h"
30 #include "desktop-handles.h"
31 #include "desktop-style.h"
32 #include "display/sp-canvas.h"
33 #include "document-private.h"
34 #include "gradient-chemistry.h"
35 #include "inkscape.h"
36 #include "selection.h"
37 #include "sp-linear-gradient.h"
38 #include "sp-pattern.h"
39 #include "sp-radial-gradient.h"
40 #include "style.h"
41 #include "widgets/paint-selector.h"
42 #include "xml/repr.h"
44 #include "fill-style.h"
45 #include "fill-n-stroke-factory.h"
48 // These can be deleted once we sort out the libart dependence.
50 #define ART_WIND_RULE_NONZERO 0
52 /* Fill */
55 Gtk::Widget *sp_fill_style_widget_new(void)
56 {
57     return Inkscape::Widgets::createStyleWidget( FILL );
58 }
61 namespace Inkscape {
63 class FillNStroke : public Gtk::VBox
64 {
65 public:
66     FillNStroke( FillOrStroke kind );
67     ~FillNStroke();
69     void setFillrule( SPPaintSelector::FillRule mode );
71     void setDesktop(SPDesktop *desktop);
73 private:
74     static void paintModeChangeCB(SPPaintSelector *psel, SPPaintSelector::Mode mode, FillNStroke *self);
75     static void paintChangedCB(SPPaintSelector *psel, FillNStroke *self);
76     static void paintDraggedCB(SPPaintSelector *psel, FillNStroke *self);
77     static gboolean dragDelayCB(gpointer data);
79     static void fillruleChangedCB( SPPaintSelector *psel, SPPaintSelector::FillRule mode, FillNStroke *self );
81     void selectionModifiedCB(guint flags);
83     void dragFromPaint();
84     void updateFromPaint();
86     void performUpdate();
88     FillOrStroke kind;
89     SPDesktop *desktop;
90     SPPaintSelector *psel;
91     guint32 lastDrag;
92     guint dragId;
93     bool update;
94     sigc::connection selectChangedConn;
95     sigc::connection subselChangedConn;
96     sigc::connection selectModifiedConn;
97 };
99 } // namespace Inkscape
101 void sp_fill_style_widget_set_desktop(Gtk::Widget *widget, SPDesktop *desktop)
103     Inkscape::FillNStroke *fs = dynamic_cast<Inkscape::FillNStroke*>(widget);
104     if (fs) {
105         fs->setDesktop(desktop);
106     }
109 namespace Inkscape {
111 /**
112  * Create the fill or stroke style widget, and hook up all the signals.
113  */
114 Gtk::Widget *Inkscape::Widgets::createStyleWidget( FillOrStroke kind )
116     FillNStroke *filler = new FillNStroke(kind);
118     return filler;
121 FillNStroke::FillNStroke( FillOrStroke kind ) :
122     Gtk::VBox(),
123     kind(kind),
124     desktop(0),
125     psel(0),
126     lastDrag(0),
127     dragId(0),
128     update(false),
129     selectChangedConn(),
130     subselChangedConn(),
131     selectModifiedConn()
133     // Add and connect up the paint selector widget:
134     psel = sp_paint_selector_new(kind);
135     gtk_widget_show(GTK_WIDGET(psel));
136     gtk_container_add(GTK_CONTAINER(gobj()), GTK_WIDGET(psel));
137     g_signal_connect( G_OBJECT(psel), "mode_changed",
138                       G_CALLBACK(paintModeChangeCB),
139                       this );
141     g_signal_connect( G_OBJECT(psel), "dragged",
142                       G_CALLBACK(paintDraggedCB),
143                       this );
145     g_signal_connect( G_OBJECT(psel), "changed",
146                       G_CALLBACK(paintChangedCB),
147                       this );
148     if (kind == FILL) {
149         g_signal_connect( G_OBJECT(psel), "fillrule_changed",
150                           G_CALLBACK(fillruleChangedCB),
151                           this );
152     }
154     performUpdate();
157 FillNStroke::~FillNStroke()
159     if (dragId) {
160         g_source_remove(dragId);
161         dragId = 0;
162     }
163     psel = 0;
164     selectModifiedConn.disconnect();
165     subselChangedConn.disconnect();
166     selectChangedConn.disconnect();
169 /**
170  * On signal modified, invokes an update of the fill or stroke style paint object.
171  */
172 void FillNStroke::selectionModifiedCB( guint flags )
174     if (flags & ( SP_OBJECT_MODIFIED_FLAG |
175                    SP_OBJECT_PARENT_MODIFIED_FLAG |
176                    SP_OBJECT_STYLE_MODIFIED_FLAG) ) {
177 #ifdef SP_FS_VERBOSE
178         g_message("selectionModifiedCB(%d) on %p", flags, this);
179 #endif
180         performUpdate();
181     }
184 void FillNStroke::setDesktop(SPDesktop *desktop)
186     if (this->desktop != desktop) {
187         if (dragId) {
188             g_source_remove(dragId);
189             dragId = 0;
190         }
191         if (this->desktop) {
192             selectModifiedConn.disconnect();
193             subselChangedConn.disconnect();
194             selectChangedConn.disconnect();
195         }
196         this->desktop = desktop;
197         if (desktop && desktop->selection) {
198             selectChangedConn = desktop->selection->connectChanged(sigc::hide(sigc::mem_fun(*this, &FillNStroke::performUpdate)));
199             subselChangedConn = desktop->connectToolSubselectionChanged(sigc::hide(sigc::mem_fun(*this, &FillNStroke::performUpdate)));
201             // Must check flags, so can't call performUpdate() directly.
202             selectModifiedConn = desktop->selection->connectModified(sigc::hide<0>(sigc::mem_fun(*this, &FillNStroke::selectionModifiedCB)));
203         }
204         performUpdate();
205     }
208 /**
209  * Gets the active fill or stroke style property, then sets the appropriate
210  * color, alpha, gradient, pattern, etc. for the paint-selector.
211  *
212  * @param sel Selection to use, or NULL.
213  */
214 void FillNStroke::performUpdate()
216     if ( update || !desktop ) {
217         return;
218     }
220     if ( dragId ) {
221         // local change; do nothing, but reset the flag
222         g_source_remove(dragId);
223         dragId = 0;
224         return;
225     }
227     update = true;
229     // create temporary style
230     SPStyle *query = sp_style_new(desktop->doc());
232     // query style from desktop into it. This returns a result flag and fills query with the style of subselection, if any, or selection
233     int result = sp_desktop_query_style(desktop, query, (kind == FILL) ? QUERY_STYLE_PROPERTY_FILL : QUERY_STYLE_PROPERTY_STROKE);
235     SPIPaint &targPaint = (kind == FILL) ? query->fill : query->stroke;
236     SPIScale24 &targOpacity = (kind == FILL) ? query->fill_opacity : query->stroke_opacity;
238     switch (result) {
239         case QUERY_STYLE_NOTHING:
240         {
241             /* No paint at all */
242             psel->setMode(SPPaintSelector::MODE_EMPTY);
243             break;
244         }
246         case QUERY_STYLE_SINGLE:
247         case QUERY_STYLE_MULTIPLE_AVERAGED: // TODO: treat this slightly differently, e.g. display "averaged" somewhere in paint selector
248         case QUERY_STYLE_MULTIPLE_SAME:
249         {
250             SPPaintSelector::Mode pselmode = SPPaintSelector::getModeForStyle(*query, kind);
251             psel->setMode(pselmode);
253             if (kind == FILL) {
254                 psel->setFillrule(query->fill_rule.computed == ART_WIND_RULE_NONZERO?
255                                   SPPaintSelector::FILLRULE_NONZERO : SPPaintSelector::FILLRULE_EVENODD);
256             }
258             if (targPaint.set && targPaint.isColor()) {
259                 psel->setColorAlpha(targPaint.value.color, SP_SCALE24_TO_FLOAT(targOpacity.value));
260             } else if (targPaint.set && targPaint.isPaintserver()) {
262                 SPPaintServer *server = (kind == FILL) ? query->getFillPaintServer() : query->getStrokePaintServer();
264                 if (server && SP_IS_GRADIENT(server) && SP_GRADIENT(server)->getVector()->isSwatch()) {
265                     SPGradient *vector = SP_GRADIENT(server)->getVector();
266                     psel->setSwatch( vector );
267                 } else if (SP_IS_LINEARGRADIENT(server)) {
268                     SPGradient *vector = SP_GRADIENT(server)->getVector();
269                     psel->setGradientLinear( vector );
271                     SPLinearGradient *lg = SP_LINEARGRADIENT(server);
272                     psel->setGradientProperties( lg->getUnits(),
273                                                  lg->getSpread() );
274                 } else if (SP_IS_RADIALGRADIENT(server)) {
275                     SPGradient *vector = SP_GRADIENT(server)->getVector();
276                     psel->setGradientRadial( vector );
278                     SPRadialGradient *rg = SP_RADIALGRADIENT(server);
279                     psel->setGradientProperties( rg->getUnits(),
280                                                  rg->getSpread() );
281                 } else if (SP_IS_PATTERN(server)) {
282                     SPPattern *pat = pattern_getroot(SP_PATTERN(server));
283                     psel->updatePatternList( pat );
284                 }
285             }
286             break;
287         }
289         case QUERY_STYLE_MULTIPLE_DIFFERENT:
290         {
291             psel->setMode(SPPaintSelector::MODE_MULTIPLE);
292             break;
293         }
294     }
296     sp_style_unref(query);
298     update = false;
301 /**
302  * When the mode is changed, invoke a regular changed handler.
303  */
304 void FillNStroke::paintModeChangeCB( SPPaintSelector * /*psel*/,
305                                      SPPaintSelector::Mode /*mode*/,
306                                      FillNStroke *self )
308 #ifdef SP_FS_VERBOSE
309     g_message("paintModeChangeCB(psel, mode, self:%p)", self);
310 #endif
311     if (self && !self->update) {
312         self->updateFromPaint();
313     }
316 void FillNStroke::fillruleChangedCB( SPPaintSelector * /*psel*/,
317                                      SPPaintSelector::FillRule mode,
318                                      FillNStroke *self )
320     if (self) {
321         self->setFillrule(mode);
322     }
325 void FillNStroke::setFillrule( SPPaintSelector::FillRule mode )
327     if (!update && desktop) {
328         SPCSSAttr *css = sp_repr_css_attr_new();
329         sp_repr_css_set_property(css, "fill-rule", (mode == SPPaintSelector::FILLRULE_EVENODD) ? "evenodd":"nonzero");
331         sp_desktop_set_style(desktop, css);
333         sp_repr_css_attr_unref(css);
334         css = 0;
336         DocumentUndo::done(desktop->doc(), SP_VERB_DIALOG_FILL_STROKE,
337                            _("Change fill rule"));
338     }
341 static gchar const *undo_F_label_1 = "fill:flatcolor:1";
342 static gchar const *undo_F_label_2 = "fill:flatcolor:2";
344 static gchar const *undo_S_label_1 = "stroke:flatcolor:1";
345 static gchar const *undo_S_label_2 = "stroke:flatcolor:2";
347 static gchar const *undo_F_label = undo_F_label_1;
348 static gchar const *undo_S_label = undo_S_label_1;
351 void FillNStroke::paintDraggedCB(SPPaintSelector * /*psel*/, FillNStroke *self)
353 #ifdef SP_FS_VERBOSE
354     g_message("paintDraggedCB(psel, spw:%p)", self);
355 #endif
356     if (self && !self->update) {
357         self->dragFromPaint();
358     }
362 gboolean FillNStroke::dragDelayCB(gpointer data)
364     gboolean keepGoing = TRUE;
365     if (data) {
366         FillNStroke *self = reinterpret_cast<FillNStroke*>(data);
367         if (!self->update) {
368             if (self->dragId) {
369                 g_source_remove(self->dragId);
370                 self->dragId = 0;
372                 self->dragFromPaint();
373                 self->performUpdate();
374             }
375             keepGoing = FALSE;
376         }
377     } else {
378         keepGoing = FALSE;
379     }
380     return keepGoing;
383 /**
384  * This is called repeatedly while you are dragging a color slider, only for flat color
385  * modes. Previously it set the color in style but did not update the repr for efficiency, however
386  * this was flakey and didn't buy us almost anything. So now it does the same as _changed, except
387  * lumps all its changes for undo.
388  */
389 void FillNStroke::dragFromPaint()
391     if (!desktop || update) {
392         return;
393     }
395     guint32 when = gtk_get_current_event_time();
397     // Don't attempt too many updates per second.
398     // Assume a base 15.625ms resolution on the timer.
399     if (!dragId && lastDrag && when && ((when - lastDrag) < 32)) {
400         // local change, do not update from selection
401         dragId = g_timeout_add_full(G_PRIORITY_DEFAULT, 33, dragDelayCB, this, 0);
402     }
404     if (dragId) {
405         // previous local flag not cleared yet;
406         // this means dragged events come too fast, so we better skip this one to speed up display
407         // (it's safe to do this in any case)
408         return;
409     }
410     lastDrag = when;
412     update = true;
414     switch (psel->mode) {
415         case SPPaintSelector::MODE_COLOR_RGB:
416         case SPPaintSelector::MODE_COLOR_CMYK:
417         {
418             // local change, do not update from selection
419             dragId = g_timeout_add_full(G_PRIORITY_DEFAULT, 100, dragDelayCB, this, 0);
420             psel->setFlatColor( desktop, (kind == FILL) ? "fill" : "stroke", (kind == FILL) ? "fill-opacity" : "stroke-opacity" );
421             DocumentUndo::maybeDone(desktop->doc(), (kind == FILL) ? undo_F_label : undo_S_label, SP_VERB_DIALOG_FILL_STROKE,
422                                     (kind == FILL) ? _("Set fill color") : _("Set stroke color"));
423             break;
424         }
426         default:
427             g_warning( "file %s: line %d: Paint %d should not emit 'dragged'",
428                        __FILE__, __LINE__, psel->mode );
429             break;
430     }
431     update = false;
434 /**
435 This is called (at least) when:
436 1  paint selector mode is switched (e.g. flat color -> gradient)
437 2  you finished dragging a gradient node and released mouse
438 3  you changed a gradient selector parameter (e.g. spread)
439 Must update repr.
440  */
441 void FillNStroke::paintChangedCB( SPPaintSelector * /*psel*/, FillNStroke *self )
443 #ifdef SP_FS_VERBOSE
444     g_message("paintChangedCB(psel, spw:%p)", self);
445 #endif
446     if (self && !self->update) {
447         self->updateFromPaint();
448     }
451 void FillNStroke::updateFromPaint()
453     if (!desktop) {
454         return;
455     }
456     update = true;
458     SPDocument *document = sp_desktop_document(desktop);
459     Inkscape::Selection *selection = sp_desktop_selection(desktop);
461     GSList const *items = selection->itemList();
463     switch (psel->mode) {
464         case SPPaintSelector::MODE_EMPTY:
465             // This should not happen.
466             g_warning( "file %s: line %d: Paint %d should not emit 'changed'",
467                        __FILE__, __LINE__, psel->mode);
468             break;
469         case SPPaintSelector::MODE_MULTIPLE:
470             // This happens when you switch multiple objects with different gradients to flat color;
471             // nothing to do here.
472             break;
474         case SPPaintSelector::MODE_NONE:
475         {
476             SPCSSAttr *css = sp_repr_css_attr_new();
477             sp_repr_css_set_property(css, (kind == FILL) ? "fill" : "stroke", "none");
479             sp_desktop_set_style(desktop, css);
481             sp_repr_css_attr_unref(css);
482             css = 0;
484             DocumentUndo::done(document, SP_VERB_DIALOG_FILL_STROKE,
485                                (kind == FILL) ? _("Remove fill") : _("Remove stroke"));
486             break;
487         }
489         case SPPaintSelector::MODE_COLOR_RGB:
490         case SPPaintSelector::MODE_COLOR_CMYK:
491         {
492             if (kind == FILL) {
493                 // FIXME: fix for GTK breakage, see comment in SelectedStyle::on_opacity_changed; here it results in losing release events
494                 sp_canvas_force_full_redraw_after_interruptions(sp_desktop_canvas(desktop), 0);
495             }
497             psel->setFlatColor( desktop,
498                                 (kind == FILL) ? "fill" : "stroke",
499                                 (kind == FILL) ? "fill-opacity" : "stroke-opacity" );
500             DocumentUndo::maybeDone(sp_desktop_document(desktop), (kind == FILL) ? undo_F_label : undo_S_label, SP_VERB_DIALOG_FILL_STROKE,
501                                     (kind == FILL) ? _("Set fill color") : _("Set stroke color"));
503             if (kind == FILL) {
504                 // resume interruptibility
505                 sp_canvas_end_forced_full_redraws(sp_desktop_canvas(desktop));
506             }
508             // on release, toggle undo_label so that the next drag will not be lumped with this one
509             if (undo_F_label == undo_F_label_1) {
510                 undo_F_label = undo_F_label_2;
511                 undo_S_label = undo_S_label_2;
512             } else {
513                 undo_F_label = undo_F_label_1;
514                 undo_S_label = undo_S_label_1;
515             }
517             break;
518         }
520         case SPPaintSelector::MODE_GRADIENT_LINEAR:
521         case SPPaintSelector::MODE_GRADIENT_RADIAL:
522         case SPPaintSelector::MODE_SWATCH:
523             if (items) {
524                 SPGradientType const gradient_type = ( psel->mode != SPPaintSelector::MODE_GRADIENT_RADIAL
525                                                        ? SP_GRADIENT_TYPE_LINEAR
526                                                        : SP_GRADIENT_TYPE_RADIAL );
527                 bool createSwatch = (psel->mode == SPPaintSelector::MODE_SWATCH);
529                 SPCSSAttr *css = 0;
530                 if (kind == FILL) {
531                     // HACK: reset fill-opacity - that 0.75 is annoying; BUT remove this when we have an opacity slider for all tabs
532                     css = sp_repr_css_attr_new();
533                     sp_repr_css_set_property(css, "fill-opacity", "1.0");
534                 }
536                 SPGradient *vector = psel->getGradientVector();
537                 if (!vector) {
538                     /* No vector in paint selector should mean that we just changed mode */
540                     SPStyle *query = sp_style_new(desktop->doc());
541                     int result = objects_query_fillstroke(const_cast<GSList *>(items), query, kind == FILL);
542                     if (result == QUERY_STYLE_MULTIPLE_SAME) {
543                         SPIPaint &targPaint = (kind == FILL) ? query->fill : query->stroke;
544                         SPColor common;
545                         if (!targPaint.isColor()) {
546                             common = sp_desktop_get_color(desktop, kind == FILL);
547                         } else {
548                             common = targPaint.value.color;
549                         }
550                         vector = sp_document_default_gradient_vector( document, common, createSwatch );
551                         if ( vector && createSwatch ) {
552                             vector->setSwatch();
553                         }
554                     }
555                     sp_style_unref(query);
557                     for (GSList const *i = items; i != NULL; i = i->next) {
558                         //FIXME: see above
559                         if (kind == FILL) {
560                             sp_repr_css_change_recursive(reinterpret_cast<SPObject*>(i->data)->getRepr(), css, "style");
561                         }
563                         if (!vector) {
564                             SPGradient *gr = sp_gradient_vector_for_object( document, desktop, reinterpret_cast<SPObject*>(i->data), kind == FILL, createSwatch );
565                             if ( gr && createSwatch ) {
566                                 gr->setSwatch();
567                             }
568                             sp_item_set_gradient(SP_ITEM(i->data),
569                                                  gr,
570                                                  gradient_type, kind == FILL);
571                         } else {
572                             sp_item_set_gradient(SP_ITEM(i->data), vector, gradient_type, kind == FILL);
573                         }
574                     }
575                 } else {
576                     // We have changed from another gradient type, or modified spread/units within
577                     // this gradient type.
578                     vector = sp_gradient_ensure_vector_normalized(vector);
579                     for (GSList const *i = items; i != NULL; i = i->next) {
580                         //FIXME: see above
581                         if (kind == FILL) {
582                             sp_repr_css_change_recursive(reinterpret_cast<SPObject*>(i->data)->getRepr(), css, "style");
583                         }
585                         SPGradient *gr = sp_item_set_gradient(SP_ITEM(i->data), vector, gradient_type, kind == FILL);
586                         psel->pushAttrsToGradient( gr );
587                     }
588                 }
590                 if (css) {
591                     sp_repr_css_attr_unref(css);
592                     css = 0;
593                 }
595                 DocumentUndo::done(document, SP_VERB_DIALOG_FILL_STROKE,
596                                    (kind == FILL) ? _("Set gradient on fill") : _("Set gradient on stroke"));
597             }
598             break;
600         case SPPaintSelector::MODE_PATTERN:
602             if (items) {
604                 SPPattern *pattern = psel->getPattern();
605                 if (!pattern) {
607                     /* No Pattern in paint selector should mean that we just
608                      * changed mode - dont do jack.
609                      */
611                 } else {
612                     Inkscape::XML::Node *patrepr = pattern->getRepr();
613                     SPCSSAttr *css = sp_repr_css_attr_new();
614                     gchar *urltext = g_strdup_printf("url(#%s)", patrepr->attribute("id"));
615                     sp_repr_css_set_property(css, (kind == FILL) ? "fill" : "stroke", urltext);
617                     // HACK: reset fill-opacity - that 0.75 is annoying; BUT remove this when we have an opacity slider for all tabs
618                     if (kind == FILL) {
619                         sp_repr_css_set_property(css, "fill-opacity", "1.0");
620                     }
622                     // cannot just call sp_desktop_set_style, because we don't want to touch those
623                     // objects who already have the same root pattern but through a different href
624                     // chain. FIXME: move this to a sp_item_set_pattern
625                     for (GSList const *i = items; i != NULL; i = i->next) {
626                         Inkscape::XML::Node *selrepr = reinterpret_cast<SPObject*>(i->data)->getRepr();
627                         if ( (kind == STROKE) && !selrepr) {
628                             continue;
629                         }
630                         SPObject *selobj = reinterpret_cast<SPObject*>(i->data);
632                         SPStyle *style = selobj->style;
633                         if (style && ((kind == FILL) ? style->fill : style->stroke).isPaintserver()) {
634                             SPPaintServer *server = (kind == FILL) ?
635                                 selobj->style->getFillPaintServer() :
636                                 selobj->style->getStrokePaintServer();
637                             if (SP_IS_PATTERN(server) && pattern_getroot(SP_PATTERN(server)) == pattern)
638                                 // only if this object's pattern is not rooted in our selected pattern, apply
639                                 continue;
640                         }
642                         if (kind == FILL) {
643                             sp_desktop_apply_css_recursive(selobj, css, true);
644                         } else {
645                             sp_repr_css_change_recursive(selrepr, css, "style");
646                         }
647                     }
649                     sp_repr_css_attr_unref(css);
650                     css = 0;
651                     g_free(urltext);
653                 } // end if
655                 DocumentUndo::done(document, SP_VERB_DIALOG_FILL_STROKE,
656                                    (kind == FILL) ? _("Set pattern on fill") :
657                                    _("Set pattern on stroke"));
658             } // end if
660             break;
662         case SPPaintSelector::MODE_UNSET:
663             if (items) {
664                 SPCSSAttr *css = sp_repr_css_attr_new();
665                 if (kind == FILL) {
666                     sp_repr_css_unset_property(css, "fill");
667                 } else {
668                     sp_repr_css_unset_property(css, "stroke");
669                     sp_repr_css_unset_property(css, "stroke-opacity");
670                     sp_repr_css_unset_property(css, "stroke-width");
671                     sp_repr_css_unset_property(css, "stroke-miterlimit");
672                     sp_repr_css_unset_property(css, "stroke-linejoin");
673                     sp_repr_css_unset_property(css, "stroke-linecap");
674                     sp_repr_css_unset_property(css, "stroke-dashoffset");
675                     sp_repr_css_unset_property(css, "stroke-dasharray");
676                 }
678                 sp_desktop_set_style(desktop, css);
679                 sp_repr_css_attr_unref(css);
680                 css = 0;
682                 DocumentUndo::done(document, SP_VERB_DIALOG_FILL_STROKE,
683                                    (kind == FILL) ? _("Unset fill") : _("Unset stroke"));
684             }
685             break;
687         default:
688             g_warning( "file %s: line %d: Paint selector should not be in "
689                        "mode %d",
690                        __FILE__, __LINE__,
691                        psel->mode );
692             break;
693     }
695     update = false;
698 } // namespace Inkscape
700 /*
701   Local Variables:
702   mode:c++
703   c-file-style:"stroustrup"
704   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
705   indent-tabs-mode:nil
706   fill-column:99
707   End:
708 */
709 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :