package org.ebookdroid.ui.viewer.views;
import org.sufficientlysecure.viewer.R;
import org.ebookdroid.common.settings.types.PageAlign;
import org.ebookdroid.core.EventCrop;
import org.ebookdroid.core.Page;
import org.ebookdroid.core.ViewState;
import org.ebookdroid.ui.viewer.IActivityController;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.PorterDuff.Mode;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import org.emdev.ui.actions.ActionController;
import org.emdev.ui.actions.ActionDialogBuilder;
import org.emdev.ui.actions.ActionEx;
import org.emdev.ui.actions.ActionMethod;
import org.emdev.ui.actions.IActionController;
import org.emdev.utils.MathUtils;
public class ManualCropView extends View {
private static final Paint PAINT = new Paint();
private final IActivityController base;
private final GestureDetector gestureDetector;
private final ActionController<ManualCropView> controller = new ActionController<ManualCropView>(this);
private final PointF topLeft = new PointF(0.1f, 0.1f);
private final PointF bottomRight = new PointF(0.9f, 0.9f);
private PointF currentPoint = null;
private Page page;
private RectF result;
public ManualCropView(final IActivityController base) {
super(base.getContext());
this.base = base;
super.setVisibility(View.GONE);
PAINT.setColor(Color.CYAN);
setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
setFocusable(true);
setFocusableInTouchMode(true);
gestureDetector = new GestureDetector(getContext(), new GestureListener());
}
public void initControls() {
page = base.getDocumentModel().getCurrentPageObject();
if (page == null) {
return;
}
base.getZoomModel().setZoom(1.0f, true);
base.getBookSettings().pageAlign = PageAlign.AUTO;
final RectF oldCb = page.nodes.root.getCropping();
if (page.shouldCrop() && oldCb != null) {
new EventCrop(base.getDocumentController()).add(page).process().release();
}
if (oldCb == null) {
topLeft.set(0.1f, 0.1f);
bottomRight.set(0.9f, 0.9f);
} else {
final RectF ir = new RectF(page.type.getInitialRect());
final float irw = ir.width();
final float left = (oldCb.left - ir.left) / irw;
final float top = (oldCb.top);
final float right = (oldCb.right - ir.left) / irw;
final float bottom = (oldCb.bottom);
topLeft.set(left, top);
bottomRight.set(right, bottom);
}
}
public void applyCropping() {
if (page == null) {
ViewEffects.toggleControls(this);
return;
}
result = new RectF(Math.min(topLeft.x, bottomRight.x), Math.min(topLeft.y, bottomRight.y), Math.max(topLeft.x,
bottomRight.x), Math.max(topLeft.y, bottomRight.y));
final ActionDialogBuilder builder = new ActionDialogBuilder(getContext(), controller);
builder.setTitle(R.string.manual_cropping_title);
builder.setItems(R.array.list_crop_actions, controller.getOrCreateAction(R.id.actions_applyCrop));
builder.setNegativeButton(R.string.manual_cropping_back);
builder.show();
}
@ActionMethod(ids = R.id.actions_applyCrop)
public void onApply(final ActionEx action) {
final Integer index = action.getParameter(IActionController.DIALOG_ITEM_PROPERTY);
if (index == null) {
return;
}
ViewEffects.toggleControls(this);
EventCrop event = null;
switch (index.intValue()) {
case 0:
// Apply to current only
event = new EventCrop(base.getDocumentController(), result, true);
event.add(page).process().release();
return;
case 1:
// Apply to even(odd)
event = new EventCrop(base.getDocumentController(), result, true);
event.addEvenOdd(page, true).process().release();
return;
case 2:
// Apply to even(odd) symmetrically
event = new EventCrop(base.getDocumentController(), result, true);
event.addEvenOdd(page, true).process().release();
final RectF symm = new RectF();
symm.left = 1 - result.right;
symm.top = result.top;
symm.right = 1 - result.left;
symm.bottom = result.bottom;
event = new EventCrop(base.getDocumentController(), symm, true);
event.addEvenOdd(page, false).process().release();
return;
case 3:
// Apply to all
event = new EventCrop(base.getDocumentController(), result, true);
event.addAll().process().release();
return;
case 4:
// Remove manual cropping
event = new EventCrop(base.getDocumentController(), null, true);
event.add(page).process().release();
return;
case 5:
// Remove all manual cropping
event = new EventCrop(base.getDocumentController(), null, true);
event.addAll().process().release();
return;
}
}
@Override
protected void onDraw(final Canvas canvas) {
if (page == null) {
return;
}
final RectF r = getActualRect();
canvas.drawColor(0x7F000000);
canvas.save();
canvas.clipRect(r.left, r.top, r.right, r.bottom);
canvas.drawColor(0x00FFFFFF, Mode.CLEAR);
canvas.restore();
final Drawable d = base.getContext().getResources().getDrawable(R.drawable.components_cropper_circle);
d.setBounds((int) (r.left - 25), (int) (r.top - 25), (int) (r.left + 25), (int) (r.top + 25));
d.draw(canvas);
d.setBounds((int) (r.right - 25), (int) (r.bottom - 25), (int) (r.right + 25), (int) (r.bottom + 25));
d.draw(canvas);
canvas.drawLine(0, r.top, getWidth(), r.top, PAINT);
canvas.drawLine(0, r.bottom, getWidth(), r.bottom, PAINT);
canvas.drawLine(r.left, 0, r.left, getHeight(), PAINT);
canvas.drawLine(r.right, 0, r.right, getHeight(), PAINT);
}
private RectF getActualRect() {
final RectF pageBounds = getPageRect();
final float pageWidth = pageBounds.width();
final float pageHeight = pageBounds.height();
final float left = pageBounds.left + topLeft.x * pageWidth;
final float top = pageBounds.top + topLeft.y * pageHeight;
final float right = pageBounds.left + bottomRight.x * pageWidth;
final float bottom = pageBounds.top + bottomRight.y * pageHeight;
return new RectF(Math.min(left, right), Math.min(top, bottom), Math.max(right, left), Math.max(bottom, top));
}
private RectF getPageRect() {
final ViewState viewState = ViewState.get(base.getDocumentController());
final RectF pageBounds = viewState.getBounds(page);
pageBounds.offset(-viewState.viewBase.x, -viewState.viewBase.y);
viewState.release();
return pageBounds;
}
static String str(final PointF p) {
return "(" + p.x + ", " + p.y + ")";
}
@Override
public boolean onTouchEvent(final MotionEvent ev) {
try {
Thread.sleep(16);
} catch (final InterruptedException e) {
Thread.interrupted();
}
if ((ev.getAction() & MotionEvent.ACTION_UP) == MotionEvent.ACTION_UP) {
currentPoint = null;
}
return gestureDetector.onTouchEvent(ev);
}
protected class GestureListener extends SimpleOnGestureListener {
private static final int SPOT_SIZE = 25;
@Override
public boolean onDown(final MotionEvent e) {
if (page == null) {
return true;
}
final float x = e.getX();
final float y = e.getY();
final RectF r = getActualRect();
if ((Math.abs(x - r.left) < SPOT_SIZE) && (Math.abs(y - r.top) < SPOT_SIZE)) {
currentPoint = topLeft;
return true;
}
if ((Math.abs(x - r.right) < SPOT_SIZE) && (Math.abs(y - r.bottom) < SPOT_SIZE)) {
currentPoint = bottomRight;
return true;
}
currentPoint = null;
return true;
}
@Override
public boolean onScroll(final MotionEvent e1, final MotionEvent e2, final float distanceX, final float distanceY) {
if (page == null || currentPoint == null) {
return true;
}
final float x = e2.getX();
final float y = e2.getY();
final RectF r = getPageRect();
currentPoint.x = MathUtils.adjust((x - r.left) / r.width(), 0f, 1f);
currentPoint.y = MathUtils.adjust((y - r.top) / r.height(), 0f, 1f);
invalidate();
return true;
}
@Override
public boolean onDoubleTap(final MotionEvent e) {
applyCropping();
return true;
}
}
}