From: buliabyak Date: Thu, 26 Jan 2006 05:16:27 +0000 (+0000) Subject: remember rotation centers, correctly this time (by johncliff and me) X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=f51ffb90ffdf528948889a4cd54f531bd1b2a30c;p=inkscape.git remember rotation centers, correctly this time (by johncliff and me) --- diff --git a/src/attributes.cpp b/src/attributes.cpp index ce9c0e105..10b33e178 100644 --- a/src/attributes.cpp +++ b/src/attributes.cpp @@ -36,6 +36,8 @@ static SPStyleProp const props[] = { {SP_ATTR_SODIPODI_NONPRINTABLE, "sodipodi:nonprintable"}, {SP_ATTR_CONNECTOR_AVOID, "inkscape:connector-avoid"}, {SP_ATTR_STYLE, "style"}, + {SP_ATTR_TRANSFORM_CENTER_X, "inkscape:transform-center-x"}, + {SP_ATTR_TRANSFORM_CENTER_Y, "inkscape:transform-center-y"}, /* SPAnchor */ {SP_ATTR_XLINK_HREF, "xlink:href"}, {SP_ATTR_XLINK_TYPE, "xlink:type"}, diff --git a/src/attributes.h b/src/attributes.h index 2b4a68f34..b36cf2557 100644 --- a/src/attributes.h +++ b/src/attributes.h @@ -36,6 +36,8 @@ enum SPAttributeEnum { SP_ATTR_SODIPODI_NONPRINTABLE, SP_ATTR_CONNECTOR_AVOID, SP_ATTR_STYLE, + SP_ATTR_TRANSFORM_CENTER_X, + SP_ATTR_TRANSFORM_CENTER_Y, /* SPAnchor */ SP_ATTR_XLINK_HREF, SP_ATTR_XLINK_TYPE, diff --git a/src/seltrans.cpp b/src/seltrans.cpp index ca65b5d76..f83c646b7 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -50,6 +50,7 @@ static void sp_remove_handles(SPKnot *knot[], gint num); static void sp_sel_trans_handle_grab(SPKnot *knot, guint state, gpointer data); static void sp_sel_trans_handle_ungrab(SPKnot *knot, guint state, gpointer data); +static void sp_sel_trans_handle_click(SPKnot *knot, guint state, gpointer data); static void sp_sel_trans_handle_new_event(SPKnot *knot, NR::Point *position, guint32 state, gpointer data); static gboolean sp_sel_trans_handle_request(SPKnot *knot, NR::Point *p, guint state, gboolean *data); @@ -100,8 +101,6 @@ Inkscape::SelTrans::SelTrans(SPDesktop *desktop) : _updateVolatileState(); - _center = _box.midpoint(); - _updateHandles(); _selection = SP_DT_SELECTION(desktop); @@ -210,6 +209,15 @@ void Inkscape::SelTrans::increaseState() void Inkscape::SelTrans::setCenter(NR::Point const &p) { _center = p; + + // Write the new center position into all selected items + for (GSList const *l = _desktop->selection->itemList(); l; l = l->next) { + SPItem *it = (SPItem*)sp_object_ref(SP_OBJECT(l->data), NULL); + it->setCenter(p); + SP_OBJECT(it)->updateRepr(); + } + sp_document_maybe_done (SP_DT_DOCUMENT(_desktop), "center::move"); + _updateHandles(); } @@ -301,44 +309,30 @@ void Inkscape::SelTrans::transform(NR::Matrix const &rel_affine, NR::Point const _updateHandles(); } -void Inkscape::SelTrans::_centreTrans(Inkscape::XML::Node *current) const -{ - for ( Inkscape::XML::Node *child = sp_repr_children(current) ; child ; child = sp_repr_next(child) ) { - _centreTrans(child); - } - double const cx = sp_repr_get_double_attribute(current, "inkscape:c_rx", 9999999); - double const cy = sp_repr_get_double_attribute(current, "inkscape:c_ry", 9999999); - if (cx != 9999999) { - NR::Point object_centre = NR::Point(cx, cy) * _current; - sp_repr_set_svg_double(current, "inkscape:c_rx", object_centre[NR::X]); - sp_repr_set_svg_double(current, "inkscape:c_ry", object_centre[NR::Y]); - } - } - - - - void Inkscape::SelTrans::ungrab() { g_return_if_fail(_grabbed); Inkscape::Selection *selection = SP_DT_SELECTION(_desktop); - bool updh = true; if (!_empty && _changed) { sp_selection_apply_affine(selection, _current, (_show == SHOW_OUTLINE)? true : false); _center *= _current; + + // Transform may have changed the objects' bboxes, so we need to write the _center into them again + for (unsigned i = 0; i < _items.size(); i++) { + SPItem *currentItem = _items[i].first; + if (currentItem->isCenterSet() || _current[1] != 0 || _current[2] != 0) { // only if it's already set, or if it's a rotation/skew + currentItem->setCenter (_center); + SP_OBJECT(currentItem)->updateRepr(); + } + } + sp_document_done(SP_DT_DOCUMENT(_desktop)); updh = false; } - for (unsigned i = 0; i < _items.size(); i++) - { - Inkscape::XML::Node *current = SP_OBJECT_REPR(_items[i].first); - if (current != NULL) { - _centreTrans(current); - } - + for (unsigned i = 0; i < _items.size(); i++) { sp_object_unref(SP_OBJECT(_items[i].first), NULL); } _items.clear(); @@ -455,6 +449,8 @@ void Inkscape::SelTrans::_updateHandles() G_CALLBACK(sp_sel_trans_handle_grab), (gpointer) &handle_center); g_signal_connect(G_OBJECT(_chandle), "ungrabbed", G_CALLBACK(sp_sel_trans_handle_ungrab), (gpointer) &handle_center); + g_signal_connect(G_OBJECT(_chandle), "clicked", + G_CALLBACK(sp_sel_trans_handle_click), (gpointer) &handle_center); } sp_remove_handles(&_chandle, 1); @@ -469,16 +465,23 @@ void Inkscape::SelTrans::_updateHandles() _("Skew selection; with Ctrl to snap angle; with Shift to skew around the opposite side"), _("Rotate selection; with Ctrl to snap angle; with Shift to rotate around the opposite corner")); } + + // Extract the position of the center from the first selected object + GSList *items = (GSList *) _desktop->selection->itemList(); + if (items) { + SPItem *first = reinterpret_cast(g_slist_last(items)->data); // from the first item in selection + if (first->isCenterSet()) { // only if set explicitly + _center = first->getCenter(); + } else { + _center = _box.midpoint(); + } + } else { + _center = _box.midpoint(); + } + if ( _state == STATE_SCALE ) { sp_knot_hide(_chandle); } else { - Inkscape::Selection *selection = _desktop->selection; - Inkscape::XML::Node *current = selection->singleRepr(); - if (current != NULL && sp_repr_get_double_attribute(current, "inkscape:c_rx", 99999999) != 99999999) { - double cx = sp_repr_get_double_attribute(current, "inkscape:c_rx", _center[NR::X]); - double cy = sp_repr_get_double_attribute(current, "inkscape:c_ry", _center[NR::Y]); - _center = NR::Point(cx, cy); - } sp_knot_show(_chandle); sp_knot_moveto(_chandle, &_center); } @@ -581,6 +584,32 @@ static gboolean sp_sel_trans_handle_request(SPKnot *knot, NR::Point *position, g ); } +static void sp_sel_trans_handle_click(SPKnot *knot, guint state, gpointer data) +{ + SP_SELECT_CONTEXT(knot->desktop->event_context)->_seltrans->handleClick( + knot, state, *(SPSelTransHandle const *) data + ); +} + +void Inkscape::SelTrans::handleClick(SPKnot *knot, guint state, SPSelTransHandle const &handle) +{ + switch (handle.anchor) { + case GTK_ANCHOR_CENTER: + if (state & GDK_SHIFT_MASK) { + // Unset the center position for all selected items + for (GSList const *l = _desktop->selection->itemList(); l; l = l->next) { + SPItem *it = (SPItem*)sp_object_ref(SP_OBJECT(l->data), NULL); + it->unsetCenter(); + SP_OBJECT(it)->updateRepr(); + } + sp_document_maybe_done (SP_DT_DOCUMENT(_desktop), "center::unset"); + } + break; + default: + break; + } +} + void Inkscape::SelTrans::handleGrab(SPKnot *knot, guint state, SPSelTransHandle const &handle) { switch (handle.anchor) { @@ -657,7 +686,6 @@ void Inkscape::SelTrans::_selChanged(Inkscape::Selection *selection) { if (!_grabbed) { _updateVolatileState(); - _center = _box.midpoint(); _updateHandles(); } } @@ -667,17 +695,6 @@ void Inkscape::SelTrans::_selModified(Inkscape::Selection *selection, guint flag if (!_grabbed) { _updateVolatileState(); - if ( - (flags != (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG)) && - (flags != SP_OBJECT_PARENT_MODIFIED_FLAG) && - (flags != SP_OBJECT_CHILD_MODIFIED_FLAG) && - !_changed) { - // Only reset center if object itself is modified (not style, parent or child), - // and this is not a local change by seltrans - // (still annoyingly recenters on keyboard transforms, fixme) - _center = _box.midpoint(); - } - // reset internal flag _changed = false; @@ -1032,14 +1049,6 @@ gboolean Inkscape::SelTrans::centerRequest(NR::Point &pt, guint state) } } - Inkscape::Selection *selection = _desktop->selection; - Inkscape::XML::Node *current = selection->singleRepr(); - if (current != NULL){ - sp_repr_set_svg_double(current, "inkscape:c_rx", pt[X]); - sp_repr_set_svg_double(current, "inkscape:c_ry", pt[Y]); - - } - if (!(state & GDK_SHIFT_MASK)) { // screen pixels to snap center to bbox #define SNAP_DIST 5 diff --git a/src/seltrans.h b/src/seltrans.h index 30be58eeb..8ac56766e 100644 --- a/src/seltrans.h +++ b/src/seltrans.h @@ -65,6 +65,7 @@ public: gboolean handleRequest(SPKnot *knot, NR::Point *position, guint state, SPSelTransHandle const &handle); void handleGrab(SPKnot *knot, guint state, SPSelTransHandle const &handle); + void handleClick(SPKnot *knot, guint state, SPSelTransHandle const &handle); void handleNewEvent(SPKnot *knot, NR::Point *position, guint state, SPSelTransHandle const &handle); enum Show @@ -87,8 +88,7 @@ private: void _selModified(Inkscape::Selection *selection, guint flags); void _showHandles(SPKnot *knot[], SPSelTransHandle const handle[], gint num, gchar const *even_tip, gchar const *odd_tip); - void _centreTrans(Inkscape::XML::Node *current) const; - + enum State { STATE_SCALE, STATE_ROTATE diff --git a/src/sp-item.cpp b/src/sp-item.cpp index 97aeb1877..7339160c7 100644 --- a/src/sp-item.cpp +++ b/src/sp-item.cpp @@ -134,8 +134,8 @@ sp_item_init(SPItem *item) item->sensitive = TRUE; - item->r_cx = 0; - item->r_cx = 0; + item->transform_center_x = 0; + item->transform_center_y = 0; item->transform = NR::identity(); @@ -234,6 +234,42 @@ SPItem::setExplicitlyHidden(bool const val) { this->updateRepr(); } +/** + * Sets the transform_center_x and transform_center_y properties to retain the rotation centre + */ +void +SPItem::setCenter(NR::Point object_centre) { + NR::Rect bbox = invokeBbox(sp_item_i2d_affine(this)); + if (!bbox.isEmpty()) { + transform_center_x = object_centre[NR::X] - bbox.midpoint()[NR::X]; + if (fabs(transform_center_x) < 1e-5) // rounding error + transform_center_x = 0; + transform_center_y = object_centre[NR::Y] - bbox.midpoint()[NR::Y]; + if (fabs(transform_center_y) < 1e-5) // rounding error + transform_center_y = 0; + } +} + +void +SPItem::unsetCenter() { + transform_center_x = 0; + transform_center_y = 0; +} + +bool SPItem::isCenterSet() { + return (transform_center_x != 0 || transform_center_y != 0); +} + +NR::Point SPItem::getCenter() { + NR::Rect bbox = invokeBbox(sp_item_i2d_affine(this)); + if (!bbox.isEmpty()) { + return bbox.midpoint() + NR::Point (this->transform_center_x, this->transform_center_y); + } else { + return NR::Point (0, 0); // something's wrong! + } +} + + namespace { bool is_item(SPObject const &object) { @@ -313,8 +349,8 @@ sp_item_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) sp_object_read_attr(object, "mask"); sp_object_read_attr(object, "sodipodi:insensitive"); sp_object_read_attr(object, "sodipodi:nonprintable"); - sp_object_read_attr(object, "inkscape:r_cx"); - sp_object_read_attr(object, "inkscape:r_cy"); + sp_object_read_attr(object, "inkscape:transform-center-x"); + sp_object_read_attr(object, "inkscape:transform-center-y"); sp_object_read_attr(object, "inkscape:connector-avoid"); if (((SPObjectClass *) (parent_class))->build) { @@ -416,6 +452,16 @@ sp_item_set(SPObject *object, unsigned key, gchar const *value) case SP_ATTR_CONNECTOR_AVOID: item->avoidRef->setAvoid(value); break; + case SP_ATTR_TRANSFORM_CENTER_X: + if (value) { + item->transform_center_x = g_strtod(value, NULL); + } + break; + case SP_ATTR_TRANSFORM_CENTER_Y: + if (value) { + item->transform_center_y = g_strtod(value, NULL); + } + break; default: if (SP_ATTRIBUTE_IS_CSS(key)) { sp_style_read_from_object(object->style, object); @@ -583,8 +629,14 @@ sp_item_write(SPObject *const object, Inkscape::XML::Node *repr, guint flags) if (flags & SP_OBJECT_WRITE_EXT) { repr->setAttribute("sodipodi:insensitive", ( item->sensitive ? NULL : "true" )); - repr->setAttribute("inkscape:r_cx", ( item->r_cx ? NULL : "true" )); - repr->setAttribute("inkscape:r_cy", ( item->r_cy ? NULL : "true" )); + if (item->transform_center_x != 0) + sp_repr_set_svg_double (repr, "inkscape:transform-center-x", item->transform_center_x); + else + repr->setAttribute ("inkscape:transform-center-x", NULL); + if (item->transform_center_y != 0) + sp_repr_set_svg_double (repr, "inkscape:transform-center-y", item->transform_center_y); + else + repr->setAttribute ("inkscape:transform-center-y", NULL); } if (((SPObjectClass *) (parent_class))->write) { diff --git a/src/sp-item.h b/src/sp-item.h index 252821f36..141d3f881 100644 --- a/src/sp-item.h +++ b/src/sp-item.h @@ -91,9 +91,9 @@ struct SPItemCtx { struct SPItem : public SPObject { unsigned int sensitive : 1; unsigned int stop_paint: 1; - double r_cx; - double r_cy; - + double transform_center_x; + double transform_center_y; + NR::Matrix transform; SPClipPathReference *clip_ref; @@ -119,7 +119,12 @@ struct SPItem : public SPObject { bool isExplicitlyHidden() const; void setExplicitlyHidden(bool val); - + + void setCenter(NR::Point object_centre); + void unsetCenter(); + bool isCenterSet(); + NR::Point getCenter(); + bool isVisibleAndUnlocked() const; bool isVisibleAndUnlocked(unsigned display_key) const;