Package org.jdesktop.wonderland.modules.affordances.client

Source Code of org.jdesktop.wonderland.modules.affordances.client.PositionHUDPanel

/**
* Project Wonderland
*
* Copyright (c) 2004-2009, Sun Microsystems, Inc., All Rights Reserved
*
* Redistributions in source code form must reproduce the above
* copyright and this condition.
*
* The contents of this file are subject to the GNU General Public
* License, Version 2 (the "License"); you may not use this file
* except in compliance with the License. A copy of the License is
* available at http://www.opensource.org/licenses/gpl-license.php.
*
* Sun designates this particular file as subject to the "Classpath"
* exception as provided by Sun in the License file that accompanied
* this code.
*/
package org.jdesktop.wonderland.modules.affordances.client;

import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.util.List;
import javax.swing.JFormattedTextField;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.jdesktop.mtgame.Entity;
import org.jdesktop.wonderland.client.cell.Cell;
import org.jdesktop.wonderland.client.cell.CellComponent;
import org.jdesktop.wonderland.client.cell.ComponentChangeListener;
import org.jdesktop.wonderland.client.cell.MovableComponent;
import org.jdesktop.wonderland.client.cell.TransformChangeListener;
import org.jdesktop.wonderland.client.scenemanager.SceneManager;
import org.jdesktop.wonderland.common.cell.CellTransform;

/**
* A panel to display affordance items on the HUD.
*
* @author Jordan Slott <jslott@dev.java.net>
* @author Ronny Standtke <ronny.standtke@fhnw.ch>
*/
public class PositionHUDPanel extends javax.swing.JPanel {

    /* The currently selected Cell and its movable component */
    private Cell selectedCell;
    private MovableComponent movableComponent;

    /* Various listener on the Cell and Swing JSpinners */
    private ComponentChangeListener componentListener;
    private TransformChangeListener transformListener;
    private ChangeListener translationListener;
    private ChangeListener rotationListener;
    private ChangeListener scaleListener;

    /* Models for the Swing JSpinners */
    private SpinnerNumberModel xTranslationModel;
    private SpinnerNumberModel yTranslationModel;
    private SpinnerNumberModel zTranslationModel;
    private SpinnerNumberModel xScaleModel;
    private SpinnerNumberModel yScaleModel;
    private SpinnerNumberModel zScaleModel;
    private SpinnerNumberModel xRotationModel;
    private SpinnerNumberModel yRotationModel;
    private SpinnerNumberModel zRotationModel;

    /*
     * This boolean indicates whether the values of the spinners are being
     * set programmatically, e.g. when a transform changed event has been
     * received from the Cell. In such a case, we do not want to generate a
     * new message to the movable component
     */
    private boolean setLocal = false;

    /** Creates new form AffordanceHUDPanel */
    public PositionHUDPanel() {
        initComponents();

        // Set the maximum and minimum values for each
        Float value = new Float(0);
        Float min = new Float(Float.NEGATIVE_INFINITY);
        Float max = new Float(Float.POSITIVE_INFINITY);
        Float step = new Float(0.1);
        xTranslationModel = new SpinnerNumberModel(value, min, max, step);
        yTranslationModel = new SpinnerNumberModel(value, min, max, step);
        zTranslationModel = new SpinnerNumberModel(value, min, max, step);
        translationXTF.setModel(xTranslationModel);
        translationYTF.setModel(yTranslationModel);
        translationZTF.setModel(zTranslationModel);

        value = new Float(1);
        min = new Float(0);
        xScaleModel = new SpinnerNumberModel(value, min, max, step);
        yScaleModel = new SpinnerNumberModel(value, min, max, step);
        zScaleModel = new SpinnerNumberModel(value, min, max, step);
        scaleTF.setModel(xScaleModel);

        value = new Float(0);
        min = new Float(-360);
        max = new Float(360);
        step = new Float(1);
        xRotationModel = new SpinnerNumberModel(value, min, max, step);
        yRotationModel = new SpinnerNumberModel(value, min, max, step);
        zRotationModel = new SpinnerNumberModel(value, min, max, step);
        rotationXTF.setModel(xRotationModel);
        rotationYTF.setModel(yRotationModel);
        rotationZTF.setModel(zRotationModel);

        // Listen for changes, if there is a movable component added or removed
        // update the state of the fields
        componentListener = new ComponentChangeListener() {

            public void componentChanged(
                    Cell cell, ChangeType type, CellComponent component) {
                if ((type == ChangeType.ADDED) &&
                        component instanceof MovableComponent) {
                    movableComponent = (MovableComponent) component;

                    // We must enable the GUI components in the AWT Event
                    // Thread.
                    SwingUtilities.invokeLater(new Runnable() {

                        public void run() {
                            setGUIEnabled(true);
                        }
                    });
                }
            }
        };

        // Listen for changes to the cell transform that may be done by other
        // parts of this client or other clients.
        transformListener = new TransformChangeListener() {

            public void transformChanged(Cell cell, ChangeSource source) {
                // We must call this in the AWT Event Thread
                SwingUtilities.invokeLater(new Runnable() {

                    public void run() {
                        updateGUI();
                    }
                });
            }
        };

        // Listen for changes to the translation values and update the cell as
        // a result. Only update the result if it doesn't happen because the
        // value in the spinner is changed programmatically. The value of
        // 'setLocal' is set always in the AWT Event Thread, the same thread
        // as this listener.
        translationListener = new ChangeListener() {

            public void stateChanged(ChangeEvent e) {
                if (setLocal == false) {
                    updateTranslation();
                }
            }
        };
        xTranslationModel.addChangeListener(translationListener);
        yTranslationModel.addChangeListener(translationListener);
        zTranslationModel.addChangeListener(translationListener);

        // Listen for changes to the rotation values and update the cell as a
        // result. See the comments above for 'translationListener' too.
        rotationListener = new ChangeListener() {

            public void stateChanged(ChangeEvent e) {
                if (setLocal == false) {
                    updateRotation();
                }
            }
        };
        xRotationModel.addChangeListener(rotationListener);
        yRotationModel.addChangeListener(rotationListener);
        zRotationModel.addChangeListener(rotationListener);

        // Listen for changes to the scale values and update the cell as a
        // result. See the comments above for 'translationListener' too.
        scaleListener = new ChangeListener() {

            public void stateChanged(ChangeEvent e) {
                if (setLocal == false) {
                    updateScale();
                }
            }
        };
        xScaleModel.addChangeListener(scaleListener);
        yScaleModel.addChangeListener(scaleListener);
        zScaleModel.addChangeListener(scaleListener);

        // Listen for focus gained on the text field's of the spinners. Select
        // all of the text
        FocusListener focusListener = new FocusAdapter() {

            @Override
            public void focusGained(final FocusEvent e) {
                SwingUtilities.invokeLater(new Runnable() {

                    public void run() {
                        ((JFormattedTextField) e.getSource()).selectAll();
                    }
                });
            }
        };
        ((JSpinner.DefaultEditor) translationXTF.getEditor()).getTextField().
                addFocusListener(focusListener);
        ((JSpinner.DefaultEditor) translationYTF.getEditor()).getTextField().
                addFocusListener(focusListener);
        ((JSpinner.DefaultEditor) translationZTF.getEditor()).getTextField().
                addFocusListener(focusListener);
        ((JSpinner.DefaultEditor) rotationXTF.getEditor()).getTextField().
                addFocusListener(focusListener);
        ((JSpinner.DefaultEditor) rotationYTF.getEditor()).getTextField().
                addFocusListener(focusListener);
        ((JSpinner.DefaultEditor) rotationZTF.getEditor()).getTextField().
                addFocusListener(focusListener);
        ((JSpinner.DefaultEditor) scaleTF.getEditor()).getTextField().
                addFocusListener(focusListener);

        // Turn off the GUI initially, until we have a selected cell
        clearGUI();
        setGUIEnabled(false);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        translationPanel = new javax.swing.JPanel();
        jLabel4 = new javax.swing.JLabel();
        xTranslationPanel = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        translationXTF = new javax.swing.JSpinner();
        yTranslationPanel = new javax.swing.JPanel();
        jLabel2 = new javax.swing.JLabel();
        translationYTF = new javax.swing.JSpinner();
        zTranslationPanel = new javax.swing.JPanel();
        jLabel3 = new javax.swing.JLabel();
        translationZTF = new javax.swing.JSpinner();
        rotationPanel = new javax.swing.JPanel();
        jLabel10 = new javax.swing.JLabel();
        xRotationPanel = new javax.swing.JPanel();
        jLabel11 = new javax.swing.JLabel();
        rotationXTF = new javax.swing.JSpinner();
        yRotationPanel = new javax.swing.JPanel();
        jLabel12 = new javax.swing.JLabel();
        rotationYTF = new javax.swing.JSpinner();
        zRotationPanel = new javax.swing.JPanel();
        jLabel13 = new javax.swing.JLabel();
        rotationZTF = new javax.swing.JSpinner();
        resizePanel = new javax.swing.JPanel();
        jLabel14 = new javax.swing.JLabel();
        resizeSubPanel = new javax.swing.JPanel();
        scaleTF = new javax.swing.JSpinner();

        setBorder(javax.swing.BorderFactory.createEmptyBorder(3, 3, 3, 3));
        setLayout(new java.awt.GridBagLayout());

        translationPanel.setLayout(new java.awt.GridLayout(4, 1));

        java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("org/jdesktop/wonderland/modules/affordances/client/resources/Bundle"); // NOI18N
        jLabel4.setText(bundle.getString("PositionHUDPanel.jLabel4.text")); // NOI18N
        translationPanel.add(jLabel4);

        xTranslationPanel.setLayout(new javax.swing.BoxLayout(xTranslationPanel, javax.swing.BoxLayout.LINE_AXIS));

        jLabel1.setForeground(new java.awt.Color(255, 0, 0));
        jLabel1.setText(bundle.getString("PositionHUDPanel.jLabel1.text")); // NOI18N
        xTranslationPanel.add(jLabel1);

        translationXTF.setMinimumSize(new java.awt.Dimension(100, 30));
        translationXTF.setPreferredSize(new java.awt.Dimension(100, 30));
        xTranslationPanel.add(translationXTF);

        translationPanel.add(xTranslationPanel);

        yTranslationPanel.setLayout(new javax.swing.BoxLayout(yTranslationPanel, javax.swing.BoxLayout.LINE_AXIS));

        jLabel2.setForeground(new java.awt.Color(0, 255, 0));
        jLabel2.setText(bundle.getString("PositionHUDPanel.jLabel2.text")); // NOI18N
        yTranslationPanel.add(jLabel2);

        translationYTF.setMinimumSize(new java.awt.Dimension(100, 30));
        translationYTF.setPreferredSize(new java.awt.Dimension(100, 30));
        yTranslationPanel.add(translationYTF);

        translationPanel.add(yTranslationPanel);

        zTranslationPanel.setLayout(new javax.swing.BoxLayout(zTranslationPanel, javax.swing.BoxLayout.LINE_AXIS));

        jLabel3.setForeground(new java.awt.Color(0, 0, 255));
        jLabel3.setText(bundle.getString("PositionHUDPanel.jLabel3.text")); // NOI18N
        zTranslationPanel.add(jLabel3);

        translationZTF.setMinimumSize(new java.awt.Dimension(100, 30));
        translationZTF.setPreferredSize(new java.awt.Dimension(100, 30));
        zTranslationPanel.add(translationZTF);

        translationPanel.add(zTranslationPanel);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.gridheight = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        add(translationPanel, gridBagConstraints);

        rotationPanel.setLayout(new java.awt.GridLayout(4, 1));

        jLabel10.setText(bundle.getString("PositionHUDPanel.jLabel10.text")); // NOI18N
        rotationPanel.add(jLabel10);

        xRotationPanel.setLayout(new javax.swing.BoxLayout(xRotationPanel, javax.swing.BoxLayout.LINE_AXIS));

        jLabel11.setForeground(new java.awt.Color(255, 0, 0));
        jLabel11.setText(bundle.getString("PositionHUDPanel.jLabel11.text")); // NOI18N
        xRotationPanel.add(jLabel11);

        rotationXTF.setMinimumSize(new java.awt.Dimension(100, 30));
        rotationXTF.setPreferredSize(new java.awt.Dimension(100, 30));
        xRotationPanel.add(rotationXTF);

        rotationPanel.add(xRotationPanel);

        yRotationPanel.setLayout(new javax.swing.BoxLayout(yRotationPanel, javax.swing.BoxLayout.LINE_AXIS));

        jLabel12.setForeground(new java.awt.Color(0, 255, 0));
        jLabel12.setText(bundle.getString("PositionHUDPanel.jLabel12.text")); // NOI18N
        yRotationPanel.add(jLabel12);

        rotationYTF.setMinimumSize(new java.awt.Dimension(100, 30));
        rotationYTF.setPreferredSize(new java.awt.Dimension(100, 30));
        yRotationPanel.add(rotationYTF);

        rotationPanel.add(yRotationPanel);

        zRotationPanel.setLayout(new javax.swing.BoxLayout(zRotationPanel, javax.swing.BoxLayout.LINE_AXIS));

        jLabel13.setForeground(new java.awt.Color(0, 0, 255));
        jLabel13.setText(bundle.getString("PositionHUDPanel.jLabel13.text")); // NOI18N
        zRotationPanel.add(jLabel13);

        rotationZTF.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
        rotationZTF.setMinimumSize(new java.awt.Dimension(100, 30));
        rotationZTF.setPreferredSize(new java.awt.Dimension(100, 30));
        zRotationPanel.add(rotationZTF);

        rotationPanel.add(zRotationPanel);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.gridheight = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        add(rotationPanel, gridBagConstraints);

        resizePanel.setLayout(new java.awt.GridLayout(2, 0));

        jLabel14.setText(bundle.getString("PositionHUDPanel.jLabel14.text")); // NOI18N
        resizePanel.add(jLabel14);

        resizeSubPanel.setLayout(new java.awt.GridLayout(1, 0));

        scaleTF.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
        scaleTF.setMinimumSize(new java.awt.Dimension(100, 30));
        scaleTF.setPreferredSize(new java.awt.Dimension(100, 30));
        resizeSubPanel.add(scaleTF);

        resizePanel.add(resizeSubPanel);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 4;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.PAGE_START;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        add(resizePanel, gridBagConstraints);
    }// </editor-fold>//GEN-END:initComponents

    /**
     * Resets the values in the GUI back to 0.
     *
     * NOTE: This method assumes it is being called in the AWT Event Thread.
     */
    private void clearGUI() {
        // Says that we are changing the values of the spinners
        // programmatically. This prevents the values from being sent
        // back to the Cell via the movable component.
        setLocalChanges(true);

        try {
            translationXTF.setValue(0.0f);
            translationYTF.setValue(0.0f);
            translationZTF.setValue(0.0f);

            rotationXTF.setValue(0.0f);
            rotationYTF.setValue(0.0f);
            rotationZTF.setValue(0.0f);

            scaleTF.setValue(1.0f);
        } finally {
            setLocalChanges(false);
        }
    }

    /**
     * Updates the translation of the cell with the given values of the GUI.
     */
    private void updateTranslation() {
        float x = (Float) xTranslationModel.getValue();
        float y = (Float) yTranslationModel.getValue();
        float z = (Float) zTranslationModel.getValue();

        Vector3f translation = new Vector3f(x, y, z);
        if (movableComponent != null) {
            CellTransform cellTransform = selectedCell.getLocalTransform();
            cellTransform.setTranslation(translation);
            movableComponent.localMoveRequest(cellTransform);
        }
    }

    /**
     * Updates the rotation of the cell with the given values of the GUI.
     */
    private void updateRotation() {
        // Fetch the x, y, z rotation values from the GUI in degrees
        float x = (Float) xRotationModel.getValue();
        float y = (Float) yRotationModel.getValue();
        float z = (Float) zRotationModel.getValue();

        // Convert to radians
        x = (float) Math.toRadians(x);
        y = (float) Math.toRadians(y);
        z = (float) Math.toRadians(z);

        Quaternion newRotation = new Quaternion(new float[]{x, y, z});
        if (movableComponent != null) {
            CellTransform cellTransform = selectedCell.getLocalTransform();
            cellTransform.setRotation(newRotation);
            movableComponent.localMoveRequest(cellTransform);
        }
    }

    /**
     * Updates the scale of the cell with the given values of the GUI.
     */
    private void updateScale() {
        float x = (Float) xScaleModel.getValue();

        if (movableComponent != null) {
            CellTransform cellTransform = selectedCell.getLocalTransform();
            cellTransform.setScaling(x);
            movableComponent.localMoveRequest(cellTransform);
        }
    }

    /**
     * Updates the GUI items in this panel for the currently selected cell. If
     * there is nothing selected, do nothing.
     *
     * NOTE: This method assumes it is being called in the AWT Event Thread.
     */
    public void updateGUI() {
        // Fetch the currently selected Cell. If none, then do nothing
        setSelectedCell(getSelectedCell());
        if (selectedCell == null) {
            clearGUI();
            return;
        }

        // Fetch the current transform from the movable component
        CellTransform cellTransform = selectedCell.getLocalTransform();
        final Vector3f translation = cellTransform.getTranslation(null);
        Quaternion rotation = cellTransform.getRotation(null);
        final Vector3f scale = cellTransform.getScaling(null);
        final float[] angles = rotation.toAngles(new float[3]);

        // Says that we are changing the values of the spinners
        // programmatically. This prevents the values from being sent
        // back to the Cell via the movable component.
        setLocalChanges(true);

        try {
            // Do all actions to update the GUI in the AWT Event Thread.
            // Update the translation spinners
            translationXTF.setValue(translation.x);
            translationYTF.setValue(translation.y);
            translationZTF.setValue(translation.z);

            // Update the rotation spinners
            rotationXTF.setValue((float) Math.toDegrees(angles[0]));
            rotationYTF.setValue((float) Math.toDegrees(angles[1]));
            rotationZTF.setValue((float) Math.toDegrees(angles[2]));

            // Update the scale spinners only if they have changes
            scaleTF.setValue((float) scale.x);
        } finally {
            setLocalChanges(false);
        }
    }

    /**
     * Sets whether the GUI components are active (enabled).
     *
     * NOTE: This method assumes it is being called in the AWT Event Thread.
     *
     * @param enabled True to make the GUI components enabled, false to not
     */
    private void setGUIEnabled(boolean enabled) {
        translationXTF.setEnabled(enabled);
        translationYTF.setEnabled(enabled);
        translationZTF.setEnabled(enabled);
        rotationXTF.setEnabled(enabled);
        rotationYTF.setEnabled(enabled);
        rotationZTF.setEnabled(enabled);
        scaleTF.setEnabled(enabled);
    }

    /**
     * Sets whether the changes being made to the JSpinners are doing so
     * programmatically, rather than via a movable event. This is used to
     * make sure that requests to the movable component are not made at the
     * wrong time.
     *
     * @param isLocal True to indicate the JSpinner values are being set
     * programmatically.
     */
    private void setLocalChanges(boolean isLocal) {
        setLocal = isLocal;
    }

    /**
     * Handles when a new Cell is selected in the world. This removes the
     * listeners from the old Cell, adds the listeners to the new Cell and
     * updates the GUI.
     *
     * NOTE: This method assumes it is being called in the AWT Event Thread.
     */
    private void setSelectedCell(Cell cell) {
        // First remove the listeners from the old Cell if such a Cell exists.
        if (selectedCell != null) {
            selectedCell.removeComponentChangeListener(componentListener);
            selectedCell.removeTransformChangeListener(transformListener);
        }
        selectedCell = cell;

        // If the newly selected Cell is null, we turn off the GUI and return
        if (cell == null) {
            setGUIEnabled(false);
            return;
        }

        // Listen for changes in the transform of the Cell and update the
        // values of the spinners when that happens.
        cell.addTransformChangeListener(transformListener);

        // Listen for when the movable component is added, in case it has not
        // already been added. Set the movable component member variable.
        cell.addComponentChangeListener(componentListener);

        // Fetch the movable component. For now, if it does not exist, then
        // turn off everything
        movableComponent = cell.getComponent(MovableComponent.class);
        if (movableComponent == null) {
            setGUIEnabled(false);
        } else {
            setGUIEnabled(true);
        }
    }

    /**
     * Returns the currently selected cell, null if no cell is currently
     * selected.
     */
    private Cell getSelectedCell() {
        SceneManager manager = SceneManager.getSceneManager();
        List<Entity> entityList = manager.getSelectedEntities();
        if (entityList != null && entityList.size() > 0) {
            return SceneManager.getCellForEntity(entityList.get(0));
        }
        return null;
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel10;
    private javax.swing.JLabel jLabel11;
    private javax.swing.JLabel jLabel12;
    private javax.swing.JLabel jLabel13;
    private javax.swing.JLabel jLabel14;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JPanel resizePanel;
    private javax.swing.JPanel resizeSubPanel;
    private javax.swing.JPanel rotationPanel;
    private javax.swing.JSpinner rotationXTF;
    private javax.swing.JSpinner rotationYTF;
    private javax.swing.JSpinner rotationZTF;
    private javax.swing.JSpinner scaleTF;
    private javax.swing.JPanel translationPanel;
    private javax.swing.JSpinner translationXTF;
    private javax.swing.JSpinner translationYTF;
    private javax.swing.JSpinner translationZTF;
    private javax.swing.JPanel xRotationPanel;
    private javax.swing.JPanel xTranslationPanel;
    private javax.swing.JPanel yRotationPanel;
    private javax.swing.JPanel yTranslationPanel;
    private javax.swing.JPanel zRotationPanel;
    private javax.swing.JPanel zTranslationPanel;
    // End of variables declaration//GEN-END:variables
}
TOP

Related Classes of org.jdesktop.wonderland.modules.affordances.client.PositionHUDPanel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.