protected PointF getRelativePositionToSuperobject() { float x = centerX; float y = centerY; if (this.isCustomPivotUsed()) { if (this.angle == 0.0f) { x += this.getPivotXRelativeToCenter() * this.scaleX; y += this.getPivotYRelativeToCenter() * this.scaleY; } else { PointF pivotPosition = this.getPivotPointPositionConsideringScalingAndAngle(); x += pivotPosition.x; y += pivotPosition.y; } } float superAngle = superDrawable.angle; float angleToCenter = (float) Math.atan2(y - superDrawable.centerY, x - superDrawable.centerX); float angle = superAngle - angleToCenter; float radius = (float) Math.sqrt( Math.pow(Math.abs(x - superDrawable.centerX), 2) + Math.pow(Math.abs(y - superDrawable.centerY), 2)) / superDrawable.scaleX; float newX = (float) (radius * Math.cos(angle) + superDrawable.getWidth() / 2); float newY = (float) (radius * Math.sin(angle * -1) + superDrawable.getHeight() / 2); return new PointF(newX, newY); }
/** Called by activity's onResume() method to load the images */ public void load() { if (firstLoad) { getMetrics(); firstLoad = false; } for (MultiTouchDrawable sub : subDrawables) { sub.load(); } // float cx, cy, sx, sy; // if (firstLoad) { // cx = 0; // cy = 0; // // float sc = 1; // sx = sy = sc; // firstLoad = false; // } else { // // Reuse position and scale information if it is available // // FIXME this doesn't actually work because the whole activity is // // torn down and re-created on rotate // cx = this.centerX; // cy = this.centerY; // sx = this.scaleX; // sy = this.scaleY; // } // setPos(cx, cy, sx, sy, 0.0f, FLAG_FORCEALL, false); }
/** * callback method for onTouch events * * @param pointinfo info about the touch event * @return * <p><b>true</b> if the touch event is handled by this event<br> * <b>false</b> if this touch event is not for this element * <p>This is intended, that a subobject can check, if it should handle a click or so, or if * the event should be sent to the underlying object. */ public boolean onTouch(PointInfo pointinfo) { boolean handleEvent = false; // first ask our subobjects to handle it, otherwise let us handle it for (int i = subDrawables.size() - 1; i >= 0 && !handleEvent; i--) { MultiTouchDrawable sub = subDrawables.get(i); if (sub.containsPoint(pointinfo.getX(), pointinfo.getY())) { handleEvent = sub.onTouch(pointinfo); } } // Logger.d("touch action: "+this.getClass().getSimpleName()+" " + // pointinfo.getAction()+ // " 0x"+Integer.toHexString(pointinfo.getAction())); // it's hard to find MOTION_UP events, because if the finger does not // stay exactly on the correct position, // this will change to dragging and we wont't get the drag end as // MOTION_UP if (!handleEvent && pointinfo.isMultiTouch() == false && pointinfo.getNumTouchPoints() == 1 && pointinfo.getAction() == MotionEvent.ACTION_DOWN) { handleEvent = this.onSingleTouch(pointinfo); } return handleEvent; }
/** hide all open popups */ public void hidePopups() { if (this instanceof Popup) { ((Popup) this).setActive(false); } for (MultiTouchDrawable d : subDrawables) { d.hidePopups(); } }
public MultiTouchDrawable getDraggableObjectAtPoint(PointInfo pt) { float x = pt.getX(), y = pt.getY(); int n = subDrawables.size(); for (int i = n - 1; i >= 0; i--) { MultiTouchDrawable im = subDrawables.get(i); if (im.isDragable() && im.containsPoint(x, y)) { return im.getDraggableObjectAtPoint(pt); } } if (this.containsPoint(pt.getX(), pt.getY())) { return this; } return null; }
/** * set relative position to super object if set * * @param xPos relative x position * @param yPos relative y position */ public void setRelativePosition(float relX, float relY) { this.relX = relX; this.relY = relY; if (superDrawable != null) { superDrawable.recalculatePositions(); } onRelativePositionUpdate(); }
/** * tries to bring the current element to the front. * * @return true, if this element could be brought to front */ public boolean bringToFront() { if (superDrawable != null) { superDrawable.bringSubDrawableToFront(this); return true; } else { Logger.d("we can't bring ourselfs to front, because we are not attached to a super drawable"); } return false; }
/** * constructor with superDrawable * * @param context * @param superDrawable super Drawable Object */ public MultiTouchDrawable(Context context, MultiTouchDrawable superDrawable) { id = counter++; this.ctx = context; this.superDrawable = superDrawable; this.resources = context.getResources(); subDrawables = new ArrayList<MultiTouchDrawable>(); superDrawable.addSubDrawable(this); }
protected PointF getAbsolutePositionOfSubobject(MultiTouchDrawable subobject) { float xBeforeRotate = this.minX + subobject.getRelativeX() * scaleX; float yBeforeRotate = this.minY + subobject.getRelativeY() * scaleY; float radius = (float) Math.sqrt( Math.pow(Math.abs(centerX - xBeforeRotate), 2) + Math.pow(Math.abs(centerY - yBeforeRotate), 2)); float angleBeforeRotate = (float) Math.atan2(yBeforeRotate - centerY, xBeforeRotate - centerX); float newAngle = angle + angleBeforeRotate; float newY = (float) (centerY + radius * Math.sin(newAngle)); float newX = (float) (centerX + radius * Math.cos(newAngle)); // Move the drawable according to it's pivot point if one is set if (subobject.isCustomPivotUsed()) { if (subobject.angle == 0.0f) { newX -= subobject.getPivotXRelativeToCenter() * subobject.scaleX; newY -= subobject.getPivotYRelativeToCenter() * subobject.scaleY; } else { PointF pivotPosition = subobject.getPivotPointPositionConsideringScalingAndAngle(); newX -= pivotPosition.x; newY -= pivotPosition.y; } } return new PointF(newX, newY); }
/** Return whether or not the given screen coords are inside this image */ public boolean containsPoint(float scrnX, float scrnY) { // If this is a subdrawable, then don't let the controller think this is // the item to be dragged. Otherwise non-draggable subdrawables will not // allow to drag the superdrawable when the user's finger is exactly on // them. FIXME: Is this the right place to do this? // if (this.hasSuperDrawable()) // return false; // else // FIXME: need to correctly account for image rotation boolean inside = (scrnX >= minX && scrnX <= maxX && scrnY >= minY && scrnY <= maxY); if (inside) return true; Iterator<MultiTouchDrawable> it = this.subDrawables.iterator(); while (it.hasNext()) { MultiTouchDrawable sub = it.next(); if (sub.containsPoint(scrnX, scrnY)) { return true; } } return false; }
public void addSubDrawable(MultiTouchDrawable subObject) { subDrawables.add(subObject); subObject.refresher = this.refresher; this.setPos(centerX, centerY, scaleX, scaleY, angle, false); }
/** Set the position and scale of an image in screen coordinates */ protected boolean setPos( float centerX, float centerY, float scaleX, float scaleY, float angle, int flags, boolean isDraggedOrPinched) { // Reset the scale if the object is not scalable (otherwise the ws and // hs calculations below are not 100% accurate and will result in a // slight but noticable scaling of non-scalable objects if (!isScalable()) { scaleX = 1.0f; scaleY = 1.0f; } // Reset the angle if the drawable is not rotatable (for the same reason // as above) if (!isRotatable()) { this.setAngle(0.0f); } float ws = (width / 2) * scaleX, hs = (height / 2) * scaleY; float newMinX = centerX - ws, newMinY = centerY - hs, newMaxX = centerX + ws, newMaxY = centerY + hs; float scaleXChange = 1.0f, scaleYChange = 1.0f, angleChange = 0.0f; // Min and max values need to be set when item is dragged or scaled if ((flags & FLAG_FORCEXY) != 0 || this.isDragable() || (flags & FLAG_FORCESCALE) != 0 || this.isScalable()) { this.minX = newMinX; this.minY = newMinY; this.maxX = newMaxX; this.maxY = newMaxY; } if ((flags & FLAG_FORCEXY) != 0 || this.isDragable()) { this.centerX = centerX; this.centerY = centerY; } if ((flags & FLAG_FORCESCALE) != 0 || this.isScalable()) { scaleXChange = scaleX / this.scaleX; scaleYChange = scaleY / this.scaleY; this.setScale(scaleX, scaleY); } if ((flags & FLAG_FORCEROTATE) != 0 || this.isRotatable()) { angleChange = angle - this.angle; // this.angle = angle; this.setAngle(angle); } if (isDraggedOrPinched && this.hasSuperDrawable()) { PointF relativePosition = getRelativePositionToSuperobject(); // we do not want to use setRelativePosition, because this will // overwrite the angle // this.setRelativePosition(relativePosition.x, relativePosition.y); this.setRelativePosition(relativePosition); } // Iterate through the subobjects and change their position for (MultiTouchDrawable subobject : subDrawables) { PointF absolutePosition = this.getAbsolutePositionOfSubobject(subobject); subobject.setPos( absolutePosition.x, absolutePosition.y, subobject.scaleX * scaleXChange, subobject.scaleY * scaleYChange, subobject.angle + angleChange, FLAG_FORCEXY, false); } return true; }
/** Called by activity's onPause() method to free memory used for loading the images */ public void unload() { for (MultiTouchDrawable sub : subDrawables) { sub.unload(); } }