package cn.edu.chd.view;
import java.util.LinkedList;
import java.util.List;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;
import cn.edu.chd.domain.Tuyuan;
import cn.edu.chd.domain.PaintStyle;
import cn.edu.chd.graphics.Bezier;
import cn.edu.chd.graphics.BrokenLine;
import cn.edu.chd.graphics.BrokenLine.OnTurnListener;
import cn.edu.chd.graphics.Free;
import cn.edu.chd.graphics.Line;
import cn.edu.chd.graphics.Oval;
import cn.edu.chd.graphics.Polygn;
import cn.edu.chd.graphics.Rectangle;
import cn.edu.chd.values.ApplicationValues;
/**
* @author Rowand jj
*
*�ṩ��ͼ������view
*
*����Ϊ��ͼ�ĺ�����
*
*/
public class YiDrawView extends ImageView implements OnGestureListener
{
private static final String TAG = "YiDrawView";
/**
* ����
*/
private Canvas mCanvas = null;
/**
* ��ǰͼԪ
*/
private Tuyuan mCurrentPaint = null;
/**
* ������ɫ
*/
private int mPenColor = ApplicationValues.PaintSettings.PENCOLOR_DEFAULT;;
/**
* ���ʴ�С
*/
private int mPenSize = ApplicationValues.PaintSettings.PENSIZE_DEFAULT;
/**
* ��������
*/
private int mPenAlpha = ApplicationValues.PaintSettings.PEN_ALPHA_DEFAULT;
/**
* ��ͼ�ı�������������Դ���Դ�bitmap�Dz��ɱ��,���Ҫ�������bitmap���봴���丱������tempBitmap
*/
private Bitmap mBitmap = null;
/**
* mBitmap�ĸ���������ֱ�Ӳ���
*/
private Bitmap tempBitmap = null;
/**
* ����ondraw�������bitmap
*/
private Paint mPaint = null;
/**
* ����ģʽ(ֱ�ߣ�������...)
*/
private int mPaintMode = -1;
/**
* ������
*/
private int mBitmapWidth = 0;
/**
* ������
*/
private int mBitmapHeight = 0;
/**
* �ṩredo,undo�Ȳ���
*/
private PaintStack mPaintStack = null;
/**
*��ͼ�Ƿ��һ�α�����
*/
private boolean isFirstCreated = true;
private boolean isTouchUp = false;
/**
* ������ʽ
*/
private int paintStyleValue = -1;
/**
* �Ƿ���
* ��������ʱ�����������۵�
*/
private boolean isShaked = false;
/**
* ����ʶ����
*/
private GestureDetector mGestureDetector = null;
/**
* ��ǰ��ѡ�е�ͼԪ
*/
private Tuyuan checkedElement = null;
/**
* �Ƿ����϶�ͼԪ״̬
*/
private boolean shouldDrag = false;
/**
* ����ͼԪ�����
*/
private float srcX,srcY;
/**
* ��Ƥģʽ
*/
private boolean eraserMode = false;
/**
* ���ģʽ
*/
private boolean fillMode = false;
private Tuyuan copedTuyuan = null;
private boolean pasteFlag = false;
/**
* ����ģʽ
*/
private boolean zoomMode = false;
/**
* ��תģʽ
*/
private boolean rotateMode = false;
/* ������ */
public YiDrawView(Context context, AttributeSet attrs)
{
super(context, attrs);
mCanvas = new Canvas();
mPaint = new Paint(Paint.DITHER_FLAG);
//����Ĭ�ϻ�����ʽ
paintStyleValue = ApplicationValues.PaintStyle.MODE_PLAIN_PEN;
//Ĭ��Ϊ�����ֻ�ͼԪ
setCurrentTuyuanType(ApplicationValues.TuyuanStyle.STYLE_FREE);
mPaintStack = new PaintStack(this);
mGestureDetector = new GestureDetector(context,this);
}
/**
* �ⲿ���û����ӿڣ���ص���
*/
public void setImageBitmap(Bitmap image)
{
this.mBitmap = image;
postInvalidate();
}
@Override
public void setLayoutParams(LayoutParams params)
{
super.setLayoutParams(params);
postInvalidate();
}
/**
* ��dispatchTouchEvent�����иı�touch�¼��ķַ�˳��������ʶ�����Ʋ�����
* ������Ʋ����ɹ��ˣ�ʹ��һ��ͼԪ�����϶�װ̬������ô��ֹ��ͼ������������move
* �¼���ͼԪ����ƽ�Ƶȱ任,�������ִ�л�ͼ����.
* */
@Override
public boolean dispatchTouchEvent(MotionEvent event)
{
mGestureDetector.onTouchEvent(event);//��ʶ������
if(eraserMode)//�������Ƥģʽ,�����ػ�ͼ����
{
return false;
}
if(shouldDrag)//��������϶�״̬�����ֹ��ͼ����
{
switch (event.getAction())
{
case MotionEvent.ACTION_MOVE:
deleteTuyuan(checkedElement);//ɾ��ԭ��ͼԪ
checkedElement.translate(event.getX()-srcX,event.getY()-srcY);//ƽ��
srcX = event.getX();
srcY = event.getY();
invalidate();
Log.i(TAG,"=================MOVE");
break;
case MotionEvent.ACTION_UP:
if(shouldDrag)
{
shouldDrag = false;//ÿ��up������϶�״̬
checkedElement.draw(mCanvas);//��������λ���ϻ���ͼԪ
mPaintStack.push(checkedElement);//����ջ��
invalidate();
}
}
return false;
}
return super.dispatchTouchEvent(event);
}
/**
* ɾ����ѡ��ͼԪ
*/
private void deleteTuyuan(Tuyuan c)
{
mPaintStack.deleteCommand(c);
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
return handleTouchForDraw(event);
}
/**
* �����ͼ���̵�touch�¼�
*/
private boolean handleTouchForDraw(MotionEvent event)
{
Log.i(TAG, "handleTouchForDraw");
float x = event.getX();
float y = event.getY();
isTouchUp = false;
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
srcX = event.getX();
srcY = event.getY();
mCurrentPaint = createNewTuyuan(mPaintMode);
mCurrentPaint.touchDown(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
mCurrentPaint.touchMove(x, y);
isShaked = false;
invalidate();
break;
case MotionEvent.ACTION_UP:
mCurrentPaint.touchUp(x, y);
mCurrentPaint.draw(mCanvas);//���Ƶ�bitmap��
if(mCurrentPaint.hasDraw())
{
mPaintStack.push(mCurrentPaint);//����ջ��
}
invalidate();
isTouchUp = true;
if(Math.abs(srcX-x)>=2 && Math.abs(srcY-y)>=2)
{
checkedElement = mCurrentPaint;//��ǰ���ڻ��Ƶ�ͼԪĬ�ϱ�ѡ��
}
break;
}
return true;
}
@Override
public boolean onDown(MotionEvent e)
{
Log.i(TAG,"onDown");
/**
* ���ư����¼�
* */
//��ȡ��ָ��ǰ����λ��
float x = e.getX();
float y = e.getY();
//��鵱ǰλ���Ƿ���ͼԪ�ܹ���ѡ��
Tuyuan c = mPaintStack.check(x, y);
if(c != null)//ѡ����ͼԪ
{
checkedElement = c;
//�����ǰ����Ƥģʽ����ɾ����ѡ��ͼԪ
if(eraserMode)
{
deleteTuyuan(c);
checkedElement = null;
}
//�����ǰ�����ģʽ�������ѡ��ͼԪ
if(fillMode)
{
checkedElement.fill(mPenColor);
}
}else
{
checkedElement = null;
}
invalidate();//�ػ�
return false;
}
@Override
public void onShowPress(MotionEvent e)
{
}
@Override
public boolean onSingleTapUp(MotionEvent e)
{
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY)
{
return false;
}
@Override
public void onLongPress(MotionEvent e)
{
shouldDrag(e);//�ж��Ƿ���Ҫ�л�Ϊ�϶�״̬
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY)
{
return false;
}
/**
* �ж��Ƿ���Ҫ�л�Ϊ�϶�״̬
*/
private void shouldDrag(MotionEvent e)
{
//��ȡ��ָ��ǰ����λ��
float x = e.getX();
float y = e.getY();
//��鵱ǰλ���Ƿ���ͼԪ�ܹ���ѡ��
Tuyuan c = mPaintStack.check(x, y);
//�����ǰ�����ͼԪ������֮ǰѡ�е�ͼԪ��ô��ͼԪ��Ϊ�϶�״̬
if(c != null && checkedElement != null && c.equals(checkedElement))
{
shouldDrag = true;
}else
{
shouldDrag = false;
}
invalidate();
}
/**
* ��ͼ�ػ淽��
* */
@Override
protected void onDraw(Canvas canvas)
{
//TODO
if(tempBitmap != null)
{
super.onDraw(canvas);
canvas.drawBitmap(tempBitmap, 0, 0, mPaint);//����֮ǰ��·��
if(!isTouchUp)
{
mCurrentPaint.draw(canvas);//��view�ϻ��Ƶ�ǰ·��
}
}
//ѡ���ͼԪ��Ϊ��
if(checkedElement != null)
{
if(shouldDrag)//�϶�״̬����Ҫ������ʾ
{
checkedElement.setHighLight(canvas);
checkedElement.draw(mCanvas);
// checkedElement.draw(canvas);
}else if(fillMode)//���ģʽ
{
checkedElement.draw(mCanvas);
// checkedElement.draw(canvas);
}else if(zoomMode)//ͼԪ����ģʽ
{
checkedElement.checked(canvas);
checkedElement.draw(mCanvas);
// checkedElement.draw(canvas);
zoomMode = false;
}else if(rotateMode)//ͼԪ��תģʽ
{
checkedElement.checked(canvas);
checkedElement.draw(mCanvas);
// checkedElement.draw(canvas);
rotateMode = false;
}
else//����ֻ��ѡ��״̬
{
checkedElement.checked(canvas);
}
}
//�������Ƿ������ݣ���������������
if(pasteFlag && copedTuyuan!=null)
{
Log.i(TAG,"=======ONDRAW_PASTE=======");
copedTuyuan.draw(mCanvas);
copedTuyuan = null;
pasteFlag = false;
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
mBitmapWidth = w;
mBitmapHeight = h;
if(isFirstCreated)
{
createCanvasBitmap(mBitmapWidth, mBitmapHeight);
isFirstCreated = false;
}
}
/**
* @param type ͼԪ����
* @return ͼԪ
*
* �����µ�ͼԪģʽ
*/
public Tuyuan createNewTuyuan(int type)
{
Tuyuan tool = null;
switch (type)
{
case ApplicationValues.TuyuanStyle.STYLE_FREE://�����ֻ�
tool = new Free(mPenSize, mPenColor,mPenAlpha,new PaintStyle(paintStyleValue));
break;
case ApplicationValues.TuyuanStyle.STYLE_LINE://ֱ��
tool = new Line(mPenSize, mPenColor,mPenAlpha,new PaintStyle(paintStyleValue));
break;
case ApplicationValues.TuyuanStyle.STYLE_RECT://����
tool = new Rectangle(mPenSize, mPenColor, mPenAlpha,new PaintStyle(paintStyleValue));
break;
case ApplicationValues.TuyuanStyle.STYLE_OVAL://��Բ
tool = new Oval(mPenSize, mPenColor,mPenAlpha, new PaintStyle(paintStyleValue));
break;
case ApplicationValues.TuyuanStyle.STYLE_BEZIER://�����������
tool = new Bezier(mPenSize, mPenColor, mPenAlpha, new PaintStyle(paintStyleValue));
break;
case ApplicationValues.TuyuanStyle.STYLE_BROKEN_LINE://����
tool = new BrokenLine(mPenSize,mPenColor,mPenAlpha, new PaintStyle(paintStyleValue));
BrokenLine temp = (BrokenLine) tool;
//ע�ᡰ����ת�۵㡱�¼��������������ζ�ʱ���������۵�
temp.setOnTurnListener(new OnTurnListener()
{
@Override
public boolean onTurn()
{
return isShaked;
}
});
break;
case ApplicationValues.TuyuanStyle.STYLE_POLYGN://�����
tool = new Polygn(mPenSize, mPenColor, mPenAlpha, new PaintStyle(paintStyleValue));
((Polygn)tool).setOnTurnListener(new Polygn.OnTurnListener()
{
@Override
public boolean onTurn()
{
return isShaked;
}
});
break;
//TODO �������ģʽ
}
mPaintMode = type;
return tool;
}
public boolean isShaked()
{
return isShaked;
}
public void setShaked(boolean isShaked)
{
this.isShaked = isShaked;
}
/**
* �����Ƿ�Ϊ��Ƥģʽ
*/
public void setEraserMode(boolean eraserMode)
{
this.eraserMode = eraserMode;
if(fillMode)
{
fillMode = false;
}
}
public boolean getEraserMode()
{
return this.eraserMode;
}
public boolean isFillMode()
{
return fillMode;
}
/**
* �����Ƿ�Ϊ���ģʽ
*/
public void setFillMode(boolean fillMode)
{
this.fillMode = fillMode;
if(eraserMode)
{
eraserMode = false;
}
}
/**
*����ͼԪ
*/
public boolean copyTuyuan()
{
if(checkedElement != null)
{
Log.i(TAG,"copedTuyuan");
copedTuyuan = checkedElement.copy();
return true;
}else
{
return false;
}
}
/**
* ճ��ͼԪ
*/
public boolean pasteTuyuan()
{
if(mPaintStack != null && copedTuyuan != null)
{
Log.i(TAG,"PASTE Tuyuan......");
mPaintStack.push(copedTuyuan);
invalidate();
pasteFlag = true;
return true;
}
return false;
}
/**
* ͼԪ�Ŵ�
*/
public void enlarge()
{
if(checkedElement != null)
{
zoomMode = true;
mPaintStack.deleteCommand(checkedElement);
checkedElement.scale(1.1f, 1.1f);
mPaintStack.push(checkedElement);
invalidate();
}
}
/**
* ͼԪ��С
*/
public void shrink()
{
if(checkedElement != null)
{
zoomMode = true;
mPaintStack.deleteCommand(checkedElement);
checkedElement.scale(0.9f, 0.9f);
mPaintStack.push(checkedElement);
invalidate();
}
}
/**
* ������ת
*/
public void rotateLeft()
{
if(checkedElement != null)
{
rotateMode = true;
mPaintStack.deleteCommand(checkedElement);
checkedElement.rotate(30);
mPaintStack.push(checkedElement);
invalidate();
}
}
/**
* ������ת
*/
public void rotateRight()
{
if(checkedElement != null)
{
rotateMode = true;
mPaintStack.deleteCommand(checkedElement);
checkedElement.rotate(-30);
mPaintStack.push(checkedElement);
invalidate();
}
}
/**
* ���û�����ʽ
*/
public void setPaintStyle(int paintType)
{
this.paintStyleValue = paintType;
}
/**
* ���û�����ɫ
*/
public void setPenColor(int penColor)
{
this.mPenColor = penColor;
}
/**
* ���û��ʴ�С
*/
public void setPenSize(int penSize)
{
this.mPenSize = penSize;
}
/**
* ���û�������
*/
public void setPenAlpha(int penAlpha)
{
this.mPenAlpha = penAlpha;
}
/**
* ���õ�ǰͼԪ��ʽ
* @param type
*/
public void setCurrentTuyuanType(int type)
{
mCurrentPaint = createNewTuyuan(type);
mPaintMode = type;
}
public int getPenAlpha()
{
return this.mPenAlpha;
}
public int getPenSize()
{
return this.mPenSize;
}
public int getPenColor()
{
return this.mPenColor;
}
public int getPaintStyle()
{
return this.paintStyleValue;
}
public int getTuyuanStyle()
{
return this.mPaintMode;
}
public int getCurrentTuyuanMode()
{
return mPaintMode;
}
/**
* ��������bitmap
*/
private void createCanvasBitmap(int w, int h)
{
tempBitmap = mBitmap.copy(Config.ARGB_8888,true);
mCanvas.setBitmap(tempBitmap);
}
/**
* undo
*/
public void undo()
{
checkedElement = null;
if(mPaintStack != null)
{
mPaintStack.undo();
}
}
/**
* redo
*/
public void redo()
{
if(mPaintStack != null)
{
mPaintStack.redo();
}
}
/**
* ��ջ���
*/
public void clearAll()
{
checkedElement = null;
shouldDrag = false;
if(mPaintStack != null)
{
mPaintStack.clear();
}
if(tempBitmap != null && !tempBitmap.isRecycled())
{
tempBitmap.recycle();
tempBitmap = null;
}
//���軭��
createCanvasBitmap(mBitmapWidth, mBitmapHeight);
invalidate();
}
/**
* �Ƿ����������
*/
public boolean hasData()
{
return !mPaintStack.undoStack.isEmpty();
}
/**
* ��ȡ�û��Ѿ����Ƶ�����
* @return
*/
public Bitmap getDrawData()
{
return tempBitmap;
}
//---------------------------------------------------------------------------
/**
* @author Rowand jj
*
*�ṩredo undo delete check���ܵ�ջ�ṹ
*/
public class PaintStack
{
private YiDrawView view = null;
/**
* undoջ
*/
private List<Tuyuan> undoStack = new LinkedList<Tuyuan>();
/**
* redoջ
*/
private List<Tuyuan> redoStack = new LinkedList<Tuyuan>();
/**
* ������
*/
public PaintStack(YiDrawView view)
{
this.view = view;
}
/**
* ����
*/
public void redo()
{
Canvas c = view.mCanvas;
if(redoStack != null && redoStack.size() > 0)
{
Tuyuan tool = redoStack.remove(redoStack.size() - 1);
undoStack.add(tool);
tool.draw(c);
}
view.invalidate();
}
/**
* ����
*/
public void undo()
{
if(view.tempBitmap != null && !view.tempBitmap.isRecycled())
{
view.tempBitmap.recycle();
view.tempBitmap = null;
}
view.createCanvasBitmap(view.mBitmapWidth,view.mBitmapHeight);
Canvas c = view.mCanvas;
if(undoStack != null && undoStack.size() > 0)
{
Tuyuan tool = undoStack.remove(undoStack.size() - 1);
redoStack.add(tool);
for(Tuyuan t : undoStack)
{
t.draw(c);
}
}
view.invalidate();
}
/**
* ��鵱ǰλ���Ƿ���ѡ��ͼԪ
*/
public Tuyuan check(float x,float y)
{
for(Tuyuan c : undoStack)
{
if(c.contains(x, y))
{
return c;
}
}
return null;
}
/**
* ɾ��һ��ͼԪ
*/
public void deleteCommand(Tuyuan command)
{
if(view.tempBitmap != null && !view.tempBitmap.isRecycled())
{
view.tempBitmap.recycle();
view.tempBitmap = null;
}
view.createCanvasBitmap(view.mBitmapWidth,view.mBitmapHeight);
Canvas c = view.mCanvas;
if(undoStack != null && undoStack.size() > 0)
{
if(undoStack.remove(command))
{
redoStack.add(command);
}
for(Tuyuan t : undoStack)
{
t.draw(c);
}
}
view.invalidate();
}
/**
* ���û�����"ѹջ"
*/
public void push(Tuyuan tool)
{
if(undoStack != null)
{
undoStack.add(tool);
}
}
/**
* ���ջ
*/
public void clear()
{
if(undoStack != null && redoStack != null)
{
undoStack.clear();
redoStack.clear();
}
}
}
}