diff --git a/src/Gui/ViewProviderLink.cpp b/src/Gui/ViewProviderLink.cpp
index 8fdcfbbaae..da105122d7 100644
--- a/src/Gui/ViewProviderLink.cpp
+++ b/src/Gui/ViewProviderLink.cpp
@@ -51,6 +51,7 @@
#include
#include
#include
+#include
#include
#include
#include "Application.h"
@@ -2331,8 +2332,13 @@ bool ViewProviderLink::doubleClicked() {
void ViewProviderLink::setupContextMenu(QMenu* menu, QObject* receiver, const char* member)
{
auto ext = getLinkExtension();
- if(linkEdit(ext))
+ if(linkEdit(ext)) {
linkView->getLinkedView()->setupContextMenu(menu,receiver,member);
+ } else if(ext->getPlacementProperty() || ext->getLinkPlacementProperty()) {
+ QAction* act = menu->addAction(QObject::tr("Transform"), receiver, member);
+ act->setData(QVariant((int)ViewProvider::Transform));
+ }
+
if(ext && ext->getColoredElementsProperty()) {
bool found = false;
for(auto action : menu->actions()) {
@@ -2400,20 +2406,33 @@ bool ViewProviderLink::initDraggingPlacement() {
dragCtx.reset(new DraggerContext);
+ dragCtx->preTransform = doc->getEditingTransform();
+
const auto &pla = ext->getPlacementProperty()?
ext->getPlacementValue():ext->getLinkPlacementValue();
- dragCtx->preTransform = doc->getEditingTransform();
- auto plaMat = pla.toMatrix();
- plaMat.inverseGauss();
- dragCtx->preTransform *= plaMat;
+ // Cancel out our our transformation from the editing transform, because
+ // the dragger is meant to change our transformation.
+ dragCtx->preTransform *= pla.inverse().toMatrix();
+
+ dragCtx->bbox = getBoundingBox(0,false);
+ // The returned bounding box is before out own transform, but we still need
+ // to scale it to get the correct center.
+ auto scale = ext->getScaleVector();
+ dragCtx->bbox.ScaleX(scale.x);
+ dragCtx->bbox.ScaleY(scale.y);
+ dragCtx->bbox.ScaleZ(scale.z);
+ auto offset = dragCtx->bbox.GetCenter();
+
+ // This determins the initial placement of the dragger. We place it at the
+ // center of our bounding box.
+ dragCtx->initialPlacement = pla * Base::Placement(offset, Base::Rotation());
+
+ // dragCtx->mat is to transform the dragger placement to our own placement.
+ // Since the dragger is placed at the center, we set the transformation by
+ // moving the same amount in reverse direction.
+ dragCtx->mat.move(Vector3d() - offset);
- dragCtx->bbox = linkView->getBoundBox();
- const auto &offset = Base::Placement(
- dragCtx->bbox.GetCenter(),Base::Rotation());
- dragCtx->initialPlacement = pla * offset;
- dragCtx->mat = offset.toMatrix();
- dragCtx->mat.inverseGauss();
return true;
}
@@ -2427,7 +2446,15 @@ ViewProvider *ViewProviderLink::startEditing(int mode) {
return inherited::startEditing(mode);
}
+ static thread_local bool _pendingTransform;
+ static thread_local Base::Matrix4D _editingTransform;
+
+ auto doc = Application::Instance->editDocument();
+
if(mode==ViewProvider::Transform) {
+ if(_pendingTransform && doc)
+ doc->setEditingTransform(_editingTransform);
+
if(!initDraggingPlacement())
return 0;
if(useCenterballDragger)
@@ -2453,7 +2480,6 @@ ViewProvider *ViewProviderLink::startEditing(int mode) {
// and set color. We need to find a better place to declare this constant.
mode &= ~0x8000;
- auto doc = Application::Instance->editDocument();
if(!doc) {
FC_ERR("no editing document");
return 0;
@@ -2473,8 +2499,12 @@ ViewProvider *ViewProviderLink::startEditing(int mode) {
FC_ERR("no linked viewprovider");
return 0;
}
- // amend the editing transformation with the link transformation
+ // Amend the editing transformation with the link transformation.
+ // But save it first in case the linked object reroute the editing request
+ // back to us.
+ _editingTransform = doc->getEditingTransform();
doc->setEditingTransform(doc->getEditingTransform()*mat);
+ Base::FlagToggler<> guard(_pendingTransform);
return vpd->startEditing(mode);
}
@@ -2542,7 +2572,15 @@ void ViewProviderLink::setEditViewer(Gui::View3DInventorViewer* viewer, int ModN
viewer->setupEditingRoot(group,&dragCtx->preTransform);
}else{
SoFCCSysDragger* dragger = static_cast(pcDragger.get());
- dragger->draggerSize.setValue(0.05f);
+ auto doc = Application::Instance->editDocument();
+ if(doc) {
+ Base::Vector3d v0, v1(1,0,0);
+ doc->getEditingTransform().multVec(v0,v0);
+ doc->getEditingTransform().multVec(v1,v1);
+ // Compensate for possible scaling
+ dragger->draggerSize.setValue(0.05f / (v1-v0).Length());
+ } else
+ dragger->draggerSize.setValue(0.05f);
dragger->setUpAutoScale(viewer->getSoRenderManager()->getCamera());
viewer->setupEditingRoot(pcDragger,&dragCtx->preTransform);