/* * Open Source Physics software is free software as described near the bottom of this code file. * * For additional information and documentation on Open Source Physics please see: * <http://www.opensourcephysics.org/> */ package org.opensourcephysics.display; import java.awt.Cursor; import java.awt.event.MouseEvent; import java.util.ArrayList; import javax.swing.event.MouseInputAdapter; /** * InteractivePanel is a drawing panel that invokes the handleMouseAction method in * Interactive objects. * @author Wolfgang Christian * @author Francisco Esquembre * @version 1.0 */ public class InteractivePanel extends DrawingPanel implements InteractiveMouseHandler { public static final int MOUSE_PRESSED = 1; public static final int MOUSE_RELEASED = 2; public static final int MOUSE_DRAGGED = 3; public static final int MOUSE_CLICKED = 4; public static final int MOUSE_ENTERED = 5; public static final int MOUSE_EXITED = 6; public static final int MOUSE_MOVED = 7; protected boolean containsInteractive = false; protected int mouseAction = 0; protected MouseEvent mouseEvent = null; protected InteractiveMouseHandler interactive = null; private Interactive iaDraggable = null; // interactive object that is being dragged private Selectable iaSelectable = null; // interactive object that has been selected /** * Constructs an InteractivePanel with the given handler. * @param in InteractiveMouseHandler */ public InteractivePanel(InteractiveMouseHandler in) { this(); interactive = in; } /** * Constructs an InteractivePanel with an internal handler. */ public InteractivePanel() { // remove the drawing panel mouse controller removeMouseListener(mouseController); removeMouseMotionListener(mouseController); // create and add a new mouse controller for interactive drawing mouseController = new IADMouseController(); addMouseListener(mouseController); addMouseMotionListener(mouseController); interactive = this; // this panel is the default handler } /** * Adds a drawable object to the drawable list. * @param drawable */ public void addDrawable(Drawable drawable) { super.addDrawable(drawable); if(drawable instanceof Interactive) { containsInteractive = true; } } /** * Removes all drawable objects from the drawable list. */ public void clear() { super.clear(); containsInteractive = false; } /** * Sets the x axis scale based on the max and min values of all measurable objects. * Autoscale flag is not respected. */ protected void scaleX(ArrayList<Drawable> tempList) { double tempmin = xminPreferred; double tempmax = xmaxPreferred; super.scaleX(tempList); // increase but do not decrease if dragging and autoscaling if(autoscaleX&&(mouseAction==MOUSE_DRAGGED)) { if(xminPreferred>tempmin) { xminPreferred = tempmin; } if(xmaxPreferred<tempmax) { xmaxPreferred = tempmax; } } } /** * Sets the y axis scale based on the max and min values of all measurable objects. * Autoscale flag is not respected. */ protected void scaleY(ArrayList<Drawable> tempList) { double tempmin = yminPreferred; double tempmax = ymaxPreferred; super.scaleY(tempList); // increase but do not decrease if dragging and autoscaling if(autoscaleY&&(mouseAction==MOUSE_DRAGGED)) { if(yminPreferred>tempmin) { yminPreferred = tempmin; } if(ymaxPreferred<tempmax) { ymaxPreferred = tempmax; } } } /** * Sets the interactive mouse handler. * * The interactive mouse handler is notified whenever a mouse action occurs. * * @param handler the mouse handler */ public void setInteractiveMouseHandler(InteractiveMouseHandler handler) { interactive = handler; } /** * Handles mouse actions by dragging the current interactive drawable object. * * @param panel * @param evt */ public void handleMouseAction(InteractivePanel panel, MouseEvent evt) { switch(panel.getMouseAction()) { case InteractivePanel.MOUSE_CLICKED : Interactive clickedIA = getInteractive(); if((panel.getMouseClickCount()<2)||(clickedIA==null)||!(clickedIA instanceof Selectable)) { return; } if((iaSelectable!=null)&&(iaSelectable!=clickedIA)) { iaSelectable.setSelected(false); } iaSelectable = ((Selectable) clickedIA); iaSelectable.toggleSelected(); invalidateImage(); //validImage = false; if(!getIgnoreRepaint()) { panel.repaint(); } break; case InteractivePanel.MOUSE_DRAGGED : if(iaDraggable==null) { return; // nothing to drag } double x = panel.getMouseX(); double y = panel.getMouseY(); if(!autoscaleX&&(evt.getX()<1+leftGutter)) { x = panel.pixToX(1+leftGutter); } if(!autoscaleX&&(evt.getX()>panel.getWidth()-1-rightGutter)) { x = panel.pixToX(panel.getWidth()-1-rightGutter); } if(!autoscaleY&&(evt.getY()<1+topGutter)) { y = panel.pixToY(1+topGutter); } if(!autoscaleY&&(evt.getY()>panel.getHeight()-1-bottomGutter)) { y = panel.pixToY(panel.getHeight()-1-bottomGutter); } iaDraggable.setXY(x, y); // drag the interactive object invalidateImage(); //validImage = false; if(!getIgnoreRepaint()) { panel.repaint(); // repaint to keep the screen up to date } break; case InteractivePanel.MOUSE_RELEASED : if((autoscaleX||autoscaleY)&&!getIgnoreRepaint()) { panel.repaint(); // repaint to keep the screen up to date } break; } } /** * Get the Interactive object that is currently being dragged. * @return Interactive */ public Interactive getCurrentDraggable() { return iaDraggable; } /** * Gets the interactive object that was accessed by the last mouse event. * @return Interactive */ public Interactive getInteractive() { if(!containsInteractive) { return null; // don't check unless we have a least one Interactive } if(iaDraggable!=null) { return iaDraggable; } if((iaSelectable!=null)&&iaSelectable.isSelected()) { // check only selected object Interactive iad = ((Interactive) iaSelectable).findInteractive(this, mouseEvent.getX(), mouseEvent.getY()); return iad; } Object[] array = null; synchronized(drawableList) { array = drawableList.toArray(); } for(int i = array.length-1; i>=0; i--) { Object obj = array[i]; if(obj instanceof Interactive) { Interactive iad = ((Interactive) obj).findInteractive(this, mouseEvent.getX(), mouseEvent.getY()); if(iad!=null) { return iad; } } } return null; } /** * Shows the coordinates in the text box in the lower left hand corner. * * @param show */ public void setShowCoordinates(boolean show) { showCoordinates = show; } /** * Gets the mouse button of the last mouse event. * @return int */ public int getMouseButton() { switch(mouseEvent.getModifiers()) { case java.awt.event.InputEvent.BUTTON1_MASK : return 1; case java.awt.event.InputEvent.BUTTON2_MASK : return 2; case java.awt.event.InputEvent.BUTTON3_MASK : return 3; default : return 0; } } /** * Gets the click count of the last mouse event. * * @return int */ public int getMouseClickCount() { return mouseEvent.getClickCount(); } /** * Gets the last mouse action. * @return int */ public int getMouseAction() { return mouseAction; } /** * Gets the x pixel coordinate of the last mouse event. * @return pixel */ public int getMouseIntX() { return mouseEvent.getX(); } /** * Gets the y pixel coordinate of the last mouse event. * @return pixel */ public int getMouseIntY() { return mouseEvent.getY(); } /** * Gets the x world coordinate of the last mouse event. * @return coordiante */ public double getMouseX() { return pixToX(mouseEvent.getX()); } /** * Gets the y world coordinate of the last moust event * @return coordinate */ public double getMouseY() { return pixToY(mouseEvent.getY()); } /** * Saves the last mouse event. * @param type * @param evt */ public void saveMouseEvent(int type, java.awt.event.MouseEvent evt) { mouseAction = type; mouseEvent = evt; } /** * The inner class that will handle all mouse related events. */ protected class IADMouseController extends MouseInputAdapter { /** * Handle the mouse pressed event. * @param e */ public void mousePressed(MouseEvent e) { mouseEvent = e; mouseAction = MOUSE_PRESSED; if(interactive!=null) { // is there an object available to hande the mouse event interactive.handleMouseAction(InteractivePanel.this, e); iaDraggable = null; // force the panel to search all drawables iaDraggable = getInteractive(); if(iaDraggable!=null) { if(iaDraggable instanceof Selectable) { setMouseCursor(((Selectable) iaDraggable).getPreferredCursor()); } else { setMouseCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); } } } if(showCoordinates) { String s = coordinateStrBuilder.getCoordinateString(InteractivePanel.this, e); blMessageBox.setText(s); } } /** * Handles the mouse released event. * @param e */ public void mouseReleased(MouseEvent e) { mouseEvent = e; mouseAction = MOUSE_RELEASED; if(interactive!=null) { interactive.handleMouseAction(InteractivePanel.this, e); } iaDraggable = null; if(showCoordinates) { blMessageBox.setText(null); } setMouseCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); } /** * Handles the mouse entered event. * @param e */ public void mouseEntered(MouseEvent e) { if(showCoordinates) { setMouseCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); } mouseEvent = e; mouseAction = MOUSE_ENTERED; if(interactive!=null) { interactive.handleMouseAction(InteractivePanel.this, e); } } /** * Handles the mouse exited event. * @param e */ public void mouseExited(MouseEvent e) { setMouseCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); mouseEvent = e; mouseAction = MOUSE_EXITED; if(interactive!=null) { interactive.handleMouseAction(InteractivePanel.this, e); } } /** * Handles the mouse clicked event. * @param e */ public void mouseClicked(MouseEvent e) { mouseEvent = e; mouseAction = MOUSE_CLICKED; if(interactive==null) { return; } interactive.handleMouseAction(InteractivePanel.this, e); } /** * Handles the mouse dragged event. * @param e */ public void mouseDragged(MouseEvent e) { mouseEvent = e; mouseAction = MOUSE_DRAGGED; if(interactive!=null) { interactive.handleMouseAction(InteractivePanel.this, e); } if(showCoordinates) { String s = coordinateStrBuilder.getCoordinateString(InteractivePanel.this, e); blMessageBox.setText(s); } } /** * Handles the mouse moved event. * @param e */ public void mouseMoved(MouseEvent e) { mouseEvent = e; mouseAction = MOUSE_MOVED; iaDraggable = null; if(interactive!=null) { // check to see if there is an interactive object interactive.handleMouseAction(InteractivePanel.this, e); Interactive iad = getInteractive(); if(iad==null) { setMouseCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); } else { if(iad instanceof Selectable) { setMouseCursor(((Selectable) iad).getPreferredCursor()); } else { setMouseCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); } } } } } } /* * Open Source Physics software is free software; you can redistribute * it and/or modify it under the terms of the GNU General Public License (GPL) as * published by the Free Software Foundation; either version 2 of the License, * or(at your option) any later version. * Code that uses any portion of the code in the org.opensourcephysics package * or any subpackage (subdirectory) of this package must must also be be released * under the GNU GPL license. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA * or view the license online at http://www.gnu.org/copyleft/gpl.html * * Copyright (c) 2007 The Open Source Physics project * http://www.opensourcephysics.org */