Skip to content

Commit

Permalink
[359] New implementation of move with arrow keys
Browse files Browse the repository at this point in the history
Bug: #359
  • Loading branch information
lredor committed Apr 17, 2024
1 parent 88847ff commit 4abd984
Show file tree
Hide file tree
Showing 4 changed files with 561 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017 THALES GLOBAL SERVICES.
* Copyright (c) 2017, 2024 THALES GLOBAL SERVICES.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
Expand All @@ -12,14 +12,23 @@
*******************************************************************************/
package org.eclipse.sirius.diagram.ui.tools.internal.palette;

import java.util.Optional;

import org.eclipse.draw2d.XYLayout;
import org.eclipse.gef.DragTracker;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.editpolicies.NonResizableEditPolicy;
import org.eclipse.gmf.runtime.diagram.ui.internal.editparts.NoteAttachmentEditPart;
import org.eclipse.gmf.runtime.diagram.ui.internal.figures.BorderItemContainerFigure;
import org.eclipse.gmf.runtime.diagram.ui.services.palette.SelectionToolEx;
import org.eclipse.sirius.diagram.ui.edit.api.part.AbstractDiagramEdgeEditPart;
import org.eclipse.sirius.diagram.ui.internal.edit.parts.AbstractDEdgeNameEditPart;
import org.eclipse.sirius.diagram.ui.internal.edit.parts.DNodeListElementEditPart;
import org.eclipse.sirius.diagram.ui.internal.edit.parts.DNodeNameEditPart;
import org.eclipse.sirius.diagram.ui.tools.internal.part.SiriusDiagramGraphicalViewer;
import org.eclipse.swt.events.KeyEvent;

/**
* Specific Sirius SelectionToolEx to use findMouseEventTargetAt instead of findObjectAtExcluding. This allows to
Expand Down Expand Up @@ -76,4 +85,93 @@ private boolean isSiriusSpecificEditPart(EditPart editPart) {
return editPart instanceof DNodeNameEditPart || editPart instanceof AbstractDiagramEdgeEditPart || editPart instanceof AbstractDEdgeNameEditPart
|| editPart instanceof DNodeListElementEditPart;
}


/**
* Method overridden to allow arrow key press with modifier.
*
* @see org.eclipse.gmf.runtime.diagram.ui.services.palette.SelectionToolEx#handleKeyDown(org.eclipse.swt.events.KeyEvent)
*/
@Override
protected boolean handleKeyDown(KeyEvent e) {
Optional<Boolean> optionalLocalresult = specificHandleKeyDown(e);
if (optionalLocalresult.isEmpty()) {
return super.handleKeyDown(e);
} else {
return optionalLocalresult.get().booleanValue();
}
}

/**
* Method inspired by org.eclipse.gmf.runtime.diagram.ui.services.palette.SelectionToolEx.handleKeyDown(KeyEvent) to
* authorize arrow keys with modifiers ({@link #acceptArrowKey(KeyEvent)} instead of
* {@link SelectionToolEx#acceptArrowKeyOnly(KeyEvent)}; Mainly for the "Alt" modifier to disable the snap.
*
* @see org.eclipse.gmf.runtime.diagram.ui.services.palette.SelectionToolEx#handleKeyDown(org.eclipse.swt.events.KeyEvent)
*/
protected Optional<Boolean> specificHandleKeyDown(KeyEvent e) {
Optional<Boolean> optionalLocalresult = Optional.empty();
if (acceptArrowKey(e) && getState() == STATE_INITIAL && !getCurrentViewer().getSelectedEditParts().isEmpty()) {

EditPart selectedEP = (EditPart) getCurrentViewer().getSelectedEditParts().get(0);

if (selectedEP instanceof GraphicalEditPart) {

GraphicalEditPart gep = (GraphicalEditPart) selectedEP;

/*
* The shape we'll be moved in the direction of the arrow key if: 1) It has the appropriate edit policy
* that supports shape moving installed on the editpart 2) The editparts figure's parent layout manager
* is some sort of XYLayout In all other cases we just change the selection based on arrow key
* (implemented in GEF).
*/
if (gep.getEditPolicy(EditPolicy.PRIMARY_DRAG_ROLE) instanceof NonResizableEditPolicy && gep.getFigure().getParent() != null
&& (gep.getFigure().getParent().getLayoutManager() instanceof XYLayout || gep.getFigure().getParent() instanceof BorderItemContainerFigure)) {

resetHover();

if (getDragTracker() != null) {
getDragTracker().deactivate();
}

setState(STATE_ACCESSIBLE_DRAG_IN_PROGRESS);

setTargetEditPart(gep);

updateTargetRequest();
DragTracker dragTracker = gep.getDragTracker(getTargetRequest());
if (dragTracker != null) {
setDragTracker(dragTracker);
dragTracker.keyDown(e, getCurrentViewer());
lockTargetEditPart(gep);
optionalLocalresult = Optional.of(true);
}
optionalLocalresult = Optional.of(false);
}
}
}
return optionalLocalresult;
}

/**
* As for method {@link #handleKeyDown(KeyEvent)}, this method is overridden to "finish" the move in case of arrow
* key press.
*
* @see org.eclipse.gmf.runtime.diagram.ui.services.palette.SelectionToolEx#handleKeyUp(org.eclipse.swt.events.KeyEvent)
*/
@Override
protected boolean handleKeyUp(KeyEvent e) {
boolean returnVal = super.handleKeyUp(e);
if (acceptArrowKey(e)) {
// In superclass SelectionToolEx.handleKeyUp(KeyEvent), it was "if (acceptArrowKeyOnly(e) &&
// !isUsingTraverseHandles) {".
if (getDragTracker() != null) {
getDragTracker().commitDrag();
}
setDragTracker(null);
setState(STATE_INITIAL);
unlockTargetEditPart();
}
return returnVal;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*******************************************************************************
* Copyright (c) 2024 THALES GLOBAL SERVICES.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.diagram.ui.tools.internal.ruler;

import java.util.Optional;

import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.geometry.PrecisionRectangle;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.SnapToHelper;
import org.eclipse.gmf.runtime.diagram.ui.internal.ruler.SnapToGridEx;
import org.eclipse.gmf.runtime.diagram.ui.internal.ruler.SnapToHelperUtil;
import org.eclipse.sirius.diagram.ui.tools.internal.ui.SnapToAllDragEditPartsTracker;
import org.eclipse.sirius.ext.gmf.runtime.editparts.GraphicalHelper;

/**
* Overridden to support the new mode moving node with arrow keys.
*
* @author Laurent Redor
*/
@SuppressWarnings("restriction")
public class SiriusSnapToGridEx extends SnapToGridEx {

/**
* Default constructor.
*
* @param container
* the editpart which the grid is on
*/
public SiriusSnapToGridEx(GraphicalEditPart container) {
super(container);
}

/**
* Method overridden to handle the new move mode with arrow keys. Indeed, in this case, the absolute coordinate of
* <code>rect</code> consider the scrollbars. It is not the case otherwise.<BR/>
* Only the calls to {@link #makeRelative(org.eclipse.draw2d.IFigure, org.eclipse.draw2d.geometry.Translatable)} and
* {@link #makeAbsolute(org.eclipse.draw2d.IFigure, org.eclipse.draw2d.geometry.Translatable)} are replaced in this
* method.
*
* @see SnapToHelper#snapRectangle(Request, int, PrecisionRectangle, PrecisionRectangle)
*/
@Override
public int snapRectangle(Request request, int snapLocations, PrecisionRectangle rect, PrecisionRectangle result) {
boolean isMoveWithArrowSiriusMode = ((Boolean) (Optional.ofNullable(request.getExtendedData().get(SnapToAllDragEditPartsTracker.MOVE_WITH_ARROW_SIRIUS_MODE)).orElse(Boolean.FALSE)))
.booleanValue();
double zoom = GraphicalHelper.getZoom(container);

Integer restrictedDirections = (Integer) request.getExtendedData().get(SnapToHelperUtil.RESTRICTED_DIRECTIONS);
if (restrictedDirections == null || restrictedDirections == PositionConstants.NONE) {
return super.snapRectangle(request, snapLocations, rect, result);
}
int snapLocationsCopy = SnapToHelperUtil.updateSnapLocations(snapLocations, restrictedDirections);

PrecisionRectangle rectCopy = rect.getPreciseCopy();
if (isMoveWithArrowSiriusMode) {
// In the case, only the zoom must be applied
rectCopy.performScale(1.0d / zoom);
} else {
makeRelative(container.getContentPane(), rectCopy);
}
PrecisionRectangle correction = new PrecisionRectangle();
if (isMoveWithArrowSiriusMode) {
// In the case, only the zoom must be applied
correction.performScale(1.0d / zoom);
} else {
makeRelative(container.getContentPane(), correction);
}

if (gridX > 0 && (snapLocationsCopy & EAST) != 0) {
correction.setPreciseWidth(correction.preciseWidth() - Math.IEEEremainder(rectCopy.preciseRight() - origin.x - 1, gridX));
snapLocationsCopy &= ~EAST;
}

if ((snapLocationsCopy & (WEST | HORIZONTAL)) != 0 && gridX > 0) {
double leftCorrection = Math.IEEEremainder(rectCopy.preciseX() - origin.x, gridX);

// /////////////////// ADDED THIS CODE
// CHECKSTYLE:OFF
if ((restrictedDirections & EAST) != 0 && (restrictedDirections & WEST) == 0 && leftCorrection > 0) {
// restricted to moving EAST
correction.setPreciseX(correction.preciseX() + (gridX - leftCorrection));
} else if ((restrictedDirections & WEST) != 0 && (restrictedDirections & EAST) == 0 && leftCorrection < 0) {
// restricted to moving WEST
correction.setPreciseX(correction.preciseX() - (gridX + leftCorrection));
} else {
// no horizontal restrictions
correction.setPreciseX(correction.preciseX() - leftCorrection);
}
// ///////////////////
// CHECKSTYLE:ON

if ((snapLocationsCopy & HORIZONTAL) == 0)
correction.setPreciseWidth(correction.preciseWidth() + leftCorrection);
snapLocationsCopy &= ~(WEST | HORIZONTAL);
}

if ((snapLocationsCopy & SOUTH) != 0 && gridY > 0) {
correction.setPreciseHeight(correction.preciseHeight() - Math.IEEEremainder(rectCopy.preciseBottom() - origin.y - 1, gridY));
snapLocationsCopy &= ~SOUTH;
}

if ((snapLocationsCopy & (NORTH | VERTICAL)) != 0 && gridY > 0) {
double topCorrection = Math.IEEEremainder(rectCopy.preciseY() - origin.y, gridY);

// /////////////////// ADDED THIS CODE
// CHECKSTYLE:OFF
if ((restrictedDirections & SOUTH) != 0 && (restrictedDirections & NORTH) == 0 && topCorrection > 0) {
// restricted to moving SOUTH
correction.setPreciseY(correction.preciseY() + (gridY - topCorrection));
} else if ((restrictedDirections & NORTH) != 0 && (restrictedDirections & SOUTH) == 0 && topCorrection < 0) {
// restricted to moving NORTH
correction.setPreciseY(correction.preciseY() - (gridY + topCorrection));
} else {
// no vertical restrictions
correction.setPreciseY(correction.preciseY() - topCorrection);
}
// ///////////////////
// CHECKSTYLE:ON

if ((snapLocationsCopy & VERTICAL) == 0)
correction.setPreciseHeight(correction.preciseHeight() + topCorrection);
snapLocationsCopy &= ~(NORTH | VERTICAL);
}


if (isMoveWithArrowSiriusMode) {
// In the case, only the zoom must be applied
correction.performScale(zoom);
} else {
makeAbsolute(container.getContentPane(), correction);
}
result.setPreciseX(result.preciseX() + correction.preciseX());
result.setPreciseY(result.preciseY() + correction.preciseY());
result.setPreciseWidth(result.preciseWidth() + correction.preciseWidth());
result.setPreciseHeight(result.preciseHeight() + correction.preciseHeight());

return snapLocationsCopy;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/******************************************************************************
* Copyright (c) 2007, 2016 IBM Corporation and others.
* Copyright (c) 2007, 2024 IBM Corporation and others.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
Expand All @@ -24,7 +24,6 @@
import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
import org.eclipse.gmf.runtime.diagram.ui.internal.editparts.ISurfaceEditPart;
import org.eclipse.gmf.runtime.diagram.ui.internal.ruler.CompoundSnapToHelperEx;
import org.eclipse.gmf.runtime.diagram.ui.internal.ruler.SnapToGridEx;
import org.eclipse.gmf.runtime.diagram.ui.internal.ruler.SnapToGuidesEx;
import org.eclipse.gmf.runtime.diagram.ui.internal.ruler.SnapToHelperUtil;
import org.eclipse.sirius.diagram.ui.edit.api.part.AbstractDiagramNodeEditPart;
Expand Down Expand Up @@ -90,7 +89,7 @@ static public Object getSnapHelper(GraphicalEditPart editPart) {
val = (Boolean) viewer.getProperty(SnapToGrid.PROPERTY_GRID_ENABLED);

if (val != null && val.booleanValue()) {
snapStrategies.add(new SnapToGridEx(diagramEditPart));
snapStrategies.add(new SiriusSnapToGridEx(diagramEditPart));
}

if (snapStrategies.size() == 0) {
Expand Down
Loading

0 comments on commit 4abd984

Please sign in to comment.