Code

Decent support for setting the direction of infinite VPs via the toolbar and partial...
authorcilix42 <cilix42@users.sourceforge.net>
Sat, 1 Sep 2007 23:36:14 +0000 (23:36 +0000)
committercilix42 <cilix42@users.sourceforge.net>
Sat, 1 Sep 2007 23:36:14 +0000 (23:36 +0000)
src/box3d.cpp
src/perspective3d.cpp
src/vanishing-point.cpp
src/vanishing-point.h
src/widgets/toolbox.cpp

index 1942ea3d66494438522e0eebb575b3f4cf37282e..e47aa73b38d2c6e8821663d119d314b15b0d3ecc 100644 (file)
@@ -234,7 +234,13 @@ sp_3dbox_update(SPObject *object, SPCtx *ctx, guint flags)
 {
     if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
         SP3DBox *box = SP_3DBOX(object);
-        sp_3dbox_link_to_existing_paths (box, SP_OBJECT_REPR(object));
+        Inkscape::XML::Node *repr = SP_OBJECT_REPR(object);
+        sp_3dbox_link_to_existing_paths (box, repr);
+        SP3DBoxContext *bc = SP_3DBOX_CONTEXT (inkscape_active_event_context());
+        bc->_vpdrag->updateDraggers();
+        // FIXME: Should we update the corners here, too? Maybe this is the reason why the handles
+        //        are off after an undo/redo! On the other hand, if we do so we get warnings about
+        //        updates occuring while other updats are in progress ...
     }
 
     /* Invoke parent method */
index 9321af35630ca2d8ac9fbfd096de09ba7d80f5e6..db4f564c7ec8a1d2c92ab8336fde798de0134054 100644 (file)
@@ -196,6 +196,11 @@ Perspective3D::set_infinite_direction (Box3D::Axis axis, NR::Point const dir)
     }
 
     get_vanishing_point (axis)->set_infinite_direction (dir);
+    for (GSList *i = this->boxes; i != NULL; i = i->next) {
+        sp_3dbox_reshape_after_VP_rotation (SP_3DBOX (i->data), axis);
+        sp_3dbox_set_z_orders_later_on (SP_3DBOX (i->data));
+    }
+    update_box_reprs();
 }
 
 void
@@ -207,11 +212,6 @@ Perspective3D::rotate (Box3D::Axis const axis, double const angle)
         a += angle;
         a *= M_PI/180;
         this->set_infinite_direction (axis, NR::Point (cos (a), sin (a)));
-        for (GSList *i = this->boxes; i != NULL; i = i->next) {
-            sp_3dbox_reshape_after_VP_rotation (SP_3DBOX (i->data), axis);
-            sp_3dbox_set_z_orders_later_on (SP_3DBOX (i->data));
-        }
-        update_box_reprs();
     }
 }
 
index 2426c9954ebb6bc9a770882f9ae3d5fe60de43fe..f5e98face576f62534739cc6834e4c7eb5710fdc 100644 (file)
@@ -270,6 +270,8 @@ vp_knot_grabbed_handler (SPKnot *knot, unsigned int state, gpointer data)
     VPDragger *dragger = (VPDragger *) data;
     VPDrag *drag = dragger->parent;
 
+    drag->dragging = true;
+
     //sp_canvas_force_full_redraw_after_interruptions(dragger->parent->desktop->canvas, 5);
 
     if ((state & GDK_SHIFT_MASK) && !drag->hasEmptySelection()) { // FIXME: Is the second check necessary?
@@ -369,7 +371,13 @@ vp_knot_ungrabbed_handler (SPKnot *knot, guint state, gpointer data)
 
     // TODO: Update box's paths and svg representation
 
+    dragger->parent->dragging = false;
+
     // TODO: Undo machinery!!
+    g_return_if_fail (dragger->parent);
+    g_return_if_fail (dragger->parent->document);
+    sp_document_done(dragger->parent->document, SP_VERB_CONTEXT_3DBOX,
+                     _("3D box: Move vanishing point"));
 }
 
 VPDragger::VPDragger(VPDrag *parent, NR::Point p, VanishingPoint *vp)
@@ -613,6 +621,7 @@ VPDrag::VPDrag (SPDocument *document)
 
     //this->selected = NULL;
     this->local_change = false;
+    this->dragging = false;
 
     this->sel_changed_connection = this->selection->connectChanged(
         sigc::bind (
@@ -676,6 +685,8 @@ VPDrag::getDraggerFor (VanishingPoint const &vp)
 void
 VPDrag::updateDraggers ()
 {
+    if (this->dragging)
+        return;
     /***
     while (selected) {
         selected = g_list_remove(selected, selected->data);
index 428bb49adce311bc6eeeabdba866eccd67261d21..3dde393855d99362e04aa55b45949e925ff009c2 100644 (file)
@@ -55,6 +55,7 @@ public:
     bool operator== (VanishingPoint const &other);
 
     inline NR::Point get_pos() const { return NR::Point ((*this)[NR::X], (*this)[NR::Y]); }
+    inline double get_angle() const { return NR::atan2 (this->v_dir) * 180/M_PI; } // return angle of infinite direction is in degrees
     inline void set_pos(NR::Point const &pt) { (*this)[NR::X] = pt[NR::X];
                                                (*this)[NR::Y] = pt[NR::Y]; }
     inline void set_pos(const double pt_x, const double pt_y) { (*this)[NR::X] = pt_x;
@@ -120,6 +121,7 @@ public:
     //void grabKnot (VanishingPoint const &vp, gint x, gint y, guint32 etime);
 
     bool local_change;
+    bool dragging;
 
     SPDocument *document;
     GList *draggers;
index 7e5de6b512aa879530874802522f0aa6e3bc2913..81bdc6607e516626de5d00e5cbad247490df3855 100644 (file)
@@ -303,8 +303,13 @@ static gchar const * ui_descr =
         "  </toolbar>"
 
         "  <toolbar name='3DBoxToolbar'>"
+        "    <toolitem action='3DBoxPosAngleXAction' />"
         "    <toolitem action='3DBoxVPXAction' />"
+        "    <separator />"
+        "    <toolitem action='3DBoxPosAngleYAction' />"
         "    <toolitem action='3DBoxVPYAction' />"
+        "    <separator />"
+        "    <toolitem action='3DBoxPosAngleZAction' />"
         "    <toolitem action='3DBoxVPZAction' />"
         "    <separator />"
         "  </toolbar>"
@@ -2146,68 +2151,280 @@ static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions
 //##       3D Box       ##
 //########################
 
-static void sp_3dbox_toggle_vp_changed( GtkToggleAction *act, gpointer data )
+static void sp_3dbox_toggle_vp_changed (GtkToggleAction *act, GObject *dataKludge, Box3D::Axis axis)
 {
-    SPDocument *document = sp_desktop_document (inkscape_active_desktop ());
-    Box3D::Axis axis = (Box3D::Axis) GPOINTER_TO_INT(data);
+    SPDesktop *desktop = (SPDesktop *) g_object_get_data (dataKludge, "desktop");
+    SPDocument *document = sp_desktop_document (desktop);
+    Box3D::Perspective3D *persp = document->current_perspective;
 
-    if (document->current_perspective) {
-        document->current_perspective->toggle_boxes (axis);
+    g_return_if_fail (is_single_axis_direction (axis));
+    g_return_if_fail (persp);
+
+    persp->toggle_boxes (axis);
+
+    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;
+    }
+    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() );
+    }
+
+    // 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"));
+    }
+}
+
+static void sp_3dbox_toggle_vp_x_changed(GtkToggleAction *act, GObject *dataKludge)
+{
+    sp_3dbox_toggle_vp_changed (act, dataKludge, Box3D::X);
+}
+
+static void sp_3dbox_toggle_vp_y_changed(GtkToggleAction *act, GObject *dataKludge)
+{
+    sp_3dbox_toggle_vp_changed (act, dataKludge, Box3D::Y);
+}
+
+static void sp_3dbox_toggle_vp_z_changed(GtkToggleAction *act, GObject *dataKludge)
+{
+    sp_3dbox_toggle_vp_changed (act, dataKludge, Box3D::Z);
+}
+
+static void sp_3dbox_vp_angle_changed(GtkAdjustment *adj, GObject *dataKludge, Box3D::Axis axis )
+{
+    SPDesktop *desktop = (SPDesktop *) g_object_get_data(dataKludge, "desktop");
+    Box3D::Perspective3D *persp = sp_desktop_document (desktop)->current_perspective;
+
+    if (persp) {
+        double angle = adj->value * M_PI/180;
+        persp->set_infinite_direction (axis, NR::Point (cos (angle), sin (angle)));
+
+        // 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"));
+        }
+    }
+    //g_object_set_data(G_OBJECT(dataKludge), "freeze", GINT_TO_POINTER(FALSE));
+}
+
+static void sp_3dbox_vpx_angle_changed(GtkAdjustment *adj, GObject *dataKludge )
+{
+    sp_3dbox_vp_angle_changed (adj, dataKludge, Box3D::X);
+}
+
+static void sp_3dbox_vpy_angle_changed(GtkAdjustment *adj, GObject *dataKludge )
+{
+    sp_3dbox_vp_angle_changed (adj, dataKludge, Box3D::Y);
+}
+
+static void sp_3dbox_vpz_angle_changed(GtkAdjustment *adj, GObject *dataKludge )
+{
+    sp_3dbox_vp_angle_changed (adj, dataKludge, Box3D::Z);
+}
+
+// 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 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")) {
+        return;
+    }
+
+    // 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);
+    }
+}
+
+static Inkscape::XML::NodeEventVector sp_3dbox_tb_repr_events =
+{
+    NULL, /* child_added */
+    NULL, /* child_removed */
+    sp_3dbox_tb_event_attr_changed,
+    NULL, /* content_changed */
+    NULL  /* order_changed */
+};
+
+/**
+ *  \param selection Should not be NULL.
+ */
+static void
+sp_3dbox_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
+{
+    Inkscape::XML::Node *repr = NULL;
+    purge_repr_listener(tbl, tbl);
+
+    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 sp_3dbox_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 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);
+    } else {
+        gtk_action_set_sensitive(GTK_ACTION(eact), FALSE);
+    }
+
     /* toggle VP in X direction */
     {
-    InkToggleAction* act = ink_toggle_action_new( "3DBoxVPXAction",
+    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 (document->current_perspective) {
-        toggled = !document->current_perspective->get_vanishing_point(Box3D::X)->is_finite();
+                                                  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 );
+    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_changed), GINT_TO_POINTER(Box3D::X));
+    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 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);
     }
 
     /* toggle VP in Y direction */
     {
-    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 (document->current_perspective) {
-        toggled = !document->current_perspective->get_vanishing_point(Box3D::Y)->is_finite();
-    }
-    gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), toggled );
+    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_changed), GINT_TO_POINTER(Box3D::Y));
+    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 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);
+    } else {
+        gtk_action_set_sensitive(GTK_ACTION(eact), FALSE);
     }
 
     /* toggle VP in Z direction */
     {
-    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 (document->current_perspective) {
-        toggled = !document->current_perspective->get_vanishing_point(Box3D::Z)->is_finite();
+    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();
     }
     /* 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_changed), GINT_TO_POINTER(Box3D::Z));
+    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);
     }
+
+    sigc::connection *connection = new sigc::connection(
+        sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_3dbox_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);
 }
 
 //########################