21#include <gdk/gdkkeysyms.h>
22#include <glibmm/i18n.h>
23#include <giomm/application.h>
66#define SP_SELECT_CONTEXT(obj) (dynamic_cast<Inkscape::UI::Tools::SelectTool*>((Inkscape::UI::Tools::ToolBase*)obj))
94 Observer(
"/tools/bounding_box"),
101 _sel_trans._boundingBoxPrefsChanged(
static_cast<int>(val.
getBool()));
115 int prefs_bbox = prefs->
getBool(
"/tools/bounding_box");
119 g_return_if_fail(
desktop !=
nullptr);
132 _norm->set_visible(
false);
135 _grip->set_visible(
false);
139 i->set_visible(
false);
157 _sel_changed_connection.disconnect();
158 _sel_modified_connection.disconnect();
160 for (
auto &knot : knots) {
173 for (
auto &_item : _items) {
178 _objects_const.clear();
179 _items_affines.clear();
180 _items_centers.clear();
186 for (
auto old_obj :_stamp_cache) {
187 auto oldLPEObj = cast<SPLPEItem>(old_obj);
192 if(!_stamp_cache.empty()){
193 _stamp_cache.clear();
199 _state = STATE_SCALE;
205 bool show_align = prefs->
getBool(
"/dialogs/align/oncanvas",
false);
207 if (_state == STATE_SCALE) {
208 _state = STATE_ROTATE;
209 }
else if (_state == STATE_ROTATE && show_align) {
210 _state = STATE_ALIGN;
212 _state = STATE_SCALE;
215 _center_is_set =
true;
223 _center_is_set =
true;
226 auto items= _desktop->getSelection()->items();
227 for (
auto it :
items) {
242 g_return_if_fail(!_grabbed);
245 _show_handles = show_handles;
246 _updateVolatileState();
247 _current_relative_affine.setIdentity();
255 auto items= _desktop->getSelection()->items();
258 _items.push_back(it);
259 _objects_const.push_back(it);
261 _items_centers.push_back(it->
getCenter());
264 if (y != -1 && _desktop->is_yaxisdown()) {
275 _bbox = selection->
bounds(_snap_bbox_type);
280 if (_geometric_bbox) {
281 _point_geom = _geometric_bbox->min() + _geometric_bbox->dimensions() *
Geom::Scale(x, y);
288 _snap_points.clear();
292 if (_snap_points.size() > 200 && !(prefs->
getBool(
"/options/snapclosestonly/value",
false))) {
296 std::cerr <<
"Warning: limit of 200 snap sources reached, some will be ignored" << std::endl;
297 _snap_points.resize(200);
306 _bbox_points.clear();
314 bool c1 = (_items.size() > 0) && (_items.size() < 50);
315 bool c2 = prefs->
getBool(
"/options/snapclosestonly/value",
false);
316 if (translating && (c1 || c2)) {
318 for (
auto & _item : _items) {
335 _opposite_for_bboxpoints = _bbox->min() + _bbox->dimensions() *
Geom::Scale(1-x, 1-y);
336 if (snap_points_bbox) {
337 _opposite_for_specpoints = (*snap_points_bbox).min() + (*snap_points_bbox).dimensions() *
Geom::Scale(1-x, 1-y);
339 _opposite_for_specpoints = _opposite_for_bboxpoints;
341 _opposite = _opposite_for_bboxpoints;
347 if (prefs->
getBool(
"/options/snapclosestonly/value",
false)) {
348 _keepClosestPointOnly(p);
351 if ((x != -1) && (y != -1)) {
352 _norm->set_visible(
true);
353 _grip->set_visible(
true);
356 if (_show == SHOW_OUTLINE) {
358 i->set_visible(
true);
362 g_return_if_fail(_stamp_cache.empty());
367 g_return_if_fail(_grabbed);
368 g_return_if_fail(!_empty);
372 if (_show == SHOW_CONTENT) {
373 auto selection = _desktop->getSelection();
375 for (
unsigned i = 0; i < _items.size(); i++) {
377 if( is<SPRoot>(&
item) ) {
397 if (lpeitem && lpeitem->hasPathEffectRecursive()) {
406 for (
unsigned i = 0 ; i < 4 ; i++) {
407 p[i] = _bbox->corner(i) * affine;
409 for (
unsigned i = 0 ; i < 4 ; i++) {
410 _l[i]->set_coords(p[i], p[(i+1)%4]);
415 _current_relative_affine = affine;
422 g_return_if_fail(_grabbed);
424 _show_handles =
true;
426 _desktop->getSnapIndicator()->remove_snapsource();
429 _updateVolatileState();
431 for (
auto & _item : _items) {
435 _norm->set_visible(
false);
436 _grip->set_visible(
false);
438 if (_show == SHOW_OUTLINE) {
440 i->set_visible(
false);
446 _message_context.clear();
448 if (!_empty && _changed) {
449 if (!_current_relative_affine.isIdentity()) {
452 selection->
applyAffine(_current_relative_affine, (_show == SHOW_OUTLINE) ?
true :
false);
454 *_center *= _current_relative_affine;
455 _center_is_set =
true;
461 if (_show != SHOW_OUTLINE && !_current_relative_affine.isTranslation()) {
462 for (
unsigned i = 0; i < _items_centers.size(); i++) {
463 SPItem *currentItem = _items[i];
465 currentItem->
setCenter (_items_centers[i] * _current_relative_affine);
470 for (
unsigned i = 0; i < _items_centers.size(); i++) {
471 auto currentItem = cast<SPLPEItem>(_items[i]);
478 _objects_const.clear();
479 _items_affines.clear();
480 _items_centers.clear();
482 if (!_current_relative_affine.isIdentity()) {
485 if (_current_relative_affine.isTranslation()) {
486 DocumentUndo::done(_desktop->getDocument(), _(
"Move"), INKSCAPE_ICON(
"tool-pointer"));
487 }
else if (_current_relative_affine.withoutTranslation().isScale()) {
488 DocumentUndo::done(_desktop->getDocument(), _(
"Scale"), INKSCAPE_ICON(
"tool-pointer"));
489 }
else if (_current_relative_affine.withoutTranslation().isRotation()) {
490 DocumentUndo::done(_desktop->getDocument(), _(
"Rotate"), INKSCAPE_ICON(
"tool-pointer"));
492 DocumentUndo::done(_desktop->getDocument(), _(
"Skew"), INKSCAPE_ICON(
"tool-pointer"));
502 if (_center_is_set) {
504 auto items= _desktop->getSelection()->items();
509 DocumentUndo::done(_desktop->getDocument(), _(
"Set center"), INKSCAPE_ICON(
"tool-pointer"));
513 _objects_const.clear();
514 _items_affines.clear();
515 _items_centers.clear();
519 _desktop->getSnapIndicator()->remove_snaptarget();
529 bool fixup = !_grabbed;
530 if ( fixup && !_stamp_cache.empty() ) {
532 _stamp_cache.
clear();
538 std::vector<SPItem*> l;
539 if (!_stamp_cache.empty()) {
543 l.insert(l.end(), selection->
items().begin(), selection->
items().end());
547 for (
auto old_obj : l) {
548 auto oldLPEObj = cast<SPLPEItem>(old_obj);
554 std::vector<SPObject *> copies;
558 bool lpewritetransforms =
true;
559 for (
auto old_obj : l) {
560 auto oldLPEObj = cast<SPLPEItem>(old_obj);
564 std::vector<SPObject *> satellites = effect->effect_get_satellites();
565 for (
auto obj : satellites) {
567 lpewritetransforms =
false;
573 if (!oldLPEObj->optimizeTransforms() && selection->
includes(oldLPEObj)) {
574 lpewritetransforms =
false;
575 std::vector<SPObject *> satellites = effect->effect_get_satellites();
576 for (
auto obj : satellites) {
578 lpewritetransforms =
true;
586 for(
auto &original_item : l) {
598 copy_repr->
setAttribute(
"xlink:href", std::string(
"#") + original_item->getId());
599 copy_repr->
setAttribute(
"inkscape:transform-center-x", original_repr->
attribute(
"inkscape:transform-center-x"));
600 copy_repr->
setAttribute(
"inkscape:transform-center-y", original_repr->
attribute(
"inkscape:transform-center-y"));
608 SPItem *copy_item = (
SPItem *) _desktop->getDocument()->getObjectByRepr(copy_repr);
610 if (_show == SHOW_OUTLINE || clone) {
612 Geom::Affine const i2dnew( i2d * _current_relative_affine );
616 new_affine = original_item->transform.
inverse() * new_affine;
619 new_affine = original_item->transform;
621 if (original_item && copy_item && !clone) {
622 original_item->setTmpSuccessor(copy_item);
624 auto newLPEObj = cast<SPLPEItem>(copy_item);
634 !lpewritetransforms ||
640 copy_item->
setCenter(*_center * _current_relative_affine);
644 copies.push_back(copy_item);
646 for (
auto new_obj : copies) {
647 auto newLPEObj = cast<SPLPEItem>(new_obj);
648 if (newLPEObj && !clone) {
650 newLPEObj->forkPathEffectsIfNecessary(1,
true,
true);
654 for(
auto original_item : l) {
657 if (original_item && !clone) {
658 original_item->fixTmpSuccessors();
659 original_item->unsetTmpSuccessor();
662 DocumentUndo::done(_desktop->getDocument(), _(
"Stamp"), INKSCAPE_ICON(
"tool-pointer"));
665 if ( fixup && _stamped ) {
673 for (
auto & knot : knots)
676 if ( !_show_handles || _empty ) {
677 _desktop->getSelection()->setAnchor(0.0, 0.0,
false);
681 if (!_center_is_set) {
682 _center = _desktop->getSelection()->center();
683 _center_is_set =
true;
686 if ( _state == STATE_SCALE ) {
689 }
else if(_state == STATE_ALIGN) {
701 for (
int i = 0; i <
NUMHANDS; i++) {
702 if (knots[i]->is_selected()) {
703 double anchor_x, anchor_y = 0.0;
705 anchor_x = (_center->x() - _bbox->min()[
Geom::X]) / _bbox->dimensions()[
Geom::X];
706 anchor_y = (_center->y() - _bbox->min()[
Geom::Y]) / _bbox->dimensions()[
Geom::Y];
709 anchor_y = (
hands[i].
y - 0.5) * (-_desktop->yaxisdir()) + 0.5;
712 _desktop->getSelection()->setAnchor(anchor_x, anchor_y);
716 _desktop->getSelection()->setAnchor(0.0, 0.0,
false);
729 _bbox = selection->
bounds(_snap_bbox_type);
737 std::vector<SPItem *> vec(selection->
items().begin(), selection->
items().end());
746 auto const y_dir = _desktop->yaxisdir();
748 for (
int i = 0; i <
NUMHANDS; i++) {
749 if (
hands[i].type != type)
761 knots[i]->moveto(*_center);
767 for (
int i = 0; i <
NUMHANDS; i++) {
771 auto confine_mod = Modifier::get(Type::TRANS_CONFINE)->
get_label();
772 auto center_mod = Modifier::get(Type::TRANS_OFF_CENTER)->get_label();
773 auto increment_mod = Modifier::get(Type::TRANS_INCREMENT)->get_label();
775 switch (
hands[i].type) {
779 auto tip = Glib::ustring::compose(_(
"<b>Scale</b> selection; with <b>%1</b> to scale uniformly; with <b>%2</b> to scale around rotation center"), confine_mod, center_mod);
785 auto tip = Glib::ustring::compose(_(
"<b>Skew</b> selection; with <b>%1</b> to snap angle; with <b>%2</b> to skew around the opposite side"), increment_mod, center_mod);
791 auto tip = Glib::ustring::compose(_(
"<b>Rotate</b> selection; with <b>%1</b> to snap angle; with <b>%2</b> to rotate around the opposite corner"), increment_mod, center_mod);
797 auto tip = Glib::ustring::compose(_(
"<b>Center</b> of transformation: drag to reposition; scaling, rotation and skew with %1 also uses this center"), center_mod);
802 knots[i] =
new SPKnot(_desktop,
803 _(
"<b>Align</b> objects to the side clicked; <b>Shift</b> click to invert side; <b>Ctrl</b> to group whole selection."),
807 knots[i] =
new SPKnot(_desktop,
808 _(
"<b>Align</b> objects to the corner clicked; <b>Shift</b> click to invert side; <b>Ctrl</b> to group whole selection."),
812 knots[i] =
new SPKnot(_desktop,
813 _(
"<b>Align</b> objects to center; <b>Shift</b> click to center vertically instead of horizontally."),
820 knots[i]->setAnchor(
hands[i].anchor);
821 knots[i]->updateCtrl();
834 SP_SELECT_CONTEXT(knot->
desktop->
getTool())->_seltrans->handleGrab(
848 SP_SELECT_CONTEXT(knot->
desktop->
getTool())->_seltrans->handleNewEvent(
855 return SP_SELECT_CONTEXT(knot->
desktop->
getTool())->_seltrans->handleRequest(
862 SP_SELECT_CONTEXT(knot->
desktop->
getTool())->_seltrans->handleClick(
869 switch (handle.
type) {
871 if (state & GDK_SHIFT_MASK) {
873 auto items = _desktop->getSelection()->items();
874 for (
auto it :
items) {
877 _center_is_set =
false;
880 DocumentUndo::done(_desktop->getDocument(), _(
"Reset center"), INKSCAPE_ICON(
"tool-pointer"));
887 for (
auto & child_knot : knots) {
888 child_knot->selectKnot(
false);
899 align(state, handle);
907 grab(knot->
position(), handle.
x, handle.
y, FALSE, FALSE);
910 switch (handle.
type) {
913 _norm->set_visible(
false);
914 _grip->set_visible(
true);
918 _norm->set_visible(
true);
919 _grip->set_visible(
true);
933 for (
auto & _item : _items) {
934 if ( !_item->document ) {
938 switch (handle.
type) {
940 scale(*position, state);
943 stretch(handle, *position, state);
946 skew(handle, *position, state);
949 rotate(*position, state);
952 setCenter(*position);
972 if ((!off_center == !(_state == STATE_ROTATE)) && (handle.
type !=
HANDLE_CENTER)) {
974 _origin_for_bboxpoints = _opposite_for_bboxpoints;
975 _origin_for_specpoints = _opposite_for_specpoints;
976 }
else if (_center) {
978 _origin_for_bboxpoints = *_center;
979 _origin_for_specpoints = *_center;
984 if (request(handle, *position, state)) {
986 _grip->set_position(*position);
988 _norm->set_position(*position);
990 _norm->set_position(_origin);
1003 int prefs_bbox = prefs->
getBool(
"/tools/bounding_box");
1004 _snap_bbox_type = !prefs_bbox ?
1007 _updateVolatileState();
1008 _current_relative_affine.setIdentity();
1009 _center_is_set =
false;
1013 auto lpeitem = cast<SPLPEItem>(it);
1015 if (lpeitem && !lpeitem->lpe_initialized && (!is<SPGroup>(lpeitem) || !lpeitem->getAttribute(
"inkscape:groupmode"))) {
1027 _updateVolatileState();
1028 _current_relative_affine.setIdentity();
1033 _center_is_set =
false;
1041 _snap_bbox_type = !prefs_bbox ?
1044 _updateVolatileState();
1076 for (
unsigned int i = 0 ; i < 2 ; i++ ) {
1077 if (fabs(default_scale[i]) > 1) {
1078 default_scale[i] = round(default_scale[i]);
1079 }
else if (default_scale[i] != 0) {
1080 default_scale[i] = 1/round(1/(
MIN(default_scale[i], 10)));
1084 pt = _calcAbsAffineDefault(default_scale);
1095 if (fabs(default_scale[
Geom::X]) > fabs(default_scale[
Geom::Y])) {
1113 m.
setup(_desktop,
false, _objects_const);
1126 pt = _calcAbsAffineDefault(default_scale);
1133 pt = _calcAbsAffineGeom(geom_scale);
1137 _calcAbsAffineDefault(default_scale);
1138 _desktop->getSnapIndicator()->remove_snaptarget();
1148 _(
"<b>Scale</b>: %0.2f%% x %0.2f%%; with <b>%s</b> to lock ratio"),
1149 100 * _absolute_affine[0], 100 * _absolute_affine[3], confine_mod.c_str());
1169 g_assert_not_reached();
1176 default_scale[perp] = 1;
1181 geom_scale[perp] = 1;
1187 if (fabs(default_scale[axis]) > 1) {
1188 default_scale[axis] = round(default_scale[axis]);
1189 }
else if (default_scale[axis] != 0) {
1190 default_scale[axis] = 1/round(1/(
MIN(default_scale[axis], 10)));
1193 pt = _calcAbsAffineDefault(default_scale);
1199 m.
setup(_desktop,
false, _objects_const);
1221 default_scale[perp] = fabs(default_scale[axis]);
1222 geom_scale[perp] = fabs(geom_scale[axis]);
1232 pt = _calcAbsAffineDefault(default_scale);
1239 pt = _calcAbsAffineGeom(geom_scale);
1243 _calcAbsAffineDefault(default_scale);
1244 _desktop->getSnapIndicator()->remove_snaptarget();
1251 _(
"<b>Scale</b>: %0.2f%% x %0.2f%%; with <b>%s</b> to lock ratio"),
1252 100 * _absolute_affine[0], 100 * _absolute_affine[3], confine_mod.c_str());
1260 switch (handle.
type) {
1262 return scaleRequest(pt, state);
1264 return stretchRequest(handle, pt, state);
1266 return skewRequest(handle, pt, state);
1268 return rotateRequest(pt, state);
1270 return centerRequest(pt, state);
1304 g_assert_not_reached();
1311 Geom::Point const initial_delta = _point - _origin;
1317 if (fabs(initial_delta[dim_a]/d) < 1e-4) {
1329 if (fabs(
scale[dim_a]) < 1) {
1337 double radians = atan(skew[dim_a] /
scale[dim_a]);
1343 int snaps = prefs->
getInt(
"/options/rotationsnapsperpi/value", 12);
1345 double sections =
floor(radians * snaps / M_PI + .5);
1346 if (fabs(sections) >= snaps / 2) {
1347 sections =
sign(sections) * (snaps / 2 - 1);
1349 radians = (M_PI / snaps) * sections;
1351 skew[dim_a] = tan(radians) *
scale[dim_a];
1356 m.
setup(_desktop,
false, _objects_const);
1367 _desktop->getSnapIndicator()->remove_snaptarget();
1374 pt[dim_b] = initial_delta[dim_a] * skew[dim_a] + _point[dim_b];
1375 pt[dim_a] = initial_delta[dim_a] *
scale[dim_a] + _origin[dim_a];
1379 _relative_affine[2*dim_a + dim_a] = (pt[dim_a] - _origin[dim_a]) / initial_delta[dim_a];
1380 _relative_affine[2*dim_a + (dim_b)] = (pt[dim_b] - _point[dim_b]) / initial_delta[dim_a];
1381 _relative_affine[2*(dim_b) + (dim_a)] = 0;
1382 _relative_affine[2*(dim_b) + (dim_b)] = 1;
1384 for (
int i = 0; i < 2; i++) {
1385 if (fabs(_relative_affine[3*i]) < 1e-15) {
1386 _relative_affine[3*i] = 1e-15;
1392 double degrees =
mod360symm(Geom::deg_from_rad(radians));
1396 _(
"<b>Skew</b>: %0.2f°; with <b>%s</b> to snap angle"),
1397 degrees, increment_mod.c_str());
1413 int snaps = prefs->
getInt(
"/options/rotationsnapsperpi/value", 12);
1420 if (h1 < 1e-15)
return FALSE;
1423 if (fabs(h2) < 1e-15)
return FALSE;
1433 if (increments || confine) {
1437 radians = atan2(sin_t, cos_t);
1439 radians = ( M_PI / snaps ) *
floor( radians * snaps / M_PI + .5 );
1445 m.
setup(_desktop,
false, _objects_const);
1458 _desktop->getSnapIndicator()->remove_snaptarget();
1465 _relative_affine = r2 * r1.
inverse();
1472 double degrees =
mod360symm(Geom::deg_from_rad(radians));
1476 _(
"<b>Rotate</b>: %0.2f°; with <b>%s</b> to snap angle"), degrees, increment_mod.c_str());
1488 std::vector<SPItem *>
items(_selection->items().begin(), _selection->items().end());
1496 std::vector<Inkscape::Snapper::SnapConstraint> constraints;
1497 constraints.emplace_back(_point,
Geom::Point(1, 0));
1498 constraints.emplace_back(_point,
Geom::Point(0, 1));
1502 else if (!no_snap) {
1511 Glib::ustring xs(x_q.
string(_desktop->getNamedView()->display_units));
1512 Glib::ustring ys(y_q.
string(_desktop->getNamedView()->display_units));
1514 xs.c_str(), ys.c_str());
1520 Glib::ustring argument;
1523 std::cerr <<
"Inkscape::Seltrans::align: index out of bounds! " <<
index << std::endl;
1528 auto app = Gio::Application::get_default();
1529 app->activate_action(
"object-align", variant);
1551 transform(_relative_affine, _origin);
1556 transform(_relative_affine, _origin);
1579 m.
setup(_desktop,
true, _objects_const);
1582 }
else if (!no_snap) {
1588 m.
setup(_desktop,
false, _objects_const);
1591 std::list<Inkscape::SnappedPoint> s;
1631 if (bb_is_best && sn_is_best) {
1633 bb_is_best = !sn_is_best;
1639 }
else if (bb_is_best) {
1645 _desktop->getSnapIndicator()->set_new_snaptarget(best_snapped_point);
1648 _desktop->getSnapIndicator()->remove_snaptarget();
1666 transform(move, norm);
1673 Glib::ustring xs(x_q.
string(_desktop->getNamedView()->display_units));
1674 Glib::ustring ys(y_q.
string(_desktop->getNamedView()->display_units));
1676 _(
"<b>Move</b> by %s, %s; with <b>%s</b> to restrict to horizontal/vertical; with <b>%s</b> to disable snapping"),
1677 xs.c_str(), ys.c_str(), confine_mod.c_str(), no_snap_mod.c_str());
1687 return visual_handle_pos;
1690 if (!_geometric_bbox) {
1692 return visual_handle_pos;
1704 bool transform_stroke = prefs->
getBool(
"/options/transform/stroke",
true);
1705 bool preserve = prefs->
getBool(
"/options/preservetransform/value",
false);
1710 Geom::Rect new_geom_bbox =
Geom::Rect(_geometric_bbox->min() * abs_affine, _geometric_bbox->max() * abs_affine);
1724 for (
unsigned int i = 0 ; i < 2 ; i++ ) {
1725 if ( fabs(initial_delta[i]) > 1e-6 ) {
1729 scale[i] = new_delta[i] / initial_delta[i];
1741 Geom::Point new_bbox_min = _stroked_bbox->min() * abs_affine;
1742 Geom::Point new_bbox_max = _stroked_bbox->max() * abs_affine;
1744 bool transform_stroke =
false;
1745 bool preserve =
false;
1746 gdouble stroke_x = 0;
1747 gdouble stroke_y = 0;
1751 transform_stroke = prefs->
getBool(
"/options/transform/stroke",
true);
1752 preserve = prefs->
getBool(
"/options/preservetransform/value",
false);
1753 stroke_x = _stroked_bbox->width() - _geometric_bbox->width();
1754 stroke_y = _stroked_bbox->height() - _geometric_bbox->height();
1761 return ( _point - _origin ) * default_scale + _origin;
1771 bool const transform_stroke = prefs->
getBool(
"/options/transform/stroke",
true);
1772 if (_geometric_bbox) {
1781 g_warning(
"No geometric bounding box has been calculated; this is a bug that needs fixing!");
1782 return _calcAbsAffineDefault(geom_scale);
1791 _snap_points.clear();
1796 _bbox_points.clear();
1799 _all_snap_sources_sorted = _snap_points;
1800 _all_snap_sources_sorted.insert(_all_snap_sources_sorted.end(), _bbox_points.begin(), _bbox_points.end());
1803 for(
auto & i : _all_snap_sources_sorted) {
1804 i.setDistance(
Geom::L2(i.getPoint() - p));
1808 std::sort(_all_snap_sources_sorted.begin(), _all_snap_sources_sorted.end());
1811 _snap_points.clear();
1812 _bbox_points.clear();
1813 if (!_all_snap_sources_sorted.empty()) {
1814 _all_snap_sources_iter = _all_snap_sources_sorted.begin();
1816 _bbox_points.push_back(_all_snap_sources_sorted.front());
1818 _snap_points.push_back(_all_snap_sources_sorted.front());
1827 if (prefs->
getBool(
"/options/snapclosestonly/value",
false)) {
1828 if (!_all_snap_sources_sorted.empty()) {
1830 if (_all_snap_sources_iter == _all_snap_sources_sorted.begin()) {
1831 _all_snap_sources_iter = _all_snap_sources_sorted.end();
1833 --_all_snap_sources_iter;
1835 ++_all_snap_sources_iter;
1836 if (_all_snap_sources_iter == _all_snap_sources_sorted.end()) {
1837 _all_snap_sources_iter = _all_snap_sources_sorted.begin();
1841 _snap_points.clear();
1842 _bbox_points.clear();
1845 _bbox_points.push_back(*_all_snap_sources_iter);
1847 _snap_points.push_back(*_all_snap_sources_iter);
3x3 matrix representing an affine transformation.
void setIdentity()
Sets this matrix to be the Identity Affine.
Affine inverse() const
Compute the inverse matrix.
CPoint min() const
Get the corner of the rectangle with smallest coordinate values.
CPoint dimensions() const
Get rectangle's width and height as a point.
CPoint max() const
Get the corner of the rectangle with largest coordinate values.
Axis-aligned rectangle that can be empty.
Two-dimensional point that doubles as a vector.
Axis aligned, non-empty rectangle.
Rotation around the origin.
static void done(SPDocument *document, Glib::ustring const &event_description, Glib::ustring const &undo_icon, unsigned int object_modified_tag=0)
A class to represent ways functionality is driven by shift modifiers.
bool active(int button_state) const
Test if this modifier is currently active.
std::string get_label() const
static Modifier * get(Type index)
A function to turn an enum index into a modifier object.
SPItemRange items()
Returns a range of selected SPItems.
Geom::OptRect bounds(SPItem::BBoxType type) const
Returns the bounding rectangle of the selection.
void applyAffine(Geom::Affine const &affine, bool set_i2d=true, bool compensate=true, bool adjust_transf_center=true)
Apply matrix to the selection.
Geom::OptRect strokedBounds() const
void clear()
Unselects all selected objects.
Geom::OptRect geometricBounds() const
bool isEmpty()
Returns true if no items are selected.
Data type representing a typeless value of a preference.
bool getBool(bool def=false) const
Interpret the preference as a Boolean value.
Preference storage class.
bool getBool(Glib::ustring const &pref_path, bool def=false)
Retrieve a Boolean value.
static Preferences * get()
Access the singleton Preferences object.
int getInt(Glib::ustring const &pref_path, int def=0)
Retrieve an integer.
void addObserver(Observer &)
Register a preference observer.
Geom::Scale getScaleSnapped()
Geom::Coord getSkewSnapped()
Geom::Coord getMagnitude()
Geom::Scale getStretchSnapped()
Geom::Point getTranslationSnapped()
void notify(Preferences::Entry const &val) override
Notification about a preference change.
BoundingBoxPrefsObserver(SelTrans &sel_trans)
void moveTo(Geom::Point const &xy, unsigned int state)
void align(guint state, SPSelTransHandle const &handle)
std::vector< Inkscape::SnapCandidatePoint > _all_snap_sources_sorted
void handleGrab(SPKnot *knot, unsigned int state, SPSelTransHandle const &handle)
SelTrans(SPDesktop *desktop)
void stretch(SPSelTransHandle const &handle, Geom::Point &pt, unsigned int state)
Geom::OptRect _stroked_bbox
void setCenter(Geom::Point const &p)
Geom::Point _getGeomHandlePos(Geom::Point const &visual_handle_pos)
BoundingBoxPrefsObserver _bounding_box_prefs_observer
Geom::Affine _current_relative_affine
bool _center_is_set
we've already set _center, no need to reread it from items
void rotate(Geom::Point &pt, unsigned int state)
Geom::Point _calcAbsAffineDefault(Geom::Scale const default_scale)
int rotateRequest(Geom::Point &pt, unsigned int state)
Inkscape::Selection * _selection
int handleRequest(SPKnot *knot, Geom::Point *position, unsigned int state, SPSelTransHandle const &handle)
CanvasItemPtr< CanvasItemCtrl > _grip
int skewRequest(SPSelTransHandle const &handle, Geom::Point &pt, unsigned int state)
sigc::connection _sel_modified_connection
void _boundingBoxPrefsChanged(int prefs_bbox)
void getNextClosestPoint(bool reverse)
sigc::connection _sel_changed_connection
void _showHandles(SPSelTransType type)
SPItem::BBoxType _snap_bbox_type
CanvasItemPtr< CanvasItemCtrl > _norm
void skew(SPSelTransHandle const &handle, Geom::Point &pt, unsigned int state)
void _selChanged(Inkscape::Selection *selection)
std::vector< Inkscape::SnapCandidatePoint >::iterator _all_snap_sources_iter
void handleNewEvent(SPKnot *knot, Geom::Point *position, unsigned int state, SPSelTransHandle const &handle)
void _updateVolatileState()
void _keepClosestPointOnly(Geom::Point const &p)
void handleClick(SPKnot *knot, unsigned int state, SPSelTransHandle const &handle)
void grab(Geom::Point const &p, double x, double y, bool show_handles, bool translating)
void scale(Geom::Point &pt, unsigned int state)
Geom::Point _calcAbsAffineGeom(Geom::Scale const geom_scale)
void stamp(bool clone=false)
int centerRequest(Geom::Point &pt, unsigned int state)
int stretchRequest(SPSelTransHandle const &handle, Geom::Point &pt, unsigned int state)
Inkscape::MessageContext _message_context
std::array< CanvasItemPtr< CanvasItemCurve >, 4 > _l
int request(SPSelTransHandle const &handle, Geom::Point &pt, unsigned int state)
void _selModified(Inkscape::Selection *selection, unsigned int flags)
void transform(Geom::Affine const &rel_affine, Geom::Point const &norm)
int scaleRequest(Geom::Point &pt, unsigned int state)
The set of selected SPObjects for a given document and layer model.
std::vector< Inkscape::SnapCandidatePoint > getSnapPoints(SnapPreferences const *snapprefs) const
Compute the list of points in the selection that are to be considered for snapping from.
bool includes(XML::Node *repr, bool anyAncestor=false)
Returns true if the given item is selected.
sigc::connection connectChanged(sigc::slot< void(Selection *)> slot)
Connects a slot to be notified of selection changes.
sigc::connection connectModified(sigc::slot< void(Selection *, unsigned)> slot)
Connects a slot to be notified of selected object modifications.
Class to store data for points which are snap candidates, either as a source or as a target.
bool isAnyDatumSnappable() const
bool isTargetSnappable(Inkscape::SnapTargetType const target) const
Class describing the result of an attempt to snap.
Geom::Point getPoint() const
bool isOtherSnapBetter(SnappedPoint const &other_one, bool weighted) const
Glib::ustring string(Unit const *u) const
Return a printable string of the value in the specified unit.
Interface for refcounted XML nodes.
virtual Node * parent()=0
Get the parent of this node.
virtual void addChild(Node *child, Node *after)=0
Insert another node as a child of this node.
void setAttribute(Util::const_char_ptr key, Util::const_char_ptr value)
Change an attribute of this node.
virtual Node * duplicate(Document *doc) const =0
Create a duplicate of this node.
virtual char const * attribute(char const *key) const =0
Get the string representation of a node's attribute.
virtual Document * document()=0
Get the node's associated document.
To do: update description of desktop.
Inkscape::CanvasItemGroup * getCanvasControls() const
Inkscape::Selection * getSelection() const
Inkscape::UI::Tools::ToolBase * getTool() const
Base class for visual SVG elements.
void set_i2d_affine(Geom::Affine const &transform)
Geom::Affine i2dt_affine() const
Returns the transformation from item to desktop coords.
Geom::Point getCenter(bool ensure_uptodate=true) const
void doWriteTransform(Geom::Affine const &transform, Geom::Affine const *adv=nullptr, bool compensate=true)
Set a new transform on an object.
void setCenter(Geom::Point const &object_centre)
Sets the transform_center_x and transform_center_y properties to retain the rotation center.
Desktop-bound visual control object.
void setPosition(Geom::Point const &p, unsigned int state)
Move knot to new position and emits "moved" signal.
static void unref(SPKnot *knot)
Geom::Point position() const
Returns position of knot.
SPDesktop * desktop
Desktop we are on.
void selectKnot(bool select)
Select knot.
Inkscape::XML::Node * updateRepr(unsigned int flags=SP_OBJECT_WRITE_EXT)
Updates the object's repr based on the object's state.
Class to coordinate snapping operations.
void displaySnapsource(Inkscape::SnapCandidatePoint const &p) const
Mark the location of the snap source (not the snap target!) on the canvas by drawing a symbol.
void setup(SPDesktop const *desktop, bool snapindicator=true, SPObject const *item_to_ignore=nullptr, std::vector< Inkscape::SnapCandidatePoint > *unselected_nodes=nullptr)
Convenience shortcut when there is only one item to ignore.
Geom::Point multipleOfGridPitch(Geom::Point const &t, Geom::Point const &origin)
Snap to the closest multiple of a grid pitch.
void freeSnapReturnByRef(Geom::Point &p, Inkscape::SnapSourceType const source_type, Geom::OptRect const &bbox_to_snap=Geom::OptRect()) const
Try to snap a point to grids, guides or objects.
SPNamedView const * getNamedView() const
void setRotationCenterSource(const std::vector< SPItem * > &items)
void snapTransformed(std::vector< Inkscape::SnapCandidatePoint > const &points, Geom::Point const &pointer, Inkscape::PureTransform &transform)
Method for snapping sets of points while they are being transformed.
Inkscape::SnappedPoint multipleConstrainedSnaps(Inkscape::SnapCandidatePoint const &p, std::vector< Inkscape::Snapper::SnapConstraint > const &constraints, bool dont_snap=false, Geom::OptRect const &bbox_to_snap=Geom::OptRect()) const
Inkscape::SnapPreferences & snapprefs
bool someSnapperMightSnap(bool immediately=true) const
Return true if any snapping might occur, whether its to grids, guides or objects.
gdouble stroke_average_width(const std::vector< SPItem * > &objects)
Determine average stroke width, simple method.
Editable view implementation.
static char const *const parent
TODO: insert short description here.
Dim2
2D axis enumeration (X or Y).
double Coord
Floating point type used to store coordinates.
auto floor(Geom::Rect const &rect)
Macro for icon names used in Inkscape.
Declarations for SPKnot: Desktop-bound visual control object.
Raw stack of active status messages.
double mod360symm(double const x)
Returns x wrapped around to between -180 and less than 180, or 0 if x isn't finite.
TODO: insert short description here.
Affine identity()
Create an identity matrix.
SBasis L2(D2< SBasis > const &a, unsigned k)
T dot(D2< T > const &a, D2< T > const &b)
D2< T > rot90(D2< T > const &a)
static R & release(R &r)
Decrements the reference count of a anchored object.
Type
This anonymous enum is used to provide a list of the Shifts.
@ SNAPSOURCE_ROTATION_CENTER
@ SNAPSOURCE_BBOX_CATEGORY
Geom::Scale calcScaleFactors(Geom::Point const &initial_point, Geom::Point const &new_point, Geom::Point const &origin, bool const skew=false)
@ SNAPTARGET_BBOX_EDGE_MIDPOINT
@ SNAPTARGET_OTHERS_CATEGORY
@ SNAPTARGET_BBOX_MIDPOINT
@ SNAPTARGET_ALIGNMENT_CATEGORY
@ SNAPTARGET_DISTRIBUTION_CATEGORY
@ SNAPTARGET_NODE_CATEGORY
@ SNAPTARGET_BBOX_CATEGORY
@ CANVAS_ITEM_CTRL_TYPE_CENTER
@ CANVAS_ITEM_CTRL_TYPE_ADJ_ROTATE
@ CANVAS_ITEM_CTRL_TYPE_ADJ_HANDLE
@ CANVAS_ITEM_CTRL_TYPE_MARKER
@ CANVAS_ITEM_CTRL_TYPE_ADJ_SALIGN
@ CANVAS_ITEM_CTRL_TYPE_ADJ_CALIGN
@ CANVAS_ITEM_CTRL_TYPE_ADJ_SKEW
@ CANVAS_ITEM_CTRL_TYPE_ADJ_MALIGN
@ CANVAS_ITEM_CTRL_TYPE_ADJ_CENTER
void getBBoxPoints(Geom::OptRect const bbox, std::vector< SnapCandidatePoint > *points, bool const isTarget, bool const corners, bool const edges, bool const midpoint)
Default version of the getBBoxPoints with default corner source types.
SiblingState
SiblingState enums are used to associate the current state while grabbing objects.
@ SIBLING_TEXT_SHAPE_INSIDE
SPSelTransHandle const hands[]
const int ALIGN_SHIFT_OFFSET
const std::vector< Glib::ustring > AlignArguments
static bool sp_sel_trans_handle_event(SPKnot *knot, Inkscape::CanvasEvent const &event, SPSelTransHandle const *)
static gboolean sp_sel_trans_handle_request(SPKnot *knot, Geom::Point *p, guint state, SPSelTransHandle const *data)
static void sp_sel_trans_handle_new_event(SPKnot *knot, Geom::Point const &position, guint32 state, SPSelTransHandle const *data)
static void sp_sel_trans_handle_ungrab(SPKnot *knot, guint state, SPSelTransHandle const *data)
static void sp_sel_trans_handle_grab(SPKnot *knot, guint state, SPSelTransHandle const *data)
static double sign(double const x)
Returns -1 or 1 according to the sign of x.
static void sp_sel_trans_handle_click(SPKnot *knot, guint state, SPSelTransHandle const *data)
Provides a class that shows a temporary indicator on the canvas of where the snap was,...
void sp_lpe_item_update_patheffect(SPLPEItem *lpeitem, bool wholetree, bool write, bool with_satellites)
Calls any registered handlers for the update_patheffect action.
void sp_lpe_item_enable_path_effects(SPLPEItem *lpeitem, bool enable)
bool sp_object_compare_position_bool(SPObject const *first, SPObject const *second)
SPObject * sp_object_unref(SPObject *object, SPObject *owner)
Decrease reference count of object, with possible debugging and finalization.
SPObject * sp_object_ref(SPObject *object, SPObject *owner)
Increase reference count of object, with possible debugging.
SPRoot: SVG <svg> implementation.
Abstract base class for events.
virtual Node * createElement(char const *name)=0