/*
* Catroid: An on-device graphical programming language for Android devices
* Copyright (C) 2010-2011 The Catroid Team
* (<http://code.google.com/p/catroid/wiki/Credits>)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* An additional term exception under section 7 of the GNU Affero
* General Public License, version 3, is available at
* http://www.catroid.org/catroid_license_additional_term
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright (C) 2010 Draggable and Droppable ListView Project
*
*/
package at.tugraz.ist.catroid.ui.dragndrop;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.View.OnLongClickListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.ListView;
import at.tugraz.ist.catroid.R;
import at.tugraz.ist.catroid.common.Values;
import at.tugraz.ist.catroid.utils.Utils;
public class DragAndDropListView extends ListView implements OnLongClickListener {
private static final int SCROLL_SPEED = 25;
private static final int DRAG_BACKGROUND_COLOR = Color.TRANSPARENT;
private int maximumDragViewHeight;
private int previousItemPosition;
private int touchPointY;
private int upperScrollBound;
private int lowerScrollBound;
private int upperDragBound;
private int lowerDragBound;
private ImageView dragView;
private int position;
private boolean newView;
private ImageView trashView;
private int originalTrashWidth;
private int originalTrashHeight;
private int touchedListPosition;
private DragAndDropListener dragAndDropListener;
public DragAndDropListView(Context context) {
super(context);
}
public DragAndDropListView(Context context, AttributeSet attributes) {
super(context, attributes);
}
public DragAndDropListView(Context context, AttributeSet attributes, int defStyle) {
super(context, attributes, defStyle);
}
public void setTrashView(ImageView trashView) {
this.trashView = trashView;
ViewGroup.LayoutParams parameters = trashView.getLayoutParams();
originalTrashWidth = parameters.width;
originalTrashHeight = parameters.height;
}
public void setOnDragAndDropListener(DragAndDropListener listener) {
dragAndDropListener = listener;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (dragAndDropListener != null && dragView != null) {
onTouchEvent(event);
}
return super.onInterceptTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
if (y < 0) {
y = 0;
}
if (y > getHeight()) {
y = getHeight();
}
int itemPosition = pointToPosition(x, y);
if (touchedListPosition != itemPosition) {
touchedListPosition = itemPosition;
if (dragAndDropListener != null) {
dragAndDropListener.setTouchedScript(touchedListPosition);
}
}
if (dragAndDropListener != null && dragView != null) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
stopDragging();
ViewGroup.LayoutParams layoutParamemters = trashView.getLayoutParams();
layoutParamemters.width = originalTrashWidth;
layoutParamemters.height = originalTrashHeight;
trashView.setLayoutParams(layoutParamemters);
trashView.setVisibility(View.GONE);
if (x > getWidth() * 3 / 4) {
dragAndDropListener.remove(itemPosition);
} else {
// if (itemPosition < 0) {
// Log.d("TESTING", "Itemposition: " + itemPosition);
// itemPosition = ProjectManager.getInstance().getCurrentSprite().getNumberOfScripts() - 1;
// Log.d("TESTING", "Itemposition: " + itemPosition);
// }
dragAndDropListener.drop(itemPosition);
}
break;
case MotionEvent.ACTION_MOVE:
if (y > lowerScrollBound) {
smoothScrollBy(SCROLL_SPEED, 0);
} else if (y < upperScrollBound) {
smoothScrollBy(-SCROLL_SPEED, 0);
}
dragView(x, (int) event.getRawY());
if (itemPosition != INVALID_POSITION) {
int index = previousItemPosition - getFirstVisiblePosition();
if (index > 0) {
View upperChild = getChildAt(index - 1);
upperDragBound = upperChild.getBottom() - upperChild.getHeight() / 2;
} else {
upperDragBound = 0;
}
if (index < getChildCount() - 1) {
View lowerChild = getChildAt(index + 1);
lowerDragBound = lowerChild.getTop() + lowerChild.getHeight() / 2;
} else {
lowerDragBound = getHeight();
}
if ((y > lowerDragBound || y < upperDragBound)) {
dragAndDropListener.drag(previousItemPosition, itemPosition);
previousItemPosition = itemPosition;
}
}
break;
}
return true;
}
return super.onTouchEvent(event);
}
@Override
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
super.onSizeChanged(width, height, oldWidth, oldHeight);
upperScrollBound = height / 6;
lowerScrollBound = height * 5 / 6;
maximumDragViewHeight = height / 3;
}
public boolean onLongClick(View view) {
int itemPosition = -1;
int[] location = new int[2];
if (newView) {
itemPosition = this.position;
(getChildAt(getChildCount() - 1)).getLocationOnScreen(location);
touchPointY = location[1] + (getChildAt(getChildCount() - 1)).getHeight();
newView = false;
} else {
itemPosition = pointToPosition(view.getLeft(), view.getTop());
int visiblePosition = itemPosition - getFirstVisiblePosition();
(getChildAt(visiblePosition)).getLocationOnScreen(location);
touchPointY = location[1] + (getChildAt(visiblePosition)).getHeight() / 2;
}
boolean drawingCacheEnabled = view.isDrawingCacheEnabled();
view.setDrawingCacheEnabled(true);
view.measure(MeasureSpec.makeMeasureSpec(Values.SCREEN_WIDTH, MeasureSpec.EXACTLY), MeasureSpec
.makeMeasureSpec(Utils.getPhysicalPixels(400, getContext()), MeasureSpec.AT_MOST));
view.layout(0, 0, Values.SCREEN_WIDTH, view.getMeasuredHeight());
view.buildDrawingCache(true);
if (view.getDrawingCache() == null) {
return false;
}
Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());
view.setDrawingCacheEnabled(drawingCacheEnabled);
startDragging(bitmap, touchPointY);
dragAndDropListener.drag(itemPosition, itemPosition);
trashView.setVisibility(View.VISIBLE);
Animation animation = AnimationUtils.loadAnimation(getContext(), R.anim.trash_in);
trashView.startAnimation(animation);
previousItemPosition = itemPosition;
return true;
}
private void startDragging(Bitmap bitmap, int y) {
stopDragging();
if (bitmap.getHeight() > maximumDragViewHeight) {
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), maximumDragViewHeight);
}
ImageView imageView = new ImageView(getContext());
imageView.setBackgroundColor(DRAG_BACKGROUND_COLOR);
imageView.setImageBitmap(bitmap);
WindowManager.LayoutParams dragViewParameters = createLayoutParameters();
dragViewParameters.y = y - bitmap.getHeight() / 2;
WindowManager windowManager = getWindowManager();
windowManager.addView(imageView, dragViewParameters);
dragView = imageView;
}
private void dragView(int x, int y) {
ViewGroup.LayoutParams trashViewParameters = trashView.getLayoutParams();
WindowManager.LayoutParams dragViewParameters = (WindowManager.LayoutParams) dragView.getLayoutParams();
if (x > 100 && x < getWidth() - 100) {
float alpha = ((float) (getWidth() - x)) / (getWidth() - 100);
float rate = 1 - alpha;
trashViewParameters.width = (int) (originalTrashWidth * (1 + rate));
trashViewParameters.height = (int) (originalTrashHeight * (1 + rate));
trashView.setLayoutParams(trashViewParameters);
dragViewParameters.alpha = alpha;
dragViewParameters.width = getWidth() - trashViewParameters.width + 2;
}
dragViewParameters.y = y - dragView.getHeight() / 2;
WindowManager windowManager = getWindowManager();
windowManager.updateViewLayout(dragView, dragViewParameters);
}
private void stopDragging() {
if (dragView != null) {
dragView.setVisibility(GONE);
WindowManager windowManager = getWindowManager();
windowManager.removeView(dragView);
dragView.setImageDrawable(null);
dragView = null;
}
}
private WindowManager.LayoutParams createLayoutParameters() {
WindowManager.LayoutParams windowParameters = new WindowManager.LayoutParams();
windowParameters.gravity = Gravity.TOP | Gravity.LEFT;
windowParameters.height = WindowManager.LayoutParams.WRAP_CONTENT;
windowParameters.width = getWidth() - originalTrashWidth + 2;
windowParameters.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
windowParameters.format = PixelFormat.TRANSLUCENT;
return windowParameters;
}
private WindowManager getWindowManager() {
return (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
}
public int getTouchedListPosition() {
return touchedListPosition;
}
public void setInsertedBrick(int pos) {
this.position = pos;
newView = true;
}
}