summaryrefslogtreecommitdiffstats
path: root/android/source/src/java/org/libreoffice/canvas
diff options
context:
space:
mode:
Diffstat (limited to 'android/source/src/java/org/libreoffice/canvas')
-rw-r--r--android/source/src/java/org/libreoffice/canvas/AdjustLengthLine.java103
-rw-r--r--android/source/src/java/org/libreoffice/canvas/BitmapHandle.java63
-rw-r--r--android/source/src/java/org/libreoffice/canvas/CalcHeaderCell.java54
-rw-r--r--android/source/src/java/org/libreoffice/canvas/CalcSelectionBox.java111
-rw-r--r--android/source/src/java/org/libreoffice/canvas/CanvasElement.java45
-rw-r--r--android/source/src/java/org/libreoffice/canvas/CanvasElementImplRequirement.java25
-rw-r--r--android/source/src/java/org/libreoffice/canvas/CommonCanvasElement.java46
-rw-r--r--android/source/src/java/org/libreoffice/canvas/Cursor.java56
-rw-r--r--android/source/src/java/org/libreoffice/canvas/GraphicSelection.java295
-rw-r--r--android/source/src/java/org/libreoffice/canvas/GraphicSelectionHandle.java146
-rw-r--r--android/source/src/java/org/libreoffice/canvas/ImageUtils.java29
-rw-r--r--android/source/src/java/org/libreoffice/canvas/PageNumberRect.java64
-rw-r--r--android/source/src/java/org/libreoffice/canvas/SelectionHandle.java73
-rw-r--r--android/source/src/java/org/libreoffice/canvas/SelectionHandleEnd.java22
-rw-r--r--android/source/src/java/org/libreoffice/canvas/SelectionHandleMiddle.java34
-rw-r--r--android/source/src/java/org/libreoffice/canvas/SelectionHandleStart.java34
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