Code

rename, rearrange stroke shapes; add elliptic
[inkscape.git] / src / widgets / toolbox.cpp
index 647d95d800f837004abab5fa6350137ab0ecc53e..3eb3b9973fcde9058445a979565a625ba007f8a8 100644 (file)
@@ -51,6 +51,7 @@
 #include "desktop-handles.h"
 #include "xml/repr.h"
 #include "xml/node-event-vector.h"
+#include "xml/attribute-record.h"
 #include <glibmm/i18n.h>
 #include "helper/unit-menu.h"
 #include "helper/units.h"
@@ -79,6 +80,7 @@
 #include "sp-clippath.h"
 #include "sp-mask.h"
 #include "style.h"
+#include "tools-switch.h"
 #include "selection.h"
 #include "selection-chemistry.h"
 #include "document-private.h"
@@ -220,6 +222,7 @@ static struct {
     { NULL, NULL, NULL, NULL, NULL, SP_VERB_INVALID, NULL, NULL }
 };
 
+#define TOOLBAR_SLIDER_HINT "full"
 
 static gchar const * ui_descr =
         "<ui>"
@@ -364,23 +367,24 @@ static gchar const * ui_descr =
         "  </toolbar>"
 
         "  <toolbar name='PenToolbar'>"
-        "    <toolitem action='FreehandModeActionPenTemp' />"
         "    <toolitem action='FreehandModeActionPen' />"
+        "    <separator />"
+        "    <toolitem action='SetPenShapeAction'/>"
         "  </toolbar>"
 
         "  <toolbar name='PencilToolbar'>"
-        "    <toolitem action='FreehandModeActionPencilTemp' />"
         "    <toolitem action='FreehandModeActionPencil' />"
         "    <separator />"
-        "    <toolitem action='PencilToleranceAction' />"    
+        "    <toolitem action='PencilToleranceAction' />"
         "    <separator />"
         "    <toolitem action='PencilResetAction' />"
+        "    <separator />"
+        "    <toolitem action='SetPencilShapeAction'/>"
         "  </toolbar>"
 
         "  <toolbar name='CalligraphyToolbar'>"
         "    <separator />"
         "    <toolitem action='SetProfileAction'/>"
-        "    <toolitem action='SaveDeleteProfileAction'/>"
         "    <separator />"
         "    <toolitem action='CalligraphyWidthAction' />"
         "    <toolitem action='PressureAction' />"
@@ -449,7 +453,7 @@ static gchar const * ui_descr =
         "</ui>"
 ;
 
-static GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop );
+static Glib::RefPtr<Gtk::ActionGroup> create_or_fetch_actions( SPDesktop* desktop );
 
 static void toolbox_set_desktop (GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
 
@@ -462,6 +466,138 @@ static void update_aux_toolbox (SPDesktop *desktop, SPEventContext *eventcontext
 static void setup_commands_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
 static void update_commands_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
 
+
+GtkWidget * sp_toolbox_button_new_from_verb_with_doubleclick( GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
+                                                              Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
+                                                              Inkscape::UI::View::View *view, GtkTooltips *tt);
+
+class VerbAction : public Gtk::Action {
+public:
+    static Glib::RefPtr<VerbAction> create(Inkscape::Verb* verb, Inkscape::Verb* verb2, Inkscape::UI::View::View *view, GtkTooltips *tooltips);
+
+    virtual ~VerbAction();
+    virtual void set_active(bool active = true);
+
+protected:
+    virtual Gtk::Widget* create_menu_item_vfunc();
+    virtual Gtk::Widget* create_tool_item_vfunc();
+
+    virtual void connect_proxy_vfunc(Gtk::Widget* proxy);
+    virtual void disconnect_proxy_vfunc(Gtk::Widget* proxy);
+
+    virtual void on_activate();
+
+private:
+    Inkscape::Verb* verb;
+    Inkscape::Verb* verb2;
+    Inkscape::UI::View::View *view;
+    GtkTooltips *tooltips;
+    bool active;
+
+    VerbAction(Inkscape::Verb* verb, Inkscape::Verb* verb2, Inkscape::UI::View::View *view, GtkTooltips *tooltips);
+};
+
+
+Glib::RefPtr<VerbAction> VerbAction::create(Inkscape::Verb* verb, Inkscape::Verb* verb2, Inkscape::UI::View::View *view, GtkTooltips *tooltips)
+{
+    Glib::RefPtr<VerbAction> result;
+    SPAction *action = verb->get_action(view);
+    if ( action ) {
+        //SPAction* action2 = verb2 ? verb2->get_action(view) : 0;
+        result = Glib::RefPtr<VerbAction>(new VerbAction(verb, verb2, view, tooltips));
+    }
+
+    return result;
+}
+
+VerbAction::VerbAction(Inkscape::Verb* verb, Inkscape::Verb* verb2, Inkscape::UI::View::View *view, GtkTooltips *tooltips) :
+    Gtk::Action(Glib::ustring(verb->get_id()), Gtk::StockID(verb->get_image()), Glib::ustring(_(verb->get_name())), Glib::ustring(_(verb->get_tip()))),
+    verb(verb),
+    verb2(verb2),
+    view(view),
+    tooltips(tooltips),
+    active(false)
+{
+}
+
+VerbAction::~VerbAction()
+{
+}
+
+Gtk::Widget* VerbAction::create_menu_item_vfunc()
+{
+// First call in to get the icon rendered if present in SVG
+    Gtk::Widget *widget = sp_icon_get_icon( property_stock_id().get_value().get_string(), Inkscape::ICON_SIZE_MENU );
+    delete widget;
+    widget = 0;
+
+    Gtk::Widget* widg = Gtk::Action::create_menu_item_vfunc();
+//     g_message("create_menu_item_vfunc() = %p  for '%s'", widg, verb->get_id());
+    return widg;
+}
+
+Gtk::Widget* VerbAction::create_tool_item_vfunc()
+{
+//     Gtk::Widget* widg = Gtk::Action::create_tool_item_vfunc();
+    Inkscape::IconSize toolboxSize = prefToSize("toolbox.tools", "small");
+    GtkWidget* toolbox = 0;
+    GtkWidget *button = sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
+                                                                          SP_BUTTON_TYPE_TOGGLE,
+                                                                          verb,
+                                                                          verb2,
+                                                                          view,
+                                                                          tooltips );
+    if ( active ) {
+        sp_button_toggle_set_down( SP_BUTTON(button), active);
+    }
+    gtk_widget_show_all( button );
+    Gtk::Widget* wrapped = Glib::wrap(button);
+    Gtk::ToolItem* holder = Gtk::manage(new Gtk::ToolItem());
+    holder->add(*wrapped);
+
+//     g_message("create_tool_item_vfunc() = %p  for '%s'", holder, verb->get_id());
+    return holder;
+}
+
+void VerbAction::connect_proxy_vfunc(Gtk::Widget* proxy)
+{
+//     g_message("connect_proxy_vfunc(%p)  for '%s'", proxy, verb->get_id());
+    Gtk::Action::connect_proxy_vfunc(proxy);
+}
+
+void VerbAction::disconnect_proxy_vfunc(Gtk::Widget* proxy)
+{
+//     g_message("disconnect_proxy_vfunc(%p)  for '%s'", proxy, verb->get_id());
+    Gtk::Action::disconnect_proxy_vfunc(proxy);
+}
+
+void VerbAction::set_active(bool active)
+{
+    this->active = active;
+    Glib::SListHandle<Gtk::Widget*> proxies = get_proxies();
+    for ( Glib::SListHandle<Gtk::Widget*>::iterator it = proxies.begin(); it != proxies.end(); ++it ) {
+        Gtk::ToolItem* ti = dynamic_cast<Gtk::ToolItem*>(*it);
+        if (ti) {
+            // *should* have one child that is the SPButton
+            Gtk::Widget* child = ti->get_child();
+            if ( child && SP_IS_BUTTON(child->gobj()) ) {
+                SPButton* button = SP_BUTTON(child->gobj());
+                sp_button_toggle_set_down( button, active );
+            }
+        }
+    }
+}
+
+void VerbAction::on_activate()
+{
+    if ( verb ) {
+        SPAction *action = verb->get_action(view);
+        if ( action ) {
+            sp_action_perform(action, 0);
+        }
+    }
+}
+
 /* Global text entry widgets necessary for update */
 /* GtkWidget *dropper_rgb_entry,
           *dropper_opacity_entry ; */
@@ -509,10 +645,14 @@ sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSiz
         gchar key[256];
         sp_ui_shortcut_string(shortcut, key);
         gchar *tip = g_strdup_printf ("%s (%s)", action->tip, key);
-        gtk_toolbar_append_widget( GTK_TOOLBAR(t), b, tip, 0 );
+        if ( t ) {
+            gtk_toolbar_append_widget( GTK_TOOLBAR(t), b, tip, 0 );
+        }
         g_free(tip);
     } else {
-        gtk_toolbar_append_widget( GTK_TOOLBAR(t), b, action->tip, 0 );
+        if ( t ) {
+            gtk_toolbar_append_widget( GTK_TOOLBAR(t), b, action->tip, 0 );
+        }
     }
 
     return b;
@@ -561,7 +701,7 @@ static GtkAction* create_action_for_verb( Inkscape::Verb* verb, Inkscape::UI::Vi
     return act;
 }
 
-GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop )
+Glib::RefPtr<Gtk::ActionGroup> create_or_fetch_actions( SPDesktop* desktop )
 {
     Inkscape::UI::View::View *view = desktop;
     gint verbsToUse[] = {
@@ -608,27 +748,41 @@ GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop )
 
     Inkscape::IconSize toolboxSize = prefToSize("toolbox", "small");
 
-    static std::map<SPDesktop*, GtkActionGroup*> groups;
-    GtkActionGroup* mainActions = 0;
+    static std::map<SPDesktop*, Glib::RefPtr<Gtk::ActionGroup> > groups;
+    Glib::RefPtr<Gtk::ActionGroup> mainActions;
     if ( groups.find(desktop) != groups.end() ) {
         mainActions = groups[desktop];
     }
 
     if ( !mainActions ) {
-        mainActions = gtk_action_group_new("main");
+        mainActions = Gtk::ActionGroup::create("main");
         groups[desktop] = mainActions;
     }
 
     for ( guint i = 0; i < G_N_ELEMENTS(verbsToUse); i++ ) {
         Inkscape::Verb* verb = Inkscape::Verb::get(verbsToUse[i]);
         if ( verb ) {
-            if ( !gtk_action_group_get_action( mainActions, verb->get_id() ) ) {
+            if (!mainActions->get_action(verb->get_id())) {
                 GtkAction* act = create_action_for_verb( verb, view, toolboxSize );
-                gtk_action_group_add_action( mainActions, act );
+                mainActions->add(Glib::wrap(act));
             }
         }
     }
 
+    if ( !mainActions->get_action("ToolZoom") ) {
+        GtkTooltips *tt = gtk_tooltips_new();
+        for ( guint i = 0; i < G_N_ELEMENTS(tools) && tools[i].type_name; i++ ) {
+            Glib::RefPtr<VerbAction> va = VerbAction::create(Inkscape::Verb::get(tools[i].verb), Inkscape::Verb::get(tools[i].doubleclick_verb), view, tt);
+            if ( va ) {
+                mainActions->add(va);
+                if ( i == 0 ) {
+                    va->set_active(true);
+                }
+            }
+        }
+    }
+
+
     return mainActions;
 }
 
@@ -665,11 +819,11 @@ sp_tool_toolbox_new()
     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
 
-     gtk_container_add(GTK_CONTAINER(hb), tb);
-     gtk_widget_show(GTK_WIDGET(tb));
+    gtk_container_add(GTK_CONTAINER(hb), tb);
+    gtk_widget_show(GTK_WIDGET(tb));
 
     sigc::connection* conn = new sigc::connection;
-     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
+    g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
 
     g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(handlebox_detached), static_cast<gpointer>(0));
     g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(handlebox_attached), static_cast<gpointer>(0));
@@ -1329,18 +1483,12 @@ static void sp_zoom_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* /*mainA
 void
 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
 {
-    if ( GTK_IS_BIN(toolbox) ) {
-        toolbox_set_desktop(gtk_bin_get_child(GTK_BIN(toolbox)), desktop, setup_tool_toolbox, update_tool_toolbox, static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox), "event_context_connection")));
-    } else if (GTK_IS_TOOLBAR(toolbox) ) {
-        toolbox_set_desktop(toolbox,
-                            desktop,
-                            setup_tool_toolbox,
-                            update_tool_toolbox,
-                            static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox),
-                                                                             "event_context_connection")));
-    } else {
-        g_warning("Unexpected toolbox type");
-    }
+    toolbox_set_desktop(toolbox,
+                        desktop,
+                        setup_tool_toolbox,
+                        update_tool_toolbox,
+                        static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox),
+                                                                         "event_context_connection")));
 }
 
 
@@ -1400,33 +1548,75 @@ toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_
 static void
 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
 {
-    GtkTooltips *tooltips=GTK_TOOLTIPS(g_object_get_data(G_OBJECT(toolbox), "tooltips"));
+    gchar const * descr =
+        "<ui>"
+        "  <toolbar name='ToolToolbar'>"
+        "    <toolitem action='ToolSelector' />"
+        "    <toolitem action='ToolNode' />"
+        "    <toolitem action='ToolTweak' />"
+        "    <toolitem action='ToolZoom' />"
+        "    <toolitem action='ToolRect' />"
+        "    <toolitem action='Tool3DBox' />"
+        "    <toolitem action='ToolArc' />"
+        "    <toolitem action='ToolStar' />"
+        "    <toolitem action='ToolSpiral' />"
+        "    <toolitem action='ToolPencil' />"
+        "    <toolitem action='ToolPen' />"
+        "    <toolitem action='ToolCalligraphic' />"
+        "    <toolitem action='ToolEraser' />"
+        "    <toolitem action='ToolPaintBucket' />"
+        "    <toolitem action='ToolText' />"
+        "    <toolitem action='ToolConnector' />"
+        "    <toolitem action='ToolGradient' />"
+        "    <toolitem action='ToolDropper' />"
+        "  </toolbar>"
+        "</ui>";
+    Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions( desktop );
+    GtkUIManager* mgr = gtk_ui_manager_new();
+    GError* errVal = 0;
+
+    gtk_ui_manager_insert_action_group( mgr, mainActions->gobj(), 0 );
+    gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
+
+    GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/ToolToolbar" );
+    if ( prefs_get_int_attribute_limited( "toolbox", "icononly", 1, 0, 1 ) ) {
+        gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
+    }
     Inkscape::IconSize toolboxSize = prefToSize("toolbox.tools", "small");
+    gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), (GtkIconSize)toolboxSize );
 
-    for (int i = 0 ; tools[i].type_name ; i++ ) {
-        GtkWidget *button =
-            sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
-                                                              SP_BUTTON_TYPE_TOGGLE,
-                                                              Inkscape::Verb::get(tools[i].verb),
-                                                              Inkscape::Verb::get(tools[i].doubleclick_verb),
-                                                              desktop,
-                                                              tooltips );
+    gtk_toolbar_set_orientation(GTK_TOOLBAR(toolBar), GTK_ORIENTATION_VERTICAL);
+    gtk_toolbar_set_show_arrow(GTK_TOOLBAR(toolBar), TRUE);
 
-        g_object_set_data( G_OBJECT(toolbox), tools[i].data_name,
-                           (gpointer)button );
+    g_object_set_data(G_OBJECT(toolBar), "desktop", NULL);
+
+    GtkWidget* child = gtk_bin_get_child(GTK_BIN(toolbox));
+    if ( child ) {
+        gtk_container_remove( GTK_CONTAINER(toolbox), child );
     }
+
+    gtk_container_add( GTK_CONTAINER(toolbox), toolBar );
+//     Inkscape::IconSize toolboxSize = prefToSize("toolbox.tools", "small");
 }
 
 
 static void
-update_tool_toolbox( SPDesktop */*desktop*/, SPEventContext *eventcontext, GtkWidget *toolbox )
+update_tool_toolbox( SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget */*toolbox*/ )
 {
     gchar const *const tname = ( eventcontext
                                  ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
                                  : NULL );
+    Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions( desktop );
+
     for (int i = 0 ; tools[i].type_name ; i++ ) {
-        SPButton *button = SP_BUTTON(g_object_get_data(G_OBJECT(toolbox), tools[i].data_name));
-        sp_button_toggle_set_down(button, tname && !strcmp(tname, tools[i].type_name));
+        Glib::RefPtr<Gtk::Action> act = mainActions->get_action( Inkscape::Verb::get(tools[i].verb)->get_id() );
+        if ( act ) {
+            bool setActive = tname && !strcmp(tname, tools[i].type_name);
+            Glib::RefPtr<VerbAction> verbAct = Glib::RefPtr<VerbAction>::cast_dynamic(act);
+            if ( verbAct ) {
+                verbAct->set_active(setActive);
+            }
+        }
     }
 }
 
@@ -1434,10 +1624,10 @@ static void
 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
 {
     GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
-    GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
+    Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions( desktop );
     GtkUIManager* mgr = gtk_ui_manager_new();
     GError* errVal = 0;
-    gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
+    gtk_ui_manager_insert_action_group( mgr, mainActions->gobj(), 0 );
     gtk_ui_manager_add_ui_from_string( mgr, ui_descr, -1, &errVal );
 
     std::map<std::string, GtkWidget*> dataHolders;
@@ -1450,7 +1640,7 @@ setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
             g_object_set_data( G_OBJECT(kludge), "dtw", desktop->canvas);
             g_object_set_data( G_OBJECT(kludge), "desktop", desktop);
             dataHolders[aux_toolboxes[i].type_name] = kludge;
-            aux_toolboxes[i].prep_func( desktop, mainActions, G_OBJECT(kludge) );
+            aux_toolboxes[i].prep_func( desktop, mainActions->gobj(), G_OBJECT(kludge) );
         } else {
 
             GtkWidget *sub_toolbox = 0;
@@ -1572,13 +1762,13 @@ setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
         "    <toolitem action='DialogDocumentProperties' />"
         "  </toolbar>"
         "</ui>";
-    GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
+    Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions( desktop );
 
 
     GtkUIManager* mgr = gtk_ui_manager_new();
     GError* errVal = 0;
 
-    gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
+    gtk_ui_manager_insert_action_group( mgr, mainActions->gobj(), 0 );
     gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
 
     GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/CommandsToolbar" );
@@ -1635,50 +1825,6 @@ sp_empty_toolbox_new(SPDesktop *desktop)
     return tbl;
 }
 
-// helper UI functions
-
-GtkWidget *
-sp_tb_spinbutton(
-    gchar *label, gchar const *tooltip,
-    gchar const *path, gchar const *data, gdouble def,
-    GtkWidget *us,
-    GtkWidget *tbl,
-    gboolean altx, gchar const *altx_mark,
-    gdouble lower, gdouble upper, gdouble step, gdouble page,
-    void (*callback)(GtkAdjustment *, GtkWidget *),
-    gdouble climb = 0.1, guint digits = 3, double factor = 1.0)
-{
-    GtkTooltips *tt = gtk_tooltips_new();
-
-    GtkWidget *hb = gtk_hbox_new(FALSE, 1);
-
-    GtkWidget *l = gtk_label_new(label);
-    gtk_widget_show(l);
-    gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
-    gtk_container_add(GTK_CONTAINER(hb), l);
-
-    GtkObject *a = gtk_adjustment_new(prefs_get_double_attribute(path, data, def) * factor,
-                                      lower, upper, step, page, page);
-    gtk_object_set_data(GTK_OBJECT(tbl), data, a);
-    if (us)
-        sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(us), GTK_ADJUSTMENT(a));
-
-    GtkWidget *sb = gtk_spin_button_new(GTK_ADJUSTMENT(a), climb, digits);
-    gtk_tooltips_set_tip(tt, sb, tooltip, NULL);
-    if (altx)
-        gtk_object_set_data(GTK_OBJECT(sb), altx_mark, sb);
-    gtk_widget_set_size_request(sb,
-                                (upper <= 1.0 || digits == 0)? AUX_SPINBUTTON_WIDTH_SMALL - 10: AUX_SPINBUTTON_WIDTH_SMALL,
-                                AUX_SPINBUTTON_HEIGHT);
-    gtk_widget_show(sb);
-    gtk_signal_connect(GTK_OBJECT(sb), "focus-in-event", GTK_SIGNAL_FUNC(spinbutton_focus_in), tbl);
-    gtk_signal_connect(GTK_OBJECT(sb), "key-press-event", GTK_SIGNAL_FUNC(spinbutton_keypress), tbl);
-    gtk_container_add(GTK_CONTAINER(hb), sb);
-    gtk_signal_connect(GTK_OBJECT(a), "value_changed", GTK_SIGNAL_FUNC(callback), tbl);
-
-    return hb;
-}
-
 #define MODE_LABEL_WIDTH 70
 
 //########################
@@ -3122,31 +3268,27 @@ static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActio
 //##     Pen/Pencil    ##
 //########################
 
-static void sp_pc_spiro_spline_mode_changed(EgeSelectOneAction* act, GObject* /*tbl*/)
+static char const *
+freehand_tool_name(GObject *dataKludge)
 {
-    prefs_set_int_attribute("tools.freehand", "spiro-spline-mode", ege_select_one_action_get_active(act));
+    SPDesktop *desktop = (SPDesktop *) g_object_get_data(dataKludge, "desktop");
+    return ( tools_isactive(desktop, TOOLS_FREEHAND_PEN)
+             ? "tools.freehand.pen"
+             : "tools.freehand.pencil" );
 }
 
-static void sp_add_spiro_toggle(GtkActionGroup* mainActions, GObject* holder, bool tool_is_pencil)
+static void sp_pc_spiro_spline_mode_changed(EgeSelectOneAction* act, GObject* tbl)
 {
-    // FIXME: No action is needed, we only want a simple label. But sp_toolbox_add_label() always
-    //        adds the label at the end of the toolbar, whence this workarund. How to avoid this?
-    {
-        EgeOutputAction* act = ege_output_action_new(
-            tool_is_pencil ?
-            "FreehandModeActionPencilTemp" :
-            "FreehandModeActionPenTemp",
-            _("<b>Mode:</b>"), "", 0 );
-        ege_output_action_set_use_markup( act, TRUE );
-        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
-        g_object_set_data( holder, "freehand_mode_action", act );
-    }
+    prefs_set_int_attribute(freehand_tool_name(tbl), "spiro-spline-mode", ege_select_one_action_get_active(act));
+}
 
+static void sp_add_spiro_toggle(GtkActionGroup* mainActions, GObject* holder, bool tool_is_pencil)
+{
     /* Freehand mode toggle buttons */
     {
-        //gchar const *flatsidedstr = prefs_get_string_attribute( "tools.shapes.star", "isflatsided" );
-        //bool isSpiroMode = flatsidedstr ? (strcmp(flatsidedstr, "false") != 0) : true;
-        guint spiroMode = prefs_get_int_attribute("tools.freehand", "spiro-spline-mode", 0);
+        // FIXME: spiroMode seems not to be read correctly here during startup, although the
+        //        correct mode is used in pen/pencil tool later on; same for freehand shapes
+        guint spiroMode = prefs_get_int_attribute(freehand_tool_name(holder), "spiro-spline-mode", 0);
         Inkscape::IconSize secondarySize = prefToSize("toolbox", "secondary", 1);
 
         {
@@ -3155,24 +3297,23 @@ static void sp_add_spiro_toggle(GtkActionGroup* mainActions, GObject* holder, bo
             GtkTreeIter iter;
             gtk_list_store_append( model, &iter );
             gtk_list_store_set( model, &iter,
-                                0, _("Bézier"),
-                                1, _("Regular Bézier mode"),
+                                0, _("Bezier"),
+                                1, _("Create regular Bezier path"),
                                 2, "bezier_mode",
                                 -1 );
 
             gtk_list_store_append( model, &iter );
             gtk_list_store_set( model, &iter,
                                 0, _("Spiro"),
-                                1, _("Spiro splines mode"),
+                                1, _("Create Spiro path"),
                                 2, "spiro_splines_mode",
                                 -1 );
 
             EgeSelectOneAction* act = ege_select_one_action_new(tool_is_pencil ?
                                                                 "FreehandModeActionPencil" :
                                                                 "FreehandModeActionPen",
-                                                                (""), (""), NULL, GTK_TREE_MODEL(model) );
+                                                                ("Mode:"), ("Mode"), NULL, GTK_TREE_MODEL(model) );
             gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
-            g_object_set_data( holder, "freehande_mode_action", act );
 
             ege_select_one_action_set_appearance( act, "full" );
             ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
@@ -3187,9 +3328,59 @@ static void sp_add_spiro_toggle(GtkActionGroup* mainActions, GObject* holder, bo
     }
 }
 
+static void sp_freehand_change_shape(EgeSelectOneAction* act, GObject *dataKludge) {
+    gint shape = ege_select_one_action_get_active( act );
+    prefs_set_int_attribute(freehand_tool_name(dataKludge), "shape", shape);
+}
+
+/**
+ * \brief Generate the list of freehand advanced shape option entries.
+ */
+GList * freehand_shape_dropdown_items_list() {
+    GList *glist = NULL;
+
+    glist = g_list_append (glist, _("None"));
+    glist = g_list_append (glist, _("Triangle in"));
+    glist = g_list_append (glist, _("Triangle out"));
+    glist = g_list_append (glist, _("Ellipse"));
+    glist = g_list_append (glist, _("From clipboard"));
+
+    return glist;
+}
+
+static void
+sp_freehand_add_advanced_shape_options(GtkActionGroup* mainActions, GObject* holder, bool tool_is_pencil) {
+    /*advanced shape options */
+    {
+        GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
+
+        GList* items = 0;
+        gint count = 0;
+        for ( items = freehand_shape_dropdown_items_list(); items ; items = g_list_next(items) )
+        {
+            GtkTreeIter iter;
+            gtk_list_store_append( model, &iter );
+            gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
+            count++;
+        }
+        g_list_free( items );
+        items = 0;
+        EgeSelectOneAction* act1 = ege_select_one_action_new(
+            tool_is_pencil ? "SetPencilShapeAction" : "SetPenShapeAction",
+            _("Shape:"), ("Shape"), NULL, GTK_TREE_MODEL(model));
+        g_object_set( act1, "short_label", _("Shape:"), NULL );
+        ege_select_one_action_set_appearance( act1, "compact" );
+        ege_select_one_action_set_active( act1, prefs_get_int_attribute(freehand_tool_name(holder), "shape", 0) );
+        g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(sp_freehand_change_shape), holder );
+        gtk_action_group_add_action( mainActions, GTK_ACTION(act1) );
+        g_object_set_data( holder, "shape_action", act1 );
+    }
+}
+
 static void sp_pen_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* mainActions, GObject* holder)
 {
     sp_add_spiro_toggle(mainActions, holder, false);
+    sp_freehand_add_advanced_shape_options(mainActions, holder, false);
 }
 
 
@@ -3220,45 +3411,45 @@ sp_pencil_tb_tolerance_value_changed(GtkAdjustment *adj, GObject *tbl)
     }
     // in turn, prevent listener from responding
     g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
-    prefs_set_double_attribute("tools.freehand.pencil", 
+    prefs_set_double_attribute("tools.freehand.pencil",
                                "tolerance", adj->value);
     g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
-    
+
 }
 
 
 
 static void
-sp_pencil_tb_tolerance_value_changed_external(Inkscape::XML::Node *repr, 
-                                              const gchar *key, 
-                                              const gchar *oldval, 
-                                              const gchar *newval, 
-                                              bool is_interactive, 
+sp_pencil_tb_tolerance_value_changed_external(Inkscape::XML::Node */*repr*/,
+                                              const gchar */*key*/,
+                                              const gchar */*oldval*/,
+                                              const gchar */*newval*/,
+                                              bool /*is_interactive*/,
                                               void * data)
 {
     GObject* tbl = G_OBJECT(data);
     if (g_object_get_data( tbl, "freeze" )) {
         return;
-    }    
+    }
 
     g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
 
     GtkAdjustment * adj = (GtkAdjustment*)g_object_get_data(tbl,
                                                             "tolerance");
-    
-    double v = prefs_get_double_attribute("tools.freehand.pencil", 
+
+    double v = prefs_get_double_attribute("tools.freehand.pencil",
                                             "tolerance", adj->value);
     gtk_adjustment_set_value(adj, v);
     g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
-    
+
 }
 
-static Inkscape::XML::NodeEventVector pencil_node_events = 
+static Inkscape::XML::NodeEventVector pencil_node_events =
 {
-    NULL, 
-    NULL, 
+    NULL,
+    NULL,
     sp_pencil_tb_tolerance_value_changed_external,
-    NULL, 
+    NULL,
     NULL,
 };
 
@@ -3271,26 +3462,32 @@ static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActio
 
     /* Tolerance */
     {
-
+        gchar const* labels[] = {_("(many nodes, rough)"), ("(default)"), 0, 0, 0, 0, ("(few nodes, smooth)")};
+        gdouble values[] = {1, 10, 20, 30, 50, 75, 100};
         eact = create_adjustment_action( "PencilToleranceAction",
-                 _("Number of pixels allowed in interpolating"), 
-                                         _("Tolerance:"), _("Tolerance"),
-                                         "tools.freehand.pencil", "tolerance", 
+                                         _("Smoothing:"), _("Smoothing"),
+                 _("How much smoothing (simplifying) is applied to the line"),
+                                         "tools.freehand.pencil", "tolerance",
                                          3.0,
-                                         GTK_WIDGET(desktop->canvas), NULL, 
+                                         GTK_WIDGET(desktop->canvas), NULL,
                                          holder, TRUE, "altx-pencil",
-                                         0.5, 100.0, 0.5, 1.0, 
-                                         NULL, NULL, 0,
+                                         1, 100.0, 0.5, 0,
+                                         labels, values, G_N_ELEMENTS(labels),
                                          sp_pencil_tb_tolerance_value_changed,
                                          1, 2);
+        ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
 
-        Inkscape::XML::Node *repr = inkscape_get_repr(INKSCAPE, 
+        Inkscape::XML::Node *repr = inkscape_get_repr(INKSCAPE,
                                                       "tools.freehand.pencil");
         repr->addListener(&pencil_node_events, G_OBJECT(holder));
         g_object_set_data(G_OBJECT(holder), "repr", repr);
 
     }
+
+    /* advanced shape options */
+    sp_freehand_add_advanced_shape_options(mainActions, holder, true);
+
     /* Reset */
     {
         InkAction* inky = ink_action_new( "PencilResetAction",
@@ -3301,7 +3498,7 @@ static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActio
         g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_pencil_tb_defaults), holder );
         gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
     }
-    
+
     g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
 
 }
@@ -3388,9 +3585,10 @@ static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainAction
                                                               _("Width"), _("Width:"), _("The width of the tweak area (relative to the visible canvas area)"),
                                                               "tools.tweak", "width", 15,
                                                               GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-tweak",
-                                                              1, 100, 1.0, 10.0,
+                                                              1, 100, 1.0, 0.0,
                                                               labels, values, G_N_ELEMENTS(labels),
                                                               sp_tweak_width_value_changed,  0.01, 0, 100 );
+        ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
     }
@@ -3404,9 +3602,10 @@ static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainAction
                                                               _("Force"), _("Force:"), _("The force of the tweak action"),
                                                               "tools.tweak", "force", 20,
                                                               GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "tweak-force",
-                                                              1, 100, 1.0, 10.0,
+                                                              1, 100, 1.0, 0.0,
                                                               labels, values, G_N_ELEMENTS(labels),
                                                               sp_tweak_force_value_changed,  0.01, 0, 100 );
+        ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
     }
@@ -3600,22 +3799,26 @@ static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainAction
 //########################
 //##     Calligraphy    ##
 //########################
-static void update_presets_list(GObject *dataKludge ){
-    EgeSelectOneAction *sel = static_cast<EgeSelectOneAction *>(g_object_get_data(dataKludge, "profile_selector"));
+static void update_presets_list (GObject *tbl){
+
+    if (g_object_get_data(tbl, "presets_blocked")) 
+        return;
+
+    EgeSelectOneAction *sel = static_cast<EgeSelectOneAction *>(g_object_get_data(tbl, "profile_selector"));
     if (sel) {
-        ege_select_one_action_set_active(sel, 0 );
+        ege_select_one_action_set_active(sel, 0);
     }
 }
 
 static void sp_ddc_mass_value_changed( GtkAdjustment *adj, GObject* tbl )
 {
-    prefs_set_double_attribute( "tools.calligraphic", "mass", adj->value );
+    prefs_set_double_attribute( "tools.calligraphic", "mass", adj->value * 0.01 );
     update_presets_list(tbl);
 }
 
 static void sp_ddc_wiggle_value_changed( GtkAdjustment *adj, GObject* tbl )
 {
-    prefs_set_double_attribute( "tools.calligraphic", "wiggle", adj->value );
+    prefs_set_double_attribute( "tools.calligraphic", "wiggle", adj->value * 0.01 );
     update_presets_list(tbl);
 }
 
@@ -3633,19 +3836,19 @@ static void sp_ddc_width_value_changed( GtkAdjustment *adj, GObject *tbl )
 
 static void sp_ddc_velthin_value_changed( GtkAdjustment *adj, GObject* tbl )
 {
-    prefs_set_double_attribute("tools.calligraphic", "thinning", adj->value);
+    prefs_set_double_attribute("tools.calligraphic", "thinning", adj->value * 0.01 );
     update_presets_list(tbl);
 }
 
 static void sp_ddc_flatness_value_changed( GtkAdjustment *adj, GObject* tbl )
 {
-    prefs_set_double_attribute( "tools.calligraphic", "flatness", adj->value );
+    prefs_set_double_attribute( "tools.calligraphic", "flatness", adj->value * 0.01);
     update_presets_list(tbl);
 }
 
 static void sp_ddc_tremor_value_changed( GtkAdjustment *adj, GObject* tbl )
 {
-    prefs_set_double_attribute( "tools.calligraphic", "tremor", adj->value );
+    prefs_set_double_attribute( "tools.calligraphic", "tremor", adj->value * 0.01 );
     update_presets_list(tbl);
 }
 
@@ -3669,7 +3872,7 @@ static void sp_ddc_trace_background_changed( GtkToggleAction *act, GObject*  tbl
 
 static void sp_ddc_tilt_state_changed( GtkToggleAction *act, GObject*  tbl )
 {
-    GtkAction * calligraphy_angle = static_cast<GtkAction *> (g_object_get_data(tbl,"angle"));
+    GtkAction * calligraphy_angle = static_cast<GtkAction *> (g_object_get_data(tbl,"angle_action"));
     prefs_set_int_attribute( "tools.calligraphic", "usetilt", gtk_toggle_action_get_active( act ) ? 1 : 0 );
     update_presets_list(tbl);
     if (calligraphy_angle )
@@ -3677,103 +3880,175 @@ static void sp_ddc_tilt_state_changed( GtkToggleAction *act, GObject*  tbl )
 }
 
 
-#define PROFILE_FLOAT_SIZE 7
-#define PROFILE_INT_SIZE 4
-struct ProfileFloatElement {
-    char const *name;
-    double def;
-    double min;
-    double max;
-};
-struct ProfileIntElement {
-    char const *name;
-    int def;
-    int min;
-    int max;
+#define NUMBER_OF_PRESET_PARAMS 11
+static gchar * widget_names[NUMBER_OF_PRESET_PARAMS] = {
+    "width",
+    "mass",
+    "wiggle",
+    "angle",
+    "thinning",
+    "tremor",
+    "flatness",
+    "cap_rounding",
+    "usepressure",
+    "tracebackground",
+    "usetilt"
 };
 
 
+static void sp_dcc_build_presets_list(GObject *tbl) 
+{
+    EgeSelectOneAction* selector = static_cast<EgeSelectOneAction *>(g_object_get_data(tbl, "profile_selector"));
+    GtkListStore* model = GTK_LIST_STORE(ege_select_one_action_get_model(selector));
+    gtk_list_store_clear (model);
 
-static ProfileFloatElement f_profile[PROFILE_FLOAT_SIZE] = {
-    {"mass",0.02, 0.0, 1.0},
-    {"wiggle",0.0, 0.0, 1.0},
-    {"angle",30.0, -90.0, 90.0},
-    {"thinning",0.1, -1.0, 1.0},
-    {"tremor",0.0, 0.0, 1.0},
-    {"flatness",0.9, 0.0, 1.0},
-    {"cap_rounding",0.0, 0.0, 5.0}
-};
-static ProfileIntElement i_profile[PROFILE_INT_SIZE] = {
-    {"width",15, 1, 100},
-    {"usepressure",1,0,1},
-    {"tracebackground",0,0,1},
-    {"usetilt",1,0,1},
-};
+    {
+        GtkTreeIter iter;
+        gtk_list_store_append( model, &iter );
+        gtk_list_store_set( model, &iter, 0, _("No preset"), 1, 0, -1 );
+    }
+
+    //TODO: switch back to prefs API
+    Inkscape::XML::Node *repr = inkscape_get_repr(INKSCAPE, "tools.calligraphic.preset" );
+    Inkscape::XML::Node *child_repr = sp_repr_children(repr);
+    int ii=1;
+    while (child_repr) {
+        GtkTreeIter iter;
+        char *preset_name = (char *) child_repr->attribute("name");
+        gtk_list_store_append( model, &iter );
+        gtk_list_store_set( model, &iter, 0, preset_name, 1, ++ii, -1 );
+        child_repr = sp_repr_next(child_repr);
+    }
 
+    {
+        GtkTreeIter iter;
+        gtk_list_store_append( model, &iter );
+        gtk_list_store_set( model, &iter, 0, _("Save..."), 1, ii, -1 );
+        g_object_set_data(tbl, "save_presets_index", GINT_TO_POINTER(ii));
+    }
 
+    update_presets_list (tbl);
+}
 
-static void sp_dcc_save_profile( GtkWidget */*widget*/, GObject *dataKludge ){
-    SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
+static void sp_dcc_save_profile (GtkWidget */*widget*/, GObject *tbl)
+{
+    SPDesktop *desktop = (SPDesktop *) g_object_get_data(tbl, "desktop" );
     if (! desktop) return;
 
+    if (g_object_get_data(tbl, "presets_blocked")) 
+        return;
+
     Inkscape::UI::Dialogs::CalligraphicProfileDialog::show(desktop);
-    if ( ! Inkscape::UI::Dialogs::CalligraphicProfileDialog::applied()) return;
+    if ( ! Inkscape::UI::Dialogs::CalligraphicProfileDialog::applied()) {
+        // dialog cancelled
+        update_presets_list (tbl);
+        return;
+    }
     Glib::ustring profile_name = Inkscape::UI::Dialogs::CalligraphicProfileDialog::getProfileName();
 
-    unsigned int new_index = pref_path_number_of_children("tools.calligraphic.preset") +1;
-    gchar *profile_id = g_strdup_printf("dcc%d", new_index);
-    gchar *pref_path = create_pref("tools.calligraphic.preset",profile_id);    
-    
-    for (unsigned i = 0; i < PROFILE_FLOAT_SIZE; ++i) {
-        ProfileFloatElement const &pe = f_profile[i];
-        double v = prefs_get_double_attribute_limited("tools.calligraphic",pe.name, pe.def, pe.min, pe.max);
-        prefs_set_double_attribute(pref_path,pe.name,v);
-    }    
-    for (unsigned i = 0; i < PROFILE_INT_SIZE; ++i) {
-        ProfileIntElement const &pe = i_profile[i];
-        int v = prefs_get_int_attribute_limited("tools.calligraphic",pe.name, pe.def,pe.min, pe.max);
-        prefs_set_int_attribute(pref_path,pe.name,v);
-    }
-    prefs_set_string_attribute(pref_path,"name",profile_name.c_str());
-
-    EgeSelectOneAction* selector = static_cast<EgeSelectOneAction *>(g_object_get_data(dataKludge, "profile_selector"));
-    GtkListStore* model = GTK_LIST_STORE(ege_select_one_action_get_model(selector));
-    GtkTreeIter iter;
-    gtk_list_store_append( model, &iter );
-    gtk_list_store_set( model, &iter, 0, profile_name.c_str(), 1, new_index, -1 );
-
-    free(profile_id);
-    free(pref_path);
-
-    ege_select_one_action_set_active(selector, new_index);
-}
-
-
-static void sp_ddc_change_profile(EgeSelectOneAction* act, GObject *dataKludge) {
-    
-    gint preset_index = ege_select_one_action_get_active( act ); 
-    gchar *profile_name = get_pref_nth_child("tools.calligraphic.preset", preset_index);
-       
-    if ( profile_name) {        
-        g_object_set_data(dataKludge, "profile_selector",NULL); //temporary hides the selector so no one will updadte it
-        for (unsigned i = 0; i < PROFILE_FLOAT_SIZE; ++i) {
-            ProfileFloatElement const &pe = f_profile[i];
-            double v = prefs_get_double_attribute_limited(profile_name, pe.name, pe.def, pe.min, pe.max);
-            GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(dataKludge, pe.name));
-            if ( adj ) {
-                gtk_adjustment_set_value(adj, v);
+    if (!profile_name.c_str() || *profile_name.c_str() == 0) {
+        // empty name entered
+        update_presets_list (tbl);
+        return;
+    }
+
+    int new_index = -1;
+    gchar *pref_path = NULL;
+    int total_prefs = pref_path_number_of_children("tools.calligraphic.preset");
+
+    for (int i = 1; i <= total_prefs; i++) {
+        gchar *path = get_pref_nth_child("tools.calligraphic.preset", i);
+        const gchar *name = prefs_get_string_attribute(path, "name");
+        if (name && !strcmp(name, profile_name.c_str())) {
+            // we already have preset with this name, replace its values
+            new_index = i;
+            pref_path = g_strdup(path);
+            break;
+        }
+    }
+
+    if (new_index == -1) {
+        // no preset with this name, create 
+        new_index = total_prefs + 1;
+        gchar *profile_id = g_strdup_printf("dcc%d", new_index);
+        pref_path = create_pref("tools.calligraphic.preset", profile_id);
+        free(profile_id);
+    }
+
+    for (unsigned i = 0; i < NUMBER_OF_PRESET_PARAMS; ++i) {
+        gchar *widget_name = widget_names[i];
+        void *widget = g_object_get_data(tbl, widget_name);
+        if (widget) {
+            if (GTK_IS_ADJUSTMENT(widget)) {
+                GtkAdjustment* adj = static_cast<GtkAdjustment *>(widget);
+                double v = gtk_adjustment_get_value(adj);
+                prefs_set_double_attribute(pref_path, widget_name, v);
+                //std::cout << "wrote adj " << widget_name << ": " << v << "\n";
+            } else if (GTK_IS_TOGGLE_ACTION(widget)) {
+                GtkToggleAction* toggle = static_cast<GtkToggleAction *>(widget);
+                int v = gtk_toggle_action_get_active(toggle);
+                prefs_set_int_attribute(pref_path, widget_name, v);
+                //std::cout << "wrote tog " << widget_name << ": " << v << "\n";
+            } else {
+               g_warning("Unknown widget type for preset: %s\n", widget_name);
+            }
+        } else {
+            g_warning("Bad key when writing preset: %s\n", widget_name);
+        }
+    }
+    prefs_set_string_attribute(pref_path, "name", profile_name.c_str());
+
+    sp_dcc_build_presets_list (tbl);
+
+    free (pref_path);
+}
+
+
+static void sp_ddc_change_profile(EgeSelectOneAction* act, GObject* tbl) {
+
+    gint preset_index = ege_select_one_action_get_active( act );
+    gint save_presets_index = GPOINTER_TO_INT(g_object_get_data(tbl, "save_presets_index"));
+
+    if (preset_index == save_presets_index) {
+        // this is the Save command
+        sp_dcc_save_profile(NULL, tbl);
+        return;
+    }
+
+    gchar *preset_path = get_pref_nth_child("tools.calligraphic.preset", preset_index);
+
+    if (preset_path) {
+        g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(TRUE)); //temporarily block the selector so no one will updadte it while we're reading it
+
+        Inkscape::XML::Node *preset_repr = inkscape_get_repr(INKSCAPE, preset_path);
+
+        for ( Inkscape::Util::List<Inkscape::XML::AttributeRecord const> iter = preset_repr->attributeList();
+              iter; 
+              ++iter ) {
+            const gchar *attr_name = g_quark_to_string(iter->key);
+            if (!strcmp(attr_name, "id") || !strcmp(attr_name, "name"))
+                continue;
+            void *widget = g_object_get_data(tbl, attr_name);
+            if (widget) {
+                if (GTK_IS_ADJUSTMENT(widget)) {
+                    double v = prefs_get_double_attribute(preset_path, attr_name, 0); // fixme: no min/max checks here, add?
+                    GtkAdjustment* adj = static_cast<GtkAdjustment *>(widget);
+                    gtk_adjustment_set_value(adj, v);
+                    //std::cout << "set adj " << attr_name << " to " << v << "\n";
+                } else if (GTK_IS_TOGGLE_ACTION(widget)) {
+                    int v = prefs_get_int_attribute(preset_path, attr_name, 0); // fixme: no min/max checks here, add?
+                    GtkToggleAction* toggle = static_cast<GtkToggleAction *>(widget);
+                    gtk_toggle_action_set_active(toggle, v);
+                    //std::cout << "set toggle " << attr_name << " to " << v << "\n";
+                } else {
+                    g_warning("Unknown widget type for preset: %s\n", attr_name);
+                }
+            } else {
+                g_warning("Bad key found in a preset record: %s\n", attr_name);
             }
-        } 
-        for (unsigned i = 0; i < PROFILE_INT_SIZE; ++i) {
-            ProfileIntElement const &pe = i_profile[i];
-            int v = prefs_get_int_attribute_limited(profile_name, pe.name, pe.def, pe.min, pe.max);
-            GtkToggleAction* toggle = static_cast<GtkToggleAction *>(g_object_get_data(dataKludge, pe.name));
-            if ( toggle ) {
-                gtk_toggle_action_set_active(toggle, v);
-            } else printf("No toggle");
         }
-        free(profile_name);
-        g_object_set_data(dataKludge, "profile_selector",act); //restore selector visibility
+        free(preset_path);
+        g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(FALSE));
     }
 
 }
@@ -3793,9 +4068,10 @@ static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* main
                                                               _("The width of the calligraphic pen (relative to the visible canvas area)"),
                                                               "tools.calligraphic", "width", 15,
                                                               GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-calligraphy",
-                                                              1, 100, 1.0, 10.0,
+                                                              1, 100, 1.0, 0.0,
                                                               labels, values, G_N_ELEMENTS(labels),
                                                               sp_ddc_width_value_changed,  0.01, 0, 100 );
+        ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
         }
@@ -3803,15 +4079,15 @@ static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* main
         {
         /* Thinning */
             gchar const* labels[] = {_("(speed blows up stroke)"), 0, 0, _("(slight widening)"), _("(constant width)"), _("(slight thinning, default)"), 0, 0, _("(speed deflates stroke)")};
-            gdouble values[] = {-1, -0.4, -0.2, -0.1, 0, 0.1, 0.2, 0.4, 1};
+            gdouble values[] = {-100, -40, -20, -10, 0, 10, 20, 40, 100};
         EgeAdjustmentAction* eact = create_adjustment_action( "ThinningAction",
                                                               _("Stroke Thinning"), _("Thinning:"),
                                                               _("How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 makes them broader, 0 makes width independent of velocity)"),
-                                                              "tools.calligraphic", "thinning", 0.1,
+                                                              "tools.calligraphic", "thinning", 10,
                                                               GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
-                                                              -1.0, 1.0, 0.01, 0.1,
+                                                              -100, 100, 1, 0.1,
                                                               labels, values, G_N_ELEMENTS(labels),
-                                                              sp_ddc_velthin_value_changed, 0.01, 2);
+                                                              sp_ddc_velthin_value_changed, 0.01, 0, 100);
         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
         }
@@ -3829,23 +4105,23 @@ static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* main
                                                               labels, values, G_N_ELEMENTS(labels),
                                                               sp_ddc_angle_value_changed, 1, 0 );
         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
+        g_object_set_data( holder, "angle_action", eact );
         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
-        g_object_set_data( holder, "angle", eact );
         calligraphy_angle = eact;
         }
 
         {
         /* Fixation */
             gchar const* labels[] = {_("(perpendicular to stroke, \"brush\")"), 0, 0, 0, _("(almost fixed, default)"), _("(fixed by Angle, \"pen\")")};
-        gdouble values[] = {0, 0.2, 0.4, 0.6, 0.9, 1.0};
+        gdouble values[] = {0, 20, 40, 60, 90, 100};
         EgeAdjustmentAction* eact = create_adjustment_action( "FixationAction",
                                                               _("Fixation"), _("Fixation:"),
                                                               _("Angle behavior (0 = nib always perpendicular to stroke direction, 1 = fixed angle)"),
-                                                              "tools.calligraphic", "flatness", 0.9,
+                                                              "tools.calligraphic", "flatness", 90,
                                                               GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
-                                                              0.0, 1.0, 0.01, 0.1,
+                                                              0.0, 100, 1.0, 10.0,
                                                               labels, values, G_N_ELEMENTS(labels),
-                                                              sp_ddc_flatness_value_changed, 0.01, 2 );
+                                                              sp_ddc_flatness_value_changed, 0.01, 0, 100 );
         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
         }
@@ -3870,16 +4146,17 @@ static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* main
         {
         /* Tremor */
             gchar const* labels[] = {_("(smooth line)"), _("(slight tremor)"), _("(noticeable tremor)"), 0, 0, _("(maximum tremor)")};
-        gdouble values[] = {0, 0.1, 0.2, 0.4, 0.6, 1.0};
+        gdouble values[] = {0, 10, 20, 40, 60, 100};
         EgeAdjustmentAction* eact = create_adjustment_action( "TremorAction",
                                                               _("Stroke Tremor"), _("Tremor:"),
                                                               _("Increase to make strokes rugged and trembling"),
                                                               "tools.calligraphic", "tremor", 0.0,
                                                               GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
-                                                              0.0, 1.0, 0.01, 0.1,
+                                                              0.0, 100, 1, 0.0,
                                                               labels, values, G_N_ELEMENTS(labels),
-                                                              sp_ddc_tremor_value_changed, 0.01, 2 );
+                                                              sp_ddc_tremor_value_changed, 0.01, 0, 100 );
 
+        ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
         }
@@ -3887,15 +4164,16 @@ static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* main
         {
         /* Wiggle */
         gchar const* labels[] = {_("(no wiggle)"), _("(slight deviation)"), 0, 0, _("(wild waves and curls)")};
-        gdouble values[] = {0, 0.2, 0.4, 0.6, 1.0};
+        gdouble values[] = {0, 20, 40, 60, 100};
         EgeAdjustmentAction* eact = create_adjustment_action( "WiggleAction",
                                                               _("Pen Wiggle"), _("Wiggle:"),
                                                               _("Increase to make the pen waver and wiggle"),
                                                               "tools.calligraphic", "wiggle", 0.0,
                                                               GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
-                                                              0.0, 1.0, 0.01, 0.1,
+                                                              0.0, 100, 1, 0.0,
                                                               labels, values, G_N_ELEMENTS(labels),
-                                                              sp_ddc_wiggle_value_changed, 0.01, 2 );
+                                                              sp_ddc_wiggle_value_changed, 0.01, 0, 100 );
+        ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
         }
@@ -3903,15 +4181,16 @@ static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* main
         {
         /* Mass */
             gchar const* labels[] = {_("(no inertia)"), _("(slight smoothing, default)"), _("(noticeable lagging)"), 0, 0, _("(maximum inertia)")};
-        gdouble values[] = {0.0, 0.02, 0.1, 0.2, 0.5, 1.0};
+        gdouble values[] = {0.0, 2, 10, 20, 50, 100};
         EgeAdjustmentAction* eact = create_adjustment_action( "MassAction",
                                                               _("Pen Mass"), _("Mass:"),
                                                               _("Increase to make the pen drag behind, as if slowed by inertia"),
-                                                              "tools.calligraphic", "mass", 0.02,
+                                                              "tools.calligraphic", "mass", 2.0,
                                                               GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
-                                                              0.0, 1.0, 0.01, 0.1,
+                                                              0.0, 100, 1, 0.0,
                                                               labels, values, G_N_ELEMENTS(labels),
-                                                              sp_ddc_mass_value_changed, 0.01, 2 );
+                                                              sp_ddc_mass_value_changed, 0.01, 0, 100 );
+        ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
         }
@@ -3959,47 +4238,15 @@ static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* main
 
         /*calligraphic profile */
         {
-            GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );            
-            gchar *pref_path;
-
-
-            GtkTreeIter iter;
-            gtk_list_store_append( model, &iter );
-            gtk_list_store_set( model, &iter, 0, _("No preset"), 1, 0, -1 );
-
-            //TODO: switch back to prefs API
-            Inkscape::XML::Node *repr = inkscape_get_repr(INKSCAPE, "tools.calligraphic.preset" );
-            Inkscape::XML::Node *child_repr = sp_repr_children(repr);
-            int ii=1;
-            while (child_repr) {
-                GtkTreeIter iter;
-                char *preset_name = (char *) child_repr->attribute("name");
-                gtk_list_store_append( model, &iter );                
-                gtk_list_store_set( model, &iter, 0, preset_name, 1, ++ii, -1 );                
-                child_repr = sp_repr_next(child_repr); 
-            }
-
-            pref_path = NULL;
-            EgeSelectOneAction* act1 = ege_select_one_action_new( "SetProfileAction", "" , (_("Change calligraphic profile")), NULL, GTK_TREE_MODEL(model) );
-            ege_select_one_action_set_appearance( act1, "compact" );
-            g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(sp_ddc_change_profile), holder );
-            gtk_action_group_add_action( mainActions, GTK_ACTION(act1) );
-            g_object_set_data( holder, "profile_selector", act1 );
-        
-        }
-
-        /*Save or delete calligraphic profile */
-        {
-            GtkAction* act = gtk_action_new( "SaveDeleteProfileAction",
-                                             _("Defaults"),
-                                             _("Save current settings as new profile"),
-                                             GTK_STOCK_SAVE );
-            g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_dcc_save_profile), holder );
+            GtkListStore* model = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
+            EgeSelectOneAction* act1 = ege_select_one_action_new ("SetProfileAction", "" , (_("Change calligraphic profile")), NULL, GTK_TREE_MODEL(model));
+            ege_select_one_action_set_appearance (act1, "compact");
+            g_object_set_data (holder, "profile_selector", act1 );
 
+            sp_dcc_build_presets_list (holder);
 
-            gtk_action_group_add_action( mainActions, act );
-            gtk_action_set_sensitive( act, TRUE );
-            g_object_set_data( holder, "profile_save_delete", act );
+            g_signal_connect(G_OBJECT(act1), "changed", G_CALLBACK(sp_ddc_change_profile), holder);
+            gtk_action_group_add_action(mainActions, GTK_ACTION(act1));
         }
     }
 }
@@ -4466,9 +4713,10 @@ static void sp_eraser_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActio
                                                               _("The width of the eraser pen (relative to the visible canvas area)"),
                                                               "tools.eraser", "width", 15,
                                                               GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-eraser",
-                                                              1, 100, 1.0, 10.0,
+                                                              1, 100, 1.0, 0.0,
                                                               labels, values, G_N_ELEMENTS(labels),
                                                               sp_ddc_width_value_changed,  0.01, 0, 100 );
+        ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
     }
@@ -4505,7 +4753,7 @@ static void sp_eraser_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActio
         ege_select_one_action_set_active( act, eraserMode );
         g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_erasertb_mode_changed), holder );
     }
-    
+
 }
 
 //########################
@@ -4553,8 +4801,7 @@ sp_text_toolbox_selection_changed (Inkscape::Selection */*selection*/, GObject *
     SPStyle *query =
         sp_style_new (SP_ACTIVE_DOCUMENT);
 
-    int result_fontspec =
-        sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
+//    int result_fontspec = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
 
     int result_family =
         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
@@ -4568,18 +4815,24 @@ sp_text_toolbox_selection_changed (Inkscape::Selection */*selection*/, GObject *
     gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
 
     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
-    if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING)
-    {
+    if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING) {
+        // there are no texts in selection, read from prefs
         Inkscape::XML::Node *repr = inkscape_get_repr (INKSCAPE, "tools.text");
-
-        if (repr)
-        {
+        if (repr) {
             sp_style_read_from_repr (query, repr);
-        }
-        else
-        {
+            if (g_object_get_data(tbl, "text_style_from_prefs")) {
+                // do not reset the toolbar style from prefs if we already did it last time
+                sp_style_unref(query);
+                return;
+            }
+            g_object_set_data(tbl, "text_style_from_prefs", GINT_TO_POINTER(TRUE));
+        } else {
+            sp_style_unref(query);
             return;
         }
+    } else {
+        g_object_set_data(tbl, "text_style_from_prefs", GINT_TO_POINTER(FALSE));
     }
 
     if (query->text)
@@ -4609,6 +4862,7 @@ sp_text_toolbox_selection_changed (Inkscape::Selection */*selection*/, GObject *
                 path = Inkscape::FontLister::get_instance()->get_row_for_font (familyName);
             } catch (...) {
                 g_warning("Family name %s does not have an entry in the font lister.", familyName.c_str());
+                sp_style_unref(query);
                 return;
             }
 
@@ -4761,7 +5015,7 @@ sp_text_toolbox_family_changed (GtkTreeSelection    *selection,
     int result_fontspec =
         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
 
-    font_instance * fontFromStyle = font_factory::Default()->FaceFromStyle(query);
+    //font_instance * fontFromStyle = font_factory::Default()->FaceFromStyle(query);
 
     SPCSSAttr *css = sp_repr_css_attr_new ();
 
@@ -4930,14 +5184,9 @@ sp_text_toolbox_style_toggled (GtkToggleButton  *button,
     int result_fontspec =
         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
 
-    int result_family =
-        sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
-
-    int result_style =
-        sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
-
-    int result_numbers =
-        sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
+    //int result_family = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
+    //int result_style = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
+    //int result_numbers = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
 
     Glib::ustring fontSpec = query->text->font_specification.set ?  query->text->font_specification.value : "";
     Glib::ustring newFontSpec = "";
@@ -5820,7 +6069,7 @@ static void paintbucket_offset_changed(GtkAdjustment *adj, GObject *tbl)
     prefs_set_string_attribute("tools.paintbucket", "offsetunits", sp_unit_get_abbreviation(unit));
 }
 
-static void paintbucket_defaults(GtkWidget *, GObject *dataKludge)
+static void paintbucket_defaults (GtkWidget *, GObject *tbl)
 {
     // FIXME: make defaults settable via Inkscape Options
     struct KeyValue {
@@ -5833,15 +6082,15 @@ static void paintbucket_defaults(GtkWidget *, GObject *dataKludge)
 
     for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
         KeyValue const &kv = key_values[i];
-        GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(dataKludge, kv.key));
+        GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(tbl, kv.key));
         if ( adj ) {
             gtk_adjustment_set_value(adj, kv.value);
         }
     }
 
-    EgeSelectOneAction* channels_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "channels_action" ) );
+    EgeSelectOneAction* channels_action = EGE_SELECT_ONE_ACTION( g_object_get_data (tbl, "channels_action" ) );
     ege_select_one_action_set_active( channels_action, FLOOD_CHANNELS_RGB );
-    EgeSelectOneAction* autogap_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "autogap_action" ) );
+    EgeSelectOneAction* autogap_action = EGE_SELECT_ONE_ACTION( g_object_get_data (tbl, "autogap_action" ) );
     ege_select_one_action_set_active( autogap_action, 0 );
 }
 
@@ -5879,10 +6128,11 @@ static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* main
             _("Fill Threshold"), _("Threshold:"),
             _("The maximum allowed difference between the clicked pixel and the neighboring pixels to be counted in the fill"),
             "tools.paintbucket", "threshold", 5, GTK_WIDGET(desktop->canvas), NULL, holder, TRUE,
-            "inkscape:paintbucket-threshold", 0, 100.0, 1.0, 10.0,
+            "inkscape:paintbucket-threshold", 0, 100.0, 1.0, 0.0,
             0, 0, 0,
             paintbucket_threshold_changed, 1, 0 );
 
+        ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
     }