package org.ebookdroid.ui.viewer.views; import org.sufficientlysecure.viewer.R; import org.ebookdroid.common.bitmaps.BitmapManager; import org.ebookdroid.core.events.ZoomListener; import org.ebookdroid.core.models.ZoomModel; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PointF; import android.graphics.Rect; import android.support.annotation.Nullable; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.MotionEvent; import android.view.View; import android.widget.Scroller; public class ZoomRoll extends View implements ZoomListener { private static final float MULTIPLIER = 400.0f; private static final float MAX_VALUE = (1 + ZoomModel.MAX_ZOOM)* MULTIPLIER; private final Bitmap left; private final Bitmap right; private final Bitmap center; private final Bitmap serifs; private final Scroller scroller; private final ZoomModel zoomModel; private final GestureDetector gestureDetector; private boolean inTouch; public ZoomRoll(final Context context, final ZoomModel zoomModel) { super(context); this.zoomModel = zoomModel; this.zoomModel.addListener(this); left = BitmapManager.getResource(R.drawable.components_zoomroll_left); right = BitmapManager.getResource(R.drawable.components_zoomroll_right); center = BitmapManager.getResource(R.drawable.components_zoomroll_center); serifs = BitmapManager.getResource(R.drawable.components_zoomroll_serifs); scroller = new Scroller(context); gestureDetector = new GestureDetector(getContext(), new GestureListener()); setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_LOW); } @Override protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), Math.max(left.getHeight(), right.getHeight())); } @Override public void draw(final Canvas canvas) { super.draw(canvas); final Paint paint = new Paint(); canvas.drawBitmap(center, new Rect(0, 0, center.getWidth(), center.getHeight()), new Rect(0, 0, getWidth(), getHeight()), paint); float currentOffset = -getCurrentValue() % 40; while (currentOffset < getWidth()) { canvas.drawBitmap(serifs, currentOffset, (getHeight() - serifs.getHeight()) / 2.0f, paint); currentOffset += serifs.getWidth(); } canvas.drawBitmap(left, 0, 0, paint); canvas.drawBitmap(right, getWidth() - right.getWidth(), getHeight() - right.getHeight(), paint); Paint textPaint = new Paint(); textPaint.setColor(Color.BLACK); textPaint.setTextSize(24); textPaint.setAntiAlias(true); String zoomText = String.format("%.2f", zoomModel.getZoom()); canvas.drawText(zoomText+"x", 6, getHeight() / 2 + 12, textPaint); } @Override public boolean onTouchEvent(final MotionEvent ev) { super.onTouchEvent(ev); try { Thread.sleep(16); } catch (final InterruptedException e) { Thread.interrupted(); } if ((ev.getAction() & MotionEvent.ACTION_UP) == MotionEvent.ACTION_UP) { inTouch = false; } final boolean res = gestureDetector.onTouchEvent(ev); computeScroll(); return res; } @Override public void computeScroll() { if (scroller.computeScrollOffset()) { setCurrentValue(scroller.getCurrX()); invalidate(); } else if (!inTouch) { zoomModel.commit(); } } public float getCurrentValue() { return (zoomModel.getZoom() - 1.0f) * MULTIPLIER; } public void setCurrentValue(float currentValue) { if (currentValue < 0.0) { currentValue = 0.0f; } if (currentValue > MAX_VALUE) { currentValue = MAX_VALUE; } final float zoom = 1.0f + currentValue / MULTIPLIER; zoomModel.setZoom(zoom); } @Override public void zoomChanged(float oldZoom, float newZoom, boolean committed, @Nullable PointF center) { postInvalidate(); } protected class GestureListener extends SimpleOnGestureListener { @Override public boolean onDoubleTap(final MotionEvent e) { setCurrentValue(0.0f); zoomModel.commit(); ZoomRoll.this.postInvalidate(); return true; } @Override public boolean onDown(final MotionEvent e) { inTouch = true; if (!scroller.isFinished()) { scroller.abortAnimation(); zoomModel.commit(); } return true; } @Override public boolean onFling(final MotionEvent e1, final MotionEvent e2, final float vX, final float vY) { inTouch = false; scroller.fling((int) getCurrentValue(), 0, -(int)vX, 0, 0, (int)MAX_VALUE, 0, 0); ZoomRoll.this.postInvalidate(); return true; } @Override public boolean onScroll(final MotionEvent e1, final MotionEvent e2, final float distanceX, final float distanceY) { setCurrentValue(getCurrentValue() + distanceX); scroller.computeScrollOffset(); ZoomRoll.this.postInvalidate(); return true; } @Override public boolean onSingleTapUp(final MotionEvent e) { scroller.computeScrollOffset(); inTouch = false; zoomModel.commit(); return true; } } }