diff --git a/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/controller/DiagramZoomController.java b/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/controller/DiagramZoomController.java
index d9914b9eb..43e04e2aa 100644
--- a/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/controller/DiagramZoomController.java
+++ b/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/controller/DiagramZoomController.java
@@ -161,10 +161,8 @@ public void zoom(final ZoomStyle zoomStyle, final KGraphElement desiredFocusElem
* time to animate in ms
*/
private void zoomToActualSize(final int duration) {
- final KNode displayedKNode = this.canvasCamera.getDisplayedKNodeNode().getViewModelElement();
-
- final PBounds newBounds = toPBoundsIncludingPortsAndLabels(displayedKNode);
-
+ final PBounds newBounds = toPBoundsIncludingPortsAndLabelsOfDisplayedKNode();
+
this.canvasCamera.animateViewToTransform(
PAffineTransform.getTranslateInstance(-newBounds.x, -newBounds.y), duration);
}
@@ -185,10 +183,8 @@ private void zoomToActualSize(final int duration) {
*/
private void zoomToFit(final int duration, boolean narrowDownToContents,
final Spacing defaultZoomToFitContentSpacing) {
- final KNode displayedKNode = this.canvasCamera.getDisplayedKNodeNode().getViewModelElement();
-
- final PBounds newBounds = toPBoundsIncludingPortsAndLabels(
- displayedKNode, narrowDownToContents, defaultZoomToFitContentSpacing);
+ final PBounds newBounds = toPBoundsIncludingPortsAndLabelsOfDisplayedKNode(
+ narrowDownToContents, defaultZoomToFitContentSpacing);
if (this.canvasCamera.getBoundsReference().isEmpty()) {
// this case occurs while initializing the DiagramEditorPart
@@ -225,18 +221,23 @@ public void zoomToFocus(final KNode focus, final int duration) {
* diagram canvas area, see also {@link ZoomStyle#ZOOM_TO_FOCUS_OR_INCREASE_TO_FIT}
*/
private void zoomToFocus(final KNode focus, final int duration, final boolean increaseToFit) {
+ final PBounds diagramBounds = toPBoundsIncludingPortsAndLabelsOfDisplayedKNode();
final KNode displayedKNode = this.canvasCamera.getDisplayedKNodeNode().getViewModelElement();
// fetch bounds of the whole visible diagram
- final PBounds focusBounds = toPBoundsIncludingPortsAndLabels(focus);
+ final PBounds focusBounds;
- // we need the bounds in view coordinates (absolute), hence for
- // a KNode add the translations of all parent nodes
+ if (focus == displayedKNode) {
+ focusBounds = diagramBounds;
- if (focus != displayedKNode) {
+ } else {
+ focusBounds = toPBoundsIncludingPortsAndLabels(focus);
KNode parent = focus.getParent();
- while (parent != null && parent != displayedKNode.getParent()) {
+ // we need the bounds in view coordinates (absolute), hence for
+ // a KNode add the translations of all parent nodes
+
+ while (parent != null && parent != displayedKNode) {
final double scale = parent.getProperty(CoreOptions.SCALE_FACTOR).doubleValue();
focusBounds.setSize(scale * focusBounds.width, scale * focusBounds.height);
@@ -253,7 +254,6 @@ private void zoomToFocus(final KNode focus, final int duration, final boolean in
final PBounds viewBounds = canvasCamera.getViewBounds();
if (increaseToFit) {
- final PBounds diagramBounds = toPBoundsIncludingPortsAndLabels(displayedKNode);
final boolean fullyContains = viewBounds.getWidth() > diagramBounds.getWidth()
&& viewBounds.getHeight() > diagramBounds.getHeight();
@@ -285,9 +285,7 @@ private void zoomToFocus(final KNode focus, final int duration, final boolean in
* time to animate
*/
public void zoomToLevel(final float newZoomLevel, final int duration) {
- final KNode displayedKNode = this.canvasCamera.getDisplayedKNodeNode().getViewModelElement();
-
- final PBounds nodeBounds = toPBoundsIncludingPortsAndLabels(displayedKNode);
+ final PBounds nodeBounds = toPBoundsIncludingPortsAndLabelsOfDisplayedKNode();
// it would be possible to use PCamera#scaleViewAboutPoint(scale, x, y),
// however this method does not allow for animation
@@ -301,12 +299,9 @@ public void zoomToLevel(final float newZoomLevel, final int duration) {
origBounds.height * oldZoomLevel / newZoomLevel);
// add the necessary translation
- final double normalizedWidth = origBounds.width * oldZoomLevel;
- final double normalizedHeight = origBounds.height * oldZoomLevel;
- final double transX = (origBounds.width - normalizedWidth / newZoomLevel) / 2f;
- final double transY = (origBounds.height - normalizedHeight / newZoomLevel) / 2f;
-
- newBounds.moveBy(transX, transY);
+ newBounds.moveBy(
+ (origBounds.width - newBounds.width) / 2f,
+ (origBounds.height - newBounds.height) / 2f);
// make sure at least some of the diagram is visible after zooming to scale 1
final PDimension dim = newBounds.deltaRequiredToContain(nodeBounds);
@@ -336,13 +331,18 @@ public void zoomToStay(final EObject focusElement, final KVector previousPositio
final KNode displayedKNode = this.canvasCamera.getDisplayedKNodeNode().getViewModelElement();
// Fetch bounds of the focused element.
- final PBounds focusBounds = boundsComputer.toPBounds(focus);
+ final PBounds focusBounds;
- // We need the bounds in view coordinates (absolute), hence for
- // an element add the translations of all parent elements.
+ if (focus == displayedKNode) {
+ focusBounds = toPBoundsIncludingPortsAndLabelsOfDisplayedKNode();
- if (focus != displayedKNode) {
+ } else {
+ focusBounds = boundsComputer.toPBounds(focus);
EObject parent = focus.eContainer();
+
+ // We need the bounds in view coordinates (absolute), hence for
+ // an element add the translations of all parent elements.
+
while (parent != null && parent != displayedKNode.getParent()) {
while (!(parent instanceof KShapeLayout) && !(parent instanceof EMapPropertyHolder) && parent != null) {
parent = parent.eContainer();
@@ -371,6 +371,41 @@ public void zoomToStay(final EObject focusElement, final KVector previousPositio
canvasCamera.animateViewToTransform(transform, duration);
}
+ /**
+ * Converts the current diagram clip KNode's layout data into {@link PBounds} s.t. its ports
+ * and labels are included, while its scale and offset are excluded.
+ *
+ * @return the requested bounding box in form of a {@link PBounds}
+ */
+ private PBounds toPBoundsIncludingPortsAndLabelsOfDisplayedKNode() {
+ return toPBoundsIncludingPortsAndLabelsOfDisplayedKNode(false, null);
+ }
+
+ /**
+ * Converts the current diagram clip KNode's layout data into {@link PBounds} s.t. its ports
+ * and labels are included, while its scale and offset are excluded.
+ *
+ * @param doComputeSubDiagramSize
+ * set to true
yields the bounding box of the nested diagram's content
+ * including node
's ports and labels if visible, with false
+ * the bounds of the given node
including its port and labels if visible
+ * are returned
+ * @param defaultZoomToFitContentSpacing
+ * default spacing to be applied if narrowDownToContents
is
+ * true
, see also
+ * {@link de.cau.cs.kieler.klighd.util.KlighdProperties#ZOOM_TO_FIT_CONTENT_SPACING},
+ * may be null
.
+ * @return the requested bounding box in form of a {@link PBounds}
+ */
+ private PBounds toPBoundsIncludingPortsAndLabelsOfDisplayedKNode(
+ final boolean doComputeSubDiagramSize, final Spacing defaultZoomToFitContentSpacing) {
+ final KNode displayedKNode = this.canvasCamera.getDisplayedKNodeNode().getViewModelElement();
+
+ final PBounds bounds = toPBoundsIncludingPortsAndLabels(displayedKNode,
+ doComputeSubDiagramSize, defaultZoomToFitContentSpacing);
+ return eliminateOffsetAndScale(bounds, displayedKNode);
+ }
+
/**
* Converts node
's layout data into {@link PBounds} s.t. node
's ports
* and labels are included, respects an attached {@link LayoutOptions#SCALE_FACTOR}.
@@ -406,4 +441,35 @@ protected PBounds toPBoundsIncludingPortsAndLabels(final KNode node,
return boundsComputer.toPBoundsIncludingPortsAndLabels(
node, doComputeSubDiagramSize, defaultZoomToFitContentSpacing, true);
}
+
+ /**
+ * Reduces the given bounds
by node
's translation and scale.
+ * It's required for computing the visible diagram's bounding box as clipped diagrams are drawn
+ * without applying the clip node's transform (containing the scale and offset), see
+ * KNodeNode#fullPaint(PPaintContext), and scaling and translating the KNodeTopNode (root node)
+ * is invalid.
+ *
+ * Note that bounds
' (x,y) translation may differ from node
's (x,y)
+ * translation because of labels, ports, and port labels having negative x and y coordinates,
+ * i.e., are placed in left/above node
. In that case bounds
will than
+ * have negative x and/or y coordinates, which is on purpose.
+ *
+ * @param bounds
+ * full bounds of some {@link KNode} including its ports and labels, scaled by
+ * node
's scale and translated by node
's (x,y)
+ * @param node
+ * the {@link KNode} containing the reference scale and offset
+ * @return bounds
being adjusted as described above (within the argument object)
+ */
+ protected PBounds eliminateOffsetAndScale(final PBounds bounds, final KNode node) {
+
+ bounds.moveBy(-node.getXpos(), -node.getYpos());
+
+ final float scaleInverse = 1 / node.getProperty(CoreOptions.SCALE_FACTOR).floatValue();
+ bounds.setRect(
+ bounds.getX() * scaleInverse, bounds.getY() * scaleInverse,
+ bounds.getWidth() * scaleInverse, bounds.getHeight() * scaleInverse);
+
+ return bounds;
+ }
}
diff --git a/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/events/KlighdMagnificationLensEventHandler.java b/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/events/KlighdMagnificationLensEventHandler.java
index eb9557bbb..d5c0219b0 100644
--- a/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/events/KlighdMagnificationLensEventHandler.java
+++ b/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/events/KlighdMagnificationLensEventHandler.java
@@ -153,8 +153,16 @@ private Point2D determineLensOffset(final PInputEvent event) {
/**
* Composes a {@link PAffineTransform} incorporating the lens magnification according to the
- * corresponding preference setting, the inverse of the clip node's scaling, and event's mouse
- * pointer position in terms the diagram coordinates (rather than canvas coordinates).
+ * corresponding preference setting and event's mouse pointer position in terms the
+ * diagram coordinates (rather than canvas coordinates).
+ *
+ * Note that no attention need to be paid to the current diagram clip node's scale and offset.
+ * They're not applied while drawing them via the main camera, and since 'mainCamera' is
+ * the top element in the paintContext's cameraStack while drawing via 'lensCamera'
+ * (as its a transitive parent of 'lensCamera') KNodeNode#fullPaint(PPaintContext)
+ * will behave the same way as when called via 'mainCamera'.
+ *
+ * See also {@link PCamera#fullPaint(edu.umd.cs.piccolo.util.PPaintContext)}.
*
* @param event
* the {@link PInputEvent} to get the diagram position from
@@ -167,9 +175,6 @@ private PAffineTransform createViewTransform(final PInputEvent event) {
final float scale = STORE.getFloat(KlighdPreferences.MAGNIFICATION_LENS_SCALE) / 100f;
viewTransform.scale(scale, scale);
- final double clipScale = mainCamera.getDisplayedKNodeNode().getScale();
- viewTransform.scale(1 / clipScale, 1 / clipScale);
-
final Point2D pos = event.getPosition();
viewTransform.translate(-pos.getX(), -pos.getY());
return viewTransform;
diff --git a/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/nodes/KNodeNode.java b/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/nodes/KNodeNode.java
index 5c6999abd..9763385e3 100644
--- a/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/nodes/KNodeNode.java
+++ b/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/nodes/KNodeNode.java
@@ -516,7 +516,7 @@ public boolean fullPick(final PPickPath pickPath) {
// instead we want this kNodeNode be the picked node anyway so, ...
if (!fullPick && isRootLayer) {
pickPath.pushNode(this);
- pickPath.pushTransform(getTransform());
+ pickPath.pushTransform(new PAffineTransform());
return true;
}
@@ -538,10 +538,14 @@ public boolean fullPickOri(final PPickPath pickPath) {
// The filter is in charge of masking out the rendering while the diagram is
// clipped to this node and it's being drawn via the diagram's main camera!
+ final boolean isRootLayer = this.isRootLayer;
if (getVisible() && (getPickable() || getChildrenPickable())
- && fullIntersectsOri(pickPath.getPickBounds())) {
+ && (isRootLayer || fullIntersectsOri(pickPath.getPickBounds()))) {
+ final PAffineTransform transform = isRootLayer ? new PAffineTransform() : getTransformReference(true);
+
pickPath.pushNode(this);
- pickPath.pushTransform(getTransformReference(true));
+ pickPath.pushTransform(transform);
+
final boolean applyScale = nodeScale != null;
@@ -563,7 +567,7 @@ && fullIntersectsOri(pickPath.getPickBounds())) {
final int count = getChildrenCount();
for (int i = count - 1; i >= 0; i--) {
final PNode each = (PNode) getChildrenReference().get(i);
- if (this.isRootLayer) {
+ if (isRootLayer) {
if (i == 0 && each != this.childArea) {
// do not try to pick the node's figure if the main diagram is clipped to
// this node
@@ -592,21 +596,58 @@ && fullIntersectsOri(pickPath.getPickBounds())) {
kpp.popNodeScale();
}
- pickPath.popTransform(getTransformReference(false));
+ pickPath.popTransform(transform);
pickPath.popNode(this);
}
return false;
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void repaintFrom(PBounds localBounds, PNode childOrThis) {
+ if (this.isRootLayer) {
+ // This customization reports a dirty area, e.g. reported by some child, to the attached
+ // cameras without adjusting its bounds by 'this.transform'. Attached cameras are expected
+ // only in case the (main) diagram is clipped to this node. In that case the main camera
+ // and optionally the magnifier lens camera.
+ // The customization is necessary as we now ignore this node's 'transform' once the (main))
+ // diagram is clipped to this node, because of https://github.com/kieler/KLighD/issues/56,
+ // see also the corresponding changes in #fullPickOri(...) and #fullPaint(...)
+ //
+ // The above check of 'this.isRootLayer' is actually redundant, as cameras should only be
+ // registered in case of 'this.isRootLayer' is equal to 'true', but is kept for documentation
+ // and easier understanding.
+ super.notifyCameras(localBounds);
+ }
+
+ // Apart from the above immediate camera notification, the common propagation is kept in order to
+ // keep the outline always up to date, which happens via propagating up to the root KNodeTopNode
+ // and along that way to the outline camera
+ super.repaintFrom(localBounds, childOrThis);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void notifyCameras(PBounds parentBounds) {
+ // this customization is symmetric to the above one and just suppresses superfluous repaint
+ // requests of potentially incorrect bounds as we ignore 'this.transform' if the (main)
+ // diagram is clipped to this node, see above.
+ // Otherwise no attached cameras are expected at the time writing.
+ }
/**
* {@inheritDoc}
*/
@Override
public void fullPaint(final PPaintContext paintContext) {
+ final boolean isRootLayer = this.isRootLayer;
final KlighdPaintContext kpc = (KlighdPaintContext) paintContext;
- if (!this.isRootLayer && this.visibilityHelper != null
+ if (!isRootLayer && this.visibilityHelper != null
&& this.visibilityHelper.isNotVisibleOn(kpc)) {
return;
}
@@ -621,8 +662,12 @@ public void fullPaint(final PPaintContext paintContext) {
// In contrast, the rendering figure is supposed to be drawn at all times
// while the diagram is drawn via the outline view's camera!
- if (getVisible() && (kpc.isOutline() || fullIntersectsOri(paintContext.getLocalClip()))) {
- final PAffineTransform transform = getTransformReference(false);
+ // the following flag is false if drawn on the outline view, for example
+ final boolean isRootAndDrawnViaMainCamera = isRootLayer && this.getCamerasReference().contains(paintContext.getCamera());
+
+ if (getVisible() && (kpc.isOutline() || (isRootAndDrawnViaMainCamera) || fullIntersectsOri(paintContext.getLocalClip()))) {
+ final PAffineTransform transform = isRootAndDrawnViaMainCamera ? new PAffineTransform() : getTransformReference(false);
+
paintContext.pushTransform(transform);
paintContext.pushTransparency(getTransparency());
@@ -641,10 +686,8 @@ public void fullPaint(final PPaintContext paintContext) {
for (int i = 0; i < count; i++) {
final PNode each = (PNode) getChildrenReference().get(i);
- if (this.isRootLayer) {
- // the following flag is false if drawn on the outline view, for example
- final boolean drawnViaMainCamera = this.getCamerasReference().contains(paintContext.getCamera());
- if (drawnViaMainCamera) {
+ if (isRootLayer) {
+ if (isRootAndDrawnViaMainCamera) {
if (i == 0 && each != this.childArea) {
// do not draw the node's figure on the main diagram if it is clipped to this node
continue;
diff --git a/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/nodes/KlighdDisposingLayer.java b/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/nodes/KlighdDisposingLayer.java
index 10ae118f4..210f8a36e 100644
--- a/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/nodes/KlighdDisposingLayer.java
+++ b/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/nodes/KlighdDisposingLayer.java
@@ -139,7 +139,7 @@ public void validateFullPaint() {
isValidatingPaint = false;
if (!tempRect.isEmpty()) {
- repaintFrom(tempRect, this);
+ super.repaintFrom(tempRect, this);
}
}
diff --git a/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/nodes/KlighdMainCamera.java b/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/nodes/KlighdMainCamera.java
index 6fccf82d6..3cbac784b 100644
--- a/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/nodes/KlighdMainCamera.java
+++ b/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/nodes/KlighdMainCamera.java
@@ -202,13 +202,13 @@ public void exchangeDisplayedKNodeNode(final KNodeAbstractNode node,
// resizing, translation, and integration into the parent inode's figure of that
// child area node is automatically respected.
- t = NodeUtil.localToParent(node.getParent(), prevNode.getParent());
+ t = NodeUtil.localToParent(node, prevNode);
} else if (node.isAncestorOf(prevNode)) {
// Case b) is symmetric to a): child & ancestor are exchanged and the resulting
// transform must be inverted since it is to be applied "outward".
- t = NodeUtil.invert(NodeUtil.localToParent(prevNode.getParent(), node.getParent()));
+ t = NodeUtil.invert(NodeUtil.localToParent(prevNode, node));
} else {
// In case c) first the closest common ancestor (iKNodeNode) is determined
@@ -229,11 +229,11 @@ public void exchangeDisplayedKNodeNode(final KNodeAbstractNode node,
// ... apply case b) between 'prevNode's parent (child area node) and
// 'commonAncestor's child area node, ...
- t = NodeUtil.invert(NodeUtil.localToParent(prevNode.getParent(), caChildArea));
+ t = NodeUtil.invert(NodeUtil.localToParent(prevNode, caChildArea));
// ... and apply case a) between 'node's parent (child area node) and
// 'commonAncestor's child area node.
- t.concatenate(NodeUtil.localToParent(node.getParent(), caChildArea));
+ t.concatenate(NodeUtil.localToParent(node, caChildArea));
}
}
diff --git a/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/viewer/PiccoloOutlinePage.java b/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/viewer/PiccoloOutlinePage.java
index 4984c8c8e..9a6aeefe5 100644
--- a/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/viewer/PiccoloOutlinePage.java
+++ b/plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/viewer/PiccoloOutlinePage.java
@@ -504,10 +504,9 @@ public void controlResized(final ControlEvent e) {
* graph layout. Note, that the bounds of the canvas are automatically updated of the size of
* the outline page change, since the outlineCanvas is provided by this class via
* {@link #getControl()}. The canvas in turn immediately updates the bounds of its camera, see
- * {@link edu.umd.cs.piccolox.swt.PSWTCanvas#setBounds(int, int, int, int)
- * PSWTCanvas#.setBounds(int, int, int, int)}. Thus we don't need to care about the canvas' and
- * camera's (full) bounds and can limit the modifications to the camera's view bounds (/view
- * transform).
+ * {@link KlighdCanvas#setBounds(int, int, int, int) KlighdCanvas.setBounds(int, int, int,
+ * int)}. Thus we don't need to care about the canvas' and camera's (full) bounds and can limit
+ * the modifications to the camera's view bounds (/view transform).
*/
private void adjustCamera() {
if (rootNode == null) {
@@ -547,7 +546,7 @@ private void adjustOutlineRect() {
// get the new bounds
final PBounds bounds = originalCamera.getViewBounds();
final PAffineTransform localToParent =
- NodeUtil.localToParent(displayedNode.getParent(), topNode);
+ NodeUtil.localToParent(displayedNode, topNode);
localToParent.preConcatenate(outlineCanvas.getCamera().getViewTransformReference());
localToParent.transform(bounds, bounds);
@@ -556,9 +555,6 @@ private void adjustOutlineRect() {
viewportOutlineRect.setPathToRoundRectangle(
(float) bounds.x, (float) bounds.y, (float) bounds.width, (float) bounds.height,
viewportOutlineRectCornerWidth, viewportOutlineRectCornerWidth);
-
- // schedule a repaint
- outlineCanvas.getCamera().invalidatePaint();
}
@@ -636,34 +632,41 @@ private class OutlineDragHandler extends PDragSequenceEventHandler {
protected void startDrag(final PInputEvent event) {
isDragging = true;
super.startDrag(event);
- final Point2D pos = event.getPosition();
+ final Point2D clickPosInDiagramCoords = event.getPosition();
final KlighdMainCamera originalCamera = topNode.getDiagramMainCamera();
// In clipped diagrams the accumulated 'translate' offset ((x,y) positions)
- // of the displayed inode's parent pnodes (!) must be applied the determined
- // view bounds in order to get the "actual" click position.
- // Note however that the displayed inode's translate (x,y) must not be taken
- // into account because it is not contained in 'originalCamera.getViewBounds()'!
+ // of the displayed inode and all of its parent pnodes (!) must be applied to the determined
+ // view/diagram bounds in order to obtain the "actual" (true) click position.
// Since PCamera.paintCameraView() calls 'fullPaint(...)' on each displayed PLayer
// the transforms of those layers are applied on top of the camera's view transform!
- // For that reason the global translation of
- // 'originalCamera.getDisplayedLayer().getParent()' is calculated. This way an
- // optional translation of the parent inode's child area is also respected!
- final Point2D clipOffset =
- originalCamera.getDisplayedKNodeNode().getParent().getGlobalTranslation();
-
- final PBounds outlineRectBounds =
+ // Hence, for the outline view the transforms for each and every KNodeNode are always applied,
+ // while for the main diagram the transforms of the clip node's parent pnodes are ignored
+ // (of course because those nodes are simply invisible for the main diagram camera)
+ // as well is the clip node's transform, see KNodeNode#fullPaint(PPaintContext)
+ // For that reason the global translation of 'originalCamera.getDisplayedKNodeNode()' is calculated.
+ // Optional translations of some parent inodes' child areas are also respected this way.
+ final Point2D clipOffset = originalCamera.getDisplayedKNodeNode().getGlobalTranslation();
+
+ // determine the bounds of the currently visible main diagram area (excerpt) in diagram coordinates
+ // and normalize those to the diagram's root KNodeTopNode (assuming the diagram is clipped,
+ // 'clipOffset' is supposed to be (0,0) otherwise)
+ final PBounds trueBoundsOfVisibleMainDiagramArea =
originalCamera.getViewBounds().moveBy(clipOffset.getX(), clipOffset.getY());
// if the user clicks outside the outline rect,
// center it on this point before dragging starts
- final boolean withinRect = outlineRectBounds.contains(pos);
- if (!withinRect) {
+ final boolean clickedWithinVisibleMainDaigramExcerpt =
+ trueBoundsOfVisibleMainDiagramArea.contains(clickPosInDiagramCoords);
+ if (!clickedWithinVisibleMainDaigramExcerpt) {
// translate the camera by the delta between click
// and current center point of the bounds
- final Point2D center = outlineRectBounds.getCenter2D();
- originalCamera.translateView(center.getX() - pos.getX(), center.getY() - pos.getY());
+ final Point2D center = trueBoundsOfVisibleMainDiagramArea.getCenter2D();
+ originalCamera.translateView(
+ center.getX() - clickPosInDiagramCoords.getX(),
+ center.getY() - clickPosInDiagramCoords.getY()
+ );
}
}