Package com.agifans.picedit.gui.handler

Source Code of com.agifans.picedit.gui.handler.MouseHandler

package com.agifans.picedit.gui.handler;

import java.awt.AWTEvent;
import java.awt.Cursor;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.image.BufferedImage;

import com.agifans.picedit.PicEdit;
import com.agifans.picedit.gui.frame.PictureFrame;
import com.agifans.picedit.gui.frame.PicturePanel;
import com.agifans.picedit.gui.toolbar.ColourChooserDialog;
import com.agifans.picedit.picture.EditStatus;
import com.agifans.picedit.picture.Picture;
import com.agifans.picedit.picture.PictureCodeType;
import com.agifans.picedit.types.BrushTexture;
import com.agifans.picedit.types.PictureType;
import com.agifans.picedit.types.StepType;
import com.agifans.picedit.types.ToolType;

/**
* Handles processing of mouse click and mouse move events for a PictureFrame.
*
* @author Lance Ewing
*/
public class MouseHandler implements MouseMotionListener, MouseListener, MouseWheelListener {

    /**
     * The PICEDIT application component.
     */
    protected PicEdit application;
   
    /**
     * Holds the difference between mouse motion event X positions and absolute mouse X positions.
     */
    private int diffX;

    /**
     * Holds the difference between mouse motion event Y positions and absolute mouse Y positions.
     */
    private int diffY;

    /**
     * Robot used for programmatically adjusting the mouse cursor position.
     */
    private Robot robot;
   
    /**
     * The picture frame that this MouseHandler is for.
     */
    private PictureFrame pictureFrame;

    /**
     * Helps to protect against clashes between mouse wheel rotation and clicks.
     */
    private int wheelCounter;
   
    /**
     * Cursor to show when moving over the picture.
     */
    private Cursor crossHairCursor;

    /**
     * Cursor to show when moving over status bar, menu and button panel.
     */
    private Cursor defaultCursor;

    /**
     * Cursor to show when hiding the mouse cursor (i.e. a blank cursor).
     */
    private Cursor blankCursor;
   
    /**
     * Whether the mouse is over the picture or not.
     */
    private boolean mouseIsOverPicture;
   
    /**
     * The last Point that the mouse was at. Used for mouse motion checks.
     */
    private Point lastPoint;
   
    /**
     * Constructor for MouseHandler.
     *
     * @param pictureFrame The PictureFrame that this MouseHandler is for.
     * @param application The PICEDIT application component.
     */
    public MouseHandler(final PictureFrame pictureFrame, final PicEdit application) {
        this.pictureFrame = pictureFrame;
        this.application = application;
       
        // Create the different types of cursor used in different parts of the screen.
        crossHairCursor = new Cursor(Cursor.CROSSHAIR_CURSOR);
        defaultCursor = new Cursor(Cursor.DEFAULT_CURSOR);
        blankCursor = java.awt.Toolkit.getDefaultToolkit().createCustomCursor(new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB), new Point(0, 0), "blank cursor");
       
        // Create a Robot for auto adjusting mouse position when tool restricts movement.
        try {
            robot = new Robot();
        } catch (Exception e) {
        }
       
        // Registers a mouse event listener to keep mouse activity within the the
        // picture panel while in line drawing mode.
        Toolkit.getDefaultToolkit().addAWTEventListener( new AWTEventListener() {
            public void eventDispatched(AWTEvent e) {
                if (pictureFrame.isSelected()) {
                    MouseEvent mouseEvent = (MouseEvent)e;
                   
                    // If a line is being drawn and the mouse event is outside the picture...
                    if (application.getEditStatus().isLineBeingDrawn() &&
                        !mouseEvent.getSource().equals(pictureFrame.getPicturePanel())) {
                       
                        // If it is a mouse pressed event then we process the click as if
                        // it was on the picture.
                        if (mouseEvent.getID() == MouseEvent.MOUSE_PRESSED) {
                            mousePressed(mouseEvent);
                        }
                       
                        // If it is a mouse motion event then we use the robot to move it
                        // back inside the panel.
                        if (mouseEvent.getID() == MouseEvent.MOUSE_MOVED) {
                            moveMouseToPictureCoordinates();
                        }
                    }
                }
            }
        }, (AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK));
    }
   
    /**
     * Checks if the mouse has moved and if it has then triggers the processing
     * of mouse motion and the updating of the appearance of the mouse cursor. This
     * method is invoked immediately before the application screen repaint.
     */
    public void checkForMouseMotion() {
        Point mousePoint = getPoint();
        EditStatus editStatus = application.getEditStatus();

        // Check if mouse point has changed.
        if (!mousePoint.equals(lastPoint)) {
            if (editStatus.isMenuActive()) {
                // If paused or menu system is active then ignore mouse motion.
            } else {
                // Otherwise process the mouse event as per normal.
                processMouseMove(mousePoint);
            }

            // Change mouse cursor depending on position.
            updateMouseCursor();
        }
    }

    /**
     * Returns the current mouse position, adjusted to the AGI screen coordinates.
     *
     * @return the current mouse position.
     */
    public Point getPoint() {
        Point absolutePosition = MouseInfo.getPointerInfo().getLocation();
        EditStatus editStatus = application.getEditStatus();

        int x = ((int) absolutePosition.getX() - diffX) / editStatus.getZoomFactor();
        int y = ((int) absolutePosition.getY() - diffY) / editStatus.getZoomFactor();

        return new Point(x, y);
    }

    /**
     * Invoked when a mouse drag event occurs.
     *
     * @param event the mouse drag event.
     */
    public void mouseDragged(MouseEvent event) {
    }

    /**
     * Invoked when a mouse motion event occurs. This is used only to track
     * the top left corner of the PICEDIT window. The mouse position returned
     * by MouseInfo is the absolute position on the computer's screen. The
     * mouse motion tracking timer needs to know the difference between the
     * absolute mouse position and the X/Y values contained in the real mouse
     * events.
     *
     * @param event the mouse motion event.
     */
    public void mouseMoved(MouseEvent event) {
        Point absolutePosition = MouseInfo.getPointerInfo().getLocation();
        this.diffX = (int) absolutePosition.getX() - event.getX();
        this.diffY = (int) absolutePosition.getY() - event.getY();
    }

    /**
     * Invoked when a mouse button is click.
     *
     * @param event the mouse click event.
     */
    public void mouseClicked(MouseEvent event) {
        // Ignored. Button status is handled by presssed.
    }

    /**
     * Invoked when the mouse enters the PICEDIT window.
     *
     * @param event the mouse entered event.
     */
    public void mouseEntered(MouseEvent event) {
        this.mouseIsOverPicture = true;
    }

    /**
     * Invoked when the mouse exits the PICEDIT window.
     *
     * @param event the mouse exited event.
     */
    public void mouseExited(MouseEvent event) {
        this.mouseIsOverPicture = false;
    }

    /**
     * Invoked when a mouse button is pressed down.
     *
     * @param event the mouse pressed event.
     */
    public void mousePressed(MouseEvent event) {
        Point mousePoint = getPoint();
        EditStatus editStatus = application.getEditStatus();

        if (editStatus.isMenuActive()) {
            // If menu was active and we received a mouse click, then set menu active false again.
            editStatus.setMenuActive(false);
        } else {
            // Otherwise process mouse click as per normal.
            processMouseClick(mousePoint, event.getButton());
           
            // Mouse wheel button, AKA. the middle button. This is not a picture related action, so
            // we process outside of the normal processMouseClick.
            if (event.getButton() == MouseEvent.BUTTON2) {
                // Reset the current tool if line is being drawn. Doesn't make sense to keep line
                // drawing enabled while colour is being chosen.
                if (editStatus.isLineBeingDrawn()) {
                    editStatus.resetTool();
                }
               
                Point eventPoint = event.getLocationOnScreen();
                Point dialogPoint = new Point(eventPoint.x - 34, eventPoint.y - 34);
               
                // Pop up colour chooser.
                ColourChooserDialog dialog = new ColourChooserDialog(dialogPoint);
                dialog.setVisible(true);
               
                // Process the chosen visual colour.
                application.getPicture().processVisualColourChange(dialog.getChosenColour());
               
                // This helps to protect against clashes between wheel clicks and rotation.
                wheelCounter = 0;
            }
        }
    }

    /**
     * Invoked when a mouse button is released.
     *
     * @param event the mouse released event.
     */
    public void mouseReleased(MouseEvent event) {
    }
   
    /**
     * Invoked when the mouse wheel is moved.
     *
     * @param event the mouse wheel moved event.
     */
    public void mouseWheelMoved(MouseWheelEvent event) {
        EditStatus editStatus = application.getEditStatus();
       
        wheelCounter += event.getWheelRotation();
       
        if (wheelCounter < -1) {
        // Zoom in.
            int zoomFactor = editStatus.getZoomFactor();
            if (zoomFactor < 5) {
                application.resizeScreen(zoomFactor + 1);
            }
            wheelCounter = 0;
      } else if (wheelCounter > 1) {
        // Zoom out.
            int zoomFactor = editStatus.getZoomFactor();
            if (zoomFactor > 1) {
                application.resizeScreen(zoomFactor - 1);
            }
            wheelCounter = 0;
      }
    }

    /**
     * Updates the appearance of the mouse cursor depending on where the mouse is and
     * what tool is being used.
     */
    private void updateMouseCursor() {
        EditStatus editStatus = application.getEditStatus();
       
        if (!editStatus.isMenuActive() && mouseIsOverPicture) {
            if ((editStatus.getNumOfClicks() == 0) || editStatus.isFillActive() || editStatus.isBrushActive()) {
                // If the tool is Fill or Brush then show the standard cross hair cursor.
                application.setCursor(crossHairCursor);
            } else {
                // If the tool is Line, Pen or Step then show no cursor (end of line with 'glow' instead).
                application.setCursor(blankCursor);
            }
        } else {
            // If the mouse position is over the edit panel, or the status bar, or the menu
            // system is active, then show the default pointer.
            application.setCursor(defaultCursor);
        }
    }
   
    /**
     * Processes the movement of the mouse.
     *
     * @param mousePoint the Point where the mouse currently is.
     */
    public void processMouseMove(Point mousePoint) {
        EditStatus editStatus = application.getEditStatus();
        PicturePanel picturePanel = application.getPicturePanel();
       
        // Update the status line on every mouse movement.
        editStatus.updateMousePoint(mousePoint);

        int x = editStatus.getMouseX();
        int y = editStatus.getMouseY();
       
        if (editStatus.getNumOfClicks() > 0) {
            // Make sure that the mouse cursor can't leave the picture while a line
            // is being drawn.
            Point clickPoint = editStatus.getClickPoint();
            int clickX = (int) clickPoint.getX();
            int clickY = (int) clickPoint.getY();
            int lineColour = editStatus.getTemporaryLineColour();

            if (editStatus.isLineActive()) {
              picturePanel.drawTemporaryLine(clickX, clickY, x, y, lineColour);
            }
            if (editStatus.isStepActive()) {
                int dX = 0;
                int dY = 0;

                switch (editStatus.getNumOfClicks()) {
                    case 1:
                        dX = x - clickX;
                        dY = y - clickY;
                        if (Math.abs(dX) > Math.abs(dY)) {
                            y = clickY;
                        } else {
                            x = clickX;
                        }
                        picturePanel.drawTemporaryLine(clickX, clickY, x, y, lineColour);
                        break;

                    default:
                        if ((editStatus.isXCornerActive() && ((editStatus.getNumOfClicks() % 2) == 0)) || (editStatus.isYCornerActive() && ((editStatus.getNumOfClicks() % 2) > 0))) {
                            // X and Y corners toggle different direction based on number of clicks. 
                            x = clickX;
                        } else {
                            y = clickY;
                        }
                        picturePanel.drawTemporaryLine(clickX, clickY, x, y, lineColour);
                        break;
                }
            }
            if (editStatus.isPenActive()) {
                x = clickX + adjustForPen(x - clickX, 6);
                y = clickY + adjustForPen(y - clickY, 7);
                picturePanel.drawTemporaryLine(clickX, clickY, x, y, lineColour);
            }
           
            // Move the mouse to the tool restricted x/y position (if applicable).
            if ((robot != null) && ((x != editStatus.getMouseX()) || (y != editStatus.getMouseY()))) {
                // Make sure the EditStatus has the tool adjusted mouse point.
                editStatus.setMousePoint(new Point(x, y));

                // Move the mouse back to the tool adjusted point. This is important
                // when the tool is Pen or Step since these tools are restricted in
                // their movements.
                moveMouseToPictureCoordinates();
            }
        }
    }

    /**
     * Processes the given mouse click.
     *
     * @param mousePoint the Point where the mouse click occurred.
     * @param mouseButton the mouse button that was clicked.
     */
    public void processMouseClick(Point mousePoint, int mouseButton) {
        int x = (int) mousePoint.getX();
        int y = (int) mousePoint.getY();
       
        EditStatus editStatus = application.getEditStatus();
        Picture picture = application.getPicture();

        // Is it the LEFT mouse button?
        if (mouseButton == MouseEvent.BUTTON1) {
            // Is a tool active?
            if (editStatus.getTool() != ToolType.NONE) {
                // Register the new left mouse click in the edit status.
                editStatus.addClickPoint();

                // Get the 'adjusted' X & Y position back from the edit status.
                Point pictureClickPoint = editStatus.getClickPoint();
                x = (int) pictureClickPoint.getX();
                y = (int) pictureClickPoint.getY();

                // Get the previous mouse click point for use with Line, Pen, Step.
                int previousX = 0;
                int previousY = 0;
                Point previousClickPoint = editStatus.getPreviousClickPoint();
                if (previousClickPoint != null) {
                    previousX = (int) previousClickPoint.getX();
                    previousY = (int) previousClickPoint.getY();
                }

                // If a given tool is active then update the AGI picture.
                if (editStatus.isFillActive()) {
                    picture.fill(x, y);
                    if (editStatus.isFirstClick()) {
                        picture.addPictureCode(PictureCodeType.DRAW_FILL);
                    }
                    picture.addPictureCode(PictureCodeType.FILL_POINT_DATA, x, y);
                } else if (editStatus.isLineActive()) {
                    switch (editStatus.getNumOfClicks()) {
                        case 1:
                            picture.addPictureCode(PictureCodeType.DRAW_LINE);
                            picture.addPictureCode(x, y);
                            picture.putPixel(x, y);
                            break;
                        default:
                            picture.addPictureCode(x, y);
                            picture.drawLine(previousX, previousY, x, y);
                            break;
                    }
                } else if (editStatus.isPenActive()) {
                    int disp = 0;
                    int dX = 0;
                    int dY = 0;

                    switch (editStatus.getNumOfClicks()) {
                        case 1:
                            picture.addPictureCode(PictureCodeType.DRAW_SHORT_LINE);
                            picture.addPictureCode(x, y);
                            picture.putPixel(x, y);
                            break;
                        default:
                            dX = adjustForPen(x - previousX, 6);
                            dY = adjustForPen(y - previousY, 7);
                            x = previousX + dX;
                            y = previousY + dY;

                            if (dX < 0) {
                                disp = (0x80 | ((((-1) * dX) - 0) << 4));
                            } else {
                                disp = (dX << 4);
                            }
                            if (dY < 0) {
                                disp |= (0x08 | (((-1) * dY) - 0));
                            } else {
                                disp |= dY;
                            }
                            picture.addPictureCode(PictureCodeType.RELATIVE_POINT_DATA, disp, new Point(x, y));
                            picture.drawLine(previousX, previousY, x, y);
                            editStatus.setClickPoint(new Point(x, y));
                            break;
                    }
                } else if (editStatus.isBrushActive()) {
                    int patNum = 0;

                    if (editStatus.isFirstClick()) {
                        picture.addPictureCode(PictureCodeType.SET_BRUSH_TYPE);
                        picture.addPictureCode(PictureCodeType.BRUSH_TYPE_DATA, editStatus.getBrushCode());
                        picture.addPictureCode(PictureCodeType.DRAW_BRUSH_POINT);
                    }
                    patNum = (((new java.util.Random().nextInt(255)) % 0xEE) >> 1) & 0x7F;
                    picture.plotPattern(patNum, x, y);
                    if (editStatus.getBrushTexture() == BrushTexture.SPRAY) {
                        picture.addPictureCode(PictureCodeType.BRUSH_PATTERN_DATA, patNum << 1);
                    }
                    picture.addPictureCode(PictureCodeType.BRUSH_POINT_DATA, x, y);
                } else if (editStatus.isStepActive()) {
                    int dX = 0;
                    int dY = 0;

                    switch (editStatus.getNumOfClicks()) {
                        case 1:
                            break;

                        case 2:
                            dX = x - previousX;
                            dY = y - previousY;
                            if (Math.abs(dX) > Math.abs(dY)) { /* X or Y corner */
                                y = previousY;
                                editStatus.setStepType(StepType.XCORNER);
                                picture.addPictureCode(PictureCodeType.DRAW_HORIZONTAL_STEP_LINE);
                                picture.addPictureCode(previousX, previousY);
                                picture.addPictureCode(PictureCodeType.X_POSITION_DATA, x, new Point(x, y));
                            } else {
                                x = previousX;
                                editStatus.setStepType(StepType.YCORNER);
                                picture.addPictureCode(PictureCodeType.DRAW_VERTICAL_STEP_LINE);
                                picture.addPictureCode(previousX, previousY);
                                picture.addPictureCode(PictureCodeType.Y_POSITION_DATA, y, new Point(x, y));
                            }
                            picture.drawLine(previousX, previousY, x, y);
                            editStatus.setClickPoint(new Point(x, y));
                            break;

                        default:
                            if ((editStatus.isXCornerActive() && ((editStatus.getNumOfClicks() % 2) > 0)) || (editStatus.isYCornerActive() && ((editStatus.getNumOfClicks() % 2) == 0))) {
                                // X and Y corners toggle different direction based on number of clicks. 
                                x = previousX;
                                picture.addPictureCode(PictureCodeType.Y_POSITION_DATA, y, new Point(x, y));
                            } else {
                                y = previousY;
                                picture.addPictureCode(PictureCodeType.X_POSITION_DATA, x, new Point(x, y));
                            }
                            picture.drawLine(previousX, previousY, x, y);
                            editStatus.setClickPoint(new Point(x, y));
                            break;
                    }
                }
            }
        }
       
        // Is it the RIGHT mouse button?
        if (mouseButton == MouseEvent.BUTTON3) {
            // Right-clicking on the AGI picture will clear the current tool selection.
            if ((editStatus.getNumOfClicks() == 1) && (editStatus.isStepActive())) {
                // Single point line support for the Step tool.
               
                // Get the 'adjusted' X & Y position back from the edit status.
                editStatus.addClickPoint();
                Point pictureClickPoint = editStatus.getClickPoint();
                x = (int) pictureClickPoint.getX();
                y = (int) pictureClickPoint.getY();

                // Get the previous mouse click point for use with single point Step.
                int previousX = 0;
                int previousY = 0;
                Point previousClickPoint = editStatus.getPreviousClickPoint();
                if (previousClickPoint != null) {
                    previousX = (int) previousClickPoint.getX();
                    previousY = (int) previousClickPoint.getY();
                }
               
                // The X/Y corner decision for single point is based on where right click was.
                int dX = x - previousX;
                int dY = y - previousY;
                if (Math.abs(dX) > Math.abs(dY)) { /* X or Y corner */
                    picture.addPictureCode(PictureCodeType.DRAW_HORIZONTAL_STEP_LINE);
                    picture.addPictureCode(previousX, previousY);
                } else {
                    picture.addPictureCode(PictureCodeType.DRAW_VERTICAL_STEP_LINE);
                    picture.addPictureCode(previousX, previousY);
                }
               
                picture.putPixel(previousX, previousY);
            }
            if (editStatus.getNumOfClicks() > 0) {
                // If a tool is active (i.e. has a least one click) then right click resets
                // number of clicks, which allows the user to move to new location.
                editStatus.resetTool();
            } else {
                // If no clicks performed yet then a right click sets tool to None.
                editStatus.setTool(ToolType.NONE);
            }
        }
       
        // Update active status of the position slider based on whether a line is being
        // drawn or not. It should not be possible to use the slider if line drawing is
        // enabled.
        pictureFrame.getPositionSlider().setEnabled(!editStatus.isLineBeingDrawn());
    }

    /**
     * Moves the mouse cursor to the position that matches what the EditStatus says
     * is the current picture coordinates. This is useful for situations where the
     * current picture coordinates have been restricted due to the bounds of the
     * picture or the bounds of the drawing tool (e.g. Pen or Step).
     */
    private void moveMouseToPictureCoordinates() {
        EditStatus editStatus = application.getEditStatus();
       
        // Get current picture coordinates.
        int x = editStatus.getMouseX();
        int y = editStatus.getMouseY();
       
        // Adjust the picture coordinates back to screen coordinates.
        if (editStatus.getPictureType().equals(PictureType.AGI)) {
            x = ((x << 1) * editStatus.getZoomFactor()) + diffX;
        } else {
            x = (x * editStatus.getZoomFactor()) + diffX;
        }
        y = (y * editStatus.getZoomFactor()) + diffY;
     
        // Use robot to move the mouse cursor to the calculated position.
        robot.mouseMove(x, y);
    }
   
    /**
     * The Pen tool has a very short distance between two points. This
     * method is used for checking those limits.
     *
     * @param value the value to adjust. Will either be an X or Y value.
     * @param limit the limit in both directs that to enforce.
     */
    private int adjustForPen(int value, int limit) {
        if (value > limit) {
            value = limit;
        }
        if (value < -limit) {
            value = -limit;
        }
        return value;
    }
}
TOP

Related Classes of com.agifans.picedit.gui.handler.MouseHandler

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.