X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fseltrans.cpp;h=84ee0920e5b5a535107a2afc3e2e74a9c4ac659d;hb=e31600863637aa0688672fca6bdc1d19ffffe506;hp=1d4557b903fa60e7bad1e0b7780ce3ba0a9a5cb7;hpb=f951374eef04129c6a0d213e7ab4d9ed2095ca69;p=inkscape.git diff --git a/src/seltrans.cpp b/src/seltrans.cpp index 1d4557b90..84ee0920e 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -39,6 +39,7 @@ #include "seltrans.h" #include "selection-chemistry.h" #include "sp-metrics.h" +#include "verbs.h" #include #include "display/sp-ctrlline.h" #include "prefs-utils.h" @@ -87,7 +88,7 @@ Inkscape::SelTrans::SelTrans(SPDesktop *desktop) : _show(SHOW_CONTENT), _grabbed(false), _show_handles(true), - _box(NR::Point(0,0), NR::Point(0,0)), + _box(NR::Nothing()), _chandle(NULL), _stamp_cache(NULL), _message_context(desktop->messageStack()) @@ -100,14 +101,15 @@ Inkscape::SelTrans::SelTrans(SPDesktop *desktop) : } _updateVolatileState(); + _current.set_identity(); _center_is_set = false; // reread _center from items, or set to bbox midpoint _updateHandles(); - _selection = SP_DT_SELECTION(desktop); + _selection = sp_desktop_selection(desktop); - _norm = sp_canvas_item_new(SP_DT_CONTROLS(desktop), + _norm = sp_canvas_item_new(sp_desktop_controls(desktop), SP_TYPE_CTRL, "anchor", GTK_ANCHOR_CENTER, "mode", SP_CTRL_MODE_COLOR, @@ -120,7 +122,7 @@ Inkscape::SelTrans::SelTrans(SPDesktop *desktop) : "pixbuf", handles[12], NULL); - _grip = sp_canvas_item_new(SP_DT_CONTROLS(desktop), + _grip = sp_canvas_item_new(sp_desktop_controls(desktop), SP_TYPE_CTRL, "anchor", GTK_ANCHOR_CENTER, "mode", SP_CTRL_MODE_XOR, @@ -137,7 +139,7 @@ Inkscape::SelTrans::SelTrans(SPDesktop *desktop) : sp_canvas_item_hide(_norm); for (int i = 0; i < 4; i++) { - _l[i] = sp_canvas_item_new(SP_DT_CONTROLS(desktop), SP_TYPE_CTRLLINE, NULL); + _l[i] = sp_canvas_item_new(sp_desktop_controls(desktop), SP_TYPE_CTRLLINE, NULL); sp_canvas_item_hide(_l[i]); } @@ -218,24 +220,24 @@ void Inkscape::SelTrans::setCenter(NR::Point const &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); + SPItem *it = (SPItem*)SP_OBJECT(l->data); it->setCenter(p); - SP_OBJECT(it)->updateRepr(); + // only set the value; updating repr and document_done will be done once, on ungrab } - sp_document_maybe_done (SP_DT_DOCUMENT(_desktop), "center::move"); _updateHandles(); } void Inkscape::SelTrans::grab(NR::Point const &p, gdouble x, gdouble y, bool show_handles) { - Inkscape::Selection *selection = SP_DT_SELECTION(_desktop); + Inkscape::Selection *selection = sp_desktop_selection(_desktop); g_return_if_fail(!_grabbed); _grabbed = true; _show_handles = show_handles; _updateVolatileState(); + _current.set_identity(); _changed = false; @@ -253,23 +255,34 @@ void Inkscape::SelTrans::grab(NR::Point const &p, gdouble x, gdouble y, bool sho _point = p; - _snap_points = selection->getSnapPoints(); - _bbox_points = selection->getBBoxPoints(); + _snap_points = selection->getSnapPointsConvexHull(); + _box = selection->bounds(); + _bbox_points.clear(); + if (_box) { + for ( unsigned i = 0 ; i < 4 ; i++ ) { + _bbox_points.push_back(_box->corner(i)); + } + } gchar const *scale_origin = prefs_get_string_attribute("tools.select", "scale_origin"); bool const origin_on_bbox = (scale_origin == NULL || !strcmp(scale_origin, "bbox")); - NR::Rect op_box = _box; - if (origin_on_bbox == false && _snap_points.empty() == false) { - std::vector::iterator i = _snap_points.begin(); - op_box = NR::Rect(*i, *i); - i++; - while (i != _snap_points.end()) { - op_box.expandTo(*i); + + if (_box) { + NR::Rect op_box = *_box; + // FIXME: should be using ConvexHull here + if (origin_on_bbox == false && _snap_points.empty() == false) { + std::vector::iterator i = _snap_points.begin(); + op_box = NR::Rect(*i, *i); i++; + while (i != _snap_points.end()) { + op_box.expandTo(*i); + i++; + } } + + _opposite = ( op_box.min() + ( op_box.dimensions() * NR::scale(1-x, 1-y) ) ); } - _opposite = ( op_box.min() + ( op_box.dimensions() * NR::scale(1-x, 1-y) ) ); if ((x != -1) && (y != -1)) { sp_canvas_item_show(_norm); @@ -281,7 +294,6 @@ void Inkscape::SelTrans::grab(NR::Point const &p, gdouble x, gdouble y, bool sho sp_canvas_item_show(_l[i]); } - _updateHandles(); g_return_if_fail(_stamp_cache == NULL); } @@ -301,13 +313,15 @@ void Inkscape::SelTrans::transform(NR::Matrix const &rel_affine, NR::Point const sp_item_set_i2d_affine(&item, prev_transform * affine); } } else { - NR::Point p[4]; - /* update the outline */ - for (unsigned i = 0 ; i < 4 ; i++) { - p[i] = _box.corner(i) * affine; - } - for (unsigned i = 0 ; i < 4 ; i++) { - sp_ctrlline_set_coords(SP_CTRLLINE(_l[i]), p[i], p[(i+1)%4]); + if (_box) { + NR::Point p[4]; + /* update the outline */ + for (unsigned i = 0 ; i < 4 ; i++) { + p[i] = _box->corner(i) * affine; + } + for (unsigned i = 0 ; i < 4 ; i++) { + sp_ctrlline_set_coords(SP_CTRLLINE(_l[i]), p[i], p[(i+1)%4]); + } } } @@ -319,13 +333,37 @@ void Inkscape::SelTrans::transform(NR::Matrix const &rel_affine, NR::Point const void Inkscape::SelTrans::ungrab() { g_return_if_fail(_grabbed); + _grabbed = false; + _show_handles = true; + + Inkscape::Selection *selection = sp_desktop_selection(_desktop); + _updateVolatileState(); + + for (unsigned i = 0; i < _items.size(); i++) { + sp_object_unref(SP_OBJECT(_items[i].first), NULL); + } + + sp_canvas_item_hide(_norm); + sp_canvas_item_hide(_grip); + + if (_show == SHOW_OUTLINE) { + for (int i = 0; i < 4; i++) + sp_canvas_item_hide(_l[i]); + } + + if (_stamp_cache) { + g_slist_free(_stamp_cache); + _stamp_cache = NULL; + } + + _message_context.clear(); - 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; - _center_is_set = true; + if (_center) { + *_center *= _current; + _center_is_set = true; + } // If dragging showed content live, sp_selection_apply_affine cannot change the centers // appropriately - it does not know the original positions of the centers (all objects already have @@ -340,37 +378,39 @@ void Inkscape::SelTrans::ungrab() } } - sp_document_done(SP_DT_DOCUMENT(_desktop)); - updh = false; - } - - for (unsigned i = 0; i < _items.size(); i++) { - sp_object_unref(SP_OBJECT(_items[i].first), NULL); - } - _items.clear(); - _items_centers.clear(); - - _grabbed = false; - _show_handles = true; + _items.clear(); + _items_centers.clear(); + + if (_current.is_translation()) { + sp_document_done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_SELECT, + _("Move")); + } else if (_current.is_scale()) { + sp_document_done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_SELECT, + _("Scale")); + } else if (_current.is_rotation()) { + sp_document_done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_SELECT, + _("Rotate")); + } else { + sp_document_done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_SELECT, + _("Skew")); + } - sp_canvas_item_hide(_norm); - sp_canvas_item_hide(_grip); + } else { - if (_show == SHOW_OUTLINE) { - for (int i = 0; i < 4; i++) - sp_canvas_item_hide(_l[i]); - } + if (_center_is_set) { + // we were dragging center; update reprs and commit undoable action + for (GSList const *l = _desktop->selection->itemList(); l; l = l->next) { + SPItem *it = (SPItem*)SP_OBJECT(l->data); + SP_OBJECT(it)->updateRepr(); + } + sp_document_done (sp_desktop_document(_desktop), SP_VERB_CONTEXT_SELECT, + _("Set center")); + } - _updateVolatileState(); - if (updh) { + _items.clear(); + _items_centers.clear(); _updateHandles(); } - if (_stamp_cache) { - g_slist_free(_stamp_cache); - _stamp_cache = NULL; - } - - _message_context.clear(); } /* fixme: This is really bad, as we compare positions for each stamp (Lauris) */ @@ -378,7 +418,14 @@ void Inkscape::SelTrans::ungrab() void Inkscape::SelTrans::stamp() { - Inkscape::Selection *selection = SP_DT_SELECTION(_desktop); + Inkscape::Selection *selection = sp_desktop_selection(_desktop); + + bool fixup = !_grabbed; + if ( fixup && _stamp_cache ) { + // TODO - give a proper fix. Simple temproary work-around for the grab() issue + g_slist_free(_stamp_cache); + _stamp_cache = NULL; + } /* stamping mode */ if (!_empty) { @@ -408,7 +455,7 @@ void Inkscape::SelTrans::stamp() // move to the saved position copy_repr->setPosition(pos > 0 ? pos : 0); - SPItem *copy_item = (SPItem *) SP_DT_DOCUMENT(_desktop)->getObjectByRepr(copy_repr); + SPItem *copy_item = (SPItem *) sp_desktop_document(_desktop)->getObjectByRepr(copy_repr); NR::Matrix const *new_affine; if (_show == SHOW_OUTLINE) { @@ -422,10 +469,21 @@ void Inkscape::SelTrans::stamp() sp_item_write_transform(copy_item, copy_repr, *new_affine); + if ( copy_item->isCenterSet() && _center ) { + copy_item->setCenter(*_center * _current); + } + Inkscape::GC::release(copy_repr); l = l->next; } - sp_document_done(SP_DT_DOCUMENT(_desktop)); + sp_document_done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_SELECT, + _("Stamp")); + } + + if ( fixup && _stamp_cache ) { + // TODO - give a proper fix. Simple temproary work-around for the grab() issue + g_slist_free(_stamp_cache); + _stamp_cache = NULL; } } @@ -441,19 +499,17 @@ void Inkscape::SelTrans::_updateHandles() // center handle if ( _chandle == NULL ) { - _chandle = sp_knot_new(_desktop); - g_object_set(G_OBJECT(_chandle), - "anchor", handle_center.anchor, - "shape", SP_CTRL_SHAPE_BITMAP, - "size", 13, - "mode", SP_CTRL_MODE_XOR, - "fill", 0x00000000, - "fill_mouseover", 0x00000000, - "stroke", 0x000000ff, - "stroke_mouseover", 0xff0000b0, - "pixbuf", handles[handle_center.control], - "tip", _("Center of rotation and skewing: drag to reposition; scaling with Shift also uses this center"), - NULL); + _chandle = sp_knot_new(_desktop, _("Center of rotation and skewing: drag to reposition; scaling with Shift also uses this center")); + + _chandle->setShape (SP_CTRL_SHAPE_BITMAP); + _chandle->setSize (13); + _chandle->setAnchor (handle_center.anchor); + _chandle->setMode (SP_CTRL_MODE_XOR); + _chandle->setFill(0x00000000, 0x00000000, 0x00000000); + _chandle->setStroke(0x000000ff, 0xff0000b0, 0xff0000b0); + _chandle->setPixbuf(handles[handle_center.control]); + sp_knot_update_ctrl(_chandle); + g_signal_connect(G_OBJECT(_chandle), "request", G_CALLBACK(sp_sel_trans_handle_request), (gpointer) &handle_center); g_signal_connect(G_OBJECT(_chandle), "moved", @@ -480,32 +536,21 @@ void Inkscape::SelTrans::_updateHandles() } if (!_center_is_set) { - // 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(); - } + _center = _desktop->selection->center(); _center_is_set = true; } - if ( _state == STATE_SCALE ) { + if ( _state == STATE_SCALE || !_center ) { sp_knot_hide(_chandle); } else { sp_knot_show(_chandle); - sp_knot_moveto(_chandle, &_center); + sp_knot_moveto(_chandle, &*_center); } } void Inkscape::SelTrans::_updateVolatileState() { - Inkscape::Selection *selection = SP_DT_SELECTION(_desktop); + Inkscape::Selection *selection = sp_desktop_selection(_desktop); _empty = selection->isEmpty(); if (_empty) { @@ -513,14 +558,12 @@ void Inkscape::SelTrans::_updateVolatileState() } _box = selection->bounds(); - if (_box.isEmpty()) { + if (!_box) { _empty = true; return; } _strokewidth = stroke_average_width (selection->itemList()); - - _current.set_identity(); } static void sp_remove_handles(SPKnot *knot[], gint num) @@ -539,19 +582,16 @@ void Inkscape::SelTrans::_showHandles(SPKnot *knot[], SPSelTransHandle const han for (int i = 0; i < num; i++) { if (knot[i] == NULL) { - knot[i] = sp_knot_new(_desktop); - g_object_set(G_OBJECT(knot[i]), - "anchor", handle[i].anchor, - "shape", SP_CTRL_SHAPE_BITMAP, - "size", 13, - "mode", SP_KNOT_MODE_XOR, - "fill", 0x000000ff, // inversion - "fill_mouseover", 0x00ff6600, // green - "stroke", 0x000000ff, // inversion - "stroke_mouseover", 0x000000ff, // inversion - "pixbuf", handles[handle[i].control], - "tip", i % 2 ? even_tip : odd_tip, - NULL); + knot[i] = sp_knot_new(_desktop, i % 2 ? even_tip : odd_tip); + + knot[i]->setShape (SP_CTRL_SHAPE_BITMAP); + knot[i]->setSize (13); + knot[i]->setAnchor (handle[i].anchor); + knot[i]->setMode (SP_CTRL_MODE_XOR); + knot[i]->setFill(0x000000ff, 0x00ff6600, 0x00ff6600); // inversion, green, green + knot[i]->setStroke(0x000000ff, 0x000000ff, 0x000000ff); // inversion + knot[i]->setPixbuf(handles[handle[i].control]); + sp_knot_update_ctrl(knot[i]); g_signal_connect(G_OBJECT(knot[i]), "request", G_CALLBACK(sp_sel_trans_handle_request), (gpointer) &handle[i]); @@ -566,8 +606,10 @@ void Inkscape::SelTrans::_showHandles(SPKnot *knot[], SPSelTransHandle const han sp_knot_show(knot[i]); NR::Point const handle_pt(handle[i].x, handle[i].y); - NR::Point p( _box.min() - + ( _box.dimensions() + // shouldn't have nullary bbox, but knots + g_assert(_box); + NR::Point p( _box->min() + + ( _box->dimensions() * NR::scale(handle_pt) ) ); sp_knot_moveto(knot[i], &p); @@ -614,11 +656,14 @@ void Inkscape::SelTrans::handleClick(SPKnot *knot, guint state, SPSelTransHandle 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); + SPItem *it = (SPItem*)(SP_OBJECT(l->data)); it->unsetCenter(); SP_OBJECT(it)->updateRepr(); + _center_is_set = false; // center has changed + _updateHandles(); } - sp_document_maybe_done (SP_DT_DOCUMENT(_desktop), "center::unset"); + sp_document_done (sp_desktop_document(_desktop), SP_VERB_CONTEXT_SELECT, + _("Reset center")); } break; default: @@ -675,18 +720,19 @@ gboolean Inkscape::SelTrans::handleRequest(SPKnot *knot, NR::Point *position, gu return TRUE; } - knot->desktop->set_coordinate_status(*position); knot->desktop->setPosition(*position); - if (state & GDK_MOD1_MASK) { *position = _point + ( *position - _point ) / 10; } - if (!(state & GDK_SHIFT_MASK) == !(_state == STATE_ROTATE)) { + if ((!(state & GDK_SHIFT_MASK) == !(_state == STATE_ROTATE)) && (&handle != &handle_center)) { _origin = _opposite; + } else if (_center) { + _origin = *_center; } else { - _origin = _center; + // FIXME + return TRUE; } if (handle.request(this, handle, *position, state)) { sp_knot_set_position(knot, position, state); @@ -702,6 +748,7 @@ void Inkscape::SelTrans::_selChanged(Inkscape::Selection *selection) { if (!_grabbed) { _updateVolatileState(); + _current.set_identity(); _center_is_set = false; // center(s) may have changed _updateHandles(); } @@ -711,6 +758,7 @@ void Inkscape::SelTrans::_selModified(Inkscape::Selection *selection, guint flag { if (!_grabbed) { _updateVolatileState(); + _current.set_identity(); // reset internal flag _changed = false; @@ -781,6 +829,8 @@ gboolean Inkscape::SelTrans::scaleRequest(NR::Point &pt, guint state) } } + SnapManager const &m = _desktop->namedview->snap_manager; + /* Get a STL list of the selected items. ** FIXME: this should probably be done by Inkscape::Selection. */ @@ -790,50 +840,77 @@ gboolean Inkscape::SelTrans::scaleRequest(NR::Point &pt, guint state) } if ((state & GDK_CONTROL_MASK) || _desktop->isToolboxButtonActive ("lock")) { - /* Scale is locked to a 1:1 aspect ratio, so that s[X] must be made to equal s[Y] */ - - NR::Dim2 locked_dim; + /* Scale is locked to a 1:1 aspect ratio, so that s[X] must be made to equal s[Y]. + ** To do this, we snap along a suitable constraint vector from the origin. + */ + + // The inclination of the constraint vector is calculated from the aspect ratio + NR::Point bbox_dim = _box->dimensions(); + double const aspect_ratio = bbox_dim[1] / bbox_dim[0]; // = height / width + + // Determine direction of the constraint vector + NR::Point const cv = NR::Point( + pt[NR::X] > _origin[NR::X] ? 1 : -1, + pt[NR::Y] > _origin[NR::Y] ? aspect_ratio : -aspect_ratio + ); + + std::pair bb = m.constrainedSnapScale(Snapper::BBOX_POINT, + _bbox_points, + it, + Snapper::ConstraintLine(_origin, cv), + s, + _origin); + + std::pair sn = m.constrainedSnapScale(Snapper::SNAP_POINT, + _snap_points, + it, + Snapper::ConstraintLine(_origin, cv), + s, + _origin); + + if (bb.second == false && sn.second == false) { + + /* We didn't snap, so just lock aspect ratio */ + if (fabs(s[NR::X]) > fabs(s[NR::Y])) { + s[NR::X] = fabs(s[NR::Y]) * sign(s[NR::X]); + } else { + s[NR::Y] = fabs(s[NR::X]) * sign(s[NR::Y]); + } - /* Lock aspect ratio, using the smaller of the x and y factors */ - if (fabs(s[NR::X]) > fabs(s[NR::Y])) { - s[NR::X] = fabs(s[NR::Y]) * sign(s[NR::X]); - locked_dim = NR::X; } else { - s[NR::Y] = fabs(s[NR::X]) * sign(s[NR::Y]); - locked_dim = NR::Y; - } - /* Snap the scale factor */ - std::pair bb = namedview_vector_snap_list(_desktop->namedview, - Snapper::BBOX_POINT, _bbox_points, - _origin, s, it); - std::pair sn = namedview_vector_snap_list(_desktop->namedview, - Snapper::SNAP_POINT, _snap_points, - _origin, s, it); - - double bd = bb.second ? fabs(bb.first - s[locked_dim]) : NR_HUGE; - double sd = sn.second ? fabs(sn.first - s[locked_dim]) : NR_HUGE; - double r = (bd < sd) ? bb.first : sn.first; - - for ( unsigned int i = 0 ; i < 2 ; i++ ) { - s[i] = r * sign(s[i]); + /* Choose the smaller difference in scale. Since s[X] == s[Y] we can + ** just compare difference in s[X]. + */ + double const bd = bb.second ? fabs(bb.first[NR::X] - s[NR::X]) : NR_HUGE; + double const sd = sn.second ? fabs(sn.first[NR::X] - s[NR::X]) : NR_HUGE; + s = (bd < sd) ? bb.first : sn.first; } } else { /* Scale aspect ratio is unlocked */ - for ( unsigned int i = 0 ; i < 2 ; i++ ) { - std::pair bb = namedview_dim_snap_list_scale(_desktop->namedview, - Snapper::BBOX_POINT, _bbox_points, - _origin, s[i], NR::Dim2(i), it); - std::pair sn = namedview_dim_snap_list_scale(_desktop->namedview, - Snapper::SNAP_POINT, _snap_points, - _origin, s[i], NR::Dim2(i), it); - - /* Pick the snap that puts us closest to the original scale */ - NR::Coord bd = bb.second ? fabs(bb.first - s[i]) : NR_HUGE; - NR::Coord sd = sn.second ? fabs(sn.first - s[i]) : NR_HUGE; - s[i] = (bd < sd) ? bb.first : sn.first; - } + + std::pair bb = m.freeSnapScale(Snapper::BBOX_POINT, + _bbox_points, + it, + s, + _origin); + std::pair sn = m.freeSnapScale(Snapper::SNAP_POINT, + _snap_points, + it, + s, + _origin); + + /* Pick the snap that puts us closest to the original scale */ + NR::Coord bd = bb.second ? + fabs(NR::L2(NR::Point(bb.first[NR::X], bb.first[NR::Y])) - + NR::L2(NR::Point(s[NR::X], s[NR::Y]))) + : NR_HUGE; + NR::Coord sd = sn.second ? + fabs(NR::L2(NR::Point(sn.first[NR::X], sn.first[NR::Y])) - + NR::L2(NR::Point(s[NR::X], s[NR::Y]))) + : NR_HUGE; + s = (bd < sd) ? bb.first : sn.first; } /* Update the knot position */ @@ -889,34 +966,60 @@ gboolean Inkscape::SelTrans::stretchRequest(SPSelTransHandle const &handle, NR:: it.push_back(reinterpret_cast(i->data)); } + SnapManager const &m = _desktop->namedview->snap_manager; + if ( state & GDK_CONTROL_MASK ) { s[perp] = fabs(s[axis]); - std::pair sn = namedview_vector_snap_list(_desktop->namedview, - Snapper::BBOX_POINT, - _bbox_points, _origin, s, it); - std::pair bb = namedview_vector_snap_list(_desktop->namedview, - Snapper::SNAP_POINT, - _snap_points, _origin, s, it); - - double bd = bb.second ? fabs(bb.first - s[axis]) : NR_HUGE; - double sd = sn.second ? fabs(sn.first - s[axis]) : NR_HUGE; - double ratio = (bd < sd) ? bb.first : sn.first; + std::pair const bb = m.freeSnapStretch( + Snapper::BBOX_POINT, + _bbox_points, + it, + s[axis], + _origin, + axis, + true); + + std::pair const sn = m.freeSnapStretch( + Snapper::SNAP_POINT, + _snap_points, + it, + s[axis], + _origin, + axis, + true); + + NR::Coord const bd = bb.second ? fabs(bb.first - s[axis]) : NR_HUGE; + NR::Coord const sd = sn.second ? fabs(sn.first - s[axis]) : NR_HUGE; + NR::Coord const ratio = (bd < sd) ? bb.first : sn.first; s[axis] = fabs(ratio) * sign(s[axis]); s[perp] = fabs(s[axis]); } else { - std::pair bb = namedview_dim_snap_list_scale(_desktop->namedview, Snapper::BBOX_POINT, - _bbox_points, _origin, - s[axis], axis, it); - std::pair sn = namedview_dim_snap_list_scale(_desktop->namedview, Snapper::SNAP_POINT, - _snap_points, _origin, - s[axis], axis, it); - - /* Pick the snap that puts us closest to the original scale */ - NR::Coord bd = bb.second ? fabs(bb.first - s[axis]) : NR_HUGE; - NR::Coord sd = sn.second ? fabs(sn.first - s[axis]) : NR_HUGE; + + std::pair const bb = m.freeSnapStretch( + Snapper::BBOX_POINT, + _bbox_points, + it, + s[axis], + _origin, + axis, + false); + + std::pair const sn = m.freeSnapStretch( + Snapper::SNAP_POINT, + _snap_points, + it, + s[axis], + _origin, + axis, + false); + + /* Choose the smaller difference in scale */ + NR::Coord const bd = bb.second ? fabs(bb.first - s[axis]) : NR_HUGE; + NR::Coord const sd = sn.second ? fabs(sn.first - s[axis]) : NR_HUGE; s[axis] = (bd < sd) ? bb.first : sn.first; + s[perp] = 1; } pt = ( _point - _origin ) * NR::scale(s) + _origin; @@ -982,9 +1085,28 @@ gboolean Inkscape::SelTrans::skewRequest(SPSelTransHandle const &handle, NR::Poi } skew[dim_a] = tan(radians) * s[dim_a]; } else { - skew[dim_a] = namedview_dim_snap_list_skew(_desktop->namedview, - Snapper::SNAP_POINT, _snap_points, - _origin, skew[dim_a], dim_b); + SnapManager const &m = _desktop->namedview->snap_manager; + + std::pair bb = m.freeSnapSkew(Inkscape::Snapper::BBOX_POINT, + _bbox_points, + std::list(), + skew[dim_a], + _origin, + dim_b); + + std::pair sn = m.freeSnapSkew(Inkscape::Snapper::SNAP_POINT, + _snap_points, + std::list(), + skew[dim_a], + _origin, + dim_b); + + if (bb.second || sn.second) { + /* We snapped something, so change the skew to reflect it */ + NR::Coord const bd = bb.second ? bb.first : NR_HUGE; + NR::Coord const sd = sn.second ? sn.first : NR_HUGE; + skew[dim_a] = std::min(bd, sd); + } } pt[dim_b] = ( _point[dim_a] - _origin[dim_a] ) * skew[dim_a] + _point[dim_b]; @@ -1057,7 +1179,7 @@ gboolean Inkscape::SelTrans::centerRequest(NR::Point &pt, guint state) using NR::X; using NR::Y; - SnapManager const m(_desktop->namedview); + SnapManager const &m = _desktop->namedview->snap_manager; pt = m.freeSnap(Snapper::SNAP_POINT, pt, NULL).getPoint(); if (state & GDK_CONTROL_MASK) { @@ -1068,22 +1190,21 @@ gboolean Inkscape::SelTrans::centerRequest(NR::Point &pt, guint state) } } - if (!(state & GDK_SHIFT_MASK)) { + if ( !(state & GDK_SHIFT_MASK) && _box ) { // screen pixels to snap center to bbox #define SNAP_DIST 5 // FIXME: take from prefs double snap_dist = SNAP_DIST / _desktop->current_zoom(); for (int i = 0; i < 2; i++) { - - if (fabs(pt[i] - _box.min()[i]) < snap_dist) { - pt[i] = _box.min()[i]; + if (fabs(pt[i] - _box->min()[i]) < snap_dist) { + pt[i] = _box->min()[i]; } - if (fabs(pt[i] - _box.midpoint()[i]) < snap_dist) { - pt[i] = _box.midpoint()[i]; + if (fabs(pt[i] - _box->midpoint()[i]) < snap_dist) { + pt[i] = _box->midpoint()[i]; } - if (fabs(pt[i] - _box.max()[i]) < snap_dist) { - pt[i] = _box.max()[i]; + if (fabs(pt[i] - _box->max()[i]) < snap_dist) { + pt[i] = _box->max()[i]; } } } @@ -1163,11 +1284,15 @@ void Inkscape::SelTrans::stretch(SPSelTransHandle const &handle, NR::Point &pt, s[!dim] = fabs(s[dim]); } - NR::Point new_bbox_min = _box.min() * (NR::translate(-scale_origin) * NR::Matrix(s) * NR::translate(scale_origin)); - NR::Point new_bbox_max = _box.max() * (NR::translate(-scale_origin) * NR::Matrix(s) * NR::translate(scale_origin)); + if (!_box) { + return; + } + + NR::Point new_bbox_min = _box->min() * (NR::translate(-scale_origin) * NR::Matrix(s) * NR::translate(scale_origin)); + NR::Point new_bbox_max = _box->max() * (NR::translate(-scale_origin) * NR::Matrix(s) * NR::translate(scale_origin)); int transform_stroke = prefs_get_int_attribute ("options.transform", "stroke", 1); - NR::Matrix scaler = get_scale_transform_with_stroke (_box, _strokewidth, transform_stroke, + NR::Matrix scaler = get_scale_transform_with_stroke (*_box, _strokewidth, transform_stroke, new_bbox_min[NR::X], new_bbox_min[NR::Y], new_bbox_max[NR::X], new_bbox_max[NR::Y]); transform(scaler, NR::Point(0, 0)); // we have already accounted for origin, so pass 0,0 @@ -1175,6 +1300,10 @@ void Inkscape::SelTrans::stretch(SPSelTransHandle const &handle, NR::Point &pt, void Inkscape::SelTrans::scale(NR::Point &pt, guint state) { + if (!_box) { + return; + } + NR::Point const offset = _point - _origin; NR::scale s (1, 1); @@ -1184,11 +1313,11 @@ void Inkscape::SelTrans::scale(NR::Point &pt, guint state) if (fabs(s[i]) < 1e-9) s[i] = 1e-9; } - NR::Point new_bbox_min = _box.min() * (NR::translate(-_origin) * NR::Matrix(s) * NR::translate(_origin)); - NR::Point new_bbox_max = _box.max() * (NR::translate(-_origin) * NR::Matrix(s) * NR::translate(_origin)); + NR::Point new_bbox_min = _box->min() * (NR::translate(-_origin) * NR::Matrix(s) * NR::translate(_origin)); + NR::Point new_bbox_max = _box->max() * (NR::translate(-_origin) * NR::Matrix(s) * NR::translate(_origin)); int transform_stroke = prefs_get_int_attribute ("options.transform", "stroke", 1); - NR::Matrix scaler = get_scale_transform_with_stroke (_box, _strokewidth, transform_stroke, + NR::Matrix scaler = get_scale_transform_with_stroke (*_box, _strokewidth, transform_stroke, new_bbox_min[NR::X], new_bbox_min[NR::Y], new_bbox_max[NR::X], new_bbox_max[NR::Y]); transform(scaler, NR::Point(0, 0)); // we have already accounted for origin, so pass 0,0 @@ -1257,7 +1386,7 @@ void sp_sel_trans_center(Inkscape::SelTrans *seltrans, SPSelTransHandle const &, void Inkscape::SelTrans::moveTo(NR::Point const &xy, guint state) { - SnapManager const m(_desktop->namedview); + SnapManager const &m = _desktop->namedview->snap_manager; /* The amount that we've moved by during this drag */ NR::Point dxy = xy - _point; @@ -1299,10 +1428,15 @@ void Inkscape::SelTrans::moveTo(NR::Point const &xy, guint state) for (unsigned int dim = 0; dim < 2; dim++) { s.push_back(m.constrainedSnapTranslation(Inkscape::Snapper::BBOX_POINT, _bbox_points, - component_vectors[dim], it, dxy)); + it, + Inkscape::Snapper::ConstraintLine(component_vectors[dim]), + dxy)); + s.push_back(m.constrainedSnapTranslation(Inkscape::Snapper::SNAP_POINT, _snap_points, - component_vectors[dim], it, dxy)); + it, + Inkscape::Snapper::ConstraintLine(component_vectors[dim]), + dxy)); } } else {