Better JmeDragAndDrop example (with gamestates)

Enjoy  8)



See the javadoc for details, it wont compile as is because JMEDropTargetEvent does not extend EventObject, but you can easily patch JMEDropTargetEvent  or comment 2 lines of my code to see how it works without the patch.





package jmetest.awt.swingui.dnd;

import java.awt.Color;
import java.awt.GridLayout;
import java.awt.dnd.DnDConstants;

import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;

import com.jme.bounding.BoundingSphere;
import com.jme.input.KeyboardLookHandler;
import com.jme.input.MouseInput;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.scene.shape.Box;
import com.jme.system.DisplaySystem;
import com.jmex.awt.swingui.JMEDesktopState;
import com.jmex.awt.swingui.dnd.JMEDndException;
import com.jmex.awt.swingui.dnd.JMEDragAndDrop;
import com.jmex.awt.swingui.dnd.JMEDragGestureEvent;
import com.jmex.awt.swingui.dnd.JMEDragGestureListener;
import com.jmex.awt.swingui.dnd.JMEDragSourceEvent;
import com.jmex.awt.swingui.dnd.JMEDragSourceListener;
import com.jmex.awt.swingui.dnd.JMEDropTargetEvent;
import com.jmex.awt.swingui.dnd.JMEDropTargetListener;
import com.jmex.awt.swingui.dnd.JMEMouseDragGestureRecognizer;
import com.jmex.game.StandardGame;
import com.jmex.game.state.DebugGameState;
import com.jmex.game.state.GameStateManager;

/**
 * clean and simple drag and drop test with gamestates
 *
 * for making method DndIcon.drop(JMEDropTargetEvent e) work as intended, you have to patch the class
 * JMEDropTargetEvent to make it extend java.util.EventObject ,
 *
 * then add the Source Object in the constructor  like this :
 *
 * JMEDropTargetEvent(Object source, Point point, int action, JMEDragAndDrop dnd ) {
        super(source);
        ...
   
 *  and then update JME classes that instantiate JMEDropTargetEvent
 *
 * if you want to test without the swapping with source icon, comment this code in DndIcon.drop(JMEDropTargetEvent e)
 *  //DndIcon source = (DndIcon) e.getSource();
   //source.setIcon(this.getIcon());
 *
 * @author Nomis
 *
 */
public class TestDnd {

   public static void main(String[] args) {
      TestDnd test = new TestDnd();
      StandardGame game = new StandardGame("DND test");
      game.start();

      TestDnd.MyGameState ingameState = test.new MyGameState();
      GameStateManager.getInstance().attachChild(ingameState);

      // always updateRenderState or get funky effects
      ingameState.getRootNode().updateRenderState();
      // By the way I strongly advise you to comment it to see the funky
      // effects it's really fun !
      ingameState.setActive(true);

      TestDnd.MyHudState hudState = test.new MyHudState();
      hudState.setActive(true);
      hudState.getRootNode().updateRenderState();
      GameStateManager.getInstance().attachChild(hudState);

   }

   public class MyGameState extends DebugGameState {
      private Box box;
      private Quaternion rotQuat = new Quaternion();
      private float angle = 0;

      private Vector3f axis = new Vector3f(1, 1, 0.5f);

      public MyGameState() {
         // keyboard look handler because the mouse is used for the hud
         super(false);
         input = new KeyboardLookHandler(DisplaySystem.getDisplaySystem().getRenderer().getCamera(), 15.0f, 0.5f);

         this.box = new Box("my box", new Vector3f(0, 0, 0), 2, 2, 2);
         box.setModelBound(new BoundingSphere());
         box.updateModelBound();
         this.getRootNode().attachChild(box);

         this.axis.normalizeLocal();
      }

      @Override
      public void update(float tpf) {

         super.update(tpf);
         // rotating the box to show there is some 3d behind the UI
         if (tpf < 1) {
            angle = angle + (tpf * 25);
            if (angle > 360) {
               angle = 0;
            }
         }
         rotQuat.fromAngleNormalAxis(angle * FastMath.DEG_TO_RAD, axis);
         box.setLocalRotation(rotQuat);
      }
   }

   public class MyHudState extends JMEDesktopState {

      public MyHudState() {
         super();
      }

      protected void buildUI() {

         new JMEDragAndDrop(this.getDesktop());

         JInternalFrame frame = new JInternalFrame("test", true, true);
         frame.setLayout(new GridLayout(4, 4));

         Icon icon1 = getResizedIcon("Monkey.jpg");
         frame.add(new DndIcon(this, icon1));
         Icon icon2 = getResizedIcon("Monkey.png");
         frame.add(new DndIcon(this, icon2));
         Icon icon3 = getResizedIcon("logo.jpg");
         frame.add(new DndIcon(this, icon3));

         // few empty icons to let you play
         for (int i = 0; i < 13; i++) {
            frame.add(new DndIcon(this, null));
         }
         frame.setSize(64 * 4, 64 * 4);
         frame.setLocation(100, 100);
         frame.setVisible(true);
         this.getDesktop().getJDesktop().add(frame);
         MouseInput.get().setCursorVisible(true);
      }

      private Icon getResizedIcon(String fileName) {
         ImageIcon icon = new ImageIcon(this.getClass().getResource("/jmetest/data/images/" + fileName));
         icon.setImage(icon.getImage().getScaledInstance(64, 64, 16));
         return icon;
      }
   }

   /**
    * DndIcon is the drag source and the drop target, so you can easily drag /
    * swap icons from different panels
    *
    * @author Nomis
    *
    */
   public class DndIcon extends JLabel implements JMEDragGestureListener, JMEDragSourceListener, JMEDropTargetListener {

      private static final long serialVersionUID = 1L;

      private JMEDragAndDrop dndSupport;

      public DndIcon(JMEDesktopState desktopSate, Icon icon) {
         this.setIcon(icon);
         this.dndSupport = desktopSate.getDesktop().getDragAndDropSupport();
         new JMEMouseDragGestureRecognizer(dndSupport, this, DnDConstants.ACTION_COPY_OR_MOVE, this);
         this.setBorder(BorderFactory.createLineBorder(Color.black));
      }

      // drop = swap this icon with event's source component icon

      public void drop(JMEDropTargetEvent e) {

         TransferableImage t = (TransferableImage) e.getTransferable();

         Icon icon = t.getIcon();

         if (icon != null) {
            // Set current icon to the source
            DndIcon source = (DndIcon) e.getSource();
            source.setIcon(this.getIcon());
            this.setIcon(icon);
         }

      }

      public void dragGestureRecognized(JMEDragGestureEvent dge) {

         if (this.getIcon() == null) {
            // nothing to transfer
            return;
         }

         TransferableImage transferable = new TransferableImage(this.getIcon());

         try {
            dndSupport.startDrag(dge, (ImageIcon) this.getIcon(), transferable, this);
         } catch (JMEDndException e) {
            e.printStackTrace();
         }

      }

      // we don't care for all other events

      public void dragDropEnd(JMEDragSourceEvent e) {
      }

      public void dragEnter(JMEDragSourceEvent e) {
      }

      public void dragExit(JMEDragSourceEvent e) {
      }

      public void dragEnter(JMEDropTargetEvent e) {
      }

      public void dragExit(JMEDropTargetEvent e) {
      }

      public void dragOver(JMEDropTargetEvent e) {
      }

   }

}

I just added an enhancement request to the bug tracker to make JMEDropTargetEvent extend java.util.EventObject

https://jme.dev.java.net/issues/show_bug.cgi?id=277



we can discuss it here if you want.



I forgot to mention : I did add this to transferableImage, really simplifies the code :



public Icon getIcon() {

return icon;

}

Sounds reasonable to me.