Code

abstract use of sodipodi:modified
[inkscape.git] / src / widgets / toolbox.cpp
index a4d24203f95bfae6fe2ab1f8adba82ba69379c5b..56f33bf9677660f79ab2e9b89d5c4a77f03a2aa1 100644 (file)
 #include "sp-flowtext.h"
 #include "style.h"
 #include "selection.h"
+#include "selection-chemistry.h"
 #include "document-private.h"
 #include "desktop-style.h"
 #include "../libnrtype/font-lister.h"
+#include "../libnrtype/font-instance.h"
 #include "../connection-pool.h"
 #include "../prefs-utils.h"
 #include "../inkscape-stock.h"
@@ -104,7 +106,7 @@ static void       sp_zoom_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainA
 static void       sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
 static void       sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
 static void       sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
-static void       sp_3dbox_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
+static void       box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
 static void       sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
 static void       sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
 static void       sp_pen_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
@@ -128,7 +130,7 @@ static struct {
     { "SPTweakContext",    "tweak_tool",     SP_VERB_CONTEXT_TWEAK, SP_VERB_CONTEXT_TWEAK_PREFS },
     { "SPZoomContext",     "zoom_tool",      SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
     { "SPRectContext",     "rect_tool",      SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
-//    { "SP3DBoxContext",    "3dbox_tool",     SP_VERB_CONTEXT_3DBOX, SP_VERB_CONTEXT_3DBOX_PREFS },
+    { "Box3DContext",      "3dbox_tool",     SP_VERB_CONTEXT_3DBOX, SP_VERB_CONTEXT_3DBOX_PREFS },
     { "SPArcContext",      "arc_tool",       SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
     { "SPStarContext",     "star_tool",      SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
     { "SPSpiralContext",   "spiral_tool",    SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
@@ -165,7 +167,7 @@ static struct {
       SP_VERB_CONTEXT_STAR_PREFS,   "tools.shapes.star",     _("Style of new stars")},
     { "SPRectContext",   "rect_toolbox",   0, sp_rect_toolbox_prep,              "RectToolbar",
       SP_VERB_CONTEXT_RECT_PREFS,   "tools.shapes.rect",     _("Style of new rectangles")},
-    { "SP3DBoxContext",  "3dbox_toolbox",  0, sp_3dbox_toolbox_prep,             "3DBoxToolbar",
+    { "Box3DContext",  "3dbox_toolbox",  0, box3d_toolbox_prep,             "3DBoxToolbar",
       SP_VERB_CONTEXT_3DBOX_PREFS,  "tools.shapes.3dbox",    _("Style of new 3D boxes")},
     { "SPArcContext",    "arc_toolbox",    0, sp_arc_toolbox_prep,               "ArcToolbar",
       SP_VERB_CONTEXT_ARC_PREFS,    "tools.shapes.arc",      _("Style of new ellipses")},
@@ -243,8 +245,11 @@ static gchar const * ui_descr =
         "    <separator />"
         "    <toolitem action='NodesShowHandlesAction' />"
         "    <separator />"
+        "    <toolitem action='EditNextLPEParameterAction' />"
+        "    <separator />"
         "    <toolitem action='NodeXAction' />"
         "    <toolitem action='NodeYAction' />"
+        "    <toolitem action='NodeUnitsAction' />"
         "  </toolbar>"
 
         "  <toolbar name='TweakToolbar'>"
@@ -307,15 +312,14 @@ static gchar const * ui_descr =
         "  </toolbar>"
 
         "  <toolbar name='3DBoxToolbar'>"
-        "    <toolitem action='3DBoxPosAngleXAction' />"
-        "    <toolitem action='3DBoxVPXAction' />"
-        "    <separator />"
-        "    <toolitem action='3DBoxPosAngleYAction' />"
-        "    <toolitem action='3DBoxVPYAction' />"
+        "    <toolitem action='3DBoxAngleXAction' />"
+        "    <toolitem action='3DBoxVPXStateAction' />"
         "    <separator />"
-        "    <toolitem action='3DBoxPosAngleZAction' />"
-        "    <toolitem action='3DBoxVPZAction' />"
+        "    <toolitem action='3DBoxAngleYAction' />"
+        "    <toolitem action='3DBoxVPYStateAction' />"
         "    <separator />"
+        "    <toolitem action='3DBoxAngleZAction' />"
+        "    <toolitem action='3DBoxVPZStateAction' />"
         "  </toolbar>"
 
         "  <toolbar name='SpiralToolbar'>"
@@ -626,14 +630,9 @@ sp_aux_toolbox_new()
 {
     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
 
-    GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
-    GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
     gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
-    gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
-    gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
 
     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
-    g_object_set_data(G_OBJECT(tb), "top_spacer", tb_s);
 
     gtk_widget_set_sensitive(tb, FALSE);
 
@@ -663,11 +662,7 @@ sp_commands_toolbox_new()
 {
     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
 
-    GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
-    GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
     gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
-    gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
-    gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
 
     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
     gtk_widget_set_sensitive(tb, FALSE);
@@ -844,6 +839,10 @@ static void toggle_show_handles (GtkToggleAction *act, gpointer /*data*/) {
     if (shape_editor) shape_editor->show_handles(show);
 }
 
+void sp_node_path_edit_nextLPEparam (GtkAction */*act*/, gpointer data) {
+    sp_selection_next_patheffect_param( reinterpret_cast<SPDesktop*>(data) );
+}
+
 /* is called when the node selection is modified */
 static void
 sp_node_toolbox_coord_changed(gpointer /*shape_editor*/, GObject *tbl)
@@ -861,6 +860,9 @@ sp_node_toolbox_coord_changed(gpointer /*shape_editor*/, GObject *tbl)
     // in turn, prevent listener from responding
     g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
 
+    UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
+    SPUnit const *unit = tracker->getActiveUnit();
+
     ShapeEditor *shape_editor = get_current_shape_editor();
     if (shape_editor && shape_editor->has_nodepath()) {
         Inkscape::NodePath::Path *nodepath = shape_editor->get_nodepath();
@@ -875,14 +877,14 @@ sp_node_toolbox_coord_changed(gpointer /*shape_editor*/, GObject *tbl)
         } else {
             gtk_action_set_sensitive(xact, TRUE);
             gtk_action_set_sensitive(yact, TRUE);
-            NR::Coord oldx = gtk_adjustment_get_value(xadj);
-            NR::Coord oldy = gtk_adjustment_get_value(xadj);
+            NR::Coord oldx = sp_units_get_pixels(gtk_adjustment_get_value(xadj), *unit);
+            NR::Coord oldy = sp_units_get_pixels(gtk_adjustment_get_value(xadj), *unit);
 
             if (n_selected == 1) {
                 NR::Point sel_node = nodepath->singleSelectedCoords();
                 if (oldx != sel_node[NR::X] || oldy != sel_node[NR::Y]) {
-                    gtk_adjustment_set_value(xadj, sel_node[NR::X]);
-                    gtk_adjustment_set_value(yadj, sel_node[NR::Y]);
+                    gtk_adjustment_set_value(xadj, sp_pixels_get_units(sel_node[NR::X], *unit));
+                    gtk_adjustment_set_value(yadj, sp_pixels_get_units(sel_node[NR::Y], *unit));
                 }
             } else {
                 NR::Maybe<NR::Coord> x = sp_node_selected_common_coord(nodepath, NR::X);
@@ -891,11 +893,17 @@ sp_node_toolbox_coord_changed(gpointer /*shape_editor*/, GObject *tbl)
                     /* Note: Currently x and y will always have a value, even if the coordinates of the
                        selected nodes don't coincide (in this case we use the coordinates of the center
                        of the bounding box). So the entries are never set to zero. */
-                    gtk_adjustment_set_value(xadj, x ? (*x) : 0.0); // FIXME: Maybe we should clear the entry
-                    gtk_adjustment_set_value(yadj, y ? (*y) : 0.0); //        fields, not set them to zero.
+                    // FIXME: Maybe we should clear the entry if several nodes are selected
+                    //        instead of providing a kind of average value
+                    gtk_adjustment_set_value(xadj, sp_pixels_get_units(x ? (*x) : 0.0, *unit));
+                    gtk_adjustment_set_value(yadj, sp_pixels_get_units(y ? (*y) : 0.0, *unit));
                 }
             }
         }
+    } else {
+        // no shape-editor or nodepath yet (when we just switched to the tool); coord entries must be inactive
+        gtk_action_set_sensitive(xact, FALSE);
+        gtk_action_set_sensitive(yact, FALSE);
     }
 
     g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
@@ -904,6 +912,15 @@ sp_node_toolbox_coord_changed(gpointer /*shape_editor*/, GObject *tbl)
 static void
 sp_node_path_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name)
 {
+    SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
+
+    UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
+    SPUnit const *unit = tracker->getActiveUnit();
+
+    if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
+        prefs_set_double_attribute("tools.nodes", value_name, sp_units_get_pixels(adj->value, *unit));
+    }
+
     // quit if run by the attr_changed listener
     if (g_object_get_data( tbl, "freeze" )) {
         return;
@@ -914,11 +931,12 @@ sp_node_path_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_
 
     ShapeEditor *shape_editor = get_current_shape_editor();
     if (shape_editor && shape_editor->has_nodepath()) {
+        double val = sp_units_get_pixels(gtk_adjustment_get_value(adj), *unit);
         if (!strcmp(value_name, "x")) {
-            sp_node_selected_move_absolute(shape_editor->get_nodepath(), gtk_adjustment_get_value(adj), NR::X);
+            sp_node_selected_move_absolute(shape_editor->get_nodepath(), val, NR::X);
         }
         if (!strcmp(value_name, "y")) {
-            sp_node_selected_move_absolute(shape_editor->get_nodepath(), gtk_adjustment_get_value(adj), NR::Y);
+            sp_node_selected_move_absolute(shape_editor->get_nodepath(), val, NR::Y);
         }
     }
 
@@ -943,6 +961,10 @@ sp_node_path_y_value_changed(GtkAdjustment *adj, GObject *tbl)
 
 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
 {
+    UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
+    tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
+    g_object_set_data( holder, "tracker", tracker );
+
     {
         InkAction* inky = ink_action_new( "NodeInsertAction",
                                           _("Insert node"),
@@ -1067,6 +1089,16 @@ static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions
         gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.nodes", "show_handles", 1 ) );
     }
 
+    {
+        InkAction* inky = ink_action_new( "EditNextLPEParameterAction",
+                                          _("Next Path Effect Parameter"),
+                                          _("Show next Path Effect parameter for editing"),
+                                          "edit_next_parameter",
+                                          Inkscape::ICON_SIZE_DECORATION );
+        g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_nextLPEparam), desktop );
+        gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
+    }
+
     /* X coord of selected node(s) */
     {
         EgeAdjustmentAction* eact = 0;
@@ -1079,6 +1111,7 @@ static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions
                                          -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
                                          labels, values, G_N_ELEMENTS(labels),
                                          sp_node_path_x_value_changed );
+        tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
         g_object_set_data( holder, "nodes_x_action", eact );
         gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
@@ -1096,11 +1129,18 @@ static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions
                                          -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
                                          labels, values, G_N_ELEMENTS(labels),
                                          sp_node_path_y_value_changed );
+        tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
         g_object_set_data( holder, "nodes_y_action", eact );
         gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
     }
 
+    // add the units menu
+    {
+        GtkAction* act = tracker->createAction( "NodeUnitsAction", _("Units"), ("") );
+        gtk_action_group_add_action( mainActions, act );
+    }
+
     sigc::connection *connection = new sigc::connection (
         desktop->connectToolSubselectionChanged(sigc::bind (sigc::ptr_fun(sp_node_toolbox_coord_changed), (GObject *)holder))
         );
@@ -1390,10 +1430,6 @@ void show_aux_toolbox(GtkWidget *toolbox_toplevel)
     }
     gtk_widget_show(toolbox);
 
-    // need to show the spacer, or the padding will be off
-    GtkWidget *spacer = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "top_spacer"));
-    gtk_widget_show(spacer);
-
     gtk_widget_show_all(shown_toolbox);
 }
 
@@ -1824,7 +1860,6 @@ static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions
     }
 
     {
-        //EgeAdjustmentAction* calligraphy_angle = 0;
         EgeAdjustmentAction* eact = 0;
         gchar const *flatsidedstr = prefs_get_string_attribute( "tools.shapes.star", "isflatsided" );
         bool isFlatSided = flatsidedstr ? (strcmp(flatsidedstr, "false") != 0) : true;
@@ -2294,277 +2329,356 @@ static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions
 //##       3D Box       ##
 //########################
 
-static void sp_3dbox_toggle_vp_changed (GtkToggleAction */*act*/, GObject *dataKludge, Box3D::Axis axis)
-{
-    SPDesktop *desktop = (SPDesktop *) g_object_get_data (dataKludge, "desktop");
-    SPDocument *document = sp_desktop_document (desktop);
-    Box3D::Perspective3D *persp = document->current_perspective;
+// normalize angle so that it lies in the interval [0,360]
+static double box3d_normalize_angle (double a) {
+    double angle = a + ((int) (a/360.0))*360;
+    if (angle < 0) {
+        angle += 360.0;
+    }
+    return angle;
+}
 
-    g_return_if_fail (is_single_axis_direction (axis));
-    g_return_if_fail (persp);
+static void
+box3d_set_button_and_adjustment(Persp3D *persp, Proj::Axis axis,
+                                GtkAdjustment *adj, GtkAction *act, GtkToggleAction *tact) {
+    // TODO: Take all selected perspectives into account but don't touch the state button if not all of them
+    //       have the same state (otherwise a call to box3d_vp_z_state_changed() is triggered and the states
+    //       are reset).
+    bool is_infinite = !persp3d_VP_is_finite(persp, axis);
+
+    if (is_infinite) {
+        gtk_toggle_action_set_active(tact, TRUE);
+        gtk_action_set_sensitive(act, TRUE);
+
+        double angle = persp3d_get_infinite_angle(persp, axis);
+        if (angle != NR_HUGE) { // FIXME: We should catch this error earlier (don't show the spinbutton at all)
+            gtk_adjustment_set_value(adj, box3d_normalize_angle(angle));
+        }
+    } else {
+        gtk_toggle_action_set_active(tact, FALSE);
+        gtk_action_set_sensitive(act, FALSE);
+    }
+}
 
-    persp->toggle_boxes (axis);
+static void
+box3d_resync_toolbar(Inkscape::XML::Node *persp_repr, GObject *data) {
+    if (!persp_repr) {
+        g_print ("No perspective given to box3d_resync_toolbar().\n");
+        return;
+    }
 
-    gchar *str;
-    switch (axis) {
-        case Box3D::X:
-            str = g_strdup ("box3d_angle_x_action");
-            break;
-        case Box3D::Y:
-            str = g_strdup ("box3d_angle_y_action");
-            break;
-        case Box3D::Z:
-            str = g_strdup ("box3d_angle_z_action");
-            break;
-        default:
-            return;
+    GtkWidget *tbl = GTK_WIDGET(data);
+    GtkAdjustment *adj = 0;
+    GtkAction *act = 0;
+    GtkToggleAction *tact = 0;
+    Persp3D *persp = persp3d_get_from_repr(persp_repr);
+    {
+        adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "box3d_angle_x"));
+        act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_x_action"));
+        tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_x_state_action"))->action;
+
+        box3d_set_button_and_adjustment(persp, Proj::X, adj, act, tact);
     }
-    GtkAction* angle_action = GTK_ACTION (g_object_get_data (dataKludge, str));
-    if (angle_action) {
-        gtk_action_set_sensitive (angle_action, !persp->get_vanishing_point (axis)->is_finite() );
+    {
+        adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "box3d_angle_y"));
+        act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_y_action"));
+        tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_y_state_action"))->action;
+
+        box3d_set_button_and_adjustment(persp, Proj::Y, adj, act, tact);
     }
+    {
+        adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "box3d_angle_z"));
+        act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_z_action"));
+        tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_z_state_action"))->action;
 
-    // FIXME: Given how it is realized in the other tools, this is probably not the right way to do it,
-    //        but without the if construct, we get continuous segfaults. Needs further investigation.
-    if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
-        sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_3DBOX,
-                         _("3D Box: Change perspective"));
+        box3d_set_button_and_adjustment(persp, Proj::Z, adj, act, tact);
     }
 }
 
-static void sp_3dbox_toggle_vp_x_changed(GtkToggleAction *act, GObject *dataKludge)
+static void box3d_persp_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
+                                                  gchar const */*old_value*/, gchar const */*new_value*/,
+                                                  bool /*is_interactive*/, gpointer data)
 {
-    sp_3dbox_toggle_vp_changed (act, dataKludge, Box3D::X);
-}
+    GtkWidget *tbl = GTK_WIDGET(data);
 
-static void sp_3dbox_toggle_vp_y_changed(GtkToggleAction *act, GObject *dataKludge)
-{
-    sp_3dbox_toggle_vp_changed (act, dataKludge, Box3D::Y);
+    // quit if run by the attr_changed listener
+    // note: it used to work without the differently called freeze_ attributes (here and in
+    //       box3d_angle_value_changed()) but I now it doesn't so I'm leaving them in for now
+    if (g_object_get_data(G_OBJECT(tbl), "freeze_angle")) {
+        return;
+    }
+
+    // set freeze so that it can be caught in box3d_angle_z_value_changed() (to avoid calling
+    // sp_document_maybe_done() when the document is undo insensitive)
+    g_object_set_data(G_OBJECT(tbl), "freeze_attr", GINT_TO_POINTER(TRUE));
+
+    // TODO: Only update the appropriate part of the toolbar
+//    if (!strcmp(name, "inkscape:vp_z")) {
+        box3d_resync_toolbar(repr, G_OBJECT(tbl));
+//    }
+
+    Persp3D *persp = persp3d_get_from_repr(repr);
+    persp3d_update_box_reprs(persp);
+
+    g_object_set_data(G_OBJECT(tbl), "freeze_attr", GINT_TO_POINTER(FALSE));
 }
 
-static void sp_3dbox_toggle_vp_z_changed(GtkToggleAction *act, GObject *dataKludge)
+static Inkscape::XML::NodeEventVector box3d_persp_tb_repr_events =
 {
-    sp_3dbox_toggle_vp_changed (act, dataKludge, Box3D::Z);
-}
+    NULL, /* child_added */
+    NULL, /* child_removed */
+    box3d_persp_tb_event_attr_changed,
+    NULL, /* content_changed */
+    NULL  /* order_changed */
+};
 
-static void sp_3dbox_vp_angle_changed(GtkAdjustment *adj, GObject *dataKludge, Box3D::Axis axis )
+/**
+ *  \param selection Should not be NULL.
+ */
+// FIXME: This should rather be put into persp3d-reference.cpp or something similar so that it reacts upon each
+//        Change of the perspective, and not of the current selection (but how to refer to the toolbar then?)
+static void
+box3d_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
 {
-    SPDesktop *desktop = (SPDesktop *) g_object_get_data(dataKludge, "desktop");
-    Box3D::Perspective3D *persp = sp_desktop_document (desktop)->current_perspective;
+    // Here the following should be done: If all selected boxes have finite VPs in a certain direction,
+    // disable the angle entry fields for this direction (otherwise entering a value in them should only
+    // update the perspectives with infinite VPs and leave the other ones untouched).
 
-    if (persp) {
-        double angle = adj->value * M_PI/180;
-        persp->set_infinite_direction (axis, NR::Point (cos (angle), sin (angle)));
+    Inkscape::XML::Node *persp_repr = NULL;
+    purge_repr_listener(tbl, tbl);
 
-        // FIXME: See comment above; without the if construct we get segfaults during undo.
-        if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
-            sp_document_maybe_done(sp_desktop_document(desktop), "perspectiveangle", SP_VERB_CONTEXT_3DBOX,
-                             _("3D Box: Change perspective"));
+    SPItem *item = selection->singleItem();
+    if (item && SP_IS_BOX3D(item)) {
+        // FIXME: Also deal with multiple selected boxes
+        SPBox3D *box = SP_BOX3D(item);
+        Persp3D *persp = box3d_get_perspective(box);
+        persp_repr = SP_OBJECT_REPR(persp);
+        if (persp_repr) {
+            g_object_set_data(tbl, "repr", persp_repr);
+            Inkscape::GC::anchor(persp_repr);
+            sp_repr_add_listener(persp_repr, &box3d_persp_tb_repr_events, tbl);
+            sp_repr_synthesize_events(persp_repr, &box3d_persp_tb_repr_events, tbl);
         }
+
+        inkscape_active_document()->current_persp3d = persp3d_get_from_repr(persp_repr);
+        prefs_set_string_attribute("tools.shapes.3dbox", "persp", persp_repr->attribute("id"));
+    
+        box3d_resync_toolbar(persp_repr, tbl);
     }
-    //g_object_set_data(G_OBJECT(dataKludge), "freeze", GINT_TO_POINTER(FALSE));
 }
 
-static void sp_3dbox_vpx_angle_changed(GtkAdjustment *adj, GObject *dataKludge )
+static void
+box3d_angle_value_changed(GtkAdjustment *adj, GObject *dataKludge, Proj::Axis axis)
 {
-    sp_3dbox_vp_angle_changed (adj, dataKludge, Box3D::X);
+    SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
+    SPDocument *document = sp_desktop_document(desktop);
+
+    // quit if run by the attr_changed listener
+    // note: it used to work without the differently called freeze_ attributes (here and in
+    //       box3d_persp_tb_event_attr_changed()) but I now it doesn't so I'm leaving them in for now
+    if (g_object_get_data( dataKludge, "freeze_attr" )) {
+        return;
+    }
+
+    // in turn, prevent listener from responding
+    g_object_set_data(dataKludge, "freeze_angle", GINT_TO_POINTER(TRUE));
+
+    //Persp3D *persp = document->current_persp3d;
+    std::set<Persp3D *> sel_persps = persp3d_currently_selected_persps (inkscape_active_event_context());
+    if (sel_persps.empty()) {
+        // this can happen when the document is created; we silently ignore it
+        return;
+    }
+    Persp3D *persp = *(sel_persps.begin());
+
+    persp->tmat.set_infinite_direction (axis, adj->value);
+    SP_OBJECT(persp)->updateRepr();
+
+    // TODO: use the correct axis here, too
+    sp_document_maybe_done(document, "perspangle", SP_VERB_CONTEXT_3DBOX, _("3D Box: Change perspective (angle of infinite axis)"));
+
+    g_object_set_data( dataKludge, "freeze_angle", GINT_TO_POINTER(FALSE) );
 }
 
-static void sp_3dbox_vpy_angle_changed(GtkAdjustment *adj, GObject *dataKludge )
+
+static void
+box3d_angle_x_value_changed(GtkAdjustment *adj, GObject *dataKludge)
 {
-    sp_3dbox_vp_angle_changed (adj, dataKludge, Box3D::Y);
+    box3d_angle_value_changed(adj, dataKludge, Proj::X);
 }
 
-static void sp_3dbox_vpz_angle_changed(GtkAdjustment *adj, GObject *dataKludge )
+static void
+box3d_angle_y_value_changed(GtkAdjustment *adj, GObject *dataKludge)
 {
-    sp_3dbox_vp_angle_changed (adj, dataKludge, Box3D::Z);
+    box3d_angle_value_changed(adj, dataKludge, Proj::Y);
 }
 
-// normalize angle so that it lies in the interval [0,360]
-static double sp_3dbox_normalize_angle (double a) {
-    double angle = a + ((int) (a/360.0))*360;
-    if (angle < 0) {
-        angle += 360.0;
-    }
-    return angle;
+static void
+box3d_angle_z_value_changed(GtkAdjustment *adj, GObject *dataKludge)
+{
+    box3d_angle_value_changed(adj, dataKludge, Proj::Z);
 }
 
-static void sp_3dbox_tb_event_attr_changed(Inkscape::XML::Node */*repr*/, gchar const *name,
-                                           gchar const */*old_value*/, gchar const */*new_value*/,
-                                           bool /*is_interactive*/, gpointer data)
-{
-    GtkWidget *tbl = GTK_WIDGET(data);
 
-    // FIXME: if we check for "freeze" as in other tools, no action is performed at all ...
-    /***
-    // quit if run by the _changed callbacks
-    if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
+static void box3d_vp_state_changed( GtkToggleAction *act, GtkAction *box3d_angle, Proj::Axis axis )
+{
+    // TODO: Take all selected perspectives into account
+    std::set<Persp3D *> sel_persps = persp3d_currently_selected_persps (inkscape_active_event_context());
+    if (sel_persps.empty()) {
+        // this can happen when the document is created; we silently ignore it
         return;
     }
+    Persp3D *persp = *(sel_persps.begin());
 
-    // in turn, prevent callbacks from responding
-    g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
-    ***/
-
-    if (!strcmp(name, "inkscape:perspective")) {
-        GtkAdjustment *adj = 0;
-        double angle;
-        SPDesktop *desktop = (SPDesktop *) g_object_get_data(G_OBJECT(tbl), "desktop");
-        Box3D::Perspective3D *persp = sp_desktop_document (desktop)->current_perspective;
-
-        adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "dir_vp_x"));
-        angle = sp_3dbox_normalize_angle (persp->get_vanishing_point (Box3D::X)->get_angle());
-        gtk_adjustment_set_value(adj, angle);
-
-        adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "dir_vp_y"));
-        angle = sp_3dbox_normalize_angle (persp->get_vanishing_point (Box3D::Y)->get_angle());
-        gtk_adjustment_set_value(adj, angle);
-
-        adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "dir_vp_z"));
-        angle = sp_3dbox_normalize_angle (persp->get_vanishing_point (Box3D::Z)->get_angle());
-        gtk_adjustment_set_value(adj, angle);
-    }
+    bool set_infinite = gtk_toggle_action_get_active(act);
+    persp3d_set_VP_state (persp, axis, set_infinite ? Proj::VP_INFINITE : Proj::VP_FINITE);
 }
 
-static Inkscape::XML::NodeEventVector sp_3dbox_tb_repr_events =
+static void box3d_vp_x_state_changed( GtkToggleAction *act, GtkAction *box3d_angle )
 {
-    NULL, /* child_added */
-    NULL, /* child_removed */
-    sp_3dbox_tb_event_attr_changed,
-    NULL, /* content_changed */
-    NULL  /* order_changed */
-};
+    box3d_vp_state_changed(act, box3d_angle, Proj::X);
+}
 
-/**
- *  \param selection Should not be NULL.
- */
-static void
-sp_3dbox_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
+static void box3d_vp_y_state_changed( GtkToggleAction *act, GtkAction *box3d_angle )
 {
-    Inkscape::XML::Node *repr = NULL;
-    purge_repr_listener(tbl, tbl);
+    box3d_vp_state_changed(act, box3d_angle, Proj::Y);
+}
 
-    SPItem *item = selection->singleItem();
-    if (item) {
-        repr = SP_OBJECT_REPR(item);
-        if (repr) {
-            g_object_set_data(tbl, "repr", repr);
-            Inkscape::GC::anchor(repr);
-            sp_repr_add_listener(repr, &sp_3dbox_tb_repr_events, tbl);
-            sp_repr_synthesize_events(repr, &sp_3dbox_tb_repr_events, tbl);
-        }
-    }
+static void box3d_vp_z_state_changed( GtkToggleAction *act, GtkAction *box3d_angle )
+{
+    box3d_vp_state_changed(act, box3d_angle, Proj::Z);
 }
 
-static void sp_3dbox_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
+static void box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
 {
     EgeAdjustmentAction* eact = 0;
     SPDocument *document = sp_desktop_document (desktop);
-    Box3D::Perspective3D *persp = document->current_perspective;
-    bool toggled = false;
-
-    /* angle of VP in X direction */
-    eact = create_adjustment_action("3DBoxPosAngleXAction",
-                                    _("Angle X"), _("Angle X:"), _("Angle of infinite vanishing point in X direction"),
-                                    "tools.shapes.3dbox", "dir_vp_x", persp->get_vanishing_point (Box3D::X)->get_angle(),
-                                    GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
-                                    0.0, 360.0, 1.0, 10.0,
-                                    0, 0, 0, // labels, values, G_N_ELEMENTS(labels),
-                                    sp_3dbox_vpx_angle_changed,
-                                    0.1, 1);
-    gtk_action_group_add_action(mainActions, GTK_ACTION(eact));
-    g_object_set_data(holder, "box3d_angle_x_action", eact);
-    if (!persp->get_vanishing_point (Box3D::X)->is_finite()) {
-        gtk_action_set_sensitive(GTK_ACTION(eact), TRUE);
+    Persp3D *persp = document->current_persp3d;
+
+    EgeAdjustmentAction* box3d_angle_x = 0;
+    EgeAdjustmentAction* box3d_angle_y = 0;
+    EgeAdjustmentAction* box3d_angle_z = 0;
+
+    /* Angle X */
+    {
+        gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 };
+        gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
+        eact = create_adjustment_action( "3DBoxAngleXAction",
+                                         _("Angle in X direction"), _("Angle X:"),
+                                         // Translators: PL is short for 'perspective line'
+                                         _("Angle of PLs in X direction"),
+                                         "tools.shapes.3dbox", "box3d_angle_x", 30,
+                                         GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-box3d",
+                                         -360.0, 360.0, 1.0, 10.0,
+                                         labels, values, G_N_ELEMENTS(labels),
+                                         box3d_angle_x_value_changed );
+        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
+        g_object_set_data( holder, "box3d_angle_x_action", eact );
+        box3d_angle_x = eact;
+    }
+
+    if (!persp3d_VP_is_finite(persp, Proj::X)) {
+        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
     } else {
-        gtk_action_set_sensitive(GTK_ACTION(eact), FALSE);
+        gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
     }
 
-    /* toggle VP in X direction */
+
+    /* VP X state */
     {
-    InkToggleAction* act = ink_toggle_action_new("3DBoxVPXAction",
-                                                  _("Toggle VP in X direction"),
-                                                  _("Toggle VP in X direction between 'finite' and 'infinite' (=parallel)"),
-                                                  "toggle_vp_x",
-                                                  Inkscape::ICON_SIZE_DECORATION);
-    gtk_action_group_add_action(mainActions, GTK_ACTION(act));
-    if (persp) {
-        toggled = !persp->get_vanishing_point(Box3D::X)->is_finite();
-    }
-    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), toggled);
-    /* we connect the signal after setting the state to avoid switching the state again */
-    g_signal_connect_after(G_OBJECT(act), "toggled", G_CALLBACK(sp_3dbox_toggle_vp_x_changed), holder);
-    }
-
-    /* angle of VP in Y direction */
-    eact = create_adjustment_action("3DBoxPosAngleYAction",
-                                    _("Angle Y"), _("Angle Y:"), _("Angle of infinite vanishing point in Y direction"),
-                                    "tools.shapes.3dbox", "dir_vp_y", persp->get_vanishing_point (Box3D::Y)->get_angle(),
-                                    GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
-                                    0.0, 360.0, 1.0, 10.0,
-                                    0, 0, 0, // labels, values, G_N_ELEMENTS(labels),
-                                    sp_3dbox_vpy_angle_changed,
-                                    0.1, 1);
-    gtk_action_group_add_action(mainActions, GTK_ACTION(eact));
-    g_object_set_data(holder, "box3d_angle_y_action", eact);
-    if (!persp->get_vanishing_point (Box3D::Y)->is_finite()) {
-        gtk_action_set_sensitive(GTK_ACTION(eact), TRUE);
-    } else {
-        gtk_action_set_sensitive(GTK_ACTION(eact), FALSE);
+        InkToggleAction* act = ink_toggle_action_new( "3DBoxVPXStateAction",
+                                                      // Translators: VP is short for 'vanishing point'
+                                                      _("State of VP in X direction"),
+                                                      _("Toggle VP in X direction between 'finite' and 'infinite' (=parallel)"),
+                                                      "toggle_vp_x",
+                                                      Inkscape::ICON_SIZE_DECORATION );
+        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
+        g_object_set_data( holder, "box3d_vp_x_state_action", act );
+        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_x_state_changed), box3d_angle_x );
+        gtk_action_set_sensitive( GTK_ACTION(box3d_angle_x), !prefs_get_int_attribute( "tools.shapes.3dbox", "vp_x_state", 1 ) );
+        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.shapes.3dbox", "vp_x_state", 1 ) );
     }
 
-    /* toggle VP in Y direction */
+    /* Angle Y */
     {
-    InkToggleAction* act = ink_toggle_action_new("3DBoxVPYAction",
-                                                 _("Toggle VP in Y direction"),
-                                                 _("Toggle VP in Y direction between 'finite' and 'infinite' (=parallel)"),
-                                                 "toggle_vp_y",
-                                                 Inkscape::ICON_SIZE_DECORATION);
-    gtk_action_group_add_action(mainActions, GTK_ACTION(act));
-    if (persp) {
-        toggled = !persp->get_vanishing_point(Box3D::Y)->is_finite();
-    }
-    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), toggled);
-    /* we connect the signal after setting the state to avoid switching the state again */
-    g_signal_connect_after(G_OBJECT(act), "toggled", G_CALLBACK(sp_3dbox_toggle_vp_y_changed), holder);
-    }
-
-    /* angle of VP in Z direction */
-    eact = create_adjustment_action("3DBoxPosAngleZAction",
-                                    _("Angle Z"), _("Angle Z:"), _("Angle of infinite vanishing point in Z direction"),
-                                    "tools.shapes.3dbox", "dir_vp_z", persp->get_vanishing_point (Box3D::Z)->get_angle(),
-                                    GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
-                                     0.0, 360.0, 1.0, 10.0,
-                                    0, 0, 0, // labels, values, G_N_ELEMENTS(labels),
-                                    sp_3dbox_vpz_angle_changed,
-                                    0.1, 1);
-
-    gtk_action_group_add_action(mainActions, GTK_ACTION(eact));
-    g_object_set_data(holder, "box3d_angle_z_action", eact);
-    if (!persp->get_vanishing_point (Box3D::Z)->is_finite()) {
-        gtk_action_set_sensitive(GTK_ACTION(eact), TRUE);
+        gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 };
+        gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
+        eact = create_adjustment_action( "3DBoxAngleYAction",
+                                         _("Angle in Y direction"), _("Angle Y:"),
+                                         // Translators: PL is short for 'perspective line'
+                                         _("Angle of PLs in Y direction"),
+                                         "tools.shapes.3dbox", "box3d_angle_y", 30,
+                                         GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
+                                         -360.0, 360.0, 1.0, 10.0,
+                                         labels, values, G_N_ELEMENTS(labels),
+                                         box3d_angle_y_value_changed );
+        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
+        g_object_set_data( holder, "box3d_angle_y_action", eact );
+        box3d_angle_y = eact;
+    }
+
+    if (!persp3d_VP_is_finite(persp, Proj::Y)) {
+        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
     } else {
-        gtk_action_set_sensitive(GTK_ACTION(eact), FALSE);
+        gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
     }
 
-    /* toggle VP in Z direction */
+    /* VP Y state */
     {
-    InkToggleAction* act = ink_toggle_action_new("3DBoxVPZAction",
-                                                 _("Toggle VP in Z direction"),
-                                                 _("Toggle VP in Z direction between 'finite' and 'infinite' (=parallel)"),
-                                                 "toggle_vp_z",
-                                                 Inkscape::ICON_SIZE_DECORATION);
-    gtk_action_group_add_action(mainActions, GTK_ACTION(act));
-    if (persp) {
-        toggled = !persp->get_vanishing_point(Box3D::Z)->is_finite();
+        InkToggleAction* act = ink_toggle_action_new( "3DBoxVPYStateAction",
+                                                      // Translators: VP is short for 'vanishing point'
+                                                      _("State of VP in Y direction"),
+                                                      _("Toggle VP in Y direction between 'finite' and 'infinite' (=parallel)"),
+                                                      "toggle_vp_y",
+                                                      Inkscape::ICON_SIZE_DECORATION );
+        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
+        g_object_set_data( holder, "box3d_vp_y_state_action", act );
+        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_y_state_changed), box3d_angle_y );
+        gtk_action_set_sensitive( GTK_ACTION(box3d_angle_y), !prefs_get_int_attribute( "tools.shapes.3dbox", "vp_y_state", 1 ) );
+        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.shapes.3dbox", "vp_y_state", 1 ) );
     }
-    /* we connect the signal after setting the state to avoid switching the state again */
-    gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), toggled);
-    g_signal_connect_after(G_OBJECT(act), "toggled", G_CALLBACK(sp_3dbox_toggle_vp_z_changed), holder);
+
+    /* Angle Z */
+    {
+        gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 };
+        gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
+        eact = create_adjustment_action( "3DBoxAngleZAction",
+                                         _("Angle in Z direction"), _("Angle Z:"),
+                                         // Translators: PL is short for 'perspective line'
+                                         _("Angle of PLs in Z direction"),
+                                         "tools.shapes.3dbox", "box3d_angle_z", 30,
+                                         GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
+                                         -360.0, 360.0, 1.0, 10.0,
+                                         labels, values, G_N_ELEMENTS(labels),
+                                         box3d_angle_z_value_changed );
+        gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
+        g_object_set_data( holder, "box3d_angle_z_action", eact );
+        box3d_angle_z = eact;
+    }
+
+    if (!persp3d_VP_is_finite(persp, Proj::Z)) {
+        gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
+    } else {
+        gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
+    }
+
+    /* VP Z state */
+    {
+        InkToggleAction* act = ink_toggle_action_new( "3DBoxVPZStateAction",
+                                                      // Translators: VP is short for 'vanishing point'
+                                                      _("State of VP in Z direction"),
+                                                      _("Toggle VP in Z direction between 'finite' and 'infinite' (=parallel)"),
+                                                      "toggle_vp_z",
+                                                      Inkscape::ICON_SIZE_DECORATION );
+        gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
+        g_object_set_data( holder, "box3d_vp_z_state_action", act );
+        g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_z_state_changed), box3d_angle_z );
+        gtk_action_set_sensitive( GTK_ACTION(box3d_angle_z), !prefs_get_int_attribute( "tools.shapes.3dbox", "vp_z_state", 1 ) );
+        gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.shapes.3dbox", "vp_z_state", 1 ) );
     }
 
     sigc::connection *connection = new sigc::connection(
-        sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_3dbox_toolbox_selection_changed), (GObject *)holder))
+        sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(box3d_toolbox_selection_changed), (GObject *)holder))
        );
     g_signal_connect(holder, "destroy", G_CALLBACK(delete_connection), connection);
     g_signal_connect(holder, "destroy", G_CALLBACK(purge_repr_listener), holder);
@@ -3842,6 +3956,9 @@ 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_family =
         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
@@ -3875,15 +3992,27 @@ sp_text_toolbox_selection_changed (Inkscape::Selection */*selection*/, GObject *
             GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
             gtk_entry_set_text (GTK_ENTRY (entry), "");
 
-        } else if (query->text->font_family.value) {
+        } else if (query->text->font_specification.value || query->text->font_family.value) {
 
             GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
-            gtk_entry_set_text (GTK_ENTRY (entry), query->text->font_family.value);
+            
+            // Get the font that corresponds 
+            Glib::ustring familyName;
+            
+            font_instance * font = font_factory::Default()->FaceFromStyle(query);
+            if (font) {
+                familyName = font_factory::Default()->GetUIFamilyString(font->descr);
+                font->Unref();
+                font = NULL;
+            }
+            
+            gtk_entry_set_text (GTK_ENTRY (entry), familyName.c_str());
 
             Gtk::TreePath path;
             try {
-                path = Inkscape::FontLister::get_instance()->get_row_for_font (query->text->font_family.value);
+                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());
                 return;
             }
 
@@ -4036,14 +4165,58 @@ sp_text_toolbox_family_changed (GtkTreeSelection    *selection,
     SPStyle *query =
         sp_style_new (SP_ACTIVE_DOCUMENT);
 
-    int result_numbers =
-        sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
-
+    int result_fontspec =
+        sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
+    
+    font_instance * fontFromStyle = font_factory::Default()->FaceFromStyle(query);
+    
     SPCSSAttr *css = sp_repr_css_attr_new ();
-    sp_repr_css_set_property (css, "font-family", family);
+    
+    
+    // First try to get the font spec from the stored value
+    Glib::ustring fontSpec = query->text->font_specification.set ?  query->text->font_specification.value : "";
+    
+    if (fontSpec.empty()) {
+        // Construct a new font specification if it does not yet exist
+        font_instance * fontFromStyle = font_factory::Default()->FaceFromStyle(query);
+        fontSpec = font_factory::Default()->ConstructFontSpecification(fontFromStyle);
+        fontFromStyle->Unref();
+    }
+    
+    if (!fontSpec.empty()) {
+        Glib::ustring newFontSpec = font_factory::Default()->ReplaceFontSpecificationFamily(fontSpec, family);
+        if (!newFontSpec.empty() && fontSpec != newFontSpec) {
+            font_instance *font = font_factory::Default()->FaceFromFontSpecification(newFontSpec.c_str());
+            if (font) {
+                sp_repr_css_set_property (css, "-inkscape-font-specification", newFontSpec.c_str());
+                
+                // Set all the these just in case they were altered when finding the best
+                // match for the new family and old style...
+                
+                gchar c[256];
+                
+                font->Family(c, 256);
+                sp_repr_css_set_property (css, "font-family", c);
+                
+                font->Attribute( "weight", c, 256);
+                sp_repr_css_set_property (css, "font-weight", c);
+                
+                font->Attribute("style", c, 256);
+                sp_repr_css_set_property (css, "font-style", c);
+                
+                font->Attribute("stretch", c, 256);
+                sp_repr_css_set_property (css, "font-stretch", c);
+                
+                font->Attribute("variant", c, 256);
+                sp_repr_css_set_property (css, "font-variant", c);
+                
+                font->Unref();
+            }
+        }
+    }
 
     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
-    if (result_numbers == QUERY_STYLE_NOTHING)
+    if (result_fontspec == QUERY_STYLE_NOTHING)
     {
         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
         sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace trough a verb
@@ -4158,29 +4331,64 @@ sp_text_toolbox_style_toggled (GtkToggleButton  *button,
     int          prop       = GPOINTER_TO_INT(data);
     bool         active     = gtk_toggle_button_get_active (button);
 
+    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_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 = "";
+    
+    if (fontSpec.empty()) {
+        // Construct a new font specification if it does not yet exist
+        font_instance * fontFromStyle = font_factory::Default()->FaceFromStyle(query);
+        fontSpec = font_factory::Default()->ConstructFontSpecification(fontFromStyle);
+        fontFromStyle->Unref();
+    }
+    
     switch (prop)
     {
         case 0:
         {
-            sp_repr_css_set_property (css, "font-weight", active ? "bold" : "normal" );
+            if (!fontSpec.empty()) {
+                newFontSpec = font_factory::Default()->FontSpecificationSetBold(fontSpec, active);
+            }
+            if (fontSpec != newFontSpec) {
+                // Don't even set the bold if the font didn't exist on the system
+                sp_repr_css_set_property (css, "font-weight", active ? "bold" : "normal" );
+            }
             break;
         }
 
         case 1:
         {
-            sp_repr_css_set_property (css, "font-style", active ? "italic" : "normal");
+            if (!fontSpec.empty()) {
+                newFontSpec = font_factory::Default()->FontSpecificationSetItalic(fontSpec, active);
+            }
+            if (fontSpec != newFontSpec) {
+                // Don't even set the italic if the font didn't exist on the system
+                sp_repr_css_set_property (css, "font-style", active ? "italic" : "normal");
+            }
             break;
         }
     }
 
-    SPStyle *query =
-        sp_style_new (SP_ACTIVE_DOCUMENT);
-    int result_numbers =
-        sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
+    if (!newFontSpec.empty()) {
+        sp_repr_css_set_property (css, "-inkscape-font-specification", newFontSpec.c_str()); 
+    }
 
     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
-    if (result_numbers == QUERY_STYLE_NOTHING)
+    if (result_fontspec == QUERY_STYLE_NOTHING)
     {
         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
     }
@@ -4306,16 +4514,7 @@ sp_text_toolbox_size_changed  (GtkComboBox *cbox,
 
     if (g_object_get_data (tbl, "size-block")) return;
 
-#if GTK_CHECK_VERSION(2,6,0)
     char *text = gtk_combo_box_get_active_text (cbox);
-#else // GTK_CHECK_VERSION(2,6,0)
-    GtkTreeModel *model = gtk_combo_box_get_model (cbox);
-    GtkTreeIter iter;
-    char *text = NULL;
-
-    if (gtk_combo_box_get_active_iter (cbox, &iter) && model)
-        gtk_tree_model_get (model, &iter, 0, &text, -1);
-#endif // GTK_CHECK_VERSION(2,6,0)
 
     SPCSSAttr *css = sp_repr_css_attr_new ();
     sp_repr_css_set_property (css, "font-size", text);
@@ -4482,9 +4681,7 @@ sp_text_toolbox_new (SPDesktop *desktop)
 
     gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (Glib::unwrap(store)));
     gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
-#if GTK_CHECK_VERSION(2,6,0)
     gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (treeview), TRUE);
-#endif // GTK_CHECK_VERSION(2,6,0)
 
     //gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
 
@@ -4679,168 +4876,6 @@ sp_text_toolbox_new (SPDesktop *desktop)
     Inkscape::ConnectionPool::connect_destroy (G_OBJECT (tbl), pool);
 
 
-#if 0
-    // horizontal
-    {
-        GtkWidget *px= sp_icon_new(Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR);
-        GtkWidget *b = group = gtk_radio_button_new (NULL);
-        gtk_container_add (GTK_CONTAINER (b), px);
-        gtk_tooltips_set_tip (tt, b, _("Horizontal text"), NULL);
-        gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
-        gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
-        gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
-    }
-
-    // vertical
-    {
-        GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB);
-        GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
-        gtk_container_add (GTK_CONTAINER (b), px);
-        gtk_tooltips_set_tip (tt, b, _("Vertical text"), NULL);
-        gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
-        gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
-        gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
-    }
-
-    aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
-
-    // letter spacing
-    {
-        {
-            GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LETTER_SPACING);
-            GtkWidget *hb = gtk_hbox_new(FALSE, 1);
-            gtk_container_add (GTK_CONTAINER (hb), image);
-            gtk_widget_show(image);
-            gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
-        }
-
-        {
-            GtkWidget *hb = sp_tb_spinbutton((""), _("Spacing between letters"),
-                                             "tools.text", "letter_spacing", 0.0,
-                                             us, tbl, FALSE, NULL,
-                                             -1000.0, 1000.0, 0.1, 0.1,
-                                             sp_text_letter_changed, 0.1, 1);
-            gtk_widget_set_size_request (hb, 45, 6);
-            gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
-        }
-    }
-
-    // line spacing
-    {
-        {
-            GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LINE_SPACING);
-            GtkWidget *hb = gtk_hbox_new(FALSE, 1);
-            gtk_container_add (GTK_CONTAINER (hb), image);
-            gtk_widget_show(image);
-            gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
-        }
-
-        {
-            GtkWidget *hb = sp_tb_spinbutton((""), _("Spacing between lines"),
-                                             "tools.text", "line_spacing", 0,
-                                             us, tbl, FALSE, NULL,
-                                             -1000.0, 1000.0, 0.1, 0.1,
-                                             sp_text_line_changed, 0.1, 1);
-            gtk_widget_set_size_request (hb, 45, 0);
-            gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 3);
-        }
-    }
-
-    {
-        // horizontal kerning/vertical kerning units menu: create
-        GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
-        sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
-        sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
-
-        aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
-
-        // horizontal kerning
-        {
-            {
-                GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_HORZ_KERN);
-                GtkWidget *hb = gtk_hbox_new(FALSE, 1);
-                gtk_container_add (GTK_CONTAINER (hb), image);
-                gtk_widget_show(image);
-                gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
-            }
-
-            {
-                GtkWidget *hb = sp_tb_spinbutton((""), _("Horizontal kerning"),
-                                                 "tools.text", "horizontal_kerning", 0,
-                                                 us, tbl, FALSE, NULL,
-                                                 -100.00, 100.00, 0.01, 0.1,
-                                                 sp_text_horiz_kern_changed);
-                gtk_widget_set_size_request (hb, 45, 0);
-                gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
-            }
-        }
-
-        // vertical kerning
-        {
-            {
-                GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_VERT_KERN);
-                GtkWidget *hb = gtk_hbox_new(FALSE, 1);
-                gtk_container_add (GTK_CONTAINER (hb), image);
-                gtk_widget_show(image);
-                gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
-            }
-
-            {
-                GtkWidget *hb = sp_tb_spinbutton((""), _("Vertical kerning"),
-                                                 "tools.text", "vertical_kerning", 0,
-                                                 us, tbl, FALSE, NULL,
-                                                 -100.00, 100.00, 0.01, 0.1,
-                                                 sp_text_vert_kern_changed);
-                gtk_widget_set_size_request (hb, 45, 0);
-                gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 5);
-            }
-        }
-
-        // add the units menu
-        gtk_widget_show(us);
-        gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, 1);
-        gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
-    }
-
-    // letter rotation
-    aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
-    {
-        {
-            GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_ROTATION);
-            GtkWidget *hb = gtk_hbox_new(FALSE, 1);
-            gtk_container_add (GTK_CONTAINER (hb), image);
-            gtk_widget_show(image);
-            gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
-        }
-        {
-            GtkWidget *hb = sp_tb_spinbutton((""), _("Letter rotation"),
-                                             "tools.text", "letter_rotation", 0,
-                                             us, tbl, FALSE, NULL,
-                                             -180.0, 180.0, 0.1, 0.1,
-                                             sp_text_letter_rotation_changed, 0.1, 1);
-            gtk_widget_set_size_request (hb, 45, 0);
-            gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
-        }
-        // rotation degree label
-        {
-            GtkWidget *label = gtk_widget_new (GTK_TYPE_LABEL, "label", "\302\260", "xalign", 0.0, NULL);
-            gtk_box_pack_start(GTK_BOX(tbl), label, FALSE, FALSE, 0);
-        }
-    }
-
-    // Remove Manual Kerns
-    {
-        GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_REMOVE_KERNS);
-        GtkWidget *button = gtk_button_new ();
-        gtk_container_add (GTK_CONTAINER (button), px);
-        gtk_widget_show(button);
-        gtk_tooltips_set_tip (tt, button, _("Remove manual kerns"), NULL);
-        gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
-        gtk_widget_set_sensitive(button, TRUE);
-        gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
-    }
-#endif
-
     gtk_widget_show_all (tbl);
     return tbl;
 
@@ -5267,3 +5302,6 @@ static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* main
 */
 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
 
+
+
+