public void actionPerformed(ActionEvent e) { Object source = e.getSource(); if (source == testMenuItem1) { System.out.println("testMenuItem1 has been selected"); } else if (source == testMenuItem2) { System.out.println("testMenuItem2 has been selected"); } else if (source == frameAllButton) { gw.frame(drawing.getBoundingRectangle(), true); multitouchFramework.requestRedraw(); } else if (source == testButton1) { System.out.println("testButton1 has been selected"); } else if (source == testButton2) { System.out.println("testButton2 has been selected"); } }
// returns true if a redraw is requested public boolean processMultitouchInputEvent( int id, float x, // in pixels float y, // in pixels int type, GraphicsWrapper gw, boolean doOtherUserContextsHaveCursors) { // Find the cursor that corresponds to the event id, if such a cursor already exists. // If no such cursor exists, the below index will be -1, and the reference to cursor will be // null. int cursorIndex = cursorContainer.findIndexOfCursorById(id); MyCursor cursor = (cursorIndex == -1) ? null : cursorContainer.getCursorByIndex(cursorIndex); if (cursor == null) { if (type == MultitouchFramework.TOUCH_EVENT_UP) { // This should never happen, but if it does, just ignore the event. return false; } // The event does not correspond to any existing cursor. // In other words, this is a new finger touching the screen. // The event is probably of type TOUCH_EVENT_DOWN. // A new cursor will need to be created for the event. if (palette.contains(x, y)) { // The event occurred inside the palette. if (cursorContainer.getNumCursors() == 0) { // There are currently no cursors engaged for this user context. // In other words, this new finger is the only finger for the user context. // So, we allow the event for the new finger to activate a button in the palette. // We branch according to the button under the event. // int indexOfButton = palette.indexOfButtonContainingTheGivenPoint(x, y); if (indexOfButton == palette.movePalette_buttonIndex) { palette.buttons.get(indexOfButton).isPressed = true; // Cause a new cursor to be created to keep track of this event id in the future cursorIndex = cursorContainer.updateCursorById(id, x, y); cursor = cursorContainer.getCursorByIndex(cursorIndex); cursor.setType(MyCursor.TYPE_INTERACTING_WITH_WIDGET, indexOfButton); } else if (indexOfButton == palette.ink_buttonIndex || indexOfButton == palette.select_buttonIndex || indexOfButton == palette.manipulate_buttonIndex || indexOfButton == palette.camera_buttonIndex) { // We transition to the mode corresponding to the button palette.buttons.get(palette.currentlyActiveModalButton).isPressed = false; palette.currentlyActiveModalButton = indexOfButton; palette.buttons.get(indexOfButton).isPressed = true; // Cause a new cursor to be created to keep track of this event id in the future cursorIndex = cursorContainer.updateCursorById(id, x, y); cursor = cursorContainer.getCursorByIndex(cursorIndex); cursor.setType(MyCursor.TYPE_INTERACTING_WITH_WIDGET, indexOfButton); } else if (indexOfButton == palette.black_buttonIndex || indexOfButton == palette.red_buttonIndex || indexOfButton == palette.green_buttonIndex) { // We transition to the color corresponding to the button palette.buttons.get(palette.currentlyActiveColorButton).isPressed = false; palette.currentlyActiveColorButton = indexOfButton; palette.buttons.get(indexOfButton).isPressed = true; if (indexOfButton == palette.black_buttonIndex) { palette.current_red = 0; palette.current_green = 0; palette.current_blue = 0; } else if (indexOfButton == palette.red_buttonIndex) { palette.current_red = 1.0f; palette.current_green = 0; palette.current_blue = 0; } else if (indexOfButton == palette.green_buttonIndex) { palette.current_red = 0; palette.current_green = 1.0f; palette.current_blue = 0; } // Cause a new cursor to be created to keep track of this event id in the future cursorIndex = cursorContainer.updateCursorById(id, x, y); cursor = cursorContainer.getCursorByIndex(cursorIndex); cursor.setType(MyCursor.TYPE_INTERACTING_WITH_WIDGET, indexOfButton); } else if (indexOfButton == palette.horizFlip_buttonIndex) { palette.buttons.get(indexOfButton).isPressed = true; // Cause a new cursor to be created to keep track of this event id in the future cursorIndex = cursorContainer.updateCursorById(id, x, y); cursor = cursorContainer.getCursorByIndex(cursorIndex); cursor.setType(MyCursor.TYPE_INTERACTING_WITH_WIDGET, indexOfButton); // Flip the selected strokes horizontally (around a vertical axis) for (Stroke s : selectedStrokes) { Point2D center = s.getBoundingRectangle().getCenter(); for (Point2D p : s.getPoints()) { p.copy(center.x() - (p.x() - center.x()), p.y()); } s.markBoundingRectangleDirty(); } drawing.markBoundingRectangleDirty(); } else if (indexOfButton == palette.frameAll_buttonIndex) { palette.buttons.get(indexOfButton).isPressed = true; // Cause a new cursor to be created to keep track of this event id in the future cursorIndex = cursorContainer.updateCursorById(id, x, y); cursor = cursorContainer.getCursorByIndex(cursorIndex); cursor.setType(MyCursor.TYPE_INTERACTING_WITH_WIDGET, indexOfButton); // Frame the entire drawing gw.frame(drawing.getBoundingRectangle(), true); } else { // The event occurred on some part of the palette where there are no buttons. // We cause a new cursor to be created to keep track of this event id in the future. cursorIndex = cursorContainer.updateCursorById(id, x, y); cursor = cursorContainer.getCursorByIndex(cursorIndex); // Prevent the cursor from doing anything in the future. cursor.setType(MyCursor.TYPE_NOTHING); } } else { // There is already at least one cursor. // In other words, there is already one or more other fingers being tracked in this user // context // (possibly on a palette button, and/or over the drawing). // To keep things simple, we prevent this new finger from doing anything. // We create a new cursor ... cursorIndex = cursorContainer.updateCursorById(id, x, y); cursor = cursorContainer.getCursorByIndex(cursorIndex); // ... and prevent the cursor from doing anything in the future. cursor.setType(MyCursor.TYPE_NOTHING); } } else { // The event did not occur inside the palette. // This new finger may have been placed down to start // drawing a stroke, or start camera manipulation, etc. // We branch according to the current mode. // if (palette.currentlyActiveModalButton == palette.ink_buttonIndex) { // start drawing a stroke cursorIndex = cursorContainer.updateCursorById(id, x, y); cursor = cursorContainer.getCursorByIndex(cursorIndex); cursor.setType(MyCursor.TYPE_INKING); } else if (palette.currentlyActiveModalButton == palette.select_buttonIndex) { // The new finger should only start selecting // if there is not already another finger performing selection. if (cursorContainer.getNumCursorsOfGivenType(MyCursor.TYPE_SELECTION) == 0) { cursorIndex = cursorContainer.updateCursorById(id, x, y); cursor = cursorContainer.getCursorByIndex(cursorIndex); cursor.setType(MyCursor.TYPE_SELECTION); } else { cursorIndex = cursorContainer.updateCursorById(id, x, y); cursor = cursorContainer.getCursorByIndex(cursorIndex); cursor.setType(MyCursor.TYPE_NOTHING); } } else if (palette.currentlyActiveModalButton == palette.manipulate_buttonIndex) { // The new finger should only manipulate the selection // if there are not already 2 fingers manipulating the selection. if (cursorContainer.getNumCursorsOfGivenType(MyCursor.TYPE_DIRECT_MANIPULATION) < 2) { cursorIndex = cursorContainer.updateCursorById(id, x, y); cursor = cursorContainer.getCursorByIndex(cursorIndex); cursor.setType(MyCursor.TYPE_DIRECT_MANIPULATION); } else { cursorIndex = cursorContainer.updateCursorById(id, x, y); cursor = cursorContainer.getCursorByIndex(cursorIndex); cursor.setType(MyCursor.TYPE_NOTHING); } } else if (palette.currentlyActiveModalButton == palette.camera_buttonIndex) { // The new finger should only manipulate the camera // if there are not already 2 fingers manipulating the camera. if (cursorContainer.getNumCursorsOfGivenType(MyCursor.TYPE_CAMERA_PAN_ZOOM) < 2) { cursorIndex = cursorContainer.updateCursorById(id, x, y); cursor = cursorContainer.getCursorByIndex(cursorIndex); cursor.setType(MyCursor.TYPE_CAMERA_PAN_ZOOM); } else { cursorIndex = cursorContainer.updateCursorById(id, x, y); cursor = cursorContainer.getCursorByIndex(cursorIndex); cursor.setType(MyCursor.TYPE_NOTHING); } } } } else { // The event corresponds to an already existing cursor // (and the cursor was probably created during an earlier event of type TOUCH_EVENT_DOWN). // The current event is probably of type TOUCH_EVENT_MOVE or TOUCH_EVENT_UP. if (type == MultitouchFramework.TOUCH_EVENT_MOVE) { // The event is a move event, and corresponds to an existing cursor. // Is the location of the event different from the last reported location? Point2D newPosition = new Point2D(x, y); if (cursor.getCurrentPosition().equals(newPosition)) { // The event's location is the same as last time. // Don't bother processing the event any further. return false; // do not request a redraw } } // We branch according to the type of cursor. // if (cursor.type == MyCursor.TYPE_NOTHING) { // Update the cursor with its new position. cursorContainer.updateCursorById(id, x, y); if (type == MultitouchFramework.TOUCH_EVENT_UP) cursorContainer.removeCursorByIndex(cursorIndex); } else if (cursor.type == MyCursor.TYPE_INTERACTING_WITH_WIDGET) { if (type == MultitouchFramework.TOUCH_EVENT_UP) { // The user lifted their finger off of a palette button. cursorContainer.removeCursorByIndex(cursorIndex); if (!palette.buttons.get(cursor.indexOfButton).isSticky) { palette.buttons.get(cursor.indexOfButton).isPressed = false; } } else { // Earlier, the user pressed down on a button in the palette, // and now they are dragging their finger over the button // (and possibly onto other buttons). // If this is the "move palette" button, we move the palette. if (cursor.indexOfButton == palette.movePalette_buttonIndex) { movePalette(x - cursor.getCurrentPosition().x(), y - cursor.getCurrentPosition().y()); } cursorIndex = cursorContainer.updateCursorById(id, x, y); } } else if (cursor.type == MyCursor.TYPE_INKING) { if (type == MultitouchFramework.TOUCH_EVENT_UP) { // up event cursorIndex = cursorContainer.updateCursorById(id, x, y); // Add the newly drawn stroke to the drawing Stroke newStroke = new Stroke(); newStroke.setColor(palette.current_red, palette.current_green, palette.current_blue); for (Point2D p : cursor.getPositions()) { newStroke.addPoint(gw.convertPixelsToWorldSpaceUnits(p)); } drawing.addStroke(newStroke); cursorContainer.removeCursorByIndex(cursorIndex); } else { // drag event; just update the cursor with the new position cursorIndex = cursorContainer.updateCursorById(id, x, y); } } else if (cursor.type == MyCursor.TYPE_CAMERA_PAN_ZOOM) { if (type == MultitouchFramework.TOUCH_EVENT_UP) { // up event cursorContainer.removeCursorByIndex(cursorIndex); } else { // drag event cursorIndex = cursorContainer.updateCursorById(id, x, y); if (cursorContainer.getNumCursorsOfGivenType(MyCursor.TYPE_CAMERA_PAN_ZOOM) == 2) { MyCursor cursor0 = cursorContainer.getCursorByType(MyCursor.TYPE_CAMERA_PAN_ZOOM, 0); MyCursor cursor1 = cursorContainer.getCursorByType(MyCursor.TYPE_CAMERA_PAN_ZOOM, 1); gw.panAndZoomBasedOnDisplacementOfTwoPoints( id == cursor0.id ? cursor0.getPreviousPosition() : cursor0.getCurrentPosition(), id == cursor1.id ? cursor1.getPreviousPosition() : cursor1.getCurrentPosition(), cursor0.getCurrentPosition(), cursor1.getCurrentPosition()); } else if (cursorContainer.getNumCursorsOfGivenType(MyCursor.TYPE_CAMERA_PAN_ZOOM) == 1) { gw.pan( cursor.getCurrentPosition().x() - cursor.getPreviousPosition().x(), cursor.getCurrentPosition().y() - cursor.getPreviousPosition().y()); } } } else if (cursor.type == MyCursor.TYPE_SELECTION) { if (type == MultitouchFramework.TOUCH_EVENT_UP) { // up event cursorIndex = cursorContainer.updateCursorById(id, x, y); // Update the selection if (cursor.doesDragLookLikeLassoGesture()) { // complete a lasso selection // Need to transform the positions of the cursor from pixels to world space coordinates. // We will store the world space coordinates in the following data structure. ArrayList<Point2D> lassoPolygonPoints = new ArrayList<Point2D>(); for (Point2D p : cursor.getPositions()) { lassoPolygonPoints.add(gw.convertPixelsToWorldSpaceUnits(p)); } selectedStrokes.clear(); for (Stroke s : drawing.strokes) { if (s.isContainedInLassoPolygon(lassoPolygonPoints)) selectedStrokes.add(s); } } else { // complete a rectangle selection AlignedRectangle2D selectedRectangle = new AlignedRectangle2D( gw.convertPixelsToWorldSpaceUnits(cursor.getFirstPosition()), gw.convertPixelsToWorldSpaceUnits(cursor.getCurrentPosition())); selectedStrokes.clear(); for (Stroke s : drawing.strokes) { if (s.isContainedInRectangle(selectedRectangle)) selectedStrokes.add(s); } } cursorContainer.removeCursorByIndex(cursorIndex); } else { // drag event; just update the cursor with the new position cursorIndex = cursorContainer.updateCursorById(id, x, y); } } else if (cursor.type == MyCursor.TYPE_DIRECT_MANIPULATION) { if (type == MultitouchFramework.TOUCH_EVENT_UP) { // up event cursorContainer.removeCursorByIndex(cursorIndex); } else { // drag event cursorIndex = cursorContainer.updateCursorById(id, x, y); if (cursorContainer.getNumCursorsOfGivenType(MyCursor.TYPE_DIRECT_MANIPULATION) == 2) { MyCursor cursor0 = cursorContainer.getCursorByType(MyCursor.TYPE_DIRECT_MANIPULATION, 0); MyCursor cursor1 = cursorContainer.getCursorByType(MyCursor.TYPE_DIRECT_MANIPULATION, 1); // convert cursor positions to world space Point2D cursor0_currentPosition_worldSpace = gw.convertPixelsToWorldSpaceUnits(cursor0.getCurrentPosition()); Point2D cursor1_currentPosition_worldSpace = gw.convertPixelsToWorldSpaceUnits(cursor1.getCurrentPosition()); Point2D cursor0_previousPosition_worldSpace = gw.convertPixelsToWorldSpaceUnits(cursor0.getPreviousPosition()); Point2D cursor1_previousPosition_worldSpace = gw.convertPixelsToWorldSpaceUnits(cursor1.getPreviousPosition()); for (Stroke s : selectedStrokes) { Point2DUtil.transformPointsBasedOnDisplacementOfTwoPoints( s.getPoints(), id == cursor0.id ? cursor0_previousPosition_worldSpace : cursor0_currentPosition_worldSpace, id == cursor1.id ? cursor1_previousPosition_worldSpace : cursor1_currentPosition_worldSpace, cursor0_currentPosition_worldSpace, cursor1_currentPosition_worldSpace); s.markBoundingRectangleDirty(); } drawing.markBoundingRectangleDirty(); } else if (cursorContainer.getNumCursorsOfGivenType(MyCursor.TYPE_DIRECT_MANIPULATION) == 1) { // convert cursor positions to world space Point2D cursor_currentPosition_worldSpace = gw.convertPixelsToWorldSpaceUnits(cursor.getCurrentPosition()); Point2D cursor_previousPosition_worldSpace = gw.convertPixelsToWorldSpaceUnits(cursor.getPreviousPosition()); // compute translation vector Vector2D translationVector = Point2D.diff(cursor_currentPosition_worldSpace, cursor_previousPosition_worldSpace); // apply the translation to the selected strokes for (Stroke s : selectedStrokes) { for (Point2D p : s.getPoints()) { p.copy(Point2D.sum(p, translationVector)); } s.markBoundingRectangleDirty(); } drawing.markBoundingRectangleDirty(); } } } } return true; // request a redraw }