diff --git a/po/POTFILES.src.in b/po/POTFILES.src.in index fbcba2319c7f83f01ef093fd002a1093697a7237..5b4210d2c7701bf848ac0244ce64924e93163427 100644 --- a/po/POTFILES.src.in +++ b/po/POTFILES.src.in @@ -267,6 +267,7 @@ ${_build_dir}/share/templates/templates.h ../src/rdf.cpp ../src/selection-chemistry.cpp ../src/selection-describer.cpp +../src/selection.cpp ../src/seltrans-handles.cpp ../src/seltrans.cpp ../src/text-chemistry.cpp diff --git a/share/keys/inkscape.xml b/share/keys/inkscape.xml index a411da5f3d1e73395b8b9d7eef7c4a22af36de00..00fdbfaedb96142a2bf35a8e0159826b00e99079 100644 --- a/share/keys/inkscape.xml +++ b/share/keys/inkscape.xml @@ -284,8 +284,6 @@ override) the bindings in the main default.xml. - - @@ -302,12 +300,20 @@ override) the bindings in the main default.xml. + - - - - + + + + + + + + + + + diff --git a/share/keys/macromedia-freehand-mx.xml b/share/keys/macromedia-freehand-mx.xml index 53b1a57233205a77583af90e1e0f9d33a44bfb54..b6610201bb09532dbdf4c17864ac5185840ae92e 100644 --- a/share/keys/macromedia-freehand-mx.xml +++ b/share/keys/macromedia-freehand-mx.xml @@ -184,8 +184,6 @@ File, Edit, View, Modify, Text, Xtras, Window, Help. - - diff --git a/share/keys/right-handed-illustration.xml b/share/keys/right-handed-illustration.xml index 2f9a8d9bf51a2f93064629be5aba011c3f7a6a9b..ce438b1e1e474a56a9519e7d2931d1665fa96262 100644 --- a/share/keys/right-handed-illustration.xml +++ b/share/keys/right-handed-illustration.xml @@ -164,9 +164,6 @@ Future improvements: - - - diff --git a/share/keys/xara.xml b/share/keys/xara.xml index ee8224821e321d688e3a72ca861bfae399adfd01..95311dcf3e66e85042b5d6f0a6b05a27eb1df3ca 100644 --- a/share/keys/xara.xml +++ b/share/keys/xara.xml @@ -171,8 +171,6 @@ Hom/end keys-select minimum or maximum feather values - - diff --git a/src/actions/actions-object.cpp b/src/actions/actions-object.cpp index 51911e319663e0e810362067d930f6f7961b8371..b42729b23be82133d4e1a0f2b02cb27c4a4d038d 100644 --- a/src/actions/actions-object.cpp +++ b/src/actions/actions-object.cpp @@ -262,7 +262,7 @@ object_rotate_90_cw(InkscapeApplication *app) // Object Rotate 90 auto desktop = selection->desktop(); - selection->rotate((!desktop || desktop->is_yaxisdown()) ? 90 : -90); + selection->rotateAnchored((!desktop || desktop->is_yaxisdown()) ? 90 : -90); } void @@ -272,7 +272,7 @@ object_rotate_90_ccw(InkscapeApplication *app) // Object Rotate 90 CCW auto desktop = selection->desktop(); - selection->rotate((!desktop || desktop->is_yaxisdown()) ? -90 : 90); + selection->rotateAnchored((!desktop || desktop->is_yaxisdown()) ? -90 : 90); } void @@ -294,7 +294,7 @@ object_flip_horizontal(InkscapeApplication *app) } // Object Flip Horizontal - selection->setScaleRelative(center, Geom::Scale(-1.0, 1.0)); + selection->scaleRelative(center, Geom::Scale(-1.0, 1.0)); Inkscape::DocumentUndo::done(app->get_active_document(), _("Flip horizontally"), INKSCAPE_ICON("object-flip-horizontal")); } @@ -317,7 +317,7 @@ object_flip_vertical(InkscapeApplication *app) } // Object Flip Vertical - selection->setScaleRelative(center, Geom::Scale(1.0, -1.0)); + selection->scaleRelative(center, Geom::Scale(1.0, -1.0)); Inkscape::DocumentUndo::done(app->get_active_document(), _("Flip vertically"), INKSCAPE_ICON("object-flip-vertical")); } @@ -436,6 +436,7 @@ add_actions_object(InkscapeApplication* app) gapp->add_action( "object-set-inverse-mask", sigc::bind(sigc::ptr_fun(&object_mask_set_inverse), app)); gapp->add_action( "object-release-mask", sigc::bind(sigc::ptr_fun(&object_mask_release), app)); + // Depricated, see app.transform-rotate(90) gapp->add_action( "object-rotate-90-cw", sigc::bind(sigc::ptr_fun(&object_rotate_90_cw), app)); gapp->add_action( "object-rotate-90-ccw", sigc::bind(sigc::ptr_fun(&object_rotate_90_ccw), app)); gapp->add_action( "object-flip-horizontal", sigc::bind(sigc::ptr_fun(&object_flip_horizontal), app)); diff --git a/src/actions/actions-transform.cpp b/src/actions/actions-transform.cpp index 3f0ca733ad1c49155706f5c95205d32121288bd5..9b02b2db2791d5989eddaba395499a90b931a26b 100644 --- a/src/actions/actions-transform.cpp +++ b/src/actions/actions-transform.cpp @@ -14,8 +14,10 @@ #include #include "actions-helper.h" +#include "desktop.h" #include "document-undo.h" #include "inkscape-application.h" +#include "inkscape-window.h" #include "preferences.h" #include "selection.h" // Selection #include "page-manager.h" @@ -50,53 +52,62 @@ transform_translate(const Glib::VariantBase& value, InkscapeApplication *app) } void -transform_rotate(const Glib::VariantBase& value, InkscapeApplication *app) +transform_scale(const Glib::VariantBase& value, InkscapeApplication *app) { - Glib::Variant d = Glib::VariantBase::cast_dynamic >(value); - auto selection = app->get_active_selection(); - - selection->rotate(d.get()); + auto scale = (Glib::VariantBase::cast_dynamic>(value)).get(); + app->get_active_selection()->scaleAnchored(scale, false); +} - // Needed to update repr (is this the best way?). - Inkscape::DocumentUndo::done(app->get_active_document(), "ActionTransformRotate", ""); +void +transform_grow(const Glib::VariantBase& value, InkscapeApplication *app) +{ + auto scale = (Glib::VariantBase::cast_dynamic>(value)).get(); + app->get_active_selection()->scaleAnchored(scale); } void -transform_scale(const Glib::VariantBase& value, InkscapeApplication *app) +transform_grow_step(const Glib::VariantBase& value, InkscapeApplication *app) { - Glib::Variant d = Glib::VariantBase::cast_dynamic >(value); - auto selection = app->get_active_selection(); - selection->scale(d.get()); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - // Needed to update repr (is this the best way?). - Inkscape::DocumentUndo::done(app->get_active_document(), "ActionTransformScale", ""); + auto scale = (Glib::VariantBase::cast_dynamic>(value)).get(); + app->get_active_selection()->scaleAnchored(scale * prefs->getDoubleLimited("/options/defaultscale/value", 2, 0, 1000)); } void -transform_grow(const Glib::VariantBase& value, InkscapeApplication *app) +transform_grow_screen(const Glib::VariantBase& value, InkscapeWindow *win) { - Glib::Variant d = Glib::VariantBase::cast_dynamic >(value); - auto selection = app->get_active_selection(); - selection->scaleGrow(d.get()); + auto scale = (Glib::VariantBase::cast_dynamic>(value)).get(); + auto desktop = win->get_desktop(); + desktop->getSelection()->scaleAnchored(scale / desktop->current_zoom()); } void -transform_grow_step(const Glib::VariantBase& value, InkscapeApplication *app) +transform_rotate(const Glib::VariantBase& value, InkscapeApplication *app) +{ + auto angle = (Glib::VariantBase::cast_dynamic>(value)).get(); + app->get_active_selection()->rotateAnchored(angle); +} + +void +transform_rotate_step(const Glib::VariantBase& value, InkscapeApplication *app) { - Glib::Variant d = Glib::VariantBase::cast_dynamic >(value); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - auto selection = app->get_active_selection(); - selection->scaleGrow(d.get() * prefs->getDoubleLimited("/options/defaultscale/value", 2, 0, 1000)); + + auto angle = (Glib::VariantBase::cast_dynamic>(value)).get(); + app->get_active_selection()->rotateAnchored(angle / prefs->getInt("/options/rotationsnapsperpi/value", 12)); } void -transform_grow_screen(const Glib::VariantBase& value, InkscapeApplication *app) +transform_rotate_screen(const Glib::VariantBase& value, InkscapeWindow *win) { - Glib::Variant d = Glib::VariantBase::cast_dynamic >(value); - auto selection = app->get_active_selection(); - selection->scaleScreen(d.get()); + auto angle = (Glib::VariantBase::cast_dynamic>(value)).get(); + auto desktop = win->get_desktop(); + + desktop->getSelection()->rotateAnchored(angle, desktop->current_zoom()); } + void transform_remove(InkscapeApplication *app) { @@ -123,7 +134,7 @@ void page_rotate(const Glib::VariantBase& value, InkscapeApplication *app) Inkscape::DocumentUndo::done(document, "Rotate Page", INKSCAPE_ICON("tool-pages")); } -// SHOULD REALLY BE DOC LEVEL ACTIONS +// SHOULD REALLY BE SELECTION LEVEL ACTIONS std::vector> raw_data_transform = { // clang-format off {"app.transform-translate", N_("Translate"), "Transform", N_("Translate selected objects (dx,dy)")}, @@ -132,6 +143,10 @@ std::vector> raw_data_transform = { {"app.transform-grow", N_("Grow/Shrink"), "Transform", N_("Grow/shrink selected objects")}, {"app.transform-grow-step", N_("Grow/Shrink Step"), "Transform", N_("Grow/shrink selected objects by multiple of step value")}, {"app.transform-grow-screen", N_("Grow/Shrink Screen"), "Transform", N_("Grow/shrink selected objects relative to zoom level")}, + {"app.transform-rotate", N_("Rotate"), "Transform", N_("Rotate selected objects")}, + {"app.transform-rotate-step", N_("Rotate Step"), "Transform", N_("Rotate selected objects by multiple of step value")}, + {"app.transform-rotate-screen", N_("Rotate Screen"), "Transform", N_("Rotate selected objects relative to zoom level")}, + {"app.transform-remove", N_("Remove Transforms"), "Transform", N_("Remove any transforms from selected objects")}, {"app.transform-reapply", N_("Reapply Transforms"), "Transform", N_("Reapply the last transformation to the selection")}, {"app.page-rotate", N_("Rotate Page 90°"), "Transform", N_("Rotate page by 90-degree rotation steps")}, @@ -154,6 +169,7 @@ std::vector> hint_data_transform = void add_actions_transform(InkscapeApplication* app) { + // If these ever get moved to the Inkscape::Selection object, the screen and app based ones can be combined again. Glib::VariantType Bool( Glib::VARIANT_TYPE_BOOL); Glib::VariantType Int( Glib::VARIANT_TYPE_INT32); Glib::VariantType Double(Glib::VARIANT_TYPE_DOUBLE); @@ -167,7 +183,8 @@ add_actions_transform(InkscapeApplication* app) gapp->add_action_with_parameter( "transform-scale", Double, sigc::bind(sigc::ptr_fun(&transform_scale), app)); gapp->add_action_with_parameter( "transform-grow", Double, sigc::bind(sigc::ptr_fun(&transform_grow), app)); gapp->add_action_with_parameter( "transform-grow-step", Double, sigc::bind(sigc::ptr_fun(&transform_grow_step), app)); - gapp->add_action_with_parameter( "transform-grow-screen", Double, sigc::bind(sigc::ptr_fun(&transform_grow_screen), app)); + gapp->add_action_with_parameter( "transform-rotate", Double, sigc::bind(sigc::ptr_fun(&transform_rotate), app)); + gapp->add_action_with_parameter( "transform-rotate-step", Double, sigc::bind(sigc::ptr_fun(&transform_rotate_step), app)); gapp->add_action( "transform-remove", sigc::bind(sigc::ptr_fun(&transform_remove), app)); gapp->add_action( "transform-reapply", sigc::bind(sigc::ptr_fun(&transform_reapply), app)); gapp->add_action_with_parameter( "page-rotate", Int, sigc::bind(sigc::ptr_fun(&page_rotate), app)); @@ -177,6 +194,16 @@ add_actions_transform(InkscapeApplication* app) app->get_action_hint_data().add_data(hint_data_transform); } +void +add_actions_transform(InkscapeWindow* win) +{ + Glib::VariantType Double(Glib::VARIANT_TYPE_DOUBLE); + + win->add_action_with_parameter( "transform-grow-screen", Double, sigc::bind(sigc::ptr_fun(&transform_grow_screen), win)); + win->add_action_with_parameter( "transform-rotate-screen", Double, sigc::bind(sigc::ptr_fun(&transform_rotate_screen), win)); + + // action data already added above by app actions. +} /* Local Variables: diff --git a/src/actions/actions-transform.h b/src/actions/actions-transform.h index 9b1b0dc3da38a3fefdfde4585846eccb3a19d001..7f26228d1d94acbd10eddb70be7e23f32eaa692d 100644 --- a/src/actions/actions-transform.h +++ b/src/actions/actions-transform.h @@ -12,8 +12,10 @@ #define INK_ACTIONS_TRANSFORM_H class InkscapeApplication; +class InkscapeWindow; void add_actions_transform(InkscapeApplication* app); +void add_actions_transform(InkscapeWindow* win); #endif // INK_ACTIONS_TRANSFORM_H diff --git a/src/inkscape-window.cpp b/src/inkscape-window.cpp index 4532ee1d3197646363ad40223c91836c2942a5e0..b2fb1e8fc72afdb2be1c4857d098aa581e5e7a98 100644 --- a/src/inkscape-window.cpp +++ b/src/inkscape-window.cpp @@ -41,6 +41,7 @@ #include "actions/actions-paths.h" // TEMP #include "actions/actions-selection-window.h" #include "actions/actions-tools.h" +#include "actions/actions-transform.h" #include "actions/actions-view-mode.h" #include "actions/actions-view-window.h" #include "inkscape.h" @@ -83,12 +84,13 @@ InkscapeWindow::InkscapeWindow(SPDesktop *desktop) add_actions_help_url(this); // Actions to help url. add_actions_layer(this); // Actions for layer. add_actions_node_align(this); // Actions to align and distribute nodes (requiring Node tool). + add_actions_page_tools(this); // Actions specific to pages tool and toolbar add_actions_path(this); // Actions for paths. TEMP add_actions_select_window(this); // Actions with desktop selection add_actions_tools(this); // Actions to switch between tools. + add_actions_transform(this); // Actions for transforming against the screen zoom add_actions_view_mode(this); // Actions to change how Inkscape canvas is displayed. add_actions_view_window(this); // Actions to add/change window of Inkscape - add_actions_page_tools(this); // Actions specific to pages tool and toolbar // Add document action group to window and export to DBus. add_document_actions(); diff --git a/src/object/object-set.h b/src/object/object-set.h index 0b7c7b7a0476e612f13bcf8c52b620a52c41aa23..c869e5fd4cbd919ccf6f6c76e18b36a6d0717a16 100644 --- a/src/object/object-set.h +++ b/src/object/object-set.h @@ -477,16 +477,11 @@ public: void removePathTransforms(); void removeTransform(); void setScaleAbsolute(double, double, double, double); - void setScaleRelative(const Geom::Point&, const Geom::Scale&); + void scaleRelative(const Geom::Point&, const Geom::Scale&); void rotateRelative(const Geom::Point&, double); void skewRelative(const Geom::Point&, double, double); void moveRelative(const Geom::Point &move, bool compensate = true); void moveRelative(double dx, double dy); - void rotate(double); - void rotateScreen(double); - void scaleGrow(double); - void scaleScreen(double); - void scale(double); void move(double dx, double dy); void moveScreen(double dx, double dy); void move(double dx, double dy, bool rotated); diff --git a/src/object/sp-marker.cpp b/src/object/sp-marker.cpp index f38502ce28529a8cdd64501729b82cd31a2cc30f..2a28c079163d01a671243c842002fd5a799da075 100644 --- a/src/object/sp-marker.cpp +++ b/src/object/sp-marker.cpp @@ -635,7 +635,7 @@ void sp_marker_flip_horizontally(SPMarker* marker) { set.addList(marker->item_list()); Geom::OptRect bbox = set.visualBounds(); if (bbox) { - set.setScaleRelative(bbox->midpoint(), Geom::Scale(-1.0, 1.0)); + set.scaleRelative(bbox->midpoint(), Geom::Scale(-1.0, 1.0)); if (marker->document) { DocumentUndo::maybeDone(marker->document, "marker", _("Flip marker horizontally"), INKSCAPE_ICON("dialog-fill-and-stroke")); } diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 8564130862f90287bb89b151e30f78121b20cf5d..cf33e11b4d380fbcdad721916782ef0ffa9a3097 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -1880,7 +1880,7 @@ void ObjectSet::setScaleAbsolute(double x0, double x1,double y0, double y1) applyAffine(final); } -void ObjectSet::setScaleRelative(Geom::Point const &align, Geom::Scale const &scale) +void ObjectSet::scaleRelative(Geom::Point const &align, Geom::Scale const &scale) { if (isEmpty()) return; @@ -1934,30 +1934,6 @@ void ObjectSet::moveRelative(double dx, double dy) applyAffine(Geom::Affine(Geom::Translate(dx, dy))); } -void ObjectSet::rotate(gdouble const angle_degrees) -{ - if (isEmpty()) - return; - - std::optional center_ = center(); - if (!center_) { - return; - } - rotateRelative(*center_, angle_degrees); - - if (document()) { - if (angle_degrees == 90.0) { - DocumentUndo::done(document(), _("Rotate 90\xc2\xb0 CW"), INKSCAPE_ICON("object-rotate-right")); - } else if (angle_degrees == -90.0) { - DocumentUndo::done(document(), _("Rotate 90\xc2\xb0 CCW"), INKSCAPE_ICON("object-rotate-left")); - } else { - DocumentUndo::maybeDone(document(), - ( ( angle_degrees > 0 )? "selector:rotate:ccw": "selector:rotate:cw" ), - _("Rotate"), INKSCAPE_ICON("tool-pointer")); - } - } -} - /* * Selects all the visible items with the same fill and/or stroke color/style as the items in the current selection * @@ -2275,100 +2251,6 @@ std::vector sp_get_same_style(SPItem *sel, std::vector &src, S return matches; } -// helper function: -static -Geom::Point -cornerFarthestFrom(Geom::Rect const &r, Geom::Point const &p){ - Geom::Point m = r.midpoint(); - unsigned i = 0; - if (p[X] < m[X]) { - i = 1; - } - if (p[Y] < m[Y]) { - i = 3 - i; - } - return r.corner(i); -} - -/** -\param angle the angle in "angular pixels", i.e. how many visible pixels must move the outermost point of the rotated object -*/ -void ObjectSet::rotateScreen(double angle) -{ - if (isEmpty()||!desktop()) - return; - - Geom::OptRect bbox = visualBounds(); - std::optional center_ = center(); - - if ( !bbox || !center_ ) { - return; - } - - gdouble const zoom = desktop()->current_zoom(); - gdouble const zmove = angle / zoom; - gdouble const r = Geom::L2(cornerFarthestFrom(*bbox, *center_) - *center_); - - gdouble const zangle = 180 * atan2(zmove, r) / M_PI; - - rotateRelative(*center_, zangle); - - DocumentUndo::maybeDone(document(), - ( (angle > 0) ? "selector:rotate:ccw": "selector:rotate:cw" ), - _("Rotate by pixels"), INKSCAPE_ICON("tool-pointer")); -} - -void ObjectSet::scaleGrow(double grow) -{ - if (isEmpty()) - return; - - Geom::OptRect bbox = visualBounds(); - if (!bbox) { - return; - } - - Geom::Point const center_(bbox->midpoint()); - - // you can't scale "do nizhe pola" (below zero) - double const max_len = bbox->maxExtent(); - if ( max_len + grow <= 1e-3 ) { - return; - } - - double const times = 1.0 + grow / max_len; - setScaleRelative(center_, Geom::Scale(times, times)); - - if (document()) { - DocumentUndo::maybeDone(document(), - ((grow > 0) ? "selector:grow:larger" : "selector:grow:smaller" ), - ((grow > 0) ? _("Grow") : _("Shrink")), INKSCAPE_ICON("tool-pointer")); - } -} - -void ObjectSet::scaleScreen(double grow_pixels) -{ - if(!desktop()) - return; - scaleGrow(grow_pixels / desktop()->current_zoom()); -} - -void ObjectSet::scale(double times) -{ - if (isEmpty()) - return; - - Geom::OptRect sel_bbox = visualBounds(); - - if (!sel_bbox) { - return; - } - - Geom::Point const center_(sel_bbox->midpoint()); - setScaleRelative(center_, Geom::Scale(times, times)); - DocumentUndo::done(document(), _("Scale by whole factor"), INKSCAPE_ICON("tool-pointer")); -} - void ObjectSet::move(double dx, double dy) { if (isEmpty()) { diff --git a/src/selection.cpp b/src/selection.cpp index 09730f29a3e073dd336624ff0fe76c291d931261..5db44de6b27ef926fb89959214dbe9373dca3fd4 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -22,6 +22,7 @@ #include "selection.h" #include +#include #include "desktop.h" #include "document-undo.h" @@ -33,6 +34,7 @@ #include "object/sp-defs.h" #include "object/sp-page.h" #include "object/sp-shape.h" +#include "ui/icon-names.h" #include "ui/tool/control-point-selection.h" #include "ui/tool/path-manipulator.h" #include "ui/tools/node-tool.h" @@ -193,6 +195,66 @@ void Selection::setAnchor(double x, double y, bool set) } } +void Selection::scaleAnchored(double amount, bool fixed) +{ + if (Geom::OptRect bbox = visualBounds()) { + // Scale the amount by the size to get the final scale amount + if (fixed) { + double const max_len = bbox->maxExtent(); + if (max_len + amount <= 1e-3) { + return; + } + amount = 1.0 + amount / max_len; + } + + auto center = has_anchor ? bbox->min() + bbox->dimensions() * Geom::Scale(anchor) : bbox->midpoint(); + scaleRelative(center, Geom::Scale(amount, amount)); + + DocumentUndo::maybeDone(document(), + ((amount > 0) ? "selector:grow:larger" : "selector:grow:smaller" ), + ((amount > 0) ? _("Grow") : _("Shrink")), INKSCAPE_ICON("tool-pointer")); + } +} + +void Selection::rotateAnchored(double angle_degrees, double zoom) +{ + if (Geom::OptRect bbox = visualBounds()) { + auto mid = center() ? *center() : bbox->midpoint(); + auto center = has_anchor ? bbox->min() + bbox->dimensions() * Geom::Scale(anchor) : mid; + + if (auto d = desktop()) { + angle_degrees = d->yaxisdir(); + } + + if (zoom != 1.0) { + Geom::Point m = bbox->midpoint(); + unsigned i = 0; + if (center[Geom::X] < m[Geom::X]) { + i = 1; + } + if (center[Geom::Y] < m[Geom::Y]) { + i = 3 - i; + } + + double const r = Geom::L2(bbox->corner(i) - center); + angle_degrees = 180 * atan2(angle_degrees / zoom, r) / M_PI; + } + + rotateRelative(center, angle_degrees); + + if (angle_degrees == 90.0) { + DocumentUndo::done(document(), _("Rotate 90\xc2\xb0 CW"), INKSCAPE_ICON("object-rotate-right")); + } else if (angle_degrees == -90.0) { + DocumentUndo::done(document(), _("Rotate 90\xc2\xb0 CCW"), INKSCAPE_ICON("object-rotate-left")); + } else { + DocumentUndo::maybeDone(document(), + ( ( angle_degrees > 0 )? "selector:rotate:ccw": "selector:rotate:cw" ), + _("Rotate"), INKSCAPE_ICON("tool-pointer")); + } + } +} + + SPObject *Selection::_objectForXMLNode(Inkscape::XML::Node *repr) const { g_return_val_if_fail(repr != nullptr, NULL); auto object = _document->getObjectByRepr(repr); diff --git a/src/selection.h b/src/selection.h index 3f201ae5448f30cdee94ff05ec6723d8e349a245..28e1b92c8cffd1db784734d58f011e723ef988a3 100644 --- a/src/selection.h +++ b/src/selection.h @@ -175,6 +175,23 @@ public: bool has_anchor = false; Geom::Point anchor; + /** + * Scale the selection, anchoring it against the center, or a selected anchor + * + * @param amount - The amount to scale by, in a fixed or related amount. + * @param fixed - If true (default) scales by fixed document units instead of by + * factors of the size of the object. + */ + void scaleAnchored(double amount, bool fixed = true); + + /** + * Rotate the selection, anchoring it against the center, or a selected anchor + * + * @param angle_degrees - The amount to rotate by in degrees. + * @param zoom - The zoom amount for screen based rotation amount. + */ + void rotateAnchored(double angle_degrees, double zoom = 1.0); + /** * Connects a slot to be notified of selected object modifications. * diff --git a/src/ui/clipboard.cpp b/src/ui/clipboard.cpp index 0de8fef7dfa9bda17c42c90a5b8f0ad8afe9513e..1bbbafd6b91fc701f7857d90f4fa125430b7c14f 100644 --- a/src/ui/clipboard.cpp +++ b/src/ui/clipboard.cpp @@ -884,7 +884,7 @@ bool ClipboardManagerImpl::pasteSize(ObjectSet *set, bool separately, bool apply // resize the selection as a whole Geom::OptRect sel_size = set->preferredBounds(); if (sel_size) { - set->setScaleRelative(sel_size->midpoint(), + set->scaleRelative(sel_size->midpoint(), _getScale(set->desktop(), min, max, *sel_size, apply_x, apply_y)); } } diff --git a/src/ui/tools/select-tool.cpp b/src/ui/tools/select-tool.cpp index ee591a87a4e50f33655ed06b96522c65b77001a2..de5b05e6ee80bf8af9a857e98bfff447831e48c2 100644 --- a/src/ui/tools/select-tool.cpp +++ b/src/ui/tools/select-tool.cpp @@ -828,7 +828,6 @@ bool SelectTool::root_handler(CanvasEvent const &event) } gdouble const nudge = prefs->getDoubleLimited("/options/nudgedistance/value", 2, 0, 1000, "px"); // in px - int const snaps = prefs->getInt("/options/rotationsnapsperpi/value", 12); auto const y_dir = _desktop->yaxisdir(); bool const rotated = prefs->getBool("/options/moverotated/value", true); @@ -913,30 +912,6 @@ bool SelectTool::root_handler(CanvasEvent const &event) } break; - case GDK_KEY_bracketleft: - if (mod_alt(event)) { - selection->rotateScreen(-mul * y_dir); - } else if (mod_ctrl(event)) { - selection->rotate(-90 * y_dir); - } else if (snaps) { - selection->rotate(-180.0/snaps * y_dir); - } - - ret = true; - break; - - case GDK_KEY_bracketright: - if (mod_alt(event)) { - selection->rotateScreen(mul * y_dir); - } else if (mod_ctrl(event)) { - selection->rotate(90 * y_dir); - } else if (snaps) { - selection->rotate(180.0/snaps * y_dir); - } - - ret = true; - break; - case GDK_KEY_Return: if (mod_ctrl_only(event)) { if (selection->singleItem()) { diff --git a/testfiles/src/object-set-test.cpp b/testfiles/src/object-set-test.cpp index 878e6ef6c4176339b1781ce1fc9f0c894bfff725..51fd1387b0767911500f89266645e95fabd84b0e 100644 --- a/testfiles/src/object-set-test.cpp +++ b/testfiles/src/object-set-test.cpp @@ -628,14 +628,14 @@ TEST_F(ObjectSetTest, Moves) { EXPECT_EQ(15,r1->x.value); Geom::Point p(20,20); Geom::Scale s(2); - set->setScaleRelative(p,s); + set->scaleRelative(p,s); EXPECT_EQ(10,r1->x.value); EXPECT_EQ(20,r1->width.value); set->toCurves(); r1.release(); auto x = set->singleItem(); EXPECT_EQ(20,(*(x->documentVisualBounds()))[0].extent()); - set->rotate(180); + set->rotateRelative(*set->center(), 180); EXPECT_EQ(20,(*(x->documentVisualBounds()))[0].extent()); set->deleteItems(); }