Package org.jdesktop.wonderland.modules.appbase.client.view

Source Code of org.jdesktop.wonderland.modules.appbase.client.view.Gui2D$MouseListener

/**
* 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.appbase.client.view;

import com.jme.math.Vector2f;
import com.jme.math.Vector3f;
import com.jme.scene.Node;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.util.LinkedList;
import java.util.logging.Logger;
import org.jdesktop.mtgame.Entity;
import org.jdesktop.wonderland.client.input.Event;
import org.jdesktop.wonderland.client.input.EventClassListener;
import org.jdesktop.wonderland.client.jme.input.MouseButtonEvent3D;
import org.jdesktop.wonderland.client.jme.input.MouseDraggedEvent3D;
import org.jdesktop.wonderland.client.jme.input.MouseEnterExitEvent3D;
import org.jdesktop.wonderland.client.jme.input.MouseEvent3D;
import org.jdesktop.wonderland.common.InternalAPI;
import org.jdesktop.wonderland.modules.appbase.client.ControlArb;
import org.jdesktop.wonderland.modules.appbase.client.App2D;
import javax.swing.SwingUtilities;

/**
* Generic View2D event handler.
*
* @author deronj
*/
@InternalAPI
public class Gui2D {

    private static final Logger logger = Logger.getLogger(Gui2D.class.getName());

    /** The type of actions that user events can generate */
    public enum ActionType {

        TOGGLE_CONTROL,
        MOVE_CAMERA_TO_BEST_VIEW,
        MOVE_AVATAR_TO_BEST_VIEW,
        MOVE_WINDOW_TO_BEST_VIEW,
        CLOSE_BUTTON_ENTER,
        CLOSE_BUTTON_EXIT,
        CLOSE_BUTTON_PRESSED,
        DRAG_START,
        DRAG_UPDATE,
        DRAG_FINISH,
        TO_FRONT;
    };

    /** A basic action object */
    public static class Action {

        /** The type of the action */
        public ActionType type;

        /**
         * Create a new instance of Action.
         *
         * @param type The type of the action.
         */
        public Action(ActionType type) {
            this.type = type;
        }
    }

    /** The possible view configuration GUI states */
    protected enum ConfigState {

        /** No user interaction is underway */
        IDLE,
        /** The user has started a mouse drag */
        DRAG_ACTIVE,
        /** The user has actually dragged the mouse */
        DRAGGING
    };

    /** The possible view configuration drag types */
    protected enum ConfigDragType {

        /** The user is dragging the mouse to move the view within its current plane */
        MOVING_PLANAR,
        /** The user is dragging the mouse to move the view in the Z direction to its current plane */
        MOVING_Z,
        /** The user is dragging the mouse to rotate the view around its Y axis */
            // TODO        ROTATING_Y
    };
    /** The view configuration GUI state */
    protected ConfigState configState = ConfigState.IDLE;
    /** The view configuration drag type (only valid when configState != IDLE */
    protected ConfigDragType configDragType;
    /** The intersection point on the entity over which the button was pressed, in world coordinates. */
    protected Vector3f dragStartWorld;
    /** The intersection point in parent local coordinates. */
    protected Vector3f dragStartLocal;
    /** The screen coordinates of the button press event. */
    protected Point dragStartScreen;
    /** The amount that the cursor has been dragged in local coordinates. */
    protected Vector3f dragVectorLocal;

    /** A listener for 3D mouse events */
    protected EventClassListener mouseListener;

    /** This Gui's view */
    protected View2DEntity view;

    /** The entities to which this GUI's listeners are attached. */
    private LinkedList<Entity> attachedToEntities = new LinkedList<Entity>();

    /**
     * Create a new instance of Gui2D.
     *
     * @param view The view associated with the component that uses this Gui.
     */
    public Gui2D(View2DEntity view) {
        this.view = view;
    }

    /**
     * {@inheritDoc}
     */
    public synchronized void cleanup() {
        for (Entity entity : attachedToEntities) {
            detachMouseListener(entity);
            detachKeyListener(entity);
        }
        attachedToEntities.clear();

        mouseListener = null;
        view = null;
    }

    /**
     * Returns this GUI's view.
     */
    public View2DEntity getView () {
        return view;
    }

    /**
     * Attach this GUI controller's event listeners to the given entity.
     */
    public synchronized void attachEventListeners(Entity entity) {
        attachMouseListener(entity);
        attachKeyListener(entity);
        attachedToEntities.add(entity);
    }

    /**
     * Detach this GUI controller's event listeners from the entity to which it is attached.
     */
    public synchronized void detachEventListeners(Entity entity) {
        detachMouseListener(entity);
        detachKeyListener(entity);
        attachedToEntities.remove(entity);
    }

    /**
     * Start listening to mouse events from this entity.
     */
    protected void attachMouseListener(Entity entity) {
        mouseListener = new MouseListener();
        mouseListener.addToEntity(entity);
    }

    /**
     * Stop listening to mouse events from this entity.
     */
    protected void detachMouseListener(Entity entity) {
        if (mouseListener != null && entity != null) {
            mouseListener.removeFromEntity(entity);
        }
    }

    /**
     * Start listening to key events from this entity.
     */
    protected void attachKeyListener(Entity entity) {
    }

    /**
     * Stop listening to keyboard events from this entity.
     */
    protected void detachKeyListener(Entity entity) {
    }

    /** A basic listener for 3D mouse events */
    protected class MouseListener extends EventClassListener {

        /**
         * {@inheritDoc}
         */
        @Override
        public Class[] eventClassesToConsume() {
            return new Class[]{MouseEvent3D.class};
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void commitEvent(final Event event) {
            if (view != null) {
                SwingUtilities.invokeLater(new Runnable () {
                    public void run () {
                        if (view != null) {
                            view.deliverEvent(view.getWindow(), (MouseEvent3D) event);
                        }
                    }
                });
            }
        }
    }

    /**
     * Determine if this 3D mouse event provokes a miscellaneous action. That is, one of:
     * <br><br>
     *    + Move camera to best view
     * <br>
     *    + Move avatar to best view
     * <br>
     *    + Move window to best view
     * <br>
     *    + Change control
     *
     * @param me The AWT event for this 3D mouse event.
     * @param me3d The 3D mouse event.
     */
    protected Action determineIfMiscAction(MouseEvent me, MouseEvent3D me3d) {

        // Is this the Take Control or Release Control event?
        if (isChangeControlEvent(me)) {

            // Ignore any enter/exit events that LG generates for the click event
            if (me3d instanceof MouseEnterExitEvent3D) {
                return null;
            }

            return new Action(ActionType.TOGGLE_CONTROL);
        }

        return null;
    }

    /**
     * Is this the event which takes or releases control of an app group (which for this LAF is Shift-Left-click)?
     */
    public static boolean isChangeControlEvent(MouseEvent me) {
        // Note: this used to be MOUSE_CLICKED. But in order to fix 246 we need
        // FrameHeaderSwing.ConsumeOnControlListener to work and for this to work
        // I found that I needed the control changed event to be pressed, not clicked.
        // I don't know why. See the doc in FrameHeaderSwing.ConsumeOnControlListener.consumesEvent
        // for more info.
        return me.getID() == MouseEvent.MOUSE_PRESSED &&
                me.getButton() == MouseEvent.BUTTON1 &&
                (me.getModifiersEx() & MouseEvent.SHIFT_DOWN_MASK) != 0;
    }

    /**
     * Perform miscellaneous action. (Refer to determineIfMiscAction)
     *
     * @param action The miscellaneous action the given event provokes.
     * @param me The AWT event for this 3D mouse event.
     * @param me3d The 3D mouse event.
     */
    protected void performMiscAction(Action action, MouseEvent me, MouseEvent3D me3d) {
        //logger.severe("Gui misc action = " + action.type);

        switch (action.type) {

            case TOGGLE_CONTROL:
                ControlArb controlArb = view.getWindow().getApp().getControlArb();
                if (controlArb.hasControl()) {
                    logger.info("Release control");
                    controlArb.releaseControl();
                } else {
                    logger.info("Take control");
                    controlArb.takeControl();
                }
                break;
        }
    }

    /**
     * Determine if this is a window configuration action. That is, one of:
     * <br><br>
     *     + Planar move (move within the cell local z=0 plane).
     * <br>
     *     + Z move (move along the cell local z axis).
     * <br>
     *     + Y rotation.
     *
     * @param me The AWT event for this 3D mouse event.
     * @param me3d The 3D mouse event.
     */
    protected Action determineIfConfigAction(MouseEvent me, MouseEvent3D me3d) {
        Action action = null;

        switch (me.getID()) {

        case MouseEvent.MOUSE_PRESSED:
            MouseButtonEvent3D buttonEvent = (MouseButtonEvent3D) me3d;
            if (configState == ConfigState.IDLE &&
                me.getButton() == MouseEvent.BUTTON1 &&
                me.getModifiersEx() == MouseEvent.BUTTON1_DOWN_MASK) {

                // Remember: the move occurs in parent coords
                View2DEntity parentView = (View2DEntity) view.getParent();
                if (parentView == null) {
                    // Note: we don't yet support dragging of primaries
                    return null;
                }

                configState = ConfigState.DRAG_ACTIVE;
                action = new Action(ActionType.DRAG_START);
                dragStartScreen = new Point(me.getX(), me.getY());
                dragStartWorld = buttonEvent.getIntersectionPointWorld();
                configDragType = ConfigDragType.MOVING_PLANAR;

                dragStartLocal = parentView.getNode().worldToLocal(dragStartWorld, new Vector3f());
            }
            return action;

        case MouseEvent.MOUSE_DRAGGED:
            if (configState == ConfigState.DRAG_ACTIVE ||
                configState == ConfigState.DRAGGING) {
                action = new Action(ActionType.DRAG_UPDATE);
                configState = ConfigState.DRAGGING;

                MouseDraggedEvent3D dragEvent = (MouseDraggedEvent3D) me3d;
                Vector3f dragVectorWorld = dragEvent.getDragVectorWorld(dragStartWorld, dragStartScreen,
                                                                        new Vector3f());

                // Convert from world to parent coordinates.
                Node viewNode = ((View2DEntity)view.getParent()).getNode();
                Vector3f curWorld = dragStartWorld.add(dragVectorWorld, new Vector3f());
                Vector3f curLocal = viewNode.worldToLocal(curWorld, new Vector3f());
                dragVectorLocal = curLocal.subtract(dragStartLocal);
            }
            return action;

        case MouseEvent.MOUSE_RELEASED:
            if (me.getButton() == MouseEvent.BUTTON1) {
                if (configState == ConfigState.DRAGGING) {
                    // Note: the misc action ToggleControl may produce an mouse
                    // press/release without a drag in between so only perform
                    // a dragfinish if an actual drag occurred between the
                    // mouse press and release
                    action = new Action(ActionType.DRAG_FINISH);

                } else if (configDragType == ConfigDragType.MOVING_PLANAR &&
                           me.getModifiersEx() == 0) {

                    // Note: A bit of uncleanliness: Even though we haven't been
                    // actually dragging we still need to restore the cursor to
                    // its original form.
                    view.userMovePlanarFinish();
                }

                configState = ConfigState.IDLE;
                // Note: the coordinates for WL mouse release events are invalid.
                // So we just use the coordinates from the last drag or press.
            }
            return action;
        }

        return null;
    }

    /**
     * Perform a view configuration action. That is, one of:
     * <br><br>
     *     + Planar move (move within the cell local z=0 plane).
     * <br>
     *     + Z move (move along the cell local z axis).
     * <br>
     *     + Y rotation.
     *
     * @param action The configuration action the given event provokes.
     * @param me The AWT event for this 3D mouse event.
     * @param me3d The 3D mouse event.
     */
    protected void performConfigAction(Action action, MouseEvent me, MouseEvent3D me3d) {

        switch (action.type) {

        case DRAG_START:
            switch (configDragType) {
            case MOVING_PLANAR:
                App2D.invokeLater(new Runnable() {
                    public void run () {
                        view.userMovePlanarStart();
                    }
                });
                break;
            }
            break;

        case DRAG_UPDATE:
            switch (configDragType) {
            case MOVING_PLANAR:
                App2D.invokeLater(new Runnable() {
                    public void run () {
                        view.userMovePlanarUpdate(new Vector2f(dragVectorLocal.x, dragVectorLocal.y));
                    }
                });
                break;
            }
            break;

        case DRAG_FINISH:
            switch (configDragType) {
            case MOVING_PLANAR:
                App2D.invokeLater(new Runnable() {
                    public void run () {
                        view.userMovePlanarFinish();
                    }
                });
                break;
            }
            break;

        default:
            throw new RuntimeException("Unrecognized action");
        }
    }

    /**
     * Determine if this is an action which moves the window to the front of the stack.
     *
     * @param me The AWT event corresponding to a 3D mouse event which has been received.
     */
    protected Action determineIfToFrontAction(MouseEvent me) {
        if (me.getID() == MouseEvent.MOUSE_CLICKED &&
                me.getButton() == MouseEvent.BUTTON1 &&
                me.getModifiersEx() == 0) {
            return new Action(ActionType.TO_FRONT);
        } else {
            return null;
        }
    }
}
TOP

Related Classes of org.jdesktop.wonderland.modules.appbase.client.view.Gui2D$MouseListener

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.