diff options
Diffstat (limited to 'android/experimental/LOAndroid3/src/java/org/libreoffice/overlay/DocumentOverlayView.java')
-rw-r--r-- | android/experimental/LOAndroid3/src/java/org/libreoffice/overlay/DocumentOverlayView.java | 377 |
1 files changed, 377 insertions, 0 deletions
diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/overlay/DocumentOverlayView.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/overlay/DocumentOverlayView.java new file mode 100644 index 000000000000..7d72d3e7ef94 --- /dev/null +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/overlay/DocumentOverlayView.java @@ -0,0 +1,377 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.libreoffice.overlay; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PointF; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; + +import org.libreoffice.canvas.Cursor; +import org.libreoffice.canvas.GraphicSelection; +import org.libreoffice.canvas.SelectionHandle; +import org.libreoffice.canvas.SelectionHandleEnd; +import org.libreoffice.canvas.SelectionHandleMiddle; +import org.libreoffice.canvas.SelectionHandleStart; +import org.mozilla.gecko.gfx.ImmutableViewportMetrics; +import org.mozilla.gecko.gfx.LayerView; +import org.mozilla.gecko.gfx.RectUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * Document overlay view is responsible for showing the client drawn overlay + * elements like cursor, selection and graphic selection, and manipulate them. + */ +public class DocumentOverlayView extends View implements View.OnTouchListener { + private static final String LOGTAG = DocumentOverlayView.class.getSimpleName(); + + private static final int CURSOR_BLINK_TIME = 500; + + private boolean mInitialized = false; + + private List<RectF> mSelections = new ArrayList<RectF>(); + private List<RectF> mScaledSelections = new ArrayList<RectF>(); + private Paint mSelectionPaint = new Paint(); + private boolean mSelectionsVisible; + + private GraphicSelection mGraphicSelection; + + private boolean mGraphicSelectionMove = false; + + private LayerView mLayerView; + + private SelectionHandle mHandleMiddle; + private SelectionHandle mHandleStart; + private SelectionHandle mHandleEnd; + + private Cursor mCursor; + + private SelectionHandle mDragHandle = null; + + public DocumentOverlayView(Context context) { + super(context); + } + + public DocumentOverlayView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public DocumentOverlayView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + /** + * Initialize the selection and cursor view. + */ + public void initialize(LayerView layerView) { + if (!mInitialized) { + setOnTouchListener(this); + mLayerView = layerView; + + mCursor = new Cursor(); + mCursor.setVisible(false); + + mSelectionPaint.setColor(Color.BLUE); + mSelectionPaint.setAlpha(50); + mSelectionsVisible = false; + + mGraphicSelection = new GraphicSelection(); + mGraphicSelection.setVisible(false); + + postDelayed(cursorAnimation, CURSOR_BLINK_TIME); + + mHandleMiddle = new SelectionHandleMiddle(getContext()); + mHandleStart = new SelectionHandleStart(getContext()); + mHandleEnd = new SelectionHandleEnd(getContext()); + + mInitialized = true; + } + } + + /** + * Change the cursor position. + * @param position - new position of the cursor + */ + public void changeCursorPosition(RectF position) { + if (RectUtils.fuzzyEquals(mCursor.mPosition, position)) { + return; + } + mCursor.mPosition = position; + + ImmutableViewportMetrics metrics = mLayerView.getViewportMetrics(); + repositionWithViewport(metrics.viewportRectLeft, metrics.viewportRectTop, metrics.zoomFactor); + } + + /** + * Change the text selection rectangles. + * @param selectionRects - list of text selection rectangles + */ + public void changeSelections(List<RectF> selectionRects) { + mSelections = selectionRects; + + ImmutableViewportMetrics metrics = mLayerView.getViewportMetrics(); + repositionWithViewport(metrics.viewportRectLeft, metrics.viewportRectTop, metrics.zoomFactor); + } + + /** + * Change the graphic selection rectangle. + * @param rectangle - new graphic selection rectangle + */ + public void changeGraphicSelection(RectF rectangle) { + if (RectUtils.fuzzyEquals(mGraphicSelection.mRectangle, rectangle)) { + return; + } + + mGraphicSelection.mRectangle = rectangle; + + ImmutableViewportMetrics metrics = mLayerView.getViewportMetrics(); + repositionWithViewport(metrics.viewportRectLeft, metrics.viewportRectTop, metrics.zoomFactor); + } + + public void repositionWithViewport(float x, float y, float zoom) { + RectF rect = convertToScreen(mCursor.mPosition, x, y, zoom); + mCursor.reposition(rect); + + rect = convertToScreen(mHandleMiddle.mDocumentPosition, x, y, zoom); + mHandleMiddle.reposition(rect.left, rect.bottom); + + rect = convertToScreen(mHandleStart.mDocumentPosition, x, y, zoom); + mHandleStart.reposition(rect.left, rect.bottom); + + rect = convertToScreen(mHandleEnd.mDocumentPosition, x, y, zoom); + mHandleEnd.reposition(rect.left, rect.bottom); + + mScaledSelections.clear(); + for (RectF selection : mSelections) { + RectF scaledSelection = convertToScreen(selection, x, y, zoom); + mScaledSelections.add(scaledSelection); + } + + RectF scaledGraphicSelection = convertToScreen(mGraphicSelection.mRectangle, x, y, zoom); + mGraphicSelection.reposition(scaledGraphicSelection); + invalidate(); + } + + /** + * Convert the input rectangle from document to screen coordinates + * according to current viewport data (x, y, zoom). + */ + private static RectF convertToScreen(RectF inputRect, float x, float y, float zoom) { + RectF rect = RectUtils.scale(inputRect, zoom); + rect.offset(-x, -y); + return rect; + } + + /** + * Drawing on canvas. + */ + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + mCursor.draw(canvas); + + mHandleMiddle.draw(canvas); + mHandleStart.draw(canvas); + mHandleEnd.draw(canvas); + + if (mSelectionsVisible) { + for (RectF selection : mScaledSelections) { + canvas.drawRect(selection, mSelectionPaint); + } + } + + mGraphicSelection.draw(canvas); + + } + + /** + * Cursor animation function. Switch the alpha between opaque and fully transparent. + */ + private Runnable cursorAnimation = new Runnable() { + public void run() { + if (mCursor.isVisible()) { + mCursor.cycleAlpha(); + invalidate(); + } + postDelayed(cursorAnimation, CURSOR_BLINK_TIME); + } + }; + + /** + * Show the cursor on the view. + */ + public void showCursor() { + if (!mCursor.isVisible()) { + mCursor.setVisible(true); + invalidate(); + } + } + + /** + * Hide the cursor. + */ + public void hideCursor() { + if (mCursor.isVisible()) { + mCursor.setVisible(false); + invalidate(); + } + } + + /** + * Show text selection rectangles. + */ + public void showSelections() { + if (!mSelectionsVisible) { + mSelectionsVisible = true; + invalidate(); + } + } + + /** + * Hide text selection rectangles. + */ + public void hideSelections() { + if (mSelectionsVisible) { + mSelectionsVisible = false; + invalidate(); + } + } + + /** + * Show the graphic selection on the view. + */ + public void showGraphicSelection() { + if (!mGraphicSelection.isVisible()) { + mGraphicSelectionMove = false; + mGraphicSelection.reset(); + mGraphicSelection.setVisible(true); + invalidate(); + } + } + + /** + * Hide the graphic selection. + */ + public void hideGraphicSelection() { + if (mGraphicSelection.isVisible()) { + mGraphicSelection.setVisible(false); + invalidate(); + } + } + + /** + * Handle the triggered touch event. + */ + @Override + public boolean onTouch(View view, MotionEvent event) { + PointF point = new PointF(event.getX(), event.getY()); + switch (event.getActionMasked()) { + case MotionEvent.ACTION_DOWN: { + if (mGraphicSelection.isVisible()) { + // Check if inside graphic selection was hit + if (mGraphicSelection.contains(point.x, point.y)) { + mGraphicSelectionMove = true; + mGraphicSelection.dragStart(point); + invalidate(); + return true; + } + } else { + if (mHandleStart.contains(point.x, point.y)) { + mHandleStart.dragStart(point); + mDragHandle = mHandleStart; + return true; + } else if (mHandleEnd.contains(point.x, point.y)) { + mHandleEnd.dragStart(point); + mDragHandle = mHandleEnd; + return true; + } else if (mHandleMiddle.contains(point.x, point.y)) { + mHandleMiddle.dragStart(point); + mDragHandle = mHandleMiddle; + return true; + } + } + } + case MotionEvent.ACTION_UP: { + if (mGraphicSelection.isVisible() && mGraphicSelectionMove) { + mGraphicSelection.dragEnd(point); + mGraphicSelectionMove = false; + invalidate(); + return true; + } else if (mDragHandle != null) { + mDragHandle.dragEnd(point); + mDragHandle = null; + } + } + case MotionEvent.ACTION_MOVE: { + if (mGraphicSelection.isVisible() && mGraphicSelectionMove) { + mGraphicSelection.dragging(point); + invalidate(); + return true; + } else if (mDragHandle != null) { + mDragHandle.dragging(point); + } + } + } + return false; + } + + public void positionHandle(SelectionHandle.HandleType type, RectF position) { + SelectionHandle handle = getHandleForType(type); + if (RectUtils.fuzzyEquals(handle.mDocumentPosition, position)) { + return; + } + + RectUtils.assign(handle.mDocumentPosition, position); + + ImmutableViewportMetrics metrics = mLayerView.getViewportMetrics(); + repositionWithViewport(metrics.viewportRectLeft, metrics.viewportRectTop, metrics.zoomFactor); + } + + public void hideHandle(SelectionHandle.HandleType type) { + SelectionHandle handle = getHandleForType(type); + if (handle.isVisible()) { + handle.setVisible(false); + invalidate(); + } + } + + public void showHandle(SelectionHandle.HandleType type) { + SelectionHandle handle = getHandleForType(type); + if (!handle.isVisible()) { + handle.setVisible(true); + invalidate(); + } + } + + private SelectionHandle getHandleForType(SelectionHandle.HandleType type) { + switch(type) { + case START: + return mHandleStart; + case END: + return mHandleEnd; + case MIDDLE: + return mHandleMiddle; + } + return null; + } + + public RectF getCursorPosition() { + return mCursor.mPosition; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |