From fa90912de6e92199e5fa5957d1d47fd485abc011 Mon Sep 17 00:00:00 2001 From: cilix42 Date: Thu, 13 Dec 2007 20:08:06 +0000 Subject: [PATCH] If necessary, split up perspectives when applying transformations to boxes; moreover, fix crash caused by listening to already destroyed perspectives --- src/box3d-context.cpp | 8 ++++---- src/box3d.cpp | 36 ++++++++++++++++++++++++++++++++---- src/box3d.h | 1 + src/desktop-style.cpp | 2 -- src/persp3d.cpp | 34 ++++++++++++++++++++++++++++++++-- src/persp3d.h | 4 +++- src/vanishing-point.cpp | 6 +----- 7 files changed, 73 insertions(+), 18 deletions(-) diff --git a/src/box3d-context.cpp b/src/box3d-context.cpp index d74b0e7d1..858e7fc57 100644 --- a/src/box3d-context.cpp +++ b/src/box3d-context.cpp @@ -187,7 +187,7 @@ static void sp_box3d_context_selection_changed(Inkscape::Selection *selection, g SPDocument *doc = sp_desktop_document(bc->desktop); doc->persps_sel.clear(); - doc->persps_sel = persp3d_currently_selected(bc); + doc->persps_sel = persp3d_currently_selected_persps(ec); SPItem *item = selection->singleItem(); if (item) { @@ -538,7 +538,7 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven break; case GDK_X: if (MOD__CTRL) break; // Don't catch Ctrl+X ('cut') and Ctrl+Shift+X ('open XML editor') - persp3d_toggle_VPs(persp3d_currently_selected(bc), Proj::X); + persp3d_toggle_VPs(persp3d_currently_selected_persps(event_context), Proj::X); bc->_vpdrag->updateLines(); // FIXME: Shouldn't this be done automatically? ret = true; break; @@ -546,7 +546,7 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven case GDK_Y: { if (MOD__CTRL) break; // Don't catch Ctrl+Y ("redo") - persp3d_toggle_VPs(persp3d_currently_selected(bc), Proj::Y); + persp3d_toggle_VPs(persp3d_currently_selected_persps(event_context), Proj::Y); bc->_vpdrag->updateLines(); // FIXME: Shouldn't this be done automatically? ret = true; break; @@ -555,7 +555,7 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven case GDK_Z: { if (MOD__CTRL) break; // Don't catch Ctrl+Z ("undo") - persp3d_toggle_VPs(persp3d_currently_selected(bc), Proj::Z); + persp3d_toggle_VPs(persp3d_currently_selected_persps(event_context), Proj::Z); bc->_vpdrag->updateLines(); // FIXME: Shouldn't this be done automatically? ret = true; break; diff --git a/src/box3d.cpp b/src/box3d.cpp index c9f3bb7d2..038a6b06b 100644 --- a/src/box3d.cpp +++ b/src/box3d.cpp @@ -345,11 +345,29 @@ box3d_position_set (SPBox3D *box) static NR::Matrix box3d_set_transform(SPItem *item, NR::Matrix const &xform) { - SPBox3D *box = SP_BOX3D(item); - - Persp3D *persp = box->persp_ref->getObject(); + /* check whether we need to unlink any boxes from their perspectives */ + std::set p_sel = persp3d_currently_selected_persps(inkscape_active_event_context()); + Persp3D *persp; + Persp3D *transf_persp; + for (std::set::iterator p = p_sel.begin(); p != p_sel.end(); ++p) { + persp = (*p); + if (!persp3d_has_all_boxes_in_selection (persp)) { + std::list sel = persp3d_selected_boxes (persp); + + /* create a new perspective as a copy of the current one and link the selected boxes to it */ + transf_persp = persp3d_create_xml_element (SP_OBJECT_DOCUMENT(persp), persp); + + for (std::list::iterator b = sel.begin(); b != sel.end(); ++b) { + box3d_switch_perspectives(*b, persp, transf_persp); + } + } else { + transf_persp = persp; + } - persp3d_apply_affine_transformation(persp, xform); // also triggers repr updates + /* concatenate the affine transformation with the perspective mapping; this + function also triggers repr updates of boxes and the perspective itself */ + persp3d_apply_affine_transformation(transf_persp, xform); + } /*** // FIXME: We somehow have to apply the transformation to strokes, patterns, and gradients. How? @@ -1324,6 +1342,16 @@ box3d_relabel_corners(SPBox3D *box) { box3d_swap_coords(box, Proj::Z, true); } +void +box3d_switch_perspectives(SPBox3D *box, Persp3D *old_persp, Persp3D *new_persp) { + persp3d_remove_box (old_persp, box); + persp3d_add_box (new_persp, box); + gchar *href = g_strdup_printf("#%s", SP_OBJECT_REPR(new_persp)->attribute("id")); + SP_OBJECT_REPR(box)->setAttribute("inkscape:perspectiveID", href); + g_free(href); +} + + /* Local Variables: mode:c++ diff --git a/src/box3d.h b/src/box3d.h index c676696e9..78ee45077 100644 --- a/src/box3d.h +++ b/src/box3d.h @@ -70,6 +70,7 @@ int box3d_VP_lies_in_PL_sector (SPBox3D const *box, Proj::Axis vpdir, int id1, i /* ensures that the coordinates of corner0 and corner7 are in the correct order (to prevent everted boxes) */ void box3d_relabel_corners(SPBox3D *box); +void box3d_switch_perspectives(SPBox3D *box, Persp3D *old_persp, Persp3D *new_persp); #endif /* __SP_BOX3D_H__ */ diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index eaa4ee6a7..d0cecda03 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -167,10 +167,8 @@ sp_desktop_set_style(SPDesktop *desktop, SPCSSAttr *css, bool change, bool write for (const GSList *i = desktop->selection->itemList(); i != NULL; i = i->next) { /* last used styles for 3D box faces are stored separately */ if (SP_IS_BOX3D_SIDE (i->data)) { - //const char * descr = SP_OBJECT_REPR (G_OBJECT (i->data))->attribute ("inkscape:box3dside"); const char * descr = box3d_side_axes_string(SP_BOX3D_SIDE(i->data)); if (descr != NULL) { - g_print ("################ Box3DSide description found.\n"); gchar *style_grp = g_strconcat ("desktop.", descr, NULL); sp_repr_css_change(inkscape_get_repr(INKSCAPE, style_grp), css_write, "style"); g_free (style_grp); diff --git a/src/persp3d.cpp b/src/persp3d.cpp index 3dafba30d..818afe053 100644 --- a/src/persp3d.cpp +++ b/src/persp3d.cpp @@ -129,6 +129,8 @@ static void persp3d_build(SPObject *object, SPDocument *document, Inkscape::XML: static void persp3d_release(SPObject *object) { //Persp3D *persp = (Persp3D *) object; + SP_OBJECT_REPR(object)->removeListenerByData(object); + // FIXME: What precisely does this do and is it necessary for perspectives? /** if (SP_OBJECT_DOCUMENT(object)) { @@ -356,6 +358,7 @@ void persp3d_apply_affine_transformation (Persp3D *persp, NR::Matrix const &xform) { persp->tmat *= xform; persp3d_update_box_reprs(persp); + SP_OBJECT(persp)->updateRepr(SP_OBJECT_WRITE_EXT); } gchar * @@ -489,8 +492,8 @@ persp3d_on_repr_attr_changed ( Inkscape::XML::Node * repr, /* returns a std::set() of all perspectives of the currently selected boxes */ std::set -persp3d_currently_selected (Box3DContext *bc) { - Inkscape::Selection *selection = sp_desktop_selection (bc->desktop); +persp3d_currently_selected_persps (SPEventContext *ec) { + Inkscape::Selection *selection = sp_desktop_selection (ec->desktop); std::set p; for (GSList *i = (GSList *) selection->itemList(); i != NULL; i = i->next) { @@ -501,6 +504,33 @@ persp3d_currently_selected (Box3DContext *bc) { return p; } +/* checks whether all boxes linked to this perspective are currently selected */ +bool +persp3d_has_all_boxes_in_selection (Persp3D *persp) { + const GSList *selection = sp_desktop_selection (inkscape_active_desktop())->itemList(); + + for (std::vector::iterator i = persp->boxes.begin(); i != persp->boxes.end(); ++i) { + if (g_slist_find((GSList *) selection, *i) == NULL) { + // we have an unselected box in the perspective + return false; + } + } + return true; +} + +std::list +persp3d_selected_boxes (Persp3D *persp) { + const GSList *selection = sp_desktop_selection (inkscape_active_desktop())->itemList(); + std::list sel; + + for (std::vector::iterator i = persp->boxes.begin(); i != persp->boxes.end(); ++i) { + if (g_slist_find((GSList *) selection, *i) != NULL) { + sel.push_back(SP_BOX3D(*i)); + } + } + return sel; +} + void persp3d_print_debugging_info (Persp3D *persp) { g_print ("=== Info for Persp3D %d ===\n", persp->my_counter); diff --git a/src/persp3d.h b/src/persp3d.h index 934136ba2..696c0cdad 100644 --- a/src/persp3d.h +++ b/src/persp3d.h @@ -75,7 +75,9 @@ void persp3d_absorb(Persp3D *persp1, Persp3D *persp2); Persp3D * persp3d_create_xml_element (SPDocument *document, Persp3D *dup = NULL); -std::set persp3d_currently_selected (Box3DContext *bc); +std::set persp3d_currently_selected_persps (SPEventContext *ec); +bool persp3d_has_all_boxes_in_selection (Persp3D *persp); +std::list persp3d_selected_boxes (Persp3D *persp); void persp3d_print_debugging_info (Persp3D *persp); void persp3d_print_debugging_info_all(SPDocument *doc); diff --git a/src/vanishing-point.cpp b/src/vanishing-point.cpp index 0a8336102..0b68ff541 100644 --- a/src/vanishing-point.cpp +++ b/src/vanishing-point.cpp @@ -125,11 +125,7 @@ vp_knot_moved_handler (SPKnot *knot, NR::Point const *ppointer, guint state, gpo /* if a box in the VP is unselected, move it to the newly created perspective so that it doesn't get dragged **/ //g_print (" switching box #%d to new perspective.\n", (*i)->my_counter); - persp3d_remove_box (old_persp, *i); - persp3d_add_box (new_persp, *i); - gchar *href = g_strdup_printf("#%s", SP_OBJECT_REPR(new_persp)->attribute("id")); - SP_OBJECT_REPR(*i)->setAttribute("inkscape:perspectiveID", href); - g_free(href); + box3d_switch_perspectives(*i, old_persp, new_persp); } } } -- 2.30.2