|
@@ -31,22 +31,17 @@
|
|
*/
|
|
*/
|
|
package com.jme3.gde.core.sceneexplorer.nodes;
|
|
package com.jme3.gde.core.sceneexplorer.nodes;
|
|
|
|
|
|
-import com.jme3.cinematic.MotionPath;
|
|
|
|
import com.jme3.gde.core.scene.SceneApplication;
|
|
import com.jme3.gde.core.scene.SceneApplication;
|
|
-import com.jme3.gde.core.scene.controller.SceneToolController;
|
|
|
|
-import com.jme3.gde.core.sceneexplorer.SceneExplorerTopComponent;
|
|
|
|
|
|
+import com.jme3.math.Spline;
|
|
import com.jme3.math.Vector3f;
|
|
import com.jme3.math.Vector3f;
|
|
|
|
+import java.util.logging.Logger;
|
|
import java.util.ArrayList;
|
|
import java.util.ArrayList;
|
|
-import java.util.Arrays;
|
|
|
|
-import java.util.HashMap;
|
|
|
|
import java.util.LinkedList;
|
|
import java.util.LinkedList;
|
|
import java.util.List;
|
|
import java.util.List;
|
|
import java.util.concurrent.Callable;
|
|
import java.util.concurrent.Callable;
|
|
import java.util.concurrent.ExecutionException;
|
|
import java.util.concurrent.ExecutionException;
|
|
-import javax.swing.event.ChangeEvent;
|
|
|
|
-import javax.swing.event.ChangeListener;
|
|
|
|
|
|
+import java.util.logging.Level;
|
|
import org.openide.loaders.DataObject;
|
|
import org.openide.loaders.DataObject;
|
|
-import org.openide.nodes.Children;
|
|
|
|
import org.openide.nodes.Index;
|
|
import org.openide.nodes.Index;
|
|
import org.openide.nodes.Node;
|
|
import org.openide.nodes.Node;
|
|
import org.openide.util.Exceptions;
|
|
import org.openide.util.Exceptions;
|
|
@@ -58,13 +53,10 @@ import org.openide.util.Exceptions;
|
|
* It will use this class as Children (which are JmeMotionPaths)<br>
|
|
* It will use this class as Children (which are JmeMotionPaths)<br>
|
|
* @author MeFisto94
|
|
* @author MeFisto94
|
|
*/
|
|
*/
|
|
-public class JmeVector3fChildren extends Children.Keys<Vector3f> implements Index {
|
|
|
|
|
|
+public class JmeVector3fChildren extends Index.ArrayChildren {
|
|
|
|
|
|
protected JmeMotionPath jmeMotionPath;
|
|
protected JmeMotionPath jmeMotionPath;
|
|
protected boolean readOnly = true;
|
|
protected boolean readOnly = true;
|
|
-
|
|
|
|
- protected List<Vector3f> keys;
|
|
|
|
- protected LinkedList<ChangeListener> listeners = new LinkedList<ChangeListener>();
|
|
|
|
private DataObject dataObject;
|
|
private DataObject dataObject;
|
|
|
|
|
|
public JmeVector3fChildren() {
|
|
public JmeVector3fChildren() {
|
|
@@ -75,22 +67,16 @@ public class JmeVector3fChildren extends Children.Keys<Vector3f> implements Inde
|
|
}
|
|
}
|
|
|
|
|
|
public void refreshChildren(boolean immediate) {
|
|
public void refreshChildren(boolean immediate) {
|
|
- keys = createKeys();
|
|
|
|
- setKeys(keys);
|
|
|
|
refresh();
|
|
refresh();
|
|
|
|
+ for (Node n : getNodes()) {
|
|
|
|
+ n.setDisplayName("Waypoint " + indexOf(n));
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
public void setReadOnly(boolean cookie) {
|
|
public void setReadOnly(boolean cookie) {
|
|
this.readOnly = cookie;
|
|
this.readOnly = cookie;
|
|
}
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
|
- protected void addNotify() {
|
|
|
|
- super.addNotify();
|
|
|
|
- keys = createKeys();
|
|
|
|
- setKeys(keys);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
protected List<Vector3f> createKeys() {
|
|
protected List<Vector3f> createKeys() {
|
|
try {
|
|
try {
|
|
return SceneApplication.getApplication().enqueue(new Callable<List<Vector3f>>() {
|
|
return SceneApplication.getApplication().enqueue(new Callable<List<Vector3f>>() {
|
|
@@ -114,14 +100,66 @@ public class JmeVector3fChildren extends Children.Keys<Vector3f> implements Inde
|
|
}
|
|
}
|
|
return null;
|
|
return null;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * This is called when Index.ArrayChildren initiates it's list.
|
|
|
|
+ * It's similar to createNodes and createKeys.
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
@Override
|
|
@Override
|
|
- protected Node[] createNodes(Vector3f key) {
|
|
|
|
- Node n = new JmeVector3f(this, jmeMotionPath, key).setReadOnly(readOnly);
|
|
|
|
- n.setDisplayName("Waypoint " + keys.indexOf(key));
|
|
|
|
- return new Node[]{ n };
|
|
|
|
|
|
+ protected List<Node> initCollection() {
|
|
|
|
+ List<Vector3f> keyList = createKeys();
|
|
|
|
+ ArrayList<Node> nodeList = new ArrayList<Node>(keyList.size());
|
|
|
|
+ int i = 0;
|
|
|
|
+
|
|
|
|
+ for (Vector3f v: keyList) {
|
|
|
|
+ Node n = new JmeVector3f(this, jmeMotionPath, v).setReadOnly(readOnly);
|
|
|
|
+ n.setDisplayName("Waypoint " + i);
|
|
|
|
+ nodeList.add(n);
|
|
|
|
+ i++;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return nodeList;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ @Override
|
|
|
|
+ public boolean remove(Node[] arr) {
|
|
|
|
+ for (Node n : arr) {
|
|
|
|
+ jmeMotionPath.getMotionPath().removeWayPoint(((JmeVector3f)n).getVector3f());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return super.remove(arr);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public boolean add(Node[] arr) {
|
|
|
|
+ for (Node n: arr) {
|
|
|
|
+ //DON'T USE THIS -> jmeMotionPath.getMotionPath().addWayPoint(v);
|
|
|
|
+ // It will clone v and as such we're not able to change it anymore.
|
|
|
|
+ //jmeMotionPath.getMotionPath().getSpline().getControlPoints().add(((JmeVector3f)n).getVector3f());
|
|
|
|
+ addControlPoint(jmeMotionPath.getMotionPath().getSpline(), ((JmeVector3f)n).getVector3f());
|
|
|
|
+ // Alternative could be nodes = initCollection()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return super.add(arr);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Code taken from Spline.java, except the clone part */
|
|
|
|
+ private void addControlPoint(Spline spline, Vector3f controlPoint) {
|
|
|
|
+ List<Vector3f> controlPoints = spline.getControlPoints();
|
|
|
|
+ if (controlPoints.size() > 2 && spline.isCycle()) {
|
|
|
|
+ controlPoints.remove(controlPoints.size() - 1);
|
|
|
|
+ }
|
|
|
|
+ controlPoints.add(controlPoint);
|
|
|
|
+ if (controlPoints.size() >= 2 && spline.isCycle()) {
|
|
|
|
+ controlPoints.add(controlPoints.get(0).clone());
|
|
|
|
+ }
|
|
|
|
+ if (controlPoints.size() > 1) {
|
|
|
|
+ // spline.computeTotalLength();
|
|
|
|
+ spline.setCurveTension(spline.getCurveTension());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* This Method is used because before createNodes takes place we are called by the default constructor and have to pass things...
|
|
* This Method is used because before createNodes takes place we are called by the default constructor and have to pass things...
|
|
* @param jmeMotionPath The JmeMotionPath instance which is this nodes parent.
|
|
* @param jmeMotionPath The JmeMotionPath instance which is this nodes parent.
|
|
@@ -137,135 +175,33 @@ public class JmeVector3fChildren extends Children.Keys<Vector3f> implements Inde
|
|
this.dataObject = dataObject;
|
|
this.dataObject = dataObject;
|
|
}
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
|
- public int indexOf(Node node) {
|
|
|
|
- Vector3f key = node.getLookup().lookup(Vector3f.class); // reverseLookup.get(node);
|
|
|
|
-
|
|
|
|
- if (key == null)
|
|
|
|
- return -1;
|
|
|
|
-
|
|
|
|
- return keys.indexOf(key); // For this to work, keys has to have ALWAYS be in sync for EVERY Change to the MotionPath.Waypoints
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * "Invoke a dialog for reordering the children."
|
|
|
|
|
|
+ /* Basically we should override everything from Index.ArrayChildren, but it's no fun and since we don't support dragging them (which could need exchange()
|
|
|
|
+ * we just stick with this way :P
|
|
*/
|
|
*/
|
|
- @Override
|
|
|
|
- public void reorder() {
|
|
|
|
- // We wont...
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * Reorder all children with a given permutation.
|
|
|
|
- * TODO: Test this....
|
|
|
|
- * @param perm - permutation with the length of current nodes. The permutation lists the new positions of the original nodes, that is, for nodes [A,B,C,D] and permutation [0,3,1,2], the final order would be [A,C,D,B].
|
|
|
|
- * @throws IllegalArgumentException - if the permutation is not valid
|
|
|
|
- */
|
|
|
|
- @Override
|
|
|
|
- public void reorder(int[] perm) {
|
|
|
|
- List<Vector3f> oldKeys = Arrays.asList((Vector3f[])keys.toArray());
|
|
|
|
-
|
|
|
|
- for (int i = 0; i < perm.length; i++) {
|
|
|
|
- keys.get(i).set(oldKeys.get(perm[i]));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- triggerChangeListeners();
|
|
|
|
-
|
|
|
|
- for (Node n: getNodes()) {
|
|
|
|
- ((JmeVector3f)n).moveBox();
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * Move the element at the x-th position to the y-th position. All elements after the y-th position are moved down.
|
|
|
|
- * @param x the position to remove the element from
|
|
|
|
- * @param y the position to insert the element to
|
|
|
|
- */
|
|
|
|
- @Override
|
|
|
|
- public void move(int x, int y) {
|
|
|
|
- MotionPath m = jmeMotionPath.getMotionPath();
|
|
|
|
- /* TODO: Check and Implement Method correctly. */
|
|
|
|
- if (x < y) { /* X above Y, means: remove x, shift everything until y up, move everything from y one down. set x to y's value. */
|
|
|
|
- Vector3f v_x = keys.get(x).clone(); // We can't use remove() because of the MotionPaths
|
|
|
|
- for (int i = x+1; i <= y - 1; i++) {
|
|
|
|
- moveUp(i); // This causes quite some rendering updates and messes up the selection, but when it's there, we use it.
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- for (int i = keys.size() - 2; i >= y; i--) {
|
|
|
|
- moveDown(i);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- keys.get(y).set(v_x);
|
|
|
|
- } else { /* X below Y, means: remove x, shift everything until end up, move everyting from x one down. set y to x's value */
|
|
|
|
- // TODO IMPLEMENT
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- triggerChangeListeners();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+
|
|
/**
|
|
/**
|
|
- * Exchange two elements.
|
|
|
|
- * @param x Position of the first Element
|
|
|
|
- * @param y Position of the second Element
|
|
|
|
|
|
+ * Move an element up
|
|
|
|
+ * @param i index of element to move up
|
|
*/
|
|
*/
|
|
@Override
|
|
@Override
|
|
- public void exchange(int x, int y) {
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * There are two ways to achieve this Exchange. Keep in mind we actually have two lists:
|
|
|
|
- * We have the "keys" and the motionPaths Waypoints (controlPoints). In order to exchange, we have:
|
|
|
|
- *
|
|
|
|
- * Method A: Exchanging the Vector3f Reference in BOTH keys and motionPaths (this basically means reordering them, really!)
|
|
|
|
- * This is problematic, because MotionPath doesn't support accessing it's list.
|
|
|
|
- *
|
|
|
|
- * Method B: Exchanging the Vector3f's Values. This means The upper Node (Waypoint) will still be the upper, but it's contents just change
|
|
|
|
- * This is easy to achieve using Vector3f#set(). The downside is that that since the keys have not been altered, they aren't recreated.
|
|
|
|
- * We will just call the apropriate update Methods for the Visual Representations.
|
|
|
|
- * Note: I don't know yet what netbeans thinks of Method B. Probably we need ugly reflection and Method A.
|
|
|
|
- */
|
|
|
|
-
|
|
|
|
- /* Clone because the contents will be altered */
|
|
|
|
- Vector3f v_x = keys.get(x).clone();
|
|
|
|
- Vector3f v_y = keys.get(y).clone();
|
|
|
|
-
|
|
|
|
- // Exchange keys
|
|
|
|
- /* METHOD A:
|
|
|
|
- //keys.set(x, v_y);
|
|
|
|
- //keys.set(y, v_x);*/
|
|
|
|
-
|
|
|
|
- keys.get(x).set(v_y);
|
|
|
|
- keys.get(y).set(v_x);
|
|
|
|
|
|
+ public void moveUp(int i) {
|
|
|
|
+ super.moveUp(i);
|
|
|
|
|
|
- MotionPath m = jmeMotionPath.getMotionPath();
|
|
|
|
|
|
+ List<Vector3f> controlPoints = jmeMotionPath.getMotionPath().getSpline().getControlPoints();
|
|
|
|
|
|
- // Exchange Waypoints
|
|
|
|
- // This only works because waypoint y == keys.y (v_y). If this isn't true we messed up somewhere, really hard.
|
|
|
|
- // it would mean that the saved Motion Path derives from the shown...
|
|
|
|
|
|
+ if (i < 1 || i > controlPoints.size())
|
|
|
|
+ throw new IndexOutOfBoundsException();
|
|
|
|
|
|
- m.getWayPoint(x).set(v_y);
|
|
|
|
- m.getWayPoint(y).set(v_x);
|
|
|
|
|
|
+ Vector3f element = controlPoints.get(i);
|
|
|
|
+ Vector3f over_element = controlPoints.get(i - 1);
|
|
|
|
|
|
|
|
+ controlPoints.set(i - 1, element);
|
|
|
|
+ controlPoints.set(i, over_element);
|
|
|
|
|
|
- /* Let the nodes know that their content has been changed */
|
|
|
|
- ((JmeVector3f)getNodeAt(x)).moveBox();
|
|
|
|
- ((JmeVector3f)getNodeAt(y)).moveBox();
|
|
|
|
- //jmeMotionPath.updateSpline(true);// MoveBox calls UpdateSpline
|
|
|
|
|
|
+ jmeMotionPath.getMotionPath().getSpline().setType(jmeMotionPath.getMotionPath().getSpline().getType()); // retrigger some internal computations
|
|
|
|
|
|
- // Netbeans API wants that.
|
|
|
|
- triggerChangeListeners();
|
|
|
|
- SceneExplorerTopComponent.findInstance().setSelectedNode((AbstractSceneExplorerNode)getNodeAt(y)); // Speak: "Replace X with Y"
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * Move an element up
|
|
|
|
- * @param i index of element to move up
|
|
|
|
- */
|
|
|
|
- @Override
|
|
|
|
- public void moveUp(int i) {
|
|
|
|
- if (i <= 0 || i >= keys.size()) // Can't move up
|
|
|
|
- throw new IndexOutOfBoundsException();
|
|
|
|
-
|
|
|
|
- exchange(i, i-1); // Clever Code reusing, huh? ;)
|
|
|
|
|
|
+ refreshChildren(true);
|
|
|
|
+ jmeMotionPath.updateSpline(true);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -274,25 +210,22 @@ public class JmeVector3fChildren extends Children.Keys<Vector3f> implements Inde
|
|
*/
|
|
*/
|
|
@Override
|
|
@Override
|
|
public void moveDown(int i) {
|
|
public void moveDown(int i) {
|
|
- if (i < 0 || i >= keys.size() - 1)
|
|
|
|
|
|
+ super.moveDown(i);
|
|
|
|
+ List<Vector3f> controlPoints = jmeMotionPath.getMotionPath().getSpline().getControlPoints();
|
|
|
|
+
|
|
|
|
+ if (i < 0 || i >= controlPoints.size())
|
|
throw new IndexOutOfBoundsException();
|
|
throw new IndexOutOfBoundsException();
|
|
|
|
|
|
- exchange(i, i+1); // moveUp(i+1); wouldn't respect the setSelectedNode
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void triggerChangeListeners() {
|
|
|
|
- for (ChangeListener cl : listeners) {
|
|
|
|
- cl.stateChanged(new ChangeEvent(this));
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- public void addChangeListener(ChangeListener cl) {
|
|
|
|
- listeners.add(cl);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- public void removeChangeListener(ChangeListener cl) {
|
|
|
|
- listeners.remove(cl);
|
|
|
|
|
|
+ Vector3f element = controlPoints.get(i);
|
|
|
|
+ Vector3f under_element = controlPoints.get(i + 1);
|
|
|
|
+
|
|
|
|
+ controlPoints.set(i + 1, element);
|
|
|
|
+ controlPoints.set(i, under_element);
|
|
|
|
+
|
|
|
|
+ jmeMotionPath.getMotionPath().getSpline().setType(jmeMotionPath.getMotionPath().getSpline().getType()); // retrigger some internal computations
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ refreshChildren(true);
|
|
|
|
+ jmeMotionPath.updateSpline(true);
|
|
}
|
|
}
|
|
}
|
|
}
|