Package com.ardor3d.input.jogl

Source Code of com.ardor3d.input.jogl.JoglNewtMouseWrapper

/**
* Copyright (c) 2008-2012 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
* Ardor3D is free software: you can redistribute it and/or modify it
* under the terms of its license which may be found in the accompanying
* LICENSE file or at <http://www.ardor3d.com/LICENSE>.
*/

package com.ardor3d.input.jogl;

import static com.google.common.base.Preconditions.checkNotNull;

import java.util.EnumMap;
import java.util.EnumSet;
import java.util.LinkedList;

import com.ardor3d.annotation.GuardedBy;
import com.ardor3d.framework.jogl.NewtWindowContainer;
import com.ardor3d.input.ButtonState;
import com.ardor3d.input.GrabbedState;
import com.ardor3d.input.MouseButton;
import com.ardor3d.input.MouseManager;
import com.ardor3d.input.MouseState;
import com.ardor3d.input.MouseWrapper;
import com.google.common.collect.AbstractIterator;
import com.google.common.collect.EnumMultiset;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multiset;
import com.google.common.collect.PeekingIterator;
import com.jogamp.newt.event.MouseEvent;
import com.jogamp.newt.event.MouseListener;
import com.jogamp.newt.event.NEWTEvent;
import com.jogamp.newt.opengl.GLWindow;

public class JoglNewtMouseWrapper implements MouseWrapper, MouseListener {

    @GuardedBy("this")
    protected final LinkedList<MouseState> _upcomingEvents = Lists.newLinkedList();

    @GuardedBy("this")
    protected JoglNewtMouseIterator _currentIterator = null;

    @GuardedBy("this")
    protected MouseState _lastState = null;

    protected final GLWindow _newtWindow;

    protected final MouseManager _manager;

    protected boolean _consumeEvents = false;

    protected final Multiset<MouseButton> _clicks = EnumMultiset.create(MouseButton.class);
    protected final EnumMap<MouseButton, Long> _lastClickTime = Maps.newEnumMap(MouseButton.class);
    protected final EnumSet<MouseButton> _clickArmed = EnumSet.noneOf(MouseButton.class);

    protected int _ignoreX = Integer.MAX_VALUE;
    protected int _ignoreY = Integer.MAX_VALUE;

    public JoglNewtMouseWrapper(final NewtWindowContainer newtWindowContainer, final MouseManager manager) {
        _newtWindow = checkNotNull(newtWindowContainer.getNewtWindow(), "newtWindow");
        _manager = manager;
        for (final MouseButton mb : MouseButton.values()) {
            _lastClickTime.put(mb, 0L);
        }
    }

    @Override
    public void init() {
        _newtWindow.addMouseListener(this);
    }

    @Override
    public synchronized PeekingIterator<MouseState> getEvents() {
        expireClickEvents();

        if (_currentIterator == null || !_currentIterator.hasNext()) {
            _currentIterator = new JoglNewtMouseIterator();
        }

        return _currentIterator;
    }

    private void expireClickEvents() {
        if (!_clicks.isEmpty()) {
            for (final MouseButton mb : MouseButton.values()) {
                if (System.currentTimeMillis() - _lastClickTime.get(mb) > MouseState.CLICK_TIME_MS) {
                    _clicks.setCount(mb, 0);
                }
            }
        }
    }

    @Override
    public synchronized void mousePressed(final MouseEvent me) {
        final MouseButton b = getButtonForEvent(me);
        if (_clickArmed.contains(b)) {
            _clicks.setCount(b, 0);
        }
        _clickArmed.add(b);
        _lastClickTime.put(b, System.currentTimeMillis());

        initState(me);
        if (_consumeEvents) {
            me.setAttachment(NEWTEvent.consumedTag);
        }

        final EnumMap<MouseButton, ButtonState> buttons = _lastState.getButtonStates();

        setStateForButton(me, buttons, ButtonState.DOWN);

        addNewState(me, buttons, null);
    }

    @Override
    public synchronized void mouseReleased(final MouseEvent me) {
        initState(me);
        if (_consumeEvents) {
            me.setAttachment(NEWTEvent.consumedTag);
        }

        final EnumMap<MouseButton, ButtonState> buttons = _lastState.getButtonStates();

        setStateForButton(me, buttons, ButtonState.UP);

        final MouseButton b = getButtonForEvent(me);
        if (_clickArmed.contains(b) && (System.currentTimeMillis() - _lastClickTime.get(b) <= MouseState.CLICK_TIME_MS)) {
            _clicks.add(b); // increment count of clicks for button b.
            // XXX: Note the double event add... this prevents sticky click counts, but is it the best way?
            addNewState(me, buttons, EnumMultiset.create(_clicks));
        } else {
            _clicks.setCount(b, 0); // clear click count for button b.
        }
        _clickArmed.remove(b);

        addNewState(me, buttons, null);
    }

    @Override
    public synchronized void mouseDragged(final MouseEvent me) {
        mouseMoved(me);
    }

    @Override
    public synchronized void mouseMoved(final MouseEvent me) {
        _clickArmed.clear();
        _clicks.clear();

        // check that we have a valid _lastState
        initState(me);
        if (_consumeEvents) {
            me.setAttachment(NEWTEvent.consumedTag);
        }

        // remember our current ardor3d position
        final int oldX = _lastState.getX(), oldY = _lastState.getY();

        // check the state against the "ignore next" values
        if (_ignoreX != Integer.MAX_VALUE // shortcut to prevent dx/dy calculations
                && (_ignoreX == getDX(me) && _ignoreY == getDY(me))) {

            // we matched, so we'll consider this a "mouse pointer reset move"
            // so reset ignore to let the next move event through.
            _ignoreX = Integer.MAX_VALUE;
            _ignoreY = Integer.MAX_VALUE;

            // exit without adding an event to our queue
            return;
        }

        // save our old "last state."
        final MouseState _savedState = _lastState;

        // Add our latest state info to the queue
        addNewState(me, _lastState.getButtonStates(), null);

        // If we have a valid move... should always be the case, but occasionally something slips through.
        if (_lastState.getDx() != 0 || _lastState.getDy() != 0) {

            // Ask our manager if we're currently "captured"
            if (_manager.getGrabbed() == GrabbedState.GRABBED) {

                // if so, set "ignore next" to the inverse of this move
                _ignoreX = -_lastState.getDx();
                _ignoreY = -_lastState.getDy();

                // Move us back to our last position.
                _manager.setPosition(oldX, oldY);

                // And finally, revert our _lastState.
                _lastState = _savedState;
            } else {
                // otherwise, set us to not ignore anything. This may be unnecessary, but prevents any possible
                // "ignore" bleeding.
                _ignoreX = Integer.MAX_VALUE;
                _ignoreY = Integer.MAX_VALUE;
            }
        }
    }

    @Override
    public void mouseWheelMoved(final MouseEvent me) {
        initState(me);

        addNewState(me, _lastState.getButtonStates(), null);
        if (_consumeEvents) {
            me.setAttachment(NEWTEvent.consumedTag);
        }
    }

    private void initState(final MouseEvent mouseEvent) {
        if (_lastState == null) {
            _lastState = new MouseState(mouseEvent.getX(), getArdor3DY(mouseEvent), 0, 0, 0, null, null);
        }
    }

    private void addNewState(final MouseEvent mouseEvent, final EnumMap<MouseButton, ButtonState> enumMap,
            final Multiset<MouseButton> clicks) {
        final MouseState newState = new MouseState(mouseEvent.getX(), getArdor3DY(mouseEvent), getDX(mouseEvent),
                getDY(mouseEvent), (int) (mouseEvent.isShiftDown() ? mouseEvent.getRotation()[0]
                        : mouseEvent.getRotation()[1]), enumMap, clicks);

        synchronized (JoglNewtMouseWrapper.this) {
            _upcomingEvents.add(newState);
        }
        _lastState = newState;
    }

    private int getDX(final MouseEvent me) {
        return me.getX() - _lastState.getX();
    }

    private int getDY(final MouseEvent me) {
        return getArdor3DY(me) - _lastState.getY();
    }

    /**
     * @param e
     *            our mouseEvent
     * @return the Y coordinate of the event, flipped relative to the component since we expect an origin in the lower
     *         left corner.
     */
    private int getArdor3DY(final MouseEvent me) {
        return _newtWindow.getHeight() - me.getY();
    }

    private void setStateForButton(final MouseEvent e, final EnumMap<MouseButton, ButtonState> buttons,
            final ButtonState buttonState) {
        final MouseButton button = getButtonForEvent(e);
        buttons.put(button, buttonState);
    }

    private MouseButton getButtonForEvent(final MouseEvent me) {
        MouseButton button;
        switch (me.getButton()) {
            case MouseEvent.BUTTON1:
                button = MouseButton.LEFT;
                break;
            case MouseEvent.BUTTON2:
                button = MouseButton.MIDDLE;
                break;
            case MouseEvent.BUTTON3:
                button = MouseButton.RIGHT;
                break;
            case MouseEvent.BUTTON4:
                button = MouseButton.FOUR;
                break;
            case MouseEvent.BUTTON5:
                button = MouseButton.FIVE;
                break;
            case MouseEvent.BUTTON6:
                button = MouseButton.SIX;
                break;
            case MouseEvent.BUTTON7:
                button = MouseButton.SEVEN;
                break;
            case MouseEvent.BUTTON8:
                button = MouseButton.EIGHT;
                break;
            case MouseEvent.BUTTON9:
                button = MouseButton.NINE;
                break;
            default:
                throw new RuntimeException("unknown button: " + me.getButton());
        }
        return button;
    }

    private class JoglNewtMouseIterator extends AbstractIterator<MouseState> implements PeekingIterator<MouseState> {

        @Override
        protected MouseState computeNext() {
            synchronized (JoglNewtMouseWrapper.this) {
                if (_upcomingEvents.isEmpty()) {
                    return endOfData();
                }
                return _upcomingEvents.poll();
            }
        }
    }

    @Override
    public synchronized void mouseClicked(final MouseEvent me) {
        // Yes, we could use the click count here, but in the interests of this working the same way as SWT and Native,
        // we
        // will do it the same way they do it.

    }

    @Override
    public synchronized void mouseEntered(final MouseEvent me) {
        // ignore this
    }

    @Override
    public synchronized void mouseExited(final MouseEvent me) {
        // ignore this
    }

    public boolean isConsumeEvents() {
        return _consumeEvents;
    }

    public void setConsumeEvents(final boolean consumeEvents) {
        _consumeEvents = consumeEvents;
    }
}
TOP

Related Classes of com.ardor3d.input.jogl.JoglNewtMouseWrapper

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.