Переглянути джерело

SDK SceneComposer : all shortcuts tool are now outside of the selectTool,
- added the Delete and Duplicate shortcut
- deleted the MoveManager
- clean up the SelectTool (removed old shortCuts)
- now the ShortcutManager can also provide to SorthcutTools the state of ctr, alt and shift key

Maselbas 10 роки тому
батько
коміт
4e32743a83

+ 0 - 204
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/MoveManager.java

@@ -1,204 +0,0 @@
-/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-package com.jme3.gde.scenecomposer.tools;
-
-import com.jme3.bullet.control.CharacterControl;
-import com.jme3.bullet.control.RigidBodyControl;
-import com.jme3.gde.core.undoredo.AbstractUndoableSceneEdit;
-import com.jme3.gde.scenecomposer.SceneEditTool;
-import com.jme3.math.FastMath;
-import com.jme3.math.Quaternion;
-import com.jme3.math.Vector2f;
-import com.jme3.math.Vector3f;
-import com.jme3.renderer.Camera;
-import com.jme3.scene.Geometry;
-import com.jme3.scene.Node;
-import com.jme3.scene.Spatial;
-import com.jme3.scene.shape.Quad;
-import org.openide.util.lookup.ServiceProvider;
-
-/**
- *
- * @author Nehon
- */
-@ServiceProvider(service = MoveManager.class)
-public class MoveManager {
-
-    private Vector3f startLoc;
-    private Vector3f startWorldLoc;
-    private Vector3f lastLoc;
-    private Vector3f offset;
-    private Node alternativePickTarget = null;
-    private Node plane;
-    private Spatial spatial;
-    protected static final Quaternion XY = new Quaternion().fromAngleAxis(0, new Vector3f(1, 0, 0));
-    protected static final Quaternion YZ = new Quaternion().fromAngleAxis(-FastMath.PI / 2, new Vector3f(0, 1, 0));
-    protected static final Quaternion XZ = new Quaternion().fromAngleAxis(FastMath.PI / 2, new Vector3f(1, 0, 0));
-    //temp vars 
-    private Quaternion rot = new Quaternion();
-    private Vector3f newPos = new Vector3f();
-
-    public MoveManager() {
-        float size = 1000;
-        Geometry g = new Geometry("plane", new Quad(size, size));
-        g.setLocalTranslation(-size / 2, -size / 2, 0);
-        plane = new Node();
-        plane.attachChild(g);
-    }
-
-    public Vector3f getOffset() {
-        return offset;
-    }
-
-    public void reset() {
-        offset = null;
-        startLoc = null;
-        startWorldLoc = null;
-        lastLoc = null;
-        spatial = null;
-        alternativePickTarget = null;
-    }
-
-    public void initiateMove(Spatial selectedSpatial, Quaternion planeRotation, boolean local) {
-        spatial = selectedSpatial;
-        startLoc = selectedSpatial.getLocalTranslation().clone();
-        startWorldLoc = selectedSpatial.getWorldTranslation().clone();
-        if (local) {
-            rot.set(selectedSpatial.getWorldRotation());
-            plane.setLocalRotation(rot.multLocal(planeRotation));
-        } else {
-            rot.set(planeRotation);
-        }
-
-        plane.setLocalRotation(rot);
-        plane.setLocalTranslation(startWorldLoc);
-
-    }
-
-    public void updatePlaneRotation(Quaternion planeRotation) {
-        plane.setLocalRotation(rot);
-    }
-
-    public boolean move(Camera camera, Vector2f screenCoord) {
-        return move(camera, screenCoord, Vector3f.UNIT_XYZ, false);
-    }
-
-    public boolean move(Camera camera, Vector2f screenCoord, Vector3f constraintAxis, boolean gridSnap) {
-        Node toPick = alternativePickTarget == null ? plane : alternativePickTarget;
-
-        Vector3f planeHit = SceneEditTool.pickWorldLocation(camera, screenCoord, toPick, alternativePickTarget == null ? null : spatial);
-        if (planeHit == null) {
-            return false;
-        }
-
-        Spatial parent = spatial.getParent();
-        //we are moving the root node, there is a slight chance that something went wrong.
-        if (parent == null) {
-            return false;
-        }
-
-        //offset in world space
-        if (offset == null) {
-            offset = planeHit.subtract(spatial.getWorldTranslation()); // get the offset when we start so it doesn't jump
-        }
-
-        newPos.set(planeHit).subtractLocal(offset);
-
-        //constraining the translation with the contraintAxis.
-        Vector3f tmp = startWorldLoc.mult(Vector3f.UNIT_XYZ.subtract(constraintAxis));
-        newPos.multLocal(constraintAxis).addLocal(tmp);
-        worldToLocalMove(gridSnap);
-        return true;
-    }
-
-    private void worldToLocalMove(boolean gridSnap) {
-        //snap to grid (grid is assumed 1 WU per cell)
-        if (gridSnap) {
-            newPos.set(Math.round(newPos.x), Math.round(newPos.y), Math.round(newPos.z));
-        }
-
-        //computing the inverse world transform to get the new localtranslation        
-        newPos.subtractLocal(spatial.getParent().getWorldTranslation());
-        newPos = spatial.getParent().getWorldRotation().inverse().normalizeLocal().multLocal(newPos);
-        newPos.divideLocal(spatial.getParent().getWorldScale());
-       
-        lastLoc = newPos;
-        spatial.setLocalTranslation(newPos);        
-
-        RigidBodyControl control = spatial.getControl(RigidBodyControl.class);
-        if (control != null) {
-            control.setPhysicsLocation(spatial.getWorldTranslation());
-        }
-        CharacterControl character = spatial.getControl(CharacterControl.class);
-        if (character != null) {
-            character.setPhysicsLocation(spatial.getWorldTranslation());
-        }
-    }
-
-    public boolean moveAcross(Vector3f constraintAxis, float value, boolean gridSnap) {
-        newPos.set(startWorldLoc).addLocal(constraintAxis.mult(value));
-        Spatial parent = spatial.getParent();
-        //we are moving the root node, there is a slight chance that something went wrong.
-        if (parent == null) {
-            return false;
-        }
-        worldToLocalMove(gridSnap);
-        return true;
-    }
-
-    public MoveUndo makeUndo() {
-        return new MoveUndo(spatial, startLoc, lastLoc);
-    }
-
-    public void setAlternativePickTarget(Node alternativePickTarget) {
-        this.alternativePickTarget = alternativePickTarget;
-    }
-
-    protected class MoveUndo extends AbstractUndoableSceneEdit {
-
-        private Spatial spatial;
-        private Vector3f before = new Vector3f(), after = new Vector3f();
-
-        MoveUndo(Spatial spatial, Vector3f before, Vector3f after) {
-            this.spatial = spatial;
-            this.before.set(before);
-            if (after != null) {
-                this.after.set(after);
-            }
-        }
-
-        @Override
-        public void sceneUndo() {
-            spatial.setLocalTranslation(before);
-            RigidBodyControl control = spatial.getControl(RigidBodyControl.class);
-            if (control != null) {
-                control.setPhysicsLocation(spatial.getWorldTranslation());
-            }
-            CharacterControl character = spatial.getControl(CharacterControl.class);
-            if (character != null) {
-                character.setPhysicsLocation(spatial.getWorldTranslation());
-            }
-            //     toolController.selectedSpatialTransformed();
-        }
-
-        @Override
-        public void sceneRedo() {
-            spatial.setLocalTranslation(after);
-            RigidBodyControl control = spatial.getControl(RigidBodyControl.class);
-            if (control != null) {
-                control.setPhysicsLocation(spatial.getWorldTranslation());
-            }
-            CharacterControl character = spatial.getControl(CharacterControl.class);
-            if (character != null) {
-                character.setPhysicsLocation(spatial.getWorldTranslation());
-            }
-            //toolController.selectedSpatialTransformed();
-        }
-
-        public void setAfter(Vector3f after) {
-            this.after.set(after);
-        }
-    }
-}

+ 30 - 664
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/SelectTool.java

@@ -8,425 +8,51 @@ import com.jme3.gde.core.sceneexplorer.SceneExplorerTopComponent;
 import com.jme3.gde.core.sceneexplorer.nodes.JmeNode;
 import com.jme3.gde.core.sceneexplorer.nodes.JmeSpatial;
 import com.jme3.gde.core.sceneviewer.SceneViewerTopComponent;
-import com.jme3.gde.core.undoredo.AbstractUndoableSceneEdit;
 import com.jme3.gde.scenecomposer.SceneEditTool;
-import com.jme3.input.KeyInput;
-import com.jme3.input.event.KeyInputEvent;
-import com.jme3.math.FastMath;
-import com.jme3.math.Quaternion;
 import com.jme3.math.Vector2f;
-import com.jme3.math.Vector3f;
 import com.jme3.scene.Node;
 import com.jme3.scene.Spatial;
 import com.jme3.terrain.Terrain;
 import org.openide.loaders.DataObject;
-import org.openide.util.Lookup;
 
 /**
- * This duplicates the Blender manipulate tool.
- * It supports quick access to Grab, Rotate, and Scale operations
- * by typing one of the following keys: 'g', 'r', or 's'
- * Those keys can be followed by an axis key to specify what axis
- * to perform the transformation: x, y, z
- * Then, after the operation and axis are selected, you can type in a
- * number and then hit 'enter' to complete the transformation.
- * 
- * Ctrl+Shift+D will duplicate an object
- * X will delete an object
- * 
- * ITEMS TO FINISH:
- * 1) fixed scale and rotation values by holding Ctrl and dragging mouse
- * BUGS:
- * 1) window always needs focus from primary click when it should focus from secondary and middle mouse
- * 
+ * This duplicates the Blender manipulate tool. It supports quick access to
+ * Grab, Rotate, and Scale operations by typing one of the following keys: 'g',
+ * 'r', or 's' Those keys can be followed by an axis key to specify what axis to
+ * perform the transformation: x, y, z Then, after the operation and axis are
+ * selected, you can type in a number and then hit 'enter' to complete the
+ * transformation.
+ *
+ * Ctrl+Shift+D will duplicate an object X will delete an object
+ *
+ * ITEMS TO FINISH: 1) fixed scale and rotation values by holding Ctrl and
+ * dragging mouse BUGS: 1) window always needs focus from primary click when it
+ * should focus from secondary and middle mouse
+ *
  * @author Brent Owens
  */
 public class SelectTool extends SceneEditTool {
 
-    private enum State {
-
-        translate, rotate, scale
-    };
-    private State currentState = null;
-    private Vector3f currentAxis = Vector3f.UNIT_XYZ;
-    private StringBuilder numberBuilder = new StringBuilder(); // gets appended with numbers
-    private Quaternion startRot;
-    private Vector3f startTrans;
-    private Vector3f startScale;
-    private boolean wasDraggingL = false;
     private boolean wasDraggingR = false;
     private boolean wasDownR = false;
-    private boolean ctrlDown = false;
-    private boolean shiftDown = false;
-    private boolean altDown = false;
-    private MoveManager.MoveUndo moving;
-    private ScaleUndo scaling;
-    private RotateUndo rotating;
-    private Vector2f startMouseCoord; // for scaling and rotation
-    private Vector2f startSelectedCoord; // for scaling and rotation
-    private float lastRotAngle; // used for rotation
 
     /**
-     * This is stateful:
-     * First it checks for a command (rotate, translate, delete, etc..)
-     * Then it checks for an axis (x,y,z)
-     * Then it checks for a number (user typed a number
-     * Then, finally, it checks if Enter was hit.
-     * 
+     * This is stateful: First it checks for a command (rotate, translate,
+     * delete, etc..) Then it checks for an axis (x,y,z) Then it checks for a
+     * number (user typed a number Then, finally, it checks if Enter was hit.
+     *
      * If either of the commands was actioned, the preceeding states/axis/amount
-     * will be reset. For example if the user types: G Y 2 R
-     * Then it will:
-     * 1) Set state as 'Translate' for the G (grab)
-     * 2) Set the axis as 'Y'; it will translate along the Y axis
-     * 3) Distance will be 2, when the 2 key is hit
-     * 4) Distance, Axis, and state are then reset because a new state was set: Rotate
-     * it won't actually translate because 'Enter' was not hit and 'R' reset the state.
-     * 
+     * will be reset. For example if the user types: G Y 2 R Then it will: 1)
+     * Set state as 'Translate' for the G (grab) 2) Set the axis as 'Y'; it will
+     * translate along the Y axis 3) Distance will be 2, when the 2 key is hit
+     * 4) Distance, Axis, and state are then reset because a new state was set:
+     * Rotate it won't actually translate because 'Enter' was not hit and 'R'
+     * reset the state.
+     *
      */
-    @Override
-    public void keyPressed(KeyInputEvent kie) {
-
-        checkModificatorKeys(kie); // alt,shift,ctrl
-        Spatial selected = toolController.getSelectedSpatial();
-
-        if (selected == null) {
-            return; // only do anything if a spatial is selected
-        }
-        // key released
-        if (kie.isPressed()) {
-            boolean commandUsed = checkCommandKey(kie);
-            boolean stateChange = checkStateKey(kie);
-            boolean axisChange = checkAxisKey(kie);
-            boolean numberChange = checkNumberKey(kie);
-            boolean enterHit = checkEnterHit(kie);
-            boolean escHit = checkEscHit(kie);
-
-            if (commandUsed) {
-                return; // commands take priority
-            }
-            if (stateChange) {
-                currentAxis = Vector3f.UNIT_XYZ;
-                numberBuilder = new StringBuilder();
-                recordInitialState(selected);
-            } else if (axisChange) {
-            } else if (numberChange) {
-            } else if (enterHit) {
-                if (currentState != null && numberBuilder.length() > 0) {
-                    applyKeyedChangeState(selected);
-                    clearState(false);
-                }
-            }
-
-
-            // -----------------------
-            // reset conditions below:
-
-            if (escHit) {
-                if (moving != null) {
-                    moving.sceneUndo();
-                }
-
-                moving = null;
-                clearState();
-            }
-
-            if (!stateChange && !axisChange && !numberChange && !enterHit && !escHit) {
-                // nothing valid was hit, reset the state
-                //clearState(); // this will be 
-            }
-        }
-    }
-
-    /**
-     * Abort any manipulations
-     */
-    private void clearState() {
-        clearState(true);
-    }
-
-    private void clearState(boolean resetSelected) {
-        Spatial selected = toolController.getSelectedSpatial();
-        if (resetSelected && selected != null) {
-            // reset the transforms
-            if (startRot != null) {
-                selected.setLocalRotation(startRot);
-            }
-            if (startTrans != null) {
-                selected.setLocalTranslation(startTrans);
-            }
-            if (startScale != null) {
-                selected.setLocalScale(startScale);
-            }
-        }
-        currentState = null;
-        currentAxis = Vector3f.UNIT_XYZ;
-        numberBuilder = new StringBuilder();
-        startRot = null;
-        startTrans = null;
-        startScale = null;
-        startMouseCoord = null;
-        startSelectedCoord = null;
-        lastRotAngle = 0;
-    }
-
-    private void recordInitialState(Spatial selected) {
-        startRot = selected.getLocalRotation().clone();
-        startTrans = selected.getLocalTranslation().clone();
-        startScale = selected.getLocalScale().clone();
-    }
-
-    /**
-     * Applies the changes entered by a number, not by mouse.
-     * Translate: adds the value to the current local translation
-     * Rotate: rotates by X degrees
-     * Scale: scale the current scale by X amount
-     */
-    private void applyKeyedChangeState(Spatial selected) {
-        Float value = null;
-        try {
-            value = new Float(numberBuilder.toString());
-        } catch (NumberFormatException e) {
-            return;
-        }
-
-        if (currentState == State.translate) {
-            MoveManager moveManager = Lookup.getDefault().lookup(MoveManager.class);
-            moveManager.moveAcross(currentAxis, value, toolController.isSnapToGrid());
-            moving.setAfter(selected.getLocalTranslation());
-            actionPerformed(moving);
-            moving = null;
-        } else if (currentState == State.scale) {
-            float x = 1, y = 1, z = 1;
-            if (currentAxis == Vector3f.UNIT_X) {
-                x = value;
-            } else if (currentAxis == Vector3f.UNIT_Y) {
-                y = value;
-            } else if (currentAxis == Vector3f.UNIT_Z) {
-                z = value;
-            } else if (currentAxis == Vector3f.UNIT_XYZ) {
-                x = value;
-                y = value;
-                z = value;
-            }
-            Vector3f before = selected.getLocalScale().clone();
-            Vector3f after = selected.getLocalScale().multLocal(x, y, z);
-            selected.setLocalScale(after);
-            actionPerformed(new ScaleUndo(selected, before, after));
-        } else if (currentState == State.rotate) {
-            float x = 0, y = 0, z = 0;
-            if (currentAxis == Vector3f.UNIT_X) {
-                x = 1;
-            } else if (currentAxis == Vector3f.UNIT_Y) {
-                y = 1;
-            } else if (currentAxis == Vector3f.UNIT_Z) {
-                z = 1;
-            }
-            Vector3f axis = new Vector3f(x, y, z);
-            Quaternion initialRot = selected.getLocalRotation().clone();
-            Quaternion rot = new Quaternion();
-            rot = rot.fromAngleAxis(value * FastMath.DEG_TO_RAD, axis);
-            selected.setLocalRotation(selected.getLocalRotation().mult(rot));
-            RotateUndo undo = new RotateUndo(selected, initialRot, rot);
-            actionPerformed(undo);
-            toolController.updateSelection(null);// force a re-draw of the bbox shape
-            toolController.updateSelection(selected);
-
-        }
-        clearState(false);
-    }
-
-    private void checkModificatorKeys(KeyInputEvent kie) {
-        if (kie.getKeyCode() == KeyInput.KEY_LCONTROL || kie.getKeyCode() == KeyInput.KEY_RCONTROL) {
-            ctrlDown = kie.isPressed();
-        }
-
-        if (kie.getKeyCode() == KeyInput.KEY_LSHIFT || kie.getKeyCode() == KeyInput.KEY_RSHIFT) {
-            shiftDown = kie.isPressed();
-        }
-
-        if (kie.getKeyCode() == KeyInput.KEY_LMENU || kie.getKeyCode() == KeyInput.KEY_RMENU) {
-            altDown = kie.isPressed();
-        }
-    }
-
-    private boolean checkCommandKey(KeyInputEvent kie) {
-        if (kie.getKeyCode() == KeyInput.KEY_D) {
-            if (shiftDown) {
-                duplicateSelected();
-                return true;
-            }
-        }
-        // X will only delete if the user isn't already transforming
-        if (currentState == null && kie.getKeyCode() == KeyInput.KEY_X) {
-            if (!ctrlDown && !shiftDown) {
-                deleteSelected();
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private boolean checkStateKey(KeyInputEvent kie) {
-        Spatial selected = toolController.getSelectedSpatial();
-        if (kie.getKeyCode() == KeyInput.KEY_G && !ctrlDown) {
-            currentState = State.translate;
-            MoveManager moveManager = Lookup.getDefault().lookup(MoveManager.class);
-            moveManager.reset();
-            Quaternion rot = camera.getRotation().mult(new Quaternion().fromAngleAxis(FastMath.PI, Vector3f.UNIT_Y));
-            moveManager.initiateMove(selected, rot, false);
-            moving = moveManager.makeUndo();
-            return true;
-        } else if (kie.getKeyCode() == KeyInput.KEY_R && !ctrlDown) {
-            currentState = State.rotate;
-            return true;
-        } else if (kie.getKeyCode() == KeyInput.KEY_S && !ctrlDown) {
-            currentState = State.scale;
-            return true;
-        }
-        return false;
-    }
-
-    private boolean checkAxisKey(KeyInputEvent kie) {
-        if (kie.getKeyCode() == KeyInput.KEY_X) {
-            currentAxis = Vector3f.UNIT_X;
-            checkMovePlane(MoveManager.XY, MoveManager.XZ);
-            return true;
-        } else if (kie.getKeyCode() == KeyInput.KEY_Y) {
-            currentAxis = Vector3f.UNIT_Y;
-            checkMovePlane(MoveManager.XY, MoveManager.YZ);
-            return true;
-        } else if (kie.getKeyCode() == KeyInput.KEY_Z) {
-            currentAxis = Vector3f.UNIT_Z;
-            checkMovePlane(MoveManager.XZ, MoveManager.YZ);
-            return true;
-        }
-        return false;
-    }
-
-    private void checkMovePlane(Quaternion rot1, Quaternion rot2) {
-        if (currentState == State.translate) {
-            MoveManager moveManager = Lookup.getDefault().lookup(MoveManager.class);
-            Quaternion rot = camera.getRotation().mult(new Quaternion().fromAngleAxis(FastMath.PI, Vector3f.UNIT_Y));
-            Quaternion planRot = null;
-            if (rot.dot(rot1) < rot.dot(rot2)) {
-                planRot = rot1;
-            } else {
-                planRot = rot2;
-            }
-            moveManager.updatePlaneRotation(planRot);
-        }
-    }
-
-    private boolean checkNumberKey(KeyInputEvent kie) {
-        if (kie.getKeyCode() == KeyInput.KEY_MINUS) {
-            if (numberBuilder.length() > 0) {
-                if (numberBuilder.charAt(0) == '-') {
-                    numberBuilder.replace(0, 1, "");
-                } else {
-                    numberBuilder.insert(0, '-');
-                }
-            } else {
-                numberBuilder.append('-');
-            }
-            return true;
-        } else if (kie.getKeyCode() == KeyInput.KEY_0 || kie.getKeyCode() == KeyInput.KEY_NUMPAD0) {
-            numberBuilder.append('0');
-            return true;
-        } else if (kie.getKeyCode() == KeyInput.KEY_1 || kie.getKeyCode() == KeyInput.KEY_NUMPAD1) {
-            numberBuilder.append('1');
-            return true;
-        } else if (kie.getKeyCode() == KeyInput.KEY_2 || kie.getKeyCode() == KeyInput.KEY_NUMPAD2) {
-            numberBuilder.append('2');
-            return true;
-        } else if (kie.getKeyCode() == KeyInput.KEY_3 || kie.getKeyCode() == KeyInput.KEY_NUMPAD3) {
-            numberBuilder.append('3');
-            return true;
-        } else if (kie.getKeyCode() == KeyInput.KEY_4 || kie.getKeyCode() == KeyInput.KEY_NUMPAD4) {
-            numberBuilder.append('4');
-            return true;
-        } else if (kie.getKeyCode() == KeyInput.KEY_5 || kie.getKeyCode() == KeyInput.KEY_NUMPAD5) {
-            numberBuilder.append('5');
-            return true;
-        } else if (kie.getKeyCode() == KeyInput.KEY_6 || kie.getKeyCode() == KeyInput.KEY_NUMPAD6) {
-            numberBuilder.append('6');
-            return true;
-        } else if (kie.getKeyCode() == KeyInput.KEY_7 || kie.getKeyCode() == KeyInput.KEY_NUMPAD7) {
-            numberBuilder.append('7');
-            return true;
-        } else if (kie.getKeyCode() == KeyInput.KEY_8 || kie.getKeyCode() == KeyInput.KEY_NUMPAD8) {
-            numberBuilder.append('8');
-            return true;
-        } else if (kie.getKeyCode() == KeyInput.KEY_9 || kie.getKeyCode() == KeyInput.KEY_NUMPAD9) {
-            numberBuilder.append('9');
-            return true;
-        } else if (kie.getKeyCode() == KeyInput.KEY_PERIOD) {
-            if (numberBuilder.indexOf(".") == -1) { // if it doesn't exist yet
-                if (numberBuilder.length() == 0
-                        || (numberBuilder.length() == 1 && numberBuilder.charAt(0) == '-')) {
-                    numberBuilder.append("0.");
-                } else {
-                    numberBuilder.append(".");
-                }
-            }
-            return true;
-        }
-
-        return false;
-    }
-
-    private boolean checkEnterHit(KeyInputEvent kie) {
-        if (kie.getKeyCode() == KeyInput.KEY_RETURN) {
-            return true;
-        }
-        return false;
-    }
-
-    private boolean checkEscHit(KeyInputEvent kie) {
-        if (kie.getKeyCode() == KeyInput.KEY_ESCAPE) {
-            return true;
-        }
-        return false;
-    }
-
     @Override
     public void actionPrimary(Vector2f screenCoord, boolean pressed, final JmeNode rootNode, DataObject dataObject) {
-        if (!pressed) {
-            Spatial selected = toolController.getSelectedSpatial();
-            // left mouse released
-            if (!wasDraggingL) {
-                // left mouse pressed
-                if (currentState != null) {
-                    // finish manipulating the spatial
-                    if (moving != null) {
-                        moving.setAfter(selected.getLocalTranslation());
-                        actionPerformed(moving);
-                        moving = null;
-                        clearState(false);
-                    } else if (scaling != null) {
-                        scaling.after = selected.getLocalScale().clone();
-                        actionPerformed(scaling);
-                        scaling = null;
-                        clearState(false);
-                        toolController.rebuildSelectionBox();
-                    } else if (rotating != null) {
-                        rotating.after = selected.getLocalRotation().clone();
-                        actionPerformed(rotating);
-                        rotating = null;
-                        clearState(false);
-                    }
-                } else {
-                    // mouse released and wasn't dragging, place cursor
-                    final Vector3f result = pickWorldLocation(getCamera(), screenCoord, rootNode);
-                    if (result != null) {
-                        if (toolController.isSnapToGrid()) {
-                            result.set(Math.round(result.x), result.y, Math.round(result.z));
-                        }
-                        toolController.setCursorLocation(result);
-                    }
-                }
-            }
-            wasDraggingL = false;
-        }
+
     }
 
     @Override
@@ -435,19 +61,7 @@ public class SelectTool extends SceneEditTool {
             Spatial selected = toolController.getSelectedSpatial();
             // mouse down
 
-            if (moving != null) {
-                moving.sceneUndo();
-                moving = null;
-                clearState();
-            } else if (scaling != null) {
-                scaling.sceneUndo();
-                scaling = null;
-                clearState();
-            } else if (rotating != null) {
-                rotating.sceneUndo();
-                rotating = null;
-                clearState();
-            } else if (!wasDraggingR && !wasDownR) { // wasn't dragging and was not down already
+            if (!wasDraggingR && !wasDownR) { // wasn't dragging and was not down already
                 // pick on the spot
                 Spatial s = pickWorldSpatial(camera, screenCoord, rootNode);
                 if (!toolController.selectTerrain() && isTerrain(s)) {
@@ -498,8 +112,8 @@ public class SelectTool extends SceneEditTool {
     }
 
     /**
-     * Climb up the spatial until we find the first node parent.
-     * TODO: use userData to determine the actual model's parent.
+     * Climb up the spatial until we find the first node parent. TODO: use
+     * userData to determine the actual model's parent.
      */
     private Spatial findModelNodeParent(Spatial child) {
         if (child == null) {
@@ -519,14 +133,10 @@ public class SelectTool extends SceneEditTool {
 
     @Override
     public void mouseMoved(Vector2f screenCoord, JmeNode rootNode, DataObject currentDataObject, JmeSpatial selectedSpatial) {
-        if (currentState != null) {
-            handleMouseManipulate(screenCoord, currentState, currentAxis, rootNode, currentDataObject, selectedSpatial);
-        }
     }
 
     @Override
     public void draggedPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) {
-        wasDraggingL = pressed;
     }
 
     @Override
@@ -535,252 +145,8 @@ public class SelectTool extends SceneEditTool {
     }
 
     /**
-     * Manipulate the spatial
-     */
-    private void handleMouseManipulate(Vector2f screenCoord,
-            State state,
-            Vector3f axis,
-            JmeNode rootNode,
-            DataObject currentDataObject,
-            JmeSpatial selectedSpatial) {
-        if (state == State.translate) {
-            doMouseTranslate(axis, screenCoord, rootNode, selectedSpatial);
-        } else if (state == State.scale) {
-            doMouseScale(axis, screenCoord, rootNode, selectedSpatial);
-        } else if (state == State.rotate) {
-            doMouseRotate(axis, screenCoord, rootNode, selectedSpatial);
-        }
-
-    }
-
-    private void doMouseTranslate(Vector3f axis, Vector2f screenCoord, JmeNode rootNode, JmeSpatial selectedSpatial) {
-        MoveManager moveManager = Lookup.getDefault().lookup(MoveManager.class);
-        if (toolController.isSnapToScene()) {
-            moveManager.setAlternativePickTarget(rootNode.getLookup().lookup(Node.class));
-        }
-        // free form translation
-        moveManager.move(camera, screenCoord, axis, toolController.isSnapToGrid());
-    }
-
-    private void doMouseScale(Vector3f axis, Vector2f screenCoord, JmeNode rootNode, JmeSpatial selectedSpatial) {
-        Spatial selected = toolController.getSelectedSpatial();
-        // scale based on the original mouse position and original model-to-screen position
-        // and compare that to the distance from the new mouse position and the original distance
-        if (startMouseCoord == null) {
-            startMouseCoord = screenCoord.clone();
-        }
-        if (startSelectedCoord == null) {
-            Vector3f screen = getCamera().getScreenCoordinates(selected.getWorldTranslation());
-            startSelectedCoord = new Vector2f(screen.x, screen.y);
-        }
-
-        if (scaling == null) {
-            scaling = new ScaleUndo(selected, selected.getLocalScale().clone(), null);
-        }
-
-        float origDist = startMouseCoord.distanceSquared(startSelectedCoord);
-        float newDist = screenCoord.distanceSquared(startSelectedCoord);
-        if (origDist == 0) {
-            origDist = 1;
-        }
-        float ratio = newDist / origDist;
-        Vector3f prev = selected.getLocalScale();
-        if (axis == Vector3f.UNIT_X) {
-            selected.setLocalScale(ratio, prev.y, prev.z);
-        } else if (axis == Vector3f.UNIT_Y) {
-            selected.setLocalScale(prev.x, ratio, prev.z);
-        } else if (axis == Vector3f.UNIT_Z) {
-            selected.setLocalScale(prev.x, prev.y, ratio);
-        } else {
-            selected.setLocalScale(ratio, ratio, ratio);
-        }
-    }
-
-    private void doMouseRotate(Vector3f axis, Vector2f screenCoord, JmeNode rootNode, JmeSpatial selectedSpatial) {
-        Spatial selected = toolController.getSelectedSpatial();
-        if (startMouseCoord == null) {
-            startMouseCoord = screenCoord.clone();
-        }
-        if (startSelectedCoord == null) {
-            Vector3f screen = getCamera().getScreenCoordinates(selected.getWorldTranslation());
-            startSelectedCoord = new Vector2f(screen.x, screen.y);
-        }
-
-        if (rotating == null) {
-            rotating = new RotateUndo(selected, selected.getLocalRotation().clone(), null);
-        }
-
-        Vector2f origRot = startMouseCoord.subtract(startSelectedCoord);
-        Vector2f newRot = screenCoord.subtract(startSelectedCoord);
-        float newRotAngle = origRot.angleBetween(newRot);
-        float temp = newRotAngle;
-
-        if (lastRotAngle != 0) {
-            newRotAngle -= lastRotAngle;
-        }
-
-        lastRotAngle = temp;
-
-        Quaternion rotate = new Quaternion();
-        if (axis != Vector3f.UNIT_XYZ) {
-            rotate = rotate.fromAngleAxis(newRotAngle, selected.getWorldRotation().inverse().mult(axis));
-        } else {
-            rotate = rotate.fromAngleAxis(newRotAngle, selected.getWorldRotation().inverse().mult(getCamera().getDirection().mult(-1).normalizeLocal()));
-        }
-        selected.setLocalRotation(selected.getLocalRotation().mult(rotate));
-
-
-    }
-
-    private void duplicateSelected() {
-        Spatial selected = toolController.getSelectedSpatial();
-        if (selected == null) {
-            return;
-        }
-        Spatial clone = selected.clone();
-        clone.move(1, 0, 1);
-
-        selected.getParent().attachChild(clone);
-        actionPerformed(new DuplicateUndo(clone, selected.getParent()));
-        selected = clone;
-        final Spatial cloned = clone;
-        final JmeNode rootNode = toolController.getRootNode();
-        refreshSelected(rootNode, selected.getParent());
-
-        java.awt.EventQueue.invokeLater(new Runnable() {
-
-            @Override
-            public void run() {
-                if (cloned != null) {
-                    SceneViewerTopComponent.findInstance().setActivatedNodes(new org.openide.nodes.Node[]{rootNode.getChild(cloned)});
-                    SceneExplorerTopComponent.findInstance().setSelectedNode(rootNode.getChild(cloned));
-                }
-            }
-        });
-
-        // set to automatically 'grab'/'translate' the new cloned model
-        toolController.updateSelection(selected);
-        currentState = State.translate;
-        currentAxis = Vector3f.UNIT_XYZ;
-    }
-
-    private void deleteSelected() {
-        Spatial selected = toolController.getSelectedSpatial();
-        if (selected == null) {
-            return;
-        }
-        Node parent = selected.getParent();
-        selected.removeFromParent();
-        actionPerformed(new DeleteUndo(selected, parent));
-
-        selected = null;
-        toolController.updateSelection(selected);
-
-        final JmeNode rootNode = toolController.getRootNode();
-        refreshSelected(rootNode, parent);
-    }
-
-    private void refreshSelected(final JmeNode jmeRootNode, final Node parent) {
-        java.awt.EventQueue.invokeLater(new Runnable() {
-
-            @Override
-            public void run() {
-                jmeRootNode.getChild(parent).refresh(false);
-            }
-        });
-    }
-
-    private class ScaleUndo extends AbstractUndoableSceneEdit {
-
-        private Spatial spatial;
-        private Vector3f before, after;
-
-        ScaleUndo(Spatial spatial, Vector3f before, Vector3f after) {
-            this.spatial = spatial;
-            this.before = before;
-            this.after = after;
-        }
-
-        @Override
-        public void sceneUndo() {
-            spatial.setLocalScale(before);
-        }
-
-        @Override
-        public void sceneRedo() {
-            spatial.setLocalScale(after);
-        }
-    }
-
-    private class RotateUndo extends AbstractUndoableSceneEdit {
-
-        private Spatial spatial;
-        private Quaternion before, after;
-
-        RotateUndo(Spatial spatial, Quaternion before, Quaternion after) {
-            this.spatial = spatial;
-            this.before = before;
-            this.after = after;
-        }
-
-        @Override
-        public void sceneUndo() {
-            spatial.setLocalRotation(before);
-        }
-
-        @Override
-        public void sceneRedo() {
-            spatial.setLocalRotation(after);
-        }
-    }
-
-    private class DeleteUndo extends AbstractUndoableSceneEdit {
-
-        private Spatial spatial;
-        private Node parent;
-
-        DeleteUndo(Spatial spatial, Node parent) {
-            this.spatial = spatial;
-            this.parent = parent;
-        }
-
-        @Override
-        public void sceneUndo() {
-            parent.attachChild(spatial);
-        }
-
-        @Override
-        public void sceneRedo() {
-            spatial.removeFromParent();
-        }
-    }
-
-    private class DuplicateUndo extends AbstractUndoableSceneEdit {
-
-        private Spatial spatial;
-        private Node parent;
-
-        DuplicateUndo(Spatial spatial, Node parent) {
-            this.spatial = spatial;
-            this.parent = parent;
-        }
-
-        @Override
-        public void sceneUndo() {
-            spatial.removeFromParent();
-        }
-
-        @Override
-        public void sceneRedo() {
-            parent.attachChild(spatial);
-        }
-    }
-
-    /**
-     * Check if the selected item is a Terrain
-     * It will climb up the parent tree to see if
-     * a parent is terrain too.
-     * Recursive call.
+     * Check if the selected item is a Terrain It will climb up the parent tree
+     * to see if a parent is terrain too. Recursive call.
      */
     protected boolean isTerrain(Spatial s) {
         if (s == null) {

+ 123 - 0
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/DeleteShortcut.java

@@ -0,0 +1,123 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.scenecomposer.tools.shortcuts;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.gde.core.sceneexplorer.SceneExplorerTopComponent;
+import com.jme3.gde.core.sceneexplorer.nodes.JmeNode;
+import com.jme3.gde.core.sceneexplorer.nodes.JmeSpatial;
+import com.jme3.gde.core.sceneviewer.SceneViewerTopComponent;
+import com.jme3.gde.core.undoredo.AbstractUndoableSceneEdit;
+import com.jme3.gde.scenecomposer.SceneComposerToolController;
+import com.jme3.input.KeyInput;
+import com.jme3.input.event.KeyInputEvent;
+import com.jme3.math.Vector2f;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import org.openide.loaders.DataObject;
+import org.openide.util.Lookup;
+
+/**
+ *
+ * @author dokthar
+ */
+public class DeleteShortcut extends ShortcutTool {
+
+    @Override
+    public boolean isActivableBy(KeyInputEvent kie) {
+        if (kie.getKeyCode() == KeyInput.KEY_X && kie.isPressed()) {
+            if (Lookup.getDefault().lookup(ShortcutManager.class).isShiftDown()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void cancel() {
+        terminate();
+    }
+
+    @Override
+    public void activate(AssetManager manager, Node toolNode, Node onTopToolNode, Spatial selectedSpatial, SceneComposerToolController toolController) {
+        super.activate(manager, toolNode, onTopToolNode, selectedSpatial, toolController); //To change body of generated methods, choose Tools | Templates.
+        hideMarker();
+        if (selectedSpatial != null) {
+            delete();
+        }
+        terminate();
+    }
+
+    private void delete() {
+        Spatial selected = toolController.getSelectedSpatial();
+
+        Node parent = selected.getParent();
+        selected.removeFromParent();
+        actionPerformed(new DeleteUndo(selected, parent));
+
+        selected = null;
+        toolController.updateSelection(selected);
+
+        final JmeNode rootNode = toolController.getRootNode();
+        refreshSelected(rootNode, parent);
+    }
+
+    private void refreshSelected(final JmeNode jmeRootNode, final Node parent) {
+        java.awt.EventQueue.invokeLater(new Runnable() {
+
+            @Override
+            public void run() {
+                jmeRootNode.getChild(parent).refresh(false);
+            }
+        });
+    }
+
+    @Override
+    public void keyPressed(KeyInputEvent kie) {
+
+    }
+
+    @Override
+    public void actionPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) {
+    }
+
+    @Override
+    public void actionSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) {
+    }
+
+    @Override
+    public void mouseMoved(Vector2f screenCoord, JmeNode rootNode, DataObject dataObject, JmeSpatial selectedSpatial) {
+    }
+
+    @Override
+    public void draggedPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) {
+    }
+
+    @Override
+    public void draggedSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) {
+    }
+    
+    private class DeleteUndo extends AbstractUndoableSceneEdit {
+
+        private Spatial spatial;
+        private Node parent;
+
+        DeleteUndo(Spatial spatial, Node parent) {
+            this.spatial = spatial;
+            this.parent = parent;
+        }
+
+        @Override
+        public void sceneUndo() {
+            parent.attachChild(spatial);
+        }
+
+        @Override
+        public void sceneRedo() {
+            spatial.removeFromParent();
+        }
+    }
+}

+ 141 - 0
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/DuplicateShortcut.java

@@ -0,0 +1,141 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.gde.scenecomposer.tools.shortcuts;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.gde.core.sceneexplorer.SceneExplorerTopComponent;
+import com.jme3.gde.core.sceneexplorer.nodes.JmeNode;
+import com.jme3.gde.core.sceneexplorer.nodes.JmeSpatial;
+import com.jme3.gde.core.sceneviewer.SceneViewerTopComponent;
+import com.jme3.gde.core.undoredo.AbstractUndoableSceneEdit;
+import com.jme3.gde.scenecomposer.SceneComposerToolController;
+import com.jme3.input.KeyInput;
+import com.jme3.input.event.KeyInputEvent;
+import com.jme3.math.Vector2f;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import org.openide.loaders.DataObject;
+import org.openide.util.Lookup;
+
+/**
+ *
+ * @author dokthar
+ */
+public class DuplicateShortcut extends ShortcutTool {
+
+    @Override
+    public boolean isActivableBy(KeyInputEvent kie) {
+        if (kie.getKeyCode() == KeyInput.KEY_D && kie.isPressed()) {
+            if (Lookup.getDefault().lookup(ShortcutManager.class).isShiftDown()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void cancel() {
+        terminate();
+    }
+
+    @Override
+    public void activate(AssetManager manager, Node toolNode, Node onTopToolNode, Spatial selectedSpatial, SceneComposerToolController toolController) {
+        super.activate(manager, toolNode, onTopToolNode, selectedSpatial, toolController); //To change body of generated methods, choose Tools | Templates.
+        hideMarker();
+        if (selectedSpatial != null) {
+            duplicate();
+            terminate();
+            
+            //then enable move shortcut
+            toolController.doKeyPressed(new KeyInputEvent(KeyInput.KEY_G, 'g', true, false));
+        } else {
+            terminate();
+        }
+    }
+
+    private void duplicate() {
+        Spatial selected = toolController.getSelectedSpatial();
+
+        Spatial clone = selected.clone();
+        clone.move(1, 0, 1);
+
+        selected.getParent().attachChild(clone);
+        actionPerformed(new DuplicateUndo(clone, selected.getParent()));
+        selected = clone;
+        final Spatial cloned = clone;
+        final JmeNode rootNode = toolController.getRootNode();
+        refreshSelected(rootNode, selected.getParent());
+
+        java.awt.EventQueue.invokeLater(new Runnable() {
+
+            @Override
+            public void run() {
+                if (cloned != null) {
+                    SceneViewerTopComponent.findInstance().setActivatedNodes(new org.openide.nodes.Node[]{rootNode.getChild(cloned)});
+                    SceneExplorerTopComponent.findInstance().setSelectedNode(rootNode.getChild(cloned));
+                }
+            }
+        });
+
+        toolController.updateSelection(selected);
+    }
+
+    private void refreshSelected(final JmeNode jmeRootNode, final Node parent) {
+        java.awt.EventQueue.invokeLater(new Runnable() {
+
+            @Override
+            public void run() {
+                jmeRootNode.getChild(parent).refresh(false);
+            }
+        });
+    }
+
+    @Override
+    public void keyPressed(KeyInputEvent kie) {
+
+    }
+
+    @Override
+    public void actionPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) {
+    }
+
+    @Override
+    public void actionSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) {
+    }
+
+    @Override
+    public void mouseMoved(Vector2f screenCoord, JmeNode rootNode, DataObject dataObject, JmeSpatial selectedSpatial) {
+    }
+
+    @Override
+    public void draggedPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) {
+    }
+
+    @Override
+    public void draggedSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) {
+    }
+
+    private class DuplicateUndo extends AbstractUndoableSceneEdit {
+
+        private Spatial spatial;
+        private Node parent;
+
+        DuplicateUndo(Spatial spatial, Node parent) {
+            this.spatial = spatial;
+            this.parent = parent;
+        }
+
+        @Override
+        public void sceneUndo() {
+            spatial.removeFromParent();
+        }
+
+        @Override
+        public void sceneRedo() {
+            parent.attachChild(spatial);
+        }
+    }
+}

+ 48 - 4
jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/ShortcutManager.java

@@ -22,12 +22,17 @@ public class ShortcutManager {
 
     private ShortcutTool currentShortcut;
     private ArrayList<ShortcutTool> shortcutList;
+    private boolean ctrlDown = false;
+    private boolean shiftDown = false;
+    private boolean altDown = false;
 
     public ShortcutManager() {
         shortcutList = new ArrayList<ShortcutTool>();
         shortcutList.add(new MoveShortcut());
         shortcutList.add(new RotateShortcut());
         shortcutList.add(new ScaleShortcut());
+        shortcutList.add(new DuplicateShortcut());
+        shortcutList.add(new DeleteShortcut());
     }
 
     /*
@@ -41,6 +46,27 @@ public class ShortcutManager {
         return currentShortcut != null;
     }
 
+    /**
+     * @return the ctrlDown
+     */
+    public boolean isCtrlDown() {
+        return ctrlDown;
+    }
+
+    /**
+     * @return the shiftDown
+     */
+    public boolean isShiftDown() {
+        return shiftDown;
+    }
+
+    /**
+     * @return the altDown
+     */
+    public boolean isAltDown() {
+        return altDown;
+    }
+
     public void setShortCut(ShortcutTool shortcut) {
         if (isActive()) {
             currentShortcut.cancel();
@@ -49,6 +75,9 @@ public class ShortcutManager {
     }
 
     public ShortcutTool getActivableShortcut(KeyInputEvent kie) {
+        if (checkCommandeKey(kie)) {
+            return null;
+        } 
         for (ShortcutTool s : shortcutList) {
             if (s != currentShortcut) {
                 if (s.isActivableBy(kie)) {
@@ -69,12 +98,12 @@ public class ShortcutManager {
 
     public boolean activateShortcut(KeyInputEvent kie) {
         ShortcutTool newShortcut = getActivableShortcut(kie);
-        if(newShortcut != null){
+        if (newShortcut != null) {
             currentShortcut = newShortcut;
         }
         return newShortcut != null;
     }
-    
+
     /**
      * This should be called to trigger the currentShortcut.keyPressed() method.
      * This method do a first check for command key used to provide isCtrlDown,
@@ -83,12 +112,27 @@ public class ShortcutManager {
      * @param kie
      */
     public void doKeyPressed(KeyInputEvent kie) {
-        ///todo check commande key
-        if (isActive()) {
+        if (checkCommandeKey(kie)) {
+            //return;
+        } else if (isActive()) {
             currentShortcut.keyPressed(kie);
         }
     }
 
+    private boolean checkCommandeKey(KeyInputEvent kie) {
+        if (checkCtrlHit(kie)) {
+            ctrlDown = kie.isPressed();
+            return true;
+        } else if (checkAltHit(kie)) {
+            altDown = kie.isPressed();
+            return true;
+        } else if (checkShiftHit(kie)) {
+            shiftDown = kie.isPressed();
+            return true;
+        }
+        return false;
+    }
+
     /*
      STATIC
      */