The default is SolidLine, I can start drawing, switch to Airbrush, and everything looks fine. If I switch back to SolidLine, the Airbrush draws disappear, but the previous SolidLine draws remain. If I then switch back to Airbrush, the previous Airbrush draw reappear, and the previous SolidLine draws remain. In the function touch_up(event), in (line_type == SOLID_LINE), if I comment out
//mCanvas.drawPath(mPath, mPaint);
then When I select Airbrush the SolidLine draws disappear, and reapear when I select back to SolidLine, while as usual Airbrush draw disappear. So it seems clear to me that I need to get my Airbrush draws onto the onDraw Canvas, but I've not been able to get that to work, trying a variety of things focussing on trying to draw the Bitmap mSourceBM used to initialize mCanvas, onto the onDraw Canvas canvas.
Any ideas would be greatly appreciated!
My onDraw function
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(line_type == SOLID_LINE){
for (Pair<Path, Paint> p : paths) {
canvas.drawPath(p.first, p.second);
}
canvas.drawPath(mPath, mPaint);
}else if(line_type == AIRBRUSH){
Log.d(DTAG, "onDraw: AIRBRUSH: no call");
canvas.drawBitmap(mSourceBM, 0,0, null);
}
}
My init function, for context
private void init(AttributeSet attrs, int defStyle) {
if(line_type == SOLID_LINE){
setSolidLine(); // various paint settings
}else if(line_type == AIRBRUSH){
setAirbrush(); // other paint settings
}
}
Here's the drawSpalsh function that is fired multiple times in touch_move, and once in touch up. It draws a paint with a radial gradient, and a radius of have half the Paint Stroke width at point (x,y). invalidate() is called in onTouchEvent after each touch_move(x,y), touch_start(x,y), and touch_up(event) call.
private void drawSplash(int x, int y)
{
mBrush.setBounds(x - strokeRadius, y - strokeRadius, x + strokeRadius, y + strokeRadius);
mBrush.draw(mCanvas);
//mPaint = mBrush.getPaint();
//mCanvas.drawBitmap(mSourceBM, x, y, mPaint);
//mCanvas.drawPaint(mPaint);
}
touch_start, called from onTouchEvent
private void touch_start(float x, float y) {
if(line_type == SOLID_LINE){
undonePaths.clear();// we clear the undonePaths because we are drawing
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}else if(line_type == AIRBRUSH){
mPreviousX = x;
mPreviousY = y;
Log.d(DTAG, "touch_start");
}
}
touch_move called from onTouchEvent
private void touch_move(float x, float y) {
if(line_type == SOLID_LINE){
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;
}
// displayMemoryUsage("touch_move SOLID");
}else if(line_type == AIRBRUSH){
float mX = x;
float mY = y;
// get vector from previous to current position
float xdist = mX - mPreviousX;
float ydist = mY - mPreviousY;
// get the length
float segmentLength = (float) Math.sqrt(xdist * xdist + ydist * ydist);
// derive a suitable step size from stroke width
float stepSize = Math.max(strokeRadius / 10, 1f);
// calculate the number of steps we need to take
// NOTE: this draws a bunch of evenly spaced splashes from the start point
// to JUST BEFORE the end point.
int steps = Math.max(Math.round(segmentLength / stepSize), 2);
for(int i = 0; i < steps; ++i)
{
int currentX = (int) (mPreviousX + xdist * i / steps);
int currentY = (int) (mPreviousY + ydist * i / steps);
drawSplash(currentX, currentY);
}
//Log.d(DTAG, "touch_move: AIRBRUSH xdist, ydist: "+xdist+" "+ydist);
// update the previous position
mPreviousX = mX;
mPreviousY = mY;
//displayMemoryUsage("touch_move AIR");
//Log.d(DTAG, "touch_move AIR: previous x y "+mX+" "+mY);
}
}
touch_up called from onTouchEvent
private void touch_up(MotionEvent event) {
if(line_type == SOLID_LINE){
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
Paint newPaint = new Paint(mPaint);
paths.add(new Pair<Path, Paint>(mPath, newPaint));
mPath = new Path();
}else if(line_type == AIRBRUSH){
drawSplash((int) event.getX(), (int)event.getY());
}
}
the Activity sets the Bitmap. Actually I don't use the BitmapDrawable. Just the Bitmap to initialize the Airbrush canvas mCanvas.
/**
* Sets the Canvas Bitmap we intend to modify
*/
public boolean setCanvasBitmapDrawable(BitmapDrawable bitmapdrawable, Bitmap sourceBM, int left_bound, int top_bound) {
// supply bounds as parameters
mSourceBM = sourceBM;
// mSourceBM = convertToMutable(this, mSourceBM);
bmDrawable = bitmapdrawable;
mCanvas = new Canvas(mSourceBM);
//bmDrawable.setBounds(left_bound, top_bound, bitmapdrawable.getIntrinsicWidth()+left_bound, bitmapdrawable.getIntrinsicHeight()+top_bound);
invalidate();
return true;
}