Code

RegisteredEnum is now subclassed from RegisteredWidget<enum> instead of old RegisteredWdg
[inkscape.git] / src / ui / widget / selected-style.cpp
index 22cd30828fa8d3b419352a8fd04ca419434d277c..20838ee22ba8d0d12d2ba9ece042db14363b35cc 100644 (file)
@@ -29,6 +29,7 @@
 #include "sp-pattern.h"
 #include "ui/dialog/dialog-manager.h"
 #include "ui/dialog/fill-and-stroke.h"
+#include "ui/dialog/panel-dialog.h"
 #include "xml/repr.h"
 #include "document.h"
 #include "widgets/widget-sizes.h"
 #include "svg/svg-color.h"
 #include "svg/css-ostringstream.h"
 #include "helper/units.h"
+#include "event-context.h"
+#include "message-context.h"
 #include "verbs.h"
+#include "color.h"
 #include <display/sp-canvas.h>
+#include "pixmaps/cursor-adj-h.xpm"
+#include "pixmaps/cursor-adj-s.xpm"
+#include "pixmaps/cursor-adj-l.xpm"
+#include "sp-cursor.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 *const _sw_presets_str[] = {"32", "16", "10", "8", "6", "4", "3", "2", "1.5", "1", "0.75", "0.5", "0.25", "0.1"};
 
-static void 
+static void
 ss_selection_changed (Inkscape::Selection *, gpointer data)
 {
     Inkscape::UI::Widget::SelectedStyle *ss = (Inkscape::UI::Widget::SelectedStyle *) data;
@@ -52,13 +60,13 @@ ss_selection_changed (Inkscape::Selection *, gpointer data)
 }
 
 static void
-ss_selection_modified (Inkscape::Selection *selection, guint flags, gpointer data)
+ss_selection_modified( Inkscape::Selection *selection, guint /*flags*/, gpointer data )
 {
     ss_selection_changed (selection, data);
 }
 
 static void
-ss_subselection_changed (gpointer dragger, gpointer data)
+ss_subselection_changed( gpointer /*dragger*/, gpointer data )
 {
     ss_selection_changed (NULL, data);
 }
@@ -85,16 +93,19 @@ static GtkTargetEntry ui_drop_target_entries [] = {
 #define ENTRIES_SIZE(n) sizeof(n)/sizeof(n[0])
 static guint nui_drop_target_entries = ENTRIES_SIZE(ui_drop_target_entries);
 
+/* convenience function */
+static Dialog::FillAndStroke *get_fill_and_stroke_panel(SPDesktop *desktop);
 
-SelectedStyle::SelectedStyle(bool layout)
+SelectedStyle::SelectedStyle(bool /*layout*/)
     : _desktop (NULL),
 
       _table(2, 6),
       _fill_label (_("Fill:")),
       _stroke_label (_("Stroke:")),
       _opacity_label (_("O:")),
-      _fill_place (),
-      _stroke_place (),
+
+      _fill_place (SS_FILL),
+      _stroke_place (SS_STROKE),
 
       _fill_flag_place (),
       _stroke_flag_place (),
@@ -119,7 +130,7 @@ SelectedStyle::SelectedStyle(bool layout)
 {
     _drop[0] = _drop[1] = 0;
     _dropEnabled[0] = _dropEnabled[1] = false;
-    
+
     _fill_label.set_alignment(0.0, 0.5);
     _fill_label.set_padding(0, 0);
     _stroke_label.set_alignment(0.0, 0.5);
@@ -193,52 +204,52 @@ SelectedStyle::SelectedStyle(bool layout)
         __multiple[i] = (i == SS_FILL)? (_("Multiple selected objects have the same fill")) : (_("Multiple selected objects have the same stroke"));
 
         _popup_edit[i].add(*(new Gtk::Label((i == SS_FILL)? _("Edit fill...") : _("Edit stroke..."), 0.0, 0.5)));
-        _popup_edit[i].signal_activate().connect(sigc::mem_fun(*this, 
+        _popup_edit[i].signal_activate().connect(sigc::mem_fun(*this,
                                (i == SS_FILL)? &SelectedStyle::on_fill_edit : &SelectedStyle::on_stroke_edit ));
 
         _popup_lastused[i].add(*(new Gtk::Label(_("Last set color"), 0.0, 0.5)));
-        _popup_lastused[i].signal_activate().connect(sigc::mem_fun(*this, 
+        _popup_lastused[i].signal_activate().connect(sigc::mem_fun(*this,
                                (i == SS_FILL)? &SelectedStyle::on_fill_lastused : &SelectedStyle::on_stroke_lastused ));
 
         _popup_lastselected[i].add(*(new Gtk::Label(_("Last selected color"), 0.0, 0.5)));
-        _popup_lastselected[i].signal_activate().connect(sigc::mem_fun(*this, 
+        _popup_lastselected[i].signal_activate().connect(sigc::mem_fun(*this,
                                (i == SS_FILL)? &SelectedStyle::on_fill_lastselected : &SelectedStyle::on_stroke_lastselected ));
 
         _popup_invert[i].add(*(new Gtk::Label(_("Invert"), 0.0, 0.5)));
-        _popup_invert[i].signal_activate().connect(sigc::mem_fun(*this, 
+        _popup_invert[i].signal_activate().connect(sigc::mem_fun(*this,
                                (i == SS_FILL)? &SelectedStyle::on_fill_invert : &SelectedStyle::on_stroke_invert ));
 
         _popup_white[i].add(*(new Gtk::Label(_("White"), 0.0, 0.5)));
-        _popup_white[i].signal_activate().connect(sigc::mem_fun(*this, 
+        _popup_white[i].signal_activate().connect(sigc::mem_fun(*this,
                                (i == SS_FILL)? &SelectedStyle::on_fill_white : &SelectedStyle::on_stroke_white ));
 
         _popup_black[i].add(*(new Gtk::Label(_("Black"), 0.0, 0.5)));
-        _popup_black[i].signal_activate().connect(sigc::mem_fun(*this, 
+        _popup_black[i].signal_activate().connect(sigc::mem_fun(*this,
                                (i == SS_FILL)? &SelectedStyle::on_fill_black : &SelectedStyle::on_stroke_black ));
 
         _popup_copy[i].add(*(new Gtk::Label(_("Copy color"), 0.0, 0.5)));
-        _popup_copy[i].signal_activate().connect(sigc::mem_fun(*this, 
+        _popup_copy[i].signal_activate().connect(sigc::mem_fun(*this,
                                (i == SS_FILL)? &SelectedStyle::on_fill_copy : &SelectedStyle::on_stroke_copy ));
 
         _popup_paste[i].add(*(new Gtk::Label(_("Paste color"), 0.0, 0.5)));
-        _popup_paste[i].signal_activate().connect(sigc::mem_fun(*this, 
+        _popup_paste[i].signal_activate().connect(sigc::mem_fun(*this,
                                (i == SS_FILL)? &SelectedStyle::on_fill_paste : &SelectedStyle::on_stroke_paste ));
 
         _popup_swap[i].add(*(new Gtk::Label(_("Swap fill and stroke"), 0.0, 0.5)));
-        _popup_swap[i].signal_activate().connect(sigc::mem_fun(*this, 
+        _popup_swap[i].signal_activate().connect(sigc::mem_fun(*this,
                                &SelectedStyle::on_fillstroke_swap));
 
         _popup_opaque[i].add(*(new Gtk::Label((i == SS_FILL)? _("Make fill opaque") : _("Make stroke opaque"), 0.0, 0.5)));
-        _popup_opaque[i].signal_activate().connect(sigc::mem_fun(*this, 
+        _popup_opaque[i].signal_activate().connect(sigc::mem_fun(*this,
                                (i == SS_FILL)? &SelectedStyle::on_fill_opaque : &SelectedStyle::on_stroke_opaque ));
 
         //TRANSLATORS COMMENT: unset is a verb here
         _popup_unset[i].add(*(new Gtk::Label((i == SS_FILL)? _("Unset fill") : _("Unset stroke"), 0.0, 0.5)));
-        _popup_unset[i].signal_activate().connect(sigc::mem_fun(*this, 
+        _popup_unset[i].signal_activate().connect(sigc::mem_fun(*this,
                                (i == SS_FILL)? &SelectedStyle::on_fill_unset : &SelectedStyle::on_stroke_unset ));
 
         _popup_remove[i].add(*(new Gtk::Label((i == SS_FILL)? _("Remove fill") : _("Remove stroke"), 0.0, 0.5)));
-        _popup_remove[i].signal_activate().connect(sigc::mem_fun(*this, 
+        _popup_remove[i].signal_activate().connect(sigc::mem_fun(*this,
                                (i == SS_FILL)? &SelectedStyle::on_fill_remove : &SelectedStyle::on_stroke_remove ));
 
         _popup[i].attach(_popup_edit[i], 0,1, 0,1);
@@ -255,7 +266,7 @@ SelectedStyle::SelectedStyle(bool layout)
         _popup_copy[i].set_sensitive(false);
         _popup[i].attach(_popup_paste[i], 0,1, 11,12);
         _popup[i].attach(_popup_swap[i], 0,1, 12,13);
-          _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 13,14); 
+          _popup[i].attach(*(new Gtk::SeparatorMenuItem()), 0,1, 13,14);
         _popup[i].attach(_popup_opaque[i], 0,1, 14,15);
         _popup[i].attach(_popup_unset[i], 0,1, 15,16);
         _popup[i].attach(_popup_remove[i], 0,1, 16,17);
@@ -297,8 +308,8 @@ SelectedStyle::SelectedStyle(bool layout)
         _popup_sw.show_all();
     }
 
-    _fill_place.signal_button_press_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_fill_click));
-    _stroke_place.signal_button_press_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_stroke_click));
+    _fill_place.signal_button_release_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_fill_click));
+    _stroke_place.signal_button_release_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_stroke_click));
     _opacity_place.signal_button_press_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_opacity_click));
     _stroke_width_place.signal_button_press_event().connect(sigc::mem_fun(*this, &SelectedStyle::on_sw_click));
 
@@ -364,6 +375,9 @@ SelectedStyle::SelectedStyle(bool layout)
                      "drag_data_received",
                      G_CALLBACK(dragDataReceived),
                      _drop[SS_FILL]);
+
+    _fill_place.parent = this;
+    _stroke_place.parent = this;
 }
 
 SelectedStyle::~SelectedStyle()
@@ -377,7 +391,7 @@ 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 
+        // 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]));
     }
@@ -413,12 +427,12 @@ SelectedStyle::setDesktop(SPDesktop *desktop)
     //_sw_unit = (SPUnit *) sp_desktop_namedview(desktop)->doc_units;
 }
 
-void SelectedStyle::dragDataReceived( GtkWidget *widget,
-                                      GdkDragContext *drag_context,
-                                      gint x, gint y,
+void SelectedStyle::dragDataReceived( GtkWidget */*widget*/,
+                                      GdkDragContext */*drag_context*/,
+                                      gint /*x*/, gint /*y*/,
                                       GtkSelectionData *data,
-                                      guint info,
-                                      guint event_time,
+                                      guint /*info*/,
+                                      guint /*event_time*/,
                                       gpointer user_data )
 {
     DropTracker* tracker = (DropTracker*)user_data;
@@ -443,7 +457,7 @@ 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_VERB_NONE, 
+                sp_document_done( sp_desktop_document(tracker->parent->_desktop) , SP_VERB_NONE,
                                   _("Drop color"));
             }
         }
@@ -454,7 +468,7 @@ void SelectedStyle::dragDataReceived( GtkWidget *widget,
 void SelectedStyle::on_fill_remove() {
     SPCSSAttr *css = sp_repr_css_attr_new ();
     sp_repr_css_set_property (css, "fill", "none");
-    sp_desktop_set_style (_desktop, css, true, true); 
+    sp_desktop_set_style (_desktop, css, true, true);
     sp_repr_css_attr_unref (css);
     sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
                       _("Remove fill"));
@@ -463,7 +477,7 @@ void SelectedStyle::on_fill_remove() {
 void SelectedStyle::on_stroke_remove() {
     SPCSSAttr *css = sp_repr_css_attr_new ();
     sp_repr_css_set_property (css, "stroke", "none");
-    sp_desktop_set_style (_desktop, css, true, true); 
+    sp_desktop_set_style (_desktop, css, true, true);
     sp_repr_css_attr_unref (css);
     sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
                       _("Remove stroke"));
@@ -472,7 +486,7 @@ void SelectedStyle::on_stroke_remove() {
 void SelectedStyle::on_fill_unset() {
     SPCSSAttr *css = sp_repr_css_attr_new ();
     sp_repr_css_unset_property (css, "fill");
-    sp_desktop_set_style (_desktop, css, true, true); 
+    sp_desktop_set_style (_desktop, css, true, true);
     sp_repr_css_attr_unref (css);
     sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
                       _("Unset fill"));
@@ -520,7 +534,7 @@ 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_VERB_DIALOG_FILL_STROKE, 
+    sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
                       _("Apply last set color to fill"));
 }
 
@@ -532,7 +546,7 @@ 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_VERB_DIALOG_FILL_STROKE, 
+    sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
                       _("Apply last set color to stroke"));
 }
 
@@ -554,7 +568,7 @@ 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_VERB_DIALOG_FILL_STROKE, 
+    sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
                       _("Apply last selected color to stroke"));
 }
 
@@ -596,7 +610,7 @@ void SelectedStyle::on_stroke_invert() {
     sp_repr_css_attr_unref (css);
     sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
                       _("Invert stroke"));
-} 
+}
 
 void SelectedStyle::on_fill_white() {
     SPCSSAttr *css = sp_repr_css_attr_new ();
@@ -618,7 +632,7 @@ 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_VERB_DIALOG_FILL_STROKE, 
+    sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
                       _("White stroke"));
 }
 
@@ -630,7 +644,7 @@ 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_VERB_DIALOG_FILL_STROKE, 
+    sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
                       _("Black fill"));
 }
 
@@ -642,7 +656,7 @@ 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_VERB_DIALOG_FILL_STROKE, 
+    sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
                       _("Black stroke"));
 }
 
@@ -685,7 +699,7 @@ 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_VERB_DIALOG_FILL_STROKE, 
+        sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
                       _("Paste fill"));
     }
 }
@@ -757,30 +771,27 @@ 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_VERB_DIALOG_FILL_STROKE, 
+    sp_document_done (sp_desktop_document(_desktop), SP_VERB_DIALOG_FILL_STROKE,
                       _("Swap fill and stroke"));
 }
 
 void SelectedStyle::on_fill_edit() {
-    if (Dialog::FillAndStroke *dialog = dynamic_cast<Dialog::FillAndStroke *>(
-            _desktop->_dlg_mgr->getDialog("FillAndStroke")))
-        dialog->showPageFill();
+    if (Dialog::FillAndStroke *fs = get_fill_and_stroke_panel(_desktop))
+        fs->showPageFill();
 }
 
 void SelectedStyle::on_stroke_edit() {
-    if (Dialog::FillAndStroke *dialog = dynamic_cast<Dialog::FillAndStroke *>(
-            _desktop->_dlg_mgr->getDialog("FillAndStroke")))
-        dialog->showPageStrokePaint();
+    if (Dialog::FillAndStroke *fs = get_fill_and_stroke_panel(_desktop))
+        fs->showPageStrokePaint();
 }
 
-bool 
+bool
 SelectedStyle::on_fill_click(GdkEventButton *event)
 {
     if (event->button == 1) { // click, open fill&stroke
 
-        if (Dialog::FillAndStroke *dialog = dynamic_cast<Dialog::FillAndStroke *>(
-                _desktop->_dlg_mgr->getDialog("FillAndStroke")))
-            dialog->showPageFill();
+        if (Dialog::FillAndStroke *fs = get_fill_and_stroke_panel(_desktop))
+            fs->showPageFill();
 
     } else if (event->button == 3) { // right-click, popup menu
         _popup[SS_FILL].popup(event->button, event->time);
@@ -794,13 +805,12 @@ SelectedStyle::on_fill_click(GdkEventButton *event)
     return true;
 }
 
-bool 
+bool
 SelectedStyle::on_stroke_click(GdkEventButton *event)
 {
     if (event->button == 1) { // click, open fill&stroke
-        if (Dialog::FillAndStroke *dialog = dynamic_cast<Dialog::FillAndStroke *>(
-                _desktop->_dlg_mgr->getDialog("FillAndStroke")))
-            dialog->showPageStrokePaint();
+        if (Dialog::FillAndStroke *fs = get_fill_and_stroke_panel(_desktop))
+            fs->showPageStrokePaint();
     } else if (event->button == 3) { // right-click, popup menu
         _popup[SS_STROKE].popup(event->button, event->time);
     } else if (event->button == 2) { // middle click, toggle none/lastcolor
@@ -813,13 +823,12 @@ SelectedStyle::on_stroke_click(GdkEventButton *event)
     return true;
 }
 
-bool 
+bool
 SelectedStyle::on_sw_click(GdkEventButton *event)
 {
     if (event->button == 1) { // click, open fill&stroke
-        if (Dialog::FillAndStroke *dialog = dynamic_cast<Dialog::FillAndStroke *>(
-                _desktop->_dlg_mgr->getDialog("FillAndStroke")))
-            dialog->showPageStrokeStyle();
+        if (Dialog::FillAndStroke *fs = get_fill_and_stroke_panel(_desktop))
+            fs->showPageStrokeStyle();
     } else if (event->button == 3) { // right-click, popup menu
         _popup_sw.popup(event->button, event->time);
     } else if (event->button == 2) { // middle click, toggle none/lastwidth?
@@ -828,7 +837,7 @@ SelectedStyle::on_sw_click(GdkEventButton *event)
     return true;
 }
 
-bool 
+bool
 SelectedStyle::on_opacity_click(GdkEventButton *event)
 {
     if (event->button == 2) { // middle click
@@ -901,7 +910,7 @@ SelectedStyle::update()
         _popup_copy[i].set_sensitive(false);
 
         // query style from desktop. This returns a result flag and fills query with the style of subselection, if any, or selection
-        int result = sp_desktop_query_style (_desktop, query, 
+        int result = sp_desktop_query_style (_desktop, query,
                                              (i == SS_FILL)? QUERY_STYLE_PROPERTY_FILL : QUERY_STYLE_PROPERTY_STROKE);
         switch (result) {
         case QUERY_STYLE_NOTHING:
@@ -915,7 +924,7 @@ SelectedStyle::update()
             break;
         case QUERY_STYLE_SINGLE:
         case QUERY_STYLE_MULTIPLE_AVERAGED:
-        case QUERY_STYLE_MULTIPLE_SAME: 
+        case QUERY_STYLE_MULTIPLE_SAME:
             if ( !_dropEnabled[i] ) {
                 gtk_drag_dest_set( GTK_WIDGET( (i==SS_FILL) ? _fill_place.gobj():_stroke_place.gobj()),
                                    GTK_DEST_DEFAULT_ALL,
@@ -968,7 +977,7 @@ SelectedStyle::update()
                 place->add(*_color_preview[i]);
                 gchar c_string[64];
                 g_snprintf (c_string, 64, "%06x/%.3g", color >> 8, SP_RGBA32_A_F(color));
-                _tooltips.set_tip(*place, __color[i] + ": " + c_string);
+                _tooltips.set_tip(*place, __color[i] + ": " + c_string + _(", drag to adjust"));
                 _mode[i] = SS_COLOR;
                 _popup_copy[i].set_sensitive(true);
 
@@ -1014,8 +1023,8 @@ SelectedStyle::update()
     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_sb, _("Master opacity, %"));
+        _tooltips.set_tip(_opacity_place, _("Opacity, %"));
+        _tooltips.set_tip(_opacity_sb, _("Opacity, %"));
         if (_opacity_blocked) break;
         _opacity_blocked = true;
         _opacity_sb.set_sensitive(true);
@@ -1032,7 +1041,7 @@ SelectedStyle::update()
         break;
     case QUERY_STYLE_SINGLE:
     case QUERY_STYLE_MULTIPLE_AVERAGED:
-    case QUERY_STYLE_MULTIPLE_SAME: 
+    case QUERY_STYLE_MULTIPLE_SAME:
     {
         double w;
         if (_sw_unit) {
@@ -1046,9 +1055,9 @@ SelectedStyle::update()
             g_free (str);
         }
         {
-            gchar *str = g_strdup_printf(_("Stroke width: %.5g%s%s"), 
-                                         w, 
-                                         _sw_unit? sp_unit_get_abbreviation(_sw_unit) : "px", 
+            gchar *str = g_strdup_printf(_("Stroke width: %.5g%s%s"),
+                                         w,
+                                         _sw_unit? sp_unit_get_abbreviation(_sw_unit) : "px",
                                          (result_sw == QUERY_STYLE_MULTIPLE_AVERAGED)?
                                          _(" (averaged)") : "");
             _tooltips.set_tip(_stroke_width_place, str);
@@ -1136,11 +1145,200 @@ void SelectedStyle::on_opacity_changed () {
     _opacity_blocked = false;
 }
 
+RotateableSwatch::RotateableSwatch(guint mode) {
+    fillstroke = mode;
+    startcolor_set = false;
+    undokey = "ssrot1";
+    cr = NULL;
+    cr_set = false;
+}
+
+RotateableSwatch::~RotateableSwatch() {
+}
+
+double
+RotateableSwatch::color_adjust(float *hsl, double by, guint32 cc, guint modifier)
+{
+    sp_color_rgb_to_hsl_floatv (hsl, SP_RGBA32_R_F(cc), SP_RGBA32_G_F(cc), SP_RGBA32_B_F(cc));
+
+    double diff = 0;
+    if (modifier == 2) { // saturation
+        double old = hsl[1];
+        if (by > 0) {
+            hsl[1] += by * (1 - hsl[1]);
+        } else {
+            hsl[1] += by * (hsl[1]);
+        }
+        diff = hsl[1] - old;
+    } else if (modifier == 1) { // lightness
+        double old = hsl[2];
+        if (by > 0) {
+            hsl[2] += by * (1 - hsl[2]);
+        } else {
+            hsl[2] += by * (hsl[2]);
+        }
+        diff = hsl[2] - old;
+    } else { // hue
+        double old = hsl[0];
+        hsl[0] += by/2;
+        while (hsl[0] < 0)
+            hsl[0] += 1;
+        while (hsl[0] > 1)
+            hsl[0] -= 1;
+        diff = hsl[0] - old;
+    }
+
+    float rgb[3];
+    sp_color_hsl_to_rgb_floatv (rgb, hsl[0], hsl[1], hsl[2]);
+
+    gchar c[64];
+    sp_svg_write_color (c, sizeof(c),
+        SP_RGBA32_U_COMPOSE(
+                (SP_COLOR_F_TO_U(rgb[0])),
+                (SP_COLOR_F_TO_U(rgb[1])),
+                (SP_COLOR_F_TO_U(rgb[2])),
+                0xff
+        )
+    );
+
+    SPCSSAttr *css = sp_repr_css_attr_new ();
+    if (fillstroke == SS_FILL)
+        sp_repr_css_set_property (css, "fill", c);
+    else
+        sp_repr_css_set_property (css, "stroke", c);
+    sp_desktop_set_style (parent->getDesktop(), css);
+    sp_repr_css_attr_unref (css);
+    return diff;
+}
+
+void
+RotateableSwatch::do_motion(double by, guint modifier) {
+    if (parent->_mode[fillstroke] != SS_COLOR)
+        return;
+
+    if (!cr_set && modifier != 3) {
+        GtkWidget *w = GTK_WIDGET(gobj());
+
+        GdkBitmap *bitmap = NULL;
+        GdkBitmap *mask = NULL;
+        if (modifier == 2) { // saturation
+            sp_cursor_bitmap_and_mask_from_xpm(&bitmap, &mask, cursor_adj_s_xpm);
+        } else if (modifier == 1) { // lightness
+            sp_cursor_bitmap_and_mask_from_xpm(&bitmap, &mask, cursor_adj_l_xpm);
+        } else { // hue
+            sp_cursor_bitmap_and_mask_from_xpm(&bitmap, &mask, cursor_adj_h_xpm);
+        }
+        if ((bitmap != NULL) && (mask != NULL)) {
+            cr = gdk_cursor_new_from_pixmap(bitmap, mask,
+                                            &w->style->black,
+                                            &w->style->white,
+                                            16, 16);
+            g_object_unref (bitmap);
+            g_object_unref (mask);
+            gdk_window_set_cursor(w->window, cr);
+            cr_set = true;
+        }
+    }
+
+    guint32 cc;
+    if (!startcolor_set) {
+        cc = startcolor = parent->_thisselected[fillstroke];
+        startcolor_set = true;
+    } else {
+        cc = startcolor;
+    }
+
+    float hsl[3];
+    double diff = 0;
+    if (modifier != 3) {
+        diff = color_adjust(hsl, by, cc, modifier);
+    }
+
+    if (modifier == 3) { // do nothing
+
+    } else if (modifier == 2) { // saturation
+        sp_document_maybe_done (sp_desktop_document(parent->getDesktop()), undokey,
+                                SP_VERB_DIALOG_FILL_STROKE, (_("Adjust saturation")));
+        double ch = hsl[1];
+        parent->getDesktop()->event_context->_message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("Adjusting <b>saturation</b>: was %.3g, now <b>%.3g</b> (diff %.3g); with <b>Ctrl</b> to adjust lightness, without modifiers to adjust hue"), ch - diff, ch, diff);
+
+    } else if (modifier == 1) { // lightness
+        sp_document_maybe_done (sp_desktop_document(parent->getDesktop()), undokey,
+                                SP_VERB_DIALOG_FILL_STROKE, (_("Adjust lightness")));
+        double ch = hsl[2];
+        parent->getDesktop()->event_context->_message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("Adjusting <b>lightness</b>: was %.3g, now <b>%.3g</b> (diff %.3g); with <b>Shift</b> to adjust saturation, without modifiers to adjust hue"), ch - diff, ch, diff);
+
+    } else { // hue
+        sp_document_maybe_done (sp_desktop_document(parent->getDesktop()), undokey,
+                                SP_VERB_DIALOG_FILL_STROKE, (_("Adjust hue")));
+        double ch = hsl[0];
+        parent->getDesktop()->event_context->_message_context->setF(Inkscape::IMMEDIATE_MESSAGE, _("Adjusting <b>hue</b>: was %.3g, now <b>%.3g</b> (diff %.3g); with <b>Shift</b> to adjust saturation, with <b>Ctrl</b> to adjust lightness"), ch - diff, ch, diff);
+    }
+}
+
+void
+RotateableSwatch::do_release(double by, guint modifier) {
+    if (parent->_mode[fillstroke] != SS_COLOR)
+        return;
+
+    float hsl[3];
+    if (modifier != 3) {
+        color_adjust(hsl, by, startcolor, modifier);
+    }
+
+    if (cr_set) {
+        GtkWidget *w = GTK_WIDGET(gobj());
+        gdk_window_set_cursor(w->window, NULL);
+        if (cr) {
+           gdk_cursor_unref (cr);
+           cr = NULL;
+        }
+        cr_set = false;
+    }
+
+    if (modifier == 3) { // nothing
+    } else if (modifier == 2) { // saturation
+        sp_document_maybe_done (sp_desktop_document(parent->getDesktop()), undokey,
+                                SP_VERB_DIALOG_FILL_STROKE, ("Adjust saturation"));
+
+    } else if (modifier == 1) { // lightness
+        sp_document_maybe_done (sp_desktop_document(parent->getDesktop()), undokey,
+                                SP_VERB_DIALOG_FILL_STROKE, ("Adjust lightness"));
+
+    } else { // hue
+        sp_document_maybe_done (sp_desktop_document(parent->getDesktop()), undokey,
+                                SP_VERB_DIALOG_FILL_STROKE, ("Adjust hue"));
+    }
+
+    if (!strcmp(undokey, "ssrot1")) {
+        undokey = "ssrot2";
+    } else {
+        undokey = "ssrot1";
+    }
+
+    parent->getDesktop()->event_context->_message_context->clear();
+    startcolor_set = false;
+}
+
+Dialog::FillAndStroke *get_fill_and_stroke_panel(SPDesktop *desktop)
+{
+    if (Dialog::PanelDialogBase *panel_dialog = 
+        dynamic_cast<Dialog::PanelDialogBase *>(desktop->_dlg_mgr->getDialog("FillAndStroke"))) {
+        try {
+            Dialog::FillAndStroke &fill_and_stroke = 
+                dynamic_cast<Dialog::FillAndStroke &>(panel_dialog->getPanel());
+            return &fill_and_stroke;
+        } catch (std::exception e) { }
+    }        
+
+    return 0;
+}
+
 } // namespace Widget
 } // namespace UI
 } // namespace Inkscape
 
-/* 
+/*
   Local Variables:
   mode:c++
   c-file-style:"stroustrup"