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 19, 2024
1 parent 88847ff commit 403cf22
Show file tree
Hide file tree
Showing 5 changed files with 596 additions and 14 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
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2015, 2016 THALES GLOBAL SERVICES.
* Copyright (c) 2015, 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 @@ -15,12 +15,17 @@
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;

import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PrecisionRectangle;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.draw2d.geometry.Translatable;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.handles.HandleBounds;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.internal.ruler.SnapToGeometryEx;
import org.eclipse.sirius.diagram.ui.edit.api.part.AbstractBorderedDiagramElementEditPart;
Expand All @@ -29,6 +34,8 @@
import org.eclipse.sirius.diagram.ui.graphical.edit.policies.SnapChangeBoundsRequest;
import org.eclipse.sirius.diagram.ui.internal.edit.policies.SnapBendpointRequest;
import org.eclipse.sirius.diagram.ui.tools.internal.ui.NoCopyDragEditPartsTrackerEx;
import org.eclipse.sirius.diagram.ui.tools.internal.ui.SnapToAllDragEditPartsTracker;
import org.eclipse.sirius.ext.draw2d.figure.FigureUtilities;
import org.eclipse.sirius.ext.gef.query.EditPartQuery;
import org.eclipse.sirius.ext.gmf.runtime.editparts.GraphicalHelper;

Expand All @@ -46,6 +53,8 @@ public class SiriusSnapToGeometry extends SnapToGeometryEx {

boolean snapToAll;

boolean isMoveWithArrowSiriusMode;

/**
* A vertical or horizontal snapping point.<BR>
* Only overridden to have access to constructor.
Expand Down Expand Up @@ -88,9 +97,22 @@ public int snapRectangle(Request request, int snapOrientation, PrecisionRectangl
cols = null;
}

// Get the new move mode with arrow keys from request (then used in makeRelative and makeAbsolute). Indeed, in
// this case, the absolute coordinate of <code>baseRect</code> consider the scrollbars. It is not the case
// otherwise.
setMoveWithArrowSiriusMode(((Boolean) (Optional.ofNullable(request.getExtendedData().get(SnapToAllDragEditPartsTracker.MOVE_WITH_ARROW_SIRIUS_MODE)).orElse(Boolean.FALSE))).booleanValue());

return super.snapRectangle(request, snapOrientation, baseRect, result);
}

protected void setMoveWithArrowSiriusMode(boolean moveWithArrowSiriusMode) {
this.isMoveWithArrowSiriusMode = moveWithArrowSiriusMode;
}

protected boolean isMoveWithArrowSiriusMode() {
return isMoveWithArrowSiriusMode;
}

@Override
protected List generateSnapPartsList(List exclusions) {
if (!snapToAll) {
Expand Down Expand Up @@ -182,4 +204,60 @@ protected void populateRowsAndCols(List parts) {
}
}
}

/**
* Translates from absolute to coordinates relative to the given figure.
*
* @param figure
* the reference figure
* @param t
* the object to translate
*/
@Override
protected void makeRelative(IFigure figure, Translatable t) {
// In the case of move with arrow key, there is nothing to do. Compute is already done in absolute coordinates
// (considering zoom and scrollbars).
if (!isMoveWithArrowSiriusMode()) {
super.makeRelative(figure, t);
}
}

/**
* Translates from a given figure to absolute coordinates.
*
* @param figure
* the reference figure
* @param t
* the object to translate
*/
@Override
protected void makeAbsolute(IFigure figure, Translatable t) {
// In the case of move with arrow key, there is nothing to do. Compute is already done in absolute coordinates
// (considering zoom and scrollbars).
if (!isMoveWithArrowSiriusMode()) {
super.makeAbsolute(figure, t);
}
}

// TODO: Comment and see if specific code is needed for border nodes in populateRowsAndCols(List)
@Override
protected Rectangle getFigureBounds(GraphicalEditPart part) {
if (isMoveWithArrowSiriusMode()) {
IFigure figure = part.getFigure();
PrecisionRectangle bounds = null;
if (figure instanceof HandleBounds) {
bounds = new PrecisionRectangle(((HandleBounds) figure).getHandleBounds());
} else {
bounds = new PrecisionRectangle(figure.getBounds());
}
Point topLeft = bounds.getTopLeft();
FigureUtilities.translateToAbsoluteByIgnoringScrollbar(figure, topLeft);
bounds.setX(topLeft.x);
bounds.setY(topLeft.y);
return bounds;
} else {
return super.getFigureBounds(part);
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*******************************************************************************
* 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.IFigure;
import org.eclipse.draw2d.geometry.PrecisionRectangle;
import org.eclipse.draw2d.geometry.Translatable;
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.sirius.diagram.ui.tools.internal.ui.SnapToAllDragEditPartsTracker;

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

boolean isMoveWithArrowSiriusMode;

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

protected void setMoveWithArrowSiriusMode(boolean moveWithArrowSiriusMode) {
this.isMoveWithArrowSiriusMode = moveWithArrowSiriusMode;
}

protected boolean isMoveWithArrowSiriusMode() {
return isMoveWithArrowSiriusMode;
}

/**
* Method overridden to handle the new move mode with arrow keys (then used in makeRelative and makeAbsolute).
* Indeed, in this case, the absolute coordinate of <code>rect</code> consider the scrollbars. It is not the case
* otherwise.
*
* @see SnapToHelper#snapRectangle(Request, int, PrecisionRectangle, PrecisionRectangle)
*/
@Override
public int snapRectangle(Request request, int snapLocations, PrecisionRectangle rect, PrecisionRectangle result) {
setMoveWithArrowSiriusMode(((Boolean) (Optional.ofNullable(request.getExtendedData().get(SnapToAllDragEditPartsTracker.MOVE_WITH_ARROW_SIRIUS_MODE)).orElse(Boolean.FALSE))).booleanValue());
return super.snapRectangle(request, snapLocations, rect, result);
}

/**
* Translates from absolute to coordinates relative to the given figure.
*
* @param figure
* the reference figure
* @param t
* the object to translate
*/
@Override
protected void makeRelative(IFigure figure, Translatable t) {
// In the case of move with arrow key, there is nothing to do. Compute is already done in absolute coordinates
// (considering zoom and scrollbars).
if (!isMoveWithArrowSiriusMode()) {
super.makeRelative(figure, t);
}
}

/**
* Translates from a given figure to absolute coordinates.
*
* @param figure
* the reference figure
* @param t
* the object to translate
*/
@Override
protected void makeAbsolute(IFigure figure, Translatable t) {
// In the case of move with arrow key, there is nothing to do. Compute is already done in absolute coordinates
// (considering zoom and scrollbars).
if (!isMoveWithArrowSiriusMode()) {
super.makeAbsolute(figure, t);
}
}
}
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 403cf22

Please sign in to comment.