/*
============================================================================
Author : Dmitry Soldatenkov
Version : 1.5
Copyright : Copyright (C) 2010 Rhomobile. All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
============================================================================
*/
package com.rhomobile.rhodes.signature;
import java.util.Vector;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.PointF;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.MotionEvent;
import java.io.Serializable;
import java.io.IOException;
import com.rhomobile.rhodes.Logger;
class SignatureView extends SurfaceView implements SurfaceHolder.Callback {
private class PointSequence {
public Vector mPoints = new Vector();
}
public static String mStateID = "SignatureViewState";
public class SignatureViewState extends Object implements Serializable {
public Vector mSequences;
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
int s;
int p;
out.writeInt(mSequences.size());
for (s = 0; s < mSequences.size(); s++) {
PointSequence ps = mSequences.elementAt(s);
out.writeInt(ps.mPoints.size());
for (p = 0; p < ps.mPoints.size(); p++) {
PointF cur = ps.mPoints.elementAt(p);
out.writeFloat(cur.x);
out.writeFloat(cur.y);
}
}
}
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
int seq_count = in.readInt();
int s;
int p;
mSequences = new Vector();
for (s = 0; s < seq_count; s++) {
int point_count = in.readInt();
PointSequence ps = new PointSequence();
for (p = 0; p < point_count; p++) {
PointF cur = new PointF();
cur.x = in.readFloat();
cur.y = in.readFloat();
ps.mPoints.add(cur);
}
mSequences.add(ps);
}
}
}
private Vector mSequences = new Vector();
private PointSequence mCurrentSequence = new PointSequence();
private static final String TAG = "SignatureView";
Bitmap mBitmap;
Canvas mCanvas;
private float mX;
private float mY;
//private Path mCurrentPath;
//private Path mGlobalPath;
private Paint mPaint;
public void doClear() {
// clear paths
mSequences.clear();
doFullRedraw();
}
public void onRestoreInstanceState(Bundle savedInstanceState) {
SignatureViewState s = (SignatureViewState)savedInstanceState.getSerializable(mStateID);
mSequences = s.mSequences;
}
public void onSaveInstanceState(Bundle outState) {
mSequences.add(mCurrentSequence);
mCurrentSequence = new PointSequence();
SignatureViewState s = new SignatureViewState();
s.mSequences = mSequences;
outState.putSerializable(mStateID, s);
}
private void doFullRedraw() {
Paint paint = new Paint();
paint.setAntiAlias(false);
paint.setARGB(255, 255, 255, 255);
mCanvas.drawRect(0, 0, mCanvas.getWidth(), mCanvas.getHeight(), paint);
// draw path
int s;
int p;
for (s = 0; s < mSequences.size(); s++) {
PointSequence ps = mSequences.elementAt(s);
if ((ps != null) && (ps.mPoints != null)) {
for (p = 1; p < ps.mPoints.size(); p++) {
PointF prev = ps.mPoints.elementAt(p-1);
PointF cur = ps.mPoints.elementAt(p);
if ((prev != null) && (cur != null)) {
mCanvas.drawLine(prev.x, prev.y, cur.x, cur.y, mPaint);
}
}
}
else {
if (ps == null) {
//Logger.D(TAG, "################## ps == null !");
}
else {
if (ps.mPoints == null) {
//Logger.D(TAG, "################## ps.mPoints == null !");
}
}
}
}
// update screen
Canvas c = null;
try {
c = getHolder().lockCanvas(null);
synchronized (getHolder()) {
c.drawBitmap(mBitmap, 0, 0, null);
}
} finally {
if (c != null) {
getHolder().unlockCanvasAndPost(c);
}
}
}
private void doDrawSegment(float x1, float y1, float x2, float y2) {
Canvas c = null;
Rect rect = new Rect((int)(x1-1),(int)(y1-1),(int)(x1+1),(int)(y1+1));
rect.union((int)(x2-1),(int)(y2-1),(int)(x2+1),(int)(y2+1));
try {
c = getHolder().lockCanvas(rect);
synchronized (getHolder()) {
mCanvas.drawLine(x1,y1,x2,y2,mPaint);
c.drawBitmap(mBitmap, rect, rect, null);
}
} finally {
if (c != null) {
getHolder().unlockCanvasAndPost(c);
}
}
}
public SignatureView(Context context, AttributeSet attrs) {
super(context, attrs);
Logger.D(TAG, "SignatureView()");
// register our interest in hearing about changes to our surface
SurfaceHolder holder = getHolder();
holder.addCallback(this);
setVisibility(VISIBLE);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(0xFF66009A);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(2);
setFocusable(true); // make sure we get key events
requestFocus();
bringToFront();
}
public Bitmap makeBitmap() {
return mBitmap;
}
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mCurrentSequence = new PointSequence();
mCurrentSequence.mPoints.add(new PointF(x,y));
break;
case MotionEvent.ACTION_MOVE:
doDrawSegment(mX,mY, x,y);
mCurrentSequence.mPoints.add(new PointF(x,y));
break;
case MotionEvent.ACTION_UP:
doDrawSegment(mX,mY, x,y);
mCurrentSequence.mPoints.add(new PointF(x,y));
mSequences.add(mCurrentSequence);
mCurrentSequence = new PointSequence();
break;
}
mX = x;
mY = y;
return true;
}
/* Callback invoked when the surface dimensions change. */
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Logger.D(TAG, "SurfaceChanged()");
mBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.RGB_565);
mCanvas = new Canvas(mBitmap);
doFullRedraw();
}
/*
* Callback invoked when the Surface has been created and is ready to be
* used.
*/
public void surfaceCreated(SurfaceHolder holder) {
Logger.D(TAG, "SurfaceCreated()");
}
public void surfaceDestroyed(SurfaceHolder holder) {
Logger.D(TAG, "SurfaceDestroyed()");
mBitmap = null;
mCanvas = null;
}
}