Code

search and reset buttons added to ocal related features. fixed signals in import...
[inkscape.git] / src / ui / widget / selected-style.cpp
index a2e57d6000a315003ab097d31408d0af5e857d30..fcd56ad441333185317f9b4999230e5bc45d22d7 100644 (file)
 #include "document.h"
 #include "widgets/widget-sizes.h"
 #include "widgets/spinbutton-events.h"
+#include "widgets/gradient-image.h"
+#include "sp-gradient.h"
 #include "svg/svg-color.h"
 #include "svg/css-ostringstream.h"
 #include "helper/units.h"
+#include "verbs.h"
+#include <display/sp-canvas.h>
 
 static gdouble const _sw_presets[]     = { 32 ,  16 ,  10 ,  8 ,  6 ,  4 ,  3 ,  2 ,  1.5 ,  1 ,  0.75 ,  0.5 ,  0.25 ,  0.1 };
 static gchar* const _sw_presets_str[] = {"32", "16", "10", "8", "6", "4", "3", "2", "1.5", "1", "0.75", "0.5", "0.25", "0.1"};
@@ -85,8 +89,8 @@ SelectedStyle::SelectedStyle(bool layout)
     : _desktop (NULL),
 
       _table(2, 6),
-      _fill_label (_("F:")),
-      _stroke_label (_("S:")),
+      _fill_label (_("Fill:")),
+      _stroke_label (_("Stroke:")),
       _opacity_label (_("O:")),
       _fill_place (),
       _stroke_place (),
@@ -95,8 +99,8 @@ SelectedStyle::SelectedStyle(bool layout)
       _stroke_flag_place (),
 
       _opacity_place (),
-      _opacity_adjustment (1.0, 0.0, 1.0, 0.01, 0.1),
-      _opacity_sb (0.02, 2),
+      _opacity_adjustment (100, 0.0, 100, 1.0, 10.0),
+      _opacity_sb (0.02, 0),
 
       _stroke (),
       _stroke_width (""),
@@ -132,7 +136,7 @@ SelectedStyle::SelectedStyle(bool layout)
         _na[i].show_all();
         __na[i] = (_("Nothing selected"));
 
-        _none[i].set_markup (_("None"));
+        _none[i].set_markup (_("<i>None</i>"));
         sp_set_font_size_smaller (GTK_WIDGET(_none[i].gobj()));
         _none[i].show_all();
         __none[i] = (i == SS_FILL)? (_("No fill")) : (_("No stroke"));
@@ -142,22 +146,32 @@ SelectedStyle::SelectedStyle(bool layout)
         _pattern[i].show_all();
         __pattern[i] = (i == SS_FILL)? (_("Pattern fill")) : (_("Pattern stroke"));
 
-        _lgradient[i].set_markup (_("L Gradient"));
+        _lgradient[i].set_markup (_("<b>L</b>"));
         sp_set_font_size_smaller (GTK_WIDGET(_lgradient[i].gobj()));
         _lgradient[i].show_all();
         __lgradient[i] = (i == SS_FILL)? (_("Linear gradient fill")) : (_("Linear gradient stroke"));
 
-        _rgradient[i].set_markup (_("R Gradient"));
+        _gradient_preview_l[i] =  GTK_WIDGET(sp_gradient_image_new (NULL));
+        _gradient_box_l[i].pack_start(_lgradient[i]);
+        _gradient_box_l[i].pack_start(*(Glib::wrap(_gradient_preview_l[i])));
+        _gradient_box_l[i].show_all();
+
+        _rgradient[i].set_markup (_("<b>R</b>"));
         sp_set_font_size_smaller (GTK_WIDGET(_rgradient[i].gobj()));
         _rgradient[i].show_all();
         __rgradient[i] = (i == SS_FILL)? (_("Radial gradient fill")) : (_("Radial gradient stroke"));
 
+        _gradient_preview_r[i] = GTK_WIDGET(sp_gradient_image_new (NULL));
+        _gradient_box_r[i].pack_start(_rgradient[i]);
+        _gradient_box_r[i].pack_start(*(Glib::wrap(_gradient_preview_r[i])));
+        _gradient_box_r[i].show_all();
+
         _many[i].set_markup (_("Different"));
         sp_set_font_size_smaller (GTK_WIDGET(_many[i].gobj()));
         _many[i].show_all();
         __many[i] = (i == SS_FILL)? (_("Different fills")) : (_("Different strokes"));
 
-        _unset[i].set_markup (_("Unset"));
+        _unset[i].set_markup (_("<b>Unset</b>"));
         sp_set_font_size_smaller (GTK_WIDGET(_unset[i].gobj()));
         _unset[i].show_all();
         __unset[i] = (i == SS_FILL)? (_("Unset fill")) : (_("Unset stroke"));
@@ -305,8 +319,8 @@ SelectedStyle::SelectedStyle(bool layout)
     _opacity_sb.set_size_request (SELECTED_STYLE_SB_WIDTH, -1);
     _opacity_sb.set_sensitive (false);
 
-    _table.attach(_fill_label, 0,1, 0,1, Gtk::SHRINK, Gtk::SHRINK);
-    _table.attach(_stroke_label, 0,1, 1,2, Gtk::SHRINK, Gtk::SHRINK);
+    _table.attach(_fill_label, 0,1, 0,1, Gtk::FILL, Gtk::SHRINK);
+    _table.attach(_stroke_label, 0,1, 1,2, Gtk::FILL, Gtk::SHRINK);
 
     _table.attach(_fill_flag_place, 1,2, 0,1, Gtk::SHRINK, Gtk::SHRINK);
     _table.attach(_stroke_flag_place, 1,2, 1,2, Gtk::SHRINK, Gtk::SHRINK);
@@ -362,6 +376,9 @@ SelectedStyle::~SelectedStyle()
 
     for (int i = SS_FILL; i <= SS_STROKE; i++) {
         delete _color_preview[i];
+        // FIXME: do we need this? the destroy methods are not exported 
+        //sp_gradient_image_destroy(GTK_OBJECT(_gradient_preview_l[i]));
+        //sp_gradient_image_destroy(GTK_OBJECT(_gradient_preview_r[i]));
     }
 
     delete (DropTracker*)_drop[SS_FILL];
@@ -425,7 +442,8 @@ void SelectedStyle::dragDataReceived( GtkWidget *widget,
                 sp_repr_css_set_property( css, (tracker->item == SS_FILL) ? "fill":"stroke", c );
                 sp_desktop_set_style( tracker->parent->_desktop, css );
                 sp_repr_css_attr_unref( css );
-                sp_document_done( sp_desktop_document(tracker->parent->_desktop) );
+                sp_document_done( sp_desktop_document(tracker->parent->_desktop) , SP_VERB_NONE, 
+                                  _("Drop color"));
             }
         }
         break;
@@ -437,7 +455,8 @@ void SelectedStyle::on_fill_remove() {
     sp_repr_css_set_property (css, "fill", "none");
     sp_desktop_set_style (_desktop, css, true, true); 
     sp_repr_css_attr_unref (css);
-    sp_document_done (sp_desktop_document(_desktop));
+    sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
+                      _("Remove fill"));
 }
 
 void SelectedStyle::on_stroke_remove() {
@@ -445,7 +464,8 @@ void SelectedStyle::on_stroke_remove() {
     sp_repr_css_set_property (css, "stroke", "none");
     sp_desktop_set_style (_desktop, css, true, true); 
     sp_repr_css_attr_unref (css);
-    sp_document_done (sp_desktop_document(_desktop));
+    sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
+                      _("Remove stroke"));
 }
 
 void SelectedStyle::on_fill_unset() {
@@ -453,7 +473,8 @@ void SelectedStyle::on_fill_unset() {
     sp_repr_css_unset_property (css, "fill");
     sp_desktop_set_style (_desktop, css, true, true); 
     sp_repr_css_attr_unref (css);
-    sp_document_done (sp_desktop_document(_desktop));
+    sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
+                      _("Unset fill"));
 }
 
 void SelectedStyle::on_stroke_unset() {
@@ -461,7 +482,8 @@ void SelectedStyle::on_stroke_unset() {
     sp_repr_css_unset_property (css, "stroke");
     sp_desktop_set_style (_desktop, css, true, true);
     sp_repr_css_attr_unref (css);
-    sp_document_done (sp_desktop_document(_desktop));
+    sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
+                      _("Unset stroke"));
 }
 
 void SelectedStyle::on_fill_opaque() {
@@ -469,7 +491,8 @@ void SelectedStyle::on_fill_opaque() {
     sp_repr_css_set_property (css, "fill-opacity", "1");
     sp_desktop_set_style (_desktop, css, true);
     sp_repr_css_attr_unref (css);
-    sp_document_done (sp_desktop_document(_desktop));
+    sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
+                      _("Make fill opaque"));
 }
 
 void SelectedStyle::on_stroke_opaque() {
@@ -477,7 +500,8 @@ void SelectedStyle::on_stroke_opaque() {
     sp_repr_css_set_property (css, "stroke-opacity", "1");
     sp_desktop_set_style (_desktop, css, true);
     sp_repr_css_attr_unref (css);
-    sp_document_done (sp_desktop_document(_desktop));
+    sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
+                      _("Make fill opaque"));
 }
 
 void SelectedStyle::on_fill_lastused() {
@@ -488,7 +512,8 @@ void SelectedStyle::on_fill_lastused() {
     sp_repr_css_set_property (css, "fill", c);
     sp_desktop_set_style (_desktop, css);
     sp_repr_css_attr_unref (css);
-    sp_document_done (sp_desktop_document(_desktop));
+    sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE, 
+                      _("Apply last set color to fill"));
 }
 
 void SelectedStyle::on_stroke_lastused() {
@@ -499,7 +524,8 @@ void SelectedStyle::on_stroke_lastused() {
     sp_repr_css_set_property (css, "stroke", c);
     sp_desktop_set_style (_desktop, css);
     sp_repr_css_attr_unref (css);
-    sp_document_done (sp_desktop_document(_desktop));
+    sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE, 
+                      _("Apply last set color to stroke"));
 }
 
 void SelectedStyle::on_fill_lastselected() {
@@ -509,7 +535,8 @@ void SelectedStyle::on_fill_lastselected() {
     sp_repr_css_set_property (css, "fill", c);
     sp_desktop_set_style (_desktop, css);
     sp_repr_css_attr_unref (css);
-    sp_document_done (sp_desktop_document(_desktop));
+    sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
+                      _("Apply last selected color to fill"));
 }
 
 void SelectedStyle::on_stroke_lastselected() {
@@ -519,7 +546,8 @@ void SelectedStyle::on_stroke_lastselected() {
     sp_repr_css_set_property (css, "stroke", c);
     sp_desktop_set_style (_desktop, css);
     sp_repr_css_attr_unref (css);
-    sp_document_done (sp_desktop_document(_desktop));
+    sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE, 
+                      _("Apply last selected color to stroke"));
 }
 
 void SelectedStyle::on_fill_invert() {
@@ -538,7 +566,8 @@ void SelectedStyle::on_fill_invert() {
     sp_repr_css_set_property (css, "fill", c);
     sp_desktop_set_style (_desktop, css);
     sp_repr_css_attr_unref (css);
-    sp_document_done (sp_desktop_document(_desktop));
+    sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
+                      _("Invert fill"));
 }
 
 void SelectedStyle::on_stroke_invert() {
@@ -557,7 +586,8 @@ void SelectedStyle::on_stroke_invert() {
     sp_repr_css_set_property (css, "stroke", c);
     sp_desktop_set_style (_desktop, css);
     sp_repr_css_attr_unref (css);
-    sp_document_done (sp_desktop_document(_desktop));
+    sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
+                      _("Invert stroke"));
 } 
 
 void SelectedStyle::on_fill_white() {
@@ -568,7 +598,8 @@ void SelectedStyle::on_fill_white() {
     sp_repr_css_set_property (css, "fill-opacity", "1");
     sp_desktop_set_style (_desktop, css);
     sp_repr_css_attr_unref (css);
-    sp_document_done (sp_desktop_document(_desktop));
+    sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
+                      _("White fill"));
 }
 
 void SelectedStyle::on_stroke_white() {
@@ -579,7 +610,8 @@ void SelectedStyle::on_stroke_white() {
     sp_repr_css_set_property (css, "stroke-opacity", "1");
     sp_desktop_set_style (_desktop, css);
     sp_repr_css_attr_unref (css);
-    sp_document_done (sp_desktop_document(_desktop));
+    sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE, 
+                      _("White stroke"));
 }
 
 void SelectedStyle::on_fill_black() {
@@ -590,7 +622,8 @@ void SelectedStyle::on_fill_black() {
     sp_repr_css_set_property (css, "fill-opacity", "1.0");
     sp_desktop_set_style (_desktop, css);
     sp_repr_css_attr_unref (css);
-    sp_document_done (sp_desktop_document(_desktop));
+    sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE, 
+                      _("Black fill"));
 }
 
 void SelectedStyle::on_stroke_black() {
@@ -601,7 +634,8 @@ void SelectedStyle::on_stroke_black() {
     sp_repr_css_set_property (css, "stroke-opacity", "1.0");
     sp_desktop_set_style (_desktop, css);
     sp_repr_css_attr_unref (css);
-    sp_document_done (sp_desktop_document(_desktop));
+    sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE, 
+                      _("Black stroke"));
 }
 
 void SelectedStyle::on_fill_copy() {
@@ -643,7 +677,8 @@ void SelectedStyle::on_fill_paste() {
         sp_repr_css_set_property (css, "fill", text.c_str());
         sp_desktop_set_style (_desktop, css);
         sp_repr_css_attr_unref (css);
-        sp_document_done (sp_desktop_document(_desktop));
+        sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE, 
+                      _("Paste fill"));
     }
 }
 
@@ -660,15 +695,14 @@ void SelectedStyle::on_stroke_paste() {
         sp_repr_css_set_property (css, "stroke", text.c_str());
         sp_desktop_set_style (_desktop, css);
         sp_repr_css_attr_unref (css);
-        sp_document_done (sp_desktop_document(_desktop));
+        sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
+                      _("Paste stroke"));
     }
 }
 
 void SelectedStyle::on_fillstroke_swap() {
     SPCSSAttr *css = sp_repr_css_attr_new ();
 
-    g_message("on_fillstroke_swap()");
-
     switch (_mode[SS_FILL]) {
     case SS_NA:
     case SS_MANY:
@@ -715,7 +749,8 @@ void SelectedStyle::on_fillstroke_swap() {
 
     sp_desktop_set_style (_desktop, css);
     sp_repr_css_attr_unref (css);
-    sp_document_done (sp_desktop_document(_desktop));
+    sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE, 
+                      _("Swap fill and stroke"));
 }
 
 void SelectedStyle::on_fill_edit() {
@@ -777,12 +812,13 @@ bool
 SelectedStyle::on_opacity_click(GdkEventButton *event)
 {
     if (event->button == 2) { // middle click
-        const char* opacity = _opacity_sb.get_value() < 0.5? "0.5" : (_opacity_sb.get_value() == 1? "0" : "1");
+        const char* opacity = _opacity_sb.get_value() < 50? "0.5" : (_opacity_sb.get_value() == 100? "0" : "1");
         SPCSSAttr *css = sp_repr_css_attr_new ();
         sp_repr_css_set_property (css, "opacity", opacity);
         sp_desktop_set_style (_desktop, css);
         sp_repr_css_attr_unref (css);
-        sp_document_done (sp_desktop_document (_desktop));
+        sp_document_done (sp_desktop_document (_desktop), SP_VERB_DIALOG_FILL_STROKE,
+                      _("Change opacity"));
         return true;
     }
 
@@ -813,9 +849,11 @@ void SelectedStyle::on_popup_preset(int i) {
     Inkscape::CSSOStringStream os;
     os << w;
     sp_repr_css_set_property (css, "stroke-width", os.str().c_str());
+    // FIXME: update dash patterns!
     sp_desktop_set_style (_desktop, css, true);
     sp_repr_css_attr_unref (css);
-    sp_document_done (sp_desktop_document(_desktop));
+    sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_SWATCHES,
+                      _("Change stroke width"));
 }
 
 void
@@ -825,7 +863,7 @@ SelectedStyle::update()
         return;
 
     // create temporary style
-    SPStyle *query = sp_style_new ();
+    SPStyle *query = sp_style_new (sp_desktop_document(_desktop));
 
     for (int i = SS_FILL; i <= SS_STROKE; i++) {
         Gtk::EventBox *place = (i == SS_FILL)? &_fill_place : &_stroke_place;
@@ -895,11 +933,15 @@ SelectedStyle::update()
                     _paintserver_id[i] += ")";
 
                     if (SP_IS_LINEARGRADIENT (server)) {
-                        place->add(_lgradient[i]);
+                        SPGradient *vector = sp_gradient_get_vector(SP_GRADIENT(server), false);
+                        sp_gradient_image_set_gradient ((SPGradientImage *) _gradient_preview_l[i], vector);
+                        place->add(_gradient_box_l[i]);
                         _tooltips.set_tip(*place, __lgradient[i]);
                         _mode[i] = SS_LGRADIENT;
                     } else if (SP_IS_RADIALGRADIENT (server)) {
-                        place->add(_rgradient[i]);
+                        SPGradient *vector = sp_gradient_get_vector(SP_GRADIENT(server), false);
+                        sp_gradient_image_set_gradient ((SPGradientImage *) _gradient_preview_r[i], vector);
+                        place->add(_gradient_box_r[i]);
                         _tooltips.set_tip(*place, __rgradient[i]);
                         _mode[i] = SS_RGRADIENT;
                     } else if (SP_IS_PATTERN (server)) {
@@ -940,21 +982,25 @@ SelectedStyle::update()
 
 // Now query opacity
     _tooltips.unset_tip(_opacity_place);
+    _tooltips.unset_tip(_opacity_sb);
 
     int result = sp_desktop_query_style (_desktop, query, QUERY_STYLE_PROPERTY_MASTEROPACITY);
 
     switch (result) {
     case QUERY_STYLE_NOTHING:
         _tooltips.set_tip(_opacity_place, _("Nothing selected"));
+        _tooltips.set_tip(_opacity_sb, _("Nothing selected"));
         _opacity_sb.set_sensitive(false);
         break;
     case QUERY_STYLE_SINGLE:
     case QUERY_STYLE_MULTIPLE_AVERAGED:
     case QUERY_STYLE_MULTIPLE_SAME:
-        _tooltips.set_tip(_opacity_place, _("Master opacity"));
+        _tooltips.set_tip(_opacity_place, _("Master opacity, %"));
+        _tooltips.set_tip(_opacity_sb, _("Master opacity, %"));
+        if (_opacity_blocked) break;
         _opacity_blocked = true;
         _opacity_sb.set_sensitive(true);
-        _opacity_adjustment.set_value(SP_SCALE24_TO_FLOAT(query->opacity.value));
+        _opacity_adjustment.set_value(SP_SCALE24_TO_FLOAT(query->opacity.value) * 100);
         _opacity_blocked = false;
         break;
     }
@@ -995,14 +1041,14 @@ SelectedStyle::update()
         break;
     }
 
-    g_free (query);
+    sp_style_unref(query);
 }
 
 void SelectedStyle::opacity_0(void) {_opacity_sb.set_value(0);}
-void SelectedStyle::opacity_025(void) {_opacity_sb.set_value(0.25);}
-void SelectedStyle::opacity_05(void) {_opacity_sb.set_value(0.5);}
-void SelectedStyle::opacity_075(void) {_opacity_sb.set_value(0.75);}
-void SelectedStyle::opacity_1(void) {_opacity_sb.set_value(1.0);}
+void SelectedStyle::opacity_025(void) {_opacity_sb.set_value(25);}
+void SelectedStyle::opacity_05(void) {_opacity_sb.set_value(50);}
+void SelectedStyle::opacity_075(void) {_opacity_sb.set_value(75);}
+void SelectedStyle::opacity_1(void) {_opacity_sb.set_value(100);}
 
 void SelectedStyle::on_opacity_menu (Gtk::Menu *menu) {
 
@@ -1019,25 +1065,25 @@ void SelectedStyle::on_opacity_menu (Gtk::Menu *menu) {
     }
     {
         Gtk::MenuItem *item = new Gtk::MenuItem;
-        item->add(*(new Gtk::Label("0.25", 0, 0)));
+        item->add(*(new Gtk::Label("25%", 0, 0)));
         item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_025 ));
         menu->add(*item);
     }
     {
         Gtk::MenuItem *item = new Gtk::MenuItem;
-        item->add(*(new Gtk::Label("0.5", 0, 0)));
+        item->add(*(new Gtk::Label("50%", 0, 0)));
         item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_05 ));
         menu->add(*item);
     }
     {
         Gtk::MenuItem *item = new Gtk::MenuItem;
-        item->add(*(new Gtk::Label("0.75", 0, 0)));
+        item->add(*(new Gtk::Label("75%", 0, 0)));
         item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_075 ));
         menu->add(*item);
     }
     {
         Gtk::MenuItem *item = new Gtk::MenuItem;
-        item->add(*(new Gtk::Label(_("1.0 (opaque)"), 0, 0)));
+        item->add(*(new Gtk::Label(_("100% (opaque)"), 0, 0)));
         item->signal_activate().connect(sigc::mem_fun(*this, &SelectedStyle::opacity_1 ));
         menu->add(*item);
     }
@@ -1051,11 +1097,22 @@ void SelectedStyle::on_opacity_changed () {
     _opacity_blocked = true;
     SPCSSAttr *css = sp_repr_css_attr_new ();
     Inkscape::CSSOStringStream os;
-    os << CLAMP (_opacity_adjustment.get_value(), 0.0, 1.0);
+    os << CLAMP ((_opacity_adjustment.get_value() / 100), 0.0, 1.0);
     sp_repr_css_set_property (css, "opacity", os.str().c_str());
+    // FIXME: workaround for GTK breakage: display interruptibility sometimes results in GTK
+    // sending multiple value-changed events. As if when Inkscape interrupts redraw for main loop
+    // iterations, GTK discovers that this callback hasn't finished yet, and for some weird reason
+    // decides to add yet another value-changed event to the queue. Totally braindead if you ask
+    // me. As a result, scrolling the spinbutton once results in runaway change until it hits 1.0
+    // or 0.0. (And no, this is not a race with ::update, I checked that.)
+    // Sigh. So we disable interruptibility while we're setting the new value.
+    sp_canvas_force_full_redraw_after_interruptions(sp_desktop_canvas(_desktop), 0);
     sp_desktop_set_style (_desktop, css);
     sp_repr_css_attr_unref (css);
-    sp_document_maybe_done (sp_desktop_document (_desktop), "fillstroke:opacity");
+    sp_document_maybe_done (sp_desktop_document (_desktop), "fillstroke:opacity", SP_VERB_DIALOG_FILL_STROKE,
+                      _("Change opacity"));
+    // resume interruptibility
+    sp_canvas_end_forced_full_redraws(sp_desktop_canvas(_desktop));
     spinbutton_defocus(GTK_OBJECT(_opacity_sb.gobj()));
     _opacity_blocked = false;
 }