0

I am working on a painting app, code as follows:

DrawActivity

protected void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
    getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
    setContentView(R.layout.coloring_activity3);
    ....

    mv = (MyDrawView2) findViewById(R.id.drawerView);   
    mv.setDrawingCacheEnabled(true);
    Constants.mPaint = new Paint();
    Constants.mPaint.setAntiAlias(true);
    Constants.mPaint.setDither(true);
    Constants.mPaint.setColor(0xFF000000);
    Constants.mPaint.setStyle(Paint.Style.STROKE);
    Constants.mPaint.setStrokeJoin(Paint.Join.ROUND);
    Constants.mPaint.setStrokeCap(Paint.Cap.ROUND);
    Constants.mPaint.setStrokeWidth(Brush_size);

    ....
    case R.id.btn_eraser:
        Constants.mPaint.setXfermode(null);
        Constants.mPaint.setAlpha(0xFF);
        Constants.mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        layout_eraser_size.startAnimation(eraser_move_from_bottom_into_screen);
        layout_eraser_size.setVisibility(View.VISIBLE); 
        btn_eraser.setEnabled(false);
        break;

    case R.id.btn_brush:
        layout_brush_btns.startAnimation(brush_move_from_bottom_into_screen);
        layout_brush_btns.setVisibility(View.VISIBLE); 
        btn_brush.setEnabled(false);
        break;

    case R.id.btn_undo:
        Constants.custom_toast(this, "undo", "clicked");
        mv.onClickUndo();
        break;

DrawView2

public class MyDrawView2 extends View 
{
    private Bitmap mBitmap;
    private Canvas mCanvas;
    private Path mPath;
    private Paint mBitmapPaint;
    Context context;

    private ArrayList<Path> paths = new ArrayList<Path>();
    private ArrayList<Path> undonePaths = new ArrayList<Path>(); 


    public MyDrawView2(Context c, AttributeSet attrs) 
    {
        super(c, attrs);
        context = c;
        mPath = new Path();
        mBitmapPaint = new Paint(Paint.DITHER_FLAG);
        setLayerType(View.LAYER_TYPE_SOFTWARE, null); // for solely removing the black eraser
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) 
    {
        super.onSizeChanged(w, h, oldw, oldh);
        mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);
    }

    @Override
    protected void onDraw(Canvas canvas) 
    {
        super.onDraw(canvas);
        canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
        canvas.drawPath(mPath, Constants.mPaint);
    }

    public void onClickUndo () 
    { 
        if (paths.size()>0) 
        { 
           undonePaths.add(paths.remove(paths.size()-1));
           invalidate();
        }
        else
        {
            Toast.makeText(getContext(), "nothing to undo", Toast.LENGTH_SHORT).show();  
        }     
    }

    public void onClickRedo ()
    {
       if (undonePaths.size()>0) 
       { 
           paths.add(undonePaths.remove(undonePaths.size()-1)) ;
           invalidate();
       } 
       else
       {
           Toast.makeText(getContext(), "nothing to redo", Toast.LENGTH_SHORT).show();  
       }

    }

    private float mX, mY;
    private static final float TOUCH_TOLERANCE = 4;

    private void touch_start(float x, float y) 
    {
        undonePaths.clear();
        mPath.reset();
        mPath.moveTo(x, y);
        mX = x;
        mY = y;
    }

    private void touch_move(float x, float y) 
    {
        float dx = Math.abs(x - mX);
        float dy = Math.abs(y - mY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) 
        {
            mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
            mX = x;
            mY = y;
        }   
    }

    private void touch_up() 
    {
        mPath.lineTo(mX, mY);   
        mCanvas.drawPath(mPath, Constants.mPaint);  // commit the path to our offscreen
        paths.add(mPath);   
        Toast.makeText(getContext(), "path added" + paths.size(), Toast.LENGTH_SHORT).show();  
        mPath.reset();  // kill this so we don't double draw
        Constants.mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
        // mPaint.setMaskFilter(null);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) 
    {
        float x = event.getX();
        float y = event.getY();

        switch (event.getAction()) 
        {
         case MotionEvent.ACTION_DOWN:
                touch_start(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE:

                touch_move(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                touch_up();
                invalidate();
                break;
        }
        return true;
    }
}

Question:

on each touch_up I have added a toast counting the number of path in the arraylist paths and that was showing correctly. But the undo function does not work after clicking btn_undo.

How could that be fixed? Thanks a lot!

pearmak
  • 4,979
  • 15
  • 64
  • 122
  • did you debug? put a break point inside `onClickUndo()` and check – Rustam Oct 26 '14 at 03:56
  • @Rustam: yes, I have checked that the condition of paths.size()>0 is valid and it has gone through that `if` loop in the `onClickUndo()`. the path.size has been reduced by 1 properly, but dont know why the view is not invalidated. – pearmak Oct 26 '14 at 04:00

1 Answers1

1

I got the undo and redo to work by doing the following changes to onSizeChanged(), onDraw() and touch_up():

public class MyDrawView2 extends View 
{

    private Canvas mCanvas;
    private Path mPath;

    Context context;

    private ArrayList<Path> paths = new ArrayList<Path>();
    private ArrayList<Path> undonePaths = new ArrayList<Path>(); 


    public MyDrawView2(Context c, AttributeSet attrs) 
    {
        super(c, attrs);
        context = c;
        mPath = new Path();
        //added
        mCanvas = new Canvas();

    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) 
    {
        super.onSizeChanged(w, h, oldw, oldh);
    //removed bitmap ...

    }

    @Override
    protected void onDraw(Canvas canvas) 
    {
        super.onDraw(canvas);
         //added
           for (Path p : paths){
               canvas.drawPath(p, Constants.mPaint);
           }


        canvas.drawPath(mPath, Constants.mPaint);

      //removed bitmap ...
    }

    public void onClickUndo () 
    { 
        if (paths.size()>0) 
        { 
           undonePaths.add(paths.remove(paths.size()-1));
           invalidate();
        }
        else
        {
            Toast.makeText(getContext(), "nothing to undo", Toast.LENGTH_SHORT).show();  
        }     
    }

    public void onClickRedo ()
    {
       if (undonePaths.size()>0) 
       { 
           paths.add(undonePaths.remove(undonePaths.size()-1)) ;
           invalidate();
       } 
       else
       {
           Toast.makeText(getContext(), "nothing to redo", Toast.LENGTH_SHORT).show();  
       }

    }

    private float mX, mY;
    private static final float TOUCH_TOLERANCE = 4;

    private void touch_start(float x, float y) 
    {
        undonePaths.clear();
        mPath.reset();
        mPath.moveTo(x, y);
        mX = x;
        mY = y;
    }

    private void touch_move(float x, float y) 
    {
        float dx = Math.abs(x - mX);
        float dy = Math.abs(y - mY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) 
        {
            mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
            mX = x;
            mY = y;
        }   
    }

        private void touch_up() 
        {
            mPath.lineTo(mX, mY);   
            mCanvas.drawPath(mPath, Constants.mPaint);  // commit the path to our offscreen
            paths.add(mPath);   
            Toast.makeText(getContext(), "path added" + paths.size(), Toast.LENGTH_SHORT).show();  
            //added
            mPath = new Path();
            //removed reset...

        }

    @Override
    public boolean onTouchEvent(MotionEvent event) 
    {
        float x = event.getX();
        float y = event.getY();

        switch (event.getAction()) 
        {
         case MotionEvent.ACTION_DOWN:
                touch_start(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE:

                touch_move(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                touch_up();
                invalidate();
                break;
        }
        return true;
    }
}
Wildroid
  • 864
  • 7
  • 9
  • still the same...the undopath.size has reported deducted by 1 but is not reflected in the drawView – pearmak Oct 26 '14 at 06:08
  • Ok - so I got the redo and undo to work - see edited answer above. – Wildroid Oct 26 '14 at 15:11
  • thanks for your help a lot!!! the undo function is now working well...however, after first line is drawn (eg in red), then when second line is orange, once touching the screen to draw the orange line, the first red line is immediately changed to the same orange color. And then when using the rubber, once the rubber touch the screen, all previously drawn lines are gone together as well.... i.e. all previously drawn lines' color will follow the last chosen color... – pearmak Oct 26 '14 at 17:36
  • 1
    This is a different question. This happens because when you perform undo and redo, the path loses the assigned paint unless you recall the saved paint. You can map the paint to path or create class to combine path and paint. This may help [link](http://stackoverflow.com/questions/13564989/how-perform-undo-redo-on-canvas-without-losing-previous-color) – Wildroid Oct 26 '14 at 19:27
  • @pearmak If this answer worked for you, please consider accepting it so users can benefit from the answer. Thanks. – Wildroid Nov 05 '14 at 01:51
  • thanks for your help! the undo and redo part is working =) it would be great if you can also help for the question at http://stackoverflow.com/questions/26636487/android-painting-app-with-eraser-not-working – pearmak Nov 05 '14 at 12:24
  • @pearmak I already posted my workaround solution for that question. Give it a try. – Wildroid Nov 05 '14 at 12:32