diff options
Diffstat (limited to 'android/source/src/java/org/libreoffice/canvas')
16 files changed, 1200 insertions, 0 deletions
diff --git a/android/source/src/java/org/libreoffice/canvas/AdjustLengthLine.java b/android/source/src/java/org/libreoffice/canvas/AdjustLengthLine.java new file mode 100644 index 000000000..a6f8cb17c --- /dev/null +++ b/android/source/src/java/org/libreoffice/canvas/AdjustLengthLine.java @@ -0,0 +1,103 @@ +package org.libreoffice.canvas; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PointF; +import android.graphics.RectF; + +import org.json.JSONException; +import org.json.JSONObject; +import org.libreoffice.LOEvent; +import org.libreoffice.LOKitShell; +import org.libreoffice.LibreOfficeMainActivity; +import org.libreoffice.overlay.CalcHeadersView; +import org.mozilla.gecko.gfx.ImmutableViewportMetrics; + +import static org.libreoffice.SearchController.addProperty; +import static org.libreoffice.UnitConverter.pixelToTwip; +import static org.libreoffice.UnitConverter.twipsToHMM; + +public class AdjustLengthLine extends CommonCanvasElement { + + private static final float STROKE_WIDTH = 4f; + private static final float TOUCH_VICINITY_RADIUS = 24f; + + private LibreOfficeMainActivity mContext; + private CalcHeadersView mCalcHeadersView; + private boolean mIsRow; + private PointF mScreenPosition; + private float mWidth; + private float mHeight; + private Paint mPaint; + private PointF mStartScreenPosition; + private int mIndex; + + public AdjustLengthLine(LibreOfficeMainActivity context, CalcHeadersView view, boolean isRow, float width, float height) { + super(); + mContext = context; + mCalcHeadersView = view; + mIsRow = isRow; + mWidth = width; + mHeight = height; + mPaint = new Paint(); + mPaint.setColor(Color.BLACK); + mPaint.setStrokeWidth(STROKE_WIDTH); + } + + @Override + public boolean onHitTest(float x, float y) { + if (mIsRow) { + return mScreenPosition.y - TOUCH_VICINITY_RADIUS < y && + y < mScreenPosition.y + TOUCH_VICINITY_RADIUS; + } else { + return mScreenPosition.x - TOUCH_VICINITY_RADIUS < x && + x < mScreenPosition.x + TOUCH_VICINITY_RADIUS; + } + } + + @Override + public void onDraw(Canvas canvas) { + if (mIsRow) { + canvas.drawLine(0f, mScreenPosition.y, mWidth, mScreenPosition.y, mPaint); + } else { + canvas.drawLine(mScreenPosition.x, 0f, mScreenPosition.x, mHeight, mPaint); + } + } + + public void dragStart(PointF point) { + } + + public void dragging(PointF point) { + mScreenPosition = point; + } + + public void dragEnd(PointF point) { + ImmutableViewportMetrics viewportMetrics = mContext.getLayerClient().getViewportMetrics(); + float zoom = viewportMetrics.zoomFactor; + + PointF documentDistance = new PointF(pixelToTwip((point.x-mStartScreenPosition.x)/zoom, LOKitShell.getDpi(mContext)), + pixelToTwip((point.y-mStartScreenPosition.y)/zoom, LOKitShell.getDpi(mContext))); + + try { + JSONObject rootJson = new JSONObject(); + if (mIsRow) { + addProperty(rootJson, "Row", "long", String.valueOf(mIndex)); + addProperty(rootJson, "RowHeight", "unsigned short", String.valueOf(Math.round(documentDistance.y > 0 ? twipsToHMM(documentDistance.y) : 0))); + LOKitShell.sendEvent(new LOEvent(LOEvent.UNO_COMMAND, ".uno:RowHeight", rootJson.toString())); + } else { + addProperty(rootJson, "Column", "long", String.valueOf(mIndex)); + addProperty(rootJson, "ColumnWidth", "unsigned short", String.valueOf(documentDistance.x > 0 ? twipsToHMM(documentDistance.x) : 0)); + LOKitShell.sendEvent(new LOEvent(LOEvent.UNO_COMMAND, ".uno:ColumnWidth", rootJson.toString())); + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + + public void setScreenRect(RectF position) { + mScreenPosition = new PointF(position.right, position.bottom); + mStartScreenPosition = new PointF(position.left, position.top); + mIndex = 1 + mCalcHeadersView.getIndexFromPointOfTouch(new PointF(position.centerX(), position.centerY())); + } +} diff --git a/android/source/src/java/org/libreoffice/canvas/BitmapHandle.java b/android/source/src/java/org/libreoffice/canvas/BitmapHandle.java new file mode 100644 index 000000000..51f6f7cf8 --- /dev/null +++ b/android/source/src/java/org/libreoffice/canvas/BitmapHandle.java @@ -0,0 +1,63 @@ +package org.libreoffice.canvas; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import androidx.core.content.ContextCompat; + +/** + * Bitmap handle canvas element is used to show a handle on the screen. + * The handle visual comes from the bitmap, which must be provided in time + * of construction. + */ +public abstract class BitmapHandle extends CommonCanvasElement { + public final RectF mDocumentPosition; + private final Bitmap mBitmap; + final RectF mScreenPosition; + + BitmapHandle(Bitmap bitmap) { + mBitmap = bitmap; + mScreenPosition = new RectF(0, 0, mBitmap.getWidth(), mBitmap.getHeight()); + mDocumentPosition = new RectF(); + } + + /** + * Return a bitmap for a drawable id. + */ + static Bitmap getBitmapForDrawable(Context context, int drawableId) { + Drawable drawable = ContextCompat.getDrawable(context, drawableId); + + return ImageUtils.getBitmapForDrawable(drawable); + } + + /** + * Draw the bitmap handle to the canvas. + * @param canvas - the canvas + */ + @Override + public void onDraw(Canvas canvas) { + canvas.drawBitmap(mBitmap, mScreenPosition.left, mScreenPosition.top, null); + } + + /** + * Test if the bitmap has been hit. + * @param x - x coordinate + * @param y - y coordinate + * @return true if the bitmap has been hit + */ + @Override + public boolean onHitTest(float x, float y) { + return mScreenPosition.contains(x, y); + } + + /** + * Change the position of the handle. + * @param x - x coordinate + * @param y - y coordinate + */ + public void reposition(float x, float y) { + mScreenPosition.offsetTo(x, y); + } +} diff --git a/android/source/src/java/org/libreoffice/canvas/CalcHeaderCell.java b/android/source/src/java/org/libreoffice/canvas/CalcHeaderCell.java new file mode 100644 index 000000000..c1f8e74e7 --- /dev/null +++ b/android/source/src/java/org/libreoffice/canvas/CalcHeaderCell.java @@ -0,0 +1,54 @@ +package org.libreoffice.canvas; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Paint.Style; +import android.graphics.RectF; +import android.text.TextPaint; + +public class CalcHeaderCell extends CommonCanvasElement { + private TextPaint mTextPaint = new TextPaint(); + private Paint mBgPaint = new Paint(); + private RectF mBounds; + private String mText; + + public CalcHeaderCell(float left, float top, float width, float height, String text, boolean selected) { + mBounds = new RectF(left, top, left + width, top + height); + if (selected) { + // if the cell is selected, display filled + mBgPaint.setStyle(Style.FILL_AND_STROKE); + } else { + // if not, display only the frame + mBgPaint.setStyle(Style.STROKE); + } + mBgPaint.setColor(Color.GRAY); + mBgPaint.setAlpha(100); // hard coded for now + mTextPaint.setColor(Color.GRAY); + mTextPaint.setTextSize(24f); // hard coded for now + mText = text; + } + + /** + * Implement hit test here + * + * @param x - x coordinate of the + * @param y - y coordinate of the + */ + @Override + public boolean onHitTest(float x, float y) { + return false; + } + + /** + * Called inside draw if the element is visible. Override this method to + * draw the element on the canvas. + * + * @param canvas - the canvas + */ + @Override + public void onDraw(Canvas canvas) { + canvas.drawRect(mBounds, mBgPaint); + canvas.drawText(mText, mBounds.left, mBounds.bottom, mTextPaint); + } +}
\ No newline at end of file diff --git a/android/source/src/java/org/libreoffice/canvas/CalcSelectionBox.java b/android/source/src/java/org/libreoffice/canvas/CalcSelectionBox.java new file mode 100644 index 000000000..af31d708d --- /dev/null +++ b/android/source/src/java/org/libreoffice/canvas/CalcSelectionBox.java @@ -0,0 +1,111 @@ +package org.libreoffice.canvas; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PointF; +import android.graphics.RectF; + +import org.libreoffice.LOKitShell; +import org.libreoffice.LibreOfficeMainActivity; +import org.mozilla.gecko.gfx.ImmutableViewportMetrics; + +/** + * CalcSelectionBox is the selection frame for the current highlighted area/cells + * in Calc. + */ + +public class CalcSelectionBox extends CommonCanvasElement { + private static final long MINIMUM_HANDLE_UPDATE_TIME = 50 * 1000000; + private static final float CIRCLE_HANDLE_RADIUS = 8f; + + public RectF mDocumentPosition; + + private LibreOfficeMainActivity mContext; + private RectF mScreenPosition; + private long mLastTime = 0; + private Paint mPaint; + private Paint mCirclePaint; + + public CalcSelectionBox(LibreOfficeMainActivity context) { + mContext = context; + mScreenPosition = new RectF(); + mDocumentPosition = new RectF(); + mPaint = new Paint(); + mPaint.setStyle(Paint.Style.STROKE); + mPaint.setColor(Color.BLACK); + mPaint.setStrokeWidth(2f); + mCirclePaint = new Paint(); + mCirclePaint.setColor(Color.BLACK); + mCirclePaint.setStyle(Paint.Style.FILL); + } + + /** + * Start of a touch and drag action on the box. + */ + public void dragStart(PointF point) {} + + /** + * End of a touch and drag action on the box. + */ + public void dragEnd(PointF point) {} + + /** + * Box has been dragged. + */ + public void dragging(PointF point) { + long currentTime = System.nanoTime(); + if (currentTime - mLastTime > MINIMUM_HANDLE_UPDATE_TIME) { + mLastTime = currentTime; + signalHandleMove(point.x, point.y); + } + } + + /** + * Signal to move the handle to a new position to LO. + */ + private void signalHandleMove(float newX, float newY) { + ImmutableViewportMetrics viewportMetrics = mContext.getLayerClient().getViewportMetrics(); + float zoom = viewportMetrics.zoomFactor; + PointF origin = viewportMetrics.getOrigin(); + + PointF documentPoint = new PointF((newX+origin.x)/zoom , (newY+origin.y)/zoom); + + if (documentPoint.x < mDocumentPosition.left || documentPoint.y < mDocumentPosition.top) { + LOKitShell.sendChangeHandlePositionEvent(SelectionHandle.HandleType.START, documentPoint); + } else if (documentPoint.x > mDocumentPosition.right || documentPoint.y > mDocumentPosition.bottom){ + LOKitShell.sendChangeHandlePositionEvent(SelectionHandle.HandleType.END, documentPoint); + } + } + + @Override + public boolean onHitTest(float x, float y) { + return mScreenPosition.contains(x, y); + } + + @Override + public void onDraw(Canvas canvas) { + canvas.drawRect(mScreenPosition, mPaint); + canvas.drawCircle(mScreenPosition.left, mScreenPosition.top, CIRCLE_HANDLE_RADIUS, mCirclePaint); + canvas.drawCircle(mScreenPosition.right, mScreenPosition.bottom, CIRCLE_HANDLE_RADIUS, mCirclePaint); + } + + public void reposition(RectF rect) { + mScreenPosition = rect; + } + + @Override + public boolean contains(float x, float y) { + // test if in range of the box or the circular handles + boolean inRange = new RectF(mScreenPosition.left - CIRCLE_HANDLE_RADIUS, + mScreenPosition.top - CIRCLE_HANDLE_RADIUS, + mScreenPosition.left + CIRCLE_HANDLE_RADIUS, + mScreenPosition.top + CIRCLE_HANDLE_RADIUS).contains(x, y) + || new RectF(mScreenPosition.right - CIRCLE_HANDLE_RADIUS, + mScreenPosition.bottom - CIRCLE_HANDLE_RADIUS, + mScreenPosition.right + CIRCLE_HANDLE_RADIUS, + mScreenPosition.bottom + CIRCLE_HANDLE_RADIUS).contains(x, y) + || onHitTest(x, y); + return inRange && isVisible(); + } +} diff --git a/android/source/src/java/org/libreoffice/canvas/CanvasElement.java b/android/source/src/java/org/libreoffice/canvas/CanvasElement.java new file mode 100644 index 000000000..51e8801f6 --- /dev/null +++ b/android/source/src/java/org/libreoffice/canvas/CanvasElement.java @@ -0,0 +1,45 @@ +/* -*- 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.canvas; + +import android.graphics.Canvas; + +/** + * Canvas element is an element (or part) that is drawn canvas and can + * potentially be interacted with. + */ +public interface CanvasElement { + /** + * Called when the element needs to be draw no the canvas. This method + * should call onDraw when conditions to draw are satisfied. + * + * @param canvas - the canvas + */ + void draw(Canvas canvas); + + /** + * Hit test - returns true if the object has been hit + * @param x - x coordinate of the + * @param y - y coordinate of the + */ + boolean contains(float x, float y); + + /** + * Return if element is visible. + */ + boolean isVisible(); + + /** + * Set element visibility. + * @param visible - is element visible + */ + void setVisible(boolean visible); +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
\ No newline at end of file diff --git a/android/source/src/java/org/libreoffice/canvas/CanvasElementImplRequirement.java b/android/source/src/java/org/libreoffice/canvas/CanvasElementImplRequirement.java new file mode 100644 index 000000000..26789e8d8 --- /dev/null +++ b/android/source/src/java/org/libreoffice/canvas/CanvasElementImplRequirement.java @@ -0,0 +1,25 @@ +package org.libreoffice.canvas; + +import android.graphics.Canvas; + +/** + * The interface defines a set of method that a typical CanvasElement + * implementation should implement. + */ +interface CanvasElementImplRequirement { + + /** + * Implement hit test here + * @param x - x coordinate of the + * @param y - y coordinate of the + */ + boolean onHitTest(float x, float y); + + /** + * Called inside draw if the element is visible. Override this method to + * draw the element on the canvas. + * + * @param canvas - the canvas + */ + void onDraw(Canvas canvas); +} diff --git a/android/source/src/java/org/libreoffice/canvas/CommonCanvasElement.java b/android/source/src/java/org/libreoffice/canvas/CommonCanvasElement.java new file mode 100644 index 000000000..6b40ae4ba --- /dev/null +++ b/android/source/src/java/org/libreoffice/canvas/CommonCanvasElement.java @@ -0,0 +1,46 @@ +package org.libreoffice.canvas; + +import android.graphics.Canvas; + +/** + * Common implementation to canvas elements. + */ +public abstract class CommonCanvasElement implements CanvasElement, CanvasElementImplRequirement { + + private boolean mVisible = false; + + /** + * Is element visible? + */ + @Override + public boolean isVisible() { + return mVisible; + } + + /** + * Set element visibility. + */ + @Override + public void setVisible(boolean visible) { + mVisible = visible; + } + + /** + * Trigger drawing the element on the canvas. + */ + @Override + public void draw(Canvas canvas) { + if (isVisible()) { + onDraw(canvas); + } + } + + /** + * Hit test. Return true if the element was hit. Directly return false if + * the element is invisible. + */ + @Override + public boolean contains(float x, float y) { + return isVisible() && onHitTest(x, y); + } +} diff --git a/android/source/src/java/org/libreoffice/canvas/Cursor.java b/android/source/src/java/org/libreoffice/canvas/Cursor.java new file mode 100644 index 000000000..1cd30edb7 --- /dev/null +++ b/android/source/src/java/org/libreoffice/canvas/Cursor.java @@ -0,0 +1,56 @@ +package org.libreoffice.canvas; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.RectF; + +/** + * Handles the cursor drawing on the canvas. + */ +public class Cursor extends CommonCanvasElement { + private static final float CURSOR_WIDTH = 2f; + private final Paint mCursorPaint = new Paint(); + public RectF mPosition = new RectF(); + public RectF mScaledPosition = new RectF(); + public int mAlpha = 0; + + /** + * Construct the cursor and set the default values. + */ + public Cursor() { + mCursorPaint.setColor(Color.BLACK); + mCursorPaint.setAlpha(0xFF); + } + + /** + * Hit test for cursor, always false. + */ + @Override + public boolean onHitTest(float x, float y) { + return false; + } + + /** + * Draw the cursor. + */ + @Override + public void onDraw(Canvas canvas) { + canvas.drawRect(mScaledPosition, mCursorPaint); + } + + /** + * Reposition the cursor on screen. + */ + public void reposition(RectF rect) { + mScaledPosition = rect; + mScaledPosition.right = mScaledPosition.left + CURSOR_WIDTH; + } + + /** + * Cycle the alpha color of the cursor, makes the + */ + public void cycleAlpha() { + mCursorPaint.setAlpha(mCursorPaint.getAlpha() == 0 ? 0xFF : 0); + } +} diff --git a/android/source/src/java/org/libreoffice/canvas/GraphicSelection.java b/android/source/src/java/org/libreoffice/canvas/GraphicSelection.java new file mode 100644 index 000000000..8d773b2ea --- /dev/null +++ b/android/source/src/java/org/libreoffice/canvas/GraphicSelection.java @@ -0,0 +1,295 @@ +/* -*- 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.canvas; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PointF; +import android.graphics.RectF; + +import org.libreoffice.LOKitShell; +import org.libreoffice.LibreOfficeMainActivity; +import org.mozilla.gecko.gfx.LayerView; + +import static org.libreoffice.canvas.GraphicSelectionHandle.HandlePosition; + +/** + * This class is responsible to draw and reposition the selection + * rectangle. + */ +public class GraphicSelection extends CommonCanvasElement { + private final Paint mPaintStroke; + private final Paint mPaintFill; + public RectF mRectangle = new RectF(); + public RectF mScaledRectangle = new RectF(); + private RectF mDrawRectangle = new RectF(); + private DragType mType = DragType.NONE; + private PointF mStartDragPosition; + + private GraphicSelectionHandle mHandles[] = new GraphicSelectionHandle[8]; + private GraphicSelectionHandle mDragHandle = null; + private boolean mTriggerSinglePress = false; + private LibreOfficeMainActivity mContext; + + /** + * Construct the graphic selection. + */ + public GraphicSelection(LibreOfficeMainActivity context) { + mContext = context; + // Create the paint, which is needed at drawing + mPaintStroke = new Paint(); + mPaintStroke.setStyle(Paint.Style.STROKE); + mPaintStroke.setColor(Color.GRAY); + mPaintStroke.setStrokeWidth(2); + mPaintStroke.setAntiAlias(true); + + mPaintFill = new Paint(); + mPaintFill.setStyle(Paint.Style.FILL); + mPaintFill.setColor(Color.WHITE); + mPaintFill.setAlpha(200); + mPaintFill.setAntiAlias(true); + + // Create the handles of the selection + mHandles[0] = new GraphicSelectionHandle(HandlePosition.TOP_LEFT); + mHandles[1] = new GraphicSelectionHandle(HandlePosition.TOP); + mHandles[2] = new GraphicSelectionHandle(HandlePosition.TOP_RIGHT); + mHandles[3] = new GraphicSelectionHandle(HandlePosition.LEFT); + mHandles[4] = new GraphicSelectionHandle(HandlePosition.RIGHT); + mHandles[5] = new GraphicSelectionHandle(HandlePosition.BOTTOM_LEFT); + mHandles[6] = new GraphicSelectionHandle(HandlePosition.BOTTOM); + mHandles[7] = new GraphicSelectionHandle(HandlePosition.BOTTOM_RIGHT); + } + + /** + * Viewport has changed, reposition the selection to the new rectangle. + * @param scaledRectangle - rectangle of selection position on the document + */ + public void reposition(RectF scaledRectangle) { + mScaledRectangle = scaledRectangle; + mDrawRectangle = scaledRectangle; // rectangle that will be draw + + // reposition the handles too + mHandles[0].reposition(scaledRectangle.left, scaledRectangle.top); + mHandles[1].reposition(scaledRectangle.centerX(), scaledRectangle.top); + mHandles[2].reposition(scaledRectangle.right, scaledRectangle.top); + mHandles[3].reposition(scaledRectangle.left, scaledRectangle.centerY()); + mHandles[4].reposition(scaledRectangle.right, scaledRectangle.centerY()); + mHandles[5].reposition(scaledRectangle.left, scaledRectangle.bottom); + mHandles[6].reposition(scaledRectangle.centerX(), scaledRectangle.bottom); + mHandles[7].reposition(scaledRectangle.right, scaledRectangle.bottom); + } + + /** + * Hit test for the selection. + * @see org.libreoffice.canvas.CanvasElement#draw(android.graphics.Canvas) + */ + @Override + public boolean onHitTest(float x, float y) { + // Check if handle was hit + for (GraphicSelectionHandle handle : mHandles) { + if (handle.contains(x, y)) { + return true; + } + } + return mScaledRectangle.contains(x, y); + } + + /** + * Draw the selection on the canvas. + * @see org.libreoffice.canvas.CanvasElement#draw(android.graphics.Canvas) + */ + @Override + public void onDraw(Canvas canvas) { + canvas.drawRect(mDrawRectangle, mPaintStroke); + if (mType != DragType.NONE) { + canvas.drawRect(mDrawRectangle, mPaintFill); + } + for (GraphicSelectionHandle handle : mHandles) { + handle.draw(canvas); + } + } + + /** + * Dragging on the screen has started. + * @param position - position where the dragging started + */ + public void dragStart(PointF position) { + mDragHandle = null; + mType = DragType.NONE; + for (GraphicSelectionHandle handle : mHandles) { + if (handle.contains(position.x, position.y)) { + mDragHandle = handle; + mDragHandle.select(); + mType = DragType.EXTEND; + sendGraphicSelectionStart(handle.mPosition); + } + } + if (mDragHandle == null) { + mType = DragType.MOVE; + sendGraphicSelectionStart(position); + } + mStartDragPosition = position; + mTriggerSinglePress = true; + } + + /** + * Dragging is in process. + * @param position - position of the drag + */ + public void dragging(PointF position) { + if (mType == DragType.MOVE) { + float deltaX = position.x - mStartDragPosition.x; + float deltaY = position.y - mStartDragPosition.y; + + mDrawRectangle = new RectF(mScaledRectangle); + mDrawRectangle.offset(deltaX, deltaY); + } else if (mType == DragType.EXTEND) { + adaptDrawRectangle(position.x, position.y); + } + mTriggerSinglePress = false; + } + + /** + * Dragging has ended. + * @param position - last position of the drag + */ + public void dragEnd(PointF position) { + PointF point = new PointF(); + if (mDragHandle != null) { + point.x = mDragHandle.mPosition.x; + point.y = mDragHandle.mPosition.y; + mDragHandle.reset(); + mDragHandle = null; + } else { + point.x = mStartDragPosition.x; + point.y = mStartDragPosition.y; + } + float deltaX = position.x - mStartDragPosition.x; + float deltaY = position.y - mStartDragPosition.y; + point.offset(deltaX, deltaY); + + sendGraphicSelectionEnd(point); + + if (mTriggerSinglePress && mDragHandle == null) { + onSinglePress(point); + mTriggerSinglePress = false; + } + + mDrawRectangle = mScaledRectangle; + mType = DragType.NONE; + } + + /** + * Adapt the selection depending on which handle was dragged. + */ + private void adaptDrawRectangle(float x, float y) { + mDrawRectangle = new RectF(mScaledRectangle); + switch(mDragHandle.getHandlePosition()) { + case TOP_LEFT: + mDrawRectangle.left = x; + mDrawRectangle.top = y; + break; + case TOP: + mDrawRectangle.top = y; + break; + case TOP_RIGHT: + mDrawRectangle.right = x; + mDrawRectangle.top = y; + break; + case LEFT: + mDrawRectangle.left = x; + break; + case RIGHT: + mDrawRectangle.right = x; + break; + case BOTTOM_LEFT: + mDrawRectangle.left = x; + mDrawRectangle.bottom = y; + break; + case BOTTOM: + mDrawRectangle.bottom = y; + break; + case BOTTOM_RIGHT: + mDrawRectangle.right = x; + mDrawRectangle.bottom = y; + break; + } + } + + /** + * Send graphic selection start event to LOKitTread. + * @param screenPosition - screen position of the selection + */ + private void sendGraphicSelectionStart(PointF screenPosition) { + sendGraphicSelection("GraphicSelectionStart", screenPosition); + } + + /** + * Send graphic selection end event to LOKitTread. + * @param screenPosition - screen position of the selection + */ + private void sendGraphicSelectionEnd(PointF screenPosition) { + sendGraphicSelection("GraphicSelectionEnd", screenPosition); + } + + /** + * Send graphic selection event to LOKitTread. + * @param type - type of the graphic selection + * @param screenPosition - screen position of the selection + */ + private void sendGraphicSelection(String type, PointF screenPosition) + { + LayerView layerView = mContext.getLayerClient().getView(); + if (layerView != null) { + // Position is in screen coordinates. We need to convert them to + // document coordinates. + PointF documentPoint = layerView.getLayerClient().convertViewPointToLayerPoint(screenPosition); + LOKitShell.sendTouchEvent(type, documentPoint); + } + } + + /** + * When a single press (no dragging happened) was performed. + */ + private void onSinglePress(PointF screenPosition) { + sendGraphicSelection("LongPress", screenPosition); + } + + /** + * Set the visibility of the graphic selection. + */ + @Override + public void setVisible(boolean visible) { + super.setVisible(visible); + for (GraphicSelectionHandle handle: mHandles) { + handle.setVisible(visible); + } + } + + /** + * Reset the selection. + */ + public void reset() { + mDragHandle = null; + for (GraphicSelectionHandle handle : mHandles) { + handle.reset(); + } + } + + /** + * Type of the selection dragging. + */ + public enum DragType { + NONE, + MOVE, + EXTEND + } +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/android/source/src/java/org/libreoffice/canvas/GraphicSelectionHandle.java b/android/source/src/java/org/libreoffice/canvas/GraphicSelectionHandle.java new file mode 100644 index 000000000..68b445af6 --- /dev/null +++ b/android/source/src/java/org/libreoffice/canvas/GraphicSelectionHandle.java @@ -0,0 +1,146 @@ +/* -*- 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.canvas; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PointF; +import android.graphics.RectF; + +/** + * This class is responsible to draw the selection handles, track the handle + * position and perform a hit test to determine if the selection handle was + * touched. + */ +public class GraphicSelectionHandle extends CommonCanvasElement { + /** + * The factor used to inflate the hit area. + */ + private final float HIT_AREA_INFLATE_FACTOR = 1.75f; + + private final HandlePosition mHandlePosition; + public PointF mPosition = new PointF(); + private float mRadius = 20.0f; + private Paint mStrokePaint = new Paint(); + private Paint mFillPaint = new Paint(); + private Paint mSelectedFillPaint = new Paint(); + private RectF mHitRect = new RectF(); + private boolean mSelected = false; + + /** + * Construct the handle - set the handle position on the selection. + * @param position - the handle position on the selection + */ + public GraphicSelectionHandle(HandlePosition position) { + mHandlePosition = position; + + mStrokePaint.setStyle(Paint.Style.STROKE); + mStrokePaint.setColor(Color.GRAY); + mStrokePaint.setStrokeWidth(3); + mStrokePaint.setAntiAlias(true); + + mFillPaint.setStyle(Paint.Style.FILL); + mFillPaint.setColor(Color.WHITE); + mFillPaint.setAlpha(200); + mFillPaint.setAntiAlias(true); + + mSelectedFillPaint.setStyle(Paint.Style.FILL); + mSelectedFillPaint.setColor(Color.GRAY); + mSelectedFillPaint.setAlpha(200); + mSelectedFillPaint.setAntiAlias(true); + } + + /** + * The position of the handle. + * @return + */ + public HandlePosition getHandlePosition() { + return mHandlePosition; + } + + /** + * Draws the handle to the canvas. + * + * @see org.libreoffice.canvas.CanvasElement#draw(android.graphics.Canvas) + */ + @Override + public void onDraw(Canvas canvas) { + if (mSelected) { + drawFilledCircle(canvas, mPosition.x, mPosition.y, mRadius, mStrokePaint, mSelectedFillPaint); + } else { + drawFilledCircle(canvas, mPosition.x, mPosition.y, mRadius, mStrokePaint, mFillPaint); + } + } + + /** + * Draw a filled and stroked circle to the canvas. + */ + private void drawFilledCircle(Canvas canvas, float x, float y, float radius, Paint strokePaint, Paint fillPaint) { + canvas.drawCircle(x, y, radius, fillPaint); + canvas.drawCircle(x, y, radius, strokePaint); + } + + /** + * Viewport has changed, reposition the handle to the input coordinates. + */ + public void reposition(float x, float y) { + mPosition.x = x; + mPosition.y = y; + + // inflate the radius by HIT_AREA_INFLATE_FACTOR + float inflatedRadius = mRadius * HIT_AREA_INFLATE_FACTOR; + + // reposition the hit area rectangle + mHitRect.left = mPosition.x - inflatedRadius; + mHitRect.right = mPosition.x + inflatedRadius; + mHitRect.top = mPosition.y - inflatedRadius; + mHitRect.bottom = mPosition.y + inflatedRadius; + } + + /** + * Hit test for the handle. + * @see org.libreoffice.canvas.CanvasElement#draw(android.graphics.Canvas) + */ + @Override + public boolean onHitTest(float x, float y) { + return mHitRect.contains(x, y); + } + + /** + * Mark the handle as selected. + */ + public void select() { + mSelected = true; + } + + /** + * Reset the selection for the handle. + */ + public void reset() { + mSelected = false; + } + + /** + * All possible handle positions. The selection rectangle has 8 possible + * handles. + */ + public enum HandlePosition { + TOP_LEFT, + TOP, + TOP_RIGHT, + RIGHT, + BOTTOM_RIGHT, + BOTTOM, + BOTTOM_LEFT, + LEFT + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
\ No newline at end of file diff --git a/android/source/src/java/org/libreoffice/canvas/ImageUtils.java b/android/source/src/java/org/libreoffice/canvas/ImageUtils.java new file mode 100644 index 000000000..ecda9b77c --- /dev/null +++ b/android/source/src/java/org/libreoffice/canvas/ImageUtils.java @@ -0,0 +1,29 @@ +package org.libreoffice.canvas; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; + +class ImageUtils { + static Bitmap getBitmapForDrawable(Drawable drawable) { + drawable = drawable.mutate(); + + int width = !drawable.getBounds().isEmpty() ? + drawable.getBounds().width() : drawable.getIntrinsicWidth(); + + width = width <= 0 ? 1 : width; + + int height = !drawable.getBounds().isEmpty() ? + drawable.getBounds().height() : drawable.getIntrinsicHeight(); + + height = height <= 0 ? 1 : height; + + final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + drawable.draw(canvas); + + return bitmap; + } +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/android/source/src/java/org/libreoffice/canvas/PageNumberRect.java b/android/source/src/java/org/libreoffice/canvas/PageNumberRect.java new file mode 100644 index 000000000..62de88ea5 --- /dev/null +++ b/android/source/src/java/org/libreoffice/canvas/PageNumberRect.java @@ -0,0 +1,64 @@ +/* + * 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.canvas; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.text.TextPaint; + +/* + * A canvas element on DocumentOverlayView. Shows a rectangle with current page + * number and total page number inside of it. + */ +public class PageNumberRect extends CommonCanvasElement { + private String mPageNumberString; + private TextPaint mPageNumberRectPaint = new TextPaint(); + private Paint mBgPaint = new Paint(); + private Rect mTextBounds = new Rect(); + private float mBgMargin = 5f; + + public PageNumberRect() { + mBgPaint.setColor(Color.BLACK); + mBgPaint.setAlpha(100); + mPageNumberRectPaint.setColor(Color.WHITE); + } + + /** + * Implement hit test here + * + * @param x - x coordinate of the + * @param y - y coordinate of the + */ + @Override + public boolean onHitTest(float x, float y) { + return false; + } + + /** + * Called inside draw if the element is visible. Override this method to + * draw the element on the canvas. + * + * @param canvas - the canvas + */ + @Override + public void onDraw(Canvas canvas) { + canvas.drawRect(canvas.getWidth()*0.1f - mBgMargin, + canvas.getHeight()*0.1f - mTextBounds.height() - mBgMargin, + mTextBounds.width() + canvas.getWidth()*0.1f + mBgMargin, + canvas.getHeight()*0.1f + mBgMargin, + mBgPaint); + canvas.drawText(mPageNumberString, canvas.getWidth()*0.1f, canvas.getHeight()*0.1f, mPageNumberRectPaint); + } + + public void setPageNumberString (String pageNumberString) { + mPageNumberString = pageNumberString; + mPageNumberRectPaint.getTextBounds(mPageNumberString, 0, mPageNumberString.length(), mTextBounds); + } +} diff --git a/android/source/src/java/org/libreoffice/canvas/SelectionHandle.java b/android/source/src/java/org/libreoffice/canvas/SelectionHandle.java new file mode 100644 index 000000000..ddd16fe5e --- /dev/null +++ b/android/source/src/java/org/libreoffice/canvas/SelectionHandle.java @@ -0,0 +1,73 @@ +package org.libreoffice.canvas; + +import android.graphics.Bitmap; +import android.graphics.PointF; + +import org.libreoffice.LOKitShell; +import org.libreoffice.LibreOfficeMainActivity; +import org.mozilla.gecko.gfx.ImmutableViewportMetrics; + +/** + * Selection handle is a common class for "start", "middle" and "end" types + * of selection handles. + */ +public abstract class SelectionHandle extends BitmapHandle { + private static final long MINIMUM_HANDLE_UPDATE_TIME = 50 * 1000000; + + private final PointF mDragStartPoint = new PointF(); + private final PointF mDragDocumentPosition = new PointF(); + private long mLastTime = 0; + + private LibreOfficeMainActivity mContext; + + public SelectionHandle(LibreOfficeMainActivity context, Bitmap bitmap) { + super(bitmap); + mContext = context; + } + + /** + * Start of a touch and drag action on the handle. + */ + public void dragStart(PointF point) { + mDragStartPoint.x = point.x; + mDragStartPoint.y = point.y; + mDragDocumentPosition.x = mDocumentPosition.left; + mDragDocumentPosition.y = mDocumentPosition.top; + } + + /** + * End of a touch and drag action on the handle. + */ + public void dragEnd(PointF point) { + } + + /** + * Handle has been dragged. + */ + public void dragging(PointF point) { + long currentTime = System.nanoTime(); + if (currentTime - mLastTime > MINIMUM_HANDLE_UPDATE_TIME) { + mLastTime = currentTime; + signalHandleMove(point.x, point.y); + } + } + + /** + * Signal to move the handle to a new position to LO. + */ + private void signalHandleMove(float newX, float newY) { + ImmutableViewportMetrics viewportMetrics = mContext.getLayerClient().getViewportMetrics(); + float zoom = viewportMetrics.zoomFactor; + + float deltaX = (newX - mDragStartPoint.x) / zoom; + float deltaY = (newY - mDragStartPoint.y) / zoom; + + PointF documentPoint = new PointF(mDragDocumentPosition.x + deltaX, mDragDocumentPosition.y + deltaY); + + LOKitShell.sendChangeHandlePositionEvent(getHandleType(), documentPoint); + } + + public abstract HandleType getHandleType(); + + public enum HandleType { START, MIDDLE, END } +} diff --git a/android/source/src/java/org/libreoffice/canvas/SelectionHandleEnd.java b/android/source/src/java/org/libreoffice/canvas/SelectionHandleEnd.java new file mode 100644 index 000000000..b85b80fc9 --- /dev/null +++ b/android/source/src/java/org/libreoffice/canvas/SelectionHandleEnd.java @@ -0,0 +1,22 @@ +package org.libreoffice.canvas; + +import org.libreoffice.LibreOfficeMainActivity; + +import org.libreoffice.R; + +/** + * Selection handle for showing and manipulating the end of a selection. + */ +public class SelectionHandleEnd extends SelectionHandle { + public SelectionHandleEnd(LibreOfficeMainActivity context) { + super(context, getBitmapForDrawable(context, R.drawable.handle_alias_end)); + } + + /** + * Define the type of the handle. + */ + @Override + public HandleType getHandleType() { + return HandleType.END; + } +} diff --git a/android/source/src/java/org/libreoffice/canvas/SelectionHandleMiddle.java b/android/source/src/java/org/libreoffice/canvas/SelectionHandleMiddle.java new file mode 100644 index 000000000..76bdf9110 --- /dev/null +++ b/android/source/src/java/org/libreoffice/canvas/SelectionHandleMiddle.java @@ -0,0 +1,34 @@ +package org.libreoffice.canvas; + +import org.libreoffice.LibreOfficeMainActivity; + +import org.libreoffice.R; + +/** + * Selection handle that is used to manipulate the cursor. + */ +public class SelectionHandleMiddle extends SelectionHandle { + public SelectionHandleMiddle(LibreOfficeMainActivity context) { + super(context, getBitmapForDrawable(context, R.drawable.handle_alias_middle)); + } + + /** + * Change the position of the handle on the screen. Take into account the + * handle alignment to the center. + */ + @Override + public void reposition(float x, float y) { + super.reposition(x, y); + // align to the center + float offset = mScreenPosition.width() / 2.0f; + mScreenPosition.offset(-offset, 0); + } + + /** + * Define the type of the handle. + */ + @Override + public HandleType getHandleType() { + return HandleType.MIDDLE; + } +} diff --git a/android/source/src/java/org/libreoffice/canvas/SelectionHandleStart.java b/android/source/src/java/org/libreoffice/canvas/SelectionHandleStart.java new file mode 100644 index 000000000..ad28826f6 --- /dev/null +++ b/android/source/src/java/org/libreoffice/canvas/SelectionHandleStart.java @@ -0,0 +1,34 @@ +package org.libreoffice.canvas; + +import org.libreoffice.LibreOfficeMainActivity; + +import org.libreoffice.R; + +/** + * Selection handle for showing and manipulating the start of a selection. + */ +public class SelectionHandleStart extends SelectionHandle { + public SelectionHandleStart(LibreOfficeMainActivity context) { + super(context, getBitmapForDrawable(context, R.drawable.handle_alias_start)); + } + + /** + * Change the position of the handle on the screen. Take into account the + * handle alignment to the right. + */ + @Override + public void reposition(float x, float y) { + super.reposition(x, y); + // align to the right + float offset = mScreenPosition.width(); + mScreenPosition.offset(-offset, 0); + } + + /** + * Define the type of the handle. + */ + @Override + public HandleType getHandleType() { + return HandleType.START; + } +}
\ No newline at end of file |